hd-geometry.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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. #include "block/block.h"
  33. #include "hw/block-common.h"
  34. #include "trace.h"
  35. struct partition {
  36. uint8_t boot_ind; /* 0x80 - active */
  37. uint8_t head; /* starting head */
  38. uint8_t sector; /* starting sector */
  39. uint8_t cyl; /* starting cylinder */
  40. uint8_t sys_ind; /* What partition type */
  41. uint8_t end_head; /* end head */
  42. uint8_t end_sector; /* end sector */
  43. uint8_t end_cyl; /* end cylinder */
  44. uint32_t start_sect; /* starting sector counting from 0 */
  45. uint32_t nr_sects; /* nr of sectors in partition */
  46. } QEMU_PACKED;
  47. /* try to guess the disk logical geometry from the MSDOS partition table.
  48. Return 0 if OK, -1 if could not guess */
  49. static int guess_disk_lchs(BlockDriverState *bs,
  50. int *pcylinders, int *pheads, int *psectors)
  51. {
  52. uint8_t buf[BDRV_SECTOR_SIZE];
  53. int i, heads, sectors, cylinders;
  54. struct partition *p;
  55. uint32_t nr_sects;
  56. uint64_t nb_sectors;
  57. bdrv_get_geometry(bs, &nb_sectors);
  58. /**
  59. * The function will be invoked during startup not only in sync I/O mode,
  60. * but also in async I/O mode. So the I/O throttling function has to
  61. * be disabled temporarily here, not permanently.
  62. */
  63. if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
  64. return -1;
  65. }
  66. /* test msdos magic */
  67. if (buf[510] != 0x55 || buf[511] != 0xaa) {
  68. return -1;
  69. }
  70. for (i = 0; i < 4; i++) {
  71. p = ((struct partition *)(buf + 0x1be)) + i;
  72. nr_sects = le32_to_cpu(p->nr_sects);
  73. if (nr_sects && p->end_head) {
  74. /* We make the assumption that the partition terminates on
  75. a cylinder boundary */
  76. heads = p->end_head + 1;
  77. sectors = p->end_sector & 63;
  78. if (sectors == 0) {
  79. continue;
  80. }
  81. cylinders = nb_sectors / (heads * sectors);
  82. if (cylinders < 1 || cylinders > 16383) {
  83. continue;
  84. }
  85. *pheads = heads;
  86. *psectors = sectors;
  87. *pcylinders = cylinders;
  88. trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
  89. return 0;
  90. }
  91. }
  92. return -1;
  93. }
  94. static void guess_chs_for_size(BlockDriverState *bs,
  95. uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
  96. {
  97. uint64_t nb_sectors;
  98. int cylinders;
  99. bdrv_get_geometry(bs, &nb_sectors);
  100. cylinders = nb_sectors / (16 * 63);
  101. if (cylinders > 16383) {
  102. cylinders = 16383;
  103. } else if (cylinders < 2) {
  104. cylinders = 2;
  105. }
  106. *pcyls = cylinders;
  107. *pheads = 16;
  108. *psecs = 63;
  109. }
  110. void hd_geometry_guess(BlockDriverState *bs,
  111. uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
  112. int *ptrans)
  113. {
  114. int cylinders, heads, secs, translation;
  115. if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
  116. /* no LCHS guess: use a standard physical disk geometry */
  117. guess_chs_for_size(bs, pcyls, pheads, psecs);
  118. translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
  119. } else if (heads > 16) {
  120. /* LCHS guess with heads > 16 means that a BIOS LBA
  121. translation was active, so a standard physical disk
  122. geometry is OK */
  123. guess_chs_for_size(bs, pcyls, pheads, psecs);
  124. translation = *pcyls * *pheads <= 131072
  125. ? BIOS_ATA_TRANSLATION_LARGE
  126. : BIOS_ATA_TRANSLATION_LBA;
  127. } else {
  128. /* LCHS guess with heads <= 16: use as physical geometry */
  129. *pcyls = cylinders;
  130. *pheads = heads;
  131. *psecs = secs;
  132. /* disable any translation to be in sync with
  133. the logical geometry */
  134. translation = BIOS_ATA_TRANSLATION_NONE;
  135. }
  136. if (ptrans) {
  137. *ptrans = translation;
  138. }
  139. trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
  140. }
  141. int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
  142. {
  143. return cyls <= 1024 && heads <= 16 && secs <= 63
  144. ? BIOS_ATA_TRANSLATION_NONE
  145. : BIOS_ATA_TRANSLATION_LBA;
  146. }