Compare commits

...

46 Commits

Author SHA1 Message Date
Bruce Rogers
36f5bc4fdb This is the delta between the qemu and qemu-kvm v0.15.1 versions
Signed-off-by: Bruce Rogers <brogers@suse.com>
2018-02-09 11:41:11 -07:00
Justin M. Forbes
82b2b32a32 Version 0.15.1
Signed-off-by: Justin M. Forbes <jforbes@redhat.com>
2011-10-11 09:46:03 -05:00
Stefan Hajnoczi
4a81ab81e4 qed: fix use-after-free during l2 cache commit
QED's metadata caching strategy allows two parallel requests to race for
metadata lookup.  The first one to complete will populate the metadata
cache and the second one will drop the data it just read in favor of the
cached data.

There is a use-after-free in qed_read_l2_table_cb() and
qed_commit_l2_update() where l2_table->offset was used after the
l2_table may have been freed due to a metadata lookup race.  Fix this by
keeping the l2_offset in a local variable and not reaching into the
possibly freed l2_table.

Reported-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-10-05 11:33:31 -05:00
Jan Kiszka
68e3508eaf sdl: Fix termination in -no-shutdown mode
Just like the monitor does, we need to clear no_shutdown before calling
qemu_system_shutdown_request on quit requests. Otherwise, QEMU just
stops the VM.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-10-03 14:42:24 -05:00
Kevin Wolf
fb524042db Fix termination by signal with -no-shutdown
On signals such as SIGTERM qemu should exit instead of just stopping the VM
even with -no-shutdown.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-10-03 14:42:16 -05:00
Brad
336398391a Add support for finding libpng via pkg-config.
Signed-off-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-10-03 14:41:44 -05:00
Brad
672aefeb5e Check for presence of compiler -pthread flag.
OpenBSD / FreeBSD and some other OS's require the use of
cc -pthread to link threaded programs so have QEMU's
configure script check for the presence of the flag
and use it if so.

Signed-off-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2011-10-03 14:41:23 -05:00
Brad
6a10ccca80 Allow overriding the location of Samba's smbd.
Allow overriding the location of Samba's smbd.

Pretty much every OS I look at has some means of
changing this path (patching) so lets just make
it easier for OS developers creating packages
and/or end users to override the location.

Signed-off-by: Brad Smith <brad@comstyle.com>
Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2011-10-03 14:40:52 -05:00
Gerd Hoffmann
7095e71576 Fix linker scripts
Remove PROVIDE_HIDDEN and ONLY_IF_{RO,RW} from linker scripts to make
them work with older binutils versions.  Fixes *-bsd-user build on
OpenBSD 4.9 which ships binutils 2.15.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2011-10-03 14:40:25 -05:00
Brad
91b31d6158 Fix install(1) usage to be compatible with OpenBSD's install(1).
Fix install(1) usage to be compatible with OpenBSD's install(1).

When creating a directory via the -d flag the -p flag cannot be
used at the same time. Also in the context of installing QEMU it
doesn't make sense to use the -p flag anyway so use the [default]
-c flag instead.

Signed-off-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-10-03 14:39:58 -05:00
Jan Kiszka
b89f4a7d2a Fix qjson test of solidus encoding
"\/" is supposed to be decoded as "/", but there is no need to encode
"/" via escape. Fix the existing test and add a second one expressing
this.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Acked-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2011-10-03 14:38:17 -05:00
Luiz Capitulino
fbdd7c8bd5 configure: Copy test data to build directory
The QDict unit-tests (check-qdict) will fail when ran on a different
build directory. That's, it only works when ran on the source dir.

This happens because its data file (qdict-test-data.txt) is not
copied to the build dir. Fix it.

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>

Conflicts:

	configure
2011-10-03 14:37:44 -05:00
Jamie Iles
e19a4e89ae monitor: fix build breakage for !CONFIG_VNC
Commit c62f6d1 (monitor: fix build breakage with --disable-vnc)
conditionalised some VNC setup code but left an unused variable.  Move
the variable into the conditional code to fix the build breakage.

Cc: Luiz Capitulino <lcapitulino@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2011-08-31 15:09:31 -05:00
TeLeMan
ff5acedd8f monitor: fix build breakage with --disable-vnc
The breakage was introduced by the commit 1366108981

Signed-off-by: TeLeMan <geleman@gmail.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-08-31 15:09:25 -05:00
Brad
2af86a2ff7 Fix forcing multicast msgs to loopback on OpenBSD.
Fix forcing multicast msgs to loopback on OpenBSD.
e.g.
$ sudo qemu -m 128 -no-fd-bootchk \
        -hda virtual.img -boot n -nographic \
        -net nic,vlan=0,model=rtl8139,macaddr=52:54:00:12:34:03 \
        -net user -tftp /usr/src/sys/arch/i386/compile/TEST -bootp pxeboot \
        -net nic,vlan=1,model=rtl8139,macaddr=52:54:00:23:03:01 \
        -net tap,vlan=1,script=no \
        -net nic,vlan=3,model=rtl8139,macaddr=52:54:00:23:03:03 \
        -net socket,vlan=3,mcast=230.0.0.1:10003
setsockopt(SOL_IP, IP_MULTICAST_LOOP): Invalid argument
qemu: -net socket,vlan=3,mcast=230.0.0.1:10003: Device 'socket' could not be initialized

Signed-off-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2011-08-31 15:08:26 -05:00
Justin M. Forbes
e62ad8314a Merge branch 'stable-0.15' of git://git.qemu.org/qemu 2011-08-14 10:55:05 -05:00
Anthony Liguori
76e4e1d237 Update version to 0.15.0
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-08-08 13:27:32 -05:00
Kevin Wolf
4fbe5233fd qcow2: Fix L1 table size after bdrv_snapshot_goto
When loading an internal snapshot whose L1 table is smaller than the current L1
table, the size of the current L1 would be shrunk to the snapshot's L1 size in
memory, but not on disk. This lead to incorrect refcount updates and eventuelly
to image corruption.

Instead of writing the new L1 size to disk, this simply retains the bigger L1
size that is currently in use and makes sure that the unused part is zeroed.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Tested-by: Philipp Hahn <hahn@univention.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
(cherry picked from commit 35d7ace74b)
2011-08-05 07:25:45 -05:00
Justin M. Forbes
4bea41dbaa Merge branch 'stable-0.15' of git://git.qemu.org/qemu 2011-08-04 16:40:07 -05:00
Anthony Liguori
e2f775205a Revert "floppy: save and restore DIR register"
This reverts commit 7d905f716b.

The use of subsections by this commit are broken because of a fundamental
limitations of subsections in the current protocol.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-08-04 16:19:04 -05:00
Richard Henderson
51dd7a94c7 alpha-softmmu: Disable for the 0.15 release branch.
The system emulation code was not merged before the branch.
Let's leave that work for the next release.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-08-04 16:19:04 -05:00
Wolfgang Mauerer
9096de69ff vhost build fix for i386
vhost.c uses __sync_fetch_and_and(), which is only
available for -march=i486 and above (see
https://bugzilla.redhat.com/show_bug.cgi?id=624279).

Signed-off-by: Wolfgang Mauerer <wolfgang.mauerer@siemens.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
(cherry picked from commit 023367e6cd)
2011-08-04 16:19:04 -05:00
Michael Roth
09afeef1ab guest agent: add --enable-guest-agent config option
QAPI will require glib/python, but for now the guest agent is the only
user. For now, make these dependencies an explicit guest agent one, and
give users the option to disable it if need be.

Once QAPI is adopted in core QEMU code, we would basically revert this
patch.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-08-04 16:19:04 -05:00
Peter Maydell
01825a8ddf user: Restore debug usage message for '-d ?' in user mode emulation
The code which prints the debug usage message on '-d ?' for *-user
has to come before the check for "not enough arguments", so that
"qemu-foo -d ?" prints the list of possible debug log items rather than
the generic usage message. (This was inadvertently broken in commit
c235d73.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-08-04 16:19:04 -05:00
Michael Walle
ae2dd33693 lm32: softusb: claim to support full speed
The QEMU keyboard and mouse reports themselves as full speed devices,
though they are actually low speed devices. Until this is fixed, claim that
we are supporting full speed devices.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Michael Walle <michael@walle.cc>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
2011-08-04 01:25:39 +02:00
Peter Maydell
a80f53aee3 user: Restore debug usage message for '-d ?' in user mode emulation
The code which prints the debug usage message on '-d ?' for *-user
has to come before the check for "not enough arguments", so that
"qemu-foo -d ?" prints the list of possible debug log items rather than
the generic usage message. (This was inadvertently broken in commit
c235d73.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-08-02 14:38:17 -05:00
Michael Roth
88ca9f047b Makefile: add missing deps on $(GENERATED_HEADERS)
This fixes a build issue with make -j6+ due to qapi-generated files
being built before $(GENERATED_HEADERS) have been created.

Tested-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
2011-07-31 15:56:52 -05:00
Anthony Liguori
898517b0bc Update version to 0.15.0-rc2 2011-07-31 15:38:11 -05:00
Anthony Liguori
9dc9f2b820 Bump version to 0.15.0-rc1
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2011-07-29 17:14:11 -05:00
Justin M. Forbes
ef942b795a Merge branch 'for-upstream-0.15' of git://git.linaro.org/people/pmaydell/qemu-arm 2011-07-29 10:14:01 -05:00
Amit Shah
868aa386b8 virtio-balloon: Unregister savevm section on device unplug
Migrating after unplugging a virtio-balloon device resulted in an error
message on the destination:

Unknown savevm section or instance '0000:00:04.0/virtio-balloon' 0
load of migration failed

Fix this by unregistering the section on device unplug.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
2011-07-28 15:10:39 +05:30
Amit Shah
7e10be8c74 virtio-balloon: Add exit handler, fix memleaks
Add an exit handler that will free up RAM after a virtio-balloon device
is unplugged.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
2011-07-28 15:10:33 +05:30
Amit Shah
9843621e3b balloon: Reject negative balloon values
Negative balloon values don't make sense, reject them and throw a qerror
with QERR_INVALID_PARAMETER_VALUE.

Reported-by: Mike Cao <bcao@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
2011-07-28 15:10:27 +05:30
Amit Shah
ab640dbfc0 virtio-balloon: Check if balloon registration failed
Multiple balloon registrations are not allowed; check if the
registration with the qemu balloon api succeeded.  If not, fail the
device init.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
2011-07-28 15:10:19 +05:30
Amit Shah
eaa8b2778c balloon: Don't allow multiple balloon handler registrations
Multiple balloon devices don't make sense; disallow more than one
registration attempt to register handlers.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
2011-07-28 15:09:49 +05:30
Peter Maydell
7ec7f28019 target-arm: UNDEF on a VCVTT/VCVTB UNPREDICTABLE to avoid TCG assert
VCVTT/VCVTB with bit 8 set is UNPREDICTABLE; we choose to UNDEF.
This avoids a TCG assert later when the VCVTT/VCVTB code tries to
use a source register that wasn't ever set up.

We pull the check for the presence of the half-precision extension
up in to this common code as well.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-07-27 09:29:22 +00:00
Peter Maydell
31b1308046 target-arm: Handle UNDEF and UNPREDICTABLE cases for VLDM, VSTM
Handle the UNDEF and UNPREDICTABLE cases for VLDM and VSTM. In
particular, we now generate an undef exception for overlarge imm8
values rather than generating 1000+ TCG ops and hitting an assertion.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-07-27 09:29:22 +00:00
Peter Maydell
4ec648dd6e target-arm: Support v6 barriers in linux-user mode
ARMv6 implemented various operations as special cases of cp15 accesses
which are true instructions in v7; this includes barriers (DMB, DSB, ISB).
Catch this special case at translate time, so that it works in linux-user
mode (which doesn't provide a functional get_cp15 helper) as well as
system mode.

Includes minor cleanup of the existing cases (single switch statement,
and doing the "OK in user mode?" test explicitly rather than hiding it in
cp15_user_ok()).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-07-27 09:29:22 +00:00
Peter Maydell
e961d129e1 target-arm: Mark 1136r1 as a v6K core
The 1136r1 is actually a v6K core (unlike the 1136r0); mark it as such,
thus enabling the TLS registers, NOP hints, CLREX, half and byte wide
exclusive load/stores, etc.

The VA-to-PA translation registers are not present on 1136r1, so
introduce a new feature flag for them, which is enabled on
11MPCore and all v7 cores.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2011-07-26 14:58:43 +00:00
Amit Shah
8959459386 virtio-balloon: Fix header comment; add Copyright
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2011-07-26 11:21:15 +05:30
Amit Shah
e2b40e003a balloon: Fix header comment; add Copyright
Signed-off-by: Amit Shah <amit.shah@redhat.com>
2011-07-26 11:21:14 +05:30
Amit Shah
1a39b0fcff balloon: Separate out stat and balloon handling
Passing on '0' as ballooning target to indicate retrieval of stats is
bad API.  It also makes 'balloon 0' in the monitor cause a segfault.
Have two different functions handle the different functionality instead.

Detailed explanation from Markus's review:

1. do_info_balloon() is an info_async() method.  It receives a callback
   with argument, to be called exactly once (callback frees the
   argument).  It passes the callback via qemu_balloon_status() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().

   virtio_balloon_to_target() executes its balloon stats half.  It
   stores the callback in the device state.

   If it can't send a stats request, it resets stats and calls the
   callback right away.

   Else, it sends a stats request.  The device model runs the callback
   when it receives the answer.

   Works.

2. do_balloon() is a cmd_async() method.  It receives a callback with
   argument, to be called when the command completes.  do_balloon()
   calls it right before it succeeds.  Odd, but should work.

   Nevertheless, it passes the callback on via qemu_ballon() and
   indirectly through qemu_balloon_event to virtio_balloon_to_target().

   a. If the argument is non-zero, virtio_balloon_to_target() executes
      its balloon half, which doesn't use the callback in any way.

      Odd, but works.

   b. If the argument is zero, virtio_balloon_to_target() executes its
      balloon stats half, just like in 1.  It either calls the callback
      right away, or arranges for it to be called later.

      Thus, the callback runs twice: use after free and double free.

Test case: start with -S -device virtio-balloon, execute "balloon 0" in
human monitor.  Runs the callback first from virtio_balloon_to_target(),
then again from do_balloon().

Reported-by: Mike Cao <bcao@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-26 11:21:14 +05:30
Amit Shah
4a97e18b87 virtio-balloon: Separate status handling into separate function
Separate out the code to retrieve balloon info from the code that sets
balloon values.

This will be used to separate the two callbacks from balloon.c and help
cope with 'balloon 0' on the monitor.  Currently, 'balloon 0' causes a
segfault in monitor_resume().

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-26 11:21:13 +05:30
Amit Shah
f1ee0a0ebd balloon: Simplify code flow
Replace:
  if (foo) {
    ...
  } else {
    return 0;
  }

by

  if (!foo) {
    return 0;
  }
  ...

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-26 11:21:13 +05:30
Amit Shah
3583bc031e balloon: Add braces around if statements
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-26 11:21:12 +05:30
Amit Shah
2798b5e174 balloon: Make functions, local vars static
balloon.h had function declarations for a couple of functions that are
local to balloon.c.  Make them static.

Drop the 'qemu_' prefix for balloon.c-local variables, and make them
static.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-26 11:21:12 +05:30
198 changed files with 32393 additions and 443 deletions

2
.gitignore vendored
View File

@@ -65,6 +65,8 @@ pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/extboot.bin
pc-bios/optionrom/vapic.bin
.stgit-*
cscope.*
tags

2
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "roms/vgabios"]
path = roms/vgabios
url = git://git.qemu.org/vgabios.git/
url = git://git.kernel.org/pub/scm/virt/kvm/vgabios.git/
[submodule "roms/seabios"]
path = roms/seabios
url = git://git.qemu.org/seabios.git/

View File

@@ -192,8 +192,10 @@ test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types
test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o
QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c)
qemu-ga.o: $(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c) $(qapi-obj-y)
$(QGALIB_GEN): $(GENERATED_HEADERS)
$(QGALIB) qemu-ga.o: $(QGALIB_GEN) $(qapi-obj-y)
qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
@@ -244,6 +246,8 @@ mpc8544ds.dtb \
multiboot.bin linuxboot.bin \
s390-zipl.rom \
spapr-rtas.bin slof.bin
BLOBS += extboot.bin
BLOBS += vapic.bin
else
BLOBS=
endif
@@ -270,7 +274,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"
@@ -391,6 +400,7 @@ tarbin:
$(datadir)/pxe-pcnet.rom \
$(datadir)/pxe-rtl8139.rom \
$(datadir)/pxe-virtio.rom \
$(datadir)/extboot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 \

View File

@@ -17,6 +17,7 @@ block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.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 += raw.o 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 qcow2-cache.o
@@ -145,7 +146,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))
common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y))
common-obj-y += iov.o acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o
#common-obj-$(CONFIG_POSIX) += compatfd.o
common-obj-y += notify.o event_notifier.o
common-obj-y += qemu-timer.o qemu-timer-common.o
@@ -170,11 +171,11 @@ user-obj-y += cutils.o cache-utils.o
# libhw
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-y += loader.o
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
@@ -191,14 +192,16 @@ hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
hw-obj-$(CONFIG_SERIAL) += serial.o
hw-obj-$(CONFIG_PARALLEL) += parallel.o
hw-obj-$(CONFIG_I8254) += i8254.o
hw-obj-$(CONFIG_PCSPK) += pcspk.o
# Moved back to Makefile.target due to #include qemu-kvm.h:
#hw-obj-$(CONFIG_I8254) += i8254.o
#hw-obj-$(CONFIG_PCSPK) += pcspk.o
hw-obj-$(CONFIG_PCKBD) += pckbd.o
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
hw-obj-$(CONFIG_FDC) += fdc.o
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
# needs fixes for cpu hotplug, so moved to Makefile.target:
# hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o
hw-obj-$(CONFIG_HPET) += hpet.o

View File

@@ -71,14 +71,19 @@ all: $(PROGS) stap
#########################################################
# 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-y += fpu/softfloat.o
libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o
endif
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-y += disas.o
@@ -187,10 +192,11 @@ endif #CONFIG_BSD_USER
# System emulator target
ifdef CONFIG_SOFTMMU
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o vl.o balloon.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-$(CONFIG_NO_PCI) += pci-stub.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
@@ -227,10 +233,24 @@ obj-i386-y += mc146818rtc.o i8259.o pc.o
obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += extboot.o
obj-i386-y += debugcon.o multiboot.o
obj-i386-y += pc_piix.o
obj-i386-$(CONFIG_KVM) += kvmclock.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
obj-i386-y += testdev.o
obj-i386-y += acpi.o acpi_piix4.o
obj-i386-y += pcspk.o i8254.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
@@ -286,6 +306,8 @@ obj-lm32-y += milkymist-vgafb.o
obj-lm32-y += framebuffer.o
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += pcspk.o i8254.o
obj-mips-y += acpi.o acpi_piix4.o
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
obj-mips-y += vga.o i8259.o
obj-mips-y += g364fb.o jazz_led.o
@@ -372,6 +394,11 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o
obj-alpha-y = i8259.o mc146818rtc.o
obj-alpha-y += vga.o cirrus_vga.o
ifeq ($(TARGET_ARCH), ia64)
firmware.o: firmware.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
endif
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
monitor.o: hmp-commands.h qmp-commands.h

View File

@@ -1 +1 @@
0.15.50
0.15.1

12
arm.ld
View File

@@ -71,23 +71,23 @@ SECTIONS
.data1 : { *(.data1) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
PROVIDE (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE (__fini_array_end = .);
}
.ctors :
{

View File

@@ -1,7 +1,9 @@
/*
* QEMU System Emulator
* Generic Balloon handlers and management
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2011 Amit Shah <amit.shah@redhat.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
@@ -30,44 +32,53 @@
#include "balloon.h"
#include "trace.h"
static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonStatus *balloon_stat_fn;
static void *balloon_opaque;
static QEMUBalloonEvent *qemu_balloon_event;
void *qemu_balloon_event_opaque;
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque)
{
qemu_balloon_event = func;
qemu_balloon_event_opaque = opaque;
if (balloon_event_fn || balloon_stat_fn || balloon_opaque) {
/* We're already registered one balloon handler. How many can
* a guest really have?
*/
error_report("Another balloon device already registered");
return -1;
}
balloon_event_fn = event_func;
balloon_stat_fn = stat_func;
balloon_opaque = opaque;
return 0;
}
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
static int qemu_balloon(ram_addr_t target)
{
if (qemu_balloon_event) {
trace_balloon_event(qemu_balloon_event_opaque, target);
qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
return 1;
} else {
if (!balloon_event_fn) {
return 0;
}
trace_balloon_event(balloon_opaque, target);
balloon_event_fn(balloon_opaque, target);
return 1;
}
int qemu_balloon_status(MonitorCompletion cb, void *opaque)
static int qemu_balloon_status(MonitorCompletion cb, void *opaque)
{
if (qemu_balloon_event) {
qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
return 1;
} else {
if (!balloon_stat_fn) {
return 0;
}
balloon_stat_fn(balloon_opaque, cb, opaque);
return 1;
}
static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
{
Monitor *mon = opaque;
if (strcmp(key, "actual"))
if (strcmp(key, "actual")) {
monitor_printf(mon, ",%s=%" PRId64, key,
qint_get_int(qobject_to_qint(obj)));
}
}
void monitor_print_balloon(Monitor *mon, const QObject *data)
@@ -75,9 +86,9 @@ void monitor_print_balloon(Monitor *mon, const QObject *data)
QDict *qdict;
qdict = qobject_to_qdict(data);
if (!qdict_haskey(qdict, "actual"))
if (!qdict_haskey(qdict, "actual")) {
return;
}
monitor_printf(mon, "balloon: actual=%" PRId64,
qdict_get_int(qdict, "actual") >> 20);
qdict_iter(qdict, print_balloon_stat, mon);
@@ -129,6 +140,7 @@ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
int do_balloon(Monitor *mon, const QDict *params,
MonitorCompletion cb, void *opaque)
{
int64_t target;
int ret;
if (kvm_enabled() && !kvm_has_sync_mmu()) {
@@ -136,7 +148,12 @@ int do_balloon(Monitor *mon, const QDict *params,
return -1;
}
ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
target = qdict_get_int(params, "value");
if (target <= 0) {
qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
return -1;
}
ret = qemu_balloon(target);
if (ret == 0) {
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
return -1;

View File

@@ -16,14 +16,12 @@
#include "monitor.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
MonitorCompletion cb, void *cb_data);
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb,
void *cb_data);
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
int qemu_balloon_status(MonitorCompletion cb, void *opaque);
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque);
void monitor_print_balloon(Monitor *mon, const QObject *data);
int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque);

View File

@@ -317,7 +317,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
int i, snapshot_index, l1_size2;
int i, snapshot_index;
int cur_l1_bytes, sn_l1_bytes;
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
if (snapshot_index < 0)
@@ -330,14 +331,19 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0)
goto fail;
s->l1_size = sn->l1_size;
l1_size2 = s->l1_size * sizeof(uint64_t);
cur_l1_bytes = s->l1_size * sizeof(uint64_t);
sn_l1_bytes = sn->l1_size * sizeof(uint64_t);
if (cur_l1_bytes > sn_l1_bytes) {
memset(s->l1_table + sn->l1_size, 0, cur_l1_bytes - sn_l1_bytes);
}
/* copy the snapshot l1 table to the current l1 table */
if (bdrv_pread(bs->file, sn->l1_table_offset,
s->l1_table, l1_size2) != l1_size2)
s->l1_table, sn_l1_bytes) < 0)
goto fail;
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
s->l1_table, l1_size2) < 0)
s->l1_table, cur_l1_bytes) < 0)
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);

View File

@@ -230,21 +230,21 @@ static void qed_read_l2_table_cb(void *opaque, int ret)
QEDRequest *request = read_l2_table_cb->request;
BDRVQEDState *s = read_l2_table_cb->s;
CachedL2Table *l2_table = request->l2_table;
uint64_t l2_offset = read_l2_table_cb->l2_offset;
if (ret) {
/* can't trust loaded L2 table anymore */
qed_unref_l2_cache_entry(l2_table);
request->l2_table = NULL;
} else {
l2_table->offset = read_l2_table_cb->l2_offset;
l2_table->offset = l2_offset;
qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
/* This is guaranteed to succeed because we just committed the entry
* to the cache.
*/
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache,
l2_table->offset);
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
assert(request->l2_table != NULL);
}

View File

@@ -915,14 +915,14 @@ static void qed_commit_l2_update(void *opaque, int ret)
QEDAIOCB *acb = opaque;
BDRVQEDState *s = acb_to_s(acb);
CachedL2Table *l2_table = acb->request.l2_table;
uint64_t l2_offset = l2_table->offset;
qed_commit_l2_cache_entry(&s->l2_cache, l2_table);
/* This is guaranteed to succeed because we just committed the entry to the
* cache.
*/
acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache,
l2_table->offset);
acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
assert(acb->request.l2_table != NULL);
qed_aio_next_io(opaque, ret);

View File

@@ -17,6 +17,8 @@
#include "hw/qdev.h"
#include "block_int.h"
DriveInfo *extboot_drive = NULL;
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
static const char *const if_name[IF_COUNT] = {
@@ -236,6 +238,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
int on_read_error, on_write_error;
const char *devaddr;
DriveInfo *dinfo;
int is_extboot = 0;
int snapshot = 0;
int ret;
@@ -363,6 +366,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
}
}
is_extboot = qemu_opt_get_bool(opts, "boot", 0);
if (is_extboot && extboot_drive) {
fprintf(stderr, "qemu: two bootable drives specified\n");
return NULL;
}
on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
@@ -468,6 +477,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
if (is_extboot) {
extboot_drive = dinfo;
}
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
switch(type) {

View File

@@ -66,4 +66,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
extern DriveInfo *extboot_drive;
#endif

View File

@@ -856,9 +856,6 @@ int main(int argc, char **argv)
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* init debug */
cpu_set_log_filename(log_file);
@@ -877,6 +874,11 @@ int main(int argc, char **argv)
cpu_set_log(mask);
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));

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

View File

@@ -33,7 +33,8 @@ START_TEST(escaped_string)
{ "\"\\n\"", "\n" },
{ "\"\\r\"", "\r" },
{ "\"\\t\"", "\t" },
{ "\"\\/\"", "\\/" },
{ "\"/\"", "/" },
{ "\"\\/\"", "/", .skip = 1 },
{ "\"\\\\\"", "\\" },
{ "\"\\\"\"", "\"" },
{ "\"hello world \\\"embedded string\\\"\"",

168
configure vendored
View File

@@ -93,7 +93,17 @@ audio_pt_int=""
audio_win_int=""
cc_i386=i386-pc-linux-gnu-gcc
target_list=""
target_list="x86_64-softmmu"
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
@@ -163,11 +173,14 @@ darwin_user="no"
bsd_user="no"
guest_base=""
uname_release=""
io_thread="no"
io_thread="yes"
mixemu="no"
kvm_cap_pit="yes"
kvm_cap_device_assignment="yes"
aix="no"
blobs="yes"
pkgversion=""
pkgversion=" ($(kvm_version))"
cpu_emulation="yes"
check_utests="no"
user_pie="no"
zero_malloc=""
@@ -179,6 +192,7 @@ smartcard=""
smartcard_nss=""
usb_redir=""
opengl=""
guest_agent="yes"
# parse CC options first
for opt do
@@ -408,6 +422,7 @@ SunOS)
make="${MAKE-gmake}"
install="${INSTALL-ginstall}"
ld="gld"
smbd="${SMBD-/usr/sfw/sbin/smbd}"
needs_libsunmath="no"
solarisrev=`uname -r | cut -f2 -d.`
# have to select again, because `uname -m` returns i86pc
@@ -463,6 +478,13 @@ Haiku)
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
@@ -476,6 +498,7 @@ fi
: ${make=${MAKE-make}}
: ${install=${INSTALL-install}}
: ${python=${PYTHON-python}}
: ${smbd=${SMBD-/usr/sbin/smbd}}
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
@@ -519,6 +542,8 @@ for opt do
;;
--python=*) python="$optarg"
;;
--smbd=*) smbd="$optarg"
;;
--extra-cflags=*)
;;
--extra-ldflags=*)
@@ -636,6 +661,14 @@ for opt do
;;
--enable-kvm) kvm="yes"
;;
--disable-kvm-pit) kvm_cap_pit="no"
;;
--enable-kvm-pit) kvm_cap_pit="yes"
;;
--disable-kvm-device-assignment) kvm_cap_device_assignment="no"
;;
--enable-kvm-device-assignment) kvm_cap_device_assignment="yes"
;;
--disable-spice) spice="no"
;;
--enable-spice) spice="yes"
@@ -725,6 +758,8 @@ for opt do
;;
--enable-docs) docs="yes"
;;
--disable-cpu-emulation) cpu_emulation="no"
;;
--disable-vhost-net) vhost_net="no"
;;
--enable-vhost-net) vhost_net="yes"
@@ -751,6 +786,10 @@ for opt do
;;
--enable-usb-redir) usb_redir="yes"
;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -840,7 +879,6 @@ if [ "$softmmu" = "yes" ] ; then
default_target_list="\
i386-softmmu \
x86_64-softmmu \
alpha-softmmu \
arm-softmmu \
cris-softmmu \
lm32-softmmu \
@@ -928,6 +966,7 @@ echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
echo " --make=MAKE use specified make [$make]"
echo " --install=INSTALL use specified install [$install]"
echo " --python=PYTHON use specified python [$python]"
echo " --smbd=SMBD use specified smbd [$smbd]"
echo " --static enable static build [$static]"
echo " --mandir=PATH install man pages in PATH"
echo " --datadir=PATH install firmware in PATH"
@@ -980,6 +1019,10 @@ echo " --enable-bluez enable bluez stack connectivity"
echo " --disable-slirp disable SLIRP userspace network connectivity"
echo " --disable-kvm disable KVM acceleration support"
echo " --enable-kvm enable KVM acceleration support"
echo " --disable-kvm-pit disable KVM pit support"
echo " --enable-kvm-pit enable KVM pit support"
echo " --disable-kvm-device-assignment disable KVM device assignment support"
echo " --enable-kvm-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"
@@ -1012,6 +1055,7 @@ echo " --disable-attr disables attr and xattr support"
echo " --enable-attr enable attr and xattr support"
echo " --enable-io-thread enable IO thread"
echo " --disable-blobs disable installing provided firmware blobs"
echo " --disable-cpu-emulation disables use of qemu cpu emulation code"
echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support"
@@ -1029,6 +1073,8 @@ echo " --disable-smartcard-nss disable smartcard nss support"
echo " --enable-smartcard-nss enable smartcard nss support"
echo " --disable-usb-redir disable usb network redirection support"
echo " --enable-usb-redir enable usb network redirection support"
echo " --disable-guest-agent disable building of the QEMU Guest Agent"
echo " --enable-guest-agent enable building of the QEMU Guest Agent"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -1088,11 +1134,13 @@ if test "$solaris" = "yes" ; then
fi
fi
if has $python; then
:
else
echo "Python not found. Use --python=/path/to/python"
exit 1
if test "$guest_agent" != "no" ; then
if has $python; then
:
else
echo "Python not found. Use --python=/path/to/python"
exit 1
fi
fi
if test -z "$target_list" ; then
@@ -1505,11 +1553,17 @@ int main(void) {
return 0;
}
EOF
if $pkg_config libpng --modversion >/dev/null 2>&1; then
vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null`
vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null`
else
vnc_png_cflags=""
vnc_png_libs="-lpng"
fi
if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
vnc_png=yes
libs_softmmu="$vnc_png_libs $libs_softmmu"
QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags"
else
if test "$vnc_png" = "yes" ; then
feature_not_found "vnc-png"
@@ -1822,19 +1876,42 @@ fi
##########################################
# glib support probe
if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
libs_softmmu="$glib_libs $libs_softmmu"
libs_tools="$glib_libs $libs_tools"
else
echo "glib-2.0 required to compile QEMU"
exit 1
if test "$guest_agent" != "no" ; then
if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then
glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null`
glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null`
libs_softmmu="$glib_libs $libs_softmmu"
libs_tools="$glib_libs $libs_tools"
else
echo "glib-2.0 required to compile QEMU"
exit 1
fi
fi
##########################################
# libpci header probe for kvm_cap_device_assignment
if test $kvm_cap_device_assignment = "yes" ; then
cat > $TMPC << EOF
#include <pci/header.h>
#ifndef PCI_VENDOR_ID
#error NO LIBPCI HEADER
#endif
int main(void) { return 0; }
EOF
if compile_prog "" "" ; then
kvm_cap_device_assignment=yes
else
echo
echo "Error: libpci header check failed"
echo "Disable KVM Device Assignment capability."
echo
kvm_cap_device_assignment=no
fi
fi
##########################################
# pthread probe
PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
pthread=no
cat > $TMPC << EOF
@@ -2509,6 +2586,29 @@ if test "$trace_backend" = "dtrace"; then
fi
fi
##########################################
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
# use i686 as default anyway, but for those that don't, an explicit
# specification is necessary
if test $vhost_net = "yes" && test $cpu = "i386"; then
cat > $TMPC << EOF
int sfaa(unsigned *ptr)
{
return __sync_fetch_and_and(ptr, 0);
}
int main(int argc, char **argv)
{
int val = 42;
sfaa(&val);
return val;
}
EOF
if ! compile_prog "" "" ; then
CFLAGS+="-march=i486"
fi
fi
##########################################
# End of CC checks
# After here, no more $cc or $ld runs
@@ -2566,7 +2666,9 @@ if test "$softmmu" = yes ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
tools="qemu-nbd\$(EXESUF) $tools"
if [ "$guest_agent" = "yes" ]; then
tools="qemu-ga\$(EXESUF) $tools"
fi
if [ "$check_utests" = "yes" ]; then
tools="check-qint check-qstring check-qdict check-qlist $tools"
tools="check-qfloat check-qjson $tools"
@@ -2603,6 +2705,9 @@ echo "LDFLAGS $LDFLAGS"
echo "make $make"
echo "install $install"
echo "python $python"
if test "$slirp" = "yes" ; then
echo "smbd $smbd"
fi
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
@@ -2638,6 +2743,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"
@@ -2652,6 +2758,8 @@ echo "Linux AIO support $linux_aio"
echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs"
echo "KVM support $kvm"
echo "KVM PIT support $kvm_cap_pit"
echo "KVM device assig. $kvm_cap_device_assignment"
echo "fdt support $fdt"
echo "preadv support $preadv"
echo "fdatasync $fdatasync"
@@ -2667,6 +2775,7 @@ echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "usb net redir $usb_redir"
echo "OpenGL support $opengl"
echo "build guest agent $guest_agent"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2760,6 +2869,7 @@ if test $profiler = "yes" ; then
fi
if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=y" >> $config_host_mak
echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak
QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES"
fi
if test "$vde" = "yes" ; then
@@ -2941,6 +3051,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
if test "$madvise" = "yes" ; then
echo "CONFIG_MADVISE=y" >> $config_host_mak
fi
@@ -3012,9 +3127,9 @@ echo "TOOLS=$tools" >> $config_host_mak
echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
echo "INSTALL=$install" >> $config_host_mak
echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak
echo "INSTALL_DATA=$install -m0644 -p" >> $config_host_mak
echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak
echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak
echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
echo "CC_I386=$cc_i386" >> $config_host_mak
@@ -3148,6 +3263,9 @@ case "$target_arch2" in
target_phys_bits=64
target_long_alignment=8
;;
ia64)
target_phys_bits=64
;;
alpha)
target_phys_bits=64
target_long_alignment=8
@@ -3310,6 +3428,12 @@ case "$target_arch2" in
if test $vhost_net = "yes" ; then
echo "CONFIG_VHOST_NET=y" >> $config_target_mak
fi
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
if test "$target_bigendian" = "yes" ; then
@@ -3530,7 +3654,7 @@ DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi"
DIRS="$DIRS qga"
FILES="Makefile tests/Makefile"
FILES="Makefile tests/Makefile qdict-test-data.txt"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
FILES="$FILES pc-bios/spapr-rtas/Makefile"

View File

@@ -19,7 +19,9 @@
#include "config.h"
#include "cpu.h"
#include "disas.h"
#if !defined(TARGET_IA64)
#include "tcg.h"
#endif
#include "qemu-barrier.h"
int tb_invalidated_flag;
@@ -222,6 +224,7 @@ int cpu_exec(CPUState *env)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X)
#elif defined(TARGET_IA64)
/* XXXXX */
#else
#error unsupported target CPU
@@ -613,6 +616,7 @@ int cpu_exec(CPUState *env)
#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)

5
cpus.c
View File

@@ -688,6 +688,11 @@ void qemu_main_loop_start(void)
qemu_cond_broadcast(&qemu_system_cond);
}
bool qemu_system_is_ready(void)
{
return qemu_system_ready;
}
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
{
struct qemu_work_item wi;

1
cpus.h
View File

@@ -7,6 +7,7 @@ void qemu_main_loop_start(void);
void resume_all_vcpus(void);
void pause_all_vcpus(void);
void cpu_stop_current(void);
bool qemu_system_is_ready(void);
void cpu_synchronize_all_states(void);
void cpu_synchronize_all_post_reset(void);

View File

@@ -809,9 +809,6 @@ int main(int argc, char **argv)
usage();
}
}
if (optind >= argc)
usage();
filename = argv[optind];
/* init debug */
cpu_set_log_filename(log_file);
@@ -830,6 +827,11 @@ int main(int argc, char **argv)
cpu_set_log(mask);
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));

21
exec.c
View File

@@ -26,7 +26,12 @@
#include "qemu-common.h"
#include "cpu.h"
#include "cache-utils.h"
#if !defined(TARGET_IA64)
#include "tcg.h"
#endif
#include "hw/hw.h"
#include "hw/qdev.h"
#include "osdep.h"
@@ -461,6 +466,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;
@@ -3910,6 +3918,11 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
cpu_physical_memory_set_dirty_flags(
addr1, (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);
qemu_put_ram_ptr(ptr);
}
} else {
@@ -4103,6 +4116,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_nofail(buffer);
@@ -4120,7 +4135,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);
}
if (xen_enabled()) {
xen_invalidate_map_cache_entry(buffer);
@@ -4723,7 +4740,9 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
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
}
#define MMUSUFFIX _cmmu

View File

@@ -1213,6 +1213,19 @@ STEXI
@item block_passwd @var{device} @var{password}
@findex block_passwd
Set the encrypted device @var{device} password to @var{password}
ETEXI
{
.name = "cpu_set",
.args_type = "cpu:i,state:s",
.params = "cpu [online|offline]",
.help = "change cpu state",
.mhandler.cmd = do_cpu_set_nr,
},
STEXI
@item cpu_set @var{cpu} [online|offline]
Set CPU @var{cpu} online or offline.
ETEXI
{

18
hppa.ld
View File

@@ -75,36 +75,34 @@ SECTIONS
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.PARISC.unwind : { *(.PARISC.unwind) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x10000) + (. & (0x10000 - 1));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
PROVIDE (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
PROVIDE (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
PROVIDE (__fini_array_end = .);
}
.ctors :
{

View File

@@ -36,13 +36,19 @@
#define ACPI_DBG_IO_ADDR 0xb044
#define GPE_BASE 0xafe0
#define PROC_BASE 0xaf00
#define GPE_LEN 4
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PIIX4_CPU_HOTPLUG_STATUS 4
#define PIIX4_PCI_HOTPLUG_STATUS 2
struct gpe_regs {
uint8_t cpus_sts[32];
};
struct pci_status {
uint32_t up;
uint32_t down;
@@ -68,6 +74,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */
ACPIGPE gpe;
struct gpe_regs gpe_cpu;
struct pci_status pci0_status;
uint32_t pci0_hotplug_enable;
} PIIX4PMState;
@@ -216,10 +223,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
{ \
.name = (stringify(_field)), \
.version_id = 0, \
.num = GPE_LEN, \
.info = &vmstate_info_uint16, \
.size = sizeof(uint16_t), \
.flags = VMS_ARRAY | VMS_POINTER, \
.flags = VMS_SINGLE | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, uint8_t), \
}
@@ -326,11 +332,16 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
}
static PIIX4PMState *global_piix4_pm_state; /* cpu hotadd */
static int piix4_pm_initfn(PCIDevice *dev)
{
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
uint8_t *pci_conf;
/* for cpu hotadd */
global_piix4_pm_state = s;
pci_conf = s->dev.config;
pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02;
@@ -339,6 +350,13 @@ static int piix4_pm_initfn(PCIDevice *dev)
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
/* APM */
apm_init(&s->apm, apm_ctrl_changed, s);
@@ -422,7 +440,16 @@ device_init(piix4_pm_register);
static uint32_t gpe_readb(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr);
uint32_t val = 0;
struct gpe_regs *g = &s->gpe_cpu;
switch (addr) {
case PROC_BASE ... PROC_BASE+31:
val = g->cpus_sts[addr - PROC_BASE];
break;
default:
val = acpi_gpe_ioport_readb(&s->gpe, addr);
}
PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
return val;
@@ -510,17 +537,28 @@ static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
return;
}
extern const char *global_cpu_model;
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
struct pci_status *pci0_status = &s->pci0_status;
int i = 0, cpus = smp_cpus;
while (cpus > 0) {
s->gpe_cpu.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
cpus -= 8;
}
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->gpe, GPE_BASE);
register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, s);
register_ioport_read(PROC_BASE, 32, 1, gpe_readb, s);
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
@@ -533,6 +571,48 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
}
#if defined(TARGET_I386)
static void enable_processor(PIIX4PMState *s, int cpu)
{
struct gpe_regs *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->gpe;
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
g->cpus_sts[cpu/8] |= (1 << (cpu%8));
}
static void disable_processor(PIIX4PMState *s, int cpu)
{
struct gpe_regs *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->gpe;
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
g->cpus_sts[cpu/8] &= ~(1 << (cpu%8));
}
void qemu_system_cpu_hot_add(int cpu, int state)
{
CPUState *env;
PIIX4PMState *s = global_piix4_pm_state;
if (state && !qemu_get_cpu(cpu)) {
env = pc_new_cpu(global_cpu_model);
if (!env) {
fprintf(stderr, "cpu %d creation failed\n", cpu);
return;
}
env->cpuid_apic_id = cpu;
}
if (state)
enable_processor(s, cpu);
else
disable_processor(s, cpu);
pm_update_sci(s);
}
#endif
static void enable_device(PIIX4PMState *s, int slot)
{
s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;

120
hw/apic.c
View File

@@ -23,6 +23,7 @@
#include "host-utils.h"
#include "sysbus.h"
#include "trace.h"
#include "kvm.h"
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
@@ -302,8 +303,11 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
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;
@@ -418,6 +422,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);
@@ -889,6 +898,113 @@ 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_ns(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 kvm_load_lapic(CPUState *env)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = DO_UPCAST(APICState, busdev.qdev, env->apic_state);
if (!s) {
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_load_from_user(s);
}
#endif
}
void kvm_save_lapic(CPUState *env)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = DO_UPCAST(APICState, busdev.qdev, env->apic_state);
if (!s) {
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_save_to_user(s);
}
#endif
}
/* This function is only used for old state version 1 and 2 */
static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
{

View File

@@ -13,6 +13,7 @@ void apic_deliver_pic_intr(DeviceState *s, int level);
int apic_get_interrupt(DeviceState *s);
void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void);
void apic_set_irq_delivered(void);
void cpu_set_apic_base(DeviceState *s, uint64_t val);
uint64_t cpu_get_apic_base(DeviceState *s);
void cpu_set_apic_tpr(DeviceState *s, uint8_t val);

View File

@@ -2497,6 +2497,7 @@ static void map_linear_vram(CirrusVGAState *s)
if (!s->vga.map_addr)
return;
#ifndef TARGET_IA64
s->vga.lfb_vram_mapped = 0;
if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
@@ -2519,6 +2520,7 @@ 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);
}

