Files
grub/stage2/bios.c
T
okuji 4f29a8af45 2004-03-27 Yoshinori K. Okuji <okuji@enbug.org>
* stage2/char_io.c [!GRUB_UTIL] (memcpy): New function. It is
	defined as an alias of grub_memmove. This is copied from GRUB 2.

	* stage2/disk_io.c (print_completions): Simplified conditionals
	to make it easier to edit the file with Emacs.
	Added support for (cd).
	(set_device): Likewise.

	* stage2/common.c (init_bios_info): Check if BOOT_DRIVE is a
	CDROM drive. If it is true, set CDROM_DRIVE to BOOT_DRIVE.
	(cdrom_drive): New variable.

	From Leonid Lisovskiy <lly@pisem.net>:
	* stage2/start_eltorito.S: New file.

	* stage2/stage2.c (run_menu): Use GRUB_INVALID_DRIVE instead of
	0xFF.

	* stage2/shared.h (STAGE2_ID_ISO9660_STAGE1_5): New macro.
	[FSYS_ISO9660] (STAGE2_ID): Set to STAGE2_ID_ISO9660_STAGE1_5.
	(struct geometry): Added a new member ``sector_size''.
	(BIOSDISK_FLAG_CDROM): New macro.
	(cdrom_drive): Declared.

	* stage2/fsys_iso9660.c: New file.
	* stage2/iso9660.h: Likewise.

	* stage2/filesys.h (FSYS_ISO9660_NUM): New macro.
	[FSYS_ISO9660] (iso9660_mount): Declared.
	[FSYS_ISO9660] (iso9660_read): Likewise.
	[FSYS_ISO9660] (iso9660_dir): Likewise.
	(NUM_FSYS): Added FSYS_ISO9660_NUM.

	* stage2/disk_io.c (fsys_table) [FSYS_ISO9660]: Added iso9660.
	(current_drive): Use GRUB_INVALID_DRIVE.
	(log2): New function.
	(rawread): Use BUF_GEOM.SECTOR_SIZE instead of SECTOR_SIZE.
	Change the type of BUFADDR from int to char *.
	Use a virtual track to make sure that one track fits in the
	buffer.
	(sane_partition): Allow CURRENT_DRIVE to be CDROM_DRIVE, because
	a bios drive for a CD-ROM is often assigned to greater than
	0x88.
	(set_device): Use GRUB_INVALID_DRIVE instead of 0xFF.
	(setup_part): Likewise.

	* stage2/cmdline.c (init_cmdline): Use GRUB_INVALID_DRIVE.

	* stage2/builtins.c (install_func): Use GRUB_INVALID_DRIVE.
	(setup_func): Added iso9660_stage1_5.

	* stage2/bios.c (biosdisk): Don't fall back to the CHS mode
	if the drive is a CDROM.
	(get_cdinfo): New function.
	(get_diskinfo): Call get_cdinfo if the drive is greater than or
	equal to 0x88 or the drive supports LBA.
	Set the sector size to SECTOR_SIZE if it is not a CD-ROM.

	* stage2/asm.S (biosdisk_int13_extensions): Take a word
	argument AX instead of a byte argument AH.
	(get_diskinfo_int13_extensions): Removed.

	* stage2/Makefile.am (noinst_HEADERS): Added iso9660.h.
	(libgrub_a_SOURCES): Added fsys_iso9660.c.
	(libgrub_a_CFLAGS): Added -DFSYS_ISO9660=1.
	(pkgdata_DATA): Added iso9660_stage1_5 and stage2_eltorito.
	(noinst_PROGRAMS): Added iso9660_stage1_5.exec and
	start_eltorito.exec.
	(noinst_DATA): Added start_eltorito.
	(pre_stage2_exec_SOURCES): Added fsys_iso9660.c.
	(START_ELTORITO_LINK): New variable.
	(start_eltorito_exec_SOURCES): Likewise.
	(start_eltorito_exec_CCASFLAGS): Likewise.
	(start_eltorito_exec_LDFLAGS): Likewise.
	(start_eltorito_exec-start.$(OBJEXT)): New dependency.
	(stage2_eltorito): New target.
	(iso9660_stage1_5_exec_SOURCES): New variable.
	(iso9660_stage1_5_exec_CFLAGS): Likewise.
	(iso9660_stage1_5_exec_CCASFLAGS): Likewise.
	(iso9660_stage1_5_exec_LDFLAGS): Likewise.

	* stage1/stage1.h (GRUB_INVALID_DRIVE): New macro.

	* stage1/stage1.S (boot_drive): Use the macro GRUB_INVALID_DRIVE.
	(real_start): Likewise.

	* lib/device.c (get_drive_geometry): Set GEOM->SECTOR_SIZE to
	SECTOR_SIZE by default.

	* configure.ac (--disable-iso9660): New option.
