Compare commits

..

96 Commits

Author SHA1 Message Date
Bruce Rogers
69903f803a This is the delta between the qemu and qemu-kvm v0.12.5 versions
Signed-off-by: Bruce Rogers <brogers@suse.com>
2018-01-22 14:00:07 -07:00
Aurelien Jarno
174f225e9d Update for 0.12.5 release
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-07-22 14:39:04 +02:00
malc
e916448940 audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit d9812b033a)
2010-07-22 14:37:23 +02:00
Kevin Wolf
bb44e0bbce block: Handle multiwrite errors only when all requests have completed
Don't try to be clever by freeing all temporary data and calling all callbacks
when the return value (an error) is certain. Doing so has at least two
important problems:

* The temporary data that is freed (qiov, possibly zero buffer) is still used
  by the requests that have not yet completed.
* Calling the callbacks for all requests in the multiwrite means for the caller
  that it may free buffers etc. which are still in use.

Just remember the error value and do the cleanup when all requests have
completed.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit de189a1b4a)
2010-07-14 13:09:24 +02:00
Kevin Wolf
191d44fc43 block: Fix early failure in multiwrite
bdrv_aio_writev may call the callback immediately (and it will commonly do so
in error cases). Current code doesn't consider this. For details see the
comment added by this patch.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 453f9a1652)

Conflicts:

	block.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 13:09:24 +02:00
Kevin Wolf
a2f0cbaa58 vpc: Use bdrv_(p)write_sync for metadata writes
Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 078a458e07)

Conflicts:

	block/vpc.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 13:08:45 +02:00
Kevin Wolf
a9d9a66f13 vmdk: Use bdrv_(p)write_sync for metadata writes
Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit b8852e87d9)

Conflicts:

	block/vmdk.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 13:08:04 +02:00
Kevin Wolf
37060c28e5 qcow2: Use bdrv_(p)write_sync for metadata writes
Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 8b3b720620)

Conflicts:

	block/qcow2-cluster.c
	block/qcow2-refcount.c
	block/qcow2-snapshot.c
	block/qcow2.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 12:39:38 +02:00
Kevin Wolf
7205c21e76 qcow: Use bdrv_(p)write_sync for metadata writes
Use bdrv_(p)write_sync to ensure metadata integrity in case of a crash.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 5e5557d970)

Conflicts:

	block/qcow.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 12:18:35 +02:00
Kevin Wolf
ceef722d01 block: Add bdrv_(p)write_sync
Add new functions that write and flush the written data to disk immediately.
This is what needs to be used for image format metadata to maintain integrity
for cache=... modes that don't use O_DSYNC. (Actually, we only need barriers,
and therefore the functions are defined as such, but flushes is what is
implemented in this patch - we can try to change that later)

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f08145fe16)
2010-07-14 12:18:26 +02:00
Kevin Wolf
dfe0bb55ee qcow2: Restore L1 entry on l2_allocate failure
If writing the L1 table to disk failed, we need to restore its old content in
memory to avoid inconsistencies.

Reported-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 68dba0bf45)
2010-07-14 11:55:31 +02:00
Kevin Wolf
6fd82592ce block/vdi: Fix image opening and creation for odd disk sizes
The fix is based on a patch from Kevin Wolf. Here his comment:

"The number of blocks needs to be rounded up to cover all of the virtual hard
disk. Without this fix, we can't even open our own images if their size is not
a multiple of the block size."

While Kevin's patch addressed vdi_create, my modification also fixes
vdi_open which now accepts images with odd disk sizes.

v3:
Don't allow reading of disk images with too large disk sizes.
Neither VBoxManage nor old versions of qemu-img read such images.
This change requires rounding of odd disk sizes before we do the checks.

Cc: Kevin Wolf <kwolf@redhat.com>
Cc: François Revol <revol@free.fr>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f21dc3a465)

Conflicts:

	block/vdi.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 11:50:47 +02:00
Stefan Weil
39187b5192 block/vpc: Fix conversion from size to disk geometry
The VHD algorithm calculates a disk geometry
which is usually smaller than the requested size.

QEMU tried to round up but failed for certain sizes:

qemu-img create -f vpc disk.vpc 9437184
would create an image with 9435136 bytes
(which is too small for qemu-img convert).

Instead of hacking the geometry algorithm, the patch
increases the number of sectors until we get enough
sectors.

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 dede4188cc)
2010-07-14 11:46:22 +02:00
Kevin Wolf
729862401d qcow2: Remove abort on free_clusters failure
While it's true that during regular operation free_clusters failure would be a
bug, an I/O error can always happen. There's no need to kill the VM, the worst
thing that can happen (and it will) is that we leak some clusters.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 003fad6e2c)
2010-07-14 11:45:07 +02:00
Kevin Wolf
34d0d68bdf vmdk: Fix COW
When trying to do COW, VMDK wrote the data back to the backing file. This
problem was revealed by the patch that made backing files read-only. This patch
does not only fix the problem, but also simplifies the VMDK code a bit.

This fixes the backing file qemu-iotests cases for VMDK.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit c336500df5)
2010-07-14 10:41:09 +02:00
Kevin Wolf
82e9cbeb0d qcow2: Fix creation of large images
qcow_create2 assumes that the new image will only need one cluster for its
refcount table initially. Obviously that's not true any more when the image is
big enough (exact value depends on the cluster size).

This patch calculates the refcount table size dynamically.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 4768fa902c)

Conflicts:

	block/qcow2.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 10:33:49 +02:00
Kevin Wolf
2020dd5535 vmdk: fix double free
fail_gd error case would also free rgd_buf that was already freed

Signed-off-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit a161329b61)

Conflicts:

	block/vmdk.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-07-14 10:30:42 +02:00
Aurelien Jarno
0c0f53e25c qemu-options: add documentation for stdio signal=on|off
Commit 5989020bc1 introduced a chardev
option to disable signals on stdio. Add the corresponding documentation.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-07-13 21:18:13 +02:00
Chih-Min Chao
3dbe0714dd target-arm : fix parallel saturated subtraction implementation
Signed-off-by: Chih-Min Chao <cmchao@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 4c4fd3f852)
2010-07-01 23:57:36 +02:00
Chih-Min Chao
9067bac11d target-arm : fix thumb2 parallel add/sub opcode decoding
Signed-off-by: Chih-Min Chao <cmchao@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit ed89a2f1b1)
2010-07-01 23:57:02 +02:00
Chih-Min Chao
74471f3742 target-arm: fix addsub/subadd implementation
Signed-off-by: Chih-Min Chao <cmchao@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit bb42e28bdb)
2010-07-01 23:56:49 +02:00
Richard Henderson
370f80376a target-i386: fix xchg rax,r8
We were ignoring REX_B while special-casing NOP, i.e. xchg eax,eax.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 7418027ea4)
2010-07-01 23:56:32 +02:00
Kirill A. Shutemov
ed3aac289a block/vvfat.c: fix warnings with _FORTIFY_SOURCE
CC    block/vvfat.o
cc1: warnings being treated as errors
block/vvfat.c: In function 'commit_one_file':
block/vvfat.c:2259: error: ignoring return value of 'ftruncate', declared with attribute warn_unused_result
make: *** [block/vvfat.o] Error 1
  CC    block/vvfat.o
In file included from /usr/include/stdio.h:912,
                 from ./qemu-common.h:19,
                 from block/vvfat.c:27:
In function 'snprintf',
    inlined from 'init_directories' at block/vvfat.c:871,
    inlined from 'vvfat_open' at block/vvfat.c:1068:
/usr/include/bits/stdio2.h:65: error: call to __builtin___snprintf_chk will always overflow destination buffer
make: *** [block/vvfat.o] Error 1

Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 2dedf83ef0)
2010-06-30 23:40:48 +02:00
Vagrant Cascadian
11b52a6536 audio/alsa: Spelling typo (paramters)
Trivial patch to fix the spelling of "parameters".

Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit f093feb735)
2010-06-30 23:39:08 +02:00
Aurelien Jarno
b6185fc79c target-mips: fix DINSU instruction
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-06-30 23:38:04 +02:00
Jes Sorensen
8fd7d5438e Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE
Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE in hw/fdc.c

Per https://bugs.launchpad.net/qemu/+bug/424453 the correct values
for FD_CMD_SAVE is 0x2e and FD_CMD_RESTORE is 0x4e. Verified against
the Intel 82078 manual which can be found at:
http://wiki.qemu.org/Documentation/HardwareManuals page 22.

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit bb350a5e9b)
2010-06-15 22:50:47 +02:00
Kevin Wolf
a513171f80 qcow2: Fix corruption after error in update_refcount
After it is done with updating refcounts in the cache, update_refcount writes
all changed entries to disk. If a refcount block allocation fails, however,
there was no change yet and therefore first_index = last_index = -1. Don't
treat -1 as a normal sector index (resulting in a 512 byte write!) but return
without updating anything in this case.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 86fa8da837)
2010-06-09 18:36:09 +02:00
Kevin Wolf
ff9e177617 qcow2: Fix corruption after refblock allocation
Refblock allocation code needs to take into consideration that update_refcount
will load a different refcount block into the cache, so it must initialize the
cache for a new refcount block only afterwards. Not doing this means that not
only the refcount in the wrong block is updated, but also that the caller will
work on the wrong block.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 25408c0950)
2010-06-09 18:36:09 +02:00
Kevin Wolf
db3519a9ec block: Fix multiwrite with overlapping requests
With overlapping requests, the total number of sectors is smaller than the sum
of the nb_sectors of both requests.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit cbf1dff2f1)
2010-06-09 18:36:09 +02:00
Kevin Wolf
258e351d12 qcow2: Fix error handling in l2_allocate
l2_allocate has some intermediate states in which the image is inconsistent.
Change the order to write to the L1 table only after the new L2 table has
successfully been initialized.

Also reset the L2 cache in failure case, it's very likely wrong.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 175e11526e)

Conflicts:

	block/qcow2-cluster.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-06-09 18:36:09 +02:00
Kevin Wolf
cd14f4d346 qcow2: Clear L2 table cache after write error
If the L2 table was already updated in cache, but writing it to disk has
failed, we must not continue using the changed version in the cache to stay
consistent with what's on the disk.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 1b7c801b40)

Conflicts:

	block/qcow2-cluster.c

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-06-09 18:36:09 +02:00
Kevin Wolf
df631629b1 ide: Fix ide_dma_cancel
When cancelling a request, bdrv_aio_cancel may decide that it waits for
completion of a request rather than for cancellation. IDE therefore can't
abandon its DMA status before calling bdrv_aio_cancel; otherwise the callback
of a completed request would use invalid data.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 38d8dfa193)
2010-06-09 18:36:09 +02:00
Luiz Capitulino
af0269b036 usb-bus: fix no params
After commit 702f3e0fb5, the params is
nerver NULL. It should check *params instead of params to determine
whether the params is empty.

Signed-off-by: TeLeMan <geleman@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
(cherry picked from commit 98f22dc172)
2010-06-09 12:45:03 +02:00
Jan Kiszka
d37dbf988d Avoid crash on '-usbdevice <device>' without parameters
Many usbdevice_init implementors assume params is non-NULL.

Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 702f3e0fb5)
2010-06-09 12:44:57 +02:00
Paul Brook
cc7ed88f28 Fix -usbdevice crash
If -usbdevice is used on a machine with no USB busses, usb_create
will fail and return NULL.  Patch below handles this failure gracefully
rather than crashing when we try to init the device.

Signed-off-by: Paul Brook <paul@codesourcery.com>
(cherry picked from commit d44168fffa)
2010-06-09 12:44:56 +02:00
Alexander Graf
07442ab4a1 Fix multiboot compilation
Commit dd4239d657 broke multiboot. It replaced the
instruction "rep insb (%dx), %es:(%edi)" by the binary output of
"addr32 rep insb (%dx), %es:(%di)".

Linuxboot calls the respective helper function in a code16 section. So the
original instruction was automatically translated to its "addr32" equivalent.
For multiboot, we're running in code32 so gcc didn't add the "addr32" which
breaks the instruction.

This patch splits that helper function in one which uses addr32 and one which
does not, so everyone's happy.

The good news is that nobody probably cared so far. The bundled multiboot.bin
binary was built before the change and is thus correct.

Please also put this patch into -stable.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 590bf491a4)
2010-06-09 12:36:11 +02:00
Loïc Minier
dbe6a18d82 Fix missing symbols in .rel/.rela.plt sections
Fix .rel.plt sections in the output to not only include .rel.plt
sections from the input but also the .rel.iplt sections and to define
the hidden symbols __rel_iplt_start and __rel_iplt_end around
.rel.iplt as otherwise we get undefined references to these when
linking statically to a multilib libc.a.  This fixes the static build
under i386.

Apply similar logic to rela.plt/.iplt and __rela_iplt/_plt_start/_end to
fix the static build under amd64.

Signed-off-by: Loïc Minier <lool@dooz.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 845f2c2812)
2010-06-02 20:45:03 +02:00
Thomas Monjalon
7dd007c2ed target-ppc: fix RFI by clearing some bits of MSR
Since commit 2ada0ed, "Return From Interrupt" is broken for PPC processors
because some interrupt specifics bits of SRR1 are copied to MSR.

SRR1 is a save of MSR during interrupt.
During RFI, MSR must be restored from SRR1.
But some bits of SRR1 are interrupt-specific and are not used for MSR saving.

This is the specification (ISA 2.06) at chapter 6.4.3 (Interrupt Processing):
"2. Bits 33:36 and 42:47 of SRR1 or HSRR1 are loaded with information specific
    to the interrupt type.
 3. Bits 0:32, 37:41, and 48:63 of SRR1 or HSRR1 are loaded with a copy of the
    corresponding bits of the MSR."

Below is a representation of MSR bits which are not saved:
0:15 16:31 32  33:36    37:41      42:47     48:63
——— | ——— | — X X X X — — — — — X X X X X X | ————
0000 0000 |    7   |   8   |   3   |   F    | 0000

History:
In the initial Qemu implementation (e1833e1), the mask 0x783F0000 was used for
saving MSR in SRR1. But all the bits 32:47 were cleared during RFI restoring.
This was wrong. The commit 2ada0ed explains that this breaks Altivec.
Indeed, bit 38 (for Altivec support) must be saved and restored.
The change of 2ada0ed was to restore all the bits of SRR1 to MSR.
But it's also wrong.

Explanation:
As an example, let's see what's happening after a TLB miss.
According to the e300 manual (E300CORERM table 5-6), the TLB miss interrupts
set the bits 44-47 for KEY, I/D, WAY and S/L. These bits are specifics to the
interrupt and must not be copied into MSR at the end of the interrupt.
With the current implementation, a TLB miss overwrite bits POW, TGPR and ILE.

Fix:
It shouldn't be needed to filter-out bits on MSR saving when interrupt occurs.
Specific bits overwrite MSR ones in SRR1.
But at the end of interrupt (RFI), specifics bits must be cleared before
restoring MSR from SRR1. The mask 0x783F0000 apply here.

Discussion:
The bits of the mask 0x783F0000 are cleared after an interrupt.
I cannot find a specification which talks about this
but I assume it is the truth since Linux can run this way.
Maybe it's not perfect but it's better (works for e300).

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit c3d420ead1)
2010-05-31 22:26:37 +02:00
Riccardo Magliocchetti
9c6a8f503d Fix typo in balloon help
Fix launchpad #563883

Signed-off-by: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 3c05613a6a)
2010-05-28 22:59:04 +02:00
Rabin Vincent
0c459361a1 arm_timer: fix oneshot mode
In oneshot mode, the delta needs to come from the TimerLoad register,
not the maximum limit.

Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit a9cf98d939)
2010-05-27 15:52:57 +02:00
Rabin Vincent
72d3457e8d arm_timer: reload timer when enabled
Reload the timer when TimerControl is written, if the timer is to be
enabled.  Otherwise, if an earlier write to TimerLoad was done while
periodic mode was not set, s->delta may incorrectly still have the value
of the maximum limit instead of the value written to TimerLoad.

This problem is evident on versatileap on current linux-next, which
enables TIMER_CTRL_32BIT before writing to TimerLoad and then enabling
periodic mode and starting the timer.  This causes the first periodic
tick to be scheduled to occur after 0xffffffff periods, leading to a
perceived hang while the kernel waits for the first timer tick.

Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit d6759902cb)
2010-05-27 15:52:52 +02:00
Jens Osterkamp
e1f0c1d05d qemu-sockets: avoid strlen of NULL pointer
If the user wants to create a chardev of type socket but forgets to give a
host= option, qemu_opt_get returns NULL. This NULL pointer is then fed into
strlen a few lines below without a check which results in a segfault.
This fixes it.

Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit e23a22e620)
2010-05-27 15:52:42 +02:00
Avi Kivity
74bcc51b99 block: fix aio_flush segfaults for read-only protocols (e.g. curl)
Not all block format drivers expose an io_flush method (reasonable for
read-only protocols), so calling io_flush there will immediately segfault.

Fix by checking for the method's existence before calling it.

Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit c53a7285b4)
2010-05-27 13:58:57 +02:00
Christoph Hellwig
7e4f956056 virtio-blk: fix barrier support
Before issuing the barrier to the block driver we need to flush our oustanding
queue of write requests, as the flush is supposed to be issued after them.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 618fbb8429)
2010-05-27 13:58:42 +02:00
Christoph Hellwig
1fb9798b69 block: fix sector comparism in multiwrite_req_compare
The difference between the start sectors of two requests can be larger
than the size of the "int" type, which can lead to a not correctly
sorted multiwrite array and thus spurious I/O errors and filesystem
corruption due to incorrect request merges.

So instead of doing the cute sector arithmetics trick spell out the
exact comparisms.

Spotted by Kevin Wolf based on a testcase from Michael Tokarev.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 77be4366ba)
2010-05-27 13:58:34 +02:00
Michael S. Tsirkin
9f6a84bc43 pci: irq_state vmstate breakage
Code for saving irq_state got vm_state
macros wrong, passing in the wrong parameter.
As a result, we both saved a wrong value
and restored it to a wrong offset.

This leads to device and bus irq counts getting
out of sync, which in turn leads to interrupts getting lost or
never cleared, such as
https://bugzilla.redhat.com/show_bug.cgi?id=588133

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Juan Quintela <quintela@redhat.com>
(cherry picked from commit c3f8f61157)
2010-05-18 13:27:46 +02:00
TeLeMan
8cef921d18 qemu-img: use the heap instead of the huge stack array for win32
The default stack size of PE is 1MB on win32 and IO_BUF_SIZE in
img_convert() & img_rebase() is 2MB, so qemu-img will crash when doing
"convert" & "rebase" on win32.
Although we can improve the stack size of PE to resolve it, I think we
should avoid using the huge stack variables.

Signed-off-by: TeLeMan <geleman@gmail.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 72ff25e4e9)
2010-05-07 09:07:42 +02:00
Anthony Liguori
b04c3db504 Update for 0.12.4 release
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-05-04 09:17:19 -05:00
Juergen Lock
d04d7cf158 Workaround for broken OSS_GETVERSION on FreeBSD, part two
Turns out on those versions of FreeBSD (>= 7.x) that know OSS_GETVERSION
the ioctl doesn't actually work yet (except in the Linuxolator), so if
building on FreeBSD assume the sound drivers are new enough if the ioctl
returns the errno it does currently on FreeBSD.

(Rev 2 after private discussion with malc.)

 Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de>

Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 72ff25e4e9)
2010-04-25 12:20:26 +02:00
malc
2b8bdd5c7f oss: fix fragment setting
Previous patch introduced subtle regression, in cases when
OSS_GETVERSION fails the code wasn't falling back to
SNDCTL_DSP_SETFRAGMENT.

Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 3d709fe73a)
2010-04-25 12:20:10 +02:00
malc
2a44494726 oss: issue OSS_GETVERSION ioctl only when needed
Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 6d246526ce)
2010-04-25 12:20:01 +02:00
malc
8f30db54d9 oss: refactor code around policy setting
This fixes a problem with a previous patch spotted by Juergen Lock,
thanks to him again.

Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit 78d9356d3c)
2010-04-25 12:19:48 +02:00
malc
b09ac1abe7 oss: workaround for cases when OSS_GETVERSION is not defined
Thanks to Juergen Lock.

Signed-off-by: malc <av1474@comtv.ru>
(cherry picked from commit e726fe7d60)
2010-04-25 12:19:39 +02:00
Stefan Hajnoczi
012d4869c1 block: Free iovec arrays allocated by multiwrite_merge()
A new iovec array is allocated when creating a merged write request.
This patch ensures that the iovec array is deleted in addition to its
qiov owner.

Reported-by: Leszek Urbanski <tygrys@moo.pl>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 1e1ea48d42)
2010-04-24 12:45:03 +02:00
Gerd Hoffmann
3597c9c1d5 lsi: fix segfault in lsi_command_complete
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 6ac08101f9)
2010-04-18 22:02:30 +02:00
Gerd Hoffmann
3b4bef0696 lsi: pass lsi_request to lsi_reselect
All callers of lsi_reselect have a lsi_request struct at hand anyway.
So just pass it directly instead of having lsi_reselect search for it
using the tag.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit aa4d32c474)
2010-04-18 22:02:03 +02:00
Gerd Hoffmann
d899303743 lsi: move dma_len+dma_buf into lsi_request
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit b96a0da06b)
2010-04-18 22:01:55 +02:00
Gerd Hoffmann
5773685183 lsi: move current_dev into lsi_request
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit daa70311e0)
2010-04-18 22:01:47 +02:00
Gerd Hoffmann
d40ba77ebf lsi: have lsi_request for the whole life time of the request.
Right now lsi_request is allocated when a request is queued and released
when a request is unqueued.  With this patch applied the lsi_request is
kept for the whole lifetime of the scsi request.

Rationale: We can use it for per-request data then.  The patch does that
already for the request tag.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit af12ac9880)
2010-04-18 22:01:41 +02:00
Gerd Hoffmann
a8c46d182c lsi: use QTAILQ for lsi_queue
Replace the funky array logic for queued commands with standard
qemu list functions.  Also rename lsi_queue to lsi_request.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 042ec49dc5)
2010-04-18 22:01:31 +02:00
Stefan Weil
d80e20a1c3 tcp/mips: Change TCG_AREG0 (fp -> s0)
Register fp (frame pointer) is a bad choice for compilations
without optimisation, because the compiler makes heavy use
of this register (so the resulting code crashes).

Register s0 had been used for TCG_AREG1 in earlier releases,
but was no longer used and is now free for TCG_AREG0.

The resulting code works for compilations without
optimisation (tested with qemu mips in qemu mips
on x86 host).

Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-04-14 01:02:24 +02:00
Aurelien Jarno
1ce4fad939 sh_pci: fix memory and I/O access
Since commit 8da3ff1809 ("MMIO callback
interface changes"), the addresses passed to the I/O functions are an
offset to the start of the area. As a consequence, there is no need to
correct the address using the value of IOBR. This make possible the use
of the default MMIO functions. Moreover the addresses are now remaped
when the value if IOBR change.

The memory area corresponds to the devices behing the PCI bus, it should
not be mapped by the PCI controller. Remove the corresponding code.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry-picked from commit 5ba9e9522c)
2010-04-14 00:54:38 +02:00
Marcelo Tosatti
9167a242db Fix incoming migration with iothread
Do not allow the vcpus to execute if the vm is stopped.

Fixes -incoming with CONFIG_IOTHREAD enabled.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
(cherry picked from commit c5f32c99c6)
2010-04-14 00:10:24 +02:00
Chris Webb
09e96924ec Fix SIGFPE for vnc display of width/height = 1
During boot, the screen gets resized to height 1 and a mouse click at this
point will cause a division by zero when calculating the absolute pointer
position from the pixel (x, y). Return a click in the middle of the screen
instead in this case.

Signed-off-by: Chris Webb <chris@arachsys.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit cc39a92cbf)
2010-04-11 13:34:43 +02:00
Eduardo Habkost
69ff4e9dbd net: remove broken net_set_boot_mask() boot device validation
There are many problems with net_set_boot_mask():

1) It is broken when using the device model instead of "-net nic". Example:
   $ qemu-system-x86_64 -device rtl8139,vlan=0,id=net0,mac=52:54:00:82:41:fd,bus=pci.0,addr=0x4 -net user,vlan=0,name=hostnet0 -vnc 0.0.0.0:0 -boot n
   Cannot boot from non-existent NIC
   $
2) The mask was previously used to set which boot ROMs were supposed to be
   loaded, but this was changed long time ago. Now all ROM images are loaded,
   and SeaBIOS takes care of jumping to the right boot entry point depending on
   the boot settings.
3) Interpretation and validation of the boot parameter letters is done on
   the machine type code. Examples: PC accepts only a,b,c,d,n as valid boot
   device letters. mac99 accepts only a,b,c,d,e,f.

As a side-effect of this change, qemu-kvm won't abort anymore if using "-boot n"
on a machine with no network devices. Checking if the requested boot device is
valid is now a task for the BIOS or the machine-type code.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Acked-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry-picked from da1fcfda59)
2010-04-11 12:33:21 +02:00
Kevin Wolf
0434349d6a qcow2: Remove request from in-flight list after error
If we complete a request with a failure we need to remove it from the list of
requests that are in flight. If we don't do it, the next time the same AIOCB is
used for a cluster allocation it will create a loop in the list and qemu will
hang in an endless loop.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit c644db3d53)
2010-04-10 01:54:52 +02:00
Kevin Wolf
e007221223 qcow2: Don't ignore immediate read/write failures
Returning -EIO is far from optimal, but at least it's an error code.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 171e3d6b99)
2010-04-10 01:51:35 +02:00
Kevin Wolf
4622317288 block: Fix multiwrite memory leak in error case
Previously multiwrite_user_cb was never called if a request in the multiwrite
batch failed right away because it did set mcb->error immediately. Make it look
more like a normal callback to fix this.

Reported-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 7eb58a6c55)
2010-04-10 01:15:54 +02:00
Kevin Wolf
ffac613ff9 block: Fix error code in multiwrite for immediate failures
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 0f0b604b00)
2010-04-10 01:15:44 +02:00
Kevin Wolf
aba5288247 block: Fix multiwrite error handling
When two requests of the same multiwrite batch fail, the callback of all
requests in that batch were called twice. This could have any kind of nasty
effects, in my case it lead to use after free and eventually a segfault.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit cb6d3ca07b)
2010-04-10 00:36:49 +02:00
Gerd Hoffmann
4f7cb96931 scsi-disk: fix buffer overflow
In case s->version is shorter than 4 bytes we overflow the memcpy src
buffer.  Fix it by clearing the target buffer, then copy only the
amount of bytes we actually have.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from 314b1811c1)

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-04-09 18:41:59 +02:00
Kevin Wolf
fafc2e4b33 qcow2: Rewrite alloc_refcount_block/grow_refcount_table
The current implementation of alloc_refcount_block and grow_refcount_table has
fundamental problems regarding error handling. There are some places where an
I/O error means that the image is going to be corrupted. I have found that the
only way to fix this is to completely rewrite the thing.

In detail, the problem is that the refcount blocks itself are allocated using
alloc_refcount_noref (to avoid endless recursion when updating the refcount of
the new refcount block, which migh access just the same refcount block but its
allocation is not yet completed...). Only at the end of the refcount allocation
the refcount of the refcount block is increased. If an error happens in
between, the refcount block is in use, but has a refcount of zero and will
likely be overwritten later.

The new approach is explained in comments in the code. The trick is basically
to let new refcount blocks describe their own refcount, so their refcount will
be automatically changed when they are hooked up in the refcount table.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 92dcb59fd4)
2010-04-09 18:41:59 +02:00
Kevin Wolf
83ef70f24a qcow2: Factor next_refcount_table_size out
When the refcount table grows, it doesn't only grow by one entry but reserves
some space for future refcount blocks. The algorithm to calculate the number of
entries stays the same with the fixes, so factor it out before replacing the
rest.

As Juan suggested take the opportunity to simplify the code a bit.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 05121aedc4)
2010-04-09 18:41:59 +02:00
Christoph Hellwig
de17c16e1f block: avoid creating too large iovecs in multiwrite_merge
If we go over the maximum number of iovecs support by syscall we get
back EINVAL from the kernel which translate to I/O errors for the guest.

Add a MAX_IOV defintion for platforms that don't have it.  For now we use
the same 1024 define that's used on Linux and various other platforms,
but until the windows block backend implements some kind of vectored I/O
it doesn't matter.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit e2a305fb13)

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2010-04-09 18:41:59 +02:00
Kevin Wolf
9462695b64 json-parser: Fix segfault on malformed input
If the parser fails to parse the key in parse_pair, it will access a NULL
pointer. A simple way to trigger this is sending {foo} via QMP. This patch
turns the segfault into a syntax error reply.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit d758d90fe1)
2010-04-09 18:41:59 +02:00
Aurelien Jarno
5eb089588e linux-user: switch default ppc64 CPU to 970fx from 970
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit f7177937a2)
2010-04-09 18:40:39 +02:00
Aurelien Jarno
2039f70c23 target-sh4: MMU: fix store queue addresses
The store queues are located from 0xe0000000 to 0xe3ffffff.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit b1563142123593581895049568c5526b1e91da7b)
2010-04-09 18:22:38 +02:00
Aurelien Jarno
082a9fc256 target-sh4: MMU: fix ITLB priviledge check
There is an ITLB access violation if SR_MD=0 (user mode) while
the high bit of the protection key is 0 (priviledge mode).

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit bc13ad29e6b7484ccd5e7ee0f5d0f966585eb4c9)
2010-04-09 18:22:06 +02:00
Aurelien Jarno
36a013c956 target-sh4: MMU: fix mem_idx computation
The mem_idx is wrongly computed. As written in target-sh4/cpu.h, mode 0
corresponds to kernel mode (SR_MD = 1), while mode 1 corresponds to user
mode (SR_MD = 0).

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 33b8f5546cc16eaa3d89fe133a9843c794b65d6c)
2010-04-09 18:21:51 +02:00
Aurelien Jarno
c4c4b32b81 sh7750: handle MMUCR TI bit
When the MMUCR TI bit is set, all the UTLB and ITLB entries should be
flushed.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit e781d1285fc3b81d689ba25360c6c272116387fa)
2010-04-09 18:21:35 +02:00
Paul Brook
804b6ab08d UHCI spurious interrut fix
Only raise an interrupt if the TD has actually completed.

Signed-off-by: Paul Brook <paul@codesourcery.com>
2010-04-06 07:02:37 +02:00
Aurelien Jarno
81b168a702 tcg/mips: fix branch offset during retranslation
Branch offsets should only be overwritten during relocation, to support
partial retranslation.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 6d8ff4d85c)
2010-03-29 02:11:35 +02:00
Aurelien Jarno
5c6892078a tcg/arm: correctly save/restore registers in prologue/epilogue
Since commit 6113d6d316 QEMU crashes
on ARM hosts. This is not a bug of this commit, but a latent bug
revealed by this commit.

The TCG code is called through a procedure call using the prologue
and epilogue code. This code does not save and restore enough registers.
The "Procedure Call Standard for the ARM Architecture" says:

  A subroutine must preserve the contents of the registers r4-r8, r10,
  r11 and SP (and r9 in PCS variants that designate r9 as v6).

