Example #1
0
static grub_err_t
grub_biosdisk_open (const char *name, grub_disk_t disk)
{
  grub_uint64_t total_sectors = 0;
  int drive;
  struct grub_biosdisk_data *data;

  drive = grub_biosdisk_get_drive (name);
  if (drive < 0)
    return grub_errno;

  disk->has_partitions = ((drive & 0x80) && (drive != cd_drive));
  disk->id = drive;

  data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data));
  if (! data)
    return grub_errno;

  data->drive = drive;

  if ((cd_drive) && (drive == cd_drive))
    {
      data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
      data->sectors = 32;
      total_sectors = GRUB_ULONG_MAX;  /* TODO: get the correct size.  */
    }
  else if (drive & 0x80)
    {
      /* HDD */
      int version;

      version = grub_biosdisk_check_int13_extensions (drive);
      if (version)
	{
	  struct grub_biosdisk_drp *drp
	    = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;

	  /* Clear out the DRP.  */
	  grub_memset (drp, 0, sizeof (*drp));
	  drp->size = sizeof (*drp);
	  if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp))
	    {
	      data->flags = GRUB_BIOSDISK_FLAG_LBA;

	      if (drp->total_sectors)
		total_sectors = drp->total_sectors;
	      else
                /* Some buggy BIOSes doesn't return the total sectors
                   correctly but returns zero. So if it is zero, compute
                   it by C/H/S returned by the LBA BIOS call.  */
                total_sectors = drp->cylinders * drp->heads * drp->sectors;
	    }
	}
    }

  if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM))
    {
      if (grub_biosdisk_get_diskinfo_standard (drive,
					       &data->cylinders,
					       &data->heads,
					       &data->sectors) != 0)
        {
	  if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA))
	    {
	      data->sectors = 63;
	      data->heads = 255;
	      data->cylinders
		= grub_divmod64 (total_sectors
				 + data->heads * data->sectors - 1,
				 data->heads * data->sectors, 0);
	    }
	  else
	    {
	      grub_free (data);
	      return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name);
	    }
        }

      if (! total_sectors)
        total_sectors = data->cylinders * data->heads * data->sectors;
    }

  disk->total_sectors = total_sectors;
  disk->data = data;

  return GRUB_ERR_NONE;
}
Example #2
0
static struct grub_biosdisk_data *
get_drive_geom (int drive)
{
  int i;
  struct grub_biosdisk_data *data = grub_biosdisk_geom;
  grub_uint64_t total_sectors = 0;
  unsigned long cylinders;
  int is_fb = 0;
  struct fb_mbr *m;

  for (i = 0; i < grub_biosdisk_num; i++, data++)
    if (data->drive == drive)
      return data;

  m = (struct fb_mbr *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
  if (drive != cd_drive)
    {
      if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
				     GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
	return 0;
      is_fb = ((m->fb_magic == FB_MAGIC_LONG) && (m->end_magic == 0xaa55));
    }
  else
    is_fb = 0;

  if ((grub_biosdisk_num & (DISK_NUM_INC - 1)) == 0)
    {
      grub_biosdisk_geom = grub_realloc (grub_biosdisk_geom,
					 (grub_biosdisk_num + DISK_NUM_INC) *
					 sizeof (*data));
      if (! grub_biosdisk_geom)
	return 0;
    }

  data = &grub_biosdisk_geom[grub_biosdisk_num++];
  grub_memset (data, 0, sizeof (*data));
  data->drive = drive;

  if (drive == cd_drive)
    {
      data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
      data->max_sectors = data->sectors = 32;
      data->total_sectors = GRUB_ULONG_MAX;  /* TODO: get the correct size.  */
      return data;
    }

  if (drive & 0x80)
    {
      /* HDD */
      int version;

      version = grub_biosdisk_check_int13_extensions (drive);
      if (version)
	{
	  struct grub_biosdisk_drp *drp
	    = (struct grub_biosdisk_drp *)
	    (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 512);

	  /* Clear out the DRP.  */
	  grub_memset (drp, 0, sizeof (*drp));
	  drp->size = sizeof (*drp);
	  if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp))
	    {
	      data->flags = GRUB_BIOSDISK_FLAG_LBA;

	      if (drp->cylinders == 65535)
		total_sectors = GRUB_ULONG_MAX;
	      else if (drp->total_sectors)
		total_sectors = drp->total_sectors;
	      else
                /* Some buggy BIOSes doesn't return the total sectors
                   correctly but returns zero. So if it is zero, compute
                   it by C/H/S returned by the LBA BIOS call.  */
                total_sectors = drp->cylinders * drp->heads * drp->sectors;
	    }
	}

      data->sectors = 63;
      data->heads = 255;
      cylinders = 0;
      grub_biosdisk_get_diskinfo_standard (drive, &cylinders,
					   &data->heads, &data->sectors);
    }
  else
    {
      grub_uint16_t t;

      t = *((grub_uint16_t *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 0x18));
      data->sectors = ((t > 0) && (t <= 63)) ? t : 18;
      t = *((grub_uint16_t *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 0x1a));
      data->heads = ((t > 0) && (t <= 255)) ? t : 2;
      cylinders = 1024;
    }

  data->max_sectors = 63;
  if (is_fb)
    {
      grub_uint16_t ofs = m->lba;

      data->max_sectors = m->max_sec;
      if (data->max_sectors >= 0x80)
	{
	  data->max_sectors &= 0x7f;
	  data->flags &= ~GRUB_BIOSDISK_FLAG_LBA;
	}

      if (! (data->flags & GRUB_BIOSDISK_FLAG_LBA))
	{
	  grub_uint16_t lba;

	  if (grub_biosdisk_rw_standard (0x02, drive,
					 0, 1, 1, 1,
					 GRUB_MEMORY_MACHINE_SCRATCH_SEG))
	    goto next;

	  lba = m->end_magic;
	  if (lba == 0xaa55)
	    {
	      if (m->fb_magic != FB_MAGIC_LONG)
		goto next;
	      else
		lba = m->lba;
	    }

	  data->sectors = lba - ofs;

	  if (grub_biosdisk_rw_standard (0x02, drive,
					 1, 0, 1, 1,
					 GRUB_MEMORY_MACHINE_SCRATCH_SEG))
	    goto next;

	  lba = m->end_magic;
	  if (lba == 0xaa55)
	    goto next;

	  data->heads = (lba - ofs) / data->sectors;
	}

      data->flags |= GRUB_BIOSDISK_FLAG_FB;
    }

  if ((data->flags & GRUB_BIOSDISK_FLAG_LBA) &&
      (data->max_sectors == 63))
    data->max_sectors = GRUB_BIOSDISK_MAX_SECTORS;

 next:
  cylinders *= data->heads * data->sectors;
  if (total_sectors < cylinders)
    total_sectors = cylinders;

  data->total_sectors = total_sectors;
  return data;
}