~smartboyhw/wubi/bug-1080090-new

« back to all changes in this revision

Viewing changes to src/grub4dos/stage2/.svn/text-base/bios.c.svn-base

  • Committer: Howard Chan
  • Date: 2012-11-20 10:16:05 UTC
  • Revision ID: smartboyhw@gmail.com-20121120101605-qfmjfsdynpzg9an9
Added images

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* bios.c - implement C part of low-level BIOS disk input and output */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 1999,2000,2003,2004  Free Software Foundation, Inc.
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
 */
20
 
 
21
 
#include "shared.h"
22
 
#include "iso9660.h"
23
 
 
24
 
/* These are defined in asm.S, and never be used elsewhere, so declare the
25
 
   prototypes here.  */
26
 
extern int biosdisk_standard (int ah, int drive,
27
 
                              int coff, int hoff, int soff,
28
 
                              int nsec, int segment);
29
 
extern int get_diskinfo_standard (int drive,
30
 
                                  unsigned long *cylinders,
31
 
                                  unsigned long *heads,
32
 
                                  unsigned long *sectors);
33
 
 
34
 
extern struct drive_map_slot hooked_drive_map[DRIVE_MAP_SIZE + 1];
35
 
extern int drive_map_slot_empty (struct drive_map_slot item);
36
 
 
37
 
/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
38
 
   from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
39
 
   else if READ is BIOSDISK_WRITE, then write it. If an geometry error
40
 
   occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
41
 
   return the error number. Otherwise, return 0.  */
42
 
int
43
 
biosdisk (int read, int drive, struct geometry *geometry,
44
 
          int sector, int nsec, int segment)
45
 
{
46
 
  int err;
47
 
  
48
 
  /* first, use EBIOS if possible */
49
 
  if ((geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION) && (! (geometry->flags & BIOSDISK_FLAG_BIFURCATE) || (drive & 0xFFFFFF00) == 0x100))
50
 
    {
51
 
      struct disk_address_packet
52
 
      {
53
 
        unsigned char length;
54
 
        unsigned char reserved;
55
 
        unsigned short blocks;
56
 
        unsigned long buffer;
57
 
        unsigned long long block;
58
 
        
59
 
        /* This structure is passed in the stack. A buggy BIOS could write
60
 
         * garbage data to the tail of the struct and hang the machine. So
61
 
         * we need this protection. - Tinybit
62
 
         */
63
 
        unsigned char dummy[16];
64
 
      } __attribute__ ((packed)) *dap;
65
 
 
66
 
      /* Even the above protection is not enough to avoid stupid actions by
67
 
       * buggy BIOSes. So we do it in the 0040:0000 segment. - Tinybit
68
 
       */
69
 
      dap = (struct disk_address_packet *)0x580;
70
 
 
71
 
      if (drive == 0xffff || (drive == ram_drive && rd_base != 0xffffffff))
72
 
      {
73
 
        char *disk_sector;
74
 
        char *buf_address;
75
 
        
76
 
        if (nsec <=0 || nsec >= 0x80)
77
 
                return 1;       /* failure */
78
 
        
79
 
        disk_sector = (char *)((sector<<9) + ((drive==0xffff) ? 0 : rd_base));
80
 
        buf_address = (char *)(segment<<4);
81
 
 
82
 
        if (read)       /* read == 1 really means write to DISK */
83
 
                grub_memmove (disk_sector, buf_address, nsec << 9);
84
 
        else            /* read == 0 really means read from DISK */
85
 
                grub_memmove (buf_address, disk_sector, nsec << 9);
86
 
                
87
 
        return 0;       /* success */
88
 
      }
89
 
 
90
 
      dap->length = 0x10;
91
 
      dap->block = sector;
92
 
      dap->blocks = nsec;
93
 
      dap->reserved = 0;
94
 
      dap->buffer = segment << 16;
95
 
      
96
 
      err = biosdisk_int13_extensions ((read + 0x42) << 8, (unsigned char)drive, dap);
97
 
 
98
 
      if (!err)
99
 
        return 0;       /* success */
100
 
 
101
 
      /* bootable CD-ROM specification has no standard CHS-mode call */
102
 
      if (geometry->flags & BIOSDISK_FLAG_CDROM)
103
 
      {
104
 
#ifndef STAGE1_5
105
 
        if (debug > 1)
106
 
          grub_printf ("biosdisk_int13_extensions read=%d, drive=0x%x, dap=%x, err=0x%x\n", read, drive, dap, err);
107
 
#endif
108
 
        return err;
109
 
      }
110
 
 
111
 
      if (geometry->flags & BIOSDISK_FLAG_BIFURCATE)
112
 
        return err;
113
 
 
114
 
    } /* if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION) */
115
 
 
116
 
   /* try the standard CHS mode */
117
 
  
118
 
    {
119
 
      int cylinder_offset, head_offset, sector_offset;
120
 
      int head;
121
 
 
122
 
      /* SECTOR_OFFSET is counted from one, while HEAD_OFFSET and
123
 
         CYLINDER_OFFSET are counted from zero.  */
124
 
      sector_offset = sector % geometry->sectors + 1;
125
 
      head = sector / geometry->sectors;
126
 
      head_offset = head % geometry->heads;
127
 
      cylinder_offset = head / geometry->heads;
128
 
      
129
 
      err = biosdisk_standard (read + 0x02, drive,
130
 
                               cylinder_offset, head_offset, sector_offset,
131
 
                               nsec, segment);
132
 
    }
133
 
 
134
 
  return err;
135
 
}
136
 
 
137
 
