merge trunk
This commit is contained in:
commit
99cecb4fc7
548 changed files with 39743 additions and 8076 deletions
|
@ -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;
|
||||
|
|
|
@ -46,10 +46,6 @@ 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 DISK_CACHE_STATS
|
||||
static unsigned long grub_disk_cache_hits;
|
||||
static unsigned long grub_disk_cache_misses;
|
||||
|
@ -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,110 @@ 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_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 ();
|
||||
return grub_errno;
|
||||
}
|
||||
grub_memcpy (buf, tmp_buf + offset, size);
|
||||
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, §or, &offset, size) != GRUB_ERR_NONE)
|
||||
|
@ -399,126 +494,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 +622,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, §or, &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 +654,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 +665,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 +675,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 +699,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;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
#define GRUB_MODULES_MACHINE_READONLY
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
grub_dl_t grub_dl_head = 0;
|
||||
|
@ -86,6 +90,7 @@ struct grub_symbol
|
|||
struct grub_symbol *next;
|
||||
const char *name;
|
||||
void *addr;
|
||||
int isfunc;
|
||||
grub_dl_t mod; /* The module to which this symbol belongs. */
|
||||
};
|
||||
typedef struct grub_symbol *grub_symbol_t;
|
||||
|
@ -110,21 +115,22 @@ grub_symbol_hash (const char *s)
|
|||
|
||||
/* Resolve the symbol name NAME and return the address.
|
||||
Return NULL, if not found. */
|
||||
static void *
|
||||
static grub_symbol_t
|
||||
grub_dl_resolve_symbol (const char *name)
|
||||
{
|
||||
grub_symbol_t sym;
|
||||
|
||||
for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
|
||||
if (grub_strcmp (sym->name, name) == 0)
|
||||
return sym->addr;
|
||||
return sym;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a symbol with the name NAME and the address ADDR. */
|
||||
grub_err_t
|
||||
grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
|
||||
grub_dl_register_symbol (const char *name, void *addr, int isfunc,
|
||||
grub_dl_t mod)
|
||||
{
|
||||
grub_symbol_t sym;
|
||||
unsigned k;
|
||||
|
@ -147,6 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
|
|||
|
||||
sym->addr = addr;
|
||||
sym->mod = mod;
|
||||
sym->isfunc = isfunc;
|
||||
|
||||
k = grub_symbol_hash (name);
|
||||
sym->next = grub_symtab[k];
|
||||
|
@ -225,6 +232,48 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
grub_size_t tsize = 0, talign = 1;
|
||||
#ifdef __ia64__
|
||||
grub_size_t tramp;
|
||||
grub_size_t got;
|
||||
#endif
|
||||
char *ptr;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
|
||||
{
|
||||
tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
|
||||
if (talign < s->sh_addralign)
|
||||
talign = s->sh_addralign;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
||||
tramp *= GRUB_IA64_DL_TRAMP_SIZE;
|
||||
got *= sizeof (grub_uint64_t);
|
||||
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
||||
talign = GRUB_ARCH_DL_TRAMP_ALIGN;
|
||||
tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
|
||||
if (talign < GRUB_ARCH_DL_GOT_ALIGN)
|
||||
talign = GRUB_ARCH_DL_GOT_ALIGN;
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
if (talign < 8192 * 16)
|
||||
talign = 8192 * 16;
|
||||
tsize = ALIGN_UP (tsize, 8192 * 16);
|
||||
#endif
|
||||
|
||||
mod->base = grub_memalign (talign, tsize);
|
||||
if (!mod->base)
|
||||
return grub_errno;
|
||||
ptr = mod->base;
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#endif
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
|
@ -242,12 +291,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
{
|
||||
void *addr;
|
||||
|
||||
addr = grub_memalign (s->sh_addralign, s->sh_size);
|
||||
if (! addr)
|
||||
{
|
||||
grub_free (seg);
|
||||
return grub_errno;
|
||||
}
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
|
||||
addr = ptr;
|
||||
ptr += s->sh_size;
|
||||
|
||||
switch (s->sh_type)
|
||||
{
|
||||
|
@ -270,6 +316,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
mod->segment = seg;
|
||||
}
|
||||
}
|
||||
#ifdef __ia64__
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||
mod->tramp = ptr;
|
||||
ptr += tramp;
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
|
||||
mod->got = ptr;
|
||||
ptr += got;
|
||||
#endif
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -320,17 +374,20 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
|
|||
/* Resolve a global symbol. */
|
||||
if (sym->st_name != 0 && sym->st_shndx == 0)
|
||||
{
|
||||
sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
|
||||
if (! sym->st_value)
|
||||
grub_symbol_t nsym = grub_dl_resolve_symbol (name);
|
||||
if (! nsym)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"symbol not found: `%s'", name);
|
||||
sym->st_value = (Elf_Addr) nsym->addr;
|
||||
if (nsym->isfunc)
|
||||
sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
|
||||
return grub_errno;
|
||||
}
|
||||
break;
|
||||
|
@ -338,10 +395,21 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
|
|||
case STT_FUNC:
|
||||
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
#ifdef __ia64__
|
||||
{
|
||||
/* FIXME: free descriptor once it's not used anymore. */
|
||||
char **desc;
|
||||
desc = grub_malloc (2 * sizeof (char *));
|
||||
if (!desc)
|
||||
return grub_errno;
|
||||
desc[0] = (void *) sym->st_value;
|
||||
desc[1] = mod->base;
|
||||
sym->st_value = (grub_addr_t) desc;
|
||||
}
|
||||
#endif
|
||||
if (bind != STB_LOCAL)
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
|
||||
return grub_errno;
|
||||
|
||||
if (grub_strcmp (name, "grub_mod_init") == 0)
|
||||
mod->init = (void (*) (grub_dl_t)) sym->st_value;
|
||||
else if (grub_strcmp (name, "grub_mod_fini") == 0)
|
||||
|
@ -373,6 +441,38 @@ grub_dl_call_init (grub_dl_t mod)
|
|||
(mod->init) (mod);
|
||||
}
|
||||
|
||||
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
|
||||
GNU module policy. Note that this license check is informative only.
|
||||
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
|
||||
multi-licensed under other licences as well) independently of the
|
||||
presence of this check and solely by linking (module loading in GRUB
|
||||
constitutes linking) and GRUB core being licensed under GPLv3+.
|
||||
Be sure to understand your license obligations.
|
||||
*/
|
||||
static grub_err_t
|
||||
grub_dl_check_license (Elf_Ehdr *e)
|
||||
{
|
||||
Elf_Shdr *s;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
|
||||
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
|
||||
str = (char *) e + s->sh_offset;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (grub_strcmp (str + s->sh_name, ".module_license") == 0)
|
||||
{
|
||||
if (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
|
||||
|| grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
|
||||
|| grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
|
||||
{
|
||||
|
@ -519,7 +619,16 @@ grub_dl_load_core (void *addr, grub_size_t size)
|
|||
mod->ref_count = 1;
|
||||
|
||||
grub_dprintf ("modules", "relocating to %p\n", mod);
|
||||
if (grub_dl_resolve_name (mod, e)
|
||||
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
|
||||
GNU module policy. Note that this license check is informative only.
|
||||
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
|
||||
multi-licensed under other licences as well) independently of the
|
||||
presence of this check and solely by linking (module loading in GRUB
|
||||
constitutes linking) and GRUB core being licensed under GPLv3+.
|
||||
Be sure to understand your license obligations.
|
||||
*/
|
||||
if (grub_dl_check_license (e)
|
||||
|| grub_dl_resolve_name (mod, e)
|
||||
|| grub_dl_resolve_dependencies (mod, e)
|
||||
|| grub_dl_load_segments (mod, e)
|
||||
|| grub_dl_resolve_symbols (mod, e)
|
||||
|
@ -579,13 +688,11 @@ 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 = 0;
|
||||
mod->ref_count--;
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
@ -642,8 +749,7 @@ grub_dl_unload (grub_dl_t mod)
|
|||
{
|
||||
depn = dep->next;
|
||||
|
||||
if (! grub_dl_unref (dep->mod))
|
||||
grub_dl_unload (dep->mod);
|
||||
grub_dl_unload (dep->mod);
|
||||
|
||||
grub_free (dep);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <grub/efi/console_control.h>
|
||||
#include <grub/efi/pe32.h>
|
||||
#include <grub/machine/time.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/mm.h>
|
||||
|
@ -193,8 +194,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
|
|||
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
|
||||
}
|
||||
|
||||
grub_uint32_t
|
||||
grub_get_rtc (void)
|
||||
grub_uint64_t
|
||||
grub_rtc_get_time_ms (void)
|
||||
{
|
||||
grub_efi_time_t time;
|
||||
grub_efi_runtime_services_t *r;
|
||||
|
@ -204,9 +205,14 @@ grub_get_rtc (void)
|
|||
/* What is possible in this case? */
|
||||
return 0;
|
||||
|
||||
return (((time.minute * 60 + time.second) * 1000
|
||||
+ time.nanosecond / 1000000)
|
||||
* GRUB_TICKS_PER_SECOND / 1000);
|
||||
return ((time.minute * 60 + time.second) * 1000
|
||||
+ time.nanosecond / 1000000);
|
||||
}
|
||||
|
||||
grub_uint32_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
return grub_rtc_get_time_ms ();
|
||||
}
|
||||
|
||||
/* Search the mods section from the PE32/PE32+ image. This code uses
|
||||
|
@ -740,3 +746,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;
|
||||
}
|
||||
|
|
|
@ -42,84 +42,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
|
||||
|
|
|
@ -25,26 +25,13 @@
|
|||
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
|
||||
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
|
||||
|
||||
#define BYTES_TO_PAGES(bytes) ((bytes) >> 12)
|
||||
#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12)
|
||||
#define PAGES_TO_BYTES(pages) ((pages) << 12)
|
||||
|
||||
/* The size of a memory map obtained from the firmware. This must be
|
||||
a multiplier of 4KB. */
|
||||
#define MEMORY_MAP_SIZE 0x3000
|
||||
|
||||
/* Maintain the list of allocated pages. */
|
||||
struct allocated_page
|
||||
{
|
||||
grub_efi_physical_address_t addr;
|
||||
grub_efi_uint64_t num_pages;
|
||||
};
|
||||
|
||||
#define ALLOCATED_PAGES_SIZE 0x1000
|
||||
#define MAX_ALLOCATED_PAGES \
|
||||
(ALLOCATED_PAGES_SIZE / sizeof (struct allocated_page))
|
||||
|
||||
static struct allocated_page *allocated_pages = 0;
|
||||
|
||||
/* The minimum and maximum heap size for GRUB itself. */
|
||||
#define MIN_HEAP_SIZE 0x100000
|
||||
#define MAX_HEAP_SIZE (1600 * 0x100000)
|
||||
|
@ -65,13 +52,13 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
|
|||
grub_efi_status_t status;
|
||||
grub_efi_boot_services_t *b;
|
||||
|
||||
#if GRUB_TARGET_SIZEOF_VOID_P < 8
|
||||
#if 1
|
||||
/* Limit the memory access to less than 4GB for 32-bit platforms. */
|
||||
if (address > 0xffffffff)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
|
||||
#if 1
|
||||
if (address == 0)
|
||||
{
|
||||
type = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
|
||||
|
@ -102,22 +89,6 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (allocated_pages)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
|
||||
if (allocated_pages[i].addr == 0)
|
||||
{
|
||||
allocated_pages[i].addr = address;
|
||||
allocated_pages[i].num_pages = pages;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAX_ALLOCATED_PAGES)
|
||||
grub_fatal ("too many page allocations");
|
||||
}
|
||||
|
||||
return (void *) ((grub_addr_t) address);
|
||||
}
|
||||
|
||||
|
@ -128,20 +99,6 @@ grub_efi_free_pages (grub_efi_physical_address_t address,
|
|||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
|
||||
if (allocated_pages
|
||||
&& ((grub_efi_physical_address_t) ((grub_addr_t) allocated_pages)
|
||||
!= address))
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
|
||||
if (allocated_pages[i].addr == address)
|
||||
{
|
||||
allocated_pages[i].addr = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
efi_call_2 (b->free_pages, address, pages);
|
||||
}
|
||||
|
@ -294,7 +251,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
|||
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
|
||||
{
|
||||
if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
|
||||
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
|
||||
#if 1
|
||||
&& desc->physical_start <= 0xffffffff
|
||||
#endif
|
||||
&& desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
|
||||
|
@ -310,7 +267,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
|
|||
desc->physical_start = 0x100000;
|
||||
}
|
||||
|
||||
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
|
||||
#if 1
|
||||
if (BYTES_TO_PAGES (filtered_desc->physical_start)
|
||||
+ filtered_desc->num_pages
|
||||
> BYTES_TO_PAGES (0x100000000LL))
|
||||
|
@ -422,14 +379,6 @@ grub_efi_mm_init (void)
|
|||
grub_efi_uint64_t required_pages;
|
||||
int mm_status;
|
||||
|
||||
/* First of all, allocate pages to maintain allocations. */
|
||||
allocated_pages
|
||||
= grub_efi_allocate_pages (0, BYTES_TO_PAGES (ALLOCATED_PAGES_SIZE));
|
||||
if (! allocated_pages)
|
||||
grub_fatal ("cannot allocate memory");
|
||||
|
||||
grub_memset (allocated_pages, 0, ALLOCATED_PAGES_SIZE);
|
||||
|
||||
/* Prepare a memory region to store two memory maps. */
|
||||
memory_map = grub_efi_allocate_pages (0,
|
||||
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||||
|
@ -447,6 +396,9 @@ grub_efi_mm_init (void)
|
|||
((grub_efi_physical_address_t) ((grub_addr_t) memory_map),
|
||||
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||||
|
||||
/* Freeing/allocating operations may increase memory map size. */
|
||||
map_size += desc_size * 32;
|
||||
|
||||
memory_map = grub_efi_allocate_pages (0, 2 * BYTES_TO_PAGES (map_size));
|
||||
if (! memory_map)
|
||||
grub_fatal ("cannot allocate memory");
|
||||
|
@ -499,24 +451,3 @@ grub_efi_mm_init (void)
|
|||
grub_efi_free_pages ((grub_addr_t) memory_map,
|
||||
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
|
||||
}
|
||||
|
||||
void
|
||||
grub_efi_mm_fini (void)
|
||||
{
|
||||
if (allocated_pages)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
|
||||
{
|
||||
struct allocated_page *p;
|
||||
|
||||
p = allocated_pages + i;
|
||||
if (p->addr != 0)
|
||||
grub_efi_free_pages ((grub_addr_t) p->addr, p->num_pages);
|
||||
}
|
||||
|
||||
grub_efi_free_pages ((grub_addr_t) allocated_pages,
|
||||
BYTES_TO_PAGES (ALLOCATED_PAGES_SIZE));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
static grub_err_t
|
||||
|
@ -171,11 +174,12 @@ grub_elf32_phdr_iterate (grub_elf_t elf,
|
|||
|
||||
/* Calculate the amount of memory spanned by the segments. */
|
||||
grub_size_t
|
||||
grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
|
||||
grub_elf32_size (grub_elf_t elf, Elf32_Addr *base, grub_uint32_t *max_align)
|
||||
{
|
||||
Elf32_Addr segments_start = (Elf32_Addr) -1;
|
||||
Elf32_Addr segments_end = 0;
|
||||
int nr_phdrs = 0;
|
||||
grub_uint32_t curr_align = 1;
|
||||
|
||||
/* Run through the program headers to calculate the total memory size we
|
||||
* should claim. */
|
||||
|
@ -192,6 +196,8 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
|
|||
segments_start = phdr->p_paddr;
|
||||
if (phdr->p_paddr + phdr->p_memsz > segments_end)
|
||||
segments_end = phdr->p_paddr + phdr->p_memsz;
|
||||
if (curr_align < phdr->p_align)
|
||||
curr_align = phdr->p_align;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -215,7 +221,8 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
|
|||
|
||||
if (base)
|
||||
*base = segments_start;
|
||||
|
||||
if (max_align)
|
||||
*max_align = curr_align;
|
||||
return segments_end - segments_start;
|
||||
}
|
||||
|
||||
|
@ -290,7 +297,6 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 64-bit */
|
||||
|
||||
|
@ -357,16 +363,17 @@ grub_elf64_phdr_iterate (grub_elf_t elf,
|
|||
|
||||
/* Calculate the amount of memory spanned by the segments. */
|
||||
grub_size_t
|
||||
grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
|
||||
grub_elf64_size (grub_elf_t elf, Elf64_Addr *base, grub_uint64_t *max_align)
|
||||
{
|
||||
Elf64_Addr segments_start = (Elf64_Addr) -1;
|
||||
Elf64_Addr segments_end = 0;
|
||||
int nr_phdrs = 0;
|
||||
grub_uint64_t curr_align = 1;
|
||||
|
||||
/* Run through the program headers to calculate the total memory size we
|
||||
* should claim. */
|
||||
auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
|
||||
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
|
||||
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
|
||||
Elf64_Phdr *phdr,
|
||||
void *_arg __attribute__ ((unused)))
|
||||
{
|
||||
|
@ -378,6 +385,8 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
|
|||
segments_start = phdr->p_paddr;
|
||||
if (phdr->p_paddr + phdr->p_memsz > segments_end)
|
||||
segments_end = phdr->p_paddr + phdr->p_memsz;
|
||||
if (curr_align < phdr->p_align)
|
||||
curr_align = phdr->p_align;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -401,11 +410,11 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
|
|||
|
||||
if (base)
|
||||
*base = segments_start;
|
||||
|
||||
if (max_align)
|
||||
*max_align = curr_align;
|
||||
return segments_end - segments_start;
|
||||
}
|
||||
|
||||
|
||||
/* Load every loadable segment into memory specified by `_load_hook'. */
|
||||
grub_err_t
|
||||
grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
|
||||
|
|
13
grub-core/kern/emu/cache.c
Normal file
13
grub-core/kern/emu/cache.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
#if defined(__ia64__)
|
||||
#include <grub/cache.h>
|
||||
|
||||
void __clear_cache (char *beg, char *end);
|
||||
|
||||
void
|
||||
grub_arch_sync_caches (void *address, grub_size_t len)
|
||||
{
|
||||
__clear_cache (address, (char *) address + len);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@ FUNCTION (grub_arch_sync_caches)
|
|||
.set macro
|
||||
#elif defined(__powerpc__)
|
||||
#include "../powerpc/cache.S"
|
||||
#elif defined(__ia64__)
|
||||
#else
|
||||
#error "No target cpu type is defined"
|
||||
#endif
|
|
@ -50,6 +50,15 @@ grub_emu_init (void)
|
|||
grub_no_autoload = 1;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
|
||||
grub_size_t *tramp, grub_size_t *got)
|
||||
{
|
||||
*tramp = 0;
|
||||
*got = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_LINKER_HAVE_INIT
|
||||
void
|
||||
grub_arch_dl_init_linker (void)
|
||||
|
|
|
@ -1,840 +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.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 __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__
|
||||
|
||||
/* Statting something on a btrfs filesystem always returns a virtual device
|
||||
major/minor pair rather than the real underlying device, because btrfs
|
||||
can span multiple underlying devices (and even if it's currently only
|
||||
using a single device it can be dynamically extended onto another). We
|
||||
can't deal with the multiple-device case yet, but in the meantime, we can
|
||||
at least cope with the single-device case by scanning
|
||||
/proc/self/mountinfo. */
|
||||
static char *
|
||||
find_root_device_from_mountinfo (const char *dir)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buf = NULL;
|
||||
size_t len = 0;
|
||||
char *ret = NULL;
|
||||
|
||||
fp = fopen ("/proc/self/mountinfo", "r");
|
||||
if (! fp)
|
||||
return NULL; /* fall through to other methods */
|
||||
|
||||
while (getline (&buf, &len, fp) > 0)
|
||||
{
|
||||
int mnt_id, parent_mnt_id;
|
||||
unsigned int major, minor;
|
||||
char enc_root[PATH_MAX], enc_path[PATH_MAX];
|
||||
int count;
|
||||
size_t enc_path_len;
|
||||
const char *sep;
|
||||
char fstype[PATH_MAX], device[PATH_MAX];
|
||||
struct stat st;
|
||||
|
||||
if (sscanf (buf, "%d %d %u:%u %s %s%n",
|
||||
&mnt_id, &parent_mnt_id, &major, &minor, enc_root, enc_path,
|
||||
&count) < 6)
|
||||
continue;
|
||||
|
||||
if (strcmp (enc_root, "/") != 0)
|
||||
continue; /* only a subtree is mounted */
|
||||
|
||||
enc_path_len = strlen (enc_path);
|
||||
if (strncmp (dir, enc_path, enc_path_len) != 0 ||
|
||||
(dir[enc_path_len] && dir[enc_path_len] != '/'))
|
||||
continue;
|
||||
|
||||
/* This is a parent of the requested directory. /proc/self/mountinfo
|
||||
is in mount order, so it must be the closest parent we've
|
||||
encountered so far. If it's virtual, return its device node;
|
||||
otherwise, carry on to try to find something closer. */
|
||||
|
||||
free (ret);
|
||||
ret = NULL;
|
||||
|
||||
if (major != 0)
|
||||
continue; /* not a virtual device */
|
||||
|
||||
sep = strstr (buf + count, " - ");
|
||||
if (!sep)
|
||||
continue;
|
||||
|
||||
sep += sizeof (" - ") - 1;
|
||||
if (sscanf (sep, "%s %s", fstype, device) != 2)
|
||||
continue;
|
||||
|
||||
if (stat (device, &st) < 0)
|
||||
continue;
|
||||
|
||||
if (!S_ISBLK (st.st_mode))
|
||||
continue; /* not a block device */
|
||||
|
||||
ret = strdup (device);
|
||||
}
|
||||
|
||||
free (buf);
|
||||
fclose (fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
|
||||
static char *
|
||||
find_root_device_from_libzfs (const char *dir)
|
||||
{
|
||||
char *device;
|
||||
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)
|
||||
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;
|
||||
#ifdef __GNU__
|
||||
file_t file;
|
||||
mach_port_t *ports;
|
||||
int *ints;
|
||||
loff_t *offsets;
|
||||
char *data;
|
||||
error_t err;
|
||||
mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0;
|
||||
size_t name_len;
|
||||
|
||||
file = file_name_lookup (dir, 0, 0);
|
||||
if (file == MACH_PORT_NULL)
|
||||
return 0;
|
||||
|
||||
err = file_get_storage_info (file,
|
||||
&ports, &num_ports,
|
||||
&ints, &num_ints,
|
||||
&offsets, &num_offsets,
|
||||
&data, &data_len);
|
||||
|
||||
if (num_ints < 1)
|
||||
grub_util_error ("Storage info for `%s' does not include type", dir);
|
||||
if (ints[0] != STORAGE_DEVICE)
|
||||
grub_util_error ("Filesystem of `%s' is not stored on local disk", dir);
|
||||
|
||||
if (num_ints < 5)
|
||||
grub_util_error ("Storage info for `%s' does not include name", dir);
|
||||
name_len = ints[4];
|
||||
if (name_len < data_len)
|
||||
grub_util_error ("Bogus name length for storage info for `%s'", dir);
|
||||
if (data[name_len - 1] != '\0')
|
||||
grub_util_error ("Storage name for `%s' not NUL-terminated", dir);
|
||||
|
||||
os_dev = xmalloc (strlen ("/dev/") + data_len);
|
||||
memcpy (os_dev, "/dev/", strlen ("/dev/"));
|
||||
memcpy (os_dev + strlen ("/dev/"), data, data_len);
|
||||
|
||||
if (ports && num_ports > 0)
|
||||
{
|
||||
mach_msg_type_number_t i;
|
||||
for (i = 0; i < num_ports; i++)
|
||||
{
|
||||
mach_port_t port = ports[i];
|
||||
if (port != MACH_PORT_NULL)
|
||||
mach_port_deallocate (mach_task_self(), port);
|
||||
}
|
||||
munmap ((caddr_t) ports, num_ports * sizeof (*ports));
|
||||
}
|
||||
|
||||
if (ints && num_ints > 0)
|
||||
munmap ((caddr_t) ints, num_ints * sizeof (*ints));
|
||||
if (offsets && num_offsets > 0)
|
||||
munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets));
|
||||
if (data && data_len > 0)
|
||||
munmap (data, data_len);
|
||||
mach_port_deallocate (mach_task_self (), file);
|
||||
#else /* !__GNU__ */
|
||||
struct stat st;
|
||||
|
||||
#ifdef __linux__
|
||||
os_dev = find_root_device_from_mountinfo (dir);
|
||||
if (os_dev)
|
||||
return os_dev;
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
|
||||
os_dev = find_root_device_from_libzfs (dir);
|
||||
if (os_dev)
|
||||
return os_dev;
|
||||
#endif
|
||||
|
||||
if (stat (dir, &st) < 0)
|
||||
grub_util_error ("cannot stat `%s'", dir);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
/* Cygwin specific function. */
|
||||
os_dev = grub_find_device (dir, st.st_dev);
|
||||
|
||||
#else
|
||||
|
||||
/* This might be truly slow, but is there any better way? */
|
||||
os_dev = grub_find_device ("/dev", st.st_dev);
|
||||
#endif
|
||||
#endif /* !__GNU__ */
|
||||
|
||||
return os_dev;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_util_is_dmraid (const char *os_dev)
|
||||
{
|
||||
if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/isw_", 16))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/hpt37x_", 19))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/hpt45x_", 19))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/via_", 16))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/lsi_", 16))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/pdc_", 16))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/jmicron_", 20))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/asr_", 16))
|
||||
return 1;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/sil_", 16))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused)))
|
||||
{
|
||||
#ifdef __linux__
|
||||
/* 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 (!strncmp (os_dev, "/dev/mapper/", 12)
|
||||
&& ! grub_util_is_dmraid (os_dev)
|
||||
&& strncmp (os_dev, "/dev/mapper/mpath", 17) != 0)
|
||||
return GRUB_DEV_ABSTRACTION_LVM;
|
||||
|
||||
/* Check for RAID. */
|
||||
if (!strncmp (os_dev, "/dev/md", 7))
|
||||
return GRUB_DEV_ABSTRACTION_RAID;
|
||||
#endif
|
||||
|
||||
/* No abstraction found. */
|
||||
return GRUB_DEV_ABSTRACTION_NONE;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static char *
|
||||
get_mdadm_name (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_NAME=", sizeof ("MD_NAME=") - 1) == 0)
|
||||
{
|
||||
char *name_start, *colon;
|
||||
size_t name_len;
|
||||
|
||||
free (name);
|
||||
name_start = buf + sizeof ("MD_NAME=") - 1;
|
||||
/* Strip off the homehost if present. */
|
||||
colon = strchr (name_start, ':');
|
||||
name = strdup (colon ? colon + 1 : name_start);
|
||||
name_len = strlen (name);
|
||||
if (name[name_len - 1] == '\n')
|
||||
name[name_len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
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_name (os_dev);
|
||||
|
||||
if (mdadm_name)
|
||||
{
|
||||
free (grub_dev);
|
||||
grub_dev = xasprintf ("md/%s", mdadm_name);
|
||||
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;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/emu/misc.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#include <grub/emu/getroot.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/list.h>
|
||||
|
@ -42,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. */
|
||||
|
@ -92,6 +94,8 @@ struct hd_geometry
|
|||
# include <sys/disk.h> /* DIOCGMEDIASIZE */
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# define MAJOR(dev) major(dev)
|
||||
# define FLOPPY_MAJOR 2
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
@ -102,7 +106,7 @@ struct hd_geometry
|
|||
# include <libdevmapper.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#if defined(__NetBSD__)
|
||||
# define HAVE_DIOCGDINFO
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/disklabel.h> /* struct disklabel */
|
||||
|
@ -134,6 +138,7 @@ struct grub_util_biosdisk_data
|
|||
char *dev;
|
||||
int access_mode;
|
||||
int fd;
|
||||
int is_disk;
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -207,7 +212,8 @@ 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;
|
||||
|
||||
|
@ -218,6 +224,82 @@ 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(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
|
||||
# if defined(__NetBSD__)
|
||||
struct disklabel label;
|
||||
# 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(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
|
||||
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)
|
||||
# else
|
||||
if (ioctl (fd, BLKGETSIZE64, &nr))
|
||||
# endif
|
||||
goto fail;
|
||||
|
||||
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
if (ioctl (fd, DIOCGSECTORSIZE, §or_size))
|
||||
# else
|
||||
if (ioctl (fd, BLKSSZGET, §or_size))
|
||||
# endif
|
||||
goto fail;
|
||||
|
||||
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;
|
||||
# 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
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -235,6 +317,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
data->dev = NULL;
|
||||
data->access_mode = 0;
|
||||
data->fd = -1;
|
||||
data->is_disk = 0;
|
||||
|
||||
/* Get the size. */
|
||||
#if defined(__MINGW32__)
|
||||
|
@ -252,92 +335,64 @@ 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;
|
||||
}
|
||||
|
||||
# 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;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
device_is_mapped (const char *dev)
|
||||
int
|
||||
grub_util_device_is_mapped (const char *dev)
|
||||
{
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
struct stat st;
|
||||
|
||||
if (!grub_device_mapper_supported ())
|
||||
return 0;
|
||||
|
||||
if (stat (dev, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return dm_is_dm_major (major (st.st_rdev));
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif /* HAVE_DEVICE_MAPPER */
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
|
||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
static grub_disk_addr_t
|
||||
find_partition_start (const char *dev)
|
||||
{
|
||||
grub_disk_addr_t out;
|
||||
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return 0;
|
||||
grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
|
||||
static grub_disk_addr_t
|
||||
find_partition_start (const char *dev)
|
||||
{
|
||||
|
@ -350,7 +405,7 @@ find_partition_start (const char *dev)
|
|||
# endif /* !defined(HAVE_DIOCGDINFO) */
|
||||
|
||||
# ifdef HAVE_DEVICE_MAPPER
|
||||
if (grub_device_mapper_supported () && device_is_mapped (dev)) {
|
||||
if (grub_util_device_is_mapped (dev)) {
|
||||
struct dm_task *task = NULL;
|
||||
grub_uint64_t start, length;
|
||||
char *target_type, *params, *space;
|
||||
|
@ -453,9 +508,12 @@ devmapper_fail:
|
|||
# if !defined(HAVE_DIOCGDINFO)
|
||||
return hdg.start;
|
||||
# else /* defined(HAVE_DIOCGDINFO) */
|
||||
p_index = dev[strlen(dev) - 1] - 'a';
|
||||
|
||||
if (p_index >= label.d_npartitions)
|
||||
if (dev[0])
|
||||
p_index = dev[strlen(dev) - 1] - 'a';
|
||||
else
|
||||
p_index = -1;
|
||||
|
||||
if (p_index >= label.d_npartitions || p_index < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"no disk label entry for `%s'", dev);
|
||||
|
@ -479,7 +537,7 @@ struct linux_partition_cache
|
|||
struct linux_partition_cache *linux_partition_cache_list;
|
||||
|
||||
static int
|
||||
linux_find_partition (char *dev, unsigned long sector)
|
||||
linux_find_partition (char *dev, grub_disk_addr_t sector)
|
||||
{
|
||||
size_t len = strlen (dev);
|
||||
const char *format;
|
||||
|
@ -487,6 +545,7 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
int i;
|
||||
char real_dev[PATH_MAX];
|
||||
struct linux_partition_cache *cache;
|
||||
int missing = 0;
|
||||
|
||||
strcpy(real_dev, dev);
|
||||
|
||||
|
@ -495,6 +554,12 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
p = real_dev + len - 4;
|
||||
format = "part%d";
|
||||
}
|
||||
else if (strncmp (real_dev, "/dev/disk/by-id/",
|
||||
sizeof ("/dev/disk/by-id/") - 1) == 0)
|
||||
{
|
||||
p = real_dev + len;
|
||||
format = "-part%d";
|
||||
}
|
||||
else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
|
||||
{
|
||||
p = real_dev + len;
|
||||
|
@ -525,7 +590,13 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
|
||||
fd = open (real_dev, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
{
|
||||
if (missing++ < 10)
|
||||
continue;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
missing = 0;
|
||||
close (fd);
|
||||
|
||||
start = find_partition_start (real_dev);
|
||||
|
@ -552,6 +623,37 @@ linux_find_partition (char *dev, unsigned long 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)
|
||||
{
|
||||
|
@ -596,7 +698,19 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
|||
{
|
||||
free (data->dev);
|
||||
if (data->fd != -1)
|
||||
close (data->fd);
|
||||
{
|
||||
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
|
||||
{
|
||||
fsync (data->fd);
|
||||
#ifdef __linux__
|
||||
if (data->is_disk)
|
||||
ioctl (data->fd, BLKFLSBUF, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
close (data->fd);
|
||||
data->fd = -1;
|
||||
}
|
||||
|
||||
/* Open the partition. */
|
||||
grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
|
||||
|
@ -607,10 +721,6 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Flush the buffer cache to the physical disk.
|
||||
XXX: This also empties the buffer cache. */
|
||||
ioctl (fd, BLKFLSBUF, 0);
|
||||
|
||||
data->dev = xstrdup (dev);
|
||||
data->access_mode = (flags & O_ACCMODE);
|
||||
data->fd = fd;
|
||||
|
@ -648,7 +758,18 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
|
|||
{
|
||||
free (data->dev);
|
||||
if (data->fd != -1)
|
||||
close (data->fd);
|
||||
{
|
||||
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
|
||||
{
|
||||
fsync (data->fd);
|
||||
#ifdef __linux__
|
||||
if (data->is_disk)
|
||||
ioctl (data->fd, BLKFLSBUF, 0);
|
||||
#endif
|
||||
}
|
||||
close (data->fd);
|
||||
data->fd = -1;
|
||||
}
|
||||
|
||||
fd = open (map[disk->id].device, flags);
|
||||
if (fd >= 0)
|
||||
|
@ -685,44 +806,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;
|
||||
|
||||
|
@ -805,20 +902,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);
|
||||
close (fd);
|
||||
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;
|
||||
|
@ -851,13 +948,34 @@ 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;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_util_biosdisk_flush (struct grub_disk *disk)
|
||||
{
|
||||
struct grub_util_biosdisk_data *data = disk->data;
|
||||
|
||||
if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID)
|
||||
return GRUB_ERR_NONE;
|
||||
if (data->fd == -1)
|
||||
{
|
||||
data->fd = open_device (disk, 0, O_RDONLY);
|
||||
if (data->fd < 0)
|
||||
return grub_errno;
|
||||
}
|
||||
fsync (data->fd);
|
||||
#ifdef __linux__
|
||||
if (data->is_disk)
|
||||
ioctl (data->fd, BLKFLSBUF, 0);
|
||||
#endif
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_util_biosdisk_close (struct grub_disk *disk)
|
||||
{
|
||||
|
@ -865,7 +983,11 @@ grub_util_biosdisk_close (struct grub_disk *disk)
|
|||
|
||||
free (data->dev);
|
||||
if (data->fd != -1)
|
||||
close (data->fd);
|
||||
{
|
||||
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
|
||||
grub_util_biosdisk_flush (disk);
|
||||
close (data->fd);
|
||||
}
|
||||
free (data);
|
||||
}
|
||||
|
||||
|
@ -1035,6 +1157,54 @@ make_device_name (int drive, int dos_part, int bsd_part)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
grub_util_get_dm_node_linear_info (const char *dev,
|
||||
int *maj, int *min)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t length, start;
|
||||
char *target, *params;
|
||||
char *ptr;
|
||||
int major, minor;
|
||||
|
||||
dmt = dm_task_create(DM_DEVICE_TABLE);
|
||||
if (!dmt)
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, dev))
|
||||
return 0;
|
||||
dm_task_no_open_count(dmt);
|
||||
if (!dm_task_run(dmt))
|
||||
return 0;
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target, ¶ms);
|
||||
if (grub_strcmp (target, "linear") != 0)
|
||||
return 0;
|
||||
major = grub_strtoul (params, &ptr, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (*ptr != ':')
|
||||
return 0;
|
||||
ptr++;
|
||||
minor = grub_strtoul (ptr, 0, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (maj)
|
||||
*maj = major;
|
||||
if (min)
|
||||
*min = minor;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
||||
{
|
||||
|
@ -1152,16 +1322,22 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
|||
|| strncmp ("sd", p, 2) == 0)
|
||||
&& p[2] >= 'a' && p[2] <= 'z')
|
||||
{
|
||||
/* /dev/[hsv]d[a-z][0-9]* */
|
||||
p[3] = '\0';
|
||||
char *pp = p + 2;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/[hsv]d[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
/* If this is a Xen virtual block device. */
|
||||
if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
|
||||
{
|
||||
/* /dev/xvd[a-z][0-9]* */
|
||||
p[4] = '\0';
|
||||
char *pp = p + 3;
|
||||
while (*pp >= 'a' && *pp <= 'z')
|
||||
pp++;
|
||||
/* /dev/xvd[a-z]+[0-9]* */
|
||||
*pp = '\0';
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -1205,9 +1381,40 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
|||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
else if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
if (strncmp (node_uuid, "LVM-", 4) == 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s is an LVM\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "mpath-", 6) == 0)
|
||||
{
|
||||
/* Multipath partitions have partN-mpath-* UUIDs, and are
|
||||
linear mappings so are handled by
|
||||
grub_util_get_dm_node_linear_info. Multipath disks are not
|
||||
linear mappings and must be handled specially. */
|
||||
grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
int major, minor;
|
||||
const char *node_name;
|
||||
grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
|
||||
|
||||
if ((node_name = dm_tree_node_get_name (node))
|
||||
&& grub_util_get_dm_node_linear_info (node_name,
|
||||
&major, &minor))
|
||||
{
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
char *ret = grub_find_device ("/dev/mapper",
|
||||
(major << 8) | minor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
@ -1278,7 +1485,17 @@ devmapper_out:
|
|||
path[8] = 0;
|
||||
return path;
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
char *out, *out2;
|
||||
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
|
||||
return xstrdup (os_dev);
|
||||
grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
|
||||
|
||||
out2 = xasprintf ("/dev/%s", out);
|
||||
free (out);
|
||||
|
||||
return out2;
|
||||
#elif defined(__APPLE__)
|
||||
char *path = xstrdup (os_dev);
|
||||
if (strncmp ("/dev/", path, 5) == 0)
|
||||
{
|
||||
|
@ -1431,9 +1648,12 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
|
|||
struct stat st;
|
||||
int drive;
|
||||
|
||||
grub_util_info ("Looking for %s", os_dev);
|
||||
|
||||
if (stat (os_dev, &st) < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
|
||||
grub_util_info ("cannot stat `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1442,6 +1662,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
|
|||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"no mapping exists for `%s'", os_dev);
|
||||
grub_util_info ("no mapping exists for `%s'", os_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1456,7 +1677,8 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
|
|||
#endif
|
||||
return make_device_name (drive, -1, -1);
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
|
||||
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
|
||||
partition, so mapping them to GRUB devices is not trivial.
|
||||
Here, get the start sector of a partition by HDIO_GETGEO, and
|
||||
|
@ -1620,7 +1842,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)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "../mips/dl.c"
|
||||
#elif defined(__powerpc__)
|
||||
#include "../powerpc/dl.c"
|
||||
#elif defined(__ia64__)
|
||||
#include "../ia64/dl.c"
|
||||
#else
|
||||
#error "No target cpu type is defined"
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
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;
|
||||
|
||||
|
@ -71,11 +71,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
|
||||
|
@ -84,6 +83,8 @@ grub_machine_fini (void)
|
|||
grub_console_fini ();
|
||||
}
|
||||
|
||||
char grub_prefix[64] = "";
|
||||
|
||||
|
||||
|
||||
static struct option options[] =
|
||||
|
@ -110,7 +111,7 @@ usage (int status)
|
|||
"\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"
|
||||
|
@ -132,22 +133,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;
|
||||
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;
|
||||
|
@ -201,27 +204,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)
|
||||
|
|
|
@ -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
|
||||
|
@ -242,233 +234,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);
|
||||
free (buf2);
|
||||
return xstrdup ("");
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
offset = p - buf;
|
||||
/* offset == 1 means root directory. */
|
||||
if (offset == 1)
|
||||
{
|
||||
/* Include leading slash. */
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (buf);
|
||||
buf3 = xstrdup (buf2 + offset);
|
||||
free (buf2);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
|
||||
{
|
||||
/* Reached some mount point not below /cygdrive.
|
||||
GRUB does not know Cygwin's emulated mounts,
|
||||
convert to Win32 path. */
|
||||
grub_util_info ("Cygwin path = %s\n", buf3);
|
||||
char * temp = get_win32_path (buf3);
|
||||
free (buf3);
|
||||
buf3 = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove trailing slashes, return empty string if root directory. */
|
||||
len = strlen (buf3);
|
||||
while (len > 0 && buf3[len - 1] == '/')
|
||||
{
|
||||
buf3[len - 1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
#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)),
|
||||
|
|
|
@ -240,3 +240,23 @@ grub_register_variable_hook (const char *name,
|
|||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_env_export (const char *name)
|
||||
{
|
||||
struct grub_env_var *var;
|
||||
|
||||
var = grub_env_find (name);
|
||||
if (! var)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_env_set (name, "");
|
||||
if (err)
|
||||
return err;
|
||||
var = grub_env_find (name);
|
||||
}
|
||||
var->global = 1;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
@ -68,7 +71,7 @@ grub_file_open (const char *name)
|
|||
goto fail;
|
||||
|
||||
/* Get the file part of NAME. */
|
||||
file_name = grub_strchr (name, ')');
|
||||
file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
|
||||
if (file_name)
|
||||
file_name++;
|
||||
else
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -107,10 +107,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
|
||||
|
|
|
@ -87,3 +87,4 @@ codestart:
|
|||
*/
|
||||
#include "../realmode.S"
|
||||
|
||||
#include "../int.S"
|
||||
|
|
|
@ -39,9 +39,3 @@ grub_machine_fini (void)
|
|||
{
|
||||
grub_efi_fini ();
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_set_prefix (void)
|
||||
{
|
||||
grub_efi_set_prefix ();
|
||||
}
|
||||
|
|
140
grub-core/kern/i386/int.S
Normal file
140
grub-core/kern/i386/int.S
Normal 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
|
||||
|
||||
call 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
|
||||
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
|
||||
#ifndef GRUB_MACHINE_PCBIOS
|
||||
lidt protidt
|
||||
#endif
|
||||
ret
|
||||
#ifndef GRUB_MACHINE_PCBIOS
|
||||
realidt:
|
||||
.word 0x100
|
||||
.long 0
|
||||
protidt:
|
||||
.word 0
|
||||
.long 0
|
||||
#endif
|
|
@ -45,52 +45,41 @@ 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);
|
||||
|
||||
void
|
||||
grub_machine_get_bootlocation (char **device, char **path)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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", (grub_boot_drive & 0x80) ? 'h' : 'f',
|
||||
grub_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 (grub_install_dos_part >= 0)
|
||||
grub_snprintf (ptr, DEV_SIZE - (ptr - *device),
|
||||
",%u", grub_install_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 (grub_install_bsd_part >= 0)
|
||||
grub_snprintf (ptr, DEV_SIZE - (ptr - *device), ",%u",
|
||||
grub_install_bsd_part + 1);
|
||||
ptr += grub_strlen (ptr);
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
/* Add a memory region. */
|
||||
|
@ -140,36 +129,27 @@ compact_mem_regions (void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* grub_get_conv_memsize(i) : return the conventional memory size in KB.
|
||||
* BIOS call "INT 12H" to get conventional memory size
|
||||
* The return value in AX.
|
||||
*/
|
||||
static inline grub_uint16_t
|
||||
grub_get_conv_memsize (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x12, ®s);
|
||||
return regs.eax & 0xffff;
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
int i;
|
||||
#if 0
|
||||
int grub_lower_mem;
|
||||
#endif
|
||||
|
||||
/* Initialize the console as early as possible. */
|
||||
grub_console_init ();
|
||||
|
||||
/* This sanity check is useless since top of GRUB_MEMORY_MACHINE_RESERVED_END
|
||||
is used for stack and if it's unavailable we wouldn't have gotten so far.
|
||||
*/
|
||||
#if 0
|
||||
grub_lower_mem = grub_get_conv_memsize () << 10;
|
||||
|
||||
/* Sanity check. */
|
||||
if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
|
||||
grub_fatal ("too small memory");
|
||||
#endif
|
||||
|
||||
/* FIXME: This prevents loader/i386/linux.c from using low memory. When our
|
||||
heap implements support for requesting a chunk in low memory, this should
|
||||
|
@ -220,13 +200,6 @@ 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)
|
||||
{
|
||||
|
|
|
@ -36,6 +36,22 @@ struct grub_machine_mmap_entry
|
|||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* grub_get_conv_memsize(i) : return the conventional memory size in KB.
|
||||
* BIOS call "INT 12H" to get conventional memory size
|
||||
* The return value in AX.
|
||||
*/
|
||||
static inline grub_uint16_t
|
||||
grub_get_conv_memsize (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x12, ®s);
|
||||
return regs.eax & 0xffff;
|
||||
}
|
||||
|
||||
/*
|
||||
* grub_get_ext_memsize() : return the extended memory size in KB.
|
||||
* BIOS call "INT 15H, AH=88H" to get extended memory size
|
||||
|
@ -155,6 +171,10 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
|||
{
|
||||
grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
|
||||
|
||||
if (hook (0x0, ((grub_uint32_t) grub_get_conv_memsize ()) << 10,
|
||||
GRUB_MEMORY_AVAILABLE))
|
||||
return 0;
|
||||
|
||||
if (eisa_mmap)
|
||||
{
|
||||
if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10,
|
||||
|
@ -162,7 +182,8 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
|||
hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE);
|
||||
}
|
||||
else
|
||||
hook (0x100000, grub_get_ext_memsize () << 10, GRUB_MEMORY_AVAILABLE);
|
||||
hook (0x100000, ((grub_uint32_t) grub_get_ext_memsize ()) << 10,
|
||||
GRUB_MEMORY_AVAILABLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -151,8 +151,6 @@ LOCAL (codestart):
|
|||
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
|
||||
testl %edx, %edx
|
||||
jz post_reed_solomon
|
||||
call EXT_C (grub_reed_solomon_recover)
|
||||
jmp post_reed_solomon
|
||||
|
||||
|
@ -224,6 +222,7 @@ multiboot_trampoline:
|
|||
movb $0xFF, %dh
|
||||
/* enter the usual booting */
|
||||
call prot_to_real
|
||||
jmp LOCAL (codestart)
|
||||
|
||||
post_reed_solomon:
|
||||
|
||||
|
@ -591,7 +590,7 @@ FUNCTION(grub_console_putchar)
|
|||
|
||||
|
||||
LOCAL(bypass_table):
|
||||
.word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
|
||||
.word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
|
||||
.word 0x1c00 | '\n'
|
||||
LOCAL(bypass_table_end):
|
||||
|
||||
|
@ -615,6 +614,7 @@ LOCAL(bypass_table_end):
|
|||
|
||||
FUNCTION(grub_console_getkey)
|
||||
pushl %ebp
|
||||
pushl %edi
|
||||
|
||||
call prot_to_real
|
||||
.code16
|
||||
|
@ -644,15 +644,16 @@ FUNCTION(grub_console_getkey)
|
|||
jz 1f
|
||||
|
||||
andl %edx, %eax
|
||||
cmp %eax, 0x20
|
||||
ja 2f
|
||||
cmpl $0x20, %eax
|
||||
jae 2f
|
||||
movl %edx, %eax
|
||||
leal LOCAL(bypass_table), %esi
|
||||
movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx
|
||||
repne cmpsw
|
||||
leal LOCAL(bypass_table), %edi
|
||||
movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx
|
||||
repne scasw
|
||||
jz 3f
|
||||
|
||||
addl $('a' - 1 | GRUB_TERM_CTRL), %eax
|
||||
andl $0xff, %eax
|
||||
addl $(('a' - 1) | GRUB_TERM_CTRL), %eax
|
||||
jmp 2f
|
||||
3:
|
||||
andl $0xff, %eax
|
||||
|
@ -661,7 +662,8 @@ FUNCTION(grub_console_getkey)
|
|||
1: movl %edx, %eax
|
||||
shrl $8, %eax
|
||||
orl $GRUB_TERM_EXTENDED, %eax
|
||||
2:
|
||||
2:
|
||||
popl %edi
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
|
@ -817,6 +819,10 @@ FUNCTION(grub_console_setcursor)
|
|||
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 */
|
||||
|
@ -904,102 +910,4 @@ 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)
|
||||
|
||||
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
|
||||
#include "../int.S"
|
||||
|
|
|
@ -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
|
||||
|
|
276
grub-core/kern/ia64/dl.c
Normal file
276
grub-core/kern/ia64/dl.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
/* dl.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
grub_err_t
|
||||
grub_arch_dl_check_header (void *ehdr)
|
||||
{
|
||||
Elf_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
if (e->e_ident[EI_CLASS] != ELFCLASS64
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|
||||
|| e->e_machine != EM_IA_64)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#define MASK20 ((1 << 20) - 1)
|
||||
#define MASK19 ((1 << 19) - 1)
|
||||
|
||||
struct unaligned_uint32
|
||||
{
|
||||
grub_uint32_t val;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static void
|
||||
add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
|
||||
{
|
||||
struct unaligned_uint32 *p;
|
||||
switch (addr & 3)
|
||||
{
|
||||
case 0:
|
||||
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
|
||||
p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
|
||||
| (p->val & ~(MASK20 << 2)));
|
||||
break;
|
||||
case 1:
|
||||
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
|
||||
p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
|
||||
| (p->val & ~(MASK20 << 3)));
|
||||
break;
|
||||
case 2:
|
||||
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
|
||||
p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
|
||||
| (p->val & ~(MASK20 << 4)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) )
|
||||
|
||||
static grub_uint32_t
|
||||
add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
|
||||
{
|
||||
grub_uint32_t high, mid, low, c;
|
||||
low = (a & 0x00007f);
|
||||
mid = (a & 0x7fc000) >> 7;
|
||||
high = (a & 0x003e00) << 7;
|
||||
c = (low | mid | high) + value;
|
||||
return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
|
||||
}
|
||||
|
||||
static void
|
||||
add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
|
||||
{
|
||||
struct unaligned_uint32 *p;
|
||||
switch (addr & 3)
|
||||
{
|
||||
case 0:
|
||||
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
|
||||
p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2));
|
||||
break;
|
||||
case 1:
|
||||
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
|
||||
p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3));
|
||||
break;
|
||||
case 2:
|
||||
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
|
||||
p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_uint8_t nopm[5] =
|
||||
{
|
||||
/* [MLX] nop.m 0x0 */
|
||||
0x05, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
static grub_uint8_t jump[0x20] =
|
||||
{
|
||||
/* ld8 r16=[r15],8 */
|
||||
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
|
||||
/* mov r14=r1;; */
|
||||
0xe0, 0x00, 0x04, 0x00, 0x42, 0x00,
|
||||
/* nop.i 0x0 */
|
||||
0x00, 0x00, 0x04, 0x00,
|
||||
/* ld8 r1=[r15] */
|
||||
0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,
|
||||
/* mov b6=r16 */
|
||||
0x60, 0x80, 0x04, 0x80, 0x03, 0x00,
|
||||
/* br.few b6;; */
|
||||
0x60, 0x00, 0x80, 0x00
|
||||
};
|
||||
|
||||
struct ia64_trampoline
|
||||
{
|
||||
/* nop.m */
|
||||
grub_uint8_t nop[5];
|
||||
/* movl r15 = addr*/
|
||||
grub_uint8_t addr_hi[6];
|
||||
grub_uint8_t e0;
|
||||
grub_uint8_t addr_lo[4];
|
||||
grub_uint8_t jump[0x20];
|
||||
};
|
||||
|
||||
static void
|
||||
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
|
||||
{
|
||||
COMPILE_TIME_ASSERT (sizeof (struct ia64_trampoline)
|
||||
== GRUB_IA64_DL_TRAMP_SIZE);
|
||||
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
|
||||
tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
|
||||
tr->addr_hi[1] = (addr >> 24) & 0xff;
|
||||
tr->addr_hi[2] = (addr >> 32) & 0xff;
|
||||
tr->addr_hi[3] = (addr >> 40) & 0xff;
|
||||
tr->addr_hi[4] = (addr >> 48) & 0xff;
|
||||
tr->addr_hi[5] = (addr >> 56) & 0xff;
|
||||
tr->e0 = 0xe0;
|
||||
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
|
||||
tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
|
||||
| ((addr & 0x200000) >> 17));
|
||||
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
|
||||
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
|
||||
grub_memcpy (tr->jump, jump, sizeof (tr->jump));
|
||||
}
|
||||
|
||||
/* Relocate symbols. */
|
||||
grub_err_t
|
||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||
{
|
||||
Elf_Ehdr *e = ehdr;
|
||||
Elf_Shdr *s;
|
||||
Elf_Word entsize;
|
||||
unsigned i;
|
||||
grub_uint64_t *gp, *gpptr;
|
||||
struct ia64_trampoline *tr;
|
||||
|
||||
gp = (grub_uint64_t *) mod->base;
|
||||
gpptr = (grub_uint64_t *) mod->got;
|
||||
tr = mod->tramp;
|
||||
|
||||
/* Find a symbol table. */
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == e->e_shnum)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
|
||||
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
|
||||
if (s->sh_type == SHT_RELA)
|
||||
{
|
||||
grub_dl_segment_t seg;
|
||||
|
||||
/* Find the target segment. */
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == s->sh_info)
|
||||
break;
|
||||
|
||||
if (seg)
|
||||
{
|
||||
Elf_Rela *rel, *max;
|
||||
|
||||
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
|
||||
max = rel + s->sh_size / s->sh_entsize;
|
||||
rel < max;
|
||||
rel++)
|
||||
{
|
||||
grub_addr_t addr;
|
||||
Elf_Sym *sym;
|
||||
grub_uint64_t value;
|
||||
|
||||
if (seg->size < (rel->r_offset & ~3))
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"reloc offset is out of the segment");
|
||||
|
||||
addr = (grub_addr_t) seg->addr + rel->r_offset;
|
||||
sym = (Elf_Sym *) ((char *) mod->symtab
|
||||
+ entsize * ELF_R_SYM (rel->r_info));
|
||||
|
||||
/* On the PPC the value does not have an explicit
|
||||
addend, add it. */
|
||||
value = sym->st_value + rel->r_addend;
|
||||
|
||||
switch (ELF_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_IA64_PCREL21B:
|
||||
{
|
||||
grub_uint64_t noff;
|
||||
make_trampoline (tr, value);
|
||||
noff = ((char *) tr - (char *) (addr & ~3)) >> 4;
|
||||
tr++;
|
||||
if (noff & ~MASK19)
|
||||
return grub_error (GRUB_ERR_BAD_OS,
|
||||
"trampoline offset too big (%lx)", noff);
|
||||
add_value_to_slot_20b (addr, noff);
|
||||
}
|
||||
break;
|
||||
case R_IA64_SEGREL64LSB:
|
||||
*(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr;
|
||||
break;
|
||||
case R_IA64_FPTR64LSB:
|
||||
case R_IA64_DIR64LSB:
|
||||
*(grub_uint64_t *) addr += value;
|
||||
break;
|
||||
case R_IA64_PCREL64LSB:
|
||||
*(grub_uint64_t *) addr += value - addr;
|
||||
break;
|
||||
case R_IA64_GPREL22:
|
||||
add_value_to_slot_21 (addr, value - (grub_addr_t) gp);
|
||||
break;
|
||||
|
||||
case R_IA64_LTOFF22X:
|
||||
case R_IA64_LTOFF22:
|
||||
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
|
||||
value = *(grub_uint64_t *) sym->st_value + rel->r_addend;
|
||||
case R_IA64_LTOFF_FPTR22:
|
||||
*gpptr = value;
|
||||
add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
|
||||
gpptr++;
|
||||
break;
|
||||
|
||||
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
|
||||
case R_IA64_LDXMOV:
|
||||
break;
|
||||
default:
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"this relocation (0x%x) is not implemented yet",
|
||||
ELF_R_TYPE (rel->r_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
73
grub-core/kern/ia64/dl_helper.c
Normal file
73
grub-core/kern/ia64/dl_helper.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* dl.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
void
|
||||
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||
grub_size_t *got)
|
||||
{
|
||||
const Elf64_Ehdr *e = ehdr;
|
||||
grub_size_t cntt = 0, cntg = 0;;
|
||||
const Elf64_Shdr *s;
|
||||
Elf64_Word entsize;
|
||||
unsigned i;
|
||||
|
||||
/* Find a symbol table. */
|
||||
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff));
|
||||
i < grub_le_to_cpu16 (e->e_shnum);
|
||||
i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize)))
|
||||
if (grub_le_to_cpu32 (s->sh_type) == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == grub_le_to_cpu16 (e->e_shnum))
|
||||
return;
|
||||
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff));
|
||||
i < grub_le_to_cpu16 (e->e_shnum);
|
||||
i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize)))
|
||||
if (grub_le_to_cpu32 (s->sh_type) == SHT_RELA)
|
||||
{
|
||||
Elf64_Rela *rel, *max;
|
||||
|
||||
for (rel = (Elf64_Rela *) ((char *) e + grub_le_to_cpu32 (s->sh_offset)),
|
||||
max = rel + grub_le_to_cpu32 (s->sh_size) / grub_le_to_cpu16 (s->sh_entsize);
|
||||
rel < max; rel++)
|
||||
switch (ELF64_R_TYPE (grub_le_to_cpu32 (rel->r_info)))
|
||||
{
|
||||
case R_IA64_PCREL21B:
|
||||
cntt++;
|
||||
break;
|
||||
case R_IA64_LTOFF_FPTR22:
|
||||
case R_IA64_LTOFF22X:
|
||||
case R_IA64_LTOFF22:
|
||||
cntg++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*tramp = cntt;
|
||||
*got = cntg;
|
||||
}
|
||||
|
54
grub-core/kern/ia64/efi/init.c
Normal file
54
grub-core/kern/ia64/efi/init.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* init.c - initialize an ia64-based EFI system */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/cache.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/efi/efi.h>
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
grub_efi_init ();
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
{
|
||||
grub_efi_fini ();
|
||||
}
|
||||
|
||||
void
|
||||
grub_arch_sync_caches (void *address, grub_size_t len)
|
||||
{
|
||||
/* Cache line length is at least 32. */
|
||||
grub_uint64_t a = (grub_uint64_t)address & ~0x1f;
|
||||
|
||||
/* Flush data. */
|
||||
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
|
||||
asm volatile ("fc.i %0" : : "r" (a));
|
||||
/* Sync and serialize. Maybe extra. */
|
||||
asm volatile (";; sync.i;; srlz.i;;");
|
||||
}
|
54
grub-core/kern/ia64/efi/startup.S
Normal file
54
grub-core/kern/ia64/efi/startup.S
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/offsets.h>
|
||||
|
||||
.text
|
||||
.psr abi64
|
||||
.psr lsb
|
||||
.lsb
|
||||
|
||||
.global _start
|
||||
.proc _start
|
||||
_start:
|
||||
alloc loc0=ar.pfs,2,4,0,0
|
||||
mov loc1=rp
|
||||
addl loc2=@gprel(grub_efi_image_handle),gp
|
||||
addl loc3=@gprel(grub_efi_system_table),gp
|
||||
;;
|
||||
st8 [loc2]=in0
|
||||
st8 [loc3]=in1
|
||||
br.call.sptk.few rp=grub_main
|
||||
;;
|
||||
mov ar.pfs=loc0
|
||||
mov rp=loc1
|
||||
;;
|
||||
br.ret.sptk.few rp
|
||||
|
||||
.endp _start
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX
|
||||
VARIABLE(grub_prefix)
|
||||
.byte 0
|
||||
/* to be filled by grub-mkimage */
|
||||
|
||||
/*
|
||||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
|
@ -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);
|
||||
|
@ -84,6 +88,9 @@ grub_ieee1275_find_options (void)
|
|||
if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC"))
|
||||
is_qemu = 1;
|
||||
|
||||
if (grub_strncmp (tmp, "PowerMac", sizeof ("PowerMac") - 1) == 0)
|
||||
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS);
|
||||
|
||||
if (is_smartfirmware)
|
||||
{
|
||||
/* Broken in all versions */
|
||||
|
|
|
@ -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,21 @@ grub_machine_init (void)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static grub_uint64_t ieee1275_get_time_ms (void);
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,12 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
|||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"couldn't examine /memory/available property");
|
||||
|
||||
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
|
||||
{
|
||||
address_cells = 1;
|
||||
size_cells = 1;
|
||||
}
|
||||
|
||||
/* Decode each entry and call `hook'. */
|
||||
i = 0;
|
||||
available_size /= sizeof (grub_uint32_t);
|
||||
|
|
|
@ -22,11 +22,14 @@
|
|||
#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. */
|
||||
|
@ -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,92 @@ 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>". */
|
||||
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_printf ("Unsupported type %s for device %s\n", 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)
|
||||
{
|
||||
|
@ -467,3 +509,4 @@ grub_ieee1275_canonicalise_devname (const char *path)
|
|||
grub_free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,8 @@ grub_module_iterate (int (*hook) (struct grub_module_header *header))
|
|||
}
|
||||
}
|
||||
|
||||
/* This is actualy platform-independant but used only on yeeloong and sparc. */
|
||||
#if defined (GRUB_MACHINE_MIPS_YEELOONG) || defined (GRUB_MACHINE_SPARC64)
|
||||
/* This is actualy platform-independant but used only on loongson and sparc. */
|
||||
#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64)
|
||||
grub_addr_t
|
||||
grub_modules_get_end (void)
|
||||
{
|
||||
|
@ -129,27 +129,74 @@ 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;
|
||||
|
||||
grub_register_variable_hook ("root", 0, grub_env_write_root);
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
{
|
||||
char *pptr = NULL;
|
||||
if (grub_prefix[0] == '(')
|
||||
{
|
||||
pptr = grub_strrchr (grub_prefix, ')');
|
||||
if (pptr)
|
||||
{
|
||||
device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1);
|
||||
pptr++;
|
||||
}
|
||||
}
|
||||
if (!pptr)
|
||||
pptr = grub_prefix;
|
||||
if (pptr[0])
|
||||
path = grub_strdup (pptr);
|
||||
}
|
||||
if ((!device || device[0] == ',' || !device[0]) || !path)
|
||||
grub_machine_get_bootlocation (&fwdevice, &fwpath);
|
||||
|
||||
if (prefix)
|
||||
if (!device && fwdevice)
|
||||
device = fwdevice;
|
||||
else if (fwdevice && (device[0] == ',' || !device[0]))
|
||||
{
|
||||
char *dev;
|
||||
/* We have a partition, but still need to fill in the drive. */
|
||||
char *comma, *new_device;
|
||||
|
||||
dev = grub_file_get_device_name (prefix);
|
||||
if (dev)
|
||||
comma = grub_strchr (fwdevice, ',');
|
||||
if (comma)
|
||||
{
|
||||
grub_env_set ("root", dev);
|
||||
grub_free (dev);
|
||||
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;
|
||||
|
||||
prefix = grub_xasprintf ("(%s)%s", device, path ? : "");
|
||||
if (prefix)
|
||||
{
|
||||
grub_env_set ("prefix", prefix);
|
||||
grub_free (prefix);
|
||||
}
|
||||
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 +206,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;
|
||||
|
||||
|
@ -187,8 +234,9 @@ 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");
|
||||
|
||||
grub_register_core_commands ();
|
||||
|
||||
|
|
213
grub-core/kern/mips/arc/init.c
Normal file
213
grub-core/kern/mips/arc/init.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/arc/console.h>
|
||||
#include <grub/cpu/memory.h>
|
||||
#include <grub/cpu/time.h>
|
||||
#include <grub/memory.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/arc/arc.h>
|
||||
#include <grub/offsets.h>
|
||||
|
||||
const char *type_names[] = {
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
NULL,
|
||||
#endif
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
"eisa", "tc", "scsi", "dti", "multi", "disk", "tape", "cdrom", "worm",
|
||||
"serial", "net", "video", "par", "point", "key", "audio", "other",
|
||||
"rdisk", "fdisk", "tape", "modem", "monitor", "print", "pointer",
|
||||
"keyboard", "term", "other", "line", "network", NULL
|
||||
};
|
||||
|
||||
static int
|
||||
iterate_rec (const char *prefix, const struct grub_arc_component *parent,
|
||||
int (*hook) (const char *name,
|
||||
const struct grub_arc_component *comp),
|
||||
int alt_names)
|
||||
{
|
||||
const struct grub_arc_component *comp;
|
||||
FOR_ARC_CHILDREN(comp, parent)
|
||||
{
|
||||
char *name;
|
||||
const char *cname = NULL;
|
||||
if (comp->type < ARRAY_SIZE (type_names))
|
||||
cname = type_names[comp->type];
|
||||
if (!cname)
|
||||
cname = "unknown";
|
||||
if (alt_names)
|
||||
name = grub_xasprintf ("%s/%s%lu", prefix, cname, comp->key);
|
||||
else
|
||||
name = grub_xasprintf ("%s%s(%lu)", prefix, cname, comp->key);
|
||||
if (!name)
|
||||
return 1;
|
||||
if (hook (name, comp))
|
||||
{
|
||||
grub_free (name);
|
||||
return 1;
|
||||
}
|
||||
if (iterate_rec ((parent ? name : prefix), comp, hook, alt_names))
|
||||
{
|
||||
grub_free (name);
|
||||
return 1;
|
||||
}
|
||||
grub_free (name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
grub_arc_iterate_devs (int (*hook) (const char *name,
|
||||
const struct grub_arc_component *comp),
|
||||
int alt_names)
|
||||
{
|
||||
return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, alt_names);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
{
|
||||
struct grub_arc_memory_descriptor *cur = NULL;
|
||||
while (1)
|
||||
{
|
||||
grub_memory_type_t type;
|
||||
cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
|
||||
if (!cur)
|
||||
return GRUB_ERR_NONE;
|
||||
switch (cur->type)
|
||||
{
|
||||
case GRUB_ARC_MEMORY_EXCEPTION_BLOCK:
|
||||
case GRUB_ARC_MEMORY_SYSTEM_PARAMETER_BLOCK:
|
||||
case GRUB_ARC_MEMORY_FW_PERMANENT:
|
||||
default:
|
||||
type = GRUB_MEMORY_RESERVED;
|
||||
break;
|
||||
|
||||
case GRUB_ARC_MEMORY_FW_TEMPORARY:
|
||||
case GRUB_ARC_MEMORY_FREE:
|
||||
case GRUB_ARC_MEMORY_LOADED:
|
||||
case GRUB_ARC_MEMORY_FREE_CONTIGUOUS:
|
||||
type = GRUB_MEMORY_AVAILABLE;
|
||||
break;
|
||||
case GRUB_ARC_MEMORY_BADRAM:
|
||||
type = GRUB_MEMORY_BADRAM;
|
||||
break;
|
||||
}
|
||||
if (hook (((grub_uint64_t) cur->start_page) << 12,
|
||||
((grub_uint64_t) cur->num_pages) << 12, type))
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
extern grub_uint32_t grub_total_modules_size;
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
struct grub_arc_memory_descriptor *cur = NULL;
|
||||
|
||||
grub_console_init_early ();
|
||||
|
||||
/* FIXME: measure this. */
|
||||
grub_arch_cpuclock = 64000000;
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_uint64_t start, end;
|
||||
cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
|
||||
if (!cur)
|
||||
break;
|
||||
if (cur->type != GRUB_ARC_MEMORY_FREE
|
||||
&& cur->type != GRUB_ARC_MEMORY_LOADED
|
||||
&& cur->type != GRUB_ARC_MEMORY_FREE_CONTIGUOUS)
|
||||
continue;
|
||||
start = ((grub_uint64_t) cur->start_page) << 12;
|
||||
end = ((grub_uint64_t) cur->num_pages) << 12;
|
||||
end += start;
|
||||
if ((grub_uint64_t) end > ((GRUB_KERNEL_MIPS_ARC_LINK_ADDR
|
||||
- grub_total_modules_size) & 0x1fffffff))
|
||||
end = ((GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size)
|
||||
& 0x1fffffff);
|
||||
if (end > start)
|
||||
grub_mm_init_region ((void *) (grub_addr_t) (start | 0x80000000),
|
||||
end - start);
|
||||
}
|
||||
|
||||
grub_console_init_lately ();
|
||||
|
||||
grub_arcdisk_init ();
|
||||
}
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size;
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
grub_halt (void)
|
||||
{
|
||||
GRUB_ARC_FIRMWARE_VECTOR->powerdown ();
|
||||
|
||||
grub_millisleep (1500);
|
||||
|
||||
grub_printf ("Shutdown failed\n");
|
||||
grub_refresh ();
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_exit (void)
|
||||
{
|
||||
GRUB_ARC_FIRMWARE_VECTOR->exit ();
|
||||
|
||||
grub_millisleep (1500);
|
||||
|
||||
grub_printf ("Exit failed\n");
|
||||
grub_refresh ();
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_reboot (void)
|
||||
{
|
||||
GRUB_ARC_FIRMWARE_VECTOR->restart ();
|
||||
|
||||
grub_millisleep (1500);
|
||||
|
||||
grub_printf ("Reboot failed\n");
|
||||
grub_refresh ();
|
||||
while (1);
|
||||
}
|
||||
|
|
@ -8,3 +8,38 @@ FUNCTION (grub_cpu_flush_cache)
|
|||
FUNCTION (grub_arch_sync_caches)
|
||||
#include "cache_flush.S"
|
||||
j $ra
|
||||
|
||||
FUNCTION (grub_arch_sync_dma_caches)
|
||||
move $t2, $a0
|
||||
addu $t3, $a0, $a1
|
||||
srl $t2, $t2, 5
|
||||
sll $t2, $t2, 5
|
||||
addu $t3, $t3, 0x1f
|
||||
srl $t3, $t3, 5
|
||||
sll $t3, $t3, 5
|
||||
move $t0, $t2
|
||||
subu $t1, $t3, $t2
|
||||
1:
|
||||
cache 1, 0($t0)
|
||||
addiu $t1, $t1, 0xffff
|
||||
bne $t1, $zero, 1b
|
||||
addiu $t0, $t0, 0x1
|
||||
sync
|
||||
move $t0, $t2
|
||||
subu $t1, $t3, $t2
|
||||
2:
|
||||
cache 0, 0($t0)
|
||||
addiu $t1, $t1, 0xffff
|
||||
bne $t1, $zero, 2b
|
||||
addiu $t0, $t0, 0x1
|
||||
sync
|
||||
move $t0, $t2
|
||||
subu $t1, $t3, $t2
|
||||
2:
|
||||
cache 23, 0($t0)
|
||||
addiu $t1, $t1, 0xffff
|
||||
bne $t1, $zero, 2b
|
||||
addiu $t0, $t0, 0x1
|
||||
sync
|
||||
|
||||
jr $ra
|
|
@ -9,15 +9,22 @@
|
|||
subu $t1, $t3, $t2
|
||||
1:
|
||||
cache 1, 0($t0)
|
||||
addiu $t1, $t1, 0xffff
|
||||
/* 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, 0x1
|
||||
addiu $t0, $t0, 0x4
|
||||
sync
|
||||
move $t0, $t2
|
||||
subu $t1, $t3, $t2
|
||||
2:
|
||||
cache 0, 0($t0)
|
||||
addiu $t1, $t1, 0xffff
|
||||
addiu $t1, $t1, -0x4
|
||||
bne $t1, $zero, 2b
|
||||
addiu $t0, $t0, 0x1
|
||||
addiu $t0, $t0, 0x4
|
||||
sync
|
||||
|
|
|
@ -34,7 +34,7 @@ grub_arch_dl_check_header (void *ehdr)
|
|||
Elf_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
if (e->e_ident[EI_CLASS] != ELFCLASS32
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2MSB
|
||||
|| e->e_machine != EM_MIPS)
|
||||
|
@ -144,14 +144,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
rel < max;
|
||||
rel++)
|
||||
{
|
||||
Elf_Word *addr;
|
||||
grub_uint8_t *addr;
|
||||
Elf_Sym *sym;
|
||||
|
||||
if (seg->size < rel->r_offset)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"reloc offset is out of the segment");
|
||||
|
||||
addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
|
||||
addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset);
|
||||
sym = (Elf_Sym *) ((char *) mod->symtab
|
||||
+ entsize * ELF_R_SYM (rel->r_info));
|
||||
if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy)
|
||||
|
@ -163,7 +163,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
{
|
||||
grub_uint32_t value;
|
||||
Elf_Rel *rel2;
|
||||
|
||||
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
addr += 2;
|
||||
#endif
|
||||
|
||||
/* Handle partner lo16 relocation. Lower part is
|
||||
treated as signed. Hence add 0x8000 to compensate.
|
||||
*/
|
||||
|
@ -175,13 +179,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
&& ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16)
|
||||
{
|
||||
value += *(grub_int16_t *)
|
||||
((char *) seg->addr + rel2->r_offset);
|
||||
((char *) seg->addr + rel2->r_offset
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
+ 2
|
||||
#endif
|
||||
);
|
||||
break;
|
||||
}
|
||||
*(grub_uint16_t *) addr = (value >> 16) & 0xffff;
|
||||
}
|
||||
break;
|
||||
case R_MIPS_LO16:
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
addr += 2;
|
||||
#endif
|
||||
*(grub_uint16_t *) addr += (sym->st_value) & 0xffff;
|
||||
break;
|
||||
case R_MIPS_32:
|
||||
|
@ -208,11 +219,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
case R_MIPS_GOT16:
|
||||
case R_MIPS_CALL16:
|
||||
/* FIXME: reuse*/
|
||||
#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||||
addr += 2;
|
||||
#endif
|
||||
*gpptr = sym->st_value + *(grub_uint16_t *) addr;
|
||||
*(grub_uint16_t *) addr
|
||||
= sizeof (grub_uint32_t) * (gpptr - gp);
|
||||
gpptr++;
|
||||
break;
|
||||
case R_MIPS_JALR:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
grub_free (gp);
|
||||
|
@ -232,6 +248,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
|||
void
|
||||
grub_arch_dl_init_linker (void)
|
||||
{
|
||||
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0);
|
||||
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,17 +18,27 @@
|
|||
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/cpu/time.h>
|
||||
#include <grub/cpu/mips.h>
|
||||
|
||||
/* FIXME: use interrupt to count high. */
|
||||
grub_uint64_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
static grub_uint32_t high = 0;
|
||||
static grub_uint32_t last = 0;
|
||||
grub_uint32_t low;
|
||||
|
||||
asm volatile ("mfc0 %0, " GRUB_CPU_MIPS_COP0_TIMER_COUNT : "=r" (low));
|
||||
if (low < last)
|
||||
high++;
|
||||
last = low;
|
||||
|
||||
return (((grub_uint64_t) high) << 32) | low;
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_set_prefix (void)
|
||||
grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
|
||||
char **path __attribute__ ((unused)))
|
||||
{
|
||||
grub_env_set ("prefix", grub_prefix);
|
||||
}
|
||||
|
||||
extern char _end[];
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
#include <grub/cs5536.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/machine/ec.h>
|
||||
#include <grub/cpu/memory.h>
|
||||
|
||||
extern void grub_video_sm712_init (void);
|
||||
extern void grub_video_sis315pro_init (void);
|
||||
extern void grub_video_init (void);
|
||||
extern void grub_bitmap_init (void);
|
||||
extern void grub_font_init (void);
|
||||
|
@ -41,22 +43,7 @@ extern void grub_at_keyboard_init (void);
|
|||
extern void grub_serial_init (void);
|
||||
extern void grub_terminfo_init (void);
|
||||
extern void grub_keylayouts_init (void);
|
||||
|
||||
/* FIXME: use interrupt to count high. */
|
||||
grub_uint64_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
static grub_uint32_t high = 0;
|
||||
static grub_uint32_t last = 0;
|
||||
grub_uint32_t low;
|
||||
|
||||
asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_TIMER_COUNT : "=r" (low));
|
||||
if (low < last)
|
||||
high++;
|
||||
last = low;
|
||||
|
||||
return (((grub_uint64_t) high) << 32) | low;
|
||||
}
|
||||
extern void grub_boot_init (void);
|
||||
|
||||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
|
@ -78,7 +65,7 @@ init_pci (void)
|
|||
/* FIXME: autoscan for BARs and devices. */
|
||||
switch (pciid)
|
||||
{
|
||||
case GRUB_YEELOONG_OHCI_PCIID:
|
||||
case GRUB_LOONGSON_OHCI_PCIID:
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
|
||||
grub_pci_write (addr, 0x5025000);
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
|
||||
|
@ -90,7 +77,7 @@ init_pci (void)
|
|||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS);
|
||||
grub_pci_write_word (addr, 0x0200 | GRUB_PCI_STATUS_CAPABILITIES);
|
||||
break;
|
||||
case GRUB_YEELOONG_EHCI_PCIID:
|
||||
case GRUB_LOONGSON_EHCI_PCIID:
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
|
||||
grub_pci_write (addr, 0x5026000);
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
|
||||
|
@ -162,7 +149,7 @@ grub_machine_init (void)
|
|||
if (err)
|
||||
grub_fatal ("Couldn't init SMBus: %s\n", grub_errmsg);
|
||||
|
||||
/* Yeeloong has only one memory slot. */
|
||||
/* Yeeloong and Fuloong have only one memory slot. */
|
||||
err = grub_cs5536_read_spd (smbbase, GRUB_SMB_RAM_START_ADDR, &spd);
|
||||
if (err)
|
||||
grub_fatal ("Couldn't read SPD: %s\n", grub_errmsg);
|
||||
|
@ -201,15 +188,19 @@ grub_machine_init (void)
|
|||
relies on a working heap. */
|
||||
grub_video_init ();
|
||||
grub_video_sm712_init ();
|
||||
grub_video_sis315pro_init ();
|
||||
grub_bitmap_init ();
|
||||
grub_font_init ();
|
||||
grub_gfxterm_init ();
|
||||
|
||||
grub_keylayouts_init ();
|
||||
grub_at_keyboard_init ();
|
||||
if (grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG)
|
||||
grub_at_keyboard_init ();
|
||||
|
||||
grub_terminfo_init ();
|
||||
grub_serial_init ();
|
||||
|
||||
grub_boot_init ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -220,8 +211,28 @@ grub_machine_fini (void)
|
|||
void
|
||||
grub_halt (void)
|
||||
{
|
||||
grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG)
|
||||
& ~GRUB_CPU_LOONGSON_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG);
|
||||
switch (grub_arch_machine)
|
||||
{
|
||||
case GRUB_ARCH_MACHINE_FULOONG:
|
||||
{
|
||||
grub_pci_device_t dev;
|
||||
grub_port_t p;
|
||||
if (grub_cs5536_find (&dev))
|
||||
{
|
||||
p = (grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_GPIO_BAR)
|
||||
& GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE;
|
||||
grub_outl ((1 << 13), p + 4);
|
||||
grub_outl ((1 << 29), p);
|
||||
grub_millisleep (5000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GRUB_ARCH_MACHINE_YEELOONG:
|
||||
grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG)
|
||||
& ~GRUB_CPU_YEELOONG_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG);
|
||||
grub_millisleep (1500);
|
||||
break;
|
||||
}
|
||||
|
||||
grub_printf ("Shutdown failed\n");
|
||||
grub_refresh ();
|
||||
|
@ -239,8 +250,17 @@ 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_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#include <grub/kernel.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/cpu/kernel.h>
|
||||
|
||||
#define RAMSIZE (*(grub_uint32_t *) ((16 << 20) - 264))
|
||||
|
||||
grub_uint32_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
static int calln = 0;
|
||||
return calln++;
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
grub_mm_init_region ((void *) GRUB_MACHINE_MEMORY_USABLE,
|
||||
RAMSIZE - (GRUB_MACHINE_MEMORY_USABLE & 0x7fffffff));
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
grub_exit (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_halt (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_reboot (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
{
|
||||
hook (0, RAMSIZE, GRUB_MEMORY_AVAILABLE);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
121
grub-core/kern/mips/qemu_mips/init.c
Normal file
121
grub-core/kern/mips/qemu_mips/init.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include <grub/kernel.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/machine/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_at_keyboard_init (void);
|
||||
extern void grub_serial_init (void);
|
||||
extern void grub_terminfo_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;
|
||||
|
||||
modend = grub_modules_get_end ();
|
||||
grub_mm_init_region ((void *) modend, grub_arch_memsize
|
||||
- (modend - GRUB_ARCH_LOWMEMVSTART));
|
||||
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
|
||||
grub_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
|
||||
grub_machine_fini (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
grub_exit (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_halt (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_reboot (void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
{
|
||||
hook (0, grub_arch_memsize, GRUB_MEMORY_AVAILABLE);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
extern char _end[];
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include <grub/symbol.h>
|
||||
#include <grub/offsets.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <grub/offsets.h>
|
||||
|
||||
#define BASE_ADDR 8
|
||||
|
@ -35,8 +36,8 @@ start:
|
|||
bal cont
|
||||
nop
|
||||
|
||||
. = _start + GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE
|
||||
total_module_size:
|
||||
. = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
|
||||
VARIABLE(grub_total_modules_size)
|
||||
.long 0
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX
|
||||
|
@ -50,7 +51,6 @@ VARIABLE(grub_prefix)
|
|||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
VARIABLE (grub_arch_busclock)
|
||||
.long 0
|
||||
VARIABLE (grub_arch_cpuclock)
|
||||
|
@ -59,21 +59,32 @@ VARIABLE (grub_arch_memsize)
|
|||
.long 0
|
||||
VARIABLE (grub_arch_highmemsize)
|
||||
.long 0
|
||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||
VARIABLE (grub_arch_machine)
|
||||
.long GRUB_ARCH_MACHINE_FULOONG
|
||||
#endif
|
||||
cont:
|
||||
/* Save our base. */
|
||||
move $s0, $ra
|
||||
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
|
||||
lui $t1, %hi(grub_arch_busclock)
|
||||
addiu $t1, %lo(grub_arch_busclock)
|
||||
sw $s4, 8($t1)
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||
lui $t1, %hi(grub_arch_busclock)
|
||||
addiu $t1, %lo(grub_arch_busclock)
|
||||
sw $s2, 0($t1)
|
||||
sw $s3, 4($t1)
|
||||
sw $s4, 8($t1)
|
||||
sw $s5, 12($t1)
|
||||
sw $s7, 16($t1)
|
||||
#endif
|
||||
|
||||
/* Move the modules out of BSS. */
|
||||
#ifndef GRUB_MACHINE_ARC
|
||||
lui $t2, %hi(__bss_start)
|
||||
addiu $t2, %lo(__bss_start)
|
||||
|
||||
|
@ -103,6 +114,7 @@ modulesmovcont:
|
|||
b modulesmovcont
|
||||
addiu $t3, $t3, -1
|
||||
modulesmovdone:
|
||||
#endif
|
||||
|
||||
/* Clean BSS. */
|
||||
|
||||
|
|
|
@ -597,23 +597,23 @@ grub_reverse (char *str)
|
|||
|
||||
/* Divide N by D, return the quotient, and store the remainder in *R. */
|
||||
grub_uint64_t
|
||||
grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
|
||||
grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
|
||||
{
|
||||
/* This algorithm is typically implemented by hardware. The idea
|
||||
is to get the highest bit in N, 64 times, by keeping
|
||||
upper(N * 2^i) = upper((Q * 10 + M) * 2^i), where upper
|
||||
upper(N * 2^i) = (Q * D + M), where upper
|
||||
represents the high 64 bits in 128-bits space. */
|
||||
unsigned bits = 64;
|
||||
unsigned long long q = 0;
|
||||
unsigned m = 0;
|
||||
grub_uint64_t q = 0;
|
||||
grub_uint64_t m = 0;
|
||||
|
||||
/* Skip the slow computation if 32-bit arithmetic is possible. */
|
||||
if (n < 0xffffffff)
|
||||
if (n < 0xffffffff && d < 0xffffffff)
|
||||
{
|
||||
if (r)
|
||||
*r = ((grub_uint32_t) n) % d;
|
||||
*r = ((grub_uint32_t) n) % (grub_uint32_t) d;
|
||||
|
||||
return ((grub_uint32_t) n) / d;
|
||||
return ((grub_uint32_t) n) / (grub_uint32_t) d;
|
||||
}
|
||||
|
||||
while (bits--)
|
||||
|
@ -666,7 +666,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
|
|||
/* BASE == 10 */
|
||||
do
|
||||
{
|
||||
unsigned m;
|
||||
grub_uint64_t m;
|
||||
|
||||
n = grub_divmod64 (n, 10, &m);
|
||||
*p++ = m + '0';
|
||||
|
|
|
@ -311,11 +311,13 @@ grub_memalign (grub_size_t align, grub_size_t size)
|
|||
count++;
|
||||
goto again;
|
||||
|
||||
#if 0
|
||||
case 1:
|
||||
/* Unload unneeded modules. */
|
||||
grub_dl_unload_unneeded ();
|
||||
count++;
|
||||
goto again;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -513,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);
|
||||
|
@ -526,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);
|
||||
|
@ -545,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);
|
||||
|
@ -559,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);
|
||||
|
|
|
@ -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 ();
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -37,80 +37,94 @@
|
|||
.text
|
||||
|
||||
FUNCTION(efi_wrap_0)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_1)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_2)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_3)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
mov %rcx, %r8
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_4)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
mov %r8, %r9
|
||||
mov %rcx, %r8
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_5)
|
||||
subq $40, %rsp
|
||||
subq $48, %rsp
|
||||
mov %r9, 32(%rsp)
|
||||
mov %r8, %r9
|
||||
mov %rcx, %r8
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $40, %rsp
|
||||
addq $48, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_6)
|
||||
subq $56, %rsp
|
||||
mov 56+8(%rsp), %rax
|
||||
subq $64, %rsp
|
||||
mov 64+8(%rsp), %rax
|
||||
mov %rax, 40(%rsp)
|
||||
mov %r9, 32(%rsp)
|
||||
mov %r8, %r9
|
||||
mov %rcx, %r8
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $56, %rsp
|
||||
addq $64, %rsp
|
||||
ret
|
||||
|
||||
FUNCTION(efi_wrap_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 $88, %rsp
|
||||
mov 88+40(%rsp), %rax
|
||||
subq $96, %rsp
|
||||
mov 96+40(%rsp), %rax
|
||||
mov %rax, 72(%rsp)
|
||||
mov 88+32(%rsp), %rax
|
||||
mov 96+32(%rsp), %rax
|
||||
mov %rax, 64(%rsp)
|
||||
mov 88+24(%rsp), %rax
|
||||
mov 96+24(%rsp), %rax
|
||||
mov %rax, 56(%rsp)
|
||||
mov 88+16(%rsp), %rax
|
||||
mov 96+16(%rsp), %rax
|
||||
mov %rax, 48(%rsp)
|
||||
mov 88+8(%rsp), %rax
|
||||
mov 96+8(%rsp), %rax
|
||||
mov %rax, 40(%rsp)
|
||||
mov %r9, 32(%rsp)
|
||||
mov %r8, %r9
|
||||
mov %rcx, %r8
|
||||
mov %rsi, %rcx
|
||||
call *%rdi
|
||||
addq $88, %rsp
|
||||
addq $96, %rsp
|
||||
ret
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue