1
/****************************************************************************
7
*****************************************************************************
9
Master boot record format:
11
Offset Length Description
12
------ ------ -----------
13
0 446 Boot machine code
14
446 16 Partion #1 info
15
462 16 Partion #2 info
16
478 16 Partion #3 info
17
494 16 Partion #4 info
18
510 2 Magic bytes (0x55 0xAA)
21
Partition info format:
23
Offset Length Description
24
------ ------ -----------
25
0 1 Bootable (0x80=bootable 0x00=not bootable)
27
2 1 Starting sector (bits 5-0) and high bits of starting track (bits 6-5)
28
3 1 Low bits of starting track
34
0x?6 FAT16` (32 MB-2 GB)
37
0x?B FAT32 (512 MB-2 TB)
38
0x?C FAT32 (512 MB-2 TB LBA)
39
0x1? OS/2 Boot manager/Win95 hidden
40
0xC? DR-DOS secured partition
41
0xD? Multiuser DOS secured partition
42
0xE? SpeedStor extended partition
44
6 1 Ending sector (bits 5-0) and high bits of ending track (bits 6-5)
45
7 1 Low bits of ending track
46
8 4 Sector index of beginning of partition
47
12 4 Total sectors in partition
49
****************************************************************************/
51
#include "formats/imageutl.h"
54
#define FAT_SECLEN 512
56
static OPTION_GUIDE_START( pc_chd_create_optionguide )
57
OPTION_INT('T', "cylinders", "Cylinders" )
58
OPTION_INT('H', "heads", "Heads" )
59
OPTION_INT('S', "sectors", "Sectors" )
62
static const char pc_chd_create_optionspec[] = "H1-[16]S1-[32]-63T10/20/30/40/50/60/70/80/90/[100]/110/120/130/140/150/160/170/180/190/200";
64
static const char fat8_string[8] = { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' };
65
static const char fat12_string[8] = { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' };
66
static const char fat16_string[8] = { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' };
67
static const char fat32_string[8] = { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' };
69
/* imports from fat.c */
70
extern void fat_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info);
73
typedef struct _pc_chd_image_info pc_chd_image_info;
74
struct _pc_chd_image_info
76
struct mess_hard_disk_file hard_disk;
80
unsigned int corrupt : 1;
83
UINT32 starting_track;
85
UINT32 starting_sector;
96
static pc_chd_image_info *pc_chd_get_image_info(imgtool_image *image)
98
return (pc_chd_image_info *) imgtool_image_extra_bytes(image);
103
static void pc_chd_locate_block(imgtool_image *image, UINT64 block, UINT32 *cylinder, UINT32 *head, UINT32 *sector)
105
pc_chd_image_info *info;
106
const hard_disk_info *hd_info;
108
info = pc_chd_get_image_info(image);
109
hd_info = imghd_get_header(&info->hard_disk);
111
*sector = block % hd_info->sectors;
112
*head = (block / hd_info->sectors) % hd_info->heads;
113
*cylinder = block / hd_info->sectors / hd_info->heads;
118
static imgtoolerr_t pc_chd_partition_create(imgtool_image *image, int partition_index, UINT64 first_block, UINT64 block_count)
121
UINT8 header_block[FAT_SECLEN];
122
UINT8 partition_block[FAT_SECLEN];
123
UINT8 partition_type;
125
UINT8 *partition_entry;
126
UINT32 first_cylinder, first_head, first_sector;
127
UINT32 last_cylinder, last_head, last_sector;
128
imgtool_class imgclass = { fat_get_info };
129
imgtoolerr_t (*fat_partition_create)(imgtool_image *image, UINT64 first_block, UINT64 block_count);
132
assert((partition_index >= 0) && (partition_index <= 3));
134
/* compute geometry */
135
pc_chd_locate_block(image, first_block, &first_cylinder, &first_head, &first_sector);
136
pc_chd_locate_block(image, first_block + block_count - 1, &last_cylinder, &last_head, &last_sector);
138
/* load fat_partition_create */
139
fat_partition_create = (imgtoolerr_t (*)(imgtool_image *, UINT64, UINT64))
140
imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_PARTITION);
142
/* first create the actual partition */
143
err = fat_partition_create(image, first_block, block_count);
147
/* read the first block of the partition, to determine the type of FAT */
148
err = imgtool_image_read_block(image, first_block, partition_block);
151
fat_type = &partition_block[54];
152
if (!memcmp(fat_type, fat8_string, sizeof(fat8_string)))
153
partition_type = 0x01;
154
else if (!memcmp(fat_type, fat12_string, sizeof(fat12_string)))
155
partition_type = 0x01;
156
else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count < 32*1024*1024/FAT_SECLEN))
157
partition_type = 0x04;
158
else if ((!memcmp(fat_type, fat16_string, sizeof(fat16_string))) && (block_count >= 32*1024*1024/FAT_SECLEN))
159
partition_type = 0x06;
161
partition_type = 0x0B;
163
/* read the partition header */
164
err = imgtool_image_read_block(image, 0, header_block);
168
/* fill out the partition entry */
169
partition_entry = &header_block[446 + (partition_index * 16)];
170
place_integer_le(partition_entry, 0, 1, 0x80);
171
place_integer_le(partition_entry, 1, 1, first_head);
172
place_integer_le(partition_entry, 2, 1, ((first_sector & 0x3F) | (first_cylinder >> 8 << 2)));
173
place_integer_le(partition_entry, 3, 1, first_cylinder);
174
place_integer_le(partition_entry, 4, 1, partition_type);
175
place_integer_le(partition_entry, 5, 1, last_head);
176
place_integer_le(partition_entry, 6, 1, ((last_sector & 0x3F) | (last_cylinder >> 8 << 2)));
177
place_integer_le(partition_entry, 7, 1, last_cylinder);
178
place_integer_le(partition_entry, 8, 4, first_block);
179
place_integer_le(partition_entry, 12, 4, block_count);
181
/* write the partition header */
182
err = imgtool_image_write_block(image, 0, header_block);
192
static imgtoolerr_t pc_chd_read_partition_header(imgtool_image *image)
196
const UINT8 *partition_info;
197
pc_chd_image_info *info;
198
UINT8 buffer[FAT_SECLEN];
200
info = pc_chd_get_image_info(image);
202
/* read the initial block */
203
err = imgtool_image_read_block(image, 0, buffer);
207
/* magic bytes present? */
208
if ((buffer[510] != 0x55) || (buffer[511] != 0xAA))
209
return IMGTOOLERR_CORRUPTIMAGE;
211
for (i = 0; i < ARRAY_LENGTH(info->partitions); i++)
213
partition_info = &buffer[446 + i * 16];
215
info->partitions[i].partition_type = partition_info[4];
216
info->partitions[i].starting_head = partition_info[1];
217
info->partitions[i].starting_track = ((partition_info[2] << 2) & 0xFF00) | partition_info[3];
218
info->partitions[i].starting_sector = partition_info[2] & 0x3F;
219
info->partitions[i].ending_head = partition_info[5];
220
info->partitions[i].ending_track = ((partition_info[6] << 2) & 0xFF00) | partition_info[7];
221
info->partitions[i].ending_sector = partition_info[6] & 0x3F;
223
info->partitions[i].sector_index = pick_integer_le(partition_info, 8, 4);
224
info->partitions[i].total_sectors = pick_integer_le(partition_info, 12, 4);
226
if (info->partitions[i].starting_track > info->partitions[i].ending_track)
227
return IMGTOOLERR_CORRUPTIMAGE;
229
return IMGTOOLERR_SUCCESS;
234
static imgtoolerr_t pc_chd_image_create(imgtool_image *image, imgtool_stream *f, option_resolution *opts)
237
UINT32 cylinders, heads, sectors;
238
pc_chd_image_info *info;
239
UINT8 header_block[FAT_SECLEN];
241
cylinders = option_resolution_lookup_int(opts, 'T');
242
heads = option_resolution_lookup_int(opts, 'H');
243
sectors = option_resolution_lookup_int(opts, 'S');
245
info = pc_chd_get_image_info(image);
247
/* create the hard disk image */
248
err = imghd_create(f, 0, cylinders, heads, sectors, FAT_SECLEN);
252
err = imghd_open(f, &info->hard_disk);
256
/* set up partition header block */
257
memset(header_block, 0, sizeof(header_block));
258
header_block[510] = 0x55;
259
header_block[511] = 0xAA;
260
err = imgtool_image_write_block(image, 0, header_block);
264
err = pc_chd_partition_create(image, 0, 1, cylinders * heads * sectors - 1);
268
err = pc_chd_read_partition_header(image);
274
imghd_close(&info->hard_disk);
280
static imgtoolerr_t pc_chd_image_open(imgtool_image *image, imgtool_stream *stream)
283
pc_chd_image_info *info;
285
info = pc_chd_get_image_info(image);
287
/* open the hard drive */
288
err = imghd_open(stream, &info->hard_disk);
292
err = pc_chd_read_partition_header(image);
296
return IMGTOOLERR_SUCCESS;
301
static void pc_chd_image_close(imgtool_image *image)
303
pc_chd_image_info *info;
304
info = pc_chd_get_image_info(image);
305
imghd_close(&info->hard_disk);
310
static imgtoolerr_t pc_chd_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors)
312
pc_chd_image_info *info;
313
const hard_disk_info *hd_info;
315
info = pc_chd_get_image_info(image);
316
hd_info = imghd_get_header(&info->hard_disk);
318
*tracks = hd_info->cylinders;
319
*heads = hd_info->heads;
320
*sectors = hd_info->sectors;
321
return IMGTOOLERR_SUCCESS;
326
static imgtoolerr_t pc_chd_image_getsectorsize(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, UINT32 *sector_size)
328
pc_chd_image_info *info;
329
info = pc_chd_get_image_info(image);
330
*sector_size = imghd_get_header(&info->hard_disk)->sectorbytes;
331
return IMGTOOLERR_SUCCESS;
336
static UINT32 pc_chd_calc_lbasector(pc_chd_image_info *info, UINT32 track, UINT32 head, UINT32 sector)
339
const hard_disk_info *hd_info;
341
hd_info = imghd_get_header(&info->hard_disk);
343
lbasector *= hd_info->heads;
345
lbasector *= hd_info->sectors;
352
static imgtoolerr_t pc_chd_image_readsector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, void *buffer, size_t len)
354
pc_chd_image_info *info;
355
info = pc_chd_get_image_info(image);
356
return imghd_read(&info->hard_disk,
357
pc_chd_calc_lbasector(info, track, head, sector),
363
static imgtoolerr_t pc_chd_image_writesector(imgtool_image *image, UINT32 track, UINT32 head, UINT32 sector, const void *buffer, size_t len, int ddam)
365
pc_chd_image_info *info;
366
info = pc_chd_get_image_info(image);
367
return imghd_write(&info->hard_disk,
368
pc_chd_calc_lbasector(info, track, head, sector),
374
static imgtoolerr_t pc_chd_image_readblock(imgtool_image *image, void *buffer, UINT64 block)
376
pc_chd_image_info *info;
377
info = pc_chd_get_image_info(image);
378
return imghd_read(&info->hard_disk, block, buffer);
383
static imgtoolerr_t pc_chd_image_writeblock(imgtool_image *image, const void *buffer, UINT64 block)
385
pc_chd_image_info *info;
386
info = pc_chd_get_image_info(image);
387
return imghd_write(&info->hard_disk, block, buffer);
392
static imgtoolerr_t pc_chd_list_partitions(imgtool_image *image, imgtool_partition_info *partitions, size_t len)
394
pc_chd_image_info *info;
397
info = pc_chd_get_image_info(image);
399
for (i = 0; i < MIN(4, len); i++)
401
partitions[i].base_block = info->partitions[i].sector_index;
402
partitions[i].block_count = info->partitions[i].total_sectors;
404
switch(info->partitions[i].partition_type)
406
case 0x00: /* Empty Partition */
407
partitions[i].get_info = NULL;
410
case 0x01: /* FAT12 */
411
case 0x04: /* FAT16 (-32 MB) */
412
case 0x06: /* FAT16 (32+ MB) */
413
case 0x0B: /* FAT32 */
414
case 0x0C: /* FAT32 (LBA Mapped) */
415
case 0x0E: /* FAT16 (LBA Mapped) */
416
case 0x11: /* OS/2 FAT12 */
417
case 0x14: /* OS/2 FAT16 (-32 MB) */
418
case 0x16: /* OS/2 FAT16 (32+ MB) */
419
case 0x1B: /* Hidden Win95 FAT32 */
420
case 0x1C: /* Hidden Win95 FAT32 (LBA Mapped) */
421
case 0x1D: /* Hidden Win95 FAT16 (LBA Mapped) */
422
case 0xC1: /* DR-DOS FAT12 */
423
case 0xC4: /* DR-DOS FAT16 (-32 MB) */
424
case 0xC6: /* DR-DOS FAT16 (32+ MB) */
425
case 0xD1: /* Old Multiuser DOS FAT12 */
426
case 0xD4: /* Old Multiuser DOS FAT16 (-32 MB) */
427
case 0xD6: /* Old Multiuser DOS FAT16 (32+ MB) */
428
partitions[i].get_info = fat_get_info;
432
partitions[i].get_info = unknown_partition_get_info;
436
return IMGTOOLERR_SUCCESS;
441
void pc_chd_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info)
445
/* --- the following bits of info are returned as 64-bit signed integers --- */
446
case IMGTOOLINFO_INT_BLOCK_SIZE: info->i = FAT_SECLEN; break;
447
case IMGTOOLINFO_INT_IMAGE_EXTRA_BYTES: info->i = sizeof(pc_chd_image_info); break;
448
case IMGTOOLINFO_INT_TRACKS_ARE_CALLED_CYLINDERS: info->i = 1; break;
450
/* --- the following bits of info are returned as NULL-terminated strings --- */
451
case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "pc_chd"); break;
452
case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "PC CHD disk image"); break;
453
case IMGTOOLINFO_STR_FILE_EXTENSIONS: strcpy(info->s = imgtool_temp_str(), "chd"); break;
454
case IMGTOOLINFO_STR_CREATEIMAGE_OPTSPEC: strcpy(info->s = imgtool_temp_str(), pc_chd_create_optionspec); break;
456
/* --- the following bits of info are returned as pointers to data or functions --- */
457
case IMGTOOLINFO_PTR_CREATE: info->create = pc_chd_image_create; break;
458
case IMGTOOLINFO_PTR_OPEN: info->open = pc_chd_image_open; break;
459
case IMGTOOLINFO_PTR_CLOSE: info->close = pc_chd_image_close; break;
460
case IMGTOOLINFO_PTR_READ_SECTOR: info->read_sector = pc_chd_image_readsector; break;
461
case IMGTOOLINFO_PTR_WRITE_SECTOR: info->write_sector = pc_chd_image_writesector; break;
462
case IMGTOOLINFO_PTR_READ_BLOCK: info->read_block = pc_chd_image_readblock; break;
463
case IMGTOOLINFO_PTR_WRITE_BLOCK: info->write_block = pc_chd_image_writeblock; break;
464
case IMGTOOLINFO_PTR_GET_SECTOR_SIZE: info->get_sector_size = pc_chd_image_getsectorsize; break;
465
case IMGTOOLINFO_PTR_CREATEIMAGE_OPTGUIDE: info->createimage_optguide = pc_chd_create_optionguide; break;
466
case IMGTOOLINFO_PTR_GET_GEOMETRY: info->get_geometry = pc_chd_image_get_geometry; break;
467
case IMGTOOLINFO_PTR_LIST_PARTITIONS: info->list_partitions = pc_chd_list_partitions; break;