Compare commits

...

55 Commits

Author SHA1 Message Date
Anthony Liguori
0850f81099 Update version for 0.14.0
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-16 08:42:46 -06:00
Anthony Liguori
6a7999b222 Update version for 0.14.0-rc2
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-14 16:01:01 -06:00
Anthony Liguori
e3c8fc83aa Fix build from previous commit
I unfortunately got on an unnamed branch and pushed the wrong bits

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-14 14:42:29 -06:00
Bruce Rogers
bd2483faf1 PATCH] slirp: fix buffer overrun
Since the addition of the slirp member to struct mbuf, the value of
SLIRP_MSIZE and the initialization of m_size have not been correct,
resulting in overrunning the end of the malloc'd buffer in some cases.

Signed-off-by: Bruce Rogers <brogers@novell.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-14 14:19:12 -06:00
Gleb Natapov
7083b66b45 correctly check ppr priority during interrupt injection]
TPR blocks all interrupts in a priority class, so simple "less or
equal" check is not enough.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Reviewed-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-14 14:15:36 -06:00
Justin M. Forbes
9de12c453d Merge branch 'linux-user-for-0.14' of git://gitorious.org/qemu-maemo/qemu 2011-02-14 12:11:43 -06:00
Kevin Wolf
c7e9df3bc6 qcow2: Fix order in L2 table COW
When copying L2 tables (this happens only with internal snapshots), the order
wasn't completely safe, so that after a crash you could end up with a L2 table
that has too low refcount, possibly leading to corruption in the long run.

This patch puts the operations in the right order: First allocate the new
L2 table and replace the reference, and only then decrease the refcount of the
old table.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 16fde5f2c2)
2011-02-11 14:34:06 +01:00
Kevin Wolf
038a866f81 qemu-img: Improve error messages for failed bdrv_open
Output the error message string of the bdrv_open return code. Also set a
non-empty device name for the images because the unknown feature error message
includes it.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b9eaf9ecb1)
2011-02-11 14:34:01 +01:00
Kevin Wolf
64a216f58e qed: Report error for unsupported features
Instead of just returning -ENOTSUP, generate a more detailed error.

Unfortunately we don't have a helpful text for features that we don't know yet,
so just print the feature mask. It might be useful at least if someone asks for
help.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Acked-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 10b758e85c)
2011-02-11 14:34:01 +01:00
Kevin Wolf
12597b0608 qcow2: Report error for version > 2
The qcow2 driver is now declared responsible for any QCOW image that has
version 2 or greater (before this, version 3 would be detected as raw).

For everything newer than version 2, an error is reported.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit e8cdcec123)
2011-02-11 14:34:00 +01:00
Kevin Wolf
e37dcdfb8d qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit f54e364112)
2011-02-11 14:33:59 +01:00
Kevin Wolf
5c9596112c qcow2: Fix error handling for reading compressed clusters
When reading a compressed cluster failed, qcow2 falsely returned success.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
(cherry picked from commit 8af3648843)
2011-02-11 14:33:58 +01:00
Kevin Wolf
16e07bc282 qcow2: Fix error handling for immediate backing file read failure
Requests could return success even though they failed when bdrv_aio_readv
returned NULL for a backing file read.

Reported-by: Chunqiang Tang <ctang@us.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 3ab4c7e92d)
2011-02-11 14:33:57 +01:00
Chunqiang Tang
607a375709 QCOW2: bug fix - read base image beyond its size
This patch fixes the following bug in QCOW2. For a QCOW2 image that is larger
than its base image, when handling a read request straddling over the end of the
base image, the QCOW2 driver attempts to read beyond the end of the base image
and the request would fail.

This bug was found by Fast Virtual Disk (FVD)'s fully automated testing tool.
The following test triggered the bug.

dd if=/dev/zero of=/var/ramdisk/truth.raw count=0 bs=1 seek=1098561536
dd if=/dev/zero of=/var/ramdisk/zero-500M.raw count=0 bs=1 seek=593099264
./qemu-img create -f qcow2 -ocluster_size=65536,backing_fmt=blksim -b /var/ramdisk/zero-500M.raw /var/ramdisk/test.qcow2 1098561536
./qemu-io --auto --seed=30477694 --truth=/var/ramdisk/truth.raw --format=qcow2 --test=blksim:/var/ramdisk/test.qcow2 --verify_write=true --compare_before=false --compare_after=true --round=100000 --parallel=100 --io_size=10485760 --fail_prob=0 --cancel_prob=0 --instant_qemubh=true

Signed-off-by: Chunqiang Tang <ctang@us.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit e0d9c6f937)
2011-02-11 14:33:56 +01:00
Jes Sorensen
ac12a5af0b Change snapshot_blkdev hmp to use correct argument type for device
Pointed out by Markus

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 982aa95532)
2011-02-11 14:33:54 +01:00
Stefan Weil
b03088c32f linux-user: Fix possible realloc memory leak
Extract from "man realloc":
"If realloc() fails the original block is left untouched;
it is not freed or moved."

Fix a possible memory leak (reported by cppcheck).

Cc: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
(cherry picked from commit 8d79de6e42)
2011-02-09 21:24:05 +01:00
Stefan Weil
eee37d310c linux-user: Fix possible realloc memory leak
Extract from "man realloc":
"If realloc() fails the original block is left untouched;
it is not freed or moved."

Fix a possible memory leak (reported by cppcheck).

Cc: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
2011-02-09 09:05:48 +02:00
Martin Mohring
28637533d6 linux-user: fix for loopmount ioctl
In case a chrooted build uses XEN or KVM, a looped mount needs to be done to setup the chroot.
The ioctl for loop mount works correctly for arm, mips, ppc32 and sh4, so its now activated.

Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
2011-02-09 09:05:48 +02:00
Justin M. Forbes
23e4cff984 Merge branch 'master' of git+ssh://git.qemu.org/pub/git/qemu-stable-0.14 2011-02-08 12:41:18 -06:00
Markus Armbruster
0893194783 blockdev: Plug memory leak in drive_init() error paths
Should have spotted this when doing commit 319ae529.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
2011-02-08 08:41:54 -06:00
Markus Armbruster
e5f1c19665 blockdev: Plug memory leak in drive_uninit()
Started leaking in commit 1dae12e6.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
2011-02-08 08:41:54 -06:00
Jan Kiszka
343c1de916 x86: Fix MCA broadcast parameters for TCG case
When broadcasting MCEs, we need to set MCIP and RIPV in mcg_status like
it is done for KVM. Use the symbolic constants at this chance.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 2905749287)
2011-02-08 12:37:30 +01:00
Stefan Weil
b75568889f qemu-timer: Fix compilation of new timer code for w32, w64
qemu_next_alarm_deadline() is needed by MinGW, too.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit f26e5a54f0)
2011-02-08 09:06:41 +01:00
Anthony Liguori
a3dfab563e Update version for 0.14.0-rc1
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-07 13:36:28 -06:00
Marcelo Tosatti
c1f1ffff21 block: enable in_use flag
Set block device in use during block migration, disallow drive_del and
bdrv_truncate for in use devices.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 8591675f44)
2011-02-07 12:55:32 +01:00
Marcelo Tosatti
44d631a001 Add flag to indicate external users to block device
Certain operations such as drive_del or resize cannot be performed
while external users (eg. block migration) reference the block device.

Add a flag to indicate that.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit db593f2565)
2011-02-07 12:55:29 +01:00
Marcelo Tosatti
28b0e1cd0e block-migration: add reference to target DriveInfo
So that ejection of attached device by guest does not free data
in use by block migration instance.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
CC: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f48905d44f)
2011-02-07 12:55:27 +01:00
Marcelo Tosatti
ddebe9d473 blockdev: add refcount to DriveInfo
The host part of a block device can be deleted with in progress
block migration.

To fix this, add a reference count to DriveInfo, freeing resources
on last reference.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
CC: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 84fb392526)
2011-02-07 12:55:26 +01:00
Marcelo Tosatti
f17f8b687c block-migration: actually disable dirty tracking on cleanup
Call to set_dirty_tracking() is misplaced.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 8f794c557c)
2011-02-07 12:55:25 +01:00
Alexander Graf
d27dd7e1a2 ahci: make number of ports runtime determined
Different AHCI controllers have a different number of ports, so the core
shouldn't care about the amount of ports available.

This patch makes the number of ports available to the AHCI core runtime
configurable, allowing us to have multiple different AHCI implementations
with different amounts of ports.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 2c4b9d0ea4)
2011-02-07 12:55:25 +01:00
Alexander Graf
c3a965c943 ahci: Implement HBA reset
The ahci code was missing its soft reset functionality. This wasn't really an
issue for Linux guests, but Windows gets confused when the controller doesn't
reset when it tells it so.

Using this patch I can now successfully boot Windows 7 from AHCI using AHCI
enabled SeaBIOS.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 760c3e44d3)
2011-02-07 12:55:24 +01:00
Alexander Graf
abc9997416 ahci: send init d2h fis on fis enable
The drive sends a d2h init fis on initialization. Usually, the guest doesn't
receive fises yet at that point though, so the delivery is deferred.

Let's reflect that by sending the init fis on fis receive enablement.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 87e62065bb)
2011-02-07 12:55:23 +01:00
Alexander Graf
ed97a4f2cf ahci: split ICH and AHCI even more
Sebastian's patch already did a pretty good job at splitting up ICH-9
AHCI code and the AHCI core. We need some more though. Copyright was missing,
the lspci dump belongs to ICH-9, we don't need the AHCI core to have its
own qdev device duplicate.

So let's split them a bit more in this patch, making things easier to
read an understand.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 7fb6577b13)
2011-02-07 12:55:22 +01:00
Alexander Graf
8f7dfd6bda ahci: add license header in ahci.h
Due to popular request, this patch adds a license header to ahci.h

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f83a40dcd7)
2011-02-07 12:55:21 +01:00
Sebastian Herbszt
e81c113d28 ahci: split ICH9 from core
There are multiple ahci devices out there. The currently implemented ich-9
is only one of the many. So let's split that one out into a separate file
to stress the difference.

Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 03c7a6a8e7)
2011-02-07 12:55:19 +01:00
Stefan Weil
d4e6590ab8 block/vdi: Fix wrong size in conditionally used memset, memcmp
Error report from cppcheck:
block/vdi.c:122: error: Using sizeof for array given as function argument returns the size of pointer.
block/vdi.c:128: error: Using sizeof for array given as function argument returns the size of pointer.

