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 | } |