The current code only saves and restores r9 to r11, and misses r4 to
r8. The patch fixes that by saving r4 to r12. Theoretically there is
no need to save and restore r12, but an even number of registers have
to be saved as per EABI.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 4e17eae9f2)
2010-03-19 23:02:37 +01:00
Igor V. Kovalenko
18a21890ff workaround for cmd646 bmdma register access while no dma is active
This is a workaround only, and is a partial revert
of a few changes to BMDMAState which removed pci_dev
field on the way.

- cmd646 pci_from_bm() expects bm->unit value to
correspond with bm data being passed to callback
as opaque pointer. This breaks when write to dma
control register of second channel happens when no
dma operation is in progress, so bm->unit is zero
for second channel, and pci_from_bm() returns garbage
pointer. Crash happens shortly after that while
dereferencing that pointer.

v0->v1: cleaned up dead code from pci_from_bm.

Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 90228ee395)
2010-03-19 22:54:17 +01:00
Jan Kiszka
6629fa6473 Fix corner case in chardev udp: parameter
The missing '@' broke 'udp::<port>@:<port>' parsing.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 39324ca488)
2010-03-16 08:40:50 +01:00
Jan Kiszka
2a7996ce0e Don't set default monitor when there is a mux'ed one
This fixes eg. "-nographic -serial mon:stdio [-serial ...]".

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 18141ed67f)
2010-03-16 08:40:47 +01:00
Vagrant Cascadian
8ec131fb59 spelling typo (compatibilty) in hw/fw_cfg.c
here's a trivial patch to fix the spelling of "compatibility":

Signed-off-by: Vagrant Cascadian <vagrant@freegeek.org>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 66c80e7575)
2010-03-14 22:54:26 +01:00
Gerd Hoffmann
30d061750d fdc: fix drive property handling.
Fix the floppy controller init wrappers to set the drive properties
only in case the DriveInfo pointers passed in are non NULL.  This allows
to set the properties using -global.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 995bf0ca57)
2010-03-13 12:16:06 +01:00
TeLeMan
c5f5dc5bad target-i386: fix commit c22549204a
The commit c22549204a led movntps &
movntdq to be translated incorrectly.

Signed-off-by: TeLeMan <geleman@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 2e21e7491f)
2010-03-13 11:37:33 +01:00
Aurelien Jarno
d2df336c58 target-i386: fix SIB decoding with index = 4
A SIB byte with an index of 4 means "no scaled index", even if the scale
value is not 0. In 64-bit mode, if REX.X is used, an index of 4 selects
%r12. This is correctly handled by the computation of the index variable,
which includes the index bits, and also the REX.X prefix:

    index = ((code >> 3) & 7) | REX_X(s);

Thanks to Avi Kivity, Jamie Lokier and Malc for the analysis of the
problem and the initial patch.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit b16f827bdf)
2010-03-10 08:52:46 +01:00
Ryan Harper
b299b12b17 Fix segfault with ram_size > 4095M without kvm
Currently, x86_64-softmmu qemu segfaults when trying to use > 4095M memsize.
This patch adds a simple check and error message (much like the 2047 limit on
32-bit hosts) on ram_size in the control path after we determine we're
not using kvm

Upstream qemu-kvm is affected if using the -no-kvm option; this patch address
the segfault there as well.

Signed-off-by: Ryan Harper <ryanh@us.ibm.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-03-06 22:30:25 +01:00
malc
c248df6161 target-i386: Fix long jumps/calls in long mode with REX.W set
Signed-off-by: malc <av1474@comtv.ru>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 41b1e61f51)
2010-03-06 19:40:11 +01:00
Aurelien Jarno
7d5625d5f7 target-i386: fix lddqu SSE instruction
This instruction load data from memory to register and not the reverse.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit c22549204a)
2010-03-06 19:40:06 +01:00
Jan Kiszka
cc21d131e3 qemu-char.c: drop debug printfs from qemu_chr_parse_compat
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 5bb599023a)
2010-02-28 14:11:32 +01:00
Paolo Bonzini
41a5bda61f fix undefined shifts by >32
This one is for 0.12 too.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
(cherry picked from commit 0dfbd51446)
2010-02-27 16:36:21 +01:00
Aurelien Jarno
5163f6e864 Fix qemu -net user,hostfwd= example
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit aa37520618)
2010-02-27 11:00:13 +01:00
323 changed files with 45496 additions and 767 deletions

1
.gitignore vendored
View File

@@ -48,4 +48,5 @@ pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/extboot.bin
.stgit-*

View File

@@ -1,3 +1,100 @@
version 0.12.5
- audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
- block: Handle multiwrite errors only when all requests have completed
- block: Fix early failure in multiwrite
- vpc: Use bdrv_(p)write_sync for metadata writes
- vmdk: Use bdrv_(p)write_sync for metadata writes
- qcow2: Use bdrv_(p)write_sync for metadata writes
- qcow: Use bdrv_(p)write_sync for metadata writes
- block: Add bdrv_(p)write_sync
- qcow2: Restore L1 entry on l2_allocate failure
- block/vdi: Fix image opening and creation for odd disk sizes
- block/vpc: Fix conversion from size to disk geometry
- qcow2: Remove abort on free_clusters failure
- vmdk: Fix COW
- qcow2: Fix creation of large images
- vmdk: fix double free
- qemu-options: add documentation for stdio signal=on|off
- target-arm : fix parallel saturated subtraction implementation
- target-arm : fix thumb2 parallel add/sub opcode decoding
- target-arm: fix addsub/subadd implementation
- target-i386: fix xchg rax,r8
- block/vvfat.c: fix warnings with _FORTIFY_SOURCE
- audio/alsa: Spelling typo (paramters)
- target-mips: fix DINSU instruction
- Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE
- qcow2: Fix corruption after error in update_refcount
- qcow2: Fix corruption after refblock allocation
- block: Fix multiwrite with overlapping requests
- qcow2: Fix error handling in l2_allocate
- qcow2: Clear L2 table cache after write error
- ide: Fix ide_dma_cancel
- usb-bus: fix no params
- Avoid crash on '-usbdevice <device>' without parameters
- Fix -usbdevice crash
- Fix multiboot compilation
- Fix missing symbols in .rel/.rela.plt sections
- target-ppc: fix RFI by clearing some bits of MSR
- Fix typo in balloon help
- arm_timer: fix oneshot mode
- arm_timer: reload timer when enabled
- qemu-sockets: avoid strlen of NULL pointer
- block: fix aio_flush segfaults for read-only protocols (e.g. curl)
- virtio-blk: fix barrier support
- block: fix sector comparism in multiwrite_req_compare
- pci: irq_state vmstate breakage
- qemu-img: use the heap instead of the huge stack array for win32
version 0.12.4
- Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock)
- oss: fix fragment setting (malc)
- oss: issue OSS_GETVERSION ioctl only when needed (malc)
- oss: refactor code around policy setting (malc)
- oss: workaround for cases when OSS_GETVERSION is not defined (malc)
- block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi)
- lsi: fix segfault in lsi_command_complete (Gerd Hoffmann)
- lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann)
- lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann)
- lsi: move current_dev into lsi_request (Gerd Hoffmann)
- lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann)
- lsi: use QTAILQ for lsi_queue (Gerd Hoffmann)
- tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil)
- sh_pci: fix memory and I/O access (Aurelien Jarno)
- Fix incoming migration with iothread (Marcelo Tosatti)
- Fix SIGFPE for vnc display of width/height = 1 (Chris Webb)
- net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost)
- qcow2: Remove request from in-flight list after error (Kevin Wolf)
- qcow2: Don't ignore immediate read/write failures (Kevin Wolf)
- block: Fix multiwrite memory leak in error case (Kevin Wolf)
- block: Fix error code in multiwrite for immediate failures (Kevin Wolf)
- block: Fix multiwrite error handling (Kevin Wolf)
- scsi-disk: fix buffer overflow (Gerd Hoffmann)
- qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf)
- qcow2: Factor next_refcount_table_size out (Kevin Wolf)
- block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig)
- json-parser: Fix segfault on malformed input (Kevin Wolf)
- linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno)
- target-sh4: MMU: fix store queue addresses (Aurelien Jarno)
- target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno)
- target-sh4: MMU: fix mem_idx computation (Aurelien Jarno)
- sh7750: handle MMUCR TI bit (Aurelien Jarno)
- UHCI spurious interrut fix (Paul Brook)
- tcg/mips: fix branch offset during retranslation (Aurelien Jarno)
- tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno)
- workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko)
- Fix corner case in chardev udp: parameter (Jan Kiszka)
- Don't set default monitor when there is a mux'ed one (Jan Kiszka)
- spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian)
- fdc: fix drive property handling. (Gerd Hoffmann)
- target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan)
- target-i386: fix SIB decoding with index = 4 (Aurelien Jarno)
- Fix segfault with ram_size > 4095M without kvm (Ryan Harper)
- target-i386: Fix long jumps/calls in long mode with REX.W set (malc)
- target-i386: fix lddqu SSE instruction (Aurelien Jarno)
- qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka)
- fix undefined shifts by >32 (Paolo Bonzini)
- Fix qemu -net user,hostfwd= example (Aurelien Jarno)
version 0.12.3
- kvm: Fix eflags corruption in kvm mode (Jan Kiszka)
- qcow2: Fix access after end of array (Kevin Wolf)

2
EXTERNAL_DEPENDENCIES Normal file
View File

@@ -0,0 +1,2 @@
seabios 9fb3f4d950744e97cc655b7d7b523d8bf101e4a0
vgabios 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a

1
KVM_VERSION Normal file
View File

@@ -0,0 +1 @@
qemu-kvm-0.12.5

View File

@@ -63,6 +63,18 @@ config-host.h-timestamp: config-host.mak
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
ifeq ($(KVM_KMOD),yes)
.PHONEY: kvm-kmod
all: kvm-kmod
kvm-kmod:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C kvm/kernel V="$(V)" )
endif
subdir-%: $(GENERATED_HEADERS)
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
@@ -94,6 +106,7 @@ block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
block-obj-y += nbd.o block.o aio.o aes.o osdep.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-$(CONFIG_POSIX) += compatfd.o
block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
@@ -283,6 +296,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
bamboo.dtb petalogix-s3adsp1800.dtb \
multiboot.bin linuxboot.bin
BLOBS += extboot.bin
BLOBS += vapic.bin
else
BLOBS=
endif
@@ -305,7 +320,12 @@ endif
ifneq ($(BLOBS),)
$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \
if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
fi \
; if [ -f pc-bios/optionrom/$$x ];then \
$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
fi \
done
endif
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
@@ -315,6 +335,9 @@ endif
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
ifeq ($(KVM_KMOD),yes)
$(MAKE) -C kvm/kernel $@
endif
# various test targets
test speed: all
@@ -435,6 +458,7 @@ tarbin:
$(datadir)/pxe-rtl8139.bin \
$(datadir)/pxe-pcnet.bin \
$(datadir)/pxe-e1000.bin \
$(datadir)/extboot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 \

View File

@@ -25,7 +25,9 @@ obj-$(CONFIG_ESCC) += escc.o
# PCI watchdog devices
obj-y += wdt_i6300esb.o
obj-y += msix.o
# MSI-X depends on kvm for interrupt injection,
# so moved it from Makefile.hw to Makefile.target for now
# obj-y += msix.o
# PCI network cards
obj-y += ne2000.o

View File

@@ -30,6 +30,8 @@ LIBS+=-lm
kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
CFLAGS += $(KVM_CFLAGS)
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
@@ -40,12 +42,18 @@ all: $(PROGS)
#########################################################
# cpu emulator library
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
libobj-y += tcg/tcg.o
libobj-y = exec.o cpu-exec.o
libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
libobj-y += op_helper.o helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
libobj-$(CONFIG_KVM) += qemu-kvm-helper.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ALPHA) += alpha_palcode.o
@@ -82,6 +90,8 @@ op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
# cpu_signal_handler() in cpu-exec.c.
signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
#########################################################
# Linux user emulator target
@@ -158,6 +168,10 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
# need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
# MSI-X depends on kvm for interrupt injection,
# so moved it from Makefile.hw to Makefile.target for now
obj-y += msix.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
@@ -194,12 +208,25 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += extboot.o
obj-i386-y += ne2000-isa.o
obj-i386-y += testdev.o
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
# Hardware support
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
obj-ia64-y += usb-uhci.o
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
# shared objects
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
obj-ppc-y += ide/cmd646.o
obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
obj-ppc-y += cirrus_vga.o
# PREP target
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o
@@ -295,6 +322,11 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
ifeq ($(TARGET_ARCH), ia64)
firmware.o: firmware.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
endif
main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)

View File

@@ -1 +1 @@
0.12.3
0.12.5

4
aio.c
View File

@@ -113,7 +113,9 @@ void qemu_aio_flush(void)
qemu_aio_wait();
QLIST_FOREACH(node, &aio_handlers, node) {
ret |= node->io_flush(node->opaque);
if (node->io_flush) {
ret |= node->io_flush(node->opaque);
}
}
} while (qemu_bh_poll() || ret > 0);
}

View File

@@ -213,6 +213,10 @@ static void alsa_poll_handler (void *opaque)
state = snd_pcm_state (hlp->handle);
switch (state) {
case SND_PCM_STATE_SETUP:
alsa_recover (hlp->handle);
break;
case SND_PCM_STATE_XRUN:
alsa_recover (hlp->handle);
break;
@@ -665,7 +669,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
(obt->fmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq)) {
dolog ("Audio paramters for %s\n", typ);
dolog ("Audio parameters for %s\n", typ);
alsa_dump_info (req, obt);
}

View File

@@ -38,6 +38,10 @@
#define AUDIO_CAP "oss"
#include "audio_int.h"
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
#define USE_DSP_POLICY
#endif
typedef struct OSSVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
@@ -236,14 +240,39 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
}
#endif
#ifdef USE_DSP_POLICY
static int oss_get_version (int fd, int *version, const char *typ)
{
if (ioctl (fd, OSS_GETVERSION, &version)) {
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
/*
* Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
* since 7.x, but currently only on the mixer device (or in
* the Linuxolator), and in the native version that part of
* the code is in fact never reached so the ioctl fails anyway.
* Until this is fixed, just check the errno and if its what
* FreeBSD's sound drivers return atm assume they are new enough.
*/
if (errno == EINVAL) {
*version = 0x040000;
return 0;
}
#endif
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
return -1;
}
return 0;
}
#endif
static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd)
{
int fd;
int version;
int oflags = conf.exclusive ? O_EXCL : 0;
audio_buf_info abinfo;
int fmt, freq, nchannels;
int setfragment = 1;
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
const char *typ = in ? "ADC" : "DAC";
@@ -281,27 +310,30 @@ static int oss_open (int in, struct oss_params *req,
goto err;
}
if (ioctl (fd, OSS_GETVERSION, &version)) {
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
version = 0;
}
#ifdef USE_DSP_POLICY
if (conf.policy >= 0) {
int version;
if (conf.debug) {
dolog ("OSS version = %#x\n", version);
}
if (!oss_get_version (fd, &version, typ)) {
if (conf.debug) {
dolog ("OSS version = %#x\n", version);
}
#ifdef SNDCTL_DSP_POLICY
if (conf.policy >= 0 && version >= 0x040000) {
int policy = conf.policy;
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
conf.policy);
goto err;
if (version >= 0x040000) {
int policy = conf.policy;
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
oss_logerr2 (errno, typ,
"Failed to set timing policy to %d\n",
conf.policy);
goto err;
}
setfragment = 0;
}
}
}
else
#endif
{
if (setfragment) {
int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
@@ -857,7 +889,7 @@ static struct audio_option oss_options[] = {
.valp = &conf.exclusive,
.descr = "Open device in exclusive mode (vmix wont work)"
},
#ifdef SNDCTL_DSP_POLICY
#ifdef USE_DSP_POLICY
{
.name = "POLICY",
.tag = AUD_OPT_INT,

107
block.c
View File

@@ -452,6 +452,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
(flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
else
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
bs->open_flags = open_flags;
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
ret = -ENOTSUP;
else
@@ -779,6 +781,43 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
return count1;
}
/*
* Writes to the file and ensures that no writes are reordered across this
* request (acts as a barrier)
*
* Returns 0 on success, -errno in error cases.
*/
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
const void *buf, int count)
{
int ret;
ret = bdrv_pwrite(bs, offset, buf, count);
if (ret < 0) {
return ret;
}
/* No flush needed for cache=writethrough, it uses O_DSYNC */
if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
bdrv_flush(bs);
}
return 0;
}
/*
* Writes to the file and ensures that no writes are reordered across this
* request (acts as a barrier)
*
* Returns 0 on success, -errno in error cases.
*/
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
buf, BDRV_SECTOR_SIZE * nb_sectors);
}
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
@@ -1608,6 +1647,9 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
for (i = 0; i < mcb->num_callbacks; i++) {
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
if (mcb->callbacks[i].free_qiov) {
qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
}
qemu_free(mcb->callbacks[i].free_qiov);
qemu_vfree(mcb->callbacks[i].free_buf);
}
@@ -1617,23 +1659,32 @@ static void multiwrite_cb(void *opaque, int ret)
{
MultiwriteCB *mcb = opaque;
if (ret < 0) {
if (ret < 0 && !mcb->error) {
mcb->error = ret;
multiwrite_user_cb(mcb);
}
mcb->num_requests--;
if (mcb->num_requests == 0) {
if (mcb->error == 0) {
multiwrite_user_cb(mcb);
}
multiwrite_user_cb(mcb);
qemu_free(mcb);
}
}
static int multiwrite_req_compare(const void *a, const void *b)
{
return (((BlockRequest*) a)->sector - ((BlockRequest*) b)->sector);
const BlockRequest *req1 = a, *req2 = b;
/*
* Note that we can't simply subtract req2->sector from req1->sector
* here as that could overflow the return value.
*/
if (req1->sector > req2->sector) {
return 1;
} else if (req1->sector < req2->sector) {
return -1;
} else {
return 0;
}
}
/*
@@ -1669,6 +1720,10 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
}
if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
merge = 0;
}
if (merge) {
size_t size;
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
@@ -1692,7 +1747,7 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
// Add the second request
qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
reqs[outidx].nb_sectors += reqs[i].nb_sectors;
reqs[outidx].nb_sectors = qiov->size >> 9;
reqs[outidx].qiov = qiov;
mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
@@ -1744,8 +1799,29 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
// Check for mergable requests
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
// Run the aio requests
/*
* Run the aio requests. As soon as one request can't be submitted
* successfully, fail all requests that are not yet submitted (we must
* return failure for all requests anyway)
*
* num_requests cannot be set to the right value immediately: If
* bdrv_aio_writev fails for some request, num_requests would be too high
* and therefore multiwrite_cb() would never recognize the multiwrite
* request as completed. We also cannot use the loop variable i to set it
* when the first request fails because the callback may already have been
* called for previously submitted requests. Thus, num_requests must be
* incremented for each request that is submitted.
*
* The problem that callbacks may be called early also means that we need
* to take care that num_requests doesn't become 0 before all requests are
* submitted - multiwrite_cb() would consider the multiwrite request
* completed. A dummy request that is "completed" by a manual call to
* multiwrite_cb() takes care of this.
*/
mcb->num_requests = 1;
for (i = 0; i < num_reqs; i++) {
mcb->num_requests++;
acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
reqs[i].nb_sectors, multiwrite_cb, mcb);
@@ -1753,22 +1829,25 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
// We can only fail the whole thing if no request has been
// submitted yet. Otherwise we'll wait for the submitted AIOs to
// complete and report the error in the callback.
if (mcb->num_requests == 0) {
reqs[i].error = EIO;
if (i == 0) {
goto fail;
} else {
mcb->error = EIO;
multiwrite_cb(mcb, -EIO);
break;
}
} else {
mcb->num_requests++;
}
}
/* Complete the dummy request */
multiwrite_cb(mcb, 0);
return 0;
fail:
free(mcb);
for (i = 0; i < mcb->num_callbacks; i++) {
reqs[i].error = -EIO;
}
qemu_free(mcb);
return -1;
}

View File

@@ -77,6 +77,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count);
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);

View File

@@ -277,8 +277,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
&tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite_sync(s->hd,
s->l1_table_offset + l1_index * sizeof(tmp),
&tmp, sizeof(tmp)) < 0)
return 0;
new_l2_table = 1;
}
@@ -306,8 +307,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
l2_table = s->l2_cache + (min_index << s->l2_bits);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
s->l2_size * sizeof(uint64_t)) < 0)
return 0;
} else {
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
@@ -372,8 +373,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* update L2 table */
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
if (bdrv_pwrite(s->hd,
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp),
&tmp, sizeof(tmp)) < 0)
return 0;
}
return cluster_offset;
@@ -821,8 +822,9 @@ static int qcow_make_empty(BlockDriverState *bs)
int ret;
memset(s->l1_table, 0, l1_length);
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
return -1;
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, s->l1_table,
l1_length) < 0)
return -1;
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
if (ret < 0)
return ret;

View File

@@ -62,8 +62,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
for(i = 0; i < s->l1_size; i++)
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
if (ret != new_l1_size2)
ret = bdrv_pwrite_sync(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
if (ret < 0)
goto fail;
for(i = 0; i < s->l1_size; i++)
new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
@@ -71,8 +71,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
/* set new table */
cpu_to_be32w((uint32_t*)data, new_l1_size);
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
if (ret != sizeof(data)) {
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
if (ret < 0) {
goto fail;
}
qemu_free(s->l1_table);
@@ -84,7 +84,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
fail:
qemu_free(new_l1_table);
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
return ret < 0 ? ret : -EIO;
return ret;
}
void qcow2_l2_cache_reset(BlockDriverState *bs)
@@ -188,17 +188,17 @@ static int write_l1_entry(BDRVQcowState *s, int l1_index)
{
uint64_t buf[L1_ENTRIES_PER_SECTOR];
int l1_start_index;
int i;
int i, ret;
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
}
if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
buf, sizeof(buf)) != sizeof(buf))
{
return -1;
ret = bdrv_pwrite_sync(s->hd, s->l1_table_offset + 8 * l1_start_index,
buf, sizeof(buf));
if (ret < 0) {
return ret;
}
return 0;
@@ -221,6 +221,7 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
uint64_t old_l2_offset;
uint64_t *l2_table;
int64_t l2_offset;
int ret;
old_l2_offset = s->l1_table[l1_index];
@@ -231,13 +232,6 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
return NULL;
}
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
if (write_l1_entry(s, l1_index) < 0) {
return NULL;
}
/* allocate a new entry in the l2 cache */
min_index = l2_cache_new_entry(bs);
@@ -251,13 +245,20 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
if (bdrv_pread(s->hd, old_l2_offset,
l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return NULL;
goto fail;
}
/* write the l2 table to the file */
if (bdrv_pwrite(s->hd, l2_offset,
l2_table, s->l2_size * sizeof(uint64_t)) !=
s->l2_size * sizeof(uint64_t))
return NULL;
ret = bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
s->l2_size * sizeof(uint64_t));
if (ret < 0) {
goto fail;
}
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
if (write_l1_entry(s, l1_index) < 0) {
goto fail;
}
/* update the l2 cache entry */
@@ -265,6 +266,11 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
s->l2_cache_counts[min_index] = 1;
return l2_table;
fail:
s->l1_table[l1_index] = old_l2_offset;
qcow2_l2_cache_reset(bs);
return NULL;
}
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
@@ -380,8 +386,8 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
s->cluster_data, n, 1,
&s->aes_encrypt_key);
}
ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
s->cluster_data, n);
ret = bdrv_write_sync(s->hd, (cluster_offset >> 9) + n_start,
s->cluster_data, n);
if (ret < 0)
return ret;
return 0;
@@ -593,10 +599,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
/* compressed clusters never have the copied flag */
l2_table[l2_index] = cpu_to_be64(cluster_offset);
if (bdrv_pwrite(s->hd,
if (bdrv_pwrite_sync(s->hd,
l2_offset + l2_index * sizeof(uint64_t),
l2_table + l2_index,
sizeof(uint64_t)) != sizeof(uint64_t))
sizeof(uint64_t)) < 0)
return 0;
return cluster_offset;
@@ -614,11 +620,12 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
int start_offset = (8 * l2_index) & ~511;
int end_offset = (8 * (l2_index + num) + 511) & ~511;
size_t len = end_offset - start_offset;
int ret;
if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
len) != len)
{
return -1;
ret = bdrv_pwrite_sync(s->hd, l2_offset + start_offset,
&l2_table[l2_start_index], len);
if (ret < 0) {
return ret;
}
return 0;
@@ -672,8 +679,9 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
}
if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) {
ret = -1;
ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters);
if (ret < 0) {
qcow2_l2_cache_reset(bs);
goto err;
}
@@ -811,6 +819,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
if (cluster_offset < 0) {
QLIST_REMOVE(m, next_in_flight);
return cluster_offset;
}

View File

@@ -27,7 +27,7 @@
#include "block/qcow2.h"
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
static int update_refcount(BlockDriverState *bs,
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length,
int addend);
@@ -42,8 +42,8 @@ static int write_refcount_block(BDRVQcowState *s)
return 0;
}
if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
s->refcount_block_cache, size) != size)
if (bdrv_pwrite_sync(s->hd, s->refcount_block_cache_offset,
s->refcount_block_cache, size) < 0)
{
return -EIO;
}
@@ -123,124 +123,273 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
return be16_to_cpu(s->refcount_block_cache[block_index]);
}
static int grow_refcount_table(BlockDriverState *bs, int min_size)
/*
* Rounds the refcount table size up to avoid growing the table for each single
* refcount block that is allocated.
*/
static unsigned int next_refcount_table_size(BDRVQcowState *s,
unsigned int min_size)
{
BDRVQcowState *s = bs->opaque;
int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
uint64_t *new_table;
int64_t table_offset;
uint8_t data[12];
int old_table_size;
int64_t old_table_offset;
unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
unsigned int refcount_table_clusters =
MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
if (min_size <= s->refcount_table_size)
return 0;
/* compute new table size */
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
for(;;) {
if (refcount_table_clusters == 0) {
refcount_table_clusters = 1;
} else {
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
}
new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
if (min_size <= new_table_size)
break;
}
#ifdef DEBUG_ALLOC2
printf("grow_refcount_table from %d to %d\n",
s->refcount_table_size,
new_table_size);
#endif
new_table_size2 = new_table_size * sizeof(uint64_t);
new_table = qemu_mallocz(new_table_size2);
memcpy(new_table, s->refcount_table,
s->refcount_table_size * sizeof(uint64_t));
for(i = 0; i < s->refcount_table_size; i++)
cpu_to_be64s(&new_table[i]);
/* Note: we cannot update the refcount now to avoid recursion */
table_offset = alloc_clusters_noref(bs, new_table_size2);
ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
if (ret != new_table_size2)
goto fail;
for(i = 0; i < s->refcount_table_size; i++)
be64_to_cpus(&new_table[i]);
cpu_to_be64w((uint64_t*)data, table_offset);
cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
data, sizeof(data));
if (ret != sizeof(data)) {
goto fail;
while (min_clusters > refcount_table_clusters) {
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
}
qemu_free(s->refcount_table);
old_table_offset = s->refcount_table_offset;
old_table_size = s->refcount_table_size;
s->refcount_table = new_table;
s->refcount_table_size = new_table_size;
s->refcount_table_offset = table_offset;
update_refcount(bs, table_offset, new_table_size2, 1);
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
return 0;
fail:
qemu_free(new_table);
return ret < 0 ? ret : -EIO;
return refcount_table_clusters << (s->cluster_bits - 3);
}
/* Checks if two offsets are described by the same refcount block */
static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
uint64_t offset_b)
{
uint64_t block_a = offset_a >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
uint64_t block_b = offset_b >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
return (block_a == block_b);
}
/*
* Loads a refcount block. If it doesn't exist yet, it is allocated first
* (including growing the refcount table if needed).
*
* Returns the offset of the refcount block on success or -errno in error case
*/
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, refcount_block_offset;
unsigned int refcount_table_index;
int ret;
uint64_t data64;
int cache = cache_refcount_updates;
/* Find L1 index and grow refcount table if needed */
/* Find the refcount block for the given cluster */
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
if (refcount_table_index >= s->refcount_table_size) {
ret = grow_refcount_table(bs, refcount_table_index + 1);
if (ret < 0)
if (refcount_table_index < s->refcount_table_size) {
uint64_t refcount_block_offset =
s->refcount_table[refcount_table_index];
/* If it's already there, we're done */
if (refcount_block_offset) {
if (refcount_block_offset != s->refcount_block_cache_offset) {
ret = load_refcount_block(bs, refcount_block_offset);
if (ret < 0) {
return ret;
}
}
return refcount_block_offset;
}
}
/*
* If we came here, we need to allocate something. Something is at least
* a cluster for the new refcount block. It may also include a new refcount
* table if the old refcount table is too small.
*
* Note that allocating clusters here needs some special care:
*
* - We can't use the normal qcow2_alloc_clusters(), it would try to
* increase the refcount and very likely we would end up with an endless
* recursion. Instead we must place the refcount blocks in a way that
* they can describe them themselves.
*
* - We need to consider that at this point we are inside update_refcounts
* and doing the initial refcount increase. This means that some clusters
* have already been allocated by the caller, but their refcount isn't
* accurate yet. free_cluster_index tells us where this allocation ends
* as long as we don't overwrite it by freeing clusters.
*
* - alloc_clusters_noref and qcow2_free_clusters may load a different
* refcount block into the cache
*/
if (cache_refcount_updates) {
ret = write_refcount_block(s);
if (ret < 0) {
return ret;
}
}
/* Load or allocate the refcount block */
refcount_block_offset = s->refcount_table[refcount_table_index];
if (!refcount_block_offset) {
if (cache_refcount_updates) {
write_refcount_block(s);
cache_refcount_updates = 0;
}
/* create a new refcount block */
/* Note: we cannot update the refcount now to avoid recursion */
offset = alloc_clusters_noref(bs, s->cluster_size);
/* Allocate the refcount block itself and mark it as used */
uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
#ifdef DEBUG_ALLOC2
fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
" at %" PRIx64 "\n",
refcount_table_index, cluster_index << s->cluster_bits, new_block);
#endif
if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
/* Zero the new refcount block before updating it */
memset(s->refcount_block_cache, 0, s->cluster_size);
ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
if (ret != s->cluster_size)
return -EINVAL;
s->refcount_table[refcount_table_index] = offset;
data64 = cpu_to_be64(offset);
ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
refcount_table_index * sizeof(uint64_t),
&data64, sizeof(data64));
if (ret != sizeof(data64))
return -EINVAL;
s->refcount_block_cache_offset = new_block;
refcount_block_offset = offset;
s->refcount_block_cache_offset = offset;
update_refcount(bs, offset, s->cluster_size, 1);
cache_refcount_updates = cache;
/* The block describes itself, need to update the cache */
int block_index = (new_block >> s->cluster_bits) &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
s->refcount_block_cache[block_index] = cpu_to_be16(1);
} else {
if (refcount_block_offset != s->refcount_block_cache_offset) {
if (load_refcount_block(bs, refcount_block_offset) < 0)
return -EIO;
/* Described somewhere else. This can recurse at most twice before we
* arrive at a block that describes itself. */
ret = update_refcount(bs, new_block, s->cluster_size, 1);
if (ret < 0) {
goto fail_block;
}
/* Initialize the new refcount block only after updating its refcount,
* update_refcount uses the refcount cache itself */
memset(s->refcount_block_cache, 0, s->cluster_size);
s->refcount_block_cache_offset = new_block;
}
return refcount_block_offset;
/* Now the new refcount block needs to be written to disk */
ret = bdrv_pwrite_sync(s->hd, new_block, s->refcount_block_cache,
s->cluster_size);
if (ret < 0) {
goto fail_block;
}
/* If the refcount table is big enough, just hook the block up there */
if (refcount_table_index < s->refcount_table_size) {
uint64_t data64 = cpu_to_be64(new_block);
ret = bdrv_pwrite_sync(s->hd,
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
&data64, sizeof(data64));
if (ret < 0) {
goto fail_block;
}
s->refcount_table[refcount_table_index] = new_block;
return new_block;
}
/*
* If we come here, we need to grow the refcount table. Again, a new
* refcount table needs some space and we can't simply allocate to avoid
* endless recursion.
*
* Therefore let's grab new refcount blocks at the end of the image, which
* will describe themselves and the new refcount table. This way we can
* reference them only in the new table and do the switch to the new
* refcount table at once without producing an inconsistent state in
* between.
*/
/* Calculate the number of refcount blocks needed so far */
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
uint64_t blocks_used = (s->free_cluster_index +
refcount_block_clusters - 1) / refcount_block_clusters;
/* And now we need at least one block more for the new metadata */
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
uint64_t last_table_size;
uint64_t blocks_clusters;
do {
uint64_t table_clusters = size_to_clusters(s, table_size);
blocks_clusters = 1 +
((table_clusters + refcount_block_clusters - 1)
/ refcount_block_clusters);
uint64_t meta_clusters = table_clusters + blocks_clusters;
last_table_size = table_size;
table_size = next_refcount_table_size(s, blocks_used +
((meta_clusters + refcount_block_clusters - 1)
/ refcount_block_clusters));
} while (last_table_size != table_size);
#ifdef DEBUG_ALLOC2
fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
s->refcount_table_size, table_size);
#endif
/* Create the new refcount table and blocks */
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
s->cluster_size;
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size);
uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t));
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
/* Fill the new refcount table */
memcpy(new_table, s->refcount_table,
s->refcount_table_size * sizeof(uint64_t));
new_table[refcount_table_index] = new_block;
int i;
for (i = 0; i < blocks_clusters; i++) {
new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
}
/* Fill the refcount blocks */
uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
int block = 0;
for (i = 0; i < table_clusters + blocks_clusters; i++) {
new_blocks[block++] = cpu_to_be16(1);
}
/* Write refcount blocks to disk */
ret = bdrv_pwrite_sync(s->hd, meta_offset, new_blocks,
blocks_clusters * s->cluster_size);
qemu_free(new_blocks);
if (ret < 0) {
goto fail_table;
}
/* Write refcount table to disk */
for(i = 0; i < table_size; i++) {
cpu_to_be64s(&new_table[i]);
}
ret = bdrv_pwrite_sync(s->hd, table_offset, new_table,
table_size * sizeof(uint64_t));
if (ret < 0) {
goto fail_table;
}
for(i = 0; i < table_size; i++) {
cpu_to_be64s(&new_table[i]);
}
/* Hook up the new refcount table in the qcow2 header */
uint8_t data[12];
cpu_to_be64w((uint64_t*)data, table_offset);
cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, refcount_table_offset),
data, sizeof(data));
if (ret < 0) {
goto fail_table;
}
/* And switch it in memory */
uint64_t old_table_offset = s->refcount_table_offset;
uint64_t old_table_size = s->refcount_table_size;
qemu_free(s->refcount_table);
s->refcount_table = new_table;
s->refcount_table_size = table_size;
s->refcount_table_offset = table_offset;
/* Free old table. Remember, we must not change free_cluster_index */
uint64_t old_free_cluster_index = s->free_cluster_index;
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
s->free_cluster_index = old_free_cluster_index;
ret = load_refcount_block(bs, new_block);
if (ret < 0) {
goto fail_block;
}
return new_block;
fail_table:
qemu_free(new_table);
fail_block:
s->refcount_block_cache_offset = 0;
return ret;
}
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
@@ -248,21 +397,26 @@ static int write_refcount_block_entries(BDRVQcowState *s,
int64_t refcount_block_offset, int first_index, int last_index)
{
size_t size;
int ret;
if (cache_refcount_updates) {
return 0;
}
if (first_index < 0) {
return 0;
}
first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
last_index = (last_index + REFCOUNTS_PER_SECTOR)
& ~(REFCOUNTS_PER_SECTOR - 1);
size = (last_index - first_index) << REFCOUNT_SHIFT;
if (bdrv_pwrite(s->hd,
ret = bdrv_pwrite_sync(s->hd,
refcount_block_offset + (first_index << REFCOUNT_SHIFT),
&s->refcount_block_cache[first_index], size) != size)
{
return -EIO;
&s->refcount_block_cache[first_index], size);
if (ret < 0) {
return ret;
}
return 0;
@@ -478,7 +632,7 @@ void qcow2_free_clusters(BlockDriverState *bs,
ret = update_refcount(bs, offset, size, -1);
if (ret < 0) {
fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
abort();
/* TODO Remember the clusters to free them later and avoid leaking */
}
}
@@ -618,8 +772,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
}
}
if (l2_modified) {
if (bdrv_pwrite(s->hd,
l2_offset, l2_table, l2_size) != l2_size)
if (bdrv_pwrite_sync(s->hd,
l2_offset, l2_table, l2_size) < 0)
goto fail;
}
@@ -640,8 +794,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (l1_modified) {
for(i = 0; i < l1_size; i++)
cpu_to_be64s(&l1_table[i]);
if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
l1_size2) != l1_size2)
if (bdrv_pwrite_sync(s->hd, l1_table_offset, l1_table,
l1_size2) < 0)
goto fail;
for(i = 0; i < l1_size; i++)
be64_to_cpus(&l1_table[i]);