1909
hw/device-assignment.c Normal file

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,120 @@
/*
* 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 seg;
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 - 1];
int config_fd;
} PCIDevRegions;
typedef struct {
pcibus_t e_physbase;
ram_addr_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 */
PCIRegion *region;
} AssignedDevRegion;
#define ASSIGNED_DEVICE_USE_IOMMU_BIT 0
#define ASSIGNED_DEVICE_PREFER_MSI_BIT 1
#define ASSIGNED_DEVICE_USE_IOMMU_MASK (1 << ASSIGNED_DEVICE_USE_IOMMU_BIT)
#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
typedef struct AssignedDevice {
PCIDevice dev;
PCIHostDevice host;
uint32_t features;
int intpin;
uint8_t debug_flags;
AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1];
PCIDevRegions real_device;
int run;
int girq;
unsigned int h_segnr;
unsigned char h_busnr;
unsigned int h_devfn;
int irq_requested_type;
int bound;
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;
uint32_t emulate_cmd_mask;
char *configfd_name;
int32_t bootindex;
QLIST_ENTRY(AssignedDevice) next;
} AssignedDevice;
void assigned_dev_update_irqs(void);
#endif /* __DEVICE_ASSIGNMENT_H__ */

123
hw/extboot.c Normal file
View File

@@ -0,0 +1,123 @@
/*
* 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 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)
{
register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
}

View File

@@ -36,7 +36,6 @@
#include "qdev-addr.h"
#include "blockdev.h"
#include "sysemu.h"
#include "block_int.h"
/********************************************************/
/* debug Floppy devices */
@@ -83,7 +82,6 @@ typedef struct FDrive {
uint8_t max_track; /* Nb of tracks */
uint16_t bps; /* Bytes per sector */
uint8_t ro; /* Is read-only */
uint8_t media_changed; /* Is media changed */
} FDrive;
static void fd_init(FDrive *drv)
@@ -535,63 +533,16 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
NULL,
};
static void fdrive_media_changed_pre_save(void *opaque)
{
FDrive *drive = opaque;
drive->media_changed = drive->bs->media_changed;
}
static int fdrive_media_changed_post_load(void *opaque, int version_id)
{
FDrive *drive = opaque;
if (drive->bs != NULL) {
drive->bs->media_changed = drive->media_changed;
}
/* User ejected the floppy when drive->bs == NULL */
return 0;
}
static bool fdrive_media_changed_needed(void *opaque)
{
FDrive *drive = opaque;
return (drive->bs != NULL && drive->bs->media_changed != 1);
}
static const VMStateDescription vmstate_fdrive_media_changed = {
.name = "fdrive/media_changed",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = fdrive_media_changed_pre_save,
.post_load = fdrive_media_changed_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(media_changed, FDrive),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_fdrive = {
.name = "fdrive",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
.fields = (VMStateField []) {
VMSTATE_UINT8(head, FDrive),
VMSTATE_UINT8(track, FDrive),
VMSTATE_UINT8(sect, FDrive),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_fdrive_media_changed,
.needed = &fdrive_media_changed_needed,
} , {
/* empty */
}
}
};

View File

@@ -236,6 +236,11 @@ static int hpet_post_load(void *opaque, int version_id)
if (s->timer[0].config & HPET_TN_FSB_CAP) {
s->flags |= 1 << HPET_MSI_SUPPORT;
}
if (hpet_in_legacy_mode(s)) {
hpet_pit_disable();
}
return 0;
}

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

@@ -0,0 +1,115 @@
/*
* 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 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 (kvm_has_pit_state2()) {
kvm_get_pit2(kvm_state, &pit2);
s->flags = pit2.flags;
} else {
/* pit2 is superset of pit struct so just cast it and use it */
kvm_get_pit(kvm_state, (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 (kvm_has_pit_state2()) {
kvm_set_pit2(kvm_state, &pit2);
} else {
kvm_set_pit(kvm_state, (struct kvm_pit_state *)&pit2);
}
return 0;
}
static void dummy_timer(void *opaque)
{
}
void kvm_pit_init(PITState *pit)
{
PITChannelState *s;
s = &pit->channels[0];
s->irq_timer = qemu_new_timer_ns(vm_clock, dummy_timer, s);
vmstate_pit.pre_save = kvm_pit_pre_save;
vmstate_pit.post_load = kvm_pit_post_load;
return;
}

View File

@@ -25,41 +25,11 @@
#include "pc.h"
#include "isa.h"
#include "qemu-timer.h"
#include "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;
typedef struct PITState {
ISADevice dev;
uint32_t irq;
uint32_t iobase;
PITChannelState channels[3];
} PITState;
static PITState pit_state;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
@@ -236,13 +206,18 @@ int pit_get_mode(ISADevice *dev, 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_ns(vm_clock);
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
s->channels[chan].count_load_time = qemu_get_clock_ns(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 */
@@ -302,17 +277,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;
}
@@ -372,6 +347,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;
@@ -382,16 +362,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)
@@ -431,9 +430,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);
@@ -454,16 +454,18 @@ 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()
@@ -476,20 +478,40 @@ static void pit_reset(DeviceState *dev)
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);
}
if (vmstate_pit.post_load) {
vmstate_pit.post_load(pit, 2);
}
}
#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_pit_disable(void)
{
PITChannelState *s = &pit_state.channels[0];
if (kvm_enabled() && kvm_pit_in_kernel()) {
if (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
@@ -499,18 +521,33 @@ void hpet_pit_disable(void) {
void hpet_pit_enable(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() && kvm_pit_in_kernel()) {
if (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
static int pit_initfn(ISADevice *dev)
{
PITState *pit = DO_UPCAST(PITState, dev, dev);
PITChannelState *s;
#ifdef CONFIG_KVM_PIT
if (kvm_enabled() && kvm_pit_in_kernel())
kvm_pit_init(pit);
else {
#endif
s = &pit->channels[0];
/* the timer 0 is connected to an IRQ */
s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
@@ -520,6 +557,9 @@ static int pit_initfn(ISADevice *dev)
register_ioport_read(pit->iobase, 3, 1, pit_ioport_read, pit);
isa_init_ioport(dev, pit->iobase);
#ifdef CONFIG_KVM_PIT
}
#endif
qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
return 0;

75
hw/i8254.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* 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 {
ISADevice dev;
uint32_t irq;
uint32_t iobase;
PITChannelState channels[3];
uint32_t flags;
};
void pit_save(QEMUFile *f, void *opaque);
int pit_load(QEMUFile *f, void *opaque, int version_id);
typedef struct PITState PITState;
/* i8254-kvm.c */
void kvm_pit_init(PITState *pit);
#endif

View File

@@ -27,6 +27,8 @@
#include "monitor.h"
#include "qemu-timer.h"
#include "kvm.h"
/* debug PIC */
//#define DEBUG_PIC
@@ -223,6 +225,9 @@ static inline void pic_intack(PicState *s, int irq)
s->irr &= ~(1 << irq);
}
extern int time_drift_fix;
extern int64_t timer_acks, timer_ints_to_push;
int pic_read_irq(PicState2 *s)
{
int irq, irq2, intno;
@@ -230,6 +235,17 @@ int pic_read_irq(PicState2 *s)
irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) {
pic_intack(&s->pics[0], irq);
#ifdef TARGET_I386
if (time_drift_fix && irq == 0) {
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) {
@@ -262,6 +278,8 @@ int pic_read_irq(PicState2 *s)
return intno;
}
static int kvm_kernel_pic_load_from_user(PicState *s);
static void pic_reset(void *opaque)
{
PicState *s = opaque;
@@ -282,6 +300,10 @@ static void pic_reset(void *opaque)
s->init4 = 0;
s->single_mode = 0;
/* Note: ELCR is not reset */
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_load_from_user(s);
}
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -448,9 +470,32 @@ 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 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 []) {
@@ -537,3 +582,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_state, &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_state, &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(NULL, 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

@@ -28,6 +28,8 @@
#include "host-utils.h"
#include "sysbus.h"
#include "kvm.h"
//#define DEBUG_IOAPIC
#ifdef DEBUG_IOAPIC
@@ -268,6 +270,57 @@ ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
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_state, &chip);
kioapic = &chip.chip.ioapic;
s->id = kioapic->id;
s->ioregsel = kioapic->ioregsel;
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->busdev.mmio[0].addr;
kioapic->irr = s->irr;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
kioapic->redirtbl[i].bits = s->ioredtbl[i];
}
kvm_set_irqchip(kvm_state, &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_post_load(void *opaque, int version_id)
{
IOAPICState *s = opaque;
@@ -276,15 +329,21 @@ static int ioapic_post_load(void *opaque, int version_id)
/* set sane value */
s->irr = 0;
}
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 = 3,
.post_load = ioapic_post_load,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = ioapic_post_load,
.pre_save = ioapic_pre_save,
.fields = (VMStateField[]) {
VMSTATE_UINT8(id, IOAPICState),
VMSTATE_UINT8(ioregsel, IOAPICState),
@@ -306,6 +365,11 @@ static void ioapic_reset(DeviceState *d)
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
}
#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] = {

707
hw/ipf.c Normal file
View File

@@ -0,0 +1,707 @@
/*
* 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++;
}
}
}
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

@@ -66,7 +66,7 @@ void isa_bus_irqs(qemu_irq *irqs)
*/
qemu_irq isa_get_irq(int isairq)
{
if (isairq < 0 || isairq > 15) {
if (isairq < 0 || isairq > 23) {
hw_error("isa irq %d invalid", isairq);
}
return isabus->irqs[isairq];

View File

@@ -310,10 +310,12 @@ static int milkymist_softusb_init(SysBusDevice *dev)
usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
/* FIXME: claim to support full speed devices. qemu mouse and keyboard
* report themselves as full speed devices. */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
USB_SPEED_MASK_LOW);
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
USB_SPEED_MASK_LOW);
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
/* and finally create an usb keyboard */
s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");

131
hw/msi.c
View File

@@ -20,6 +20,7 @@
#include "msi.h"
#include "range.h"
#include "kvm.h"
/* Eventually those constants should go to Linux pci_regs.h */
#define PCI_MSI_PENDING_32 0x10
@@ -109,6 +110,94 @@ bool msi_enabled(const PCIDevice *dev)
PCI_MSI_FLAGS_ENABLE);
}
static void kvm_msi_message_from_vector(PCIDevice *dev, unsigned vector,
KVMMsiMessage *kmm)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
unsigned int nr_vectors = msi_nr_vectors(flags);
kmm->addr_lo = pci_get_long(dev->config + msi_address_lo_off(dev));
if (msi64bit) {
kmm->addr_hi = pci_get_long(dev->config + msi_address_hi_off(dev));
} else {
kmm->addr_hi = 0;
}
kmm->data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
if (nr_vectors > 1) {
kmm->data &= ~(nr_vectors - 1);
kmm->data |= vector;
}
}
static void kvm_msi_update(PCIDevice *dev)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
unsigned int max_vectors = 1 <<
((flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1));
unsigned int nr_vectors = msi_nr_vectors(flags);
KVMMsiMessage new_entry, *entry;
bool changed = false;
unsigned int vector;
int r;
for (vector = 0; vector < max_vectors; vector++) {
entry = dev->msi_irq_entries + vector;
if (vector >= nr_vectors) {
if (vector < dev->msi_entries_nr) {
kvm_msi_message_del(entry);
changed = true;
}
} else if (vector >= dev->msi_entries_nr) {
kvm_msi_message_from_vector(dev, vector, entry);
r = kvm_msi_message_add(entry);
if (r) {
fprintf(stderr, "%s: kvm_msi_add failed: %s\n", __func__,
strerror(-r));
exit(1);
}
changed = true;
} else {
kvm_msi_message_from_vector(dev, vector, &new_entry);
r = kvm_msi_message_update(entry, &new_entry);
if (r < 0) {
fprintf(stderr, "%s: kvm_update_msi failed: %s\n",
__func__, strerror(-r));
exit(1);
}
if (r > 0) {
*entry = new_entry;
changed = true;
}
}
}
dev->msi_entries_nr = nr_vectors;
if (changed) {
r = kvm_commit_irq_routes();
if (r) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
strerror(-r));
exit(1);
}
}
}
/* KVM specific MSI helpers */
static void kvm_msi_free(PCIDevice *dev)
{
unsigned int vector;
for (vector = 0; vector < dev->msi_entries_nr; ++vector) {
kvm_msi_message_del(&dev->msi_irq_entries[vector]);
}
if (dev->msi_entries_nr > 0) {
kvm_commit_irq_routes();
}
dev->msi_entries_nr = 0;
}
int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
{
@@ -121,6 +210,10 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
" 64bit %d mask %d\n",
offset, nr_vectors, msi64bit, msi_per_vector_mask);
if (kvm_enabled() && kvm_irqchip_in_kernel() && !kvm_has_gsi_routing()) {
return -ENOTSUP;
}
assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
assert(nr_vectors > 0);
assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
@@ -159,6 +252,12 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
dev->msi_irq_entries = qemu_malloc(nr_vectors *
sizeof(*dev->msix_irq_entries));
}
return config_offset;
}
@@ -172,6 +271,12 @@ void msi_uninit(struct PCIDevice *dev)
}
flags = pci_get_word(dev->config + msi_flags_off(dev));
cap_size = msi_cap_sizeof(flags);
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_free(dev);
qemu_free(dev->msi_irq_entries);
}
pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
dev->cap_present &= ~QEMU_PCI_CAP_MSI;
@@ -183,6 +288,10 @@ void msi_reset(PCIDevice *dev)
uint16_t flags;
bool msi64bit;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_free(dev);
}
flags = pci_get_word(dev->config + msi_flags_off(dev));
flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
msi64bit = flags & PCI_MSI_FLAGS_64BIT;
@@ -232,6 +341,11 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_set_irq(dev->msi_irq_entries[vector].gsi, 1, NULL);
return;
}
if (msi64bit) {
address = pci_get_quad(dev->config + msi_address_lo_off(dev));
} else {
@@ -320,6 +434,10 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
pci_set_word(dev->config + msi_flags_off(dev), flags);
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_update(dev);
}
if (!msi_per_vector_mask) {
/* if per vector masking isn't supported,
there is no pending interrupt. */
@@ -350,3 +468,16 @@ unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
return msi_nr_vectors(flags);
}
void msi_post_load(PCIDevice *dev)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
if (kvm_enabled() && dev->msi_irq_entries) {
kvm_msi_free(dev);
if (flags & PCI_MSI_FLAGS_ENABLE) {
kvm_msi_update(dev);
}
}
}

View File

@@ -32,6 +32,7 @@ void msi_reset(PCIDevice *dev);
void msi_notify(PCIDevice *dev, unsigned int vector);
void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
void msi_post_load(PCIDevice *dev);
static inline bool msi_present(const PCIDevice *dev)
{

275
hw/msix.c
View File

@@ -15,6 +15,7 @@
#include "msix.h"
#include "pci.h"
#include "range.h"
#include "kvm.h"
#define MSIX_CAP_LENGTH 12
@@ -35,6 +36,93 @@
/* Flag for interrupt controller to declare MSI-X support */
int msix_supported;
/* 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_msi_message_del(&dev->msix_irq_entries[vector]);
changed = 1;
}
}
if (changed) {
kvm_commit_irq_routes();
}
}
static void kvm_msix_message_from_vector(PCIDevice *dev, unsigned vector,
KVMMsiMessage *kmm)
{
uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
kmm->addr_lo = pci_get_long(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
kmm->addr_hi = pci_get_long(table_entry + PCI_MSIX_ENTRY_UPPER_ADDR);
kmm->data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
}
static void kvm_msix_update(PCIDevice *dev, int vector,
int was_masked, int is_masked)
{
KVMMsiMessage new_entry, *entry;
int mask_cleared = was_masked && !is_masked;
int r;
/* 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;
kvm_msix_message_from_vector(dev, vector, &new_entry);
r = kvm_msi_message_update(entry, &new_entry);
if (r < 0) {
fprintf(stderr, "%s: kvm_update_msix failed: %s\n", __func__,
strerror(-r));
exit(1);
}
if (r > 0) {
*entry = new_entry;
r = kvm_commit_irq_routes();
if (r) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
strerror(-r));
exit(1);
}
}
}
static int kvm_msix_vector_add(PCIDevice *dev, unsigned vector)
{
KVMMsiMessage *kmm = dev->msix_irq_entries + vector;
int r;
kvm_msix_message_from_vector(dev, vector, kmm);
r = kvm_msi_message_add(kmm);
if (r < 0) {
fprintf(stderr, "%s: kvm_add_msix failed: %s\n", __func__, strerror(-r));
return r;
}
r = kvm_commit_irq_routes();
if (r < 0) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, strerror(-r));
return r;
}
return 0;
}
static void kvm_msix_vector_del(PCIDevice *dev, unsigned vector)
{
kvm_msi_message_del(&dev->msix_irq_entries[vector]);
kvm_commit_irq_routes();
}
/* 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.
@@ -45,36 +133,43 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
{
int config_offset;
uint8_t *config;
uint32_t new_size;
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1)
return -EINVAL;
if (bar_size > 0x80000000)
return -ENOSPC;
pdev->msix_bar_size = bar_size;
/* Add space for MSI-X structures */
if (!bar_size) {
new_size = MSIX_PAGE_SIZE;
} else if (bar_size < MSIX_PAGE_SIZE) {
bar_size = MSIX_PAGE_SIZE;
new_size = MSIX_PAGE_SIZE * 2;
} else {
new_size = bar_size * 2;
config_offset = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
if (!config_offset) {
uint32_t new_size;
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1)
return -EINVAL;
if (bar_size > 0x80000000)
return -ENOSPC;
/* Add space for MSI-X structures */
if (!bar_size) {
new_size = MSIX_PAGE_SIZE;
} else if (bar_size < MSIX_PAGE_SIZE) {
bar_size = MSIX_PAGE_SIZE;
new_size = MSIX_PAGE_SIZE * 2;
} else {
new_size = bar_size * 2;
}
pdev->msix_bar_size = new_size;
config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
0, MSIX_CAP_LENGTH);
if (config_offset < 0)
return config_offset;
config = pdev->config + config_offset;
pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
/* Table on top of BAR */
pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
/* Pending bits on top of that */
pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
bar_nr);
}
pdev->msix_bar_size = new_size;
config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
0, MSIX_CAP_LENGTH);
if (config_offset < 0)
return config_offset;
config = pdev->config + config_offset;
pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
/* Table on top of BAR */
pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
/* Pending bits on top of that */
pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
bar_nr);
pdev->msix_cap = config_offset;
/* Make flags bit writable. */
pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
@@ -175,7 +270,16 @@ 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 / PCI_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));
}
if (was_masked != msix_is_masked(dev, vector) && dev->msix_mask_notifier) {
int r = dev->msix_mask_notifier(dev, vector,
msix_is_masked(dev, vector));
assert(r >= 0);
}
msix_handle_mask_update(dev, vector);
}
@@ -208,17 +312,25 @@ void msix_mmio_map(PCIDevice *d, int region_num,
return;
if (size <= offset)
return;
cpu_register_physical_memory(addr + offset, size - offset,
cpu_register_physical_memory(addr + offset,
MIN(size - offset, MSIX_PAGE_SIZE),
d->msix_mmio_index);
}
static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
{
int vector;
int vector, r;
for (vector = 0; vector < nentries; ++vector) {
unsigned offset =
vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
int was_masked = msix_is_masked(dev, vector);
dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
if (was_masked != msix_is_masked(dev, vector) &&
dev->msix_mask_notifier) {
r = dev->msix_mask_notifier(dev, vector,
msix_is_masked(dev, vector));
assert(r >= 0);
}
}
}
@@ -229,12 +341,15 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
{
int ret;
/* Nothing to do if MSI is not supported by interrupt controller */
if (!msix_supported)
if (!msix_supported ||
(kvm_enabled() && kvm_irqchip_in_kernel() && !kvm_has_gsi_routing())) {
return -ENOTSUP;
}
if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL;
dev->msix_mask_notifier = NULL;
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
sizeof *dev->msix_entry_used);
@@ -254,6 +369,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
if (ret)
goto err_config;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
dev->msix_irq_entries = qemu_malloc(nentries *
sizeof *dev->msix_irq_entries);
}
dev->cap_present |= QEMU_PCI_CAP_MSIX;
return 0;
@@ -272,6 +392,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);
@@ -292,6 +416,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;
}
@@ -300,10 +426,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 * PCI_MSIX_ENTRY_SIZE);
qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
}
@@ -313,6 +442,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;
}
@@ -357,6 +489,11 @@ void msix_notify(PCIDevice *dev, unsigned vector)
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL);
return;
}
address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
stl_le_phys(address, data);
@@ -384,9 +521,17 @@ 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 (kvm_enabled() && kvm_irqchip_in_kernel() &&
!dev->msix_entry_used[vector]) {
ret = kvm_msix_vector_add(dev, vector);
if (ret) {
return ret;
}
}
++dev->msix_entry_used[vector];
return 0;
}
@@ -399,6 +544,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_vector_del(dev, vector);
}
msix_clr_pending(dev, vector);
}
@@ -408,3 +556,66 @@ void msix_unuse_all_vectors(PCIDevice *dev)
return;
msix_free_irq_entries(dev);
}
/* Invoke the notifier if vector entry is used and unmasked. */
static int msix_notify_if_unmasked(PCIDevice *dev, unsigned vector, int masked)
{
assert(dev->msix_mask_notifier);
if (!dev->msix_entry_used[vector] || msix_is_masked(dev, vector)) {
return 0;
}
return dev->msix_mask_notifier(dev, vector, masked);
}
static int msix_set_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
{
/* Notifier has been set. Invoke it on unmasked vectors. */
return msix_notify_if_unmasked(dev, vector, 0);
}
static int msix_unset_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
{
/* Notifier will be unset. Invoke it to mask unmasked entries. */
return msix_notify_if_unmasked(dev, vector, 1);
}
int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func f)
{
int r, n;
assert(!dev->msix_mask_notifier);
dev->msix_mask_notifier = f;
for (n = 0; n < dev->msix_entries_nr; ++n) {
r = msix_set_mask_notifier_for_vector(dev, n);
if (r < 0) {
goto undo;
}
}
return 0;
undo:
while (--n >= 0) {
msix_unset_mask_notifier_for_vector(dev, n);
}
dev->msix_mask_notifier = NULL;
return r;
}
int msix_unset_mask_notifier(PCIDevice *dev)
{
int r, n;
assert(dev->msix_mask_notifier);
for (n = 0; n < dev->msix_entries_nr; ++n) {
r = msix_unset_mask_notifier_for_vector(dev, n);
if (r < 0) {
goto undo;
}
}
dev->msix_mask_notifier = NULL;
return 0;
undo:
while (--n >= 0) {
msix_set_mask_notifier_for_vector(dev, n);
}
return r;
}

