Commit b570094d9bb19e59618902d825da6d2899b8d295

Authored by ths
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