Fix both by setting the correct size.

The buggy code is only used when QEMU is build without uuid support.
The bug is not critical, so there is no urgent need to apply it to
old versions of QEMU.

Cc: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 4f3669ea5b)
2011-02-07 12:55:18 +01:00
MORITA Kazutaka
f188c02db7 Documentation: add Sheepdog disk images
Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 42af9c30ea)
2011-02-07 12:55:17 +01:00
Kevin Wolf
7edb1c3a51 qcow2: Really use cache=unsafe for image creation
For cache=unsafe we also need to set BDRV_O_CACHE_WB, otherwise we have some
strange unsafe writethrough mode.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit e1a7107f2d)
2011-02-07 12:55:16 +01:00
Gleb Natapov
fd08f20c23 do not pass NULL to strdup.
Also use qemu_strdup() instead of strdup() in bootindex code.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 4fef930af8)
2011-02-04 21:23:05 +01:00
Christophe Lyon
8798240196 Set the right overflow bit for neon 32 and 64 bit saturating add/sub.
Signed-off-by: Christophe Lyon <christophe.lyon@st.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 72902672dc)
2011-02-04 20:59:57 +01:00
Christophe Lyon
ffbda4e682 target-arm: Fix Neon vsra instructions.
This patch fixes the errors reported by my tests in VSRA.

Signed-off-by: Christophe Lyon <christophe.lyon@st.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 5371cb8140)
2011-02-04 20:50:21 +01:00
Aurelien Jarno
81cd8f6047 target-sh4: fix negc
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 7026259f79)
2011-02-04 20:50:16 +01:00
Jan Kiszka
1299aa0d03 ioapic: Style & magics cleanup
Fix a few style issues and convert magic numbers into prober symbolic
constants, also fixing the wrong but unused IOAPIC_DM_SIPI value.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 1f5e71a8e6)
2011-02-04 06:53:52 -06:00
Jan Kiszka
8faaf42a4c ioapic: Add support for qemu-kvm's vmstate v2
qemu-kvm carries the IOAPIC base address in its v2 vmstate. We only
support the default base address so far, and saving even that in the
device state was rejected.

Add a padding field to be able to read qemu-kvm's old state, but
increase our version to 3, indicating that we are not saving a valid
address. This also gives downstream the chance to change to stop
evaluating the base_address and move to v3 as well.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 5dce499948)
2011-02-04 06:53:52 -06:00
Jan Kiszka
f05929b182 ioapic: Save/restore irr
This is a guest modifiable state that must be saved/restored properly.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 35a74c5c59)
2011-02-04 06:53:52 -06:00
Jan Kiszka
bc3aaac57b ioapic: Implement EOI handling for level-triggered IRQs
Add the missing EOI broadcast from local APIC to the IOAPICs on
completion of level-triggered IRQs. This ensures that a still asserted
IRQ source properly re-triggers an APIC IRQ.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 0280b571c1)
2011-02-04 06:53:52 -06:00
Corentin Chary
602c075070 vnc: qemu can die if the client is disconnected while updating screen
agraf reported that qemu_mutex_destroy(vs->output_mutex) while failing
in vnc_disconnect_finish().

It's because vnc_worker_thread_loop() tries to unlock the mutex while
not locked. The unlocking call doesn't fail (pthread bug ?), but
the destroy call does.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 73eb4c04e9)
2011-02-04 06:53:52 -06:00
Amit Shah
cb5281b199 virtio-serial: Make sure virtqueue is ready before discarding data
This can happen if a port gets unplugged before guest has chance to
initialise vqs.

Reported-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 7185f9315b)
2011-02-04 06:53:52 -06:00
Stefan Weil
9a121a2fbf ui/sdl: Fix handling of caps lock and num lock keys
Starting with SDL version 1.2.14, caps lock and num lock keys
will send a SDL_KEYUP when SDL_DISABLE_LOCK_KEYS=1 is set in
the environment.

The new code sets the environment unconditionally
(it won't harm old versions which do not know it).

The workaround for SDL_KEYUP is only compiled with old SDL versions.

A similar patch without handling of old SDL versions was already
published by Benjamin Drung for Ubuntu.

Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Benjamin Drung <benjamin.drung@gmail.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 4e79bcbb96)
2011-02-04 06:53:52 -06:00
Paolo Bonzini
366c2452b1 Unify alarm deadline computation
This patch shows how using the correct formula for
qemu_next_deadline_dyntick can simplify the code of
host_alarm_handler and eliminate useless duplication.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 4c3d45eb69)
2011-02-04 06:53:52 -06:00
Paolo Bonzini
bbd9827cc7 Correct alarm deadline computation
When the QEMU_CLOCK_HOST clock was added, computation of its
deadline was added to qemu_next_deadline, which is correct but
incomplete.

I noticed this by reading the very convoluted rules whereby
qemu_next_deadline_dyntick is computed, which miss QEMU_CLOCK_HOST
when use_icount is true.  This patch inlines qemu_next_deadline
into qemu_next_deadline_dyntick, and then corrects the logic to skip
only QEMU_CLOCK_VIRTUAL when use_icount is true.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 6ad0a1ed21)
2011-02-04 06:53:51 -06:00
Paolo Bonzini
d7f88b4bbd use nanoseconds everywhere for timeout computation
Suggested by Aurelien Jarno.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 9c13246ac1)
2011-02-04 06:53:51 -06:00
Yoshiaki Tamura
ea01a58014 savevm: fix corruption in vmstate_subsection_load().
Although it's rare to happen in live migration, when the head of a
byte stream contains 0x05 which is the marker of subsection, the
loader gets corrupted because vmstate_subsection_load() continues even
the device doesn't require it.  This patch adds a checker whether
subsection is needed, and skips following routines if not needed.

Signed-off-by: Yoshiaki Tamura <tamura.yoshiaki@lab.ntt.co.jp>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit eb60260de0)
2011-02-04 06:53:51 -06:00
Aurelien Jarno
0833073edf Revert "Open up the 0.15 development branch"
This reverts commit 0e1272f22b.
2011-02-02 08:39:44 +01:00
Anthony Liguori
0e1272f22b Open up the 0.15 development branch
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-02-01 20:15:26 -06:00
41 changed files with 1134 additions and 657 deletions

View File

@@ -244,6 +244,7 @@ hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o
hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
hw-obj-$(CONFIG_AHCI) += ide/ahci.o
hw-obj-$(CONFIG_AHCI) += ide/ich.o
# SCSI layer
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o

View File

@@ -1 +1 @@
0.13.90
0.14.0

View File

@@ -19,6 +19,7 @@
#include "monitor.h"
#include "block-migration.h"
#include "migration.h"
#include "blockdev.h"
#include <assert.h>
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
@@ -299,6 +300,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
bmds->completed_sectors = 0;
bmds->shared_base = block_mig_state.shared_base;
alloc_aio_bitmap(bmds);
drive_get_ref(drive_get_by_blockdev(bs));
bdrv_set_in_use(bs, 1);
block_mig_state.total_sector_sum += sectors;
@@ -533,8 +536,12 @@ static void blk_mig_cleanup(Monitor *mon)
BlkMigDevState *bmds;
BlkMigBlock *blk;
set_dirty_tracking(0);
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
bdrv_set_in_use(bmds->bs, 0);
drive_put_ref(drive_get_by_blockdev(bmds->bs));
qemu_free(bmds->aio_bitmap);
qemu_free(bmds);
}
@@ -545,8 +552,6 @@ static void blk_mig_cleanup(Monitor *mon)
qemu_free(blk);
}
set_dirty_tracking(0);
monitor_printf(mon, "\n");
}

13
block.c
View File

@@ -1132,6 +1132,8 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return -ENOTSUP;
if (bs->read_only)
return -EACCES;
if (bdrv_in_use(bs))
return -EBUSY;
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
@@ -2774,6 +2776,17 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs)
return bs->dirty_count;
}
void bdrv_set_in_use(BlockDriverState *bs, int in_use)
{
assert(bs->in_use != in_use);
bs->in_use = in_use;
}
int bdrv_in_use(BlockDriverState *bs)
{
return bs->in_use;
}
int bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags)

View File

@@ -241,6 +241,8 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors);
int64_t bdrv_get_dirty_count(BlockDriverState *bs);
void bdrv_set_in_use(BlockDriverState *bs, int in_use);
int bdrv_in_use(BlockDriverState *bs);
typedef enum {
BLKDBG_L1_UPDATE,

View File

@@ -515,13 +515,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return ret;
}
} else {
/* FIXME Order */
if (l2_offset)
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
/* First allocate a new L2 table (and do COW if needed) */
ret = l2_allocate(bs, l1_index, &l2_table);
if (ret < 0) {
return ret;
}
/* Then decrease the refcount of the old table */
if (l2_offset) {
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
}
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
}
@@ -878,11 +881,11 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
if (ret < 0) {
return -1;
return ret;
}
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data + sector_offset, csize) < 0) {
return -1;
return -EIO;
}
s->cluster_cache_offset = coffset;
}

View File