View File

@@ -33,4 +33,6 @@ void msix_reset(PCIDevice *dev);
extern int msix_supported;
int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func);
int msix_unset_mask_notifier(PCIDevice *dev);
#endif

46
hw/pc.c
View File

@@ -39,6 +39,7 @@
#include "msix.h"
#include "sysbus.h"
#include "sysemu.h"
#include "kvm.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
@@ -56,6 +57,8 @@
#endif
#define BIOS_FILENAME "bios.bin"
#define EXTBOOT_FILENAME "extboot.bin"
#define VAPIC_FILENAME "vapic.bin"
#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -601,7 +604,7 @@ static void *bochs_bios_init(void)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len);
fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
smbios_table = smbios_get_table(&smbios_len);
if (smbios_table)
@@ -921,10 +924,18 @@ static void pc_cpu_reset(void *opaque)
env->halted = !cpu_is_bsp(env);
}
static CPUState *pc_new_cpu(const char *cpu_model)
CPUState *pc_new_cpu(const char *cpu_model)
{
CPUState *env;
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
}
env = cpu_init(cpu_model);
if (!env) {
fprintf(stderr, "Unable to find x86 CPU definition\n");
@@ -944,14 +955,6 @@ void pc_cpus_init(const char *cpu_model)
int i;
/* init CPUs */
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
}
for(i = 0; i < smp_cpus; i++) {
pc_new_cpu(cpu_model);
}
@@ -1010,10 +1013,21 @@ void pc_memory_init(const char *kernel_filename,
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);
cpu_register_physical_memory(0x100000 - isa_bios_size,
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
if (extboot_drive) {
option_rom[nb_option_roms].name = qemu_strdup(EXTBOOT_FILENAME);
option_rom[nb_option_roms].bootindex = 0;
nb_option_roms++;
}
option_rom[nb_option_roms].name = qemu_strdup(VAPIC_FILENAME);
option_rom[nb_option_roms].bootindex = -1;
nb_option_roms++;
option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
@@ -1168,4 +1182,16 @@ void pc_pci_device_init(PCIBus *pci_bus)
for (bus = 0; bus <= max_bus; bus++) {
pci_create_simple(pci_bus, -1, "lsi53c895a");
}
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);
}
}

12
hw/pc.h
View File

@@ -62,6 +62,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);
@@ -172,6 +173,9 @@ void pcspk_init(ISADevice *pit);
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;
@@ -182,6 +186,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,
@@ -229,6 +237,10 @@ static inline bool isa_ne2000_init(int base, int irq, NICInfo *nd)
return true;
}
/* extboot.c */
void extboot_init(BlockDriverState *bs);
/* e820 types */
#define E820_RAM 1
#define E820_RESERVED 2

View File

@@ -43,12 +43,16 @@
# include <xen/hvm/hvm_info_table.h>
#endif
qemu_irq *ioapic_irq_hack;
#define MAX_IDE_BUS 2
static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
const char *global_cpu_model; /* cpu hotadd */
static void ioapic_init(IsaIrqState *isa_irq_state)
{
DeviceState *dev;
@@ -90,6 +94,8 @@ static void pc_init1(ram_addr_t ram_size,
BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state;
global_cpu_model = cpu_model;
pc_cpus_init(cpu_model);
if (kvmclock_enabled) {
@@ -112,7 +118,11 @@ static void pc_init1(ram_addr_t ram_size,
if (!xen_enabled()) {
cpu_irq = pc_allocate_cpu_irq();
i8259 = i8259_init(cpu_irq[0]);
if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
i8259 = i8259_init(cpu_irq[0]);
} else {
i8259 = kvm_i8259_init(cpu_irq[0]);
}
} else {
i8259 = xen_interrupt_controller_init();
}
@@ -121,7 +131,11 @@ static void pc_init1(ram_addr_t ram_size,
if (pci_enabled) {
ioapic_init(isa_irq_state);
}
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
} else {
isa_irq = i8259;
}
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
@@ -149,7 +163,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);
}
ide_drive_get(hd, MAX_IDE_BUS);

140
hw/pci.c
View File

@@ -29,8 +29,12 @@
#include "net.h"
#include "sysemu.h"
#include "loader.h"
#include "hw/pc.h"
#include "kvm.h"
#include "device-assignment.h"
#include "qemu-objects.h"
#include "range.h"
#include "msi.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -346,6 +350,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
memcpy(s->config, config, size);
pci_update_mappings(s);
msi_post_load(s);
qemu_free(config);
return 0;
@@ -537,6 +542,83 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
return 0;
}
/*
* Parse device seg and bdf in device assignment command:
*
* -pcidevice host=[seg:]bus:dev.func
*
* Parse [seg:]<bus>:<slot>.<func> return -1 on error
*/
int pci_parse_host_devaddr(const char *addr, int *segp, int *busp,
int *slotp, int *funcp)
{
const char *p;
char *e;
int val;
int seg = 0, bus = 0, slot = 0, func = 0;
/* parse optional seg */
p = addr;
val = 0;
while (1) {
p = strchr(p, ':');
if (p) {
val++;
p++;
} else
break;
}
if (val <= 0 || val > 2)
return -1;
p = addr;
if (val == 2) {
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == ':') {
seg = val;
p = e + 1;
}
} else
seg = 0;
/* parse bdf */
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 (seg > 0xffff || bus > 0xff || slot > 0x1f || func > 0x7)
return -1;
if (*e)
return -1;
*segp = seg;
*busp = bus;
*slotp = slot;
*funcp = func;
return 0;
}
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp)
{
@@ -711,7 +793,7 @@ static void pci_config_alloc(PCIDevice *pci_dev)
pci_dev->cmask = qemu_mallocz(config_size);
pci_dev->wmask = qemu_mallocz(config_size);
pci_dev->w1cmask = qemu_mallocz(config_size);
pci_dev->used = qemu_mallocz(config_size);
pci_dev->config_map = qemu_mallocz(config_size);
}
static void pci_config_free(PCIDevice *pci_dev)
@@ -720,7 +802,7 @@ static void pci_config_free(PCIDevice *pci_dev)
qemu_free(pci_dev->cmask);
qemu_free(pci_dev->wmask);
qemu_free(pci_dev->w1cmask);
qemu_free(pci_dev->used);
qemu_free(pci_dev->config_map);
}
/* -1 for devfn means auto assign */
@@ -751,6 +833,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
pci_dev->irq_state = 0;
pci_config_alloc(pci_dev);
memset(pci_dev->config_map, 0xff, PCI_CONFIG_HEADER_SIZE);
pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
pci_config_set_device_id(pci_dev->config, info->device_id);
pci_config_set_revision(pci_dev->config, info->revision);
@@ -1126,6 +1210,14 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
}
#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) ||
@@ -1149,6 +1241,10 @@ 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);
if (pci_irq_disabled(pci_dev))
@@ -1156,6 +1252,11 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
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 */
@@ -1798,7 +1899,7 @@ static int pci_find_space(PCIDevice *pdev, uint8_t size)
int offset = PCI_CONFIG_HEADER_SIZE;
int i;
for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
if (pdev->used[i])
if (pdev->config_map[i])
offset = i + 1;
else if (i - offset + 1 == size)
return offset;
@@ -1823,7 +1924,7 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
return next;
}
static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
{
cpu_register_physical_memory(addr, size, pdev->rom_offset);
}
@@ -1975,18 +2076,34 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
if (!offset) {
return -ENOSPC;
}
} else {
int i;
for (i = offset; i < offset + size; i++) {
if (pdev->config_map[i]) {
fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
"Attempt to add PCI capability %x at offset "
"%x overlaps existing capability %x at offset %x\n",
pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
cap_id, offset, pdev->config_map[i], i);
return -EINVAL;
}
}
}
config = pdev->config + offset;
config[PCI_CAP_LIST_ID] = cap_id;
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
pdev->config[PCI_CAPABILITY_LIST] = offset;
pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
memset(pdev->used + offset, 0xFF, size);
memset(pdev->config_map + offset, cap_id, size);
/* Make capability read-only by default */
memset(pdev->wmask + offset, 0, size);
/* Check capability by default */
memset(pdev->cmask + offset, 0xFF, size);
pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
return offset;
}
@@ -2002,16 +2119,11 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
memset(pdev->w1cmask + offset, 0, size);
/* Clear cmask as device-specific registers can't be checked */
memset(pdev->cmask + offset, 0, size);
memset(pdev->used + offset, 0, size);
memset(pdev->config_map + offset, 0, size);
if (!pdev->config[PCI_CAPABILITY_LIST])
if (!pdev->config[PCI_CAPABILITY_LIST]) {
pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
}
/* Reserve space for capability at a known offset (to call after load). */
void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
{
memset(pdev->used + offset, 0xff, size);
}
}
uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)

View File

@@ -5,6 +5,7 @@
#include "qobject.h"
#include "qdev.h"
#include "kvm.h"
/* PCI includes legacy ISA access. */
#include "isa.h"
@@ -127,6 +128,9 @@ enum {
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
};
typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
int masked);
struct PCIDevice {
DeviceState qdev;
/* PCI config space */
@@ -142,8 +146,8 @@ struct PCIDevice {
/* Used to implement RW1C(Write 1 to Clear) bytes */
uint8_t *w1cmask;
/* Used to allocate config space for capabilities. */
uint8_t *used;
/* Used to allocate config space and track capabilities. */
uint8_t *config_map;
/* the following fields are read only */
PCIBus *bus;
@@ -191,6 +195,21 @@ struct PCIDevice {
char *romfile;
ram_addr_t rom_offset;
uint32_t rom_bar;
/* MSI entries */
int msi_entries_nr;
struct KVMMsiMessage *msi_irq_entries;
/* 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;
KVMMsiMessage *msix_irq_entries;
msix_mask_notifier_func msix_mask_notifier;
};
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -204,23 +223,24 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr,
pcibus_t size, int type);
int pci_map_irq(PCIDevice *pci_dev, int pin);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
uint8_t offset, uint8_t size);
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
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);
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);
@@ -265,6 +285,9 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp);
int pci_parse_host_devaddr(const char *addr, int *segp, int *busp,
int *slotp, int *funcp);
void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);
void pci_bridge_update_mappings(PCIBus *b);

View File

@@ -44,9 +44,16 @@
#define PCI_STATUS 0x06 /* 16 bits */
#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
#ifndef PCI_STATUS_66MHZ
#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
#endif
#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
#ifndef PCI_STATUS_FAST_BACK
#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
#endif
#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
#define PCI_STATUS_DEVSEL_FAST 0x000

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,46 @@ typedef struct {
static const char *s_spk = "pcspk";
static PCSpkState pcspk_state;
#ifdef CONFIG_KVM_PIT
static void kvm_get_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state)
{
struct PITState *pit = DO_UPCAST(struct PITState, dev, dev);
struct kvm_pit_state pit_state;
if (kvm_enabled() && kvm_pit_in_kernel()) {
kvm_get_pit(kvm_state, &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(ISADevice *dev,
struct kvm_pit_state *inkernel_state)
{
struct PITState *pit = DO_UPCAST(struct PITState, dev, dev);
if (kvm_enabled() && 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_state, inkernel_state);
}
}
#else
static inline void kvm_get_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state) { }
static inline void kvm_set_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state) { }
#endif
static inline void generate_samples(PCSpkState *s)
{
unsigned int i;
@@ -72,6 +114,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 +161,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_ns(vm_clock)) << 5;
@@ -125,9 +171,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 +184,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(ISADevice *pit)

View File

@@ -30,6 +30,7 @@
#include "sysbus.h"
#include "range.h"
#include "xen.h"
#include "kvm.h"
/*
* I440FX chipset data sheet.
@@ -238,6 +239,8 @@ static int i440fx_initfn(PCIDevice *dev)
return 0;
}
static PIIX3State *piix3_dev;
static PCIBus *i440fx_common_init(const char *device_name,
PCII440FXState **pi440fx_state,
int *piix3_devfn,
@@ -284,6 +287,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
ram_size = 255;
(*pi440fx_state)->dev.config[0x57]=ram_size;
piix3_dev = piix3;
return b;
}
@@ -354,6 +359,13 @@ static void piix3_write_config(PCIDevice *dev,
}
}
int piix_get_irq(int pin)
{
if (piix3_dev)
return piix3_dev->dev.config[0x60+pin];
return 0;
}
static void piix3_write_config_xen(PCIDevice *dev,
uint32_t address, uint32_t val, int len)
{

140
hw/testdev.c Normal file
View File

@@ -0,0 +1,140 @@
#include <sys/mman.h>
#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)
{
qemu_set_irq(isa_get_irq(addr - 0x2000), !!data);
}
static uint32 test_device_ioport_data;
static void test_device_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
test_device_ioport_data = data;
}
static uint32_t test_device_ioport_read(void *opaque, uint32_t addr)
{
return test_device_ioport_data;
}
static void test_device_flush_page(void *opaque, uint32_t addr, uint32_t data)
{
target_phys_addr_t len = 4096;
void *a = cpu_physical_memory_map(data & ~0xffful, &len, 0);
mprotect(a, 4096, PROT_NONE);
mprotect(a, 4096, PROT_READ|PROT_WRITE);
cpu_physical_memory_unmap(a, len, 0, 0);
}
static char *iomem_buf;
static uint32_t test_iomem_readb(void *opaque, target_phys_addr_t addr)
{
return iomem_buf[addr];
}
static uint32_t test_iomem_readw(void *opaque, target_phys_addr_t addr)
{
return *(uint16_t*)(iomem_buf + addr);
}
static uint32_t test_iomem_readl(void *opaque, target_phys_addr_t addr)
{
return *(uint32_t*)(iomem_buf + addr);
}
static void test_iomem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
iomem_buf[addr] = val;
}
static void test_iomem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
*(uint16_t*)(iomem_buf + addr) = val;
}
static void test_iomem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
*(uint32_t*)(iomem_buf + addr) = val;
}
static CPUReadMemoryFunc * const test_iomem_read[3] = {
test_iomem_readb,
test_iomem_readw,
test_iomem_readl,
};
static CPUWriteMemoryFunc * const test_iomem_write[3] = {
test_iomem_writeb,
test_iomem_writew,
test_iomem_writel,
};
static int init_test_device(ISADevice *isa)
{
struct testdev *dev = DO_UPCAST(struct testdev, dev, isa);
int iomem;
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_read(0xe0, 1, 1, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 1, test_device_ioport_write, dev);
register_ioport_read(0xe0, 1, 2, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 2, test_device_ioport_write, dev);
register_ioport_read(0xe0, 1, 4, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 4, test_device_ioport_write, dev);
register_ioport_write(0xe4, 1, 4, test_device_flush_page, dev);
register_ioport_write(0x2000, 24, 1, test_device_irq_line, NULL);
iomem_buf = qemu_mallocz(0x10000);
iomem = cpu_register_io_memory(test_iomem_read, test_iomem_write, NULL,
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(0xff000000, 0x10000, iomem);
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

@@ -1885,6 +1885,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
@@ -225,7 +225,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

@@ -1,7 +1,9 @@
/*
* Virtio Block Device
* Virtio Balloon Device
*
* Copyright IBM, Corp. 2008
* Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
@@ -43,6 +45,7 @@ typedef struct VirtIOBalloon
size_t stats_vq_offset;
MonitorCompletion *stats_callback;
void *stats_opaque_callback_data;
DeviceState *qdev;
} VirtIOBalloon;
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
@@ -199,36 +202,44 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
return f;
}
static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
MonitorCompletion cb, void *cb_data)
static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
void *cb_data)
{
VirtIOBalloon *dev = opaque;
if (target > ram_size)
target = ram_size;
/* For now, only allow one request at a time. This restriction can be
* removed later by queueing callback and data pairs.
*/
if (dev->stats_callback != NULL) {
return;
}
dev->stats_callback = cb;
dev->stats_opaque_callback_data = cb_data;
if (ENABLE_GUEST_STATS
&& (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq);
return;
}
/* Stats are not supported. Clear out any stale values that might
* have been set by a more featureful guest kernel.
*/
reset_stats(dev);
complete_stats_request(dev);
}
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
{
VirtIOBalloon *dev = opaque;
if (target > ram_size) {
target = ram_size;
}
if (target) {
dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
virtio_notify_config(&dev->vdev);
} else {
/* For now, only allow one request at a time. This restriction can be
* removed later by queueing callback and data pairs.
*/
if (dev->stats_callback != NULL) {
return;
}
dev->stats_callback = cb;
dev->stats_opaque_callback_data = cb_data;
if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq);
} else {
/* Stats are not supported. Clear out any stale values that might
* have been set by a more featureful guest kernel.
*/
reset_stats(dev);
complete_stats_request(dev);
}
}
}
@@ -259,6 +270,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
VirtIODevice *virtio_balloon_init(DeviceState *dev)
{
VirtIOBalloon *s;
int ret;
s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
VIRTIO_ID_BALLOON,
@@ -268,15 +280,29 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
s->vdev.set_config = virtio_balloon_set_config;
s->vdev.get_features = virtio_balloon_get_features;
ret = qemu_add_balloon_handler(virtio_balloon_to_target,
virtio_balloon_stat, s);
if (ret < 0) {
virtio_cleanup(&s->vdev);
return NULL;
}
s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
reset_stats(s);
qemu_add_balloon_handler(virtio_balloon_to_target, s);
s->qdev = dev;
register_savevm(dev, "virtio-balloon", -1, 1,
virtio_balloon_save, virtio_balloon_load, s);
return &s->vdev;
}
void virtio_balloon_exit(VirtIODevice *vdev)
{
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
unregister_savevm(s->qdev, "virtio-balloon", s);
virtio_cleanup(vdev);
}

View File

@@ -545,6 +545,57 @@ static void virtio_pci_guest_notifier_read(void *opaque)
}
}
static int virtio_pci_mask_vq(PCIDevice *dev, unsigned vector,
VirtQueue *vq, int masked)
{
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi,
event_notifier_get_fd(notifier),
!masked);
if (r < 0) {
return (r == -ENOSYS) ? 0 : r;
}
if (masked) {
qemu_set_fd_handler(event_notifier_get_fd(notifier),
virtio_pci_guest_notifier_read, NULL, vq);
} else {
qemu_set_fd_handler(event_notifier_get_fd(notifier),
NULL, NULL, NULL);
}
return 0;
}
static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
int masked)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev;
int r, n;
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
break;
}
if (virtio_queue_vector(vdev, n) != vector) {
continue;
}
r = virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), masked);
if (r < 0) {
goto undo;
}
}
return 0;
undo:
while (--n >= 0) {
if (virtio_queue_vector(vdev, n) != vector) {
continue;
}
virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), !masked);
}
return r;
}
static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
{
VirtIOPCIProxy *proxy = opaque;
@@ -561,6 +612,9 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
} else {
qemu_set_fd_handler(event_notifier_get_fd(notifier),
NULL, NULL, NULL);
/* Test and clear notifier before closing it,
* in case poll callback didn't have time to run. */
virtio_pci_guest_notifier_read(vq);
event_notifier_cleanup(notifier);
}
@@ -579,6 +633,13 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
VirtIODevice *vdev = proxy->vdev;
int r, n;
/* Must unset mask notifier while guest notifier
* is still assigned */
if (!assign) {
r = msix_unset_mask_notifier(&proxy->pci_dev);
assert(r >= 0);
}
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
break;
@@ -590,6 +651,16 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
}
}
/* Must set mask notifier after guest notifier
* has been assigned */
if (assign) {
r = msix_set_mask_notifier(&proxy->pci_dev,
virtio_pci_mask_notifier);
if (r < 0) {
goto assign_error;
}
}
return 0;
assign_error:
@@ -597,6 +668,11 @@ assign_error:
while (--n >= 0) {
virtio_pci_set_guest_notifier(opaque, n, !assign);
}
if (!assign) {
msix_set_mask_notifier(&proxy->pci_dev,
virtio_pci_mask_notifier);
}
return r;
}
@@ -788,10 +864,22 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
VirtIODevice *vdev;
vdev = virtio_balloon_init(&pci_dev->qdev);
if (!vdev) {
return -1;
}
virtio_init_pci(proxy, vdev);
return 0;
}
static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
virtio_pci_stop_ioeventfd(proxy);
virtio_balloon_exit(proxy->vdev);
return virtio_exit_pci(pci_dev);
}
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -866,7 +954,7 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.alias = "virtio-balloon",
.qdev.size = sizeof(VirtIOPCIProxy),
.init = virtio_balloon_init_pci,
.exit = virtio_exit_pci,
.exit = virtio_balloon_exit_pci,
.vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
.device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
.revision = VIRTIO_PCI_ABI_VERSION,

View File

@@ -213,6 +213,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
void virtio_net_exit(VirtIODevice *vdev);
void virtio_blk_exit(VirtIODevice *vdev);
void virtio_serial_exit(VirtIODevice *vdev);
void virtio_balloon_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \

View File

