From f2360620fbebc24a0e2d58d0038ed3a007d28521 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 31 Oct 2011 11:36:32 +0100 Subject: [PATCH 01/11] qemu-io: Handle create_iovec errors Callers of create_iovec() didn't check for failure and continued with uninitialised data in error cases. This patch adds checks to each call. Signed-off-by: Kevin Wolf --- qemu-io.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/qemu-io.c b/qemu-io.c index 5af887e057..1c49d447aa 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -596,6 +596,9 @@ static int readv_f(int argc, char **argv) nr_iov = argc - optind; buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab); + if (buf == NULL) { + return 0; + } gettimeofday(&t1, NULL); cnt = do_aio_readv(&qiov, offset, &total); @@ -850,6 +853,9 @@ static int writev_f(int argc, char **argv) nr_iov = argc - optind; buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern); + if (buf == NULL) { + return 0; + } gettimeofday(&t1, NULL); cnt = do_aio_writev(&qiov, offset, &total); @@ -950,8 +956,8 @@ static int multiwrite_f(int argc, char **argv) } } - reqs = g_malloc(nr_reqs * sizeof(*reqs)); - buf = g_malloc(nr_reqs * sizeof(*buf)); + reqs = g_malloc0(nr_reqs * sizeof(*reqs)); + buf = g_malloc0(nr_reqs * sizeof(*buf)); qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); for (i = 0; i < nr_reqs; i++) { @@ -985,8 +991,12 @@ static int multiwrite_f(int argc, char **argv) nr_iov = j - optind; /* Build request */ + buf[i] = create_iovec(&qiovs[i], &argv[optind], nr_iov, pattern); + if (buf[i] == NULL) { + goto out; + } + reqs[i].qiov = &qiovs[i]; - buf[i] = create_iovec(reqs[i].qiov, &argv[optind], nr_iov, pattern); reqs[i].sector = offset >> 9; reqs[i].nb_sectors = reqs[i].qiov->size >> 9; @@ -1014,7 +1024,9 @@ static int multiwrite_f(int argc, char **argv) out: for (i = 0; i < nr_reqs; i++) { qemu_io_free(buf[i]); - qemu_iovec_destroy(&qiovs[i]); + if (reqs[i].qiov != NULL) { + qemu_iovec_destroy(&qiovs[i]); + } } g_free(buf); g_free(reqs); @@ -1185,6 +1197,10 @@ static int aio_read_f(int argc, char **argv) nr_iov = argc - optind; ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab); + if (ctx->buf == NULL) { + free(ctx); + return 0; + } gettimeofday(&ctx->t1, NULL); acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, @@ -1280,6 +1296,10 @@ static int aio_write_f(int argc, char **argv) nr_iov = argc - optind; ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern); + if (ctx->buf == NULL) { + free(ctx); + return 0; + } gettimeofday(&ctx->t1, NULL); acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, From 67403dbba76fb294fb3a2317227f4b77037145cc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 31 Oct 2011 11:49:21 +0100 Subject: [PATCH 02/11] qemu-io: Fix multiwrite_f error handling Without this fix, some qiovs can be leaked if an error occurs. Also a semicolon at the end of the command line would make the code walk beyond the end of argv. Signed-off-by: Kevin Wolf --- qemu-io.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qemu-io.c b/qemu-io.c index 1c49d447aa..de26422fcf 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -960,21 +960,21 @@ static int multiwrite_f(int argc, char **argv) buf = g_malloc0(nr_reqs * sizeof(*buf)); qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); - for (i = 0; i < nr_reqs; i++) { + for (i = 0; i < nr_reqs && optind < argc; i++) { int j; /* Read the offset of the request */ offset = cvtnum(argv[optind]); if (offset < 0) { printf("non-numeric offset argument -- %s\n", argv[optind]); - return 0; + goto out; } optind++; if (offset & 0x1ff) { printf("offset %lld is not sector aligned\n", (long long)offset); - return 0; + goto out; } if (i == 0) { @@ -1005,6 +1005,9 @@ static int multiwrite_f(int argc, char **argv) pattern++; } + /* If there were empty requests at the end, ignore them */ + nr_reqs = i; + gettimeofday(&t1, NULL); cnt = do_aio_multiwrite(reqs, nr_reqs, &total); gettimeofday(&t2, NULL); From acae6f1c4c1dae1b7e059751347ca4225b01a391 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 28 Oct 2011 05:28:13 -0400 Subject: [PATCH 03/11] dma: Avoid reentrancy in DMA transfer handlers With the conversion of the block layer to coroutines, bdrv_read/write have changed to run a nested event loop that calls qemu_bh_poll. Consequently a scheduled BH can be called while a DMA transfer handler runs and this means that DMA_run becomes reentrant. Devices haven't been designed to cope with that, so instead of running a nested transfer handler just wait for the next invocation of the BH from the main loop. This fixes some problems with the floppy device. Signed-off-by: Kevin Wolf --- hw/dma.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/dma.c b/hw/dma.c index 8a7302a42f..0a9322daa3 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -358,6 +358,14 @@ static void DMA_run (void) struct dma_cont *d; int icont, ichan; int rearm = 0; + static int running = 0; + + if (running) { + rearm = 1; + goto out; + } else { + running = 1; + } d = dma_controllers; @@ -374,6 +382,8 @@ static void DMA_run (void) } } + running = 0; +out: if (rearm) qemu_bh_schedule_idle(dma_bh); } From 5b47b7c3d38e2fe23948313a8a6af227ba6d46a5 Mon Sep 17 00:00:00 2001 From: Dong Xu Wang Date: Wed, 2 Nov 2011 16:36:20 +0800 Subject: [PATCH 04/11] block/cloop: Fix coding style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix coding style in block/cloop.c. Reviewed-by: Andreas Färber Reviewed_by: Ray Wang Signed-off-by: Dong Xu Wang Signed-off-by: Kevin Wolf --- block/cloop.c | 113 +++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index 775f8a98e1..799b6c2125 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -30,7 +30,7 @@ typedef struct BDRVCloopState { CoMutex lock; uint32_t block_size; uint32_t n_blocks; - uint64_t* offsets; + uint64_t *offsets; uint32_t sectors_per_block; uint32_t current_block; uint8_t *compressed_block; @@ -40,21 +40,23 @@ typedef struct BDRVCloopState { static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) { - const char* magic_version_2_0="#!/bin/sh\n" - "#V2.0 Format\n" - "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; - int length=strlen(magic_version_2_0); - if(length>buf_size) - length=buf_size; - if(!memcmp(magic_version_2_0,buf,length)) - return 2; + const char *magic_version_2_0 = "#!/bin/sh\n" + "#V2.0 Format\n" + "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; + int length = strlen(magic_version_2_0); + if (length > buf_size) { + length = buf_size; + } + if (!memcmp(magic_version_2_0, buf, length)) { + return 2; + } return 0; } static int cloop_open(BlockDriverState *bs, int flags) { BDRVCloopState *s = bs->opaque; - uint32_t offsets_size,max_compressed_block_size=1,i; + uint32_t offsets_size, max_compressed_block_size = 1, i; bs->read_only = 1; @@ -74,26 +76,28 @@ static int cloop_open(BlockDriverState *bs, int flags) s->offsets = g_malloc(offsets_size); if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < offsets_size) { - goto cloop_close; + goto cloop_close; } for(i=0;in_blocks;i++) { - s->offsets[i]=be64_to_cpu(s->offsets[i]); - if(i>0) { - uint32_t size=s->offsets[i]-s->offsets[i-1]; - if(size>max_compressed_block_size) - max_compressed_block_size=size; - } + s->offsets[i] = be64_to_cpu(s->offsets[i]); + if (i > 0) { + uint32_t size = s->offsets[i] - s->offsets[i - 1]; + if (size > max_compressed_block_size) { + max_compressed_block_size = size; + } + } } /* initialize zlib engine */ - s->compressed_block = g_malloc(max_compressed_block_size+1); + s->compressed_block = g_malloc(max_compressed_block_size + 1); s->uncompressed_block = g_malloc(s->block_size); - if(inflateInit(&s->zstream) != Z_OK) - goto cloop_close; - s->current_block=s->n_blocks; + if (inflateInit(&s->zstream) != Z_OK) { + goto cloop_close; + } + s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; - bs->total_sectors = s->n_blocks*s->sectors_per_block; + bs->total_sectors = s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; @@ -105,27 +109,30 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num) { BDRVCloopState *s = bs->opaque; - if(s->current_block != block_num) { - int ret; - uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; + if (s->current_block != block_num) { + int ret; + uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num]; ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block, bytes); - if (ret != bytes) + if (ret != bytes) { return -1; + } - s->zstream.next_in = s->compressed_block; - s->zstream.avail_in = bytes; - s->zstream.next_out = s->uncompressed_block; - s->zstream.avail_out = s->block_size; - ret = inflateReset(&s->zstream); - if(ret != Z_OK) - return -1; - ret = inflate(&s->zstream, Z_FINISH); - if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) - return -1; + s->zstream.next_in = s->compressed_block; + s->zstream.avail_in = bytes; + s->zstream.next_out = s->uncompressed_block; + s->zstream.avail_out = s->block_size; + ret = inflateReset(&s->zstream); + if (ret != Z_OK) { + return -1; + } + ret = inflate(&s->zstream, Z_FINISH); + if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) { + return -1; + } - s->current_block = block_num; + s->current_block = block_num; } return 0; } @@ -136,12 +143,15 @@ static int cloop_read(BlockDriverState *bs, int64_t sector_num, BDRVCloopState *s = bs->opaque; int i; - for(i=0;isectors_per_block), - block_num=(sector_num+i)/s->sectors_per_block; - if(cloop_read_block(bs, block_num) != 0) - return -1; - memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); + for (i = 0; i < nb_sectors; i++) { + uint32_t sector_offset_in_block = + ((sector_num + i) % s->sectors_per_block), + block_num = (sector_num + i) / s->sectors_per_block; + if (cloop_read_block(bs, block_num) != 0) { + return -1; + } + memcpy(buf + i * 512, + s->uncompressed_block + sector_offset_in_block * 512, 512); } return 0; } @@ -160,20 +170,21 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num, static void cloop_close(BlockDriverState *bs) { BDRVCloopState *s = bs->opaque; - if(s->n_blocks>0) - free(s->offsets); + if (s->n_blocks > 0) { + free(s->offsets); + } free(s->compressed_block); free(s->uncompressed_block); inflateEnd(&s->zstream); } static BlockDriver bdrv_cloop = { - .format_name = "cloop", - .instance_size = sizeof(BDRVCloopState), - .bdrv_probe = cloop_probe, - .bdrv_open = cloop_open, - .bdrv_read = cloop_co_read, - .bdrv_close = cloop_close, + .format_name = "cloop", + .instance_size = sizeof(BDRVCloopState), + .bdrv_probe = cloop_probe, + .bdrv_open = cloop_open, + .bdrv_read = cloop_co_read, + .bdrv_close = cloop_close, }; static void bdrv_cloop_init(void) From 756f51e408febecdaff041f096527b820e857762 Mon Sep 17 00:00:00 2001 From: Dong Xu Wang Date: Wed, 2 Nov 2011 16:36:21 +0800 Subject: [PATCH 05/11] block/cloop: Use g_free instead of free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix mismatching allocation and deallocation: g_free should be used to pair with g_malloc. Reviewed-by: Andreas Färber Reviewed_by: Ray Wang Signed-off-by: Dong Xu Wang Signed-off-by: Kevin Wolf --- block/cloop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index 799b6c2125..7570eb8e74 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -171,10 +171,10 @@ static void cloop_close(BlockDriverState *bs) { BDRVCloopState *s = bs->opaque; if (s->n_blocks > 0) { - free(s->offsets); + g_free(s->offsets); } - free(s->compressed_block); - free(s->uncompressed_block); + g_free(s->compressed_block); + g_free(s->uncompressed_block); inflateEnd(&s->zstream); } From 2b6a43a835e5082dedc6a5eea39a59463f97c81c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Oct 2011 09:12:03 +0200 Subject: [PATCH 06/11] vvfat: fix out of bounds array_get usage When reading the address of the first free entry, you cannot use array_get without first marking all entries as occupied. This is visible if you change the sectors per cluster on a floppy from 2 to 1. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/vvfat.c b/block/vvfat.c index e1fcdbc45b..75d0dc07e0 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -799,6 +799,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) /* root directory */ int cur = s->directory.next; array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1); + s->directory.next = ROOT_ENTRIES; memset(array_get(&(s->directory), cur), 0, (ROOT_ENTRIES - cur) * sizeof(direntry_t)); } From e654bfe4c1211754d52b324a505ac46c2bfe2069 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Oct 2011 09:12:04 +0200 Subject: [PATCH 07/11] vvfat: do not fail if the disk has spare sectors If the number of "faked sectors" + the number of sectors that are part of a cluster does not sum up to the total number of sectors, qemu-img convert fails. Read these spare sectors as all zeros. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index 75d0dc07e0..9f851b09de 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1245,7 +1245,7 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, int i; for(i=0;i= s->sector_count) + if (sector_num >= bs->total_sectors) return -1; if (s->qcow) { int n; @@ -1271,7 +1271,7 @@ DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num)); uint32_t sector=sector_num-s->faked_sectors, sector_offset_in_cluster=(sector%s->sectors_per_cluster), cluster_num=sector/s->sectors_per_cluster; - if(read_cluster(s, cluster_num) != 0) { + if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { /* LATER TODO: strict: return -1; */ memset(buf+i*0x200,0,0x200); continue; From aad37c06dda2cd6ab950648435b24ef7776574b0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Oct 2011 09:12:05 +0200 Subject: [PATCH 08/11] vvfat: need to use first_sectors_number to distinguish fdd/hdd This is consistent with what "real" floppies have, so file(1) now actually recognizes the VVFAT image as a 1.44 MB floppy. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index 9f851b09de..1f7cc48fe5 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -954,7 +954,7 @@ static int init_directories(BDRVVVFATState* s, bootsector->number_of_fats=0x2; /* number of FATs */ bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10); bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count); - bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */ + bootsector->media_type=(s->first_sectors_number>1?0xf8:0xf0); /* media descriptor (f8=hd, f0=3.5 fd)*/ s->fat.pointer[0] = bootsector->media_type; bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); bootsector->sectors_per_track=cpu_to_le16(s->bs->secs); @@ -963,7 +963,7 @@ static int init_directories(BDRVVVFATState* s, bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); /* LATER TODO: if FAT32, this is wrong */ - bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */ + bootsector->u.fat16.drive_number=s->first_sectors_number==1?0:0x80; /* fda=0, hda=0x80 */ bootsector->u.fat16.current_head=0; bootsector->u.fat16.signature=0x29; bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); From 5a742b55576c044a6fe07b42937272e553503ddd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Oct 2011 09:12:06 +0200 Subject: [PATCH 09/11] vvfat: unify and correct computation of sector count The sector count is stored in the partition and hence must not include the sectors before its start. At the same time, remove the useless special casing for 1.44 MB floppies. This fixes fsck on VVFAT hard disks, which otherwise tries to seek past the end of the disk. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index 1f7cc48fe5..3e7b40786f 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1026,8 +1026,6 @@ DLOG(if (stderr == NULL) { bs->cyls = 80; bs->heads = 2; bs->secs = 36; } - s->sector_count=bs->cyls*bs->heads*bs->secs; - if (strstr(dirname, ":32:")) { fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); s->fat_type = 32; @@ -1035,9 +1033,11 @@ DLOG(if (stderr == NULL) { s->fat_type = 16; } else if (strstr(dirname, ":12:")) { s->fat_type = 12; - s->sector_count=2880; + bs->secs = 18; } + s->sector_count=bs->cyls*bs->heads*bs->secs-(s->first_sectors_number-1); + if (strstr(dirname, ":rw:")) { if (enable_write_target(s)) return -1; From d71cff42e4cd614986e2d0b8ded7aa3acaf28d92 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Oct 2011 09:12:07 +0200 Subject: [PATCH 10/11] vvfat: do not hardcode sector counts in error message Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index 3e7b40786f..faf2947664 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -916,11 +916,8 @@ static int init_directories(BDRVVVFATState* s, cluster = mapping->end; if(cluster > s->cluster_count) { - fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n", - s->fat_type, - s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB" - : "2.88 MB" - : "504MB"); + fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n", + s->fat_type, s->sector_count / 2000.0); return -EINVAL; } From 273e4e03b3413fd489601cd9d8ba407ccb3b4130 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 4 Nov 2011 17:21:53 +0100 Subject: [PATCH 11/11] vvfat: reorganize computation of disk geometry First determine FAT12/16/32, then compute geometry from that for both FDD and HDD. For 1.44MB floppies, and 2.88MB floppies using FAT16, change to 1 sector/cluster. The default remains 2.88MB with FAT12 and 2 sectors/cluster. Both DOS and mkdosfs by default format a 2.88MB floppy as FAT12. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/vvfat.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/block/vvfat.c b/block/vvfat.c index faf2947664..8511fe523c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -982,7 +982,6 @@ static int is_consistent(BDRVVVFATState *s); static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags) { BDRVVVFATState *s = bs->opaque; - int floppy = 0; int i; #ifdef DEBUG @@ -996,11 +995,8 @@ DLOG(if (stderr == NULL) { s->bs = bs; - s->fat_type=16; /* LATER TODO: if FAT32, adjust */ s->sectors_per_cluster=0x10; - /* 504MB disk*/ - bs->cyls=1024; bs->heads=16; bs->secs=63; s->current_cluster=0xffffffff; @@ -1015,14 +1011,6 @@ DLOG(if (stderr == NULL) { if (!strstart(dirname, "fat:", NULL)) return -1; - if (strstr(dirname, ":floppy:")) { - floppy = 1; - s->fat_type = 12; - s->first_sectors_number = 1; - s->sectors_per_cluster=2; - bs->cyls = 80; bs->heads = 2; bs->secs = 36; - } - if (strstr(dirname, ":32:")) { fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n"); s->fat_type = 32; @@ -1030,7 +1018,27 @@ DLOG(if (stderr == NULL) { s->fat_type = 16; } else if (strstr(dirname, ":12:")) { s->fat_type = 12; - bs->secs = 18; + } + + if (strstr(dirname, ":floppy:")) { + /* 1.44MB or 2.88MB floppy. 2.88MB can be FAT12 (default) or FAT16. */ + if (!s->fat_type) { + s->fat_type = 12; + bs->secs = 36; + s->sectors_per_cluster=2; + } else { + bs->secs=(s->fat_type == 12 ? 18 : 36); + s->sectors_per_cluster=1; + } + s->first_sectors_number = 1; + bs->cyls=80; bs->heads=2; + } else { + /* 32MB or 504MB disk*/ + if (!s->fat_type) { + s->fat_type = 16; + } + bs->cyls=(s->fat_type == 12 ? 64 : 1024); + bs->heads=16; bs->secs=63; } s->sector_count=bs->cyls*bs->heads*bs->secs-(s->first_sectors_number-1); @@ -1058,10 +1066,10 @@ DLOG(if (stderr == NULL) { if(s->first_sectors_number==0x40) init_mbr(s); - - /* for some reason or other, MS-DOS does not like to know about CHS... */ - if (floppy) + else { + /* MS-DOS does not like to know about CHS (?). */ bs->heads = bs->cyls = bs->secs = 0; + } // assert(is_consistent(s)); qemu_co_mutex_init(&s->lock);