@@ -28,6 +28,7 @@
#include "aes.h"
#include "block/qcow2.h"
#include "qemu-error.h"
#include "qerror.h"
/*
Differences with QCOW:
@@ -59,7 +60,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
be32_to_cpu(cow_header->version) == QCOW_VERSION)
be32_to_cpu(cow_header->version) >= QCOW_VERSION)
return 100;
else
return 0;
@@ -163,10 +164,18 @@ static int qcow2_open(BlockDriverState *bs, int flags)
be64_to_cpus(&header.snapshots_offset);
be32_to_cpus(&header.nb_snapshots);
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) {
if (header.magic != QCOW_MAGIC) {
ret = -EINVAL;
goto fail;
}
if (header.version != QCOW_VERSION) {
char version[64];
snprintf(version, sizeof(version), "QCOW version %d", header.version);
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "qcow2", version);
ret = -ENOTSUP;
goto fail;
}
if (header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS) {
ret = -EINVAL;
@@ -355,7 +364,7 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
else
n1 = bs->total_sectors - sector_num;
qemu_iovec_memset(qiov, 0, 512 * (nb_sectors - n1));
qemu_iovec_memset_skip(qiov, 0, 512 * (nb_sectors - n1), 512 * n1);
return n1;
}
@@ -478,10 +487,11 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
if (n1 > 0) {
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
&acb->hd_qiov, acb->cur_nr_sectors,
qcow2_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
&acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
}
} else {
ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
if (ret < 0)
@@ -496,8 +506,10 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
}
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0)
ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
if (ret < 0) {
goto done;
}
qemu_iovec_from_buffer(&acb->hd_qiov,
s->cluster_cache + index_in_cluster * 512,
@@ -975,7 +987,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,
*/
BlockDriver* drv = bdrv_find_format("qcow2");
assert(drv != NULL);
ret = bdrv_open(bs, filename, BDRV_O_RDWR | BDRV_O_NO_FLUSH, drv);
ret = bdrv_open(bs, filename,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv);
if (ret < 0) {
goto out;
}

View File

@@ -14,6 +14,7 @@
#include "trace.h"
#include "qed.h"
#include "qerror.h"
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
{
@@ -311,7 +312,13 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
return -EINVAL;
}
if (s->header.features & ~QED_FEATURE_MASK) {
return -ENOTSUP; /* image uses unsupported feature bits */
/* image uses unsupported feature bits */
char buf[64];
snprintf(buf, sizeof(buf), "%" PRIx64,
s->header.features & ~QED_FEATURE_MASK);
qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "QED", buf);
return -ENOTSUP;
}
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
return -EINVAL;

View File

@@ -119,13 +119,13 @@ void uuid_unparse(const uuid_t uu, char *out);
#if !defined(CONFIG_UUID)
void uuid_generate(uuid_t out)
{
memset(out, 0, sizeof(out));
memset(out, 0, sizeof(uuid_t));
}
int uuid_is_null(const uuid_t uu)
{
uuid_t null_uuid = { 0 };
return memcmp(uu, null_uuid, sizeof(uu)) == 0;
return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
}
void uuid_unparse(const uuid_t uu, char *out)

View File

@@ -199,6 +199,7 @@ struct BlockDriverState {
char device_name[32];
unsigned long *dirty_bitmap;
int64_t dirty_count;
int in_use; /* users other than guest access, eg. block migration */
QTAILQ_ENTRY(BlockDriverState) list;
void *private;
};

View File

@@ -71,7 +71,7 @@ void blockdev_auto_del(BlockDriverState *bs)
DriveInfo *dinfo = drive_get_by_blockdev(bs);
if (dinfo && dinfo->auto_del) {
drive_uninit(dinfo);
drive_put_ref(dinfo);
}
}
@@ -178,14 +178,28 @@ static void bdrv_format_print(void *opaque, const char *name)
error_printf(" %s", name);
}
void drive_uninit(DriveInfo *dinfo)
static void drive_uninit(DriveInfo *dinfo)
{
qemu_opts_del(dinfo->opts);
bdrv_delete(dinfo->bdrv);
qemu_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
qemu_free(dinfo);
}
void drive_put_ref(DriveInfo *dinfo)
{
assert(dinfo->refcount);
if (--dinfo->refcount == 0) {
drive_uninit(dinfo);
}
}
void drive_get_ref(DriveInfo *dinfo)
{
dinfo->refcount++;
}
static int parse_block_error_action(const char *buf, int is_read)
{
if (!strcmp(buf, "ignore")) {
@@ -453,6 +467,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
dinfo->bus = bus_id;
dinfo->unit = unit_id;
dinfo->opts = opts;
dinfo->refcount = 1;
if (serial)
strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
@@ -511,7 +526,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
} else if (ro == 1) {
if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
error_report("readonly not supported by this bus type");
return NULL;
goto err;
}
}
@@ -521,12 +536,19 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
if (ret < 0) {
error_report("could not open disk image %s: %s",
file, strerror(-ret));
return NULL;
goto err;
}
if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
return dinfo;
err:
bdrv_delete(dinfo->bdrv);
qemu_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
qemu_free(dinfo);
return NULL;
}
void do_commit(Monitor *mon, const QDict *qdict)
@@ -712,6 +734,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
qerror_report(QERR_DEVICE_NOT_FOUND, id);
return -1;
}
if (bdrv_in_use(bs)) {
qerror_report(QERR_DEVICE_IN_USE, id);
return -1;
}
/* quiesce block driver; prevent further io */
qemu_aio_flush();

View File

@@ -36,13 +36,15 @@ struct DriveInfo {
QemuOpts *opts;
char serial[BLOCK_SERIAL_STRLEN + 1];
QTAILQ_ENTRY(DriveInfo) next;
int refcount;
};
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
int drive_get_max_bus(BlockInterfaceType type);
DriveInfo *drive_get_next(BlockInterfaceType type);
void drive_uninit(DriveInfo *dinfo);
void drive_get_ref(DriveInfo *dinfo);
void drive_put_ref(DriveInfo *dinfo);
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
QemuOpts *drive_def(const char *optstr);

View File

@@ -267,6 +267,37 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count)
}
}
void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
size_t skip)
{
int i;
size_t done;
void *iov_base;
uint64_t iov_len;
done = 0;
for (i = 0; (i < qiov->niov) && (done != count); i++) {
if (skip >= qiov->iov[i].iov_len) {
/* Skip the whole iov */
skip -= qiov->iov[i].iov_len;
continue;
} else {
/* Skip only part (or nothing) of the iov */
iov_base = (uint8_t*) qiov->iov[i].iov_base + skip;
iov_len = qiov->iov[i].iov_len - skip;
skip = 0;
}
if (done + iov_len > count) {
memset(iov_base, c, count - done);
break;
} else {
memset(iov_base, c, iov_len);
}
done += iov_len;
}
}
#ifndef _WIN32
/* Sets a specific flag */
int fcntl_setfl(int fd, int flag)

View File

@@ -822,7 +822,7 @@ ETEXI
{
.name = "snapshot_blkdev",
.args_type = "device:s,snapshot_file:s?,format:s?",
.args_type = "device:B,snapshot_file:s?,format:s?",
.params = "device [new-image-file] [format]",
.help = "initiates a live snapshot\n\t\t\t"
"of device. If a new image file is specified, the\n\t\t\t"

View File

@@ -18,6 +18,7 @@
*/
#include "hw.h"
#include "apic.h"
#include "ioapic.h"
#include "qemu-timer.h"
#include "host-utils.h"
#include "sysbus.h"
@@ -57,7 +58,8 @@
#define ESR_ILLEGAL_ADDRESS (1 << 7)
#define APIC_SV_ENABLE (1 << 8)
#define APIC_SV_DIRECTED_IO (1<<12)
#define APIC_SV_ENABLE (1<<8)
#define MAX_APICS 255
#define MAX_APIC_WORDS 8
@@ -370,19 +372,36 @@ static int apic_get_arb_pri(APICState *s)
return 0;
}
/*
* <0 - low prio interrupt,
* 0 - no interrupt,
* >0 - interrupt number
*/
static int apic_irq_pending(APICState *s)
{
int irrv, ppr;
irrv = get_highest_priority_int(s->irr);
if (irrv < 0) {
return 0;
}
ppr = apic_get_ppr(s);
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
return -1;
}
return irrv;
}
/* signal the CPU if an irq is pending */
static void apic_update_irq(APICState *s)
{
int irrv, ppr;
if (!(s->spurious_vec & APIC_SV_ENABLE))
if (!(s->spurious_vec & APIC_SV_ENABLE)) {
return;
irrv = get_highest_priority_int(s->irr);
if (irrv < 0)
return;
ppr = apic_get_ppr(s);
if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
return;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
if (apic_irq_pending(s) > 0) {
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
}
void apic_reset_irq_delivered(void)
@@ -420,8 +439,9 @@ static void apic_eoi(APICState *s)
if (isrv < 0)
return;
reset_bit(s->isr, isrv);
/* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
set the remote IRR bit for level triggered interrupts. */
if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
ioapic_eoi_broadcast(isrv);
}
apic_update_irq(s);
}
@@ -587,12 +607,13 @@ int apic_get_interrupt(DeviceState *d)
if (!(s->spurious_vec & APIC_SV_ENABLE))
return -1;
/* XXX: spurious IRQ handling */
intno = get_highest_priority_int(s->irr);
if (intno < 0)
intno = apic_irq_pending(s);
if (intno == 0) {
return -1;
if (s->tpr && intno <= s->tpr)
} else if (intno < 0) {
return s->spurious_vec & 0xff;
}
reset_bit(s->irr, intno);
set_bit(s->isr, intno);
apic_update_irq(s);

View File