View File

@@ -158,25 +158,25 @@ static int qcow_write_snapshots(BlockDriverState *bs)
h.id_str_size = cpu_to_be16(id_str_size);
h.name_size = cpu_to_be16(name_size);
offset = align_offset(offset, 8);
if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0)
goto fail;
offset += sizeof(h);
if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0)
goto fail;
offset += id_str_size;
if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0)
goto fail;
offset += name_size;
}
/* update the various header fields */
data64 = cpu_to_be64(snapshots_offset);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
&data64, sizeof(data64)) != sizeof(data64))
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
&data64, sizeof(data64)) < 0)
goto fail;
data32 = cpu_to_be32(s->nb_snapshots);
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
&data32, sizeof(data32)) != sizeof(data32))
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
&data32, sizeof(data32)) < 0)
goto fail;
/* free the old snapshot table */
@@ -284,9 +284,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
for(i = 0; i < s->l1_size; i++) {
l1_table[i] = cpu_to_be64(s->l1_table[i]);
}
if (bdrv_pwrite(s->hd, sn->l1_table_offset,
l1_table, s->l1_size * sizeof(uint64_t)) !=
(s->l1_size * sizeof(uint64_t)))
if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
l1_table, s->l1_size * sizeof(uint64_t)) < 0)
goto fail;
qemu_free(l1_table);
l1_table = NULL;
@@ -335,8 +334,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
if (bdrv_pread(s->hd, sn->l1_table_offset,
s->l1_table, l1_size2) != l1_size2)
goto fail;
if (bdrv_pwrite(s->hd, s->l1_table_offset,
s->l1_table, l1_size2) != l1_size2)
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
s->l1_table, l1_size2) < 0)
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);

View File

@@ -467,8 +467,10 @@ static void qcow_aio_read_cb(void *opaque, int ret)
acb->hd_aiocb = bdrv_aio_readv(s->hd,
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto done;
}
}
return;
@@ -620,11 +622,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
(acb->cluster_offset >> 9) + index_in_cluster,
&acb->hd_qiov, acb->n,
qcow_aio_write_cb, acb);
if (acb->hd_aiocb == NULL)
goto done;
if (acb->hd_aiocb == NULL) {
ret = -EIO;
goto fail;
}
return;
fail:
if (acb->l2meta.nb_clusters != 0) {
QLIST_REMOVE(&acb->l2meta, next_in_flight);
}
done:
if (acb->qiov->niov > 1)
qemu_vfree(acb->orig_buf);
@@ -739,10 +747,11 @@ static int qcow_create2(const char *filename, int64_t total_size,
{
int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
int ref_clusters, backing_format_len = 0;
int ref_clusters, reftable_clusters, backing_format_len = 0;
int rounded_ext_bf_len = 0;
QCowHeader header;
uint64_t tmp, offset;
uint64_t old_ref_clusters;
QCowCreateState s1, *s = &s1;
QCowExtension ext_bf = {0, 0};
@@ -801,17 +810,37 @@ static int qcow_create2(const char *filename, int64_t total_size,
header.l1_size = cpu_to_be32(l1_size);
offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
s->refcount_table = qemu_mallocz(s->cluster_size);
/* count how many refcount blocks needed */
#define NUM_CLUSTERS(bytes) \
(((bytes) + (s->cluster_size) - 1) / (s->cluster_size))
ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t));
do {
uint64_t image_clusters;
old_ref_clusters = ref_clusters;
/* Number of clusters used for the refcount table */
reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t));
/* Number of clusters that the whole image will have */
image_clusters = NUM_CLUSTERS(offset) + ref_clusters
+ reftable_clusters;
/* Number of refcount blocks needed for the image */
ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t));
} while (ref_clusters != old_ref_clusters);
s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size);
s->refcount_table_offset = offset;
header.refcount_table_offset = cpu_to_be64(offset);
header.refcount_table_clusters = cpu_to_be32(1);
offset += s->cluster_size;
header.refcount_table_clusters = cpu_to_be32(reftable_clusters);
offset += (reftable_clusters * s->cluster_size);
s->refcount_block_offset = offset;
/* count how many refcount blocks needed */
tmp = offset >> s->cluster_bits;
ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
for (i=0; i < ref_clusters; i++) {
s->refcount_table[i] = cpu_to_be64(offset);
offset += s->cluster_size;
@@ -823,7 +852,8 @@ static int qcow_create2(const char *filename, int64_t total_size,
qcow2_create_refcount_update(s, 0, header_size);
qcow2_create_refcount_update(s, s->l1_table_offset,
l1_size * sizeof(uint64_t));
qcow2_create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
qcow2_create_refcount_update(s, s->refcount_table_offset,
reftable_clusters * s->cluster_size);
qcow2_create_refcount_update(s, s->refcount_block_offset,
ref_clusters * s->cluster_size);
@@ -851,7 +881,8 @@ static int qcow_create2(const char *filename, int64_t total_size,
write(fd, &tmp, sizeof(tmp));
}
lseek(fd, s->refcount_table_offset, SEEK_SET);
write(fd, s->refcount_table, s->cluster_size);
write(fd, s->refcount_table,
reftable_clusters * s->cluster_size);
lseek(fd, s->refcount_block_offset, SEEK_SET);
write(fd, s->refcount_block, ref_clusters * s->cluster_size);

View File

@@ -27,6 +27,8 @@
#include "qemu-log.h"
#include "block_int.h"
#include "module.h"
#include "compatfd.h"
#include <assert.h>
#include "block/raw-posix-aio.h"
#ifdef CONFIG_COCOA

View File

@@ -399,6 +399,15 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
vdi_header_print(&header);
#endif
if (header.disk_size % SECTOR_SIZE != 0) {
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
We accept them but round the disk size to the next multiple of
SECTOR_SIZE. */
logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
header.disk_size += SECTOR_SIZE - 1;
header.disk_size &= ~(SECTOR_SIZE - 1);
}
if (header.version != VDI_VERSION_1_1) {
logout("unsupported version %u.%u\n",
header.version >> 16, header.version & 0xffff);
@@ -417,9 +426,9 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
} else if (header.block_size != 1 * MiB) {
logout("unsupported block size %u B\n", header.block_size);
goto fail;
} else if (header.disk_size !=
} else if (header.disk_size >
(uint64_t)header.blocks_in_image * header.block_size) {
logout("unexpected block number %u B\n", header.blocks_in_image);
logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
goto fail;
} else if (!uuid_is_null(header.uuid_link)) {
logout("link uuid != 0, unsupported\n");
@@ -831,7 +840,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
return -errno;
}
blocks = bytes / block_size;
/* We need enough blocks to store the given disk size,
so always round up. */
blocks = (bytes + block_size - 1) / block_size;
bmap_size = blocks * sizeof(uint32_t);
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));

View File

@@ -87,14 +87,6 @@ typedef struct VmdkMetaData {
int valid;
} VmdkMetaData;
typedef struct ActiveBDRVState{
BlockDriverState *hd; // active image handler
uint64_t cluster_offset; // current write offset
}ActiveBDRVState;
static ActiveBDRVState activeBDRV;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
@@ -161,7 +153,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
pstrcat(desc, sizeof(desc), tmp_desc);
}
if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
if (bdrv_pwrite_sync(s->hd, 0x200, desc, DESC_SIZE) < 0)
return -1;
return 0;
}
@@ -285,7 +277,6 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
goto fail_rgd;
if (write(snp_fd, rgd_buf, gd_size) == -1)
goto fail_rgd;
qemu_free(rgd_buf);
/* write GD */
gd_buf = qemu_malloc(gd_size);
@@ -298,6 +289,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
if (write(snp_fd, gd_buf, gd_size) == -1)
goto fail_gd;
qemu_free(gd_buf);
qemu_free(rgd_buf);
close(p_fd);
close(snp_fd);
@@ -458,30 +450,28 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
uint64_t offset, int allocate)
{
uint64_t parent_cluster_offset;
BDRVVmdkState *s = bs->opaque;
uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
// we will be here if it's first write on non-exist grain(cluster).
// try to read from parent image, if exist
if (bs->backing_hd) {
BDRVVmdkState *ps = bs->backing_hd->opaque;
int ret;
if (!vmdk_is_cid_valid(bs))
return -1;
parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL,
offset, allocate);
ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
s->cluster_sectors);
if (ret < 0) {
return -1;
}
if (parent_cluster_offset) {
BDRVVmdkState *act_s = activeBDRV.hd->opaque;
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
return -1;
//Write grain only into the active image
if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
return -1;
//Write grain only into the active image
ret = bdrv_write(s->hd, cluster_offset, whole_grain,
s->cluster_sectors);
if (ret < 0) {
return -1;
}
}
return 0;
@@ -492,14 +482,14 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
BDRVVmdkState *s = bs->opaque;
/* update L2 table */
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) < 0)
return -1;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
&(m_data->offset), sizeof(m_data->offset)) < 0)
return -1;
}
@@ -567,9 +557,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
cluster_offset >>= 9;
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
// Save the active image state
activeBDRV.cluster_offset = cluster_offset;
activeBDRV.hd = bs;
}
/* First of all we write grain itself, to avoid race condition
* that may to corrupt the image.

View File

@@ -266,7 +266,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
bdrv_pwrite_sync(s->hd, bitmap_offset, bitmap, s->bitmap_size);
}
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
@@ -316,7 +316,7 @@ static int rewrite_footer(BlockDriverState* bs)
BDRVVPCState *s = bs->opaque;
int64_t offset = s->free_data_block_offset;
ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
ret = bdrv_pwrite_sync(s->hd, offset, s->footer_buf, HEADER_SIZE);
if (ret < 0)
return ret;
@@ -351,7 +351,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
// Initialize the block's bitmap
memset(bitmap, 0xff, s->bitmap_size);
bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
bdrv_pwrite_sync(s->hd, s->free_data_block_offset, bitmap,
s->bitmap_size);
// Write new footer (the old one will be overwritten)
s->free_data_block_offset += s->block_size + s->bitmap_size;
@@ -362,7 +363,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
// Write BAT entry to disk
bat_offset = s->bat_offset + (4 * index);
bat_value = be32_to_cpu(s->pagetable[index]);
ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
ret = bdrv_pwrite_sync(s->hd, bat_offset, &bat_value, 4);
if (ret < 0)
goto fail;
@@ -470,9 +471,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
}
}
// Note: Rounding up deviates from the Virtual PC behaviour
// However, we need this to avoid truncating images in qemu-img convert
*cyls = (cyls_times_heads + *heads - 1) / *heads;
*cyls = cyls_times_heads / *heads;
return 0;
}
@@ -484,9 +483,9 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
struct vhd_dyndisk_header* dyndisk_header =
(struct vhd_dyndisk_header*) buf;
int fd, i;
uint16_t cyls;
uint8_t heads;
uint8_t secs_per_cyl;
uint16_t cyls = 0;
uint8_t heads = 0;
uint8_t secs_per_cyl = 0;
size_t block_size, num_bat_entries;
int64_t total_sectors = 0;
@@ -503,9 +502,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
if (fd < 0)
return -EIO;
// Calculate matching total_size and geometry
if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
return -EFBIG;
/* Calculate matching total_size and geometry. Increase the number of
sectors requested until we get enough (or fail). */
for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
if (calculate_geometry(total_sectors + i,
&cyls, &heads, &secs_per_cyl)) {
return -EFBIG;
}
}
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
// Prepare the Hard Disk Footer

View File

@@ -868,7 +868,8 @@ static int init_directories(BDRVVVFATState* s,
{
direntry_t* entry=array_get_next(&(s->directory));
entry->attributes=0x28; /* archive | volume label */
snprintf((char*)entry->name,11,"QEMU VVFAT");
memcpy(entry->name,"QEMU VVF",8);
memcpy(entry->extension,"AT ",3);
}
/* Now build FAT, and write back information into directory */
@@ -2256,7 +2257,11 @@ static int commit_one_file(BDRVVVFATState* s,
c = c1;
}
ftruncate(fd, size);
if (ftruncate(fd, size)) {
perror("ftruncate()");
close(fd);
return -4;
}
close(fd);
return commit_mappings(s, first_cluster, dir_index);

View File

@@ -127,6 +127,7 @@ struct BlockDriverState {
int64_t total_sectors; /* if we are reading a disk image, give its
size in sectors */
int read_only; /* if true, the media is read only */
int open_flags; /* flags used to open the file, re-used for re-open */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */

View File

@@ -34,7 +34,28 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
asm volatile ("isync" : : : "memory");
}
/*
* Is this correct for PPC?
*/
static inline void dma_flush_range(unsigned long start, unsigned long stop)
{
}
#elif defined(__ia64__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
while (start < stop) {
asm volatile ("fc %0" :: "r"(start));
start += 32;
}
asm volatile (";;sync.i;;srlz.i;;");
}
#define dma_flush_range(start, end) flush_icache_range(start, end)
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
#else
static inline void dma_flush_range(unsigned long start, unsigned long stop)
{
}
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
#endif

13
compat/sys/eventfd.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef _COMPAT_SYS_EVENTFD
#define _COMPAT_SYS_EVENTFD
#include <unistd.h>
#include <syscall.h>
static inline int eventfd (int count, int flags)
{
return syscall(SYS_eventfd, count, flags);
}
#endif

143
compatfd.c Normal file
View File

@@ -0,0 +1,143 @@
/*
* signalfd/eventfd compatibility
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "compatfd.h"
#include <sys/syscall.h>
#include <pthread.h>
struct sigfd_compat_info
{
sigset_t mask;
int fd;
};
static void *sigwait_compat(void *opaque)
{
struct sigfd_compat_info *info = opaque;
int err;
sigset_t all;
sigfillset(&all);
sigprocmask(SIG_BLOCK, &all, NULL);
do {
siginfo_t siginfo;
err = sigwaitinfo(&info->mask, &siginfo);
if (err == -1 && errno == EINTR) {
err = 0;
continue;
}
if (err > 0) {
char buffer[128];
size_t offset = 0;
memcpy(buffer, &err, sizeof(err));
while (offset < sizeof(buffer)) {
ssize_t len;
len = write(info->fd, buffer + offset,
sizeof(buffer) - offset);
if (len == -1 && errno == EINTR)
continue;
if (len <= 0) {
err = -1;
break;
}
offset += len;
}
}
} while (err >= 0);
return NULL;
}
static int qemu_signalfd_compat(const sigset_t *mask)
{
pthread_attr_t attr;
pthread_t tid;
struct sigfd_compat_info *info;
int fds[2];
info = malloc(sizeof(*info));
if (info == NULL) {
errno = ENOMEM;
return -1;
}
if (pipe(fds) == -1) {
free(info);
return -1;
}
qemu_set_cloexec(fds[0]);
qemu_set_cloexec(fds[1]);
memcpy(&info->mask, mask, sizeof(*mask));
info->fd = fds[1];
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, sigwait_compat, info);
pthread_attr_destroy(&attr);
return fds[0];
}
int qemu_signalfd(const sigset_t *mask)
{
#if defined(CONFIG_SIGNALFD)
int ret;
ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
if (ret != -1) {
qemu_set_cloexec(ret);
return ret;
}
#endif
return qemu_signalfd_compat(mask);
}
int qemu_eventfd(int *fds)
{
int ret;
#if defined(CONFIG_EVENTFD)
ret = syscall(SYS_eventfd, 0);
if (ret >= 0) {
fds[0] = ret;
qemu_set_cloexec(ret);
if ((fds[1] = dup(ret)) == -1) {
close(ret);
return -1;
}
qemu_set_cloexec(fds[1]);
return 0;
}
#endif
ret = pipe(fds);
if (ret != -1) {
qemu_set_cloexec(fds[0]);
qemu_set_cloexec(fds[1]);
}
return ret;
}

45
compatfd.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* signalfd/eventfd compatibility
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_COMPATFD_H
#define QEMU_COMPATFD_H
#include <signal.h>
struct qemu_signalfd_siginfo {
uint32_t ssi_signo; /* Signal number */
int32_t ssi_errno; /* Error number (unused) */
int32_t ssi_code; /* Signal code */
uint32_t ssi_pid; /* PID of sender */
uint32_t ssi_uid; /* Real UID of sender */
int32_t ssi_fd; /* File descriptor (SIGIO) */
uint32_t ssi_tid; /* Kernel timer ID (POSIX timers) */
uint32_t ssi_band; /* Band event (SIGIO) */
uint32_t ssi_overrun; /* POSIX timer overrun count */
uint32_t ssi_trapno; /* Trap number that caused signal */
int32_t ssi_status; /* Exit status or signal (SIGCHLD) */
int32_t ssi_int; /* Integer sent by sigqueue(2) */
uint64_t ssi_ptr; /* Pointer sent by sigqueue(2) */
uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */
uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */
uint64_t ssi_addr; /* Address that generated signal
(for hardware-generated signals) */
uint8_t pad[48]; /* Pad size to 128 bytes (allow for
additional fields in the future) */
};
int qemu_signalfd(const sigset_t *mask);
int qemu_eventfd(int *fds);
#endif

183
configure vendored
View File

@@ -160,7 +160,7 @@ else
cpu=`uname -m`
fi
target_list=""
target_list="x86_64-softmmu"
case "$cpu" in
alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
cpu="$cpu"
@@ -197,6 +197,16 @@ case "$cpu" in
;;
esac
kvm_version() {
local fname="$(dirname "$0")/KVM_VERSION"
if test -f "$fname"; then
cat "$fname"
else
echo "qemu-kvm-devel"
fi
}
# Default value for a variable defining feature "foo".
# * foo="no" feature will only be used if --enable-foo arg is given
# * foo="" feature will be searched for, and if found, will be used
@@ -250,10 +260,15 @@ guest_base=""
uname_release=""
io_thread="no"
mixemu="no"
kvm_trace="no"
kvm_cap_pit=""
kvm_cap_device_assignment=""
kerneldir=""
aix="no"
blobs="yes"
pkgversion=""
pkgversion=" ($(kvm_version))"
cpu_emulation="yes"
kvm_kmod="no"
check_utests="no"
user_pie="no"
zero_malloc=""
@@ -389,6 +404,13 @@ AIX)
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod"
fi
if [ "$cpu" = "ia64" ] ; then
xen="no"
target_list="ia64-softmmu"
cpu_emulation="no"
gdbstub="no"
slirp="no"
fi
;;
esac
@@ -518,6 +540,14 @@ for opt do
;;
--enable-kvm) kvm="yes"
;;
--disable-kvm-cap-pit) kvm_cap_pit="no"
;;
--enable-kvm-cap-pit) kvm_cap_pit="yes"
;;
--disable-kvm-cap-device-assignment) kvm_cap_device_assignment="no"
;;
--enable-kvm-cap-device-assignment) kvm_cap_device_assignment="yes"
;;
--enable-profiler) profiler="yes"
;;
--enable-cocoa)
@@ -595,12 +625,16 @@ for opt do
;;
--kerneldir=*) kerneldir="$optarg"
;;
--with-kvm-trace) kvm_trace="yes"
;;
--with-pkgversion=*) pkgversion=" ($optarg)"
;;
--disable-docs) docs="no"
;;
--enable-docs) docs="yes"
;;
--disable-cpu-emulation) cpu_emulation="no"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -722,6 +756,10 @@ echo " --disable-bluez disable bluez stack connectivity"
echo " --enable-bluez enable bluez stack connectivity"
echo " --disable-kvm disable KVM acceleration support"
echo " --enable-kvm enable KVM acceleration support"
echo " --disable-cap-kvm-pit disable KVM pit support"
echo " --enable-cap-kvm-pit enable KVM pit support"
echo " --disable-cap-device-assignment disable KVM device assignment support"
echo " --enable-cap-device-assignment enable KVM device assignment support"
echo " --disable-nptl disable usermode NPTL support"
echo " --enable-nptl enable usermode NPTL support"
echo " --enable-system enable all system emulation targets"
@@ -753,6 +791,8 @@ echo " --enable-linux-aio enable Linux AIO support"
echo " --enable-io-thread enable IO thread"
echo " --disable-blobs disable installing provided firmware blobs"
echo " --kerneldir=PATH look for kernel includes in PATH"
echo " --with-kvm-trace enable building the KVM module with the kvm trace option"
echo " --disable-cpu-emulation disables use of qemu cpu emulation code"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -1384,8 +1424,22 @@ EOF
kvm_cflags="$kvm_cflags -I$kerneldir/arch/$cpu/include"
fi
else
kvm_cflags=""
case "$cpu" in
i386 | x86_64)
kvm_arch="x86"
;;
ppc)
kvm_arch="powerpc"
;;
*)
kvm_arch="$cpu"
;;
esac
kvm_cflags="-I$source_path/kvm/include"
kvm_cflags="$kvm_cflags -include $source_path/kvm/include/linux/config.h"
kvm_cflags="$kvm_cflags -I$source_path/kvm/include/$kvm_arch"
fi
kvm_cflags="$kvm_cflags -idirafter $source_path/compat"
if compile_prog "$kvm_cflags" "" ; then
kvm=yes
else
@@ -1407,6 +1461,75 @@ EOF
fi
fi
##########################################
# test for KVM_CAP_PIT
if test "$kvm_cap_pit" != "no" ; then
if test "$kvm" = "no" -a "$kvm_cap_pit" = "yes" ; then
feature_not_found "kvm_cap_pit (kvm is not enabled)"
fi
cat > $TMPC <<EOF
#include <linux/kvm.h>
#ifndef KVM_CAP_PIT
#error "kvm no pit capability"
#endif
int main(void) { return 0; }
EOF
if compile_prog "$kvm_cflags" ""; then
kvm_cap_pit=yes
else
if test "$kvm_cap_pit" = "yes" ; then
feature_not_found "kvm_cap_pit"
fi
kvm_cap_pit=no
fi
fi
##########################################
# test for KVM_CAP_DEVICE_ASSIGNMENT
if test "$kvm_cap_device_assignment" != "no" ; then
if test "$kvm" = "no" -a "$kvm_cap_device_assignment" = "yes" ; then
feature_not_found "kvm_cap_device_assignment (kvm is not enabled)"
fi
cat > $TMPC <<EOF
#include <linux/kvm.h>
#ifndef KVM_CAP_DEVICE_ASSIGNMENT
#error "kvm no device assignment capability"
#endif
int main(void) { return 0; }
EOF
if compile_prog "$kvm_cflags" "" ; then
kvm_cap_device_assignment=yes
else
if test "$kvm_cap_device_assignment" = "yes" ; then
feature_not_found "kvm_cap_device_assigment"
fi
kvm_cap_device_assignment=no
fi
fi
##########################################
# libpci probe for kvm_cap_device_assignment
if test $kvm_cap_device_assignment = "yes" ; then
cat > $TMPC << EOF
#include <pci/pci.h>
#ifndef PCI_VENDOR_ID
#error NO LIBPCI
#endif
int main(void) { struct pci_access a; pci_init(&a); return 0; }
EOF
if compile_prog "" "-lpci -lz" ; then
libs_softmmu="-lpci -lz $libs_softmmu"
else
echo
echo "Error: libpci check failed"
echo "Disable KVM Device Assignment capability."
echo
kvm_cap_device_assignment=no
fi
fi
##########################################
# pthread probe
PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
@@ -1613,6 +1736,21 @@ if compile_prog "" "" ; then
splice=yes
fi
##########################################
# signalfd probe
signalfd="no"
cat > $TMPC << EOF
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
EOF
if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
signalfd=yes
fi
# check if eventfd is supported
eventfd=no
cat > $TMPC << EOF
@@ -1842,6 +1980,20 @@ else
binsuffix="/bin"
fi
if test -f kvm/kernel/configure; then
kvm_kmod="yes"
kmod_args=""
if test -n "$kerneldir"; then
kmod_args="--kerneldir=$kerneldir"
fi
if test "$kvm_trace" = "yes"; then
kmod_args="$kmod_args --with-kvm-trace"
fi
# hope there are no spaces in kmod_args; can't use arrays because of
# dash.
(cd kvm/kernel; ./configure $kmod_args)
fi
echo "Install prefix $prefix"
echo "BIOS directory $prefix$datasuffix"
echo "binary directory $prefix$binsuffix"
@@ -1885,6 +2037,7 @@ if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
echo "xen support $xen"
echo "CPU emulation $cpu_emulation"
echo "brlapi support $brlapi"
echo "bluez support $bluez"
echo "Documentation $docs"
@@ -1898,6 +2051,9 @@ echo "IO thread $io_thread"
echo "Linux AIO support $linux_aio"
echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "KVM PIT support $kvm_cap_pit"
echo "KVM device assig. $kvm_cap_device_assignment"
echo "KVM trace support $kvm_trace"
echo "fdt support $fdt"
echo "preadv support $preadv"
echo "fdatasync $fdatasync"
@@ -2104,6 +2260,9 @@ fi
if test "$fdt" = "yes" ; then
echo "CONFIG_FDT=y" >> $config_host_mak
fi
if test "$signalfd" = "yes" ; then
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
fi
if test "$need_offsetof" = "yes" ; then
echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
fi
@@ -2113,6 +2272,11 @@ fi
if test "$fdatasync" = "yes" ; then
echo "CONFIG_FDATASYNC=y" >> $config_host_mak
fi
if test $cpu_emulation = "yes"; then
echo "CONFIG_CPU_EMULATION=y" >> $config_host_mak
else
echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak
fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
@@ -2138,6 +2302,8 @@ bsd)
;;
esac
echo "KVM_KMOD=$kvm_kmod" >> $config_host_mak
tools=
if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
@@ -2288,6 +2454,9 @@ case "$target_arch2" in
TARGET_BASE_ARCH=i386
target_phys_bits=64
;;
ia64)
target_phys_bits=64
;;
alpha)
target_phys_bits=64
;;
@@ -2418,6 +2587,12 @@ case "$target_arch2" in
\( "$target_arch2" = "i386" -a "$cpu" = "x86_64" \) \) ; then
echo "CONFIG_KVM=y" >> $config_target_mak
echo "KVM_CFLAGS=$kvm_cflags" >> $config_target_mak
if test $kvm_cap_pit = "yes" ; then
echo "CONFIG_KVM_PIT=y" >> $config_target_mak
fi
if test $kvm_cap_device_assignment = "yes" ; then
echo "CONFIG_KVM_DEVICE_ASSIGNMENT=y" >> $config_target_mak
fi
fi
esac
echo "TARGET_PHYS_ADDR_BITS=$target_phys_bits" >> $config_target_mak
@@ -2626,7 +2801,7 @@ if test "$source_path_used" = "yes" ; then
fi
# temporary config to build submodules
for rom in seabios vgabios ; do
for rom in seabios vgabios; do
config_mak=roms/$rom/config.mak
echo "# Automatically generated by configure - do not modify" >> $config_mak
echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak

View File

@@ -849,6 +849,7 @@ extern int phys_ram_fd;
extern uint8_t *phys_ram_dirty;
extern ram_addr_t ram_size;
extern ram_addr_t last_ram_offset;
extern uint8_t *bios_mem;
/* physical memory access */

View File

@@ -34,6 +34,7 @@ void qemu_ram_free(ram_addr_t addr);
/* This should only be used for ram local to a device. */
void *qemu_get_ram_ptr(ram_addr_t addr);
/* This should not be used by devices. */
int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
ram_addr_t qemu_ram_addr_from_host(void *ptr);
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,

View File

@@ -27,6 +27,7 @@
#include <setjmp.h>
#include <inttypes.h>
#include <signal.h>
#include <pthread.h>
#include "osdep.h"
#include "qemu-queue.h"
#include "targphys.h"
@@ -134,6 +135,16 @@ typedef struct CPUWatchpoint {
QTAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint;
/* forward decleration */
struct qemu_work_item;
struct KVMCPUState {
pthread_t thread;
int signalled;
struct qemu_work_item *queued_work_first, *queued_work_last;
int regs_modified;
};
#define CPU_TEMP_BUF_NLONGS 128
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
@@ -146,8 +157,6 @@ typedef struct CPUWatchpoint {
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
uint32_t stop; /* Stop request */ \
uint32_t stopped; /* Artificially stopped */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
/* The meaning of the MMU modes is defined in the target code. */ \
@@ -188,6 +197,7 @@ typedef struct CPUWatchpoint {
int nr_cores; /* number of cores within this CPU package */ \
int nr_threads;/* number of threads within this CPU */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
int thread_id; \
/* user data */ \
void *opaque; \
\
@@ -197,6 +207,9 @@ typedef struct CPUWatchpoint {
const char *cpu_model_str; \
struct KVMState *kvm_state; \
struct kvm_run *kvm_run; \
int kvm_fd;
int kvm_fd; \
uint32_t stop; /* Stop request */ \
uint32_t stopped; /* Artificially stopped */ \
struct KVMCPUState kvm_cpu_state;
#endif

View File

@@ -19,7 +19,9 @@
#include "config.h"
#include "exec.h"
#include "disas.h"
#if !defined(TARGET_IA64)
#include "tcg.h"
#endif
#include "kvm.h"
#if !defined(CONFIG_SOFTMMU)
@@ -38,6 +40,8 @@
#endif
#endif
#include "qemu-kvm.h"
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
// Work around ugly bugs in glibc that mangle global register contents
#undef env
@@ -252,6 +256,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X)
#elif defined(TARGET_IA64)
/* XXXXX */
#else
#error unsupported target CPU
@@ -319,6 +324,8 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
#elif defined(TARGET_M68K)
do_interrupt(0);
#elif defined(TARGET_IA64)
do_interrupt(env);
#endif
#endif
}
@@ -674,6 +681,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
#elif defined(TARGET_IA64)
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X)

View File

@@ -218,6 +218,11 @@ void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
}
}
/*
* No dma flushing needed here, as the aio code will call dma_bdrv_cb()
* on completion as well, which will result in a call to
* dma_bdrv_unmap() which will do the flushing ....
*/
void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
{
const uint8_t *p = (const uint8_t *)buf;

View File

@@ -2,3 +2,4 @@
CONFIG_USB_OHCI=y
CONFIG_PTIMER=y
CONFIG_ISA_MMIO=y

View File

@@ -2,3 +2,4 @@
CONFIG_USB_OHCI=y
CONFIG_PTIMER=y
CONFIG_ISA_MMIO=y

View File

@@ -160,6 +160,10 @@ static BlockDriverAIOCB *dma_bdrv_io(
dbs->is_write = is_write;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
/*
* DMA flushing is handled in dma_bdrv_cb() calling dma_bdrv_unmap()
* so we don't need to do that here.
*/
dma_bdrv_cb(dbs, 0);
if (!dbs->acb) {
qemu_aio_release(dbs);

View File

@@ -69,9 +69,9 @@ extern int printf(const char *, ...);
#define AREG1 "r14"
#define AREG2 "r15"
#elif defined(__mips__)
#define AREG0 "fp"
#define AREG1 "s0"
#define AREG2 "s1"
#define AREG0 "s0"
#define AREG1 "s1"
#define AREG2 "fp"
#elif defined(__sparc__)
#ifdef CONFIG_SOLARIS
#define AREG0 "g2"

172
exec.c
View File

@@ -34,7 +34,13 @@
#include "cpu.h"
#include "exec-all.h"
#include "qemu-common.h"
#include "cache-utils.h"
#if !defined(TARGET_IA64)
#include "tcg.h"
#endif
#include "qemu-kvm.h"
#include "hw/hw.h"
#include "osdep.h"
#include "kvm.h"
@@ -74,6 +80,8 @@
#define TARGET_PHYS_ADDR_SPACE_BITS 42
#elif defined(TARGET_I386)
#define TARGET_PHYS_ADDR_SPACE_BITS 36
#elif defined(TARGET_IA64)
#define TARGET_PHYS_ADDR_SPACE_BITS 36
#else
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#endif
@@ -111,6 +119,7 @@ uint8_t *code_gen_ptr;
#if !defined(CONFIG_USER_ONLY)
int phys_ram_fd;
uint8_t *phys_ram_dirty;
uint8_t *bios_mem;
static int in_migration;
typedef struct RAMBlock {
@@ -412,6 +421,9 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
static void code_gen_alloc(unsigned long tb_size)
{
if (kvm_enabled())
return;
#ifdef USE_STATIC_CODE_GEN_BUFFER
code_gen_buffer = static_code_gen_buffer;
code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
@@ -588,6 +600,11 @@ void cpu_exec_init(CPUState *env)
env->numa_node = 0;
QTAILQ_INIT(&env->breakpoints);
QTAILQ_INIT(&env->watchpoints);
#ifdef __WIN32
env->thread_id = GetCurrentProcessId();
#else
env->thread_id = getpid();
#endif
*penv = env;
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
@@ -1553,6 +1570,8 @@ void cpu_interrupt(CPUState *env, int mask)
old_mask = env->interrupt_request;
env->interrupt_request |= mask;
if (kvm_enabled() && !kvm_irqchip_in_kernel())
kvm_update_interrupt_request(env);
#ifndef CONFIG_USER_ONLY
/*
@@ -1880,7 +1899,6 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
int cpu_physical_memory_set_dirty_tracking(int enable)
{
in_migration = enable;
if (kvm_enabled()) {
return kvm_set_migration_log(enable);
}
@@ -2404,6 +2422,113 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
kvm_uncoalesce_mmio_region(addr, size);
}
#ifdef __linux__
#include <sys/vfs.h>
#define HUGETLBFS_MAGIC 0x958458f6
static long gethugepagesize(const char *path)
{
struct statfs fs;
int ret;
do {
ret = statfs(path, &fs);
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
perror("statfs");
return 0;
}
if (fs.f_type != HUGETLBFS_MAGIC)
fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
return fs.f_bsize;
}
static void *file_ram_alloc(ram_addr_t memory, const char *path)
{
char *filename;
void *area;
int fd;
#ifdef MAP_POPULATE
int flags;
#endif
unsigned long hpagesize;
extern int mem_prealloc;
if (!path) {
return NULL;
}
hpagesize = gethugepagesize(path);
if (!hpagesize) {
return NULL;
}
if (memory < hpagesize) {
return NULL;
}
if (kvm_enabled() && !kvm_has_sync_mmu()) {
fprintf(stderr, "host lacks mmu notifiers, disabling --mem-path\n");
return NULL;
}
if (asprintf(&filename, "%s/kvm.XXXXXX", path) == -1) {
return NULL;
}
fd = mkstemp(filename);
if (fd < 0) {
perror("mkstemp");
free(filename);
return NULL;
}
unlink(filename);
free(filename);
memory = (memory+hpagesize-1) & ~(hpagesize-1);
/*
* ftruncate is not supported by hugetlbfs in older
* hosts, so don't bother checking for errors.
* If anything goes wrong with it under other filesystems,
* mmap will fail.
*/
ftruncate(fd, memory);
#ifdef MAP_POPULATE
/* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case
* MAP_PRIVATE is requested. For mem_prealloc we mmap as MAP_SHARED
* to sidestep this quirk.
*/
flags = mem_prealloc ? MAP_POPULATE|MAP_SHARED : MAP_PRIVATE;
area = mmap(0, memory, PROT_READ|PROT_WRITE, flags, fd, 0);
#else
area = mmap(0, memory, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
#endif
if (area == MAP_FAILED) {
perror("alloc_mem_area: can't mmap hugetlbfs pages");
close(fd);
return (NULL);
}
return area;
}
#else
static void *file_ram_alloc(ram_addr_t memory, const char *path)
{
return NULL;
}
#endif
extern const char *mem_path;
ram_addr_t qemu_ram_alloc(ram_addr_t size)
{
RAMBlock *new_block;
@@ -2411,16 +2536,20 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
size = TARGET_PAGE_ALIGN(size);
new_block = qemu_malloc(sizeof(*new_block));
new_block->host = file_ram_alloc(size, mem_path);
if (!new_block->host) {
#if defined(TARGET_S390X) && defined(CONFIG_KVM)
/* XXX S390 KVM requires the topmost vma of the RAM to be < 256GB */
new_block->host = mmap((void*)0x1000000, size, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
new_block->host = mmap((void*)0x1000000, size,
PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#else
new_block->host = qemu_vmalloc(size);
new_block->host = qemu_vmalloc(size);
#endif
#ifdef MADV_MERGEABLE
madvise(new_block->host, size, MADV_MERGEABLE);
madvise(new_block->host, size, MADV_MERGEABLE);
#endif
}
new_block->offset = last_ram_offset;
new_block->length = size;
@@ -2482,9 +2611,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
return block->host + (addr - block->offset);
}
/* Some of the softmmu routines need to translate from a host pointer
(typically a TLB entry) back to a ram offset. */
ram_addr_t qemu_ram_addr_from_host(void *ptr)
int do_qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
{
RAMBlock *prev;
RAMBlock **prevp;
@@ -2501,11 +2628,23 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr)
prev = block;
block = block->next;
}
if (!block) {
if (!block)
return -1;
*ram_addr = block->offset + (host - block->host);
return 0;
}
/* Some of the softmmu routines need to translate from a host pointer
(typically a TLB entry) back to a ram offset. */
ram_addr_t qemu_ram_addr_from_host(void *ptr)
{
ram_addr_t ram_addr;
if (do_qemu_ram_addr_from_host(ptr, &ram_addr)) {
fprintf(stderr, "Bad ram pointer %p\n", ptr);
abort();
}
return block->offset + (host - block->host);
return ram_addr;
}
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -3091,6 +3230,11 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
(0xff & ~CODE_DIRTY_FLAG);
}
/* qemu doesn't execute guest code directly, but kvm does
therefore flush instruction caches */
if (kvm_enabled())
flush_icache_range((unsigned long)ptr,
((unsigned long)ptr)+l);
}
} else {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -3283,6 +3427,8 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
int is_write, target_phys_addr_t access_len)
{
unsigned long flush_len = (unsigned long)access_len;
if (buffer != bounce.buffer) {
if (is_write) {
ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
@@ -3300,7 +3446,9 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
}
addr1 += l;
access_len -= l;
}
}
dma_flush_range((unsigned long)buffer,
(unsigned long)buffer + flush_len);
}
return;
}
@@ -3668,7 +3816,9 @@ void dump_exec_info(FILE *f,
cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
#ifdef CONFIG_PROFILER
tcg_dump_info(f, cpu_fprintf);
#endif
}
#if !defined(CONFIG_USER_ONLY)

View File

@@ -5,6 +5,7 @@
#if defined(CONFIG_SOLARIS)
#include <fenv.h>
#endif
#include "config-host.h"
void set_float_rounding_mode(int val STATUS_PARAM)
{

View File

@@ -34,6 +34,7 @@
#include "sysemu.h"
#include "gdbstub.h"
#endif
#include "qemu-kvm.h"
#define MAX_PACKET_LENGTH 4096

View File

@@ -23,6 +23,8 @@
#include "i2c.h"
#include "smbus.h"
#include "kvm.h"
#include "qemu-kvm.h"
#include "string.h"
//#define DEBUG
@@ -521,6 +523,13 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
pci_conf[0x40] = 0x01; /* PM io base read only bit */
#if defined(TARGET_IA64)
pci_conf[0x40] = 0x41; /* PM io base read only bit */
pci_conf[0x41] = 0x1f;
pm_write_config(s, 0x80, 0x01, 1); /*Set default pm_io_base 0x1f40*/
s->pmcntrl = SCI_EN;
#endif
register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
@@ -559,12 +568,14 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
}
#define GPE_BASE 0xafe0
#define PROC_BASE 0xaf00
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
struct gpe_regs {
uint16_t sts; /* status */
uint16_t en; /* enabled */
uint8_t cpus_sts[32];
};
struct pci_status {
@@ -587,6 +598,10 @@ static uint32_t gpe_readb(void *opaque, uint32_t addr)
uint32_t val = 0;
struct gpe_regs *g = opaque;
switch (addr) {
case PROC_BASE ... PROC_BASE+31:
val = g->cpus_sts[addr - PROC_BASE];
break;
case GPE_BASE:
case GPE_BASE + 1:
val = gpe_read_val(g->sts, addr);
@@ -629,6 +644,10 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
{
struct gpe_regs *g = opaque;
switch (addr) {
case PROC_BASE ... PROC_BASE + 31:
/* don't allow to change cpus_sts from inside a guest */
break;
case GPE_BASE:
case GPE_BASE + 1:
gpe_reset_val(&g->sts, addr, val);
@@ -712,22 +731,72 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
#endif
}
static const char *model;
static int piix4_device_hotplug(PCIDevice *dev, int state);
void piix4_acpi_system_hot_add_init(PCIBus *bus)
void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *cpu_model)
{
int i = 0, cpus = smp_cpus;
while (cpus > 0) {
gpe.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
cpus -= 8;
}
register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe);
register_ioport_read(GPE_BASE, 4, 1, gpe_readb, &gpe);
register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, &gpe);
register_ioport_read(PROC_BASE, 32, 1, gpe_readb, &gpe);
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, &pci0_status);
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
model = cpu_model;
pci_bus_hotplug(bus, piix4_device_hotplug);
}
#if defined(TARGET_I386)
static void enable_processor(struct gpe_regs *g, int cpu)
{
g->sts |= 4;
g->cpus_sts[cpu/8] |= (1 << (cpu%8));
}
static void disable_processor(struct gpe_regs *g, int cpu)
{
g->sts |= 4;
g->cpus_sts[cpu/8] &= ~(1 << (cpu%8));
}
void qemu_system_cpu_hot_add(int cpu, int state)
{
CPUState *env;
if (state && !qemu_get_cpu(cpu)) {
env = pc_new_cpu(model);
if (!env) {
fprintf(stderr, "cpu %d creation failed\n", cpu);
return;
}
env->cpuid_apic_id = cpu;
}
if (state)
enable_processor(&gpe, cpu);
else
disable_processor(&gpe, cpu);
if (gpe.en & 4) {
qemu_set_irq(pm_state->irq, 1);
qemu_set_irq(pm_state->irq, 0);
}
}
#endif
static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot)
{
g->sts |= 2;

144
hw/apic.c
View File

@@ -24,6 +24,8 @@
#include "host-utils.h"
#include "kvm.h"
#include "qemu-kvm.h"
//#define DEBUG_APIC
/* APIC Local Vector Table */
@@ -299,8 +301,11 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
#endif
if (!s)
return;
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
if (kvm_enabled() && kvm_irqchip_in_kernel())
s->apicbase = val;
else
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
if (!(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
@@ -393,6 +398,11 @@ int apic_get_irq_delivered(void)
return apic_irq_delivered;
}
void apic_set_irq_delivered(void)
{
apic_irq_delivered = 1;
}
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{
apic_irq_delivered += !get_bit(s->irr, vector_num);
@@ -478,6 +488,7 @@ void apic_init_reset(CPUState *env)
if (!s)
return;
cpu_synchronize_state(env);
s->tpr = 0;
s->spurious_vec = 0xff;
s->log_dest = 0;
@@ -497,6 +508,13 @@ void apic_init_reset(CPUState *env)
s->wait_for_sipi = 1;
env->halted = !(s->apicbase & MSR_IA32_APICBASE_BSP);
#ifdef KVM_CAP_MP_STATE
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
env->mp_state
= env->halted ? KVM_MP_STATE_UNINITIALIZED : KVM_MP_STATE_RUNNABLE;
kvm_load_mpstate(env);
}
#endif
}
static void apic_startup(APICState *s, int vector_num)
@@ -864,6 +882,115 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
#ifdef KVM_CAP_IRQCHIP
static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id)
{
return *((uint32_t *) (kapic->regs + (reg_id << 4)));
}
static inline void kapic_set_reg(struct kvm_lapic_state *kapic,
int reg_id, uint32_t val)
{
*((uint32_t *) (kapic->regs + (reg_id << 4))) = val;
}
static void kvm_kernel_lapic_save_to_user(APICState *s)
{
struct kvm_lapic_state apic;
struct kvm_lapic_state *kapic = &apic;
int i, v;
kvm_get_lapic(s->cpu_env, kapic);
s->id = kapic_reg(kapic, 0x2) >> 24;
s->tpr = kapic_reg(kapic, 0x8);
s->arb_id = kapic_reg(kapic, 0x9);
s->log_dest = kapic_reg(kapic, 0xd) >> 24;
s->dest_mode = kapic_reg(kapic, 0xe) >> 28;
s->spurious_vec = kapic_reg(kapic, 0xf);
for (i = 0; i < 8; i++) {
s->isr[i] = kapic_reg(kapic, 0x10 + i);
s->tmr[i] = kapic_reg(kapic, 0x18 + i);
s->irr[i] = kapic_reg(kapic, 0x20 + i);
}
s->esr = kapic_reg(kapic, 0x28);
s->icr[0] = kapic_reg(kapic, 0x30);
s->icr[1] = kapic_reg(kapic, 0x31);
for (i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = kapic_reg(kapic, 0x32 + i);
s->initial_count = kapic_reg(kapic, 0x38);
s->divide_conf = kapic_reg(kapic, 0x3e);
v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
s->count_shift = (v + 1) & 7;
s->initial_count_load_time = qemu_get_clock(vm_clock);
apic_timer_update(s, s->initial_count_load_time);
}
static void kvm_kernel_lapic_load_from_user(APICState *s)
{
struct kvm_lapic_state apic;
struct kvm_lapic_state *klapic = &apic;
int i;
memset(klapic, 0, sizeof apic);
kapic_set_reg(klapic, 0x2, s->id << 24);
kapic_set_reg(klapic, 0x8, s->tpr);
kapic_set_reg(klapic, 0xd, s->log_dest << 24);
kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
kapic_set_reg(klapic, 0xf, s->spurious_vec);
for (i = 0; i < 8; i++) {
kapic_set_reg(klapic, 0x10 + i, s->isr[i]);
kapic_set_reg(klapic, 0x18 + i, s->tmr[i]);
kapic_set_reg(klapic, 0x20 + i, s->irr[i]);
}
kapic_set_reg(klapic, 0x28, s->esr);
kapic_set_reg(klapic, 0x30, s->icr[0]);
kapic_set_reg(klapic, 0x31, s->icr[1]);
for (i = 0; i < APIC_LVT_NB; i++)
kapic_set_reg(klapic, 0x32 + i, s->lvt[i]);
kapic_set_reg(klapic, 0x38, s->initial_count);
kapic_set_reg(klapic, 0x3e, s->divide_conf);
kvm_set_lapic(s->cpu_env, klapic);
}
#endif
void qemu_kvm_load_lapic(CPUState *env)
{
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_vcpu_inited(env) && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_load_from_user(env->apic_state);
}
#endif
}
static void apic_pre_save(void *opaque)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = (void *)opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_save_to_user(s);
}
#endif
}
static int apic_post_load(void *opaque, int version_id)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_load_from_user(s);
}
#endif
return 0;
}
/* This function is only used for old state version 1 and 2 */
static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
{
@@ -900,6 +1027,9 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
if (version_id >= 2)
qemu_get_timer(f, s->timer);
qemu_kvm_load_lapic(s->cpu_env);
return 0;
}
@@ -930,7 +1060,9 @@ static const VMStateDescription vmstate_apic = {
VMSTATE_INT64(next_time, APICState),
VMSTATE_TIMER(timer, APICState),
VMSTATE_END_OF_LIST()
}
},
.pre_save = apic_pre_save,
.post_load = apic_post_load,
};
static void apic_reset(void *opaque)
@@ -955,6 +1087,7 @@ static void apic_reset(void *opaque)
*/
s->lvt[APIC_LVT_LINT0] = 0x700;
}
qemu_kvm_load_lapic(s->cpu_env);
}
static CPUReadMemoryFunc * const apic_mem_read[3] = {
@@ -998,6 +1131,11 @@ int apic_init(CPUState *env)
vmstate_register(s->idx, &vmstate_apic, s);
qemu_register_reset(apic_reset, s);
/* apic_reset must be called before the vcpu threads are initialized and load
* registers, in qemu-kvm.
*/
apic_reset(s);
local_apics[s->idx] = s;
return 0;
}

View File

@@ -71,7 +71,7 @@ static void arm_timer_recalibrate(arm_timer_state *s, int reload)
{
uint32_t limit;
if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
/* Free running. */
if (s->control & TIMER_CTRL_32BIT)
limit = 0xffffffff;
@@ -113,7 +113,7 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset,
case 1: freq >>= 4; break;
case 2: freq >>= 8; break;
}
arm_timer_recalibrate(s, 0);
arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
ptimer_set_freq(s->timer, freq);
if (s->control & TIMER_CTRL_ENABLE) {
/* Restart the timer if still enabled. */

View File

@@ -32,6 +32,7 @@
#include "console.h"
#include "vga_int.h"
#include "kvm.h"
#include "qemu-kvm.h"
#include "loader.h"
/*
@@ -2552,6 +2553,7 @@ static CPUWriteMemoryFunc * const cirrus_linear_bitblt_write[3] = {
static void map_linear_vram(CirrusVGAState *s)
{
vga_dirty_log_stop(&s->vga);
if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
s->vga.map_addr = s->vga.lfb_addr;
s->vga.map_end = s->vga.lfb_end;
@@ -2561,13 +2563,19 @@ static void map_linear_vram(CirrusVGAState *s)
if (!s->vga.map_addr)
return;
#ifndef TARGET_IA64
s->vga.lfb_vram_mapped = 0;
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
(s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_UNASSIGNED);
cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
(s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_UNASSIGNED);
if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
&& !((s->vga.sr[0x07] & 0x01) == 0)
&& !((s->vga.gr[0x0B] & 0x14) == 0x14)
&& !(s->vga.gr[0x0B] & 0x02)) {
vga_dirty_log_stop(&s->vga);
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
(s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
@@ -2579,12 +2587,14 @@ static void map_linear_vram(CirrusVGAState *s)
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
s->vga.vga_io_memory);
}
#endif
vga_dirty_log_start(&s->vga);
}
static void unmap_linear_vram(CirrusVGAState *s)
{
vga_dirty_log_stop(&s->vga);
if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
s->vga.map_addr = s->vga.map_end = 0;
cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
@@ -2592,6 +2602,8 @@ static void unmap_linear_vram(CirrusVGAState *s)
}
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
s->vga.vga_io_memory);
vga_dirty_log_start(&s->vga);
}
/* Compute the memory access functions */
@@ -3145,6 +3157,8 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
{
CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
vga_dirty_log_stop(&s->vga);
/* XXX: add byte swapping apertures */
cpu_register_physical_memory(addr, s->vga.vram_size,
s->cirrus_linear_io_addr);
@@ -3176,10 +3190,14 @@ static void pci_cirrus_write_config(PCIDevice *d,
PCICirrusVGAState *pvs = DO_UPCAST(PCICirrusVGAState, dev, d);
CirrusVGAState *s = &pvs->cirrus_vga;
vga_dirty_log_stop(&s->vga);
pci_default_write_config(d, address, val, len);
if (s->vga.map_addr && d->io_regions[0].addr == PCI_BAR_UNMAPPED)
s->vga.map_addr = 0;
cirrus_update_memory_access(s);
vga_dirty_log_start(&s->vga);
}
static int pci_cirrus_vga_initfn(PCIDevice *dev)

1379
hw/device-assignment.c Normal file

File diff suppressed because it is too large Load Diff

117
hw/device-assignment.h Normal file
View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2007, Neocleus Corporation.
* Copyright (c) 2007, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
* Data structures for storing PCI state
*
* Adapted to kvm by Qumranet
*
* Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
* Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
* Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
* Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
*/
#ifndef __DEVICE_ASSIGNMENT_H__
#define __DEVICE_ASSIGNMENT_H__
#include <sys/mman.h>
#include "qemu-common.h"
#include "qemu-queue.h"
#include "pci.h"
/* From include/linux/pci.h in the kernel sources */
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
typedef struct PCIHostDevice {
int bus;
int dev;
int func;
} PCIHostDevice;
typedef struct {
int type; /* Memory or port I/O */
int valid;
uint32_t base_addr;
uint32_t size; /* size of the region */
int resource_fd;
} PCIRegion;
typedef struct {
uint8_t bus, dev, func; /* Bus inside domain, device and function */
int irq; /* IRQ number */
uint16_t region_number; /* number of active regions */
/* Port I/O or MMIO Regions */
PCIRegion regions[PCI_NUM_REGIONS];
int config_fd;
} PCIDevRegions;
typedef struct {
pcibus_t e_physbase;
uint32_t memory_index;
union {
void *r_virtbase; /* mmapped access address for memory regions */
uint32_t r_baseport; /* the base guest port for I/O regions */
} u;
int num; /* our index within v_addrs[] */
pcibus_t e_size; /* emulated size of region in bytes */
pcibus_t r_size; /* real size of region in bytes */
} AssignedDevRegion;
typedef struct AssignedDevice {
PCIDevice dev;
PCIHostDevice host;
uint32_t use_iommu;
int intpin;
uint8_t debug_flags;
AssignedDevRegion v_addrs[PCI_NUM_REGIONS];
PCIDevRegions real_device;
int run;
int girq;
unsigned char h_busnr;
unsigned int h_devfn;
int irq_requested_type;
int bound;
struct pci_dev *pdev;
struct {
#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
uint32_t available;
#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
uint32_t state;
} cap;
int irq_entries_nr;
struct kvm_irq_routing_entry *entry;
void *msix_table_page;
target_phys_addr_t msix_table_addr;
int mmio_index;
int need_emulate_cmd;
QLIST_ENTRY(AssignedDevice) next;
} AssignedDevice;
QemuOpts *add_assigned_device(const char *arg);
void add_assigned_devices(PCIBus *bus, const char **devices, int n_devices);
void assigned_dev_update_irqs(void);
#define MAX_DEV_ASSIGN_CMDLINE 8
extern const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
extern int assigned_devices_index;
#endif /* __DEVICE_ASSIGNMENT_H__ */

135
hw/extboot.c Normal file
View File

@@ -0,0 +1,135 @@
/*
* Extended boot option ROM support.
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "hw.h"
#include "pc.h"
#include "isa.h"
#include "block.h"
/* Extended Boot ROM suport */
union extboot_cmd
{
uint16_t type;
struct {
uint16_t type;
uint16_t cylinders;
uint16_t heads;
uint16_t sectors;
uint64_t nb_sectors;
} query_geometry;
struct {
uint16_t type;
uint16_t nb_sectors;
uint16_t segment;
uint16_t offset;
uint64_t sector;
} xfer;
};
static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
{
bdrv_get_geometry_hint(bs, c, h, s);
if (*c <= 1024) {
*c >>= 0;
*h <<= 0;
} else if (*c <= 2048) {
*c >>= 1;
*h <<= 1;
} else if (*c <= 4096) {
*c >>= 2;
*h <<= 2;
} else if (*c <= 8192) {
*c >>= 3;
*h <<= 3;
} else {
*c >>= 4;
*h <<= 4;
}
/* what is the correct algorithm for this?? */
if (*h == 256) {
*h = 255;
*c = *c + 1;
}
}
static uint32_t extboot_read(void *opaque, uint32_t addr)
{
int *pcmd = opaque;
return *pcmd;
}
static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
{
union extboot_cmd cmd;
BlockDriverState *bs = opaque;
int cylinders, heads, sectors, err;
uint64_t nb_sectors;
target_phys_addr_t pa = 0;
int blen = 0;
void *buf = NULL;
cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (cmd.type == 0x01 || cmd.type == 0x02) {
pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
blen = cmd.xfer.nb_sectors * 512;
buf = qemu_memalign(512, blen);
}
switch (cmd.type) {
case 0x00:
get_translated_chs(bs, &cylinders, &heads, &sectors);
bdrv_get_geometry(bs, &nb_sectors);
cmd.query_geometry.cylinders = cylinders;
cmd.query_geometry.heads = heads;
cmd.query_geometry.sectors = sectors;
cmd.query_geometry.nb_sectors = nb_sectors;
break;
case 0x01:
err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Read failed\n");
cpu_physical_memory_write(pa, buf, blen);
break;
case 0x02:
cpu_physical_memory_read(pa, buf, blen);
err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Write failed\n");
break;
}
cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (buf)
qemu_free(buf);
}
void extboot_init(BlockDriverState *bs, int cmd)
{
int *pcmd;
pcmd = qemu_mallocz(sizeof(int));
*pcmd = cmd;
register_ioport_read(0x404, 1, 1, extboot_read, pcmd);
register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
}

View File

@@ -370,9 +370,9 @@ enum {
FD_CMD_PART_ID = 0x18,
FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
FD_CMD_SAVE = 0x2c,
FD_CMD_SAVE = 0x2e,
FD_CMD_OPTION = 0x33,
FD_CMD_RESTORE = 0x4c,
FD_CMD_RESTORE = 0x4e,
FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
FD_CMD_FORMAT_AND_WRITE = 0xcd,
@@ -1860,8 +1860,12 @@ fdctrl_t *fdctrl_init_isa(DriveInfo **fds)
ISADevice *dev;
dev = isa_create("isa-fdc");
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
if (fds[0]) {
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
}
if (fds[1]) {
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
}
if (qdev_init(&dev->qdev) < 0)
return NULL;
return &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
@@ -1879,8 +1883,12 @@ fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
qdev_prop_set_drive(dev, "driveA", fds[0]);
qdev_prop_set_drive(dev, "driveB", fds[1]);
if (fds[0]) {
qdev_prop_set_drive(dev, "driveA", fds[0]);
}
if (fds[1]) {
qdev_prop_set_drive(dev, "driveB", fds[1]);
}
qdev_init_nofail(dev);
sysbus_connect_irq(&sys->busdev, 0, irq);
sysbus_mmio_map(&sys->busdev, 0, mmio_base);
@@ -1896,7 +1904,9 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
fdctrl_t *fdctrl;
dev = qdev_create(NULL, "SUNW,fdtwo");
qdev_prop_set_drive(dev, "drive", fds[0]);
if (fds[0]) {
qdev_prop_set_drive(dev, "drive", fds[0]);
}
qdev_init_nofail(dev);
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
fdctrl = &sys->state;

View File

@@ -179,7 +179,7 @@ static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
static void put_unused(QEMUFile *f, void *pv, size_t size)
{
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibilty.\n");
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
fprintf(stderr, "This functions shouldn't be called.\n");
}

View File

@@ -170,6 +170,11 @@ static int hpet_post_load(void *opaque, int version_id)
/* Recalculate the offset between the main counter and guest time */
s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
if (hpet_in_legacy_mode()) {
hpet_disable_pit();
}
return 0;
}
@@ -473,9 +478,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
}
/* i8254 and RTC are disabled when HPET is in legacy mode */
if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
hpet_pit_disable();
hpet_disable_pit();
dprintf("qemu: hpet disabled pit\n");
} else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
hpet_pit_enable();
hpet_enable_pit();
dprintf("qemu: hpet enabled pit\n");
}
break;
case HPET_CFG + 4:
@@ -559,7 +566,7 @@ static void hpet_reset(void *opaque) {
* hpet_reset is called due to system reset. At this point control must
* be returned to pit until SW reenables hpet.
*/
hpet_pit_enable();
hpet_enable_pit();
count = 1;
}

