diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index ddcc666..75b8845 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,15 +27,12 @@ #include #include -static int cd_start = GRUB_BIOSDISK_MACHINE_CDROM_START; -static int cd_count = 0; - static int grub_biosdisk_get_drive (const char *name) { unsigned long drive; - if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd') + if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd') goto fail; drive = grub_strtoul (name + 2, 0, 10); @@ -43,8 +41,6 @@ grub_biosdisk_get_drive (const char *name) if (name[0] == 'h') drive += 0x80; - else if (name[0] == 'c') - drive += cd_start; return (int) drive ; @@ -58,10 +54,7 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive) { char name[10]; - if (drive >= cd_start) - grub_sprintf (name, "cd%d", drive - cd_start); - else - grub_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); + grub_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); return hook (name); } @@ -78,7 +71,8 @@ grub_biosdisk_iterate (int (*hook) (const char *name)) return 1; /* For hard disks, attempt to read the MBR. */ - for (drive = 0x80; drive < 0x90; drive++) + for (drive = 0x80; + drive < GRUB_BIOSDISK_MACHINE_CDROM_START; drive++) { if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) @@ -91,9 +85,30 @@ grub_biosdisk_iterate (int (*hook) (const char *name)) return 1; } - for (drive = cd_start; drive < cd_start + cd_count; drive++) - if (grub_biosdisk_call_hook (hook, drive)) - return 1; + if (grub_boot_drive >= drive) + for (drive = grub_boot_drive; + drive < GRUB_BIOSDISK_MACHINE_CDROM_END; drive++) + { + struct grub_biosdisk_dap *dap; + + dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + + (4 << GRUB_DISK_SECTOR_BITS)); + + dap->length = sizeof (*dap); + dap->reserved = 0; + dap->blocks = 1; + dap->buffer = GRUB_MEMORY_MACHINE_SCRATCH_SEG << 16; + dap->block = 0; + + if (grub_biosdisk_rw_int13_extensions (0x42, drive, dap)) + { + grub_dprintf ("disk", "Read error when probing cd 0x%2x\n", drive); + break; + } + + if (grub_biosdisk_call_hook (hook, drive)) + return 1; + } return 0; } @@ -109,7 +124,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) if (drive < 0) return grub_errno; - disk->has_partitions = ((drive & 0x80) && (drive < cd_start)); + disk->has_partitions = ((drive & 0x80) != 0); disk->id = drive; data = (struct grub_biosdisk_data *) grub_malloc (sizeof (*data)); @@ -119,42 +134,54 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) data->drive = drive; data->flags = 0; - if (drive >= cd_start) + if (drive & 0x80) { - data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; - data->sectors = 32; - total_sectors = 9000000; /* 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; - } - } + struct grub_biosdisk_cdrp *cdrp + = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + grub_memset (cdrp, 0, sizeof (*cdrp)); + cdrp->size = sizeof (*cdrp); + if ((! grub_biosdisk_get_cdinfo_int13_extensions (drive, cdrp)) && + (cdrp->drive_no == drive) && + ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK) + == GRUB_BIOSDISK_CDTYPE_NO_EMUL)) + { + disk->has_partitions = 0; + data->flags = (GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM); + data->sectors = 32; + total_sectors = 9000000; /* TODO: get the correct size. */ + } + else + { + /* 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 (drive < cd_start) + if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM)) { if (grub_biosdisk_get_diskinfo_standard (drive, &data->cylinders, @@ -364,8 +391,6 @@ grub_disk_biosdisk_fini (void) GRUB_MOD_INIT(biosdisk) { - int drive, found = 0; - if (grub_disk_firmware_is_tainted) { grub_printf ("Firmware is marked as tainted, refusing to initialize.\n"); @@ -374,24 +399,6 @@ GRUB_MOD_INIT(biosdisk) grub_disk_firmware_fini = grub_disk_biosdisk_fini; grub_disk_dev_register (&grub_biosdisk_dev); - - for (drive = GRUB_BIOSDISK_MACHINE_CDROM_START; - drive < GRUB_BIOSDISK_MACHINE_CDROM_END; drive++) - { - if (grub_biosdisk_check_int13_extensions (drive)) - { - if (! found) - cd_start = drive; - found++; - } - else - { - if (found) - break; - } - } - - cd_count = found; } GRUB_MOD_FINI(biosdisk) diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h index 770f942..cba09d2 100644 --- a/include/grub/i386/pc/biosdisk.h +++ b/include/grub/i386/pc/biosdisk.h @@ -25,9 +25,18 @@ #define GRUB_BIOSDISK_FLAG_LBA 1 #define GRUB_BIOSDISK_FLAG_CDROM 2 -#define GRUB_BIOSDISK_MACHINE_CDROM_START 0xe0 +#define GRUB_BIOSDISK_MACHINE_CDROM_START 0x9f #define GRUB_BIOSDISK_MACHINE_CDROM_END 0xf0 +#define GRUB_BIOSDISK_CDTYPE_NO_EMUL 0 +#define GRUB_BIOSDISK_CDTYPE_1_2_M 1 +#define GRUB_BIOSDISK_CDTYPE_1_44_M 2 +#define GRUB_BIOSDISK_CDTYPE_2_88_M 3 +#define GRUB_BIOSDISK_CDTYPE_2_88_M 3 +#define GRUB_BIOSDISK_CDTYPE_HARDDISK 4 + +#define GRUB_BIOSDISK_CDTYPE_MASK 0xF + struct grub_biosdisk_data { int drive; @@ -74,6 +83,23 @@ struct grub_biosdisk_drp grub_uint8_t dummy[16]; } __attribute__ ((packed)); +struct grub_biosdisk_cdrp +{ + grub_uint8_t size; + grub_uint8_t media_type; + grub_uint8_t drive_no; + grub_uint8_t controller_no; + grub_uint32_t image_lba; + grub_uint16_t device_spec; + grub_uint16_t cache_seg; + grub_uint16_t load_seg; + grub_uint16_t length_sec512; + grub_uint8_t cylinders; + grub_uint8_t sectors; + grub_uint8_t heads; + grub_uint8_t dummy[16]; +} __attribute__ ((packed)); + /* Disk Address Packet. */ struct grub_biosdisk_dap { @@ -90,6 +116,8 @@ int EXPORT_FUNC(grub_biosdisk_rw_standard) (int ah, int drive, int coff, int hof int EXPORT_FUNC(grub_biosdisk_check_int13_extensions) (int drive); int EXPORT_FUNC(grub_biosdisk_get_diskinfo_int13_extensions) (int drive, void *drp); +int EXPORT_FUNC(grub_biosdisk_get_cdinfo_int13_extensions) (int drive, + void *cdrp); int EXPORT_FUNC(grub_biosdisk_get_diskinfo_standard) (int drive, unsigned long *cylinders, unsigned long *heads, diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h index 848dad1..43a8d5b 100644 --- a/include/grub/i386/pc/kernel.h +++ b/include/grub/i386/pc/kernel.h @@ -71,7 +71,7 @@ extern grub_int32_t grub_memdisk_image_size; extern char grub_prefix[]; /* The boot BIOS drive number. */ -extern grub_int32_t grub_boot_drive; +extern grub_int32_t EXPORT_VAR(grub_boot_drive); /* The root BIOS drive number. */ extern grub_int32_t grub_root_drive; diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index 7237492..757f5d5 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -77,13 +76,8 @@ make_install_device (void) if (grub_root_drive == 0xFF) grub_root_drive = grub_boot_drive; - if (grub_root_drive >= GRUB_BIOSDISK_MACHINE_CDROM_START) - grub_sprintf (dev, "(cd%u", - grub_root_drive - GRUB_BIOSDISK_MACHINE_CDROM_START); - else - grub_sprintf (dev, "(%cd%u", - (grub_root_drive & 0x80) ? 'h' : 'f', - grub_root_drive & 0x7f); + grub_sprintf (dev, "(%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f', + grub_root_drive & 0x7f); if (grub_install_dos_part >= 0) grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index bf3d4ee..35b19fd 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -780,6 +780,17 @@ FUNCTION(grub_biosdisk_check_int13_extensions) /* + * int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp) + * + * Return the cdrom information of DRIVE in CDRP. If an error occurs, + * then return non-zero, otherwise zero. + */ + +FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions) + movw $0x4B01, %cx + jmp 1f + +/* * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) * * Return the geometry of DRIVE in a drive parameters, DRP. If an error @@ -787,6 +798,8 @@ FUNCTION(grub_biosdisk_check_int13_extensions) */ FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions) + movb $0x48, %ch +1: pushl %ebp pushl %ebx pushl %esi @@ -802,7 +815,7 @@ FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions) call prot_to_real .code16 - movb $0x48, %ah + movw %cx, %ax movw %bx, %ds int $0x13 /* do the operation */ movb %ah, %bl /* save return value in %bl */