Initial variable sector size support

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-03-29 02:02:55 +02:00
parent f329eda79e
commit 09573499ff
7 changed files with 155 additions and 96 deletions

View file

@ -536,8 +536,13 @@ grub_efidisk_open (const char *name, struct grub_disk *disk)
and total sectors should be replaced with total blocks. */ and total sectors should be replaced with total blocks. */
grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n", grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
m, (unsigned long long) m->last_block, m->block_size); m, (unsigned long long) m->last_block, m->block_size);
disk->total_sectors = (m->last_block disk->total_sectors = m->last_block;
* (m->block_size >> GRUB_DISK_SECTOR_BITS)); if (m->blocksize & (m->blocksize - 1) || !m->blocksize)
return grub_error (GRUB_ERR_IO, "invalid sector size %d",
m->blocksize);
for (disk->log_sector_size = 0;
(1 << disk->log_sector_size) < m->blocksize;
disk->log_sector_size++);
disk->data = d; disk->data = d;
grub_dprintf ("efidisk", "opening %s succeeded\n", name); grub_dprintf ("efidisk", "opening %s succeeded\n", name);
@ -571,8 +576,8 @@ grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
(unsigned long) size, (unsigned long long) sector, disk->name); (unsigned long) size, (unsigned long long) sector, disk->name);
status = efi_call_5 (dio->read, dio, bio->media->media_id, status = efi_call_5 (dio->read, dio, bio->media->media_id,
(grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, (grub_efi_uint64_t) sector << disk->log_sector_size,
(grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, (grub_efi_uintn_t) size << disk->log_sector_size,
buf); buf);
if (status != GRUB_EFI_SUCCESS) if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error"); return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error");
@ -599,8 +604,8 @@ grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
(unsigned long) size, (unsigned long long) sector, disk->name); (unsigned long) size, (unsigned long long) sector, disk->name);
status = efi_call_5 (dio->write, dio, bio->media->media_id, status = efi_call_5 (dio->write, dio, bio->media->media_id,
(grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, (grub_efi_uint64_t) sector << disk->log_sector_size,
(grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, (grub_efi_uintn_t) size << disk->log_sector_size,
(void *) buf); (void *) buf);
if (status != GRUB_EFI_SUCCESS) if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error"); return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error");

View file

@ -338,7 +338,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
if ((cd_drive) && (drive == cd_drive)) if ((cd_drive) && (drive == cd_drive))
{ {
data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
data->sectors = 32; data->sectors = 8;
disk->log_sector_size = 11;
/* TODO: get the correct size. */ /* TODO: get the correct size. */
total_sectors = GRUB_DISK_SIZE_UNKNOWN; total_sectors = GRUB_DISK_SIZE_UNKNOWN;
} }
@ -347,6 +348,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
/* HDD */ /* HDD */
int version; int version;
disk->log_sector_size = 9;
version = grub_biosdisk_check_int13_extensions (drive); version = grub_biosdisk_check_int13_extensions (drive);
if (version) if (version)
{ {
@ -367,6 +370,15 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
correctly but returns zero. So if it is zero, compute correctly but returns zero. So if it is zero, compute
it by C/H/S returned by the LBA BIOS call. */ it by C/H/S returned by the LBA BIOS call. */
total_sectors = drp->cylinders * drp->heads * drp->sectors; total_sectors = drp->cylinders * drp->heads * drp->sectors;
if (drp->bytes_per_sector
&& !(drp->bytes_per_sector & (drp->bytes_per_sector - 1))
&& drp->bytes_per_sector >= 512
&& drp->bytes_per_sector <= 16384)
{
for (disk->log_sector_size = 0;
(1 << disk->log_sector_size) < drp->bytes_per_sector;
disk->log_sector_size++);
}
} }
} }
} }
@ -429,7 +441,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
+ (data->sectors + (data->sectors
<< GRUB_DISK_SECTOR_BITS)); << disk->log_sector_size));
dap->length = sizeof (*dap); dap->length = sizeof (*dap);
dap->reserved = 0; dap->reserved = 0;
dap->blocks = size; dap->blocks = size;
@ -443,9 +455,6 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
if (cmd) if (cmd)
return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom"); return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom");
dap->blocks = ALIGN_UP (dap->blocks, 4) >> 2;
dap->block >>= 2;
for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++) for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++)
if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap)) if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap))
break; break;
@ -501,10 +510,12 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
/* Return the number of sectors which can be read safely at a time. */ /* Return the number of sectors which can be read safely at a time. */
static grub_size_t static grub_size_t
get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors) get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector)
{ {
grub_size_t size; grub_size_t size;
grub_uint32_t offset; grub_uint32_t offset;
struct grub_biosdisk_data *data = disk->data;
grub_uint32_t sectors = data->sectors;
/* OFFSET = SECTOR % SECTORS */ /* OFFSET = SECTOR % SECTORS */
grub_divmod64 (sector, sectors, &offset); grub_divmod64 (sector, sectors, &offset);
@ -512,8 +523,8 @@ get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors)
size = sectors - offset; size = sectors - offset;
/* Limit the max to 0x7f because of Phoenix EDD. */ /* Limit the max to 0x7f because of Phoenix EDD. */
if (size > 0x7f) if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size))
size = 0x7f; size = ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size);
return size; return size;
} }
@ -522,21 +533,11 @@ static grub_err_t
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf) grub_size_t size, char *buf)
{ {
struct grub_biosdisk_data *data = disk->data;
while (size) while (size)
{ {
grub_size_t len; grub_size_t len;
grub_size_t cdoff = 0;
len = get_safe_sectors (sector, data->sectors); len = get_safe_sectors (disk, sector);
if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
{
cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS;
len = ALIGN_UP (sector + len, 4) - (sector & ~3);
sector &= ~3;
}
if (len > size) if (len > size)
len = size; len = size;
@ -545,9 +546,10 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
GRUB_MEMORY_MACHINE_SCRATCH_SEG)) GRUB_MEMORY_MACHINE_SCRATCH_SEG))
return grub_errno; return grub_errno;
grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff), grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
len << GRUB_DISK_SECTOR_BITS); len << disk->log_sector_size);
buf += len << GRUB_DISK_SECTOR_BITS;
buf += len << disk->log_sector_size;
sector += len; sector += len;
size -= len; size -= len;
} }
@ -568,18 +570,18 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
{ {
grub_size_t len; grub_size_t len;
len = get_safe_sectors (sector, data->sectors); len = get_safe_sectors (disk, sector);
if (len > size) if (len > size)
len = size; len = size;
grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf, grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf,
len << GRUB_DISK_SECTOR_BITS); len << disk->log_sector_size);
if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len, if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len,
GRUB_MEMORY_MACHINE_SCRATCH_SEG)) GRUB_MEMORY_MACHINE_SCRATCH_SEG))
return grub_errno; return grub_errno;
buf += len << GRUB_DISK_SECTOR_BITS; buf += len << disk->log_sector_size;
sector += len; sector += len;
size -= len; size -= len;
} }

