Commit b570094d9bb19e59618902d825da6d2899b8d295
1 parent
b427c726
vvfat mbr fixes, by Ivan Kalvachev.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3234 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
66 additions
and
29 deletions
block-vvfat.c
@@ -242,21 +242,25 @@ typedef struct bootsector_t { | @@ -242,21 +242,25 @@ typedef struct bootsector_t { | ||
242 | uint8_t magic[2]; | 242 | uint8_t magic[2]; |
243 | } __attribute__((packed)) bootsector_t; | 243 | } __attribute__((packed)) bootsector_t; |
244 | 244 | ||
245 | +typedef struct { | ||
246 | + uint8_t head; | ||
247 | + uint8_t sector; | ||
248 | + uint8_t cylinder; | ||
249 | +} mbr_chs_t; | ||
250 | + | ||
245 | typedef struct partition_t { | 251 | typedef struct partition_t { |
246 | uint8_t attributes; /* 0x80 = bootable */ | 252 | uint8_t attributes; /* 0x80 = bootable */ |
247 | - uint8_t start_head; | ||
248 | - uint8_t start_sector; | ||
249 | - uint8_t start_cylinder; | ||
250 | - uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */ | ||
251 | - uint8_t end_head; | ||
252 | - uint8_t end_sector; | ||
253 | - uint8_t end_cylinder; | 253 | + mbr_chs_t start_CHS; |
254 | + uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */ | ||
255 | + mbr_chs_t end_CHS; | ||
254 | uint32_t start_sector_long; | 256 | uint32_t start_sector_long; |
255 | - uint32_t end_sector_long; | 257 | + uint32_t length_sector_long; |
256 | } __attribute__((packed)) partition_t; | 258 | } __attribute__((packed)) partition_t; |
257 | 259 | ||
258 | typedef struct mbr_t { | 260 | typedef struct mbr_t { |
259 | - uint8_t ignored[0x1be]; | 261 | + uint8_t ignored[0x1b8]; |
262 | + uint32_t nt_id; | ||
263 | + uint8_t ignored2[2]; | ||
260 | partition_t partition[4]; | 264 | partition_t partition[4]; |
261 | uint8_t magic[2]; | 265 | uint8_t magic[2]; |
262 | } __attribute__((packed)) mbr_t; | 266 | } __attribute__((packed)) mbr_t; |
@@ -350,26 +354,57 @@ typedef struct BDRVVVFATState { | @@ -350,26 +354,57 @@ typedef struct BDRVVVFATState { | ||
350 | int downcase_short_names; | 354 | int downcase_short_names; |
351 | } BDRVVVFATState; | 355 | } BDRVVVFATState; |
352 | 356 | ||
357 | +/* take the sector position spos and convert it to Cylinder/Head/Sector position | ||
358 | + * if the position is outside the specified geometry, fill maximum value for CHS | ||
359 | + * and return 1 to signal overflow. | ||
360 | + */ | ||
361 | +static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){ | ||
362 | + int head,sector; | ||
363 | + sector = spos % (bs->secs); spos/= bs->secs; | ||
364 | + head = spos % (bs->heads); spos/= bs->heads; | ||
365 | + if(spos >= bs->cyls){ | ||
366 | + /* Overflow, | ||
367 | + it happens if 32bit sector positions are used, while CHS is only 24bit. | ||
368 | + Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */ | ||
369 | + chs->head = 0xFF; | ||
370 | + chs->sector = 0xFF; | ||
371 | + chs->cylinder = 0xFF; | ||
372 | + return 1; | ||
373 | + } | ||
374 | + chs->head = (uint8_t)head; | ||
375 | + chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) ); | ||
376 | + chs->cylinder = (uint8_t)spos; | ||
377 | + return 0; | ||
378 | +} | ||
353 | 379 | ||
354 | static void init_mbr(BDRVVVFATState* s) | 380 | static void init_mbr(BDRVVVFATState* s) |
355 | { | 381 | { |
356 | /* TODO: if the files mbr.img and bootsect.img exist, use them */ | 382 | /* TODO: if the files mbr.img and bootsect.img exist, use them */ |
357 | mbr_t* real_mbr=(mbr_t*)s->first_sectors; | 383 | mbr_t* real_mbr=(mbr_t*)s->first_sectors; |
358 | partition_t* partition=&(real_mbr->partition[0]); | 384 | partition_t* partition=&(real_mbr->partition[0]); |
385 | + int lba; | ||
359 | 386 | ||
360 | memset(s->first_sectors,0,512); | 387 | memset(s->first_sectors,0,512); |
361 | 388 | ||
389 | + /* Win NT Disk Signature */ | ||
390 | + real_mbr->nt_id= cpu_to_le32(0xbe1afdfa); | ||
391 | + | ||
362 | partition->attributes=0x80; /* bootable */ | 392 | partition->attributes=0x80; /* bootable */ |
363 | - partition->start_head=1; | ||
364 | - partition->start_sector=1; | ||
365 | - partition->start_cylinder=0; | 393 | + |
394 | + /* LBA is used when partition is outside the CHS geometry */ | ||
395 | + lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1); | ||
396 | + lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count); | ||
397 | + | ||
398 | + /*LBA partitions are identified only by start/length_sector_long not by CHS*/ | ||
399 | + partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1); | ||
400 | + partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1); | ||
401 | + | ||
366 | /* FAT12/FAT16/FAT32 */ | 402 | /* FAT12/FAT16/FAT32 */ |
367 | - partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb); | ||
368 | - partition->end_head=s->bs->heads-1; | ||
369 | - partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */; | ||
370 | - partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */; | ||
371 | - partition->start_sector_long=cpu_to_le32(s->bs->secs); | ||
372 | - partition->end_sector_long=cpu_to_le32(s->sector_count); | 403 | + /* DOS uses different types when partition is LBA, |
404 | + probably to prevent older versions from using CHS on them */ | ||
405 | + partition->fs_type= s->fat_type==12 ? 0x1: | ||
406 | + s->fat_type==16 ? (lba?0xe:0x06): | ||
407 | + /*fat_tyoe==32*/ (lba?0xc:0x0b); | ||
373 | 408 | ||
374 | real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; | 409 | real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; |
375 | } | 410 | } |
@@ -973,10 +1008,9 @@ DLOG(if (stderr == NULL) { | @@ -973,10 +1008,9 @@ DLOG(if (stderr == NULL) { | ||
973 | 1008 | ||
974 | s->fat_type=16; | 1009 | s->fat_type=16; |
975 | /* LATER TODO: if FAT32, adjust */ | 1010 | /* LATER TODO: if FAT32, adjust */ |
976 | - s->sector_count=0xec04f; | ||
977 | s->sectors_per_cluster=0x10; | 1011 | s->sectors_per_cluster=0x10; |
978 | - /* LATER TODO: this could be wrong for FAT32 */ | ||
979 | - bs->cyls=1023; bs->heads=15; bs->secs=63; | 1012 | + /* 504MB disk*/ |
1013 | + bs->cyls=1024; bs->heads=16; bs->secs=63; | ||
980 | 1014 | ||
981 | s->current_cluster=0xffffffff; | 1015 | s->current_cluster=0xffffffff; |
982 | 1016 | ||
@@ -991,12 +1025,6 @@ DLOG(if (stderr == NULL) { | @@ -991,12 +1025,6 @@ DLOG(if (stderr == NULL) { | ||
991 | if (!strstart(dirname, "fat:", NULL)) | 1025 | if (!strstart(dirname, "fat:", NULL)) |
992 | return -1; | 1026 | return -1; |
993 | 1027 | ||
994 | - if (strstr(dirname, ":rw:")) { | ||
995 | - if (enable_write_target(s)) | ||
996 | - return -1; | ||
997 | - bs->read_only = 0; | ||
998 | - } | ||
999 | - | ||
1000 | if (strstr(dirname, ":floppy:")) { | 1028 | if (strstr(dirname, ":floppy:")) { |
1001 | floppy = 1; | 1029 | floppy = 1; |
1002 | s->fat_type = 12; | 1030 | s->fat_type = 12; |
@@ -1005,6 +1033,8 @@ DLOG(if (stderr == NULL) { | @@ -1005,6 +1033,8 @@ DLOG(if (stderr == NULL) { | ||
1005 | bs->cyls = 80; bs->heads = 2; bs->secs = 36; | 1033 | bs->cyls = 80; bs->heads = 2; bs->secs = 36; |
1006 | } | 1034 | } |
1007 | 1035 | ||
1036 | + s->sector_count=bs->cyls*bs->heads*bs->secs; | ||
1037 | + | ||
1008 | if (strstr(dirname, ":32:")) { | 1038 | if (strstr(dirname, ":32:")) { |
1009 | fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); | 1039 | fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); |
1010 | s->fat_type = 32; | 1040 | s->fat_type = 32; |
@@ -1015,6 +1045,12 @@ DLOG(if (stderr == NULL) { | @@ -1015,6 +1045,12 @@ DLOG(if (stderr == NULL) { | ||
1015 | s->sector_count=2880; | 1045 | s->sector_count=2880; |
1016 | } | 1046 | } |
1017 | 1047 | ||
1048 | + if (strstr(dirname, ":rw:")) { | ||
1049 | + if (enable_write_target(s)) | ||
1050 | + return -1; | ||
1051 | + bs->read_only = 0; | ||
1052 | + } | ||
1053 | + | ||
1018 | i = strrchr(dirname, ':') - dirname; | 1054 | i = strrchr(dirname, ':') - dirname; |
1019 | assert(i >= 3); | 1055 | assert(i >= 3); |
1020 | if (dirname[i-2] == ':' && isalpha(dirname[i-1])) | 1056 | if (dirname[i-2] == ':' && isalpha(dirname[i-1])) |
@@ -1024,11 +1060,12 @@ DLOG(if (stderr == NULL) { | @@ -1024,11 +1060,12 @@ DLOG(if (stderr == NULL) { | ||
1024 | dirname += i+1; | 1060 | dirname += i+1; |
1025 | 1061 | ||
1026 | bs->total_sectors=bs->cyls*bs->heads*bs->secs; | 1062 | bs->total_sectors=bs->cyls*bs->heads*bs->secs; |
1027 | - if (s->sector_count > bs->total_sectors) | ||
1028 | - s->sector_count = bs->total_sectors; | 1063 | + |
1029 | if(init_directories(s, dirname)) | 1064 | if(init_directories(s, dirname)) |
1030 | return -1; | 1065 | return -1; |
1031 | 1066 | ||
1067 | + s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; | ||
1068 | + | ||
1032 | if(s->first_sectors_number==0x40) | 1069 | if(s->first_sectors_number==0x40) |
1033 | init_mbr(s); | 1070 | init_mbr(s); |
1034 | 1071 |