qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

hd-geometry.c (6055B)


      1 /*
      2  * Hard disk geometry utilities
      3  *
      4  * Copyright (C) 2012 Red Hat, Inc.
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7  * See the COPYING file in the top-level directory.
      8  *
      9  * This file incorporates work covered by the following copyright and
     10  * permission notice:
     11  *
     12  * Copyright (c) 2003 Fabrice Bellard
     13  *
     14  * Permission is hereby granted, free of charge, to any person obtaining a copy
     15  * of this software and associated documentation files (the "Software"), to deal
     16  * in the Software without restriction, including without limitation the rights
     17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     18  * copies of the Software, and to permit persons to whom the Software is
     19  * furnished to do so, subject to the following conditions:
     20  *
     21  * The above copyright notice and this permission notice shall be included in
     22  * all copies or substantial portions of the Software.
     23  *
     24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     30  * THE SOFTWARE.
     31  */
     32 
     33 #include "qemu/osdep.h"
     34 #include "sysemu/block-backend.h"
     35 #include "qapi/qapi-types-block.h"
     36 #include "qemu/bswap.h"
     37 #include "hw/block/block.h"
     38 #include "trace.h"
     39 
     40 struct partition {
     41         uint8_t boot_ind;           /* 0x80 - active */
     42         uint8_t head;               /* starting head */
     43         uint8_t sector;             /* starting sector */
     44         uint8_t cyl;                /* starting cylinder */
     45         uint8_t sys_ind;            /* What partition type */
     46         uint8_t end_head;           /* end head */
     47         uint8_t end_sector;         /* end sector */
     48         uint8_t end_cyl;            /* end cylinder */
     49         uint32_t start_sect;        /* starting sector counting from 0 */
     50         uint32_t nr_sects;          /* nr of sectors in partition */
     51 } QEMU_PACKED;
     52 
     53 /* try to guess the disk logical geometry from the MSDOS partition table.
     54    Return 0 if OK, -1 if could not guess */
     55 static int guess_disk_lchs(BlockBackend *blk,
     56                            int *pcylinders, int *pheads, int *psectors)
     57 {
     58     uint8_t buf[BDRV_SECTOR_SIZE];
     59     int i, heads, sectors, cylinders;
     60     struct partition *p;
     61     uint32_t nr_sects;
     62     uint64_t nb_sectors;
     63 
     64     blk_get_geometry(blk, &nb_sectors);
     65 
     66     if (blk_pread(blk, 0, BDRV_SECTOR_SIZE, buf, 0) < 0) {
     67         return -1;
     68     }
     69     /* test msdos magic */
     70     if (buf[510] != 0x55 || buf[511] != 0xaa) {
     71         return -1;
     72     }
     73     for (i = 0; i < 4; i++) {
     74         p = ((struct partition *)(buf + 0x1be)) + i;
     75         nr_sects = le32_to_cpu(p->nr_sects);
     76         if (nr_sects && p->end_head) {
     77             /* We make the assumption that the partition terminates on
     78                a cylinder boundary */
     79             heads = p->end_head + 1;
     80             sectors = p->end_sector & 63;
     81             if (sectors == 0) {
     82                 continue;
     83             }
     84             cylinders = nb_sectors / (heads * sectors);
     85             if (cylinders < 1 || cylinders > 16383) {
     86                 continue;
     87             }
     88             *pheads = heads;
     89             *psectors = sectors;
     90             *pcylinders = cylinders;
     91             trace_hd_geometry_lchs_guess(blk, cylinders, heads, sectors);
     92             return 0;
     93         }
     94     }
     95     return -1;
     96 }
     97 
     98 static void guess_chs_for_size(BlockBackend *blk,
     99                 uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
    100 {
    101     uint64_t nb_sectors;
    102     int cylinders;
    103 
    104     blk_get_geometry(blk, &nb_sectors);
    105 
    106     cylinders = nb_sectors / (16 * 63);
    107     if (cylinders > 16383) {
    108         cylinders = 16383;
    109     } else if (cylinders < 2) {
    110         cylinders = 2;
    111     }
    112     *pcyls = cylinders;
    113     *pheads = 16;
    114     *psecs = 63;
    115 }
    116 
    117 void hd_geometry_guess(BlockBackend *blk,
    118                        uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
    119                        int *ptrans)
    120 {
    121     int cylinders, heads, secs, translation;
    122     HDGeometry geo;
    123 
    124     /* Try to probe the backing device geometry, otherwise fallback
    125        to the old logic. (as of 12/2014 probing only succeeds on DASDs) */
    126     if (blk_probe_geometry(blk, &geo) == 0) {
    127         *pcyls = geo.cylinders;
    128         *psecs = geo.sectors;
    129         *pheads = geo.heads;
    130         translation = BIOS_ATA_TRANSLATION_NONE;
    131     } else if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
    132         /* no LCHS guess: use a standard physical disk geometry  */
    133         guess_chs_for_size(blk, pcyls, pheads, psecs);
    134         translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
    135     } else if (heads > 16) {
    136         /* LCHS guess with heads > 16 means that a BIOS LBA
    137            translation was active, so a standard physical disk
    138            geometry is OK */
    139         guess_chs_for_size(blk, pcyls, pheads, psecs);
    140         translation = *pcyls * *pheads <= 131072
    141             ? BIOS_ATA_TRANSLATION_LARGE
    142             : BIOS_ATA_TRANSLATION_LBA;
    143     } else {
    144         /* LCHS guess with heads <= 16: use as physical geometry */
    145         *pcyls = cylinders;
    146         *pheads = heads;
    147         *psecs = secs;
    148         /* disable any translation to be in sync with
    149            the logical geometry */
    150         translation = BIOS_ATA_TRANSLATION_NONE;
    151     }
    152     if (ptrans) {
    153         if (*ptrans == BIOS_ATA_TRANSLATION_AUTO) {
    154             *ptrans = translation;
    155         } else {
    156             /* Defer to the translation specified by the user.  */
    157             translation = *ptrans;
    158         }
    159     }
    160     trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation);
    161 }
    162 
    163 int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
    164 {
    165     return cyls <= 1024 && heads <= 16 && secs <= 63
    166         ? BIOS_ATA_TRANSLATION_NONE
    167         : BIOS_ATA_TRANSLATION_LBA;
    168 }