/* Check bootable CD-ROM emulation status. Return 0 on failure. */
138
 
int
139
 
get_cdinfo (int drive, struct geometry *geometry)
140
 
{
141
 
  int err;
142
 
  struct iso_spec_packet
143
 
  {
144
 
    unsigned char size;
145
 
    unsigned char media_type;
146
 
    unsigned char drive_no;
147
 
    unsigned char controller_no;
148
 
    unsigned long image_lba;
149
 
    unsigned short device_spec;
150
 
    unsigned short cache_seg;
151
 
    unsigned short load_seg;
152
 
    unsigned short length_sec512;
153
 
    unsigned char cylinders;
154
 
    unsigned char sectors;
155
 
    unsigned char heads;
156
 
    
157
 
    unsigned char dummy[16];
158
 
  } __attribute__ ((packed));
159
 
  
160
 
  struct iso_spec_packet *cdrp;
161
 
  
162
 
  cdrp = (struct iso_spec_packet *)0x580;
163
 
  grub_memset (cdrp, 0, sizeof (struct iso_spec_packet));
164
 
  cdrp->size = sizeof (struct iso_spec_packet) - 16;
165
 
 
166
 
#ifndef STAGE1_5
167
 
  if (debug > 1)
168
 
        grub_printf (" int13/4B01(%X),", drive);
169
 
#endif
170
 
  err = biosdisk_int13_extensions (0x4B01, drive, cdrp);
171
 
#ifndef STAGE1_5
172
 
  if (debug > 1)
173
 
        grub_printf ("err=%X,drive=%X, ", err, drive);
174
 
#endif
175
 
 
176
 
  if (drive == 0x7F && drive < (unsigned long)(cdrp->drive_no))
177
 
        drive = cdrp->drive_no;
178
 
 
179
 
  if (! err && cdrp->drive_no == drive && !(cdrp->media_type & 0x0F))
180
 
    {
181
 
        /* No-emulation mode bootable CD-ROM */
182
 
        geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
183
 
        geometry->cylinders = 65536;
184
 
        geometry->heads = 255;
185
 
        geometry->sectors = 15;
186
 
        geometry->sector_size = 2048;
187
 
        geometry->total_sectors = 65536 * 255 * 15;
188
 
        return drive;
189
 
    }
190
 
  return 0;     /* failure */
191
 
}
192
 
 
193
 