@@ -19,47 +19,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*
* lspci dump of a ICH-9 real device in IDE mode (hopefully close enough):
*
* 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
* Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
* Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
* Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
* Latency: 0
* Interrupt: pin B routed to IRQ 222
* Region 0: I/O ports at d000 [size=8]
* Region 1: I/O ports at cc00 [size=4]
* Region 2: I/O ports at c880 [size=8]
* Region 3: I/O ports at c800 [size=4]
* Region 4: I/O ports at c480 [size=32]
* Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
* Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
* Address: fee0f00c Data: 41d9
* Capabilities: [70] Power Management version 3
* Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
* Status: D0 PME-Enable- DSel=0 DScale=0 PME-
* Capabilities: [a8] SATA HBA <?>
* Capabilities: [b0] Vendor Specific Information <?>
* Kernel driver in use: ahci
* Kernel modules: ahci
* 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
* 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
* 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
* 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
* 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
* 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
* 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
* 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
* a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
* b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
* c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
*
*/
#include <hw/hw.h>
@@ -72,6 +31,7 @@
#include "cpu-common.h"
#include "internal.h"
#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>
/* #define DEBUG_AHCI */
@@ -83,308 +43,11 @@ do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
#define DPRINTF(port, fmt, ...) do {} while(0)
#endif
#define AHCI_PCI_BAR 5
#define AHCI_MAX_PORTS 32
#define AHCI_MAX_SG 168 /* hardware max is 64K */
#define AHCI_DMA_BOUNDARY 0xffffffff
#define AHCI_USE_CLUSTERING 0
#define AHCI_MAX_CMDS 32
#define AHCI_CMD_SZ 32
#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
#define AHCI_RX_FIS_SZ 256
#define AHCI_CMD_TBL_CDB 0x40
#define AHCI_CMD_TBL_HDR_SZ 0x80
#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
AHCI_RX_FIS_SZ)
#define AHCI_IRQ_ON_SG (1 << 31)
#define AHCI_CMD_ATAPI (1 << 5)
#define AHCI_CMD_WRITE (1 << 6)
#define AHCI_CMD_PREFETCH (1 << 7)
#define AHCI_CMD_RESET (1 << 8)
#define AHCI_CMD_CLR_BUSY (1 << 10)
#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
/* global controller registers */
#define HOST_CAP 0x00 /* host capabilities */
#define HOST_CTL 0x04 /* global host control */
#define HOST_IRQ_STAT 0x08 /* interrupt status */
#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
/* HOST_CAP bits */
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
#define PORT_IRQ_STAT 0x10 /* interrupt status */
#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
#define PORT_CMD 0x18 /* port command */
#define PORT_TFDATA 0x20 /* taskfile data */
#define PORT_SIG 0x24 /* device TF signature */
#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
#define PORT_CMD_ISSUE 0x38 /* command issue */
#define PORT_RESERVED 0x3c /* reserved */
/* PORT_IRQ_{STAT,MASK} bits */
#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
PORT_IRQ_UNK_FIS)
#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
PORT_IRQ_HBUS_DATA_ERR)
#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
/* PORT_CMD bits */
#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
#define PORT_CMD_CLO (1 << 3) /* Command list override */
#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */
#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */
#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */
#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */
#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */
#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */
#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */
#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence
Status */
#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */
#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier
Status */
#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */
#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error
Status */
#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */
#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */
#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */
#define ATA_SRST (1 << 2) /* software reset */
#define STATE_RUN 0
#define STATE_RESET 1
#define SATA_SCR_SSTATUS_DET_NODEV 0x0
#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
#define SATA_SCR_SSTATUS_SPD_NODEV 0x00
#define SATA_SCR_SSTATUS_SPD_GEN1 0x10
#define SATA_SCR_SSTATUS_IPM_NODEV 0x000
#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100
#define AHCI_SCR_SCTL_DET 0xf
#define SATA_FIS_TYPE_REGISTER_H2D 0x27
#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
#define AHCI_CMD_HDR_PRDT_LEN 16
#define SATA_SIGNATURE_CDROM 0xeb140000
#define SATA_SIGNATURE_DISK 0x00000101
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
/* Shouldn't this be 0x2c? */
#define SATA_PORTS 4
#define AHCI_PORT_REGS_START_ADDR 0x100
#define AHCI_PORT_REGS_END_ADDR (AHCI_PORT_REGS_START_ADDR + SATA_PORTS * 0x80)
#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
#define AHCI_NUM_COMMAND_SLOTS 31
#define AHCI_SUPPORTED_SPEED 20
#define AHCI_SUPPORTED_SPEED_GEN1 1
#define AHCI_VERSION_1_0 0x10000
#define AHCI_PROGMODE_MAJOR_REV_1 1
#define AHCI_COMMAND_TABLE_ACMD 0x40
#define IDE_FEATURE_DMA 1
#define READ_FPDMA_QUEUED 0x60
#define WRITE_FPDMA_QUEUED 0x61
#define RES_FIS_DSFIS 0x00
#define RES_FIS_PSFIS 0x20
#define RES_FIS_RFIS 0x40
#define RES_FIS_SDBFIS 0x58
#define RES_FIS_UFIS 0x60
typedef struct AHCIControlRegs {
uint32_t cap;
uint32_t ghc;
uint32_t irqstatus;
uint32_t impl;
uint32_t version;
} AHCIControlRegs;
typedef struct AHCIPortRegs {
uint32_t lst_addr;
uint32_t lst_addr_hi;
uint32_t fis_addr;
uint32_t fis_addr_hi;
uint32_t irq_stat;
uint32_t irq_mask;
uint32_t cmd;
uint32_t unused0;
uint32_t tfdata;
uint32_t sig;
uint32_t scr_stat;
uint32_t scr_ctl;
uint32_t scr_err;
uint32_t scr_act;
uint32_t cmd_issue;
uint32_t reserved;
} AHCIPortRegs;
typedef struct AHCICmdHdr {
uint32_t opts;
uint32_t status;
uint64_t tbl_addr;
uint32_t reserved[4];
} __attribute__ ((packed)) AHCICmdHdr;
typedef struct AHCI_SG {
uint64_t addr;
uint32_t reserved;
uint32_t flags_size;
} __attribute__ ((packed)) AHCI_SG;
typedef struct AHCIDevice AHCIDevice;
typedef struct NCQTransferState {
AHCIDevice *drive;
BlockDriverAIOCB *aiocb;
QEMUSGList sglist;
int is_read;
uint16_t sector_count;
uint64_t lba;
uint8_t tag;
int slot;
int used;
} NCQTransferState;
struct AHCIDevice {
IDEDMA dma;
IDEBus port;
int port_no;
uint32_t port_state;
uint32_t finished;
AHCIPortRegs port_regs;
struct AHCIState *hba;
QEMUBH *check_bh;
uint8_t *lst;
uint8_t *res_fis;
int dma_status;
int done_atapi_packet;
int busy_slot;
BlockDriverCompletionFunc *dma_cb;
AHCICmdHdr *cur_cmd;
NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
};
typedef struct AHCIState {
AHCIDevice dev[SATA_PORTS];
AHCIControlRegs control_regs;
int mem;
qemu_irq irq;
} AHCIState;
typedef struct AHCIPCIState {
PCIDevice card;
AHCIState ahci;
} AHCIPCIState;
typedef struct NCQFrame {
uint8_t fis_type;
uint8_t c;
uint8_t command;
uint8_t sector_count_low;
uint8_t lba0;
uint8_t lba1;
uint8_t lba2;
uint8_t fua;
uint8_t lba3;
uint8_t lba4;
uint8_t lba5;
uint8_t sector_count_high;
uint8_t tag;
uint8_t reserved5;
uint8_t reserved6;
uint8_t control;
uint8_t reserved7;
uint8_t reserved8;
uint8_t reserved9;
uint8_t reserved10;
} __attribute__ ((packed)) NCQFrame;
static void check_cmd(AHCIState *s, int port);
static int handle_cmd(AHCIState *s,int port,int slot);
static void ahci_reset_port(AHCIState *s, int port);
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
static void ahci_init_d2h(AHCIDevice *ad);
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
{
@@ -482,7 +145,7 @@ static void ahci_check_irq(AHCIState *s)
DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
for (i = 0; i < SATA_PORTS; i++) {
for (i = 0; i < s->ports; i++) {
AHCIPortRegs *pr = &s->dev[i].port_regs;
if (pr->irq_stat & pr->irq_mask) {
s->control_regs.irqstatus |= (1 << i);
@@ -568,6 +231,16 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
pr->cmd |= PORT_CMD_FIS_ON;
}
/* XXX usually the FIS would be pending on the bus here and
issuing deferred until the OS enables FIS receival.
Instead, we only submit it once - which works in most
cases, but is a hack. */
if ((pr->cmd & PORT_CMD_FIS_ON) &&
!s->dev[port].init_d2h_sent) {
ahci_init_d2h(&s->dev[port]);
s->dev[port].init_d2h_sent = 1;
}
check_cmd(s, port);
break;
case PORT_TFDATA:
@@ -630,7 +303,8 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr)
DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
(addr < AHCI_PORT_REGS_END_ADDR)) {
(addr < (AHCI_PORT_REGS_START_ADDR +
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
addr & AHCI_PORT_ADDR_OFFSET_MASK);
}
@@ -662,7 +336,7 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
case HOST_CTL: /* R/W */
if (val & HOST_CTL_RESET) {
DPRINTF(-1, "HBA Reset\n");
/* FIXME reset? */
ahci_reset(container_of(s, AHCIPCIState, ahci));
} else {
s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
ahci_check_irq(s);
@@ -682,7 +356,8 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
}
} else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
(addr < AHCI_PORT_REGS_END_ADDR)) {
(addr < (AHCI_PORT_REGS_START_ADDR +
(s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
}
@@ -705,16 +380,16 @@ static void ahci_reg_init(AHCIState *s)
{
int i;
s->control_regs.cap = (SATA_PORTS - 1) |
s->control_regs.cap = (s->ports - 1) |
(AHCI_NUM_COMMAND_SLOTS << 8) |
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
HOST_CAP_NCQ | HOST_CAP_AHCI;
s->control_regs.impl = (1 << SATA_PORTS) - 1;
s->control_regs.impl = (1 << s->ports) - 1;
s->control_regs.version = AHCI_VERSION_1_0;
for (i = 0; i < SATA_PORTS; i++) {
for (i = 0; i < s->ports; i++) {
s->dev[i].port_state = STATE_RUN;
}
}
@@ -800,12 +475,29 @@ static void ahci_check_cmd_bh(void *opaque)
check_cmd(ad->hba, ad->port_no);
}
static void ahci_init_d2h(AHCIDevice *ad)
{
uint8_t init_fis[0x20];
IDEState *ide_state = &ad->port.ifs[0];
memset(init_fis, 0, sizeof(init_fis));
init_fis[4] = 1;
init_fis[12] = 1;
if (ide_state->drive_kind == IDE_CD) {
init_fis[5] = ide_state->lcyl;
init_fis[6] = ide_state->hcyl;
}
ahci_write_fis_d2h(ad, init_fis);
}
static void ahci_reset_port(AHCIState *s, int port)
{
AHCIDevice *d = &s->dev[port];
AHCIPortRegs *pr = &d->port_regs;
IDEState *ide_state = &d->port.ifs[0];
uint8_t init_fis[0x20];
int i;
DPRINTF(port, "reset port\n");
@@ -820,6 +512,7 @@ static void ahci_reset_port(AHCIState *s, int port)
pr->scr_err = 0;
pr->scr_act = 0;
d->busy_slot = -1;
d->init_d2h_sent = 0;
ide_state = &s->dev[port].port.ifs[0];
if (!ide_state->bs) {
@@ -842,7 +535,6 @@ static void ahci_reset_port(AHCIState *s, int port)
ncq_tfs->used = 0;
}
memset(init_fis, 0, sizeof(init_fis));
s->dev[port].port_state = STATE_RUN;
if (!ide_state->bs) {
s->dev[port].port_regs.sig = 0;
@@ -852,8 +544,6 @@ static void ahci_reset_port(AHCIState *s, int port)
ide_state->lcyl = 0x14;
ide_state->hcyl = 0xeb;
DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
init_fis[5] = ide_state->lcyl;
init_fis[6] = ide_state->hcyl;
ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
} else {
s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
@@ -861,9 +551,7 @@ static void ahci_reset_port(AHCIState *s, int port)
}
ide_state->error = 1;
init_fis[4] = 1;
init_fis[12] = 1;
ahci_write_fis_d2h(d, init_fis);
ahci_init_d2h(d);
}
static void debug_print_fis(uint8_t *fis, int cmd_len)
@@ -1410,17 +1098,19 @@ static const IDEDMAOps ahci_dma_ops = {
.reset = ahci_dma_reset,
};
static void ahci_init(AHCIState *s, DeviceState *qdev)
void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
{
qemu_irq *irqs;
int i;
s->ports = ports;
s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports);
ahci_reg_init(s);
s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s,
DEVICE_LITTLE_ENDIAN);
irqs = qemu_allocate_irqs(ahci_irq_set, s, SATA_PORTS);
irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
for (i = 0; i < SATA_PORTS; i++) {
for (i = 0; i < s->ports; i++) {
AHCIDevice *ad = &s->dev[i];
ide_bus_new(&ad->port, qdev, i);
@@ -1434,7 +1124,12 @@ static void ahci_init(AHCIState *s, DeviceState *qdev)
}
}
static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
void ahci_uninit(AHCIState *s)
{
qemu_free(s->dev);
}
void ahci_pci_map(PCIDevice *pci_dev, int region_num,
pcibus_t addr, pcibus_t size, int type)
{
struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev;
@@ -1443,81 +1138,15 @@ static void ahci_pci_map(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr, size, s->mem);
}
static void ahci_reset(void *opaque)
void ahci_reset(void *opaque)
{
struct AHCIPCIState *d = opaque;
int i;
for (i = 0; i < SATA_PORTS; i++) {
d->ahci.control_regs.irqstatus = 0;
d->ahci.control_regs.ghc = 0;
for (i = 0; i < d->ahci.ports; i++) {
ahci_reset_port(&d->ahci, i);
}
}
static int pci_ahci_init(PCIDevice *dev)
{
struct AHCIPCIState *d;
d = DO_UPCAST(struct AHCIPCIState, card, dev);
pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR);
pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA);
pci_config_set_revision(d->card.config, 0x02);
pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
pci_config_set_interrupt_pin(d->card.config, 1);
/* XXX Software should program this register */
d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
qemu_register_reset(ahci_reset, d);
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY,
ahci_pci_map);
msi_init(dev, 0x50, 1, true, false);
ahci_init(&d->ahci, &dev->qdev);
d->ahci.irq = d->card.irq[0];
return 0;
}
static int pci_ahci_uninit(PCIDevice *dev)
{
struct AHCIPCIState *d;
d = DO_UPCAST(struct AHCIPCIState, card, dev);
if (msi_enabled(dev)) {
msi_uninit(dev);
}
qemu_unregister_reset(ahci_reset, d);
return 0;
}
static void pci_ahci_write_config(PCIDevice *pci, uint32_t addr,
uint32_t val, int len)
{
pci_default_write_config(pci, addr, val, len);
msi_write_config(pci, addr, val, len);
}
static PCIDeviceInfo ahci_info = {
.qdev.name = "ahci",
.qdev.size = sizeof(AHCIPCIState),
.init = pci_ahci_init,
.exit = pci_ahci_uninit,
.config_write = pci_ahci_write_config,
};
static void ahci_pci_register_devices(void)
{
pci_qdev_register(&ahci_info);
}
device_init(ahci_pci_register_devices)