@@ -42,16 +42,16 @@ SECTIONS
.rel.plt :
{
*(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
PROVIDE (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
PROVIDE (__rel_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
PROVIDE (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
PROVIDE (__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

@@ -76,6 +76,15 @@ struct KVMState
int pit_in_kernel;
int xsave, xcrs;
int many_ioeventfds;
int pit_state2;
int irqchip_inject_ioctl;
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
#endif
void *used_gsi_bitmap;
int max_gsi;
};
KVMState *kvm_state;
@@ -781,6 +790,13 @@ int kvm_init(void)
s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
#endif
s->pit_state2 = 0;
#ifdef KVM_CAP_PIT_STATE2
s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
#endif
s->pit_in_kernel = kvm_pit;
ret = kvm_arch_init(s);
if (ret < 0) {
goto err;
@@ -791,6 +807,11 @@ int kvm_init(void)
s->many_ioeventfds = kvm_check_many_ioeventfds();
ret = kvm_create_irqchip(s);
if (ret < 0) {
return ret;
}
cpu_interrupt_handler = kvm_handle_interrupt;
return 0;
@@ -1103,6 +1124,11 @@ int kvm_has_xcrs(void)
return kvm_state->xcrs;
}
int kvm_has_pit_state2(void)
{
return kvm_state->pit_state2;
}
int kvm_has_many_ioeventfds(void)
{
if (!kvm_enabled()) {
@@ -1111,6 +1137,11 @@ int kvm_has_many_ioeventfds(void)
return kvm_state->many_ioeventfds;
}
int kvm_allows_irq0_override(void)
{
return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
}
void kvm_setup_guest_memory(void *start, size_t size)
{
if (!kvm_has_sync_mmu()) {
@@ -1385,6 +1416,23 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
#endif
}
int kvm_set_irqfd(int gsi, int fd, bool assigned)
{
struct kvm_irqfd irqfd = {
.fd = fd,
.gsi = gsi,
.flags = assigned ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
};
int r;
if (!kvm_enabled() || !kvm_irqchip_in_kernel())
return -ENOSYS;
r = kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
if (r < 0)
return r;
return 0;
}
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
{
return kvm_arch_on_sigbus_vcpu(env, code, addr);
@@ -1394,3 +1442,6 @@ int kvm_on_sigbus(int code, void *addr)
{
return kvm_arch_on_sigbus(code, addr);
}
#undef PAGE_SIZE
#include "qemu-kvm.c"

View File

@@ -78,6 +78,16 @@ int kvm_has_many_ioeventfds(void)
return 0;
}
int kvm_allows_irq0_override(void)
{
return 1;
}
int kvm_has_pit_state2(void)
{
return 0;
}
void kvm_setup_guest_memory(void *start, size_t size)
{
}
@@ -120,6 +130,42 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
return -ENOSYS;
}
int kvm_has_gsi_routing(void)
{
return 0;
}
int kvm_get_irq_route_gsi(void)
{
return -ENOSYS;
}
int kvm_msi_message_add(KVMMsiMessage *msg)
{
return -ENOSYS;
}
int kvm_msi_message_del(KVMMsiMessage *msg)
{
return -ENOSYS;
}
int kvm_msi_message_update(KVMMsiMessage *old, KVMMsiMessage *new)
{
return -ENOSYS;
}
int kvm_commit_irq_routes(void)
{
return -ENOSYS;
}
int kvm_set_irq(int irq, int level, int *status)
{
assert(0);
return -ENOSYS;
}
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
{
return 1;
@@ -129,3 +175,8 @@ int kvm_on_sigbus(int code, void *addr)
{
return 1;
}
int kvm_set_irqfd(int gsi, int fd, bool assigned)
{
return -ENOSYS;
}

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

@@ -0,0 +1,380 @@
/*
* 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 "kvm.h"
#include "cpu.h"
#include <stdio.h>
static uint64_t map_addr(CPUState *env, target_ulong virt, unsigned *perms)
{
uint64_t mask = ((1ull << 48) - 1) & ~4095ull;
uint64_t p, pp = 7;
p = env->cr[3];
if (env->cr[4] & 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)
{
return ldub_phys(map_addr(env, virt, NULL));
}
static void write_byte_virt(CPUState *env, target_ulong virt, uint8_t b)
{
cpu_physical_memory_write_rom(map_addr(env, virt, NULL), &b, 1);
}
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_write_rom(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios);
}
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 (env->regs[R_ESP] == 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;
unsigned perms;
uint32_t i;
uint32_t offset, fixup, start = vapic_bios_addr ? : 0xe0000;
uint32_t patch;
if (bios_enabled)
return 1;
probe = (rip & 0xf0000000) + start;
phys = map_addr(env, 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;
patch = ldl_phys(fixup) + bios_addr - vapic_bios.virt_base;
cpu_physical_memory_write_rom(fixup, (uint8_t *)&patch, 4);
}
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_write_rom(vapic_phys + (pcr_cpu << 7) + 4, &one, 1);
env->kvm_vcpu_update_vapic = 0;
bios_enabled = 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)
{
cpu_synchronize_state(env);
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);
}
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)
env->kvm_vcpu_update_vapic = 1;
}
return 0;
}
static void vtpr_ioport_write16(void *opaque, uint32_t addr, uint32_t val)
{
CPUState *env = cpu_single_env;
cpu_synchronize_state(env);
vapic_bios_addr = ((env->segs[R_CS].base + env->eip) & ~(512 - 1)) + val;
bios_enabled = 0;
}
static void vtpr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
CPUState *env = cpu_single_env;
uint32_t rip;
cpu_synchronize_state(env);
rip = env->eip - 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");
for (addr = 0xfffff000u; addr >= 0x80000000u; addr -= 4096)
if (map_addr(env, addr, NULL) == 0xfee00000u) {
real_tpr = addr + 0x80;
break;
}
bios_enabled = 1;
update_vbios_real_tpr();
kvm_tpr_enable_vapic(env);
}
static void kvm_tpr_opt_setup(void)
{
register_savevm(NULL, "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);
}
device_init(kvm_tpr_opt_setup);

33
kvm.h
View File

@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);
int kvm_has_xsave(void);
int kvm_has_xcrs(void);
int kvm_has_many_ioeventfds(void);
int kvm_has_pit_state2(void);
#ifdef NEED_CPU_H
int kvm_init_vcpu(CPUState *env);
@@ -76,10 +77,10 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
#endif
int kvm_pit_in_kernel(void);
int kvm_irqchip_in_kernel(void);
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
int kvm_on_sigbus(int code, void *addr);
#endif /* NEED_CPU_H */
/* internal API */
@@ -91,6 +92,7 @@ int kvm_ioctl(KVMState *s, int type, ...);
int kvm_vm_ioctl(KVMState *s, int type, ...);
#ifdef NEED_CPU_H
int kvm_vcpu_ioctl(CPUState *env, int type, ...);
/* Arch specific hooks */
@@ -186,7 +188,6 @@ static inline void cpu_synchronize_post_init(CPUState *env)
}
}
#if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
target_phys_addr_t *phys_addr);
@@ -195,5 +196,33 @@ int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
#endif
int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
int kvm_set_irqfd(int gsi, int fd, bool assigned);
int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
typedef struct KVMMsiMessage {
uint32_t gsi;
uint32_t addr_lo;
uint32_t addr_hi;
uint32_t data;
} KVMMsiMessage;
int kvm_has_gsi_routing(void);
int kvm_allows_irq0_override(void);
int kvm_get_irq_route_gsi(void);
int kvm_msi_message_add(KVMMsiMessage *msg);
int kvm_msi_message_del(KVMMsiMessage *msg);
int kvm_msi_message_update(KVMMsiMessage *old, KVMMsiMessage *new);
int kvm_commit_irq_routes(void);
int kvm_irqchip_in_kernel(void);
int kvm_set_irq(int irq, int level, int *status);
#ifdef NEED_CPU_H
#include "qemu-kvm.h"
#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

142
kvm/configure vendored Executable file
View File

@@ -0,0 +1,142 @@
#!/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
EOF
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"})
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

41
kvm/extboot/Makefile Normal file
View File

@@ -0,0 +1,41 @@
OBJCOPY=objcopy
# from kernel sources - scripts/Kbuild.include
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# Exit code chooses option. "$$TMP" is can be used as temporary file and
# is automatically cleaned up.
try-run = $(shell set -e; \
TMP="$(TMPOUT).$$$$.tmp"; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi; \
rm -f "$$TMP")
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
$(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
CFLAGS = -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
ifeq ($(call cc-option-yn,-fno-stack-protector),y)
CFLAGS += -fno-stack-protector
endif
all: extboot.bin
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
extboot.img: extboot.o
$(LD) --oformat binary -Ttext 0 -o $@ $<
extboot.bin: extboot.img signrom
./signrom extboot.img extboot.bin
signrom: signrom.c
$(CC) -o $@ -g -Wall $^
clean:
$(RM) *.o *.img *.bin signrom *~

6
kvm/extboot/STATUS Normal file
View File

@@ -0,0 +1,6 @@
Working
-------
Ubuntu Server 7.04 (i386)
Windows 2000 Professional (i386)
Windows XP SP2 (i386)

79
kvm/extboot/signrom.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* Extended Boot Option ROM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corporation, 2007
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fin, *fout;
char buffer[512], oldbuffer[512];
int i, size, lag = 0;
uint8_t sum = 0;
if (argc != 3) {
printf("Usage: %s ROM OUTPUT\n", argv[0]);
return 1;
}
fin = fopen(argv[1], "rb");
fout = fopen(argv[2], "wb");
if (fin == NULL || fout == NULL) {
fprintf(stderr, "Could not open input/output files\n");
return 1;
}
do {
size = fread(buffer, 512, 1, fin);
if (size == 1) {
for (i = 0; i < 512; i++)
sum += buffer[i];
if (lag) {
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Write failed\n");
return 1;
}
}
lag = 1;
memcpy(oldbuffer, buffer, 512);
}
} while (size == 1);
if (size != 0) {
fprintf(stderr, "Failed to read from input file\n");
return 1;
}
oldbuffer[511] = -sum;
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Failed to write to output file\n");
return 1;
}
fclose(fin);
fclose(fout);
return 0;
}

264
kvm/include/ia64/asm/kvm.h Normal file
View File

@@ -0,0 +1,264 @@
#ifndef __ASM_IA64_KVM_H
#define __ASM_IA64_KVM_H
/*
* kvm structure definitions for ia64
*
* Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/ioctl.h>
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_IOAPIC
#define __KVM_HAVE_DEVICE_ASSIGNMENT
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
#define KVM_IOAPIC_NUM_PINS 48
struct kvm_ioapic_state {
__u64 base_address;
__u32 ioregsel;
__u32 id;
__u32 irr;
__u32 pad;
union {
__u64 bits;
struct {
__u8 vector;
__u8 delivery_mode:3;
__u8 dest_mode:1;
__u8 delivery_status:1;
__u8 polarity:1;
__u8 remote_irr:1;
__u8 trig_mode:1;
__u8 mask:1;
__u8 reserve:7;
__u8 reserved[4];
__u8 dest_id;
} fields;
} redirtbl[KVM_IOAPIC_NUM_PINS];
};
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
#define KVM_NR_IRQCHIPS 3
#define KVM_CONTEXT_SIZE 8*1024
struct kvm_fpreg {
union {
unsigned long bits[2];
long double __dummy; /* force 16-byte alignment */
} u;
};
union context {
/* 8K size */
char dummy[KVM_CONTEXT_SIZE];
struct {
unsigned long psr;
unsigned long pr;
unsigned long caller_unat;
unsigned long pad;
unsigned long gr[32];
unsigned long ar[128];
unsigned long br[8];
unsigned long cr[128];
unsigned long rr[8];
unsigned long ibr[8];
unsigned long dbr[8];
unsigned long pkr[8];
struct kvm_fpreg fr[128];
};
};
struct thash_data {
union {
struct {
unsigned long p : 1; /* 0 */
unsigned long rv1 : 1; /* 1 */
unsigned long ma : 3; /* 2-4 */
unsigned long a : 1; /* 5 */
unsigned long d : 1; /* 6 */
unsigned long pl : 2; /* 7-8 */
unsigned long ar : 3; /* 9-11 */
unsigned long ppn : 38; /* 12-49 */
unsigned long rv2 : 2; /* 50-51 */
unsigned long ed : 1; /* 52 */
unsigned long ig1 : 11; /* 53-63 */
};
struct {
unsigned long __rv1 : 53; /* 0-52 */
unsigned long contiguous : 1; /*53 */
unsigned long tc : 1; /* 54 TR or TC */
unsigned long cl : 1;
/* 55 I side or D side cache line */
unsigned long len : 4; /* 56-59 */
unsigned long io : 1; /* 60 entry is for io or not */
unsigned long nomap : 1;
/* 61 entry cann't be inserted into machine TLB.*/
unsigned long checked : 1;
/* 62 for VTLB/VHPT sanity check */
unsigned long invalid : 1;
/* 63 invalid entry */
};
unsigned long page_flags;
}; /* same for VHPT and TLB */
union {
struct {
unsigned long rv3 : 2;
unsigned long ps : 6;
unsigned long key : 24;
unsigned long rv4 : 32;
};
unsigned long itir;
};
union {
struct {
unsigned long ig2 : 12;
unsigned long vpn : 49;
unsigned long vrn : 3;
};
unsigned long ifa;
unsigned long vadr;
struct {
unsigned long tag : 63;
unsigned long ti : 1;
};
unsigned long etag;
};
union {
struct thash_data *next;
unsigned long rid;
unsigned long gpaddr;
};
};
#define NITRS 8
#define NDTRS 8
struct saved_vpd {
unsigned long vhpi;
unsigned long vgr[16];
unsigned long vbgr[16];
unsigned long vnat;
unsigned long vbnat;
unsigned long vcpuid[5];
unsigned long vpsr;
unsigned long vpr;
union {
unsigned long vcr[128];
struct {
unsigned long dcr;
unsigned long itm;
unsigned long iva;
unsigned long rsv1[5];
unsigned long pta;
unsigned long rsv2[7];
unsigned long ipsr;
unsigned long isr;
unsigned long rsv3;
unsigned long iip;
unsigned long ifa;
unsigned long itir;
unsigned long iipa;
unsigned long ifs;
unsigned long iim;
unsigned long iha;
unsigned long rsv4[38];
unsigned long lid;
unsigned long ivr;
unsigned long tpr;
unsigned long eoi;
unsigned long irr[4];
unsigned long itv;
unsigned long pmv;
unsigned long cmcv;
unsigned long rsv5[5];
unsigned long lrr0;
unsigned long lrr1;
unsigned long rsv6[46];
};
};
};
struct kvm_regs {
struct saved_vpd vpd;
/*Arch-regs*/
int mp_state;
unsigned long vmm_rr;
/* TR and TC. */
struct thash_data itrs[NITRS];
struct thash_data dtrs[NDTRS];
/* Bit is set if there is a tr/tc for the region. */
unsigned char itr_regions;
unsigned char dtr_regions;
unsigned char tc_regions;
char irq_check;
unsigned long saved_itc;
unsigned long itc_check;
unsigned long timer_check;
unsigned long timer_pending;
unsigned long last_itc;
unsigned long vrr[8];
unsigned long ibr[8];
unsigned long dbr[8];
unsigned long insvc[4]; /* Interrupt in service. */
unsigned long xtp;
unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
unsigned long metaphysical_rr4; /* from kvm_arch (so is pinned) */
unsigned long metaphysical_saved_rr0; /* from kvm_arch */
unsigned long metaphysical_saved_rr4; /* from kvm_arch */
unsigned long fp_psr; /*used for lazy float register */
unsigned long saved_gp;
/*for phycial emulation */
union context saved_guest;
unsigned long reserved[64]; /* for future use */
};
struct kvm_sregs {
};
struct kvm_fpu {
};
#define KVM_IA64_VCPU_STACK_SHIFT 16
#define KVM_IA64_VCPU_STACK_SIZE (1UL << KVM_IA64_VCPU_STACK_SHIFT)
struct kvm_ia64_vcpu_stack {
unsigned char stack[KVM_IA64_VCPU_STACK_SIZE];
};
struct kvm_debug_exit_arch {
};
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
};
#endif

View File

@@ -0,0 +1,31 @@
#ifndef __IA64_KVM_PARA_H
#define __IA64_KVM_PARA_H
/*
* Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
*
* 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.
*
*/
#ifdef __KERNEL__
static inline unsigned int kvm_arch_para_features(void)
{
return 0;
}
#endif
#endif

View File

@@ -0,0 +1,2 @@
/* dummy file */

View File

@@ -0,0 +1,43 @@
#ifndef KVM_UNIFDEF_H
#define KVM_UNIFDEF_H
#ifdef __i386__
#ifndef CONFIG_X86_32
#define CONFIG_X86_32 1
#endif
#endif
#ifdef __x86_64__
#ifndef CONFIG_X86_64
#define CONFIG_X86_64 1
#endif
#endif
#if defined(__i386__) || defined (__x86_64__)
#ifndef CONFIG_X86
#define CONFIG_X86 1
#endif
#endif
#ifdef __ia64__
#ifndef CONFIG_IA64
#define CONFIG_IA64 1
#endif
#endif
#ifdef __PPC__
#ifndef CONFIG_PPC
#define CONFIG_PPC 1
#endif
#endif
#ifdef __s390__
#ifndef CONFIG_S390
#define CONFIG_S390 1
#endif
#endif
#endif
#define __user

784
kvm/include/linux/kvm.h Normal file
View File

