From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49111) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XCYgu-0005ej-QM for qemu-devel@nongnu.org; Wed, 30 Jul 2014 14:33:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XCYgn-000218-Uq for qemu-devel@nongnu.org; Wed, 30 Jul 2014 14:33:32 -0400 Received: from g9t1613g.houston.hp.com ([15.240.0.71]:57416) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XCYgn-0001zI-Mc for qemu-devel@nongnu.org; Wed, 30 Jul 2014 14:33:25 -0400 Received: from g4t3427.houston.hp.com (g4t3427.houston.hp.com [15.201.208.55]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by g9t1613g.houston.hp.com (Postfix) with ESMTPS id E394965576 for ; Wed, 30 Jul 2014 18:09:03 +0000 (UTC) From: Eniac Zhang Date: Tue, 29 Jul 2014 20:22:06 -0400 Message-Id: <1406679726-32293-1-git-send-email-eniacz@hp.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH] AHCI read/write corruption with int13h List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: eniacz@hp.com, jsnow@redhat.com The AHCI controller code in Qemu has a bug that it will use the wrong LBA address when Seabios tries to access LBA>128GB (aka 127.5GB limit http://www.hardwaresecrets.com/printpage/Hard-Disk-Dr= ives-Capacity-Limits/482). When we needs to access the LBA>0xfffffff, 28bit LBA is not sufficient thus AHCI code needs to convert that into an LBA48 command, but it didn=E2=80=99t set all the flags correctly, so low level code ends up re= ading a sector at different address. how to duplicate: turn off the workaround in ahci.c, leaving the debug logs in core.c, compile your qemu-system-x86_64 and then run: ./ qemu-system-x86_64 -fda dos622.img -drive if=3Dnone,file=3D./blank.qco= w2,id=3Dhdc,media=3Ddisk -device ide-hd,drive=3Dhdc,bus=3Dide.0 -M q35 -m= 256M -vnc :1 -boot a Blank.qcow2 is a 300GB virtual disk file I pre-created, you can leave it = blank cause what=E2=80=99s on disk doesn=E2=80=99t matter in this test. = dos622.img is the dos622 floppy image with debug.com and a batch file: a 100 mov si, 0200 mov ax, 4200 mov dx, 0080 int 13 ret ; 0x3: length e 200 10 00 7f 00 00 00 00 50 ; lba e 208 88 69 e2 11 00 00 00 00 r ip 100 g r d 5000:0 q Connect vncviewer, once dos boot is completed, type debuglba48 =3D (cmd_fis[2] =3D=3D WIN_READDMA_EXT=20 + || cmd_fis[2] =3D=3D WIN_READ_EXT + || cmd_fis[2] =3D=3D WIN_READDMA_QUEUED_EXT + || cmd_fis[2] =3D=3D WIN_READ_NATIVE_MAX_EXT + || cmd_fis[2] =3D=3D WIN_MULTREAD_EXT + || cmd_fis[2] =3D=3D WIN_WRITE_EXT + || cmd_fis[2] =3D=3D WIN_WRITEDMA_EXT + || cmd_fis[2] =3D=3D WIN_WRITEDMA_QUEUED_EXT + || cmd_fis[2] =3D=3D WIN_SET_MAX_EXT + || cmd_fis[2] =3D=3D WIN_MULTWRITE_EXT + || cmd_fis[2] =3D=3D WIN_VERIFY_EXT + || cmd_fis[2] =3D=3D WIN_FLUSH_CACHE_EXT + ); + ide_state->select |=3D 0x40; ide_set_sector(ide_state, ((uint64_t)cmd_fis[10] << 40) | ((uint64_t)cmd_fis[9] << 32) /* This is used for LBA48 commands *= / diff --git a/hw/ide/core.c b/hw/ide/core.c index db191a6..988a935 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -445,9 +445,23 @@ void ide_transfer_stop(IDEState *s) s->status &=3D ~DRQ_STAT; } =20 +#define DEBUG_SECTOR 1 + +#if DEBUG_SECTOR +#define DPRINTF(fmt, ...) \ + do { printf("debug_sector: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) +#endif + +/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. = */ +#define ACPI_DATA_SIZE 0x10000 +#define BIOS_CFG_IOPORT 0x510 + int64_t ide_get_sector(IDEState *s) { int64_t sector_num; + if (s->select & 0x40) { /* lba */ if (!s->lba48) { @@ -464,12 +478,18 @@ int64_t ide_get_sector(IDEState *s) sector_num =3D ((s->hcyl << 8) | s->lcyl) * s->heads * s->sector= s + (s->select & 0x0f) * s->sectors + (s->sector - 1); } +#if DEBUG_SECTOR + DPRINTF("get_sector: %lx\n", sector_num); +#endif return sector_num; } =20 void ide_set_sector(IDEState *s, int64_t sector_num) { unsigned int cyl, r; +#if DEBUG_SECTOR + DPRINTF("set_sector: %lx\n", sector_num); +#endif if (s->select & 0x40) { if (!s->lba48) { s->select =3D (s->select & 0xf0) | (sector_num >> 24); --=20 1.7.11.7