View file

@ -463,15 +463,20 @@ grub_scsi_open (const char *name, grub_disk_t disk)
return err; return err;
} }
/* SCSI blocks can be something else than 512, although GRUB disk->total_sectors = scsi->size;
wants 512 byte blocks. */ if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize)
disk->total_sectors = ((grub_uint64_t)scsi->size {
* (grub_uint64_t)scsi->blocksize) grub_free (scsi);
>> GRUB_DISK_SECTOR_BITS; return grub_error (GRUB_ERR_IO, "invalid sector size %d",
scsi->blocksize);
}
for (disk->log_sector_size = 0;
(1 << disk->log_sector_size) < scsi->blocksize;
disk->log_sector_size++);
grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n", grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
scsi->size, scsi->blocksize); scsi->size, scsi->blocksize);
grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n", grub_dprintf ("scsi", "Disk total sectors = %llu\n",
(unsigned long long) disk->total_sectors); (unsigned long long) disk->total_sectors);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
@ -501,25 +506,6 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
scsi = disk->data; scsi = disk->data;
/* SCSI sectors are variable in size. GRUB uses 512 byte
sectors. */
if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
{
unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
if (spb == 0 || (scsi->blocksize & (GRUB_DISK_SECTOR_SIZE - 1)) != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported SCSI block size");
grub_uint32_t sector_mod = 0;
sector = grub_divmod64 (sector, spb, &sector_mod);
if (! (sector_mod == 0 && size % spb == 0))
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unaligned SCSI read not supported");
size /= spb;
}
/* Depending on the type, select a read function. */ /* Depending on the type, select a read function. */
switch (scsi->devtype) switch (scsi->devtype)
{ {

View file

@ -247,6 +247,7 @@ grub_disk_open (const char *name)
disk = (grub_disk_t) grub_zalloc (sizeof (*disk)); disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
if (! disk) if (! disk)
return 0; return 0;
disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
p = find_part_sep (name); p = find_part_sep (name);
if (p) if (p)
@ -266,7 +267,6 @@ grub_disk_open (const char *name)
if (! disk->name) if (! disk->name)
goto fail; goto fail;
for (dev = grub_disk_dev_list; dev; dev = dev->next) for (dev = grub_disk_dev_list; dev; dev = dev->next)
{ {
if ((dev->open) (raw, disk) == GRUB_ERR_NONE) if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
@ -282,6 +282,14 @@ grub_disk_open (const char *name)
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk"); grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk");
goto fail; 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; disk->dev = dev;
@ -373,14 +381,23 @@ grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
*sector += start; *sector += start;
} }
if (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) || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector) >> 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_error (GRUB_ERR_OUT_OF_RANGE, "out of disk");
return GRUB_ERR_NONE; 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);
}
/* Read data from the disk. */ /* Read data from the disk. */
grub_err_t grub_err_t
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
@ -433,27 +450,39 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
else else
{ {
/* Otherwise read data from the disk actually. */ /* Otherwise read data from the disk actually. */
if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors if ((disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN
|| (disk->dev->read) (disk, start_sector, && start_sector + GRUB_DISK_CACHE_SIZE
GRUB_DISK_CACHE_SIZE, tmp_buf) > (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
|| (disk->dev->read) (disk, transform_sector (disk, start_sector),
1 << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS
- disk->log_sector_size), tmp_buf)
!= GRUB_ERR_NONE) != GRUB_ERR_NONE)
{ {
/* Uggh... Failed. Instead, just read necessary data. */ /* Uggh... Failed. Instead, just read necessary data. */
unsigned num; unsigned num;
char *p; char *p;
grub_disk_addr_t aligned_sector;
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1) aligned_sector = (sector & ~((1 << (disk->log_sector_size
>> GRUB_DISK_SECTOR_BITS); - GRUB_DISK_SECTOR_BITS))
- 1));
real_offset += ((sector - aligned_sector)
<< GRUB_DISK_SECTOR_BITS);
num = ((size + real_offset + (1 << (disk->log_sector_size))
- 1) >> (disk->log_sector_size));
p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS); p = grub_realloc (tmp_buf, num << disk->log_sector_size);
if (!p) if (!p)
goto finish; goto finish;
tmp_buf = p; tmp_buf = p;
if ((disk->dev->read) (disk, sector, num, tmp_buf)) if ((disk->dev->read) (disk, transform_sector (disk,
aligned_sector),
num, tmp_buf))
{ {
grub_error_push (); grub_error_push ();
grub_dprintf ("disk", "%s read failed\n", disk->name); grub_dprintf ("disk", "%s read failed\n", disk->name);
@ -528,25 +557,31 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, const void *buf) grub_off_t offset, grub_size_t size, const void *buf)
{ {
unsigned real_offset; unsigned real_offset;
grub_disk_addr_t aligned_sector;
grub_dprintf ("disk", "Writing `%s'...\n", disk->name); grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE) if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
return -1; 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) 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_size_t len;
grub_partition_t part; grub_partition_t part;
part = disk->partition; part = disk->partition;
disk->partition = 0; 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) != GRUB_ERR_NONE)
{ {
disk->partition = part; disk->partition = part;
@ -554,7 +589,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
} }
disk->partition = part; disk->partition = part;
len = GRUB_DISK_SECTOR_SIZE - real_offset; len = (1 << disk->log_sector_size) - real_offset;
if (len > size) if (len > size)
len = size; len = size;
@ -565,7 +600,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) if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE)
goto finish; goto finish;
sector++; sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
buf = (char *) buf + len; buf = (char *) buf + len;
size -= len; size -= len;
real_offset = 0; real_offset = 0;
@ -575,8 +610,8 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t len; grub_size_t len;
grub_size_t n; grub_size_t n;
len = size & ~(GRUB_DISK_SECTOR_SIZE - 1); len = size & ~((1 << disk->log_sector_size) - 1);
n = size >> GRUB_DISK_SECTOR_BITS; n = size >> disk->log_sector_size;
if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE) if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
goto finish; goto finish;
@ -599,6 +634,8 @@ grub_disk_get_size (grub_disk_t disk)
{ {
if (disk->partition) if (disk->partition)
return grub_partition_get_len (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 else
return disk->total_sectors; return GRUB_DISK_SIZE_UNKNOWN;
} }

View file

@ -42,6 +42,7 @@
#ifdef __linux__ #ifdef __linux__
# include <sys/ioctl.h> /* ioctl */ # include <sys/ioctl.h> /* ioctl */
# include <sys/mount.h>
# if !defined(__GLIBC__) || \ # if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */ /* Maybe libc doesn't have large file support. */
@ -264,6 +265,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
# else # else
unsigned long long nr; unsigned long long nr;
# endif # endif
int sector_size;
int fd; int fd;
fd = open (map[drive].device, O_RDONLY); fd = open (map[drive].device, O_RDONLY);
@ -295,16 +297,28 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
goto fail; goto fail;
} }
if (ioctl (fd, BLKSSZGET, &sector_size))
{
close (fd); close (fd);
goto fail;
}
close (fd);
if (sector_size & (sector_size - 1) || !sector_size)
goto fail;
for (disk->log_sector_size = 0;
(1 << disk->log_sector_size) < sector_size;
disk->log_sector_size++);
# if defined (__APPLE__) # if defined (__APPLE__)
disk->total_sectors = nr; disk->total_sectors = nr;
# elif defined(__NetBSD__) # elif defined(__NetBSD__)
disk->total_sectors = label.d_secperunit; disk->total_sectors = label.d_secperunit;
# else # else
disk->total_sectors = nr / 512; disk->total_sectors = nr >> disk->log_sector_size;
if (nr % 512) if (nr & ((1 << disk->log_sector_size) - 1))
grub_util_error ("unaligned device size"); grub_util_error ("unaligned device size");
# endif # endif
@ -321,7 +335,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
if (stat (map[drive].device, &st) < 0) if (stat (map[drive].device, &st) < 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device);
disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS; disk->total_sectors = st.st_size >> disk->log_sector_size;
grub_util_info ("the size of %s is %lu", name, disk->total_sectors); grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
@ -760,7 +774,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh); loff_t *, res, uint, wh);
offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS; offset = (loff_t) sector << disk->log_sector_size;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{ {
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
@ -770,7 +784,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
} }
#else #else
{ {
off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS; off_t offset = (off_t) sector << disk->log_sector_size;
if (lseek (fd, offset, SEEK_SET) != offset) if (lseek (fd, offset, SEEK_SET) != offset)
{ {
@ -870,20 +884,21 @@ 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 sectors that are read together with the MBR in one read. It
should only remap the MBR, so we split the read in two should only remap the MBR, so we split the read in two
parts. -jochen */ parts. -jochen */
if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) if (nread (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); grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
close (fd); close (fd);
return grub_errno; return grub_errno;
} }
buf += GRUB_DISK_SECTOR_SIZE; buf += (1 << disk->log_sector_size);
size--; size--;
} }
#endif /* __linux__ */ #endif /* __linux__ */
if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) if (nread (fd, buf, size << disk->log_sector_size)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
return grub_errno; return grub_errno;
@ -916,8 +931,8 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
if (fd < 0) if (fd < 0)
return grub_errno; return grub_errno;
if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS) if (nwrite (fd, buf, size << disk->log_sector_size)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device); grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
return grub_errno; return grub_errno;