@@ -0,0 +1,784 @@
#ifndef __LINUX_KVM_H
#define __LINUX_KVM_H
/*
* Userspace interface for /dev/kvm - kernel based virtual machine
*
* Note: you must update KVM_API_VERSION if you change this interface.
*/
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <asm/kvm.h>
#define KVM_API_VERSION 12
/* *** Deprecated interfaces *** */
#define KVM_TRC_SHIFT 16
#define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT)
#define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1))
#define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01)
#define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02)
#define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01)
#define KVM_TRC_HEAD_SIZE 12
#define KVM_TRC_CYCLE_SIZE 8
#define KVM_TRC_EXTRA_MAX 7
#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04)
#define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05)
#define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06)
#define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07)
#define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08)
#define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09)
#define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A)
#define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B)
#define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C)
#define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D)
#define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E)
#define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F)
#define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10)
#define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11)
#define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12)
#define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13)
#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14)
#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15)
#define KVM_TRC_GTLB_WRITE (KVM_TRC_HANDLER + 0x16)
#define KVM_TRC_STLB_WRITE (KVM_TRC_HANDLER + 0x17)
#define KVM_TRC_STLB_INVAL (KVM_TRC_HANDLER + 0x18)
#define KVM_TRC_PPC_INSTR (KVM_TRC_HANDLER + 0x19)
struct kvm_user_trace_setup {
__u32 buf_size;
__u32 buf_nr;
};
#define __KVM_DEPRECATED_MAIN_W_0x06 \
_IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
struct kvm_breakpoint {
__u32 enabled;
__u32 padding;
__u64 address;
};
struct kvm_debug_guest {
__u32 enabled;
__u32 pad;
struct kvm_breakpoint breakpoints[4];
__u32 singlestep;
};
#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
/* *** End of deprecated interfaces *** */
/* for KVM_CREATE_MEMORY_REGION */
struct kvm_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
};
/* for KVM_SET_USER_MEMORY_REGION */
struct kvm_userspace_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
__u64 userspace_addr; /* start of the userspace allocated memory */
};
/* for kvm_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES 1UL
#define KVM_MEMSLOT_INVALID (1UL << 1)
/* for KVM_IRQ_LINE */
struct kvm_irq_level {
/*
* ACPI gsi notion of irq.
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
* For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
*/
union {
__u32 irq;
__s32 status;
};
__u32 level;
};
struct kvm_irqchip {
__u32 chip_id;
__u32 pad;
union {
char dummy[512]; /* reserving space */
#ifdef __KVM_HAVE_PIT
struct kvm_pic_state pic;
#endif
#ifdef __KVM_HAVE_IOAPIC
struct kvm_ioapic_state ioapic;
#endif
} chip;
};
/* for KVM_CREATE_PIT2 */
struct kvm_pit_config {
__u32 flags;
__u32 pad[15];
};
#define KVM_PIT_SPEAKER_DUMMY 1
#define KVM_EXIT_UNKNOWN 0
#define KVM_EXIT_EXCEPTION 1
#define KVM_EXIT_IO 2
#define KVM_EXIT_HYPERCALL 3
#define KVM_EXIT_DEBUG 4
#define KVM_EXIT_HLT 5
#define KVM_EXIT_MMIO 6
#define KVM_EXIT_IRQ_WINDOW_OPEN 7
#define KVM_EXIT_SHUTDOWN 8
#define KVM_EXIT_FAIL_ENTRY 9
#define KVM_EXIT_INTR 10
#define KVM_EXIT_SET_TPR 11
#define KVM_EXIT_TPR_ACCESS 12
#define KVM_EXIT_S390_SIEIC 13
#define KVM_EXIT_S390_RESET 14
#define KVM_EXIT_DCR 15
#define KVM_EXIT_NMI 16
#define KVM_EXIT_INTERNAL_ERROR 17
#define KVM_EXIT_OSI 18
/* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
__u8 request_interrupt_window;
__u8 padding1[7];
/* out */
__u32 exit_reason;
__u8 ready_for_interrupt_injection;
__u8 if_flag;
__u8 padding2[2];
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;
__u64 apic_base;
#ifdef __KVM_S390
/* the processor status word for s390 */
__u64 psw_mask; /* psw upper half */
__u64 psw_addr; /* psw lower half */
#endif
union {
/* KVM_EXIT_UNKNOWN */
struct {
__u64 hardware_exit_reason;
} hw;
/* KVM_EXIT_FAIL_ENTRY */
struct {
__u64 hardware_entry_failure_reason;
} fail_entry;
/* KVM_EXIT_EXCEPTION */
struct {
__u32 exception;
__u32 error_code;
} ex;
/* KVM_EXIT_IO */
struct {
#define KVM_EXIT_IO_IN 0
#define KVM_EXIT_IO_OUT 1
__u8 direction;
__u8 size; /* bytes */
__u16 port;
__u32 count;
__u64 data_offset; /* relative to kvm_run start */
} io;
struct {
struct kvm_debug_exit_arch arch;
} debug;
/* KVM_EXIT_MMIO */
struct {
__u64 phys_addr;
__u8 data[8];
__u32 len;
__u8 is_write;
} mmio;
/* KVM_EXIT_HYPERCALL */
struct {
__u64 nr;
__u64 args[6];
__u64 ret;
__u32 longmode;
__u32 pad;
} hypercall;
/* KVM_EXIT_TPR_ACCESS */
struct {
__u64 rip;
__u32 is_write;
__u32 pad;
} tpr_access;
/* KVM_EXIT_S390_SIEIC */
struct {
__u8 icptcode;
__u16 ipa;
__u32 ipb;
} s390_sieic;
/* KVM_EXIT_S390_RESET */
#define KVM_S390_RESET_POR 1
#define KVM_S390_RESET_CLEAR 2
#define KVM_S390_RESET_SUBSYSTEM 4
#define KVM_S390_RESET_CPU_INIT 8
#define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags;
/* KVM_EXIT_DCR */
struct {
__u32 dcrn;
__u32 data;
__u8 is_write;
} dcr;
struct {
__u32 suberror;
/* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
__u32 ndata;
__u64 data[16];
} internal;
/* KVM_EXIT_OSI */
struct {
__u64 gprs[32];
} osi;
/* Fix the size of the union. */
char padding[256];
};
};
/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
struct kvm_coalesced_mmio_zone {
__u64 addr;
__u32 size;
__u32 pad;
};
struct kvm_coalesced_mmio {
__u64 phys_addr;
__u32 len;
__u32 pad;
__u8 data[8];
};
struct kvm_coalesced_mmio_ring {
__u32 first, last;
struct kvm_coalesced_mmio coalesced_mmio[0];
};
#define KVM_COALESCED_MMIO_MAX \
((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
sizeof(struct kvm_coalesced_mmio))
/* for KVM_TRANSLATE */
struct kvm_translation {
/* in */
__u64 linear_address;
/* out */
__u64 physical_address;
__u8 valid;
__u8 writeable;
__u8 usermode;
__u8 pad[5];
};
/* for KVM_INTERRUPT */
struct kvm_interrupt {
/* in */
__u32 irq;
};
/* for KVM_GET_DIRTY_LOG */
struct kvm_dirty_log {
__u32 slot;
__u32 padding1;
union {
void *dirty_bitmap; /* one bit per page */
__u64 padding2;
};
};
/* for KVM_SET_SIGNAL_MASK */
struct kvm_signal_mask {
__u32 len;
__u8 sigset[0];
};
/* for KVM_TPR_ACCESS_REPORTING */
struct kvm_tpr_access_ctl {
__u32 enabled;
__u32 flags;
__u32 reserved[8];
};
/* for KVM_SET_VAPIC_ADDR */
struct kvm_vapic_addr {
__u64 vapic_addr;
};
/* for KVM_SET_MPSTATE */
#define KVM_MP_STATE_RUNNABLE 0
#define KVM_MP_STATE_UNINITIALIZED 1
#define KVM_MP_STATE_INIT_RECEIVED 2
#define KVM_MP_STATE_HALTED 3
#define KVM_MP_STATE_SIPI_RECEIVED 4
struct kvm_mp_state {
__u32 mp_state;
};
struct kvm_s390_psw {
__u64 mask;
__u64 addr;
};
/* valid values for type in kvm_s390_interrupt */
#define KVM_S390_SIGP_STOP 0xfffe0000u
#define KVM_S390_PROGRAM_INT 0xfffe0001u
#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
#define KVM_S390_RESTART 0xfffe0003u
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
#define KVM_S390_INT_EMERGENCY 0xffff1201u
struct kvm_s390_interrupt {
__u32 type;
__u32 parm;
__u64 parm64;
};
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
#define KVM_GUESTDBG_SINGLESTEP 0x00000002
struct kvm_guest_debug {
__u32 control;
__u32 pad;
struct kvm_guest_debug_arch arch;
};
enum {
kvm_ioeventfd_flag_nr_datamatch,
kvm_ioeventfd_flag_nr_pio,
kvm_ioeventfd_flag_nr_deassign,
kvm_ioeventfd_flag_nr_max,
};
#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio)
#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign)
#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1)
struct kvm_ioeventfd {
__u64 datamatch;
__u64 addr; /* legal pio/mmio address */
__u32 len; /* 1, 2, 4, or 8 bytes */
__s32 fd;
__u32 flags;
__u8 pad[36];
};
/* for KVM_ENABLE_CAP */
struct kvm_enable_cap {
/* in */
__u32 cap;
__u32 flags;
__u64 args[4];
__u8 pad[64];
};
#define KVMIO 0xAE
/*
* ioctls for /dev/kvm fds:
*/
#define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */
#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
#define KVM_S390_ENABLE_SIE _IO(KVMIO, 0x06)
/*
* Check if a kvm extension is available. Argument is extension number,
* return is 1 (yes) or 0 (no, sorry).
*/
#define KVM_CHECK_EXTENSION _IO(KVMIO, 0x03)
/*
* Get size for mmap(vcpu_fd)
*/
#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
#define KVM_TRACE_ENABLE __KVM_DEPRECATED_MAIN_W_0x06
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
/*
* Extension capability list.
*/
#define KVM_CAP_IRQCHIP 0
#define KVM_CAP_HLT 1
#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
#define KVM_CAP_USER_MEMORY 3
#define KVM_CAP_SET_TSS_ADDR 4
#define KVM_CAP_VAPIC 6
#define KVM_CAP_EXT_CPUID 7
#define KVM_CAP_CLOCKSOURCE 8
#define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
#define KVM_CAP_PIT 11
#define KVM_CAP_NOP_IO_DELAY 12
#define KVM_CAP_PV_MMU 13
#define KVM_CAP_MP_STATE 14
#define KVM_CAP_COALESCED_MMIO 15
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
#define KVM_CAP_DEVICE_ASSIGNMENT 17
#endif
#define KVM_CAP_IOMMU 18
#ifdef __KVM_HAVE_MSI
#define KVM_CAP_DEVICE_MSI 20
#endif
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
#ifdef __KVM_HAVE_USER_NMI
#define KVM_CAP_USER_NMI 22
#endif
#ifdef __KVM_HAVE_GUEST_DEBUG
#define KVM_CAP_SET_GUEST_DEBUG 23
#endif
#ifdef __KVM_HAVE_PIT
#define KVM_CAP_REINJECT_CONTROL 24
#endif
#ifdef __KVM_HAVE_IOAPIC
#define KVM_CAP_IRQ_ROUTING 25
#endif
#define KVM_CAP_IRQ_INJECT_STATUS 26
#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
#define KVM_CAP_DEVICE_DEASSIGNMENT 27
#endif
#ifdef __KVM_HAVE_MSIX
#define KVM_CAP_DEVICE_MSIX 28
#endif
#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
#ifdef __KVM_HAVE_MCE
#define KVM_CAP_MCE 31
#endif
#define KVM_CAP_IRQFD 32
#ifdef __KVM_HAVE_PIT
#define KVM_CAP_PIT2 33
#endif
#define KVM_CAP_SET_BOOT_CPU_ID 34
#ifdef __KVM_HAVE_PIT_STATE2
#define KVM_CAP_PIT_STATE2 35
#endif
#define KVM_CAP_IOEVENTFD 36
#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
#ifdef __KVM_HAVE_XEN_HVM
#define KVM_CAP_XEN_HVM 38
#endif
#define KVM_CAP_ADJUST_CLOCK 39
#define KVM_CAP_INTERNAL_ERROR_DATA 40
#ifdef __KVM_HAVE_VCPU_EVENTS
#define KVM_CAP_VCPU_EVENTS 41
#endif
#define KVM_CAP_S390_PSW 42
#define KVM_CAP_PPC_SEGSTATE 43
#define KVM_CAP_HYPERV 44
#define KVM_CAP_HYPERV_VAPIC 45
#define KVM_CAP_HYPERV_SPIN 46
#define KVM_CAP_PCI_SEGMENT 47
#define KVM_CAP_PPC_PAIRED_SINGLES 48
#define KVM_CAP_INTR_SHADOW 49
#ifdef __KVM_HAVE_DEBUGREGS
#define KVM_CAP_DEBUGREGS 50
#endif
#define KVM_CAP_X86_ROBUST_SINGLESTEP 51
#define KVM_CAP_PPC_OSI 52
#define KVM_CAP_PPC_UNSET_IRQ 53
#define KVM_CAP_ENABLE_CAP 54
#ifdef __KVM_HAVE_XSAVE
#define KVM_CAP_XSAVE 55
#endif
#ifdef __KVM_HAVE_XCRS
#define KVM_CAP_XCRS 56
#endif
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing_irqchip {
__u32 irqchip;
__u32 pin;
};
struct kvm_irq_routing_msi {
__u32 address_lo;
__u32 address_hi;
__u32 data;
__u32 pad;
};
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
struct kvm_irq_routing_entry {
__u32 gsi;
__u32 type;
__u32 flags;
__u32 pad;
union {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
__u32 pad[8];
} u;
};
struct kvm_irq_routing {
__u32 nr;
__u32 flags;
struct kvm_irq_routing_entry entries[0];
};
#endif
#ifdef KVM_CAP_MCE
/* x86 MCE */
struct kvm_x86_mce {
__u64 status;
__u64 addr;
__u64 misc;
__u64 mcg_status;
__u8 bank;
__u8 pad1[7];
__u64 pad2[3];
};
#endif
#ifdef KVM_CAP_XEN_HVM
struct kvm_xen_hvm_config {
__u32 flags;
__u32 msr;
__u64 blob_addr_32;
__u64 blob_addr_64;
__u8 blob_size_32;
__u8 blob_size_64;
__u8 pad2[30];
};
#endif
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
struct kvm_irqfd {
__u32 fd;
__u32 gsi;
__u32 flags;
__u8 pad[20];
};
struct kvm_clock_data {
__u64 clock;
__u32 flags;
__u32 pad[9];
};
/*
* ioctls for VM fds
*/
#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region)
/*
* KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
* a vcpu fd.
*/
#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45)
#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
struct kvm_userspace_memory_region)
#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
/* Device model IOC */
#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
#define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state)
#define KVM_IRQ_LINE_STATUS _IOWR(KVMIO, 0x67, struct kvm_irq_level)
#define KVM_REGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
#define KVM_UNREGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone)
#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
struct kvm_assigned_pci_dev)
#define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
#define KVM_ASSIGN_IRQ __KVM_DEPRECATED_VM_R_0x70
#define KVM_ASSIGN_DEV_IRQ _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
struct kvm_assigned_pci_dev)
#define KVM_ASSIGN_SET_MSIX_NR _IOW(KVMIO, 0x73, \
struct kvm_assigned_msix_nr)
#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO, 0x74, \
struct kvm_assigned_msix_entry)
#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
#define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config)
#define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data)
#define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data)
/* Available with KVM_CAP_PIT_STATE2 */
#define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
/*
* ioctls for vcpu fds
*/
#define KVM_RUN _IO(KVMIO, 0x80)
#define KVM_GET_REGS _IOR(KVMIO, 0x81, struct kvm_regs)
#define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs)
#define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs)
#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs)
#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation)
#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt)
/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
#define KVM_DEBUG_GUEST __KVM_DEPRECATED_VCPU_W_0x87
#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs)
#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
#define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state)
#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state)
#define KVM_SET_CPUID2 _IOW(KVMIO, 0x90, struct kvm_cpuid2)
#define KVM_GET_CPUID2 _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
/* Available with KVM_CAP_VAPIC */
#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
/* Available with KVM_CAP_VAPIC */
#define KVM_SET_VAPIC_ADDR _IOW(KVMIO, 0x93, struct kvm_vapic_addr)
/* valid for virtual machine (for floating interrupt)_and_ vcpu */
#define KVM_S390_INTERRUPT _IOW(KVMIO, 0x94, struct kvm_s390_interrupt)
/* store status for s390 */
#define KVM_S390_STORE_STATUS_NOADDR (-1ul)
#define KVM_S390_STORE_STATUS_PREFIXED (-2ul)
#define KVM_S390_STORE_STATUS _IOW(KVMIO, 0x95, unsigned long)
/* initial ipl psw for s390 */
#define KVM_S390_SET_INITIAL_PSW _IOW(KVMIO, 0x96, struct kvm_s390_psw)
/* initial reset for s390 */
#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
/* Available with KVM_CAP_NMI */
#define KVM_NMI _IO(KVMIO, 0x9a)
/* Available with KVM_CAP_SET_GUEST_DEBUG */
#define KVM_SET_GUEST_DEBUG _IOW(KVMIO, 0x9b, struct kvm_guest_debug)
/* MCE for x86 */
#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
/* IA64 stack access */
#define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
#define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *)
/* Available with KVM_CAP_VCPU_EVENTS */
#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events)
#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events)
/* Available with KVM_CAP_DEBUGREGS */
#define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs)
#define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs)
#define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap)
/* Available with KVM_CAP_XSAVE */
#define KVM_GET_XSAVE _IOR(KVMIO, 0xa4, struct kvm_xsave)
#define KVM_SET_XSAVE _IOW(KVMIO, 0xa5, struct kvm_xsave)
/* Available with KVM_CAP_XCRS */
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
struct kvm_assigned_pci_dev {
__u32 assigned_dev_id;
__u32 busnr;
__u32 devfn;
__u32 flags;
__u32 segnr;
union {
__u32 reserved[11];
};
};
#define KVM_DEV_IRQ_HOST_INTX (1 << 0)
#define KVM_DEV_IRQ_HOST_MSI (1 << 1)
#define KVM_DEV_IRQ_HOST_MSIX (1 << 2)
#define KVM_DEV_IRQ_GUEST_INTX (1 << 8)
#define KVM_DEV_IRQ_GUEST_MSI (1 << 9)
#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10)
#define KVM_DEV_IRQ_HOST_MASK 0x00ff
#define KVM_DEV_IRQ_GUEST_MASK 0xff00
struct kvm_assigned_irq {
__u32 assigned_dev_id;
__u32 host_irq;
__u32 guest_irq;
__u32 flags;
union {
struct {
__u32 addr_lo;
__u32 addr_hi;
__u32 data;
} guest_msi;
__u32 reserved[12];
};
};
struct kvm_assigned_msix_nr {
__u32 assigned_dev_id;
__u16 entry_nr;
__u16 padding;
};
#define KVM_MAX_MSIX_PER_DEV 256
struct kvm_assigned_msix_entry {
__u32 assigned_dev_id;
__u32 gsi;
__u16 entry; /* The index of entry in the MSI-X table */
__u16 padding[3];
};
#endif /* __LINUX_KVM_H */

View File

@@ -0,0 +1,41 @@
#ifndef __LINUX_KVM_PARA_H
#define __LINUX_KVM_PARA_H
/*
* This header file provides a method for making a hypercall to the host
* Architectures should define:
* - kvm_hypercall0, kvm_hypercall1...
* - kvm_arch_para_features
* - kvm_para_available
*/
/* Return values for hypercalls */
#define KVM_ENOSYS 1000
#define KVM_EFAULT EFAULT
#define KVM_E2BIG E2BIG
#define KVM_EPERM EPERM
#define KVM_HC_VAPIC_POLL_IRQ 1
#define KVM_HC_MMU_OP 2
/*
* hypercalls use architecture specific
*/
#include <asm/kvm_para.h>
#ifdef __KERNEL__
#ifdef CONFIG_KVM_GUEST
void __init kvm_guest_init(void);
#else
#define kvm_guest_init() do { } while (0)
#endif
static inline int kvm_para_has_feature(unsigned int feature)
{
if (kvm_arch_para_features() & (1UL << feature))
return 1;
return 0;
}
#endif /* __KERNEL__ */
#endif /* __LINUX_KVM_PARA_H */

130
kvm/include/linux/vhost.h Normal file
View File

@@ -0,0 +1,130 @@
#ifndef _LINUX_VHOST_H
#define _LINUX_VHOST_H
/* Userspace interface for in-kernel virtio accelerators. */
/* vhost is used to reduce the number of system calls involved in virtio.
*
* Existing virtio net code is used in the guest without modification.
*
* This header includes interface used by userspace hypervisor for
* device configuration.
*/
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
struct vhost_vring_state {
unsigned int index;
unsigned int num;
};
struct vhost_vring_file {
unsigned int index;
int fd; /* Pass -1 to unbind from file. */
};
struct vhost_vring_addr {
unsigned int index;
/* Option flags. */
unsigned int flags;
/* Flag values: */
/* Whether log address is valid. If set enables logging. */
#define VHOST_VRING_F_LOG 0
/* Start of array of descriptors (virtually contiguous) */
__u64 desc_user_addr;
/* Used structure address. Must be 32 bit aligned */
__u64 used_user_addr;
/* Available structure address. Must be 16 bit aligned */
__u64 avail_user_addr;
/* Logging support. */
/* Log writes to used structure, at offset calculated from specified
* address. Address must be 32 bit aligned. */
__u64 log_guest_addr;
};
struct vhost_memory_region {
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
__u64 userspace_addr;
__u64 flags_padding; /* No flags are currently specified. */
};
/* All region addresses and sizes must be 4K aligned. */
#define VHOST_PAGE_SIZE 0x1000
struct vhost_memory {
__u32 nregions;
__u32 padding;
struct vhost_memory_region regions[0];
};
/* ioctls */
#define VHOST_VIRTIO 0xAF
/* Features bitmask for forward compatibility. Transport bits are used for
* vhost specific features. */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
/* Set current process as the (exclusive) owner of this file descriptor. This
* must be called before any other vhost command. Further calls to
* VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
/* Give up ownership, and reset the device to default values.
* Allows subsequent call to VHOST_OWNER_SET to succeed. */
#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
/* Set up/modify memory layout */
#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
/* Write logging setup. */
/* Memory writes can optionally be logged by setting bit at an offset
* (calculated from the physical address) from specified log base.
* The bit is set using an atomic 32 bit operation. */
/* Set base address for logging. */
#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
/* Specify an eventfd file descriptor to signal on log write. */
#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
/* Ring setup. */
/* Set number of descriptors in ring. This parameter can not
* be modified while ring is running (bound to a device). */
#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
/* Set addresses for the ring. */
#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
/* Base value where queue looks for available descriptors */
#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/* Get accessor: reads index, writes value in num */
#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/* The following ioctls use eventfd file descriptors to signal and poll
* for events. */
/* Set eventfd to poll for added buffers */
#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
/* Set eventfd to signal when buffers have beed used */
#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
/* Set eventfd to signal an error */
#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
/* VHOST_NET specific defines */
/* Attach virtio net ring to a raw socket, or tap device.
* The socket must be already bound to an ethernet device, this device will be
* used for transmit. Pass fd -1 to unbind from the socket and the transmit
* device. This can be used to stop the ring (e.g. for migration). */
#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
/* Feature bits */
/* Log all write descriptors. Can be changed while device is active. */
#define VHOST_F_LOG_ALL 26
/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
#define VHOST_NET_F_VIRTIO_NET_HDR 27
#endif

View File

@@ -0,0 +1,62 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corp. 2007
*
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef __LINUX_KVM_POWERPC_H
#define __LINUX_KVM_POWERPC_H
#include <linux/types.h>
struct kvm_regs {
__u64 pc;
__u64 cr;
__u64 ctr;
__u64 lr;
__u64 xer;
__u64 msr;
__u64 srr0;
__u64 srr1;
__u64 pid;
__u64 sprg0;
__u64 sprg1;
__u64 sprg2;
__u64 sprg3;
__u64 sprg4;
__u64 sprg5;
__u64 sprg6;
__u64 sprg7;
__u64 gpr[32];
};
struct kvm_sregs {
};
struct kvm_fpu {
__u64 fpr[32];
};
struct kvm_debug_exit_arch {
};
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
};
#endif /* __LINUX_KVM_POWERPC_H */

View File

@@ -0,0 +1,37 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corp. 2008
*
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__
#ifdef __KERNEL__
static inline int kvm_para_available(void)
{
return 0;
}
static inline unsigned int kvm_arch_para_features(void)
{
return 0;
}
#endif /* __KERNEL__ */
#endif /* __POWERPC_KVM_PARA_H__ */

324
kvm/include/x86/asm/kvm.h Normal file
View File

@@ -0,0 +1,324 @@
#ifndef _ASM_X86_KVM_H
#define _ASM_X86_KVM_H
/*
* KVM x86 specific structures and definitions
*
*/
#include <linux/types.h>
#include <linux/ioctl.h>
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
#define __KVM_HAVE_IOAPIC
#define __KVM_HAVE_DEVICE_ASSIGNMENT
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_MSIX
#define __KVM_HAVE_MCE
#define __KVM_HAVE_PIT_STATE2
#define __KVM_HAVE_XEN_HVM
#define __KVM_HAVE_VCPU_EVENTS
#define __KVM_HAVE_DEBUGREGS
#define __KVM_HAVE_XSAVE
#define __KVM_HAVE_XCRS
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
struct kvm_memory_alias {
__u32 slot; /* this has a different namespace than memory slots */
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size;
__u64 target_phys_addr;
};
/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
struct kvm_pic_state {
__u8 last_irr; /* edge detection */
__u8 irr; /* interrupt request register */
__u8 imr; /* interrupt mask register */
__u8 isr; /* interrupt service register */
__u8 priority_add; /* highest irq priority */
__u8 irq_base;
__u8 read_reg_select;
__u8 poll;
__u8 special_mask;
__u8 init_state;
__u8 auto_eoi;
__u8 rotate_on_auto_eoi;
__u8 special_fully_nested_mode;
__u8 init4; /* true if 4 byte init */
__u8 elcr; /* PIIX edge/trigger selection */
__u8 elcr_mask;
};
#define KVM_IOAPIC_NUM_PINS 24
struct kvm_ioapic_state {
__u64 base_address;
__u32 ioregsel;
__u32 id;
__u32 irr;
__u32 pad;
union {
__u64 bits;
struct {
__u8 vector;
__u8 delivery_mode:3;
__u8 dest_mode:1;
__u8 delivery_status:1;
__u8 polarity:1;
__u8 remote_irr:1;
__u8 trig_mode:1;
__u8 mask:1;
__u8 reserve:7;
__u8 reserved[4];
__u8 dest_id;
} fields;
} redirtbl[KVM_IOAPIC_NUM_PINS];
};
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
#define KVM_NR_IRQCHIPS 3
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
__u64 rax, rbx, rcx, rdx;
__u64 rsi, rdi, rsp, rbp;
__u64 r8, r9, r10, r11;
__u64 r12, r13, r14, r15;
__u64 rip, rflags;
};
/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
#define KVM_APIC_REG_SIZE 0x400
struct kvm_lapic_state {
char regs[KVM_APIC_REG_SIZE];
};
struct kvm_segment {
__u64 base;
__u32 limit;
__u16 selector;
__u8 type;
__u8 present, dpl, db, s, l, g, avl;
__u8 unusable;
__u8 padding;
};
struct kvm_dtable {
__u64 base;
__u16 limit;
__u16 padding[3];
};
/* for KVM_GET_SREGS and KVM_SET_SREGS */
struct kvm_sregs {
/* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
struct kvm_segment cs, ds, es, fs, gs, ss;
struct kvm_segment tr, ldt;
struct kvm_dtable gdt, idt;
__u64 cr0, cr2, cr3, cr4, cr8;
__u64 efer;
__u64 apic_base;
__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};
/* for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
__u8 fpr[8][16];
__u16 fcw;
__u16 fsw;
__u8 ftwx; /* in fxsave format */
__u8 pad1;
__u16 last_opcode;
__u64 last_ip;
__u64 last_dp;
__u8 xmm[16][16];
__u32 mxcsr;
__u32 pad2;
};
struct kvm_msr_entry {
__u32 index;
__u32 reserved;
__u64 data;
};
/* for KVM_GET_MSRS and KVM_SET_MSRS */
struct kvm_msrs {
__u32 nmsrs; /* number of msrs in entries */
__u32 pad;
struct kvm_msr_entry entries[0];
};
/* for KVM_GET_MSR_INDEX_LIST */
struct kvm_msr_list {
__u32 nmsrs; /* number of msrs in entries */
__u32 indices[0];
};
struct kvm_cpuid_entry {
__u32 function;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding;
};
/* for KVM_SET_CPUID */
struct kvm_cpuid {
__u32 nent;
__u32 padding;
struct kvm_cpuid_entry entries[0];
};
struct kvm_cpuid_entry2 {
__u32 function;
__u32 index;
__u32 flags;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding[3];
};
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
#define KVM_CPUID_FLAG_STATEFUL_FUNC 2
#define KVM_CPUID_FLAG_STATE_READ_NEXT 4
/* for KVM_SET_CPUID2 */
struct kvm_cpuid2 {
__u32 nent;
__u32 padding;
struct kvm_cpuid_entry2 entries[0];
};
/* for KVM_GET_PIT and KVM_SET_PIT */
struct kvm_pit_channel_state {
__u32 count; /* can be 65536 */
__u16 latched_count;
__u8 count_latched;
__u8 status_latched;
__u8 status;
__u8 read_state;
__u8 write_state;
__u8 write_latch;
__u8 rw_mode;
__u8 mode;
__u8 bcd;
__u8 gate;
__s64 count_load_time;
};
struct kvm_debug_exit_arch {
__u32 exception;
__u32 pad;
__u64 pc;
__u64 dr6;
__u64 dr7;
};
#define KVM_GUESTDBG_USE_SW_BP 0x00010000
#define KVM_GUESTDBG_USE_HW_BP 0x00020000
#define KVM_GUESTDBG_INJECT_DB 0x00040000
#define KVM_GUESTDBG_INJECT_BP 0x00080000
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
__u64 debugreg[8];
};
struct kvm_pit_state {
struct kvm_pit_channel_state channels[3];
};
#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001
struct kvm_pit_state2 {
struct kvm_pit_channel_state channels[3];
__u32 flags;
__u32 reserved[9];
};
struct kvm_reinject_control {
__u8 pit_reinject;
__u8 reserved[31];
};
/* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
/* Interrupt shadow states */
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
#define KVM_X86_SHADOW_INT_STI 0x02
/* for KVM_GET/SET_VCPU_EVENTS */
struct kvm_vcpu_events {
struct {
__u8 injected;
__u8 nr;
__u8 has_error_code;
__u8 pad;
__u32 error_code;
} exception;
struct {
__u8 injected;
__u8 nr;
__u8 soft;
__u8 shadow;
} interrupt;
struct {
__u8 injected;
__u8 pending;
__u8 masked;
__u8 pad;
} nmi;
__u32 sipi_vector;
__u32 flags;
__u32 reserved[10];
};
/* for KVM_GET/SET_DEBUGREGS */
struct kvm_debugregs {
__u64 db[4];
__u64 dr6;
__u64 dr7;
__u64 flags;
__u64 reserved[9];
};
/* for KVM_CAP_XSAVE */
struct kvm_xsave {
__u32 region[1024];
};
#define KVM_MAX_XCRS 16
struct kvm_xcr {
__u32 xcr;
__u32 reserved;
__u64 value;
};
struct kvm_xcrs {
__u32 nr_xcrs;
__u32 flags;
struct kvm_xcr xcrs[KVM_MAX_XCRS];
__u64 padding[16];
};
#endif /* _ASM_X86_KVM_H */

View File

@@ -0,0 +1,149 @@
#ifndef _ASM_X86_KVM_PARA_H
#define _ASM_X86_KVM_PARA_H
#include <linux/types.h>
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
* should be used to determine that a VM is running under KVM.
*/
#define KVM_CPUID_SIGNATURE 0x40000000
/* This CPUID returns a feature bitmap in eax. Before enabling a particular
* paravirtualization, the appropriate feature bit should be checked.
*/
#define KVM_CPUID_FEATURES 0x40000001
#define KVM_FEATURE_CLOCKSOURCE 0
#define KVM_FEATURE_NOP_IO_DELAY 1
#define KVM_FEATURE_MMU_OP 2
#define MSR_KVM_WALL_CLOCK 0x11
#define MSR_KVM_SYSTEM_TIME 0x12
#define KVM_MAX_MMU_OP_BATCH 32
/* Operations for KVM_HC_MMU_OP */
#define KVM_MMU_OP_WRITE_PTE 1
#define KVM_MMU_OP_FLUSH_TLB 2
#define KVM_MMU_OP_RELEASE_PT 3
/* Payload for KVM_HC_MMU_OP */
struct kvm_mmu_op_header {
__u32 op;
__u32 pad;
};
struct kvm_mmu_op_write_pte {
struct kvm_mmu_op_header header;
__u64 pte_phys;
__u64 pte_val;
};
struct kvm_mmu_op_flush_tlb {
struct kvm_mmu_op_header header;
};
struct kvm_mmu_op_release_pt {
struct kvm_mmu_op_header header;
__u64 pt_phys;
};
#ifdef __KERNEL__
#include <asm/processor.h>
extern void kvmclock_init(void);
/* This instruction is vmcall. On non-VT architectures, it will generate a
* trap that we will then rewrite to the appropriate instruction.
*/
#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
* instruction. The hypervisor may replace it with something else but only the
* instructions are guaranteed to be supported.
*
* Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
* The hypercall number should be placed in rax and the return value will be
* placed in rax. No other registers will be clobbered unless explicited
* noted by the particular hypercall.
*/
static inline long kvm_hypercall0(unsigned int nr)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr)
: "memory");
return ret;
}
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1)
: "memory");
return ret;
}
static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
unsigned long p2)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2)
: "memory");
return ret;
}
static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3)
: "memory");
return ret;
}
static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3,
unsigned long p4)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
: "memory");
return ret;
}
static inline int kvm_para_available(void)
{
unsigned int eax, ebx, ecx, edx;
char signature[13];
cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
memcpy(signature + 0, &ebx, 4);
memcpy(signature + 4, &ecx, 4);
memcpy(signature + 8, &edx, 4);
signature[12] = 0;
if (strcmp(signature, "KVMKVMKVM") == 0)
return 1;
return 0;
}
static inline unsigned int kvm_arch_para_features(void)
{
return cpuid_eax(KVM_CPUID_FEATURES);
}
#endif
#endif /* _ASM_X86_KVM_PARA_H */

139
kvm/kvm.spec Normal file
View File

@@ -0,0 +1,139 @@
Name: kvm
Version: 0.0
Release: 0
Summary: Kernel Virtual Machine virtualization environment
Group: System Environment/Kernel
License: GPL
URL: http://www.qumranet.com
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
ExclusiveArch: i386 x86_64 ia64
Requires: kvm-kmod bridge-utils
%define Distribution %(rpm -q -qf /etc/redhat-release --qf '%%{name}' | cut -d"-" -f 1)
%define os_version %(rpm -q --qf '%%{version}' %{Distribution}-release)
%define os_release %(rpm -q --qf '%%{release}' %{Distribution}-release | cut -d"." -f 1)
%if %([ x"%{Distribution}" = x"fedora" -a x"%{os_version}" = x"5" ] && echo 1 || echo 0)
%define require_gccver 32
%endif
%if %([ x"%{Distribution}" = x"fedora" -a 0"%{os_version}" -ge "8" ] && echo 1 || echo 0)
%define qemuldflags --qemu-ldflags=-Wl,--build-id
%else
%define qemuldflags ""
%endif
%if %([ x"%{Distribution}" = x"centos" -a x"%{os_version}" = x"4" ] && echo 1 || echo 0)
%define require_gccver 32
%endif
%if %([ x"%{Distribution}" = x"redhat" -a x"%{os_release}" = x"5" ] && echo 1 || echo 0)
%define require_gccver 34
%endif
%if %( [ x"%{require_gccver}" = x"32" ] && echo 1 || echo 0)
BuildRequires: compat-gcc-32
%else
BuildRequires: compat-gcc-34
%endif
BuildRequires: SDL-devel zlib-devel alsa-lib-devel
%define _prebuilt %{?prebuilt:1}%{!?prebuilt:0}
%if !%{_prebuilt}
Source0: kvm.tar.gz
Source1: user.tar.gz
Source2: kernel.tar.gz
Source3: scripts.tar.gz
Source4: Makefile
Source5: configure
Source6: kvm_stat
Source7: libkvm.tar.gz
Source8: extboot.tar.gz
%endif
%description
The Kernel Virtual Machine provides a virtualization enviroment for processors
with hardware support for virtualization: Intel's VT-x&VT-i and AMD's AMD-V.
%prep
%if !%{_prebuilt}
%setup -T -b 0 -n qemu
%setup -T -b 1 -n user -D
%setup -T -b 2 -n kernel -D
%setup -T -b 7 -n libkvm -D
%setup -T -b 3 -n scripts -D
%setup -T -b 8 -n extboot -D
cd ..
cp %{_sourcedir}/Makefile %{_sourcedir}/configure %{_sourcedir}/kvm_stat .
%endif
%build
rm -rf %{buildroot}
%if !%{_prebuilt}
cd ..
./configure --prefix=/usr/kvm %{qemuldflags}
make -C libkvm
make -C user
%ifarch i386 x86_64
make extboot
%endif
#(cd qemu;
# ./co
# kpath="$(readlink -f ../kernel/include)"
# upath="$(readlink -f ../user)"
# ./configure --target-list=$(uname -i)-softmmu \
# --extra-cflags="-I$kpath -I$upath" \
# --extra-ldflags="-L$upath" \
# --disable-kqemu --enable-kvm --prefix=/usr/kvm
#)
make -C qemu
%endif
%install
%if !%{_prebuilt}
cd ..
%else
cd %{objdir}
%endif
make DESTDIR=%{buildroot} install-rpm
%define bindir /usr/bin
%define bin %{bindir}/kvm
%define initdir /etc/init.d
%define confdir /etc/kvm
%define utilsdir /etc/kvm/utils
%post
/sbin/chkconfig --add kvm
/sbin/chkconfig --level 2345 kvm on
/sbin/chkconfig --level 16 kvm off
/usr/sbin/groupadd -fg 444 kvm
%preun
if [ "$1" != 0 ]; then
/sbin/service kvm stop
/sbin/chkconfig --level 2345 kvm off
/sbin/chkconfig --del kvm
fi
%clean
%{__rm} -rf %{buildroot}
%files
/usr/bin/kvm
/usr/bin/kvm_stat
%{confdir}/qemu-ifup
%{initdir}/kvm
/etc/udev/rules.d/*kvm*.rules
/usr/kvm
%changelog

469
kvm/kvm_stat Executable file
View File

@@ -0,0 +1,469 @@
#!/usr/bin/python
import curses
import sys, os, time, optparse
class DebugfsProvider(object):
def __init__(self):
self.base = '/sys/kernel/debug/kvm'
self._fields = os.listdir(self.base)
def fields(self):
return self._fields
def select(self, fields):
self._fields = fields
def read(self):
def val(key):
return int(file(self.base + '/' + key).read())
return dict([(key, val(key)) for key in self._fields])
vmx_exit_reasons = {
0: 'EXCEPTION_NMI',
1: 'EXTERNAL_INTERRUPT',
2: 'TRIPLE_FAULT',
7: 'PENDING_INTERRUPT',
8: 'NMI_WINDOW',
9: 'TASK_SWITCH',
10: 'CPUID',
12: 'HLT',
14: 'INVLPG',
15: 'RDPMC',
16: 'RDTSC',
18: 'VMCALL',
19: 'VMCLEAR',
20: 'VMLAUNCH',
21: 'VMPTRLD',
22: 'VMPTRST',
23: 'VMREAD',
24: 'VMRESUME',
25: 'VMWRITE',
26: 'VMOFF',
27: 'VMON',
28: 'CR_ACCESS',
29: 'DR_ACCESS',
30: 'IO_INSTRUCTION',
31: 'MSR_READ',
32: 'MSR_WRITE',
33: 'INVALID_STATE',
36: 'MWAIT_INSTRUCTION',
39: 'MONITOR_INSTRUCTION',
40: 'PAUSE_INSTRUCTION',
41: 'MCE_DURING_VMENTRY',
43: 'TPR_BELOW_THRESHOLD',
44: 'APIC_ACCESS',
48: 'EPT_VIOLATION',
49: 'EPT_MISCONFIG',
54: 'WBINVD',
55: 'XSETBV',
}
svm_exit_reasons = {
0x000: 'READ_CR0',
0x003: 'READ_CR3',
0x004: 'READ_CR4',
0x008: 'READ_CR8',
0x010: 'WRITE_CR0',
0x013: 'WRITE_CR3',
0x014: 'WRITE_CR4',
0x018: 'WRITE_CR8',
0x020: 'READ_DR0',
0x021: 'READ_DR1',
0x022: 'READ_DR2',
0x023: 'READ_DR3',
0x024: 'READ_DR4',
0x025: 'READ_DR5',
0x026: 'READ_DR6',
0x027: 'READ_DR7',
0x030: 'WRITE_DR0',
0x031: 'WRITE_DR1',
0x032: 'WRITE_DR2',
0x033: 'WRITE_DR3',
0x034: 'WRITE_DR4',
0x035: 'WRITE_DR5',
0x036: 'WRITE_DR6',
0x037: 'WRITE_DR7',
0x040: 'EXCP_BASE',
0x060: 'INTR',
0x061: 'NMI',
0x062: 'SMI',
0x063: 'INIT',
0x064: 'VINTR',
0x065: 'CR0_SEL_WRITE',
0x066: 'IDTR_READ',
0x067: 'GDTR_READ',
0x068: 'LDTR_READ',
0x069: 'TR_READ',
0x06a: 'IDTR_WRITE',
0x06b: 'GDTR_WRITE',
0x06c: 'LDTR_WRITE',
0x06d: 'TR_WRITE',
0x06e: 'RDTSC',
0x06f: 'RDPMC',
0x070: 'PUSHF',
0x071: 'POPF',
0x072: 'CPUID',
0x073: 'RSM',
0x074: 'IRET',
0x075: 'SWINT',
0x076: 'INVD',
0x077: 'PAUSE',
0x078: 'HLT',
0x079: 'INVLPG',
0x07a: 'INVLPGA',
0x07b: 'IOIO',
0x07c: 'MSR',
0x07d: 'TASK_SWITCH',
0x07e: 'FERR_FREEZE',
0x07f: 'SHUTDOWN',
0x080: 'VMRUN',
0x081: 'VMMCALL',
0x082: 'VMLOAD',
0x083: 'VMSAVE',
0x084: 'STGI',
0x085: 'CLGI',
0x086: 'SKINIT',
0x087: 'RDTSCP',
0x088: 'ICEBP',
0x089: 'WBINVD',
0x08a: 'MONITOR',
0x08b: 'MWAIT',
0x08c: 'MWAIT_COND',
0x400: 'NPF',
}
vendor_exit_reasons = {
'vmx': vmx_exit_reasons,
'svm': svm_exit_reasons,
}
exit_reasons = None
for line in file('/proc/cpuinfo').readlines():
if line.startswith('flags'):
for flag in line.split():
if flag in vendor_exit_reasons:
exit_reasons = vendor_exit_reasons[flag]
filters = {
'kvm_exit': ('exit_reason', exit_reasons)
}
def invert(d):
return dict((x[1], x[0]) for x in d.iteritems())
for f in filters:
filters[f] = (filters[f][0], invert(filters[f][1]))
import ctypes, struct, array
libc = ctypes.CDLL('libc.so.6')
syscall = libc.syscall
class perf_event_attr(ctypes.Structure):
_fields_ = [('type', ctypes.c_uint32),
('size', ctypes.c_uint32),
('config', ctypes.c_uint64),
('sample_freq', ctypes.c_uint64),
('sample_type', ctypes.c_uint64),
('read_format', ctypes.c_uint64),
('flags', ctypes.c_uint64),
('wakeup_events', ctypes.c_uint32),
('bp_type', ctypes.c_uint32),
('bp_addr', ctypes.c_uint64),
('bp_len', ctypes.c_uint64),
]
def _perf_event_open(attr, pid, cpu, group_fd, flags):
return syscall(298, ctypes.pointer(attr), ctypes.c_int(pid),
ctypes.c_int(cpu), ctypes.c_int(group_fd),
ctypes.c_long(flags))
PERF_TYPE_HARDWARE = 0
PERF_TYPE_SOFTWARE = 1
PERF_TYPE_TRACEPOINT = 2
PERF_TYPE_HW_CACHE = 3
PERF_TYPE_RAW = 4
PERF_TYPE_BREAKPOINT = 5
PERF_SAMPLE_IP = 1 << 0
PERF_SAMPLE_TID = 1 << 1
PERF_SAMPLE_TIME = 1 << 2
PERF_SAMPLE_ADDR = 1 << 3
PERF_SAMPLE_READ = 1 << 4
PERF_SAMPLE_CALLCHAIN = 1 << 5
PERF_SAMPLE_ID = 1 << 6
PERF_SAMPLE_CPU = 1 << 7
PERF_SAMPLE_PERIOD = 1 << 8
PERF_SAMPLE_STREAM_ID = 1 << 9
PERF_SAMPLE_RAW = 1 << 10
PERF_FORMAT_TOTAL_TIME_ENABLED = 1 << 0
PERF_FORMAT_TOTAL_TIME_RUNNING = 1 << 1
PERF_FORMAT_ID = 1 << 2
PERF_FORMAT_GROUP = 1 << 3
import re
sys_tracing = '/sys/kernel/debug/tracing'
class Group(object):
def __init__(self, cpu):
self.events = []
self.group_leader = None
self.cpu = cpu
def add_event(self, name, event_set, tracepoint, filter = None):
self.events.append(Event(group = self,
name = name, event_set = event_set,
tracepoint = tracepoint, filter = filter))
if len(self.events) == 1:
self.file = os.fdopen(self.events[0].fd)
def read(self):
bytes = 8 * (1 + len(self.events))
fmt = 'xxxxxxxx' + 'q' * len(self.events)
return dict(zip([event.name for event in self.events],
struct.unpack(fmt, self.file.read(bytes))))
class Event(object):
def __init__(self, group, name, event_set, tracepoint, filter = None):
self.name = name
attr = perf_event_attr()
attr.type = PERF_TYPE_TRACEPOINT
attr.size = ctypes.sizeof(attr)
id_path = os.path.join(sys_tracing, 'events', event_set,
tracepoint, 'id')
id = int(file(id_path).read())
attr.config = id
attr.sample_type = (PERF_SAMPLE_RAW
| PERF_SAMPLE_TIME
| PERF_SAMPLE_CPU)
attr.sample_period = 1
attr.read_format = PERF_FORMAT_GROUP
group_leader = -1
if group.events:
group_leader = group.events[0].fd
fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
if fd == -1:
raise Exception('perf_event_open failed')
if filter:
import fcntl
fcntl.ioctl(fd, 0x40082406, filter)
self.fd = fd
def enable(self):
import fcntl
fcntl.ioctl(self.fd, 0x00002400, 0)
def disable(self):
import fcntl
fcntl.ioctl(self.fd, 0x00002401, 0)
class TracepointProvider(object):
def __init__(self):
path = os.path.join(sys_tracing, 'events', 'kvm')
fields = [f
for f in os.listdir(path)
if os.path.isdir(os.path.join(path, f))]
extra = []
for f in fields:
if f in filters:
subfield, values = filters[f]
for name, number in values.iteritems():
extra.append(f + '(' + name + ')')
fields += extra
self._setup(fields)
self.select(fields)
def fields(self):
return self._fields
def _setup(self, _fields):
self._fields = _fields
cpure = r'cpu([0-9]+)'
self.cpus = [int(re.match(cpure, x).group(1))
for x in os.listdir('/sys/devices/system/cpu')
if re.match(cpure, x)]
import resource
nfiles = len(self.cpus) * 1000
resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
events = []
self.group_leaders = []
for cpu in self.cpus:
group = Group(cpu)
for name in _fields:
tracepoint = name
filter = None
m = re.match(r'(.*)\((.*)\)', name)
if m:
tracepoint, sub = m.groups()
filter = '%s==%d\0' % (filters[tracepoint][0],
filters[tracepoint][1][sub])
event = group.add_event(name, event_set = 'kvm',
tracepoint = tracepoint,
filter = filter)
self.group_leaders.append(group)
def select(self, fields):
for group in self.group_leaders:
for event in group.events:
if event.name in fields:
event.enable()
else:
event.disable()
def read(self):
from collections import defaultdict
ret = defaultdict(int)
for group in self.group_leaders:
for name, val in group.read().iteritems():
ret[name] += val
return ret
class Stats:
def __init__(self, provider, fields = None):
self.provider = provider
self.fields_filter = fields
self._update()
def _update(self):
def wanted(key):
import re
if not self.fields_filter:
return True
return re.match(self.fields_filter, key) is not None
self.values = dict([(key, None)
for key in provider.fields()
if wanted(key)])
self.provider.select(self.values.keys())
def set_fields_filter(self, fields_filter):
self.fields_filter = fields_filter
self._update()
def get(self):
new = self.provider.read()
for key in self.provider.fields():
oldval = self.values.get(key, (0, 0))
newval = new[key]
newdelta = None
if oldval is not None:
newdelta = newval - oldval[0]
self.values[key] = (newval, newdelta)
return self.values
if not os.access('/sys/kernel/debug', os.F_OK):
print 'Please enable CONFIG_DEBUG_FS in your kernel'
sys.exit(1)
if not os.access('/sys/kernel/debug/kvm', os.F_OK):
print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
print "and ensure the kvm modules are loaded"
sys.exit(1)
label_width = 40
number_width = 10
def tui(screen, stats):
curses.use_default_colors()
curses.noecho()
drilldown = False
fields_filter = stats.fields_filter
def update_drilldown():
if not fields_filter:
if drilldown:
stats.set_fields_filter(None)
else:
stats.set_fields_filter(r'^[^\(]*$')
update_drilldown()
def refresh(sleeptime):
screen.erase()
screen.addstr(0, 0, 'kvm statistics')
row = 2
s = stats.get()
def sortkey(x):
if s[x][1]:
return (-s[x][1], -s[x][0])
else:
return (0, -s[x][0])
for key in sorted(s.keys(), key = sortkey):
if row >= screen.getmaxyx()[0]:
break
values = s[key]
if not values[0] and not values[1]:
break
col = 1
screen.addstr(row, col, key)
col += label_width
screen.addstr(row, col, '%10d' % (values[0],))
col += number_width
if values[1] is not None:
screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
row += 1
screen.refresh()
sleeptime = 0.25
while True:
refresh(sleeptime)
curses.halfdelay(int(sleeptime * 10))
sleeptime = 3
try:
c = screen.getkey()
if c == 'x':
drilldown = not drilldown
update_drilldown()
if c == 'q':
break
except KeyboardInterrupt:
break
except curses.error:
continue
def batch(stats):
s = stats.get()
time.sleep(1)
s = stats.get()
for key in sorted(s.keys()):
values = s[key]
print '%-22s%10d%10d' % (key, values[0], values[1])
def log(stats):
keys = sorted(stats.get().iterkeys())
def banner():
for k in keys:
print '%10s' % k[0:9],
print
def statline():
s = stats.get()
for k in keys:
print ' %9d' % s[k][1],
print
line = 0
banner_repeat = 20
while True:
time.sleep(1)
if line % banner_repeat == 0:
banner()
statline()
line += 1
options = optparse.OptionParser()
options.add_option('-1', '--once', '--batch',
action = 'store_true',
default = False,
dest = 'once',
help = 'run in batch mode for one second',
)
options.add_option('-l', '--log',
action = 'store_true',
default = False,
dest = 'log',
help = 'run in logging mode (like vmstat)',
)
options.add_option('-f', '--fields',
action = 'store',
default = None,
dest = 'fields',
help = 'fields to display (regex)',
)
(options, args) = options.parse_args(sys.argv)
try:
provider = TracepointProvider()
except:
provider = DebugfsProvider()
stats = Stats(provider, fields = options.fields)
if options.log:
log(stats)
elif not options.once:
import curses.wrapper
curses.wrapper(tui, stats)
else:
batch(stats)

19
kvm/libfdt/Makefile Normal file
View File

@@ -0,0 +1,19 @@
include ../config.mak
include ../user/config.mak
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
LIBFDT_INCLUDES = fdt.h libfdt.h
LIBFDT_EXTRA = libfdt_internal.h
LIBFDT_LIB = libfdt.a
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
CFLAGS += -I .
$(LIBFDT_LIB): $(LIBFDT_OBJS)
$(AR) rcs $@ $^
all: $(LIBFDT_LIB)
clean:
rm -rf *.o *.a

3
kvm/libfdt/README Normal file
View File

@@ -0,0 +1,3 @@
libfdt was grabbed from dtc source. This is the upstream source for libfdt.
It can be found here:
http://www.jdl.com/software/

194
kvm/libfdt/fdt.c Normal file
View File

@@ -0,0 +1,194 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_check_header(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
} else if (fdt_magic(fdt) == SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, int len)
{
const void *p;
if (fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
p = _fdt_offset_ptr(fdt, offset);
if (p + len < p)
return NULL;
return p;
}
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
const char *p;
if (offset % FDT_TAGSIZE)
return -1;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp)
return FDT_END;
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
break;
}
if (nextoffset)
*nextoffset = ALIGN(offset, FDT_TAGSIZE);
return tag;
}
int fdt_next_node(const void *fdt, int offset, int *depth)
{
int nextoffset = 0;
uint32_t tag;
if (offset >= 0) {
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
}
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_PROP:
case FDT_NOP:
break;
case FDT_BEGIN_NODE:
if (depth)
(*depth)++;
break;
case FDT_END_NODE:
if (depth)
(*depth)--;
break;
case FDT_END:
return -FDT_ERR_NOTFOUND;
default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (tag != FDT_BEGIN_NODE);
return offset;
}
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
const char *p;
for (p = strtab; p <= last; p++)
if (memeq(p, s, len))
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
CHECK_HEADER(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
return 0;
}

60
kvm/libfdt/fdt.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef _FDT_H
#define _FDT_H
#ifndef __ASSEMBLY__
struct fdt_header {
uint32_t magic; /* magic word FDT_MAGIC */
uint32_t totalsize; /* total size of DT block */
uint32_t off_dt_struct; /* offset to structure */
uint32_t off_dt_strings; /* offset to strings */
uint32_t off_mem_rsvmap; /* offset to memory reserve map */
uint32_t version; /* format version */
uint32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
uint32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
uint32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */
uint32_t size_dt_struct; /* size of the structure block */
};
struct fdt_reserve_entry {
uint64_t address;
uint64_t size;
};
struct fdt_node_header {
uint32_t tag;
char name[0];
};
struct fdt_property {
uint32_t tag;
uint32_t len;
uint32_t nameoff;
char data[0];
};
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(uint32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(uint32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
#endif /* _FDT_H */

476
kvm/libfdt/fdt_ro.c Normal file
View File

@@ -0,0 +1,476 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int nodename_eq(const void *fdt, int offset,
const char *s, int len)
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
/* short match */
return 0;
if (memcmp(p, s, len) != 0)
return 0;
if (p[len] == '\0')
return 1;
else if (!memchr(s, '@', len) && (p[len] == '@'))
return 1;
else
return 0;
}
const char *fdt_string(const void *fdt, int stroffset)
{
return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
CHECK_HEADER(fdt);
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
int i = 0;
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
i++;
return i;
}
int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen)
{
int depth;
CHECK_HEADER(fdt);
for (depth = 0;
offset >= 0;
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth < 0)
return -FDT_ERR_NOTFOUND;
else if ((depth == 1)
&& nodename_eq(fdt, offset, name, namelen))
return offset;
}
return offset; /* error */
}
int fdt_subnode_offset(const void *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_path_offset(const void *fdt, const char *path)
{
const char *end = path + strlen(path);
const char *p = path;
int offset = 0;
CHECK_HEADER(fdt);
if (*path != '/')
return -FDT_ERR_BADPATH;
while (*p) {
const char *q;
while (*p == '/')
p++;
if (! *p)
return offset;
q = strchr(p, '/');
if (! q)
q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
if (offset < 0)
return offset;
p = q;
}
return offset;
}
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh;
int err;
if ((err = fdt_check_header(fdt)) != 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
goto fail;
if (len)
*len = strlen(nh->name);
return nh->name;
fail:
if (len)
*len = err;
return NULL;
}
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
{
uint32_t tag;
const struct fdt_property *prop;
int namestroff;
int offset, nextoffset;
int err;
if ((err = fdt_check_header(fdt)) != 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
if (nodeoffset % FDT_TAGSIZE)
goto fail;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
goto fail;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
err = -FDT_ERR_TRUNCATED;
goto fail;
case FDT_BEGIN_NODE:
case FDT_END_NODE:
case FDT_NOP:
break;
case FDT_PROP:
err = -FDT_ERR_BADSTRUCTURE;
prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
if (! prop)
goto fail;
namestroff = fdt32_to_cpu(prop->nameoff);
if (streq(fdt_string(fdt, namestroff), name)) {
/* Found it! */
int len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, offset,
sizeof(*prop)+len);
if (! prop)
goto fail;
if (lenp)
*lenp = len;
return prop;
}
break;
default:
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
err = -FDT_ERR_NOTFOUND;
fail:
if (lenp)
*lenp = err;
return NULL;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property(fdt, nodeoffset, name, lenp);
if (! prop)
return NULL;
return prop->data;
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const uint32_t *php;
int len;
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
return fdt32_to_cpu(*php);
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
int offset, depth, namelen;
const char *name;
CHECK_HEADER(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (pdepth < depth)
continue; /* overflowed buffer */
while (pdepth > depth) {
do {
p--;
} while (buf[p-1] != '/');
pdepth--;
}
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
}
if (offset == nodeoffset) {
if (pdepth < (depth + 1))
return -FDT_ERR_NOSPACE;
if (p > 1) /* special case so that root path is "/", not "" */
p--;
buf[p] = '\0';
return p;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int supernodedepth, int *nodedepth)
{
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
CHECK_HEADER(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth == supernodedepth)
supernodeoffset = offset;
if (offset == nodeoffset) {
if (nodedepth)
*nodedepth = depth;
if (supernodedepth > depth)
return -FDT_ERR_NOTFOUND;
else
return supernodeoffset;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_node_depth(const void *fdt, int nodeoffset)
{
int nodedepth;
int err;
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth;
}
int fdt_parent_offset(const void *fdt, int nodeoffset)
{
int nodedepth = fdt_node_depth(fdt, nodeoffset);
if (nodedepth < 0)
return nodedepth;
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
nodedepth - 1, NULL);
}
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen)
{
int offset;
const void *val;
int len;
CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
val = fdt_getprop(fdt, offset, propname, &len);
if (val && (len == proplen)
&& (memcmp(val, propval, len) == 0))
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
phandle = cpu_to_fdt32(phandle);
return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
&phandle, sizeof(phandle));
}
int _stringlist_contains(const void *strlist, int listlen, const char *str)
{
int len = strlen(str);
const void *p;
while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
return 1;
p = memchr(strlist, '\0', listlen);
if (!p)
return 0; /* malformed strlist.. */
listlen -= (p-strlist) + 1;
strlist = p + 1;
}
return 0;
}
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
const void *prop;
int len;
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
if (_stringlist_contains(prop, len, compatible))
return 0;
else
return 1;
}
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
int offset, err;
CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
err = fdt_node_check_compatible(fdt, offset, compatible);
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
return err;
else if (err == 0)
return offset;
}
return offset; /* error from fdt_next_node() */
}