333
hw/ide/ahci.h Normal file
View File

@@ -0,0 +1,333 @@
/*
* QEMU AHCI Emulation
*
* Copyright (c) 2010 qiaochong@loongson.cn
* Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
* Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
* Copyright (c) 2010 Alexander Graf <agraf@suse.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HW_IDE_AHCI_H
#define HW_IDE_AHCI_H
#define AHCI_PCI_BAR 5
#define AHCI_MAX_PORTS 32
#define AHCI_MAX_SG 168 /* hardware max is 64K */
#define AHCI_DMA_BOUNDARY 0xffffffff
#define AHCI_USE_CLUSTERING 0
#define AHCI_MAX_CMDS 32
#define AHCI_CMD_SZ 32
#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ)
#define AHCI_RX_FIS_SZ 256
#define AHCI_CMD_TBL_CDB 0x40
#define AHCI_CMD_TBL_HDR_SZ 0x80
#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16))
#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS)
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
AHCI_RX_FIS_SZ)
#define AHCI_IRQ_ON_SG (1 << 31)
#define AHCI_CMD_ATAPI (1 << 5)
#define AHCI_CMD_WRITE (1 << 6)
#define AHCI_CMD_PREFETCH (1 << 7)
#define AHCI_CMD_RESET (1 << 8)
#define AHCI_CMD_CLR_BUSY (1 << 10)
#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
/* global controller registers */
#define HOST_CAP 0x00 /* host capabilities */
#define HOST_CTL 0x04 /* global host control */
#define HOST_IRQ_STAT 0x08 /* interrupt status */
#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
/* HOST_CAP bits */
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
#define PORT_IRQ_STAT 0x10 /* interrupt status */
#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
#define PORT_CMD 0x18 /* port command */
#define PORT_TFDATA 0x20 /* taskfile data */
#define PORT_SIG 0x24 /* device TF signature */
#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
#define PORT_CMD_ISSUE 0x38 /* command issue */
#define PORT_RESERVED 0x3c /* reserved */
/* PORT_IRQ_{STAT,MASK} bits */
#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
PORT_IRQ_UNK_FIS)
#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
PORT_IRQ_HBUS_DATA_ERR)
#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
/* PORT_CMD bits */
#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
#define PORT_CMD_CLO (1 << 3) /* Command list override */
#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */
#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */
#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */
#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */
#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */
#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */
#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */
#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence
Status */
#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */
#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier
Status */
#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */
#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error
Status */
#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */
#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */
#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */
#define ATA_SRST (1 << 2) /* software reset */
#define STATE_RUN 0
#define STATE_RESET 1
#define SATA_SCR_SSTATUS_DET_NODEV 0x0
#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3
#define SATA_SCR_SSTATUS_SPD_NODEV 0x00
#define SATA_SCR_SSTATUS_SPD_GEN1 0x10
#define SATA_SCR_SSTATUS_IPM_NODEV 0x000
#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100
#define AHCI_SCR_SCTL_DET 0xf
#define SATA_FIS_TYPE_REGISTER_H2D 0x27
#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80
#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f
#define AHCI_CMD_HDR_PRDT_LEN 16
#define SATA_SIGNATURE_CDROM 0xeb140000
#define SATA_SIGNATURE_DISK 0x00000101
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
/* Shouldn't this be 0x2c? */
#define AHCI_PORT_REGS_START_ADDR 0x100
#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f
#define AHCI_PORT_ADDR_OFFSET_LEN 0x80
#define AHCI_NUM_COMMAND_SLOTS 31
#define AHCI_SUPPORTED_SPEED 20
#define AHCI_SUPPORTED_SPEED_GEN1 1
#define AHCI_VERSION_1_0 0x10000
#define AHCI_PROGMODE_MAJOR_REV_1 1
#define AHCI_COMMAND_TABLE_ACMD 0x40
#define IDE_FEATURE_DMA 1
#define READ_FPDMA_QUEUED 0x60
#define WRITE_FPDMA_QUEUED 0x61
#define RES_FIS_DSFIS 0x00
#define RES_FIS_PSFIS 0x20
#define RES_FIS_RFIS 0x40
#define RES_FIS_SDBFIS 0x58
#define RES_FIS_UFIS 0x60
typedef struct AHCIControlRegs {
uint32_t cap;
uint32_t ghc;
uint32_t irqstatus;
uint32_t impl;
uint32_t version;
} AHCIControlRegs;
typedef struct AHCIPortRegs {
uint32_t lst_addr;
uint32_t lst_addr_hi;
uint32_t fis_addr;
uint32_t fis_addr_hi;
uint32_t irq_stat;
uint32_t irq_mask;
uint32_t cmd;
uint32_t unused0;
uint32_t tfdata;
uint32_t sig;
uint32_t scr_stat;
uint32_t scr_ctl;
uint32_t scr_err;
uint32_t scr_act;
uint32_t cmd_issue;
uint32_t reserved;
} AHCIPortRegs;
typedef struct AHCICmdHdr {
uint32_t opts;
uint32_t status;
uint64_t tbl_addr;
uint32_t reserved[4];
} __attribute__ ((packed)) AHCICmdHdr;
typedef struct AHCI_SG {
uint64_t addr;
uint32_t reserved;
uint32_t flags_size;
} __attribute__ ((packed)) AHCI_SG;
typedef struct AHCIDevice AHCIDevice;
typedef struct NCQTransferState {
AHCIDevice *drive;
BlockDriverAIOCB *aiocb;
QEMUSGList sglist;
int is_read;
uint16_t sector_count;
uint64_t lba;
uint8_t tag;
int slot;
int used;
} NCQTransferState;
struct AHCIDevice {
IDEDMA dma;
IDEBus port;
int port_no;
uint32_t port_state;
uint32_t finished;
AHCIPortRegs port_regs;
struct AHCIState *hba;
QEMUBH *check_bh;
uint8_t *lst;
uint8_t *res_fis;
int dma_status;
int done_atapi_packet;
int busy_slot;
int init_d2h_sent;
BlockDriverCompletionFunc *dma_cb;
AHCICmdHdr *cur_cmd;
NCQTransferState ncq_tfs[AHCI_MAX_CMDS];
};
typedef struct AHCIState {
AHCIDevice *dev;
AHCIControlRegs control_regs;
int mem;
int ports;
qemu_irq irq;
} AHCIState;
typedef struct AHCIPCIState {
PCIDevice card;
AHCIState ahci;
} AHCIPCIState;
typedef struct NCQFrame {
uint8_t fis_type;
uint8_t c;
uint8_t command;
uint8_t sector_count_low;
uint8_t lba0;
uint8_t lba1;
uint8_t lba2;
uint8_t fua;
uint8_t lba3;
uint8_t lba4;
uint8_t lba5;
uint8_t sector_count_high;
uint8_t tag;
uint8_t reserved5;
uint8_t reserved6;
uint8_t control;
uint8_t reserved7;
uint8_t reserved8;
uint8_t reserved9;
uint8_t reserved10;
} __attribute__ ((packed)) NCQFrame;
void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
void ahci_uninit(AHCIState *s);
void ahci_pci_map(PCIDevice *pci_dev, int region_num,
pcibus_t addr, pcibus_t size, int type);
void ahci_reset(void *opaque);
#endif /* HW_IDE_AHCI_H */