13
hw/hw.h
View File

@@ -342,6 +342,10 @@ extern const VMStateInfo vmstate_info_uint16;
extern const VMStateInfo vmstate_info_uint32;
extern const VMStateInfo vmstate_info_uint64;
#ifdef __linux__
extern const VMStateInfo vmstate_info_u64;
#endif
extern const VMStateInfo vmstate_info_timer;
extern const VMStateInfo vmstate_info_ptimer;
extern const VMStateInfo vmstate_info_buffer;
@@ -622,6 +626,15 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_UINT64(_f, _s) \
VMSTATE_UINT64_V(_f, _s, 0)
/* This is needed because on linux __u64 is unsigned long long
and on glibc uint64_t is unsigned long on 64 bits */
#ifdef __linux__
#define VMSTATE_U64_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_u64, __u64)
#define VMSTATE_U64(_f, _s) \
VMSTATE_U64_V(_f, _s, 0)
#endif
#define VMSTATE_UINT8_EQUAL(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)

122
hw/i8254-kvm.c Normal file
View File

@@ -0,0 +1,122 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "pc.h"
#include "isa.h"
#include "qemu-timer.h"
#include "i8254.h"
#include "qemu-kvm.h"
extern VMStateDescription vmstate_pit;
static PITState pit_state;
static void kvm_pit_pre_save(void *opaque)
{
PITState *s = (void *)opaque;
struct kvm_pit_state2 pit2;
struct kvm_pit_channel_state *c;
struct PITChannelState *sc;
int i;
if(qemu_kvm_has_pit_state2()) {
kvm_get_pit2(kvm_context, &pit2);
s->flags = pit2.flags;
} else {
/* pit2 is superset of pit struct so just cast it and use it */
kvm_get_pit(kvm_context, (struct kvm_pit_state *)&pit2);
}
for (i = 0; i < 3; i++) {
c = &pit2.channels[i];
sc = &s->channels[i];
sc->count = c->count;
sc->latched_count = c->latched_count;
sc->count_latched = c->count_latched;
sc->status_latched = c->status_latched;
sc->status = c->status;
sc->read_state = c->read_state;
sc->write_state = c->write_state;
sc->write_latch = c->write_latch;
sc->rw_mode = c->rw_mode;
sc->mode = c->mode;
sc->bcd = c->bcd;
sc->gate = c->gate;
sc->count_load_time = c->count_load_time;
}
}
static int kvm_pit_post_load(void *opaque, int version_id)
{
PITState *s = opaque;
struct kvm_pit_state2 pit2;
struct kvm_pit_channel_state *c;
struct PITChannelState *sc;
int i;
pit2.flags = s->flags;
for (i = 0; i < 3; i++) {
c = &pit2.channels[i];
sc = &s->channels[i];
c->count = sc->count;
c->latched_count = sc->latched_count;
c->count_latched = sc->count_latched;
c->status_latched = sc->status_latched;
c->status = sc->status;
c->read_state = sc->read_state;
c->write_state = sc->write_state;
c->write_latch = sc->write_latch;
c->rw_mode = sc->rw_mode;
c->mode = sc->mode;
c->bcd = sc->bcd;
c->gate = sc->gate;
c->count_load_time = sc->count_load_time;
}
if(qemu_kvm_has_pit_state2()) {
kvm_set_pit2(kvm_context, &pit2);
} else {
kvm_set_pit(kvm_context, (struct kvm_pit_state *)&pit2);
}
return 0;
}
static void dummy_timer(void *opaque)
{
}
PITState *kvm_pit_init(int base, qemu_irq irq)
{
PITState *pit = &pit_state;
PITChannelState *s;
s = &pit->channels[0];
s->irq_timer = qemu_new_timer(vm_clock, dummy_timer, s);
vmstate_pit.pre_save = kvm_pit_pre_save;
vmstate_pit.post_load = kvm_pit_post_load;
vmstate_register(base, &vmstate_pit, pit);
qemu_register_reset(pit_reset, pit);
pit_reset(pit);
return pit;
}

View File

@@ -25,38 +25,11 @@
#include "pc.h"
#include "isa.h"
#include "qemu-timer.h"
#include "qemu-kvm.h"
#include "i8254.h"
//#define DEBUG_PIT
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
qemu_irq irq;
} PITChannelState;
struct PITState {
PITChannelState channels[3];
};
static PITState pit_state;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
@@ -228,13 +201,18 @@ int pit_get_mode(PITState *pit, int channel)
return s->mode;
}
static inline void pit_load_count(PITChannelState *s, int val)
static inline void pit_load_count(PITState *s, int val, int chan)
{
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock(vm_clock);
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
s->channels[chan].count_load_time = qemu_get_clock(vm_clock);
s->channels[chan].count = val;
#ifdef TARGET_I386
if (chan == 0 && pit_state.flags & PIT_FLAGS_HPET_LEGACY) {
return;
}
#endif
pit_irq_timer_update(&s->channels[chan], s->channels[chan].count_load_time);
}
/* if already latched, do not latch again */
@@ -294,17 +272,17 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
switch(s->write_state) {
default:
case RW_STATE_LSB:
pit_load_count(s, val);
pit_load_count(pit, val, addr);
break;
case RW_STATE_MSB:
pit_load_count(s, val << 8);
pit_load_count(pit, val << 8, addr);
break;
case RW_STATE_WORD0:
s->write_latch = val;
s->write_state = RW_STATE_WORD1;
break;
case RW_STATE_WORD1:
pit_load_count(s, s->write_latch | (val << 8));
pit_load_count(pit, s->write_latch | (val << 8), addr);
s->write_state = RW_STATE_WORD0;
break;
}
@@ -364,6 +342,11 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
return ret;
}
/* global counters for time-drift fix */
int64_t timer_acks=0, timer_interrupts=0, timer_ints_to_push=0;
extern int time_drift_fix;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
{
int64_t expire_time;
@@ -374,16 +357,35 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
expire_time = pit_get_next_transition_time(s, current_time);
irq_level = pit_get_out1(s, current_time);
qemu_set_irq(s->irq, irq_level);
if (time_drift_fix && irq_level==1) {
/* FIXME: fine tune timer_max_fix (max fix per tick).
* Should it be 1 (double time), 2 , 4, 10 ?
* Currently setting it to 5% of PIT-ticks-per-second (per PIT-tick)
*/
const long pit_ticks_per_sec = (s->count>0) ? (PIT_FREQ/s->count) : 0;
const long timer_max_fix = pit_ticks_per_sec/20;
const long delta = timer_interrupts - timer_acks;
const long max_delta = pit_ticks_per_sec * 60; /* one minute */
if ((delta > max_delta) && (pit_ticks_per_sec > 0)) {
printf("time drift is too long, %ld seconds were lost\n", delta/pit_ticks_per_sec);
timer_acks = timer_interrupts;
timer_ints_to_push = 0;
} else if (delta > 0) {
timer_ints_to_push = MIN(delta, timer_max_fix);
}
timer_interrupts++;
}
#ifdef DEBUG_PIT
printf("irq_level=%d next_delay=%f\n",
irq_level,
(double)(expire_time - current_time) / get_ticks_per_sec());
#endif
s->next_transition_time = expire_time;
if (expire_time != -1)
if (expire_time != -1) {
qemu_mod_timer(s->irq_timer, expire_time);
else
} else {
qemu_del_timer(s->irq_timer);
}
}
static void pit_irq_timer(void *opaque)
@@ -423,9 +425,10 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
PITChannelState *s;
int i;
if (version_id != 1)
if (version_id != PIT_SAVEVM_VERSION)
return -EINVAL;
pit->flags = qemu_get_be32(f);
for(i = 0; i < 3; i++) {
s = &pit->channels[i];
s->count=qemu_get_be32(f);
@@ -446,57 +449,85 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_timer(f, s->irq_timer);
}
}
return 0;
}
static const VMStateDescription vmstate_pit = {
VMStateDescription vmstate_pit = {
.name = "i8254",
.version_id = 2,
.minimum_version_id = 2,
.minimum_version_id_old = 1,
.load_state_old = pit_load_old,
.fields = (VMStateField []) {
VMSTATE_UINT32(flags, PITState),
VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
VMSTATE_TIMER(channels[0].irq_timer, PITState),
VMSTATE_END_OF_LIST()
}
};
static void pit_reset(void *opaque)
void pit_reset(void *opaque)
{
PITState *pit = opaque;
PITChannelState *s;
int i;
#ifdef TARGET_I386
pit->flags &= ~PIT_FLAGS_HPET_LEGACY;
#endif
for(i = 0;i < 3; i++) {
s = &pit->channels[i];
s->mode = 3;
s->gate = (i != 2);
pit_load_count(s, 0);
pit_load_count(pit, 0, i);
}
}
#ifdef TARGET_I386
/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
void hpet_pit_disable(void) {
PITChannelState *s;
s = &pit_state.channels[0];
if (s->irq_timer)
qemu_del_timer(s->irq_timer);
void hpet_disable_pit(void)
{
PITChannelState *s = &pit_state.channels[0];
if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
if (qemu_kvm_has_pit_state2()) {
kvm_hpet_disable_kpit();
} else {
fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
exit(1);
}
} else {
pit_state.flags |= PIT_FLAGS_HPET_LEGACY;
if (s->irq_timer) {
qemu_del_timer(s->irq_timer);
}
}
}
/* When HPET is reset or leaving legacy mode, it must reenable i8254
* timer 0
*/
void hpet_pit_enable(void)
void hpet_enable_pit(void)
{
PITState *pit = &pit_state;
PITChannelState *s;
s = &pit->channels[0];
s->mode = 3;
s->gate = 1;
pit_load_count(s, 0);
PITChannelState *s = &pit->channels[0];
if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
if (qemu_kvm_has_pit_state2()) {
kvm_hpet_enable_kpit();
} else {
fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
exit(1);
}
} else {
pit_state.flags &= ~PIT_FLAGS_HPET_LEGACY;
pit_load_count(pit, s->count, 0);
}
}
#endif
PITState *pit_init(int base, qemu_irq irq)
{

69
hw/i8254.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_I8254_H
#define QEMU_I8254_H
#define PIT_SAVEVM_NAME "i8254"
#define PIT_SAVEVM_VERSION 2
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
#define PIT_FLAGS_HPET_LEGACY 1
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
qemu_irq irq;
} PITChannelState;
struct PITState {
PITChannelState channels[3];
uint32_t flags;
};
void pit_save(QEMUFile *f, void *opaque);
int pit_load(QEMUFile *f, void *opaque, int version_id);
void pit_reset(void *opaque);
#endif

View File

@@ -27,6 +27,8 @@
#include "monitor.h"
#include "qemu-timer.h"
#include "qemu-kvm.h"
/* debug PIC */
//#define DEBUG_PIC
@@ -181,7 +183,6 @@ int64_t irq_time[16];
static void i8259_set_irq(void *opaque, int irq, int level)
{
PicState2 *s = opaque;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
@@ -212,18 +213,35 @@ static inline void pic_intack(PicState *s, int irq)
} else {
s->isr |= (1 << irq);
}
/* We don't clear a level sensitive interrupt here */
if (!(s->elcr & (1 << irq)))
s->irr &= ~(1 << irq);
}
extern int time_drift_fix;
int pic_read_irq(PicState2 *s)
{
int irq, irq2, intno;
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
pic_intack(&s->pics[0], irq);
#ifndef TARGET_IA64
if (time_drift_fix && irq == 0) {
extern int64_t timer_acks, timer_ints_to_push;
timer_acks++;
if (timer_ints_to_push > 0) {
timer_ints_to_push--;
/* simulate an edge irq0, like the one generated by i8254 */
pic_set_irq1(&s->pics[0], 0, 0);
pic_set_irq1(&s->pics[0], 0, 1);
}
}
#endif
if (irq == 2) {
irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) {
@@ -446,9 +464,33 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
return s->elcr;
}
static void kvm_kernel_pic_save_to_user(PicState *s);
static int kvm_kernel_pic_load_from_user(PicState *s);
static void pic_pre_save(void *opaque)
{
PicState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_save_to_user(s);
}
}
static int pic_post_load(void *opaque, int version_id)
{
PicState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_load_from_user(s);
}
return 0;
}
static const VMStateDescription vmstate_pic = {
.name = "i8259",
.version_id = 1,
.pre_save = pic_pre_save,
.post_load = pic_post_load,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
@@ -535,3 +577,103 @@ qemu_irq *i8259_init(qemu_irq parent_irq)
isa_pic = s;
return qemu_allocate_irqs(i8259_set_irq, s, 16);
}
static void kvm_kernel_pic_save_to_user(PicState *s)
{
#ifdef KVM_CAP_IRQCHIP
struct kvm_irqchip chip;
struct kvm_pic_state *kpic;
chip.chip_id = (&s->pics_state->pics[0] == s) ?
KVM_IRQCHIP_PIC_MASTER :
KVM_IRQCHIP_PIC_SLAVE;
kvm_get_irqchip(kvm_context, &chip);
kpic = &chip.chip.pic;
s->last_irr = kpic->last_irr;
s->irr = kpic->irr;
s->imr = kpic->imr;
s->isr = kpic->isr;
s->priority_add = kpic->priority_add;
s->irq_base = kpic->irq_base;
s->read_reg_select = kpic->read_reg_select;
s->poll = kpic->poll;
s->special_mask = kpic->special_mask;
s->init_state = kpic->init_state;
s->auto_eoi = kpic->auto_eoi;
s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
s->special_fully_nested_mode = kpic->special_fully_nested_mode;
s->init4 = kpic->init4;
s->elcr = kpic->elcr;
s->elcr_mask = kpic->elcr_mask;
#endif
}
static int kvm_kernel_pic_load_from_user(PicState *s)
{
#ifdef KVM_CAP_IRQCHIP
struct kvm_irqchip chip;
struct kvm_pic_state *kpic;
chip.chip_id = (&s->pics_state->pics[0] == s) ?
KVM_IRQCHIP_PIC_MASTER :
KVM_IRQCHIP_PIC_SLAVE;
kpic = &chip.chip.pic;
kpic->last_irr = s->last_irr;
kpic->irr = s->irr;
kpic->imr = s->imr;
kpic->isr = s->isr;
kpic->priority_add = s->priority_add;
kpic->irq_base = s->irq_base;
kpic->read_reg_select = s->read_reg_select;
kpic->poll = s->poll;
kpic->special_mask = s->special_mask;
kpic->init_state = s->init_state;
kpic->auto_eoi = s->auto_eoi;
kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
kpic->special_fully_nested_mode = s->special_fully_nested_mode;
kpic->init4 = s->init4;
kpic->elcr = s->elcr;
kpic->elcr_mask = s->elcr_mask;
kvm_set_irqchip(kvm_context, &chip);
#endif
return 0;
}
#ifdef KVM_CAP_IRQCHIP
static void kvm_i8259_set_irq(void *opaque, int irq, int level)
{
int pic_ret;
if (kvm_set_irq(irq, level, &pic_ret)) {
if (pic_ret != 0)
apic_set_irq_delivered();
return;
}
}
static void kvm_pic_init1(int io_addr, PicState *s)
{
vmstate_register(io_addr, &vmstate_pic, s);
qemu_register_reset(pic_reset, s);
}
qemu_irq *kvm_i8259_init(qemu_irq parent_irq)
{
PicState2 *s;
s = qemu_mallocz(sizeof(PicState2));
kvm_pic_init1(0x20, &s->pics[0]);
kvm_pic_init1(0xa0, &s->pics[1]);
s->parent_irq = parent_irq;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
isa_pic = s;
return qemu_allocate_irqs(kvm_i8259_set_irq, s, 24);
}
#endif

View File

@@ -70,11 +70,7 @@ static void ide_map(PCIDevice *pci_dev, int region_num,
static PCIIDEState *pci_from_bm(BMDMAState *bm)
{
if (bm->unit == 0) {
return container_of(bm, PCIIDEState, bmdma[0]);
} else {
return container_of(bm, PCIIDEState, bmdma[1]);
}
return bm->pci_dev;
}
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
@@ -145,6 +141,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
BMDMAState *bm = &d->bmdma[i];
d->bus[i].bmdma = bm;
bm->bus = d->bus+i;
bm->pci_dev = d;
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);

View File

@@ -2827,10 +2827,6 @@ static void ide_dma_restart(IDEState *s, int is_read)
void ide_dma_cancel(BMDMAState *bm)
{
if (bm->status & BM_STATUS_DMAING) {
bm->status &= ~BM_STATUS_DMAING;
/* cancel DMA request */
bm->unit = -1;
bm->dma_cb = NULL;
if (bm->aiocb) {
#ifdef DEBUG_AIO
printf("aio_cancel\n");
@@ -2838,6 +2834,10 @@ void ide_dma_cancel(BMDMAState *bm)
bdrv_aio_cancel(bm->aiocb);
bm->aiocb = NULL;
}
bm->status &= ~BM_STATUS_DMAING;
/* cancel DMA request */
bm->unit = -1;
bm->dma_cb = NULL;
}
}

View File

@@ -481,6 +481,7 @@ struct BMDMAState {
uint8_t status;
uint32_t addr;
struct PCIIDEState *pci_dev;
IDEBus *bus;
/* current transfer state */
uint32_t cur_addr;

View File

@@ -78,6 +78,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
BMDMAState *bm = &d->bmdma[i];
d->bus[i].bmdma = bm;
bm->bus = d->bus+i;
bm->pci_dev = d;
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);

View File

@@ -22,12 +22,16 @@
#include "hw.h"
#include "pc.h"
#include "sysemu.h"
#include "qemu-timer.h"
#include "host-utils.h"
#include "qemu-kvm.h"
//#define DEBUG_IOAPIC
#define IOAPIC_NUM_PINS 0x18
#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
#define IOAPIC_LVT_MASKED (1<<16)
#define IOAPIC_TRIGGER_EDGE 0
@@ -45,6 +49,7 @@
struct IOAPICState {
uint8_t id;
uint8_t ioregsel;
uint64_t base_address;
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
@@ -94,8 +99,9 @@ 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. */
if (vector == 0)
if (vector == 0 && irq0override) {
vector = 2;
}
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
@@ -191,14 +197,91 @@ static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va
}
}
static void kvm_kernel_ioapic_save_to_user(IOAPICState *s)
{
#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
struct kvm_irqchip chip;
struct kvm_ioapic_state *kioapic;
int i;
chip.chip_id = KVM_IRQCHIP_IOAPIC;
kvm_get_irqchip(kvm_context, &chip);
kioapic = &chip.chip.ioapic;
s->id = kioapic->id;
s->ioregsel = kioapic->ioregsel;
s->base_address = kioapic->base_address;
s->irr = kioapic->irr;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
s->ioredtbl[i] = kioapic->redirtbl[i].bits;
}
#endif
}
static void kvm_kernel_ioapic_load_from_user(IOAPICState *s)
{
#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
struct kvm_irqchip chip;
struct kvm_ioapic_state *kioapic;
int i;
chip.chip_id = KVM_IRQCHIP_IOAPIC;
kioapic = &chip.chip.ioapic;
kioapic->id = s->id;
kioapic->ioregsel = s->ioregsel;
kioapic->base_address = s->base_address;
kioapic->irr = s->irr;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
kioapic->redirtbl[i].bits = s->ioredtbl[i];
}
kvm_set_irqchip(kvm_context, &chip);
#endif
}
static void ioapic_pre_save(void *opaque)
{
IOAPICState *s = (void *)opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_save_to_user(s);
}
}
static int ioapic_pre_load(void *opaque)
{
IOAPICState *s = opaque;
/* in case we are doing version 1, we just set these to sane values */
s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
s->irr = 0;
return 0;
}
static int ioapic_post_load(void *opaque, int version_id)
{
IOAPICState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_load_from_user(s);
}
return 0;
}
static const VMStateDescription vmstate_ioapic = {
.name = "ioapic",
.version_id = 1,
.version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_load = ioapic_pre_load,
.post_load = ioapic_post_load,
.pre_save = ioapic_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT8(id, IOAPICState),
VMSTATE_UINT8(ioregsel, IOAPICState),
VMSTATE_UINT64_V(base_address, IOAPICState, 2),
VMSTATE_UINT32_V(irr, IOAPICState, 2),
VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
VMSTATE_END_OF_LIST()
}
@@ -210,8 +293,14 @@ static void ioapic_reset(void *opaque)
int i;
memset(s, 0, sizeof(*s));
s->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
for(i = 0; i < IOAPIC_NUM_PINS; i++)
s->ioredtbl[i] = 1 << 16; /* mask LVT */
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_load_from_user(s);
}
#endif
}
static CPUReadMemoryFunc * const ioapic_mem_read[3] = {

713
hw/ipf.c Normal file
View File

@@ -0,0 +1,713 @@
/*
* Itanium Platform Emulator derived from QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Copyright (c) 2007 Intel
* Ported for IA64 Platform Zhang Xiantao <xiantao.zhang@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "pc.h"
#include "fdc.h"
#include "pci.h"
#include "block.h"
#include "sysemu.h"
#include "audio/audio.h"
#include "net.h"
#include "smbus.h"
#include "boards.h"
#include "firmware.h"
#include "ia64intrin.h"
#include <unistd.h>
#include "device-assignment.h"
#include "virtio-blk.h"
#include "qemu-kvm.h"
#define FW_FILENAME "Flash.fd"
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
#define ACPI_DATA_SIZE 0x10000
#define MAX_IDE_BUS 2
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PCIDevice *i440fx_state;
static uint32_t ipf_to_legacy_io(target_phys_addr_t addr)
{
return (uint32_t)(((addr&0x3ffffff) >> 12 << 2)|((addr) & 0x3));
}
static void ipf_legacy_io_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outb(0, port, val);
}
static void ipf_legacy_io_writew(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outw(0, port, val);
}
static void ipf_legacy_io_writel(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outl(0, port, val);
}
static uint32_t ipf_legacy_io_readb(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inb(0, port);
}
static uint32_t ipf_legacy_io_readw(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inw(0, port);
}
static uint32_t ipf_legacy_io_readl(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inl(0, port);
}
static CPUReadMemoryFunc *ipf_legacy_io_read[3] = {
ipf_legacy_io_readb,
ipf_legacy_io_readw,
ipf_legacy_io_readl,
};
static CPUWriteMemoryFunc *ipf_legacy_io_write[3] = {
ipf_legacy_io_writeb,
ipf_legacy_io_writew,
ipf_legacy_io_writel,
};
static void pic_irq_request(void *opaque, int irq, int level)
{
fprintf(stderr,"pic_irq_request called!\n");
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
static int cmos_get_fd_drive_type(int fd0)
{
int val;
switch (fd0) {
case 0:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case 1:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case 2:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
default:
val = 0;
break;
}
return val;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
{
RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
rtc_set_memory(s, info_ofs, cylinders);
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
rtc_set_memory(s, info_ofs + 2, heads);
rtc_set_memory(s, info_ofs + 3, 0xff);
rtc_set_memory(s, info_ofs + 4, 0xff);
rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
rtc_set_memory(s, info_ofs + 6, cylinders);
rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
rtc_set_memory(s, info_ofs + 8, sectors);
}
/* convert boot_device letter to something recognizable by the bios */
static int boot_device2nibble(char boot_device)
{
switch(boot_device) {
case 'a':
case 'b':
return 0x01; /* floppy boot */
case 'c':
return 0x02; /* hard drive boot */
case 'd':
return 0x03; /* CD-ROM boot */
case 'n':
return 0x04; /* Network boot */
}
return 0;
}
/* hd_table must contain 4 block drivers */
static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device, BlockDriverState **hd_table)
{
RTCState *s = rtc_state;
int nbds, bds[3] = { 0, };
int val;
int fd0, fd1, nb;
int i;
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
val = 640; /* base memory in K */
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
val = (ram_size / 1024) - 1024;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
if (above_4g_mem_size) {
rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
rtc_set_memory(s, 0x5d, above_4g_mem_size >> 32);
}
rtc_set_memory(s, 0x5f, smp_cpus - 1);
if (ram_size > (16 * 1024 * 1024))
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
else
val = 0;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
/* set boot devices, and disable floppy signature check if requested */
#define PC_MAX_BOOT_DEVICES 3
nbds = strlen(boot_device);
if (nbds > PC_MAX_BOOT_DEVICES) {
fprintf(stderr, "Too many boot devices for PC\n");
exit(1);
}
for (i = 0; i < nbds; i++) {
bds[i] = boot_device2nibble(boot_device[i]);
if (bds[i] == 0) {
fprintf(stderr, "Invalid boot device for PC: '%c'\n",
boot_device[i]);
exit(1);
}
}
rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
/* floppy type */
fd0 = fdctrl_get_drive_type(floppy_controller, 0);
fd1 = fdctrl_get_drive_type(floppy_controller, 1);
val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
rtc_set_memory(s, 0x10, val);
val = 0;
nb = 0;
if (fd0 < 3)
nb++;
if (fd1 < 3)
nb++;
switch (nb) {
case 0:
break;
case 1:
val |= 0x01; /* 1 drive, ready for boot */
break;
case 2:
val |= 0x41; /* 2 drives, ready for boot */
break;
}
val |= 0x02; /* FPU is there */
val |= 0x04; /* PS/2 mouse installed */
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
cmos_init_hd(0x19, 0x1b, hd_table[0]);
if (hd_table[1])
cmos_init_hd(0x1a, 0x24, hd_table[1]);
val = 0;
for (i = 0; i < 4; i++) {
if (hd_table[i]) {
int cylinders, heads, sectors, translation;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation = bdrv_get_translation_hint(hd_table[i]);
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
bdrv_get_geometry_hint(hd_table[i], &cylinders,
&heads, &sectors);
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
/* No translation. */
translation = 0;
} else {
/* LBA translation. */
translation = 1;
}
} else {
translation--;
}
val |= translation << (i * 2);
}
}
rtc_set_memory(s, 0x39, val);
}
static void main_cpu_reset(void *opaque)
{
CPUState *env = opaque;
cpu_reset(env);
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340,
0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
{
struct soundhw *c;
int audio_enabled = 0;
for (c = soundhw; !audio_enabled && c->name; ++c) {
audio_enabled = c->enabled;
}
if (audio_enabled) {
AudioState *s;
s = AUD_init ();
if (s) {
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
c->init.init_isa (s, pic);
} else {
if (pci_bus) {
c->init.init_pci (pci_bus, s);
}
}
}
}
}
}
}
#endif
static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
{
static int nb_ne2k = 0;
if (nb_ne2k == NE2000_NB_MAX)
return;
isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
nb_ne2k++;
}
/* Itanium hardware initialisation */
static void ipf_init1(ram_addr_t ram_size,
const char *boot_device, DisplayState *ds,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename,
int pci_enabled, const char *cpu_model)
{
char buf[1024];
int i;
ram_addr_t ram_addr;
ram_addr_t above_4g_mem_size = 0;
PCIBus *pci_bus;
PCIDevice *pci_dev;
int piix3_devfn = -1;
CPUState *env;
qemu_irq *cpu_irq;
qemu_irq *i8259;
int page_size;
int index;
unsigned long ipf_legacy_io_base, ipf_legacy_io_mem;
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BlockDriverState *fd[MAX_FD];
page_size = getpagesize();
if (page_size != TARGET_PAGE_SIZE) {
fprintf(stderr,"Error! Host page size != qemu target page size,"
" you may need to change TARGET_PAGE_BITS in qemu!"
"host page size:0x%x\n", page_size);
exit(-1);
};
if (ram_size >= 0xc0000000 ) {
above_4g_mem_size = ram_size - 0xc0000000;
ram_size = 0xc0000000;
}
/* init CPUs */
if (cpu_model == NULL) {
cpu_model = "IA64";
}
for(i = 0; i < smp_cpus; i++) {
env = cpu_init(cpu_model);
if (!env) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
if (i != 0)
env->hflags |= HF_HALTED_MASK;
register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, 0, env);
}
/* allocate RAM */
if (kvm_enabled()) {
ram_addr = qemu_ram_alloc(0xa0000);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
ram_addr = qemu_ram_alloc(0x20000); // Workaround 0xa0000-0xc0000
ram_addr = qemu_ram_alloc(0x40000);
cpu_register_physical_memory(0xc0000, 0x40000, ram_addr);
ram_addr = qemu_ram_alloc(ram_size - 0x100000);
cpu_register_physical_memory(0x100000, ram_size - 0x100000, ram_addr);
} else {
ram_addr = qemu_ram_alloc(ram_size);
cpu_register_physical_memory(0, ram_size, ram_addr);
}
/* above 4giga memory allocation */
if (above_4g_mem_size > 0) {
ram_addr = qemu_ram_alloc(above_4g_mem_size);
cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr);
}
/*Load firware to its proper position.*/
if (kvm_enabled()) {
unsigned long image_size;
uint8_t *image = NULL;
unsigned long nvram_addr;
unsigned long nvram_fd = 0;
unsigned long type = READ_FROM_NVRAM;
unsigned long i = 0;
unsigned long fw_offset;
ram_addr_t fw_mem = qemu_ram_alloc(GFW_SIZE);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, FW_FILENAME);
image = read_image(buf, &image_size );
if (NULL == image || !image_size) {
fprintf(stderr, "Error when reading Guest Firmware!\n");
fprintf(stderr, "Please check Guest firmware at %s\n", buf);
exit(1);
}
fw_offset = GFW_START + GFW_SIZE - image_size;
cpu_register_physical_memory(GFW_START, GFW_SIZE, fw_mem);
cpu_physical_memory_write(fw_offset, image, image_size);
free(image);
if (nvram) {
nvram_addr = NVRAM_START;
nvram_fd = kvm_ia64_nvram_init(type);
if (nvram_fd != -1) {
kvm_ia64_copy_from_nvram_to_GFW(nvram_fd);
close(nvram_fd);
}
i = atexit((void *)kvm_ia64_copy_from_GFW_to_nvram);
if (i != 0)
fprintf(stderr, "cannot set exit function\n");
} else
nvram_addr = 0;
kvm_ia64_build_hob(ram_size + above_4g_mem_size, smp_cpus, nvram_addr);
}
/*Register legacy io address space, size:64M*/
ipf_legacy_io_base = 0xE0000000;
ipf_legacy_io_mem = cpu_register_io_memory(0, ipf_legacy_io_read,
ipf_legacy_io_write, NULL);
cpu_register_physical_memory(ipf_legacy_io_base, 64*1024*1024,
ipf_legacy_io_mem);
cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
i8259 = kvm_i8259_init(cpu_irq[0]);
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, i8259);
piix3_devfn = piix3_init(pci_bus, -1);
} else {
pci_bus = NULL;
}
if (cirrus_vga_enabled) {
if (pci_enabled)
pci_cirrus_vga_init(pci_bus);
else
isa_cirrus_vga_init();
} else {
if (pci_enabled)
pci_vga_init(pci_bus, 0, 0);
else
isa_vga_init();
}
rtc_state = rtc_init(0x70, i8259[8], 2000);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, NULL, NULL);
}
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], i8259[parallel_irq[i]],
parallel_hds[i]);
}
}
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
pc_init_ne2k_isa(nd, i8259);
else
pci_nic_init(nd, "e1000", NULL);
}
#undef USE_HYPERCALL //Disable it now, need to implement later!
#ifdef USE_HYPERCALL
pci_hypercall_init(pci_bus);
#endif
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
fprintf(stderr, "qemu: too many IDE bus\n");
exit(1);
}
for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
if (index != -1)
hd[i] = drives_table[index].bdrv;
else
hd[i] = NULL;
}
if (pci_enabled) {
pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
}
}
i8042_init(i8259[1], i8259[12], 0x60);
DMA_init(0);
#ifdef HAS_AUDIO
audio_init(pci_enabled ? pci_bus : NULL, i8259);
#endif
for(i = 0; i < MAX_FD; i++) {
index = drive_get_index(IF_FLOPPY, 0, i);
if (index != -1)
fd[i] = drives_table[index].bdrv;
else
fd[i] = NULL;
}
floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
cmos_init(ram_size, above_4g_mem_size, boot_device, hd);
if (pci_enabled && usb_enabled) {
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
}
if (pci_enabled && acpi_enabled) {
uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
i2c_bus *smbus;
/* TODO: Populate SPD eeprom data. */
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
for (i = 0; i < 8; i++) {
DeviceState *eeprom;
eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
qdev_set_prop_int(eeprom, "address", 0x50 + i);
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
qdev_init(eeprom);
}
}
if (i440fx_state) {
i440fx_init_memory_mappings(i440fx_state);
}
if (pci_enabled) {
int max_bus;
int bus;
max_bus = drive_get_max_bus(IF_SCSI);
for (bus = 0; bus <= max_bus; bus++) {
pci_create_simple(pci_bus, -1, "lsi53c895a");
}
}
/* Add virtio block devices */
if (pci_enabled) {
int index;
int unit_id = 0;
while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
pci_dev = pci_create("virtio-blk-pci",
drives_table[index].devaddr);
qdev_init(&pci_dev->qdev);
unit_id++;
}
}
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
if (kvm_enabled())
add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
}
static void ipf_init_pci(ram_addr_t ram_size,
const char *boot_device, DisplayState *ds,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
const char *cpu_model)
{
ipf_init1(ram_size, boot_device, ds, kernel_filename,
kernel_cmdline, initrd_filename, 1, cpu_model);
}
QEMUMachine ipf_machine = {
.name = "itanium",
.desc = "Itanium Platform",
.init = (QEMUMachineInitFunc *)ipf_init_pci,
.max_cpus = 255,
.is_default = 1,
};
static void ipf_machine_init(void)
{
qemu_register_machine(&ipf_machine);
}
machine_init(ipf_machine_init);
#define IOAPIC_NUM_PINS 48
static int ioapic_irq_count[IOAPIC_NUM_PINS];
static int ioapic_map_irq(int devfn, int irq_num)
{
int irq, dev;
dev = devfn >> 3;
irq = ((((dev << 2) + (dev >> 3) + irq_num) & 31) + 16);
return irq;
}
/*
* Dummy function to provide match for call from hw/apic.c
*/
void apic_set_irq_delivered(void) {
}
void ioapic_set_irq(void *opaque, int irq_num, int level)
{
int vector, pic_ret;
PCIDevice *pci_dev = (PCIDevice *)opaque;
vector = ioapic_map_irq(pci_dev->devfn, irq_num);
if (level)
ioapic_irq_count[vector] += 1;
else
ioapic_irq_count[vector] -= 1;
if (kvm_enabled()) {
if (kvm_set_irq(vector, ioapic_irq_count[vector] == 0, &pic_ret))
if (pic_ret != 0)
apic_set_irq_delivered();
return;
}
}
int ipf_map_irq(PCIDevice *pci_dev, int irq_num)
{
return ioapic_map_irq(pci_dev->devfn, irq_num);
}

View File

@@ -173,11 +173,15 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
/* Flag set if this is a tagged command. */
#define LSI_TAG_VALID (1 << 16)
typedef struct {
typedef struct lsi_request {
uint32_t tag;
SCSIDevice *dev;
uint32_t dma_len;
uint8_t *dma_buf;
uint32_t pending;
int out;
} lsi_queue;
QTAILQ_ENTRY(lsi_request) next;
} lsi_request;
typedef struct {
PCIDevice dev;
@@ -198,16 +202,13 @@ typedef struct {
* 3 if a DMA operation is in progress. */
int waiting;
SCSIBus bus;
SCSIDevice *current_dev;
SCSIDevice *select_dev;
int current_lun;
/* The tag is a combination of the device ID and the SCSI tag. */
uint32_t current_tag;
uint32_t current_dma_len;
uint32_t select_tag;
int command_complete;
uint8_t *dma_buf;
lsi_queue *queue;
int queue_len;
int active_commands;
QTAILQ_HEAD(, lsi_request) queue;
lsi_request *current;
uint32_t dsa;
uint32_t temp;
@@ -370,7 +371,7 @@ static int lsi_dma_64bit(LSIState *s)
static uint8_t lsi_reg_readb(LSIState *s, int offset);
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
static void lsi_execute_script(LSIState *s);
static void lsi_reselect(LSIState *s, uint32_t tag);
static void lsi_reselect(LSIState *s, lsi_request *p);
static inline uint32_t read_dword(LSIState *s, uint32_t addr)
{
@@ -391,9 +392,9 @@ static void lsi_stop_script(LSIState *s)
static void lsi_update_irq(LSIState *s)
{
int i;
int level;
static int last_level;
lsi_request *p;
/* It's unclear whether the DIP/SIP bits should be cleared when the
Interrupt Status Registers are cleared or when istat0 is read.
@@ -427,9 +428,9 @@ static void lsi_update_irq(LSIState *s)
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
DPRINTF("Handled IRQs & disconnected, looking for pending "
"processes\n");
for (i = 0; i < s->active_commands; i++) {
if (s->queue[i].pending) {
lsi_reselect(s, s->queue[i].tag);
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
lsi_reselect(s, p);
break;
}
}
@@ -508,15 +509,16 @@ static void lsi_do_dma(LSIState *s, int out)
uint32_t count;
target_phys_addr_t addr;
if (!s->current_dma_len) {
assert(s->current);
if (!s->current->dma_len) {
/* Wait until data is available. */
DPRINTF("DMA no data available\n");
return;
}
count = s->dbc;
if (count > s->current_dma_len)
count = s->current_dma_len;
if (count > s->current->dma_len)
count = s->current->dma_len;
addr = s->dnad;
/* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
@@ -532,29 +534,29 @@ static void lsi_do_dma(LSIState *s, int out)
s->dnad += count;
s->dbc -= count;
if (s->dma_buf == NULL) {
s->dma_buf = s->current_dev->info->get_buf(s->current_dev,
s->current_tag);
if (s->current->dma_buf == NULL) {
s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
s->current->tag);
}
/* ??? Set SFBR to first data byte. */
if (out) {
cpu_physical_memory_read(addr, s->dma_buf, count);
cpu_physical_memory_read(addr, s->current->dma_buf, count);
} else {
cpu_physical_memory_write(addr, s->dma_buf, count);
cpu_physical_memory_write(addr, s->current->dma_buf, count);
}
s->current_dma_len -= count;
if (s->current_dma_len == 0) {
s->dma_buf = NULL;
s->current->dma_len -= count;
if (s->current->dma_len == 0) {
s->current->dma_buf = NULL;
if (out) {
/* Write the data. */
s->current_dev->info->write_data(s->current_dev, s->current_tag);
s->current->dev->info->write_data(s->current->dev, s->current->tag);
} else {
/* Request any remaining data. */
s->current_dev->info->read_data(s->current_dev, s->current_tag);
s->current->dev->info->read_data(s->current->dev, s->current->tag);
}
} else {
s->dma_buf += count;
s->current->dma_buf += count;
lsi_resume_script(s);
}
}
@@ -563,15 +565,14 @@ static void lsi_do_dma(LSIState *s, int out)
/* Add a command to the queue. */
static void lsi_queue_command(LSIState *s)
{
lsi_queue *p;
lsi_request *p = s->current;
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
if (s->queue_len == s->active_commands) {
s->queue_len++;
s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue));
}
p = &s->queue[s->active_commands++];
p->tag = s->current_tag;
assert(s->current != NULL);
assert(s->current->dma_len == 0);
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
s->current = NULL;
p->pending = 0;
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
}
@@ -588,45 +589,29 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data)
}
/* Perform reselection to continue a command. */
static void lsi_reselect(LSIState *s, uint32_t tag)
static void lsi_reselect(LSIState *s, lsi_request *p)
{
lsi_queue *p;
int n;
int id;
p = NULL;
for (n = 0; n < s->active_commands; n++) {
p = &s->queue[n];
if (p->tag == tag)
break;
}
if (n == s->active_commands) {
BADF("Reselected non-existant command tag=0x%x\n", tag);
return;
}
id = (tag >> 8) & 0xf;
assert(s->current == NULL);
QTAILQ_REMOVE(&s->queue, p, next);
s->current = p;
id = (p->tag >> 8) & 0xf;
s->ssid = id | 0x80;
/* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
if (!s->dcntl & LSI_DCNTL_COM) {
s->sfbr = 1 << (id & 0x7);
}
DPRINTF("Reselected target %d\n", id);
s->current_dev = s->bus.devs[id];
s->current_tag = tag;
s->scntl1 |= LSI_SCNTL1_CON;
lsi_set_phase(s, PHASE_MI);
s->msg_action = p->out ? 2 : 3;
s->current_dma_len = p->pending;
s->dma_buf = NULL;
s->current->dma_len = p->pending;
lsi_add_msg_byte(s, 0x80);
if (s->current_tag & LSI_TAG_VALID) {
if (s->current->tag & LSI_TAG_VALID) {
lsi_add_msg_byte(s, 0x20);
lsi_add_msg_byte(s, tag & 0xff);
}
s->active_commands--;
if (n != s->active_commands) {
s->queue[n] = s->queue[s->active_commands];
lsi_add_msg_byte(s, p->tag & 0xff);
}
if (lsi_irq_on_rsl(s)) {
@@ -638,10 +623,9 @@ static void lsi_reselect(LSIState *s, uint32_t tag)
the device was reselected, nonzero if the IO is deferred. */
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
{
lsi_queue *p;
int i;
for (i = 0; i < s->active_commands; i++) {
p = &s->queue[i];
lsi_request *p;
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->tag == tag) {
if (p->pending) {
BADF("Multiple IO pending for tag %d\n", tag);
@@ -656,10 +640,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
!(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
/* Reselect device. */
lsi_reselect(s, tag);
lsi_reselect(s, p);
return 0;
} else {
DPRINTF("Queueing IO tag=0x%x\n", tag);
DPRINTF("Queueing IO tag=0x%x\n", tag);
p->pending = arg;
return 1;
}
@@ -687,11 +671,15 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
} else {
lsi_set_phase(s, PHASE_ST);
}
qemu_free(s->current);
s->current = NULL;
lsi_resume_script(s);
return;
}
if (s->waiting == 1 || tag != s->current_tag ||
if (s->waiting == 1 || !s->current || tag != s->current->tag ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
if (lsi_queue_tag(s, tag, arg))
return;
@@ -699,7 +687,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
/* host adapter (re)connected */
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
s->current_dma_len = arg;
s->current->dma_len = arg;
s->command_complete = 1;
if (!s->waiting)
return;
@@ -721,14 +709,20 @@ static void lsi_do_command(LSIState *s)
cpu_physical_memory_read(s->dnad, buf, s->dbc);
s->sfbr = buf[0];
s->command_complete = 0;
n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf,
s->current_lun);
assert(s->current == NULL);
s->current = qemu_mallocz(sizeof(lsi_request));
s->current->tag = s->select_tag;
s->current->dev = s->select_dev;
n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf,
s->current_lun);
if (n > 0) {
lsi_set_phase(s, PHASE_DI);
s->current_dev->info->read_data(s->current_dev, s->current_tag);
s->current->dev->info->read_data(s->current->dev, s->current->tag);
} else if (n < 0) {
lsi_set_phase(s, PHASE_DO);
s->current_dev->info->write_data(s->current_dev, s->current_tag);
s->current->dev->info->write_data(s->current->dev, s->current->tag);
}
if (!s->command_complete) {
@@ -851,16 +845,16 @@ static void lsi_do_msgout(LSIState *s)
}
break;
case 0x20: /* SIMPLE queue */
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
break;
case 0x21: /* HEAD of queue */
BADF("HEAD queue not implemented\n");
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
case 0x22: /* ORDERED queue */
BADF("ORDERED queue not implemented\n");
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
default:
if ((msg & 0x80) == 0) {
@@ -905,17 +899,17 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
static void lsi_wait_reselect(LSIState *s)
{
int i;
lsi_request *p;
DPRINTF("Wait Reselect\n");
if (s->current_dma_len)
BADF("Reselect with pending DMA\n");
for (i = 0; i < s->active_commands; i++) {
if (s->queue[i].pending) {
lsi_reselect(s, s->queue[i].tag);
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
lsi_reselect(s, p);
break;
}
}
if (s->current_dma_len == 0) {
if (s->current == NULL) {
s->waiting = 1;
}
}
@@ -1093,8 +1087,8 @@ again:
/* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
s->current_dev = s->bus.devs[id];
s->current_tag = id << 8;
s->select_dev = s->bus.devs[id];
s->select_tag = id << 8;
s->scntl1 |= LSI_SCNTL1_CON;
if (insn & (1 << 3)) {
s->socl |= LSI_SOCL_ATN;
@@ -2006,9 +2000,11 @@ static void lsi_pre_save(void *opaque)
{
LSIState *s = opaque;
assert(s->dma_buf == NULL);
assert(s->current_dma_len == 0);
assert(s->active_commands == 0);
if (s->current) {
assert(s->current->dma_buf == NULL);
assert(s->current->dma_len == 0);
}
assert(QTAILQ_EMPTY(&s->queue));
}
static const VMStateDescription vmstate_lsi_scsi = {
@@ -2101,8 +2097,6 @@ static int lsi_scsi_uninit(PCIDevice *d)
cpu_unregister_io_memory(s->mmio_io_addr);
cpu_unregister_io_memory(s->ram_io_addr);
qemu_free(s->queue);
return 0;
}
@@ -2138,9 +2132,7 @@ static int lsi_scsi_init(PCIDevice *dev)
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
s->queue = qemu_malloc(sizeof(lsi_queue));
s->queue_len = 1;
s->active_commands = 0;
QTAILQ_INIT(&s->queue);
lsi_soft_reset(s);

159
hw/msix.c
View File

@@ -14,6 +14,8 @@
#include "hw.h"
#include "msix.h"
#include "pci.h"
#define QEMU_KVM_NO_CPU
#include "qemu-kvm.h"
/* Declaration from linux/pci_regs.h */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
@@ -62,6 +64,117 @@
/* Flag for interrupt controller to declare MSI-X support */
int msix_supported;
#ifdef CONFIG_KVM
/* KVM specific MSIX helpers */
static void kvm_msix_free(PCIDevice *dev)
{
int vector, changed = 0;
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
if (dev->msix_entry_used[vector]) {
kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
changed = 1;
}
}
if (changed) {
kvm_commit_irq_routes(kvm_context);
}
}
static void kvm_msix_routing_entry(PCIDevice *dev, unsigned vector,
struct kvm_irq_routing_entry *entry)
{
uint8_t *table_entry = dev->msix_table_page + vector * MSIX_ENTRY_SIZE;
entry->type = KVM_IRQ_ROUTING_MSI;
entry->flags = 0;
entry->u.msi.address_lo = pci_get_long(table_entry + MSIX_MSG_ADDR);
entry->u.msi.address_hi = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
entry->u.msi.data = pci_get_long(table_entry + MSIX_MSG_DATA);
}
static void kvm_msix_update(PCIDevice *dev, int vector,
int was_masked, int is_masked)
{
struct kvm_irq_routing_entry e = {}, *entry;
int mask_cleared = was_masked && !is_masked;
/* It is only legal to change an entry when it is masked. Therefore, it is
* enough to update the routing in kernel when mask is being cleared. */
if (!mask_cleared) {
return;
}
if (!dev->msix_entry_used[vector]) {
return;
}
entry = dev->msix_irq_entries + vector;
e.gsi = entry->gsi;
kvm_msix_routing_entry(dev, vector, &e);
if (memcmp(&entry->u.msi, &e.u.msi, sizeof entry->u.msi)) {
int r;
r = kvm_update_routing_entry(kvm_context, entry, &e);
if (r) {
fprintf(stderr, "%s: kvm_update_routing_entry failed: %s\n", __func__,
strerror(-r));
exit(1);
}
memcpy(&entry->u.msi, &e.u.msi, sizeof entry->u.msi);
r = kvm_commit_irq_routes(kvm_context);
if (r) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
strerror(-r));
exit(1);
}
}
}
static int kvm_msix_add(PCIDevice *dev, unsigned vector)
{
struct kvm_irq_routing_entry *entry = dev->msix_irq_entries + vector;
int r;
if (!kvm_has_gsi_routing(kvm_context)) {
fprintf(stderr, "Warning: no MSI-X support found. "
"At least kernel 2.6.30 is required for MSI-X support.\n"
);
return -EOPNOTSUPP;
}
r = kvm_get_irq_route_gsi(kvm_context);
if (r < 0) {
fprintf(stderr, "%s: kvm_get_irq_route_gsi failed: %s\n", __func__, strerror(-r));
return r;
}
entry->gsi = r;
kvm_msix_routing_entry(dev, vector, entry);
r = kvm_add_routing_entry(kvm_context, entry);
if (r < 0) {
fprintf(stderr, "%s: kvm_add_routing_entry failed: %s\n", __func__, strerror(-r));
return r;
}
r = kvm_commit_irq_routes(kvm_context);
if (r < 0) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, strerror(-r));
return r;
}
return 0;
}
static void kvm_msix_del(PCIDevice *dev, unsigned vector)
{
if (dev->msix_entry_used[vector]) {
return;
}
kvm_del_routing_entry(kvm_context, &dev->msix_irq_entries[vector]);
kvm_commit_irq_routes(kvm_context);
}
#else
static void kvm_msix_free(PCIDevice *dev) {}
static void kvm_msix_update(PCIDevice *dev, int vector,
int was_masked, int is_masked) {}
static int kvm_msix_add(PCIDevice *dev, unsigned vector) { return -1; }
static void kvm_msix_del(PCIDevice *dev, unsigned vector) {}
#endif
/* Add MSI-X capability to the config space for the device. */
/* Given a bar and its size, add MSI-X table on top of it
* and fill MSI-X capability in the config space.
@@ -200,7 +313,11 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
PCIDevice *dev = opaque;
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
int vector = offset / MSIX_ENTRY_SIZE;
int was_masked = msix_is_masked(dev, vector);
pci_set_long(dev->msix_table_page + offset, val);
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
}
msix_handle_mask_update(dev, vector);
}
@@ -259,6 +376,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL;
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
dev->msix_irq_entries = qemu_malloc(nentries *
sizeof *dev->msix_irq_entries);
}
#endif
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
sizeof *dev->msix_entry_used);
@@ -295,6 +418,10 @@ static void msix_free_irq_entries(PCIDevice *dev)
{
int vector;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_free(dev);
}
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
dev->msix_entry_used[vector] = 0;
msix_clr_pending(dev, vector);
@@ -315,6 +442,8 @@ int msix_uninit(PCIDevice *dev)
dev->msix_table_page = NULL;
qemu_free(dev->msix_entry_used);
dev->msix_entry_used = NULL;
qemu_free(dev->msix_irq_entries);
dev->msix_irq_entries = NULL;
dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
return 0;
}
@@ -323,10 +452,13 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
{
unsigned n = dev->msix_entries_nr;
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
if (!msix_supported) {
return;
}
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
return;
}
qemu_put_buffer(f, dev->msix_table_page, n * MSIX_ENTRY_SIZE);
qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
}
@@ -336,6 +468,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
{
unsigned n = dev->msix_entries_nr;
if (!msix_supported)
return;
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
return;
}
@@ -380,6 +515,13 @@ void msix_notify(PCIDevice *dev, unsigned vector)
return;
}
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL);
return;
}
#endif
address = pci_get_long(table_entry + MSIX_MSG_UPPER_ADDR);
address = (address << 32) | pci_get_long(table_entry + MSIX_MSG_ADDR);
data = pci_get_long(table_entry + MSIX_MSG_DATA);
@@ -408,9 +550,19 @@ void msix_reset(PCIDevice *dev)
/* Mark vector as used. */
int msix_vector_use(PCIDevice *dev, unsigned vector)
{
int ret;
if (vector >= dev->msix_entries_nr)
return -EINVAL;
dev->msix_entry_used[vector]++;
if (dev->msix_entry_used[vector]) {
return 0;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
ret = kvm_msix_add(dev, vector);
if (ret) {
return ret;
}
}
++dev->msix_entry_used[vector];
return 0;
}
@@ -423,6 +575,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector)
if (--dev->msix_entry_used[vector]) {
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_del(dev, vector);
}
msix_clr_pending(dev, vector);
}

85
hw/pc.c
View File

