15b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* bios.c - implement C part of low-level BIOS disk input and output */
25b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/*
35b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  GRUB  --  GRand Unified Bootloader
45b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  Copyright (C) 1999,2000,2003,2004  Free Software Foundation, Inc.
55b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *
65b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  This program is free software; you can redistribute it and/or modify
75b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  it under the terms of the GNU General Public License as published by
85b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  the Free Software Foundation; either version 2 of the License, or
95b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  (at your option) any later version.
105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *
115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  This program is distributed in the hope that it will be useful,
125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  GNU General Public License for more details.
155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *
165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  You should have received a copy of the GNU General Public License
175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  along with this program; if not, write to the Free Software
185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */
205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "shared.h"
225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* These are defined in asm.S, and never be used elsewhere, so declare the
255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   prototypes here.  */
265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectextern int biosdisk_int13_extensions (int ax, int drive, void *dap);
275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectextern int biosdisk_standard (int ah, int drive,
285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			      int coff, int hoff, int soff,
295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			      int nsec, int segment);
305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectextern int check_int13_extensions (int drive);
315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectextern int get_diskinfo_standard (int drive,
325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				  unsigned long *cylinders,
335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				  unsigned long *heads,
345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				  unsigned long *sectors);
355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#if 0
365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectextern int get_diskinfo_floppy (int drive,
375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				unsigned long *cylinders,
385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				unsigned long *heads,
395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				unsigned long *sectors);
405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif
415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   else if READ is BIOSDISK_WRITE, then write it. If an geometry error
465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   return the error number. Otherwise, return 0.  */
485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint
495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectbiosdisk (int read, int drive, struct geometry *geometry,
505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  int sector, int nsec, int segment)
515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  int err;
535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION)
555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      struct disk_address_packet
575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      {
585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	unsigned char length;
595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	unsigned char reserved;
605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	unsigned short blocks;
615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	unsigned long buffer;
625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	unsigned long long block;
635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      } __attribute__ ((packed)) dap;
645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* XXX: Don't check the geometry by default, because some buggy
665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 BIOSes don't return the number of total sectors correctly,
675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 even if they have working LBA support. Hell.  */
685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef NO_BUGGY_BIOS_IN_THE_WORLD
695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (sector >= geometry->total_sectors)
705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return BIOSDISK_ERROR_GEOMETRY;
715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif /* NO_BUGGY_BIOS_IN_THE_WORLD */
725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 can't add any padding.  */
755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      dap.length = sizeof (dap);
765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      dap.block = sector;
775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      dap.blocks = nsec;
785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      dap.reserved = 0;
795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* This is undocumented part. The address is formated in
805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 SEGMENT:ADDRESS.  */
815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      dap.buffer = segment << 16;
825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap);
845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* #undef NO_INT13_FALLBACK */
865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifndef NO_INT13_FALLBACK
875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (err)
885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	{
895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  if (geometry->flags & BIOSDISK_FLAG_CDROM)
905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    return err;
915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  geometry->flags &= ~BIOSDISK_FLAG_LBA_EXTENSION;
935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  geometry->total_sectors = (geometry->cylinders
945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				     * geometry->heads
955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				     * geometry->sectors);
965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  return biosdisk (read, drive, geometry, sector, nsec, segment);
975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif /* ! NO_INT13_FALLBACK */
995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  else
1025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
1035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      int cylinder_offset, head_offset, sector_offset;
1045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      int head;
1055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
1075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 CYLINDER_OFFSET are counted from zero.  */
1085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      sector_offset = sector % geometry->sectors + 1;
1095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      head = sector / geometry->sectors;
1105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      head_offset = head % geometry->heads;
1115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      cylinder_offset = head / geometry->heads;
1125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (cylinder_offset >= geometry->cylinders)
1145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return BIOSDISK_ERROR_GEOMETRY;
1155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      err = biosdisk_standard (read + 0x02, drive,
1175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			       cylinder_offset, head_offset, sector_offset,
1185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			       nsec, segment);
1195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  return err;
1225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
1235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Check bootable CD-ROM emulation status.  */
1255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int
1265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectget_cdinfo (int drive, struct geometry *geometry)
1275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
1285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  int err;
1295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  struct iso_spec_packet
1305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  {
1315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char size;
1325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char media_type;
1335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char drive_no;
1345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char controller_no;
1355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned long image_lba;
1365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short device_spec;
1375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short cache_seg;
1385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short load_seg;
1395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned short length_sec512;
1405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char cylinders;
1415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char sectors;
1425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char heads;
1435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    unsigned char dummy[16];
1455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  } __attribute__ ((packed)) cdrp;
1465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  grub_memset (&cdrp, 0, sizeof (cdrp));
1485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  cdrp.size = sizeof (cdrp) - sizeof (cdrp.dummy);
1495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  err = biosdisk_int13_extensions (0x4B01, drive, &cdrp);
1505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  if (! err && cdrp.drive_no == drive)
1515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
1525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if ((cdrp.media_type & 0x0F) == 0)
1535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        {
1545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          /* No emulation bootable CD-ROM */
1555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
1565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->cylinders = 0;
1575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->heads = 1;
1585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->sectors = 15;
1595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->sector_size = 2048;
1605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->total_sectors = MAXINT;
1615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          return 1;
1625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        }
1635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      else
1645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        {
1655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  /* Floppy or hard-disk emulation */
1665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->cylinders
1675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    = ((unsigned int) cdrp.cylinders
1685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	       + (((unsigned int) (cdrp.sectors & 0xC0)) << 2));
1695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->heads = cdrp.heads;
1705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->sectors = cdrp.sectors & 0x3F;
1715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->sector_size = SECTOR_SIZE;
1725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          geometry->total_sectors = (geometry->cylinders
1735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				     * geometry->heads
1745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				     * geometry->sectors);
1755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project          return -1;
1765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project        }
1775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
1785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  return 0;
1795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
1805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
1825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project   non-zero, otherwise zero.  */
1835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectint
1845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectget_diskinfo (int drive, struct geometry *geometry)
1855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{
1865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  int err;
1875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  /* Clear the flags.  */
1895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  geometry->flags = 0;
1905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  if (drive & 0x80)
1925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
1935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* hard disk or CD-ROM */
1945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      int version;
1955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      unsigned long total_sectors = 0;
1965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      version = check_int13_extensions (drive);
1985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
1995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (drive >= 0x88 || version)
2005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	{
2015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  /* Possible CD-ROM - check the status.  */
2025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  if (get_cdinfo (drive, geometry))
2035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    return 0;
2045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
2055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (version)
2075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	{
2085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  struct drive_parameters
2095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  {
2105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned short size;
2115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned short flags;
2125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned long cylinders;
2135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned long heads;
2145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned long sectors;
2155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned long long total_sectors;
2165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned short bytes_per_sector;
2175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    /* ver 2.0 or higher */
2185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned long EDD_configuration_parameters;
2195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    /* ver 3.0 or higher */
2205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned short signature_dpi;
2215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char length_dpi;
2225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char reserved[3];
2235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char name_of_host_bus[4];
2245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char name_of_interface_type[8];
2255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char interface_path[8];
2265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char device_path[8];
2275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char reserved2;
2285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char checksum;
2295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    /* XXX: This is necessary, because the BIOS of Thinkpad X20
2315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	       writes a garbage to the tail of drive parameters,
2325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	       regardless of a size specified in a caller.  */
2335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    unsigned char dummy[16];
2345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  } __attribute__ ((packed)) drp;
2355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  /* It is safe to clear out DRP.  */
2375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  grub_memset (&drp, 0, sizeof (drp));
2385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  /* PhoenixBIOS 4.0 Revision 6.0 for ZF Micro might understand
2405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	     the greater buffer size for the "get drive parameters" int
2415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	     0x13 call in its own way.  Supposedly the BIOS assumes even
2425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	     bigger space is available and thus corrupts the stack.
2435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	     This is why we specify the exactly necessary size of 0x42
2445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	     bytes. */
2455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  drp.size = sizeof (drp) - sizeof (drp.dummy);
2465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  err = biosdisk_int13_extensions (0x4800, drive, &drp);
2485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  if (! err)
2495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    {
2505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      /* Set the LBA flag.  */
2515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
2525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      /* I'm not sure if GRUB should check the bit 1 of DRP.FLAGS,
2545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		 so I omit the check for now. - okuji  */
2555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      /* if (drp.flags & (1 << 1)) */
2565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      /* FIXME: when the 2TB limit becomes critical, we must
2585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		 change the type of TOTAL_SECTORS to unsigned long
2595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		 long.  */
2605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      if (drp.total_sectors)
2615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		total_sectors = drp.total_sectors & ~0L;
2625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	      else
2635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		/* Some buggy BIOSes doesn't return the total sectors
2645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		   correctly but returns zero. So if it is zero, compute
2655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		   it by C/H/S returned by the LBA BIOS call.  */
2665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project		total_sectors = drp.cylinders * drp.heads * drp.sectors;
2675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	    }
2685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
2695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* Don't pass GEOMETRY directly, but pass each element instead,
2715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	 so that we can change the structure easily.  */
2725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      err = get_diskinfo_standard (drive,
2735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->cylinders,
2745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->heads,
2755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->sectors);
2765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (err)
2775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return err;
2785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (! total_sectors)
2805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	{
2815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	  total_sectors = (geometry->cylinders
2825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			   * geometry->heads
2835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project			   * geometry->sectors);
2845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	}
2855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      geometry->total_sectors = total_sectors;
2865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      geometry->sector_size = SECTOR_SIZE;
2875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
2885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  else
2895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    {
2905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* floppy disk */
2915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* First, try INT 13 AH=8h call.  */
2935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      err = get_diskinfo_standard (drive,
2945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->cylinders,
2955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->heads,
2965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->sectors);
2975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
2985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#if 0
2995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      /* If fails, then try floppy-specific probe routine.  */
3005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (err)
3015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	err = get_diskinfo_floppy (drive,
3025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->cylinders,
3035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->heads,
3045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				   &geometry->sectors);
3055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif
3065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      if (err)
3085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project	return err;
3095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      geometry->total_sectors = (geometry->cylinders
3115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				 * geometry->heads
3125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project				 * geometry->sectors);
3135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project      geometry->sector_size = SECTOR_SIZE;
3145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project    }
3155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project
3165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project  return 0;
3175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}
318