148
hw/ide/ich.c Normal file
View File

@@ -0,0 +1,148 @@
/*
* QEMU ICH Emulation
*
* Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
* Copyright (c) 2010 Alexander Graf <agraf@suse.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*
* lspci dump of a ICH-9 real device
*
* 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0])
* Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922]
* Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
* Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
* Latency: 0
* Interrupt: pin B routed to IRQ 222
* Region 0: I/O ports at d000 [size=8]
* Region 1: I/O ports at cc00 [size=4]
* Region 2: I/O ports at c880 [size=8]
* Region 3: I/O ports at c800 [size=4]
* Region 4: I/O ports at c480 [size=32]
* Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K]
* Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+
* Address: fee0f00c Data: 41d9
* Capabilities: [70] Power Management version 3
* Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
* Status: D0 PME-Enable- DSel=0 DScale=0 PME-
* Capabilities: [a8] SATA HBA <?>
* Capabilities: [b0] Vendor Specific Information <?>
* Kernel driver in use: ahci
* Kernel modules: ahci
* 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00
* 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00
* 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29
* 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00
* 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00
* 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00
* 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00
* 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00
* a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00
* b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00
* c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00
*
*/
#include <hw/hw.h>
#include <hw/msi.h>
#include <hw/pc.h>
#include <hw/pci.h>
#include <hw/isa.h>
#include "block.h"
#include "block_int.h"
#include "sysemu.h"
#include "dma.h"
#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>
static int pci_ich9_ahci_init(PCIDevice *dev)
{
struct AHCIPCIState *d;
d = DO_UPCAST(struct AHCIPCIState, card, dev);
pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL);
pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR);
pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA);
pci_config_set_revision(d->card.config, 0x02);
pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */
d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */
pci_config_set_interrupt_pin(d->card.config, 1);
/* XXX Software should program this register */
d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
qemu_register_reset(ahci_reset, d);
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY,
ahci_pci_map);
msi_init(dev, 0x50, 1, true, false);
ahci_init(&d->ahci, &dev->qdev, 6);
d->ahci.irq = d->card.irq[0];
return 0;
}
static int pci_ich9_uninit(PCIDevice *dev)
{
struct AHCIPCIState *d;
d = DO_UPCAST(struct AHCIPCIState, card, dev);
if (msi_enabled(dev)) {
msi_uninit(dev);
}
qemu_unregister_reset(ahci_reset, d);
ahci_uninit(&d->ahci);
return 0;
}
static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
uint32_t val, int len)
{
pci_default_write_config(pci, addr, val, len);
msi_write_config(pci, addr, val, len);
}
static PCIDeviceInfo ich_ahci_info[] = {
{
.qdev.name = "ich9-ahci",
.qdev.alias = "ahci",
.qdev.size = sizeof(AHCIPCIState),
.init = pci_ich9_ahci_init,
.exit = pci_ich9_uninit,
.config_write = pci_ich9_write_config,
},{
/* end of list */
}
};
static void ich_ahci_register(void)
{
pci_qdev_register_many(ich_ahci_info);
}
device_init(ich_ahci_register);

View File

@@ -23,6 +23,7 @@
#include "hw.h"
#include "pc.h"
#include "apic.h"
#include "ioapic.h"
#include "qemu-timer.h"
#include "host-utils.h"
#include "sysbus.h"
@@ -36,19 +37,50 @@
#define DPRINTF(fmt, ...)
#endif
#define IOAPIC_LVT_MASKED (1<<16)
#define MAX_IOAPICS 1
#define IOAPIC_TRIGGER_EDGE 0
#define IOAPIC_TRIGGER_LEVEL 1
#define IOAPIC_VERSION 0x11
#define IOAPIC_LVT_DEST_SHIFT 56
#define IOAPIC_LVT_MASKED_SHIFT 16
#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
#define IOAPIC_LVT_POLARITY_SHIFT 13
#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12
#define IOAPIC_LVT_DEST_MODE_SHIFT 11
#define IOAPIC_LVT_DELIV_MODE_SHIFT 8
#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT)
#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
#define IOAPIC_TRIGGER_EDGE 0
#define IOAPIC_TRIGGER_LEVEL 1
/*io{apic,sapic} delivery mode*/
#define IOAPIC_DM_FIXED 0x0
#define IOAPIC_DM_LOWEST_PRIORITY 0x1
#define IOAPIC_DM_PMI 0x2
#define IOAPIC_DM_NMI 0x4
#define IOAPIC_DM_INIT 0x5
#define IOAPIC_DM_SIPI 0x5
#define IOAPIC_DM_EXTINT 0x7
#define IOAPIC_DM_FIXED 0x0
#define IOAPIC_DM_LOWEST_PRIORITY 0x1
#define IOAPIC_DM_PMI 0x2
#define IOAPIC_DM_NMI 0x4
#define IOAPIC_DM_INIT 0x5
#define IOAPIC_DM_SIPI 0x6
#define IOAPIC_DM_EXTINT 0x7
#define IOAPIC_DM_MASK 0x7
#define IOAPIC_VECTOR_MASK 0xff
#define IOAPIC_IOREGSEL 0x00
#define IOAPIC_IOWIN 0x10
#define IOAPIC_REG_ID 0x00
#define IOAPIC_REG_VER 0x01
#define IOAPIC_REG_ARB 0x02
#define IOAPIC_REG_REDTBL_BASE 0x10
#define IOAPIC_ID 0x00
#define IOAPIC_ID_SHIFT 24
#define IOAPIC_ID_MASK 0xf
#define IOAPIC_VER_ENTRIES_SHIFT 16
typedef struct IOAPICState IOAPICState;
@@ -56,11 +88,12 @@ struct IOAPICState {
SysBusDevice busdev;
uint8_t id;
uint8_t ioregsel;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
};
static IOAPICState *ioapics[MAX_IOAPICS];
static void ioapic_service(IOAPICState *s)
{
uint8_t i;
@@ -78,18 +111,22 @@ static void ioapic_service(IOAPICState *s)
if (s->irr & mask) {
entry = s->ioredtbl[i];
if (!(entry & IOAPIC_LVT_MASKED)) {
trig_mode = ((entry >> 15) & 1);
dest = entry >> 56;
dest_mode = (entry >> 11) & 1;
delivery_mode = (entry >> 8) & 7;
polarity = (entry >> 13) & 1;
if (trig_mode == IOAPIC_TRIGGER_EDGE)
trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
dest = entry >> IOAPIC_LVT_DEST_SHIFT;
dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
delivery_mode =
(entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
polarity = (entry >> IOAPIC_LVT_POLARITY_SHIFT) & 1;
if (trig_mode == IOAPIC_TRIGGER_EDGE) {
s->irr &= ~mask;
if (delivery_mode == IOAPIC_DM_EXTINT)
} else {
s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
}
if (delivery_mode == IOAPIC_DM_EXTINT) {
vector = pic_read_irq(isa_pic);
else
vector = entry & 0xff;
} else {
vector = entry & IOAPIC_VECTOR_MASK;
}
apic_deliver_irq(dest, dest_mode, delivery_mode,
vector, polarity, trig_mode);
}
@@ -105,15 +142,16 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
* to GSI 2. GSI maps to ioapic 1-1. This is not
* the cleanest way of doing it but it should work. */
DPRINTF("%s: %s vec %x\n", __func__, level? "raise" : "lower", vector);
if (vector == 0)
DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
if (vector == 0) {
vector = 2;
}
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
if ((entry >> 15) & 1) {
if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
IOAPIC_TRIGGER_LEVEL) {
/* level triggered */
if (level) {
s->irr |= mask;
@@ -131,82 +169,126 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
}
}
void ioapic_eoi_broadcast(int vector)
{
IOAPICState *s;
uint64_t entry;
int i, n;
for (i = 0; i < MAX_IOAPICS; i++) {
s = ioapics[i];
if (!s) {
continue;
}
for (n = 0; n < IOAPIC_NUM_PINS; n++) {
entry = s->ioredtbl[n];
if ((entry & IOAPIC_LVT_REMOTE_IRR)
&& (entry & IOAPIC_VECTOR_MASK) == vector) {
s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
ioapic_service(s);
}
}
}
}
}
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
{
IOAPICState *s = opaque;
int index;
uint32_t val = 0;
addr &= 0xff;
if (addr == 0x00) {
switch (addr & 0xff) {
case IOAPIC_IOREGSEL:
val = s->ioregsel;
} else if (addr == 0x10) {
break;
case IOAPIC_IOWIN:
switch (s->ioregsel) {
case 0x00:
val = s->id << 24;
break;
case 0x01:
val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
break;
case 0x02:
val = 0;
break;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1)
val = s->ioredtbl[index] >> 32;
else
val = s->ioredtbl[index] & 0xffffffff;
case IOAPIC_REG_ID:
val = s->id << IOAPIC_ID_SHIFT;
break;
case IOAPIC_REG_VER:
val = IOAPIC_VERSION |
((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
break;
case IOAPIC_REG_ARB:
val = 0;
break;
default:
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
val = s->ioredtbl[index] >> 32;
} else {
val = s->ioredtbl[index] & 0xffffffff;
}
}
}
DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
break;
}
return val;
}
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
static void
ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
IOAPICState *s = opaque;
int index;
addr &= 0xff;
if (addr == 0x00) {
switch (addr & 0xff) {
case IOAPIC_IOREGSEL:
s->ioregsel = val;
return;
} else if (addr == 0x10) {
break;
case IOAPIC_IOWIN:
DPRINTF("write: %08x = %08x\n", s->ioregsel, val);
switch (s->ioregsel) {
case 0x00:
s->id = (val >> 24) & 0xff;
return;
case 0x01:
case 0x02:
return;
default:
index = (s->ioregsel - 0x10) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
} else {
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
ioapic_service(s);
case IOAPIC_REG_ID:
s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
break;
case IOAPIC_REG_VER:
case IOAPIC_REG_ARB:
break;
default:
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
} else {
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
ioapic_service(s);
}
}
break;
}
}
static int ioapic_post_load(void *opaque, int version_id)
{
IOAPICState *s = opaque;
if (version_id == 1) {
/* set sane value */
s->irr = 0;
}
return 0;
}
static const VMStateDescription vmstate_ioapic = {
.name = "ioapic",
.version_id = 1,
.version_id = 3,
.post_load = ioapic_post_load,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
.fields = (VMStateField[]) {
VMSTATE_UINT8(id, IOAPICState),
VMSTATE_UINT8(ioregsel, IOAPICState),
VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
VMSTATE_UINT32_V(irr, IOAPICState, 2),
VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
VMSTATE_END_OF_LIST()
}
@@ -220,8 +302,9 @@ static void ioapic_reset(DeviceState *d)
s->id = 0;
s->ioregsel = 0;
s->irr = 0;
for(i = 0; i < IOAPIC_NUM_PINS; i++)
s->ioredtbl[i] = 1 << 16; /* mask LVT */
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
}
}
static CPUReadMemoryFunc * const ioapic_mem_read[3] = {
@@ -240,6 +323,11 @@ static int ioapic_init1(SysBusDevice *dev)
{
IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
int io_memory;
static int ioapic_no;
if (ioapic_no >= MAX_IOAPICS) {
return -1;
}
io_memory = cpu_register_io_memory(ioapic_mem_read,
ioapic_mem_write, s,
@@ -248,6 +336,8 @@ static int ioapic_init1(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
ioapics[ioapic_no++] = s;
return 0;
}

20
hw/ioapic.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* ioapic.c IOAPIC emulation logic
*
* Copyright (c) 2011 Jan Kiszka, Siemens AG
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
void ioapic_eoi_broadcast(int vector);

View File

@@ -147,7 +147,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict)
err:
if (dinfo)
drive_uninit(dinfo);
drive_put_ref(dinfo);
return;
}

View File

@@ -117,6 +117,9 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
{
VirtQueueElement elem;
if (!virtio_queue_ready(vq)) {
return;
}
while (virtqueue_pop(vq, &elem)) {
virtqueue_push(vq, &elem, 0);
}

View File

@@ -1481,7 +1481,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
struct elf_sym *syms;
struct elf_sym *syms, *new_syms;
shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr);
@@ -1550,12 +1550,14 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
that we threw away. Whether or not this has any effect on the
memory allocation depends on the malloc implementation and how
many symbols we managed to discard. */
syms = realloc(syms, nsyms * sizeof(*syms));
if (syms == NULL) {
new_syms = realloc(syms, nsyms * sizeof(*syms));
if (new_syms == NULL) {
free(s);
free(syms);
free(strings);
return;
}
syms = new_syms;
qsort(syms, nsyms, sizeof(*syms), symcmp);

View File

@@ -312,10 +312,8 @@
IOCTL(LOOP_CLR_FD, 0, TYPE_INT)
IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
#if 0 /* These have some problems - not fully tested */
IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
#endif
IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT)
IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop)))