View file

@ -90,8 +90,11 @@ grub_partition_msdos_iterate (grub_disk_t disk,
{ {
e = mbr.entries + p.index; e = mbr.entries + p.index;
p.start = p.offset + grub_le_to_cpu32 (e->start) - delta; p.start = p.offset
p.len = grub_le_to_cpu32 (e->length); + (grub_le_to_cpu32 (e->start)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta;
p.len = grub_le_to_cpu32 (e->length)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
p.msdostype = e->type; p.msdostype = e->type;
grub_dprintf ("partition", grub_dprintf ("partition",
@ -126,7 +129,9 @@ grub_partition_msdos_iterate (grub_disk_t disk,
if (grub_msdos_partition_is_extended (e->type)) if (grub_msdos_partition_is_extended (e->type))
{ {
p.offset = ext_offset + grub_le_to_cpu32 (e->start); p.offset = ext_offset
+ (grub_le_to_cpu32 (e->start)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
if (! ext_offset) if (! ext_offset)
ext_offset = p.offset; ext_offset = p.offset;
@ -204,8 +209,11 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
e = mbr.entries + i; e = mbr.entries + i;
if (!grub_msdos_partition_is_empty (e->type) if (!grub_msdos_partition_is_empty (e->type)
&& end > offset + grub_le_to_cpu32 (e->start)) && end > offset
end = offset + grub_le_to_cpu32 (e->start); + (grub_le_to_cpu32 (e->start)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
end = offset + (grub_le_to_cpu32 (e->start)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
/* If this is a GPT partition, this MBR is just a dummy. */ /* If this is a GPT partition, this MBR is just a dummy. */
if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0)
@ -219,7 +227,9 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
if (grub_msdos_partition_is_extended (e->type)) if (grub_msdos_partition_is_extended (e->type))
{ {
offset = ext_offset + grub_le_to_cpu32 (e->start); offset = ext_offset
+ (grub_le_to_cpu32 (e->start)
<< (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
if (! ext_offset) if (! ext_offset)
ext_offset = offset; ext_offset = offset;

View file

@ -100,6 +100,9 @@ struct grub_disk
/* The total number of sectors. */ /* The total number of sectors. */
grub_uint64_t total_sectors; grub_uint64_t total_sectors;
/* Logarithm of sector size. */
unsigned int log_sector_size;
/* The id used by the disk cache manager. */ /* The id used by the disk cache manager. */
unsigned long id; unsigned long id;
@ -132,9 +135,10 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
/* The maximum number of disk caches. */ /* The maximum number of disk caches. */
#define GRUB_DISK_CACHE_NUM 1021 #define GRUB_DISK_CACHE_NUM 1021
/* The size of a disk cache in sector units. */ /* The size of a disk cache in 512B units. Must be at least as big as the
#define GRUB_DISK_CACHE_SIZE 8 largest supported sector size, currently 16K. */
#define GRUB_DISK_CACHE_BITS 3 #define GRUB_DISK_CACHE_BITS 6
#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
/* Return value of grub_disk_get_size() in case disk size is unknown. */ /* Return value of grub_disk_get_size() in case disk size is unknown. */
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL