Statistics
| Branch: | Revision:

root / hw / hd-geometry.c @ a1bc20df

History | View | Annotate | Download (5.5 kB)

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