View File

@@ -322,6 +322,8 @@ void qemu_iovec_reset(QEMUIOVector *qiov);
void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
size_t skip);
struct Monitor;
typedef struct Monitor Monitor;

View File

@@ -407,6 +407,7 @@ snapshots.
* host_drives:: Using host drives
* disk_images_fat_images:: Virtual FAT disk images
* disk_images_nbd:: NBD access
* disk_images_sheepdog:: Sheepdog disk images
@end menu
@node disk_images_quickstart
@@ -630,6 +631,57 @@ qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
@end example
@node disk_images_sheepdog
@subsection Sheepdog disk images
Sheepdog is a distributed storage system for QEMU. It provides highly
available block level storage volumes that can be attached to
QEMU-based virtual machines.
You can create a Sheepdog disk image with the command:
@example
qemu-img create sheepdog:@var{image} @var{size}
@end example
where @var{image} is the Sheepdog image name and @var{size} is its
size.
To import the existing @var{filename} to Sheepdog, you can use a
convert command.
@example
qemu-img convert @var{filename} sheepdog:@var{image}
@end example
You can boot from the Sheepdog disk image with the command:
@example
qemu sheepdog:@var{image}
@end example
You can also create a snapshot of the Sheepdog image like qcow2.
@example
qemu-img snapshot -c @var{tag} sheepdog:@var{image}
@end example
where @var{tag} is a tag name of the newly created snapshot.
To boot from the Sheepdog snapshot, specify the tag name of the
snapshot.
@example
qemu sheepdog:@var{image}:@var{tag}
@end example
You can create a cloned image from the existing snapshot.
@example
qemu-img create -b sheepdog:@var{base}:@var{tag} sheepdog:@var{image}
@end example
where @var{base} is a image name of the source snapshot and @var{tag}
is its tag name.
If the Sheepdog daemon doesn't run on the local host, you need to
specify one of the Sheepdog servers to connect to.
@example
qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size}
qemu sheepdog:@var{hostname}:@var{port}:@var{image}
@end example
@node pcsys_network
@section Network emulation

View File

@@ -213,8 +213,9 @@ static BlockDriverState *bdrv_new_open(const char *filename,
BlockDriverState *bs;
BlockDriver *drv;
char password[256];
int ret;
bs = bdrv_new("");
bs = bdrv_new("image");
if (fmt) {
drv = bdrv_find_format(fmt);
@@ -225,10 +226,13 @@ static BlockDriverState *bdrv_new_open(const char *filename,
} else {
drv = NULL;
}
if (bdrv_open(bs, filename, flags, drv) < 0) {
error_report("Could not open '%s'", filename);
ret = bdrv_open(bs, filename, flags, drv);
if (ret < 0) {
error_report("Could not open '%s': %s", filename, strerror(-ret));
goto fail;
}
if (bdrv_is_encrypted(bs)) {
printf("Disk image '%s' is encrypted.\n", filename);
if (read_password(password, sizeof(password)) < 0) {

View File

@@ -197,8 +197,8 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
t->rearm(t);
}
/* TODO: MIN_TIMER_REARM_US should be optimized */
#define MIN_TIMER_REARM_US 250
/* TODO: MIN_TIMER_REARM_NS should be optimized */
#define MIN_TIMER_REARM_NS 250000
#ifdef _WIN32
@@ -635,6 +635,8 @@ void qemu_run_all_timers(void)
qemu_run_timers(host_clock);
}
static int64_t qemu_next_alarm_deadline(void);
#ifdef _WIN32
static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1,
@@ -677,14 +679,7 @@ static void host_alarm_handler(int host_signum)
}
#endif
if (alarm_has_dynticks(t) ||
(!use_icount &&
qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL],
qemu_get_clock(vm_clock))) ||
qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME],
qemu_get_clock(rt_clock)) ||
qemu_timer_expired(active_timers[QEMU_CLOCK_HOST],
qemu_get_clock(host_clock))) {
qemu_next_alarm_deadline () <= 0) {
t->expired = alarm_has_dynticks(t);
t->pending = 1;
qemu_notify_event();
@@ -698,11 +693,11 @@ int64_t qemu_next_deadline(void)
if (active_timers[QEMU_CLOCK_VIRTUAL]) {
delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
qemu_get_clock(vm_clock);
qemu_get_clock_ns(vm_clock);
}
if (active_timers[QEMU_CLOCK_HOST]) {
int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
qemu_get_clock(host_clock);
qemu_get_clock_ns(host_clock);
if (hdelta < delta)
delta = hdelta;
}
@@ -713,35 +708,37 @@ int64_t qemu_next_deadline(void)
return delta;
}
#ifndef _WIN32
#if defined(__linux__)
#define RTC_FREQ 1024
static uint64_t qemu_next_deadline_dyntick(void)
static int64_t qemu_next_alarm_deadline(void)
{
int64_t delta;
int64_t rtdelta;
if (use_icount)
if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) {
delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time -
qemu_get_clock(vm_clock);
} else {
delta = INT32_MAX;
else
delta = (qemu_next_deadline() + 999) / 1000;
}
if (active_timers[QEMU_CLOCK_HOST]) {
int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time -
qemu_get_clock_ns(host_clock);
if (hdelta < delta)
delta = hdelta;
}
if (active_timers[QEMU_CLOCK_REALTIME]) {
rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time -
qemu_get_clock(rt_clock))*1000;
rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time * 1000000 -
qemu_get_clock_ns(rt_clock));
if (rtdelta < delta)
delta = rtdelta;
}
if (delta < MIN_TIMER_REARM_US)
delta = MIN_TIMER_REARM_US;
return delta;
}
#if defined(__linux__)
#define RTC_FREQ 1024
static void enable_sigio_timer(int fd)
{
struct sigaction act;
@@ -887,8 +884,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
{
timer_t host_timer = (timer_t)(long)t->priv;
struct itimerspec timeout;
int64_t nearest_delta_us = INT64_MAX;
int64_t current_us;
int64_t nearest_delta_ns = INT64_MAX;
int64_t current_ns;
assert(alarm_has_dynticks(t));
if (!active_timers[QEMU_CLOCK_REALTIME] &&
@@ -896,7 +893,9 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
!active_timers[QEMU_CLOCK_HOST])
return;
nearest_delta_us = qemu_next_deadline_dyntick();
nearest_delta_ns = qemu_next_alarm_deadline();
if (nearest_delta_ns < MIN_TIMER_REARM_NS)
nearest_delta_ns = MIN_TIMER_REARM_NS;
/* check whether a timer is already running */
if (timer_gettime(host_timer, &timeout)) {
@@ -904,14 +903,14 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
fprintf(stderr, "Internal timer error: aborting\n");
exit(1);
}
current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
if (current_us && current_us <= nearest_delta_us)
current_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec;
if (current_ns && current_ns <= nearest_delta_ns)
return;
timeout.it_interval.tv_sec = 0;
timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
timeout.it_value.tv_sec = nearest_delta_us / 1000000;
timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
timeout.it_value.tv_sec = nearest_delta_ns / 1000000000;
timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000;
if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
perror("settime");
fprintf(stderr, "Internal timer error: aborting\n");
@@ -921,6 +920,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
#endif /* defined(__linux__) */
#if !defined(_WIN32)
static int unix_start_timer(struct qemu_alarm_timer *t)
{
struct sigaction act;

View File

@@ -200,6 +200,11 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_UNDEFINED_ERROR,
.desc = "An undefined error has ocurred",
},
{
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)",
},
{
.error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)",

View File

@@ -165,6 +165,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
#define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"

View File

@@ -1638,6 +1638,12 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque)
{
const VMStateSubsection *sub = vmsd->subsections;
if (!sub || !sub->needed) {
return 0;
}
while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
char idstr[256];
int ret;
@@ -1650,10 +1656,11 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
idstr[len] = 0;
version_id = qemu_get_be32(f);
sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
sub_vmsd = vmstate_get_subsection(sub, idstr);
if (sub_vmsd == NULL) {
return -ENOENT;
}
assert(!sub_vmsd->subsections);
ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
if (ret) {
return ret;
@@ -1677,6 +1684,7 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
qemu_put_be32(f, vmsd->version_id);
assert(!vmsd->subsections);
vmstate_save_state(f, vmsd, opaque);
}
sub++;

View File

@@ -23,7 +23,7 @@
* Find a nice value for msize
* XXX if_maxlinkhdr already in mtu
*/
#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6)
#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
void
m_init(Slirp *slirp)
@@ -65,7 +65,7 @@ m_get(Slirp *slirp)
m->m_flags = (flags | M_USEDLIST);
/* Initialise it */
m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr);
m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
m->m_data = m->m_dat;
m->m_len = 0;
m->m_nextpkt = NULL;

View File

@@ -137,10 +137,6 @@ DEF_HELPER_2(rsqrte_f32, f32, f32, env)
DEF_HELPER_2(recpe_u32, i32, i32, env)
DEF_HELPER_2(rsqrte_u32, i32, i32, env)
DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32)
DEF_HELPER_2(neon_add_saturate_u64, i64, i64, i64)
DEF_HELPER_2(neon_add_saturate_s64, i64, i64, i64)
DEF_HELPER_2(neon_sub_saturate_u64, i64, i64, i64)
DEF_HELPER_2(neon_sub_saturate_s64, i64, i64, i64)
DEF_HELPER_2(add_cc, i32, i32, i32)
DEF_HELPER_2(adc_cc, i32, i32, i32)
@@ -160,10 +156,18 @@ DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32)
DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32)
DEF_HELPER_3(neon_qadd_u64, i64, env, i64, i64)
DEF_HELPER_3(neon_qadd_s64, i64, env, i64, i64)
DEF_HELPER_3(neon_qsub_u64, i64, env, i64, i64)
DEF_HELPER_3(neon_qsub_s64, i64, env, i64, i64)
DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)

View File

@@ -198,6 +198,28 @@ NEON_VOP_ENV(qadd_u16, neon_u16, 2)
#undef NEON_FN
#undef NEON_USAT
uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b)
{
uint32_t res = a + b;
if (res < a) {
SET_QC();
res = ~0;
}
return res;
}
uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 + src2;
if (res < src1) {
SET_QC();
res = ~(uint64_t)0;
}
return res;
}
#define NEON_SSAT(dest, src1, src2, type) do { \
int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -218,6 +240,28 @@ NEON_VOP_ENV(qadd_s16, neon_s16, 2)
#undef NEON_FN
#undef NEON_SSAT
uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b)
{
uint32_t res = a + b;
if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
SET_QC();
res = ~(((int32_t)a >> 31) ^ SIGNBIT);
}
return res;
}
uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 + src2;
if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
SET_QC();
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
}
return res;
}
#define NEON_USAT(dest, src1, src2, type) do { \
uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -234,6 +278,29 @@ NEON_VOP_ENV(qsub_u16, neon_u16, 2)
#undef NEON_FN
#undef NEON_USAT
uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b)
{
uint32_t res = a - b;
if (res > a) {
SET_QC();
res = 0;
}
return res;
}
uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2)
{
uint64_t res;
if (src1 < src2) {
SET_QC();
res = 0;
} else {
res = src1 - src2;
}
return res;
}
#define NEON_SSAT(dest, src1, src2, type) do { \
int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
if (tmp != (type)tmp) { \
@@ -254,6 +321,28 @@ NEON_VOP_ENV(qsub_s16, neon_s16, 2)
#undef NEON_FN
#undef NEON_SSAT
uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b)
{
uint32_t res = a - b;
if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
SET_QC();
res = ~(((int32_t)a >> 31) ^ SIGNBIT);
}
return res;
}
uint64_t HELPER(neon_qsub_s64)(CPUState *env, uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 - src2;
if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
SET_QC();
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
}
return res;
}
#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1
NEON_VOP(hadd_s8, neon_s8, 4)
NEON_VOP(hadd_u8, neon_u8, 4)

View File

@@ -424,52 +424,3 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
return ((uint32_t)x >> shift) | (x << (32 - shift));
}
}
uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 + src2;
if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
env->QF = 1;
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
}
return res;
}
uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 + src2;
if (res < src1) {
env->QF = 1;
res = ~(uint64_t)0;
}
return res;
}
uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2)
{
uint64_t res;
res = src1 - src2;
if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
env->QF = 1;
res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
}
return res;
}
uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
{
uint64_t res;
if (src1 < src2) {
env->QF = 1;
res = 0;
} else {
res = src1 - src2;
}
return res;
}

View File

@@ -3539,12 +3539,6 @@ static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32
#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32
/* FIXME: This is wrong. They set the wrong overflow bit. */
#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c)
#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c)
#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c)
#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c)
#define GEN_NEON_INTEGER_OP_ENV(name) do { \
switch ((size << 1) | u) { \
case 0: \
@@ -4233,16 +4227,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
switch (op) {
case 1: /* VQADD */
if (u) {
gen_helper_neon_add_saturate_u64(CPU_V001);
gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
cpu_V0, cpu_V1);
} else {
gen_helper_neon_add_saturate_s64(CPU_V001);
gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
cpu_V0, cpu_V1);
}
break;
case 5: /* VQSUB */
if (u) {
gen_helper_neon_sub_saturate_u64(CPU_V001);
gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
cpu_V0, cpu_V1);
} else {
gen_helper_neon_sub_saturate_s64(CPU_V001);
gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
cpu_V0, cpu_V1);
}
break;
case 8: /* VSHL */
@@ -4686,7 +4684,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
}
if (op == 1 || op == 3) {
/* Accumulate. */
neon_load_reg64(cpu_V0, rd + pass);
neon_load_reg64(cpu_V1, rd + pass);
tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */
@@ -4750,7 +4748,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (op == 1 || op == 3) {
/* Accumulate. */
tmp2 = neon_load_reg(rd, pass);
gen_neon_add(size, tmp2, tmp);
gen_neon_add(size, tmp, tmp2);
dead_tmp(tmp2);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */

View File

@@ -1147,8 +1147,8 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
if (cenv == env) {
continue;
}
qemu_inject_x86_mce(env, 1, 0xa000000000000000, 0, 0, 0);
qemu_inject_x86_mce(env, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0);
}
}
}

View File

@@ -960,9 +960,9 @@ static void _decode_opc(DisasContext * ctx)
tcg_gen_andi_i32(t1, cpu_sr, SR_T);
tcg_gen_sub_i32(REG(B11_8), t0, t1);
tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
tcg_gen_setcond_i32(TCG_COND_GE, t1, REG(B11_8), t0);
tcg_gen_setcondi_i32(TCG_COND_GTU, t1, t0, 0);
tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
tcg_gen_setcondi_i32(TCG_COND_GE, t1, t0, 0);
tcg_gen_setcond_i32(TCG_COND_GTU, t1, REG(B11_8), t0);
tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);

View File

@@ -388,12 +388,16 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
else
modifiers_state[keycode] = 1;
break;
#define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION)
#if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14
/* SDL versions before 1.2.14 don't support key up for caps/num lock. */
case 0x45: /* num lock */
case 0x3a: /* caps lock */
/* SDL does not send the key up event, so we generate it */
kbd_put_keycode(keycode);
kbd_put_keycode(keycode | SCANCODE_UP);
return;
#endif
}
/* now send the key code */
@@ -831,6 +835,10 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
}
/* Enable normal up/down events for Caps-Lock and Num-Lock keys.
* This requires SDL >= 1.2.14. */
setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
if (SDL_Init (flags)) {
fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",

View File

@@ -227,6 +227,10 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
if (job->vs->csock == -1) {
vnc_unlock_display(job->vs->vd);
/* output mutex must be locked before going to
* disconnected:
*/
vnc_lock_output(job->vs);
goto disconnected;
}

4
vl.c
View File

@@ -738,7 +738,7 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev,
node = qemu_mallocz(sizeof(FWBootEntry));
node->bootindex = bootindex;
node->suffix = strdup(suffix);
node->suffix = suffix ? qemu_strdup(suffix) : NULL;
node->dev = dev;
QTAILQ_FOREACH(i, &fw_boot_order, link) {
@@ -785,7 +785,7 @@ char *get_boot_devices_list(uint32_t *size)
} else if (devpath) {
bootpath = devpath;
} else {
bootpath = strdup(i->suffix);
bootpath = qemu_strdup(i->suffix);
assert(bootpath);
}