static int grub_biosdisk_iterate (int (*hook) (const char *name)) { int drive; int num_floppies; /* For hard disks, attempt to read the MBR. */ for (drive = 0x80; drive < 0x90; drive++) { if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) { grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive); break; } if (grub_biosdisk_call_hook (hook, drive)) return 1; } if (cd_drive) { if (grub_biosdisk_call_hook (hook, cd_drive)) return 1; } /* For floppy disks, we can get the number safely. */ num_floppies = grub_biosdisk_get_num_floppies (); for (drive = 0; drive < num_floppies; drive++) if (grub_biosdisk_call_hook (hook, drive)) return 1; return 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; }