static unsigned long flags;
194
 
static unsigned long cylinders;
195
 
static unsigned long heads;
196
 
static unsigned long sectors;
197
 
 
198
 
 
199
 
/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
200
 
   non-zero, otherwise zero.  */
201
 
int
202
 
get_diskinfo (int drive, struct geometry *geometry)
203
 
{
204
 
  int err;
205
 
  int version;
206
 
  unsigned long long total_sectors = 0, tmp = 0;
207
 
 
208
 
  if (drive == 0xffff)  /* memory disk */
209
 
    {
210
 
      unsigned long long total_mem_bytes;
211
 
 
212
 
      total_mem_bytes = 0;
213
 
 
214
 
      if (mbi.flags & MB_INFO_MEM_MAP)
215
 
        {
216
 
          struct AddrRangeDesc *map = (struct AddrRangeDesc *) saved_mmap_addr;
217
 
          unsigned long end_addr = saved_mmap_addr + saved_mmap_length;
218
 
 
219
 
          for (; end_addr > (unsigned long) map; map = (struct AddrRangeDesc *) (((int) map) + 4 + map->size))
220
 
            {
221
 
              unsigned long long top_end;
222
 
 
223
 
              if (map->Type != MB_ARD_MEMORY)
224
 
                  continue;
225
 
              top_end =  map->BaseAddr + map->Length;
226
 
              if (top_end > 0x100000000ULL)
227
 
                  top_end = 0x100000000ULL;
228
 
              if (total_mem_bytes < top_end)
229
 
                  total_mem_bytes = top_end;
230
 
 
231
 
            }
232
 
        }
233
 
      else
234
 
          grub_printf ("Address Map BIOS Interface is not activated.\n");
235
 
 
236
 
      if (total_mem_bytes)
237
 
      {
238
 
        geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
239
 
        geometry->sector_size = SECTOR_SIZE;
240
 
        geometry->total_sectors = (total_mem_bytes /*+ SECTOR_SIZE - 1*/) >> SECTOR_BITS;
241
 
        geometry->heads = 255;
242
 
        geometry->sectors = 63;
243
 
        geometry->cylinders = (geometry->total_sectors + 255 * 63 -1) / (255 * 63);
244
 
        return 0;
245
 
      }
246
 
      
247
 
    } else if (drive == ram_drive)      /* ram disk device */
248
 
    {
249
 
      if (rd_base != 0xffffffff)
250
 
      {
251
 
        geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
252
 
        geometry->sector_size = SECTOR_SIZE;
253
 
        geometry->total_sectors = (rd_size ? ((rd_size + SECTOR_SIZE - 1)>> SECTOR_BITS) : 0x800000);
254
 
        geometry->heads = 255;
255
 
        geometry->sectors = 63;
256
 
        geometry->cylinders = (geometry->total_sectors + 255 * 63 -1) / (255 * 63);
257
 
        return 0;
258
 
      }
259
 
    }
260
 
 
261
 
#if defined(GRUB_UTIL) || defined(STAGE1_5)
262
 
  if (drive == cdrom_drive)
263
 
#else
264
 
  if (drive == cdrom_drive || (drive >= (unsigned char)min_cdrom_id && drive < (unsigned char)(min_cdrom_id + atapi_dev_count)))
265
 
#endif
266
 
  {
267
 
        /* No-emulation mode bootable CD-ROM */
268
 
        geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION | BIOSDISK_FLAG_CDROM;
269
 
        geometry->cylinders = 65536;
270
 
        geometry->heads = 255;
271
 
        geometry->sectors = 15;
272
 
        geometry->sector_size = 2048;
273
 
        geometry->total_sectors = 65536 * 255 * 15;
274
 
        return 0;
275
 
  }
276
 
 
277
 
  /* Clear the flags.  */
278
 
  flags = 0;
279
 
 
280
 
#ifdef GRUB_UTIL
281
 
#define FIND_DRIVES 8
282
 
#else
283
 
#define FIND_DRIVES (*((char *)0x475))
284
 
#endif
285
 
      if (((unsigned char)drive) >= 0x80 + FIND_DRIVES /* || (version && (drive & 0x80)) */ )
286
 
        {
287
 
          /* Possible CD-ROM - check the status.  */
288
 
          if (get_cdinfo ((unsigned char)drive, geometry))
289
 
            return 0;
290
 
        }
291
 
      
292
 
#if (! defined(GRUB_UTIL)) && (! defined(STAGE1_5))
293
 
    {
294
 
        unsigned long j;
295
 
        unsigned long d;
296
 
 
297
 
        /* check if the drive is virtual. */
298
 
        d = (unsigned char)drive;
299
 
        j = DRIVE_MAP_SIZE;             /* real drive */
300
 
        if (! unset_int13_handler (1))
301
 
            for (j = 0; j < DRIVE_MAP_SIZE; j++)
302
 
            {
303
 
                if (drive_map_slot_empty (hooked_drive_map[j]))
304
 
                {
305
 
                        j = DRIVE_MAP_SIZE;     /* real drive */
306
 
                        break;
307
 
                }
308
 
 
309
 
                if (((unsigned char)drive) != hooked_drive_map[j].from_drive)
310
 
                        continue;
311
 
                if ((hooked_drive_map[j].max_sector & 0x3E) == 0 && hooked_drive_map[j].start_sector == 0 && hooked_drive_map[j].sector_count <= 1)
312
 
                {
313
 
                        /* this is a map for the whole drive. */
314
 
                        d = hooked_drive_map[j].to_drive;
315
 
                        j = DRIVE_MAP_SIZE;     /* real drive */
316
 
                }
317
 
                break;
318
 
            }
319
 
 
320
 
        if (j == DRIVE_MAP_SIZE)        /* real drive */
321
 
        {
322
 
            if (d >= 0x80 && d < 0x84)
323
 
            {
324
 
                d -= 0x80;
325
 
                if (hd_geom[d].sector_size == 512 && hd_geom[d].sectors > 0 && hd_geom[d].sectors <= 63 && hd_geom[d].heads <= 256)
326
 
                {
327
 
                        geometry->flags = hd_geom[d].flags;
328
 
                        if ((geometry->flags & BIOSDISK_FLAG_BIFURCATE) && (drive & 0xFFFFFF00) == 0x100)
329
 
                        {
330
 
                                if (geometry->flags & BIOSDISK_FLAG_CDROM)
331
 
                                {
332
 
                                        geometry->cylinders = 65536;
333
 
                                        geometry->heads = 255;
334
 
                                        geometry->sectors = 15;
335
 
                                        geometry->sector_size = 2048;
336
 
                                        geometry->total_sectors = 65536 * 255 * 15;
337
 
                                        return 0;
338
 
                                }
339
 
                        }
340
 
                        geometry->sector_size = hd_geom[d].sector_size;
341
 
                        geometry->total_sectors = hd_geom[d].total_sectors;
342
 
                        geometry->heads = hd_geom[d].heads;
343
 
                        geometry->sectors = hd_geom[d].sectors;
344
 
                        geometry->cylinders = hd_geom[d].cylinders;
345
 
                        return 0;
346
 
                }
347
 
            } else if (d < 4) {
348
 
                if (fd_geom[d].sector_size == 512 && fd_geom[d].sectors > 0 && fd_geom[d].sectors <= 63 && fd_geom[d].heads <= 256)
349
 
                {
350
 
                        geometry->flags = fd_geom[d].flags;
351
 
                        if ((geometry->flags & BIOSDISK_FLAG_BIFURCATE) && (drive & 0xFFFFFF00) == 0x100)
352
 
                        {
353
 
                                if (geometry->flags & BIOSDISK_FLAG_CDROM)
354
 
                                {
355
 
                                        geometry->cylinders = 65536;
356
 
                                        geometry->heads = 255;
357
 
                                        geometry->sectors = 15;
358
 
                                        geometry->sector_size = 2048;
359
 
                                        geometry->total_sectors = 65536 * 255 * 15;
360
 
                                        return 0;
361
 
                                }
362
 
                        }
363
 
                        geometry->sector_size = fd_geom[d].sector_size;
364
 
                        geometry->total_sectors = fd_geom[d].total_sectors;
365
 
                        geometry->heads = fd_geom[d].heads;
366
 
                        geometry->sectors = fd_geom[d].sectors;
367
 
                        geometry->cylinders = fd_geom[d].cylinders;
368
 
                        return 0;
369
 
                }
370
 
            }
371
 
        }
372
 
    }
373
 
#endif
374
 
 
375
 
#ifndef STAGE1_5
376
 
        if (debug > 1)      
377
 
                grub_printf (" int13/41(%X),", drive);
378
 
#endif
379
 
        version = check_int13_extensions ((unsigned char)drive);
380
 
#ifndef STAGE1_5
381
 
        if (debug > 1)      
382
 
                grub_printf ("version=%X, ", version);
383
 
#endif
384
 
 
385
 
        /* Set the LBA flag.  */
386
 
        if (version & 1) /* support functions 42h-44h, 47h-48h */
387
 
        {
388
 
                flags = BIOSDISK_FLAG_LBA_EXTENSION;
389
 
        }
390
 
        total_sectors = 0;
391
 
 
392
 
#ifndef STAGE1_5
393
 
        if (debug > 1)
394
 
                grub_printf (" int13/08(%X),", drive);
395
 
#endif
396
 
 
397
 
        version = get_diskinfo_standard ((unsigned char)drive, &cylinders, &heads, &sectors);
398
 
 
399
 
#ifndef STAGE1_5
400
 
        if (debug > 1)
401
 
                grub_printf ("version=%X, C/H/S=%d/%d/%d, ", version, cylinders, heads, sectors);
402
 
#endif
403
 
 
404
 
#ifndef STAGE1_5
405
 
        if (debug > 1)
406
 
                grub_printf (" int13/02(%X),", drive);
407
 
#endif
408
 
 
409
 
        /* read the boot sector: int 13, AX=0x201, CX=1, DH=0 */
410
 
        err = biosdisk_standard (0x02, (unsigned char)drive, 0, 0, 1, 1, 0x5F00/*SCRATCHSEG*/);
411
 
 
412
 
#ifndef STAGE1_5
413
 
        if (debug > 1)
414
 
                grub_printf ("err=%X, ", err);
415
 
#endif
416
 
 
417
 
        //version = 0;
418
 
 
419
 
        /* try again using LBA */
420
 
        if (flags & BIOSDISK_FLAG_LBA_EXTENSION || ((unsigned char)drive) >= 0x80 + FIND_DRIVES)
421
 
        {
422
 
                struct disk_address_packet
423
 
                {
424
 
                        unsigned char length;
425
 
                        unsigned char reserved;
426
 
                        unsigned short blocks;
427
 
                        unsigned long buffer;
428
 
                        unsigned long long block;
429
 
 
430
 
                        unsigned char dummy[16];
431
 
                } __attribute__ ((packed)) *dap;
432
 
 
433
 
                dap = (struct disk_address_packet *)0x580;
434
 
 
435
 
                dap->length = 0x10;
436
 
                dap->reserved = 0;
437
 
                dap->blocks = 1;
438
 
                dap->buffer = 0x5F80/*SCRATCHSEG*/ << 16;
439
 
                dap->block = 0;
440
 
 
441
 
                /* set a known value */
442
 
                grub_memset ((char *)0x5F800, 0xEC, 0x800);
443
 
                version = biosdisk_int13_extensions (0x4200, (unsigned char)drive, dap);
444
 
                /* see if it is a big sector */
445
 
                {
446
 
                        char *p;
447
 
                        for (p = (char *)0x5FA00; p < (char *)0x60000; p++)
448
 
                        {
449
 
                                if ((*p) != (char)0xEC)
450
 
                                {
451
 
                                        flags |= BIOSDISK_FLAG_CDROM | BIOSDISK_FLAG_LBA_EXTENSION;
452
 
                                        if (! err)
453
 
                                                flags |= BIOSDISK_FLAG_BIFURCATE;
454
 
                                        break;
455
 
                                }
456
 
                        }
457
 
                }
458
 
                if ((! version) && (! err))
459
 
                {
460
 
                        if (grub_memcmp ((char *)0x5F000, (char *)0x5F800, 0x200))
461
 
                        {
462
 
                                flags |= BIOSDISK_FLAG_BIFURCATE;
463
 
                        }
464
 
                }
465
 
                if (err && ! (flags & BIOSDISK_FLAG_BIFURCATE) && !(flags & BIOSDISK_FLAG_CDROM))
466
 
                {
467
 
                        grub_memmove ((char *)0x5F000, (char *)0x5F800, 0x200);
468
 
                }
469
 
 
470
 
        } /* if (geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION) */
471
 
 
472
 
        if (err && version)
473
 
                return err; /* When we return with ERROR, we should not change the geometry!! */
474
 
 
475
 
        geometry->flags = flags;
476
 
 
477
 
        if (err && (flags & BIOSDISK_FLAG_CDROM))
478
 
        {
479
 
                geometry->cylinders = 65536;
480
 
                geometry->heads = 255;
481
 
                geometry->sectors = 15;
482
 
                geometry->sector_size = 2048;
483
 
                geometry->total_sectors = 65536 * 255 * 15;
484
 
                return 0;
485
 
        }
486
 
 
487
 
        geometry->cylinders = cylinders;
488
 
        geometry->heads = heads;
489
 
        geometry->sectors = sectors;
490
 
        geometry->sector_size = SECTOR_SIZE;
491
 
        if (geometry->heads > 256)
492
 
            geometry->heads = 256;
493
 
        if (geometry->sectors * geometry->sector_size > 63 * 512)
494
 
            geometry->sectors = 63 * 512 / geometry->sector_size;
495
 
        tmp = (unsigned long long)(geometry->cylinders) *
496
 
              (unsigned long long)(geometry->heads) *
497
 
              (unsigned long long)(geometry->sectors);
498
 
        if (total_sectors < tmp)
499
 
            total_sectors = tmp;
500
 
        geometry->total_sectors = total_sectors;
501
 
 
502
 
        /* successfully read boot sector */
503
 
 
504
 
#ifndef STAGE1_5
505
 
        if (drive & 0x80)
506
 
        {
507
 
                /* hard disk */
508
 
                if ((err = probe_mbr((struct master_and_dos_boot_sector *)0x5F000/*SCRATCHADDR*/, 0, total_sectors, 0)))
509
 
                {
510
 
                        if (debug > 1)
511
 
                                grub_printf ("\nWarning: Unrecognized partition table for drive %X. Please rebuild it using\na Microsoft-compatible FDISK tool(err=%d). Current C/H/S=%d/%d/%d\n", drive, err, geometry->cylinders, geometry->heads, geometry->sectors);
512
 
                        goto failure_probe_boot_sector;
513
 
                }
514
 
                err = (int)"MBR";
515
 
        }else{
516
 
                /* floppy */
517
 
                if (probe_bpb((struct master_and_dos_boot_sector *)0x5F000/*SCRATCHADDR*/))
518
 
                {
519
 
                        goto failure_probe_boot_sector;
520
 
                }
521
 
 
522
 
                err = (int)"BPB";
523
 
        }
524
 
 
525
 
        if (drive & 0x80)
526
 
        if (probed_cylinders != geometry->cylinders)
527
 
            if (debug > 1)
528
 
                grub_printf ("\nWarning: %s cylinders(%d) is not equal to the BIOS one(%d).\n", (char *)err, probed_cylinders, geometry->cylinders);
529
 
 
530
 
        geometry->cylinders = probed_cylinders;
531
 
 
532
 
        if (probed_heads != geometry->heads)
533
 
            if (debug > 1)
534
 
                grub_printf ("\nWarning: %s heads(%d) is not equal to the BIOS one(%d).\n", (char *)err, probed_heads, geometry->heads);
535
 
 
536
 
        geometry->heads = probed_heads;
537
 
 
538
 
        if (probed_sectors_per_track != geometry->sectors)
539
 
            if (debug > 1)
540
 
                grub_printf ("\nWarning: %s sectors per track(%d) is not equal to the BIOS one(%d).\n", (char *)err, probed_sectors_per_track, geometry->sectors);
541
 
 
542
 
        geometry->sectors = probed_sectors_per_track;
543
 
 
544
 
        if (probed_total_sectors > total_sectors)
545
 
        {
546
 
            if (drive & 0x80)
547
 
            if (debug > 1)
548
 
                grub_printf ("\nWarning: %s total sectors(%d) is greater than the BIOS one(%d).\nSome buggy BIOSes could hang when you access sectors exceeding the BIOS limit.\n", (char *)err, probed_total_sectors, total_sectors);
549
 
            geometry->total_sectors     = probed_total_sectors;
550
 
        }
551
 
 
552
 
        if (drive & 0x80)
553
 
        if (probed_total_sectors < total_sectors)
554
 
            if (debug > 1)
555
 
                grub_printf ("\nWarning: %s total sectors(%d) is less than the BIOS one(%d).\n", (char *)err, probed_total_sectors, total_sectors);
556
 
 
557
 
failure_probe_boot_sector:
558
 
        
559
 
#ifndef GRUB_UTIL
560
 
#if 1
561
 
        if (!(geometry->flags & BIOSDISK_FLAG_LBA_EXTENSION) && ! ((*(char *)0x8205) & 0x08))
562
 
        {
563
 
                err = geometry->heads;
564
 
                version = geometry->sectors;
565
 
 
566
 
                /* DH non-zero for geometry_tune */
567
 
                get_diskinfo_standard (drive | 0x0100, &geometry->cylinders, &geometry->heads, &geometry->sectors);
568
 
 
569
 
                if (debug > 0)
570
 
                {
571
 
                    if (err != geometry->heads)
572
 
                        grub_printf ("\nNotice: number of heads for drive %X tuned from %d to %d.\n", drive, err, geometry->heads);
573
 
                    if (version != geometry->sectors)
574
 
                        grub_printf ("\nNotice: sectors-per-track for drive %X tuned from %d to %d.\n", drive, version, geometry->sectors);
575
 
                }
576
 
        }
577
 
#endif
578
 
#endif
579
 
 
580
 
        /* if C/H/S=0/0/0, use a safe default one. */
581
 
        if (geometry->sectors == 0)
582
 
        {
583
 
                if (drive & 0x80)
584
 
                {
585
 
                        /* hard disk */
586
 
                        geometry->sectors = 63;
587
 
                }else{
588
 
                        /* floppy */
589
 
                        if (geometry->total_sectors > 5760)
590
 
                                geometry->sectors = 63;
591
 
                        else if (geometry->total_sectors > 2880)
592
 
                                geometry->sectors = 36;
593
 
                        else
594
 
                                geometry->sectors = 18;
595
 
                }
596
 
        }
597
 
        if (geometry->heads == 0)
598
 
        {
599
 
                if (drive & 0x80)
600
 
                {
601
 
                        /* hard disk */
602
 
                        geometry->heads = 255;
603
 
                }else{
604
 
                        /* floppy */
605
 
                        if (geometry->total_sectors > 5760)
606
 
                                geometry->heads = 255;
607
 
                        else
608
 
                                geometry->heads = 2;
609
 
                }
610
 
        }
611
 
        if (geometry->cylinders == 0)
612
 
        {
613
 
                geometry->cylinders = (geometry->total_sectors / geometry->heads / geometry->sectors);
614
 
        }
615
 
 
616
 
        if (geometry->cylinders == 0)
617
 
                geometry->cylinders = 1;
618
 
#endif  /* ! STAGE1_5 */
619
 
 
620
 
  /* backup the geometry into array hd_geom or fd_geom. */
621
 
 
622
 
#if (! defined(GRUB_UTIL)) && (! defined(STAGE1_5))
623
 
    {
624
 
        unsigned long j;
625
 
        unsigned long d;
626
 
 
627
 
        /* check if the drive is virtual. */
628
 
        d = (unsigned char)drive;
629
 
        j = DRIVE_MAP_SIZE;             /* real drive */
630
 
        if (! unset_int13_handler (1))
631
 
            for (j = 0; j < DRIVE_MAP_SIZE; j++)
632
 
            {
633
 
                if (drive_map_slot_empty (hooked_drive_map[j]))
634
 
                {
635
 
                        j = DRIVE_MAP_SIZE;     /* real drive */
636
 
                        break;
637
 
                }
638
 
 
639
 
                if (((unsigned char)drive) != hooked_drive_map[j].from_drive)
640
 
                        continue;
641
 
                if ((hooked_drive_map[j].max_sector & 0x3E) == 0 && hooked_drive_map[j].start_sector == 0 && hooked_drive_map[j].sector_count <= 1)
642
 
                {
643
 
                        /* this is a map for the whole drive. */
644
 
                        d = hooked_drive_map[j].to_drive;
645
 
                        j = DRIVE_MAP_SIZE;     /* real drive */
646
 
                }
647
 
                break;
648
 
            }
649
 
 
650
 
        if (j == DRIVE_MAP_SIZE)        /* real drive */
651
 
        {
652
 
            if (d >= 0x80 && d < 0x84)
653
 
            {
654
 
                d -= 0x80;
655
 
                if (hd_geom[d].sector_size != 512 || hd_geom[d].sectors <= 0 || hd_geom[d].sectors > 63 || hd_geom[d].heads > 256)
656
 
                {
657
 
                        hd_geom[d].flags                = geometry->flags;
658
 
                        hd_geom[d].sector_size          = geometry->sector_size;
659
 
                        hd_geom[d].total_sectors        = geometry->total_sectors;
660
 
                        hd_geom[d].heads                = geometry->heads;
661
 
                        hd_geom[d].sectors              = geometry->sectors;
662
 
                        hd_geom[d].cylinders            = geometry->cylinders;
663
 
                }
664
 
            } else if (d < 4) {
665
 
                if (fd_geom[d].sector_size != 512 || fd_geom[d].sectors <= 0 || fd_geom[d].sectors > 63 || fd_geom[d].heads > 256)
666
 
                {
667
 
                        fd_geom[d].flags                = geometry->flags;
668
 
                        fd_geom[d].sector_size          = geometry->sector_size;
669
 
                        fd_geom[d].total_sectors        = geometry->total_sectors;
670
 
                        fd_geom[d].heads                = geometry->heads;
671
 
                        fd_geom[d].sectors              = geometry->sectors;
672
 
                        fd_geom[d].cylinders            = geometry->cylinders;
673
 
                }
674
 
            }
675
 
        }
676
 
    }
677
 
        if ((geometry->flags & BIOSDISK_FLAG_BIFURCATE) && (drive & 0xFFFFFF00) == 0x100)
678
 
        {
679
 
                if (geometry->flags & BIOSDISK_FLAG_CDROM)
680
 
                {
681
 
                        geometry->cylinders = 65536;
682
 
                        geometry->heads = 255;
683
 
                        geometry->sectors = 15;
684
 
                        geometry->sector_size = 2048;
685
 
                        geometry->total_sectors = 65536 * 255 * 15;
686
 
                }
687
 
        }
688
 
#endif
689
 
 
690
 
  return 0;
691
 
}
692
 
 
693
 
#undef FIND_DRIVES
694