2004-03-27 17:02:54 +00:00

318 lines
9.3 KiB
C

/* bios.c - implement C part of low-level BIOS disk input and output */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2003,2004 Free Software Foundation, Inc.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "shared.h"
/* These are defined in asm.S, and never be used elsewhere, so declare the
prototypes here. */
extern int biosdisk_int13_extensions (int ax, int drive, void *dap);
extern int biosdisk_standard (int ah, int drive,
int coff, int hoff, int soff,
int nsec, int segment);
extern int check_int13_extensions (int drive);
extern int get_diskinfo_standard (int drive,
unsigned long *cylinders,
unsigned long *heads,
unsigned long *sectors);
#if 0
extern int get_diskinfo_floppy (int drive,
unsigned long *cylinders,
unsigned long *heads,
unsigned long *sectors);
#endif
/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
else if READ is BIOSDISK_WRITE, then write it. If an geometry error
occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
return the error number. Otherwise, return 0. */
int
biosdisk (int read, int drive, struct geometry *geometry,
int sector, int nsec, int segment)
{
int err;
if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
{
struct disk_address_packet
{
unsigned char length;
unsigned char reserved;
unsigned short blocks;
unsigned long buffer;
unsigned long long block;
} __attribute__ ((packed)) dap;
/* XXX: Don't check the geometry by default, because some buggy
BIOSes don't return the number of total sectors correctly,
even if they have working LBA support. Hell. */
#ifdef NO_BUGGY_BIOS_IN_THE_WORLD
if (sector >= geometry->total_sectors)
return BIOSDISK_ERROR_GEOMETRY;
#endif /* NO_BUGGY_BIOS_IN_THE_WORLD */
/* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
can't add any padding. */
dap.length = sizeof (dap);
dap.block = sector;
dap.blocks = nsec;
dap.reserved = 0;
/* This is undocumented part. The address is formated in
SEGMENT:ADDRESS. */
dap.buffer = segment << 16;
err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap);
/* #undef NO_INT13_FALLBACK */
#ifndef NO_INT13_FALLBACK
if (err)
{
if (geometry->flags & BIOSDISK_FLAG_CDROM)
return err;
geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
geometry->total_sectors = (geometry->cylinders
* geometry->heads
* geometry->sectors);
return biosdisk (read, drive, geometry, sector, nsec, segment);
}
#endif /* ! NO_INT13_FALLBACK */
}
else
{
int cylinder_offset, head_offset, sector_offset;
int head;
/* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
CYLINDER_OFFSET are counted from zero. */
sector_offset = sector % geometry->sectors + 1;
head = sector / geometry->sectors;
head_offset = head % geometry->heads;
cylinder_offset = head / geometry->heads;
if (cylinder_offset >= geometry->cylinders)
return BIOSDISK_ERROR_GEOMETRY;
err = biosdisk_standard (read + 0x02, drive,
cylinder_offset, head_offset, sector_offset,
nsec, segment);
}
return err;
}
/* Check bootable CD-ROM emulation status. */
static int
get_cdinfo (int drive, struct geometry *geometry)
{
int err;
struct iso_spec_packet
{
unsigned char size;
unsigned char media_type;
unsigned char drive_no;
unsigned char controller_no;
unsigned long image_lba;
unsigned short device_spec;
unsigned short cache_seg;
unsigned short load_seg;
unsigned short length_sec512;
unsigned char cylinders;
unsigned char sectors;
unsigned char heads;
unsigned char dummy[16];
} __attribute__ ((packed)) cdrp;
grub_memset (&cdrp, 0, sizeof (cdrp));
cdrp.size = sizeof (cdrp) - sizeof (cdrp.dummy);
err = biosdisk_int13_extensions (0x4B01, drive, &cdrp);
if (! err && cdrp.drive_no == drive)
{
if ((cdrp.media_type & 0x0F) == 0)
{
/* No emulation bootable CD-ROM */
geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
geometry->cylinders = 0;
geometry->heads = 1;
geometry->sectors = 15;
geometry->sector_size = 2048;
geometry->total_sectors = MAXINT;
return 1;
}
else
{
/* Floppy or hard-disk emulation */
geometry->cylinders
= ((unsigned int) cdrp.cylinders
+ (((unsigned int) (cdrp.sectors & 0xC0)) << 2));
geometry->heads = cdrp.heads;
geometry->sectors = cdrp.sectors & 0x3F;
geometry->sector_size = SECTOR_SIZE;
geometry->total_sectors = (geometry->cylinders
* geometry->heads
* geometry->sectors);
return -1;
}
}
return 0;
}
/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
non-zero, otherwise zero. */
int
get_diskinfo (int drive, struct geometry *geometry)
{
int err;
/* Clear the flags. */
geometry->flags = 0;
if (drive & 0x80)
{
/* hard disk or CD-ROM */
int version;
unsigned long total_sectors = 0;
version = check_int13_extensions (drive);
if (drive >= 0x88 || version)
{
/* Possible CD-ROM - check the status. */
if (get_cdinfo (drive, geometry))
return 0;
}
if (version)
{
struct drive_parameters
{
unsigned short size;
unsigned short flags;
unsigned long cylinders;
unsigned long heads;
unsigned long sectors;
unsigned long long total_sectors;
unsigned short bytes_per_sector;
/* ver 2.0 or higher */
unsigned long EDD_configuration_parameters;
/* ver 3.0 or higher */
unsigned short signature_dpi;
unsigned char length_dpi;
unsigned char reserved[3];
unsigned char name_of_host_bus[4];
unsigned char name_of_interface_type[8];
unsigned char interface_path[8];
unsigned char device_path[8];
unsigned char reserved2;
unsigned char checksum;
/* XXX: This is necessary, because the BIOS of Thinkpad X20
writes a garbage to the tail of drive parameters,
regardless of a size specified in a caller. */
unsigned char dummy[16];
} __attribute__ ((packed)) drp;
/* It is safe to clear out DRP. */
grub_memset (&drp, 0, sizeof (drp));
/* PhoenixBIOS 4.0 Revision 6.0 for ZF Micro might understand
the greater buffer size for the "get drive parameters" int
0x13 call in its own way. Supposedly the BIOS assumes even
bigger space is available and thus corrupts the stack.
This is why we specify the exactly necessary size of 0x42
bytes. */
drp.size = sizeof (drp) - sizeof (drp.dummy);
err = biosdisk_int13_extensions (0x4800, drive, &drp);
if (! err)
{
/* Set the LBA flag. */
geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
/* I'm not sure if GRUB should check the bit 1 of DRP.FLAGS,
so I omit the check for now. - okuji */
/* if (drp.flags & (1 << 1)) */
/* FIXME: when the 2TB limit becomes critical, we must
change the type of TOTAL_SECTORS to unsigned long
long. */
if (drp.total_sectors)
total_sectors = drp.total_sectors & ~0L;
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;
}
}
/* Don't pass GEOMETRY directly, but pass each element instead,
so that we can change the structure easily. */
err = get_diskinfo_standard (drive,
&geometry->cylinders,
&geometry->heads,
&geometry->sectors);
if (err)
return err;
if (! total_sectors)
{
total_sectors = (geometry->cylinders
* geometry->heads
* geometry->sectors);
}
geometry->total_sectors = total_sectors;
geometry->sector_size = SECTOR_SIZE;
}
else
{
/* floppy disk */
/* First, try INT 13 AH=8h call. */
err = get_diskinfo_standard (drive,
&geometry->cylinders,
&geometry->heads,
&geometry->sectors);
#if 0
/* If fails, then try floppy-specific probe routine. */
if (err)
err = get_diskinfo_floppy (drive,
&geometry->cylinders,
&geometry->heads,
&geometry->sectors);
#endif
if (err)
return err;
geometry->total_sectors = (geometry->cylinders
* geometry->heads
* geometry->sectors);
geometry->sector_size = SECTOR_SIZE;
}
return 0;
}