Browse Source

[int13] Improve geometry guessing for unaligned partitions

Some partition tables have partitions that are not aligned to a
cylinder boundary, which confuses the current geometry guessing logic.

Enhance the existing logic to ensure that we never reduce our guesses
for the number of heads or sectors per track, and add extra logic to
calculate the exact number of sectors per track if we find a partition
that starts within cylinder zero.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
ebceb8ad8a
1 changed files with 45 additions and 11 deletions
  1. 45
    11
      src/arch/x86/interface/pcbios/int13.c

+ 45
- 11
src/arch/x86/interface/pcbios/int13.c View File

@@ -219,14 +219,13 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
219 219
 	struct master_boot_record *mbr = scratch;
220 220
 	struct partition_table_entry *partition;
221 221
 	unsigned int i;
222
+	unsigned int start_cylinder;
223
+	unsigned int start_head;
224
+	unsigned int start_sector;
222 225
 	unsigned int end_head;
223 226
 	unsigned int end_sector;
224 227
 	int rc;
225 228
 
226
-	/* Default guess is xx/255/63 */
227
-	*heads = 255;
228
-	*sectors = 63;
229
-
230 229
 	/* Read partition table */
231 230
 	if ( ( rc = sandev_rw ( sandev, 0, 1, virt_to_user ( mbr ),
232 231
 				block_read ) ) != 0 ) {
@@ -244,19 +243,54 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
244 243
 	 * heads and sectors_per_track if we find any used
245 244
 	 * partitions.
246 245
 	 */
246
+	*heads = 0;
247
+	*sectors = 0;
247 248
 	for ( i = 0 ; i < 4 ; i++ ) {
249
+
250
+		/* Skip empty partitions */
248 251
 		partition = &mbr->partitions[i];
252
+		if ( ! partition->type )
253
+			continue;
254
+
255
+		/* If partition starts on cylinder 0 then we can
256
+		 * unambiguously determine the number of sectors.
257
+		 */
258
+		start_cylinder = PART_CYLINDER ( partition->chs_start );
259
+		start_head = PART_HEAD ( partition->chs_start );
260
+		start_sector = PART_SECTOR ( partition->chs_start );
261
+		if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) {
262
+			*sectors = ( ( partition->start + 1 - start_sector ) /
263
+				     start_head );
264
+			DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
265
+			       "xx/xx/%d based on partition %d\n",
266
+			       sandev->drive, *sectors, ( i + 1 ) );
267
+		}
268
+
269
+		/* If partition ends on a higher head or sector number
270
+		 * than our current guess, then increase the guess.
271
+		 */
249 272
 		end_head = PART_HEAD ( partition->chs_end );
250 273
 		end_sector = PART_SECTOR ( partition->chs_end );
251
-		if ( ! ( partition->type && end_head && end_sector ) )
252
-			continue;
253
-		*heads = ( end_head + 1 );
254
-		*sectors = end_sector;
255
-		DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
256
-		       "on partition %d\n",
257
-		       sandev->drive, *heads, *sectors, ( i + 1 ) );
274
+		if ( ( end_head + 1 ) > *heads ) {
275
+			*heads = ( end_head + 1 );
276
+			DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
277
+			       "xx/%d/xx based on partition %d\n",
278
+			       sandev->drive, *heads, ( i + 1 ) );
279
+		}
280
+		if ( end_sector > *sectors ) {
281
+			*sectors = end_sector;
282
+			DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
283
+			       "xx/xx/%d based on partition %d\n",
284
+			       sandev->drive, *sectors, ( i + 1 ) );
285
+		}
258 286
 	}
259 287
 
288
+	/* Default guess is xx/255/63 */
289
+	if ( ! *heads )
290
+		*heads = 255;
291
+	if ( ! *sectors )
292
+		*sectors = 63;
293
+
260 294
 	return 0;
261 295
 }
262 296
 

Loading…
Cancel
Save