@@ -44,6 +44,9 @@
#include "ide.h"
#include "loader.h"
#include "elf.h"
#include "device-assignment.h"
#include "qemu-kvm.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -52,6 +55,8 @@
//#define DEBUG_MULTIBOOT
#define BIOS_FILENAME "bios.bin"
#define EXTBOOT_FILENAME "extboot.bin"
#define VAPIC_FILENAME "vapic.bin"
#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -69,6 +74,8 @@ static RTCState *rtc_state;
static PITState *pit;
static PCII440FXState *i440fx_state;
qemu_irq *ioapic_irq_hack;
typedef struct isa_irq_state {
qemu_irq *i8259;
qemu_irq *ioapic;
@@ -952,7 +959,7 @@ int cpu_is_bsp(CPUState *env)
return env->cpuid_apic_id == 0;
}
static CPUState *pc_new_cpu(const char *cpu_model)
CPUState *pc_new_cpu(const char *cpu_model)
{
CPUState *env;
@@ -961,6 +968,7 @@ static CPUState *pc_new_cpu(const char *cpu_model)
fprintf(stderr, "Unable to find x86 CPU definition\n");
exit(1);
}
env->kvm_cpu_state.regs_modified = 1;
if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
env->cpuid_apic_id = env->cpu_index;
/* APIC reset callback resets cpu */
@@ -968,6 +976,11 @@ static CPUState *pc_new_cpu(const char *cpu_model)
} else {
qemu_register_reset((QEMUResetHandler*)cpu_reset, env);
}
/* kvm needs this to run after the apic is initialized. Otherwise,
* it can access invalid state and crash.
*/
qemu_init_vcpu(env);
return env;
}
@@ -1015,6 +1028,9 @@ static void pc_init1(ram_addr_t ram_size,
#endif
}
if (kvm_enabled()) {
kvm_set_boot_cpu_id(0);
}
for (i = 0; i < smp_cpus; i++) {
env = pc_new_cpu(cpu_model);
}
@@ -1022,18 +1038,11 @@ static void pc_init1(ram_addr_t ram_size,
vmport_init();
/* allocate RAM */
ram_addr = qemu_ram_alloc(0xa0000);
ram_addr = qemu_ram_alloc(below_4g_mem_size);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
/* Allocate, even though we won't register, so we don't break the
* phys_ram_base + PA assumption. This range includes vga (0xa0000 - 0xc0000),
* and some bios areas, which will be registered later
*/
ram_addr = qemu_ram_alloc(0x100000 - 0xa0000);
ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000);
cpu_register_physical_memory(0x100000,
below_4g_mem_size - 0x100000,
ram_addr);
ram_addr + 0x100000);
/* above 4giga memory allocation */
if (above_4g_mem_size > 0) {
@@ -1075,11 +1084,17 @@ static void pc_init1(ram_addr_t ram_size,
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024))
isa_bios_size = 128 * 1024;
cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
IO_MEM_UNASSIGNED);
/* kvm tpr optimization needs the bios accessible for write, at least to qemu itself */
cpu_register_physical_memory(0x100000 - isa_bios_size,
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
(bios_offset + bios_size - isa_bios_size) /* | IO_MEM_ROM */);
if (extboot_drive) {
option_rom[nb_option_roms++] = qemu_strdup(EXTBOOT_FILENAME);
}
option_rom[nb_option_roms++] = qemu_strdup(VAPIC_FILENAME);
rom_enable_driver_roms = 1;
option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE);
@@ -1101,10 +1116,18 @@ static void pc_init1(ram_addr_t ram_size,
}
cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
i8259 = i8259_init(cpu_irq[0]);
isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
isa_irq_state->i8259 = i8259;
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
isa_irq = i8259 = kvm_i8259_init(cpu_irq[0]);
} else
#endif
{
i8259 = i8259_init(cpu_irq[0]);
isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
isa_irq_state->i8259 = i8259;
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
}
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq);
@@ -1149,8 +1172,14 @@ static void pc_init1(ram_addr_t ram_size,
if (pci_enabled) {
isa_irq_state->ioapic = ioapic_init();
ioapic_irq_hack = isa_irq;
}
pit = pit_init(0x40, isa_reserve_irq(0));
#ifdef CONFIG_KVM_PIT
if (kvm_enabled() && qemu_kvm_pit_in_kernel())
pit = kvm_pit_init(0x40, isa_reserve_irq(0));
else
#endif
pit = pit_init(0x40, isa_reserve_irq(0));
pcspk_init(pit);
if (!no_hpet) {
hpet_init(isa_irq);
@@ -1174,7 +1203,7 @@ static void pc_init1(ram_addr_t ram_size,
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
pc_init_ne2k_isa(nd);
else
pci_nic_init_nofail(nd, "e1000", NULL);
pci_nic_init_nofail(nd, "rtl8139", NULL);
}
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
@@ -1226,7 +1255,7 @@ static void pc_init1(ram_addr_t ram_size,
qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
qdev_init_nofail(eeprom);
}
piix4_acpi_system_hot_add_init(pci_bus);
piix4_acpi_system_hot_add_init(pci_bus, cpu_model);
}
if (i440fx_state) {
@@ -1243,6 +1272,18 @@ static void pc_init1(ram_addr_t ram_size,
}
}
if (extboot_drive) {
DriveInfo *info = extboot_drive;
int cyls, heads, secs;
if (info->type != IF_IDE && info->type != IF_VIRTIO) {
bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs);
bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs);
}
extboot_init(info->bdrv, 1);
}
/* Add virtio console devices */
if (pci_enabled) {
for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
@@ -1251,6 +1292,12 @@ static void pc_init1(ram_addr_t ram_size,
}
}
}
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
if (kvm_enabled()) {
add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
}
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
}
static void pc_init_pci(ram_addr_t ram_size,

25
hw/pc.h
View File

@@ -28,6 +28,7 @@ extern PicState2 *isa_pic;
void pic_set_irq(int irq, int level);
void pic_set_irq_new(void *opaque, int irq, int level);
qemu_irq *i8259_init(qemu_irq parent_irq);
qemu_irq *kvm_i8259_init(qemu_irq parent_irq);
int pic_read_irq(PicState2 *s);
void pic_update_irq(PicState2 *s);
uint32_t pic_intack_read(PicState2 *s);
@@ -48,6 +49,7 @@ qemu_irq *ioapic_init(void);
void ioapic_set_irq(void *opaque, int vector, int level);
void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void);
void apic_set_irq_delivered(void);
/* i8254.c */
@@ -62,8 +64,12 @@ int pit_get_initial_count(PITState *pit, int channel);
int pit_get_mode(PITState *pit, int channel);
int pit_get_out(PITState *pit, int channel, int64_t current_time);
void hpet_pit_disable(void);
void hpet_pit_enable(void);
/* i8254-kvm.c */
PITState *kvm_pit_init(int base, qemu_irq irq);
void hpet_disable_pit(void);
void hpet_enable_pit(void);
/* vmport.c */
void vmport_init(void);
@@ -93,6 +99,7 @@ extern int fd_bootchk;
void ioport_set_a20(int enable);
int ioport_get_a20(void);
CPUState *pc_new_cpu(const char *cpu_model);
/* acpi.c */
extern int acpi_enabled;
@@ -106,7 +113,7 @@ int acpi_table_add(const char *table_desc);
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void piix4_acpi_system_hot_add_init(PCIBus *bus);
void piix4_acpi_system_hot_add_init(PCIBus *bus, const char *model);
/* hpet.c */
extern int no_hpet;
@@ -116,6 +123,9 @@ void pcspk_init(PITState *);
int pcspk_audio_init(qemu_irq *pic);
/* piix_pci.c */
/* config space register for IRQ routing */
#define PIIX_CONFIG_IRQ_ROUTE 0x60
struct PCII440FXState;
typedef struct PCII440FXState PCII440FXState;
@@ -127,6 +137,10 @@ void i440fx_init_memory_mappings(PCII440FXState *d);
extern PCIDevice *piix4_dev;
int piix4_init(PCIBus *bus, int devfn);
int piix_get_irq(int pin);
int ipf_map_irq(PCIDevice *pci_dev, int irq_num);
/* vga.c */
enum vga_retrace_method {
VGA_RETRACE_DUMB,
@@ -149,5 +163,10 @@ void isa_cirrus_vga_init(void);
void isa_ne2000_init(int base, int irq, NICInfo *nd);
/* extboot.c */
void extboot_init(BlockDriverState *bs, int cmd);
int cpu_is_bsp(CPUState *env);
#endif

View File

@@ -34,6 +34,7 @@
#include "virtio-blk.h"
#include "qemu-config.h"
#include "qemu-objects.h"
#include "device-assignment.h"
#if defined(TARGET_I386)
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -225,6 +226,24 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
return dev;
}
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
static PCIDevice *qemu_pci_hot_assign_device(Monitor *mon,
const char *devaddr,
const char *opts_str)
{
QemuOpts *opts;
DeviceState *dev;
opts = add_assigned_device(opts_str);
if (opts == NULL) {
monitor_printf(mon, "Error adding device; check syntax\n");
return NULL;
}
dev = qdev_device_add(opts);
return DO_UPCAST(PCIDevice, qdev, dev);
}
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
void pci_device_hot_add_print(Monitor *mon, const QObject *data)
{
QDict *qdict;
@@ -277,6 +296,10 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
else if (strcmp(type, "storage") == 0)
dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
else if (strcmp(type, "host") == 0)
dev = qemu_pci_hot_assign_device(mon, pci_addr, opts);
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
else
monitor_printf(mon, "invalid type: %s\n", type);

158
hw/pci.c
View File

@@ -27,6 +27,9 @@
#include "net.h"
#include "sysemu.h"
#include "loader.h"
#include "qemu-kvm.h"
#include "hw/pc.h"
#include "device-assignment.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -317,7 +320,7 @@ static VMStateInfo vmstate_info_pci_config = {
static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
{
PCIDevice *s = container_of(pv, PCIDevice, config);
PCIDevice *s = container_of(pv, PCIDevice, irq_state);
uint32_t irq_state[PCI_NUM_PINS];
int i;
for (i = 0; i < PCI_NUM_PINS; ++i) {
@@ -339,7 +342,7 @@ static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
{
int i;
PCIDevice *s = container_of(pv, PCIDevice, config);
PCIDevice *s = container_of(pv, PCIDevice, irq_state);
for (i = 0; i < PCI_NUM_PINS; ++i) {
qemu_put_be32(f, pci_irq_state(s, i));
@@ -423,6 +426,7 @@ static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
}
/*
* Parse pci address in qemu command
* Parse [[<domain>:]<bus>:]<slot>, return -1 on error
*/
static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
@@ -471,6 +475,55 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
return 0;
}
/*
* Parse device bdf in device assignment command:
*
* -pcidevice host=bus:dev.func
*
* Parse <bus>:<slot>.<func> return -1 on error
*/
int pci_parse_host_devaddr(const char *addr, int *busp,
int *slotp, int *funcp)
{
const char *p;
char *e;
int val;
int bus = 0, slot = 0, func = 0;
p = addr;
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == ':') {
bus = val;
p = e + 1;
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == '.') {
slot = val;
p = e + 1;
val = strtoul(p, &e, 16);
if (e == p)
return -1;
func = val;
} else
return -1;
} else
return -1;
if (bus > 0xff || slot > 0x1f || func > 0x7)
return -1;
if (*e)
return -1;
*busp = bus;
*slotp = slot;
*funcp = func;
return 0;
}
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp)
{
@@ -947,25 +1000,80 @@ static void pci_update_mappings(PCIDevice *d)
}
}
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len)
static uint32_t pci_read_config(PCIDevice *d,
uint32_t address, int len)
{
uint32_t val = 0;
assert(len == 1 || len == 2 || len == 4);
len = MIN(len, pci_config_size(d) - address);
memcpy(&val, d->config + address, len);
return le32_to_cpu(val);
}
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len)
{
assert(len == 1 || len == 2 || len == 4);
if (pci_access_cap_config(d, address, len)) {
return d->cap.config_read(d, address, len);
}
return pci_read_config(d, address, len);
}
static void pci_write_config(PCIDevice *pci_dev,
uint32_t address, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
pci_dev->config[address + i] = val & 0xff;
val >>= 8;
}
}
int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len)
{
if (pci_dev->cap.supported && address >= pci_dev->cap.start &&
(address + len) < pci_dev->cap.start + pci_dev->cap.length)
return 1;
return 0;
}
uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
uint32_t address, int len)
{
return pci_read_config(pci_dev, address, len);
}
void pci_default_cap_write_config(PCIDevice *pci_dev,
uint32_t address, uint32_t val, int len)
{
pci_write_config(pci_dev, address, val, len);
}
void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
{
int i;
uint32_t config_size = pci_config_size(d);
if (pci_access_cap_config(d, addr, l)) {
d->cap.config_write(d, addr, val, l);
return;
}
for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
uint8_t wmask = d->wmask[addr + i];
d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
}
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
if (kvm_enabled() && kvm_irqchip_in_kernel() &&
addr >= PIIX_CONFIG_IRQ_ROUTE &&
addr < PIIX_CONFIG_IRQ_ROUTE + 4)
assigned_dev_update_irqs();
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
@@ -986,11 +1094,20 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
if (!change)
return;
#if defined(TARGET_IA64)
ioapic_set_irq(pci_dev, irq_num, level);
#endif
pci_set_irq_state(pci_dev, irq_num, level);
pci_update_irq_status(pci_dev);
pci_change_irq_level(pci_dev, irq_num, change);
}
int pci_map_irq(PCIDevice *pci_dev, int pin)
{
return pci_dev->bus->map_irq(pci_dev, pin);
}
/***********************************************************/
/* monitor info on PCI */
@@ -1417,6 +1534,37 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
return dev;
}
int pci_enable_capability_support(PCIDevice *pci_dev,
uint32_t config_start,
PCICapConfigReadFunc *config_read,
PCICapConfigWriteFunc *config_write,
PCICapConfigInitFunc *config_init)
{
if (!pci_dev)
return -ENODEV;
pci_dev->config[0x06] |= 0x10; // status = capabilities
if (config_start == 0)
pci_dev->cap.start = PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR;
else if (config_start >= 0x40 && config_start < 0xff)
pci_dev->cap.start = config_start;
else
return -EINVAL;
if (config_read)
pci_dev->cap.config_read = config_read;
else
pci_dev->cap.config_read = pci_default_cap_read_config;
if (config_write)
pci_dev->cap.config_write = config_write;
else
pci_dev->cap.config_write = pci_default_cap_write_config;
pci_dev->cap.supported = 1;
pci_dev->config[PCI_CAPABILITY_LIST] = pci_dev->cap.start;
return config_init(pci_dev);
}
static int pci_find_space(PCIDevice *pdev, uint8_t size)
{
int config_size = pci_config_size(pdev);

View File

@@ -5,11 +5,16 @@
#include "qdev.h"
struct kvm_irq_routing_entry;
/* PCI includes legacy ISA access. */
#include "isa.h"
/* PCI bus */
/* imported from <linux/pci.h> */
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
/* PCI bus */
extern target_phys_addr_t pci_mem_base;
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -82,6 +87,12 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
pcibus_t addr, pcibus_t size, int type);
typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
typedef void PCICapConfigWriteFunc(PCIDevice *pci_dev,
uint32_t address, uint32_t val, int len);
typedef uint32_t PCICapConfigReadFunc(PCIDevice *pci_dev,
uint32_t address, int len);
typedef int PCICapConfigInitFunc(PCIDevice *pci_dev);
typedef struct PCIIORegion {
pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
@@ -160,10 +171,19 @@ typedef struct PCIIORegion {
/* Bits in the PCI Status Register (PCI 2.3 spec) */
#define PCI_STATUS_RESERVED1 0x007
#define PCI_STATUS_INT_STATUS 0x008
#ifndef PCI_STATUS_CAP_LIST
#define PCI_STATUS_CAP_LIST 0x010
#endif
#ifndef PCI_STATUS_66MHZ
#define PCI_STATUS_66MHZ 0x020
#endif
#define PCI_STATUS_RESERVED2 0x040
#ifndef PCI_STATUS_FAST_BACK
#define PCI_STATUS_FAST_BACK 0x080
#endif
#define PCI_STATUS_DEVSEL 0x600
#define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
@@ -192,6 +212,11 @@ enum {
QEMU_PCI_CAP_EXPRESS = 0x2,
};
#define PCI_CAPABILITY_CONFIG_MAX_LENGTH 0x60
#define PCI_CAPABILITY_CONFIG_DEFAULT_START_ADDR 0x40
#define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
#define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
struct PCIDevice {
DeviceState qdev;
/* PCI config space */
@@ -247,6 +272,23 @@ struct PCIDevice {
char *romfile;
ram_addr_t rom_offset;
uint32_t rom_bar;
/* How much space does an MSIX table need. */
/* The spec requires giving the table structure
* a 4K aligned region all by itself. Align it to
* target pages so that drivers can do passthrough
* on the rest of the region. */
target_phys_addr_t msix_page_size;
struct kvm_irq_routing_entry *msix_irq_entries;
/* Device capability configuration space */
struct {
int supported;
unsigned int start, length;
PCICapConfigReadFunc *config_read;
PCICapConfigWriteFunc *config_write;
} cap;
};
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -258,6 +300,14 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size, int type,
PCIMapIORegionFunc *map_func);
int pci_enable_capability_support(PCIDevice *pci_dev,
uint32_t config_start,
PCICapConfigReadFunc *config_read,
PCICapConfigWriteFunc *config_write,
PCICapConfigInitFunc *config_init);
int pci_map_irq(PCIDevice *pci_dev, int pin);
int pci_add_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
@@ -266,13 +316,17 @@ void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
void pci_default_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len);
void pci_device_save(PCIDevice *s, QEMUFile *f);
int pci_device_load(PCIDevice *s, QEMUFile *f);
uint32_t pci_default_cap_read_config(PCIDevice *pci_dev,
uint32_t address, int len);
void pci_default_cap_write_config(PCIDevice *pci_dev,
uint32_t address, uint32_t val, int len);
int pci_access_cap_config(PCIDevice *pci_dev, uint32_t address, int len);
typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -301,6 +355,9 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
int pci_parse_host_devaddr(const char *addr, int *busp,
int *slotp, int *funcp);
void pci_info(Monitor *mon);
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name);

View File

@@ -27,6 +27,8 @@
#include "isa.h"
#include "audio/audio.h"
#include "qemu-timer.h"
#include "i8254.h"
#include "qemu-kvm.h"
#define PCSPK_BUF_LEN 1792
#define PCSPK_SAMPLE_RATE 32000
@@ -48,6 +50,43 @@ typedef struct {
static const char *s_spk = "pcspk";
static PCSpkState pcspk_state;
#ifdef CONFIG_KVM_PIT
static void kvm_get_pit_ch2(PITState *pit,
struct kvm_pit_state *inkernel_state)
{
struct kvm_pit_state pit_state;
if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
kvm_get_pit(kvm_context, &pit_state);
pit->channels[2].mode = pit_state.channels[2].mode;
pit->channels[2].count = pit_state.channels[2].count;
pit->channels[2].count_load_time = pit_state.channels[2].count_load_time;
pit->channels[2].gate = pit_state.channels[2].gate;
if (inkernel_state) {
memcpy(inkernel_state, &pit_state, sizeof(*inkernel_state));
}
}
}
static void kvm_set_pit_ch2(PITState *pit,
struct kvm_pit_state *inkernel_state)
{
if (kvm_enabled() && qemu_kvm_pit_in_kernel()) {
inkernel_state->channels[2].mode = pit->channels[2].mode;
inkernel_state->channels[2].count = pit->channels[2].count;
inkernel_state->channels[2].count_load_time =
pit->channels[2].count_load_time;
inkernel_state->channels[2].gate = pit->channels[2].gate;
kvm_set_pit(kvm_context, inkernel_state);
}
}
#else
static inline void kvm_get_pit_ch2(PITState *pit,
struct kvm_pit_state *inkernel_state) { }
static inline void kvm_set_pit_ch2(PITState *pit,
struct kvm_pit_state *inkernel_state) { }
#endif
static inline void generate_samples(PCSpkState *s)
{
unsigned int i;
@@ -72,6 +111,8 @@ static void pcspk_callback(void *opaque, int free)
PCSpkState *s = opaque;
unsigned int n;
kvm_get_pit_ch2(s->pit, NULL);
if (pit_get_mode(s->pit, 2) != 3)
return;
@@ -117,6 +158,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
PCSpkState *s = opaque;
int out;
kvm_get_pit_ch2(s->pit, NULL);
s->dummy_refresh_clock ^= (1 << 4);
out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
@@ -125,9 +168,12 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
struct kvm_pit_state inkernel_state;
PCSpkState *s = opaque;
const int gate = val & 1;
kvm_get_pit_ch2(s->pit, &inkernel_state);
s->data_on = (val >> 1) & 1;
pit_set_gate(s->pit, 2, gate);
if (s->voice) {
@@ -135,6 +181,8 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->play_pos = 0;
AUD_set_active_out(s->voice, gate & s->data_on);
}
kvm_set_pit_ch2(s->pit, &inkernel_state);
}
void pcspk_init(PITState *pit)

View File

@@ -29,6 +29,8 @@
#include "isa.h"
#include "sysbus.h"
#include "qemu-kvm.h"
typedef PCIHostState I440FXState;
typedef struct PIIX3State {
@@ -88,6 +90,10 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
int i, r;
uint32_t smram, addr;
if (kvm_enabled()) {
/* FIXME: Support remappings and protection changes. */
return;
}
update_pam(d, 0xf0000, 0x100000, (d->dev.config[0x59] >> 4) & 3);
for(i = 0; i < 12; i++) {
r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
@@ -201,6 +207,8 @@ static int i440fx_initfn(PCIDevice *dev)
return 0;
}
static PIIX3State *piix3_dev;
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
{
DeviceState *dev;
@@ -226,6 +234,8 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
*piix3_devfn = piix3->dev.devfn;
piix3_dev = piix3;
return b;
}
@@ -253,6 +263,13 @@ static void piix3_set_irq(void *opaque, int irq_num, int level)
}
}
int piix_get_irq(int pin)
{
if (piix3_dev)
return piix3_dev->dev.config[0x60+pin];
return 0;
}
static void piix3_reset(void *opaque)
{
PIIX3State *d = opaque;

View File

@@ -20,6 +20,7 @@
#include "ppc405.h"
#include "sysemu.h"
#include "kvm.h"
#include "qemu-kvm.h"
#define PPC440EP_PCI_CONFIG 0xeec00000
#define PPC440EP_PCI_INTACK 0xeed00000

View File

@@ -24,6 +24,7 @@
#include "device_tree.h"
#include "loader.h"
#include "elf.h"
#include "qemu-kvm.h"
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"

View File

@@ -31,6 +31,7 @@
#include "ppce500.h"
#include "loader.h"
#include "elf.h"
#include "qemu-kvm.h"
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
#define UIMAGE_LOAD_BASE 0

View File

@@ -434,7 +434,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4);
memset(&outbuf[32], 0, 4);
memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION,
MIN(4, strlen(s->version ? s->version : QEMU_VERSION)));
/* Identify device as SCSI-3 rev 1.
Some later commands are also implemented. */
outbuf[2] = 3;

View File

@@ -396,8 +396,11 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
portb_changed(s, temp);
return;
case SH7750_MMUCR_A7:
s->cpu->mmucr = mem_value;
return;
if (mem_value & MMUCR_TI) {
cpu_sh4_invalidate_tlb(s->cpu);
}
s->cpu->mmucr = mem_value & ~MMUCR_TI;
return;
case SH7750_PTEH_A7:
/* If asid changes, clear all registered tlb entries. */
if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))

View File

@@ -47,10 +47,15 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
pcic->par = val;
break;
case 0x1c4:
pcic->mbr = val;
pcic->mbr = val & 0xff000001;
break;
case 0x1c8:
pcic->iobr = val;
if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
IO_MEM_UNASSIGNED);
pcic->iobr = val & 0xfffc0001;
isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
}
break;
case 0x220:
pci_data_write(pcic->bus, pcic->par, val, 4);
@@ -66,89 +71,16 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
case 0x1c0:
return pcic->par;
case 0x1c4:
return pcic->mbr;
case 0x1c8:
return pcic->iobr;
case 0x220:
return pci_data_read(pcic->bus, pcic->par, 4);
}
return 0;
}
static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr,
uint32_t val, int size)
{
pci_data_write(pcic->bus, addr + pcic->mbr, val, size);
}
static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr,
int size)
{
return pci_data_read(pcic->bus, addr + pcic->mbr, size);
}
static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val)
{
sh_pci_data_write(p, addr, val, 1);
}
static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val)
{
sh_pci_data_write(p, addr, val, 2);
}
static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val)
{
sh_pci_data_write(p, addr, val, 4);
}
static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr)
{
return sh_pci_mem_read(p, addr, 1);
}
static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr)
{
return sh_pci_mem_read(p, addr, 2);
}
static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr)
{
return sh_pci_mem_read(p, addr, 4);
}
static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr)
{
return addr + pcic->iobr;
}
static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val)
{
cpu_outb(sh_pci_addr2port(p, addr), val);
}
static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val)
{
cpu_outw(sh_pci_addr2port(p, addr), val);
}
static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val)
{
cpu_outl(sh_pci_addr2port(p, addr), val);
}
static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr)
{
return cpu_inb(sh_pci_addr2port(p, addr));
}
static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr)
{
return cpu_inw(sh_pci_addr2port(p, addr));
}
static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr)
{
return cpu_inl(sh_pci_addr2port(p, addr));
}
typedef struct {
CPUReadMemoryFunc * const r[3];
CPUWriteMemoryFunc * const w[3];
@@ -159,21 +91,11 @@ static MemOp sh_pci_reg = {
{ NULL, NULL, sh_pci_reg_write },
};
static MemOp sh_pci_mem = {
{ sh_pci_readb, sh_pci_readw, sh_pci_readl },
{ sh_pci_writeb, sh_pci_writew, sh_pci_writel },
};
static MemOp sh_pci_iop = {
{ sh_pci_inb, sh_pci_inw, sh_pci_inl },
{ sh_pci_outb, sh_pci_outw, sh_pci_outl },
};
PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *opaque, int devfn_min, int nirq)
{
SHPCIC *p;
int mem, reg, iop;
int reg;
p = qemu_mallocz(sizeof(SHPCIC));
p->bus = pci_register_bus(NULL, "pci",
@@ -182,14 +104,11 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
-1, NULL, NULL);
reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p);
iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p);
mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p);
cpu_register_physical_memory(0x1e200000, 0x224, reg);
cpu_register_physical_memory(0x1e240000, 0x40000, iop);
cpu_register_physical_memory(0x1d000000, 0x1000000, mem);
cpu_register_physical_memory(0xfe200000, 0x224, reg);
cpu_register_physical_memory(0xfe240000, 0x40000, iop);
cpu_register_physical_memory(0xfd000000, 0x1000000, mem);
p->iobr = 0xfe240000;
isa_mmio_init(p->iobr, 0x40000);
pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);

63
hw/testdev.c Normal file
View File

@@ -0,0 +1,63 @@
#include "hw.h"
#include "qdev.h"
#include "isa.h"
struct testdev {
ISADevice dev;
CharDriverState *chr;
};
static void test_device_serial_write(void *opaque, uint32_t addr, uint32_t data)
{
struct testdev *dev = opaque;
uint8_t buf[1] = { data };
if (dev->chr) {
qemu_chr_write(dev->chr, buf, 1);
}
}
static void test_device_exit(void *opaque, uint32_t addr, uint32_t data)
{
exit(data);
}
static uint32_t test_device_memsize_read(void *opaque, uint32_t addr)
{
return ram_size;
}
static void test_device_irq_line(void *opaque, uint32_t addr, uint32_t data)
{
extern qemu_irq *ioapic_irq_hack;
qemu_set_irq(ioapic_irq_hack[addr - 0x2000], !!data);
}
static int init_test_device(ISADevice *isa)
{
struct testdev *dev = DO_UPCAST(struct testdev, dev, isa);
register_ioport_write(0xf1, 1, 1, test_device_serial_write, dev);
register_ioport_write(0xf4, 1, 4, test_device_exit, dev);
register_ioport_read(0xd1, 1, 4, test_device_memsize_read, dev);
register_ioport_write(0x2000, 24, 1, test_device_irq_line, NULL);
return 0;
}
static ISADeviceInfo testdev_info = {
.qdev.name = "testdev",
.qdev.size = sizeof(struct testdev),
.init = init_test_device,
.qdev.props = (Property[]) {
DEFINE_PROP_CHR("chardev", struct testdev, chr),
DEFINE_PROP_END_OF_LIST(),
},
};
static void testdev_register_devices(void)
{
isa_qdev_register(&testdev_info);
}
device_init(testdev_register_devices)

View File

@@ -102,6 +102,9 @@ USBDevice *usb_create(USBBus *bus, const char *name)
USBDevice *usb_create_simple(USBBus *bus, const char *name)
{
USBDevice *dev = usb_create(bus, name);
if (!dev) {
hw_error("Failed to create USB device '%s'\n", name);
}
qdev_init_nofail(&dev->qdev);
return dev;
}
@@ -261,7 +264,8 @@ USBDevice *usbdevice_create(const char *cmdline)
USBBus *bus = usb_bus_find(-1 /* any */);
DeviceInfo *info;
USBDeviceInfo *usb;
char driver[32], *params;
char driver[32];
const char *params;
int len;
params = strchr(cmdline,':');
@@ -272,6 +276,7 @@ USBDevice *usbdevice_create(const char *cmdline)
len = sizeof(driver);
pstrcpy(driver, len, cmdline);
} else {
params = "";
pstrcpy(driver, sizeof(driver), cmdline);
}
@@ -294,7 +299,7 @@ USBDevice *usbdevice_create(const char *cmdline)
}
if (!usb->usbdevice_init) {
if (params) {
if (*params) {
qemu_error("usbdevice %s accepts no params\n", driver);
return NULL;
}

View File

@@ -592,6 +592,9 @@ static USBDevice *usb_msd_init(const char *filename)
/* create guest device */
dev = usb_create(NULL /* FIXME */, "usb-storage");
if (!dev) {
return NULL;
}
qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
if (qdev_init(&dev->qdev) < 0)
return NULL;

View File

@@ -1491,6 +1491,9 @@ static USBDevice *usb_net_init(const char *cmdline)
}
dev = usb_create(NULL /* FIXME */, "usb-net");
if (!dev) {
return NULL;
}
qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
qdev_init_nofail(&dev->qdev);
return dev;

View File

@@ -594,6 +594,9 @@ static USBDevice *usb_serial_init(const char *filename)
return NULL;
dev = usb_create(NULL /* FIXME */, "usb-serial");
if (!dev) {
return NULL;
}
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
if (vendorid)
qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);

View File

@@ -677,9 +677,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
ret = async->packet.len;
if (td->ctrl & TD_CTRL_IOC)
*int_mask |= 0x01;
if (td->ctrl & TD_CTRL_IOS)
td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -693,6 +690,8 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
here. The docs are somewhat unclear, but win2k relies on this
behavior. */
td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
if (td->ctrl & TD_CTRL_IOC)
*int_mask |= 0x01;
if (pid == USB_TOKEN_IN) {
if (len > max_len) {
@@ -750,6 +749,8 @@ out:
if (err == 0) {
td->ctrl &= ~TD_CTRL_ACTIVE;
s->status |= UHCI_STS_USBERR;
if (td->ctrl & TD_CTRL_IOC)
*int_mask |= 0x01;
uhci_update_irq(s);
}
}

View File

@@ -68,9 +68,11 @@ static void pci_vga_write_config(PCIDevice *d,
PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
VGACommonState *s = &pvs->vga;
vga_dirty_log_stop(s);
pci_default_write_config(d, address, val, len);
if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
s->map_addr = 0;
vga_dirty_log_start(s);
}
static int pci_vga_initfn(PCIDevice *dev)

View File

@@ -1277,6 +1277,8 @@ static void vga_draw_text(VGACommonState *s, int full_update)
vga_draw_glyph8_func *vga_draw_glyph8;
vga_draw_glyph9_func *vga_draw_glyph9;
vga_dirty_log_stop(s);
/* compute font data address (in plane 2) */
v = s->sr[3];
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
@@ -1589,40 +1591,65 @@ static void vga_sync_dirty_bitmap(VGACommonState *s)
}
#endif
vga_dirty_log_start(s);
}
static int s1, s2, s3;
static void mark_dirty(target_phys_addr_t start, target_phys_addr_t len)
{
target_phys_addr_t end = start + len;
while (start < end) {
cpu_physical_memory_set_dirty(cpu_get_physical_page_desc(start));
start += TARGET_PAGE_SIZE;
}
}
void vga_dirty_log_start(VGACommonState *s)
{
if (kvm_enabled() && s->map_addr)
kvm_log_start(s->map_addr, s->map_end - s->map_addr);
if (!s1) {
kvm_log_start(s->map_addr, s->map_end - s->map_addr);
mark_dirty(s->map_addr, s->map_end - s->map_addr);
s1 = 1;
}
if (kvm_enabled() && s->lfb_vram_mapped) {
kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
if (!s2) {
kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
mark_dirty(isa_mem_base + 0xa0000, 0x10000);
}
s2 = 1;
}
#ifdef CONFIG_BOCHS_VBE
if (kvm_enabled() && s->vbe_mapped) {
kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
if (!s3) {
kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
}
s3 = 1;
}
#endif
}
void vga_dirty_log_stop(VGACommonState *s)
{
if (kvm_enabled() && s->map_addr)
if (kvm_enabled() && s->map_addr && s1)
kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
if (kvm_enabled() && s->lfb_vram_mapped) {
if (kvm_enabled() && s->lfb_vram_mapped && s2) {
kvm_log_stop(isa_mem_base + 0xa0000, 0x80000);
kvm_log_stop(isa_mem_base + 0xa8000, 0x80000);
}
#ifdef CONFIG_BOCHS_VBE
if (kvm_enabled() && s->vbe_mapped) {
if (kvm_enabled() && s->vbe_mapped && s3) {
kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
}
#endif
s1 = s2 = s3 = 0;
}
void vga_dirty_log_restart(VGACommonState *s)
@@ -1860,6 +1887,7 @@ static void vga_draw_blank(VGACommonState *s, int full_update)
return;
if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
return;
vga_dirty_log_stop(s);
s->rgb_to_pixel =
rgb_to_pixel_dup_table[get_depth_index(s->ds)];
@@ -1904,6 +1932,9 @@ static void vga_update_display(void *opaque)
vga_draw_text(s, full_update);
break;
case GMODE_GRAPH:
#ifdef TARGET_IA64
full_update = 1;
#endif
vga_draw_graphic(s, full_update);
break;
case GMODE_BLANK:

View File

@@ -33,8 +33,8 @@
/* bochs VBE support */
#define CONFIG_BOCHS_VBE
#define VBE_DISPI_MAX_XRES 1600
#define VBE_DISPI_MAX_YRES 1200
#define VBE_DISPI_MAX_XRES 2560
#define VBE_DISPI_MAX_YRES 1600
#define VBE_DISPI_MAX_BPP 32
#define VBE_DISPI_INDEX_ID 0x0
@@ -224,7 +224,7 @@ void vga_init_vbe(VGACommonState *s);
extern const uint8_t sr_mask[8];
extern const uint8_t gr_mask[16];
#define VGA_RAM_SIZE (8192 * 1024)
#define VGA_RAM_SIZE (16 * 1024 * 1024)
#define VGABIOS_FILENAME "vgabios.bin"
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"

View File

@@ -19,6 +19,7 @@
#include "balloon.h"
#include "virtio-balloon.h"
#include "kvm.h"
#include "qemu-kvm.h"
#if defined(__linux__)
#include <sys/mman.h>

View File

@@ -278,10 +278,20 @@ static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
}
}
static void virtio_blk_handle_flush(VirtIOBlockReq *req)
static void virtio_blk_handle_flush(BlockRequest *blkreq, int *num_writes,
VirtIOBlockReq *req, BlockDriverState **old_bs)
{
BlockDriverAIOCB *acb;
/*
* Make sure all outstanding writes are posted to the backing device.
*/
if (*old_bs != NULL) {
do_multiwrite(*old_bs, blkreq, *num_writes);
}
*num_writes = 0;
*old_bs = req->dev->bs;
acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
if (!acb) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
@@ -344,7 +354,8 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
if (req->out->type & VIRTIO_BLK_T_FLUSH) {
virtio_blk_handle_flush(req);
virtio_blk_handle_flush(mrb->blkreq, &mrb->num_writes,
req, &mrb->old_bs);
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
virtio_blk_handle_scsi(req);
} else if (req->out->type & VIRTIO_BLK_T_OUT) {

View File

@@ -129,6 +129,9 @@ VirtIODevice *virtio_console_init(DeviceState *dev)
s = (VirtIOConsole *)virtio_common_init("virtio-console",
VIRTIO_ID_CONSOLE,
0, sizeof(VirtIOConsole));
if (s == NULL)
return NULL;
s->vdev.get_features = virtio_console_get_features;
s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);

View File

@@ -21,10 +21,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "isa.h"
#include "pc.h"
#include "sysemu.h"
#include "qemu-kvm.h"
//#define VMPORT_DEBUG
@@ -57,6 +59,10 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr)
CPUState *env = cpu_single_env;
unsigned char command;
uint32_t eax;
uint32_t ret;
if (kvm_enabled())
kvm_save_registers(env);
eax = env->regs[R_EAX];
if (eax != VMPORT_MAGIC)
@@ -73,7 +79,12 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr)
return eax;
}
return s->func[command](s->opaque[command], addr);
ret = s->func[command](s->opaque[command], addr);
if (kvm_enabled())
kvm_load_registers(env);
return ret;
}
static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val)

16
i386.ld
View File