467
kvm/libfdt/fdt_rw.c Normal file
View File

@@ -0,0 +1,467 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int _blocks_misordered(const void *fdt,
int mem_rsv_size, int struct_size)
{
return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|| (fdt_off_dt_strings(fdt) <
(fdt_off_dt_struct(fdt) + struct_size))
|| (fdt_totalsize(fdt) <
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int rw_check_header(void *fdt)
{
CHECK_HEADER(fdt);
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
}
#define RW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = rw_check_header(fdt)) != 0) \
return err; \
}
static inline int _blob_data_size(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
{
void *end = fdt + _blob_data_size(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}
static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _blob_splice_struct(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
if ((err = _blob_splice(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _blob_splice_string(void *fdt, int newlen)
{
void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
if ((err = _blob_splice(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
static int _find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
char *new;
int len = strlen(s) + 1;
int err;
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
err = _blob_splice_string(fdt, len);
if (err)
return err;
memcpy(new, s, len);
return (new - strtab);
}
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry *re;
int err;
if ((err = rw_check_header(fdt)))
return err;
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
err = _blob_splice_mem_rsv(fdt, re, 0, 1);
if (err)
return err;
re->address = cpu_to_fdt64(address);
re->size = cpu_to_fdt64(size);
return 0;
}
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
int err;
if ((err = rw_check_header(fdt)))
return err;
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
err = _blob_splice_mem_rsv(fdt, re, 1, 0);
if (err)
return err;
return 0;
}
static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
struct fdt_property **prop)
{
int oldlen;
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop))
return oldlen;
if ((err = _blob_splice_struct(fdt, (*prop)->data,
ALIGN(oldlen, FDT_TAGSIZE),
ALIGN(len, FDT_TAGSIZE))))
return err;
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
struct fdt_property **prop)
{
uint32_t tag;
int proplen;
int nextoffset;
int namestroff;
int err;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
namestroff = _find_add_string(fdt, name);
if (namestroff < 0)
return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
err = _blob_splice_struct(fdt, *prop, 0, proplen);
if (err)
return err;
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
{
char *namep;
int oldlen, newlen;
int err;
if ((err = rw_check_header(fdt)))
return err;
namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
return oldlen;
newlen = strlen(name);
err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
ALIGN(newlen+1, FDT_TAGSIZE));
if (err)
return err;
memcpy(namep, name, newlen+1);
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err;
if ((err = rw_check_header(fdt)))
return err;
err = _resize_property(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = _add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len, proplen;
RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
return _blob_splice_struct(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen)
{
struct fdt_node_header *nh;
int offset, nextoffset;
int nodelen;
int err;
uint32_t tag;
uint32_t *endtag;
RW_CHECK_HEADER(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
return -FDT_ERR_EXISTS;
else if (offset != -FDT_ERR_NOTFOUND)
return offset;
/* Try to place the new node after the parent's properties */
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset);
nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
err = _blob_splice_struct(fdt, nh, 0, nodelen);
if (err)
return err;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
memcpy(nh->name, name, namelen);
endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
*endtag = cpu_to_fdt32(FDT_END_NODE);
return offset;
}
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
{
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
RW_CHECK_HEADER(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
static void _packblocks(const void *fdt, void *buf,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
strings_off = struct_off + struct_size;
memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
fdt_set_off_dt_struct(buf, struct_off);
fdt_set_size_dt_struct(buf, struct_size);
memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(buf, strings_off);
fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
}
int fdt_open_into(const void *fdt, void *buf, int bufsize)
{
int err;
int mem_rsv_size, struct_size;
int newsize;
void *tmp;
CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
}
if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
return err;
fdt_set_version(buf, 17);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
}
/* Need to reorder */
newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ struct_size + fdt_size_dt_strings(fdt);
if (bufsize < newsize)
return -FDT_ERR_NOSPACE;
if (((buf + newsize) <= fdt)
|| (buf >= (fdt + fdt_totalsize(fdt)))) {
tmp = buf;
} else {
tmp = (void *)fdt + fdt_totalsize(fdt);
if ((tmp + newsize) > (buf + bufsize))
return -FDT_ERR_NOSPACE;
}
_packblocks(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
fdt_set_totalsize(buf, bufsize);
fdt_set_version(buf, 17);
fdt_set_last_comp_version(buf, 16);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
}
int fdt_pack(void *fdt)
{
int mem_rsv_size;
int err;
err = rw_check_header(fdt);
if (err)
return err;
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _blob_data_size(fdt));
return 0;
}

96
kvm/libfdt/fdt_strerror.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
struct errtabent {
const char *str;
};
#define ERRTABENT(val) \
[(val)] = { .str = #val, }
static struct errtabent errtable[] = {
ERRTABENT(FDT_ERR_NOTFOUND),
ERRTABENT(FDT_ERR_EXISTS),
ERRTABENT(FDT_ERR_NOSPACE),
ERRTABENT(FDT_ERR_BADOFFSET),
ERRTABENT(FDT_ERR_BADPATH),
ERRTABENT(FDT_ERR_BADSTATE),
ERRTABENT(FDT_ERR_TRUNCATED),
ERRTABENT(FDT_ERR_BADMAGIC),
ERRTABENT(FDT_ERR_BADVERSION),
ERRTABENT(FDT_ERR_BADSTRUCTURE),
ERRTABENT(FDT_ERR_BADLAYOUT),
};
#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0]))
const char *fdt_strerror(int errval)
{
if (errval > 0)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
else if (errval > -ERRTABSIZE) {
const char *s = errtable[-errval].str;
if (s)
return s;
}
return "<unknown error>";
}

258
kvm/libfdt/fdt_sw.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int check_header_sw(void *fdt)
{
if (fdt_magic(fdt) != SW_MAGIC)
return -FDT_ERR_BADMAGIC;
return 0;
}
static void *grab_space(void *fdt, int len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
if ((offset + len < offset) || (offset + len > spaceleft))
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w(fdt, offset, len);
}
int fdt_create(void *buf, int bufsize)
{
void *fdt = buf;
if (bufsize < sizeof(struct fdt_header))
return -FDT_ERR_NOSPACE;
memset(buf, 0, bufsize);
fdt_set_magic(fdt, SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize);
return 0;
}
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
int err = check_header_sw(fdt);
int offset;
if (err)
return err;
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
re = (struct fdt_reserve_entry *)(fdt + offset);
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
return 0;
}
int fdt_finish_reservemap(void *fdt)
{
return fdt_add_reservemap_entry(fdt, 0, 0);
}
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
int err = check_header_sw(fdt);
int namelen = strlen(name) + 1;
if (err)
return err;
nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
if (! nh)
return -FDT_ERR_NOSPACE;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memcpy(nh->name, name, namelen);
return 0;
}
int fdt_end_node(void *fdt)
{
uint32_t *en;
int err = check_header_sw(fdt);
if (err)
return err;
en = grab_space(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
*en = cpu_to_fdt32(FDT_END_NODE);
return 0;
}
static int find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
return 0; /* no more room :( */
memcpy(strtab + offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
return offset;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
struct fdt_property *prop;
int err = check_header_sw(fdt);
int nameoff;
if (err)
return err;
nameoff = find_add_string(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
if (! prop)
return -FDT_ERR_NOSPACE;
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
memcpy(prop->data, val, len);
return 0;
}
int fdt_finish(void *fdt)
{
int err = check_header_sw(fdt);
char *p = (char *)fdt;
uint32_t *end;
int oldstroffset, newstroffset;
uint32_t tag;
int offset, nextoffset;
if (err)
return err;
/* Add terminator */
end = grab_space(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
/* Relocate the string table */
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(fdt, newstroffset);
/* Walk the structure, correcting string offsets */
offset = 0;
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
int nameoff;
if (! prop)
return -FDT_ERR_BADSTRUCTURE;
nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff);
}
offset = nextoffset;
}
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}

144
kvm/libfdt/fdt_wip.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *propval;
int proplen;
propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
if (! propval)
return proplen;
if (proplen != len)
return -FDT_ERR_NOSPACE;
memcpy(propval, val, len);
return 0;
}
static void nop_region(void *start, int len)
{
uint32_t *p;
for (p = start; (void *)p < (start + len); p++)
*p = cpu_to_fdt32(FDT_NOP);
}
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
nop_region(prop, len + sizeof(*prop));
return 0;
}
int _fdt_node_end_offset(void *fdt, int nodeoffset)
{
int level = 0;
uint32_t tag;
int offset, nextoffset;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
return offset;
case FDT_BEGIN_NODE:
level++;
break;
case FDT_END_NODE:
level--;
break;
case FDT_PROP:
case FDT_NOP:
break;
default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (level >= 0);
return nextoffset;
}
int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
return 0;
}

1076
kvm/libfdt/libfdt.h Normal file

File diff suppressed because it is too large Load Diff

22
kvm/libfdt/libfdt_env.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#define fdt32_to_cpu(x) (x)
#define cpu_to_fdt32(x) (x)
#define fdt64_to_cpu(x) (x)
#define cpu_to_fdt64(x) (x)
#else
#define fdt32_to_cpu(x) (bswap_32((x)))
#define cpu_to_fdt32(x) (bswap_32((x)))
#define fdt64_to_cpu(x) (bswap_64((x)))
#define cpu_to_fdt64(x) (bswap_64((x)))
#endif
#endif /* _LIBFDT_ENV_H */

View File

@@ -0,0 +1,96 @@
#ifndef _LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fdt.h>
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
#define streq(p, q) (strcmp((p), (q)) == 0)
#define CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = fdt_check_header(fdt)) != 0) \
return err; \
}
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
{
return fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
{
return (void *)_fdt_offset_ptr(fdt, offset);
}
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
fdt + fdt_off_mem_rsvmap(fdt);
return rsv_table + n;
}
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
{
return (void *)_fdt_mem_rsv(fdt, n);
}
#define SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */

54
kvm/libkvm/Makefile Normal file
View File

@@ -0,0 +1,54 @@
all: libkvm.a
include ../../config-host.mak
ifneq ($(VPATH),)
srcdir=$(VPATH)/kvm/libkvm
else
srcdir=.
endif
include $(srcdir)/config-$(ARCH).mak
# libkvm is not -Wredundant-decls friendly yet
CFLAGS += -Wno-redundant-decls
# cc-option
# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
CFLAGS += $(call cc-option, -fno-stack-protector, "")
CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
CFLAGS += $(KVM_CFLAGS)
LDFLAGS += $(CFLAGS)
CXXFLAGS = $(autodepend-flags)
VPATH:=$(VPATH)/kvm/libkvm
autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
libkvm.a: libkvm.o $(libkvm-$(ARCH)-objs)
$(AR) rcs $@ $^
install:
@echo skipping libkvm install
install-libkvm:
install -D libkvm.h $(DESTDIR)/$(PREFIX)/include/libkvm.h
install -D libkvm.a $(DESTDIR)/$(PREFIX)/$(LIBDIR)/libkvm.a
install-kernel-headers:
install -D $(LIBKVM_KERNELDIR)/include/linux/kvm.h \
$(DESTDIR)/$(PREFIX)/include/linux/kvm.h
install -D $(LIBKVM_KERNELDIR)/include/linux/kvm_para.h \
$(DESTDIR)/$(PREFIX)/include/linux/kvm_para.h
-include .*.d
clean:
$(RM) *.o *.a .*.d

View File

@@ -0,0 +1,6 @@
LIBDIR := /lib
CFLAGS += -m32
CFLAGS += -D__i386__
libkvm-$(ARCH)-objs := libkvm-x86.o

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