@@ -39,8 +39,20 @@ SECTIONS
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.rel.plt :
{
*(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.init : { *(.init) } =0x47ff041f
.text :
{

View File

@@ -7,7 +7,7 @@ ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS;
PROVIDE (__executable_start = 0x4000000060000000); . = 0x4000000060000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }

150
ia64intrin.h Normal file
View File

@@ -0,0 +1,150 @@
#ifndef IA64_INTRINSIC_H
#define IA64_INTRINSIC_H
/*
* Compiler-dependent Intrinsics
*
* Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com>
* Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com>
*
*/
extern long ia64_cmpxchg_called_with_bad_pointer (void);
extern void ia64_bad_param_for_getreg (void);
#define ia64_cmpxchg(sem,ptr,o,n,s) ({ \
uint64_t _o, _r; \
switch(s) { \
case 1: _o = (uint8_t)(long)(o); break; \
case 2: _o = (uint16_t)(long)(o); break; \
case 4: _o = (uint32_t)(long)(o); break; \
case 8: _o = (uint64_t)(long)(o); break; \
default: break; \
} \
switch(s) { \
case 1: \
_r = ia64_cmpxchg1_##sem((uint8_t*)ptr,n,_o); break; \
case 2: \
_r = ia64_cmpxchg2_##sem((uint16_t*)ptr,n,_o); break; \
case 4: \
_r = ia64_cmpxchg4_##sem((uint32_t*)ptr,n,_o); break; \
case 8: \
_r = ia64_cmpxchg8_##sem((uint64_t*)ptr,n,_o); break; \
default: \
_r = ia64_cmpxchg_called_with_bad_pointer(); break; \
} \
(__typeof__(o)) _r; \
})
#define cmpxchg_acq(ptr,o,n) ia64_cmpxchg(acq,ptr,o,n,sizeof(*ptr))
#define cmpxchg_rel(ptr,o,n) ia64_cmpxchg(rel,ptr,o,n,sizeof(*ptr))
#ifdef __INTEL_COMPILER
void __fc(uint64_t *addr);
void __synci(void);
void __isrlz(void);
void __dsrlz(void);
uint64_t __getReg(const int whichReg);
uint64_t _InterlockedCompareExchange8_rel(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange8_acq(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange16_rel(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange16_acq(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange_rel(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange_acq(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange64_rel(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
u64_t _InterlockedCompareExchange64_acq(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
#define ia64_cmpxchg1_rel _InterlockedCompareExchange8_rel
#define ia64_cmpxchg1_acq _InterlockedCompareExchange8_acq
#define ia64_cmpxchg2_rel _InterlockedCompareExchange16_rel
#define ia64_cmpxchg2_acq _InterlockedCompareExchange16_acq
#define ia64_cmpxchg4_rel _InterlockedCompareExchange_rel
#define ia64_cmpxchg4_acq _InterlockedCompareExchange_acq
#define ia64_cmpxchg8_rel _InterlockedCompareExchange64_rel
#define ia64_cmpxchg8_acq _InterlockedCompareExchange64_acq
#define ia64_srlz_d __dsrlz
#define ia64_srlz_i __isrlz
#define __ia64_fc __fc
#define ia64_sync_i __synci
#define __ia64_getreg __getReg
#else /* __INTEL_COMPILER */
#define ia64_cmpxchg1_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg1_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg1.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg2_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg2.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg2_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
\
asm volatile ("cmpxchg2.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg4_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg4.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg4_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg4.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg8_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg8.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg8_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
\
asm volatile ("cmpxchg8.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory")
#define ia64_srlz_d() asm volatile (";; srlz.d" ::: "memory");
#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory")
#endif /* __INTEL_COMPILER */
#endif /* IA64_INTRINSIC_H */

View File

@@ -266,7 +266,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
peek = qlist_peek(working);
key = parse_value(ctxt, &working, ap);
if (qobject_type(key) != QTYPE_QSTRING) {
if (!key || qobject_type(key) != QTYPE_QSTRING) {
parse_error(ctxt, peek, "key is not a string in object");
goto out;
}

View File

@@ -26,6 +26,7 @@
#include "gdbstub.h"
#include "kvm.h"
#ifdef KVM_UPSTREAM
/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
#define PAGE_SIZE TARGET_PAGE_SIZE
@@ -57,7 +58,6 @@ struct KVMState
KVMSlot slots[32];
int fd;
int vmfd;
int regs_modified;
int coalesced_mmio;
int broken_set_mem_region;
int migration_log;
@@ -157,12 +157,14 @@ static void kvm_reset_vcpu(void *opaque)
abort();
}
}
#endif
int kvm_irqchip_in_kernel(void)
{
return kvm_state->irqchip_in_kernel;
}
#ifdef KVM_UPSTREAM
int kvm_pit_in_kernel(void)
{
return kvm_state->pit_in_kernel;
@@ -343,6 +345,7 @@ int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
return ret;
}
#endif
int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
{
@@ -393,6 +396,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
return ret;
}
#ifdef KVM_UPSTREAM
int kvm_init(int smp_cpus)
{
@@ -504,6 +508,7 @@ err:
return ret;
}
#endif
static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
uint32_t count)
@@ -544,6 +549,7 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
return 1;
}
#ifdef KVM_UPSTREAM
static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run)
{
#ifdef KVM_CAP_COALESCED_MMIO
@@ -812,6 +818,7 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
}
}
#endif
int kvm_ioctl(KVMState *s, int type, ...)
{
int ret;
@@ -879,6 +886,7 @@ int kvm_has_vcpu_events(void)
return kvm_state->vcpu_events;
}
#ifdef KVM_UPSTREAM
void kvm_setup_guest_memory(void *start, size_t size)
{
if (!kvm_has_sync_mmu()) {
@@ -897,7 +905,11 @@ void kvm_setup_guest_memory(void *start, size_t size)
}
}
#endif /* KVM_UPSTREAM */
#ifdef KVM_CAP_SET_GUEST_DEBUG
#ifdef KVM_UPSTREAM
static void on_vcpu(CPUState *env, void (*func)(void *data), void *data)
{
#ifdef CONFIG_IOTHREAD
@@ -910,6 +922,7 @@ static void on_vcpu(CPUState *env, void (*func)(void *data), void *data)
func(data);
#endif
}
#endif /* KVM_UPSTREAM */
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
target_ulong pc)
@@ -928,6 +941,8 @@ int kvm_sw_breakpoints_active(CPUState *env)
return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
}
#ifdef KVM_UPSTREAM
struct kvm_set_guest_debug_data {
struct kvm_guest_debug dbg;
CPUState *env;
@@ -961,6 +976,7 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
on_vcpu(env, kvm_invoke_set_guest_debug, &data);
return data.err;
}
#endif
int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
target_ulong len, int type)
@@ -1085,3 +1101,5 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
{
}
#endif /* !KVM_CAP_SET_GUEST_DEBUG */
#include "qemu-kvm.c"

410
kvm-tpr-opt.c Normal file
View File

@@ -0,0 +1,410 @@
/*
* tpr optimization for qemu/kvm
*
* Copyright (C) 2007-2008 Qumranet Technologies
*
* Licensed under the terms of the GNU GPL version 2 or higher.
*/
#include "config.h"
#include "config-host.h"
#include <string.h>
#include "hw/hw.h"
#include "hw/isa.h"
#include "sysemu.h"
#include "qemu-kvm.h"
#include "cpu.h"
#include <stdio.h>
static uint64_t map_addr(struct kvm_sregs *sregs, target_ulong virt, unsigned *perms)
{
uint64_t mask = ((1ull << 48) - 1) & ~4095ull;
uint64_t p, pp = 7;
p = sregs->cr3;
if (sregs->cr4 & 0x20) {
p &= ~31ull;
p = ldq_phys(p + 8 * (virt >> 30));
if (!(p & 1))
return -1ull;
p &= mask;
p = ldq_phys(p + 8 * ((virt >> 21) & 511));
if (!(p & 1))
return -1ull;
pp &= p;
if (p & 128) {
p += ((virt >> 12) & 511) << 12;
} else {
p &= mask;
p = ldq_phys(p + 8 * ((virt >> 12) & 511));
if (!(p & 1))
return -1ull;
pp &= p;
}
} else {
p &= mask;
p = ldl_phys(p + 4 * ((virt >> 22) & 1023));
if (!(p & 1))
return -1ull;
pp &= p;
if (p & 128) {
p += ((virt >> 12) & 1023) << 12;
} else {
p &= mask;
p = ldl_phys(p + 4 * ((virt >> 12) & 1023));
pp &= p;
if (!(p & 1))
return -1ull;
}
}
if (perms)
*perms = pp >> 1;
p &= mask;
return p + (virt & 4095);
}
static uint8_t read_byte_virt(CPUState *env, target_ulong virt)
{
struct kvm_sregs sregs;
kvm_get_sregs(env, &sregs);
return ldub_phys(map_addr(&sregs, virt, NULL));
}
static void write_byte_virt(CPUState *env, target_ulong virt, uint8_t b)
{
struct kvm_sregs sregs;
kvm_get_sregs(env, &sregs);
stb_phys(map_addr(&sregs, virt, NULL), b);
}
static __u64 kvm_rsp_read(CPUState *env)
{
struct kvm_regs regs;
kvm_get_regs(env, &regs);
return regs.rsp;
}
struct vapic_bios {
char signature[8];
uint32_t virt_base;
uint32_t fixup_start;
uint32_t fixup_end;
uint32_t vapic;
uint32_t vapic_size;
uint32_t vcpu_shift;
uint32_t real_tpr;
struct vapic_patches {
uint32_t set_tpr;
uint32_t set_tpr_eax;
uint32_t get_tpr[8];
uint32_t get_tpr_stack;
} __attribute__((packed)) up, mp;
} __attribute__((packed));
static struct vapic_bios vapic_bios;
static uint32_t real_tpr;
static uint32_t bios_addr;
static uint32_t vapic_phys;
static uint32_t bios_enabled;
static uint32_t vbios_desc_phys;
static uint32_t vapic_bios_addr;
static void update_vbios_real_tpr(void)
{
cpu_physical_memory_rw(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios, 0);
vapic_bios.real_tpr = real_tpr;
vapic_bios.vcpu_shift = 7;
cpu_physical_memory_rw(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios, 1);
}
static unsigned modrm_reg(uint8_t modrm)
{
return (modrm >> 3) & 7;
}
static int is_abs_modrm(uint8_t modrm)
{
return (modrm & 0xc7) == 0x05;
}
static int instruction_is_ok(CPUState *env, uint64_t rip, int is_write)
{
uint8_t b1, b2;
unsigned addr_offset;
uint32_t addr;
uint64_t p;
if ((rip & 0xf0000000) != 0x80000000 && (rip & 0xf0000000) != 0xe0000000)
return 0;
if (kvm_rsp_read(env) == 0)
return 0;
b1 = read_byte_virt(env, rip);
b2 = read_byte_virt(env, rip + 1);
switch (b1) {
case 0xc7: /* mov imm32, r/m32 (c7/0) */
if (modrm_reg(b2) != 0)
return 0;
/* fall through */
case 0x89: /* mov r32 to r/m32 */
case 0x8b: /* mov r/m32 to r32 */
if (!is_abs_modrm(b2))
return 0;
addr_offset = 2;
break;
case 0xa1: /* mov abs to eax */
case 0xa3: /* mov eax to abs */
addr_offset = 1;
break;
case 0xff: /* push r/m32 */
if (modrm_reg(b2) != 6 || !is_abs_modrm(b2))
return 0;
addr_offset = 2;
default:
return 0;
}
p = rip + addr_offset;
addr = read_byte_virt(env, p++);
addr |= read_byte_virt(env, p++) << 8;
addr |= read_byte_virt(env, p++) << 16;
addr |= read_byte_virt(env, p++) << 24;
if ((addr & 0xfff) != 0x80)
return 0;
real_tpr = addr;
update_vbios_real_tpr();
return 1;
}
static int bios_is_mapped(CPUState *env, uint64_t rip)
{
uint32_t probe;
uint64_t phys;
struct kvm_sregs sregs;
unsigned perms;
uint32_t i;
uint32_t offset, fixup, start = vapic_bios_addr ? : 0xe0000;
if (bios_enabled)
return 1;
kvm_get_sregs(env, &sregs);
probe = (rip & 0xf0000000) + start;
phys = map_addr(&sregs, probe, &perms);
if (phys != start)
return 0;
bios_addr = probe;
for (i = 0; i < 64; ++i) {
cpu_physical_memory_read(phys, (void *)&vapic_bios, sizeof(vapic_bios));
if (memcmp(vapic_bios.signature, "kvm aPiC", 8) == 0)
break;
phys += 1024;
bios_addr += 1024;
}
if (i == 64)
return 0;
if (bios_addr == vapic_bios.virt_base)
return 1;
vbios_desc_phys = phys;
for (i = vapic_bios.fixup_start; i < vapic_bios.fixup_end; i += 4) {
offset = ldl_phys(phys + i - vapic_bios.virt_base);
fixup = phys + offset;
stl_phys(fixup, ldl_phys(fixup) + bios_addr - vapic_bios.virt_base);
}
vapic_phys = vapic_bios.vapic - vapic_bios.virt_base + phys;
return 1;
}
static int get_pcr_cpu(CPUState *env)
{
uint8_t b;
cpu_synchronize_state(env);
if (cpu_memory_rw_debug(env, env->segs[R_FS].base + 0x51, &b, 1, 0) < 0)
return -1;
return (int)b;
}
int kvm_tpr_enable_vapic(CPUState *env)
{
static uint8_t one = 1;
int pcr_cpu = get_pcr_cpu(env);
if (pcr_cpu < 0)
return 0;
kvm_enable_vapic(env, vapic_phys + (pcr_cpu << 7));
cpu_physical_memory_rw(vapic_phys + (pcr_cpu << 7) + 4, &one, 1, 1);
env->update_vapic = 0;
bios_enabled = 1;
return 1;
}
static int enable_vapic(CPUState *env)
{
bios_enabled = 1;
env->update_vapic = 1;
return 1;
}
static void patch_call(CPUState *env, uint64_t rip, uint32_t target)
{
uint32_t offset;
offset = target - vapic_bios.virt_base + bios_addr - rip - 5;
write_byte_virt(env, rip, 0xe8); /* call near */
write_byte_virt(env, rip + 1, offset);
write_byte_virt(env, rip + 2, offset >> 8);
write_byte_virt(env, rip + 3, offset >> 16);
write_byte_virt(env, rip + 4, offset >> 24);
}
static void patch_instruction(CPUState *env, uint64_t rip)
{
uint8_t b1, b2;
struct vapic_patches *vp;
vp = smp_cpus == 1 ? &vapic_bios.up : &vapic_bios.mp;
b1 = read_byte_virt(env, rip);
b2 = read_byte_virt(env, rip + 1);
switch (b1) {
case 0x89: /* mov r32 to r/m32 */
write_byte_virt(env, rip, 0x50 + modrm_reg(b2)); /* push reg */
patch_call(env, rip + 1, vp->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
write_byte_virt(env, rip, 0x90);
patch_call(env, rip + 1, vp->get_tpr[modrm_reg(b2)]);
break;
case 0xa1: /* mov abs to eax */
patch_call(env, rip, vp->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
patch_call(env, rip, vp->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
write_byte_virt(env, rip, 0x68); /* push imm32 */
write_byte_virt(env, rip + 1, read_byte_virt(env, rip+6));
write_byte_virt(env, rip + 2, read_byte_virt(env, rip+7));
write_byte_virt(env, rip + 3, read_byte_virt(env, rip+8));
write_byte_virt(env, rip + 4, read_byte_virt(env, rip+9));
patch_call(env, rip + 5, vp->set_tpr);
break;
case 0xff: /* push r/m32 */
printf("patching push\n");
write_byte_virt(env, rip, 0x50); /* push eax */
patch_call(env, rip + 1, vp->get_tpr_stack);
break;
default:
printf("funny insn %02x %02x\n", b1, b2);
}
}
void kvm_tpr_access_report(CPUState *env, uint64_t rip, int is_write)
{
if (!instruction_is_ok(env, rip, is_write))
return;
if (!bios_is_mapped(env, rip))
return;
if (!kvm_tpr_enable_vapic(env))
return;
patch_instruction(env, rip);
}
void kvm_tpr_vcpu_start(CPUState *env)
{
kvm_enable_tpr_access_reporting(env);
if (bios_enabled)
kvm_tpr_enable_vapic(env);
}
static void tpr_save(QEMUFile *f, void *s)
{
int i;
for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
qemu_put_be32s(f, &((uint32_t *)&vapic_bios)[i]);
qemu_put_be32s(f, &bios_enabled);
qemu_put_be32s(f, &real_tpr);
qemu_put_be32s(f, &bios_addr);
qemu_put_be32s(f, &vapic_phys);
qemu_put_be32s(f, &vbios_desc_phys);
}
static int tpr_load(QEMUFile *f, void *s, int version_id)
{
int i;
if (version_id != 1)
return -EINVAL;
for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
qemu_get_be32s(f, &((uint32_t *)&vapic_bios)[i]);
qemu_get_be32s(f, &bios_enabled);
qemu_get_be32s(f, &real_tpr);
qemu_get_be32s(f, &bios_addr);
qemu_get_be32s(f, &vapic_phys);
qemu_get_be32s(f, &vbios_desc_phys);
if (bios_enabled) {
CPUState *env = first_cpu->next_cpu;
for (env = first_cpu; env != NULL; env = env->next_cpu)
enable_vapic(env);
}
return 0;
}
static void vtpr_ioport_write16(void *opaque, uint32_t addr, uint32_t val)
{
struct kvm_regs regs;
CPUState *env = cpu_single_env;
struct kvm_sregs sregs;
kvm_get_regs(env, &regs);
kvm_get_sregs(env, &sregs);
vapic_bios_addr = ((sregs.cs.base + regs.rip) & ~(512 - 1)) + val;
bios_enabled = 0;
}
static void vtpr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
CPUState *env = cpu_single_env;
struct kvm_regs regs;
struct kvm_sregs sregs;
uint32_t rip;
kvm_get_regs(env, &regs);
rip = regs.rip - 2;
write_byte_virt(env, rip, 0x66);
write_byte_virt(env, rip + 1, 0x90);
if (bios_enabled)
return;
if (!bios_is_mapped(env, rip))
printf("bios not mapped?\n");
kvm_get_sregs(env, &sregs);
for (addr = 0xfffff000u; addr >= 0x80000000u; addr -= 4096)
if (map_addr(&sregs, addr, NULL) == 0xfee00000u) {
real_tpr = addr + 0x80;
break;
}
bios_enabled = 1;
update_vbios_real_tpr();
kvm_tpr_enable_vapic(env);
}
void kvm_tpr_opt_setup(void)
{
register_savevm("kvm-tpr-opt", 0, 1, tpr_save, tpr_load, NULL);
register_ioport_write(0x7e, 1, 1, vtpr_ioport_write, NULL);
register_ioport_write(0x7e, 2, 2, vtpr_ioport_write16, NULL);
}

12
kvm.h
View File

@@ -16,6 +16,9 @@
#include "config.h"
#include "qemu-queue.h"
#include "qemu-kvm.h"
#ifdef KVM_UPSTREAM
#ifdef CONFIG_KVM
extern int kvm_allowed;
@@ -47,7 +50,12 @@ int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
int kvm_set_migration_log(int enable);
int kvm_has_sync_mmu(void);
#endif /* KVM_UPSTREAM */
int kvm_has_vcpu_events(void);
int kvm_put_vcpu_events(CPUState *env);
int kvm_get_vcpu_events(CPUState *env);
#ifdef KVM_UPSTREAM
void kvm_setup_guest_memory(void *start, size_t size);
@@ -91,7 +99,9 @@ int kvm_arch_init(KVMState *s, int smp_cpus);
int kvm_arch_init_vcpu(CPUState *env);
#endif
void kvm_arch_reset_vcpu(CPUState *env);
#ifdef KVM_UPSTREAM
struct kvm_guest_debug;
struct kvm_debug_exit_arch;
@@ -140,3 +150,5 @@ static inline void cpu_synchronize_state(CPUState *env)
}
#endif
#endif

66
kvm/.gitignore vendored Normal file
View File

@@ -0,0 +1,66 @@
*.o
*.d
*~
*.flat
*.a
config.mak
.*.cmd
qemu/config-host.h
qemu/config-host.mak
user/test/bootstrap
user/kvmctl
qemu/dyngen
qemu/x86_64-softmmu
qemu/qemu-img
qemu/qemu-nbd
*.ko
*.mod.c
bios/*.bin
bios/*.sym
bios/*.txt
bios/acpi-dsdt.aml
vgabios/*.bin
vgabios/*.txt
extboot/extboot.bin
extboot/extboot.img
extboot/signrom
kernel/config.kbuild
kernel/modules.order
kernel/Module.symvers
kernel/Modules.symvers
kernel/Module.markers
kernel/.tmp_versions
kernel/include-compat/asm
kernel/include-compat/asm-x86/asm-x86
kernel/include
kernel/x86/modules.order
kernel/x86/i825[49].[ch]
kernel/x86/kvm_main.c
kernel/x86/kvm_svm.h
kernel/x86/vmx.[ch]
kernel/x86/svm.[ch]
kernel/x86/mmu.[ch]
kernel/x86/paging_tmpl.h
kernel/x86/x86_emulate.[ch]
kernel/x86/ioapic.[ch]
kernel/x86/iodev.h
kernel/x86/irq.[ch]
kernel/x86/kvm_trace.c
kernel/x86/lapic.[ch]
kernel/x86/tss.h
kernel/x86/x86.[ch]
kernel/x86/coalesced_mmio.[ch]
kernel/x86/kvm_cache_regs.h
kernel/x86/vtd.c
kernel/x86/irq_comm.c
kernel/x86/timer.c
kernel/x86/kvm_timer.h
kernel/x86/iommu.c
qemu/pc-bios/extboot.bin
qemu/qemu-doc.html
qemu/*.[18]
qemu/*.pod
qemu/qemu-tech.html
qemu/qemu-options.texi
user/kvmtrace
user/test/x86/bootstrap

125
kvm/Makefile Normal file
View File

@@ -0,0 +1,125 @@
include config.mak
DESTDIR=
rpmrelease = devel
sane-arch = $(subst i386,x86,$(subst x86_64,x86,$(subst s390x,s390,$(ARCH))))
.PHONY: kernel user libkvm qemu bios vgabios extboot clean libfdt cscope
all: libkvm qemu
ifneq '$(filter $(ARCH), x86_64 i386 ia64)' ''
all: $(if $(WANT_MODULE), kernel) user
endif
kcmd = $(if $(WANT_MODULE),,@\#)
qemu kernel user libkvm:
$(MAKE) -C $@
qemu: libkvm
ifneq '$(filter $(ARCH), i386 x86_64)' ''
qemu: extboot
endif
ifneq '$(filter $(ARCH), powerpc ia64)' ''
qemu: libfdt
endif
user: libkvm
# sync if kernel/Makefile exists and if using --with-patched-kernel
user libkvm qemu: header-sync-$(if $(wildcard kernel/Makefile),$(if $(WANT_MODULE),n,y),n)
header-sync-n:
header-sync-y:
make -C kernel \
LINUX=$(if $(KERNELSOURCEDIR),$(KERNELSOURCEDIR),$(KERNELDIR)) \
header-sync
rm -f kernel/include/asm
ln -sf asm-$(sane-arch) kernel/include/asm
bios:
$(MAKE) -C $@
cp bios/BIOS-bochs-latest qemu/pc-bios/bios.bin
vgabios:
$(MAKE) -C $@
cp vgabios/VGABIOS-lgpl-latest.bin qemu/pc-bios/vgabios.bin
cp vgabios/VGABIOS-lgpl-latest.cirrus.bin qemu/pc-bios/vgabios-cirrus.bin
extboot:
$(MAKE) -C $@
if ! [ -f qemu/pc-bios/extboot.bin ] \
|| ! cmp -s qemu/pc-bios/extboot.bin extboot/extboot.bin; then \
cp extboot/extboot.bin qemu/pc-bios/extboot.bin; \
fi
libfdt:
$(MAKE) -C $@
LINUX=linux-2.6
sync:
make -C kernel sync LINUX=$(shell readlink -f "$(LINUX)")
bindir = /usr/bin
bin = $(bindir)/kvm
initdir = /etc/init.d
confdir = /etc/kvm
utilsdir = /etc/kvm/utils
install-rpm:
mkdir -p $(DESTDIR)/$(bindir)
mkdir -p $(DESTDIR)/$(confdir)
mkdir -p $(DESTDIR)/$(initdir)
mkdir -p $(DESTDIR)/$(utilsdir)
mkdir -p $(DESTDIR)/etc/udev/rules.d
make -C qemu DESTDIR=$(DESTDIR)/ install
ln -sf /usr/kvm/bin/qemu-system-x86_64 $(DESTDIR)/$(bin)
install -m 755 kvm_stat $(DESTDIR)/$(bindir)/kvm_stat
cp scripts/kvm $(DESTDIR)/$(initdir)/kvm
cp scripts/qemu-ifup $(DESTDIR)/$(confdir)/qemu-ifup
install -t $(DESTDIR)/etc/udev/rules.d scripts/*kvm*.rules
install:
$(kcmd)make -C kernel DESTDIR="$(DESTDIR)" install
make -C libkvm DESTDIR="$(DESTDIR)" install
make -C qemu DESTDIR="$(DESTDIR)" install
tmpspec = .tmp.kvm.spec
RPMTOPDIR = $$(pwd)/rpmtop
rpm: srpm
rm -rf $(RPMTOPDIR)/BUILD
mkdir -p $(RPMTOPDIR)/{BUILD,RPMS/$$(uname -i)}
rpmbuild --rebuild \
--define="_topdir $(RPMTOPDIR)" \
$(RPMTOPDIR)/SRPMS/kvm-0.0-$(rpmrelease).src.rpm
srpm:
mkdir -p $(RPMTOPDIR)/{SOURCES,SRPMS}
sed 's/^Release:.*/Release: $(rpmrelease)/' kvm.spec > $(tmpspec)
tar czf $(RPMTOPDIR)/SOURCES/kvm.tar.gz qemu
tar czf $(RPMTOPDIR)/SOURCES/user.tar.gz user
tar czf $(RPMTOPDIR)/SOURCES/libkvm.tar.gz libkvm
tar czf $(RPMTOPDIR)/SOURCES/kernel.tar.gz kernel
tar czf $(RPMTOPDIR)/SOURCES/scripts.tar.gz scripts
tar czf $(RPMTOPDIR)/SOURCES/extboot.tar.gz extboot
cp Makefile configure kvm_stat $(RPMTOPDIR)/SOURCES
rpmbuild --define="_topdir $(RPMTOPDIR)" -bs $(tmpspec)
$(RM) $(tmpspec)
clean:
for i in $(if $(WANT_MODULE), kernel) user libkvm qemu libfdt; do \
make -C $$i clean; \
done
rm -f ./cscope.*
distclean: clean
rm -f config.mak user/config.mak
cscope:
rm -f ./cscope.*
find . -wholename './kernel' -prune -o -name "*.[ch]" -print > ./cscope.files
cscope -b

159
kvm/configure vendored Executable file
View File

@@ -0,0 +1,159 @@
#!/bin/bash
prefix=/usr/local
kerneldir=/lib/modules/$(uname -r)/build
cc=gcc
ld=ld
objcopy=objcopy
ar=ar
want_module=1
qemu_cflags=
qemu_ldflags=
kvm_trace=
qemu_opts=()
cross_prefix=
arch=`uname -m`
target_exec=
# don't use uname if kerneldir is set
no_uname=
if [ -z "TMPDIR" ] ; then
TMPDIR=.
fi
if [ ! -e kernel/Makefile ]; then
want_module=
fi
usage() {
cat <<-EOF
Usage: $0 [options]
Options include:
--arch=ARCH architecture to compile for ($arch)
--cross-prefix=PREFIX prefix for cross compile
--prefix=PREFIX where to install things ($prefix)
--with-patched-kernel don't use external module
--with-kvm-trace Enable kvm_trace
--kerneldir=DIR kernel build directory ($kerneldir)
--qemu-cflags=CFLAGS CFLAGS to add to qemu configuration
--qemu-ldflags=LDFLAGS LDFLAGS to add to qemu configuration
Any additional option is given to qemu's configure verbatim; including:
EOF
cd qemu
./configure --help | egrep "enable-|disable-" \
| grep -v user | grep -v system | grep -v kqemu | grep -v kvm \
| sed -e "s/^ / /g" \
| sed -e"s/ enable/enable/g" | sed -e "s/ disable/disable/g"
exit 1
}
while [[ "$1" = -* ]]; do
opt="$1"; shift
arg=
hasarg=
if [[ "$opt" = *=* ]]; then
arg="${opt#*=}"
opt="${opt%%=*}"
hasarg=1
fi
case "$opt" in
--prefix)
prefix="$arg"
;;
--kerneldir)
kerneldir="$arg"
no_uname=1
;;
--with-patched-kernel)
want_module=
;;
--with-kvm-trace)
kvm_trace=y
;;
--qemu-cflags)
qemu_cflags="$arg"
;;
--qemu-ldflags)
qemu_ldflags="$arg"
;;
--arch)
arch="$arg"
;;
--cross-prefix)
cross_prefix="$arg"
;;
--help)
usage
;;
*)
qemu_opts=("${qemu_opts[@]}" "$opt${hasarg:+=$arg}")
;;
esac
done
#set kenel directory
libkvm_kerneldir=$(readlink -f kernel)
case $arch in
i?86*|x86_64*)
arch=${arch/#i?86/i386}
target_exec="x86_64-softmmu"
qemu_cflags="$qemu_cflags -DCONFIG_X86"
;;
ia64*)
target_exec="ia64-softmmu"
;;
powerpc*)
target_exec="ppcemb-softmmu"
qemu_cflags="$qemu_cflags -I $PWD/libfdt"
qemu_ldflags="$qemu_ldflags -L $PWD/libfdt"
;;
esac
processor=${arch#*-}
arch=${arch%%-*}
#configure kernel module
[ -e kernel/Makefile ] && (cd kernel;
./configure \
--kerneldir="$kerneldir" \
--arch="$arch" \
$([ -z ${want_module} ] && echo "--with-patched-kernel") \
${cross_prefix:+"--cross-prefix=$cross_prefix"} \
${kvm_trace:+"--with-kvm-trace"}
)
#configure user dir
(cd user; ./configure --prefix="$prefix" --kerneldir="$libkvm_kerneldir" \
--arch="$arch" --processor="$processor" \
${cross_prefix:+"--cross-prefix=$cross_prefix"})
#configure qemu
(cd qemu; ./configure --target-list=$target_exec \
--disable-kqemu \
--extra-cflags="-I $PWD/../libkvm $qemu_cflags" \
--extra-ldflags="-L $PWD/../libkvm $qemu_ldflags" \
--kerneldir="$libkvm_kerneldir" \
--prefix="$prefix" \
${cross_prefix:+"--cross-prefix=$cross_prefix"} \
${cross_prefix:+"--cpu=$arch"} "${qemu_opts[@]}"
) || usage
cat <<EOF > config.mak
ARCH=$arch
PROCESSOR=$processor
PREFIX=$prefix
KERNELDIR=$kerneldir
KERNELSOURCEDIR=$kernelsourcedir
LIBKVM_KERNELDIR=$libkvm_kerneldir
WANT_MODULE=$want_module
CROSS_COMPILE=$cross_prefix
CC=$cross_prefix$cc
LD=$cross_prefix$ld
OBJCOPY=$cross_prefix$objcopy
AR=$cross_prefix$ar
EOF

Some files were not shown because too many files have changed in this diff Show More