aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2006-11-29 14:16:36 -0600
committerHollis Blanchard <hollisb@us.ibm.com>2006-11-29 14:16:36 -0600
commitab26a6a563a0acb589af87a8e063c0e171d75665 (patch)
tree71a432bde5d016e928ab3ad7860fca01312ec787
parentd3be8a6ca1aa9312cc01e780a2fea56ab8ec12b4 (diff)
parent1c804664cf63f0c2e80d0420e52d5f82c3956685 (diff)
downloadxen-ab26a6a563a0acb589af87a8e063c0e171d75665.tar.gz
xen-ab26a6a563a0acb589af87a8e063c0e171d75665.tar.bz2
xen-ab26a6a563a0acb589af87a8e063c0e171d75665.zip
Merge with xen-unstable.hg.
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
-rw-r--r--.hgignore19
-rw-r--r--.hgtags1
-rw-r--r--Config.mk56
-rw-r--r--Makefile5
-rw-r--r--buildconfigs/Rules.mk3
-rw-r--r--buildconfigs/linux-defconfig_xen0_ia6416
-rw-r--r--buildconfigs/linux-defconfig_xenU_ia649
-rw-r--r--buildconfigs/linux-defconfig_xen_ia6416
-rw-r--r--buildconfigs/linux-defconfig_xen_x86_321
-rw-r--r--buildconfigs/linux-defconfig_xen_x86_641
-rw-r--r--buildconfigs/mk.linux-2.6-xen2
-rw-r--r--config/Linux.mk8
-rw-r--r--config/OpenBSD.mk1
-rw-r--r--config/StdGNU.mk30
-rw-r--r--config/SunOS.mk35
-rw-r--r--config/ia64.mk2
-rw-r--r--config/powerpc64.mk1
-rw-r--r--config/x86_32.mk10
-rw-r--r--config/x86_64.mk12
-rw-r--r--docs/Makefile5
-rw-r--r--docs/man/xm.pod.18
-rw-r--r--docs/src/interface.tex42
-rw-r--r--docs/src/user.tex28
-rw-r--r--docs/xen-api/Makefile23
-rw-r--r--docs/xen-api/coversheet.tex50
-rw-r--r--docs/xen-api/fdl.tex488
-rw-r--r--docs/xen-api/presentation.tex149
-rw-r--r--docs/xen-api/todo.tex140
-rw-r--r--docs/xen-api/vm-lifecycle.tex24
-rw-r--r--docs/xen-api/vm_lifecycle.dot15
-rw-r--r--docs/xen-api/wire-protocol.tex287
-rw-r--r--docs/xen-api/xen.eps44
-rw-r--r--docs/xen-api/xenapi-coversheet.tex40
-rw-r--r--docs/xen-api/xenapi-datamodel-graph.dot17
-rw-r--r--docs/xen-api/xenapi-datamodel.tex9648
-rw-r--r--docs/xen-api/xenapi.tex56
-rw-r--r--extras/mini-os/Makefile13
-rw-r--r--extras/mini-os/README4
-rw-r--r--extras/mini-os/arch/x86/mm.c428
-rw-r--r--extras/mini-os/arch/x86/sched.c150
-rw-r--r--extras/mini-os/arch/x86/setup.c108
-rw-r--r--extras/mini-os/events.c48
-rw-r--r--extras/mini-os/include/events.h9
-rw-r--r--extras/mini-os/include/mm.h175
-rw-r--r--extras/mini-os/include/sched.h29
-rw-r--r--extras/mini-os/include/spinlock.h55
-rw-r--r--extras/mini-os/include/time.h6
-rw-r--r--extras/mini-os/include/x86/arch_mm.h209
-rw-r--r--extras/mini-os/include/x86/arch_sched.h58
-rw-r--r--extras/mini-os/include/x86/arch_spinlock.h (renamed from extras/mini-os/include/x86/spinlock.h)38
-rw-r--r--extras/mini-os/include/x86/os.h7
-rw-r--r--extras/mini-os/include/x86/x86_32/hypercall-x86_32.h6
-rw-r--r--extras/mini-os/include/x86/x86_64/hypercall-x86_64.h6
-rw-r--r--extras/mini-os/kernel.c101
-rw-r--r--extras/mini-os/mm.c383
-rw-r--r--extras/mini-os/sched.c198
-rw-r--r--extras/mini-os/time.c26
-rw-r--r--linux-2.6-xen-sparse/arch/i386/Kconfig3
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/fixup.c3
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S3
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c38
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c40
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c2
-rw-r--r--linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c1
-rw-r--r--linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c8
-rw-r--r--linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c16
-rw-r--r--linux-2.6-xen-sparse/arch/i386/mm/init-xen.c10
-rw-r--r--linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c10
-rw-r--r--linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c27
-rw-r--r--linux-2.6-xen-sparse/arch/i386/oprofile/Makefile5
-rw-r--r--linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c545
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/Kconfig17
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/dig/setup.c23
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/kernel/Makefile62
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S1
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/kernel/setup.c4
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/Makefile3
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c375
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/util.c2
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c303
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c319
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c656
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c263
-rw-r--r--linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S21
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/Kconfig2
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile1
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/kernel/entry-xen.S7
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c1
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c43
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/kernel/traps-xen.c5
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c41
-rw-r--r--linux-2.6-xen-sparse/arch/x86_64/oprofile/Makefile5
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c12
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tty_io.c14
-rw-r--r--linux-2.6-xen-sparse/drivers/serial/Kconfig1
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/balloon/Makefile2
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c201
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/balloon/common.h58
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c165
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c119
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkback/common.h7
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c5
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c23
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c74
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkfront/block.h2
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c85
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c799
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c7
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/char/mem.c51
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/console/console.c36
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/Makefile2
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/features.c4
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/gnttab.c4
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c185
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/reboot.c210
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/core/skbuff.c7
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c3
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/common.h7
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/interface.c80
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/loopback.c62
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/netback.c216
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c123
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c249
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c195
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/tpmback/common.h8
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c19
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c14
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c4
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile1
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c9
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c11
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c5
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c297
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h74
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c271
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c11
-rw-r--r--linux-2.6-xen-sparse/drivers/xen/xenoprof/xenoprofile.c500
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/fixmap.h3
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h10
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h13
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h3
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/maddr.h56
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h21
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h1
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h1
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/synch_bitops.h4
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/xenoprof.h48
-rw-r--r--linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h21
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/hypercall.h179
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h28
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/maddr.h20
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h3
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h76
-rw-r--r--linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h60
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/fixmap.h1
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h10
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h3
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/maddr.h39
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h21
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h19
-rw-r--r--linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h17
-rw-r--r--linux-2.6-xen-sparse/include/linux/skbuff.h24
-rw-r--r--linux-2.6-xen-sparse/include/xen/balloon.h20
-rw-r--r--linux-2.6-xen-sparse/include/xen/gnttab.h5
-rw-r--r--linux-2.6-xen-sparse/include/xen/public/evtchn.h3
-rw-r--r--linux-2.6-xen-sparse/include/xen/xenbus.h1
-rw-r--r--linux-2.6-xen-sparse/include/xen/xencons.h3
-rw-r--r--linux-2.6-xen-sparse/include/xen/xenoprof.h42
-rw-r--r--linux-2.6-xen-sparse/lib/Makefile2
-rw-r--r--linux-2.6-xen-sparse/mm/Kconfig2
-rw-r--r--linux-2.6-xen-sparse/mm/memory.c6
-rw-r--r--linux-2.6-xen-sparse/mm/mmap.c17
-rw-r--r--linux-2.6-xen-sparse/mm/page_alloc.c3
-rw-r--r--linux-2.6-xen-sparse/net/core/skbuff.c107
-rw-r--r--patches/linux-2.6.16.32/blktap-aio-16_03_06.patch (renamed from patches/linux-2.6.16.13/blktap-aio-16_03_06.patch)27
-rw-r--r--patches/linux-2.6.16.32/device_bind.patch (renamed from patches/linux-2.6.16.13/device_bind.patch)6
-rw-r--r--patches/linux-2.6.16.32/fix-hz-suspend.patch (renamed from patches/linux-2.6.16.13/fix-hz-suspend.patch)6
-rw-r--r--patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch (renamed from patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch)8
-rw-r--r--patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch (renamed from patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch)12
-rw-r--r--patches/linux-2.6.16.32/ipv6-no-autoconf.patch (renamed from patches/linux-2.6.16.13/ipv6-no-autoconf.patch)14
-rw-r--r--patches/linux-2.6.16.32/kasprintf.patch59
-rw-r--r--patches/linux-2.6.16.32/net-csum.patch (renamed from patches/linux-2.6.16.13/net-csum.patch)18
-rw-r--r--patches/linux-2.6.16.32/net-gso-0-base.patch (renamed from patches/linux-2.6.16.13/net-gso-0-base.patch)895
-rw-r--r--patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch (renamed from patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch)6
-rw-r--r--patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch (renamed from patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch)134
-rw-r--r--patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch (renamed from patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch)6
-rw-r--r--patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch (renamed from patches/linux-2.6.16.13/net-gso-4-kill-warnon.patch)8
-rw-r--r--patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch13
-rw-r--r--patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch292
-rw-r--r--patches/linux-2.6.16.32/pmd-shared.patch (renamed from patches/linux-2.6.16.13/pmd-shared.patch)24
-rw-r--r--patches/linux-2.6.16.32/rcu_needs_cpu.patch (renamed from patches/linux-2.6.16.13/rcu_needs_cpu.patch)26
-rw-r--r--patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch (renamed from patches/linux-2.6.16.13/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch)6
-rw-r--r--patches/linux-2.6.16.32/series (renamed from patches/linux-2.6.16.13/series)4
-rw-r--r--patches/linux-2.6.16.32/smp-alts.patch (renamed from patches/linux-2.6.16.13/smp-alts.patch)72
-rw-r--r--patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch (renamed from patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch)37
-rw-r--r--patches/linux-2.6.16.32/vsnprintf.patch211
-rw-r--r--patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch (renamed from patches/linux-2.6.16.13/x86-elfnote-as-preprocessor-macro.patch)7
-rw-r--r--patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch (renamed from patches/linux-2.6.16.13/x86-increase-interrupt-vector-range.patch)38
-rw-r--r--patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch (renamed from patches/linux-2.6.16.13/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch)59
-rw-r--r--patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch (renamed from patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch)19
-rw-r--r--patches/linux-2.6.16.32/xen-hotplug.patch (renamed from patches/linux-2.6.16.13/xen-hotplug.patch)5
-rw-r--r--patches/linux-2.6.16.32/xenoprof-generic.patch (renamed from patches/linux-2.6.16.13/xenoprof-generic.patch)135
-rw-r--r--tools/Makefile3
-rw-r--r--tools/Rules.mk13
-rw-r--r--tools/blktap/drivers/Makefile12
-rw-r--r--tools/blktap/drivers/blktapctrl.c201
-rw-r--r--tools/blktap/drivers/blktapctrl.h6
-rw-r--r--tools/blktap/drivers/tapdisk.c66
-rw-r--r--tools/blktap/drivers/tapdisk.h15
-rw-r--r--tools/blktap/lib/Makefile9
-rw-r--r--tools/blktap/lib/blktaplib.h26
-rw-r--r--tools/blktap/lib/xenbus.c179
-rw-r--r--tools/blktap/lib/xs_api.c93
-rw-r--r--tools/blktap/lib/xs_api.h2
-rwxr-xr-xtools/check/check_brctl31
-rwxr-xr-xtools/check/check_crypto_lib11
-rwxr-xr-xtools/check/check_iproute29
-rwxr-xr-xtools/check/check_openssl_devel11
-rwxr-xr-xtools/check/check_python17
-rwxr-xr-xtools/check/check_python_devel16
-rwxr-xr-x[-rw-r--r--]tools/check/check_udev (renamed from tools/check/check_hotplug)2
-rwxr-xr-xtools/check/check_x11_devel11
-rwxr-xr-xtools/check/check_zlib_devel17
-rwxr-xr-xtools/check/check_zlib_lib17
-rwxr-xr-xtools/check/chk19
-rw-r--r--tools/console/Makefile10
-rw-r--r--tools/console/daemon/io.c2
-rw-r--r--tools/console/daemon/utils.c2
-rw-r--r--tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c2
-rw-r--r--tools/debugger/pdb/Domain.ml61
-rw-r--r--tools/debugger/pdb/Domain.mli39
-rw-r--r--tools/debugger/pdb/Intel.ml66
-rw-r--r--tools/debugger/pdb/Makefile57
-rw-r--r--tools/debugger/pdb/OCamlMakefile1149
-rw-r--r--tools/debugger/pdb/PDB.ml342
-rw-r--r--tools/debugger/pdb/Process.ml79
-rw-r--r--tools/debugger/pdb/Process.mli41
-rw-r--r--tools/debugger/pdb/Util.ml165
-rw-r--r--tools/debugger/pdb/Xen_domain.ml43
-rw-r--r--tools/debugger/pdb/Xen_domain.mli25
-rw-r--r--tools/debugger/pdb/debugger.ml372
-rw-r--r--tools/debugger/pdb/evtchn.ml40
-rw-r--r--tools/debugger/pdb/evtchn.mli19
-rw-r--r--tools/debugger/pdb/linux-2.6-module/Makefile21
-rw-r--r--tools/debugger/pdb/linux-2.6-module/debug.c851
-rw-r--r--tools/debugger/pdb/linux-2.6-module/module.c337
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_debug.h47
-rw-r--r--tools/debugger/pdb/linux-2.6-module/pdb_module.h142
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/Makefile11
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch19
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/kdebug.patch11
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/makefile.patch12
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/ptrace.patch11
-rw-r--r--tools/debugger/pdb/linux-2.6-patches/traps.patch20
-rw-r--r--tools/debugger/pdb/pdb_caml_domain.c527
-rw-r--r--tools/debugger/pdb/pdb_caml_evtchn.c186
-rw-r--r--tools/debugger/pdb/pdb_caml_process.c587
-rw-r--r--tools/debugger/pdb/pdb_caml_xc.c170
-rw-r--r--tools/debugger/pdb/pdb_caml_xcs.c307
-rw-r--r--tools/debugger/pdb/pdb_caml_xen.h39
-rw-r--r--tools/debugger/pdb/pdb_xen.c75
-rw-r--r--tools/debugger/pdb/readme105
-rw-r--r--tools/debugger/pdb/server.ml241
-rw-r--r--tools/debugger/pdb/xcs.ml85
-rw-r--r--tools/debugger/pdb/xcs.mli13
-rw-r--r--tools/examples/Makefile5
-rw-r--r--tools/examples/blktap18
-rw-r--r--tools/examples/block31
-rw-r--r--tools/examples/external-device-migrate56
-rw-r--r--tools/examples/init.d/xendomains6
-rw-r--r--tools/examples/locking.sh2
-rwxr-xr-xtools/examples/vif-bridge2
-rw-r--r--tools/examples/vif-common.sh2
-rw-r--r--tools/examples/vif-nat4
-rwxr-xr-xtools/examples/vif-route2
-rw-r--r--tools/examples/vtpm-common.sh6
-rw-r--r--tools/examples/xen-backend.rules1
-rw-r--r--tools/examples/xend-config.sxp47
-rw-r--r--tools/examples/xmexample.hvm29
-rw-r--r--tools/examples/xmexample.vti9
-rw-r--r--tools/firmware/Makefile7
-rw-r--r--tools/firmware/acpi/Makefile68
-rw-r--r--tools/firmware/acpi/acpi2_0.h331
-rw-r--r--tools/firmware/acpi/acpi_build.c232
-rw-r--r--tools/firmware/acpi/acpi_dsdt.asl521
-rw-r--r--tools/firmware/acpi/acpi_dsdt.c296
-rw-r--r--tools/firmware/acpi/acpi_facs.c72
-rw-r--r--tools/firmware/acpi/acpi_fadt.c193
-rw-r--r--tools/firmware/acpi/acpi_fadt.h165
-rw-r--r--tools/firmware/acpi/acpi_gen.c53
-rw-r--r--tools/firmware/acpi/acpi_madt.c68
-rw-r--r--tools/firmware/acpi/acpi_madt.h44
-rw-r--r--tools/firmware/acpi/acpi_rsdt.c68
-rw-r--r--tools/firmware/hvmloader/Makefile23
-rw-r--r--tools/firmware/hvmloader/acpi/Makefile61
-rw-r--r--tools/firmware/hvmloader/acpi/README (renamed from tools/firmware/acpi/README)0
-rw-r--r--tools/firmware/hvmloader/acpi/acpi2_0.h346
-rw-r--r--tools/firmware/hvmloader/acpi/build.c206
-rw-r--r--tools/firmware/hvmloader/acpi/dsdt.asl657
-rw-r--r--tools/firmware/hvmloader/acpi/dsdt.c452
-rw-r--r--tools/firmware/hvmloader/acpi/static_tables.c145
-rw-r--r--tools/firmware/hvmloader/acpi_madt.c188
-rw-r--r--tools/firmware/hvmloader/acpi_ssdt_tpm.asl29
-rw-r--r--tools/firmware/hvmloader/acpi_ssdt_tpm.h25
-rw-r--r--tools/firmware/hvmloader/acpi_utils.c318
-rw-r--r--tools/firmware/hvmloader/acpi_utils.h (renamed from tools/firmware/acpi/acpi_facs.h)26
-rw-r--r--tools/firmware/hvmloader/apic_regs.h108
-rw-r--r--tools/firmware/hvmloader/config.h13
-rw-r--r--tools/firmware/hvmloader/hvmloader.c438
-rw-r--r--tools/firmware/hvmloader/mp_tables.c469
-rw-r--r--tools/firmware/hvmloader/pci_regs.h108
-rw-r--r--tools/firmware/hvmloader/smbios.c818
-rw-r--r--tools/firmware/hvmloader/util.c591
-rw-r--r--tools/firmware/hvmloader/util.h52
-rw-r--r--tools/firmware/rombios/rombios.c92
-rw-r--r--tools/firmware/vmxassist/Makefile9
-rw-r--r--tools/firmware/vmxassist/head.S2
-rw-r--r--tools/firmware/vmxassist/machine.h1
-rw-r--r--tools/firmware/vmxassist/setup.c3
-rw-r--r--tools/firmware/vmxassist/trap.S2
-rw-r--r--tools/firmware/vmxassist/util.c38
-rw-r--r--tools/firmware/vmxassist/util.h1
-rw-r--r--tools/firmware/vmxassist/vm86.c274
-rw-r--r--tools/firmware/vmxassist/vm86.h10
-rw-r--r--tools/guest-headers/Makefile12
-rw-r--r--tools/ioemu/Makefile.target28
-rw-r--r--tools/ioemu/d3des.c434
-rw-r--r--tools/ioemu/d3des.h51
-rw-r--r--tools/ioemu/hw/fdc.c2
-rw-r--r--tools/ioemu/hw/ide.c4
-rw-r--r--tools/ioemu/hw/ne2000.c35
-rw-r--r--tools/ioemu/hw/pc.c3
-rw-r--r--tools/ioemu/hw/pci.c24
-rw-r--r--tools/ioemu/hw/piix4acpi.c12
-rw-r--r--tools/ioemu/hw/piix_pci.c18
-rw-r--r--tools/ioemu/hw/rtl8139.c8
-rw-r--r--tools/ioemu/hw/serial.c126
-rw-r--r--tools/ioemu/hw/tpm_tis.c1114
-rw-r--r--tools/ioemu/hw/vga.c13
-rw-r--r--tools/ioemu/hw/xen_platform.c14
-rw-r--r--tools/ioemu/keymaps/ja3
-rw-r--r--tools/ioemu/patches/domain-timeoffset16
-rw-r--r--tools/ioemu/patches/fix-vga-scanning-code-overflow45
-rw-r--r--tools/ioemu/patches/hypervisor-rtc143
-rw-r--r--tools/ioemu/patches/ide-cd-dma21
-rw-r--r--tools/ioemu/patches/qemu-bootorder28
-rw-r--r--tools/ioemu/patches/qemu-cleanup45
-rw-r--r--tools/ioemu/patches/qemu-daemonize6
-rw-r--r--tools/ioemu/patches/qemu-logging6
-rwxr-xr-xtools/ioemu/patches/qemu-pci29
-rw-r--r--tools/ioemu/patches/qemu-target-i386-dm32
-rw-r--r--tools/ioemu/patches/serial-port-rate-limit116
-rw-r--r--tools/ioemu/patches/series10
-rw-r--r--tools/ioemu/patches/vnc-access-monitor-vt8
-rw-r--r--tools/ioemu/patches/vnc-backoff-screen-scan385
-rw-r--r--tools/ioemu/patches/vnc-cleanup53
-rw-r--r--tools/ioemu/patches/vnc-display-find-unused22
-rw-r--r--tools/ioemu/patches/vnc-fixes75
-rw-r--r--tools/ioemu/patches/vnc-listen-specific-interface177
-rw-r--r--tools/ioemu/patches/vnc-password785
-rw-r--r--tools/ioemu/patches/vnc-protocol-fixes63
-rw-r--r--tools/ioemu/patches/vnc-start-vncviewer16
-rw-r--r--tools/ioemu/patches/vnc-title-domain-name10
-rw-r--r--tools/ioemu/patches/xen-build21
-rw-r--r--tools/ioemu/patches/xen-platform-device32
-rw-r--r--tools/ioemu/patches/xen-support-buffered-ioreqs12
-rw-r--r--tools/ioemu/patches/xenstore-block-device-config60
-rw-r--r--tools/ioemu/patches/xenstore-write-vnc-port18
-rw-r--r--tools/ioemu/target-i386-dm/cpu.h2
-rw-r--r--tools/ioemu/target-i386-dm/exec-dm.c50
-rw-r--r--tools/ioemu/target-i386-dm/helper2.c113
-rw-r--r--tools/ioemu/target-i386-dm/i8259-dm.c42
-rw-r--r--tools/ioemu/target-i386-dm/piix_pci-dm.c152
-rw-r--r--tools/ioemu/target-i386-dm/qemu-dm.debug7
-rw-r--r--tools/ioemu/target-i386-dm/rtc-dm.c107
-rw-r--r--tools/ioemu/usb-linux.c4
-rw-r--r--tools/ioemu/vl.c114
-rw-r--r--tools/ioemu/vl.h32
-rw-r--r--tools/ioemu/vnc.c395
-rw-r--r--tools/ioemu/vnc_keysym.h10
-rw-r--r--tools/ioemu/xenstore.c190
-rw-r--r--tools/libfsimage/Makefile13
-rw-r--r--tools/libfsimage/Rules.mk32
-rwxr-xr-xtools/libfsimage/check-libext2fs21
-rw-r--r--tools/libfsimage/common/Makefile46
-rw-r--r--tools/libfsimage/common/fsimage.c142
-rw-r--r--tools/libfsimage/common/fsimage.h52
-rw-r--r--tools/libfsimage/common/fsimage_grub.c276
-rw-r--r--tools/libfsimage/common/fsimage_grub.h92
-rw-r--r--tools/libfsimage/common/fsimage_plugin.c214
-rw-r--r--tools/libfsimage/common/fsimage_plugin.h65
-rw-r--r--tools/libfsimage/common/fsimage_priv.h62
-rw-r--r--tools/libfsimage/common/mapfile-GNU37
-rw-r--r--tools/libfsimage/common/mapfile-SunOS35
-rw-r--r--tools/libfsimage/ext2fs-lib/Makefile15
-rw-r--r--tools/libfsimage/ext2fs-lib/ext2fs-lib.c172
-rw-r--r--tools/libfsimage/ext2fs/Makefile13
-rw-r--r--tools/libfsimage/ext2fs/fsys_ext2fs.c872
-rw-r--r--tools/libfsimage/reiserfs/Makefile13
-rw-r--r--tools/libfsimage/reiserfs/fsys_reiserfs.c1318
-rw-r--r--tools/libfsimage/ufs/Makefile13
-rw-r--r--tools/libfsimage/ufs/fsys_ufs.c276
-rw-r--r--tools/libfsimage/ufs/ufs.h228
-rw-r--r--tools/libxc/Makefile20
-rw-r--r--tools/libxc/ia64/xc_ia64_hvm_build.c28
-rw-r--r--tools/libxc/ia64/xc_ia64_linux_restore.c47
-rw-r--r--tools/libxc/ia64/xc_ia64_linux_save.c67
-rw-r--r--tools/libxc/xc_acm.c9
-rw-r--r--tools/libxc/xc_core.c2
-rw-r--r--tools/libxc/xc_domain.c75
-rw-r--r--tools/libxc/xc_evtchn.c6
-rw-r--r--tools/libxc/xc_hvm_build.c453
-rw-r--r--tools/libxc/xc_linux.c82
-rw-r--r--tools/libxc/xc_linux_build.c288
-rw-r--r--tools/libxc/xc_linux_restore.c145
-rw-r--r--tools/libxc/xc_linux_save.c120
-rw-r--r--tools/libxc/xc_load_elf.c2
-rw-r--r--tools/libxc/xc_misc.c96
-rw-r--r--tools/libxc/xc_private.c144
-rw-r--r--tools/libxc/xc_private.h24
-rw-r--r--tools/libxc/xc_ptrace.c51
-rw-r--r--tools/libxc/xc_ptrace.h24
-rw-r--r--tools/libxc/xc_ptrace_core.c26
-rw-r--r--tools/libxc/xc_solaris.c235
-rw-r--r--tools/libxc/xc_tbuf.c8
-rw-r--r--tools/libxc/xenctrl.h84
-rw-r--r--tools/libxc/xenguest.h53
-rw-r--r--tools/libxc/xg_private.c82
-rw-r--r--tools/libxc/xg_private.h6
-rw-r--r--tools/libxen/COPYING510
-rw-r--r--tools/libxen/Makefile37
-rw-r--r--tools/libxen/README54
-rw-r--r--tools/libxen/include/xen_boot_type.h87
-rw-r--r--tools/libxen/include/xen_boot_type_internal.h37
-rw-r--r--tools/libxen/include/xen_common.h145
-rw-r--r--tools/libxen/include/xen_cpu_feature.h387
-rw-r--r--tools/libxen/include/xen_cpu_feature_internal.h37
-rw-r--r--tools/libxen/include/xen_driver_type.h77
-rw-r--r--tools/libxen/include/xen_driver_type_internal.h37
-rw-r--r--tools/libxen/include/xen_host.h292
-rw-r--r--tools/libxen/include/xen_host_cpu.h239
-rw-r--r--tools/libxen/include/xen_host_cpu_decl.h30
-rw-r--r--tools/libxen/include/xen_host_decl.h30
-rw-r--r--tools/libxen/include/xen_int_float_map.h53
-rw-r--r--tools/libxen/include/xen_internal.h193
-rw-r--r--tools/libxen/include/xen_network.h273
-rw-r--r--tools/libxen/include/xen_network_decl.h30
-rw-r--r--tools/libxen/include/xen_on_crash_behaviour.h97
-rw-r--r--tools/libxen/include/xen_on_crash_behaviour_internal.h38
-rw-r--r--tools/libxen/include/xen_on_normal_exit.h77
-rw-r--r--tools/libxen/include/xen_on_normal_exit_internal.h37
-rw-r--r--tools/libxen/include/xen_pif.h290
-rw-r--r--tools/libxen/include/xen_pif_decl.h30
-rw-r--r--tools/libxen/include/xen_sr.h282
-rw-r--r--tools/libxen/include/xen_sr_decl.h30
-rw-r--r--tools/libxen/include/xen_string_string_map.h53
-rw-r--r--tools/libxen/include/xen_user.h204
-rw-r--r--tools/libxen/include/xen_user_decl.h30
-rw-r--r--tools/libxen/include/xen_vbd.h285
-rw-r--r--tools/libxen/include/xen_vbd_decl.h30
-rw-r--r--tools/libxen/include/xen_vbd_mode.h77
-rw-r--r--tools/libxen/include/xen_vbd_mode_internal.h37
-rw-r--r--tools/libxen/include/xen_vdi.h344
-rw-r--r--tools/libxen/include/xen_vdi_decl.h30
-rw-r--r--tools/libxen/include/xen_vdi_type.h82
-rw-r--r--tools/libxen/include/xen_vdi_type_internal.h37
-rw-r--r--tools/libxen/include/xen_vif.h305
-rw-r--r--tools/libxen/include/xen_vif_decl.h30
-rw-r--r--tools/libxen/include/xen_vm.h819
-rw-r--r--tools/libxen/include/xen_vm_decl.h30
-rw-r--r--tools/libxen/include/xen_vm_power_state.h97
-rw-r--r--tools/libxen/include/xen_vm_power_state_internal.h37
-rw-r--r--tools/libxen/include/xen_vtpm.h216
-rw-r--r--tools/libxen/include/xen_vtpm_decl.h31
-rw-r--r--tools/libxen/src/xen_boot_type.c83
-rw-r--r--tools/libxen/src/xen_common.c1363
-rw-r--r--tools/libxen/src/xen_cpu_feature.c143
-rw-r--r--tools/libxen/src/xen_driver_type.c81
-rw-r--r--tools/libxen/src/xen_host.c390
-rw-r--r--tools/libxen/src/xen_host_cpu.c287
-rw-r--r--tools/libxen/src/xen_int_float_map.c37
-rw-r--r--tools/libxen/src/xen_network.c364
-rw-r--r--tools/libxen/src/xen_on_crash_behaviour.c85
-rw-r--r--tools/libxen/src/xen_on_normal_exit.c81
-rw-r--r--tools/libxen/src/xen_pif.c403
-rw-r--r--tools/libxen/src/xen_sr.c388
-rw-r--r--tools/libxen/src/xen_string_string_map.c49
-rw-r--r--tools/libxen/src/xen_user.c201
-rw-r--r--tools/libxen/src/xen_vbd.c387
-rw-r--r--tools/libxen/src/xen_vbd_mode.c81
-rw-r--r--tools/libxen/src/xen_vdi.c533
-rw-r--r--tools/libxen/src/xen_vdi_type.c82
-rw-r--r--tools/libxen/src/xen_vif.c440
-rw-r--r--tools/libxen/src/xen_vm.c1596
-rw-r--r--tools/libxen/src/xen_vm_power_state.c85
-rw-r--r--tools/libxen/src/xen_vtpm.c227
-rw-r--r--tools/libxen/test/test_bindings.c424
-rw-r--r--tools/misc/Makefile10
-rw-r--r--tools/misc/lomount/Makefile5
-rw-r--r--tools/misc/lomount/lomount.c2
-rw-r--r--tools/misc/mbootpack/GPL340
-rw-r--r--tools/misc/mbootpack/Makefile75
-rw-r--r--tools/misc/mbootpack/README77
-rw-r--r--tools/misc/mbootpack/bin2c.c356
-rw-r--r--tools/misc/mbootpack/bootsect.S136
-rw-r--r--tools/misc/mbootpack/buildimage.c175
-rw-r--r--tools/misc/mbootpack/mb_header.h90
-rw-r--r--tools/misc/mbootpack/mb_info.h217
-rw-r--r--tools/misc/mbootpack/mbootpack.c706
-rw-r--r--tools/misc/mbootpack/mbootpack.h109
-rw-r--r--tools/misc/mbootpack/setup.S1064
-rw-r--r--tools/misc/miniterm/Makefile4
-rw-r--r--tools/misc/miniterm/miniterm.c25
-rw-r--r--tools/misc/xend10
-rw-r--r--tools/misc/xenperf.c148
-rw-r--r--tools/pygrub/Makefile8
-rw-r--r--tools/pygrub/setup.py43
-rw-r--r--tools/pygrub/src/fsimage/fsimage.c299
-rw-r--r--tools/pygrub/src/fsys/__init__.py64
-rw-r--r--tools/pygrub/src/fsys/ext2/__init__.py38
-rw-r--r--tools/pygrub/src/fsys/ext2/ext2module.c387
-rw-r--r--tools/pygrub/src/fsys/ext2/test.py15
-rw-r--r--tools/pygrub/src/fsys/reiser/__init__.py39
-rw-r--r--tools/pygrub/src/fsys/reiser/reisermodule.c345
-rw-r--r--tools/pygrub/src/pygrub55
-rw-r--r--tools/python/Makefile6
-rw-r--r--tools/python/README.XendConfig160
-rw-r--r--tools/python/README.sxpcfg117
-rw-r--r--tools/python/scripts/README49
-rw-r--r--tools/python/scripts/README.lifecycle136
-rw-r--r--tools/python/scripts/xapi.domcfg.py37
-rw-r--r--tools/python/scripts/xapi.py537
-rw-r--r--tools/python/scripts/xapi.vbdcfg.py12
-rw-r--r--tools/python/scripts/xapi.vdicfg.py7
-rw-r--r--tools/python/scripts/xapi.vifcfg.py10
-rw-r--r--tools/python/scripts/xapi.vtpmcfg.py3
-rw-r--r--tools/python/setup.py3
-rw-r--r--tools/python/xen/lowlevel/acm/acm.c15
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c123
-rw-r--r--tools/python/xen/util/auxbin.py2
-rw-r--r--tools/python/xen/util/blkif.py22
-rw-r--r--tools/python/xen/util/security.py38
-rw-r--r--tools/python/xen/util/xmlrpclib2.py61
-rw-r--r--tools/python/xen/web/connection.py16
-rw-r--r--tools/python/xen/web/tcp.py14
-rw-r--r--tools/python/xen/xend/Args.py2
-rw-r--r--tools/python/xen/xend/PrettyPrint.py2
-rw-r--r--tools/python/xen/xend/XendAPI.py1548
-rw-r--r--tools/python/xen/xend/XendAPIConstants.py75
-rw-r--r--tools/python/xen/xend/XendAuthSessions.py145
-rw-r--r--tools/python/xen/xend/XendBootloader.py9
-rw-r--r--tools/python/xen/xend/XendCheckpoint.py55
-rw-r--r--tools/python/xen/xend/XendClient.py1
-rw-r--r--tools/python/xen/xend/XendConfig.py947
-rw-r--r--tools/python/xen/xend/XendConstants.py102
-rw-r--r--tools/python/xen/xend/XendDevices.py83
-rw-r--r--tools/python/xen/xend/XendDomain.py1234
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py2272
-rw-r--r--tools/python/xen/xend/XendError.py16
-rw-r--r--tools/python/xen/xend/XendNode.py133
-rw-r--r--tools/python/xen/xend/XendProtocol.py2
-rw-r--r--tools/python/xen/xend/XendRoot.py52
-rw-r--r--tools/python/xen/xend/XendStorageRepository.py358
-rw-r--r--tools/python/xen/xend/XendVDI.py155
-rw-r--r--tools/python/xen/xend/arch.py1
-rw-r--r--tools/python/xen/xend/image.py136
-rw-r--r--tools/python/xen/xend/osdep.py36
-rw-r--r--tools/python/xen/xend/server/DevController.py57
-rw-r--r--tools/python/xen/xend/server/SrvDaemon.py26
-rw-r--r--tools/python/xen/xend/server/SrvDomain.py14
-rw-r--r--tools/python/xen/xend/server/SrvDomainDir.py2
-rw-r--r--tools/python/xen/xend/server/SrvServer.py81
-rw-r--r--tools/python/xen/xend/server/XMLRPCServer.py127
-rw-r--r--tools/python/xen/xend/server/blkif.py49
-rw-r--r--tools/python/xen/xend/server/iopif.py4
-rw-r--r--tools/python/xen/xend/server/irqif.py2
-rw-r--r--tools/python/xen/xend/server/netif.py38
-rw-r--r--tools/python/xen/xend/server/pciif.py75
-rw-r--r--tools/python/xen/xend/server/tpmif.py36
-rw-r--r--tools/python/xen/xend/sxp.py24
-rw-r--r--tools/python/xen/xend/uuid.py10
-rw-r--r--tools/python/xen/xm/addlabel.py108
-rw-r--r--tools/python/xen/xm/cfgbootpolicy.py208
-rw-r--r--tools/python/xen/xm/console.py2
-rw-r--r--tools/python/xen/xm/create.py201
-rw-r--r--tools/python/xen/xm/dry-run.py56
-rw-r--r--tools/python/xen/xm/dumppolicy.py29
-rw-r--r--tools/python/xen/xm/getlabel.py66
-rw-r--r--tools/python/xen/xm/labels.py73
-rw-r--r--tools/python/xen/xm/loadpolicy.py34
-rw-r--r--tools/python/xen/xm/main.py880
-rw-r--r--tools/python/xen/xm/makepolicy.py23
-rw-r--r--tools/python/xen/xm/migrate.py16
-rw-r--r--tools/python/xen/xm/new.py68
-rw-r--r--tools/python/xen/xm/opts.py98
-rw-r--r--tools/python/xen/xm/resources.py40
-rw-r--r--tools/python/xen/xm/rmlabel.py65
-rw-r--r--tools/python/xen/xm/shutdown.py1
-rw-r--r--tools/python/xen/xm/sysrq.py32
-rw-r--r--tools/security/example.txt376
-rw-r--r--tools/security/install.txt87
-rw-r--r--tools/security/policy.txt155
-rw-r--r--tools/security/policytools.txt148
-rw-r--r--tools/security/readme.txt31
-rw-r--r--tools/security/secpol_tool.c14
-rw-r--r--tools/security/secpol_xml2bin.c10
-rw-r--r--tools/vnet/doc/Makefile5
-rw-r--r--tools/vnet/doc/man/vn.pod.14
-rw-r--r--tools/vnet/examples/Makefile6
-rw-r--r--tools/vnet/libxutil/Makefile9
-rw-r--r--tools/vnet/libxutil/hash_table.c13
-rw-r--r--tools/vnet/libxutil/hash_table.h1
-rw-r--r--tools/vnet/scripts/Makefile6
-rw-r--r--tools/vnet/vnet-module/Makefile.ver27
-rw-r--r--tools/vnet/vnet-module/esp.c16
-rw-r--r--tools/vnet/vnet-module/etherip.c43
-rw-r--r--tools/vnet/vnet-module/tunnel.c7
-rw-r--r--tools/vnet/vnet-module/tunnel.h8
-rw-r--r--tools/vnet/vnet-module/varp.c9
-rw-r--r--tools/vnet/vnet-module/varp_socket.c72
-rw-r--r--tools/vnet/vnet-module/vif.c1
-rw-r--r--tools/vnet/vnet-module/vnet.c13
-rw-r--r--tools/vnet/vnet-module/vnet_dev.c12
-rw-r--r--tools/vnet/vnet-module/vnet_eval.c2
-rw-r--r--tools/vnet/vnet-module/vnet_forward.c1
-rw-r--r--tools/vnet/vnetd/Makefile6
-rw-r--r--tools/vnet/vnetd/vnetd.c34
-rw-r--r--tools/vtpm/Rules.mk5
-rw-r--r--tools/vtpm_manager/Rules.mk5
-rw-r--r--tools/xcutils/Makefile6
-rw-r--r--tools/xcutils/readnotes.c6
-rw-r--r--tools/xenmon/Makefile11
-rw-r--r--tools/xenmon/xenmon.py9
-rw-r--r--tools/xenstat/libxenstat/Makefile12
-rw-r--r--tools/xenstat/libxenstat/src/xenstat.c20
-rw-r--r--tools/xenstat/xentop/Makefile7
-rw-r--r--tools/xenstat/xentop/xentop.13
-rw-r--r--tools/xenstat/xentop/xentop.c21
-rw-r--r--tools/xenstore/Makefile28
-rw-r--r--tools/xenstore/xenstore_client.c21
-rw-r--r--tools/xenstore/xenstored_core.c36
-rw-r--r--tools/xenstore/xenstored_core.h3
-rw-r--r--tools/xenstore/xenstored_domain.c29
-rw-r--r--tools/xenstore/xenstored_domain.h4
-rw-r--r--tools/xenstore/xenstored_linux.c4
-rw-r--r--tools/xenstore/xenstored_solaris.c66
-rw-r--r--tools/xenstore/xenstored_transaction.c2
-rw-r--r--tools/xenstore/xs_lib.c9
-rw-r--r--tools/xenstore/xsls.c20
-rw-r--r--tools/xentrace/Makefile7
-rw-r--r--tools/xentrace/formats31
-rw-r--r--tools/xentrace/xenctx.c106
-rw-r--r--tools/xm-test/README36
-rw-r--r--tools/xm-test/configure.ac26
-rw-r--r--tools/xm-test/grouptest/default1
-rw-r--r--tools/xm-test/grouptest/security1
-rwxr-xr-xtools/xm-test/lib/XmTestLib/Console.py5
-rw-r--r--tools/xm-test/lib/XmTestLib/XenDomain.py81
-rw-r--r--tools/xm-test/lib/XmTestLib/acm.py91
-rw-r--r--tools/xm-test/lib/XmTestLib/arch.py148
-rw-r--r--tools/xm-test/lib/XmTestLib/block_utils.py2
-rw-r--r--tools/xm-test/lib/XmTestReport/OSReport.py10
-rw-r--r--tools/xm-test/lib/XmTestReport/arch.py52
-rw-r--r--tools/xm-test/ramdisk/Makefile.am38
-rw-r--r--tools/xm-test/ramdisk/README-XenSource-initrd-1.0-img46
-rw-r--r--tools/xm-test/ramdisk/README-XenSource-initrd-1.1-img45
-rw-r--r--tools/xm-test/ramdisk/configs/buildroot-i386 (renamed from tools/xm-test/ramdisk/configs/buildroot)24
-rw-r--r--tools/xm-test/ramdisk/configs/buildroot-powerpc338
-rw-r--r--tools/xm-test/ramdisk/make-release.sh47
-rw-r--r--tools/xm-test/ramdisk/patches/buildroot/add_xvd_devices.patch13
-rwxr-xr-xtools/xm-test/runtest.sh36
-rw-r--r--tools/xm-test/tests/Makefile.am1
-rw-r--r--tools/xm-test/tests/block-create/01_block_attach_device_pos.py10
-rw-r--r--tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py8
-rw-r--r--tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py16
-rw-r--r--tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py18
-rw-r--r--tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py8
-rw-r--r--tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py14
-rw-r--r--tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py16
-rw-r--r--tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py44
-rw-r--r--tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py30
-rw-r--r--tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py2
-rw-r--r--tools/xm-test/tests/block-create/12_block_attach_shared_domU.py2
-rw-r--r--tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py8
-rw-r--r--tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py8
-rw-r--r--tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py2
-rw-r--r--tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py8
-rw-r--r--tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py10
-rw-r--r--tools/xm-test/tests/block-integrity/01_block_device_read_verify.py4
-rw-r--r--tools/xm-test/tests/block-integrity/02_block_device_write_verify.py4
-rw-r--r--tools/xm-test/tests/block-list/01_block-list_pos.py6
-rw-r--r--tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py6
-rw-r--r--tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py10
-rw-r--r--tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py24
-rw-r--r--tools/xm-test/tests/create/07_create_mem64_pos.py2
-rw-r--r--tools/xm-test/tests/create/08_create_mem128_pos.py2
-rw-r--r--tools/xm-test/tests/create/09_create_mem256_pos.py2
-rw-r--r--tools/xm-test/tests/create/11_create_concurrent_pos.py2
-rw-r--r--tools/xm-test/tests/create/12_create_concurrent_stress_pos.py9
-rw-r--r--tools/xm-test/tests/create/14_create_blockroot_pos.py11
-rw-r--r--tools/xm-test/tests/create/15_create_smallmem_pos.py4
-rw-r--r--tools/xm-test/tests/create/16_create_smallmem_neg.py8
-rw-r--r--tools/xm-test/tests/network-attach/04_network_attach_baddomain_neg.py6
-rw-r--r--tools/xm-test/tests/security-acm/01_security-acm_basic.py121
-rw-r--r--tools/xm-test/tests/security-acm/02_security-acm_dom_start.py64
-rw-r--r--tools/xm-test/tests/security-acm/03_security-acm_dom_conflict.py60
-rw-r--r--tools/xm-test/tests/security-acm/04_security-acm_dom_res.py69
-rw-r--r--tools/xm-test/tests/security-acm/05_security-acm_dom_res_conf.py38
-rw-r--r--tools/xm-test/tests/security-acm/06_security-acm_dom_block_attach.py82
-rw-r--r--tools/xm-test/tests/security-acm/Makefile.am28
-rw-r--r--tools/xm-test/tests/security-acm/acm_utils.py15
-rw-r--r--tools/xm-test/tests/security-acm/xm-test-security_policy.xml110
-rw-r--r--tools/xm-test/tests/vtpm/06_vtpm-susp_res_pcrs.py2
-rw-r--r--tools/xm-test/tests/vtpm/07_vtpm-mig_pcrs.py2
-rw-r--r--tools/xm-test/tests/vtpm/08_vtpm-mig_pcrs.py2
-rw-r--r--tools/xm-test/tests/vtpm/vtpm_utils.py6
-rw-r--r--unmodified_drivers/linux-2.6/Makefile1
-rw-r--r--unmodified_drivers/linux-2.6/README4
-rw-r--r--unmodified_drivers/linux-2.6/blkfront/Makefile3
-rw-r--r--unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopmd.h14
-rw-r--r--unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopud.h15
-rw-r--r--unmodified_drivers/linux-2.6/compat-include/linux/io.h10
-rw-r--r--unmodified_drivers/linux-2.6/compat-include/linux/mutex.h31
-rw-r--r--unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h72
-rwxr-xr-x[-rw-r--r--]unmodified_drivers/linux-2.6/mkbuildtree55
-rw-r--r--unmodified_drivers/linux-2.6/netfront/Makefile3
-rw-r--r--unmodified_drivers/linux-2.6/overrides.mk2
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/Kbuild7
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/Makefile3
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/evtchn.c32
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-compat.c139
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/platform-pci.c40
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/xen_support.c4
-rw-r--r--unmodified_drivers/linux-2.6/util/Kbuild3
-rw-r--r--unmodified_drivers/linux-2.6/util/Makefile3
-rw-r--r--unmodified_drivers/linux-2.6/xenbus/Makefile3
-rw-r--r--xen/COPYING20
-rw-r--r--xen/Makefile32
-rw-r--r--xen/Rules.mk23
-rw-r--r--xen/acm/acm_chinesewall_hooks.c2
-rw-r--r--xen/acm/acm_core.c99
-rw-r--r--xen/acm/acm_simple_type_enforcement_hooks.c2
-rw-r--r--xen/arch/ia64/Makefile22
-rw-r--r--xen/arch/ia64/Rules.mk22
-rw-r--r--xen/arch/ia64/asm-offsets.c4
-rw-r--r--xen/arch/ia64/linux-xen/Makefile2
-rw-r--r--xen/arch/ia64/linux-xen/README.origin2
-rw-r--r--xen/arch/ia64/linux-xen/efi.c2
-rw-r--r--xen/arch/ia64/linux-xen/entry.S6
-rw-r--r--xen/arch/ia64/linux-xen/mca.c13
-rw-r--r--xen/arch/ia64/linux-xen/minstate.h2
-rw-r--r--xen/arch/ia64/linux-xen/mm_contig.c2
-rw-r--r--xen/arch/ia64/linux-xen/mm_numa.c75
-rw-r--r--xen/arch/ia64/linux-xen/numa.c67
-rw-r--r--xen/arch/ia64/linux-xen/sal.c75
-rw-r--r--xen/arch/ia64/linux-xen/setup.c2
-rw-r--r--xen/arch/ia64/linux-xen/smpboot.c3
-rw-r--r--xen/arch/ia64/linux-xen/tlb.c9
-rw-r--r--xen/arch/ia64/linux-xen/unaligned.c18
-rw-r--r--xen/arch/ia64/tools/p2m_expose/Makefile28
-rw-r--r--xen/arch/ia64/tools/p2m_expose/README.p2m_expose12
-rw-r--r--xen/arch/ia64/tools/p2m_expose/expose_p2m.c185
-rw-r--r--xen/arch/ia64/vmx/Makefile1
-rw-r--r--xen/arch/ia64/vmx/mm.c153
-rw-r--r--xen/arch/ia64/vmx/mmio.c133
-rw-r--r--xen/arch/ia64/vmx/optvfault.S841
-rw-r--r--xen/arch/ia64/vmx/pal_emul.c513
-rw-r--r--xen/arch/ia64/vmx/vlsapic.c347
-rw-r--r--xen/arch/ia64/vmx/vmmu.c106
-rw-r--r--xen/arch/ia64/vmx/vmx_entry.S2
-rw-r--r--xen/arch/ia64/vmx/vmx_hypercall.c28
-rw-r--r--xen/arch/ia64/vmx/vmx_init.c86
-rw-r--r--xen/arch/ia64/vmx/vmx_interrupt.c19
-rw-r--r--xen/arch/ia64/vmx/vmx_ivt.S37
-rw-r--r--xen/arch/ia64/vmx/vmx_phy_mode.c78
-rw-r--r--xen/arch/ia64/vmx/vmx_process.c226
-rw-r--r--xen/arch/ia64/vmx/vmx_support.c28
-rw-r--r--xen/arch/ia64/vmx/vmx_vcpu.c64
-rw-r--r--xen/arch/ia64/vmx/vmx_virt.c36
-rw-r--r--xen/arch/ia64/vmx/vtlb.c42
-rw-r--r--xen/arch/ia64/xen/Makefile4
-rw-r--r--xen/arch/ia64/xen/acpi.c2
-rw-r--r--xen/arch/ia64/xen/dom0_ops.c92
-rw-r--r--xen/arch/ia64/xen/dom_fw.c39
-rw-r--r--xen/arch/ia64/xen/domain.c260
-rw-r--r--xen/arch/ia64/xen/faults.c472
-rw-r--r--xen/arch/ia64/xen/flushtlb.c117
-rw-r--r--xen/arch/ia64/xen/fw_emul.c144
-rw-r--r--xen/arch/ia64/xen/hypercall.c103
-rw-r--r--xen/arch/ia64/xen/hyperprivop.S2
-rw-r--r--xen/arch/ia64/xen/irq.c16
-rw-r--r--xen/arch/ia64/xen/mm.c552
-rw-r--r--xen/arch/ia64/xen/privop.c846
-rw-r--r--xen/arch/ia64/xen/regionreg.c12
-rw-r--r--xen/arch/ia64/xen/tlb_track.c507
-rw-r--r--xen/arch/ia64/xen/vcpu.c1718
-rw-r--r--xen/arch/ia64/xen/vhpt.c319
-rw-r--r--xen/arch/ia64/xen/xen.lds.S3
-rw-r--r--xen/arch/ia64/xen/xenasm.S28
-rw-r--r--xen/arch/ia64/xen/xencomm.c387
-rw-r--r--xen/arch/ia64/xen/xenmem.c93
-rw-r--r--xen/arch/ia64/xen/xenmisc.c8
-rw-r--r--xen/arch/ia64/xen/xenpatch.c122
-rw-r--r--xen/arch/ia64/xen/xensetup.c43
-rw-r--r--xen/arch/ia64/xen/xentime.c45
-rw-r--r--xen/arch/powerpc/Makefile5
-rw-r--r--xen/arch/powerpc/backtrace.c20
-rw-r--r--xen/arch/powerpc/domain.c35
-rw-r--r--xen/arch/powerpc/domain_build.c2
-rw-r--r--xen/arch/powerpc/mm.c86
-rw-r--r--xen/arch/powerpc/of-devwalk.c18
-rw-r--r--xen/arch/powerpc/papr/xlate.c2
-rw-r--r--xen/arch/powerpc/powerpc64/domain.c6
-rw-r--r--xen/arch/powerpc/setup.c12
-rw-r--r--xen/arch/powerpc/shadow.c4
-rw-r--r--xen/arch/powerpc/usercopy.c7
-rw-r--r--xen/arch/x86/Makefile27
-rw-r--r--xen/arch/x86/Rules.mk38
-rw-r--r--xen/arch/x86/acpi/boot.c69
-rw-r--r--xen/arch/x86/apic.c93
-rw-r--r--xen/arch/x86/boot/mkelf32.c5
-rw-r--r--xen/arch/x86/boot/x86_32.S33
-rw-r--r--xen/arch/x86/boot/x86_64.S56
-rw-r--r--xen/arch/x86/cpu/mcheck/Makefile6
-rw-r--r--xen/arch/x86/cpu/mcheck/mce.c4
-rw-r--r--xen/arch/x86/cpu/mtrr/Makefile6
-rw-r--r--xen/arch/x86/cpu/mtrr/main.c8
-rw-r--r--xen/arch/x86/domain.c216
-rw-r--r--xen/arch/x86/domain_build.c152
-rw-r--r--xen/arch/x86/domctl.c11
-rw-r--r--xen/arch/x86/e820.c2
-rw-r--r--xen/arch/x86/extable.c2
-rw-r--r--xen/arch/x86/flushtlb.c101
-rw-r--r--xen/arch/x86/hvm/Makefile6
-rw-r--r--xen/arch/x86/hvm/hvm.c742
-rw-r--r--xen/arch/x86/hvm/i8254.c34
-rw-r--r--xen/arch/x86/hvm/i8259.c620
-rw-r--r--xen/arch/x86/hvm/instrlen.c (renamed from xen/arch/x86/hvm/svm/instrlen.c)195
-rw-r--r--xen/arch/x86/hvm/intercept.c168
-rw-r--r--xen/arch/x86/hvm/io.c189
-rw-r--r--xen/arch/x86/hvm/irq.c227
-rw-r--r--xen/arch/x86/hvm/platform.c951
-rw-r--r--xen/arch/x86/hvm/pmtimer.c63
-rw-r--r--xen/arch/x86/hvm/rtc.c436
-rw-r--r--xen/arch/x86/hvm/svm/Makefile1
-rw-r--r--xen/arch/x86/hvm/svm/emulate.c32
-rw-r--r--xen/arch/x86/hvm/svm/intr.c134
-rw-r--r--xen/arch/x86/hvm/svm/svm.c979
-rw-r--r--xen/arch/x86/hvm/svm/vmcb.c396
-rw-r--r--xen/arch/x86/hvm/svm/x86_32/exits.S15
-rw-r--r--xen/arch/x86/hvm/svm/x86_64/exits.S16
-rw-r--r--xen/arch/x86/hvm/vioapic.c739
-rw-r--r--xen/arch/x86/hvm/vlapic.c856
-rw-r--r--xen/arch/x86/hvm/vmx/io.c95
-rw-r--r--xen/arch/x86/hvm/vmx/vmcs.c538
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c1933
-rw-r--r--xen/arch/x86/hvm/vmx/x86_32/exits.S9
-rw-r--r--xen/arch/x86/hvm/vmx/x86_64/exits.S6
-rw-r--r--xen/arch/x86/hvm/vpic.c463
-rw-r--r--xen/arch/x86/i387.c9
-rw-r--r--xen/arch/x86/io_apic.c20
-rw-r--r--xen/arch/x86/irq.c27
-rw-r--r--xen/arch/x86/microcode.c11
-rw-r--r--xen/arch/x86/mm.c623
-rw-r--r--xen/arch/x86/mm/shadow/common.c1296
-rw-r--r--xen/arch/x86/mm/shadow/multi.c2553
-rw-r--r--xen/arch/x86/mm/shadow/multi.h11
-rw-r--r--xen/arch/x86/mm/shadow/private.h489
-rw-r--r--xen/arch/x86/mm/shadow/types.h268
-rw-r--r--xen/arch/x86/mpparse.c61
-rw-r--r--xen/arch/x86/numa.c308
-rw-r--r--xen/arch/x86/oprofile/nmi_int.c44
-rw-r--r--xen/arch/x86/oprofile/op_model_athlon.c30
-rw-r--r--xen/arch/x86/oprofile/op_model_p4.c10
-rw-r--r--xen/arch/x86/oprofile/op_model_ppro.c10
-rw-r--r--xen/arch/x86/oprofile/xenoprof.c664
-rw-r--r--xen/arch/x86/physdev.c4
-rw-r--r--xen/arch/x86/platform_hypercall.c18
-rw-r--r--xen/arch/x86/setup.c98
-rw-r--r--xen/arch/x86/smp.c2
-rw-r--r--xen/arch/x86/smpboot.c5
-rw-r--r--xen/arch/x86/srat.c315
-rw-r--r--xen/arch/x86/time.c7
-rw-r--r--xen/arch/x86/traps.c434
-rw-r--r--xen/arch/x86/x86_32/Makefile1
-rw-r--r--xen/arch/x86/x86_32/asm-offsets.c2
-rw-r--r--xen/arch/x86/x86_32/domain_page.c2
-rw-r--r--xen/arch/x86/x86_32/entry.S49
-rw-r--r--xen/arch/x86/x86_32/gpr_switch.S43
-rw-r--r--xen/arch/x86/x86_32/seg_fixup.c50
-rw-r--r--xen/arch/x86/x86_32/supervisor_mode_kernel.S2
-rw-r--r--xen/arch/x86/x86_32/traps.c47
-rw-r--r--xen/arch/x86/x86_64/Makefile1
-rw-r--r--xen/arch/x86/x86_64/asm-offsets.c2
-rw-r--r--xen/arch/x86/x86_64/entry.S36
-rw-r--r--xen/arch/x86/x86_64/gpr_switch.S63
-rw-r--r--xen/arch/x86/x86_64/mm.c36
-rw-r--r--xen/arch/x86/x86_64/traps.c57
-rw-r--r--xen/arch/x86/x86_emulate.c231
-rw-r--r--xen/common/Makefile4
-rw-r--r--xen/common/domain.c114
-rw-r--r--xen/common/domctl.c75
-rw-r--r--xen/common/elf.c2
-rw-r--r--xen/common/event_channel.c3
-rw-r--r--xen/common/gdbstub.c79
-rw-r--r--xen/common/grant_table.c116
-rw-r--r--xen/common/keyhandler.c5
-rw-r--r--xen/common/lib.c13
-rw-r--r--xen/common/memory.c236
-rw-r--r--xen/common/multicall.c2
-rw-r--r--xen/common/page_alloc.c202
-rw-r--r--xen/common/perfc.c13
-rw-r--r--xen/common/sched_credit.c559
-rw-r--r--xen/common/sched_sedf.c65
-rw-r--r--xen/common/schedule.c109
-rw-r--r--xen/common/shutdown.c3
-rw-r--r--xen/common/symbols-dummy.c16
-rw-r--r--xen/common/symbols.c13
-rw-r--r--xen/common/time.c77
-rw-r--r--xen/common/trace.c4
-rw-r--r--xen/common/vsprintf.c2
-rw-r--r--xen/common/xenoprof.c743
-rw-r--r--xen/common/xmalloc.c90
-rw-r--r--xen/drivers/acpi/Makefile1
-rw-r--r--xen/drivers/acpi/numa.c216
-rw-r--r--xen/drivers/acpi/tables.c437
-rw-r--r--xen/drivers/char/console.c302
-rw-r--r--xen/drivers/char/serial.c4
-rw-r--r--xen/drivers/video/vga.c11
-rw-r--r--xen/include/acm/acm_hooks.h14
-rw-r--r--xen/include/acpi/platform/acenv.h2
-rw-r--r--xen/include/asm-ia64/config.h22
-rw-r--r--xen/include/asm-ia64/debugger.h1
-rw-r--r--xen/include/asm-ia64/dom_fw.h9
-rw-r--r--xen/include/asm-ia64/domain.h59
-rw-r--r--xen/include/asm-ia64/flushtlb.h89
-rw-r--r--xen/include/asm-ia64/guest_access.h140
-rw-r--r--xen/include/asm-ia64/hvm/vlapic.h6
-rw-r--r--xen/include/asm-ia64/ia64_int.h4
-rw-r--r--xen/include/asm-ia64/linux-null/asm/mmzone.h1
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/README.origin3
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/acpi.h (renamed from xen/include/asm-ia64/linux/asm/acpi.h)2
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/atomic.h (renamed from xen/include/asm-ia64/linux/asm/atomic.h)5
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/cache.h2
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/numa.h (renamed from xen/include/asm-ia64/linux/asm/numa.h)6
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/pgtable.h37
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/processor.h18
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/spinlock.h6
-rw-r--r--xen/include/asm-ia64/linux-xen/asm/system.h1
-rw-r--r--xen/include/asm-ia64/linux/README.origin1
-rw-r--r--xen/include/asm-ia64/linux/asm/README.origin4
-rw-r--r--xen/include/asm-ia64/linux/asm/nodedata.h52
-rw-r--r--xen/include/asm-ia64/linux/asm/sal.h10
-rw-r--r--xen/include/asm-ia64/linux/hash.h58
-rw-r--r--xen/include/asm-ia64/mm.h34
-rw-r--r--xen/include/asm-ia64/p2m_entry.h76
-rw-r--r--xen/include/asm-ia64/perfc_defn.h65
-rw-r--r--xen/include/asm-ia64/privop.h4
-rw-r--r--xen/include/asm-ia64/tlb_track.h155
-rw-r--r--xen/include/asm-ia64/tlbflush.h10
-rw-r--r--xen/include/asm-ia64/uaccess.h18
-rw-r--r--xen/include/asm-ia64/vcpu.h295
-rw-r--r--xen/include/asm-ia64/vcpumask.h60
-rw-r--r--xen/include/asm-ia64/vhpt.h43
-rw-r--r--xen/include/asm-ia64/vlsapic.h1
-rw-r--r--xen/include/asm-ia64/vmmu.h3
-rw-r--r--xen/include/asm-ia64/vmx.h4
-rw-r--r--xen/include/asm-ia64/vmx_pal_vsa.h7
-rw-r--r--xen/include/asm-ia64/vmx_phy_mode.h9
-rw-r--r--xen/include/asm-ia64/vmx_platform.h12
-rw-r--r--xen/include/asm-ia64/vmx_uaccess.h156
-rw-r--r--xen/include/asm-ia64/vmx_vcpu.h597
-rw-r--r--xen/include/asm-ia64/vmx_vpd.h2
-rw-r--r--xen/include/asm-ia64/vtm.h3
-rw-r--r--xen/include/asm-ia64/xenkregs.h3
-rw-r--r--xen/include/asm-ia64/xenpage.h4
-rw-r--r--xen/include/asm-ia64/xensystem.h1
-rw-r--r--xen/include/asm-powerpc/mm.h8
-rw-r--r--xen/include/asm-powerpc/powerpc64/config.h6
-rw-r--r--xen/include/asm-powerpc/spinlock.h12
-rw-r--r--xen/include/asm-x86/acpi.h4
-rw-r--r--xen/include/asm-x86/apicdef.h1
-rw-r--r--xen/include/asm-x86/bitops.h60
-rw-r--r--xen/include/asm-x86/config.h18
-rw-r--r--xen/include/asm-x86/debugger.h44
-rw-r--r--xen/include/asm-x86/desc.h5
-rw-r--r--xen/include/asm-x86/domain.h30
-rw-r--r--xen/include/asm-x86/flushtlb.h7
-rw-r--r--xen/include/asm-x86/grant_table.h4
-rw-r--r--xen/include/asm-x86/guest_access.h20
-rw-r--r--xen/include/asm-x86/hvm/domain.h21
-rw-r--r--xen/include/asm-x86/hvm/hvm.h92
-rw-r--r--xen/include/asm-x86/hvm/io.h61
-rw-r--r--xen/include/asm-x86/hvm/irq.h107
-rw-r--r--xen/include/asm-x86/hvm/support.h36
-rw-r--r--xen/include/asm-x86/hvm/svm/emulate.h36
-rw-r--r--xen/include/asm-x86/hvm/svm/vmcb.h21
-rw-r--r--xen/include/asm-x86/hvm/vcpu.h10
-rw-r--r--xen/include/asm-x86/hvm/vioapic.h111
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h142
-rw-r--r--xen/include/asm-x86/hvm/vmx/vmcs.h57
-rw-r--r--xen/include/asm-x86/hvm/vmx/vmx.h280
-rw-r--r--xen/include/asm-x86/hvm/vpic.h113
-rw-r--r--xen/include/asm-x86/hvm/vpt.h (renamed from xen/include/asm-x86/hvm/vpit.h)82
-rw-r--r--xen/include/asm-x86/io_apic.h1
-rw-r--r--xen/include/asm-x86/mach-generic/mach_apic.h6
-rw-r--r--xen/include/asm-x86/mm.h154
-rw-r--r--xen/include/asm-x86/msr.h8
-rw-r--r--xen/include/asm-x86/multicall.h2
-rw-r--r--xen/include/asm-x86/numa.h78
-rw-r--r--xen/include/asm-x86/page.h12
-rw-r--r--xen/include/asm-x86/perfc_defn.h9
-rw-r--r--xen/include/asm-x86/processor.h2
-rw-r--r--xen/include/asm-x86/regs.h2
-rw-r--r--xen/include/asm-x86/shadow.h289
-rw-r--r--xen/include/asm-x86/spinlock.h8
-rw-r--r--xen/include/asm-x86/x86_32/page-2level.h3
-rw-r--r--xen/include/asm-x86/x86_32/page-3level.h13
-rw-r--r--xen/include/asm-x86/x86_32/regs.h3
-rw-r--r--xen/include/asm-x86/x86_64/asm_defns.h6
-rw-r--r--xen/include/asm-x86/x86_64/page.h18
-rw-r--r--xen/include/asm-x86/x86_64/regs.h3
-rw-r--r--xen/include/asm-x86/xenoprof.h68
-rw-r--r--xen/include/public/COPYING16
-rw-r--r--xen/include/public/acm.h18
-rw-r--r--xen/include/public/acm_ops.h18
-rw-r--r--xen/include/public/arch-ia64.h109
-rw-r--r--xen/include/public/arch-powerpc.h26
-rw-r--r--xen/include/public/arch-x86_32.h21
-rw-r--r--xen/include/public/arch-x86_64.h27
-rw-r--r--xen/include/public/callback.h18
-rw-r--r--xen/include/public/dom0_ops.h18
-rw-r--r--xen/include/public/domctl.h63
-rw-r--r--xen/include/public/elfnote.h27
-rw-r--r--xen/include/public/event_channel.h18
-rw-r--r--xen/include/public/features.h18
-rw-r--r--xen/include/public/grant_table.h18
-rw-r--r--xen/include/public/hvm/e820.h27
-rw-r--r--xen/include/public/hvm/hvm_info_table.h19
-rw-r--r--xen/include/public/hvm/hvm_op.h53
-rw-r--r--xen/include/public/hvm/ioreq.h52
-rw-r--r--xen/include/public/hvm/params.h42
-rw-r--r--xen/include/public/hvm/vmx_assist.h18
-rw-r--r--xen/include/public/io/blkif.h47
-rw-r--r--xen/include/public/io/console.h18
-rw-r--r--xen/include/public/io/netif.h18
-rw-r--r--xen/include/public/io/pciif.h18
-rw-r--r--xen/include/public/io/ring.h42
-rw-r--r--xen/include/public/io/tpmif.h18
-rw-r--r--xen/include/public/io/xenbus.h18
-rw-r--r--xen/include/public/io/xs_wire.h19
-rw-r--r--xen/include/public/memory.h18
-rw-r--r--xen/include/public/nmi.h18
-rw-r--r--xen/include/public/physdev.h21
-rw-r--r--xen/include/public/platform.h18
-rw-r--r--xen/include/public/sched.h18
-rw-r--r--xen/include/public/sysctl.h18
-rw-r--r--xen/include/public/trace.h31
-rw-r--r--xen/include/public/vcpu.h25
-rw-r--r--xen/include/public/version.h18
-rw-r--r--xen/include/public/xen-compat.h27
-rw-r--r--xen/include/public/xen.h70
-rw-r--r--xen/include/public/xencomm.h32
-rw-r--r--xen/include/public/xenoprof.h22
-rw-r--r--xen/include/xen/compiler.h2
-rw-r--r--xen/include/xen/config.h76
-rw-r--r--xen/include/xen/console.h12
-rw-r--r--xen/include/xen/cpumask.h8
-rw-r--r--xen/include/xen/domain.h16
-rw-r--r--xen/include/xen/event.h7
-rw-r--r--xen/include/xen/gdbstub.h3
-rw-r--r--xen/include/xen/iocap.h8
-rw-r--r--xen/include/xen/keyhandler.h3
-rw-r--r--xen/include/xen/lib.h9
-rw-r--r--xen/include/xen/mm.h7
-rw-r--r--xen/include/xen/nodemask.h338
-rw-r--r--xen/include/xen/numa.h13
-rw-r--r--xen/include/xen/sched-if.h8
-rw-r--r--xen/include/xen/sched.h85
-rw-r--r--xen/include/xen/softirq.h5
-rw-r--r--xen/include/xen/spinlock.h8
-rw-r--r--xen/include/xen/stdarg.h5
-rw-r--r--xen/include/xen/time.h14
-rw-r--r--xen/include/xen/xenoprof.h7
-rw-r--r--xen/tools/figlet/figlet.c5
1085 files changed, 82502 insertions, 39320 deletions
diff --git a/.hgignore b/.hgignore
index c1abfefb4a..a3e3bd2f20 100644
--- a/.hgignore
+++ b/.hgignore
@@ -15,8 +15,11 @@
.*\.rej$
.*/a\.out$
.*/cscope\..*$
+^cscope.*$
^[^/]*\.bz2$
+^\.config$
^TAGS$
+^tags$
^dist/.*$
^docs/.*\.aux$
^docs/.*\.dvi$
@@ -95,7 +98,6 @@
^tools/firmware/.*\.bin$
^tools/firmware/.*\.sym$
^tools/firmware/.*bios/.*bios.*\.txt$
-^tools/firmware/acpi/acpigen$
^tools/firmware/hvmloader/hvmloader$
^tools/firmware/hvmloader/roms\.h$
^tools/firmware/rombios/BIOS-bochs-[^/]*$
@@ -120,6 +122,7 @@
^tools/ioemu/qemu\.1$
^tools/ioemu/qemu\.pod$
^tools/libxc/xen/.*$
+^tools/libxen/test/test_bindings$
^tools/libaio/src/.*\.ol$
^tools/libaio/src/.*\.os$
^tools/misc/cpuperf/cpuperf-perfcntr$
@@ -139,12 +142,15 @@
^tools/security/secpol_tool$
^tools/security/xen/.*$
^tools/tests/test_x86_emulator$
+^tools/vnet/Make.local$
+^tools/vnet/build/.*$
^tools/vnet/gc$
^tools/vnet/gc.*/.*$
^tools/vnet/vnet-module/.*\.ko$
^tools/vnet/vnet-module/\..*\.cmd$
^tools/vnet/vnet-module/\.tmp_versions/.*$
^tools/vnet/vnet-module/vnet_module\.mod\..*$
+^tools/vnet/vnetd/vnetd$
^tools/vtpm/tpm_emulator-.*\.tar\.gz$
^tools/vtpm/tpm_emulator/.*$
^tools/vtpm/vtpm/.*$
@@ -178,6 +184,17 @@
^tools/xentrace/xenctx$
^tools/xentrace/xentrace$
^tools/xm-test/ramdisk/buildroot
+^tools/xm-test/aclocal.m4$
+^tools/xm-test/autom4te
+^tools/xm-test/install-sh$
+^tools/xm-test/mkinstalldirs$
+^tools/xm-test/missing$
+^tools/xm-test/config(ure|.log|.status|.guess|.sub)$
+^tools/xm-test/Makefile(.in)*$
+^tools/xm-test/.*/Makefile(.in)*$
+^tools/xm-test/lib/XmTestLib/config.py$
+^tools/xm-test/lib/XmTestReport/xmtest.py$
+^tools/xm-test/tests/.*\.test$
^xen/BLOG$
^xen/TAGS$
^xen/arch/x86/asm-offsets\.s$
diff --git a/.hgtags b/.hgtags
index b097c216b9..43265aa8dc 100644
--- a/.hgtags
+++ b/.hgtags
@@ -15,3 +15,4 @@ fb875591fd72e15c31879c0e9034d99b80225595 RELEASE-2.0.4
c8fdb0caa77b429cf47f9707926e83947778cb48 RELEASE-3.0.0
af0573e9e5258db0a9d28aa954dd302ddd2c2d23 3.0.2-rc
d0d3fef37685be264a7f52201f8ef44c030daad3 3.0.2-branched
+6ed4368b4a9e1924c983774c4b1a2b6baf8e98a6 3.0.3-branched
diff --git a/Config.mk b/Config.mk
index 74bd8ec80c..4cd113d905 100644
--- a/Config.mk
+++ b/Config.mk
@@ -4,43 +4,21 @@
debug ?= n
XEN_COMPILE_ARCH ?= $(shell uname -m | sed -e s/i.86/x86_32/ \
- -e s/ppc/powerpc/)
+ -e s/ppc/powerpc/ -e s/i86pc/x86_32/)
XEN_TARGET_ARCH ?= $(XEN_COMPILE_ARCH)
XEN_TARGET_X86_PAE ?= n
+XEN_OS ?= $(shell uname -s)
+
+CONFIG_$(XEN_OS) := y
# Tools to run on system hosting the build
HOSTCC = gcc
HOSTCFLAGS = -Wall -Werror -Wstrict-prototypes -O2 -fomit-frame-pointer
-AS = $(CROSS_COMPILE)as
-LD = $(CROSS_COMPILE)ld
-CC = $(CROSS_COMPILE)gcc
-CPP = $(CROSS_COMPILE)gcc -E
-AR = $(CROSS_COMPILE)ar
-RANLIB = $(CROSS_COMPILE)ranlib
-NM = $(CROSS_COMPILE)nm
-STRIP = $(CROSS_COMPILE)strip
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
-
DISTDIR ?= $(XEN_ROOT)/dist
DESTDIR ?= /
-INSTALL = install
-INSTALL_DIR = $(INSTALL) -d -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-INSTALL_PROG = $(INSTALL) -m0755
-
-ifneq ($(debug),y)
-# Optimisation flags are overridable
-CFLAGS ?= -O2 -fomit-frame-pointer
-CFLAGS += -DNDEBUG
-else
-# Less than -O1 produces bad code and large stack frames
-CFLAGS ?= -O1 -fno-omit-frame-pointer
-CFLAGS += -g
-endif
-
+include $(XEN_ROOT)/config/$(XEN_OS).mk
include $(XEN_ROOT)/config/$(XEN_TARGET_ARCH).mk
ifneq ($(EXTRA_PREFIX),)
@@ -48,19 +26,31 @@ EXTRA_INCLUDES += $(EXTRA_PREFIX)/include
EXTRA_LIB += $(EXTRA_PREFIX)/$(LIBDIR)
endif
-test-gcc-flag = $(shell $(1) -v --help 2>&1 | grep -q " $(2) " && echo $(2))
+# cc-option
+# Usage: cflags-y += $(call cc-option,$(CC),-march=winchip-c6,-march=i586)
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
+ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+ifneq ($(debug),y)
+CFLAGS += -DNDEBUG
+else
+CFLAGS += -g
+endif
+
+CFLAGS += -std=gnu99
CFLAGS += -Wall -Wstrict-prototypes
-HOSTCFLAGS += $(call test-gcc-flag,$(HOSTCC),-Wdeclaration-after-statement)
-CFLAGS += $(call test-gcc-flag,$(CC),-Wdeclaration-after-statement)
+# -Wunused-value makes GCC 4.x too aggressive for my taste: ignoring the
+# result of any casted expression causes a warning.
+CFLAGS += -Wno-unused-value
+
+HOSTCFLAGS += $(call cc-option,$(HOSTCC),-Wdeclaration-after-statement,)
+CFLAGS += $(call cc-option,$(CC),-Wdeclaration-after-statement,)
LDFLAGS += $(foreach i, $(EXTRA_LIB), -L$(i))
CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i))
-# Choose the best mirror to download linux kernel
-KERNEL_REPO = http://www.kernel.org
-
# If ACM_SECURITY = y, then the access control module is compiled
# into Xen and the policy type can be set by the boot policy file
# y - Build the Xen ACM framework
diff --git a/Makefile b/Makefile
index 186b756765..c7004c0ae2 100644
--- a/Makefile
+++ b/Makefile
@@ -2,11 +2,6 @@
# Grand Unified Makefile for Xen.
#
-KERNELS ?= linux-2.6-xen
-# You may use wildcards in the above e.g. KERNELS=*2.6*
-
-XKERNELS := $(foreach kernel, $(KERNELS), $(patsubst buildconfigs/mk.%,%,$(wildcard buildconfigs/mk.$(kernel))) )
-
# Export target architecture overrides to Xen and Linux sub-trees.
ifneq ($(XEN_TARGET_ARCH),)
SUBARCH := $(subst x86_32,i386,$(XEN_TARGET_ARCH))
diff --git a/buildconfigs/Rules.mk b/buildconfigs/Rules.mk
index 6eca30ef0a..ae61ea0095 100644
--- a/buildconfigs/Rules.mk
+++ b/buildconfigs/Rules.mk
@@ -3,6 +3,9 @@ include Config.mk
export DESTDIR
+# Choose the best mirror to download linux kernel
+KERNEL_REPO = http://www.kernel.org
+
ALLKERNELS = $(patsubst buildconfigs/mk.%,%,$(wildcard buildconfigs/mk.*))
ALLSPARSETREES = $(patsubst %-xen-sparse,%,$(wildcard *-xen-sparse))
diff --git a/buildconfigs/linux-defconfig_xen0_ia64 b/buildconfigs/linux-defconfig_xen0_ia64
index 24ce34546a..612bcfd42d 100644
--- a/buildconfigs/linux-defconfig_xen0_ia64
+++ b/buildconfigs/linux-defconfig_xen0_ia64
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16.13-xen0
-# Fri Sep 1 11:03:26 2006
+# Linux kernel version: 2.6.16.29-xen0
+# Tue Nov 14 10:39:09 2006
#
#
@@ -92,6 +92,8 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
+CONFIG_XEN_IA64_EXPOSE_P2M=y
+CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -119,6 +121,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_SMP=y
CONFIG_NR_CPUS=16
CONFIG_HOTPLUG_CPU=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_SCHED_SMT is not set
# CONFIG_PREEMPT is not set
CONFIG_SELECT_MEMORY_MODEL=y
@@ -336,13 +339,14 @@ CONFIG_FW_LOADER=y
# Block devices
#
# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
+CONFIG_BLK_CPQ_CISS_DA=y
+# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
-CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_NBD=m
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
@@ -1040,7 +1044,7 @@ CONFIG_SND_ATIIXP=y
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
CONFIG_SND_FM801=y
-CONFIG_SND_FM801_TEA575X=y
+# CONFIG_SND_FM801_TEA575X_BOOL is not set
# CONFIG_SND_HDA_INTEL is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
@@ -1526,7 +1530,7 @@ CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
-# CONFIG_XEN_BLKDEV_TAP is not set
+CONFIG_XEN_BLKDEV_TAP=y
CONFIG_XEN_NETDEV_BACKEND=y
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_NETDEV_LOOPBACK=y
diff --git a/buildconfigs/linux-defconfig_xenU_ia64 b/buildconfigs/linux-defconfig_xenU_ia64
index dd0e4e29b6..a7e15190ee 100644
--- a/buildconfigs/linux-defconfig_xenU_ia64
+++ b/buildconfigs/linux-defconfig_xenU_ia64
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16.13-xenU
-# Fri Sep 1 10:50:54 2006
+# Linux kernel version: 2.6.16.29-xenU
+# Wed Oct 4 12:54:26 2006
#
#
@@ -89,6 +89,8 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
+CONFIG_XEN_IA64_EXPOSE_P2M=y
+CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -116,6 +118,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_SMP=y
CONFIG_NR_CPUS=16
# CONFIG_HOTPLUG_CPU is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_SCHED_SMT is not set
# CONFIG_PREEMPT is not set
CONFIG_SELECT_MEMORY_MODEL=y
@@ -939,7 +942,7 @@ CONFIG_SND_AC97_BUS=y
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
CONFIG_SND_FM801=y
-CONFIG_SND_FM801_TEA575X=y
+# CONFIG_SND_FM801_TEA575X_BOOL is not set
# CONFIG_SND_HDA_INTEL is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64
index 2928e8a5c8..1bdc8edb4c 100644
--- a/buildconfigs/linux-defconfig_xen_ia64
+++ b/buildconfigs/linux-defconfig_xen_ia64
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16.13-xen
-# Fri Sep 1 10:58:55 2006
+# Linux kernel version: 2.6.16.29-xen
+# Tue Nov 14 10:38:50 2006
#
#
@@ -92,6 +92,8 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_XEN=y
CONFIG_XEN_IA64_VDSO_PARAVIRT=y
+CONFIG_XEN_IA64_EXPOSE_P2M=y
+CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_IS_DMA32=y
# CONFIG_IA64_GENERIC is not set
@@ -119,6 +121,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11
CONFIG_SMP=y
CONFIG_NR_CPUS=16
CONFIG_HOTPLUG_CPU=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
# CONFIG_SCHED_SMT is not set
# CONFIG_PREEMPT is not set
CONFIG_SELECT_MEMORY_MODEL=y
@@ -336,13 +339,14 @@ CONFIG_FW_LOADER=y
# Block devices
#
# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
+CONFIG_BLK_CPQ_CISS_DA=y
+# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
-CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_NBD=m
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
@@ -1046,7 +1050,7 @@ CONFIG_SND_ATIIXP=y
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
CONFIG_SND_FM801=y
-CONFIG_SND_FM801_TEA575X=y
+# CONFIG_SND_FM801_TEA575X_BOOL is not set
# CONFIG_SND_HDA_INTEL is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
@@ -1532,7 +1536,7 @@ CONFIG_XEN_PRIVCMD=y
CONFIG_XEN_XENBUS_DEV=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_BLKDEV_BACKEND=y
-# CONFIG_XEN_BLKDEV_TAP is not set
+CONFIG_XEN_BLKDEV_TAP=y
CONFIG_XEN_NETDEV_BACKEND=y
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
CONFIG_XEN_NETDEV_LOOPBACK=y
diff --git a/buildconfigs/linux-defconfig_xen_x86_32 b/buildconfigs/linux-defconfig_xen_x86_32
index 5c7e66550b..0dee9d8734 100644
--- a/buildconfigs/linux-defconfig_xen_x86_32
+++ b/buildconfigs/linux-defconfig_xen_x86_32
@@ -2377,6 +2377,7 @@ CONFIG_SND_ENS1371=m
CONFIG_SND_ES1938=m
CONFIG_SND_ES1968=m
CONFIG_SND_FM801=m
+# CONFIG_SND_FM801_TEA575X_BOOL is not set
CONFIG_SND_FM801_TEA575X=m
CONFIG_SND_HDA_INTEL=m
CONFIG_SND_HDSP=m
diff --git a/buildconfigs/linux-defconfig_xen_x86_64 b/buildconfigs/linux-defconfig_xen_x86_64
index 019531708b..3f9599adb0 100644
--- a/buildconfigs/linux-defconfig_xen_x86_64
+++ b/buildconfigs/linux-defconfig_xen_x86_64
@@ -2237,6 +2237,7 @@ CONFIG_SND_ENS1371=m
CONFIG_SND_ES1938=m
CONFIG_SND_ES1968=m
CONFIG_SND_FM801=m
+# CONFIG_SND_FM801_TEA575X_BOOL is not set
CONFIG_SND_FM801_TEA575X=m
CONFIG_SND_HDA_INTEL=m
CONFIG_SND_HDSP=m
diff --git a/buildconfigs/mk.linux-2.6-xen b/buildconfigs/mk.linux-2.6-xen
index 8c52deca0c..72bd77ed89 100644
--- a/buildconfigs/mk.linux-2.6-xen
+++ b/buildconfigs/mk.linux-2.6-xen
@@ -1,5 +1,5 @@
LINUX_SERIES = 2.6
-LINUX_VER = 2.6.16.13
+LINUX_VER = 2.6.16.32
EXTRAVERSION ?= xen
diff --git a/config/Linux.mk b/config/Linux.mk
new file mode 100644
index 0000000000..52c2227996
--- /dev/null
+++ b/config/Linux.mk
@@ -0,0 +1,8 @@
+include $(XEN_ROOT)/config/StdGNU.mk
+
+# You may use wildcards, e.g. KERNELS=*2.6*
+KERNELS ?= linux-2.6-xen
+
+XKERNELS := $(foreach kernel, $(KERNELS), \
+ $(patsubst buildconfigs/mk.%,%, \
+ $(wildcard buildconfigs/mk.$(kernel))) )
diff --git a/config/OpenBSD.mk b/config/OpenBSD.mk
new file mode 100644
index 0000000000..b421a1c840
--- /dev/null
+++ b/config/OpenBSD.mk
@@ -0,0 +1 @@
+include $(XEN_ROOT)/config/StdGNU.mk
diff --git a/config/StdGNU.mk b/config/StdGNU.mk
new file mode 100644
index 0000000000..2b767517b8
--- /dev/null
+++ b/config/StdGNU.mk
@@ -0,0 +1,30 @@
+AS = $(CROSS_COMPILE)as
+LD = $(CROSS_COMPILE)ld
+CC = $(CROSS_COMPILE)gcc
+CPP = $(CROSS_COMPILE)gcc -E
+AR = $(CROSS_COMPILE)ar
+RANLIB = $(CROSS_COMPILE)ranlib
+NM = $(CROSS_COMPILE)nm
+STRIP = $(CROSS_COMPILE)strip
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJDUMP = $(CROSS_COMPILE)objdump
+
+INSTALL = install
+INSTALL_DIR = $(INSTALL) -d -m0755
+INSTALL_DATA = $(INSTALL) -m0644
+INSTALL_PROG = $(INSTALL) -m0755
+
+LIB64DIR = lib64
+
+SOCKET_LIBS =
+CURSES_LIBS = -lncurses
+SONAME_LDFLAG = -soname
+SHLIB_CFLAGS = -shared
+
+ifneq ($(debug),y)
+# Optimisation flags are overridable
+CFLAGS ?= -O2 -fomit-frame-pointer
+else
+# Less than -O1 produces bad code and large stack frames
+CFLAGS ?= -O1 -fno-omit-frame-pointer
+endif
diff --git a/config/SunOS.mk b/config/SunOS.mk
new file mode 100644
index 0000000000..5d548054d3
--- /dev/null
+++ b/config/SunOS.mk
@@ -0,0 +1,35 @@
+AS = $(CROSS_COMPILE)gas
+LD = $(CROSS_COMPILE)gld
+CC = $(CROSS_COMPILE)gcc
+CPP = $(CROSS_COMPILE)gcc -E
+AR = $(CROSS_COMPILE)gar
+RANLIB = $(CROSS_COMPILE)granlib
+NM = $(CROSS_COMPILE)gnm
+STRIP = $(CROSS_COMPILE)gstrip
+OBJCOPY = $(CROSS_COMPILE)gobjcopy
+OBJDUMP = $(CROSS_COMPILE)gobjdump
+
+SHELL = bash
+
+INSTALL = ginstall
+INSTALL_DIR = $(INSTALL) -d -m0755
+INSTALL_DATA = $(INSTALL) -m0644
+INSTALL_PROG = $(INSTALL) -m0755
+
+LIB64DIR = lib/amd64
+
+SOCKET_LIBS = -lsocket
+CURSES_LIBS = -lcurses
+SONAME_LDFLAG = -h
+SHLIB_CFLAGS = -R /usr/sfw/$(LIBDIR) -shared
+
+ifneq ($(debug),y)
+# Optimisation flags are overridable
+CFLAGS ?= -O2 -fno-omit-frame-pointer
+else
+# Less than -O1 produces bad code and large stack frames
+CFLAGS ?= -O1 -fno-omit-frame-pointer
+endif
+
+CFLAGS += -Wa,--divide -D_POSIX_C_SOURCE=200112L -D__EXTENSIONS__
+
diff --git a/config/ia64.mk b/config/ia64.mk
index 4fab1118be..7cf99d9b69 100644
--- a/config/ia64.mk
+++ b/config/ia64.mk
@@ -1,4 +1,6 @@
CONFIG_IA64 := y
+CONFIG_IA64_$(XEN_OS) := y
+
CONFIG_IOEMU := y
CONFIG_XCUTILS := y
diff --git a/config/powerpc64.mk b/config/powerpc64.mk
index ee717ecd64..9773b24a6c 100644
--- a/config/powerpc64.mk
+++ b/config/powerpc64.mk
@@ -1,4 +1,5 @@
CONFIG_POWERPC := y
+CONFIG_POWERPC_$(XEN_OS) := y
CFLAGS += -DELFSIZE=64
LIBDIR := lib
diff --git a/config/x86_32.mk b/config/x86_32.mk
index 2d460a720a..4a0490afa8 100644
--- a/config/x86_32.mk
+++ b/config/x86_32.mk
@@ -1,9 +1,17 @@
CONFIG_X86 := y
+CONFIG_X86_$(XEN_OS) := y
+
CONFIG_HVM := y
CONFIG_MIGRATE := y
CONFIG_XCUTILS := y
CONFIG_IOEMU := y
-CONFIG_MBOOTPACK := y
CFLAGS += -m32 -march=i686
LIBDIR := lib
+
+# Use only if calling $(LD) directly.
+ifeq ($(XEN_OS),OpenBSD)
+LDFLAGS_DIRECT += -melf_i386_obsd
+else
+LDFLAGS_DIRECT += -melf_i386
+endif
diff --git a/config/x86_64.mk b/config/x86_64.mk
index bd43c04a6c..e85b37ff91 100644
--- a/config/x86_64.mk
+++ b/config/x86_64.mk
@@ -1,9 +1,17 @@
CONFIG_X86 := y
+CONFIG_X86_$(XEN_OS) := y
+
CONFIG_HVM := y
CONFIG_MIGRATE := y
CONFIG_XCUTILS := y
CONFIG_IOEMU := y
-CONFIG_MBOOTPACK := y
CFLAGS += -m64
-LIBDIR = lib64
+LIBDIR = $(LIB64DIR)
+
+# Use only if calling $(LD) directly.
+ifeq ($(XEN_OS),OpenBSD)
+LDFLAGS_DIRECT += -melf_x86_64_obsd
+else
+LDFLAGS_DIRECT += -melf_x86_64
+endif
diff --git a/docs/Makefile b/docs/Makefile
index 59e9fa69d7..0432855384 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,8 +1,9 @@
#!/usr/bin/make -f
+XEN_ROOT=..
+include $(XEN_ROOT)/Config.mk
+
VERSION = xen-unstable
-INSTALL = install
-INSTALL_DIR = $(INSTALL) -d -m0755
PS2PDF := ps2pdf
DVIPS := dvips
diff --git a/docs/man/xm.pod.1 b/docs/man/xm.pod.1
index 352eefd158..b0ba7f8fb2 100644
--- a/docs/man/xm.pod.1
+++ b/docs/man/xm.pod.1
@@ -393,7 +393,9 @@ specified, VCPU information for all domains will be provided.
=item B<vcpu-pin> I<domain-id> I<vcpu> I<cpus>
-Pins the the VCPU to only run on the specific CPUs.
+Pins the the VCPU to only run on the specific CPUs. The keyword
+I<all> can be used to apply the I<cpus> list to all VCPUs in the
+domain.
Normally VCPUs can float between available CPUs whenever Xen deems a
different run state is appropriate. Pinning can be used to restrict
@@ -808,13 +810,13 @@ global policy root directory.
Loads the binary representation of the I<policy> into Xen. The binary
representation can be created with the B<makepolicy> subcommand.
-=item B<cfgbootpolicy> I<policy> [I<kernelversion>]
+=item B<cfgbootpolicy> I<policy> [I<boot title>]
Configures I<policy> as the boot policy for Xen. It copies the binary
policy representation into the /boot directory and adds a module line
specifying the binary policy to the /boot/grub/menu.lst file. If your
boot configuration includes multiple Xen boot titles, then use the
-I<kernelversion> parameter to select the proper title.
+I<boot title> parameter to specify a unique part of the proper title.
=item B<dumppolicy>
diff --git a/docs/src/interface.tex b/docs/src/interface.tex
index 9a598406a1..a77d4e81c2 100644
--- a/docs/src/interface.tex
+++ b/docs/src/interface.tex
@@ -955,7 +955,6 @@ This information doesn't change and is indexed by the domain's UUID.
A {\bf /vm} entry contains the following information:
\begin{description}
-\item[ssidref] ssid reference for domain
\item[uuid] uuid of the domain (somewhat redundant)
\item[on\_reboot] the action to take on a domain reboot request (destroy or restart)
\item[on\_poweroff] the action to take on a domain halt request (destroy or restart)
@@ -1125,6 +1124,16 @@ This path contains:
\end{description}
\end{description}
+ \item[security/] access control information for the domain
+ \begin{description}
+ \item[ssidref] security reference identifier used inside the hypervisor
+ \item[access\_control/] security label used by management tools
+ \begin{description}
+ \item[label] security label name
+ \item[policy] security policy name
+ \end{description}
+ \end{description}
+
\item[store/] per-domain information for the store
\begin{description}
\item[port] the event channel used for the store ring queue
@@ -2168,19 +2177,46 @@ Most of the above are best understood by looking at the code
implementing them (in {\tt xen/common/dom0\_ops.c}) and in
the user-space tools that use them (mostly in {\tt tools/libxc}).
+\section{Access Control Module Hypercalls}
+\label{s:acmops}
+
Hypercalls relating to the management of the Access Control Module are
-also restricted to domain 0 access for now:
+also restricted to domain 0 access for now. For more details on any or
+all of these, please see {\tt xen/include/public/acm\_ops.h}. A
+complete list is given below:
\begin{quote}
-\hypercall{acm\_op(struct acm\_op * u\_acm\_op)}
+\hypercall{acm\_op(int cmd, void *args)}
This hypercall can be used to configure the state of the ACM, query
that state, request access control decisions and dump additional
information.
+\begin{description}
+
+\item [ACMOP\_SETPOLICY:] set the access control policy
+
+\item [ACMOP\_GETPOLICY:] get the current access control policy and
+ status
+
+\item [ACMOP\_DUMPSTATS:] get current access control hook invocation
+ statistics
+
+\item [ACMOP\_GETSSID:] get security access control information for a
+ domain
+
+\item [ACMOP\_GETDECISION:] get access decision based on the currently
+ enforced access control policy
+
+\end{description}
\end{quote}
+Most of the above are best understood by looking at the code
+implementing them (in {\tt xen/common/acm\_ops.c}) and in the
+user-space tools that use them (mostly in {\tt tools/security} and
+{\tt tools/python/xen/lowlevel/acm}).
+
\section{Debugging Hypercalls}
diff --git a/docs/src/user.tex b/docs/src/user.tex
index 52c2d746b2..2528861a23 100644
--- a/docs/src/user.tex
+++ b/docs/src/user.tex
@@ -3192,6 +3192,15 @@ editing \path{grub.conf}.
input to DOM0 when it boots --- if it is `x' then auto-switching is
disabled. Any other value, or omitting the character, enables
auto-switching. [NB. Default switch-char is `a'.]
+\item [ loglvl=$<$level$>/<$level$>$ ]
+ Specify logging level. Messages of the specified severity level (and
+ higher) will be printed to the Xen console. Valid levels are `none',
+ `error', `warning', `info', `debug', and `all'. The second level
+ specifier is optional: it is used to specify message severities
+ which are to be rate limited. Default is `loglvl=warning'.
+\item [ guest\_loglvl=$<$level$>/<$level$>$ ] As for loglvl, but
+ applies to messages relating to guests. Default is
+ `guest\_loglvl=none/warning'.
\item [ nmi=xxx ]
Specify what to do with an NMI parity or I/O error. \\
`nmi=fatal': Xen prints a diagnostic and then hangs. \\
@@ -3202,12 +3211,23 @@ editing \path{grub.conf}.
ignored. This parameter may be specified with a B, K, M or G suffix,
representing bytes, kilobytes, megabytes and gigabytes respectively.
The default unit, if no suffix is specified, is kilobytes.
-\item [ dom0\_mem=xxx ] Set the amount of memory to be allocated to
- domain0. In Xen 3.x the parameter may be specified with a B, K, M or
+\item [ dom0\_mem=$<$specifier list$>$ ] Set the amount of memory to
+ be allocated to domain 0. This is a comma-separated list containing
+ the following optional components:
+ \begin{description}
+ \item[ min:$<$min\_amt$>$ ] Minimum amount to allocate to domain 0
+ \item[ max:$<$min\_amt$>$ ] Maximum amount to allocate to domain 0
+ \item[ $<$amt$>$ ] Precise amount to allocate to domain 0
+ \end{description}
+ Each numeric parameter may be specified with a B, K, M or
G suffix, representing bytes, kilobytes, megabytes and gigabytes
respectively; if no suffix is specified, the parameter defaults to
- kilobytes. In previous versions of Xen, suffixes were not supported
- and the value is always interpreted as kilobytes.
+ kilobytes. Negative values are subtracted from total available
+ memory. If $<$amt$>$ is not specified, it defaults to all available
+ memory less a small amount (clamped to 128MB) for uses such as DMA
+ buffers.
+\item [ dom0\_vcpus\_pin ] Pins domain 0 VCPUs on their respective
+ physical CPUS (default=false).
\item [ tbuf\_size=xxx ] Set the size of the per-cpu trace buffers, in
pages (default 0).
\item [ sched=xxx ] Select the CPU scheduler Xen should use. The
diff --git a/docs/xen-api/Makefile b/docs/xen-api/Makefile
new file mode 100644
index 0000000000..7dfb1bfbec
--- /dev/null
+++ b/docs/xen-api/Makefile
@@ -0,0 +1,23 @@
+TEX := $(wildcard *.tex)
+EPS := $(wildcard *.eps)
+EPSDOT := $(patsubst %.dot,%.eps,$(wildcard *.dot))
+
+.PHONY: all
+all: xenapi.pdf xenapi.ps
+
+xenapi.dvi: $(TEX) $(EPS) $(EPSDOT)
+ latex xenapi.tex
+ latex xenapi.tex
+
+%.pdf: %.ps
+ ps2pdf $< $@
+
+%.ps: %.dvi
+ dvips $< -o $@
+
+%.eps: %.dot
+ dot -Tps $< >$@
+
+.PHONY: clean
+clean:
+ rm -f *.pdf *.ps *.dvi *.aux *.log $(EPSDOT)
diff --git a/docs/xen-api/coversheet.tex b/docs/xen-api/coversheet.tex
new file mode 100644
index 0000000000..cd0ad615d6
--- /dev/null
+++ b/docs/xen-api/coversheet.tex
@@ -0,0 +1,50 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\pagestyle{empty}
+
+\doctitle{} \hfill \revstring{}
+
+\vspace{1cm}
+
+\begin{center}
+\resizebox{8cm}{!}{\includegraphics{\coversheetlogo}}
+
+\vspace{3cm}
+
+\begin{Huge}
+ \doctitle{}
+\end{Huge}
+
+\vspace{1cm}
+\begin{Large}
+Version: \revstring{}\\
+Date: \datestring{}
+\\
+\releasestatement{}
+
+\vspace{1cm}
+\begin{tabular}{rl}
+\docauthors{}
+\end{tabular}
+
+\end{Large}
+\end{center}
+
+\vfill
+
+\noindent
+\legalnotice{}
+
+\newpage
+\pagestyle{plain} \ No newline at end of file
diff --git a/docs/xen-api/fdl.tex b/docs/xen-api/fdl.tex
new file mode 100644
index 0000000000..d8214575b3
--- /dev/null
+++ b/docs/xen-api/fdl.tex
@@ -0,0 +1,488 @@
+\chapter{GNU Free Documentation License}
+%\label{label_fdl}
+
+ \begin{center}
+
+ Version 1.2, November 2002
+
+
+ Copyright \copyright 2000,2001,2002 Free Software Foundation, Inc.
+
+ \bigskip
+
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ \bigskip
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+\end{center}
+
+
+\begin{center}
+{\bf\large Preamble}
+\end{center}
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+\begin{center}
+{\Large\bf 1. APPLICABILITY AND DEFINITIONS}
+\addcontentsline{toc}{section}{1. APPLICABILITY AND DEFINITIONS}
+\end{center}
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The \textbf{"Document"}, below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as \textbf{"you"}. You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A \textbf{"Modified Version"} of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A \textbf{"Secondary Section"} is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The \textbf{"Invariant Sections"} are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The \textbf{"Cover Texts"} are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A \textbf{"Transparent"} copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called \textbf{"Opaque"}.
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The \textbf{"Title Page"} means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section \textbf{"Entitled XYZ"} means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as \textbf{"Acknowledgements"},
+\textbf{"Dedications"}, \textbf{"Endorsements"}, or \textbf{"History"}.)
+To \textbf{"Preserve the Title"}
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+\begin{center}
+{\Large\bf 2. VERBATIM COPYING}
+\addcontentsline{toc}{section}{2. VERBATIM COPYING}
+\end{center}
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+\begin{center}
+{\Large\bf 3. COPYING IN QUANTITY}
+\addcontentsline{toc}{section}{3. COPYING IN QUANTITY}
+\end{center}
+
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+\begin{center}
+{\Large\bf 4. MODIFICATIONS}
+\addcontentsline{toc}{section}{4. MODIFICATIONS}
+\end{center}
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+\begin{itemize}
+\item[A.]
+ Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+
+\item[B.]
+ List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+
+\item[C.]
+ State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+
+\item[D.]
+ Preserve all the copyright notices of the Document.
+
+\item[E.]
+ Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+
+\item[F.]
+ Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+
+\item[G.]
+ Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+
+\item[H.]
+ Include an unaltered copy of this License.
+
+\item[I.]
+ Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+
+\item[J.]
+ Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+
+\item[K.]
+ For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+
+\item[L.]
+ Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+
+\item[M.]
+ Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+
+\item[N.]
+ Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+
+\item[O.]
+ Preserve any Warranty Disclaimers.
+\end{itemize}
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+\begin{center}
+{\Large\bf 5. COMBINING DOCUMENTS}
+\addcontentsline{toc}{section}{5. COMBINING DOCUMENTS}
+\end{center}
+
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+\begin{center}
+{\Large\bf 6. COLLECTIONS OF DOCUMENTS}
+\addcontentsline{toc}{section}{6. COLLECTIONS OF DOCUMENTS}
+\end{center}
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+\begin{center}
+{\Large\bf 7. AGGREGATION WITH INDEPENDENT WORKS}
+\addcontentsline{toc}{section}{7. AGGREGATION WITH INDEPENDENT WORKS}
+\end{center}
+
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+\begin{center}
+{\Large\bf 8. TRANSLATION}
+\addcontentsline{toc}{section}{8. TRANSLATION}
+\end{center}
+
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+\begin{center}
+{\Large\bf 9. TERMINATION}
+\addcontentsline{toc}{section}{9. TERMINATION}
+\end{center}
+
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+\begin{center}
+{\Large\bf 10. FUTURE REVISIONS OF THIS LICENSE}
+\addcontentsline{toc}{section}{10. FUTURE REVISIONS OF THIS LICENSE}
+\end{center}
+
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+\begin{center}
+{\Large\bf ADDENDUM: How to use this License for your documents}
+\addcontentsline{toc}{section}{ADDENDUM: How to use this License for your documents}
+\end{center}
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+\bigskip
+\begin{quote}
+ Copyright \copyright YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+\end{quote}
+\bigskip
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+\bigskip
+\begin{quote}
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+\end{quote}
+\bigskip
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/docs/xen-api/presentation.tex b/docs/xen-api/presentation.tex
new file mode 100644
index 0000000000..0072704646
--- /dev/null
+++ b/docs/xen-api/presentation.tex
@@ -0,0 +1,149 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+The API is presented here as a set of Remote Procedure Calls, with a wire
+format based upon XML-RPC. No specific language bindings are prescribed,
+although examples will be given in the python programming language.
+
+Although we adopt some terminology from object-oriented programming,
+future client language bindings may or may not be object oriented.
+The API reference uses the terminology {\em classes\/} and {\em objects\/}.
+For our purposes a {\em class\/} is simply a hierarchical namespace;
+an {\em object\/} is an instance of a class with its fields set to
+specific values. Objects are persistent and exist on the server-side.
+Clients may obtain opaque references to these server-side objects and then
+access their fields via get/set RPCs.
+
+%In each class there is a $\mathit{uid}$ field that assigns an indentifier
+%to each object. This $\mathit{uid}$ serves as an object reference
+%on both client- and server-side, and is often included as an argument in
+%RPC messages.
+
+For each class we specify a list of
+fields along with their {\em types\/} and {\em qualifiers\/}. A
+qualifier is one of:
+\begin{itemize}
+ \item $\mathit{RO}_\mathit{run}$: the field is Read
+Only. Furthermore, its value is automatically computed at runtime.
+For example: current CPU load and disk IO throughput.
+ \item $\mathit{RO}_\mathit{ins}$: the field must be manually set
+when a new object is created, but is then Read Only for
+the duration of the object's life.
+For example, the maximum memory addressable by a guest is set
+before the guest boots.
+ \item $\mathit{RW}$: the field is Read/Write. For example, the name
+of a VM.
+\end{itemize}
+
+A full list of types is given in Chapter~\ref{api-reference}. However,
+there are three types that require explicit mention:
+\begin{itemize}
+ \item $t~\mathit{Ref}$: signifies a reference to an object
+of type $t$.
+ \item $t~\mathit{Set}$: signifies a set containing
+values of type $t$.
+ \item $(t_1, t_2)~\mathit{Map}$: signifies a mapping from values of
+type $t_1$ to values of type $t_2$.
+\end{itemize}
+
+Note that there are a number of cases where {\em Ref}s are {\em doubly
+linked\/}---e.g.\ a VM has a field called {\tt groups} of type
+$(\mathit{VMGroup}~\mathit{Ref})~\mathit{Set}$; this field lists
+the VMGroups that a particular VM is part of. Similarly, the VMGroups
+class has a field called {\tt VMs} of type $(\mathit{VM}~{\mathit
+Ref})~\mathit{Set}$ that contains the VMs that are part of a particular
+VMGroup. These two fields are {\em bound together\/}, in the sense that
+adding a new VMGroup to a VM causes the VMs field of the corresponding
+VMGroup object to be updated automatically.
+
+The API reference explicitly lists the fields that are
+bound together in this way. It also contains a diagram that shows
+relationships between classes. In this diagram an edge signifies the
+existance of a pair of fields that are bound together, using standard
+crows-foot notation to signify the type of relationship (e.g.\
+one-many, many-many).
+
+\section{RPCs associated with fields}
+
+Each field, {\tt f}, has an RPC accessor associated with it
+that returns {\tt f}'s value:
+\begin{itemize}
+\item ``{\tt get\_f(Ref x)}'': takes a
+{\tt Ref} that refers to an object and returns the value of {\tt f}.
+\end{itemize}
+
+Each field, {\tt f}, with attribute
+{\em RW} and whose outermost type is {\em Set\/} has the following
+additional RPCs associated with it:
+\begin{itemize}
+\item an ``{\tt add\_to\_f(Ref x, v)}'' RPC adds a new element v to the set\footnote{
+%
+Since sets cannot contain duplicate values this operation has no action in the case
+that {\tt v} was already in the set.
+%
+};
+\item a ``{\tt remove\_from\_f(Ref x, v)}'' RPC removes element {\tt v} from the set;
+\end{itemize}
+
+Each field, {\tt f}, with attribute
+{\em RW} and whose outermost type is {\em Map\/} has the following
+additional RPCs associated with it:
+\begin{itemize}
+\item an ``{\tt add\_to\_f(Ref x, k, v)}'' RPC adds new pair {\tt (k, v)}
+to the mapping stored in {\tt f} in object {\tt x}. Adding a new pair for duplicate
+key, {\tt k}, overwrites any previous mapping for {\tt k}.
+\item a ``{\tt remove\_from\_f(Ref x, k)}'' RPC removes the pair with key {\tt k}
+from the mapping stored in {\tt f} in object {\tt x}.
+\end{itemize}
+
+Each field whose outermost type is neither {\em Set\/} nor {\em Map\/},
+but whose attribute is {\em RW} has an RPC acessor associated with it
+that sets its value:
+\begin{itemize}
+\item For {\em RW\/} ({\em R\/}ead/{\em
+W\/}rite), a ``{\tt set\_f(Ref x, v)}'' RPC function is also provided.
+This sets field {\tt f} on object {\tt x} to value {\tt v}.
+\end{itemize}
+
+\section{RPCs associated with classes}
+
+\begin{itemize}
+\item Each class has a {\em constructor\/} RPC named ``{\tt create}'' that
+takes as parameters all fields marked {\em RW\/} and
+$\mathit{RO}_\mathit{ins}$. The result of this RPC is that a new {\em
+persistent\/} object is created on the server-side with the specified field
+values.
+
+\item Each class has a {\tt get\_by\_uuid(uuid)} RPC that returns the object
+of that class that has the specified {\tt uuid}.
+
+\item Each class that has a {\tt name\_label} field has a
+``{\tt get\_by\_name\_label(name)}'' RPC that returns a set of objects of that
+class that have the specified {\tt label}.
+
+\item Each class has a ``{\tt to\_XML()}'' RPC that serialises the
+state of all fields as an XML string.
+
+\item Each class has a ``{\tt destroy(Ref x)}'' RPC that explicitly deletes
+the persistent object specified by {\tt x} from the system. This is a
+non-cascading delete -- if the object being removed is referenced by another
+object then the {\tt destroy} call will fail.
+
+\end{itemize}
+
+\subsection{Additional RPCs}
+
+As well as the RPCs enumerated above, some classes have additional RPCs
+associated with them. For example, the {\tt VM} class have RPCs for cloning,
+suspending, starting etc. Such additional RPCs are described explicitly
+in the API reference.
diff --git a/docs/xen-api/todo.tex b/docs/xen-api/todo.tex
new file mode 100644
index 0000000000..2778ccce55
--- /dev/null
+++ b/docs/xen-api/todo.tex
@@ -0,0 +1,140 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\section{To-Do}
+
+Lots and lots! Including:
+
+\subsection{Clarity}
+
+\begin{itemize}
+
+\item Roll constructors and get\_by\_uuid etc (section 1.2) into section 2 so
+that it is clearer that each class has these.
+
+\item Emphasise that enums are strings on the wire, and so are not restricted
+to a certain number of bits.
+
+\item Clarify return values, in particular that void means return a status
+code, potential error description, but otherwise no value.
+
+\item Talk about UUID generation.
+
+\item Clarify session behaviour wrt timeouts and disconnects.
+
+\item Clarify behaviour of progress field on asyncrhonous request polling when
+that request fails.
+
+\end{itemize}
+
+\subsection{Content}
+
+\subsubsection{Model}
+
+\begin{itemize}
+
+\item Improve the set of available power\_states and corresponding lifecycle
+semantics. Rename power\_state, maybe.
+
+\item Specify the CPU scheduler configuration properly, inc CPU affinity,
+weights, etc.
+
+\item Add Vm.architecture and Host.compatible\_architecture fields.
+
+\item Add migration calls, including the ability to test whether a migration
+will succeed, and authentication token exchange.
+
+\item Improve asynchronous task handling, with a registration call, a
+``blocking poll'' call, and an explicit notification destination. Registration
+for ``power\_state'' is useful.
+
+\item Specify that session keys outlive the HTTP session, and add a timeout
+for them (configurable in the tools).
+
+\item Add places for people to store extra data (``otherConfig'' perhaps)
+
+\item Specify how hardware UUIDs are used / accessed.
+
+\item Marking VDIs as exclusive / shareable (locking?)
+
+\item Consider how to represent CDROMs (as VDIs?)
+
+\item Define lists of exceptions which may be thrown by each RPC, including
+error codes and parameters.
+
+\item Host characteristics: minimum amount of memory, TPM, network bandwidth,
+amount of host memory, amount consumed by VMs, max amount available for new
+VMs?
+
+\item Cooked resource monitoring interface.
+
+\item Network needs additional attributes that provide media characteristics
+of the NIC:
+
+\begin{itemize}
+
+\item RO bandwidth integer Bandwidth in mbps
+\item RO latency integer time in ms for an icmp roundtrip to a host on the
+same subnet.
+
+\end{itemize}
+
+\item TPM
+\begin{itemize}
+
+\item Would it not be better to have a class TPM and a member TPMs ((TPM ref)
+Set) containing an array of zero or one references to TPMs? I assume that
+an empty array would make it clear that no TPM is associated with the VM
+instead of encoding its existence into TPM/instance or TPM/backend
+somehow. The current members instance and backend could then be moved into
+the TPM class.
+
+\item Also a Xen system can be running an access control policy where each
+VM's run-time access to resources is restricted by the label it has been given
+compared to those of the resources. Currently a VM's configuration file may
+contain a line like access\_control[policy='$<$name of the system's
+policy$>$',label='$<$label given to VM$>$']. I think the identifiers 'policy'
+and 'label' should also be part of the VM class either directly in the form
+'access\_control/policy' or indirectly in an access\_control class.
+
+\end{itemize}
+
+\item Mike Day's Vm.profile field?
+
+\item Clone customisation?
+
+\item NIC teaming? The NIC field of the Network class should be a list (Set)
+so that we can signify NIC teaming. (Combining physical NICs in a single host
+interface to achieve greater bandwidth).
+
+\end{itemize}
+
+\subsubsection{Transport}
+
+\begin{itemize}
+
+\item Allow non-HTTP transports. Explicitly allow stdio transport, for SSH.
+
+\end{itemize}
+
+\subsubsection{Authentication}
+
+\begin{itemize}
+
+\item Delegation to the transport layer.
+
+\item Extend PAM exchange across the wire.
+
+\item Fine-grained access control.
+
+\end{itemize}
diff --git a/docs/xen-api/vm-lifecycle.tex b/docs/xen-api/vm-lifecycle.tex
new file mode 100644
index 0000000000..23ddb9e9ae
--- /dev/null
+++ b/docs/xen-api/vm-lifecycle.tex
@@ -0,0 +1,24 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\section{VM Lifecycle}
+
+\begin{figure}
+\centering
+\resizebox{0.9\textwidth}{!}{\includegraphics{vm_lifecycle}}
+\caption{VM Lifecycle}
+\label{fig-vm-lifecycle}
+\end{figure}
+
+Figure~\ref{fig-vm-lifecycle} shows the states that a VM can be in
+and the API calls that can be used to move the VM between these states.
diff --git a/docs/xen-api/vm_lifecycle.dot b/docs/xen-api/vm_lifecycle.dot
new file mode 100644
index 0000000000..fdc97523e2
--- /dev/null
+++ b/docs/xen-api/vm_lifecycle.dot
@@ -0,0 +1,15 @@
+digraph g{
+
+node [shape=box]; "powered down" paused running suspended;
+
+"powered down" -> paused [label="start(paused=true)"];
+"powered down" -> running [label="start(paused=false)"];
+running -> suspended [label="suspend"];
+suspended -> running [label="resume(paused=false)"];
+suspended -> paused [label="resume(paused=true)"];
+paused -> suspended [label="suspend"];
+paused -> running [label="resume"];
+running -> "powered down" [label="cleanShutdown /\nhardShutdown"];
+running -> paused [label="pause"];
+
+} \ No newline at end of file
diff --git a/docs/xen-api/wire-protocol.tex b/docs/xen-api/wire-protocol.tex
new file mode 100644
index 0000000000..ecd4ed9416
--- /dev/null
+++ b/docs/xen-api/wire-protocol.tex
@@ -0,0 +1,287 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\section{Wire Protocol for Remote API Calls}
+
+API calls are sent over a network to a Xen-enabled host using
+the XML-RPC protocol. In this Section we describe how the
+higher-level types used in our API Reference are mapped to
+primitive XML-RPC types.
+
+In our API Reference we specify the signatures of API functions in the following
+style:
+\begin{verbatim}
+ (ref_vm Set) Host.ListAllVMs()
+\end{verbatim}
+This specifies that the function with name {\tt Host.ListAllVMs} takes
+no parameters and returns a Set of {\tt ref\_vm}s.
+These types are mapped onto XML-RPC types in a straight-forward manner:
+\begin{itemize}
+ \item Floats, Bools, DateTimes and Strings map directly to the XML-RPC {\tt
+ double}, {\tt boolean}, {\tt dateTime.iso8601}, and {\tt string} elements.
+
+ \item all our ``{\tt ref\_}'' types (e.g.\ {\tt ref\_vm} in the above
+ example) map to XML-RPC's {\tt String} type. The string itself is the OSF
+ DCE UUID presentation format (as output by {\tt uuidgen}, etc).
+
+ \item ints are all assumed to be 64-bit in our API and are encoded as a
+ string of decimal digits (rather than using XML-RPC's built-in 32-bit {\tt
+ i4} type).
+
+ \item values of enum types are encoded as strings. For example, a value of
+ {\tt destroy} of type {\tt on\_normal\_exit}, would be conveyed as:
+ \begin{verbatim}
+ <value><string>destroy</string></value>
+ \end{verbatim}
+
+ \item for all our types, {\tt t}, our type {\tt t Set} simply maps to
+ XML-RPC's {\tt Array} type, so for example a value of type {\tt cpu\_feature
+ Set} would be transmitted like this:
+
+ \begin{verbatim}
+<array>
+ <data>
+ <value><string>CX8</string></value>
+ <value><string>PSE36</string></value>
+ <value><string>FPU</string></value>
+ </data>
+</array>
+ \end{verbatim}
+
+ \item for types {\tt k} and {\tt v}, our type {\tt (k, v) Map} maps onto an
+ XML-RPC struct, with the key as the name of the struct. Note that the {\tt
+ (k, v) Map} type is only valid when {\tt k} is a {\tt String}, {\tt Ref}, or
+ {\tt Int}, and in each case the keys of the maps are stringified as
+ above. For example, the {\tt (String, double) Map} containing a the mappings
+ Mike $\rightarrow$ 2.3 and John $\rightarrow$ 1.2 would be represented as:
+
+ \begin{verbatim}
+<value>
+ <struct>
+ <member>
+ <name>Mike</name>
+ <value><double>2.3</double></value>
+ </member>
+ <member>
+ <name>John</name>
+ <value><double>1.2</double></value>
+ </member>
+ </struct>
+</value>
+ \end{verbatim}
+
+ \item our {\tt Void} type is transmitted as an empty string.
+
+\end{itemize}
+
+\subsection{Return Values/Status Codes}
+\label{synchronous-result}
+
+The return value of an RPC call is an XML-RPC {\tt Struct}.
+
+\begin{itemize}
+\item The first element of the struct is named {\tt Status}; it
+contains a string value indicating whether the result of the call was
+a ``{\tt Success}'' or a ``{\tt Failure}''.
+\end{itemize}
+
+If {\tt Status} was set to {\tt Success} then the Struct contains a second
+element named {\tt Value}:
+\begin{itemize}
+\item The element of the struct named {\tt Value} contains the function's return value.
+\end{itemize}
+
+In the case where {\tt Status} is set to {\tt Failure} then
+the struct contains a second element named {\tt ErrorDescription}:
+\begin{itemize}
+\item The element of the struct named {\tt ErrorDescription} contains
+an array of string values. The first element of the array represents an error code;
+the remainder of the array represents error parameters relating to that code.
+\end{itemize}
+
+For example, an XML-RPC return value from the {\tt Host.ListAllVMs} function above
+may look like this:
+\begin{verbatim}
+ <struct>
+ <member>
+ <name>Status</name>
+ <value>Success</value>
+ </member>
+ <member>
+ <name>Value</name>
+ <value>
+ <array>
+ <data>
+ <value>vm-id-1</value>
+ <value>vm-id-2</value>
+ <value>vm-id-3</value>
+ </data>
+ </array>
+ </value>
+ </member>
+ </struct>
+\end{verbatim}
+
+\section{Making XML-RPC Calls}
+
+\subsection{Transport Layer}
+
+We ought to support at least
+\begin{itemize}
+\item HTTP/S for remote administration
+\item HTTP over Unix domain sockets for local administration
+\end{itemize}
+
+\subsection{Session Layer}
+
+The XML-RPC interface is session-based; before you can make arbitrary RPC calls
+you must login and initiate a session. For example:
+\begin{verbatim}
+ session_id Session.login_with_password(string uname, string pwd)
+\end{verbatim}
+Where {\tt uname} and {\tt password} refer to your username and password
+respectively, as defined by the Xen administrator.
+The {\tt session\_id} returned by {\tt Session.Login} is passed to subequent
+RPC calls as an authentication token.
+
+A session can be terminated with the {\tt Session.Logout} function:
+\begin{verbatim}
+ void Session.Logout(session_id session)
+\end{verbatim}
+
+\subsection{Synchronous and Asynchronous invocation}
+
+Each method call (apart from those on ``Session'' and ``Task'' objects)
+can be made either synchronously or asynchronously.
+A synchronous RPC call blocks until the
+return value is received; the return value of a synchronous RPC call is
+exactly as specified in Section~\ref{synchronous-result}.
+
+Each of the methods specified in the API Reference is synchronous.
+However, although not listed explicitly in this document, each
+method call has an asynchronous analogue in the {\tt Async}
+namespace. For example, synchronous call {\tt VM.Install(...)}
+(described in Chapter~\ref{api-reference})
+has an asynchronous counterpart, {\tt
+Async.VM.Install(...)}, that is non-blocking.
+
+Instead of returning its result directly, an asynchronous RPC call
+returns a {\tt task-id}; this identifier is subsequently used
+to track the status of a running asynchronous RPC. Note that an asychronous
+call may fail immediately, before a {\tt task-id} has even been created---to
+represent this eventuality, the returned {\tt task-id}
+is wrapped in an XML-RPC struct with a {\tt Status}, {\tt ErrorDescription} and
+{\tt Value} fields, exactly as specified in Section~\ref{synchronous-result}.
+
+The {\tt task-id} is provided in the {\tt Value} field if {\tt Status} is set to
+{\tt Success}.
+
+Two special RPC calls are provided to poll the status of
+asynchronous calls:
+\begin{verbatim}
+ Array<task_id> Async.Task.GetAllTasks (session_id s)
+ task_status Async.Task.GetStatus (session_id s, task_id t)
+\end{verbatim}
+
+{\tt Async.Task.GetAllTasks} returns a set of the currently
+executing asynchronous tasks belong to the current user\footnote{
+%
+The current user is determined by the username that was provided
+to {\tt Session.Login}.
+%
+}.
+
+{\tt Async.Task.GetStatus} returns a {\tt task\_status} result.
+This is an XML-RPC struct with three elements:
+\begin{itemize}
+ \item The first element is named {\tt Progress} and contains
+an {\tt Integer} between 0 and 100 representing the estimated percentage of
+the task currently completed.
+ \item The second element is named {\tt ETA} and contains a {\tt DateTime}
+representing the estimated time the task will be complete.
+ \item The third element is named {\tt Result}. If {\tt Progress}
+is not 100 then {\tt Result} contains the empty string. If {\tt Progress}
+{\em is\/} set to 100, then {\tt Result} contains the function's return
+result (as specified in Section~\ref{synchronous-result})\footnote{
+%
+Recall that this itself is a struct potentially containing status, errorcode,
+value fields etc.
+%
+}.
+\end{itemize}
+
+\section{Example interactive session}
+
+This section describes how an interactive session might look, using the python
+XML-RPC client library.
+
+First, initialise python and import the library {\tt xmlrpclib}:
+
+\begin{verbatim}
+\$ python2.4
+...
+>>> import xmlrpclib
+\end{verbatim}
+
+Create a python object referencing the remote server:
+
+\begin{verbatim}
+>>> xen = xmlrpclib.Server("http://test:4464")
+\end{verbatim}
+
+Acquire a session token by logging in with a username and password (error-handling ommitted for brevity; the session token is pointed to by the key {\tt 'Value'} in the returned dictionary)
+
+\begin{verbatim}
+>>> session = xen.Session.do_login_with_password("user", "passwd")['Value']
+\end{verbatim}
+
+When serialised, this call looks like the following:
+
+\begin{verbatim}
+<?xml version='1.0'?>
+<methodCall>
+ <methodName>Session.do_login_with_password</methodName>
+ <params>
+ <param>
+ <value><string>user</string></value>
+ </param>
+ <param>
+ <value><string>passwd</string></value>
+ </param>
+ </params>
+</methodCall>
+\end{verbatim}
+
+Next, the user may acquire a list of all the VMs known to the host: (Note the call takes the session token as the only parameter)
+
+\begin{verbatim}
+>>> all_vms = xen.VM.do_list(session)['Value']
+>>> all_vms
+['b7b92d9e-d442-4710-92a5-ab039fd7d89b', '23e1e837-abbf-4675-b077-d4007989b0cc', '2045dbc0-0734-4eea-9cb2-b8218c6b5bf2', '3202ae18-a046-4c32-9fda-e32e9631866e']
+\end{verbatim}
+
+Note the VM references are internally UUIDs. Once a reference to a VM has been acquired a lifecycle operation may be invoked:
+
+\begin{verbatim}
+>>> xen.VM.do_start(session, all_vms[3], False)
+{'Status': 'Failure', 'ErrorDescription': 'Operation not implemented'}
+\end{verbatim}
+
+In this case the {\tt start} message has not been implemented and an error response has been returned. Currently these high-level errors are returned as structured data (rather than as XMLRPC faults), allowing for internationalised errors in future. Finally, here are some examples of using accessors for object fields:
+
+\begin{verbatim}
+>>> xen.VM.getname_label(session, all_vms[3])['Value']
+'SMP'
+>>> xen.VM.getname_description(session, all_vms[3])['Value']
+'Debian for Xen'
+\end{verbatim}
diff --git a/docs/xen-api/xen.eps b/docs/xen-api/xen.eps
new file mode 100644
index 0000000000..da14fe9b86
--- /dev/null
+++ b/docs/xen-api/xen.eps
@@ -0,0 +1,44 @@
+%!PS-Adobe-3.1 EPSF-3.0 %%Title: xen3-1.0.eps %%Creator: Adobe Illustrator(R) 11 %%AI8_CreatorVersion: 11.0.0 %AI9_PrintingDataBegin %%For: Rich Quarles %%CreationDate: 6/26/06 %%BoundingBox: 0 0 215 94 %%HiResBoundingBox: 0 0 214.1646 93.5196 %%CropBox: 0 0 214.1646 93.5196 %%LanguageLevel: 2 %%DocumentData: Clean7Bit %%Pages: 1 %%DocumentNeededResources: %%DocumentSuppliedResources: procset Adobe_AGM_Image (1.0 0) %%+ procset Adobe_CoolType_Utility_T42 (1.0 0) %%+ procset Adobe_CoolType_Utility_MAKEOCF (1.19 0) %%+ procset Adobe_CoolType_Core (2.23 0) %%+ procset Adobe_AGM_Core (2.0 0) %%+ procset Adobe_AGM_Utils (1.0 0) %%DocumentFonts: %%DocumentNeededFonts: %%DocumentNeededFeatures: %%DocumentSuppliedFeatures: %%DocumentProcessColors: Black %%DocumentCustomColors: %%CMYKCustomColor: %%RGBCustomColor: %ADO_ContainsXMP: MainFirst %AI7_Thumbnail: 128 56 8 %%BeginData: 6266 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD19FFA8A87DA8FD077DA8A8FD70FF7D7D527D527D527D7D7D527D %527D52FD047DFD6AFFA87D527D7D7D52FD0B7D52FD047DA8A8FD65FFA87D %7D527D52FD047DFD09A87D7D527D527D527D7DFD63FFA8FD057DA8A8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD057DA8FD5FFFA87D527D527D7DA8 %A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A87D7D527D527DA8FD5CFF %A87D527D7DA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8A87D7D527DA8FD5AFF7D7D527D7DFD04A8FFA8A8A8FFA8A8A8FFA8A8A8 %FFA8A8A8FFA8A8A8FFFD04A8527D527DA8FD58FFFD057DFFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD047DA8FD56 %FF7D7D527D7DA8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8A8A8FFA8 %A8A8FFA8A8A8FFA8A8FD047DA8FD54FFA8FD047DFFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFD047DA8FD %52FFA87D527D7DFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8A8FFA8A8A8FF %A8A8A8FFFD05A8FFA8FFA8FFFD047DA8FD51FF7D7D7D27FD0E527DA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFFFA827FD0552272727FD09527DFD47FFA8 %527D7D52FD0FF852A8A8A8FFA8A8A8FFA8A8A8FFA8FFA87DFD12F852FD48 %FF7D7D7DA8A827FD0FF87DFFFFA8FFA8FFA8FFA8FFA8FFFF7DFD11F8277D %FD48FF7D7D527DA8FFA827FD0FF8FD04A8FFA8A8A8FFA8FFA852FD11F827 %A8FD49FF7D7D7DA8FFA8FF7DFD0FF827FFA8FFA8FFA8FFA8FFA827FD11F8 %52FD4AFFA8527D7DFFA8A8A8FF52FD0FF852FFA8FFA8A8A8FF7DFD12F87D %FD4BFF7D7D7DA8A8FFA8FFA8FF52FD0FF87DFFA8FFA8FF7DFD12F852A8FD %4AFFA87D527DA8A8A8FFA8A8A8FF27FD0EF827A8FFA8FF52FD11F8277D7D %7DA8FD07FFA8FFA8FFA8FD23FFA8FFA8FD17FFA8527D7DFFA8FFA8FFA8FF %FFFFFD0FF852FFFF27FD11F852FF7D7D7DFFA87D52522727F827F827F827 %27527DFD0BFFFD04A87DA8A8A87DFD04A8FFFFFFA87D5227F827F8272752 %7DFD14FF7D7D52FD04A8FFA8A8A8FFA8A8FD0FF85227FD10F8277DFFA8A8 %5227FD11F82752FD07FFA8FD0CF8FFFFA827FD0CF87DFFFFFFA8F8F8F87D %27F8527DF8F8FD04FF7D7D7DA8FFA8FFA8FFA8FFA8FFFF7DFD1FF827A8FF %FF7D27FD16F8A8FD05FFA8FD0BF827FF7DFD0FF87DFFFFFFA8F87DFF27F8 %2727F8F8FFFFFFA8527D7DA8A8FFA8A8A8FFA8A8A8FFA852FD1DF852A8FF %A852FD19F87DFD04FF52FD0BF82727FD11F8A8FFFFA8F852FFF827F8F852 %F8FFFFFFA87D7DA8A8FFA8FFA8FFA8FFA8FFA8FFA852FD1BF8A8FFFFA827 %FD0BF87DA8FF7D52FD0BF8FD04FF52FD1EF852FFFFFF52A8FFFD047DA852 %FFFFFFA8527D7DFFA8FFA8A8A8FFA8A8A8FFA8FFA827FD18F827A8A8FFA8 %27FD0AF827FD06FF27FD0AF827FFFFFFFD0FF82727FD0EF852FD0FFFA87D %52A8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA827FD16F852FFFFFFA852FD0BF8 %FD07FF52FD0AF827FFFFA8FD0DF827A8FFFFFF52FD0CF852FD0FFFA8527D %7DFFA8A8A8FFA8A8A8FFA8A8A8FFA8FF7DFD15F852FFA8A8A87DFD0BF852 %FD04FFA8FFFF52FD0BF8A8FF7DFD0CF827FD05FFA8FD0CF852FD0FFFA87D %7DA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF52FD12F827A8FFA8FFA8FF27 %FD0CF8FD0727FD0CF8A8FF52FD0CF8FD07FFFD0CF87DFD0FFFA8527D7DFF %A8A8A8FFA8A8A8FFA8A8A8FFA8FF52FD12F852A8FFA8A8A8FF7DFD20F8FF %FF27FD0BF852FD06FF7DFD0CF8A8FD0FFFA87D7DA8A8FFA8FFA8FFA8FFA8 %FFA8FFFFA827FD12F827A8FFA8FFA8FFA87DFD1FF827FFFFFD0CF87DFD06 %FF7DFD0BF827FD10FFA8527D7DA8A8FFA8A8A8FFA8A8A8FFA87DFD15F852 %A8A8A8FFA8FF52FD0CF827F827F827F827F827F827F827F827F827F82752 %FF7DFD0CF8A8FD06FF27FD0BF827FD10FFA87D7D7DA8FFA8FFA8FFA8FFA8 %FFFF7DFD17F87DFFFFA8FFA852FD0BF8A8FD15FF7DFD0BF827FD07FF27FD %0BF87DFD11FF7D7D7DA8A8FFA8A8A8FFA8FFA852FD19F87DA8FFA8FF52FD %0BF87DFD15FF27FD0BF827FD06FFA8FD0CF8A8FD11FFA8527DA8FFA8FFA8 %FFA8FFA827FD1BF8A8A8FFFF7DFD0BF87DFD06FF7D272752275227522752 %27277DFFFF27FD0BF87DFD06FF7DFD0CF8FD12FF7D7D52FD06A8FF52FD1D %F827FFA8FFA8FD0CF8A8FD04FF52FD0CF8A8FFA8FD0CF87DFD06FF52FD0B %F852FD13FF7D7D7DFFA8FFFFFF52FD1FF852FFA8FF7DFD0CF8525252FD0D %F8A8FFFF7DFD0CF8FD07FF27FD0BF852FD13FF7D527DA8FFA8A827FD11F8 %2727FD0EF852FFA8FF52FD19F827A8FFFFFF52FD0BF852FD06FFA8FD0CF8 %A8FD13FFA87D52A8FF7DFD12F852FF52FD0FF87DFFA8FF7D27FD15F8277D %FD05FFFD0CF852FD06FF7DFD0CF8FD15FF527D7D52FD12F87DFFA8FF27FD %0EF827A8FFA8FFA87D2727FD0FF85252A8FD06FFA8522727275227272752 %272727A8FD06FF52FD04275227272752272752FD15FFA85227FD11F827A8 %FFA8FFA8A8FD0FF852FFFFA8FF7D7D7DA8A8A87D7D527D52FD047DA8A8FD %40FF7DFD12F852A8FFA8FFA8A8A87DFD0FF87DFFFF7D7D527DFD4DFF7DFD %12F87DA8FFA8FFA8FFA8FFA852FD0FF8A8A87D7D7DA8FD4CFF52FD12F8FD %04A8FFA8A8A8FFA8FF7DFD10F8FD047DFD4CFF27FD11F827FFFFFFA8FFA8 %FFA8FFA8FFA8FF7DFD0FF8277D7DFD4BFFA8FD12F852FFA8FFA8A8A8FFA8 %A8A8FFA8A8A8FF27FD0FF827FD4BFF7DFD0FF827F8277DFFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8A8FD10F87DFD4AFF7DFD0AA87D5252527D7DA8A8FF %A8FFA8A8A8FFA8A8A8FFA8A8A8FFFD04A87DA87DA87DA87DA87DFD0452A8 %A8A8FD56FFA87D7D7DA8A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FD05FFA8FD047DFD5BFFA8527D527D7DA8A8FFA8A8A8FFA8A8A8FF %A8A8A8FFA8A8A8FFA8A8A8FFA8A8FD047D52FD5EFFFD057DA8A8FFA8FFA8 %FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8A8FD057DFD60FF7D7D527D527D7D %FD04A8FFA8A8A8FFA8A8A8FFFD04A87D7D527D527D7DFD62FFA8A8FD077D %FD04A8FFFD06A8FD077DA8FD67FF7D7D527D527D527D527D527D7D7D527D %527D527D527D7DFD6BFFA8FD047D527D7D7D527D7D7D52FD047DFD70FFFD %04A8FD077DA8A8FFA8FD58FFFF %%EndData %%EndComments %%BeginDefaults %%ViewingOrientation: 1 0 0 1 %%EndDefaults %%BeginProlog %%BeginResource: procset Adobe_AGM_Utils 1.0 0 %%Version: 1.0 0 %%Copyright: Copyright (C) 2000-2003 Adobe Systems, Inc. All Rights Reserved. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Utils 68 dict dup begin put /bdf { bind def } bind def /nd{ null def }bdf /xdf { exch def }bdf /ldf { load def }bdf /ddf { put }bdf /xddf { 3 -1 roll put }bdf /xpt { exch put }bdf /ndf { exch dup where{ pop pop pop }{ xdf }ifelse }def /cdndf { exch dup currentdict exch known{ pop pop }{ exch def }ifelse }def /bdict { mark }bdf /edict { counttomark 2 idiv dup dict begin {def} repeat pop currentdict end }def /ps_level /languagelevel where{ pop systemdict /languagelevel get exec }{ 1 }ifelse def /level2 ps_level 2 ge def /level3 ps_level 3 ge def /ps_version {version cvr} stopped { -1 }if def /makereadonlyarray { /packedarray where{ pop packedarray }{ array astore readonly }ifelse }bdf /map_reserved_ink_name { dup type /stringtype eq{ dup /Red eq{ pop (_Red_) }{ dup /Green eq{ pop (_Green_) }{ dup /Blue eq{ pop (_Blue_) }{ dup () cvn eq{ pop (Process) }if }ifelse }ifelse }ifelse }if }bdf /AGMUTIL_GSTATE 22 dict def /get_gstate { AGMUTIL_GSTATE begin /AGMUTIL_GSTATE_clr_spc currentcolorspace def /AGMUTIL_GSTATE_clr_indx 0 def /AGMUTIL_GSTATE_clr_comps 12 array def mark currentcolor counttomark {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 3 -1 roll put /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 add def} repeat pop /AGMUTIL_GSTATE_fnt rootfont def /AGMUTIL_GSTATE_lw currentlinewidth def /AGMUTIL_GSTATE_lc currentlinecap def /AGMUTIL_GSTATE_lj currentlinejoin def /AGMUTIL_GSTATE_ml currentmiterlimit def currentdash /AGMUTIL_GSTATE_do xdf /AGMUTIL_GSTATE_da xdf /AGMUTIL_GSTATE_sa currentstrokeadjust def /AGMUTIL_GSTATE_clr_rnd currentcolorrendering def /AGMUTIL_GSTATE_op currentoverprint def /AGMUTIL_GSTATE_bg currentblackgeneration cvlit def /AGMUTIL_GSTATE_ucr currentundercolorremoval cvlit def currentcolortransfer cvlit /AGMUTIL_GSTATE_gy_xfer xdf cvlit /AGMUTIL_GSTATE_b_xfer xdf cvlit /AGMUTIL_GSTATE_g_xfer xdf cvlit /AGMUTIL_GSTATE_r_xfer xdf /AGMUTIL_GSTATE_ht currenthalftone def /AGMUTIL_GSTATE_flt currentflat def end }def /set_gstate { AGMUTIL_GSTATE begin AGMUTIL_GSTATE_clr_spc setcolorspace AGMUTIL_GSTATE_clr_indx {AGMUTIL_GSTATE_clr_comps AGMUTIL_GSTATE_clr_indx 1 sub get /AGMUTIL_GSTATE_clr_indx AGMUTIL_GSTATE_clr_indx 1 sub def} repeat setcolor AGMUTIL_GSTATE_fnt setfont AGMUTIL_GSTATE_lw setlinewidth AGMUTIL_GSTATE_lc setlinecap AGMUTIL_GSTATE_lj setlinejoin AGMUTIL_GSTATE_ml setmiterlimit AGMUTIL_GSTATE_da AGMUTIL_GSTATE_do setdash AGMUTIL_GSTATE_sa setstrokeadjust AGMUTIL_GSTATE_clr_rnd setcolorrendering AGMUTIL_GSTATE_op setoverprint AGMUTIL_GSTATE_bg cvx setblackgeneration AGMUTIL_GSTATE_ucr cvx setundercolorremoval AGMUTIL_GSTATE_r_xfer cvx AGMUTIL_GSTATE_g_xfer cvx AGMUTIL_GSTATE_b_xfer cvx AGMUTIL_GSTATE_gy_xfer cvx setcolortransfer AGMUTIL_GSTATE_ht /HalftoneType get dup 9 eq exch 100 eq or { currenthalftone /HalftoneType get AGMUTIL_GSTATE_ht /HalftoneType get ne { mark AGMUTIL_GSTATE_ht {sethalftone} stopped cleartomark } if }{ AGMUTIL_GSTATE_ht sethalftone } ifelse AGMUTIL_GSTATE_flt setflat end }def /get_gstate_and_matrix { AGMUTIL_GSTATE begin /AGMUTIL_GSTATE_ctm matrix currentmatrix def end get_gstate }def /set_gstate_and_matrix { set_gstate AGMUTIL_GSTATE begin AGMUTIL_GSTATE_ctm setmatrix end }def /AGMUTIL_str256 256 string def /AGMUTIL_src256 256 string def /AGMUTIL_dst64 64 string def /AGMUTIL_srcLen nd /AGMUTIL_ndx nd /agm_sethalftone { dup begin /_Data load /Thresholds xdf end level3 { sethalftone }{ dup /HalftoneType get 3 eq { sethalftone } {pop} ifelse }ifelse } def /rdcmntline { currentfile AGMUTIL_str256 readline pop (%) anchorsearch {pop} if } bdf /filter_cmyk { dup type /filetype ne{ exch () /SubFileDecode filter } { exch pop } ifelse [ exch { AGMUTIL_src256 readstring pop dup length /AGMUTIL_srcLen exch def /AGMUTIL_ndx 0 def AGMCORE_plate_ndx 4 AGMUTIL_srcLen 1 sub{ 1 index exch get AGMUTIL_dst64 AGMUTIL_ndx 3 -1 roll put /AGMUTIL_ndx AGMUTIL_ndx 1 add def }for pop AGMUTIL_dst64 0 AGMUTIL_ndx getinterval } bind /exec cvx ] cvx } bdf /filter_indexed_devn { cvi Names length mul names_index add Lookup exch get } bdf /filter_devn { 4 dict begin /srcStr xdf /dstStr xdf dup type /filetype ne{ 0 () /SubFileDecode filter }if [ exch [ /devicen_colorspace_dict /AGMCORE_gget cvx /begin cvx currentdict /srcStr get /readstring cvx /pop cvx /dup cvx /length cvx 0 /gt cvx [ Adobe_AGM_Utils /AGMUTIL_ndx 0 /ddf cvx names_index Names length currentdict /srcStr get length 1 sub { 1 /index cvx /exch cvx /get cvx currentdict /dstStr get /AGMUTIL_ndx /load cvx 3 -1 /roll cvx /put cvx Adobe_AGM_Utils /AGMUTIL_ndx /AGMUTIL_ndx /load cvx 1 /add cvx /ddf cvx } for currentdict /dstStr get 0 /AGMUTIL_ndx /load cvx /getinterval cvx ] cvx /if cvx /end cvx ] cvx bind /exec cvx ] cvx end } bdf /AGMUTIL_imagefile nd /read_image_file { AGMUTIL_imagefile 0 setfileposition 10 dict begin /imageDict xdf /imbufLen Width BitsPerComponent mul 7 add 8 idiv def /imbufIdx 0 def /origDataSource imageDict /DataSource get def /origMultipleDataSources imageDict /MultipleDataSources get def /origDecode imageDict /Decode get def /dstDataStr imageDict /Width get colorSpaceElemCnt mul string def /srcDataStrs [ imageDict begin currentdict /MultipleDataSources known {MultipleDataSources {DataSource length}{1}ifelse}{1} ifelse { Width Decode length 2 div mul cvi string } repeat end ] def imageDict /MultipleDataSources known {MultipleDataSources}{false} ifelse { /imbufCnt imageDict /DataSource get length def /imbufs imbufCnt array def 0 1 imbufCnt 1 sub { /imbufIdx xdf imbufs imbufIdx imbufLen string put imageDict /DataSource get imbufIdx [ AGMUTIL_imagefile imbufs imbufIdx get /readstring cvx /pop cvx ] cvx put } for DeviceN_PS2 { imageDict begin /DataSource [ DataSource /devn_sep_datasource cvx ] cvx def /MultipleDataSources false def /Decode [0 1] def end } if }{ /imbuf imbufLen string def Indexed_DeviceN level3 not and DeviceN_NoneName or { imageDict begin /DataSource [AGMUTIL_imagefile Decode BitsPerComponent false 1 /filter_indexed_devn load dstDataStr srcDataStrs devn_alt_datasource /exec cvx] cvx def /Decode [0 1] def end }{ imageDict /DataSource {AGMUTIL_imagefile imbuf readstring pop} put } ifelse } ifelse imageDict exch load exec imageDict /DataSource origDataSource put imageDict /MultipleDataSources origMultipleDataSources put imageDict /Decode origDecode put end } bdf /write_image_file { begin { (AGMUTIL_imagefile) (w+) file } stopped{ false }{ Adobe_AGM_Utils/AGMUTIL_imagefile xddf 2 dict begin /imbufLen Width BitsPerComponent mul 7 add 8 idiv def MultipleDataSources {DataSource 0 get}{DataSource}ifelse type /filetype eq { /imbuf imbufLen string def }if 1 1 Height { pop MultipleDataSources { 0 1 DataSource length 1 sub { DataSource type dup /arraytype eq { pop DataSource exch get exec }{ /filetype eq { DataSource exch get imbuf readstring pop }{ DataSource exch get } ifelse } ifelse AGMUTIL_imagefile exch writestring } for }{ DataSource type dup /arraytype eq { pop DataSource exec }{ /filetype eq { DataSource imbuf readstring pop }{ DataSource } ifelse } ifelse AGMUTIL_imagefile exch writestring } ifelse }for end true }ifelse end } bdf /close_image_file { AGMUTIL_imagefile closefile (AGMUTIL_imagefile) deletefile }def statusdict /product known userdict /AGMP_current_show known not and{ /pstr statusdict /product get def pstr (HP LaserJet 2200) eq pstr (HP LaserJet 4000 Series) eq or pstr (HP LaserJet 4050 Series ) eq or pstr (HP LaserJet 8000 Series) eq or pstr (HP LaserJet 8100 Series) eq or pstr (HP LaserJet 8150 Series) eq or pstr (HP LaserJet 5000 Series) eq or pstr (HP LaserJet 5100 Series) eq or pstr (HP Color LaserJet 4500) eq or pstr (HP Color LaserJet 4600) eq or pstr (HP LaserJet 5Si) eq or pstr (HP LaserJet 1200 Series) eq or pstr (HP LaserJet 1300 Series) eq or pstr (HP LaserJet 4100 Series) eq or { userdict /AGMP_current_show /show load put userdict /show { currentcolorspace 0 get /Pattern eq {false charpath f} {AGMP_current_show} ifelse } put }if currentdict /pstr undef } if /consumeimagedata { begin currentdict /MultipleDataSources known not {/MultipleDataSources false def} if MultipleDataSources { 1 dict begin /flushbuffer Width cvi string def 1 1 Height cvi { pop 0 1 DataSource length 1 sub { DataSource exch get dup type dup /filetype eq { exch flushbuffer readstring pop pop }if /arraytype eq { exec pop }if }for }for end } { /DataSource load type dup /filetype eq { 1 dict begin /flushbuffer Width Decode length 2 div mul cvi string def 1 1 Height { pop DataSource flushbuffer readstring pop pop} for end }if /arraytype eq { 1 1 Height { pop DataSource pop } for }if }ifelse end }bdf /addprocs { 2{/exec load}repeat 3 1 roll [ 5 1 roll ] bind cvx }def /modify_halftone_xfer { currenthalftone dup length dict copy begin currentdict 2 index known{ 1 index load dup length dict copy begin currentdict/TransferFunction known{ /TransferFunction load }{ currenttransfer }ifelse addprocs /TransferFunction xdf currentdict end def currentdict end sethalftone }{ currentdict/TransferFunction known{ /TransferFunction load }{ currenttransfer }ifelse addprocs /TransferFunction xdf currentdict end sethalftone pop }ifelse }def /clonearray { dup xcheck exch dup length array exch Adobe_AGM_Core/AGMCORE_tmp -1 ddf { Adobe_AGM_Core/AGMCORE_tmp AGMCORE_tmp 1 add ddf dup type /dicttype eq { AGMCORE_tmp exch clonedict Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf } if dup type /arraytype eq { AGMCORE_tmp exch clonearray Adobe_AGM_Core/AGMCORE_tmp 4 -1 roll ddf } if exch dup AGMCORE_tmp 4 -1 roll put }forall exch {cvx} if }bdf /clonedict { dup length dict begin { dup type /dicttype eq { clonedict } if dup type /arraytype eq { clonearray } if def }forall currentdict end }bdf /DeviceN_PS2 { /currentcolorspace AGMCORE_gget 0 get /DeviceN eq level3 not and } bdf /Indexed_DeviceN { /indexed_colorspace_dict AGMCORE_gget dup null ne { /CSD known }{ pop false } ifelse } bdf /DeviceN_NoneName { /Names where { pop false Names { (None) eq or } forall }{ false }ifelse } bdf /DeviceN_PS2_inRip_seps { /AGMCORE_in_rip_sep where { pop dup type dup /arraytype eq exch /packedarraytype eq or { dup 0 get /DeviceN eq level3 not and AGMCORE_in_rip_sep and { /currentcolorspace exch AGMCORE_gput false } { true }ifelse } { true } ifelse } { true } ifelse } bdf /base_colorspace_type { dup type /arraytype eq {0 get} if } bdf /doc_setup{ Adobe_AGM_Utils begin }bdf /doc_trailer{ currentdict Adobe_AGM_Utils eq{ end }if }bdf systemdict /setpacking known { setpacking } if %%EndResource %%BeginResource: procset Adobe_AGM_Core 2.0 0 %%Version: 2.0 0 %%Copyright: Copyright (C) 1997-2003 Adobe Systems, Inc. All Rights Reserved. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Core 216 dict dup begin put /nd{ null def }bind def /Adobe_AGM_Core_Id /Adobe_AGM_Core_2.0_0 def /AGMCORE_str256 256 string def /AGMCORE_save nd /AGMCORE_graphicsave nd /AGMCORE_c 0 def /AGMCORE_m 0 def /AGMCORE_y 0 def /AGMCORE_k 0 def /AGMCORE_cmykbuf 4 array def /AGMCORE_screen [currentscreen] cvx def /AGMCORE_tmp 0 def /AGMCORE_&setgray nd /AGMCORE_&setcolor nd /AGMCORE_&setcolorspace nd /AGMCORE_&setcmykcolor nd /AGMCORE_cyan_plate nd /AGMCORE_magenta_plate nd /AGMCORE_yellow_plate nd /AGMCORE_black_plate nd /AGMCORE_plate_ndx nd /AGMCORE_get_ink_data nd /AGMCORE_is_cmyk_sep nd /AGMCORE_host_sep nd /AGMCORE_avoid_L2_sep_space nd /AGMCORE_distilling nd /AGMCORE_composite_job nd /AGMCORE_producing_seps nd /AGMCORE_ps_level -1 def /AGMCORE_ps_version -1 def /AGMCORE_environ_ok nd /AGMCORE_CSA_cache 0 dict def /AGMCORE_CSD_cache 0 dict def /AGMCORE_pattern_cache 0 dict def /AGMCORE_currentoverprint false def /AGMCORE_deltaX nd /AGMCORE_deltaY nd /AGMCORE_name nd /AGMCORE_sep_special nd /AGMCORE_err_strings 4 dict def /AGMCORE_cur_err nd /AGMCORE_ovp nd /AGMCORE_current_spot_alias false def /AGMCORE_inverting false def /AGMCORE_feature_dictCount nd /AGMCORE_feature_opCount nd /AGMCORE_feature_ctm nd /AGMCORE_ConvertToProcess false def /AGMCORE_Default_CTM matrix def /AGMCORE_Default_PageSize nd /AGMCORE_currentbg nd /AGMCORE_currentucr nd /AGMCORE_gradientcache 32 dict def /AGMCORE_in_pattern false def /knockout_unitsq nd /AGMCORE_CRD_cache where{ pop }{ /AGMCORE_CRD_cache 0 dict def }ifelse /AGMCORE_key_known { where{ /Adobe_AGM_Core_Id known }{ false }ifelse }ndf /flushinput { save 2 dict begin /CompareBuffer 3 -1 roll def /readbuffer 256 string def mark { currentfile readbuffer {readline} stopped {cleartomark mark} { not {pop exit} if CompareBuffer eq {exit} if }ifelse }loop cleartomark end restore }bdf /getspotfunction { AGMCORE_screen exch pop exch pop dup type /dicttype eq{ dup /HalftoneType get 1 eq{ /SpotFunction get }{ dup /HalftoneType get 2 eq{ /GraySpotFunction get }{ pop { abs exch abs 2 copy add 1 gt{ 1 sub dup mul exch 1 sub dup mul add 1 sub }{ dup mul exch dup mul add 1 exch sub }ifelse }bind }ifelse }ifelse }if } def /clp_npth { clip newpath } def /eoclp_npth { eoclip newpath } def /npth_clp { newpath clip } def /add_grad { AGMCORE_gradientcache 3 1 roll put }bdf /exec_grad { AGMCORE_gradientcache exch get exec }bdf /graphic_setup { /AGMCORE_graphicsave save def concat 0 setgray 0 setlinecap 0 setlinejoin 1 setlinewidth [] 0 setdash 10 setmiterlimit newpath false setoverprint false setstrokeadjust Adobe_AGM_Core/spot_alias get exec /Adobe_AGM_Image where { pop Adobe_AGM_Image/spot_alias 2 copy known{ get exec }{ pop pop }ifelse } if 100 dict begin /dictstackcount countdictstack def /showpage {} def mark } def /graphic_cleanup { cleartomark dictstackcount 1 countdictstack 1 sub {end}for end AGMCORE_graphicsave restore } def /compose_error_msg { grestoreall initgraphics /Helvetica findfont 10 scalefont setfont /AGMCORE_deltaY 100 def /AGMCORE_deltaX 310 def clippath pathbbox newpath pop pop 36 add exch 36 add exch moveto 0 AGMCORE_deltaY rlineto AGMCORE_deltaX 0 rlineto 0 AGMCORE_deltaY neg rlineto AGMCORE_deltaX neg 0 rlineto closepath 0 AGMCORE_&setgray gsave 1 AGMCORE_&setgray fill grestore 1 setlinewidth gsave stroke grestore currentpoint AGMCORE_deltaY 15 sub add exch 8 add exch moveto /AGMCORE_deltaY 12 def /AGMCORE_tmp 0 def AGMCORE_err_strings exch get { dup 32 eq { pop AGMCORE_str256 0 AGMCORE_tmp getinterval stringwidth pop currentpoint pop add AGMCORE_deltaX 28 add gt { currentpoint AGMCORE_deltaY sub exch pop clippath pathbbox pop pop pop 44 add exch moveto } if AGMCORE_str256 0 AGMCORE_tmp getinterval show ( ) show 0 1 AGMCORE_str256 length 1 sub { AGMCORE_str256 exch 0 put }for /AGMCORE_tmp 0 def } { AGMCORE_str256 exch AGMCORE_tmp xpt /AGMCORE_tmp AGMCORE_tmp 1 add def } ifelse } forall } bdf /doc_setup{ Adobe_AGM_Core begin /AGMCORE_ps_version xdf /AGMCORE_ps_level xdf errordict /AGM_handleerror known not{ errordict /AGM_handleerror errordict /handleerror get put errordict /handleerror { Adobe_AGM_Core begin $error /newerror get AGMCORE_cur_err null ne and{ $error /newerror false put AGMCORE_cur_err compose_error_msg }if $error /newerror true put end errordict /AGM_handleerror get exec } bind put }if /AGMCORE_environ_ok ps_level AGMCORE_ps_level ge ps_version AGMCORE_ps_version ge and AGMCORE_ps_level -1 eq or def AGMCORE_environ_ok not {/AGMCORE_cur_err /AGMCORE_bad_environ def} if /AGMCORE_&setgray systemdict/setgray get def level2{ /AGMCORE_&setcolor systemdict/setcolor get def /AGMCORE_&setcolorspace systemdict/setcolorspace get def }if /AGMCORE_currentbg currentblackgeneration def /AGMCORE_currentucr currentundercolorremoval def /AGMCORE_distilling /product where{ pop systemdict/setdistillerparams known product (Adobe PostScript Parser) ne and }{ false }ifelse def level2 not{ /xput{ dup load dup length exch maxlength eq{ dup dup load dup length dup 0 eq {pop 1} if 2 mul dict copy def }if load begin def end }def }{ /xput{ load 3 1 roll put }def }ifelse /AGMCORE_GSTATE AGMCORE_key_known not{ /AGMCORE_GSTATE 21 dict def /AGMCORE_tmpmatrix matrix def /AGMCORE_gstack 32 array def /AGMCORE_gstackptr 0 def /AGMCORE_gstacksaveptr 0 def /AGMCORE_gstackframekeys 10 def /AGMCORE_&gsave /gsave ldf /AGMCORE_&grestore /grestore ldf /AGMCORE_&grestoreall /grestoreall ldf /AGMCORE_&save /save ldf /AGMCORE_gdictcopy { begin { def } forall end }def /AGMCORE_gput { AGMCORE_gstack AGMCORE_gstackptr get 3 1 roll put }def /AGMCORE_gget { AGMCORE_gstack AGMCORE_gstackptr get exch get }def /gsave { AGMCORE_&gsave AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gstackptr 1 add dup 32 ge {limitcheck} if Adobe_AGM_Core exch /AGMCORE_gstackptr xpt AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gdictcopy }def /grestore { AGMCORE_&grestore AGMCORE_gstackptr 1 sub dup AGMCORE_gstacksaveptr lt {1 add} if Adobe_AGM_Core exch /AGMCORE_gstackptr xpt }def /grestoreall { AGMCORE_&grestoreall Adobe_AGM_Core /AGMCORE_gstackptr AGMCORE_gstacksaveptr put }def /save { AGMCORE_&save AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gstackptr 1 add dup 32 ge {limitcheck} if Adobe_AGM_Core begin /AGMCORE_gstackptr exch def /AGMCORE_gstacksaveptr AGMCORE_gstackptr def end AGMCORE_gstack AGMCORE_gstackptr get AGMCORE_gdictcopy }def 0 1 AGMCORE_gstack length 1 sub { AGMCORE_gstack exch AGMCORE_gstackframekeys dict put } for }if level3 /AGMCORE_&sysshfill AGMCORE_key_known not and { /AGMCORE_&sysshfill systemdict/shfill get def /AGMCORE_&usrshfill /shfill load def /AGMCORE_&sysmakepattern systemdict/makepattern get def /AGMCORE_&usrmakepattern /makepattern load def }if /currentcmykcolor [0 0 0 0] AGMCORE_gput /currentstrokeadjust false AGMCORE_gput /currentcolorspace [/DeviceGray] AGMCORE_gput /sep_tint 0 AGMCORE_gput /devicen_tints [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] AGMCORE_gput /sep_colorspace_dict null AGMCORE_gput /devicen_colorspace_dict null AGMCORE_gput /indexed_colorspace_dict null AGMCORE_gput /currentcolor_intent () AGMCORE_gput /customcolor_tint 1 AGMCORE_gput << /MaxPatternItem currentsystemparams /MaxPatternCache get >> setuserparams end }def /page_setup { /setcmykcolor where{ pop Adobe_AGM_Core/AGMCORE_&setcmykcolor /setcmykcolor load put }if Adobe_AGM_Core begin /setcmykcolor { 4 copy AGMCORE_cmykbuf astore /currentcmykcolor exch AGMCORE_gput 1 sub 4 1 roll 3 { 3 index add neg dup 0 lt { pop 0 } if 3 1 roll } repeat setrgbcolor pop }ndf /currentcmykcolor { /currentcmykcolor AGMCORE_gget aload pop }ndf /setoverprint { pop }ndf /currentoverprint { false }ndf /AGMCORE_deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt def /AGMCORE_cyan_plate 1 0 0 0 test_cmyk_color_plate def /AGMCORE_magenta_plate 0 1 0 0 test_cmyk_color_plate def /AGMCORE_yellow_plate 0 0 1 0 test_cmyk_color_plate def /AGMCORE_black_plate 0 0 0 1 test_cmyk_color_plate def /AGMCORE_plate_ndx AGMCORE_cyan_plate{ 0 }{ AGMCORE_magenta_plate{ 1 }{ AGMCORE_yellow_plate{ 2 }{ AGMCORE_black_plate{ 3 }{ 4 }ifelse }ifelse }ifelse }ifelse def /AGMCORE_have_reported_unsupported_color_space false def /AGMCORE_report_unsupported_color_space { AGMCORE_have_reported_unsupported_color_space false eq { (Warning: Job contains content that cannot be separated with on-host methods. This content appears on the black plate, and knocks out all other plates.) == Adobe_AGM_Core /AGMCORE_have_reported_unsupported_color_space true ddf } if }def /AGMCORE_composite_job AGMCORE_cyan_plate AGMCORE_magenta_plate and AGMCORE_yellow_plate and AGMCORE_black_plate and def /AGMCORE_in_rip_sep /AGMCORE_in_rip_sep where{ pop AGMCORE_in_rip_sep }{ AGMCORE_distilling { false }{ userdict/Adobe_AGM_OnHost_Seps known{ false }{ level2{ currentpagedevice/Separations 2 copy known{ get }{ pop pop false }ifelse }{ false }ifelse }ifelse }ifelse }ifelse def /AGMCORE_producing_seps AGMCORE_composite_job not AGMCORE_in_rip_sep or def /AGMCORE_host_sep AGMCORE_producing_seps AGMCORE_in_rip_sep not and def /AGM_preserve_spots /AGM_preserve_spots where{ pop AGM_preserve_spots }{ AGMCORE_distilling AGMCORE_producing_seps or }ifelse def /AGM_is_distiller_preserving_spotimages { currentdistillerparams/PreserveOverprintSettings known { currentdistillerparams/PreserveOverprintSettings get { currentdistillerparams/ColorConversionStrategy known { currentdistillerparams/ColorConversionStrategy get /LeaveColorUnchanged eq }{ true }ifelse }{ false }ifelse }{ false }ifelse }def /convert_spot_to_process where {pop}{ /convert_spot_to_process { dup map_alias { /Name get exch pop } if dup dup (None) eq exch (All) eq or { pop false }{ AGMCORE_host_sep { gsave 1 0 0 0 setcmykcolor currentgray 1 exch sub 0 1 0 0 setcmykcolor currentgray 1 exch sub 0 0 1 0 setcmykcolor currentgray 1 exch sub 0 0 0 1 setcmykcolor currentgray 1 exch sub add add add 0 eq { pop false }{ false setoverprint 1 1 1 1 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq }ifelse grestore }{ AGMCORE_distilling { pop AGM_is_distiller_preserving_spotimages not }{ Adobe_AGM_Core/AGMCORE_name xddf false Adobe_AGM_Core/AGMCORE_in_pattern known {Adobe_AGM_Core/AGMCORE_in_pattern get}{false} ifelse not currentpagedevice/OverrideSeparations known and { currentpagedevice/OverrideSeparations get { /HqnSpots /ProcSet resourcestatus { pop pop pop true }if }if }if { AGMCORE_name /HqnSpots /ProcSet findresource /TestSpot get exec not }{ gsave [/Separation AGMCORE_name /DeviceGray {}]setcolorspace false currentpagedevice/SeparationColorNames 2 copy known { get { AGMCORE_name eq or}forall not }{ pop pop pop true }ifelse grestore }ifelse }ifelse }ifelse }ifelse }def }ifelse /convert_to_process where {pop}{ /convert_to_process { dup length 0 eq { pop false }{ AGMCORE_host_sep { dup true exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch dup (Black) eq 3 -1 roll or {pop} {convert_spot_to_process and}ifelse } forall { true exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch (Black) eq or and }forall not }{pop false}ifelse }{ false exch { dup (Cyan) eq exch dup (Magenta) eq 3 -1 roll or exch dup (Yellow) eq 3 -1 roll or exch dup (Black) eq 3 -1 roll or {pop} {convert_spot_to_process or}ifelse } forall }ifelse }ifelse }def }ifelse /AGMCORE_avoid_L2_sep_space version cvr 2012 lt level2 and AGMCORE_producing_seps not and def /AGMCORE_is_cmyk_sep AGMCORE_cyan_plate AGMCORE_magenta_plate or AGMCORE_yellow_plate or AGMCORE_black_plate or def /AGM_avoid_0_cmyk where{ pop AGM_avoid_0_cmyk }{ AGM_preserve_spots userdict/Adobe_AGM_OnHost_Seps known userdict/Adobe_AGM_InRip_Seps known or not and }ifelse { /setcmykcolor[ { 4 copy add add add 0 eq currentoverprint and{ pop 0.0005 }if }/exec cvx /AGMCORE_&setcmykcolor load dup type/operatortype ne{ /exec cvx }if ]cvx def }if AGMCORE_host_sep{ /setcolortransfer { AGMCORE_cyan_plate{ pop pop pop }{ AGMCORE_magenta_plate{ 4 3 roll pop pop pop }{ AGMCORE_yellow_plate{ 4 2 roll pop pop pop }{ 4 1 roll pop pop pop }ifelse }ifelse }ifelse settransfer } def /AGMCORE_get_ink_data AGMCORE_cyan_plate{ {pop pop pop} }{ AGMCORE_magenta_plate{ {4 3 roll pop pop pop} }{ AGMCORE_yellow_plate{ {4 2 roll pop pop pop} }{ {4 1 roll pop pop pop} }ifelse }ifelse }ifelse def /AGMCORE_RemoveProcessColorNames { 1 dict begin /filtername { dup /Cyan eq 1 index (Cyan) eq or {pop (_cyan_)}if dup /Magenta eq 1 index (Magenta) eq or {pop (_magenta_)}if dup /Yellow eq 1 index (Yellow) eq or {pop (_yellow_)}if dup /Black eq 1 index (Black) eq or {pop (_black_)}if }def dup type /arraytype eq {[exch {filtername}forall]} {filtername}ifelse end }def /AGMCORE_IsSeparationAProcessColor { dup (Cyan) eq exch dup (Magenta) eq exch dup (Yellow) eq exch (Black) eq or or or }def level3 { /AGMCORE_IsCurrentColor { gsave false setoverprint 1 1 1 1 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq grestore }def /AGMCORE_filter_functiondatasource { 5 dict begin /data_in xdf data_in type /stringtype eq { /ncomp xdf /comp xdf /string_out data_in length ncomp idiv string def 0 ncomp data_in length 1 sub { string_out exch dup ncomp idiv exch data_in exch ncomp getinterval comp get 255 exch sub put }for string_out }{ string /string_in xdf /string_out 1 string def /component xdf [ data_in string_in /readstring cvx [component /get cvx 255 /exch cvx /sub cvx string_out /exch cvx 0 /exch cvx /put cvx string_out]cvx [/pop cvx ()]cvx /ifelse cvx ]cvx /ReusableStreamDecode filter }ifelse end }def /AGMCORE_separateShadingFunction { 2 dict begin /paint? xdf /channel xdf begin FunctionType 0 eq { /DataSource channel Range length 2 idiv DataSource AGMCORE_filter_functiondatasource def currentdict /Decode known {/Decode Decode channel 2 mul 2 getinterval def}if paint? not {/Decode [1 1]def}if }if FunctionType 2 eq { paint? { /C0 [C0 channel get 1 exch sub] def /C1 [C1 channel get 1 exch sub] def }{ /C0 [1] def /C1 [1] def }ifelse }if FunctionType 3 eq { /Functions [Functions {channel paint? AGMCORE_separateShadingFunction} forall] def }if currentdict /Range known {/Range [0 1] def}if currentdict end end }def /AGMCORE_separateShading { 3 -1 roll begin currentdict /Function known { currentdict /Background known {[1 index{Background 3 index get 1 exch sub}{1}ifelse]/Background xdf}if Function 3 1 roll AGMCORE_separateShadingFunction /Function xdf /ColorSpace [/DeviceGray] def }{ ColorSpace dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [/DeviceN [/_cyan_ /_magenta_ /_yellow_ /_black_] /DeviceCMYK {}] def }{ ColorSpace dup 1 get AGMCORE_RemoveProcessColorNames 1 exch put }ifelse ColorSpace 0 get /Separation eq { { [1 /exch cvx /sub cvx]cvx }{ [/pop cvx 1]cvx }ifelse ColorSpace 3 3 -1 roll put pop }{ { [exch ColorSpace 1 get length 1 sub exch sub /index cvx 1 /exch cvx /sub cvx ColorSpace 1 get length 1 add 1 /roll cvx ColorSpace 1 get length{/pop cvx} repeat]cvx }{ pop [ColorSpace 1 get length {/pop cvx} repeat cvx 1]cvx }ifelse ColorSpace 3 3 -1 roll bind put }ifelse ColorSpace 2 /DeviceGray put }ifelse end }def /AGMCORE_separateShadingDict { dup /ColorSpace get dup type /arraytype ne {[exch]}if dup 0 get /DeviceCMYK eq { exch begin currentdict AGMCORE_cyan_plate {0 true}if AGMCORE_magenta_plate {1 true}if AGMCORE_yellow_plate {2 true}if AGMCORE_black_plate {3 true}if AGMCORE_plate_ndx 4 eq {0 false}if dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading currentdict end exch }if dup 0 get /Separation eq { exch begin ColorSpace 1 get dup /None ne exch /All ne and { ColorSpace 1 get AGMCORE_IsCurrentColor AGMCORE_plate_ndx 4 lt and ColorSpace 1 get AGMCORE_IsSeparationAProcessColor not and { ColorSpace 2 get dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [ /Separation ColorSpace 1 get /DeviceGray [ ColorSpace 3 get /exec cvx 4 AGMCORE_plate_ndx sub -1 /roll cvx 4 1 /roll cvx 3 [/pop cvx]cvx /repeat cvx 1 /exch cvx /sub cvx ]cvx ]def }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { currentdict 0 false AGMCORE_separateShading }if }ifelse }{ currentdict ColorSpace 1 get AGMCORE_IsCurrentColor 0 exch dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading }ifelse }if currentdict end exch }if dup 0 get /DeviceN eq { exch begin ColorSpace 1 get convert_to_process { ColorSpace 2 get dup type /arraytype eq {0 get}if /DeviceCMYK eq { /ColorSpace [ /DeviceN ColorSpace 1 get /DeviceGray [ ColorSpace 3 get /exec cvx 4 AGMCORE_plate_ndx sub -1 /roll cvx 4 1 /roll cvx 3 [/pop cvx]cvx /repeat cvx 1 /exch cvx /sub cvx ]cvx ]def }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { currentdict 0 false AGMCORE_separateShading /ColorSpace [/DeviceGray] def }if }ifelse }{ currentdict false -1 ColorSpace 1 get { AGMCORE_IsCurrentColor { 1 add exch pop true exch exit }if 1 add }forall exch dup not currentoverprint and {/AGMCORE_ignoreshade true def}if AGMCORE_separateShading }ifelse currentdict end exch }if dup 0 get dup /DeviceCMYK eq exch dup /Separation eq exch /DeviceN eq or or not { exch begin ColorSpace dup type /arraytype eq {0 get}if /DeviceGray ne { AGMCORE_report_unsupported_color_space AGMCORE_black_plate not { ColorSpace 0 get /CIEBasedA eq { /ColorSpace [/Separation /_ciebaseda_ /DeviceGray {}] def }if ColorSpace 0 get dup /CIEBasedABC eq exch dup /CIEBasedDEF eq exch /DeviceRGB eq or or { /ColorSpace [/DeviceN [/_red_ /_green_ /_blue_] /DeviceRGB {}] def }if ColorSpace 0 get /CIEBasedDEFG eq { /ColorSpace [/DeviceN [/_cyan_ /_magenta_ /_yellow_ /_black_] /DeviceCMYK {}] }if currentdict 0 false AGMCORE_separateShading }if }if currentdict end exch }if pop dup /AGMCORE_ignoreshade known { begin /ColorSpace [/Separation (None) /DeviceGray {}] def currentdict end }if }def /shfill { clonedict AGMCORE_separateShadingDict dup /AGMCORE_ignoreshade known {pop} {AGMCORE_&sysshfill}ifelse }def /makepattern { exch dup /PatternType get 2 eq { clonedict begin /Shading Shading AGMCORE_separateShadingDict def currentdict end exch AGMCORE_&sysmakepattern }{ exch AGMCORE_&usrmakepattern }ifelse }def }if }if AGMCORE_in_rip_sep{ /setcustomcolor { exch aload pop dup 7 1 roll inRip_spot_has_ink not { 4 {4 index mul 4 1 roll} repeat /DeviceCMYK setcolorspace 6 -2 roll pop pop }{ Adobe_AGM_Core begin /AGMCORE_k xdf /AGMCORE_y xdf /AGMCORE_m xdf /AGMCORE_c xdf end [/Separation 4 -1 roll /DeviceCMYK {dup AGMCORE_c mul exch dup AGMCORE_m mul exch dup AGMCORE_y mul exch AGMCORE_k mul} ] setcolorspace }ifelse setcolor }ndf /setseparationgray { [/Separation (All) /DeviceGray {}] setcolorspace_opt 1 exch sub setcolor }ndf }{ /setseparationgray { AGMCORE_&setgray }ndf }ifelse /findcmykcustomcolor { 5 makereadonlyarray }ndf /setcustomcolor { exch aload pop pop 4 {4 index mul 4 1 roll} repeat setcmykcolor pop }ndf /has_color /colorimage where{ AGMCORE_producing_seps{ pop true }{ systemdict eq }ifelse }{ false }ifelse def /map_index { 1 index mul exch getinterval {255 div} forall } bdf /map_indexed_devn { Lookup Names length 3 -1 roll cvi map_index } bdf /n_color_components { base_colorspace_type dup /DeviceGray eq{ pop 1 }{ /DeviceCMYK eq{ 4 }{ 3 }ifelse }ifelse }bdf level2{ /mo /moveto ldf /li /lineto ldf /cv /curveto ldf /knockout_unitsq { 1 setgray 0 0 1 1 rectfill }def /level2ScreenFreq{ begin 60 HalftoneType 1 eq{ pop Frequency }if HalftoneType 2 eq{ pop GrayFrequency }if HalftoneType 5 eq{ pop Default level2ScreenFreq }if end }def /currentScreenFreq{ currenthalftone level2ScreenFreq }def level2 /setcolorspace AGMCORE_key_known not and{ /AGMCORE_&&&setcolorspace /setcolorspace ldf /AGMCORE_ReplaceMappedColor { dup type dup /arraytype eq exch /packedarraytype eq or { dup 0 get dup /Separation eq { pop dup length array copy dup dup 1 get current_spot_alias { dup map_alias { begin /sep_colorspace_dict currentdict AGMCORE_gput pop pop pop [ /Separation Name CSA map_csa dup /MappedCSA xdf /sep_colorspace_proc load ] dup Name end }if }if map_reserved_ink_name 1 xpt }{ /DeviceN eq { dup length array copy dup dup 1 get [ exch { current_spot_alias{ dup map_alias{ /Name get exch pop }if }if map_reserved_ink_name } forall ] 1 xpt }if }ifelse }if }def /setcolorspace { dup type dup /arraytype eq exch /packedarraytype eq or { dup 0 get /Indexed eq { AGMCORE_distilling { /PhotoshopDuotoneList where { pop false }{ true }ifelse }{ true }ifelse { aload pop 3 -1 roll AGMCORE_ReplaceMappedColor 3 1 roll 4 array astore }if }{ AGMCORE_ReplaceMappedColor }ifelse }if DeviceN_PS2_inRip_seps {AGMCORE_&&&setcolorspace} if }def }if }{ /adj { currentstrokeadjust{ transform 0.25 sub round 0.25 add exch 0.25 sub round 0.25 add exch itransform }if }def /mo{ adj moveto }def /li{ adj lineto }def /cv{ 6 2 roll adj 6 2 roll adj 6 2 roll adj curveto }def /knockout_unitsq { 1 setgray 8 8 1 [8 0 0 8 0 0] {<ffffffffffffffff>} image }def /currentstrokeadjust{ /currentstrokeadjust AGMCORE_gget }def /setstrokeadjust{ /currentstrokeadjust exch AGMCORE_gput }def /currentScreenFreq{ currentscreen pop pop }def /setcolorspace { /currentcolorspace exch AGMCORE_gput } def /currentcolorspace { /currentcolorspace AGMCORE_gget } def /setcolor_devicecolor { base_colorspace_type dup /DeviceGray eq{ pop setgray }{ /DeviceCMYK eq{ setcmykcolor }{ setrgbcolor }ifelse }ifelse }def /setcolor { currentcolorspace 0 get dup /DeviceGray ne{ dup /DeviceCMYK ne{ dup /DeviceRGB ne{ dup /Separation eq{ pop currentcolorspace 3 get exec currentcolorspace 2 get }{ dup /Indexed eq{ pop currentcolorspace 3 get dup type /stringtype eq{ currentcolorspace 1 get n_color_components 3 -1 roll map_index }{ exec }ifelse currentcolorspace 1 get }{ /AGMCORE_cur_err /AGMCORE_invalid_color_space def AGMCORE_invalid_color_space }ifelse }ifelse }if }if }if setcolor_devicecolor } def }ifelse /sop /setoverprint ldf /lw /setlinewidth ldf /lc /setlinecap ldf /lj /setlinejoin ldf /ml /setmiterlimit ldf /dsh /setdash ldf /sadj /setstrokeadjust ldf /gry /setgray ldf /rgb /setrgbcolor ldf /cmyk /setcmykcolor ldf /sep /setsepcolor ldf /devn /setdevicencolor ldf /idx /setindexedcolor ldf /colr /setcolor ldf /csacrd /set_csa_crd ldf /sepcs /setsepcolorspace ldf /devncs /setdevicencolorspace ldf /idxcs /setindexedcolorspace ldf /cp /closepath ldf /clp /clp_npth ldf /eclp /eoclp_npth ldf /f /fill ldf /ef /eofill ldf /@ /stroke ldf /nclp /npth_clp ldf /gset /graphic_setup ldf /gcln /graphic_cleanup ldf currentdict{ dup xcheck 1 index type dup /arraytype eq exch /packedarraytype eq or and { bind }if def }forall /currentpagedevice currentpagedevice def /getrampcolor { /indx exch def 0 1 NumComp 1 sub { dup Samples exch get dup type /stringtype eq { indx get } if exch Scaling exch get aload pop 3 1 roll mul add } for ColorSpaceFamily /Separation eq { sep } { ColorSpaceFamily /DeviceN eq { devn } { setcolor }ifelse }ifelse } bind def /sssetbackground { aload pop setcolor } bind def /RadialShade { 40 dict begin /ColorSpaceFamily exch def /background exch def /ext1 exch def /ext0 exch def /BBox exch def /r2 exch def /c2y exch def /c2x exch def /r1 exch def /c1y exch def /c1x exch def /rampdict exch def /setinkoverprint where {pop /setinkoverprint{pop}def}if gsave BBox length 0 gt { newpath BBox 0 get BBox 1 get moveto BBox 2 get BBox 0 get sub 0 rlineto 0 BBox 3 get BBox 1 get sub rlineto BBox 2 get BBox 0 get sub neg 0 rlineto closepath clip newpath } if c1x c2x eq { c1y c2y lt {/theta 90 def}{/theta 270 def} ifelse } { /slope c2y c1y sub c2x c1x sub div def /theta slope 1 atan def c2x c1x lt c2y c1y ge and { /theta theta 180 sub def} if c2x c1x lt c2y c1y lt and { /theta theta 180 add def} if } ifelse gsave clippath c1x c1y translate theta rotate -90 rotate { pathbbox } stopped { 0 0 0 0 } if /yMax exch def /xMax exch def /yMin exch def /xMin exch def grestore xMax xMin eq yMax yMin eq or { grestore end } { /max { 2 copy gt { pop } {exch pop} ifelse } bind def /min { 2 copy lt { pop } {exch pop} ifelse } bind def rampdict begin 40 dict begin background length 0 gt { background sssetbackground gsave clippath fill grestore } if gsave c1x c1y translate theta rotate -90 rotate /c2y c1x c2x sub dup mul c1y c2y sub dup mul add sqrt def /c1y 0 def /c1x 0 def /c2x 0 def ext0 { 0 getrampcolor c2y r2 add r1 sub 0.0001 lt { c1x c1y r1 360 0 arcn pathbbox /aymax exch def /axmax exch def /aymin exch def /axmin exch def /bxMin xMin axmin min def /byMin yMin aymin min def /bxMax xMax axmax max def /byMax yMax aymax max def bxMin byMin moveto bxMax byMin lineto bxMax byMax lineto bxMin byMax lineto bxMin byMin lineto eofill } { c2y r1 add r2 le { c1x c1y r1 0 360 arc fill } { c2x c2y r2 0 360 arc fill r1 r2 eq { /p1x r1 neg def /p1y c1y def /p2x r1 def /p2y c1y def p1x p1y moveto p2x p2y lineto p2x yMin lineto p1x yMin lineto fill } { /AA r2 r1 sub c2y div def /theta AA 1 AA dup mul sub sqrt div 1 atan def /SS1 90 theta add dup sin exch cos div def /p1x r1 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def /p1y p1x SS1 div neg def /SS2 90 theta sub dup sin exch cos div def /p2x r1 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def /p2y p2x SS2 div neg def r1 r2 gt { /L1maxX p1x yMin p1y sub SS1 div add def /L2maxX p2x yMin p2y sub SS2 div add def } { /L1maxX 0 def /L2maxX 0 def }ifelse p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto L1maxX L1maxX p1x sub SS1 mul p1y add lineto fill } ifelse } ifelse } ifelse } if c1x c2x sub dup mul c1y c2y sub dup mul add 0.5 exp 0 dtransform dup mul exch dup mul add 0.5 exp 72 div 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 1 index 1 index lt { exch } if pop /hires exch def hires mul /numpix exch def /numsteps NumSamples def /rampIndxInc 1 def /subsampling false def numpix 0 ne { NumSamples numpix div 0.5 gt { /numsteps numpix 2 div round cvi dup 1 le { pop 2 } if def /rampIndxInc NumSamples 1 sub numsteps div def /subsampling true def } if } if /xInc c2x c1x sub numsteps div def /yInc c2y c1y sub numsteps div def /rInc r2 r1 sub numsteps div def /cx c1x def /cy c1y def /radius r1 def newpath xInc 0 eq yInc 0 eq rInc 0 eq and and { 0 getrampcolor cx cy radius 0 360 arc stroke NumSamples 1 sub getrampcolor cx cy radius 72 hires div add 0 360 arc 0 setlinewidth stroke } { 0 numsteps { dup subsampling { round cvi } if getrampcolor cx cy radius 0 360 arc /cx cx xInc add def /cy cy yInc add def /radius radius rInc add def cx cy radius 360 0 arcn eofill rampIndxInc add } repeat pop } ifelse ext1 { c2y r2 add r1 lt { c2x c2y r2 0 360 arc fill } { c2y r1 add r2 sub 0.0001 le { c2x c2y r2 360 0 arcn pathbbox /aymax exch def /axmax exch def /aymin exch def /axmin exch def /bxMin xMin axmin min def /byMin yMin aymin min def /bxMax xMax axmax max def /byMax yMax aymax max def bxMin byMin moveto bxMax byMin lineto bxMax byMax lineto bxMin byMax lineto bxMin byMin lineto eofill } { c2x c2y r2 0 360 arc fill r1 r2 eq { /p1x r2 neg def /p1y c2y def /p2x r2 def /p2y c2y def p1x p1y moveto p2x p2y lineto p2x yMax lineto p1x yMax lineto fill } { /AA r2 r1 sub c2y div def /theta AA 1 AA dup mul sub sqrt div 1 atan def /SS1 90 theta add dup sin exch cos div def /p1x r2 SS1 SS1 mul SS1 SS1 mul 1 add div sqrt mul neg def /p1y c2y p1x SS1 div sub def /SS2 90 theta sub dup sin exch cos div def /p2x r2 SS2 SS2 mul SS2 SS2 mul 1 add div sqrt mul def /p2y c2y p2x SS2 div sub def r1 r2 lt { /L1maxX p1x yMax p1y sub SS1 div add def /L2maxX p2x yMax p2y sub SS2 div add def } { /L1maxX 0 def /L2maxX 0 def }ifelse p1x p1y moveto p2x p2y lineto L2maxX L2maxX p2x sub SS2 mul p2y add lineto L1maxX L1maxX p1x sub SS1 mul p1y add lineto fill } ifelse } ifelse } ifelse } if grestore grestore end end end } ifelse } bind def /GenStrips { 40 dict begin /ColorSpaceFamily exch def /background exch def /ext1 exch def /ext0 exch def /BBox exch def /y2 exch def /x2 exch def /y1 exch def /x1 exch def /rampdict exch def /setinkoverprint where {pop /setinkoverprint{pop}def}if gsave BBox length 0 gt { newpath BBox 0 get BBox 1 get moveto BBox 2 get BBox 0 get sub 0 rlineto 0 BBox 3 get BBox 1 get sub rlineto BBox 2 get BBox 0 get sub neg 0 rlineto closepath clip newpath } if x1 x2 eq { y1 y2 lt {/theta 90 def}{/theta 270 def} ifelse } { /slope y2 y1 sub x2 x1 sub div def /theta slope 1 atan def x2 x1 lt y2 y1 ge and { /theta theta 180 sub def} if x2 x1 lt y2 y1 lt and { /theta theta 180 add def} if } ifelse gsave clippath x1 y1 translate theta rotate { pathbbox } stopped { 0 0 0 0 } if /yMax exch def /xMax exch def /yMin exch def /xMin exch def grestore xMax xMin eq yMax yMin eq or { grestore end } { rampdict begin 20 dict begin background length 0 gt { background sssetbackground gsave clippath fill grestore } if gsave x1 y1 translate theta rotate /xStart 0 def /xEnd x2 x1 sub dup mul y2 y1 sub dup mul add 0.5 exp def /ySpan yMax yMin sub def /numsteps NumSamples def /rampIndxInc 1 def /subsampling false def xStart 0 transform xEnd 0 transform 3 -1 roll sub dup mul 3 1 roll sub dup mul add 0.5 exp 72 div 0 72 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt 1 index 1 index lt { exch } if pop mul /numpix exch def numpix 0 ne { NumSamples numpix div 0.5 gt { /numsteps numpix 2 div round cvi dup 1 le { pop 2 } if def /rampIndxInc NumSamples 1 sub numsteps div def /subsampling true def } if } if ext0 { 0 getrampcolor xMin xStart lt { xMin yMin xMin neg ySpan rectfill } if } if /xInc xEnd xStart sub numsteps div def /x xStart def 0 numsteps { dup subsampling { round cvi } if getrampcolor x yMin xInc ySpan rectfill /x x xInc add def rampIndxInc add } repeat pop ext1 { xMax xEnd gt { xEnd yMin xMax xEnd sub ySpan rectfill } if } if grestore grestore end end end } ifelse } bind def }def /page_trailer { end }def /doc_trailer{ }def systemdict /findcolorrendering known{ /findcolorrendering systemdict /findcolorrendering get def }if systemdict /setcolorrendering known{ /setcolorrendering systemdict /setcolorrendering get def }if /test_cmyk_color_plate { gsave setcmykcolor currentgray 1 ne grestore }def /inRip_spot_has_ink { dup Adobe_AGM_Core/AGMCORE_name xddf convert_spot_to_process not }def /map255_to_range { 1 index sub 3 -1 roll 255 div mul add }def /set_csa_crd { /sep_colorspace_dict null AGMCORE_gput begin CSA map_csa setcolorspace_opt set_crd end } def /setsepcolor { /sep_colorspace_dict AGMCORE_gget begin dup /sep_tint exch AGMCORE_gput TintProc end } def /setdevicencolor { /devicen_colorspace_dict AGMCORE_gget begin Names length copy Names length 1 sub -1 0 { /devicen_tints AGMCORE_gget 3 1 roll xpt } for TintProc end } def /sep_colorspace_proc { Adobe_AGM_Core/AGMCORE_tmp xddf /sep_colorspace_dict AGMCORE_gget begin currentdict/Components known{ Components aload pop TintMethod/Lab eq{ 2 {AGMCORE_tmp mul NComponents 1 roll} repeat LMax sub AGMCORE_tmp mul LMax add NComponents 1 roll }{ TintMethod/Subtractive eq{ NComponents{ AGMCORE_tmp mul NComponents 1 roll }repeat }{ NComponents{ 1 sub AGMCORE_tmp mul 1 add NComponents 1 roll } repeat }ifelse }ifelse }{ ColorLookup AGMCORE_tmp ColorLookup length 1 sub mul round cvi get aload pop }ifelse end } def /sep_colorspace_gray_proc { Adobe_AGM_Core/AGMCORE_tmp xddf /sep_colorspace_dict AGMCORE_gget begin GrayLookup AGMCORE_tmp GrayLookup length 1 sub mul round cvi get end } def /sep_proc_name { dup 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or level2 not and has_color not and{ pop [/DeviceGray] /sep_colorspace_gray_proc }{ /sep_colorspace_proc }ifelse } def /setsepcolorspace { current_spot_alias{ dup begin Name map_alias{ exch pop }if end }if dup /sep_colorspace_dict exch AGMCORE_gput begin /MappedCSA CSA map_csa def Adobe_AGM_Core/AGMCORE_sep_special Name dup () eq exch (All) eq or ddf AGMCORE_avoid_L2_sep_space{ [/Indexed MappedCSA sep_proc_name 255 exch { 255 div } /exec cvx 3 -1 roll [ 4 1 roll load /exec cvx ] cvx ] setcolorspace_opt /TintProc { 255 mul round cvi setcolor }bdf }{ MappedCSA 0 get /DeviceCMYK eq currentdict/Components known and AGMCORE_sep_special not and{ /TintProc [ Components aload pop Name findcmykcustomcolor /exch cvx /setcustomcolor cvx ] cvx bdf }{ AGMCORE_host_sep Name (All) eq and{ /TintProc { 1 exch sub setseparationgray }bdf }{ AGMCORE_in_rip_sep MappedCSA 0 get /DeviceCMYK eq and AGMCORE_host_sep or Name () eq and{ /TintProc [ MappedCSA sep_proc_name exch 0 get /DeviceCMYK eq{ cvx /setcmykcolor cvx }{ cvx /setgray cvx }ifelse ] cvx bdf }{ AGMCORE_producing_seps MappedCSA 0 get dup /DeviceCMYK eq exch /DeviceGray eq or and AGMCORE_sep_special not and{ /TintProc [ /dup cvx MappedCSA sep_proc_name cvx exch 0 get /DeviceGray eq{ 1 /exch cvx /sub cvx 0 0 0 4 -1 /roll cvx }if /Name cvx /findcmykcustomcolor cvx /exch cvx AGMCORE_host_sep{ AGMCORE_is_cmyk_sep /Name cvx /AGMCORE_IsSeparationAProcessColor load /exec cvx /not cvx /and cvx }{ Name inRip_spot_has_ink not }ifelse [ /pop cvx 1 ] cvx /if cvx /setcustomcolor cvx ] cvx bdf }{ /TintProc /setcolor ldf [/Separation Name MappedCSA sep_proc_name load ] setcolorspace_opt }ifelse }ifelse }ifelse }ifelse }ifelse set_crd setsepcolor end } def /additive_blend { 3 dict begin /numarrays xdf /numcolors xdf 0 1 numcolors 1 sub { /c1 xdf 1 0 1 numarrays 1 sub { 1 exch add /index cvx c1 /get cvx /mul cvx }for numarrays 1 add 1 /roll cvx }for numarrays [/pop cvx] cvx /repeat cvx end }def /subtractive_blend { 3 dict begin /numarrays xdf /numcolors xdf 0 1 numcolors 1 sub { /c1 xdf 1 1 0 1 numarrays 1 sub { 1 3 3 -1 roll add /index cvx c1 /get cvx /sub cvx /mul cvx }for /sub cvx numarrays 1 add 1 /roll cvx }for numarrays [/pop cvx] cvx /repeat cvx end }def /exec_tint_transform { /TintProc [ /TintTransform cvx /setcolor cvx ] cvx bdf MappedCSA setcolorspace_opt } bdf /devn_makecustomcolor { 2 dict begin /names_index xdf /Names xdf 1 1 1 1 Names names_index get findcmykcustomcolor /devicen_tints AGMCORE_gget names_index get setcustomcolor Names length {pop} repeat end } bdf /setdevicencolorspace { dup /AliasedColorants known {false}{true}ifelse current_spot_alias and { 6 dict begin /names_index 0 def dup /names_len exch /Names get length def /new_names names_len array def /new_LookupTables names_len array def /alias_cnt 0 def dup /Names get { dup map_alias { exch pop dup /ColorLookup known { dup begin new_LookupTables names_index ColorLookup put end }{ dup /Components known { dup begin new_LookupTables names_index Components put end }{ dup begin new_LookupTables names_index [null null null null] put end } ifelse } ifelse new_names names_index 3 -1 roll /Name get put /alias_cnt alias_cnt 1 add def }{ /name xdf new_names names_index name put dup /LookupTables known { dup begin new_LookupTables names_index LookupTables names_index get put end }{ dup begin new_LookupTables names_index [null null null null] put end } ifelse } ifelse /names_index names_index 1 add def } forall alias_cnt 0 gt { /AliasedColorants true def 0 1 names_len 1 sub { /names_index xdf new_LookupTables names_index get 0 get null eq { dup /Names get names_index get /name xdf name (Cyan) eq name (Magenta) eq name (Yellow) eq name (Black) eq or or or not { /AliasedColorants false def exit } if } if } for AliasedColorants { dup begin /Names new_names def /AliasedColorants true def /LookupTables new_LookupTables def currentdict /TTTablesIdx known not { /TTTablesIdx -1 def } if currentdict /NComponents known not { /NComponents TintMethod /Subtractive eq {4}{3}ifelse def } if end } if }if end } if dup /devicen_colorspace_dict exch AGMCORE_gput begin /MappedCSA CSA map_csa def currentdict /AliasedColorants known { AliasedColorants }{ false } ifelse /TintTransform load type /nulltype eq or { /TintTransform [ 0 1 Names length 1 sub { /TTTablesIdx TTTablesIdx 1 add def dup LookupTables exch get dup 0 get null eq { 1 index Names exch get dup (Cyan) eq { pop exch LookupTables length exch sub /index cvx 0 0 0 } { dup (Magenta) eq { pop exch LookupTables length exch sub /index cvx 0 /exch cvx 0 0 } { (Yellow) eq { exch LookupTables length exch sub /index cvx 0 0 3 -1 /roll cvx 0 } { exch LookupTables length exch sub /index cvx 0 0 0 4 -1 /roll cvx } ifelse } ifelse } ifelse 5 -1 /roll cvx /astore cvx } { dup length 1 sub LookupTables length 4 -1 roll sub 1 add /index cvx /mul cvx /round cvx /cvi cvx /get cvx } ifelse Names length TTTablesIdx add 1 add 1 /roll cvx } for Names length [/pop cvx] cvx /repeat cvx NComponents Names length TintMethod /Subtractive eq { subtractive_blend } { additive_blend } ifelse ] cvx bdf } if AGMCORE_host_sep { Names convert_to_process { exec_tint_transform } { currentdict /AliasedColorants known { AliasedColorants not }{ false } ifelse 5 dict begin /AvoidAliasedColorants xdf /painted? false def /names_index 0 def /names_len Names length def Names { AvoidAliasedColorants { /currentspotalias current_spot_alias def false set_spot_alias } if AGMCORE_is_cmyk_sep { dup (Cyan) eq AGMCORE_cyan_plate and exch dup (Magenta) eq AGMCORE_magenta_plate and exch dup (Yellow) eq AGMCORE_yellow_plate and exch (Black) eq AGMCORE_black_plate and or or or { /devicen_colorspace_dict AGMCORE_gget /TintProc [ Names names_index /devn_makecustomcolor cvx ] cvx ddf /painted? true def } if painted? {exit} if }{ 0 0 0 0 5 -1 roll findcmykcustomcolor 1 setcustomcolor currentgray 0 eq { /devicen_colorspace_dict AGMCORE_gget /TintProc [ Names names_index /devn_makecustomcolor cvx ] cvx ddf /painted? true def exit } if } ifelse AvoidAliasedColorants { currentspotalias set_spot_alias } if /names_index names_index 1 add def } forall painted? { /devicen_colorspace_dict AGMCORE_gget /names_index names_index put }{ /devicen_colorspace_dict AGMCORE_gget /TintProc [ names_len [/pop cvx] cvx /repeat cvx 1 /setseparationgray cvx 0 0 0 0 () /findcmykcustomcolor cvx 0 /setcustomcolor cvx ] cvx ddf } ifelse end } ifelse } { AGMCORE_in_rip_sep { Names convert_to_process not }{ level3 } ifelse { [/DeviceN Names MappedCSA /TintTransform load] setcolorspace_opt /TintProc level3 not AGMCORE_in_rip_sep and { [ Names /length cvx [/pop cvx] cvx /repeat cvx ] cvx bdf }{ /setcolor ldf } ifelse }{ exec_tint_transform } ifelse } ifelse set_crd /AliasedColorants false def end } def /setindexedcolorspace { dup /indexed_colorspace_dict exch AGMCORE_gput begin currentdict /CSD known { CSD get_csd /Names known { CSD get_csd begin currentdict devncs AGMCORE_host_sep{ 4 dict begin /devnCompCnt Names length def /NewLookup HiVal 1 add string def 0 1 HiVal { /tableIndex xdf Lookup dup type /stringtype eq { devnCompCnt tableIndex map_index }{ exec } ifelse setdevicencolor currentgray tableIndex exch HiVal mul cvi NewLookup 3 1 roll put } for [/Indexed currentcolorspace HiVal NewLookup] setcolorspace_opt end }{ level3 { [/Indexed [/DeviceN Names MappedCSA /TintTransform load] HiVal Lookup] setcolorspace_opt }{ [/Indexed MappedCSA HiVal [ Lookup dup type /stringtype eq {/exch cvx CSD get_csd /Names get length dup /mul cvx exch /getinterval cvx {255 div} /forall cvx} {/exec cvx}ifelse /TintTransform load /exec cvx ]cvx ]setcolorspace_opt }ifelse } ifelse end }{ } ifelse set_crd } { /MappedCSA CSA map_csa def AGMCORE_host_sep level2 not and{ 0 0 0 0 setcmykcolor }{ [/Indexed MappedCSA level2 not has_color not and{ dup 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or{ pop [/DeviceGray] }if HiVal GrayLookup }{ HiVal currentdict/RangeArray known{ { /indexed_colorspace_dict AGMCORE_gget begin Lookup exch dup HiVal gt{ pop HiVal }if NComponents mul NComponents getinterval {} forall NComponents 1 sub -1 0{ RangeArray exch 2 mul 2 getinterval aload pop map255_to_range NComponents 1 roll }for end } bind }{ Lookup }ifelse }ifelse ] setcolorspace_opt set_crd }ifelse }ifelse end }def /setindexedcolor { AGMCORE_host_sep { /indexed_colorspace_dict AGMCORE_gget dup /CSD known { begin CSD get_csd begin map_indexed_devn devn end end }{ AGMCORE_gget/Lookup get 4 3 -1 roll map_index pop setcmykcolor } ifelse }{ level3 not AGMCORE_in_rip_sep and /indexed_colorspace_dict AGMCORE_gget /CSD known and { /indexed_colorspace_dict AGMCORE_gget /CSD get get_csd begin map_indexed_devn devn end } { setcolor } ifelse }ifelse } def /ignoreimagedata { currentoverprint not{ gsave dup clonedict begin 1 setgray /Decode [0 1] def /DataSource <FF> def /MultipleDataSources false def /BitsPerComponent 8 def currentdict end systemdict /image get exec grestore }if consumeimagedata }def /add_csa { Adobe_AGM_Core begin /AGMCORE_CSA_cache xput end }def /get_csa_by_name { dup type dup /nametype eq exch /stringtype eq or{ Adobe_AGM_Core begin 1 dict begin /name xdf AGMCORE_CSA_cache { 0 get name eq { exit }{ pop } ifelse }forall end end }{ pop } ifelse }def /map_csa { dup type /nametype eq{ Adobe_AGM_Core/AGMCORE_CSA_cache get exch get }if }def /add_csd { Adobe_AGM_Core begin /AGMCORE_CSD_cache xput end }def /get_csd { dup type /nametype eq{ Adobe_AGM_Core/AGMCORE_CSD_cache get exch get }if }def /pattern_buf_init { /count get 0 0 put } def /pattern_buf_next { dup /count get dup 0 get dup 3 1 roll 1 add 0 xpt get } def /cachepattern_compress { 5 dict begin currentfile exch 0 exch /SubFileDecode filter /ReadFilter exch def /patarray 20 dict def /string_size 16000 def /readbuffer string_size string def currentglobal true setglobal patarray 1 array dup 0 1 put /count xpt setglobal /LZWFilter { exch dup length 0 eq { pop }{ patarray dup length 1 sub 3 -1 roll put } ifelse {string_size}{0}ifelse string } /LZWEncode filter def { ReadFilter readbuffer readstring exch LZWFilter exch writestring not {exit} if } loop LZWFilter closefile patarray end }def /cachepattern { 2 dict begin currentfile exch 0 exch /SubFileDecode filter /ReadFilter exch def /patarray 20 dict def currentglobal true setglobal patarray 1 array dup 0 1 put /count xpt setglobal { ReadFilter 16000 string readstring exch patarray dup length 1 sub 3 -1 roll put not {exit} if } loop patarray dup dup length 1 sub () put end }def /add_pattern { Adobe_AGM_Core begin /AGMCORE_pattern_cache xput end }def /get_pattern { dup type /nametype eq{ Adobe_AGM_Core/AGMCORE_pattern_cache get exch get dup wrap_paintproc }if }def /wrap_paintproc { statusdict /currentfilenameextend known{ begin /OldPaintProc /PaintProc load def /PaintProc { mark exch dup /OldPaintProc get stopped {closefile restore end} if cleartomark } def end } {pop} ifelse } def /make_pattern { dup matrix currentmatrix matrix concatmatrix 0 0 3 2 roll itransform exch 3 index /XStep get 1 index exch 2 copy div cvi mul sub sub exch 3 index /YStep get 1 index exch 2 copy div cvi mul sub sub matrix translate exch matrix concatmatrix 1 index begin BBox 0 get XStep div cvi XStep mul /xshift exch neg def BBox 1 get YStep div cvi YStep mul /yshift exch neg def BBox 0 get xshift add BBox 1 get yshift add BBox 2 get xshift add BBox 3 get yshift add 4 array astore /BBox exch def [ xshift yshift /translate load null /exec load ] dup 3 /PaintProc load put cvx /PaintProc exch def end gsave 0 setgray makepattern grestore }def /set_pattern { dup /PatternType get 1 eq{ dup /PaintType get 1 eq{ currentoverprint sop [/DeviceGray] setcolorspace 0 setgray }if }if setpattern }def /setcolorspace_opt { dup currentcolorspace eq{ pop }{ setcolorspace }ifelse }def /updatecolorrendering { currentcolorrendering/Intent known{ currentcolorrendering/Intent get }{ null }ifelse Intent ne{ false Intent AGMCORE_CRD_cache { exch pop begin dup Intent eq{ currentdict setcolorrendering_opt end exch pop true exch exit }if end } forall pop not{ systemdict /findcolorrendering known{ Intent findcolorrendering pop /ColorRendering findresource dup length dict copy setcolorrendering_opt }if }if }if } def /add_crd { AGMCORE_CRD_cache 3 1 roll put }def /set_crd { AGMCORE_host_sep not level2 and{ currentdict/CRD known{ AGMCORE_CRD_cache CRD get dup null ne{ setcolorrendering_opt }{ pop }ifelse }{ currentdict/Intent known{ updatecolorrendering }if }ifelse currentcolorspace dup type /arraytype eq {0 get}if /DeviceRGB eq { currentdict/UCR known {/UCR}{/AGMCORE_currentucr}ifelse load setundercolorremoval currentdict/BG known {/BG}{/AGMCORE_currentbg}ifelse load setblackgeneration }if }if }def /setcolorrendering_opt { dup currentcolorrendering eq{ pop }{ begin /Intent Intent def currentdict end setcolorrendering }ifelse }def /cpaint_gcomp { convert_to_process Adobe_AGM_Core/AGMCORE_ConvertToProcess xddf Adobe_AGM_Core/AGMCORE_ConvertToProcess get not { (%end_cpaint_gcomp) flushinput }if }def /cpaint_gsep { Adobe_AGM_Core/AGMCORE_ConvertToProcess get { (%end_cpaint_gsep) flushinput }if }def /cpaint_gend { newpath }def /path_rez { dup 0 ne{ AGMCORE_deviceDPI exch div dup 1 lt{ pop 1 }if setflat }{ pop }ifelse }def /set_spot_alias_ary { /AGMCORE_SpotAliasAry where{ pop pop }{ Adobe_AGM_Core/AGMCORE_SpotAliasAry xddf true set_spot_alias }ifelse }def /set_spot_alias { /AGMCORE_SpotAliasAry where{ /AGMCORE_current_spot_alias 3 -1 roll put }{ pop }ifelse }def /current_spot_alias { /AGMCORE_SpotAliasAry where{ /AGMCORE_current_spot_alias get }{ false }ifelse }def /map_alias { /AGMCORE_SpotAliasAry where{ begin /AGMCORE_name xdf false AGMCORE_SpotAliasAry{ dup/Name get AGMCORE_name eq{ save exch /Adobe_AGM_Core currentdict def /CSD get get_csd exch restore exch pop true exit }{ pop }ifelse }forall end }{ pop false }ifelse }bdf /spot_alias { true set_spot_alias /AGMCORE_&setcustomcolor AGMCORE_key_known not { Adobe_AGM_Core/AGMCORE_&setcustomcolor /setcustomcolor load put } if /customcolor_tint 1 AGMCORE_gput Adobe_AGM_Core begin /setcustomcolor { dup /customcolor_tint exch AGMCORE_gput current_spot_alias{ 1 index 4 get map_alias{ mark 3 1 roll setsepcolorspace counttomark 0 ne{ setsepcolor }if pop pop }{ AGMCORE_&setcustomcolor }ifelse }{ AGMCORE_&setcustomcolor }ifelse }bdf end }def /begin_feature { Adobe_AGM_Core/AGMCORE_feature_dictCount countdictstack put count Adobe_AGM_Core/AGMCORE_feature_opCount 3 -1 roll put {Adobe_AGM_Core/AGMCORE_feature_ctm matrix currentmatrix put}if }def /end_feature { 2 dict begin /spd /setpagedevice load def /setpagedevice { get_gstate spd set_gstate } def stopped{$error/newerror false put}if end count Adobe_AGM_Core/AGMCORE_feature_opCount get sub dup 0 gt{{pop}repeat}{pop}ifelse countdictstack Adobe_AGM_Core/AGMCORE_feature_dictCount get sub dup 0 gt{{end}repeat}{pop}ifelse {Adobe_AGM_Core/AGMCORE_feature_ctm get setmatrix}if }def /set_negative { Adobe_AGM_Core begin /AGMCORE_inverting exch def level2{ currentpagedevice/NegativePrint known{ currentpagedevice/NegativePrint get Adobe_AGM_Core/AGMCORE_inverting get ne{ true begin_feature true{ bdict /NegativePrint Adobe_AGM_Core/AGMCORE_inverting get edict setpagedevice }end_feature }if /AGMCORE_inverting false def }if }if AGMCORE_inverting{ [{1 exch sub}/exec load dup currenttransfer exch]cvx bind settransfer gsave newpath clippath 1 /setseparationgray where{pop setseparationgray}{setgray}ifelse /AGMIRS_&fill where {pop AGMIRS_&fill}{fill} ifelse grestore }if end }def /lw_save_restore_override { /md where { pop md begin initializepage /initializepage{}def /pmSVsetup{} def /endp{}def /pse{}def /psb{}def /orig_showpage where {pop} {/orig_showpage /showpage load def} ifelse /showpage {orig_showpage gR} def end }if }def /pscript_showpage_override { /NTPSOct95 where { begin showpage save /showpage /restore load def /restore {exch pop}def end }if }def /driver_media_override { /md where { pop md /initializepage known { md /initializepage {} put } if md /rC known { md /rC {4{pop}repeat} put } if }if /mysetup where { /mysetup [1 0 0 1 0 0] put }if Adobe_AGM_Core /AGMCORE_Default_CTM matrix currentmatrix put level2 {Adobe_AGM_Core /AGMCORE_Default_PageSize currentpagedevice/PageSize get put}if }def /driver_check_media_override { /PrepsDict where {pop} { Adobe_AGM_Core /AGMCORE_Default_CTM get matrix currentmatrix ne Adobe_AGM_Core /AGMCORE_Default_PageSize get type /arraytype eq { Adobe_AGM_Core /AGMCORE_Default_PageSize get 0 get currentpagedevice/PageSize get 0 get eq and Adobe_AGM_Core /AGMCORE_Default_PageSize get 1 get currentpagedevice/PageSize get 1 get eq and }if { Adobe_AGM_Core /AGMCORE_Default_CTM get setmatrix }if }ifelse }def AGMCORE_err_strings begin /AGMCORE_bad_environ (Environment not satisfactory for this job. Ensure that the PPD is correct or that the PostScript level requested is supported by this printer. ) def /AGMCORE_color_space_onhost_seps (This job contains colors that will not separate with on-host methods. ) def /AGMCORE_invalid_color_space (This job contains an invalid color space. ) def end end systemdict /setpacking known { setpacking } if %%EndResource %%BeginResource: procset Adobe_CoolType_Core 2.23 0 %%Copyright: Copyright 1997-2003 Adobe Systems Incorporated. All Rights Reserved. %%Version: 2.23 0 10 dict begin /Adobe_CoolType_Passthru currentdict def /Adobe_CoolType_Core_Defined userdict /Adobe_CoolType_Core known def Adobe_CoolType_Core_Defined { /Adobe_CoolType_Core userdict /Adobe_CoolType_Core get def } if userdict /Adobe_CoolType_Core 60 dict dup begin put /Adobe_CoolType_Version 2.23 def /Level2? systemdict /languagelevel known dup { pop systemdict /languagelevel get 2 ge } if def Level2? not { /currentglobal false def /setglobal /pop load def /gcheck { pop false } bind def /currentpacking false def /setpacking /pop load def /SharedFontDirectory 0 dict def } if currentpacking true setpacking /@_SaveStackLevels { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 2 copy known not { 2 copy 3 dict dup /args 7 index 5 add array put put get } { get dup /args get dup length 3 index lt { dup length 5 add array exch 1 index exch 0 exch putinterval 1 index exch /args exch put } { pop } ifelse } ifelse begin count 2 sub 1 index lt { pop count 1 sub } if dup /argCount exch def dup 0 gt { exch 1 index 2 add 1 roll args exch 0 exch getinterval astore pop } { pop } ifelse count 1 sub /restCount exch def end /@opStackLevel @opStackLevel 1 add def countdictstack 1 sub @dictStackCountByLevel exch @dictStackLevel exch put /@dictStackLevel @dictStackLevel 1 add def end } bind def /@_RestoreStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def @opStackCountByLevel @opStackLevel get begin count restCount sub dup 0 gt { { pop } repeat } { pop } ifelse args 0 argCount getinterval {} forall end /@dictStackLevel @dictStackLevel 1 sub def @dictStackCountByLevel @dictStackLevel get end countdictstack exch sub dup 0 gt { { end } repeat } { pop } ifelse } bind def /@_PopStackLevels { Adobe_CoolType_Data begin /@opStackLevel @opStackLevel 1 sub def /@dictStackLevel @dictStackLevel 1 sub def end } bind def /@Raise { exch cvx exch errordict exch get exec stop } bind def /@ReRaise { cvx $error /errorname get errordict exch get exec stop } bind def /@Stopped { 0 @#Stopped } bind def /@#Stopped { @_SaveStackLevels stopped { @_RestoreStackLevels true } { @_PopStackLevels false } ifelse } bind def /@Arg { Adobe_CoolType_Data begin @opStackCountByLevel @opStackLevel 1 sub get /args get exch get end } bind def currentglobal true setglobal /CTHasResourceForAllBug Level2? { 1 dict dup begin mark { (*) { pop stop } 128 string /Category resourceforall } stopped cleartomark currentdict eq dup { end } if not } { false } ifelse def /CTHasResourceStatusBug Level2? { mark { /steveamerige /Category resourcestatus } stopped { cleartomark true } { cleartomark currentglobal not } ifelse } { false } ifelse def setglobal /CTResourceStatus { mark 3 1 roll /Category findresource begin ({ResourceStatus} stopped) 0 () /SubFileDecode filter cvx exec { cleartomark false } { { 3 2 roll pop true } { cleartomark false } ifelse } ifelse end } bind def /CTWorkAroundBugs { Level2? { /cid_PreLoad /ProcSet resourcestatus { pop pop currentglobal mark { (*) { dup /CMap CTHasResourceStatusBug { CTResourceStatus } { resourcestatus } ifelse { pop dup 0 eq exch 1 eq or { dup /CMap findresource gcheck setglobal /CMap undefineresource } { pop CTHasResourceForAllBug { exit } { stop } ifelse } ifelse } { pop } ifelse } 128 string /CMap resourceforall } stopped { cleartomark } stopped pop setglobal } if } if } bind def /doc_setup { Adobe_CoolType_Core begin CTWorkAroundBugs /mov /moveto load def /nfnt /newencodedfont load def /mfnt /makefont load def /sfnt /setfont load def /ufnt /undefinefont load def /chp /charpath load def /awsh /awidthshow load def /wsh /widthshow load def /ash /ashow load def /sh /show load def end userdict /Adobe_CoolType_Data 10 dict dup begin /AddWidths? false def /CC 0 def /charcode 2 string def /@opStackCountByLevel 32 dict def /@opStackLevel 0 def /@dictStackCountByLevel 32 dict def /@dictStackLevel 0 def /InVMFontsByCMap 10 dict def /InVMDeepCopiedFonts 10 dict def end put } bind def /doc_trailer { currentdict Adobe_CoolType_Core eq { end } if } bind def /page_setup { Adobe_CoolType_Core begin } bind def /page_trailer { end } bind def /unload { systemdict /languagelevel known { systemdict/languagelevel get 2 ge { userdict/Adobe_CoolType_Core 2 copy known { undef } { pop pop } ifelse } if } if } bind def /ndf { 1 index where { pop pop pop } { dup xcheck { bind } if def } ifelse } def /findfont systemdict begin userdict begin /globaldict where { /globaldict get begin } if dup where pop exch get /globaldict where { pop end } if end end Adobe_CoolType_Core_Defined { /systemfindfont exch def } { /findfont 1 index def /systemfindfont exch def } ifelse /undefinefont { pop } ndf /copyfont { currentglobal 3 1 roll 1 index gcheck setglobal dup null eq { 0 } { dup length } ifelse 2 index length add 1 add dict begin exch { 1 index /FID eq { pop pop } { def } ifelse } forall dup null eq { pop } { { def } forall } ifelse currentdict end exch setglobal } bind def /copyarray { currentglobal exch dup gcheck setglobal dup length array copy exch setglobal } bind def /newencodedfont { currentglobal { SharedFontDirectory 3 index known { SharedFontDirectory 3 index get /FontReferenced known } { false } ifelse } { FontDirectory 3 index known { FontDirectory 3 index get /FontReferenced known } { SharedFontDirectory 3 index known { SharedFontDirectory 3 index get /FontReferenced known } { false } ifelse } ifelse } ifelse dup { 3 index findfont /FontReferenced get 2 index dup type /nametype eq {findfont} if ne { pop false } if } if { pop 1 index findfont /Encoding get exch 0 1 255 { 2 copy get 3 index 3 1 roll put } for pop pop pop } { dup type /nametype eq { findfont } if dup dup maxlength 2 add dict begin exch { 1 index /FID ne {def} {pop pop} ifelse } forall /FontReferenced exch def /Encoding exch dup length array copy def /FontName 1 index dup type /stringtype eq { cvn } if def dup currentdict end definefont def } ifelse } bind def /SetSubstituteStrategy { $SubstituteFont begin dup type /dicttype ne { 0 dict } if currentdict /$Strategies known { exch $Strategies exch 2 copy known { get 2 copy maxlength exch maxlength add dict begin { def } forall { def } forall currentdict dup /$Init known { dup /$Init get exec } if end /$Strategy exch def } { pop pop pop } ifelse } { pop pop } ifelse end } bind def /scff { $SubstituteFont begin dup type /stringtype eq { dup length exch } { null } ifelse /$sname exch def /$slen exch def /$inVMIndex $sname null eq { 1 index $str cvs dup length $slen sub $slen getinterval cvn } { $sname } ifelse def end { findfont } @Stopped { dup length 8 add string exch 1 index 0 (BadFont:) putinterval 1 index exch 8 exch dup length string cvs putinterval cvn { findfont } @Stopped { pop /Courier findfont } if } if $SubstituteFont begin /$sname null def /$slen 0 def /$inVMIndex null def end } bind def /isWidthsOnlyFont { dup /WidthsOnly known { pop pop true } { dup /FDepVector known { /FDepVector get { isWidthsOnlyFont dup { exit } if } forall } { dup /FDArray known { /FDArray get { isWidthsOnlyFont dup { exit } if } forall } { pop } ifelse } ifelse } ifelse } bind def /?str1 256 string def /?set { $SubstituteFont begin /$substituteFound false def /$fontname 4 index def /$doSmartSub false def end 3 index currentglobal false setglobal exch /CompatibleFonts /ProcSet resourcestatus { pop pop /CompatibleFonts /ProcSet findresource begin dup /CompatibleFont currentexception 1 index /CompatibleFont true setexception 1 index /Font resourcestatus { pop pop 3 2 roll setglobal end exch dup findfont /CompatibleFonts /ProcSet findresource begin 3 1 roll exch /CompatibleFont exch setexception end } { 3 2 roll setglobal 1 index exch /CompatibleFont exch setexception end findfont $SubstituteFont /$substituteFound true put } ifelse } { exch setglobal findfont } ifelse $SubstituteFont begin $substituteFound { false (%%[Using embedded font ) print 5 index ?str1 cvs print ( to avoid the font substitution problem noted earlier.]%%\n) print } { dup /FontName known { dup /FontName get $fontname eq 1 index /DistillerFauxFont known not and /currentdistillerparams where { pop false 2 index isWidthsOnlyFont not and } if } { false } ifelse } ifelse exch pop /$doSmartSub true def end { exch pop exch pop exch 2 dict dup /Found 3 index put exch findfont exch } { exch exec exch dup findfont dup /FontType get 3 eq { exch ?str1 cvs dup length 1 sub -1 0 { exch dup 2 index get 42 eq { exch 0 exch getinterval cvn 4 1 roll 3 2 roll pop exit } {exch pop} ifelse }for } { exch pop } ifelse 2 dict dup /Downloaded 6 5 roll put } ifelse dup /FontName 4 index put copyfont definefont pop } bind def /?str2 256 string def /?add { 1 index type /integertype eq { exch true 4 2 } { false 3 1 } ifelse roll 1 index findfont dup /Widths known { Adobe_CoolType_Data /AddWidths? true put gsave dup 1000 scalefont setfont } if /Downloaded known { exec exch { exch ?str2 cvs exch findfont /Downloaded get 1 dict begin /Downloaded 1 index def ?str1 cvs length ?str1 1 index 1 add 3 index putinterval exch length 1 add 1 index add ?str1 2 index (*) putinterval ?str1 0 2 index getinterval cvn findfont ?str1 3 index (+) putinterval 2 dict dup /FontName ?str1 0 6 index getinterval cvn put dup /Downloaded Downloaded put end copyfont dup /FontName get exch definefont pop pop pop } { pop } ifelse } { pop exch { findfont dup /Found get dup length exch ?str1 cvs pop ?str1 1 index (+) putinterval ?str1 1 index 1 add 4 index ?str2 cvs putinterval ?str1 exch 0 exch 5 4 roll ?str2 cvs length 1 add add getinterval cvn 1 dict exch 1 index exch /FontName exch put copyfont dup /FontName get exch definefont pop } { pop } ifelse } ifelse Adobe_CoolType_Data /AddWidths? get { grestore Adobe_CoolType_Data /AddWidths? false put } if } bind def /?sh { currentfont /Downloaded known { exch } if pop } bind def /?chp { currentfont /Downloaded known { pop } { false chp } ifelse } bind def /?mv { currentfont /Downloaded known { moveto pop pop } { pop pop moveto } ifelse } bind def setpacking userdict /$SubstituteFont 25 dict put 1 dict begin /SubstituteFont dup $error exch 2 copy known { get } { pop pop { pop /Courier } bind } ifelse def /currentdistillerparams where dup { pop pop currentdistillerparams /CannotEmbedFontPolicy 2 copy known { get /Error eq } { pop pop false } ifelse } if not { countdictstack array dictstack 0 get begin userdict begin $SubstituteFont begin /$str 128 string def /$fontpat 128 string def /$slen 0 def /$sname null def /$match false def /$fontname null def /$substituteFound false def /$inVMIndex null def /$doSmartSub true def /$depth 0 def /$fontname null def /$italicangle 26.5 def /$dstack null def /$Strategies 10 dict dup begin /$Type3Underprint { currentglobal exch false setglobal 11 dict begin /UseFont exch $WMode 0 ne { dup length dict copy dup /WMode $WMode put /UseFont exch definefont } if def /FontName $fontname dup type /stringtype eq { cvn } if def /FontType 3 def /FontMatrix [ .001 0 0 .001 0 0 ] def /Encoding 256 array dup 0 1 255 { /.notdef put dup } for pop def /FontBBox [ 0 0 0 0 ] def /CCInfo 7 dict dup begin /cc null def /x 0 def /y 0 def end def /BuildChar { exch begin CCInfo begin 1 string dup 0 3 index put exch pop /cc exch def UseFont 1000 scalefont setfont cc stringwidth /y exch def /x exch def x y setcharwidth $SubstituteFont /$Strategy get /$Underprint get exec 0 0 moveto cc show x y moveto end end } bind def currentdict end exch setglobal } bind def /$GetaTint 2 dict dup begin /$BuildFont { dup /WMode known { dup /WMode get } { 0 } ifelse /$WMode exch def $fontname exch dup /FontName known { dup /FontName get dup type /stringtype eq { cvn } if } { /unnamedfont } ifelse exch Adobe_CoolType_Data /InVMDeepCopiedFonts get 1 index /FontName get known { pop Adobe_CoolType_Data /InVMDeepCopiedFonts get 1 index get null copyfont } { $deepcopyfont } ifelse exch 1 index exch /FontBasedOn exch put dup /FontName $fontname dup type /stringtype eq { cvn } if put definefont Adobe_CoolType_Data /InVMDeepCopiedFonts get begin dup /FontBasedOn get 1 index def end } bind def /$Underprint { gsave x abs y abs gt { /y 1000 def } { /x -1000 def 500 120 translate } ifelse Level2? { [ /Separation (All) /DeviceCMYK { 0 0 0 1 pop } ] setcolorspace } { 0 setgray } ifelse 10 setlinewidth x .8 mul [ 7 3 ] { y mul 8 div 120 sub x 10 div exch moveto 0 y 4 div neg rlineto dup 0 rlineto 0 y 4 div rlineto closepath gsave Level2? { .2 setcolor } { .8 setgray } ifelse fill grestore stroke } forall pop grestore } bind def end def /$Oblique 1 dict dup begin /$BuildFont { currentglobal exch dup gcheck setglobal null copyfont begin /FontBasedOn currentdict /FontName known { FontName dup type /stringtype eq { cvn } if } { /unnamedfont } ifelse def /FontName $fontname dup type /stringtype eq { cvn } if def /currentdistillerparams where { pop } { /FontInfo currentdict /FontInfo known { FontInfo null copyfont } { 2 dict } ifelse dup begin /ItalicAngle $italicangle def /FontMatrix FontMatrix [ 1 0 ItalicAngle dup sin exch cos div 1 0 0 ] matrix concatmatrix readonly end 4 2 roll def def } ifelse FontName currentdict end definefont exch setglobal } bind def end def /$None 1 dict dup begin /$BuildFont {} bind def end def end def /$Oblique SetSubstituteStrategy /$findfontByEnum { dup type /stringtype eq { cvn } if dup /$fontname exch def $sname null eq { $str cvs dup length $slen sub $slen getinterval } { pop $sname } ifelse $fontpat dup 0 (fonts/*) putinterval exch 7 exch putinterval /$match false def $SubstituteFont /$dstack countdictstack array dictstack put mark { $fontpat 0 $slen 7 add getinterval { /$match exch def exit } $str filenameforall } stopped { cleardictstack currentdict true $SubstituteFont /$dstack get { exch { 1 index eq { pop false } { true } ifelse } { begin false } ifelse } forall pop } if cleartomark /$slen 0 def $match false ne { $match (fonts/) anchorsearch pop pop cvn } { /Courier } ifelse } bind def /$ROS 1 dict dup begin /Adobe 4 dict dup begin /Japan1 [ /Ryumin-Light /HeiseiMin-W3 /GothicBBB-Medium /HeiseiKakuGo-W5 /HeiseiMaruGo-W4 /Jun101-Light ] def /Korea1 [ /HYSMyeongJo-Medium /HYGoThic-Medium ] def /GB1 [ /STSong-Light /STHeiti-Regular ] def /CNS1 [ /MKai-Medium /MHei-Medium ] def end def end def /$cmapname null def /$deepcopyfont { dup /FontType get 0 eq { 1 dict dup /FontName /copied put copyfont begin /FDepVector FDepVector copyarray 0 1 2 index length 1 sub { 2 copy get $deepcopyfont dup /FontName /copied put /copied exch definefont 3 copy put pop pop } for def currentdict end } { $Strategies /$Type3Underprint get exec } ifelse } bind def /$buildfontname { dup /CIDFont findresource /CIDSystemInfo get begin Registry length Ordering length Supplement 8 string cvs 3 copy length 2 add add add string dup 5 1 roll dup 0 Registry putinterval dup 4 index (-) putinterval dup 4 index 1 add Ordering putinterval 4 2 roll add 1 add 2 copy (-) putinterval end 1 add 2 copy 0 exch getinterval $cmapname $fontpat cvs exch anchorsearch { pop pop 3 2 roll putinterval cvn /$cmapname exch def } { pop pop pop pop pop } ifelse length $str 1 index (-) putinterval 1 add $str 1 index $cmapname $fontpat cvs putinterval $cmapname length add $str exch 0 exch getinterval cvn } bind def /$findfontByROS { /$fontname exch def $ROS Registry 2 copy known { get Ordering 2 copy known { get } { pop pop [] } ifelse } { pop pop [] } ifelse false exch { dup /CIDFont resourcestatus { pop pop save 1 index /CIDFont findresource dup /WidthsOnly known { dup /WidthsOnly get } { false } ifelse exch pop exch restore { pop } { exch pop true exit } ifelse } { pop } ifelse } forall { $str cvs $buildfontname } { false (*) { save exch dup /CIDFont findresource dup /WidthsOnly known { dup /WidthsOnly get not } { true } ifelse exch /CIDSystemInfo get dup /Registry get Registry eq exch /Ordering get Ordering eq and and { exch restore exch pop true exit } { pop restore } ifelse } $str /CIDFont resourceforall { $buildfontname } { $fontname $findfontByEnum } ifelse } ifelse } bind def end end currentdict /$error known currentdict /languagelevel known and dup { pop $error /SubstituteFont known } if dup { $error } { Adobe_CoolType_Core } ifelse begin { /SubstituteFont /CMap /Category resourcestatus { pop pop { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $sname null eq { dup $str cvs dup length $slen sub $slen getinterval cvn } { $sname } ifelse Adobe_CoolType_Data /InVMFontsByCMap get 1 index 2 copy known { get false exch { pop currentglobal { GlobalFontDirectory 1 index known { exch pop true exit } { pop } ifelse } { FontDirectory 1 index known { exch pop true exit } { GlobalFontDirectory 1 index known { exch pop true exit } { pop } ifelse } ifelse } ifelse } forall } { pop pop false } ifelse { exch pop exch pop } { dup /CMap resourcestatus { pop pop dup /$cmapname exch def /CMap findresource /CIDSystemInfo get { def } forall $findfontByROS } { 128 string cvs dup (-) search { 3 1 roll search { 3 1 roll pop { dup cvi } stopped { pop pop pop pop pop $findfontByEnum } { 4 2 roll pop pop exch length exch 2 index length 2 index sub exch 1 sub -1 0 { $str cvs dup length 4 index 0 4 index 4 3 roll add getinterval exch 1 index exch 3 index exch putinterval dup /CMap resourcestatus { pop pop 4 1 roll pop pop pop dup /$cmapname exch def /CMap findresource /CIDSystemInfo get { def } forall $findfontByROS true exit } { pop } ifelse } for dup type /booleantype eq { pop } { pop pop pop $findfontByEnum } ifelse } ifelse } { pop pop pop $findfontByEnum } ifelse } { pop pop $findfontByEnum } ifelse } ifelse } ifelse } { //SubstituteFont exec } ifelse /$slen 0 def end } } { { $SubstituteFont begin /$substituteFound true def dup length $slen gt $sname null ne or $slen 0 gt and { $findfontByEnum } { //SubstituteFont exec } ifelse end } } ifelse bind readonly def Adobe_CoolType_Core /scfindfont /systemfindfont load put } { /scfindfont { $SubstituteFont begin dup systemfindfont dup /FontName known { dup /FontName get dup 3 index ne } { /noname true } ifelse dup { /$origfontnamefound 2 index def /$origfontname 4 index def /$substituteFound true def } if exch pop { $slen 0 gt $sname null ne 3 index length $slen gt or and { pop dup $findfontByEnum findfont dup maxlength 1 add dict begin { 1 index /FID eq { pop pop } { def } ifelse } forall currentdict end definefont dup /FontName known { dup /FontName get } { null } ifelse $origfontnamefound ne { $origfontname $str cvs print ( substitution revised, using ) print dup /FontName known { dup /FontName get } { (unspecified font) } ifelse $str cvs print (.\n) print } if } { exch pop } ifelse } { exch pop } ifelse end } bind def } ifelse end end Adobe_CoolType_Core_Defined not { Adobe_CoolType_Core /findfont { $SubstituteFont begin $depth 0 eq { /$fontname 1 index dup type /stringtype ne { $str cvs } if def /$substituteFound false def } if /$depth $depth 1 add def end scfindfont $SubstituteFont begin /$depth $depth 1 sub def $substituteFound $depth 0 eq and { $inVMIndex null ne { dup $inVMIndex $AddInVMFont } if $doSmartSub { currentdict /$Strategy known { $Strategy /$BuildFont get exec } if } if } if end } bind put } if } if end /$AddInVMFont { exch /FontName 2 copy known { get 1 dict dup begin exch 1 index gcheck def end exch Adobe_CoolType_Data /InVMFontsByCMap get exch $DictAdd } { pop pop pop } ifelse } bind def /$DictAdd { 2 copy known not { 2 copy 4 index length dict put } if Level2? not { 2 copy get dup maxlength exch length 4 index length add lt 2 copy get dup length 4 index length add exch maxlength 1 index lt { 2 mul dict begin 2 copy get { forall } def 2 copy currentdict put end } { pop } ifelse } if get begin { def } forall end } bind def end end %%EndResource %%BeginResource: procset Adobe_CoolType_Utility_MAKEOCF 1.19 0 %%Copyright: Copyright 1987-2003 Adobe Systems Incorporated. %%Version: 1.19 0 systemdict /languagelevel known dup { currentglobal false setglobal } { false } ifelse exch userdict /Adobe_CoolType_Utility 2 copy known { 2 copy get dup maxlength 25 add dict copy } { 25 dict } ifelse put Adobe_CoolType_Utility begin /ct_Level2? exch def /ct_Clone? 1183615869 internaldict dup /CCRun known not exch /eCCRun known not ct_Level2? and or def ct_Level2? { globaldict begin currentglobal true setglobal } if /ct_AddStdCIDMap ct_Level2? { { ((Hex) 57 StartData 0615 1e27 2c39 1c60 d8a8 cc31 fe2b f6e0 7aa3 e541 e21c 60d8 a8c9 c3d0 6d9e 1c60 d8a8 c9c2 02d7 9a1c 60d8 a849 1c60 d8a8 cc36 74f4 1144 b13b 77) 0 () /SubFileDecode filter cvx exec } } { { <BAB431EA07F209EB8C4348311481D9D3F76E3D15246555577D87BC510ED54E 118C39697FA9F6DB58128E60EB8A12FA24D7CDD2FA94D221FA9EC8DA3E5E6A1C 4ACECC8C2D39C54E7C946031DD156C3A6B4A09AD29E1867A> eexec } } ifelse bind def userdict /cid_extensions known dup { cid_extensions /cid_UpdateDB known and } if { cid_extensions begin /cid_GetCIDSystemInfo { 1 index type /stringtype eq { exch cvn exch } if cid_extensions begin dup load 2 index known { 2 copy cid_GetStatusInfo dup null ne { 1 index load 3 index get dup null eq { pop pop cid_UpdateDB } { exch 1 index /Created get eq { exch pop exch pop } { pop cid_UpdateDB } ifelse } ifelse } { pop cid_UpdateDB } ifelse } { cid_UpdateDB } ifelse end } bind def end } if ct_Level2? { end setglobal } if /ct_UseNativeCapability? systemdict /composefont known def /ct_MakeOCF 35 dict def /ct_Vars 25 dict def /ct_GlyphDirProcs 6 dict def /ct_BuildCharDict 15 dict dup begin /charcode 2 string def /dst_string 1500 string def /nullstring () def /usewidths? true def end def ct_Level2? { setglobal } { pop } ifelse ct_GlyphDirProcs begin /GetGlyphDirectory { systemdict /languagelevel known { pop /CIDFont findresource /GlyphDirectory get } { 1 index /CIDFont findresource /GlyphDirectory get dup type /dicttype eq { dup dup maxlength exch length sub 2 index lt { dup length 2 index add dict copy 2 index /CIDFont findresource/GlyphDirectory 2 index put } if } if exch pop exch pop } ifelse + } def /+ { systemdict /languagelevel known { currentglobal false setglobal 3 dict begin /vm exch def } { 1 dict begin } ifelse /$ exch def systemdict /languagelevel known { vm setglobal /gvm currentglobal def $ gcheck setglobal } if ? { $ begin } if } def /? { $ type /dicttype eq } def /| { userdict /Adobe_CoolType_Data known { Adobe_CoolType_Data /AddWidths? known { currentdict Adobe_CoolType_Data begin begin AddWidths? { Adobe_CoolType_Data /CC 3 index put ? { def } { $ 3 1 roll put } ifelse CC charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore currentfont /Widths get exch CC exch put } { ? { def } { $ 3 1 roll put } ifelse } ifelse end end } { ? { def } { $ 3 1 roll put } ifelse } ifelse } { ? { def } { $ 3 1 roll put } ifelse } ifelse } def /! { ? { end } if systemdict /languagelevel known { gvm setglobal } if end } def /: { string currentfile exch readstring pop } executeonly def end ct_MakeOCF begin /ct_cHexEncoding [/c00/c01/c02/c03/c04/c05/c06/c07/c08/c09/c0A/c0B/c0C/c0D/c0E/c0F/c10/c11/c12 /c13/c14/c15/c16/c17/c18/c19/c1A/c1B/c1C/c1D/c1E/c1F/c20/c21/c22/c23/c24/c25 /c26/c27/c28/c29/c2A/c2B/c2C/c2D/c2E/c2F/c30/c31/c32/c33/c34/c35/c36/c37/c38 /c39/c3A/c3B/c3C/c3D/c3E/c3F/c40/c41/c42/c43/c44/c45/c46/c47/c48/c49/c4A/c4B /c4C/c4D/c4E/c4F/c50/c51/c52/c53/c54/c55/c56/c57/c58/c59/c5A/c5B/c5C/c5D/c5E /c5F/c60/c61/c62/c63/c64/c65/c66/c67/c68/c69/c6A/c6B/c6C/c6D/c6E/c6F/c70/c71 /c72/c73/c74/c75/c76/c77/c78/c79/c7A/c7B/c7C/c7D/c7E/c7F/c80/c81/c82/c83/c84 /c85/c86/c87/c88/c89/c8A/c8B/c8C/c8D/c8E/c8F/c90/c91/c92/c93/c94/c95/c96/c97 /c98/c99/c9A/c9B/c9C/c9D/c9E/c9F/cA0/cA1/cA2/cA3/cA4/cA5/cA6/cA7/cA8/cA9/cAA /cAB/cAC/cAD/cAE/cAF/cB0/cB1/cB2/cB3/cB4/cB5/cB6/cB7/cB8/cB9/cBA/cBB/cBC/cBD /cBE/cBF/cC0/cC1/cC2/cC3/cC4/cC5/cC6/cC7/cC8/cC9/cCA/cCB/cCC/cCD/cCE/cCF/cD0 /cD1/cD2/cD3/cD4/cD5/cD6/cD7/cD8/cD9/cDA/cDB/cDC/cDD/cDE/cDF/cE0/cE1/cE2/cE3 /cE4/cE5/cE6/cE7/cE8/cE9/cEA/cEB/cEC/cED/cEE/cEF/cF0/cF1/cF2/cF3/cF4/cF5/cF6 /cF7/cF8/cF9/cFA/cFB/cFC/cFD/cFE/cFF] def /ct_CID_STR_SIZE 8000 def /ct_mkocfStr100 100 string def /ct_defaultFontMtx [.001 0 0 .001 0 0] def /ct_1000Mtx [1000 0 0 1000 0 0] def /ct_raise {exch cvx exch errordict exch get exec stop} bind def /ct_reraise { cvx $error /errorname get (Error: ) print dup ( ) cvs print errordict exch get exec stop } bind def /ct_cvnsi { 1 index add 1 sub 1 exch 0 4 1 roll { 2 index exch get exch 8 bitshift add } for exch pop } bind def /ct_GetInterval { Adobe_CoolType_Utility /ct_BuildCharDict get begin /dst_index 0 def dup dst_string length gt { dup string /dst_string exch def } if 1 index ct_CID_STR_SIZE idiv /arrayIndex exch def 2 index arrayIndex get 2 index arrayIndex ct_CID_STR_SIZE mul sub { dup 3 index add 2 index length le { 2 index getinterval dst_string dst_index 2 index putinterval length dst_index add /dst_index exch def exit } { 1 index length 1 index sub dup 4 1 roll getinterval dst_string dst_index 2 index putinterval pop dup dst_index add /dst_index exch def sub /arrayIndex arrayIndex 1 add def 2 index dup length arrayIndex gt { arrayIndex get } { pop exit } ifelse 0 } ifelse } loop pop pop pop dst_string 0 dst_index getinterval end } bind def ct_Level2? { /ct_resourcestatus currentglobal mark true setglobal { /unknowninstancename /Category resourcestatus } stopped { cleartomark setglobal true } { cleartomark currentglobal not exch setglobal } ifelse { { mark 3 1 roll /Category findresource begin ct_Vars /vm currentglobal put ({ResourceStatus} stopped) 0 () /SubFileDecode filter cvx exec { cleartomark false } { { 3 2 roll pop true } { cleartomark false } ifelse } ifelse ct_Vars /vm get setglobal end } } { { resourcestatus } } ifelse bind def /CIDFont /Category ct_resourcestatus { pop pop } { currentglobal true setglobal /Generic /Category findresource dup length dict copy dup /InstanceType /dicttype put /CIDFont exch /Category defineresource pop setglobal } ifelse ct_UseNativeCapability? { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering (Identity) def /Supplement 0 def end def /CMapName /Identity-H def /CMapVersion 1.000 def /CMapType 1 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } if } { /ct_Category 2 dict begin /CIDFont 10 dict def /ProcSet 2 dict def currentdict end def /defineresource { ct_Category 1 index 2 copy known { get dup dup maxlength exch length eq { dup length 10 add dict copy ct_Category 2 index 2 index put } if 3 index 3 index put pop exch pop } { pop pop /defineresource /undefined ct_raise } ifelse } bind def /findresource { ct_Category 1 index 2 copy known { get 2 index 2 copy known { get 3 1 roll pop pop} { pop pop /findresource /undefinedresource ct_raise } ifelse } { pop pop /findresource /undefined ct_raise } ifelse } bind def /resourcestatus { ct_Category 1 index 2 copy known { get 2 index known exch pop exch pop { 0 -1 true } { false } ifelse } { pop pop /findresource /undefined ct_raise } ifelse } bind def /ct_resourcestatus /resourcestatus load def } ifelse /ct_CIDInit 2 dict begin /ct_cidfont_stream_init { { dup (Binary) eq { pop null currentfile ct_Level2? { { cid_BYTE_COUNT () /SubFileDecode filter } stopped { pop pop pop } if } if /readstring load exit } if dup (Hex) eq { pop currentfile ct_Level2? { { null exch /ASCIIHexDecode filter /readstring } stopped { pop exch pop (>) exch /readhexstring } if } { (>) exch /readhexstring } ifelse load exit } if /StartData /typecheck ct_raise } loop cid_BYTE_COUNT ct_CID_STR_SIZE le { 2 copy cid_BYTE_COUNT string exch exec pop 1 array dup 3 -1 roll 0 exch put } { cid_BYTE_COUNT ct_CID_STR_SIZE div ceiling cvi dup array exch 2 sub 0 exch 1 exch { 2 copy 5 index ct_CID_STR_SIZE string 6 index exec pop put pop } for 2 index cid_BYTE_COUNT ct_CID_STR_SIZE mod string 3 index exec pop 1 index exch 1 index length 1 sub exch put } ifelse cid_CIDFONT exch /GlyphData exch put 2 index null eq { pop pop pop } { pop /readstring load 1 string exch { 3 copy exec pop dup length 0 eq { pop pop pop pop pop true exit } if 4 index eq { pop pop pop pop false exit } if } loop pop } ifelse } bind def /StartData { mark { currentdict dup /FDArray get 0 get /FontMatrix get 0 get 0.001 eq { dup /CDevProc known not { /CDevProc 1183615869 internaldict /stdCDevProc 2 copy known { get } { pop pop { pop pop pop pop pop 0 -1000 7 index 2 div 880 } } ifelse def } if } { /CDevProc { pop pop pop pop pop 0 1 cid_temp /cid_CIDFONT get /FDArray get 0 get /FontMatrix get 0 get div 7 index 2 div 1 index 0.88 mul } def } ifelse /cid_temp 15 dict def cid_temp begin /cid_CIDFONT exch def 3 copy pop dup /cid_BYTE_COUNT exch def 0 gt { ct_cidfont_stream_init FDArray { /Private get dup /SubrMapOffset known { begin /Subrs SubrCount array def Subrs SubrMapOffset SubrCount SDBytes ct_Level2? { currentdict dup /SubrMapOffset undef dup /SubrCount undef /SDBytes undef } if end /cid_SD_BYTES exch def /cid_SUBR_COUNT exch def /cid_SUBR_MAP_OFFSET exch def /cid_SUBRS exch def cid_SUBR_COUNT 0 gt { GlyphData cid_SUBR_MAP_OFFSET cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi 0 1 cid_SUBR_COUNT 1 sub { exch 1 index 1 add cid_SD_BYTES mul cid_SUBR_MAP_OFFSET add GlyphData exch cid_SD_BYTES ct_GetInterval 0 cid_SD_BYTES ct_cvnsi cid_SUBRS 4 2 roll GlyphData exch 4 index 1 index sub ct_GetInterval dup length string copy put } for pop } if } { pop } ifelse } forall } if cleartomark pop pop end CIDFontName currentdict /CIDFont defineresource pop end end } stopped { cleartomark /StartData ct_reraise } if } bind def currentdict end def /ct_saveCIDInit { /CIDInit /ProcSet ct_resourcestatus { true } { /CIDInitC /ProcSet ct_resourcestatus } ifelse { pop pop /CIDInit /ProcSet findresource ct_UseNativeCapability? { pop null } { /CIDInit ct_CIDInit /ProcSet defineresource pop } ifelse } { /CIDInit ct_CIDInit /ProcSet defineresource pop null } ifelse ct_Vars exch /ct_oldCIDInit exch put } bind def /ct_restoreCIDInit { ct_Vars /ct_oldCIDInit get dup null ne { /CIDInit exch /ProcSet defineresource pop } { pop } ifelse } bind def /ct_BuildCharSetUp { 1 index begin CIDFont begin Adobe_CoolType_Utility /ct_BuildCharDict get begin /ct_dfCharCode exch def /ct_dfDict exch def CIDFirstByte ct_dfCharCode add dup CIDCount ge { pop 0 } if /cid exch def { GlyphDirectory cid 2 copy known { get } { pop pop nullstring } ifelse dup length FDBytes sub 0 gt { dup FDBytes 0 ne { 0 FDBytes ct_cvnsi } { pop 0 } ifelse /fdIndex exch def dup length FDBytes sub FDBytes exch getinterval /charstring exch def exit } { pop cid 0 eq { /charstring nullstring def exit } if /cid 0 def } ifelse } loop } def /ct_SetCacheDevice { 0 0 moveto dup stringwidth 3 -1 roll true charpath pathbbox 0 -1000 7 index 2 div 880 setcachedevice2 0 0 moveto } def /ct_CloneSetCacheProc { 1 eq { stringwidth pop -2 div -880 0 -1000 setcharwidth moveto } { usewidths? { currentfont /Widths get cid 2 copy known { get exch pop aload pop } { pop pop stringwidth } ifelse } { stringwidth } ifelse setcharwidth 0 0 moveto } ifelse } def /ct_Type3ShowCharString { ct_FDDict fdIndex 2 copy known { get } { currentglobal 3 1 roll 1 index gcheck setglobal ct_Type1FontTemplate dup maxlength dict copy begin FDArray fdIndex get dup /FontMatrix 2 copy known { get } { pop pop ct_defaultFontMtx } ifelse /FontMatrix exch dup length array copy def /Private get /Private exch def /Widths rootfont /Widths get def /CharStrings 1 dict dup /.notdef <d841272cf18f54fc13> dup length string copy put def currentdict end /ct_Type1Font exch definefont dup 5 1 roll put setglobal } ifelse dup /CharStrings get 1 index /Encoding get ct_dfCharCode get charstring put rootfont /WMode 2 copy known { get } { pop pop 0 } ifelse exch 1000 scalefont setfont ct_str1 0 ct_dfCharCode put ct_str1 exch ct_dfSetCacheProc ct_SyntheticBold { currentpoint ct_str1 show newpath moveto ct_str1 true charpath ct_StrokeWidth setlinewidth stroke } { ct_str1 show } ifelse } def /ct_Type4ShowCharString { ct_dfDict ct_dfCharCode charstring FDArray fdIndex get dup /FontMatrix get dup ct_defaultFontMtx ct_matrixeq not { ct_1000Mtx matrix concatmatrix concat } { pop } ifelse /Private get Adobe_CoolType_Utility /ct_Level2? get not { ct_dfDict /Private 3 -1 roll { put } 1183615869 internaldict /superexec get exec } if 1183615869 internaldict Adobe_CoolType_Utility /ct_Level2? get { 1 index } { 3 index /Private get mark 6 1 roll } ifelse dup /RunInt known { /RunInt get } { pop /CCRun } ifelse get exec Adobe_CoolType_Utility /ct_Level2? get not { cleartomark } if } bind def /ct_BuildCharIncremental { { Adobe_CoolType_Utility /ct_MakeOCF get begin ct_BuildCharSetUp ct_ShowCharString } stopped { stop } if end end end end } bind def /BaseFontNameStr (BF00) def /ct_Type1FontTemplate 14 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [-250 -250 1250 1250] def /Encoding ct_cHexEncoding def /PaintType 0 def currentdict end def /BaseFontTemplate 11 dict begin /FontMatrix [0.001 0 0 0.001 0 0] def /FontBBox [-250 -250 1250 1250] def /Encoding ct_cHexEncoding def /BuildChar /ct_BuildCharIncremental load def ct_Clone? { /FontType 3 def /ct_ShowCharString /ct_Type3ShowCharString load def /ct_dfSetCacheProc /ct_CloneSetCacheProc load def /ct_SyntheticBold false def /ct_StrokeWidth 1 def } { /FontType 4 def /Private 1 dict dup /lenIV 4 put def /CharStrings 1 dict dup /.notdef <d841272cf18f54fc13> put def /PaintType 0 def /ct_ShowCharString /ct_Type4ShowCharString load def } ifelse /ct_str1 1 string def currentdict end def /BaseFontDictSize BaseFontTemplate length 5 add def /ct_matrixeq { true 0 1 5 { dup 4 index exch get exch 3 index exch get eq and dup not { exit } if } for exch pop exch pop } bind def /ct_makeocf { 15 dict begin exch /WMode exch def exch /FontName exch def /FontType 0 def /FMapType 2 def dup /FontMatrix known { dup /FontMatrix get /FontMatrix exch def } { /FontMatrix matrix def } ifelse /bfCount 1 index /CIDCount get 256 idiv 1 add dup 256 gt { pop 256} if def /Encoding 256 array 0 1 bfCount 1 sub { 2 copy dup put pop } for bfCount 1 255 { 2 copy bfCount put pop } for def /FDepVector bfCount dup 256 lt { 1 add } if array def BaseFontTemplate BaseFontDictSize dict copy begin /CIDFont exch def CIDFont /FontBBox known { CIDFont /FontBBox get /FontBBox exch def } if CIDFont /CDevProc known { CIDFont /CDevProc get /CDevProc exch def } if currentdict end BaseFontNameStr 3 (0) putinterval 0 1 bfCount dup 256 eq { 1 sub } if { FDepVector exch 2 index BaseFontDictSize dict copy begin dup /CIDFirstByte exch 256 mul def FontType 3 eq { /ct_FDDict 2 dict def } if currentdict end 1 index 16 BaseFontNameStr 2 2 getinterval cvrs pop BaseFontNameStr exch definefont put } for ct_Clone? { /Widths 1 index /CIDFont get /GlyphDirectory get length dict def } if FontName currentdict end definefont ct_Clone? { gsave dup 1000 scalefont setfont ct_BuildCharDict begin /usewidths? false def currentfont /Widths get begin exch /CIDFont get /GlyphDirectory get { pop dup charcode exch 1 index 0 2 index 256 idiv put 1 index exch 1 exch 256 mod put stringwidth 2 array astore def } forall end /usewidths? true def end grestore } { exch pop } ifelse } bind def /ct_ComposeFont { ct_UseNativeCapability? { 2 index /CMap ct_resourcestatus { pop pop exch pop } { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CMapName 3 index def /CMapVersion 1.000 def /CMapType 1 def exch /WMode exch def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-) search { pop pop (-) search { dup length string copy exch pop exch pop } { pop (Identity)} ifelse } { pop (Identity) } ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } ifelse composefont } { 3 2 roll pop 0 get /CIDFont findresource ct_makeocf } ifelse } bind def /ct_MakeIdentity { ct_UseNativeCapability? { 1 index /CMap ct_resourcestatus { pop pop } { /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CMapName 2 index def /CMapVersion 1.000 def /CMapType 1 def /CIDSystemInfo 3 dict dup begin /Registry (Adobe) def /Ordering CMapName ct_mkocfStr100 cvs (Adobe-) search { pop pop (-) search { dup length string copy exch pop exch pop } { pop (Identity) } ifelse } { pop (Identity) } ifelse def /Supplement 0 def end def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 begincidrange <0000> <FFFF> 0 endcidrange endcmap CMapName currentdict /CMap defineresource pop end end } ifelse composefont } { exch pop 0 get /CIDFont findresource ct_makeocf } ifelse } bind def currentdict readonly pop end end %%EndResource %%BeginResource: procset Adobe_CoolType_Utility_T42 1.0 0 %%Copyright: Copyright 1987-2003 Adobe Systems Incorporated. %%Version: 1.0 0 userdict /ct_T42Dict 15 dict put ct_T42Dict begin /Is2015? { version cvi 2015 ge } bind def /AllocGlyphStorage { Is2015? { pop } { {string} forall } ifelse } bind def /Type42DictBegin { 25 dict begin /FontName exch def /CharStrings 256 dict begin /.notdef 0 def currentdict end def /Encoding exch def /PaintType 0 def /FontType 42 def /FontMatrix [1 0 0 1 0 0] def 4 array astore cvx /FontBBox exch def /sfnts } bind def /Type42DictEnd { currentdict dup /FontName get exch definefont end ct_T42Dict exch dup /FontName get exch put } bind def /RD {string currentfile exch readstring pop} executeonly def /PrepFor2015 { Is2015? { /GlyphDirectory 16 dict def sfnts 0 get dup 2 index (glyx) putinterval 2 index (locx) putinterval pop pop } { pop pop } ifelse } bind def /AddT42Char { Is2015? { /GlyphDirectory get begin def end pop pop } { /sfnts get 4 index get 3 index 2 index putinterval pop pop pop pop } ifelse } bind def end %%EndResource Adobe_CoolType_Core begin /$Oblique SetSubstituteStrategy end %%BeginResource: procset Adobe_AGM_Image 1.0 0 %%Version: 1.0 0 %%Copyright: Copyright (C) 2000-2003 Adobe Systems, Inc. All Rights Reserved. systemdict /setpacking known { currentpacking true setpacking } if userdict /Adobe_AGM_Image 75 dict dup begin put /Adobe_AGM_Image_Id /Adobe_AGM_Image_1.0_0 def /nd{ null def }bind def /AGMIMG_&image nd /AGMIMG_&colorimage nd /AGMIMG_&imagemask nd /AGMIMG_mbuf () def /AGMIMG_ybuf () def /AGMIMG_kbuf () def /AGMIMG_c 0 def /AGMIMG_m 0 def /AGMIMG_y 0 def /AGMIMG_k 0 def /AGMIMG_tmp nd /AGMIMG_imagestring0 nd /AGMIMG_imagestring1 nd /AGMIMG_imagestring2 nd /AGMIMG_imagestring3 nd /AGMIMG_imagestring4 nd /AGMIMG_imagestring5 nd /AGMIMG_cnt nd /AGMIMG_fsave nd /AGMIMG_colorAry nd /AGMIMG_override nd /AGMIMG_name nd /AGMIMG_maskSource nd /invert_image_samples nd /knockout_image_samples nd /img nd /sepimg nd /devnimg nd /idximg nd /doc_setup { Adobe_AGM_Core begin Adobe_AGM_Image begin /AGMIMG_&image systemdict/image get def /AGMIMG_&imagemask systemdict/imagemask get def /colorimage where{ pop /AGMIMG_&colorimage /colorimage ldf }if end end }def /page_setup { Adobe_AGM_Image begin /AGMIMG_ccimage_exists {/customcolorimage where { pop /Adobe_AGM_OnHost_Seps where { pop false }{ /Adobe_AGM_InRip_Seps where { pop false }{ true }ifelse }ifelse }{ false }ifelse }bdf level2{ /invert_image_samples { Adobe_AGM_Image/AGMIMG_tmp Decode length ddf /Decode [ Decode 1 get Decode 0 get] def }def /knockout_image_samples { Operator/imagemask ne{ /Decode [1 1] def }if }def }{ /invert_image_samples { {1 exch sub} currenttransfer addprocs settransfer }def /knockout_image_samples { { pop 1 } currenttransfer addprocs settransfer }def }ifelse /img /imageormask ldf /sepimg /sep_imageormask ldf /devnimg /devn_imageormask ldf /idximg /indexed_imageormask ldf /_ctype 7 def currentdict{ dup xcheck 1 index type dup /arraytype eq exch /packedarraytype eq or and{ bind }if def }forall }def /page_trailer { end }def /doc_trailer { }def /imageormask_sys { begin save mark level2{ currentdict Operator /imagemask eq{ AGMIMG_&imagemask }{ use_mask { level3 {process_mask_L3 AGMIMG_&image}{masked_image_simulation}ifelse }{ AGMIMG_&image }ifelse }ifelse }{ Width Height Operator /imagemask eq{ Decode 0 get 1 eq Decode 1 get 0 eq and ImageMatrix /DataSource load AGMIMG_&imagemask }{ BitsPerComponent ImageMatrix /DataSource load AGMIMG_&image }ifelse }ifelse cleartomark restore end }def /overprint_plate { currentoverprint { 0 get dup type /nametype eq { dup /DeviceGray eq{ pop AGMCORE_black_plate not }{ /DeviceCMYK eq{ AGMCORE_is_cmyk_sep not }if }ifelse }{ false exch { AGMOHS_sepink eq or } forall not } ifelse }{ pop false }ifelse }def /process_mask_L3 { dup begin /ImageType 1 def end 4 dict begin /DataDict exch def /ImageType 3 def /InterleaveType 3 def /MaskDict 9 dict begin /ImageType 1 def /Width DataDict dup /MaskWidth known {/MaskWidth}{/Width} ifelse get def /Height DataDict dup /MaskHeight known {/MaskHeight}{/Height} ifelse get def /ImageMatrix [Width 0 0 Height neg 0 Height] def /NComponents 1 def /BitsPerComponent 1 def /Decode [0 1] def /DataSource AGMIMG_maskSource def currentdict end def currentdict end }def /use_mask { dup type /dicttype eq { dup /Mask known { dup /Mask get { level3 {true} { dup /MaskWidth known {dup /MaskWidth get 1 index /Width get eq}{true}ifelse exch dup /MaskHeight known {dup /MaskHeight get 1 index /Height get eq}{true}ifelse 3 -1 roll and } ifelse } {false} ifelse } {false} ifelse } {false} ifelse }def /make_line_source { begin MultipleDataSources { [ Decode length 2 div cvi {Width string} repeat ] }{ Width Decode length 2 div mul cvi string }ifelse end }def /datasource_to_str { exch dup type dup /filetype eq { pop exch readstring }{ /arraytype eq { exec exch copy }{ pop }ifelse }ifelse pop }def /masked_image_simulation { 3 dict begin dup make_line_source /line_source xdf /mask_source AGMIMG_maskSource /LZWDecode filter def dup /Width get 8 div ceiling cvi string /mask_str xdf begin gsave 0 1 translate 1 -1 Height div scale 1 1 Height { pop gsave MultipleDataSources { 0 1 DataSource length 1 sub { dup DataSource exch get exch line_source exch get datasource_to_str } for }{ DataSource line_source datasource_to_str } ifelse << /PatternType 1 /PaintProc [ /pop cvx << /ImageType 1 /Width Width /Height 1 /ImageMatrix Width 1.0 sub 1 matrix scale 0.5 0 matrix translate matrix concatmatrix /MultipleDataSources MultipleDataSources /DataSource line_source /BitsPerComponent BitsPerComponent /Decode Decode >> /image cvx ] cvx /BBox [0 0 Width 1] /XStep Width /YStep 1 /PaintType 1 /TilingType 2 >> matrix makepattern set_pattern << /ImageType 1 /Width Width /Height 1 /ImageMatrix Width 1 matrix scale /MultipleDataSources false /DataSource mask_source mask_str readstring pop /BitsPerComponent 1 /Decode [0 1] >> imagemask grestore 0 1 translate } for grestore end end }def /imageormask { begin SkipImageProc { currentdict consumeimagedata } { save mark level2 AGMCORE_host_sep not and{ currentdict Operator /imagemask eq DeviceN_PS2 not and { imagemask }{ AGMCORE_in_rip_sep currentoverprint and currentcolorspace 0 get /DeviceGray eq and{ [/Separation /Black /DeviceGray {}] setcolorspace /Decode [ Decode 1 get Decode 0 get ] def }if use_mask { level3 {process_mask_L3 image}{masked_image_simulation}ifelse }{ DeviceN_NoneName DeviceN_PS2 Indexed_DeviceN level3 not and or or AGMCORE_in_rip_sep and { Names convert_to_process not { 2 dict begin /imageDict xdf /names_index 0 def gsave imageDict write_image_file { Names { dup (None) ne { [/Separation 3 -1 roll /DeviceGray {1 exch sub}] setcolorspace Operator imageDict read_image_file names_index 0 eq {true setoverprint} if /names_index names_index 1 add def }{ pop } ifelse } forall close_image_file } if grestore end }{ Operator /imagemask eq { imagemask }{ image } ifelse } ifelse }{ Operator /imagemask eq { imagemask }{ image } ifelse } ifelse }ifelse }ifelse }{ Width Height Operator /imagemask eq{ Decode 0 get 1 eq Decode 1 get 0 eq and ImageMatrix /DataSource load /Adobe_AGM_OnHost_Seps where { pop imagemask }{ currentgray 1 ne{ currentdict imageormask_sys }{ currentoverprint not{ 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentdict ignoreimagedata }ifelse }ifelse }ifelse }{ BitsPerComponent ImageMatrix MultipleDataSources{ 0 1 NComponents 1 sub{ DataSource exch get }for }{ /DataSource load }ifelse Operator /colorimage eq{ AGMCORE_host_sep{ MultipleDataSources level2 or NComponents 4 eq and{ AGMCORE_is_cmyk_sep{ MultipleDataSources{ /DataSource [ DataSource 0 get /exec cvx DataSource 1 get /exec cvx DataSource 2 get /exec cvx DataSource 3 get /exec cvx /AGMCORE_get_ink_data cvx ] cvx def }{ /DataSource Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul /DataSource load filter_cmyk 0 () /SubFileDecode filter def }ifelse /Decode [ Decode 0 get Decode 1 get ] def /MultipleDataSources false def /NComponents 1 def /Operator /image def invert_image_samples 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentoverprint not Operator/imagemask eq and{ 1 AGMCORE_&setgray currentdict imageormask_sys }{ currentdict ignoreimagedata }ifelse }ifelse }{ MultipleDataSources NComponents AGMIMG_&colorimage }ifelse }{ true NComponents colorimage }ifelse }{ Operator /image eq{ AGMCORE_host_sep{ /DoImage true def HostSepColorImage{ invert_image_samples }{ AGMCORE_black_plate not Operator/imagemask ne and{ /DoImage false def currentdict ignoreimagedata }if }ifelse 1 AGMCORE_&setgray DoImage {currentdict imageormask_sys} if }{ use_mask { level3 {process_mask_L3 image}{masked_image_simulation}ifelse }{ image }ifelse }ifelse }{ Operator/knockout eq{ pop pop pop pop pop currentcolorspace overprint_plate not{ knockout_unitsq }if }if }ifelse }ifelse }ifelse }ifelse cleartomark restore }ifelse end }def /sep_imageormask { /sep_colorspace_dict AGMCORE_gget begin /MappedCSA CSA map_csa def begin SkipImageProc { currentdict consumeimagedata } { save mark AGMCORE_avoid_L2_sep_space{ /Decode [ Decode 0 get 255 mul Decode 1 get 255 mul ] def }if AGMIMG_ccimage_exists MappedCSA 0 get /DeviceCMYK eq and currentdict/Components known and Name () ne and Name (All) ne and Operator /image eq and AGMCORE_producing_seps not and level2 not and { Width Height BitsPerComponent ImageMatrix [ /DataSource load /exec cvx { 0 1 2 index length 1 sub{ 1 index exch 2 copy get 255 xor put }for } /exec cvx ] cvx bind MappedCSA 0 get /DeviceCMYK eq{ Components aload pop }{ 0 0 0 Components aload pop 1 exch sub }ifelse Name findcmykcustomcolor customcolorimage }{ AGMCORE_producing_seps not{ level2{ AGMCORE_avoid_L2_sep_space not currentcolorspace 0 get /Separation ne and{ [/Separation Name MappedCSA sep_proc_name exch 0 get exch load ] setcolorspace_opt /sep_tint AGMCORE_gget setcolor }if currentdict imageormask }{ currentdict Operator /imagemask eq{ imageormask }{ sep_imageormask_lev1 }ifelse }ifelse }{ AGMCORE_host_sep{ Operator/knockout eq{ currentdict/ImageMatrix get concat knockout_unitsq }{ currentgray 1 ne{ AGMCORE_is_cmyk_sep Name (All) ne and{ level2{ [ /Separation Name [/DeviceGray] { sep_colorspace_proc AGMCORE_get_ink_data 1 exch sub } bind ] AGMCORE_&setcolorspace /sep_tint AGMCORE_gget AGMCORE_&setcolor currentdict imageormask_sys }{ currentdict Operator /imagemask eq{ imageormask_sys }{ sep_image_lev1_sep }ifelse }ifelse }{ Operator/imagemask ne{ invert_image_samples }if currentdict imageormask_sys }ifelse }{ currentoverprint not Name (All) eq or Operator/imagemask eq and{ currentdict imageormask_sys }{ currentoverprint not { gsave knockout_unitsq grestore }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ currentcolorspace 0 get /Separation ne{ [/Separation Name MappedCSA sep_proc_name exch 0 get exch load ] setcolorspace_opt /sep_tint AGMCORE_gget setcolor }if currentoverprint MappedCSA 0 get /DeviceCMYK eq and Name inRip_spot_has_ink not and Name (All) ne and { imageormask_l2_overprint }{ currentdict imageormask }ifelse }ifelse }ifelse }ifelse cleartomark restore }ifelse end end }def /decode_image_sample { 4 1 roll exch dup 5 1 roll sub 2 4 -1 roll exp 1 sub div mul add } bdf /colorSpaceElemCnt { currentcolorspace 0 get dup /DeviceCMYK eq { pop 4 } { /DeviceRGB eq { pop 3 }{ 1 } ifelse } ifelse } bdf /devn_sep_datasource { 1 dict begin /dataSource xdf [ 0 1 dataSource length 1 sub { dup currentdict /dataSource get /exch cvx /get cvx /exec cvx /exch cvx names_index /ne cvx [ /pop cvx ] cvx /if cvx } for ] cvx bind end } bdf /devn_alt_datasource { 11 dict begin /srcDataStrs xdf /dstDataStr xdf /convProc xdf /origcolorSpaceElemCnt xdf /origMultipleDataSources xdf /origBitsPerComponent xdf /origDecode xdf /origDataSource xdf /dsCnt origMultipleDataSources {origDataSource length}{1}ifelse def /samplesNeedDecoding 0 0 1 origDecode length 1 sub { origDecode exch get add } for origDecode length 2 div div dup 1 eq { /decodeDivisor 2 origBitsPerComponent exp 1 sub def } if 2 origBitsPerComponent exp 1 sub ne def [ 0 1 dsCnt 1 sub [ currentdict /origMultipleDataSources get { dup currentdict /origDataSource get exch get dup type }{ currentdict /origDataSource get dup type } ifelse dup /filetype eq { pop currentdict /srcDataStrs get 3 -1 /roll cvx /get cvx /readstring cvx /pop cvx }{ /stringtype ne { /exec cvx } if currentdict /srcDataStrs get /exch cvx 3 -1 /roll cvx /xpt cvx } ifelse ] cvx /for cvx currentdict /srcDataStrs get 0 /get cvx /length cvx 0 /ne cvx [ 0 1 Width 1 sub [ Adobe_AGM_Utils /AGMUTIL_ndx /xddf cvx currentdict /origMultipleDataSources get { 0 1 dsCnt 1 sub [ Adobe_AGM_Utils /AGMUTIL_ndx1 /xddf cvx currentdict /srcDataStrs get /AGMUTIL_ndx1 /load cvx /get cvx /AGMUTIL_ndx /load cvx /get cvx samplesNeedDecoding { currentdict /decodeDivisor known { currentdict /decodeDivisor get /div cvx }{ currentdict /origDecode get /AGMUTIL_ndx1 /load cvx 2 /mul cvx 2 /getinterval cvx /aload cvx /pop cvxs BitsPerComponent /decode_image_sample load /exec cvx } ifelse } if ] cvx /for cvx }{ Adobe_AGM_Utils /AGMUTIL_ndx1 0 /ddf cvx currentdict /srcDataStrs get 0 /get cvx /AGMUTIL_ndx /load cvx currentdict /origDecode get length 2 idiv dup 3 1 /roll cvx /mul cvx /exch cvx /getinterval cvx [ samplesNeedDecoding { currentdict /decodeDivisor known { currentdict /decodeDivisor get /div cvx }{ currentdict /origDecode get /AGMUTIL_ndx1 /load cvx 2 /mul cvx 2 /getinterval cvx /aload cvx /pop cvx BitsPerComponent /decode_image_sample load /exec cvx Adobe_AGM_Utils /AGMUTIL_ndx1 /AGMUTIL_ndx1 /load cvx 1 /add cvx /ddf cvx } ifelse } if ] cvx /forall cvx } ifelse currentdict /convProc get /exec cvx currentdict /origcolorSpaceElemCnt get 1 sub -1 0 [ currentdict /dstDataStr get 3 1 /roll cvx /AGMUTIL_ndx /load cvx currentdict /origcolorSpaceElemCnt get /mul cvx /add cvx /exch cvx currentdict /convProc get /filter_indexed_devn load ne { 255 /mul cvx /cvi cvx } if /put cvx ] cvx /for cvx ] cvx /for cvx currentdict /dstDataStr get ] cvx /if cvx ] cvx bind end } bdf /devn_imageormask { /devicen_colorspace_dict AGMCORE_gget begin /MappedCSA CSA map_csa def 2 dict begin dup dup /dstDataStr exch /Width get colorSpaceElemCnt mul string def /srcDataStrs [ 3 -1 roll begin currentdict /MultipleDataSources known {MultipleDataSources {DataSource length}{1}ifelse}{1} ifelse { Width Decode length 2 div mul cvi string } repeat end ] def begin SkipImageProc { currentdict consumeimagedata } { save mark AGMCORE_producing_seps not { level3 not { Operator /imagemask ne { /DataSource [ DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse colorSpaceElemCnt /devicen_colorspace_dict AGMCORE_gget /TintTransform get dstDataStr srcDataStrs devn_alt_datasource /exec cvx ] cvx 0 () /SubFileDecode filter def /MultipleDataSources false def /Decode colorSpaceElemCnt [ exch {0 1} repeat ] def } if }if currentdict imageormask }{ AGMCORE_host_sep{ Names convert_to_process { CSA map_csa 0 get /DeviceCMYK eq { /DataSource Width BitsPerComponent mul 7 add 8 idiv Height mul 4 mul [ DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse 4 /devicen_colorspace_dict AGMCORE_gget /TintTransform get dstDataStr srcDataStrs devn_alt_datasource /exec cvx ] cvx filter_cmyk 0 () /SubFileDecode filter def /MultipleDataSources false def /Decode [1 0] def /DeviceGray setcolorspace currentdict imageormask_sys }{ AGMCORE_report_unsupported_color_space AGMCORE_black_plate { /DataSource [ DataSource Decode BitsPerComponent currentdict /MultipleDataSources known {MultipleDataSources}{false} ifelse CSA map_csa 0 get /DeviceRGB eq{3}{1}ifelse /devicen_colorspace_dict AGMCORE_gget /TintTransform get dstDataStr srcDataStrs devn_alt_datasource /exec cvx ] cvx 0 () /SubFileDecode filter def /MultipleDataSources false def /Decode colorSpaceElemCnt [ exch {0 1} repeat ] def currentdict imageormask_sys } { gsave knockout_unitsq grestore currentdict consumeimagedata } ifelse } ifelse } { /devicen_colorspace_dict AGMCORE_gget /names_index known { Operator/imagemask ne{ MultipleDataSources { /DataSource [ DataSource devn_sep_datasource /exec cvx ] cvx def /MultipleDataSources false def }{ /DataSource /DataSource load dstDataStr srcDataStrs 0 get filter_devn def } ifelse invert_image_samples } if currentdict imageormask_sys }{ currentoverprint not Operator/imagemask eq and{ currentdict imageormask_sys }{ currentoverprint not { gsave knockout_unitsq grestore }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ currentdict imageormask }ifelse }ifelse cleartomark restore }ifelse end end end }def /imageormask_l2_overprint { currentdict currentcmykcolor add add add 0 eq{ currentdict consumeimagedata }{ level3{ currentcmykcolor /AGMIMG_k xdf /AGMIMG_y xdf /AGMIMG_m xdf /AGMIMG_c xdf Operator/imagemask eq{ [/DeviceN [ AGMIMG_c 0 ne {/Cyan} if AGMIMG_m 0 ne {/Magenta} if AGMIMG_y 0 ne {/Yellow} if AGMIMG_k 0 ne {/Black} if ] /DeviceCMYK {}] setcolorspace AGMIMG_c 0 ne {AGMIMG_c} if AGMIMG_m 0 ne {AGMIMG_m} if AGMIMG_y 0 ne {AGMIMG_y} if AGMIMG_k 0 ne {AGMIMG_k} if setcolor }{ /Decode [ Decode 0 get 255 mul Decode 1 get 255 mul ] def [/Indexed [ /DeviceN [ AGMIMG_c 0 ne {/Cyan} if AGMIMG_m 0 ne {/Magenta} if AGMIMG_y 0 ne {/Yellow} if AGMIMG_k 0 ne {/Black} if ] /DeviceCMYK { AGMIMG_k 0 eq {0} if AGMIMG_y 0 eq {0 exch} if AGMIMG_m 0 eq {0 3 1 roll} if AGMIMG_c 0 eq {0 4 1 roll} if } ] 255 { 255 div mark exch dup dup dup AGMIMG_k 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 1 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_y 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 2 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_m 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec 4 3 roll pop pop pop counttomark 1 roll }{ pop }ifelse AGMIMG_c 0 ne{ /sep_tint AGMCORE_gget mul MappedCSA sep_proc_name exch pop load exec pop pop pop counttomark 1 roll }{ pop }ifelse counttomark 1 add -1 roll pop } ] setcolorspace }ifelse imageormask_sys }{ write_image_file{ currentcmykcolor 0 ne{ [/Separation /Black /DeviceGray {}] setcolorspace gsave /Black [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 1 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Yellow /DeviceGray {}] setcolorspace gsave /Yellow [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 2 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Magenta /DeviceGray {}] setcolorspace gsave /Magenta [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {4 3 roll pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore }if 0 ne{ [/Separation /Cyan /DeviceGray {}] setcolorspace gsave /Cyan [{1 exch sub /sep_tint AGMCORE_gget mul} /exec cvx MappedCSA sep_proc_name cvx exch pop {pop pop pop 1 exch sub} /exec cvx] cvx modify_halftone_xfer Operator currentdict read_image_file grestore } if close_image_file }{ imageormask }ifelse }ifelse }ifelse } def /indexed_imageormask { begin save mark currentdict AGMCORE_host_sep{ Operator/knockout eq{ /indexed_colorspace_dict AGMCORE_gget dup /CSA known { /CSA get map_csa }{ /CSD get get_csd /Names get } ifelse overprint_plate not{ knockout_unitsq }if }{ Indexed_DeviceN { /devicen_colorspace_dict AGMCORE_gget /names_index known { indexed_image_lev2_sep }{ currentoverprint not{ knockout_unitsq }if currentdict consumeimagedata } ifelse }{ AGMCORE_is_cmyk_sep{ Operator /imagemask eq{ imageormask_sys }{ level2{ indexed_image_lev2_sep }{ indexed_image_lev1_sep }ifelse }ifelse }{ currentoverprint not{ knockout_unitsq }if currentdict consumeimagedata }ifelse }ifelse }ifelse }{ level2{ Indexed_DeviceN { /indexed_colorspace_dict AGMCORE_gget begin CSD get_csd begin }{ /indexed_colorspace_dict AGMCORE_gget begin CSA map_csa 0 get /DeviceCMYK eq ps_level 3 ge and ps_version 3015.007 lt and { [/Indexed [/DeviceN [/Cyan /Magenta /Yellow /Black] /DeviceCMYK {}] HiVal Lookup] setcolorspace } if end } ifelse imageormask Indexed_DeviceN { end end } if }{ Operator /imagemask eq{ imageormask }{ indexed_imageormask_lev1 }ifelse }ifelse }ifelse cleartomark restore end }def /indexed_image_lev2_sep { /indexed_colorspace_dict AGMCORE_gget begin begin Indexed_DeviceN not { currentcolorspace dup 1 /DeviceGray put dup 3 currentcolorspace 2 get 1 add string 0 1 2 3 AGMCORE_get_ink_data 4 currentcolorspace 3 get length 1 sub { dup 4 idiv exch currentcolorspace 3 get exch get 255 exch sub 2 index 3 1 roll put }for put setcolorspace } if currentdict Operator /imagemask eq{ AGMIMG_&imagemask }{ use_mask { level3 {process_mask_L3 AGMIMG_&image}{masked_image_simulation}ifelse }{ AGMIMG_&image }ifelse }ifelse end end }def /OPIimage { dup type /dicttype ne{ 10 dict begin /DataSource xdf /ImageMatrix xdf /BitsPerComponent xdf /Height xdf /Width xdf /ImageType 1 def /Decode [0 1 def] currentdict end }if dup begin /NComponents 1 cdndf /MultipleDataSources false cdndf /SkipImageProc {false} cdndf /HostSepColorImage false cdndf /Decode [ 0 currentcolorspace 0 get /Indexed eq{ 2 BitsPerComponent exp 1 sub }{ 1 }ifelse ] cdndf /Operator /image cdndf end /sep_colorspace_dict AGMCORE_gget null eq{ imageormask }{ gsave dup begin invert_image_samples end sep_imageormask grestore }ifelse }def /cachemask_level2 { 3 dict begin /LZWEncode filter /WriteFilter xdf /readBuffer 256 string def /ReadFilter currentfile 0 (%EndMask) /SubFileDecode filter /ASCII85Decode filter /RunLengthDecode filter def { ReadFilter readBuffer readstring exch WriteFilter exch writestring not {exit} if }loop WriteFilter closefile end }def /cachemask_level3 { currentfile << /Filter [ /SubFileDecode /ASCII85Decode /RunLengthDecode ] /DecodeParms [ << /EODCount 0 /EODString (%EndMask) >> null null ] /Intent 1 >> /ReusableStreamDecode filter }def /spot_alias { /mapto_sep_imageormask { dup type /dicttype ne{ 12 dict begin /ImageType 1 def /DataSource xdf /ImageMatrix xdf /BitsPerComponent xdf /Height xdf /Width xdf /MultipleDataSources false def }{ begin }ifelse /Decode [/customcolor_tint AGMCORE_gget 0] def /Operator /image def /HostSepColorImage false def /SkipImageProc {false} def currentdict end sep_imageormask }bdf /customcolorimage { Adobe_AGM_Image/AGMIMG_colorAry xddf /customcolor_tint AGMCORE_gget bdict /Name AGMIMG_colorAry 4 get /CSA [ /DeviceCMYK ] /TintMethod /Subtractive /TintProc null /MappedCSA null /NComponents 4 /Components [ AGMIMG_colorAry aload pop pop ] edict setsepcolorspace mapto_sep_imageormask }ndf Adobe_AGM_Image/AGMIMG_&customcolorimage /customcolorimage load put /customcolorimage { Adobe_AGM_Image/AGMIMG_override false put dup 4 get map_alias{ /customcolor_tint AGMCORE_gget exch setsepcolorspace pop mapto_sep_imageormask }{ AGMIMG_&customcolorimage }ifelse }bdf }def /snap_to_device { 6 dict begin matrix currentmatrix dup 0 get 0 eq 1 index 3 get 0 eq and 1 index 1 get 0 eq 2 index 2 get 0 eq and or exch pop { 1 1 dtransform 0 gt exch 0 gt /AGMIMG_xSign? exch def /AGMIMG_ySign? exch def 0 0 transform AGMIMG_ySign? {floor 0.1 sub}{ceiling 0.1 add} ifelse exch AGMIMG_xSign? {floor 0.1 sub}{ceiling 0.1 add} ifelse exch itransform /AGMIMG_llY exch def /AGMIMG_llX exch def 1 1 transform AGMIMG_ySign? {ceiling 0.1 add}{floor 0.1 sub} ifelse exch AGMIMG_xSign? {ceiling 0.1 add}{floor 0.1 sub} ifelse exch itransform /AGMIMG_urY exch def /AGMIMG_urX exch def [AGMIMG_urX AGMIMG_llX sub 0 0 AGMIMG_urY AGMIMG_llY sub AGMIMG_llX AGMIMG_llY] concat }{ }ifelse end } def level2 not{ /colorbuf { 0 1 2 index length 1 sub{ dup 2 index exch get 255 exch sub 2 index 3 1 roll put }for }def /tint_image_to_color { begin Width Height BitsPerComponent ImageMatrix /DataSource load end Adobe_AGM_Image begin /AGMIMG_mbuf 0 string def /AGMIMG_ybuf 0 string def /AGMIMG_kbuf 0 string def { colorbuf dup length AGMIMG_mbuf length ne { dup length dup dup /AGMIMG_mbuf exch string def /AGMIMG_ybuf exch string def /AGMIMG_kbuf exch string def } if dup AGMIMG_mbuf copy AGMIMG_ybuf copy AGMIMG_kbuf copy pop } addprocs {AGMIMG_mbuf}{AGMIMG_ybuf}{AGMIMG_kbuf} true 4 colorimage end } def /sep_imageormask_lev1 { begin MappedCSA 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or has_color not and{ { 255 mul round cvi GrayLookup exch get } currenttransfer addprocs settransfer currentdict imageormask }{ /sep_colorspace_dict AGMCORE_gget/Components known{ MappedCSA 0 get /DeviceCMYK eq{ Components aload pop }{ 0 0 0 Components aload pop 1 exch sub }ifelse Adobe_AGM_Image/AGMIMG_k xddf Adobe_AGM_Image/AGMIMG_y xddf Adobe_AGM_Image/AGMIMG_m xddf Adobe_AGM_Image/AGMIMG_c xddf AGMIMG_y 0.0 eq AGMIMG_m 0.0 eq and AGMIMG_c 0.0 eq and{ {AGMIMG_k mul 1 exch sub} currenttransfer addprocs settransfer currentdict imageormask }{ currentcolortransfer {AGMIMG_k mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_y mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_m mul 1 exch sub} exch addprocs 4 1 roll {AGMIMG_c mul 1 exch sub} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }ifelse }{ MappedCSA 0 get /DeviceGray eq { {255 mul round cvi ColorLookup exch get 0 get} currenttransfer addprocs settransfer currentdict imageormask }{ MappedCSA 0 get /DeviceCMYK eq { currentcolortransfer {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }{ currentcolortransfer {pop 1} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 2 get} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 1 get} exch addprocs 4 1 roll {255 mul round cvi ColorLookup exch get 0 get} exch addprocs 4 1 roll setcolortransfer currentdict tint_image_to_color }ifelse }ifelse }ifelse }ifelse end }def /sep_image_lev1_sep { begin /sep_colorspace_dict AGMCORE_gget/Components known{ Components aload pop Adobe_AGM_Image/AGMIMG_k xddf Adobe_AGM_Image/AGMIMG_y xddf Adobe_AGM_Image/AGMIMG_m xddf Adobe_AGM_Image/AGMIMG_c xddf {AGMIMG_c mul 1 exch sub} {AGMIMG_m mul 1 exch sub} {AGMIMG_y mul 1 exch sub} {AGMIMG_k mul 1 exch sub} }{ {255 mul round cvi ColorLookup exch get 0 get 1 exch sub} {255 mul round cvi ColorLookup exch get 1 get 1 exch sub} {255 mul round cvi ColorLookup exch get 2 get 1 exch sub} {255 mul round cvi ColorLookup exch get 3 get 1 exch sub} }ifelse AGMCORE_get_ink_data currenttransfer addprocs settransfer currentdict imageormask_sys end }def /indexed_imageormask_lev1 { /indexed_colorspace_dict AGMCORE_gget begin begin currentdict MappedCSA 0 get dup /DeviceRGB eq exch /DeviceCMYK eq or has_color not and{ {HiVal mul round cvi GrayLookup exch get HiVal div} currenttransfer addprocs settransfer imageormask }{ MappedCSA 0 get /DeviceGray eq { {HiVal mul round cvi Lookup exch get HiVal div} currenttransfer addprocs settransfer imageormask }{ MappedCSA 0 get /DeviceCMYK eq { currentcolortransfer {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} exch addprocs 4 1 roll setcolortransfer tint_image_to_color }{ currentcolortransfer {pop 1} exch addprocs 4 1 roll {3 mul HiVal mul round cvi 2 add Lookup exch get HiVal div} exch addprocs 4 1 roll {3 mul HiVal mul round cvi 1 add Lookup exch get HiVal div} exch addprocs 4 1 roll {3 mul HiVal mul round cvi Lookup exch get HiVal div} exch addprocs 4 1 roll setcolortransfer tint_image_to_color }ifelse }ifelse }ifelse end end }def /indexed_image_lev1_sep { /indexed_colorspace_dict AGMCORE_gget begin begin {4 mul HiVal mul round cvi Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 1 add Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 2 add Lookup exch get HiVal div 1 exch sub} {4 mul HiVal mul round cvi 3 add Lookup exch get HiVal div 1 exch sub} AGMCORE_get_ink_data currenttransfer addprocs settransfer currentdict imageormask_sys end end }def }if end systemdict /setpacking known { setpacking } if %%EndResource currentdict Adobe_AGM_Utils eq {end} if %%EndProlog %%BeginSetup Adobe_AGM_Utils begin 2 2010 Adobe_AGM_Core/doc_setup get exec Adobe_CoolType_Core/doc_setup get exec Adobe_AGM_Image/doc_setup get exec currentdict Adobe_AGM_Utils eq {end} if %%EndSetup %%Page: xen3-1.0.eps 1 %%EndPageComments %%BeginPageSetup /currentdistillerparams where {pop currentdistillerparams /CoreDistVersion get 5000 lt} {true} ifelse { userdict /AI11_PDFMark5 /cleartomark load put userdict /AI11_ReadMetadata_PDFMark5 {flushfile cleartomark } bind put} { userdict /AI11_PDFMark5 /pdfmark load put userdict /AI11_ReadMetadata_PDFMark5 {/PUT pdfmark} bind put } ifelse [/NamespacePush AI11_PDFMark5 [/_objdef {ai_metadata_stream_123} /type /stream /OBJ AI11_PDFMark5 [{ai_metadata_stream_123} currentfile 0 (% &&end XMP packet marker&&) /SubFileDecode filter AI11_ReadMetadata_PDFMark5 <?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 3.0-29, framework 1.6'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'>
+
+ <rdf:Description rdf:about='uuid:bacf4235-e435-11da-8f1a-000d93afebb2'
+ xmlns:pdf='http://ns.adobe.com/pdf/1.3/'>
+ <pdf:Producer>Adobe PDF library 6.66</pdf:Producer>
+ </rdf:Description>
+
+ <rdf:Description rdf:about='uuid:bacf4235-e435-11da-8f1a-000d93afebb2'
+ xmlns:tiff='http://ns.adobe.com/tiff/1.0/'>
+ </rdf:Description>
+
+ <rdf:Description rdf:about='uuid:bacf4235-e435-11da-8f1a-000d93afebb2'
+ xmlns:xap='http://ns.adobe.com/xap/1.0/'
+ xmlns:xapGImg='http://ns.adobe.com/xap/1.0/g/img/'>
+ <xap:CreateDate>2006-05-14T09:34:14-07:00</xap:CreateDate>
+ <xap:ModifyDate>2006-06-26T18:03:19Z</xap:ModifyDate>
+ <xap:CreatorTool>Illustrator</xap:CreatorTool>
+ <xap:MetadataDate>2006-05-14T09:34:14-07:00</xap:MetadataDate>
+ <xap:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType='Resource'>
+ <xapGImg:format>JPEG</xapGImg:format>
+ <xapGImg:width>256</xapGImg:width>
+ <xapGImg:height>112</xapGImg:height>
+ <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAcAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FUn13zZoei&#xA;L/ps49elVto/ilP+x7fNqYq8/wBW/NrVpyyabbpZx9pH/eyfPf4B9xxVIX1Tzpqx5fWLy4Rv5C6x&#xA;/ctExVT/AMJ+Zpvia1Zj4vIgP/DNirY8v+arT4o4JoyNwYXBP/CMcVV7fzf5z0pwj3c4p/uq6Beo&#xA;8P3oJH0YqyvRfzcidli1i19OuxubepX5mM1P3E/LFWfafqVhqNuLmxnS4hP7aGtD4EdQfY4qicVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVececvzLMbSafobguKrNfdQ&#xA;D3EXj/rfd44qxDSfLOq6zIbqZmjhkPJrmWrM57lQd2+eKsz03yro1gAVgE0o/wB2zUc19h0H0DFU&#xA;3xV2KuxVZLDFMhjlRZEPVHAYH6DirHdV8jabchnsz9Um6gDeMn3Xt9GKsWjk8w+VtREkbNby/wAw&#xA;+KKVR2PZh8+mKvVPKHnex1+L0nAt9SQVkt67MP5o69R7dvxxVk2KuxV2KuxV2KuxV2KuxV2KuxV2&#xA;KuxV2KuxV2KuxV2KuxV2KuxV2KvNPzI86uHk0PTpONPhvp1O58Ygf+Jfd44qk3lTyksypf6gtYjv&#xA;BbkfaHZm9vAd8VZuAAAAKAbADFW8VdirsVdirsVdiqhe2Nre27W9zGJIn7HqD4g9jirznWdHvvL+&#xA;oxz28jCMNztbldiCu9D/AJQ/HFXq3krzZF5g06slE1CCguohsD4Ovs34YqyPFXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWP+d/MY0PRJJoyPrk/7q1HgxG7/wCxG/zpirxaPyPJ5xsL&#xA;61lvJ7FShKX8DMsq3BBKMCCOQB3YV3G3euKvmfzZf/mb5V1+70LVtb1KK8tG4ki8uODod0kjJYVR&#xA;huMVSj/HPnb/AKmDUv8ApMn/AOa8Vd/jnzt/1MGpf9Jk/wDzXiqc+Wfzh/MPQtYstQXXb+9gtJAz&#xA;6fdXU8tvKh2dHjdmX4gTvSoO43xV9teUPNekea/L1nrulSc7S7TlxP243GzxuOzI2x/piqc4q7FX&#xA;l/5v/nnofkSB7C04aj5mdf3diD8EIYVElwR0FNwg+I+w3xV8m6p+Zn5ganqE9/deYL8T3DF3WK4l&#xA;hjHskcbKiqOwAxVBS+c/OEycJtd1CROvF7udhX5F8VW2/nDzbbOZLbW7+CQiheO6mQ08KqwxVG2/&#xA;nr8xrmeO3t/MOsTXEzBIoY7y6d3djRVVQ5JJPQDFX1b+R/5I+fLc2/mL8wvMGqPOOMtn5e+v3BVC&#xA;N1a7IejH/iobfzV3UKvoPFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXjX5m6u9/5kNoh&#xA;5Q2CiFFHeRqM5+daL9GKsq0LTV07S4LUD4wOUx8Xbdv6YqwP87/yjtvPugetZqkXmTT1LafcGg9R&#xA;ept5G/lb9k/st7E4q+J7u1ubO6mtLqJoLm3dop4ZAVdHQ8WVgehBGKqWKuxV6p+Qf5tP5I8w/UdR&#xA;lP8AhvVHC3incQS7KtwB7dHp1X/VGKvtJZEdBIjBo2HJXBqCDuCDir5+/Oj/AJyRg031/L3kqZZ9&#xA;RFY7vWVo0cJGxSCtVd/F/sjtU9FXy9cXFxc3ElxcyvNcTMZJppGLu7saszMakknqTiqnirsVTPQP&#xA;Lms6/fCz0q2e4lADSsB8EaEgc5H6KtT1Py64q+xf+caPyr8qeXYLq/mhS981QkBr+QVEUUi0426n&#xA;7G4YM/2iPAGmKvfMVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVWSyJFE8rmiRqWY+wFTi&#xA;rwjQ1fVPNEUs27SzPcy18QTIa/M4q9OxV2KvAf8AnJH8mf0vay+c9Ag/3K2qV1a1jG9xCg/vlA6y&#xA;Rgb/AMy+67qvlXFXYq7FWcy/nN57fyJb+S1vTFpsHKNp0qLh7c/Zt2kr/drvsO3w/Z2xVg2KuxV2&#xA;KvRvyp/JTzJ5+uVuFBsPL8b8bjU5F2ah+JIFNOb/AIDv4Yq9180ebvym/KHyzP5T0uH6zqkkf7yz&#xA;gKvcNKRVZbyciinuB1p9leOKvD5v+cgvzEhmnbQ7tNFjnX03FuivIUqDvJKHoajqoXFWKat+YPnz&#xA;V2Lap5i1K85bcZruZ1oewUtxA9gMVSKWaaZzJM7SSHq7ksdvc4qiLPVtVsiDZXk9sVqVMMrx0J60&#xA;4kYqzXy3+ff5u+X5FNl5mvJ4lO8F8/1yMj+Wlx6hUf6pGKvpP8m/+crdJ8131voHmy3j0jW7hlit&#xA;LuEt9TuJWNFSjFmhdifhBYg+INBir6BxV8PfnL+ev5kWn5o+ZLHQ/MN1Y6XY3jWkFrCy8ENsohkp&#xA;Ve8iMT74qwz/AJX9+cn/AFNl9/wS/wDNOKu/5X9+cn/U2X3/AAS/804q9x0z/nKCLyh+Vmix6hcP&#xA;5o8+X8UlzcRySD07dJZn9D6xItaH0uBEaivjxqCVXiXm78//AM2fNE0jXmv3FlbOTSy05mtIVU/s&#xA;0iIdx/rs2KsBuby7u5TLdTyTymtZJWZ23NTuxJ64qmmh+dfOGgypLoutXunslOIt7iSNdhQAqG4k&#xA;U7EYq+qP+cd/+cltR80atD5Q85FH1a4B/RmqoixidkUs0UyLRFfiPhZQAelK0qqzX/nI7XPPnlfy&#xA;dJ5r8r+Ym0pLAxQzacLS1uFnaeZUDmWdJGTiG6Ab4q8488+f/wA7NB8j/l9eab5ra/1vzqUnFdPs&#xA;I+H1m3tmitlHpMrcZJm+OgJrirDde/5yZ/NvUdDsdS8vap9Rg0qxtLbzBMbW0czalM8w5j1IXVfU&#xA;jh5BUoo3xV9ieZJPT8u6o4NCtpOQT4+m1MVeReQEDa3IT+xAxHz5KP44q9DxV2KuxV8k/wDORf5M&#xA;f4dvn816DBTQbyT/AE62jHw2k7nqAOkUhO3ZW26FcVeG4q7FXYq7FW1VmYKoJYmgA3JJxV9Cfk9/&#xA;zjPcagINd88Rtb2JpJbaLUrNKOoa4IoY1/yB8R78e6r0P8+fzQj/AC98tWuheXVjttZv4zHZrEqq&#xA;lpap8JkVAKA/sxilOp/ZoVXx1NNNPM80ztLNKxeSRyWZmY1LMTuST1OKrMVe9/8AOL/5HaZ54u7r&#xA;zJ5jiM3l/TJRBBZVKrc3XEOwcgg+nErKSP2iR2qCq+woPKPlS3sP0fBotjFYU4/VEtoVip4cAvHt&#xA;4Yq+H/8AnKHyP5f8ofmebXQYEtLHULKLUDZRbRwySSSxOiL+yp9HkF6Cu21MVeRYq2CQajYjFX6G&#xA;/k158fW/yY0nzPq8paa1s5l1Kd/tMbFnjeRiepdYuZ+eKvz71XUJ9S1O81Gf+/vZ5LiXv8crl2/E&#xA;4qhcVdir3P8AKr/nFLzV5z0eDXdWv00DSbtRJZBojPczRncSCLlEqI4+yxap68aUJVa/Ob/nGG//&#xA;AC+8tnzJY6wNX0yGSOK8jeD6vLF6p4I4o8iupchT0IqOu+KvDcVdirJfy0kuI/zG8rPblhONXsfT&#xA;4btyNygAA71xV+keraNpGsWL2Gr2NvqNjIVMlpdxJPExU8lJjkDKaEVG2Koebyt5YnTTUn0iylTR&#xA;ih0dXtomFmY+Ppm2BX9zw4Lx4UpQeGKoL/lXf5f/AFOay/wxpP1K5lWe4tvqNt6UkqAhZHThxZ1D&#xA;tRiK7nFUw8xxmTy9qiKKs1pOFHuY2piryHyA4XW5FP7cDAfMMp/hir0PFXYqpXNzbWtvJc3MqQW8&#xA;Kl5ppGCIiqKlmZqAADucVfL/AOdn/ORsesWt55X8ohW0udWgv9VkSpmRtmSBHHwoR+2RU9qdSq+f&#xA;MVdirsVdir6g/wCcXvIfkG60f/FHMal5kt5DHNBOoAsWqeBjjqal1HISn5ChDYq+iMVfCv57eYJt&#xA;b/NTX5XYmOyuG0+BD0RLT90wHzkVm+nFWA4q7FUwtotfjiH1ZLtIW+JfTEgU1HUcdt8VVf8Anaf+&#xA;X7/ktiqhNY65O/Oa3uZXpTk6SMafMjFVn6J1X/ljn/5Fv/TFXfonVf8Aljn/AORb/wBMVfV0dxce&#xA;TP8AnDLjPyivtWtpYEifYkandsCoH/MM5bFXyNirsVZT+V3ldPNX5h+X9AkUvb315Gt0o6m3Q+pP&#xA;0/4qRsVfpTHHHFGscahI0AVEUAKqgUAAHQDFXhn/ADmLr66f+VKaYG/e6zfwQlP+K4K3DH6HjT78&#xA;VfEGKuxV6n/zjJ5dGt/nNoQdOcGmmXUZvb6uhMR/5HGPFX6A4q7FXYqtljSSN43FUcFWHsRQ4q8H&#xA;0Vn0rzRHFNsYZ2tpa7dSYz9x3xV6diqSeb/Ofl3yjo8mra7drbWybRp1klftHEnV2P8AadsVfHn5&#xA;s/nh5i8+XD2kZbTvLiNWHTUbeTiaq9ww+23fj9le2+5Vea4q7FXYq7FXYqy38svzD1XyJ5ng1izr&#xA;JbNSLUbKtFngJ+Jf9ZeqHsfauKvuvy/r2leYNGtNZ0qcXFhexiWCUeB2KsOzKdmHY7Yq+Ffza0W5&#xA;0b8yvMdlOhSt/PPDy7w3DmaJveqOMVYjirsVfpZ+WGu6Prf5f6BfaRMktmbG3iohH7t4olR4mA+y&#xA;0bDiRiq38x/zI8teQPLs2s61MAQCtnZKw9e5l7RxKf8Ahm6KNzirxT/od7yt/wBS1ff8jocVd/0O&#xA;95W/6lq+/wCR0OKp15N/5yy0vzb5n0/y9pXla+e81CZYlb1oisa9Xlen7MaAs3sMVY//AM5u+YvS&#xA;0Ty35cjfe7uJr+dB2W3QRR19mM7/AHYq+RsVdir3z/nDXy7+kPzNutYkSsWi2Ejxv/LPcsIUH0xG&#xA;XFX2xir48/5zZ8xfWfN2g+X0eqabZvdyqOgku5OND7hLcH6cVfN2KuxV9R/84Q+XeV75m8ySJ/dR&#xA;wadbSePqMZph9HpxYq+scVdirsVdirxz8z9Iax8xG8RaQ36iVSOgkWiuP1N9OKpD55/Pzy35S0CF&#xA;mIv/ADHNHSPS42oVcbepOwr6aHqO57eIVfJfnPzx5l846w+q69dm4mNRDCPhhhQmvpwp0VfxPUkn&#xA;fFUgxV2Kro43kdY41LyOQqIoqSTsAAMVe5+Vf+cWPMeo+UrzU9XnOna1LBz0fSjSvMfEBdE/Y5jb&#xA;iN1rVuhXFXh91bXFrcy2tzG0NxA7RTROKMjoeLKwPQgihxVSxV2KvX/+cffzgbybrP6F1eanlnU5&#xA;BzdjtaztRRMP8hthJ9/bdV77+cP5LaR+YdnFeW8qWXmC2Tja39OUckf2hFNx3K1NVYbr79MVfJ3m&#xA;78r/ADv5TvHttX02QBRyFzB+/hZakBuaV41p0ah9sVYpiqYaV5g17SC50nUrrTzJ/eG1nkh5U/m9&#xA;Nlriqhf6lqOo3LXWoXU15cts09xI0shHuzknFXWGmajqM4t9PtZry4b7MNvG0rmv+SgJxV6n5L/5&#xA;xe/NnzJLG1zpv6BsWoXutTrC4HWgtxWavzUD3xV9ZflH+R3lL8trNmsA19rdwnC81ecASMuxMcSi&#xA;ojjqK8QST3JoMVfNX/OV6+Yte/NqeK0027uLPSbS3s4ZYoJXjYspuHIZVofin4n5Yq8b/wAJ+af+&#xA;rNff9I03/NOKu/wn5p/6s19/0jTf804q+vP+cNvKN5o/kvWtVv7WS0u9UvliEcyMjmG0j+BuLAH7&#xA;c0mKvoPFXwB+fcPmbzH+bnmTUIdLvZbWO5+p2zrbyshjtFEAZCFoVYxlh88Vef8A+E/NP/Vmvv8A&#xA;pGm/5pxV3+E/NP8A1Zr7/pGm/wCacVfcP/OLHlW48v8A5RWRu4Gt73VLi4vriKRSjrVvRj5A77xw&#xA;qfpxV69irsVdirRIUEk0A3JPQDFXy1/zkV/zkboMsLeWPKBS/voJKz64pDQQsAVZLc7iVt92+yO3&#xA;Lsq+Vbi4nuJnnuJGmnlJaSVyWZmPUkncnFVPFXYqmXl3y5rfmPVoNJ0W0e8v7g0SKMdB3ZidlVe7&#xA;HYYq+vfyf/IPRPJMceqapw1LzMwr9YIrDbVG6wA/teMh38Kb1Ves4q+Z/wDnKP8AKoRv/jvSIaI5&#xA;WPXYUHRjRY7mg8dkf3oe5OKvm/FXYq7FX0z/AM48fnhENL/wj5jmJuLKMnRLhjUyxqP95Sf5k/YP&#xA;8u3YVVeh6Tp995p8xiNiazt6lxIOkcS9afIbLir2C78n+U7yOOO90axu0iVUQXFtFLRVFFHxq3QY&#xA;qln/ACqf8rP+pN0P/uG2n/VPFVe1/LX8ubRuVr5V0e3aoblFYWqGo6H4Yx0xVPrWztLSIQ2sEdvC&#xA;OkcSqijanRQB2xVWxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kvmj877n/nIfzqZ9C8ueV7zSvKx&#xA;qkp9e2W5vF6H1Ss3wRn/AH2Dv+0T0Crw3/oW/wDO3/qVp/8Akdbf9VcVUrn/AJx3/Oi2geebyvcC&#xA;KMFnIkt2IA6miyE4qki/lZ5+Zgo0h6nYVkhA+8virJvLv/OOH5o6rqdvbXenDS7KT4ptQnkieNE6&#xA;1CxuzOT+yB18QN8VfVn5e/lr5Y8iaT9R0eCs8gBvL+QAzzsO7t2UfsqNh86nFWV4q7FVG9s7W9s5&#xA;7O7iWe1uY2hnhcVV43BVlYeBBpir4686/wDOOHn/AE7zLe23l7S5NT0XnzsLpZIQfSfcI4d1PJPs&#xA;k03698VSP/lQP5v/APUtzf8AI23/AOqmKqF5+R/5qWcPrXWgSQx9OTTW+58APU3xVD6f+VX5lyXs&#xA;C2Gjzm85g2/pPHz5g1BWj9uuKvt78jtO8wWnk5T5m0eTSvMfMx35laJxME/u5IzEzgIVO4P7Ve1M&#xA;VeiYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8885/lqLl5NQ0RQkzVaay&#xA;6Kx6kx9gf8npirCtL8xavocxtZUZoozSS0mqpU+1d1xVmWm+bdGvgF9b6vMesc3w7+zfZP34qnII&#xA;IBBqD0IxVvFXYqpz3FvbxmSeRYox1Z2Cj7zirG9V892FuCliv1qX+c1WMH9Z+j78VYzb23mLzVqP&#xA;GNWuJB1b7MUSnxPRR+J98Ver+UvJdh5fg57XGoSCktyR0H8sfgv68VZHirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdiqVa55Y0XWo+N/bhpAKJOnwyr8mH6jtirANW/KPUY&#xA;mL6XdJcx9opv3cg9qiqn8MVY8+geddKJC2t5CB1MHJ0++IsuKqf6e82RfA004I7MlT+K1xVsan5w&#xA;u/hje7kJ2pEjA/8ACAYqiLXyP5y1KQPJaSpXrLdNwI+Yc8/wxVlujflHaRFZNXuTcMNzbwVRPpc/&#xA;EfoAxVndjYWVjbrbWcKQQL0RBQfM+J98VRGKuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV/9k=</xapGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xap:Thumbnails>
+ </rdf:Description>
+
+ <rdf:Description rdf:about='uuid:bacf4235-e435-11da-8f1a-000d93afebb2'
+ xmlns:xapMM='http://ns.adobe.com/xap/1.0/mm/'>
+ <xapMM:DocumentID>uuid:65ad4e0e-e367-11da-8f1a-000d93afebb2</xapMM:DocumentID>
+ </rdf:Description>
+
+ <rdf:Description rdf:about='uuid:bacf4235-e435-11da-8f1a-000d93afebb2'
+ xmlns:dc='http://purl.org/dc/elements/1.1/'>
+ <dc:format>application/postscript</dc:format>
+ </rdf:Description>
+
+</rdf:RDF>
+</x:xmpmeta>
+ <?xpacket end='w'?> % &&end XMP packet marker&& [{ai_metadata_stream_123} <</Type /Metadata /Subtype /XML>> /PUT AI11_PDFMark5 [/Document 1 dict begin /Metadata {ai_metadata_stream_123} def currentdict end /BDC AI11_PDFMark5 Adobe_AGM_Utils begin Adobe_AGM_Core/page_setup get exec Adobe_CoolType_Core/page_setup get exec Adobe_AGM_Image/page_setup get exec %%EndPageSetup Adobe_AGM_Core/AGMCORE_save save ddf 1 -1 scale 0 -93.5196 translate [1 0 0 1 0 0 ] concat % page clip gsave newpath gsave % PSGState 0 0 mo 0 93.5196 li 214.165 93.5196 li 214.165 0 li clp [1 0 0 1 0 0 ] concat 8.25879 46.7579 mo 8.25879 22.3165 28.0782 2.5 52.521 2.5 cv 76.9634 2.5 96.7769 22.3165 96.7769 46.7579 cv 96.7769 71.2032 76.9634 91.0196 52.521 91.0196 cv 28.0782 91.0196 8.25879 71.2032 8.25879 46.7579 cv false sop /0 [/DeviceGray] add_csa 0.8706 gry f 5 lw 0 lc 0 lj 4 ml [] 0 dsh true sadj 8.25879 46.7579 mo 8.25879 22.3165 28.0782 2.5 52.521 2.5 cv 76.9634 2.5 96.7769 22.3165 96.7769 46.7579 cv 96.7769 71.2032 76.9634 91.0196 52.521 91.0196 cv 28.0782 91.0196 8.25879 71.2032 8.25879 46.7579 cv cp 0.5647 gry @ 116.116 47.1055 mo 117.075 42.9981 115.555 40.2793 110.896 40.2793 cv 106.516 40.2793 103.46 42.9356 102.483 47.1055 cv 116.116 47.1055 li cp 101.063 53.17 mo 99.8052 58.5411 101.595 61.004 106.256 61.004 cv 110.22 61.004 112.205 59.3594 113.233 57.3379 cv 133.266 57.3379 li 131.397 62.6465 123.05 67.7012 105.038 67.7012 cv 88.691 67.7012 78.7691 62.834 81.5796 50.8321 cv 84.4605 38.5137 97.022 33.586 112.466 33.586 cv 125.82 33.586 138.41 37.4395 135.127 51.4629 cv 134.728 53.17 li 101.063 53.17 li /1 [/DeviceCMYK] add_csa 0 0 0 1 cmyk f 139.871 47.2325 mo 140.86 42.9981 141.766 38.8282 142.365 34.7872 cv 162.536 34.7872 li 161.512 40.3458 li 161.648 40.3458 li 166.04 35.8575 172.068 33.586 179.16 33.586 cv 185.423 33.586 195.758 35.4805 192.936 47.5469 cv 188.498 66.4981 li 168.054 66.4981 li 172.026 49.5059 li 173.122 44.8301 171.49 43.1876 167.941 43.1876 cv 163.209 43.1876 160.644 45.8418 159.507 50.7051 cv 155.807 66.4981 li 135.358 66.4981 li 139.871 47.2325 li f 39.7618 47.836 mo 17.8775 20.8731 li 44.6934 20.92 li 56.3023 36.6368 li 75.6192 20.8731 li 106.646 20.8731 li 67.9107 50.6114 li 89.6958 78.6407 li 62.6739 78.6407 li 51.5777 62.3243 li 30.9258 78.6407 li 0 78.6407 li 39.7618 47.836 li f 199.061 36.5992 mo 197.165 36.5992 li 197.165 35.1919 li 203.389 35.1919 li 203.389 36.5992 li 201.493 36.5992 li 201.493 40.9673 li 199.061 40.9673 li 199.061 36.5992 li f 204.381 35.1919 mo 208.069 35.1919 li 209.276 39.063 li 209.292 39.063 li 210.46 35.1919 li 214.165 35.1919 li 214.165 40.9673 li 211.909 40.9673 li 211.909 36.6236 li 211.893 36.6236 li 210.309 40.9673 li 207.956 40.9673 li 206.469 36.6236 li 206.444 36.6236 li 206.444 40.9673 li 204.381 40.9673 li 204.381 35.1919 li f %ADOBeginClientInjection: EndPageContent "AI11EPS" userdict /annotatepage 2 copy known {get exec}{pop pop} ifelse %ADOEndClientInjection: EndPageContent "AI11EPS" % page clip grestore grestore % PSGState Adobe_AGM_Core/AGMCORE_save get restore %%PageTrailer [/EMC AI11_PDFMark5 [/NamespacePop AI11_PDFMark5 Adobe_AGM_Image/page_trailer get exec Adobe_CoolType_Core/page_trailer get exec Adobe_AGM_Core/page_trailer get exec currentdict Adobe_AGM_Utils eq {end} if %%Trailer Adobe_AGM_Image/doc_trailer get exec Adobe_CoolType_Core/doc_trailer get exec Adobe_AGM_Core/doc_trailer get exec %%EOF %AI9_PrintingDataEnd userdict /AI9_read_buffer 256 string put userdict begin /ai9_skip_data { mark { currentfile AI9_read_buffer { readline } stopped { } { not { exit } if (%AI9_PrivateDataEnd) eq { exit } if } ifelse } loop cleartomark } def end userdict /ai9_skip_data get exec %AI9_PrivateDataBegin %!PS-Adobe-3.0 EPSF-3.0 %%Creator: Adobe Illustrator(R) 11.0 %%AI8_CreatorVersion: 11.0.0 %%For: (Rich Quarles) (glassCanopy, LLC) %%Title: (xen.eps) %%CreationDate: 6/26/06 11:03 AM %AI9_DataStream %Gb"-6l#J&kFY<FlrXS_PAtmN]Ljbu=A<r@?WQR@K]8]PA.h1lL)d%f3@Yb(hW%(ZHVk:<,+8>9G%;<$r+h\4JAk%%?HMjl%q;R=s %l1<s4qoA0&VuQP2<E3""F^&*.AUi5eNVh^ns)J(n]8u26fCdMAGi<dF<t/Ej?+8'<^b,5%hc=^Nr:KFKLV(T&?TgWe]DMACqt0CM %r:(S)e&1Rb5F\kN:QM.+j'ViUI"2%mkJ)HAE;O=_rVH-[h`ooR^!C#mq.9HJrr1kos7H6Jp=!#k?/TAg2tX'+J%YaJmMAss2h1bK %a*/&dhqrhc%Cgcbb7F+88,T+]LAq2KmaEQI+$??PkAPkKYQ)rBo>aX&+/jcu>SYjZe[P=S*uao3P\knM>lDQAS)=/3bMVZhb-J_7 %r_2ae?%uR_PZRnScOWg$]RA]M^e=\\W2FB'pt8J\f+$>;(,1hrp%J+641uJ#(gBgs*W-hfTu.YeFoVAeGPA$PQGZPXY6Jc$(]EV? %SuiedFbrn0b9!]'i.'R,XhXS]:[e:)X4Ku,l`n<Qa/6d^78]-Fnh6VR+2818/Qut*?2&KkJ?SC4n,IG.pudFE:if>g=(N1T$!6pg %.SFU7aLrMV;OE7e2"nC4=*jOAei9$c45`g:F>Ie"f6=r=:"0!CmGkt\o+/Qh4AH(+;;X7E\aEhn*ZgpP,+%R_s5CG2hq`e[oR-Q# %rortQr/@!"n*WAes)@l"Ncn6)^j`ho`tj/Z^ZA'idrZ=`1Akq.&[iB)M8&.;po:R5mf*1amOte)DVs87IX:kc-f+i1h7qu%Z?cHA %p&0BW?Ke&fI]W=nhgU$aHiF!(4`2e(2^@5Rl_jK$&$uZ(hYk>DmL&>dTnP/ph<jfXGFsCN4?\)3hYuML.-.GdI/`W9gE5jT5>#eQ %2d_#`p\;@us$a'gGu[j(lh)!7M>nu4!CDRR$L2<.WfEYT<2bsMQh5j9%-td!oFX5[_,mk%^O3cqmf)_md_PjOIt#+]+80jgFn6./ %"0HnJ5O*`9/G/hgVn5H5I/hI[rq-$(+!5FiEH%r:WpQrs,/0FPVB>!U:U`$j<S(OTO1YG%RXY$bUnrTC?/s86_k5tF5IXkq['&qC %?/rD:NSi;EJ%OUuh0`;UiDj0=n%'"4l8lSXlh5\-Eua_=EPuW^Gi@K=Lf]Q\?A3mf:V:GS`N-FO]Q:^(Dmil_B"uB)p\V,2]D$[M %I_Y&m\Ad60D@\so^Vr;-qmprXi(pumqh.3(.dWAmPeY*WiD7)jH\=Vgh`;Bt0D5^%i]HK=rkt7MS@E1t&cT^tj)=i0qh3;VdH'KN %<S/u&M:_+gpmKD<[[bC*8!-:JJ+B/cF)F.MS_M.[a-Q$2knX-5X0@*K'5QSFjBhG%4Ce.*YJU;'%.gFe^">RIM=7Zm4TG2?>E5?6 %:V7&3LHg&"H'Rm/o(2C.\d#D#\pebH\:$L)GSQ:/NXPTO>E:B!G4BXaAt:Th6=4sHp.e[9p($QR?LtYY5Q$@>nbU9)nX/gZp_0jI %hRP:]AaA43OlIhYlIIhoCIM;D[[^D+Y6E_u3i>+.gc?L!IP-[#[TmH5qo3KnX7YX]45\BAo8?hu4-N`%cT.$qf<D.hYMZS=q&]9a %maeVKFI^5%kLH^#5--u]400U]l!]m#Pf#UkMf^67mP#R5<c,$(Qg<`pbHdcWrar04b,_Q;S+)nS9uHG;Dgo5Mg6Or0^\QFSr'(&@ %f.c^k@F/Wto%IpTS+)nSe&:^mDgo5Mk*\F?^\P:lnb_gF?\Nta4ib+NT00=T?Jk9kk[2kVRs%#_0Qrpo1\C9Nf[%p8);jiE*j4km %IVu4U?f0o"p_R2mo^dP"2HYaJ#/6MB'jP8#nl>)cX\nO?7f5As(>MdI*UnJ-Fhg(D(&V/$J%0eh_rH-F\44,8Y<2I4[YJUm]bGdl %=.]C5mgf"gSXV=Q1_.cVX17'W2ge-F9)]Mo@/9/1>"do.8=^bb41+VSfYtV9hsiY&p."2S8_\X8I-:Nbg2WtC[<]FBp,BHcC2EK; %BM0D9I]e"lF=/kaUuhB8Y&E'plET8"^jGfse+;DN@bN.*4j<Kn#]gMb03<B=e1g*FnSD(i:^?]DXZ^cU\VFs?LLM94cM8rlA[tS+ %5<bG&VmSEA@qYmM6S!PF=6/(c[H%3B@ro!83d&aC8RX10q9luMb9u'=n-m"bY(A?B]NQ4@ajP1kq8N'^)Kj8kY0fk%q_qT!pq,nQ %Ib>`6K\?*\T80i74780<NRnSuV#5FDJCmPrVjN]$BFb/UfmASnm]8s76K?GVN9;UO[Z"BiE1cqFS2"k2f&fJ10"-,=f!i3ll!#Vs %C=j#2qnQtt>rS0o]%:*CF\Ya$p-S`>fb:PG?$5k_pbtAOT8gV[IV]Km31B;=<XVb0qIJC)(s<heG[,M^FLTGp%fAF/o=^QS_rh=h %AI<S=I.ME(Pk;oEnY>Do\rQ9nV-3HWW5!WCBD1H&j/mE_Aok<A=m]a4nG@W9`Br+b*VdaJ:Of6PLT%H&Vm`3f!;f:bmU_pe'5>0n %>nc"'?>nfEbdU\hP3Xd'Y#[!1h`[1I(l^.46X/V#gK)<]fAALRpF/3,c!4go$r\3np6OjMf=g6ZRX@lj^6Q)Cc#,M]EdcMOng^n$ %[4:mUa68qToV`-\(:nHm%I5J,kB5063P5!6rIeJ_kM^V@;P'Yq1sDZ\G8RBJEj#B(>nZh:$f_fPZ::m>O&9-XpuF:_#MU-h%qcK( %!uF2l(mJTXROq:j;<`W)dbNZuD8nd'lD3U03hFM4PPLr=#26+8o.&\i_u=;;b5Kj<L[0)jQBaIG3kl$lr3lMh)#GZ(TD_N#jtXie %WLhh8R"6HGL3M"Qi+Yf-e$Db5rN<GAT5+qsAbhXJhM%LX0'JJO8(nL9REA^ZB2=GQUKd4?Eosc\?UMD7W(oJ//_6TTc('qp(0W<% %GYdnClA<j"&[tfOeaT(*9m;A\B^?K3P?Y:0/?`I5>2V)VVhA&gV(jJt!l%b]4IeFRifd_b!<-s"He]E"')D,7n'i^@?e9)rXe\fu %E5C%e@^"2gh%=u!q2bJP2@-rM97k7&DMBkFnWQk-9'6P21\^4mHTj%ZccLe2XFg1FZ]Q.ab&(=.HWYk0S7haA5KES^Q@hkFC$2a" %ERF>rb0i8YP>\YQ-c;WV;!Z!oD0IHsgQikH6T:`df[!it4-:PPQ0re5'$Wr.C[CHE67kW%"5!3=/^9`m`md2+dBcmYmN8W!%?Or[ %5r1oQP+D\DoS_PcHaHB6?e_IhBIEYTer$Z&T,sT<j6up'oZc!3T0@bnro!)3k2/?eICf<#s7kEfh::06I.r$cmrrI>\CnO0^O(]R %52L+IiTm!#]=[h3%hH-.]A%P%5Mb/nk0s:Hqn&=NoeLa_H[j'f?ZJfIh;#`VIt%.f_m^/#s)E*!Y2T7rWUb7:q&S;UDXR;N4*0_Y %^\+2!^ZTD#br,7pRRaC7h)t58:OMPn\b=-Pqnu5)ba3e@90\2)h9BS^mJGZ,^:Sa+Gn1@s]=W=nj*gOhe(sTtp>Y,g4#DrQr:0Br %_qh5[mr+h<"MXob%G^L4p@8)'+(1>)a^b[b]t\jeo_f<HpYYr6e'4fRg\5n6DP-rV_enn(]7,/(o`":5S'CB`bE!1C+91F"8)HOY %rqPIOnT232J,aK^Gk9m8qQX70Vn\jqhg]tX<S]mriSP_p5JI$mJ8b(3>PMHprbnFt5%5ns5Q0^6k3bIj4ktLZ5@J]j^UnoE)uO"! %5!6[B/t;CeB:.tr%o8f=m_8W6hXO.l4ZqMLO$3O<rU%5/Rgi057M_Kkg>+mM)L6]@9tIn45egtU_[obCqM+=3GN!WBnGW=#hr=e. %KBC5P?i=?h52YpimQNj";+kW$pib+JWm9FJHOh-_jT//kq&Z.!oH"eSc#qZOJ%Y`)k8Qs1i6kDNHM[OOQAE0+QmK="IrBRCm!Ri: %4>ah6c[TYqlS&3*^Z:<ejGU`/okD1Uj=>]*=8^oUo6^K%4jMQtO7tTqDOuXp\*oo.]g(EEA[h,A6h$E(*URbDo_J$hgZQm)*c=2l %JpmFdGk^BjGIMO`qq[9+]^>ask'%n3J%5BpeSjA=2L6%)g-*/s6=5sa>^^*&6=TDF5MSY6hF(GN4o'=%038L&:oh7_]RTe<h=#gf %rm(J9lq5sW=(Par^pr1ugZR;rGgkL(5CO";imSEM\)CH9"[FX-DK0jiN@Tbs2]Z`2:\V=/n*e$ip'*SNJQr:p^41TXs7m[sKR9Zf %',!7&IMd";r,DDdm?K3Bp')oFDP4%Nlu-dVLE$4[=tpLGoA.<^gT.>jAC\P7qp2mpn*[?YVSJ*3?laagoa`/Dq"4(#%K@404a4U$ %nb`U2pFDUN[#quXI#m.nhgG+d)8>t1kGQY`s75^7-he-.107hV;>g7[b=D?f:KQ$:kDt,(qVBWL_p>LF$fih@"i#HaA?S2l%(LJo %r_V!2F`22LO:_)uJ![3"o=]Y!g:[_5\:;#:^'f)1>Q=TYSR9.,U!0o"rlS<6\`</mBM%!/r"(>9T7jt?XU(;m#GAXMI5Up\2!e<< %s/mFbY&(iLp?DC*R9KH/p\=3$%o;)P@J$/lD7o`&\'Ns8<K!u3Xnj).jm17eTC0Qa5CN;JIG1j<rmU9/q!m?9hB>-(m/HeUcOXi^ %Wk4]@c1h6sRhmL10<Y:_^AA2cr9AdIdJ'8/O$@^M#NY,)]a*]c++aBj2c(hLgNnU[K<fD&-mb)b8dtr2/X-`;%qTED-lXQJPV!R\ %Wg[5"F7<\sm+VS6#mFmq)G3AoduI$2AUlO6fg(suCoPWTG#\0;]#&SY=&Q#je5W@a<#<;q.K^I\:XH(\7qKFanGfB@<)@=C/cNcq %G+5)GYSj-j0m9mW12h?*4oV&\.-4FeIg;N\l$ir7T*?_([%[NK1f)k?2smOA[b-mB.MrZ^9=O;^$rH9"S[R;?DEDc6b>?EZK9<<E %`3?l04No%7c+KSp2"<ocmttBWV8Cp<2:*dqKS."T8G#^_-t<Qh/"qO`e/?E3gm@o<W(Jg]f._D#NYtCF6T%3`<)Wt&X6+.umH^K! %l`.*n?,HfS0W][cct_L(YbMq0dG22flN>E,6urg$9U!X5Mc2[b1r9AVS2Hb<L*ikf`bkn=[dA7o^.79r%4eAGK/lWA6k`%b>LQsr %2#K.'`<;A[_A)Ys>qJcW"oX-(KrLW`m5Vr;NT2_d@gD=u)/JGG3>TM]fXYE3[P1@D@2t#qLNUuSbtnr$;"XX6#?&jUTA\rY[%W8_ %dmAt-BNa")h&b916Ye&_2>TK0d"g1<B56X.fn%obMfXWE:=/#5Q>mH6DdaW#(ltsS@/98i;tMHMTrkSRJ]$k1_CuHRR(.`P(g>^" %'lC@QhF#uD-JZH`i3jV68d:Y">kP4OC[kE@`0GIBm@ilS12!!&$!0)[1%Z$S)^i=Ql%_o?+d>e1>T0h3AmD"5?uY(`N`K"Q];pW4 %@(d:89,,>dapuuPXD-;mY_e7"3`S!aPkt%3<kkXe.kZ-P*\5U:k3@kCVIuF'4jEASL_,cFM.V$#1HcAulD\k^k;_c:c$W6=%LHGR %VVTY4Di$mQh!==mr3o'rGn%]m+KPZJ#u&uT>3d31q4<$FoUgVnZlAZ#LAooR0!RWlB[P\1T+6>.<l1JMk3"AgF-lgsms$5KVVRQ: %$rK:BKj/[hg1.t\8jlIs*Y:a_H:[OmfJ3'fWBe.7\"U+`9iO$JN92K(^1L#l#UqdSm'5K#k&%*p2VkdP8OqI,]KId5Pb$]tUMNMl %p85!_CrRK47c'"ID8i*T+`G;@)pYf"AL#>]KUkXcUpEaOjt(&LoRsOqdQ&NA">VmQ5ja=.C8cY`1pBA0+F!u>M@C-4/J,e4)[ddI %'bJGU(=+*r@nX/+B-a+0SXbUc,0k3Ei^m84&P+L,0jq^]Gm?Gf[_b<Y(U9a3]_>s1oGe&+'ZsLmq;OMXTaXCd4,)>rAMok.@!4n? %%UqJdk>8mF>"G-40>l$:cErXf>mGhC_<9cY;V2UBCkO&X;66:tOV-+dlA5'E.HE$Z''\JQ[$&QsV5FAb@R3["NeA]>n2YrY=,qAU %eq(6R<'NLC6m"<l51gQc<%C'r00I$@>QAtcG1>D4Oh[&]JXV=`=TN(<2T-",G$l[K5sZO2K;0d-TYY-9(&":J(1ElX\'r*Wl&R3a %fLVJ1KTUA2PLN1LE0>Z:bD;9kN^MJkUr9q[ISr2K;+S-9QHEJ_Nu9oOr>fmKI*U\YnA<.9l_oJn)Z<(K1f8U'(o<k#f!B)-Uq$Yi %Q;1.MLUU%'Q4EU/*qD'<4=Q967d'\[XRkmhcr8daN44a'C`=8Sg'fTpkse.&`^b9cMV.E!fP`*<)^&4:@(?HcZ;bTD7P%'=OE+&f %\VP3i9Xnb>jJIP&Cdkhms-hM999jJ\V6WCe*/PKe&5gBg\]i,Cm\K46H2,<ESm+dcW<E`NR4XQJ:<m31I7O<YF@99lUK5]B4Y&r^ %U&Q=3_#KRrE(N`@:"1$EET;lLm6kdTL`7Ck6jMZS3T[@Z?tSDjpN.Ur:ZSHCQmn-7G.@!tAg>LD@LWZ&/I492ZR6ooLCTuM_kPFE %_Ti@=*>Nj3&:4-$0.qURF(P?sR(J8:7*BVZaYrO?qD'AR\:h6/`)Xp['%^[_$?;VnZL7KeELst3i^g.t=a.4?kHL]`Z/'an>O.l( %6=M/WN6]btlseec\9Cp[/'XA#K`&)W[GM)H1IKiIF:)daQJ8Xa/^sfhCZolCTJ(PSm=A&"IVC;ped+@3hn`?J:#?LBYBHb;'5nE5 %c,@(cYh3np&$VUeUMGF&f>QX5BQo2_1,$?gP(I]"ofsa`RP\tm<"=YYKS+?,.u@<W6u-Ta&Y%B^&.MW!<:MXJLajUcDIFtkjhr8j %WiW/IU6c[!@K\`b,%D0&6#:Wg2^4M9kqH3';<:<5+B=.);P_Ht.S5dSBr?Y4Kr7<dKVh*`K;V$`Ju8Vr_9;n?s57ScFms\?H/Nht %H-g9HA\</mH)u:e]a4%46O("D\;Onenkpo!#iY1c.K":JhOcAFGKbMj-W1WJ/.^h&cSOAiMd";O=2^%4Ib(dccuqq(TBK\DkoW;l %ePTs_ic],&;FMM,K!Yoj$p&YOFEBtT[/t"cIX2#o2%Q`#W:M3H,(qSe:a:dR;IZ<UG?tb'h1R"*L"$cB6(occ/]gJ^W)-KJ.P"\s %Suf.-=fEkp5'^6ZrM"Cl@S[+e(RuHS\[&:X.Ug/K(JPGB46epYAI;;UW!oU;TZVa4OKe:e'YR0*8B.Srjg#P.@M08^0VX3`<N$YN %rtN<TSb'IPI[=5CpsTq(6`::"Y->u_a7k:kZag>gVXoqU40Q057n6mep0d!#"ZrOmeLrC92Pg,=JJt<C[tK`;PLd2F&i5WpG9Z_# %NqC#`!,5j0GIu]4eK7AVYpC\#W\6u/"]-HG.YB@l^b__5RC^JA5l0NMJV],1,t.sH?Gu/91g.N=Uu$k]8HGjSM"HP,SB0YWgcLj* %MC<7N?%`Zf*8Zj(Mj_#h\A_[\Mmp+;m.B(^Drq">s7^5]_h'GPW3"IHoiqF;Ng,Q)4At_E=;`qq(^OL7KX'([2e?l2@;`1NJQZ7$ %j;KpXH!FF)=)Af1-*(g@%'pNFIA0m67L(TiHId9oRYAjs'jtP88EgC;1+Kt7S60L<'PTZSM^pFk#E2bXC2Y\\D'_IL0-f_n2hJLm %l7?m9imleB`FS\r$u7^tnTlA_`1EjY$J2sQ?PW>KM/8a6^@;+(,2Oi8$S#+nr3]i]#KR:r9.J.,M9!rdjXkqW[+6hN09[2'7gc!T %7D/!.HJ=7;M/l<Z@P`q2H]i>k:*`T8gE0#F)<=J"q6M@^D_4k#7HB:/d63=Q3spt$A(JJ93g!C;Ep4^%'MG>UBoH1fa\lkF%+efr %<>:m$?H'3i,X89dg63MQibQFMDdmOFF;?FJ^.ERI8pHY)0M6u-?ehtWHH'I-m$F0$[7d8N4\GT]H\8\Sd2/,Hj,UXmA_"Gll:>m; %8ZJ[jSlk'0":hmbEU:WpA>G6>d'<71a$BP:>:JKp-$GjjPVjLo9`E2J[suMHQ[TM%)OJ/T%PW9.>f6^sbIY6q:&^;;>_Y1CE2CF4 %l2SThPC<"c37u()ORfVq[rUk2mG`0I'fn^`dbHFsm!l(D9)ifSbEZ87Upu@O*7$n*`7T$9R\)HcgULq@m>uM=@+t9``H&DgKbdG/ %1jfp2pfQ4Fh3:6eaE;bVQ4%VZG/F.oVM&T\5lF""eOI*i"3reTN2%U"<\V^A^@>)/ZHJ\uG@HH?^kV2r7V)%`@fNDZ&G4fC!jp-D %d,HimAEZr\BG\e;@Mrmm?)/-\Lq8#>4_-oST9rD^Y(N+/]f:TYl3ug26"!`e&^R\IfEh-\@ipPiHFjd7K3pG-*"2X=M!nG;"&Y1= %Tk5OZ(bn)jQ_)3/n:"pf)Pr9[C9'TDlt;'J7Tt5+q1u^n7Z6[!/Ic8]_qEM#%V!0[%MoLs$`Et>1u]f9J!D^>,R(Gg*u-Qp;&Q?L %8?"n-aF2&T3n;-p%'_Bk7\H3`fi^d2a+?gV1Lm/SU*CnXj3.Mf+GG@RK=1:hV*J6X1N&J<ShgJIK,=ejLJim`%-_GQ=XNIXilh\S %]C8]%<T/kG4NNWMT^0Dj_09Jq3ap`b*l;1OCi%=ckcAT!rL-YJ=^^Ooi/6itkR$cqCrub>f*iC'gslhf<rbNc:qZ(n/ZsV/@Kg,N %0>>!0K'=LB]jeLd:,!([89!e^nfDc]Tanp-6bGRn\SJBA@/`J#?;_*;!k:Y"!*EaBKjYOslaF^>2Zs;_cR>j&jU,0I";fojcPF=6 %Jh[]H1R#*2pi!aNWNP3Ukecr:\;-]mOG+EZ+1?knCP:)E#fiO0,k9sUg["^ICqA%Wo&;.'"Wf9-$a5)P;(hMBlW6mn#3iC#0,!h% %2MYM`;f`/5J%deIqqN.LC")ES^"$USn&51jqtKPtIpd(`qZ`WgX7J6sPTc_?.Re+jOqOphKWOsTd7&h#OBPY%<QUM5F&WQB$M;CW %dZfnBHQ)*.?rboB;))n>n=j73auHY]12GW*Z&&R`7#Vba8Y*(V`#gQOP+D,6/r;/HV?g<KA;H<fWdkWF`>rM_*"_[*aSdg]_jh8/ %4nY[pjHhTa(WMJ[*ThI*D.##:jDgR)$2b6R2]29q_h$>OQWQ6(I;%itXZA4EA41Pf8>^$f:u/-fHC?jQK[ZSLM,d27Z'80:<Q95k %mhb%c4W%G"8d^HOS.]OK4;sO>,LIJk;&sr$;-%D<0m\bS[]$Jm%oQ%2hKs/V\%U5bmLQQL3mpBn;T.EDKS].D+[Z,#'.ICaHO_6Q %$4nUL*-XUVZ:!_AHoOWHYgPn#*@13mR8&C:22>E"VCIP<D3,$]XY=knF#QTBB0P1SE.4Vmc!^7*jmP'be'cI)9"$5,Nj8L&9;k." %9kE%\=F__Ocj(`O'^,MOaoD%>2:o*6+V=01X\6so=kLg65M=hfSrg@)d5KjrWY#bG/Y+gnFcQ)m^&Q2d)mrZTiiY@8@:RU&gT>'5 %-mX0bGsRoplc<,'<[sn2lM8RT$+n9tdX/_!I-.e,92fF$W_>C*Z\j=Wc/djVP;De-A1JA]b97Vt,oUrN8B$%7L><kJZ!VPL]CQcd %LD^)9Z?#e0#/He*SkbR"]L,bFJl:CqQ[HV[pu@SrJ@4?:pk-Z/'_)Hp9?:5&>\%<tX`+ZC."SZD6Yp+MAD#RtU4QB6lnGsn[1k\s %p7ep'f?&a]>*V'DQ?7ZD]c6)"aD#l3DorO"'G'&uZ4f1nL6c[NEKoNh8]u>H>qA!j#huS'ibLPH>Z+ASd]N:L2WRM:d/mD,93gUm %hCl"n?lTMGI6\u"8Q?srQ7R+O>qom^"m=^]dN<m7`L"%^?^FDor03+B.V9-@(T,651#V<q&TRd2##k=8pREI"roWW%=22>Yr>+Hb %s!Q=WV+=SuP:ELFBdgo5Nl($t`RQ>THa2?)5d%GtN1I8&Zpto[H#HIIdDW6@s6P_Ss3LQ!q*2OLeWTgaO[rJt9eksj<Ca^%+l;UW %W[pLKaD'a43+T'J--oJ.0V;6g9BRn'2mbcCp6OPSMXN[TVif)`KdB<HahcR*<@]BbFMK=CT\<0MONX"?oB1X&1SkhJHoskEL5.+= %*X9H,f0G7r8.r65<`%b*$Bcp07"<tdD\+[KREe!2ap(Z95$hu]`3=hQ`?9o7+QfG<>S;_-+rNJ)B!en$IPt&`@s98p(l:C<[P!]0 %7;<<+Cat[J&2JRR@e+QWm,K:A&!_,UF%P`/G`8p)Tf>5of<`!"H`j.6T$E&Z*]riN]FbWan?1$OKfEL/auGQQSop0f_>tFpj`r7\ %)j?*re7)":Fdqcnd[B)@*p:EKD3/1sW6XK=&5BKAj5KTa28VLm/j,(HOUiOJf-'`':%%+Cck4jg=U?H'CUZg'%nP.EF>1dX[^P5e %W4_J?H?'60O.+U,,=cWeagm$R3Xm%BQ1FJs\UY(V5NblAlM9lHmAHlFX5+;1E3MfMiG`Z+E!>3qVOb2I4k0QVWdkf"dt&Y.gF_cR %*Lp;(CM-u$IPjnbQN_G,*HP#:(3U:DXiqL.[dg99i*BGgp=-!2\T!F>KEIbj]'tJ'\01u5KM[spMJ!d=4OO!RL/LApp-+"8'&d;Y %[W^[U(((X0G#>'PBQ4Yi&h"hG'Ja+f-8Ha_,ue1jTnCG.=VOA@dtsm7P82KiU"BGF)h=,cWX3Fo69Fm[r7!E95YYW!R*p)Jh?_B" %T/\hf7?5HMb&JoUKl^Ql;Bpk:'.6"S8u?.M*&1tdDkdH4oU^044u@tM=I;OJ8I\AAi2"Kj8KE5@$;YO^h't<tW(Q<,<HPYOCr4bK %gk:XtarR;M!Wphb64H4Xcp/@P)O6&`i"C%:9(WP=\/&7$G0W/$(GcWO&^KnIApnK!36#qHVI?rJVKn(4g.701$]O!"$]`dc%uTuP %=#OcWE"R70&*/^7LkCVX3r.kW+/ucg10YV@8=LG^Jf/)W$LpM)m``"82bPe+B1m%dp3%9cg+Xf7hrCa3XFKE]9I)rD)P4I4RTnF9 %Ham_k1oc9`AtWuu>eL<lXs8M-!4d:tQ56%jOEmDEh%(o@L\tFL1?f5.'\UBa*;gAZ*%<.^e-e\rrJoV,1LIO:C,1@2i+*K(I0hRs %;m[je?kV+&ODpI`%R_haG_l`-KI[WZ9*htZ'.1<MJ16P&?r1/tY7e&K'^2Ak5Q_O/Y[\\nn-KK*;'o>;2#d77I6S$GJV"U>^\bnQ %No$=<j#FkRb,tNm?g&s#c2u`[_,JLI"1N9-Vj(DH29J?^ke)V;gD[6PL5U/&"p;dH1Aa6j`(!M?ck7D7^nV]Z`.neCQ?dTo[@m/U %)l?[a3'o.bL_)SNK&@ER^af[hY*8:]++E3llIAUH6nV&.$[*SA+BF'W1=1^dQ9si4f@FF9N6[?`ZXT1koRBTXC+f^ni'X:G&IE-+ %`7;d;&R-=B23bS#nJ2+,`WReYOZ<KaS&^Ko88jJ-l\b?Nd,"gNa4=X:GiT=";Op=)M\4iKCQ^S%_O51Mdp%bkI@`WZT2H".W1Bgg %G$-4NfL\?ab-I+B3/_?F3PQuRBMltp@Ublh`(!QH$k=]'CjZRNodQR(ckA;&NY1'aXOfmX]Ij8t+iQ$`!g`+o_d)8S:*N/[S4_AL %(3c@dd6NO7(U[X&ghu3gr7#6,7]bCt71'M^=/p6q&3V1`/qM[0)</+.IE3);dN3*TH`$=649W**%lJ^0m@>D?&`=^W9.hf"a.c$5 %)RZ(9?s'mR*Ri+IXc-JhD&om!XiF_W+H+5TY0.PM#HVk3Fi-Q"`a&dWY\nl1CMMJrTFjJn&W3X!"I2hm'cs&VY<K(nfOs^]*-H$1 %$%Dt<YF#8=#c>IH/`L1*d1%R<Ud>H2Y]#K(XVVImi3i\)[dihlUL6j56oi*BlU:_g+sfUqC'LGJ#[dpqc_tdg/8]UVCE;]-NK;F) %B*3iA/l3K%0TP;:M*FGENQX'Nb2+Xb=Y3T)7WKb1W\`9/-IbNe(Gs]uG5jf4%IX1PC]lOKW#H>W33Wba'(7(RZ4cjCn"_!$Yt]<K %g'F`+g$l=&EELSIf'b-:8Pu:q3-T;9/N*mIL8pa/7,c>tG4M+t2P0NGS5DuuQ,D0k6f!X2)0J<hQINn5r$i#bPP;!Cd5kGN!BkDm %gQ`S/Cg(K!4MC2g]GL^-?!%B/?NrS:g.?NbJ@ApY'ocQ,@:.%+1INa6X<P8RTNuph4*X7c9aSka$jR1^/hI=q_4e02irk[3U\.U7 %HK*Jna%'u[1/m7u*iILiBX'Y<'nWCS*)Yb4kUq_3WC=ZAXl\Kk<*mfCFErmgQ+@s0`P=;T/;7'Qc_7mQg(;^:0Bp*D8<Pu1^Q:mW %[(t_5@b?m!3<bM]YS7FI$B\ae6#:M4V+."XlYCXWOZ`rCU30gG@,*Y#jFY6Z!Jqao=gubDCa,C;LpWU*Zl:HgX"K#2=\%20,p6_. %&ot91IHs1ArJF\03k0'ZG'c:<mH"gYN1h0f7^mZJap?`p\]RNF"An(\QR%AgK)gs+*bo6KKe+a#>N%Z"hcn(m>?[+']h]5]K,>Zr %`Zg3X\F@dhaLrE@g`hG&Wa72jS)0q'9qo:g"&QKP*DY^k_E.2n++,'\<n',kM>\nmWDe0%n6U_)aM#Fcpb"uH076#d,9@Ad&)dl3 %>I4/iGUZMN[8\6\&]%11\%MjFjq'@-$_:V(eQW+2$%dmjQ7ie+@NX_YL.89'':"V_BRJrUnV*(G1ak-0ong-'H$*Jon4SK3e@R`k %qP>?u$e8Uar(GRiBrIh@!1d0lVLV$J^gn?=RC^=-BSc8"PGo776RUc5_gbb!iQIs/h$HVO_2[E2N;?Oi6a?Cg1A$nQ:01#3+3(M[ %E2p`8$*]Q+)M3tKr*)0"DsYX)pb;7lEKmED7tIDujK?3PEHp['$-t-4]=mZ_pu!-)KAYPB5Q:3;00aOW0;taH(Ba+eUfP:@=E@u? %=pK\bc<KQZg,'&UP/)X+'6S8f<X3A>2R/ujE2$th/X,Cc-4pLt]n>.;=fK=hV++tsPmCKp,jtt.-G;!f!e%lL&1KkU!0mOViVo8> %B)tl>IUZEgBJ8!LYE+&\Mgd5L+^<)?.C#YbMD?^.dMt"2_R_PP:7NZ2m;7e\m,K(uS<jNuAn--+"(1IY=-uJs@#)]h$2ie']Y_Ri %Kkf7/dE8^SH>+JIq8^HC,+6p.7AVqS)<2^'_'M'1SQ$JFY]N7op#3Mj"[E$pW`F>%;+jAPU'TWdjL56Enn,*%3krP`LN!(%X70Ms %RTCn-/$r.hs6.*0W@O!Z83O8rc:>R$\/1-Q=b;OH[4YXa)O\<r(l9Q=>87=qfJ(Lkd@/*<0GA8UJt0%`_,2`);[BFadF09b%_7'c %5ReOkONGJ_pBf2<^uEut$<=#*o^!]tgJ<AU7QNsV6%+YYOVHXs8lOacoKHApS)aU/^(F\XpAtk5I%<'+=IVB>rs%Om\Kg[TYf:TE %7=Paofac<3)U>N-cE7I`5UlE5,sB2$!^1aq@qt$`BUUUX(g.qVVQC\>CN!gU..P9JE&f3sRZ8L"M=ptt:(Ek7m"@`=Ur\oD*B(;J %#]./mT2-7e>PMa&Es3470S7)2Bbt@fFj>cRe:'(*Z_KASTQ=GT\,%3,4eV9HD[;(^6&bYdE0gVWXG'`ep%V-t%5d7%?S&WZM\6]F %"%:_^=jWQRb]_S`V-]C$Xgn&-<cG2;X?onZ?4hWX/>hJaB%WUkfhbS5S>f_F4-`1*nfV4X6HGhDFV31tN;I&fp<&o3#D60Ma%Yk0 %J6(i![9AE`IRVmo#*(a'Wb\hT[i+O8F5X%hO>@bLE]Hm>K[r[p-77L[d8H.(^na5u#a09RFTrf.G@]DQT4B^=UNq7I*Kng78\,9W %rl@WGG3"QDP-Gtj$i;)C@VKV:Z3!USij>Y]!XZqu%LjFU&#:5GW'FQ)jf&nN"VM1g'hg$C9JDT*&eP_3KB,<"lO+gJDo1Y+YSh5+ %]dqqdnhQ5HV);jB,jXD:[3CX5LP%*$[iS:4e9#?,#$D>]8haA90"VV[8siXqLim`Sb/*<T1rq+T.lGi:-l28Tk#W93cB9he?!qrY %n5UrK*HdrZaU$LdeWb&lG*/S*-E:Pp<8Anti"`Ul(S%0DaNGn%jdbfc/&`P.qIj"8nBYVD^FJhtiTk02JW"mh1Z-,E'Jk_!nd3AU %a)SXjT])7!3(3](&Xp+O4VL[6'l;RSQ/kE4<0W$(Mm=YJ<TLc7YS(/mK"'LpH't?S?VLlu:A(EhS6!MsL't\+/t5BqF_.@V(.'ad %7'a-e6:o*G&Vph4%,=;4iBWKU>7cS8(qNMh52h,&S;C/Rj<5(i;b;U.I-k4E93bAI5ADQj3Q:Ynf);)>q'Kl\=gP>o.0Y?XO)6`] %hQqT1AhZPH\X5L67Y]Vdm,+jo,Ycl!(4#9)AW/H88EC&7R_cim]\(pQg_0<6.^cqk`bc["G(iBM((cdoJ6<`C>C<6("XNi9CUm3[ %P8P8)`Eu^1FgfGfQ_*4Np%@/$a3V4*=22Fqs"bJ)6Ph86D5Ml[)FV_cadT]/SWa<I*P)h1j[m6BB()fPph3E_1RhW(UfFc.'c4t+ %7CcJc<?#U:!OSLg-hn:0jVGr1*[jho`+]47\d)-a")5Zj<mk4g*dcWC.4d@E(>aB=n1Atnc4oGQTUq1qM@?LX?<[q:$^SGZo43Rh %@fiC]"#[(9e=%EMX9[H[_9'(ic?"^BA-Ual86</C7bR3XO/6j$;[ji9gn$o8CUjAc)>1DkYdL_lM$4leJoN5s,>lRf5/Bo/5kQTL %N$XS3!m]AfK+i3UDN&Q4%57eb*)de9$[6R*FE$/O7q+UN/=a3Ok97B*@bh<c\:asB3Ns[t9G-5fdeb.ik4i;<5Md%s`kYr8&k>;3 %'&JYmJ8,4'#j6F7h+#:hj'_`)Epg'Y4jhTXQQ7Afk_2j+CQ*jL"s^iUJoHKq5eR:t=:%=b81$>B%tqT>5.158_1EY>/ro*iI*ZZ6 %GqRTpLdKoF+6jmKh,t7c3!kn4*/(4TSM0J4FtpLae[[7U_MqXM!GtERB9XI?kV]Z$QU\`D/NG4mjCq92IihqR<^#m9N!Um)U9IZf %YqS6=LHn[>%C8@+a@(*Y5)@%\KFq/HM#1K@$EF8+gt<N^Vu.Z-?bR(>3#+*:pQ^/\$j%h`30c/F>o2IiLD]rNRWUORIg[j\q'd46 %fSG`Yqd9e&!CntPlPP1^=BGt@4<\)@kOZ1ZI'Xe,h?b1_0b3usS5ml(^c;lAH!ocbeQ8dF]WXK"I4>`i5oS8L\Oi'c9D*#ONHXJT %0g>/]:,h'-DkS01;ZsP!E%#Vg+qS3P:A0o&W^p9S.Y^'mC*)Ro:7%KkK^dXfZ8U[gZ+ppX8E83k<bH-SQ<%oAF&RL%NCQ1PM((X( %OBW0k<DP0p@]Gk@!cN$I=!?9)NS/Z`C=&R;/h?g+Q@4okFglCm#P+#gS33Up9=$Q0FC^0M;M/R+V!VWn6\<3cl:@t9bH5H!^WSN` %XfFrLNP+jPO8+$`Xs@#4\21K<p/G9k9&e.CPoRq_kem2N$/1Q8.liiaKN'81S(>EP[!`l,m2Ca!L6d.^N]W'"4_Adt7r666BJu-P %DTA>`p.UAq`s6`J7]Va,Mj$hY['`QXn6Tr!a]WuGb7$R-Nm#,[i03_:6fD?do#\]$]FL<'BTRQ]0Um%.\CUbf#tKu%a]XfjC8.q$ %<D=3$h-p:e%PQo@"-P!MPl-'%\rXVt!J2Z=i)t9We:s.S@'%Mr!'Sg0HA@2b53jgm+P9Wd6V9BV<-B8N.%3EMOjbp!AL+0jjBjbq %.CiLOK:U>X(MP0k^Zd:\ihsE#LTBeQ&,2.Rn"*CK(k7'3.9*39gP.YI7B-^Ir9JmUAI_PiH*$Y`DlOY_B(fFZ[Gb5h)UHSe&#eGa %8Qa@Rj0-K/lrs;MJXSV1I1i-H!%<N2j:!_;!:U7**bPR5]+c!V(:]2Y4R#%j/n-N2k8^A+96"*9RQ"ip=\\2rE5Y2L/VH.$@"jrE %aU*oJD6[B;#ph_Em2EcGpB`O1#:4@5pU0SB4Q8S/>3T*[._XNH,pW$4n@q9,]l4bWp."5Q!,LsWW<]io7=^G=hFOukN`!#]$eLi" %NgVG?N/OrN330".%L(CE"\kOgeAq4`0bjoJRGN:pg4eNge]'==Bi#Zd:`X2'"U9\n=0/ukKs6*6CQr*2#4/kN*U!=K)Vc'-KeMCc %[4?C3"C.d@\-R(sYHXO,UkH!fQoS3b"=9#S_$"FHP#,GQJL$.Fgb6Xs2-JJK_Q)aMIl/f/ZJWschn=mPR#AND[mpB4)]dF+];Y'@ %?"/pIk"5Wl<2g]M[E"e[ZEP]pVoW!jl3%rM%=/tZ]1^M[dr\"_I7]86n(GrXZ'e*L$+i/$g%@_jU+IAsG;E_?%Da$=^^gJUK+n1= %@'s.k!tk[W*D9m6QR0r#]'OamD&5PIS">t70'>89&t2_-?)H6%B/B>q0)048nX^clIOl[kTsAl2':$HVNI`12+[].`NIu*\(;Rr1 %Si[UY(HXRS2VnXhq&IbD:-O8.G+rbUC7A8s9lD'L47$("9-4$4nRDmmX1GQi"IYAq#C!s%F$N78Ebe4boOA4$$0LV!ZO)ce>\XpI %'.@.jGY/::P(>\(R(*+6P"L'f(LA<`LP/PL_<1hhVn=.Uq;KcIV!+p%^QjdeR`BBThH*Sd,^-+"O\53^-0n&o/p-;4:Y2p@g,+h- %h8Z(.F*3iE\aJ?9p\3H'Ij4YMadaZf0W>U?V4T)(mR;#-,pdRh`eb;K<223BRLo1%e[*FGo4-'#;rcH\W&`ush5k(j>BRC:P`u#q %/sH5)7I"Npe3Eh@THV4HaW%KB!tpdW2&SQ)5`h<j]-q0'89B'\$JOV4)N'bJWQ>8KJ2$IQ.2f$/j+Ls+Nm-Z1j%O"9&nNV]WM!lb %O'HoXR,\T4Zs2ghnbcj%e18O4TOQ$F,WWD;1$\<A'5rm1)`Bl*Gb1,#8-,O@Url:P\p'=k\Kj4?'@#V^M%Y-R>2n3',33ZG!>t"b %f!C$47ui*=*@_Fs<MYO#"b.[?XQj^qhpW;]@/qCZKl_usaK_l25u.6P#Y(I5D*C&.S`mY-_I!8a=6J1n$+Hihi>+`PDjC>OEkK5K %G6rNl`2j8@QR4!f%c0+5figQqS&qc(c9Z!eBM@'8%liOq;Y>?4YnrQRg:E_W<P)>@)dU)%Git#eP0%U]F@3@4,Uu0^-IZ4?BstaW %[P0W;G_/9.nd/QeN'h$<X]F8hoIDYf,qD0<s+R*,Qi<gTj;JQn/n#s7o+uG#CCHoKKHo!4>f>L$EHgg`p5W?t+g8>oWjtcI27@1) %Gl4b9rpGs0s/dU#Q3:FfE@^jRSU>-#O)3otXqe@3#M-lb6Qp&=O&-q!kb;!43_.Ft)GX5V?/A26N)$,hj^9)@l>.^.lf9j7bejAH %4:Y"-fijaXXFqa-QE]n<+VcA]>aS16_@MQ3)dfI2fnSL>_)tnG8Y+irOEVVa\.)Q\JLPU\0R6]o1oi'@OtnAZbN<"$R8u2sW_'Uu %8cM,AChKJQHfr:W6`@)4AV=IEJEIcrf580:fmE_97A7%k/5OmnKpf[Q!je*ZqJf@j\\`a@EW:kQ%uR1o7H?m7S"N+69/2n2SP:`m %IDkR(b3lgY9-j:h`5./6jo)hj\kShJ/TFA?F2+)>4.CCW=6@s,l!0^upA>fPc<,5o:NIl)\s"Zc8g9UbI(n4j=q[>ueD>#0BHMN^ %N,-fr)fo+MHVYk9moYg68p):"eZ9`@+tOO')M8s:54Msjmp!-YLM1*iag.!;D@G`?]Hld<[(4%[+%Q8m<]rX44s,p=L\5W4V3G![ %&+op:/INYbUc.Dl&6\m^]rt]"?";/[q,X-5FK*HR,HI;6(A=a^N9kJIB[DSFX7VfPpJJ@sS$>r9`oJ`m]q%fRoBAq9l#Pm&#2a%^ %D$L%&1MH8rHH@cSiS<&r3CK_(&&o4o=_r\jj9rQ1Q\8B!Fl0[9WAaaGnS'[RV<b:H_mo!OCHQbL2GNUD]!&6GZF7C5S$EF2UgJ)d %0R7ch?GkilX4&`3\'k5d]cLAsEYEptf/?SoIgtT1GZCS'c@3sQ3)WgX?Pdk@Rs:F`$b@6bK!+C]L:)\qc3[\MrSur*LV*:^hoSAQ %F3BWK?B&0?]j.VPS@J;Wa_@_W/b_H,V.R,OHreEcK&F[`j-%?HSD(7O*j"qC/N$+.927C6jg$,?)pWT*fe,5IOYcg?QWc`PbJL0m %XCP6e4qT-rD?iaQk^h5("5/Q!@[R?GW_#.FqH..WVI^'b5:,b"(.JcWA)i!-jLn2Qp6XF0LWaE?:Wq7qL*14n[h;36//\@iriU'W %qs#PlOm#<8E7IO#%G,XF!Aa=:%7&VukA8s@e0tj:L5J$kUFkeL:t"#p_A"O`Fd-$t?gLhJGqhg[C9b"Tdk$3cTR=6DM7%S#29lTX %XXHiLkdb;c4`_HXU(WL2aU+]fWF\7o>g41X/?Ebpc@XaJlU0sO<VTpr_Z/?>nVdf.8uh#:cP(?2%Og+E8T;-E&/\\",2d\_6kg:I %"[tsIKEd/6HED/g9!ncgmS),\Q6?rThtSt0QHc\o9%LBjYg3b/FtsZ5o"p[`ZB^]UJnM?2bdF10$;i96WK2&f`(N&al.0Ca(11@Q %R&S-r9U7JXfq%=p)i`l1HTcMs\083Y;_:Ka:KAXq]^3tVPB1h=AWj@h?FZcUND<[??#j0>p/R12g+S4:39_>Oh7]s@k<4!$Zi!.+ %:0=;MQmIEq/>-k^g.Zk/X*4kSPNH\;I!q&oi:CVM%)R)p2LZB4,fUI:SGVMDkTq<,?r09;C;BY\!<j:u!&k@,@tb;k>ZBt)C)9p` %/=]6Ol!JH@!'q9n/c`]o5huEL7fZN4&BqNX"/psO;PsMuW<p;3_)XdJs+@9@=iK8Z0u,`bfr7%u.I1d<h#_a`X411/o93j4e5:`i %ohH4KC97apn]"GDL0"Q/hT7Sg6T2p4+@0M[-4on#mU1&%/k2d#0)[&0\C6V^=W-169kMSkGF=-0CU3?l11u\H2erK]7V(>F^`%Z+ %q0>R9f_'EbaH)cg/gQR[I@Ll8F(]NbKoBZ>hshjhW1fbhMdV20]TB@k4[#;!_!HFW&SWgbK/%]3d#3p:2'*2Q5%e>u=D\e!VG!T0 %NY1$SUe9<:`"=6'1$N@CpJTI;7HB(,aPN,A5X:Qe!"j51LgG#PPOZ-sA9=%`'UL4(X[;W0=u2qs'Y.&Z`'ul8C<m4ViPHK1p2Y>_ %WJtId2S]&d)[[V</tCIt[J5-@.*pR9(o)$QLN&a:*594_l+V3cp1B<p><ZFR71)\sN/rh@:Zi6`H[&kE1B*hapj.h4[d<WeiEM#u %'d&PgH6&dWi=NSq;NYDRF!Zs`E^En[_$(Unb'UBi?j$S@.N(YFJWs,!fIk*pNEaI/3Nu(JaGpN0cH$/>ZGDCGIJMpPU7ZmgQYD,5 %%'2N-_1,^,Z3]<JZRi3Z/0'CEYj-(V<LB+VPb:<F;4tkM'<a647UHcY5Q]Yo"^]i<?G,bK5VWC/irk.2(#D=Vl3F(9=$JKpjk+hp %T`@l*!3.!A-P+r$0le0fc=aul/92demR,8bq';@$`pYa<[#^?+,$Z<.66$[Fooua3AYnsbo59DY`"H?`+0GIm7P7@Ba2Kq!`RoSn %Ed3MTRuEu/1G3QZY)hL^W33HF>GOP5`?GkiEKT/Fi58DM``[KJj.lbMlS;LuUSTk$$CKQ1!iEm9CsB_.qPC,oM5r4\l.8dOXhr"o %N7!uECc0Ep"PVR+>8qCj#e+(DgocFf/i/pjX?^Yd/^T=3PLiet<Wj-D1_4RY'g6T*)<f$)fpGQLEY*bAXQ6\$CF)\M2."m/5?p(` %p!@oBZ1jl3Qag'9DGq(4e4&FtE;D.>EB8WDaS6e6Vsr2*>n;se:<*j;jQLU*l'$bQcJa%%Z$iFXjF]>NUQ`k^Gg^np++C#>LJ&-* %.,jNQUS$^>Dmd*__*+i(3eiu)btd2ZcETGO.;Li@Mp$VA$?Ol]cRpXp<N^RM'<eb(Ej4r:`$sP4@AOX`lf(SPL:aQ3#EHl4?"!L\ %8=[^jF6c)"L+,hQV,TYJe%2UopZZ.JFm<?'<S'Kkd0EMhMJJrb-KcVR[YpfU&@H7?YidFA.ZQG03+g9"r^WC.;s]VdqFCg?`+:)_ %1dd3Gko[gj2[C\s!!J-Ie0brnO<F@;VEKcC.qT$qp;Nli,o%KMn%;CU<oM^L^0d<O>]TuBP,9ot==F'P=_Z(<[.S?bY-O1Ap-RW= %O>2PH"M$sahN5=lVX5:LDB(Rl.*.mn]Eu[6DOt.bI+*qo<_YMaK_76M43a/.]f"QuC$M4M4NH2b9_KHu*C:?1pQ>8p$pO:.]?LSb %dbm*WGFc4r)<1Q&*<HqBZk3mpBaS49"#.u1C,haMn'o!8##*%-&Y\"5(taPjBD1%#9hA:ZPL%/G7`jDZ^b"ZDZ>>Pi.>l6)@8\XU %b%:Zm:hW+$':j+]cGuhfJ4ACb5ebBS;u";+;pT`CMM6BmeI&Vt.Dq6Z;Tm(i).(."$S^&T%%CfCEd@-%b]btBc(iAb_!Ip.dBBg4 %.TK8I\ElX`RknL"$^DEc$%Y.;7lS38PeGDQFGEOG+iif4EiSp\M(Z&VDg"$gl59I_/j?Vug#?]4<&#PfdrBgoakoSPgGTB"N<uR3 %VU!Oe92V+WSg``k-+B[$qE["-!=q1DrOLoaY-eu+Ha.GtO"2()0%oe-a>Y%OeJ6.d"3'[n-Y-`Y4p'^V'[@MA[d9`073.!6X@&'f %o`sZ"6uB*#3;+h^^8eN[a@LV@3(BE&7?S354@RP:P<(GSP0;rkH:bCgpKDh!H>pG_R>j2o]+`6!e@@5Umjl@J[Egi.7;dQ,nad\5 %$X_3,0=L%4`]WlMYZAEh_(U!!3sCmJ`*;'NZ0AA=+ojun`4#5XQCg5F/t^,Y1FVlIe5>0^osKLM?pW'fkH0>bq.bn9=//"5bRbkp %Z"[\%)Xo!/N[6N;k)69:M;JZU(95ZH87el`[s4/h0=&loAOV[pH(1p_G$2#P3_Fm;;rFqkRu`@Wb837TF/L9@E,0,kP_:jc"B2h. %(`>LJ(H7.m.CLb'Bp*hO-`J\3?H_7s',/<1SID(sZFM[[@6c/#(#RF`%p=!I@Xam;^FA[!12>=u:g0LRNR+Nr)N!-0B2.l\02/js %4EY,f\C+Vm=K8F)\F03j]Ll(ejXuW7>U(R8.kka>EBU[nV$lmI2)X+si.FH2Z#afGJ5aV8<HG`+2G:i;_-\d,4DXee;:EYnDddHu %=R%3Ao973)>6KllehFrpimjP%XlbKha]c[iFT/BqZ_CE%.n]IjR^R>hb)9SE'jgf!a[0rD3F(N3-AUWq*UCrL$0q(k.;7<AFM=8W %M6^C3+Zn2PQDhX+8+H%HChG+5hi:p;VR>Da^=]#^AlH-S6.deP]p;p`iPu*B$q6L61RXI8Q^_RQ;B3NKVMjRgXR2ociSTNG*@n<Y %_N#8<o17L?h?>MT6$XYoCpteH0:*6Pb^-iXAK2oH0-/lsXAWh_DIH1.So0Z2Z02$/+XVSo</%T,S'=G>j'\kOQ!N*ec@G"Z\\k/? %,t_7BE".hC5r+t#_7`JR)cORl*QZsUL2S@(a0+p0b;>bZI4f-#%b$aX]PWs6B#Uh%X'l[n=r7"bY#-1.[k@6R?,RZq`Si5tfL]L` %=qdfS,P>8X/.o!dEe;o[kQlOPU,FLh`6p,D>SkI.@=_e=G6%u.1I.Js]J-H1^pY;)gS;P2"GMYg,ANs;7-OuPOqSQBrDFk:m\AAb %TcZT_p>g_-*G:a0F?4(UGoTK`b!UU^mF5'hPF6e+)PC=[3>:afB^<3uLNt[oaZ-#$Pj1Ub#*ChWp/^-VKg1D$s$jZpR4"W`F@rC1 %/NiFM4iFkb(;@`t^/]Eol_igFG-Pu=g"p=V^1F3(Li)/2dLV9Y_cdof'_6IhPqH9]0gn`@>i[[!>pkZJ0H@l2E4c&L=G8UHL"MSW %$UsX!Og(HYKs0K`HB:Bsk%]4jIQhQA0"7oD\lXr0c"&oIBK*)2_<f`/")%=r9/]tb_4n%HjUD]]+H9/=>jj0*h+LE2ZIjL_e"&Id %WNW:5't/W9l4rCY:0e&[,TqhDW/puk&mU1Va:EF>O<E*hPs&c]1TL5r6teoNEM?Sq&NTBWanaAdHIFF8BnHBLpdW,LljA4VQK/,D %F4`SQ>fq*h`AsLCX;q!q.^Pp*l"P%VMd'#E*,Q"HV=m+=<C0Z.lFT4fU9UOC!IuSm-5f\o',&s8/tsSJ7@*OWhg!bbKDpWYj+)Bc %$XQL^Lg[`K@]2'l]@*o.%D1#\'+MS#TE>Y7c_0k<]$?sAHI\<8\!/3IF6)uS/lRn5%&XUUlAcip8qI;:#SID/J1;+#GD,[B3'ZVJ %=2LJDMbPo??."0FBmeg(Xu&M\mR9M#YlbG\Sm8`A7XI;(LIr^B,K2X(DbAJj*DFbnojnU[D:ZP!r>@bL*)$\hB57a5C)RRdmoBPX %<mWg%:jk!:31$%@,-A;3$u!?KRL]Z92CFFmZjXUh+YO7M,U]R"Eg_Y3P9&d^(+F:FF2jJ/mnBp&Gpd3[ED_<)[?IROVnstf8-Qt. %#`&eU",=jsG!=AJ7k3snE"GA40QqOh.4hYL(X&,oi4UBBj4n%$isqu;'7X3*&`^f"S0geuH#_t!ent![;#E%CI`3ncf@Eg?cBaM7 %L$5$P,nlE]T![fg[Sm$C[M9L;D6(Wm"lWn%d:0aD3`@@W&N!9n$B'W;R#*Nc'%&NNCmQpJR,dT*L\1GZIY)n*1(ND9k,3Yja7j`. %pSIJ.lM_hd^pbp9_GL@MlNZ5uU<18D*!HC_5.k,-ck')eh/"%hki91Y`6$T4H.ag?Ct%1.RH,p_)='s'omD4S/:R)7H57<.B/tJc %Cf#d:L2`(q4<TAtDdWm<35R,-E#q[)TF&49R.+5!!NXRg!=)g<3,faCiGelJQ@aqs8#uha/-@16JVbse`:?`6-7C$F2B2do8:C@j %YcL%FrZDbl;rk`M1Id!S"34tbQW9O#X1[:[fGb-D,@PL9m#?\3Og$bWp-upU8D)gUKI,?g;Y5JIAR>@?e.<sq_lC98@B$?/(;g;/ %e+Sc(D;U0.A3M*n_AP2F\@*"/q-&Z<9MEW5jN=i7YM&"tjt]'^DVhItnCSoADi6t_EHPIHOh`$ejT+54clIN67)MMe8:g@>+:!P7 %R4,@,.9IRI_a,?ILVe4)$X4g8o;ER,LXo2bbj)j-I,`E9*TWPae$3\9E/Z0S/XO<.MUAku=Bc0//ISoH#\T&l8NHB='1IrUd^U"= %Fn0d['-2j4YC,(2WiKO=3hOArEPt0FF*?29ACjkd>mHGXWq``\`HQG/i`/6M"mE@iZTS<%"uJ)np<$L@#4L*)#':Z4^6[h(>gf$@ %)p#=N30.AMPe^W0qiqDPcsIfq=Zicl+nO]NLYqE^ijC:aobK/1A6(YX_K<@n;c;CbQQ>RP=u^)`E7)6ieZu^FQR!m->:7CX5A<Yq %6"7'C-13Vj9.XD+HO[b'lXJgN^lk$N&@d6V5XXgjQ.<NEd_Gs1UEj[j8MA?s0P)S@e?m:3V/jdXOqCj:---OQh9ZNZ8.]G9IY/h( %bY_D%O_C6j1fgDT$8a[(pKCTYO^q].A0Nk:al=?-'E#.:Nr"942Z!Tk1'`72d-3=\S0"/`jq:)36'bl!@/9=To,R)Ue"tZQW?-bZ %]p!$:U"Rj?=45lC?4;'F6WQ&S8=9c2]HZQ4#tgo`cR@JSKQObUIC=boWF,fPZ6a-qSdDs.g,0B&%:`<pK^Gn_h@,l"0WQYY9b#1C %d5X$"0<inlORs0#<SY_M,;cI*8F@%W@:1$CgK.4]ag5M4-u/-0TjDu9NGpr[(_p-kB<Y6;_58:WQ(FDn"Cks_\M(hf,GDXp0t@kC %GU<ipN?dDk-W*sO.$Z'o_DoLPl@B<PclofKT8s+HIQ\kZH?%cG"BA^9>r`aOM6h,3%umG5*"P_(O21'u9n!j8,']'*,#U5,7tk#" %E(PI@es4?.s,ou66Te`1<..E!-:ANCI.40Q&<ieSIh:u/dTPYJqd1U9Ae@Tc+N^\]Mj/#V,"L#<O*HWU0cWSF=>C>G4QnNZ,!b:\ %a2g:?,!Gg]$kZ="obL,oW,2sN@P2t;AsNO)2MSe%WB_/lfm8Ln4sH,ALl4A`XFEdd42guMeD_=>DB\?`il*8;#q<P`8F-rJrBV'/ %&F0ZiDBLS%"'PJN/DWOll\BW[+P-n^I6Q0@,BEK[3-m,]4<iquG43L4Ff[TEN2teS).2m']>b_;(ouL1QYQ(%*ggi-D)Ir$FTJS2 %GW'l_7^iB^N?NV''k#!\?+r+DdA>fZ"%PIuk.NpXaWFWKh[*Z?/G/_DYk5sYb=^+Oc7VR<1E-0Ylu&o<O&Yj+a7$1rmF)Kf<aj<( %qoXWjbMnS`gA41iQ\1_j9tafC6pn_TGra$ZCm=Kk+]"YM.liqr*KdA[f@)=@PSH2ijI2ON?.H"!=m(endZ<WkQ>5g27rMW0D2Z/G %n[C+L[`..4ptHSaqq^84d4@.)./F$hkAZ!]>+]a#IY"XFRmaD/@eeD^W/F;*lu[!:ljBmtAgYb_8?CcNVU/!C9&t9J*5Hek='n/! %h&9\`JI:!l5r.h=eR:-s029gE!0%nPO<u1_&ktrjQ3QOQgmpAh2lR,;,'UX6'D*.HBZ]kaGqg]0'0R(nlH(B!9(QHe<)7JqKfi/" %jbY`T3QZWi=YDXl72;Z'd%$GdBZ;L3`1@KZ0acZOTUHJ"1?RPW)cTPNSM:k[Z$=2lU"3\coiXY+FK1)NTd?8<S3^+qLpl:bf9=0[ %ZACW7:fPnSbnN^jBgiEX]bGS(f:$$1``+aQ%]"lJ.#f"VAd<f.]<J2!esonYYnJ\uFsdSd7r\XdqR!"ZU@b:X*^qEPjlE0WEA""3 %+PdT%,Ip8,OPn>,'rc*co,a3+hCNYAaXBLUY0>^O]*]c`p(3t>.4%8.8OJYJ>RjiF%a)"ZnusX2Q1K'M/M`(ZUO*F`]!\3Cf.`n& %$bCZo'=uGLj\AL1FTRRf>M.^3".M6Q-.XrYXg)eDQaMb7/E:Oc:TWU5hcD'4(VBUJ48l>Yr$GabmYKMX(Hee.DrU$IN7agjLD;gK %i/#'mXe_XgL.E0,M\e[h:r,IE$BZXI%&&d;Z"]E(JgFPHYCX_3NK(0Gcu.HV:4Ym9PW#ATg%VdlPOfBFC]PM%__Yk55YL$#<l1`[ %=VT2sojnP\SRq;+j,hEO-'Z^dg!2oZ\0>sd<0Q(bJPt;O`HTae)9lbO4le`YHKRl9!_mrA(L/>%)]IXi\0qd(c>--@m_YVTiN,pj %'1.rj@6=+QTV?C_jO?N40FZ0gS>%Sdpk+f!96\Gl@6SqeMKFUn!&$EsIq892>kbgnMH4t^PMN5;HJIF[F'E.FRM1I>=$(ChW_+>k %OD<%M-e\EJEH]-Z:M='")N]()1,eF=6LE%H$GbDcbX*YWU27QdL$VT,)Tc&4k>rLIJ;^CO<X0]+_P9jg%3=09a_nc]L@\Q=Q.:9M %Lh0F"ji1NQHgd1]MBfG'+KG`&cYFfl#"dFh\X^t_KJY@AZ:gP+AK4*BS&<lj0Flco<OA;kQ:?I@`nX")W]>00BmOkM.nOZcpF5N4 %!nD+dWOlW'F]Susn$Z!`\oFg:C3QH6;Q7PXcQ3<U]p-e59V+m5TUsHiV;)5%?"-93(qMbKItH(dDoX$=>+Bf3bmPhcQ[fsP$pVV< %FDqYPgJ_I;^Jf8\21;lWnjSgGf.A*FGfr?78l@rBrOFQ-0e:0%>Zehc31VVI:.7E054jS+T&QKT"VpVX7=A&>\W-Nh3Y!W7d,oN! %%2NqY5[20\-2b_n8;kYrPUdd_Kcm=1dEaoRgPMYZ$L]hd51mY:nqK-IW/O%><?qr18$E_\71"toAFVt6%6A"+W$S`&`!b:t_7bmI %AEsCLc88)=gFSkfd^'>n7g'mA;l"to2%('-6)[bO?q-)\b`JemQ<*$snFX\`[ilH5L(Kg4PV&S=/Sp^b1\D?9I8.cE#,i4WPa*Jd %q>o59"K3uq6`VTLX;R%_P!$!q3\b6pQ_L3r,U]WU3EL?V5ej.*K"QLPks62:^(f\l5c;I/=OTlII7M_rc#aZLF:\k\h^%c"PG`=0 %,^scuN>GlK/+N3a9(1`Z^3m!rB8ui/7o7Hm^FflrV>j-H)?4k,FE/sX1<l`-$q2s5I(.J;+1M.fN.6d+**KK%/kU=Sl.:eKDh\qJ %GcWls-2VYL:+50HmeE-]To=oRi&&=30Uot=N\W]?mYl`K22)ku6(%3d=BM(12gA,!4q=W*as-=RSWC_KBWOKDZ8`n@,G8"?AhI\P %b`]IeYC\DQ"un$h=oI1_CfMkJpYMt.8HJ9*@#G`glsfueBlI&uk&P0T&#dF,.`>ST1&f-!0kW@Q&S#`jI[0cY=:1>l<Vhai6Ydlj %,,!,8MC>?2"b\HeeqVsJAOmkO6.e"W&]\*ZKgD.<2%?m^fYZa'5^/B7Lsq&k1>79p,HSVAe'R*S_GrE!\Rt/m`_I^J^N2fM.o3SU %43t@8F\>`:iBmAZr9Er0Qa4%=:F"?h`<W)Og35`NBQgbD2MOHJR%ce(ctuTV*)I>9MC>"971ht9JnmKr?LWGWYNaT!U/?M4HNKdL %jf&sWs/\Ur;mB%)CKSK`qPf5HgTpp(NUnXPfdgO:Cj[+qdYG]>V:+C[=p:)K?nbP.15sHOD2?f]-e+q/5T:oI"\'\G*?neqG49*> %L:Jmi&`KZ4[AcP4Rn6sDdVK;NJXN#WFD-o\_F]@D_6>'m)H(ZQG)*?P7,;3"d7Pq+k9(0UZ<W*VHu>L!Bc2V^"?KFMlK#'K,S+44 %g^)Y9#`CY#``Emp.uIc#]lkTH+nO7m_c@G3-JDeg:Y+M:ndu-fmsrfc1nBI]#XM"XVfT6P0'EbPg\<$d]3%5V@dHZ8KDB;r"K*:= %MkUeEj0p6_FHKUV]G`'H@$lauDEQP4%(d7AXM@gb-P^kRmhisrZrbYKKud'aRW^2DUYT_>XXI3JCYGmsR"(Q!9pQ&C/#?N#R?s+N %r`g=Ab.(?*ZoauN[S5A[>q'i"S3[_-Q`MZ]eK:]2M@>]5C8DagSlN.3*9f@Ye-=2gd:X2@2@^rHe6-G4Uhu&BA@GC^"pQGPc]W>" %ZT?CmIh0m=Ja62%Sn8SRBJV=H5G,qA&WBY-pJH\f@H^ntV][Z#MOu#_5NM_%]I1q]_%Jk,Jp2:8]lORn!O3kGUlXh%i37a*%P`J8 %hd!Fh9i?b5GU977+0QX9l9RZ-P"J842K1cdbsjh'g9H71i]A(dS*Vh.:r<o]30llU?;LlBkpQT12<BFV&4Aghk1aWJr1Tj%Tq"7F %hA>G=Z:;nr"+b;OV+91e2&nhb=A0/D1D<T<!Z3M"ZRRpj[W#:>E(V6C[3`j@jJ?TG]kq/V[:ATWJPu25@]k-p23N7ES-0RTnpF@f %>a*n2Krd@u]a@-V2^WQ.jdC/e;JTPNS;I-6N5f%D@_m[U\F'R!h4P$P2-B;kF*a=ckSh+76rfFPctq8eXj1q29b]I!9$WX*X4A88 %cS^=rIJpSFfr8u$,Ykf\/>FB*0iDrm$Z3+1O:7;71M>,+,[-YsEs?o:!)64Bm#5"[N,"TgQ!0m931%4t^XRRs"s;=PAZEdG@iS3q %X!o&NcD1)4hWIkO:=U,hG47?J<G@I7og2YC<&W3*hKuOAO&VG7fdi?KI.9j0QcWFD;aK\m,kqmZb1h_@6$t"N%1p0!CW];tP$YUB %7GHbV-7@74DE5N:g&&_I-T420CMg_"CI];S_'UEB2qKW-b1ISE=$hP4^hG9/2l=Fl28X2bW4[-7MgX;rFKEXg`MRXXDeoAimD#e% %\$c7EpA[4VrRJ-OVR]0!CD$K/]cn+L<VP)cXQMG,.X/_PjI.DGfJG#0Zp&m&&;!M<.=Eg'I0^*^s6?E,\AcAAatjRI33>Cr!NeM] %@n/ndghIt`Ta)SdDRD&D[jfcmesWBpI[V*JP+bGS1ei?U8ZoCm=&mMFkZ2\u#M#h(=+b6&Q)g*m33eq&>eoef%5(7d=HNlW:M6W+ %<]3gn6,+c5f6KGX$uMo9^ENAr$#>lM&p$]!Z,?taJF0oNgeL4h9*91CGK(seM`0#;V6"7.pGh$#GOsE!gT/t'1gX->CW3E*FgP[$ %F_M4bM`]^FPqoHXkDuFH1*7p4QOE!1M4'K`_o:#a(IP^t/+7G*^7$7H8pHU:^/B[<hY\*mp_#6)R-sNMmQBUW/U&iF\b"YiOc:Kl %&4A_;8'D&fYn-1:p48H0htY-2l6i\\!X\sO_R*OUh4Pc,>J\`H>$Zh?`b7'<i#XIf5lmFbn]jD))c5l&'`<ISS>#ATo2"`P@pOW7 %$-9^[nV]L^cqW6(_8P<mbXO23n<TC''lM,2;erJmX:5hf\15\o/@;?M_U9FagfA]p/<o$!o65l03a>OBO'?0n6OQ]KISXGg1Llg9 %UFj!g_TQ0XaR):Sfc1m.dD*(H,Tqf.Ns50`81>M>5<BPBhaFuOLSF^s#+18<GACXdQNGDn+6]>Mq(JK?RnT@P1<P)c-\Oh18X+]< %7JUjIb(""m_(k;PLqc7No`?g9;2f&qX?IX55>IB4[1k\=peA7cNY@cS9t3QN':8Jg\3l8iQhX:b<CkpRj*_r#l&n>K6WPk[2JIu! %QXmY3LINsiV/Aq]Aal)R"=K]C-Wg^7&t_F)A2-a;QVYjV,#4l40)MH^*a/fp-[4WZa;G?r*e,WmbSp+Gr4iDqF4ihi'b0NI\W!O, %<oDlqBW;dRfm*V/MP@&$A/sZ>Q&1,ECnTWBD3^$0hEsQ?GIB>Zm(&?\+b3iBf3K#tY(>mXZZcql'l&]=`2C6$L8WWe^a+T2#=,@% %QQ@@!)p1WVKfF/jKqWFD2k:l26hIoJPU@gK?lV+M<Ok'mhJ]SE1Tne\2MRtYC^us\K#>3BZ^W0p.&4ep+>=W>-QNB(TM2YTTU1C8 %Occ"BA3lR`@J0ekO5P*88-B>kB>["SgoZ^h@,:jCJmgu(S!!8@1Oi8JO6^+3$g&sqX)PpT-qgfRV[V?KN#4AW6N3!!nuG^aLH(ZA %AgP&;g(g>oTl,(KDeG'AC>Dn]NbXc-'#q`q=$m[S\qiWEi`-YGSd+_")oSejZ'5CC//>7<:_a*_S)Pc^9c?d(BAn_+`d/9a-c(BI %gJEJ:AJ8I->X0J'QBXGI+&_a)%E7'@CPm([$p7L)J=D`.\PqiD[C<'pX=7AFA*5Em75VEgM@s_R_1(B\-\cORIaO"SK^C%"+5(sm %aH)`Aqi-C/]Ak%t#:]0M\l=%)Hj$7H/^<uiAir=^f_h6pofW&q5_@!AW>[k@O^OG"m4?6TCJQHjB3'eh%n@!Q\7R5m`XkHSNii]D %9T'YU3WW04m!3h-jAnUY%O0sVkMmJt)MhH[R/aAlP,oXlQ\,9SA0pGCke(6C`[:\PCr<*QKpjh7Tb6nqX>@g?!uD_'9CPrF^9f7O %7+<KtT2AmZE$Lo%8[cR"0MbRZ'51Ak>N/A#&gC?iIj1g,cK&3^)i\N-OA(L_V">"W/kW5gDWadeSpVr%GU2T9B;6lkF'+]sWP=$G %7q6#=b5#O+GUn`9=b4k&@N12k\VXkG*4jWkjGYpNX`Y0%nTF43C@X1je-aX"HX.X+kMsa;9jXcPlCE^kfLDBA]`Q@h@np4G8]eoh %:)K6AA*Sl$(l<Oj''!BPL)ods>N..k_EJA0Y+l27@sAcqo?Nhr-SZH9IZ0l.S5slm>%!U&'*C084E\NO6RRrdQK_O;&a\c28#K-o %Ct3l^ibTjt-*^SXX0m__VDF$RPQ4h!+Vp<[lSO`G!3R[4',Mga9L_L4/_M;LoFY<9Mi?=L8NiE3Xm]b%lWWCmb*O!b;9%8>E:/j> %b!M@a5QQM*$,@A]'U7tMT1'tdq&U#,.*EbZ6:,OfGH7^GlLl,E97>@af0DtIo9==a&g.ki.$:T0rf0kqe@*tKP,d!6kIN\'TqcD6 %+kOu(!3S0gN'_As536Mh$DGNQj/9g_2dR_?2K9fD07/gC;UuedM6WRXq=ReIlW/8(`B%MD5$1PhYK-`WA4fTGH`4"_h@=k2*O@Vp %CD]1QTdqS06C$=Fe__::G>dC6/VtQ*AkEgnD(>*J[b$^pS)R*k[SV-;$EH\kd<e`Y3qG7aOC;^2GZCWj^,2\up\pAAMr#olYJ1\V %]=>^VWSS42k#.Xk&IHXJdafg;cA7aIKGY`WAN#$U?S=A%Eb![hmmFq!'R2uD0SV?OFGr+(j4:#;PiBX?]T>tTdX+T?4H6JZ<s[Fb %)t,tefJ96FE8nK9eB@3<R_Q*dfLm_t*.sTCMo$W:imgTd"=c2MAM/S>25tEf7`'W@$@`bIF!eeHS7t%"*3Bg6i1Q@5-\qMT%,#U# %oHVC8"Mt`a&48QbR7Z+))GkdR#6Mbsf0DY<H!Ho<)+lj]*d8bS(J65f.$g6"b`#,Q$CG9g+p&6Sl?bsq!>WOB"/]%+E'C[F^n?SX %@%C$TRV9PnSlh$&@&a?.%9REkj\2f-6J>7J<f9RM;gsg:ZU&OdL6ugKV_sVqM_g)DLu:\$X-0cB%qKD,;5WhdlsE+jpY*?DYdXts %.f;B-n8HKc^[MMWku#$L,GAlE=+.b^pg:bPh1"N^N[d)p>ZtPgnb?o&Dbi%@_o8a*EI-cAPB&,ncKoX$WDpWuW$2`een.Mf([".E %D5e;IN(O^@AnT;Dq+Y49&=X,PZa"NGfKN&Fs$jkSqA'!p#fN/.h4;.I:Yb1>Eho84Rnq*=F(in&DcPGYDRi9^!9U`OE]Z`pdHNiZ %FNqMOco[l-Y`W%*[ASdZ7>84Pn)\9EJuF]8PF1%Rcor:VHUmL4C2df&>+<2jXmYe(lQXgTkY:NNl^)hl'(c"ec0srg,rq\3__r@h %e"C]'&6'I^6b/r)2uFU$qlq[L;(0]n]YtcoEK%K1&sY;uirN>H+X@pLOrjD/,CW3F;R0_eL.`sb67sgo8-q^Y,_SQFj81i*j<8d- %=C7S_0\E0J)btTh8V6WT.2Ku:-<WH.!K57h?%cKO!m^HONq%D:6.cJX3W"Gh#4/o6:Jg`m*XGU_]g0OA<.M,uM,,Q(jEfhlg_tT) %/+WJ*`S7^D:X9ZNHR9P)FR[6,Ob0g;2j@JKSN0?1PARQRL8$1:&0qc5ruV%0]\i?%];%%[B0@@Wc1P2HXb#NN"@:"L9C=f#pRUpE %I@5^Z(<Eh]NJg@?g_F0d9sLDo=P&r'<8t.qgag-LFa$Z&HaU;eL'<ZXX1]R+`nG!f\E0uH:NF!fX$2k9dB*>KlHP1nAlLFaEgbAr %CqEtK5ffDVJAZ8$U!2e4Ru7Icaln8dK99Rgnch#HT(L()4l-:'5gAi=_-hEW"N/ai?/*5HeNdE\S@dcbPf$^i_qS(6>7,:AiGC#S %A"T(b;hS;Fq_!O!QZ,LkDdUEbof3ed2u/^<d3YABkPNaT`LV#=TuU'iCnTnB@:k-:0d>cbLq!VtP/N/e"%8Fu+qu<>OY;qR'7U%< %O)SkNA0!\;q;#NST9=D/8H9S5c_f*9adhf%m`ZRcCOJ+.GtkU!E;#AuW6Hk9:*g'!.J.A2[$`ep"3j(X$2!2Hb_]r&M7q'qH@(HE %aak[?GXN\SRM>'AKftsX--ke5$.aO75VY0.Pan#f6VuXflDb`).p/cJqLjcEQ`LYY:(Fm<gaUnti6J%bC`(.epW>9P[fl_G.4_G. %a6<'mVB;7sKR*R10;>U:<l,jA[igDARH0E4eB`,(bBgG)L$RE"kgd34=A:s'@P9P'4>)&<V=6P+8X=[aD7qnm,G3tSk?*hhX^nT4 %>r_<4'/)B;>a/3Y:VA_;;K;Jt#mpF'_`Bk4V9b1@FHY'V&!)i",MZ0H6L42"^NjAgR#W\PS6&I+&jI\*j\UbjESY_.?Ft?H9a7XY %jQTBAHsPgo*B$r^naR[F"q+bnhD5haJZ<\:#&CN6/23?WoN9sARsct>A*n(j=r!P\$&)t9cIfu%Z=PSU[p="$l\o+hM1\kVFQ,^g %kOh!uZ@N\0_B]UN3P2qRF*&,Xp.[N0>/,">?udSJ,,ER[2Gb(o@H/J^A$bTqN=/=#C"Onb::7HW(_@Fa[Bgu70fDAi[O^2a4T7D5 %GW_$$S/an=$p/FE<&u67.lqH^b$!l6VX=09fG3?k^.ChC%o5.[YBUPfKn2IlM+E&H;EMV%i&bkk\#0&\knDh;HNT6>Ou%=j4a,4a %n1b-p8-O)DZ,R_UI*bP5\g`un9ZQsJ<@an,.FL_K2N!dI"(a]51k2m-m,+<6Z(^g;QiV3$Cu/i#Y9a/,L2nAV^??RabPlFm/+iLt %h6C2='pn9JBSX*VF'[Z$-)[*Qlk(%PP(efeE,I\C9=h?#SD>UMNFb$$e;s'^SV8\;OV7DM%4B`b#5tZ=Dcq-C45)6a<CEB%C(q&u %'rlVWUV2i4(AbHijRpC'ESO@g*1*pa>PTEIYnQkeb8qkt%S9HYoc4*\`7Z`J4A'.F"<Xi;fH,$]P?:2mq>&S>/og,6n[l^].>6V< %Mp>V%qd.)P$A>:J1*VpR]BVG)=-C`%]&k9_9iICSLTWDDl3m'1RD+!glDo]m*dB0$S_#DE38un.6H6M!OAf(IRHanO4-SqletR%^ %65:a(&J_<MA0/s/;.FRUS?%iTVRg#Gm4hK3F=AMgl]>11jQ)DmT##(WS=,.7+d[geW"r"n<70M^R\N'pG&P#g+b2-1]d"GbF]5DI %-TZst)-DSaFl;HI#u20:h29YQ'X9<lg2S"DcI/Yq?!(O%6SH>!oV$E%f4hP3(O^m]Z,"$YDLlD#rn`noVs4:`'F6)M#Z"A2]%eVq %bb#mg@<;@#kI>"c_K$0(ABq>f<]W!M>GHAW?]<nZRh`s=W-IPBHui'"N1#8;>B&3ql59,>9Lk0b@[F<8\O#X-k%nn-AZ/lsf$R<l %K:R$k]8Sj:3g4usNEkg[p\N"m@Z3=Pb$\J3j2mOseK:,/N[nNR>dB9@a-7fDq;D/n8"u\]Pmc2d-O1MqQU)E.U6l-@gsI%d"'[^% %OTQ9:gj8-7i+^dCC=aSCCIrh!Shn[(c7EC=/Pp9m;nE144U>&G@'tlkIgT;[5h4;WMYJp6CYOM@f'F/-6g&ENLeDdn",6]d!Xq]B %6at7s,;hY0*RB;\JhrEp4u(kK3LqEF$2NgBJO4<ng/3Wb29"_8X$,pHBMsJf8/eNSqEA'f!1/5S$kX#NA#1m$3`ZY(P<qeP=6g9P %<5=WrU602MV]:b]@S0?O83Bj5lRfOL!OQB8;g'VMJ$DYK`C>F8,RdNi%C*1S&3La].lIe_-Girn%XK$kLL92&]6"g0-T^;MJ`eh\ %\F(ZG\?RD6FZ:IbAXjG*"-OT9)AKXtQ-?b>GU[9\`arG@o-9Li<jmY!*DWBUnfF7i0Z6`?dE6EdObf>o]KkJM83I;o0UuJsnS#ji %gZ`a8LI2:,OSYalYM55qrDn"gi;uoQe?F0op!Hk)&dZ+P$\!^K.7\^8MY%2LbQ,c8Fk-+a:o:mu%VeAWDM\f)1Y;Q-@`QTRiMJ,G %S@l"o0r)t'nG[Kn3WJF5]A'CNiUbmOSG=*.e>I1S*%]E=q+,@tTaRRJS5*\e.:mZ7gcGSOG6kRY.:`KQ]&]$S,Xe/[:JHJ_nNG\i %!M<#0nVe6Er#/1oH[%A2+O)<PMe9HW4@LSYZ]/.b2Z=F:eYTu&<=5ff6:]tF+WnSH-^`g;=#1g\-(R,fGZ3(/mcn'29lW3lQ_TEK %E66!_rm3<U;_am/iiDLmLf?C1_tA$ED@s"64!N-@dN4SY*HVM<Sk,QoSkjC"-Y]bXY"bND8Wk'4RY/lk+?Za59,tfi!"JWjf4=Gq %qoEV%6;6b[Ha])DTbfFSKd$sZa&Pq'S/Q:ebZU1lb_lnPR4^:q,)i-iFQP"4ZAA(A;=4d3kH%5h(^.`pVCYrqs(cp:9lB)lRlSW. %[[#&N(#et2PST0U;D>*mVP@fBg!;5/f8)Ys8%Lc4hp*Z%cahFnEG>nVN%t1]ZHa`7./hF##r,n@m*1o_ho:"Q^te_0CiofaLmlj" %\5X+T"On^]Kk.j#@V\FnZ=_"s?lGG\[dr2K91'Ftl&[='69^NH7Bo;%LE(+e))OhA:rL4t[uf't$R6atLP8'oN,ldDd4J-28pf7? %C:iWjpO4WJVB:G>n=U<ea"*d&=a-iI_hmP[7u,[6H'(Y+d`dXhP+GL%Xhq@)ptVm-^Oc76Fs7pPCO*0VL3+n*L?=5!Y][=M*c&gM %/A/NP*Qr"g=]R<FU<%in\nhdGm8X@l5N(%aK;8b&'VV)=]P<g2I+uf@%)iiUn<oP_5'uMERjY^qUIcW?9KF9RIUbW1=^?_Ldq5#! %(W<F:mg*neXQoFV_s+F7l'Z/pPQM@g_X,VBE:WJYj:>oSqGV?7S:;3>KY7rn]ruO<LcuJ'r]*9bp<^3!bY\b=T,`eY"c(e;LKk/+ %g'/msK*B`?P\sm#C(4c=$pYPPO4ofU2PR[5jZ_>_9rWO.ge*]A@^cFj4fl1+(0h(l9!N(M9[j:/Xah(0J<d?o'7'aRG(_.u_6VOM %&4`gI?O,#if]6BKC%%A0^T;--$L`(0"E^E[ZPqDV"')*0<RY-hf%\*O"13LFT[jIAg-E8r31C02"=Dc_-$>t5.d>#h1:/&.!u7f. %JhXDV([?aFV`C^r4&+>D"ATHF-0,&gs2,D>4fm`d)EpMu@>2KTQp?m&4H0h/bnfHJJis91#hE#[]5I\8XFNGp^fab?,;:9a7KZRG %"6jN.mEL6S0u+^3kS^b\q9\0nEqVMP[mJ.o5*p7_ZBbV$-J'R9C.YPi"fYZ<.RU)g.[;ImM*deT9i6)5T$/ds`g6k14-QN2P^rGm %!P\6KS1lM"kt*&Io[gUkCs_D991a'=\Z;k`F#A_Y9%84<L+6!/QKscke@$7nFc6g[j"FHiR&6I"]l!3D1_MZ%_a#*X`:nudM%lV= %DX3Y65NC>07_o'(rmUhD]DqbCHFSCtkF]<[/_0Y$F7]ZXoEKC/#&*R^D=b1MhNl%5;Rd.tk^3m&&pU41\=TbY_T0+r$1jpa^-Oor %nN_"Tcl9B>48@Zu_V7t5>7,kp:lk+^2nsWar9F+Wn^IHsG<c,<@?'UimPj%`2`6*Vea981GL)>c1Mr`PDQeNdq)_uKr1Dc%K)T*n %^rq,qc"Cd^[d7@MTXXq7rqufS_nTG6=22KG_uD0ghUCZfnltA%#Pa;O'N`&4^SF>FT>'?d*q@CRc1gkXQ_\*nV@#2+XAg.d<=?LM %-r+YfnF0=P_pQls?Z(9r.r?do!Zk?>POreJLb`[RGTYdjlN`$2GE#j*5Ue(b4D5*aS`./uHV(E_fQ5QJEk#k>lY`X_*hN?LQ=/rA %.m"12C[q@"TQ[`VDYk$[+/-mIZn:-eTCr+b!VOn<VW.?paR?0uhj8^`L[FB3g7i=#Hji+P0'TOZZ0:`V3'b+1(40!M4oKM/p'lH$ %6"f,(f/@^]<f8!W^YZfG<='JnXaUDZdamnZe'ajW\?<AWi7UI.?cXfnU\2`9n+bl60`=o'Jo>Gg]!`F4_`l[9;P0BrL8q%5;4j?K %HL0U93\9dW%uZBO"-Y]R[5,&[^97Ctj838doeA9j:e`tD1b:J9%<cAtW#tRXFh##cMn\eT<A9kA0j`B4_B3r&(%u1:YNk8]WQL>E %;8YO[1pQJP>G,e6YV)SIFkr,RV\r3V#JKOD\5r%^Wp9jiP-;?I/e$06I<J[uGJuOJC"rRF$Z#@)XS:_c@46TQUT;"9am/;KepYel %Pn!.P^Vjp&gWC+?ZENnq$J''NTChcR=W&M04p!<k"YI2?]jDYj>oC";oum>\!:im'bH]%\4ie`;^?TK>aWOj8at"%jO]E.0DdbL4 %/#t+)EQNfk<bo"*m35>-^Y]gsL5C+Q]%,6"\@,V8:Mg3ceDlhf)4ibsr1:p)X^F(EV;=RLLS'-.GbmbX;\eHBX9Mu2*1kq$Z2f^W %C<SG?;;m,#jUe<bK=mED:KBs_\?mj2VImFr6;ueuVLnt7WdrnsIth[QaW$nENcm)3"3ZBI5^rO)9.X7tna_XjY$'<FEp)CtfjH(+ %U`.5_LQ7E*):jBM))@<$GRirF>`u"*91'%V`<]ZZqV"t(+X91Jmg&Y]+#mRaj#%,;jcs']m6]Hi/#a$tgpaSTTV`3c1JlF.[Nd>s %)TSej`ge5U6CQ?V,qWHkYQj:sN`6,2_37M51aI<W'hoK?H\Y+^g]K(AWN^*ISZk62ij1:Z4A$.C(8)2B.V&NenI7ARNeVp#ArdtU %>>AHJdoM8ppXo"R^`Ck]*&;B4lt3J-:.JfR-<[pfUhe/mgKdlL6do9!3Dm4An^q(@duJHA.gYIiH_A,@%<Q5oZ_d:?VE_VZ8S?@C %Cpgi7]"T?Y_LjGPU-cBH!gdO9D2u!&+3Y;km[0TC6f?!3*OZ]o&CCtT<`48(#uO<i1.1s+`QVn;eI?tI_&GL+i(?*iRK;:Y$\C/9 %,MNN[J<-M.66C=rC^o/KFb=VUHK]p?+;`GW4H$^dCAA,NlH%(nkUimXOZ0pa4-5^2qUQhM7%:.X14lVW];kLA#<uJa8WVX5Y&`T( %T\2JK03.&#ZG&+g)0.mEU'BV/TJg28OOE[p=m-r3injRPZh-*s_X\!qZfKRqC<r`(:i0j?`X\%Xb2<S,[.kDi(O?He/ACN;[UK.G %[o@u%_'0&o%F\C<4FMX$qN;-p1EZ97F>*'j*t]B^1<;\-QH:L3`otdk>q^tga/*F)&nM7A6Ogpfr.,,f;DAPj;C+ODj?)8m8erCa %SZ^3H=>H[\XJ:N)p;d.&mI6SuP2;0`l%S#*Q%+m4&at?cQRoRA_]O#G@RFu9f7l\-Phrls#g!Os,1&g^hb`jt*e_JUT)2QbRrH`& %0EP#q.]/qN:>D(\b(buW%bDl3PD,kD794fnFoEH?@/7-l`Ro'mVBC:lT#$aL7#A,iL74O*Lm03=0"[I=WeG`:ZYH0#g#9;=Z;flq %hC?s$;C!C.jZ>l3=A;]k=Q'Ui@'EjG,J$d]3%u*rLp\6U"CO<1rurB`.m.,h(\8P:kAW6j;N_T[m*5ZHE5XdejFBjo<bS(`7VbI\ %L?;RM+jHr36^enbb7B!X#$Tk\o9-OpHP]PFR-]'T['btjQ#CLAniO:@o*=pC9Ka!_A8YqW@`T_96IA-p^rq_US=Z-hqusPRLP5;8 %_0DiIl%4!$0XmI`\(I27rl&r#)"BC=[p@srI`2&`qf,l9:b`E;-sX-RPN<kSL#lXOS0(XL<n0mh54Agj4&Nh^LX]53N=&G)&b^gh %XfI[,WGsr7Z\=mJlY?Xl<n_?>2f]PX8+iN&!PRl>.-Rk.(Z'th'@[5&A$+euhU\nTFf3_HPCIZ'6Yf4g6g^nCY.okJ%/h&G!?js] %V4:@n3MA3I6GbJ!-d#5Y,,-^0X)oK%Zs:H`8OJmtWXD]#n<mO@g<e5(<*F-@2YeV?2!Mab9/9hA&J^a*=#?Jr7!M@VJ5?]">BR53 %K\M$<b+=tDI..D8IVkSD!k,$_#BhpR@C2b!Kbbq.b;Pqn@tgk%T&eFJ][c_#X2^Of*G:<.g/a6T0)W\saD;i$>kCn>Ce`/mCZpH` %*I9e87#*sXc3Vgk\$5)US`VpVUX/Ta;6'4^Fi$eZ0iCu^UanSsV>!F?.4RJMNZ.#JkVFO7neaImF/nA(@u6SM64_G8?Va:):f*!S %:kcj$1s-B!c5*@Y:<n"X7*bJ:]cM,eB(f7lcOst/:QV(R2/I(K9Kj2+PfHX^)YN#WCm"/tM]Hq"f7eXO,PD-VMh][8?:maW6:eE# %3uY>J1juuB`XjH`r",5Tm7H)-56<UnPo1'))\U#M)32nnU3+<:^0GKSACICP10%;nHH`4[;n+F/\KUV[?EA]1QKYTg=EF#$9GVHW %RT!CsTN"Qf7P%RL-Z2r3#tu=@K@\:.92^#I-*>_tceI4A>*!IP@8Ck!iO]D(h\7>.Uo<'/"UBi\6%X3K\.Jj0UYOsQd(<_.g[3UR %`m:GO0(!Q.>'544:4:PsP/oq0EcV/<\]HLn[uDoRoog[QMML8]FNm0oUn;[pjKB034+/Vbs7pZmhBf%Dd@HtRI7OT8ee2A-=>.=, %]rsOoE1V-c\J0oo,K)`g3T6&ljaXn,^LoLUn^B?O[Uq3c5-9LWW*OVlnuZE6p<s+Yb-e?X]f;HV0)fSB!aU!:cZ\OnLL#4%(8`:* %h1:=/Df?_O$S<`/IY0fNKQZ2$)>:nP?8E&bYg-\S>HXB4SF8bReV,9KODFa:\#`rDr686IbN4]ri,(/$9f`J752oeo#$c%*]Xs`E %^?0gMPC9tun8mK$<+f8?['k9E)[0h<p$B^??&>ncn\l1;m&_7>aukfX-<lXaq0Gb=YF\uT44Uo#0H*i?ph5'QlL$LpjC#TIYdCK" %WAS`CLg+ZW$D<G81_]Uko8e$HlaEa6EDLFX+6^d;TpO>'$6SWun_LPkVrfgWT-j;C@\#'SY9mGtegT*eWNKP$!iXs*M>(XXg-O6/ %BsWZmaeCUrS=V(c0M1G!r%ueEi%[-V*+)K&[]]XNf'NkCW_[+^O68LX%hms=3&d8nVPEbUM'H<<!7&J]"ZNte$LXP^nURbC3-^P+ %<XBqQTb+H0@?Lo$QG?E;nXmPqFmhG4\=_+HO7n.8M,P33H>*DXAn>K_UAZPHWL6\,??@Y;o(Ss,9FLgBpSOKofTok<XL=g^S)#KG %B*nMd^n4Z^;6Nt('/H,rPtY5Jr'?kWBuSn$D[E0sIU?ZHJr"^cB7c)sG,GHuYAoaDj>ok0]eYui#!:UJ_sIEg[\I^j(j:d&3)5Y. %7Ber^hl0+ELF4pgKM_^87j(ndr>B)(C$#?FodS7sj;@";+=s-1BeO(2)>pf6d3A6]4[P'80DqtC1%=e)GaLG'H,0<icRYkCo0Ad- %m%5?N&\eh0Z%Z-JkMAAj<25,:-0R9toq#@0L"[E"Gb)VXL]-';pJUZH?2^sUiPls&eT'8X4h/eF%,3%,O^171$HUpkXf"+'L":<& %Cs[K+C0FF2PDdLsB\WtIp!S"ucF79;R<#lCZo3Xk*9P8=E%rk8pdl;\TdXbLQA/MBfC_#6.24)N:KY_R[`HD7m]>YC57AX7V@iRR %#<T@j\N,oBRrCFtbB=AA2ic&EA;okt#Xb!KTQfF&YBO@*SiQdO0Bdd6"Pnbb(Y'aT1Va\'cU0NYrCp.?;paH@+g&>p&D%nrOBsYj %Z$-"VL?9,n[,r"GI'C@[VX52;pG\E.0V-OUp$Yr.Yfc*.pp<pNjKEneRh1EL/0*t%97*$ie4cd>o[O8)2Vk7`pbZD$%"#>>n&78" %F_X:;m<#C-0J,P8r5S@h)+Q('kqop!nA!2-V\s%0^VN*3N[F_.B!$3(?@8@pVU<Gf:,*4q?=8)2EjV<0<g<n4hptH`WS6Z?h8V8; %9>dVam:bNt2p'u\5gRmU<Cg73K7OMj-aYVCF03-T+'6XaNMS[NA,V",?S@sSqUHV?S&cTrngLYR=oKo9T=+j9(M6EXkhFZFoH&\u %U)CcpPXA:A.jp#C/>!1+h2gqOcXpV[XLa@#e.(<f,AVZ]kgoO_S9S0-DsF/p(sH?V)Y5]d[o%Kij7P7+ZQttce[I]J&'c,I.k:cN %Ykk_/1a1i=3T@IiirfsC2(dEMYPEORpr-eMcl`7_a7`GKIPjVkJ[p!CmM*_]n\%lZmphUICW+%'Rkb2N/:HSEl\[H/ncfuW>T@.B %Mt1c"F4_RT?;-q?@@IDpXt,aBqBe=6qGu4(B\Ukj^`9-@K$"d:0a1s4f:.!Hc-jZ/2Q'^p/`]!W1[`f^?khPN3)F@+^CCh-bQe\C %7(r=):6(FX:%C>ba,0c>HI.Uc9cpt=SU9grTT?/RrLouQIB@.o=/"FkpS"?K7p=2(LZ?'i2P2\,Y9S&^KWEY)cM(;se!)qO&b$Mf %c[)r(phD+bO6<Z;$?Y?r+F81V8#29seE<2=d'cTj0u;hb3@;e.'8.n!R)C4E,=1PDSRW9SCO];f,0(t_gW+5&T-CR)qAbXj!D=e, %!kARr$tLU@0[T8_].lY2>DNk"k5kG,q%aG^5N3aNhMArUhnlY3g1ZE)=s@/XJa6(,.RV2cU?e@r(!f9K<kPnCZK'\ZcAT-=ad6>Z %H1-F5e<XIY)=Ek'hn#6p.4<0?ET#!=2t;^1CMN-5D^p?1QL9f1H>?0eWGqZ>.V^'2?B^BmOUY,3grA"IO0`PlEV"kMBBqC>qaiut %rjFAt"Z*<YQ_cUB`:$_W;Xp9*&Uf]+Mnl/b&I@_IFXWpU:u10ac%b,J@<E+PQ`afqVjT8gm\MKg9muBRZJQN1GbHo7lB&f4.q^u_ %1Qh4sc1IF%fJitgkrI&FDH;hIrVbrJ'Di?JJ31`mBd#&O#X8:e%_I+OI'[d>'qVU%!eDNHFGg9i>$HSP*AU6%D2CXM9I(*2:>OOH %B\][1p+uFs@OV?Za&3%.SJ#mFI;/!4HL%b%lC4r@U#oukmb32=G96SY@6QVX?bQjmB99ll9tgINQ#Eji(u[@JChZB3:,An;RSgcI %N8g6r1\t_2c#RE\6VdeJ:Ps&(e3>;/C2W<<#=7ZNf@(UhL<U.]2tCCA+e<kGjN]?=Am+d6m0?7\op5*A>=`SWPJ`<-Xq"(/)a1>c %QW1TYE!*1s54mrA?K35K%sF5(C#XZAQ>3^c\L(G=Lms32/r7cY[M4O==6O<>NfSNk:+`1'gfm7q3OXEU3CRT.G3`BW:a^@!7C]FC %&FTprlI'X!X'2?WoW9"eH`V\2Y&k_5GR(CA"E]B][,)6uLB_sZ@T2alIa<Q"8Bi8@!1fs)6peoX2'*VQV^H8PZuC>DNbg(baluQE %?b<`Eq]h1a.#?O^<"IsW]qHTj)^"sNH0agT'+9#&BVH*Po5Y^(e,J[mOlt34=*M(l:*B-7jn01;+MPpii:UD["pM2k0g_Ua"u._. %B+WP_FR]*#Rq&))oWktK(B9SKJ-9[#.,?aJ:_j/hVf2A&g[[;mSUJ0b3(BV4a!GLeIolr>cO'PY3LYNaKG'F$J7'Snfe(C/G_Cp^ %!MAFq.VDGN*^-[B=WkukF-<GjVK>J^P!TlI.oV3e;IR/N"dMiLK`mo"$[q@5Sf?ohO%X@+0=1G!h?udY7teK4^.aLCV,,>&Q*d.Z %1j6D3UeQQsj3u28(NK%sche<uZNph.o-,M.0euCjq-5YF4'qU?1Kf@=3>9<LUQb)5&+ae4Z1EX?k5-\9*[J^W1g/dTMib4OpY39f %OKp6bq7\J)[KqboG/`7/fRY:C-`2)0Orp_h;A<U5[iC*E%-t>aDFlFGa"=?'H$0+A;V+gdehP1>]:S]4QBc(4Z6cVupZPoKTgV>p %<p3ZOXcTZ[6Io^JKmr&dYX1FTl5U`9JJQgtdEs_86;r])V-'%3@R5gP8@/Z-'q#huj8(P)h6\#lm^bH2cp?.m4+$KA>*h%PU<(Tj %qtdQ5en9Rd6ZPXe2r=u,(?l]t0YTg.NPYZef9`b/?(9Q:rTCN(VDZcnRVCRdlfqp3mH^<<@3O.k.4g.,#RROp/OZ>FArO[G;Z3^2 %jaAmVM"4)+#uMbc-r1&3-_J6A;g@jpp_bojs%Em@o6ACZq'/kD)tL3#gt2bg/1@,,*Hd',E!flZ]2e]E<9ZK:=Qk%E'l%-$`Oq?+ %4sFoUOcL.p=\HgRkKqsuf\FrZmblYacn(o_f,qDgaMS@%B"PI=D:E1/be"2((Si-Bir^'f].'G9G7Auba)bTXGr1DZ:71uBIdaW@ %qIu+?Gtuf3D.dH/9]=6DY[gM;c50FCo4"?R_2Gsn(2bNh&ZK<3WJ)gM-dj?H2i,FEC<d2r=td'0lM]Akj1'`D^Z%;+mLM]Cm3UcW %C[-Q?@Anf'[f$eVXY&bN-CoP]i9?[5A#-WMA%3M*UprOTO2@k53F:ZDN#XOYWCmgb&>Hem).\LC6r#FobKft3DV:7uUbR#UaUNO^ %6S\rVLV*=@(oDI9k,49]5)q@8?+;tp]cVo3pNS'+\+?lu:A!\#SR&V[\8a5OOeEG@()].fY^Pk_%"@7c`8#;M6;;lg_L[fJCZG,j %_\#h0U[X)rN:8Y(cXSfCP:(SGjGj.5Vmp.ekh9NGbF#kmlT(6)ehPdYSjP!_UX<__*5>[C^GA'_1p>#MrS96o=5(:uT,&s:qT@N4 %1l+W^B_5-W1\RC/h0D&0F`O3N\Tpe2:"on?h/(/Z1%l@FHoW4I,!^;<d\4C]\BS'bfkNGTnh^k`VTI:dEeI\.E)^Y#q.LWc:TO!` %(uD6ap508\]O:Dck@?65m0QR5^)b6Uce5Ks%X"8f\4?32fX/8M45V<G?c;Ugb?lMq*OBkQ1*lBt2V]3.Y+1+IG8K71,7!IIA\K8, %41E^$r[<7dnN=t^(W$(ppRh-`p*fL%Zk+)I3h\5o1aDdKZDI7fT&G=+*[LP8[\I6"V;ANs1Q>6jHp`t'+dK4m1"5Q)h7jcHqhW)d %[Abl61U%>24C/P.3_Q5N>(,/3GBD?',1cao>IM8bPo8QT]]^mjER":G=LJgs*>>F`2@`/#dOVD47/"T0lrY1TDaL-+1LYJjl^X)6 %(0YK!S1.O4kpE+C[6IlRMfcBtX.m)I8D&bN2%k(A<;ZI_=Nus3&W>I9ho"rgNp8HOY>1he<jX#*"/;?7'RB<sZ?r=LcL,tbd*0n4 %F*-X`i&A^V]u1.>`t/_ZAY)IhZd#4';CFm(2D"\=MPd(j#$G8&$:9QO84!#_LrX3`:Qq]U1`<Q2,POE2#Ob@JUFH/XL1_e]n-^Nk %n-bB,itl/g<cl-pjkaM?To/];AT9KqbpL6(8_DA<GoAnAFUQnoQj>ts#nrAubfGdZ5.WeHCojrPFu!fcJf%WsTccgjfCqb\%lDd" %c"si$9SSs*gWeNnW=Mf'Hs8n-=+$B:jumD1TO)fF[^D+LhC+=i,k['<J!'rijs(`M1Lt37=_He'[EQ*H/W97o-b8r]Ji[9tI;s#K %eCrCbP+m_oOS$du12f,3DU_>;8NaaYmr+;TdJrJAf1f9VJp`_dZWN].hQ$e#@gZJ>Ibu?XN2kbu-XPu\B*rB<XtR(sQ?CO622u</ %gdA9B0$f>9T_<iOcoI?5(]nC6f\4sH>@c1;8N8*gCmGk&af(U["F'dET8f)7LF@eA38H3?GE+'<^(l[ON[T/[kBVpXH&,NeQ^4Bm %JanFh"7*\Om0gZn#O42-HcG,N4Mu^^9q%RKe>##p@h.Mn-4KaQ3VD;CR9aU'kH4@!rB(R&eAR4iY3;ml\A!)6]JCZ@boXXN2e3he %kNUfg`l$f(SO0[3ke!G"'<e]GWEjEMEP#dtm;>(2[5GE@'*r++DAW07:r%W!1#j7JIl`U&[m,(Z=PI_Cmcq$ch&aMBMuD?M7'YGR %ZL=fGPW/U52LSh3amlT^"ApSu,VS[@r%85$YQ%_YA"_Dahj7"5:c<rEZlto?ZYsJ7cY2qsRqOYTRa2"lChDBd.[ukbOR/C?"79oF %N#7[nnr"?iG279bpb?Gh0D6Nu"P@H]D"(qVp@Zk1p)gMhR[8:MJ`_,'7I?-)nZAqB$1[?tB<^h&>F`ObL7!55`bB>IkFLKPncO?2 %DMGd[P9TX)&?3p9o`bl94<RYo+1Lq\rn2iqXq1dVB<rY_%Q7q]5WVkK`<n[?2ah;OZ8EtEm7V6.bc5sNFd$j;X_etP'7?2Ge'dFr %c+KM5AN$a-LK0dIM)(>I]?:5S4HTO54W[l\.q0h\,Jn_e>;uDn5:Pt@<Y#-hk5B*54u]iYDW5.b,kE#*\NA$NDaXWNg.s:tq"]t_ %[#J]?Vp.?3\lnb_*Fk[91O,;Dmml^1g4Hn$l.t)R25_X(0p2?%T0;Yo6!$.Vplk<orENCoFf1fbg=5c*&WE/a#7NjldW?85ZS6i7 %>-r=O;%g`FaD5PNQF])MckkTn*VpDp4t_\;F.5,'BlA*d7.`/?T,E.kqX3kD7SSooZS,+X^=tFn:WUe4CDLa4ZaaoK<)K]t$%R8^ %2)ho6NOFIfI&e!to!=CXE#(F>5^HH_`_d]\H(4p(7l&?6eQ+MLC$b?qa,JOWjYP\e@%$*$+I"40ocha(i-o&)KWhXT^<J+R<ZWG( %g[u1'.Itc@gmgcYF1O/_eEO(Uo9;,0c'HS6#oiDq::ghoV";6;[]MWgA@$"+_%d6Dm&9Sb1H&16aap-XXeB3@Y8SChe0KLl?*sfb %39=KP-iY`_+891KmM=F?F>eE;oqP3eo8Q'R(Pr$'0]dS<d9o:_dc0,R]?$4-F3couFDGl=8d\S4lI55s"$DQlf:T=K*<`3ol0Mh> %=h[6=TFHaUd>]5h!RWh-U"cJu;tjR6;Ek=V4gR;B+SlN!"R1G\f?gc5GMcRcg*6H-6_C8ZrY;o>FYKq\QXs\3H(=Uf7i$7VDiEei %K-tufH#oPP"$mb_Xh3J83c#bp=.Cl>ZfK#,oBAC6;V<6"n#?]`>^nP]2SuN"3gjN&5U50kD"BjhLW)<80Rl[h%-$VBfY+Aa80_3O %]$!*5rp-.&EXR0(mUBDcW.&XH+'KqY\S#sd.MT-nnXI,t%cmI?8)@9:VLErISEM6?Mk#&q=AIddr\c=-5FgD$bC#f![9pC%=;-Rq %35<6&\*nh2,+:BspK:H(_W7"<I?/F#U\@-ALU$$r$Y,iGJ\+WR2ANskU9h-dl`u_S40PlD(&5"*f2e*p1n3L9rbuu1G;<ip;POYi %K\SE%L["iE3o3qgN\\a/\qOr-$/L0kODpu+_H-'sNa`@MpnJ^CXg3UKV\?5Pjb58RMhPYB+72U'LI?-i@`tJ)@`EWJ6<2RLf1/mX %e29Ko3o&i%C:CAg/ideVSNZ]>UK;q[YQ!#a.MDY`j]n;G1]r"6bO=&89'u6nVO#,0X@B@tq&X>'aO]?XF:fN23]Qb[Jn;gc)cX'^ %,R'*%2O8s6<I6fq;-YC%l:#]Pn1C+"#O"G_JhLCHR1Z^_;c>2QReYBh1H3,TWF@(OISW&V=n)BrHI+Xt^Z*PG&>j%0Y`SLm>u+l[ %QC8!q<*V\e/(*8[+G4!%*dTSGI_U8K[LSALj&b8]gfm1JLseL2@'a(m$eXf@KrWX0[mCq\ETRe\KsLOPg'0rHh"B\MMEF7Aah7a\ %H:>KBf[*:@pst3!['X.-g*#lk-).G$H#G+fkHm/VNW2NaCAlQHloWfuLZ5>l<ZRc5cm1"D1%Kk7K\$ZDYA:eS"ANb2dJs]h\@^?C %Co(4c3_;#^LfXl==,#e5&Z]hV53)2P=5RhpS4o?S[SCmL>.r(p%Vg%2H$YIVDk<E$F8&\ubT^a6>,JL3C6d%N*LbTDnG&[5!oeem %*t>DP'M=3A+[reW.K9"@2.X]5`?-*JjDaoHi]Y^1ENqsN@'Jfa`1SkW*h?:CTB_rKYQuO:6akMD8\7DZ^\V8okZHn^Q/&N(lW^t9 %V8^mHja49X.E#(_n1J8U,5!hY;B;JQ?Mi/!?"uRHeI_L(=4</GXWP1h&;te-IQVc?cYV\ql&%B8Na1i'fi;&!Gt/HrdFH99s6Q_6 %ojlAY`S'E6q]rqG$N4e/-e$OtMpSCJ$T$1$%aXU;$IE]!UX-c/q/J/b5+=4Q`7;sud7,nYkH2.Sgsia&1q@R+k<6bp>.7UUCKH_? %@:R$jOKVX&(`j+Eo>I+Gk;7CTVtXjs*A+Cg)>=#2f_M$T<i6ald5SI2UUehfI@7oIZTLdrSRerb?48+=jR[gAW,XNS_1%a^YD0O. %/2nZ>*E9U21MUu-l0?KlVka(BJ[!Vt3TJ.irI!m[qY]-eQS,rEo'J-`H&[;rl_iK^`dOiD[&+j\h!HF3r$%hInbocA**g'994i6a %WS`Q1mjo>]3RMJt:s$,-F1b&LpVUD%l0hndh?\jA@_cCdR^5D1hWCa8FBon@E+!5WjM8omho!>0blcF)DnT_HKVP1[V<EhnI?D<@ %Mk>E$p[B3%QiZ"k6_D@aTBF/A]Ql.=p2O>M"=J_,AmjrAgq*doAe@%]cu2D>4h\5P=JN6F7%"ae=/KlgntMVV\rQF*1f!Zf]f,H6 %a8P#=_fkT]juSN"j#N,sj([+4eu(>GCSF=4Ut/L<*>I0\1:BD;feMg/O+Ce<=@iitM7Q<'ePqeGl'?(@@Pnpm-&U4Yk^+"-dn6OZ %\?Gn_*BZ7bf0.bJPdB18L+1s5h?L--[e>>X[S^r&]$1^jgge:gOE;eXRP0nIhnV0;4H7/*+AEGuF+iI=&E.OkIGYcgA!hWo7PP$J %1pp])dF?NLU8aj"4IOqNbP#K@*fT*B`Vd]Jrj7KYFZ(njVko9UO>a'8@b1nn*,7.ghcEM7M=dWa)^jB"(E_[+T1jL9M/PGs(Y?8+ %D5t,&<G5=g)*(2Ck[Yre(tW3[kGdu.I9^V:Ud)2.le\H;e(T.Q0qCB$V'-^rQuMoAUcMUQ-H!t.PjddJV:Wue@IG'lVUo+SD/&$R %2bN%37))@`-S_H,;-(cb-nAj'kH,A]F3k_`F]9`[QK7q#l.f1K"@f(H8E;.<h95@ld(aB$ql#I=1?`Hd(*,q%ILd:qf(CF,c<%Km %G-ZB)h1Ne;jOoI$HP21a(emBmg*`qKdAKh:Seh9OMWm&JN*klh1:D-?P'P!;\+if7c(aLXT"U=\o+6Q?S<Ts4ots?df>$aLW;a6k %l0@H8f'"P>GDt;D6[Hddh`2DG0jsZ3dU8)%q9d&X3_)I$$:@pc=ee'j&o4!]oo5UCNT?_`QB!%*)U[:5o)SGC1(Re,;d@9UFn+7R %G:$%"TA1;)R%7l,Ek0G4#N_+;s0F4l4nSbkaBuW2P:'o3PIsZHEGE7k"TE(Nq:M`\=5H#I*hc*UoQ'#kAeKnE7l?Jq:XU69m,@cB %-7KDMD`(+#p-29\(P2)+N0t7`?d4rUiS:j$BT*pp<cFk5%T5=bcR)#:$5sq/Nlf[hJrVH2-jg^Qf"SW6p:YsJY5"^30kl>1*3S,, %1BQj:0+h#&IGNKUMLcSOe.t7c8.Otj7QW^=0d>R'L_8sUB2=+m2JVh/OCmN(bpn'^//43m`H#;Np*5a!9$>j9?+ucVYC%k+Zf9Zb %YP\(7))'\T'//'!c-?-io(rN%7)./^pni@5qji=Z[#O,0G)fTC9JbaCO/^]6qjjlD'=sW/A.FWuo\)$KG3*H3%8lf/'t#8RlJnsl %R<dVaS7ZQ+`o@1DBE,V$\j\EYVRF_2(&5..STGHlM56'nCLdJ<GXUgn@-59,"S]EKU]4ALeStiDb[]MSL>d3%46@kRG=+.37';Zr %:g9M\5>4gan?#5nLh@g-c-+W%B&,QiA"J]:Gb!XZa2N:!48V@3hN4$&IbkE7bO%@ZgodN;Xb0@acWUK4],]fQQmEnkMqkD2CRo&% %/95Bcr4KgY&#c?3N\$[R;Gh1q_rbd2pnP0Xin;A+0lM('(-(]C%[;bj3]b1WTCD:Z+`HIFeNWeNkk5B6:WUf?CDLj7F'3(X9T0sJ %7C=EWe^qa63[PW]Z]AmA(-Aj)H<)`>;4Ii9QiZZ2)9pEKG2(ZGWQ,)\'36b_5/TO@QVmU<U1ootZWMR)qgJE!r9C!4cq.f`3a&]8 %gAL7!g4EJQN]AZ-&)*WrIrLj$X>ue4?Ds/n@Z(!DJMm[[Mn?^F*?sn0F="`DHT9]247V:rMT\F8&PFZ'pk#J5k8oY\o@BQYRE2j8 %;3cifksXjc;/#=`neYT'0"`*Z>:OT3r0YmFa6KcHXRiTj)OWh(PtojofU;Wc2n!M6e&5Fn`r;!+]HB'4q&S*qc>p>-aN#F^]WR[: %+;4DA$r`^AY@Tc*;g4;7(&q<4<Zpn.bCF=/EW"ZdA#>PUp'%uDVp"koF]dg0^=Rg-c='EGlN3:5K1JXaRLUjc@HQOMj*P!6>=M%= %8UJBMe;aoQ.-Rn;,Q$5X*m[?k`<s@]E6BVu(\oTbScjb>WCIuPC6X%"D02"T/Z$@LpAHd[jI)"EjUV_r%Vs9;`g5J)74t&t[Zf0N %8c(QmMldK\,0Ef"W?iXWY*/Ujra#cf-nl`RWfpRV^RpRQbp*#_r+#$:7s[q^\]AgVqjLMq,3P9bUuDjF]<sQ?Q;R?<iA4ur_-;\7 %p`P]7C9-t!`r:'cc/\Ss&X-OObd-=FP7J;<VKLc?ga:].aGrj!bU8#4]^Tm5YYk!KDc'Uo:\,Jf9YG^p^<GGh$3%1$?UVd_4sIL1 %Ul#ah<mA2M,UD:!^IjJ;2S:`brUI#(f\Imh4hZdPXH"9S=S7fP&?EN6HJbAPf;n"Pb@n.#DSFau%Yp62Pe-@iLXK8hTG*'P4mn$! %4]KRC[.h1%,]8>,F=jWAX6QX6*MW\5C8@l*m_#P"YkC-&#?bE)jqX:V^(mV>dL.8@TO4%JBG%O"1+bgn4c\eio$bMoqDEE,LLVEG %>=[K"V?o\'<ckA@+duL,]eA?sJ%jDZhBGrE`7m4)N^+,M0Jn%>:"R^$I22DSXQJ'$#$R>C?sA,g]g(35aV\fqWP=0g'la8f:l0R_ %OMHuS&e]Gp=Srpb]3DftI;N<HoBLf?&B2;mB;DWj]h-HaP0ceFrY[+rrF_e54UIB<9^A/Di7+Gt%_g*-f2^uBVpGuIC)TDV2>B:K %nCZR!dY30%[(YrDFo,9Ok/9G!\N-pU4cIJZ\RJJr^I#I&!pEWL]rjP3@YGFnDC)0=8k^+fQla-_hM39L+FPf%_PV,,h"GZ^b92?s %iA<$>-,1MXhTI&]B1D@3$md<,R@tlhfGu?WjD;8pXI:ddjAj,\L`qL#L&TQ<PGB7J.gos71!,V^jNMCI=sFR$kl%I99uPN*+Q/tB %`uSuGR"CbCSS^!^a\*Vip=6go&N!cTL>>C9WFdK$>"^_/q3-@X1:tE8(n"ai?0n^uZ_HRuX"4+(oWf^L9UMS*Xq1fLp?*h`QH"lW %_&"!>PkHhCLn+MBSOZ1>kVJ5T/kpDG.74=9*edh?GUI6Mo!X",\&':M3c#ms(/E24Om+:Z`=).EnU>F%59V?R;\3D]`'q![(!S9" %>t9>F$+7BIrX$:Nictg$L1tZYcYhnNcZJ63h=W4+S9uiAZ'I+UP(_8d%hie+&c],E[aoLjR2db>Z^H%r,EGmffa.OcUjcK=dpefu %imW3rJjqW8GpI&[/E1%2S:)c,GFhN9J%APsgPd(!jC9=LP;-r5ekKf-8;*uq!"au`eHH#g[AZf#\(N8*1qro&QtOLh/9:._C!tIV %e"W<arFl^iSlXF-\9Pi!_Wi'Bl!PU#bQgp_^)asMce(dBSp-l:MgF'kg?(;2I%rfQ&_8V@r(1:q85sHJ7s/Of8+gJoO5qPCMWCOI %VY[35q*AKCe5BMF8+A[^jsS"$8bH6I^MXESDi4N^HB[5H@F9]aj7eH$DdAE5l1F4oSWFn(GV?NQU%T]%T&elf7ahp_p1YJ0#&>9D %#5`!3An'FL$IdV<L(#Z(L1D@1kKSGi7^K>q[V'LnWD3+4r/0fB\.NuS[977ZE$KBbroh/c=L\rTgeXrkX9_NF1+tuCGRPY"5qnPC %0F3D2=mDZ$7NP^fM``e2XDuoF]C(uBMB/H%pLHU4Y"if$OfK-WC':F._]%bMZ(M2DQ)@3K.!T)jAJ.6eSoN$$6rH:W+i;:sG",q: %oYlYMdFCa^di:@D)H]$B,j#ZR3CNAKR4ujNGr@h1\D0^@:]M/h&AUG0JU1s9[L$G#5L8KVDbSesV\PA.AgeqPb^TN1iX)S&CWh<. %'t<A-#iCN@LleWtPAd%ce,4WcihIfJZF!D^q"Ie<fbVp_DJ$6:Ct>+giA=D=k4-o*GH+&eg.7J7;>\U7NPdc9p="\>0N$+BbSS`_ %'>-Y!N!-?2&>(L%T-p"K.dCPnRB88@hk/ZudYEU,^9+-TX1_:]lLplZM]2;mBlb4P^.BBl_KqO/Y7#4g2u6'4niQMdZUr]ERRL[^ %W+Jg\m=Q+ZBaqub1%,FdL=,$8MU,G654A8VJ%DeC(mI>4MaXItho"aXm8%r#@GdgrJN1fq;4,Xlp/MYg8H?I`PeU+cni-5U*;"MO %4O'?S;p:iQF[g<OpgjYI@rbrBh%KjrS=J^)2l$%X[a7AQZ868u`i(T#k&fE(E60b#U07C?d\#NmVdP'95^A;q*eTsFaQGQ;qDi`. %CS*/6K9^qBfpTa'?31k3"*V85;^?q5$bK2WgV`p!B76l/*(;SP=Zg(R_>cW0r8lFh\XVI[$b\F.*h4I]B<?6dNA6K"]BPl-.TaMp %a^!6]Dd<_mjJMUpT"[*AAso-;UH^?-#NsG"+.E-ucX$FWfDj,<s5IDbpilc$ornCCrGVZ)YPt<:8oD$B?4d6&^tL<JnkV?Sa!Yg$ %odtnFThd,[=.d*fiYS2J/*9/e_Xs"Tb+kf*Nibi(q]C6"<e,ph<1gSXd&\@C6Z()8:i6R^lPkIXhi%>9h5Xh(EJ\-sPtRpM)S)nn %jJGAY?Z8+(P$?n%/?#XE+4>o[TDtSH4b5GtX!\3;71u,rU,[1T"QPX8:U]R%rS3ML^LG@f6PU@JF`L_EP"X9p(ZP3c1bFPaGu<=Z %P0>UGFp=JdD$@WAJ])b+n\VJGStFV4V*-0CM9"_h0'-!uIbH\3=oS"P^Zj1rPcFE'&)eg=;#B\W54j(J52uHqJr;-;_Xbt;?^JSN %1&mH-bP1XIe(iEEs$`Thn,M&frr?@9>>0GBB8sjrIb+O%k'Z'VT";PPHoF!-EHB8ed@<F5WqS+9SCBYcP\B;qmb-o/^5u-uS)gUa %1]Ig.^qLPelR)C"2nI>=g4\o\\gB/?#u>F97sp&Yfu(K%D_nF]Wace:17b^UJY&+j]W^_i7m-D+&F-s3G"O_tW&(FWJNb7-mo#ib %]KuRX5?tK)N>l@B:C$'R[s3,L*ZMWh1Ca9B7/YD$$[LQ$K;b]l<[8l#I>DtQHiKu[pAF%'KKW\<M%eeBY(&+lZGaLJ=7Vr7rhrQL %o=f"@`\ZM#j3K4I@s*H<O4=gd5?>gsDf&/JhU&ZQ&OLsVWP<Usp<U#i`\rhP8>RmC97JUG@4hEQ<l3Lr>;'^6^cOi`Jl#u?e[638 %CVY:JQ[nf3YCLWl5P/Z'M`6;+5Apc]o=Z6a`#koUJ#c/%,gYQjo<*['EnL-1+9J-X8etn@WeY2*U9bF%F[Br`Zg2TPmEb_!IQu-8 %DQPrT*Kg=m]K'<70C/DUFr`#*,5bUA3>rb/V`s`J]0BabdP.#+?'*[i+[,;81-L*?EtQ=]&f#K*!6-,JBAB3p3Zd@9hqC3BHCKDk %b;?-+QCGE653Z9dSfd=Rg,Zc/?iTrg+h4\BYmg+RMtUc&ft/5Hs2_\CouDKYDs"djmtpeID#<!f(A3aJO6;T$c>0oh)"EdJN^@"o %GiB4r)IG:<(#:[/h_<#<8$#A]ne)`.KK[Y?Y2N1JO1=8/NqS.?<Pq_@Lm=#r%tClj\lJ\Br**IeV/b`qcMcscAmdT#\&NiLm2-Eh %gZ%3cYh!ZSRdj=/c*$ji\PQ]1"XQc50B<A;[8@<3L19JPm8nV"^F[:Witp)C^ED7^[Jni7no+R#YQ+7PrN#s4qg\V<hu3HPornAD %J,8KGs#XNd%tFO"roWZskJ.&e07No$s7l><oA_M'e)12MJ,JV^pm6K!XuRL6Am%Iog=S1#YV/6?c1TE_n%/=%IdB;uk9'`Us1S@* %pUpOpr\mP(@a%n.403Q(dO)6o^OOj!`$^$a10.7KEH_=,,PConhu0S\%CZ920=i)RbkTfI?N9j0^<Kl9Z9@t@VE;cOc?Qq-Vb;@T %poaV4osoQJ%H)HJrVulAhu344r:Q-NrGV[9E"CPC:d^%mrr\[>0Fe'6aSb3K/`iVCIsgS6I4%5JMe,r`Z/M:(rl`Ks@`4QSrsSAA %EXt0Vgp,pum%eec'FCLU2H0,?Ofr]Wo$HIL[QHDA[r*s(79C8/Z8-1t6BU$!rkC5e!0\R3J6kCuM!shDD'ZWdYMQP9f*6kXA_QA$ %THZNVIeLt`ZUH=q^HB.;p\r!gB,O8?SPsL@ZlC@(lRfkn5NBd"I5kS+?!a.P'ebK+i2L!9L6WQNXd9q=hhj<9V]^H_9D:Mtm$H>5 %[?%h1qQlS-N"b%\NJuc6f7)*kAHC26T>g-U1Y7lk'-h)Q&OP#^`(ua),+ZAH'.C\@P=Zit)\,?CVdgn!,sUt,*]`g]<_%/Xj\+?3 %a:`kL>@\RGAQ@]2`0:1:Z%-Mqogl)b?<\u4Yodb.G2%K"pR:aBKAk-l]K9tir0pG=ZuMFMaLV?W1>8.!>kaGi[F:H8p3CmWb4-]A %E!/2WD?PM^TG?X?!!,BX];kZ^5h(@X90!=&R<JkmW`"a@fGEY@&d68#r.U`s?$1cB3;]#f"pfU#hAZaur_aX?r]V"V#f=khmu6=f %5QSRRf%Nr6i*Y)]+g5;-Q5fpglfND]U*o!Y&-0<nXJ&<pmS3p?6L&_.<^P:1RA:Zmr$3_NHS'W_NWbjHqLuqtlHOTo`\\6Z:*5Mu %dGrGC`N:*`HB.goXVCrsOUNWl%!MYb6X1OUJ<EPFgd<K[qprKB\WBU\P.bL:^/Xco-t#*dZSiLOjf4DKF1/40dNnCW&HWC9NO.5* %.=*Clg+]n[+!S-#(r#Vl4pi-O#/"8JQG(,Mc^2&Un?^tM=:!D1TRciQ'Jepq[31Gq6iZFo9ba?76@&OHi\sG$r5C7<Y:l5XhY3cA %C4F@5rQma@Q=a?_712UMNsH5UE$Q^(9=.D5E3HN[n$N5BOP3@0jQ>;b'bk"gpUf=kkGR5:cJ9s<E1ldPh'4Q/.G0TCSlDImkP'-D %c/@GDhF@\u/(,H4B5G^JVO:Ws!Jh9):ZHouds1^`4O@a-'c.(uV>TnCnYX<Qr=%WhG[<nu/J"=["pW9H+XA!Hmk>)baubW7LNu%m %fii1NIeVUjr:Jb$#tf$0"NR^+HN?mS)XF6WM"04LZZNr@^Q/[LQab2D?Pi$-=9S-]"9tt_rb^HZIiH^XMsNLr;DHqP1I;Im>5#:u %:j]=>b#Y&nXetH6RYdkj42$pZFZ+BTQN-?<DS1-O&Q/R7-s7+;J,A(.iq!Gd8IiH0lL)W@J+;^9],1MGjl(X$RYYED>n>p16F/uZ %?PoI2FNY3oo(oNR'-6dqep"^7q*3]Y*q%fZrI`+E?gD%UDV`W.bF`\.n!i/kJ"d/sT'e\pmWC4kB:nTd5`H$G2eDP'm1t%kEbH[A %P7UN9Xo&:TnF`91KpYmeijLH#[Rse!X8CcPA<h#@]`K+pV,bHHIb&C82Q3SM-]g$#QO&3K\X;%ts&>&UD+6Fbi"t"pgeh<3Sd/%d %g=dpiEE+4naN_6U>1n*XK?_'cPecb72SuN8CN;h)HeX!Z1tk$M=T=pgqJ`<>BnphjNJ61Y5\k)l^iND>*;E)UYoQq2aObEBaUPq! %IYjOS5#Gkfq,r"id(?+EO\"dbRS&s3Y9QHN#J0gh)gC<Y5;@WWL?M_=&b_br%lGW:M1u4`G?<KOgt-e'OD*N*<o'0X3@c\8G?qR] %KpJoh3A7bX,r%YkK<Lt9b[BennaT;\Qo=R0#/gqRa,fp/E*_A^9*K&b<$2SV5XGV'odV^22HA\h.5lOPJb?Qs^WFbYp,as5$jQ(4 %K->r;*GrWS_\O)+`LK37GMetb)gAj+_hb\ge@V6j?V!`Ua&ZAnkrlYI0A\6HEX`Nmq>aW4L53S:BC2oS2We@O';-?,I_P%<&>/Hk %iF"Du!Q?TW&m#'jg)3H"$=+hQ+06]"5kTk^1VOIWr)p=rm0G,qb!;uk/rLpoJ!O8gY/X6G7!jKil9?KQhLD*pmbdrmJ,%?>p%SLW %:[ns9aVU'9,JJ#+RP$Q8EW.E_:N'D%g.V393RkX$r6jEJB67qcp2mW(g7.CDKa4(0BpYeV49Z'%Y+eP.05.Kb1Ule]JF'jgF<o,= %f8edP,i=K]\SuX=a7Rehi75L.:tAK%?^#<d4X[XDZA[>dYnOg^B"X`*[JVe/`qM)cI/(sH5\OJ*IYZ5`XkIp2`55ABGX9A6A271' %aA8Kt5_k>uGQ$o^l_NA77C(s:iRaQ<BO5tM:-=:&9e+gWFL1R`Bg?mQ\cO]p'W#[5Edt2Fbm%dUWl<_,]_(H$?!s<tM_^tlcrX'6 %K=1bPk7)9dCSSlpWji<!A/s7VohL2\!3IBl[AWB,hsd==::b4S;*o=6Oa^[/ELgLlZq$1]m:+2RXBON^Jm\VE"CHipH0K&KSC/@X %>1K:D+``\]B/F%!Nf<*`-]cGo[WCK3DldE&JPcSTEm,7@[pWP7F(Z4V?JN/9M$!Q>]AB<1e>Z+W6UsclTK@*XaHg[Y1@T72XcVBA %G.U7b^b-"C@$e<c$Co*K`Ur)-HKf7$SM\]!$b"4T(cd:j!LQ,aD.4d,MHVkqFcZ.i$02C5/NlYB:PWNj<Y.0e[9XAslO.??[s%?M %\*HbC%m[M<q8[,k7gr[q8\$O2TB86-Fh_l"OA&XlEP#ft9&NCInPBMDp*FQ*6O,t7?<),U*W+O+p7l3L`-g&#F0:ZB0n!'=XNJkH %QX?tg6)L-M?"-PR'+0t`R;k=8_)U=/$%-UBFsu6fDtfs4?!e7YLYe>9p8f]^PAfR"%1-H>9D2Z9\V@XKZ[k1&"<1XZ,AmZn)VQic %3Hh69,L.!(#SP,#ID'X,%r^&X<?9ng6hI(J[&e+R7BAjA8$r`.j5:k;IN6]`2IVg:']%Ulj;)TC\i+X\@a!aPKO3NIlg%hfeKj:. %T+>f045`bG8)a]RZ9'B1Z<+&J>L%MGY/K\oTfY6?JK2.tX(Pc!]8XW\?1!_p7[MDV<ThCkbP'<-XFh`8Wm!_E5u5pl/Hp/Bg]<Wr %&>YYa\DVmf??;;^nH3(sWcR*pr8%)Y*3lhnS?J-cMsHhsTgMCH:..UOTe=;NTQ]BJ!D&bP#2l/mDY(#W">8VN?[$K\n*4&qd(OP/ %6V\-9:!&'Z\],b(KiN52(HMQT<I51q`+mDDTpDCfdg!ST?;VH9WPYgAN>hBuj5)ZnY!FZ627so#HWn^1%FdqF_psqXNu?Hqd@PBq %A-I<UXY73S:c[N9<UOe=VW2\J3biC0:AFhNSp$c@0%h$!$"fIOb;MEo%80mK#`JTaGTGD1JV.Lo\1H]I:,PW(D9tua22/OsC-9MT %]mZ%AY[(bVjT=51;mouAih/trL8V:Tn=1!AJ*h9,nN(RS'5C9A),WKWf`Pu'heCuHX-MZI@J/'t%QIN80dE/gmGb7"HUABm/)Ufj %B^t$Hc_J#o(X8LV&PaHj=Z8WhSd`W5h'B-0*TVtj0`L3VU4f^)!EH@O6`+NqrHN.S$YQ1#qH3NdCn&us@^/Gk'K+3q>cl1@jK9.& %krLa!H#Rf>=M=@76VaYMQimr%<bH2J.3um;EAs60.T7'.C)!0?8+X$$E0tMSmKE5EER&jud']!G_HQi]l)K!BVK_RW4AJG9n:"98 %L!HsEeTpLSnj/-*8od)?&\5%2661+!c_N$,HTi5NZpWmt^%eG-?-ntGNF]G6=.U?G]BZ2+*?_:0#BFpQi-T7Lf&/?[$3lbDB<G91 %'D>TqJbtR&]/F]o./Wt4dhN\fl]MkE!K^d/!GCWnF<]\nFsJNAj;u*C>gN6J>s2ghDDV"g\oJf32B]u?m?PuAP;gM,G0gQ%`0GW3 %/03-(?GcOL:M5Z&q`H^WF0bCIK;uV!U7]%[eWh1PL^4;J"ciAHd(tQq1;NE!\2i#]?_>UD_+Mpa'9CREZ6gY5cg.=NOc][V8u\#I %K,CJ.E'g^n<QL``;4>`_TrQ^9$dmVY%QPuN5("@X=<-"*1_WgO^fsZD#A0<n3s^ZF)-bn6AA[-iY.`.gYcaO]/"DlY!ROe@<a?Lr %BCBK%NW<:Rkkk?,6[@lYOcGM5;j>+Rc5/bm>,2[H$=Tcej2'l@1,.7e-BGk,c4"V.7ET(L`DW\j7m8D8eoJQhRlB(`QA%OhDC2-r %Dj*^UA2[jckCrt+5#HMYBnDXM207c.,PfnW5cYVZOQIOAC#6s$G2<br50kj^5#K8^Z*$[M;a3IOH5'mI@+m5NLf#>3`juj9Wk;PF %08k^_?GP'5-.OIs0bKb2UE5$dEJ=KN33uTj^6P3D<#Wgr;B%SH7:'%aH;o$Te2;s[je:p*k=@N>d=J%pi"7@+[UBZ>o^X:H?TRhI %D<#r5;gn!)e'cmDf)o7KKhm8qb1IGo&'V^;#BB8W,Db;=2Sm;i"["c:eh"]m)1Cg'P*IU(.l`.u/m-$uLcB/=-rp'd^o+PrZ]DXG %`eQ%b!h7h./pUDW>>`]B"BiRrUX'>c"ZB"eIFef--H8PqC.hFf$DOoDg'E39ihJ9YmS(K9DD)2BW.]G\.Gd?DJER^L?P)qA$Jh`5 %!!laC8lCNF@O8/+l&'=H>OT+YeN9'A@YK>.?:<YS:mYHhSX/CZI:0%a?H'_("YguT.H[Rt]OZ<e1/pWIj(HjN]>3Ar!M&.t!jRKL %^u7!Qi#J"=&_r\g_bAd?S`q]FL1aC`91,f5KaQ)&Q,d(t'T$9"Re>Mcs(215i1X8o6W+ME]rp##GEPN,4o3AB;-&Ma$6$FB%+'S' %(][NY'ZnUoX9V#fN^SqD-DZ>EnRT'`5]g4:!)`Om5\;@:jTaN!,h'qo<FC"e*MVl&#Z:q<b`fX%i-do0BG8`fU]r;AkQ2ng\LrOF %bXN_^*^XQ,dq<h/O=2cXY:e89%8f9VQ$COoVSEm7YlUR.C']JI688HPpppp^YmI-\H\'#q>[]^eUu2BY0$.OTR$e&j(Xa4J8jZ8t %e*@8Pd8^d"L.GqQ$R1>^OdcV[m/dg,M4o\gI:-Hu]9%o'G;5WX93])],BiV=?h!-(C5Gg(L+keZ++>bfj%\R4T39!k"fut#6e1.8 %THK"^>`1rFn4Z+N=XI;1`fsmkN)u8]h<ON_Rhan]&B]`l2<FlLM714pZ8-LmP[X*Y9:qUb_#IG<67aYCaTsUb&J2bfL!ki0L;)S& %]om&hd6sk&pf4XQm/gt=jputb")=)4LEpH)_aEc+#)M"i-5Ce[Zg=-I:thUGJ:rq>i^p2k#Z:Dp(01qiUlaU?*ak5\R(N!QblHO& %V<VpP@;WSXec6h)'P;Tb9oRDo=@aE"5QRS-qp>SpNX9oAWQftW&snsa_BfA*$Ju\t']K+K:po@:dKbfgKf<GraeZl/:,(WSWD?!K %bE!!cW;Kq*IBcTGV,&2d#-PGcbS@dk=IBb1h@FMpXMRE6Qs(Ts#m="(=c^-udsuPtKoi[YAE)$97ZERr+-/tsS$O9l&!3D(,"0$c %>0/&O?:-,.KfTlAE&$gE<AN87_:b'dX4-52d\i.B!2RQf2-h';CP8W4YKNeNBIkXUK2YJ>aCD8U@n\X84t#,rB3$Q>n3Pk,l"G*. %$\[PFGcg1rnVL4VmYb$F2bGCa5gTXWP0g"hgEY5RSI>lnfu;L<>ta[G*W"ui?]oS7]^=-&CVW=%%!]33(*Af%3>Kf!eV%LcJdua\ %s(]@RrT\K^$1NKb%r0<<N@!tGpi,ZkR=hMY`F3\e>#Cq-N"rhC@sr7;*AB[>NinV*Jd;pT.A>5-DXu5P:QG#mfmBu?b1-4Wg#M!K %\Z*kk2M(=Nc[j#UX<hcJa*j\6gcC-b>.qW[W\CD''W#mrT.J+3GhO!dImM*'mU<OU'QL.o0YNe7W=#';K_I9mT%[$Tn_$\eD)D]m %Yt#fsg<l*@`C";5Lph9BPfoiW2,KHq);"2CNu?(gh+,Yrh'*UE#7i'i>QAcW'rP<,'d]6u!/TkVB9AM_!:cIWgHAR=Ft>@?)V!2W %AH`!"DffDEXK,e79q:R1&6Xe\0^]]Q@^"BEkV?@PT6o&gjAWX(#_C;4ZBfR$f,rI99:KH;_(<^RpO`er>WB&E;4n>)\59L[MprL" %EmG[?9t=ZRLY!9(TIuX)N%t?4m\;<sPE<"KN:I\OfTghfB>>hE&;$.mS]f??e8h"S!ob6nABn1QR#:RlS'Pn74S>/nJHd$Hf<-$$ %T($oEC["nJHhi_P,#O'^Xg7'<,2RQLdu]d^B>V%]`_QL;8!h/B5I!gTk"e7n\]NJ;&J*6R[_:@Tc:oso1A+&ICchLDNL'[FZ<=P> %Fh`J3+Fa3q=bh6Jj)6i)"^PLt:RSbD&t_0_pWVp[m-Q_6P(3:afa2S\=TT6[lmhAV_/7<79C.UnPU"7/MK*/Zd/p`_2JM.G7BV9n %HPZAj:MSCebrf\';C_3tPI%X-JeBFjFpIF:=KpZNW2GbWSZ-M2Cr$:+1=6dZDVYJ=#u`hN/nE"W1gRLt8AXo$W5[aY"B/\VNYisd %.-hYt%(;d#\RYfoWcLMANT78W_LjX\eZVGM]5`/7re1kfHFd0/gn&AUGj;t'-S\Iu^mpr_K";2EKFMT/&\sWr.>m(52>kqT6TfB$ %o-0ZioJ..Ej+_o'OerYn!TPN`^^%#.`mheUKYn)hUKo3L'lg0rD0;BBgF-oq7t%p;E"p:R+2;9SG1ko9#5<.1dtF-CXuCGk`0<r[ %"'dC):0lj]gE:@o>0Eq+p^1ap88m/=n30;^o6i3a"aq(2:f0L-KnL5e6@rdPVG/S!XX"AGWFO`+A:T:he]JA)%\;K?9M,tPI`Sgs %MmD96\0_Y(:]I<p;#/J;1CY10&af[0%F2gEb"uel"$r:mVF_]k5cDB=@uoJ;_t/p;`=Xe^!RFd[0iCk<5[J/4%Kk)BckERlA$]?[ %*pk[/<oSA@Ct9D9]:o)7k!6SM2FkJtohh7>ZlG5C$^@Tr.A)B3KcVV5I5qO8q#OYA8+SbsX?&*ol,el^M_M.`4NAM;>E>dhM]&9- %>)XoC`[K5eFZmlh8B@*eA8?iI/Xco:>!t$O;51HQM-ber9p]$kL_E0;HttT`.q:lhJ/ElP+bC;c(:P!1IEI+i3n>GYM;A;-22:V6 %i-Gp^4(_(PTjU@-3A$9'lsX4:QV?BmeLk@cEfSQhCZS_gLo!-K0j8WbJcGf1CYL\,9A=,2_g%Keb/>>+d0VZO.g-&7,jf(7DP#mM %JQZ^kBtUb(+Wsc>_4uG/[-9;=N)$@H'1#uGPlZe-P!IXXLlfV1-(;4O<Tb+T#K<5#Nn=9CWA$+k,&MF1CI\E820>$'f5?u40TG(7 %Wg8(U65RPHT=1pN3+L8!+BaLdI+@8Q\0&FpQ'a&P)6P#$(q=)u(_q;!$lXqqSK<T!3KliAZt9s%iD>n5k'CR5`sk.0N1P"`F4SKM %[]Upap/PnbD4D`55S[#^"F:/sF8SWsI4lM&-GEURJ]\DMMMX<_.G$hM(]l;h>qVs3^9I%c9Z1&');/o#I]n;<D'I<V.;+)KUlD\' %CB%GS.[h)ci^#U/pEdaO&m+ZR$!1,Nbj;Z=JIu3(N&KY*C/k;o<F\FHdOAf@e>U:Y1^k>_RNPM]efm41A.[bJ]%VF?kT^+d58=sB %'$\*j8,S88S>@C/W3Kff<_s"KJ7Fe68pO`9T<STYe'+L<Cr^g^/><D8[C5j34fmHF]jW/J.H1mLg:96s<*l5'4X4AOb%Z_NdU!WJ %;O4MBEY(`!==U^W*Ju2[YcS$24,Ljg0m3fh-^uXjn>MtZO,iE^%,8(,S;=l!8R0>p<'_R+(S7sD"EOC>f5MZV(a)-tU,Vm1NqP!K %*a%a-T!V4haG']Pl>h1`d`T']p^NNW9MajZQ\Ku#YBYOI"'K8E]5d]GQ>/6K$fR=]]FC'bZ^]8i4tO)Zl!^T$`[`s1CnZ7nf`3aE %8$^7?fJnPh4"3<u,RBPHp1^`Q,'XL\e$edce1-blm!Ntbpt19)(G^)lX_t7lfF.HPef`Ba3mnJg58r+Gi5DfI"$$E:*n</B/*t>> %b-'HX;:Xec7mAphA3W?:g$c2BAII%!iG3qZ[2Yt"D_5Uk@)L"=8nW6:d`sc>SS-l1+c8fXN`,DMP<ISC#6o@Z?->Of_bRq0=;<>d %N2-mm1m--f&Un\D`j.#8Y'9eY7E(:R6m*>P%eC1t&8iF&=r>Q;K-^=(4\)!&SkD&MD*u<DHKtR!#;o[`4<3&(Y-d:hS[Zi)+XmUd %qrf1:dgMuG!52gBB;64o'X!9N5W[A3b]()k\1^8PWZp6Bj23"RlODGpOjNBL$dj\d_a;FF&P@]e5^-j/iW;&?V<1tT<9/On[@[dA %:PcIOi,AhV,-,!Nrg'h4B2T:VZk!Ll3c;W^.CJ?u^bms$eHGe#b4;RaE0A-f$/X_kC2CehjdTcUB6f"65Z?RH%QT>E3)?N;"0gT8 %rI1XF6,pd^gQqFp/J2Y7I6Amhh/!.Rirkipetcg^30;t09/jJKVUd*8N;4dKjPI*0p0g+9^4n7rKkDP5KOml7?R8gRbHU?<X?s;6 %A#2LpM=pu)ot6QF<OJu%R/#oNNZW7`;,'WqT!h;P^L"V>n-p*u)Re8>23=D39Mg_hUimj&]m0Xe)lDN[\e(O'O&V_).-XEp]M4n\ %.:ao"#'l<SndZV^?KBTr[?E<tO2l3S]1KW>!FMQ!ksP`,;e1,:_nG16O8/0Qlu3/#S'EC+ERf/=1mYR_1_0t:?#IW4L60k888&-[ %EVt]gS9Bic>'?R@UY@CZ>jAg]/<i+4n#i4@>d?5pa-\mkF-XE<'<^.6^#;68KYf_MYKOt7=B]gD[>IHLC;@BNF.B9.XYS%k*%/&J %F6t)+%J0&8;_=gXK=Nti.d`B3dL)(!YA50PMmO0_<"T[t7C>d`PLV"L_V4CpQF<T9S<?5p6WGS7rJ$;BPh`G,`4m3#l?mjH@3(^. %5-d4211F*2\Z<\JPpR):T;6TkT\9k'mrIDaGj/b_I8ZgBT1i*-%?Zj&K.?1:Xk:O$]e.p_#X:<NPSY">!9l(L-qY?:!4?+JFR)51 %*U.8#d;V;-D%SLVIoF5bj-CP#GlTpIBNo?s"!G#hTZ(ip5ZC(#<`B#(f@jK8_ANDjR1tOKG?f!1=278qnmam=5@K8%a&I=/Z4J?n %48[i<%OJ_kn;jI$XXS."Xb/L$7<T.aU!PadaC+.S(,aVK2nP%C(`F`$'IcgC+Gk@hmP4_UbdU1e7lXmW)Fdnp3RtF>*BcMB]Q:0f %j1dl//$a:<b3KWLE)]2Q?'-Ci[8.Q&T'K1Mp*)_?=mWL).j`om86742j<m3!>:QU@(jB*On2=a\rcFlhNj+=/0V*4D?V/ZV//WC" %gA2;<\""_oXQ*]Z/#N.E)AQO[fA4!0CNZYsE^k)bicHU8/W5\09TNFHgs;ODM+^$S;(H<n*3rbmB\]+FQk8U6&3c<b`iT<%a\(A2 %gYQB/Q7q6dbS=ac'liP0X:Vq'n_]jg1#U\p(L<7kZprhtViYm0PJrd8)=T,XDi2CN$C]sD-u@ZK.%I6J.T(q'E7j6uRRIGE\b-s] %^Y@P)[7;_`\7HGB4iQ-JEIZfP/M]nEX.C&Qe`q:]$+M0"HE,KZ9ee)c"M7\tUbH!p:fL<gbYZZq&l:"3-S5hI9M#^KY#l_G?<Z6? %OM,.'LBp#q?^tuZ+?Hj.%BJU77;;.3=ZeL)pRBr&k_[lrOK^-[m4.!:;q)YBH?+IV?r0iF^fXCsPl_%GpStij6"<IU;me-oS=aQG %f_>r8G>-V&;7[/o$lD(?/6&H#XdaSHOKW#sr#cVX&Gt"YK]1sBL'%re42lgLJaWC"%*YG\+06&7j1u`_n=[U^";SP*'GQ).Q:QFm %g>Ba:]+)\hM"$:pSe,:3BYp.tD"LZ_L[)Z0X9dsm_,M+r&=VD(TJ:An?urOccN:LB72$tSO(_MS%0RT;%RAf$VFM3FDGWg9p7R&u %*G[4W5>H24Q_u9o.5GV>=uSmC1:Nk.=[;%e,'l=mj>GFfkS6[H0f'6*"BV]:;H3:=:_&G7*7DD#&1,H#%\b<.<);,I8?pbVFF_#4 %p.XU0UWeCupp*.n?iUk8P39`GGL$g-';R<t;aIsRASZOH>Qk?NDMB9Ad)g?O)L(,Eb2G8=6"`lQpX%(/ja6>[6#]@(@M%C3#<G!( %0JGiLgF4X3E>j=0VYDD#-g,`tLCH)K6b2JEj2_33Xp&VdWXH3`cBe9fHkQu$_XWAU2H$OZ8!3Nli1S+'GFbqMRoe\9]E[DmrE\dE %)s08=-[cVNOkS0d`(m$ciKh;>+ZdTBE^f4$;c$e\I5V=7)n%$RTf,i3NZnpm`;HAJ%>J6q)Y3T2Bb[UgEe\Q5=0mY4G?DLd1W*Cl %N<d&i@>7.4,VUSJ+]=(%7O/9@`o?oC#&qX2S/N0%EMPIDn\Ce^i(eq=oU^+/`hkQgLdm\!/^R>beS:!VF-^ND=@(P:"io8H%ZfLc %SAJSJ1?+,\,uc@p@]W\@Ld,+DVFI\g`ggK31;'6U_/Z7risb=+baUb3=%nR_n).U0[h4XkW`s!3i`N9JGn.4'iW3N)@SVrgr>cgF %=Fj"Z^1pZ0%IqW*L9=4iR*k'@XQ`a6UXC?D7BkL*:6+pQh61CV+gMC]3\?2MKMLI1/$+!6@h[&&0>=u_1KMBOo_bfOc@ZJF9D^e5 %I\4F[/!Ju/`U(?KUD.:9\6(^7S&<'9[ST;W-o.S'%U6@hBj$u"m?eRne$O<aA2.?85VO0*J5?4W@SKY)`R-&,BkH4kU%t>#aVIC3 %k1cmJOebD`oGfAd,KcJ,]:R,g(-W6f:esBQ%4<C08eeGS>7fAa_r0S_f))sYc.)?C[2iGYOMJmC2)XpApsVTRrPP-3lL:cK+\7'u %5nU.4)AhD2:C2$4(N]"L0!%9g,W#<NBjedNT:nc!At6MK%#6G_R=:mReD_%GG4+OSQWAPRbNU^<!uq4PHM4(p&You#)@&kB5)N#A %C%r*D7>bNL]qNd),''sj%)W9#q)O5t`Ec5_SV#GSod6<.%X0UKn$"reB]5k/Obd4&nMWGLe_a@B.41<km80T"Aj2D+)X!9A')cS/ %BLC(7_Z<hm(*bb\2m!*BCr2O<_i886XG@+fEp4+&ReTHr+_X:&6p*A=LPBN+DM8`#)1#AKV^cSj:g9@&?gdn/Qb$4b-VfIKj5uls %f&9okXeEXj.M_jo=t*B@'mB2saq$l4E(7h=4Z8kV_X\Ja\T3"jO&5)&SBEb0eZL91A8ST`@k8bV+jan9=lHs(p2hQ"G?-ZL6EJ?Y %^_-!oUtY$RKWK3DTA''KfGfbcN%j-'fGk)RRMM#MQObaGKup,gB[Ad'gdoRL\(4tW?XX`!T*#-t`3u<EH0q]9\O[e[H<fQ7NZOfm %//Md[R2brn"<"+6B&XU#OQ\AmTh)t2W#H/50XifijA_2.k(,@p4kp.?'2io!fH_-#+SY6Xmt5R;?/X)i6P3kD=Jb0RJ"6'1^9mIK %Lo_jHhr2N+0HG2C.+nimeH(q+j^ue#N-6^_p[.rcbp8Pb`VFJWOO8AXl+O]&I<=\Y,Bom*4@OdL6H5t/NM"0J_((@CK5Agrr5^j$ %*_O.YBJc&$!ZMKZ6Wn8V?Au7o*(oIi0NDZI/uNOCHU9J-)U[4B62uPLm&A#u?.S.>Tr[uKJui[$jCa$1@HY>\7\<Zt^)/"\k)T&; %jn;Mj8&hT,]NCUS0sNI334s<3m/j"^VYKN13fW41ab+WDY!dB#3>%q1fYa0,2tOB6)dj$-d'6+sKl)aKWORZm*@$rAAQ+.M,4C1n %>&0T4%JiQ19Nl8[LE9b?*Mkf!(4eMg)Nc`8p7O,cq8gGFV4!s0Z6[nO?Z./@GSm[K!@Su8N9*L6TM1rXgr`mZCY3Ec9Y8rnWu:0e %lC:M=T;'f8/20Gh2c22\)h>aZ6t/0+]JT5T^_#.&'!ileX!Oi&i]&@[=edbaT1hL6jO`JGVjM0Y\kFlK<PcNBC,npa?7kn2.@ao3 %EDh$noU)ZO!E,/V2t`1.0ZX;(G;pP.;qk]d7)=G7/CMMe_2RK0$C\9s9ZqTFp:sOo)4SoZAq6Mc9f=L!WdKrmoYrH-U!G5hf<ElT %)Mtia25pBJ7_TnLJ2]gt\6cQ),;iC5Xm\^4ZclXt>;+r.TGE<9dYNqtFfr;b4!bDs=9iU_HHP&WkisA+KP%;U+<!41`3hK\nMBW` %1*,#u%a!D_6]'q,;lH>ZnXkdi/Fl/0;g4WlCe_X.8"So.9t'?\6r9DW:@HDH]sfQ:FcUm0_HDMV>o[A-QR71%CYN9F<JLJ;,U(7X %b$f3`;II2Fj:YH>V#;D*M)<L;^^u'X(\AqA+%7'_N1CiqZNW40B%/>_i`=P\@jYh6TgX@K-I\4\<uI$(4!lQ>#E+(i2q#86$kmG+ %[Q.=L`I[s!.-kEGEX^')ru9;a$ulR))\0n^f>$$JT(gZPQSfVl)c't4m].lEMmi?.#Ng_K<L\+C*Wm986Z2Lr?]O?(`F;1!ZZ(Yp %$j/o`*,V-CSO>"m8/;[=pbMI\VfsS^LojlcU6.Ea&_JR>H_g]cPCeIdRi(!M0+fWJ+S^`0(Vmqu-#R5'6gG>g?XOt!`,\ZgnZpj[ %S&KBn6WXh^_DGY=.^qE,)cBIbb-Y9/FNou&@27bJ=<)9\'ZUK;n\K4<%rfDNZe1*[M23RYTWWDpCkf6h+S\_[-aSt4&VePd@?X`^ %@d?Ckd)pF-JkH\S"'lXZ_kYA!9de5i&g"t,QqIb=`9JQlCsg?6P"OnL'-/7BF`jJjIHJ(Ql4;N9^5VXgS_26PK.e7CQUSr[0SL-_ %\nhe%'nbA[pk5]kPsP>LofODj6'-is)paOoF>o/G]$O,]`hrr-6E.<63r2dVmtJ6\M.&l:-cpq/0]H\Wc*S%S4_d=%SD8_%hfUpf %]<(:RVc#MK[9ONmIND$FXi4_I<+?>`=ql"S4:8(b]S:B-A:oHVafsBo/1f"h7jngF'uV8;3j31JlEbF@jM#8Igi4PSmUX/MoS'.+ %g>:G8T+_`uEr-Fef-99%/f=#tR->ab]J,U8=N2B/Ud]%Sk+`oXk7k@B9bTXL[7(#J6Y0Upn1GA.Qp(T00?rOoSc"0KV@20nR&AI8 %P2-:sWjYs%c:AA=DH7Lic7mN.?o`/0LFaAX<1cUN,giqPfQ01WG8u3c/D7I2iYJ;L\?&%DfqG1B:3*A7jhS)n`gpFFH;UV4<KriL %Z/J7WgU2,cHP%#.CW54N<<3&FXoUWESH/NsIaJNl]?O>K7_:M%Z)6+,K&<k[hO>=QL/f3Zq.mQe"["f+&B/JHX+E^8)`q-".`H0) %l[p=H,`ro%b^r"!Z"Ri',3V>&0im[MEj7*;$Gi=E$!2u4e"m509=\k,SW%FX=>#^XPsis9bj&+AY_l&S,ir;2V=daWmQrHJ>Peh; %"Fe+;9iWffQt($hGmIiK%T_EY(DjdDl!iVTR2QjNYKC$FBr"2N.#VhsXU=.*<Ws0a\3::u8W>Ta7Nc-c0PEkK6P^B`E)hV+*+F,' %P+)1jWqqcU%_/<1(%>AaHXh"$ZqL5o_@NLQMQi$1,4&AjhX3nLc9\?!Rg`:&d?NOF-i>MQKY!.QGrB;+^bp43q=]--haO40kS'W` %"XpR`R__bE?+CH5NK%,[,>K>7lti[u0)D=Uql7*HdhRn]JVVR&9^oXI9`5^m[oDo9p^,pC=K\J(^kpf;$"OY$Z`8I5BcFRs/l?a> %WIjhN8l&nj'l4&@p8/>]0[Nl=A!J!]9X5B?:.WAe.E2q>1W17cqD!q>JbpegP&N@T8VD4U=T>,ac!Yr6*#,Yd0uu\Q,r$8("q\,> %Ldh"CE`@s""Fi!MQ+LSh@3/i<6`[n1,U5\SX\Md:*c5Uc%Zpkkj<X3r!LZYAHSjRf@`*pu?"%Mk$j$J\b3"]7\t*?+3O^Gm<!ec2 %-e+`A9BM1jO,K%FVb>F?XphZ_eT+9+c3m8`c\Qu`N3q7_b!=0!L+6YKIK8%Gq.:j_`!nIDS^4Z3W6+!b*Po*]*O:VL#_kRE">M]6 %ZYT-%b#or4#h2>JTp]hS.c=ZKmp=_N]0i\](jZggqn#M)0OVN/:F@cU>RXS4H8(*[\q/cM]A)nOV%XbqnW0?]o`\CEYU`_0PCE`% %U[Y0U_0V>lBo.7]?Ong("D`ep'*'S#MP28hUnc8]7@GW;$kfQNQ]f4e_A6?#s/WMI+_P<pSLP^5SXKR:E0goXe^@P71tLr_41/oA %R@c#l23<#)!!3H;*eP;IZa'uEJ`#[C$/g`S+p+?kB*PVL7l;kt;BG[ne0e*oYjcKF%==*Uetgm=SBX8YB9OM6@:<;DTN7^I)h/M% %QRT^`+eU"8`A1#0B%FOd.++![W+$[fB2kSM<._mG6K36/"+V(<U$@.]r`\\a#UGKPlm/+@,%12*Z3V;MLis/MMT#Spk^hnGP9Hh@ %[&!Q[8i]9/pBe"K6Fo'p9/,/f=CS1n*<hoD*";YgTHY+;jr'_q"JPf]?]hA4E.]f0;=e&8Q0:$Y8G&lIkG2oZP4W-\4N*IQ]!'Z3 %)ojO_A/=mI5pPIpmI#d@C^93@n0c8ql%gIeaeLR9q4c9[SP!7cNW*B50o:=1JLcX7MTCc$)s!I.Ni\7("MqmY_RuO?2IcMbj`/04 %h4V+!U1flkih7"Q]4r&IY!<4h"$)d%FVkM/8j*T@8\*+*C)#:/8-:9gc>6r6:-e1oHWElFjh5eA1'?Npq3R7j14-/jVSiKEgF_^X %l7=%Z`-\H67GES7bnL@I)$f`@Ko\$",)5BI0[W^Rm%B75GDTj;+-a%RY%?riEn&7kJsj_Zg%;ul_Oj99D,(S$'Z-f)<.e]hPn%m5 %7QcM-1.@V\`ThaD"e6Us8uuW3j9.SVUT^u]U[fk%=B1)0q>'&_Rb[7$0FMD*Ajq[^;uj4jT[p`>CQs$#`T<CSdS9ZMB'["6+'J#/ %dB/cm"?U<?7oc)'7>Z`FZZPhF>G8<#Gri6*?k]]#4$-_$N"KPkr2dlrQ`uq=/5TVe#>qg-7/fj_:P\4j*%*84&\qDHn8X>"!X8:Z %;c9W]4A+@;[g#FJ@J\]k"J9b#OPFkY<#:nTT)/DR+Wf/:`Gh.lZ](Who,S4%+r5jK.;%N+!`r2YRF5&'".Zd.Z;@p,3_3aH&.t%M %OGA^E2+S)T)\.ac5g5uQ*c/XB4Fota)+)@mF$;'J_+7a)O]1YZCi#cAX(G_l9,*S0VYc\>BXd3,3qrM-X#b#O<cL0^dir1)c&^/S %Jn4`dpIk^@)+IZV6fA=ipJ)%Mdq3mD^OU;8N$iUa9,;`E)_.<<gcuG[L;SDE!L^?#EeBKq*RJ8%T`cWq#=QJfLdDui9e`k,%q3Zl %AHT3oVK.2L3T2sd;JfpY5Hp;h@&'q0k:R41KE!ub4:D/@`E>Z@k9kk3f<m[W=iU<XPthb=FG?QVm*q`W0dh#gIQSoB8g)9M-H30^ %+tCm&eI8%hO',/l'ZBSkgP%F5gu+Ruq^1bb34DX%mIsm@]f<bnG+cnnQ4,d:0aYlQIqJ(;7Ffk/g%8;MK"Do+EUH5+/5`PtL#O"9 %`hbDjYlHs?_UDaOaF$`pM,!]W,n$>kLuCNX3?PNGi'1Vccc"IG:AI/:&p&1A[+-I"[&.7<!:A*AqprId]=2X:gFa`Il%5*P*WF8t %NRuRP^Sn_[^aH2&-<_g^3u.!#]\#Z(%E[9_Vb*j*bB/mnQ6nj"42K-hY'21mA/>7`qRC'oC+,`g"o.^e=r+jVTSTg-J6\,5r.WeN %*PGjW!`pc2mK2P6YUO&-eo58U8><O:LYA^3F/M5V5I23t4qWhW^bDaM7P,WXd/hh@J8_p!T.KDhY7auD7aNjb#)ZMO=.@9p3@r"- %%Nc$m$*mUZ0$\AL<A1BY>bh'-l3tN6<]<UhI?>!,a>/V=%TFQdZSc]$Lnnl,C-)?FZCZimM!6.5l1J\4A<c&M/*'[4?sjg`1)AD5 %p(_8fb]0&.[//5t6^#R9a[5fU),L,QDKX\tOlR"Y"?'"I]gJ5X[>u=S6`H[Dg45/+FCAcY*2qpgq0<\M1/Q^ZM><bO_?eSnh`/`d %>m-67U"NPTIH^672IW*fC(b7%H-a=lC,cMiX&Ki)6XI[dg'ebj:B)/J<%7UOc)I=O?itp&hP$9'&:r)NkL?B3M/$g6)G-jsh<u$5 %[OOJA>'WI-9c0'+p5<GDmSa8PkE>!hk,$]WP6+(E7^KhN+hQRcl-F1XRjp845?6<^#+dFh7f,6b4#T1qZk-_V"Bjp[oEnC>js0iP %at3\XL7ke0J?5&fb(QiaIOO'LB)-dUn+_"h,C?A>+B?Ee[[PGE4cW.G:6[C`=ln;Y?+=4K]pof=%9i[0'Vf`15I8UPU1B&>&nZ%! %-T<i5-a*7Hfm]NU_'TdaBlT:U*RY>settD8-Ggp!X[nk_2BX>J.##<hV&H]:+K=c51H<P.-<EWn+u_%qWk&8=;f8PY:oJ9\>`IE= %=b<BI4V3d3PEqV:%$bb1Us(i-LS$[+R;I(Fd:COre0\PtFK"AtF?!D1X+HEBT8'S3YV]np1@6i5@=q^Y6BcNFk`L!'7+C]JU9ZVg %^GqWHUi'4sCUmST2uDT:&F\o=Fsn90Y)9L&<)ckY)P!h+9>&pE_2X=Eb@Zd&,l%3WIq0e[`#+3TU-7=R%u(fY*ao/+:o\+2"T+q@ %j*h%^1[6#M"uAZX<Lq9#$f.Td6lfdmd(X9a@Cq4'_K%8sFegH?E'UB4MEnFM.*Opng=g_k-W6.M^?r-l<^cq7,chi\fQFFO@Z\[% %X1:02pd6PZfQqbUSLK-khsMs@f\JL<'I!4C".*-5hE`FnZ,9UoI0l$PTMC'\6UJeg'(irYH9XiIBmh9L)d-a_#GZ;poOq3ZLj5Ml %/b0=#V"#'!W$i-rkA%/U%>Qe1G^%,u7A^9+nku$`;c#9pMU%[&r3k!-<4!ie[X\i/5DWH=]!DZhAIJj^<X`9q:7Oc;N=>l*;abdq %IH+(Nm#=j!d-2CO89IWdMf)F&W1g>6bJL7l]V9q:`t;N^[_f_VlKlcip:CUWZV^^i<@!#Ueo?mMd5=u!SiZe;&J4%h1!^BLY:q@X %C[)usq.6#u&"31_ikKBU]XOMj-:2,nei%`*DG_bJB'UOR<2R9t2/d@0C-:G(gYK;!e>.0JmI!5J<"hE^J#`ee_.<(=4V0oA.+hL! %LDI?1S.:n-61*^QeE`0SJP8>NI+MZ?1/!S"J0\$T*9_Q*Bfn%$eYN>p1jUfY/r,("E%F_q,.itBLB@#tgK;DGdUX'?6X7/OSj<\l %Pd5_h#*QSROF%R:#R2/T8Jrmape6jF.?Pq`N=Z%@VKg-00j,f"i$1Am]f97?D[,,UX'f)k)Fh!_i'P8Y6Y3t#@jjXO#NH@!,2bR_ %(p:Cbo-+tN)MRG[q^*g5X'&_;G@0H"@TcN_SRKQl#o@j'E?3A9Zh!Ne`KtW\SWF<,>k1E/7-$#j`9*LID,3j4gGoI[&/e8idn3M3 %!-49c/:K.q&t0s<bWs6)C.OFg<R/X8;Wg,"%3Y^?O;.bM[4"+Gl:?,e\\&2&VSc\+E8P1;A$*G_22k+/]TZQPj+Q*n41-FO\[,ti %5Da$2:>`JAOh\t0atPtjk1<Q)7aa%c@7Y3ol4Onl4!uC-a&.[%[9`OG<TLaZIpaTkKi#N6B*UYop+t8-A08f@-`Y#mfN"H'aA.Sq %P<;*5*&K_C53/"ZF)+mRO=XF[.YY^]]qa<:Sls!j]4^pSEg9;L:bkZ/RX2%]QlRW=(!M2-B3()\.Z"t6O@mru=F<:]G5KSkHtG9I %`Ep6;9!%QYWr[5P.Q6e78HilKLYqG"k_F#r"r%)RLJ)qZls[qG?-Q#7m$eKl^b_;7^+'4,"kmqJC!S=cO'Z:Y4r]`j9X`@;LQ3B+ %5$Wagp28qi,LMMc!m,/Cp'.22+jOH6$m.$Y^=._MZ(<-6b`9b"g,RMBs2';dR!Oor!C2hKUfSB`Ct!2O;/nBFMYfV=<T2`>&VLVr %4=P/F0mGXl0BOenZgQ\Qie^*OaOkZD2ot/VW4#b2Ps@1C.[+<'5*UPWJEL`=0^@&@L5>\e&5:'O8YjRAc;,(bbQ*#u;l!0^=4)V7 %/?':(X%k6,.FnOP-?E]_28a)C#E@h6hH^md^-qDWj)h8p*Sbi`k=YHVSOV.$3X+4n.jI(K6Pd[hhQ5+O<@fm:JE@@r+]EI5Te\]1 %)>2Z!X6:+SI-oLblLMX83=l3K6h$Ll0cui:a!)C15e/sSSqp3qmLoqC/?)X)"HMZm!2ZNQ8Y"D>^f#kA<=WRXm[6gBi43aM)+%[B %n3kPhHc0fUrD;EfEA7k(8js.$'dQCsV6^Z>[Me(g\[=^\L^5)g]*7lIG0=J#2\bh&rL!K^Og-VW`U.#"`BtQ[g_=;A<LX+<5IcT+ %)cHfR&]5K_QFYCEl>i+fn,_Q.jcBplcghB4JpOqm@'@LDHbJWlB%90[E`-Z2(4=X/W>mfIAMVQ411=[.6<%,Hhc*bH1Ca%(FJir4 %>/AF:]b9'FHu:_C+.41VAJpY#%i;1hUuTD)"o:KJTd>NoaeZOWp-"KF.h+BafHsER*>):NAcTfD@!%oJ=O"EshI$%i;@q5Tdsf%] %j*@gX>q[6#"%aODJ,uE1?ENc?MS78]e&h&55.&?QjnR>aAis"s\UNuD7n-$)`b^$*Ei$L_8Mc!FMsMc1g8aG^Z:kRdA=,CjMUmM- %cb@@EWA(7.P:Aa86Nf`%!m?D^hM\0ad*1;j8^p\N107Qa[Xj9!TdDWR<a\L!^06fZ[8UNF$g(hj=<8\F),IQ_`fT>M\5W,dZ:I=# %ls%PlL?/X21_m<r"*!rbKKbpnBEE(Pq:)_9;<$dA]Q[u='pk$7%r3GnC`J3KWdVM7?@F)t`oql/*M(XM\<!gQl!i$b$S+<;MD`hY %,;Ed?#OfVd._/(\7`)WqWRRO_aM%TarVsf"$+1ClI&Y6g2O617!@ne4-09Pa*\LENBK?B7S!O:H."XgDe[AcGoRd!o?0cW1Q$3G@ %)G<+*MTH^q&\E8];bD@ej46Nt#6`ZpENk2GLmDGbOSe#k$PS=2f"8X--6C)=;TuD%ZHF@*LBYs'HtKS+-DZ>^QikX0OJ64!'&\G* %'h\SM%!hsO,363RFBJ>m,,(5VbaA9!Bir;L[%EqD=k)':RY16YRQ0qmF3$$COl$8CYhid9'c,oNo.$SkLO)KboC%i6a@@0<I*jpm %N<Q<qhg3A(5'R!3b9_n*ml?V^D%I(R(9/pQ3QVNC6[%F615:psc7%*WE8;aFfmXUegCQQ-.E6RDH;6'fW5o096$i_h]=?9d3o.0: %@1g;F41.*Z$JS"]F>f[9Cd`9)JH,ko"jd4&!`dS!Jis5*R3e%3>'F.E<`@kkK^Due*HRq/#^Ek:!LAP0!-j/jZk("\JMY_$q]^K? %C)"^c&C;uOAc%1qE*/@k[ir$m'dhSp^5feZRso@g>gIRXE4V3`Dma?2gSX;U<O__XXJ;k0<;4tjdo;'W^H!M0OgXf1p'ImlC_AYG %ObbhbNe:&Q'D<[k,N)tdWDYW,C75JunNs"K$fo[u=B%Eg[Sj7l"!'V2S['kGmh,?*R')WA4W3S,#WtA35d<\!$;U2Aa#1+SWb`@C %&Bu/Sfe[AZo-h(l6ASK]VsM[?M_24U'IT2O.m6Fq)+<GJ_E*4YK_QEP%YNKo!g2$@Gd*ATdl&&E@#Mo_ok.!(;D/a=\%k;>b2>p] %$"BK?apZ;N(J/mWea2;".oi3ZCJgAR4\>Z9*FK&#,VgM$6q47Z>T7d&6#hrGZVUu?USdT]LFb<0&[.`jG6O[fo4"pAQtEFF1u\(p %eb!t6*@P)WXpDM^U1%)Rmp1!dg;(+$N`0S/W)BjcrN'^,-GJKhp*9TJRiIWMM0]aA;S_^-,]2Ub<=&5:;m4e?=d$CT"J!d9fhU4j %Z2C$cj_KLoGoZQXR%c:Uf+d45OUsLJ[%[t"l9N^BZkp-DG$5/0PgQ%!qS9Uu=!:7rlGK1qE#L^7TrGOW[9W'?d'r9a+Gu"KJ(>TO %A."?[E)Bs*P*[=.A^D%ZS,UeSJUWcLePm22f3k2meuhh"R]>hR<3oNQL[],j"tQ,%igPC1ES&/m->Xt):*Ymh,C9n"=ehQ2#ZI(l %[2)cn:A%_J-kf4F).67la,6g7A'PcgHkD5\8ghO8KTd2S<u6R&Q<i"55C3SZ2B+[lrW[aYL!D$S-0A44JUr+E,Y@C'0$jV&0=5T+ %oFZc^A+qG264pXf8;'umYm5A:,B2i*Yif4a+G?A&CDf=J:.Em1EtE:63t@rcd9mY!,o;i1ChB>(1Xk?#(d+/h2ODlY+;_$6%V7?F %XAB)qq\[V_b(K`sX8,;I6b<g6+An73#U?MU^(\_.U4.t:/l7V$,aj'1dWd\ln7nc@+g)RjHC/sn8JcE8m4@nRid<_Vq9kXKMgT9o %VMWR>\lBW<<9Ihf=u=a$;tcNHMaEN0"Vk6#B9YTajdo3VLDMq5aA<<^Vu38W(WJ'R)J<`/7%c%U)@lVrXFA_7Ad((pZ,">2ZiI<h %AhtV3E9(OP;^VR+T-SEk:cD!/l)YI*$2k/E;m;\%$oE5b&AEt.I`<N+RZO#`541.!*P3ESqs$e,PaOL\QK'St7Kjr=I(JA\'STOk %BTLVT#%,"Pd(sn8fG9-Z]0i_<XL%3?L@B]p;8gMHniO,%g<Z5)jQM;%"klq@2%0^poS]BG@[St7nI$\8A!^e7ETX5as"JNXBM';_ %H_n][JFBA$a0cNB7NV;'Nt].p,-qX:Z<&WTPe:!@I#(bMDXEiC4\[=]A+Ym\(jR$e<$:&PQR5ch-!-DG!F\hsid1n>:j'lE3)SYa %s&j<(.0cTQYV4M6FWtN%`Thu*(4aF92Pn&oT8'e)P@q/^VRl1:XE9CDF`A5;M(?RR&bU-Xa>loQSuQW[PjY9L!S7YA'sVOB0a/2G %*77rS6\esDln+E/_!!#D0j[>L_-IgM"3uNkES1qY9GKTk@$@Uj'F&>?0juI%N?YtcHWR=Bk9B;bJ3.Tq!0<ag:27pL()_th:d/F= %XR_F.M.IDX2I4@["^ANga0cL,6Y"nMqV94!IhH36;Heh>Q?.]R1^K(S/o&$#+m`0aS=;h@aLlnhCnd;sc%tu().=JlWZf@C9G#'F %70u_hV4WGh]Z2_`Y%$Oka2Eis&`9E,"QJqb-gB3V=r)pOf^(akrXH2,%L%1]EGh$gg]fN&/jEYU]hN6Bqi.Em%TMS0@735:Xtda' %ocmWJ5"<bmZAIRW`onWloP%r98P6boOpuq`E5b"dA3qEK(%rh2^+X;)LBg>o79_.d7#Wr2'FZ8B`Pe4i\Nn*>"DJu"569Ma_E*9, %!o$[nLfPUA@D]/_.2W^Z<Br!u[&:sPnYX_T5H-.0Z#?@'7k?2\*Kk2&g<jWTFH!Z6VKegA=2eAkLd&(Bj'<@#8SOlQ)\FEYcnL8@ %62,K`d0r=C=Q_[5Cp%&s492[\4(kKa/'^mJqa[44C#f`1rJOC%*E!825)`H^?8a&JoFpS0Vh.(BXsh\u@&`PA?rLp&?Q:PQ\F1WG %7Q;`#X0srkQR(s12"bs14?E<tC4uaTT@pL>[N^L]mYH.Cn#nLf6SCPrPIHA-KttL?E@M%PB0iNQYW*UZJsWd5=,*3B^OSCpinXFr %LiR_OKD`PC<M>o2hI13J?;.8_<960DM-c?3dsb5k4%$DDn,^n4'lCK5;bU3@oO_kNW\31R'&4Kmn!^iXROXX`_d3a.6Z%?)9\Z(D %MLM=I&5m(@L^[30IeGcA(*]7di:b$$5]qg^#SrhXo_AXqfK_KHZH6I3D%YrN#"XCb&1d7=-r:M>"N_u\G3$CnK/'Ng1fn2aN=/Q* %r>-0N]6J*.rGbnG?PS^>[_b-5^G[W18-bM:qTKl7lH*j(D88Frc]!K.WU^j^7'>DimEO^7I"mlg61s=KDKX?50^J5^212b0>afAp %AW:(p.R-A('O(5R7D%Pg7AKhQT5LfAjD\N^ZiUA4&\H`Sac6L`%8j<U="qZ8r5bm4`]`JRluMe'<BYujPA>c32=VqqVsA,t/EM0? %'p0MijkpWH#.),*%P!64Q$tIe7j3l2GpAVD>N&1H4:!"^:)aqTP14fr?sJ;[0+c<%V(laSOhffn\G"@ocOA:`_F',*&kO48>@C0l %'"0YiX!H@<:td^B,1oGXA`k+fTqKdUO%Iu<5S==L[CP\'=GHWjaG88aKAGc'3sL6<7;5c16S$e5TeQSgD'a_mTkpbbW":?/pYg^$ %C#u=lT@oN5O-fZt8Oo&E&\qm?;JjCt\]I_Qi(/Ab6LD]:o/4T=8T`&MN/,^FAG)XrFie=F!,#:sXu?@mX.9:8WemdV?WA)p[4<l1 %mLR*5`DoE.!G^>Y?u+8_\[IEu\?=]Ddgll*Wp!^`/nXe[C39"t;:=#*#M'FC6u#,(KZs?=a?$RQ2pt0_:G;%0=^:q3Qk_>!Q>X!j %OlCK98RMas1=8Itl=Y-(%$9F-;"!T^e.oDZ_.'37"hDL9bpkbuo.q%5.iUchXu^2`AHnaP\&F%f;8O:K!)R_;_qd,.-0PNdDDKBb %E*,2[L.?;rZC7L);cE0$'/in'j!+#B^g_LrU:m8$o-u=V[E;CgA;>oR'bb%X.]i+WD6BDWp[^0K/X`)"\?j=9(U10uCMLM3RA]"E %`#CgNSnj>PNS'Bq\[k+,OY!Im?`F;PRF\R0S*H!%0K/)1:a9]Eb)DLqYb'&X")=^R$.tWWZ"4,fF6J`:M(Kj^2Y,5D&'V,N^0[%B %`Mg.E'4Z)YG8/hE@@i^8/1WZi7RrhRb;tKR#*<d;,q.!GX(qPf\f7,Z3BGe`b+7$"_P[2!f73\GVRDKp\F#1FLe8R""\?3XMeMMr %*QPfM1U%C\rQJBD>1b?H9PKq+m'I7t`%@?QRHTtOCFLi+fJ,\l=6k,o@%dX[MSOdLRXB?cGt"%[eBSlgd2@s]-Am;QFR(8sqZbpN %>(D%-*MX?U!HBD@f-o]6#ImVV*Mm+hqiT]uo`eHn1,:&]eKk6A.2Z(+,`E`V3]XE+%i'!s]'E'qN`egUs3nAs+c]?u/ZSYjf2CIi %$e_ao+jE_R4_n<.da+d#2XGT*Sd+DKl4D>4],R]hbj%t7%[,.<CjG=47i"e^54f4-[1QSV'KMk?7o&,W[V9Kf/6&B]?+JtaiTt?4 %N\2gpibtQ):F\m&HCq"O;CR_+kbfFHRO]Zq\`A&[V6A^gbNM#Q\+]Jp2att8eXRpCP?%.4eeT!')ERbX.?`5>?qNpUD-_)DaOpnu %1O]u[/3Gc9TZ!:2<R<I3iRcFc/h*&*0uKF]n20\%E2Za;8t':E!&in/8!cBV=e1l1.b,-PAL1,Ha>KPMP`]+aO92(SQ:VZY-L?0F %kslLXQC`\(%%5ne+cDiA_Ipa`.2oqAN_`MuiKS0]a.14?TN!i<'&=F1/gQkB"-]hR(*q@;k%7n+W+e4i;F%N5/[U`d9%4'9m5+oe %<ke_t*n$.@>ufpB-ShdKZFeIahqLr.K.7R88]/F=#BUA]!7q2]=QJkLga$R+e2AN7NX,oa#_pu'Mc-6J''F3G*`qI"]aeY,j2a0$ %Rgs1Tf;^__eA(%`ZKOQjZVh<>3b:?heVp`-i[2EY(DI]$WfS/\qjFFE4$&V6U'0)H$n]=ULQT'OLFGbT+Yl1GaS>D.(HH8g-HE<0 %e[)87r2Nah*L2gUd\%`g%2Nt^iX"g$Ls##m-'>76g()2(Km3cA4K.9%jq;C()`ttV3VW2PZQ467\<k<P;9oFb$Z!#;G?%d'C0Rcd %%qd^7!TtEILYL3A,L8+fApJF`_Z3%46RbXPf%]ajaCtLN0h7.l\<*GaLCDt#lNGm,Vfib!k;a7NA1H6m)o1N<M[Ob%?2`"FL,oRp %K?h(/1Q8Spc,U$K!s(ri\..@uFDbrND1S@\%)>GcT6(,%]?"#Hrp+EHP;*Puld,eoA[TDm>+@"UaV\2dI3g>c[U$$f%6e[7fG;A! %GbS?k#'a!J#ITuT(j^nGQ"tkQPhQ7Vgbl^$j"$>=[W^gU,,+*MN"2u@-lS%4%G`br0Ns&"eeud5j%l;#YT@9GMh35r)cG:lAeO;e %2tQ,r2-f>rNQGCo*tC2KM$b4W&A%qe/NMbH"2k8$3*bFXNEF.ejq+DnE/7Op,hi/YgmIT.JQ6JeHA&HQ4*!RRXfe<cmkuHaB(%oS %/\n9,*ss\W9Pt)>)$:@^J))ETORE?__s\YF@]aln`H2<#]7G8Uo^u&R6uG7BkAjb2`fU>nla57WgDCPGk_:R=$i?1Uq\@R.RB7FP %G,L(P<Nfl1%W186e-'&qVEodT(`Y#l3ng[:'\A/9b,UC[?*AILESQ2H_:7bOTJ`Zk8Tdjdi-FM^,B09_5iGLLi3_-+&](1=2l%Aj %m\.d\+N&t1<kK<Sm7-B3E7lFi($H-#\;?,hV4$@u.or4dl5Y_s6*t8B.-tYR8[EfUj;J/(V8STYDIqekeF@7iFbA52;PWlXLPpLE %NKFZJ3Okh%1bCSFl!FCgogBQ$fNp9uMGoVA.FJ#/f4Nt5Js&:7!A0F?:9uP#7>a6og,\rL+`V+H)57Grd/_q7W'6Tto",-MO7Ni` %Ndf2>d1,I227XouP19qBbZrme9>bVJ?H8i=BbCYM9*!,EVVOJo:(`R,MdI6FqPVI3BuWV9P\ml\,aqmb"cL/BF442ms"88a&=b(" %_mgog)9*8EH6dF![*CC;ocLU:+9T'k0f[.`GZJ!f]3Z2emD[+m3%pdOCT:'Y9n<Pgr^7]Sq2"i3OPoFe4#"E*]I?BLhAB4(6Ea6K %CDr(W<8S&\c'l[p*pdo4?lEUI3>"T"7caVJ@32/]>WC#!fitu5Aht)NPp)8G$ikt`9:Zg\O\k9R,6P7nCB7MU=]45(inO.AdXdZW %&:em"9iPIn1AjYE5!#Pqg.4PHR`<W?;nH;!0C+acIB+b6)'au$MWF3Je(+P3;9]je/a&i'qYkuuhJC6@/@uDhK)CE$@R(XC_Wi)T %ak(jC&:t=U75J?X7cB4_BJ9^[,#e!gqi#-i^!F5d2DYD$!L<EGf^3Ed1ZfN*]*+irTbkd\@iYI8cE.^V94m10l&Ap)IKj*5P]qiC %@[TY)RX0L7(WNL#30coK`fs?/%;tM:M]E@18&a:Z<mAN3eHh*VCq#d_`/ldD.)i.)AHJ@Lj:k,Ida=]:p`M/Bq\iu.2g#hj@.\Y: %3Q*)>Rp0gGq:W$YndtXUCQi;AZl2kN&i+.2D<'2L=q#-]m8Bn=+m^(\1NHXG;Yrl6&jF1j*,![41N#AQ].qMu*mPB!L:^H*2.N?\ %Tq%'e=A#]OF""C`NE[O*$B461Y;;IP]^lE_O\g.=bN1A@DIo(<j7B(H-L_/3O'U%7bSV[cefp8"dC2p!0=b;T#pMetqh4Orcthc1 %lebf-QI0^8fT99DPW`ChbUVF[#Q_K3TY5p-2>,co(GJjhd57c;=:E8J]a+e>BgrH]Z>&iu,$`bU3sq'e?"puh+hC7>T/Sh5j8d&) %+HV6".SDVe0-0ep1][mUO="=iXUTe=L0mW.%p0D%a@0kX]LWP2Y%G-*_STc_R1baTBm+Le!-nZ7&BqA@:X'LK/t&XtPO]D2=$/<o %!)N,#4UkU#5B?@im1gH*kI,1a.7QJRi\qNf[L(9bTpd&_\QD)+G3(89NQ1EO28A'ca:pGldY58&i";Fe"0dM'J7"!liWV]3Z9g:> %`DuS8n2sbUc(I,Xa?;F9Q8363^$-*Ok><PCMG("LMG!Q@f=mL8fM82Z<TC`-8m<*9]1FnoU"FD,f$s#cS.(1/H*SaUM<3OR;GHcb %Q=+c2+>eoW@-Ed5"_2-@3`T`h0a)_rf3G=>`=h"ABgrbN?X*^nXGFpl\:t-9@m/!%XOK;^'ipcc[Vi#&:LA`dp@^@bTH5MnKF2)o %4c256l%16`N9=!eP?&F3J6/#4pKDc;@#5c\T.qKk#jaAF>uRP&0AZ8s*"?'$BlQmL;%S"EAOW^MgIa7/dd/68,VuCt\4I"18&'G5 %aE+u6an2s;!hi]t6FIr>7M`s\Yq)OOWQNa8*J&R-GqT_Tj&oJk\M[U=lSir.="$%,,`k[-&esVgT.i*:3YPW9\p<MD$kF8Ofu-iQ %7*2?"@ULLV$rf,/p2;MS_aKPk/=p.drpFbehG$OKXRnc2CQ2G]'tjM\j.C)XbOQ)nGk;@7gdPRB/!3I]b;`b3d3f#HZIhUM?k\)l %"\o4lFXloKg9r]BZ05bO^K-$NQP$,_28YYSi?_b9;TuhVc*%WSel[O!_\q119$^m"AMCX9d/HbQQ]VZ1fnWrRk$h2tSBH6Vc=VQe %q9!2Q(,j;)#2Mu,ho0<_XNd3#'_04[<=DX?h(:E;OTYcHoaa=n5938Yb,MM=P,ohQ&cdD`'`-o4-bi$=0L[D"jNtU6e!G)aR#Y1X %irR^6\=GWYKkXY9>e05Z;pJ!a]F+m\4,rpR89?d+="/j:K\HO8q.,8eg"bTj\mb"-c+KPJ6;QR>^WPo.Zq6OKfBe9iT$+ofl92rr %RVMT4c8UtF@A5#rA%rnYlT*"s\B)eA3LT%V`=853M;^Ep4pbgMLhHODVW>tnimXb!3j(FDb"N*XGA0e":,4tN<*J3eD@i*d`X,!I %#$\?_QYuXl.W7cP/8GE/kq1:`<.F645aUH&2IXp7=[Ui(6V?!cLpWZBT@(a\<b.tu=UEH\E_<L/A.9.V!jTkjC;n/<S^H]SjUj49 %FCuM/;iG1.V\>hY<!p=t,2)YKU9+-LnJ?r#3G+_.p*eO8nW-j0"-2YVQ:7]Ej!gPDRsHZ<Dbl-aTgrK?]]itC[%WXL@[,DnKp,mb %U2O#%^c_1[]`ae>la<(nQ@b&!"l$J\C$7_h0S![_)WIuKp.(lQTQ#p]S2[=Q'<it-[MikoQ.Bp(bY(Y:g*E8><D+Elrkb+JO38;_ %`,-D%KZ,$slSnR0"p&$(.V&l;6<NC?)aeO*dsd="\J"+"^uVhhHRU)T]W59a?IB5rbQ>"DWtoRbmD;hXV6U4Os.MT4E<6hqEK287 %ChP=#LZk"G73e/B:Z@>9niObo=GQD$9:sJ"Y-("in7gjc@lYFF?[5F*U_LP%ZmM"=^""WA5p@RbMH>%Z;&Yu9*_k99;p"a.%0Dt; %,41^nhC+.jFD&eYO5@lnYs?cC6EInA_5;coWZ.7R@RQRoSA99&ER2r['@M<,A)3rI[LNT2Oo%kq>KD^l@MntK",khhEJV0CEi*k% %8:!25IRtaFmac-S]#JkdD(U8R6M4,5#SC!T7MG/E4N8Y$K;Y<PAUZk+ZN@<18nGH`_^L,i79Z3%;h:qUZ45L:T;Wl-f2"ND>5KJ' %!D,dAZ78!DC;psj)a/nX6rk-CQr))hU70=Mi#$!9pg:9lnVSfY_(97OCcK@9PG!<ER<Re=W4E#M[l]W36Z5"R7kG%M#r3uTc.Q!r %=lENT/)[+oJg9N@$p8L+TtJDkY:n.El\ePLV9$-U-\HEH7pjW#fja;d=c.r6!-XT%:kd<3UFWVtl*-6M[PLV:I&20uW.c`'qu[c> %=^PZ;M,\L+o/p0IL5?stgUs8;@jc%$L\nHdap?Y;ptNJ,Oof(dN^ud$3Y.*78XNgel'O*KX!0hLp4Gfk?-n<M8d$+"d(M9lXWN"1 %&uf$VF=S?N:2&3YO`Ad%r8uW9TQY+pa)?0RZ;,BLp.+(f,rrB7#ar(^YY@RLK"r4sVRA46.'4q'.!>CGK`sJmD^tW76U;F,'nHu` %me#'4:!-,<%RB\(a:+4\Og^Y*Z9jd(bpEuu\?m?H3fJ/UJHVEM<_H;RQZfup&3c6GBdS476HctSBLHe15WWEZ82/IW+HdkmftX9u %W`C.2;lp79Fd`AhL-d:M@:!8MVPL^2[d>O_`qYuqa=Gag?,Wq"\khUq'3-khd?2LVLYsoLn%C*7dO4dl=CNOIJlX]r3UeVh:T.U_ %Z]u:'TufY+_5V5R$<F-.WKQq@f"6(D-h9'lIYAWW@dO/B_YaU5;D_#_^^Wi#7]NNldr4tKUKi&6dj2JgXlfub+m%)dEq'c08ku7m %N-QZDU>00(bV:+ZUXL\gdtX"%V#Z!S/gR4_bUdi(Lr#b+]cZT2-$]hGQB[=`V,u#`R7N(]XIs+Kn@gSeTFX:pf.>QM%<q,khj[5h %hC&YgQhX5,"[u2MZG+R!#`Jd#hu]4o2#T4VTG+Bl;f2nG,)<T6L9hap@tE$lRj_2CjhRR4"5(!!&EL6q:V#hd"_Ipl(+#8cJ68M3 %V]P&2$+kD4*MareU#nKd$QK\S=#`+28hlP,;L3,a&@n3hIu3gmV<,FWb5cr.1PrF;g^Q]OPNk"rC;<uV0/1CC'@X^k+5k&,F.*9Z %Kg5a1LU'*n#kTH$*triVoF%MeW%q-)8rRfC+'$7H]O308$k-3P#>G[A0G=i$ds.Gh:":$R?GM;UVI;2E1H_^oQ5hd"Yb8%A7=T"1 %FNf"Elq4sEK5/P?H"jfB,nsMph&DHU@3]>9[D%!q^_Z7D(98_&^DFZ@$!!G]5,Uu!o?liVeKer)W_Ya_\RD\:91QSi+mO/c,T-': %4#kRDb1pU.)2'&F(/Br[3SXZQIHN+\/e_?WV)Car:(fW$KHU/@hTr6C!r#H*9&#_M#$)*ILS?=;2?c([<URm<gREj,SShmJI&]O) %V5:qk'7bPNAE8ZXG-B"R2A_oq<oJ/9bZW(eph+[edDJ-MFH>pROT)=AbWc_"GT)Z(E%.qn9^+aZY$DHBW^7TorjXWLYGJ+N;(Q/] %oFG1l$_-Ve#\,AE:5uk4ml8EpB7],ihYE_=^%YYmIE(r^#5fg;H%HB'<V/:91c#G.*\mrH8P",$X`,r\r2%IuHjr-Q(YN+fP4kEO %]s,4J\(i8o;b!p>]$JM_IrEIiDT,stW:4PcorMRsE#i(X<a8i`R6lP!V&.apqeQm,XeAUo$WJB7=,gG3*-@Oh_&%Yh2+:-cRTdb\ %6MTAP$_5[mQ^*rNFB9V3!YVJ!+pIUOj$F<b:<dgh6`bLq+nG1S;YSV\?]*"$GMl_">5Ar!ZOY9f%.k/=acbUh.7"fcU:Y_8J+"<A %VDt[.9NbEuJJs$>W'reC1ItOEfO5EiQg@lkS`fgO'edG-)>IK:>m6]/\>H"Q4O<J"B![pC!t8&&^P%#=a^<`S>PZ]sjd]-;Pn:Hu %UuW\I/MNW_Op=4aVo+N*0$tr:)$7X4'!o%OrCZjTN]ODL>%ueOX@aIQ@.A*>kd^X[<"Heus,>7FkO2\3%SP6hPsj7?WcZR']fIhW %cuZ?`-Z[;6iiEdbDW_o<Df/7W-EItc8?IL"LL>0L1#4RigU5X6K3'&'X'7&O8S&u.4>n_!pUqi%bXtM9d56KA+&aHmC+4lG%&BtL %898>pH89^5Xnf@QG7>E(H+!"-ATE+ge4pJN.Be8:SE]rnf1<U"B6<CG9P`<_=Vk"jJt<7,1EknaW?jhO/Ou&1`g/2F9m;]1:47YX %%@_B<eJ:,50X5OMU"UMG&GuZ"r@B?TQ=O^aYl+>.[0*%5d9s=9quc%&>*@M!l=/'s/r>4X34.llCihufpGVtd9H%i;R1l3qP/Rc/ %3"R@"3Al5_Lu0<1E'Q#RR+pCnif($:eeJ".D=O2Jdd/AmL!;WR=TB4Y/4s1tcBoG&-JO6O7IMQUq4t<s9p*^N(8TY(Ki:+T4i<#W %MVj%h!S8,VZGB8O#gm41<ei,]8-9qu\LU_V"_`28gg\TR=#+sJ-(p1T%0$*3_:5A`]g^(-;)^m3KIRu`"2()a1Rf0SE3$&78ST6F %$IZOI.*a7$0\;)!-]5qkM0JdE(bfo1i@2,NNYn:X+uUPX.\II]6W\r'HEDL6U"qsG^O/!6U?VN@:](.7(J8qF-%XSbc7LBn]=s>Q %<HDlh)iE!K;K.kLXErl#Z),AFLim*>G!iP6]st-Z'ZHlQF^,P)_;UCnUR%]P6HNg'Iujl2RA:m5+#$]pem>g#?'Y2:0&A"<I8*2Y %T>'dF=J&,U0F2%-!d<(ITp^\g$FU*TE,I8<C\-P1+YR8n)Ai?VS-#l3$,teDqi(/(!_RD^&Qko-P/Oj6Tr+f@obiua+Lt,8n6&Ts %3&`Mu0X*5gKAI&RX0I;"ld!F]TZN@MICP$FIcdc[4sQP2CDrq>r>K-=CVbfq$o:50OG'TnQJ($E#6,Mphr9<pAD=Z:BR'[`8):L$ %XC72sJ_pl)cR:ZRkqj9Y6Esd(c[_Z^PKd^R2?o@KO`I."9Oaq!##KCcW^*,SbSGR%``n@Lqn:^N74':4FS1SIY1:d(jlU$,V-:dm %c*\S!";E:[!HH##JI^+#f^]U_2K'Z-2FpS]Bj&kjW_%dNrcka=OY7,&T.4k+fST*7W:@]7grWT@lSupToVc@AEiEA0nnP@(a^;p, %ii9fJiHK\sPu1pJ6e0%f"keu)1/nbKa\A*n*2fGB#5LBj(d6K4!:SJQA8-"\Hl=T&RP"pY#R[lOc!X#*7:hmZL]h.Sj-h,$)RgOm %iV3\c(fint4CM(!I,h?F4sOuKj<i>'X<h&/@9=A^LaB[PL_PEM2A!r9gDKrU.?O>6GmZp=F[V/89e.!A"?.RWq5WK9E%WX&%,qdg %11>I099_rnV8W41:"hSn$,a9*#OOE:/24d>1p4&e&5V<4Ieh,jS,I46962J29X\7pD!]!6)e%uK0_QD_S\q95fGUroOskoK90<A$ %"=0Xio:0G>U;?l&=N'Vr$R84VR<(N,YDFP3X!$D!LfQepaK(boB%c.u3r:fS;R]R?T)g-:%.2W!!IF^g>Dmo!Vm6RT6#-(57N"o% %)"C/G3o=*P$a3Ulp?G,G;l*7A[rVmMVNdk'.Vn^d(iZ..#J[?Bj0Q?Y#p)gpf=D+bM>k*-:hS2(<[ct@'t$?"Nc^NNLfBA[5bfK[ %%=8OeK@eG^2;0G=.-ja\DTLtRhaRk&gXB]W0b(9-YoV327*S,.es^6I9/rZXRKXoHSpE=`)l>25ZA)ZYE_/Sb;&UBmSLS(VAQ+Q! %,,#@(*;4%/MV@6RDs1K%$$Q%S&bOO2hAY_oHBV?4G=[/"LNS5(3^S<A[m4"k1oZpS_m<?AVC3s?cH43R\^BV;<Mr,JL73fsTYHD- %RQcdljd9Y<hK^oL0F-b#2Z[@F@7A6XM;]#Tl]0uFB7RCVb?^7hqtc^^Rsdb0dPsUK0!7JuVY,YsKh,'&%TR5TbrFFX(Y<_g/,4S* %%:ZD`:!C\cl:E+04^tSe7;sG0!585D`^hN!@Q#CJJP]^_?6/`l&_`OL.Wt8%BJ_]M/L5[M^@TohT+I-dh@$f3_P,ILG@bKfEMLXj %*f>RRU4fkoA_?19U7KDc7\OJamSVi;BqrT:VTk)EX`4/a3T!Wk?C68!;o089Y+\US<\J/j<pPt?R\=D$Hj2I&QZQQ>=4-nXhV.>j %CILue_[ni\%PGU@B8R1]\BaofKNGid":)8orqgocECNs+Y`E^/'Hq$d]kFsE2qt)WLjmVu!joS-2-p[Lm*JJ0Rbjl3G#X%*Wh?kk %R:Zf-T[$Rag't0ELuIZ$IP'c=Kn(%F/>A.Voa!$!@Fie;>a)V[@^%3,T(:dpAs@@(A-7rY[i&[=[EGcGE0UIjr6@;-Q"552RrRtZ %#S_D#CJir98CruF[E<EHEJArVl&mGCc9Nitd0b"lhtbqr*2\SE$2VTk,:2k9k=$K_m2?oJano1L(pka=Fj?s9ZhCkD]rTj;+N9.- %Ik;!_P3cD0g)L,d3)N8M).R\(+n-nb?";h`Lo<rtO!-bq_`]E^"6A%;SWP1pHM5O+hE9"X7)u<[<(QSi9VP"<8^Xfsp![k=Uj]fP %PnTsnNdIHg<0X0fZLaA11%nu7K&T$3k+'KoFbVks5V).Cf-.rd4sUK+iWiLQk"7Kb@9ub!6`VD@^]N4:=sj(pcU9p`ZN`>s/NW`R %]l_F]V!&kghk<0F_b3)J6C,AN'F18(cmLqd3gckO4@rquODQ?]3[%k<$Bu6N]C$E&q\ZfD,IX+ZDfY0$H"o=1,.Ui&086g+.Hmk+ %4dFaq(99e[JUUqQ2[$>bEktAt.PMS'LS5n.6B`TLk3h371%)(nF_5-FA=,OVLS86D%KVotB!nYA`C+*qZ%s_^$$QuP!kO8SgRmKW %>BMVQ%=@E::P8_K",TS4L$O\V#4m[?86cQF+G5M&c!p.[8+[atP$I41)BAus.Umj$`\DZR\:-mDnKH%-Q7I]<PuLRFZScH!E'e,m %-Vm)C5UrET_?S-lEs=.(%ISbDLa/H]o9dR^X)!X8nWCDAQPmKD;5[\&.m\XpR=N;%.C7Bd"*0]%S)b4N<HW!fbR?I7YK_CZUecX` %3H&q=]WB?@,f27_8P-H[0&-`4UTb%2PUR4;*6"KdQkik<'H(<0BdFK,fQV7a76qhN+!Zkd6HHQ3h"aO'KV/g.LDr;),Vk!ZDDlLA %/&6dZ?k`iR6Bm;"Fs(bW&UB*L#`04s/j]<JH9E7bUU/+X>/:L%"nG;'$nqg?2DF_T>[Jh/[QV<t)@@<pS6[dbHg@Zg)sXMjdL(>l %h:*.U7(et8V@2@]PtnAjb]%GE5AZT\<pKjPL@>P]Ch[3)G$Y;aE>Kc:a,O^e/4JW?:C>s15nd00Jo:[q6@H'@E!3"S(mdXTdPPJ: %=06r%L"#R&k06<<ZInA@=V#]f3C$,r`*#oNS<oGd<O?:MEHMVJ"r2;(/DBk<VskHYm'T]/kbq:1<i\O+o[WPn/dd*"=abZ/'uuW) %QN6(cP.]aiEAnISh-HM%QijcJb&T.q?H+0+<1=,*40<^5ajXJUhI+>9G7/K!%uDGJB0jC&,@32%;OG^!A&5juUhRMXr<m;;+&*0d %A3kY'QICM3F$FNZ9G?A46m'uNFO&noZS'h.d@I3/TZp+HQ>,L2G\u&:07>%99CDL>a-Z+FH\oo+bt9loks]CufPG!0@4=HO/ebcp %;fbj2]^gCaYfW')@U<eaM9I#EBMnU8=Q#ZX]U=19N$msD"P?P1ZIUHPi!9OOP?VChLe9K=q8d4#<\_luPYgt'7@)UrX.-p)?Zcie %/)]j^2"WY$!2M-8>O7HFfRs'W='u[CS@oiWeng5X2X@K/IW#3(]?QSmB@'':`MQZsUaiAZMu_ue.'7_<ULnZhF9Z#IWt$l;g:/1r %F^QmGNiaX;j>>$lW(W#K'MHOMS]h/s.U4`lae@]m/4#>5(3JH\Z:1e+U6FjP?gM!>JfYp4Q/Yu>C<8GZ&?B`30s6s79K*%L"oomU %/iq76_r-=+D(Ar:[5q+lbam2k]Jo/YK0BmN-M5&lB4Hpl4,HNNWlPo-hS`tZW6\Vb"hPYni'(V0;R;`"!P1#dMWm0(e&'J-]84'^ %VIJ)MV1A0#/]>nGZ\qA$l7SgCI^7+%-7<tfjK]`e\uZY)0'WMBZI6!;qd(l(qJ4;24He4s"L?13,>,ON-Vs6E*?E)j!uA>J*hiPY %1t(gL?5rRg7DD&J%Yk9OB#I^4*'L)h>K#&3GU*8Jno?S!ZAV>>^BZ0rGlT(VM\/Lb\o]e=$B]X.,fjOR)C!Da_(<SA6I!.p^,5R^ %$'$F$f,Qs@fT27g6"@`&K<[1CCQ58-M-el<GamRH?![$%cD`4lJCh@833G0aW0,7p<u$k_j/TCMm"&s,Y[+*X.FC/Z9mc3(h]J*' %`e^#k885@(Sq)@9XBAZ\RP`H(R:ZQtV^aa_98\S$Q=Po<R4d[R!a.&_eP%(t@shtX0He6WIB[)`\W^E"JYBd/X^Z6!=,g+'Q8L'7 %b+',k`6gJpQ?\B2c+8cF"Nf2-/b]k!7Bmbi,o`i4!\\LkYdH1O\O6m:p_@(G+;+j#<";&_g@r!PD\9>5T)rD=9Q"\U+hTn0_\$.\ %J5J8'd)@C4,rVCL%>gNd6P?&7WNNG7&uc`XMO%]1J'!1a+#.L?#Rmam*@]$2=P@(PVZ:GQ3K>ggq%dG*F'#81_41ueCYSKNj]h-u %Kh8_-2A5fOP,ZCYY<#0V<3$?[mOQ'oq+<BL**O@q'CP^GAldZNa#,lBa:n7#[^V:nrFlML(cFXP/#(s`@.MO`,jVnKd0J\5`7--B %k>c'Se5eB-&lS>j_jY?h0Xnh*NdWLFl!h1LbT1L2`RNBS%n/C(_-RX60$q;]G+&PWa;pb)+1^U^U1EXtb8$'rA/e\iN5D%^^ths) %KnQLf#+gEJ<TFQB\JUO<(>03[.Dj^l/Hqc"IR2Q-qqA-\55P3hC-se_lI=TVXOocK%4uL?Jt!uR>hZbSCOsX.L8qV#A]prEB@`>W %C2oH+.Nrlfd>c#m.7W4"S%AYI`?jguUoIML(?%<87K`;u':D1SMooMOcYkF_jsBQ]AAk)q<D2[JmNAYQBQb)GefpD[3kpM8U:..O %OnU$cT%3?^.DhZ!Cj[rAs5'ha9<2HM@0*Bm#N'Ak%jBtd4O3LZ>1>?@>;#m&3/OYqAsJ:QBS1$=;N#+5E(I@SIC'MM;>s/A*XhUa %@&VF?#kEb4mJt*(7NLoI`>!s6$.$Sd'mGC[MMh&e,ZBGbY=sS=)pb_U7UX!h)Spm'/eWh=[7ke*%@<c[fRuP24]UBH20#@BJRPFB %LAbp,LIUm../`+`7W]3b][/rI>:Jbg;+X>!F-<HcS\a,<'W'd68[525hosRb-mE4$5!C+CNLMO/Kd*?75-uh!KRp7\Q9b(`&Q9.: %@MsnD"\6E"QC#"Nq'gW1;H1:3G]0X*h)gK1%>49D[Aq(0B/"?a<AfgN<fot<7:Cg'X]J@4pSCl.Z+<^[Tg#;p-t*]Z+!kcoY8KqF %ALCQ66r?+QVpD#$k;\,C6ZRC`?jaN($^O+M/%/K0=I4TWM(Iah,#8WXp8kp(BaoSO&k.dZK!Papo2"&=cV'ijGhYq(`HGsa_%8O0 %MnbO$!G\C@a]&<X%2Dc\nDN7'Z*d9.N4oB-9NOM.gmEr7`XAZ.$<C&9\C!iTD..E+fVl:b\8A8$(UX]<e_PPG=?/8Aef8n;ht+7' %$-8t\q!3e`\TO:c#-]p_3tl$bW6CI>7d1i"<BGYo`"e0n/hlW'3WTPM$#%8!2G'sFefd'QgnGsmWoR>!2J;=q8PZ](_[:-!7MCo/ %!=,&L,=Hs;*VJZD^6Y\tK`Ej(6i&$D*@$Mt8\^U><To9)Y;I8<K]WX83CH?=CsG-GPS2qC:9RJu$)0FUQ?%jd+!cN@%]2)bINo]? %$3)1oZ!58OX]e5IV$UKjV)cnn*e+'Z0-gcr7h5"lK"Z%>impUt*,6o.5H8Em]!<?O.UMIDUVn<\/HZbVD#.PIKHIccf&e(V>ReT& %.aNsOj_&Hc4='j*msQ+oTh70Nnb9^cJN6/<YeY(XN)*gP[@mHKrW?7'TG5fe;V(rA7p\uX$W]R%_0uLo'f8q:LZO?+n8P?BamgkF %",WZ*g@7F8B'*:G^2oS`CF$?M\YTIrctWuC\8gHlp?'A']d?!<0^YaYXh&(=?bY]=Z#K(uKU^I&Vc&[iAAQ0\MiKLSbJernbiS8G %*/D_9LU'IpCdhls/p*PQM/0L.UJHrZ+WSUgMpnW4KKg%FI+ecn[:l!QIQCq-aH=SX2+o\O`m+Ht^(>fQ+@!)cP$q>kq8eF2:'&.# %;].0!)q)j'?,Sq[FV(;TXTd8upajkuL.Q@#/8-TYOK1FE@pDD("D0rQ4P;=qcad?J$`[WkigmsB=Fn(G?M*eK?OQcU<e1tE5"%0! %bU]]biT:JDih@t59f2,CTL-*/J7d8(nU_0*lV`KW]PCZ'qFc_[[e$FbOcCJrg,_fI2uohl&a:u)\nRH5qU@>)Q3(]V!/UeY^tlj^ %I/]Wh"^EYFN/F#;VG0t!"8:_Kg&g!OUKN9&$<e3&@EUW\"q;0efOWU0Ao4NM/"Dl?0s9`oen5fo[7CE8@gFG/P%a!$(7Itp>7HdM %'j]=CVa*^1dF$.HHmuik<PC:`'i/RQH10CO&RZF_bmlE8FD2A/I;V"&5URW#FP%:8>%$`b.HVl,lrd,H[jc&Xlq$SO'k\@Kd&K_9 %_m5)<,(p_#\(#7n\.Nj47&FXC6:8SuIefKe72Dd$i<.ApmCb(f$Ulb-1jZ5-**l\oMCq0]V5`V>LFbimTJ]`#CcQOb`n."X4A1nJ %G!]_J%8t#G9*FGiafC(Zd(D?__QQqFcrC07)e#0fSjppDPdnARb*V+4;^&_L6oXkC-$aRI0`BuLf\m0So-QVLQK1AcCi(Japd%MH %Q,=`$`muq>j%iX,RmlDPehYEHjIEZm'6c5p`9h#_[C6FIA/uk6Le:@HROL-bZQ8VmPl3mH!MCc8(fLkb`65W>-.Xu=Xh`r&D#,]N %)8dFM?"f/D[9RUc18uuc64EChM,t2&C8raY:$:hsOS;kJ[^VRBA07c=iHQa7(m@_(E-rtB-Z6u!p3j8q=8Cq\Jt@R$g7V%:(4N^U %@WD"T4[qiPHS$sTjNGSn/L!(e0nAp%8C>%t-BK%RB"s87B`NER^'D6R<ZV(rJ:Q@>oaORc)0.D^HSAm@NHMYhA"OqgFj`>aEAd.* %,j"`n;fOoU7@&]prsA^7''-7Ge?8.9;fel!qF_?)FO`f;T%S9[;'\kQc"olEjNVQW&lAtanYpdt)qW6,l%U2r?;(sD"K".&2[\LQ %Mi=<(P*Tg\NDARk\6-V!:ka9-`^sIk[J0U'8'-b20eVNP,c"G7l5g<;E.dQj&pJ!!;MfWsaF%MnHc9oh!`A4oRW2i;GV.l]N)$oN %R]JBM+Z*l%8-l>e5a.$,PJK!O%&tqT/mrU@H9="rd<*n(H>^j.KsLPp=+_K#=fkWTjD:bMJhVmKKc9A,>SN=(._'O&Pc?@'ro61' %-!d6@Ls.$_To_$t.^6_QbRt[c'E,Kn)@@*b26.u>6?$R/(?#!=^(eNNo'iW2dCWH^efM\N,YN<cm5r7kR,&>SQip8$`%0fu&CHW] %FN3,K!Tujc+YIO]K/MB46#bn!&r@k7O@=s=U_ZP"c=?)fnnUmZ68qU(53<5`9HN4.)FlI<o!S6m(JGX`SD+a5;f6,h0>ZWO8dN8W %:0i38`.=?`6k+kc&JVBubo!n"*;n5=jE=fO`NF"X#o#Zg`;V,A%m2qERa7RH.;9NZ[82W[330e?3VW)!?]/2M9gW4.&URFd6X.6: %Z1a>&*uGT/QPXXNQ@:-AF("43<gG=G%[')?K1K.(.27uJ)J[YQWg$mjVC#[fgcD!0RN%")T.E-k853\FWZ5C<6Dp3qe!GG*B[sJ/ %;a2UC[$\0CGh]PZ)qde_\;=A\XZ8_ag%*J1a.U4sCQ5A)cjWuuND$9E9`@:s1[1ou#d@6`+XEWdQX4O7`97qR!>W$+9im7H,XKgb %53?W8X/:JnX;VA.WF]89$?VK.2//(9FMeG3XR;kYajF9NU:r$o\ch],U35m!?Q#`:L*;1rN?"rPf>KsrkN9<8_@Jp'/dkqml7!gd %$BPHeA<9?pI*:.$<DCI][[?2$l(K@T1sdht6?X59=Q"XP@DkJ`0P;&3AD)Z0;:;,-F0*%J98p-$obg6<MUsD@h/!g(>Xb^[#]aNg %%]K@sNn`Ws6(+_8:\d>aWX2X^3-H.:>os<:?-KmVO>_1tWktgV?km2"WFT)!MUY<cVLn@f2Z^9%6r!n(<$L9YA67:uBF<foPKqFr %NIjk`]8d_GOWm!KV.QtB6A@$\IK#J77B3AN%bY'Eg4^eqg!q!6fG9P\!Iq`C4sGQ`*C.h\%"rFMjaQ9MTUj.C0?1YNM="?]24Gln %($*=@NCf7SmQ:rB"[WUkH<>KKZ+n-:A,qG^ngRoQ;cOR@B2`3QCF-uLOI`&3lE0D]ZfL/?&0O:L>=<*PNZVe6@h9W>"S9'i=0`+g %Wb*F,)_`ihN\NE0:H)gp'L=D-.Rd")>(pE^_>RZ(.R?r@kbjbcq,3T[dQ5MtGZ;#*8ppl:.fCa[cGJa%qfn=cRhDsBhJEG1JRKCm %&-2.:0Y#=pSm!F:QVsAPo9#_DG)K+<X&KrDC)*^_<L.fqNB:?BjS;0W'VDB4"2ZC!5oqKq3XNGG^$N-QSN&'#97TtdpqV_fP3a`Z %.<B/:ZR/_LVMQ@6nm?YHHo\L]7f6>kV<ItSga5bHLt[M\&u%Rs-nX`??$Gi:-!q!T'ang$X16tS`Di%2=G0mF7aAH*n.9hX<'/>F %WAE+^&R'qQZtXQHZHVtQm2X,]!8lH@FGR9pfI=ZeEN7ciMfD)N,4X+%,H/=,U.T_Yckq$,QEPt2MRQoPE]&^W8%/2L/VAl5<Nql" %H*4)skUH'EU6D)SVDL)R"VO<k^N(Qr/]tq\YR35o=^[;"%]6%C9=\5[bGZCujg0]<Q;hjeVgQL^:\e2XW&PO+<&LOr@0J-FE=hP] %0SKR/#cK499p*o_DGU>,"P^"GMZKr2:K?KQZVho<5V.WPFZR.6OW\/?/<+a1bKuubAs&,*_f,SXA@D@.']\`,[sU*Zj(`NaUk(0L %VQ!8;hKG0+;W=dWMS#8C^^_G,!Dl]QH>`4pMsKS$EEcZ[V>qB)#_3k/99eY7Y#;po5agCQ_"kN,jG?RPH"B&]92Od6&%UDhbHN'H %ghc@nemqQ&XZHhl6Nt08<9s6Yb*>/"<`hP`W]_'t6<Ib9Ft>s\!(2_h1:@V[?n$?U(PN!LW-_(&"Yg8WgTa\#f7WQ899kCUllR"9 %G-5_qHVTnW'e4$MVqXkd)3V*I.^bIR)u,177:;"qn4?!KQr"3^i[^-jqd]VC!e1Klhu.$-ljfJ$"2t$C^eIZ^0k8hg1-=qD^E8\* %&ff!\W&:GrZ:rpg##BC$-$dn((gJib1"%JSK(([Zqr5rCPAQ*+\9LZSEG+ARVF/WjC"&N:Mci]a;a8dDjD]_#)R1DhRYRrb07rgH %jqQlP"3smu6"\Xf>QX>ph3C*N*AB5GOAJDL^hO4(^?^d#[g(A3MqN-a?d0S$6Wfsl82;-]OJt3[Q:87F'!LH$l6FGrm4Nd*?g>C; %ap&DF_4ZPT<J\0o789K99C?.c8HZ:'a>$R'W1F*kmDs9c=YeGo_#P)JZ80\e3gYdl.!4."=BQD&<S<TVeaKBNk\Ci#e!39G9p-m, %9MH;?<hc4f@h;s%I7H/\K^k-(^3UmEcAGSZf1umTB!R5<VA(Q/>*$F&mcH1'hA)7eRJc6G5]iAn\I4H.Fu+A=*XCLM$,Bet@@]i+ %93SGg\:`'6JJboAaI4pjD=^1E;(]X^bR.O5@&F'=+^CHJ(9e>Q0fq7iP3F;KR3MtHTE=9gHH%QVo`5=-@sI+<@rRJT+iBE9YB&=< %db-Ghi<878GR(KqK(&T#oEC.U8XulFfchhB;mb\`T;29Z;]!n8dq?TsJHu?M02R*ndaYB$"=!nZ_-AIOpFRJ8TI%q'#>GIm6-Cf; %#F;nDe<7oZOiFl&hVa@:XqGZSnJlKPrR-`i#>o>hE<fdCgVD"c.17cd<J#:[&Xl"Er/ur&0*=ole^WTe*'m`\MHnAaG4$$IMOF[J %"G1FJJ8S(4Qh*6anJkRI_Ojt1J,4uuAL,EpdZA0TW7Zb?#%E(7[PYms:MikNgN/9c1DK"]J-c&Tq##rKK(fQR&0">ue$>Lj#@U,r %,&!.s:`O"1:%D54S;nKh-7j65]PCXn>SSdb;LeeaKPcECP42lfS\d,[cu$98@U#RuDR#2-f:bYV:i!7mBHP]^3oDX<b6D<llcR"Z %U$D9P5UUKdSgcX+V?G)HWc"fh(R)??%sdH-Ui>d=#O4b9k"J\j=6Eb;k-7L3PQ`V/\HNMB:..J9)-K_=#E`-IdFP?ZdUr=gW0*sW %C=%=N7Z3JGAoLQ/=*%uh-3_U*M['mok\aLg*9<IoG[`DP":ikc`HiiDOtP10EZ*f@<)cf>^<%;9Hb9&`.&D``\B;\UTOJJ8WkJhZ %!*nJ\<<Nl,+B0E"\md'+<S,mUZ(EqLHW3E8_hhsN>Pm)+W[\&82"n,\%VhNV,)q2U*A1_j;ll_C'38(3`DE2`UpM[VgYAaL`P_iM %@:R9W``/mL/Lrk"PeVj@f!U0X$%1$6>Wtl'XI@i@hG_2/]%`4#8Ff0#J/j3ARq9#u]fgtoP;FL<,XCf26?V*7&lr#\6;<'-a;T\I %Wp,RQTpeOaR:=XndN(iX('o.e.7g9X0au)-\<C[T";jI!6S0U?Llk"R^<#VerKnG!0MX?2k7EB%Hco<e*IpXBYIf;fR!icQW4Bl1 %!BlHBI)s/:ZI?nYb#Ndl\tk8]C8NN6cu,J2a&"N#(_oF(HW&!r-=Kd<*FL)rp(pIXcqdb^.BV?=IP]P4PEJ\Lm7@.0VSNR5r&+Cj %V/ZatAQ[+>a3A`m:43F]WXj:Ho!Ql>0i9\2ju'q'n<K:T<5$5GGY>A=M2!Doh(27gF(aHrZo$9oliH>?&9\pamSEN4!AD<rWsZ0h %MHhN>NNe!:<G*d\_U5tA3b#kC1=fa3J5Z+nWD)H(_5%-JO[P;kBJd^GiaddE*s5)hhnFPg1^j9#/a?4$ZL9tZ7jS^t3JT2KG;K_N %J&WR8=)qh!2R"C4_D;PKG*905N$1:pkXQjd5)4qPBlY0ej!Z@8E^]>-0pH`MJpA[HFmKd(&0*;<3ZB9d!$Tbs&-Tb`q$,J2Wg<-H %99YccKi?kaS5k,%"dM-sDS,<I!lkiq#9!heQdt2p`B!F$"tq-HJ\RiIj^BoVmaQl##.+cBb)r^9>uj2'AgGMa]h\O=<"p]Gm1Tr( %A8-29N<d9)]Pld@RCoDm>Z4ONj*AgoP=4HB7TE2fnBDStIorF5InY@RVkFZ3A2bt)1k..Z*F!JLN)a!?'I5?ke!=hnaIgF<lsde. %m:Ok!9+4,<JUj2$*O49_%#'QDVAYo9@HtsCh%[#Z<V*B8.OO[Z>_APhEuLS*H5?1_oYM",T<Ku]lRZV5WbTose0/)"LV3s<HV)26 %b'WLBTr(bf+8_&^okG"r0o'M#K$XbBY!&`OQ+Rb_0d=SAI;S0E*+e]bY5Z%O`\@dL*.HStdTfpRja>eoKf-%O\$9.]8r'a0G>Y)S %R101h$B',?XM`XD15Oim&HkP^d!KHd6V&FVF./r]cAT!<VQk%q5_S*ZkZ:kiBfGRdk-QC4a31n^YIOP;)CJNB&K6nb_II^c>Mr:c %?=lf?,Pme-o9_Nn,cNk`R[2qZQr=$/i;'%AOHBcD-oDlMR/iHs@nS-jiiJ.olm\PL)]OP#"/c["(4,O*K_Vp0[=@JS<b-;nPoU:` %E0N??nPo2!ie5HT[QkpIic$fnZ:?H\_5qJeh5,3tPKjoS@QHi[MMI/bNWm\=8lI]pQnU:S76#m:=OrS,8#V,.P%aK)a>>45daDFa %XU,U'A/o?)E2%te5`I,li:JdLc_+mi!VYEt!.OZ.C$MR)h'+tEEHeoMOSPc+T=j[^/N8q(Lm$^[7&Gk-Qt"%Ogq>Q&1?+b\<\Z%T %Vu\UOCPFH_'huYNWaO7&%Y5I`)6YbQLbRRd3dj5@bkXkCE0Ai^Wj1oYX?].A59)P"m_)kEG%@W.ncV]G\uIrKS_T'A@%\nMN7E*m %,GcJTl2igAlf52C1'ROd<^D_[Q,YH!-.0Dlr$Q"SkG:-Ym]Vk]%*Z3X(OP(OAgoDY"OVREo)4P+9S?GGYRoh<@Am*WdG\ac(r-sh %PfRd7r\Vcu=^3]#Z'!RUiR1\PP^W16ED3#?1YQ6.'98X.bCe3JZ4K)T<;ghqbdpG4&n?PR33t>S^/P!>L3b2,YoAPPip'L^gU+/_ %]+BBbfG%VVSO$AO/mG0^NL&Rkmii5pjb0Kk<3[F,b]5F3,lY[F4?@03Lj[CgOmsprVaI7rj;#e48/0<,^lL^&cM)9T<(Kj!M?rJr %9$nmk&YshH<FlFgQ9I)A[E'k/Zf8@W=B:TAJ?"%-&lYI^k#e;j>[7[aXJ3ks@=g"6M6T@_4R<_mB7bNVRIDNIa&WJCV_0AgQY8TJ %J'bT,H2KONF^8X\JBi7m0[kp[@Zr^c0\,Bu4MbiXM;/Mu-7TTdbcIu$VID2F=X^$#dJi0qF')Oa&Qii>aU"n0J7I;q7BDM<b<pG- %DN]ZfUoXp>H;8=Wr0uh=d10$Mg0>A9W=%a-RgAh&0!t3u:(s2odS;1Lnee?cp1Qotb7G:A!GlBILW3?'6WFk$\JK?'GnserB)5M" %6!1T8!$S-MmfBG'euj+MGD71V8Q1mD1O/BM]oL&^05ib;(_5g9>+6^GMIE^tK",h9XFUdq"uM@48#`)U+[&h1bN-'6c4RC=q34n1 %#MYPqW$:c/DMo^";tPNRS:]::Lg[bu@O9rM-l,l'j.^L9?>V#Zb_d#c;bEW`;;dAK<0-s8[@ETEfUOV6IYj/@1$l,8@PLG(e\iWI %+=\r(Ab86^*RG<D&@Qe=*uG*bKP0Sqd<#HcT6oXfQ:!`@+1M)j:<ZHTS"^:Lga;i8lo(rSno#h2pYG6LOVDd*.ZO9V_Zht+=R(D- %=i=sXq?m=&GZ=_DFC:(_0X7"-2SR;:q;GC!0dX[oC!'1]q0@$HL"k[M9%])Y$5RDT6oSn=?ur0%2b%jt!l7@BPad0[Pu69R:!9Ip %@crPdTmQ81jFJK/r7"40e<JS)guV@$-QcOn(-_X[@[phF"+`D/b0Y1;#<]--*pq>J/_7jJ38JL/g#0QB,3t($gCqsQA#l1&2CAa] %8h*?)d=II\F\>rcWhRb-'dLn4J^0,rZW,@)7CIg=Ch>8c(r#e_9<)unO<G/iJa!4@MR#$6D03=+fmZ2M%DdY0V3;KQ#&J)0=!3gl %d:1k/lXF*R(YrI!CH@4GKQH_8IGm99"J"($178AESIAQ&XZ<6N@$sIAWk);47mu)dXllaPr%-iLX$Mh%[LO,]30r?3_mdY8c[<he %No<>*57hfgbTa6\3W=2cFe%->8lAW+\Ksmg$i#Y-bJCn*Xb(pq=2+Xm9j?Yb>.n'\ESh]/NSd+TT]R6gW9n>&(94Pb;GhrI9T<Vh %I+36mKQ-IR5bsR_ZN1;5jbHt4q%Oqi(mS7Uf:Wb9X9r7O7+aR4%I'<q_]euJC@rpaeNKsi!QaPRadp5\-1fh'NT*aoo>I5iH5@7n %.a:NX1U=p71GJ2]aWVA.P(t?t,@Z92ror@l_4AG'mZ&rh+e.%s#T[>Wd/G?;j'urY;\:8![].Ida#=DTi'4uWV,^YsN8T1a;_h9B %H^GOT=:[EU:#5Nl#9VE+l!Y`uAIW:Tr_R+gU:+&ieo##;j7RODq#\24@h5ptj088CX^MU99,j46o;8t=MHGG:O\>&*.Fu]L%($m] %.mZ\dLX6*RB:4UH$f*%IT-b-r+`Xs.K&D"[h%MMS(-O'ML,Ca;Ui0"0RQkOZ/-6j&b3GX9Z(`hk;qK!C6&Qf<$;C%1!Y?Pr=II:_ %DcqEnj/=C!VF7KA9n'&;NTTp_1?/(HQ>!?pOA]&_M_q&*m++X;RpD9FbYu!J]N5Q^]O2S+)$'C^,4j7tC,IFsM)`jKI#DI&=Re+G %@nU]V$&94D3B5':R`.[-r!ZM0Fpu`lFVqpF.9\8c_\%#NGXleDi0kiR)C4"8-s6HkejRWgeT8<%P%sUG-+>jci/cj`\o(cNq[dcS %0S&i?KmM'^&hS5/GQ#ffh3g4Ph<(GNl]X$cfG(9M&8l\YPN&rDP-^G]R4$7U%paYr'r-6J6eaepdmjR$.mY7<$4rr5QV_Y1pj)2' %Zat3:8;:P,`L;cf.Ps),K64QCB_n^sm\-"'c>S/?W2fG4nJ0=3)#T$A[]bg2`9D4*MG-cF^..c%m*BoeC"Hu+D`o/<h>-n6-j]J? %I/e5o1NbnUD*WmOIT[niDgt-fIJ(7\oa"h@hEI6.14\Z^fO%4`L!1F:MKV6pEJ$1Jr26glS&\Vefn/B*4j9"[#0k4H@,.t+@em[L %A.bQ@IIfu@QLhQPW`@='Yu>FP#W1lC!<d@&1caI1J_H)hJS!^b6JUB7B40<>AQI%p,*(.V^>7%3$H6g`8t7=.hE`e(F-!dB&^FM) %[Nl>@En5'fn-fn"V%q7G;N^SlB#+>^3$J&J$QLKW=eBE(DgOlWU2g7"ko5:h3Lq.U"9l[W_jGl,?pJu1$8_g_SR/%O`VIpf5<@*B %'PigE<>5jQMYQ@1^\l3R;HeGm2GgeQ&iqg]'+W*!WCm)M.%G:,<[e%`3`EuIP2cD\rkUb8]AStK2GCObcUp"[&5b-QkKs%+LbN97 %S6<&7U;>IU]R%!._*TV!=l5T@!Mn#d@WZ2>(f^Rjg#?\fm;Vj6H2"m,ak>1*9R.Ug+V*@fn6uBR:hfjV$QOds0HM-eanmA#l:a5r %nnkV<$BX>g7TLpt_9s!G/Rf")R%eT:Z=%cccDN:gG_fX,9k2)&dm<=-jsl:JM\Sk1_pHgDp`#qR68'hQ+2=:DLdjYd7o<7mUdG!h %Z-Wc`@?Cgh\pPSJ4oFei$<"fL85MBiKZ$iBQ_HqAg4i\`P.q1V)Z[/p15oLu<s!^Bna8KL.b$"oaR7T!.$auCSRR;pAl?Sb;c/&u %6=@GJ"I\Ka3*9ml`hRo#o58#f33"[O<NrA,6AbiL)t6AKFs/Mr'@]@<78?]%8J4K#0fESQQU;?<XUpJ5Wb$sDgf/`>UqLP9?2_`O %;DCh[_Zr\=cKPCeU$p'EaKSJ8,"\cZl-O&o9?CN7F/C33E"HH3Z`n+";cnQV8<R$$cgPkN]#aE5hX<+WVno+0.c8=AF^_%SaJOF( %g+2rY@pFei_$J^/Y-/AI2=)]J('&o<1UpLgc.`R%m7m?Q(@lo9%(D;DJi/i@_i?LjA1[ZWJ=b1A]2^lPVp!4CbGjC/bLtGH4T"ml %=sM@#o<faNVB4Wka7la8%s+XSHT,R*m3bT"SY+4V^4ud,];k7+FVp1H]?eh-bLp*_HL^1s*?rb7I+u;oEAc?.`*h"nB?=gaUqc(9 %cQK8*%#Q>h"b`5.&jeQhNq;j1J>Nj6iHDeg.-oW^rZRVTr$m:9%WE/tKO=9K&^abN[4!eTna7/_S"!ejYJeFl55dM$lHD#.K.54s %DTU]/EPn7^SQ)dX7%*>!6inEeFjI76S5.DgSIZF1RS<t$b$qOPc07S/+f(BI48F)&o%9J@lcNTXj/-V4*>I%2B-%2[D5h!=]'dQu %rt)YE=$8uC2_L4%`s#ZQL6o*"O8BG)TATXe?[Vb:s-:@uoe6@$^\XSfs8K5%r]gA-J,738r0r32Hi<pcroX7YgV<KFs8LcfppYbL %]>+<&?h>F>Omt:5'dp5l548&=g1pH(o^/j^+9)0sO+7.9O+[K*>Pn,4^\r*N0n&pp4T<t4T)VAugD"kjK)L)Wqk9fJRfE9Zr:dtt %OkZ*"o]9;hH;8%\=bZgn9F.YegKI[UMVC_8')^/\F'pifP:D]#$1L&c'M8-E3+qM8nT6&&%er!6X<F0];TDX$D[K>UeaK0ET4\TJ %n;_fr"OsC0SK_WD9JSjG@1M[H8/J':-8\7*(E9bL=?rOuVAP&!bE0hlP_*LeB/6iM=3o*q5C`[#:dr>H.$Y3k7ZI?1<8mm_iBE%5 %0bba,s(l#Ss/`OYRe]4#+OHSmKd!`,du_rFWNZ%YA?#gI2K40t6S3,2aZE&SCKq,o#V!+I\uMN@3grnYj2_;3TYdFVLe+cjN^;[S %0Qh`KQMRE]cGE\JoK[)1Rl_i;+[A3+TdaRU"RH,"TWhD[\KN#!NbFqtS#>PR&VO[PX.KXgRNSO0'B3]SWYWTHAD-"%`S$0#9GYte %G@Rj".kW=A)q8-1F%@#aU*a$nmKdq?.$B1*Yhi@>;&j%UD,I0srmV(u1dLHFFQN5)AB(u%j:L*QC?0oi-Z+:ob$+\]4AHHZ6Zj9b %l0rt[i5.WZ`82dPd$!U.:kTSF(C4<PUhNF%K7s;=(Fnkra=#E&6XGC5rXuOO+WS;kAf%mWJqnppV?OYW1WB8i99E855D_IMrV@2i %CIaqSatiEH-3/ZKSfjQX2,0A1W*3?&>-h!iM]UdgaHJG1;%eT$lDh3.=5:9;%\e7(%gKie:B`7A-0Cir-o[_-5l\0jJgcT7<1iJK %Bgh*hdVVLOK3I]k]O]s)gH$0<<kj+^ER&qm@Kr3KUnDG%iP\h@>92e,1C;H"QpTBHc#H8(&:1,%i81X$3t1#c'L5V8`,<]<$YLT; %4ph:P61.A\<])[:G-bbJOk;ZTU?+(A=JF_+^mr9m5!7.G5uKr!LkKm^>QR%V&=iq+0sBIVm=OmOg]EBp'#laX#8uZ^b9<cHmKeBi %0"#Y!Aqa)Ra<LS[1kZXC&ig"qGM:@dNEWq$CB4s=&6pIM/`Zk%XWeJh9,*SO6c0p)SP.#u!%\d/h-1:8=mua7OVhNl^1<Y9To4=! %&.?eeJm;Zt5MF*24sh51T^VF['J<RX!<@%Yeh:&&,7@5gUigZK!G8UDr355f`ioaW=E0#//#a6T\')o2AE=bP"d"5Q(duVh]N5p$ %aS2<6p"1YT,hb9<X5o.,+r<[l\e0f4JE#2fO;+0"08<a_]BF.#\+pO\X"LM,6_oo[d;5R'mDIWSIQF\,rTVibA#]Sm#DDEUrMR`) %je,12"f&)EQcRj]p9<@0]#a1=LA+H$N:='><H4-R8h$EO2SEX%-j'9"6k?i;VH>m/r1PEIML:/f(ga!nI>hSMIA\lk3#6^pN.p\A %6Pe2Xeh,<uno6n$89<?-eM\Y7ZM4JmHW&SW_9);uk2FE=15.Aq`cKpKS"O*kN+3KLLpE6>dE+?1ZS/n^&`gFWaXYi$8t-Da08A=9 %dTFZDn.6TnjOQl8,E&h"7WJ$G,`TO]fOFKoOPRB*e7tNH-?$+>?H@(+/[9>""q(rN>Y1V9=qFtQ=\!F=+DpfnYCj91DJ!e8&1mhG %,a,ODk<k#r*L;3mAnZ]B9nO_HE?UBAN%c2E<JNP%!.iRVP#;bZG0QWEJtf"0(k[^>q0\,[3Y.nb01_<\De_T<h6i*RP"hYn<.IaI %hsdg;[Z;Kgch+QA'0gTmRhd?nb9S<+VMm5onRXmj0c8B6R=)9&as[P2j>!'`V&oam:'A]B0V_AF-B%<;LCdN=jEdWj!n'b3)uVeK %9.'lEWf0*A1itVY?e\a4e.gMhaa%Fn'J4JfdTIiL-,g]]1,UE+[,K*U\lrdmYdou]E+e-c&VHrL'eCVd?.WM@JmA\p0,lfP<'PGN %(WL(Z/?H3@"KMWi9"2.FP]=AJX;W#K[r\F7X0,5'7uSYSf3-kUPj?:QSgsJ%02q;BAEB"T\YqWX(\,D3>Et$!5n:<d)f4V07VU!' %+bM/5]],V6iIq)2Q3=7/-2u[\F'FVnep93GIm,MmL_jW_KPU?FYDR8hog"%3[7g']4V'S$4U`@RF;#qG,<bh?Y*5@b\:"Q^FN/s: %PIAtgDC9k:'/[VuI44/Zmlt1QQbnXYH80h(li6m^&LsaePk._4-0I;sVW?P,Gt<p4#,f$&R:Uqq109A6LXTjOP&GLu!$#o4gYV9a %OGZAo`LEA#b2eE\K1B1`QN^+HTd:g[]9WhfiZkoV!cCd+/B%JRJNteqhWLqN:kT*UmkuRs%Je7>C`\tk<+iX&%M8\^>=cb7;r)%E %\?'+>Vb=c2jdDd6Zn=$C<B1Fg>Ce@0hUj](O,7tm(u\`4eEnOF,'?*;>5P]W"aGOIf_GBV0ht--)#j6SFj?Uk^65DjBD*,^nOi6( %Z:DOB\LT*dje'<0$A@7#,CnKGCI4N/b;OAlq^ui&ZhDq]T#:tXTP=>HqHCDnnIYoYN;1"($$YX"*/h8$Cgcmd>5[VAFj&6:mQ4+H %mP,\ebS&%q1_=W[MS\NHJlcle4:NgtDEj1GcuD.SW=dk,`NBuo(_Mkkd2/RkH0.7aMPTITII?%+et/cV_X$af0b^$DKt$l8a)3QT %0rnLnU>]hWh]M/1ined^O<Cb@fY^g0RY;sRb7_$_E/O+b(LF;WNFS(Y7G%E?piN*.9_;Go<33,;8?q[&dMp59A\S2A1qeBg^TI%E %&:/eM-b-oWlk`HqH!>PTc^W7oKjp*h3_qgTe4Zi4:$d("V^5)sC\i#9e4K#GF)5+%@e5$Eh5Yp*m6S":hnLO^qtgbS;/dVe@66TB %B+kBPZojB]JjJPl2lm_;F\L7ogSi>b8_L_h'?=F/s*D#AmSc7W/3G\cB05H<2oAgG3j"0>/CQM$_scisHIV0)M@aC\ds5'F$,I%i %8XlKB,2lGRBYAnH/R'ie*mqEFmr)eOq7ZuO=(iq"k!Y<%I=E[bj0t>QV`akKR'$5^ZqX=h/33ApIGjRg[fH1KO<!4QJ4^gQ2)^?e %D3Q4<OuVTpL5PZ+S\6G#s0uoIk8\>PnKu"WHeeR"@rFci%7`fm\#?cC%U$DK--&VWfjj`q5.Mt@-2u"cmS$\5?gg4ePJ';imA;W> %?,lYRT/'SV/h!:9GVOQ@0bi-RrgU,RoOm1oiU+W'*"Hsns$J$"54c>)/p.Rp45KX(_Cas#'>BoA4+E<`Vrlh8kHQoEr%rUC!QQm+ %,1(kl+\AnJ&bqn;%ZPE2`kFaUN+U"/p>J>^?OT)85?^I3?J\l`VHC>FJ8(>%HX325H4mTrLb'[C4D<_s`IZBU&Pl8oW0u3`Jk/R= %Pks>Cj_.W*YoS>(pF3+rk!BnJ@U@G]&J^5[gdkSa5c^-t,-H[H6#88BDtk@;Ta8r;aT3B<fNjH1#k,`'1^'*F^j(%@#NM<[+iZZo %a@Kg*0o"_"mRa#9;GeK4[,SSeN:.%QOFCYfHW_M0n_JOiqDi>NV;Yc*]:Qe9O2$&dQ5U.]+KFu1G/S^!2L(W_#,mj2@7N%G2IdX& %qe:@2V!G6#ah4EI['at0g%(Ld@d6G4``&j:k(f2`X"I+7KcMBk-?',FfW"?K<_p(a16^67R,;HjNT*A"DF2j2s%p948YKdi>!pXD %fcq^?;>I?BDH)fu_>;Qk^M;XQ.0+B.8RcnDX<3l=>i)$CnB7]XJA5hp;?O\U18&RA<<n>;"4eampMVg8=9one!1p+3(J&hZ<rDk= %F.<!X3!RYRPc@5:#,nF<JKdT1!Mr,0`N)._KV8-5**-4$"'Cda:h\6Rk,FGB:S^NC?l+R1\!-8b!*Z'+a]jW"5I)440ar\G`;+gW %'*7ca1)FseYitQe(-s(d1@,q#WCC=c&&2dX2I9O,$Rer$)B&$68dp`@:mYjIikVpCGs(DB8:Nf3LUt4uJH#cLX[Zi)/=`t,es6hE %]lPj+VOJB#Jk'8`I7BR1AMo"GWpp)_R4aD7(-AMTO2-3rBRAh`g(o)JpQKS9MDS:"R&aIEBS^3hmXl_mfB87FZE-b0)3?:EO=G"; %QS/e9)A)e]W>B4!U\ojFG#J;ScZCnd6r!`\%Qot52b'tPEIfB*M#jq.nl[MsL>Q98HJ"E77XCh?8U(m(TsG>M,DJaYWYZ,u&:C=B %h:5+59qqkWII[V"WL4]D`<E7YX]I*aNfc_EeX+Us!>AQK=N*5s/glTt0(^XE#lFu0#*NQ-J>/K3(LmW'=-4mOl^522T`gi"*`J40 %bbQ&_1"IJk.]c>m1*T')5]Vr7"UePZ,..Kb%$M+W:fSN)^SDe/J86?-L<:A>bRp#(<7_?B9oc,<VtBu%0flOYZ\aHXY%D7A9iH^e %7,^R3VMH(EmR/:V1AWHUi#Y8T6=k!TJco1%^f&djWe$9lmQl/&cC3'r%t`=3hP/:/%0^,c*lm7Ze":^e814m$aXp')&3:b6*j8pl %O9NY1;P7YNShuTGi+h,'DPR=+6l+Ij@`n-aq34;;'I+m3\nYDC'0pTf<u!Erj`+B*8jHZ(k"E,;T::FDS*2rPaI9sbeV1pi6Ro+J %j]:Q1@.=5gP-'h&*"Aa5<42Po`R3S!J&.&1-QS,01SJ/[]SB$o@pOV^#Xj9,Ot>XV0Uo!a)/OAK/FXSmdTFYkDpoE=5p,JJW1#O_ %aL0I+a`.L(I_W#-9UM8M2PU<Z(WS6[V(_:"<H,A1!_#ee;q2kD]5G1?/Zd*VmsBK\#rHsCLSPY(`EQb.N!'>/[H&%Ilr&5*0Gk)f %[L@9o3"Ibi'%_hk)o+]q4NS6lWuPiecDs]]-BXb?fnG'?C1&]NWPCBaEWM3;C.cD)HsD0SiJ3i5!"aZRVMb$q5Z^Z]o(oUG-N<+V %GVr5\iPGf9TrDf%At`hCUtTT"E[$tV2#pNG:`s_@@mX,LH)UBYH=*dSLJ;tqAIlSc`s[KB4\rpF06d][D3%&bMq;eWIp(nghJY0) %5-ek/]Nt5s%bMh,U<UL[#`EOSlk]<M<d3<Xo.R]8[L%@19Lb,JVgYX=s86liSN`57*\pO#2@5hMhk\>[2>nRL7@]?0](a1(hdfT$ %m;:E8hQ"aUf-FP7KOlc1>sM1O]TjaRLmk_`djRX.(MR?A10s#SVsG%7TJS=qN/5J7g(_CU$uNg=`*W"9ZJLGC%c;pcfL^62$jPiA %]5h!Z-R<H6cmC"Fd;#b]>25@e@4@3=Yf5oOS5"*CGTO6I+S\'bjb?l+:+2n9VJa-\Hrf!H*c+kZI_gmNWt/0g88k_a:3+Gn;qUQc %<ZK+K,\.E3!i7@Y#FqX*C?,]@4(YL?BLXN/_GdCqN;,9g8;UM(`5EiT"d1qSjqRA-dST*#Qu[G*D*CAP[5sj.3(hi8O;t!K#mU3S %AsEX)RRi$]B[6m9Y3TA'!Jn_6Nen/gaOPqt(5k=(n3LP/Gpp7Y,mg=/YN0((8Y0k(&>P>h9dn[?5VIT[.W9XuB2D!.jm+U((1kZh %8(UbJJ/lbX_Kc<g[+K=o796>k6ZE5?YJ;]9q5E=n/EIkN#7q;GLs?^K%4PTp@Es0\f"pNdlueSbO$dLfbs4Su+]3Ks6m3>PLV"03 %NfWqfK&%Jr;O%ce4hB2jggl=$*+E8"fomkJ"L,O=I5?9Q9/GQ8%d)R+'4e(E6fN<X9deAUQPPCC3>_bU^Oj1j()n';/<<X/Rm^QO %Ri7=q5#rXk"1$IC!LFm7M3(=:8H!bC]j@!N?tc6SngS&m5]pp:0%sZsaIP`j"S!-@g-'&J<#B;Fm#/+QCD+LN>Ic^mM/M`2id$%Q %cJsa50i%o?fj*<n@mr@f6G*neSlT<nF19EGfeba>aE8't!Z"g8IXk$KVK`2=!NUFJJf"X"#VC2a[Rin=>K[1dilI>sGj\I/E6*/2 %IPQ?qgbf3_g`fL0%+$!UN+TA5N/fN!<2)n)N6d4Ql0DhUJ>7BD&2BqT#HA*$Z%e7[d"7F6l<)80M@;6hNb\<DAl0BT[$>c.;K7'i %-uSk26^X0VGAauQmA;_G]orugYnC1%\+?=o2Q',jh->%8[PKR@8KVVXZ5!9:NA2PF[6?nlDkR3X>fBRA7InJJjJkkb8FX=&$6L=t %@8h_WiF(eP_DsD:[E1*jY6bBII9f*0MD*ZE#D5e19P/H3X5u'UJs:I=[$j_$5b@E):sGfoq:!APs$B^+2EA;k/a3ZN,T:b6CjI3R %Vq.&)1k&@ZBG4$R%WK#\?Cjk*_6Q-?3m.SuE/?jY[B1LB"[_+P]oaKd'@*Fn2AumO[e+?#\qE&]en7*OO^@KWnCq@#6JEpph$LCY %S:CL]-fb&q>G1ZXrprARm>jL1h7#WJhuE>HJ,#N5ne](=F@9\E6duVnC&6q,F^%0)A5hK:kGMg>[W2b9Nt`b:FD//"nsQY.m2"/e %qmEluF,uZ%naGSA=BZ;PhiSUK+[sM/\s5;u"*T(hl[OTlr6[QdSaG0]PqaNbRjQM[qs>5"N?Z&k.DFD(LZ6Ic&+50^s$cCUGHo(l %<Pp)uQ)X)(Cc:#Vc4s\"g.e;)^Mkkf7*iua#DXNTduTO.V/JTUmIk.l^<I;CX&3fY>23gt=F#HaJE#,A<53O;&AI$3Of5u74:!YY %+!'sLDa3.HHF9iuLhhOI]ME;h/jm<P/Nb`pokIm?6$T?c]QtZhG('m7q6S-$g:%U\GJ.8rD+g't`J/ufFaD?7D-gl)!?B#ghm-YH %DoZHN?V\2&eNQ#.=2'*%\+<e\U6lSnj+F<7Z)CuQLA3beY2MVgdJE?/\]34dh;Z6rM+J]`UO#VPZ,MlG"$`&drSULWq=_Y\52GK] %Ek=ujHbUS*l+2.A.FABUil\_@me4&^9!5g$qYsQ"O6A]eJPYa>Zl7u@d[(IS`Kb?`h!Jl5]NY*#j]ppgO(6Pq__HdHrp6o"p?dM0 %I;*7DB$]i)"]IB:Ne).(4s.aC'Xd_o=Btas_>S7)pR1EfASEj!@O@UTj#67f#1J@Jau'Z9mh]nDjIk5[H,#Am$q<o9e5:X9bZDOW %FK[??:=mb&T(d[SWU%,W-5(hY+!'\!Rm,`qCEjb+*JcJ([<THH+D?GbO%Da6[L\Dob."#2osIeM)XV(;I<9Na])*?/%ubtR%/P%c %inCjPme>tBPOqT2=h6\TTb]^R*OCMUM@Y`d[;R/Bn,Hn@@Yh5K;o&<[5?=u8:b9BWiN[JDhCnUbRoU224!c%RW#^`4rS^(J7NJ1n %5999*Da3.Ddu=jd%C\gt9^h!DF^B9H/]XBu#KM/'jO9[62FLu[AHklWgbPkg:aM39*BObakDtZ!d^Pk;p9e$4PDq=#i2'-qLWO$k %]rn=6WIOnL>l462rP#]SDLFX8KgYR^a3)%Y+3#:(jJ-4)mFqm?qq=5&EnAOfnJV:FN'a;[hBUqV:IjEU[h%mADt_M"IfK28s7RQ6 %oQLh<fDf6YHn<hHp0oZ=6.$3rZh!9!hq,KShi>[8[8st)meLO$s7X8l0*bW$C=9%u8unr*cI1k#Wps319[pZNmGIiY[->J9Oq>qJ %Nk3V,7iil$:]R([[*t0@@MW)rL"jP_J,G#AUR>(T5X_T^73C@,FcGoE.KXLA*K`Yk0B\W4;p`i!ZY$YI#SIDq=-lN&!lia-/qecf %JA>tYpq&=RIn0nN#XL$F5qUH9i0j_[a10:%L2sbC#e\bXXH&7(j(kq'<EU(M?\s/Wg8%qac+<QX)$g>RNcY_AGW]1!iRcJ,Eb]`O %!7;cA[&X4db]7p%'UYSkY4c=FL^C&*4K1I7FWG=2ies2HAS(u@Sh1PS7)9p@_%Hp<0A9ZSJ<0pKpB2)nX>tO3JN(DD>ZhGLr$74e %A*e9d6C80K?:]W%Bso9j`LPNkEuZT&&4<>kAZ)gUP7<$BFTJ>"U`VGRa[k^T2_5K]G;(9K.35(8!5@*O6ic`jrXICQ^^s$gg7+I/ %J.M&,/#]=G43^kq]1C>V>s`aW(KHqq[1sUW/rkM.Bee($9\U./027sUbaJX^!l1#lAZ1s434Ka4C=0P7@7hr?MJ,RV"?MZu&%oLW %n74u@cbS:->CpqCjpJL#aI,"6rJeYIR1_IE%&e8>3sVAH(!)aPXs&pR;@XW9L=h;JW^gAIgmH3i;H.6"6RI4SUqBq>[5=$g$rLAp %&N-e)!1PS3"qG0>Q<o`b.=c(3g;s@'IC-e]A,s)ZaSBA4Pj"<f68?*1=\Z6h5;ZK>Afnl<dLNZ/&6PQW:BRB4_T5aulrN'Og36IX %%KWHd,r2.BQqm.1OGjcW'1t4k<Bl==biJI0h\\%*\MLie^i^+V=l,1\ejQ@Q'flJ.FA;6U%j*9T&P-k7%GTMMO;<BKfkI1X$mnuA %P0HX-`k8`V&1Io\:MQi-(f*^lqk&]MTZPhAOZFK;_b;^fW3-0J%GB2?:V\'[JSaWo&s),s?1)K#pgm*$G`4,+q95`]J-uDSFL<kX %'cW!kTh5V\,/L<(Q=n%0_89>8!Vp"LS(PTIP5u<jK(<)JMN1"<!hm\/mTq0_E(AP-Uq/`lm-:Z7'8;@mYN-b&T^tK0k&Ea8b-DZV %H\#Ei1>9gqCnsLV-j/Gm!Ycbs2R)o,BUdD)2Q"E#rna,hDGnDHOuT^gM)_\P'o7(2_%iIZ9Lsd'XXZN_$#T/se"%$.NB%8M$d(HY %Xm@KE4js8l[40'uNXJf-U=9>$KHV)KVk[:d9OUWhp=!/UV2X!,;Y4]qHCK=K?k`Sf.H0W!bO`NiP`$hPk#'j=S2DCH6G^Tt<BoO9 %ReP::+8>(i,o1,&c_PJ\GpF2GdX=k*>&Y4C"HD\/Y@ThCp;T-gWUe<Q:()@0l8P<$EkY"8)MN;TZH1)]aK8uqgRos:#2K;FS]pRW %D9f&UC-:'G'4m:![G+m&2Tjf3Of1I'`+0]uMkcQ9^B-4U\u3:ZVkej;Se&gcV7(?W3!kmr^,V<'CgFN?R41l:MbJaD+VB;32Ir2: %V#lM`X?T5X!^/W7MWKtfb?ho58jaADRWTN_`I_l2QT(3YUW0sbQm"6m4:Irtf\_4h6fV)e)T<Ke4)ZuQ-:1rG7+NNgZip+('bdnK %QuddXJ?>eC:mp'pD:$<52l'8U8aFiFO5<lZ"p2uqo]fj):<7(i/EZBQ6.qM?!@Ep92OKBWB2e@]Eh97eH64^I'uQW=JdnoE.Q<F) %7`cI)EBmtRe'.U"T!)iuBk#-j<t"JoCRej[U+/"\CYnaZ\Mn(NRJ97/'`eNgEc8\VL5=BcOnD(B1FLq_cV9EK#aS'ml>akl+fC[' %8S3$rWTqMM$l0<$&d)PJiZ\)C5[-Tm$N@tfS&_id@dDD1"58r3CtC'P`]]D3-\lH8?JF$S&aLcH)7;4Cg5/Sj#):C!(-=*HZk1$G %T_[S(H/BlE\&ngD[6%BhdQ]'%,ZnaG31P;,#6gbKg4"4Nah;V&s'_`>`Zg001'9^JM&\$Om#PfM,2:kjAkKRjQJem%JgG9_g&oo1 %Q*17l&2U_./W>+A#>KKjOfD4lUfK#*j?6X-"pFNd)Y-j!jCQ^<XFi-o$9WhTK'Yl_nsn9DWo>Bu6!4]0.++3*o^S*kf44VbJNd55 %&lP3iHSP%VgqE77Q-PXs_#Y)l6ESH#aQ*LEgdFnk+dU$$)9^iY1bAKr+@ko(o/MTV>rG69?$^ZRekK*MMqE?MS8Fmo3[-pIQHG_t %.M'IF^XAp);?AKL7t5SLm[od2p<>?#S#R`d.Wp2j:I2k5ns(=MmWf/#DULtggVY,0<*BSbc^qFm+?2clp[*=(5VoVmIhS@!6F7-; %]9l:]XP*,W%^[\gR\>fPJTao50gZt*e76Q,epoG2Zlt*s2kZJ%U%FOO=Sk7)Pm!oi(TF'k+8[K]%cW(*KhH.V,[c]U20.[bA*(R> %!0u"(6n:X"#j*[3eG1j[7dk.s^@rp6f;N2U)QcE_IGm3qX;W@LJ\Quj1VInGP"`+'dSUg-9FRp.ZIT17bmB9[=iDN(N<HP?&o1Dl %cL`>9_Q2dX;3)#p\M]6iEYF-_*e$rII&lq7m_e[iln)Tk_sI2<MBQ"'$_4pPp_eWNVJcX4E4Q9YIP-uj(EmUl]>oXf?rp>9R1k_< %'a)Yo?gQd7BCl:9\9AL$^e<?ahFO176b@``:u,&@X?OOAbC]9D"O-^9%TW[bL&D-p1C;D660qcCbtl&V-tT;+2;^UR^;0@g$Vh@9 %#s]'GIL2oEQi=6`'q.LrfpPqV]kB6g=R/<iqH7XSCbEr4G%kUNJ<EY?*GW%3/]S,k%,"d""#,.N4=mSO>73heWKIRb1stl-UZW%! %"JGQb[s^'.@T/t[-J8mma5YYr9AEOCL2\i0gd';jSJYQ>SLdY!p\W<'liX\X7SX9GHOh+kDU%:=0lG?-n-ELU+=5"Ck>;<`[Mf&Y %K;P8-5ED4AVTL]*CjOu/9KH[;Z?_LB1klA&WPUl[OTH(OLc&\8TN8E*'!-'sjjErRH0c&bJiH4rU(+FSL'T<$T#M"GP#,s8_h3.2 %mapZ)U-X2G**lPJ0fG*tWpP`R,c"[&(?;,[;`.#J,%dd/M*V.jH60OA%:d)f#fd(b4S5X\p6OCX3:Y!44JdNngCfJCA17]WnSX:^ %UqMmTH7EqWMe$al8miKr3[BnnB2^ek'iS.s<[4``j/O?jVbp*9Y]mYHXj*^=MFu%6LYG4W"A+[WKj?),aV=^@?G46j/`LcYgY_U3 %,;$jt(8YG.1CkF4'cHYe9J#)IIXhD=,1eG%eu++^'9[Lr9.%^P67pg+/!1('+'LW8:.[Cp<RR,94.KECP^92-.TSmkGN*$uHo4-) %RF.b_-#+!qJM`7uMnZ]?fAE:Dc<V+6a:jHq78dr,(L*%4!c:I8ngq!u;g:K^[M-j@#%\G$f)!Le1?aEo<=Kju.a;$.*Q,;'pjNVh %_<VJkO:%9s>0RdHK>SCUES+FSP+UDM;o74,CES>@2)d6Lqikd\BL*]!+?a%=pYZ,A?iuSW.=GRkOq\^c,eX(/#Z!"3>!#NAl04\l %;U4&Y+&+S+:`g!MMua&87pXNT&KRL)"XdK_=RQ*%>i5^1HZ%T8(&G<(&@s))(Af]?rmn;=<[5Nr%9o]$Y"uqReGIaul"X',/'N8W %[*$S+2eSn+q`_-=!:%-S--15k;bM.o@8m<KStP^]:O.F[aokFuTt5)7_9bgp_>W>4:tW$6$N1h,$tE,U&uCT"6ia_iZN<[6l9a!Y %L1,Wa+KKbo'?8aV<IJM^4hJi2g=Te<N'S[.[e/F6=`-Rd'[pW<(<jC38mnJ2,Aofd_"s@-4>e+YTs]OW4<%=0Ad%61IA47VV6ei= %S9MdB2Fii:B4e:4b:6*Rj6Se27'"$+GB+I3s#.4OncqoEr3H,p;[6$Z12ikT1`>pSF0\?uh:DJ@"-h/q.*=7n3+0ic%R`(?S7I?1 %"#VnWOqj3a,Hhq%&pP1tOYf5--HkgX;YY$DO0(Q_:<oqu'!3?HOE^*.XDC>%*9nUm,"[])*N;@:Do?\)[Knifll&H_4[^Nd:NW57 %@R-:io;)H%!'2bAN^19%ito*!c,*22BAt.5D(m(#K@2d(GRt0-KkEd#'^u-B^;;%Ha%2*_8P0dC=GJYH.+P=-qGJNA;^dj_4I0tE %WDnKaK)1Cr^0$AhksAqrCB'Ct)O[mkFHgQ5nJ0]'&G9?>.Lr3Y&2p5B*Q8Y'2B7?>,8J%-A/3]b-DKK_(!1*nDm=KG/It.?3C6VL %]5D8m=>ca&2_L-%3(:[(+;$'5D.Y1m1QV2Q1),kFr[C,6[qemZQrT+M8*6A`.^$WuP%HQ)KM=M-%m,REc/W?,cpS^Up*@nd%ko<l %>$WIgfp@X5Hlus[VtJckFqf]RLO4eB._*<nJRL35V4`>rS<EK@*WR#Qb]NBVas7t%Lr'eaK<coMm"OY,d]Oh6MWp0'J@dDZY*Fpb %oVqHDUg4%K3m&$_2ng.HSBPamT8q5%L&!;lKc(:dE\\aKE57Ip"q?<k)_AY)E2k[t-I<\jF`b23>TMo&7a;$C4_1)qeqNe7\KEu@ %%M!:.m?Ge#[u`hNc-_YHEN$+_*]qN=K)B@]?tY*X?BTFV+SnWs;sDd^l[Dj2#oolWnu%8c_*VU.9$>$V)i<qG0\n3pYWa]Q8DOa) %q1Z\R,L%p%JRo`..Td@<ja4(3Z,/9iP_Vs=?_`sWXc5#>;7Z@01`L"mVMmTWk9+;f?jd0<Q#moK(*]6s;@D)gO;7(i3HD(:,c8V, %&2FTO%jH),XDc;+CFS;Ncu#m"GQrJ(focnS0kq>[A!'k<I\Frr+rBB<S?CXp'IkQ:)K';_GhM4Qjq]ke'Ss(hOd_aWcm\;3YDOqZ %/N6*98SX#/ggd_X-"[8/cP8kU:G(rUFkPg:,\K]s\9EX9<e`UF_mBc0+gZ3'(Zt'[[PNt(;T,Dn\OP/oe5bZj?tS8Yabt>#r/=ci %R86Ubf#9#UE/<S,f86"+7OY?-+:P.(JD^=cqB/gQ_A#DhjPB,B=L+5kX2(KhUd08AUh,'PRfb4?g&<B=BM3WRCI<u2-oh76[[V@j %*j<?34@J2eI_Ej#,ZhkMIKV2h"<=;IDb'U*Qm1<c:scVN<6WHE7Z;oCa\X)BAij_@9%noEpsQGk=_Gl?4?bd]JOOec\gWAPhHka= %%[upDa!9_K,-[#GM1kKaneF]dE(9=2Y9If<D$RMSG)[hc.9cHf"+\cDQD`a2U]JOf2E\O&L?c=l/gn!EqpWC&*ABG4\9-3>ast8l %E]CCs<%RWW0='3@EcnY'A6+KJH$1$LO;g"=Fc2q@R?9bGp&tb<NjCAmU^eUp2?prN$3RFa3s4LRErJo#]uG=\VWkX5&duO[KO\_l %)b1A,oOq`ZnVmAsHhuue;L-I;%=p`q=*JOQAXB]O^)qu*WG0mI6kQ`oXk--B&#lu-V3ecH-Lt]cNESdA$rBT(Ka^rQ!5=qGQ"G.H %GUeR3qan2e5O?.,g@AVoi&\g)CUA;//k>fX;"uk,F*Kn<#D`B-R,>j\Cc^2_L<"j'onge#OeH?h^I+j:m*uP]B*)-:P<uME[pkVX %ETW91__<:/i!q5(BUS[O5a;qX1R-^]S2/nsk@+Ko`Z[ojH3;>Gm*[*K,48F\I)i[g#Va06pl,;/@i.'p9"]lc-ca1"?S7EX_r"Z2 %IRKSIe=;`qhAP4.KK>`;S=/s4XWF,QZfu6GUtJ[%4eQDGW>&c^Lc+5A@Ef&0%/2'Si+ZSoc&bgNr:(7UbM5o/.jWt&#8_=Zc;*M. %+Vh&>7cOD4cBu'o3A>)AC&7n$EEL"K2s:[pafJ%+cIA8YrB-jbPh](XS5=_b_*($S#t(*iY3?'lT!Z]4Cnb%dm+5bLZt%si&h0;V %k#"'SfpP=YN?,>2O")Kp3O=Obl0`0s4aJ$d7nb(F&N!QL`tUT)XI)8,5ajKW&4^*n*b'99(6RtOb^+qY8`tdUM^,Z8a]>qR[Tf`J %&)sunC(6*SiS(F4nI!i.TFdf#^d>1?44q<Mru/=@kT>%;0P(@^#H^115o]Sh/j2_K"8@R=#^JH5p/aX[F\mQTmf3#g0$k]tX<5M* %;Pr)3!qB@#OBaa!P(5b.,ihVC9mFG2SMf2@B_+Dq^S[9K/p(M"[anbpr?sIu)FkBG/7RCPYsV6pHa!X0B8SQ,<`32:F[@CA0=6+5 %,:3@p=Si'g:]KpFJ+kmOnOre4q"^m5Kh#(W00kaB<:CF1p6SS*@R&\reZ'C)3[F8L%l+4o0DsbTmD=4Hp;>BM,t1_.[KU$4o&If] %TZ@2jX@hm[VD%[n7"_IL!_<P'ehe1!$pLSp_F"85DCW@;o$,;SFN:a]EY[V:?eSPl!BM?T+MsiD(c*csq2"X`VX%`3hE9sYd0Ok. %5J!/74;Ru'S84VO/aGQI*hUjRm=*a/VV]Y>GV*<tEF+:0R&P(P*LjdO?/L3X51m_U]:RcWK`Fg7k468HG0U1Xc,\*c^adG&p$:@I %pN_3(3-'E(VYgCY(57!ol[A*0mX!dLoBP_q<kAUCZ.ig!9s.uDGJn2j)`P0':JZD>rlMWbfBM&=-AY1%cV@i+\DR8;n?ob&!M&l4 %H/6MY@qt)fnbG5#J,A>@XY#\[("MbP#t&9iM5]9%s0#=l5O%hgnE9c<kp0]ciu":W50cmGkqLE0T=6/*f3Gd.Xn-F9"nrrU(u<'& %mM:6E\6W>;DR\b_\&i:<].1C;h7Cbd7<@l8+u)O/D)r(9_g.^],E8%`?dFi%\*9Pqj#W5,VUV3/9@0s3[r0Y<m`4q7AN]99"[*mc %4j%V&[%F5:n9O\MbY&fJWc-@;rH`sSBQl/VgnmG^)rLPdVkMi-)$AJig8E9^D*#USXg_`QIiA1T_t3HbQl>dGI(kX"CHDC]h187> %#UX1M\>'*E`rL,JQM5s,KfEG3[q!PCq-'C\(,aHc,&-QoMaYV>mF]ead,gt'F,lN`o>I]eT'jX)'LD,-D=MoKFtEN]M\7FeBB15I %'5R-\3/!*"W+7`7ft'>Sqel;qQs)0!>/4K"mSEM`UY`^#;EpG>Q0UOW7]&^RrH:N:593WmgrgH=q<iJ'on.^AqrQ9Wk'>>ufSG;R %oai:iO.1KCLg7u`ch"R=Tg\aWHFgJ/Lg8!3LJ<54aR(-kDt**:EZGNJLANYU54@?ZamWJP_`I[clg:8'He7Xjg,X?VNpT,Qs,QBI %\F/PK)#*4i>/[IZcWKVhqc"i!n+2>XE:Wg$LQFBIQ8Ua5TC2@;#<dD<aj21&J-[@Y"Rp!2G??F2!GEj4N@_-`;j:0H]6=!!S64\) %[eA=u>Vc_;[S>uO9VG<S3@P_HBe+<$VVk/&\)0EW;)!PBa&(_#P."s8jBo=2P)QG'0bF%%NY0q_a1A+%ZSXPEa_cRoWsJ&u>N<bl %>tm3/;;\IDor_3Z1+>YX[74g(A'q^uX`C%AOkI].`;^C$7t`S[\r*u/@9(>9C,L^,_5A[OcA<MgbSr\2YIpH)^tOHe=E/kR"sGMd %)-Cdb1'f/sqsIGj5u!_1E./A]@*.;fa:=pFE(FCeT\>gc4SB6bVV=qj+mas3>io/oFZAM]b4sJ_''B.;s#ASaaBG)+lHrP?(OB`( %/.X((D`jBAMS5r>!aZ![FY*pNV+L45(;Nt=+)=[,'#u#_U>>I/qgeG_"(Gq/+@1i83GPsP@&A%^9,Cn:U8i6ZQnL]lTPdB*<`'2, %ZN,4\c@A0t_@4-fLg#1bXSc3D3kQaukhsj@[uZC5)LXk34W\(ZAu+!`_*Nd*>c)JQke?L(*omarq_2Fk^XnI^r;RcYA<<^,0RHRq %,(cc@Ma?pVP2;uO%'oc\3(HrO4cPJI'rI'a;:de,-\iSc!SA)O"rk?/5kX?&Iah2N!W5K;?I=p(&B%a-o\J%W#I-IW/5NgH8?EJn %?FchM=W+0-Qn(W2@_jbI0J3sOKbtL.$i9M'40QKjM)YTT#+k;99k%o]R#5BB8il$n*(eR/ALipoSka/A*-5-S8jdn:>ai.M_,u:l %%#YJ\\mg5ii(HQ841_pYD#e*f(>fBBHej@ZhmJ(C/RGfKP4#,IAYp=<jl`9Q_-2gk!$k7<hiQo*B+ZD@]mF*r6U*^jW1)p;fE%r< %@qBZt!Ng@;*%WYP'i=?W("qZhQsCq(@%Im!"umqa1+8MLV*mf$Z/&At;IgIbGg,>-ND?Rs/g,)Z=hn/(;Cd%Xc>.6<g$i8]+2ds_ %7tZRkQJ+#_O2f2&KZpZJN>'I12nj3KJ9$0@(M;uD3-2LG@XT$GF7#Q("NV%#f(3l%A*I=Z[rVKs;&-c4RI/s"ck"ss9t:UC"u'9^ %UYsMO>[0l_1(`04Mm>KJZTq/W>HqCh6T*ULN;%9G>p"88I.1S\Ss'W$"V6II*\UK#M.6s\VurktNk;ojG53R(N)[$M@_md0hF5`1 %obW8@DH_;#0F??jXU:.%)JKJ!1c['ZNg6CH^)^uG!^tc8#mYeDi9t%-Au9/QQ3h1lW\^h\h*sSEB`NqJ&>_hbFke(Wc-QIWJIPlI %=klS&b%$)"+&X<#R9E"*'"?5iN8fu*J[TkEj.\r'Nrh!;((Ki#8F&Yqnol%V-pV<jCQf?bZ^^6IM*)$E,N)7>4W_D;6P'^HfRQ>@ %U'/0LqdA+/Ci!-BMIUT]YTaYQPZ25&30q'QHE8f+`/pJ,/Ei>(Pcq([!!'9AGQu1qZXmBGTZ_ou#7u=>RGMPu']:@UhJ5h*o'D<, %oUcuJ6M(2eJ'VNud(3R41?n[M;^'`qNg3&e&"*euS5^&s_:7gM>l*mb!HN0")j3\D7PLQq#2![2T1fUhnqn`p'q@al?m-hfP`;B0 %&G<Fhf3GI;2GtH6-!V^[!5SY(n.u*9PgNH1UF$i7mWcTEg6N'Ye%+b#ViHhqmeBbUpEX9=mUY+*0I)d'@:6kpE%74L,ZMXtlOruJ %YKm9%W"SGsFf2mlr7Qo*;;5uEHQPt6iYX^5)!Fme$/ak2:`p^p"*"b-P$im'UZL6GGCFC-)>`.&Sr?Oh*oIlO3cI^l[b,Gj,H6SX %2kia]p"LsiN+;dfC\[d.SMU"h3eoh3h3?-fBUp`MiSbBE]%E]ra=Q[Y5*'e<6d$$2d'_`+.5-7VCd9kN'\#jHN-cae8@Yg&)CRc$ %#k*?'!p#SUL>uhJ?2G%Oj80f`YCY"*[m3(h9N=[fDUlpV"DQS8c"J$N4nOT,2MR9\euQX,7iYEle^l>`fV`P-7W>Vs9E@4;IXi!M %`7u7pKToqgBf&GR])6=JlTCC1)F*(j*lhm^KgL;4nZD&0!Gk"eltIhgHf#j,+o#J)K"U&0&-5*.0U#b!>tdB+h_m+5OE-U7/.?]M %Q-99r??uf$eFmS7`.r7k-$m\=??Tg[FVHFU9lnI0KkgbnTCDCG?u.g<L(S"1"I=l$*\Ar$Nan<Pll9u%Fq:]2h(A'B_WWt''`"nr %bN_MO@h]rbg3G<oQai)oU3[4YJDcOEVDr`8e?KOEL$u=6=?_CPM=HH;=BFYpE\0Fsn/%(IU%$=UE+sLTVkfMlTt^d!'eFri!,m%% %N!p]+l=H98?su@`V;"#Kn#h_SXe#]RPJ,^[VMSLt)@>0Ih@0H@?@8!j.8kGCR1/QlB<S<M!u$K*4V&!2TR2hXL(D9PlM5!7a\N;d %UtA^3$V;L1:_jF*o.0QNVh]U-`r_=dZ>I^4JiC+/_D\Ki8b:$E9oDYT&ZJH\WId*-CJra!FR$<5&@6p<LrI@[kU[V3i2?dI5BZ.+ %/,HrY$>_b:(kf,t1)d2CYkkj2l[V:gQXb]5kZW_e*&m#i7<#uTU`cmUjDr4Xq$bI@7dS`9SV/ggUu".1=.IksEU)K8T)O5=H^A#2 %P3"ao$gJgS,!['N&H;A?8dPs<O\uPgR&rbD&;25RZ%8tlfOP<epV#1r4?W<tH$CjK-3AI2h<bq)*p2VIk%;f&Tn:j*.gQGfX003C %V_f+27:3(a`R/jrp*=S.*UC<0>Tu"Ih=V0u[r,]A_<i+]IE*D`fCtTs40iFYj5V%.QF#=o=]V!#W?_+2VL=YBo6#>J2qo+6gKns# %3GR1'QF+Z_]ToqfI&2M+f_!tl0#_-G/)Bd-Y.+aHl,L(/]oZ,p[rM]=VTN+DCT6lrl+0jiHq0IJ2l\uX+q@VEn#18R8!Vu-G@6Be %;<@D/.duYNWH*?\b$-EG;s""=.\H1.o(e:q[l:<lDbDibH+m/;]W&A?q6n4OhTjAV>cKpDW,gSRD6,`in#5f)UWV?>fMoDr;<;(P %03)oYW:KaRPrHDQ8ZOsYkuP7Q!O,7#S]02;Je%$EdU7nK/3N^^+K,.3qo*^0=OIsf2cY_#&/'is%6J+a:`@rZlV!3KF$+XpH@`HO %)QWkl9l6#/nT@K)RbrDjgD45ac,qsbOcH.3%H"?(^[nt:/Q-#)m^ZWd=AhlJFicDpX>dS;b3HLt]^@_el^[[cWHT;>moZjsk$]8( %?)ZF>fp<(uIV68Ge*]6-aY.29h66Qqh>0%\$9uWH70/_3V*eD"$rjeheR6EO5YgU@)E3q/_,-2SE7^S-f@qcEH!E.[()4E!Ch$%D %Ip3)j%L[FV;RN=fU11Mu,c,tG&#CK$j>@S]BqEWhg<5ZK2*2tE[V=7eNcoV^kcWalZdWgGF'+VZN=QIXD]2f]ak([,=h'JbCLbn5 %;<i;=ERX@)Rb[)4G4-r`0"G4sIBE!3#1MJACM6o'?1PU<HHjKQ^WW?GC[EHI^bdUWh4h1D*jiU/<=M*qg@!Q%>LIrdVNXZdhhgY. %_^56DOgV)GO64)AYn%S^11l1k!=<5*q*lWNM\6("XV4="T3.PC6d?eN,u'V!E>ns"qMO^F8hE-V"-X^8ZSe]cjWoY/eMuKh%W,Oj %;cHt.Ya]*SF&JWi-f]=lO8$GP5e0Uo<J'`L.9o8:J]DkJZX$N`VY#YbgT"tL^2"DFHfCU7dE(T`StJn1,2+bnV$jk/+M28!;^cu! %];lf0+4Wi2#oiff%TAKo]24rL:&n9lXF4#=(KU<@2'[/1X:&h2!g?.45U-@nqn/VSK7OP0(nN6JQP="DlV#G`U[Y1Umc;n\Ro5;W %"]Un&_O0rj,WNVQ!7->N(1Q.E(n3elYWhusm)#/;3XO"f1Fm1U$dNF=Mb=Vp_CblF6*UA'iA"Q&0nb:,8?.&]#+,:\.qs'l_'Rs6 %.-:4\RkJCJVtr&UKl+E;]$,DJ<icocr=BUW-D_3,,KH7C,1L)&KiZ/r?)S.4d5T]fJ-6+iE!2.W$'mTf;pF5473pj$g\g'"TiN7/ %Dr?u`qd:HUbX:!0/<]AZJ/.'Q=<1B5XIor1$R%]E#<#jqcV'3CT`s)O3kKq`E#f56P6c<16?<on%'#8MQ)XD[,,T!4J'Ja9X-"`> %2]66lSEp[\/USrtrin4tlrSt4EYl&@@u-(p276lGBCE7\kZ"TX3d$oA+O#KT?raea,`pYT>DB4"Q'!Fi!3>uWFq>Y3-m8Mb:T^21 %5@OIFJ0#sLJ=5=-)%[XnHRs&<IW/;n=PSCgWbBYHMA[:=.[Our*ei,mo8KaYGINA4^u0:c9+!_25QQ\RP&=D=F`gI]5#me*^hE3V %LU`fCNKFQYO/YDKX%c9L'0?LZQlg&I2jRp]0d&mp0kdfT*KS=:M^6hQ,\KEo#Wjs+kS-j-@.m>IZeK<1Q?G8)(m\i#'2FW,T?P]( %*=Z.kMO,ebdjb"sR3i,.$PSDQU:&PgdDgNl.?n*02d(2.p5&"@Z\.0]Q!l%@d7=bFgW@$sqe@0K,2J-\KFNMu!`P(s_k%IY<]t@o %A_9^</h&->Tur1$j#r[$9qoc94jI@"e?4VO4d3tM6:OBa$2.V7<T)"E$%Sp6`Ih,)/5(%s>$Or/rC]U!_<@)&V=HQ'n`hoOUh@<o %j028'_14Qn'^24Q$%=UF5*`[q_oc5M7(+t0*sJZab5ALJ:cZHu=A@E1^cD:BEibd7G"nugRWV<W_JMBeO/5C;hJlC^SMJFS^^OFg %SD"eE9#/89n.!pKM>85S&>sb9!#r7B&9V#IAjK3g[YI,;ifG"++(Zl)!JdJpCT#nH9e$oO[=Rj5*A=d1[*T/'?bdt@JXg0o.5#[3 %IuL*S%*UdpH-::BCeHZI/ZXPkY=OUKVeijGS:"fk=rqi:3SBhVjAmn>Gallf8)A7TV^j>/jafP],Y=pH%EV5b(Un79'G9IT\](g- %1i1h^A(Y<_e8e0=bd<MZ2RS)6SO-a#\&QB^4ag^N\n&s[_Q:f?b%hV1bnDB!Qu&R0YdtulnrYg+_K>6/q..X"QVk_HG^t?ur=!Lb %Om4A7oJ2L>(rN6qnOghL)=Pt<askAs&iCUVT6Fs=W3S\=0N%E%6G*\Q8qI;X;dE59=P7^R]";^IX"L!KJ:l%C@Tt;Dq8)MC@G^/< %<B++/j3LFYP]StJ4X(aI!aE<XdOH4g$X]IB+E69QFuPVD7T%oTNZ[gRnJfD;iK"]E6if@T!s)oKp*JlN-dR-.p)4Ik##p3qc4L^h %krYgkED)s#?j^(#mq*`H]g;tklm%P"bE?e31q0iC]%:U:QgG'%]b$,lE-UE1?1jG@3oOfj/N5^nra@<CDWe5L>sO>N+FFfA$,9Jc %dcpD_+LC3/$XSO]5D9\78q*_f3W6"VaaDY+9N\%.jcZ;T4@PlO="^Y[-kXkBD1]TsN6i%1AfT",L'4sOrL%=f3h\o>+<Ki<X[@jF %<\L(c:8&W2jk+O0p0Iq;,%j\<Y9ni=ljZ<TSmZL31OT21PsQpMUL<8VY%8$VW0HCj*]VnDf$)9&LbcuM*P8#j&J(LdWH!NQfK^k/ %7MA>pXoXM0iF%,)@'4=g?CJ+"edbiaVLC>BhU5<5#+W0P.U8Ln%*tHN/^u3Jo?\0QaRhTk0-='QA^)fEj@3,q!pWqH(+P,f.6;MY %aOc.,-,hTk.mo\r_XhEW#on^bqL`H.I"?t31%NftlN3^kBAcJ,?rK/YRV?Wn6!)Rs"V_d"/i-=B1X1S5`o,C@j:"""7(MP"2drng %/`ANEdtAHE*UDhCJqF'=*I(dN6`"?UY/#B1[>)tGGbo$=7CAg_$Z$u5F6X[HpnY$ZVYY"E5(N;hQY*iK+j!43SK;?297b;DcJ!83 %(2t(&#s++2N??1D'78&tJl%(J]Sjd"=USjV&=Z&9MgSc;#01/a$](Q`o^+6F^8/?b4jaiF6B'-1FKG1'2uo<f@aP?m@&07aS1`&- %G3j/W:q>Ad`<;H_q\o;Y]CSddpkXd#(5EB#(UFN2J"Tes_kr5!j%J$oltQYI(N@N>J4ph*bd(-&#p[(ed&F\g,e4E4Zm6VOqCq(& %&/MGgfV)>3I'9F'#O*Gji!mW$1_)CKg*Ln_7"/T\_;ob\W&V8P55Xlg+cDEq<W5mi*Q'1o)RQdb?:0lPbfF9-r2NEN<>>V>EAALJ %-`,+Kj?t6_%*K1-@YJ7$(:4oiAVIDGKOsrRXY]Ru=lVGTXQ!OZ>p;4]=:/8bS;%n+_XFg>5CEMe9Gu@A6j4UbHW]G]M6FdH?<7i! %=>ds3:P-a!R[sY-:!-6kJui80qrG=*)VIRa5h4g+%d[+*3&lOQ.:%(]`3/ZDf?_JFH;9j:XtI3%*:W_W'Uf,2"RY*V5k3Zg%h%Qr %qD'Kr9SE""-_KjK6BiEm/F^$+=D+OS@W;R0/TOOAc;`'M%n"GB-m@1-&#P"4/Z-J"e7bC'4(St(\;Tl%_`L9J8mpga&jHtq#@&,- %Rj:oaPW0[+[S0ZEq4)V;E"+="MCL$C]1J9uIS6Bt'rYQa1N'`Q)!i$I[iChAjTgYp8fr5sVh4-g3t0%8(."bCJ`ara3f:XZbe/bb %3t./NhM[U#Pmql9!S;.5a1j']fgDi(3'iEFOYqO4;L?Y"%0PchTjYW^>$NPooa6L"+#jrGq'M4;;i5:?C*Se#bluPtcf;(0@>q=e %cN=t^(HWo?R[#]'1rZgIq9"@EZV-.\?=]p&-J(OO\kJ\4*ACoS:A-Kj0r:o&OW!+7(#,tiJ8:<O2NlW"D2F,OlD2rserj=a?/-M8 %F)(7_7n#Mgks%2I34b%=A&Y(C`9O3FCh&T-Lih04`9IE1-$7c(,1c];TgNhQ'!4u77&b@0=GLkY-4bCU@Yun>WNBQ>ZU4$s;qWT* %a+pg>L)&nR"=%07Zq1[`r1PRH,:js&&oj.ISu=hfejoR'DPYh@r8(N6q)Y+?aLb%Z))pgjerW!nYif;RY6>0#FcIUS]CUR<4((Lj %`&&bTc&jm+S0pglT0s*2_ndTQ&&oAe?[^1mF>ESmTZggbMnm]a[<FU]p9BnbG7-q^Rm-b6UoYLa41g'hN16n?@EHLI^DPgl?%CS` %:E?d)l<6;\`P\R'fG/_B<Rm>^b!Qt9`=:]%Zn)nC*%R"O+30<RP6'?Uq+Zkk/VNCS>#hj_>]8iDNnf8V8Xd93]FWQmAH/P&q*Vc1 %>f2@3@+^9AK9d?_'pN\.[k",#PDkF?80un_HO>pa\@CG_[cHJ/.K`rV<[Sbr]7:2NYII3^!#E'4qsoo%iX%Gr=n+e!]]f_kac8?V %<#%:F,a@?Ml&`H4Aj5a$0JW\+in:-AI^U2Pdmc51#In+XG;tgK_dgc#fB4>OB9EC-DMprYMr+L81e3#bq_3".!+?/i!$@&$WTN7Y %nWI)CA>i0cds8qGr-/dW@3^$\-\Ef2=r#8KU>'Oiqghm]+,<3/S*1Vf$8me)%T,B#C1_]Zbf3!P)_&C!99,%USS\hX4c@d3eGSl^ %Tl.tgamqPohd5!3=Y?o=1;2"V>Ykp#KchL@!m>O;5io%gK-c5!$(&QFG9Z>5XD3!Y]I',CGiHd.L-e6ZWZ)GbUs[-N`:P3hOlCUC %F:\i@:iF>8"Ch(KR3q</qm]S<LKH>gWBt5k2<hqQOj\TV)=U48Ib<EO9i;0t3u1=.gK)n%j4QsPc5gQ'+7dg(R)9_1M)R%QbR)CW %kX7G\&WY[*dA_.95$G+kN32gclspd,V[9qHq^7CI5FCgDWA0G<&YkaLUTO3Jg")1RFM\3'&N#HFb<_LU5X7;DOVG7([.9<\AX:32 %'m^F%88MhU<g@,lcF5f_$k[!\XT8m93d0-&Z(E'DIcDJM!LW0=g`MEPE;CfAmO@i=hLOQpc@7UJ`Hp(fMFbK0=*hML%\=&%^Fu;H %MRcD9D/c3=PErC&Ic0H\)\pr8Fa5SfE%4=NijXQ;.5H0f6HQ^"Kff>)o`(_P:I[AskKnu.W$Ep:1K";c`8Y,F7QE\%,)G<&RXWg^ %g4?oVg9j?aTpaR!ZT6T,Hh_h_miWXO'-MP\MOPQ)Jh%,I@n]*f2b6<BlSWt//Q<\+?$OEoars?Y66unK3eUNVm<Kq=kUE&FheZ?) %`B(g:H70OAKl@U$X:n?an5^Y7gu.P"r>A<=o_6_[NgYaj@h&Cb_j(:7Gt$P^40CLnGfNf]`K$RtmRd&U<XL-+P2+]fBagQrk3ba: %#2WQ(\69M"EDp0"E#K5@P\4'Ep`[?qSuoATdfOf<[:q@4ME,/^WJa6]-:2cX"Wr?<a<\bO0uZ%>Pa&*97-$JMn/F8;I`F93mrMZ* %RpJ+(HQ&=08dkuM)B"D44$!0"4Zl?jf^-mHTQc#tq$n"._]323BtD^Q7,bDE0-_7"`F+YmB)3[)$ThZi(F&,ud7l`DB^bXnGciWm %Z@/=HQacK9/6=Xr2Z<Vr.U_.U,Z^(YkVCIH)&;Yli0qKZDH%i[n=0/ZHq;af@%+>6@-Z_/ID&uT,']Id6k;P52,jW*`*0`Q%XVlr %.Zp3^JNHI:cZ45u+Xa,7@qO[3S)kXQH+'#7@cKfE#Zs.C,5@X9fAX='/D:+E2l@@Xm0^I>;oXM#k`3iK]Y=!IcJU5]#s3&kQ7M)b %o<JI=gC0KpRZ985DbhhN:E2;^9H9hE6UXPfbi!iY,[;+K>Thc0-6r-"TLGAq8Ub?@0pUOMBq2IqKtoHQ.^;f4Pm@\*-4>H1h/MCa %WppZG=X8Eu2'u4*H<-='W>n*N,/'!=*$Q3PmS(hLf<@DuDYbR$FdD"b9.'6!_1Ll)S626k*XGts-5k1L9Tk+1BrfEH[%]8aU+=o5 %6(UZf1iiBh5FBQbh0rp:VP7)J'cG@^AS;HHmp$-rBQ:c?L_g(SR.%imj8S5?QQl[=#XpBNg'74/37_j-JX0kA.L>-rRbdG3Kh9JC %+[>;SKL*cG*e]+K\kQ>;$I%r!A.pu]aef";_[kZ1!^MO"6**tiFC\I9G]F*9aj0Hd3KXH;.hLI).aG@X5ITFMV-D^]6eh2H3hj6` %1iF?J]m@;^@LI[WNt9fUl&-I!j^S=1_Xr%nj<;6\OCFC=P-]1B3UF,'88pboi]cF"/K+Z+`H5N,qk!:pWb8!Aj'dd9YM8qZg#en0 %b:?'>XqEMLbmFVI<(/Yg'gbU1m8V^RQKa#e>l`-sh4><h?C2_N3D9_,(2Y8%buMR(>o:lAGFL['g!J9[WaM?t=m`*M$or%H?=C>J %RjVYm@%tI2FB*\TTD'8$#EiF+78"!,:^id=Jd3@[57%?c?]\/OE(=%r2hiE9K46G-Zmm6.Q'29aj*VIS[tVGma:a&cd@pF3NqLeJ %BHAq\h1-R,!U*j6P6qCb*"gUET_A)%04GdJ!OCH##S)<HEHSC.P01Wk[#9$]EbRjM3JB+464R/6@+Jk]Wb72VMABfj<>4H_^;_#R %@?"%p>o(b'bp\tLX/njKS0IZ65h,:@,S$m;qs0!9h*:?c4A_A_f_]8e%bYKR2.`Vi6jHpel:3n(LO47Jl>Xf\A`S=(5dAHl9qJSI %WAD#1QP.2RW;Sdmc5GRDXVqGP#Nt*RS5-bp?q"CS4YWd0TD%j8H^5?)gfQq.'>raepd#=E9X4UtikNe/i?[ueqa\P+F\!F+[M_tf %P\3SL=e8&N?3Pj3Os"mX_s/SUaA[k(Y,nm9[#C%<mZ=$0:B/eKqFMkA7S:75^D7T!:b\ch8CjEk_uj.D]0s>N[]1i$N?\teQ_aB9 %E+@.d"a-.I_0`f$*#BSdPt11a+iTm@+;=7I.G978,eRVnY,`WjP*A+Kn5#[c#n(TqEJi'Rf$LVu38B##ioe&>!`\I<&sgl$]4R1: %&S"Lp7?hsDE_Z&MaWiq,-H7Hr7LMd<1hm4a$-A0hA9\-&7FH#hf:\1MQWAh#K-E_r[P9#Kd(q//Y;iHB^-K9cL^F.G!TK'a_9ViR %GqW;NHG_uX9I4pWSj3XSmYiZ25tQbl>pIk\_"W,f!7Tb\;/`a@Z6ZELCHPi4,`]IQVTcVL^/]Cur!eZrjBCiUr^RRpP,PqIP:^`` %=IP=j'"3`bq[o(S9qg<i:/4s:I8Zs-pI:H]%Lare]O=tn(]Zt.n2lfr<-'s'm:SEOr*I@:T&fYZ`.Z??\iDk:Gu@09#lF[/N?#`% %e?F#-ZXD![Gdf&I$l7BmU^W-3JAC)"MB6"AoXoMB"=g*L9gQdVE$(t<OQT/`ktSh08>KP(4oc%an6cj*Q3H6GKIgoe(`B`+aaf-j %>onesp==d)<r)_ROaN6BFR:G>!U38cO/EPFJfq@r*%\,9F1"J)'@4l$!1JcB/B4,.:Df$W*lq^urLO(S>("2DR"Z"e-AW>*$NP[, %%LRdZOge?;<4WEFAYi[8MZqoV=ue,YgI7^`KPqMa4rRuV_ZaqZr('g$Vm80t8&L"m?5Nh;&+PGh:HD5s\ccBtjnN$1]Jq4p?)/#W %/V"E6%k1J]J/G2O@6#cg9C?D(&6*X!%*dpK?)J</BJnU-5YSjtV*dAZ#1]CDl&9^A_k>+B\n=\^HC%NW9#rf%!:^]kOk$4BT9QG< %d69!NDXGM[;oQV7bXip:':-`Z$F>kd'V'5(-OT[32QE6`pfWV!Xb.uNSg\5[BOQ_8(on-Z"bu@S]$Au6.l@l4d;K%'o8S6RXcUpN %mi`H"H3-"%;KZ>q\LQahKKbhX<O972h!Y#ZV<#gcDb*Jd,pB=6fecE<\MF/_0QcZ;V'npd2mO.D,)E@ac))*?BXb!M-)Z,Kai5F] %EEVod9UIPdB"nPheVM2NY=.Mg0MmapP""I",e!lc?r=%LWGEKIbpJ\aRl`\04CjBF].EM[K"Wk8"N/X?f$r'F6NNVH!kUbkYa;(s %*%N+c;L-BXo5C').efoZ^8bMc=n]&UC_6h7<J:e$%C<B0E@i<'?j"b_3!q<DJ<5Wu^JX3]S7.<u$Dqt><B\LO9puDF"ns_GI[\Ad %R5QNr-IIMJ#f)OH3iRfSW.Ic%T>&S=MpD'=ihG69Mn,\SGhO$[j:pMuRA+XD<HeE-Qpk!50VE_s0gB>E'Bp*47nse3>$%)5+rEb. %jd<''Gc1-n4KMql.QWm?r.*\X.=Ob*d)f-@Kg6Q._!FFg&s.>1#@0,ErAi9r:5)9sA0Y5,Sdr<Tf\BkUnL$2J!b''FW/WXO.9gt> %5mJL41_k/8r2`?4mYe&ZVZu2oMdr3Fc]s%-T:e_E,\g5Ra>d:S0%\WU;,WY%'kF>iP6&CJoibA^aqc$bK\e'R[<TK//@ODONC)Pt %gtAbP`_ib'pqbV<m,#0oOAo_XPo6D)QRMXb9MMuI+OaG8`]9`DZg"L2F"jRD2!*:1!^os%5h4]o],2g'N*.T!p-!oL_N[Y-qnXs7 %rQ)%&,%VX8CC#iPd3gZ*I$`N+[,X?@Z@pbZR\iI*UT-^D1q\_=R9gK^36tTuc;pW`i?l]T`;-)O#dTOYpn<`[`!h!4.PCg2M=I+( %rG3PR+6X"#"OIb3arepb\7=Uk]Y5-iRDp/qc,=];4kGs]P1_8;qYs,5ER9IJ?tpa!@dr8(Rqm'GDep>MYb"T_W[m@0S1f=]Hn'Kb %<Cr]g!k(ND+JMGKH8=jn=:MJPd!,gJ/QF6OA6;h;fh9CH%!p(OS!"dSWsX7sBOr7EB15Dp"Ek2F%l'PO0q=:iW!rYXg82Y=,Jj`, %%:<o%$3lBN$-oY[7/8/72Bk8D,Uh#[pe<`,\J82I5i.'<Kc`p1d]ofY*nph4^*DV/S))6<l9]X>h?Q;o=-U-@BG'jgOts1U(:gN/ %EM%,9!5&r0AMB4`1,p-*,7`1$-fbuc&a,Sbehlo@e*fP;B1(-nNRFqfLh$<j-/su-#*-R,c;[eK=_B])+>m]QSCipd<igFu&GhW& %VV/:=9=l(4+3Meo5L-W6*t5WQX`@J4ZIF4\$fFK&i=K4+\.k)nKnshlrfamF],>"<#`[9OWX>cm+uM?d@.\tNj#VjAP*a>(lfsCC %45]\(OdDqY^PEM@Uh750+dgFQ.&N&J,#nT36a],*]E56=0qSI@.A.9(GL+:C_u.)pPgM"'B82iOVYu1YJ^hX!lba<[]&Aj_g_:nK %(kl^h3f`Sm%jlK60#lXT_)GqEX7lp:4';_0m'W&$FnO:*#21hd6eU"5"7s^1j0$O(]Q)-<q@h3]Z;"pXL14'Mg<BU+c@n).:gl4b %/pYVa+aL!$j0>W-:VtL`"^%3"HTg[`'Tn[HJ"G7npD=[JjLc3WRlq0iVf8VkZEVr$(Z$F8"icI"$5hdMN"-n2G/t^S1/quu-8_=K %k#I1o$j3'1g-dNEFkVK]k&6,A8!P)g_C;CK8/K'9%W+2'a>[dDpG3G_n"i8TmGViC\k?%-]Tn1VNGsCcWkMpL"T!gmCb(F*_6NC> %rs_pdWDS4)VKV@"(o*Z\Z[R,kmRkbgOBaE(aLR`Y<+MH&nR+;2+*=ME2VSaBT=TSg1X/[;:BMf:1-H8YXFLDg.eBPEIbARl_2W>W %ee\+*ftH]Kg>.J?jDb<W*A7KXja!\eB_t@&-LdIo<mfD;!k5s]jt!XWGRr#6QhO),8SW9fnJg4:U`HQ-n4#,oWOY8W.k$6+L\)Qh %Z(>K>U(rD(-as-l%l(\LR9a]%;<XF>cH5nf&h3?uCFd@*,2W1$!V-jmZgfMe:Mj,$qWV8A!X#'o#pt9q2oG`NWG:M6-LO6Aoq0=P %:%^/PU_^\P2dD(YA^8aspR'A&0rAI+TeukX%a=G6*5Cp+'OeSUK?eGS2sG"tAkAE399k/XSb;Lfa-oVG*N*qN:^?o^#"Fh_n#OZs %b#ln`,VW.q8<`bB-HUV;9(uGp!Ld%[X%<a3cYN(ufDZWb#&#QkOu+dVg_RpgCJ7/,OU`b>g0!JC-0oFfaFIfa5;Z@MF]RmioKe9o %OF:@b;t+9P?]J-?YRUpKVkK;9:Jn[)K:`*r%NpJ"MF.TTYnZGc<2F3TGnkGN,,bjMctMF^."lZHA(:)aJ)HImO_EGSk-7:*^n7il %7Bh\0:_bUu]X]M*P"rG,5Il)B_D>Xl@"Q92@@(U4oF2kU!LO2HW'#D^*uEGGgfB.\NCcfHAXbS%qr_mCXZhLT88qG;@Ue6n"Km!E %&*\*ugh`O'fe2SFF.dQ4/SE4EF^("u-i[+Dc)5!aoI/M20jrnR&pDnB[]CDF9emI4RI1(A+*gT::$5Kiedro)Y[#bXCfIl1%$euf %QQ$!lIb'Gh.lL?cd^/GZLgWErQZH1aIi)XcGE`G'=dfUkPM*VY!qW.Zn]0/4DeI#>@NZ.4[FJ.@-N&cDiFg;B&VfnoFmcUs;*YMO %e8GJPku1H>Di-uF;$XM^#E*oE"UPq1!r!]BI<CDO2/V]E,LuBE0o-E_.0<`J3]"^^9!^`tC2*'PD48rFeI>DO=7/3[Mp]d$qKjWP %7,i+V_j)IsP;r-Q,#RQ!?VK"U"""<@6:>H-CI-sF&O:rm7?cIn^H32PYW@R5aE=4H*Gm>6:+b7JQr2q[/I(>jYu1n2^!F\UZThCL %Djoh<Y+>]ncTc"=Gs#ua5Fc`s4gjp(K1bhO,0TKY:G0u>6\.Hu0]S_9OJ@BQB0E[!^]I)'mMcJ?7JZ929JfbO<%U!pN+!;>DPc&9 %WmT6^4j9Z&j<o&Ean81$48(QJC)c"!i'0os'0X+cYGRh-/7mIu,e)UY$Y+_F%3\20V/RjkYPt<]V>"QZ"_O,,nKPW>76uD9#;['t %4\a(fiHHeA8S-)<<=kKre[sgk5gX>q+nt'Bq7IDBQ_du\Ma5\N:mh7J0,Ffd&3gc==p#TeLeUiUZY,1WJRZ@G-WVUHAkoG9/^H'C %0_5[Hf*``#o'5`EP)Et5aQUn^.<_S8I)g=``1]m#`YcW@]EqY=ofZi`)9gO5/],q1R^m/M/I@IMRVA-Z-0FJNDct1(X9)::9JRmO %8-Q3Kk]EBagiiL=11%;tD$:IG`h$>Y-k?2p;aC/>1Z26m1f*N!Fr0U%3>7,I94-e:0\A/A.APl3M5@I3@lOATm`Kl4'7k%9OSo0p %dC,</FK&>cj#^m)bbL+8VLuXp,@4IPLe)ZX`'[Y5^d&!5OYN-E"[FXZ%Nb>%Z&Uu2@3IWf:<i4b;J2j*6Zt"Ln+OK"+r5Sm;@3Iq %CLhac+a\5?kU8Z'ck#L+S^fp53Vd>s2Jj*%;s8t6:T9!uc>iK@"or&rSG19W,3fT6!-ss68R7)To),a<Has&SH0HImNTq=IU0h1D %8+_)Nc$PYpLe!e-!b=Mh4W9BTXD5'@Fha:oU]4qM?T$FPGcSf<>,[JrgY-.5Wi2Br^GC.7!([9?6VhL'R(E;I(!ptQdS2W]btQ!5 %35WP)jq9?0ds.=4(E&s9TU708DLU(!-tSjHAo?erhS<8M2!('Pf#GilY/@5Th+4kFSsl$/GU,=01rD#&U4J[pODt\/&B<E+RVoXb %fJGRjK#;D:rJV"WF5CH+`e($?J233IY'Gep<u3rAmVPL\du39!UbEEU0"Z%j)b$?^E4G<U62)90CLW234VlFZ`9=u$esu3i'!!FE %_r!jt7rh*j2gCR6SqWQ\Isc_X!qM9JGcq_C7TTSDS<)2EK_`5t#A,%[5\1mEk')Hl1fJC16U^k`6+W-]rpn@(]Z>JN31M\k%$^S" %j@p-sf1!R_E"YUap-&\"kL!4eO^2Z#Y#C%hqfapo[X]@6p\XO,Md2nI1Bi?S?s0g/IFeRg3pH?4I%$U'M[Zf2$l%\URt<$U@r-S` %=E`(m"!j*-B)tTTDBIcb!X$p3md?GI>i1L8pX@lGcqjg`C7H5nD)t#n]1f7Clht,5q,9XrO-VDMTUmX"fZ3Je50W%5OK$&(@i+eT %'c3fHegm,dakuno^1dUiqCW3mZ3&0Kj<h2U"3<Yfs3I>/Z7]bi0+W'U=Z/YrFn^["E-SVR`o"cP!`),C@SO<d5hlqc1,!&h_@.K* %g%a+ONPlqHR)c''?aY]X2r-o$"M+oD/4_?f+_AbZrpB+)KP:A]nXoF%5Q;Olrknd3@r$4S8?3(>`B]Smr:/k@JO?SG0+-'@8:T9q %X'gn,?-e`2/_ih*C[W&,koF*"=u5NNdaV+7.\_[<r@=h:p%Co+:sRJ<7VMu*m1BB\],i/ThGK'&le(a;.MUN0gXA6sA=spcJ^FQp %M_9Nd\iWJM20o+FAhbC48"QAar+DCS;nT$H=cVpD@1["(N)"YPRnfD>mj8+e!q-omkp8PJ92u+02C%+%47F/1B2lDP(ld?>185<? %(=l&kXj?$?mIoIKiY"f2AeT;:-V!/W:FL9?\mHc+FHo6+oVg?k@DH-a+#`QARnn9'>N9EU*8drnh7b_NhP"E@%"#'Na]SBa\i33o %G;CpA$jI"(0Pkj2=U7EIZB$FCj_fa#D7;Z2ABHf6(S!Mnhk.X@:Dk5f1`,u7hed$dU.PIbEo"Mi=q@K,O0CS04gTSd[]HMerOs5G %L%hMDn^>&ZL[LEie!ngU1%f]ec^CT1a#>R^e.s*6=GZl^^T`_/EQ<=\=Mh'6meao)(]OeW1(4Oe.pThJnQkQAUQkPIW!UiTJu9Yu %/^R)NfWE7=^YcWAeA&%TDU2LirDjBaH`;s5UrRos$h.!,:Dua-8%\sbM[htD.j%?)Se%)\7"sLHbIj.!6XA5qX@YjZpH9jUS>,u/ %XIGq'<=4dMjP\G*D11Ddao-@<T%E&58O12j1ZEi_U/aY"<5i:<=.;jS"Esc$G]ZX6Ff+eF6-?CRr$M$2E<'OmdfaG^pO:B^_1t;s %5\X<Q_JgKS9q>[+MGU)$<6S/=g7%/O*5W>D4I.fV3#bU/#hUFZb.s_pm$PB\;9,T??L@@XW@VTO\Vj<O]H*M?f$8BF!beU\]=n/C %_XTGJ1,D[_C:#g,ap:@)QV-=CLAIX>A-"L-f+#sqp&7rul1ZPU"D]Bcb-+'C;;<,frlB>2\2!JFdnm9eF2Hpp1fhR!ZR2YeBi1*C %c#9("ZWh5@<QO:a5g"&J<-$lUk@]6?G4D?Z,@YJf7[(#'1_JJ\`;;,u+h_5OQ2`mSZgSf2opO+)0MB:ndgob]1.P!LC-1?F+="<2 %OBR68D;A%+,P.?Pd\>@8/sZt[@Z5.k:n1>O;JJa`o=21moX29(;&%sj;AZ#cleOgS@WHh%i@"sdSW3qa5)BF_Fq0BZ?@f>*=Cqke %>V3T6n065n`PT>HJ7>cOrTQb&@,`iGGDP]]3qI^67:YF?Aos4Y+9o2q3Rud56'H6aAq9,B#?IFgpnAYM3p>T1c-S0^)j7+!&anT5 %J[t!aY]oga6!h#Q&iCL37M^$.A"9&p[c)n]7iiT=;'%1tjVF=YZ%j<]eh3OOQ:d#1Sn".6Y][,+'\<6g'NWUi3YiO%D`/rmJX@T] %HnHK>r;$@+lmV%f$(iM:-!V:rjD"Rgm'tc!+A52&h4b`[p'rOWDjkknEG)55%m+9!:.hfdnmP_6g/$[%ODU&`@Ae)C[P7Tb0[nQQ %GQ=@hZhYat55D;*`V06*+'I$.eq?AkjV$(jKHH;!^u0_G(I/r[//Si<N$<\9$kt-`![1Kn;GojCbTS@]%NNXU%(B[PA-mJX-5q0J %4tW^D7SRn-4:BV"4I`/'KR&@oD8s#;BXY5QOsMTG,CGismf\(j#?\r&;M+:E(XS)+2T=Z$FaQ_!;*i'5)IoP<76uS3e\T/]L@/`, %jir7'L_V*RO4D@fN-4YpXOo-`a6m_\^U&HL,cPg6U1"$.`io[BqkPuSnoh4P(k^4+T;1fJoe.tL-e4\=O/a^b7?8o+iRMu`J+#/h %=Edp3#4MaRp$e;umuC)eE&TYMgffk_U!*_V/_d-;9^i3BW[ZUo'#8FZAXR.pn<Z)KZRD^OS*HlW`#)/a`j.)%77o_M.P4@1:WD$8 %U'91u\+SdEk+S6inF$?nlUaOH32,qZP!\9V64/"PZ`!e]V+!`+KfV2c@1&0pPJ$F9,q:3q-6gC5W`TIAs5!*`[]_pKD9n;d!;2J1 %9$1(5X6+%YJ<eg<NP,g3mAI0^:N,mApV%:m5BYfaU1p\b'*6U]UP"s?^SQoi#jl=K8&1_8TnbNcIQ8+X/sUI&,1k:MFrr+kF;O2n %iINs!N$0K:#>K+cXoQ3[lOK5(JQ?5@#;DYRXbZ^CZJ'u,5un^(`9jPI-&uRoP5qZQ-m:ha+mjeaZ]gMs;Y4dJo_H.V/*3Vke>q`G %<PrCi840")PRL_<[@)tV`Pt;f6tEI,agmLPT/n35YPFX5@D!<\ne'CI*b4#9RGWfqg2-*0mDG.6^@'mKKg^m$+-'.a$83ouOI?(O %mgoL&7J5083K0j-IHd2AYf`R>,!Nd(a/:I@=^VEQCmT4)"TJH])oiTf4,8.3l]Y(<dJc_H"#YAIZT3W#C9d;n`;T/ucl]IK7R07[ %_"]u#8KI(7]bY&(&.VPljC9`&E&VW*LH9b+pk@/n_`<=d*JV%jah]1nE;:#rLqE6`8T+dpO;;9ZrB4Ks'T6G6$eM=B0mtUIPYo/t %**(hqp0!7=!lWaOO0[M])'R8YA];P0-#aP!g*<mZ6A^oCa$oK2=l>V!%JB7+%<4__%H%9jit$-ZfSMfA1><.aVuW.U@<9k!TCiuN %3I'=Jbr5\g#>aP`&;gQ3cKOX3D`s/r:$,YP/lubG7Q@S>GdftH83,c\]QscS(N`WD('#>G"T+?..)o,AlW2,eFsNWL!QUDl7-1`V %g6=ESe5.Hi*=h18,eeP;UF)(i>O@j.b2O'%,T!5c5f'Rp(f"bp?dGK)L1!kaX[)S7`(EH7j^Q)Z:S)@EfI$bYBK/R127u7!I5W/( %P\I).KQn>!JW/3Nc,Ze@k);9fY"DQT2CJ$m-I+_?F/.5BAW>(u`nH;#X\FCiQh(H:/@e]T9B,'/W!?^=J%qdR)8Gg#";6;Rnuuo" %A?dimPJLGRs!'"KT^AF"j!CL&<BjrH05C083XF8^($Ts@mgg-173g5+,K$+LpehjlQX[>jrB'"sM^YqDpi<^B,#iP]oI$-48nJ.b %K6+^+BnpkS/2ae4\Vd'UrJ.=`%>?q^;8[d.6A\>#ii>O[E@(1F4XO$7<qJ2*>E^%;%$;i4Cm^SW2ESX$b%ld7/FbJ627u/PU6IJc %p+nM"<*k\e>u9p!6G9_;D$7]4(7@5EWh\&GEOpdH``IX!.5C)S,m9f8]F#(D4$>B[Lg[U4ACD)1NMV<2]"!=pZKf>Z?lJ?lDI<+8 %4C!Z(!Dn\$mG4!l8bm@CBulGBf&=,m_3/!ElpFQ-I;Olm%SeliV52C8-Vj>u<*@]1I4'<m<Gdd69f'O[OipL]Hl8PM_r&_JF"de5 %A/N>o>Bur<[=M6cOq^'.Ie2aC&/l"f1IDhEjltl6g.&_MS(W1#[;'GcU4u*c8?M)')]];m`*eG24G5l0nEhnSjr8OEQ`n,rl+@KR %U5@G'Qm6F]9njSek2:r,Z=)Lj0QFZV.Q,$sR%e/+ee2iW6q^Eo%jd?,nE[<:h`pf:A+$M%c"tp6fC9RaK4H\gP"4=rh-$:F;5SoX %U?Q4G&![c,itdgIeXtr:,tW]aAkDu0e3"a\;n%TE,gmS8T.r=6n0FFkm<)cG`-)_Bi9\PHptJrg@#Rtq!gMNOd%jbo'-CCj/.U(p %*pVSI6mG`2L)Mfu'Dq7',!#WX2E^2=##>KjY/N[@#%L8tSmM*m^iFI.8Jg)PdkunZD#['u\8Dcm6U890qVIn(ZZ^P75*WJuH4CuG %"$kn&/M'4<qCM'B0m)X'*'a+!FPWEj;*;O0I+V[#CFVMkA.ANY6.sAb1ZO;.s,!Lg>mCcP_Ak#M,Ablt_h7i%m_O[2<N!fLO$a@o %CVY%,(X_!+a/@O8c!3KApiJ@#iH4q^;"HpDYfjNY;\p#hpaW1M-jHKu*nkA^Et`(&C4V&!Ldn+A+_\73,V+jhd86ll";lo!8#NT^ %<@'CK%7554pa*=`4[nf#.F5"c0.NN$Pb>*X_H#t$5+2#U8EcS9*!)+QLZr8S+87UjWnB@BjqqJ+@V,H$-"bT%WBSa+id@`K`W%]u %3Q$HLaU.U6/@\X%e`(b4PJG:L%P%4FeSOc3;N2MH8glVcJML0Yc&bMFePQ"J6Dc+&D*r_aV7XpjcH?>WB5.`W6+efaD=W%BVOGTF %6[uj@<m:)"r?s`&<>(Xs=Qf\>+.clsOV$>mgaa$`Ud3b8U5Fb1T#*,WaOiMi1PNa4/ZH6:]2r6@'o1K(=,FWnQN@9fLEtR)*e.E( %oaVupnVfkY;*k6X=A8Wtd`UT_W)jU7",=npTc=7$n5K.VI$,fWgoE#;_*U8m,3:"XE"^BJ+F![^^H#;RcY>b28j^os)"X?UX*3>' %&kR4Q2&Q?7^<B/@]QS]01\Wb@a1]7Jqh]-lU.Q*BilS3aAHk(>p@!)$GCDYJ!GWK'E+gD$@\=j!W^8+k3&./M2G.Vlkdh*I0r91e %^_QW^7gsP<+jR:C<W'b_pEBLo']4Od).#a$iXnOo.RmTbS:L9Ncls,Mi"'[!W,b83fKkI-nWOTgpibHqkMNoncD2$h$I0MVC&p*_ %LDj&pP'.9lM_8@df_$EO@Ma&G4Z"fP3BiGbAhip7%JpVr7@m5bm",?],3SSg30X4-MQPDBaq!UfDR1[SAd"W:a[h%61+,oC[1YiA %;eilMMhZ5_,#"nhaQ/9C`-%@EYjXsU6fSV5Ha75IH3q>1gGebYD$57f%Z6]O[Gj;kl`+kR>t<"Tf0'sol#Bok!A"s7`V]-g+CA>0 %Vs]8kY+`9l8)@%d$h'4=92;C>d])LR>pX2+,456tFrFgVJ!;;FWWGKZ'nQNM7Cta%?8S`K(6D'gon4;'Ee`<XO$ZZL;]/hnaI,P" %g1DE.8P289:ntghhnIq6l.'*]mSKq!CB$\@i-,\d1mJ2_pnD\>3Rs@dg^R5S!ip_I`Uu=U,hG?pA0%m%i?5`-_hO=3T63;d/TkKF %=`2.R?.QE+2P4[+L[&JlBZd.C1[9P'3Jk9Q\#Vr4ckL\(La0<,afNihG*+*L`CU\0;p^'i8KP!Sq`TP2(hjG&=Y4B]#7;?G"e'o1 %J=YDZfd5mm=;XO_p&$06fD;&/B)8W]nUB)W#U_,'J>iC&H-HOD@gpCa:^D_0Tk^N^[5+SZ&e!)l=8oM:/O:<eV"!`C-\;#n^h8'' %TFSO:R^s&9,7hfC?V*oXb0?pSlUjsWPpH27CfT+dAa<Wn$/+`H`'"9uVleZV9-Esi=A2o;'e]LS`BaBa"q2i\L5Q(bnp=I@LhO+! %ORn9]Yi7/LC#:bXoPI2aE;i\GEN1"K,hnp(W(L'B07P^7De=mk'5^ha0nH6`FBJUgq`rj%S0qrG3.Jl9X+=-+l![;BVh^[%;+./S %73NgA;C.Dc!N>>SB:01V*B4DMY-&&g#m_=&$G%e$B9S>J\tLk-m3.I83XO0uM\*Fg4`cDk$ftic9J0;Ua=g<ahQ\sr<:Q$3Y0,&( %r@DEVoj<4W3<ej=>XdKnFEj7Jf)jQ#NH(P*hE9\q@PrAmQgMC>L)lAWq4`f'>@u?.``Qej7],0qFdo`m.PBdrbB'N>/L?^ng0ki? %77J3s&@1).:DHH`L(Rh]?o=/KTsi@q0*f3]*a5I$#TFZWWQ70*3/N"jFSl33UEOb@oQJ?>hn8nG[b]8;'@c+7mB](X'X#s<ZfF<) %MRa`QJuV-L-n9,!5NBe-Q_7SppDURCe]WY,7D%(da8pZ185c&5=B$>,:i^T#a=hI=l*W['$4k/IBW%)MFfcN^B^YAiGB7h8'F<d` %;6EAAi".&sU;G!I"b]rghQ/<@EXhR:(O_H@mMN^)%NtZSg#@fk<7Xo8&`MYN\S)'BQ6qdZ_6Lqe0&;2Vb(+uUNW=k8_`M9X\gp<m %C8LU(Lu(=+QXL$71B'14fHKJU8]/][5.$6=ijh$KkE29pq"@b^f0oVV*^<BPG)/]^qf_ksb3TP/b]=KF204<nR@:+jZYAR!qq\ES %,,nMg0blnbSLZ>8Y6)'](_]7nR;+/"eN\<WU7Q%5<WB8!jE[haWrQ"tBO8&@&U_<mE7$6WRr+SUaeUPX>8H-R,r\W]d$/9797!t; %=5$o#gZ2g_5>Q0K5)k.Y6s_d:&FnhE?>p,?_G0kKZpo/T8gq`"'jn4:,n$-BBb>,adFePL,Dd.dkuKp1Vlh.11m(=Lf>HT..k2EX %Ls/4KN$Y_V3Ff@DX[_m7XfFlu<=Dh?BX4"'n%r4-P07u'[?,&mCj/%j8@3E+&lq:U\b/<$f;=B$:mGnt27ABN5dmV5`%'UYQ^N"[ %Q4G\*Z9ujNVrEo(s8#^\SUF/A:Vhs%,]3@QV<I=kD>UujB3"+8lr$B3R$*caS(n:d6^dWmgTaRcCAjle7M_n"RCNSp;qXQoMutps %8FSKVZ.b<I&rV2>jM7Hfe_KadIk,$saWmMJ:mZs?7tb(hl:8rOJb6`Je]Gq&i`r'Ano'-K6=Z-_S1`\nFRLSThX<YH%Orm]=O"kr %EOc.3O2EYDA)Ijt-CE%s_\g9_0BGf\4>iD`fMFo-Dl>D;2RA&"\Gd8;Z`a25aMe-L""AG8qJ`OJV<&DshID3A_P\l'5Nhc\gg,Ck %oNaFd+4jW-bB;XOT"Eji)?da'D`.JW)Qq&k<0KJN(8ItsRbrDjgQ:qhVR]6a%)D])0tn#5R($l1pr.*?#/+jX$U?g-)?_DRC)#l; %c%#"YHa9ZYNHYFtEdb;T8,#pS@Q)$VOBsACaa^U-lSY$-d=NpP>@UTn]=n'uos=PB\V.1630YhUnl_)^.dBHT9m<Z_VVFm"\5fi0 %>/Y0Vns=$B3aJcqD9T#T%p--JD#/>.;ud+mXG7T-b/iK@:<7t,4MSmOgdf#HaqiZOb9+.AWOqH/R-b^55Ge(i8%lTP?IM*IQ0?7D %=7Q2,0@?hcYtPhHBBJ]KATAkF^DCtd3.%gSN;'is/&<1+@pg3t^\\a)qU<Q@BHuW6r-'_PHTd;Z[AM+ZC7!lU^&Jd5ps3#QJ)>CP %*)gh\;=fmqAP*:?M:jn-QX+FRUb:b2d@[:U6$KZ[<BdQF.[YD46L3FH%fbqO`bb(ZP.^3!A)j;hc#p]-YKJhRTOGdPrm3O6J+VRb %&k:"[+^;D>hdhJ-8">(Jb&/0I,n0-g"R^(nQN&;u@e%Z8ZCtUr\iobPH69.i6Xsmb<b!bCIVgRI=1pI7@jn<oXicC87;Yu%]@sr[ %>cB;]Zu$/?T3J)D.l]K8pta8c[)V];fllR;5L7d#=+dqkdpP?pGil*D)KXe]C[:en/R4F:OhTI);]9jtA&nH#CTOW'pA8Q?>V4iR %?13rX_:0N6XZ$\QXjs=,=B]&'S^u`m,Y'[MH!94hGb`d-96)+(Tbb7;iDo%efeB4+)Q'$5NV]Ng*ib\6HSX?Q_7\C&S#7]q\(*0c %`bV&5h=YZ"n2kU5TkFWA#PD=YeRhZbIRCJE7dWib>Li:^)iP#iEgDbdSU(0B/G'0S?ZXJ%g^gnKk:blm!S:M))V&Ngg6KP1@k=pL %7`(<6YhlHNle?l38oZR$.E*`,5TB(8^"eHQjP@60WEF,qG&8m0!8$5(*bs`D3GPX&QZZ)>h`UA-Vs^0R<3t$,-'0g^q\]/d'n(L0 %H=cPpW")3:Z`CM;V3fI)o]R$9q!NT=Cjr%#A4H[T&s*i0s&F"MQA`-nLKFp;]+&VK6adD=]:F@LI<]R'YRe]iQ[eQ/UI+R2+anLH %"D/k]L!4='09S73HJ8IX,j)c9R<aXNSKa[IGq&Ka;r.&R:K$pge[l$^Vo;R#=mQM*Qj,4D9@HWdl2J0THL?r$2<L&I[V:^m'C'E< %`B<T>mI338rFBK=a2H!cL!H6oDVLVt[2tn7^d]6$s6+WG8gQghka96U9&"^JmEr?9ra^3dJ1lEWm=F=>3dm/R1gf,!)=ncknP!Wu %(hC3o$4eC-=$80c*`2WV`g:n@]/pQgf5\]oiJKLOAahUaV9A.8gr>f[V:Fb7.@3[LQD!-bnFk3>FqB`fA,?9i&!"GKE`=11YP:BT %\g_.<`)EA;LSg=m]"NDo07+\4kX^9)cP86TQepKqP%OI^[teE(AWMU?5NCPc:/L)>>O4_2ATNcXfXC4oh8ZV`*:6)eV.D.4=p#q" %/RG2rhIMll<[`==`P+gp.fZfrXjPrX(0\9J[VkR.k$>jPgo_Sg/*>)>>I&!&R;.3:(;n8nNk3J\?A3ZkM_Kk8J882U4GpXDk`GI& %o=M![Z`^uV*kIVJTqg4mn!!(1(j>It#qptE],0uLQU2`dn9m+AnVl:o^JXjjpU`VtU9?C.b`-4fs(K+*S$P::,sqVBoKe;:A]3[' %[8R@ogXj$;maKc#[!_mUQBg9]:s8A#WMD_(qG_(YSj)i@Ej*aRBpnk!^@-,![KURjmF&I4k%&?I=0sO\S&N4hkPK`sK`9I-fsXa? %lJ!3bq\FUN]M?t2Vehi9d=(TU'Q2-2f5poXiVTJ=D]PIiF_bidX$,AeK"9`L"VbDna^%?KiB$jSb8+`Nr_s7u[Rrm4bsmsUG.gOl %-/Z8h0DS._DF_UC5qBG1%c?`$k9,`;K-fu.3T%!O`pUO'rQ8knZ(4ccI=""--G*%5[UlE(DJ\;OApPP6ne#?fqfc8gn_EHAe+`1; %-Ku*I>0jl@qt:4SrRAApXs&<gWD5B>\gsEPFqZ95/H4D)Oj]HA^UfdW1e-m3*e)c5CsSq,]/U1#C=9YL]ns9(TsjSU[SLDJ`4>8g %LFL<a[L20"(9sUnpE0;0?Ip_CM0;,VE2E(gIE?stD_#$j5IYQWP0o1,L!<mof+M.Ek.H+fnTDIY'Jm)m6.9>qHB#2?buS3:FmKJ[ %(>*5kDA!6T,_#cu^Md@uY.qLcb8qIngfd*[rE\4pQL*&4D\KaA?M-ZPFg!-NQZ1E>F;pg)9C;ThmXAHCakOa9`VC)XUQ=;^fGj># %l^CJKQI+PDgIOu&TAG"^a7O"srP6As;fi<(<!9B:6YSHe.W+^!a52Ae1h5Eoq[r7=h.m84rQ3tL)IS.>bV,2l,h<?#dIX38kdLiE %3.'#&J0;*@kH%D6]611#5;/Zh(^68aGA[=oXfrgL@\`DRmDA5_G4<lWp+\Z!qqoDe"Vms$IU3`H0q2psg&6+rZFd8`]9:WQNKn_E %=391'hLWHAn@jUOpU\A\_K_tsg5FTlV!$Jr(1ZYLf6(X4FZdc((,UU]Cm]5-)np*HPp?JFk'.;m-22e3[JSgiF&NIOD(JE+9_<b> %UJ5m^48h$3>\-).WD-C(^>o$;0>mF[e\?AJ`j'YV4%s(-MC-0sY"*@H";V[%H_1mt!QX=\k0u6WYgj4Z9.QjQIAm3-\"VaKhkbLC %j7Vs2!'!FNgDAsq0!V34oL2,`gigU\=[fcJkpS#Lrg1)Qh6pa9U\"Jc*Od=qB4_<uP,pr9G]pdZ@!b=?Hq*J&'8!#IH;tA:Mgp6t %`*$nY^e-j#<E1!u/3#99e7/\Ve:rRW3Q!7FK*77&<-<F5,ndp3`=o2t6aN4Khjc@81tNVg]nnqj<lK<or7RudfkfSB1q4%B^(=Q, %2cmSKVB7'MR>=&ThgUb3>j+g[CT]DBr/Rtl6Ck:0e<3KOn6q"n@WIgPq(1oF"5bE)UTc#6Qt1lW#aicRFd`ST+UfBNkGQ+fDOX/i %Za6j%^OP*U3,Zm0\96A7LCRbI"CFEd@Wei,VZP(<=`r9<\\20Q9G@Vs;cYLp8L"#oTo+1;)j]P#ddbqP(#uf?@Nkm_J]Q5^9],:/ %g+6Dcs#!G;ZM7h+<h*=+r;H4nUJ*EgYK?06U&qTt"Am>:?I`61U1/+X'&.PPq%#_dAVR-clBQIlm)kP[*:#RZV\%AQoeJDg$p+j1 %LQc`jmB]tj5bs67RlMD+3f0C2CPA:/KPBiSIK-`WQeslF.Y,f&'tm*aX0NV%`Dk4d,RG"f+`s$WYL[7;aao57d,baXOe/mZ*<$u` %D[D;$rNV\&]mGQU"ELR0G<cj))shTZnhfgM*hmtLTQ=b]p:T8\8!<`%eMd[!*pLg2O:)T.TVtCLC,>712'(p,0JPb^SYZLj[B(i* %KoK$;&]>geR8]M;2Q#uaZ>sBqMVX7%OUP2JmS.N,#.^tp=b#)SVU/Rp>^%Qbd<=3ArPLNB!@H'$'q_4-H-An$Jt&D2&$"5--.kq? %k`QS5'GgrWX&)dXEjh37Q^'u+!'C`pN?#e8J(59*A/]t+5cTSdX6D"T8WNRJAk+F!=C18VZWbo?m7DuNi/.[*25u6%B=X$`DEV=0 %;E3h?MFBOn:S7BeNB50$8,KT">K7V@8s#`g_#n#8U@O0.&;D<[I&^gS_-%urb^*IeU;YBt.FXllmaO`L+NXk47!OOlKBTrK'saqD %o7FQ?;aV'mo`]jY1`D,h#FVPec8%S3h9/ja,SHO=,ch]jbL@:=faQg#_/.`i,YW&*(/:AEmkEM',t4cr+V,>QBr-m2DPgdmd_hqA %js;Hs9-7?fe\/$p@EGR>TcZTQqp26*LH5UT9S#4/W6"/do00,.j-:WuDY@jM.auI!i3j75AYN=+o1b!%HLq]/!.i:L'M?$c^KKI5 %I,)R*$GWN/n=6X7aMDHuYUn_rLI;ff<*$o\VcS;op,5p$]5EkjNEd/b":VZr,EKRQWnuNq/G"'6E/GHs':0;,j,;p)l",=P82L39 %2L^%"p]mW4!U`*'m[@CV%/Va^?I4iqnD\6`Hb)K_3<GN551GN*3:_E$pC24&p6lihWQ#s2,CPi[?:@EL"N07F`J#LEU4&d46lbGG %o4abS9FJCW,/&&">/;am;@aeoIi*TI\"Q'Fkp7=P[pZB!)3/I]A#h5+QaJc87P1SE[85@B?h!Hb6sg>sFj\_Z<t]EDP!X][oMMhk %onn4(a>T^9LDJ>$gWfGur_KV_Y"$l1(l@*NK-8C')B'W"%cgYRFGpWYe"O+ukM*\QGP]eI/f_)56;uqGR@kNt!f5pe_:Ffs?2[C: %"#nmS#f9;#0U$gk?CV4>m0d:b=s:[gcF2B9c>"OO'/)1L<HQb-ra?r-[NRCd[e%@Y1f_Hqg32:&rbs`6X1mlm6k*u5XKfQ&$^Gh: %X4AAu2YcNKoBd>WIJ4*_(16H`&LK1$o2`64q5SId'`t_kp*%-"gp6Z`$u9'&\?8&$5a:9/[O9':DNu#h$/:&SF'Z3Q&=jl7D`6I$ %dF3<SU4ZAK^Dd_pL(2_gp'nb@`XH1_Z#5/fPEEVb?0?+rW-AeH@7OI_L%!W)?ag^bJS75k^L+2[eEq^f#=ae9?15gHoF:"#hpJm$ %L>ZduJPFsukIsq2TrB^&D_'.:EnR)^,eo_(iJf\+4S/G6euo3OGG:AM]5*A5KI@5\``*&R-!q6U4iL0Dh/>nli,T8<G;nf8#@b#+ %?$XdsXoJNM7M3cX599G$5sr9(K%=aCV$Z[/E2u=.cSB`RTqbkI,+2L;nho"%<spbEEYFXC2r2L7kA6!hDB*fQn)oGYC&?DI1?>o' %&Q>fTr&Y`sq"aa^r"2WQgN3rZO5+YP_/D]4AXeRH$sqUk:#H@T61j<W#%Pn\Y6NYGS$D&#5Hi[p@/)A6(9^pq1"C?)S`TZcq[GkG %rM`j>ep3#*YGnJLU2(^6`g1dLMcuB,]oBS\-!8NB^M7Umdo^)ubOlnGIX<O[gR2-rF^=V@h4Df5&Pjp!c,U%PBZ"lIat`at`\'94 %GQ.;MIUDW%Jp_!3L9+Bjqu3SVSM?%5YB=SlD+2E7cVH#e2e5L9^"r+#4KfI/Ji5B*S"?hmqp\5dg,??e_4%M]qae1Nj*1&pgJr*( %T2bWGoniFt%5!\)QIU,K>C<:7\ZJt^2A""h+.$5e<GufVH*!ihaa(Vl[nlVmJlP*RG#)R_%_C!(c(n%88fu+,QT]HrC6#(FR^"6\ %['h+odeD!94?YLWr^XV8R=q\2SBBaNRqRK971TE1cqYi!qW$@d[WMjGajEUM.C(bMg'?$a/$#L7\3IW3-?6igENaN]7Jj7iAAR:G %AC=$\,r_EI8;tqkKc1QUE7gkRhK$:_ZV\]rg!'P$c-8PpVDHRbU#$me;JgA3V[6*+[0L+\:R+L[2_l[83^d:q^OFFEHXZTANF-G3 %XOOJ&2UWqOg\K;35Nr"Ark!<m(aaL@+c&ME+O-qX^o$rO$cN^)ITM2dS>^n;VY2.^Jfh\WcRD;ldC9No+%&/l,W/YSO5:_/B*K.H %#%j8sS\u$'8%:VH?Al>^Ee03Y_.n=C<kS4NN1s_j>`&5]6\<EeE1^[V9tSt[=s\J?C%_"q]$t`79]fs!bg[&D)fe5Ng&B?KJE->= %1pG"UA0?b9^P!94.eB5qD*&[BfW?*B&)m,<Da]J/a^ld?>Beki)LDe]`W`1(FunnGe7QAJFo*.[mJ$1u`?<iD-Is"*&T>G@CTMd6 %\n^:C\k".#RH`[OoR-UTimuf_A:+6<UdBT7D*j`g>DVf2%J&_hJ_h3GF/8;`Bn>ehaRahjY'%S0QT+YC45`3M3HeBehW!'/b.:SJ %FZW-:$PUJ#(qG0ENTlXN!_rQ?\)9RH`4P<K)tm:d"b5g2e/RNSFS5NRhXK4)'<rNrgjP#bY2A-=SSu9:fnl_5'EHD`!r\)Ga)tP$ %s'6s&s7Fs$b`$\ZlT.BTlW.K)hBd*J+AJtV!3Qeuep+l<qqUtR]M4(^h_f=N&`PUm7Q7D48p1-[RZTRX0P:oNcJR51(en<-D;E5' %<kKch;p,@KlUK+KZ;"d%1[jYsVM:G`p+ndOOuHCq'h%BUQ!1Bbl=`Wn*q$T[QQEFY:7]JqR"J=*<4?d?b"?.RdcG7tI+R8m!5TnY %>GNnJ*Uh=.?WEA$Wi+![[>`gnB'jIta^Y6iIX;";fD8nI[%=e3QtU/qQ-Nleges&!F=I1!'RYU,RLckMa&t^BpS=+Yl^"e)95?/> %$WFc&(K(VC"Io<6WVIGMR]#V%N<Ii-]NVI1`\k3F'uOeR(A2q8_rKkPk1XNTf/E^^$bZikT"CJBg\ZE'&V)3^Us[gYMtWfGq0Cch %@MS,"gFHk@4;NT7XOJg-inYXZK'IPJK"<H3l`9AXPlG$.d^d4DBaYO"*8d@OQ;75sEelOBANpX,bI]jpm3lo,g'i59Kg]0^S+g=' %/*HKclEi([dZ8#im96&]Gil:8Ba#ndBgQXD@$+Q$>s61>[OU^0dgb-S]0k]1#pddlgO+^HG/qe3huEDI'pi3T`PuGl=50*ej1a31 %(u+^4kGPQOqHMSD`%h],s.O5&\4SiQ_9$\hk8F'>]BPH]kfr^G^LT.S\ScSD&0>>T6?EU)lY5"&i;/PQf>uSblU+.KV<l500jREu %mWIFLDX[(G?!'D)6]_&GeY4=8\nF3XA)e?GCN>NPQFX/>&M`MmgKJ:umd7uFY5TKW#)-<'_WJLVIN4fc+^0H&4joaZ\`s,+VgqFV %r1W;uUiJn?[6N8Cf8668',#_Vg.VE=o8t=>=$8T"V&!Rs6lW<kY>=<iS=?a"_X:kqrO1=55!AP51W2GAl>DFa>Z>3pH,Eu$TL0Gt %_nh"c0>STJ-E6aCPq>tSlqR0o:sLtqH4>.3.s><'7^Rn5f`VqbJ%B%q$3:CDl'd/%p2[>s8OF?<G$H0e+VoM09#3HE%MLDUkQcBi %#Ol-/?HASD8j_U!QudIbe*[T77""lMP3uj`1*IpbWuq#tM!1O]NB"I$d`B`I$DVjI>6`gRE@=*$8b*QF:sEnEeHD`PefuG@c;1Jd %ne;]EaEZX^;0iBIA)mqooQ0@#HLmR-[ADrtD.`0`'%UiXqln,@-ZV')"E>&R"CZG]UHg%[285c19OVH#Eeg,$%^BK)1Q/?*'dXb$ %_N6F/J:A,^JDsYkR\Iu"MDu,hT.^7(&&J)D40#i#:JV6;0f&r6!30R:jPuIPOfA'@S*S0/H>A<f1V6@[&M+SQ=D1nF%hA'r\N8)N %W7nf'NnROCl2E#\9m!q+DFI>&goB*-4;JMdL`hi#]h^9`F9Mk33Q_HV-hS%D&$l9HeotbZEG4,RP?dcK=1)36Yfs8dQjllmRTQ"@ %QA7MlN.l5B-Q<NMVB_[OYZm"L^8^*G3`THTg!V.g1d)ec(,_WflaH\H<d4>^8IV*=PeW`J,k^+5:l#BAGKrs;RWp`@X(6^^o'';+ %+-bMUp!dQ&V_]0g#ouO1Y`Y$M:72qCd_#?6<d1;;C]i,=A;3s@JOsJ.VO@]*kt0D"$k"rKhTk?(jK;K/!+jVO557jEom*q,W$ZuK %$q,TY;BPQn#n>0YaPgaSR)DQFOjH4Y#DHD$KoK3f9+`@(+#/$=RQA3ilmeDi.6<#Cam(a1UHYo0RqNMi7'2AV"kX\T^A*[8l)NF, %,eD8mP'q)F#gOJ8fcdUBlXT'Vo]WN)FGUE:1>,NT46GQUK>_NAC/4F&0R7um9T[F7$4^plb`Fn-5j*EqH1=jro:CrSJ/1>unUgk2 %_;A8hNJO$9MEV[0Wk0r+H;WL*pm]2j5We6lTGp\dql!<PTGgii!HG32W,#@!!8A"OJ>([%igim2o=Q!Y5%NNTTI/t@6,W9?AXEsL %PV`=P]/u=t<^$)CUPK-ohi:TBA.POuP<n]g[OR6C]/>-)*USSI/V:DjW5<0@p*iDE,oqsGfg-(1`_qGbPCC7kBs%KsYAdS84%3'A %Lq]9BQ_IL;&HD0^r*ElfA_V.S;7+g-*lnA4TH&Y%K1u.f\,rY[_b@tu"BTn,o8Q.,q[N4[g9Qg6\q/p=Rh.uFH4?HcG-A]!L?Q'I %1J(SMn.:2)!:>U7!*7+48fkGC]dNH']eQL4U]i-*<A_c<B%E$'+/c]API"*_1'>Q&]+gV'd/g7^km;h3j>J*@a^D#@:POJ<6aZYb %o(tuFMb:11"8-CI9hu.-DC^UHDMj7X*6oBkW>%2;6,r!R][.IrD3CVc.tb&,jqW.EjQB[,PiP;C^Vf&]9>MV).6$3E\JYk$?f5CF %TcCRr.NAJ1mGG;H0cLTNH4QYGl.]O&)'l]K/P.6Fp:7F\5VA$R?uHBGJsbAtEYX\0"H*V6NiK3E&.gOS:&XAH+l->V`/B3a'2g8X %=`LOj5n8&`N=Y\gPR]H#!sf#k%XG7530@$RU(=-^*q0)tFG62Jra]tcA@#(H$c8ot'7d4W2fFgQnXVJZZ(MIA9Eh*+@HU$K>4!66 %;ZrL^nNB=/h1`[8Qak(`+Y#G,QPn0aKn>],`K[+rWjk5JMtFMil*q0;.m((Bf&nK..6PIb$9/)-^D`RDL'n^(M.UZSm8_*Kr)N_j %&l+MHYcbVmb/fU]T.j6Gf^%KcU::i06]gMa/$<mPA,#4dr\h<=r!.%QJ:#'q-dFW^TQ+GfQ30,N;&s()AfFl<DQf8E-X%GdY*pG9 %+T)]ab\eMn?)!Fs84[ZV42b2P2`<G/*5S\r&quIcoI@l"@lJ2i][\1"M7:WI(j*)oL_H7(1^.b;(/rF1oG0+hVuR<bpGppjYQ+OR %!PB"9>\R^_r2pQC\Lh\0PQh7^':s:YqeF.kE=V1L_Er0JC$N^J!69p^^&`[o8_0)gE%4$S.N.M2"M$dS]<EN]bk,?_18if<F?=a: %Amn)&Po"#l+0?sXeqXdYipBa69ba/.BSpX>CFBN':>'K4TdTn-j7h'*;QRa1Y2uS#I&Lfj'Sj]o?k4tB$;96S0N3'6kWk9d)A72o %7nB"4*0G&!fRa0*P/[)i;tXUlF\lP=]_dQYl%p4mhOt!''(=a$EMt;3'E?^.3Gn$qrn(ML[\o(ZAtE<,E#3U4RW]PY'gQKu:FHSi %;q1B[%Com:%`0VJTD35e`G+I;Jsm,[3E9o(/1BZG'\Rt23_+5QPF=9p3T0=u9akb`aa(%lK^>OqIufB'e?afM3_F=]?64P2c+$r# %U8g38h1nlLZ(XUnmFsB>6T)DXYW]sF'j1XTG#`mL6fM7P=@1Ee=5N83V:oF?^Wg$MkO95=LA$_Zq(=ma]R#@-;4&oeDAM"F_%e$3 %WSTI1$k/ZP.4aR.QU0:1f/BZ^(t&ZK:YC\]J=AYlDVEc'J>DQ=T*rn8LX#pf50X"=\P-#/AZ$lqkHJ^6IuAn+aY:\M-!`m)QN<DJ %]8g=c5;+>QKI%LV\rbV<7If+G#!t,-rHRq1nff%34hm[mQTg`tD;qZo`5b%=TH9E#CY1iCS*#If!`I$dTBGL9Ad__(BNKqXA&3HM %fkUgc$tgusiG#C,4emu(nP2?lTSj%KgM(,S;^J6.Glm1"N7KrKA-"[`+9O_n=\se"j5@rc+UU=8"rIA&6o,cLJfX4_M9NC"E-+I& %<+n,rcnP37VC(%U2'E;=;aW8cVnOYjT&!>(-fC:C"Zt7NL[48.`s3K4XHH.+9Uo.FE)W!^_%c5fj1P*c@WDJ&BUF!\8_r#nm"1%1 %6A.dEQ>\SLd>;AuOHA:Nc'*=T=a0L8;oA]XaR=GD6Z6t'ARLBlY@]+F@$QLF\6.W9s+pY,N`q(<2bgpS'jSuN(C*9h:2de]>PQD( %ON1'h)N3_ur1`!tCmrCsFEZljP=TR.#/eW`_c#[?UCV^_H9/+R07ncEl:L0B--hsug_<8UO!sC")ZdEogK5T_n2hWX3n>i/`6E@F %$%882(D$'$lBUOtY<tp8*O+\0m_[Wg+j4KtqkeWb%hac[%sI6uq&DW8TqdHUS2HcJlI6l7M8^&4CS:2Zq+[;[T#^%j*/ko:Pi%9b %m$USkk_p&Y\i4.p'$)5Zq`:/Q%F[q929RrLZmq9-eW;9jPEiEM)C3M.)Vr+O=Et6>N5jBB`,t*2:\;*U!DPA9EU<AUbU+?144)%: %U59se.O@S2U%]&Rm*kG9V.s&c>$#E5_1.N2R4BQ/?k$tR3dDDO?*p@!>HTm.f?IV`G,%e:V2X`:6sgQ[eT"&NMEiD5X/^C?a%-?N %^Fn,P3U#BaD^_\0SYl=OlVT<hC`s3nTJmo!8?=a^6epbrL".-#iiG@j@o?+%GgTfrPERE\;(loMTR7CXG\dt0>(e'!\;4]m=efT# %AGH4ZIT_=4bme.6-QWOV-K]N@]1lnVWh5mT)A>D(CB<u7";W+#Tl;R3!M%eoDG%be@Y]NiEHl]BMpJsP60*fC!;G'7o,lSZ5%'%W %nnsL:jCr>uGs![?0Dj;CNCC1s&YHseYI_d\P-]+34mPZAj3ZFT0[Me8lW12\(jd!s?K.5@c/Me+KbEX!R$,Yt(aS4]n.Wpj/-`:K %0Z%g(mU?]NROWG:[@cua?Hnfj[Ck?u"n_,?'2eHG1;Xt?E[@\=j4tO&[ck0R%r\N=9hok'>u,c\m9uW#b?EgU0)LCpFWq"<9FB%l %+\=07aG5?t8HIHT0t`pMj;SRpHL-0hY"*o5`(uiqh/\$O>q^?E"jMNe1&oEM(IX#$^RS0uHlFjcRjh-<O0J[_U0n\MM'^;^,!P+0 %!aIT_o/pCgRlS-iG(L1^W&I,""JBj)klV7?hS.AFk,?CqMf5jt@W5t.+,G=@os5$C)o!7*FScJ_DE+-ei=+<=#\j($/57$]V;,[( %!M1#F)B)!f4qH-bY(;C:DAs2hB>9;%-sF0>.(^5(6]WL@*%]TOS/4&7PE=]D$r&.dlN4^7[e^.`+I^)(je\P[o%M+[\ETNrl.?,4 %MN8TAYrMI&ot0Os*5<r)-<(+o$"]DFWOlaXV,r2"]/!*HY@R)9&TG`\Ts9D_MT,Wnh'`$0<T5@_L>2u[(/heN>c^U(i[=:X=98O# %!"/h>$Y:>/>?e[)qNPWL]]KB>;7b`KRs5n#>qlO#4`FB1p5lda4lP960/Gt4.W,AEfHERa2S=_t+5bhh!>pr<gJf_NAD)OJAYT$_ %hI8&Zrd0tb\ZkMm7EV?o0G@P>2A.XbNCLl@^i[PdTpmhCYR4NZ/$)QKioF5h001Z'IB*5MG-o>efmT*$7M@Z"A)Z!$VLT\*iXO9( %W_+g?nflfCp"RaEpV-_O(RZPsR)ker#AdF=L[Dt*3Z.DM,KI0Q;&,r4=_/AdUAZQ.gP8l)S@<43qNH>2WW3.r.kjp\^Fbk"LLP8J %ggMH<53ZJ3,k]QaV$]UJgmGq'(\Is1@2@p/oG9Nr(&$=,m/O$="#p=bJ19pk+FM]s`:?`ITpKXPhd!)`2*kigNCuDgEEJrFm:a_g %XP[$R6MmC*Ylj."SOt$A'&ho,=$omJ#BN8m2&%LXm9#;*><GR?7E'-3MG#l)^jRtQecVOGfj,Z"3gdJW@L;@aLWMnE!_G'e[&aa_ %[BZ_2:eRQ#lfOdE^P`0]qql@<<Hc>S['E96@pFq2)ll@R9/.<!ic@k+W_b=(gdEs]@lMQj8LbgS%-6!l9Z@*a.W1Gb-Y8`FS([<P %PDmAfE)Hb`h"0X;1o&*qIBBd5ATZ`,<_cHF`e*@Id/1AB5in'ik,u6T&Ra?R/JjG`S,Iee>DE@5GFU#?:=nAmPm&YSeoT0^0Vt\P %Z8ljCk(?9=NQjngZbNiLCY/NZ('j8?\c,Xbj_]VW)ikE03%d2r2,DrgL^_7HX2dQ5IE74`p`sci[pKdCGmA'[!Lq[Mf<=GFY(mpt %If%X'e850_:pZXk:eXI?>ke!]5BP/_>n]mqGr*2iI:[b39L6@Oh7i,B++7Ca6H:CGON+,a7^.OBBKIeZOmEDkP0>ig#sUeCENEsN %gCgNqCL!8Fp\C[>f=UHCmkUWl4$7r?Wt><#)LUGE8DR<f?RtMIV1!J&fZ.%eK&bN6h*4R70/r3Y/V*/9=$-:h'DNNsrDE+dL629\ %6CX^',?"XlH>qC02'Rg2nZXI`fW(#C4S0EZ6c1K?>SN@YEpJ?r"OZ6ko*-q63&gn@^p4@g$&6$+gu%S>i!o*[]+17X#aR1UD13a; %&G-_!^0+a=JH?$59(g"*dKUXo<=>SU'KT0/JI26TY9Xs3:2+Je2C?%A0Im2HRlk(%eO?;tP5T:;g=;H$3!$gU5b_h_1Xj41Mj_fL %^5KBKJieo?!AOVr?+W015DeC-#ZFWu%"!R\kGQ[Qh">XIo:ao<EoE]PU8VlO8L><r4H/!qQ)u8Kbqh6nEm+OdS3D3U*JolCU;N/= %Ih$2.B?Y+?i1,*\C+3oOTqajm;7Mf5YS4)kGN#.lI]Q/$a*ss<!g3lhKau.+i8[NMYD'iVaG[YQ;C8q_VNXd"j%PKX!:^^\4%H6> %TplYh9f_GKLC-/fLl%].V:qdhLHK9.;Zp=)bb/E\L+-SD[E52Fl88Yu5c?rB"L8J0[i=[)#h77Eedsg!M:Pt26J^O1b+oad(9j0j %"V9ndj7"=O(Ce3[d-A[gQO-R3X;u:\<AK7]HsK.0P'^L,*h\Q^J.k)RPNgXd&"<feWC^dj#!jGW1Sih5UQ8n9KTo^lJLr+C"l:Wp %PVIqg6(X)q0i.jKJ2uU1g!5k_#'uEVC//2;YSt)eb6*?H*!X]\9J/Pdj5XB%Mjk95#dH+SKMrCP>`f#(lGc0Gm<__mjZt?9GNd*J %ee$X"'`&DNLrKjb1D86j@A1tSR0$9a)%DktE&IAj$sYM^>0WlU#U9FIcENhSoo+i?eH&cmA6Qo[9PJ-kT!@r2K<Rsl:7`oVq1"UJ %bIM%.j[&EXN)`?teAR)s?Yl!@^&hG(1R$QO,D6sE5Ead):qTa"SI!Vq4TQCeF=^$VL3"+sW_Tr5`g1C"%qJ271/?9qFdag$d!"=j %i3XqscK%U94T?kh-DD_%8F=9;6mW>kA2m6u@6&LfI&*!4>9aV7OKrXg1;G1)P&juh4U_g0/Kc<Rs+>iTmd"_JLbo,Q6nq7@'&J/E %_=^DVrfl'CY^=)X5lbgi*[CNZRn.d0#<0]U3J59gD2+Mfh;u2k7\U08kfX7%ScZsOL;[[ak>_mbDRY6%bB.Tq-5/fjN!@s09.jXd %4)DU2C^hWn+hL=!)tj<"kqD#N@%K[HBJfP&H/Vtin"HoMLuACu'O$H?N!*Da,5kn._T%u\0b_?9j?##!2XfJ9GIWY?c4"Xm?f'1e %Qd,S5M3ZrsaoF;m[\+hpq+G1$:9$jH`4ugLS.J<oI>C%0U-];_[HlQJE_hY$o+idLb>=V,'2gRmP(B'sM-*Q;`3b?POELb+.Z>@q %O^D'V0_XVQ#JF4Dd$9%E/.N$OE(+0SZS`u8a=XVjP9hrkK@4b"V$FIO>S_="_#o4rl:*Wr&9.F6)dAbb6YHbFcklf+,YAZ?%P=.W %S/8(S0?kXOVVA<Po(IE:<?0QmO]Z3=I_bDA,*hIr6uNl3^#UeaagBaW]a;SH3pjR$1]C?9#gSk5UCmod\tM$e\@A"C_C@]:YCVmZ %/u,\dmmlP17r,0K(CXL5d!R`s[2I-,T#>cFOWNQLprU+>l.A<TLW4S/%CmUP?L.<o:DM6]b4lAn<*A<9eRNb#D-g`<\uAb6/`%1S %Bb'fa[:@LkD(7"4U9Wji^"t<Rr;qY-T*/'D?`n=>95N5G++Daf]meQE],=k?&TCPeddqg!B(C,WCe:MYQl_`MPlp5ckVjUZa"G?, %=\cr^gXfV5pV(5lB)(#MpJ`AeRs!35GV$Sn]&/\U^:$ig;k"n?7=aC0^2j:E>h^Sq0/HEFg"Qs!?p3EiegP\mHKYCa.4$uLO5CU+ %rUu/1b_<Ibf=eM%SV9^A)EULd`>/bd!>YO+\,#F^BNQUJeof1h`H/f,rQH&eJ!E5#8qk_c&.$P(G](]"',o+PhA=mL4=!p#b8a@# %^4i3U]I"U`Xa)]UmgC_M>G__=<)G[Nl5cGL>-QV$:Z(u1<Lc*^!3m@D`m@X,H(/h"iNQkCF"ePG^Lf.]ndm9A;6:(Z,Feo3:B2lV %k_#B=7S!`9%&Q9I!Bc]pq5]22n_@jiZn#?cZ5h8r&uE3*.mR+&*FSI#PVj)u7X^0oYQ>GEAVXj3[^nS.1D=LKWXbTiW]1KM9IHs` %e^ZU`Xr5T!(A6apb*/k8*p;ZP$K>8i!:J*_Tu4NSOE+O\L+cTc;p,m6[hQ!oPhSZVPAh%/o[^U`SaFkahda!)Th9_$P:F5ZegQfl %@Do4&?U6aVD0hN'+1apL1mP@V)'JNE)Q&]JeW.#tqO=%7U&%0s5N!0aK.$*Vc.89$Y>+[j?hQ_Ug$-[A0E%>nDWVN%p::V2O+,]Q %GS/8i>hs42>5O298Pj:1jEC40$2+8**+Y-gSRm*@\*&6O"cs:24@n)EFqKG5#XT`(\9qSg540CaY\0mA)>^Qk?!W!4d[0nLNEtgo %5)$#q-TI6ckP^>__JumWA_P[?41e%5HP-AS#T>8Oo(EqS*toL0_OMe-s'7O6OQ\YWSEa.Dbe!gShTS4o!WhJ7qF-NslRZ1X+:.j! %(K-fG+46^c(mCZ!Ofu?JVZc[G_hM>,(00#g%P$h/3*$>gf;)AW^PUEMf0,_+?oSYq!I'pg,^gG0_2Doe\H43d=2/]P0fJtjUEa&$ %&=r/FfjL*hE2i^gEf5P:)-u>U-d0WR@[%>KJgP^)l>m+&S<nPfs%B3(N19\J9R`/\,SK*(Zo:`oaZ2-Fi'#qd3='cUZA&3kVj(2l %8Q5b189$=1Yqh2eN:.76&'m2@@0,gUJUo:_^=iinQD_!F"V4,^H/jmQ.VP9NIQcNR^><*^1mQ9=pO3`R9GL;WMG`#Z:uSR5^c"o9 %<c$";aI-a/G_eO5446-<%6b9g[9uduMY+e;!PED%.MR#TQtM^jV#9Ik3aSNlb!mj+PL=_ofg?P$;fi(P:LMJ&J*!)8n15tmPmY3q %>81u:,)VE#GUA9di'!1IVPk+@F$1L!LCla*[03V<RYX12WpR@!E,DJq5Cg-pm+R@!4=It?hZI#:PH[T;ZtW:cO&T6e`2YNcB'rkO %D=Dk]WWjU#b.mCSJPsuqQrMCM7LB7)!fagaWPdt"H%sEK3>HVRjoc7G.;B"30Z3&R/I`Gbn!!<.0Jr&sZ0ke%CQfO(SI[D9d7`-B %.c9Tho<6f#2-A%#h<(oNK(e`V.\j,Q]1OIefCbr?<Yo\8e&Z&"f?p0=\&i]8Ji7;"m0hJQ[0W=7IggNE_C#'-$L0#4?oHgQ@CJt9 %/lpaNPAjls8.;Fr"Bpa!fA4M*4%UkCn?`$Pm`7aQ"Q42$<PVEOQ!8GgL,jCp5gf:8=%4Xp=^pAmfLEo^?Y.22*A<\%Aco`q`o`;P %Sn/+d][C.K\a;!(=ZBlXUo'DIG9E<L2YP)396f+*\mjWO]Bh6NI;j3"kQ;05J9^pTrT0aQi,hJo43sq.%$pkUc=#;7GP/3._YJM8 %'6:,/TtVuO\e[*4m^S1[``#P=d=jM'@0*ZW0)*\lkAq.HVq5&T3E0OH.51T'SkZub$K`g'j)siV5QDe^3DNRbdigu:#['C<b=BbI %:p-BraZ3i<=cnSp%MM"]SH[0tY/1'Yq)U`oD%#u,c;W@^)R8XnjjTaq5-,>U'a2M%WK2[5jZ2A`'$W=igmbR3Do<-T"u3DLM7a>H %oM_;Cbl@Qm3J7;(X9Nsj+@R!iApA$nFXNO]f:8@ZQWd,O&tUekgJh467A4ghAr>a8LWV1,:)$QBgh,Nagmsp9+G*OD!tfYbPQ!&H %3uJsYW*<JhAoo,ELBYKQG5=+uDM^UsI!VCBO6bkbJH%'2%so9)hPn5n?[]d_/-KO%2S$m$&1IcXaX=!JgJ)LA1O!:6-9"@?9sB6Z %Aa>`!^ZZKU:'CL*CQ<to#tA$AUG/09"JMDQZb^\Z_H@lJQ`7Xh=._W&B9g+lABAO2:?*E9WcCf/EhfilP6/^*NosR?W"naZ`FFeV %=G2\s/OJ#.-a\lBR]4Igf#AL\!FD*FdU!#4pO7C-fm,[JOhPWB7'*F)B/R)ih7@DJK2Kt\M95^A\,I7IBtA%6k@QM)mu5!=oN'_0 %ldH<,Ap9I):N']hm6#<)m[ZBTY4c]+G9]>uM,.7"$t@LfNZLf>!u:]RR*k;=\#74ngcN^Woe6@AQ[e]^s0qQkrq5`0oC)\M5Q&FV %rr)<\h=1;+rS.A8pODr3J+rh)r8$iAorn?e_uK"?s6JS@^Aj*urp>3U^R=pWs6B(Qnc/Q+EM%a[f>%@bT>1EnhgA&rig8]S^O5tB %5Q$RLrpfN.Ru[JtO!"E!j+%!aO.lUDWIF\&TDl%oG^T?,>l3u>q5\hg"+,j3P,%dK07WZIlW?1(YL,#4d>%je6&#DCJ,eBXp"-tU %V>cN_hCKf)(d?RPe_j;(3NBQ%gA<nS!3-6[C?-N%-T0PuJi\o1Pqj8,R.@a?QsMn2I8/=f<^;;:%R5hfk&l<VQJR\]XRs.0>KsmJ %9V]<76#[>)ck89F]qb"bW$B"[lo'V@eo\"P!g56$m]lZQgPU58FUJ=DD\I48&kR>\DGVo>S.liWnh<-rn@jTr@h"q!mgqNVJiN&, %0u*pX%\R/)qbcnsDaO><%TdmU*Y^9cJ^\h#S*&c>o=:_'6.]:&N.nBLH"P[k6MS,IA#H^]&-M#5N,Ik]R,Y@q-K8IqbGTP!m.2n1 %`HO:]ro,FVWJXPh7.\plj7FD`!]mjfe%,Ms*hM;%Ulr)1KgIY4MAbi22u&(QVNN;nNNriTrl'qff'1N%%u'T4XOB,Qk>JVE4I_YT %aF;_#S.r8s`FFiG;Y;,DF^-S-ku>3+ERQpq/Q+eOm&Bg`Qii9`@+7KbT@ZIn%aDn0F\Uq,ok$FgVm[qXY-0u#;":495dY0)KU.rr %+9eZucOf'q3-P.%B)4AE>25e';Nr:>o'i'K#:&uIGjtX/23^UW%JCC7M&g+([A_p0TZAF]GZ3=PNfprSqhB\?J1E('*[G;FXGVH$ %8tpeeEShDk_@tB/?cEYoHcgacrK@f-a)G<&!uu!U]Q4PUrpb#Vs4ZkCfAQ6Wo$p39>!#`Bq;&s;;OHeA#*9nNf9.9)KA^M'+D6A2 %`f`BN25^+bE!L_nq\E]WeDU!0A6dR@_dFi$VAX.c*H739_GIaFKBJ14UfQKoNn4+7j>W)<W:^Y(:"9S+^hAr0^;M72Y\/!n*l-X0 %dt>VD'QA.OmL*V5IIIepNUC$#1\!3$aCC17i/j]obCU1nK8(]JpnRQIh>-$Je`.cnb4*$J7?0ia-?&6*KV6cO@rLrX2_HReWE0p/ %7"+b<R+'M<icuT8qM6<^H1(o'UN$2b6f7SKUm6@-`5D+W5gk77k_k3,P!.i?*i!icr_F$0-.BL#N<^)n5.)(T]8<]<jO%BJA$FZJ %&.n%kh`.<)@OssIU\b6HDYUMl[1kbDKDBn-0^XMY^+%*N&PipSf-Uo2`\i#<0RrT9Z+Hq$K.#Wm8Y]_=0W:u6T[rXD=QT0_BjEC3 %CH8(.QC5]7M:m"Rfr-h_i"lL,)tJ@NVGf`f^)<qM&Lcc1H'U!QU>V"-'o!g5*1&Eag7?38Zl9o/Nf\l&=eX0U6,@8$_qK*-+YhtZ %0b`p-?@CdB$S(K2COqhk(RW-0C03Z55>Np5hdR!'Z5=I3;e_63"<BO=a*gD*Na^??ln=)ZT"=k)<EmYO\^C1+7(;qFLAWUAF*%qY %\ctgM*X!&HZR:?-F\+]N]DHc#^1cLKX*3,#1`F<M2MscaS=V\MTA_0MA`YLAG^Ke`^3eb`f)s]SJM)@cs4$Yo)'17.R2W.QT5fYX %r:Ji_0:UJS@4Q^J1@[M^cP4A:TP4iF]--;-%c9'++'J>n:j`M&E;V6i:%Sd6KM?f>YNpn'5&>tas2MMFmO#7UoJ$CcjJrkPi\4GA %CadsUBK:COgsb<#e/W)G+-FtZ>N7jX=n&X&7gPa?>ks$d80HaH:juWW-DAfaeF;][p)"d%P%P9([ia6@^DFHD0q-[Y8Y.8,<*7GW %ViOn=+ceF]kN@Jl@INE&m?GeF0J38rGGVY`OIpfdb!(t1<T0GDcaddFfR\hL2^.W8!Q'hT)u-(bGSg3qKO'lE7_l.H@*/&ZE7]^N %H5K,hAbrr^K;sRp"EoS2/X(6:Wm?PpH;!0/?r\Rfh6rp*Q[1e;;WgupA+5`+QIHLKJ)?K^B?7o<3hDQn<YWd,@(`FI'Ckj-e;.5b %[&q.i'>hs_O*=4egs[<YQu(JXHu0h2E79<X<sX"Z3YimDAF0[:M1cM620)mpNThd)9/Btb(P?m,1"\AEKUMjBc5KUfaW&AJZGY!Q %;i,d"miZ>1U(#D!c4_&d3UL)*&qU]Th&>@n;D)h4hBO^FfO/C)c`?hmH%rc:(>%+oXi(!`i(+Z6bAYsQm'TR+eq^Yo[0A</Vp<0Z %5B$#!CKls,LODJe6bNaJ$(k,P0D6')j9HXYYT]cU&r%Pd%S<&mFphu-6dX_;7Dp#fF76M[M3?'M7X(C:2-8(nH&^"'&[A5frR2C; %..e`I%aJntC$:[8D26K[fqM!V&dMk#Yo_ZZ_/&!=:-d*E"jIcD4Pl?5q+pJ_`o-<7)M"6B__Y]+8TW&074oJ3&?$9;rRZ2FJled> %O9o?dIKb$o*J^kM:E"qhSp"CFnE[m'-6ZV?m^+"2XjB>trOP_U^rdT*3-IN>,8O9?MSh8Q&k(+HVE'VOhqhb13MI0Vaj,T)VDi>q %#W!Cg1+TlZUiK]72;qT/?cAo"2*sP,p:=;DaO!2_c6(b<#b:nsMpL]\q,90:7Mqh"gNsPCcX["WW5#<IRDGl_kuF^]JLGm,ilkK7 %-64i_-RjRXEM^qW9)<d46FiNbn&Jt"_7SJrb(\C:cj)?rCY"MYI:+1fm"I+*mq?*PMOilK_SUFQg#f4,;os8tZ=/+5f*r7=6&_if %7HQF\'2*dYXf\KK1T/+.@pjFtY!QV#SXBr*EV%.KI!c]Y7W4Q?rV:%!q-D)$$6OgFlVQ?2K5JbjA;]1[Y`0[4!u5bi#Y-C8gKV)5 %*O)t/6Rc/5d>1lC68md^]9?Q(j6>bi$L%LILg0#5s7?Ib0;NN4`Ad;8-6/jD#hl55*`^dpCC"G=\SuU,SeP%X6dN$nhkqNlVo3kY %?hTBbjH+A@%-Mhjl$o5^G^nc&EEfsM!c"D`rlV.db0M`14gm*C6`u*>I#R)0h=T@.;>4gOQn7>p$Cd<F(tTK`(=mt0o]WJgphsGk %XpCB:H_;nq;tS_[A('C>hU(#2F)bB"FPp<*L\@d<NV@LO>na[dS6Qq6#Mb!k?a=aGm])b\SM/aMfnNhf]HC8-k$O`J3t8`>_Qo_E %Z=aFb(-lN5Rl6@(07.Yc5eXujZ>'L.!Ng;S-=0P$80)[>LG%\hGH_*oZ?E<oW$A]H=K%7ljtV.&+emoT<RCp&#WB!%UOdf_3nD@- %H1>e/*Wn&_*E?>niFPT`0?nQbXNgjMS&SBYIs4Bd_@Ykd+a!3)(T7G6I<%eP1^G"iZY*ZN=E*K8l#;m=ZOSH"8p@#MZ_^Lk4L\cP %a/&O<oA4R/0C7R2H]JY&0?4dddWt?LFIl3l_@ibuQ`S;!ftkf-T`P!r4uDc.#Bj;KeXq?65Q;\sM`AKY`_\FGfK7$p.M.9!>;t*F %A?u>se>FLD%1VM4QNJs]&''7W.iM\2?JZ)dPaefj#Bc>i>$1XZRiCiG]F1<']GJk#=pQE>=s$LX:OK_`obHm/7ju3_hh!fh4eSm8 %NAn8T@&_OkoZN5Y&G?D#HHHPLI73_P*XlLelD$0Wb2CSr'EPOuEgJIi<(h)k)JuTaYR8(](5U3P<gltDWJ4H3Go62T0M-<ceBk8+ %!R7CT#-,n+*5k<eqlC.4FOO'#ghWM[[&JBg(g6@2Z@T.*VYT]G!F5ls#_=[0oG'3ZQs(>a.#Yq;VRGfuQQY(s^?@inO&#tt0ih/) %'rdM>H@lCZW)Ba-$T;o[TO<l?]/ef/>%3>u?O.6XL^#[D*\F1;IDF^cYnae5NcV1"3nWVkZKsCJ+!.dF;ta[`nlX+k&L)l^m67(L %)]2dF"ODH1e>f.=)7Dg@KHo>1>@gSXK*c6NN)i#AS5UG<c"FOj//4@-*U]\$8EIZM5Q)Q@;<6*ef(NR[]&JlqP@O/+JnN>IBo9qk %,)c=cU%E&a;u!`;q-jm8_T5ju_:V%IqpF[I#%41KcECFX]elF,$Z7A&(r:O'&YMm9BC'A<SiO/>5ED;X^,726E(J_,SoB:"GscNt %]L**'[Crs:"?-CDOo'nIBXkmK.;SeDO3RO?nN1N>7=UbY.;Y]l;k+\kIS?A`HrL+ln7![M_d/RifD?Qt*'ack&nS[>+ZH!>!%$9C %QNeX;a(oHY6I=M/QsahDn'H:m(*o?IX\fpJa`G(A@DY`I@>JaOO2%nBH4aQk;d&#IZkj6@F96;,5YJ0bp[c(7(G@U]G9Z5s>8`WK %MIG6^*VYP&.%!HXfAY['cPA';'97Ylh5:2NqK:/%=q\Kbo7Wgl1p9sbA-(K7c,uf$Qp(<M63RI>@=6,a>9USn$dl20_+&4<n5BS; %PQVi@LTX@)=A55D`Ecsq[;&&GN[kdSY3j*B*H+m9k<QE/46L;m2GcmCC@Y\S$tJP7Jee=&YL7WPeP*m&kL??=IZ2[BE7i_t+_'PH %5X"Q)<BFLRi6,`Vrc8T0Qm;2$>+eJ#QCE`i*6Y&"7O-$FT-7IuD0Ce%`gD1rIt-9,`kn\SqF"^F.j/Jh+$e(Zb2+8<r<)(:KFMc# %If$G,mi)+t`T>)L#G3'Z*4HN5=E,CZKW&Jeel-H)qQVKPi>_#[d(p5eIX4.9HD3nk[E&GqLR<X?L`t!Q;M]1-_HnkRG;`9,UULN` %]Y/b7-6sZAKmES$:4#bO9GBj4oo-22:ajOj6aP?<R/f?2R$]!"P0Fb\Vf48sq<@hpTSc-T5FS\4G=jSRd(Vhki-uF1,qI]@GW!#n %k;sSQECCLd#9a(G-*g]]Fau:2/mL@_h"H,N(u@e>FRdI""E\JgA*WaDC$`Gqr1+;<rh[6C60k!]H/'Ie4ZHaEe2"W?)p$:kad.to %4b,,i1a/OD_!B(E3N*'%oMFke<>k>r`Ou&UQqg:Ub]p^9Y'1QR6ns)a-4E6m3EE^XaDJ[:+mV3.Lgo2L42i-U&GD(YI-SOlD1Med %m,l@I(.c:Iql"o>)PXc^fp,D"Lk]0uL#';/BM*0sEj0OV@HnISEGU/]\"])3Z(htF1TY-aI2(@0Ai_W3ksTq?LX1Po0KXJ32?4a( %q)Fg`KWWo-!=ChH8("BFE=_[U/i;l[,G\u9::-@qNpECSoZQtpl'317!#.`:^sCKFh?dQTb#Q[0.)\IK?&fT$&*g'HYW/fq6Y/(d %]=AeVpT&+N(+5c.,uT'="*iEj&8T#MKEII>-nOCi>m>sF/nD0E=>@9j?6udQ8jN07hpmkp9*NC6;n`rqZKU]Pon0_=q7@d2:jta@ %-i<aSeXu6u\?Y#KX*/H&4"OVfM\I*A"7j'u-9;?Z/IK&X2Gk$GL7Dn.5/$A^(#l1<W6%\4Tl/R\/MTM.@[ZVd6%na[G');![sP:= %#(*&U-29*,i$q+:qm6A+f4?2=Y`<ATLK96\1KYS:+N4snhBf$`TFh$$kVMp7@qucRqABu4p.+BI\0!lN]?q-0@*bp1BnNkHc#eB# %GY'cH8Su?#5:Wob[*6#k2M/Q#"AK5D6Pss-T#uahS'O7-#E=ap97=IlEBB.!2+Ys5X&"3@q=UfhJgK2ac`a74R0/o8!cUSYTSYVr %=LuDO'MjB@'+13-/Y4PX81Z7^pS2%WqW5?AM5mUf`J+!a>5UiEOQ.JSK[@8b@cLM3J.#[Lj7N;NAuW;V\!TE49?k_FpB&_YEId>Q %/u\=Id*?Ad!#7FY&rP/0%7cJ9&`0i`QZ.[U8Y8(`Xe$%b7Z1nTGcN<b15.E#Sh^jH7Z.)YZ;kJuZfa`Vg0FcYeol_=[VT(#PKomZ %,'*2`YsTU#4@4U4-_4^[)k%=_`"<+bhq:8cBU:,MD]mVlkH]"5F/CVuCV9!Nr<":G#lb^Do"7?&6KVSg8<>:['r!L<\@ZA:+Q)^) %Wh^bt1L\%;I@U&_K9eIm2&YgscCmNYPX0(BU7l;BY\tcW?2[ar$]I5V]--$f5p1WP.k]2-"ss-""'!,AVLC`)+SOKE5DATSWJ<Jo %gmi8n0H.43hU/Ku"8J/ZMr>4\.pSY8XK6)N2=mtS%i&C0Vn%L@d!d<2`35_ZU#G'>O9**P:(EF]/T:sT3-1s]Y_huIGl`?Fb5/J' %['Bg)84-<K`Q0abZ2ID,$\aNIQo$PMSq6;%c8$rCNN26$`>Lfp]H!R#B:#3SOr9Wt#W%Yn#d?%P5j7eta9h$bM(rj'$J;#&?Ici% %X.O]W;?[84p@6C$'d2jf`lT5fK\8K$@51MIm<`$jp2SB-&i5bLi:WWgS<AT]RO;/_?Psae*:VH`?6)K!5X"T;mhB\X<anCdIP0@< %_M$Jas!$_sHq+8LgCbHXRR\qABb0/4:hXuM+%"$:WI_^eZ/p/=]1!g`o-^&N9fo$J'(#$0/^b+6TOE"'_;E]Dkjkc%(9i)XXAJs_ %#iA.=_>i#9mi$9t.3mV'*-B+VdSNDsdIK`9k94s$-kg3Hpr<P]HAGW&3*b86/6j"B!:[6N$Z/'/Zc`R:h&^QfiFQss$n^B":Z/^- %+be4-$a+jnoD0<6&mVp_L%@OX2>Y.E:r],24gGS=p_]]s3@[,/+>!WhMZ=C]KX+8#*5G9.$%)[TO]O4Wrr*Kp.fnq]l[XsX&PkKG %kA1]MGDr3<@CqZAiaQ._ZWr-i<`P.t>[J`8nnd6hJ(E)TLg)0i3ao'.bA-J:@3#ZC_^O14-ikbt8P]Y?9M?<L9agK_]L\Poi*4"0 %)KBUhbP(=)^i%ZD:$H+LIO+4,_We]5BAhH0]c#38$f&W-2W[s0\3'/aGsQORYBX$&Sk`M/G7#P&-g?&6?;!++4lnJeL14^&KM&=M %jTq7c@qaJSAf"-o)0[(WFgC<[SK.5j_^VR)b1SW^g2JNJ1bUM=M9R%[X1J?r16ja^TM8Z^WtBOhIm0_D9(mB>=I*4HRqdK<QR*"N %Z,/j>hmJ01!Z]r0"Q?7JimiDX"njKJ2V:c6@(0iD;R-ES++p=G!4+R'*J19VZA&cRKo]=J+q5^"+u\4E^7SWP5\AL\:\mMK&X3da %[H3LkDbqmm0h2r6<2'T(i[NcB-#*i<HEMCGn9B2@_H2K8JmQ0E.p4a"8?iYD`n@DG)K"(B37&*V[eU)2H+41+8c,S8;n)?HZ=a9: %?l?9nFmuaJHDu/(4G6C(>$&Ygnj7;@@tujAK8T2XjKK25kQRPem]q:UN_Tipbs#Q$M'4I_E.n=_@mW.b/P(\A%7^(dQn&DX$=l-X %>?j@i]_)9L?RIpb7M`iO1se=25\I/)E?KUYE);A00qqu!Hbb$k&QOodBN`Q9>7VeBLN"GDKq]X9J;)AEIBDI2>uft:=:=bGri.`b %)JCmTWAX+>/TM&-VlL'c!o-q[&sHSE+_Jcl>dQRuf95IsBX^fhnX@.-QYZN_2;:se\qC)dYo[;2N%=.6Rn&%M>!q#:-*,L\/%?D( %j4pV).`l*,B:6>iKq4LT4TqI_-c(.]q@IIN9+tm"eMc:j3t&rG/*k6@87'NPaJ^+idY8TI\FBspqd$&jNh@3u+ld4q$Ma"7q[\E" %Gb"K?"Q?cF<Ec1j*oggCIQEYYAX0ag6u6L?C)61ga(qo1a/Z#Z!k7[-\eBb;,K.!LYsd2g@Kui*U6aSXET-<(KIZ;'8JE@I_g5KC %Z^Wt+^:a"8c%HKamD@Ia/m-'E7c[m(pY:&S(o*uOEX>uq-Q#qf%q/L"l'1uXim$5kmY46rfU1X'$6ef<1Be;/d@i[T2C=*j;8Jc1 %"K4_(?B-<JTBQhMUC.qP2ru/\(<AR=V"AGk]-HV<L2^f-4B3kaa$+uHb!Z>$%n)[3P.LQo+q'?L'nc]jIY/FjnfphEgqQ`'li]0h %c<r&0#.T'e"d"MbqW"K8eudKF$!d4FG>A[$<14W/#@2`$2F#=?+@`dhV^qNUc=qS2^L1UiS^pF64G&),oAk%u';$85_M+!f-@?;. %?ZH*/K]\oBA\DT\5pPK?QW!K\l3\cG$%d.H")['>/>m:(MkI?J:f-sAOoHFc3u?>WLBA1+`D[H/B8GN5lG$<s*j,^rX<G]T?A2X" %eW9SQ"sihV(QLm*AgB^TO?9[>4cOXN5Qf<%a.[C$S%(O+VOFS'/WaFF(g+a/guqiULetH<oL$&XQIRjBY%5N9h@;-X;TPruG]t<F %:YIIj_rMPK!I&N`4WYmNVOi3%(*s38lg4r(&mi0%/-p>uT_RO6Rj$8boKe9Fp27D6+2T03W\Zb]#Tj9fHGt8/hq;"WA,?2@<#n'1 %@KkDa_a:CjB"5>RB&'8[Ff\U_A!e8O6mH\^/[@IW%I^4Yc=A]'a3:.Z0\GF,i>d#\<YK)/imC.$StK_RAcm2@4A=cTj;$`F%B4cc %1aYeE.TffY_QHW&m^RCi6EL;2C^[igD1p9(h1\jrTKWo!0gZ:gTXcEpIa:BF`+],spNX\j25s__-;k:S`>c`7k>2>ff:0jS774A) %#TK"](?u%WSQj8V:elAjk,(fLetgj,qWS`3l5"n4$j!RGfWlIsm]B.(Gp9UTN#8,O#QXIE<9kG`@gG.)k^%$@P:8AZY;_9`1cUO8 %KRfeCr_Ts?F\b>+:91bWC-XAE&dcoMh!7-_?Y-I+l4\^eCJL".5_1JKR)9NgKRX7ZC(9)b.u+jM+rK`7,cg8\%CcOH3'Vru6P8,t %FM3D<`c!PR3b&`JeY>:%1f?0qYQG;"*Xq`0Y2h:gH(p.b3RBc@5H:aVb!Xp,1l/gRkmtB3c[k'\+_1R51NsQ`5IR\nIGsiT91XRP %k'HBik\lKLM$>N?YX$DhZCQ*['k';-eO]+JMF,ut.F`up=eR:1)IZRgDL,E@,Qfj8%ajTHajCT5#N=$q%U?o\!c)h6P#9ncp+1T= %LW@`bd6qF\mb>.GK,FdHZ!7TU2lY#3P5F@)VR\?<`mR;aYf17B_qQ%<**0QZ?e1[^]baHo5KUj/==cl0bu;t\G=R>'!qUGS5`+i+ %1gik'TNbo=,%TfBR_LB`20)lu1n[/@F8VL!Po3VYqc2p8XTC)-&UT<JD_"&W0n7.3@?Z]h"rYYJ?6LgfRsV(94ZMb;>06.dK)@0k %N<@VA3h:LIZ#Xs*m;!8^j4ANnJjSki:lT"%rk**BF<.1I#&tH9+UW.9qr!feCgE]==1sD,;f*c\)+q\@L7e"OjFgC0AWgn_f47'm %/Tu=jNcf5pM4eVk_N9W`;_9ms'[5kL^$=I-dm0lpp(k;ST))'HAHSor$'AD*+V,WUej(P.2j:+W1EFhr6`J4b$Z#(\Sm0Rk*!XMD %GOfciB*IhL+Uh\QI'G,&nnf\tg&_qG4hLTh4`Ji<;n95%c/79`\LJOX.2691G)L&kQA.9"XQ2^P.5R1Mbml0XNi@sXFGjIR''GuA %."_](0al%&pkFk[:d0_W6cu6HMDLNu.gV=`boqaWE-]g(lf9'0b#t-CLI=%)W"]bkI^eEk'"RJS/Uf6#*CkW)Z+LDoSc[R?c/V;^ %=QV<@(foW?b!C4n6H5S";(Y)U'h=QLCb9*$+D$j+h?)d?qp*V\/,>%;O$WFC^>'\3eISk@lC[qBTo#%1].\I.lK!peQkl2,U@u76 %YB^#[Gq.Z71C148Prt)%.%N7p?oXU\4o"n>Y8V@RM8`&1;*)lEKs00`q/OF?"*gH8!(:d6WgN7><LV%GOqPHf(8F;0l>_?21kYVL %p2cD99k3J7i3ID[nQR:)H+-ILlTU_pfcru3kgqal59gEfWW0R#5m%MS:KAc8'@n8iAf$S>O<V71E2hq)C^/8Wb"<-,](_2[(J',X %-;u'g%pK7bo*WNm'.LkEP$mnr^'Z\'FCPZt$N<09)]\'e6JBrI;FDpC04l3%.5F@-c&DjI'9gqK0G3&m9\M+V>@J=dj!/Es3n?_' %_MCNV;JlU$>V*dVX3Y`Mnj:35&-XeV5=sjkXppT3fu-6.@EYH+J_hNH3L0c%_'>8sIStF8c979">)Fm++9i=$?eeRjXrargT=Qq` %OdSr)3`I]4HnEf!N(OEe;G/j`%6VMENgF<49SL(=ZEd4nfF'IRY1_jj*HA4X1/^q1`ZX3VqUjd48*%<3FhSfRT0Ui=phV3mqn%*I %2E@jV\e8Srqm5@>lEI:Z)tP?9%p*X5mH+lp[>TS[[Ac_kgoJLPYj\m5P7+QjF1[RaLZ0ed=sM!6O8H"&_44T4`Zu^um<dtrcDj6L %SPuQ*$feUfArUd\jLcB[8d.84^#WFmKGG7)R_@79c=RJhq53YB"2X@e'9@GL>'J)8=tFk-.6suj.Lm%P'LufJbRr/$&DFI$REEl\ %I0f6lGB[crmq5WaII6#hA\ru6c+0".bg[RKqjJHn>>,<eqbig5ZGG/N(FZejHtsfm/9"60GP/f`C8fEf,6Q+ja+:0n\d67aM$sd% %_8nuL9JQ"DTN?Io<'<M!)'&^^qCn]M3GEpAL%'IUY+1,1[&=Konm/<tI9'FE`9q-S`U=U:,4>LGX>(;$O5!1[YnLiRlgii!=?A`7 %A[.Rr*OUDMN<S47+$GNW%*Pu4b6B?m)oN-Zg_A;"+WNU?$D;#iL'[UjZ,_%>,V(Ln.I0>FLn3,.$)M%k`h9b]%4K82AMp,"+Gi:4 %iU_-p?>X\u1,[oHY/:Gs7Zq8seeUs+HmO?uU7_)2Ghrok"b906a=TSU%34JT/B&7.#fphli<74G+LClI9Iudp#CL.\-*;+\FlTdC %%NG!"+8')F?.=S=D4(sRd=He.Mi"I\kgt"7^t"L`&t#3L5%Ff<i+?N+$n!Cl1L!smcrPZAA/Hq`D'#=%M2U_X_,p<L<+iKtR5!8] %9dlO@M-%S82Slu_6=rA?9F&GZ[-/1h+,B;-*AZk+1A%@l#:AfMn""Qm%1q<]75WBpQoL[fdDB*(4p.4!_lEEn9Yt^"-?5#5'9Y== %HZmTD#!um']LI(@k\!CcR?``PRgVLrCX7$R']j/nX7CdtO2]ZT%uDL^Yc[CkP:c65d-)g[bs7PqB]'jC=VQ3R*=6/>ehU986<$De %=h6",a+7m!_^ApPEcOhJCVRPXSq>TXW1dttpH]O8X5>/f:u<)<bFfRb$I3$ll]s.*m#LgtGL^hg)#m*u+&*1`fOI,Ge7=ciH-U[a %"#`CSM^/aGgieO/^p7Wf!$$ThE=cXE&>3*MMGdgq>fI%_ML^dhf;2I0/+rBVpAi1kQ\q]W_a>p(%jOj367(%LFg3)q70;8e)k^)% %"4?iPLXntM]51@q+3a0jm<[GGI"HXdAak6'eh(,s54p#,DQ#<H?hp$f0VYii"qli3"d9P;Z'`GOc0O`%+q8^MU,^6Zk'_mU3/h\Y %3mOm@L$q]hN#)R5s.][prA%8)n@S0$2iS6!^%Z:$==#22kfT+45,!GUr^Af9Oc]G]EslH7KE,r;^Hcj5O_o\)j>GS,SnK+?*ORs) %L3hh5#,*M^eKL3OVpYl/P0,s/A%%T[2!/dV31Q-kR.rHUkZ5ohreh4Tl+V]-FX%$:FFD5f=cmA;%03AWe@\=1m,<JRW<#l&nae#l %3LE'np+![^>sR=S&MEYe?Nc.,"SH6_,D+D1Ff&u:R.i'p@_0q5h4seQ-V"0OHUE\'T.)AaRGNN)m*d$AmFn@g$o.L*A5Ym8^dNqE %9cq),YR:uGCM4'Q#E&1a%)[c3jt*o!'?g.tiL)DE:&5![jPRQ^5SC*lKTnA.i^RjRaPr_WTij<25b0`ck7S.'3Uc2^l.$#A\>_$c %dDjQd6`k\2aJXTs`&R&Z`$<tsWk>RO5P1$@Q(srUM-`FDIBC*8.QcQ-4*K9.j>\:mcFCCQ0J=*R(12eB_I_#Y_[jh(S-C#Q##?Zs %T7(&&^ejV`h>c3R&AgR9dtXtGN@lS6cRdnh>&H\a:atmFr&s:7'>X3f8h!PnkJ&4DJTsfr.[iQ?:6e9-AO=@d]\9b_jhqpC(A*e4 %R*W$Y)CU^``s,-ZT)uq.*FQ8jTrkQ&qbX.Z\X;m`:qZ"r@b</r3_2#iB,2_oX@XG[4g<]r7,Ql)J'ZnZ'H^P<[*cQ;?_Tqj%;UET %0r0eOp,rkFU-.B5+\5bSGh*`'3cm/)Q3pCP2A6.&F\Tdf]c)r,_FobGaR,ANN(ss!@&NX)o[4sKCuE)Ag_59l?@5"3pGLnPkU"c% %;UA&`0VZGnkp<W9>=>8A]`pKo$#g;-'+[M<H$EtHMdjOO4*;()BJ"\*<@9.a:'dF[hG&m%`ZZV?a((ljs1,<L,2Lg!i)gKZZ$fVa %E3#IC^_&hC!UEhTf<kl[KmCU-!bE0XVb,1^16:*O6mQlFp*OTiNoAK)=_Pc"nEP*1S@FU_Pkg?#B^IY'#*54H,%\H<BfW[(-FjD< %2%p!X0B*sDpKBJ2(WWt"^ab&6n[+uY2"K5`D&O`=`L'5+6ef[@ck.,(5.,Lip3OK$;loiCZ`k;ric/'?U;h.Z$Pu^fBM&RRTcbTJ %8Jn"i^i4VkE-tAp(Za?[qL!AT_K2t->`<Mic1DQZAt-2V;9Y<I1TaeK4R+kcAU22B_7:^h,(pOloOl!)gOf#\L+Am_;0TsN3!^o2 %k?O>sD":6G*:=%OQt#bL#R#GqQAN&R3U^)DNHH.EB@&B\etr,:c'j-!!IMtn#GqB(YXjoL7iCc+>gV>^"K:(GB0E<fmPkm.4c5qZ %FcKpJHkiYXKt%5ePuO'g"rD_#ipCPe3o+tW,,C?*,+UY],a$P@TLar<VQk$FZin]=`>Y'Za-Anb"&h_7F^NF'j9b*O5%Cs[lJS<V %:;c+-)(S':V]?IuM?;<O9Lm@f`G_O[S)3E6NRA+P'Zr[!U?,/e)VM$!N/:uOL=u;*Bp)d50#6$M7WqoEZbf9a(joh:J;YYE-fSB" %X;@?FQSCM*?A&JJs)DgpR)>ik#4^`JC*0oU3u(MRZF-dC6]<OT"T&*0=Y?VjNWn@t(Hk"uem!i&LlRLX;1tKX7\a#bc68b)*Pket %T=]sV1[^4Idh5aPj3bZ\hCb]aY6c^'6StBnf)'TiKlDpuPPLgpZ]H,_%BQRl=X:>H2NqV)KWn'#(\GP26RL,tZ6S&3<h;EV$2_Ci %.TlojZE_gue52s\^/`elL5g"dpK`#JnQrKVU$Y91YV!haMs.!S<"^?m<Fof;4Ll1i[i`;ce.S2$Ag8uuT@jaObLVB,6c59"'_A1' %hRWtK5(#W1U\9sh?`hKW8BSr.Xd!oMnuh4T8Q1jI_ELMD!M/<<a.AuZPTibfmBYqk&iG)Qi^HJu/drmqS_:K3G1oZ',%Jqu<FJG8 %KA(C3H@YH:rk*,p.6MkuKLF[nF0RV_>%2L6dm.;*jdP0@_8%PuINbkeDt@gUVBa'j1It<CV`-o>/@!0rJfXicQIG,AdQ,l6g+=dU %Gp7SeK1@/<Gi@=i$2H41?c@4n!rh,<rjR!E)PV&d.oKe<3]ZLFoH5_m,qQ$Z[O`Jim$S(JqlDggVZ]i>E7+Ks+@'d^dP9^G!80UQ %$A[T[<pm17N/L/3LU[D-:788tWTPGC@;IYrbaGBcX=d>4+&#%0IPA_kWLu'cBLrm\-5=\j<7GW[>Yl41p$3Y5E%2)f:R>jRmXuG/ %BMfu#@lE6MCZUEs\d+b?:SO<=HtS`(a8q,,+g[R-`ESR\RE`Lf@VVpKkU;gS0%eV="OE3J[O"dffg30ob#/Q&Ka<#uXISFhY:L<& %JKI\CW,@n!.,g55UNiEpeJo3CpLd?MeZJErX4#Zg=?_dRh7#-erMFJ`FJ((\GJPk>g0!LL(2UDni#$Q$(bN4Wpc<$*-`MQ;Z[Q@U %&L<(7colK0PId"PP6.?I"u3<_'[]1'Hfe%WCU^HcW8Ipl"@]`R&;JI@f%PR[B\$Na[8UC,J3Ig`Fg)r<Ub6pi;E3>sG^PRj2V'0Z %#a0e6JU%E:(n[r%%V6m+oJM9X_:?q-B+0+W`skF2C^>\3on7R=_Vp\)`KTsq%,`"k0IG"Sfe8V6\i$-8?t"l&=B-qa3ML?4Wt=>i %#O5d+Wp>nS!LKDh:fLd)FAAA>/+o"7U9o4PR2V7+:De_,!mF#Cg.f5un7nW_2i%bB/>6!7/.-)%+B(sVU.3CbQjC!I'GYB_MT!)5 %bef<<e]%Y0T(RX,dH-.oI<W(J;5hhp:p'YTnj?eoeuI60*,0-brP=tM0K;7tMBb$Yno\e#&=*g>s5Q\&Q.$IQXJfV9Kbs)N`\^7= %)VGh4arbg(QYMA]6AQ5UX+s,"95ge$)/(IT+JOE4KfP:T]I"paAt^j#<WZC;I%'/m*?'-SSh5TI%dHSr.2t'K`QH@Q'b/4i)JB96 %pjC)FbQuI[K>4K\=)FmV=Q[Tkgi0lk6]%-^(gn4JQfNt:L[Zuk-b*?<JbuEAFXb]Kna0qYkePk]`:fOC<L:HKm-!J,"PLIeE(CZM %YW\ni'AVPX.J6.77kmmf]tBp+=*DN]EUM;m"]+TU27e$#/aO8mkc.SnWcB^4$p"BM>bI>#/rX#>XAB13],%PWqn;P0acC!T:cVA( %S5M#-gco?Wc!8+[bg33$;+O?m&E!'nT92nOW4cnJ8p19N6-Q[/KJuojbrd-[PeLQ,1f/!gRJ:?L);Z@gkZSc?8f$B=5?ebC9G)Yr %V4Aq^F2`/E)g)NK%NaVa@uF3edT*+6e<2Lok5F[8Cjc91,mgl]B.'ffYF1:rPuHd,Z$cS7MT>XLEoKqrqk>UbL4!P2Sp7]-=Qk`" %>/;b`dU`S#PU;q%+E:E/8R/ioK8UkU-Ie$`BeYhg%OTt#Ma_.lE,QJ](G9M2"!*-/LR?Gr&ge_OehAJN$:\3f6=^6;q[XhW'1W/) %6r7Hp>uc\1.m83-H%]p*^%.s/a)%_Y7Ai=O3VQPi:\45_2d3OEEH,6=8W.uR=<!(35(l#@,T?:(gn?d!YIJOcQW&U'j1S`)oT"P# %p8Sr@Vu.BDL[qXUbN>XmDDO:tHPJq=lt&LX*?SCo/c6'LbgJm.T7R=k7PW@9=E5RQ=BT0._^\)C@9LYCMm?,%^(T:1*']*%kqKPq %>\HR[6b/<OV24?D"EacPVE,.`!#oE_EQ=&QjYd>;\0E!M+=;';W%*#5=8&llSJPkq0e&%4MJXc<R!,834-M3uCV(i($^E5hVBhk" %$e`*a^1p-a\RrSu9^A!/gjVF)Igr+`(G[)@M.\bc;*3;N?1\=p%)5;t]?P'hQ15AAo;a>o+WaILWt834[EVC$UW8%?`"QG@2u.,f %eItqcPCT*@'=4`^('@JM4g:Xm\Cd9&\MLI^C?puRT>Z4R)"usD5?J\kiB1]qMq,dPXDE*8bSP1g%cMLYWqSjgZsTZt9"Gr6H7U4% %bd:'<J#ZYEYJP/4,H/ehU<73m&2)f`$CX\+0l+&eHZs+1eq.shEl!sL]F,Tm%4l[;fL<g98`&A;RCXQsE3XN\Zg=&dUl<Ss\;k^Y %,;/Z/EusJnLbXieMcm2M`bt&#cBoDQeZ\j:Aj*[flqlU#c"\AjZeMpHXU_^[V(9(EY48B4X14P^KQ#BTTgjbe_T5E]J;[tg27a3e %HoJ0@):I\K"AM4M6*IY[e`s/^'%:JXf>e)<ne)[gI@+bmPbU^t_u->jQB*7^&t)=/[u]/B00Op'bSg;6(Cb5),7pfGFb=rH"?*)1 %O!qrFRg)L.,faAn(XkDN4AE9[U3[6?H?51bRq(bT1hCC\Wt*@$L6Bjn./JHcc%>jio99BW8rZs3\`Z^ID!"K`N&t`nXI/laZ7Mes %Z1XG7"TO6'HddR]>a$ctA):Cj.7VQk?JHFM&N>>6o/\$A1E];UOY\4OaA+J<Z;*DH$_rdqbuoAG-'F&OI9eUnoT5*\3<d[K1?L*? %@TJ=FoY=KW-]*M!<7X@H#k3LCbJZ)>oY1.J%a6'F^hJ2kl^G7ZdZl^8[iO?+DhXHu._KJ`>d=j?WI:+89eisIo?Q(9-nFppN^l%n %i%@3EZ'&XpGS3qF#8g_LW=\]_f+l*bS_la"#@V'nF9dn;>qE^ib%4Q_C#i=B-eJ,q2k?P.;FKucn+-icA"s:Mpbpr)Y<$N4f)@_G %`N+CN<d'AV4]o!ooeB'IF_;pc;Z]E;="P3IFKMa?)eX[Pg!^@<(+d@qh'gjtU.D-dX1ERFabqA6/MHGENZq2:hj3l^%ZSK6EspOC %9fQ;FXU?mt%;9KU8+=%DenMNaA]Dfk!F,k%$nonG[P7nM:`#7)gD;7<kZ1%bmPYM)*MX1(b?=NOgL]@2@psmK%7>AC-s3hL[ZpUS %Vg"hAfNkAdb&,SF7<sd?>6hr0ZB$N^*2cXB52C+k_]iSCqq?1nT0d_e]'CRShn,BTnV"9n0o/Xo;=saMWo=Io0FZ1b0&nEs,p2)R %X=WOuW*n&l1>c5+k@H?^`gX#Od</GO@M#ihX-E9;Hd#%tUR4h_2u<_+\3cjZhqMi/kUfG&oI\-j=fa=Db95:,L)e"!Y5j?7"8\Ga %`o<bGK5FQV[s7I[4'%e)O'EY:?5+F'E0H-u^/^R:71#\Xi(+[9@TK!,l"1((_g\e2EI0NaNLU.b24no!h/")9RkY$jFt>E*2W;99 %5%_$8pmaTFfM$J7GHA5"<^P$Q5HGXr/t:&IGg<(ES%W$".lFC"\e`Gf$t14\6JPaH'@T"=I*l-#79*4S`9MW$G:OaPBpJ)3g.^iu %ckq!43_Or&XDQi%-)D@]iU'9l9!NCXK:@jWrVl0;gf4sP[1:-+O]/'aZ3,Wb=9BcLgK(L%\@?UCB;fEKZ8l2.jn:GMYjUY%K/df+ %P/m'n<?[SI`G6`Rb@o':B&`k:d(Ta/X*EbAmAR>T[MT']P8]>V_/CAbRL%WB:+$-@41&d1$(7Kn8<`X$'(KfH[;PDB^HNNs_k,1G %mWOYK@LS>An>^`r[grMY/`2`)J$QomR0;i?HYm&a#o5a2]FYeQUVCTFKVCp+:s<@'?S['o=H"r-oK(^U%'V4D`VeYb>J]R>%lihq %oCD3FZpUg]F^M/+]0I6%miY.h&_7W%=4u4>VDL5*ULjS&\8D@0mF5[GU;S;`gGf6q[rc=2XrY5B$q*HH-(15MStfSbJK;d^NqLYq %8'?J-MTr2T^ijSpTCMY@XBPYY!Jqp2_SB"upf*O@@Gu7bG:Kq^10FCe"b\<Eqc#eSJO[\3.hKR:o'/nZSM6]_r-1<OZ/bSL+jQTQ %EN2dTDE\26D31J@")8MZ$sFMD"86T[kESi?\-%\8qm2q`PMK`Dg8G4a_bFO3i([02]l%&/WWB+3N!.PFO.Sadb'OcCgCHaCP-a/Y %etMiRng;j=b9D;i`9uCfM62qIDd=2oCDSP!>NILXE6eP<]+TfnVt.R+`!3_i*(1S3l$&Oij^Am)J['Q9.DMtrh/BW-2BajoMYaPK %2:W'b3nUHFU.T$"/gIbfKYZBsU(dL%jW/#qOs7c_#*Ia_!=JI7o(5+0E,-TdTO^I6dV9?lg2[U(hS\8p3rH@NCQiFIF_2?=LcrVV %<'!S3600)^r&lR-mr74)aL',XjV?J=%@NKc'<:Rbf:1h`*)D0L4nDZ)DSffMWiYK=lR-g#ZLmS56errl1sK19Yu`qUf#K$]igFFi %Z0K6f#M="HRW-X)nf7H:ZB4O44H])Gi0<'aA[)9e<F=\MFs.=GF_P!Em\suXi4FFT.?5Xg1,(YbE@ZiZRAlYGWct/FVVTk#0Y`OV %Si>8b%2_^jT$uC4V<Z%HDJq'1pd(N2Z&50#M#aEuAK@jE+]Lm$^Hj>*!&4VZr9lEs7mZBuEH_SbD<h8gD!@*DBWcHrF,c3d`%;m6 %0fH7</R,L.d%G+-;%#%1Fq+JemotnP=`;-\@/5sohrcNQelF(93/&RQB#[d]__W6JP>T1i,NE%aS6R^9)RiZ&/Gf$J]LH?eg*V5# %k-3<j3;WJB/@^otCo,TSnG%XL0Z8rfp'.mVOm);C(Q$X/"\WYP_-,uT)RNp&r#VUEs.*)%IaLD(-GsF22+YEpDrI-PT^,U/?\fM8 %';AigU5a%/-P@($Q(^AWf0FrAa-,!GWle#rS-]R_n>i`kmZ`!QHRc?ZY=i[k[X\Q0H!i,L:,Xeo%dTekb++\[576qcDVJ]"EWEK4 %>ELP;;$lRY-!SIC:a]P)N.r2:7,q]"31\OACoS\E$l9r0rGsJL\W$01*Do2hR,:MD2/+UoP*5l>O!h8HM>O2gnS0q>M:6T8QD,`# %6410J&E]a`h&IB+WelWDUJr7(M]ZpjN[B(A.6j0Ni75nV^iLJ'@dc9<'McSTTu08;EusbC9iZUtkg#dm<1R-a=Zf3Y_Qmj2j%6g1 %/G?scJd9+K=Or6JSb[,?Ht.erEE)EWGHsU=6[&0s%NW$VMe2:q?p._c;/BY(k[=D4?s6D!G*<\V@F?BcQbS<^c4?m.)QhE0h`GZt %\r'gj.o8&*g'PrqiE7:irBSO'X=!i>Uh(Gt'rhH(83[b@<U$f"\p0bmNI3_99VrBXEFY"P!nVS+0]XGP*%_YY>j7/+LG:G^R;!(> %>V9A-RDrY$,c;#S1ZfD_@)YogR>qP)cM7joP/E0"?_?cAI=iAQ_tfPlFtu&D:Qbo6YW[^g6"Ano9,b*d>n8;Bhm%o)>I6pcS;ZtD %oCid/'os!.CI6gT-%\og67FX!#/RGmJqm^NhNf&G,E_WNQeomFlsgXab3Zd!Q?UEr1JcDU&W"XBZC]j]H0[A*DQc?#n=K:rA:qiU %PH$2C+l?oF!-^mb%i]A`@bG0i,kPu3ZJ'O-<U/ecHrUp2+X>oGLjtqCZ":oJ8D7JW8DW?PR:='L%<)@q/K/IIap0TiakEE'SEP`! %4'd7YUh+.le52Bsdm=ea?NaiX=,cd3/mOKt@:MkOZAP%]23iK`s*dH?"?L]TU,.]8%qRC;>b"m95\n%aQLI(#'[IM_.4-b?<)%ET %@MQU.HJPJ+[U+;>9)EF*4S6PiS`6dZ^oZ:umK0O$$OgI@E1dO]T>__>H;\PCC@^ENX^<O"mZ+*^@n\m2Gs"i)lDA"lUSoN.?/JP" %:1]aohKG`[24C)*'CX'phF52623:pNC8`bA.:fHSlZcME@r53ge&d!#UBZY$O1RT^QSrKk7U]kRHA=taU1e$:pt&%<-ap)2M,@K: %MJ$(+A"9p<-KpS?/LlR`^^>I=3T-k2D,u>4`EV'G4"M/WPo8A<8*TC^@[ZQfR5Q\k+gWe#[h'tj,70nq<*j\eplslI*/ijA=Cd\3 %2g?7](.b@$rnAVaD<H?\VaeV-hdoNe:a>prDY^MVR`/#87PKJ$0789*mb>.Tf2^&JF/@_BL5`^g;SC/sC*([`g3HF7-.s-k"s69F %8#KZ&:e94/F3"F/A1;n!!W=VeNG)dr:QnlLVp;&tpR%rmMPK+#.RW6aG'GG%BuIrF*"So:<0lktNPq2V!Z2NTe=E/AV?g+;V$C.K %\fi6h\RXuGdoiuNj`cNKpL99862nVFO:\B/X6QgH+E?<?Yr"f.9J\FtI4mShS>WRSdZg&/360-H:hYI-MXoT?h\5?i#pHTbS'q:* %TR?76g2;!<]4n,$b=^0e#*=]t6?`lI4f-C6eKNs$o;4rmb07H3J2bq<`dF,>H%rFHRh=CfM$q3>!:Tsa7=G"hK@etg\G5,=Gl7<, %@MLYre'<V;L-)5;/U=0)T6NiGnh1booO_Zn=_JdpVGe$)arhQL;.j6T9$\)\\G0$#ALWOX$8%9WD244[2-+fg&;_EhZk*oF\-;.8 %-V\$M)#=M6*$a<3i)t"ZfGA(m!uX%D*nor>Y"^a`4^8Nd&9D(K3"dB&a[Aq1r-Nqan-k7@AUZuZ,W4?`Lj>Pk9mL"R(.ZROC,1e@ %'`=Fm)B2b[jAR\P*gL@uX%3IgVL%lj3J&g:Z!qC2;:rBRR0tsL*@rZ<%j@N*`Rl`\&4cF,QGNh/JFaL9nKER`_E'Qtkrk(V7nUK] %QrWgF&C9&ra:\*7is;e^#qRn%%GuZ0QjCI&G]V?I:<%p430LDV.Xup<Jqah\(;rDk!")Bdf<nqM4C:lf93:80AM"[t[A4nGQ1uT] %hAV][9T^4*V$t[+?$:t'0SF"MR;JEILT0"P#7tZBNp5olb%JcK7!!qs_-R;#_Mm[e)`WQgd?+>Y@gM0_C&e:BY+-,W5D07g:neiR %k"5?JG)Lnn(^AZa%,<^ISr2iFBs;hFZh`t0Z\m@g<S>G>>=oj8q'lYGe^^;Q(hAo8Z$*N`=Xh@D6<5n?`O_n'p?jkK"3bd*(Stij %iYi\,s/9)]F$nWMf,0n<MFV]0RM;a(ETblR]WE?72Z):O1WpY@J"V@W\3sK2bXS;3;Co@0l63\$(R:`f!#r,R;B@SK(3FQ.e@U%n %@@o?\mY%;S01r1nfcn;(es3:G&0/L1]BYEfpgb8P=!1Nplac\E:LS<TogpIHCk">!"J4#W]bi<$EBt9c+YV'TaiJ_@@A)"j@6Mlj %Yq>MV0i=?Em.pSk:RI:!aL>.]Hc(Ml3e'i+EHqtO)6<#+,RrD;S/sL\g<&e'&LM"T^F?H[0#tCg3Bi+*2=Q,O'i\,]I\5hJne?KA %RsB]3hiNM6=<1Y<bbE[WdQ(nj-+6GcFe.`#>P)@%-2N\!1M%T,Vj#fK0!2@[$Re:<>MIcdB26/1Rr*K.>Zq#cnYQqI;B9Sd-"L!& %?kmGbl+g\a4hCrj-(*=(?o1!B_,!$m,SbR28$NQ4i.q#/![ABOCeqp<h]E*sJ1\cN+eOn!"9Z!iS8ljq%rN3Pg/)2MPjX?]`:+kC %6oMTFkQM$S9W/6ZWO?R$!2Y27m'b%50jdU^;u%>9mZoc,W:%hGEcIglRW+oCMMD;knlH.JY$-.k=bY6"EO`JV$?+BIDNeWC5/;Va %kNQ7n#S&"DPNISWBQ[:)hr0+]n^E7Z9S_T_<l\aK6nbm2m]ZcS_@E*?fVrS*Z$%/S5aseF<lF;I/6q+^]s:q,JkdM(D6s[hD5s!n %"dTDt\cuc&$u@]%f7n$0*2efo`51nNfh_o7`N&?l+<tVQeuW)ea:5a]#jOCR_H,bC6q09VXN$o7P<>Cjo0Qd;e=D"b+&/"^&,b'W %-5uL69g&2bIWeO]I<49#=LlV>>D^-RB$hKa1tgBt\>=j"I"]dV-HpbU)TH28FDaKOEoW$lX^4gl*GU=]iJ_WaZeNSIR*#nP<I?oe %/DBK!M,k<8ipU"NdBG&ZHjW/iSnM+PjR"oOFrFR1X(K6T]/#shS7JR??7UWdNLS^]gff/<ZBCYt3%]HVTRn(A;>R`ZKdS$f>UqYq %YT?ZN%?ED.F[Zu,Q!<><Y"]?FPs9i`aP`>?bFk_%8u01hp3Es,lW,(c#^$s#:*K5?Wrq8KWZip_btJ?-(BAr-M^%$)0S8=_cTR(Y %_l,J.3'=k>+YO_,4G<4659-!0#"Z*U'F_1cj_kHfST%]:TCg=[IR.UnKVcc]ZkSk#dU4.YR-2Z:h0-rIpW/BUb`I.La#YTfF]LQ3 %)7DHS0_g"+.S.%MjI,_biNg\M)/QSpN3j!TWVo0Sd3@VJ>t*+D62?$::=)e`NZR#h;?0K6;VnjlQm>-4WC=jM/0]aW<U@/MrNN!- %XB4F%S/e"s&BVmqZ+.ns'p2Rii(:"%e'"i8Z*mTC9I*fr7`JPEfX%BFOe&'k%oML=lZ\larrQW>Qll@/)Rt.0'$V2MbG:P":_f+! %)aYbGqF,_iA$Bn-SfE_8am#g[C!XYmD?Z=o*k;kmC_nYIqE)*(WN[=s"I<._r%;#<C007tCKGhl<A29<0QPhjq([O+-X@*KPI^`; %FR@MS\6s&*^I$6L+*"nh:8T:JL851P41FY@(Aq%W5i1km7I%EOg/t+&:^G1uerK1.72s_8pnMQ=,_7<2@Uo'pJ+i)D)o:8E>ZWcP %\<lL>:/6@KYT//Da)EX>SfF:KdKO9#Oj-9nE>He"'s_/1<SGCEph[OiVJUAN+Og3.ia_F%:#8^5E:`a$_PLV*\Z^hQE$sSiNVfc* %#p\*3&2oGlquhK9U8.(i.&Yrp*c-SC4m<M0*684BpauEd43%__ZWWH?NN5/CZI[H#&O^sW4';bs2fCSb7&gZ$#c#mL?+H"HWc[M6 %?0,"2&.?La%&6Pm+F7,+oc5$VJej%XeeJMN#$[ATa#!lKriqJ=79>d<S#?Y_33l?DoI^FR5"3m[/rFh)W(Ki3^S=(oEC/?bW1C2r %#5j45#0a^#R/TEULDLe:JpK&-+B]=lcH)DS",5I4`lhU%M`sujXej-/aUg@LWR'@E98T+7PTq3aJh@Je]>=HVJIs?^+f#YE!,q^3 %4mI%7"S=9LLMOkG'raBs;r>1+&[uBT"kq03XgABLhdhJM$0eT.BhI9'=-)R<@)Daml:B_FaoSgkF+*N#Y&W@T%l?O4q@hPg6;oYM %#ZJ$t<]Ho;jbWA3k80GO++NY0EU>I5_ZJtaq>X'#fIDun]Jtq+X3oe7b3P-t7-.p^27kL1DDuX)YI^`J9U57S4Z:srOM]%tjV[L, %pRc"N'YY70J0,@in?L6@)u+#lYk+eJGXgkF5ChB4"2Kq7n4h-=P"tlcCRe)U3$C:p6AR"1OpbM'Y*Pe9WQZf$Vd7@e<i*3M<at%W %gQi;U6M,qde<rD76@U6D\1$c30GTi6<iN42.2H]fI(In3d-VZO&J3:`Gc+ZnhZTpJ9_DOfC@oljSu]gP4d@pZ]tCA<>XG^%](#U_ %DAfJ7YC=O5Via5\U2Bg@mgt[gX5+ahD,KD(@7at6J.JYcG*n,Ulj?-oN.iHM.X`/ak8lmHaSW8p9RgNt]"h-;?-H&CW)=T6IH0MC %eF3rFRX\Lm(38WUTAK:=?KB$-+\t4XDChb";\4'rs3Mr1LCrSeCC^4=NWtkd[ckoW9-IAXM\NI-jhe^?47CD+Ji'jFNt-oI2;600 %P$;%PGq.cb?'4_@"oXpAZ\XqgDP0$:r%nOhL76Q*4HY\'6n0>7*ZSTD,40>$:jcNSXsgrrDAs6eN[kn[X2IO?V4;Wm)"&Q0d(`Rh %,`nqa/H=c"K6$NZ.NjB\*H`Opi_p'f9hb-B6kQgl-D#fV+J4('E=p,>"WZ<Nq5T2/`mUo"1&;[XYH5P$TV$Fae"jL4`,PXUXAhUg %Wi'Bk8ao\YWA(dZIE^KKidl'W]>U6%X9MFZ]]Y<gWQ0Sa$X2edeRRb8,r+XEg[rM-kM%>:$/12h:K\jtg=;."A6)ec`47Au_*B_M %D`,utGjZDqC`/D**r<iSh*Qlkq.co\D,6&iT[5._g]eZUQdE,O(Ph%(N)6oLg!GEVHsC<1Heet>^'.h8YmZ&`orl?,)E@nP9&Q:g %Pa_l3RG?`g,ltgt2+US&j)ZGXTl>pl(d'F8j$%Ze:f*9KI]8=NTR'6!fc`W6Ve33!>.KN.\-MaKi`WcFRtq'6@jMI`eg7J.I<E$E %gZu<DO\;MrFtd^Hdt:ejXi=mlbL6]DlI<kRRkDC%(E\(]^f'1<.GagT"-,mZD*h$CB%K^-UK06iDCRIRO$G,#\1:8^*0:nKO<VU] %SMY+P9<9N2W<<1RSn/dt=3k"6@[u^a:JQAX7$;rA9b@]Ph6[1EN;`'JHfu^O+L4(H_feRp8#-]qpraG**6p+=#XaRgkZ@A?ab6-- %I5H6MbagWGkeL[8c@K4]OT9+_SCTt9]M7=j^:9"Nc#?'V_Cp;+PGTL?0RoK!oQGnYT[+rKAG]Q(eQ#qo[4`Df.M)2dBFfE@'kgXd %7c*+XlDSj0">)MYJANd_Z9^7-[S\AP,o"I-Gur/5W'1cX=(0l1BGdaC9]);&J"nEZ;Y(jm&M>4bT>,oKp=/Xp`%8"%P`aNm"e2RT %EC*Ym(S4O(#t4,4VI(VM()!I=;<d_l[rE&_!9T-5Z_$3N1D/"F*eaj;[c=4Ihd/84VE*H\>I1IaDV=WL27JFulNR2!/hHWpZ5ToJ %I)BS9ru6G?O$U_kl=HZ?;LErn&'`0.X/\5_3@"+PM=okYLdXXN&dA+8A[?$IOB'Z9I$.(9lC$K^?[pk5Qg/?k:3<tnNkT6S2l9rZ %P>>jYeJ::_s8$#DMNg8)T=(uO0MD7)pOHPU'M\/.*cP'/J^W?SIY3lmCO8Inhd/52VV-Lsgm459UcBAZ!?N#VSs:%^:A*3aYP\lG %p:GXuBY5&/*DH[ej\op1c@\_1JYJ#Sg7XRrf_DU=W!Wok4Fb-aZqh-Pe=uA:nBpJsao]C5D!sJ5bfe:(Msd"pC9rdS.gn$Y&I#rG %Y^_7CLqo5m#g7G'S-Jq0?>:EG5q"]$?i#hOh_aF10VK+!)u%<M#M?A/IBf7Q4>Z2#L"c0RVpEah6071HBrO#@;k?,Z`!;'XBNde+ %S5o6[ZT;5#4_/Q+/@'a7!FVP3HP2Z361V?tniOi?<k>I10_Vk`_bBDjR2"8dEL:qs'SUTd8erlgkgR_hWu'sqoLIbfrH17N4fpOp %Q;h3XS3FF*l0Ct%T7LKtLR=aM)$nb(;I>rolXmk%R/kOQU54s$hO\k?Q[OhP]^,[>U**Unb9e)NNCeQ7=;'^:$e&>g3p0s@aIaF1 %I%.1B4l(7Pc&sf6a7-<TP0'386TrTK7odkME1FDhD=aSR7@c`8cVGbBAJT`,AE&K:7pnY!7J&thnsr,lK$ktBa5/_r8]W%Pabe5s %.FC2<[=cC%pY9&%a4s4:N7(]@a3i]#/,$8mTr-(_<ELT]^teEDqlH_;Q&.G8"9L_@[j'kQI!Q(!C3L]$hmngVi`0/@B5'!Z_7Pa/ %;)3'!iSs2pFd\`sL0b[Z:li.`br#>RO_ci*<IKdZ@HLH_@g\;N)^'7^YYr]A*%>8,6PpEK(]kJ3S-r^:s"Y9MR1h;)T7oR6`-5H5 %(Y^dM-jRD8,&C"Nd%PFNL<s4-Z)$X.2Q8Opn>4HfNIS"H-:H\A(!^Ik4A3em9?Dj`:ot^R1nbcQ]"$WEOej4uJhi/ap#C41<5K@a %4#f-Yp"pFPUk<Dao&+eQT[TE%*\nn@'jF%p+6G[AC`oZmicMA/h/TjWZNXb,\Z[g*[:Coc@%6-u]Q&G;2Hl]P,jEhG1:1Sk's;n5 %EO7BNJW94s\cX"jF^H;f>[@_]5(C96cBSt\O4)/rZS_4;1p3M=Xpf_%o_SWDRS[eC@B@jo!D:YV.s*leU'1!aG4/lHc0,12%+dfk %T6<`sCP%Ja=#-N9C[-:3`R<ANcCM&"2erU``i49!_>tI;.MITa.mCqT'uXl^("l2g;-EL2KMittDI!F4R8RMR--meQKrb=*6t=o+ %2&4a9)Y7cQL^a@^7j2[uq)f7=>of5^+-L/h2<eLC>,GH(/r"mD_6LSE#jFr1=^@H\:r?a[g/SEh!4fA9GS>u91*LkLWrh)8q,mr- %Q%NJ$mH2AK;'XT.<Ng_b"/P"YP-W9B.qF`ubD1\eDd9!$B0Dr,b6eI%lcA(U.k:uh?%kU]O*$X!('%rXTkTM;0JGI:$cHouC?F)- %(CL>u-<.BF9ghn'4H%_*\i!KoYFH8W<WU;1H-S73lK,UL)\n*,dJKa]!8[&<*dm-jg$.(aPKU*`(bnU4ZoJjV^3LCj=dJ(m>/XXi %pWL:\M>mm;7AQ6h]iEFe0?t-hUZIV"61)?$2P:FToBNkh%YZnZ#*]b(O;1,;Y%roN^Y)IO3f^;W$U9;S/9tED2U$_E*-"6,@b&DT %LHiZ4F!,Ncr,5"j<I^>3mCB]*q$&79rDI?6?U87N#t-ZV<aaQRJR&$9B)h]XG2o]Z`PsZdr[r^@T=X]$h;uJ\UX0eRbNc%!ns(CB %L9i(mk3#3ord2.*4YMQd03Kc*,fN,H,h<.S<n$2Nki_'+^L4;;ar8W36qhJQA0eKF^]3Z4.=uJ&6Ii>[]c0D,:14eHndA44J"PK2 %=)[7P(K,i^Z^mAsC-[R$/U(fYNS!b1XRA@KKdlTW^7t]iV37?l4-Rb1)q\ub;\.0N:7IrK6d;ko4:?/X"]<[9+PH:s[ds9*H#rud %eVXFoD?nICB0uC8UMP7AFD^:HmeNR/l,;V86u73%Palf'h\'ff^:-#]g/ifh4@+m:F5<c]#\.]oBDa9E1VCs55n!H%<nRfWh1#@) %=XEbYF,5rL]9Cb*c28-:20Kd"1_WrdS]$oC?a<lYlX7()7UT:OJON0*:h4a]UT0"pm]L)<F)c<<_L<B'@=ruNT<]LeS.tMj&q9?] %(>)YrO-Gm!]$#kt`["]q7ClU"h9hs8BK$PTI!R-G+73bi5`O;*YnS-tXTe9=DPs&FJ=V;)4'aYTem\`0'>DE?);c)18fS!5cH81@ %_B82E$ml:cqJ&s&\!aL%#56VK7SJ]@U6hA<^bW4>kqRf".)_\=ZpOlN.%UQNKcLaleJ4*ZLTfFN1#Umkl=hVd@rm/;AJ,rm2a_DR %_)qA@O4W2trNL(BfF)9C,6?%9Z;@6/KqRu!cLG.FJ3j&FYRBM4iXH>_kEP9>6GNSa\aR\Y#NoW)/P$7"9j%RTLGa?.rMjLap#D.C %"u`N:]=*ZbJ`eC0qp`<Mgkg+#Y^?@'I^(2_e"*`o8W@nKY@qr.nF0fmHb*$Jc]+IG5;g@0affia42f!C^aEj%,30<V;0H"^l##Cl %l?%,X^o8+JgJF:ZilI"eS6UE6;J4XCfW50(mOi>*R%Bd1T?W%SFK%C7?TNC/"fYSJKK'C=30Q_cGR.H*.uAQJq/tTFO&+f[IRL34 %0*X,]QuLHQTH1O*IuNQdFT8O.jMeM*'<EG>alKB7o+"^ee7:QXTSXmB`OU=uCt7695fOuFD_IUB.k>E'3RKD.YLP8884Q7J,sJ6- %S:]FtMO1lcRas*Lei4iEKF&#uGUJ.RN;IZ,W$-^kiUJR9?tA+;->@m*&9P=i:0e,JZ?ZLD8.M'.l:b8;1//HCH3g!4iJbH!9Oa>P %1e&er5BB[J2JXFE8(K/KGUmpLd"/'W$Js6l8(5C&e]=_$`1Q[923tJjcA9lu^^11efPWOhSc(J0?_87@$KZ?Og:4?k$Ei6.PNQQ* %pT>YdkU_h0H#6BBWjqqeZJ^J?EL-1im!fI_0]j:sV2G*HGl_kq1r]nZl5aomNY6uk`0k4T(R1.NMBI[i60Q-/%5$.DohC$-;*_(N %q0qT/HaX[E2X@UgXhJG6A`T]"b\tM>#'plI].1nPWbhI<Q%4b_So51417#k[=s#Lkb6f^b5Bfda7L+mLoDR:uQ,O]_FPF2,b<K\o %+.BhHAfhL&+q.2YQm"iNkI%L.OWL1miWC=CjZZ,Fk/'=7C7P:L4lGQ8r,jF+B#MD^/70mS8Ilt-dT]IUo<6'DZD4SkG;Kj6:`lj$ %Gm0^O*'O%HlKDVI/^mU4L,M(G%C<s9(uch=Z0)e3n6CVVD1'_\hNgqt8?6)S!(tOlF`Kqa&qg6':Sa_=&?/Zf6i?TCN/i1ai]hI% %d]4Ge3*lF61:r:hB'+RkC3aUjKH]mt*XX3t5Xj;K[j]!\%N)@,0?sPr8L\8'`/;ElkQ<rL9UL)g'*%UQms`tTs2A@Er-/1q(Ou9_ %J,MU5J+qk#i?/']O+7/Ds3L`,pOE%g5Q:0`+oIgZr:g6hLC`CZpt[%knGDs0r.gncrQCh]c[Yoghr"CQTDnc`Du)KoSG^-OpR`LV %q&^].pqIlEs7g[4q1&8:J,_a]ci7D!r`fDqnd>pnhdunLhkX\Rq!E\nU-ZWe_%pA!Y+Pa1HhBW''YRE5IfJq\XRs_C0W2/(/RH\c %9a2n'l"ZB^g`V>^-:eq=@nK.U4hlpEg/IaZ#I]NrAJBL^<'_^jbJfrqW&C//9Z4E]1A3bMj<PZu80$U4\ui$`_e%@d3SV_h/[_Tp %72!9uGF(#`-D,q$,6\bKOiu.*lATADkrY/$C"-(:1Jf?7LG70i+lg^(HFcIu$Qo(`#EG9lWRAFX?G/]gOK`1RS'<p8?'4PO<C_'^ %OW`7;*kI$uXF]qtYd#\VDOCr]lG;`=Vj?#D#*Z`T:&GI:DO-u7W/Y6&&Xf!YioDn8Aqi<9h-+*(@b!`b5Zh-,^5[0IXlY*<>0TL^ %2KfI%A?Q1bi#<2D.aWJZ<U\fg#$ISad#E`H=T?j[)o,[L<I;k\r@s0lZ?3_UO>&k11dJG3aE1BGKERi+`/%UlkQ2?R%Fc-,Um+F. %T,o"HS]S\U5`p(eL?MPS?p.W5V4'4`C^VBoPLVq$Z@Q10)K6O##a&HSg3I>Z1L(A9m.I/RZ:9TanRY\>8k5H#VutNiWg%<BRKdYb %E>=3JRE9kH?*n8k4]WMYVVm_`(tp7-&ISu;XHs<N^/)/X9r+IaAk40kSWh!HNk8\n5Z\P>_:pcH:`)*S`!k2[(s"%-`^S6O8VXq[ %EbHgnJ'#1K])7)u1s>ZnPDBfRN`rr!?B.-]%58T2^10j3<?W:(Pse,c264gKLbbJokU^bPU"D9>Re\YUO*iXZ-pZf4+e-!XUr9,_ %GGqd_<Se=aPXFTanDq]KF<ISu*q7paE'8r";g.T&[or)NT!aB198eV]6T%-_8r#A]lbL-T!?7Ri]*6\/?G_X;=p$d[E9X&)?M232 %;(d7t_e2h^X>A$>^'q1tqY8MMS-LTJ@(qrP!`*neRmg3]:HWo\hWf<T7n$tj46h`.Kd``05j-%K#b7=2-lR!>?qn1)M0MJSZaPLE %:hi]bLguqZ8/Z$tNk,C96Y/lng0$t@SWr51``bI?-b5u+@5PHf5MTi9e6!WY3Mek&N4E:B<ZNH^)Ma@$9SCEP0j&9X+r*I;U=rN5 %[kiap($BT6(BFigk1str=lgljF-BSG.``kU*gO@]`)<@P?egafRL3j%S@r,^_]Dj1-Bn&PDlaM5[pk"L3/"1Z8L&c(Uk>'^/$"cY %(]kAW-J$\/2D>&*UP,hP#FJ+rD'%17p<9%**2nt"gO0`OTJUgmos7Wfc&Vs3fi)FOXT,MV_"5IC1$6HY_(4$'m^[&&*?Z7[G.&Cq %.P*r=d*<>lYlkWC'r(N1Cue?c)0T=$GYAhR\V1i4Ra?@UBlU2J'.#>rdEJkGjd6<,Kr0Z?GoR3cd#G,u19o+4WTg1N#,N=;"lE-7 %,dq:k#HA*2i((;l6PVBu]h.<?J6B49s1sS&!'FGMJScl1e^&H7K(i(a.NVm:f.UQlR.(4lbH4DU&QLA(e56]a,d01]&QM,l?rH!4 %]<E)FVa&WcLNj'K@Fba*,j2ieU[l&OQmO9cZq,Z[;RLRX\[;l/3nT4u2\E9.Ff^q9>qMdX1CQ6%e\2&"4.sprWVPps21(8,]#O+B %+UB`Yl4M7(\*Brj#?-<Hk*DDtdtM)G5aF+_^H#8-!gQaEZ4A+Xht'hccCe'CW[['S&;giEKiYZ3e$7c&g(]1*1Rd4>As-XS&i$hg %Fd4?WpFSXZ5e*KhbW!QJYa12q0U&pccc83.<+ZR:PK0C%7u."kPI:Wj/dpjGL:,o^@Q6S$Qi#ti4'`LfO8$p9r>*K%G7dhX\TDj" %KEIlZ3sLi>.XLk:Ia6bOs2t-`efDc3>W<+Zndf"VOjRp&*C:,bFkfQLO$!oR+f7Q?!lGo:LCWaJ(!`IkI3]&G:&1/YVeX2K]$0nQ %>TI.]d9fg_Ho$fOSSF^^T3'MK+aHA(_23b2D3@S$XpuhG;>^d^j84`5_F^V[WWnV9^"$<E6%!@Gif4=i6ASFVe_K(CMd06F7XfZ: %OHeb'p_=IH<#s><h9iBFl'$#;2b:=16n7VtK.+=\D!g37a2E*+OeCi>#SH`K0fRRAZmrMR2RBf;'=@mu.5t3+-Xf9YQmiR'aj&13 %I<"Q*PMAA-8jk[Q#UUNOE.Z+Rk_Uk71P-^a`Mh2E$Om4&Af`MCa4YpG"\^UrSEZOd9+pHm>)O3]G2Z8jaXN39#XUnbnPtOogtJ7f %RkU30H/Leu1JZ>nm')H4!+0_[190sN0h_E]kkb_UN`29MF9('qAWZMm2OkhS#L9?\'6aBKe!iD+nEN*YMm<N]1G$m^&^.ErbBR:e %=pg.rD=N5E.$?1SPg]J;NZ*"!%Um[iXUH>'g>(HoF.G!k:5L##1Z*Ga(Hbn)-h\Z'ieYe^22lM(S@>=K!`uYb\;?UV\:57)SBM4[ %JC<+ukEto^=Xs.Bh!"kAS^QQm"&QX>`lufu9A,$F2Bm^_kjljLfS&")%8=bb/Pd_@Z-sP":-@.PXTF,jV3lNr(Y?4ndie"<*5%$: %`6=O2b0W]>mQoIE,`fgK`o^['.c;Y'Q&Qs"19SD.#[LN,Xai64)qq-)W_V>CI]-p6U-R:=Yu%qZ]h7[h'29>_cTXF2J1O],C1/#L %.eTcX#bMhP&:)ZMkij7/GWGi:_9OG]p4hA3G,Tq`?H8;u/IgN=$4rR`nk9>FbiJ)Y3(_l\Mbd'[a^M_0Bc!6Zl#^#;<S-KUhe5ZT %[$\"9]Y/4Dm=7nM2)R)g\5/D=rnaKh;N];!PD'WCEe8\LQ:tS<DOfbHIs_""2aK[+JD2,'@4_%IF\+IGLb;-1Nrl-A7`([kP.DIi %O=6Z6RTa8>1I_6"\HC`CQ_f_6S>l?*$J[2NeZBbBk09\r@*TO@-W@rX$Yk2hRlB>rr&r.DOu17XpO=2@qlbpCNDHgbs3bQuO5(L0 %M%>Z8^O>3:r:WE=%),r:Pj3/I$h;c'L!BV^cV>DAdBgmmGoSppV.uU(a1ehnqM.)ud+Am/+42rE_D[<iH1>/qP0r@D;0D50E*\G, %+[PTuChcgkXJ]IR/S<.o$"5ofX=1,XV/fLEP*N_Lf;_Zl,=dtYAj\t)T+f^ND*+EHlD91(I\u93TfLNaYZ-SRHBR$<9"B;J&,:`Q %Ut5"qoW$UlX,/9'DPCa]XHh*aeH0^G1g1oqVo^,!o%Q<V?fWkFnn5<RhM:b3F<0BE.\q`>r7V\ZSfW_/<+-q\mFWF<??C]m:kP#, %;u*,f<_">1@o<'>/Y@pJ4Dr1-+*ZbE5ttR.WRB'KU.;4PoFDlXXR\QV.Zps(Zjg9(MeU6ZE@5K,iSHJsc";^1!HXp:2=];OZ[6?A %e%t<cXYsooY0JhC,]A8>jHVh`f](K[(1)',N*?EnIit[Wc3oCCd6UN_Dc8r,$V=l,4Wi[N)@<<j6]VQb^")I$FAh$4Ydd_LYcNVS %3Yhm71miKfA>1@g]E[RZKWH/=qqCn\_O7g\4l.)?73/OJ\r"XX7JFNQ)uVLMSX9th[42L"KaHXI/+!RkO+;$[b=Z;qK-Km6is$<C %P4*+R.J!YUApUK209^LGF<#S&2emGn&[s:)@EubcQM[4^oW6D\,#(9h=sb5Zs2/0Snm+Pjd"fG0EXUTr)k$<e2i^W@XW\G$GIF:7 %h#8TYVpe,`=#"q&paJs:RC%aH)mk30X/_Eg?m$B7EQJoI&>O]jMNgNCN8U\Gg/J/(j(A/A&(m6pQ81]/0(D6EMpqme1?2%Ld)WF/ %0noK9e^^G_>E0Uhgc9SU_6O8j\MS9O<_78OFdOmFW<PeOq2-6;9mG0R*O`S["_YA.bRm4gYX]hp5X8Lc<`mehFMttk7DAnd8X<]i %[m3k'_"jZ2KnDticABPa,HVFNVL3Q;DTG^^bFlbJM3*h`,Gl\0D7IWFI<1`rl&eIt6qu$*g@QP)@Hm_ur,G/'\YZ5[?CSa[d8WBO %R,O.Gdk:OEDYP+&HL4`FK!`aJV*!O:Y\WmR'9Ra:JW).s),0`I,hWs(@F50r"h5%pl?(=+(:a%:ElgHLEBp>WnU-of+X0RkGJtXK %]],?9P:2:%M#^44meC31^J'JE9]6#Y^pA0I,ibTd0U3L\S5DRjVDF#0_0Fq$A\KDbp_t'Na;?XY<@t=EUq-f_@fXaG6&VJD/?%6j %#oe_mdk\^?()bgg@ImBscVb3Fo5UWE_5]<BNh$q8rpc#ZfR8Z1B!#!E":hqONbWPUe7Ht:UN>9sHmNC%LoSuuLIC^Eq)1Q6n,koG %5g?AXEn6aq.C,U-N\g^</D?'a?C9.Un+Ik_`kX'A2Usben!DSX6)bt/gf0S^A'$0(,`VJLbhlM?dV7c=M`p5YY04b&_pL4uSLgat %EMFN]r,_D::@DY,0n[D]nD#l3Wle!j[Hpj1H@1/VDk;_9^%Wi/2$_Jn2A!LC5p18\)Im3$)/$=7)0D<gN*f'<eY/-@c[([+KR#5d %g74)a#9$-s2%gcSo6A!r+Ae8nXW=_is4+m]f73b>5Q.($rpcn9rXXMRr?)'gci<B"oG?C9)`tNos75?&rP/?rO8o-5J,f+Ir6=-s %ooC2EIfHnWiD74tBE.Pcs5rk4J+r^[)6aR<VXusJ<FM&8L<aD)+G?f,W;"Q7Q0F*^,0rlEUF3+9BLdrD#[2<3TqE6\),\Ud&`.MM %dDjq,-_CRc<b2jd4Fb.b2*ufc4*W'Hd"uU+f>$5-/*rCb>/PrJ^@]Ed`"S*D7?TYZ<m5@(H3;VHZtC?\KEQJJB.tLB<[QUA`Hff= %RrAi`bNAkaiFO-baf7gH6.%H-&05Dl+Vd9K@g0t.)b/X#Vd9t[cDi9'l).J)a'lSG.9XT0j_6Ib_Ob<-":i@GZHapVSplkW#0Ntm %+NSnk'8<&jiQ#jnbHZ`bA]g]>P.\N>dUmrf`KCjtanE^^6A4)_rV'_1/%ZI.cpi\7GT:_0Li\eI*N%<E!\1YQGE4--mi*Y)5c$IS %2\:5!au-K;?;D7E[h.fLd=[Y9;V[186;48A_P4jF>p-&O-QQhZJoLr@FhoO7hbFQMa^,aoKuI>;ee[>=apAc;F[F*orO"4G^S:lm %k^74U2;4XCr'LZs_7MJ>hICL5XTOOQgT_]tNT\i(C_O.Y13tW-n%!e#9h:c+KI*qEF6Gmk.ZB$4oru@QSdbsf$(:e`]T.HAUBp/i %3U#soKo7u@UG)S?1/_]AgR-%F4I^eS=Ra@#JbK(Qcln-5Cc\",rP!%*`p(X3?T[\LYZH`b8eQ_oiC*cGC_#:o>JqXF&#L"t)A^ri %'^)Ee3B"`1-7"Z@fEga;+\%6>9078I>2305,h214^\`W"WB(MAX6H9#WOpW]A\;5i9hs\A$MEHbit9+#BY,%(S/$7L)di5NBfp8/ %0h?1m[F:7cT7l1/.dpd*84**>&4neEni-BN>SI@s$<H<&K_:O>Cd'MEhs^V/"e.(4D%<@cY)YuGO$5q+)2gdApY@D&LY?:Eh'mn6 %/+FPr!-\^&Le\d/"$)(gSnhlDr'1@d1Jh2n,+tn<Bj@f%P76Oeol*%e2\'p;51,l7X#3(.`2o.:E$OPibUmpsO<5;XW8K#ZE^-9d %M[/kZA6&Q)LRHo8MiTWic4Hm`h*?UZPOKO:nEOHo[-4pW9Nu%W4ePqt$q@Ol#rd7W_`b:OD!*+QG4TUJ#4"9hrr]jo6=rJ"^LD%r %@'FU7UJZYEVoa6CN9^u=2?T2'q'7MPs2\hCVa.p7BOH+dpX-3[^P+m[&gre>e4@d%-e'bC;"2i^WA;Vf),(_bcEC+?BT47dj4D5> %ndqd%/QN,KDObSGHk0%4q:UL\hd#-H6G#@b/AjN84XaWI_%!K5X/?7$]5Z_JF=8^=.ZoGQ7l*05$bUq.i)<[m;J2Xk]$,!V[)kgH %4kg[$)oX5o1?#)%ef_#\X!m#F0KZK[0IDj)LX&2,fFrG:*scl5,QO9<5=M)^)?FsIR$a[o.@'Ggf#eM:_EAVb:2.QqOFm"LZKF&P %p3dO?0.4De"2"iPLiDT>F[O%"/m6gDAlc>oJpm^,j)0J\Rum[Uh^ESaj[A<1Ji.LPcOQ0H^SPl1eWnQB6LCAk+$HhE[9GcEC,!LH %N;"oefsn6D6Sb4)l5uaSk(%.bNa$;+14\]0RR7oOT]!is]T1qk#+<5>E-bS!1l2NEfcaXsN3r[mo__2RbKh/-"E8SuBsa<oL`9)W %+`\W>,#@Q6k=I$F-S6B7M@g^r;;42<$Rtp9*MgI#.=Hu7e'AQTmg]C`rp^L`NSc5Lr&Np;09/$<7Hf_VNK'UgmZBN=,=h'^^3u5, %X<jh:mj>a[WsrWS52*7iE],U(s74g]_u=+?)rn6fe,Sr?!>]?t]\Q.t]=hfGk1)Q3T&Li$dtAh32BR]+.2VhX'LK9r6F_V:f#8]" %N!?kB54GQpcgqriMuC5kQ_8\EYm3[&lu;A(%Q!ufkc?3d5N$<u`%t6P)#l@>i6c%U'0O8f^9%TYa2R^kO@!ahb`H[jS5FE_ll$cR %.>6@ClQL-]l#G\XN,8.7&DC,'h\K`_nb^B!5<\;p@0h3lUS%D_)idXLW-lhO*#P,bof+p??!-J&Ldta_F.kDHL9QECio8GK+?b]b %/PH@WAud"8n=._8F'ciN1J^-rI4!6ZE:nn2MK)$CnsN5=C"kgpFaOu$lAZ[Qm90-teifo<)lhgf:KS*p(T-tR@-uW(3!j0#o.=BY %UH6T!YQ+W4A3CID`NsPl*u?X-[a$?]:#'=7X*/INE>V_64VkYGid4r3q#C3>/DFS/l#%YqU(-(dI$Zm,&;8"=P//K7KV$`Y6KWVt %[J"!NF7DU9@q0`h5:u5-Scn`u[U9o,0YCmJp)'6VK9,FDll=*3cM;>qqs7@aR7I)26nB%10qed0k)*467]U^(PlY=g0;Dh1/M?`P %bMFan+hGm=/$Yp`_\]Q4C!9ba.ln6PBlWT,eC3RY:b7hD_`C,$H&,NI#):d_"[e(j`Ip<3#`HN$@T8FSlJhF7S9/`s1\De^Bh&W` %\;Q:OeR^r.\dP99K?eXG(^[P1ju!D%iu7d=QKJ[,"89XT]');4'PFb-@pE'ZW-QICci3IrJ+&Gec[5.t2dfAdk8GGOfefi`@n;SK %!M+7NbIsZV-P:Nq8*!qMfXhO.D"`VlgIRh?UP]<\J8)nE`9;f$*t9KEm>`Y1nSH$eB1`)JicCU.[Ts_)/KZUkRuSki5.c&)"^2MO %LTp?Fg9%fU?]Ol!3g[Ph@iS<'e\r&_#NP-(6UU'g^(;o>mYe:7]40Ef'Qj\$*BB9___^=p"_<](1]o2%J^#7#Y&;3UEGN6<BK=]F %G85/6q72b"\;B`j%"?*hHp#]mKXUh!LpPkPkePe1kJ^[D*1p=EdgnB)YT#\TQ6^,V>[70AiX&ds(Ud0t]Q6=t#1mR)rA9%7hd0p1 %JIl]V&8ne/ci?%b><!@fUui#;QKm"tq<Tdj_%:p0!uLC^n?'X=5K#-U/b*YI>)))'H1PT]5ZeHV&Aj#6'&kP6g3RopDW,\j>Gk;# %EL@ZZ0QTB=A0ZbM(A,''dt=WRMk&)VmGKE-[1)*-#+qH[?.fd^:M[,8f;I=V1I4bW:!UusA=S^,rVDg@O#@OH\ZkgZ#(j&/KsN=Z %.2X(1]GDNc)9]6kHS"qF>j1XqHDMs%cPA.9]G_%@bkEF]U'FtV("jr/Y!#!$_ljkBdPBU908$-D0>ht8j4(A`5Ik+iTuZr^T%rrL %RMUsLKYrB#[j+**g^G?J2H_ke8JuLLSQkFc)VA*11qkE6T9c5/nF]X@h1Yt.@RceYoY;<:fn85TE1mMD6g/W7/p&3Me7*j?Z#Q%L %[0pE@.dsf%KOrJ&1KFUfnf8ffU(rf8FD?",4"iKN']S;aSiO)4@C.SE<hUOm^*n*b%/T[*!tXci_p,o]j'>d7<!_7>nX9]0:n2qL %03c\d"qu<"`H[dS-N=k-D@>T:_W,Sa`ZLLk]WEk*MO-\D:G9o]`4;nBeYQn+lr<;:H"pToWOA2(R"s/`^Xg7[[kWt-#1LhPMqc4; %m#RdQGk>R:?bcV0?XJ94QQs;.?/`FT(kX!lqXnM-O4#gB=*uH:>IiAu7VHnd`A>D3n9"tB9\7IEI9Hcg\mR]RY.t#$X+g=haaUM- %Xkg^qQY>+f"8H\IcTRgbS9,g>'A+\F(m$YY1X!'2lcdG_npk\=\>,M3n/$c&;Y7U&b@cA%4!I:/6::XjZ/#N6r"'bS:5eT+EW17d %IF1*D5e9(2_lDn=EUYr,@;!n#Z)qSdb+8;6'C\%!VpH?Kh[COBLDo-gjWtmn#^uOF+KcJ5O,/<J5)XN4X?ic4jmD!e9(>h5&*]rk %M&s^Lh2hme0&.Q"r!F[QW.s;!4@:n2.kHHJ2N.!_%5>b27%B_ZDmCdKJ,AG\@pJfqOTLjDpj9Em7pf*+;d!Jc:PaS20ok-LWAhM0 %;6Qi-$N?b;6?aZ#k?ABKr'T7LLYCIM[.52G'Ma=e,NomP:r=fI?<WPI[CcoX(or.3gc/&j8o&X9i%F/(Y;no(Td#d:_64[WM\j>* %fjQJBYYrFqNlFA)*PBWuX=&>0U#<;:=-YeHY.#+Z<(ip]3abS@^g,3UfRjpYkH`H]`roRaM]9I47,f^L3.o0GWYhS+dBX_((aKd4 %"hij7J4XLm[epE:c6bA_=QtYi]f#qWPbnYZ?@dUnC2Tr<bG<0(A2A><<dc\q6W1sfo+\]R).c>)M^f0ObXtA8Ea6I0:ran^]FoV7 %i?+MJVTQg+V]VZdIR/un=r4@W#HkB\CqM8=$OXA4%FuNcJF9^3m#_[h#'pQSq4qt\Ks5`H?$=!hUKto5]+??jNsiTQRjY94QT!AF %-],tW;pB=%[2@OA)pYeQFZ(@2_8U84BG,_u<lq,co@=hnBe(`%'ADjEj/4Q&rM%gqHLS5L0>Hi7(nbV;9KE(ITOPc8=Qqs?*kK^: %`UE<pd4j6E[t?C,pT4nifO95\=.#iY0u56B"&flM%3l2pUqXD6O^i?>XtHl^C-D#*%8?$[-ls!f7MN:m""pI^]d'U!"-_g2P6Z8b %.hVX4W+quJ)I*P[/OqkNBQeSQ4uR&dMVu-db\l9YMpp;\>S((EI>mOMi`V?%a0SSUNk<mNn]Y>Zn)HDQq3u_HpDL+O#&ZKY\/d,T %C-]Aa1()-AY<4:as-n:Lm&W"`$Z%J@2Z7$aFB+PN6b=Ms\.h"\mf@O'&+5n+/*Ah_%!KW>f"l+Np9^#hA#,fH*%M$m&*l;MNu:!3 %5CLE#nac^SiV<q(Yh/o5E4A347h(0n?'RjurYc@Q58)0;*J<m"rU^Kf@`C9Xi7VS?L(0WDAK>2u"MRTAr:H$UK6nZ!?g^(!Tm',, %4&@sukZs!p9Q(Lh$)(T%0'ps(9T$W:8Niio3''bQC_4#\>ne^m-EIC=csfM6lR-$:\46eJ.X/#F6*(ZY.#TfoK?`(()%E[_dC=FI %B!^l-qQLBl'VUG?XEM?nq@)a:IW+F=5H0JLI0cn0-%<0=m:u"W=YjPk-JXaKq@FSP<!]70_*_1SG5WRhW"eL5&Viq:^D_Q;7YG\R %j*ifhBG4QuL7^n_LWs?r6mQ$YRKXiU)\%J7iNgh`7ll'=1q*@3jNF04M=&L,hs)@pW%&.+5(nV5]kN>j_cOhH49[QLWU4]J%jrUq %QaIfYOtQ+5K[=i=N[L6rq[hAX=R'AJSL2S0=,V'Y["s>o<NKuLAuC24`l/5Rg9Yd%cdj:g-sH:*_IW.%>-I)*&/qT"3m]&c,G'<# %pNFP\#+b@ZqNJ(r4bUiE=S7"G*;Q?n0I@cjG]mN5*&Lkn#uB]?$d$=Mqe@-'%*T8l?!H;IerXJ@LO\1(@dg9#*ifsL'i=F6+Lr-W %&43eq<u&2B*]#n?4:OQ2),<oTn-P]%i=h5ecG+/,dcq5g@qc@+6)\'/"e8k#X(r7K5l;2i.e1Ia@S%[0'lF(Wnn).c?")+P9d@Wg %l=i:3S-97QMjkfTh+K;<]]$lr4*&Lf%(D>[2O\!0%="Ds`BERsl&<T$3%Ul#\Id=r2b3$+JDj$93ugS<Z#<(p`/"c;W>!H4G5#Bt %5/\\IDhABE1f3FlmTjfk'8G\e1@d^6)-`uX^c[?rA$deY_?QMS/VL7r8\(Kfll<bmNq/&[7)7P-f'eUc]pBg%p8Y^8)Y!,-a0l'r %UOfs0#/Rp)=)FJh*_p)Fc40)K#Q0!02EJ-C0J4)1nc(u3]<0em,["S`E;nh/#c*6@q#0d9^!VJN((u37%?1q<WR;5V5.%n8o_4ed %2MQLY29g=\Q)>0^jj(/h'f3_E06S4C=@NBd2=#>Lk;"JX2(jfcW4?]99>,A8RbLnQ1\.m>EL+VN+3W;3I3"-JB#^+HO*]Zu:-#kg %V>,2CqW<6C(_e^iaI/0EG[YOYKjB.3!34%MF).OjWYl7P+;<W+68\-elbnrZL7gEa[]4%1YA:c7,V6&ie)nZ(\2E^$o)RZe6bQQ\ %$IDj!2(S?i!SgBu<dsfd=/MGN<g?_*[I/eJ;**+RcQXH6#hTJ6F;Sh/W?R(g]\#0^=Lau=@tN)gj)B*U_Hos=g9=TXq(W2$S:d/: %2mqj9S-1DgfS%9W,<Zu8L[T:Bj-k47olb]f;%ol3IMPsM:%jFf#jD_F/hW1(^e7u@J[,Puj-Zr4#t5(e2B=gn0COO*Me1E:.(6lj %6;5>-)dbmPR!+*o+3EAU(_!Z-;b'Y/#Gug#e3T&T2gbdVF:0Z03ig;RC93p.R_q%m2!;n1JdYOH/"AE`(!$k@qI;*DH?uuNYM[,. %>U"Lr-q>;Z+A';P-24jRm;U%=9TB-_UL';seaZ7Tb#I:CocmQB8u2)P/NsQK*L(U/[RFOZnKIJ-QCO(OTVQZ+V2"oR9J<3)HSLZD %%s=5H?22U16$l\.c5sU'*nPdC\jCj=dJ.J;<`0eUcI*ee>rs(]df$X)KSV0e^u6N@LA<<;Z,KdaXT'ie?"q!KrOsS"8YVUqi9"kh %;9s_C>^9PDT>+[`ENn:Q4%$N9K_s#*Dn>:F_2``m*Q+F)giMNS3S_g<>sCLqDJ)O_lGNp,E0c3UhW9D!:Xegg]q!L/H%%dL6SBU' %-n_+3`CgM#R_\[.pdplR3AG`h<%0[u:!JXOG?)_a)D-$6o4%3\a;0Z<qd9*;h%D+CYmn^r._Dp(&rhL\@@De%?!BB8c>[P/\++FT %^Dm`MK-WEs0#uH&-jpNub5iJ%VW"e,3MJ1Iq>8!XE=tTn,'5sL0BN)f=u67ZU`_&-R]5N]]-RJ7,i&=o&,+VaO8Jb-FWuK;jtaWE %R2AZOBPtkK+C6Xd!$hhN/n*!N":E#B0X/+m@:?qeL3?uB(l!uXE#FD(@DEe9[b!2m%%5#k3XisETKN_Pj%R67Bb7'V/uaX\D%S*S %Y/ubZE>#-N_K=!GaAc%r*Qb@!iZ2b:86(K/<o"k]h5Yu)1?1&-BTHapN`Hs\nqI_u;2s9/IVo&?P.QltTbt+Q_.j+-\2t3g32q2_ %'8gR>]:7lV/?;"C]hV#eNSAo;'!e@jh";B=Z>V#B:fEQn($K)PW_LP+8u3@K,K=ZS*GRN0d1p.=aF#ggra_9"$J1GbC\%agfhuZ" %@n23^"r9G%^n5l^P4hSnF_X9*]n*Q,.I&C?`1I)LVTb4'eIM+I[]Ld"_c1%1/8.a$%c\MLBGr.'7NTQY(^)Q'_Mj.\TCE!#F6J6e %?8]IjbmC.F<i0t(ad/n?KEaVk&Dle2PNOksJf''QdcP8PNjUMJSMug,ZQ&8ob7=F+,1DVhZDu&YHPr`F(Sma#1!,QE)>m5e1Pn=( %cVs)mL8ju(/gS7:+4IJ4:D':*>b8"^BSg,P_/n]BL*E,helcm\$-.ndjk+IR5A"\+M1(A-79l_B9hkai>-T"tDT6EL$AB\2(U(eJ %<"0nlegaW?K/alM-/Sn_:+E10f=Gr@1tpaE76&$r[EXOMm%!o-Af_sJH,3#_^k4=noh%rWgC<Z7[N-/gpI]Luf[!Fe=WfQ%9nP"o %qek.7rnaN2Zp1ut:7c4T^hWUS4hRU!Pttpf8&Uoj&:7<Ml@bQ;P__1+#Qi%1)`DXf0Ib4.nRKc7<m?H#cT9N:*AF[aiG5D^5dDPp %k#T.2_YRHjO,e<;6<b2iE9V0]*Fsd&gYWgo,ilkq`q_B9+>(P+cL>RWg$WT1#527/492>mAR%5=<2QH$PpN^,GC^LW/LF>)`ps[p %98&kZ[4#Boe>DkAm>1D.>TSQh,?qhd7Xp#Tf-0p>bb-#m,(K"A3XpPW5pg)!R'4^Y\Z=OO1(,'(<f0g#V,Nln"3X4YIh_gD6Ddk+ %#JsCl-(2i">Q"qMi\d/5S-=T)+:5e9E^,G:n:t#aaY44TR)+3_lD,S*7VCcj\;iIb?p)1(CY/P!K4EOPR0D;r;?mRu<IkNlY_a4/ %B/^=7^`Yd<q!p<4"c/dobauN`q%i6?Si>cgCF.7Q-W0QeOKiQ-mZ3*]_JY_L7]?KO.iHO1'M5Z_YfC-e`!RomcJI&*+p&/A'r/el %_$9gcE]+)$:jE/f\(L.bUF85?E[P>W"!gc_'W^(0Y3\ir-nHB=8YJmk]68H#2'3CKi[9iV15SoNkP35\nLLn.?usHG6,o*MHkqNm %^-F+MT'/rf*4VA4V:bj^.?\V=)!P+DLFHIX-;\\/CO(4?E2o3Lq$[G)gDKs:R&mc"JJOGIIH%,@h&k,P/<(L;dnh<!=IXr;dFhE3 %G&FG_&.#j+)_a]rblm-pAU-t.^VLtfFY]O2Rf^@YJ<?.;AuT.]=uJ:FAMfala-M&lJ9@8WNuDQ.&DXAPX$qK\MRm7Jh03m$$,ibo %H0kh6J7:[j_@V3[@[N_u_lOOPJ75@oR#(O>Q&I>2^,U(K0)c1%YubFZ0."qcK=*P:/cN2h^]Ku0s)$[o`7U%`"og4VBJ4Y"c8EfT %7tdbD"@U,R<d*k(ZA@h0\--RH$\Oh`!BdD74#?'\56pc>p?/GV967Qg=Ht_`kRQcH`I;Q>.1WZ6P/hQg<9h)Q?p0OuiXe:F.F*q7 %P54m9;m]6_.*c=;![[5im7?T+>!Fo2fadQM9b,V<lcjU'#*aiH0q:P`UU2f3Z&TE*QCbf(@2(H%OpC<k"b;-5'`,[slPu_#04j$p %C5.V\hH!\pk[5dX'A6%]Zg&!1N4Om&8E7^(^d&@d3fjf_.1/Pkn6ep]i'D9L^u$.W403(Y)2CR(CgQC7R.EBL"`k,;ZpcfD23l[I %*/d"]m4Ha)dpM#U2IGT\WPWXW&S([c54!tH'TIs]%Q*`S1H;[MpeE7))681<J_$f8e/)(/j<Zu('Yfa)R#kdDiUNS-!PUha\W&Fs %=CN$Pj1mJ`,U-JO"KJ#i<2ag#-5,!6\pp4S\1dG-OWV8;OYCBpmBm$c^h/iLAoi#W5c`%l[9\!d?j5MeB'ee[$IsZ6]:[/63=VRk %+@D1UGoHhO":CUc#fZIJGlu>O_8YYt<HN:nP%>Sl5aiFjd^TjNKjQ+eA(._$.jP@\AU-TJ`kH@2LD>t`H7a2o)rePGA>W'*@l,#g %:?^I0:?iJmBe@&B9)c2PSs2FqE+kL$DYZ(B+uoe4(s[$0_SAcM@bOMa.c8.,^_5=2c9qD8-7[CR9Na*LXS[)n@$MediTP#c^htjN %^U(RXBq-rhG<A0.O3,AQC3&&VU1M+c\H7_n.,$`[NUo[X3GkH,U\$mb6+:L6igH(m`7Sf+r,.)f3Lrnh5WpJiWIj<Of[9kbe:E=/ %q@t]tX+LK*K?Z-o,@R![UeF>uBDCD5msu4f9Jo(%lrs2fg!Ui/@2jCmnAM[7oV?=[1Kdi.'6D;i9:9CBE/kKJBi`=]3hj:mW*QjU %K:_>]!dE+GK)C>hJsH\.itEM(pNC(^c<fd];/3`,G3sQP;i]5L\8S2>P*9U7FJG@"]g.6=Ps['M#9\O##A7#^;,/i9%N0]-ogk=( %&]FcFkk)kNb3H(6ia$@kY-n,>U)e4n<215^p`["DVlt1>$cu6)FA0:-$qs.alrCJfJK;'1?N&i68;rnH#7rlB2`DOoTj\$49G8<8 %r-e+2!N@oEWh^4mM<l8)6hA-m7OBqBn1kTuQYh&*F/*l[)RV5Z??d5^+%/_9A8ND]bN>4k=9/2E@q**S,9C<IY)7(TA2:iaB\P@; %+%rbANQ,-5=nh2Cf),m\Yk!lWS*a[J/[g]a`a5S?<3<AeU/J4-,V4.J9aVA>Dj3Aak;EH"JWfk]<33WKQ'HgK)#@&qRNcZe<''cX %Xs/\309i_J[V!7;%!Js?:lGCNm,O:Q%2#h&QYMroP4&(-$^Zt=oj_@a0$^Q\3OXE'gVmMhm@e1-7=sTDoY@cV^>31ZYqK]^nqjCT %3p2o4D4!A<D>2<[P=j&,A3Q\neU.i#`>Y_eg6F+u<lh4QOS:RffIh2s_X/+2).G/7djU3t"bHREJMBh]n]/FCPVk3(Dt"Z?c>4lt %$ECnsC7-d/G+@\/:ITGo@kY=rWsn36c[5o4mM$(2Rs*kKER5ZWLj6nKR$)$%FsX`JI7q;<C+l^36/78TZ6,.N1]A"*&b360+D\tT %p^pgeeO!rWETWm1Zu1aLl.iT-IoLKuT;,CE/EWJV$#\@)(1r5#FaHQ$=n]Y6"Lbmo0$>3LrB.$(N?]*b#mAkD,'aO4iAN<u"F+WN %,!f\e66ZDDU%K[&5oF'D]/"@LSk5#!GesI/*NS!lCk4FjS#Xa!]\@L)!c5Y^/Z@lJ*3\(`p'$fG(S#EtV_`9L_8+GbW`tFt`b8;Q %c7qRs!h8]k?E!'k@bX7[efs4,A`QC(]ehN`5oP*pO4"0W8'/!2be2\<BI2?!;NXWr.CpiZF`5hu`M`qcH`E:g;(R;:nZG;L\_#I# %X_b3+mfPe9'GEHk@Ks/>5]`eaVTEV@L_b7KiQAB:1iU0s@[iQokt:(FQ;1JlSFdkkQH$k8k*+&VPdF_=J(iIMOdLeTWkHo2+@CrY %K'p1'1'1W$Y`H@X`L%:9Q'Z9Nm^p!jm/`30A[DT!.YstMaI>JT7QSbU&tuh+fq0X?5;d<kHQeUu`obu*e$A]@[b,T<=;e&6h*?q= %85X<'*+lEQ2JpV;'jTfmOJlM]bSU3k,AqVe@PQ8hWj\uQkWVO8HB>eWYGe8("pfopPO&LH6K*`NRROWJc!h<5g0@2U'r,TaIj!8O %L:Wc,TOcJ!DT$fKgu?URlQMoF\HI4#.WkT^on,D?J%Vp%qrA!cmM&8@n]!r=7>MF=Bq"1I?$XF4]2+XK@$hh.SaBrBOlZ^GG**Q9 %XfD.##okHW%bkU/"uO_V,[dG+;tpP,Jl#=Z`+U_gFL%;bAoD6AAu69Plg_\kDsE^Ee"UY7!WsU[E44so<M-M5qNTVAME;?P9n=4] %`VMm!OjX91O"$rD+d`.Qp2[0.8%ha@a@%U'q5Mef!uD_0FYS/F+O']0);FSBF[uIh9V:jD[2UIYY'Z:%/gs.2?FHN@$B,bRMiDO9 %JaO'QZ\N0[L;T)HG^AJ^%iG1R>!-\!&F^28jG@!E`EG$se6hMmYf`_u_DeNegI)eH40$8[\&[GS("6mn9-#CfrG?,F8'Ok@PHmf$ %,7:uH>."@3naC8I*7P!T`(K+uH2*BX/'J1>OJ%06.HXbs<6_QZVi;hC\1%:[OFl+)jf0mkm*Hd`e<XkX++OokmI^j4Jb/hu9a7)' %PjHSR<UXH+C+g`C@(+@DEAH[KR4TL17c^!1@1DA02A'.KWHKV/5dD+>?^4/?BglK"8:f#gZ:0b,hsa:pIMeh`JU<rAJ&""g)_B*+ %B=sLY2Z*A)=@R/\?ml2sAPuCVH*KF%3aC5/pF[uMOg6n/"RFEe?M;mM+[;9ZS->gqG/hT9c`,P)^+A&=1"N-t9lHrd./*np6m?9e %7Z%dh3!$3$6r?f&$bV/WZCZ)@cr_gZm*uA]A\kMN`M<hm"kZfYic5=3;s6!$.,LV"T<%(P>eii8W9sD>+?.,ODD$m'X^EGr]dGMa %`=rOO!hc(l-B0D_8a`"g2HI*0l['n#FJo5[bWN*$p%uZZI9K\//0FOO):eg4F='4YJMocYBBn*iVhP=A8*Q-l!4<Sf=KAjn[5chL %mQqXN%-!D1["I:d\2>$,H&,9cR^`CGPQE]DGW8pWW]*cILlL@;N,,!bXItsfE(qUuBKkO=h[D/,LTi`T:f>54?'JEp$AuX$!/]sn %dSG%=mX%D]\>1!>8Up53,jj@]))W0("#kbS*?.rp%Vugh$r8&^;jsB'*5MS*XF0>agQItVXQ"RQ+IsgDMIFocXtMIKXFuK9V5GR\ %[1)u8/Z8EnD=J#J:ne71b337;.Y##fIM7A5.#b*gRH&AqKp<oG-C:r7c-<jN"tf[J,igd/\%Ig/Rq;1[<*c"fY5@:u[?.[-cm8Z9 %b!Y_I:o4mq\jJ_af3'>2Bk>.a=_,TSRa`:`_lteCOu*u(l%M]M"jUSniqTl"/B\$^Grn6ZH3/d5JVnP=[\-_8`bs-0p6)=JeH!/) %F=?OZQD%72phWbed'T:uTNPaQbiUl7&I"8n`Y+YJ]oc#(.MNtt]'IdL_,p1mL,K\i(6R+P+_T0On(&p9f$#_tMIg6!D-^s;8d3h< %WZ+#i0L$C\epL_^MH@2QK/i$fkXM`dh-<Z,24>[=gg&H)N"9/X2Q-DuH&u?Pi&F`']p5+O_&;<]Y^2oYeM/bQ<.o?!WjKP'qB4cn %1.b5<e(=Q.1BKr;@)t,4LbIXG(]PZg%S;PQ7#VTI'5#)k&OKo_)N%21eQ14gg4Gl,noN$2gL<uE/T!.W#7uZQRi3l]:BtH=<4dbW %29.`feGDcI$j(jqaF_ts3f!\+121YWnltZl2Q^D@""B^PJ<,m-^UhsUD22)dV41E$[B*\WJO7b?RY2UDW(JYcP_9:OINJpIL4kd> %24,Ms5dbBuGUtM`M"s/M+k!n]XGE[hd2Z+B/5OSD*Zh.?QIYBAfWERFkRS?u'-fVVrL6Q\H)FWLZ3Y8U$AtR>6NDqXe?<'V-TJA_ %*)N&jOq,3VPl$"d32.#fR0Ng8jDhup#aVkhB6.o0]oPXqTU_IlHc^h/Cn[48TbBC[6o`Q!guH>6@hBS-Kh!LJ$B?>EOFb1a@$9c' %j+'7MJM'W6*.J@aTu/5<GMlrPM/I96_/bo!-VojEW5"a5(r1Qga0:(kfn9Y\T\[a\3oE-WAp#fJV#H^*+ptn:,O!0G_;6-N<&jni %B.e4L>"4Ghp"A)'rDnnCln1q.faSi5UgkDe:QFfD1l+5MQ)SihV+;1?q0NPE[Y\D,`P$$@6!u;d@IF#'I4#u>W&`>CRXP?i7hc3^ %"#_@8FSEO?el%S[<\0aSp^%mj$Dd]2Y$jGu<U/[X?J>hH"EZV",>\O&B+mkA$kD3h>3EuP"]%?%6WRQp,b()4PCXRVND7\p!@Q9> %i8bF#Fh?P);Nr,QFhB!9e@1;_5b10D"_&0=j9)(kTiM]"IcJg/M[7PbKag>-'na"7o>04Rm0:JVDfu3miq1hCQ94ri+FI@E<6bQC %h^t,W_\ZAuhM7pT/3&tD!"h[5+dRMAM0s:1Q2*^#>C*)*7EL7j-"-pV;jg(u3D.;J_WdKRO4k/][]q:LBnd)_BKkHFq5nL3Zc0>N %Unn0Hpp.MgK"^'+H$)B5VT5d&0-Q)k3mr!m=]_*QVb//:S*Y9C`1,1\U[nLEGhg^\aq?G83&t3S7mUXefP16gZ\DLF:pY^];IW?i %N!AI-XCF,-AS;QUehUCo`0\"UP^V[6P4"ij6:_n;P67<)^l*[bCJ'$<9)bS&!=+a(&`nZ+AZ^gWdEL?sn07T1*_;aAg\7:Uj/C)X %Ch8_85LFAq%<HD_!;1Et`,=Y'=flFI.;G(J<S'1%bVdI01S;U(B0Q8OMgB690>&J3>ku`%FQe>s*iZI`'V_pZd.brs"cXnX,B]Q: %?=4]oLS1n]3)3D&_k.d%E&`SW*mN(Sg+@!S8amc[R869:(8h2uOGZ5VEarR9Ai'U*g?^0]V4K%Go7YI,".Qtp"s6?^6]@QE/M5KK %#TWb=hb=#jld*#EgP=lmALk"^,aaG73\+2raVe"C0BN6@>0XPu?G/%0<uERIO$jZrLM,XuVL"R"+?Wqq</T(Wr[4U+R_n=P@WbHm %3@DQ"38N[YcRCeT']88@^:*/@bd\>"dcKsjOc6]JJ2i-Mf2T^l!2V&g6rIeE.-uip^U$bV-G`8HCRM=tVoWj&&UC+YXVJZ%P>!c: %,2[8<"V+[*,?ZHn%\<m",Gg+^!Slo4iKgJi<4`flA^r2`9IID!gC9J;>6ui>WK/7',3mI4W.<+YbokD;^n*F\3YZ1^_+/$k"E%5n %+;eHqf#,2MNX(mMI;GEOoe`%k@!gQ4@kgb-^=ZmT5=<QK'\1[[j[[q,i?HCl$bfKQ?K7#0:esQsCSK%3HM"#;^/BiiTRDL5[qhfI %Q)#/'CBCY.e.nI^iS'PZ%/ni<8[/n41YJA#i9XIuDQqCHHk#GgWud<ic,4(pX-_R/!sZ?]e^1g<7)5b@F9isZnuW#gY:>\;@jB9o %nhaLqSZ#TT]OO"UTWO(MKOpPsnXKq0*@?<nCrgbsCLb=_M?sjQ'bqX>:8iVe,)HE\g,a0eA;"$n_QOgX7M$g?'8("J0fl7*A0?k" %/STU^E3!d6MK9,HYR#ARa^%AHXFk.7f"XJha)(td"f8j'4:i8h9U)iS'T4[]M[=uJ#=BRGc#Nt*0nP'0)/i.6$X]f1)4B,ROlTWW %P^@IGUiq[oY7'-O9mZVW\K*C+"?4qrZ?3Z-9]&3p=&Ge?!Mk1fG!C'CnK^FC##h/"EBP^?5ibJ6"B30:oM4dUmVJ:mS'17295nkh %Ya8s7/1dE:>M;QPl]<g'!%?MIia`4DCDk9"4=Un3,fsYP@"CqVs+6>`(](K[mUo2L.2<-R%gAgRdlLd+Eja%PlU2Xj5GMW[d(cZF %pEh*`(,*pkVTR&lTji,PbdorfZ>/=JC-CiL0o%0p8>cX.h5'2'q5BJtM;%SK'\+[J*t!>4q(`?$HO>(Ppi/24)r?*`Rglf>5DE_( %b`5S>RYjIG;447Wi$95Y-/V5b#1cbq`F$To/WA/'V;Wr57A?dDAIN*"GYm0Q'<]h\(QL$P#,6c,OdkoGOG/ue!R@E-7].M0d:">h %k@/pj%LkElou_1.E:#2n`!m7(cF+bnp=Fq;/+QTR2MqpH]>P_oho3SLl6[/ghp;+cS_k]C(Y_Jkr,!>;KaC\S-3orOG>Y/QUJ4#h %[hr3LA?.++BjjOBo2Dth)nlI?*HLNq("8%J2p4N2L/SA_Y(<kBkmFfuhQ&V@L+/8g".Dt=^p#KZX=H"E6rldsGk>`=!--^%LiEqV %X`A<@8V>DFZm@BCJapmCZ(6Tu3Vh7_'Pl:_ci?6TnZQs,1h&:#E=*,W@;S%X9/[,=crBK8CmE#iO$mt!I[<AD4>/.m'3Z`qP!/>> %oUht0bk-])n2bCd],>TL`-*UKP`[LL6ns"Z:)qt.Kb:cq2Ybn>,ASV;cTd84Q/spV"=BPk+sZJCJ[n<Oek].6R7bO\8;5]dYm!i( %>HEOLfqe$D;Sfef^DSCi@uqs=g5dF$nT@7rjUA:c-FJ]fcW"j*e(`eo;jiT3ip7iJ)1`ST$K6Vr.>fU!a*oOKapDtb!Q@"(<ZY]S %h+.nDPPP(_A=h<GOYuEb`bo7WX:#R`XN#k(d`Ge/?YKS5gR+@fZS`YH)<qJRfSW8[ku0kLaE,>sr2"rX$;F$+j"nsbE.ltQ@A\8n %J)F,EBpYu!P>;\/:$F"e8D`TGjMkc<Z*t6t`-q.c+9FU.lEED4q0L^s^=B2H@Kbr"3d'H-\-pr7&WQ8%p^>c++ce>:*/=C0R)sS] %4baBeO@slX?%s?DONi&ZIKh(FOA1%2Sq\fHOO&77^'6^QOAU@9hhFh\JCAl(s+X5+J5L]&+,<POOOJU95=\uCOB$^=@#&RcOOkLo %^dGh\bUefHkTO=3_JG9(n0).&@b/RFr0X[;@J5I+!23jeTIb'4+:.WI6=kdG"X-i=#dkDM3Xi9*6_s,].RA`f&[Au:/4:(b<Wq\' %(F>#:2'^W&\8$#ra``@6*]G[4:cII00QL#8$'\(LNK[HS,udVG'NQhi/>6rS,k,j%JpCFW$.WU)8i35V9rMuOdD?34F$bSOM]0o1 %\L5o%$2&fml(CRVkc.)d-l7RU7oqjL83/3H=M!]NL"]8i)G_/,W)u&0e<mi2;2*_(TutnS&M$i,$?`d0RTtu&=/b_5d0'jM_ZH[> %M^mCK_(=(s]BGuC)JYu"g-qD]<,i<=hQGROJW=!23#@M%`B&19in[TT03$@-2"rX!Hl"BL5kXT?&/_DRL:W!RNP\630[r7uBI&=Y %MNRJh7A]OOkSS&!L,tG5:!$4[1/t7^<@pT:bDTD5W2gdcE*h$T0?Tl;#&((S)JY2M.\mm"dYk\NW.Q![VM=B9Takihfc$m&L,uOT %c.Gj"2A2aD2/>R-gK4dVU7*#Nm"S]V(Z!q?"H>h@=GkfqK(2`%2gFu8@\S)s4F+cUc%V9-5h\s78P1)>@;4Ub\lJYHfrL!$U;*ST %ra!ui^WZVf^\ju1FPh?dT.l%jOcWjh@A:D5<WZmVK`uO+bf&;*LkQN5F[B\9a8u\d6Qrr&_F'209*)Nd_Li1U;^&d<_Scda>9UcI %_?Gj2@j/VR_F9ArCE^I[_M,Vkk!Ff.`5W1QHSNS0_?Z$uK-A;)b!ulMM`6r3`/'AoP9J+)A7U#W<nWtX03-K-\#7*]\8b,.ronWi %l@mD"nm4\<m$19a12d8TmY/t+;1Crnn:aYci?#b=PV8!X$i;rY8V_]YOEhjeZnHgp$hl_nM+<6iOF&%2e1Z4COS^*)j=cJgOF85" %oHQj*NVssa"@S[[Z2R"e<,b\l\0rI&=pZ!NKi!CF<,8ul4+o'pTjGZ+>N2AE&L^[be1GQ1(nkP2XKN4NEJ1>4Tu'<u"qp0T>VnoZ %4d&XPjJ$Z-$)3*q.2S87:m!&eDRl^Y"F;bqDTkOZ-ISXqQ"t7U2h;lBW1.kYfEq4q!p-#cb"j,c'IX2l<JCQDU/8JcU2q#`,),;R %(SrFWMstSO.M\_V;HV'W]Gi??:H48s&AV1+^p&]^7lCS%G*8l$0"e8dm<Je[/k6gRJ9Yd:f0T;,X4l&lR4?^j$MCP'AZUfA<iEHL %;<A3C]L'<8M`+\9,5//u(+PNe)J680fgQc1e5-PGeo'2XTo*'Mp_KmIKfX5jc+/`r?)V:X;8!>Pnj4qAMsaoEd2/hY?'P@5Ohadf %n=i$i;(2qH$mY/W:a[tu</ed4M`^Ti9eMc1q"Y+7Q>^f*p=GRhdcCi`MH$J+$U;)q=a/uM;!%7R%eHEbGuNCTof*'@c;<[[<!9n5 %LPAErOX00k^%>Uo1fQlVWi&<QX7(qITlt4Qnp8]9%CK\5S_8oFm7k:f?0O8s`4bBt?F4kX<SiXcmmZV&e-5h(*uq9hLO-nDG&aI% %*"!ls[?EtGj\V!udV]P;SjPs1X*XE]_r3&'mjBQ)`/<#f:ndmuL*WUXW[%jA5;3(OFBVd:MTK2_'qf#?8OUWqa1Z6m?ot#pYsIWi %qAG3)=,Hr5B?tT1oO5!cNQ`na&D4o\):a(S;9U=@X[$k#38,@)TJ2d2<a4.XWCMH,6f$Gj<G,iSa%)pO`(2&@G3IgEe"Q`pS4t,! %,r:>G$M=q$BYgW5eldM@Gmu%=Q88+lP*8$f)B[BKM=Hhc^kCo/P?PL#0O)o&J07=S7]]<>@%FSZi*^;K"ptY!k^YL?_Q'60c%%J& %KM]rjd1YBPOHj+4NiZtH'@/^O?iC0j7(X35?pnVMFUcj1OR>0_WMM#bNbMJ!DhHP;)&1l1dE7uKM*[8_f:Xe9,=dh\&<</k+)SrX %Wj&d)A;O[-\meR397F<PD0@Wp>*^pa2din0Tq.m.ko'c.0[JRn6'c[@old,@m*fe.AqCi(K4\LMVB!F3r@EV>eOCUU$0b11dd(0D %j[nrIA=a`c6mYJGi86\_jMa<n(>rF47)DO\P\MX;%*."%p[ANj/?5G(>Z<aFg/:K]Pf;o5>A8j`gImaJPIi&=],-(LBFP$]X7M.A %lP["P9L=G(,['Y)HpuKh;.%UDc%b_IcJYoL]PT03_Soc/""Q$_O,=5o5K-g7\?fAd<&88plM;F_;iKX`3!6k]#N_u]aY0bZ$,Sc> %-<\R`@2M,E]h/g]rda.)Z6s,f!(b;ibodm$fo4&oduU/)mQV8J1&G9>#]@b3:;$Z?de.!BdO@('[0R@@EWAV#mSYB-q7M;ZVZ--H %OT\mDLuA%\[2Mh5NR!jm04)<Y[LY'pf7DO_80]"5deH`8XtM#m(NSX*9F`)6TZlPt$7sB5.hnd)N<G(Qm>X_G;/$QK0W5h%b/u$B %1p?YI3Nq%:iaY!E6d3!T,X7Dan`4UL1bu3'@;.,tT7>/!+31BlO(XKB>$RUb.u6SrQh2(dAYC6@=>PI($(AuZ=PAEb?$##2A-XJ> %]Q@>*(bVmgfo:%sT@bm!`es_CA"-YIqNQ9iCFrtfG-aR4A^#L29HLk,9'15>&>W^IOM])9kk&;?j%4+$;e?RHQsi+qN0?Xhc8]r% %0e-Z!BN+KKm*ddM>b]0urj&*`LW7c241>>Z6hZaiqVF9XD)+nj#<oT)bsm>Y]<t-6AMK7/Y_aKK&aD=KCgcJN#TR_P-Q,r'!5WF) %dB0DF8WqoWP*uZjCH;od`CuiPln%U)LbJ1a&/>p6W.j@$7Z=cTE$eAJMUPO8,\Fm:+E]bWYOuJU$fVW2``:,?(G"G>;ESHTSEnUS %)I]mB!N^H868;1a>Kc?mfd-nr>40pPij,El\:i=m/XaNfaUNF&EoZXUFu@p/=8\.^W2I)X%?@9g!9U6&NqdVJR2Z\n6h:E>g<q@; %o3h(mh3`pT3S$=c8hIC&o\';^8L7UhQcr2)ZaQLsm/^'`]j",db9>K:2G9qtO[-+HfuBpfFoX&$O<B_@DWnoIB$]QumYSN^^l>cm %MG_UE/sL.FVip842[=[9?>a_)m62q3ZO)e[9<$FO=D/6fThHrWK'BAhr->=A#l<Wd3n-*DK/=54ScTiJ[_?l;-R<Cd<BrLL:&,ep %\9'Z7P_FNa+T2d_8RmRh>`s4V6#<a>Vr&e1]%a]D%*bN#F@,P@0E2.h5`8U1#MAs)fSRP[?BrM6giP\!/?QGbGZ,TmZ9;]pd-44L %^pi3NJ#B#SS0D[o,dY/JRr*`D$jl:8raYCCV&k.1L5iCN=#k]0jLZ:UWCR&q&buIPAn?+3h3aRQ0rNmdg(US82`Pa^L]WhTi3nE^ %@6(1YApOmZ[",cFE>['!S8b/B+g*T5?Ig-r;`^Dl9>Fu/@PJLCKL`EhFN;<.!7:D:7ORiD2SJhsr;L7k+D"]l_GWAH-d5Q/lJ.+o %9XBqLUaM]N2eWuE6I7sh#'(CmP(fQ"g-G9c37iZtAZ*hQC9UTR9N^/(bTK/J,\^OTDR:HI@Y8?jA?K0UY>%eG*[ltnrfg&Db#jTn %/uT7cipSP(5"u9A#b??>"OGUT4V]T25sd<emjm'h5$4#s9p3r':_TC[FR5kraZ&FC;Mq"i0Nf`bcNQ.^0]+7_G?t="d5pL'@>^1> %Zes:+1VZ57g"BQ.*BdBOPa&Rg40tle>01#7KpKoG.nL8R`m!EOOCB9j=kaXhL01p5WF01lAn(kF9%eJS0F<k9<`J,?[H%QN\;nBN %ro8F(X"\Mt4^Fud-HfPJ!uGXN;)ST$#Ua/7;/\qB-_fY^TJ90R'_$7UT84(-eSR;O1GZGOND./-&?kFH.Y1,KK4,#q2F6$FlW011 %bJ62q\Jkf?pkjN7`j]<>-CWb+q?($qIUHR)rE.;3:Mk;Ugped=gg#T]PKTs>Ck<(Y'j__EM/2mjZal__2?hSBq"Ltg`6g>dZp%K` %Q2sk[Dr38$d0(!`/[oINgckA+YiDhJS'Hf)=W38DW72"b&M(-ejB?6@'fHFuZ.2Q'$R44<Oet4Ql:X,'FgsJ_'HcZnLQP0E,0psK %5#OgUcCS4ZiO-qg)cI>K'iUA&[H'MG<Dagf<AZS\](!-2nb8fV=/f=6N+"QiP="%,?mZ@?WB=L.(4\.O0ac)FY\EHBo@AJsh(-ks %iOLX`[]::;ocRt_6Es<L=S1g>P[Nf2cYPPeb"]m:BkIB4Z.O=T9QER&fF<^,'6Yr[Xjk/u)orYtXX-RW:4hQG]/%I*4r/fG)hEu( %.`95;!K3+<OX4DMIu6MWB[usT)XHUD^WE>+%Gk)b,O*`\VDXNY%A[>a,-di7Cb._rOf?#bg4nUrThoVTWZ0+L?DMm#ZG*"4n3no' %9ia6<+218\LU+pn!:iQ0q')m[8h`bUc(VLc/-:53N4t*@LGI@LXdXa/I0TS*/Gh!KDq2*#2kXQF)BSR-["6HM:RZ.o8Q,hoa+t=T %<REoRO/*Vs777^b"iY/(R)jN&]Hr%;"X4)G]Ve?gXHN\6O5)(XfG#?WrQ*.=U+Tmn8G_E]NOjVo%C0b_DG(e5&K[8MP>YTZaP2lc %,.UMf3,=N/eC9Wlks4hD*<AKohhNm&kI%j<>;neKj%u\?[r)8=An5BM2=6jq%)A-mLk%=&0dH;<\oYNmUo]Fm'630'Z8/1J2lkV( %"5QonBhU4TGcO;TKGnrpGm!7R8l.nG?T#.NbK!ncm\WH`YUF$p;Q_mHk02"R=f,78>sfWi&c7.-r%+iBg4DH#TmUVP,tLG)Z/Ok; %JpRFs_,o?]bH1l'nB!dn2Fnb?@)LVQC/CJSZ/J898=A-J%5_O2";m']<(E'F^ZNq\S6MAO]4CJaXC%>:]]KjE]]1;*).k[g3U`7[ %V'[jhd"gqX'(MQVcXi;X"kbOUS,b!:3'Nd$,RB7jS!n@ks$AGG%X`;f1,6(hQRL@a_eKLmSrOAZITWg*ZGC5E\PV$SI[9D1X]-hb %ff@:f?8l"]fo4#*M31u^QV;"YoaLGef3BeFQ'mnJV/FMoA1[9_n#PApWE>!"@l5aQj:gZen4uojUV(@4SYNbQM:<1iRGOUp_9rAY %NoK7oJb,?Y.5ud?X/N`B5(PXRO__cU'JoLe3K[:kg<iTBH\LZHVuLkJ(%mD%&Q>XaMUijrU>!?JH7!=0YnuYeWWfitI\<,QTt7r2 %gR*@"j#1YW)I5?hX12aEn%H6rSU`1elRu*)2P[<F$7['!AOm/t&L)uc83fmA.1dk+HYDpU/DZgU6$jLb7Z>-!l*XPU07uB%q0"A! %>8f4!Xk9tQRV5Zrf<qG3lFLFpdE8[<i0,6f`DtM^@KBiA,C"pTRB>#m1T;J$$*@kj\Ga$f<a^.5!MCGUh\oG!)U7g`bRB:T8g1fY %1)9l+Dl!3nKghPB4es,U#[h<<R.A"pE!I"tD;T!aHO>%Se==$%[5t.*=H5Me$\/+F;og:'X;aJFW]/(WNC%u5R\1.UOU/nX-mLj6 %Rb]"kAGH9Th6t-b9FIsLjsKmp4-?orMj%L1<@TJ_9K&;Lkfu"Siu0XIgq`aQD-6+o+.V)Tf7Lgh7\CCdBapi7._qM1OLkj9afF;7 %$cjjJdP//hB/ZQDD/KHtdiSM%PhP*Rb7d,VUF^G-g2Q"00j5JdmV5sfR/upo1MX%';lNZR5WO]3X%<UVW(mp*J5fL;p5U5l)Jc`Y %dIJ8F&>[fqTs$$k9pj(rWdZ;H!A^=O)CH8(9:>V2dfC",P9<o+'+#c&-G^rd>fdGsB)K#$_eu-r^X*C$5c8Rg(f)5gJ1B)oW!TTt %F&V=/BFI?qD$VQ7L]i.l%o@HjbSmLQC*`ucM'I#6;8X3S8ECY$0#(^/41;-!*%e*_,B\L&1#-.V'PL[/96:e4A9^=FTilhHB`rm] %,0UM;PF-%sZahVr4KB58Ehsa`%#,d<G(WKA*uT]*bRV^OWq'?8(]Z6i'PU\W'$sFW)]RDQM+AbboH`EVMue`>WH7JuTPD>dG'I.( %BK*.\W3I297cQ!WoL\h/2h3^9JBkJUj=s`,EZh!t<5P#S[uW52!GL"\XF^R1ikPIp+VG&eQi<5uI(W+,?L-n.Lp"]fQ)`")V$99C %%3:u%<h7`@[;M!\7O^I.OO*A3*s'cqg4%*DPuoqQ\?-hBk!dFs(cU9MiWAQ8aMo!^fP+YB]cQg>;\6MN(KVi'90rmGip;>Y;<1&t %cIU5l$QZa8ZhNStL@/Pjd!n<5Ik_t*J`[R,;oOnodu@^1oKT2'*)*K\hlbE^S?UnJp('jaAX[6%k7l*,_\7+!!5qrAq218!1W$d* %!-t[bKn0cR=fg8UbM%2^o\UJSkAStk*c;@(>K@=m+ZRW%6QbV>#Y(.,eGmJG9";\\fVl?u-hW\A.Iui6(qr?+SfN5_bX7Z"q%I?s %5A1:QD(RC!\JFO<MCGT[l]F#c?C5VH?B.u2mEQHgALdK__`'K-iSs;Hl"lTeKhH\pTSJXIkr:SBp$;nUiK%2+<?;LI)^<iCU8a*% %Z1_@HHmhE@(/CFWrS#D=QJ0:G6hi#d7he8'8Krh>BaiNHkkHQsC(n?ISF,tBh@Z^Fj+;c:E"Z5C"f^&.'5GKj[Riapq'T`(:J)>2 %[Sq16F@!PAn0BXpPj7nd_XA]\TebIY&VeHtkq<bd9/@uD@'J/(@1o5"@:`&0_@B3%"CNp%WL[*@IV^,AIR?P/&/5/rie#@0+WTrI %NrTpccd(oZFoi5S)OAMaF(sA-U9Q0QL!D!kq/Slp+D.S.iCo%r5S-u1PoiA%X-6I*Enk/q$6Y.).PPK1:uu$uUu@RXp5@os=G@(h %(4S+rs)pAMrc[t]6=2@tF+:S^LHG=`?2kGjJB5]We4Da.W8`TYFS_[JE%kL#S0*-4Wi3+eM7aBE1_,c3qmXl&n19SqmB>^MgF0g` %pn'6Y_`"mi$D`iE1I[FLpe49ok4s*e5c*TCeDg#c%Z3c:&qj#c4!69*XQX+P(rR##_T(gMh)$hI\NAFJ;V0[k+P5ciUe^*ii9&b] %_lc./o.<MD">jQNo+i[dO0m7t3-q#o\+;aG*+ikYM6Z)_CG*+:SSl2'$,\PT3aY\ZTb,c2]OQoqE9J[BTN'cI&_fPF@[/YM:oe>! %`iM4uqgAbL"C8D/U[@Z^?Q=^WJU,-`^1/*L']]]W8N_.mo(N^<BeD_"7LQedHZoto:$,\uVQO!h1E@E+4CTS<!.>+>#)<38l/Tmn %'K#qskMdMp+7='lZThk.)f5g3\M*?^0<Ms@VVmdFig49;;-3=uIsKE+4D]n(l^o6*=q@+.?Q6K[c/-@Hn<Xp]@Cu?>1&[r*IG"%< %Zd>jT6mE"[M,['_3=TGob\"!0Pf7.i>P==S)*nVal-<=+"KUqr2lHs7f-[l&7=[$WOQdkNH^0RWjRt@!R'#'oFHOGT:PmSm$<aUq %9!O8oVZpFJJ9K[H=J)#nY,'i=`ijOB0#=7?<s4CIpJXcGk'K@fC5^@hCb3]4Un!4U:5ZT'acQA`;WtEr:2r![b$=sQPY;L7V'2Tc %G>ZZ+f0X,CTSNIVr:t]Sqq%H-`)mnERu@0u7M+r&Dk?kSb\2=#B(tA+Wf%JF458ce;g@NuGs^0_B##\P%A/+f^Z"3SR*?3!)<!hJ %bc#n-2KOTuJiu@dF9-q>H.$P#)3#-I:f'(#,fFBn[;[u,WO=AeP?.qK)=<Q3K3&IWF2Q;1*;;XabI@Ye6S*J4)S[K?K=L4[TtNm9 %+hi6+%u"o>"?;#C/iZ#XHA[*,iFduDqY6=ZCT-S<C;>RMZ,Q9hL8TYPUukB0E8YD*+]h]8>!F"5WLRJ,kWj,m?Pf.Tm@_S,2j3U, %&?8jl9f<)8^%^jp,2JB=mt2I:FSA?.e[J>A($]BrDI?_)GAUL<M_mdeE4DXTlli3c6ej5=>U^5.&DOlFEHH-'[uWU=/dBdQ_qY^% %mij7E:BS/(5YG>?h,U$/@8j2ZG%Yu\J^M<A%7Il'To6d6,Rc5B,!NJiooi7:TS^K437?(M!=VH`.lD)>D/ls_I]8h@T)7$.OpNEI %kS,^Dd7tE=r.-44Q5>YD;[0JSET-JnYj9!;6M-l(FU#H4M*>@FHe06]V90blTKl!gL%(s6kGY9EO,5-sWXQD/2PN0N\</ik^>$`\ %/q/HGE9'SsdjM)5j1/[7^I%F];fP:rMD\-&#rAk4*S$GdeIAE`[&g7]LFS6]"*Yedr992#"BgTgp-i[!/7L?^?\PMWh*;#kWhhCF %,Y]jrD&00s2P1K.E8pTcbr%Vm8VVY\oX_HL;nXj=<ht9o>RC`mWi%Sl?`;YTR1(klrCs!iV(#]F0U5:hM4*pVO.R%Nq2Dl!+F#FS %;_+#f<YN*<M]&p#_;\r<T#Y!(%`"Z<0_VW/-N82GGl$)9bunoBb>&4*?4a@Gr`'D+_St\]IeU4*lU+\JdH=Ul(GKHjTOr:)?l^T( %CWkq&5qmGcD2d88hVP#'PF*fpN::(Zef9E^*<c$u-_o4XrTP=r,I8J,p2dK\U>-1$^uZRmqIr5J?P(K!KsCa<pusBrHh.nT)U$!% %DoU*&JJn*9KKr.Tbr4r0Va_XE,5pua-Q9sF$<-t9pe$m,AS#^:`sNW&[*lFE>W1rp-c['a0)DF8.l/k(_+25FPuH`hDQ^(3IHs*\ %5bs$<-fU<BE9fduj#Ng!]+F8'(@$_9fQoOR&P!Yh%LS0%UJ?h`Th6NUk"bnMdqNkTk!R$Vi`d&3`r&ciKIqJFP1c0t7[C95:"\E8 %^LKZ.SLZ9pB2ET1M0Q9s]kHQJZ5d95m:CA@Rq)@q/?kuc%:L!E><5gn[87^l8=tc5fVs%di*<+sUPk/b(.c]0!kiHAeI8q"e$Ru` %)L]^Y5_<Dc<EsJ!D65]/,]PZ<q#dfcPt]$o%,[JG3H_o/]MISo9`5t;q[%'4WO=<6bQf*@.<QWog,C:[5%T],%Iq,5/F^%CV$\T= %8$\KU:N>>m78m9f>NeQPj#fW$q6\p3JP>1tB7bsH[+J0qr3X,$RId/W!l@=LIs(n1ESegK@VT4Rq3Vf)bj;^8KML(pjPfL\7u/q? %Djg,kR#r>O/G_VLIWDWT6j.$PKXYaQjBH7=M@UF=b.sTjQRn7Agp1U&KXcnM@.Ic9H^'`a`O7%:$D9+"??IZ7*L"LPN:3sU_dOTH %auM-(QaWDKA<tt\KVIt(b-p&5Fl6:l#\sq-lP&0>eu^Ss:ff.s=7Q<T5U(`<f(57.2!i5obg\#bTd3Vd?53cPKq_\CI+C`$/!T/, %#^D&4?]ctn76iC<)nQB>"VPEk\[-KoZq*UP,.JDHZNVOj(V.#51gDFQG7g>Q`9BT+];t!u/<:SSl!6^O6@ljIatK(Z$RGiV0u8e; %i'jFqPV]sC+,2P-TqGjC^).27L6@Q5q8\CmA1/oFktac@Q(b#8<W4b>ap^]r"9$J8W\Y@^]]aj";PBe[kXBkU'IjP;9eZ(8eYVN] %l+Ys.T3,FPT(7:HdNAEqC%Ye.>E$]'mi!5":12:21![d0gB1Gm$=>36mS0C1VuN+LdVAMhC6M^2@C$mmfpJ*D]o/_h]6B\g?sVc) %f/bPFB8N%&c'qS$p8ZF)o)LKQC\CM;mZORE[ZV#TDsOlL`b>j)(!JSKKL?Ph?t;FQe0`u-6\>fTj\/;BjQni9SM/a,rB+2D<O5DG %R690N-E`lD``X$$pu5aVjg9bT)/-Ol,K@-r7C'O_TP:'`":]h:J7<o^>B;H^g2t_0h,i=*%n=1"=5_slJQJi)-4'[^gXWt`l(`-$ %AI/_7j6nEmSW+D>)aI1`UZITiFIekufgrd&G#jQ0#e#q@SK>_/jTF]ZOa`h%9R)3b'UZ._-=Ts'I0(r8$l:u\88O7/'\[;iOX`jk %fNG_rM%rO?+F!u8+fb!@o(-f`f]?N^/gPK/S:GFi;+\XVftOD8VMR+1Mb,rWERrV7WEM-e@pl#qMAjlI9%VeZJYDKAQf':)_8J($ %M%s*%!pW/*e!o7qeUug-!&fe'RfP@C9+-Of.&)"P_sP!m%/+D$q.Fs]h/Vr`m*VjqdtX@U@?m4ZqcQI:(1W)2HZ:$jm!"G:gu1H] %*3R4]$jm>OAf:e]DbCb(<!#/iE-C^8P1e/UN8Q:g)Q+VFZ[3QL>7Y&P61^=TEErEXmaPk;D(fWJe\sAY1&NT(cmdbi5W1F)+X!I= %AgF0.CYL-s$^4/f/1Y;l,Y/%_M:%X^E!h+FI'Od[fY0-eb$0\lcr@"..RFu3L$VCe`Snd(m:t#DpW0m;PQbU%V"&<4C;sr!0*0`p %$1k+l^=YnG!!E9mNVWAJdu`QK6O%-@/kX`]"0oe01YL94,VZpZ3LE3,eg>F:^`.oS^gi\==(bX<!JB2NgEO&'V\K&;R<gC>28&O9 %7]u&F"R)>Ob(P$<j;ZiNY#PZ"KRAJTf<msGd_I7HS$Bas--O"DEk8DiTk7Pd1;9-S`0oF=cit':PSa(4qBWKtq"KsRKUAZL"-cK. %h0U<G!X?%>#=r2?APk^TXd[afh"ZE"]u>d9_2kB5VD0sXeK$>!i?4`W-C&D>OA=<\'!K8NGAi<_5F*.b,'4HeGPBOV[pukOpNh$D %=IFd)kUphL8T]a1K/0MTVa=8t)%ehg?^mL5TmZLi$ZQPZX&#*eamS(&Sq8c')9P^O8\L"&bdRaNFu35Q@k;9QX\(G]SN$$RWp9]3 %e)s2?aof?ue6jBD`h6_ieMFg^EIklKnI7.#ADhG3hWae'dS6Q9rjTW@:;4tXqL>nX^AVQo_fq2tQ..$D8.6NL8s=raAte/973$/* %2OtR$fb<WT+@MK85%<`k`uSb'!YR-D"f-]KnrJS\1a!G+7<S52Ud>2s_7[Mm+b(uHYARf(=H'0iCUq=99D?oaE2jt*_/7jS?2(O] %CT4Ud#MOj(S.NF+#5.f(1P>eUN<h#:\a3>9o;k(siP'dfXIbpu7R@k,"aJ4^]bT3dWen?#4e#FlUf#M+F@OLhP#pn`?,!mk-8J\; %FPR[+?2E4ZZr''Q(tl<sZl:J`TTArQ#(erb]c6Y6e3p`eU)BkE;_,tNW0QGLjm^A$iSqQrO</_n1<qoi_,Z&DALZ\^7B>]uGls%e %[<CtQr!bakeXQ.u07+]5mGWLL24(::\LOJ=Zh^MF1b1f9.5SR30GJ!8ag"^.A%kf7<rA@Xmu*W3EjdMk2$<KW,cf#W:"^LMn)YmQ %r+T`]mZUbc5@a9Mmp#T_-@R,L9?`eFL!sKD$Z5;CLlF7-jc>F\AM[9iT#VIGmE!UVgJm\-]lp(ke,Ue8/ZP`&cF)\9E'\V5FW+OR %5d_,"k?qe#RF.7'LYlQ6Joli\Kc\NgC/Z^Zhj>!*nFAjl7_`r:&_+rB*2I9Ql`2+8\Em"T:U"-HVhr/t2ipuoAa$PgCoa#M6o+&B %)36b*.R`S0@W$IL$P[Pk[t#=7FocW?f1aXfI")sW3JUAa0!HS$/lNG=2'EY17-Zt.M73)@5UJR)TQ]2]&i/OUDLg[W>^Sg\Ig7P) %rLV(,^_/OCI"_!1>s<*b%5&=V2S#Q=(eiW+oWGna/bVS00W&]hm/RJH;r]Wm_?orp3T!\tD`cV7DjS-ig(Q.:B=u]J4*%iXkJo[e %"\c<j=9"H2;e`tk^Xi_<fme)DHZBCKe82_2WU3>V0WE8%C<&jArC4$$X<T]V#-#Rp+N[M$`C9ib7YLI8K=O#PZV9Uh,qt2KTR+;m %H#=+bB(bKpMi:F(I>hPg'4H:r!!%\N4FngFf;rYZmD'>o+]=k%]W3C4@0C_$)s>RU*S$oo$+,3bXF?6^f<q04[U\s0q,;m4Wp`W3 %eqab:%bi\h0MXgIJNHCOUJ*d$_K%B*;se9ln?Tb*I_mBN/h'5IhD[Y.!,mM;T.DJeh3%fGn5584ISa:<Up5IOP['k=^9KR+b@7nc %J*MU0TutYmN$&t)bSPMUdpd,hL][tq6Pjjl"c;l3=h<O\/l8JP13GlaFm/X;=-QtSnbZuIYF$og"IBjDG_9&tNI1slDC]6/9i`#c %mWqr]WjWs(hXY'>)4O+Jj<f:JN0&hGW_pW/.4*W%cnM3Zbp5e7>3SmpNX/M<X@a/-_N0N8P:AN!p^ruQB,7kt.Lf<lUU/NrB_P,J %Hr9`P;>PJL)D3tQ-HZ\,!chnE%)'Lqc"gAOi/^_NF5#S\`aV).gH:'K$D'\0W)MJW^pb-sa/2Ya9NP)giB%V`9!7%sJ7:@FBSW*1 %=_'lc4@Gm]W_=>t3=lMR4LQ0HQH_r0Y\D'=m\S/F!%Qj?.DEI!lV3Fp,eh555:r^Ha2(]iM)6T26!/]:H.-UjGWN2kVWHV5^j-,X %p%)@*\1GY[j+$[`04',J*X&0)(j<gu8eB4Z$d)3[&7h?R-iBdNnV6[NQ=KDAZ#/F->JHN/2b_^ik0e5rCebX$Z+9S?6.*1C=("M" %Mq_IPO4]l&=KRtoFY8R[$SFc8`(8nc+sU?=qf&<4-C\F&&C:](]*-E;dO%`UAY/4C$>$Z^&5Sd2faTu(^,IEhM1dC$eeZ6ZY3<S2 %$$a8p?LWXL(,83/?4i4<`?`c&i09L^@tJa7BX%>'E1]L.>]]"X;c-%W6Ajff-,(pA"'0n7ZDFT;SY9WBO;VD`UN0pK+Y62+RG3lS %&nijD<D%2QGl]<qC@#6!Y0_i=6\fcS,?(%bE=Z<UH`'08XPVG&P,Cl3%?8O."gmq_-3<>E,$@NtRmfcR[$]7(k<FR/!f>u(9Gu>K %<(_5nHYofqX;fu^.,cP:WE'<fLU5-riilSJTp]mJT'afrQe$,0d1NTsdOiaJ7E^8`>V#!X5^W3"HI)[d+?*tq]dbX!iJUo%gL[SX %9\-Ok25+Bh(;8sR,LoS&J/)R#`_e]sr3U_IYqK8SEE.+edICeOm^sT:0T#,;bPRhXf-Vo&o25XdUH4hSqL*T)_o.QNb+$m2?NU;= %`(af\'t8;Ba<_6fnk5l^j$X:*9':4M5C+7Q6COq8a[;9o+JKg0IUppCPVsr6Em0:A8Y58PeP9cN4<,b2Le#R>B[ZUiFli&D=`L5+ %!>PprkcS#>3B)-GOQ53<:M'UT,h"91\[':07\bIT]]-RF-NDC2J@tReI*@jm@[[t<j9[/nc#/\GG(YuhBF:,ZX]"kOTHnCM\>Xr; %KraPL5.0()8RB+PQ4(.3[,eh7Z$h3p[l@>HITJo9"5?@Q'+ep$\]U5'W<G&.b"0GIaYp3WfF8&^:5ZSjcPu"e^h?0q1gJtG*Q#DS %YG5"P"T9NTGAbZb<YZC0EC4kr!J-/&q91OZ^)bqBWC7>O<B]:F-/S=Ij'`.bY=Rd.Xt<,#l4&(S].<jGna$;?4G#IS:_FO0U,1!H %JG^*jFijHjGkbfUX%eV`*rZ?K<@Q6h\3=S2m3"5cq]"C.F(V;VVK5nYGoWrU7R)&%.9&tJo!bBAlCA$kFW'rVIh*<G4I-_$e^9$+ %RWJeC9$3G$:Ob!Co.%5)n:sZH"D^P.@Ab^!ESn"a(!T@[oWcFS'gR_(@,$G;j(05G`G)W.5N!A#nQQc'eg1+$)5,Jqcmih(8Fl5- %J+&f\Kf4=Q-=<mDp$S3^GM<c+8npQm0DPqG,7+OErmK#CZL\[4VU?MGOlQM*dN?a7=0$#7A\'HshDSjcSngppW-*\3UBh(m'"f.q %$n><L@<.up9%T8Kncg!edW$31U++,+>uif^0YpV1nWksX</6]X$28(0/4GZ`>Z/s-72&8;c-^O1q2t7fZN&[e*%uRj6Q=PA_H4pT %%_I:"2OOe#E&1K,\Ibr4l!Eg'`lo-80Kc^fke!/*;SiEkWO<%#D@F9GF673-B#h<K.ujsDF%rsY<l%si[i9FhRu6[On`l0g%g6:Y %\/]PM#F?hZ-[LhE'!&gE6$K^R1+8[9D<TZg[r1c^1_Ecf?4<9h4MWcn7SAK%1o#F9]g4_dl"6ngoR$ZOe<EsB([ul?/'$1ulBt#e %#\R-4@TEq'*n<I8p(b!(8_m)Qlq*.q[dA!+A`4N_U6ha7Fa:UZK*G5mSk1`V.pI?_6*Xst(giaM?/S%'RjahML3JVQd!aBt/qnc? %`?)F(&,WuRon'ZfGJq6K;-UMH;b97pe*a:gi'c<^3[i//8hL5VG>G"$_+\*hl"H",9LLVK3SR3C!`1aiAsZiEomj:mrdM#."4/.c %4\e?^_8:fi6a9?Q;L9q_"g4RkoN/Ssb(ng94NCanUL)[qOJl>q/C$Fk*#7n-]CF>/hE&9jb7=OVXtZX8WU;Ou*ZT:-kRt^11'[*0 %.BBUR^GbVbbG&,+mS$K(O81^\EkB.V[62ep^M'<r]'5p*qF-DBU>-f)]Z5'^TlPOZ0d#].LYDD;Q2=)`5Ldsh<VBogr]n%ZeG-fQ %!sj2XKO"eb*=7>c"_"$U92C5FImVe%iN4WJ&,8V9!MGtjLFFgdKqLG_0f+7Fng)oj@dqimB8Vm9RZs)b.,C6QTmDt;H7i,W0dHW` %:FWu(G<s7ZR:UsOepc3J8(&6r;K?.E!LkllN/!3&[@<T&?VG5C6Bn1^1;K"icPUm?0L_0DaIp(Gdo*+Z])k6Fid'-nH*]_S"(39p %a0dm,8>)1*2pokJN6P4X&h=o]Glp;dd^ASCA+fQZmc!U0Z6!*Z8U#="`[6Ye9/_RgU-9S)<JQag(\qi41)J`3WNGS:D0[VHq6^FK %8[#pQ*gMh!BS4R*oN4g-Xk-b9%K861g?"C'lib;"%o:+&]AB'3QTML?"[hN?LF#%]V.U:s[qYaf5ZN8!FUm?Y&^L4[ao7U8Inl<k %U_lN>E]`.'9,"YPW$i5Bb/hf.&S?JtR_^`h(ORp:B%FlI4puc#K>pnnalF-5%8?Rf"MOhg3Ip@LJGqY*5MuhNKS#S<E1n]`FG>nP %&5XVr.`I*bEMI3#A<%&f,I]IV(9^;2?_dD;=3d20Rl]4bK`(c^;tJ7;"NpL:);8j3Jfq.rUVGZHIkON6R1;KR;<YMra=Q$/'Q;KZ %[n6-[%f1i9;9B#=oh5lMXWH"78o<PraTep!7hkP=pm;_?k(a]ZA.%5);>g<A7MQQ=0''*qa;%Ue0(c@UPq42OK`nfFb]]bp`>#kE %:)=Q3/gNU<Ti;r]r#JYr)J!AZl`2K\6'@dsI5njTUe\T!(Odf4(G`UqWj**s[_*R!FCFhE8Q2q%24rJsI?8Znbk8E1@f2*sH`?PA %D+_,q?=4GF/Ok8.jCk[VbKo/XmcLOtmc'3>Sg8@FSfs/`HjCD?#Ij(<ZC)aKE_U"2b:$J-e!"2!6ck)U$$/<F@D5Q]gpa5XnA.3: %[*j3#'e$ZWnRmn-`_8-8[cls)1ca$PD&%,qA/MZ5U\&]<cq)o3E8X8u0'9-PN3I@Pd^2gaJ0I5.3siU8Il']7N7Ujm6[!:eUCB5m %+[>_<jF-4hL@!ic7ss88L[=)``I)/X8*oH$7t'?$^QYuk%ek\G9e+.C2,uJlnkRu:KpIGfI6V15)(Jka7gn"7"?%,AaHm05cCCQ! %/R-'[8*t#ASR@n'hfpi5D#s^g-H=?LJcH!2Gou,@c(cRf9\'_QYj`<r''27Hfp.?nZ!g?hGglb.qbJ@79Il>FdqYSgWL2(u>PLiK %\b7Y#@Dh^F5(4[S)s@E[MS`Fm<(N[.Vcqnj=kIKm6gR_4I2`?lYm-l)C,-ZY62&%HmBgPF(-e/uDS'SmTO&m0e>*(`Stu@!>)aQe %g#PQefPDtnfurLE)as2b_Q("7ZUfhoi8Krd`GtNU]>OZ',:=0YD`GS<+1P",QV#b!AeWB?nhc[1f>$e(X*p2/rOC&'`e(\)3%dJ> %!rB8&>5D3a9,59K@e1NtJME5.f[T#U:6fe5al'5lojn'g>[Y2m3!X3ETe>u._\hna6Y9lMU@^4(R";E*o<;'GR%hK:ZQR]@IDaK_ %_E94C8u!?#G3JI3&`a33T'`D<BfYEVMS/DP40tXN.*(fG)B@fAZU#>a5.a!%3_Z$0#==V6$Ch".+l;eu,lEKp;*e,+Ht#7Xr5i:G %fjiBUKT;+Do[Q4kFt!S1]c0g9AG-UT!UL"&D]iR-gt2lKk!Hk'\F:Y.mR5.%#T+HJJu5(m%ZNs_H?BMQ5;CSQG=OB^&>G]PnOk=S %MsP!tOEhGe%#$W-M9[X45GSNP4G&Z80H=rDO&5FmYj[ZLquu=.+@q/bMC\)Rja(<F\1aj5<M:6OL@FRT7W@BHh:GGiRgENqm&9iK %Oo!_`oVBa1W7C"#2[ia7]Q$?ZcFJs1)MiQGF<(ll#UR0,ao#;/'3l)%,D<,9A*D`W)%k["#)s*Ye6d29G(\D!fb91p;uktoP(P9b %opmrlB(@Z>mja9SfB4O.F+]s%!'A@]rU8O#JB)Y<I"^jJ:o?6OoF9<"hfW96X5VPOrIgSRLB:%tAnbgH+E?b-8\+0IP<;ZD<M#1W %Q+68E?.-1)e*h0(b-q)YFj'1`)4P50!\mGKm-)R<i#eY+lGm1;2,n%ui49"!GQ\esi6"CqHAGV:+PT6tI#+-(@-]I*r"-,_62.^> %hY'F#]/V-['4ha!U1gR?.K"Y3gmiH.#<F>eajM"JMCknn-`=#uV<"OE2Fb+m0mL!TR7ZJN\^<R5gR32fSe#Kj)jgpl0&Y-8VsZrs %S#p[;k%9]sE>VPi:6j6uZ?>c4l@T0s4L.`<[8F92572';FKKD0oqD0-'8%g.g2=,9*7"h/Q?706M)$Vrq2tB(s.iAC40:/<r[@.= %9P,GLS$q?X[t2Hi#5S(+J=_8DT['=C>!l$FPF4Zo_u;i(l35J1jbe(j"2<fH.]=BIM3(.*"#nlZ9[38Z*t$i#S:5X(eU4mRflHi\ %"I85lSm;g[HP'I?:u&ETMb$$_K?/'X867DIBHk'SOSi/%%R.><O3BPK"7u#]Om+JI-@A^lK47@tg"`na*VptaEn?m*gHmU]8BX$k %4>S`,s'[qK+A7NLA2c5ZV2uQAcd-&^-%D**b3[HHV!0`miUbN"qrSpPI,Z=?X_<:R.K!'MRN)NB;0N*r`9sX`n29n9QhblQoJI:! %"^BPi$H!-Y,B">U1r_Gp7eYmW?M[#4+2.6J%_H_F\3um)'>oU^m#SCa`(?h_-)EYmH_$3IWq<EbFT8/FpU_:T59:VE&U^?Pc#HZ] %ZmC(:0A3nII8Ug&U^KL\!RPIWkn=>oa\-JSa87Oj*bl.@FD(j9AX=J&hV7Y#%O[TAPG7rr,smRY#(I#SEZqCL$G[%bH6KBY$3:Rn %Jg%Af$:5.$M]oIt$A/a0P9IFk#%E=[bo#;_JV&W\d1B\(@o4n`eI^Yb!Q,,WfaqV>J`DL3h%8Xo"U'V=i;dJ;JL"U\b9>4m!_%kE %l548aJRsTJmL\`5!JZ@PndF7N!_j26liH&C!fdeBoHE9Z!-!?kZ!IGZliJ<YRO^CLckVn"DA2_8"nE$I/7aeF/@-iKm@Cj)ZJ7'c %\<&cgZKs3&]TBfCo)(,1^lUbt1(>n<`!_4fNTk]H6q7*rOD/uMAVLW=R-Js*Kt\3k6`0+%Po;D[,HC'`'cR`u6`07)PoDK'6a#m3 %(E@IO"1I`RR=&EtLOA882`g:>'D.LqqTlg>VNl<pp&*G/X>6?$f:.Q-YD9P67_fVb;/,LMi5`iO\iaUi1$E^F]Op+TN1Jdb94_1U %1qh)"QlDZJ6CQ/C:n;?;D!]S;@]$m%;3"D(\91e?X^i*N?I8\grZGp"<jFg^8;riOl,X*!,8cEGGTQ3#Tdb^lQrdk6&GgTRr3&db %"JDPNEBS(PC%Ed_\,1E<X7J,'[a`GFLBZ#B.;Z3G9Df4g`9%&3gEeg%bG46=Y7S?ZhQ02FdT[p!lq#*cfcUE-oZ-9&p*I<ZIm</i %P$K!1q[TBpgr'V2!uEu,`l(r*Sm/>gdAN2")]D+$mUW/u^nLo(ec.ZRB3kO(R!Y]pMV*m7W%XAD?A4^+J+2+^IWZ<LMfJrCRQ#P< %+2)'<MjFh5+_@u'F`3^ZMgSm[[=ufINZI=7/M>3INT_R\HR%a0YHQVbr868EWmP=\9g(<./Oc]k"+Epi2rIU_6JFg9H%SLqeoLS0 %0c+:mZkQ=1L:ELD')^Jq6sZXH?doPLprS%u:5gn>'<O6QU,dPkAYbW;2'=.hU'ulb)(1/&SVr]B4c+1*;li1CU$(_'$T/`_Q$igm %JbKt:hQi9N,9,@pJs47h)J;Q5?[Jo]ffM8*$&j=Z>FD&no82MqIG$K"otG;0PbQF5pn$2>Q(_tP\IZ-L1#jtO[lcqu%#D[363R21 %Up\94$2'p%9"fIFD(98>g'9;`kS(/`jMjnk1Q)$rRe#1&Mq7`PC!j<`Zq&ocm9m>=fu&]U)-tBd6:sj:\kSh:kVDUF&-5k%mm-2i %VNV?99%VhH2P[Ud=8-a>(nld4H9W)Oe93r)i<J/f8,s1ecpH6VFR1m8"Do,WcJKj61-M6j5g*!!G>IK7XmFNl5sQi.:#5jgr6;k9 %0$@[W6h'9#<ruAMp@E]6O:&Cmm]ofUoJY8gje`T$RRGC*%hQCALujMc7]e;)5%GImo7)d=s4E7C$]]YP]UYm%U!^>S/6Qs['Q#(' %9QaTCP[dND/^[rp3IL?T)/imJMI?rLXB&XWS+FH8K\Dg!i(8q63:RfDq1r8tZLBN+rNXF.R^Q@uEKUm^=srF(nA+"-D^bcuGr=+# %C]M&)9McXTq/5$b.=t*u'*kq4TmErK'*Pp%IQl+=1I3ob"TeuS-t%.?f:#`^i1qb-E&]eu\PSkM'XA*7n,APOq_#q0ao*jJ(Q/.H %"T_!\^d)N$;YIhhaFdsuAV#Mm.9q&T!Y&1N\E%RSKK&;88EK>8&M_^dqmM:hTFje,>f8HciJg[0,EhZ.8:SQ5+ebRMS+m8-5e<@F %B4@[bD^T*]*Xg&);3:;`!V0i6@!Nt0<LpbGNI[atQ]:(7k<ur2gJ/OW`Vlh,_S3O2*)%b#EtOfH"_g<fRZ#Ba.#E!WcO#;KVC1B7 %Mph#ZIZ3'tU?P52junrWdrbFS=Z+QU$C.><W`#Ml<N&n4b?@=9=J8XD79(j;i/4nQ0"P@%bR]^^!U_8EDrW?Gi`T;WL37M5JL!N! %>gf^U4"j?Fd##ogd=Tdj"hpqJ5cU=edj;plGrh'2@cVRn`]IWNR9b*M6i87@N0O4_/#<RM)3I'#m,jHG70fY>p;W>3[gRGcba#g+ %p3,J.rIGgd*f67]cB2glQ-sq/?Y.&?$*d<C/.a.TcR?F\k!)^_$/"no&-$!hZiB`dn)=hL0`V/*mLW\ChDBV1n6s5d$M5pEG1tiL %8D$[!PV!1E:+c\:l#+:I`_?@QHLnF2+Ar]V;#Z,--X\ot@(i\!YFJ,DI9-Jsjg!3D]6b?%oq[sCeTcNt/d!P"ZSR<_#MQ'2g2=kM %\q3shQaU7f(1CW-YtO,^O=;,GC.%^^FK4>rQMAnZ/UgNI*S.VbK["_j#Q:'-`eOjuRunWV"'m+h`aK`S9XhbQ-q'dsLWY./SJs^N %n"&Xo3-B5RQZR76qVh6"0b-AI:K?Y*4no09=d;@Y=Zf[kZF!!3EB5$)Jm=gHh$q9=^L)_]H*i9lhqHR/jJaOj&N[(qkmRRdJ7a4N %D6R"+=H/"Dd2.-5BqP)k"cV\WfOcr_Hrg;#S!/K41&%D^q]qbV(9&209Jn.\/X5F`5sK#c$5`:CZab@[6LBCpT1ntl1D5ht%mX0^ %$tp<F_1rk)8<P>Sd&AY-6=C:F7X0Pp82(4m?k>a8Eo@5PQ&sO%3A@Jr_4?,D1R^[H](\4'Ve1$Jn[JmSK[M!*N(>?WEY0[UFA,$C %PD_Cm.&:kq>m]RpY'L\BZp^iYnYTCXkD7X#bq:J6KJP?MZ^:K9=UX2g$!5dK4fVY"lg*#oHMPb[*Nk*(eH@BRP1',K(jt=+_4>K# %n3_@>PgC]1!T`36$R4#Y#Se]SC(rtWd]g:HV%IIp1c9*QqUUPs#86IL],DfV>cRElIo_np)..q*S9aeqliu"*n%*#CjKYfXRKP'! %dXQ8.]H'/o)0Isc/n\O98mY9BpX;&`Vf-3oI/JbK6Kh@$r^Z1O"CB?FiGcM\>?57NGnA8gE-?q0J\QC=^,-Z:Rh:EmMrP;fkc/$? %^UuohJR)p-Wj2Yt;K9mk[RAeW&M:nC-nV%(@7Gru`.UO<I95r<p]M_kaq4a"h1.DF)<&;#j6"V]5J'n@=O$u1nAB4#8k:7@V.1Ga %:;^"[IDO;J-e=mon1u:ND@BEgjJ+F'Vl^[3q[mg)a:Qg0(3$;0ALXD1iD2JphV[\k\*GGqj)lBsAl:*fB!:Udn>*lI/[qD[8+A@k %Dr9]L.HD/"Q,KsT(C?=&/g\qG\Os)&p2>4&?2i^PU?&B]'6eC3<@A:uJ@icCk?HdC]e[P4+Q6lDh%j8*1o"V%0)=8a&FUiP;t[Bn %qVP>9R>);-]Y_l,8=<GGHXOAGUd!f@gCVJ*I/H=R,1=,[j=r"OJgqXJlY3qfK#eBugZB\='M9$E7#WaM7oX.N:s,,RA>PQ00D.5T %J'Jr,^&gK,#!H0SJ"pfp-#C'.->%VoLpa[*Vb"/lM(R\FO3e<OCJ-YYmm@g9cbuan)TL=<Mupcp(.1X=M1glM8K[a^TEcdp".eEO %;:%`6Z&cL.e4hbL;O<8pW5;[ObdXWp9.9BE$Gp&d@h;]kUMt2rOZ&Gp@A@sQ[XV4>+)eBRf[+H<T:4QuNXHA9DHD-!3o3`KfotJ2 %DdY2dMKIZ'/blK`UQ[+WlFEkiKF0trjmoj'cp&ujRXYOl@0,h-`l=7A0[7GcOA45R^H-1T\W\Yaj\sa4X9D1*GsAI>XFqB\h@Ii& %^N>OP*@/7[<A_tEF)2M;Udsq8(S"g==_J9o<d*jM?M;e7ENIkF#_C,Jg<4nNilPh_j=;:/Ei^f&mgl.UFF4(20t7`Z,s]aG\-=.a %dHH7*Wde;Ld`\U/SBl+8g%WJls$C)ZI<g6MH3ZK+OlFhY*U9LI'l$KLoVp^!;Rl"p$T(u/dA"DD&)gh-mQ,8Je=U`,$/j0LCQcgP %Lta<$m!h(L]N<8lR;OeMFAXXMj&Yo1$7&]XgG`9j:d4V'[2[9ZL'#)OfP`/H*(pQEjG*9$2QFkO1M._GAaPsa\)sOcMUpeoH=^8< %-"rkka1efGjjMXT_\79EEd]`^9uM^s$mP=qS)K`NYZG.aAU&eoa^#8T)lkU^^%S66XD*OT9oVuu\paasC%TH=]c]+`bH"cte;PEu %EHI#F)g(7?T&cSEH6F!NS.G6UO5JPZQ&S.e<CQX0>9L5HEj;/76uQp4&?3t>VP]]/>0%rj8M22e)6/A/'U(^[q?f)8'o!V;8ZbCO %7?Hf3njqQl)/^_^>km+DCo$a:C-A'(e'U4*S$-VqNp2d#YKKp,^t?30<)e=NYDEdQ=PPah=>B_M6)$C(>J8=)G5<2A:]Y/M$j[H< %C@pW\s-?s:r\EYCd,d)=R3f%93sDGjnQYZI5#_mpqi0CH2(k]2Z&a"LclVH_8Qm/!O'"C)j/T?tMXcA:4`P9!YQsbYR4B5-8.dA: %c?b]-ZG4.2V[hH`LFo]n,>YcLPjIG0_PE2!W"=O.R,1)ieVcgap:M2e^I0u)#4V372`th0*qgemoIZ,-S;4f)htj59htPCFWNL4l %+/mo7X((cqMKV)O]aau:Eh1clc!"p\,!-r\4J]Sg24FicVLuC/96Tu\kr2/9BRmTuG5t\O;;@2f?l3Y44<en/m@%\)[>:2L(N;(d %JPM,kO0CETB"D>$([2,l:"9S$7?PR4Z5ZaR,?uaEC<^M/HfHXkeRRs4aje=Z?lK9%;S4rG&8&B+:hcqG?U9]=rfhImV^dI!LC0+k %0nKM.:QXc.iC<eokh3!>TdsMaBBW-[c/D\=n"No,Q"Z>i<k]$ejkB4,hk&cPcl@JSo,:O":M;K^G9De#;e"WQ`'7Z>ou9@1nipF! %r(fV#^V`9q$^j^o@2Y'W#])ifm48VV"dPOg9s7:I@=:__F:A^:\NoE;mAH9k;`E9pH.ACA1"&>894l\mGT!dI[:D2:DC1*:4IB1I %"ri^%TU;NP:,C)nVXP?X]AsG#c=WE6W\KAjguM@#@TK'#:Xqug;lk'#"%Yb2FlNosl#]>A3ZF:kBq"gqDYU.Ppkfu'0#P@;2I;-Z %jo_-A>^<qIMq2bgW^#[eJ4&0eham;\bq"bJ*S^@D@5Vl]V2oK?nb0R-Ju1,;U'[O+_PNSpd.c_O+m@?K.-s&1p*dNE1MT+N:mb3o %V8H2ucOn^&b'_KMXr]HWf-/B70%=`+F_NOcB(Q]:M;R9_Dp?$\@1F3074lJ2mDn3eARSND9*;Q*=^'HYmF$S<CtBF\G.TS^$QI*> %XlZ_MMBK;=-:*5KPLhPo-g"Rkq*ma]Zn'*$!VY(d_@Nb0ZDs+V,0&5FE8"3!Dn<>Z*nHi0^I!LMjtPGWIBf,7M_SVZ,rs%IJ5HKc %VNr9*FQd.k&YsYGR5F1?&S!gp=[6n%pB/f9(mrNB^QoIZeAgpKNFi[Tg0GWTrV=_/hD%>5b\c!`.-snIp,$e-3Q[bc8tkV^W$=&O %8T0F>&=jd"GV>HA&0Dl9M>nntm3;\M&XrVN#K-N"g4*/pVEY4bo=ak@7QUS?g@$[I%<)*VpAB<?J+m1D?+fU_PQ&nCs*oOIJ,\uI %n\!e\iP54Js5!P/rnG3ej1kPRs7u]j5Q@X2peUqSTDmkXc1l5Wl2UOnrqaV3?iRaQrq.?ss61VT=6o</s5*aEf5:Q4l[Ss5IsI$T %r(m/P5G-oLJ,P`6qdoUW^UN,#LYr-Ls-eE:8%JJGetfs+AYF[XULDr=l0$N[Xhsi(r8"u=J+crlN;rE,HOPCoIsBhR)G6&T$b&Ah %Pbi!-T*D\urgQksIg1,lq>(LAb411(,*b!Og3l+_fp_YB`Ccmi@8=gIP$^UaJ<pl-I1*d'h,e/X-(_F'n.5G%2;!XGRmB%,JW5"& %GI93))KDUL>omb,0BWqnMdoHLg,(.C)mnm+:cb2ujm^4dMU-QTWY.85Ein@"%[?sokI])*g[bX3TPNp,g=-1Aa=m\AU17u82(:^a %Gj)u*o39;H=thoc1WjY+\nGT$1PSC`:ur?XZraD($1BdOUSHu&nJiLT4IL=j^!B]X!ua;<%tCr@oB$=B_n.r?#J#::EhNM!(A]fj %Z+F!r^44F:%D?:%Vra-/gM_(Z`$6n(^BOuc2>]bJ>faf^KkN8G.&k563.5./%N`L9>-^U5'u4/d+9-etp3ZQ7*1fam+0YZs)&e;$ %Ia.]WQGm&U0E$e6Z^*g:&t</#AEjNuAt.N8:]f-$kl1=q`85(f+Q4`8=q?gNS@6*K,h-Ae/D'Q\\>$fUm=Ec!n[M=6X;,a3-M@i! %:_iS8(!Ap:]0GgjflH[n#,,,>re$E.nAjAip;c'Z$S"YVB%).8QWpu+ZZh2(?lUD`(j\sR'\u:":b>of^RP_MpJ08IpEt<5b*Z"o %48haW*KReAF*7*+HZ0:92bf]''(V0[h6rXEo^cYbMcGYjpA?cCota._`EB-U/gPB,#/tBcCjO^T>nN?MANas\4(i)]H!umd._PQj %<eqC0r';6I/]0Et.jK]CraHjAnNSd(:.9,LdQD@ajeJn"DMQL29Z4:V>GH0tV0eD.,A,(XLl9\h*#f:Rm0W8qU1Kq_(?N&b67a3' %iF?Q#n0cGqE6=us2C6AUHndP-huS\$Y=Y[KZK$/P4C]"BJ:,g4/]NaBnh+cG1]<SGYn4o7Qh(?65M"&@(F'I4HH7sQ/p23#YZJ_S %BlsIK@E+EW`k\"k@YS9BScXadKkRl7pGjJ,2LCGjp]kpq\b"eg6ao^Idj1>^0q&i,DW0NsFM@DP3*u1As1O1`P)Z(p9gBKJDV>Oj %WHUJ&2EGoSC(J.so8Wj>h(?"7RPg6>Plg;B`PdYOan1s3NN8.DA?g0m(4Go.+9(??@rc]!CuK#O%r<WA;.4HC8s>:sb?Q!I#UPr= %KXn0jGT&Drs+<<_ZdL8=C<RF)_=mIob]VFU.:Yg^;7*<SVCWqTTBYLg,;;sHIn,eKlI%>\\;PUcJMgF*k^5PZU?%'9JFGM(S=Nti %q-'j7mRl^]q'G>$MA_p70r'CM`lt@?N09kl]U0PL`#u02X=u#cLN3`r<OXq6\[%^$_!IO&pEA[?I&@E6Kr8!G/W84dGA8gtk-*-* %nc_[M;1gu`Z'AlMTP2$>mFo!YS1jkYd[Z`:h;(q35A*p'^+IZJV_HZICH65EVp/b!/\/=e%>N1?FNm\WhV)bY562j#,(ot5Ql;B- %c,H#<a&(2s.b;o9Qf"Ouc2D5*_A`pT4L7O+Dngdn.oi`uKspQg>3:.]L%=iEYI?tHi+BkLnq5lG`V8ZWO7DW#loA$LZ7`eHP+=dN %:=TS_HGbNS`Egh#qdk.lh#4L3s1f)jn5a%tarA"+m/<<&Ad$lQ\R<Ab0SW8X1AtCoj.7-bcT:<O3=a""DHEZEOf=>0)Vlo/4B/M+ %db"+P[&TTBpBY!sCNj:4EGA+=h8rGQeKCP"KpfMS&k[jJSh&Ccf*P.6X@sF.'tsE8-Q"k>Qa%'N/./?`5-)NK4hXso8][W-lm9$W %6FP)ACIPWSl"_*$`EcDW)$uZ#8:bf?rAe*05kbL"RK^C5F\1c\G6AXWrYk'<>6Md*LZT8YF51QmMLU\A'C+=UDnGBd%!mS9UZp9L %P-7Ie(2_FIQZ%)%8i+#ccI64,(QbLAD7YqQWAcg&Mi1=enp$Cl6&HMiX&XeCE:\UCiZi9qh;Yg7N/ZgiJ#l_-eGTTT2o%3.)g$rU %ko6ik:iW*M;=m3!+IHoaeVRY%P@"\;/iCLQcR*/?^XnX2RN'RN&`p3`.BQcm.GDk&CNra>ct&5d+-FCFM7)"F6fnr[4XiNL)m3hC %m'O/pX8?^')]H?WZAa7TPc@_2rcHXU$j])</"i/).l9$#k-L_3Cm,3;mkj5O0-HP#_eR!V'B[p%TM*-l.+Zna7\$=2icDOjQsCna %m;B5T"'b>qd/.fGlq6W':/:*2,fG8D!<e[W?X$4Y!kX@*N+HZ1$Ya'&oK%27gkhI)H267g*-d>Fi=/VdO_[7EP.MnQ-&2VAqA?<q %?%j2D#]M8]&bRJ6H[L<Rbl7+HA;fPpEa$m^c$f1lBBNU6#P3U#Z)*<X&,[@pQ/j=dph,Jd\5]l>-9p\U,M"l_>WlXfUPAl;`#pf4 %3O3%Y@FeA/7XhFcQs5PJ,Y-1P?fP:C50O?M[!Q_;eHTr6=OF9B7)1TK_)8Td3JdB8HXsn-XGi?7C(b0Qorl)Li,-gMH$cnoRM4S\ %AUh*GE+<VlM_Q$\n)FBgr[f4_Z_e=!bt(Zc,fdEkBQ]ZFQEbD7'bkpFUJ(6g$O?EEH!(&'V_tY8j(<7S2#`72C%MLk#qN_dniR+e %MWEL1YS0XUpHe91_<>L)U[q&u@8`YU!kOXfbsni*Mq?CZJH"*`k`:*4dVESS%aIBsZ6/UXrPSdshi"g@q*/9lA5\1(B12@`7V9m@ %Mqq*O<Lem#Rs=X=n+H;O!$"V)4tnk`$M0PcUGR>049^FS'2oD$*&F^;Hg6&"NF)-j%A9#?h$_PtGfY=1q6R6>@d![NjC;_dXb?P7 %0(\-VYI!h5HkUmg4:Lgpc<(+f5'N1.QV\!)I>Mp3eRt_m"$s3I9QaNu]?p)6Y%EM>6$@Fn^e3;Z$dN'r<'8aCa.rYPFM9("/hW*s %8!_@Qo:j>(M9K-PS?4p,Z3u>#%-:bg1-&QBnA9fhGB>-$Cr?Rh61]Dj+O>=cf?qQ6"[IaBJ//?Q!4:hJ2^iiNhLH2F0t,F6>)RW> %%"P/ObiBei<>JPQ_:fNop*Zph$`lT>q<ZkLEf#:u8\d]S9fe%H:Nd:g,l-bEreAU5X+*W."hgc0@Z8dEB*jHZFMp.%lLrd_Vi_&0 %*G/Q1%XAtLA!5X)BWc':8FY)$$Qn=%)rAIc)$4Gr?BR7ooT_Rim(+1dkt*P[$;;5Afe"?6,p1*i96sY8[i14!?0j7jI0r2nBeek/ %Bu^\.QK(hhg-DR@^DjdFAgG[ha!crs)\d(mY%8jV%23)Bj9'X.W+a<2b&1d&D:ZK2'c2=ECgpe:aRTJ7<^qXWG'2?,>V7lQl_?X4 %Z)(]"RemL&DkOlrRpaUX&S%])8-*l#&]Bl25L'eP!^oq./T*a<?/1K3eWbNCS'e2^>keH(E#=_91uV:I*u!4qa@#f;*P.EtOX=,j %_+PMoacm1bc))1$TN3fN^-]et!Dj!e:DdkV4kk21/p\-$0bnPt5<0,$B^FH:>h7Ccn#LieolQ%ef@0G8%alD=?PY;7b<c(RH)>Ef %hepG=kTZW7%q<O";-fAWA3W4oj<&>cNM&Hm?AF:=eJ1iU.*$`H]r(J%&o[%=215J7E7NLs`0aXVR0FLU4$7Lnk=h-Xq#ZJW`-j4Q %*Xp6#E')Duc]%5!ola^Ai$,jh3Cit_9r,B*@ceEI[E4IU[d716q",j9-sEmiUJMX?rDM`E!iqn/&`'OLnuokmeA<J3m=(^!a=bc4 %ED8C!&%\HTX]L0UUr85:.r9$_X#Js'kgY%so;Q0)F^Nu>X*kD,FG+?:D@cS#Di=4'@*s7n,YoNufCG.Fi6#e.2hU@HY\mAR1'&\h %DR.M+1fY7fo,0q,HGs-W/'i/M9/91u)'R;$3+(!_Nq<"i+Q5'Ym+rsj-XQ@NrW^"+XD3HlHkBZp+WY6DX[qQm3\\/N(!dDtPCU%6 %5;p4&Y1noZ2)WsI[21AD(,'/XJ'W%8II#6Qq6"O_+g$>CF1=*>&8q2@P5q3\PR_"L5J/::Gk:C37A[P]Op:lAJXu<+RY1S1VBDEH %.7EN#>&o7]\G%Va1_DN/"_+To=.nFsU<As%<aW!`Xnm"[_'H[1?;.&,17n57^-X/jebM2o#M$'A,BL+0E1Wujk`7]XBKUY(T<)\9 %J]#6-W:sk?"slJ;(Xmfh4R@U#(-V%N01&ZtG_>8"):WQsWJj3C:>Y+K#HF`BCjrV$m?.m0-IqXP<>If-4VahCFet]a-dQo/iND27 %H^oGlbiu<n%W>)IY#8Y&IrGrs[J_W-_D7^kq=Lk1gjQ]f@a%4N:3qV4%tI$Bj9HSkru9&t.hD@g1?OWK%Zf'a+lh.nEY*SRSa&I- %dHCJ+p^BJu[=+hg51nV(Xat-9R]@<%M2(+;+a<u@fq)tc3\;!g7tDW4ZlE/ea]chs.m+/jdd3/$&u`\rBnY#m1"]/-bp>1nAjB>V %;u)`C]H,Yj^C@@?]j\"%W4eJ\n;96r^(C-ffL4?>k03]&Eb%V>\2(3>e6XQ?$fQr`^9pD@%sY17K=\]Bo[r&0@;;rMZ&#%6mi?3I %^mu;Q/FE'rP&#u&m;5^d*7>":VP@)DoGl;S"tjM*OCuP!l"Q3Big21m!J1)r^>*:bm'-:iAPtBaOYCC2oGeGrMLadF0@(FJC0q)q %7=WRoP:m.CeOOQQZCcrVcJIP1."*um1NINr<VcBi&L,/B#=[;)qqHt?4na4L&8H5bPo&r>kV,J(LSVJkf-3%U@Q/6AURn'e_)!f4 %5)OG7Fq5T^I5=)SF#:h8P(d>iM"A5jCNsYSE6hA)Kk3-ZfU8#/^(VjE@MLM"i0\I`&0BW]29B=:/It+3(;K7Noaq16j]>T0>TV*3 %fD[2^W+0JLmCl+5Lhoq[04&-rW`Y_&qeslgWPYR1&*-k(&]?VZC;'#mV<B0WB)m<kBbKl:&5B\7^]Q!fBg&5sg<HP'cN"2<H?8sW %4JYc8e=U'?KjLJN=S8neY;NC-OF7:NJ14:@[N>nnU"&VRO0"A-h]d<d8n_X]^.o2<X&YF7_FuN&M-lOR6aRLTiF8mXQ/'C_SIa3u %;^liP&!^iMOSfe+V67X=k6!W[h*=#hB.aa=Y^V"<QJs37aUci/Zu3(dmc)atRFNT!X7I"dbBh1)<hmXMM_o9%0fmn(4/#a%%(gjo %k&_(kmLf-N8IqVNjT^X`g6X0pEhurd75LNKB]dONk/kY)ZodNVINFFUTmEg<R,*JM#kA+^_.tW/.=d&r9d4jh=1rV..?f88aro_D %eZ-k]*^D978[Q*kJ1ZDU2-+j,\ieRGnM[4.DfE/X/q!f2)CJEFdeCC8iYHd,dN=S]5D8t5,[0>hUKfnE<Dk3B1lj-NRkT7n=ae*C %-3g)'NIJ`+R@Z#(kY8uT*"tV5D)2;;gm`K"X0ZWA+"5InmeK%*GXYfk%\MS8=aG.2]bq%_0Y>fC+ikG0a5_pDW*hRV17U[..'E72 %8(#0<m'3ZcT=p`5N$:c5>pD(U-.BLnI/dLfDqo1$@76b8R^Rnlr7_nCdG?f>Z5]:F,Cmi!VH13X4Ee<R^GuAoFW"F'gCb!do`]Yq %D(XC@h;SD!msYIQT9S4[ci<"Vp).*skMs91H@G:_EueTapp#VERs4kH@fgEMFEoRaf/Pt#6G0g7<56]?OR1.Tj-q0''OpE@:ogqs %'BYK2<WL*7?L7a5!Smi4SnPfLP&nCo(U'SPj)j2o"idDs/(#eG+NR?Ih#V,q7XGZrF$<NJle?jXK;'?XLbW7QK;NDMR;UhE/O*;! %#*qP+*TE,Tiq6R-F&^<LC'ob=@+<6;"j,!<Tpb?-EB^C4H8*TghmRjk;If!8TRqsjbjo`D%%.>:^!Ip0N,*Q^6i1jqQd%@j0K:EG %^J64R7#AQ%^YFMV;>O2TBi+&#nEP]153tS0i"$@"=g2Eq35qh.VjSDu@=qI\,C.\K>'5W[?u4_+&lEu7qOD)t0(SUnO/8tKoEN`l %[ec"u:$/el!cn(\%o1M+E\-;Oa54E\f9'>$Jkpo@^`Q"d*eC>mb"J!]k(a(B%SoofE6C:_9MBQ$2plB1!toI4Cl*W;a`[D[Y,i'h %5jVOX8FAH-')`tt<aJk1qeE*4;_^12Mn5Eu<dJRmgKhsGUp5MKhC.V2H[j7UPoX7fM;eanTGDaD]q]>J1qB]_e3XpSKOjfA"tk+[ %"3Pm0d"1<]pDr&B/'/%iC)A0IQ&`,XC)ElDDmO#kH^1Td:H2YBeOf8'NkJ;RAo[(!d/nYk)/2G"?0ImApI+Li90&SA^g]TG;"dfl %,0<>MG:C.;lZSHAV'cE_VhI5DP`KO`4d[@M:dQ14,:BSDkk8fA_T.n'B<q;*9DHW.&d+B`K9f1:0"M`D3m%n3TM(h,Igd\b2aS7d %r(E,:]@dT#dLm-jUW`6o,8b8,Vi9k8VEG-e7$G"`RYt*K#O7U8+gR=rf)0BCqG^@WG;d'dbA7J$f#b"`S>:T&3\CGCNrHgd#I=U* %7+<!C3?]%s5[>GR]<P&$K0ol_(Rq4@O?>Nl,UTARR[Q",8-]Mj<rPc+1U*)I,/a4q!(Rcq.)X!U`+!i27H!7F=H0JNj\_4uBs*EU %r7c:,p!d2^ibUV?U;]^QS^<ZS@RB[[EOHMO\Ro'Xr-WN<GLD4?<<4P<_(J1b+.j`@Y!G\hNlt%$M:%0Dc(0V&A-NTO^3oc3P6)NA %\0[P4E/?Op$c\f.=BaCQ?FFu5`FC.kdBXLmM,F1/ib6V;(>Z'r`mmf/fF`aiGr\050qX4,V`;t?A+'0TjAY$jgl+(5L40YNdV4(E %G6U#b7lmU+MGRu$A0/!_d.`pb\hJ9(,=M%S&+FnahMFNe*1H7#6P+:+7nQ$)R>?[;7F]o,njQIcnT#N/RmtTA1I/EZEQt$GV80SC %eOBs<`!?QK6*mnd!u?#@:WE#ZZgCjIFr=9B'?O(85W`VJm6&8k.A6SiSV6-B"bd+kZVbZ/+Ml$0RO8B-,a_ao:+.eRX1Q`"KC+i& %GXJBV%++UF2g85]TP^*&?$#<Re[[WIoFE/jT]h\UQIgD(<QVc=)>n`IY7iTm.%-r!+E1KMqFA1*"If\?-&dM%2$(Oji8$\&$qg/P %e*u/TH:QW/<ff)]E!4AX['L`\[RXk).cqpGH.^(Ac62mOjq>t)r3qJIk_kRe\S^!Ph%GM:S'2a%fqSW2?kdNH"X?JJ7XQWfBKqoo %8#MQuFM!L-1kHm$ohPW9oB'_`%"a[cTX$N>eAB3bcpbR79pHdI&O,3Q."rk0b$=-FDnaAhb9BFE[5f3%<7[Ar!]Hd52.5)Y*!;@: %=F;3AG-W[4FrAQk'Mq;O&u/\-#P]PX^G=_YK.eokkq''[_7,nL%%-k#(jD8s-F=1PD&k/Q+]s"#c9#7-If1[#jp^c<X&>EcQ<N(I %fc_b*WJU,KG,FCW4GmXEEifGNcfX"JI,&1..-au+>]3P$l#i\A`9&8s]\>GfZV<>k6mu[n)D):U6u_22a[`[-0KVLO5NNFhL]_4) %Z!0f!+]UHU8'Bhr7+nC?l(oSM-4_p6SJ&q7,-Z?uTYfc<Wt:E6+G:8kBHX@\KlT*A6[I9D0Cr_WU0O.*5ZBWeq37!ShFj`2DACMR %NFS:>KFjB"<K/+E["+^U/Yc\_plD`7>$?q"[_,V>/1q&A`_qtdPo;TRd^2OL2-BtO"JiJC@3F+F8BKs^29hL9@"8QL&e#$7mVkB7 %.=?Y2!&GM#>in3"4I)EEVI)$6^F`+,YY;'t\q%%6AcO-%_Xkm-nQ[pXCq:?*V`o#Z+P@n'1(n[H/+o%iPplHR.)n>`!Y9mPC72c> %Sc^mN:sA6l$OVO;=K0F)rB?[MBE*$i*35YcN\]U:@bF2rklC,/XD.1l3P5Y9gZQt)JT>&=ma]nifJD+BjW,$6"q%ZT'Q4-n8$8VC %LO7G@O*O&L(@#'dJ#U*@JsUsQ*bTA+dMT"'F0Ats@:@q5_7:"LMe%GM?tbqc`6j`EoP"BGH#gI,pA<3^QY6fR,fuf,c`^F0Za]:B %Kqh6J)JOZ?[990XV4^TB0rYqO3ScO(@*'/e*]9o.=$9GsHo0uT$GNIu,e9o_V(m3lZoD]'D?[s/+o)Ta,?'4qPX=ie!N!A`.KcrO %-gS)UK,0H1U$Qc66quYEH,^Tai$K#ScV4&#!k;lKYQ]3E4Bi(Vi]$=b$dY(@8J&nt>g1MN3[Z;,(G$$cRa2]X3J<,:VUUOh5,][6 %-'sK%_hVPA?deC_7'abOaq@BOYqoV.PZ+Ai$RgqY7m/e,kU=AM5ckYV7tdXLc%%7\MP`ngQJ3QTeDqM!3eSKPb:Oi=GHEAI*@*(i %5[RE+6>geWdCdDrke`FcfSD3*'Snd5midg(qUM6/!3XFhZ8$V.,2G!H]UpGYMfdmP;T)^n=sc?h(4q[D1Dtb-Uesj%`C!BII8)J1 %bb'gU2>F`!8St<o)+l)NNMHU#0'[Anq[,3$5Vd`?K#&-n`O6m6Y8]U)kt;o-2O,%pltjP5?>uo'\cdB2PV<jb\qF7UP<QeuZcW&9 %]*IIW%OYR4p)(Rb+R9,pc6uNP]5!O(d[3FTTQdQ,B%8,Y5*b']bR,/.0NiEKgRTN`<AHAl`<]-kIl'qL.LQiN\-/=>/nS[R`f*n/ %WpJs/%#Mh0GQhI_]T:"<pVP'i8A>qT#,/eT4#Jm_5,er/QO4tcm,H,V7h/b#0$QJ-n*aJJ>"_"^iRu^oLp!H2-5g,9E"/P#o&^;+ %,-$IGgVj1h?Dt.cC^75t9@9>E99i%edko%BQ+_bWc,b.FJn.?<c!W+D"O#=0br_n`(5C3XRPMHEfFlgK$u]0d#CimiHNNf5:EYK2 %/N?*E)_EBi\j.<gj(uBoUpepMcUN8c"[qup1h@O>F%PT)3>^/nXI7)&W@1BG+K9$4M1(s_3?9Rn3K6'(VP#T-BkY-^Hd+cFlNC:1 %.o&\1%(!;*F3Tiq(JpjKM!@0i`-"kd&bTO)cu[Y9Crr1HHL^I&g1hLp'J#>Sn;_eYKP,d&)Rn!egB3fLeST<aZqWm;eJpIf2%_?3 %g,q-j"ee=<+[7:i=]<dgP+!TsN_us/&q<*5g0B?9TPa(nc'F).MJK8C1"g'*Ci*c`SQ*nt\Y?;^7C/f>eU\rR18@Vo@`asl41d'H %^!qYc!mUmqd&bN_VjGDu&8J,un[3KP""`#nq[G6N!qjD74=<6GE%%HlEgd@jR3ng_W22KNFQR-h>tT=6.hcZ@6!.RY5rQ?E0id1* %`i_WX,rC8+6=__#BXEPMBZm$UD0)76a_iR2\/5IK`/1Pi)9Zna3#*$fC,iS9l7PCD9G%qB7&NZM8n'MP!7["&-4=]K_C=WpES"64 %:m8i_]HCD&Sij"T'>=36S!(bXc]d`_&lZC>IPMjQ9.J7+"jgo#GXH*.)+I_2AHM.[`6V`9*G7a$J9YMDGWiM+Sc!uY[j:nq[iGQ' %UqYYKeM;Rl1ehi,\nSUhBL2Lle>8:uqU4\hj4FX!*LMPEER5\V'('iPiJ5Ja=XK$.I`B_GA!k1;.3M$7jEr]U#PNP1E;Qefh3V#$ %&bsoFDdND4p?L1tX&jd63tmu;D>QPfr;JeS9,Q_c?iKlYIX?3C]/f\`rU]Yg:4E#*h`_#<c&9dAc_#^)i'3e3o#iu"O2%:cr9l;B %?e)o^d=5$AmXI:r`Q?qcrVkgQ/cRi$rpnrR^$5Rlk1t7Z[pT."p@dM%qP0C,H@,P^g[!$a]??i)dpKJsn%QKHIW9`1MZ<[FX508G %Ro^E8lg[OW5<,g<^NjJs2TG8W)l%1J:WMkQf5KPO^8>N8&([MFa6i!S\(>O>1Qu\"!TWQ[nb'lebMV/_rqG0Yf^BlM$mf38`ai,f %mcX6-mE7`\hHYG(XabR^j#1N0#M`,:op`!@]5R^kFoCf7?JU"NNOLX=DW&;)Tr,S,;6TS\Qf$W3^3[+WicXqZTl'Sqk3_R(o&"=< %^AIV=[uJ)2HF5q;=0M$Rq&:Sa4P5,\2r@ot?G*gok\7_[]7/`g[.->!(#JgQ5"r;4[Z)TcUXFYl=@W;aouR/Vp#=5EACa3lL96DA %LYL/6gWQY4Iet8^ZCOQp]IQ&:ih77flJKAQeb+.D?@3Kr0b52m0CBAarq"[jRg5S\S$2kdjmLBsDr/3S;&fK1k.WA<'@3YI_%.0g %?iK3YS's$N!n32_0R\"h;&RI@hqq\P5)N%g&t(XEG^^op.;iWR7u?IY1&W>(l(c1=PaFZ,&f`3p%lO?]`'b6e7\9IO`3_gel/+,M %^4(KQn`n`XDh!Y*^Gh:)S>>]JrM/8'V"%RDM=9ag-F1rX]mfS42j`E/?-r%)''Z,4npBodJ,&/qf9[!g]FA5))]o"i>jII3@Vk4B %n)&p;&$hiI\Hae]=O7ipnt92)qVU3%idU^ZjmMO/`U.a+Rd0*dngF*k2cm3>4F[Kpq*Ct"K1GX:Ek]GqNQls&alt?nB(1/ae,MNi %pi/Ags$&`^_#Cj!lZKnUIs?<IZfA+Z,Of^AXrk#<>V#J0gYH,lh#>LS^:dl(q31Dl4T*a"hVN^&Z+KpSGOb1P2WFP^%s^#QIDc'W %n))s6\pX/VA]7.$Zo@EbkB27FlLgX)8'GaQdqZf"FO^/Z&Q.E7,bAP7fV"Pgo.a'hEgQY!lHLD(Y3r.'+3CYa<32*!UJ=V!f,(nt %Dn^XFq.;.HiU=7Jci:OO_9o?'gR%sMF>`^fpnH"B4mWW+qFGip)X(r"%pn4s%"3NL\*S=*[t"?*hQ]/V9)n&i?dOScSZO?nYMRmJ %nWC$T[^_YoXT"pNpd_j8S;gbCEd329G;E`YU74j3b4lKePM+/*%WIX-p#Yq7f3`uRn`&\LgBoV/q#!^4GB<Z;[l;ntIsm.FCfi=H %Li2;fFsVF8/G\;jqI1suL\p/RLFLGJ[UIM^me5YZe_:=7n%uDj6s!m.n&OO=!X*3^hWR`]86\+ST/deCa=6sJajA)r:AFKOpu3Y_ %A8GcNG?>%j^:,%aqYc?LYlEb:<kJ^q^#sf,7M9VgP5+@FOT$=HNd)diq2sZm2r[R)l,OCNkBj\'8)l$/hF;D(K0$O8U[ahSfABk@ %ln2XO^3]C_Msn+LE]fNAhIi\@"MOc4:]J=m+IbCjq`Z-`\@W\?3W%%c]CTqo?G3q_rpoXVEq]j5s&[sBaSrDFB!V0$ephLG>5Q3D %^"SP;jPIs\HOUeZpNS15afYPd(U_XXG0\>>(b^APoH0--Yn7<8a\U_^0#<_g]oB,lraWbHGYh]`:@\?Zp\l&AIr8bfR+6O\Wh27< %JH,D`X/hT]/)EK=Jc+ZqqYFV0biRsdCde"Aj6cTl)Z?6tr.'.b_pSKKnW[(l?_,s+S!P4R];?"E+9%b!O$rG'"'m@0+!_La:\R`; %T3<cCG)u*nXPE5f2\5aQrquWXe`Fb>4?qSf=8.'NHi*C$&""u?ip5,ak`d1\C,R_O>eR]ErkZ/#?Et&Q,L`n`n+!8n/oDd)7(WBP %`Oh+7()ug:q+W.l*b:Kn1'\idLC%esH6X^4acaYE\Flaj)B2iVI7`IIZ79^E@JPkg.d].""eVJ-`)`3'8T#+22TC2fK@msd4C)%! %gPBG)=Foat[s92Z^7upk7\>[<4F%mVn"6d.`,6gNQ)F2")a=324$mcGpcl_0@OihhkQl1SZp#d+LlI3,7n8@G^'+`I(E66?4o))3 %$Gh,tUUQAns3Vf0_U/s)WuULr`9o![o;u8_Vd/hQXSq="KfJ5,H:#?BboGRfmInT4m[Gq:IV.o[WN68Yq^_TS*Y4;;r7stOW2J., %fZ;F3QrbhTAa)GR]OL%_2qPh$O;%,g!oG_Bg5l5.IMDUe5G_%<O%YhG&T-/FPNBIW\U4har=/5X<uY;"@nOcdJN=DlRn;JV,dot2 %2R4#e!d,bb#8=&ZgREOI4s(Mfg'H="60Zk5dUjQrV^$IJP,GFEViC0S)^%oq=c&3)4DioViI+DK)t=A^0@TPXk%aZsrG!S#EkEP; %re?YS*/1NNOGtg7a*C$9nh`M=QS3:F9e3K"1d-n@_$m7#MfC]cWW)X2>6"1_rHJ4t0BsWS[kYGUFnt)L6up$Aj5/nM;@9-g,f0jl %8W7XS-Ci]F;(eAU9]MKHV^H<$9K:'d3-W]b1?%kPn_N<GS)6>%\#s&N\GYLSec"%EJ+=VbJU`D,rEjK?#43dCZL/;bL,Q@IL\^[_ %6l%i!^]45oj``Yen#&o&_4BFk$@d<4OUB-):-#\PC[mW3oM&LRp>XIAC]:hf]0;nTj7Bt:)i:A:E[]f,B[d&AHrJ80POJ7bmF@\E %?XCJ"$E:V_`qb,P1J'DhBc@_YJZa`VhlY_id)4_en+5Vm>&5PqF>`[qYOPYJ5/-3LFppig8hfQ(?I<Tol939(p;a5K?XEd&qVp=4 %>?T-F5>Z'DEq`cq>2oJ=1i;;rEFV19/:U(Ap\@oBq(S#WEZDgGd(qnL.JGg&XV`XMofA+6b(&o&N`O<OUQtBl[Ne9mjYlhkBVjM$ %kWa,=j_q<9q<%)1bNG*rUe]qu!nl"L2BpM[bNnJ`^O>Y(gWRcA?dtQjq*f_<Y5Wb=`V3Fmf9^Ei\@m:[`QdehX*YS7+.m@kXiLBV %7u;`)0s-'3Ugl^.UO[G#OH'Cj;*at#!n)"il;#'>oDB2WjZWr;F*V'+n//#\DaXiq#/$[5s)[l(m3>L?c5W1-NVCI'0mfG7qa+E_ %D61](l+m%d]Xt-p\3o>*Hi$NcgqS51Q&gnM!q(iV@[:T5cYm,E7K,i*2YKVRa4o+%o;F7paFq,:pQKler3[/6[kXlTaPVnEq!u&? %?0/qAO4ooG=50I\("'Igl@kKU7r?FHgN(fPllEI.[cN-;kGW5X4_e2]g6VJBBHEHGYCBsD+'^!P.Z6J-[Jd>PU=UlhCaPV9;cFUI %O1lof":>qbRXb;5GEiJ]KZ7RRF4qT-h=Gs"->=\]A:NBiW*cPm\rCDEUjMn?U38a=g:XtQI.e_qa,p30ICZPbhYcp'lJ=J^,IuKs %9N:P8]=feKh(]Un47VZ5#fY\W4mjbmpfgno-\UJtAa&S%MZ4!rAK*Z):OUHqocucd*SV^7I=03r6^j$LANl9dCb%k;VNpr`d`QCm %p&$(5b1q3Y5.I<RQr<)=Qr<':Uj^9;m;9oS)cR<N-h0BOc5WIL#6[*fiL=al?Z+:ljDe8\L<!*AqY'L!L<e>IBV0eE:m&u(e9Ia> %Y(hBI=0T6/s8=?=r8V@FX\t-K#Siu]5&Ae&p//tT?[d@lioY1"4JDeb3N[tGUE"B?K8t!!Fp_Otje0k<1nUZc1iHmf:Q^:<1A%=] %FHhE<EmU\mhuh%d%oV8jOFFWt"l,ld&!Gf:N;`52Z2a4V`?TuRiinR8lYu_]I!b[FW5tTdBe,C_G^o6o9u'6B'1Yd4"uQF2H@,P^ %g[!$apP.-=e#hDN*k._Yjh4QRI!tP]o!c)ps8BBtKDV7k/S-(#k4[s!K<BIF2A/J.KC(&Uk2tX]D^9Zf%<WsZ5+G.%R/Z2;S]3D_ %92Bkpl!JnVoIlh&ns&n2&7i"0]H#ha?L6NR>lXfcC+GEef&M+XQ$4/Z+mrAU5DFU>*ac,iF[)^(DdWL;St>BmFq3>#<Wt_I[0>g[ %c0j=N?!TZWR9)=SEoV"1W>kX0=tXu&Z+o`47Qm\2fZJ=QNPTu*IlAAgpkU`4Q$#;<I+ZFQ*hDfZr=@q`oS7?;2A8l2e/j),g;ACG %Qi?-@)148'3mD1SF8/VBo\n8.dl68^n`b,ZT+AE@SI9r.(I*1onR7=RZY_80qtjT6A`QYZ[MZG.r^4=M2D^0l]Ib$Xr7-5K2NBQA %;.f\"AYr8FZEYDsl:6u*2A3b#,7.'`RE\TB3XSSOU$99o*/18bcu]tjN^D426ISC<^.4l2K0n$A@/Zu72Ep++[J(n.gY%BEb"]W@ %_#6_*Ugq4=k!E]F`IRi@n+Fp9SYcpHZ]Bsl2OH2V\(<Pt&"Ta1e"7'aNP:2/4R?prSLN@e)S^X/$K3pcL8=7k^O1HXZ26amS-jB0 %h8SgIc+AJYN+,hcoBBrd50m;V93:7)C<WgJa![b/Hp9[iR^30fDs1lJYP\?<Ub:>AXb?M6CFMH0ZJ/T?69*QP%b!n3U*$o5p8/0, %I\*;,VRGCm55dX%L2Z-JrD:aX?0t.Kf&"E*p-sIs8'^/[\o2(Fh2(sM]O-rn^O<_^YkWk9KR]s9o8YBQ@4]tfNl$pr3c\=6rjGi7 %o2F_U4u"AfBBES$rnYi"b=?M#)ke/Hj1]kH*uXg\5O9W8nk!Mu58i1f\VV;SE&X`'rk'lX[`YOug4!H@hsG8p\W54u[o63'$.[rm %_A>D4)Z3W:IG,Y:K3*:J6\"!.nAi"S,B)8DB(;[0CkI]?nL<3$AU;3l[[!ONi@3O(/,Y'uCb%l&hl#gCK^/r,akQKFHckc+]_eqP %kPoLZd!P-:0gWpI&sPMg)k5cch^_FCVj?(W.sA$j5>TC"P`d-[;p*D<^UpG(*f@_d/1l>H6_jZpW:7RP&\S)DZi)5,nA@1oCQHTO %Ee=Vd0Z?0qo`*b?0130&8PJB^DZ6Prn6gUkb[C^Y%8Gmnn"O=OJ</o/r*cA[r_kJkp1CU[6QQ`Q5MM!)nrsFXZ]/5TpC>%>">!n: %"hF_ag.Zh/Vr$HnEOnq$Ir1IZI_LhGT*@CCDtukSA=n1m[n!Y4@q`b\auUTZddfIj%dAJS]m05HRh(Tmn$d4BmJ^URp[^,.VDf;u %DroN\9@:\qqt$T4)rp0P1s4XAh_2*04\>Zs4@pXk,X!ZU_s'X&EmRtcp$jS]n?Wfm7^DXsA-N!2TBP0=h/6bI5:M0Po@"b:K)+Fk %:><At#6]<h/>2*GeK,_/$(p.r[RHq]@sPDo5DeLHr71K52V+Q6f,o2g*k$!?Xji;Ss,nV])>b)*Nhie9s,`s"S!h1q77[@/c-;0] %hHk$[<BO;%3W7suB>=<;0RWPsY?k>m&V:W=?iBudeK=+93![Bi^q[V]ld[NcLQgVFVg\',^3o\Gl^R4OgU@u+?bZO.3q\]qoN1]M %J,.j@g\O-a3#S=,.E']o=UHJ,s-`2&VNMVk:Wc?/T<U;QrtC,u55i[D8TQW_bIdV#r'0irs1:UI4,p/Q48j[/^Z"egFoNO2B4YE? %ZP;G?3p2(n<L2+#'jcXKos-u;QY5nHSe;g1c#LjWNRJRZSEa1R7,[to/9R?Cg20s?6u[HQQJ*pAe$G2FG>KYA:\3h#ESL&#:@bOZ %Cm[\>XJ@Vp\E9d990P7hbUq#E<5QQq>O'PO1.5h\(P\F1!K8I!V`EAjO\VgE7KUVCH)br=l!S")C>6*HcdFd"*c,[jnk<F35gCU, %iE9>R#0X?Cl>3;L\hui`GclCYdD7O"76XbHXME\-mnUTj*p3=20T<T%TmlC*G!(LEmDJ^8bV<T=0sAF`feQ@1"sM&;b<CSl9AM5V %a-b#Kp,X`r7PU3&)`c5;*PoTEVe8AQY(M#HrJd"i/CmOV8No&O3M6;=gX_W"]Y%Zt<m!O5b%2%anmnPK@@BY'5o=48A#Su*L#DGO %a,rSeQ\PO^Mp$m5^etCn.@?EIPdl@Vc=\,T^rsUXQG@fpP0@`I`m[$$)]LNj/Ch`$'DPJaEQXJt'qE0*3/t3L$D+#F\`bdWENp"N %a9OZTI7i'VRWQ&ZN3.`CN'VWm?6EC?\e-qMrE,"E2I]GS4=3373TWi!+\'[lQuZ"We.%W][F"X8["D8C:sNrA>PM<ZFMqj4lZpUM %I_>k876@HgAt%2KmI2[Y'<pbeW)jHG_5&;(osg;2aCpp'Ub1E[-1!5YC<(EHbP3UubG_>'W#9MbR;.4la;1IO"I<\/T!I]N)O#]X %dC-<gN'_FEP3Pc1ZX/K7N_cM'\;^9hZIH;BSL@>^WcrUDqc>Q@?Nie7(EL=iL=2V`=e6cEa_Q[@;Yi52r@+q&?"05Q2kkJ"VKqHF %:RsebLnVRrFh&hFn,?)Ej]NU4P(Pj\A1RHsUL*S<./<aU\^+h/E]o&uUf9G%oo-R`\-*sL'jbLD"bC1/!`fB;!2QqQi)l$TmmBim %^d4TK0OeRXl7:7flKuu]e\."6maO*ld['3NUo832h0f$!IA=YAb;Sio_#'L5+,,G#Q'rET2qK!+"spGF"Z_k0R]"S4GW?"O&b-^6 %TY"&#PPS@U2Pa^Smn5fKAZ.iYhP0kCKtm%_Xh#iH89t0NA`=/V5-_UW\Ph0=ktkk\Vg%PD?)E+#HP0)'6QO^Cp#HnaBH_-9HWes8 %/7XhF<?H>N/'oRaZ5d/?P)qq"lN$aTnGpI3DtZ:CCChi\@&ts.0FKik"-5LmBnrdjQBtGd%_>tT.CqoiWm;Qb:F3b31u'D'dR11( %-3dbc+jW3P;NdW6S;LXf:`l\<q_hGhcY`"6VO(p6A5iYjA^M$JF_Tt#oY/WArApr8o<G9!;!C3jTG!7",_6F5:GpDh:'\JGFKYE3 %9gf5DI"&0sUkP::,pZ-@!`iK*8eEc=UrtM/]haLK9:#H3VYX(P3HJK63KDh0Y]'j?;bXuO"B0P'UmX:eMThD<<d&-:LS,9NTubK: %q,u[sO?e7dGQ=_'-;<33W)$,?H:p'mZ\%j\a'mJ]*uB6dWIkn:^*Ih^_b:RA9l*EVl.%56RBq2sL90I)T$*OJXZ*j'IgU3J/5ROr %[:fefN.q"V3f(YFdKmb/;i%^r6A"MJ4#,2c];j<cb(,F3h(6_qN)crL7TR.X-%.J'=W,4NQ8V][=C9N'nqeMB+Nc=fIju&6%s+;L %Hi'6-(p"jD56B"PjG2<--H^5a%Sp+8;r>"rOIUR,`4s;,</GBmF93JQ@_G6Y]5jJ'^jA_VZ^cY?5dRO-EIM'3;QBA?q$Ed2dkpBp %'"pK81(U,i/(Ji3p5?*%+GV2hhG1C^\tL/M*3QA:rW!]qO#WYOjl]4t73]a9Pci:kSFj#o_?JMk4;Qe+<;/Qj-)!]^??lQ$]]]Xd %=Hlmf",P)VnEV`,<?>CoJV`CRFKOi?36A)<qOHe5.*V_=Yj1bJEB.WV(.al#3nI79CFW3>N/*p0l@aHI)bO`c`PmCKN%;_NVH$h5 %acnq:odU>";0T@*K@80fQR:2'_XMI)/>BpH;J4K*,`[lFXB9rfdqT=-H9*F9LgjY-VE7Esd?OhbK9Ob.i+V\t-mVt!4aO#<m?]+& %)*nqM`\`TQ8ODC!K"`XU(T$#_4s&AGqIF4:=Ga@J?M2DSp4D4*`<HrJB!e,l;9r[,!T9-flVJI>R;Ssi3Qqd7R;[=]2s]UbG3#(\ %/B%'5A)(?#&pNr1-eX8!2dt[CE15n:R?1G@E:O/a+?U[gfD54L-95q2<.LLYJOtOc_FgV;qh4H43/b+_!@4b.+>;nn/:?uDc^tu/ %V7`^"eE[2IM46,(8IDAK&JX@t(nBYF<0.EXJ0]6Zbj*X+LKrcJ5Up>k_bX9\F,HRNH4hS+Va\R_K`hst9pOq?&@7sg=ST/&e#JAA %*#[`KRASTT(e/pRQ;I(NOBaXt@o$s>.-jc$<?EFi(ZPP]q\'4J$tDFb=\_KK/JH<K<Dob#!LK<0Ad'PCWjn),TJ(B"b!O3]F."ai %lH@D_%f$n1huqWg:WtK=-5&hg^F+9JQiYH#5`q>\9_W2>mrQX'`Hp`Z"_+;P,P.oM<\@i)i`Wfu=Y1qVFcc9JNMGt^6W)6CWRSDK %r)#J7M$:/<SshWLH#1NXcXskRok4ZP'85P4%d6b,ojt=#HfDK0=sAe]eZP'k\TK)G!>%5@lWd?)BIh+WP*A<V&HQ2>H8U@_TZIsP %K*moQ$G$J#r#Z?J-AD/o%VQJO.<W=BQ,2L%9[(V/7BD83cYT1AHr>87/1u?eijXM2,3r)=M&jOH#a$!\/*"('kiS:W0k;6S.*ScS %`.C?`iL".i8=-51dsf'`I`",L);$\sEk^j*ZaCh:3U$:AZlfYl(:t]S?(C^CA4QS6V5Xl\GXl.uHpJ#`U+A+<_a(h<QVQ%VTq3-6 %V<B0m52]/)6taMRjlej9eHAP3Z06h<</MO9U^FA(/dm;Ah(g93WhiNOK;.VC<a]&GJ>Pe=AEe=APA9"?D4-&m.\1/r-C.6gA=9>[ %=4WSEO/H2k#4%Zm+c5jP8uHfq7"n2[g#S3J'ZDkfMZcCm"F0t\1Lkg9KL6tQ:rK>7_,'"3nEP`_X:.Q0Nk,k.7?eF\<oNe=c4Rfa %kKpXCRgXH_2"oaX0j4gmnAja?`Yl(#@]`0a`:[`##.)T%A6qWdCe:W<-EdbJ0kadI\YM1+6#KC[EAJ\_k/ZJS6dX"EN)pjJ?@A,n %'J,/?Ne)*;:73s$5_REn;%lo*?d%1'1aIlBU?\O3XJ]#Xin@U;&S,X>IcVGLAu9&p5gg1CKd'r:Xs/h1`!`.Z;E6.`7-sZ`HUFj5 %o-3=B8pUs\PU_rKMh[\?227j,5&ol!#k\9LaB#%VcOhf3=OL;Yn\QIY&NZ(<\R0qE%VR"+/b_=q4EqUDI<-4RC_(g)%#]!uK^t2E %4,MHj+1u;'fk_4.JP?ISMe[r[dL^P3qHWM7!7_S*,%Jqg)+(>KB*P&%.YC,n`HiEd8`/ciNHQ6JQBi$rYBLiLHLn'J1&97\:7Xop %FHTeD0D)c3E(Mg<0Sr3.Lc7:p,nu^q<N<*9<Z6r0.T]=4;+=EXiHWX65"=>!Wm&K*i(Qa@b:j,(lgM(^7)Ns]lXE8M)!&b)epsjO %P6D_9.>g(tL$N!:aVp-&+=i2j?k@<bp])TP<=0^f?0J7*oeP-IM)d(J33,4ic>"jRE"Z3/oF\*S-I#%D%5NH[#SJZ/=EuZYlB=1Y %ej7cr`'qc6=<D'"h?n9.,AA<So5nj8cA#2?&_d3;_&S@"ii"dect/^Kh?qa3eB8nD%JWg58A`$DjE6[(TPI)e4]VN^`^AIW@8`dP %"?H#Lg,d[E%AM!L8En6R'kX!%\JLH.'XiqY-&VUo(8F_XAG(X&9mA=(.L;%*W,cKc>:'sWZraM'i(]CI^mrH&jNR@?$#7aqmJ+mF %@!ud`<?R$$*^YC%oR_rpXmJG)Dq9GXVt'E)'bH?^Z-i6sR2,rqd7BQBR9=Bgq!"sp"nZDbl*?*K/AbuJSu4T!kKbIeg2frXTh*P[ %_'I/DOq&fV>2B&OX;:220Pt!U2c@F6KUh*YOhaJm[5"R;7hK'q.ALf5&8##dTgD78gR7koL"(s"`[\GO5b1Gb]eTrXTgWauD\ei" %7&Z[]]UCXUJV(2.">>t]+tPn`3(/labudZQWd9#hX\1t\W3*e<"Aer_&m,s].&b/BB`R`n+:3r]!g6@am6Gs&8fm9?UP"rWXMU49 %!<g7Na"g[H$<N[4JsV(S5)]O#l55@hMWUdsiN/+4980]i7-,f8^-7\L?TJ\$p!E5,*<8saBn8*-qXUS<1lXr"8%#<PaS$6,[)u7M %c;R_2[7`0OanP*ZLfTfnQm0o-M2<[D`m4lqp;W+O*@*d>PA1B!D9B2&Y!,5g9QmiO>=]'iLmqG,%1BgH+s--TSh=fK?r3P`S/+Yu %D$9AQAmeGd/eZL:!1]g9Cbl\8@O=5k;c"/p?6UFY`3I:!'#4=-$D`kWg5-5Y?iXi1)=aZ"(8/]O`LA@)lEqkV@6b(9!7"8$8P,LB %(os=^M<Q#e=U7fX7@@IFVFK!b4`GKu,&9g:M!B1#4^,2Ij^aq-@],A(TY$S'3<[MVP'TfFg*4ThkmH(9.D&m#K.A090ikC>>Y0)S %eRSRU+R4T*%gQMH$>D"bd4r^*,cs3cn9!0\j:e@5$`\5Ke1*^QjYA7/WTPQB?>974Q4E+uQ=kRdTn+Ca70V98PY!qZQutq&K5=UC %A#<aIlh+p$_B4p:@p3iYl]\:1<Vc[+SBi\,dlrBiZ:(;G!_adTb1B.&_kcg(H8C^4P8.V>XV1RF'P)'u3?F/"FJ%r!_=:4a(dd+] %_b`Kom-B<"X41HFLqL*Cd%)_bGhBc^qP&^:'se1OPq3U9Gc>a/&PUp)"`"rT%U;[07'E[S^!s<4r_*F4dm?MY\XI"`-FF>-&:u^t %3FXmNhd]PSW.84\'m7G'!sY<j=`-,PD:-EI]lE58,n];U^-YH^fRKcsaXep*97#8/r%N19kGj;JWC>m]OMn&S$tt96Sp8QS=-,#? %s*=1--U7LnQbU+[dlG)>m&Ro!ht=b`q/-)6Zb%3L?Lf0JFFB<)%WQr\d2h4_L1rcqh+UuojDZG55/cRLB4$'cs$IQE*mVJQPA\Z3 %hFuRk"8p38Mh=.5XG]UEO@ebj]ZBTY"8p5NHd;'MD8O:4jP@a[*9Q.3i>pj?AmIOT.h,cHc7_mq+68iE/e7AFZd%>#QdX,Ab[ZOB %365`)#'#`gRWS(%2`5;tOJA7\bTX-(D-p<R:bQZO%WHu^?$X!pPV23//o/nS+\lh$_dhNRV"GmkCY4`H\us_`P%pSKVQ/eE_Rs]7 %-nJNj+4Q!R:QbZaY''%W=R3N*<h87,#L@NL_@bVga<lBraH_as36[db]%D4>'Dru.2X03$QSpDNe",3gLP+C9\;S6EgUN/o>hccD %_joKBFrfZ##"!fiK:@tjK3[2jMg`1#S$<T%GB:)\n#;=bGe3WSh;f(O3P3CQ3Q0__#O^gdDt\iIb2l@3GC\-]<p]mr2qcW3*8fgb %*T[&$$1e/[2j"sgEds9**pWe2+nYgO3:>c[-TLAM+?)9Ja?bi*OSSWUiRWL'JhnD-oE3n-A/#8/`(:c#\AZKE+64+`RsgB&*-ZCi %@iT]4OD>j1E0,.2oPfn=*-ZCiK:I%'OGb*&EL;r[m)MD0EcSAoEg2b?*pY:'Qf53pEp3B#G<*n:!/ET!iZORJUEWKXRKG-'^hjPl %p&U1p?tl8$3X=d2!R>b2)%LVX1JQ6F*U(j=/n2W?@TsF62i1$.\^4'gEkg6XIu%US+7tgDJ%0&diB<6S8D\]rF^WH)EioKpG^t,] %ZmQ)<fEkK(Ll3;+l9-LVP7X>RB#e34j_-%$mNZ$)UmK+_gI^_O]%]gBV`W\Aom;Y@S[:Pukmf2M"5N<<L3^Aj*A6j_Y'7C,:NsO: %`B;6?%d3E`#<^E4*9;\V(#8mcGbW,;a:1q0OTTEMG<+^**tE>3K0eMtLHOh\&=5LAVGDEYK-'h`a#s:Y!7s>q3t?;VP:d>bc]]C[ %ER9mj%W]r1G5WO24`k[oS"=_AOJ<jl`<!,fG3\L9f>A]%m]\(&4NM)0\i@K>:HEa3gR^"CP9'DOe\8qH:]><hqk!G!O9;*\_$@O? %M(!h7';'AdJ/b,^`$(.g\5H+Fjb%=1l-=Z9D?m]C8J_UloLTipG3P3_+6:paO3Q/0qQLG73;2%U^!!qsZ[B?2+5W,-48>4EjlnCH %d-Vh2j9Nrp!H*@ld,aB!SGrGY:B0n"lG*>o*k/mMF66>K\^MQFS::A#`Tc],0>>%\IE<@9Io0Eu;?'Sps'Pc/qHr#9r:/dkS'0Pf %IsCkQqWcVmDf9O.r9j:<h;tbSD]cIdGETN)Na-bB^4(ESqR`6On%QL"ZIrq9),=pZ`A$QV]jK4!8t9#J4Qhi#\l#f\7+D8lS;ULM %,!EHS^LpFqPKcXO&.tlJA3,bo[=PjgJshf90JL7,?reLj,l>5>,u;L/SgH@jf@.g-KYVn1``^&`a[T-hD8!'JFHD_q-$Ti-aKIG4 %*eVR_C^kEgk8L4q-750H*g2D*KuN9PigMX)4s`Q.cS&2/N7pQ-iY#)f5t6*]8b8a82Zd-jm_L/4"%]Cg+1580OqQIU'dYQ6&48%g %O!mDie'c&8#FPp3nc0=WQ;QDR*lBYu`3+"=*)u;!bjdBUAlVH_C3aC"1FTjrOHc?(JU"q%>91MXc4CBgEMd3kT;4YLbT9keOTk`L %=\g$^?qT]V2%*4#k2R$r$^6s0YU8-`lc7(Z#K%bQn2h(sAaPGLZ[@XD:K/,qQ<j]abhoWs^<#Y=iIEd&7o<*GP2>=YMHZQTcAR8t %%4s^[RhaSL/0pE(QX&$a%k"L^=hf`*YAo+p0H75qN/YVb/5?-`@@JRtg5II7djgmQ/36`67<_tP6!`SC3`'_tnmOm$)"L7'QE4pH %a<o:E1,pk,g]JeW%Wno`$fFUS:r,^Eo3#>q'MQBZOcRkB.:h*Em9kKC=aYF-\oC\.b`&H\Ctc.j4_,S2THq3U.m1)/1Vnu%,%4%H %AbOtbK5=)qYh5]#?j12Jg^^1fV?+V(NMrV+`m-C$HZB*)1Rs`2<'';P8br0pZsD)_TmD<.SrGuDL8(!a)&=ne#KTb!WrnWYNehVQ %:(Kia^j0&QhDt-\bHa8jM[FJ6Ao\9e&O]c>3ZZ2Z.\c1UC^B^[b;A4sVY5@ZENK14`F^6Af`VLBRu9>ZZ^QHp=Q^Us3/AXVrE`5M %\WqkOXn&gPIqa!R1e`Ac;798jYm3Q7q*?200sU]Jm5:MVE]Q<QEX?@;RI2[OZj,NQ`.<"G^?1Aks/\uYVhZq,`)=ANRD[HT=(2U& %3L`F2'p^P3D_^e*FPBu,TR_Zb*o[k)+MJR?^'U`60DQ@3[?;@C;Z$cR#Na!+neGM+H2.b?0rUF'S"Jg:d39,K]R']Tl6!lH!EJZo %@>_]Q`ea)EZK:)`-VA"5k/E`-c40o]RRFeLkgl;?4rO.b.(fb0YL]@0r<2:-NY%-<6o$<:&n4])1B]>i"1G0(!5YM\0WU,UOJC&Y %MM"'[BZI%l^r`U4!?Q#1MO[G%KnFeI<R.BXb]3o%=CQ_+"94HeW0Fg3Z:[$42MFU^MA@mr\@Qt1WZ'=r3`87Z1/DV(1uWde.S.c> %!`nM=Wm7H^q_-m+6>V&UQP&6tXP4/s&IU'%ZuNsl&/`?"JOhWN:Nq+bpu!sP-gZdt03#3uH:BoG`8$25RbfZC%!I%Y(+Jk)SV!s- %F&Z:dN[!Wh1+!81<OY-%XRJ/\q,R*^`8%?`a!<4Q]+]m0!skJfCWjO<$jr38#4i!"0^FkIFgN9-p#(dmb"5#ZW9!IkRZ*?Ih3R06 %3hKfd(",LSHGU>_`UfI]D"D&XV=rm0)0-i4WcC,!1=Z8Y`,C[1+eb@^,6>,BTpEogiFu>&;+r\'f,pt8P1a1Cd:p9f[b)$0+\%Y+ %J==90$BGR:"_KGuWttg;KaJbMP@EZT4?,fQ:,)D_b*k([#]hNS]SPIpRiO=FUk4f/"U3+I%%*4ajKa@L9!M(6X!k-<Po!5PTm:R\ %ooq^^M]!-%:<-0JJODO,d2Gj*ME(+2hG-GH(0K*bP/gQ8IarY,"X\h6Z'5j!LHDJ<?bg)^eP%/=2%kWi%EM(SZ3Q,3i^BkD'ANm0 %dViZDLkN%(5-IC;NDc(c09<_!jeVTP8AI5!+,)/E7mkD>K1V):C5!'/M^&(p?:-aWl98#AXL]+05`4&/m(%XFUi/!bilW^'^Q!d1 %/L\&0Os6_)'#Fi4W2O2^kt:N>[e`E4V$LVDY#qdIWtQK^&jf-+Mg@aLd(GS>71kZIn+cr;kWpO4\t^GjjC]HA_KT2=HIN=R?+jBk %aR!Vs%f""C(Edm:;_W9[?(O:iB>3UC<D]SV5Vt!LGfqeb4S'FPUIsS`T@kcU.0RqtGY5pO+sgU<U4m&Y>US3m29Ct(k6]g110?/V %PEKmKo(+,5n;OX\oU357AiYTC4OaKB=[#6R?KB5q@+@Y&+c\g:5m:5;r%q%0&sCVG^9YVn1GuM9"f@_&`@^A64X(+#n"Ru_bUk") %/2(p6_Ysqa$j5As3#0p"`W&&_0AW^VR$'5)e<Y4d4_SXe?!hSr8G"*%QJa/er#-km^'+p".k(fThNJV]Yj(NGJpal26s84J'CQSk %*(8`%TECk^0`DcsOF`ko0MA!MlkGRO;0591[kkIo0-Yqo&XecJ/1ttp`?AXupt.9(9SGN(N+S]V34.)I06+757@<%Q5,D,Aan6@4 %IT#ju[;<(CA.!^rl00h#d4/VLB9!$ZKBs/ZW2XW=AuN7R4.!q&BC%=fek5K4T#I3@ZT&1Kp(MbXqOi1;6+4oK>AGH[>GZX-cc?0P %e0;iJ:(`0ofg/R?R)F>X5[j!2h;&_)8)dL*#/KfT&4dS[X:]Ymr&A2_+?Pd#+S3tN&@(CT_i(b!o<d^6YX3&cTGFj%Q)K9LZVTAm %A=iJe*JK*>K&R>5R_#T#T1Rkm=:!B+^#)`K3-cSWT>X/ekUI+=L7gjXbVPE-377b"Un_BHk)g@c_PjH^"sVhqKe&3H$&hAt?eg!P %i].0oUYJ5q'@;;]FZ2.'<C*j^$UsHagGX!bqUgF/"BS%!OoqKo>n>),%_loaG<4D46\B,j.3)MT28dt)fI$t2E>tQejiGi&JCeXZ %8-$W3?m%L,YPl1P"5O5$36kG9\])+T)Ze?'=`2jWXO00610'&O,'iql(=lHg6'uZ!g"guhD6NZE*^PAJcEBOCZ4abpRd":U6.RH) %%ZO=76Gjl4_,s6ZA.[E\82-\"*c)'+,F<pilO@MZgI`3b,C]>I9umL,*!"aAanI&)LpEPI?m.nUp_P;4COUl>i4eq.T>j*rG[;.G %`i`\>1<Jho^g:\5CU`T%?+?#a_GL*B183Sj-j\1<Ib*"'bk1S!-?X)[K>[LVhc=se>%*9HpR=]368>;nRtYd[0lt^t?kJPM)uA6b %-I5'N5p4no0JP+F6N!Y:L1hd:lQCMm79cu&S2#R=Tb5@#kO21B/k1]flURVV%'Pa9h>B%ka[V2VW?u!'5a,9&?ij@4UY_G9q<bKF %6*NU$2_6`f1c5[*%p=I-Y#EDV\J\)EkLPPtUUWKZK35"T?C2W#ZfA(Q+MrIaWkf#6m8I:`4S0]Di@BZ1hpq;#*q/s6%D=&Lkshgf %q!QaL%3&a&6eKD@jJuqFp5KcY6Ybes_:+XBUZ<B*#19E%k9k]4![F#Ce]lb,c7Z(p8R1-F(BnbBWt*(2W3p;];>Q>:!2dRaItMek %q]g&f)_6R(rUiOmh1=u[$"Gn**AlD<lTq*pmQ(hc5u=[JIgUXSZ6"X6gH\ut#'O^P>/+34c1M/po3>4P)L/t7XnMVo^#HU7qjc*' %/s+7m0Eps:+F6c!X.QRJG,<N+?I;7"5s(an'$$c`;_$qI,P7#e"c4t]pDP>``/6HnNfGlcY//IOSH)EZfNp_(6PQS/Iig%8l1DH) %''hA*)>\SuP+hsIcEWB-2R\pX=P%`pHg3"O[X:i06M[-69X*XAUs^?[HSbkqkIc89juVt*VYVa#/RM_Rf8nlY!\=_"lkY]A:qC<u %'7G)8K.3aUd[k^bF+e4+('G1$l;jRjRf'mkGuiOCVT?/^>ce*ns2"d*/VUAC(;ZF:;q)Q$[2fM9^Bb5sC!/VHANH2)lSZ1G\m,[i %f@(VZ05\NpNE]Y?gfD3n*'qq%3e6bFI;D`ToKD,I":]N!^rJKTA`o9+@>BSNJ=+=3;/Dg_Nidrob_k.B^MAp$nGQZt/5:I\HVcA* %2r/XsqmHsPF?@iDfD!H.m@upf8oinoNm_&XFu?g=?`<.(_;m(;`C9S+,:C-eRYG2mSNslWoWjR5TMc`[&<NW..H7`s8\QN#^.6UK %;+#jp3,t1?KJGFH)l:=e@0[(JRPW!sQ>*2qN%0PoW:<9Gi$+JAM>#DnW[9"_Mn%`FRW+7kl;>8Z+jAN:*]Z,F+A2_JO=Pp!!2TOS %T@<b2e?Y1d?GLi[=Na838n=6&>$;*]b1d2c$\<:0Kk_<",2b;76<.%&]9>)liZ)#A;baNIK=I/=-$PFeAE.X/Ar_RSo9L=]#;.=3 %.A1%u.\Eta&aLE`rGr_9U8W/k<LE!BZ_kr%=?mAi^E7!_Z?20>-^.$0>]\i`^cj%cN:?<(4,@?MDBG'W=Hc/*pL>&jfZt>-TQ-1\ %U<n#OdP&.9Z`tAE+K>,$P"R3pgE)5<'FcI)^=AH7-[hGX4*I@%oe<I@BiYE"$EVi23tNFffbWlOG4=g7=lal2jAV75Tu4%`.9h*f %qPT]dlCU)J89FPuN71sCT/@u0TeJ5^o70p<j6(IKG:./?(8B)`J077@)*^Bj##HUd(+9G`SAY^^2a8\qY"T&b_uk5n_Wcsh`%j@5 %_X:qD(H%@9d+KC$fLhPoe2BjVSq-/lh`u8`@u0iZ<WfVg3(nu.-ZNcf#HdA;R3B3pAJE>@41.muOF_?)^e"S0f-!:60QF&MK7#,) %+*bN*]ML/Xg7HN-!`NM<VJ#%YR=aM3@[+s,e]&0H1F?766VRR^L(oTKQIuu)Ru+55X[lM3i13,&blQlN%2(-=6-s?X8eh%:/-hEf %!]#B]#T@#G,--@LoW\VZlPRb:`16_`cU2Ydf`[Hu*lI\^^'#Jk[tWY\9GN[M`1+-.q6n9H!BLogS)KLm#*9s#oq4?poUrb*\;?Je %f%RQeV2-?q\([ZL;TE(X2oMMFLplU883+Q:;pi"C`@//VEB=Z7L[<'3ME&><R8"n,Ajh3\ZUT5Y1dn_l98]>jTiG01Y\J@:'e#!. %Qo^<r5'D6X;A_5M9prD4NB7Pl6=o4Z,Qhur#'"qV80OgNY_T[7-ORL_?D3M6]>7@/O8BqKRc;SCUDWV"@4@!BPSh]@jjnHF0L:3B %K8ni)qo&S$F6]q:"aNQHQmSHMQ>m+?^H:(aV&iTs.KVX(Z%;,3Y)J+-ipA!!XMg*^Z^S2Ic<<:SgjT^qE(AZ]E<<:EmiEJukKBsk %f?Dn$^o>:F1m$q%l[XEP(oA`;JW.[(-Mb:'@U;X)KE->AE0iF6A@8)!ELDd$)GN_0<:pX<m.==l:2EV<3Tp6c$1-bAZt/QOY,5XQ %&D>PgI9Y5;8^"3Ha<We$bdJK`m.=:g>@(niE)a;9T]@rpFIWK3:.NKnl+tf#MJjU@Tk&9kSLHkG@[:_"k0Ogl'LYkZ*Mq6[;n1)N %eh=EUaKecj,YT+j&=$V!LfCd)2NWO!B*:hG+<#IN[:NXkF+lJ;2mc!T,)c)(%R&8b_/-2'@\+S<[^N8=P((NeSe7J:et5$?k5BO) %"gl_b-T.8DipSL-0aSd:=suX-CkJKP$)<+WX'1:E>f'g<k(&)P&g&@eqqQCg$CJFqi"iT#1("`j,raR$JXjPl%:Tna>d(7IJnYgl %UkENLj?($ecId2(;KhjQ,P#iA_S!@iR)18f/*A9q(f\%t&okVe0sB-<`AX1Add9@W8eEH`-d=KcTjuJ#8=qDieC]T>Z5>;k#Dc&& %i_i2]Z+19d0]126BK+UsB!-,NB)SiMrpN;u)C\Jo*H5,%(WTHg$.9ZZSUj$4([`gU^9(;8kFOr,6,6F)Nog@A*BcHSe]a\tJ'd#; %(E"A\Y,uEe4b6UM3p83;nHeRuhmU3'NPb#!Z$oIQ8W`-B5Ni"_a0GcY)L3An,1it"pS-L.(Y,+qD!mtiU.Lr>ADU?3,(A25C>FGf %W`o]\Js(06E_n;7gGd_@H`AO)8#>4r[V$B&1,iEbc^BFu^1G*cKR8/tZA,,hj#YQ^V$<r@gA,%[`^\e5_**fpG<3Dp:uhI:(RF,R %g*q)tpnVS<S0e\*T!8SBo-?@Tn<\+TT1g?YfQg(^&S<_q.q_%Z(/tA(=_+lKboP8cX<L":/*?kJ,rmNFTuRU86-/>8[V_UoGChW@ %!I?`g\DNTW+/)fHb=T!JOD()MV,G`V[Cu'?P!6\M=/)GsAS7R$l,:%s69EbmA!9i^n7_ASAAtlMbZ1&Di\TLSgGXns".Spu6,m5/ %^=2n"hbb-/>NHPPX3WEE(=I]CQI1n,]/H1u3inbS`&,l?,b-l7m=h(^.L;pSC"(3mB'7fR3q>7#8<VSkOD8j*q@02j=m1#IR%<Tl %_4$"c#>=AJD`GP?HK\,k;W9CW2)_>ZN\""!RBl1[]S:^67=]grf/(W*4*V3<$G<6ARugpgLHB)(^(9kM^\!E#oX`4-]s(QZgX<p/ %hVEDPJ`#iMI^aCoSR1OSGcWj#p)TT>f7DKbBo;JPlG(f"5Sq[377q^E"`;tB!r&5QGA9LT_a0n]*3pIuiiE?B60g.c'nbCrS_>DM %j)K"G5la'!O:&<@$?)5pSJk3^H!5oSA6D!($OoF>JgGHtk]9KYS:VTTV1XA)U&JQ.V"=#j]taf=Y3l^=ctmg\51<2,\hIpS='I=j %cg&;X;/71o0JlRL#%[(ijNt^`JK=j&R,-V>W`P#u;+mU)J7/9"fJk'nW&mOLD*[[dE=to4RT"7M@J'%lB.\7<d>3I736JJ@MUSoH %$hP"7k[jMNCh;lh>7Lh`%7()(OBLMeTU<@OB/8ae^oT(pMFh;u@,IYW3L]J-M2$DmL^'e6qbW#1M$*>bC]b>rpfdl`FTD3^?JfJO %/-V"'+?@'[<p"F5"Jcht74!^iG]78D+D1q_6!0mC0UP*jXG8&9GD7Kr8&lA7-8$YND[Sl:)X?Ud^MBl'Kn*'sb2*h=n6(sdG4,r] %C(aN?`n4/[!o+adKaufEfR\8JpO*gq!Fi50J;]C0j7.(\TpG$H;$QTAQp[FL\j!K,dj`%2=RFC_-&<"pN4,$ob(DU4*_o$CcD4uQ %8BMtV8b^gi%kDh-PY$j9K:6j@IIa$CFeiVPJ]c-Vc[uu@j5A9MCG,Al/-:q8E)'JX/dETANW]Y#2gZ+.;=Ju+o`\[Y'G/@='?)#i %r1*pIHkF7LecBgO0Sj,[;8r.X!C5mWe1u3s6#9&GeZt]M)thF,A5[!#"70n'/130>-<c"Sm+e*KYZk'Ka3/&W,QP.RdfIp*UEuU$ %eqc5:D?RmYN=(;\V>s<OYrf0\r^MG$-YjQuLa`d;(psGr3B*s)&2D?F!6/$RWd.7lTIc8:+/rHFi]FL?C;dn/29NLgF_rAj^CRkm %1tkOU`@!oeQi2u94d4r=a_sG*UFM/cj)V1L/MGD!>>e1(]N_LE1PjJYdL?'aS<2\3+:`o9-K@(+I1J:;J(2^-aBm=V<@L]J0Yp/q %`2FDF)-%qNM$OS!(<LK\X:Xt$#hFrtWQgSCLa%A5%*:+%+>4/Og'\]lZ150.eG<PEge3lc?TtmpU4WYGTN*&?WfA,?>)F0XCLUC_ %:8Epg0NsK:QAK@*$%SCm%T+`#fj.8AWq7O?>X\X:g4<jr@@sq.*@M_/5oW*&C=&h#*@,1Lp)imC@4.tQ'<5eDg&(\X%C;mYh5^W^ %Y7.--^q&9E9-@1n!c`qY^LRP5Rm(N7+>2@^gcgN(L^mImg7/.E*GDi:@cip0@kajd4O%'tWc^!Wo2l6%#KbL0Rl*QWbP+DC\nSPY %etdtI#K]kR0,_CCM7lu:,R8)b?,*V%3Cu))'im:`aFn+SX-NsJWgP$H5Wa_#KYf`E$-<RKS*E8K$ZmLe!$-%TrP!mj$2usZUm:Be %FepFk.hF"tkMflt7RV>MRU<VcA:-gga/M)N'ZWJ=+3YX>^+K#in?-JS0LW`;^.a34[2^H$"N6rE`i5ZX=2IgU;km*/<]S*DX?nmE %8$d:(JBMBodRci)S$WG/FOj#W/,.[#>@!')Ns;B5qb/IC"[CDfQdkjf$;@[eM`G*9Ua&YC\P"BhaD&]5"1YVrCi(#Ro@AelB3`JY %eUL=hT^p&XSAUG*T`^^ST:`2nGcc*2X-j)iX^i6K:SisOe4ahD>?Z`KVL.=0k&@25Y()A7B9_JQ#]6Gb.c[>=K9k#81bUBpp8!>_ %1m!>XHp9huG6*hIR1L01gTS'_%LdO3./S:]7iX%)b8+*lG+Oji'NVEP!XfWQq85r6k1,19I&T-"qk=olna_$!l8,Fa!!Zd[7kP-2 %ZkZCf\NmiY%N9.@^KUp`3/pRMTWA.T4q+I7J6%YErf1d7>,kl/3F09UKeddBikVFOTsA3*bF,sp-&NSi'mXQ6(X=*IM4U2/M@5Q- %:e@WUM9DU=:e>Y"FF^g"XaA?t<>,I^`YiR":7qh:1'[kC57r-t_sBS]>iBL6.Fj^r\1C5%LoT""F?*Ug@QiZqQM%rohq!tN-7%%B %L^lD(Eo/dM0Mi9phQX]r[33c?=.OB`(%plO^NrWbP[eka6'd8r/rX,S.c;_c]mU-4T3>%,SXP5u4s"OPcum\ndZeu]]1l00[FbP1 %C(rcp=i3.OJ995Rf-%%=k0Ah@TA-N$#20?]kYDP4M`@)r\9;i)#MU)C(CoL]V%)3o#:b`/Jbc`l?ql!n54.Q!9,_f89+cn-V%`$0 %oa9-dlMH-YJ0m,*FmoCPWml+W+K2$IBilAV\d*&kJe!Mneq&k8[SJ?^SjM$E[*B7a8p>sH(Isl4gi^t/,OOQ9Ph0i+h_CUP56ibZ %UH>,$jM;r#Xt:-^dJG!GXhb$T+1&D.Mf*LO_Ei3Xi")!QJT';78&#01EaH4Y:m8LS:c8(C-iNT-]jbd%AEDN*NAu3Vb]r^/)XB)t %)mkr/62\I5i)q)QN,)C,;_:@XbKNHF4:LgfgO8CX"$P,f_)>I-7a2;,5,BA=!A:UjDVIG?kpn-4QjmsJBWR#&`f06QS6na*bFV?` %AdI,bl][?O!k\`2^@+<fo^DMM2,;\Sb]^bMO%iO@bd4n#jZ-=*fB&NLfqDmsSYi"D(KhfeP*Fc]Q5"<U]9>*gU&buQ6-KQ!Z?on< %ESB`Lo%HM6S^[_tZd3i*0sn,C<,Lo+O6Wh7)#_r^0KVJ5RHYMpMA!pY-[lcOKIe.Bk@Sd#&29!(fSQu*bS_];=nk-EkliS[JQRPd %F.K\7;'b?j4eHcD9&'Y\=IS"@r1k:!q\UV5/n<S(_RM.#8Zq14V^/=,Q1C+QZnC,(I3>`0:'K#b7H``RfgXqj=[*qd)H<gpF@-M' %<1AP4FL'L0(JCVb\J37.4<g=?q8l/b2034mhU[sHfqV`<[K!c>27jtrF>-5[bKP6$G&PXFfQVjAFW+jV!hS#T!s>$19RC'G#J7DE %SW;HWlrJfMTGqrFfG'Q%lH"rmBW4=F(qLlgN-'4a>?N`KRrYLm#G'<TA`Zl='W85eW$r/D+EX7]"qb-]1f]NfCO^Moi^>>XJ^.Z0 %33qCpN/XZ6/;o^s/Tl$Z^+:\X#4J[\/(c;Zm5DP3.!KGf:%+$'J'QNd[4Nt9^TBj>_;o"U6+^Q#K0;<0\3#];@hEE.*:^QMC`P?) %LGRM6blOq^3Ep+pLYB0c1dVLf79#i*U?T(5Y79hf&Bnb8[8jW!++_*`A4K`e<'&[_TG>(T2mNP=CkWJ.J[n5!kK8"q(<09!#9-N_ %^Md/fp,%A!6Oh]+'NKNqUJ_cg]D`\E_#!obb"9!X:ftM18iu_h:6L2GK-lEYZ0B9dhDY+i/%Aacs1UEuJm>"(YQC#u<UOoei(re# %=dir!GSY6W%98D"A$$B$L[;?O5JW_U$ILk237,8LG&U@6S)[\AB4&\'QSLBuG3.I++<m0X'QLa;8I(=4@!M*%%'h2qEeY80l59@\ %OlD>=T,'-Kj:![k\[H^49iP#0/Lkm[S"p/TV64C7JfO/f?;NqILe_a@'F'I'#4,`]MG.I:(X[kQ&PXtPMeF@)EfLI"OBjOAFhI>j %NGf1hVlj)KC\bF,@qaU+$_L<.]7@i_mUN[5?@$>kaZHkQYR+;NKR8d_]h<3@Z[8AqR87^a<D7NGTAm8Sep%dN6e-$dh3'dgokd_O %*>g)eGW8a;d4!&^/\]jm>Gp);^,_-6d[R*$f=TSNQn;UIHYT!r]-I;iDVUeaiN1"0R_\!dTT,6%bc"5IEsBt1@C6r'#-&OWlqM9\ %El'aHKu>!]j9)b0J#")Ihh1Ca_G%DXIs-t7Nq7=M?js.*[E1o4%a9%q:m^MFP;Sk7N?8S1"\Q:5XmGlA-sbTIHb*N&\4DI824s1- %ENb"=-iGN:")HiUB@^HYE-.jt+I5m@2$`R9jDAVb&U1jf*;FCt:q(6CmYGX_E),fcJ?sahP,VuCqZM)bZ29GY&FMTPfW]W-mSgVk %9oq*__Ljc&4d"o!Ssh9j5s6,n.a7h"E)kSSTd,&D9,#a:V0"F**X8t"JKWZ!"\Y2sA9)eLJhEo^?3hA%TPk/*KhFhoi[ZS@iBGTl %>t"FY=`t^ADfBl819)2gd/9EG[`iJK<u>?VNS3M\BQ.6.K\,p\Q<d6rEr`*N\5Mk6q2`.h7G^!i?]`,Zc5,G\/@>mVFkg.aX\6N" %S>Q'(3X`2#RnuK*=dS<nVnhTOZE[6s7g5r@dZSsfr)#*(ed2;N0"Dc7</c+Q[Ul:MfqUUTCnj19_Zb]]=o:.5BF\\3oi\Y,L]q@! %L+O9?%kdFJl[Xjt,IJ;]&M#iANQ4c0V[RW,Zom^/9'JYa+[M&[-pAnG7PId6Y@Z7mo(0b^<kZd^H?#2nc,6st*d#(>Gf?(p$)VBI %#N#ot5aSX+(?j2SeH-9\FSV5M5g_m`f+,,/!J>mY)m/d[cP5f;DN!h#D;1Ag7;N:h])1+m_R5aH#J)@/Ydnb`Ibj.JkWQ,q5t`6M %Fl;$Fa.Ap)>MC"KD<Sbp_B<dJllJ&Wdlq@jDZ;/&\_dE#%_><u^kd$uhAkr>i&);gY$/Cf.q71fO3d_nDp"#tM:Os;C<`47aIaj3 %<00#@m&3&Qh]kX.`T4Qkl%sZVBZ^GBD>O"(V:8F(HMq/lD%TRATZ$cR;BNJglTkgDj9mra]')??@='"X#ar<jPsLA;%F!P_"1EKc %B=ju?lpdYNR82#T*aQk71'.tjXud.42aPt--82a$"1>H3[VZ-fW/1tqTVq\@2ULGP4if2Aq8mqjf%.\iS_B__2XJoc<N1;9]f0EX %eo>%+m#pK+%[bdnhX`q&/[RWtT%V=cXG0$AE]LTsME^O](bHgRls$b:nGHhQ(=lU.lF@C`/Hifs^/E5@:i>u71RL/I<iq5BTYZrF %Y-Gtu[`@phhRq>4n1n*4%2VdpN2J8s(bO-$K4.F<5c?k-YZY^FdR)jB&f*H<FN]ZJmQfkLke>Aj:q&6%3`+AndQpM8f<k!!l+oNU %jfNKY&=QA7FkTLjme:JH5R0kTMCf:1lW(di[4N"B1^f,9b\L5o#ISd]Q\Ie9,H_b6(']>OM%544W<6@>6.`:iV>:L?+GR(/0a<C) %%W)P*&OWn^\ss9D1ppQd^4(27o4kMtBXS<Nh?Dc!;<g#bhJ[4J<NBDWb8-ta00>@'Ic_rs=mJDgln:Ok+X)iIAQJKg9.IUdk5Zd` %44at./>Z%P%TGm_4##+3k=RItk`W'Tf4L&_4gp-"%*q,"Y!*YPq[PY`?P%ag\$9l+5idjf^ucWh*WWtr:%fU7Kh5_\fU_XBhD3Zl %Q#.sggbpVfieQlW/SC):,*SMoh9ru--6J=%TIh0m#J/gY!<]jt8XF@2jM^fHE\A32\pE43*_![kH4SS5T9aDnTVQnGFBkPe!&<Qh %eR_'h8UO\k7JHCSUV,E#;KZ-B\IQnng2Cb1)$<Id2_8rCFma)3Ou>1t"-?%"'!8YR)VJT[kH[^d_KD1iE`?29PpJu+gqN1.P23O3 %UC.?O*ucej[KBe?!(3f!g\7`P!*f`]AJBluD`KgB2:q;-9T\Q_UAB1?6VUgB:"8M_aE#u&=11HcY%;d=e1KDbi-l!?.!N.)a?I&d %`!V.KE"c(;?+4"?KQq9J))Zap3*sK,B(23]b]>Es(#8Qo[QL+p<sQ/G0R1=#K')MaF(pG89pV)4Fd8*<_j4I9\V[E5$F5gdW\@L? %VW@r%F_Nt:3U_,=CH/9MNr)o`NbP(*LuZlj9<d$Fi:;Z3QEJ;ls-QIVk<TqKgfUsRdWu6QnK:`9qJ:sY!f*k6noN"+MP=Hj/e9"S %=Yo]ZP^Or@-64A2%a8lm4_2_HLh^U95!L1\P"GtFcHml/N)\>PSm5IHZ^0R48mb>L>DqR-N]M5b43f/:['GA7E6+tDak6u2#?t-/ %9ClEIA<e$<;UWN61EsqQQhutFP+M,bi7bUL>d%gD>_&QlmAf4F!H>EoLl8f/FRYi<[0C"L>1Lk=%O6"r+tp!*/u*,2f]\NPqN_RX %1iEV&c-\_/CfYGYA`*-XXX0S*EdG/>Pu_bHkEC!:3EnC6]pn14CY8'P#OQF*?EO-mcU@+*6.3si?2Dg32Rt&eaQD+e38`:8A-6+o %/Di`-M<an.:CCF-:+?r,.9%>PDCm.^kILRuP"-0HBdfK!a6oK`NlUS`ZG_fKs3PUu$X((Dm87\l)I1RHQG[U>qiL22d"IRI>L7nG %UW+g5a7=O$<TfcGJk%.oggoFQ4N#nj"(c"ibU!Ge@*;m-p]>!`I,8pA?>+"GUIlOI(BaJDc,dq+<MW2!V"c#S&?[;$o."MSo@oIJ %qAV:885UPaj(?<5E+";#_/iREG6K:hnBd>`O;CTN3$_PoSu`Li7)a"#3=e.8ZK6s.(<o5nQ3EdLQo:b9[EBR`.etXan;)*YbpYh" %4%2O6?=/g?LOW3=!8333JoddHRS(</Br8Ug`TWci^[!akY[^anXr.f;WliAJPXBrPo;"+.7P)j8UfbC.S.j=#OT)R;Rd:iGQSbPO %akY<TDMm2?paI:g>Qq,'q3Vc(1_ZtCA\4ss"K-65/i3#9"H1c\;[UcSX)KBR+@.?End%QeK:80Pf87/K1hTS>kGbEE$]V!92h5-? %=4-JCE3e!7>mHR)6,kgo&Wer<e\&p.oPjF@97LRA"4:o9!<jrG[D]Wpb6[cSZB)g\`8l!R[4[<3kV;l_"r$K[JomZ(kqnuKDjnIM %l;[ljFY%\l:alMf1`-`pf7=%/hd-ZS?oQdE^tEN*<0f9)o4"N#ZDW'dq/M7Qgf<7@,gdfehX[Ee_WYOa9bqmU*1B&9/(U(XK)$`c %\#l;4CQ=^6KL/CQ!_F.TTYW6pWp2coWE6JQBSl2]K].'WVOD>7C1W3dp;M7&7.b:%?CflDS_'VU6)usG71[?F%XWgPjWG2[2r.>r %d.tB>2et;fE]4#ajk&C^RutR?a<9ZQ$2UWdp;_U*9t#3&<#fsd;b6L(dD/4M+,*9'Pib/"T9APrI>2bfjR9CB0D`uaBJk&GNF6:. %lV]!!%Ea2Lfmg67IG8WHS<%EmL^n;ITIH,h+(4!3J!K9:bXontddRi.%?nNK.@X@RM9<J7JQ>p+;+]i#RKBlK>Hh3M!V(>1=*W1k %TS!GEXbP7++>X#+#0I(Z!]9Qi`1Y<Upb=]20*BRI76EaO>$qjb'jB3THP:[A74".%Nq;1n*:>s,Q/>Ht#h1Cp@I@`30=j*4pO^1H %4V/9.**j783JcCLeon=jg6)f.5k+FqW7--$?%K/"PgRe$XriUEcOrgI@hi.R*s'%bPD9=+]GE=,1Nl>V>4-NL"esZF;OZ;PZ5Q3: %AEBXU&M>.Tme^]L%`\*EVEHVn@C`.cXJ071ChAp=2pAj?7\j"V@;op)5V"]jQTJA7G-3@4@*4e`*Y5B1e+Tg-#jP!"NtV%DZW'M7 %lY=CVQiY#XP)LacZ,t.qj_<.X3@MQ!p_!aMN9]rQBH'BV8&J:UFQjR+a-Ti^B[P&+I(k_-?`Vlg38=BEpH7l:jj,$eDT/glDpA[S %mu\guW]7fW#JD-QT?u<#6P*tjYuJP[!j[&cf5$+M;@8ucn<HusO]Ake^BF(M.[V\Fkt&jBdK(J%'a`;;B\=,d`%cdC`O]SYG=n`! %mQg@kd&5l^1XO:?bYXVQ.3,G5*W%U9F^JqgI)0Sgih1tS2biMHX-f+U'kFGb9\[CV>0KFY/_#hq-1W`noc<cU=#&IC<3A'@4c8uc %9Wd\fB91J9hs&lJXZ/`g_,ALWe!A!&`b`>:#6deJha)mcEqM_;)KHdJA1B98c\?E;pOTE,5R2"^pmAe]F>an3/OhPA[6#$MT-KpQ %R]bFVK%1W2+.K(q3TZb>o4h^tq&J0UN)@")aK?Et9hA.=4KLON<&f)gRG2>#P3@L<`ba3fCO?sJYa261kif(N8;_J?3AaOIU'9@G %j4T;FZ^lQQ6_R/$(i0O[\%/YYgY/Mb2eis\)e.F>Y\AmIDE7+TU<,DrqJG-@eC+kKe@^3$CW']_&t.iRa*UX*iG6f>rpOQZa`bA+ %&ObV^N#_-I[Q=)1[9X#;@LA<k(Y#c8O]]@"Z9-/HP]/93-X[J(h3piAetX'9=K<?LcV1!>_6V,<L)Ke&8=[c"7A^73r?a"-%(bpc %AGg+-0aBYY\$?b9'V?)?L:6EIiAe2r7n*sV"(NjI975rr(#_h9%I.Q<!l[m/Y6[Y`')&9q[G-Kl&d?'A@?q!4,Otd!$bE0+r<dCU %"Y;]dFu3*]B]R\jP2A.1>+MXKI!EN,*Pcij,.'>:[<(rj)5M?kD'FjL9JG0udhWb;SqsFWkhpUr3Y;&7c.1]_;NPV_\0CnWZ<U$* %/Ml-C791c<Qc<:1'f33`B067FWLHO&)?d'mmu*g3%8/sj"`@?Hf'.*nMXJn:31O%(Cg@F=IGhoif@3HhSrKs,U9kLY!)C*V<\5al %\A%ZokC>\=o:l,!QR7SOLjVl<AKFmgrGEO3W%%N[7fD*FSZnk8DHP^5BW?CS==`3ue.>i>L"h_\RY&@1O0/*_bGPE:OArN+QECL3 %Z9.5$Q<&@O^I[JqN7Wh=3/uUT._hmjIaf_[X//QWJuMe@4Kn@LIBp55hb1guDED(i(Zt$$Zuq)K(kKDEH;Hf2)!.TMWgLT%5kgb- %Pitfg5u*WHbE18\,sukC6#j,5Fc\F^LrO"TU#jt%$kRI5Rd56;9IIUR3-\QAGu1qa$kji!,]sNH;om?e&8Y@R\pgVA16F^1"I"Es %`n/?$4e,C6r^!c.Q53cgfiSVUn>rUq2/'0I5tJq]B;@*bK"r7T+@232)BTG>MPSnsr4UYQ+UJ63(lQZ&CU0*@-94p"S;":d<TY^d %6bbjs9J?m9kZ&ju/N/8JQ$dr*J"O]qraSg3Wj7GVFTolJ[@f!d9:\o<=^<dP;gf9<#r*MR<hYqj](2N=QKHsm3Y80<.S182q?&Q' %cXQ$aIF/OH*Aikk/^]-fkcEJrd.ODn_gV`#jE#ofZT\$?U?l(8!M];!O50nifi`IE@'CqfI8*R%H]kDAX9oZA&At4l6$qHEW.E3u %aMR_&Sa4UW&6/a=q6`^K'2KCNZYrb(o[mVkG'56U8pIlO,D!C()at.dEo?$D6a/9lWtlV-l%g'ZB%>G#MMjflZQCta:tD37STG#& %4(k*FF)kE43Z,gJ#TRHa?s@cp?jcBabW.Rui3^:'4d\!$).?-/%/\K0nt"C?eW*XF`O`XI.hL79BV!@7c5@VaU%u*Hnk`Pub\'jC %&NI\,lkGf[p#PJ*#3NR9<c"&4EUS!1&0oDmj<\1k<\26V;N4;OP/N_f)2p871m@ic:&-ciQV:]+DkMWH@rHircY`??h1Y1jjW9An %X`Q0p6'tKfQkm)sj(#P!$bQX0[SW*;j'gWlYdC_pWNDoo/DCX_s$KMUWH]fHm)gGc2R`Pj\9"L$I3NjC&OCm")_j1Z9>H]!'EoL[ %2FaTpD]YR^.Jm7<,+ur^mZ6:2K-eUM+ZFt#*aTa%oHp7Q\?gfeE/JWGA.+S19Z3`8ZDq2XCP'-BTN2]]RT9bU>7_mIBFogGC//Bj %[?%b/=Rt#:)r/S7b.3clR:2k[rjgi)(e#5IOM]8aHpS*.\\M`9FU9&BI0rif?l:Hhm\"B:=;Gt`:?^51a_"PLn<hi\%nt%OY=Epe %W#73B2f)V.l^q#XOTC6bS$#ROHUR!e)]>k<0^3^re9_`c/dB3U@:4@eZmBKEd6V#&WCJ`gMkER:>F<t1gUs<`MtnmW=WYhI;3bd1 %,stu.EAYOi6UUj1V&B,!Fl"I=X3p4O$Bl!4$"&[bh1(^V?p_fYR*^bfW`B$m@8nb279B[eGLX6&o'6M/Kr05Ao@F7p$Aq66:Wa(b %&,S!>pNZ.b=e31@,&QB>%,=Pp_X.&G].%4ZX"_]T&?*n&;lf1G^djBc"I'YX1fuPUs,JuI8R/JI=ZYB2@8_r7`=O9ke"RT]j(/F> %!Ke@s4ERpUL?SS)#5HkK>>iW-BN7.Z.-'/&S@]#.\k&n]`nIXH6_m,p-(:9,EGEO9&FG(jK5klakTibKooIMt1JS:oNj^kH;#R88 %bS&EcOf>f1$d(rrVBr29]1b\"VEDXB5^[NT1Qc<J;i_A+:<+Iu%c\6b!s3DQa>:B;ZOA1DOg8DIJIIF;/EPKP@mEV'AtJ*dJZCYA %[hWOWZtX\dQ_IZ>!-t'L%'[FQ:qd_8$nskSR^HuPD;-f&@[ZQ;aLjQPO=3iNGec!sJ--p2i*q]\M]-5aCM`tS#\qGH5a'X3_lW0@ %raY6tfO#JiFMm<CAlNIV!aGu!q9^&JhYcTrfuP"GnQ6'?IKV2T#T2=BU$`FCAsI`OJkD;g2<(:<rU3,Der<\e)*b1<oUH7,XYG'6 %e5#Dr"NG9T/HILJ1fgU6j7Z]Gd\pV%gdCh&hiSe)\ef?P[21u:F[Ik7JjCnK&nnP=K=LnPbFo5`ij-,i'&i60/G%`oGo`4ZHW"qZ %98/]<%hJ0dK,2[@)g\7kGnq`VER@'?'bfSOTU'1CL8*Ro>;S.m;DS*Ekkq(B0n`1N,#&BpBZt2mmaY7,l6r78=E0WG7.l0ngOn&X %-4i'3+L+opRtc]DiM^B1FX1Z5<)6'D5:1:tZc(eO3f#4OTa$6Z0Up*r/)r%Pf5`V-=VT0/S,joJ*RCa*]rMm@V>9<S["BU[K2IXc %k_-Ou;c8)Sas,"p*&MEX*&*Rk6n#d3"ajDSGYAMnA0!(ubi^Y[8GMgP"N1dS!F+!VCQpPGD3KEU8iIEN,>:ut,mL-p+=GWr'V2!a %K]WAq0SCX84?P-.EOK2@[uaePbV[.fO,(-a@mjS;>=ilb\0tGAlUb7L9GGJV"L/]q';@f^Y\I]D:^H3tid0-oem>NMOfRVpg)X@E %?\;M5het6P:8DlXqNbi8c9a,PF\IeoB\VaMDZc?Q3%)uSl_@dFr=a!1VZ,0VD%X5D4(GQH^UaEfGEkIY==Y+biP^;BK?mXO(kmNP %kB,\#b6WiTKNQ\R((KA%0j*a`O7IAuLhcBHQiuCr!C$ep2gP]pDatle8$C.kl&SE$^M6El7H[\#P8.'c*S[].TY^ASZl-ckf7A_9 %>44YPgNM_:\+^J4<kk1ggZOC$XJE?JFR*kQhH`6"-+N,.S3XUF[efH3Tp?0NCo&AY/A-n>VP9tsm2"Mm`V2Seb8HD,GmF*H5IWE: %c<Is3PXd9mFPpT3mB2'Oe?Y-`#?K7.\^;5dEtmed%D=3K5(3?d=AaFGZDm&U0CjQ>-5V#QZ:55EG)?YPmeVEI6S81,02O1\Y%?LW %VRUNo_@]G]j(sFWOV'iDX[;G(E7^8TRQKn%.f_XDmQPe)(b@P/KA.X151Y;[eDQiqmV@/^Y73%Ks17M=`aC[.V.@,``i.`R4%o57 %?n:X#GL/eeRsaN:Y:E)8rOR@iXk+WDHJnkM:Y%54nljFR8ti>h's/$j`sK8:\[Hso2?LXL_0h3sTlY!7m+YA15cnFPXZ9`/AR4fg %-iLU-f$@F"oe8P\CWegZT5p==M=*q]5e83`>>YR[rn9j&??B8UOhqkF@ruo`2E]2IJnko0)@f_][Q@X0#i)Xc@Kjo$@UT60F>Oo> %?UoI<3oTfOh$un,Xq%h:_h0P-7L.]&A+b7sE3Ru](1:s_%l!E:IOTsN:0OoW?WC)mPR1eZ7BrO'E]s2KNVc'S(Xnpu0Z9WC!NZ)# %$k%)i+>pYD5.9+RF6u68)>fLU.t$-W)]iO5IEh+D.!BE0$W!R_CL!:WQngDT0(;^1iLCsrE)$qL4L&+5:sA[SZD2_!Gfu-4Pcj>\ %YWh3g+uJ]jIFprmF9SK6`J+mIgW?\LV.cK.4m+ZRMc=)en)?`LXsp&%V7@)+hg-i9Ea\',qiEYdPfen5JoOL<'ipZW$DS6GS)%J' %ROre9m_d<s!\4Z>M*f-D.GHRm`_WnFZS*ANlu!*c[8'Lh"dJD=3c.FGhJno<8o#);UE/2?j"j4p7!e`gp]D'`,KXGlb.s_["i_J9 %CJ(GSjWu&W3o\s0s&%o!e=O#H`oALh&$K`Ik<\,u\1R!`2pf;Ao,q(JL/k'F"'?Zn,0/:6'>NZW7LPoh/$LE*/`q#ZcT>SB)k1O% %g,#aQ0V9lX=.Ir)mPP=j.HEuVZU>PIW'EYa(89!KC/ACo*4-)NU85774sB<0l@%Bg/n?l2=pa\++_.arfb9a2g-s\jDT>R@E%3;: %4$S]sgQ#krX>GpCEAj8ogEVSN=oo"S@Z^m9<K1V:%]5`Sf,<2+*Kfh$#.5tiXD!hcd"EG7[?=c<Bl^b+NSNX`H"Or&Sh]c7TNst6 %<$L9:.g]ie.Ti%!qgt@JC_t,\m?4+hPb)oM"]C&$-Z*Wm,)AfR0^@g&[3B2R/;"R#j<Ys',bH2nrto_0k6`Gu.Z5e:biPR2_Q!Wu %%eSG9/9eS>4\>$+8J>u;bIMdMW;RA*5L-#PH@uJ$':/M8R!_%YD(X2ddtcAGg<r:9SQ_?NeaT&PP^Dk\FLulggRRmN4[3)er/UJL %m6EX:FU8ao9j1(hERF-U<-_AXCG%&f)ci:nU'SLk9D0q8(`@cmp%P^Jf$/!3@i?g'&\h"s2H@aZ-d1q?c##"hl]<qKE\;,E`G(Le %E)b(,--"P-9aeW^LI+Q9`5-7t3@=?@0o\8knVC?>"-!n"QW3hp\C`n[OZ/1\l-7P;'sh@>d!$k<$\qmelseKAPg#E<npSEpE0.EU %JRjOL:5<8LJa")4F6F4s.Ik/WQ:Xdc1\_5K-UR6Ja9LLAN49j8/g\XAf.5$bINN013:q!+)^e"0)FAMN$UQu6KWcWjahiCWhe14* %1mic8c=0OZd"mG4g+F`!3Dd0Z60E!^(*io<*R!/81.ZAfpSsb-\R9-^B-t*:1EoA1$Q37^1I\jMF+Bf4Lp"66DLkG,:7\8METu&c %;rb[UJ]d+:)usL\$^QZ.lYdqlE7'kHQ\d5pi8a=;+3\Gk-9ogkWImu6kCD;\"mmY=<_j`_mfD+@(8I3/#X!F/SZs_-A:@dbK*Gp\ %c^Rf)ME=WL70Q19oQ_Nf<:_e?3^?#[[d`5/\'=2'N=/2\k;iZ=Vuo9HFg"?1S&s;>n(GT>(b'3u=)emb)r%U`obr2_>cj+n#'4>s %nOPX_Ep&>*_`HC:$qpG1nNuT95-#F0W)o4)E:;T%K12_5@X9/9&4]uJA!)JMFSP"<+uUMR_t2_7"fsu-TD5os%THQ[UYjK.'Vc0. %)3Vl^iF%m/;LVmjW`MbKT=]c\I@"3c7B%[`^X#Gk)-TXePi4&1SDRfar^c%XZodO2CfrN-$VO?`+/F+VD)'Y4jp+:k;piQR3WS#< %FF]J&/p&8F@O-:4%;X="+'Rkp2ZhmfJgXaVBJP4*T]dVY*Sa(jE,i?E\-g?^;eRkJ/lN4:1?f&e-X.%<5-fDt/>NMT>R].d;ND[; %0Kn>W)seChMese;o$pTN1:TjsQEoS^FT?YAVh)egs,mNn]+C@joM0*dEiobI!>R">$OMe-C%0k7ne4R#V/r^klY'^+XHB&"@O`N. %WeG%fg>WSOZ^P4,ATKCS+aAT//B(7VO:eJMMr+8=\_p@B&t>B\eIlq;C`&,_%CNJFUDCc.VO1BT1[.$&/:eNu[KP*U<$#kJl=baF %lbX)qF7sP,Y4\\rGWKL'JBsU.e-'1_KTr2$6EoCq":tMgn^C&]&Bci3B_'O&nn33>_Ss[Nctk!]LSqbZnW]6!g9])$8TPt]#,<m. %";f64;@jaX0og+Q1c.f/&<OnbhBP[<L:<5.27<[O-,"ek.Jg@Rc2Z]O\.)sAd6?:4dRQ-s_MV^q&>8nc`0>S^VM"8G*]1@MBO5Z6 %'V\6/iAuLI@5if#Q0#ZlU/iaS(k/$`"8+2Q/P=$4b'A>&kRWJ06jif:W^6o&\6gT'g(kckR$>'!RYU9`X>@f!(Fq#1RAWUbTSF$? %Y`)H4;[\4!+V@XWP]uX]@r[@M&Z,;i3KLYgaWY<Bh#l<p(3D-2D_D`8[Ubna##\)H%Pb6i/Jb85dd(!@PtUT/,bq1*7e1>>HVCq: %,]4&lXUrrq(FVl].o4qEGGCIf1kDs'BL_@PMt<ULZ7O<I(aFhoaTFQ,&d?fK%nQXs;F93.Qko))68_S!_/`WGZie]4o>f?$U"rVl %a:hVuhYj`!8T:)I>E$)<[a[&oG1i1M^;74Z1c^VsE3L2P(1?5]6"pC#,s<[saf$gOFB50IT]:]9Vei8D5tF-ffHTNY8qZDPXP2-6 %HJU&/`=B$R*E)r0,JP3'.(\$me2:pdg#Te6>N4.(Zal5l<e`VM[eCHE`[?l?W,j#,!-IHEmn#EoHS\j*MO$TXB5dE&*MF[#EI`\& %gVUAk:,97)K250a#D>6HrOB[eH9IYh,C1%l#N?-/7S4mD=r!1,_k?)_*5h@#/B&S0OnJH>q:\H@/k^8aoAJ-8egrQF1,hB!LPNQg %@dHmo=atYOrgDr1'tbD3(m%t[%.YZe3<G<ldT`BtRrs<sX'Hj^WpG$6=2U]:*.^i3P+]p,H[CZh=`ROsW2ds6/;jeD>KrfH5:hFu %?WT.[:!ogA^Gr?"Yrh4/0#DL'X%qjC#@Bo,%td>Jd!!/N9Ej1?!,V:-aX/=pghjD<%7*UQ02no3QdeXM?YXCS7TCB_mR><Q$hpd. %q(u=G0=XYa"O1B')#5ScWHqWJU'o47h0W`l34()(NHLkAW>"H"WaO00G9%fm?KX"W"`+1AcZa'e@7Sil171`7f_:)&BXGa9\>ZQ` %[RS__"uF'Ye'=O8@;HIM(3Q.:1"^>&A[G[,>3ei99Q1()m^WXa`8lK6N&)LIkH6F76rclPLu*$.HIKB=4[ES-#qK%XJEW<om`[<. %LRf4WI@Cnc]ZQMVp+(;i"treLJ"*Gai<7BiR__SD/L;_iGuuE<SY"=GS!8Q,f:i`tF1#JJaKf\aN\P8R<\CamWY8_oWmuMd7Ws#7 %U_s7j6`O`[iXruf`1/7P%LP$">mGKcQj`*).Vmml_<T1*1FiiH#+p`>^k.U^[E$1s&uE6KLDBcf-&U;WC!id!MBbsGJtXS0b`#// %hhd8tPN,bqW^p%7&6@;@9A1?1iCY3tOmQ+B+nd"0"2_q`$J`rnij=DMTbs2LTO_2,HY@+^OuiIRBY"9rn3oNN;eh9ZPh?_6I)_gW %84!ou!t-YqV8*;tq/MJ&p_p`Wo36!lPA"D*.)&/jEgWqA-Tu&f/es#UPO1]L/4T1%_3X$jkRs0-L1VrOBN]_s+jhJI(u(5;0Zj4! %EU!.L'on;%(mR/rguQP]!eHP9Zb4N-4/dejOOf`/3$tDOMqIreNfI">E+r`!GCil(%3V5d^iPF?L`5U);eVChCUk2&kZQVL.+,R. %a'_dS8m0GO4*"^pl@Y,6(RJHb?4pjK8neoaX2S4hdY:=GG9Nsq6#"caLpPcE>1HE-hfKj>IA5V'l7mXDfk5!<>HDu1MC(qQ<aUZ# %EI!@13s<Z\O.^0aQDX"[4bB@bGPdP,')m&ZaCK1N,"WO11g79s',_*B414@<mIptU:=cZ"a0[V(^5f'*%n+Z:$p`;c"M<q#ZQ>(i %Xr=3J1I&I1*A+/8._!jP9<U@]6DCoBH.8JT.96b6lE9Ef\nd9:;u4%hV6-dC,(>R%eg.-$/ILo@eo5M[+E.s%*l2+4bGlf&$8ra4 %_PD'5g_:!odEs*11AeaInh_u;aLBt4/[9p5LF*h]WpEEuZ*,#_&:C2,<iT6;h8pSD4Gl_D&Z@tY$oNd%VnQ,KKBHhhcnZXNg9>B& %:gk&R+?$(!n7Y^@-ZrgK\AaTl=^8/8MkcC*>g2l:>n6EaRB;)Gnu(uMn2&p^+D[Ec/s;+HPslQ>T?8M8'KO_Q]5o7c5?'_pb]7P0 %'O:)nf=$70L$^`O>(UHiSN40DLTQSX#GU@%f7A]/#uI[bI1OC>i$:qof'[%S<l1$%R4JT7aOl`WWC0f'I6mtg[$^Lk`Oh$g!'*mU %AKrn]W[uA%GH!/\c`Gb[\N#_Ll8e4HH>6[&!>PYXjTQ`B?>LTeoK)S2"*=HHB$c`NVJK!^,P4A[+d,@4PX+B"5<r2'.BW_7R)_r7 %s&[R=1["\_P=0G#@VmK8@#eV,ri_grCP$2`3l'/LXS+UCbZlHNM)(6<=TBmNW.klr%RF.(\kQU4(gcap;rVRq>7*5<DLDH`;t_h* %[N*JRfGE%%E2(GX2O3`d!"FTrBXF[3k`,e>J-HqEC]TO`"7YcEmV_0)*buL92)pAe<@lJ;aEVt)_u-:Ga'F_T%D4Os'p.UC;&OdX %FSI,?k]I83LqU\/0J8$p&&TpA@6KXANWQ(35K?a#+cMH.rP4F`7jp=S,Mg'Eka*+kPNe:)#78flHJMGtHnSZ%\lTmT?b5&jel_^Z %j[NheJrHp6E+_Q@S+c$?J9sK;6RoHW/K0ac.kPqdDgoH4FLF;].r/(+^qtcmU1<6l!:K;Z-0VZZ<3K`&NcT[P7e;`Xa%(*G4$UCJ %L.t`<<Y]qYhk&_)C/dXS6#L8+fE\j#hIM7rC$B'HhNkaLc+pPsfWJrGPT'p&3YoL:;slsJP251DY>#3.+RKS'D.g).`^XkgL%#S6 %pB->rM//jmaBQ*,2P%+rcUjdM^juB6)98=G4hJs71So'kTDRIt0OAOO[T@G&rK&E:"3X_D6VDY,8[mG>AYTYp+%'0:kQ-+;qQDQl %;hfW`7=K7jR=2X#Zt3q2(?QKaIg-bB>kB!O"21L&oRDWDBD9='?l\*9;/u@4(tF99eZijOl4lT)(K-GP9\Lg.B7D7hjDOhu)pO,< %7?rZ^Hd6UYO%H4PoXaQ1I\#s6dR;Ku8f4f4#Qd-;/'kOLgUI5_VeTTgVA?+Y/OrlO4\RkZr$cLV-%I*Am.%?VD'g75*^1]Fgik`0 %"n0[EqF@c7j(bq-\'b0bXHYFQE9*Dn?/S,:6(IDBT4u>Y=R7X6+\hs5KB0.k;->:4alMal3.%?j@13k4/8AQ&CP%>i&=R@>*d=5r %p'U5+[s<?C)s;3/R.Nts@.6oN7ZEFGE9m80m4pQpqhU1))Zru'4bmFb7a,ZeS*%m(?.kK[:*P&g.d!.;i69-J5P'buJaEYRIT_5+ %O@R:174k&i$^2$BO+Q0mkh6,tGih+Fq>29qZ9;]-OK!40`DTs^)L7t_=r[YYDf&Y#dU5#Mr<++JHM30QKS25L*62=7*Qdhdi0!(: %-5O2IS5GW]^P,D"ioq<<acL6>\'1)BM!-^&G:F)27SimkMsR8ApH'?ugidZY')nTIZCM0JLn,8I(16*^Q8?Tbr6+mFF[*2lCT4]9 %4dB*C=)_:CN%;4,M97=niiQc1Po@doUf\[a$u+&JnT4L(S`I7OhV4(=r.:et?)bEr`#q0o,*egt=0oD,9fTT[M$]++Tille/o@rI %Vj>$`R1]5\m290)?P)_NFbT>uTfkHI4mJgu6Y/4RHUTm1;=$!36gT]h_-6hPcAP0o:=!F-3tO=aW&+^rf>sL;^_kdHb*.18N-N+J %XISi8\XjI/Q?LZ/A+q8?W@u03Ssjq=4P&RZZ&@U^;(6[!A`!:robul2)]5.:cMJhAb$Zoo8BR$I(c9g_cO\@c:%3obRHaNFTET47 %jr3r0lRi^n*V<c[0j`NXjFs3IM3p<ef^=\@"]d+N0*r:GdaESXY'BDa_.fo32\>4r%#Nj)r[3/SA&M3@^i+7IkH[cRQ/;K,3S3*& %j=[^9Qu!ii8p-^u(:U@:E>p=;^+CSWe*_UZ.bjZiejE=[Rj$C;.s76pr2Gq'YI?tD@m#T>oumYZG2@9@7q`tm3&3(8&2)!sOmG;F %533iBl+_Y%e[qlM\2@RWpO(CJ@)`m<Yrhkmnt"CnZR\WKq_h$7/b<LOnf8)4#'<X'B<PMO$6Ftkl)9;=35mrA!!Y6a^MJ@tfR,F" %i\La^&2AVr387W[mHC1+"@M4)pQ0B^UJ@gm93=\XPN+Q'>%)eSm[2XI>s>XG.DkL_Nl!+kg9R0R9Z9C)k)>e7m58!:grB#]fIp,7 %ppaJhp09HQ*=Ps!(=lNs7EF[5a=N7Q<(mEPc_fL<H/i(dZ.F*J*0ulf;A3mTes+)dH"OFo4#&,?k&-bc\-La16P)ZJgZBb7rAjT- %/U^TA"UMCHS(UV%mDt^5bR&2'2>E!hFGC^mafPeh]`69a1]*K9hlZ/'b+/e9Wk)`L?#MHCZPK0@kE%Tn9rWGa[kE&=;'<YLPDqcn %;B*nK*3f(CT-ma^h6.6!nR>4eZT(Fi$9$1S(qg=>YR@=no?)EmFo5pui\(Rn(i+aqamIC/%K>+Xa>fqs]n>pB=ka0K8ZXSLW*2Z? %;"E!a)_I0phH[Gt:9oR*!kp>\1_uoZo/*%0T8?]ioD"2`U$@&j]bV`?mr\XNhRR)S`ooP`,PbuXKQU@q3E)WL*4:fM:cYsC./fjQ %J^Mg#&AU+>T9;:u*5d>b.\XD2mGg[seQMmIilSK%M_e0a2rR73mbA,KIW@1BLr[9?KT'k#K:@if,&GDTnZ[fiZak^ZXE_>Q/?"=A %&_Kc`/OW!@&!ChI!\>l'.XEcn][K5!OG@jNjBe!WN$;#3;'SP&2+:>A7F,<^;iA')Qs!j>RY/R?"K]F')$)aAm,gY+1oITa5kV;d %qpU^:'?-5Z/]lsQ@pl#d0;75r"lpI5YWb%_cTVl@0=c(Qg!2:78E;li-ETsf[I:c`]>+G6't(O4/tJRe"*5Mi1`0OlZKN,cg3R14 %08*WS#cs0Wq1TE"UJ8RA)OZ*o(>NB%26M<H6EHtu9sOj7E%k7L)+)<>@P'66#IbkH:'a+&KM??C^`#d\nZM&hhL&3N'rV_!BC4LQ %p\BPoUq(aiIg2[1_^o(uMsCG&p]ro<#=jl.[3]=<9Ip51'*.)S>2kQbD/#L6?"&]XP>;1?4Wo.5A_\%Y@O<V20RC*aYM0Q-Yi/6Z %U7[eliZ`Fs:W>UDLqSuV`U'm%&^/Z#$tE!7<g&jr&(KoA)O+DCQMgIsB0QELcA&QP_$5JfN8Wm>#h(f\^l>eF!t=u3nr,U@)ghQj %RZa:D&Q^tjRs5Y4?(0=Yp[5*;6T0Q@5fEe2ECZ8hF*aPLEE8XAL80WeJ^^uHHfojU^TY1k;Q5i`Gc'Fj)IDrPr2^<d]s@^.%9;uE %ntH/=c6C8P#/iBd"LSG[XTo;2Y?Oa0:UcfjGg7`s^`o!eCSWYk+mb$:bVa8\7Zk=G4mC`f*(=&qj;5rK%(>T9G-I1<cQ/ejIu0-1 %.g[gWi!d6-;Ykrs!!2Y)?\2:jO5\#=PXYRm%AdBK[$rmX'W="nDE+'qJ^N5.Y.=:'#.f?@6eA:'isp&Nl11"_mWsS>qKj<("%s#) %pe;(pE4_\(&I"L5\TP(95?+Z!A?8@o.iKL<6l5j;,jJ2-_5*O`M(/'U8&>YO.Ln4r>Ik6\"@+Er/^NF#H!i"d$0iiq%H[f6G07b: %T$QTG@4di21\Q2mTG<$Ofi\h$\oEg4=dI!7V:brb?]g_>&^r/aehW-lNXDDE=bO3M>s4;$`/*0TralX<G;j2M;L@&#n=(IQF5ki+ %:huq65"Sm(3"'C:#9/6Aj+6sR]F>NWY*-C`HZ3T@FHam)/g7*S:m9nM5tgnO*&*Nq-Hn<3E)pL">5^qsGS\%Orrbrsa+\_Oqu+c# %6/7?OG6f<3*[pC<`SZ[a<C"fu\X^-#91#X73m(<UH($Ng`OsqaGpW'iP,e_h`BXOPV+bsaLob=[9R(m?_;E96mfSpn,E(p!B=)7* %qm#56>)EkB8Q[=$MD3J/*)XRZYs]=*][iOj2"0Of*`)i8+f@m2$?2Uida2uZcd6><r.G'QR^JNACcE3]f0WGGnQ`:6(ONA1DfL]H %23<^<$u9S\8!Zq)DU)]D\:^jG;Kb0\/Qm]]D_'Q?j@+>Z0D[s8."?!Ng7VC];2+RjAXuaM+h'7Q0]RBdcEPub.b&FZM:!cr/2&<[ %_R>Y%(S7kr+:EKg[i2`GKbojpSoeVI#FTCir"i?BE.iKCBEAHO,ZB;e&?pdYmrZlM1^,=`;TgNQY%GBK7n+=j^B$@KVpt5Mpo<;Y %'[i1^l+0O!P>4M)kJ@tV49[MhYs9<2V\<5g"=+;X]m#AcfJTt:oh<R=mIOh@C".,5DX\EZ))b@!;?XT>2KoHj<i&@A/*!Xr%lJ"o %op^Hhc2R73V,#gWRI4TucXG&":Hu\NH7q(\L5jd*Xp]^\Ak<QgNpWBU.mOd`=QYV?We,TmipAliN#76YU<qD,[>oiXR,B=pq"k!( %/M:eOj[Rs%K?<W1g9LqgG8b<)nFL.CO]hF>i:%)TXtHns0Hp<Tn0I[BIl!n7hd3hY*oCb"@U$!o:dDFBNmbQ4#2CE;FW?$n\skmb %JL?>2DrKU[!IGH$D(L0ZHW@HOPdVf]O9WD9nur1XNS>O$YHT8#]"ROW&t1:m6g^!=fn4&**W,LAX]]eeGU(daM=pTk9t$3Ic_-rb %%43P==hTe"/[W8QCBEBL;kfh-/@H&kTmb3ZeNCU+Kk*6\Ee8j"-B*kY0IVQs44iX*QB[(MLYJdg8=d2BH/bEqk]m9^XE,Zh:0]HC %UEjlcDqe#?;MUo]ipEP3.l\ri^eY4qOAXuTUF4b:aVOCUkkS7d+!Za(CgCe-eUoXds3ZIi%"`Z87I=FcV$@dA43o+9!dM66d(bQ\ %(AtcRgq`3%L9E@]?>uc$F:dS.Q$QEGmbS`4b8oAi"Ob*I+E+63?P!3hWnt0LO]nFM^e1^MgE<0)SY<IrZEtHhm(XZN\QHN]26@=H %Jf36b"HNZ,,QE>'.<Vn+56YBt]^5afHjXa_=JK=af\R#=o2rnTA)+A)?Uo=!T42R=U)D#b_#Rhl05V(")d<OpH<+paZ?h7[[F3C( %TEnr2H\)qC?A4WugSWQO6,+jrI>mY8'p/s\/ljYBE!<R(5k]`t6Jb]WYXFM$J703'NYeXc\(<ZK?$*$E[r^,aMOVbp'irtn&4,U] %7[8BtTO`VS?Nj+Sn7:H6+#)Jp63%0oabilWYm)sRdS)/!m07]e0pBkE`Xd$&2NW-U#.>ScD9MZg;QC%Oh4fFMSN%VgIP6>$_5>-i %KQ3TbgEJ4:_"B)k$]/"O[j5go?rW2Q-VSAY(qM+<o_4#cgH.DqNCZ6"$OBW11@b=JlS>i\K!2Ae]HYqaolm_T?DMQ1[_E$WB,X5, %P?AAbQQKtU'h=.s8GanteHA$+6I[^cmC])a=R_>)?1@UH&hqc]l7ADn1nljGW)E^@#fnR*=b>_kR43/pO[S\SOSeBM#fgh"R8teX %=/ei(#2F:SU+JOghgtCcOe%^T!j(\27Vaj?)l2kiSlu/]0[9.4$>*P>86mFr-,:a7G0NK@Z"iTq8T08P:o"jT4XbR"8dP!l#1gsY %a;uI?\@8SqaX\JF@=3c\V(JN%E0*Zm_pFA#!Y\H6Vc.oWLWpF#hRb)l8m79.?tF5Wnadl"V?qJT]%!pE&S?c_\NM,Zr15\dgjDNZ %bKNfqKKZ9B//0;AI1$rN-$*0-I"J+a*nJ-*m?o)D:bYfDmtCd1pVco$KjD1.FiEAUAUNqKd]Zk#n-rVXmERnDA3sQ:Q?6>-K5X<4 %(%F^u^_Q!1$:%E:i=Qb)"]j?Jc%p?*B\Sq$._Z#`;)&7^Dt(Y'W<-*2QHU=bnCtDB?GdV-]aUXB/Pr5YfQqLD5tE9)RkmFHD9b(h %gL2O7NO#**&K?d=[7a:-:sL)P)uZ"@k#U=,fZ%'!LPP!_1&&pfW8MGFp8U[\Z._A,"q1tmUI[I<;C/C-M?I/M%hhb94X)oT-*%)0 %TN@MA]kh;6KrGGOe4&e?"!b#%p2fX3VN6hPb9Os>TE^+`^pdg@NSX-5jaMZTEeUNHCRKcK6fa`=,RQD*r2VXA,8LBni2$#?$0ouJ %>O\A&Tujj.I2m3[,/V4""N]**@?'9;N1.kNG7l-_?/XOlX2Vm4[L[+5A.RD%(eG:AYH56"]1!pJ\n`OE_N^ENIiWti"6!%#<eA_7 %+dh3sg7Ds=)]tZ'/mt*g8'p"bC6XE3KTk<;S>6TTKAZJ<ek]0k,o_Ac1Eq;O<2iWIo_HnnMm^"-!DBFDisoS@G7^62Q^XDC[0<Bn %mD]LiM!-_?,E<BUJ$(@X.X@?$!-5W"iTEMl/dqYb(++TO_$B3(>$qW?<.dQ!\6f?.kGa"k-?4AL6+!HCJe:sji44u%%Z6!)8ed6p %6`]GooH/K;d?X?4WE3fC!<+kJG%J&4]rYb5.&C.EK"QS\fM92dIYYQFkSH=\Cm;d\TK`2nT'O/fUo0#G/tAmji;B,X+?I9smdmL* %7%bdu1:M0\9P4=j8\l"<?+Rm:h?W-nLQ95igKn;1mrJKefC/rI>CKWSf4R:LgPZ&co1%D%i2YQ/i8@raD2Hl`]Y9]a(2?3ZGIF?l %ohk?bCY*S8UQ@E]lYTHR1t-uki3V!iXZ2TbjIouI6-5\^*j)\IUIt\B`ptXm"EBVXV#cMU:[msE!)5k>Oj;fb[kZ!<XcY\.%Up<_ %o$]G"UoK\1#<],$,=jncJ?[+CI>mYZ/]2P0A6Z(UeI?p^>\3+4:]r26%+RDGdb4K(!<;i+[Y*AE4o"lchXY(ajIB/dBPU8aC2;!I %</_Qd3XQO>'3Q/Z<6W5H'3siYI$V'0bKjV1rYdhY[_IPlU%PTtIC@]GMgC1j]SW;p]a6+AI-\``9H[WVpTH;H\^lB7V$@14*kZ3f %".<&&-(lPK6lb7PbE-9cmoA9X"baTR7Mo,&\eH)#gNS7A0*:>K8f^u]1pX$O;7rkYPNn<omHA)S-[jJ^N%c4RDFdJe*7s(?FY/(W %:ej"gfo%D=qJ"G\.+@3#n#?k,3?(C:.S=lt/`GQgGMrCh<L1!Lm(Qe/DS#Z\Zg%p'd+JL^7Y`%@^[sUl*jt6u:`[`7jVRe(PTJo+ %Z,.?uEXt;]T5f8_[`hg/W6;3BiNqi\&Ii%S-IuLn_$\GF)2`97J[L;HEh*:Y;\g^d)Rphc[q7&rB7o5fmgeoER>_WogQpI(AgbED %0cA\c>Zd_%#@"n0%=V.Uk01fqD[:;Y6[Ds3Ql1"Ag2KfA#MIAEl!N309S81161mT]d)&sZm*OWtA>`6\A"-Gn]MC.\X)52XDT.:L %!>1Cq!q9u-6*2`T2<oCETLW(B!YC:;kP@f>Q4Ea\3ueHX]@;]@Ome@HQZ<!IQt1$VE#*_`L@iR).OI[h+:)`c/#Z"qX<O%m1CCW\ %V!np3<D%h\:b>]KF<88eKh$g$EZPpR9Y:j]S]8F!8U$KFUumUAW.?t(L=1$c;JnQ-fs,^Fnkh7*"@p4.l\[M/h-I2YTRCah+r,Se %s6#;?-$:9%m0G=<Xls^fllSKsacAqnP0E[jH4-<UNV\F=k\Zs"!67ZTP#8E4>6-_pg+1\NP1Qh,:V'P6)aoC$^h_X_O?L+2Ro0FF %T^V2bHe3PaBlH/3hri$>3C$3hVoDbl%%]rU"_cd1VHgMDWR]EEgujTGD7#`?;Rnmio'k`BOgYUoe5T3?/5TFO&<p=jMpB.$rq?[g %Ci'J:W<K^OPQ7M=h"Em,IMrQ<^`^#1Q7bGV2?>@(p'k.$d<r9HP\b"WojH<.m/_A_$CIU.Og_[9>-@?@fW5Opk"@u^`;)aAoq?5R %frY>GW6^MW\$je9#(<9GH4ds[[lmDM:V\#HOB9!Q^^)oYm+:-C"b*`M'aebaJYhP*[l,Z[UbXs_%!2q@5[uLS5ja'uT-*ZCs67E; %chuN3l$86>%NC')ESnt2O4Aj59ojc<K*^2>Y+.eIGsjiY#Ar2r"bt*NTe[ZW]TK]='pT4rcF$*MZV6C7d!DfG'/51ZgFiO3W!%Bn %bup)t\SDF0Eps.#!?MZbD;^:.<eoi?r-elE!u?"d`fhiGSH_P_NtNO<<9t#opaKkuU+JWgUkcqE<.3,uSoLff=&9`:J-oJ1c1MF8 %9HuARMCf08X%3&YT#t:0]*:GXCjZAOG>L+pOt>6&Q(<M:H2.1bHXqcFHL78,K;`o?,AT[dPE7[iC(*:HDP44tc[u$\gGp`%)Rr;c %1Pp:M#9.G"3!3<;5tBdO;6kKVneJ6>6JlPIZCROUc_?M`gNZC08`%7?3k)\Hf+.R::'s8KX&IEk^du*Dnq6`98a7Ek\mdYWRCp*= %8QcMXUWSMVN\KM@_k?`H%Enn#k#L5'cS^h8_EG,E/=AMss$OT=O)S]STuZXLiA4)rH"?C[TAZ=*^HI[FB*65%[Pb_=Pm]VopZg%7 %nuHP@#3@n\@-!!s;jM?B?Ls,T"fXopoI_P(m%eY>qRWjH(`QPr1bXfg1J54efXK(mE9]K31Eq"1GI5&&7rR=V4s(/s]aq>B:-lV[ %i(hQhYie'WcM2_"nUplZ2]P"2pbg1u46`Rr%L+nDi,T4UJHBH1a)7kR=F)$]SO'OpSN+d<ku+E"[%6Bmn`OHEhT,`XEN:4Lh^Xsr %iLlG?2KQ:hPal39K<:4!oF=CBZSRQCfll>gE(2Ei#A<H4-b&W+@]<)_?SRkj?sX+X-(&!t&"Hoj9YI%a5:S>>*fL^l(34_bbs,.; %4YC2V<<lj//PkZc60HB_mJ$99Ba#S\DIF<"Ej%%36'bQ06FfWm7fM2T#aU]6Y/;Y@Eh=Uc[s\39R%GARP;dA3!Eaom`eK)E*\htl %;/=m<b3qO"'TDUs=kfkn.(jK\)N>jN,?k3s`I5%t>[sAk0]Vn&<ie(g"gKY,2$toQQuo"`EK(FZpqOTWFe9)lZW@.-5m-3`/n9]f %!:lO]$,S:(^>=I7IN#sf<QPiW$)enEOW'-)RTS[k8RN+R)j)gD!X8Eaq$KX1gr)V7K-f/YZ4<:\5.5*:':CYdF'h2TjX-AY_%sTQ %<p+-V)8UPD`=c<c%4mC8bc)T9V>sXg8>inK+KN,k%SQm.9"uWWRMC2QpXM]5578FB@VT4h3qDGV9ff>RXT^M2/a^\Q'c*P[XSi8h %^a`l-j<+!/WYNHL)Zr0cYf"7%oedS6<dk\^[%-nO=X>VR$h^-VGKPP&r4T*cf^2n^()Rn1/B[$;4IU-tZBY.[6r!WK,MXj(DQ#*e %1eJrk.@]Do`b)]n$@")/BWDOGMp%V:6uHULHYp9&@h3a%m\!r-"gDK:>g@q.U(3*q6@ha5AKc,g[MTepWq+kf%I.+!6&oe:g]s7; %;Bt[%`R(KbA4NnMH*[u%3EnW$/`OT3]_.+M\AcZGIO;er(@/e&1)\Xg,\pA\@O,+nN2[h?G:li$)aV5_IIRc@q?5dI@C`qMX9$KG %K,fIm0pi##<Z1*DHa&2)+W"V)o"+0g'gn4')9'R<^@VEp[fVL',"U7kFCTqpg=cZ8GQuJV_9\1WC&8*^H.:K!%GhbZ6CjF3fQIcJ %Ia;_Y!cu5!AV#n>,46%^T;,H64)cH<due3X/[0!O^ucTc9L_\#A@;ZB<BGM/X:lu[9EE*G<JS-s9hF)M?]qR`IcL>G7c;3JZsuah %C16^31B:D85^@BG8!d=2+4qBZ]cQD62'K/6,J3>cQ9):6bML%1Tt.L=O$3JG\HIq(a0X>A6i8qFp#QPbpJbLP=)oS.$Wu%rC/d8F %n6T,SaclgB`Dr2SEbM0uR0?hC_7PtI%Pr\C!4.N1WT,="f9C"c'V\V0[jJ.Ub6?jKI=@+56u?FlJt"*?>gLNs?[@mb$T9RclAB]q %[DM813AOIW#)'7IjDhOHXDH(#.1SBb.dJ4t/)28t82rli"7-Gj\p\5@q'$U,\su_GB">ucbk7.PL+$b$W[lpZE>,^XCKUNe;@?`4 %4-D6*_mr3.WqcP4Y@umYYRjq_ouZ.4SX3A%)-n,$4Y:FQ84S'6I3jPO9j(fJoM]'M&('Ga,o,eLYj%:c.R9ruX?I[Jf$'+_URs1@ %^fmKDCEV1e6&ksqmb0fM38+6kNed#d@CCO?:;X:g9pHK##Qh-&B<s#`Q&K>WEl*?^N>%HGZUfCQHHYBLoqBp;AM)$*\%nP]QF9o( %#BM*WdS($dD6]L%7;i47,l!?[UQGV_k@H8T`%C?Zlq%Cn9l`J;o.Z!KK,1nC+jo`=/pE4_<P&8s$7ImSnB+Yn<EW6)G5)>Z>9%qZ %A`P@J+=-6jGO:<PGu&ScZ[&D?@V0*0/S;F`<+%DgRG#FWAX@A!+RC4=n_@)8<?Ua:<[ruL5e8gU?!K,$m8gI3b=6?[>)Ai-]>8l* %`/L%gQr--07196Z/5bJE]a%<m2D4)QNT4l(n+C"p(W]K4>KMSS_(8K==lC]KHAZE'A1_N8c"(2J2EO7,-`]2FN,AYf_>s'=k2PkV %36ZI\1K5nJX^c$GK#o51"`s3]hi#9,68RI7V-M2Oh0@.iDo(.;i'7kg0=rbDG"l2!Nm(*I6j9[VcB1VJK8UN6W#Fkkr'BRa@$(cW %+J'"dZM8,02'6o@A&H0![TgcaW4<TI_ANA3=#.mGI>m[0@F:I27k-GQ#0Dfm9?tGB?#@S$8c+gdGBGA^oaqAWZ3-M"Zt3!YG&%2. %<9#utF87k.J]&EIJS=FI"3G-qQ(K..>LWZG>cO&lhP_M1VK=RaMLa,+:@_tRQ.sQ5fV;%r3NAUO)l\nN\dm/s7@)T7EKaT4;W.ZO %3?5(]D>^Djm?p@G41CWfcau+-2065_qiA+IF)lg,rI&$A^J#pqn<>c(A_U*:FmORUDDD)[!P%p84_EeM)`L8[QTb'u2XpVH4G'OV %.sOac==[:PoDmJGm6TUN]8j"4.Mh[a!nO+HIX[5c.fq[aU*A23[W?k`FDMh6cYs0Zc>SW!$8hgP4UXI>@CYQD&>e;(+g)(^*?]:8 %$C8[8rG]7qhclqiQHD\95]s,58eO(Majc2BC%nIF^s[OYPIEHX\6;@7g!0t)/m6rG(*:7-[utk!=N1e/BeJI9pfT[EDN_SH["D+> %hp>:ZMMS;YSTAEcaS=g]iQ]El?.MAFFV8:gDZfU$;pa\U"Y^^?b=K[1Fc.g???@t6XLOG,OiePnKo<]CgEt6U#ENoB*iL^Z0_Wa9 %8*e55<&s,8V+1D!B?1/-,[fhU1W^0DfBM33`'RQ#Rs6EH3Uk7kG6:,XCWsX3O(tl%kMVpl7jdWU`Z?OaC(La+p$o\$FK7Q]dd1E> %KQ0TX+J&5ZKC6o!qF/pEPEo+S4(6]>L$)jg!7_r+8DQlAbc!!/\Jh:+W?*>DVtP8"j>H1h*CMhnQe_]VBij<pNnW;Y?5qG_[W9Eh %G3:@43!N4U7\,[7%#h3A1\ol*@6sB)@5/^IJ88%%/0BHsN8_JUF]9!T)An1M#4T39J=c#GO&.NQo_'tN"h$pH9+%VQV1<lo#"E.M %+Fq9X3Xqm%D%RZ)PROZ.E#muaOjQ@0+u1o%kBmP#c&56):b=;35&O2WK!WtB%1L7fROs8+-ad4M5q89"L+9ucnFb2fK6;N%Qt*@p %;TCHq>GOoG!7%>Km.\4?_B/CV#fksu%giLg]ftf9=jH[Y\n.^SBRI/V\n:;-b]g<H^_qB.DN9Z,Fu8oc?oUJ8BF:C0$9K6A(TouH %poX</H.B4T"4iHW)&InW,NM_J!mY./no/%u,b%u?qKPA,3NWiQs"t['A'1sq/cnPFXcD>F0_"/.QoiLohF77,Ru&^hP4RcV2bt;; %=LVRfgl2ZTmqEIiB0r(MC6$Gn'YoaR`Gh4!);C1E+6M>eYgZel:3b&p/_e;GD+6*\bP5HW'Di-q&N"aqf!T$fl'a^9),=hT)1K?] %/Fk7OD0*RqVurQ,gH6h(Q#m.uhn7Q'4sGKp_>=5MmYSN((2B9R=GujbFs^k[Md&I8c<sZ7EX<#F+lEX,I"0]Z\!oo6=TRsL_h\S! %>?rBP&OQ^,p^Hor!kP5ChN\-d+Kl6*K(HR6i"khs'JLc=G%38hS,YO$;1im#YQ_e!_l1mni4L]gG$Ro3aOm3mEZT4D(n8f.S-cV) %CjFIeW1"MobnM"m0fI-f+_>I,heM347/k%BloR:Z/!2X=])C)j2iL&n&[n^Zj'ND/+`"1u.lY8&VJ4kQ@2`OX^+bV6P9Z:OI4"4G %7Si:9;:V3-169^7[Q$r9K_^97g=mh.:K@O/kLZpPAC>o/7ZGXqfn66bk4"@\eWW\sF+q4DG]J+CVRN6?<TUuV]$2;B^6"M',=aK0 %>TuY.e`%V+:;jm<f1^9KkU&*)5E8IR:]1't<8I=l'GU2TpOcUPj>=-GG@X=_PS=1:l=&8o4gUQmpM/I.R2e3F1!!Y@qqp>U+YBoV %Qj0/V+h9&4l;:@._!0naEtpU*\nsnA/7!@)L99N+3.*mtms;B),DRCM`o^Iks3)c6i,t2/g-H(u63/e2BR%i3S1Z@\e94gVb[R39 %#!;?GieasC'#6O%*luN6+aub.QQ0h2fj_mpa7^^B!jHH;^lF2P)*;b7NsdD#HY(f6$VsbeJ$TC,6It3!p6=BkD%Y"FHJlu9!nc6g %_O$Z/TBXl3>[:skAF/&bUl$^gcb=KAJcG--YO*,Tq"aH#c<WA3lk_2DSl6)$()WB<A[,4DCYf6r.uNtEL+`Xm3rHGR#55,F[Ip2= %Rkt2S`o]+2b:(XNRh]^T@7E.R.AojWBct/""QZr7S74s'gD\`\oH5$aC>M>HU]>Gb:R+Lm-cQ!_4T.3J$!m..8EnX^b\]mi@XTD& %j/-DNk']aULnf@GL&06#c*,p6Z2%/hn*+q-ke!/LYW[L%55jH^;3\e)'*u\^j.YM7GECHP2gMQ8jN3[>'^1ACaa&h<YI?'<EFpW6 %'cQT.%f]kOGH)mGCE:/+k(/nlCA3oBTP[5+C,]@Gp<ETMJ8[\;_fE)=?1,j8A*5`7Z8@Z86OeD5Aoa*MW>gYiX#B'O=gZ/$W^!F, %)dpVN\:k!;)DfP0ej]M;T3#L:WmcQ:`ub$K4u[hID4*cVFSu\C^1l72#lb@T*Xi,*(?XbW,-sYJhR""r<HUQarcmksFK;6pgUW^9 %/4oXal$SnoC-upS'eh_Q?s/\.lPI`CD:/dRG5f1*[h#6&9jU,FMO*QKjY$E!V9(jG^fglF.H\X`P&rjDfqtue3(T3&q0ohKHjqlF %<Se4o/Z6(b<56+of*DWFfF4WmrQt$XIt!>1?+UQALSKE[gCEDB\4DoSR`-tmkPOQ4Pm5iY"_?CX""S9,"tHoYND^5()5bMgJ4(HU %H#7:N#BbOJn,`dXTP7ef?.@`Vg22-?PeUN7)@76okhDtQ_=I?DWE*@uNlh-pZ3@7\9"$u&mFhUl*%!%57]:E_=oJ;uh@C`DQtp!F %%Q![PFc/BoFTc(Z5Xi*f!O7+Fh8i9NEfi434^qhh&?pKfO8Q\Hdmqk=e"GaF9m:&2MEM@KhOQc8K9gs,0Z4'AIIr)mJ;7+K)ot`) %_7kX]&2=]XN-ajJjc#2bF*N<ENf`^M<!k0pK0A-Yj;sTT>@9m5k!%K=`O36Ji2;N,7SuRMXo5>Ur;"#r>hKncMk]Hfk`.63qRM`q %\uGZ[cmZ(d*])mc(aWL3J:ii^*!NQRAO=PQ;$-@]bDNK0hf^FeNZ,#.%BO-f"W4lnjPU9$Kl)0.M+YMAg^@>r61&V([]++"P-T8@ %(,8\;U=PY,H%otq[ai6`rPj@f4-;0T0/82)mA0/Y/agTmpr!a/R?koE(^E0Z42!5YS$^7SRI_0t:26R%#Sh<]TTi:HhSp2;R.[C9 %*G2ehFe+Y=?5$Y>oAc9(0kPp<]78n(H>n9r+2`Dq<LM[PR$5Vm$k4n0^,ATsn)4F"3a^HSFg]eJ-8rpbPQKKtU0@FkpACC7UR#n= %j?A/9a''NuKY10Y/#o&9r<MTKQEC7G*;P,@o?7^^E@dE_!%u\(P&4;(a9SXg6Je!Z(EJ^0^lk.[^HTdZ:d<9BPMS&N;p)s0ks8n: %p;6I'#0(&-9UH-aOG0uIBM3u[73r)Y]Og9AMO@n4q5Edu,o;+(+PfqYTN#g.QCZK5jO&(r6^UBC%Xt,Wi>IkRSr1a*!Z9.NO5_!q %BVYllXH]f]%VClia$=)Gm@)d[R(R&CpD:brTJ;$39?L4oQip0"i`Lp_&[]S/][OV8oljG->o9<,iS;XTqtb!"hcIfHB\RW+GTOtM %X9,[4aSB6?>eC,u&jGZ;L.Yce__a?5e#V-ZW1jO<K_,N)@W.FF1CpBM[c<hM/-E/@2Z_Mci>&e</cLB:=s,b6Y@4,`f*0-TX7Q'; %01u<L+0:!j+O-SpDq`5SUJi]!;;t]#A2EPJpH[Jj!!LP]&"XhKf.JXB5_e:`.r7MkcirdsFm-#:(6faKUM[J\;6GTjRhF7HO@sRr %<j]R(j^3Y#iQ;kh!)^^d+:gk)7B]6%:(no%TsrOp">i$>WKd!nfGQ4Aegn'&jar^eOpSA^\.fL*q58@O9?15S736ZQVDH:,*/q2n %s6%GpgOK'5_7.WGrY$t%RM88e;qnX1RFH#TNsu2]d4cUR]:[/g7NdA>^>a*+l4+>QNN2ORhIe.166!=KA&_WFY&q%a(oPQ1es;W7 %_X$=QOl_;J@",XAj?::7_5m,-B-c^n=`2kki5gVa,lblA5crd6%i2H)fbbndHHH(l8aWZa06>(KI,Xfse^E38hVdYb^*)J6AhBlP %?%c1+"#-QVUh]GGPmQW-%<K<3#dPgDM1L>u57,B]BJ:Z:=(WeM2a[]FHQ<L"mW8=s#3W]s^rg1tm(rt0)2(0Fi:H!DI/M`K`d,e! %FGgRH5B4t)ATLMe3qGpZO^5P0I?gOOdTgO>3Q*n(IX]4)&2>>KGUZ`V=iQ-e9hTYmg>Ekt!Xc#W2a\C'f?5S!-@ioOIFl[3%G`0` %EZh4Xqa["-g4El">,!M-#\I9>2ZcU4PZP*:hfUmXqYkUF6p/d$*a*tMUH2Rs)/55k+!2^Y]k,5&=P]u59chm"/u=$gakQHDn01"q %AL^7^'U73DC,0YLGY9'\@c6OLC8oj+!ahZVj]TiIio+,qAQT(G!h!d=9N,^&SYUCn0%`H%:gc%5r!1ree:7LCgP<&C$.aH3l&W$[ %jo*qWV40OU#W^aX<ORncs"EPAC[+1[r1AMqf\u=K0qJVcrE+s_ZG7c\?9Ve*M86LZRLAVPJgG9Wd"&Et(o\LG%<^ntp3]'k_Mors %YFM._YC7",'^ul[WkL,'Gesu+N)4.mV"q5FCl1ILG5Zr_K@O7V#,aYP(*^3cTblbl3M@FEY[SPFZ`$Esr6`pt&,WhOFSQf%d4h(+ %NcRg.E>lZaB^XS)_M%D`[W)J=k#f'V#BYtaRV6)R+[!1Z03N)Ti*`ZE=tSJ+lP11K6&Mf4Z5?'hPd%N@rYcTt+)7ukbJ@LZVQ1g( %"t5Y5%_=H90_V)b2#-ak*s[#ndiV_ccpW#Dlu_g&#-q_=a,Z_\Nr@_(l3cHd"%6#(r&.:uGd!t2'jc_/4OgK?n5X?$`>ZgYH\ks6 %HB>4%C2J9OB]TlI('FE0_1_\[9/u1Y!XrnL+A5?3_\u"a\r;4tnBNL,!meMQaKF44LmMpG;&+s<4AS9_WqqPnfV2(d+Y)I@`1Qc, %.2CW4?QUNZ9)c"[lY(KKl8!WXl*%='J<+Ac1('ij-E35ET4!0IqWPMjOM]T$2NVG'"QVk6*+%b+m*hf.`\c5n!VF%B!:d,92o=tS %q$u2d)H.YJ%m6VQ;$Lep0Kg9VLH4,D(:\r8Uk-X)-50Wc>`PM03PG;?jHn9Gc0N5N&4=W@;b\oE=ShI[QnJTq!N8*6G"^,oDnmpT %WHXHff?]N/==27=N)R@'<V9?U5n.VDWd^:Kg1t;.DOsp`NM[%^Uj97/En;@[!Sl^*0U$uaK-<bdd#<;*[ii;*8q<*fbi55fEeq\3 %h%$FCki7M%#OoHtK+GF5eNDqO#u?\=-3'ek+9;H7U0(sAI'p@iS9o3,'-'foXZT$0#$ZeHf-$gL\/EBRf",cB(Ti^abV..7g\5.0 %Q3L3uC_opkY-fiXU_^IQM*@@$#?`Xn"hA@Q!<pZa$I!C)_Q#&gONXo<I1*ng3=<P.f%Ut-h,7'U+mf=,]&/#l&rZnEgJSr$Rr.bI %+1t>FRN=5Lo)S,"2kMFi2P8E[j]EuY>>DskE[upW*d%.jc%%+LYE)NX\T?]#oJEtA5CqfpB&(#Ii(-!I#-,c@%#iB9Xr,]Pqa7uR %PU5/S/c:%5,\.[a%HR*]Nll?IOp##>'i;^m)9LW89beMaOfk0PBe(o7_u9C9IV29:%\F0F2uPCs;(?D_?6YpQjJ:]:OLDR]e`Bdh %]gh?qdh6lYT-%QY;Bj3+DBRP]?A_C:m!ZYn3pn8AW?.Gij@GbUp4.,JJR8&XV;1B:Y/BW_IKtaAT`eVcs&6oTYq2+WV[:FS6JEuW %4]&B"\Gf&blP;u+()%0%H[Aa0=)L&>Uj]5-D,>I+>7ccXbs9354JG<a3/C(iY,KYpFWUs,4fC;$a[t8Rn(&TZYjQAcK)B)U7]gB/ %;Yi4(D-RFZ[tnB"7uFb*0=K__ps:4@cT%j2D#:Oh!GWr3USLSE4G*HFaFdKjSUr$ca!r/gpcrrcV+&(M\Co<'p4Wl-N9B@<KP:#G %TJb[.iS@?b.rZ&qq>O)mQ+AZ&o\5B@S@ar9Dr8bDEUYXS[^aKS!O"eRNT+NjS'%Hpd/(>?L25@6BJYTGl)\huSY-IQ>LhJRqp!:R %V>'YgEcRq"=f23;[e@0-.A1Ml'QA_"J%22QM7^3r#1fs<"_,JW.8%PN[uHOYIG$pKE4]\jqJaV^PlU=;%N>#&oX_UPA[lNq?q2,? %FS`ZbbR\%<V7EQ_B15'<;4Va<^,WUcoO@&*ffRW7X(u\b`fsYb?SJQ)LlJg&$mZib1PM$?A^Gi4(3N#28klmL?<4&BbsZh,[i>"9 %+6n#bOW`b@'(rBDkX6d5E#BK*+WrYeMI@1sZ'Zo4BZAA^:9q8$@Z,r3s21UTm];+>2i<LIOkWD']n:f^h_ob%4,=FkK(6&R.$FIg %V:\09L):S]7Z\FbE;F.Y$a9Ln!@+C3X9$9Ogd/kHdE4bc.+KQ^%ftWbkWQ^-nd>L15:(Ns#1@YA5eh8e^'Ju4[e6</\mNX:eQ'3R %<i!$4H\EB,\k:/eSsf:QO_OH9HpRgbd&clZS/dRq<tfYC#Z/uREBIEm$o2RG"7f:hUB_ZA-WXFZ"cPEVYmqO<U\Zth$H%#(b^8jr %=u+5VI2Wakp`<)7\)l?!f3fT$VW,paQLGNlUS+R862<u8[4IA:1=3!nWn9#u"4ijVYfNLJ\iQ<48b/-$O5GLYAm%#OMal78O9o9% %>;7uiABEB?BMsVR9`a#lg?R[N072(3Y/0qV\QtLmGqW<@2$_kde5q`eeQ6E,6;1O8LP&]JmTU%0*VHUsZ"(/Ob%GN55IoKF)k7kI %K"b+^oeJAGR9O%"Jc&tl.VlXTrR%qDXfN#^_5n9G`sU,(3.QU>:i0dcA]W>`B2os\e[!K3GNYtgrnS/kkGKBOKr%YKpu9Jo<+5$k %;e-^SFf"k]#2N*Wq>$bcLpDZSHAPOuBV_d_.85Y[#\[VF:r:>V!g4/m)g1I`&$i9FJ(P^>)/%L&M@J^MY^rN';DfG?&.DdfWg,'3 %#*=q!0?mSJ=UWNUU4RYj<)B`TWAU`6Sj$nskYr;=G&u#nR<a"UM_45MrFe-F2>ArIX,"VP't@5&f=D#:=sTF+D,!9<CFd8u.Kuh` %pl^"ub4*q-K/GFe7,:g3;UM=JD;RHkc"oIe&r'f,qlEr4>em1lNTsf9#Se:Q%SJ@rhA0Z=J$drH5^l/q<WlB?Q`AP>F(:1XDbe4Y %73^h<A-bR.3>(!_BNlR2T-%S/*#eCj%3UuH5V=eHeKcD85UlVuMijWo!g$R'if>>*ku%<aVoQ$h8c2ir\O$FXM)bJu6M:2M'Z7om %m.4_'=X::k+-*IIGW9T@A]:UM?UX$*d2oGB=l;&Zk_<)mW^?+=JG.mP_NL4c'M=\;eCk\ZfcqSgPp5"cXj?^LR1oMM7j#O8m<):X %*b9(:B,X:@gA8tUDcVcm5.0LgVB0!USYNPuJ$V/f8H7mdfAY\hl`c,@0[$jMfW+u&K&,nB-JH<LYbYGkgFQZ8X-iB)oaQ.7g;[N= %frYtJ4q(N+JIF*dp$6+@cgt[O:ADB`X;1AYV.p-maiY6g@urITkQ#%EiE)fT,SKD7b"O1R#-#T7$FZoPl:.(cTIu_`/c-/R/_2D1 %cWT>m>*iNTqB($+C8T&"cGfG.5ai`5.&@>MC"J-:]qg:b5]d%a[)Lio@YU^*9TR*i5WiFs:D4Cd"3Xq%Y94?S:]qJ7?CE3"$VL=A %kbe<pg`_!:%/?q^0mK1&b&lJ'6l3!FSZ).&Vc;u]gcru..KZ&<$@jo1.NfJp]'KKoab6N"H!$r_QE=4d?!Du'A]q*M29dq'V($B3 %+s^/c\s.<9V^qqQ?o`M.p2_\Ioa4[Hs6@;"#qBjo:*-C@Ush]2(R/oFgSRJGWc7JC69qF<f'>pDE.'Gi18i]KWC'Rm+tXcs<RKG# %`AT>+XA6l)XP1]fB'**Q@G$K&nU$Q8:,@.`<L/Nf4D+82Fu[OH`[)FHrs7lJd#X:VP[5539'QlIZM>72`QKK*Q!e^7XU3I"b*mD5 %<0Na*UpB!j3m&@7T9r=+#4bUkBl&I);idF560XS:Z/&DZrZ67)<\^/kc_Qj"S1RGQ\S\\Y@>AR3/hE2r)Tl]j8[Mp>O+Wj#D[[qt %DN4cbAc2HCgZDA*RjJ:Ip,UYaX0(T`\J_k<FkQ`Sr[h"Krpb2L#Itl)];#WCKdVokm;8D-9hR.iUpVd.FfPSul^$>;CR7%Z2=Kh] %'!q[l"^:?J9`QisdKA]lj"!C4r&(#1U=#;;n."Sc39=&sYVJd/Pp:Nj*[MbjaVBJl:$nt7;B[\fN,&?!h+gQSTjbh5\_@U?&&qPH %mU*m#ceke,cp\lX1[TfTSaYM2C/(B,ZKVXd$k@.W:u3LsL>)GC;ni2iM<*r!o4:P6A6B/)"4Y-ocL4r;<ph3?(X,0-2=<1CTXI1t %Usr/<G,,<M.0fOQ#4bW.*E:'_gB-t9UnBB$E=?A(egiS=I9j6sXL?B57scaL(g`M@*01bY=<2%[q:<qDk!\/daV.+nW]VM++cm[7 %<A`/#.[lB4+/KX-0!AGUC>Goi1_:s3eLW;kZ79Bcb+N?cXq]ephgC24(2L)12\<o!"=X<c]ZOa5"g$l`^fhrp3fH=U%S?s3i^oaa %Du93CGd.Z<d!hhWY00PS=+;r=M]1GX._igHZ%ClAI1(?P`;"2uEMbd<"$&B[S#-P,4=mD93lA6K0RQj;qPkZV\^)j2n;MQUgsJS] %B>nr$[VnIBqir*>D1@"nI:29Ih#>HAQ:gYUYJnkXgbm#AVc]3fWV^?J5O:&fpQMY/\d2ln_:n\[d<;'-J=%mi]#h?k=J&c_Oa_eu %fLXh+:5\Si-?DUAR;<&<6^RqbCWUmJ4'Q&mf'@X-,9T/"g/8p^.Q?2C]"6@oY'YoueTH4P!n]F0hgH`30usuaq?gAM;5Ile7eYaR %!`77+n0fDd6!JZN61c:FAL\`l.U?)*L(N!NR[Fl*e@&NZZ:cL"DQsEMb:B58Aq,O1g5_N'TWe5^5T<i5B\Qi"BLbZ88R,ZrBdG], %VbC9a3X>hWcFCDUB_@T$@u5eO^ejOfWSTH3/qnCU$V5%Donq051?)KgB\=G<4f`!:G6nJ1EgqX!V^rCbc'5%ibq4&m=$;Gd0NGUs %UKsbsR`6+[=kIi`"#ah>'Um$bm8<]g[I[kEf,%.oS.:CgI>t3CA`U1^"^XEN.$6ME\m\3>R'1':WjPGbq1(K3e;0sWK!@nZ,u+Tn %DDMBjK;gZY(gpak.9&?Pc*mJ)3nW[#l#;*id_iQOV7o)f8i=oX#>["ZIdk"-kVNq7(7hXSEU%CL5Yt9?pi777Me:Z.j@Yku%WCul %BhePOW@N*&HIXEoD<:Jpi5lA6Jk%j)9=*C/0&*SPqjE,8ASp+[6T&YKVnHY+Zb0/g7<WaGSYH5$*,$2s=h">S\TQ'u_hWB6@4RuO %U>$EoWC19_T``W=1Cc.aq];!&,KN3'@T3C'"a;(OIh,4.k40nf7rfB3kE,g0iK-H8QjQCIjhAcu$kU-KJeV%#^-_\.T,n9s.X\7E %%+;hm!\ur)?_Q8i!#b8+a*)B*i/.S1%GZuEJd+hbp,64B*JA4!+<B5/GIP$QN40iB3*35j&l<'\md^u5^3RB.kJu6+Hgp?2Cn9A/ %)$)(tXXG8DV<D"c5j_%`I,'@)19i\;a*Rhh+Vd2k0SCKefmeI09p>Q9"4J_.5T7XC&l2;lQ*TmZjHFCV'miC='>KUNYdqX\KRt-7 %OO7,M6pf*"SlOMnP@k_@nacqXekLgPBI#_]_0FjpU6E$N*;3Vu\"+Z5^^q[Z#m!^CW^B5/QBe_+A_(a<`h6>?;?O`M5`e-:>DYWr %WT>gqpO[_ap!JOa64muEOiGqcDW`jW3'><bWj\(^VP#2cAeL:SJQBSB2diXe*R6dKIfQ28N<4buXh#f=Ie=%]a['GcU%D@j1"1:r %7T8q8SOf"g=.`M[/745'^5QIGf^sW^IuAe;L#-B?j[$/0'T#&*65=oFE1oK$FVIu@>R\NqB`Z4i$:0R`k.6R,&mUS,@\DU]YEfT* %n@hSHaX\kC1.+AMKpM'+qH@-1#-K<q#,W7?Q[-<A#G6JnTH9C^W,<cNk4<*LD$mLpMrbf4bHa)Gmo[5S<QJM7Tsk2W6RP,@jJt!^ %)8$3tU(6rWi,PieV=XL;b0A82D369r_'CQefU9Z's5m1(;28HPM@A:C`m#2<:`,$U#"C2<U*_Y^RVj9*qng\XfPch#??"a##-1=c %W'4J&m(J"m(M3)VPMI^DO-MNUn0rT-jmmQ7WS,#9rL>FfZ+Y\^\fEP-i^0M]dPD\a(2a"DRSG2kK`HhC@:\;FSZkj4"0I44Ooi(' %;t?CXUC+3#";r%VGZtY_LXS:qFP.IHKP@lAmPrr??bo?LF"o;4I8,Yc>?HK\Q=97+h8,_b/u(8!]a%ckOMY^!86]K@Rja)'CDn7& %?fMI_o:oI@e@:WA::\3=H**Q@dV>Ygo`F4Z?A8cC2=GLm/YcALBuF]:rA%*S[^9nI<mnhV;K`)tp?,i'8Dg0F.@'L&N=up*XCd.X %(9>Cs2*M<nU2i8]&KWpt.O^)i!#5JSR6;sCbK)ej2^D5/0O,.n7u1EDhu=\1,usFR=q?D+V.">o!2K-(c5s5T<(je#QNa5=+3L\4 %g=!&H7Yq1d&KBNo]ZpCOLNXKLXu6;pmnmR^JKd@q,muiYlUh]1/gF9;#h3bLg,<m,);rt0)KGE;>6,E7*r9<4>7_gM(5N=8BJtr- %c0S$j0!QE+AA#u!*7J9!i\9A&/*cB)fEbTV)(UieH?3PcJ_D&D)!'7l&8Cq+f&oPAgIsd:i9i`n^*.jmC.Lqtosuoaos+R3aa2^- %VC[)uk%E+W-5N*I3+;t="'qD(ouUcoI08&jEFU$neGMoX?WdlR!F$)Wb*Ygi5oMhRku$#+XbO:V\O\#gWg5I-!aL!*V:rZ,0[:*` %dO7p`B':q3)&/TDTWWnb.G!n/a0a=J9Y5ISeJ4>,+[)",gg-6=9X`>Y:,8r_D4_%03gK<6Y&9%23)b87;,'Y9BRU@>(6Srrr]p"8 %Q0XQ-Hmr&^:G(Cm"fGj6_=W;FDV+gJ<l8Ml_mHj#257hE!eoQ1"c/YSoLj1J0@(3CEO73SP]HpKFn$27YnX%kIae#B7ot'o6!i<' %NieuOMSB>rm7+<s)m61WYH#qHhD`!WnP3"2C]O/"L>eF"Cq*6iji].f0#NZ@D?tQ\Pfpj$D0[FnO/4d=H2Y=;25u&Pqs1#"XM#D; %:;t+ei,VP:s!5_;+\7W/*NOne`,/>3=NKR*k#gYE=EN+@@%P]@KCW#qj'(OkRC-@Y76o\.d4O4i$O4e_hR+;);Nn!TgU;%:iDI8) %_ZJ3>Y-Ds];0[$DPs%SU5ZUVD,E"#o3f$ZZ7P<Y*!(SptH`0oC_9l\)*%IUR^WE6SRCN+S=jTkj;G"R"0H0]&*4kLBAr09$&Wgd" %/"t&G?=(+Dp/Rc^\'3P`ZG`aYM_%=4O?7+D6*=kfJI7KVnPK8k6UZE0[ZpoA2$Qr2:^'C$5R#ukpTKplCH_#+5juO)DmK`-2d`Z# %XgdA]iUk2pPhJ#'0'XRRi8XORZauoLJ#J+TV4,97?24iomJ6Y&Bpf\sjTp;hf!q!L-sOKgXd4N@/-ajn&DqHQ(UK+0Xib0Uh8&][ %dRg=jGP/A47UQ%>8qC+c'u9eBhgjIq]G'4B#IEj#:)45<\4ZhbEGJe:H/=0c@n54_DrY7t\1O-;5c4hal94W\]_CAn=_Ch`L:rP* %#.50o0ib/S4sJaATIA7rbJQs;)\@Fo/rG`Plf's(Qc7ak2qI5YaL9jIEDm%R_'!AfcU"5&D3#%haf%LW['CiWR[(Mf7!)\ar)OAo %`$q?eM+]<p!h6]acLQ>H.l7:nf#b;Q0%F7uK;F_"#`8W;4ffS!EP@*,IFn0EfQr(K:/tVe92Pq&W\f@eRV-RX+B]>+PaWbBBbf1X %nblltL%iE4fg4ENm^j*Y,nA,"PKPjp*d!KlI4h;l;$-Ns]8YVCYd4BIlVT:m'0"CMKH=_JA=+[HWs2n^_SEjhT,qUgRpUdF%^U(j %h>V]0q17,6YWj1H^=XoP1+r<Vk6N++I=uEL>IChMb?"]q\t(01"-WeEk(U^9h,cZ.dhIp`(U/TLU@ZbMS>9T#D)RKq^15llJp+W# %)!o4/e`<-8eSLC#?NhG$dBhL89L?5jbo]$6%5@.&#4JKudFtlY7Vd8us'W[k2BosA0FV4nFt7+GmGQ)YUh)_GE%PQVA'#-kEKRWD %)0h7DO1)X;X4&Aa8@8X!2ddIm'-)AGg(lZC]L`5(E_6?YpE50ap0aNdqrJPt5W>J[<XX#J"+8=9'1Z1hL92Kf*!Xgc4bMN&<h&Ea %i1\q?"^gm"g@du>VtR'Y\%piTBcHSahguXtZJQ!3\5_!h"kWRM$Hlj$[dgq*_'t3pCg]gf8^$6M%r#6B\1^[Hh6e3/PsD7%_+FN, %>L+AVVseYq3`9ag[,dIq=Gb\a_i;ep_o'BpR(G;ds)=VWgs:Xl^agoP1Zk%fLrmsNoW$5E0@*GZ!M3X&Y34@2%'jG/!"GNe42;N: %SR4KF%G\G)r0;8V-eo7+>8%?11WZ>SH44p;3Nc#=&hP<23`L"\$Drh33_sIRhghk$;3reXA%cE$R"0-/'-+[<p+jiI."unYR;K-B %]S5'Q228)aUrh1[05&Dl_NoV\#B3\HF^>m/M8,srO)"YtY3aU#fA[B@G[XLb??JZ\YNq*LmFSq=([Qh<m1-"[P.[pi91deEDh\@o %or5*K@O[3s-r!l%J(]"e(a;H'JE#dJ7cj-N*Ytjd!IEZ4m`JY(%O0V_+9fDpqc<"/K<L=Gn"FLqLHo52m(n+^P=-r>1+m.DBV:hR %`\B=%hKHUqlj^IY.<0`h19ei$p]biX&P]$VK@72>`3]e6`.sTaZh9ucQ8Uc44.&n\/;mPm97rJ]@5iqDlY&k$nD73)Qu=OFC5"7? %T$2-;6&f]K"l!uh&%(_(YJ?9K.f^pR;*Z!GAL`V[[jF7A`ZQ=*8R2bS):_9)HuGEajnft>g5lYR0i%*OS.FY#%cZj3fa?8/RG3/' %oO"2SiKs1Mr6Ts`Jg!B(5i8p`cU5)Cpk^%SF)19/#Uk.b)V/N[=#dsg$4r<T;X8FWF2E;,;Q:Y%V$CR>Y?4Sk75_C.$D>(6`_3rY %)6V\#6/h0I"mejj8h.X&O0NQ)U^WXXh;Y3ZADQ2!39jo]]T-KIfoBg_AacZ@aF70N6;.%1fs>VMlFR$V'^B61EX^g5/MN53(#\"0 %Lh.\.B2D@SHJ"p2f6lCm^p:O1!D)V)YE5W+RE;-jN,)9pEc,&W`]d)V_"\'nj3qPqY``+U55SX/rg^]4l*E1%>$BL;V\jVI<N-\o %Zi:?4T%=9Un#aobLM>(kQD%Y"*!&\oJ5bNE3/5W'045I/o+mpLYE'8bL5^^YC4X\]^\WcfpYL?$\m'mjW#rC%;<rH7@LU7P+DpF` %D^3G$#Xs*15GEYZoIGERbgWUZ5!)H!Q-<5/ohk8eDqf^cPosCVm"#STK(O];UY8do&b'QqS=3[mN?qf2YM_uE."TX.4l+jc+7^1H %6N_9E)@H94!n.rc,3Xr"CQ'k@dA]0l2bYPhlWDE8K;i9"cI#VmDaFD8YOa[,lGV#RboM@F0\f%fFl*[&I`CO3CTr2VqW'X@04/oc %1YN6f!P'8PV)g*\.W]j)ppkQjM9+CN=I*YA>NW!blXN?/l[E\Sk>n.,F\_-l>3Abr<ULj'j/>nc_9u73511g,P!5LQ6hU(77Q$k= %RQ?)0/<"MCfU4JY%>OWSdE9agHWbfp/aQU"3OSh"X=jfFje'X!=&RG/!quR42n3e%(?fi1[0O8!'@b",rB?XsXJ-%g^nV*0)na*: %&d'3%P;PgKS%1.iEa:2#^?5anfO6KT$06R(q!mqP\R.$GdILi"cIE_gH.IVUdD4kR!:C_)EEQ3("d@RCgXcN[;1$ZA0!7"-`>$/& %%\E%"Jp/'R"FI!N<+a+,@Df7BPFE_5,JaojT7u&h^8]`u)jk2!%GpMeH"fpU4P:M+([7q&7ff`/JTPfhY^G\0Y.+?9G`EJJ0q^Fd %B%[h=o5[QtE9]851n1>CC8BEcMrD>2@sEY6F:\'NqVn<$I>SnbO_X^_/AuDp9$<u;\u(!jHE+1%^b^A-,IgD\Cu8BXfO/pM\tpB_ %d0?bo[WY#b$8CtnLf@kInm]l./MQ\IB5N73?c.*.!1,RUOfM:k=Z!<`M\ZQeF`%f/0nN82f0E,j%fm$dZQ^Ms`IFRu<5)%=Z%6Zn %H?TDUZc%nl>/nI[XVoq^2_Y`IHTT3Kr5Zh`9A="gLO0-(>AMZ9[>-L4:-_Id$]X0I\+SIo"\f"$_a.kliT2TpOKT&]<</QI$9guC %*/rP]37$QQLLWCK4F?3*o*__g!2KOk\=fHGn@:6FQai;j^_MUecG7U2#)EMpK3.4*Sf[0EX8DQNT"Q:Pf^kV!\AoioZHH8E,Q7A& %oG>u"?8B[N\U=*R4KSfO,8Xc!oQ#CI^p@*c=07&.FK;/n^akq6lMOU@]r/QQ/$)YNMZ;8cAN9ao0_$"kJCAQJ4kM!r6=%sheeu!o %lPB8c/21?J[JT7ggW>&XYs^0:dt/kc4^pc6R]S`MiQXLE#<TL)rpsWQiGJ$+r:1'gQS3<J"4*9j\FTo&WhiC6%AFU@@.8?3EsiiK %D%TsuV.LQr_:'7,n/cDLOF[s]jE:R0%]Wa2,U:J_A15I,i,Q]t$`OhZ/aMuuY[C)u(2Q,^31$q&LaMAIEq&ZhJ@$niU]:Hg5`BOl %Zc0!>[L/n]B;*P.,A=\dE-;WkfX>X0gNi4mnVmT\msOhuPq`Nfka"q`QOFL@Ml<ABJ=ji>^p,9!6=$8jIA>Z!i2^b\E\8+%p1,/' %@306*ACk7TiF1:mC/QkMCco]TM5G%'Hd$VjcU!PhVPS:Fa-Ps`-)=@\;^GJrlf#ri._fj^d(*CK]S%\&d&a069jSaZi:RF7hQi!H %(adYIT$p4t!;Z5-<8do,TSV+I')]\/YB/T.1r)oq^JuG`Le)I-W/?h.i#b<jd;;ljAH`Pg8%>Hk<+A+n?j;3@E%S&_`$Y6c!S>$p %;5^-X2l3.hH+O4p/=.1Wo+Ih-L8:LtfX%*&$d\_MXtX8Z)7oG*,9%[i[*oQj/%6T-aM&\6o$c@U'sBlU<r5hdHDU/_E^OVZ$!%U\ %]1l>=[:PZk@1HrPSdXrb>75Cai'IrJ6XT;gMUcbVj3unnHmc0`qt&p(NL#lE[kYDTgkQtA%*mMqDsRH1cGgs1s&Lj6Hog"_'TT_M %pD@JB+0j6Z^_!+%:<oKpe6h#Ee6<]U1*<@O$kr(gc`bE]nPMLT.nJdHR]CmA2M!q<1)2oS5GQ+X%:o.9"s3B5i9//5p<d&5qi2MA %l;8I&,QboKUnAZjrci.HQDfrSZe(7M9PVT=Zpq%NpDN+OhNbJ0VLbiE]q0/O9hVrbQ@VfdQYD@&38!5tD$b&%T0EU3/ZuQ/=M\!p %/SXs6M,(^9mgot!s!:MKeuH4/#M1IQ6UlQtoI/mmU-n^2g@i+.>Ue4Rg5i%.[7d8n4:,C<P+UpB<aW1.5kUGoDQ[oM3u:!4Ag8>R %S9UE^l4;3PU17Z5X!PE<1KU<klD$1TfjB27dm:hRl;L:H6FB5R_H33e'%11"bAn+X=)]Id`':\qBWug1(-,E*-#IG%7;>Ps-9u#% %68m2#4beAS6U9pF&m/$`f-1i)\It>$%>_?Fi39=u+APW?M%?UPCe;_G?BR!J92L5+'_DC'EOf,u\3.MMZt`R)LFh=T)8l"Nes-,< %ekGN3lj'SSc7-8hJ-,]+4K(Y7pf.].Giq_`-?[5!Z3irb.42o!<o8eVr1(%`Zlqk&WRPs3.m[Al3J,.-k\U^OO]AUo0Ur5;]15EU %q/R/5CkOgP8.jKd!%HOrMdiVLqj&U:TU%;]fDZ]N99E<*r[RRj8hH?$pS(b_M8)rSX44i^*b>2],%94BEjY#I0Cr#u]Pb6]Q?cbV %V%?d8cNc.AnspRjg(j]kg:3CJ/<'kU%8JGNJVqXiif^_QTlDXt7hWhg8eU7tW=,e*Ma8mg*6Csn*mF4@3\+*db-ikVaa(cFCn38m %9L?_W<OSYl+BJ3:+qQ9"QnT5@XY.G-n.aTLZFC7\OVqtrqZ>GOP)(')*TV;HL"81*D7doPoI<+P^p_?]e-.+e;=>@c[L@OYH&st9 %&ulAfaZi53r<45tYY+j*_nC#.Q/On3-=1,12RmUO(bOeN3'=4qh$mrrW4YG!_ee1#]ZRsh]hK07YZg9B'WUI/KDhc#Mu"/,-khHd %\>E[dJg?29ALOtMA8N(/[5P-e5a,ZPd[(]PX%7_i+GN7T,dk$k`=(e"4=j((oMKH?dtQE-.[X*ACd#iK:1#0Rbq9!cVUcRP0Gq;] %.,?AP>K4)$^=rgq>7I\.b)1^t]X"Z"Q]liY@"m`#\L>t+4+FMeaa!rLY>B1Ug^<0Z?\]&MK?rLE.gE9Ao\66g)\*`hD2/4MG2%27 %V*S+B6s=G]qY<Y7A#kc,5t1fV(04=jd:N]cBi0bQW`K@2.S)hi`HH@<?<]Tl.<nc08kRRDD0?I/-,Dmp'V;W8VWskJ.t!!F:rprc %bTbN1&[hJTA\dVKTg285kluJ'"pG^b.b4*o#-qG55<hW)21tlGbW>+(#8.U>[Te.4i>#`lPVUjbJJRFO>W>P3DQloI]f<uoa1'83 %W7Nq6Qr)&s8%UI?!\D+<idPnSWIe.PMHX<N\rmheC+o=P\upk'?ZueMjp_M!]s(M[]WUL9_a0`X?j"m$9#frV?"YF4GF&#:MgS9\ %.5!K=!am<.9FlAsoDE*HNo%m"`q).dGgDT[,5LU7J')mbc_-Y,cC*b&"7MDWJ^<k+>laWW;7O'tXaSb;kRfU7(n9@7=7^8\F1M@\ %jj?,U=kX(i\m`]aSp>hBStGiXnXS-!LA>%]dh4AM2fk*'Cc?k-K0>EDVHN\F=23o:]Yco*J?q=b$s[X)s7+N\`>igSZ:qI[ABNp[ %"<<c?.g`[$:iH_E])nb:3<m/K_)%H&7e"WP/s0pQD5`fLK4jK+b;"ql5e[;.EsdV47Ki)"!:r<f&*,RAN6e3tJ:!p^Ljg:IDUVe< %j`%9;0gE\sb'6)@D=P="=gl)cI<=6(aS#$;B=`u`.nj]M#Me)e1OuVN'_mO\^)Re1<>]2UR30[:V"9i8`LD:K'C5`-COL;lG59Bp %cAYkh'/?KrgbraiDDq/g`,@3W2Nk<M!N-1pHE^">B1Z<LX=\>o[H3sd9a+`-*r%JT]r\:F1mjHKJRK)9Ym7uZXNru:BHPq+N\,4" %[NZ7\cJ]66cY;Jqg"Q-#QRU$&:epG(e?f/IgQ&K,>W;6JP6Y:7/?1n9i>3L2DgQJo5k;(d^Ma7'69BF)W9e]IPkJ6R2lI",e4JjN %osNs7[f+O5Z)tnET'fmh-*ruR[^Y$<ZrB5UXOqi$"8T6`cBW.#Zj#5,ej,83&al92%$'teb=XhDIkMpf+po_X[k]HjirKkLpA1Q2 %Ooj8jg%K.lEP!:.l&`<3'rlUh%?*i[Bo!f=92T&i4q/Pkp7T)##@(S:"e6GLdGR,6$C'"4_)3Gt=s$X-I0C5PHr8L#ZK2mf"h0]( %dn;tCnAhc\U?sUMi3sXo#8,FuT>S4@THEOe"1r_(98H7Q&Q$rO.1A)p,+q-rZO>$OI`]_5q"<&/R;^fNYfaD?B+gcVY120G97.Gh %m3$(D]huR_>2Q]2odG%17u]i`c'#V>K[;j\\eM:PgH@'F/HbT@aPkaW\N[IY;DHO22_=2Zp,O<_*M"BLoYK\M)#C#po[t9jg4'"a %)4pCIn,6XL'.U4lr;&E&Nb.uRqf>`lrDPlkphe_th]F0+S;2C]J>]_HWqO!l+>iOCG=Q>hfTopI8[C0Ia#Y]2%H^Q*@&^a)@9aDJ %*=Hi>Q^;8-Ye4i[Gig^8%(fXJejX3=f\;kA],`ErhgoRo&q588BR;bcGkT_(dr(kj"o3U[-;FAbrH4`,E8&@9T\st?7fC-KgtQ0W %<hK_s*lo_\hFcN/LPAL6C>$U7M`?i-G0cc)C\K7(jOmGg4\76/@8sT@4qU6>^`@Xdg6;k@!4N]RalR-4;Y)I+pVUa($g,d<Id"I$ %cXR,c0!9@*rm)\dbQ%OUrZD1=J,H5EqXm)Pli6k>rh'5if5L]D"8uU,qt#=;p-52LZi<2'?Cr25I.1l])o\HBLP6+S?%Z>(5p")7 %$R'cS0O.la9*sb^Xi/I0!Bu:tcLi0@f"gUeoQn)Y@nRDB$F)f88Ae\N(bL-d+_+9_4"_0\@AJn3.=VWmNdQs!T)4@i#7=IgGZnUV %h_;i_(@8R`C^n'c$@>9nLYEnVKO<@JmbuLIqC+C"T^rXtLP'r*B7W0^^a)l'pA7SM/O^W_f#+r.M.hBHpEm+*fcQ4f[m?M`':)/F %n=DX'`U'0@[[".XR``s$>;pWZre$'o!>"t&2KRJZboCUuTR^[1k6aQbgiH2]Q4&,^)qIWV"C"cWR:am'K*obEduLK7K=I3$IE)XH %%CG[A'X=,VC5Y;m(R3Jq[=Z/#O!3NMlMY=c%su0+MAZ&KTCmtT`IQf8l<MB@N.^bQ(Pi!MbeOcu?5$BFD21Lfo`K*\`bgosUOk,- %7-l:6`cWB9@pY?LgBJkH`H82&_0#3P8r2-E?acXEXHR(Q^56p'&MUC9!_&ImPUA8$YT1<\>b.W%-dBT)h&S![E?Zdacas:JeB(BI %gNVRqfi<lPIqso1@)Zdg;E+d1)uCL%ES__='N'?fUm['!W2&iWB&J'q*;+GH&^R@9(MrP80`$=^ra/`3P\)mOB=Vi)'K[Q[WG0Yt %GSpU-4=`!]`?$`3ciokN[rs/M"Cl=`rrY:MN]"k+cRmdQT!;F:cNfkZq3gS?lER@mLfq'W$bY9gqg:i?oHWb*B"OF*Omq_:YZ*;5 %oQf;II'9pjL_bo8pGY!;Q&'Zg0+1HckDG5%--hAJk;clZ\RA/#!(\cg:q;niH<(\l^@Hj6#CF6rTdA%L[S"KPZF-#hrkW]d1Va;7 %'F$2e8hekaH&R=Vf5Lj]5N&fk&Bb&AbM>N%js]Od!G;snHJ=^%T/WSHCpG\dL3[MpCUZ$Zs1'-9"(mWH]8[g@hijntSJ/qnauCZ: %iPp[<^qO:95,[&Wo\9/or4FKc*]G0j5VfC:oh?r`HtRiD]khrPAZg+1>&P3f0:WZ@nT;#.Z89R2SbX>5/5b`PFWH]0E?pis_9ajZ %mX(.*8J09AF,[9KeK45467mP-l$FW\\narBN$=B-_Lfc)Ho$B,':q]ET"?05d)2K)S8ZhD+l^,0d^SJ=6`MV)]M33jRf`I6>rG*P %TT66@OLrfT)jZCMZZHu;4qPBD7SC<5,2uI!fQs9-^(P_#j1J\`A.;JSgDo64fuS(eQUA\MH-U=aU5/+"'#CZsk:&L)I.*K##2c;/ %du9%I]'*oL48Q0\rg5@VaF=:XUA*UJBs3<T<$2#DN^(=NAYB@&4.?M1^q=3JQ\`E$:Ic&R+5-Kbk53mQq3QJT54EF_rS'I52`^g[ %iYr)P[p/qe]E/f;L5"P;?bm\!K+RP^'>du!KRmLh1I\rfA,'9bL9,e7,/,FWG\)hQX*jp9/H`t=Y)7e^U-oDP(dHpUi@SibpKS\F %Da_6Hj7msb&;k^D%sc>So#aN*&cY+(nrDqPo;MHU\*PP^Gue62=X`8K#+%8R0*<^5"h`rXH-8!"E70u$[gY05\8GVtE@>9h]'(RW %NW>D+fVYRN8HFdC`!_gj,so-#.f&8[GApt:]@%'O:l0G?-?PdpEfs6T_8qSDLa"Z2UJlKDZ[egY/k2YrD-HD(idB^0U540-q$4EV %%:%5M,&W:JpDjdne'%c1bjl"?4!TZ@%Er@(^)l>XJ&YtbL8D.YD:(LN;fcj&:3UhgS234f8B*(4(pdIq-qk+W.`%HJ&<nb<cF'bZ %,`ne;F--H.?4eam6kral!tuQ]Sf8pld\tk=2cqfAmFhXV;)R.[j\PgWIrO;sD^1X[4\*H,'WC&5U\2=`8/+_NHn6on(tGo*bG'Il %n6A_?aZP;L@B3uiUWnL@DNo*/JQ;jb*+@d1P8EXJC/LHESud9LIm'p0/XYLeS30%ajhNWW7)H:i%Q;$lBDo1`(E[BG^@LTTLj;d: %/K!(J>c.^gZImjn@ONFGLEa0Z,1^<K)r<IBX[VYCO[g#09"rWI'thU53R9MP(G?CS>D`%_/PipU=R1<$CKGZ]o\,fFc<#$lLQ0/0 %VgB-bi5<=RXR\^QI90\*)j8DZ&c!'jqHDSK3A]%DQ)Q?:jCQ$h7)scmIWM&7`qI!>=I:de^/0>X`8;2^^82T>*^GTB;#p-3;bf;. %(<tJk1BlFB[Voumk]])^op.i7(V-i!Y(J0)cXWeHboBcBoj52Jmb'JIF1;d&/\Q,HPKQ.23)LRY@KCX^9<SKG7g1@KGA%Zb"-f07 %Y55>0bUWddQ^]0qmb:gd9mZLbcR(,8k/Q5mWOg2SBPVCpnC$W]_T*>f;na;U?2(2F!C_B7(u]<<Kq[9'7D(4tn4adUU#\RtGZ,aE %D(1=.Z4drB%n.tTRROE,5lkn^A@sLlnPX[c,/,MUn[>769DK*UGZu`[D-<!f&gSX[D8DBR8t3JX5m\-AMl(l#?KJ!t$Uq][h"%nl %b>8\G7%A&2^Wi0=@s=mEg^-_YC4"i@Au:M5G,IDbI_m_Flc,Y[cRoX2[,Y7_S1,uE*7l>Xf$4.T?34d"o9Mna,+*Lm?L%)X`1&5? %DsI;6W=9Oc^8WCM[cYq0I3ORDVOGoe\jo,I,`6i4*23aLJ+U<F#l^5/8`s*JSF\WjIUDl`S)\5UM[57ABgQ*-VWl<ddR@fGrIKN% %.jG:;1N(Mtj*G4YHd;R\IWC?2BUiAHCl15_IGhY\FsnS,F,,`\[bQd^0/j@;m`!;Mqd+."h;QTLr42m;Y`tV)0PhO0*XHYO)*ph+ %(F!*r``j@k,A?3Yd+,eo`L\52GO4/^^]n*_:?,aT,#kk44bD>pA&6l#Bh8p0#C2toB-_PAd.=D4KI=?"PX>SW)Ak$KmM(R0ZF#"n %h,,YtrS`L7"Fp4BncrBR;$_"rZTe=Z9;k#-nr1MlQgS"D@$F/ckMZ2XpC:*QADk%SaSrEH@B88K&%:/6>Uu=#G@]Pp$IQ0t0Of0q %CQ'#:-TL#b3D^0%1#(!*3*K@.>E5)d^*^<Nr?Crj/N+1KnXX-o/k6cV,=XX"eL_$>cdNnH5>$/qVdfqUSHo)raK<p/jO_EE[$,#1 %BhfB4BK`SZZf9jE5"@bLk27h:eD7JZ5<IOq,@U:t#um.<=9;a<F*dYu!1,4S_MDA>&<Pk#f[jrQ/d0K%Vj62KM?lm!@kM!T5Vjfq %3/8%^A)O-T>W<&YZX./O]f+0]F(]:`YGWg%D#pdu5rXpjLh/^mgJ@bJT/#-RHB,.2>3<hjLJ4f4#e4NoF(M!2"IgRO:]1:2/39<o %p'55I;U*"nN=#[6\f=u-?XN%D_UH'.(C2ti?<dl&(8uqra$,T^CbFV?^W:Sm2(L[N@(<2l6laDR#$rtl>`gpE,+^:b<$s>_'Z5e( %mW[M_@c4SOm(+k;Msq78h&(V'+/&&n%fdgbHN;[X'_#$h>d2:Uf?Bg#2q\dl8Up+jlk;rBQ@j;91tD"6%MHN&2,-c&M`b5</ORGW %h.&>Jk_@kHl%[HrK6t/a]uM0`iECN^eU6SY'1>fH=NqRc,4qUU6.u$#J._C?i#gW5'H6uRC<.;QT=hTp$3EKmf)YP<T!tJ0_.)h+ %2Kn\^K6(9c*F'E9[-i?G[*.WhS!NLgr<4:6@61P-d'$LCnb@lP-UGjWq]Ih74,AKF2l7Tt/Fkh9O,,fOfsA?.P['i!?RXM@F:j(4 %T&SXVefPCY4E5u\fiPW=Ep*n[X_>=))P6XB%G.)d35hBHR@VO#oc@"!1PaTu68g&j4oU]cc3*%6ImI^(E+8JQ'J$V:YDN2UiqMsp %CVE?=FD'o&a9i?G$bS-Yc7t$Q6nJ'@&aQmf`d+aA(r.YIRr4K%o12-l$$0b*OI`<<K[\;aTR\fe6s[\T.Y3#F#S4`?5NJ!!&4GJb %0_cLKO\!:tF`!sR5G.'bY8<A(D\)BO8U5I7"Qq<r\<]A+eFI5j6Nfr9%6UPmS6J0CbY1snYN27sp_C\\7R!3+l/9^nG$??0j'^%f %bu;(t>[.NDUSuaH`6bk=oi0FD[To1GD!.Z0<@;rX-9<STe8MemagQcul.@nGbFT\HAOWsjpf*&6bb5GJ:(g6'CJIrhoEeluJQ(go %_]Rm@f0T;.In8lo`=Q:82rL"[;%MHD;rC[!:c-mHUTSk/2%1<&qTe3\>0>3^7MWi$Jie>7!aaTe8HM#jR0I9%P!B[g;FVPfY,W\4 %qY+g>/Jh##,0%[>q.Ar<U58J+n8?]<f46m.c0ts-TTW`$,]JdCj2Q2I'big#QpjINf+r_VPkp,cdg#*:/LpHS\AT-aX'X*(^gQ`= %ane[K4:AX_#6X9Xjq2[CK-I"s/M)^]3[T0F/>Hrqk#YVS.ZsO=Y^b&/e\2(7UNj'Q>f(pa*I+)i]nHAnXk)jX736&X$(@dG!2h^F %bVSqH2o$^Pb!Fp<XYN!Gk7Q`*H`0H$jrY]i`lGn?_(b!hGfo,_iph:80`=%e9_Ft,)uWp5Jf,DZDmL*U4Dtb&.R\sgq5iDqT>e`n %^V.^8i!#5ts7=JWAmUnf(`CZ<7l77g'&i@i._cC5(j+)hOg6o_0EIooIYSFlJ2K7GRP1g8qB(aZi8fd/a5WA9XA3D5:_/?^i+@mW %>;t._UXni.(:,c2eQYEZGbNi3E/@A"AGITK@J?LeF4gG6[On<:3Yp"ul#[Za(n[t$`?7`!pc;jH0TV29_J^-Y8Er;I`5Fni=cUH0 %+j5V))'o?BXGFgm`!/NM:$]-%'Ppp-^73'!Tq]_)3Y#s$BFos+PYL@H_30pa#)eU*7n1Fa(cY<?V)cgl"fkQdK#Vtp1rM]A"rC*q %J8in?`c5H2PN;oR&KW4WZ';4I\3\?TI$#)q((Qp[lbtdB%qj\7/H76u:Q@#+MEDTZ5`lV,J#BQo[jHqNl!7ge#<>JK7n<&['^:R- %:2o@V2!9>ZUr6\7_OHljfOBDuR:l43qPZjW66ETKht(IhI!!J'P_mHnp"&(J\33Xa"R%sY!BOYaKC_"#52tGCkT4UuVL#c>fKa\+ %rF&2-c-5-L-kSFnq$0#9\@'$QcX7*QM#)bYL7o?Q,a8C*S[JZ(;>"Cha^59f,6OR-9IHGgh<Y2I$paMqKpQFg4^Xj`6<Ui!f3Q2? %-_G;c%_Fg.6QB>YOA&ri]XW\ek,EE):?_rS8c-E<;QE7YOF]*83#KkYG;Hf*+#]3Y*Ci827aDRIdK\!k/2?ADs'RQ85>10_DcMm7 %i=tj%05!&P_K'MOS=FH;)l)c_&,Qig[,lh\nUP7MWSJk0EYXT3C*d>LU2p,sk-j"a.p&rb4WpV[?-[%i*^rF&;t?G!OmF+H\t*M_ %*0fad;1XQUI`?(u*.C-D%njj]O9dPU8-BLH^tT:>'<1rcP""PnrdiWQ"2iDl?t=gJ\?6YT4o)0Cbabu6WlmO[\D'8-L'8EN'&L#= %>RM,["6YUb0ALOOi\kDUI;<Y>dtPq,:)nKuil?rS!+Y%Nmr7+AB(&js`f>!`3[-jKp4r,bfH4^1#H*2c!r(74D1QOoYct5A86HQL %'d`nL_gQNK"Dr98&eku>47!Q\1Uc.*/%MseGAl^gHgtpC@4\aLBj@dbr!m=1&b53sgOpC5ipS/pEFP6)D3+[aY"!VVefT@N@hR>m %"eRr%M:Vr&flJE<f0b&M+8CbZ2;o#:OKE7<i,lD/kNGXIrRf^gd3g_J7qgnrAWcG'r[)\rH%j.ACm0dqbNUmN7:pH6Fh).fp9Pa^ %l-pLZbm-B)oC"s=BtfHQ!m$6A&->BYpTAt+@*=FR5fc9S5[&Sg0T?FG@g,e]fs)_Sp/$R!Z*D/#KN7NM/&J:(L_]kcIpa6p7=PS5 %CION\PLa2>So4";df)qn-&0(<Ad7*mS@20<f]$*Fg\33i[mFVY9$lqBZYorB91Y;l@<PG'ZC-=LWW"T'jNMH`-jj<MOJK*)K.O"f %7Pr$tH;&![G@%^2O01U3VBB&idLoWkA$7<L%$E+B58RbE<I<('>?L^@R`hY9/%g=244j+I#qN3j^d<3GKnY66YA2\[6:2>&)eqr0 %bJI`\L_tTV*Q]91FH)#!p5#i193B_mLN2+4JED9qQBm==(..TU+Uuo\\dr,((dsZ%i6Qc:a/#EfW3p&P%3cs!b?T^":-]\$A'Vc2 %'`j)Y[3c!gGu/n7YmV9@Utj0O&X3P;$]t[bnsS1KAh/`Ufk7I,=]_!iZ,O\S+tNcLPric@PbQ?;(NFB#'\R"HFAGKP_5Sd4'UuYn %a^kF%`sN,U!7quGTB3=#+sL!=A#g,Lp5IWY[Z!2W=@CE%3.otI,3C\aG8?ipOW;aX+gIWAKCmrt8n9lL]94T0%hX54XRljEil/Rh %ro8)<!D^+.%?;_9\4ab&:Z0J]p,bq<6sQpHCQa>qhrIo!p_"0;qZ@nLo7?]]ca:7)M<^c>'N''to;:ncp8k=J\uas3I2#V9cm\/M %@O/O'P!MHS>0mI>6i_Jsd!^M`F^'l!6p1@`NB_rYg;*N=Lb*@d=m\'4h]?<8+ssCGR5P6Sh3T,m]U8,/T*JPWS_!fPWg3Nk41"U. %Z8H*]9eLUu3PqsmKX4t\*uO'f)F`/GXQP^-DRid1Kd06.k?\H&(]4T+$-0o)Gp(6<+S\?aC:l<eT0FG;`^DJ$-@)^D$$`YEEhPT5 %=`;8=)b'`m#n41!&//Ho&sStL`iJ[1WL,%WM-T\<XllKucT5R%^j;_fRcE^`aOUq3',bV+$r'$17drfqQO4p[ZS5C0AP%2TIcdUb %,GB1P':#P5J%.F"0?ZhVe=?e_j%#PLEgmq]7OKMol<&&6l/Hi6c&-:,3*>OY^.9%#&R,M>J8'-o'Fhj93J,ngp*eds&oKU6Vegb* %$RL=Q3QoE(=J<&KZ`CG*:\hmhb:aLXGPS-Q4AYH>?ZQuF36lmfB\EZVOeSd+S@&*HSUrsUV^9j>Qp?YTdO:HM`7`nF,+c+C,/E#F %72O5WNL?hUi-qDoQZ=V`Za3gqKD;aV[C\@;4KC4\fVlEVD)cER=(USZg;t,WR`*g,.s9'96N2G/I?Ek,!H-AFb5uCHKKm+V=bHhr %M]tF7YTLu9+I)7r2]tL&_0k:P-U%E7=hDY+hsXlSdaS0qQ[tGpW9]oe9#*lV,4lDU5BdYtiXTj'p6Qu#d.HTE)Wb86o*+2!kTUMc %$79"h)>.mtM^)6BDT'bXY:9lP<5bJdWhZe3nR&(IFc`K(3<C3Mi^c/Q9TS:H)B14bF82)O"Js'LQ4p#uQqG;lO_iW-4E+mL"8i#6 %ff_HDH+`TQDF-JJ5'"7a/CW.aZq]il5[o]WMQj>F$+#H^[/CPG)q1nDZF+\(91G3F+\ku5")ah;c:?a5B4BhZi"GiX#ua"um!`Q` %\n>9s-`gR^CTU^!c4@cUm*rZ&7N)*.J]j"8+jBF7m^A&3;5Qn]K.CbTSI1`%1:H!-^2a%JJ.5BS=mmKK3@nNX,Mt;a@CS1a+m.\d %3PWS&g/67:ljGD8_l^KLiCF$XA_NfCo"_R\IBn<]-6V%b[cuor@Zr](dWAS/-U<UZ&?nQ-&Tm28-ug:IR+24\V##A[*PFGT3UD6_ %(]<5!qkSf+[c(g"];Li<7]rB>9S=2#f&jN;FYPhd*S.J'>]KnGGGsQfOlJ@?_/5Ng0!O,<]l_DsYON#Q>*EpKW$65>fn6"-i"7pB %^!Ufc(1k4taYe!V#jmq+E!"h'fQd.IR6KG&k,cMQI``a%E(:Mg#&Y0dTmm'c8q=9#_-lfNq4WC_<ET0)7++bCeH+^bF3YQ/@Mk0i %)/j`*enp5Q5_^b;?tXsXbWmrR91'QN9#;0a_K3o[B*Rc,=TZpbYf<%KYh-PY5;4'c3Kh8qqP39kaLj7aYDCo>W.QMB8J.n&@XknR %C`O!#%pYLtEbG/X:@)U>iX5YLbfD@@2ckYqUuET^'e.->%N0UB$W(30_EaX_.r9nJ(b$'i#Hm\'ZFlQTLet(maXE!\^#Ojp8e0>j %XEnn$&c?BIqon8/_u".,qs^,sP%M'r/_$GGe9V8+[6tc[_10dJQJl0Z,jH3`IZ0XON'%@_Wbo=dcGBe^($&_?>4]VrS?FKrk8*dl %pM4C!ePQWjHNrMVl`f9ud;ieFMh6"`/73Z`eK;Gm?otZq=<Q7AUue<\'^mi`I?tj_:uXL&1i2<[\2+=`1`"8Y>OdIoK:>-hA0<'p %AN-t-]rdIrCP.dZO'AIAQ8,Lb(=o/>Zp3f[2r9;L-NA+;cEe1WVZU4-*4/*VG"J]g2NX_?!^c>,IoHR:Xu=Xpk?^SfQ.H94^u6g0 %cskRE#KgR&_*i3ikNAn36i-1^\'W2LXWm6=3j56@K7JEp5ighKOl9@cgu8r\Z7nXjCDQbiNedZO:o#4(\jYIg.0\9+/979c[ZdYt %7ZO6r2`!5OP)FqD[otPq['Q5DNE%6?PM_c^MA>]4@70aAd4"BL&U#$X)CS8h#!tT#bT2o%1I-((=4U:F;lo-"''V5G0M8)$m!4Bh %\^L2AQl_Ze1f)L[HleTZ7#DXlfdXYD%4A8*314LCkK=s-)UH[OFI<)qVpcE80e:_Z":#B(k(]10rW7aa5Fa5<PsU/XCdWI9$ThOS %PO]5)["AYVY=h\e3p;X$#lVZqed%5;#$tR<aAb;LJ<`Y@+?5gKZZV2X[6TlnT,I8XL@;uf91n(jGLI!=>FKi8>eD2`KAb:3m7<.+ %K$X*ZN_Y*D7@Z/LR7MY9M0;O#eA8ZA(2S#W&f<>c:)(>n+Qq3Ak1,^;*M'gZ1%/M3lcooo1fE<p;S'!=7TB<p#o@=*S5"#ij(k&J %7gVN!eJKH#7HpA:J2:,E2o``rkdMm3RcH[(9&"/+r_$OY4(%cTDuPjbibs+`?T?6phWrp"r*d9`F["uZ,-ZI>6?(i'3)t8f^M'f] %AEKG(\$A^>i=$7`DnPoeS3NYB,"PS.+3MD5Us:L!f[mD'XFW-.bO)3qB7W4hiQlPgC^14Lk$t.C_37)'Up>@lBf<d&&GH_i1Sjs8 %QugI1a4$$gUdb9Z;qb`X(NX0c:]82Q5>604D%Qbdi0lj77iP+jl?m2^>F4-UjL/BBIb29*eb@'5k.t&IefU49om6VASLf!iUU5Rp %BJV>O69OJ)r&,lGU/NUl!LH_8D7rF0i0(f/02aq8/A#]5)qnndmta_MJ)@tnHlXG'fQ_:?24Y/"ROlKVHd+f/nEODd/@Y_;fV]'! %:8/5F>0nTuGq.0*N*WCMH(Icuol(<71\"j7p7"TBi<ESe?"NGN8<Y`DSi!UYngA86qjD[W!WKn!T]Go4=L;pLO5Jf:X`k_(P]Zh( %^S*O=FUO&((7)U>]S!<lU,Pj8"\BNb-,ItVfCTB40n]j/54ooN.0?sVIM3_#JEV=F`69hiDrp(Dj<Z)^*<q<alOWU45=dX/]HDo9 %^G77r^(2J.[&D9>6.o#GRE6Mr/cZKtBENore9OUrbsOe`h"guTpT?TH**7=I'D+B9:Ju@5EPELRr*]8D$lLpg+aMdX(kt9jgCfLK %-:*dDiS1![H`sh%^.XUE<M#<X&2Y"[O]h3c7`K"Hem?PUSL`%ak2`R?8JG'gl`2&pcM1B4Y6MY,1q#,e%V@V:jlnOS\tu\O8O[b/ %=Wq#@F&L25]&ch0E,AlGTA!diq[Z`1djm)WXnWX-+E7@s0;'A+'+pR#,U4,OSMZWrfXT9/deBCEH0U$+&'LS:C86"HgKVIaXe-01 %&#5<;]<d8s/4#s-qP0Up#iAOE,j*?!TAFtchiE8F2uiAVjbF'S\]7kKYdLZf1=P-Yak8USn(eVeHU@SL?atAE`3m%&EdTq$.[>+b %Vk,\^(XUe?pX\Vna1AbRQj_YAAp0_k[));a=!(nD:`"$9_n$E$ETsaW]oa"*d[3Sk[rYfG>YosR259_2$D*S'Hc;E8,7=.^e:U$> %o&(=c3`(*!i7UWL%h`c5g=Tr:=.)tGf\Hq^;97Qalq=7F8PiiPke3QN_Y/AD6*1C,:r^9oUR2KI)Wk3AOdfQh&N8LL0$GY%]t6b" %'Jc;*4g_ZD_\:tJRYM/M.8V9dWjl$bm>B^a"(=Lo>RNY5[#6mL5d<q>8)PWX/"c'cXKN&e>>)$qPF<ar>/A1Mqp$oV"]+Y@i-oCL %Phj!HH*WBQn2aC0qVg.^%K0fs!(in"7o_^(,W[QFS@jH9U3G!7m`lBbpc2;Rn@G"rW<[,?W$XRWqrN`PDoojEFZ-XsLFX/Rk\[0) %.Lc*Vbdoo3?E_kJ]K;4o+)2hUFH8^'s2SXMVN]nIqiqX`#H9n01,%Nos,\$ZljrDKFk68>`K6X9`L4H+`4@l[3(4>a(LZ-'^H&X* %;:YXQ)a%Dm$ZaPu^L1ke7XtidTb7#`(P(gaWD]i*I"k(`fi\ojNJ0Km="$Q"&V'J0gf(`Yol&]:J+LeF^PUq3rgS[]^\Qje=#YX) %o9\@K]m9D8X1+_Xr;5NWs)@o1pqJK]h=3^UDu?eGIfKB$n)"*<L[X,KrVl1KIe2Ca^]!TDTAG%+h<u\Ao_jRFq#7>Os7Gg$Dr0IQ %J,/e6?b]+S-SKsopuAuq2_X(&rU`Ogq>C$V(Opl'_sre;3<&g0(\K-3"T?X_59145q=p<VI5LoqVVM*uc2[R2iT;ZdMr-fihD4pG %!>CAu7@FD#&gPJ;W&l6cZ;)(Wn@J&,l>\<Z0EnMRNhrC(Sdb4S_@t'(@4^o3b]QD9@_=ErDk[E3`jBY\-RmHign7,X8CfGJ#1MR5 %h9p-5";>``4j]YHGTWh3KXCem\eotp(GGg`,%(CXrqT!qq;e1*^]3l`m8l5rqX2P1^4(EVs"Q^&bFd=S)/^^rIk3k<:usB27.6*> %mV_)bPUW+pR>1@Xno%eJ94%V^`N;rE#VWEDHO6rr;UbI:I_lo^j(iUL*T)&3nj+P3DdL/j5!_CFpi/>QO\]nErVQ&uqtg8`DE`@A %o(2bU+!,n*c1bSfXZ#?k^&R'9YQ)d)huE-3rAWV^FhFSVrn+^Up$^adq<jlh4FZi#dn0T)oABHnN7NLU?f-8*@$`S'O#?IX2h-5P %LX1H+s)>Wfn%\neh:k/qkLgV>39KTE?_)V-oRUAf<e:5<1"n[%%BD&JCZOpliQ2HNl`f:%`h=XUPVjS'?l9%Yf?l:KG`'PnPDJIB %MIGO:9.I.;pGHo<%@hm+T:>iEI/6J9`K'Vg[-A0('Ko@I@SkfI._?>'Rs[Ok7'W"??Qt+\q3p7jN11$-'@B66;AWkn(1or)IWgA9 %g[pg\,4enfBU6kI1_o,K?Qu:SR@K-1;u-XVK/M+-)Co?diM%b_,#D\a6gu8j^Z^d:b._pYAcHK?fZrS#i[0IYEW#EMjrA!QiQ4WE %7-YL0`8gHF.3^iFPj/_b#74Q)c)jC//:MsAK)]T/i$7.ADnQX`J!?Qi%6je-^&#>8njU&n,Vudn7.Vh89"O!L%HL2sRd!hOeNm\C %>7t(o4#-q3[1^;@c6>3sLu:3D*<h1!W8i,r\s<tPRA9fWaN$MO5F#'_07J>.m4eTCgrAt1TQ)uGpkh<j.7?9/IiBU*ZRiC(?dL+* %_,)WBdlX%1&9oQnd5=#:=KMZd+_a?+Y!^fQ=D;o95'"1HdE7+:neHV:3HK'1`qlZ.P9`4T\B1IZE4?L3AN>55Cq`I4iAd[0G3@MT %<3]TPXMa^BHA2"tP%XRLiIt`TgPql9O!hR1(BY;aqGNL=IsM(!5P+H4In"Hf0s]k1lB>T3F5MfKliQ9%%1"hj"b/LKPp/9i3!GU] %P^/0f6&Pe@:l@ftr[We5pNpOb%V+gI2<"XQoCc36X$e:WFXk&i/B.,a@&%nL*d5/>^"1d#`<^k4mN9=O(nLJ)eAi&ZIft8TfXGj' %>C!`i'h/(dPKcW@"Vl,?MPks>RaUpeUa^F?RXlP42U@9F@&gGc*L3A'=#_n?'s[3J$rTej&L@STKPrP%i/(GXeNS<Qq%f:;<.jVC %7`MGO#G_pH+?T`&/[SU`DkAfM?WdeD*@E.U/PJu:.lB.I[)`\V6GpWjB2IPp:esdt-8[$e<!p/3!0stS"LX!ZR;i3:8RMZJK.'0. %q%7.O4a%_Oo4U\0ZlaccL]OQgG6/rL>p&PJRai,Y)AZtCb5PLh$/ln/A'n]U^"<nN1e>R5oehI[Z+NNhTaIaf,?4*=>ZnEQk]_PG %;a5?#R:t[$H7so*PlYA\_4'J.X7[\G![fYl<`!l`%4=C-1`^+$2%RTBgfbSS&gj[C(.5IVF``:2"r0^d1JTbJ/:i>TMgg;",=nMj %;$;f9<*l5Oe$&7^oAJ97;N(P[kCIO2k8s$Jp[kBNl07B$W*AeY"oP=$q"Ksm*C$qioQ+),l7B%78L,)uh>VBIXK&'Sfc!gVmHj9> %FBHn%T-YAMeUFDGL"3L^=!N3dJI45pA=BbNSZ:C@c_nP(7P7b)l?;WBWNFdq!I0X&-2s_=V;XBDX'"R_O&I2k<R>U9cJ_u91mL>8 %6l`MJJBlGL55-_?<PR`LIE3*#gN/M&SKW":/JBb<)3WUUK?($_qt--:Yu!$AV-o'U-mit^NGM6Wl#+c++-s4;Jqe)0g[`=0"A:A) %<.kSck(=e3KK>59)!@(_G*)>qC7\rZ,gdkkA`C6FB=0S]*j79'@7[`Z.a!NTJ\XkYN[nW/<3&kOFN4Aq"a;_ojKQ9"JUG+Ql<PPH %a.eU6$'KF+2qe2MN@6alX,/5I#]0-6dk0Cr3:CAT9/-PIl/Q0Cc]=WFj9tpgQc'+Ho03mSrqh:ll@LGI1$"C&$F6Qg;>NkM5fm&i %/_#QDRSV#"b[<@/hcI[iLVo=naJ*>Q1rliSbQmp-e`a]b!<>AWke0m0F@W30B[3u$hWimnZHaC6*9,$P8cgAK=Q5+dl;!<R0,RcO %kUBX4,^AH&F>kQnr8bo"2H4h5.DR:l`?nEHXicN@jMTPcQ@gS6!>>rk<01)R7P;a>=b5W_Ypk7nch"[lfb,GDPb<"G;P\cOXKiV[ %C(nP#ZG9+I`=uG5Z($/rU0i19.$!=.s7I/Fa1fpXHndb@;JII@<mek(K4,UG66/YR29e3,Cc>8:5r*f#2jEon)B.a[E)hM\)5PM$ %.EP[FBD4]a>\0-ST-q/V7D7DG0U:.*-GZX</ecHu#$FW_^%5&3hY@I0+dY5AjOFf"4^`@ahuE\\J8Ee]C_Z$3A'@B.7G^Ml54Kg> %HRiY]&j[(;,_=D#$Ea$lGQJ#"3-@R]<@*h3,5B-0r1-.(Z7pMoDWUHX"C*P%,8Z8s]tAjKcb97\T9F@rBD&?>3NNMRUWYA6e)ZjJ %#ajpjd6sH<%%Ri;Cj7pTY"/tZ*auAl=YfTaG*$H`/iMQ2C=KAsGJ?(%"`3LG2<!/taVNL%aWLgjIEM3+q=NjtAq05El?@,![(<p@ %nhT(bLRD%M>"UOh4j*qVV.,8g%A?EeQ561HO\NJVbpd.ZQ'0^@PU*R)C6T4B3pIhFJAJNpd;PS>?mmbBmX7I-2-(o$S3c)Q0sK&! %h#\nOC@(`ei5D28&XPi"$.r7%[J%cEG]_n:-:Md+8Jo5t/kTG]-BGt+K<TCOj=-%O+rG_IRkPaQ'Mt+%JFTJ%<)U#slPUfZ$Y%:R %nB!+X@6i(5o(<uVLL!TbgYA(=9o(mVs13@#g8I`]2-CPmU2;:DqFSI!nq2GD2YtF.CdjM9aRVM)`*E9P!#Rob48b!Y[T=KQPI^:+ %-``eBTHG)mk<H3(8;sod)RHmjmAFD($B7f""A.EoDUjB&e.l,V,1A'0"=G$`A;'>T=+;(;f2OHp@"ifK7b2o[.#_'`:4%M/1tWJA %<qk6^@,T>k<Ii+_+i0lYFnfVd"7X-bZ6^A+WH8^[/;VEM#`cf<RRKrURo0ACOcGQgYnnQIGnknfMtmGf0VP[#grK;nHpoL54VhRj %^q(d-%bk0p*j>P,bf+,9NWWT[C?O)FmjUKsncOA>/K(=2P'F;Anh2R_;)8V4L$)[R+#EQhQ`n9l)9Ob9=,Gmq**%#/13qEcO<CXT %4jE?iY9NaMb3Qps/1XHa!@jpH=^D,L7+(S3>$i#+Qh7$.>GsP9J5rhn#]bVC3,V?k"jg.(X7'))>!uneJsgDck[GU&`k0;rJ7hL: %PGBT!mmSJ=aM=%>\PW]$WI@]5H+9D'2O0cQF;eK5=9'GTF<HF*+#./3<[>.Zo-BDL9nWKmdJ(_L^H:Ser?+f')6E931m]oscVgK+ %<-T9:Z5e2m]=-nd`]C6"(`W_p39_tW9T\fZq2QHJ#S186\r9L"KLP$qa_<(Kn472/eV[u-?^s$`<K*4qi<[c('cR@V`30L=VDto2 %.[+Oc.9kB4')$n9;llC3LbS-63RE_<TP,/pEQH,kL(cJ=7&ljlWcaZGr=cntCO_/l,oQ0,(]T:E2tM^%V0&X/JXV\4qJ&S9l%oti %/65(7,:9Xo$0tg-"tR[6VK%LJXVpI5ZA**dP`hm.fN@-rR3nR0!G/.bUP!*1p0r:Of7bd+*89h7U*<Zu"*[k/`]g;^VC,aO)rt<o %EMp$-=d^C]_TW+;RoU/'b/$IZCmrJsK!,q?.FDU8P8fLD$@+G^gAgF6R(rM%TMU`&jObY&T-Fc/@Sg>7"!f]Rb<r4-"?mtS.,l9e %2Z_eMPiQ;BbP9c$=_26XeTr6'`*WA<#em7kOd+a!9lAcOm2',Yi%IPb7b%35M"<YbD-a)NMCfUCPIHsLaC.&pe?DIYk($!UngOHm %D2:f3eR]ahlcrV3A/dQnqN"_iN;9:rQO'0'1U)k[7HG-e4]M)fma2%NO(9LZk94S+c)T6UaiiFB*Ms(7\q,ecb+:C+FY$?2O2V3k %ZM+LI>WBQSFR=eA.+<8<ARkq4nKTt*;h#HiT!df>Ceoi\.Q5^Nf>mfG1KVKqV:\lIm\UP.qhMSVj)hUWjUu*@[TREqV]],\W&ih9 %IS8*Le(\gFVlHhfEY&OSOj*9eRO<,2*_3l9dbC$O5'EMs/93h`.!A7d=m,PnIeDfXri1G!=T^RS+kY@Q2@]o?R-V)<_iOa#Il$uk %K=AW0Ha00]<U)=&-%bA53<2B*;JV"h+uu>F&YYo'A7g4ip(SDi<I##46B6b)Z&8S`d0b`7k:4ppn15.;8S+Ibmm[8pj@1D4"+O23 %lJQMi,C@,SddB52!@lMk4"-X\>8"f0NV&*-rJZYko3qio??DEcaYXi)iN4Nr%9_9DfPr1`;(CY)&)11hj,SD,HleDD;^L^=/KM#? %""2s-BN"NVI#Qh<(tT9hQ`5f1SBpqp55L9<egZ46efOd<5s0-QS/381AM)\L@=f@U;E].I;4-BUiDB]<E]6[RNhK>crd>gb9@P&? %XI2qr8;9*g[05!s2@<<&:kcHLS1<"[SSVW1C24q@dAJRIC?51+!'l*cYTFh3Y=9'gXu.Y"Xi(`P!L441nKpq<:K@JN%L2s6"&6b& %8]X@,Td:]@[[9'D"G?'/=uq-*je%_kc;BMM>-J.qagB0F+*;`m!nqI"AVi,oCI%V1a\do*.:G%V9p^!A]Kl3mm+X&i.kZI8I%S1H %.erdlnV)Oi1XH[A&u)h2+C;9<N/L=E#ShHPn9eL$,u^=QoI[VNH9T.i'bI3$Q;o*Y,]cgGJXmnp^L3sr"]_@[/r`DV3"q$`<1_*7 %BuV,@3`J(u8hl2^m?UW[63CAMgbDpEe!8O7\o#qB^TJ*E;s/+i,rK6]<U*$lE1;WEUE!$_qDL[<4/ZKOP*FcLd2`dlSZ"piD2n!B %]H7-FBSS)uT:aF)a;=\W084$X7XnbN+2&62D5*(u"1Jo:OL2>^,\"NFU>gA*UJPVN6e4mEWdkU]GZt-]!r`?sU238L$8,8*-Cb"` %[.Gos!Ij")dc$5`Bs(:mLjY3Mg[oEVeQQA1,Z\2O$]=9J;p>9De^[?g1@F9)gnRbU7"r0B385.AQ(1giX%a62:*Qj'/A5!H3,JgU %(3Re-kg#^%6"aJRUiO'eKBH?+<Mldh5C5P_40ti8]%3Z^^QJo?;Gd3`UUHH#jRJo7VV-R^/'e).s7Os[8&!=,H7aNW@Isg3cPQWM %nNXeb6#3:qoYT5c0+q_)Ic2h([KO*),SBk+mf)-DUtu!NA0b;-T:V(M(]:Ljj;ZnQTd`PChM3@&a^43OLSD'%1QGdIjCFDep6:RC %"D#^+=]."nI3ro!>onku."6/d?9N&,SB@Wm^-'99*qkq4_4nqI=pdhdP+YK(!tg4I<4`mYZOm2Ohtb]s'N3JhAB-:OdAmIg[k9qV %IZ:MLfWQp,?*7)@>bd5)D_%(RWoYVg"15i.Be*FfM982lS>r7KltQ'oTrD0p'a%GUWGAk.DbgX&OR'SXYeX8nCF7,4h7_HrTgl$7 %PX+I7("%<7VJ,8)&6Li1OdKG's2-VNcBJ.T>e"qGS8:/lmmH[)Hp(HURepuEqjJ9hRC&b&F5^^I"oOkZ+OGA^Deam\K$6.W`2b17 %cEE`NlAq4t("angHpgR37YX5;Xb7TZA#*d%\H)#JXeo'JraVHUZHdOa^imsV>%9&3o:]!7(.%7;dN[m$<NI"ZIY!J1Z-d`PCN\.- %$RZ<OiOLclFX!+8f>YahK>-'BZ1Yol;Q6cWTQhY$Y';rL\W\G,!QAW.lALL(/jQ$V\TiX)F$h6W=._A$3[lF.HrI)(C.\%=S]tM" %@66>-kc<'D@`LuKh5"QA!Z7)q';]B17R0[n"n4@:4L)=D:H*WVcC,^]JRFH`l-!qf^sdK=@5mD./77<W/Pr2M[4'19?j`jLD\.`= %^#1hOjFn$ED%.t`JqkusZKA;]hYbD>Y`SfP%MKsOMHP[#mhKDq#gHDHID#f&IY(t*QJ$1mQo.1%0.gpaYd@@kgi'B:c8[QD$tPnH %XLLH[]\X%1:-6:hJ[2-1].ZlO@72fI6TH/"Pn$lD3V7d(e7%*g]@sl.\'\l.!tcH+EhQ$@fn(0OO==DlZFhq6KDL,OFfq[+H7cru %6KcO6`++X^M^6@&KN@<F!r2'/EO.4rP'ao"J,X<S9ce2hnU%IrrU?/KdhBmG?S0jNT19%`!Y&^qI]V0b<Fd*kctl<ADWFop+h:QF %A^l%[W)`t7-hlc'@;DA-0i?Jq"pu<n34:`_fb`,=4h7n-6&Is!fhatZ-Y&!M$93A9#)m@j-#1[$G%Ym1$&0p?U@2*BB/PkMbga54 %H`*%+:&oh6!.1I\-Z)ksYuqK"\(Ze570XKQU%2,S_64qGWE<J@#K_W\:$nhtV!I6[83DQh%K('iYD'XYp&mesP0j$(`8X3>XUPXa %R*h$gNE[Xt3X1L&\T_pU2Mo7QNPPU)7%/[e7c@!sbl1k'U2q6O;Lgns$7h'Cg,q+>Bo*(/b+"!*K;u/YA@!m7(Lb0_K!lnE;4KpF %<t.^p=X.TNZmNdDaJ1Jf$%!>+T$f0IQ=`K".Lj_RWNJ=?XVbal"t<o=q?/gb9Q@['GB4,A"LT)jegBfR*;K-U.WdWGWjsejeV4Z- %94KeU5i)=lN(,,"hqM7F\TQU+7QbB!JSY'^B+H+'YHV?b98Q.ugXuS2O`8:B51+iJRM]84>N>\cX*K%q_)k!?FM1bU-JEi*#,tEb %YRTV4[`9k-6BAGlc(FW3F+j0N:B_+tI]QYd<V.fspQ)[*<%6LjJ2'`(!K@RgSY_t8HS!JWmBM2>4DgTh&'2uuc+SMEC>/dV-`p+` %1.h\T*TsV\ia2_'M%U1&[C]4*/\s\%H7eFl&_Tu`MqCV4'd#ap"K5WED&Ncr/.(!@6(2]fp@fbBB#5gYH9V3f#rF3pZc6\4JS4F) %^^BEG,5[ZV9L4O<:T;YY@r&FiO/"YW;/Gt:f=bM(DN4N,m*4(E*+Fl*d[-Ca0p-d;haOmf7s7cXU)>-u^@GC-MFbTiEo+=n,^XTV %V($C[9[uH,8E`ssC3X6pIp+5%'SKGmRAR;%Jsu&JN2@D0]tstP]_.6_$HZ3:&p'hE5"UkZp0+W['["40U616-1_QnghW(k7J:9?< %.@$pe5u++O-<Qs2ZUhG5blIS-TM_CVAFL8A`aJ^ur/><TR>@5nHJ8)/=f^&-m6I_72N?u=TA1rDL$`h`T<%MCpUB9oG/m1X)TrP% %:V]GHK&Lj3gV)&Ci%3X08:nt+?NG1hctX#]ZO3##r2BZV08\Ss:'4&E";<:-q\:k'?sSs/-tm&`9L/lNRWP/I3ZcGpkcbV_L95eK %Vq!#s[NM!q)F^]]a<kiVF:"%/lr5PZW*B'"GU'tscCE@1)nq5r%p')fUgR'+W?Mfl6$'XqfK%a7K@ZTX\,$>+nNTsYPZ_f"G#Fj4 %G.#tVTt+]Ic4JBu(nrGX.GL7_7N+Y.1adP"C)<m6eZGfD9N<k_7!EHXjt]_6)S9!O>d=$1Bn:pMNLD]9KPVnT:)\"po@rp*M;[T[ %XdJ)WVRK^qE_^2/(/OPpD5.W`DS>tU4*qB)'4H.)mP]g&DHhaB$Ou1PiRodM-f<@oKH!_WWKJ+n]jq(:$$)I:&`WE>H@q?YVDVhc %MhLrJn#2<oD,u'_I0cr+<CUrTO<U`/2do\aU2!Kh;i#Fm[E:'-L?[jcO5VN5>,!`Q28;5Q/]T[oCm4NCc?iEGM+\OXhZ7/,'.keg %Se2[\NIR\RaJ[R-K!NUf8SKFVjqVF%gned$'sOW)2'bEtTN.>V!o-WS7TJ9HcttPN_E"JAIEQH4>WYbb;Ii+hZXfX;J5&ut1/')e %>X".^Z4>D!@%'pfa$PO!N,OI!SMrM9NQ=k"8bLC$;]ZTA$^&s)Wt?XL(I.WucVaX>+;XX#$3?p6d;bB!o*tp1]dCB$82)o?*Gc', %4n&Z0%W-B"BbUH`Mk@n.W/FkoL<-(YJEC8*5^"n=n>,b*:UER6b"R[lW[4PK<E@XE.-1&t.^jrP?&o_AhOm-9E]oOckCDP`<O\UW %,B0bo+#XpMe!%]ofq[QQ-U]dKEb/[*afJYLM*)E`o#oY*4@p"H)"ek`2aZUT>f0#TE1$Va`+PB4Gl`\m(7FBAaO(EF,8nIF#uJ`3 %N?pP5)9t1mJ*ub&3BH<\flLuDja%CS9DN=8cQPc@R@i5TW21Bsq/c&gn/O_VW=DQkXaA@F<Z<r6NT'/M%?4MN2GD9\G-CEK0Jg0q %krDmTNel^@f^]hCL\[sV42Y.On=>grFVEdkbVPf4JM'[<DC8<#I"St@l<L>]>2al5#k'ggqT\]*j*5YOq%uY4-6EcXR9\6G)Ng)D %kVaA-A%#iDRfotg$RmP[qGEq&._2s`^ogeh5pA8@b3O^1(,gb$B+q\B:6$Ui+G:pArS=!(^RP.i-8>"2\9,Wr*$5#nSem]XMja7( %B4CpW5a,2)FdnTL8tpY8\?_FE&5!I$B8'!gA'QP1JAHQN]olrI#;79j*3DWuBs(h@R`q%(rNkN&UAd[Y;m'rn%kk)'ollH;$Wm&o %f8o>!=+9Qpb_-@NJBA=6#Q!7$8,oEJnG6"7ipt,r@s>Ic+cih(bGF_)`RTZ`pZNg5r&Hm[jg"Q!rK+[=oRsh=%:;>GEaJ_bT&Xhr %I=/N;gaZ[G\@Ss%4h:r,rnPJ6n3hR"oXR(FcCTXnc.R/SLXP;1@?t5gc4AONm(5cIj9p>2oqSDYj_o.<>ke[kj',c5#53]4DT(Ak %*ll7'i@uso,Vh$DD.%RKlucAfWn3;LC6u^/g(2!*;tT%r'DM'>IXV/G^O,Sq^AL!:NaDp6?1er!Rb]d*6gWg3q&uVTT:@(1%\Aq1 %,$sFM=X*1k=a;4Wi`VZn5/f<u7>>&m<jp)'R@g'(,'NG>)']@t5!<Oh>s'WQUg6)1De'kN-Z`f]4=bVtp(1$A*naXZ.t;Y!Xe(\A %ihUfg%`u;,<YieXl*KqO>j+u/,S;*moNW"@MGMPF=V&j$-_677;_grJ6p2cm6o<@KZ:Y7C4X7/K(O8J^agu^tDM^%;N9h0OJnO/2 %-t)q2%$O'.Ssj/0WSj[eR1(22X?7.nDGSP7Z%H]MR]ME[AXeL?HUb`k\p-uiamJ;ik+"Ds:X;)T90=`nUg76I4Lp:EdrS=7V7m?? %5HOQ+#D-Y(5!9P(JrZbL_V)hjUZ"C)f-6N(iE7m.pAKrKV02=0\0[40B1+A=`q`'kMAk[(a^4MEI!YdLcg^Q@*fl\$,k:kN^g>p4 %I=Lka\)4n]f3/.@APDkDd&p8U!nmBZ+_7V?MTW31YA;qC9GO&-9kSi$MlfusW2El+m$ON?XS&#Z!83d;UC-^/SPO,M>];O*0QS/[ %]6-rP;Ga,#XR)HDS#jF,jmnlt"]Z(Xh+8Ym%5qm@lBV;9lBl>QK*A/NVlF_cg%A3T?mZ6#i&Dm?:@-hJCMUWOBqsV?=kp\J-fYb+ %@qqg[7^9nn=('U1;/T5G/X(0@=c?Bq,lXAt]*7C$m;L8&Sce#2/rFdkX+C5UIYmXW]n?&o/0nn;Ks7+Ylse"5C]iO`5/BB[4m9AW %%O@ccN?'6lg,QMg=O#hOn]0_Wn(?@H_>5V65<.l4@A6o5m?T^9dpD"#6(%gR[RP`Mj!89.n)S]s^@'RN`.9:[;JcuKYhrZuKAoZ\ %MJYY[On7`+?7EcX@p=qL+'_j$5=,$0S<tA,=t7dp%K9JM(JSesXq$o8mT?Yh-_IhCmo;[^ena/g%AZ)g?aoAdL3o!'6+6NRIE"O! %R'<OIo8Be&bR1l3-\mSm@F!0c/+e6>EumlGQM"GQ)FT)+ReG(k:FfVsk[8hY@kk5inWCJ(lbJiXXo>[o7uG=#3k/:OZM]D24\sW` %I&?g762jsH5bX]E>i0+]p[E]EN;>1N,b<%;aNY0X&0Z8dj*L$I)pVD3W%jgi[(>nME:Ki_>$N#C3/djGDR'7O='@RLec71],Vku? %;+$?)2D"!!<O@V*!6805V*WdBi2D`fN]I&9b=if!@c]nnPRU_Kd3Q_7&T2"d^M'^[/]hH?TeZ02Oh0ZK8-hLGA=J-Jb>n[:SM5fa %?)=QX(hFSQgb]pqbdA#+a,rl.%>@f<]W/=?1hr4Fgf&\(/F8iuXVAp$IK$"f$HkR8@i%'MDNYupDY0ck&<X&omFie,#fkrsdQ<*3 %s%P"*\nB_]<[u_P5b4Z`#F,W\_#D$7Kf4@ce-E&0P0+:NAS@$"QiX3d7>j1)s+iE2/=.sVq5C5ldL\MuA8.lAd].'<YpH-*=&?%[ %CK0R$K\ZrZ(2^Bi3E*+B<DjS_e<V<9>RL5T@E$<$jF1S1?2M;J9Pe=O*kda&,$76<T0R0p\LE._=%m)Ec";;jFY-7;W+CN'0@kf_ %458M%ZGIk**]d_P8VRQc2cDo(aW$[)e*:g2ZF6BfBWNfAS?jkV?SgAI,aslBlb<iSF]%9Us*,kI0+PLH&I?c_\iMVoiG+R95[R#[ %]OobLV'D580'.,Dl-6pk"rrAqP4GW>NNni*^01l4gPWoKhDf8hmSoCorr*bmMKDqiinI9RE`GrD\&DHq8*Tsh#,RNch""OffBY_a %D2q0VY&Pg;:he>4IRPDBS3QuE/3&lZL(%#;=AEE#$TYC.OpO0")&o(SG%"qSiX=tj4"lBLpfdn`@Y8iG,V,hEk(.'6(3l=l)XWcn %Lj2rH4u(t8:+Z4F;0;ZUKLb:;qU1r]JJ?TgG@R_]2-l>V.$^oOE@kSU4(`]b^%aRFh<H%^`ekDX7SLH2T%E!>Zma9,g^K7YpUiQB %AGr>M0CT<ookG(!fjgpo@7`H+K&1f,,,n)9Olgh-5d_;EVTEF<H=Wl+G$_$#HJ*c`LCl>6>Eu;3VPWO42*fE+@GW^7$Rn\B`T>pU %Y2@r,/)$$o,a9d(V8pM2e_ee\%r21*JiiE%$d^)AD+:U2G'V?]>+)USMcShAMI+#?Fe)&XW?P$TBsAoi[+O7HiHdA)q>cO3Mgc2: %6j?:d=GS4KV?+[L\ANVo)=^k=7Y5sPTF&p-1q>rBYq93d",)+FVrR")[We<0P1DB(U[8XMYXcBlL=$cnGiOXIbbWm7AeoTcGHkZq %"RX1.SMoHh%bZ@V+[6!g0r%#i>GHHPfaJ_&C)KaL%!GY3ZFs^71\>.lP\&MuH^!PWiKK-0&5?\a=Q8oe>Q`(U_DORa\qpobaid(a %rW^V>2;.csH?,I^=^dLeLl'Nc)$:8[cT],p#D(2B_(MPrk6KYnW7':B?fc1*4:mgLYqVRsg51K-g'U\V28(`i[ZL*B+],)`%PF$& %DkMkWI_<h&>s"q"dG<k\NnlNE"@tEC!c&K+gSs,TMGiA=TYI`GFp:]5$/Ei0EJ%8M1J!X>?cJ:B+=%fIk.Vg'L)[.d2Uik*1/As1 %J9Agj.!@4hP/>Rb$GTt6S+!5_O*o/Q05-THDU$:4SsIT63:)&G9-h3t!iTEfh$j=VVknkafgdS(EQn=0Qnbh<\"8lW#%S'21XtEY %eE\H4V74mnfH-\f/sY"SD)<UNOJ0fB6NDY")O1T!+Wbq?`##(+OpE\A)?E'_ClTX3&0+M'>9QVYS[0h]eAtHR1`fB*8`EYS:eR/; %?T.$>cblm:j4FP4:bS-JPV"u+;p:plR[UG6=u*%`?:3YG13@a,(-6rQdHTBe^h30:EfP.s;/R6l^RAE'ctksk*cHT;j^+ZDLcj8A %*#=c1Gc[9seRedCqD>qXq5qlQ)J=+448#8.9j/W?+?('O']L+P)B2FV0cIH47QYs)>`osHV3nO-jE+%4aXI2:TQf?BOk?4])sB,e %&2bgupNh5Fd`ILsJQ7#c*6PfC,XIgOkrO5g;I_I,,F7.T5+5t%aE$OC[RPkGVKi>'LdUj[%&M^j`sbWq;9"Ol`o9<AHRl7<0uhb# %QQbuf4?\r]0Io+@gV>,K?;)2^g.m$2<&*4I4p?(4],Nmf1,f2$P$1S^_"1C[HCk=T3"H4`28=!@ehhcV2<Jcl_XK\JjXb`NJb[&S %Z[eQUf8PNdk/Ofmd8H]bf&5u6`8t-SgcNL3coAQ%eDFAm?a`U.C=?U\Xs;BfY)\&j=F`5_m[4muL=FL$+PWn03UfJA;i.GhY3<@E %OL?bs,eenJ!4K)I><BP[0[J@Z)U%M3Z7fMO@+TQ`H\e_Lj4.H-b)YelKiES5%&;2o#g#!li%%DTpoWPrZIm@dRt_f#+b7*lXXMr+ %VMOV%(A6T59lo;ZmKSg%_b?b*H5<?s/p*-,)4_T>Q!?i^GF.P>SS^2O1R)hIOjfp*59WuGP]-t@![JB1ZZJ@*&"*DO&V_@[LI/3r %4i.%D+-<WnC02okb&"m+,(_"Rl`D_3AWNVppAos5P<W0L#@mju3*RQc=?mb%>.u!T##3/pf<Xl/Rr:T7l8(P=P+k+qa*(4bVgI)T %'[Q<U*=rl_3H^R_1$-JGcjjf@SF3l=O$!#67Gg:m]B/psEK[l:M'<d!Vc)O.2]MEF`A':M4'd*A_ZNYLV-j".[bk?]i3)p&fDNKA %?HR%A$87(`E#+T$9hqg"KMTMV41I(I(^!C'\JET_W\=_"=XG4G;O^amRau_"N*)U$a;!>7)<+r()q&"gFZ/6"G'[cY_GIK<^M;>) %1OuVG9/_4%RT<LLYU]pIF`GC5]5@m\ILpt7s19EV^NoVJ]=3:cbOJhEs5i2J1a"VX^O)Y`]Jlk;VrYNsRHcXJ0*&#JNNL;eN`jkM %^A.V9TESfH,fV%+KMP`*(Mu6q);@7=h)+P-=L2ncXe9b;Z0N;.p@),)!785@DQp(,!GEm#)_BBJrk#M6b7c.aGLE$&?;;a>f#A+O %1d=O]85iSM<KY?0/?9VM[6?jJM$N))1YnX)nuXbQef9K8?#?DRDZkYWXJJ0d<t+iI^Ft5S<HCnON=GBKBSVi$^N:6W.0U_1;6CP` %2n8X=pXd1I],,sJUH(^3"-Sd&0p4fMH^oi44_6%l$!O,pg:%q.G&iW+mLCq4LrY70i[i3eG-oh`]G3j3ZLk!BGP'e_>htk9h?Ggg %Zl2BFZQ^q4%"uV+KH\+3(2ok'd8(8nLr,n3%d6TL&`<c\7ep%(8eK-f7?^!f\II%>aX3fh1*<JTB*1PQe\#HDiRFLg`W`K(USDWn %aUkS,e_L'/KHN$+J#g5f\!B*E0WZ1gO%^c,E>=,>^-a]AB`uai#&08-@\kT#oda,g8r-56G7e[gC<!sC8$$m0NE#Hh5\4A'bg_$_ %SV2k$o;EM;bCZk<l?k-i4[=?BS>(QMUWG"r:%6J#_f5R"WuM8T6-VOA'f0;L?_X\J+k\F\dJgkKa([gq;GnR%Jj7`"j%J2nKHm;Q %a3iK5%tZ#S6^PWpPbB#:@^+bKme$uL48<YLXoeXLG,7\J0sFciYKf=LZe90dK,jqGMaf81P?A,r$en\*Ci:^mcl#U*Es&#V_L\[> %*(RfXLTf-r,6XjfJf)`$U)MN82*j9J>kH;[An;7.(n%KdQkP$?oD6C;8Y)LdgLkVfL#Mo[!Sf52E"(a<b@[j(P=G$7UsY"-Z(YR' %*3<)i5dZS(Vk%X'(Y`IhM4-9),q>CFDnf'%>sR/H!<ZjT`OW@-8SRh#.#D]Z1f`euh.:ZtS2PPI8(o5Cn-XY_ha![963UiWck3EB %.E!6Kh;\:>M.ntaNej^TmDm_#Z,ZHCH&Yn\IuMFbRe'b=jl0ZX#A;:@#UN(YN8;5&dEPMa!&sgaH]1Me3?#=kT`GS*lT(rlK:K8D %B&"i6FVmo3C2/:)41)XFN!u.arctrhc'VbR9YfB8l9Wm>_`FDgmYjgk8kLCQAE$O2LKc"r(4'K-ZSD!cpEqA(2:K7&%U@SO`nP/2 %KO0Y^Np=`+HLF&MhWr,s\A/#OBY$l7nj5B'K1uki[XDC*:EsmU0\r=tLmYK"D$;X+Q#63<&3qFp_4(ZfEXg\)`*9*L.qub#admT! %$.!gU?U;'<Uni-1!T/h[#AYmik?=@noui]SSi9f6B&/C,2\TMl#/ZKJrmi;Z/Y*cLFmiR&F%h^"n6!grcR5s./;;6JV_u9)Aioci %`JXHBSXqr[S9fY"D1ap@a*eoEBk)t&j5$`3c5gtK:uprT6c(8Jqm$E"4P(0a7&=Ai\3L.tmTQKI=R.li"K.T:4t!DBFPp(Ko>.;b %@bq1W!j]a\b"KT[qWH,sZr\XCrUp!1Xf6jY6Vgkd`d83G!7R+Uapts@4[I9^<N`D`bS9I0^\Gsin+Fqae)lI(HY_J*l0+hel%/Y6 %;.?cTT$^5>A51NsE5M6m1_&CPrY8EZR[\gD2l@P[(.G@dP1AR\0c<lL#,[;ZlD1>`_ObZtLgXeuEdS)F_g:lS7bj[D,//m$O;<Qm %ll`3['R!_[F%92s*AYSfU1NQ-.q0P'E(.+h.jl3O%"6hI)=oXM#fW$N>Ld1U%*Li[c&nPFBX4`^ebt*!(`)r`=1TP;@k8Y3.nGVT %T>n`N)LrVqL-%<2@d8+ZZ+6W%UR@&=Nd"-hf;9Bfn=,'gNh7qp]_5T[h)nX`cP67grT<dkU#PD3>1gZ)'i1LuGeQYf<nrW=`u5]N %BT7/?nSIIF?XH[9e?3R>-/J9)qBa60%JSMQ90FLHeLN-M#*^+'2'U@%46"-B@qH!$FK6h:`eDAC,<[>h>8fhULLtEm.(YON(6s=$ %pckk-8m/ii':R79<R8\]bau(4,-<X4S$=*<]!EZJ#Uj96q3:Kf_CEdG2MP+dCoC+>Tf<$fm$$U;i#])%.m<Iq)oNY0agcMo)Z^j; %DomEF;4Ns:OB\kTYa$AaaeA:gMlH6"@LNqj'Vd#F47COtWA&2?f=QBL3o&6u"oL"=H`%@ENt+Rd2F7ChG47Kdb]q);ldJBR+fpgd %>n*cBNLbp74JGW<Ja"A="_N;cO!<.L8nJdYbesmr]q._D%>jf:-Q&/b[@[\Cl!hBa?X3hYQDlKs"V/MiOj1erSdJ?V^%$&<M'%qI %(2U`+T$#)ad6o_]8rnE\YSd2'M;@D_O;@+m<U.WNWZFq_FQ3)]Lf;J29p0@:)IZ+MaY^N/OnkNcgm0d#Z'7.9!\#C6O2>VEr!rT` %A:u6PKIp0_H+Fbj5,FXc-0ZDrk9N\EE!t4d\)us1Gsa,Uj$6d8)D0IrOU:Lee9IoqNnj//!Det^_IE!_Pjk;9Lj;P?d.5U:F_lqN %Y9XpeO?#B,hnVY"Cq/,f/[]SRk(lg!c)A1jf)a!K6kMkrj5"9f+ur`o`(pX3!Tu"SF-WB!3!mthP?o>*P.EQj7OJ%8AuL:4AV0^d %m0kOe`2nSd0bqqIkK/&[jt/6&5(PPRjWlM>>FO*RhFCY5Nd;r993tn"pXb`LCrqNs#9=_:C-Jj>T<n*F[1T%Fg,NTc`%72$@skfe %=]H1G+#qU@k$G]%r)BrsJ6l/ATgKjRHd.#?o"*53"L"*5VR]?FCnmXiUMhqj;lFG1.5PRgCq"u^?u(RJ#@XbZ)&>2*!*G2eqaQF\ %EWbX"lsnf+nqGb5gdG&nU9<-16mBjt<JD._$^+4BZ),YFPMd=ElFsMO%^TPY;$.AIO?J3^2fq0;dJ2D5kl_"N-k-%)>THcPA+?*] %H:8']6f9B?=T[!=DOG_4=5iOm[r00/\=5QTh56!Yq@"c(OYlo?S_o#^gC(3WbHe-.%R!d5i1=<If4\q>et(XH&D7(+XBWI5"FT<K %<+37a5q)EO`bL.LAfCo,/\7.Dh5Z[:,\S;&TKegZ,):d)+*">^6(bmD,E9s*\n%u=F,<P*r$C)i)ZdH'q<GOMo#E*6+o1(Ad/$F% %03s)$@XM?>T:)G-"uiXJ=:I`3N=Iu1']%_QZGLID86+80E$K=qb&TbY7(We&FOD]O,C=^'Wa2oqAW:q=.8M6j4$"EA=cFF`W1ZXS %Nae>Eqd*/4+KP-)g^?"CBnd8UogXdk)U]KH"<Xe@7tc-7,Q[.1Ni:K35u=[JE^@73PSP+l.N4'_i8.\Us%T7Dad_YhW&uEIOp@3K %-`2;JE\Oi?_c-gCae.\/&t$Rm&L9,k`1&$%.aA'XmM%n8X0#Uoj(HWfBGR<a)6[CPD*C*QE,+oLSf2b%*D#!RO'CY*4A5T+g[8@, %gQ**I=JJub24OR5c$0:Pm7H>!A$oB]E-Ck[D>X^fc,%Oi?*QCC%X2,h.b<i'r:G?F9d0>'-W)3mNXGd-Ls*nH&TciuYua1=&m\W" %l?@kj#&[-*Ddn(+6NEQ^DKmUsKQJBDVBh%d\k4)VN*j<2CM0HO"FZ^[e]+X97A&,?#'sYt:i"f?.2C<$$R->RfY\u:k<a1,eHe\o %RFtZN\=OB:CLg_epBe@&L(M'O?c;VP6[>Ca%PK#?Us[]RCY0ma!9t]f@l-jt-T;2d;QYR[fTosI0(sRe[bm,FA%ZKVX#H`c$H1'< %T3>u!l;]87\b:3o1;ptc]nFi\Ql1.0,REP,$:Ye38F\\-bC#[XfVqnRF)OE]Zmp<le?ZbLSW!&_/(-W[lpW]t]MqW8`ncM^[[Rii %h!Gj)Z;._kB^gP[6(]O9`o25QHsX)!3ZlRo6p:BSQ:sNULRXZ>`RHOVn,;o:]ol/V^^WhuP1@IsXt'==*BAa2*b"G=PsV0bc?ZX! %Jk"n$dNZB4."Kk19(a>Oq]5p>)YNF>NT\F2rTs`HfF#d4>sEGX0,SYckl1.hqKd`b]3Z_8!09qM]%WH>R$6</o!J2WgQ/2m5KaR> %A$fO'0iK,W/%Hdi+kr<k\Kk`EG,IT24VomY%hsT95rVi4>&@g%@nEtFP,`AW\e_m8Ho!T[j"9kYLS4fe\=9UBG/4')I>(N9)&V1N %0p`R<rqcPe4"+ju'9u#6F(gobek"Z'ArWSr5&7SrILBt1]_AM\)K?$uk+L_L(+bfcT6qGo)TX(,.ES`OQ?KbOb[IofMV5Bp6L%cO %T]D%U\"7&9hEF:!_DPFd+3A/a7\jUT>eZrQc+M!Bbg!7eUfS\RSB]UE%Dk8D!'0^Qj5NlY;dEg<6A&X"%+'%U@kR`$V_r?dfp')V %#6;$041,[$9('Waq%bCE-FR\_a)YY3->A0_1+hVCp^qK[ZFfrNToh5@RV9>_;.G:PI)oAE.^tj<J)HI#JP=m\\.sr'ZJPF'$1QKb %R3rnSe4)dgQ(LaXS#m9bTGdGFCVHoRDXq=aN6+JL&hqtqO1A<`BlffA\#juC):J[,NV7\p#4*I8YY^c=MK:;c;.FR?O[_SS3F(-$ %"o5J_7tsJdgPV9Bl.=ADmF@,qbnr"4W8U6orShQJBR>t#_0;+c?X.G;UD_0W'qH!6XhLu>(Hki7k_WHC4,!8W,n>d0J3c;^+3lQ> %!u)0Qi,YAjGd0S\9kdtN?<i?IO@CA'A<@3QKlR5(B9ih7f8P(P'$V&W5B?:(ef;`e>.Z&2$hbb2-)QsJkY?d$3LL2M)cEOMc)`KZ %pi/pX`MuNjp'0i2oN8Ng'2FY+CI.p\NCr?KUMO`&Eg<&T1YKQX%qN\38)4W3^"JVG(TmC0E,:c3@NqbUrE/a&MVO--['%M]P2tC7 %h>CEZ:`S+1!onNUZ5J$_$XE+ra-D`V3pV<.$@[jQ>Wi><)W+Y76P>`o^!e8S/\[[o(=F8ZCp7%K?ESH,+\+>2Fr*\@^2,PQ-U-0> %)Ikk2S$umF3c'[3[QpHc;b*(1Vd>`cZQ,Mmf$se;-)kIV/"_RD'cnc*qP;'[L\1d8i^=><p#S5=P#>l))3+A"n?`f'FUfNQ9/]ia %/8,:=RSmQ%U[H^Q5K3nTE[O*$8V^qcn,E/RI<XYC:Fk.omPL\0_gU[uh/t`*6pudJmkQOsC>=6_[>)7FFh/0m3uYFo'/pG/rEPi6 %_>G2:TF0tH*^39HVV&Ut[OhRr%@C77>W-pB9&U-#dNd5oj&hM>*N*DO]S7/?B(LjXG1scI/3X7cc!Gn6pDTBrG4lZr4Y8MNWsP#u %0`KcgX<P#bLqEQC09%;qhuSC5"$^:7VU:4RQpjJ%V=G`tdO_V_136fel#*Z#;?3sA<`UR"98gQTY"ZlCK1T8c_*FN-*8(@EO7E:7 %aRmo[)h:L=(_E6P_n=*]YlWJD&W`RZWbUQA@_t3%ir,&Kqo%EtlOu*7`G':H>BoQ%TmC'8YgS+4Aq26a:a_7po<o._(1V$GE>fR> %ETAlephAdA*4WaI2<^TD+N>\^Umnc;kE,mAc&#jT?3S3NL30Bu1]U5dm]uN.dn5jigB6Dfj53>o%+R&9KXr\pgc!*_Bb9MeL4`]= %n/VNu1BrLZceqX5DXhTnbtBsTEbZ7+%k\i9.to,BofG&#FKNG&[C]p#W:6d-7bH)q_qHfN>2H\*8VK,Y4^V3t6=]<mJY0fXe1g[/ %EkH6?9C&po>:ft8H<)#F*.J9Q)iDBFS&jprN:$1?">]?b\6FA9""p32RlOt*8OI%o'j=Sg^-q0s>,(0qWI0j24.C-Jeha"!j+7+f %8\fjMPD&d`YW_=Tn9[e2!u3+d!,S+.M.5"F!J5\!n8J)*,[Qf5<\rTLcWX:/gI0eucRZ8I5RrK[)V#P]"0rD.P(7%M8(9!2,TuE) %U%Mn+7^+iZ7W(/TVep-r$gjW/+&;_q]Pp238CFlNbqS.Adm?S0qXF>c1gD<CQFYU:'\LSCXXnP:,SsBkFmdD+]CH4;pcGp^SqoYn %rm,7UT[u!9qSqt-:.,hL.:bu)g4::P%-F]BS*?`-Orrul?UiL&9[F]2ep]44Q+$oR^0&(h4)Z/GS(+a(>s)7ErY7?>Q-nsI.t7*4 %OsOb`+MP.,?>jBd"I#7DC85_UT64^"]?fR%ahD7^JY#MENVN)OYb?fn$k"C?_8pSJ=R7;1"3Y\D^?#mDmmghTSCc[K=pWDq03Pei %o_6u3!neiJOaZ3oX\8Vpr9q[,I=CEKh^Nf,V$u=8?\gEHg&T6IT98d1/6NRR_)c!iB_[3*idjB<os%>S*fMPm)LLD@N"Tel<9JXj %ENK\)#ad(6)m!.Hol$*lCo6@_VEIg[e6-',.tJ[J/ps0?@KXkD>qh0BrRdgD_&W-p\m#U-,CmL(2kG-mS<@p/,]G:n>#<7"Z%%WU %'\V,m'4m@hBn99V1GT$3(gh.@NZsHCTFbmcDeV^U5k&N6kr*,f6BQ/'!_0&H<<t2-6\J^8ae;^a5q/2d3$8FJ5%iNJa1P//3Y<@K %ESIFpm7C:?f&.]s1:-:d8E9'H]B&+6V\>C#h"ERuPE'#/dLYZ\(uEeRZ6VmpdkUGGNL>P5bQ2l!1#909hkICM`5^(_V-uT11$5nu %;PD4I4[lB-O%+5V1bt;$XA[Z^B\p`#Q'bam1/Om!?"A>9>2mXk,WqW`DlrJd0Uc5XbPKLc@k!$V<#5&1SZ@rJ-[-'@d>1AjjHrRT %J1%[*'SWU^0]6(J\HrD0IR8KjfbM20IShZ[Ho4$*[+YD^>mMjF-EDt[VHDO8+f;RL\X&GN_RRCC=pU+).(Ibrn$[*1aMlWaiH<3c %j=+bG9b6Ok.X\97%G"Wn@[."24L+2;A3n)r<.!'q=)a?g4%mb$@qV&.MNl)amgXL+Sqa-Z[R'DS*+&ujotiRGioCd-F:^Y+cKJco %`-UL]`]+)S9b%8+p"?>%*$IBq9Lrla!,;ae2K=TB[L4\X_J"Ba92k?slH`XDbVUd^\<Bm*N$FQG<XU(i">c"$(7=h>(":.QqC8IA %mW'tFc0MVZb";7'TZ^)N%Y[G0B$boMmRBsYLlZ.C"M2(Zd`2@@L1)rA[i0]U$oK0p%@9H%+dVgYVl:>-npn"I3`Z<(W!.sF0VWe& %*F=h6+E)FY)llEt16ukVm_5]B\"i!UK$:gL$c3276CE#DkQup1YKCPm\r'Z"[-3=+DiD<9#^>rI)jQD)AatAJr<enn'Ks2`J.>M. %fd)Fe[jL+eRp`1V`b<b\@K,`/G@?23VXdh;L/]mG@a:e:U4L`djCAiZC"8+Z\i$\C3L3HRdAn>UlN2RAR5qnX7HS4@R'gZ`1L%O\ %_C5\B4)p=$T0[F/WoY"ud5F'\5_sR&n"7;!):Xgn(Dh`bTp>"3L]MT"'/Hpu1`XRf)Pa>XJ1(QBE=Q*FoVB&@G('cRcZnN90%qc? %1TX;Z5H9Xh.baa)0nC=7BF]8NKb-3i%Sq%2'EYb8,.:,CMWsUo+;)QfNep)6C0&tF@LVWDMdmPm/Sf$`9:H5-.P#58BW#s[Q>aG, %*bGhj=XB9_0[H.KGH'^oWrOZ0DI*Z=nfVT@iSR-FetJ13K-MjrZ>G157h6Jj8>RbA))Y6i(XoE$h?;"_XVjpob\2m5el]`-)9jm^ %]k1e_WD`fkUf+BlctS_]`oNLh3tn0(8A8mo;U8A.-Wu^&)?X"O&J\o#2Jk'E\fr[A%<YclLfANNiXE_aI;)sa*A-HVMrY9fXDZg, %4eu7%Ebp=:m9%E?Hh*7q=<)&)7ORm[,r0<G&TbhSCrmtFZC>i.ifo!`?OK!\ZsF+ufM]DH$dc23Xh)g5iuDHuZ&\45Y"%ZPS3&%f %Jl7tIO$;<u'm!l,\:ZKE`4-ZoZ<Je!8_YN,[F,FsD)T6<!Xl:b'1Xp]EAti\`5G9D_QC^OhO9gIRq:RIUbUfV`+>"#=`794$FETO %"]sD,D:(c:Kg_uB's;E%6oG."Za#LlE@lG+*1bkJ4FTU((YplLSJmHoJR+43noeI!)FC.:PkI6b2`IRFg=hT4&Png(?sPkZ;KTfu %/a]kffmGcQ<,W?j>a_Z8eqG!W$tBGTCeo%Kp;C'[BYB-lH5Ms=MUY.kF#G.Q-E8&<ZU7g?^!C%#GJo2//O^mCdCCM7b?IfGAB))V %hq*ek:@/+((D<)ZH$7jXFhg^PN14hQ@Q=0X_BM^g(;U4O`chU5h2,,>%_S+:h.HGrZ>E<YnP"i$lfdhM:s[rsIMA8`2B$g7(aW3g %QP>`>V'%!sH'3\NT_3#l@$d%U4o'Pe&s)Ejl/k!+4)/1^J`8KSoc0es*$@]F()IotCCTa+W1RYbOTIuP.B?H7)J4rJD(-U^@cs/t %!I*"N;IA4u`9`)ganuS?XjWLd2D4OM[FJq3VVjcd>.LqBJKMnO"1]B4``iqd>c;2N=4l82O=$Z82TaSn>PA<-1eqo30F)3C*Z"'n %DL$E!`r/5@AG]cU8qmLLn!dQ\,o<A3O&FhhJ=G1rqaU6QCg,d3^-g/L.hqfb54nAekX*PWogqMGn1Sm9ge@Z/aVZ9ngifAJr.ZG_ %`<Sr<7au$[@mbW04k!Ke4DLOC;&o6e?,31:bc&@$>$T7BjK"-Mb-J6P?rUlIS<b<:R8$%?S$dh+V@!%+O]]/L\?G9fd<_'`[CtX? %TkN4U$]V/Ogu<ja95QPSX(E"T!H+TcK"9Za\VbN,a`!,;PInkf<'>C#h8>ZU1raHn9Kii\lQUjrLq_LFdE>Y#Lusr[T'Yhp"!KIC %M\i`#/"g+CRR\3`o6Y?/LQHlmp8#eA?KfmEf4ro/Q89-u/P]2([":MQ?e_0BE__W_3:CG=Rrrp&X0f]u[&oDi9sr3t=P/6cM6Bqj %M67r*68a+sAFYFj@mp_1]GKEn@?+,pNR1cP:[>ak4[%P6/j0j&l\g$`Qo(i7VlCum4"k-JZ&4KMq2t3Gb8*B<UDF1RM%]Yq4<'5I %4aO-0SJ^:OO*;AqgN\c)0Tb;6s/LIIl[gtqa>9=/P&H>Q3-s[lj;<,h$VH<Hg1%E\H:Y'FGAB4r3^EQ#Cq^nnLIubBM7i6:1l2Be %-%fK+6V"``#\PlD\5kqqHrWai899]B+Kd$;kjD,DZ*U\]:FE3CYdX3c[bt(_+VM?$]L>m2ilo#9i`G;Y;oiP(H&XBiY<503>I93; %ZE\MW,h]XTY"X))T9'kXcYc=jf,;muho3X5=hC2T@:3+\!Y`'bk<j@eMJ:q+IE54m4P3@sjKKg?@oqi(nH!Eg`!e!6e.:!"Btld& %0:q2"1AkQfMNX?%'^.NbEf[QMKpm3/?YcIU7U?E4P(]?mR*honfL<ZNS(8D]o*m8Ek[59jm6Y%16Cj=(-ob%15pU/"<\Oe!Qn=EM %Up_"m(k0It9KEfWOqNJ3.m.W*T1E"'b,l]ll.IqO[M`Ok,*JF0&f+j[[1R.-@e<]9X.WSHSZC^n6Nsbo0uFnkh7mIUJa>u2,b(^` %N+fZSfWF@6)p\-+HJ:&k7Wfs!Yf9d,8>H`:`nAC?`Ck/p/`C3!QL$/!/r.BDatR-RCXa5>mimPSMQABfI--$W&Wu^j]+VL.V^]-W %V`6k=[0qg%bV8haXD18EY;V8ibBeg_.gVKQh^`q:gH*5!pC\['Oqg3h`V*3Hh'taB09oIGUJ&K?;[/I=_VD6j1(&=uqp_XVTasl8 %XUBlEf$9a(d$UO'M]NEN"!TUXH^;,)S.e=(*P0^iO9QmQDg_@_+eu<rFk2bCdbro[>klj/jBBc\=qK/+NtjIuNR]Y_G\A*,c]l4O %YCn/7GA?'peMc/R*Toh9a4c'c51f$IhoFnND#6iY6lX9V(JR_)Gik<0Y.ht1(d'i=,bXJGk-it_BGm)VKoOCIjB/0-UO.!SLFYN0 %hg"lW=01WFiQeMFYsZBk*#T,`dTQLJ9Y8$TB`'nGn3-o-`?Bo4aTr]2mXb;53h;\5'g+5t+'eURI&ZTE1'M@R.'SV\FL3[="X2\S %P7Z/uBRFk^l01OC'A+G)H%e@0d=Ecu9L*,[9M?9q@u@9(,5J^VF<KWG,XpH;eX4(N3anCs3!\*?C6^Xj4a3uF`M2.&9a.=QA+\E9 %K)Tn)a%.+'l[nU-2$e7Goa_NYfa'iE24!+MYe%LO]r>BS*QJ(qNJG9,PD!>OTct:8?J7/NKt+VPTE7Uh00k;!;PeH20iZ7>,DXE@ %pE4a;L7=::OtJduY*@"D4a%-s*qq(1aTPmF+oU_+I1FnIRVfUY;J\=f71IN+<:RMgW<-448>OR0cf15aT]$a"+Q*F;TM3RaDTIqk %NIg(\<3R7)$IlPf.hStJETG);(0PEh2>Frj2V-H@:/6)6CCD>5on%($lgYCL+;`O<fIjO1pkd&H0@U'?2A_L<`C^>W5iN5-?9!", %E,RFNVAC"#@"9ZQg,FtQ4FJSs>aFI:G%$Kt23/IiO:*k^TMqDs49&&en2R>_P?'D!ruuE?eD`?6N3Fnb%&gfM1[;-#I<'LQ;5&%_ %BJi^mMnt?WmMIIG3m='_FdOmt.bA-?>9^a$C58mGADoNX@3Lf/)\Fj[ToaurCgXq:Yn\YF:^Rf9H<;![oF(=cqO3DI\%>5Waj"<N %N4T>%8Y(\h`:?"_8a+a#eFUiC]m8QS#P%:UiSkKRr*`l]8ole.!A&_jNm2O^BEYGOA,.gfPrLOc@rs`)'GL=s5`dmU\$BrLJVB*V %7`ds"#tTK#[^=g()2i?cR/>>oNLB^,\%Z'6U64b2];<'1.[*61.!<g$qGrO$'":H*e?s9XkWCes(IA,!U]S@j!Q-b-%A.eYM2Z=k %P#qX)N!YATesn[pHctmY+Za+/`]UBG=`"[HHfg&tN,A-+Pm^30>H\OUF[4Z;ZRin%W+8Qo5c>V5Z!bn\%SdWRCupL?>CB1Q1<fPt %Yo1*6\>LfoCZ4oE:e@4[JF\HZ!dV)CYpUR[/NJ(I8rP9[B?.^+f&G2LTogq83a_&YU!P5-$SWdobYk[e3c!ub\P21k#,es\P]W?P %'$4E%;$5V;Kt*0C:"/1Q/s$IG_>D`)BT7e:S9^c?,5ng.1aip:$_bnL#bE``V1i%eN1*A!.?-rJ2E@sB\4SB(&[s<'<(UuGat==G %NM*F&NIJNtrJ&Et:Hkjb-q#i?[K=it&aNK8D:u3$KA$\F&MaZ-V9I<ur!@k[K/CCR,+,]jdd<SoTu3#=_KNN=Ki33O)E,>sZD[fF %\Des1boq:?O/mHf/c4497oZN<kOiPMkqrhR[8cjJ(a!G8la<De,ojF3XV\MJD08]8i'H+]'7*<qlAa[pU>YBo7m$a*29'F5\N:-g %;eNp"/>/;Da#/OA'X"]H(_[K<<PZ1M;[O-Qa`;hg<C[mbU,a_"CqmLd4j&qiM0-DiWBOS#d%,M"Ld3fr[,##42k3Y!%_+8c\u9h9 %i)pf/?9S!-qoMcr6<rD9MesO5Jgg`cKp_R"R[N,>'dL?^^S")^59md6FmgU)B"IQ&*tf))?;Xt/(?rXgA.ViX@joAUCirj;<It7' %*=49Afu!W2-'K!>U/U4V-M:KL[/2@<P=$t4]9P_K>H):1IS$8(P##0r%dt,K'Y_WrOa1\AAJmU5LI!8u@trO2N![.M1Pae`Zu&W1 %^#8Dd/Op`!&LW\u*6n^k(!6k1feR^O)bitd<PQW]*HX!Cd/qufRP7&tNH4\;V^O5?P8CX'a;t`VBq>W9OI9:3*D'LG4S8!%>_#Y@ %7$=j\MaT#7MdU')A97"Z"`u/SXY((c#i(s2nVE14Djo\i*D6L)9F2L#HAG&81MN12J@fqIAanj-3PA^]HPsfgWY,CPMI;BE6Z9Dq %ZQOiT>K+)\,MD0/)3G9%-cHT;pj<u1@HG2bT;6'MYL/]-H;oumL-[_'npWJ(_^ejt`ji%k)EZ"k:%!]ZV)#4S"ICMeW-Dif>%O8C %GfTZ.>&I7mU8j9cAiQ%.79ZR8,ZQE_PGOMFSfO:mr/?e?0LK>Qg%=V:WN:fP'F_JO)Y$Cf/\rG7OUbHAZ[A22WNfJORm;mO5<,X/ %`E\\;2(!NiUbK\/=t5^<msUR0K/S#gEKH>YJ?#m8bs*)37-r$HN"S,gNM?i99*-B,,bS?6[^o"aRdM\#V_O]rC$liZ!8Km-(Xpq= %^f)^-2uNuP)P_Z#8<6&@Y&fi0LL\jnm`'Wg?uf7n[ka=n[V]A5.F[LJ4)2:r#a4]V`1'X-G_.MQa.&/9@5^anGA]9+dg<)h,Lu(% %,Tg,kW,FS$X(GZ<4[gJOo?,mTL"?^_mr%!k7K8U2*,M_/QW=C?Je`UJa9^>"6DMn%Vs6J`I5E'k]<A#e&#YfP4$OV`/)]"]O&W;b %m!;.T%\UUXh(DN&c)m[jr46+6`\nVsiipQjjUZ*Yb^JJIY-S9Nd=>n]m;EQ]P7[K4!s]=s_?[FM\]fd&,*G<g3)ra('jX(0>Y/.Y %HV=(WT(9<Y*^c:(GOh:jjs1*A.?ZcNFGGs^fT+XT^jAracH'N.%irhS_1X(9pjisSWR8+DL@!*g3hfO8_&T,P<u/Vp!ReXgD3%nJ %#nbXfKp+`ol>\S=NYVAnf[H"W1:@REHd=UNoKqbD%A7d?rHG>X;ICkb(kRXKAfD,+iBB&h7KpYq95TjC7W?#Z$n"]9Hh."In["5H %8jre.9Ae#QN=Q:.L_X?`'Ea+&o3@-JS3qi[$Y11cT;<3Vl=,VHcb5Dn8:c%D@^sPbWXrL(J]47E6eRK:!q2b5bNB$9#*cWm12:FA %?>n5R<S)3lUgECPe+An$O1hQ,(gb2TJJOW?5P?HCX/dpG;t2ol[BfIj5=K@``ml`UWd^B;SJ4LQp2V9Pk6U3*Xlt=BE!#X[![=2Y %G!WE)l[krjFm\.XmiE_h@jWHZ`YLj%UjMDG7BM3i$gRTBB2IhVD59jRZRh]U8T8o?FD;,,;9G`9[bq/I0[gIO@ZT5f3Y_YndW23V %iPh07)-Gse7h=6n'j7o[/tK+u3FDS<KAZDT]AL_ZY>"EFUjB'gF>7rPm3')nN4)<bqLpqTTgg4h:gg(Um=Sf/(>+>8k4k^'"Z"ZT %Akq:?\cB^'AiALh@8ug<:u$#q=Ml!;F`.P?"1+sM\X\pH9pAJ1SuKs@jAE'Zi3F\mIGXPpH3R7)6",q#l[hED[7m6Sm/kQd`@joJ %6-Msm2_IctNRin2jMJhLWs_!A`%?Dd273ZUG7A'M\CqGT0/)OP6rdeCfK'fSR<L9Z_lNlLcc`dp'MXS^c+W&aapIS4jJ<HX3[FK= %h9Phi5>OY?ju!V06HGP$c+O9r0A]I:m:#Ep=;ui@,6U>LLBrdiP.#'N3-1joQ",Zs2aRNe498=]n!so(ZMGmUBF%mjiO]CHgEd[, %">@H,V%E\RBiHQdCK/3$#lXW-3bn&OnOa.IZe)<l&E"s(cJ3o4,`::(_2gG`/%Q<qqHWb:"k/B7OSIgY]NMedaHlMY"Z_3W>mVp^ %q/1Cml.SAch+itS8UZ9)!/Z>F+QSNJ3ACS667O_lKDK+)//P-\CKP7SRKqG1\Kfi=UP2T%dU9[fP5t;1[Ip["8`Ws30`LBqY%Nnf %af2Q(9r2C>&H,Qh6t80VAts#j(1G_4/;Xm\;97lL:D[&ki!Hagf`f94q#tOjosU((l@Ln<dK'2BJO"EqT:1jE+hGQOS6%B-;qm%0 %=,jBJ-hE:-WLl(hf2^lP)gQf]g3u1ZEPVXop"WhX.(e;^HGPfQ&mjYuSZol/0q+bc'>nieXcsR_NOno9==])k1ai<8I>gb^+%=(` %?cf=)'^)rA&g`(qe8ZZ.Z`oTn[]3dPKnRd@mj6`<:bj+%.LdNcIFk;`"Y,9[mFFo9<sN,1O4)Aq/ul>AY.arWOtNA`'=i`i69VtL %Ji?!q/>FB?^gjrmehL4!?0JG^l_h***PC&HKK:k<.^F@d"f7)`e@f$Kc@dLLl#O_f7]iqjh:MHF-LB\se,b"ZK\+SlYl\<;]1?$[ %OO3\R)B[;+ME?YcFLW^'dV%Hf5)F^T&HZ9GnX'i96)TTGJEEXIItKshVFq.;^="RlYU39>\).Ia.XWeP>c/g/-Zq5PS8EDb'b.p% %=WY`=XV^]::BgHP5soo88?)a,fqN1k1a_W]).Z"!6h4t2Y@tQa3p.5WcLGpqU^g8nm@YF5+Nl/jP^g)7\(2Y2"T%XB#R/N1p=a2o %e8YL,fa_1:CRkCjTeTGj;W][8^-jWQ\@=D^P`SND@#RtR0W$%Y;fHl!]E2D-(GE?R!m&+J.6I$\[Y+;0O?Bs-gN#6B3l/:hMTP3* %)#]hR/3AP1:lhYQS,28<*iB7u:9D(dS>mE7=#]QeP<N4_CH4\o0mq#Xl)Hqr>&cK';#m[rU$hU7V(j]'OQt?aQ!ksgV_H>aB)J%D %G*^[tC_`flZHjH6TT0&PQ))e7Xi6Ok@?%L1f[+_>Z12BcU!cIG$8u'0\Y*LXHGQC.rPHVeL/<-K\hF]jg1H>EI_a%J<)HPNJc[_X %Y,Z?L]1j7mV)[GOY_=8Z-s*?HNE!R;g^-2u@[SM7bZLojr#C+H5dlCRD'VX^0)K_`V:s;9c"5oiK3iI<a2A\?8_*_3e^CHe'k4:? %WN!88#EeA<"'G<JNTF@:j%hk_[C3C^B]#Bckp@.A=6Fb`!o9lt\Aj%p/XBhG`f"IC*//G`+0_m(/m](uK2nL/rp8oh2]4VK7>a.c %-p.8B),5Z%k/,prgd(_[h&B-sA37.D*Z$'pnfWFeP--4=;g+KnSE8_C@LWe_Tuai#!'Ia"']^P;jlsu%>8!Z/=7OF3HpGDJ*)`7B %Xd\:28!eNj46kO-9rH&6ou_Lc2E%7!:cu=Lp]_D4eYQZhTRaY6g-^soLf2f=BH?bko^ofj/p`@nL/RUb7'KPd.hGn6B)@TGp/NVM %`R5XfU;B?_MT?@M+-37(?1h,CK;e5-77>pX\r,AjK*J7u7*Gr0Xh)1mnB4/)QmX6Ee6;J'2cWZ*RGA":$r!t.7inG=/Ktu#]l!/Y %M2<]Wg$s)Pb`YY<Z2opp^B;]Qm"43ZAWFm4XUHQ?c<u]VlrHZZVL>A,]PKkX<^#tqDDJLZNHohU.(qCXDMh#uTK&1:(D(GH.[Wi_ %J@R1eW_r-/,fB:`,eL;kp0iE"T8VSm1oUP>020$875l[""PG#COc\%]*dgug&ta^i;r&!Mg:3o5A<#Z)Y']*OI8]X"F`.n%,^XhO %JGfAS_$/a#2J^Z):mr)mAH?YE%?IDTWYlb5]'#PO>,X*QR?f_sTdF*-1sL3;:h1tJ2i5>I-kg8?i3X?H>[a1+E=WA-,>g,(?CR7- %9-Y[@Y2?+4NI1\@.U3+^Y\4tE!m)+OOiNJEQpru?q<U%40)ZiW$^6"*OjOmp('h6X#3G_Oi$h[0oSbp:]p/MjfCs$M`\cK5Sfq%` %h,L$Wf77_ifXss1@:`3a73bU;k)5c!aKCb4c('.M$]"6Y-^F4BM1HE<SE'qiD]:<!5G<dq]*!I3NB^XBnq,eY8^tRlB!UZ"XBeVR %@\'J\Y8#7L-Ud,VQd%*!&0i#RmCgiCBg:7=fubuTb]dgP8768D^j7.R"_hhD6KqgU;*ibbg$B="%'I$B)kB8TZ-llI=lX:59gPEn %?E(m_UGlA.J9Pm:Ue68pjlhSJKXIQ@s(i*[ge>rG=^<XQhMd_c!39(mMqJuemAXUB'OeD0+gmtbi$-r=brB>E>btK!KP2l@]NA3l %8CS7;+L#5hY+fGPgH@W2k2k[:SpQE#E/)Z[Zm+.Xm=L$>jsmh+e5W.pi76(sgInYr9.nR_3,'XD[mXtN.*\m^nD`CZbKN473Xd7> %&;$?jZ%E0!O-?u@\ejJ4d#AA/IG["#`url+$E%#Pf9ouG;YWM]I=RPPYnaYMMD;Br"=\RQqOt0.#0E45eHD;/"mjfD5"sL%"3UmF %)Bl384sQ;gfVDO<BUr8/]E]"X.5kfB:ZTCRKtK.qa?*L9>U5qN@Hl%a/+f96NI2PCp9"L?qu"i2I#r$mJ_WX*57oOd#50>T81UoS %GM5d5Tj*YOm!](M-5uE;$D3HgHm'6C0\,^.pUQF_J<Rt%]Y5#-%s^3i4VqW3ZpK5Z6[($C!TGJd_l0JEgeb&R+DGVkFXuf%3*@QS %OH#^H!K#VWI):N".D2SV+ra3(2UI?QW74_#cECYWnBlD]ZtNBVHM,WhjU>O5>&Xiak59=Cg*kJ&4%V;'L/qi8((+EL)P`30Jd5#; %HNqA#FTGN=fBFU0l55(-0WW0,He@%4D7&*cDS*\cd"(35Q(C%R/_^7a'A5XG8K+OF?/E;"kNn3-Kak\5NK`:A%P8T+XU[+M9J4:@ %8/++H;7=J&IIbWD[qBBF\Z60`Y;3Q;\0f_q.G9E.dFM5=Trs-t<l!6(\$a@9P]F[YapYt`U5]FX":O)=g/Mu_^G&A\8NNZ%SDk%K %*n/_h1*IY'_CBXaG/\p$K3+B5$'Y1P['mLY:QL^>oP\:u`G@B"F`"8.jGM&SKJTOn6c1eBY0Fjkp?+lJ;/9"8,E6P&X:'laapfU2 %SXi6X`LtKn_38<eA<Z]YWY*oA1+ifceK7F/BXifd$Y=L$CmnIfBbf'PdbKN<?npO2425/S)L<QENsOcP7r0dY8W`I8:3HV9/9%N0 %eF%p_U\*B&b#f*Df3JD0BlY42iDf:Pb1a)Yg.K9j=/X.Y>76ZpaISTVUJ[4@itSO%"ENS!ac9FE1I?DG6>O^65/Y;H6hAo3qK0VC %L<f5t!p4iXj_hS4f%;FrB^l.X2'Qsn7Elp=PWUVkZB0;4#Bnckfkf5nA3?!KF.%P\I&+#*45-U'q<Ku!@n\Q"X_[tG"2f8j[L:aH %-Hk]99,a;"8p="f2aof6%ga[,b8]S?6N'@t"_&YK>r_s92A+A\!QcUdV):nLd$CAn#,:m1PB**0SBBKc(?SQ)0tlLSP)\>/f#%Xm %6+KEY9,?r_:JJ"uLbN`hiq*:Y^Ur,FPX43.]2RVnf!4u/P-W.=>@Zof/Wi"kj1nUDe0Q00$DW@S<;S/K^?&b+SWc(Pm=HN>m)%0g %SAst\"q0"XYoD2:5`FlTI@O%9kLfj(Y9$j1YZ8(?Ribmd=5F&3=r"n;fRqVtRUm2GMk&T'&k?YY@HCXhJ3:k1Fm+.[cVS]2;"8A1 %+R3$nScXmsgIMMV3%,SXNQjkmL<D,B-!*\I>0Gj]qhAdljXQOP*F$ZeX?oJO\;j1G5W#)-"0$+KGaso`QL<,e[o,!n'pZ3T%k-%C %1iIMfSDsU9`S0c<)J\Ea;E6I#<#S?tjRq00dM9#uN,D/s)2!a%Bfr//jDlfJLcGPdE]]EcVHbK@>#\%P%Q9]UaVqg^-If6YoE?pP %,Fr/??M+dWV*YnPR^#,dap%9T.tN!N>;8d\Ke1kAcRK/SQ6h^Y<iR\tCmdtj:mFHeVeo(.Ps+U<C:L@-&W(+]If*5;pt1J#fcHkU %T/)D]*aCeW^`\$[M94O3,mCtI8_q)mqOV"aZ[+P:F'm=ODuB$4@0uUG(\CKPTd*fL"h13\<1NP2;%[LnGhM0](FB77#OYVfgXS5J %,78.Aqm/do\(248qhl/6JT\)85XlSjA?OF^NY:$a<Xp^3\;Ue1KmY($A/.C>\1GUDi3LjX&%ePH\G=+lg0sEk/a%/S09f`>\Yus# %fuV5&i^$O(g_u4gMm60q3I`hG%'_4!g8^=e\$PP0$rb-A=\)@OI_#rMU1j_'`n,\6nBFjVkZ9\F)Hh237qlBEmiGdG4q&a1NFadA %*e=u.GF5N$^qR4bH<l%RR6"W=p%1kJU+;NNWY!&a:f#(JG?6elL6ke17+Nji@j>R!/>a",P%"^VTATNX3=L$UP69?T6MD'BC_!Dp %8L"ng?qt;Mfb'^F^/UYK$`E8D_=3I]"ju@C76]eLa?4/:A<97de;BH!iRBBLb;jlA$Wfr0TL^9B%t5\GaU9uXh0q_[\Z]jQC$Bn& %A3\iOEfb^ij^%]0<>Va&R=S:I%9+\lfkP>Fc^:d>!].Q\r3]A<4M0d[=f_55CAuir00l1:aH[PWW'ZJMb:\Xn;:=$u)*)QcSSe6+ %/!ndg:TE0'&e_'pB%GN:'Z.qF]fN&&!&&!KS5b*$&<[u]g'/(DMEapAgs!4`r5*Q.Qk<'=J#eQBkW.29MdnP%F"jY80(W6!>Th9a %>=BJ9Cu-a;BdH^E)sA;"cqGX"bVbIN<!lFVhI-n]bhru[2hjUSM:8qZ2:86uAM7\Lqs#GT^4)/]94h!X76b-0B[jo!eHN":"gM)X %G)t;imT,8U)K?BV\S(_Hb>Zo23B#=0GFk)44.<drRQZ/R5N@^DKY>Kdl[5p6W->0bEUOoiPHGan9Tn[$p&KHcGK+Ad5B_qNQ>ZFq %,a4p"/@_8rcL"*9B"Fm<b^EU@K41E[`mjIc$Q_@&"#l(K;k(Q/n7=foQ@9g-d4R;OiU%CBAC-.S<_c;s`TUoY68J["\hdXsn5$Ho %'DkduS(.\K#*gqPAlfe-*`0GraFI,N&)_-0$[:(@cRfQcIs9)NL!8Em]CV*kO*8Lhh/-Y$h,qSE(CcVeDsa]%$OiCOA_"*3@ph!j %Y]*O^4"!BgTt=BS\p#euNt/QZ=UG1Z=<B\K2]ZMbAcmp1#.O[%*p[PgQ:T'5XZQpo8$d<s?nI=X;Z*HHPC+/rCeJ99WAj[L-60$` %25n#U(GC:1oSGVL'u_@Ll\T5A%'``K;lXat:#N6lf>p%=7=R*U$\ON[ft"J&Xs=WMWKkWp1SE>ENE4dVNEaMj8q86`LbUk?4VkN^ %'8P]9"n,7D5+>0F3(6.9Yhjir[7Z3EZaaH0)l9,bSiL%'(M;\PU'sdJZImoHUmY8lG7:2'+EM`W;719mXbP$NGdYf`83n1TNgeE^ %WNg'/.`D3lfbl5o7U@Qs]-s55NHp*Jo`Eo&'gUg(ppj/LOZ"CGNdA?L0Z"3`1QBt[Q"e<DS'8^6GPD0BS(QP,!jbnl.W!WR(df07 %"4;.r,9\&&]h>^BUl/RQ2$H+$>hJrbWL:t$cmt0elkP\/;Y-U@-05Ol=$i)EZ0\_H6m.b,+aYc`6uAa$U:=LJ8o:P-X1MZV$^FCV %)Gr:f!%n)A.mXpPCKlqDiIrhq<siqW3pUlFSfTu02:_qo-CM@Y@anr"@\k#UN7,idclnLk>f1/SCS`++Y'?<Yh:q)9+cW4h##CC2 %0tn-E\%pG[S/NfRgFfoS3>Ci'KbYGj$c1iSXaAVSJE4"6TaNd\&d\<8op[r,Nq[Ns[n%W1",cO3Zoq2fb2=BMd%e;-nj<\/M?Y\c %l"R`,=rc1.9X^6A"#Z^WN(GGaG,3:-BNPEec4#QZ3QAY6NOb?l#&5ldIF)Q32:K%`C;7PS4+!*,j3fSD0pW_MkPB>bRX>QbI<d7> %B_8SeOaUp<7LFY'jt&O=JhOg6>/t<D(GsGjTAho7jV2>hh+C'.io/n6E(UbZkZOn@(m_;4`aZe,Ctt\4Ofk%&j9XPA+OjCM!&Ze- %d"&M_MQo+>/W'PVNO!5sj[*M+Fg(8!$])J$bu_+BR%1M"651mr)@=MaarY>'35&GR_J;$O?4#54oXg+><Z=oh-gTTcPp.Rlr_if< %K-V>Q]/21];inL@\4/A/A^/lsT*gYeGS)Lr<a!-rimQY_<mn.1)a1g?2o6SZrmk,DJ#XB=hH;9]/<(c"r_c-4Q;pe-jK7',k!tfn %L%?`O80378mk3N.:$OMb.'++WpTQ9c%uH$a\Q]kXEl=1:TjI4l!9:947c6b1/)N4?Rg_Ym/<"Ube8p`[QA)Ojl0+IkEmj.RXHhD@ %]F3$08B0\J[Q!O/aGP`1^QsC2O/>O%`ld;Xi4b/W.uX#'a=&<]VaH3-gRV72%X?Sb$-12kSf(r\LnQ]PK,1=AY'd5[Y^/]oWDi1\ %M4,L`_K#!3]:a+5gc_UV(es`r:G1\,:$T+W>6tq]nt"&E-B6(Qbd<Vr,iW382/+KPg3s(f,dj^)b1jKV%r,Tb^Q"LaWg:>U"IeCP %#3)YeYZ-C\&#MjQfb]0/L!ciJs+6%JHU!/3a9RNc'4UW2lEq]i"Y55KY4CCLbT,+?+F;R.X/s5DDjIaf0,*/@D=p3ui3pI`f5?Gu %e[$>.J`B^3L:>-#r*[R&\Q*LKl/`;eGd:Ba5j"27ACf]._C[#r>Is#W>,]2gl^0Y3M.bWm8p,_?^.PE8,7IM%'Wfd-<87"bh*2.e %5*RFdHZ-='Z^"p^M)(5#hNS[[$^k%_Diikio-q;I'/dpbq/$CTWC*;1C\V`!>je+Kj_Zqi7K(,=2Fj2#V<`)j&2)Sqee/3PSg@sd %lA=U:AMD:@duh[E"ho5Q^kuYV)[gG;phhj,#ok7^K<,,.A;pbUOaEL$NR$!(P3A/Kj:72T&L];rcd::[XgE9UCDk:?+t+C_mh*oG %P8q?NXZEh)mt^G2KQDBk-1%3Tj^VX+85%(YokbQVVC^fFnF%<hPU/W2_+bB[C!?jB?/_<:Wks1P>Z5[lQj*82cpj,:)>5[V%p_CV %.eB--7:n@d^>-g=]"X`=Xdg#k>)<rZ&4^dj2I24nljh3,)r&$>C=g>CLQW&'q2n.N$++9SAJ5ob`f25=o't!ZdT(JPK"oetr2-4R %7GGt\@#]T=jI7k'>.j./RSG1G^p&oVH:bn/W%An;b`M&u/K59?d)3EU':bgKLShg6)f0``Rppr+[PG9pj_BnQH6W/5n6XUflkM?L %@Zjit5[Aq7f2kpFHRI941L,VR#?'?!mp-dJXZbHMjTU`ch"f?OED=R#5?:5B!3%YY]^Tee,e!&%]>J4N>.2euHG;Qi0'k]$_K9Nl %0JWrBe;?h7F028b;EsQBZr&?\3<>]NW:mo&:LR?$L.A_;9h$^'57,m+KhB(u[`E\^-+P_^6(Sih8M1$D50AJ"FbZK#+]Te-,Xaii %U)Ud2*Yad)S__!#2!dQd0!I(.CQ3\UpKJG8mp>t$CJW@3k#Ue:!u/qtYejj^(Js'7NMQ?u*9ZYTBa1;%3X+sLJo1d9@7*CQ6-GWD %QV?)A8K\+(NI)E?on_:tgV`1MQ@ug:.]qOdin?qWA[0C(_6h\<cuSccDW^`-l*T8M+A-N"bpQcp^9@8!E94uAR/*hg22mYA;7B?3 %(!F*@jZ`[qg,>+XT4<S8/=9<uhb^aB0b^-UIDITdGQJS]'&c5Z/^HgVG3*N#Y(@!k3s;7U35!%-:@^j3Wot4>,>QBcPZ,fQQ]0>t %)VX2\2K+P2"X.SM&a^D*%f_W2ZA.^,_+:SB&.#@l7BD>N@b6liCjS9tWghUi88oIaK'(4)dYKsU1PqR:i`I5'YUWm="LJk4g/q-A %*HG]2DG`MfWK7cZl=luZ:]YDYSkBVJY0=Ks7:!]Aom4JZ&<(_p@-L;F@5uWtKR#n*@ZN%5^:'@30=BLhpYt(HH#hFW+"-0eZ2"R, %.0]CQ2Qfs=f&P>khH\IHFs4GU)ra9>aC>L[6ttEJ7.krmm"+FoO_hPe%%u`fCD#bFX4dGdXfP-);'Yj[gBH=-RVu@G:qJC#-nCH) %)/!JoN(b_8R3p^,4dsuDUD?K[-CdFV6>#pNmGKUYqo)8"bu9i7`b1sDU;X[oQn^7"I#g]geEoqle01V=KK[^R_W:5`5:4#QQ:b3M %=^R[R*AXb*pfF_E[q[[65@[Enl4A(B<qJs'@>h(bS8kIbCGlS%24^iWUfg[nFKb'9/4C<%S<ji?#-D>@S.'$LkCjSJ.^.VE[H@Kt %^G*,)[j]gNhln`p;lmBCTTOB0E@5(!LU%m(GR[D*.?0Nd90&sR#<l;(RHZh$<hi@pj!rog#,IDun#QpKd[sg`I7*=Bn]Z=+m?<ak %9okO@r]:iYikj-5Uh\p73b?WjG'`l$/R&7o[Ia2pTZV<@Ji+<R.FQ5Tj:gc"mNoTYAS*$^fX@?.$!Ibq.\q"&U3btabM!m&.upoV %5%PB3O;ZH`$#sPH=@5l2=!:E,>=IH#l9Gn`0BAZFG.Q<bBSX"?+G+103d.B8V6On`=)rL-PW=J^he_(<o9Kg3Y$=W43qq7uAI>qW %GACNGM8"&/JHGH0r9,ERS.8Ut_?>B+X3&<8P-4n%I95s(K.LS=(go^1;CU@k4*+Tjl5=>XJn1/_5\(@+`Gbn%S&66D6,Sph5qF>0 %(&lNZ+[.\.`;BiRnN<7glI89-ab3WQL9d/_GFT89XIm(`gJG6lo+tpP9`e&Bhtq(6,:/G7[HJmXVN[bg-Ji"`d]V>l^QSWkf:RQe %rBG[Xs8CR,]`7Q7T5OWMh&CkBS+kgtI.I)O@^ruKk2G'5IX(nCc!UJJjgT/H*kqI8mADoCrj_8Y*</2$mu)[>r/]\Rs6H$/J,f5S %pV6[cqfcD^J,>;aI/!MV^\dT"\)2&sqi=D-J,#)n^\[n)%tFN>*WH)*Du]J&HaJ1k?bZNgT>//:rV'ZJpZ[TToD.q60E1h-LZ9Jk %4oT6sM>Eht^3l&\KM99%^\I''rh#7$q;96#^YY3EJ%GFts"iGX,oupOL"XKr]/5O2a./0F(Ur=-+@8I"1@CsK2Cg5\k^HEI`7)?! %rS-."hr=TV"(%Gh^"<GbD?8rFAol]#\pJpibNHTdn\:)cO6aci6REiTWZoNn1O8'1T3?I);0i.67\l][TGcctnis[q=bu%<kB/SQ %j1O\DiioIZ/amk*G(+H^eb(fGn`e<%J,fIk?bcWibpP/OIXZeH_o(rWq>O$tGFNUBk4<MP:]J$C!dhQT:G4!lG\eRRQ!\AYk__l[ %3,R6kB<dj8;S(-#=Nlf7@H5&8HZmD"^XiU2H9CG7CZH."#@"P$6VsNN?<-fdP3>(YfVhU(:V5MrhJ;HMEX_AC]_nNXZ'Tr(7duUk %IfKDjLUUXHr;Z,s#IIN#Q8\Yihh:Eh)5jCE=1>;K^jn0iG]HW1,Y:`@6'0<E!@/#=$[cJ1K.N2H]SJ%7d3TD."9fP`)$ORPP*:Pf %LARTKHgdsqkC#!gZuu6B<hE^!^!qC(SZ4^cG1D'8o/(7?W(DoEdG/..V`"\J^Z+ZnpOQETlu1gSL%ugbT_&T,8<mk:?fS*JQ7-`[ %*`Gn;rt"7iNaac$^0gLSpj13'^U=%NHfRr/"&Bl6b"Y@$Z2d\N.#5bP-G`V@W&^G?&],a>il"Zag3]">7)5I/lX_3_$/P=!+(uAI %#c5UK;cC7N+o6anh$h50"r`(1&rAq\6sM5A)59//9#\e5$Nc5BIT#S)%I(hf&7DTF+GC'i8(5R(,gnGY."Vq]q,&8$$-Yl(KnIE" %!/rXDV-Q.,2t<[]';Jj-Ko%O-'*F)pEEbiO@=mSZ_]Sr"7S16V>)3Yb)6c\C.APA1ri^KRQq.I>_BZ(f<.p]85eB*L1*pV4fdXb% %Ro/,bLCaFP5gP#^SmVs^YGJ39Rj$7QRaV6$TX;)KK#3E</WqDI8fZnN_aIF@\V1YEB43OB[U?Ks3"$?2$e9g'cu9;*l_Q&H$K6:6 %p]tSL8ZHInfb2aG#^HeY:"9\+hraD;d'I0#93^h54W4&"]JEMB0.-W'dQPZl&h:<n@.?WU'8(rlO]YZ"-Ih6A*KI67KEXbD$Lpu, %R/=r`LP[nj_F'Ka;d$UIYn8I)OY:1`aIX&8ig<7VjKRTbZqh&&03W\UUu8O+/dr<RM2A#S"WLUhb:RD>6i')h*4sFd):C5ZcMiFN %.0(eqh)d1[)penp=OB5>qA3jDjhR)FjWW%mW>p<8AV)$qdq:[t0_?e%?h4(*L&sn1'FfofP?'-.LQ_$AJUJU/J63"s!MS'3)2(IX %Rgk<JP!<Wl/I*T!%:n_#NJ3-SIYKt@"Ct8Xg7^up9c]O3P*%V(Y=kCuM=>OVA-*3"YAjWd6<Ao[+%#?":(3]c7+01Pb6"SJp`\]R %LBIhe=_1&V_l3ku&j^efcXRO%d1^9&l6K(l[m2.0'V]&i:Pl)#"=$'EI[d906G"1hF)Xj/:Y.-1>r>Jg<,K8ZjXZRgR9IjGNG:um %*R7_?Q&A&8(3:6,0mSQs8A3b%Z;!l"hA^FiRJ\\^Wsr#OSk&#r'+rl#Xs)EAVAL>9k\G4^5[E;ErKsAg\1E<,+=o'B&Lp@d9ekt4 %/9&?G]:7W+QuBco#VB0b.olp7#l&!Y\he08=b*%l%1aoW9cALfL@#*CJ8tAZKWU0(CK71s4[_l\M?+@;Ss,kl*YGjE(%h,RF%a#N %dT[UC%IO_N`8)KRai1uL7ghc>f7Or62B73^T-C@G]`Qai,=<8Vor(uB@k($_@j61s=s"6qV&/IfI"E:V)Z^tFVi;tQP)>72&CeOZ %,8B;+oYDL[=[d/f_nfa=a6/8?_d/E]M@c3<JKuHg=A;P_W;oKV`b%Ktk(.524q!)LU3k?&/Xbh'//WPiF"p+]Rj8uKce<pJVI!u4 %.:tQ:cRXTX$pr\\f+*_6<A7es<uQ3P$9nfhQ<]#$&Oir6Pf)Ftd-!eq%gK:kOOlU\DQr3tD9)fK*5pm:@r*;'i0tjF/\3-HLGd;$ %FVZ@/]FsOG3LgSIAe8>F_%2.ONQOWhh%(bB8D"T-h>hs`b5)+-2/n/WSH:c'0+?:2)Xp-<P"i96K_hk?`iUP+V]k)(_R9MUQ>@1F %M1IBSVk"_Kgh"%!KS:dqJ6d>oP!'YnN&8p57l^OTq34`41IHcS`,*juE_L6!CIk0&BsoYLis%g)15=Qm2Qk_fL'(0RbU4rZ\/S#8 %`SD56jtSPZjD2h7Qu&7-.Y=#kS)T_W=kD;Ul,ng,BIZEWLW$[D=njPp-[$!$Ce]k8+pZl6F$8H!:YoqDjW:[\W==^Z>T>r2mp=oS %;_+o^%OcEDoL[dP62qL;9l^ajH4qBfo8X4TSe37'=$Y)%^6/1c%_Ak!3qBuq3kB+4]7>'\Jmuu9c]Y`/%!=dgXn0Ld`6noS(0Dr] %<3`LS3TTgS:%orq#QJOW$q&gT'"_g'4dt#E_^&[U]CV,_S7B2+:^A`Xl$ND+80OGl'7u=u4C`"1JsF^)E:Nub*I.b;3<^\Vl(^;e %#\De1iqrn-5^893=ou%4`<ZZ3<s_k\EVpLTk%fU[QMAZ.&oBf=imSo=jS1_%,Uene.WoJOc2fA':nB=s7$EH2[*pH$J^8RTil/id %n&A;/`1:M=8:<7`814$&OBPBYJQ_EB0_%aG]jC5,$f+%LbQc*?bFhJX(,#/el0UrVoNJk()nTi6<aWb,;)r&9&0086Pm)YO7l&n9 %IDS;3fiSadK0FC!%:24:LEULLLilC1()X&iPMCbLn-#!YFo&mSJtm@2_"K+:I@CEScsjT?Ua_'?i;?9:KgeS7r%,lD36!cY9f;Km %2::DDKr,,8o2jB]9dg%aS#Em?-^mq#/V8!E'9(e20U&@q&SU7i9W'^-.`kn3)MNUA03KuCdM8;6ROXVnU02jj2OOraHAC)SRejip %bd#*kKgLu?:eM-Ti6?ccB`[c<L5fH?;"-0'X.UgD>YJHBBb_=;'cMFtO)lo0c.nUKZQTZi/Pe!OY0.`:Tc[W49e$=9F$_FK@NCh8 %=4dVRYY!91RT8@PQmNL?-F+ae2:$S>)ogKcC8J<_e5]e_G.<BW'L,GtO<l37J0(&/CbC6qKGN1"$oB%4BpFNFesrTAVX-KR6-5@V %.*fgHH+("-=]d:gI0rtg$6khFWmH`_=j1F0!rgl=/7BOC612RV`@M^6[AK&Z24PbO'To]>!MjGXY`X)j`:NiJPDj]IBm3)Cg1gAo %U]?Z\$6LMAiapD34-qfKPAL=PB;W.C`\o/q!WF8hAJU+EPb]>sn6G&E^dJR(GsZ['P[n5]CU_=m@@J,kI)unNgEVcJ<-I@cgKAEk %`8)ch/+?(3N\*U1\(P!n-(h>Wl$NZ7;gUaUcJhDnDA;&OgN.K%h.TER*t2B1/_Kt&U%r=n<c"DgdRCgMg+l/kF,3&*,e,&ld4AV` %ntO1:DP:b'BmToF&PbZpal/%nK):+#^lrC<Zq`u1]W\mdfO5Q,<?\(@0e%[4)t6kWMSOq?:59#2,]sUV0rl)f5]N7P0Si`;9oBO< %"PsX;4@@04C/X'49WAST6m3P.iM8#2%5:'?I"kksaODQq3"(Qe<>It5,g%VJk4"a2e1:mdadhD7G*$=&3^OKEfE#W9LM\5t"`=$J %:*^`-g]EmcrP[N``)p6LX$J21\9G4maF,E'-KtRkF`\TuAFHeQS?s!5^Mmf#"odF6J#@NX@Bosn&)n[IQ\.;mNL5nXM9R:\a`<U7 %CqQ'Q`9RS`p>?&3[+=9tj4N18clDp4[PT\d8jO`SqA8>TmTAB)ZgkDo`$afSIV3Bjar\\1oZ?N;@8L&'jufs"$DEM/$b7Tn_p=W7 %DV@&R]VN`qUQ9/R#scHL+IsM_M:u0+W?l*'+;Qe6NZUS4CGQQKK3/,-jt,aY9$VC)^s[G\I#'s8-U)TDf2cp`Q&[P8;H=8`D>%#e %[DZ=R>]JK?TU^2Z)PUJaM%rN@"L[noGn.6I9_fP>l^lJA%,CV-$2OFK_s=;@=g3;d?[[@^V2]-H16nVH[g7b'84J@oYg=Ae(f_[e %)X2;hVLFXr@,8@;d_-QK+ZX!h6V4h*'8DZjnnNoBEX-B7P&_Tk$mk"MedNkdPh$6hjhac[Y0,_*)7msJXpa;_5C2+6<_dk`fN.Ec %bq)rAr.GZc>lU87Y<W0Ck!23>&mGYG5gVDc$E9\8[1obeYq]0*#]1NYn.OH0:SB9OgI$\6co.'p[@qG!'uhK'8QCQXD+gq6,MM9] %+\`SRAVEe)2V&5OU2@^]hBfF8=6LK<H`qBFl5W'?DA%^/$D=.h(_i-'4,?_CT>\!g64%@]*"#K;*JZ'8;<%(5@?n3p(56L$B/0eq %PrQS,!)r0m7tXjAK-:\['gG19?sDpC8HX4:j!b9=M]ZME^bKuuV*W>T!LX-_dgjiKn<uIaUI=,+7b:c/5&lr[el4!#X,JjQQdXQ[ %3-T20p=]X]cK)SnU?g=>,M&#$Jc_ZP;/6j)^u;.H/]*R+Qq4nR!t<<%gQU$1[c.(_4dck@'Vj-XQDNjuEb?6n0m0qU5.F0,3ut5S %ao^STf_/mco-@=&&FXc`A\epudI""h/IRb%p<rG[7Mn\1;+EqY4_EYcKp_Li`+qqqM+fMV=rUZM*MlF%/q[O=GXO4TL$/p\Vu3!> %V\nANJbUcJ#LDEMj=K?DI$UCT(YV(5%L"!Y-))L`6lV;Z?[=lpQ1U/c)tp7n0r7mua5C%(eb(r'ct.52Bf8Pj'G9i1aZ[L?at[9j %8K]pV$>57501oRYTQKk+e<3p(=\7U<K`*fSQ.,&m=41WfSWG[$>2Q7/$`6V%/T&U<mL#O38YupP=lAMp(+nSJ!I#<Gd$,))a?_F] %/or>W_3#`#'e=mtYWp?B90KBmH5.a<-@>\pb9&J`*/XPINeK=WOCD?\#c>>EF$PFlg0@%?dhOTn*[fCe=Ic:C\qOQQ%Yq_WXKbM! %"@4J-Ae%5fZZA';rBe/REWo,7CEkY]S<=:o8aDcI?WtmS*J8*iemf-;R:o:-V/=f@(%,t9km+"6psP7;D1!XDi$j&JNU28Xm+*?t %@i.sTdZQRM*-*hRq@9IJN#5=Dh<Sb#A0na;MVh.@6jEq'cKg7Cnd"(A#TOD]D;aD7J@Gd3:ceasR:pn-TTeD]!Ylan#E$ZY$)jIA %@&5,R5c'S>#bdP",iG\ZMNkb,)%,WNff)0bf%0DIB\R+Y%jB]ZYfF'q:rJ[S3Su-)B5DVtXDepu:Mk+hLb-Cs/INT3C?Z:5%I2*4 %J8T2!K45K/d<i7Q3YPU1^7/$"1^o.)/s>kMPB^a0k&IK&d'U\Ol8GHAQ/!`>0sQ0$#lnKQ12%&`mfY,]dZsm*A9AFujB45GO'X5' %6BfsHX!iuV64Nde@TkA"`L6eEU>#mG:UWB[&-SMtKT;`rS"hEb=TgM6ggE[<jMX\YaQdCi$;W04'2_^/ZS48,DOA4YE@oYtZ\jr$ %RT(h-WY&nU>lM1N?oOPg>tVE1!XbI!_;JH+m"5^56JGXT_""?armk$H4V+o;7U0l+)Hn/TJ.CW=CafUE3*_2HC>.\VrUYi,'McY1 %M+P'3?mU=Z(h_!H4<ak6bp?6Z"M348dCj4Na"W>Sm<9/+Ltg7_>3Ii&j*'P&/'\\D&KKHoFAlT2#^#<M`+9dS53"7Y*BPgL+O#F: %q;AX-obbngE\+0Ln;Y<]duIN>Gr*oF5RsL23EYer<j%0`7J8#QWsIn`TpNjA,=2Z`V8_dA69I9AJ3GPEH>R,1<N^Lqqml>g!cA"Y %:Gf%H,_3/>:KBid@XnPTos<6?#<\i?ou`B5U1:kq,c2pT,RSr=&m\M=7tjA!*:%rkoW5)LPUM@"m+29V=1a;$OB)moOpPg'Vab/e %6Gti@&B.1r)qk!3&eb"hg6;\Bp_'c+DGO[;\%VQ)QB&,mP/YV#`Qa4m9iONaV+ED`ai,KUZ8ELYX5e1OaeTnHmj=TUqDoetLlP`) %Ur%-RHE4S#WM)/ADB.**!J'!"MhbaULCKWelS-O6)L[+VFVOnQ_W5jI'C39'V"7j""uL"_NA`hc%Z\b!=U7X^8`>"r75JG)EPJ09 %#O.N3H7DKkl%3RFOmADIBIdBcEC_]&e>ECn#rW?Mq\$\0Zdf[B@V+4!2n@tgm6KWZ2e?6W<'q>haOo2bb$V[P9sTia:H-f64\JU5 %`gfZBJ8PX*r'>><B7pm2GX8[Ke(\"I=9)%"K=%bF!2`kII*3^a.9m]!OIR\GR9:ca`[Qp=QEms%A3J;K@t:a+iC^M''0008O!`8m %nS4k\.\Du6H#)5>r]kjTYV0Un"@,rj&u]S",RRV&YpVDO<3PamE[u'#BNN:Q(qa>pkV,AAcHS=09Mu920.[4G.1:bA'D4m<=9?KS %Ba5YNCt`kHTIZih!q#V)A1@(7MZ,X"o#fCd@#>_l=@M7`@,#(6*%;=)qB6;I)Bcb]:0&Vj\mXg$1Dkm5HAROC4ZA,pKbGtr\=F+j %i-<H)dY*EF'9o2n`$TgHL#E6='*fQS9Nn6F^M-aWk)RX+8Z$rj1Ts&6mok9PnHkV:Dd%7q&Bc7pO*Dra!+T##Q_o0E_$6:jfUT_' %<2:^a/eL/O3oMVA$g'Dq'b80;L(ndT#HP']==d-]kYWiRcrXEGK+5DBS:upLVIS#t882)I^ges"0iP#SZ7o%0@c(-'A1//4e"2.g %4"PZOnbrl<GKW_(K":AZd[(%*BL9a7U?Mn3+!Qup+U^(W&3JiGYDB2)JW7d4Tt)WYDG96QI/5MS`f.4c,F96@gP`tVIAs;[=Y^)D %Dj1NE6h1C_L(a2P_d018W"URr$/O2&gp*kjY.*m.[8+n.00j\AE*MoA@>.f31bo+IbV#,jpn#FKLd[<V:.RK##2e"1G."a`D%]a/ %:g_?+"-9h#`B,r$-Pq!2W`+!%F&Z\3lD>'>UrcA+4RfUH'JT_mKi92-H)ruM!Yk*bC%1]?@!tl6A(3QNMZd#tlOg=r:\$k2&p(*G %H58$Z4%/okAfU^Q[K8/#r+%U(gb\V37gEY1O&b-O)C""'>s2!]3e8lu"j<)C$"m,.CW9PrX(W`])3bY4"]\!LKV0m4hTlR"5Y;.& %?8%T^PPj)\^hqRn87^h$aC,4;beds^[r!H-M0*u)CCo]`?mS/J7346c6a'uB"\jQI:n:eKb"dg/_W<"Z!(%"5kpDKGedu==<@,W3 %.U`[#94f=JoieF/,pgA$A/Y_AJM]BC[LEcOXG`9C%D@eME+7UU1&sZe:DC;F)%Ird'>dI'.\[9TjC.s:q!8OcBaJCX&Fi45TFtg\ %>$r$9h6Su>#S'uX!oXBm/TWTtcGAGW6p3;oo7W<A/^s5p!HBk-EpkuHJ@Cbg9d4h$_Ws7/+J;.i4ApAgR.u\pYFCAn`cS";D'.cI %G1pVc/-;-jM-!'JU.mAB!hAANY%mQK!$F')ITH>GJQ$X?hUIf][nml>Z]VC&OD^AKG4Q-+ZZ$Q3@tAaNpPa^FM1BK(Pd<_H:]S)3 %4drH@VS`lMk0kTplqi;'/VYd2/f0s*Vo;42A+k"b+?Yl2oUnk<GOc;65RN>s4\s";![$fS1(/f3p(ZpU<fp)TJ7L5Xh*hD'W'_`! %])j@.4Q[1i$MZ;^Ql30/$^Up]>GlrEq9ViSep%u&!R`K]dBQ&%76,N2_[3hS0r:UW=uLRh>8$CuVQ=\\9KYtk_6^[fHgH8;A0MNc %i>W+TmV=j7PP*lSe/_-(+cs?snQP-6P\r_j#V$'bA/@lu+b9c$B(?YO6]ZeR%VifcR%e&o(0MJ0FMj=_2hjthNq?dO:LYLb,Q.l/ %.j]s]*3)Q4b;cFT;8\@,kkL+;I(n=IQ5AI6:O&[D"VM,U160a@4J'Xsjj,j&oJp-#^DYd>.IX`A0P7^.UfAWLC`mX[iuXK#h*Cp] %/`96o"@>`Acn'a^PcKZWa9>]LT`eOK4suEN`l+Gf'1i62(/?(YNUV<*-5.)tS4+j4+REB;4lV_PkXE?N&3p]8#a=\2Doq6*5_2*K %U*Y_2><6J`KuT"k_IX^b@2dS\0UUCKjXEN\=&g*&!)I\?TloS@/3IWiR%0PB80!@O(`50:'F`$)(nkY82DJcf)866&qSX*j`Z:uj %ZQjMKRgIjp9K,ImBKWS3A$`Tm-%$.nMLsb+4"Z@Y2:B;S'%"Q4ZU.[V5Z4/7NU1gM,T\`i-rWd-^8FoYd?6#cORQ/dh$?AQTh@b0 %/ral*d52NWUAB+Z)[!2hC6<\nVr2:%q,%mWd&LV>$IkP4DtYKY<H,WJ0k4<S-cBl!/Is`ClHQ&>H"SK)DS.P/rAY)66C)q%_FI$1 %.L91>pj'tES:\hM;Ti,m-)uua8lV9d%DN1\A!uI&_U?9l10$So7`KIV&7lh=91VKg,>:<5Y#0&*&HV-9(+(CUlCh3U_g?.],W[j5 %<BpqG,*aMi0a+\'RN_+,M%u=P5"),:MN)F8Lf^R#H;4>j%@aEI<D(K=L?%B1k]gI:DHuSDD78?%mG#'eRbbVj`ssi4?fq5Co1A?X %)Q"3kD:>B`9%Ra/&a`glQZjR@7#ZcFN-_2@i\ViQ.H`nE-Dhgj.tNJEX/8Vj84Z-WF48*Y*\fec(lR<i2$6$f(*7(N@?ub%+e7'B %R5[dKe/Ya=@^6OR(Pfsf+pF[AJ`DqPKa1g3/?8s(5;]0LisTnl+f^-E0k1A<_p6H(M<scR1`Q#N%4[tNl)e12U*M!^L#W7]N^MQs %GS:`V<?t$Q>(j1/RW]C4p?Ag8[uGV=KIbae3!58i'7P0;KslASn1;kP,BJC]"Q0CoV&_\A_@UBkgC;MWN:-B.\1_=rU:gOn+F*-6 %d$.&*@43^&b+<>:]HfP$CQbS(_g/Hl6AZ(7/g"qN!FY#Fp:ujP`TQ_1Ot"H4J:^S\1LR@"p(;F8Ncr<JAas>^TZtO?!UtZgW1FO@ %$4\.8m?!!`7J)(<g5cKGOUu=Gn^`:,Lei8#mG*iM3,Rp<J?J@gdfrD%a_uul_IPqXKbb\&I!$Q:,5gGH[d^P(e4e5e$W"GBdLL/r %9[TT\j?f5m1)Z5%-[.VO!7@HPPpm<h/D/2e'1EPD!K#=O2PaHJ(heL`cCuaKLC6ad!!Pf`?'@Ui&.[QmVccj$$!`7"Ytq/L7]1uc %Y:2UNJ0/eCMW5N#L]\)UON=[-cT;tf%Bf'E@dHap99^>8#002r:insEp;d@'ZYp8r<`<_,=\KsrROVR*&kuUh@YniC&/l_Uh#L#Q %?\SVO)_5>=)]/g;mg&']7BukD*XbIB%YqSe#[o-HIV:(O,%>MX*4)f*q)6kZ(7I!(T]2[N$pEa=:E9Y8b8c0G3K!jg-Skh<+\NSb %M'5>`0pOZnB0DjUdIMK8=.ZceLB3BZ%gh[bVZi2U=E$Y/"S3old]O/popWkU"fu+m(g!b++JdXM7"i=@I"/f:@-tE)g3.JsM!(HE %S_3\aH6O&/;9]m;CLPplADikX6G3Sc_($ZKTL5C$h8<M,54>c7,`(%a?qtB^-'f2fk=h#'50Ip*],['&M#'<[O'2QLb_bu.<<i:& %V/B9`O*7RcJ;QBm%Wr4F[):Nqk_A;l('@#/eeT#VRN?L9M80LOhdqCGP\:+k#)@d=*t&%Z+Yj_hS[=;p/HS1H[Nn6(5gLX>17))G %?,oJ/bebbQCPd>P0bd?p3&j:]HRiXSg'e`nQ[B@US)Ji4J?5O9@A'>*MFiL*@/704AH8#lkb->I>sO)AQ"Y>J@A+uI!6uSbdc:`l %?!%)%]U85Qi'b#/8noYUhtQ#*JP)0JClpobs1?)<Q.opN=4=7Zm@-N*I89,j1R@+ts(^8d<M`1<m9=ZJ2JU@njiUEeWrI:tp9!j4 %Z;)VX[Ro5n9cFd"(H.'V:bB:PX/6?UCGd%HCsQ9Z&hReqKGJ*mHr5BS/EAp0oB.V]lHiH,AJTO)7,,/P$5BMmU.rh.9sB/",p,\K %,D4]e:qB)rVD%F'KQ6rtNB0HSHB],W,cX;$kc[%?PQ=uP;4$J[M=](JRdn`4&=!q1$M=andH<<\[)fUlIW&#>HIC:?ha"6W'E-7- %OqnbN/Cc/\d0g-%W3?'leLL;HWP;eZrNBT!?,,IDrqA)@Y(-;g?g_5"o#p^]IsLO7?iO$mqK&?^J,"_(p%rFiIcqSo=2AA-MA?&# %?M/:-RWYV7J,CU!og$pY/Qt%\o@P_dY30T/mFnC:eO%$dWu`nNWqW08frmR5$bXZ"fQ6iOTq,ut!q1H2Eq\6$-4K?Bj6<39>u"GX %n^Ai"h7if>5PqK&WgGqYg<9j*Ref8GX&;COoc?>=qWP)s7+V_%(d*)`U]GCur:uiO_+G_<:7XF$Vt/k4ql<VKC3:U]AUNB]ci!^E %MEY+FG:&?oH0#ie<U0DV4\(JPdcSN@od+-.'s?#&fVnd$IbkS7&-!dOo5otP"5iOq`;*QnohYT5rprCCQG!KEDe/mLn+nop1/@dC %]fJ*^_n5mT<pG+Js-<@tTrK\+Ff=d.SF?=!K+IpmpuB]>lEtNYT_SJ2hY@[Hfd+;Hi0.]I'e8+FH,Hp`jE]oQr`"gNhk)ZrUT45H %W7IVjV8@N7q@C@;M(a5*H,4lYrdO(ml?0,?r0KP7rTE)9UmKnU'ef!rM>cZo2/?96nhf&!nR$d'q0g"\Z<ShOG)&9c<F;q8-L]X^ %fDkQj5Q4[6/!VS!J*sd$iMeST)V-P:BO:H5dr0a1@r(dN]1gai'gaM<qd6GXUfj6$"nI!!hsUNn^](`E3G#8AXBMq!n$KH7.Q;4r %[UIk%f#qG!l-W#is0j*AWcHX*<@_q+]#((41sY@=jc)l.jmg^455OVe:YkW>.=,!Rg,7%,M0Zt:ds9<prB&NMX+NP(r!P.nq9tCM %<B96gM=a:fG8relb30mhT$R>iDkA[[rY>1!bb%,QAZKHi<@V"Uh5GTl(/5n#U0-Q=p2oPf[B"uTn?UpjV=Sq3b%a+dn_,Ws0,g<Y %o@Zfu(+e(1H'@N%L*uT&Sga+Y]]t%V5<[S:eAke.q<"a>e,-eDWJ<TB^1hc2(9clT@"$se.^a&XG;GSfb-4\9SiCfXlSZ#[^RAT_ %pZGW7kl+W7VPWidYs18aCY,TIAZAaPPomU.^kM)Uc[<'66G"qhmmUIR)`Fp1omCW_$^H.RIZ9]bRa90j^&%VA\[g<fDI;&2qSVR4 %QYc]q\5BpXjNe*XTNLT_L)'<M@ET0cHgG?^DXPLBb==E^s"'5\kV787KRn%Us*]@Q<MXr!edY:6d=S>sKb<WGgkss2jj7XMZdMoM %,AZ5e3R`_k/s2cM4]Jk8ViHag4FaOkqTI?s`Of01XA^8/kHN4Pg$d0&g*5to[*,W0[9q6AD!7mZgO(o*<UQ^^*tKchrpqXG-G29e %qOjqf(m5D0lnDuBi&37LGsgu`4"e=\cL$"o9DVpief-SiiIWLse]H,;.pTjXU`&2RQcSLeB<i?A^Cn6F`pk]/Aj)RUo?2'4H#N5" %@lm]7cpQ87\)k\TQcp=L3Nq=5$s7f9"uP;QO5<Ld+;Lp.J&\5%Z\CBao,Hm/lO2C05@4<1e@&C!pXY_9ktKSaDP#QEX[UsR-r?b` %q"Z!_R+S0;JNP"RhuBAJj5mFbeo'=9dE%'1:GE3#=Rc![W*5Mu//q\DmFN.Y&"ia8#BPX5O_6>CSHrQ@HS3s`J,eYbIFE7hX5_lL %TF#P/rG#B6[!DZ(L')$?q.O29XZVZbI\g7P-/Mh2o@U$p)eO<8e8([l1M=`=;73PK?8X^E0SO97T"8IcdQ)Lg>lSo<DJ5=%]CbEq %Qd6cKI)6g??<1sbMSiMjG?rl"DO]^Wn^M>;VCYlTI.;m8Q1MBJIe.pBc78A8dVgbn\p8c)MD=?Od'KieD`\p2N8(6h]Mg-HgLIF1 %Sb0b`[EI_C]#.[eIJ<bsp912R(@R7&lHOBs4s!l\\M06i]](&5lfPHP^!+E50=N&'iVH:75FU7(-'akQPPt46#IR%nZKH*i#@mGV %p4[FM8QKWX=(bpt^%)'Lf#]CSNEGc5NpZ-J%")>$#ljASQL+@,4f26GM+//m3!!g7eRKP2^D[&^jT[A&#]iK'NMF[C`p<;2otKmC %Z$65Ne^Lj3<iKff^HWK]8iPs+%p8OraRJc:2.ITiU[4CL1Uis1C?=;5\UHqohY#St?G6*SiEaVrB`mrKde64].eK7F#"RKq4+.(` %gHU)a@6_G8QfV-+k+:HbZX1;eI@':[G37G;`P"mD`7Vj?fDX#u:]J'#n#@U6+1W_%lK%)1D3W<@<:d)Y:>Nj4>s5R-[r-"Ed<OI# %KBFnYLdnm4_>eT1(?pn+q3F2e?L5+6O'"8[Y8gY)XH&goMt[),Ru@'AB\qArqb:pVNI'*_;qJ1Eg,u@CQIBd#G"D?jqbf.Q1U3Nf %3pDQ4f>VA_Zi/]4ncYu8aL+OAe%9Y(*F1n+Q0L@_p\Nh6$b(&HffYt><it9Dbs`*2EqqJnAm`4!Hc_j$Y[WAgNMoIK:Uci?`\Cbc %&$2>K7a=H!qCaoA%D3dk9s1Jdq3M?dEaSBCNu,!#ZXTS$n>@1b?2M>1@^jX#TA/KGfnB5Ta]IT\^@9t4krIk)e!1ueo)#B2(\c-f %W:Ko[_bWFu:D7\1;Z*pl%:0KCa1"+RgOAi3I^/!N<)e2@ZbtDF]5hgq4Leg+^\ZT,ap_R(oEKE*O7b-sOPrBmfH:(^Kj)`*AQ@/> %:rUMa'tsLqWQeA2$a]g%`\b\8bq:*o\p.>CGZi_/f,T_*FmJ\^l-7^opon,2\<SbVMc=V_h7c`h[HJ<B208@\=Qsl[I^>iJQjBcO %dl3o1PoI?<*oHe@W$V_^$OUq9]+orKW<R^KEjZ7'I",,"nf(lGB/_<;qF?s&d;0?H>sGW,KWmVPFu.S'Q$_oJY)c(0Ng><<_q%'l %7NZm<r%=SBf?6#iepfQ9D,(%8Z>%p>IBmW;)rp2&j$"7]qY&UEe!n/b1KmKOiqSMO]5k*Ig@aFO\cl$ohu6;O4Ls((Dj]CMD>?DL %[9BqOqJ)-p`LQd1#7c0_X`bcRFF8#I3U#E<pFOC:62P?OOXgrK8\Q_Lg52s#FY=bPPZAj>7`/c]p_GtF5@:`kkF?/G@S>l?26mIH %*7h`I.FkjAL9;.b?eN3$B/)q*d=)"S1W`+FIQt>c@f*0bL@S;h)ckW=1p]>N[8"t2SK!j@kM$6b[-B_fbhHE02e:@CDn`jL4FI/2 %bPI+\oVnpsT,kG+p9&(H=ZEWOeK,*AT;R?`HTrBKs!c+"AadJ64)3Hcf;RGP`:u%h>*W#]ek./NLMhM,d.70LEu+((GLNgtBeR*. %n)M6L;mjVnaWofbl(*b/cmn?moboa$DsO]T?[SfhRmY1k*7:mK1,5Bh\7jc2Gh7fRpoYuZ%pH:!eFhn7XrL\1Ug0ofhbSL1ah;k6 %j,DRAMM:A<+#.AP\(WS&hJ(VhoYe$5>A1X"RZk1M(%n;FV2@)Lp<i:aad69r]Q-Q2e?c8$o71JsbMTH><``B)%opmm5&oq>B!G(M %,F(:u)*_P3a%E?D?Q$.1)P>FOl;rj@MDQ3aCsSM;a1leB`LtYY<9<)>E"7l1S#<a/gJr?o<7*UB:RXD?A*''[ghtdASVa+geQ%T2 %\C3qQYN9*dp7pK`3QZ"sC>%IMnX!NE\?'&EX*LDfI-r#Z#co"G:J=,no0JS<O6[P<,!B0kqsEo`#;k&0cE%3,?FbLKlc!./RaGrq %nupBYVSt(CIaC5mU;uS\=a,ftEV&7gR;Kp!0%-EM`#06c2i_*/DUr%\N#U?AZJ%8q>PR$>>N^4TCS_n.G-cCYJ+J<lZ:fQ%CCN3^ %*>a/VLVs_8k'%DLiZm!bO.AIK@+2VOp1T_]@H0lPW\5==m.'?7f5LVlD5t=O7s!4j<VnGJ2)G")p*mDf03-&1OM0]6f1UGJ#:lB/ %Elu=O9bU#.?F)p2-4XoBXb`ue2OqL(qqTbZYJtI$>)Z[6i3I[\\LljA;V@?Xi<irgk(B9#Q!\4rp;CtLZ4bp&a6N;d4EIUZ]p^s> %^:=ALNDE[E<i`2=NiQ2C]6Og%6CTPeFC!I5EHec]K9h/1Npb`=M!'mMhe0r\3CDFYWAT,,bQL.HSWMVQq!HtpF&B+Wh9\L%lhmp[ %3ar3e/I%.Tf(HH3cEVcspK)`'VjmIYG3r]g`6s$^gS@mapSD19])K)7@ct3rXs$^1hCFXaF^ZT5jZF9bkVmlc]CJOD8W?Tj[VT/, %Dd_&GCH(NAq(q@<QZgVu/buPKRq9Y$N.:)]GFRUP'=XL,Zs+om(fLl^/_[5^d'oGi%k!ra2gaS9UBe8X[U@\1pQf_\Hr1UVlF./, %dbj`^EVZaV7op3R#*nTIaT8!$Y9-n)"D?VI.sDgiUh?I`8Q`O>TC+pfjmorlhsT=,s2[3hE,H_$e%]SUcB=q]EXbE$porp3Yg;0K %NZ7]7G>!9j<Jo;n2Io@f\r!R%D6C==Jq8FClK-2jeN@q^chnc2s8-'cH@qP)d+4MPBD6d/VY`GJGFk*2?/.6F'q/'0o=i+tFKV%a %BpKjJr':)s&"C;XF#me1IAU\Gb-a;@R1Tm?rJmB1%rV:(WrqNaq0r*R&ruF9X6.&XH:WgKnZDoCb-8hI_K*"prkPVeW`=P^?*D)> %V_2/drVMM^@s?_BG2_eAX'4619k.mb2i8rr_6%(%="F,N),(id>s5T.p&#\k-dS1[nRl3Hhgb9RCROWif9qWei:nq]I`.J-K:9Eo %C414cA$qsI0-&`]C]!grh]+V%lMQo(__(hEl6XIEPBHasSipXMUU]?Wr4pN`MlrON/tP:Wnaa(,\+@=(];"a?VOuiga1o)kg06EV %d9lQ?b8FOTXOb'ld=.nmjI.t(rD,VIhCX0t=1\DZhd*sC*r3LP*r_s21eoOmIJ:'jb@boLVSDDqVGfCE]Qs66npB1V]7"jtBR%j- %[se/=R2oeqLmP\+rqbX1ZcN/hrV2]3IE$]Fot0\eYFk>sX;b1[[e`O`iV/P=CFAjoqWcg6(X=,U0X[=/m!H&6Zn5q]f>I0-h7Rk/ %_UY-bYFjT00t'jPS`]COE;.D&b]WgLQAO/aG89GMo\7,i08s3"[nWiq^T1?6:Cj=@$N<*<V;8KDlL0%1i:96ZS`>1[FnOK8g%rPS %.g(77GMP6aWk[t(.,"'Q"$]j+hEJVeXEKm3Vb-c7Y.g$FEUWgAmGQXAIW*iaeE=Zn=Zrj\HIihTVJ\Tr=!#QU\p\J:]J`s^W&3kI %_`q5caLun5je)t7gtQ\nT(>0J`GV7BCA+-3s7K@BKQTe6[Ye?SY^AiEA^He1\T$`"^Z#;1]5F.k1qQBaH(Ip<rhpRhr`ib!f'+35 %#LubN;J+\J?Q?V/EV!,3lR0.n*h!hB_r"?ThqrbXB6i14$O>8/l1;KchXtEM+\T9B*&"pLiUH!K,?gD_c0QV`LG%8+o[7*WkMO"" %k1^=Q8$l%,JI4=S\mXQl$\-^`Gl<CB4$T2jYY!6<;mAlahQtf$47h&CB@edVh6V"HQqk&IUscDtjZ6*5FQ_&0J!I%i\p")*hCk0g %lIEC4jp29kg$j]&mQ5^YVnVQlND!momp?%1`*U\\jloWi^0^9-T5=Mpo];_9[[YZ6GlLjG(Ja2MV"C3sc36j"ml+b0QMi2V?i;^_ %]7';)V.do_D=,bS_n'HF]GmTV:t\m%Aph7"c_6Qc03u8?j6!KA%>3EEY$\karlg5:qmNV23dXhuQBdBjKgaCnB?S!Yete!M^>/8' %GDD5!4)sQP&!sG(^N&Sjm>PtsIJ_TTCR:g*I"1(D*LkW^=>FZ&c^%RhjZ?A6;!B<4#EP@fki:d*eu\ah9=1IIGFh!H-N,uRqW*L. %L\C,jZu4DAMs!bR3O&B"<F3DKY`aSkQDsjQkMH.B%37WY_X,7b<ioZ:reiGEglT1_r:5d=CHl%3ACe7&KDTh+=gMS:(\?*tl0f"; %QRYqBI-$g!]D!C&CrFClUGH/M7ZJ<D\6kR<2(Fn@q8-J^`1tZe,tjRT=2%"uX*j_`AR?nFrrR`sJ$Ts0PJ5JB#t0tDCi!5aKoOMk %+Dg/`EOIX6[Wo?e5j==/kPoWQ!0O`Fl5L#VQ%V&Y#cE)/hILR8V-7tSe@65`kfVtLX]i)If:l!G6uogr3DJ7@oA)'W!]3H\)ImA& %Ie_4T2hE-LM$tiY8=ibIM!>*DM!Z?I4>>h]i&f)_!(.7F)$9C8Ot]4-HshVjk('D_4\t@+GTLU/#[.K\h")LbfL;eFSWlE2qB9hs %]h>4'I?d*\pS:$0Zo;%$/-.Xa[L'qgT2`io+Nn0,=2BfW6];"7^k0mq;*a\Q_d>T*SOJ$SaRLLTALL:VgC\fu&E_:iAj@Rd83!?L %0^"@W:'OT"Uocth"t#RU;=k$M77?SeY_8MsWW5<W&GVrpKg74=+Z3]=9NGk\+UOcpX@VOuD+*;"?4gPm8jo:E#SVQ>V6nk&T$Li^ %%O;/[i<A-0j/j&Z5V_pVjP'sq+s->/W,-nANn4X]Lc%Pocj5LG?JoLhJ28<g&H2r;0?4kkV(V8aUI74`[NH6DM8Hkq=lMjl7M(<! %QD>Q*$3FaaL_;j[C&eGr'V:?]1Poeb$Ob*(!OJPo@M,j?0`@`-SbIqZbq_;3kT<*@$p4(rOl43d/Rh+'![M4_,_%&Ch09]J_"j^T %P>kJe8]f..@ZtQ7/='q1E!k(&Gckm.AVlO#JS,%*ODKQr'J_`c:fNgJCdd=n"F_'5Ad*o,&+u*[D@5AU3F#Z*AWD/2TQT8IC,H9I %f`JQcJ3D=8,p<f@[faZF?qEg0MtK%L7=<#&7JcKR-NCk+@QLBI'n8!6Gt?Ykn/)d]!/HOZ/J/=J8GHbi*"l-NKfGQH!@gOY'4'0@ %LaT5@!r/6Y9JhVpV6VLH&9\GY-_DK)RB%A'@ouh>LhQpbhJqfQ(6cc0<//_'-s7``U*'sq/3&nck?^sVM9nd'AEJP#%6$#XJDcL+ %'K%cX>+$e[C]Yd]'<FkNpK6183[9JdR=^@(e((@M7*e6.(/Q55D5,"TEB9(CZ&->cKore!GF;O(((-_>-MeiP;W4Sfkj9[\"<:sq %-#uZ<4L8uu10BJKMFCc"9[&dC^]bS\08N]G[:tYQ9Pr9e"_DQ*jT8P[(C&>+a^>.3)KFQ5'a7.[R)FnTPsoO<W"OqL#O1SS!S#W" %AY@@Hg:_P"dGG*qa<Asi7HG/.0`$/67Uo`*YbDFkA7:6];bT8,3XhZ$@Y-N^f+QUl+IX;nW<mO,F^:<RJK)j!FDobrDJX^W7lhAn %R?3X@E4.bTWo/-GhupS'gQb.3B?WA*QAKH.<lQsPkc[=:;qM)..3OKd',Zf^/$qVgP;<X]^,Uo`P\>64*DN;0JLJ>KPX[P^D:)(n %G_q+'5k]q+KXQs>@m>r5-f9XT4-r_A\9,4tcliiBoE;/&H3IQK5\MY4S@icnFM&Lks/nIE:,K``%FF26l`]aLM0(03h6))7TmQR+ %aXHM=pUXogrd(!Eh\<[PFD,fXJ`/K_%=J-2Su=G[C6-"PAhlP)mep!?mXCXKeTba+Uk\X9`/D=l://UmmrC9*5HF7dL$TWE2g&fa %]AKJmbsi5HG5&W@X6uXPj\ik><s0@GFh5'Q;NKrXP<mf=e=Y;23RRSGnh-^pJ'akGV:r=-Rn>hlQVRRJL6F%C#"#Pcb:>+LYJ32p %]q\1M^it$7meDqm[<Qbj78#m3^/QW/TW73*?tp9PeN*uOhFijok8hiLYaC10/(:ne5jfA$d&)8`<@M*Cj]6*2PTfh<bI)c)666Y^ %FVNK,qNth9%4rq+2!SX2aW/902L8<q]COu?m9A1pro#eR=$I"`_n3MRQ:%h(qQh!Io+TLrXYPVf]f(*`K+oi[3LZGL\#9/'6CUH4 %?IJ&.GO!YL/QQ6(c2FN+r5ij11'@,;J[SLS1nh\Agi+JsG@,:]A+_`oR(MQs5%F#MoOl@nYN=p7n"Y?4f"#XPfrk/+V8K9"<*jf- %2tu(9e8M`!oZ[p]f4<a<=cMY66/Uhe*ZUi%C\5oN3pBGiS$dER-i,oOlcn5FUXa;Mk=c[7]ALPu-o$,BkHbH0;.[lFgri>:R^'`* %cPF!A59>d(%^]BMrJOOLnaEptkMG(FSq$";k3L@359;HhH_SBaD>QNbJ:Dds))^kZqP!V<8'Yre"YQ_X]a-7T\`*GAdkKdTk,N4- %5CA"K;gulu[r1Ts$@b7ANii<]@IS1d5B1MY)ji>B@d]6#pjLkFIO-ps]6Hgh[F"j^+r&2G5C.cOBCYFoCZ2>g&q:FNRek#.0kikM %q(KZa4RB]'Hh"]Wgm=M"HZTDg=o#rWEcZ_4.%Kq<Jq*`%b^9Ndh`*A(ri#iGpgl*2Jae@'Rr:d")[OR3PZ)u6?T7I^m\Pu=@9$n4 %&`L7qZ;$QCpcr`b[Ip869@kW4%hpK>7eiqB\[c)/Uf+n8,@54W2u&b;Th`<,?di`;8p:%D[/g,,I75tD%So^)=A.$)D[*%9m5EhF %^&:qi\EhZtDt;[p2/WF*pY$(c*Vs._A#YM_/"5b62`LKT+rJX7a*t-.h=PH[p<iO,l=,EG.YuRJP?pij59.@P0\fZPnB_C3JDYeU %!2Y&/9"JGSpIS@iF>!=aQVd,eHVPWu?,#$C\"eLOon,&W#HiO42Uu9]Q/#=0@9TZgHHpJ!lSa$$<&>tEhk%d,STqVae3turh^^l[ %MeR80&ifN[[q:T$PH+-/WPelt2Kq`hZ9C9tH8Y>VUA`u?hND2BA(80=2,^R.?Vf2Kke(Tg/MhJBY$',,CQ=fIJZDXdm-MG>V7Q") %[se"u%W^?3q,2Tn?E;]ML]99"0Xj9eb11iOI+6,^m"*nd://.QN_^X`+\$=hAY4f,)GQUGJj4LN&Yl(tlLd$iFtahYMhG=3i[5SW %QG%=^HpGq5T/]Fe_-\-B]E(7eh8!"7254%:m>J`&q;UTJBWJ:WhNl>hjT38gVaPHZHI^AAG>Z!lX3#nXZfh1Mm8HN8q/":eg!a<l %2Q#XFWNJ>A`m`C7P>7!]^JDV)3XT8u@jfPB=eL@pRZ2U)7]Pi&nH"]R4H(o(9l7geNRondkh65$)l4I6+5\L>l:2-D@jL6V01U/a %T#t5_>(3)lK@CQ5k![\JQkP<_p&2%Yo<r=\mIUY3G068[Cj^rdaCDd&lc*MLX52Qsbtli[]kKpMeF[fr:F*)14@uDBc.IAPpX6s' %HQ`(",2$.PpT#4iiOZR+g8=iBhu.`.[WU^[qL4pK-['Xq-O(R7h\1@t&jI_V@5C-qM]Ug&Sc<nUr$n>cMr"<Ld!Sk=G:1qRg<t@8 %Ec,fle[sRrI(nU_)R2].b07t?9B@4eMnPq67q_Gf^l<2AUX`Rj14N)iS530oM0F.+$fZL.$e_ReS%^6l^mf+$a/YQ$k-Stih!K[Y %HRP$\YGs`M\dPb0g7BaM%;>]C?_+pKR(Bpdq*6bkp3;))^=/Ki'\AAK+'U8k5]g"PF3k0HdNCU&cQ1a2jh+?R1-?\*=SC*1laQ98 %ZY-JOp?^YDD>g3f4ko+1l/S7:GOF=o(L929GA`r[AGJZs^H8Q-:?rfiXd=u!D*$C[?.(\EkJ+.@2dchRWC!nZM,D2"%2)P1Hmo6e %U#;/shD-)8>B!:0!X.Rq!s)@/rPBZt9UZ\[Hhef3o@Z._iR'Z322S=SoIWa96SkQt*dB5l<8K/=RUK<k,\96@]AT2e#tpUl-IeYY %E"fSnKV"nS.d$jYPNEjp29GY!r^E&K!.oV`@/Wq)I?L1W%fMQ\!D<!1*m-jDj2VFZ[\)`UUC[se6W^Y'#AQqe/,`>JI$o((=XZUg %/PBt]E,pZ6=t0B&HseVG$d`fZ$5Z%`'0i6n,kN)%eX#39inLb+c:>Dc<f]\AU1ZQ`@k2q.QtR[L5:D)6OFh.u!'ZuAWb6lQT@(HG %-5+Gd!dFJhdfP+%Th@S).+pn3"=RB&r[:<Z!qJQ2C]U>!6D"qqUMaJ]$quH<G(_se'asta500MolmfuX#j;?S;iF>)mQ]Tp+sTsO %[A9%eM3S/0(_Sa4Mb#"J!/)C)Z=$+Lf4Q:W+`WIp2'bHu6<@ToF@/Z`$f![W(33ua0_ie,!dtmqb'jHo\pmPCfjSFoBPPj9eSX_@ %+S8D7Of5.c)cEgkHAVff&`j?Z-tEnq:^*+k\;sHg.DQu-8ma!4"DTFU;+o@/2G/?))-=O0E("&aeg9Fh^u[9N+&\+"OST<<K1rY` %a#Z@Y(m%NoW'ul58%PmXqhd0@8iFP+7uG<\!$OAo9U%pKFYhVmfSmTLi8[[G/9[3)(_-Ot@o<+X$j3:Y!i\;CWiVR]^-(W;Uj<f, %5-IECA)T5]6m'rB6?$V[!FYFc#juQHpkY7CpG[mX=k!EupHT9u2HeU&Ld;t$qOaU#MrWOnaC:eJ(+)Lh%M0I#6m53dCl<5bUc-1e %IGlbHI#RX<$O'aVM?bPVaR9XU7bnp2!)^3ncjm#%=9ct5=LN0;JmM:;-kM,e5SWG!fN',sl6EA2PbL_?1uQJ=,g\kL_P('IG"e8B %9h+M<%:E,/06Le/ZjOE!cN#*d6Y3Z9>=/M&69,Z8LDbrDSi9b.SJr>M`rToi@]Q0%&p+qA-%KAW_Lk5]j]NSWe]229Z=/;Q9<)5c %M4Wg-.n+lU)@oef8[P#[WUZ05W%&"(__`3djTH'QJ'3`gX<_Am3qGN`,>mc2kQcjqJNtN#UVkeeJQ,YNobrVXFaR(q&TYr@jQA!Q %9CV$^<%%dO@Eb'0oa2CFb<aNsnOX^(7"(aND=Vl\4fSL\[6!sUS:L6BV'7=8.2X(Z8Ia/s9em4^dMOiRT^7`d;"SUMYLKB?8C5rm %UPH)f+="e]+L3Oh-=&UXYugO;!?PC-5E'gq(E3pki='NQ+J#FoF)`kk>W&M?BU(8V=p(O7;\PP2?jdu\K>3aA,0d!JRg#"0D'#e` %0F*CE"pPR>idgJQ`=VNTV<@'9W?f8iOi>Dt^ubC71U)'9Eki;N%MHI:Ko:Z!Q[f&B*2Dl@VH=*i_T.e=b/2>^+<]QRfj<+X"Uuc7 %FS+ZW*naFh^=5IX)Hh,&K+GqqML_PEAs&(o2HkV=/1-f6;sh];:%T61*I'3F]Bi"c2%,+L5[UmIqOD6*-83.K7@.WeM]<%:8jLk2 %e99=P$2b$,W`8$g&a82*j_C1)$s[0)qh^=K;PNEu6jq6Lf>FG8#I>_`!!-n&[LhYsU7NR%FUX!bOsT6OROJh+&LfJ(ahHp_<\se6 %>'`C>8jW`:a`(D;O;W^&-0Q4+r%O6592W$O<KBa[$*skIb9S3,'[3B8p.Pc.,u#iPgnqpIT@*YV`"+A;H!.4AL<(:cXO+B['YMf4 %L&D+\)ckPa/D@*PL`,h*PNC\UW"cti73EB<B\'p"/>Z"FhI=]K,8qhg*Cu1XW1T/T=C_N<kcI+nfrXTL8?n<\)7IY[M&Od;Y5i_s %mKiro*=9WP2")XC%+O6.P1gZZFA'\PPZ]j)g4\eQ]chc#'Ba68a.0(pPYBNR6:ogNk["Y+G-HEe#qn#;To?'P??DI/k"4UN"c5O7 %bV-tiJk28;P4<4<D'3TO]"H]&e/f%0FMQ&@@Maj(,0`)tEeS<D64$><[Ta$k$:(a%#857YUn-]NILG=%?c//?^>.?A/fTSOB?IqW %lPFt;"DC.1LMTl(2m>aFN3Y3P,e,+8-Uo]V$Tom1)\lNn!1\TR#l>ua,;8[,3Gu[;N"Si69+Hf=OR72+OCS)V84Ji7'-M$,F1'@! %L_:p7d%k.(BWa>k`\+9PB8TRHK!$d#6T6-Y7jnC^jJ[qo@cX7OJ]5P9?tU[t%9.n;=D2Y0TIP2"fgf<m1kbFCPifm%<0BG>(i,iG %]S*m<O*aq79u8.mME/tU;9oCO:aatJC"B!PH`hU[iup`('-k[m4RX'U[.;ZIm+B_jM&JW9;3Y`cL`ODB(nsogM'`X\6^$YS%,RFA %SOf\>8!R+!LTk*X?"le42;'[=W=^^GgW-c=(>sZs@j@M)<>Ia9P);Z4jRQi9:hiOEPXr-=:chHfq16*<LoJIU$j#6c`h>)mU1@C) %*,.q&,%JMS%)2dm`=]r/M7bdAYH?Ugj51K=.pIk7_CeMa]XEIU<I?tsI5"9*!R8u&FEEa]8>;JjRcK>T,J)?UcGG*=ctgO012hjR %/]*Td@At%cUaj54Tht73&X)C?$7dCV+j'=:Cd?W*D0Q%Cl3VSmBNEk3#VSM26V8[?>=^#]F-J))9aGEiIF&2>WC5YK%,$ZP"t?m1 %^p"snl6=WN>/BV6mgO3.`Ym,0"Xki)W5i_\($X@!)N'BCJ2ResBO2*814GX)CsYXFLc".Xcgc:-#`0^BqP3!rpW&pJD$C1RcHnu, %@FO7BK54%dYt.:Y9cKemQiZE`#1BNV3!5N0&XSP#Ki#0'Fr5+IQ3(Y0o`upQ_[MN/5UY!]k?>O=&VAH)pp/<.,9nKWfgIQAQp*WX %0:17&JRA1-Zq(3#fU!m<837CL-/,*rZIa2O,otf7V?Z6hdqKZ#-d^YS&b0G:?5S,VeI;qVN[bpNCr-ZL_W_.mIRW!&]aG6_6@qSG %"+G5c.W@]T=;WplM?[RS6!P>Q5gYujH!6?oo+>jsTnZMu([Ynn_S&E1b(*6:K_VV6(=35a"mXj=:M]NX&t#)kg2J"b(0c/u8=^MC %<gs^2cer&R/)d3C^tjMbIUI#7H-CrOR/t!6O%-$CnFWY.*E,]9DTE8X_oMhqe>7#S*!Lkgk9qn//bfF(>nQ?8@hb,O4WP5)T>IDW %+lq\@^dgE<P!"cPfRl=I[3*U&G^'I+@X*>Q3jI_.Yo/3?iX5M0q(6E"EK_:J*H8)Ha8n+a.NKm2rLaph.5iWDmHL\c?:N+p0-`g% %XQT15=WG:k0u+hG2do2)W;t.hoX3Xh%^iCYp/bem$E-)5VN*+F2lQ^rn3iKk*nZ*Z9J\u!84GEU3jDNb?dVADF.Wt976#lLVJ(bs %#Ye'XK"42fQRb>Y(1M.A`:).MVh=#`DFBCR*8l.slgXs-+R]Vj3&h*_TTGQB92o;<"H^GI*>"k&\9*07of$,:_*;GY@4uKeK[WJ> %(%<m[I+G>E>A/0=o5q,K6GSK#)>F[HkQR9I,#UfDnYD,1ZY2I*+b_P'G3DgJMVX3>,-&B%RrQeqQLa^?m?("&*B[_i/tLI)TAS`) %$=CfB_8:'CW!"-H6oH==$I9<I*0.m^gjrYR/Nt_@j$=KRLQ/[.)8QJ$=!@`uqKs4913,gPWT*E%$g#aZ&Bu0.Zj,GF6*sV`]Jp/5 %(81I-Nr<Xt!hhgm?0L<<JB\t;hgHF(QtTt7J-0CJ<9!:iV?r%:C_;D@L*3?:39$gaK[=49+GAE.;QATiK0]dKJJFX0I]gd=&<Si7 %.isL7V.G)<d-&2$T.Fh3!LXG%&Tph$#6R`^o>5UqB3%1t="NAr+Z@=/UJ;>t<^Ni.QNf,GU:&YWG9k4`#]4-+g/5YBV^812_:K=m %hPadO'1VV$LcTWcDMXb;VN=3uhHQfLCqsZO-`T>eX]YVPYq#Q_ftY4.Q%3@@%+&dM\i)t1A-u@oh[&Ik1]ID[K2l1*&,lcb<IW/W %`a8[TXrj>sQ$3*Ts/JJ4?4T8a+,,k>?OrPnns$Q(p[tV/[tojP?V_A1W^Y_?oiS3!)/+-[nZjX0a]iF3^R&$`V0hZHaTo[a?V:9# %@,(,n/5+SLpiVg2d9=Lf.8UBIO*cs%e!3?e5G1tVePlkekmunU6iToBX1A8f;lNB[HdjPL'Q]=!T=<`cr;+keRMsu[:I[@q*&_Z$ %:_A$#8ltH&F?NU-TO)U=Z#;>hUUcphL`:U,/qIKaRK['&oFaAc'LFXFcX4Gc>u[iE;JpfYqlN%Pr"2m?MGu2E.r`o$&.mB#`U9!3 %UJb*jqH>Z$les45D3EDd&#E1M^"sqK'31ho.mUu]gid/]^f7=1URX7VOW]^=DN+S'i+(0Dbiu1O@AHM<):1.(C:=&aX])9hV,FFN %oh$@n]Q0VCc\Lndc)M8D3(/f`X#+q7q]j+^"u,/,25>rNR6@3j/<?^/e;T6B'n3Da.TL96]ZG(1E^"o]go/Qn*B8obLR/M>fsJ8E %p>W#$^JM\J*jbIZ9.rI1&T8%hF=s#.YRjR.O/;\jerZ*YGL("H+8Fk<U4-CJ=WO%`nsPi;8(JXZhO%nEW_b+TK2n]:nF[^4p$CDH %9[!Fro1qa#7#a-86$CS!0J"-'TA2T@n+gFSUY2kMqtBJ!;UEM@P<%dFY9B^SMfp,r8C+(Cb^WsnM8K?dD\iWopK)_8X.QCFESWSJ %^Rp/QL37k8&1)!Ej8B!>lgXL!7p/n218RdoW3!sEN/H_@*^?Z2.b/SfTe?r$mu#OJIa6H^Z^OC6e=O!lo.3&q`eG"1Do/Sl@!@&; %-GsSn(=$_/Q%qW>QW>q<Gp9KQ[4*'hD&ee?hW(C059+%e;Tm")[F3O'<qAQ?QR^jb\nLVgZe$g`!1'kq\NMYjlG+U--6F;>qSS?( %.s@JoSU5KHNg@eNj^0O)lG)T<cc8`uMKGT;5MWRKJh:SDUR[pG8d-DHWl9i;J.DF5OLa&HKb[$pC#$,Rg,%>6ID98H#1Kq^FlLo: %n\Z^@_)Aj<I;%pn,"A<sVcqt<2HPeCrH5-ocqfZgnqG=o0pB!]F0?WL/9uUrIe@"XU$PTfSeb`(_t#-0O5JieHD/q_/GS1dWDp7o %2I2T`G+\Q:#7f#k7o\KE[4:%=5_3UUbs^XjeP3rf)`jr*M\<8W'2+eQc!ug7`!`3:cVk[,=6D.@rOoj^jg_6F9hZ\'^R^&.YP!`1 %'TOi/_l7&.&lJD'\sV?&oB<*S;H4@.nB5V)9`=e/#?)qgI%q8;(Ujg:3_;!S'RD>DIXZ-\pJco"EM2fp)3n)gMAK#F?E3!"0(#)Q %OhFOjHbD7Xd^Sr?Y=HU0`lDQsY&3Nq8sQ=rVV82:;!a+PVPnaeTQUc!Mt`L)h"Z'Wr\uh4gu>?5,5%Fj89N_3,s8YRZ8N@1COf@H %M!q`1a'1FqkW>bCfoDUQUcL5$s5_n=HJE8'Q6L.AnRq+G+S%QR/sUa2d"#jdP98BJN6U),hAXcfVq]SKa\X)X]!D0l<2WmZlD/I/ %@U-s);5r2JGOi%>CU`)QHh6$IfrMl4[rJGH7YJbLknDC=g&%95*5!eWpU,)*%P;O\C.=KFd64'mp4jSGD#Gt.+So"Y2,':5!2o3i %@sM#l]401'\),e`GP(lkfqhWH+U9c5o&<jqXb+X'jB0NCI60i>aW9409PVo/[cc\*WRUG+mug,($%sVta.SZ&IJ$:&/j47FnGJ$? %.<kX*GTDc)95=BEnb<#;qU48Kq75;88&+u[gUi6!>hqJef[O1d*qg)q%>%'A^^P0<?c9lA:E;HHH!FYLVI#hAZ]=53q8@DF`)>DE %mCWATr.n#V%o36!hm<>K7Wt]3q1pdu?AG8Ym8d00Us3!>#fbRsP>^L(G#T%]j^oLDqa8Kkf'\ra(/Lk^1J-\Ep^sU2\'CPspL,#+ %8VPhfn,?.<lg23s=tFlq9g=Lbqs9d.>+Bj!3HkuQ9>@XsInqZ7d?X\+?/o_KY3Xtne@1g:8XV:pmP%4F0#sQom1V5HeYhOW4@m)% %m%'G;,SB-Y0APJE&&"HhN8h80Hh(O=)b3*:cB(OqQH@nM)@MAQ[Bk4G%P!_uP>nrpCCadbbJJ8bd`MGL2gdHb9ceRJh^EjJWpPSe %?d1C%X%0V%IWnVtp'j[XQ%d;V7F0Yf2K%9SF6>0eG(4r0oVH=^Dr/-Ujii9uF8E8DGc0a#.c7U]:?O6OFm[nbfALqtf5KHWH,J@4 %;qgE6,(%qB9TsYQ3?>H\B&+tsaoB0LpZSPDFB$8[(+T!L"eMo`h**;]JO7nU2epsO7'!2%RT+-gh7QuAHu#D_H/;H49=q'87Cue% %'tAI(;n+/jVatJ_Sqt,_^F-iAli8&:m(=/&AB.$G:C]DRI:PQa4N>BqVU(W:5TeYl6:$DR(S%T1";8Fi_^EG\%#4htWFmsiVs.;) %]7,SSe1>'3Su5iV'Kfn^JeHp/;(@,?*G<chli</l/ir.)!1[kek707)4SI/0A4d>oR/%63"*r$2$E0b^q#"B=4G&dH,kQV@?r(sO %$*H?e1!`5"L`md,;%$K^AVOGAh]c<\!9?^Q4[O]&C`1Xli$>XrO-"W`6NEoaKIdQ6NHC1)e%>Z*70qh(k]K.;]-al8;-A<SGBB>& %HYQq2$2V/:$@aca3.h'U`:R_Q<#.R;":$!Zn5XQOH/nt=%RDO(*6EuP0&Vj"D20-nIcr,m!lTkeV\*DCfr+-\jqaW09F;*Y15%/; %87ot$nB$)-!9NR3A5An[.$IcP!16@)1%c-gW13l9CGC0d$OA.3$pYpq'XAPM5!'*gLI:c/"G))-Q2R%%A'_\hgp3G%N=bL_-36+D %]FGO>5%@LoeRP>^JAC?o.%<j?"S=Ad6$,-OKSF"FZ$$*q73jL.3<p3l^tdnL>_7\3>ej2fRT))pP0C>ld)ROA(W,)iOO-F4#!an+ %l,$F3bimN&Y"-`*i%74,)FSBjBa-`9;_Yp%_B+,VAeqnoO;UD;N'dUsORFm)c_Ji_qD'%uBHkbUO8N*(E!c[e.OT\K(>9nF\7I!V %Zc-V?BT<YN:k"gbEGp0P)A3Yu24S6a8!bDY\R?&f(j10A;7A``q$L'MU/1/._]F5_eH]?!^]@=E1MSr(G:8E4K:YG;_/_6F#d=rU %#UJBC_'+u[e>n'=eM,A5-uMp`JQE!m@u!<dm`Pm],j^c!,6+CJ9o^k="<iEqY^6SOUq?mOV_>kV'VYciKEu&j8@TPYkD:5oEoM=/ %:PM&"KWr](`g1<OG223t6F@rC]4l:NVeq<J$Q+@\ah;K%%RG1>"Z0g&Pn9&sEWHj4Ggn`:)=RZ;bLhY2<!T%NQqbJT:E-=8C'fUr %6u*t=<s_&(d>KjH*QHfi-pc<,W#6hU!u]Mp+EGJ^?tg2uX`YhKUUSaO=)W,rGaK\knf/C,-rsgYX`PP>joBLiMeM5a_=&@R,TqR+ %*cH"+"oMYh27mn6Fp#_c$d:jQT/^7sa)DCuB4>hI*sEnb(<0p,R%EI``O\]M4c%Omm!pE").!t3B\0/DeE$3%ii''][UBbq8DoqX %')25V1"*1q(K/&(LlZ$iEA-CLP'N`%i9'hLdD\s=&8UG6Y-uP.b1[.gMN?r:+`auI1n;HS<+,g3C!-nd%P;c;r5P(#+967([V7>5 %M9I@XI3QsSTU&[,?_1ucRW2;/KIBup!"ner_@-h]m#TCE&Boc?2^f'.o`Xl5kj)aZN)]OOYT&QTF`2(bLiW)@9F50Q>`R:-G]D&B %+JaP!gUqn_(2PX3Zk<Mg&;38o/F[W<Zt/B`:Jhn-GB9i)^!)`AG4fPl.)r/57[p+B]M`fl;a_<10WZgZ&N^IlZst:KLB=:*jUVj2 %fYAd@J18*1Y-%j"6YdeQO4Q#.J5Cg%@I$O\;d8E-@K^1F4^k)+k8C"p3Xc-Z@;H3FSQGk,n>N)[i%Yt'8HIDHjq5Tm:m"NhKf@%( %A-g#F-n,GJV-"Xoj51utQ.qC&(_BJY0_;n(6bEGX$),4<Je6$4J4n[n%3-W`X!3=j,@DUF5(&58O*\QnCC70)U$0P46HrAAd)ZF[ %Web\"6j)CMKQqqO@)Y35N37gVHPn'sL<-6CZ+n5T!#Tnfj'FkW7E\Q59,)",'1"UZ))roI=tG]VJ82l..jg"l_!DD4`53\ublso0 %8/.1ip^rnl5i3,<@&S^6>RLSffS1(`U<NmmLA/A(3MEG#7W/j3&qrc=OFl%&S:QIX?c(gn%#eO-",-OPCcBaX2DI<4CLCRE^D"j< %!=MIaPR^0uBnI"VE7^g!Ph$r,fWhh^[4DGqfeQaV`(_pRXVhiM'J1"5qZLmrL5J,,s+i88E)8eC$^>E:7E^PWXOqUr&JR4?[,i?L %Q#Rnn!iC8[$!]GX=W\SU*7.S#V,&d!*.iqkR>_EP'NTa76H\O8E"!)%iSYpcb9B8s"S*T]`/k'=Cf=Jg2M0Q"_$b<L8Fnb5]\6uM %&D86^d'Tj\/]BlFG++UJ9W=RYj<NYB""X5j$:u-fQrX7:!H*[+jI6@tR'<1"W=7I2+ig^@;FQfE:P=mC0$XDUJ2G$cppUMOF[HN: %Ujdl.,hrtsMDkkBWONiGs6a^dVX+7h$6W&J^V9RsGId]lIm2bS(S(!(^OQ+M4FTn-^W@`!cOZqFISN\[)nD?V-i:7G9ZeujM^@MF %OhEDhnq/S!WE3EV\>"KIT`0#6U$r"e.cXOADQPk'1cWuPcfo_nSpE($k\QZqh7>JmTP>!>3d#Y*"Sbd=B$R/LG0fO,FGs@29iq(G %+NCtj>aU?cgjH6C)m@r"PS3oH1G=tA=]k^gq=:]p]]u-gW+B2G9%>[Ma)4OQ<NBWq3j7)7kf-R1T;Yj$^ke%c8omb@k-(Z`EhBA\ %^)>^>BB<Z,W<0=8<35Mg:Sf*^<^D2Nk8X0^?9O]D.eRPKTj>j=;DeXeb5r5f&ZlN@3d(DN,@t13aU+fUNu=+3:U&io3U[H[QKn,1 %I%XRm?GTH$p8OMRU[S4lK0!92b(HRPWL'2Fcu\.^CR7_#\T>gN*\HZdD"*%2GqE)ZqU`&r>1]K';.8DLaj&;@82Zq/eWJmI:RjWJ %ou^FT]/L4o:I'HTVdHP4be[:?Zm)uTf4Ff[hAM^Y?QQ`VjOMGop4%SMWt0un"r,NR">gRgQ\DVH0rIr%66k)#5%eD\R\Zt.gNWA, %Wp--n>W\deGf?FK%:?V;7F;Dlk2b$H:A3"1lPVL*^Q]n&hOj7Aeh,Eenm"Mn!6?^&QE=3rb?VH-?sEU@(dN6$R5_igL+GA=>qr3c %lD;e$HR$&dn]+O]b-gTkY.Eh27\dDq(PtW1PCT6PWV;p,#GuiP9+:^e]lqeQ96TXY>+eidH9>35_m&+e&bK5/FlTDts'fKaXZL^r %m'kE5SP<^E4AE1[US.d@"8EJ;@&hAb)&)Q3^!NViJ@1to)&_"4m(;3)pNe)q$!nL_I)YSan5k7I;n>C2Jb-arWG9?.T+*)>3GmXp %!;ShQ$@U,&PF&JAg,,Bi];=7_F:j![S$D1J3[ptIdHE(hT"fLQOMP!?5"B_9a!t')rq00m7A#&j.`N-/F7.XMefemFVo>:RkgAV= %2_.@gW;Vqkh]3R4d:1tT\`00Vl;u!iU[3fulTaU.IG(pdG$Vbd%G4t0G'JN(VdnG&)`@iGVT!l,>IJ'E[8c&0G:aI.SC5[J&X]K\ %h"@:8f+=oAlRq8\*gcpucrJgZcY8\[1j8!eJ01-F^\H"&$R`,BIVtW_5H`_?+i/2WpKP6!j$==5pY%q6p"\1]Fi*]t-]bDN<%:mh %go$d)D\Baf_W6^R^Y<ttG4#kkZVk5>eno3nr)Rgk(LPBoioV`>pBeV5c-n$njlW.:&@MJ[_q+2-3"r=LA_"8F%j&<PRsXGL_*e'A %CS62)IFi=A5\Q4A,JV[C(#KCT>P@?W-ao%lVO<a.2JlPYI7KOBM2dE_\'iXB6auL^L^9oJIXG>>$QL5jM-1pk^2`GukTrs$0-4=Z %eURI]ge2u1pCKJ8<MjJc/q$3*3dU!',&cqa/VY^coI40$9##]sp\O#c$>VhSF>Oe7SbqgMP8f6D7sM:If9sf@Cu9U7_W?DCY]mc9 %qabVkg-6$s6>msgc2DNrWli\.h4WHUI_9n%9E5a?d,Y(ahk.Xn\?9mW-R'FWf!5G>jiZ.\;=^A.M]7#?^H6qH(ceE^0E49kf@HM! %Q_5I6^7*Um!RRt"-8?k1fClD5RL4#D)oq]T*fT"UNG2<[`ETH4(s'+;/)R=lH;YRjXk0EN9J1e#qYgAKW'%DVOKR-k*\4P;hB2f_ %(O+0h=>'7_1isXaE^#m[DXLNMp<5j4PRVu"*s="acJ,!0ITZVF[$3]>ikkW9]G'O4aQq=imKRURR+E_^VVQI4)ntM:&<H!Ie&jdl %h]9#4oEiFKhcR+#62OW]+5D9\*1!ZEbrVE(hEd7u[M4mLo<X),/8gsr#K,d[EbLeU8<[EPPo1K-?72(NiGC`d?+tJkrVUTmIFs0N %[5p._`[H1HSCr`pHA\YRG5ui0"$=;`eW=^g?A%"\7+gJi4/.e]lrZB_?iN\ZF>W@S[A3U/QoK:p)\Te32s3`'cbjncgu84h*K.fo %07X#H[S=rb80ahgg3\Ttjk`29pVS'#jsrOeSj?Z0Flpm+g(aPOjPBP3`Y-n"*TLZ)T:46D^.7,<jZQNT#$6duHg`DEbBp+_R;B(O %\<h5@gc`&W1']3tI_fa-Y+49.3J6"P:MAJT1Z.TQ[XRK14J[V0:YL-[Np+dCQ]>rg0XPJj[Z-/Uc6<%mUR(:0G2_0">IQD&CgT3: %HgRn0G@R0rft>q<:Y0I;ZLo_fD2YRa4*L'SHN*K3F5O-IpT7J-mui738nYQTcKWiHY:a+loc,r0jl`6hSXBB9O^tFjq'N4J2n1(L %mXP644,3)l0l-r*MO;M%U:Y)5N#`+b8kE=p;sGDc5UYW^"RpH!`WTt_!Wn!7bZtLU=GA1@;Z_a"J-1ie:Sq"-[=jmcQ1tq^$qPd" %P\^H;,N>J&cUD_0k2n?o]2CW^88C%i9F./$Rj;`#(cRO-ap#:WaJ,3C!Wd0]a(Bu?E>AWs%\,70^e-^9?uD.s61L>Q;J=OD8+&Vs %&1SS%*u2<Er*OGupdi:7e\Ik*!5]/D%;R[B6Z?pNF,>6\]GD(#R8QkCWNZ^[Z.jjTLj2#_=bH>R^ur\$$%VA.au'taM'_=OB[]g@ %_&NU.3jJql%9[@#eN+9s3'Is7Es>$A"fLc0agaCUH0/4lXV(UqLs0jDCe[+M-MAQi>9[\[0T%*oSSLb4"n6(HUs:7i?-L)mi0Ogn %b^i8sksX:Bm=cq8[`;-M?g0*H&dW"\7g>amU#5tQ:DbUZKCZ82&QgAjn=@CO]VnrV>6:upmMa\B<s-4[5b]8998$%A?N@WC>Y,2, %3mB!dAWoW@TcSf1#mi7JPHcHpmCB7$Ko$Aq+[2PqEbk_c[;#G?T.>jOdHG$EO/`9.6m%$m9;//0"/0B0*;Km'Ti.SbbTjW1%`(I7 %M@I[^==kIG/:eHfCt/2a*+%-)q->7Bms<(CO5L0[T>GS>gr[>V,B_cVICR*m/&7Fg9^N#s,U+h(,\.CuJ;AXUM$;A"&("[9J-8Um %qNMsdOI57o&CgQZ8O*M:A<\&qI0'9HkNJWD"L]a0Sq0PA3nsj#n]8ubUsCsl35o2*(_k^M='=If4F8p%4<0ro2ss=>FiQdf!etHC %kTY4UFL`/&QjD:[">C>%oEl7S*nGl*Xr'4X,Q!<u=J(8:`L*n>!^HGgU_:s[`XW!\/g;mSkmYoP"@#jk(=3^ch?SQ;$%Pu."1D<c %ILp!h5[.K4i8r`1cb`XlKeP%[:[@[u07ZGmA=b5TJ4Z(1-%J2*:gBkE5qRbBRQ^KK8K_apG];&E9>D1u;^:^4Qat=FNNH&#Vudn2 %L-]-]9.$+-@8+["!@Oi\:Nf)p[q_HA+BScIoFTatcTkQ5LM<!/D@PTFpP9;?rj;aWA]WEF<K*QAA^bD]d@(2SD[76c5WD#`EYqW' %b`Y40MB)ob.]F3b7h=!Y]$,F(*-6.XJf5hq'L8H7i^3;ac`VmK#')>#^9,Xam%5W@EGa4Bk<SgSLYrD\:CF%96tqFpfI>K]TeQj* %$Ee9!k;^kCn6I`-)t^f]9*N8Q`'=a<K,.D(qS[.X!#J,:^o0R5!;L.4^&\c\":)K#O%pf6OJ'^H.En,#QC--G=iO6&kXB><&F^,3 %nbC1m/b'p=Wf3eqVK`/'B.3oM.Qdg\BY0uLEVVa&-[A&t)doOs$k3inQ8u7R?Ds->4u\'3*=llSnP77mhH7a<-]f[K(rhSm&-O$X %U:]*0i]m,SWa^=D*X'j.U\"e1L5#tk"GV>6gpCUdRZ))f!sbllcF,$'F!16%6d1h+=@"28TpE.,(C<Q-J;/d#5QKda-7C1!GQu>U %5A1$=^"A>g1qSBRTUB2c6I,mI>4hX^7KX?ZDAu;@((B_H%PqB-ZrR2M;T;!&Q3o6!;*e&ErVo;;5e\3-D[?g0Z&:j3M=h3De#F'n %`WF(s'Nb?T1]ID[YlM4Ds'LZfaO;N/n*;?"8_jcT:ZguZL[KUe`p7!Ap5f,Bp*Wl6!fu1%^:Z+!p;`f:dsZLH^XC=)Ujqj?:VZiq %.eT/s?Tdn"d<i%:?QMb7Sl1Sp^O0WnC:k09:nmn1Gk-opPkBpP)`T]]NVi\5qR>@_o'.%d]H;A6$6@]s_>^cm<?"tN<5NRAK';r) %@m`D@TPag-`T'Ae$1LiN%e]VA0/ouM49H,9:\7o^Q[rW+08VT5,eDq`!B`&>]p6i^][,01q]aSc#ml`=U1VS<;>]/KCqRqTq*aLs %"/-)sL\-^TJu)e3Eqg/176KU&PX3Rn6eY&P"\g!no8$a%b!C7p?g9XXWQ:ENmA6`_nE_rgSZKZGKp*HGaY+C\\>.8Wd0D'FEi:p/ %ehELZq79"i*Wj8UO-V9?YACple(Tr';^o>!H24EHQ7X,bb;4[?-pMh14@u/EZ=SqBLSoN5rKjQ=-D\PJmggtpMOphEY<&^?$_jhh %;mUXJ]@$(#R?EOOTL?*e_qIRkJ$oL8pI]9,+Um"GjjM.Td2tgB[&APi=/4.^i)=s)g#2*&Q[LX$&"^X>*P$F6]ASp#m$4Ll6'EY7 %0S<!h:Zgeg59$2mgo_ME$s2]A<O@4-8^"kN1[hGLd%c1OAo@GDn63Zn;nDMbofI848TMb?[p7,$4hhW.C+=CC-OuZ;lqrB<T1[og %X1qch)]PL(HXC.*]tR;;R]CNLo_-X<os(u-Qj3\df/J6hGEo>ailo'XcrjjH@!f:9++H6Yqa.9%42HPhrY$D7W\\VLR"<M]GBV[? %KESc.!UQLdT,c8S?D"H4>!r'0lofP2;'7\B%]8^OX.Lm@k.h#RS'`oA4WRg@qqm8p:UabNM@\3E`q"?$CYN\')"OW7,MniXLDKXJ %d]IAgniYX3LiV_3fMnmDe4E3ddr<Uq+5j1=]JH"d*',i,cAcc)okgSB(>>o]<e]jdVMnfhINc:m?_>#O9eUn1U^?)am'<1q'F/4P %>if>mR<%MqOdmUS:)uE;C^nMrQ^mj$h?AMuVote<XPpaKEtF5\J!Aut_^<X1Ec!o.SIF.nk.jLCX/6dfh"fJ/r0Y/D7E7@cU45?Y %ECarulb:1;UoQWE_!P?=[On,Xp?:VE?_X4Y-qXGXn=Ad80:(U+eRXC%#sGagpctj.#VP>q=3a)N*M3QWU>ZI$c#IH7e'uQDom!Vh %1J;Ak\?Vkh,kfooq.QsKko[=s!q!EPX+lZTe>=WqU\@O>UO.00eFZJ$`TW^BI5Q;el=7EkkhOHpj',':obP_\\"?tiIaZpQaij?U %-PJ,C'5IhGe5Y^uZ$TqddOV4jhVJ)&rPE0H9;QC9J'WKaB0RJ7;Tg5KZi3^[l1F;mkq>QFh,`XXCsAmKZ+)D-=?\S+pT$&pH[[!P %2pNLM5GMLFImWhUWt&IG4$h/obMRfW@VWsSC!X[%kqHVlSeIIYi9QGMeqr4Tc0YBu\P1>-^=heR\LTW-3HF(^7OF%_(QNl'YA]=\ %MW70o1s>,B02?#^C\QH<SN(]eaOaWs:%+H6[pb65!_=kg%[se9nVhoWc$t>sYZ/;^J+ku&^Z0CZA(N3=V9a5t7B@^4^KL4/Gbcej %0*F)C$,K69jU\0e!L3$uAH_2j[YV+$RX=71&l(dCd6i'+Ot$^g+=;?ROX`,CpXP5jrbpLIRfuFCZg"2Y<34:V:Dq-E1'gBY(7A.! %nrTV=PHMbBi(V1h+>O^8!f8.\mK5(^&laQ`>000M"eI.^#Fl#'ZT=1'0a*Q4'+SOWUi)5\U0>qPCg5)u[K@.h+J+'F=UU$QK>X]E %Kj\=H1'VQ+%.-Xp"61s'#T?>=R+7LHB+.;R(q>ljET8%e"6)(jcD?<L;&2LAb,-6^RmjN>clq4:gTY6GR2o,-&ojirAIa:9@=@3o %(ZCD<RgqQ[&=FuOOL+FMLEm2]J.IB?cQtj_)&!7;U+T%6#/7:+_%0ZqJch"k]U?KgKgNYDBNlfBV;nUk6po'S81HoMgG"c>[@qIj %#tb4_LIpb=6H=he!3-$"?m&`\8.08MWrW-fRe#U>Kh*rME]E,5FDQu7jD)aB73#86SKse(.(hY:s4M`4n@5Xe0\GA[M4c8ZU,GX_ %;I%!@i7f'N!^VDW8<<rj;'JF<#"&IO?j<&#.+A-YI/UA%;-h4J^;TOS98Y=ANoS2Ul6uVe/9S\HEEaets/&PTfPTVa:#_sOCr]-= %TCooW1N.dE8;`MRd>6l=GMg+.gjAJ"kFNF_LG&d!+t&JN<n&cs<(7*4Z6k,Wco"^5ab^l1S2Nu1SaXZ!Z;Jl4O>TV!JM,f133=J= %Bu2-l+1d!C&mg7>l=ptEVp&c9EJ5<r0<q;d+b^VGdd/C5ZjE\oeL"ah^<SG>WY0M8oQbIOC;V1@1`N6=P1dd^)$f1io+n&m^m"]. %Q>86TMS(qB3"/TdBd/Kea\*T]'amIm9"BD!9gfh6P,^JgduAr^&CrT?.%8[cA!)#P#?GMY9KK7CJo,4CG!Z?WOJ!]sVIk]Z(1+E` %!H_a2+XAK/!&gok0U>\"!Tm>n^JjbXArS<%q4U*7_MfB]*ZXH-:"%T0FY6MSR&ouunfd&saT4DapR3h0oTf=&YT0@6hT!d_UnBk\ %CAW+3dY#VSb(7LN>c;:N<q9j>+sYWZF%YYtjO)IBG,jdB8ZA0l=DJS<l)lfU@lG^]eg=WtR0#-4i^,XIO^P_;&pAq;[udG?D%IJH %_Dn\$q+s48"sdVo&E[tmN%p"G.Wgh:PafHn3e>JbYTqGZL6K_^n7[r#';NDgNDtG-4kS,8Rt+K]YRtFm,8-#g"!e"mBHl<kjsCmK %J;0%]'TbRn(?2SN$\Cm1lZ7Oig#8s!3"F&\q^KlG/9jSX0r(fSaGE%P$-(=[Ic.(Mc?I,rZ,P<<],i#_Lf^U&a2I;0A+TVS]<mTM %Bmj_t,Jb[UIb`JBC([u\,,PAF-$'`/5m_26G2fifH,;".!\duM]ab.r\1Y&iJKs$g3X?/bKk:aECDd:4)F&phM%QBu*Wd_=,.<.1 %^pG",3#6rE$6>=P3VFb*6f@_ZktK,;kVV$kG@Eo#0t"4f:$WSB[YP2n,1\Xg)@'^(L;:bF%3pa/Z^bo73H8m:1Fpm^!O(aMKj\l( %Ypa1UB&Z!O]H#8!56dQcQ5<[(aWV^\bboF$S>;7uK8p["2FI[hmBAc=:'Ilm\.7J_.ll*R+WUo7;X,ZXaX2d>X,0es]8ZGs5Sp`6 %6B%n;9e%^OjWhrWlU\/rE29=$gtR1>-KGej&5)(293Hn'Jn3rJPA+_5P338Pau/o-nue#B0sMW`_E(l*e0Gt;*<QL#+o<j%ApF:% %&eT:V+EUZO)a2H*N+CX?P*MiY$Rcg\V[9Re$ZVj8+1jL/)gUN)eg!P?AFVY1)PX=oNFiPe3]J-:H2tONqkg>1[_CgE?029&UJd-K %f0Cp,b])F^m8<3Nd&^2!4bTE8>*)p(3IlinBS</pkN`kKc8l8=LqD9%qijK(a@t]m9k5Mub=iM7O\Uq+#h$8uOsZ@9mprONYm-&* %;XQSn7f`oROr.B#fd7N5CPBVn$E'1%0N":S#GEAD9/4cN64QtMKdL)t"Fa5I2JGK5<)RHfPDmrQ7-Tq-g'qV,:"]ObO;>A01U7L& %A16Lc0J0d\[s,t(cU7:`a<I5RGZA/\E]En5>(PTalSYX&>BIq`VJOBFR)DqAeE\IWUrF[$3<#O.JbW!63?qU":br/WShmdnm#(5* %XsUsnfo@u]9Y<tG"Ra(c67ZJLcmB\9-;@;f7Q19i_E`%<Z/\Da`6$Yo;R9@G2\C!M<h^gJHq$+k*ThbohPiQu#k-SiQ:NFG<$>TB %-#09^h&P9$Uj-Y0">X2?8Y/Dj6O4tX(tph36oZNc]'H0S(baiQmdY!e'BFEOP#R%uA`aZV=j+lMR[L(\3Mi^l+9I<`N^ecUMIX&' %$[DDTC0Fu^rDC#u?8IelSRgW<?)`hR8fTQO-He%`=_MSs>fTXdKI$QiO?rP^P;O0mSP,nMj@K=d2p"#d3)-f/($fhA85BS`aG:&i %J]G")84+E"h%80`U%XK]M2dbAmYFa>*3kUr+u):%j4"ld/4((_023E>Hsk^Q?;c<\QjX"np(Sk#[knR&nuCCH#*\SrVMf+X(E))H %FbC*1Ilk)Fm@#6;n3%'e*Fn?\>erQ\bJllpdb&>9(l5.-RHs-<$g:"FL_1LIR&@E<9=%LE<C:Z<6(i48S00DXi$_,q*bgE\SRO!h %SOfOr9p'ITLoVu-:1aX#XCsaJBL@mm9cR?SM`;+C8UNSo0N=EO/,(phY&A:c;?6pF3o*'LY\VHCBYq/$afTG+PSqTrFVGGl'Jm9m %clOqnFX:n<ORJ"2h7I-GBr=?uIZj1<n#NUJEYN;"9jJ=;QB'VN^u`q5#p;KFAHQ]j:P=bg-2S`&/+\!QF_*jROog8M*p/sdK,.=P %cC*B),L,7RU='1f!O5IQf3rHtedPI3\rV)Q9?=+uJpAP>Fst`Y'fE>a@2f@:C$XGG4535ggdJfFBtrD1l[-q,eu4)H#o?2lej,Co %GDZ95W.`_tAEnWt]dM_\_e9):]@);,0ddi_W'U;/Y#VJ*Rl1aRHf*I73uX"-M>=STTtkJ-=]0Hj6r]2mMGXRFZZ/<9!sP`B/p]J\ %_A>i&5=IL;6AAo0?/Hd<aSS*[S^OScknRce-&Rq?^W,6j77\+Ar.&kBU0sD<@b95_K8+,%;Maa##qP-t$EE'gnOhk5TkD@0-.Wbd %>T(E*`,F`+W"er1U0q2[ahWd"A0Q2$:3mIFiK_Q/8K)<lXDLjL2bZY+AudF4&aWV?nWA@OJ^Fm7Tk=a#DXL7:`RC)!aNI4pXmj+O %[IuF+Yt9e29o*<\n#r/m32Pr7e?tl]OmLFrs"]as:a$!HY.G(Z]u%S;V&j4]=5.djpbIg9lB?KOQP%\;9H3)emkl["?7_dI,s=Bf %S[m1#lQr-@/344hQ$oY9EC@[[a^2o:7=b`dl&(n>)X4)=<G33nkNEc=+C=7V7pUulnI%]=(N8Poe)#-ZJT2a:/2%$eSD/\sk[>Q+ %^c/,nOfO&:7C[l%$+#?s@`ObDPn`YI\KSM@Opb5?AWEN"021RVPfq;fM3.L:`Q%j4iBskHjSaYb;gV4PP-6rTpD#<=*O!"Vn[QG& %'ETSD(+XQ^^/8![J_=%H>4+p!bL)f\<JV&l+He+qZ&EuH*P;HjO[sS[>SscY!2V-*4Y;V@;*LgVW7XKXLmlCQ.!7E:3*hAc?\PY/ %c(LLT&ZssnQ[N_-f+cOd<uhlM&E?A^_'VEF;#6l_@Ri@^4&M_^'M/d9MCajf6@@goM67V?0#i,gBY;o\gt]r[II'!1)6"L"XKd`/ %M\<,u`VPe8^^_!:Q)-d#Z#)L)"6%AS:!N9/jlseM0+sp^@':H%S:LrSinXW':j=So8P]6:')rg#[F1tZmqABJQmi2n]AtB3(q`mi %NT6.<"VO3Z:=2pd^hQDf^lfD[gj>@^fL3a&W*qhejMNnt*N6Wj.(j&%RYWP-Qf40M'MfCAUlEDqK?$s-1a*m'H<qUr,kF$rpH99q %@q!=GL$^puR;.N:TbUa?(LSE,/%'eFcH1m2X73[4Z`o0hV/VrjV'FQ*C7:"Oc8?tjN#,I98YQ_t=H4"u?^-Mb_Lt2t)CCVJGDSg" %8HCE$SQ&Pa.#6lG=BhL";dou%g83hn$RJ;kN+"^KZRsPDK"\*2#,e6$X*oa53RhDMr:*#UI[!/_d06;P_Im/0Dh>Z3+Wj3V-p'?* %!RYXN0di#QRYW.l*i),d9-F&_2Pc<>D:,DI#WC'6_*DQG-9?FR%cs'N6:.P./P(KC.#AZ[%4N[qT4=i*QAD!s5\8J4CP^1Ahe!a( %(tI;4`5lkrG$HC0O7Lp<q3T4+&;kuS)-7=dQK6tj6j=LO4]Xb![M)5l@aUPV6_[1s_VM!khf>R%#(so^%Ok/RB(CGuh*s6`#o1A` %N\:o:%MJ-Tej;ALRZjBiqPT::.8B&,cC#0]@hroD>Vj$CjT?o.PS5FaF%.N09W:*M.cQ9[Lsc.=gbl9j/uT%J:q[U>KV]Gs;Fm9= %@%eA@HHOr2"4D]b8djqOj,A[mZZXKZGl[2]=HFrF?uQB3f`QASD@W,kCKg5[BqEa;Lg`nSIqgsO\V8:tQ.pJ\4FsAR[Zr@B`l9Nm %jl'GRo/5XL.`94d.mUN>4(R*do+MeVC3a3-U,6%+p/S,Fj44(8@Pq0CbQkS9L5:K6`eGrhq+Y0r;UTi<Z8u;Ajp(G-@;'LVLR%0k %Zb@5(2TS(>&#*rX2Z<A\^<sa"V.CdNRu?^`Tbq12N<.!5E?3ge6u>'JJn!=u?I*0q7(3:IFCGrt6pg>dn\'o&`8*t?-I<Yt*7epe %9VEJ%"Tb^-W>T^#?4D/=W@`_a]l56P!89f=]$N5nW\?cEM/M^,Cdpe\4")QEa'pE^M\iCO#`Dqlh;sKbo3"DS_+8fKE\#*p7He^6 %#nJG<#S?EQ$._n_,1qh0A*f.K_?4n8BBS1)Yr/=>`ohP[QcR,?`&<=@Wh=?DARa!r7&COIJ>X?0H88^-B/GJoG4E*qV-FVGLdrA- %>]/1u!^Xa`IOpL96j&lOLn*3g`]B>9/RJ4spsP(\T1Eam*,6d:LG9=YJf`kri$0mRkds/ja:MuX@RE,8Wp1m?#Uon(5N:]dL-$2f %<E48HEYOYd;h&u6r>h6-HUh9hcV@,@E':'FN)M_3"G:IrZJ][*f+EXuU`X#CR"\S$3N\F@9BI)F=J"k;e#K7HlF&1`#^dMWS^b'l %BH:SeeI2M^+/?9ON#5r1o1b!R*J;?0&gAN?"3LJ7!?*A''hcLi20QdC"Kk$ESt\.88i._RE^U'\pO:Of"gM/JP3!W!H<)$:*@tGH %o%FetU&loG1j1b8SW/@`Eh37r)P8B6`BNTlj_0kF'kdY+10ph3A/B,V"Tta8BIoRA8WK^m3a6">YhULTJA^V>0KXra!]a^fq<X<! %CgNQ:$"f;6q\kb(-'QPL-Kus5]9E;G_AQ(X'`2JH,+]X[$h-M@aJHJL`D10:#"UOUhl\@t=](-oF*s_f9a['g:`1X.95Khb2Pi_R %P6pdI-_4HYW"C4ooSNfiBT)CmUaesKPS6D!>ADm/Kq9!iR\u+%RIJ0jP'%?/1i,2aW#CFYAU-K.Ek6\k8lR@rM*0X@Td?QJ^03#% %eh_UH**F121uVVo`U`eej-Z2Z0e-SJW.+2)'Tsr/ZR[eVD1#8@+[:FWPQiEjdXW-R.$9>1?QD;[6;nlq&^GJUd#0X3ed3t_W_bu9 %Q*tIr_A!Ll_,6oF5sgiuD7AV=+r2#X)lbk,Kp%Ja&=8RF8T?$,3iIM'gC[]uR>"+YU(sIq*<G;WL=de_&VHgg;'Q2j78n$!#W&&I %IdF@sMsr56(lYhsBS@f!7G0I;_ehAaU1[m#k$6$TKOo&^]53r^d<2ZiQe#Y]`n2.HPjqoNc@rpsYV')VMN1eR\m3;Y!#EBCD&JZl %>5qD)(YP64Z[nN.I7KDUF;2>e?]W0dCR"T;3Z$/MW_&@J1FU<^lH+^LNQ"pM\:f7SN_uJh-uqASBA>I89FPqS-cuK[%%6(Z\W,Ve %NtFbUa?7:qKY&MI;I'C842r`ta5ul$2)3SPL.NQJ]8:j#PU8-JYg@ED$^7Z.e5=:9BfL/[ZZ[2]`RZ#mlt1f68NKLD3jUTE-#;XV %h@d3l$lnB)/M@Z<3kNe$-&*.L7P`jUi!3_oA8B%-68urN4?$]a7Q36Id\MtV'57Q_D),YlAI8ecgR"R+'!hjV-"_XWOR,D]&)j(G %f/<&W$4]Es`IS/E;We_>cjM[D8Mf1+m&.sh8aqNkJJ<5="tNA<N`$*]Sg@pnobjCS!Ch*bH%AiuFB"Ai2<t7VILaiPoo(h:h.2!j %j0).l=@9@4MA8M^F)t.09Z/q]D@V,A04LZd.&a>mb\KSHWPTe.5Z/R`#+(NSj"OsG>0%pBUJ995i(CE249l#s0Opu]N\e`@Hj5bS %#;5OK*W7h66IRpN(E.g\Nm^BEU.>^.-la8rIe8e"f-c>JFV+tS<+1mDD=qj+Ka$0/^)+<hFjWjt,^&0I5d>t&,?>>:+:cZH&4Rg7 %r`K&NAaD]Ja_\qL%3#aY3uOn<J/]k@jMSPLJIo'M-7OQnNhq@?SrDfa25K#Xn&/)'=RNH./^-!gfQ&,hrSg:814C8F&d.e`ip^V@ %>>F+5jNWJn&dY:ph[ed]X/h.R1q)KFdM'D&NF9n<B!,5)Sup4N&VXCMBGK`fi6KOSAIArFKmJQc[N@HXF]&"r0Nc%+!N$2mS]M<d %`=Z=nf<lN$)K72a!\IAkMO6r1l_8$LMItCl(N5*\jX'pW3CE9;&rEnf-$K&E,695+'.gL2n^K:]6#d>S[PburK2a_;$G6[jNAqWW %7_`$u^"i<X5O'.,La#pQ6d5psbJK`)p0!Jc8=)d)@dIH"CHIZI!YLJ486P/3_HN$]WM4p17A??dR-Zis<+X6a=qoDp@:^OYDqISd %KT_u\4eX,^"*RS0O<WY\HOY[<eO%&\A_Af@3^m]a:7r&p5V+(mH7;^MG9'W6;K#SePRW7c+*5h;6'mCk.:jbLJ\W"hfUce\-7j1' %R7YSciY;(:cB8C#amk?M0W/qccBO<IR0V=e*T8>M\V]5Hc(^-9Iq1-lKk1*1+s(me_M`!*!AZ's\uoI8*/>DGf7`m6(0kSfBX_K* %gieLRO8e3k)]7HeG-/SIa"g?&;pPcHmRc3PFkr9a%s:$Z-+,CtrG>+XAZt..`(aL_NN(e(Guf,9C'"o_n^t+r+!#R%"KEg;LsR+c %X>2#[R^)WX(4g=qe7_<r$2+p!SYtrOXiLr1&ZXY:Oh=MY]i\QO8CPmA<t%hQ`I-m<5o;s?V!o?UPppf#AD_%#:+RZFJI4Qtbb]*] %aX-6rI.l024iVO9lk"o%6jTrcO9D%2JPbU=:>%chd^,!d8[C?JL1m&\LlI-T1icK-Z_;fc#:1/fMFq<--H)l1@Waf!1uMIa4:E!/ %7R5jQ%FujmE=RdM<@'LQY.9Aa^4HCKVDOdNF@1>fD(?D8o1![D_[;.<N]cVWW_H#HDI`r=hW8Wce@)l3QF?+#N)%M\DN))7be>Ml %"'g"8lXG^$98;MLTk7kmCRhCqSS]q"nB_fA*GP$ajk\"\R85TKk[pArgk;GZ4#-K;ChX-f8Ms.!jUN(*f5ee9_=NioYq\9q7pp;d %.$lj,D2WUi\iF?Wba%*la5(!iR/QF-kbMj@5Goj6DWq#V]'eeEE-!#(HmMQ%.25j-f9fiP+bqmEp;BaCnsZs=1;)r%]<LjNcK^Bb %Na=;<F+'>%B`<%Ig3<TTG0"3e.9_PT9O0Wc=`&pV1Fgrr%tgD+5]M`LfkEgI9JN]hks?pF`["6%bU,$XD(K#@U,'#2KK:UZ1ebC! %%Z;1$>9cAM5=<Ft?^8ZB_rUYkl6<:FO=eZ,A&C/I\Q)BGE5ZP#$4*b!Hj[to;hH7J+YcU1b-Jhik&q6V=j]uBZ?r959h%qF,eu)X %5'^A+\"gqJ7NWKQYG^St/3=gH:c;?1KnYQ`\sA2TiKCE$84I`%`9]5+cFS"hfs37C&BHY_Kj/Q`"jE]dm#kZ[Qk^uT)7X!rb_fON %MUd_<P/%1)AgX[M6n?YQR5H*I]pKV*#4NZLfd>3mXH[&/D0/>l)*W^i2S.t</i*iJi>ar$#]*_)d7k&D"H@5-.[(SCi[7['8%CI& %il#duB%t628l-"Cdi_8']`Sq(FWFtPh7OK*P-Q'%-8D7!mF,*g\\fGD9Hf/97Qn?#O)4__gCO$oZ3-BV-SKbX7'_(Y,6N5-PIJ&> %*Fp0WFs31Ppk1UJg(;\eY^KQ/1$6?ENu4?C":0_rpO$u$<REebIa!3Xh*%oE7!^b-<$RU"_CT_<PPGFOd&N"/cqt1K&Vtgs\7).s %o702_UMe9^lMJF`iD(5Go0;!uU)T8*"mYt,M_</Y`!8=4QA_G;d"!#nRH?GBSlh.<!i,#"6n_iAQNW!^`UGLGTY3Kkd"Y7/Z]!'" %6GEI]5"WT17#1,U)W=&Y0OVJ:%bY6p=n5Q!3=_DLJ3sXAnU%54EBsMB4G<f=*E.cG=@3BKrF:>^_"3Q+5N\j;BXuM9QI4P6K1IGt %d,^1Q$_9_#6fT1`6T(R^4[j<T2_UD!C4u>;(s'M1[-+\=Vua*\!8N)PON@XP!XaZ)>Fu->M@,Zd+\3L]A347\VI4CQRCY^qHX%S. %;N/(=c*2dDs3QliS&H_K*+_Yt_iY[JdLi7M,#^fL/cO3DlV:DFq'HZ1'EUou(fA@Zn^7m$r9363qY1'X1Mh(iOU7$SS%M:'9Xr7c %$M6_:KI02jL#b;]2\.tsQ1]^aQND78't5iT<om85*ER82BeG<',0Y%(lC_Qagjk?l>['Wj1r#V4a.?r7rEuiA1,6Z]Q5_Q45m_7p %"$7T>Fp:(uq=4s<R<W,49<UeIPA;K7c[8/Yf3tjGF#nOSJ[$LgMe0=K`_08Z<mIDYeaRsGg!_6BN[,:R'9k0!G\Xf*7I`XW31%0* %XKuRqc6Ip<:E(;EC.DASC^r$E7LWZs7-8a!"ptF30!NuZ;MU@0SW856qha&UnJ3a_6&tM@&JJ8GYM52mD]Z4hY(W8&69F,i88M!T %?&BXaN&ZBj)3$=ZQ;</+*-RCG0=:N"I^QmB?8R;]WUJ%?c/(j4CmR%2HDk"^H;b&N-q<kH97b<J&G\.a7J#"Ef\QqJZu&uF,t;B2 %,_MI.\YP"HJ8DPpd8`3t6]V@jSu[/@ghoCp$X,q2Y6FmkCcX#m/],o2><Z>q?/DcjKeQDr:K>)icS++W&^t::2oHMRYh2gj!%;1` %=k)]1.=Vt7Zo.A%N&</U)`'+#`ilIh@c[I)PK72n3I5,SHs^i\Ad.h)Mq'Tn5;^Flk]Z,Kb[lilC7+fojKBO8XC+jMS+KF>ZGZ8Z %7@LFU752XihSm(I86"'0=W5Qh%D2D.6n_<P6oA#.!(>l\<rY5'N'b3>_e;@KHD6IVlLFY*#`U[c7[#-U71kaG<$Z:!BSoQ?_E+XZ %h.KOG=Q0FfbQHL4;.$8Q.*>G$8Pli13g'LO)rRJI4THkHn5+-SV3Sbu2q1)[_m-3f<5VqcD2*Y%a9bjdX&kWE=?'*X'sUUOBSfdm %REJq&i!G>fXI"V*iJER??6I7sZ6NL;N!AO&r4te<0oLWsB8i`FP>'VG$U^#%*UQ#OD7m8l=9B3@#CTl%$#>W5`BrnhaHZ`+)P\fP %,oq?k>AA,EJZOPEF`?B2"8er]_/Sqa7(jp:GB(FD>J+X,SN]Osd,hZO<J?:XJFLji"IG(-1ur=7XPc`.M.*>aA'&bDW9?=*B`1oe %N3<2P-%Z[h+W2##3K0pi];uQqZY32DH)rF#[%dE.0S27kU\YS\V+L15:K!=;r%8IZD\mGmUsogG"PHdlAAcX"GPEAL2Q,G!+%u6c %)A=gD%?9.X6qiGPDbJZ<*1dS+i`Qra]p]>f%+.q`NiFW^2j=;8DX8Z!DNC"l]]Z'kP\7O)-s?"P-i9T>:f-pAe^&uT0=#mq5=Go_ %d9(..*sZ^:JI::E='rF),t#Wq77:Vp6(aC7Sg)KL.B&JEW23g^.$u"`MBkU5&OT:u?1&`$JQVMV+^>#5'Pd[idT;+]>9Gi@%a$Jq %:tI!M=KV2[WsXg(`.9LM<=<0H3='mtN(O[a$!.^KGa"6TU;):3?4_9&G%sbH_Ai_g%%mI-?RYoF\l*e>P9%7TN0Hi+;)6Ot?1QJ' %Lb0+b'0D&63&%pn40eKEjDZA0WKG-W1qKbd^lZ[C_&4isPVj]NcQ[g;T"A$j1r'='j@(UlH*l"09L'H4:e'cO'79)A[F]/@l^5&W %Uc&QK@q.9;,.MSHE28&@&VT;i;r^+t\S7X>VTB>*`^P\$+:CJ%9JdJR.ijjn\u>DM?qS:,.>BFRjMlk:Ad4`FVV*<n@:4(c%Qm]g %JkBE0,]6GsiM\0b(MaR^g<rCo]rkVi6bX-'WT;1T#3>$lYm4.]7FmG!7cb2*'(U]'AM`H&<'_g6cVm*8^ea_loHWBX25W,t[n;r/ %KVE"P$[h;Te3M#nA1Tm#",e'E09VecjlYSR)q5-"1+1KZ'i>[I=<sQB\1iZ23]t9*)*3OJck7BE*HW.YC,ci76fVV7oo@j1nQ'5> %U?#KP#7>'lP?U0b&kP>e,DdZ!]Xj%V*em3B(df.'6Qlm7X^FP-r6#k7@BBit4q_.HCsXpag]Y7HU7teQ";`ku`#,&J>?=85'1iIJ %f7[Xj4Un<D"AMhA;P58Q1(<j>W[e`(.ZQu@MDb<aYG&048Sl'f,\+W(FX"G3?m]h:l2YZ-Ztdfj;%`1L>sV6fVEcQr%;[2J'"sRi %la[q2;Za@ME@<EQB<W8(>3+Em9,_[?ZmV,`'EpV,'R!YSICt(ts+S=fgZ0n81.CcMbZpPTa/5OZY9-B,:ia!UF$^:B'T5XiPP1-f %$HZ@c,jM)-]-oNI34*D<P&;nZ]L_BBPYJJ\/KJL9e53>!W/YpgJZlY+$52UGl:B?/Ehs//nNdqi+BP^B\AqDdmZCq$m6I25;,OBa %3QhdjAuhc;.)!a@)D?nuW47il%?8V7,nqtie`82Jd8Fe32:._CZ$6AU=.c\<[P?WG,QWl^>aUMfe4?](6F"0mnNI1R%T;I2$ACJi %X(A"k:r[Pl4CLj((=nV1#n'@A;&pE5qXcb'W4"?fQe=[L;$.MsIu5'S79UBC&.,G`,7/6N0B-3MaC6kP/%L;mF^D5\W>!-9*_W=J %k[GM$)<%"!?.>,m!e$'+NV8Wb6D3CEh'JdlcL-5X8I<KY$"m"R1(J3E6\&$k"GI=BTg(7Bei.U<.H2jN*[80@CL8'm#A(hk^nDGr %Z8"dr_o'REJ/V/Rg*U<idVgHdW(DdnoS6[?/_fE9DeKI*,tj$pL"kQ\LpIafY\jbP6)irpH6_h$5iQKeQrOeh1bcC68+*YsQ<=8o %>%h99OgZ^;MFo;<4cR^QCqU4gZsbDX[RqoLl%8Y75B=sXi4(M?6IUHP87Hj.D%*MjL)#O0U@,?B*`lklR66D9&5jQl^-de^:J!*a %K4W9-Lr;X&I1\4j6D8MA6orFRX0dDO[`#408JH-CajNeH'H@DuMrg+_\Ai.gknAI,P"=Tl#rA<1Z4WSi\6N%^K95[R$&UH08>I.I %p>Vr4kaJ"^(oWmTqZ.'3FMPgqDh(J_!B^tHDq,Xf!7-OY\4AB[al4496;;h`H8_M*#]ku#\,%4_`%;<,l`88qTRqC;61?Kq\grAV %,SP2KUNEh_&kdIFBp7-d`FFH9=^1#6Ko;0bTCn1t[,ia?j_4'e6j_G4Ok1eg.Pg^C5qLX^j:"DmD8d,5?3q5Jl=VEKce-QC8e-)= %_AO+eZU-,Y$0d#/.5XU^,l@s;[A$;?C.aSg.qDFuWD1Oo1!`Fae(H`._AAb(7mhJF3>'FQKE81VP]B1O8a7625Wh5!gm-ro7m>$m %%jt`16tH&p-PjH^<FEe3#SkGG0_A&OF0Y"(P][fj6r$.:r>h:i]3[%sM.Ef1<Q(hPiC52sU\"t^!`tcs>GE9%Ni-LAT(0Zc9oL<j %EWZcWWj[bK$:K=8RjRh5MT.b9>/F!mJQ'QVZ63%C$@:#R@Pk)m/AeuC#M2E9fddDp9<PJGi.*)0adU@9/Rapc'[EZDcsB_jBLmq) %aZWt7*Cna,8ahZu+XY(iTl/;bUNAG:1pqtsTT5!:1nk?6'm/!uVX<\LL<^`2o8Z@jFUCL\q(RnM0Hq08c-R8r6FG]@F:K=N=fd57 %VQ%OGRl8_o=-e,)P")G((adF@-Hj2ZK61Xmj('(rA/P,UF=^cCf_I#*+uQjMJJFq*_b[6$Y0[4rQ%/uhOR,f]!Ja.FmY`e<^*d&T %4I4h87A*'-)T0VIE4IACEg!Xo^'NMB8Q:AS.#Pi5gqSS7O].1?KrcPB3?=r<ZU\AJa&*:*E?W70P&):U_KCYkTLF>UqON_-6:o.2 %DUo[4GE%X5XIda=j>SOdPG#,(-3DHS"A-PW-JO/H,D@\$#+g-G-r7?T2t3%>[:6FQGC;C*j:0:0cu:J9<%8o1o4(mm,l@nZl&/\u %f[XR@7G*2I;hU;[ChX[/-m2Z%S7[nEk+E$F=bIf'e=UEa:5hAS_n]dtZ'679*+Su*%t*pT_ZqLm=0+-d:roI6Zsm(];^#j%$YJD> %L7!^3H*LskOGbnMAWk%[9D51q(UF&C._$d*(/eK4WZYjkLNJG@_t6P\9jPIEc!DUN-"7QaF"]P)@`D1r$pqZPH5sU\M79E,@?M$c %`3T3%<lbp<4^Jd!82?c=QinUiY:ltAL'-AGHF%uC$&m^lc,c2s1s&7tJP9cMVVEIb7`.qkUh+"=1r=G^WFAE.+<kbT&:HNP&UZN2 %JLh,Y:m9jql4;^P@QDp88<p7c]VU@#,mCno>(mig5lBtYKHUm@#[dX4H"s0bkTdK4Xd/%$B\$/JZtJV\RrtBeqBK3SR\<l$d_Q]X %k<cMp[TU3mK?MgLB5*@31sCsK-0j\&X`]AI>A'.MU'H!G[U"m&M@'Y_=D!?OO*^@qDD/0S#U:pj0&mQg!2H;3q`.QuJ'WrC9WgG. %EE2d)`l[#='fft:jN.1+`)6.D?Y+sHE3CZ+ZRc/7H>nW;5c1ADP>sp^d]LWG+[^sb+l+mgc5EYH9Jn_h3E,15V&aL*UN6N?3qjE4 %q$'9:+X)'<-Eg5\%@[9BZ$HY22iEAm?NSJc&Xad7PYN>2,[k-r)S(a#_<)`Ba2kgrCM5aV@S*u(@:CVr?K=aO\hK3o`M'*81<R$N %b&&7-5(^.PSut/./>3@IR\fD_r0akd-9;&cdp\!\^P.-06'kD%(h@>e6A`nOF$N(och@O$=es_P0q<4"n=ktlib>7#!-B9AdRcRr %^_FhU39E>^$-OT^btou=An=]fNlnCZ)+XBZ5"M)>Af=re)//S+Hk?OFd=;Qtd6ZG%Oq.9Q8td7b&mgfc[jip]bL$$UbRpV+RC54$ %rim[l%Z=VP+q@(PR@*F[:f<HgH&59G@X/o&VqBHAh\KuQW\=b.8C=e8]85]:,`>s7oHVIC#ko$\J?Anidp6Tc/NqK:SQqAiZLhPY %9W$Al9>?dhMrW!E#1LKR]-1*Fb"YIe3m*'4)O"\d0_'i'8FBiJd)T',mL6FI)02U6I?Q[?;E;X>5L[h@_^0i&aE/QGE](pY9@-=3 %V@u>']0hm""HObUOWr99,/ZR]KIh"]k/_ZAaDql$8O/S/8Z(fFPF%06OR:KEjSj2&WHR8PPNc,3jaq!:&2stDa34X/-R&cPEg>(+ %S-kM+U0-g#3@mB0#"e`"e9o='kj*$Z1MVN%-$"9kD3G^^U:V;Cb4&H(OIoYIa<@GiiBkRt>sK$94VAE9('rp%+_egaI$#jm\5Wn2 %C8i^@`Au56Mpt-P><!mZeibtCh&l27&*4-eF<V?5?OY*'HPnEPdhts#cAUn>.](O60-F\6&8Eh(FLu'T(E2nB"$S6(pe5a^/@coE %>.>k9;L9&o$KKp%np7`(PWP<U/_)lHg#QfjddF(TmjOlXhe9"!Sc;9@96PY!"MB2Vj(Sgg_fe).4H&oqT=^2;?@3I-4ukAu/M-%Q %r+D78;$\8l)]noiFf\qG4n$QijL=;g+RN%HPDAT(a4m6@T:>k+9BpT!a)YIX\'4bkX,!5DR0=^S'?hC*a=Vu57ZHnto_4BCn'-XX %`WMABs1IE>a8C4*hg+hSdBo"L_%9<C8.("Rn=>'L6M\o2Zp;>5nLN]/;SY&TR?686ct3T?6Etdo]I!&Q1iMWQq00]"nbg#_HRF:Z %c!S$f.kG:o%AYRVo7fMsL1Q[$d,=@r14Ru?"W^5P/76!HmQ25d\81%dr*:XV."QD`g9G/hJ.+(t$O4gK(p=0*!uJ=l]mqY<Gjhql %.m"NK>/'47jbm0s^%hRAM]]S:^.TNq0DpJiGQ`0W-"*(s\R=)'CllHVL2hC`0k^ku#gOFpQ5K_o!!2Z;]h9DQ\`BkCQThuql!sH> %?*jCQ[J/SSp]G`BUG)NIIR52?H=YRSL[QNs("0]#9YfBc`p3UY%2uSX.g9lH:k1>-$NP2pi`-qJgrY'H#jWSFCZ@e*3Zh\:l)btq %+6hGSBLg[LbI\k6DqALB[m%BNb9J%sBZ!3\eiei)k#UC8-p\3b65M=u!$_mS`WH=TUE3-B!1e#11ha*kYTmNo!MWR7!XiBMoKG,T %>6kc?_9+@=fA>nr^"[s_KthLoY^T$NrZ:uT^d!Ho/%io(^sd/2])c#cFP4ZhQ`VW++2)SAoEB;\pRM\#,VUJj33rT==h$;%LjKNu %m9$mpmR=?FDdBmV&WC+Kg"r*"OYe2P!-1lBiLY;S]fS:Dh7;e,?(4p`hQh1JQBb6^=[c]qp[69Vi=XQ?8Dt;.f3WO-[H?oFgi?NV %c#;tL0Q[!E$!VQ6Z:-In0IdoGRonBpR1()eguA01]8o40XT?TJp]IQ!PDnG$+]rDH#`sBM&/[2iZ#s&Bf;cO?X7g\n[t!.\IF`fO %m+(Sg8DaO#lFq-0_5"\LX.]%/9e3\k]JngRV6<\<$GaO.Xab:-i!Ed$9Ju1$Keirf%38+Sm'Yp`g2^=RfFb>u!#fqab641:@t89+ %E1Y^n'#rVZ]ug<V+<5Fi5O@6V`4`qC]Dni0^p2D`W/'JiCkT(&CDBMH/FJNmpMTH<0@(8Yi?&%TbTU@"i$p9%Cj^l3l##'"J.$&X %!'44AfP@_=#dgFh'/ja*<J0^IbJ7r_6F[/s!sm1e(c.*j`]k"sE'/C7Gkg3RnA1;#IL#,\s+YQmdn]t\]=`a-#Z2J!iFgKf<D_O> %JA[gnb:NreKu!a`"1m;8J.9+$?@`oDMc`a$_0!M""41GB!GGblORD.Q"#b&SGRm.H#hEW3B`/(cn_aG&j])0)C%uRqkY17L5G<Id %!/(M=m+`-?p3,<uWt.1o$UMCk6,R;CdKkU/bak=!\nb@If`>gij:l8/XMRX3`9!JDb6Og[0GE"ITS#hr<O:9_oaBBp7Y;lS8738g %<*6X2K'j>j[H!se4!&h`^,tims$!dL@434V+$)^2#H3R-FWmaC[0$CH3`o<GDa\F9I\$ZjLKT=:&).5q+WS!_B4_4<_,#:f?AEt' %aNC>E9X[.5!MBHu9L&S0bm#p"cAW!00Z<&t!"gW6NWCu`dFt^WI1#EurA4s=FF^iN%g.IqcmGCje:[i&$GeV'4pSM,YY7_]B*9?= %(EcO>VP"Ng.j4fk*Lp&_.PaTQV;L+?=]4Q6=:4@"3-gh*1sdCXH8si2gAig,6*i7T1iM"M1^3)hOJ"D.%MJp0#joOJ_DVNH#8@\D %r+8:L#(Ur2!<NF8$?dM-4ZJ(ER-`O[bJ\Lo8NMg4N[AR7TrTg-M,8@>J!$r<&&QCrqu?o5cK(+Jq\:j1+g_52%UKB>7l6lE%0(k/ %TH#GsCr;P>2@0\(HRD6#_"e2MAIG1DBF:+6QsT.2\dtYY(?c;M?2t6F!`1RAR!`3AhNa&)N+5P&@+?+C@,u%c?nZkKbVB+7/A\qp %!VS9B%O8b,,"dBdcmd0d:iE#f^cT@<@@T%*#(CDm!.fg?!<El=)M+bn`o(5+E"Md)nA9/dYSpSoq6$)=m0UWd-ETrin@WgCdp&ls %>6#HNA9[Fs%0/^J-Zp6C(BFpcJ9%#?+JcdR_FXbQKQ/W55B$O;!JEq8.@;iW2cr9!'I!0#";!!92I&WMLPH3EiSh=CaOZ3[M6XXQ %%Xn,9%m,;i([en^QmHeq:Tr^!\eQJO$ss#(2us;%6=jO\kU7\Vq'_a:J/ndN_olEf0Q/Z:4KITM"*gLNO/G]a/QSYX&YZIW=Du0r %3k]C>G8bp(Q6(=+9e1KB,^WA6:"[+o&ae8W$;_Y$6=:Va5O1*+>ZhR[bT?*PVAN"i)Z[g7^cK"KUtJTlZfs-khG)(4o$MtmR@ZKp %D4j=nj+aM]TE5BpTaP8@q5f>jk]HsZaT-3%!!<B9M'6b(Qtg0+n-U<4SN>,R-_YJ=R0(ETcW9l4Z5W3MZ&qN'Q9VN7*qTr3!pTmR %$YMWXbO0/8R;$:;&*V"Te3/Tm)=U^3"Q-Y+9HF(ZK>>=,1fkj2*t`F*GVE[G/7Cqn#Z@hSgP#cfaVq6$oZ.%'=V#oZR[GicD#n=P %k4rQOB_b]p"c(]fNr-!?:;g+c%o*$)rS0n^$#0'o-%J3gjQ>6C_SF6/"7kgi%/A&j+Fntc1M(0q"jg(C^>nk7=[pTDMV-sS]/M*) %8tQLRd,ZicSQ>KsE]BY`krPt'`biR,mF`tj;6R8pco#/k#XDp4*hN`p1Goniefl%8CV_%]8G:L5Yt$`JO&?1P"?b6Wi/nNQEc0kB %q(bK:%6)QHP.):"XgY;Uj/QPf@-nFa6IW@VJA<<mFO-*bm4gEGSqD"/pNF_cmpPGKQKCN_g`m?$fe^;>d7WqoE%mTUBDJ9q*4UQ^ %Y"lKP%?.uPo@P_S$(r^($6O#PR:ui__^gG)JOs>]5CHWYF=F68d)#Kkn1o$q+3>Ob^Ln7`F7A!Sh\;$(Iul9\FK)`RmN"Q'RK8qI %R:uu#n=n+":$+-VM,l;N+DSY(8cWp?jr$41,rPJ,T%f[gQ->R:4dGjNN-pVZMZupdlM0;OR)+CW(PiK)-l>3XAnD0RMV3`-TJ^DH %\S-%cij/W8"l]W*c9/mVL2PV\:XtLjoDA/tq*)2*J+AJh&f?nl&2T@p.@mK_^&l^:nn?'I,VlZW1BfI\>lnaLV^aC<cn]V[F<$[M %8&oVd(nXglbi%7RiZ]"oBDB=\+JEDU*#[AQ_XPA/"#e/&F#R?$fA(l="%5RjMP>27`!c#@\aV3TAd5K(R:4a,4$36RT.j5lYCZKS %9Z,DK+`q<.@<)?;+ZOMlb.cUrbS'D!E:j3i!o!Y+I7n!nZN?5,oI@.KK`W.M**?a6^*Y+001+*L+Qr(kh#5fFAi"=Sa=p87*\fSZ %"+Xe[7_ou4Le(#PkW(U)!*LYtZ"*m>l`^g!).4&g+'T5](X]&uBR#-!+^Va60Ugh,Hfe[=5pf3]W93N_$HVIT!YB;Wn.R\i:j?BV %@230%g-5i"U/Kmf6qC`*!ZF0n;Dm+Yp=d-0SJJ1krJef.J,/N$q3PILPD.:YF6hoI&%3V]#kJJ2SQh)Zhg7GHfks<1T*CD=U'hd1 %$45ggb88!'!Aap]0UP#5$3>ZB^_o?AlD6,2\)2]h?]IZ.r4k%Q]FgG2J0#^BE&@.jK_^E#i8U.,#l)VG$F_T3)VsloSel@8#&4>n %W"BXtpGIJ.'I^4+HT#5ZSXN0HqKuW95nq!K%LA^3E,rX7jjO#s4d";M9qgsV"&Q6:L"dla#>tXdgZ&h"$.hind>Xnt-jR^B[!qJY %&RWu-fI/N2cO,R^.+8A5C?=B(=9dslPQC!#Cqp2l>/D]g9X%Jf9j59E`K8Q.Hn=PO<Ht!52r]atR>X<%&oU>)-]I$3<J$jE#&VB+ %l*8_Dn9#=O-c2Z6N%g#mO"T=U6ff?S0lPp8<J7:ZI2%JbW^.^O*U"tT^,m,bIPr^^S"Z<t&RhD7gk@GfAe6BCj.s@WV'kLjq:g2T %^8=V<+*rLPTL\5?Od/RJ%&CjK0SL:S/HBo*(G3Ei+'Q9\[=i'&Yse9R2uO,t4G7k`9;(2>g9<qX+$eCd1Q8EPL1Xk$Zdf(\:uJfm %iQ@Y]KpK7W1n2$k+nQ/U:MWPM-@cOZZ4Xr_['*$RNP&+qmVXIV4Y<8N(8qsu;o=u)a;Bi@PYp+.s3:k*k)%L>Ho9?A+`s+P^*R?G %<bDtg/&(WES$G.m@?3>NJ?<3q"SPlGVuB?j>rsacn^"Sh]m7G1+1*s7][mJ;\'4#9YJUhJgl]FZc(^%Vk.t[or\:JI[#+VMk:]rI %E7(E!M\e$MZuA<`P'/0H/7,u"l(*#MlWAW1h01O@\81><3&IOIl])`TgqD^=Q)dqMnBbA]H/u(<5B,LC*PbsfBIfL.q$SsIGVo0i %qTd>kgMGX0g9g:1eLU&m1r$#hL-]?-Z),WaK6ZRNhS)?INZ?cf-eQ$(JJCfo2@KuITf,RPpTD04Z&'iS%idcViq/ENo#6aS7PEqs %m,)Z^?/;cqITUg<>Hhe_S]d=g5s2S&Z\d)7k9o-[*WPd/rn0BinU9:t/Y(J,ooXTe/k@pDa8CWam^dc,r=;&S>DlEg3F8*+`&liO %mXP0[msjRh+8Lap?[g=Zf*_Jm])1o!3%mFlKhIc9H>(RC0&)G+.LmO@3-k@*7MA#VnXog1Vgn^'s3bOEqof$.CEIr/p>hf>%s0?p %2)T<gP3&_dgZ7eXGBi$[9gu$ZS\3P/`%V/5YC?Jcr;(pAbqK'Ws7+urrNi^+k][L/F[*NdEAI!,bZf2@WlMPc5C!%XO`HGYih+!O %?iHPhA2Ni2^\d-mp%s7.7t:*Es5X^*oGaFunK/T.@R"mW\u>j+mXAiup7iEShsp[6r)Z,R5%rn&5OmIRA2WnTJ+hF-pri^/=+C0- %J,L15oNT*$Z$23Ko,bMVao#+:GHP32*kXK."$c_+:O_ll_GpHUJ,J)Ob&$'U^\5(=J)_JtpNM,]NPG:q0E'U#^\dhj_4#^L:!HnP %m/Du+:KN#'"/#A4YC-<WeA@ROkO2t>n]eiKqnN.9r-\*O?i=@3j_+S;jQZI0PppO:\#A>\Xh>PNT-+'N0E:leIJNVV.fSe\Z^^a) %o_HOWr4i:$NPGDi?iTbFY+==Xrk:Hg;g6GiI.pjS*PD$X0E8Xks3`"ffjEZ:r9`+MT%SdGTW.t_#QOJ[hu=]5p2mIOCS>HWro1O3 %EVc=)_2nML0E0p;r6<iuKiUp8cTh?`?iAAjrqi&]Btef_"3V+56;oBUFcVNqo-aRun,2G-I,jZi$X$1L:&XaWI.<OeoR4]mY(mW0 %Q);_(iho!7V*G"62lCI8Jaf.Yo=oePZQK!U,DWD1/oPE<T_trgr7[M;r+gf><_Lfhhu;<trl:)5Gbs:hi@$VWQo@jXVS;p"G+8@* %YPn9`554Ss;*O,+]#'Psff&NR0E9`RIVAYhT1dOZQ;)f+X8hcUII^`G#K%7ecaKgfpq8"rT3YB`kW[au1=1GM9kC*sCn&R4pXqE8 %d/D>""Pm_FeDL8Ymh!(.8Fe=$6?N7XNrqsKU&42G!d&onA\`ZZqO@?HQTtN!miF]Ug,ZKVMK[:[WhjpbXIEt]3O<NOCZipQWTK`r %<0WkeQ\n+.Y]KeJ_p0t>R;':)&^u/9kPXidJ*G"gG<!!Ob_br]?i=7iEU_aukOZs%s4&3@nWuK<".'O9H['hI.Hfo[(I.cLhtj+_ %p_u2Rg\H6aDu][7?hqrRr9t5U*.ft:Fq1+hO'%0-^AjJEr5P*&kYM6VX6k?7r(m@^GJEY9?M`MO#IgOu>."4dY5S1bHI$B!rJf_2 %h(O2e^!E$okDR+S++F&V^@U%V>mT@/b'lIWC!W!N(LMLU1S=Wrci%$oT?mK$B0Z"A#CiuSjR*]m3H*k^pT4i"$eJ^4cRU+9peQ=4 %^!BK&r1gGPEOL'B=F/:<>Bc\fe@t8G?[V%KgAS\U`U@a)[p]S)<j/oSpHP&f\M@3g[.c#1>o@@f"X("^idnLAK0B)B+$DO/mcW6M %_p*Ch46A3-F2dE7enkKFhfW5.SIa4k12]d0baZ@\Bu`C24n.qcO2C(bG!9$uOc4W,['alCd_"GW\7-eWbhFH!i8F;upXkm]ZL>Hg %8i_OM<&a>/B)9VcjT^+`YMW\.`jdH<:EJR60(<'h\/ah=F$8QR\@jp#q8j*uikM,Pkt(c_#4EUfT?lVhg^>,80e8msBc,JQOp(.d %4?K;$@9VGn=,\:j?&Yo;0A0^kXt'5S]EnMeTA=[?`t4!4):*299_/m*fQ%=W(-<:dLteEt@'!AcHR0%j6rA%\0V'"nI8$7[ajHbc %N#sG7#FH3o+s_mY#Nm"h\FZs?9!Tl^"3G$NWPW4*b^Z4A9WT:l_1f-L0iGCcToHn[>`*[eRm>M-/*s^W\q23k[2*/Q%B8;aaCG_T %D>A@>H7cF$Y6DXp9W+82?'MVF%4SOu`gh'/TbD$ETI>i_<L_HJE!1;Y/V/U6BB4rEma1[&e>l0b07;<1,S-+Q>+,n#U?23%;cf+b %P308AJ0q7/A\Q1PQ"]2U&t'T4(k:6Rof!XTS>8O\@L\Kj'I9BV9i:j^'\t^L01\.uPG8&r,&KgWCt"Cn8D4B5UAi.VD+=pQduGkJ %g51uerl-.!7g`MMN[Z[L"E%,ehcM/kBS!)K,R$b$@8bV4=JW-SN=CY;isG[]nK^OAptBWd1b%omJ^YP#-Rk4%[(o@_;NO9Y[@>_t %.?\k]^`YsA?ioOq<[7U>MRXZY0Sl,H8D8o`UAi.VD'u@@'rcd1TPnRp8NRbA3RgGmZ*,#g--W;t]5ajh&.gE!0fh@NQ?=1hf7OYg %!tP;P'5#%?8Ac&f7K&37$B#TDYaC"FpT10h^Tg=,c)P\A<R@tje)N_LA@WEI%`?Xb&5o,ub=N7Jb5ILMj<X$&:J!UG<eRFQ.%2:i %5);qu5Ud"6fQ8^L]Ak#5C+hR\.8,4,Vn*8"G_gE%qVC(#AUJm4I(:j2*cjFm?=o'+GT>Mmi[gg$-sV`\_&:ea.!PgAM<UMj/fa#9 %iuC[b-:Sdm,ZWH?q4HnP;h^>ZEA8baCtXt$a#(l2ln,iPF&T%%Vg+l6\d:p,<pLn^FR1"LY-7G=\XX`l%d,HGo>@?Bo#)kIHl-?] %_(M3*LP70R>nc`=s4ht3UW^Xs=EmqXUf-IX0f91M_6Q%%J-UEYnq<r$JA8WBa7qe.=UX"-;3:Gp-<-WLNr`j8^rh!)<54p^O#jZB %ijS^<4,0pBR$"&b`=,M0Y@7,+U,*C830*722MUHpn8+&%)0:&Q]puKHmp9VFq8c:]H`Xpap85k/6q0/5,c?*UKksV<CdcN"8d(F/ %762tmS$\V6'P'j/O>ctKWnfLfYu*<=btjEQ)/-Ua!@cQ64li`-XUD#]`QV"]YgaMa'GGQ'1,WGY`gF,PoeC$EK`T[*b[l<pTn@oY %,p]]?=`hMuf+'r32p<bp_3-C//tD_]-D;_P*+1U:N,K47$0Q#]JQoaj"\PiH:60ocGfE\3=[Z4"P:AH)Lhpe`8_@kEYe?0F:,chb %_7PLDGU\THqbpuYcl#@O[-5LDj=]NOB&R>jqb1a4&_H#,Vi10RL_G5A"SurK\)437Ds@=7,e80;3gt3[fAB5j^#-J_VX=>*f5G37 %[sPmGq^q(/QM:B5%H)Eu[sNVb#B7<L>LNB_?/P)KgU?ipq#T94hIf"0gV(qdhV2c3L5^D$".7o3g[BHGen-l'R<G.Sg?cgA])g7; %K9e7ZfVdLZJ+<)Vmp2MCq9NqprfWQ4G9&m25HlQB<O'JFZ@(c6#<2&iH05G3<QSQj7ro-BZ3i)K4FHL;l!M0ufjB!'U,>l/8<osj %#0rIinXfLRfZ/L+=$HHJ9=l8+hWHIc)EB]pr606NGgC`opX7*2p<t,^Yn)6GA+(l@D7FdE5rA&5gl=bBNZC?*jW3f8s%BQ0qOrta %p5pGDku45Sge5tc3IU.aN9u(5.GIPPYrF];]iaB+TD7JCI-=M$s88dDllFEC3WIp-r`%Epq!l8ZH#;.rC500Ea7m=AM-#2ho:LO" %?)>F4I/;=LI<PA)LGk`Rq1E<$>4UU.J,M_>moA,OQ%sk]POBoLhkr^;?&(@W3WJZnkLZn>Z>fKPHf$o(hjk^XHhE.)R@:1:IINI# %UqcEAb>5<EG5lQ\Y^69h;#$eMHL/?\]AE)34*E3j6ea`oA&%O$;\q[f_6XY*Tr(jDR(%VFn\FE7n+k%G)jdL3g@AP<r5Da@N.'cb %X57&>@db7:Y?JU?s3]NqoLg8grSW'/R3`eFT7$TmhYi@>GdV_gr:dl'qY-R'3&YaTH[bDG^?<@en,Cg0"02iRb^]-Ka8YZ`I-*Bf %i4o6WbHJSX`S^[6=5X&7pV-S%J,eu@^[fOnIK%-`Re'Q#J+X2aoVl3sm4Z3Qb0*$Hhr'3T>1Hl'j9*0l_=)X=k?n7\o4MjBIc2*W %kNN#rq^4UqWX0gHi2>I2\FS[`>hJ[^:j_T[B0%,ZT_$#NY?]_mq8,en4-lnWAE/r9^0E-Tc-D*R%_ql#(K*+TptetE!9s,+T6f*" %^&I9bIej3>$@`Kn4T4*?XO-i?^$"n-UaE2+H[k#;?3f81l$Y3.M?$':pFEG]rg=ib91/jkhtFccIf(QWo(!%Bs+-M$Jq)2*YPe1A %rn>\_bS&;g+5?P^cqpDiKHL!tr[sFbkk,IY0h]GBH_8Fk21:5"hu3DpWC_]1bO!Xf^%ZsJTD*inQ&kn1YPdRMNi]=cH0&E2-p<(K %H[h8EmsY4ks4qVmiW&o%+7<EsY.<bIi:*`;cfUjJqUE;8rZ".Hou"Q;f73c!]rU>Qe2Z>@DpaG4]Rbup$V.cL\dpajWr!k2a'SZA %Dg^U>55OX+MsIGFQ`N@IcTgu!YIm#)0qYG_MV[b!NPG=FJ,$)%pua`*f@=-?iuOcharc-'K84$abe*VjLVE?(J,I?*IcWpemS-W` %H2$rZi6,L-]0H9dSWf?sU!4Cgn<[M^b(k+7mT@1:$GQ>\^\ks,%D=E$F70!6q"!Ts:lDmB.pr+hqp2CDKBOoYQ?AdGnH85>D2P=N %_]O?t>j&Bs,!1;-RN6f<Ed,c$($n&1GitN,oAA!c!J5OAo#:4c$@lqGc61m&+l6$l=43CSiQ4RL_?N(gYogn0I5**[Fu`nj>M5]& %NAZksgb1-OgU8D(\EE[(<esl^".'Y>@g1A%pNI%GU5R51WD-&.Ce6\?#kQl4km2[ZnuKb)Eor!/l-'VpM7JTPCUJW?.)o6Ln+_nk %4Yc1]%us<oBO"kflu5^@bkg]21'Ohc=#<i@rBq5k!nh3/7&X6i_ahbAbe4JY1&7rT3^g8&@5pr(@nO#m`EF?u6*$1GgP^/F&3PlX %fNO7,>FUf0]YLf.D:t/A(DAa]3a+#1CoF%GEl5mN[8A3+:LfH,<Pgj$/o.Pn0Q:12N2__F2L(Hq2U8*D[+M8.#>u.:U/M#r^5g0s %*B]SYP2)pO;-)Q#mLGu4fD[L5XqV)S1]V$F.3gAYH\!#C=Uq@"`)[%lVAVX)Co.5--Yg1D4*9IV\SZs4e^<sL>j'tW4b^c6fZD9( %*p]\^@UrJL(mMcp8/=jU@<SA1o5$Gtg!aCs9NuNF#CoO%Am.a`Kp[]ZZlA;Mh*0N7f!Uq\ap8=pou1Ug`MQ)'<b3oL8!'>#e7_d' %'=^rB2U)7tnC/enJ@1hh[D>mU/BNi7.r-"\GIoJ#+Z3o&SZRtlP$NjNclBC]U''Q;YtFgOm"bu#'O=un1PPIRNaq,E,iU2l99\l. %^sI/A_F-n,cZ!HoR+ki9XGu;$k0*SD`G0:`3XgY.qH8h#p?##EdEC)<prI,7C7_G)9&"B(DL<XP&gq/C'NI*R\iMmOIXq+g9)4>! %<;!4?9QEVWe5V>BI!fA\C;)NAgCCYd:!m@GXm]GQ9`o\MP[S,nW#dgmQ$Z$lV(9*m6?RB`W)Uui60mq@gcAEKP,^oEA^lBi\3,@[ %<st9o_pGum@/O)Ha/Q%I\M-'=os8qZcU+I-WTJa!<j#tlR@6a_dl09lgpSZ`bnp[6>).#T(iNW[$fGY)8amN?%=S'PPV9jP6_.N/ %#2?Xt+2>ODhgiGb%c$i>$$Q\mWFP_f0VlLVGeQLl_n1%1-9C=ZBo_+)*6(^Al"'B7^`L<3=u,F;9`d<u<n&jokCR&H#]<_50]0s2 %OL9RHD"SKt#.lIbAq]ldSGn;RYq7>>lLf%S(1Rr6ei8I.4UOk7m`(9.dg(M)WaR0h)`o)5A@lh^gc'C1E\>_$cnH0:-`fqcHXk+H %F9"0,/uhD_cZ+@\T&HV[]FAA"!^e$!\5k*13jp%X='d<(&)[[SpD(lH@rPF.#"&MgDHdW*McYi5G[%@*Ljc$E!"N?9,T&,r\,r"7 %U1%u(.U05c)P"mdP0NKm2L=)HYDj<\2gBTP/mYIl-P-YT2US$A06Gc.gW$RX7^E/F_t-g%'.'*41_1%:<LGgL/6%/1*/95SY_FN` %q,4B%EiCsJm'*Ak@jRZ"XW<Gkgs;65`pre`*4;0gd/dau=!oag@18S;HADK*)Q69aBu[]CX3&fP8A9^'`Za97CV^V0*Q8V:"BZiH %'t^/t,S'd"TJ6)."[Gf-(HufdM$!t5Hu^&.<P4RNOmC)2V?YCV(=Elek!]RU2F?1-KP6a7hF`'<Ece#j-;4Sgeo]dTFMle(qLpBM %"(+i)@fTOSG%)!FS/9/ao>3h$'jFbTl?7Dp4I"rhqfdDD;<0Tr?454BXos]/0-"`;cI92\ri=$/_!l<4BY(ZP/.Z+.*74T),`kr& %)rMu\,RqCP2!2e2]&hs-q^D&(QPnPQ9o(D?h6n=.\EG?R7K*tOIL[q*n\LgUr&FVa3)0VK@dcje[u&TiJ%m.8,I?TN7]!PLY-0*n %3'WNI*.9n7Zu,91f'XFB4`i+CpV@fdf\$$Xn6$^#lgNa%p>42&DC>G?!l)4J:O]M%EG97fRH4+rn(\B$6!_]XAkl)88kh*_Z8aRB %Qn4)53+Gu-.br5cR67kH;?Ci>YkrP:k2c9pY0PJkrmV?^s,?SNCX'n?Dm`KDNT;Gofr&lHj-r"I\GdihBK,9+Sp$\us+]]Ham[9J %SW3?'[Mqn.gER1a,,$%3p:m_3R)C/p"+%H@DGcgTMgTQ?T*)Q]2kI!`QSQmS24>CI2!7Xt4,T-]Zoqc.X?30VmC@2OnNGl22.*Ll %W`7$-aH_%6gRiCMZ;N?b8$U9O-hL,qCXd=M?'2Zr<3?uI?9CD;`HA"iZrD03jiOdab4oYT-C5>p*$6aSYDebpl=L=5*3P5,RC'?K %.Om-1(\\Xt=,Y%$et\H)iR'cKd+1^p6G<RIm)p1l.\n[`Bl![Rj2Gc,fJ!GSe3@+hB!c_nMUp'`[T4td.MW=):M(?5Rh6Da3CCGt %50?gBXr.IB&)01Q'X5FDHi[_#+LnQT\#4VA&K=*'BMG3?B1IaI^7&5trPOt["':E2;P#M2(`CE-_P=u9Y/rK3iE>\E^,g"Nf2d+U %_!3"SoN>8Sc,c.Hb`o_]$0I-P?'0QJPMN*5fegjrUf$Ps)KhN=]ub!<9dVg0LA5b,1i<%H\=6GJj5Vhf_3&2LW&To$F_uLY?;RLq %3&U,=W)WLN@rIhdWQdTDqi-lGh6R7+obcIN:5k[LBs":s&iV9b'/R7KUUBVirYkg4JK5REHL<&cZTZq4es'+F/Zj5L;09s^&WN\% %W>G5TUMi*`,"7L^,pe1YC,PqEA8Pd,+nsF%A/Q,:V+T^h$_t+=qUt-'g?<Kq+!>CU^-)rs>H-')Pih&/Yi55*"$1YkKjt$R1GcnE %=ZhL&C$Y8nF_4*g&I`iC<2sl7&p"B[NM!/Er;!$iV)120e0Dr>PqNqCl3]#)oVQ=P5Jj=ER%,o,X)&*o`erR@ZXQBo_qlQhnP-if %Eiul#QWX:=`FGX(6T8@_HsimpZ3a58j<n_#@+K@F99[n"FD7i((>:b)XFu.[Sf>62p7A4%HED[3mgr(gf$m@j%*DhXHn4JT^@g02 %KDEo0DJpSajuLHiI!Z2NDt_0,F(;l'#HUlnRA1ilUgrEtg[RiELEVrG(+9*9?hN1_hTlY"DL2#8ms.i:o,8_$ht$-5mWeGA/pZ-6 %N4/u#.cc@80/QCCh6W&CY(,<bq:*L*3/q1%ZBdkSno.lg+Z]gIk/,%F"X[m2c+Rc@$74ug2fh0QY?n1i'$#R1VMAKV<=?:uOM"SK %bFq7BcJ13o*4J][X(&VBWNG8bqJ>c)>rH&CB8t?R7OB/YoXfiQ%8ZIV.4"utOA0$0#W+UfEptEgO*>q]5_:@d(jY`a4QKr^V:r0h %7kHCYmOYO)A?jqP`LQ7CRp="sTTJ"Mi,qB_]$f>"qAUr\^YtNn+;G1W``pR0!Kkg#3b052nURl#%iBX/#L!XlhZW.[T9p3O*&CcY %KC0<"]th&=(>Wlj5'bALNa9-9j-t`bg2@07i`drm2`F/M2E+9W'?'$)j0qj"hAnU/a`Y6mmEHUoM.G5S/Fb<WpO):6LlW;0l!1b2 %h]dOh5sr'N7qW=+=a2`<p9;s"I2U3a$h'Ng"uA"X@d;W`fl9:S01K;PfU+jTn$e&.GuI*!qJIK`2@N_.GqPrc+<R4(bIpNaT>ce; %%Y;q3ms;F+e&`a%/b3TF,;T-bTmSB[]f.hD]_\5$^&ajsIJglIn3aR:D?^"j9IAmAp]6qsh%o6]&:?\blUiSGVs)sd$N/i:)uT2" %%6bI);"d*?!<Sm,SeG9UOpnQm/+B;m2>Fi\&_"7#p%]T7K`p=n]G:53Ri6Z8kS;bad`6gU(AejDNZGLhHE<S;s4gF?cVjLdZh2BB %PPF`7BbhW5oW)gZ4R:Lbk0>qBFf'.Y-\<O`H@<g/Wn@7Cd8E<u_?apIDZ-Eu9dN)K\tc3@+gULB-U^]g3b(V?/X%SWDo",SJWeJ1 %:ib]M4@sG[[d>7L-\35TCHmg]1+jaTBC<jo&!b>E-1U5$gI)UfJ]<&mDO/gFg]j/WC`b%Xis6Jc1Ct-6?CCcA?5?/:C?!DMf@l5/ %El7QqSpTLSs/fi3k+5l;\,JAtZl]Aq$rulKiONolho<5H`6[6&UFW6SJG*5gA=\?*N3*Lm'4:ZL%n:WYAU#oK%F8YI_3j_Qha253 %[o"m'`-MWTR"Z5k?t+@DR-9"",2t1r^s,?e^<*k!rEAW&^=I[kUIY27>q-U:1(gdpR%G3E[d>5L(*!cX->U)UeZb=ZY>m(c@<jKp %;`@H.EdY0?Kd6eJ99oEC'5AP[/6maUV(-$6QW2[HWjIIl@0fqFbCmnU^3Ibe)pKD6Fj)aaR"0l"79FTfmG_-\FV)c"3B+]%D</q: %<+dFW=)(Fim-D$@94S5E7WR>!+8HAl^SNODhV>V[SZ(I(/p/0aKTY_O/#0u+0gWI#'MNcd39imF7P(:/!-M+u.c",1_9K5cH?4$' %gW.*hgA>qhQTYSVo&'9[P#J-`g*DdHr&BYG[o+^;07TH0dbYc3[cn0Q6/mkEP1Ue3Nm_LXV1tF/F3HWepLoR&?)er^NYY>\<t=@c %QR43DCdD<)Q*q18kW/daR&JB$K#db4Ngej@,Q+*#O^;83hb!dS)t8&#H2lM+M6Ym\bk5#?eKuteeD"2$=l&]C/0M%I7:EBi5Ers! %cafE(cAeakF.6(OCtH.P.HU?63i:DD@W@l>]^`ELhepB,gEP#nk#fV2Z$80_jV+,0Mmip/8)<;WDA.n35Ua(e3C4>56pgE5_@bV( %q_&;M`[[=UUR+GAZh\H_o-M-Yp*Oh4)DYb8pc;&m^%d_J8X=FO`qf/,l^(Q,La22Edd1DD-odbCdhX$8136pN.rd<G1u3"+F5[Rs %\MnXJKK1K:S7=`?F%KQ-*S;WA>45b#[,-^EMsH"5.s/\[id.u$D^hr0HIR\b^,s^tA]X3WT=l\*SD6.Ko[?X*T.E]A8=dMJULW=1 %F8iVp#.,<o4u:Uf?OMn3YqhF[)PoOP?QSViac<:DR!]n))"n)ljnOoT;WlLViFr`Z%RPXG=6@V.7oS[B68N/CB1GE=MQ(5;.l*K7 %i$%k5SC\BeK`5N&Djs,?qA]gX,"GLVZ*ubT<^UX`I[+D(`LJ\67[H^,5T,aJM7e#=;QUW?q/Yoa,dQ_-ZGg^iP%E&V7honr@NNCP %BBZ<dc/^Oq(<C7nm(lI0;W'4N8=AMi*9m2k4t#5[ALr&23,DnI#@NnWPKP+T'l@B8na-?"*g_f]MYbk"ilf,^NM]uri-sq^jS&_G %AFH+=f4&rdOPHm>(rbGMk`%]AY]Ibr3OA5Q:9!BPDMDOsqa\\KPcgfojn\Md_j;`.?umLZT$dgO'Dnf)R!p5t!#=ohS7Dp<W%"2u %VV+BT-\2M.\i*lqj:2/%<MYF":iT+UL(ss61#sPJa/.bkb2e4kclfm'#8A2agVmXeBqu(Q5F/M'^WsYF3(n5+,A7&<"Jm)S$(En< %>#lJ'EI=,K-*&NM;4hN.OMNI!0UTJd'!ko]Oss*u(XuSm_O0<*4iPT5=II!7^2@!$\%FnmWc38*K,c'k81VS,dJ<HLCqjr%'A^4Z %73L9kTulT]o['M^):]%kbNK>/jXVX*B?E&UYS#i1W"f@)9'@6p7gs&T)/GWC8.YN"%1eR-2"%<&RuRXH5bbFnIX;FM8>U8/,Bq#Q %?)c`S/eK$l*C^);=2=:lSKp#U"-[5;DfW-e$$`2g[Z$ZQ.-+APA>"ZHCX8JaF9qV(nbM1`ZC1KD[`ZMWFV6oi\&Y=S%QMg?J$C\: %[O@oI`;:=_Z^DHJ0;2$,R<?(UEuB%HVR;QMbW'9mCjq.D[WUmUXV=5A%9Yqk#K,,_S,lP[`Z(qH('Z.D`DWl5>%t?+XSbE.2B"*8 %<_gN:3J=bWb1B@iV"\?/2@5lcOn5Qa:=h>k*uu@Cc<nc2rgr9FF@Gfp5/;MQ9FbO!=$-bdCn\*h\"[O.hN>h>a:Z0iR_c"k2mSl9 %<dXpE07R])p6'/nNLVG(c3lLtZB\D&XCdJoMo0huDKG]Y:"N9k<G8J?Vcq:Hmr3PNh.urGe#>5XjMoZ6n^ZJY*'H:jq)aUaG8p!0 %]KqO9+P.)>-b'Dhfgu&\fZ<%LjiMnXXgb\f^':'V[&o\),/,fd4u!DRL>:_Ycq9c0DL)O,)B9j$.QU>r^/i5):/+b:9#\5Fe#H,Y %C?L.GAI-:ca:sa0.if(qm;nut+u>l$XeiSVBfSP/8\)`n[^):?QAhHMUg.7o>BS.t]6p$\/::>_PA0H!3\Et\&P?3XNY9=!0Lk21 %jGFl11Rq?Yc9pn)f?qr3RMVBHj3^rV>Yd_&9aoEkI#!!0(llVe&h[^,>_G"cS4$;V>Zf#^nEhJFre<C%Q_W>L&eXJ$?PgGLU!\Nt %0UmV<[BjAT"9mie'A(ZX]][qHJReRu[dE7(V7j?\1_rH2a7l$\YhjSf)fYXggi7/#0@BD[YL3;f!D$Si>?IIS$09R/6lOinPfZ\^ %6th^G0-)=D_5Fh(_0A"j:QmVc^mJ.FO>.ca`K(5,N=Al[fZ[RhYfdOlM+PZj4\Q&b[DtcephOmY#IV$sNt)0*^l"G.d*[d`)9DK0 %O4.bQNK"%^8+q>;L6HUno^^'+S:GmR]P;#Z3&+=$XPj\!h;PqI*QHhJY\0_4@IF"BV,<i]Zc/WndJRZLrWsSBpc/*\$31'HHMFV? %6.UKlV(d`6[kBt.moY'ZS,U]MVdCmh'`NRPB`Bed^#>$ta+pL/.KR?>`_'g@d"QtBPmGO&emHXMIPjp6$s&0Q_O,d76/b0#l*d0u %24l`-R'o-Cq6"oAp?W!&'tk[i#mQ;95J?`B\E.4F,A1FT;Pu3(=rOOZb>P5=D,V2@'@?R%j9/,3n^5p"=LQiP.+cBhnHLX_gE>%- %(uLa1R%52=[>P22:mJ:+/Lm[<m(BUHTJ/2U#<g^g[6=!Z%r65$3.t^U46SXs/-+<'?'!Bd9K-$?ULcDl0&(GcWmX^#,6K906!;*I %n<M[!B9'g*UVE4!0EYK4QT%R,P>i'>mEuBOliaDT7LS)d`ub=;=IH6+ML3a`@nsm?5NHV/%ajrHD!Mq/mi4XdCRGFa[*WoK;<%=. %7mM?((+:hT]TR!EYlcq*k8603BV^n_O@G+PGFKAFf^8D"GciW]%_`g^TumN-L&Jt`'*He4b8AuR\j]P=LcGN?1B;LWP_DKh9n(1? %\<H%Z%6c(`^_/M.l8`D03?u<>/oktpf:O^'T$1Ook)NN_-c[0&QX2XX730h,@d[4cD%jJY_kRn@U!_<PK[AkspKcZu&EiW7$'IpB %$=jcekGl\P9j@3EMh]ud4(L%_G<@6f?.DLN0Q#(a!2ck[e9$!q=0"hsHqkGjj*=bY_DUOpF?$2gEG:h_g>gsJM%ja#A!82P4pm>7 %`02)i%89NU:JTtGk#&'(8KW"$M\JY3]OUh]mi3q17](IKW`stlV;*KK6LFR[>"hLYY*P?VP_#1)^u-hH.uIE!:EM.uO%t_33kUR. %q,uq7=$fPC%'`E<30?j>HlBGH>2d<AbJ]/so>BU`h$p.(QUYa"7:R$,MPf(Z"HMZ#PP[nsTj5q)7)dBA$m\LXe[BLbb_W<!Xm9^6 %D<c./q,4q3BO9u8=(&m!**I.\[T`9/bc4ejCYILlPmaG9EPP*Zg:Rm'_e#4CC#0]Y9jbG7XJ4t'KY66>OBE>(([o:Q*_A]$^Nd.g %P,8mt^!^ucGeOM8LW1KiP=)R9I2-Gd,i[^DijF(f<EFPIfMHS_GdVR+ZrER,k1PmE_FS02"(,?aj88]"3#d0>;mPc$=A`VX/IoM+ %ZY-LE3gcN>/FK\Ung26*)ElD-VbGo6QuM`F^3%Wlj&7?d`*W,a[Zp`#_giZM,H#s[m([DZ8[>HZ>ci.T/?J@Odo7o+/lr[%jV;^6 %Uo7:oeLt?P`Q<./ROZ*=^k<-*79%\g^MUVFiB=JMLC0=:iQ5d`e>@#T:oQYr)CjZ_S@V%`N5<>UCJWWMe4bu4^I:jVg?OMW*@4iG %X,StGI;>c`8's(nI[o#<l;`U35S*/GV9ZWkW[%>u@^S1<HR69hgO%(80R)la2J&G6c/57%\Tg,qXu93Z)BqDJHCgdLi!K5'C?/9< %U:UWjEsf^eb&D(-HDt@EFr$B`[B[lY$ouD!m`T*A]#XBl/%*Nr9AOuHBY/RJ\Oj2+H_N:PG23ed@E\k]W!r<l38?LY2QEZEh*u6; %l8IqYNOjE&YqGR*6i$"HaGokm.HB`.Wf@0s5?bd#RBG^f$Bja*"GkRlG5RX+%i6lBA!2ucA.rIQr*3fH@W\?o,U[@K+<<mqZqiL% %RTf8X;5`j[aJr7=%X1^-Q4/hD[=b\YX\^EA[2HO#Gc@>U7Q+E0CACc4qeDVn7]&F4XAu6+f!_HW,OK"RGcWZ,WJsZ4A695jHX*m] %['!E.@P!1HE4/TCFrQH_LeXtJWiIN/G\(?A9nP;:;O<ASJ;M`/#?YJLFCHdchKV;oW_H=NC]%'L<@_#.\#D;3@cs^?%MroUQcmiP %p\9!@S$&Pci<iU(!>8E`:.6&"g'd:J98hK#BP^ib!gSp+$_qMf%$a<&J.1!L"b%G8LY6="WLl3ZCo9@WNG$j$B0d/k4M,'C&;5&H %Wp(B.>.9lfU+@4:<JK11BaU"/Q)<a:CD/"n2*O4Z\jrhK4dp]!)h]]N02#HJP,>gHq8I*>J9B$&\\;A_;VkPZ4i#I'5&7B,&col[ %,61+"WZJ:495\4f>ch2s:$aDq1!NIs!\7BT'sY/]COi[%mE4WPd)tpEl0''A"(E8(%,^$dclld2;U?_1/Z?&VpgA!45o*9ENKQ?d %?'srW:2lpRPSd.EO-6s^BW)nuM^;?)/g9?tQGRH"_r?rpXi)_FF:jk0aqUr,f,8BN;W2B(-qrk?@EQ^!0Vofc(:GoN:s2VW!6^Wq %r/r!NP6;+dj=C=6],,h$.'63c_d@:?*h18o)suu!E7[t9k%S2+4"d#e;n?_X1]`B92l#*pN+tF1Wbo6%Hg/\J[DLQRfiDE+b?NT* %-7+3.>rKf"f=k395!Om5?s39mE4Ru_MrgB><_YMp37Z%_rJ9&pm1cC:VlO\RSo,C^TX?+Sl,n\C;\?:1ZI9/+eREs\pY3\oB1CP> %bQrQd).B^)'C9l,Y]or0;okGVqaf=V5[O*7SaMa\@'A%0]i1]$dtk\?ZB`#dD.9\IO1j"BScSQ=Xg$FP(JidNgZWG!#^u(XTs$U( %oX/=`^31Ong/5?BHL\B0-V/'oduL:3M6ei<kuVJI`-)4q:Q:W_,8*dH/+'d-fU`B^gG;-)Wtc9A?H\\5`F,`p%(9c$_:FQ!fU<BV %>;O*'Wt'bL]A(B9E7;3Z!t;W,0fYQ/K,J($eUYJ7USQFr_:(=!-3d[1_-edQ_,G;9L!!rZW7.+i5?,@[6`6%>mrt<u+"EsO99jln %B5ti5Jd'28Hsbc"27r'$<%C?3M>mF\i`(M<I4`jgo%cVb20JYbRD(eN;FJdjFhB0F7>^J)%9L)`g>M:&h<ch;JS_6<USHqjb@D"R %;TfjHDej/t#$T&JXgWuho%'e)h8o3r@4pgoEH97FM*@N\n^A#*<:YfjHUZOMKpG<ffSd=nrmC:9b\1;<^!g\4l=ur[;@QQ+p#Ir] %a8-Ae8R3ZQ?tPm=Spf/3=AO)!KhD$\W@=*8/RLS"NQ/']MgMANbdDgSJZtD77peDZ*?@51Y?j4n0=m^+I$+15?TBtiTf4V)l[*;; %9pO;*=JL5@<0M#r+?MQ72JO^hD.'\RK_/6A3+oVhd7UrI(dS\PPTe/2dIOM6'rDl`^:^Z?6CIeS%\`[-B;hP>k%kKUF2pi[9qo-8 %^7UA=nUi:I4]'C1_mff$`^VG9qb>[;9obSR)0Bcj^!tu1WD4:XXnAK%)c1([4-Sp1J$[sf,ZJ]3-E6iXVR#a2G3>%FS*a`E]KDD2 %Cj7fTmZ^4U^,Bu>3-8c>pqlZgYnm8nB/FX-/hRKPo+T)A,ElV)jnrek%4\+M?&F>(gKItqHLp05@6:K%ldT_,AB4rp/NaUdbcmZ7 %XGMp2il0G04(Aff"HD3353nl5dj:EELUZU[]%0#Ag[sR\I7Fb`0(j'BiUf8&r8)'I]fcJDmLIRSf'n^Zp@W"n\`6MgEiJN\rlL.J %CUQ?B23_t2F(T*Tjch+iSs-)K:-Gk1r'DAc'oY<+Z$p?;Z[ER'%/S^UlPZ3Th:Y^J\m1GCG!A4BF6)]ea/dbH]7tX?NZU@\`0%R< %4$'nCCj07J.IYL[lM7?ZI8BO,44Ug@B30Z<gTl1Xpj0.+Xuin"ccCdoZ+f&ab[<:'nq#5WkD&[oHh9^%cdoCMTk"%]4nb:WhrDV< %qtKb)4F\Mi.(dMYm2Uni%sIV,lZPG'YC#hsdll[cMs#\5j7`#W%4@_u8QUV;%Jqc;DmF^b*M/Wlau\*pl&d>P9gCdq-hh`oN9mWH %]mZZA'<E4(iloEYF^3b2Np$9t9l.o>hg486[_9LXB<AQ4CupLgF[tg59\n8eQJM5hFrD@Hdb^2$`K'W!W,L[So1\8gL>YI>o+lgM %n"p,(kDAT([d6$mN)VH4[@Q,kJ*_")I:1;(YNF>p_J%4_h:l\l!AAbJa)g`kdjAjT_mt3gSY!#k3-tQ,FUC*/h^uJ[53$QGoLsI@ %VpDG+f&*d^@._Nkoi[i/XKPZKY3E%=m.Jm[=DQ<(qn0DhftKJIe(VgD8%VrHlAp&L2kJc"ST_)QK%8UtI`kLLnqkRcfChAf4aq^i %e=Y9je[P:o'3UlLXG:\Ga4HTWRs&@=Y]oLQX7+KA_<ao-XP(/#5()m"Au>kD3iAoTh##>0lo_]Qe?dZ(]t%chJ,QC=Xe)0?h2e,p %BO905F7.L'HP:MT[5I1_H=9e<\+U01a#@mPkg]@I/rmF+oO@L18GQ5C:7oT4@Ga,X@sp_RJkCB]4kZjaKBq=<*Tsajh7;Z7mI?=u %abEQ!mrPrcH8k5?Ibe+U<i9/FPd^$udA]@9H-]Db$tOSISNCKW`RZcZYq0#/p0A0[SK)\TZ9#Di/mRUUd:r+FqCC[&]a^N!0A::" %3jA;11YJ<?Y^/2C42Z--dl[*peihIG\ZX54l.pF)gNC5_pStq,r0=uW=J+;]onQg2G.P#Zdt>V3E&->45c7Xa,Gb965F$0NP^3pD %_^iWQca;tZT658IKfH]n6dK\#ijn?ZPF7sOmaqg.9++jSa,^o>?)pDl:Noro(H8J@me"T:ij#DRg=2O4$E%"Sm?rsqb:Pdr*'*QU %:od>%=D*YQn'(4,hd,-ErcI$24*P8QH=m*Eg6S;$\ThNL7&s&fXL!86lq9Ci':HHq\pOIrB22^AOP/lPJLcLZG5BuSJ%2[NVrrV7 %=r1qMY&%4$4Z>P_&4^VMV\]kdQ!8E8>sGi1:!tJ^@d1RPg=ebPFuZhWkZHHj2,@K@g(0ach2Rn9nmZi@3ZW6"2/J_Aop_Q<cYo[u %SW16C&(\YPD`t^XHOk;2]:i/:p:9@OkQfi\40;L@m#k*kp2#;&WJ>W@q>A^2\C8.SlpLHAE,2k)HM8?EoSI1KFJqhUh.\fi$8]-N %i7`^nh.%PkC*847a1Yu1d^\VOpE$=&FBu;C+"CcuHQ+-1p(T$7]mBe#)NSq=\a=Fcm+Hi^]4$<C<f54pi\S!0^DPH2l/:e8cW%>c %4f&hF5BuUL4a*^QgEY:cB@fqfHjZZnhhDnB@0JQ*l!5sldOIF^$lbcCOaU*I?+U_,4tVhsIBqt`nG&^EkEDf<Wuj?k:HmP(m:[dF %bf5rEH^kO@'saD<&(A:i]Z4a^G5oq)V&_.[%]h5j*Gk7&3k4/,cI4YAYtH%.NuQq>]k(0rdnBDgm>Xns%M+k05!?5jbEZi5Zt[P* %XrlB+VWHQFcgTW&X6%fCf09qObBbWop>!UVnUiFN^2h6HH_TWNYq(77T5!s4VWu)0hoo3oo>?TtqoP."$g"(ur`2fRXP%RVr8uQd %[UF[3d@k$m[gtQIf%R6tp8i8bD;*ie`r(J?r`u!.lKt-()YWfh;^Z=,jCrQ,cA&6pSis<g-iMQLH4gP,$,4XVG&?XNhK!*'R1$]p %7o#bf\S'O^pu"3OXL"I<>M`<2hW!6jHh*"LQVJ(bS3"(W/<Qm&;b)VVrV>a-laQ5_e;bhd*UEb*k.YmuGo0c_$FkkX)L=-O,[b+U %:M?F*6ALXfkhhp+F0>J*A:olHYmb0F1UAG"@Z8".-11\JJZJ/c,j-ACOS0Cq1T`MVok<`7V4k<K5H@t7Dd:b[5:d'7Y7arh5=qt% %ht(29Krl4qp/XP2lD+l6VlQG?+W-e;:Y\QUO+(Y!`:Wbo5pEo6kieO2mlq<,Zm8`F-Wm8BY`<sS0"oUFCW_J,*HYpXNa.g_:W)#q %]rges44/I0OlT#*nNPlc%1SREr]Z<=p.hYCVHkW70qcQ-$h2,e'h]A'M2#AU["iXnnSMSP@#QD)LIuuJn\h?lcoF2EVdD4$BeJHr %jsEC`dAeRHm=go"OY&gY:1NWOEUS\e=X/D6GL#Z`ZHEGA5(L-/-[<TLd'\8?<-u!?]&q=+9;!:RA2q=aB\K$lE0=IChCVR@>Y^-p %*<0,G-P-(%>o_jGbePZd.`de9B(E3iLcif4n@d7u.H6GrjN231YfKHV!]\,pbPJZ_k*I;GPW;r!ZFjsQXqM&k(d#./q)T"2WRO"N %iZ1`om6:gEJ9&gjf151?0<iF6CFgYP`Ui0jUo-*($VC'.TuHehHL1)A#QN6>_4,OV]G0#rkH@>*nVo30799:"I-DQS`D%<b?cas. %O.-qnC;-e6e>Q=S*$^?I6Yb,>1tcY73M*.Tj(DaK0o&1O>(/!<YTe)`[K?I4SFE.i(/SlJ@?U.O'hu<UZe3r;?;aRLg8Yn9kX;1p %=e!Gn/lZm5?t;bg1G6amrA1efgcDaPcu,7NW8ceXqE!?_?:q(0GRIJ_J\Ba#k'gt\e#_42.&1$S'ACP,!UHBZ*``VehA1@nBhH`+ %BGb8fcA+[nU'bQN7_p2Ak"'u#M?m2I)0m0$`1^I^Q+WeL,=S1,EE66%i)hu0Fu\QV'oH$<pV^<-DR]rNH,nU)*AI7e@>E%GDBsrE %S?'O"iG-ld`foi1V8C@8MqLXfQ>dG^i'u/$;C@PnAo'X&&l-3.JELGuU-HRpgms.PA5A79+!k8C!,he/_7TaQWK'!R(lN=oYu9J< %gCs:1-bP9o[,=X?;s^7@*eRTQ)NTAq<c1:!OMPp(Z?BH%],Q?9ME5\oW575*l-AE4#4g>)a$OGe\*r/r49Gni*R;L2jV\G+0i132 %<MUnoBihb0CGD13ld+X/&hO9d8b3q\1pSr6dWlLRF%(-C;k:D2BWh8K=1BNE.jWt/7TfbAp;FNXj,)Q`6'I$3b/hm-B?G"GjpPgC %V14YuX%CEIioW[]A+<+#p_]%=2U%RGBfLAd/K6lP0Mp+-ku[O'BoJ-%-SA7',QXOF,t3uMY#ODE>D]/@m?omVO=4N29C<.48a",o %NgY,j7(@S@n<2,29'kI#'oQTn>c<&3h2CDaErRmmL6]]qo=!0SH6S\X4+!R=a?D=r:?AaHP!I,'_pU:Q%$q^QVd5'o(t$&RLSRYZ %1KFla`'@BLY&b3CQa8Qc%itRoT0<^4bs+9h1HcK%[EeO!m@cQsg0&^1oBC_rB(2bn/ME;I>q)V6Y+)\/:MfI%lSsmoC`t:_=[/Un %HFlm]]_]Ra@k>H[(AeDRZ(C_Q[.=)ZC=U1jdkJA*'?apKB#emEcK=4]s6+_7)]h-q@4^k:c+J_<X=dL.BqQ,sR*(h&Bc0K(:@hMe %`d$&#_@]]$FJnFTfuX7Mq3Gl"^JH[e=fF,*Do8\i@!KiL_b-%#".4pX_5^r*E!Ne<U6Vk70n1"=_3;Wp\?g\$E\?n+fF2]<.]bA] %[$NU-#cd\H2EI\%Tb07)d^-]L@sO8>\#+skE@gX2k<*C%kP8GE[</:dE9q.k-[JPEe>7lEg+ZnpUoV814@`P;<;XbbD?D/`[8o^/ %S)KVZ$;7O0OOW#omJV):>L'1=AL*6"/+Km.LL#n2Vk,BYa2Z>6n5JWu]"9,Nr!I&eF?[I5Nl`43ddO8ar%pqfAn[.u:,o6hP$$#c %h62D1ckn'RP*+_FG?3g1*Jr5^A]WUVQmJd)T#O<CpI=Kq+Q[3nL3r/qj2@0mB4Gk,_Bhs01E3P&iE^:'8Eem"alKt"hFe02gDA`` %EQYtpd>KbX5'oGG-FB"VQa?N")R<a^*(7k5'L]QgJOmSIilR_`d?&Rhj.>%[4+eD;PDo.r6p\1!UG#q@`,%\["lu%k&.N,nK-r_! %\s\')`U#,CmU].A#Yg%`k<ZJE3>UJ]0DEXAnZ$.1,D;r1--CR1#`[$uYXHS:d8]_Z0-U^90oRu>(+VCLn\B"W#gR1fR1<KDadXE0 %(lspTE_423>j!Q[Ln\qf*iqW?WbE*IjR]dccAQ.:1>;lRAOa9E4L'7+ni.Qtrjf13]^b`P=Ys3q[Zh8u>>.QpaDoGp.#pm_iEI(@ %r8$SMbjaI5!!#U>VbL*UUpEah,#R@UL.d]NhhOU*W*@qgXL(-=2Leo0N0WbPP)af\\GC1?kbB=0SX3j2WpJ<M-1R9R/Np*$/hOC) %Db0"9!SorEI3^DbE-3d<fIh"+inR=re<Q-8B:RJ?_X<+oo>^+(,2VZ:Z-?`YNkj]A41$muU3X9/4-,JR&ROA5\6BeFU4mgHmTsCh %Mo<-DMU:9r?h?bA/=lQ]Ji+m;qtSrOa^(aD^UT.rA&M2dE;")AUmk+CnemF%7&EgIAA[M\rM#Z0<-k9,:]oF@(>dWi(sf=T,`i9D %b\_o.514gK:(!0+p[4$sO+MmDX^p52#S7"$%3@JE)3Y<RW/r1@PYU[d^HBA7JL&o$j."gH+i7!.8:e0,G4jlW72//uj"`B8PCBL7 %OLt(V2.jIb28Zj'We<K1*%T0+a>V!gcWSt(KC?B:0$5N$Tj!VO0Quocb'52J(YPpj=d+ak"1fTA^GP6eXWd`ZM?4;d<<RP.-e7I; %"/rMAdho8?G;.h`EFPSi!NY69Nd0UZU^MF-pdu:,Y:^PQ]QoLm<-p!pQ4\]f5#EZ]E)3V;MD,uIb8R-T,r6)b"\bNGW+ArWqhXGZ %Ut^ML@IVffB;8'NCD7s)O@J-`C71>@N<cFo5a"K,/^*3+Y&D%*Y,JLL:,YE?`qLmhgt=q!o8#@M@[=*!k%tsCC0@R.927'+NI7ht %_c+alm1m#K1#ko"*4632qbV=a-i8+SUmE?n=D]rB.f6DM/+S&!)O6T0^$W`1Ie0gj^UI4:pZ:C7kL1GrW$`)@L2_Ne_=Q_sI;k@7 %"!OSMK+m`aoD?[W+/dOe.dBN#bnc/1IN%6XB"lrECt'!H.IhCBR0BXsPSBPt@aQE_)8RdK'eTloq4kPcP?_]&40/\n`=4:)_MWkR %19"\Qj'J8N=#OS7723B.>PK*SBB]nM,4kYGV>[e7--/07U3Y"cS5Z4bH1+\VSmmf?Z7m;=nQbO(C5]PMW6"nchB]/qk)-8<%eGo0 %[!K@Be#A+g\6B`RRqWnXjdsHtdF0PHKCjV-*P$-H"&A$r/Zo!;]*A9piACg+Xcj$/%6I,!aQh)lRMn'C,<1u'6tEai61q(i=LK(a %?8Xi"oT)?E;:IeT;IT[XV+e"UZL,:O?IK+M^PCLld#kg@gV1ZXr*3O<YN0_riEkX7/4W;LpMCFhVaK`5NUcSbL^3+f3p'B3M3msr %?$Kl,1#J@:?@/rs!ZP\GZ(@>+KE_+l+_A-pLi"O'6R!'%oejJkVu?g>5i.mR/.:Nm3=EZfGaoW3fj`??7?P*1?G?dd3dg'q*bYD% %LXBEX!6D^r?uBRVX'q*&.SRRraroo)LcF>+9&eT4b=rE%\Po[RBoIo!(sda4o&Q'S#"Dgh?%OqgNQ6cem&6qNC5dc7_gXt^][URC %YqP3*$\`1:_AELt%;[XGn@PhM@e5!]55RKSZ]:U;Rj[%mf+'j(M01*b_]6+Br]]c\aBS.3:/f9APUjYEH)j]6EnH6UUV+AuT)3tg %9VO4L.ZYL]#cHSl-g)e@9G^r7#-,`W#:7Rt@-aBcITjVIU;b3"'eWSP#of4`LZ,qR$.UVmo*fQZ[)/jU#=8q3Z><H:Di(gqE02U4 %#,+0E>9]cC^d(k;Gn'G+<KO<#5kl+TKbrFX4#VnnYj;_6mKs&m,[/Cj.jr_BCe%;1:DH["[Hs'.=a^GP1Sm9#_]lYPo'P@l%k0%k %c@2eB;Xeb4@[&I"A1?@e*)iJnOfl'HM%nadNZo)SCuGV073P6iR<KXFPc?"iUI+MkPKuL!pP5Sg00B'OrAu9*Er236BD5$JO:2Gs %no3qPb0[3,Y#3,fDD<QB-ai9MI]sHI6KK'UJAF[mCF"Y;Lu8=-G!ZDL1J[NIT'MaUI*AQ6."cj\QVG6s8n+3RP'3=*?!eMV>7WWV %'AKrXhZr`)@S$R[R7tV?0@&_A;Z#640?R">eBSGnaf9)^n2^TL5q@lB<\Qj\:NIk=<`V[FC"-ue9]K-sb#>cpWD/#s'*s5US.,Rg %WL/*5b=Wi)F<-RDg+hL"Co#Q'O*_Tl_V6+&rJObeb,qq4BeR.0Af4T$a/PuZ`U%4k"e;-k0)EM!?Zp3+3@<]Khs<Joj'jlq1WN=g %p-Ufo-[L#a9PuTOi3'`BdoSY%H'2/(aKe3>-3USE&k!F06t+1P%$Gk-mJ>[(pTS3APVC4$;)0@:*trqP8o8Is;u&=1h;(b0`1Sh7 %45j7+d$W:X_1]pJ`*T>ki^B4/n*K^F;mka8GTJ\_E;RL$iO=X2hCRPm5sD/f"f&1h\1#m26dYBU&KhDKL6]m6lN0EOE(*f`A9T.& %]m'^dN1nQSQWs@p!u88S/-@1MfW5cJ;^DOlC_)Mf6YC^c4#nZNGBX>[**MaP?aq2eiHd6TO/^jhi/,T"1^uW0dh)&*>9)FOIKCKf %J7RU`U%.G$P[MPa.#dI4%NuJ]&\p#Y&JB59%4Xl29F+?][hI`ujURWZ&?aNoSZ6OllEm#N8ONgj`Ph=T`UECW(,H=K,*!dL%o.6[ %Ft87@Hgp9of8ZeZU*=-NCb#X2=J#GMFj*`'1Fe,d0p0h\<X=9cmu?gQS@tf9K4j(E_T_iQO=6VC:s9R!]QD.cAL3mXiGrW]CSAXP %d"<AT)BWnX6;4@WCinL_,llAq.W$KI=NSEJX*</1?Qb%EdL@&!/TJRsI3l>\k,pOCnE##e7'&8+^rG#TMA;91(Ja\KCJ7`@"H>1` %(HrEQjt!FUfsb2fID7.Afom$'A(*4DNfR7`-bV1fJ`(mLfJ$G_h8EKF-Q3;=]K-![=o:=*SdW/KO6dOVnEX:->NaMl'LGbP@TZO_ %!ip\OW_#L6paBQg_\qJmElQC`5dY=cE215oK+u&D[G2&Uoff6g'*9go`&FMCm;_(-at98sa2^c#*kn]]<PV(M4!1rOA.lqW[':as %UKj]-;;Xu*9Z^06W5TGo-GWr5H'(Z<,CldlbX&!Jj,n5]Dk&\)4?9D+49R55a4#cfA/.C.[W^i8M?%GT[+:QU`LH_@,uktCTEnl, %YAcWgV=?^K2\_2B^5*ie]Z-137_nb/d.9@YSX6.NQM7h']qBpVpdhe$*(>8@iqb->@&W0#MA&o?%s0tYRQ7'F^4m>NN*6F%o09+= %)?MR!;9P]ZP=k?+)qFLJKET,X+/G2-]&J?':EjC"WFb;^X$_=;[]*<NfFc*N[<aG.AA+_'2*rr'9.fnHl>`HE@l_R2X/f9c_L5b3 %A8p]CkL:]']cT!+*ier8Kg,cH]oUS6)e-N]i'&kXn_P%rLfXfTai4)f^)n0eM2hC[HEMUZpV)MWf<_F5E$pP>STtt^b5/oP+$hd) %#K<:P.SE>Vn6;bqJKQ`mhlo@X=U]Ma@7BPNF0.rVT,[4&_hpG@$Bi]-MS5&U=]XAI6@P*J[O]/GqdB*SgTH(UqlJN2A]%06lm40_ %`.2"oo?3NG9n,cOMpjuBQUarC.u#079NNBH\tCcm*?dpKnt9`5N==Te:poMSC5qaZ%]U9b;iN(&it&.*h5<",a[+IOA#c_njlV2q %A]OAgK;qA\<5VHFIrJ5le4JPY5H%aRSAt=O#?BO(O/W=nq29m*7Dtl:m,JVV(*->%`4eD0TPDk/eZ_[5%h>TT]bI&ur<ER-6Q-*J %<1fllO$0H<>l+dOn;f]1>&EB*!fU%>TPB<WU;4(Fo:ThYil#.9mQoC5!:h-OLA/-/W^Y7Gm+&*!EoA!;XU;t(G>P^<;IRUtI8DdZ %AGQ.jCAE0Kgr1Xd:pk>Wjh1n!9/'39Ui2O;j4>.SHZigTbJ`3Z/#b=JU_%_%%(lk:.!5hmE-ne)ZQG_!Ob%.T`9f0PP^[$?4<C#P %HTHdWAa+>V[[J&7$p=D&N]j7NXpCPG:KE^4B0W'S"p:HV5n]WQqr$-Ei+tE6h&*M^!G<KMP^[.aKhHBnbXk9=i7Za?MKcnC0d:A< %=WVs82?l.1hj$.<ZSA8Glr`c9g"<3ghZ_>lQp`Yg>Mb*3nO,h4U6HEl$-sBg=ugQqQ$L3"B<.Dd45eeT>Wg=i4Chb4X^@@,3i1cf %pRf6]"4+t@2Y^4=DMDe6J?ss_KR8jLo&/lh\sf8-ZS>Q2=.cPqSrEcr<h0u=KP+d[NMYq:<5Psr^tB'CiGd`.(uXcPWgfL9ff*tG %-%]#,S?9/*0OVp<>$?PMPY1SELnmtWmHsE099LRc`p\Xp@j:7-KP)ffZ\>g<E3'^mi?7hbV)n(8cH_a@d4IID)]u,0mHeYjo>InB %j)T`CKX&B?:Z^9_8sT+23BN_^aO6u!h`MijB4k^ud_"i3Cafbc)NG`ZUq%>Fm+LT0G`>rBJ`mA.NVr_oid0n8cBdhIM9S:J6O(</ %_UerH%_I,q0S]dNrqtXs`aq3=4r?#7&VYQ3@f-ihqA4s-H&b$#1&c\5LDYheg^],6+i]3n=+>uBa#VQ*I`/`cU#>,hM"/XqU;&sP %T+H1/@,ja#`d+A!&9FW&Jf)8q$p/Tfn`q0A'Oi'5-f9rT_F9EAF0C(G(mdYA59)D<hi$D6`:u>BmB7)]f4metLDX+CHgkXc\Emp4 %%n2FA#+)-=(fu8]\cX[9;$6hGM"(_O0au"1#%.8aJJ^UU@t04M=*&!Pm>,bM1[?-A(e5T4$/Fn4Xb^tVnaaoqa!8SGKX"E?N!iZA %4u>tk@[rGNadG8P6B&8%L%eG\PC]U1a1^>](mg7g4;osR\2AGtbJ*=+W"PPr&i$Odjgs6)(`2r5qA[A_I&GOc,0!FBV^Lj1CH!BU %n*+tINu6JV*-cnHZ#Mn6*!=W0#@^s+>b8t[`ilSN9>n>DI.pcf+NZtm*etSfB5gMo90X1HcCU/EJ*kg0`4/pdr!d+?UE#,8!+PjO %@6?U+;b:mmN8N8,8gRsE8qc8VLiHg^T.o;TJf%!m=oJPc7j>tK'0oNe's&<.Nfb3)!+K3M9DSb/31>7u3:WaTir[^dDSZ)Q`;"0i %%b2cC<I*R_,K;$U7/R'p*$L(%O$"BG/F(8!`\g6M,OQY3(^FP2@E/<W0eSk3GrT9'c\u7e'lQ?rUUiYB,OQY-(dIEdUbhdiLiJ,@ %qZe:a<V7HG))3bmJ*]4*r/siW&E=<@%aX)4.s*b3%0q7[cd:YKI?7rgKb!;7dhr)p*I`DfO$\WnpM#S9LCWL`[[/@i57S^ZA&ETA %^uNi$4E5#30L$BpNea^N(EG+pf)H=C>S1-=&9KlBdfq`1T:s/JD"plBquo-O;[JB8!H@DOd,DWGaE^@,Je"-JJU]43>\(bM&NX/: %;u.GTpu>,l]7pg1!AATu3rJ:-V%5qKo@WOOC3m/4iV[X@:X++q3aADRq[_'4Oqld`7u-\MC^$?J?0H5V0Blp/n0@CtE#*qR%d07R %;-Zo+UVe`=]RPMCa/^;o(EG-0,5=6Apa,5$0@8\0C(qbF%TggB4pE%QA&B%]D=9fHbAlmRk\qR^N`.rc.lpq4HLSc7E*h.;BT>;C %L\$H?oi65b3h.imdMVuo*A0F>LSD\3Cq+_L4VAbfDo4[M*A42-*fgfG1+s/+L\'0fa3KUudG9#jMi+:AYBYG=UVloLQE^0,L(<Ao %)s5*=$6?:&id;.qr6,uS1NYTW?Np22i9OWZV''Zk%:#8j()0;QN5lQfj[B(J?`Nq$rW(<Hm,"@G*X1WDm&Im;HV"SUN:.#;"Q2K6 %#pWOC;U_DFPc3_6g_F$.Pk0K:.\WAQ*5h/fU!0dbcG(iTG+B(:eqI0o'$;KnYf`)mcV'T><q:B]Z@#OV,!GO(77>tY`D%u4Khc$r %`Hu(Hr,AGJ[6&?'B/[MXV_2oPa3F6WcI1$rr:ITs@8:+Dct"Cd*np@cTVH<NE'W96;g_Bf&NnC<ia`hDTOV"\k]jcN<dlru<,ENW %0.D6P9?M%kHARfhqi1Y@.7B0c&Y0TL0$;qp)(9P9mhH%5.GU5#TWAS)_<X_4@Fu!ADh6hh-%CO,SV2`^W#4@8Y$g/"L@?)dfmjlk %?07qps+[Phgquqdb<>Pe"!AmB2YM"7B>37"?B-HUpkKZpK]qY*SWT@.(#Sc;N?aT39"h&^[:8Vs1!XlIZH$F"j@Zd%Gl>qJ;,>Te %1U*?-?JEpadA;!b`[Yok(p#[qDA.5E\Rh3Rj^V=jWMU/,]gp69g['ZTds:TihQe,J[QK4Qg*9qjc9geY7M-NpM4]m.HYU.r3PN.* %Cu[uKM6]V&ZTLiL5(p*!PQP[M"#SS1$5Oa@<at+Ggi47pKs3j,)P[qB(f0=$f=5JV,A6ibEOb-(7M-3CIb_Vg%.?n<m1+G%%3@?n %:i%]%/%`aq;j\_Gr=Rj0=Od3C(;@2W#"#HH+1K8>C0rFGbPNsVM*pVeVP8=Jq?pl?9H4WKHE^f4b)24OrT^S&4!aK5Ce17b(R^/h %V;R2N0G!foX)2u97Z8]e@T0D)s&fg7o.Cn(\NL`9e0Kcpe)9R%5W=>%pgaL$QT,?q!-!;2?t!!9AEgDoi(`^GqW^+"oka=:U"Ip8 %h'Z&^)6Jq>?rJ6HqA:cs=2.#M\hZ/YGE#$E$7*PUUh^\N12#02aA$Xs"9U&r8rP!_I-f;_ph5pE(A4Ia8K=X).cqj6QFa(s=]Z3S %QtP#[B?bu(qp6C.O@FBk*otX;Y,giSFWH9d7+^;OUd;.O8^cWt53`!2k_%C\Pn:ER;q!9HAkDYmPR<O^*ejun.$spp>%9$c7LXD' %\=?`?n7l)l>%4MncK;]A<hWk)\gC0O;bAXboH=7AO1Xk"e2"nS%Nc7'JS^NMbEoQ=G^)0UV9a'C8X\@YQs,76CS6t8cpa-eX^>)O %Wn(9LZ,)'O>/#/lrSuDu777`b?1"q4):8/=j-khSZM[gnb%_e5\]T7j]re#;F`HQS14Gd=[,17g+0>2]B&&+R`j8@u'mT]GSZN[R %4n5D,5R@*P=l,"P+;h%iAMjealcOPr#Ji#)p$6=q7K%sm6O9iAicn>8C!s!=,JlF!9Zr-*OQJ3mL(!/Z\/L<t#-GMTMAL[TV.u1] %#V3>/lRd&C5)c0#p_k%=\8rIpH%!X%aJ^]4d\7[!/tDD/(/CB,NAns0/Qcpon2]U\<d-K$BFi)lj4_$TkMGNO`$P:EN/Y=6qbA/S %\;2BjA"f2,\jf?`GN;kgrl(QZdK/Q3e7'&0-Xo;Y*QDi?3sq;dBqhM@MhfM8g4e!<"##L$hK-;"I!bmY^R`--`G0BT.D/N9OOfVC %D3QDA/Ce`lnMSOLV+cu-%J=Fia;!2G3*hN))#2$I,$HK=+?hh"EbJ1&<.eq!cSnp^*^p:ne>SuhD7@HDe66M>ZHH[8R(SEQTC`A) %]<A;OFVneN:ROd&ClNo]g,a(oDpa_A`MI?u"sSe:6VeYNI]J1#ak,5YW"q;)i6Sne9DnEh^[dS'3;hLPD!G$H3^9`qQ04)"[&\GM %pX0guYEuV!^0CU*[q3YsSSF+!><B+I)QW"umFH("l;j+6bNLj374moDW,<!tMWU7b@9JBtrQ6q\Nl?+pD*1_E>.a$nQD!(M[ckf! %E&6qWMjp\'(jB/uH?H.C?GEr'H/,YfI(]Mo\U1Ws%\;HC3'p[=ZR5l!#NP-G*5R6k3u!W$o@+sd[NY,u(hp)VBUF`q&e,X&l5\HE %e/0K9/m.7oYh$8PQ/V&Br6gQ9K;W`6k/d="5l25&WCZW*iUKp_h@5rki]$A,0kqZ2H(+kn%Xk7kC,.\?L/;tX),&M%m\sR<55W3o %@K;@EdZQK>0Fe-S2;>I\d=B.='@H72K$Ke/EHF6bX6`U3K>$YiQIEI&E^rn0]86ib?,i@jaLW<(7Il"g/8eAZd*<L]ji[2DmM2gE %TGL3lIT'p=a)03Uo'5%*/G?@0=5^1ak%aW^K"5Qb4m0^2okZA?X^1(^[=<T`@D@`sB1cqm2O[gUA"\H[/opGW<9k[?-*>'rqLm>i %U36C"4'LC[)2@MIPEf>7.5c3;KBV")L=\S#dFdqqdE-%c$V900)2q00KAD&6dk3f:DXHM*<S2k"2)asXQq:1Z?/f'a/s>gWbN!d7 %qBgO`epA]1p@ZRoW])`lk,&X$cdmm<cP!q8f^AH\lAa<aXW(`4jC+-Pml\MJM4ZGPOZbQ?l)feUmK[S*I"%-H-9#qslP!M$GY:%` %Mc[CNaYG*AUSe2s[YF).C?7!36e)`]jaZlYaBS3seT]72M-/PGUo?\/"NM/)(n#jAD,&UF2?B,UrL'7g>Hk5"fRq0N5P>bqJ9D=0 %L#mDn)7(Rq<GM($jF@bfLGS1mIPqc_<@/.Ub."j.0]lBm6Ve^EDb0HnI:,p3p[C0pHJ33=WC::TKhk,4+Dp]8@s!M@D;Gf5%e>F# %Ye1r9-<7.&(p1Kg0KmTL5-SCDQG?bEm=5bM3PFm`LL=(U+-amXK.RZeBOP7RX.IW"1I:MG^%:SNk,78#cs&L!*L!!Q4t*''f7K=( %EDE"CjHh)QcKLh=+@"1kn+X.L5lB&?U[?&'A'SVkO]Ui;6"dM1'7VSp,?d<2k5BMA^5k7\*+4k<*Ig_T*VfUV/(<1;T"5?De4BTQ %8$;u(!<cMle><mfX;8E"TT:q1WKB@+3#gp/!FACsU<jKJ,P>!:\A1/hCgeuK,a*$:P\Pjgg>=6m6>@7&'O_##N.;q%^A!i\;Qas3 %ULt?I!G[gE_1;+DoL_CH1UG2r=T_Un;,1p<bS+(eXh*8feV.]"gD>hr&_LUBA^iu2[B1;`7PI?qqE#A;GL'PR@@o*L5bbMLqUOt9 %[2)"a2>?1$a&1qFB=ojlq;lLfL6G#RqVD2Ror13A>A6$*#$PM80S>X%Q0Dfd'Cm_H[HN!=>JKrBk0B[72U>uj]cUo&h@n,r`6b6b %$em0p?#<qN_<$YW:"67MY",CF;A(V;%bUYtF0a@3&n.]-T$7M7T8p%u"/^!ncnO;L`mOQirCP])m<q6lI-Y("'H$;T]Yk9;ak:%2 %?g;;USaLPXT5r=8LNuFF!^S2$[q^*%[buq1fLO&&aZ+'*F4@/)`-:GYe$$5O?qf*uE(a&=eR9jQMpK.0:0NS`4/uP7H`'?JLJMeo %6GKje2`3-FTe2XU#3(2G3gm#Cp=p;%[hd)*_qq&aj]rB(iHHX1fc"Q$?irpGG0mBXbS6KD5.q'0r+:8\Mu,KjBmjD8m=B-=,mo!r %B<Ogu)-[lf%7f=7A>hB$\r;C%e<O"Ho[pe9oNF+*AWgE:4;X?<EXYKOV?Z^"3:Qne8WrP>BHQ%3,n0V(JA93'$Y-<)SBZ4\5]SR^ %.1;tArk9[\?PLrd/d^+P+#WP#3FH=\O#.JXkZ[%i(7dtXT:m_/_IM^d+a?/sQ';%/,Ag+u^/MpQb0N9\a>)sCclB.QBTh>;XO<<0 %`I%I6VgaG7m88":Sm]I&0stt$Cr#f0>/7P1$*82T$LE34,i0hK?Z/ujmlGp:R)e)+WPQ@lIL0YD(!G*9VZ)e3VO,)5Y^DaNB4XK( %DpL$6,a?U1jQrqu"84SI/8;pi"Mo%"RWLff^)I^4eZqWWm0C8e,\$[_rN>L)2.cW<_\6Ar^gH+Klt*LkdP@X(k$mg/@Tj@-?k.,? %$.n$+gVSDH%/_WA9=T023;B58UCW"*)u/DQc@cXlEO)(_B9672X?1MmVI).`\PV=TFRiWLg+Yd[!Kr:,C=I]%.^9%s=)87gjW)Q3 %(0CQC08`lII9o8[/JoKc*MWF/2JZ\=GlAar;aX&!MscKu1G7lo]XcW_\Brm/J]#nt"EV;V+c?KriW=JAR7(X<f\J_I&>P^,1,36u %5-s6qG(md`f9EB)f*=(g[Y3#e6e>^a>BmRHqpS+G:"EY5\`7P27e#0P18<V8:M)#l1A(3;pQO!+dS:q>3t9gPBZ$3Yhe'ZkQ(*-: %To<"pfX#J-b6'*h"["8.!*s<.ch'JK5NT]YDG7inBpm)c@Vni!IPtVBpQ,m[W]<sN?o-Hi5j0S;BU,6f6I1sPD2oHcL5UFDGUS^g %`O%em:FD&i:[+5\D$c*f'Se)![CI0:jSf2bOm\-J6tcZQ*`%99.lbq.#?5eUq/u7&qIYKp=oq7cZgnuW#mdZsSFsc"*\ge*CqUDa %F>[TYf[p#!`9_?P_pJ+-9qXB(PurYnS%A4@YaRePC]u2Fhblp):\DD/=*DT<)4GtueH5q>F:V(&2f3fUN&oA.]4F`s2S(If0+>E4 %@k#YI[[1AbPO/<G<dN1Y[$feMCQXE,`kgmI*=sXT(F2:CT;u*"=CHK+%0M!L5`hZUG#nRXND0TMq>E+u>I_%s81Ide_pQ-W35>/% %YW-5"L0R47a.>f-\+;'N29s(d.;hJ'3sJ#[]#>3ad"4Ce"4*0\9Dq7g%b=(9-VYg<;FoGg"RT=SgppJ)m59.k8_8>LaEd+US)7^O %c4WPF24l&'HZR8<2a8ZPUIlZPrsZn!ebnnrQ433cnlldP60'ofl2\FJjuV23)'E@"[dFL)jJ,DWlBCgFbno0G<Z>?nYR2]H6oS5; %+.,\=b$QgjU"&<op1BD(Ji5bd/c8*11G=W>5lW.uIQ^P/j9$R<CW=[!Tj2<+g8mi=o2Gi.hM?<9pb0DkR?hg,=L]74:8YhPDrrps %j>V5NZ`Xu]!TWS7nZE$`$8[F>`![Q2&a9+LNj5r`_":8\?BC.@erk_Zb2.PhTq.(tr+o\-k@!Dq[##6k:Va6fa(*WM$q3O"cdgNI %?n;[,7fJQ)&5j9c)"U53%,eUu^-q&T-VV4=eoNOdLl(dTF\,JdW.oVjV0c5Y]oP_8L;%.WD<du6bI)tfmC_?,*_kGED(K"I&Ol2R %C#4J1U?I$@HSsL>WDfml--[)[%%fEEoOZ,*eWIR=N>->*C96.Pf(*X3/k9Xd\%EP&h<>craAtXMO&]udY8F@'&dLRAdG;q?GJFBP %S]651+6l#pH2B]_T@jp(-ZGm`#0u\AL+:9@jM(]G,?:TB7Rfn]R]>hsDqj68mHoa$Ce#'N6S<h1d,b9(Ks3,-TUT'KI"4<97Ndod %5p0Fr0;Q&7:,PC5A;>WN\*2GAhjPC'3+,<<Co]G^)8#&)#aD0&&"&\sIZO_Jdb0At\Eo[!rRt]u\lY\ucE'1oN_d(0pC"=-P?<3M %;kp&@5Yn;S0="VCKTDuG]q]X,X.Jl>#l*af2d+u8<gh:5lMu;eoGhBo*Vp?Yptg#kMBLLRNmFbk/1mnY-98(ONu\tQ0.GZAC;d-j %ZYu?&>9Z(WVJOZ%Vu8FI(!)CY21COXF5q8Z#`+@rLcQb0iOqk3-VooF-p^g*QDgi0-"KTq(r:eF]<2arq@II"Tgq1jEtatN"3lr" %#l:W6VGE;&Y.Z(qGQYrbBuQIGK-nrSkH>%BS[nPA7JNuKHXf6$WtfA`'7"^RH@\H&gCT@jqQU4D@Vbr48\PopD:)"mY)Et!nnI!p %!aiR;:IKAd($r8iK5@[30qDmUj@b1Y;s>=f#KsE<^14$%1/(tR&Q?MM,hS!oa0YI0V9]97d[o\'$Z<=5qpt!kOYfF`$V:8TjX!@F %[O+)b[MZ]Y?6^oX7FG)".$%:p'HTi$G7dEn;Gog1N?k3BZ7Jl/hR+)L09.=P^:Z_B/rnkh4W16,c]1G.otrA:2Pf,$]Bk8'>GE4] %:HRinBo"Cu?NmuA_1mVs1cG/X%^oVLG+[Mud:J$&rU`955qbBjrTNIIaN]/d4HQ(?8^RX`#3=ArfQsd]mU;S\G+HNC(#bl*4[u-d %Y2ie&'l['#MAQC0pgR.mRqPpU;L/]HjD":-Ra]>%8M,1gg_R]Y!%1s4*"tO0RT=.1Y<=e:2cQ*]V\H6O,;*orW#]8^=!7>#2QYDO %of*@_O3DbVkg<&"[O^8QZ3E)'ek#A:Bkh.?I4X_%?BUQTDPimh.<$&h'X3a#IIi6>=dG[r["hAl*Jt>]bTo5[Abu(Ao$6-#'BorR %^u6lMP`>`=9YPKfZ>24D;f'82`0pU'I`)C"\YrkkAeM/uZ(Br!ed)-32(YFO^cDInM9=??V9AdE@7!m]P8QLol?uU<T8:`&\mp2/ %it2u/SE1H%ChNjhLVNt;Z>c`RXu:e;qtc=j1uJ;[YlP$tY9`DWX:Z^!_5M,;a0b^0:%i!^?YidB9\JQg"])TAe\YKLQCa8]>%MBj %pe=jDN7&-QplGta3iF48Q:/)\fj0T5,bs$u^CK%aq!tNG%P^Vkd8n_36S*0p28dH`fGJZkBH;[bO*'II64rZp/Z'>-49."#nL"pN %mRrchoPK>FL+ZULY,=tQ4Y^UGiGP"V.o?e?c;Q0)C3Wj)iE47\M/GIN]fL#I\iob8:HH#*b^DgP)#.&BCtVVmA#u7?q(l3oE\I[L %"Js.5:Qf)1nfBskP1KGhNAuK).uc8dpoTar7WD^FZVFR.opWPPS82FLclW)N3TRG8hSNU)hgIr$E9u;'fk:V$f_)T6$_>R<a@3B* %<l%][rRpBgZ(ZIj'GlAl4pp**n8E(*[M-]0"Zc$dDqQlL@asuQg4Ac%9^33DEG24^[dk\(#o-l2q-F"/=)Bm`LjhC8,-5p]CjbS, %l2$(LU&?tp.!!;B7$nW^Xf.-J<(]/>F@G>a\H/^c=kfWG><:'GZ_"79l]QOYB\kGed$&<oKbb6T+@Q(Z&K)X*rB>O*/Ct`BYE#+' %#)[+&f7r?Y2PB^"Ohm$R+=E0T3CVkW;!;([;1J?k1j;m4"6F]%p'I*0Z<,+^HMe6Ge_:9t'qA;a05XAQ.qh)]l)lc'cr^[iGL#/W %_k'OG#'S+?3H.Q!kH9-D-*_uOZQ*)Thfa7MK:QLoVJ`.+Q@S?BNR$Xt/f16G#.QIs`Or(Y+UImS^;d6T?"tUX%'P1a2R;WJrdgca %CA<.VrBLC/2K6aXME]pP;g?JI/)WPces<R)NHuuB0L.>>:sGAe;?!;6&,&2Vr)>1'cBj714W4(tSrqFsC3sZ;XmTHJjp1p$R#gp^ %'&*u;;'QG&n<dH_*7shJ%4C$0P$?43XDY]=geWV)#1'ITbbWE5b[Z#j;(WakpYn,h[K^hIYKU*#+V1RYi)VT`r]+fr'Gs^Y5j5tg %3k(W>l<0V`X)ge,(050$8akNj!-9h??jhu)%/Zs8-ET--_r:fl0_+-?)1q@*0l\0qq3F.^_3;-4]=q'/F.rMG,''Db^aY,XOZG., %BetKS.7A6Mb2SfqW5!_$``9<8a^7h%j<\<p1aLT>)&BMd5YWR4U\Dt]H4QL?[I&fA1TG*JKXJ[)!NZZ(A$_GBgN0_3goars]4tdE %"n`Q%Qqo"c^u<lEm-'E(="btD6HVO[X1,&nE9?5C.0BDMP5P/CV8X^ZYSBdW%lPcW-?A&H3=j@BNsal_O7eoEIW[HRhu=(kfU-!X %*Rb'N5?fsb/9osURjOVaf>.g]4sd*[B`g&ZbZVC.U6aQc;'LQ#dN=C"2Uq<b`IF+c"L'MGJ]%MOr3Ea'a/Th_$*NB4E13YUbh%.& %nsD=2l+e:+k<Np$B.15$$I)q)R?qn@ad5,0-a<_/W+A8I92;+o8hfSLesODB#J-$K-9eeQo(,hL&tRMfNDnP2&G?;XW&6WTDkV_u %GQMBK^Sh%[aJu@_1S"nQ;\#qirV4cE@Ea#+Oj8Do;TES?MD,kU?B:&$A7>(I8<!Zd5?7(%B7-fqXGF*2,uUMq%<Qd@m.'&mo.m9l %q4"X,:;g)\:Z6ZDVPgssZGqc*N5l^><c;0W9NDG5d-7X?#:45Ne*]$`fsQ25T#4>6DnMCqe(<Um&6'S$8cQ<3!A*[YNn:oZQq_fu %rdoi$J*-'o;FAp]#]FaRY$'20Qa._C)RCC2he4%#b*Lsa11mtRLoH\p[+k*3j_K4sTo@i"K]2:4o#Ul?!E5k5K8/nL9_h+PC[jXn %aFK9+iiF_5mPn,<g?9DHp3gu0an<GM0S$D6$8$YQcOBh.<9m?ilGqmI(&Tr6bib34ZbR\3;N$U`RTg3E@DSM(eS)EhiZFc`^?Gc^ %WrZ8bRgu:Bi)'bQ@AF(.U<rK#OeoD-V-`@gHj3p(r1[DIdErnX9&QJiee0ip&IW%P>[tgkUbdZ&\L[M#\1to6A]8/a;IGum-M%uC %c/X7?V+b.R9jB2+W2#kOIZNdQO`bZTM$DDOBp5]D)B3j-)idk(X'#pi8.)Kd`/a\fT>$=`oqqne4o6WFbF%=h1th7SP2>BU$cb0@ %K\4aknd4WQ5,k0KbokMe=`"U>(im$5Y4@iRa/Z+6*SN`(3;S<J8BjV^%r/JWPh\Zs.7)4m(=hq?/%_?eO)t"&)gkL?VX.a7B-QWD %)n<QJo1MK=q?;dC@uLkodg6_k#HgV\U++g\"?<QW8Gu1A^!FGo`CipP?kjLe&e<@D^FpHOl#&R>K=B'5p2+&TUHOq@3`I$5[/[KQ %ZVu38XCA3&/@;'*&QVV'MbZ6P&n1!-=/ss\^A\+\Z#sSJeroK#C(\mL:-28WG?Z4&?+qSF[7a1$jgpKpQ[Mi;^fA/R>UJs)Cl<K$ %/4!qa=PSSI]I2V-],[4:@`)OSZ995j%/T!c<5Ht"Z]7,QAft%.?i'_kSldL(MBEZ\QEs(;Y'QdDFeqhWZ?uV'oe9aFV/uT=J<bK- %jR7'7k;<O7h^9Gd0j-8jMJQQ?9@mV`[)ueH%Fdd=J(.bA"6o]!(XRS#HmLml.^;Pb@beM4m%&!XlOIq_>-Z[!:\9m!.R?L)7u@kV %_>3#fQ<.AUK[O,MZ=U^92(KU*n]pRb<9<^n<9doOFR=i8iF-N#pFdIfjV&:A'G9H,P=^.NCeloY;4n15Nl95KFD-VI,NG>iLG;u5 %ZgIHE,$pX?S$9=&?f:QG/K&<.*:&-+&iZ>Hf8b8Z2VU(8;\uhaX7jC;n4EMr_57=`+S70Yeu>;j.-H)'*/fE#/.s[B1<$+u!I`8= %mLq\$X<E$nLP3e\/LFn-5e(r20XfU798)Y:/-3O6*ia254q"7F.iADJT@XZVg$a3Y:qjC85h=#AQ.M9sk1!e3hbu`=Cb;SIn[lY* %HLdX(!Q,opfkZ.\kUTdaN&O]bl"MLO_tsZ]WPhk(CH7?rqk-XG@OjCi8>Ha^Q`o$+LmmLa7;.BPlrTdSEK_;2?C#!jGq-1:O:(QC %6''*OW&_s+>\Jb"0^Vh/FSKOd)VPL_WEHsF$IrYbOn4+1jsa3J<ZM,-M^B8Jq>Z0HU#8.:jfk+ghmW.0r:cgh'@jV6XN0r34'jYr %aeUijT09k+*L;oHrP-E<(KjH6[16`sBJlB3gX.o5J2Ps.!K1hPjZtjg,!]^Jicuha40WN'kmo.oK,4Zb3s^9jK6a*VpgQ^qPjr>S %RpOUZLK)#j-;"*<V]1VBl60=q5,@CQVUI]RlWO^o#MusG.4PUK*g66iCG(_[mp8>K=Mr7^g-22,;qk(%9t-NkNHlkC7oK!KJO3I- %s/j#J'C(%<'WLXuhp=fgLeIkMFsa*T[9#*skeCSlGNODK.&6jL<q,!Od71Ucel]V815!BcqVtR`"i+oD2/!?aO6cXI@Rd+)<,'JO %3l!D>]q@4u2?W>#O28]:Vs*1j:kJ05J/1ZV3!;l9/2&Yr2<J]aD`7s_NHkTQ,-Xnj2!5j?`;gbGFG>_!H/*KXQ-I*8>k2BFE[K\r %,#[KK_.Yb<CZ0##Tsd6/:HfGA/X#k<>\EI2(\39OP.g0oH8">E*mAWl'ueUZQW@k2aoE6Q]dfW>g?$H:i9FNSeKD(L[j*8X_!I1c %\HHUhYG(>WG<=qXE`+L&?[=>V18Lq7l_?1(MM#r>'eoPZ2i?oP,6$B:JAn5PNUYZMr5=sm*Tp#83>oEXFpUc.U&1Ye;mq(.\<02f %RK_Y+4""d9()+iS=MCo\>Qr]c(`%?q_"]jn:e@?L>%dtQd/AS>.ZjH74C-CM$:2I(!*UN6^bsp#'AN?(E[6_$dTNHL4+<,KOddsC %ctHo_Y77*6Nqa9lkcGCEUGsN'#n7!MloDkoBu4Fs(mCeD.S$RIQ6a-DPJPu*0]m2XEgiLBLVe'WZH/bk^*R8/*.<^unAGgWd8eTf %OJ98g>bEaA1F[t:X!*&Sa;o\iNq3Z<de0IQa=B;hc$#S$H80&c[kts#H=k>2=J,rlgJ2'N/2_b<lG;]O9bBr^?^BI43J?r_W?63C %([W$5],R%<NFg6M3)mbY9@'H`II=`pT,DZ+)aX,9X2ss"(m':)j)2AaeK;5[Ug]$5kHY*biE:"Q8>j?O6IUQlmQD/A+83@*%*\H^ %KD/G8d9LGFS6<t^BNdYE>uWu2HR.D`BFdEFNQfN?0'5GC0$++kWN[(>p;t2:k=tZHYeoGe[<KABnFH!o-/GiDNq]<!7V6/>0)[D7 %H]N'tRtBJ$)?#:WDa6_2&\Mc8+=a#ZP]2O*XN]8PL>_#!-c4fLaiZOD]<\meIg^jI-g+5C"bM+4@*eE*_P's^e`B":%41s#SC8`7 %`WS1.paY,'X#ddRiB_uq+0]&SP)`o1:<1_aN_CGng[1cEJSM6.8i*X<YNi:,\Gd:@;/:T%;X7D7Z5kL8W+k<_*VDUWV.S$ncQ+.* %/@O@IH^!"nHhD(nY,=<KGLBXs*K$E'SoONo:2Aaghr#;jM#A</mDW[,CYe3`?s\`H;iJq(Kk2WO[qKP$Ua'nZ=n\I43hk(lHH%4B %M2oA-o2*?.Mu,J%7sGh?7gbl6B%n/l"_E0(Snh8#^SWb/an$ZFNWNG#/;TQ(hbFY9a51HQ0#<!&5`4X$)A.TPP*<c`qABq\]-XCf %X,n5\`tRN7+V=oYoo=*j[e7"eKhkU2(3gfPM'F:aCsoOo_i(K4RG2%O.gX&>^DpO\`W=d-3J<"/4Fbr<QgUNm8>f[K+o*)/Y/!@3 %kh1\1hO)tdqT%jp`+D(-4n^"f2tp(U&^oGUYsIhn7Fi@]CT8IYO3jFQ?(h<(=C)K&9]-j.:0Z#23rNJC4i[nkO)\oJ*"U$:)=WJH %!i7J\Trn'!:Hpe8aTN%I:K*S*_$oP\g+LpIlqL!P3Ai-mrpMkK:j5$E!Bnb+a=Qlfq+pr50nZV0MhLRH,(m`cp!k^=W&`PqVhX<a %aen"S+\\[2!o-E(08%Uo^j38F+Ddgki^ISR<A;u0oH5].%WQUPPeAtt#q1Er<.jkUfs,=b9tl>'INk(L3oRuN>ipU,h$EM;'>MZb %]XHE/Oej3-)?>fQNj5t"#a"r,`0df"Cs]N&JZpdpL7W)1G.<;sM0^a8?rE]hK^D1FSA(H.3HkQ%618I`_1[Vg#5J,-.ZY`\o3C8V %N3CS$0irEnYg,_@^Jhi"^72Fq]V^ku]3:3.9?://+)B7o-D<(>!\B.blJ_!tjf:iJFUYb]=%/q8m`iB07JuRia6pls.ia;?NG,+A %1FaI3b0#e<qFGb?QZsDNY&H^J?@uk";mEfr_FQ%8^IraGa4Y*\6+Mk2"h6n=PS)Im`R?a!kmXrP=?b/GCi5^=U4KZl_MTH.*W,dQ %L4BYh]qh`9;tRs@SS=)@WDT]l:lCk0>MrTEr6?]Ad46oCe!0X:)C,,p!Vi>#gn""1,>\/Wk!jRrB]`l)QM9a+2/Rp?=b.<\'A/ga %Jh"fcS:,Koht@rY_kRD3KDL7H$bkfP3GeS-8Z8Y@:_>kl^EiHa+LHC,)Z+iGlHQ0Of;hmJYIIs?Hmh8'%WnOpH!mjcH+d)sR#dLX %CCUT\FB2@H$+j!i"9pirI7]A9?0G@i!s:)(lKdl!BOOkY0#^k9Ph=fWf3g/-g?\VdYN)50:5YiW?11eG#KqtqEc=lIlZJAD*OLMg %78!FrOXO*QSQDa?&g^JM?=3Y<XAJBc+08;*g?3)f:9d,k^5go01fQNf@1OR0"#Vic4[dNf#JqNM>OOEGl5%ohVb50h[+M,fb5%3h %S5;S^/?5ksA,G8N.Q&"7TWS4O3j!'H2c)#cr/a84M9oM5\@qn6*mOhTHjquZ.mai><V=LQ=7KCYf?k:/*,d)D90sFJ,mVi]Y[`fF %/G*<G>X7N/\0@tjm@GNu`G_QA;$`.3H47eP&Rssm_j[_/F<eDFdk._/JP/KRP7OCr>B`$^!ZY-V]6/>H/bX9%Ksk302r2n!1"pNu %mVTOhC<2XnDVa,j$YJ92gMYj'FA#`l-/3V/m\X1o25J`FlgCWS)C%`+Xh1'?Tfs&\D7=?U2Vit10u^S*G;n=ZDc(DaA\5G9(@8&r %fQQTKVH[FZb&+WUDRp#MIC6c&e2Q2E7XM;Hh7C5_()VsMgTA)WDXe_dYI*,s]BL*tW5Z1#P#/9ur!?b4&2gl./?OT(."o/c>NUHj %A:lNaj!nqT>c<#+\LL3a8'gk7i\S$=/4<P+56ejKPmt1d>/"IG4Z:S^-lL7Z0;n#ah@$UE-T<E\S8ler-.Ai0U3?s5,DE\hdgVSn %?&\q(n93riIn\(r\3RU"5P;TsEuJUK@t!&Ppp:9*"FZpKIOs!sAnnR]bK&5=qKis.7G\o6G'qqq\WlV8Qa6!VVW:h!CF@pkLEKc* %)C&UI#*nO'"_M9Kd38fJO8N7_THoIM/+JdCS?`d_Bl\lTX+ea[kPW&8bS\Q2"Lm73S9d'kZqdT^jQY;&dkMR=2D0)3:_DRG');<B %Hb.0L#T28&.j@g'#V<&':jrJSdf#gdWTFk%!ac)d=>KilapT1Jh%qrp-[&`SnCWs4.d.),r>)o/Fok%M0k8GVcmS0W22!u0j4Z!8 %BZKtVR+jjL__*)M8!5PgpM&f!f*'g*FuXs0[Ze+`BoXZ.l02-dbF%lHDaIP>Od$5E:hgh[D9F-G2B4LjNFAP^#pDQDR@E)D!edTf %LD`UrkO%Pa?SkWaN3XL#0D.CBerja+7W>1bfcOUG^oY:@9kO"S_Vi1mXiBsnrN@1<(]Fkus*9FI5Jljo+8kVC@AkoUHiJ@BrsHLZ %A'[S]p[ij?T<E\Kg].82^e;p]iB9j6Mu7)Rm=BVZs3-!3G7WI<^9YNU[N;*GVfD_]_>fu(d2]sfaYikfS&Xh("l4`Z1[q(>5555o %i4lY=bu"]5r\+&."98/qkPt:KJ%gEOIihtj^G1+4772=Tc@F78cPm?R_dT2#hstm27sLOf0,P2XFZY!P0=^$53!heM`oqJuh#[!/ %_FR#s_bRBg']AEdLRk":i=S37GieQMn?^TO+Q;ti6@aR+#C69$1[$-4r7atJ_!d:/nTPuYEdEglA0]>q@m*'u6H1%D%C'RHf_HTu %YWSF>?\e\H!IP%M^BBl/V^Lg8:C6ifi/-EBn>:.Ylj$V-RscH!+U$X(B&IoBV"&a:B>EmJguIpU#DU&Z69_;+9RrTqIV6Fuh\?JX %I3(eJf*ebWdEB%8"`V`P%#,%4T?$29"#bH35N&FM4<bV]])?M;6."j@LbO;^1=kK-#6P*YNIVQ/qZ%R&DJ.T(07]/f+E_)o>R6,D %cbQ#;5(E'ocOIn[%=-@&q:n9qT+CG?'*t89K`#5j`s[E:,31$)ILgphcg;-qI:;W4J.ll(;!e]Qr>n`G]o35Ng$o9;*Y73mn[ia# %"UiQhbRG"`)KP]1m+Md@!e**f*^CSc_[YJapO^e>K$LS:b`!&r,Y3H0H+`'@DD-JC]G+%@fF=4lhZ\`Qo(dn$8Kgk0nD=\0(dM&> %DbFCL!%G7gZRZC0k6&WmqnqWE^F+sGoRYWk+BqSdqKuZ\d*'7o#5gnkJro%)3u<F_!;st[k-"fo"ME#V35>t4mY(_RcgCB<kLW%. %-%MV<)$<*R.kp1.qYX[9e:;,gpVEifV_80j#)e2M-QI/QHpdss5Qj7.0k%iG9=VZKG\F+ncbL6K69sUWK0_270K_Tc&F<&o=3duM %&j.5V3Zm9M!%mN0+)j"I6E^_0*k6C0&.p:O%"h>pK3&6_rX.]qpfZ5g'&3XMis%"O4:'.pYk>dH%iDk_NWOUi$c$?@on*:!4h`_X %_!2=(]YrL2Mco+RR/l,iHpP[Xpimo0$+CQZ#Smn9!89g0$%sr;p)TBMn<t/rB`bq0^^^gVG<`YS$ou-JoEg$4Fbded_UU,\*+/g[ %7Ke"QgVL#pf>%l:LEJe^2ZR4D`"V($DL_HZRNLs9-l0U_qhSVk?3B3*/,C\+EF?f!B@fO]Kj9_h?=pR=4at-VaAFW8p`I[D=*;9K %s3CV3.>f)G9j7La%(63p"rR3>$3)ecr\YW[Pl^%Dgjhes:0AY6_4h"c#=ooN0-&uT'nk2SFptn>>(WIu(kh0Go%N?;E1_f8_6D-@ %+K7`B+M)`j7Htfc>CL!G)&E_V"8r%_)RtuYI\5e^-BH1b#^AIFo*<Y7U.`<fkj/q%PX^73"tiEj?fS*gU6u!*;!&[hS-\qNf)U0C %Y5t1/7N<*>(2Q;+c>ua6JGAm8c[H8*!KA=F:%6mNVkgJ8A)fQGNg+X,X9ihR`IZA9:epclY]H,!&01]6F$X;b[J[@O\,"roEe>NU %\",])DaX:#B^:4lm/H1"-j#2O!/hP>)D!8hhsocWf[&+HCAZoKkGUjD=b1%a6XVDg)pSJsG[kGAS(+m!q#]3+ZeaR>:&YTNIolN` %I^018r0qON47LbA^YRN,5O]$TamjO^FhTT!rsoOub:E~> %AI9_PrivateDataEnd \ No newline at end of file
diff --git a/docs/xen-api/xenapi-coversheet.tex b/docs/xen-api/xenapi-coversheet.tex
new file mode 100644
index 0000000000..35beca7e09
--- /dev/null
+++ b/docs/xen-api/xenapi-coversheet.tex
@@ -0,0 +1,40 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+%% Document title
+\newcommand{\doctitle}{Xen Management API Draft}
+
+\newcommand{\coversheetlogo}{xen.eps}
+
+%% Document date
+\newcommand{\datestring}{25th August 2006}
+
+\newcommand{\releasestatement}{Open Preview Release\\Comments are welcome!}
+
+%% Document revision
+\newcommand{\revstring}{API Revision 0.4.3 (Draft for discussion)}
+
+%% Document authors
+\newcommand{\docauthors}{
+Ewan Mellor: & {\tt ewan@xensource.com} \\
+Richard Sharp: & {\tt richard.sharp@xensource.com} \\
+David Scott: & {\tt david.scott@xensource.com} \\
+Jon Harrop: & {\tt jon.harrop@xensource.com}
+}
+\newcommand{\legalnotice}{Copyright \copyright{} 2006 XenSource, Inc.\\ \\
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU Free Documentation License, Version 1.2 or any later
+version published by the Free Software Foundation; with no Invariant Sections,
+no Front-Cover Texts and no Back-Cover Texts. A copy of the license is
+included in the section entitled "GNU Free Documentation License".
+}
diff --git a/docs/xen-api/xenapi-datamodel-graph.dot b/docs/xen-api/xenapi-datamodel-graph.dot
new file mode 100644
index 0000000000..794d9ea17a
--- /dev/null
+++ b/docs/xen-api/xenapi-datamodel-graph.dot
@@ -0,0 +1,17 @@
+digraph g{
+node [ shape=box ]; session [ URL="session.html" ] task [ URL="task.html" ] VM [ URL="VM.html" ] host [ URL="host.html" ] host_cpu [ URL="host_cpu.html" ] network [ URL="network.html" ] VIF [ URL="VIF.html" ] PIF [ URL="PIF.html" ] SR [ URL="SR.html" ] VDI [ URL="VDI.html" ] VBD [ URL="VBD.html" ] VTPM [ URL="VTPM.html" ] user [ URL="user.html" ] debug [ URL="debug.html" ];
+session -> host [ label="this_host(1)" ]
+session -> user [ label="this_user(1)" ]
+host -> VM [ color="blue", arrowhead="crow", arrowtail="none" ]
+host -> host_cpu [ color="blue", arrowhead="crow", arrowtail="none" ]
+VIF -> VM [ color="blue", arrowhead="none", arrowtail="crow" ]
+VIF -> network [ color="blue", arrowhead="none", arrowtail="crow" ]
+PIF -> host [ color="blue", arrowhead="none", arrowtail="crow" ]
+PIF -> network [ color="blue", arrowhead="none", arrowtail="crow" ]
+SR -> VDI [ color="blue", arrowhead="crow", arrowtail="none" ]
+VDI -> VBD [ color="blue", arrowhead="crow", arrowtail="none" ]
+VDI -> VDI [ color="blue", arrowhead="none", arrowtail="crow" ]
+VBD -> VM [ color="blue", arrowhead="none", arrowtail="crow" ]
+VTPM -> VM [ label="backend(1)" ]
+VTPM -> VM [ color="blue", arrowhead="none", arrowtail="crow" ]
+}
diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex
new file mode 100644
index 0000000000..8c06fb8a33
--- /dev/null
+++ b/docs/xen-api/xenapi-datamodel.tex
@@ -0,0 +1,9648 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\chapter{API Reference}
+\label{api-reference}
+
+
+\section{Classes}
+The following classes are defined:
+
+\begin{center}\begin{tabular}{|lp{10cm}|}
+\hline
+Name & Description \\
+\hline
+{\tt session} & A session \\
+{\tt task} & A longrunning asynchronous task \\
+{\tt VM} & A virtual machine (or 'guest') \\
+{\tt host} & A physical host \\
+{\tt host\_cpu} & A physical CPU \\
+{\tt network} & A virtual network \\
+{\tt VIF} & A virtual network interface \\
+{\tt PIF} & A physical network interface (note separate VLANs are represented as several PIFs) \\
+{\tt SR} & A storage repository \\
+{\tt VDI} & A virtual disk image \\
+{\tt VBD} & A virtual block device \\
+{\tt VTPM} & A virtual TPM device \\
+{\tt user} & A user of the system \\
+{\tt debug} & A basic class for testing \\
+\hline
+\end{tabular}\end{center}
+\section{Relationships Between Classes}
+Fields that are bound together are shown in the following table:
+\begin{center}\begin{tabular}{|ll|l|}
+\hline
+{\em object.field} & {\em object.field} & {\em relationship} \\
+
+\hline
+VDI.VBDs & VBD.VDI & many-to-one\\
+VDI.parent & VDI.children & one-to-many\\
+VBD.VM & VM.VBDs & one-to-many\\
+VIF.VM & VM.VIFs & one-to-many\\
+VIF.network & network.VIFs & one-to-many\\
+PIF.host & host.PIFs & one-to-many\\
+PIF.network & network.PIFs & one-to-many\\
+SR.VDIs & VDI.SR & many-to-one\\
+VTPM.VM & VM.VTPMs & one-to-many\\
+host.resident\_VMs & VM.resident\_on & many-to-one\\
+host.host\_CPUs & host\_cpu.host & many-to-one\\
+\hline
+\end{tabular}\end{center}
+
+The following represents bound fields (as specified above) diagramatically, using crows-foot notation to specify one-to-one, one-to-many or many-to-many
+ relationships:
+
+\begin{center}\resizebox{0.8\textwidth}{!}{
+\includegraphics{xenapi-datamodel-graph}
+}\end{center}
+\
+\subsection{List of bound fields}
+\section{Types}
+\subsection{Primitives}
+The following primitive types are used to specify methods and fields in the API Reference:
+
+\begin{center}\begin{tabular}{|ll|}
+\hline
+Type & Description \\
+\hline
+String & text strings \\
+Int & 64-bit integers \\
+Float & IEEE double-precision floating-point numbers \\
+Bool & boolean \\
+DateTime & date and timestamp \\
+Ref (object name) & reference to an object of class name \\
+\hline
+\end{tabular}\end{center}
+\subsection{Higher order types}
+The following type constructors are used:
+
+\begin{center}\begin{tabular}{|ll|}
+\hline
+Type & Description \\
+\hline
+List (t) & an arbitrary-length list of elements of type t \\
+Map (a $\rightarrow$ b) & a table mapping values of type a to values of type b \\
+\hline
+\end{tabular}\end{center}
+\subsection{Enumeration types}
+The following enumeration types are used:
+
+\begin{longtable}{|ll|}
+\hline
+{\tt enum vdi\_type} & \\
+\hline
+\hspace{0.5cm}{\tt system} & a disk that may be replaced on upgrade \\
+\hspace{0.5cm}{\tt user} & a disk that is always preserved on upgrade \\
+\hspace{0.5cm}{\tt ephemeral} & a disk that may be reformatted on upgrade \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum vm\_power\_state} & \\
+\hline
+\hspace{0.5cm}{\tt Halted} & Halted \\
+\hspace{0.5cm}{\tt Paused} & Paused \\
+\hspace{0.5cm}{\tt Running} & Running \\
+\hspace{0.5cm}{\tt Suspended} & Suspended \\
+\hspace{0.5cm}{\tt ShuttingDown} & Shutting Down \\
+\hspace{0.5cm}{\tt Unknown} & Some other unknown state \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum cpu\_feature} & \\
+\hline
+\hspace{0.5cm}{\tt FPU} & Onboard FPU \\
+\hspace{0.5cm}{\tt VME} & Virtual Mode Extensions \\
+\hspace{0.5cm}{\tt DE} & Debugging Extensions \\
+\hspace{0.5cm}{\tt PSE} & Page Size Extensions \\
+\hspace{0.5cm}{\tt TSC} & Time Stamp Counter \\
+\hspace{0.5cm}{\tt MSR} & Model-Specific Registers, RDMSR, WRMSR \\
+\hspace{0.5cm}{\tt PAE} & Physical Address Extensions \\
+\hspace{0.5cm}{\tt MCE} & Machine Check Architecture \\
+\hspace{0.5cm}{\tt CX8} & CMPXCHG8 instruction \\
+\hspace{0.5cm}{\tt APIC} & Onboard APIC \\
+\hspace{0.5cm}{\tt SEP} & SYSENTER/SYSEXIT \\
+\hspace{0.5cm}{\tt MTRR} & Memory Type Range Registers \\
+\hspace{0.5cm}{\tt PGE} & Page Global Enable \\
+\hspace{0.5cm}{\tt MCA} & Machine Check Architecture \\
+\hspace{0.5cm}{\tt CMOV} & CMOV instruction (FCMOVCC and FCOMI too if FPU present) \\
+\hspace{0.5cm}{\tt PAT} & Page Attribute Table \\
+\hspace{0.5cm}{\tt PSE36} & 36-bit PSEs \\
+\hspace{0.5cm}{\tt PN} & Processor serial number \\
+\hspace{0.5cm}{\tt CLFLSH} & Supports the CLFLUSH instruction \\
+\hspace{0.5cm}{\tt DTES} & Debug Trace Store \\
+\hspace{0.5cm}{\tt ACPI} & ACPI via MSR \\
+\hspace{0.5cm}{\tt MMX} & Multimedia Extensions \\
+\hspace{0.5cm}{\tt FXSR} & FXSAVE and FXRSTOR instructions (fast save and restore \\
+\hspace{0.5cm}{\tt XMM} & Streaming SIMD Extensions \\
+\hspace{0.5cm}{\tt XMM2} & Streaming SIMD Extensions-2 \\
+\hspace{0.5cm}{\tt SELFSNOOP} & CPU self snoop \\
+\hspace{0.5cm}{\tt HT} & Hyper-Threading \\
+\hspace{0.5cm}{\tt ACC} & Automatic clock control \\
+\hspace{0.5cm}{\tt IA64} & IA-64 processor \\
+\hspace{0.5cm}{\tt SYSCALL} & SYSCALL/SYSRET \\
+\hspace{0.5cm}{\tt MP} & MP Capable. \\
+\hspace{0.5cm}{\tt NX} & Execute Disable \\
+\hspace{0.5cm}{\tt MMXEXT} & AMD MMX extensions \\
+\hspace{0.5cm}{\tt LM} & Long Mode (x86-64) \\
+\hspace{0.5cm}{\tt 3DNOWEXT} & AMD 3DNow! extensions \\
+\hspace{0.5cm}{\tt 3DNOW} & 3DNow! \\
+\hspace{0.5cm}{\tt RECOVERY} & CPU in recovery mode \\
+\hspace{0.5cm}{\tt LONGRUN} & Longrun power control \\
+\hspace{0.5cm}{\tt LRTI} & LongRun table interface \\
+\hspace{0.5cm}{\tt CXMMX} & Cyrix MMX extensions \\
+\hspace{0.5cm}{\tt K6\_MTRR} & AMD K6 nonstandard MTRRs \\
+\hspace{0.5cm}{\tt CYRIX\_ARR} & Cyrix ARRs (= MTRRs) \\
+\hspace{0.5cm}{\tt CENTAUR\_MCR} & Centaur MCRs (= MTRRs) \\
+\hspace{0.5cm}{\tt K8} & Opteron, Athlon64 \\
+\hspace{0.5cm}{\tt K7} & Athlon \\
+\hspace{0.5cm}{\tt P3} & P3 \\
+\hspace{0.5cm}{\tt P4} & P4 \\
+\hspace{0.5cm}{\tt CONSTANT\_TSC} & TSC ticks at a constant rate \\
+\hspace{0.5cm}{\tt FXSAVE\_LEAK} & FXSAVE leaks FOP/FIP/FOP \\
+\hspace{0.5cm}{\tt XMM3} & Streaming SIMD Extensions-3 \\
+\hspace{0.5cm}{\tt MWAIT} & Monitor/Mwait support \\
+\hspace{0.5cm}{\tt DSCPL} & CPL Qualified Debug Store \\
+\hspace{0.5cm}{\tt EST} & Enhanced SpeedStep \\
+\hspace{0.5cm}{\tt TM2} & Thermal Monitor 2 \\
+\hspace{0.5cm}{\tt CID} & Context ID \\
+\hspace{0.5cm}{\tt CX16} & CMPXCHG16B \\
+\hspace{0.5cm}{\tt XTPR} & Send Task Priority Messages \\
+\hspace{0.5cm}{\tt XSTORE} & on-CPU RNG present (xstore insn) \\
+\hspace{0.5cm}{\tt XSTORE\_EN} & on-CPU RNG enabled \\
+\hspace{0.5cm}{\tt XCRYPT} & on-CPU crypto (xcrypt insn) \\
+\hspace{0.5cm}{\tt XCRYPT\_EN} & on-CPU crypto enabled \\
+\hspace{0.5cm}{\tt LAHF\_LM} & LAHF/SAHF in long mode \\
+\hspace{0.5cm}{\tt CMP\_LEGACY} & If yes HyperThreading not valid \\
+\hspace{0.5cm}{\tt VMX} & VMX instruction set \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum on\_normal\_exit} & \\
+\hline
+\hspace{0.5cm}{\tt destroy} & destroy the VM state \\
+\hspace{0.5cm}{\tt restart} & restart the VM \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum on\_crash\_behaviour} & \\
+\hline
+\hspace{0.5cm}{\tt destroy} & destroy the VM state \\
+\hspace{0.5cm}{\tt coredump\_and\_destroy} & record a coredump and then destroy the VM state \\
+\hspace{0.5cm}{\tt restart} & restart the VM \\
+\hspace{0.5cm}{\tt coredump\_and\_restart} & record a coredump and then restart the VM \\
+\hspace{0.5cm}{\tt preserve} & leave the crashed VM as-is \\
+\hspace{0.5cm}{\tt rename\_restart} & rename the crashed VM and start a new copy \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum boot\_type} & \\
+\hline
+\hspace{0.5cm}{\tt bios} & boot an HVM guest using an emulated BIOS \\
+\hspace{0.5cm}{\tt grub} & boot from inside the machine using grub \\
+\hspace{0.5cm}{\tt kernel\_external} & boot from an external kernel \\
+\hspace{0.5cm}{\tt kernel\_internal} & boot from a kernel inside the guest filesystem \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum vbd\_mode} & \\
+\hline
+\hspace{0.5cm}{\tt RO} & disk is mounted read-only \\
+\hspace{0.5cm}{\tt RW} & disk is mounted read-write \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+\begin{longtable}{|ll|}
+\hline
+{\tt enum driver\_type} & \\
+\hline
+\hspace{0.5cm}{\tt ioemu} & use hardware emulation \\
+\hspace{0.5cm}{\tt paravirtualised} & use paravirtualised driver \\
+\hline
+\end{longtable}
+
+\vspace{1cm}
+
+\newpage
+\section{Class: session}
+\subsection{Fields for class: session}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf session} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A session}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{ins}$ & {\tt this\_host} & host ref & Currently connected host \\
+$\mathit{RO}_\mathit{ins}$ & {\tt this\_user} & user ref & Currently connected user \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: session}
+\subsubsection{RPC name:~login\_with\_password}
+
+{\bf Overview:}
+Attempt to authenticate the user, returning a session\_id if successful
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (session ref) login_with_password (string uname, string pwd)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uname & Username for login. \\ \hline
+
+{\tt string } & pwd & Password for login. \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+session ref
+}
+
+
+ID of newly created session
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~logout}
+
+{\bf Overview:}
+Log out of a session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void logout (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_this\_host}
+
+{\bf Overview:}
+get accessor message derived from field this\_host of object session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) get_this_host (session_id s, session ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt session ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_this\_user}
+
+{\bf Overview:}
+get accessor message derived from field this\_user of object session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (user ref) get_this_user (session_id s, session ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt session ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+user ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (session ref) create (session_id s, session record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt session record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+session ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, session ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt session ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the session instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (session ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+session ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class session
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (session record) get_record (session_id s, session ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt session ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+session record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: task}
+\subsection{Fields for class: task}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf task} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A longrunning asynchronous task}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: task}
+\subsubsection{RPC name:~get\_status}
+
+{\bf Overview:}
+Poll a running asynchronous RPC invocation and query its status
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (uuid ref) get_status (session_id s, task ref task)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & task & The ID of the RPC call to poll \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+uuid ref
+}
+
+
+String describing status of specified asynchronous RPC invocation, including estimated completion time
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_all\_tasks}
+
+{\bf Overview:}
+List all asynchronous RPC calls currently executing
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((task ref) Set) get_all_tasks (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(task ref) Set
+}
+
+
+A list of tasks currently executing. Note that
+tasks are associated with users rather than sessions. Thus, if you logout and
+login again with a different session but the same user, this function will still
+return the user's running tasks.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, task ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, task ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, task ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, task ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, task ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (task ref) create (session_id s, task record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+task ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, task ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the task instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (task ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+task ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class task
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (task record) get_record (session_id s, task ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt task ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+task record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the task instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((task ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(task ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: VM}
+\subsection{Fields for class: VM}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VM} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual machine (or 'guest')}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RO}_\mathit{run}$ & {\tt power\_state} & vm\_power\_state & Current power state of the machine \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+$\mathit{RW}$ & {\tt user\_version} & int & a user version number for this machine \\
+$\mathit{RW}$ & {\tt is\_a\_template} & bool & true if this is a template. Template VMs can never be started, they are used only for cloning other VMs \\
+$\mathit{RO}_\mathit{run}$ & {\tt resident\_on} & host ref & the host the VM is currently resident on \\
+$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_max} & int & Statically-set (i.e. absolute) maximum \\
+$\mathit{RW}$ & {\tt memory/dynamic\_max} & int & Dynamic maximum \\
+$\mathit{RO}_\mathit{run}$ & {\tt memory/actual} & int & Guest's actual usage \\
+$\mathit{RW}$ & {\tt memory/dynamic\_min} & int & Dynamic minimum \\
+$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_min} & int & Statically-set (i.e. absolute) mininum \\
+$\mathit{RW}$ & {\tt VCPUs/policy} & string & the name of the VCPU scheduling policy to be applied \\
+$\mathit{RW}$ & {\tt VCPUs/params} & string & string-encoded parameters passed to selected VCPU policy \\
+$\mathit{RO}_\mathit{run}$ & {\tt VCPUs/number} & int & Current number of VCPUs \\
+$\mathit{RO}_\mathit{run}$ & {\tt VCPUs/utilisation} & (int $\rightarrow$ float) Map & Utilisation for all of guest's current VCPUs \\
+$\mathit{RO}_\mathit{ins}$ & {\tt VCPUs/features/required} & (cpu\_feature) Set & CPU features the guest demands the host supports \\
+$\mathit{RO}_\mathit{ins}$ & {\tt VCPUs/features/can\_use} & (cpu\_feature) Set & CPU features the guest can use if available \\
+$\mathit{RW}$ & {\tt VCPUs/features/force\_on} & (cpu\_feature) Set & CPU features to expose to the guest above the bare minimum \\
+$\mathit{RW}$ & {\tt VCPUs/features/force\_off} & (cpu\_feature) Set & CPU features to hide to the guest \\
+$\mathit{RW}$ & {\tt actions/after\_shutdown} & on\_normal\_exit & action to take after the guest has shutdown itself \\
+$\mathit{RW}$ & {\tt actions/after\_reboot} & on\_normal\_exit & action to take after the guest has rebooted itself \\
+$\mathit{RW}$ & {\tt actions/after\_suspend} & on\_normal\_exit & action to take after the guest has suspended itself \\
+$\mathit{RW}$ & {\tt actions/after\_crash} & on\_crash\_behaviour & action to take if the guest crashes \\
+$\mathit{RO}_\mathit{run}$ & {\tt VIFs} & (VIF ref) Set & virtual network interfaces \\
+$\mathit{RO}_\mathit{run}$ & {\tt VBDs} & (VBD ref) Set & virtual block devices \\
+$\mathit{RO}_\mathit{run}$ & {\tt VTPMs} & (VTPM ref) Set & virtual TPMs \\
+$\mathit{RW}$ & {\tt bios/boot} & string & device to boot the guest from \\
+$\mathit{RW}$ & {\tt platform/std\_VGA} & bool & emulate standard VGA instead of cirrus logic \\
+$\mathit{RW}$ & {\tt platform/serial} & string & redirect serial port to pty \\
+$\mathit{RW}$ & {\tt platform/localtime} & bool & set RTC to local time \\
+$\mathit{RW}$ & {\tt platform/clock\_offset} & bool & timeshift applied to guest's clock \\
+$\mathit{RW}$ & {\tt platform/enable\_audio} & bool & emulate audio \\
+$\mathit{RW}$ & {\tt builder} & string & domain builder to use \\
+$\mathit{RW}$ & {\tt boot\_method} & boot\_type & select how this machine should boot \\
+$\mathit{RW}$ & {\tt kernel/kernel} & string & path to kernel e.g. /boot/vmlinuz \\
+$\mathit{RW}$ & {\tt kernel/initrd} & string & path to the initrd e.g. /boot/initrd.img \\
+$\mathit{RW}$ & {\tt kernel/args} & string & extra kernel command-line arguments \\
+$\mathit{RW}$ & {\tt grub/cmdline} & string & grub command-line \\
+$\mathit{RO}_\mathit{ins}$ & {\tt PCI\_bus} & string & PCI bus path for pass-through devices \\
+$\mathit{RO}_\mathit{run}$ & {\tt tools\_version} & (string $\rightarrow$ string) Map & versions of installed paravirtualised drivers \\
+$\mathit{RW}$ & {\tt otherConfig} & (string $\rightarrow$ string) Map & additional configuration \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: VM}
+\subsubsection{RPC name:~clone}
+
+{\bf Overview:}
+Clones the specified VM, making a new VM. Clone automatically exploits the capabilities of the underlying storage repository in which the VM's disk images are stored (e.g. Copy on Write). This function can only be called when the VM is in the Halted State.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) clone (session_id s, VM ref vm, string new_name)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to be cloned \\ \hline
+
+{\tt string } & new\_name & The name of the cloned VM \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+The ID of the newly created VM.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~start}
+
+{\bf Overview:}
+Start the specified VM. This function can only be called with the VM is in the Halted State.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void start (session_id s, VM ref vm, bool start_paused)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to start \\ \hline
+
+{\tt bool } & start\_paused & Instantiate VM in paused state if set to true. \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~pause}
+
+{\bf Overview:}
+Pause the specified VM. This can only be called when the specified VM is in the Running state.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void pause (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to pause \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~unpause}
+
+{\bf Overview:}
+Resume the specified VM. This can only be called when the specified VM is in the Paused state.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void unpause (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to pause \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~clean\_shutdown}
+
+{\bf Overview:}
+Attempt to cleanly shutdown the specified VM. (Note: this may not be supported---e.g. if a guest agent is not installed).
+
+Once shutdown has been completed perform poweroff action specified in guest configuration.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void clean_shutdown (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to shutdown \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~clean\_reboot}
+
+{\bf Overview:}
+Attempt to cleanly shutdown the specified VM (Note: this may not be supported---e.g. if a guest agent is not installed).
+
+Once shutdown has been completed perform reboot action specified in guest configuration.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void clean_reboot (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to shutdown \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~hard\_shutdown}
+
+{\bf Overview:}
+Stop executing the specified VM without attempting a clean shutdown. Then perform poweroff action specified in VM configuration.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void hard_shutdown (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to destroy \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~hard\_reboot}
+
+{\bf Overview:}
+Stop executing the specified VM without attempting a clean shutdown. Then perform reboot action specified in VM configuration
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void hard_reboot (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to reboot \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~suspend}
+
+{\bf Overview:}
+Suspend the specified VM to disk.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void suspend (session_id s, VM ref vm)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to hibernate \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~resume}
+
+{\bf Overview:}
+Awaken the specified VM and resume it.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void resume (session_id s, VM ref vm, bool start_paused)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & vm & The VM to unhibernate \\ \hline
+
+{\tt bool } & start\_paused & Unhibernate VM in paused state if set to true. \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_all}
+
+{\bf Overview:}
+Return a list of all the VMs known to the system.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VM ref) Set) get_all (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VM ref) Set
+}
+
+
+A list of all the IDs of all the VMs
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_power\_state}
+
+{\bf Overview:}
+get accessor message derived from field power\_state of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (vm_power_state) get_power_state (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+vm\_power\_state
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_user\_version}
+
+{\bf Overview:}
+get accessor message derived from field user\_version of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_user_version (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_user\_version}
+
+{\bf Overview:}
+set accessor message derived from field user\_version of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_user_version (session_id s, VM ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_is\_a\_template}
+
+{\bf Overview:}
+get accessor message derived from field is\_a\_template of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_is_a_template (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_is\_a\_template}
+
+{\bf Overview:}
+set accessor message derived from field is\_a\_template of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_is_a_template (session_id s, VM ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_resident\_on}
+
+{\bf Overview:}
+get accessor message derived from field resident\_on of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) get_resident_on (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_memory\_static\_max}
+
+{\bf Overview:}
+get accessor message derived from field memory/static\_max of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_memory_static_max (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_memory\_dynamic\_max}
+
+{\bf Overview:}
+get accessor message derived from field memory/dynamic\_max of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_memory_dynamic_max (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_memory\_dynamic\_max}
+
+{\bf Overview:}
+set accessor message derived from field memory/dynamic\_max of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_memory_dynamic_max (session_id s, VM ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_memory\_actual}
+
+{\bf Overview:}
+get accessor message derived from field memory/actual of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_memory_actual (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_memory\_dynamic\_min}
+
+{\bf Overview:}
+get accessor message derived from field memory/dynamic\_min of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_memory_dynamic_min (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_memory\_dynamic\_min}
+
+{\bf Overview:}
+set accessor message derived from field memory/dynamic\_min of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_memory_dynamic_min (session_id s, VM ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_memory\_static\_min}
+
+{\bf Overview:}
+get accessor message derived from field memory/static\_min of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_memory_static_min (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_policy}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/policy of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_VCPUs_policy (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VCPUs\_policy}
+
+{\bf Overview:}
+set accessor message derived from field VCPUs/policy of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VCPUs_policy (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_params}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/params of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_VCPUs_params (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VCPUs\_params}
+
+{\bf Overview:}
+set accessor message derived from field VCPUs/params of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VCPUs_params (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_number}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/number of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_VCPUs_number (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_utilisation}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/utilisation of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((int -> float) Map) get_VCPUs_utilisation (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(int $\rightarrow$ float) Map
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_features\_required}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/features/required of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_required (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(cpu\_feature) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_features\_can\_use}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/features/can\_use of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_can_use (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(cpu\_feature) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_features\_force\_on}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/features/force\_on of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_force_on (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(cpu\_feature) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~add\_VCPUs\_features\_force\_on}
+
+{\bf Overview:}
+set add message derived from field VCPUs/features/force\_on of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void add_VCPUs_features_force_on (session_id s, VM ref self, cpu_feature value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt cpu\_feature } & value & New value to add \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~remove\_VCPUs\_features\_force\_on}
+
+{\bf Overview:}
+set remove message derived from field VCPUs/features/force\_on of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void remove_VCPUs_features_force_on (session_id s, VM ref self, cpu_feature value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt cpu\_feature } & value & Value to remove \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VCPUs\_features\_force\_off}
+
+{\bf Overview:}
+get accessor message derived from field VCPUs/features/force\_off of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_force_off (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(cpu\_feature) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~add\_VCPUs\_features\_force\_off}
+
+{\bf Overview:}
+set add message derived from field VCPUs/features/force\_off of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void add_VCPUs_features_force_off (session_id s, VM ref self, cpu_feature value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt cpu\_feature } & value & New value to add \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~remove\_VCPUs\_features\_force\_off}
+
+{\bf Overview:}
+set remove message derived from field VCPUs/features/force\_off of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void remove_VCPUs_features_force_off (session_id s, VM ref self, cpu_feature value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt cpu\_feature } & value & Value to remove \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_actions\_after\_shutdown}
+
+{\bf Overview:}
+get accessor message derived from field actions/after\_shutdown of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (on_normal_exit) get_actions_after_shutdown (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+on\_normal\_exit
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_actions\_after\_shutdown}
+
+{\bf Overview:}
+set accessor message derived from field actions/after\_shutdown of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_actions_after_shutdown (session_id s, VM ref self, on_normal_exit value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt on\_normal\_exit } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_actions\_after\_reboot}
+
+{\bf Overview:}
+get accessor message derived from field actions/after\_reboot of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (on_normal_exit) get_actions_after_reboot (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+on\_normal\_exit
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_actions\_after\_reboot}
+
+{\bf Overview:}
+set accessor message derived from field actions/after\_reboot of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_actions_after_reboot (session_id s, VM ref self, on_normal_exit value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt on\_normal\_exit } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_actions\_after\_suspend}
+
+{\bf Overview:}
+get accessor message derived from field actions/after\_suspend of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (on_normal_exit) get_actions_after_suspend (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+on\_normal\_exit
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_actions\_after\_suspend}
+
+{\bf Overview:}
+set accessor message derived from field actions/after\_suspend of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_actions_after_suspend (session_id s, VM ref self, on_normal_exit value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt on\_normal\_exit } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_actions\_after\_crash}
+
+{\bf Overview:}
+get accessor message derived from field actions/after\_crash of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (on_crash_behaviour) get_actions_after_crash (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+on\_crash\_behaviour
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_actions\_after\_crash}
+
+{\bf Overview:}
+set accessor message derived from field actions/after\_crash of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_actions_after_crash (session_id s, VM ref self, on_crash_behaviour value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt on\_crash\_behaviour } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VIFs}
+
+{\bf Overview:}
+get accessor message derived from field VIFs of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VIF ref) Set) get_VIFs (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VIF ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VBDs}
+
+{\bf Overview:}
+get accessor message derived from field VBDs of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VBD ref) Set) get_VBDs (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VBD ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VTPMs}
+
+{\bf Overview:}
+get accessor message derived from field VTPMs of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VTPM ref) Set) get_VTPMs (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VTPM ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_bios\_boot}
+
+{\bf Overview:}
+get accessor message derived from field bios/boot of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_bios_boot (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_bios\_boot}
+
+{\bf Overview:}
+set accessor message derived from field bios/boot of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_bios_boot (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_platform\_std\_VGA}
+
+{\bf Overview:}
+get accessor message derived from field platform/std\_VGA of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_platform_std_VGA (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_platform\_std\_VGA}
+
+{\bf Overview:}
+set accessor message derived from field platform/std\_VGA of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_platform_std_VGA (session_id s, VM ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_platform\_serial}
+
+{\bf Overview:}
+get accessor message derived from field platform/serial of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_platform_serial (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_platform\_serial}
+
+{\bf Overview:}
+set accessor message derived from field platform/serial of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_platform_serial (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_platform\_localtime}
+
+{\bf Overview:}
+get accessor message derived from field platform/localtime of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_platform_localtime (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_platform\_localtime}
+
+{\bf Overview:}
+set accessor message derived from field platform/localtime of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_platform_localtime (session_id s, VM ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_platform\_clock\_offset}
+
+{\bf Overview:}
+get accessor message derived from field platform/clock\_offset of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_platform_clock_offset (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_platform\_clock\_offset}
+
+{\bf Overview:}
+set accessor message derived from field platform/clock\_offset of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_platform_clock_offset (session_id s, VM ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_platform\_enable\_audio}
+
+{\bf Overview:}
+get accessor message derived from field platform/enable\_audio of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_platform_enable_audio (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_platform\_enable\_audio}
+
+{\bf Overview:}
+set accessor message derived from field platform/enable\_audio of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_platform_enable_audio (session_id s, VM ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_builder}
+
+{\bf Overview:}
+get accessor message derived from field builder of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_builder (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_builder}
+
+{\bf Overview:}
+set accessor message derived from field builder of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_builder (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_boot\_method}
+
+{\bf Overview:}
+get accessor message derived from field boot\_method of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (boot_type) get_boot_method (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+boot\_type
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_boot\_method}
+
+{\bf Overview:}
+set accessor message derived from field boot\_method of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_boot_method (session_id s, VM ref self, boot_type value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt boot\_type } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_kernel\_kernel}
+
+{\bf Overview:}
+get accessor message derived from field kernel/kernel of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_kernel_kernel (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_kernel\_kernel}
+
+{\bf Overview:}
+set accessor message derived from field kernel/kernel of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_kernel_kernel (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_kernel\_initrd}
+
+{\bf Overview:}
+get accessor message derived from field kernel/initrd of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_kernel_initrd (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_kernel\_initrd}
+
+{\bf Overview:}
+set accessor message derived from field kernel/initrd of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_kernel_initrd (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_kernel\_args}
+
+{\bf Overview:}
+get accessor message derived from field kernel/args of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_kernel_args (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_kernel\_args}
+
+{\bf Overview:}
+set accessor message derived from field kernel/args of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_kernel_args (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_grub\_cmdline}
+
+{\bf Overview:}
+get accessor message derived from field grub/cmdline of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_grub_cmdline (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_grub\_cmdline}
+
+{\bf Overview:}
+set accessor message derived from field grub/cmdline of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_grub_cmdline (session_id s, VM ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_PCI\_bus}
+
+{\bf Overview:}
+get accessor message derived from field PCI\_bus of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_PCI_bus (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_tools\_version}
+
+{\bf Overview:}
+get accessor message derived from field tools\_version of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((string -> string) Map) get_tools_version (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(string $\rightarrow$ string) Map
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_otherConfig}
+
+{\bf Overview:}
+get accessor message derived from field otherConfig of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((string -> string) Map) get_otherConfig (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(string $\rightarrow$ string) Map
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~add\_to\_otherConfig}
+
+{\bf Overview:}
+map add message derived from field otherConfig of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void add_to_otherConfig (session_id s, VM ref self, string key, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & key & Key to add \\ \hline
+
+{\tt string } & value & Value to add \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~remove\_from\_otherConfig}
+
+{\bf Overview:}
+map remove message derived from field otherConfig of object VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void remove_from_otherConfig (session_id s, VM ref self, string key)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+{\tt string } & key & Key to remove \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) create (session_id s, VM record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the VM instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class VM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM record) get_record (session_id s, VM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VM ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the VM instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VM ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VM ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: host}
+\subsection{Fields for class: host}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf host} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A physical host}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+$\mathit{RO}_\mathit{run}$ & {\tt software\_version} & (string $\rightarrow$ string) Map & version strings \\
+$\mathit{RO}_\mathit{run}$ & {\tt resident\_VMs} & (VM ref) Set & list of VMs currently resident on host \\
+$\mathit{RO}_\mathit{run}$ & {\tt PIFs} & (PIF ref) Set & physical network interfaces \\
+$\mathit{RO}_\mathit{run}$ & {\tt host\_CPUs} & (host\_cpu ref) Set & The physical CPUs on this host \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: host}
+\subsubsection{RPC name:~disable}
+
+{\bf Overview:}
+Puts the host into a state in which no new VMs can be started. Currently active VMs on the host continue to execute.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void disable (session_id s, host ref host)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & host & The Host to disable \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~enable}
+
+{\bf Overview:}
+Puts the host into a state in which new VMs can be started.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void enable (session_id s, host ref host)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & host & The Host to enable \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~shutdown}
+
+{\bf Overview:}
+Shutdown the host. (This function can only be called if there are no currently running VMs on the host and it is disabled.)
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void shutdown (session_id s, host ref host)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & host & The Host to shutdown \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~reboot}
+
+{\bf Overview:}
+Reboot the host. (This function can only be called if there are no currently running VMs on the host and it is disabled.)
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void reboot (session_id s, host ref host)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & host & The Host to reboot \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_all}
+
+{\bf Overview:}
+Return a list of all the hosts known to the system
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((host ref) Set) get_all (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(host ref) Set
+}
+
+
+A list of all the IDs of all the hosts
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, host ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, host ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_software\_version}
+
+{\bf Overview:}
+get accessor message derived from field software\_version of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((string -> string) Map) get_software_version (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(string $\rightarrow$ string) Map
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_resident\_VMs}
+
+{\bf Overview:}
+get accessor message derived from field resident\_VMs of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VM ref) Set) get_resident_VMs (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VM ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_PIFs}
+
+{\bf Overview:}
+get accessor message derived from field PIFs of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((PIF ref) Set) get_PIFs (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(PIF ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_host\_CPUs}
+
+{\bf Overview:}
+get accessor message derived from field host\_CPUs of object host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((host_cpu ref) Set) get_host_CPUs (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(host\_cpu ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) create (session_id s, host record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the host instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class host
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host record) get_record (session_id s, host ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the host instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((host ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(host ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: host\_cpu}
+\subsection{Fields for class: host\_cpu}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf host\_cpu} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A physical CPU}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RO}_\mathit{ins}$ & {\tt host} & host ref & the host the CPU is in \\
+$\mathit{RO}_\mathit{ins}$ & {\tt number} & int & the number of the physical CPU within the host \\
+$\mathit{RO}_\mathit{ins}$ & {\tt vendor} & string & the vendor of the physical CPU \\
+$\mathit{RO}_\mathit{ins}$ & {\tt speed} & int & the speed of the physical CPU \\
+$\mathit{RO}_\mathit{ins}$ & {\tt modelname} & string & the model name of the physical CPU \\
+$\mathit{RO}_\mathit{ins}$ & {\tt features} & (cpu\_feature) Set & the features supported by the CPU \\
+$\mathit{RO}_\mathit{run}$ & {\tt utilisation} & float & the current CPU utilisation \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: host\_cpu}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_host}
+
+{\bf Overview:}
+get accessor message derived from field host of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) get_host (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_number}
+
+{\bf Overview:}
+get accessor message derived from field number of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_number (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_vendor}
+
+{\bf Overview:}
+get accessor message derived from field vendor of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_vendor (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_speed}
+
+{\bf Overview:}
+get accessor message derived from field speed of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_speed (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_modelname}
+
+{\bf Overview:}
+get accessor message derived from field modelname of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_modelname (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_features}
+
+{\bf Overview:}
+get accessor message derived from field features of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((cpu_feature) Set) get_features (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(cpu\_feature) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_utilisation}
+
+{\bf Overview:}
+get accessor message derived from field utilisation of object host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_utilisation (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host_cpu ref) create (session_id s, host_cpu record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host\_cpu ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the host\_cpu instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host_cpu ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host\_cpu ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class host\_cpu
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host_cpu record) get_record (session_id s, host_cpu ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt host\_cpu ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host\_cpu record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: network}
+\subsection{Fields for class: network}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf network} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual network}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+$\mathit{RO}_\mathit{run}$ & {\tt VIFs} & (VIF ref) Set & list of connected vifs \\
+$\mathit{RO}_\mathit{run}$ & {\tt PIFs} & (PIF ref) Set & list of connected pifs \\
+$\mathit{RW}$ & {\tt default\_gateway} & string & default gateway IP address. Used for auto-configuring guests with fixed IP setting \\
+$\mathit{RW}$ & {\tt default\_netmask} & string & default netmask. Used for auto-configuring guests with fixed IP setting \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: network}
+\subsubsection{RPC name:~get\_all}
+
+{\bf Overview:}
+Return a list of all the networks known to the system
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((network ref) Set) get_all (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(network ref) Set
+}
+
+
+A list of all the IDs of all the networks
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, network ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, network ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VIFs}
+
+{\bf Overview:}
+get accessor message derived from field VIFs of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VIF ref) Set) get_VIFs (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VIF ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_PIFs}
+
+{\bf Overview:}
+get accessor message derived from field PIFs of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((PIF ref) Set) get_PIFs (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(PIF ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_default\_gateway}
+
+{\bf Overview:}
+get accessor message derived from field default\_gateway of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_default_gateway (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_default\_gateway}
+
+{\bf Overview:}
+set accessor message derived from field default\_gateway of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_default_gateway (session_id s, network ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_default\_netmask}
+
+{\bf Overview:}
+get accessor message derived from field default\_netmask of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_default_netmask (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_default\_netmask}
+
+{\bf Overview:}
+set accessor message derived from field default\_netmask of object network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_default_netmask (session_id s, network ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (network ref) create (session_id s, network record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+network ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the network instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (network ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+network ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class network
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (network record) get_record (session_id s, network ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt network ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+network record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the network instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((network ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(network ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: VIF}
+\subsection{Fields for class: VIF}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VIF} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual network interface}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name} & string & human-readable name of the interface \\
+$\mathit{RW}$ & {\tt type} & driver\_type & interface type \\
+$\mathit{RW}$ & {\tt device} & string & name of network device as exposed to guest e.g. eth0 \\
+$\mathit{RW}$ & {\tt network} & network ref & virtual network to which this vif is connected \\
+$\mathit{RW}$ & {\tt VM} & VM ref & virtual machine to which this vif is connected \\
+$\mathit{RW}$ & {\tt MAC} & string & ethernet MAC address of virtual interface, as exposed to guest \\
+$\mathit{RW}$ & {\tt MTU} & int & MTU in octets \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s) \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: VIF}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name}
+
+{\bf Overview:}
+get accessor message derived from field name of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name}
+
+{\bf Overview:}
+set accessor message derived from field name of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name (session_id s, VIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_type}
+
+{\bf Overview:}
+get accessor message derived from field type of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (driver_type) get_type (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+driver\_type
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_type}
+
+{\bf Overview:}
+set accessor message derived from field type of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_type (session_id s, VIF ref self, driver_type value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt driver\_type } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_device}
+
+{\bf Overview:}
+get accessor message derived from field device of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_device (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_device}
+
+{\bf Overview:}
+set accessor message derived from field device of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_device (session_id s, VIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_network}
+
+{\bf Overview:}
+get accessor message derived from field network of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (network ref) get_network (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+network ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_network}
+
+{\bf Overview:}
+set accessor message derived from field network of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_network (session_id s, VIF ref self, network ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt network ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VM}
+
+{\bf Overview:}
+get accessor message derived from field VM of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) get_VM (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VM}
+
+{\bf Overview:}
+set accessor message derived from field VM of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VM (session_id s, VIF ref self, VM ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt VM ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_MAC}
+
+{\bf Overview:}
+get accessor message derived from field MAC of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_MAC (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_MAC}
+
+{\bf Overview:}
+set accessor message derived from field MAC of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_MAC (session_id s, VIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_MTU}
+
+{\bf Overview:}
+get accessor message derived from field MTU of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_MTU (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_MTU}
+
+{\bf Overview:}
+set accessor message derived from field MTU of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_MTU (session_id s, VIF ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_read\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/read\_kbs of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_read_kbs (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_write\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/write\_kbs of object VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_write_kbs (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VIF ref) create (session_id s, VIF record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VIF ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the VIF instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VIF ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VIF ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class VIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VIF record) get_record (session_id s, VIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VIF ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VIF record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: PIF}
+\subsection{Fields for class: PIF}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf PIF} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A physical network interface (note separate VLANs are represented as several PIFs)}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name} & string & human-readable name of the interface \\
+$\mathit{RW}$ & {\tt network} & network ref & virtual network to which this pif is connected \\
+$\mathit{RW}$ & {\tt host} & host ref & physical machine to which this pif is connected \\
+$\mathit{RW}$ & {\tt MAC} & string & ethernet MAC address of physical interface \\
+$\mathit{RW}$ & {\tt MTU} & int & MTU in octets \\
+$\mathit{RW}$ & {\tt VLAN} & string & VLAN tag for all traffic passing through this interface \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s) \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: PIF}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name}
+
+{\bf Overview:}
+get accessor message derived from field name of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name}
+
+{\bf Overview:}
+set accessor message derived from field name of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name (session_id s, PIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_network}
+
+{\bf Overview:}
+get accessor message derived from field network of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (network ref) get_network (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+network ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_network}
+
+{\bf Overview:}
+set accessor message derived from field network of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_network (session_id s, PIF ref self, network ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt network ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_host}
+
+{\bf Overview:}
+get accessor message derived from field host of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (host ref) get_host (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+host ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_host}
+
+{\bf Overview:}
+set accessor message derived from field host of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_host (session_id s, PIF ref self, host ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt host ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_MAC}
+
+{\bf Overview:}
+get accessor message derived from field MAC of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_MAC (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_MAC}
+
+{\bf Overview:}
+set accessor message derived from field MAC of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_MAC (session_id s, PIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_MTU}
+
+{\bf Overview:}
+get accessor message derived from field MTU of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_MTU (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_MTU}
+
+{\bf Overview:}
+set accessor message derived from field MTU of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_MTU (session_id s, PIF ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VLAN}
+
+{\bf Overview:}
+get accessor message derived from field VLAN of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_VLAN (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VLAN}
+
+{\bf Overview:}
+set accessor message derived from field VLAN of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VLAN (session_id s, PIF ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_read\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/read\_kbs of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_read_kbs (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_write\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/write\_kbs of object PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_write_kbs (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (PIF ref) create (session_id s, PIF record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+PIF ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the PIF instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (PIF ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+PIF ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class PIF
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (PIF record) get_record (session_id s, PIF ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt PIF ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+PIF record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: SR}
+\subsection{Fields for class: SR}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf SR} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A storage repository}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+$\mathit{RO}_\mathit{run}$ & {\tt VDIs} & (VDI ref) Set & managed virtual disks \\
+$\mathit{RO}_\mathit{run}$ & {\tt virtual\_allocation} & int & sum of virtual\_sizes of all VDIs in this storage repository (in bytes) \\
+$\mathit{RO}_\mathit{run}$ & {\tt physical\_utilisation} & int & physical space currently utilised on this storage repository (in bytes). Note that for sparse disk formats, physical\_utilisation may be less than virtual\_allocation \\
+$\mathit{RO}_\mathit{ins}$ & {\tt physical\_size} & int & total physical size of the repository (in bytes) \\
+$\mathit{RO}_\mathit{ins}$ & {\tt type} & string & type of the storage repository \\
+$\mathit{RO}_\mathit{ins}$ & {\tt location} & string & a string that uniquely determines the location of the storage repository; the format of this string depends on the repository's type \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: SR}
+\subsubsection{RPC name:~clone}
+
+{\bf Overview:}
+Take an exact copy of the Storage Repository;
+ the cloned storage repository has the same type as its parent
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (SR ref) clone (session_id s, SR ref sr, string loc, string name)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & sr & The Storage Repository to clone \\ \hline
+
+{\tt string } & loc & The location string that defines where the new storage repository will be located \\ \hline
+
+{\tt string } & name & The name of the new storage repository \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+SR ref
+}
+
+
+The ID of the newly created Storage Repository.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_all}
+
+{\bf Overview:}
+Return a list of all the Storage Repositories known to the system
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((SR ref) Set) get_all (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(SR ref) Set
+}
+
+
+A list of all the IDs of all the Storage Repositories
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, SR ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, SR ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VDIs}
+
+{\bf Overview:}
+get accessor message derived from field VDIs of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VDI ref) Set) get_VDIs (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VDI ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_virtual\_allocation}
+
+{\bf Overview:}
+get accessor message derived from field virtual\_allocation of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_virtual_allocation (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_physical\_utilisation}
+
+{\bf Overview:}
+get accessor message derived from field physical\_utilisation of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_physical_utilisation (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_physical\_size}
+
+{\bf Overview:}
+get accessor message derived from field physical\_size of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_physical_size (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_type}
+
+{\bf Overview:}
+get accessor message derived from field type of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_type (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_location}
+
+{\bf Overview:}
+get accessor message derived from field location of object SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_location (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (SR ref) create (session_id s, SR record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+SR ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the SR instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (SR ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+SR ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class SR
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (SR record) get_record (session_id s, SR ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt SR ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+SR record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the SR instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((SR ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(SR ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: VDI}
+\subsection{Fields for class: VDI}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VDI} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual disk image}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\
+$\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\
+$\mathit{RW}$ & {\tt SR} & SR ref & storage repository in which the VDI resides \\
+$\mathit{RO}_\mathit{run}$ & {\tt VBDs} & (VBD ref) Set & list of vbds that refer to this disk \\
+$\mathit{RW}$ & {\tt virtual\_size} & int & size of disk as presented to the guest (in multiples of sector\_size field) \\
+$\mathit{RO}_\mathit{run}$ & {\tt physical\_utilisation} & int & amount of physical space that the disk image is currently taking up on the storage repository (in bytes) \\
+$\mathit{RO}_\mathit{ins}$ & {\tt sector\_size} & int & sector size of VDI (in bytes) \\
+$\mathit{RO}_\mathit{ins}$ & {\tt type} & vdi\_type & type of the VDI \\
+$\mathit{RO}_\mathit{ins}$ & {\tt parent} & VDI ref & parent disk (e.g. in the case of copy on write) \\
+$\mathit{RO}_\mathit{run}$ & {\tt children} & (VDI ref) Set & child disks (e.g. in the case of copy on write) \\
+$\mathit{RW}$ & {\tt sharable} & bool & true if this disk may be shared \\
+$\mathit{RW}$ & {\tt read\_only} & bool & true if this disk may ONLY be mounted read-only \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: VDI}
+\subsubsection{RPC name:~snapshot}
+
+{\bf Overview:}
+Take an exact copy of the VDI; the snapshot lives in the same Storage Repository as its parent.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI ref) snapshot (session_id s, VDI ref vdi)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & vdi & The VDI to snapshot \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI ref
+}
+
+
+The ID of the newly created VDI.
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~resize}
+
+{\bf Overview:}
+Resize the vdi to the size.
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void resize (session_id s, VDI ref vdi, int size)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & vdi & The VDI to resize \\ \hline
+
+{\tt int } & size & The new size of the VDI \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_label}
+
+{\bf Overview:}
+get accessor message derived from field name/label of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_label (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_label}
+
+{\bf Overview:}
+set accessor message derived from field name/label of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_label (session_id s, VDI ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_name\_description}
+
+{\bf Overview:}
+get accessor message derived from field name/description of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_name_description (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_name\_description}
+
+{\bf Overview:}
+set accessor message derived from field name/description of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_name_description (session_id s, VDI ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_SR}
+
+{\bf Overview:}
+get accessor message derived from field SR of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (SR ref) get_SR (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+SR ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_SR}
+
+{\bf Overview:}
+set accessor message derived from field SR of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_SR (session_id s, VDI ref self, SR ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt SR ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VBDs}
+
+{\bf Overview:}
+get accessor message derived from field VBDs of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VBD ref) Set) get_VBDs (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VBD ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_virtual\_size}
+
+{\bf Overview:}
+get accessor message derived from field virtual\_size of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_virtual_size (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_virtual\_size}
+
+{\bf Overview:}
+set accessor message derived from field virtual\_size of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_virtual_size (session_id s, VDI ref self, int value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt int } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_physical\_utilisation}
+
+{\bf Overview:}
+get accessor message derived from field physical\_utilisation of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_physical_utilisation (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_sector\_size}
+
+{\bf Overview:}
+get accessor message derived from field sector\_size of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_sector_size (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_type}
+
+{\bf Overview:}
+get accessor message derived from field type of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (vdi_type) get_type (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+vdi\_type
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_parent}
+
+{\bf Overview:}
+get accessor message derived from field parent of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI ref) get_parent (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_children}
+
+{\bf Overview:}
+get accessor message derived from field children of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VDI ref) Set) get_children (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VDI ref) Set
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_sharable}
+
+{\bf Overview:}
+get accessor message derived from field sharable of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_sharable (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_sharable}
+
+{\bf Overview:}
+set accessor message derived from field sharable of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_sharable (session_id s, VDI ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_read\_only}
+
+{\bf Overview:}
+get accessor message derived from field read\_only of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} bool get_read_only (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+bool
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_read\_only}
+
+{\bf Overview:}
+set accessor message derived from field read\_only of object VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_read_only (session_id s, VDI ref self, bool value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+{\tt bool } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI ref) create (session_id s, VDI record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the VDI instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class VDI
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI record) get_record (session_id s, VDI ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VDI ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_name\_label}
+
+{\bf Overview:}
+returns the VDI instance with a particular name label
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((VDI ref) Set) get_by_name_label (session_id s, string label)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & label & label of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(VDI ref) Set
+}
+
+
+references to objects with match names
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: VBD}
+\subsection{Fields for class: VBD}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VBD} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual block device}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RW}$ & {\tt VM} & VM ref & the virtual machine \\
+$\mathit{RW}$ & {\tt VDI} & VDI ref & the virtual disk \\
+$\mathit{RW}$ & {\tt device} & string & device seen by the guest e.g. hda1 \\
+$\mathit{RW}$ & {\tt mode} & vbd\_mode & the mode the disk should be mounted with \\
+$\mathit{RW}$ & {\tt driver} & driver\_type & the style of driver \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s) \\
+$\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: VBD}
+\subsubsection{RPC name:~media\_change}
+
+{\bf Overview:}
+Change the media in the device for CDROM-like devices only. For other devices, detach the VBD and attach a new one
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void media_change (session_id s, VBD ref vbd, VDI ref vdi)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & vbd & The vbd representing the CDROM-like device \\ \hline
+
+{\tt VDI ref } & vdi & The new VDI to 'insert' \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VM}
+
+{\bf Overview:}
+get accessor message derived from field VM of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) get_VM (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VM}
+
+{\bf Overview:}
+set accessor message derived from field VM of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VM (session_id s, VBD ref self, VM ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+{\tt VM ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VDI}
+
+{\bf Overview:}
+get accessor message derived from field VDI of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VDI ref) get_VDI (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VDI ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_VDI}
+
+{\bf Overview:}
+set accessor message derived from field VDI of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_VDI (session_id s, VBD ref self, VDI ref value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+{\tt VDI ref } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_device}
+
+{\bf Overview:}
+get accessor message derived from field device of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_device (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_device}
+
+{\bf Overview:}
+set accessor message derived from field device of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_device (session_id s, VBD ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_mode}
+
+{\bf Overview:}
+get accessor message derived from field mode of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (vbd_mode) get_mode (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+vbd\_mode
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_mode}
+
+{\bf Overview:}
+set accessor message derived from field mode of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_mode (session_id s, VBD ref self, vbd_mode value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+{\tt vbd\_mode } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_driver}
+
+{\bf Overview:}
+get accessor message derived from field driver of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (driver_type) get_driver (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+driver\_type
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_driver}
+
+{\bf Overview:}
+set accessor message derived from field driver of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_driver (session_id s, VBD ref self, driver_type value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+{\tt driver\_type } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_read\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/read\_kbs of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_read_kbs (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_io\_write\_kbs}
+
+{\bf Overview:}
+get accessor message derived from field io/write\_kbs of object VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} float get_io_write_kbs (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+float
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VBD ref) create (session_id s, VBD record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VBD ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the VBD instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VBD ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VBD ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class VBD
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VBD record) get_record (session_id s, VBD ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VBD ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VBD record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: VTPM}
+\subsection{Fields for class: VTPM}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf VTPM} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A virtual TPM device}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RO}_\mathit{ins}$ & {\tt VM} & VM ref & the virtual machine \\
+$\mathit{RO}_\mathit{ins}$ & {\tt backend} & VM ref & the domain where the backend is located \\
+$\mathit{RO}_\mathit{ins}$ & {\tt driver} & driver\_type & the style of driver \\
+$\mathit{RO}_\mathit{ins}$ & {\tt instance} & int & the instance number the virtual TPM represents \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: VTPM}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_VM}
+
+{\bf Overview:}
+get accessor message derived from field VM of object VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) get_VM (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_backend}
+
+{\bf Overview:}
+get accessor message derived from field backend of object VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VM ref) get_backend (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VM ref
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_driver}
+
+{\bf Overview:}
+get accessor message derived from field driver of object VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (driver_type) get_driver (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+driver\_type
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_instance}
+
+{\bf Overview:}
+get accessor message derived from field instance of object VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} int get_instance (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+int
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VTPM ref) create (session_id s, VTPM record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VTPM ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the VTPM instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VTPM ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VTPM ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class VTPM
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (VTPM record) get_record (session_id s, VTPM ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt VTPM ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+VTPM record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: user}
+\subsection{Fields for class: user}
+\begin{longtable}{|lllp{0.38\textwidth}|}
+\hline
+\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf user} \\
+\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A user of the system}} \\
+\hline
+Quals & Field & Type & Description \\
+\hline
+$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\
+$\mathit{RO}_\mathit{ins}$ & {\tt short\_name} & string & short name (e.g. userid) \\
+$\mathit{RW}$ & {\tt fullname} & string & full name \\
+\hline
+\end{longtable}
+\subsection{Additional RPCs associated with class: user}
+\subsubsection{RPC name:~get\_uuid}
+
+{\bf Overview:}
+get accessor message derived from field uuid of object user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_uuid (session_id s, user ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_short\_name}
+
+{\bf Overview:}
+get accessor message derived from field short\_name of object user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_short_name (session_id s, user ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_fullname}
+
+{\bf Overview:}
+get accessor message derived from field fullname of object user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} string get_fullname (session_id s, user ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+string
+}
+
+
+value of the field
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~set\_fullname}
+
+{\bf Overview:}
+set accessor message derived from field fullname of object user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void set_fullname (session_id s, user ref self, string value)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & object instance \\ \hline
+
+{\tt string } & value & New value to set \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (user ref) create (session_id s, user record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+user ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, user ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the user instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (user ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+user ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class user
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (user record) get_record (session_id s, user ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt user ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+user record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\newpage
+\section{Class: debug}
+\subsection{Fields for class: debug}
+{\bf Class debug has no fields.}
+\subsection{Additional RPCs associated with class: debug}
+\subsubsection{RPC name:~get\_all}
+
+{\bf Overview:}
+Return a list of all the debug records known to the system
+
+ \noindent {\bf Signature:}
+\begin{verbatim} ((debug ref) Set) get_all (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+(debug ref) Set
+}
+
+
+A list of all the IDs of all the debug records
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~return\_failure}
+
+{\bf Overview:}
+Return an API 'successful' failure
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void return_failure (session_id s)\end{verbatim}
+
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~create}
+
+{\bf Overview:}
+constructor for class debug
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (debug ref) create (session_id s, debug record args)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt debug record } & args & All constructor arguments \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+debug ref
+}
+
+
+reference to the newly created object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~destroy}
+
+{\bf Overview:}
+destructor for class debug
+
+ \noindent {\bf Signature:}
+\begin{verbatim} void destroy (session_id s, debug ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt debug ref } & self & object instance \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+void
+}
+
+
+
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_by\_uuid}
+
+{\bf Overview:}
+returns the debug instance with a particular uuid
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (debug ref) get_by_uuid (session_id s, string uuid)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt string } & uuid & UUID of object to return \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+debug ref
+}
+
+
+reference to the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+\subsubsection{RPC name:~get\_record}
+
+{\bf Overview:}
+returns a record containing the state of an instance of class debug
+
+ \noindent {\bf Signature:}
+\begin{verbatim} (debug record) get_record (session_id s, debug ref self)\end{verbatim}
+
+
+\noindent{\bf Arguments:}
+
+
+\vspace{0.3cm}
+\begin{tabular}{|c|c|p{7cm}|}
+ \hline
+{\bf type} & {\bf name} & {\bf description} \\ \hline
+{\tt debug ref } & self & reference to the object \\ \hline
+
+\end{tabular}
+
+\vspace{0.3cm}
+
+ \noindent {\bf Return Type:}
+{\tt
+debug record
+}
+
+
+all fields from the object
+\vspace{0.3cm}
+\vspace{0.3cm}
+\vspace{0.3cm}
+
+\vspace{1cm}
+\section{DTD}
+General notes:
+\begin{itemize}
+\item Values of primitive types (int, bool, etc) and higher-order types (Sets, Maps) are encoded as simple strings, rather than being expanded into XML fragments. For example ``5'', ``true'', ``1, 2, 3, 4'', ``(1, 2), (2, 3), (3, 4)''
+\item Values of enumeration types are represented as strings (e.g. ``PAE'', ``3DNow!'')
+\item Object References are represented as UUIDs, written in string form
+\end{itemize}
diff --git a/docs/xen-api/xenapi.tex b/docs/xen-api/xenapi.tex
new file mode 100644
index 0000000000..ff8cfa9fcc
--- /dev/null
+++ b/docs/xen-api/xenapi.tex
@@ -0,0 +1,56 @@
+%
+% Copyright (c) 2006 XenSource, Inc.
+%
+% Permission is granted to copy, distribute and/or modify this document under
+% the terms of the GNU Free Documentation License, Version 1.2 or any later
+% version published by the Free Software Foundation; with no Invariant
+% Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the
+% license is included in the section entitled
+% "GNU Free Documentation License" or the file fdl.tex.
+%
+% Authors: Ewan Mellor, Richard Sharp, Dave Scott, Jon Harrop.
+%
+
+\documentclass{report}
+
+\usepackage{a4wide}
+\usepackage{graphics}
+\usepackage{longtable}
+
+\setlength\topskip{0cm}
+\setlength\topmargin{0cm}
+\setlength\oddsidemargin{0cm}
+\setlength\evensidemargin{0cm}
+\setlength\parindent{0pt}
+
+%% Parameters for coversheet:
+\input{xenapi-coversheet}
+
+\begin{document}
+
+% The coversheet itself
+\include{coversheet}
+
+% ... and off we go!
+
+\chapter{Introduction}
+
+This document contains a proposal for a Xen Management API---an interface for
+remotely configuring and controlling virtualised guests running on a
+Xen-enabled host.
+
+~
+
+{\bf \large This document is an early draft for discussion purposes only.}
+
+~
+
+\input{presentation}
+
+\include{wire-protocol}
+\include{vm-lifecycle}
+\include{todo}
+\include{xenapi-datamodel}
+\include{fdl}
+
+\end{document}
diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
index 9bc4eb37f9..01176a625f 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -55,9 +55,10 @@ EXTRA_SRC += arch/$(EXTRA_INC)
endif
ifeq ($(TARGET_ARCH),ia64)
-CFLAGS += -mfixed-range=f12-f15,f32-f127
-ASFLAGS += -x assembler-with-cpp -ansi -Wall
-ASFLAGS += -mfixed-range=f12-f15,f32-f127
+CFLAGS += -mfixed-range=f2-f5,f12-f15,f32-f127 -mconstant-gp
+ASFLAGS += -x assembler-with-cpp -Wall
+ASFLAGS += -mfixed-range=f2-f5,f12-f15,f32-f127 -fomit-frame-pointer
+ASFLAGS += -fno-builtin -fno-common -fno-strict-aliasing -mconstant-gp
ARCH_LINKS = IA64_LINKS # Special link on ia64 needed
define arch_links
[ -e include/ia64/asm-xsi-offsets.h ] || ln -sf ../../../../xen/include/asm-ia64/asm-xsi-offsets.h include/ia64/asm-xsi-offsets.h
@@ -122,6 +123,7 @@ clean:
rm -f *.o *~ core $(TARGET).elf $(TARGET).raw $(TARGET) $(TARGET).gz
rm -f libminios.a
find . -type l | xargs rm -f
+ rm -f tags TAGS
%.o: %.c $(HDRS) Makefile
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
@@ -137,4 +139,7 @@ endef
cscope:
$(all_sources) > cscope.files
cscope -k -b -q
-
+
+.PHONY: tags
+tags:
+ $(all_sources) | xargs ctags
diff --git a/extras/mini-os/README b/extras/mini-os/README
index d4bab382af..afd880733a 100644
--- a/extras/mini-os/README
+++ b/extras/mini-os/README
@@ -26,5 +26,5 @@ Stuff it doesn't show:
- to start it do the following in domain0 (assuming xend is running)
# xm create domain_config
-this starts the kernel and prints out a bunch of stuff and then every
-1000 timer interrupts the system time.
+this starts the kernel and prints out a bunch of stuff and then once
+every second the system time.
diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c
new file mode 100644
index 0000000000..20031a002e
--- /dev/null
+++ b/extras/mini-os/arch/x86/mm.c
@@ -0,0 +1,428 @@
+/*
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: mm.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes: Grzegorz Milos
+ *
+ * Date: Aug 2003, chages Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: memory management related functions
+ * contains buddy page allocator from Xen.
+ *
+ ****************************************************************************
+ * 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 <os.h>
+#include <hypervisor.h>
+#include <mm.h>
+#include <types.h>
+#include <lib.h>
+#include <xmalloc.h>
+
+#ifdef MM_DEBUG
+#define DEBUG(_f, _a...) \
+ printk("MINI_OS(file=mm.c, line=%d) " _f "\n", __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...) ((void)0)
+#endif
+
+unsigned long *phys_to_machine_mapping;
+extern char *stack;
+extern void page_walk(unsigned long virt_addr);
+
+void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,
+ unsigned long offset, unsigned long level)
+{
+ pgentry_t *tab = (pgentry_t *)start_info.pt_base;
+ unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn);
+ unsigned long prot_e, prot_t, pincmd;
+ mmu_update_t mmu_updates[1];
+ struct mmuext_op pin_request;
+
+ DEBUG("Allocating new L%d pt frame for pt_pfn=%lx, "
+ "prev_l_mfn=%lx, offset=%lx",
+ level, *pt_pfn, prev_l_mfn, offset);
+
+ /* We need to clear the page, otherwise we might fail to map it
+ as a page table page */
+ memset((unsigned long*)pfn_to_virt(*pt_pfn), 0, PAGE_SIZE);
+
+ switch ( level )
+ {
+ case L1_FRAME:
+ prot_e = L1_PROT;
+ prot_t = L2_PROT;
+ pincmd = MMUEXT_PIN_L1_TABLE;
+ break;
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+ case L2_FRAME:
+ prot_e = L2_PROT;
+ prot_t = L3_PROT;
+ pincmd = MMUEXT_PIN_L2_TABLE;
+ break;
+#endif
+#if defined(__x86_64__)
+ case L3_FRAME:
+ prot_e = L3_PROT;
+ prot_t = L4_PROT;
+ pincmd = MMUEXT_PIN_L3_TABLE;
+ break;
+#endif
+ default:
+ printk("new_pt_frame() called with invalid level number %d\n", level);
+ do_exit();
+ break;
+ }
+
+ /* Update the entry */
+#if defined(__x86_64__)
+ tab = pte_to_virt(tab[l4_table_offset(pt_page)]);
+ tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
+#endif
+#if defined(CONFIG_X86_PAE)
+ tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
+#endif
+
+ mmu_updates[0].ptr = ((pgentry_t)tab[l2_table_offset(pt_page)] & PAGE_MASK) +
+ sizeof(pgentry_t) * l1_table_offset(pt_page);
+ mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT |
+ (prot_e & ~_PAGE_RW);
+ if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
+ {
+ printk("PTE for new page table page could not be updated\n");
+ do_exit();
+ }
+
+ /* Pin the page to provide correct protection */
+ pin_request.cmd = pincmd;
+ pin_request.arg1.mfn = pfn_to_mfn(*pt_pfn);
+ if(HYPERVISOR_mmuext_op(&pin_request, 1, NULL, DOMID_SELF) < 0)
+ {
+ printk("ERROR: pinning failed\n");
+ do_exit();
+ }
+
+ /* Now fill the new page table page with entries.
+ Update the page directory as well. */
+ mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
+ mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t;
+ if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
+ {
+ printk("ERROR: mmu_update failed\n");
+ do_exit();
+ }
+
+ *pt_pfn += 1;
+}
+
+/* Checks if a pagetable frame is needed (if weren't allocated by Xen) */
+static int need_pt_frame(unsigned long virt_address, int level)
+{
+ unsigned long hyp_virt_start = HYPERVISOR_VIRT_START;
+#if defined(__x86_64__)
+ unsigned long hyp_virt_end = HYPERVISOR_VIRT_END;
+#else
+ unsigned long hyp_virt_end = 0xffffffff;
+#endif
+
+ /* In general frames will _not_ be needed if they were already
+ allocated to map the hypervisor into our VA space */
+#if defined(__x86_64__)
+ if(level == L3_FRAME)
+ {
+ if(l4_table_offset(virt_address) >=
+ l4_table_offset(hyp_virt_start) &&
+ l4_table_offset(virt_address) <=
+ l4_table_offset(hyp_virt_end))
+ return 0;
+ return 1;
+ } else
+#endif
+
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+ if(level == L2_FRAME)
+ {
+#if defined(__x86_64__)
+ if(l4_table_offset(virt_address) >=
+ l4_table_offset(hyp_virt_start) &&
+ l4_table_offset(virt_address) <=
+ l4_table_offset(hyp_virt_end))
+#endif
+ if(l3_table_offset(virt_address) >=
+ l3_table_offset(hyp_virt_start) &&
+ l3_table_offset(virt_address) <=
+ l3_table_offset(hyp_virt_end))
+ return 0;
+
+ return 1;
+ } else
+#endif /* defined(__x86_64__) || defined(CONFIG_X86_PAE) */
+
+ /* Always need l1 frames */
+ if(level == L1_FRAME)
+ return 1;
+
+ printk("ERROR: Unknown frame level %d, hypervisor %llx,%llx\n",
+ level, hyp_virt_start, hyp_virt_end);
+ return -1;
+}
+
+void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
+{
+ unsigned long start_address, end_address;
+ unsigned long pfn_to_map, pt_pfn = *start_pfn;
+ static mmu_update_t mmu_updates[L1_PAGETABLE_ENTRIES + 1];
+ pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
+ unsigned long mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
+ unsigned long offset;
+ int count = 0;
+
+ pfn_to_map = (start_info.nr_pt_frames - NOT_L1_FRAMES) * L1_PAGETABLE_ENTRIES;
+
+ if (*max_pfn >= virt_to_pfn(HYPERVISOR_VIRT_START))
+ {
+ printk("WARNING: Mini-OS trying to use Xen virtual space. "
+ "Truncating memory from %dMB to ",
+ ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
+ *max_pfn = virt_to_pfn(HYPERVISOR_VIRT_START - PAGE_SIZE);
+ printk("%dMB\n",
+ ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
+ }
+
+ start_address = (unsigned long)pfn_to_virt(pfn_to_map);
+ end_address = (unsigned long)pfn_to_virt(*max_pfn);
+
+ /* We worked out the virtual memory range to map, now mapping loop */
+ printk("Mapping memory range 0x%lx - 0x%lx\n", start_address, end_address);
+
+ while(start_address < end_address)
+ {
+ tab = (pgentry_t *)start_info.pt_base;
+ mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
+
+#if defined(__x86_64__)
+ offset = l4_table_offset(start_address);
+ /* Need new L3 pt frame */
+ if(!(start_address & L3_MASK))
+ if(need_pt_frame(start_address, L3_FRAME))
+ new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
+
+ page = tab[offset];
+ mfn = pte_to_mfn(page);
+ tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
+#endif
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+ offset = l3_table_offset(start_address);
+ /* Need new L2 pt frame */
+ if(!(start_address & L2_MASK))
+ if(need_pt_frame(start_address, L2_FRAME))
+ new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
+
+ page = tab[offset];
+ mfn = pte_to_mfn(page);
+ tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
+#endif
+ offset = l2_table_offset(start_address);
+ /* Need new L1 pt frame */
+ if(!(start_address & L1_MASK))
+ if(need_pt_frame(start_address, L1_FRAME))
+ new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
+
+ page = tab[offset];
+ mfn = pte_to_mfn(page);
+ offset = l1_table_offset(start_address);
+
+ mmu_updates[count].ptr = ((pgentry_t)mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
+ mmu_updates[count].val = (pgentry_t)pfn_to_mfn(pfn_to_map++) << PAGE_SHIFT | L1_PROT;
+ count++;
+ if (count == L1_PAGETABLE_ENTRIES || pfn_to_map == *max_pfn)
+ {
+ if(HYPERVISOR_mmu_update(mmu_updates, count, NULL, DOMID_SELF) < 0)
+ {
+ printk("PTE could not be updated\n");
+ do_exit();
+ }
+ count = 0;
+ }
+ start_address += PAGE_SIZE;
+ }
+
+ *start_pfn = pt_pfn;
+}
+
+
+void mem_test(unsigned long *start_add, unsigned long *end_add)
+{
+ unsigned long mask = 0x10000;
+ unsigned long *pointer;
+
+ for(pointer = start_add; pointer < end_add; pointer++)
+ {
+ if(!(((unsigned long)pointer) & 0xfffff))
+ {
+ printk("Writing to %lx\n", pointer);
+ page_walk((unsigned long)pointer);
+ }
+ *pointer = (unsigned long)pointer & ~mask;
+ }
+
+ for(pointer = start_add; pointer < end_add; pointer++)
+ {
+ if(((unsigned long)pointer & ~mask) != *pointer)
+ printk("Read error at 0x%lx. Read: 0x%lx, should read 0x%lx\n",
+ (unsigned long)pointer,
+ *pointer,
+ ((unsigned long)pointer & ~mask));
+ }
+
+}
+
+static pgentry_t *demand_map_pgt;
+static void *demand_map_area_start;
+
+void arch_init_demand_mapping_area(unsigned long max_pfn)
+{
+ unsigned long mfn;
+ pgentry_t *tab;
+ unsigned long start_addr;
+ unsigned long pt_pfn;
+ unsigned offset;
+
+ /* Round up to four megs. + 1024 rather than + 1023 since we want
+ to be sure we don't end up in the same place we started. */
+ max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1);
+ if (max_pfn == 0 ||
+ (unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >=
+ HYPERVISOR_VIRT_START) {
+ printk("Too much memory; no room for demand map hole.\n");
+ do_exit();
+ }
+
+ demand_map_area_start = pfn_to_virt(max_pfn);
+ printk("Demand map pfns start at %lx (%p).\n", max_pfn,
+ demand_map_area_start);
+ start_addr = (unsigned long)demand_map_area_start;
+
+ tab = (pgentry_t *)start_info.pt_base;
+ mfn = virt_to_mfn(start_info.pt_base);
+ pt_pfn = virt_to_pfn(alloc_page());
+
+#if defined(__x86_64__)
+ offset = l4_table_offset(start_addr);
+ if (!(tab[offset] & _PAGE_PRESENT)) {
+ new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
+ pt_pfn = virt_to_pfn(alloc_page());
+ }
+ ASSERT(tab[offset] & _PAGE_PRESENT);
+ mfn = pte_to_mfn(tab[offset]);
+ tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
+#endif
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+ offset = l3_table_offset(start_addr);
+ if (!(tab[offset] & _PAGE_PRESENT)) {
+ new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
+ pt_pfn = virt_to_pfn(alloc_page());
+ }
+ ASSERT(tab[offset] & _PAGE_PRESENT);
+ mfn = pte_to_mfn(tab[offset]);
+ tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
+#endif
+ offset = l2_table_offset(start_addr);
+ if (tab[offset] & _PAGE_PRESENT) {
+ printk("Demand map area already has a page table covering it?\n");
+ BUG();
+ }
+ demand_map_pgt = pfn_to_virt(pt_pfn);
+ new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
+ ASSERT(tab[offset] & _PAGE_PRESENT);
+ printk("Initialised demand area.\n");
+}
+
+void *map_frames(unsigned long *f, unsigned long n)
+{
+ unsigned long x;
+ unsigned long y = 0;
+ mmu_update_t mmu_updates[16];
+ int rc;
+
+ if (n > 16) {
+ printk("Tried to map too many (%ld) frames at once.\n", n);
+ return NULL;
+ }
+
+ /* Find a run of n contiguous frames */
+ for (x = 0; x <= 1024 - n; x += y + 1) {
+ for (y = 0; y < n; y++)
+ if (demand_map_pgt[x+y] & _PAGE_PRESENT)
+ break;
+ if (y == n)
+ break;
+ }
+ if (y != n) {
+ printk("Failed to map %ld frames!\n", n);
+ return NULL;
+ }
+
+ /* Found it at x. Map it in. */
+ for (y = 0; y < n; y++) {
+ mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]);
+ mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT;
+ }
+
+ rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF);
+ if (rc < 0) {
+ printk("Map %ld failed: %d.\n", n, rc);
+ return NULL;
+ } else {
+ return (void *)(unsigned long)((unsigned long)demand_map_area_start +
+ x * PAGE_SIZE);
+ }
+}
+
+void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
+{
+
+ unsigned long start_pfn, max_pfn;
+
+ printk(" _text: %p\n", &_text);
+ printk(" _etext: %p\n", &_etext);
+ printk(" _edata: %p\n", &_edata);
+ printk(" stack start: %p\n", &stack);
+ printk(" _end: %p\n", &_end);
+
+ /* First page follows page table pages and 3 more pages (store page etc) */
+ start_pfn = PFN_UP(to_phys(start_info.pt_base)) +
+ start_info.nr_pt_frames + 3;
+ max_pfn = start_info.nr_pages;
+
+ printk(" start_pfn: %lx\n", start_pfn);
+ printk(" max_pfn: %lx\n", max_pfn);
+
+ build_pagetable(&start_pfn, &max_pfn);
+
+ *start_pfn_p = start_pfn;
+ *max_pfn_p = max_pfn;
+}
+
diff --git a/extras/mini-os/arch/x86/sched.c b/extras/mini-os/arch/x86/sched.c
new file mode 100644
index 0000000000..e56479b90f
--- /dev/null
+++ b/extras/mini-os/arch/x86/sched.c
@@ -0,0 +1,150 @@
+/*
+ ****************************************************************************
+ * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: sched.c
+ * Author: Grzegorz Milos
+ * Changes: Robert Kaiser
+ *
+ * Date: Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: simple scheduler for Mini-Os
+ *
+ * The scheduler is non-preemptive (cooperative), and schedules according
+ * to Round Robin algorithm.
+ *
+ ****************************************************************************
+ * 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 <os.h>
+#include <hypervisor.h>
+#include <time.h>
+#include <mm.h>
+#include <types.h>
+#include <lib.h>
+#include <xmalloc.h>
+#include <list.h>
+#include <sched.h>
+#include <semaphore.h>
+
+
+#ifdef SCHED_DEBUG
+#define DEBUG(_f, _a...) \
+ printk("MINI_OS(file=sched.c, line=%d) " _f "\n", __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...) ((void)0)
+#endif
+
+
+void dump_stack(struct thread *thread)
+{
+ unsigned long *bottom = (unsigned long *)(thread->stack + 2*4*1024);
+ unsigned long *pointer = (unsigned long *)thread->sp;
+ int count;
+ if(thread == current)
+ {
+#ifdef __i386__
+ asm("movl %%esp,%0"
+ : "=r"(pointer));
+#else
+ asm("movq %%rsp,%0"
+ : "=r"(pointer));
+#endif
+ }
+ printk("The stack for \"%s\"\n", thread->name);
+ for(count = 0; count < 25 && pointer < bottom; count ++)
+ {
+ printk("[0x%lx] 0x%lx\n", pointer, *pointer);
+ pointer++;
+ }
+
+ if(pointer < bottom) printk(" ... continues.\n");
+}
+
+/* Gets run when a new thread is scheduled the first time ever,
+ defined in x86_[32/64].S */
+extern void thread_starter(void);
+
+/* Pushes the specified value onto the stack of the specified thread */
+static void stack_push(struct thread *thread, unsigned long value)
+{
+ thread->sp -= sizeof(unsigned long);
+ *((unsigned long *)thread->sp) = value;
+}
+
+struct thread* create_thread(char *name, void (*function)(void *), void *data)
+{
+ struct thread *thread;
+ unsigned long flags;
+
+ thread = xmalloc(struct thread);
+ /* Allocate 2 pages for stack, stack will be 2pages aligned */
+ thread->stack = (char *)alloc_pages(1);
+ thread->name = name;
+ printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
+ thread->stack);
+
+ thread->sp = (unsigned long)thread->stack + 4096 * 2;
+ /* Save pointer to the thread on the stack, used by current macro */
+ *((unsigned long *)thread->stack) = (unsigned long)thread;
+
+ stack_push(thread, (unsigned long) function);
+ stack_push(thread, (unsigned long) data);
+ thread->ip = (unsigned long) thread_starter;
+
+ /* Not runable, not exited, not sleeping */
+ thread->flags = 0;
+ thread->wakeup_time = 0LL;
+ set_runnable(thread);
+ local_irq_save(flags);
+ if(idle_thread != NULL) {
+ list_add_tail(&thread->thread_list, &idle_thread->thread_list);
+ } else if(function != idle_thread_fn)
+ {
+ printk("BUG: Not allowed to create thread before initialising scheduler.\n");
+ BUG();
+ }
+ local_irq_restore(flags);
+ return thread;
+}
+
+
+void run_idle_thread(void)
+{
+ /* Switch stacks and run the thread */
+#if defined(__i386__)
+ __asm__ __volatile__("mov %0,%%esp\n\t"
+ "push %1\n\t"
+ "ret"
+ :"=m" (idle_thread->sp)
+ :"m" (idle_thread->ip));
+#elif defined(__x86_64__)
+ __asm__ __volatile__("mov %0,%%rsp\n\t"
+ "push %1\n\t"
+ "ret"
+ :"=m" (idle_thread->sp)
+ :"m" (idle_thread->ip));
+#endif
+}
+
+
+
diff --git a/extras/mini-os/arch/x86/setup.c b/extras/mini-os/arch/x86/setup.c
new file mode 100644
index 0000000000..db24b41ebc
--- /dev/null
+++ b/extras/mini-os/arch/x86/setup.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * common.c
+ *
+ * Common stuff special to x86 goes here.
+ *
+ * Copyright (c) 2002-2003, K A Fraser & R Neugebauer
+ * Copyright (c) 2005, Grzegorz Milos, Intel Research Cambridge
+ *
+ * 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 <os.h>
+
+
+/*
+ * Shared page for communicating with the hypervisor.
+ * Events flags go here, for example.
+ */
+shared_info_t *HYPERVISOR_shared_info;
+
+/*
+ * This structure contains start-of-day info, such as pagetable base pointer,
+ * address of the shared_info structure, and things like that.
+ */
+union start_info_union start_info_union;
+
+/*
+ * Just allocate the kernel stack here. SS:ESP is set up to point here
+ * in head.S.
+ */
+char stack[8192];
+
+extern char shared_info[PAGE_SIZE];
+
+/* Assembler interface fns in entry.S. */
+void hypervisor_callback(void);
+void failsafe_callback(void);
+
+#if !defined(CONFIG_X86_PAE)
+#define __pte(x) ((pte_t) { (x) } )
+#else
+#define __pte(x) ({ unsigned long long _x = (x); \
+ ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); })
+#endif
+
+static
+shared_info_t *map_shared_info(unsigned long pa)
+{
+ if ( HYPERVISOR_update_va_mapping(
+ (unsigned long)shared_info, __pte(pa | 7), UVMF_INVLPG) )
+ {
+ printk("Failed to map shared_info!!\n");
+ do_exit();
+ }
+ return (shared_info_t *)shared_info;
+}
+
+void
+arch_init(start_info_t *si)
+{
+ /* Copy the start_info struct to a globally-accessible area. */
+ /* WARN: don't do printk before here, it uses information from
+ shared_info. Use xprintk instead. */
+ memcpy(&start_info, si, sizeof(*si));
+
+ /* set up minimal memory infos */
+ phys_to_machine_mapping = (unsigned long *)start_info.mfn_list;
+
+ /* Grab the shared_info pointer and put it in a safe place. */
+ HYPERVISOR_shared_info = map_shared_info(start_info.shared_info);
+
+ /* Set up event and failsafe callback addresses. */
+#ifdef __i386__
+ HYPERVISOR_set_callbacks(
+ __KERNEL_CS, (unsigned long)hypervisor_callback,
+ __KERNEL_CS, (unsigned long)failsafe_callback);
+#else
+ HYPERVISOR_set_callbacks(
+ (unsigned long)hypervisor_callback,
+ (unsigned long)failsafe_callback, 0);
+#endif
+
+}
+
+void
+arch_print_info(void)
+{
+ printk(" stack: %p-%p\n", stack, stack + 8192);
+}
+
+
diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index 57e835225d..5d60ab70fc 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -35,6 +35,21 @@ typedef struct _ev_action_t {
static ev_action_t ev_actions[NR_EVS];
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data);
+void unbind_all_ports(void)
+{
+ int i;
+
+ for(i=0;i<NR_EVS;i++)
+ {
+ if(ev_actions[i].handler != default_handler)
+ {
+ struct evtchn_close close;
+ mask_evtchn(i);
+ close.port = i;
+ HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+ }
+ }
+}
/*
* Demux events to different handlers.
@@ -88,19 +103,18 @@ void unbind_evtchn(evtchn_port_t port )
int bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
{
- evtchn_op_t op;
+ evtchn_bind_virq_t op;
/* Try to bind the virq to a port */
- op.cmd = EVTCHNOP_bind_virq;
- op.u.bind_virq.virq = virq;
- op.u.bind_virq.vcpu = smp_processor_id();
+ op.virq = virq;
+ op.vcpu = smp_processor_id();
- if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ if ( HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op) != 0 )
{
printk("Failed to bind virtual IRQ %d\n", virq);
return 1;
}
- bind_evtchn(op.u.bind_virq.port, handler, data);
+ bind_evtchn(op.port, handler, data);
return 0;
}
@@ -151,14 +165,13 @@ void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
void *data, evtchn_port_t *port)
{
- evtchn_op_t op;
- op.cmd = EVTCHNOP_alloc_unbound;
- op.u.alloc_unbound.dom = DOMID_SELF;
- op.u.alloc_unbound.remote_dom = pal;
- int err = HYPERVISOR_event_channel_op(&op);
+ evtchn_alloc_unbound_t op;
+ op.dom = DOMID_SELF;
+ op.remote_dom = pal;
+ int err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
if (err)
return err;
- *port = bind_evtchn(op.u.alloc_unbound.port, handler, data);
+ *port = bind_evtchn(op.port, handler, data);
return err;
}
@@ -169,14 +182,13 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
evtchn_handler_t handler, void *data,
evtchn_port_t *local_port)
{
- evtchn_op_t op;
- op.cmd = EVTCHNOP_bind_interdomain;
- op.u.bind_interdomain.remote_dom = pal;
- op.u.bind_interdomain.remote_port = remote_port;
- int err = HYPERVISOR_event_channel_op(&op);
+ evtchn_bind_interdomain_t op;
+ op.remote_dom = pal;
+ op.remote_port = remote_port;
+ int err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op);
if (err)
return err;
- evtchn_port_t port = op.u.bind_interdomain.local_port;
+ evtchn_port_t port = op.local_port;
clear_evtchn(port); /* Without, handler gets invoked now! */
*local_port = bind_evtchn(port, handler, data);
return err;
diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h
index cdb6311845..45b47c1549 100644
--- a/extras/mini-os/include/events.h
+++ b/extras/mini-os/include/events.h
@@ -20,7 +20,7 @@
#define _EVENTS_H_
#include<traps.h>
-#include <xen/event_channel.h>
+#include<xen/event_channel.h>
typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *);
@@ -39,10 +39,9 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
static inline int notify_remote_via_evtchn(evtchn_port_t port)
{
- evtchn_op_t op;
- op.cmd = EVTCHNOP_send;
- op.u.send.port = port;
- return HYPERVISOR_event_channel_op(&op);
+ evtchn_send_t op;
+ op.port = port;
+ return HYPERVISOR_event_channel_op(EVTCHNOP_send, &op);
}
diff --git a/extras/mini-os/include/mm.h b/extras/mini-os/include/mm.h
index 4c820e07e4..cd53a4bf25 100644
--- a/extras/mini-os/include/mm.h
+++ b/extras/mini-os/include/mm.h
@@ -29,182 +29,15 @@
#include <xen/arch-x86_32.h>
#elif defined(__x86_64__)
#include <xen/arch-x86_64.h>
+#elif defined(__ia64__)
+#include <xen/arch-ia64.h>
#else
#error "Unsupported architecture"
#endif
#include <lib.h>
+#include <arch_mm.h>
-#define L1_FRAME 1
-#define L2_FRAME 2
-#define L3_FRAME 3
-
-#define L1_PAGETABLE_SHIFT 12
-
-#if defined(__i386__)
-
-#if !defined(CONFIG_X86_PAE)
-
-#define L2_PAGETABLE_SHIFT 22
-
-#define L1_PAGETABLE_ENTRIES 1024
-#define L2_PAGETABLE_ENTRIES 1024
-
-#define PADDR_BITS 32
-#define PADDR_MASK (~0UL)
-
-#define NOT_L1_FRAMES 1
-#define PRIpte "08lx"
-typedef unsigned long pgentry_t;
-
-#else /* defined(CONFIG_X86_PAE) */
-
-#define L2_PAGETABLE_SHIFT 21
-#define L3_PAGETABLE_SHIFT 30
-
-#define L1_PAGETABLE_ENTRIES 512
-#define L2_PAGETABLE_ENTRIES 512
-#define L3_PAGETABLE_ENTRIES 4
-
-#define PADDR_BITS 44
-#define PADDR_MASK ((1ULL << PADDR_BITS)-1)
-
-#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1)
-
-/*
- * If starting from virtual address greater than 0xc0000000,
- * this value will be 2 to account for final mid-level page
- * directory which is always mapped in at this location.
- */
-#define NOT_L1_FRAMES 3
-#define PRIpte "016llx"
-typedef uint64_t pgentry_t;
-
-#endif /* !defined(CONFIG_X86_PAE) */
-
-#elif defined(__x86_64__)
-
-#define L2_PAGETABLE_SHIFT 21
-#define L3_PAGETABLE_SHIFT 30
-#define L4_PAGETABLE_SHIFT 39
-
-#define L1_PAGETABLE_ENTRIES 512
-#define L2_PAGETABLE_ENTRIES 512
-#define L3_PAGETABLE_ENTRIES 512
-#define L4_PAGETABLE_ENTRIES 512
-
-/* These are page-table limitations. Current CPUs support only 40-bit phys. */
-#define PADDR_BITS 52
-#define VADDR_BITS 48
-#define PADDR_MASK ((1UL << PADDR_BITS)-1)
-#define VADDR_MASK ((1UL << VADDR_BITS)-1)
-
-#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1)
-#define L3_MASK ((1UL << L4_PAGETABLE_SHIFT) - 1)
-
-#define NOT_L1_FRAMES 3
-#define PRIpte "016lx"
-typedef unsigned long pgentry_t;
-
-#endif
-
-#define L1_MASK ((1UL << L2_PAGETABLE_SHIFT) - 1)
-
-/* Given a virtual address, get an entry offset into a page table. */
-#define l1_table_offset(_a) \
- (((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
-#define l2_table_offset(_a) \
- (((_a) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1))
-#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
-#define l3_table_offset(_a) \
- (((_a) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1))
-#endif
-#if defined(__x86_64__)
-#define l4_table_offset(_a) \
- (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1))
-#endif
-
-#define _PAGE_PRESENT 0x001UL
-#define _PAGE_RW 0x002UL
-#define _PAGE_USER 0x004UL
-#define _PAGE_PWT 0x008UL
-#define _PAGE_PCD 0x010UL
-#define _PAGE_ACCESSED 0x020UL
-#define _PAGE_DIRTY 0x040UL
-#define _PAGE_PAT 0x080UL
-#define _PAGE_PSE 0x080UL
-#define _PAGE_GLOBAL 0x100UL
-
-#if defined(__i386__)
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY |_PAGE_USER)
-#if defined(CONFIG_X86_PAE)
-#define L3_PROT (_PAGE_PRESENT)
-#endif /* CONFIG_X86_PAE */
-#elif defined(__x86_64__)
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#endif /* __i386__ || __x86_64__ */
-
-#ifndef CONFIG_X86_PAE
-#define PAGE_SIZE (1UL << L1_PAGETABLE_SHIFT)
-#else
-#define PAGE_SIZE (1ULL << L1_PAGETABLE_SHIFT)
-#endif
-#define PAGE_SHIFT L1_PAGETABLE_SHIFT
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT)
-#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT)
-#define PFN_PHYS(x) ((x) << L1_PAGETABLE_SHIFT)
-
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* Definitions for machine and pseudophysical addresses. */
-#ifdef CONFIG_X86_PAE
-typedef unsigned long long paddr_t;
-typedef unsigned long long maddr_t;
-#else
-typedef unsigned long paddr_t;
-typedef unsigned long maddr_t;
-#endif
-
-extern unsigned long *phys_to_machine_mapping;
-extern char _text, _etext, _edata, _end;
-#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
-static __inline__ maddr_t phys_to_machine(paddr_t phys)
-{
- maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
- machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
- return machine;
-}
-
-#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
-static __inline__ paddr_t machine_to_phys(maddr_t machine)
-{
- paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
- phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
- return phys;
-}
-
-#define VIRT_START ((unsigned long)&_text)
-
-#define to_phys(x) ((unsigned long)(x)-VIRT_START)
-#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START))
-
-#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt)))
-#define virt_to_mfn(_virt) (pfn_to_mfn(virt_to_pfn(_virt)))
-#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach)))
-#define virt_to_mach(_virt) (phys_to_machine(to_phys(_virt)))
-#define mfn_to_virt(_mfn) (to_virt(mfn_to_pfn(_mfn) << PAGE_SHIFT))
-#define pfn_to_virt(_pfn) (to_virt((_pfn) << PAGE_SHIFT))
-
-/* Pagetable walking. */
-#define pte_to_mfn(_pte) (((_pte) & (PADDR_MASK&PAGE_MASK)) >> L1_PAGETABLE_SHIFT)
-#define pte_to_virt(_pte) to_virt(mfn_to_pfn(pte_to_mfn(_pte)) << PAGE_SHIFT)
void init_mm(void);
unsigned long alloc_pages(int order);
@@ -220,6 +53,8 @@ static __inline__ int get_order(unsigned long size)
return order;
}
+void arch_init_demand_mapping_area(unsigned long max_pfn);
+void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p);
void *map_frames(unsigned long *f, unsigned long n);
diff --git a/extras/mini-os/include/sched.h b/extras/mini-os/include/sched.h
index ce57be8a6c..f162062c45 100644
--- a/extras/mini-os/include/sched.h
+++ b/extras/mini-os/include/sched.h
@@ -2,39 +2,46 @@
#define __SCHED_H__
#include <list.h>
+#include <time.h>
+#include <arch_sched.h>
struct thread
{
char *name;
char *stack;
+#if !defined(__ia64__)
unsigned long sp; /* Stack pointer */
unsigned long ip; /* Instruction pointer */
+#else /* !defined(__ia64__) */
+ thread_regs_t regs;
+#endif /* !defined(__ia64__) */
struct list_head thread_list;
u32 flags;
+ s_time_t wakeup_time;
};
+extern struct thread *idle_thread;
+void idle_thread_fn(void *unused);
+#define RUNNABLE_FLAG 0x00000001
+
+#define is_runnable(_thread) (_thread->flags & RUNNABLE_FLAG)
+#define set_runnable(_thread) (_thread->flags |= RUNNABLE_FLAG)
+#define clear_runnable(_thread) (_thread->flags &= ~RUNNABLE_FLAG)
+
+#define switch_threads(prev, next) arch_switch_threads(prev, next)
+
void init_sched(void);
void run_idle_thread(void);
struct thread* create_thread(char *name, void (*function)(void *), void *data);
void schedule(void);
-static inline struct thread* get_current(void)
-{
- struct thread **current;
-#ifdef __i386__
- __asm__("andl %%esp,%0; ":"=r" (current) : "r" (~8191UL));
-#else
- __asm__("andq %%rsp,%0; ":"=r" (current) : "r" (~8191UL));
-#endif
- return *current;
-}
-
#define current get_current()
void wake(struct thread *thread);
void block(struct thread *thread);
+void sleep(u32 millisecs);
#endif /* __SCHED_H__ */
diff --git a/extras/mini-os/include/spinlock.h b/extras/mini-os/include/spinlock.h
new file mode 100644
index 0000000000..ecfe73627e
--- /dev/null
+++ b/extras/mini-os/include/spinlock.h
@@ -0,0 +1,55 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <lib.h>
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+ volatile unsigned int slock;
+} spinlock_t;
+
+
+#include "arch_spinlock.h"
+
+
+#define SPINLOCK_MAGIC 0xdead4ead
+
+#define SPIN_LOCK_UNLOCKED ARCH_SPIN_LOCK_UNLOCKED
+
+#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+
+/*
+ * Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define spin_is_locked(x) arch_spin_is_locked(x)
+
+#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+
+#define _spin_trylock(lock) ({_raw_spin_trylock(lock) ? \
+ 1 : ({ 0;});})
+
+#define _spin_lock(lock) \
+do { \
+ _raw_spin_lock(lock); \
+} while(0)
+
+#define _spin_unlock(lock) \
+do { \
+ _raw_spin_unlock(lock); \
+} while (0)
+
+
+#define spin_lock(lock) _spin_lock(lock)
+#define spin_unlock(lock) _spin_unlock(lock)
+
+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
+
+#endif
diff --git a/extras/mini-os/include/time.h b/extras/mini-os/include/time.h
index aacf1d17e7..468a8d9173 100644
--- a/extras/mini-os/include/time.h
+++ b/extras/mini-os/include/time.h
@@ -7,8 +7,9 @@
* File: time.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ * Robert Kaiser (kaiser@informatik.fh-wiesbaden.de)
*
- * Date: Jul 2003, changesJun 2005
+ * Date: Jul 2003, changes: Jun 2005, Sep 2006
*
* Environment: Xen Minimal OS
* Description: Time and timer functions
@@ -57,7 +58,8 @@ struct timespec {
void init_time(void);
s_time_t get_s_time(void);
s_time_t get_v_time(void);
+u64 monotonic_clock(void);
void gettimeofday(struct timeval *tv);
-void block_domain(u32 millisecs);
+void block_domain(s_time_t until);
#endif /* _TIME_H_ */
diff --git a/extras/mini-os/include/x86/arch_mm.h b/extras/mini-os/include/x86/arch_mm.h
new file mode 100644
index 0000000000..795ef070a7
--- /dev/null
+++ b/extras/mini-os/include/x86/arch_mm.h
@@ -0,0 +1,209 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ *
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ * Copyright (c) 2005, Keir A Fraser
+ *
+ * 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 _ARCH_MM_H_
+#define _ARCH_MM_H_
+
+#if defined(__i386__)
+#include <xen/arch-x86_32.h>
+#elif defined(__x86_64__)
+#include <xen/arch-x86_64.h>
+#else
+#error "Unsupported architecture"
+#endif
+
+#define L1_FRAME 1
+#define L2_FRAME 2
+#define L3_FRAME 3
+
+#define L1_PAGETABLE_SHIFT 12
+
+#if defined(__i386__)
+
+#if !defined(CONFIG_X86_PAE)
+
+#define L2_PAGETABLE_SHIFT 22
+
+#define L1_PAGETABLE_ENTRIES 1024
+#define L2_PAGETABLE_ENTRIES 1024
+
+#define PADDR_BITS 32
+#define PADDR_MASK (~0UL)
+
+#define NOT_L1_FRAMES 1
+#define PRIpte "08lx"
+typedef unsigned long pgentry_t;
+
+#else /* defined(CONFIG_X86_PAE) */
+
+#define L2_PAGETABLE_SHIFT 21
+#define L3_PAGETABLE_SHIFT 30
+
+#define L1_PAGETABLE_ENTRIES 512
+#define L2_PAGETABLE_ENTRIES 512
+#define L3_PAGETABLE_ENTRIES 4
+
+#define PADDR_BITS 44
+#define PADDR_MASK ((1ULL << PADDR_BITS)-1)
+
+#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1)
+
+/*
+ * If starting from virtual address greater than 0xc0000000,
+ * this value will be 2 to account for final mid-level page
+ * directory which is always mapped in at this location.
+ */
+#define NOT_L1_FRAMES 3
+#define PRIpte "016llx"
+typedef uint64_t pgentry_t;
+
+#endif /* !defined(CONFIG_X86_PAE) */
+
+#elif defined(__x86_64__)
+
+#define L2_PAGETABLE_SHIFT 21
+#define L3_PAGETABLE_SHIFT 30
+#define L4_PAGETABLE_SHIFT 39
+
+#define L1_PAGETABLE_ENTRIES 512
+#define L2_PAGETABLE_ENTRIES 512
+#define L3_PAGETABLE_ENTRIES 512
+#define L4_PAGETABLE_ENTRIES 512
+
+/* These are page-table limitations. Current CPUs support only 40-bit phys. */
+#define PADDR_BITS 52
+#define VADDR_BITS 48
+#define PADDR_MASK ((1UL << PADDR_BITS)-1)
+#define VADDR_MASK ((1UL << VADDR_BITS)-1)
+
+#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1)
+#define L3_MASK ((1UL << L4_PAGETABLE_SHIFT) - 1)
+
+#define NOT_L1_FRAMES 3
+#define PRIpte "016lx"
+typedef unsigned long pgentry_t;
+
+#endif
+
+#define L1_MASK ((1UL << L2_PAGETABLE_SHIFT) - 1)
+
+/* Given a virtual address, get an entry offset into a page table. */
+#define l1_table_offset(_a) \
+ (((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1))
+#define l2_table_offset(_a) \
+ (((_a) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1))
+#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
+#define l3_table_offset(_a) \
+ (((_a) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1))
+#endif
+#if defined(__x86_64__)
+#define l4_table_offset(_a) \
+ (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1))
+#endif
+
+#define _PAGE_PRESENT 0x001UL
+#define _PAGE_RW 0x002UL
+#define _PAGE_USER 0x004UL
+#define _PAGE_PWT 0x008UL
+#define _PAGE_PCD 0x010UL
+#define _PAGE_ACCESSED 0x020UL
+#define _PAGE_DIRTY 0x040UL
+#define _PAGE_PAT 0x080UL
+#define _PAGE_PSE 0x080UL
+#define _PAGE_GLOBAL 0x100UL
+
+#if defined(__i386__)
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY |_PAGE_USER)
+#if defined(CONFIG_X86_PAE)
+#define L3_PROT (_PAGE_PRESENT)
+#endif /* CONFIG_X86_PAE */
+#elif defined(__x86_64__)
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#endif /* __i386__ || __x86_64__ */
+
+#ifndef CONFIG_X86_PAE
+#define PAGE_SIZE (1UL << L1_PAGETABLE_SHIFT)
+#else
+#define PAGE_SIZE (1ULL << L1_PAGETABLE_SHIFT)
+#endif
+#define PAGE_SHIFT L1_PAGETABLE_SHIFT
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT)
+#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT)
+#define PFN_PHYS(x) ((x) << L1_PAGETABLE_SHIFT)
+#define PHYS_PFN(x) ((x) >> L1_PAGETABLE_SHIFT)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+/* Definitions for machine and pseudophysical addresses. */
+#ifdef CONFIG_X86_PAE
+typedef unsigned long long paddr_t;
+typedef unsigned long long maddr_t;
+#else
+typedef unsigned long paddr_t;
+typedef unsigned long maddr_t;
+#endif
+
+extern unsigned long *phys_to_machine_mapping;
+extern char _text, _etext, _edata, _end;
+#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
+static __inline__ maddr_t phys_to_machine(paddr_t phys)
+{
+ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
+ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
+ return machine;
+}
+
+#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
+static __inline__ paddr_t machine_to_phys(maddr_t machine)
+{
+ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
+ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
+ return phys;
+}
+
+#define VIRT_START ((unsigned long)&_text)
+
+#define to_phys(x) ((unsigned long)(x)-VIRT_START)
+#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START))
+
+#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt)))
+#define virt_to_mfn(_virt) (pfn_to_mfn(virt_to_pfn(_virt)))
+#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach)))
+#define virt_to_mach(_virt) (phys_to_machine(to_phys(_virt)))
+#define mfn_to_virt(_mfn) (to_virt(mfn_to_pfn(_mfn) << PAGE_SHIFT))
+#define pfn_to_virt(_pfn) (to_virt((_pfn) << PAGE_SHIFT))
+
+/* Pagetable walking. */
+#define pte_to_mfn(_pte) (((_pte) & (PADDR_MASK&PAGE_MASK)) >> L1_PAGETABLE_SHIFT)
+#define pte_to_virt(_pte) to_virt(mfn_to_pfn(pte_to_mfn(_pte)) << PAGE_SHIFT)
+
+
+#endif /* _ARCH_MM_H_ */
diff --git a/extras/mini-os/include/x86/arch_sched.h b/extras/mini-os/include/x86/arch_sched.h
new file mode 100644
index 0000000000..e02dbd05a5
--- /dev/null
+++ b/extras/mini-os/include/x86/arch_sched.h
@@ -0,0 +1,58 @@
+
+#ifndef __ARCH_SCHED_H__
+#define __ARCH_SCHED_H__
+
+
+static inline struct thread* get_current(void)
+{
+ struct thread **current;
+#ifdef __i386__
+ __asm__("andl %%esp,%0; ":"=r" (current) : "r" (~8191UL));
+#else
+ __asm__("andq %%rsp,%0; ":"=r" (current) : "r" (~8191UL));
+#endif
+ return *current;
+}
+
+#ifdef __i386__
+#define arch_switch_threads(prev, next) do { \
+ unsigned long esi,edi; \
+ __asm__ __volatile__("pushfl\n\t" \
+ "pushl %%ebp\n\t" \
+ "movl %%esp,%0\n\t" /* save ESP */ \
+ "movl %4,%%esp\n\t" /* restore ESP */ \
+ "movl $1f,%1\n\t" /* save EIP */ \
+ "pushl %5\n\t" /* restore EIP */ \
+ "ret\n\t" \
+ "1:\t" \
+ "popl %%ebp\n\t" \
+ "popfl" \
+ :"=m" (prev->sp),"=m" (prev->ip), \
+ "=S" (esi),"=D" (edi) \
+ :"m" (next->sp),"m" (next->ip), \
+ "2" (prev), "d" (next)); \
+} while (0)
+#elif __x86_64__
+#define arch_switch_threads(prev, next) do { \
+ unsigned long rsi,rdi; \
+ __asm__ __volatile__("pushfq\n\t" \
+ "pushq %%rbp\n\t" \
+ "movq %%rsp,%0\n\t" /* save RSP */ \
+ "movq %4,%%rsp\n\t" /* restore RSP */ \
+ "movq $1f,%1\n\t" /* save RIP */ \
+ "pushq %5\n\t" /* restore RIP */ \
+ "ret\n\t" \
+ "1:\t" \
+ "popq %%rbp\n\t" \
+ "popfq" \
+ :"=m" (prev->sp),"=m" (prev->ip), \
+ "=S" (rsi),"=D" (rdi) \
+ :"m" (next->sp),"m" (next->ip), \
+ "2" (prev), "d" (next)); \
+} while (0)
+#endif
+
+
+
+
+#endif /* __ARCH_SCHED_H__ */
diff --git a/extras/mini-os/include/x86/spinlock.h b/extras/mini-os/include/x86/arch_spinlock.h
index 4274cd2869..a181ed3c92 100644
--- a/extras/mini-os/include/x86/spinlock.h
+++ b/extras/mini-os/include/x86/arch_spinlock.h
@@ -1,21 +1,12 @@
-#ifndef __ASM_SPINLOCK_H
-#define __ASM_SPINLOCK_H
-#include <lib.h>
-
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- */
-typedef struct {
- volatile unsigned int slock;
-} spinlock_t;
+#ifndef __ARCH_ASM_SPINLOCK_H
+#define __ARCH_ASM_SPINLOCK_H
-#define SPINLOCK_MAGIC 0xdead4ead
+#include <lib.h>
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+#define ARCH_SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
@@ -24,7 +15,7 @@ typedef struct {
* We make no fairness assumptions. They have a cost.
*/
-#define spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) <= 0)
+#define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) <= 0)
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
#define spin_lock_string \
@@ -99,23 +90,4 @@ static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
:"=m" (lock->slock) : "r" (flags) : "memory");
}
-#define _spin_trylock(lock) ({_raw_spin_trylock(lock) ? \
- 1 : ({ 0;});})
-
-#define _spin_lock(lock) \
-do { \
- _raw_spin_lock(lock); \
-} while(0)
-
-#define _spin_unlock(lock) \
-do { \
- _raw_spin_unlock(lock); \
-} while (0)
-
-
-#define spin_lock(lock) _spin_lock(lock)
-#define spin_unlock(lock) _spin_unlock(lock)
-
-#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
-
#endif
diff --git a/extras/mini-os/include/x86/os.h b/extras/mini-os/include/x86/os.h
index 2b6ed5512b..80f5586a49 100644
--- a/extras/mini-os/include/x86/os.h
+++ b/extras/mini-os/include/x86/os.h
@@ -19,6 +19,8 @@
#include <types.h>
#include <hypervisor.h>
+#define USED __attribute__ ((used))
+
extern void do_exit(void);
#define BUG do_exit
@@ -61,6 +63,11 @@ extern shared_info_t *HYPERVISOR_shared_info;
void trap_init(void);
+void arch_init(start_info_t *si);
+void arch_print_info(void);
+
+
+
/*
diff --git a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
index 6556c4f7e2..5f8b51f872 100644
--- a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
+++ b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h
@@ -167,7 +167,7 @@ HYPERVISOR_fpu_taskswitch(
static inline int
HYPERVISOR_sched_op(
- int cmd, unsigned long arg)
+ int cmd, void *arg)
{
return _hypercall2(int, sched_op, cmd, arg);
}
@@ -238,9 +238,9 @@ HYPERVISOR_update_va_mapping(
static inline int
HYPERVISOR_event_channel_op(
- void *op)
+ int cmd, void *op)
{
- return _hypercall1(int, event_channel_op, op);
+ return _hypercall2(int, event_channel_op, cmd, op);
}
static inline int
diff --git a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
index 6a68a10b02..2d2904a218 100644
--- a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
+++ b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
@@ -171,7 +171,7 @@ HYPERVISOR_fpu_taskswitch(
static inline int
HYPERVISOR_sched_op(
- int cmd, unsigned long arg)
+ int cmd, void *arg)
{
return _hypercall2(int, sched_op, cmd, arg);
}
@@ -235,9 +235,9 @@ HYPERVISOR_update_va_mapping(
static inline int
HYPERVISOR_event_channel_op(
- void *op)
+ int cmd, void *op)
{
- return _hypercall1(int, event_channel_op, op);
+ return _hypercall2(int, event_channel_op, cmd, op);
}
static inline int
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index d66dd35ab0..0799116aa6 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -6,6 +6,7 @@
*
* Copyright (c) 2002-2003, K A Fraser & R Neugebauer
* Copyright (c) 2005, Grzegorz Milos, Intel Research Cambridge
+ * Copyright (c) 2006, Robert Kaiser, FH Wiesbaden
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@@ -39,49 +40,6 @@
#include <xen/features.h>
#include <xen/version.h>
-/*
- * Shared page for communicating with the hypervisor.
- * Events flags go here, for example.
- */
-shared_info_t *HYPERVISOR_shared_info;
-
-/*
- * This structure contains start-of-day info, such as pagetable base pointer,
- * address of the shared_info structure, and things like that.
- */
-union start_info_union start_info_union;
-
-/*
- * Just allocate the kernel stack here. SS:ESP is set up to point here
- * in head.S.
- */
-char stack[8192];
-
-
-/* Assembler interface fns in entry.S. */
-void hypervisor_callback(void);
-void failsafe_callback(void);
-
-extern char shared_info[PAGE_SIZE];
-
-#if !defined(CONFIG_X86_PAE)
-#define __pte(x) ((pte_t) { (x) } )
-#else
-#define __pte(x) ({ unsigned long long _x = (x); \
- ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); })
-#endif
-
-static shared_info_t *map_shared_info(unsigned long pa)
-{
- if ( HYPERVISOR_update_va_mapping(
- (unsigned long)shared_info, __pte(pa | 7), UVMF_INVLPG) )
- {
- printk("Failed to map shared_info!!\n");
- do_exit();
- }
- return (shared_info_t *)shared_info;
-}
-
u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
@@ -109,11 +67,24 @@ void xenbus_tester(void *p)
/* test_xenbus(); */
}
+void periodic_thread(void *p)
+{
+ struct timeval tv;
+ printk("Periodic thread started.\n");
+ for(;;)
+ {
+ gettimeofday(&tv);
+ printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
+ sleep(1000);
+ }
+}
+
/* This should be overridden by the application we are linked against. */
__attribute__((weak)) int app_main(start_info_t *si)
{
printk("Dummy main: start_info=%p\n", si);
create_thread("xenbus_tester", xenbus_tester, si);
+ create_thread("periodic_thread", periodic_thread, si);
return 0;
}
@@ -126,32 +97,10 @@ void start_kernel(start_info_t *si)
(void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
- /* Copy the start_info struct to a globally-accessible area. */
- /* WARN: don't do printk before here, it uses information from
- shared_info. Use xprintk instead. */
- memcpy(&start_info, si, sizeof(*si));
-
- /* set up minimal memory infos */
- phys_to_machine_mapping = (unsigned long *)start_info.mfn_list;
-
- /* Grab the shared_info pointer and put it in a safe place. */
- HYPERVISOR_shared_info = map_shared_info(start_info.shared_info);
-
- /* Set up event and failsafe callback addresses. */
-#ifdef __i386__
- HYPERVISOR_set_callbacks(
- __KERNEL_CS, (unsigned long)hypervisor_callback,
- __KERNEL_CS, (unsigned long)failsafe_callback);
-#else
- HYPERVISOR_set_callbacks(
- (unsigned long)hypervisor_callback,
- (unsigned long)failsafe_callback, 0);
-#endif
+ arch_init(si);
+
trap_init();
- /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
- __sti();
-
/* print out some useful information */
printk("Xen Minimal OS!\n");
printk("start_info: %p\n", si);
@@ -163,16 +112,20 @@ void start_kernel(start_info_t *si)
printk(" flags: 0x%x\n", (unsigned int)si->flags);
printk(" cmd_line: %s\n",
si->cmd_line ? (const char *)si->cmd_line : "NULL");
- printk(" stack: %p-%p\n", stack, stack + 8192);
+
+ /* Set up events. */
+ init_events();
+
+ /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
+ __sti();
+
+ arch_print_info();
setup_xen_features();
/* Init memory management. */
init_mm();
- /* Set up events. */
- init_events();
-
/* Init time and timers. */
init_time();
@@ -206,5 +159,9 @@ void start_kernel(start_info_t *si)
void do_exit(void)
{
printk("Do_exit called!\n");
- for ( ;; ) HYPERVISOR_sched_op(SCHEDOP_shutdown, SHUTDOWN_crash);
+ for( ;; )
+ {
+ struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
+ HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
+ }
}
diff --git a/extras/mini-os/mm.c b/extras/mini-os/mm.c
index 03fb3e9ab5..a24a521cf6 100644
--- a/extras/mini-os/mm.c
+++ b/extras/mini-os/mm.c
@@ -48,10 +48,6 @@
#define DEBUG(_f, _a...) ((void)0)
#endif
-unsigned long *phys_to_machine_mapping;
-extern char *stack;
-extern void page_walk(unsigned long virt_addr);
-
/*********************
* ALLOCATION BITMAP
* One bit per page of memory. Bit set => page is allocated.
@@ -148,7 +144,7 @@ static chunk_head_t free_tail[FREELIST_SIZE];
* Prints allocation[0/1] for @nr_pages, starting at @start
* address (virtual).
*/
-static void print_allocation(void *start, int nr_pages)
+USED static void print_allocation(void *start, int nr_pages)
{
unsigned long pfn_start = virt_to_pfn(start);
int count;
@@ -163,7 +159,7 @@ static void print_allocation(void *start, int nr_pages)
* Prints chunks (making them with letters) for @nr_pages starting
* at @start (virtual).
*/
-static void print_chunks(void *start, int nr_pages)
+USED static void print_chunks(void *start, int nr_pages)
{
char chunks[1001], current='A';
int order, count;
@@ -226,11 +222,11 @@ static void init_page_allocator(unsigned long min, unsigned long max)
/* All allocated by default. */
memset(alloc_bitmap, ~0, bitmap_size);
/* Free up the memory we've been given to play with. */
- map_free(min>>PAGE_SHIFT, range>>PAGE_SHIFT);
+ map_free(PHYS_PFN(min), range>>PAGE_SHIFT);
/* The buddy lists are addressed in high memory. */
- min += VIRT_START;
- max += VIRT_START;
+ min = (unsigned long) to_virt(min);
+ max = (unsigned long) to_virt(max);
while ( range != 0 )
{
@@ -297,7 +293,7 @@ unsigned long alloc_pages(int order)
free_head[i] = spare_ch;
}
- map_alloc(to_phys(alloc_ch)>>PAGE_SHIFT, 1<<order);
+ map_alloc(PHYS_PFN(to_phys(alloc_ch)), 1<<order);
return((unsigned long)alloc_ch);
@@ -365,353 +361,6 @@ void free_pages(void *pointer, int order)
}
-void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,
- unsigned long offset, unsigned long level)
-{
- pgentry_t *tab = (pgentry_t *)start_info.pt_base;
- unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn);
- unsigned long prot_e, prot_t, pincmd;
- mmu_update_t mmu_updates[1];
- struct mmuext_op pin_request;
-
- DEBUG("Allocating new L%d pt frame for pt_pfn=%lx, "
- "prev_l_mfn=%lx, offset=%lx",
- level, *pt_pfn, prev_l_mfn, offset);
-
- /* We need to clear the page, otherwise we might fail to map it
- as a page table page */
- memset((unsigned long*)pfn_to_virt(*pt_pfn), 0, PAGE_SIZE);
-
- switch ( level )
- {
- case L1_FRAME:
- prot_e = L1_PROT;
- prot_t = L2_PROT;
- pincmd = MMUEXT_PIN_L1_TABLE;
- break;
-#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
- case L2_FRAME:
- prot_e = L2_PROT;
- prot_t = L3_PROT;
- pincmd = MMUEXT_PIN_L2_TABLE;
- break;
-#endif
-#if defined(__x86_64__)
- case L3_FRAME:
- prot_e = L3_PROT;
- prot_t = L4_PROT;
- pincmd = MMUEXT_PIN_L3_TABLE;
- break;
-#endif
- default:
- printk("new_pt_frame() called with invalid level number %d\n", level);
- do_exit();
- break;
- }
-
- /* Update the entry */
-#if defined(__x86_64__)
- tab = pte_to_virt(tab[l4_table_offset(pt_page)]);
- tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
-#endif
-#if defined(CONFIG_X86_PAE)
- tab = pte_to_virt(tab[l3_table_offset(pt_page)]);
-#endif
-
- mmu_updates[0].ptr = ((pgentry_t)tab[l2_table_offset(pt_page)] & PAGE_MASK) +
- sizeof(pgentry_t) * l1_table_offset(pt_page);
- mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT |
- (prot_e & ~_PAGE_RW);
- if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
- {
- printk("PTE for new page table page could not be updated\n");
- do_exit();
- }
-
- /* Pin the page to provide correct protection */
- pin_request.cmd = pincmd;
- pin_request.arg1.mfn = pfn_to_mfn(*pt_pfn);
- if(HYPERVISOR_mmuext_op(&pin_request, 1, NULL, DOMID_SELF) < 0)
- {
- printk("ERROR: pinning failed\n");
- do_exit();
- }
-
- /* Now fill the new page table page with entries.
- Update the page directory as well. */
- mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
- mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t;
- if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)
- {
- printk("ERROR: mmu_update failed\n");
- do_exit();
- }
-
- *pt_pfn += 1;
-}
-
-/* Checks if a pagetable frame is needed (if weren't allocated by Xen) */
-static int need_pt_frame(unsigned long virt_address, int level)
-{
- unsigned long hyp_virt_start = HYPERVISOR_VIRT_START;
-#if defined(__x86_64__)
- unsigned long hyp_virt_end = HYPERVISOR_VIRT_END;
-#else
- unsigned long hyp_virt_end = 0xffffffff;
-#endif
-
- /* In general frames will _not_ be needed if they were already
- allocated to map the hypervisor into our VA space */
-#if defined(__x86_64__)
- if(level == L3_FRAME)
- {
- if(l4_table_offset(virt_address) >=
- l4_table_offset(hyp_virt_start) &&
- l4_table_offset(virt_address) <=
- l4_table_offset(hyp_virt_end))
- return 0;
- return 1;
- } else
-#endif
-
-#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
- if(level == L2_FRAME)
- {
-#if defined(__x86_64__)
- if(l4_table_offset(virt_address) >=
- l4_table_offset(hyp_virt_start) &&
- l4_table_offset(virt_address) <=
- l4_table_offset(hyp_virt_end))
-#endif
- if(l3_table_offset(virt_address) >=
- l3_table_offset(hyp_virt_start) &&
- l3_table_offset(virt_address) <=
- l3_table_offset(hyp_virt_end))
- return 0;
-
- return 1;
- } else
-#endif /* defined(__x86_64__) || defined(CONFIG_X86_PAE) */
-
- /* Always need l1 frames */
- if(level == L1_FRAME)
- return 1;
-
- printk("ERROR: Unknown frame level %d, hypervisor %llx,%llx\n",
- level, hyp_virt_start, hyp_virt_end);
- return -1;
-}
-
-void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
-{
- unsigned long start_address, end_address;
- unsigned long pfn_to_map, pt_pfn = *start_pfn;
- static mmu_update_t mmu_updates[L1_PAGETABLE_ENTRIES + 1];
- pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
- unsigned long mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
- unsigned long offset;
- int count = 0;
-
- pfn_to_map = (start_info.nr_pt_frames - NOT_L1_FRAMES) * L1_PAGETABLE_ENTRIES;
-
- if (*max_pfn >= virt_to_pfn(HYPERVISOR_VIRT_START))
- {
- printk("WARNING: Mini-OS trying to use Xen virtual space. "
- "Truncating memory from %dMB to ",
- ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
- *max_pfn = virt_to_pfn(HYPERVISOR_VIRT_START - PAGE_SIZE);
- printk("%dMB\n",
- ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);
- }
-
- start_address = (unsigned long)pfn_to_virt(pfn_to_map);
- end_address = (unsigned long)pfn_to_virt(*max_pfn);
-
- /* We worked out the virtual memory range to map, now mapping loop */
- printk("Mapping memory range 0x%lx - 0x%lx\n", start_address, end_address);
-
- while(start_address < end_address)
- {
- tab = (pgentry_t *)start_info.pt_base;
- mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));
-
-#if defined(__x86_64__)
- offset = l4_table_offset(start_address);
- /* Need new L3 pt frame */
- if(!(start_address & L3_MASK))
- if(need_pt_frame(start_address, L3_FRAME))
- new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
-
- page = tab[offset];
- mfn = pte_to_mfn(page);
- tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
-#endif
-#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
- offset = l3_table_offset(start_address);
- /* Need new L2 pt frame */
- if(!(start_address & L2_MASK))
- if(need_pt_frame(start_address, L2_FRAME))
- new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
-
- page = tab[offset];
- mfn = pte_to_mfn(page);
- tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
-#endif
- offset = l2_table_offset(start_address);
- /* Need new L1 pt frame */
- if(!(start_address & L1_MASK))
- if(need_pt_frame(start_address, L1_FRAME))
- new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
-
- page = tab[offset];
- mfn = pte_to_mfn(page);
- offset = l1_table_offset(start_address);
-
- mmu_updates[count].ptr = ((pgentry_t)mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;
- mmu_updates[count].val = (pgentry_t)pfn_to_mfn(pfn_to_map++) << PAGE_SHIFT | L1_PROT;
- count++;
- if (count == L1_PAGETABLE_ENTRIES || pfn_to_map == *max_pfn)
- {
- if(HYPERVISOR_mmu_update(mmu_updates, count, NULL, DOMID_SELF) < 0)
- {
- printk("PTE could not be updated\n");
- do_exit();
- }
- count = 0;
- }
- start_address += PAGE_SIZE;
- }
-
- *start_pfn = pt_pfn;
-}
-
-
-void mem_test(unsigned long *start_add, unsigned long *end_add)
-{
- unsigned long mask = 0x10000;
- unsigned long *pointer;
-
- for(pointer = start_add; pointer < end_add; pointer++)
- {
- if(!(((unsigned long)pointer) & 0xfffff))
- {
- printk("Writing to %lx\n", pointer);
- page_walk((unsigned long)pointer);
- }
- *pointer = (unsigned long)pointer & ~mask;
- }
-
- for(pointer = start_add; pointer < end_add; pointer++)
- {
- if(((unsigned long)pointer & ~mask) != *pointer)
- printk("Read error at 0x%lx. Read: 0x%lx, should read 0x%lx\n",
- (unsigned long)pointer,
- *pointer,
- ((unsigned long)pointer & ~mask));
- }
-
-}
-
-static pgentry_t *demand_map_pgt;
-static void *demand_map_area_start;
-
-static void init_demand_mapping_area(unsigned long max_pfn)
-{
- unsigned long mfn;
- pgentry_t *tab;
- unsigned long start_addr;
- unsigned long pt_pfn;
- unsigned offset;
-
- /* Round up to four megs. + 1024 rather than + 1023 since we want
- to be sure we don't end up in the same place we started. */
- max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1);
- if (max_pfn == 0 ||
- (unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >=
- HYPERVISOR_VIRT_START) {
- printk("Too much memory; no room for demand map hole.\n");
- do_exit();
- }
-
- demand_map_area_start = pfn_to_virt(max_pfn);
- printk("Demand map pfns start at %lx (%p).\n", max_pfn,
- demand_map_area_start);
- start_addr = (unsigned long)demand_map_area_start;
-
- tab = (pgentry_t *)start_info.pt_base;
- mfn = virt_to_mfn(start_info.pt_base);
- pt_pfn = virt_to_pfn(alloc_page());
-
-#if defined(__x86_64__)
- offset = l4_table_offset(start_addr);
- if (!(tab[offset] & _PAGE_PRESENT)) {
- new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);
- pt_pfn = virt_to_pfn(alloc_page());
- }
- ASSERT(tab[offset] & _PAGE_PRESENT);
- mfn = pte_to_mfn(tab[offset]);
- tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
-#endif
-#if defined(__x86_64__) || defined(CONFIG_X86_PAE)
- offset = l3_table_offset(start_addr);
- if (!(tab[offset] & _PAGE_PRESENT)) {
- new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);
- pt_pfn = virt_to_pfn(alloc_page());
- }
- ASSERT(tab[offset] & _PAGE_PRESENT);
- mfn = pte_to_mfn(tab[offset]);
- tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);
-#endif
- offset = l2_table_offset(start_addr);
- if (tab[offset] & _PAGE_PRESENT) {
- printk("Demand map area already has a page table covering it?\n");
- BUG();
- }
- demand_map_pgt = pfn_to_virt(pt_pfn);
- new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);
- ASSERT(tab[offset] & _PAGE_PRESENT);
-}
-
-void *map_frames(unsigned long *f, unsigned long n)
-{
- unsigned long x;
- unsigned long y = 0;
- mmu_update_t mmu_updates[16];
- int rc;
-
- if (n > 16) {
- printk("Tried to map too many (%ld) frames at once.\n", n);
- return NULL;
- }
-
- /* Find a run of n contiguous frames */
- for (x = 0; x <= 1024 - n; x += y + 1) {
- for (y = 0; y < n; y++)
- if (demand_map_pgt[x+y] & _PAGE_PRESENT)
- break;
- if (y == n)
- break;
- }
- if (y != n) {
- printk("Failed to map %ld frames!\n", n);
- return NULL;
- }
-
- /* Found it at x. Map it in. */
- for (y = 0; y < n; y++) {
- mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]);
- mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT;
- }
-
- rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF);
- if (rc < 0) {
- printk("Map %ld failed: %d.\n", n, rc);
- return NULL;
- } else {
- return (void *)(unsigned long)((unsigned long)demand_map_area_start +
- x * PAGE_SIZE);
- }
-}
void init_mm(void)
{
@@ -720,22 +369,7 @@ void init_mm(void)
printk("MM: Init\n");
- printk(" _text: %p\n", &_text);
- printk(" _etext: %p\n", &_etext);
- printk(" _edata: %p\n", &_edata);
- printk(" stack start: %p\n", &stack);
- printk(" _end: %p\n", &_end);
-
- /* First page follows page table pages and 3 more pages (store page etc) */
- start_pfn = PFN_UP(to_phys(start_info.pt_base)) +
- start_info.nr_pt_frames + 3;
- max_pfn = start_info.nr_pages;
-
- printk(" start_pfn: %lx\n", start_pfn);
- printk(" max_pfn: %lx\n", max_pfn);
-
- build_pagetable(&start_pfn, &max_pfn);
-
+ arch_init_mm(&start_pfn, &max_pfn);
/*
* now we can initialise the page allocator
*/
@@ -745,8 +379,7 @@ void init_mm(void)
init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn));
printk("MM: done\n");
- init_demand_mapping_area(max_pfn);
- printk("Initialised demand area.\n");
+ arch_init_demand_mapping_area(max_pfn);
}
void sanity_check(void)
diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
index ee1adb6549..9b111c28e5 100644
--- a/extras/mini-os/sched.c
+++ b/extras/mini-os/sched.c
@@ -5,7 +5,7 @@
*
* File: sched.c
* Author: Grzegorz Milos
- * Changes:
+ * Changes: Robert Kaiser
*
* Date: Aug 2005
*
@@ -54,82 +54,9 @@
#define DEBUG(_f, _a...) ((void)0)
#endif
-
-#define RUNNABLE_FLAG 0x00000001
-
-#define is_runnable(_thread) (_thread->flags & RUNNABLE_FLAG)
-#define set_runnable(_thread) (_thread->flags |= RUNNABLE_FLAG)
-#define clear_runnable(_thread) (_thread->flags &= ~RUNNABLE_FLAG)
-
-
struct thread *idle_thread = NULL;
LIST_HEAD(exited_threads);
-void idle_thread_fn(void *unused);
-
-void dump_stack(struct thread *thread)
-{
- unsigned long *bottom = (unsigned long *)(thread->stack + 2*4*1024);
- unsigned long *pointer = (unsigned long *)thread->sp;
- int count;
- if(thread == current)
- {
-#ifdef __i386__
- asm("movl %%esp,%0"
- : "=r"(pointer));
-#else
- asm("movq %%rsp,%0"
- : "=r"(pointer));
-#endif
- }
- printk("The stack for \"%s\"\n", thread->name);
- for(count = 0; count < 25 && pointer < bottom; count ++)
- {
- printk("[0x%lx] 0x%lx\n", pointer, *pointer);
- pointer++;
- }
-
- if(pointer < bottom) printk(" ... continues.\n");
-}
-
-#ifdef __i386__
-#define switch_threads(prev, next) do { \
- unsigned long esi,edi; \
- __asm__ __volatile__("pushfl\n\t" \
- "pushl %%ebp\n\t" \
- "movl %%esp,%0\n\t" /* save ESP */ \
- "movl %4,%%esp\n\t" /* restore ESP */ \
- "movl $1f,%1\n\t" /* save EIP */ \
- "pushl %5\n\t" /* restore EIP */ \
- "ret\n\t" \
- "1:\t" \
- "popl %%ebp\n\t" \
- "popfl" \
- :"=m" (prev->sp),"=m" (prev->ip), \
- "=S" (esi),"=D" (edi) \
- :"m" (next->sp),"m" (next->ip), \
- "2" (prev), "d" (next)); \
-} while (0)
-#elif __x86_64__
-#define switch_threads(prev, next) do { \
- unsigned long rsi,rdi; \
- __asm__ __volatile__("pushfq\n\t" \
- "pushq %%rbp\n\t" \
- "movq %%rsp,%0\n\t" /* save RSP */ \
- "movq %4,%%rsp\n\t" /* restore RSP */ \
- "movq $1f,%1\n\t" /* save RIP */ \
- "pushq %5\n\t" /* restore RIP */ \
- "ret\n\t" \
- "1:\t" \
- "popq %%rbp\n\t" \
- "popfq" \
- :"=m" (prev->sp),"=m" (prev->ip), \
- "=S" (rsi),"=D" (rdi) \
- :"m" (next->sp),"m" (next->ip), \
- "2" (prev), "d" (next)); \
-} while (0)
-#endif
-
void inline print_runqueue(void)
{
struct list_head *it;
@@ -142,6 +69,54 @@ void inline print_runqueue(void)
printk("\n");
}
+/* Find the time when the next timeout expires. If this is more than
+ 10 seconds from now, return 10 seconds from now. */
+static s_time_t blocking_time(void)
+{
+ struct thread *thread;
+ struct list_head *iterator;
+ s_time_t min_wakeup_time;
+ unsigned long flags;
+ local_irq_save(flags);
+ /* default-block the domain for 10 seconds: */
+ min_wakeup_time = NOW() + SECONDS(10);
+
+ /* Thread list needs to be protected */
+ list_for_each(iterator, &idle_thread->thread_list)
+ {
+ thread = list_entry(iterator, struct thread, thread_list);
+ if(!is_runnable(thread) && thread->wakeup_time != 0LL)
+ {
+ if(thread->wakeup_time < min_wakeup_time)
+ {
+ min_wakeup_time = thread->wakeup_time;
+ }
+ }
+ }
+ local_irq_restore(flags);
+ return(min_wakeup_time);
+}
+
+/* Wake up all threads with expired timeouts. */
+static void wake_expired(void)
+{
+ struct thread *thread;
+ struct list_head *iterator;
+ s_time_t now = NOW();
+ unsigned long flags;
+ local_irq_save(flags);
+ /* Thread list needs to be protected */
+ list_for_each(iterator, &idle_thread->thread_list)
+ {
+ thread = list_entry(iterator, struct thread, thread_list);
+ if(!is_runnable(thread) && thread->wakeup_time != 0LL)
+ {
+ if(thread->wakeup_time <= now)
+ wake(thread);
+ }
+ }
+ local_irq_restore(flags);
+}
void schedule(void)
{
@@ -202,88 +177,39 @@ void exit_thread(void)
schedule();
}
-/* Pushes the specified value onto the stack of the specified thread */
-static void stack_push(struct thread *thread, unsigned long value)
-{
- thread->sp -= sizeof(unsigned long);
- *((unsigned long *)thread->sp) = value;
-}
-
-struct thread* create_thread(char *name, void (*function)(void *), void *data)
+void block(struct thread *thread)
{
- struct thread *thread;
- unsigned long flags;
-
- thread = xmalloc(struct thread);
- /* Allocate 2 pages for stack, stack will be 2pages aligned */
- thread->stack = (char *)alloc_pages(1);
- thread->name = name;
- printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
- thread->stack);
-
- thread->sp = (unsigned long)thread->stack + 4096 * 2;
- /* Save pointer to the thread on the stack, used by current macro */
- *((unsigned long *)thread->stack) = (unsigned long)thread;
-
- stack_push(thread, (unsigned long) function);
- stack_push(thread, (unsigned long) data);
- thread->ip = (unsigned long) thread_starter;
-
- /* Not runable, not exited */
- thread->flags = 0;
- set_runnable(thread);
- local_irq_save(flags);
- if(idle_thread != NULL) {
- list_add_tail(&thread->thread_list, &idle_thread->thread_list);
- } else if(function != idle_thread_fn)
- {
- printk("BUG: Not allowed to create thread before initialising scheduler.\n");
- BUG();
- }
- local_irq_restore(flags);
- return thread;
+ thread->wakeup_time = 0LL;
+ clear_runnable(thread);
}
-
-void block(struct thread *thread)
+void sleep(u32 millisecs)
{
+ struct thread *thread = get_current();
+ thread->wakeup_time = NOW() + MILLISECS(millisecs);
clear_runnable(thread);
+ schedule();
}
void wake(struct thread *thread)
{
+ thread->wakeup_time = 0LL;
set_runnable(thread);
}
void idle_thread_fn(void *unused)
{
+ s_time_t until;
for(;;)
{
schedule();
- block_domain(10000);
+ /* block until the next timeout expires, or for 10 secs, whichever comes first */
+ until = blocking_time();
+ block_domain(until);
+ wake_expired();
}
}
-void run_idle_thread(void)
-{
- /* Switch stacks and run the thread */
-#if defined(__i386__)
- __asm__ __volatile__("mov %0,%%esp\n\t"
- "push %1\n\t"
- "ret"
- :"=m" (idle_thread->sp)
- :"m" (idle_thread->ip));
-#elif defined(__x86_64__)
- __asm__ __volatile__("mov %0,%%rsp\n\t"
- "push %1\n\t"
- "ret"
- :"=m" (idle_thread->sp)
- :"m" (idle_thread->ip));
-#endif
-}
-
-
-
DECLARE_MUTEX(mutex);
void th_f1(void *data)
diff --git a/extras/mini-os/time.c b/extras/mini-os/time.c
index 5567b5d391..0fad40f6de 100644
--- a/extras/mini-os/time.c
+++ b/extras/mini-os/time.c
@@ -3,6 +3,7 @@
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
* (C) 2002-2003 - Keir Fraser - University of Cambridge
* (C) 2005 - Grzegorz Milos - Intel Research Cambridge
+ * (C) 2006 - Robert Kaiser - FH Wiesbaden
****************************************************************************
*
* File: time.c
@@ -194,21 +195,15 @@ void gettimeofday(struct timeval *tv)
}
-static void print_current_time(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv);
- printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
-}
-
-
-void block_domain(u32 millisecs)
+void block_domain(s_time_t until)
{
struct timeval tv;
gettimeofday(&tv);
- HYPERVISOR_set_timer_op(monotonic_clock() + 1000000LL * (s64) millisecs);
- HYPERVISOR_sched_op(SCHEDOP_block, 0);
+ if(monotonic_clock() < until)
+ {
+ HYPERVISOR_set_timer_op(until);
+ HYPERVISOR_sched_op(SCHEDOP_block, 0);
+ }
}
@@ -217,15 +212,8 @@ void block_domain(u32 millisecs)
*/
static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign)
{
- static int i;
-
get_time_values_from_xen();
update_wallclock();
- i++;
- if (i >= 1000) {
- print_current_time();
- i = 0;
- }
}
diff --git a/linux-2.6-xen-sparse/arch/i386/Kconfig b/linux-2.6-xen-sparse/arch/i386/Kconfig
index 661d0bbecd..b3ef1013c4 100644
--- a/linux-2.6-xen-sparse/arch/i386/Kconfig
+++ b/linux-2.6-xen-sparse/arch/i386/Kconfig
@@ -789,6 +789,9 @@ config DOUBLEFAULT
endmenu
+config ARCH_ENABLE_MEMORY_HOTPLUG
+ def_bool y
+ depends on HIGHMEM
menu "Power management options (ACPI, APM)"
depends on !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/fixup.c b/linux-2.6-xen-sparse/arch/i386/kernel/fixup.c
index 20535e8fd4..2bf16fb732 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/fixup.c
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/fixup.c
@@ -46,6 +46,9 @@ fastcall void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
if (test_and_set_bit(0, &printed))
return;
+ if (current->tgid == 1) /* Ignore statically linked init */
+ return;
+
HYPERVISOR_vm_assist(
VMASST_CMD_disable, VMASST_TYPE_4gb_segments_notify);
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S b/linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
index dcef669792..1d0278c69b 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
@@ -9,7 +9,7 @@
#include <asm/page.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
-#include <xen/interface/arch-x86_32.h>
+#include <xen/interface/xen.h>
#include <xen/interface/elfnote.h>
/*
@@ -192,6 +192,7 @@ ENTRY(cpu_gdt_table)
#endif /* !CONFIG_XEN_COMPAT_030002 */
ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, startup_32)
ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page)
+ ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long, HYPERVISOR_VIRT_START)
ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel")
#ifdef CONFIG_X86_PAE
ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "yes")
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c
index 65d6ff995e..926ba175c3 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/microcode-xen.c
@@ -50,9 +50,6 @@ MODULE_LICENSE("GPL");
/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
static DECLARE_MUTEX(microcode_sem);
-
-static void __user *user_buffer; /* user area microcode data buffer */
-static unsigned int user_buffer_size; /* it's size */
static int microcode_open (struct inode *unused1, struct file *unused2)
{
@@ -60,21 +57,26 @@ static int microcode_open (struct inode *unused1, struct file *unused2)
}
-static int do_microcode_update (void)
+static int do_microcode_update (const void __user *ubuf, size_t len)
{
int err;
- dom0_op_t op;
+ void *kbuf;
+
+ kbuf = vmalloc(len);
+ if (!kbuf)
+ return -ENOMEM;
- err = sys_mlock((unsigned long)user_buffer, user_buffer_size);
- if (err != 0)
- return err;
+ if (copy_from_user(kbuf, ubuf, len) == 0) {
+ dom0_op_t op;
- op.cmd = DOM0_MICROCODE;
- set_xen_guest_handle(op.u.microcode.data, user_buffer);
- op.u.microcode.length = user_buffer_size;
- err = HYPERVISOR_dom0_op(&op);
+ op.cmd = DOM0_MICROCODE;
+ set_xen_guest_handle(op.u.microcode.data, kbuf);
+ op.u.microcode.length = len;
+ err = HYPERVISOR_dom0_op(&op);
+ } else
+ err = -EFAULT;
- (void)sys_munlock((unsigned long)user_buffer, user_buffer_size);
+ vfree(kbuf);
return err;
}
@@ -88,17 +90,9 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
return -EINVAL;
}
- if ((len >> PAGE_SHIFT) > num_physpages) {
- printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
- return -EINVAL;
- }
-
down(&microcode_sem);
- user_buffer = (void __user *) buf;
- user_buffer_size = (int) len;
-
- ret = do_microcode_update();
+ ret = do_microcode_update(buf, len);
if (!ret)
ret = (ssize_t)len;
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
index 3457e31c8c..2586296dbb 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
@@ -65,6 +65,7 @@
#include <xen/interface/physdev.h>
#include <xen/interface/memory.h>
#include <xen/features.h>
+#include <xen/xencons.h>
#include "setup_arch_pre.h"
#include <bios_ebda.h>
@@ -155,6 +156,9 @@ struct ist_info ist_info;
EXPORT_SYMBOL(ist_info);
#endif
struct e820map e820;
+#ifdef CONFIG_XEN
+struct e820map machine_e820;
+#endif
extern void early_cpu_init(void);
extern void generic_apic_probe(char *);
@@ -1450,7 +1454,6 @@ e820_setup_gap(struct e820entry *e820, int nr_map)
static void __init register_memory(void)
{
#ifdef CONFIG_XEN
- struct e820entry *machine_e820;
struct xen_memory_map memmap;
#endif
int i;
@@ -1460,14 +1463,14 @@ static void __init register_memory(void)
return;
#ifdef CONFIG_XEN
- machine_e820 = alloc_bootmem_low_pages(PAGE_SIZE);
-
memmap.nr_entries = E820MAX;
- set_xen_guest_handle(memmap.buffer, machine_e820);
+ set_xen_guest_handle(memmap.buffer, machine_e820.map);
- BUG_ON(HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap));
+ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
+ BUG();
+ machine_e820.nr_map = memmap.nr_entries;
- legacy_init_iomem_resources(machine_e820, memmap.nr_entries,
+ legacy_init_iomem_resources(machine_e820.map, machine_e820.nr_map,
&code_resource, &data_resource);
#else
if (efi_enabled)
@@ -1485,8 +1488,7 @@ static void __init register_memory(void)
request_resource(&ioport_resource, &standard_io_resources[i]);
#ifdef CONFIG_XEN
- e820_setup_gap(machine_e820, memmap.nr_entries);
- free_bootmem(__pa(machine_e820), PAGE_SIZE);
+ e820_setup_gap(machine_e820.map, machine_e820.nr_map);
#else
e820_setup_gap(e820.map, e820.nr_map);
#endif
@@ -1665,33 +1667,15 @@ void __init setup_arch(char **cmdline_p)
screen_info.orig_video_cols = 80;
screen_info.orig_video_ega_bx = 3;
screen_info.orig_video_points = 16;
+ screen_info.orig_y = screen_info.orig_video_lines - 1;
if (xen_start_info->console.dom0.info_size >=
sizeof(struct dom0_vga_console_info)) {
const struct dom0_vga_console_info *info =
(struct dom0_vga_console_info *)(
(char *)xen_start_info +
xen_start_info->console.dom0.info_off);
- screen_info.orig_video_mode = info->txt_mode;
- screen_info.orig_video_isVGA = info->video_type;
- screen_info.orig_video_lines = info->video_height;
- screen_info.orig_video_cols = info->video_width;
- screen_info.orig_video_points = info->txt_points;
- screen_info.lfb_width = info->video_width;
- screen_info.lfb_height = info->video_height;
- screen_info.lfb_depth = info->lfb_depth;
- screen_info.lfb_base = info->lfb_base;
- screen_info.lfb_size = info->lfb_size;
- screen_info.lfb_linelength = info->lfb_linelen;
- screen_info.red_size = info->red_size;
- screen_info.red_pos = info->red_pos;
- screen_info.green_size = info->green_size;
- screen_info.green_pos = info->green_pos;
- screen_info.blue_size = info->blue_size;
- screen_info.blue_pos = info->blue_pos;
- screen_info.rsvd_size = info->rsvd_size;
- screen_info.rsvd_pos = info->rsvd_pos;
+ dom0_init_screen_info(info);
}
- screen_info.orig_y = screen_info.orig_video_lines - 1;
xen_start_info->console.domU.mfn = 0;
xen_start_info->console.domU.evtchn = 0;
} else
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c b/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c
index 844c87e78c..f300bd159e 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/sysenter.c
@@ -60,7 +60,7 @@ int __init sysenter_setup(void)
#ifdef CONFIG_XEN
if (boot_cpu_has(X86_FEATURE_SEP)) {
- struct callback_register sysenter = {
+ static struct callback_register __initdata sysenter = {
.type = CALLBACKTYPE_sysenter,
.address = { __KERNEL_CS, (unsigned long)sysenter_entry },
};
diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c
index cc9907901b..05f3c47e50 100644
--- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c
@@ -716,6 +716,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
rcu_check_callbacks(cpu, user_mode(regs));
scheduler_tick();
run_posix_cpu_timers(current);
+ profile_tick(CPU_PROFILING, regs);
return IRQ_HANDLED;
}
diff --git a/linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c
index 16a0155ecb..4939ab106e 100644
--- a/linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c
@@ -282,12 +282,6 @@ static int spurious_fault(struct pt_regs *regs,
pmd_t *pmd;
pte_t *pte;
-#ifdef CONFIG_XEN
- /* Faults in hypervisor area are never spurious. */
- if (address >= HYPERVISOR_VIRT_START)
- return 0;
-#endif
-
/* Reserved-bit violation or user access to kernel space? */
if (error_code & 0x0c)
return 0;
@@ -372,7 +366,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
if (unlikely(address >= TASK_SIZE)) {
#ifdef CONFIG_XEN
/* Faults in hypervisor area can never be patched up. */
- if (address >= HYPERVISOR_VIRT_START)
+ if (address >= hypervisor_virt_start)
goto bad_area_nosemaphore;
#endif
if (!(error_code & 5))
diff --git a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c
index 5dc6646cf5..3c20351e92 100644
--- a/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c
+++ b/linux-2.6-xen-sparse/arch/i386/mm/hypervisor.c
@@ -99,18 +99,6 @@ void xen_l4_entry_update(pgd_t *ptr, pgd_t val)
}
#endif /* CONFIG_X86_64 */
-void xen_machphys_update(unsigned long mfn, unsigned long pfn)
-{
- mmu_update_t u;
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- BUG_ON(pfn != mfn);
- return;
- }
- u.ptr = ((unsigned long long)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
- u.val = pfn;
- BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
-}
-
void xen_pt_switch(unsigned long ptr)
{
struct mmuext_op op;
@@ -325,6 +313,7 @@ int xen_create_contiguous_region(
success = (exchange.nr_exchanged == (1UL << order));
BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
BUG_ON(success && (rc != 0));
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
/* Compatibility when XENMEM_exchange is unsupported. */
if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
@@ -341,6 +330,7 @@ int xen_create_contiguous_region(
BUG();
}
}
+#endif
/* 3. Map the new extent in place of old pages. */
for (i = 0; i < (1UL<<order); i++) {
@@ -419,6 +409,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
success = (exchange.nr_exchanged == 1);
BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
BUG_ON(success && (rc != 0));
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
/* Compatibility when XENMEM_exchange is unsupported. */
if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
@@ -429,6 +420,7 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
BUG();
success = 1;
}
+#endif
/* 4. Map new pages in place of old pages. */
for (i = 0; i < (1UL<<order); i++) {
diff --git a/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c
index c0c0bb2fa8..4d2b33068f 100644
--- a/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/mm/init-xen.c
@@ -130,7 +130,7 @@ static void __init page_table_range_init (unsigned long start, unsigned long end
pud = pud_offset(pgd, vaddr);
pmd = pmd_offset(pud, vaddr);
for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
- if (vaddr < HYPERVISOR_VIRT_START && pmd_none(*pmd))
+ if (vaddr < hypervisor_virt_start && pmd_none(*pmd))
one_page_table_init(pmd);
vaddr += PMD_SIZE;
@@ -187,7 +187,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
pmd += pmd_idx;
for (; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;
- if (address >= HYPERVISOR_VIRT_START)
+ if (address >= hypervisor_virt_start)
continue;
/* Map with big pages if possible, otherwise create normal page tables. */
@@ -410,7 +410,7 @@ static void __init pagetable_init (void)
* created - mappings will be set by set_fixmap():
*/
vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
- page_table_range_init(vaddr, 0, pgd_base);
+ page_table_range_init(vaddr, hypervisor_virt_start, pgd_base);
permanent_kmaps_init(pgd_base);
}
@@ -663,8 +663,8 @@ void __init mem_init(void)
totalram_pages += free_all_bootmem();
/* XEN: init and count low-mem pages outside initial allocation. */
for (pfn = xen_start_info->nr_pages; pfn < max_low_pfn; pfn++) {
- ClearPageReserved(&mem_map[pfn]);
- set_page_count(&mem_map[pfn], 1);
+ ClearPageReserved(pfn_to_page(pfn));
+ set_page_count(pfn_to_page(pfn), 1);
totalram_pages++;
}
diff --git a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
index 2fac26719c..b2e8832b85 100644
--- a/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c
@@ -29,6 +29,8 @@ static int direct_remap_area_pte_fn(pte_t *pte,
{
mmu_update_t **v = (mmu_update_t **)data;
+ BUG_ON(!pte_none(*pte));
+
(*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) <<
PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
(*v)++;
@@ -110,12 +112,14 @@ int direct_remap_pfn_range(struct vm_area_struct *vma,
pgprot_t prot,
domid_t domid)
{
- /* Same as remap_pfn_range(). */
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return remap_pfn_range(vma, address, mfn, size, prot);
if (domid == DOMID_SELF)
return -EINVAL;
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
vma->vm_mm->context.has_foreign_mappings = 1;
return __direct_remap_pfn_range(
@@ -245,7 +249,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
return NULL;
area->phys_addr = phys_addr;
addr = (void __iomem *) area->addr;
- flags |= _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED;
+ flags |= _KERNPG_TABLE;
if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr,
phys_addr>>PAGE_SHIFT,
size, __pgprot(flags), domid)) {
diff --git a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c
index 843c9d0fd3..0ff01f52f8 100644
--- a/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c
+++ b/linux-2.6-xen-sparse/arch/i386/mm/pgtable-xen.c
@@ -102,8 +102,11 @@ static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
return;
}
pte = pte_offset_kernel(pmd, vaddr);
- /* <pfn,flags> stored as-is, to permit clearing entries */
- set_pte(pte, pfn_pte(pfn, flags));
+ if (pgprot_val(flags))
+ /* <pfn,flags> stored as-is, to permit clearing entries */
+ set_pte(pte, pfn_pte(pfn, flags));
+ else
+ pte_clear(&init_mm, vaddr, pte);
/*
* It's enough to flush this one mapping.
@@ -140,8 +143,11 @@ static void set_pte_pfn_ma(unsigned long vaddr, unsigned long pfn,
return;
}
pte = pte_offset_kernel(pmd, vaddr);
- /* <pfn,flags> stored as-is, to permit clearing entries */
- set_pte(pte, pfn_pte_ma(pfn, flags));
+ if (pgprot_val(flags))
+ /* <pfn,flags> stored as-is, to permit clearing entries */
+ set_pte(pte, pfn_pte_ma(pfn, flags));
+ else
+ pte_clear(&init_mm, vaddr, pte);
/*
* It's enough to flush this one mapping.
@@ -186,9 +192,16 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
}
static int nr_fixmaps = 0;
+unsigned long hypervisor_virt_start = HYPERVISOR_VIRT_START;
unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE);
EXPORT_SYMBOL(__FIXADDR_TOP);
+void __init set_fixaddr_top()
+{
+ BUG_ON(nr_fixmaps > 0);
+ __FIXADDR_TOP = hypervisor_virt_start - 2 * PAGE_SIZE;
+}
+
void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags)
{
unsigned long address = __fix_to_virt(idx);
@@ -211,12 +224,6 @@ void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags)
nr_fixmaps++;
}
-void set_fixaddr_top(unsigned long top)
-{
- BUG_ON(nr_fixmaps > 0);
- __FIXADDR_TOP = top - PAGE_SIZE;
-}
-
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
diff --git a/linux-2.6-xen-sparse/arch/i386/oprofile/Makefile b/linux-2.6-xen-sparse/arch/i386/oprofile/Makefile
index e596c39c09..caaff108dc 100644
--- a/linux-2.6-xen-sparse/arch/i386/oprofile/Makefile
+++ b/linux-2.6-xen-sparse/arch/i386/oprofile/Makefile
@@ -7,7 +7,10 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
ifdef CONFIG_XEN
-oprofile-y := $(DRIVER_OBJS) xenoprof.o
+XENOPROF_COMMON_OBJS = $(addprefix ../../../drivers/xen/xenoprof/, \
+ xenoprofile.o)
+oprofile-y := $(DRIVER_OBJS) \
+ $(XENOPROF_COMMON_OBJS) xenoprof.o
else
oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
diff --git a/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c b/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c
index ed648c72cd..cf6d463fe7 100644
--- a/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c
+++ b/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c
@@ -9,249 +9,83 @@
* Modified by Aravind Menon and Jose Renato Santos for Xen
* These modifications are:
* Copyright (C) 2005 Hewlett-Packard Co.
+ *
+ * x86-specific part
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
*/
#include <linux/init.h>
-#include <linux/notifier.h>
-#include <linux/smp.h>
#include <linux/oprofile.h>
-#include <linux/sysdev.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <asm/nmi.h>
-#include <asm/msr.h>
-#include <asm/apic.h>
+#include <linux/sched.h>
#include <asm/pgtable.h>
-#include <xen/evtchn.h>
-#include "op_counter.h"
#include <xen/driver_util.h>
#include <xen/interface/xen.h>
#include <xen/interface/xenoprof.h>
-#include <../../../drivers/oprofile/cpu_buffer.h>
-#include <../../../drivers/oprofile/event_buffer.h>
-
-#define MAX_XENOPROF_SAMPLES 16
-
-static int xenoprof_start(void);
-static void xenoprof_stop(void);
+#include <xen/xenoprof.h>
+#include "op_counter.h"
-static int xenoprof_enabled = 0;
static unsigned int num_events = 0;
-static int is_primary = 0;
-static int active_defined;
-/* sample buffers shared with Xen */
-xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS];
-/* Shared buffer area */
-char * shared_buffer = NULL;
-/* Number of buffers in shared area (one per VCPU) */
-int nbuf;
-/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */
-int ovf_irq[NR_CPUS];
-/* cpu model type string - copied from Xen memory space on XENOPROF_init command */
-char cpu_type[XENOPROF_CPU_TYPE_SIZE];
-
-/* Passive sample buffers shared with Xen */
-xenoprof_buf_t *p_xenoprof_buf[MAX_OPROF_DOMAINS][MAX_VIRT_CPUS];
-/* Passive shared buffer area */
-char *p_shared_buffer[MAX_OPROF_DOMAINS];
-
-#ifdef CONFIG_PM
-
-static int xenoprof_suspend(struct sys_device * dev, pm_message_t state)
+void __init xenoprof_arch_init_counter(struct xenoprof_init *init)
{
- if (xenoprof_enabled == 1)
- xenoprof_stop();
- return 0;
-}
-
-
-static int xenoprof_resume(struct sys_device * dev)
-{
- if (xenoprof_enabled == 1)
- xenoprof_start();
- return 0;
-}
-
-
-static struct sysdev_class oprofile_sysclass = {
- set_kset_name("oprofile"),
- .resume = xenoprof_resume,
- .suspend = xenoprof_suspend
-};
-
-
-static struct sys_device device_oprofile = {
- .id = 0,
- .cls = &oprofile_sysclass,
-};
-
-
-static int __init init_driverfs(void)
-{
- int error;
- if (!(error = sysdev_class_register(&oprofile_sysclass)))
- error = sysdev_register(&device_oprofile);
- return error;
-}
-
-
-static void __exit exit_driverfs(void)
-{
- sysdev_unregister(&device_oprofile);
- sysdev_class_unregister(&oprofile_sysclass);
-}
-
-#else
-#define init_driverfs() do { } while (0)
-#define exit_driverfs() do { } while (0)
-#endif /* CONFIG_PM */
-
-unsigned long long oprofile_samples = 0;
-unsigned long long p_oprofile_samples = 0;
-
-unsigned int pdomains;
-struct xenoprof_passive passive_domains[MAX_OPROF_DOMAINS];
-
-static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive)
-{
- int head, tail, size;
-
- head = buf->event_head;
- tail = buf->event_tail;
- size = buf->event_size;
-
- if (tail > head) {
- while (tail < size) {
- oprofile_add_pc(buf->event_log[tail].eip,
- buf->event_log[tail].mode,
- buf->event_log[tail].event);
- if (!is_passive)
- oprofile_samples++;
- else
- p_oprofile_samples++;
- tail++;
- }
- tail = 0;
- }
- while (tail < head) {
- oprofile_add_pc(buf->event_log[tail].eip,
- buf->event_log[tail].mode,
- buf->event_log[tail].event);
- if (!is_passive)
- oprofile_samples++;
- else
- p_oprofile_samples++;
- tail++;
+ num_events = init->num_events;
+ /* just in case - make sure we do not overflow event list
+ (i.e. counter_config list) */
+ if (num_events > OP_MAX_COUNTER) {
+ num_events = OP_MAX_COUNTER;
+ init->num_events = num_events;
}
-
- buf->event_tail = tail;
}
-static void xenoprof_handle_passive(void)
+void xenoprof_arch_counter(void)
{
- int i, j;
- int flag_domain, flag_switch = 0;
-
- for (i = 0; i < pdomains; i++) {
- flag_domain = 0;
- for (j = 0; j < passive_domains[i].nbuf; j++) {
- xenoprof_buf_t *buf = p_xenoprof_buf[i][j];
- if (buf->event_head == buf->event_tail)
- continue;
- if (!flag_domain) {
- if (!oprofile_add_domain_switch(passive_domains[i].
- domain_id))
- goto done;
- flag_domain = 1;
- }
- xenoprof_add_pc(buf, 1);
- flag_switch = 1;
- }
+ int i;
+ struct xenoprof_counter counter;
+
+ for (i=0; i<num_events; i++) {
+ counter.ind = i;
+ counter.count = (uint64_t)counter_config[i].count;
+ counter.enabled = (uint32_t)counter_config[i].enabled;
+ counter.event = (uint32_t)counter_config[i].event;
+ counter.kernel = (uint32_t)counter_config[i].kernel;
+ counter.user = (uint32_t)counter_config[i].user;
+ counter.unit_mask = (uint64_t)counter_config[i].unit_mask;
+ HYPERVISOR_xenoprof_op(XENOPROF_counter,
+ &counter);
}
-done:
- if (flag_switch)
- oprofile_add_domain_switch(COORDINATOR_DOMAIN);
}
-static irqreturn_t
-xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+void xenoprof_arch_start(void)
{
- struct xenoprof_buf * buf;
- int cpu;
- static unsigned long flag;
-
- cpu = smp_processor_id();
- buf = xenoprof_buf[cpu];
-
- xenoprof_add_pc(buf, 0);
-
- if (is_primary && !test_and_set_bit(0, &flag)) {
- xenoprof_handle_passive();
- smp_mb__before_clear_bit();
- clear_bit(0, &flag);
- }
-
- return IRQ_HANDLED;
+ /* nothing */
}
-
-static void unbind_virq(void)
+void xenoprof_arch_stop(void)
{
- int i;
-
- for_each_cpu(i) {
- if (ovf_irq[i] >= 0) {
- unbind_from_irqhandler(ovf_irq[i], NULL);
- ovf_irq[i] = -1;
- }
- }
+ /* nothing */
}
-
-static int bind_virq(void)
+void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer * sbuf)
{
- int i, result;
-
- for_each_cpu(i) {
- result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
- i,
- xenoprof_ovf_interrupt,
- SA_INTERRUPT,
- "xenoprof",
- NULL);
-
- if (result < 0) {
- unbind_virq();
- return result;
- }
-
- ovf_irq[i] = result;
+ if (sbuf->buffer) {
+ vunmap(sbuf->buffer);
+ sbuf->buffer = NULL;
}
-
- return 0;
}
-
-static int map_xenoprof_buffer(int max_samples)
+int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer * get_buffer,
+ struct xenoprof_shared_buffer * sbuf)
{
- struct xenoprof_get_buffer get_buffer;
- struct xenoprof_buf *buf;
- int npages, ret, i;
+ int npages, ret;
struct vm_struct *area;
- if ( shared_buffer )
- return 0;
-
- get_buffer.max_samples = max_samples;
-
- if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, &get_buffer)) )
+ sbuf->buffer = NULL;
+ if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, get_buffer)) )
return ret;
- nbuf = get_buffer.nbuf;
- npages = (get_buffer.bufsize * nbuf - 1) / PAGE_SIZE + 1;
+ npages = (get_buffer->bufsize * get_buffer->nbuf - 1) / PAGE_SIZE + 1;
area = alloc_vm_area(npages * PAGE_SIZE);
if (area == NULL)
@@ -259,231 +93,55 @@ static int map_xenoprof_buffer(int max_samples)
if ( (ret = direct_kernel_remap_pfn_range(
(unsigned long)area->addr,
- get_buffer.buf_maddr >> PAGE_SHIFT,
- npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE), DOMID_SELF)) ) {
+ get_buffer->buf_gmaddr >> PAGE_SHIFT,
+ npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE),
+ DOMID_SELF)) ) {
vunmap(area->addr);
return ret;
}
- shared_buffer = area->addr;
- for (i=0; i< nbuf; i++) {
- buf = (struct xenoprof_buf*)
- &shared_buffer[i * get_buffer.bufsize];
- BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
- xenoprof_buf[buf->vcpu_id] = buf;
- }
-
- return 0;
-}
-
-
-static int xenoprof_setup(void)
-{
- int ret;
- int i;
-
- if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) )
- return ret;
-
- if ( (ret = bind_virq()) )
- return ret;
-
- if (is_primary) {
- struct xenoprof_counter counter;
-
- /* Define dom0 as an active domain if not done yet */
- if (!active_defined) {
- domid_t domid;
- ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
- if (ret)
- goto err;
- domid = 0;
- ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
- if (ret)
- goto err;
- active_defined = 1;
- }
-
- ret = HYPERVISOR_xenoprof_op(XENOPROF_reserve_counters, NULL);
- if (ret)
- goto err;
- for (i=0; i<num_events; i++) {
- counter.ind = i;
- counter.count = (uint64_t)counter_config[i].count;
- counter.enabled = (uint32_t)counter_config[i].enabled;
- counter.event = (uint32_t)counter_config[i].event;
- counter.kernel = (uint32_t)counter_config[i].kernel;
- counter.user = (uint32_t)counter_config[i].user;
- counter.unit_mask = (uint64_t)counter_config[i].unit_mask;
- HYPERVISOR_xenoprof_op(XENOPROF_counter,
- &counter);
- }
- ret = HYPERVISOR_xenoprof_op(XENOPROF_setup_events, NULL);
-
- if (ret)
- goto err;
- }
-
- ret = HYPERVISOR_xenoprof_op(XENOPROF_enable_virq, NULL);
- if (ret)
- goto err;
-
- xenoprof_enabled = 1;
- return 0;
- err:
- unbind_virq();
- return ret;
-}
-
-
-static void xenoprof_shutdown(void)
-{
- xenoprof_enabled = 0;
-
- HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL);
-
- if (is_primary) {
- HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL);
- active_defined = 0;
- }
-
- unbind_virq();
-
-}
-
-
-static int xenoprof_start(void)
-{
- int ret = 0;
-
- if (is_primary)
- ret = HYPERVISOR_xenoprof_op(XENOPROF_start, NULL);
-
- return ret;
-}
-
-
-static void xenoprof_stop(void)
-{
- if (is_primary)
- HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL);
-}
-
-
-static int xenoprof_set_active(int * active_domains,
- unsigned int adomains)
-{
- int ret = 0;
- int i;
- int set_dom0 = 0;
- domid_t domid;
-
- if (!is_primary)
- return 0;
-
- if (adomains > MAX_OPROF_DOMAINS)
- return -E2BIG;
-
- ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
- if (ret)
- return ret;
-
- for (i=0; i<adomains; i++) {
- domid = active_domains[i];
- if (domid != active_domains[i]) {
- ret = -EINVAL;
- goto out;
- }
- ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
- if (ret)
- goto out;
- if (active_domains[i] == 0)
- set_dom0 = 1;
- }
- /* dom0 must always be active but may not be in the list */
- if (!set_dom0) {
- domid = 0;
- ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
- }
-
-out:
- if (ret)
- HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
- active_defined = !ret;
+ sbuf->buffer = area->addr;
return ret;
}
-static int xenoprof_set_passive(int * p_domains,
- unsigned int pdoms)
+int xenoprof_arch_set_passive(struct xenoprof_passive * pdomain,
+ struct xenoprof_shared_buffer * sbuf)
{
int ret;
- int i, j;
int npages;
- struct xenoprof_buf *buf;
struct vm_struct *area;
pgprot_t prot = __pgprot(_KERNPG_TABLE);
- if (!is_primary)
- return 0;
-
- if (pdoms > MAX_OPROF_DOMAINS)
- return -E2BIG;
-
- ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_passive_list, NULL);
+ sbuf->buffer = NULL;
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive, pdomain);
if (ret)
- return ret;
-
- for (i = 0; i < pdoms; i++) {
- passive_domains[i].domain_id = p_domains[i];
- passive_domains[i].max_samples = 2048;
- ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive,
- &passive_domains[i]);
- if (ret)
- goto out;
-
- npages = (passive_domains[i].bufsize * passive_domains[i].nbuf - 1) / PAGE_SIZE + 1;
-
- area = alloc_vm_area(npages * PAGE_SIZE);
- if (area == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = direct_kernel_remap_pfn_range(
- (unsigned long)area->addr,
- passive_domains[i].buf_maddr >> PAGE_SHIFT,
- npages * PAGE_SIZE, prot, DOMID_SELF);
- if (ret) {
- vunmap(area->addr);
- goto out;
- }
+ goto out;
- p_shared_buffer[i] = area->addr;
-
- for (j = 0; j < passive_domains[i].nbuf; j++) {
- buf = (struct xenoprof_buf *)
- &p_shared_buffer[i][j * passive_domains[i].bufsize];
- BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
- p_xenoprof_buf[i][buf->vcpu_id] = buf;
- }
+ npages = (pdomain->bufsize * pdomain->nbuf - 1) / PAGE_SIZE + 1;
+ area = alloc_vm_area(npages * PAGE_SIZE);
+ if (area == NULL) {
+ ret = -ENOMEM;
+ goto out;
}
- pdomains = pdoms;
- return 0;
-
-out:
- for (j = 0; j < i; j++) {
- vunmap(p_shared_buffer[j]);
- p_shared_buffer[j] = NULL;
+ ret = direct_kernel_remap_pfn_range(
+ (unsigned long)area->addr,
+ pdomain->buf_gmaddr >> PAGE_SHIFT,
+ npages * PAGE_SIZE, prot, DOMID_SELF);
+ if (ret) {
+ vunmap(area->addr);
+ goto out;
}
+ sbuf->buffer = area->addr;
- return ret;
+out:
+ return ret;
}
struct op_counter_config counter_config[OP_MAX_COUNTER];
-static int xenoprof_create_files(struct super_block * sb, struct dentry * root)
+int xenoprof_create_files(struct super_block * sb, struct dentry * root)
{
unsigned int i;
@@ -510,75 +168,12 @@ static int xenoprof_create_files(struct super_block * sb, struct dentry * root)
return 0;
}
-
-struct oprofile_operations xenoprof_ops = {
- .create_files = xenoprof_create_files,
- .set_active = xenoprof_set_active,
- .set_passive = xenoprof_set_passive,
- .setup = xenoprof_setup,
- .shutdown = xenoprof_shutdown,
- .start = xenoprof_start,
- .stop = xenoprof_stop
-};
-
-
-/* in order to get driverfs right */
-static int using_xenoprof;
-
int __init oprofile_arch_init(struct oprofile_operations * ops)
{
- struct xenoprof_init init;
- int ret, i;
-
- ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init);
-
- if (!ret) {
- num_events = init.num_events;
- is_primary = init.is_primary;
-
- /* just in case - make sure we do not overflow event list
- (i.e. counter_config list) */
- if (num_events > OP_MAX_COUNTER)
- num_events = OP_MAX_COUNTER;
-
- /* cpu_type is detected by Xen */
- cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0;
- strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1);
- xenoprof_ops.cpu_type = cpu_type;
-
- init_driverfs();
- using_xenoprof = 1;
- *ops = xenoprof_ops;
-
- for (i=0; i<NR_CPUS; i++)
- ovf_irq[i] = -1;
-
- active_defined = 0;
- }
- printk(KERN_INFO "oprofile_arch_init: ret %d, events %d, "
- "is_primary %d\n", ret, num_events, is_primary);
- return ret;
+ return xenoprofile_init(ops);
}
-
-void __exit oprofile_arch_exit(void)
+void oprofile_arch_exit(void)
{
- int i;
-
- if (using_xenoprof)
- exit_driverfs();
-
- if (shared_buffer) {
- vunmap(shared_buffer);
- shared_buffer = NULL;
- }
- if (is_primary) {
- for (i = 0; i < pdomains; i++)
- if (p_shared_buffer[i]) {
- vunmap(p_shared_buffer[i]);
- p_shared_buffer[i] = NULL;
- }
- HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL);
- }
-
+ xenoprofile_exit();
}
diff --git a/linux-2.6-xen-sparse/arch/ia64/Kconfig b/linux-2.6-xen-sparse/arch/ia64/Kconfig
index c32f4cee4c..4073a04638 100644
--- a/linux-2.6-xen-sparse/arch/ia64/Kconfig
+++ b/linux-2.6-xen-sparse/arch/ia64/Kconfig
@@ -64,6 +64,20 @@ config XEN_IA64_VDSO_PARAVIRT
help
vDSO paravirtualization
+config XEN_IA64_EXPOSE_P2M
+ bool "Xen/IA64 exposure p2m table"
+ depends on XEN
+ default y
+ help
+ expose p2m from xen
+
+config XEN_IA64_EXPOSE_P2M_USE_DTR
+ bool "Xen/IA64 map p2m table with dtr"
+ depends on XEN_IA64_EXPOSE_P2M
+ default y
+ help
+ use dtr to map the exposed p2m table
+
config SCHED_NO_NO_OMIT_FRAME_POINTER
bool
default y
@@ -276,6 +290,9 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
+config ARCH_ENABLE_MEMORY_HOTPLUG
+ def_bool y
+
config SCHED_SMT
bool "SMT scheduler support"
depends on SMP
diff --git a/linux-2.6-xen-sparse/arch/ia64/dig/setup.c b/linux-2.6-xen-sparse/arch/ia64/dig/setup.c
index 90d6ab64fa..7f3826991a 100644
--- a/linux-2.6-xen-sparse/arch/ia64/dig/setup.c
+++ b/linux-2.6-xen-sparse/arch/ia64/dig/setup.c
@@ -25,6 +25,8 @@
#include <asm/machvec.h>
#include <asm/system.h>
+#include <xen/xencons.h>
+
void __init
dig_setup (char **cmdline_p)
{
@@ -78,27 +80,8 @@ dig_setup (char **cmdline_p)
(struct dom0_vga_console_info *)(
(char *)xen_start_info +
xen_start_info->console.dom0.info_off);
- screen_info.orig_video_mode = info->txt_mode;
- screen_info.orig_video_isVGA = info->video_type;
- screen_info.orig_video_lines = info->video_height;
- screen_info.orig_video_cols = info->video_width;
- screen_info.orig_video_points = info->txt_points;
- screen_info.lfb_width = info->video_width;
- screen_info.lfb_height = info->video_height;
- screen_info.lfb_depth = info->lfb_depth;
- screen_info.lfb_base = info->lfb_base;
- screen_info.lfb_size = info->lfb_size;
- screen_info.lfb_linelength = info->lfb_linelen;
- screen_info.red_size = info->red_size;
- screen_info.red_pos = info->red_pos;
- screen_info.green_size = info->green_size;
- screen_info.green_pos = info->green_pos;
- screen_info.blue_size = info->blue_size;
- screen_info.blue_pos = info->blue_pos;
- screen_info.rsvd_size = info->rsvd_size;
- screen_info.rsvd_pos = info->rsvd_pos;
+ dom0_init_screen_info(info);
}
- screen_info.orig_y = screen_info.orig_video_lines - 1;
xen_start_info->console.domU.mfn = 0;
xen_start_info->console.domU.evtchn = 0;
#endif
diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile b/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile
new file mode 100644
index 0000000000..003e9ee600
--- /dev/null
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile
@@ -0,0 +1,62 @@
+#
+# Makefile for the linux kernel.
+#
+
+extra-y := head.o init_task.o vmlinux.lds
+
+obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
+ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
+ salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
+ unwind.o mca.o mca_asm.o topology.o
+
+obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
+obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o
+obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o
+obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o
+
+ifneq ($(CONFIG_ACPI_PROCESSOR),)
+obj-y += acpi-processor.o
+endif
+
+obj-$(CONFIG_IA64_PALINFO) += palinfo.o
+obj-$(CONFIG_IOSAPIC) += iosapic.o
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_SMP) += smp.o smpboot.o
+obj-$(CONFIG_NUMA) += numa.o
+obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
+obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq/
+obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
+obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
+obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
+mca_recovery-y += mca_drv.o mca_drv_asm.o
+
+# The gate DSO image is built using a special linker script.
+targets += gate.so gate-syms.o
+
+extra-y += gate.so gate-syms.o gate.lds gate.o
+
+# fp_emulate() expects f2-f5,f16-f31 to contain the user-level state.
+CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31
+
+CPPFLAGS_gate.lds := -P -C -U$(ARCH)
+
+quiet_cmd_gate = GATE $@
+ cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
+$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
+ $(call if_changed,gate)
+
+$(obj)/built-in.o: $(obj)/gate-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
+
+GATECFLAGS_gate-syms.o = -r
+$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
+ $(call if_changed,gate)
+
+# gate-data.o contains the gate DSO image as data in section .data.gate.
+# We must build gate.so before we can assemble it.
+# Note: kbuild does not track this dependency due to usage of .incbin
+$(obj)/gate-data.o: $(obj)/gate.so
diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S b/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S
index 5f0163f0be..45377beaa4 100644
--- a/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S
@@ -13,6 +13,7 @@ SECTIONS
. = GATE_ADDR + SIZEOF_HEADERS;
.hash : { *(.hash) } :readable
+ .gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c
index f792900cf9..8f15b3001c 100644
--- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c
@@ -63,6 +63,7 @@
#include <asm/system.h>
#ifdef CONFIG_XEN
#include <asm/hypervisor.h>
+#include <asm/xen/xencomm.h>
#endif
#include <linux/dma-mapping.h>
@@ -433,6 +434,9 @@ setup_arch (char **cmdline_p)
#ifdef CONFIG_XEN
if (is_running_on_xen()) {
+ /* Must be done before any hypercall. */
+ xencomm_init();
+
setup_xen_features();
/* Register a call for panic conditions. */
notifier_chain_register(&panic_notifier_list, &xen_panic_block);
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile
index c2b4f94edd..36434aac72 100644
--- a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile
@@ -3,6 +3,7 @@
#
obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \
- hypervisor.o pci-dma-xen.o util.o
+ hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \
+ xcom_mini.o xcom_privcmd.o
pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c
index 0b286047b9..2a85caa0d5 100644
--- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c
@@ -40,59 +40,11 @@ EXPORT_SYMBOL(xen_start_info);
int running_on_xen;
EXPORT_SYMBOL(running_on_xen);
-//XXX xen/ia64 copy_from_guest() is broken.
-// This is a temporal work around until it is fixed.
-// used by balloon.c netfront.c
-
-// get_xen_guest_handle is defined only when __XEN_TOOLS__ is defined
-// if the definition in arch-ia64.h is changed, this must be updated.
-#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
-
-int
-ia64_xenmem_reservation_op(unsigned long op,
- struct xen_memory_reservation* reservation__)
-{
- struct xen_memory_reservation reservation = *reservation__;
- unsigned long* frame_list;
- unsigned long nr_extents = reservation__->nr_extents;
- int ret = 0;
- get_xen_guest_handle(frame_list, reservation__->extent_start);
-
- BUG_ON(op != XENMEM_increase_reservation &&
- op != XENMEM_decrease_reservation &&
- op != XENMEM_populate_physmap);
-
- while (nr_extents > 0) {
- int tmp_ret;
- volatile unsigned long dummy;
-
- set_xen_guest_handle(reservation.extent_start, frame_list);
- reservation.nr_extents = nr_extents;
-
- dummy = frame_list[0];// re-install tlb entry before hypercall
- tmp_ret = ____HYPERVISOR_memory_op(op, &reservation);
- if (tmp_ret < 0) {
- if (ret == 0) {
- ret = tmp_ret;
- }
- break;
- }
- if (tmp_ret == 0) {
- //XXX dirty work around for skbuff_ctor()
- // of a non-privileged domain,
- if ((op == XENMEM_increase_reservation ||
- op == XENMEM_populate_physmap) &&
- !is_initial_xendomain() &&
- reservation.extent_order > 0)
- return ret;
- }
- frame_list += tmp_ret;
- nr_extents -= tmp_ret;
- ret += tmp_ret;
- }
- return ret;
-}
-EXPORT_SYMBOL(ia64_xenmem_reservation_op);
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+static int p2m_expose_init(void);
+#else
+#define p2m_expose_init() (-ENOSYS)
+#endif
//XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear()
// move those to lib/contiguous_bitmap?
@@ -371,8 +323,6 @@ gnttab_map_grant_ref_pre(struct gnttab_map_grant_ref *uop)
int
HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
{
- __u64 va1, va2, pa1, pa2;
-
if (cmd == GNTTABOP_map_grant_ref) {
unsigned int i;
for (i = 0; i < count; i++) {
@@ -380,29 +330,7 @@ HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
(struct gnttab_map_grant_ref*)uop + i);
}
}
- va1 = (__u64)uop & PAGE_MASK;
- pa1 = pa2 = 0;
- if ((REGION_NUMBER(va1) == 5) &&
- ((va1 - KERNEL_START) >= KERNEL_TR_PAGE_SIZE)) {
- pa1 = ia64_tpa(va1);
- if (cmd <= GNTTABOP_transfer) {
- static uint32_t uop_size[GNTTABOP_transfer + 1] = {
- sizeof(struct gnttab_map_grant_ref),
- sizeof(struct gnttab_unmap_grant_ref),
- sizeof(struct gnttab_setup_table),
- sizeof(struct gnttab_dump_table),
- sizeof(struct gnttab_transfer),
- };
- va2 = (__u64)uop + (uop_size[cmd] * count) - 1;
- va2 &= PAGE_MASK;
- if (va1 != va2) {
- /* maximum size of uop is 2pages */
- BUG_ON(va2 > va1 + PAGE_SIZE);
- pa2 = ia64_tpa(va2);
- }
- }
- }
- return ____HYPERVISOR_grant_table_op(cmd, uop, count, pa1, pa2);
+ return xencomm_mini_hypercall_grant_table_op(cmd, uop, count);
}
EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
@@ -526,6 +454,10 @@ out:
privcmd_resource_min, privcmd_resource_max,
(privcmd_resource_max - privcmd_resource_min) >> 20);
BUG_ON(privcmd_resource_min >= privcmd_resource_max);
+
+ // XXX this should be somewhere appropriate
+ (void)p2m_expose_init();
+
return 0;
}
late_initcall(xen_ia64_privcmd_init);
@@ -546,6 +478,7 @@ struct xen_ia64_privcmd_range {
};
struct xen_ia64_privcmd_vma {
+ int is_privcmd_mmapped;
struct xen_ia64_privcmd_range* range;
unsigned long num_entries;
@@ -684,12 +617,15 @@ __xen_ia64_privcmd_vma_open(struct vm_area_struct* vma,
static void
xen_ia64_privcmd_vma_open(struct vm_area_struct* vma)
{
+ struct xen_ia64_privcmd_vma* old_privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
struct xen_ia64_privcmd_vma* privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range;
atomic_inc(&privcmd_range->ref_count);
// vm_op->open() can't fail.
privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL);
+ // copy original value if necessary
+ privcmd_vma->is_privcmd_mmapped = old_privcmd_vma->is_privcmd_mmapped;
__xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range);
}
@@ -725,6 +661,14 @@ xen_ia64_privcmd_vma_close(struct vm_area_struct* vma)
}
int
+privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
+{
+ struct xen_ia64_privcmd_vma* privcmd_vma =
+ (struct xen_ia64_privcmd_vma *)vma->vm_private_data;
+ return (xchg(&privcmd_vma->is_privcmd_mmapped, 1) == 0);
+}
+
+int
privcmd_mmap(struct file * file, struct vm_area_struct * vma)
{
int error;
@@ -749,6 +693,8 @@ privcmd_mmap(struct file * file, struct vm_area_struct * vma)
if (privcmd_vma == NULL) {
goto out_enomem1;
}
+ privcmd_vma->is_privcmd_mmapped = 0;
+
res = kzalloc(sizeof(*res), GFP_KERNEL);
if (res == NULL) {
goto out_enomem1;
@@ -831,3 +777,276 @@ time_resume(void)
/* Just trigger a tick. */
ia64_cpu_local_tick();
}
+
+///////////////////////////////////////////////////////////////////////////
+// expose p2m table
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+#include <linux/cpu.h>
+#include <asm/uaccess.h>
+
+int p2m_initialized __read_mostly = 0;
+
+unsigned long p2m_min_low_pfn __read_mostly;
+unsigned long p2m_max_low_pfn __read_mostly;
+unsigned long p2m_convert_min_pfn __read_mostly;
+unsigned long p2m_convert_max_pfn __read_mostly;
+
+static struct resource p2m_resource = {
+ .name = "Xen p2m table",
+ .flags = IORESOURCE_MEM,
+};
+static unsigned long p2m_assign_start_pfn __read_mostly;
+static unsigned long p2m_assign_end_pfn __read_mostly;
+volatile const pte_t* p2m_pte __read_mostly;
+
+#define GRNULE_PFN PTRS_PER_PTE
+static unsigned long p2m_granule_pfn __read_mostly = GRNULE_PFN;
+
+#define ROUNDDOWN(x, y) ((x) & ~((y) - 1))
+#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1))
+
+#define P2M_PREFIX "Xen p2m: "
+
+static int xen_ia64_p2m_expose __read_mostly = 1;
+module_param(xen_ia64_p2m_expose, int, 0);
+MODULE_PARM_DESC(xen_ia64_p2m_expose,
+ "enable/disable xen/ia64 p2m exposure optimization\n");
+
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+static int xen_ia64_p2m_expose_use_dtr __read_mostly = 1;
+module_param(xen_ia64_p2m_expose_use_dtr, int, 0);
+MODULE_PARM_DESC(xen_ia64_p2m_expose_use_dtr,
+ "use/unuse dtr to map exposed p2m table\n");
+
+static const int p2m_page_shifts[] = {
+ _PAGE_SIZE_4K,
+ _PAGE_SIZE_8K,
+ _PAGE_SIZE_16K,
+ _PAGE_SIZE_64K,
+ _PAGE_SIZE_256K,
+ _PAGE_SIZE_1M,
+ _PAGE_SIZE_4M,
+ _PAGE_SIZE_16M,
+ _PAGE_SIZE_64M,
+ _PAGE_SIZE_256M,
+};
+
+struct p2m_itr_arg {
+ unsigned long vaddr;
+ unsigned long pteval;
+ unsigned long log_page_size;
+};
+static struct p2m_itr_arg p2m_itr_arg __read_mostly;
+
+// This should be in asm-ia64/kregs.h
+#define IA64_TR_P2M_TABLE 3
+
+static void
+p2m_itr(void* info)
+{
+ struct p2m_itr_arg* arg = (struct p2m_itr_arg*)info;
+ ia64_itr(0x2, IA64_TR_P2M_TABLE,
+ arg->vaddr, arg->pteval, arg->log_page_size);
+ ia64_srlz_d();
+}
+
+static int
+p2m_expose_dtr_call(struct notifier_block *self,
+ unsigned long event, void* ptr)
+{
+ unsigned int cpu = (unsigned int)(long)ptr;
+ if (event != CPU_ONLINE)
+ return 0;
+ if (!(p2m_initialized && xen_ia64_p2m_expose_use_dtr))
+ smp_call_function_single(cpu, &p2m_itr, &p2m_itr_arg, 1, 1);
+ return 0;
+}
+
+static struct notifier_block p2m_expose_dtr_hotplug_notifier = {
+ .notifier_call = p2m_expose_dtr_call,
+ .next = NULL,
+ .priority = 0
+};
+#endif
+
+static int
+p2m_expose_init(void)
+{
+ unsigned long num_pfn;
+ unsigned long size = 0;
+ unsigned long p2m_size = 0;
+ unsigned long align = ~0UL;
+ int error = 0;
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+ int i;
+ unsigned long page_size;
+ unsigned long log_page_size = 0;
+#endif
+
+ if (!xen_ia64_p2m_expose)
+ return -ENOSYS;
+ if (p2m_initialized)
+ return 0;
+
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+ error = register_cpu_notifier(&p2m_expose_dtr_hotplug_notifier);
+ if (error < 0)
+ return error;
+#endif
+
+ lock_cpu_hotplug();
+ if (p2m_initialized)
+ goto out;
+
+#ifdef CONFIG_DISCONTIGMEM
+ p2m_min_low_pfn = min_low_pfn;
+ p2m_max_low_pfn = max_low_pfn;
+#else
+ p2m_min_low_pfn = 0;
+ p2m_max_low_pfn = max_pfn;
+#endif
+
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+ if (xen_ia64_p2m_expose_use_dtr) {
+ unsigned long granule_pfn = 0;
+ p2m_size = p2m_max_low_pfn - p2m_min_low_pfn;
+ for (i = 0;
+ i < sizeof(p2m_page_shifts)/sizeof(p2m_page_shifts[0]);
+ i++) {
+ log_page_size = p2m_page_shifts[i];
+ page_size = 1UL << log_page_size;
+ if (page_size < p2m_size)
+ continue;
+
+ granule_pfn = max(page_size >> PAGE_SHIFT,
+ p2m_granule_pfn);
+ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
+ granule_pfn);
+ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn,
+ granule_pfn);
+ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
+ size = num_pfn << PAGE_SHIFT;
+ p2m_size = num_pfn / PTRS_PER_PTE;
+ p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT);
+ if (p2m_size == page_size)
+ break;
+ }
+ if (p2m_size != page_size) {
+ printk(KERN_ERR "p2m_size != page_size\n");
+ error = -EINVAL;
+ goto out;
+ }
+ align = max(privcmd_resource_align, granule_pfn << PAGE_SHIFT);
+ } else
+#endif
+ {
+ BUG_ON(p2m_granule_pfn & (p2m_granule_pfn - 1));
+ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
+ p2m_granule_pfn);
+ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn);
+ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
+ size = num_pfn << PAGE_SHIFT;
+ p2m_size = num_pfn / PTRS_PER_PTE;
+ p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT);
+ align = max(privcmd_resource_align,
+ p2m_granule_pfn << PAGE_SHIFT);
+ }
+
+ // use privcmd region
+ error = allocate_resource(&iomem_resource, &p2m_resource, p2m_size,
+ privcmd_resource_min, privcmd_resource_max,
+ align, NULL, NULL);
+ if (error) {
+ printk(KERN_ERR P2M_PREFIX
+ "can't allocate region for p2m exposure "
+ "[0x%016lx, 0x%016lx) 0x%016lx\n",
+ p2m_convert_min_pfn, p2m_convert_max_pfn, p2m_size);
+ goto out;
+ }
+
+ p2m_assign_start_pfn = p2m_resource.start >> PAGE_SHIFT;
+ p2m_assign_end_pfn = p2m_resource.end >> PAGE_SHIFT;
+
+ error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn,
+ p2m_assign_start_pfn,
+ size, p2m_granule_pfn);
+ if (error) {
+ printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n",
+ error);
+ printk(KERN_ERR P2M_PREFIX "conv 0x%016lx assign 0x%016lx "
+ "size 0x%016lx granule 0x%016lx\n",
+ p2m_convert_min_pfn, p2m_assign_start_pfn,
+ size, p2m_granule_pfn);;
+ release_resource(&p2m_resource);
+ goto out;
+ }
+ p2m_pte = (volatile const pte_t*)pfn_to_kaddr(p2m_assign_start_pfn);
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+ if (xen_ia64_p2m_expose_use_dtr) {
+ p2m_itr_arg.vaddr = (unsigned long)__va(p2m_assign_start_pfn
+ << PAGE_SHIFT);
+ p2m_itr_arg.pteval = pte_val(pfn_pte(p2m_assign_start_pfn,
+ PAGE_KERNEL));
+ p2m_itr_arg.log_page_size = log_page_size;
+ smp_mb();
+ smp_call_function(&p2m_itr, &p2m_itr_arg, 1, 1);
+ p2m_itr(&p2m_itr_arg);
+ }
+#endif
+ smp_mb();
+ p2m_initialized = 1;
+ printk(P2M_PREFIX "assign p2m table of [0x%016lx, 0x%016lx)\n",
+ p2m_convert_min_pfn << PAGE_SHIFT,
+ p2m_convert_max_pfn << PAGE_SHIFT);
+ printk(P2M_PREFIX "to [0x%016lx, 0x%016lx) (%ld KBytes)\n",
+ p2m_assign_start_pfn << PAGE_SHIFT,
+ p2m_assign_end_pfn << PAGE_SHIFT,
+ p2m_size / 1024);
+out:
+ unlock_cpu_hotplug();
+ return error;
+}
+
+#ifdef notyet
+void
+p2m_expose_cleanup(void)
+{
+ BUG_ON(!p2m_initialized);
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
+ unregister_cpu_notifier(&p2m_expose_dtr_hotplug_notifier);
+#endif
+ release_resource(&p2m_resource);
+}
+#endif
+
+//XXX inlinize?
+unsigned long
+p2m_phystomach(unsigned long gpfn)
+{
+ volatile const pte_t* pte;
+ unsigned long mfn;
+ unsigned long pteval;
+
+ if (!p2m_initialized ||
+ gpfn < p2m_min_low_pfn || gpfn > p2m_max_low_pfn
+ /* || !pfn_valid(gpfn) */)
+ return INVALID_MFN;
+ pte = p2m_pte + (gpfn - p2m_convert_min_pfn);
+
+ mfn = INVALID_MFN;
+ if (likely(__get_user(pteval, (unsigned long __user *)pte) == 0 &&
+ pte_present(__pte(pteval)) &&
+ pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT)))
+ mfn = (pteval & _PFN_MASK) >> PAGE_SHIFT;
+
+ return mfn;
+}
+
+EXPORT_SYMBOL_GPL(p2m_initialized);
+EXPORT_SYMBOL_GPL(p2m_min_low_pfn);
+EXPORT_SYMBOL_GPL(p2m_max_low_pfn);
+EXPORT_SYMBOL_GPL(p2m_convert_min_pfn);
+EXPORT_SYMBOL_GPL(p2m_convert_max_pfn);
+EXPORT_SYMBOL_GPL(p2m_pte);
+EXPORT_SYMBOL_GPL(p2m_phystomach);
+#endif
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/util.c b/linux-2.6-xen-sparse/arch/ia64/xen/util.c
index 02dfaabc66..7df0c5f72c 100644
--- a/linux-2.6-xen-sparse/arch/ia64/xen/util.c
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/util.c
@@ -28,6 +28,8 @@
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <xen/driver_util.h>
+#include <xen/interface/memory.h>
+#include <asm/hypercall.h>
struct vm_struct *alloc_vm_area(unsigned long size)
{
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c
new file mode 100644
index 0000000000..fda0a45ec5
--- /dev/null
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ *
+ * Tristan Gingold <tristan.gingold@bull.net>
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/dom0_ops.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/xencomm.h>
+#include <xen/interface/version.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/event_channel.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/callback.h>
+#include <xen/interface/acm_ops.h>
+#include <xen/interface/hvm/params.h>
+#include <asm/hypercall.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/xen/xencomm.h>
+
+/* Xencomm notes:
+ * This file defines hypercalls to be used by xencomm. The hypercalls simply
+ * create inlines descriptors for pointers and then call the raw arch hypercall
+ * xencomm_arch_hypercall_XXX
+ *
+ * If the arch wants to directly use these hypercalls, simply define macros
+ * in asm/hypercall.h, eg:
+ * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
+ *
+ * The arch may also define HYPERVISOR_xxx as a function and do more operations
+ * before/after doing the hypercall.
+ *
+ * Note: because only inline descriptors are created these functions must only
+ * be called with in kernel memory parameters.
+ */
+
+int
+xencomm_hypercall_console_io(int cmd, int count, char *str)
+{
+ return xencomm_arch_hypercall_console_io
+ (cmd, count, xencomm_create_inline(str));
+}
+
+int
+xencomm_hypercall_event_channel_op(int cmd, void *op)
+{
+ return xencomm_arch_hypercall_event_channel_op
+ (cmd, xencomm_create_inline(op));
+}
+
+int
+xencomm_hypercall_xen_version(int cmd, void *arg)
+{
+ switch (cmd) {
+ case XENVER_version:
+ case XENVER_extraversion:
+ case XENVER_compile_info:
+ case XENVER_capabilities:
+ case XENVER_changeset:
+ case XENVER_platform_parameters:
+ case XENVER_pagesize:
+ case XENVER_get_features:
+ break;
+ default:
+ printk("%s: unknown version cmd %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ return xencomm_arch_hypercall_xen_version
+ (cmd, xencomm_create_inline(arg));
+}
+
+int
+xencomm_hypercall_physdev_op(int cmd, void *op)
+{
+ return xencomm_arch_hypercall_physdev_op
+ (cmd, xencomm_create_inline(op));
+}
+
+static void *
+xencommize_grant_table_op(unsigned int cmd, void *op, unsigned int count)
+{
+ switch (cmd) {
+ case GNTTABOP_map_grant_ref:
+ case GNTTABOP_unmap_grant_ref:
+ break;
+ case GNTTABOP_setup_table:
+ {
+ struct gnttab_setup_table *setup = op;
+ struct xencomm_handle *frame_list;
+
+ frame_list = xencomm_create_inline
+ (xen_guest_handle(setup->frame_list));
+
+ set_xen_guest_handle(setup->frame_list, (void *)frame_list);
+ break;
+ }
+ case GNTTABOP_dump_table:
+ case GNTTABOP_transfer:
+ case GNTTABOP_copy:
+ break;
+ default:
+ printk("%s: unknown grant table op %d\n", __func__, cmd);
+ BUG();
+ }
+
+ return xencomm_create_inline(op);
+}
+
+int
+xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, unsigned int count)
+{
+ void *desc = xencommize_grant_table_op (cmd, op, count);
+
+ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
+}
+
+int
+xencomm_hypercall_sched_op(int cmd, void *arg)
+{
+ switch (cmd) {
+ case SCHEDOP_yield:
+ case SCHEDOP_block:
+ case SCHEDOP_shutdown:
+ case SCHEDOP_remote_shutdown:
+ break;
+ case SCHEDOP_poll:
+ {
+ sched_poll_t *poll = arg;
+ struct xencomm_handle *ports;
+
+ ports = xencomm_create_inline(xen_guest_handle(poll->ports));
+
+ set_xen_guest_handle(poll->ports, (void *)ports);
+ break;
+ }
+ default:
+ printk("%s: unknown sched op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ return xencomm_arch_hypercall_sched_op(cmd, xencomm_create_inline(arg));
+}
+
+int
+xencomm_hypercall_multicall(void *call_list, int nr_calls)
+{
+ int i;
+ multicall_entry_t *mce;
+
+ for (i = 0; i < nr_calls; i++) {
+ mce = (multicall_entry_t *)call_list + i;
+
+ switch (mce->op) {
+ case __HYPERVISOR_update_va_mapping:
+ case __HYPERVISOR_mmu_update:
+ /* No-op on ia64. */
+ break;
+ case __HYPERVISOR_grant_table_op:
+ mce->args[1] = (unsigned long)xencommize_grant_table_op
+ (mce->args[0], (void *)mce->args[1],
+ mce->args[2]);
+ break;
+ case __HYPERVISOR_memory_op:
+ default:
+ printk("%s: unhandled multicall op entry op %lu\n",
+ __func__, mce->op);
+ return -ENOSYS;
+ }
+ }
+
+ return xencomm_arch_hypercall_multicall
+ (xencomm_create_inline(call_list), nr_calls);
+}
+
+int
+xencomm_hypercall_callback_op(int cmd, void *arg)
+{
+ switch (cmd)
+ {
+ case CALLBACKOP_register:
+ case CALLBACKOP_unregister:
+ break;
+ default:
+ printk("%s: unknown callback op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ return xencomm_arch_hypercall_callback_op
+ (cmd, xencomm_create_inline(arg));
+}
+
+static void
+xencommize_memory_reservation (xen_memory_reservation_t *mop)
+{
+ struct xencomm_handle *desc;
+
+ desc = xencomm_create_inline(xen_guest_handle(mop->extent_start));
+ set_xen_guest_handle(mop->extent_start, (void *)desc);
+}
+
+int
+xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
+{
+ XEN_GUEST_HANDLE(xen_pfn_t) extent_start_va[2];
+ xen_memory_reservation_t *xmr = NULL, *xme_in = NULL, *xme_out = NULL;
+ int rc;
+
+ switch (cmd) {
+ case XENMEM_increase_reservation:
+ case XENMEM_decrease_reservation:
+ case XENMEM_populate_physmap:
+ xmr = (xen_memory_reservation_t *)arg;
+ xen_guest_handle(extent_start_va[0]) =
+ xen_guest_handle(xmr->extent_start);
+ xencommize_memory_reservation((xen_memory_reservation_t *)arg);
+ break;
+
+ case XENMEM_maximum_ram_page:
+ break;
+
+ case XENMEM_exchange:
+ xme_in = &((xen_memory_exchange_t *)arg)->in;
+ xme_out = &((xen_memory_exchange_t *)arg)->out;
+ xen_guest_handle(extent_start_va[0]) =
+ xen_guest_handle(xme_in->extent_start);
+ xen_guest_handle(extent_start_va[1]) =
+ xen_guest_handle(xme_out->extent_start);
+ xencommize_memory_reservation
+ (&((xen_memory_exchange_t *)arg)->in);
+ xencommize_memory_reservation
+ (&((xen_memory_exchange_t *)arg)->out);
+ break;
+
+ default:
+ printk("%s: unknown memory op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ rc = xencomm_arch_hypercall_memory_op(cmd, xencomm_create_inline(arg));
+
+ switch (cmd) {
+ case XENMEM_increase_reservation:
+ case XENMEM_decrease_reservation:
+ case XENMEM_populate_physmap:
+ xen_guest_handle(xmr->extent_start) =
+ xen_guest_handle(extent_start_va[0]);
+ break;
+
+ case XENMEM_exchange:
+ xen_guest_handle(xme_in->extent_start) =
+ xen_guest_handle(extent_start_va[0]);
+ xen_guest_handle(xme_out->extent_start) =
+ xen_guest_handle(extent_start_va[1]);
+ break;
+ }
+
+ return rc;
+}
+
+unsigned long
+xencomm_hypercall_hvm_op(int cmd, void *arg)
+{
+ switch (cmd) {
+ case HVMOP_set_param:
+ case HVMOP_get_param:
+ break;
+ default:
+ printk("%s: unknown hvm op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ return xencomm_arch_hypercall_hvm_op(cmd, xencomm_create_inline(arg));
+}
+
+int
+xencomm_hypercall_suspend(unsigned long srec)
+{
+ struct sched_shutdown arg;
+
+ arg.reason = SHUTDOWN_suspend;
+
+ return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg));
+}
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c
new file mode 100644
index 0000000000..5adec0c325
--- /dev/null
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ *
+ * Tristan Gingold <tristan.gingold@bull.net>
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/dom0_ops.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/xencomm.h>
+#include <xen/interface/version.h>
+#include <xen/interface/event_channel.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/hvm/params.h>
+#ifdef CONFIG_VMX_GUEST
+#include <asm/hypervisor.h>
+#else
+#include <asm/hypercall.h>
+#endif
+#include <asm/xen/xencomm.h>
+
+int
+xencomm_mini_hypercall_event_channel_op(int cmd, void *op)
+{
+ struct xencomm_mini xc_area[2];
+ int nbr_area = 2;
+ struct xencomm_handle *desc;
+ int rc;
+
+ rc = xencomm_create_mini(xc_area, &nbr_area,
+ op, sizeof(evtchn_op_t), &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_event_channel_op(cmd, desc);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_event_channel_op);
+
+static int
+xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, int *nbr_area,
+ unsigned int cmd, void *op, unsigned int count,
+ struct xencomm_handle **desc)
+{
+ struct xencomm_handle *desc1;
+ unsigned int argsize;
+ int rc;
+
+ switch (cmd) {
+ case GNTTABOP_map_grant_ref:
+ argsize = sizeof(struct gnttab_map_grant_ref);
+ break;
+ case GNTTABOP_unmap_grant_ref:
+ argsize = sizeof(struct gnttab_unmap_grant_ref);
+ break;
+ case GNTTABOP_setup_table:
+ {
+ struct gnttab_setup_table *setup = op;
+
+ argsize = sizeof(*setup);
+
+ if (count != 1)
+ return -EINVAL;
+ rc = xencomm_create_mini
+ (xc_area, nbr_area,
+ xen_guest_handle(setup->frame_list),
+ setup->nr_frames
+ * sizeof(*xen_guest_handle(setup->frame_list)),
+ &desc1);
+ if (rc)
+ return rc;
+ set_xen_guest_handle(setup->frame_list, (void *)desc1);
+ break;
+ }
+ case GNTTABOP_dump_table:
+ argsize = sizeof(struct gnttab_dump_table);
+ break;
+ case GNTTABOP_transfer:
+ argsize = sizeof(struct gnttab_transfer);
+ break;
+ default:
+ printk("%s: unknown mini grant table op %d\n", __func__, cmd);
+ BUG();
+ }
+
+ rc = xencomm_create_mini(xc_area, nbr_area, op, count * argsize, desc);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+int
+xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op,
+ unsigned int count)
+{
+ int rc;
+ struct xencomm_handle *desc;
+ int nbr_area = 2;
+ struct xencomm_mini xc_area[2];
+
+ rc = xencommize_mini_grant_table_op(xc_area, &nbr_area,
+ cmd, op, count, &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_grant_table_op);
+
+int
+xencomm_mini_hypercall_multicall(void *call_list, int nr_calls)
+{
+ int i;
+ multicall_entry_t *mce;
+ int nbr_area = 2 + nr_calls * 3;
+ struct xencomm_mini xc_area[nbr_area];
+ struct xencomm_handle *desc;
+ int rc;
+
+ for (i = 0; i < nr_calls; i++) {
+ mce = (multicall_entry_t *)call_list + i;
+
+ switch (mce->op) {
+ case __HYPERVISOR_update_va_mapping:
+ case __HYPERVISOR_mmu_update:
+ /* No-op on ia64. */
+ break;
+ case __HYPERVISOR_grant_table_op:
+ rc = xencommize_mini_grant_table_op
+ (xc_area, &nbr_area,
+ mce->args[0], (void *)mce->args[1],
+ mce->args[2], &desc);
+ if (rc)
+ return rc;
+ mce->args[1] = (unsigned long)desc;
+ break;
+ case __HYPERVISOR_memory_op:
+ default:
+ printk("%s: unhandled multicall op entry op %lu\n",
+ __func__, mce->op);
+ return -ENOSYS;
+ }
+ }
+
+ rc = xencomm_create_mini(xc_area, &nbr_area, call_list,
+ nr_calls * sizeof(multicall_entry_t), &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_multicall(desc, nr_calls);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_multicall);
+
+static int
+xencommize_mini_memory_reservation(struct xencomm_mini *area, int *nbr_area,
+ xen_memory_reservation_t *mop)
+{
+ struct xencomm_handle *desc;
+ int rc;
+
+ rc = xencomm_create_mini
+ (area, nbr_area,
+ xen_guest_handle(mop->extent_start),
+ mop->nr_extents
+ * sizeof(*xen_guest_handle(mop->extent_start)),
+ &desc);
+ if (rc)
+ return rc;
+
+ set_xen_guest_handle(mop->extent_start, (void *)desc);
+
+ return 0;
+}
+
+int
+xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg)
+{
+ int nbr_area = 4;
+ struct xencomm_mini xc_area[4];
+ struct xencomm_handle *desc;
+ int rc;
+ unsigned int argsize;
+
+ switch (cmd) {
+ case XENMEM_increase_reservation:
+ case XENMEM_decrease_reservation:
+ case XENMEM_populate_physmap:
+ argsize = sizeof(xen_memory_reservation_t);
+ rc = xencommize_mini_memory_reservation
+ (xc_area, &nbr_area, (xen_memory_reservation_t *)arg);
+ if (rc)
+ return rc;
+ break;
+
+ case XENMEM_maximum_ram_page:
+ argsize = 0;
+ break;
+
+ case XENMEM_exchange:
+ argsize = sizeof(xen_memory_exchange_t);
+ rc = xencommize_mini_memory_reservation
+ (xc_area, &nbr_area,
+ &((xen_memory_exchange_t *)arg)->in);
+ if (rc)
+ return rc;
+ rc = xencommize_mini_memory_reservation
+ (xc_area, &nbr_area,
+ &((xen_memory_exchange_t *)arg)->out);
+ if (rc)
+ return rc;
+ break;
+
+ case XENMEM_add_to_physmap:
+ argsize = sizeof (xen_add_to_physmap_t);
+ break;
+
+ default:
+ printk("%s: unknown mini memory op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_memory_op(cmd, desc);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_memory_op);
+
+unsigned long
+xencomm_mini_hypercall_hvm_op(int cmd, void *arg)
+{
+ struct xencomm_handle *desc;
+ int nbr_area = 2;
+ struct xencomm_mini xc_area[2];
+ unsigned int argsize;
+ int rc;
+
+ switch (cmd) {
+ case HVMOP_get_param:
+ case HVMOP_set_param:
+ argsize = sizeof(xen_hvm_param_t);
+ break;
+ default:
+ printk("%s: unknown HVMOP %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_hvm_op(cmd, desc);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_hvm_op);
+
+int
+xencomm_mini_hypercall_xen_version(int cmd, void *arg)
+{
+ struct xencomm_handle *desc;
+ int nbr_area = 2;
+ struct xencomm_mini xc_area[2];
+ unsigned int argsize;
+ int rc;
+
+ switch (cmd) {
+ case XENVER_version:
+ /* do not actually pass an argument */
+ return xencomm_arch_hypercall_xen_version(cmd, 0);
+ case XENVER_extraversion:
+ argsize = sizeof(xen_extraversion_t);
+ break;
+ case XENVER_compile_info:
+ argsize = sizeof(xen_compile_info_t);
+ break;
+ case XENVER_capabilities:
+ argsize = sizeof(xen_capabilities_info_t);
+ break;
+ case XENVER_changeset:
+ argsize = sizeof(xen_changeset_info_t);
+ break;
+ case XENVER_platform_parameters:
+ argsize = sizeof(xen_platform_parameters_t);
+ break;
+ case XENVER_pagesize:
+ argsize = (arg == NULL) ? 0 : sizeof(void *);
+ break;
+ case XENVER_get_features:
+ argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
+ break;
+
+ default:
+ printk("%s: unknown version op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc);
+ if (rc)
+ return rc;
+
+ return xencomm_arch_hypercall_xen_version(cmd, desc);
+}
+EXPORT_SYMBOL(xencomm_mini_hypercall_xen_version);
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c
new file mode 100644
index 0000000000..51cbb9f4c0
--- /dev/null
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c
@@ -0,0 +1,656 @@
+/*
+ * 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.
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Tristan Gingold <tristan.gingold@bull.net>
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/dom0_ops.h>
+#define __XEN__
+#include <xen/interface/domctl.h>
+#include <xen/interface/sysctl.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/version.h>
+#include <xen/interface/event_channel.h>
+#include <xen/interface/acm_ops.h>
+#include <xen/interface/hvm/params.h>
+#include <xen/public/privcmd.h>
+#include <asm/hypercall.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/xen/xencomm.h>
+
+#define ROUND_DIV(v,s) (((v) + (s) - 1) / (s))
+
+static int
+xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall)
+{
+ dom0_op_t kern_op;
+ dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0];
+ struct xencomm_handle *op_desc;
+ struct xencomm_handle *desc = NULL;
+ int ret = 0;
+
+ if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t)))
+ return -EFAULT;
+
+ if (kern_op.interface_version != DOM0_INTERFACE_VERSION)
+ return -EACCES;
+
+ op_desc = xencomm_create_inline(&kern_op);
+
+ switch (kern_op.cmd) {
+ default:
+ printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd);
+ return -ENOSYS;
+ }
+
+ if (ret) {
+ /* error mapping the nested pointer */
+ return ret;
+ }
+
+ ret = xencomm_arch_hypercall_dom0_op(op_desc);
+
+ /* FIXME: should we restore the handle? */
+ if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t)))
+ ret = -EFAULT;
+
+ if (desc)
+ xencomm_free(desc);
+ return ret;
+}
+
+/*
+ * Temporarily disable the NUMA PHYSINFO code until the rest of the
+ * changes are upstream.
+ */
+#undef IA64_NUMA_PHYSINFO
+
+static int
+xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall)
+{
+ xen_sysctl_t kern_op;
+ xen_sysctl_t __user *user_op;
+ struct xencomm_handle *op_desc;
+ struct xencomm_handle *desc = NULL;
+ struct xencomm_handle *desc1 = NULL;
+ int ret = 0;
+
+ user_op = (xen_sysctl_t __user *)hypercall->arg[0];
+
+ if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t)))
+ return -EFAULT;
+
+ if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION)
+ return -EACCES;
+
+ op_desc = xencomm_create_inline(&kern_op);
+
+ switch (kern_op.cmd) {
+ case XEN_SYSCTL_readconsole:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.readconsole.buffer),
+ kern_op.u.readconsole.count,
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.readconsole.buffer,
+ (void *)desc);
+ break;
+ case XEN_SYSCTL_tbuf_op:
+#ifndef IA64_NUMA_PHYSINFO
+ case XEN_SYSCTL_physinfo:
+#endif
+ case XEN_SYSCTL_sched_id:
+ break;
+ case XEN_SYSCTL_perfc_op:
+ {
+ struct xencomm_handle *tmp_desc;
+ xen_sysctl_t tmp_op = {
+ .cmd = XEN_SYSCTL_perfc_op,
+ .interface_version = XEN_SYSCTL_INTERFACE_VERSION,
+ .u.perfc_op = {
+ .cmd = XEN_SYSCTL_PERFCOP_query,
+ // .desc.p = NULL,
+ // .val.p = NULL,
+ },
+ };
+
+ if (xen_guest_handle(kern_op.u.perfc_op.desc) == NULL) {
+ if (xen_guest_handle(kern_op.u.perfc_op.val) != NULL)
+ return -EINVAL;
+ break;
+ }
+
+ /* query the buffer size for xencomm */
+ tmp_desc = xencomm_create_inline(&tmp_op);
+ ret = xencomm_arch_hypercall_sysctl(tmp_desc);
+ if (ret)
+ return ret;
+
+ ret = xencomm_create(xen_guest_handle(kern_op.u.perfc_op.desc),
+ tmp_op.u.perfc_op.nr_counters *
+ sizeof(xen_sysctl_perfc_desc_t),
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ set_xen_guest_handle(kern_op.u.perfc_op.desc, (void *)desc);
+
+ ret = xencomm_create(xen_guest_handle(kern_op.u.perfc_op.val),
+ tmp_op.u.perfc_op.nr_vals *
+ sizeof(xen_sysctl_perfc_val_t),
+ &desc1, GFP_KERNEL);
+ if (ret)
+ xencomm_free(desc);
+
+ set_xen_guest_handle(kern_op.u.perfc_op.val, (void *)desc1);
+ break;
+ }
+ case XEN_SYSCTL_getdomaininfolist:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.getdomaininfolist.buffer),
+ kern_op.u.getdomaininfolist.max_domains *
+ sizeof(xen_domctl_getdomaininfo_t),
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer,
+ (void *)desc);
+ break;
+#ifdef IA64_NUMA_PHYSINFO
+ case XEN_SYSCTL_physinfo:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.physinfo.memory_chunks),
+ PUBLIC_MAXCHUNKS * sizeof(node_data_t),
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+ set_xen_guest_handle(kern_op.u.physinfo.memory_chunks,
+ (void *)desc);
+
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.physinfo.cpu_to_node),
+ PUBLIC_MAX_NUMNODES * sizeof(u64),
+ &desc1, GFP_KERNEL);
+ if (ret)
+ xencomm_free(desc);
+ set_xen_guest_handle(kern_op.u.physinfo.cpu_to_node,
+ (void *)desc1);
+ break;
+#endif
+ default:
+ printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd);
+ return -ENOSYS;
+ }
+
+ if (ret) {
+ /* error mapping the nested pointer */
+ return ret;
+ }
+
+ ret = xencomm_arch_hypercall_sysctl(op_desc);
+
+ /* FIXME: should we restore the handles? */
+ if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t)))
+ ret = -EFAULT;
+
+ if (desc)
+ xencomm_free(desc);
+ if (desc1)
+ xencomm_free(desc1);
+ return ret;
+}
+
+static int
+xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall)
+{
+ xen_domctl_t kern_op;
+ xen_domctl_t __user *user_op;
+ struct xencomm_handle *op_desc;
+ struct xencomm_handle *desc = NULL;
+ int ret = 0;
+
+ user_op = (xen_domctl_t __user *)hypercall->arg[0];
+
+ if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t)))
+ return -EFAULT;
+
+ if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION)
+ return -EACCES;
+
+ op_desc = xencomm_create_inline(&kern_op);
+
+ switch (kern_op.cmd) {
+ case XEN_DOMCTL_createdomain:
+ case XEN_DOMCTL_destroydomain:
+ case XEN_DOMCTL_pausedomain:
+ case XEN_DOMCTL_unpausedomain:
+ case XEN_DOMCTL_getdomaininfo:
+ break;
+ case XEN_DOMCTL_getmemlist:
+ {
+ unsigned long nr_pages = kern_op.u.getmemlist.max_pfns;
+
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.getmemlist.buffer),
+ nr_pages * sizeof(unsigned long),
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.getmemlist.buffer,
+ (void *)desc);
+ break;
+ }
+ case XEN_DOMCTL_getpageframeinfo:
+ break;
+ case XEN_DOMCTL_getpageframeinfo2:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.getpageframeinfo2.array),
+ kern_op.u.getpageframeinfo2.num,
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.getpageframeinfo2.array,
+ (void *)desc);
+ break;
+ case XEN_DOMCTL_shadow_op:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap),
+ ROUND_DIV(kern_op.u.shadow_op.pages, 8),
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap,
+ (void *)desc);
+ break;
+ case XEN_DOMCTL_max_mem:
+ break;
+ case XEN_DOMCTL_setvcpucontext:
+ case XEN_DOMCTL_getvcpucontext:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.vcpucontext.ctxt),
+ sizeof(vcpu_guest_context_t),
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc);
+ break;
+ case XEN_DOMCTL_getvcpuinfo:
+ break;
+ case XEN_DOMCTL_setvcpuaffinity:
+ case XEN_DOMCTL_getvcpuaffinity:
+ ret = xencomm_create(
+ xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap),
+ ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8),
+ &desc, GFP_KERNEL);
+ set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap,
+ (void *)desc);
+ break;
+ case XEN_DOMCTL_max_vcpus:
+ case XEN_DOMCTL_scheduler_op:
+ case XEN_DOMCTL_setdomainhandle:
+ case XEN_DOMCTL_setdebugging:
+ case XEN_DOMCTL_irq_permission:
+ case XEN_DOMCTL_iomem_permission:
+ case XEN_DOMCTL_ioport_permission:
+ case XEN_DOMCTL_hypercall_init:
+ case XEN_DOMCTL_arch_setup:
+ case XEN_DOMCTL_settimeoffset:
+ break;
+ default:
+ printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd);
+ return -ENOSYS;
+ }
+
+ if (ret) {
+ /* error mapping the nested pointer */
+ return ret;
+ }
+
+ ret = xencomm_arch_hypercall_domctl (op_desc);
+
+ /* FIXME: should we restore the handle? */
+ if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t)))
+ ret = -EFAULT;
+
+ if (desc)
+ xencomm_free(desc);
+ return ret;
+}
+
+static int
+xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall)
+{
+ int cmd = hypercall->arg[0];
+ void __user *arg = (void __user *)hypercall->arg[1];
+ struct xencomm_handle *op_desc;
+ struct xencomm_handle *desc = NULL;
+ int ret;
+
+ switch (cmd) {
+ case ACMOP_getssid:
+ {
+ struct acm_getssid kern_arg;
+
+ if (copy_from_user(&kern_arg, arg, sizeof (kern_arg)))
+ return -EFAULT;
+
+ op_desc = xencomm_create_inline(&kern_arg);
+
+ ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf),
+ kern_arg.ssidbuf_size, &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc);
+
+ ret = xencomm_arch_hypercall_acm_op(cmd, op_desc);
+
+ xencomm_free(desc);
+
+ if (copy_to_user(arg, &kern_arg, sizeof (kern_arg)))
+ return -EFAULT;
+
+ return ret;
+ }
+ default:
+ printk("%s: unknown acm_op cmd %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int
+xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall)
+{
+ const unsigned long cmd = hypercall->arg[0];
+ int ret = 0;
+
+ switch (cmd) {
+ case XENMEM_increase_reservation:
+ case XENMEM_decrease_reservation:
+ case XENMEM_populate_physmap:
+ {
+ xen_memory_reservation_t kern_op;
+ xen_memory_reservation_t __user *user_op;
+ struct xencomm_handle *desc = NULL;
+ struct xencomm_handle *desc_op;
+
+ user_op = (xen_memory_reservation_t __user *)hypercall->arg[1];
+ if (copy_from_user(&kern_op, user_op,
+ sizeof(xen_memory_reservation_t)))
+ return -EFAULT;
+ desc_op = xencomm_create_inline(&kern_op);
+
+ if (xen_guest_handle(kern_op.extent_start)) {
+ void * addr;
+
+ addr = xen_guest_handle(kern_op.extent_start);
+ ret = xencomm_create
+ (addr,
+ kern_op.nr_extents *
+ sizeof(*xen_guest_handle
+ (kern_op.extent_start)),
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+ set_xen_guest_handle(kern_op.extent_start,
+ (void *)desc);
+ }
+
+ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
+
+ if (desc)
+ xencomm_free(desc);
+
+ if (ret != 0)
+ return ret;
+
+ if (copy_to_user(user_op, &kern_op,
+ sizeof(xen_memory_reservation_t)))
+ return -EFAULT;
+
+ return ret;
+ }
+ case XENMEM_translate_gpfn_list:
+ {
+ xen_translate_gpfn_list_t kern_op;
+ xen_translate_gpfn_list_t __user *user_op;
+ struct xencomm_handle *desc_gpfn = NULL;
+ struct xencomm_handle *desc_mfn = NULL;
+ struct xencomm_handle *desc_op;
+ void *addr;
+
+ user_op = (xen_translate_gpfn_list_t __user *)
+ hypercall->arg[1];
+ if (copy_from_user(&kern_op, user_op,
+ sizeof(xen_translate_gpfn_list_t)))
+ return -EFAULT;
+ desc_op = xencomm_create_inline(&kern_op);
+
+ if (kern_op.nr_gpfns) {
+ /* gpfn_list. */
+ addr = xen_guest_handle(kern_op.gpfn_list);
+
+ ret = xencomm_create(addr, kern_op.nr_gpfns *
+ sizeof(*xen_guest_handle
+ (kern_op.gpfn_list)),
+ &desc_gpfn, GFP_KERNEL);
+ if (ret)
+ return ret;
+ set_xen_guest_handle(kern_op.gpfn_list,
+ (void *)desc_gpfn);
+
+ /* mfn_list. */
+ addr = xen_guest_handle(kern_op.mfn_list);
+
+ ret = xencomm_create(addr, kern_op.nr_gpfns *
+ sizeof(*xen_guest_handle
+ (kern_op.mfn_list)),
+ &desc_mfn, GFP_KERNEL);
+ if (ret)
+ return ret;
+ set_xen_guest_handle(kern_op.mfn_list,
+ (void *)desc_mfn);
+ }
+
+ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op);
+
+ if (desc_gpfn)
+ xencomm_free(desc_gpfn);
+
+ if (desc_mfn)
+ xencomm_free(desc_mfn);
+
+ if (ret != 0)
+ return ret;
+
+ return ret;
+ }
+ default:
+ printk("%s: unknown memory op %lu\n", __func__, cmd);
+ ret = -ENOSYS;
+ }
+ return ret;
+}
+
+static int
+xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall)
+{
+ int cmd = hypercall->arg[0];
+ void __user *arg = (void __user *)hypercall->arg[1];
+ struct xencomm_handle *desc;
+ size_t argsize;
+ int rc;
+
+ switch (cmd) {
+ case XENVER_version:
+ /* do not actually pass an argument */
+ return xencomm_arch_hypercall_xen_version(cmd, 0);
+ case XENVER_extraversion:
+ argsize = sizeof(xen_extraversion_t);
+ break;
+ case XENVER_compile_info:
+ argsize = sizeof(xen_compile_info_t);
+ break;
+ case XENVER_capabilities:
+ argsize = sizeof(xen_capabilities_info_t);
+ break;
+ case XENVER_changeset:
+ argsize = sizeof(xen_changeset_info_t);
+ break;
+ case XENVER_platform_parameters:
+ argsize = sizeof(xen_platform_parameters_t);
+ break;
+ case XENVER_pagesize:
+ argsize = (arg == NULL) ? 0 : sizeof(void *);
+ break;
+ case XENVER_get_features:
+ argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t);
+ break;
+
+ default:
+ printk("%s: unknown version op %d\n", __func__, cmd);
+ return -ENOSYS;
+ }
+
+ rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL);
+ if (rc)
+ return rc;
+
+ rc = xencomm_arch_hypercall_xen_version(cmd, desc);
+
+ xencomm_free(desc);
+
+ return rc;
+}
+
+static int
+xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall)
+{
+ int cmd = hypercall->arg[0];
+ struct xencomm_handle *desc;
+ unsigned int argsize;
+ int ret;
+
+ switch (cmd) {
+ case EVTCHNOP_alloc_unbound:
+ argsize = sizeof(evtchn_alloc_unbound_t);
+ break;
+
+ case EVTCHNOP_status:
+ argsize = sizeof(evtchn_status_t);
+ break;
+
+ default:
+ printk("%s: unknown EVTCHNOP %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ ret = xencomm_create((void *)hypercall->arg[1], argsize,
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ ret = xencomm_arch_hypercall_event_channel_op(cmd, desc);
+
+ xencomm_free(desc);
+ return ret;
+}
+
+static int
+xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall)
+{
+ int cmd = hypercall->arg[0];
+ struct xencomm_handle *desc;
+ unsigned int argsize;
+ int ret;
+
+ switch (cmd) {
+ case HVMOP_get_param:
+ case HVMOP_set_param:
+ argsize = sizeof(xen_hvm_param_t);
+ break;
+ case HVMOP_set_irq_level:
+ argsize = sizeof(xen_hvm_set_irq_level_t);
+ break;
+ default:
+ printk("%s: unknown HVMOP %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ ret = xencomm_create((void *)hypercall->arg[1], argsize,
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ ret = xencomm_arch_hypercall_hvm_op(cmd, desc);
+
+ xencomm_free(desc);
+ return ret;
+}
+
+static int
+xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall)
+{
+ int cmd = hypercall->arg[0];
+ struct xencomm_handle *desc;
+ unsigned int argsize;
+ int ret;
+
+ switch (cmd) {
+ case SCHEDOP_remote_shutdown:
+ argsize = sizeof(sched_remote_shutdown_t);
+ break;
+ default:
+ printk("%s: unknown SCHEDOP %d\n", __func__, cmd);
+ return -EINVAL;
+ }
+
+ ret = xencomm_create((void *)hypercall->arg[1], argsize,
+ &desc, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ ret = xencomm_arch_hypercall_sched_op(cmd, desc);
+
+ xencomm_free(desc);
+ return ret;
+}
+
+int
+privcmd_hypercall(privcmd_hypercall_t *hypercall)
+{
+ switch (hypercall->op) {
+ case __HYPERVISOR_dom0_op:
+ return xencomm_privcmd_dom0_op(hypercall);
+ case __HYPERVISOR_domctl:
+ return xencomm_privcmd_domctl(hypercall);
+ case __HYPERVISOR_sysctl:
+ return xencomm_privcmd_sysctl(hypercall);
+ case __HYPERVISOR_acm_op:
+ return xencomm_privcmd_acm_op(hypercall);
+ case __HYPERVISOR_xen_version:
+ return xencomm_privcmd_xen_version(hypercall);
+ case __HYPERVISOR_memory_op:
+ return xencomm_privcmd_memory_op(hypercall);
+ case __HYPERVISOR_event_channel_op:
+ return xencomm_privcmd_event_channel_op(hypercall);
+ case __HYPERVISOR_hvm_op:
+ return xencomm_privcmd_hvm_op(hypercall);
+ case __HYPERVISOR_sched_op:
+ return xencomm_privcmd_sched_op(hypercall);
+ default:
+ printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op);
+ return -ENOSYS;
+ }
+}
+
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c b/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c
new file mode 100644
index 0000000000..367b6b32de
--- /dev/null
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <xen/interface/xen.h>
+#include <asm/page.h>
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+#include <asm/xen/xencomm.h>
+
+static int xencomm_debug = 0;
+
+static unsigned long kernel_start_pa;
+
+void
+xencomm_init (void)
+{
+ kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START);
+}
+
+/* Translate virtual address to physical address. */
+unsigned long
+xencomm_vaddr_to_paddr(unsigned long vaddr)
+{
+#ifndef CONFIG_VMX_GUEST
+ struct page *page;
+ struct vm_area_struct *vma;
+#endif
+
+ if (vaddr == 0)
+ return 0;
+
+#ifdef __ia64__
+ if (REGION_NUMBER(vaddr) == 5) {
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep;
+
+ /* On ia64, TASK_SIZE refers to current. It is not initialized
+ during boot.
+ Furthermore the kernel is relocatable and __pa() doesn't
+ work on addresses. */
+ if (vaddr >= KERNEL_START
+ && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) {
+ return vaddr - kernel_start_pa;
+ }
+
+ /* In kernel area -- virtually mapped. */
+ pgd = pgd_offset_k(vaddr);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ return ~0UL;
+
+ pud = pud_offset(pgd, vaddr);
+ if (pud_none(*pud) || pud_bad(*pud))
+ return ~0UL;
+
+ pmd = pmd_offset(pud, vaddr);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ return ~0UL;
+
+ ptep = pte_offset_kernel(pmd, vaddr);
+ if (!ptep)
+ return ~0UL;
+
+ return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK);
+ }
+#endif
+
+ if (vaddr > TASK_SIZE) {
+ /* kernel address */
+ return __pa(vaddr);
+ }
+
+
+#ifdef CONFIG_VMX_GUEST
+ /* No privcmd within vmx guest. */
+ return ~0UL;
+#else
+ /* XXX double-check (lack of) locking */
+ vma = find_extend_vma(current->mm, vaddr);
+ if (!vma)
+ return ~0UL;
+
+ /* We assume the page is modified. */
+ page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
+ if (!page)
+ return ~0UL;
+
+ return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
+#endif
+}
+
+static int
+xencomm_init_desc(struct xencomm_desc *desc, void *buffer, unsigned long bytes)
+{
+ unsigned long recorded = 0;
+ int i = 0;
+
+ BUG_ON((buffer == NULL) && (bytes > 0));
+
+ /* record the physical pages used */
+ if (buffer == NULL)
+ desc->nr_addrs = 0;
+
+ while ((recorded < bytes) && (i < desc->nr_addrs)) {
+ unsigned long vaddr = (unsigned long)buffer + recorded;
+ unsigned long paddr;
+ int offset;
+ int chunksz;
+
+ offset = vaddr % PAGE_SIZE; /* handle partial pages */
+ chunksz = min(PAGE_SIZE - offset, bytes - recorded);
+
+ paddr = xencomm_vaddr_to_paddr(vaddr);
+ if (paddr == ~0UL) {
+ printk("%s: couldn't translate vaddr %lx\n",
+ __func__, vaddr);
+ return -EINVAL;
+ }
+
+ desc->address[i++] = paddr;
+ recorded += chunksz;
+ }
+
+ if (recorded < bytes) {
+ printk("%s: could only translate %ld of %ld bytes\n",
+ __func__, recorded, bytes);
+ return -ENOSPC;
+ }
+
+ /* mark remaining addresses invalid (just for safety) */
+ while (i < desc->nr_addrs)
+ desc->address[i++] = XENCOMM_INVALID;
+
+ desc->magic = XENCOMM_MAGIC;
+
+ return 0;
+}
+
+static struct xencomm_desc *
+xencomm_alloc(gfp_t gfp_mask)
+{
+ struct xencomm_desc *desc;
+
+ desc = (struct xencomm_desc *)__get_free_page(gfp_mask);
+ if (desc == NULL)
+ panic("%s: page allocation failed\n", __func__);
+
+ desc->nr_addrs = (PAGE_SIZE - sizeof(struct xencomm_desc)) /
+ sizeof(*desc->address);
+
+ return desc;
+}
+
+void
+xencomm_free(struct xencomm_handle *desc)
+{
+ if (desc)
+ free_page((unsigned long)__va(desc));
+}
+
+int
+xencomm_create(void *buffer, unsigned long bytes,
+ struct xencomm_handle **ret, gfp_t gfp_mask)
+{
+ struct xencomm_desc *desc;
+ struct xencomm_handle *handle;
+ int rc;
+
+ if (xencomm_debug)
+ printk("%s: %p[%ld]\n", __func__, buffer, bytes);
+
+ if (buffer == NULL || bytes == 0) {
+ *ret = (struct xencomm_handle *)NULL;
+ return 0;
+ }
+
+ desc = xencomm_alloc(gfp_mask);
+ if (!desc) {
+ printk("%s failure\n", "xencomm_alloc");
+ return -ENOMEM;
+ }
+ handle = (struct xencomm_handle *)__pa(desc);
+
+ rc = xencomm_init_desc(desc, buffer, bytes);
+ if (rc) {
+ printk("%s failure: %d\n", "xencomm_init_desc", rc);
+ xencomm_free(handle);
+ return rc;
+ }
+
+ *ret = handle;
+ return 0;
+}
+
+/* "mini" routines, for stack-based communications: */
+
+static void *
+xencomm_alloc_mini(struct xencomm_mini *area, int *nbr_area)
+{
+ unsigned long base;
+ unsigned int pageoffset;
+
+ while (*nbr_area >= 0) {
+ /* Allocate an area. */
+ (*nbr_area)--;
+
+ base = (unsigned long)(area + *nbr_area);
+ pageoffset = base % PAGE_SIZE;
+
+ /* If the area does not cross a page, use it. */
+ if ((PAGE_SIZE - pageoffset) >= sizeof(struct xencomm_mini))
+ return &area[*nbr_area];
+ }
+ /* No more area. */
+ return NULL;
+}
+
+int
+xencomm_create_mini(struct xencomm_mini *area, int *nbr_area,
+ void *buffer, unsigned long bytes,
+ struct xencomm_handle **ret)
+{
+ struct xencomm_desc *desc;
+ int rc;
+ unsigned long res;
+
+ desc = xencomm_alloc_mini(area, nbr_area);
+ if (!desc)
+ return -ENOMEM;
+ desc->nr_addrs = XENCOMM_MINI_ADDRS;
+
+ rc = xencomm_init_desc(desc, buffer, bytes);
+ if (rc)
+ return rc;
+
+ res = xencomm_vaddr_to_paddr((unsigned long)desc);
+ if (res == ~0UL)
+ return -EINVAL;
+
+ *ret = (struct xencomm_handle*)res;
+ return 0;
+}
diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S b/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S
index 918622918e..e761278670 100644
--- a/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S
+++ b/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S
@@ -23,12 +23,11 @@ GLOBAL_ENTRY(early_xen_setup)
mov cr.iva=r10
-#if XSI_BASE != 0xf100000000000000UL
- /* Backward compatibility. */
-(isBP) mov r2=0x600
+ /* Set xsi base. */
+#define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600
+(isBP) mov r2=FW_HYPERCALL_SET_SHARED_INFO_VA
(isBP) movl r28=XSI_BASE;;
(isBP) break 0x1000;;
-#endif
br.ret.sptk.many rp
;;
@@ -38,18 +37,18 @@ END(early_xen_setup)
/* Stub for suspend.
Just force the stacked registers to be written in memory. */
-GLOBAL_ENTRY(HYPERVISOR_suspend)
+GLOBAL_ENTRY(xencomm_arch_hypercall_suspend)
+ mov r15=r32
+ ;;
alloc r20=ar.pfs,0,0,0,0
- mov r14=2
- mov r15=r12
- ;;
+ mov r2=__HYPERVISOR_sched_op
+ ;;
/* We don't want to deal with RSE. */
flushrs
- mov r2=__HYPERVISOR_sched_op
- st4 [r12]=r14
+ mov r14=2 // SCHEDOP_shutdown
;;
break 0x1000
;;
mov ar.pfs=r20
br.ret.sptk.many b0
-END(HYPERVISOR_suspend)
+END(xencomm_arch_hypercall_suspend)
diff --git a/linux-2.6-xen-sparse/arch/x86_64/Kconfig b/linux-2.6-xen-sparse/arch/x86_64/Kconfig
index 45d8302cb4..79bd0044fa 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig
+++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig
@@ -368,6 +368,8 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
+config ARCH_ENABLE_MEMORY_HOTPLUG
+ def_bool y
config HPET_TIMER
bool
diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile b/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile
index aa84f6eb98..57b7fe1c11 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += processor.o
+processor-y := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o
endif
boot-$(CONFIG_XEN) := ../../../i386/kernel/acpi/boot-xen.o
diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/entry-xen.S b/linux-2.6-xen-sparse/arch/x86_64/kernel/entry-xen.S
index 7edd8d5cb6..687c486878 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/entry-xen.S
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/entry-xen.S
@@ -316,12 +316,7 @@ tracesys:
ja 1f
movq %r10,%rcx /* fixup for C */
call *sys_call_table(,%rax,8)
- movq %rax,RAX-ARGOFFSET(%rsp)
-1: SAVE_REST
- movq %rsp,%rdi
- call syscall_trace_leave
- RESTORE_TOP_OF_STACK %rbx
- RESTORE_REST
+1: movq %rax,RAX-ARGOFFSET(%rsp)
/* Use IRET because user could have changed frame */
jmp int_ret_from_sys_call
CFI_ENDPROC
diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c
index ca96708d1c..65ba83c625 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/process-xen.c
@@ -350,7 +350,6 @@ static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr)
struct user_desc ud = {
.base_addr = addr,
.limit = 0xfffff,
- .contents = (3 << 3), /* user */
.seg_32bit = 1,
.limit_in_pages = 1,
.useable = 1,
diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c
index 8fe13ee2b0..711ce5d198 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c
@@ -74,6 +74,7 @@
#include <asm/hypervisor.h>
#include <xen/interface/nmi.h>
#include <xen/features.h>
+#include <xen/xencons.h>
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
#include <asm/mach-xen/setup_arch_post.h>
@@ -143,6 +144,9 @@ struct sys_desc_table_struct {
struct edid_info edid_info;
struct e820map e820;
+#ifdef CONFIG_XEN
+struct e820map machine_e820;
+#endif
extern int root_mountflags;
@@ -625,7 +629,6 @@ static void __init reserve_ebda_region(void)
void __init setup_arch(char **cmdline_p)
{
unsigned long kernel_end;
- struct e820entry *machine_e820;
struct xen_memory_map memmap;
#ifdef CONFIG_XEN
@@ -645,33 +648,15 @@ void __init setup_arch(char **cmdline_p)
screen_info.orig_video_cols = 80;
screen_info.orig_video_ega_bx = 3;
screen_info.orig_video_points = 16;
+ screen_info.orig_y = screen_info.orig_video_lines - 1;
if (xen_start_info->console.dom0.info_size >=
sizeof(struct dom0_vga_console_info)) {
const struct dom0_vga_console_info *info =
(struct dom0_vga_console_info *)(
(char *)xen_start_info +
xen_start_info->console.dom0.info_off);
- screen_info.orig_video_mode = info->txt_mode;
- screen_info.orig_video_isVGA = info->video_type;
- screen_info.orig_video_lines = info->video_height;
- screen_info.orig_video_cols = info->video_width;
- screen_info.orig_video_points = info->txt_points;
- screen_info.lfb_width = info->video_width;
- screen_info.lfb_height = info->video_height;
- screen_info.lfb_depth = info->lfb_depth;
- screen_info.lfb_base = info->lfb_base;
- screen_info.lfb_size = info->lfb_size;
- screen_info.lfb_linelength = info->lfb_linelen;
- screen_info.red_size = info->red_size;
- screen_info.red_pos = info->red_pos;
- screen_info.green_size = info->green_size;
- screen_info.green_pos = info->green_pos;
- screen_info.blue_size = info->blue_size;
- screen_info.blue_pos = info->blue_pos;
- screen_info.rsvd_size = info->rsvd_size;
- screen_info.rsvd_pos = info->rsvd_pos;
+ dom0_init_screen_info(info);
}
- screen_info.orig_y = screen_info.orig_video_lines - 1;
xen_start_info->console.domU.mfn = 0;
xen_start_info->console.domU.evtchn = 0;
} else
@@ -936,14 +921,14 @@ void __init setup_arch(char **cmdline_p)
probe_roms();
#ifdef CONFIG_XEN
if (is_initial_xendomain()) {
- machine_e820 = alloc_bootmem_low_pages(PAGE_SIZE);
-
memmap.nr_entries = E820MAX;
- set_xen_guest_handle(memmap.buffer, machine_e820);
+ set_xen_guest_handle(memmap.buffer, machine_e820.map);
- BUG_ON(HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap));
+ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
+ BUG();
+ machine_e820.nr_map = memmap.nr_entries;
- e820_reserve_resources(machine_e820, memmap.nr_entries);
+ e820_reserve_resources(machine_e820.map, machine_e820.nr_map);
}
#else
e820_reserve_resources(e820.map, e820.nr_map);
@@ -959,10 +944,8 @@ void __init setup_arch(char **cmdline_p)
}
#ifdef CONFIG_XEN
- if (is_initial_xendomain()) {
- e820_setup_gap(machine_e820, memmap.nr_entries);
- free_bootmem(__pa(machine_e820), PAGE_SIZE);
- }
+ if (is_initial_xendomain())
+ e820_setup_gap(machine_e820.map, machine_e820.nr_map);
#else
e820_setup_gap(e820.map, e820.nr_map);
#endif
diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/traps-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/traps-xen.c
index 9fd0b94cb5..653af67c08 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/kernel/traps-xen.c
+++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/traps-xen.c
@@ -30,6 +30,7 @@
#include <linux/moduleparam.h>
#include <linux/nmi.h>
#include <linux/kprobes.h>
+#include <linux/kexec.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -438,6 +439,8 @@ void __kprobes __die(const char * str, struct pt_regs * regs, long err)
printk(KERN_ALERT "RIP ");
printk_address(regs->rip);
printk(" RSP <%016lx>\n", regs->rsp);
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
}
void die(const char * str, struct pt_regs * regs, long err)
@@ -461,6 +464,8 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs)
*/
printk(str, safe_smp_processor_id());
show_registers(regs);
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
if (panic_on_timeout || panic_on_oops)
panic("nmi watchdog");
printk("console shuts up ...\n");
diff --git a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
index d3ce58355f..032c31e532 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
+++ b/linux-2.6-xen-sparse/arch/x86_64/mm/init-xen.c
@@ -56,6 +56,11 @@
struct dma_mapping_ops* dma_ops;
EXPORT_SYMBOL(dma_ops);
+#ifdef CONFIG_XEN_COMPAT_030002
+unsigned int __kernel_page_user;
+EXPORT_SYMBOL(__kernel_page_user);
+#endif
+
extern unsigned long *contiguous_bitmap;
static unsigned long dma_reserve __initdata;
@@ -260,7 +265,10 @@ static void set_pte_phys(unsigned long vaddr,
return;
}
}
- new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
+ if (pgprot_val(prot))
+ new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
+ else
+ new_pte = __pte(0);
pte = pte_offset_kernel(pmd, vaddr);
if (!pte_none(*pte) &&
@@ -524,6 +532,33 @@ void __init xen_init_pt(void)
addr = page[pud_index(__START_KERNEL_map)];
addr_to_page(addr, page);
+#ifdef CONFIG_XEN_COMPAT_030002
+ /* On Xen 3.0.2 and older we may need to explicitly specify _PAGE_USER
+ in kernel PTEs. We check that here. */
+ if (HYPERVISOR_xen_version(XENVER_version, NULL) <= 0x30000) {
+ unsigned long *pg;
+ pte_t pte;
+
+ /* Mess with the initial mapping of page 0. It's not needed. */
+ BUILD_BUG_ON(__START_KERNEL <= __START_KERNEL_map);
+ addr = page[pmd_index(__START_KERNEL_map)];
+ addr_to_page(addr, pg);
+ pte.pte = pg[pte_index(__START_KERNEL_map)];
+ BUG_ON(!(pte.pte & _PAGE_PRESENT));
+
+ /* If _PAGE_USER isn't set, we obviously do not need it. */
+ if (pte.pte & _PAGE_USER) {
+ /* _PAGE_USER is needed, but is it set implicitly? */
+ pte.pte &= ~_PAGE_USER;
+ if ((HYPERVISOR_update_va_mapping(__START_KERNEL_map,
+ pte, 0) != 0) ||
+ !(pg[pte_index(__START_KERNEL_map)] & _PAGE_USER))
+ /* We need to explicitly specify _PAGE_USER. */
+ __kernel_page_user = _PAGE_USER;
+ }
+ }
+#endif
+
/* Construct mapping of initial pte page in our own directories. */
init_level4_pgt[pgd_index(__START_KERNEL_map)] =
mk_kernel_pgd(__pa_symbol(level3_kernel_pgt));
@@ -913,8 +948,8 @@ void __init mem_init(void)
#endif
/* XEN: init and count pages outside initial allocation. */
for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
- ClearPageReserved(&mem_map[pfn]);
- set_page_count(&mem_map[pfn], 1);
+ ClearPageReserved(pfn_to_page(pfn));
+ set_page_count(pfn_to_page(pfn), 1);
totalram_pages++;
}
reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
diff --git a/linux-2.6-xen-sparse/arch/x86_64/oprofile/Makefile b/linux-2.6-xen-sparse/arch/x86_64/oprofile/Makefile
index 589a7966e8..cc3b9939b0 100644
--- a/linux-2.6-xen-sparse/arch/x86_64/oprofile/Makefile
+++ b/linux-2.6-xen-sparse/arch/x86_64/oprofile/Makefile
@@ -12,6 +12,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
ifdef CONFIG_XEN
+XENOPROF_COMMON_OBJS = $(addprefix ../../../drivers/xen/xenoprof/, \
+ xenoprofile.o)
OPROFILE-y := xenoprof.o
else
OPROFILE-y := init.o backtrace.o
@@ -19,4 +21,5 @@ OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \
op_model_ppro.o
OPROFILE-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
endif
-oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y))
+oprofile-y = $(DRIVER_OBJS) $(XENOPROF_COMMON_OBJS) \
+ $(addprefix ../../i386/oprofile/, $(OPROFILE-y))
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
index 71c7dd3a00..adf016ba90 100644
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
@@ -41,6 +41,7 @@
#include <xen/evtchn.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/io/tpmif.h>
+#include <xen/gnttab.h>
#include <xen/xenbus.h>
#include "tpm.h"
#include "tpm_vtpm.h"
@@ -343,6 +344,7 @@ static void backend_changed(struct xenbus_device *dev,
case XenbusStateInitialising:
case XenbusStateInitWait:
case XenbusStateInitialised:
+ case XenbusStateUnknown:
break;
case XenbusStateConnected:
@@ -351,13 +353,14 @@ static void backend_changed(struct xenbus_device *dev,
case XenbusStateClosing:
tpmif_set_connected_state(tp, 0);
+ xenbus_frontend_closed(dev);
break;
- case XenbusStateUnknown:
case XenbusStateClosed:
+ tpmif_set_connected_state(tp, 0);
if (tp->is_suspended == 0)
device_unregister(&dev->dev);
- xenbus_switch_state(dev, XenbusStateClosed);
+ xenbus_frontend_closed(dev);
break;
}
}
@@ -419,9 +422,10 @@ static int tpmfront_suspend(struct xenbus_device *dev)
mutex_lock(&suspend_lock);
tp->is_suspended = 1;
- for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 25; ctr++) {
+ for (ctr = 0; atomic_read(&tp->tx_busy) && ctr <= 300; ctr++) {
if ((ctr % 10) == 0)
- printk("TPM-FE [INFO]: Waiting for outstanding request.\n");
+ printk("TPM-FE [INFO]: Waiting for outstanding "
+ "request.\n");
/*
* Wait for a request to be responded to.
*/
diff --git a/linux-2.6-xen-sparse/drivers/char/tty_io.c b/linux-2.6-xen-sparse/drivers/char/tty_io.c
index f6f0689771..0372d93bca 100644
--- a/linux-2.6-xen-sparse/drivers/char/tty_io.c
+++ b/linux-2.6-xen-sparse/drivers/char/tty_io.c
@@ -2761,7 +2761,7 @@ static void flush_to_ldisc(void *private_)
struct tty_struct *tty = (struct tty_struct *) private_;
unsigned long flags;
struct tty_ldisc *disc;
- struct tty_buffer *tbuf;
+ struct tty_buffer *tbuf, *head;
int count;
char *char_buf;
unsigned char *flag_buf;
@@ -2778,7 +2778,9 @@ static void flush_to_ldisc(void *private_)
goto out;
}
spin_lock_irqsave(&tty->buf.lock, flags);
- while((tbuf = tty->buf.head) != NULL) {
+ head = tty->buf.head;
+ tty->buf.head = NULL;
+ while((tbuf = head) != NULL) {
while ((count = tbuf->commit - tbuf->read) != 0) {
char_buf = tbuf->char_buf_ptr + tbuf->read;
flag_buf = tbuf->flag_buf_ptr + tbuf->read;
@@ -2787,10 +2789,12 @@ static void flush_to_ldisc(void *private_)
disc->receive_buf(tty, char_buf, flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
}
- if (tbuf->active)
+ if (tbuf->active) {
+ tty->buf.head = head;
break;
- tty->buf.head = tbuf->next;
- if (tty->buf.head == NULL)
+ }
+ head = tbuf->next;
+ if (head == NULL)
tty->buf.tail = NULL;
tty_buffer_free(tty, tbuf);
}
diff --git a/linux-2.6-xen-sparse/drivers/serial/Kconfig b/linux-2.6-xen-sparse/drivers/serial/Kconfig
index fa1fdb0b37..c6be86d83e 100644
--- a/linux-2.6-xen-sparse/drivers/serial/Kconfig
+++ b/linux-2.6-xen-sparse/drivers/serial/Kconfig
@@ -821,6 +821,7 @@ config SERIAL_ICOM
tristate "IBM Multiport Serial Adapter"
depends on PCI && (PPC_ISERIES || PPC_PSERIES)
select SERIAL_CORE
+ select FW_LOADER
help
This driver is for a family of multiport serial adapters
including 2 port RVX, 2 port internal modem, 4 port internal
diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile b/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile
index 0e3a3485c4..3fc3d0bae5 100644
--- a/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/Makefile
@@ -1,2 +1,2 @@
-obj-y += balloon.o
+obj-y := balloon.o sysfs.o
diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
index a6a8396c05..b621d76383 100644
--- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
@@ -53,10 +53,8 @@
#include <asm/uaccess.h>
#include <asm/tlb.h>
#include <linux/list.h>
-
#include <xen/xenbus.h>
-
-#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+#include "common.h"
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *balloon_pde;
@@ -71,9 +69,7 @@ static DECLARE_MUTEX(balloon_mutex);
*/
DEFINE_SPINLOCK(balloon_lock);
-/* We aim for 'current allocation' == 'target allocation'. */
-static unsigned long current_pages;
-static unsigned long target_pages;
+struct balloon_stats balloon_stats;
/* We increase/decrease in batches which fit in a page */
static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
@@ -81,18 +77,8 @@ static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
/* VM /proc information for memory */
extern unsigned long totalram_pages;
-/* We may hit the hard limit in Xen. If we do then we remember it. */
-static unsigned long hard_limit;
-
-/*
- * Drivers may alter the memory reservation independently, but they must
- * inform the balloon driver so that we can avoid hitting the hard limit.
- */
-static unsigned long driver_pages;
-
/* List of ballooned pages, threaded through the mem_map array. */
static LIST_HEAD(ballooned_pages);
-static unsigned long balloon_low, balloon_high;
/* Main work function, always executed in process context. */
static void balloon_process(void *unused);
@@ -124,10 +110,10 @@ static void balloon_append(struct page *page)
/* Lowmem is re-populated first, so highmem pages go at list tail. */
if (PageHighMem(page)) {
list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
- balloon_high++;
+ bs.balloon_high++;
} else {
list_add(PAGE_TO_LIST(page), &ballooned_pages);
- balloon_low++;
+ bs.balloon_low++;
}
}
@@ -143,9 +129,9 @@ static struct page *balloon_retrieve(void)
UNLIST_PAGE(page);
if (PageHighMem(page))
- balloon_high--;
+ bs.balloon_high--;
else
- balloon_low--;
+ bs.balloon_low--;
return page;
}
@@ -172,9 +158,9 @@ static void balloon_alarm(unsigned long unused)
static unsigned long current_target(void)
{
- unsigned long target = min(target_pages, hard_limit);
- if (target > (current_pages + balloon_low + balloon_high))
- target = current_pages + balloon_low + balloon_high;
+ unsigned long target = min(bs.target_pages, bs.hard_limit);
+ if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high))
+ target = bs.current_pages + bs.balloon_low + bs.balloon_high;
return target;
}
@@ -216,7 +202,8 @@ static int increase_reservation(unsigned long nr_pages)
BUG_ON(ret != rc);
}
if (rc >= 0)
- hard_limit = current_pages + rc - driver_pages;
+ bs.hard_limit = (bs.current_pages + rc -
+ bs.driver_pages);
goto out;
}
@@ -228,9 +215,7 @@ static int increase_reservation(unsigned long nr_pages)
BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
phys_to_machine_mapping_valid(pfn));
- /* Update P->M and M->P tables. */
set_phys_to_machine(pfn, frame_list[i]);
- xen_machphys_update(frame_list[i], pfn);
/* Link back into the page tables if not highmem. */
if (pfn < max_low_pfn) {
@@ -248,8 +233,8 @@ static int increase_reservation(unsigned long nr_pages)
__free_page(page);
}
- current_pages += nr_pages;
- totalram_pages = current_pages;
+ bs.current_pages += nr_pages;
+ totalram_pages = bs.current_pages;
out:
balloon_unlock(flags);
@@ -317,8 +302,8 @@ static int decrease_reservation(unsigned long nr_pages)
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
BUG_ON(ret != nr_pages);
- current_pages -= nr_pages;
- totalram_pages = current_pages;
+ bs.current_pages -= nr_pages;
+ totalram_pages = bs.current_pages;
balloon_unlock(flags);
@@ -339,7 +324,7 @@ static void balloon_process(void *unused)
down(&balloon_mutex);
do {
- credit = current_target() - current_pages;
+ credit = current_target() - bs.current_pages;
if (credit > 0)
need_sleep = (increase_reservation(credit) != 0);
if (credit < 0)
@@ -352,18 +337,18 @@ static void balloon_process(void *unused)
} while ((credit != 0) && !need_sleep);
/* Schedule more work if there is some still to be done. */
- if (current_target() != current_pages)
+ if (current_target() != bs.current_pages)
mod_timer(&balloon_timer, jiffies + HZ);
up(&balloon_mutex);
}
/* Resets the Xen limit, sets new target, and kicks off processing. */
-static void set_new_target(unsigned long target)
+void balloon_set_new_target(unsigned long target)
{
/* No need for lock. Not read-modify-write updates. */
- hard_limit = ~0UL;
- target_pages = target;
+ bs.hard_limit = ~0UL;
+ bs.target_pages = target;
schedule_work(&balloon_worker);
}
@@ -388,7 +373,7 @@ static void watch_target(struct xenbus_watch *watch,
/* The given memory/target value is in KiB, so it needs converting to
* pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
*/
- set_new_target(new_target >> (PAGE_SHIFT - 10));
+ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
}
static int balloon_init_watcher(struct notifier_block *notifier,
@@ -424,7 +409,7 @@ static int balloon_write(struct file *file, const char __user *buffer,
memstring[sizeof(memstring)-1] = '\0';
target_bytes = memparse(memstring, &endchar);
- set_new_target(target_bytes >> PAGE_SHIFT);
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
return count;
}
@@ -442,12 +427,13 @@ static int balloon_read(char *page, char **start, off_t off,
"High-mem balloon: %8lu kB\n"
"Driver pages: %8lu kB\n"
"Xen hard limit: ",
- PAGES2KB(current_pages), PAGES2KB(target_pages),
- PAGES2KB(balloon_low), PAGES2KB(balloon_high),
- PAGES2KB(driver_pages));
+ PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages),
+ PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high),
+ PAGES2KB(bs.driver_pages));
- if (hard_limit != ~0UL)
- len += sprintf(page + len, "%8lu kB\n", PAGES2KB(hard_limit));
+ if (bs.hard_limit != ~0UL)
+ len += sprintf(page + len, "%8lu kB\n",
+ PAGES2KB(bs.hard_limit));
else
len += sprintf(page + len, " ??? kB\n");
@@ -468,13 +454,13 @@ static int __init balloon_init(void)
IPRINTK("Initialising balloon driver.\n");
- current_pages = min(xen_start_info->nr_pages, max_pfn);
- totalram_pages = current_pages;
- target_pages = current_pages;
- balloon_low = 0;
- balloon_high = 0;
- driver_pages = 0UL;
- hard_limit = ~0UL;
+ bs.current_pages = min(xen_start_info->nr_pages, max_pfn);
+ totalram_pages = bs.current_pages;
+ bs.target_pages = bs.current_pages;
+ bs.balloon_low = 0;
+ bs.balloon_high = 0;
+ bs.driver_pages = 0UL;
+ bs.hard_limit = ~0UL;
init_timer(&balloon_timer);
balloon_timer.data = 0;
@@ -489,6 +475,7 @@ static int __init balloon_init(void)
balloon_pde->read_proc = balloon_read;
balloon_pde->write_proc = balloon_write;
#endif
+ balloon_sysfs_init();
/* Initialise the balloon with excess memory space. */
for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
@@ -512,7 +499,7 @@ void balloon_update_driver_allowance(long delta)
unsigned long flags;
balloon_lock(flags);
- driver_pages += delta;
+ bs.driver_pages += delta;
balloon_unlock(flags);
}
@@ -534,75 +521,87 @@ static int dealloc_pte_fn(
return 0;
}
-struct page *balloon_alloc_empty_page_range(unsigned long nr_pages)
+struct page **alloc_empty_pages_and_pagevec(int nr_pages)
{
- unsigned long vstart, flags;
- unsigned int order = get_order(nr_pages * PAGE_SIZE);
- int ret;
- unsigned long i;
- struct page *page;
+ unsigned long vaddr, flags;
+ struct page *page, **pagevec;
+ int i, ret;
- vstart = __get_free_pages(GFP_KERNEL, order);
- if (vstart == 0)
+ pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
+ if (pagevec == NULL)
return NULL;
- scrub_pages(vstart, 1 << order);
-
- balloon_lock(flags);
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- unsigned long gmfn = __pa(vstart) >> PAGE_SHIFT;
- struct xen_memory_reservation reservation = {
- .nr_extents = 1,
- .extent_order = order,
- .domid = DOMID_SELF
- };
- set_xen_guest_handle(reservation.extent_start, &gmfn);
- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation);
- if (ret == -ENOSYS)
- goto err;
- BUG_ON(ret != 1);
- } else {
- ret = apply_to_page_range(&init_mm, vstart, PAGE_SIZE << order,
- dealloc_pte_fn, NULL);
- if (ret == -ENOSYS)
+ for (i = 0; i < nr_pages; i++) {
+ page = pagevec[i] = alloc_page(GFP_KERNEL);
+ if (page == NULL)
goto err;
- BUG_ON(ret);
- }
- current_pages -= 1UL << order;
- totalram_pages = current_pages;
- balloon_unlock(flags);
- schedule_work(&balloon_worker);
+ vaddr = (unsigned long)page_address(page);
- flush_tlb_all();
+ scrub_pages(vaddr, 1);
- page = virt_to_page(vstart);
+ balloon_lock(flags);
- for (i = 0; i < (1UL << order); i++)
- set_page_count(page + i, 1);
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ unsigned long gmfn = page_to_pfn(page);
+ struct xen_memory_reservation reservation = {
+ .nr_extents = 1,
+ .extent_order = 0,
+ .domid = DOMID_SELF
+ };
+ set_xen_guest_handle(reservation.extent_start, &gmfn);
+ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+ &reservation);
+ if (ret == 1)
+ ret = 0; /* success */
+ } else {
+ ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
+ dealloc_pte_fn, NULL);
+ }
- return page;
+ if (ret != 0) {
+ balloon_unlock(flags);
+ __free_page(page);
+ goto err;
+ }
+
+ totalram_pages = --bs.current_pages;
+
+ balloon_unlock(flags);
+ }
+
+ out:
+ schedule_work(&balloon_worker);
+ flush_tlb_all();
+ return pagevec;
err:
- free_pages(vstart, order);
+ balloon_lock(flags);
+ while (--i >= 0)
+ balloon_append(pagevec[i]);
balloon_unlock(flags);
- return NULL;
+ kfree(pagevec);
+ pagevec = NULL;
+ goto out;
}
-void balloon_dealloc_empty_page_range(
- struct page *page, unsigned long nr_pages)
+void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
{
- unsigned long i, flags;
- unsigned int order = get_order(nr_pages * PAGE_SIZE);
+ unsigned long flags;
+ int i;
+
+ if (pagevec == NULL)
+ return;
balloon_lock(flags);
- for (i = 0; i < (1UL << order); i++) {
- BUG_ON(page_count(page + i) != 1);
- balloon_append(page + i);
+ for (i = 0; i < nr_pages; i++) {
+ BUG_ON(page_count(pagevec[i]) != 1);
+ balloon_append(pagevec[i]);
}
balloon_unlock(flags);
+ kfree(pagevec);
+
schedule_work(&balloon_worker);
}
@@ -612,15 +611,15 @@ void balloon_release_driver_page(struct page *page)
balloon_lock(flags);
balloon_append(page);
- driver_pages--;
+ bs.driver_pages--;
balloon_unlock(flags);
schedule_work(&balloon_worker);
}
EXPORT_SYMBOL_GPL(balloon_update_driver_allowance);
-EXPORT_SYMBOL_GPL(balloon_alloc_empty_page_range);
-EXPORT_SYMBOL_GPL(balloon_dealloc_empty_page_range);
+EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
+EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
EXPORT_SYMBOL_GPL(balloon_release_driver_page);
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/common.h b/linux-2.6-xen-sparse/drivers/xen/balloon/common.h
new file mode 100644
index 0000000000..4496d215e2
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/common.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * balloon/common.h
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 __XEN_BALLOON_COMMON_H__
+#define __XEN_BALLOON_COMMON_H__
+
+#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+
+struct balloon_stats {
+ /* We aim for 'current allocation' == 'target allocation'. */
+ unsigned long current_pages;
+ unsigned long target_pages;
+ /* We may hit the hard limit in Xen. If we do then we remember it. */
+ unsigned long hard_limit;
+ /*
+ * Drivers may alter the memory reservation independently, but they
+ * must inform the balloon driver so we avoid hitting the hard limit.
+ */
+ unsigned long driver_pages;
+ /* Number of pages in high- and low-memory balloons. */
+ unsigned long balloon_low;
+ unsigned long balloon_high;
+};
+
+extern struct balloon_stats balloon_stats;
+#define bs balloon_stats
+
+int balloon_sysfs_init(void);
+void balloon_sysfs_exit(void);
+
+void balloon_set_new_target(unsigned long target);
+
+#endif /* __XEN_BALLOON_COMMON_H__ */
diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c b/linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c
new file mode 100644
index 0000000000..a4ed8a6f1e
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/sysfs.c
@@ -0,0 +1,165 @@
+/******************************************************************************
+ * balloon/sysfs.c
+ *
+ * Xen balloon driver - sysfs interfaces.
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 <linux/config.h>
+#include <linux/capability.h>
+#include <linux/stat.h>
+#include <linux/sysdev.h>
+#include "common.h"
+
+#define BALLOON_CLASS_NAME "memory"
+
+#define BALLOON_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ char *buf) \
+ { \
+ return sprintf(buf, format, ##args); \
+ } \
+ static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
+
+BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages));
+BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low));
+BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high));
+BALLOON_SHOW(hard_limit_kb,
+ (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n",
+ (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0);
+BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages));
+
+static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%lu\n", PAGES2KB(bs.target_pages));
+}
+
+static ssize_t store_target_kb(struct sys_device *dev,
+ const char *buf,
+ size_t count)
+{
+ char memstring[64], *endchar;
+ unsigned long long target_bytes;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (count <= 1)
+ return -EBADMSG; /* runt */
+ if (count > sizeof(memstring))
+ return -EFBIG; /* too long */
+ strcpy(memstring, buf);
+
+ target_bytes = memparse(memstring, &endchar);
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
+ show_target_kb, store_target_kb);
+
+static struct sysdev_attribute *balloon_attrs[] = {
+ &attr_target_kb,
+};
+
+static struct attribute *balloon_info_attrs[] = {
+ &attr_current_kb.attr,
+ &attr_low_kb.attr,
+ &attr_high_kb.attr,
+ &attr_hard_limit_kb.attr,
+ &attr_driver_kb.attr,
+ NULL
+};
+
+static struct attribute_group balloon_info_group = {
+ .name = "info",
+ .attrs = balloon_info_attrs,
+};
+
+static struct sysdev_class balloon_sysdev_class = {
+ set_kset_name(BALLOON_CLASS_NAME),
+};
+
+static struct sys_device balloon_sysdev;
+
+static int register_balloon(struct sys_device *sysdev)
+{
+ int i, error;
+
+ error = sysdev_class_register(&balloon_sysdev_class);
+ if (error)
+ return error;
+
+ sysdev->id = 0;
+ sysdev->cls = &balloon_sysdev_class;
+
+ error = sysdev_register(sysdev);
+ if (error) {
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
+ error = sysdev_create_file(sysdev, balloon_attrs[i]);
+ if (error)
+ goto fail;
+ }
+
+ error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
+ if (error)
+ goto fail;
+
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+}
+
+static void unregister_balloon(struct sys_device *sysdev)
+{
+ int i;
+
+ sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+}
+
+int balloon_sysfs_init(void)
+{
+ return register_balloon(&balloon_sysdev);
+}
+
+void balloon_sysfs_exit(void)
+{
+ unregister_balloon(&balloon_sysdev);
+}
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c b/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c
index 416f7bc18c..e8df9e0346 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/blkback.c
@@ -56,8 +56,6 @@ static int blkif_reqs = 64;
module_param_named(reqs, blkif_reqs, int, 0);
MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
-static int mmap_pages;
-
/* Run-time switchable: /sys/module/blkback/parameters/ */
static unsigned int log_stats = 0;
static unsigned int debug_lvl = 0;
@@ -87,8 +85,7 @@ static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
#define BLKBACK_INVALID_HANDLE (~0)
-static unsigned long mmap_vstart;
-static unsigned long *pending_vaddrs;
+static struct page **pending_pages;
static grant_handle_t *pending_grant_handles;
static inline int vaddr_pagenr(pending_req_t *req, int seg)
@@ -98,7 +95,8 @@ static inline int vaddr_pagenr(pending_req_t *req, int seg)
static inline unsigned long vaddr(pending_req_t *req, int seg)
{
- return pending_vaddrs[vaddr_pagenr(req, seg)];
+ unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
+ return (unsigned long)pfn_to_kaddr(pfn);
}
#define pending_handle(_req, _seg) \
@@ -191,9 +189,9 @@ static void fast_flush_area(pending_req_t *req)
static void print_stats(blkif_t *blkif)
{
- printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n",
+ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d | br %4d\n",
current->comm, blkif->st_oo_req,
- blkif->st_rd_req, blkif->st_wr_req);
+ blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req);
blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
blkif->st_rd_req = 0;
blkif->st_wr_req = 0;
@@ -243,11 +241,17 @@ int blkif_schedule(void *arg)
* COMPLETION CALLBACK -- Called as bh->b_end_io()
*/
-static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
+static void __end_block_io_op(pending_req_t *pending_req, int error)
{
/* An error fails the entire request. */
- if (!uptodate) {
- DPRINTK("Buffer not up-to-date at end of operation\n");
+ if ((pending_req->operation == BLKIF_OP_WRITE_BARRIER) &&
+ (error == -EOPNOTSUPP)) {
+ DPRINTK("blkback: write barrier op failed, not supported\n");
+ blkback_barrier(XBT_NIL, pending_req->blkif->be, 0);
+ pending_req->status = BLKIF_RSP_EOPNOTSUPP;
+ } else if (error) {
+ DPRINTK("Buffer not up-to-date at end of operation, "
+ "error=%d\n", error);
pending_req->status = BLKIF_RSP_ERROR;
}
@@ -264,7 +268,7 @@ static int end_block_io_op(struct bio *bio, unsigned int done, int error)
{
if (bio->bi_size != 0)
return 1;
- __end_block_io_op(bio->bi_private, !error);
+ __end_block_io_op(bio->bi_private, error);
bio_put(bio);
return error;
}
@@ -295,7 +299,7 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
static int do_block_io_op(blkif_t *blkif)
{
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
- blkif_request_t *req;
+ blkif_request_t req;
pending_req_t *pending_req;
RING_IDX rc, rp;
int more_to_do = 0;
@@ -313,22 +317,25 @@ static int do_block_io_op(blkif_t *blkif)
break;
}
- req = RING_GET_REQUEST(blk_ring, rc);
+ memcpy(&req, RING_GET_REQUEST(blk_ring, rc), sizeof(req));
blk_ring->req_cons = ++rc; /* before make_response() */
- switch (req->operation) {
+ switch (req.operation) {
case BLKIF_OP_READ:
blkif->st_rd_req++;
- dispatch_rw_block_io(blkif, req, pending_req);
+ dispatch_rw_block_io(blkif, &req, pending_req);
break;
+ case BLKIF_OP_WRITE_BARRIER:
+ blkif->st_br_req++;
+ /* fall through */
case BLKIF_OP_WRITE:
blkif->st_wr_req++;
- dispatch_rw_block_io(blkif, req, pending_req);
+ dispatch_rw_block_io(blkif, &req, pending_req);
break;
default:
DPRINTK("error: unknown block io operation [%d]\n",
- req->operation);
- make_response(blkif, req->id, req->operation,
+ req.operation);
+ make_response(blkif, req.id, req.operation,
BLKIF_RSP_ERROR);
free_req(pending_req);
break;
@@ -342,7 +349,6 @@ static void dispatch_rw_block_io(blkif_t *blkif,
pending_req_t *pending_req)
{
extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
- int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct phys_req preq;
struct {
@@ -351,6 +357,22 @@ static void dispatch_rw_block_io(blkif_t *blkif,
unsigned int nseg;
struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int ret, i, nbio = 0;
+ int operation;
+
+ switch (req->operation) {
+ case BLKIF_OP_READ:
+ operation = READ;
+ break;
+ case BLKIF_OP_WRITE:
+ operation = WRITE;
+ break;
+ case BLKIF_OP_WRITE_BARRIER:
+ operation = WRITE_BARRIER;
+ break;
+ default:
+ operation = 0; /* make gcc happy */
+ BUG();
+ }
/* Check that number of segments is sane. */
nseg = req->nr_segments;
@@ -366,7 +388,7 @@ static void dispatch_rw_block_io(blkif_t *blkif,
pending_req->blkif = blkif;
pending_req->id = req->id;
- pending_req->operation = operation;
+ pending_req->operation = req->operation;
pending_req->status = BLKIF_RSP_OKAY;
pending_req->nr_pages = nseg;
@@ -377,12 +399,12 @@ static void dispatch_rw_block_io(blkif_t *blkif,
req->seg[i].first_sect + 1;
if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
- (seg[i].nsec <= 0))
+ (req->seg[i].last_sect < req->seg[i].first_sect))
goto fail_response;
preq.nr_sects += seg[i].nsec;
flags = GNTMAP_host_map;
- if ( operation == WRITE )
+ if (operation != READ)
flags |= GNTMAP_readonly;
gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
req->seg[i].gref, blkif->domid);
@@ -394,10 +416,15 @@ static void dispatch_rw_block_io(blkif_t *blkif,
for (i = 0; i < nseg; i++) {
if (unlikely(map[i].status != 0)) {
DPRINTK("invalid buffer -- could not remap it\n");
- goto fail_flush;
+ map[i].handle = BLKBACK_INVALID_HANDLE;
+ ret |= 1;
}
pending_handle(pending_req, i) = map[i].handle;
+
+ if (ret)
+ continue;
+
set_phys_to_machine(__pa(vaddr(
pending_req, i)) >> PAGE_SHIFT,
FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
@@ -405,6 +432,9 @@ static void dispatch_rw_block_io(blkif_t *blkif,
(req->seg[i].first_sect << 9);
}
+ if (ret)
+ goto fail_flush;
+
if (vbd_translate(&preq, blkif, operation) != 0) {
DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n",
operation == READ ? "read" : "write",
@@ -506,52 +536,43 @@ static void make_response(blkif_t *blkif, unsigned long id,
static int __init blkif_init(void)
{
- struct page *page;
- int i;
+ int i, mmap_pages;
if (!is_running_on_xen())
return -ENODEV;
- mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
- page = balloon_alloc_empty_page_range(mmap_pages);
- if (page == NULL)
- return -ENOMEM;
- mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+ mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
blkif_reqs, GFP_KERNEL);
pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
mmap_pages, GFP_KERNEL);
- pending_vaddrs = kmalloc(sizeof(pending_vaddrs[0]) *
- mmap_pages, GFP_KERNEL);
- if (!pending_reqs || !pending_grant_handles || !pending_vaddrs) {
- kfree(pending_reqs);
- kfree(pending_grant_handles);
- kfree(pending_vaddrs);
- printk("%s: out of memory\n", __FUNCTION__);
- return -ENOMEM;
- }
+ pending_pages = alloc_empty_pages_and_pagevec(mmap_pages);
- blkif_interface_init();
-
- printk("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
- __FUNCTION__, blkif_reqs, mmap_pages, mmap_vstart);
- BUG_ON(mmap_vstart == 0);
- for (i = 0; i < mmap_pages; i++) {
- pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT);
+ if (!pending_reqs || !pending_grant_handles || !pending_pages)
+ goto out_of_memory;
+
+ for (i = 0; i < mmap_pages; i++)
pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
- }
+
+ blkif_interface_init();
memset(pending_reqs, 0, sizeof(pending_reqs));
INIT_LIST_HEAD(&pending_free);
for (i = 0; i < blkif_reqs; i++)
list_add_tail(&pending_reqs[i].free_list, &pending_free);
-
+
blkif_xenbus_init();
return 0;
+
+ out_of_memory:
+ kfree(pending_reqs);
+ kfree(pending_grant_handles);
+ free_empty_pages_and_pagevec(pending_pages, mmap_pages);
+ printk("%s: out of memory\n", __FUNCTION__);
+ return -ENOMEM;
}
module_init(blkif_init);
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h
index 38cb756964..1b5b6a427e 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h
@@ -44,6 +44,7 @@
#include <xen/interface/io/ring.h>
#include <xen/gnttab.h>
#include <xen/driver_util.h>
+#include <xen/xenbus.h>
#define DPRINTK(_f, _a...) \
pr_debug("(file=%s, line=%d) " _f, \
@@ -87,6 +88,7 @@ typedef struct blkif_st {
int st_rd_req;
int st_wr_req;
int st_oo_req;
+ int st_br_req;
wait_queue_head_t waiting_to_free;
@@ -111,7 +113,7 @@ int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major,
unsigned minor, int readonly);
void vbd_free(struct vbd *vbd);
-unsigned long vbd_size(struct vbd *vbd);
+unsigned long long vbd_size(struct vbd *vbd);
unsigned int vbd_info(struct vbd *vbd);
unsigned long vbd_secsize(struct vbd *vbd);
@@ -131,4 +133,7 @@ void blkif_xenbus_init(void);
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
int blkif_schedule(void *arg);
+int blkback_barrier(struct xenbus_transaction xbt,
+ struct backend_info *be, int state);
+
#endif /* __BLKIF__BACKEND__COMMON_H__ */
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c b/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c
index a809b04cd1..34048b32c4 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c
@@ -31,12 +31,11 @@
*/
#include "common.h"
-#include <xen/xenbus.h>
#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
(_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
-unsigned long vbd_size(struct vbd *vbd)
+unsigned long long vbd_size(struct vbd *vbd)
{
return vbd_sz(vbd);
}
@@ -104,7 +103,7 @@ int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
struct vbd *vbd = &blkif->vbd;
int rc = -EACCES;
- if ((operation == WRITE) && vbd->readonly)
+ if ((operation != READ) && vbd->readonly)
goto out;
if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
index 02f90a6803..349ae64d0f 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
@@ -20,7 +20,6 @@
#include <stdarg.h>
#include <linux/module.h>
#include <linux/kthread.h>
-#include <xen/xenbus.h>
#include "common.h"
#undef DPRINTK
@@ -91,11 +90,13 @@ static void update_blkif_status(blkif_t *blkif)
VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
+VBD_SHOW(br_req, "%d\n", be->blkif->st_br_req);
static struct attribute *vbdstat_attrs[] = {
&dev_attr_oo_req.attr,
&dev_attr_rd_req.attr,
&dev_attr_wr_req.attr,
+ &dev_attr_br_req.attr,
NULL
};
@@ -165,6 +166,19 @@ static int blkback_remove(struct xenbus_device *dev)
return 0;
}
+int blkback_barrier(struct xenbus_transaction xbt,
+ struct backend_info *be, int state)
+{
+ struct xenbus_device *dev = be->dev;
+ int err;
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-barrier",
+ "%d", state);
+ if (err)
+ xenbus_dev_fatal(dev, err, "writing feature-barrier");
+
+ return err;
+}
/**
* Entry point to this code when a new device is created. Allocate the basic
@@ -366,13 +380,16 @@ static void connect(struct backend_info *be)
/* Supply the information about the device the frontend needs */
again:
err = xenbus_transaction_start(&xbt);
-
if (err) {
xenbus_dev_fatal(dev, err, "starting transaction");
return;
}
- err = xenbus_printf(xbt, dev->nodename, "sectors", "%lu",
+ err = blkback_barrier(xbt, be, 1);
+ if (err)
+ goto abort;
+
+ err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
vbd_size(&be->blkif->vbd));
if (err) {
xenbus_dev_fatal(dev, err, "writing %s/sectors",
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
index 4c44d7608d..95cff46ff9 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
@@ -48,6 +48,10 @@
#include <asm/hypervisor.h>
#include <asm/maddr.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
#define BLKIF_STATE_DISCONNECTED 0
#define BLKIF_STATE_CONNECTED 1
#define BLKIF_STATE_SUSPENDED 2
@@ -134,10 +138,10 @@ static int blkfront_resume(struct xenbus_device *dev)
DPRINTK("blkfront_resume: %s\n", dev->nodename);
- blkif_free(info, 1);
+ blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
err = talk_to_backend(dev, info);
- if (!err)
+ if (info->connected == BLKIF_STATE_SUSPENDED && !err)
blkif_recover(info);
return err;
@@ -273,7 +277,7 @@ static void backend_changed(struct xenbus_device *dev,
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
down(&bd->bd_sem);
- if (info->users > 0 && system_state == SYSTEM_RUNNING)
+ if (info->users > 0)
xenbus_dev_error(dev, -EBUSY,
"Device in use; refusing to close");
else
@@ -294,7 +298,8 @@ static void backend_changed(struct xenbus_device *dev,
*/
static void connect(struct blkfront_info *info)
{
- unsigned long sectors, sector_size;
+ unsigned long long sectors;
+ unsigned long sector_size;
unsigned int binfo;
int err;
@@ -305,7 +310,7 @@ static void connect(struct blkfront_info *info)
DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend);
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "sectors", "%lu", &sectors,
+ "sectors", "%llu", &sectors,
"info", "%u", &binfo,
"sector-size", "%lu", &sector_size,
NULL);
@@ -316,6 +321,12 @@ static void connect(struct blkfront_info *info)
return;
}
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-barrier", "%lu", &info->feature_barrier,
+ NULL);
+ if (err)
+ info->feature_barrier = 0;
+
err = xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
@@ -355,9 +366,11 @@ static void blkfront_closing(struct xenbus_device *dev)
blk_stop_queue(info->rq);
/* No more gnttab callback work. */
gnttab_cancel_free_callback(&info->callback);
- flush_scheduled_work();
spin_unlock_irqrestore(&blkif_io_lock, flags);
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
xlvbd_del(info);
xenbus_frontend_closed(dev);
@@ -466,6 +479,27 @@ int blkif_ioctl(struct inode *inode, struct file *filep,
command, (long)argument, inode->i_rdev);
switch (command) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+ case HDIO_GETGEO: {
+ struct block_device *bd = inode->i_bdev;
+ struct hd_geometry geo;
+ int ret;
+
+ if (!argument)
+ return -EINVAL;
+
+ geo.start = get_start_sect(bd);
+ ret = blkif_getgeo(bd, &geo);
+ if (ret)
+ return ret;
+
+ if (copy_to_user((struct hd_geometry __user *)argument, &geo,
+ sizeof(geo)))
+ return -EFAULT;
+
+ return 0;
+ }
+#endif
case CDROMMULTISESSION:
DPRINTK("FIXME: support multisession CDs later\n");
for (i = 0; i < sizeof(struct cdrom_multisession); i++)
@@ -542,11 +576,14 @@ static int blkif_queue_request(struct request *req)
info->shadow[id].request = (unsigned long)req;
ring_req->id = id;
- ring_req->operation = rq_data_dir(req) ?
- BLKIF_OP_WRITE : BLKIF_OP_READ;
ring_req->sector_number = (blkif_sector_t)req->sector;
ring_req->handle = info->handle;
+ ring_req->operation = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ if (blk_barrier_rq(req))
+ ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
ring_req->nr_segments = 0;
rq_for_each_bio (bio, req) {
bio_for_each_segment (bvec, bio, idx) {
@@ -643,6 +680,7 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
RING_IDX i, rp;
unsigned long flags;
struct blkfront_info *info = (struct blkfront_info *)dev_id;
+ int uptodate;
spin_lock_irqsave(&blkif_io_lock, flags);
@@ -667,19 +705,27 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
ADD_ID_TO_FREELIST(info, id);
+ uptodate = (bret->status == BLKIF_RSP_OKAY);
switch (bret->operation) {
+ case BLKIF_OP_WRITE_BARRIER:
+ if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+ printk("blkfront: %s: write barrier op failed\n",
+ info->gd->disk_name);
+ uptodate = -EOPNOTSUPP;
+ info->feature_barrier = 0;
+ xlvbd_barrier(info);
+ }
+ /* fall through */
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
if (unlikely(bret->status != BLKIF_RSP_OKAY))
DPRINTK("Bad return from blkdev data "
"request: %x\n", bret->status);
- ret = end_that_request_first(
- req, (bret->status == BLKIF_RSP_OKAY),
+ ret = end_that_request_first(req, uptodate,
req->hard_nr_sectors);
BUG_ON(ret);
- end_that_request_last(
- req, (bret->status == BLKIF_RSP_OKAY));
+ end_that_request_last(req, uptodate);
break;
default:
BUG();
@@ -714,9 +760,11 @@ static void blkif_free(struct blkfront_info *info, int suspend)
blk_stop_queue(info->rq);
/* No more gnttab callback work. */
gnttab_cancel_free_callback(&info->callback);
- flush_scheduled_work();
spin_unlock_irq(&blkif_io_lock);
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
/* Free resources associated with old device channel. */
if (info->ring_ref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(info->ring_ref, 0,
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h b/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h
index 5ba3d1ebc3..b86360f405 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h
@@ -126,6 +126,7 @@ struct blkfront_info
struct gnttab_free_callback callback;
struct blk_shadow shadow[BLK_RING_SIZE];
unsigned long shadow_free;
+ int feature_barrier;
/**
* The number of people holding this device open. We won't allow a
@@ -152,5 +153,6 @@ extern void do_blkif_request (request_queue_t *rq);
int xlvbd_add(blkif_sector_t capacity, int device,
u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
void xlvbd_del(struct blkfront_info *info);
+int xlvbd_barrier(struct blkfront_info *info);
#endif /* __XEN_DRIVERS_BLOCK_H__ */
diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c
index 8aa453d3a0..f040a2b7e3 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c
@@ -36,6 +36,10 @@
#include <linux/blkdev.h>
#include <linux/list.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
#define BLKIF_MAJOR(dev) ((dev)>>8)
#define BLKIF_MINOR(dev) ((dev) & 0xff)
@@ -46,7 +50,7 @@
*/
#define NUM_IDE_MAJORS 10
-#define NUM_SCSI_MAJORS 9
+#define NUM_SCSI_MAJORS 17
#define NUM_VBD_MAJORS 1
static struct xlbd_type_info xlbd_ide_type = {
@@ -91,7 +95,9 @@ static struct block_device_operations xlvbd_block_fops =
.open = blkif_open,
.release = blkif_release,
.ioctl = blkif_ioctl,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
.getgeo = blkif_getgeo
+#endif
};
DEFINE_SPINLOCK(blkif_io_lock);
@@ -159,8 +165,11 @@ xlbd_get_major_info(int vdevice)
case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
index = 11 + major - SCSI_DISK1_MAJOR;
break;
- case SCSI_CDROM_MAJOR: index = 18; break;
- default: index = 19; break;
+ case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR:
+ index = 18 + major - SCSI_DISK8_MAJOR;
+ break;
+ case SCSI_CDROM_MAJOR: index = 26; break;
+ default: index = 27; break;
}
mi = ((major_info[index] != NULL) ? major_info[index] :
@@ -186,7 +195,11 @@ xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
if (rq == NULL)
return -1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
elevator_init(rq, "noop");
+#else
+ elevator_init(rq, &elevator_noop);
+#endif
/* Hard sector size and max sectors impersonate the equiv. hardware. */
blk_queue_hardsect_size(rq, sector_size);
@@ -217,6 +230,7 @@ xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
struct xlbd_major_info *mi;
int nr_minors = 1;
int err = -ENODEV;
+ unsigned int offset;
BUG_ON(info->gd != NULL);
BUG_ON(info->mi != NULL);
@@ -234,15 +248,33 @@ xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
if (gd == NULL)
goto out;
- if (nr_minors > 1)
- sprintf(gd->disk_name, "%s%c", mi->type->diskname,
- 'a' + mi->index * mi->type->disks_per_major +
- (minor >> mi->type->partn_shift));
- else
- sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
- 'a' + mi->index * mi->type->disks_per_major +
- (minor >> mi->type->partn_shift),
- minor & ((1 << mi->type->partn_shift) - 1));
+ offset = mi->index * mi->type->disks_per_major +
+ (minor >> mi->type->partn_shift);
+ if (nr_minors > 1) {
+ if (offset < 26) {
+ sprintf(gd->disk_name, "%s%c",
+ mi->type->diskname, 'a' + offset );
+ }
+ else {
+ sprintf(gd->disk_name, "%s%c%c",
+ mi->type->diskname,
+ 'a' + ((offset/26)-1), 'a' + (offset%26) );
+ }
+ }
+ else {
+ if (offset < 26) {
+ sprintf(gd->disk_name, "%s%c%d",
+ mi->type->diskname,
+ 'a' + offset,
+ minor & ((1 << mi->type->partn_shift) - 1));
+ }
+ else {
+ sprintf(gd->disk_name, "%s%c%c%d",
+ mi->type->diskname,
+ 'a' + ((offset/26)-1), 'a' + (offset%26),
+ minor & ((1 << mi->type->partn_shift) - 1));
+ }
+ }
gd->major = mi->major;
gd->first_minor = minor;
@@ -257,6 +289,10 @@ xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
}
info->rq = gd->queue;
+ info->gd = gd;
+
+ if (info->feature_barrier)
+ xlvbd_barrier(info);
if (vdisk_info & VDISK_READONLY)
set_disk_ro(gd, 1);
@@ -267,8 +303,6 @@ xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
if (vdisk_info & VDISK_CDROM)
gd->flags |= GENHD_FL_CD;
- info->gd = gd;
-
return 0;
out:
@@ -316,3 +350,26 @@ xlvbd_del(struct blkfront_info *info)
blk_cleanup_queue(info->rq);
info->rq = NULL;
}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+int
+xlvbd_barrier(struct blkfront_info *info)
+{
+ int err;
+
+ err = blk_queue_ordered(info->rq,
+ info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE, NULL);
+ if (err)
+ return err;
+ printk("blkfront: %s: barriers %s\n",
+ info->gd->disk_name, info->feature_barrier ? "enabled" : "disabled");
+ return 0;
+}
+#else
+int
+xlvbd_barrier(struct blkfront_info *info)
+{
+ printk("blkfront: %s: barriers disabled\n", info->gd->disk_name);
+ return -ENOSYS;
+}
+#endif
diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c
index a6f1379c27..e0d898ab98 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c
@@ -10,6 +10,9 @@
*
* Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
*
+ * Clean ups and fix ups:
+ * Copyright (c) 2006, Steven Rostedt - Red Hat, Inc.
+ *
* 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; or, when distributed
@@ -44,7 +47,6 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
-#include <linux/miscdevice.h>
#include <linux/errno.h>
#include <linux/major.h>
#include <linux/gfp.h>
@@ -52,9 +54,33 @@
#include <asm/tlbflush.h>
#include <linux/devfs_fs_kernel.h>
-#define MAX_TAP_DEV 100 /*the maximum number of tapdisk ring devices */
+#define MAX_TAP_DEV 256 /*the maximum number of tapdisk ring devices */
#define MAX_DEV_NAME 100 /*the max tapdisk ring device name e.g. blktap0 */
+
+struct class *xen_class;
+EXPORT_SYMBOL_GPL(xen_class);
+
+/*
+ * Setup the xen class. This should probably go in another file, but
+ * since blktap is the only user of it so far, it gets to keep it.
+ */
+int setup_xen_class(void)
+{
+ int ret;
+
+ if (xen_class)
+ return 0;
+
+ xen_class = class_create(THIS_MODULE, "xen");
+ if ((ret = IS_ERR(xen_class))) {
+ xen_class = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* The maximum number of requests that can be outstanding at any time
* is determined by
@@ -67,8 +93,9 @@
* mmap_alloc is initialised to 2 and should be adjustable on the fly via
* sysfs.
*/
-#define MAX_DYNAMIC_MEM 64
-#define MAX_PENDING_REQS 64
+#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
+#define MAX_DYNAMIC_MEM BLK_RING_SIZE
+#define MAX_PENDING_REQS BLK_RING_SIZE
#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
#define MMAP_VADDR(_start, _req,_seg) \
(_start + \
@@ -82,6 +109,12 @@ static int mmap_pages = MMAP_PAGES;
* memory rings.
*/
+/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
+typedef struct domid_translate {
+ unsigned short domid;
+ unsigned short busid;
+} domid_translate_t ;
+
/*Data struct associated with each of the tapdisk devices*/
typedef struct tap_blkif {
struct vm_area_struct *vma; /*Shared memory area */
@@ -100,22 +133,11 @@ typedef struct tap_blkif {
unsigned long *idx_map; /*Record the user ring id to kern
[req id, idx] tuple */
blkif_t *blkif; /*Associate blkif with tapdev */
+ struct domid_translate trans; /*Translation from domid to bus. */
} tap_blkif_t;
-/*Private data struct associated with the inode*/
-typedef struct private_info {
- int idx;
-} private_info_t;
-
-/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
-typedef struct domid_translate {
- unsigned short domid;
- unsigned short busid;
-} domid_translate_t ;
-
-
-static domid_translate_t translate_domid[MAX_TAP_DEV];
-static tap_blkif_t *tapfds[MAX_TAP_DEV];
+static struct tap_blkif *tapfds[MAX_TAP_DEV];
+static int blktap_next_minor;
static int __init set_blkif_reqs(char *str)
{
@@ -168,16 +190,18 @@ static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
#define BLKBACK_INVALID_HANDLE (~0)
-typedef struct mmap_page {
- unsigned long start;
- struct page *mpage;
-} mmap_page_t;
+static struct page **foreign_pages[MAX_DYNAMIC_MEM];
+static inline unsigned long idx_to_kaddr(
+ unsigned int mmap_idx, unsigned int req_idx, unsigned int sg_idx)
+{
+ unsigned int arr_idx = req_idx*BLKIF_MAX_SEGMENTS_PER_REQUEST + sg_idx;
+ unsigned long pfn = page_to_pfn(foreign_pages[mmap_idx][arr_idx]);
+ return (unsigned long)pfn_to_kaddr(pfn);
+}
-static mmap_page_t mmap_start[MAX_DYNAMIC_MEM];
static unsigned short mmap_alloc = 0;
static unsigned short mmap_lock = 0;
static unsigned short mmap_inuse = 0;
-static unsigned long *pending_addrs[MAX_DYNAMIC_MEM];
/******************************************************************
* GRANT HANDLES
@@ -192,6 +216,7 @@ struct grant_handle_pair
grant_handle_t kernel;
grant_handle_t user;
};
+#define INVALID_GRANT_HANDLE 0xFFFF
static struct grant_handle_pair
pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
@@ -200,15 +225,13 @@ static struct grant_handle_pair
+ (_i)])
-static int blktap_read_ufe_ring(int idx); /*local prototypes*/
+static int blktap_read_ufe_ring(tap_blkif_t *info); /*local prototypes*/
-#define BLKTAP_MINOR 0 /*/dev/xen/blktap resides at device number
- major=254, minor numbers begin at 0 */
-#define BLKTAP_DEV_MAJOR 254 /* TODO: Make major number dynamic *
- * and create devices in the kernel *
- */
+#define BLKTAP_MINOR 0 /*/dev/xen/blktap has a dynamic major */
#define BLKTAP_DEV_DIR "/dev/xen"
+static int blktap_major;
+
/* blktap IOCTLs: */
#define BLKTAP_IOCTL_KICK_FE 1
#define BLKTAP_IOCTL_KICK_BE 2 /* currently unused */
@@ -264,17 +287,19 @@ static inline int GET_NEXT_REQ(unsigned long *idx_map)
{
int i;
for (i = 0; i < MAX_PENDING_REQS; i++)
- if (idx_map[i] == INVALID_REQ) return i;
+ if (idx_map[i] == INVALID_REQ)
+ return i;
return INVALID_REQ;
}
#define BLKTAP_INVALID_HANDLE(_g) \
- (((_g->kernel) == 0xFFFF) && ((_g->user) == 0xFFFF))
+ (((_g->kernel) == INVALID_GRANT_HANDLE) && \
+ ((_g->user) == INVALID_GRANT_HANDLE))
#define BLKTAP_INVALIDATE_HANDLE(_g) do { \
- (_g)->kernel = 0xFFFF; (_g)->user = 0xFFFF; \
+ (_g)->kernel = INVALID_GRANT_HANDLE; (_g)->user = INVALID_GRANT_HANDLE; \
} while(0)
@@ -303,7 +328,7 @@ struct vm_operations_struct blktap_vm_ops = {
*/
/*Function Declarations*/
-static int get_next_free_dev(void);
+static tap_blkif_t *get_next_free_dev(void);
static int blktap_open(struct inode *inode, struct file *filp);
static int blktap_release(struct inode *inode, struct file *filp);
static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -311,8 +336,6 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
static unsigned int blktap_poll(struct file *file, poll_table *wait);
-struct miscdevice *set_misc(int minor, char *name, int dev);
-
static struct file_operations blktap_fops = {
.owner = THIS_MODULE,
.poll = blktap_poll,
@@ -323,41 +346,96 @@ static struct file_operations blktap_fops = {
};
-static int get_next_free_dev(void)
+static tap_blkif_t *get_next_free_dev(void)
{
tap_blkif_t *info;
- int i = 0, ret = -1;
- unsigned long flags;
+ int minor;
- spin_lock_irqsave(&pending_free_lock, flags);
-
- while (i < MAX_TAP_DEV) {
- info = tapfds[i];
- if ( (tapfds[i] != NULL) && (info->dev_inuse == 0)
- && (info->dev_pending == 0) ) {
+ /*
+ * This is called only from the ioctl, which
+ * means we should always have interrupts enabled.
+ */
+ BUG_ON(irqs_disabled());
+
+ spin_lock_irq(&pending_free_lock);
+
+ /* tapfds[0] is always NULL */
+
+ for (minor = 1; minor < blktap_next_minor; minor++) {
+ info = tapfds[minor];
+ /* we could have failed a previous attempt. */
+ if (!info ||
+ ((info->dev_inuse == 0) &&
+ (info->dev_pending == 0)) ) {
info->dev_pending = 1;
- ret = i;
- goto done;
+ goto found;
}
- i++;
}
-
-done:
- spin_unlock_irqrestore(&pending_free_lock, flags);
- return ret;
+ info = NULL;
+ minor = -1;
+
+ /*
+ * We didn't find free device. If we can still allocate
+ * more, then we grab the next device minor that is
+ * available. This is done while we are still under
+ * the protection of the pending_free_lock.
+ */
+ if (blktap_next_minor < MAX_TAP_DEV)
+ minor = blktap_next_minor++;
+found:
+ spin_unlock_irq(&pending_free_lock);
+
+ if (!info && minor > 0) {
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (unlikely(!info)) {
+ /*
+ * If we failed here, try to put back
+ * the next minor number. But if one
+ * was just taken, then we just lose this
+ * minor. We can try to allocate this
+ * minor again later.
+ */
+ spin_lock_irq(&pending_free_lock);
+ if (blktap_next_minor == minor+1)
+ blktap_next_minor--;
+ spin_unlock_irq(&pending_free_lock);
+ goto out;
+ }
+
+ info->minor = minor;
+ /*
+ * Make sure that we have a minor before others can
+ * see us.
+ */
+ wmb();
+ tapfds[minor] = info;
+
+ class_device_create(xen_class, NULL,
+ MKDEV(blktap_major, minor), NULL,
+ "blktap%d", minor);
+ devfs_mk_cdev(MKDEV(blktap_major, minor),
+ S_IFCHR|S_IRUGO|S_IWUSR, "xen/blktap%d", minor);
+ }
+
+out:
+ return info;
}
int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif)
{
+ tap_blkif_t *info;
int i;
-
- for (i = 0; i < MAX_TAP_DEV; i++)
- if ( (translate_domid[i].domid == domid)
- && (translate_domid[i].busid == xenbus_id) ) {
- tapfds[i]->blkif = blkif;
- tapfds[i]->status = RUNNING;
+
+ for (i = 1; i < blktap_next_minor; i++) {
+ info = tapfds[i];
+ if ( info &&
+ (info->trans.domid == domid) &&
+ (info->trans.busid == xenbus_id) ) {
+ info->blkif = blkif;
+ info->status = RUNNING;
return i;
}
+ }
return -1;
}
@@ -367,13 +445,16 @@ void signal_tapdisk(int idx)
struct task_struct *ptask;
info = tapfds[idx];
- if ( (idx > 0) && (idx < MAX_TAP_DEV) && (info->pid > 0) ) {
+ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
+ return;
+
+ if (info->pid > 0) {
ptask = find_task_by_pid(info->pid);
- if (ptask) {
+ if (ptask)
info->status = CLEANSHUTDOWN;
- }
}
info->blkif = NULL;
+
return;
}
@@ -382,18 +463,22 @@ static int blktap_open(struct inode *inode, struct file *filp)
blkif_sring_t *sring;
int idx = iminor(inode) - BLKTAP_MINOR;
tap_blkif_t *info;
- private_info_t *prv;
int i;
- if (tapfds[idx] == NULL) {
+ /* ctrl device, treat differently */
+ if (!idx)
+ return 0;
+
+ info = tapfds[idx];
+
+ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) {
WPRINTK("Unable to open device /dev/xen/blktap%d\n",
- idx);
- return -ENOMEM;
+ idx);
+ return -ENODEV;
}
+
DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
- info = tapfds[idx];
-
/*Only one process can access device at a time*/
if (test_and_set_bit(0, &info->dev_inuse))
return -EBUSY;
@@ -410,9 +495,7 @@ static int blktap_open(struct inode *inode, struct file *filp)
SHARED_RING_INIT(sring);
FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
- prv = kzalloc(sizeof(private_info_t),GFP_KERNEL);
- prv->idx = idx;
- filp->private_data = prv;
+ filp->private_data = info;
info->vma = NULL;
info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS,
@@ -433,17 +516,14 @@ static int blktap_open(struct inode *inode, struct file *filp)
static int blktap_release(struct inode *inode, struct file *filp)
{
- int idx = iminor(inode) - BLKTAP_MINOR;
- tap_blkif_t *info;
+ tap_blkif_t *info = filp->private_data;
- if (tapfds[idx] == NULL) {
- WPRINTK("Trying to free device that doesn't exist "
- "[/dev/xen/blktap%d]\n",idx);
- return -1;
- }
- info = tapfds[idx];
+ /* check for control device */
+ if (!info)
+ return 0;
+
info->dev_inuse = 0;
- DPRINTK("Freeing device [/dev/xen/blktap%d]\n",idx);
+ DPRINTK("Freeing device [/dev/xen/blktap%d]\n",info->minor);
/* Free the ring page. */
ClearPageReserved(virt_to_page(info->ufe_ring.sring));
@@ -457,11 +537,11 @@ static int blktap_release(struct inode *inode, struct file *filp)
info->vma = NULL;
}
- if (filp->private_data) kfree(filp->private_data);
-
if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
- kthread_stop(info->blkif->xenblkd);
- info->blkif->xenblkd = NULL;
+ if (info->blkif->xenblkd != NULL) {
+ kthread_stop(info->blkif->xenblkd);
+ info->blkif->xenblkd = NULL;
+ }
info->status = CLEANSHUTDOWN;
}
return 0;
@@ -491,16 +571,12 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
int size;
struct page **map;
int i;
- private_info_t *prv;
- tap_blkif_t *info;
+ tap_blkif_t *info = filp->private_data;
- /*Retrieve the dev info*/
- prv = (private_info_t *)filp->private_data;
- if (prv == NULL) {
+ if (info == NULL) {
WPRINTK("blktap: mmap, retrieving idx failed\n");
return -ENOMEM;
}
- info = tapfds[prv->idx];
vma->vm_flags |= VM_RESERVED;
vma->vm_ops = &blktap_vm_ops;
@@ -517,8 +593,6 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
info->user_vstart = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
/* Map the ring pages to the start of the region and reserve it. */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
if (remap_pfn_range(vma, vma->vm_start,
__pa(info->ufe_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
@@ -556,20 +630,17 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
static int blktap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- int idx = iminor(inode) - BLKTAP_MINOR;
+ tap_blkif_t *info = filp->private_data;
+
switch(cmd) {
case BLKTAP_IOCTL_KICK_FE:
{
/* There are fe messages to process. */
- return blktap_read_ufe_ring(idx);
+ return blktap_read_ufe_ring(info);
}
case BLKTAP_IOCTL_SETMODE:
{
- tap_blkif_t *info = tapfds[idx];
-
- if ( (idx > 0) && (idx < MAX_TAP_DEV)
- && (tapfds[idx] != NULL) )
- {
+ if (info) {
if (BLKTAP_MODE_VALID(arg)) {
info->mode = arg;
/* XXX: may need to flush rings here. */
@@ -582,11 +653,7 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
}
case BLKTAP_IOCTL_PRINT_IDXS:
{
- tap_blkif_t *info = tapfds[idx];
-
- if ( (idx > 0) && (idx < MAX_TAP_DEV)
- && (tapfds[idx] != NULL) )
- {
+ if (info) {
printk("User Rings: \n-----------\n");
printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
"| req_prod: %2d, rsp_prod: %2d\n",
@@ -599,11 +666,7 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
}
case BLKTAP_IOCTL_SENDPID:
{
- tap_blkif_t *info = tapfds[idx];
-
- if ( (idx > 0) && (idx < MAX_TAP_DEV)
- && (tapfds[idx] != NULL) )
- {
+ if (info) {
info->pid = (pid_t)arg;
DPRINTK("blktap: pid received %d\n",
info->pid);
@@ -614,43 +677,49 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
{
uint64_t val = (uint64_t)arg;
domid_translate_t *tr = (domid_translate_t *)&val;
- int newdev;
DPRINTK("NEWINTF Req for domid %d and bus id %d\n",
tr->domid, tr->busid);
- newdev = get_next_free_dev();
- if (newdev < 1) {
+ info = get_next_free_dev();
+ if (!info) {
WPRINTK("Error initialising /dev/xen/blktap - "
"No more devices\n");
return -1;
}
- translate_domid[newdev].domid = tr->domid;
- translate_domid[newdev].busid = tr->busid;
- return newdev;
+ info->trans.domid = tr->domid;
+ info->trans.busid = tr->busid;
+ return info->minor;
}
case BLKTAP_IOCTL_FREEINTF:
{
unsigned long dev = arg;
- tap_blkif_t *info = NULL;
+ unsigned long flags;
+
+ info = tapfds[dev];
- if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
+ if ((dev > MAX_TAP_DEV) || !info)
+ return 0; /* should this be an error? */
- if ( (info != NULL) && (info->dev_pending) )
+ spin_lock_irqsave(&pending_free_lock, flags);
+ if (info->dev_pending)
info->dev_pending = 0;
+ spin_unlock_irqrestore(&pending_free_lock, flags);
+
return 0;
}
case BLKTAP_IOCTL_MINOR:
{
unsigned long dev = arg;
- tap_blkif_t *info = NULL;
-
- if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
-
- if (info != NULL) return info->minor;
- else return -1;
+
+ info = tapfds[dev];
+
+ if ((dev > MAX_TAP_DEV) || !info)
+ return -EINVAL;
+
+ return info->minor;
}
case BLKTAP_IOCTL_MAJOR:
- return BLKTAP_DEV_MAJOR;
+ return blktap_major;
case BLKTAP_QUERY_ALLOC_REQS:
{
@@ -662,25 +731,16 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
return -ENOIOCTLCMD;
}
-static unsigned int blktap_poll(struct file *file, poll_table *wait)
+static unsigned int blktap_poll(struct file *filp, poll_table *wait)
{
- private_info_t *prv;
- tap_blkif_t *info;
+ tap_blkif_t *info = filp->private_data;
- /*Retrieve the dev info*/
- prv = (private_info_t *)file->private_data;
- if (prv == NULL) {
- WPRINTK(" poll, retrieving idx failed\n");
+ /* do not work on the control device */
+ if (!info)
return 0;
- }
-
- if (prv->idx == 0) return 0;
-
- info = tapfds[prv->idx];
-
- poll_wait(file, &info->wait, wait);
+
+ poll_wait(filp, &info->wait, wait);
if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
- flush_tlb_all();
RING_PUSH_REQUESTS(&info->ufe_ring);
return POLLIN | POLLRDNORM;
}
@@ -691,11 +751,13 @@ void blktap_kick_user(int idx)
{
tap_blkif_t *info;
- if (idx == 0) return;
-
info = tapfds[idx];
-
- if (info != NULL) wake_up_interruptible(&info->wait);
+
+ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
+ return;
+
+ wake_up_interruptible(&info->wait);
+
return;
}
@@ -712,66 +774,21 @@ static void make_response(blkif_t *blkif, unsigned long id,
static int req_increase(void)
{
int i, j;
- struct page *page;
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&pending_free_lock, flags);
-
- ret = -EINVAL;
if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock)
- goto done;
-
-#ifdef __ia64__
- extern unsigned long alloc_empty_foreign_map_page_range(
- unsigned long pages);
- mmap_start[mmap_alloc].start = (unsigned long)
- alloc_empty_foreign_map_page_range(mmap_pages);
-#else /* ! ia64 */
- page = balloon_alloc_empty_page_range(mmap_pages);
- ret = -ENOMEM;
- if (page == NULL) {
- printk("%s balloon_alloc_empty_page_range gave NULL\n", __FUNCTION__);
- goto done;
- }
-
- /* Pin all of the pages. */
- for (i=0; i<mmap_pages; i++)
- get_page(&page[i]);
-
- mmap_start[mmap_alloc].start =
- (unsigned long)pfn_to_kaddr(page_to_pfn(page));
- mmap_start[mmap_alloc].mpage = page;
-
-#endif
-
- pending_reqs[mmap_alloc] = kzalloc(sizeof(pending_req_t) *
- blkif_reqs, GFP_KERNEL);
- pending_addrs[mmap_alloc] = kzalloc(sizeof(unsigned long) *
- mmap_pages, GFP_KERNEL);
-
- ret = -ENOMEM;
- if (!pending_reqs[mmap_alloc] || !pending_addrs[mmap_alloc]) {
- kfree(pending_reqs[mmap_alloc]);
- kfree(pending_addrs[mmap_alloc]);
- WPRINTK("%s: out of memory\n", __FUNCTION__);
- ret = -ENOMEM;
- goto done;
- }
-
- ret = 0;
+ return -EINVAL;
- DPRINTK("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
- __FUNCTION__, blkif_reqs, mmap_pages,
- mmap_start[mmap_alloc].start);
+ pending_reqs[mmap_alloc] = kzalloc(sizeof(pending_req_t)
+ * blkif_reqs, GFP_KERNEL);
+ foreign_pages[mmap_alloc] = alloc_empty_pages_and_pagevec(mmap_pages);
- BUG_ON(mmap_start[mmap_alloc].start == 0);
+ if (!pending_reqs[mmap_alloc] || !foreign_pages[mmap_alloc])
+ goto out_of_memory;
- for (i = 0; i < mmap_pages; i++)
- pending_addrs[mmap_alloc][i] =
- mmap_start[mmap_alloc].start + (i << PAGE_SHIFT);
+ DPRINTK("%s: reqs=%d, pages=%d\n",
+ __FUNCTION__, blkif_reqs, mmap_pages);
- for (i = 0; i < MAX_PENDING_REQS ; i++) {
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
list_add_tail(&pending_reqs[mmap_alloc][i].free_list,
&pending_free);
pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
@@ -782,67 +799,30 @@ static int req_increase(void)
mmap_alloc++;
DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
- done:
- spin_unlock_irqrestore(&pending_free_lock, flags);
- return ret;
+ return 0;
+
+ out_of_memory:
+ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
+ kfree(pending_reqs[mmap_alloc]);
+ WPRINTK("%s: out of memory\n", __FUNCTION__);
+ return -ENOMEM;
}
static void mmap_req_del(int mmap)
{
- int i;
- struct page *page;
+ BUG_ON(!spin_is_locked(&pending_free_lock));
- /*Spinlock already acquired*/
kfree(pending_reqs[mmap]);
- kfree(pending_addrs[mmap]);
-
-#ifdef __ia64__
- /*Not sure what goes here yet!*/
-#else
-
- /* Unpin all of the pages. */
- page = mmap_start[mmap].mpage;
- for (i=0; i<mmap_pages; i++)
- put_page(&page[i]);
+ pending_reqs[mmap] = NULL;
- balloon_dealloc_empty_page_range(mmap_start[mmap].mpage, mmap_pages);
-#endif
+ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
+ foreign_pages[mmap] = NULL;
mmap_lock = 0;
DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
mmap_alloc--;
}
-/*N.B. Currently unused - will be accessed via sysfs*/
-static void req_decrease(void)
-{
- pending_req_t *req;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&pending_free_lock, flags);
-
- DPRINTK("Req decrease called.\n");
- if (mmap_lock || mmap_alloc == 1)
- goto done;
-
- mmap_lock = 1;
- mmap_inuse = MAX_PENDING_REQS;
-
- /*Go through reqs and remove any that aren't in use*/
- for (i = 0; i < MAX_PENDING_REQS ; i++) {
- req = &pending_reqs[mmap_alloc-1][i];
- if (req->inuse == 0) {
- list_del(&req->free_list);
- mmap_inuse--;
- }
- }
- if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
- done:
- spin_unlock_irqrestore(&pending_free_lock, flags);
- return;
-}
-
static pending_req_t* alloc_req(void)
{
pending_req_t *req = NULL;
@@ -888,8 +868,8 @@ static void free_req(pending_req_t *req)
wake_up(&pending_free_wq);
}
-static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int
- tapidx)
+static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx,
+ int tapidx)
{
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
unsigned int i, invcount = 0;
@@ -897,49 +877,65 @@ static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int
uint64_t ptep;
int ret, mmap_idx;
unsigned long kvaddr, uvaddr;
-
- tap_blkif_t *info = tapfds[tapidx];
+ tap_blkif_t *info;
- if (info == NULL) {
+
+ info = tapfds[tapidx];
+
+ if ((tapidx < 0) || (tapidx > MAX_TAP_DEV) || !info) {
WPRINTK("fast_flush: Couldn't get info!\n");
return;
}
+
+ if (info->vma != NULL &&
+ xen_feature(XENFEAT_auto_translated_physmap)) {
+ down_write(&info->vma->vm_mm->mmap_sem);
+ zap_page_range(info->vma,
+ MMAP_VADDR(info->user_vstart, u_idx, 0),
+ req->nr_pages << PAGE_SHIFT, NULL);
+ up_write(&info->vma->vm_mm->mmap_sem);
+ }
+
mmap_idx = req->mem_idx;
for (i = 0; i < req->nr_pages; i++) {
- kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i);
+ kvaddr = idx_to_kaddr(mmap_idx, k_idx, i);
uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
khandle = &pending_handle(mmap_idx, k_idx, i);
- if (BLKTAP_INVALID_HANDLE(khandle)) {
- WPRINTK("BLKTAP_INVALID_HANDLE\n");
- continue;
+
+ if (khandle->kernel != INVALID_GRANT_HANDLE) {
+ gnttab_set_unmap_op(&unmap[invcount],
+ idx_to_kaddr(mmap_idx, k_idx, i),
+ GNTMAP_host_map, khandle->kernel);
+ invcount++;
}
- gnttab_set_unmap_op(&unmap[invcount],
- MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i),
- GNTMAP_host_map, khandle->kernel);
- invcount++;
-
- if (create_lookup_pte_addr(
- info->vma->vm_mm,
- MMAP_VADDR(info->user_vstart, u_idx, i),
- &ptep) !=0) {
- WPRINTK("Couldn't get a pte addr!\n");
- return;
+
+ if (khandle->user != INVALID_GRANT_HANDLE) {
+ BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
+ if (create_lookup_pte_addr(
+ info->vma->vm_mm,
+ MMAP_VADDR(info->user_vstart, u_idx, i),
+ &ptep) !=0) {
+ WPRINTK("Couldn't get a pte addr!\n");
+ return;
+ }
+
+ gnttab_set_unmap_op(&unmap[invcount], ptep,
+ GNTMAP_host_map
+ | GNTMAP_application_map
+ | GNTMAP_contains_pte,
+ khandle->user);
+ invcount++;
}
- gnttab_set_unmap_op(&unmap[invcount],
- ptep, GNTMAP_host_map,
- khandle->user);
- invcount++;
-
BLKTAP_INVALIDATE_HANDLE(khandle);
}
ret = HYPERVISOR_grant_table_op(
GNTTABOP_unmap_grant_ref, unmap, invcount);
BUG_ON(ret);
- if (info->vma != NULL)
+ if (info->vma != NULL && !xen_feature(XENFEAT_auto_translated_physmap))
zap_page_range(info->vma,
MMAP_VADDR(info->user_vstart, u_idx, 0),
req->nr_pages << PAGE_SHIFT, NULL);
@@ -1002,7 +998,7 @@ int tap_blkif_schedule(void *arg)
* COMPLETION CALLBACK -- Called by user level ioctl()
*/
-static int blktap_read_ufe_ring(int idx)
+static int blktap_read_ufe_ring(tap_blkif_t *info)
{
/* This is called to read responses from the UFE ring. */
RING_IDX i, j, rp;
@@ -1010,12 +1006,9 @@ static int blktap_read_ufe_ring(int idx)
blkif_t *blkif=NULL;
int pending_idx, usr_idx, mmap_idx;
pending_req_t *pending_req;
- tap_blkif_t *info;
- info = tapfds[idx];
- if (info == NULL) {
+ if (!info)
return 0;
- }
/* We currently only forward packets in INTERCEPT_FE mode. */
if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
@@ -1026,11 +1019,14 @@ static int blktap_read_ufe_ring(int idx)
rmb();
for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
+ blkif_response_t res;
resp = RING_GET_RESPONSE(&info->ufe_ring, i);
+ memcpy(&res, resp, sizeof(res));
+ mb(); /* rsp_cons read by RING_FULL() in do_block_io_op(). */
++info->ufe_ring.rsp_cons;
/*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
- usr_idx = (int)resp->id;
+ usr_idx = (int)res.id;
pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
@@ -1053,9 +1049,8 @@ static int blktap_read_ufe_ring(int idx)
struct page *pg;
int offset;
- uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j);
- kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start,
- pending_idx, j);
+ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j);
+ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, j);
pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
ClearPageReserved(pg);
@@ -1063,10 +1058,10 @@ static int blktap_read_ufe_ring(int idx)
>> PAGE_SHIFT;
map[offset] = NULL;
}
- fast_flush_area(pending_req, pending_idx, usr_idx, idx);
- make_response(blkif, pending_req->id, resp->operation,
- resp->status);
+ fast_flush_area(pending_req, pending_idx, usr_idx, info->minor);
info->idx_map[usr_idx] = INVALID_REQ;
+ make_response(blkif, pending_req->id, res.operation,
+ res.status);
blkif_put(pending_req->blkif);
free_req(pending_req);
}
@@ -1100,7 +1095,7 @@ static int print_dbug = 1;
static int do_block_io_op(blkif_t *blkif)
{
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
- blkif_request_t *req;
+ blkif_request_t req;
pending_req_t *pending_req;
RING_IDX rc, rp;
int more_to_do = 0;
@@ -1111,7 +1106,7 @@ static int do_block_io_op(blkif_t *blkif)
rmb(); /* Ensure we see queued requests up to 'rp'. */
/*Check blkif has corresponding UE ring*/
- if (blkif->dev_num == -1) {
+ if (blkif->dev_num < 0) {
/*oops*/
if (print_dbug) {
WPRINTK("Corresponding UE "
@@ -1122,7 +1117,8 @@ static int do_block_io_op(blkif_t *blkif)
}
info = tapfds[blkif->dev_num];
- if (info == NULL || !info->dev_inuse) {
+
+ if (blkif->dev_num > MAX_TAP_DEV || !info || !info->dev_inuse) {
if (print_dbug) {
WPRINTK("Can't get UE info!\n");
print_dbug = 0;
@@ -1152,24 +1148,24 @@ static int do_block_io_op(blkif_t *blkif)
break;
}
- req = RING_GET_REQUEST(blk_ring, rc);
+ memcpy(&req, RING_GET_REQUEST(blk_ring, rc), sizeof(req));
blk_ring->req_cons = ++rc; /* before make_response() */
- switch (req->operation) {
+ switch (req.operation) {
case BLKIF_OP_READ:
blkif->st_rd_req++;
- dispatch_rw_block_io(blkif, req, pending_req);
+ dispatch_rw_block_io(blkif, &req, pending_req);
break;
case BLKIF_OP_WRITE:
blkif->st_wr_req++;
- dispatch_rw_block_io(blkif, req, pending_req);
+ dispatch_rw_block_io(blkif, &req, pending_req);
break;
default:
WPRINTK("unknown operation [%d]\n",
- req->operation);
- make_response(blkif, req->id, req->operation,
+ req.operation);
+ make_response(blkif, req.id, req.operation,
BLKIF_RSP_ERROR);
free_req(pending_req);
break;
@@ -1190,17 +1186,27 @@ static void dispatch_rw_block_io(blkif_t *blkif,
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
unsigned int nseg;
int ret, i;
- tap_blkif_t *info = tapfds[blkif->dev_num];
+ tap_blkif_t *info;
uint64_t sector;
-
blkif_request_t *target;
int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
- int usr_idx = GET_NEXT_REQ(info->idx_map);
+ int usr_idx;
uint16_t mmap_idx = pending_req->mem_idx;
- /*Check we have space on user ring - should never fail*/
- if(usr_idx == INVALID_REQ) goto fail_flush;
-
+ if (blkif->dev_num < 0 || blkif->dev_num > MAX_TAP_DEV)
+ goto fail_response;
+
+ info = tapfds[blkif->dev_num];
+ if (info == NULL)
+ goto fail_response;
+
+ /* Check we have space on user ring - should never fail. */
+ usr_idx = GET_NEXT_REQ(info->idx_map);
+ if (usr_idx == INVALID_REQ) {
+ BUG();
+ goto fail_response;
+ }
+
/* Check that number of segments is sane. */
nseg = req->nr_segments;
if ( unlikely(nseg == 0) ||
@@ -1233,15 +1239,12 @@ static void dispatch_rw_block_io(blkif_t *blkif,
unsigned long uvaddr;
unsigned long kvaddr;
uint64_t ptep;
- struct page *page;
uint32_t flags;
uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
- kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start,
- pending_idx, i);
- page = virt_to_page(kvaddr);
+ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
- sector = req->sector_number + (8*i);
+ sector = req->sector_number + ((PAGE_SIZE / 512) * i);
if( (blkif->sectors > 0) && (sector >= blkif->sectors) ) {
WPRINTK("BLKTAP: Sector request greater"
"than size\n");
@@ -1251,7 +1254,7 @@ static void dispatch_rw_block_io(blkif_t *blkif,
BLKIF_OP_WRITE ? "WRITE" : "READ"),
(long long unsigned) sector,
(long long unsigned) sector>>9,
- blkif->sectors);
+ (long long unsigned) blkif->sectors);
}
flags = GNTMAP_host_map;
@@ -1261,71 +1264,123 @@ static void dispatch_rw_block_io(blkif_t *blkif,
req->seg[i].gref, blkif->domid);
op++;
- /* Now map it to user. */
- ret = create_lookup_pte_addr(info->vma->vm_mm,
- uvaddr, &ptep);
- if (ret) {
- WPRINTK("Couldn't get a pte addr!\n");
- fast_flush_area(pending_req, pending_idx, usr_idx,
- blkif->dev_num);
- goto fail_flush;
- }
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Now map it to user. */
+ ret = create_lookup_pte_addr(info->vma->vm_mm,
+ uvaddr, &ptep);
+ if (ret) {
+ WPRINTK("Couldn't get a pte addr!\n");
+ goto fail_flush;
+ }
- flags = GNTMAP_host_map | GNTMAP_application_map
- | GNTMAP_contains_pte;
- if (operation == WRITE)
- flags |= GNTMAP_readonly;
- gnttab_set_map_op(&map[op], ptep, flags,
- req->seg[i].gref, blkif->domid);
- op++;
+ flags = GNTMAP_host_map | GNTMAP_application_map
+ | GNTMAP_contains_pte;
+ if (operation == WRITE)
+ flags |= GNTMAP_readonly;
+ gnttab_set_map_op(&map[op], ptep, flags,
+ req->seg[i].gref, blkif->domid);
+ op++;
+ }
}
ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
BUG_ON(ret);
- for (i = 0; i < (nseg*2); i+=2) {
- unsigned long uvaddr;
- unsigned long kvaddr;
- unsigned long offset;
- struct page *pg;
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ for (i = 0; i < (nseg*2); i+=2) {
+ unsigned long uvaddr;
+ unsigned long kvaddr;
+ unsigned long offset;
+ struct page *pg;
- uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
- kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start,
- pending_idx, i/2);
+ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
+ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i/2);
- if (unlikely(map[i].status != 0)) {
- WPRINTK("invalid kernel buffer -- "
- "could not remap it\n");
- goto fail_flush;
- }
+ if (unlikely(map[i].status != 0)) {
+ WPRINTK("invalid kernel buffer -- "
+ "could not remap it\n");
+ ret |= 1;
+ map[i].handle = INVALID_GRANT_HANDLE;
+ }
- if (unlikely(map[i+1].status != 0)) {
- WPRINTK("invalid user buffer -- "
- "could not remap it\n");
- goto fail_flush;
+ if (unlikely(map[i+1].status != 0)) {
+ WPRINTK("invalid user buffer -- "
+ "could not remap it\n");
+ ret |= 1;
+ map[i+1].handle = INVALID_GRANT_HANDLE;
+ }
+
+ pending_handle(mmap_idx, pending_idx, i/2).kernel
+ = map[i].handle;
+ pending_handle(mmap_idx, pending_idx, i/2).user
+ = map[i+1].handle;
+
+ if (ret)
+ continue;
+
+ set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
+ FOREIGN_FRAME(map[i].dev_bus_addr
+ >> PAGE_SHIFT));
+ offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
+ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+ ((struct page **)info->vma->vm_private_data)[offset] =
+ pg;
}
+ } else {
+ for (i = 0; i < nseg; i++) {
+ unsigned long uvaddr;
+ unsigned long kvaddr;
+ unsigned long offset;
+ struct page *pg;
- pending_handle(mmap_idx, pending_idx, i/2).kernel
- = map[i].handle;
- pending_handle(mmap_idx, pending_idx, i/2).user
- = map[i+1].handle;
- set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
- FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
- offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
- pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
- ((struct page **)info->vma->vm_private_data)[offset] =
- pg;
+ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
+ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
+
+ if (unlikely(map[i].status != 0)) {
+ WPRINTK("invalid kernel buffer -- "
+ "could not remap it\n");
+ ret |= 1;
+ map[i].handle = INVALID_GRANT_HANDLE;
+ }
+
+ pending_handle(mmap_idx, pending_idx, i).kernel
+ = map[i].handle;
+
+ if (ret)
+ continue;
+
+ offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
+ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+ ((struct page **)info->vma->vm_private_data)[offset] =
+ pg;
+ }
}
+
+ if (ret)
+ goto fail_flush;
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ down_write(&info->vma->vm_mm->mmap_sem);
/* Mark mapped pages as reserved: */
for (i = 0; i < req->nr_segments; i++) {
unsigned long kvaddr;
struct page *pg;
- kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start,
- pending_idx, i);
+ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
SetPageReserved(pg);
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ ret = vm_insert_page(info->vma,
+ MMAP_VADDR(info->user_vstart,
+ usr_idx, i), pg);
+ if (ret) {
+ up_write(&info->vma->vm_mm->mmap_sem);
+ goto fail_flush;
+ }
+ }
}
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ up_write(&info->vma->vm_mm->mmap_sem);
/*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
@@ -1336,6 +1391,7 @@ static void dispatch_rw_block_io(blkif_t *blkif,
info->ufe_ring.req_prod_pvt);
memcpy(target, req, sizeof(*req));
target->id = usr_idx;
+ wmb(); /* blktap_poll() reads req_prod_pvt asynchronously */
info->ufe_ring.req_prod_pvt++;
return;
@@ -1393,7 +1449,6 @@ static void make_response(blkif_t *blkif, unsigned long id,
static int __init blkif_init(void)
{
int i,ret,blktap_dir;
- tap_blkif_t *info;
if (!is_running_on_xen())
return -ENODEV;
@@ -1413,10 +1468,8 @@ static int __init blkif_init(void)
tap_blkif_xenbus_init();
- /*Create the blktap devices, but do not map memory or waitqueue*/
- for(i = 0; i < MAX_TAP_DEV; i++) translate_domid[i].domid = 0xFFFF;
-
- ret = register_chrdev(BLKTAP_DEV_MAJOR,"blktap",&blktap_fops);
+ /* Dynamically allocate a major for this device */
+ ret = register_chrdev(0, "blktap", &blktap_fops);
blktap_dir = devfs_mk_dir(NULL, "xen", 0, NULL);
if ( (ret < 0)||(blktap_dir < 0) ) {
@@ -1424,22 +1477,36 @@ static int __init blkif_init(void)
return -ENOMEM;
}
- for(i = 0; i < MAX_TAP_DEV; i++ ) {
- info = tapfds[i] = kzalloc(sizeof(tap_blkif_t),GFP_KERNEL);
- if(tapfds[i] == NULL) return -ENOMEM;
- info->minor = i;
- info->pid = 0;
- info->blkif = NULL;
+ blktap_major = ret;
- ret = devfs_mk_cdev(MKDEV(BLKTAP_DEV_MAJOR, i),
- S_IFCHR|S_IRUGO|S_IWUSR, "xen/blktap%d", i);
+ /* tapfds[0] is always NULL */
+ blktap_next_minor++;
- if(ret != 0) return -ENOMEM;
- info->dev_pending = info->dev_inuse = 0;
+ ret = devfs_mk_cdev(MKDEV(blktap_major, i),
+ S_IFCHR|S_IRUGO|S_IWUSR, "xen/blktap%d", i);
- DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
+ if(ret != 0)
+ return -ENOMEM;
+
+ DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
+
+ /* Make sure the xen class exists */
+ if (!setup_xen_class()) {
+ /*
+ * This will allow udev to create the blktap ctrl device.
+ * We only want to create blktap0 first. We don't want
+ * to flood the sysfs system with needless blktap devices.
+ * We only create the device when a request of a new device is
+ * made.
+ */
+ class_device_create(xen_class, NULL,
+ MKDEV(blktap_major, 0), NULL,
+ "blktap0");
+ } else {
+ /* this is bad, but not fatal */
+ WPRINTK("blktap: sysfs xen_class not created\n");
}
-
+
DPRINTK("Blktap device successfully created\n");
return 0;
diff --git a/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c
index 6c16a2e60b..553ad45c48 100644
--- a/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c
@@ -189,7 +189,7 @@ static int blktap_probe(struct xenbus_device *dev,
return 0;
fail:
- DPRINTK("blktap probe failed");
+ DPRINTK("blktap probe failed\n");
blktap_remove(dev);
return err;
}
@@ -243,7 +243,7 @@ static void tap_frontend_changed(struct xenbus_device *dev,
struct backend_info *be = dev->dev.driver_data;
int err;
- DPRINTK("");
+ DPRINTK("\n");
switch (frontend_state) {
case XenbusStateInitialising:
@@ -273,7 +273,6 @@ static void tap_frontend_changed(struct xenbus_device *dev,
kthread_stop(be->blkif->xenblkd);
be->blkif->xenblkd = NULL;
}
- tap_blkif_unmap(be->blkif);
xenbus_switch_state(dev, XenbusStateClosing);
break;
@@ -319,7 +318,7 @@ static int connect_ring(struct backend_info *be)
unsigned int evtchn;
int err;
- DPRINTK("%s", dev->otherend);
+ DPRINTK("%s\n", dev->otherend);
err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
&ring_ref, "event-channel", "%u", &evtchn, NULL);
diff --git a/linux-2.6-xen-sparse/drivers/xen/char/mem.c b/linux-2.6-xen-sparse/drivers/xen/char/mem.c
index 6576135c99..ac85c8dbb2 100644
--- a/linux-2.6-xen-sparse/drivers/xen/char/mem.c
+++ b/linux-2.6-xen-sparse/drivers/xen/char/mem.c
@@ -28,13 +28,12 @@
#include <asm/io.h>
#include <asm/hypervisor.h>
-static inline int uncached_access(struct file *file)
+#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
+static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
{
- if (file->f_flags & O_SYNC)
- return 1;
- /* Xen sets correct MTRR type on non-RAM for us. */
- return 0;
+ return 1;
}
+#endif
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
@@ -47,6 +46,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,
ssize_t read = 0, sz;
void __iomem *v;
+ if (!valid_phys_addr_range(p, &count))
+ return -EFAULT;
+
while (count > 0) {
/*
* Handle first page in case it's not aligned
@@ -58,13 +60,15 @@ static ssize_t read_mem(struct file * file, char __user * buf,
sz = min_t(unsigned long, sz, count);
- if ((v = ioremap(p, sz)) == NULL) {
+ v = xlate_dev_mem_ptr(p, sz);
+ if (IS_ERR(v) || v == NULL) {
/*
- * Some programs (e.g., dmidecode) groove off into weird RAM
- * areas where no tables can possibly exist (because Xen will
- * have stomped on them!). These programs get rather upset if
- * we let them know that Xen failed their access, so we fake
- * out a read of all zeroes. :-)
+ * Some programs (e.g., dmidecode) groove off into
+ * weird RAM areas where no tables can possibly exist
+ * (because Xen will have stomped on them!). These
+ * programs get rather upset if we let them know that
+ * Xen failed their access, so we fake out a read of
+ * all zeroes.
*/
if (clear_user(buf, count))
return -EFAULT;
@@ -73,7 +77,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
}
ignored = copy_to_user(buf, v, sz);
- iounmap(v);
+ xlate_dev_mem_ptr_unmap(v);
if (ignored)
return -EFAULT;
buf += sz;
@@ -93,6 +97,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
ssize_t written = 0, sz;
void __iomem *v;
+ if (!valid_phys_addr_range(p, &count))
+ return -EFAULT;
+
while (count > 0) {
/*
* Handle first page in case it's not aligned
@@ -104,11 +111,17 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
sz = min_t(unsigned long, sz, count);
- if ((v = ioremap(p, sz)) == NULL)
+ v = xlate_dev_mem_ptr(p, sz);
+ if (v == NULL)
break;
+ if (IS_ERR(v)) {
+ if (written == 0)
+ return PTR_ERR(v);
+ break;
+ }
ignored = copy_from_user(v, buf, sz);
- iounmap(v);
+ xlate_dev_mem_ptr_unmap(v);
if (ignored) {
written += sz - ignored;
if (written)
@@ -125,6 +138,15 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return written;
}
+#ifndef ARCH_HAS_DEV_MEM_MMAP_MEM
+static inline int uncached_access(struct file *file)
+{
+ if (file->f_flags & O_SYNC)
+ return 1;
+ /* Xen sets correct MTRR type on non-RAM for us. */
+ return 0;
+}
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
@@ -136,6 +158,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
size, vma->vm_page_prot, DOMID_IO);
}
+#endif
/*
* The memory devices use the full 32/64 bits of the offset, and so we cannot
diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c
index a45d21a69c..ff3e2a411e 100644
--- a/linux-2.6-xen-sparse/drivers/xen/console/console.c
+++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c
@@ -49,6 +49,7 @@
#include <linux/console.h>
#include <linux/bootmem.h>
#include <linux/sysrq.h>
+#include <linux/screen_info.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -266,6 +267,41 @@ void xencons_force_flush(void)
}
+void dom0_init_screen_info(const struct dom0_vga_console_info *info)
+{
+ switch (info->video_type) {
+ case XEN_VGATYPE_TEXT_MODE_3:
+ screen_info.orig_video_mode = 3;
+ screen_info.orig_video_ega_bx = 3;
+ screen_info.orig_video_isVGA = 1;
+ screen_info.orig_video_lines = info->u.text_mode_3.rows;
+ screen_info.orig_video_cols = info->u.text_mode_3.columns;
+ screen_info.orig_x = info->u.text_mode_3.cursor_x;
+ screen_info.orig_y = info->u.text_mode_3.cursor_y;
+ screen_info.orig_video_points =
+ info->u.text_mode_3.font_height;
+ break;
+ case XEN_VGATYPE_VESA_LFB:
+ screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
+ screen_info.lfb_width = info->u.vesa_lfb.width;
+ screen_info.lfb_height = info->u.vesa_lfb.height;
+ screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
+ screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
+ screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
+ screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
+ screen_info.red_size = info->u.vesa_lfb.red_size;
+ screen_info.red_pos = info->u.vesa_lfb.red_pos;
+ screen_info.green_size = info->u.vesa_lfb.green_size;
+ screen_info.green_pos = info->u.vesa_lfb.green_pos;
+ screen_info.blue_size = info->u.vesa_lfb.blue_size;
+ screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
+ screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
+ screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
+ break;
+ }
+}
+
+
/******************** User-space console driver (/dev/console) ************/
#define DRV(_d) (_d)
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/Makefile b/linux-2.6-xen-sparse/drivers/xen/core/Makefile
index c1b0c1bd51..6154454339 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/Makefile
+++ b/linux-2.6-xen-sparse/drivers/xen/core/Makefile
@@ -9,5 +9,5 @@ obj-$(CONFIG_SYSFS) += hypervisor_sysfs.o
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_SYSFS) += xen_sysfs.o
obj-$(CONFIG_XEN_SKBUFF) += skbuff.o
-obj-$(CONFIG_XEN_REBOOT) += reboot.o
+obj-$(CONFIG_XEN_REBOOT) += reboot.o machine_reboot.o
obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/features.c b/linux-2.6-xen-sparse/drivers/xen/core/features.c
index 4d50caf50b..a76f58c04d 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/features.c
+++ b/linux-2.6-xen-sparse/drivers/xen/core/features.c
@@ -11,6 +11,10 @@
#include <asm/hypervisor.h>
#include <xen/features.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
EXPORT_SYMBOL(xen_features);
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
index 3195279a87..c5132c13bb 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
+++ b/linux-2.6-xen-sparse/drivers/xen/core/gnttab.c
@@ -44,6 +44,10 @@
#include <asm/io.h>
#include <xen/interface/memory.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
/* External tools reserve first few grant table entries. */
#define NR_RESERVED_ENTRIES 8
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
new file mode 100644
index 0000000000..02ee7f4728
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
@@ -0,0 +1,185 @@
+#define __KERNEL_SYSCALLS__
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/unistd.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/stringify.h>
+#include <asm/irq.h>
+#include <asm/mmu_context.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/interface/dom0_ops.h>
+#include <xen/xenbus.h>
+#include <linux/cpu.h>
+#include <linux/kthread.h>
+#include <xen/gnttab.h>
+#include <xen/xencons.h>
+#include <xen/cpu_hotplug.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_emergency_restart(void)
+{
+ /* We really want to get pending console data out before we die. */
+ xencons_force_flush();
+ HYPERVISOR_shutdown(SHUTDOWN_reboot);
+}
+
+void machine_restart(char * __unused)
+{
+ machine_emergency_restart();
+}
+
+void machine_halt(void)
+{
+ machine_power_off();
+}
+
+void machine_power_off(void)
+{
+ /* We really want to get pending console data out before we die. */
+ xencons_force_flush();
+ if (pm_power_off)
+ pm_power_off();
+ HYPERVISOR_shutdown(SHUTDOWN_poweroff);
+}
+
+int reboot_thru_bios = 0; /* for dmi_scan.c */
+EXPORT_SYMBOL(machine_restart);
+EXPORT_SYMBOL(machine_halt);
+EXPORT_SYMBOL(machine_power_off);
+
+/* Ensure we run on the idle task page tables so that we will
+ switch page tables before running user space. This is needed
+ on architectures with separate kernel and user page tables
+ because the user page table pointer is not saved/restored. */
+static void switch_idle_mm(void)
+{
+ struct mm_struct *mm = current->active_mm;
+
+ if (mm == &init_mm)
+ return;
+
+ atomic_inc(&init_mm.mm_count);
+ switch_mm(mm, &init_mm, current);
+ current->active_mm = &init_mm;
+ mmdrop(mm);
+}
+
+static void pre_suspend(void)
+{
+ HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
+ clear_fixmap(FIX_SHARED_INFO);
+
+ xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
+ xen_start_info->console.domU.mfn =
+ mfn_to_pfn(xen_start_info->console.domU.mfn);
+}
+
+static void post_suspend(void)
+{
+ int i, j, k, fpp;
+ extern unsigned long max_pfn;
+ extern unsigned long *pfn_to_mfn_frame_list_list;
+ extern unsigned long *pfn_to_mfn_frame_list[];
+
+ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
+
+ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
+
+ memset(empty_zero_page, 0, PAGE_SIZE);
+
+ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
+ virt_to_mfn(pfn_to_mfn_frame_list_list);
+
+ fpp = PAGE_SIZE/sizeof(unsigned long);
+ for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
+ if ((j % fpp) == 0) {
+ k++;
+ pfn_to_mfn_frame_list_list[k] =
+ virt_to_mfn(pfn_to_mfn_frame_list[k]);
+ j = 0;
+ }
+ pfn_to_mfn_frame_list[k][j] =
+ virt_to_mfn(&phys_to_machine_mapping[i]);
+ }
+ HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
+}
+
+#else /* !(defined(__i386__) || defined(__x86_64__)) */
+
+#define switch_idle_mm() ((void)0)
+#define mm_pin_all() ((void)0)
+#define pre_suspend() ((void)0)
+#define post_suspend() ((void)0)
+
+#endif
+
+int __xen_suspend(void)
+{
+ int err;
+
+ extern void time_resume(void);
+
+ BUG_ON(smp_processor_id() != 0);
+ BUG_ON(in_interrupt());
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (xen_feature(XENFEAT_auto_translated_physmap)) {
+ printk(KERN_WARNING "Cannot suspend in "
+ "auto_translated_physmap mode.\n");
+ return -EOPNOTSUPP;
+ }
+#endif
+
+ err = smp_suspend();
+ if (err)
+ return err;
+
+ xenbus_suspend();
+
+ preempt_disable();
+
+ mm_pin_all();
+ local_irq_disable();
+ preempt_enable();
+
+ gnttab_suspend();
+
+ pre_suspend();
+
+ /*
+ * We'll stop somewhere inside this hypercall. When it returns,
+ * we'll start resuming after the restore.
+ */
+ HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
+
+ post_suspend();
+
+ gnttab_resume();
+
+ irq_resume();
+
+ time_resume();
+
+ switch_idle_mm();
+
+ local_irq_enable();
+
+ xencons_resume();
+
+ xenbus_resume();
+
+ smp_resume();
+
+ return err;
+}
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c
index 34c3930961..af3fe3a15c 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c
+++ b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c
@@ -1,25 +1,15 @@
#define __KERNEL_SYSCALLS__
#include <linux/version.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/sysrq.h>
-#include <linux/stringify.h>
-#include <asm/irq.h>
-#include <asm/mmu_context.h>
-#include <xen/evtchn.h>
#include <asm/hypervisor.h>
-#include <xen/interface/dom0_ops.h>
#include <xen/xenbus.h>
-#include <linux/cpu.h>
#include <linux/kthread.h>
-#include <xen/gnttab.h>
-#include <xen/xencons.h>
-#include <xen/cpu_hotplug.h>
-extern void ctrl_alt_del(void);
+MODULE_LICENSE("Dual BSD/GPL");
#define SHUTDOWN_INVALID -1
#define SHUTDOWN_POWEROFF 0
@@ -31,186 +21,18 @@ extern void ctrl_alt_del(void);
*/
#define SHUTDOWN_HALT 4
-#if defined(__i386__) || defined(__x86_64__)
-
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void machine_emergency_restart(void)
-{
- /* We really want to get pending console data out before we die. */
- xencons_force_flush();
- HYPERVISOR_shutdown(SHUTDOWN_reboot);
-}
-
-void machine_restart(char * __unused)
-{
- machine_emergency_restart();
-}
-
-void machine_halt(void)
-{
- machine_power_off();
-}
-
-void machine_power_off(void)
-{
- /* We really want to get pending console data out before we die. */
- xencons_force_flush();
- if (pm_power_off)
- pm_power_off();
- HYPERVISOR_shutdown(SHUTDOWN_poweroff);
-}
-
-int reboot_thru_bios = 0; /* for dmi_scan.c */
-EXPORT_SYMBOL(machine_restart);
-EXPORT_SYMBOL(machine_halt);
-EXPORT_SYMBOL(machine_power_off);
-
-#endif /* defined(__i386__) || defined(__x86_64__) */
-
-/******************************************************************************
- * Stop/pickle callback handling.
- */
-
/* Ignore multiple shutdown requests. */
static int shutting_down = SHUTDOWN_INVALID;
+
static void __shutdown_handler(void *unused);
static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
-#if defined(__i386__) || defined(__x86_64__)
-
-/* Ensure we run on the idle task page tables so that we will
- switch page tables before running user space. This is needed
- on architectures with separate kernel and user page tables
- because the user page table pointer is not saved/restored. */
-static void switch_idle_mm(void)
-{
- struct mm_struct *mm = current->active_mm;
-
- if (mm == &init_mm)
- return;
-
- atomic_inc(&init_mm.mm_count);
- switch_mm(mm, &init_mm, current);
- current->active_mm = &init_mm;
- mmdrop(mm);
-}
-
-static void pre_suspend(void)
-{
- HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
- clear_fixmap(FIX_SHARED_INFO);
-
- xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
- xen_start_info->console.domU.mfn =
- mfn_to_pfn(xen_start_info->console.domU.mfn);
-}
-
-static void post_suspend(void)
-{
- int i, j, k, fpp;
- extern unsigned long max_pfn;
- extern unsigned long *pfn_to_mfn_frame_list_list;
- extern unsigned long *pfn_to_mfn_frame_list[];
-
- set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
-
- HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
-
- memset(empty_zero_page, 0, PAGE_SIZE);
-
- HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
- virt_to_mfn(pfn_to_mfn_frame_list_list);
-
- fpp = PAGE_SIZE/sizeof(unsigned long);
- for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
- if ((j % fpp) == 0) {
- k++;
- pfn_to_mfn_frame_list_list[k] =
- virt_to_mfn(pfn_to_mfn_frame_list[k]);
- j = 0;
- }
- pfn_to_mfn_frame_list[k][j] =
- virt_to_mfn(&phys_to_machine_mapping[i]);
- }
- HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
-}
-
-#else /* !(defined(__i386__) || defined(__x86_64__)) */
-
-#define switch_idle_mm() ((void)0)
-#define mm_pin_all() ((void)0)
-#define pre_suspend() ((void)0)
-#define post_suspend() ((void)0)
-
-#endif
-
-static int __do_suspend(void *ignore)
-{
- int err;
-
- extern void time_resume(void);
-
- BUG_ON(smp_processor_id() != 0);
- BUG_ON(in_interrupt());
-
-#if defined(__i386__) || defined(__x86_64__)
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- printk(KERN_WARNING "Cannot suspend in "
- "auto_translated_physmap mode.\n");
- return -EOPNOTSUPP;
- }
+#ifdef CONFIG_XEN
+int __xen_suspend(void);
+#else
+#define __xen_suspend() (void)0
#endif
- err = smp_suspend();
- if (err)
- return err;
-
- xenbus_suspend();
-
- preempt_disable();
-
- mm_pin_all();
- local_irq_disable();
- preempt_enable();
-
- gnttab_suspend();
-
- pre_suspend();
-
- /*
- * We'll stop somewhere inside this hypercall. When it returns,
- * we'll start resuming after the restore.
- */
- HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
-
- shutting_down = SHUTDOWN_INVALID;
-
- post_suspend();
-
- gnttab_resume();
-
- irq_resume();
-
- time_resume();
-
- switch_idle_mm();
-
- local_irq_enable();
-
- xencons_resume();
-
- xenbus_resume();
-
- smp_resume();
-
- return err;
-}
-
static int shutdown_process(void *__unused)
{
static char *envp[] = { "HOME=/", "TERM=linux",
@@ -222,11 +44,13 @@ static int shutdown_process(void *__unused)
if ((shutting_down == SHUTDOWN_POWEROFF) ||
(shutting_down == SHUTDOWN_HALT)) {
- if (execve("/sbin/poweroff", poweroff_argv, envp) < 0) {
+ if (call_usermodehelper("/sbin/poweroff", poweroff_argv, envp, 0) < 0) {
+#ifdef CONFIG_XEN
sys_reboot(LINUX_REBOOT_MAGIC1,
LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_POWER_OFF,
NULL);
+#endif /* CONFIG_XEN */
}
}
@@ -235,6 +59,13 @@ static int shutdown_process(void *__unused)
return 0;
}
+static int xen_suspend(void *__unused)
+{
+ __xen_suspend();
+ shutting_down = SHUTDOWN_INVALID;
+ return 0;
+}
+
static int kthread_create_on_cpu(int (*f)(void *arg),
void *arg,
const char *name,
@@ -257,7 +88,7 @@ static void __shutdown_handler(void *unused)
err = kernel_thread(shutdown_process, NULL,
CLONE_FS | CLONE_FILES);
else
- err = kthread_create_on_cpu(__do_suspend, NULL, "suspend", 0);
+ err = kthread_create_on_cpu(xen_suspend, NULL, "suspend", 0);
if (err < 0) {
printk(KERN_WARNING "Error creating shutdown process (%d): "
@@ -298,7 +129,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
if (strcmp(str, "poweroff") == 0)
shutting_down = SHUTDOWN_POWEROFF;
else if (strcmp(str, "reboot") == 0)
- ctrl_alt_del();
+ kill_proc(1, SIGINT, 1); /* interrupt init */
else if (strcmp(str, "suspend") == 0)
shutting_down = SHUTDOWN_SUSPEND;
else if (strcmp(str, "halt") == 0)
@@ -364,10 +195,14 @@ static int setup_shutdown_watcher(struct notifier_block *notifier,
err = register_xenbus_watch(&shutdown_watch);
if (err)
printk(KERN_ERR "Failed to set shutdown watcher\n");
+ else
+ xenbus_write(XBT_NIL, "control", "feature-reboot", "1");
err = register_xenbus_watch(&sysrq_watch);
if (err)
printk(KERN_ERR "Failed to set sysrq watcher\n");
+ else
+ xenbus_write(XBT_NIL, "control", "feature-sysrq", "1");
return NOTIFY_DONE;
}
@@ -378,6 +213,7 @@ static int __init setup_shutdown_event(void)
.notifier_call = setup_shutdown_watcher
};
register_xenstore_notifier(&xenstore_notifier);
+
return 0;
}
diff --git a/linux-2.6-xen-sparse/drivers/xen/core/skbuff.c b/linux-2.6-xen-sparse/drivers/xen/core/skbuff.c
index a4a2e4edce..2fa88069c4 100644
--- a/linux-2.6-xen-sparse/drivers/xen/core/skbuff.c
+++ b/linux-2.6-xen-sparse/drivers/xen/core/skbuff.c
@@ -18,7 +18,12 @@
/*static*/ kmem_cache_t *skbuff_cachep;
EXPORT_SYMBOL(skbuff_cachep);
-#define MAX_SKBUFF_ORDER 4
+/* Allow up to 64kB or page-sized packets (whichever is greater). */
+#if PAGE_SHIFT < 16
+#define MAX_SKBUFF_ORDER (16 - PAGE_SHIFT)
+#else
+#define MAX_SKBUFF_ORDER 0
+#endif
static kmem_cache_t *skbuff_order_cachep[MAX_SKBUFF_ORDER + 1];
static struct {
diff --git a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
index 76bfab82e6..32f8de5bff 100644
--- a/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
+++ b/linux-2.6-xen-sparse/drivers/xen/evtchn/evtchn.c
@@ -419,10 +419,9 @@ static struct file_operations evtchn_fops = {
};
static struct miscdevice evtchn_miscdev = {
- .minor = EVTCHN_MINOR,
+ .minor = MISC_DYNAMIC_MINOR,
.name = "evtchn",
.fops = &evtchn_fops,
- .devfs_name = "misc/evtchn",
};
static int __init evtchn_init(void)
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/common.h b/linux-2.6-xen-sparse/drivers/xen/netback/common.h
index 434ff6bcf2..367c008d3b 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/common.h
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/common.h
@@ -92,6 +92,9 @@ typedef struct netif_st {
unsigned long remaining_credit;
struct timer_list credit_timeout;
+ /* Enforce draining of the transmit queue. */
+ struct timer_list tx_queue_timeout;
+
/* Miscellaneous private stuff. */
struct list_head list; /* scheduling list */
atomic_t refcnt;
@@ -106,7 +109,7 @@ typedef struct netif_st {
void netif_disconnect(netif_t *netif);
-netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]);
+netif_t *netif_alloc(domid_t domid, unsigned int handle);
int netif_map(netif_t *netif, unsigned long tx_ring_ref,
unsigned long rx_ring_ref, unsigned int evtchn);
@@ -119,6 +122,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
void netif_xenbus_init(void);
+#define netif_schedulable(dev) (netif_running(dev) && netif_carrier_ok(dev))
+
void netif_schedule_work(netif_t *netif);
void netif_deschedule_work(netif_t *netif);
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
index d60b23b0f2..9fae954bd2 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/interface.c
@@ -34,6 +34,23 @@
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
+/*
+ * Module parameter 'queue_length':
+ *
+ * Enables queuing in the network stack when a client has run out of receive
+ * descriptors. Although this feature can improve receive bandwidth by avoiding
+ * packet loss, it can also result in packets sitting in the 'tx_queue' for
+ * unbounded time. This is bad if those packets hold onto foreign resources.
+ * For example, consider a packet that holds onto resources belonging to the
+ * guest for which it is queued (e.g., packet received on vif1.0, destined for
+ * vif1.1 which is not activated in the guest): in this situation the guest
+ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
+ * run a timer (tx_queue_timeout) to drain the queue when the interface is
+ * blocked.
+ */
+static unsigned long netbk_queue_length = 32;
+module_param_named(queue_length, netbk_queue_length, ulong, 0);
+
static void __netif_up(netif_t *netif)
{
enable_irq(netif->irq);
@@ -107,9 +124,9 @@ static struct ethtool_ops network_ethtool_ops =
.get_link = ethtool_op_get_link,
};
-netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
+netif_t *netif_alloc(domid_t domid, unsigned int handle)
{
- int err = 0, i;
+ int err = 0;
struct net_device *dev;
netif_t *netif;
char name[IFNAMSIZ] = {};
@@ -134,6 +151,10 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
netif->credit_bytes = netif->remaining_credit = ~0UL;
netif->credit_usec = 0UL;
init_timer(&netif->credit_timeout);
+ /* Initialize 'expires' now: it's used to track the credit window. */
+ netif->credit_timeout.expires = jiffies;
+
+ init_timer(&netif->tx_queue_timeout);
dev->hard_start_xmit = netif_be_start_xmit;
dev->get_stats = netif_be_get_stats;
@@ -144,26 +165,16 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN])
SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+ dev->tx_queue_len = netbk_queue_length;
+
/*
- * Reduce default TX queuelen so that each guest interface only
- * allows it to eat around 6.4MB of host memory.
- */
- dev->tx_queue_len = 100;
-
- for (i = 0; i < ETH_ALEN; i++)
- if (be_mac[i] != 0)
- break;
- if (i == ETH_ALEN) {
- /*
- * Initialise a dummy MAC address. We choose the numerically
- * largest non-broadcast address to prevent the address getting
- * stolen by an Ethernet bridge for STP purposes.
- * (FE:FF:FF:FF:FF:FF)
- */
- memset(dev->dev_addr, 0xFF, ETH_ALEN);
- dev->dev_addr[0] &= ~0x01;
- } else
- memcpy(dev->dev_addr, be_mac, ETH_ALEN);
+ * Initialise a dummy MAC address. We choose the numerically
+ * largest non-broadcast address to prevent the address getting
+ * stolen by an Ethernet bridge for STP purposes.
+ * (FE:FF:FF:FF:FF:FF)
+ */
+ memset(dev->dev_addr, 0xFF, ETH_ALEN);
+ dev->dev_addr[0] &= ~0x01;
rtnl_lock();
err = register_netdevice(dev);
@@ -306,11 +317,23 @@ err_rx:
return err;
}
-static void netif_free(netif_t *netif)
+void netif_disconnect(netif_t *netif)
{
+ if (netif_carrier_ok(netif->dev)) {
+ rtnl_lock();
+ netif_carrier_off(netif->dev);
+ if (netif_running(netif->dev))
+ __netif_down(netif);
+ rtnl_unlock();
+ netif_put(netif);
+ }
+
atomic_dec(&netif->refcnt);
wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
+ del_timer_sync(&netif->credit_timeout);
+ del_timer_sync(&netif->tx_queue_timeout);
+
if (netif->irq)
unbind_from_irqhandler(netif->irq, netif);
@@ -324,16 +347,3 @@ static void netif_free(netif_t *netif)
free_netdev(netif->dev);
}
-
-void netif_disconnect(netif_t *netif)
-{
- if (netif_carrier_ok(netif->dev)) {
- rtnl_lock();
- netif_carrier_off(netif->dev);
- if (netif_running(netif->dev))
- __netif_down(netif);
- rtnl_unlock();
- netif_put(netif);
- }
- netif_free(netif);
-}
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c b/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c
index 391ace8a02..d021c9689a 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/loopback.c
@@ -53,8 +53,10 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/dst.h>
+#include <net/xfrm.h> /* secpath_reset() */
+#include <asm/hypervisor.h> /* is_initial_xendomain() */
-static int nloopbacks = 8;
+static int nloopbacks = -1;
module_param(nloopbacks, int, 0);
MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
@@ -77,10 +79,60 @@ static int loopback_close(struct net_device *dev)
return 0;
}
+#ifdef CONFIG_X86
+static int is_foreign(unsigned long pfn)
+{
+ /* NB. Play it safe for auto-translation mode. */
+ return (xen_feature(XENFEAT_auto_translated_physmap) ||
+ (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT));
+}
+#else
+/* How to detect a foreign mapping? Play it safe. */
+#define is_foreign(pfn) (1)
+#endif
+
+static int skb_remove_foreign_references(struct sk_buff *skb)
+{
+ struct page *page;
+ unsigned long pfn;
+ int i, off;
+ char *vaddr;
+
+ BUG_ON(skb_shinfo(skb)->frag_list);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page);
+ if (!is_foreign(pfn))
+ continue;
+
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!page))
+ return 0;
+
+ vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
+ off = skb_shinfo(skb)->frags[i].page_offset;
+ memcpy(page_address(page) + off,
+ vaddr + off,
+ skb_shinfo(skb)->frags[i].size);
+ kunmap_skb_frag(vaddr);
+
+ put_page(skb_shinfo(skb)->frags[i].page);
+ skb_shinfo(skb)->frags[i].page = page;
+ }
+
+ return 1;
+}
+
static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_private *np = netdev_priv(dev);
+ if (!skb_remove_foreign_references(skb)) {
+ np->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
dst_release(skb->dst);
skb->dst = NULL;
@@ -110,6 +162,11 @@ static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
skb->dev = dev;
dev->last_rx = jiffies;
+
+ /* Flush netfilter context: rx'ed skbuffs not expected to have any. */
+ nf_reset(skb);
+ secpath_reset(skb);
+
netif_rx(skb);
return 0;
@@ -239,6 +296,9 @@ static int __init loopback_init(void)
{
int i, err = 0;
+ if (nloopbacks == -1)
+ nloopbacks = is_initial_xendomain() ? 4 : 0;
+
for (i = 0; i < nloopbacks; i++)
if ((err = make_loopback(i)) != 0)
break;
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c
index ad8236c82f..1d24fc9b88 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c
@@ -70,14 +70,15 @@ static struct timer_list net_timer;
static struct sk_buff_head rx_queue;
-static unsigned long mmap_vstart;
-#define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE))
-
-static void *rx_mmap_area;
+static struct page **mmap_pages;
+static inline unsigned long idx_to_kaddr(unsigned int idx)
+{
+ return (unsigned long)pfn_to_kaddr(page_to_pfn(mmap_pages[idx]));
+}
#define PKT_PROT_LEN 64
-static struct {
+static struct pending_tx_info {
netif_tx_request_t req;
netif_t *netif;
} pending_tx_info[MAX_PENDING_REQS];
@@ -186,7 +187,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
if (unlikely(!nskb))
goto err;
- skb_reserve(nskb, 16);
+ skb_reserve(nskb, 16 + NET_IP_ALIGN);
headlen = nskb->end - nskb->data;
if (headlen > skb_headlen(skb))
headlen = skb_headlen(skb);
@@ -217,7 +218,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
- page = alloc_page(GFP_ATOMIC | zero);
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
if (unlikely(!page))
goto err_free;
@@ -263,6 +264,13 @@ static inline int netbk_queue_full(netif_t *netif)
((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
}
+static void tx_queue_callback(unsigned long data)
+{
+ netif_t *netif = (netif_t *)data;
+ if (netif_schedulable(netif->dev))
+ netif_wake_queue(netif->dev);
+}
+
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
@@ -270,20 +278,13 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
BUG_ON(skb->dev != dev);
/* Drop the packet if the target domain has no receive buffers. */
- if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))
+ if (unlikely(!netif_schedulable(dev) || netbk_queue_full(netif)))
goto drop;
- if (unlikely(netbk_queue_full(netif))) {
- /* Not a BUG_ON() -- misbehaving netfront can trigger this. */
- if (netbk_can_queue(dev))
- DPRINTK("Queue full but not stopped!\n");
- goto drop;
- }
-
- /* Copy the packet here if it's destined for a flipping
- interface but isn't flippable (e.g. extra references to
- data)
- */
+ /*
+ * Copy the packet here if it's destined for a flipping interface
+ * but isn't flippable (e.g. extra references to data).
+ */
if (!netif->copying_receiver && !is_flippable_skb(skb)) {
struct sk_buff *nskb = netbk_copy_skb(skb);
if ( unlikely(nskb == NULL) )
@@ -304,8 +305,19 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif->rx.sring->req_event = netif->rx_req_cons_peek +
netbk_max_required_rx_slots(netif);
mb(); /* request notification /then/ check & stop the queue */
- if (netbk_queue_full(netif))
+ if (netbk_queue_full(netif)) {
netif_stop_queue(dev);
+ /*
+ * Schedule 500ms timeout to restart the queue, thus
+ * ensuring that an inactive queue will be drained.
+ * Packets will be immediately be dropped until more
+ * receive buffers become available (see
+ * netbk_queue_full() check above).
+ */
+ netif->tx_queue_timeout.data = (unsigned long)netif;
+ netif->tx_queue_timeout.function = tx_queue_callback;
+ __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+ }
}
skb_queue_tail(&rx_queue, skb);
@@ -373,14 +385,22 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
flipped. */
meta->copy = 1;
copy_gop = npo->copy + npo->copy_prod++;
- copy_gop->source.domid = DOMID_SELF;
+ copy_gop->flags = GNTCOPY_dest_gref;
+ if (PageForeign(page)) {
+ struct pending_tx_info *src_pend =
+ &pending_tx_info[page->index];
+ copy_gop->source.domid = src_pend->netif->domid;
+ copy_gop->source.u.ref = src_pend->req.gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+ } else {
+ copy_gop->source.domid = DOMID_SELF;
+ copy_gop->source.u.gmfn = old_mfn;
+ }
copy_gop->source.offset = offset;
- copy_gop->source.u.gmfn = old_mfn;
copy_gop->dest.domid = netif->domid;
copy_gop->dest.offset = 0;
copy_gop->dest.u.ref = req->gref;
copy_gop->len = size;
- copy_gop->flags = GNTCOPY_dest_gref;
} else {
meta->copy = 0;
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
@@ -474,7 +494,7 @@ static int netbk_check_gop(int nr_frags, domid_t domid,
copy_op = npo->copy + npo->copy_cons++;
if (copy_op->status != GNTST_okay) {
DPRINTK("Bad status %d from copy to DOM%d.\n",
- gop->status, domid);
+ copy_op->status, domid);
status = NETIF_RSP_ERROR;
}
} else {
@@ -697,6 +717,7 @@ static void net_rx_action(unsigned long unused)
}
if (netif_queue_stopped(netif->dev) &&
+ netif_schedulable(netif->dev) &&
!netbk_queue_full(netif))
netif_wake_queue(netif->dev);
@@ -754,8 +775,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif)
spin_lock_irq(&net_schedule_list_lock);
if (!__on_net_schedule_list(netif) &&
- likely(netif_running(netif->dev) &&
- netif_carrier_ok(netif->dev))) {
+ likely(netif_schedulable(netif->dev))) {
list_add_tail(&netif->list, &net_schedule_list);
netif_get(netif);
}
@@ -792,10 +812,30 @@ void netif_deschedule_work(netif_t *netif)
}
+static void tx_add_credit(netif_t *netif)
+{
+ unsigned long max_burst, max_credit;
+
+ /*
+ * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
+ * Otherwise the interface can seize up due to insufficient credit.
+ */
+ max_burst = RING_GET_REQUEST(&netif->tx, netif->tx.req_cons)->size;
+ max_burst = min(max_burst, 131072UL);
+ max_burst = max(max_burst, netif->credit_bytes);
+
+ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
+ max_credit = netif->remaining_credit + netif->credit_bytes;
+ if (max_credit < netif->remaining_credit)
+ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
+
+ netif->remaining_credit = min(max_credit, max_burst);
+}
+
static void tx_credit_callback(unsigned long data)
{
netif_t *netif = (netif_t *)data;
- netif->remaining_credit = netif->credit_bytes;
+ tx_add_credit(netif);
netif_schedule_work(netif);
}
@@ -819,7 +859,7 @@ inline static void net_tx_action_dealloc(void)
gop = tx_unmap_ops;
while (dc != dp) {
pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
- gnttab_set_unmap_op(gop, MMAP_VADDR(pending_idx),
+ gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
GNTMAP_host_map,
grant_tx_handle[pending_idx]);
gop++;
@@ -857,20 +897,28 @@ static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
netif_put(netif);
}
-static int netbk_count_requests(netif_t *netif, netif_tx_request_t *txp,
- int work_to_do)
+static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
+ netif_tx_request_t *txp, int work_to_do)
{
- netif_tx_request_t *first = txp;
RING_IDX cons = netif->tx.req_cons;
int frags = 0;
- while (txp->flags & NETTXF_more_data) {
+ if (!(first->flags & NETTXF_more_data))
+ return 0;
+
+ do {
if (frags >= work_to_do) {
DPRINTK("Need more frags\n");
return -frags;
}
- txp = RING_GET_REQUEST(&netif->tx, cons + frags);
+ if (unlikely(frags >= MAX_SKB_FRAGS)) {
+ DPRINTK("Too many frags\n");
+ return -frags;
+ }
+
+ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
+ sizeof(*txp));
if (txp->size > first->size) {
DPRINTK("Frags galore\n");
return -frags;
@@ -884,30 +932,28 @@ static int netbk_count_requests(netif_t *netif, netif_tx_request_t *txp,
txp->offset, txp->size);
return -frags;
}
- }
+ } while ((txp++)->flags & NETTXF_more_data);
return frags;
}
static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
struct sk_buff *skb,
+ netif_tx_request_t *txp,
gnttab_map_grant_ref_t *mop)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
- netif_tx_request_t *txp;
unsigned long pending_idx = *((u16 *)skb->data);
- RING_IDX cons = netif->tx.req_cons;
int i, start;
/* Skip first skb fragment if it is on same page as header fragment. */
start = ((unsigned long)shinfo->frags[0].page == pending_idx);
- for (i = start; i < shinfo->nr_frags; i++) {
- txp = RING_GET_REQUEST(&netif->tx, cons++);
+ for (i = start; i < shinfo->nr_frags; i++, txp++) {
pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
- gnttab_set_map_op(mop++, MMAP_VADDR(pending_idx),
+ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txp->gref, netif->domid);
@@ -940,7 +986,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
netif_put(netif);
} else {
set_phys_to_machine(
- __pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT,
+ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
grant_tx_handle[pending_idx] = mop->handle;
}
@@ -957,7 +1003,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
newerr = (++mop)->status;
if (likely(!newerr)) {
set_phys_to_machine(
- __pa(MMAP_VADDR(pending_idx))>>PAGE_SHIFT,
+ __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
grant_tx_handle[pending_idx] = mop->handle;
/* Had a previous error? Invalidate this fragment. */
@@ -1005,7 +1051,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
pending_idx = (unsigned long)frag->page;
txp = &pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(MMAP_VADDR(pending_idx));
+ frag->page = virt_to_page(idx_to_kaddr(pending_idx));
frag->size = txp->size;
frag->page_offset = txp->offset;
@@ -1018,7 +1064,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
int work_to_do)
{
- struct netif_extra_info *extra;
+ struct netif_extra_info extra;
RING_IDX cons = netif->tx.req_cons;
do {
@@ -1027,18 +1073,18 @@ int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
return -EBADR;
}
- extra = (struct netif_extra_info *)
- RING_GET_REQUEST(&netif->tx, cons);
- if (unlikely(!extra->type ||
- extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
+ sizeof(extra));
+ if (unlikely(!extra.type ||
+ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
netif->tx.req_cons = ++cons;
- DPRINTK("Invalid extra type: %d\n", extra->type);
+ DPRINTK("Invalid extra type: %d\n", extra.type);
return -EINVAL;
}
- memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
+ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
netif->tx.req_cons = ++cons;
- } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
return work_to_do;
}
@@ -1073,6 +1119,7 @@ static void net_tx_action(unsigned long unused)
struct sk_buff *skb;
netif_t *netif;
netif_tx_request_t txreq;
+ netif_tx_request_t txfrags[MAX_SKB_FRAGS];
struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
u16 pending_idx;
RING_IDX i;
@@ -1101,6 +1148,7 @@ static void net_tx_action(unsigned long unused)
i = netif->tx.req_cons;
rmb(); /* Ensure that we see the request before we copy it. */
memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
+
/* Credit-based scheduling. */
if (txreq.size > netif->remaining_credit) {
unsigned long now = jiffies;
@@ -1109,25 +1157,27 @@ static void net_tx_action(unsigned long unused)
msecs_to_jiffies(netif->credit_usec / 1000);
/* Timer could already be pending in rare cases. */
- if (timer_pending(&netif->credit_timeout))
- break;
+ if (timer_pending(&netif->credit_timeout)) {
+ netif_put(netif);
+ continue;
+ }
/* Passed the point where we can replenish credit? */
if (time_after_eq(now, next_credit)) {
netif->credit_timeout.expires = now;
- netif->remaining_credit = netif->credit_bytes;
+ tx_add_credit(netif);
}
/* Still too big to send right now? Set a callback. */
if (txreq.size > netif->remaining_credit) {
- netif->remaining_credit = 0;
netif->credit_timeout.data =
(unsigned long)netif;
netif->credit_timeout.function =
tx_credit_callback;
__mod_timer(&netif->credit_timeout,
next_credit);
- break;
+ netif_put(netif);
+ continue;
}
}
netif->remaining_credit -= txreq.size;
@@ -1146,19 +1196,13 @@ static void net_tx_action(unsigned long unused)
}
}
- ret = netbk_count_requests(netif, &txreq, work_to_do);
+ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
if (unlikely(ret < 0)) {
netbk_tx_err(netif, &txreq, i - ret);
continue;
}
i += ret;
- if (unlikely(ret > MAX_SKB_FRAGS)) {
- DPRINTK("Too many frags\n");
- netbk_tx_err(netif, &txreq, i);
- continue;
- }
-
if (unlikely(txreq.size < ETH_HLEN)) {
DPRINTK("Bad packet size: %d\n", txreq.size);
netbk_tx_err(netif, &txreq, i);
@@ -1180,7 +1224,7 @@ static void net_tx_action(unsigned long unused)
ret < MAX_SKB_FRAGS) ?
PKT_PROT_LEN : txreq.size;
- skb = alloc_skb(data_len+16, GFP_ATOMIC);
+ skb = alloc_skb(data_len + 16 + NET_IP_ALIGN, GFP_ATOMIC);
if (unlikely(skb == NULL)) {
DPRINTK("Can't allocate a skb in start_xmit.\n");
netbk_tx_err(netif, &txreq, i);
@@ -1188,7 +1232,7 @@ static void net_tx_action(unsigned long unused)
}
/* Packets passed to netif_rx() must have some headroom. */
- skb_reserve(skb, 16);
+ skb_reserve(skb, 16 + NET_IP_ALIGN);
if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
struct netif_extra_info *gso;
@@ -1201,7 +1245,7 @@ static void net_tx_action(unsigned long unused)
}
}
- gnttab_set_map_op(mop, MMAP_VADDR(pending_idx),
+ gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txreq.gref, netif->domid);
mop++;
@@ -1227,7 +1271,7 @@ static void net_tx_action(unsigned long unused)
pending_cons++;
- mop = netbk_get_requests(netif, skb, mop);
+ mop = netbk_get_requests(netif, skb, txfrags, mop);
netif->tx.req_cons = i;
netif_schedule_work(netif);
@@ -1260,8 +1304,8 @@ static void net_tx_action(unsigned long unused)
}
data_len = skb->len;
- memcpy(skb->data,
- (void *)(MMAP_VADDR(pending_idx)|txp->offset),
+ memcpy(skb->data,
+ (void *)(idx_to_kaddr(pending_idx)|txp->offset),
data_len);
if (data_len < txp->size) {
/* Append the packet payload as a fragment. */
@@ -1315,18 +1359,10 @@ static void netif_idx_release(u16 pending_idx)
static void netif_page_release(struct page *page)
{
- u16 pending_idx = page - virt_to_page(mmap_vstart);
-
/* Ready for next use. */
set_page_count(page, 1);
- netif_idx_release(pending_idx);
-}
-
-static void netif_rx_page_release(struct page *page)
-{
- /* Ready for next use. */
- set_page_count(page, 1);
+ netif_idx_release(page->index);
}
irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
@@ -1336,7 +1372,7 @@ irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
add_to_net_schedule_list_tail(netif);
maybe_schedule_tx_action();
- if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif))
+ if (netif_schedulable(netif->dev) && !netbk_queue_full(netif))
netif_wake_queue(netif->dev);
return IRQ_HANDLED;
@@ -1446,27 +1482,17 @@ static int __init netback_init(void)
init_timer(&net_timer);
net_timer.data = 0;
net_timer.function = net_alarm;
-
- page = balloon_alloc_empty_page_range(MAX_PENDING_REQS);
- if (page == NULL)
- return -ENOMEM;
- mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+ mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+ if (mmap_pages == NULL) {
+ printk("%s: out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
for (i = 0; i < MAX_PENDING_REQS; i++) {
- page = virt_to_page(MMAP_VADDR(i));
- set_page_count(page, 1);
+ page = mmap_pages[i];
SetPageForeign(page, netif_page_release);
- }
-
- page = balloon_alloc_empty_page_range(NET_RX_RING_SIZE);
- BUG_ON(page == NULL);
- rx_mmap_area = pfn_to_kaddr(page_to_pfn(page));
-
- for (i = 0; i < NET_RX_RING_SIZE; i++) {
- page = virt_to_page(rx_mmap_area + (i * PAGE_SIZE));
- set_page_count(page, 1);
- SetPageForeign(page, netif_rx_page_release);
+ page->index = i;
}
pending_cons = 0;
diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
index 6da614fc0c..7d301965f4 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
@@ -28,29 +28,20 @@
printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
#endif
-struct backend_info
-{
+struct backend_info {
struct xenbus_device *dev;
netif_t *netif;
- struct xenbus_watch backend_watch;
enum xenbus_state frontend_state;
};
static int connect_rings(struct backend_info *);
static void connect(struct backend_info *);
-static void maybe_connect(struct backend_info *);
-static void backend_changed(struct xenbus_watch *, const char **,
- unsigned int);
+static void backend_create_netif(struct backend_info *be);
static int netback_remove(struct xenbus_device *dev)
{
struct backend_info *be = dev->dev.driver_data;
- if (be->backend_watch.node) {
- unregister_xenbus_watch(&be->backend_watch);
- kfree(be->backend_watch.node);
- be->backend_watch.node = NULL;
- }
if (be->netif) {
netif_disconnect(be->netif);
be->netif = NULL;
@@ -63,8 +54,7 @@ static int netback_remove(struct xenbus_device *dev)
/**
* Entry point to this code when a new device is created. Allocate the basic
- * structures, and watch the store waiting for the hotplug scripts to tell us
- * the device's handle. Switch to InitWait.
+ * structures and switch to InitWait.
*/
static int netback_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
@@ -83,11 +73,6 @@ static int netback_probe(struct xenbus_device *dev,
be->dev = dev;
dev->dev.driver_data = be;
- err = xenbus_watch_path2(dev, dev->nodename, "handle",
- &be->backend_watch, backend_changed);
- if (err)
- goto fail;
-
do {
err = xenbus_transaction_start(&xbt);
if (err) {
@@ -108,9 +93,22 @@ static int netback_probe(struct xenbus_device *dev,
goto abort_transaction;
}
- err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1);
+ /* We support rx-copy path. */
+ err = xenbus_printf(xbt, dev->nodename,
+ "feature-rx-copy", "%d", 1);
+ if (err) {
+ message = "writing feature-rx-copy";
+ goto abort_transaction;
+ }
+
+ /*
+ * We don't support rx-flip path (except old guests who don't
+ * grok this feature flag).
+ */
+ err = xenbus_printf(xbt, dev->nodename,
+ "feature-rx-flip", "%d", 0);
if (err) {
- message = "writing feature-copying";
+ message = "writing feature-rx-flip";
goto abort_transaction;
}
@@ -123,9 +121,11 @@ static int netback_probe(struct xenbus_device *dev,
}
err = xenbus_switch_state(dev, XenbusStateInitWait);
- if (err) {
+ if (err)
goto fail;
- }
+
+ /* This kicks hotplug scripts, so do it immediately. */
+ backend_create_netif(be);
return 0;
@@ -175,48 +175,30 @@ static int netback_uevent(struct xenbus_device *xdev, char **envp,
}
-/**
- * Callback received when the hotplug scripts have placed the handle node.
- * Read it, and create a netif structure. If the frontend is ready, connect.
- */
-static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+static void backend_create_netif(struct backend_info *be)
{
int err;
long handle;
- struct backend_info *be
- = container_of(watch, struct backend_info, backend_watch);
struct xenbus_device *dev = be->dev;
- DPRINTK("");
+ if (be->netif != NULL)
+ return;
err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
- if (XENBUS_EXIST_ERR(err)) {
- /* Since this watch will fire once immediately after it is
- registered, we expect this. Ignore it, and wait for the
- hotplug scripts. */
- return;
- }
if (err != 1) {
xenbus_dev_fatal(dev, err, "reading handle");
return;
}
- if (be->netif == NULL) {
- u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-
- be->netif = netif_alloc(dev->otherend_id, handle, be_mac);
- if (IS_ERR(be->netif)) {
- err = PTR_ERR(be->netif);
- be->netif = NULL;
- xenbus_dev_fatal(dev, err, "creating interface");
- return;
- }
-
- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
-
- maybe_connect(be);
+ be->netif = netif_alloc(dev->otherend_id, handle);
+ if (IS_ERR(be->netif)) {
+ err = PTR_ERR(be->netif);
+ be->netif = NULL;
+ xenbus_dev_fatal(dev, err, "creating interface");
+ return;
}
+
+ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
}
@@ -249,11 +231,9 @@ static void frontend_changed(struct xenbus_device *dev,
break;
case XenbusStateConnected:
- if (!be->netif) {
- /* reconnect: setup be->netif */
- backend_changed(&be->backend_watch, NULL, 0);
- }
- maybe_connect(be);
+ backend_create_netif(be);
+ if (be->netif)
+ connect(be);
break;
case XenbusStateClosing:
@@ -279,15 +259,6 @@ static void frontend_changed(struct xenbus_device *dev,
}
-/* ** Connection ** */
-
-
-static void maybe_connect(struct backend_info *be)
-{
- if (be->netif && (be->frontend_state == XenbusStateConnected))
- connect(be);
-}
-
static void xen_net_read_rate(struct xenbus_device *dev,
unsigned long *bytes, unsigned long *usec)
{
@@ -366,6 +337,10 @@ static void connect(struct backend_info *be)
be->netif->remaining_credit = be->netif->credit_bytes;
xenbus_switch_state(dev, XenbusStateConnected);
+
+ /* May not get a kick from the frontend, so start the tx_queue now. */
+ if (!netbk_can_queue(be->netif->dev))
+ netif_wake_queue(be->netif->dev);
}
@@ -403,14 +378,16 @@ static int connect_rings(struct backend_info *be)
}
be->netif->copying_receiver = !!rx_copy;
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-notify", "%d",
- &val) < 0)
- val = 0;
- if (val)
- be->netif->can_queue = 1;
- else
- /* Must be non-zero for pfifo_fast to work. */
- be->netif->dev->tx_queue_len = 1;
+ if (be->netif->dev->tx_queue_len != 0) {
+ if (xenbus_scanf(XBT_NIL, dev->otherend,
+ "feature-rx-notify", "%d", &val) < 0)
+ val = 0;
+ if (val)
+ be->netif->can_queue = 1;
+ else
+ /* Must be non-zero for pfifo_fast to work. */
+ be->netif->dev->tx_queue_len = 1;
+ }
if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0)
val = 0;
diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
index a257cb6064..da22d45bf6 100644
--- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
+++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
@@ -47,6 +47,7 @@
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/io.h>
+#include <linux/moduleparam.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/arp.h>
@@ -63,20 +64,76 @@
#include <xen/interface/grant_table.h>
#include <xen/gnttab.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+/*
+ * Mutually-exclusive module options to select receive data path:
+ * rx_copy : Packets are copied by network backend into local memory
+ * rx_flip : Page containing packet data is transferred to our ownership
+ * For fully-virtualised guests there is no option - copying must be used.
+ * For paravirtualised guests, flipping is the default.
+ */
+#ifdef CONFIG_XEN
+static int MODPARM_rx_copy = 0;
+module_param_named(rx_copy, MODPARM_rx_copy, bool, 0);
+MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)");
+static int MODPARM_rx_flip = 0;
+module_param_named(rx_flip, MODPARM_rx_flip, bool, 0);
+MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)");
+#else
+static const int MODPARM_rx_copy = 1;
+static const int MODPARM_rx_flip = 0;
+#endif
+
#define RX_COPY_THRESHOLD 256
/* If we don't have GSO, fake things up so that we never try to use it. */
-#ifndef NETIF_F_GSO
-#define netif_needs_gso(dev, skb) 0
-#define dev_disable_gso_features(dev) ((void)0)
-#else
+#if defined(NETIF_F_GSO)
#define HAVE_GSO 1
+#define HAVE_TSO 1 /* TSO is a subset of GSO */
static inline void dev_disable_gso_features(struct net_device *dev)
{
/* Turn off all GSO bits except ROBUST. */
dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
dev->features |= NETIF_F_GSO_ROBUST;
}
+#elif defined(NETIF_F_TSO)
+#define HAVE_TSO 1
+
+/* Some older kernels cannot cope with incorrect checksums,
+ * particularly in netfilter. I'm not sure there is 100% correlation
+ * with the presence of NETIF_F_TSO but it appears to be a good first
+ * approximiation.
+ */
+#define HAVE_NO_CSUM_OFFLOAD 1
+
+#define gso_size tso_size
+#define gso_segs tso_segs
+static inline void dev_disable_gso_features(struct net_device *dev)
+{
+ /* Turn off all TSO bits. */
+ dev->features &= ~NETIF_F_TSO;
+}
+static inline int skb_is_gso(const struct sk_buff *skb)
+{
+ return skb_shinfo(skb)->tso_size;
+}
+static inline int skb_gso_ok(struct sk_buff *skb, int features)
+{
+ return (features & NETIF_F_TSO);
+}
+
+static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
+{
+ return skb_is_gso(skb) &&
+ (!skb_gso_ok(skb, dev->features) ||
+ unlikely(skb->ip_summed != CHECKSUM_HW));
+}
+#else
+#define netif_needs_gso(dev, skb) 0
+#define dev_disable_gso_features(dev) ((void)0)
#endif
#define GRANT_INVALID_REF 0
@@ -96,7 +153,6 @@ struct netfront_info {
spinlock_t tx_lock;
spinlock_t rx_lock;
- unsigned int handle;
unsigned int evtchn, irq;
unsigned int copying_receiver;
@@ -120,7 +176,7 @@ struct netfront_info {
grant_ref_t gref_tx_head;
grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
grant_ref_t gref_rx_head;
- grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
+ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
struct xenbus_device *xbdev;
int tx_ring_ref;
@@ -185,9 +241,8 @@ static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
#define WPRINTK(fmt, args...) \
printk(KERN_WARNING "netfront: " fmt, ##args)
-static int talk_to_backend(struct xenbus_device *, struct netfront_info *);
static int setup_device(struct xenbus_device *, struct netfront_info *);
-static struct net_device *create_netdev(int, int, struct xenbus_device *);
+static struct net_device *create_netdev(struct xenbus_device *);
static void netfront_closing(struct xenbus_device *);
@@ -195,9 +250,8 @@ static void end_access(int, void *);
static void netif_disconnect_backend(struct netfront_info *);
static int open_netdev(struct netfront_info *);
static void close_netdev(struct netfront_info *);
-static void netif_free(struct netfront_info *);
-static void network_connect(struct net_device *);
+static int network_connect(struct net_device *);
static void network_tx_buf_gc(struct net_device *);
static void network_alloc_rx_buffers(struct net_device *);
static int send_fake_arp(struct net_device *);
@@ -220,8 +274,7 @@ static inline int xennet_can_sg(struct net_device *dev)
/**
* Entry point to this code when a new device is created. Allocate the basic
* structures and the ring buffers for communication with the backend, and
- * inform the backend of the appropriate details for those. Switch to
- * Connected state.
+ * inform the backend of the appropriate details for those.
*/
static int __devinit netfront_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
@@ -229,31 +282,8 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
int err;
struct net_device *netdev;
struct netfront_info *info;
- unsigned int handle;
- unsigned feature_rx_copy;
-
- err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%u", &handle);
- if (err != 1) {
- xenbus_dev_fatal(dev, err, "reading handle");
- return err;
- }
-
-#ifndef CONFIG_XEN
- err = xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-copy", "%u",
- &feature_rx_copy);
- if (err != 1) {
- xenbus_dev_fatal(dev, err, "reading feature-rx-copy");
- return err;
- }
- if (!feature_rx_copy) {
- xenbus_dev_fatal(dev, 0, "need a copy-capable backend");
- return -EINVAL;
- }
-#else
- feature_rx_copy = 0;
-#endif
- netdev = create_netdev(handle, feature_rx_copy, dev);
+ netdev = create_netdev(dev);
if (IS_ERR(netdev)) {
err = PTR_ERR(netdev);
xenbus_dev_fatal(dev, err, "creating netdev");
@@ -263,20 +293,13 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
info = netdev_priv(netdev);
dev->dev.driver_data = info;
- err = talk_to_backend(dev, info);
- if (err)
- goto fail_backend;
-
err = open_netdev(info);
if (err)
- goto fail_open;
+ goto fail;
return 0;
- fail_open:
- xennet_sysfs_delif(info->netdev);
- unregister_netdev(netdev);
- fail_backend:
+ fail:
free_netdev(netdev);
dev->dev.driver_data = NULL;
return err;
@@ -296,7 +319,7 @@ static int netfront_resume(struct xenbus_device *dev)
DPRINTK("%s\n", dev->nodename);
netif_disconnect_backend(info);
- return talk_to_backend(dev, info);
+ return 0;
}
static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
@@ -379,13 +402,21 @@ again:
goto abort_transaction;
}
+#ifdef HAVE_NO_CSUM_OFFLOAD
+ err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload", "%d", 1);
+ if (err) {
+ message = "writing feature-no-csum-offload";
+ goto abort_transaction;
+ }
+#endif
+
err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
if (err) {
message = "writing feature-sg";
goto abort_transaction;
}
-#ifdef HAVE_GSO
+#ifdef HAVE_TSO
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
if (err) {
message = "writing feature-gso-tcpv4";
@@ -407,12 +438,11 @@ again:
xenbus_transaction_end(xbt, 1);
xenbus_dev_fatal(dev, err, "%s", message);
destroy_ring:
- netif_free(info);
+ netif_disconnect_backend(info);
out:
return err;
}
-
static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
{
struct netif_tx_sring *txs;
@@ -472,11 +502,9 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
return 0;
fail:
- netif_free(info);
return err;
}
-
/**
* Callback received when the backend's state changes.
*/
@@ -497,7 +525,8 @@ static void backend_changed(struct xenbus_device *dev,
break;
case XenbusStateInitWait:
- network_connect(netdev);
+ if (network_connect(netdev) != 0)
+ break;
xenbus_switch_state(dev, XenbusStateConnected);
(void)send_fake_arp(netdev);
break;
@@ -508,7 +537,6 @@ static void backend_changed(struct xenbus_device *dev,
}
}
-
/** Send a packet on a net device to encourage switches to learn the
* MAC. We send a fake ARP request.
*
@@ -537,7 +565,6 @@ static int send_fake_arp(struct net_device *dev)
return dev_queue_xmit(skb);
}
-
static int network_open(struct net_device *dev)
{
struct netfront_info *np = netdev_priv(dev);
@@ -629,14 +656,12 @@ static void network_tx_buf_gc(struct net_device *dev)
network_maybe_wake_tx(dev);
}
-
static void rx_refill_timeout(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
netif_rx_schedule(dev);
}
-
static void network_alloc_rx_buffers(struct net_device *dev)
{
unsigned short id;
@@ -669,7 +694,7 @@ static void network_alloc_rx_buffers(struct net_device *dev)
* necessary here.
* 16 bytes added as necessary headroom for netif_receive_skb.
*/
- skb = alloc_skb(RX_COPY_THRESHOLD + 16,
+ skb = alloc_skb(RX_COPY_THRESHOLD + 16 + NET_IP_ALIGN,
GFP_ATOMIC | __GFP_NOWARN);
if (unlikely(!skb))
goto no_skb;
@@ -687,7 +712,7 @@ no_skb:
break;
}
- skb_reserve(skb, 16); /* mimic dev_alloc_skb() */
+ skb_reserve(skb, 16 + NET_IP_ALIGN); /* mimic dev_alloc_skb() */
skb_shinfo(skb)->frags[0].page = page;
skb_shinfo(skb)->nr_frags = 1;
__skb_queue_tail(&np->rx_batch, skb);
@@ -742,7 +767,7 @@ no_skb:
} else {
gnttab_grant_foreign_access_ref(ref,
np->xbdev->otherend_id,
- pfn,
+ pfn_to_mfn(pfn),
0);
}
@@ -917,7 +942,7 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx->flags |= NETTXF_data_validated;
#endif
-#ifdef HAVE_GSO
+#ifdef HAVE_TSO
if (skb_shinfo(skb)->gso_size) {
struct netif_extra_info *gso = (struct netif_extra_info *)
RING_GET_REQUEST(&np->tx, ++i);
@@ -1071,6 +1096,7 @@ static int xennet_get_responses(struct netfront_info *np,
if (net_ratelimit())
WPRINTK("rx->offset: %x, size: %u\n",
rx->offset, rx->status);
+ xennet_move_rx_slot(np, skb, ref);
err = -EINVAL;
goto next;
}
@@ -1081,7 +1107,8 @@ static int xennet_get_responses(struct netfront_info *np,
* situation to the system controller to reboot the backed.
*/
if (ref == GRANT_INVALID_REF) {
- WPRINTK("Bad rx response id %d.\n", rx->id);
+ if (net_ratelimit())
+ WPRINTK("Bad rx response id %d.\n", rx->id);
err = -EINVAL;
goto next;
}
@@ -1153,6 +1180,9 @@ next:
err = -E2BIG;
}
+ if (unlikely(err))
+ np->rx.rsp_cons = cons + frags;
+
*pages_flipped_p = pages_flipped;
return err;
@@ -1205,12 +1235,14 @@ static int xennet_set_skb_gso(struct sk_buff *skb,
return -EINVAL;
}
-#ifdef HAVE_GSO
+#ifdef HAVE_TSO
skb_shinfo(skb)->gso_size = gso->u.gso.size;
+#ifdef HAVE_GSO
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
/* Header must be checked, and gso_segs computed. */
skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+#endif
skb_shinfo(skb)->gso_segs = 0;
return 0;
@@ -1255,9 +1287,9 @@ static int netif_poll(struct net_device *dev, int *pbudget)
rp = np->rx.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
- for (i = np->rx.rsp_cons, work_done = 0;
- (i != rp) && (work_done < budget);
- np->rx.rsp_cons = ++i, work_done++) {
+ i = np->rx.rsp_cons;
+ work_done = 0;
+ while ((i != rp) && (work_done < budget)) {
memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
memset(extras, 0, sizeof(extras));
@@ -1265,12 +1297,11 @@ static int netif_poll(struct net_device *dev, int *pbudget)
&pages_flipped);
if (unlikely(err)) {
-err:
- i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1;
- work_done--;
+err:
while ((skb = __skb_dequeue(&tmpq)))
__skb_queue_tail(&errq, skb);
np->stats.rx_errors++;
+ i = np->rx.rsp_cons;
continue;
}
@@ -1282,6 +1313,7 @@ err:
if (unlikely(xennet_set_skb_gso(skb, gso))) {
__skb_queue_head(&tmpq, skb);
+ np->rx.rsp_cons += skb_queue_len(&tmpq);
goto err;
}
}
@@ -1345,6 +1377,9 @@ err:
np->stats.rx_bytes += skb->len;
__skb_queue_tail(&rxq, skb);
+
+ np->rx.rsp_cons = ++i;
+ work_done++;
}
if (pages_flipped) {
@@ -1561,7 +1596,7 @@ static int xennet_set_sg(struct net_device *dev, u32 data)
static int xennet_set_tso(struct net_device *dev, u32 data)
{
-#ifdef HAVE_GSO
+#ifdef HAVE_TSO
if (data) {
struct netfront_info *np = netdev_priv(dev);
int val;
@@ -1588,20 +1623,53 @@ static void xennet_set_features(struct net_device *dev)
if (!(dev->features & NETIF_F_IP_CSUM))
return;
- if (!xennet_set_sg(dev, 1))
- xennet_set_tso(dev, 1);
+ if (xennet_set_sg(dev, 1))
+ return;
+
+ /* Before 2.6.9 TSO seems to be unreliable so do not enable it
+ * on older kernels.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
+ xennet_set_tso(dev, 1);
+#endif
+
}
-static void network_connect(struct net_device *dev)
+static int network_connect(struct net_device *dev)
{
struct netfront_info *np = netdev_priv(dev);
- int i, requeue_idx;
+ int i, requeue_idx, err;
struct sk_buff *skb;
grant_ref_t ref;
netif_rx_request_t *req;
+ unsigned int feature_rx_copy, feature_rx_flip;
+
+ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-rx-copy", "%u", &feature_rx_copy);
+ if (err != 1)
+ feature_rx_copy = 0;
+ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-rx-flip", "%u", &feature_rx_flip);
+ if (err != 1)
+ feature_rx_flip = 1;
+
+ /*
+ * Copy packets on receive path if:
+ * (a) This was requested by user, and the backend supports it; or
+ * (b) Flipping was requested, but this is unsupported by the backend.
+ */
+ np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
+ (MODPARM_rx_flip && !feature_rx_flip));
+
+ err = talk_to_backend(np->xbdev, np);
+ if (err)
+ return err;
xennet_set_features(dev);
+ IPRINTK("device %s has %sing receive path.\n",
+ dev->name, np->copying_receiver ? "copy" : "flipp");
+
spin_lock_irq(&np->tx_lock);
spin_lock(&np->rx_lock);
@@ -1632,7 +1700,8 @@ static void network_connect(struct net_device *dev)
} else {
gnttab_grant_foreign_access_ref(
ref, np->xbdev->otherend_id,
- page_to_pfn(skb_shinfo(skb)->frags->page),
+ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+ frags->page)),
0);
}
req->gref = ref;
@@ -1656,6 +1725,8 @@ static void network_connect(struct net_device *dev)
spin_unlock(&np->rx_lock);
spin_unlock_irq(&np->tx_lock);
+
+ return 0;
}
static void netif_uninit(struct net_device *dev)
@@ -1821,8 +1892,7 @@ static void network_set_multicast_list(struct net_device *dev)
{
}
-static struct net_device * __devinit
-create_netdev(int handle, int copying_receiver, struct xenbus_device *dev)
+static struct net_device * __devinit create_netdev(struct xenbus_device *dev)
{
int i, err = 0;
struct net_device *netdev = NULL;
@@ -1836,9 +1906,7 @@ create_netdev(int handle, int copying_receiver, struct xenbus_device *dev)
}
np = netdev_priv(netdev);
- np->handle = handle;
np->xbdev = dev;
- np->copying_receiver = copying_receiver;
netif_carrier_off(netdev);
@@ -1969,10 +2037,12 @@ static int open_netdev(struct netfront_info *info)
err = xennet_sysfs_addif(info->netdev);
if (err) {
- /* This can be non-fatal: it only means no tuning parameters */
+ unregister_netdev(info->netdev);
printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
__FUNCTION__, err);
+ return err;
}
+
return 0;
}
@@ -2007,14 +2077,6 @@ static void netif_disconnect_backend(struct netfront_info *info)
}
-static void netif_free(struct netfront_info *info)
-{
- close_netdev(info);
- netif_disconnect_backend(info);
- free_netdev(info->netdev);
-}
-
-
static void end_access(int ref, void *page)
{
if (ref != GRANT_INVALID_REF)
@@ -2053,6 +2115,16 @@ static int __init netif_init(void)
if (!is_running_on_xen())
return -ENODEV;
+#ifdef CONFIG_XEN
+ if (MODPARM_rx_flip && MODPARM_rx_copy) {
+ WPRINTK("Cannot specify both rx_copy and rx_flip.\n");
+ return -EINVAL;
+ }
+
+ if (!MODPARM_rx_flip && !MODPARM_rx_copy)
+ MODPARM_rx_flip = 1; /* Default is to flip. */
+#endif
+
if (is_initial_xendomain())
return 0;
@@ -2067,6 +2139,9 @@ module_init(netif_init);
static void __exit netif_exit(void)
{
+ if (is_initial_xendomain())
+ return;
+
unregister_inetaddr_notifier(&notifier_inetdev);
return xenbus_unregister_driver(&netfront);
diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c
index a1c4b6f68e..d159e4ac74 100644
--- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c
+++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c
@@ -35,6 +35,10 @@
static struct proc_dir_entry *privcmd_intf;
static struct proc_dir_entry *capabilities_intf;
+#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
+#endif
+
static int privcmd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long data)
{
@@ -49,6 +53,8 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
#if defined(__i386__)
+ if (hypercall.op >= (PAGE_SIZE >> 5))
+ break;
__asm__ __volatile__ (
"pushl %%ebx; pushl %%ecx; pushl %%edx; "
"pushl %%esi; pushl %%edi; "
@@ -65,45 +71,36 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
"popl %%ecx; popl %%ebx"
: "=a" (ret) : "0" (&hypercall) : "memory" );
#elif defined (__x86_64__)
- {
+ if (hypercall.op < (PAGE_SIZE >> 5)) {
long ign1, ign2, ign3;
__asm__ __volatile__ (
"movq %8,%%r10; movq %9,%%r8;"
- "shlq $5,%%rax ;"
+ "shll $5,%%eax ;"
"addq $hypercall_page,%%rax ;"
"call *%%rax"
: "=a" (ret), "=D" (ign1),
"=S" (ign2), "=d" (ign3)
- : "0" ((unsigned long)hypercall.op),
- "1" ((unsigned long)hypercall.arg[0]),
- "2" ((unsigned long)hypercall.arg[1]),
- "3" ((unsigned long)hypercall.arg[2]),
- "g" ((unsigned long)hypercall.arg[3]),
- "g" ((unsigned long)hypercall.arg[4])
+ : "0" ((unsigned int)hypercall.op),
+ "1" (hypercall.arg[0]),
+ "2" (hypercall.arg[1]),
+ "3" (hypercall.arg[2]),
+ "g" (hypercall.arg[3]),
+ "g" (hypercall.arg[4])
: "r8", "r10", "memory" );
}
#elif defined (__ia64__)
- __asm__ __volatile__ (
- ";; mov r14=%2; mov r15=%3; "
- "mov r16=%4; mov r17=%5; mov r18=%6;"
- "mov r2=%1; break 0x1000;; mov %0=r8 ;;"
- : "=r" (ret)
- : "r" (hypercall.op),
- "r" (hypercall.arg[0]),
- "r" (hypercall.arg[1]),
- "r" (hypercall.arg[2]),
- "r" (hypercall.arg[3]),
- "r" (hypercall.arg[4])
- : "r14","r15","r16","r17","r18","r2","r8","memory");
+ ret = privcmd_hypercall(&hypercall);
#endif
}
break;
case IOCTL_PRIVCMD_MMAP: {
-#define PRIVCMD_MMAP_SZ 32
privcmd_mmap_t mmapcmd;
- privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ];
+ privcmd_mmap_entry_t msg;
privcmd_mmap_entry_t __user *p;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long va;
int i, rc;
if (!is_initial_xendomain())
@@ -113,85 +110,92 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
p = mmapcmd.entry;
+ if (copy_from_user(&msg, p, sizeof(msg)))
+ return -EFAULT;
- for (i = 0; i < mmapcmd.num;
- i += PRIVCMD_MMAP_SZ, p += PRIVCMD_MMAP_SZ) {
- int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
- PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
-
- if (copy_from_user(&msg, p,
- n*sizeof(privcmd_mmap_entry_t)))
- return -EFAULT;
-
- for (j = 0; j < n; j++) {
- struct vm_area_struct *vma =
- find_vma( current->mm, msg[j].va );
-
- if (!vma)
- return -EINVAL;
-
- if (msg[j].va > PAGE_OFFSET)
- return -EINVAL;
-
- if ((msg[j].va + (msg[j].npages << PAGE_SHIFT))
- > vma->vm_end )
- return -EINVAL;
-
- if ((rc = direct_remap_pfn_range(
- vma,
- msg[j].va&PAGE_MASK,
- msg[j].mfn,
- msg[j].npages<<PAGE_SHIFT,
- vma->vm_page_prot,
- mmapcmd.dom)) < 0)
- return rc;
- }
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, msg.va);
+ rc = -EINVAL;
+ if (!vma || (msg.va != vma->vm_start) ||
+ !privcmd_enforce_singleshot_mapping(vma))
+ goto mmap_out;
+
+ va = vma->vm_start;
+
+ for (i = 0; i < mmapcmd.num; i++) {
+ rc = -EFAULT;
+ if (copy_from_user(&msg, p, sizeof(msg)))
+ goto mmap_out;
+
+ /* Do not allow range to wrap the address space. */
+ rc = -EINVAL;
+ if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
+ ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
+ goto mmap_out;
+
+ /* Range chunks must be contiguous in va space. */
+ if ((msg.va != va) ||
+ ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
+ goto mmap_out;
+
+ if ((rc = direct_remap_pfn_range(
+ vma,
+ msg.va & PAGE_MASK,
+ msg.mfn,
+ msg.npages << PAGE_SHIFT,
+ vma->vm_page_prot,
+ mmapcmd.dom)) < 0)
+ goto mmap_out;
+
+ p++;
+ va += msg.npages << PAGE_SHIFT;
}
- ret = 0;
+
+ rc = 0;
+
+ mmap_out:
+ up_read(&mm->mmap_sem);
+ ret = rc;
}
break;
case IOCTL_PRIVCMD_MMAPBATCH: {
privcmd_mmapbatch_t m;
- struct vm_area_struct *vma = NULL;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
xen_pfn_t __user *p;
- unsigned long addr, mfn;
+ unsigned long addr, mfn, nr_pages;
int i;
if (!is_initial_xendomain())
return -EPERM;
- if (copy_from_user(&m, udata, sizeof(m))) {
- ret = -EFAULT;
- goto batch_err;
- }
-
- if (m.dom == DOMID_SELF) {
- ret = -EINVAL;
- goto batch_err;
- }
+ if (copy_from_user(&m, udata, sizeof(m)))
+ return -EFAULT;
- vma = find_vma(current->mm, m.addr);
- if (!vma) {
- ret = -EINVAL;
- goto batch_err;
- }
+ nr_pages = m.num;
+ if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
+ return -EINVAL;
- if (m.addr > PAGE_OFFSET) {
- ret = -EFAULT;
- goto batch_err;
- }
+ down_read(&mm->mmap_sem);
- if ((m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end) {
- ret = -EFAULT;
- goto batch_err;
+ vma = find_vma(mm, m.addr);
+ if (!vma ||
+ (m.addr != vma->vm_start) ||
+ ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
+ !privcmd_enforce_singleshot_mapping(vma)) {
+ up_read(&mm->mmap_sem);
+ return -EINVAL;
}
p = m.arr;
addr = m.addr;
- for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
- if (get_user(mfn, p))
+ for (i = 0; i < nr_pages; i++, addr += PAGE_SIZE, p++) {
+ if (get_user(mfn, p)) {
+ up_read(&mm->mmap_sem);
return -EFAULT;
+ }
ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
mfn, PAGE_SIZE,
@@ -200,15 +204,8 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
put_user(0xF0000000 | mfn, p);
}
+ up_read(&mm->mmap_sem);
ret = 0;
- break;
-
- batch_err:
- printk("batch_err ret=%d vma=%p addr=%lx "
- "num=%d arr=%p %lx-%lx\n",
- ret, vma, (unsigned long)m.addr, m.num, m.arr,
- vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
- break;
}
break;
@@ -221,13 +218,35 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
}
#ifndef HAVE_ARCH_PRIVCMD_MMAP
+static struct page *privcmd_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ return NOPAGE_SIGBUS;
+}
+
+static struct vm_operations_struct privcmd_vm_ops = {
+ .nopage = privcmd_nopage
+};
+
static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
{
+ /* Unsupported for auto-translate guests. */
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return -ENOSYS;
+
/* DONTCOPY is essential for Xen as copy_page_range is broken. */
vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+ vma->vm_ops = &privcmd_vm_ops;
+ vma->vm_private_data = NULL;
return 0;
}
+
+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
+{
+ return (xchg(&vma->vm_private_data, (void *)1) == NULL);
+}
#endif
static struct file_operations privcmd_file_ops = {
diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
index 27b8fd283a..b209b4f583 100644
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h
@@ -46,11 +46,10 @@ typedef struct tpmif_st {
atomic_t refcnt;
struct backend_info *bi;
- unsigned long mmap_vstart;
grant_handle_t shmem_handle;
grant_ref_t shmem_ref;
- struct page *pagerange;
+ struct page **mmap_pages;
char devname[20];
} tpmif_t;
@@ -80,6 +79,9 @@ int vtpm_release_packets(tpmif_t * tpmif, int send_msgs);
extern int num_frontends;
-#define MMAP_VADDR(t,_req) ((t)->mmap_vstart + ((_req) * PAGE_SIZE))
+static inline unsigned long idx_to_kaddr(tpmif_t *t, unsigned int idx)
+{
+ return (unsigned long)pfn_to_kaddr(page_to_pfn(t->mmap_pages[idx]));
+}
#endif /* __TPMIF__BACKEND__COMMON_H__ */
diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
index 0105bd93bf..2614aa5126 100644
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c
@@ -25,8 +25,8 @@ static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi)
tpmif_t *tpmif;
tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
- if (!tpmif)
- return ERR_PTR(-ENOMEM);
+ if (tpmif == NULL)
+ goto out_of_memory;
memset(tpmif, 0, sizeof (*tpmif));
tpmif->domid = domid;
@@ -35,22 +35,27 @@ static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi)
snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
atomic_set(&tpmif->refcnt, 1);
- tpmif->pagerange = balloon_alloc_empty_page_range(TPMIF_TX_RING_SIZE);
- BUG_ON(tpmif->pagerange == NULL);
- tpmif->mmap_vstart = (unsigned long)pfn_to_kaddr(
- page_to_pfn(tpmif->pagerange));
+ tpmif->mmap_pages = alloc_empty_pages_and_pagevec(TPMIF_TX_RING_SIZE);
+ if (tpmif->mmap_pages == NULL)
+ goto out_of_memory;
list_add(&tpmif->tpmif_list, &tpmif_list);
num_frontends++;
return tpmif;
+
+ out_of_memory:
+ if (tpmif != NULL)
+ kmem_cache_free(tpmif_cachep, tpmif);
+ printk("%s: out of memory\n", __FUNCTION__);
+ return ERR_PTR(-ENOMEM);
}
static void free_tpmif(tpmif_t * tpmif)
{
num_frontends--;
list_del(&tpmif->tpmif_list);
- balloon_dealloc_empty_page_range(tpmif->pagerange, TPMIF_TX_RING_SIZE);
+ free_empty_pages_and_pagevec(tpmif->mmap_pages, TPMIF_TX_RING_SIZE);
kmem_cache_free(tpmif_cachep, tpmif);
}
diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c
index 466c3ee581..701a5ad03e 100644
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c
@@ -253,7 +253,7 @@ int _packet_write(struct packet *pak,
return 0;
}
- gnttab_set_map_op(&map_op, MMAP_VADDR(tpmif, i),
+ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i),
GNTMAP_host_map, tx->ref, tpmif->domid);
if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
@@ -270,7 +270,7 @@ int _packet_write(struct packet *pak,
tocopy = min_t(size_t, size - offset, PAGE_SIZE);
- if (copy_from_buffer((void *)(MMAP_VADDR(tpmif, i) |
+ if (copy_from_buffer((void *)(idx_to_kaddr(tpmif, i) |
(tx->addr & ~PAGE_MASK)),
&data[offset], tocopy, isuserbuffer)) {
tpmif_put(tpmif);
@@ -278,7 +278,7 @@ int _packet_write(struct packet *pak,
}
tx->size = tocopy;
- gnttab_set_unmap_op(&unmap_op, MMAP_VADDR(tpmif, i),
+ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i),
GNTMAP_host_map, handle);
if (unlikely
@@ -391,7 +391,7 @@ static int packet_read_shmem(struct packet *pak,
tx = &tpmif->tx->ring[i].req;
- gnttab_set_map_op(&map_op, MMAP_VADDR(tpmif, i),
+ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i),
GNTMAP_host_map, tx->ref, tpmif->domid);
if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
@@ -414,10 +414,10 @@ static int packet_read_shmem(struct packet *pak,
}
DPRINTK("Copying from mapped memory at %08lx\n",
- (unsigned long)(MMAP_VADDR(tpmif, i) |
+ (unsigned long)(idx_to_kaddr(tpmif, i) |
(tx->addr & ~PAGE_MASK)));
- src = (void *)(MMAP_VADDR(tpmif, i) |
+ src = (void *)(idx_to_kaddr(tpmif, i) |
((tx->addr & ~PAGE_MASK) + pg_offset));
if (copy_to_buffer(&buffer[offset],
src, to_copy, isuserbuffer)) {
@@ -428,7 +428,7 @@ static int packet_read_shmem(struct packet *pak,
tpmif->domid, buffer[offset], buffer[offset + 1],
buffer[offset + 2], buffer[offset + 3]);
- gnttab_set_unmap_op(&unmap_op, MMAP_VADDR(tpmif, i),
+ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i),
GNTMAP_host_map, handle);
if (unlikely
diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
index 4ee5c5bbfe..f48b0e3726 100644
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
@@ -157,10 +157,12 @@ static void frontend_changed(struct xenbus_device *dev,
case XenbusStateClosing:
be->instance = -1;
+ xenbus_switch_state(dev, XenbusStateClosing);
break;
- case XenbusStateUnknown:
+ case XenbusStateUnknown: /* keep it here */
case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
device_unregister(&be->dev->dev);
tpmback_remove(dev);
break;
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile b/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile
index d7c7d05172..ce5acc2457 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile
@@ -9,4 +9,5 @@ xenbus-objs += xenbus_client.o
xenbus-objs += xenbus_comms.o
xenbus-objs += xenbus_xs.o
xenbus-objs += xenbus_probe.o
+obj-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c
index 9b389ec06b..0111e8e3a2 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c
@@ -35,8 +35,9 @@
#include <xen/xenbus.h>
#include <xen/driver_util.h>
-/* xenbus_probe.c */
-extern char *kasprintf(const char *fmt, ...);
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
#define DPRINTK(fmt, args...) \
pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
@@ -84,7 +85,7 @@ int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
const char **, unsigned int))
{
int err;
- char *state = kasprintf("%s/%s", path, path2);
+ char *state = kasprintf(GFP_KERNEL, "%s/%s", path, path2);
if (!state) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
return -ENOMEM;
@@ -152,7 +153,7 @@ EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
*/
static char *error_path(struct xenbus_device *dev)
{
- return kasprintf("error/%s", dev->nodename);
+ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
}
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c
index 38da320b67..f0e42ba715 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c
@@ -30,15 +30,22 @@
* IN THE SOFTWARE.
*/
-#include <asm/hypervisor.h>
-#include <xen/evtchn.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/ptrace.h>
+#include <xen/evtchn.h>
#include <xen/xenbus.h>
+
+#include <asm/hypervisor.h>
+
#include "xenbus_comms.h"
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
static int xenbus_irq;
extern void xenbus_probe(void *);
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
index bbe4a8c5a8..ba37e61856 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
@@ -40,6 +40,7 @@
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/poll.h>
+#include <linux/mutex.h>
#include "xenbus_comms.h"
@@ -49,6 +50,10 @@
#include <xen/xen_proc.h>
#include <asm/hypervisor.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
struct xenbus_dev_transaction {
struct list_head list;
struct xenbus_transaction handle;
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
index bcd1f6df06..5320368443 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
@@ -42,6 +42,7 @@
#include <linux/mm.h>
#include <linux/notifier.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -55,6 +56,11 @@
#include <xen/hvm.h>
#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
int xen_store_evtchn;
struct xenstore_domain_interface *xen_store_interface;
@@ -67,12 +73,7 @@ static struct notifier_block *xenstore_chain;
static void wait_for_devices(struct xenbus_driver *xendrv);
static int xenbus_probe_frontend(const char *type, const char *name);
-static int xenbus_uevent_backend(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-static int xenbus_probe_backend(const char *type, const char *domid);
-static int xenbus_dev_probe(struct device *_dev);
-static int xenbus_dev_remove(struct device *_dev);
static void xenbus_dev_shutdown(struct device *_dev);
/* If something in array of ids matches this device, return it. */
@@ -86,7 +87,7 @@ match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
return NULL;
}
-static int xenbus_match(struct device *_dev, struct device_driver *_drv)
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
{
struct xenbus_driver *drv = to_xenbus_driver(_drv);
@@ -96,17 +97,6 @@ static int xenbus_match(struct device *_dev, struct device_driver *_drv)
return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
}
-struct xen_bus_type
-{
- char *root;
- unsigned int levels;
- int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
- int (*probe)(const char *type, const char *dir);
- struct bus_type bus;
- struct device dev;
-};
-
-
/* device/<type>/<id> => <type>-<id> */
static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
{
@@ -143,7 +133,7 @@ static void free_otherend_watch(struct xenbus_device *dev)
}
-static int read_otherend_details(struct xenbus_device *xendev,
+int read_otherend_details(struct xenbus_device *xendev,
char *id_node, char *path_node)
{
int err = xenbus_gather(XBT_NIL, xendev->nodename,
@@ -176,12 +166,6 @@ static int read_backend_details(struct xenbus_device *xendev)
}
-static int read_frontend_details(struct xenbus_device *xendev)
-{
- return read_otherend_details(xendev, "frontend-id", "frontend");
-}
-
-
/* Bus type for frontend drivers. */
static struct xen_bus_type xenbus_frontend = {
.root = "device",
@@ -191,115 +175,17 @@ static struct xen_bus_type xenbus_frontend = {
.bus = {
.name = "xen",
.match = xenbus_match,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
.probe = xenbus_dev_probe,
.remove = xenbus_dev_remove,
.shutdown = xenbus_dev_shutdown,
+#endif
},
.dev = {
.bus_id = "xen",
},
};
-/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
-static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
-{
- int domid, err;
- const char *devid, *type, *frontend;
- unsigned int typelen;
-
- type = strchr(nodename, '/');
- if (!type)
- return -EINVAL;
- type++;
- typelen = strcspn(type, "/");
- if (!typelen || type[typelen] != '/')
- return -EINVAL;
-
- devid = strrchr(nodename, '/') + 1;
-
- err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
- "frontend", NULL, &frontend,
- NULL);
- if (err)
- return err;
- if (strlen(frontend) == 0)
- err = -ERANGE;
- if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
- err = -ENOENT;
-
- kfree(frontend);
-
- if (err)
- return err;
-
- if (snprintf(bus_id, BUS_ID_SIZE,
- "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
- return -ENOSPC;
- return 0;
-}
-
-static struct xen_bus_type xenbus_backend = {
- .root = "backend",
- .levels = 3, /* backend/type/<frontend>/<id> */
- .get_bus_id = backend_bus_id,
- .probe = xenbus_probe_backend,
- .bus = {
- .name = "xen-backend",
- .match = xenbus_match,
- .probe = xenbus_dev_probe,
- .remove = xenbus_dev_remove,
-// .shutdown = xenbus_dev_shutdown,
- .uevent = xenbus_uevent_backend,
- },
- .dev = {
- .bus_id = "xen-backend",
- },
-};
-
-static int xenbus_uevent_backend(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
-{
- struct xenbus_device *xdev;
- struct xenbus_driver *drv;
- int i = 0;
- int length = 0;
-
- DPRINTK("");
-
- if (dev == NULL)
- return -ENODEV;
-
- xdev = to_xenbus_device(dev);
- if (xdev == NULL)
- return -ENODEV;
-
- /* stuff we want to pass to /sbin/hotplug */
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_TYPE=%s", xdev->devicetype);
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_PATH=%s", xdev->nodename);
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "XENBUS_BASE_PATH=%s", xenbus_backend.root);
-
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
- if (dev->driver) {
- drv = to_xenbus_driver(dev->driver);
- if (drv && drv->uevent)
- return drv->uevent(xdev, envp, num_envp, buffer,
- buffer_size);
- }
-
- return 0;
-}
-
static void otherend_changed(struct xenbus_watch *watch,
const char **vec, unsigned int len)
{
@@ -322,6 +208,20 @@ static void otherend_changed(struct xenbus_watch *watch,
DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state),
dev->otherend_watch.node, vec[XS_WATCH_PATH]);
+ /*
+ * Ignore xenbus transitions during shutdown. This prevents us doing
+ * work that can fail e.g., when the rootfs is gone.
+ */
+ if (system_state > SYSTEM_RUNNING) {
+ struct xen_bus_type *bus = bus;
+ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+ /* If we're frontend, drive the state machine to Closed. */
+ /* This should cause the backend to release our resources. */
+ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+ xenbus_frontend_closed(dev);
+ return;
+ }
+
if (drv->otherend_changed)
drv->otherend_changed(dev, state);
}
@@ -345,7 +245,7 @@ static int watch_otherend(struct xenbus_device *dev)
}
-static int xenbus_dev_probe(struct device *_dev)
+int xenbus_dev_probe(struct device *_dev)
{
struct xenbus_device *dev = to_xenbus_device(_dev);
struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
@@ -392,7 +292,7 @@ fail:
return -ENODEV;
}
-static int xenbus_dev_remove(struct device *_dev)
+int xenbus_dev_remove(struct device *_dev)
{
struct xenbus_device *dev = to_xenbus_device(_dev);
struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
@@ -430,14 +330,21 @@ static void xenbus_dev_shutdown(struct device *_dev)
put_device(&dev->dev);
}
-static int xenbus_register_driver_common(struct xenbus_driver *drv,
- struct xen_bus_type *bus)
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus)
{
int ret;
drv->driver.name = drv->name;
drv->driver.bus = &bus->bus;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
drv->driver.owner = drv->owner;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+ drv->driver.probe = xenbus_dev_probe;
+ drv->driver.remove = xenbus_dev_remove;
+ drv->driver.shutdown = xenbus_dev_shutdown;
+#endif
mutex_lock(&xenwatch_mutex);
ret = driver_register(&drv->driver);
@@ -462,14 +369,6 @@ int xenbus_register_frontend(struct xenbus_driver *drv)
}
EXPORT_SYMBOL_GPL(xenbus_register_frontend);
-int xenbus_register_backend(struct xenbus_driver *drv)
-{
- drv->read_otherend_details = read_frontend_details;
-
- return xenbus_register_driver_common(drv, &xenbus_backend);
-}
-EXPORT_SYMBOL_GPL(xenbus_register_backend);
-
void xenbus_unregister_driver(struct xenbus_driver *drv)
{
driver_unregister(&drv->driver);
@@ -545,45 +444,30 @@ static void xenbus_dev_release(struct device *dev)
kfree(to_xenbus_device(dev));
}
-/* Simplified asprintf. */
-char *kasprintf(const char *fmt, ...)
-{
- va_list ap;
- unsigned int len;
- char *p, dummy[1];
-
- va_start(ap, fmt);
- /* FIXME: vsnprintf has a bug, NULL should work */
- len = vsnprintf(dummy, 0, fmt, ap);
- va_end(ap);
-
- p = kmalloc(len + 1, GFP_KERNEL);
- if (!p)
- return NULL;
- va_start(ap, fmt);
- vsprintf(p, fmt, ap);
- va_end(ap);
- return p;
-}
-
static ssize_t xendev_show_nodename(struct device *dev,
- struct device_attribute *attr, char *buf)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ struct device_attribute *attr,
+#endif
+ char *buf)
{
return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
}
DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
static ssize_t xendev_show_devtype(struct device *dev,
- struct device_attribute *attr, char *buf)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ struct device_attribute *attr,
+#endif
+ char *buf)
{
return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
}
DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
-static int xenbus_probe_node(struct xen_bus_type *bus,
- const char *type,
- const char *nodename)
+int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename)
{
int err;
struct xenbus_device *xendev;
@@ -642,7 +526,7 @@ static int xenbus_probe_frontend(const char *type, const char *name)
char *nodename;
int err;
- nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name);
if (!nodename)
return -ENOMEM;
@@ -653,55 +537,6 @@ static int xenbus_probe_frontend(const char *type, const char *name)
return err;
}
-/* backend/<typename>/<frontend-uuid>/<name> */
-static int xenbus_probe_backend_unit(const char *dir,
- const char *type,
- const char *name)
-{
- char *nodename;
- int err;
-
- nodename = kasprintf("%s/%s", dir, name);
- if (!nodename)
- return -ENOMEM;
-
- DPRINTK("%s\n", nodename);
-
- err = xenbus_probe_node(&xenbus_backend, type, nodename);
- kfree(nodename);
- return err;
-}
-
-/* backend/<typename>/<frontend-domid> */
-static int xenbus_probe_backend(const char *type, const char *domid)
-{
- char *nodename;
- int err = 0;
- char **dir;
- unsigned int i, dir_n = 0;
-
- DPRINTK("");
-
- nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
- if (!nodename)
- return -ENOMEM;
-
- dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
- if (IS_ERR(dir)) {
- kfree(nodename);
- return PTR_ERR(dir);
- }
-
- for (i = 0; i < dir_n; i++) {
- err = xenbus_probe_backend_unit(nodename, type, dir[i]);
- if (err)
- break;
- }
- kfree(dir);
- kfree(nodename);
- return err;
-}
-
static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
{
int err = 0;
@@ -722,7 +557,7 @@ static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
return err;
}
-static int xenbus_probe_devices(struct xen_bus_type *bus)
+int xenbus_probe_devices(struct xen_bus_type *bus)
{
int err = 0;
char **dir;
@@ -764,7 +599,7 @@ static int strsep_len(const char *str, char c, unsigned int len)
return (len == 0) ? i : -ERANGE;
}
-static void dev_changed(const char *node, struct xen_bus_type *bus)
+void dev_changed(const char *node, struct xen_bus_type *bus)
{
int exists, rootlen;
struct xenbus_device *dev;
@@ -788,7 +623,7 @@ static void dev_changed(const char *node, struct xen_bus_type *bus)
rootlen = strsep_len(node, '/', bus->levels);
if (rootlen < 0)
return;
- root = kasprintf("%.*s", rootlen, node);
+ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
if (!root)
return;
@@ -809,25 +644,12 @@ static void frontend_changed(struct xenbus_watch *watch,
dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
}
-static void backend_changed(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
-{
- DPRINTK("");
-
- dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
-}
-
/* We watch for devices appearing and vanishing. */
static struct xenbus_watch fe_watch = {
.node = "device",
.callback = frontend_changed,
};
-static struct xenbus_watch be_watch = {
- .node = "backend",
- .callback = backend_changed,
-};
-
static int suspend_dev(struct device *dev, void *data)
{
int err = 0;
@@ -898,7 +720,7 @@ void xenbus_suspend(void)
DPRINTK("");
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
+ xenbus_backend_suspend(suspend_dev);
xs_suspend();
}
EXPORT_SYMBOL_GPL(xenbus_suspend);
@@ -908,7 +730,7 @@ void xenbus_resume(void)
xb_init_comms();
xs_resume();
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
+ xenbus_backend_resume(resume_dev);
}
EXPORT_SYMBOL_GPL(xenbus_resume);
@@ -941,20 +763,17 @@ void xenbus_probe(void *unused)
{
BUG_ON((xenstored_ready <= 0));
- /* Enumerate devices in xenstore. */
+ /* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices(&xenbus_frontend);
- xenbus_probe_devices(&xenbus_backend);
-
- /* Watch for changes. */
register_xenbus_watch(&fe_watch);
- register_xenbus_watch(&be_watch);
+ xenbus_backend_probe_and_watch();
/* Notify others that xenstore is up */
notifier_call_chain(&xenstore_chain, 0, NULL);
}
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST)
static struct file_operations xsd_kva_fops;
static struct proc_dir_entry *xsd_kva_intf;
static struct proc_dir_entry *xsd_port_intf;
@@ -1006,7 +825,7 @@ static int __init xenbus_probe_init(void)
/* Register ourselves with the kernel bus subsystem */
bus_register(&xenbus_frontend.bus);
- bus_register(&xenbus_backend.bus);
+ xenbus_backend_bus_register();
/*
* Domain0 doesn't have a store_evtchn or store_mfn yet.
@@ -1035,7 +854,7 @@ static int __init xenbus_probe_init(void)
xen_store_evtchn = xen_start_info->store_evtchn =
alloc_unbound.port;
-#ifdef CONFIG_PROC_FS
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST)
/* And finally publish the above info in /proc/xen */
xsd_kva_intf = create_xen_proc_entry("xsd_kva", 0600);
if (xsd_kva_intf) {
@@ -1077,7 +896,7 @@ static int __init xenbus_probe_init(void)
/* Register ourselves with the kernel device subsystem */
device_register(&xenbus_frontend.dev);
- device_register(&xenbus_backend.dev);
+ xenbus_backend_device_register();
if (!is_initial_xendomain())
xenbus_probe(NULL);
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644
index 0000000000..2d2e567826
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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 _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern void xenbus_backend_bus_register(void);
+extern void xenbus_backend_device_register(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline void xenbus_backend_bus_register(void) {}
+static inline void xenbus_backend_device_register(void) {}
+#endif
+
+struct xen_bus_type
+{
+ char *root;
+ unsigned int levels;
+ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+ int (*probe)(const char *type, const char *dir);
+ struct bus_type bus;
+ struct device dev;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
+
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c
new file mode 100644
index 0000000000..934e79732d
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -0,0 +1,271 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have (backend half).
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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.
+ */
+
+#define DPRINTK(fmt, args...) \
+ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
+ __FUNCTION__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/maddr.h>
+#include <asm/pgtable.h>
+#include <asm/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/xen_proc.h>
+#include <xen/evtchn.h>
+#include <xen/features.h>
+#include <xen/hvm.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+static int xenbus_uevent_backend(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size);
+static int xenbus_probe_backend(const char *type, const char *domid);
+
+extern int read_otherend_details(struct xenbus_device *xendev,
+ char *id_node, char *path_node);
+
+static int read_frontend_details(struct xenbus_device *xendev)
+{
+ return read_otherend_details(xendev, "frontend-id", "frontend");
+}
+
+/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
+static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+ int domid, err;
+ const char *devid, *type, *frontend;
+ unsigned int typelen;
+
+ type = strchr(nodename, '/');
+ if (!type)
+ return -EINVAL;
+ type++;
+ typelen = strcspn(type, "/");
+ if (!typelen || type[typelen] != '/')
+ return -EINVAL;
+
+ devid = strrchr(nodename, '/') + 1;
+
+ err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
+ "frontend", NULL, &frontend,
+ NULL);
+ if (err)
+ return err;
+ if (strlen(frontend) == 0)
+ err = -ERANGE;
+ if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
+ err = -ENOENT;
+ kfree(frontend);
+
+ if (err)
+ return err;
+
+ if (snprintf(bus_id, BUS_ID_SIZE,
+ "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
+ return -ENOSPC;
+ return 0;
+}
+
+static struct xen_bus_type xenbus_backend = {
+ .root = "backend",
+ .levels = 3, /* backend/type/<frontend>/<id> */
+ .get_bus_id = backend_bus_id,
+ .probe = xenbus_probe_backend,
+ .bus = {
+ .name = "xen-backend",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+// .shutdown = xenbus_dev_shutdown,
+ .uevent = xenbus_uevent_backend,
+ },
+ .dev = {
+ .bus_id = "xen-backend",
+ },
+};
+
+static int xenbus_uevent_backend(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ struct xenbus_device *xdev;
+ struct xenbus_driver *drv;
+ int i = 0;
+ int length = 0;
+
+ DPRINTK("");
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ xdev = to_xenbus_device(dev);
+ if (xdev == NULL)
+ return -ENODEV;
+
+ /* stuff we want to pass to /sbin/hotplug */
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "XENBUS_TYPE=%s", xdev->devicetype);
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "XENBUS_PATH=%s", xdev->nodename);
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "XENBUS_BASE_PATH=%s", xenbus_backend.root);
+
+ /* terminate, set to next free slot, shrink available space */
+ envp[i] = NULL;
+ envp = &envp[i];
+ num_envp -= i;
+ buffer = &buffer[length];
+ buffer_size -= length;
+
+ if (dev->driver) {
+ drv = to_xenbus_driver(dev->driver);
+ if (drv && drv->uevent)
+ return drv->uevent(xdev, envp, num_envp, buffer,
+ buffer_size);
+ }
+
+ return 0;
+}
+
+int xenbus_register_backend(struct xenbus_driver *drv)
+{
+ drv->read_otherend_details = read_frontend_details;
+
+ return xenbus_register_driver_common(drv, &xenbus_backend);
+}
+EXPORT_SYMBOL_GPL(xenbus_register_backend);
+
+/* backend/<typename>/<frontend-uuid>/<name> */
+static int xenbus_probe_backend_unit(const char *dir,
+ const char *type,
+ const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s\n", nodename);
+
+ err = xenbus_probe_node(&xenbus_backend, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+/* backend/<typename>/<frontend-domid> */
+static int xenbus_probe_backend(const char *type, const char *domid)
+{
+ char *nodename;
+ int err = 0;
+ char **dir;
+ unsigned int i, dir_n = 0;
+
+ DPRINTK("");
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
+ if (!nodename)
+ return -ENOMEM;
+
+ dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
+ if (IS_ERR(dir)) {
+ kfree(nodename);
+ return PTR_ERR(dir);
+ }
+
+ for (i = 0; i < dir_n; i++) {
+ err = xenbus_probe_backend_unit(nodename, type, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ kfree(nodename);
+ return err;
+}
+
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ DPRINTK("");
+
+ dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
+}
+
+static struct xenbus_watch be_watch = {
+ .node = "backend",
+ .callback = backend_changed,
+};
+
+void xenbus_backend_suspend(int (*fn)(struct device *, void *))
+{
+ DPRINTK("");
+ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
+}
+
+void xenbus_backend_resume(int (*fn)(struct device *, void *))
+{
+ DPRINTK("");
+ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
+}
+
+void xenbus_backend_probe_and_watch(void)
+{
+ xenbus_probe_devices(&xenbus_backend);
+ register_xenbus_watch(&be_watch);
+}
+
+void xenbus_backend_bus_register(void)
+{
+ bus_register(&xenbus_backend.bus);
+}
+
+void xenbus_backend_device_register(void)
+{
+ device_register(&xenbus_backend.dev);
+}
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
index 190fa1e794..4c5052d13a 100644
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
@@ -42,11 +42,14 @@
#include <linux/fcntl.h>
#include <linux/kthread.h>
#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <xen/xenbus.h>
#include "xenbus_comms.h"
-/* xenbus_probe.c */
-extern char *kasprintf(const char *fmt, ...);
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
struct xs_stored_msg {
struct list_head list;
@@ -289,9 +292,9 @@ static char *join(const char *dir, const char *name)
char *buffer;
if (strlen(name) == 0)
- buffer = kasprintf("%s", dir);
+ buffer = kasprintf(GFP_KERNEL, "%s", dir);
else
- buffer = kasprintf("%s/%s", dir, name);
+ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
}
diff --git a/linux-2.6-xen-sparse/drivers/xen/xenoprof/xenoprofile.c b/linux-2.6-xen-sparse/drivers/xen/xenoprof/xenoprofile.c
new file mode 100644
index 0000000000..382a50f647
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/xen/xenoprof/xenoprofile.c
@@ -0,0 +1,500 @@
+/**
+ * @file xenoprofile.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * Modified by Aravind Menon and Jose Renato Santos for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
+ *
+ * Separated out arch-generic part
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ */
+
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <linux/oprofile.h>
+#include <linux/sysdev.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <asm/pgtable.h>
+#include <xen/evtchn.h>
+#include <xen/xenoprof.h>
+#include <xen/driver_util.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/xenoprof.h>
+#include "../../../drivers/oprofile/cpu_buffer.h"
+#include "../../../drivers/oprofile/event_buffer.h"
+
+#define MAX_XENOPROF_SAMPLES 16
+
+/* sample buffers shared with Xen */
+xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS];
+/* Shared buffer area */
+struct xenoprof_shared_buffer shared_buffer;
+
+/* Passive sample buffers shared with Xen */
+xenoprof_buf_t *p_xenoprof_buf[MAX_OPROF_DOMAINS][MAX_VIRT_CPUS];
+/* Passive shared buffer area */
+struct xenoprof_shared_buffer p_shared_buffer[MAX_OPROF_DOMAINS];
+
+static int xenoprof_start(void);
+static void xenoprof_stop(void);
+
+static int xenoprof_enabled = 0;
+static int xenoprof_is_primary = 0;
+static int active_defined;
+
+/* Number of buffers in shared area (one per VCPU) */
+int nbuf;
+/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */
+int ovf_irq[NR_CPUS];
+/* cpu model type string - copied from Xen memory space on XENOPROF_init command */
+char cpu_type[XENOPROF_CPU_TYPE_SIZE];
+
+#ifdef CONFIG_PM
+
+static int xenoprof_suspend(struct sys_device * dev, pm_message_t state)
+{
+ if (xenoprof_enabled == 1)
+ xenoprof_stop();
+ return 0;
+}
+
+
+static int xenoprof_resume(struct sys_device * dev)
+{
+ if (xenoprof_enabled == 1)
+ xenoprof_start();
+ return 0;
+}
+
+
+static struct sysdev_class oprofile_sysclass = {
+ set_kset_name("oprofile"),
+ .resume = xenoprof_resume,
+ .suspend = xenoprof_suspend
+};
+
+
+static struct sys_device device_oprofile = {
+ .id = 0,
+ .cls = &oprofile_sysclass,
+};
+
+
+static int __init init_driverfs(void)
+{
+ int error;
+ if (!(error = sysdev_class_register(&oprofile_sysclass)))
+ error = sysdev_register(&device_oprofile);
+ return error;
+}
+
+
+static void exit_driverfs(void)
+{
+ sysdev_unregister(&device_oprofile);
+ sysdev_class_unregister(&oprofile_sysclass);
+}
+
+#else
+#define init_driverfs() do { } while (0)
+#define exit_driverfs() do { } while (0)
+#endif /* CONFIG_PM */
+
+unsigned long long oprofile_samples = 0;
+unsigned long long p_oprofile_samples = 0;
+
+unsigned int pdomains;
+struct xenoprof_passive passive_domains[MAX_OPROF_DOMAINS];
+
+static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive)
+{
+ int head, tail, size;
+
+ head = buf->event_head;
+ tail = buf->event_tail;
+ size = buf->event_size;
+
+ if (tail > head) {
+ while (tail < size) {
+ oprofile_add_pc(buf->event_log[tail].eip,
+ buf->event_log[tail].mode,
+ buf->event_log[tail].event);
+ if (!is_passive)
+ oprofile_samples++;
+ else
+ p_oprofile_samples++;
+ tail++;
+ }
+ tail = 0;
+ }
+ while (tail < head) {
+ oprofile_add_pc(buf->event_log[tail].eip,
+ buf->event_log[tail].mode,
+ buf->event_log[tail].event);
+ if (!is_passive)
+ oprofile_samples++;
+ else
+ p_oprofile_samples++;
+ tail++;
+ }
+
+ buf->event_tail = tail;
+}
+
+static void xenoprof_handle_passive(void)
+{
+ int i, j;
+ int flag_domain, flag_switch = 0;
+
+ for (i = 0; i < pdomains; i++) {
+ flag_domain = 0;
+ for (j = 0; j < passive_domains[i].nbuf; j++) {
+ xenoprof_buf_t *buf = p_xenoprof_buf[i][j];
+ if (buf->event_head == buf->event_tail)
+ continue;
+ if (!flag_domain) {
+ if (!oprofile_add_domain_switch(passive_domains[i].
+ domain_id))
+ goto done;
+ flag_domain = 1;
+ }
+ xenoprof_add_pc(buf, 1);
+ flag_switch = 1;
+ }
+ }
+done:
+ if (flag_switch)
+ oprofile_add_domain_switch(COORDINATOR_DOMAIN);
+}
+
+static irqreturn_t
+xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+ struct xenoprof_buf * buf;
+ int cpu;
+ static unsigned long flag;
+
+ cpu = smp_processor_id();
+ buf = xenoprof_buf[cpu];
+
+ xenoprof_add_pc(buf, 0);
+
+ if (xenoprof_is_primary && !test_and_set_bit(0, &flag)) {
+ xenoprof_handle_passive();
+ smp_mb__before_clear_bit();
+ clear_bit(0, &flag);
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static void unbind_virq(void)
+{
+ int i;
+
+ for_each_online_cpu(i) {
+ if (ovf_irq[i] >= 0) {
+ unbind_from_irqhandler(ovf_irq[i], NULL);
+ ovf_irq[i] = -1;
+ }
+ }
+}
+
+
+static int bind_virq(void)
+{
+ int i, result;
+
+ for_each_online_cpu(i) {
+ result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
+ i,
+ xenoprof_ovf_interrupt,
+ SA_INTERRUPT,
+ "xenoprof",
+ NULL);
+
+ if (result < 0) {
+ unbind_virq();
+ return result;
+ }
+
+ ovf_irq[i] = result;
+ }
+
+ return 0;
+}
+
+
+static void unmap_passive_list(void)
+{
+ int i;
+ for (i = 0; i < pdomains; i++)
+ xenoprof_arch_unmap_shared_buffer(&p_shared_buffer[i]);
+ pdomains = 0;
+}
+
+
+static int map_xenoprof_buffer(int max_samples)
+{
+ struct xenoprof_get_buffer get_buffer;
+ struct xenoprof_buf *buf;
+ int ret, i;
+
+ if ( shared_buffer.buffer )
+ return 0;
+
+ get_buffer.max_samples = max_samples;
+ ret = xenoprof_arch_map_shared_buffer(&get_buffer, &shared_buffer);
+ if (ret)
+ return ret;
+ nbuf = get_buffer.nbuf;
+
+ for (i=0; i< nbuf; i++) {
+ buf = (struct xenoprof_buf*)
+ &shared_buffer.buffer[i * get_buffer.bufsize];
+ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
+ xenoprof_buf[buf->vcpu_id] = buf;
+ }
+
+ return 0;
+}
+
+
+static int xenoprof_setup(void)
+{
+ int ret;
+
+ if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) )
+ return ret;
+
+ if ( (ret = bind_virq()) )
+ return ret;
+
+ if (xenoprof_is_primary) {
+ /* Define dom0 as an active domain if not done yet */
+ if (!active_defined) {
+ domid_t domid;
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ if (ret)
+ goto err;
+ domid = 0;
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
+ if (ret)
+ goto err;
+ active_defined = 1;
+ }
+
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reserve_counters, NULL);
+ if (ret)
+ goto err;
+ xenoprof_arch_counter();
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_setup_events, NULL);
+
+ if (ret)
+ goto err;
+ }
+
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_enable_virq, NULL);
+ if (ret)
+ goto err;
+
+ xenoprof_enabled = 1;
+ return 0;
+ err:
+ unbind_virq();
+ return ret;
+}
+
+
+static void xenoprof_shutdown(void)
+{
+ xenoprof_enabled = 0;
+
+ HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL);
+
+ if (xenoprof_is_primary) {
+ HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL);
+ active_defined = 0;
+ }
+
+ unbind_virq();
+
+ xenoprof_arch_unmap_shared_buffer(&shared_buffer);
+ if (xenoprof_is_primary)
+ unmap_passive_list();
+}
+
+
+static int xenoprof_start(void)
+{
+ int ret = 0;
+
+ if (xenoprof_is_primary)
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_start, NULL);
+ if (!ret)
+ xenoprof_arch_start();
+ return ret;
+}
+
+
+static void xenoprof_stop(void)
+{
+ if (xenoprof_is_primary)
+ HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL);
+ xenoprof_arch_stop();
+}
+
+
+static int xenoprof_set_active(int * active_domains,
+ unsigned int adomains)
+{
+ int ret = 0;
+ int i;
+ int set_dom0 = 0;
+ domid_t domid;
+
+ if (!xenoprof_is_primary)
+ return 0;
+
+ if (adomains > MAX_OPROF_DOMAINS)
+ return -E2BIG;
+
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ if (ret)
+ return ret;
+
+ for (i=0; i<adomains; i++) {
+ domid = active_domains[i];
+ if (domid != active_domains[i]) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
+ if (ret)
+ goto out;
+ if (active_domains[i] == 0)
+ set_dom0 = 1;
+ }
+ /* dom0 must always be active but may not be in the list */
+ if (!set_dom0) {
+ domid = 0;
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
+ }
+
+out:
+ if (ret)
+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ active_defined = !ret;
+ return ret;
+}
+
+static int xenoprof_set_passive(int * p_domains,
+ unsigned int pdoms)
+{
+ int ret;
+ int i, j;
+ struct xenoprof_buf *buf;
+
+ if (!xenoprof_is_primary)
+ return 0;
+
+ if (pdoms > MAX_OPROF_DOMAINS)
+ return -E2BIG;
+
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_passive_list, NULL);
+ if (ret)
+ return ret;
+ unmap_passive_list();
+
+ for (i = 0; i < pdoms; i++) {
+ passive_domains[i].domain_id = p_domains[i];
+ passive_domains[i].max_samples = 2048;
+ ret = xenoprof_arch_set_passive(&passive_domains[i],
+ &p_shared_buffer[i]);
+ if (ret)
+ goto out;
+ for (j = 0; j < passive_domains[i].nbuf; j++) {
+ buf = (struct xenoprof_buf *)
+ &p_shared_buffer[i].buffer[j * passive_domains[i].bufsize];
+ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS);
+ p_xenoprof_buf[i][buf->vcpu_id] = buf;
+ }
+ }
+
+ pdomains = pdoms;
+ return 0;
+
+out:
+ for (j = 0; j < i; j++)
+ xenoprof_arch_unmap_shared_buffer(&p_shared_buffer[i]);
+
+ return ret;
+}
+
+struct oprofile_operations xenoprof_ops = {
+#ifdef HAVE_XENOPROF_CREATE_FILES
+ .create_files = xenoprof_create_files,
+#endif
+ .set_active = xenoprof_set_active,
+ .set_passive = xenoprof_set_passive,
+ .setup = xenoprof_setup,
+ .shutdown = xenoprof_shutdown,
+ .start = xenoprof_start,
+ .stop = xenoprof_stop
+};
+
+
+/* in order to get driverfs right */
+static int using_xenoprof;
+
+int __init xenoprofile_init(struct oprofile_operations * ops)
+{
+ struct xenoprof_init init;
+ int ret, i;
+
+ ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init);
+ if (!ret) {
+ xenoprof_arch_init_counter(&init);
+ xenoprof_is_primary = init.is_primary;
+
+ /* cpu_type is detected by Xen */
+ cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0;
+ strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1);
+ xenoprof_ops.cpu_type = cpu_type;
+
+ init_driverfs();
+ using_xenoprof = 1;
+ *ops = xenoprof_ops;
+
+ for (i=0; i<NR_CPUS; i++)
+ ovf_irq[i] = -1;
+
+ active_defined = 0;
+ }
+ printk(KERN_INFO "%s: ret %d, events %d, xenoprof_is_primary %d\n",
+ __func__, ret, init.num_events, xenoprof_is_primary);
+ return ret;
+}
+
+
+void xenoprofile_exit(void)
+{
+ if (using_xenoprof)
+ exit_driverfs();
+
+ xenoprof_arch_unmap_shared_buffer(&shared_buffer);
+ if (xenoprof_is_primary) {
+ unmap_passive_list();
+ HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL);
+ }
+}
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/fixmap.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/fixmap.h
index a6f3e9ea79..a9c3cc28fd 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/fixmap.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/fixmap.h
@@ -27,7 +27,6 @@ extern unsigned long __FIXADDR_TOP;
#include <asm/acpi.h>
#include <asm/apicdef.h>
#include <asm/page.h>
-#include <xen/gnttab.h>
#ifdef CONFIG_HIGHMEM
#include <linux/threads.h>
#include <asm/kmap_types.h>
@@ -99,7 +98,7 @@ enum fixed_addresses {
extern void __set_fixmap(enum fixed_addresses idx,
maddr_t phys, pgprot_t flags);
-extern void set_fixaddr_top(unsigned long top);
+extern void set_fixaddr_top(void);
#define set_fixmap(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL)
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
index 2e6d1fa596..a12e349016 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h
@@ -260,6 +260,8 @@ HYPERVISOR_event_channel_op(
int cmd, void *arg)
{
int rc = _hypercall2(int, event_channel_op, cmd, arg);
+
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
struct evtchn_op op;
op.cmd = cmd;
@@ -267,6 +269,8 @@ HYPERVISOR_event_channel_op(
rc = _hypercall1(int, event_channel_op_compat, &op);
memcpy(arg, &op.u, sizeof(op.u));
}
+#endif
+
return rc;
}
@@ -296,6 +300,8 @@ HYPERVISOR_physdev_op(
int cmd, void *arg)
{
int rc = _hypercall2(int, physdev_op, cmd, arg);
+
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
struct physdev_op op;
op.cmd = cmd;
@@ -303,6 +309,8 @@ HYPERVISOR_physdev_op(
rc = _hypercall1(int, physdev_op_compat, &op);
memcpy(arg, &op.u, sizeof(op.u));
}
+#endif
+
return rc;
}
@@ -350,9 +358,11 @@ HYPERVISOR_suspend(
int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
&sched_shutdown, srec);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown,
SHUTDOWN_suspend, srec);
+#endif
return rc;
}
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h
index 47586d22f9..f7904ac0b0 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypervisor.h
@@ -56,6 +56,10 @@
extern shared_info_t *HYPERVISOR_shared_info;
+#ifdef CONFIG_X86_32
+extern unsigned long hypervisor_virt_start;
+#endif
+
/* arch/xen/i386/kernel/setup.c */
extern start_info_t *xen_start_info;
#ifdef CONFIG_XEN_PRIVILEGED_GUEST
@@ -94,7 +98,6 @@ void xen_pgd_pin(unsigned long ptr);
void xen_pgd_unpin(unsigned long ptr);
void xen_set_ldt(unsigned long ptr, unsigned long bytes);
-void xen_machphys_update(unsigned long mfn, unsigned long pfn);
#ifdef CONFIG_SMP
#include <linux/cpumask.h>
@@ -131,8 +134,10 @@ HYPERVISOR_yield(
{
int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
+#endif
return rc;
}
@@ -143,8 +148,10 @@ HYPERVISOR_block(
{
int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0);
+#endif
return rc;
}
@@ -159,8 +166,10 @@ HYPERVISOR_shutdown(
int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason);
+#endif
return rc;
}
@@ -177,8 +186,10 @@ HYPERVISOR_poll(
set_xen_guest_handle(sched_poll.ports, ports);
rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
+#endif
return rc;
}
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h
index 7f9b7cdd36..ed5203a573 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/io.h
@@ -54,7 +54,8 @@
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
*/
-#define xlate_dev_mem_ptr(p) __va(p)
+#define xlate_dev_mem_ptr(p, sz) ioremap(p, sz)
+#define xlate_dev_mem_ptr_unmap(p) iounmap(p)
/*
* Convert a virtual cached pointer to an uncached pointer
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/maddr.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/maddr.h
index b467320d5c..f805d6ea60 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/maddr.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/maddr.h
@@ -9,6 +9,15 @@
#define FOREIGN_FRAME_BIT (1UL<<31)
#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
+/* Definitions for machine and pseudophysical addresses. */
+#ifdef CONFIG_X86_PAE
+typedef unsigned long long paddr_t;
+typedef unsigned long long maddr_t;
+#else
+typedef unsigned long paddr_t;
+typedef unsigned long maddr_t;
+#endif
+
#ifdef CONFIG_XEN
extern unsigned long *phys_to_machine_mapping;
@@ -101,32 +110,13 @@ static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
phys_to_machine_mapping[pfn] = mfn;
}
-
-#else /* !CONFIG_XEN */
-
-#define pfn_to_mfn(pfn) (pfn)
-#define mfn_to_pfn(mfn) (mfn)
-#define mfn_to_local_pfn(mfn) (mfn)
-#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
-#define phys_to_machine_mapping_valid(pfn) (1)
-
-#endif /* !CONFIG_XEN */
-
-/* Definitions for machine and pseudophysical addresses. */
-#ifdef CONFIG_X86_PAE
-typedef unsigned long long paddr_t;
-typedef unsigned long long maddr_t;
-#else
-typedef unsigned long paddr_t;
-typedef unsigned long maddr_t;
-#endif
-
static inline maddr_t phys_to_machine(paddr_t phys)
{
maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
return machine;
}
+
static inline paddr_t machine_to_phys(maddr_t machine)
{
paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
@@ -134,6 +124,32 @@ static inline paddr_t machine_to_phys(maddr_t machine)
return phys;
}
+static inline paddr_t pte_machine_to_phys(maddr_t machine)
+{
+ /*
+ * In PAE mode, the NX bit needs to be dealt with in the value
+ * passed to mfn_to_pfn(). On x86_64, we need to mask it off,
+ * but for i386 the conversion to ulong for the argument will
+ * clip it off.
+ */
+ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT);
+ phys = (phys << PAGE_SHIFT) | (machine & ~PHYSICAL_PAGE_MASK);
+ return phys;
+}
+
+#else /* !CONFIG_XEN */
+
+#define pfn_to_mfn(pfn) (pfn)
+#define mfn_to_pfn(mfn) (mfn)
+#define mfn_to_local_pfn(mfn) (mfn)
+#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
+#define phys_to_machine_mapping_valid(pfn) (1)
+#define phys_to_machine(phys) ((maddr_t)(phys))
+#define machine_to_phys(mach) ((paddr_t)(mach))
+#define pte_machine_to_phys(mach) ((paddr_t)(mach))
+
+#endif /* !CONFIG_XEN */
+
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(v) (phys_to_machine(__pa(v)))
#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h
index 0f829c8cd3..ff183db39e 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h
@@ -6,6 +6,16 @@
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
+#ifdef CONFIG_X86_PAE
+#define __PHYSICAL_MASK_SHIFT 36
+#define __PHYSICAL_MASK ((1ULL << __PHYSICAL_MASK_SHIFT) - 1)
+#define PHYSICAL_PAGE_MASK (~((1ULL << PAGE_SHIFT) - 1) & __PHYSICAL_MASK)
+#else
+#define __PHYSICAL_MASK_SHIFT 32
+#define __PHYSICAL_MASK (~0UL)
+#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
+#endif
+
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
@@ -85,7 +95,7 @@ static inline unsigned long long pte_val(pte_t x)
if (x.pte_low) {
ret = x.pte_low | (unsigned long long)x.pte_high << 32;
- ret = machine_to_phys(ret) | 1;
+ ret = pte_machine_to_phys(ret) | 1;
} else {
ret = 0;
}
@@ -94,13 +104,13 @@ static inline unsigned long long pte_val(pte_t x)
static inline unsigned long long pmd_val(pmd_t x)
{
unsigned long long ret = x.pmd;
- if (ret) ret = machine_to_phys(ret) | 1;
+ if (ret) ret = pte_machine_to_phys(ret) | 1;
return ret;
}
static inline unsigned long long pgd_val(pgd_t x)
{
unsigned long long ret = x.pgd;
- if (ret) ret = machine_to_phys(ret) | 1;
+ if (ret) ret = pte_machine_to_phys(ret) | 1;
return ret;
}
static inline unsigned long long pte_val_ma(pte_t x)
@@ -115,7 +125,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define pgprot_val(x) ((x).pgprot)
#include <asm/maddr.h>
#define boot_pte_t pte_t /* or would you rather have a typedef */
-#define pte_val(x) (((x).pte_low & 1) ? machine_to_phys((x).pte_low) : \
+#define pte_val(x) (((x).pte_low & 1) ? \
+ pte_machine_to_phys((x).pte_low) : \
(x).pte_low)
#define pte_val_ma(x) ((x).pte_low)
#define __pte(x) ({ unsigned long _x = (x); \
@@ -125,7 +136,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
static inline unsigned long pgd_val(pgd_t x)
{
unsigned long ret = x.pgd;
- if (ret) ret = machine_to_phys(ret) | 1;
+ if (ret) ret = pte_machine_to_phys(ret) | 1;
return ret;
}
#define HPAGE_SHIFT 22
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h
index 3791d2de39..bd6346f410 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h
@@ -9,7 +9,6 @@
#define PGDIR_SHIFT 22
#define PTRS_PER_PGD 1024
-#define PTRS_PER_PGD_NO_HV (HYPERVISOR_VIRT_START >> PGDIR_SHIFT)
/*
* the i386 is two-level, so we don't really have any
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h
index 10445c142c..148c8d9e78 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h
@@ -8,7 +8,6 @@
*/
#define PGDIR_SHIFT 30
#define PTRS_PER_PGD 4
-#define PTRS_PER_PGD_NO_HV 4
/*
* PMD_SHIFT determines the size of the area a middle-level
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/synch_bitops.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/synch_bitops.h
index 6a4e5e4508..807ca388c5 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/synch_bitops.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/synch_bitops.h
@@ -9,6 +9,10 @@
#include <linux/config.h>
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
#define ADDR (*(volatile long *) addr)
static __inline__ void synch_set_bit(int nr, volatile void * addr)
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/xenoprof.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/xenoprof.h
new file mode 100644
index 0000000000..2733e00ee4
--- /dev/null
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/xenoprof.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * asm-i386/mach-xen/asm/xenoprof.h
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __ASM_XENOPROF_H__
+#define __ASM_XENOPROF_H__
+#ifdef CONFIG_XEN
+
+struct super_block;
+struct dentry;
+int xenoprof_create_files(struct super_block * sb, struct dentry * root);
+#define HAVE_XENOPROF_CREATE_FILES
+
+struct xenoprof_init;
+void xenoprof_arch_init_counter(struct xenoprof_init *init);
+void xenoprof_arch_counter(void);
+void xenoprof_arch_start(void);
+void xenoprof_arch_stop(void);
+
+struct xenoprof_arch_shared_buffer {
+ /* nothing */
+};
+struct xenoprof_shared_buffer;
+void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf);
+struct xenoprof_get_buffer;
+int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, struct xenoprof_shared_buffer* sbuf);
+struct xenoprof_passive;
+int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, struct xenoprof_shared_buffer* sbuf);
+
+#endif /* CONFIG_XEN */
+#endif /* __ASM_XENOPROF_H__ */
diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h
index 0f1caa0604..bed1e1d211 100644
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h
@@ -56,15 +56,15 @@ static void __init machine_specific_arch_setup(void)
struct xen_machphys_mapping mapping;
unsigned long machine_to_phys_nr_ents;
struct xen_platform_parameters pp;
- struct callback_register event = {
+ static struct callback_register __initdata event = {
.type = CALLBACKTYPE_event,
.address = { __KERNEL_CS, (unsigned long)hypervisor_callback },
};
- struct callback_register failsafe = {
+ static struct callback_register __initdata failsafe = {
.type = CALLBACKTYPE_failsafe,
.address = { __KERNEL_CS, (unsigned long)failsafe_callback },
};
- struct callback_register nmi_cb = {
+ static struct callback_register __initdata nmi_cb = {
.type = CALLBACKTYPE_nmi,
.address = { __KERNEL_CS, (unsigned long)nmi },
};
@@ -72,23 +72,30 @@ static void __init machine_specific_arch_setup(void)
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
if (ret == 0)
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
+#ifdef CONFIG_XEN_COMPAT_030002
if (ret == -ENOSYS)
ret = HYPERVISOR_set_callbacks(
event.address.cs, event.address.eip,
failsafe.address.cs, failsafe.address.eip);
+#endif
BUG_ON(ret);
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+#ifdef CONFIG_XEN_COMPAT_030002
if (ret == -ENOSYS) {
- struct xennmi_callback cb;
+ static struct xennmi_callback __initdata cb = {
+ .handler_address = (unsigned long)nmi
+ };
- cb.handler_address = nmi_cb.address.eip;
HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
}
+#endif
if (HYPERVISOR_xen_version(XENVER_platform_parameters,
- &pp) == 0)
- set_fixaddr_top(pp.virt_start - PAGE_SIZE);
+ &pp) == 0) {
+ hypervisor_virt_start = pp.virt_start;
+ set_fixaddr_top();
+ }
machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h
index 8375336941..7a522be483 100644
--- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h
+++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h
@@ -33,12 +33,13 @@
#ifndef __HYPERCALL_H__
#define __HYPERCALL_H__
-#include <linux/string.h> /* memcpy() */
-
#ifndef __HYPERVISOR_H__
# error "please don't include this file directly"
#endif
+#include <asm/xen/xcom_hcall.h>
+struct xencomm_handle;
+
/*
* Assembler stubs for hyper-calls.
*/
@@ -157,157 +158,117 @@
(type)__res; \
})
-static inline int
-HYPERVISOR_sched_op_compat(
- int cmd, unsigned long arg)
-{
- return _hypercall2(int, sched_op_compat, cmd, arg);
-}
static inline int
-HYPERVISOR_sched_op(
- int cmd, void *arg)
+xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg)
{
return _hypercall2(int, sched_op, cmd, arg);
}
static inline long
-HYPERVISOR_set_timer_op(
- u64 timeout)
+HYPERVISOR_set_timer_op(u64 timeout)
{
- unsigned long timeout_hi = (unsigned long)(timeout>>32);
- unsigned long timeout_lo = (unsigned long)timeout;
- return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+ unsigned long timeout_hi = (unsigned long)(timeout >> 32);
+ unsigned long timeout_lo = (unsigned long)timeout;
+ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
}
static inline int
-HYPERVISOR_dom0_op(
- dom0_op_t *dom0_op)
+xencomm_arch_hypercall_dom0_op(struct xencomm_handle *op)
{
- dom0_op->interface_version = DOM0_INTERFACE_VERSION;
- return _hypercall1(int, dom0_op, dom0_op);
+ return _hypercall1(int, dom0_op, op);
}
static inline int
-HYPERVISOR_multicall(
- void *call_list, int nr_calls)
+xencomm_arch_hypercall_sysctl(struct xencomm_handle *op)
{
- return _hypercall2(int, multicall, call_list, nr_calls);
+ return _hypercall1(int, sysctl, op);
}
-//XXX xen/ia64 copy_from_guest() is broken.
-// This is a temporal work around until it is fixed.
static inline int
-____HYPERVISOR_memory_op(
- unsigned int cmd, void *arg)
+xencomm_arch_hypercall_domctl(struct xencomm_handle *op)
{
- return _hypercall2(int, memory_op, cmd, arg);
+ return _hypercall1(int, domctl, op);
}
-#include <xen/interface/memory.h>
-#ifdef CONFIG_VMX_GUEST
-# define ia64_xenmem_reservation_op(op, xmr) (0)
-#else
-int ia64_xenmem_reservation_op(unsigned long op,
- struct xen_memory_reservation* reservation__);
-#endif
static inline int
-HYPERVISOR_memory_op(
- unsigned int cmd, void *arg)
+xencomm_arch_hypercall_multicall(struct xencomm_handle *call_list,
+ int nr_calls)
{
- switch (cmd) {
- case XENMEM_increase_reservation:
- case XENMEM_decrease_reservation:
- case XENMEM_populate_physmap:
- return ia64_xenmem_reservation_op(cmd,
- (struct xen_memory_reservation*)arg);
- default:
- return ____HYPERVISOR_memory_op(cmd, arg);
- }
- /* NOTREACHED */
+ return _hypercall2(int, multicall, call_list, nr_calls);
}
static inline int
-HYPERVISOR_event_channel_op(
- int cmd, void *arg)
+xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg)
{
- int rc = _hypercall2(int, event_channel_op, cmd, arg);
- if (unlikely(rc == -ENOSYS)) {
- struct evtchn_op op;
- op.cmd = cmd;
- memcpy(&op.u, arg, sizeof(op.u));
- rc = _hypercall1(int, event_channel_op_compat, &op);
- }
- return rc;
+ return _hypercall2(int, memory_op, cmd, arg);
}
static inline int
-HYPERVISOR_acm_op(
- unsigned int cmd, void *arg)
+xencomm_arch_hypercall_event_channel_op(int cmd, struct xencomm_handle *arg)
{
- return _hypercall2(int, acm_op, cmd, arg);
+ return _hypercall2(int, event_channel_op, cmd, arg);
}
static inline int
-HYPERVISOR_xen_version(
- int cmd, void *arg)
+xencomm_arch_hypercall_acm_op(unsigned int cmd, struct xencomm_handle *arg)
{
- return _hypercall2(int, xen_version, cmd, arg);
+ return _hypercall2(int, acm_op, cmd, arg);
}
static inline int
-HYPERVISOR_console_io(
- int cmd, int count, char *str)
+xencomm_arch_hypercall_xen_version(int cmd, struct xencomm_handle *arg)
{
- return _hypercall3(int, console_io, cmd, count, str);
+ return _hypercall2(int, xen_version, cmd, arg);
}
static inline int
-HYPERVISOR_physdev_op(
- int cmd, void *arg)
+xencomm_arch_hypercall_console_io(int cmd, int count,
+ struct xencomm_handle *str)
{
- int rc = _hypercall2(int, physdev_op, cmd, arg);
- if (unlikely(rc == -ENOSYS)) {
- struct physdev_op op;
- op.cmd = cmd;
- memcpy(&op.u, arg, sizeof(op.u));
- rc = _hypercall1(int, physdev_op_compat, &op);
- }
- return rc;
+ return _hypercall3(int, console_io, cmd, count, str);
}
-//XXX __HYPERVISOR_grant_table_op is used for this hypercall constant.
static inline int
-____HYPERVISOR_grant_table_op(
- unsigned int cmd, void *uop, unsigned int count,
- unsigned long pa1, unsigned long pa2)
+xencomm_arch_hypercall_physdev_op(int cmd, struct xencomm_handle *arg)
{
- return _hypercall5(int, grant_table_op, cmd, uop, count, pa1, pa2);
+ return _hypercall2(int, physdev_op, cmd, arg);
+}
+
+static inline int
+xencomm_arch_hypercall_grant_table_op(unsigned int cmd,
+ struct xencomm_handle *uop,
+ unsigned int count)
+{
+ return _hypercall3(int, grant_table_op, cmd, uop, count);
}
int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count);
+extern int xencomm_arch_hypercall_suspend(struct xencomm_handle *arg);
+
static inline int
-HYPERVISOR_vcpu_op(
- int cmd, int vcpuid, void *extra_args)
+xencomm_arch_hypercall_callback_op(int cmd, struct xencomm_handle *arg)
{
- return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+ return _hypercall2(int, callback_op, cmd, arg);
}
-extern int HYPERVISOR_suspend(unsigned long srec);
-
static inline unsigned long
-HYPERVISOR_hvm_op(
- int cmd, void *arg)
+xencomm_arch_hypercall_hvm_op(int cmd, void *arg)
{
return _hypercall2(unsigned long, hvm_op, cmd, arg);
}
static inline int
-HYPERVISOR_callback_op(
- int cmd, void *arg)
+HYPERVISOR_physdev_op(int cmd, void *arg)
{
- return _hypercall2(int, callback_op, cmd, arg);
+ switch (cmd) {
+ case PHYSDEVOP_eoi:
+ return _hypercall1(int, ia64_fast_eoi,
+ ((struct physdev_eoi *)arg)->irq);
+ default:
+ return xencomm_hypercall_physdev_op(cmd, arg);
+ }
}
extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
@@ -322,6 +283,9 @@ static inline void exit_idle(void) {}
#ifdef CONFIG_XEN
#include <asm/xen/privop.h>
#endif /* CONFIG_XEN */
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
static inline unsigned long
__HYPERVISOR_ioremap(unsigned long ioaddr, unsigned long size)
@@ -417,7 +381,42 @@ HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn,
return ret;
}
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+static inline unsigned long
+HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn,
+ unsigned long assign_start_gpfn,
+ unsigned long expose_size, unsigned long granule_pfn)
+{
+ return _hypercall5(unsigned long, ia64_dom0vp_op,
+ IA64_DOM0VP_expose_p2m, conv_start_gpfn,
+ assign_start_gpfn, expose_size, granule_pfn);
+}
+#endif
+
// for balloon driver
#define HYPERVISOR_update_va_mapping(va, new_val, flags) (0)
+/* Use xencomm to do hypercalls. */
+#ifdef MODULE
+#define HYPERVISOR_sched_op xencomm_mini_hypercall_sched_op
+#define HYPERVISOR_event_channel_op xencomm_mini_hypercall_event_channel_op
+#define HYPERVISOR_callback_op xencomm_mini_hypercall_callback_op
+#define HYPERVISOR_multicall xencomm_mini_hypercall_multicall
+#define HYPERVISOR_xen_version xencomm_mini_hypercall_xen_version
+#define HYPERVISOR_console_io xencomm_mini_hypercall_console_io
+#define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op
+#define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op
+#else
+#define HYPERVISOR_sched_op xencomm_hypercall_sched_op
+#define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op
+#define HYPERVISOR_callback_op xencomm_hypercall_callback_op
+#define HYPERVISOR_multicall xencomm_hypercall_multicall
+#define HYPERVISOR_xen_version xencomm_hypercall_xen_version
+#define HYPERVISOR_console_io xencomm_hypercall_console_io
+#define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op
+#define HYPERVISOR_memory_op xencomm_hypercall_memory_op
+#endif
+
+#define HYPERVISOR_suspend xencomm_hypercall_suspend
+
#endif /* __HYPERCALL_H__ */
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h
index 7b1a9a7fc9..083884c130 100644
--- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h
+++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h
@@ -75,9 +75,6 @@ HYPERVISOR_yield(
{
int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
- if (rc == -ENOSYS)
- rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
-
return rc;
}
@@ -87,9 +84,6 @@ HYPERVISOR_block(
{
int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL);
- if (rc == -ENOSYS)
- rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0);
-
return rc;
}
@@ -103,9 +97,6 @@ HYPERVISOR_shutdown(
int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
- if (rc == -ENOSYS)
- rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason);
-
return rc;
}
@@ -122,8 +113,6 @@ HYPERVISOR_poll(
set_xen_guest_handle(sched_poll.ports, ports);
rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll);
- if (rc == -ENOSYS)
- rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0);
return rc;
}
@@ -138,6 +127,7 @@ int direct_remap_pfn_range(struct vm_area_struct *vma,
pgprot_t prot,
domid_t domid);
struct file;
+int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
int privcmd_mmap(struct file * file, struct vm_area_struct * vma);
#define HAVE_ARCH_PRIVCMD_MMAP
@@ -201,6 +191,22 @@ MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd,
mcl->args[2] = count;
}
+/*
+ * for blktap.c
+ * int create_lookup_pte_addr(struct mm_struct *mm,
+ * unsigned long address,
+ * uint64_t *ptep);
+ */
+#define create_lookup_pte_addr(mm, address, ptep) \
+ ({ \
+ printk(KERN_EMERG \
+ "%s:%d " \
+ "create_lookup_pte_addr() isn't supported.\n", \
+ __func__, __LINE__); \
+ BUG(); \
+ (-ENOSYS); \
+ })
+
// for debug
asmlinkage int xprintk(const char *fmt, ...);
#define xprintd(fmt, ...) xprintk("%s:%d " fmt, __func__, __LINE__, \
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/maddr.h b/linux-2.6-xen-sparse/include/asm-ia64/maddr.h
index 55c6f94d10..cbdef5a96e 100644
--- a/linux-2.6-xen-sparse/include/asm-ia64/maddr.h
+++ b/linux-2.6-xen-sparse/include/asm-ia64/maddr.h
@@ -10,11 +10,26 @@
#define INVALID_P2M_ENTRY (~0UL)
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+extern int p2m_initialized;
+extern unsigned long p2m_min_low_pfn;
+extern unsigned long p2m_max_low_pfn;
+extern unsigned long p2m_convert_min_pfn;
+extern unsigned long p2m_convert_max_pfn;
+extern volatile const pte_t* p2m_pte;
+unsigned long p2m_phystomach(unsigned long gpfn);
+#else
+#define p2m_initialized (0)
+#define p2m_phystomach(gpfn) INVALID_MFN
+#endif
+
/* XXX xen page size != page size */
static inline unsigned long
pfn_to_mfn_for_dma(unsigned long pfn)
{
unsigned long mfn;
+ if (p2m_initialized)
+ return p2m_phystomach(pfn);
mfn = HYPERVISOR_phystomach(pfn);
BUG_ON(mfn == 0); // XXX
BUG_ON(mfn == INVALID_P2M_ENTRY); // XXX
@@ -81,11 +96,6 @@ mfn_to_local_pfn(unsigned long mfn)
#define virt_to_machine(virt) __pa(virt) // for tpmfront.c
#define set_phys_to_machine(pfn, mfn) do { } while (0)
-#ifdef CONFIG_VMX_GUEST
-extern void xen_machphys_update(unsigned long mfn, unsigned long pfn);
-#else /* CONFIG_VMX_GUEST */
-#define xen_machphys_update(mfn, pfn) do { } while (0)
-#endif /* CONFIG_VMX_GUEST */
typedef unsigned long maddr_t; // to compile netback, netfront
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h
index 073b3a2a77..6f3c20a8ed 100644
--- a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h
+++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h
@@ -14,12 +14,9 @@
#define IA64_PARAVIRTUALIZED
-#if 0
-#undef XSI_BASE
/* At 1 MB, before per-cpu space but still addressable using addl instead
of movl. */
#define XSI_BASE 0xfffffffffff00000
-#endif
/* Address of mapped regs. */
#define XMAPPEDREGS_BASE (XSI_BASE + XSI_SIZE)
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h
new file mode 100644
index 0000000000..3c073a71cd
--- /dev/null
+++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006 Tristan Gingold <tristan.gingold@bull.net>, Bull SAS
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LINUX_XENCOMM_HCALL_H_
+#define _LINUX_XENCOMM_HCALL_H_
+
+/* These function creates inline descriptor for the parameters and
+ calls the corresponding xencomm_arch_hypercall_X.
+ Architectures should defines HYPERVISOR_xxx as xencomm_hypercall_xxx unless
+ they want to use their own wrapper. */
+extern int xencomm_hypercall_console_io(int cmd, int count, char *str);
+
+extern int xencomm_hypercall_event_channel_op(int cmd, void *op);
+
+extern int xencomm_hypercall_xen_version(int cmd, void *arg);
+
+extern int xencomm_hypercall_physdev_op(int cmd, void *op);
+
+extern int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
+ unsigned int count);
+
+extern int xencomm_hypercall_sched_op(int cmd, void *arg);
+
+extern int xencomm_hypercall_multicall(void *call_list, int nr_calls);
+
+extern int xencomm_hypercall_callback_op(int cmd, void *arg);
+
+extern int xencomm_hypercall_memory_op(unsigned int cmd, void *arg);
+
+extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg);
+
+extern int xencomm_hypercall_suspend(unsigned long srec);
+
+/* Using mini xencomm. */
+extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str);
+
+extern int xencomm_mini_hypercall_event_channel_op(int cmd, void *op);
+
+extern int xencomm_mini_hypercall_xen_version(int cmd, void *arg);
+
+extern int xencomm_mini_hypercall_physdev_op(int cmd, void *op);
+
+extern int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op,
+ unsigned int count);
+
+extern int xencomm_mini_hypercall_sched_op(int cmd, void *arg);
+
+extern int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls);
+
+extern int xencomm_mini_hypercall_callback_op(int cmd, void *arg);
+
+extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg);
+
+extern unsigned long xencomm_mini_hypercall_hvm_op(int cmd, void *arg);
+
+/* For privcmd. Locally declare argument type to avoid include storm.
+ Type coherency will be checked within privcmd.c */
+struct privcmd_hypercall;
+extern int privcmd_hypercall(struct privcmd_hypercall *hypercall);
+
+#endif /* _LINUX_XENCOMM_HCALL_H_ */
diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h
new file mode 100644
index 0000000000..eae11369f1
--- /dev/null
+++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LINUX_XENCOMM_H_
+#define _LINUX_XENCOMM_H_
+
+#include <xen/interface/xencomm.h>
+
+#define XENCOMM_MINI_ADDRS 3
+struct xencomm_mini {
+ struct xencomm_desc _desc;
+ uint64_t address[XENCOMM_MINI_ADDRS];
+};
+
+/* Must be called before any hypercall. */
+extern void xencomm_init (void);
+
+/* To avoid additionnal virt to phys conversion, an opaque structure is
+ presented. */
+struct xencomm_handle;
+
+extern int xencomm_create(void *buffer, unsigned long bytes,
+ struct xencomm_handle **desc, gfp_t type);
+extern void xencomm_free(struct xencomm_handle *desc);
+
+extern int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area,
+ void *buffer, unsigned long bytes,
+ struct xencomm_handle **ret);
+
+/* Translate virtual address to physical address. */
+extern unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr);
+
+/* Inline version. To be used only on linear space (kernel space). */
+static inline struct xencomm_handle *
+xencomm_create_inline(void *buffer)
+{
+ unsigned long paddr;
+
+ paddr = xencomm_vaddr_to_paddr((unsigned long)buffer);
+ return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
+}
+
+#define xen_guest_handle(hnd) ((hnd).p)
+
+#endif /* _LINUX_XENCOMM_H_ */
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/fixmap.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/fixmap.h
index 64ae42e1aa..29beed9512 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/fixmap.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/fixmap.h
@@ -14,7 +14,6 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/apicdef.h>
-#include <xen/gnttab.h>
#include <asm/page.h>
#include <asm/vsyscall.h>
#include <asm/vsyscall32.h>
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h
index 14fb01d3d2..956a4c4b0d 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h
@@ -258,6 +258,8 @@ HYPERVISOR_event_channel_op(
int cmd, void *arg)
{
int rc = _hypercall2(int, event_channel_op, cmd, arg);
+
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
struct evtchn_op op;
op.cmd = cmd;
@@ -265,6 +267,8 @@ HYPERVISOR_event_channel_op(
rc = _hypercall1(int, event_channel_op_compat, &op);
memcpy(arg, &op.u, sizeof(op.u));
}
+#endif
+
return rc;
}
@@ -294,6 +298,8 @@ HYPERVISOR_physdev_op(
int cmd, void *arg)
{
int rc = _hypercall2(int, physdev_op, cmd, arg);
+
+#ifdef CONFIG_XEN_COMPAT_030002
if (unlikely(rc == -ENOSYS)) {
struct physdev_op op;
op.cmd = cmd;
@@ -301,6 +307,8 @@ HYPERVISOR_physdev_op(
rc = _hypercall1(int, physdev_op_compat, &op);
memcpy(arg, &op.u, sizeof(op.u));
}
+#endif
+
return rc;
}
@@ -351,9 +359,11 @@ HYPERVISOR_suspend(
int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown,
&sched_shutdown, srec);
+#ifdef CONFIG_XEN_COMPAT_030002
if (rc == -ENOSYS)
rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown,
SHUTDOWN_suspend, srec);
+#endif
return rc;
}
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h
index 1ae9c89ba9..4d13b1b9c7 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/io.h
@@ -346,7 +346,8 @@ extern int iommu_bio_merge;
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
*/
-#define xlate_dev_mem_ptr(p) __va(p)
+#define xlate_dev_mem_ptr(p, sz) ioremap(p, sz)
+#define xlate_dev_mem_ptr_unmap(p) iounmap(p)
/*
* Convert a virtual cached pointer to an uncached pointer
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/maddr.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/maddr.h
index 0104de8082..77544b3ca2 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/maddr.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/maddr.h
@@ -9,6 +9,10 @@
#define FOREIGN_FRAME_BIT (1UL<<63)
#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
+/* Definitions for machine and pseudophysical addresses. */
+typedef unsigned long paddr_t;
+typedef unsigned long maddr_t;
+
#ifdef CONFIG_XEN
extern unsigned long *phys_to_machine_mapping;
@@ -99,20 +103,6 @@ static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
phys_to_machine_mapping[pfn] = mfn;
}
-#else /* !CONFIG_XEN */
-
-#define pfn_to_mfn(pfn) (pfn)
-#define mfn_to_pfn(mfn) (mfn)
-#define mfn_to_local_pfn(mfn) (mfn)
-#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
-#define phys_to_machine_mapping_valid(pfn) (1)
-
-#endif /* !CONFIG_XEN */
-
-/* Definitions for machine and pseudophysical addresses. */
-typedef unsigned long paddr_t;
-typedef unsigned long maddr_t;
-
static inline maddr_t phys_to_machine(paddr_t phys)
{
maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT);
@@ -127,6 +117,27 @@ static inline paddr_t machine_to_phys(maddr_t machine)
return phys;
}
+static inline paddr_t pte_machine_to_phys(maddr_t machine)
+{
+ paddr_t phys;
+ phys = mfn_to_pfn((machine & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT);
+ phys = (phys << PAGE_SHIFT) | (machine & ~PHYSICAL_PAGE_MASK);
+ return phys;
+}
+
+#else /* !CONFIG_XEN */
+
+#define pfn_to_mfn(pfn) (pfn)
+#define mfn_to_pfn(mfn) (mfn)
+#define mfn_to_local_pfn(mfn) (mfn)
+#define set_phys_to_machine(pfn, mfn) BUG_ON((pfn) != (mfn))
+#define phys_to_machine_mapping_valid(pfn) (1)
+#define phys_to_machine(phys) ((maddr_t)(phys))
+#define machine_to_phys(mach) ((paddr_t)(mach))
+#define pte_machine_to_phys(mach) ((paddr_t)(mach))
+
+#endif /* !CONFIG_XEN */
+
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(v) (phys_to_machine(__pa(v)))
#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT))
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h
index cd23862b05..7573cce405 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h
@@ -33,6 +33,13 @@
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK (~(PAGE_SIZE-1))
+
+/* See Documentation/x86_64/mm.txt for a description of the memory map. */
+#define __PHYSICAL_MASK_SHIFT 46
+#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)
+#define __VIRTUAL_MASK_SHIFT 48
+#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
+
#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
#define THREAD_ORDER 1
@@ -90,28 +97,28 @@ typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
-#define pte_val(x) (((x).pte & 1) ? machine_to_phys((x).pte) : \
+#define pte_val(x) (((x).pte & 1) ? pte_machine_to_phys((x).pte) : \
(x).pte)
#define pte_val_ma(x) ((x).pte)
static inline unsigned long pmd_val(pmd_t x)
{
unsigned long ret = x.pmd;
- if (ret) ret = machine_to_phys(ret);
+ if (ret) ret = pte_machine_to_phys(ret);
return ret;
}
static inline unsigned long pud_val(pud_t x)
{
unsigned long ret = x.pud;
- if (ret) ret = machine_to_phys(ret);
+ if (ret) ret = pte_machine_to_phys(ret);
return ret;
}
static inline unsigned long pgd_val(pgd_t x)
{
unsigned long ret = x.pgd;
- if (ret) ret = machine_to_phys(ret);
+ if (ret) ret = pte_machine_to_phys(ret);
return ret;
}
@@ -163,12 +170,6 @@ static inline pgd_t __pgd(unsigned long x)
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* See Documentation/x86_64/mm.txt for a description of the memory map. */
-#define __PHYSICAL_MASK_SHIFT 46
-#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)
-#define __VIRTUAL_MASK_SHIFT 48
-#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
-
#define KERNEL_TEXT_SIZE (40UL*1024*1024)
#define KERNEL_TEXT_START 0xffffffff80000000UL
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
index ff6d94f9e0..0c4d0a888e 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/pgtable.h
@@ -205,8 +205,14 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
#define _PAGE_PROTNONE 0x080 /* If not present */
#define _PAGE_NX (1UL<<_PAGE_BIT_NX)
+#ifdef CONFIG_XEN_COMPAT_030002
+extern unsigned int __kernel_page_user;
+#else
+#define __kernel_page_user 0
+#endif
+
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user)
#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -219,13 +225,13 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
#define __PAGE_KERNEL_EXEC \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | __kernel_page_user)
#define __PAGE_KERNEL_NOCACHE \
- (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
+ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
#define __PAGE_KERNEL_RO \
- (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+ (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user)
#define __PAGE_KERNEL_VSYSCALL \
(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL_VSYSCALL_NOCACHE \
@@ -422,7 +428,8 @@ static inline pud_t *pud_offset_k(pgd_t *pgd, unsigned long address)
can temporarily clear it. */
#define pmd_present(x) (pmd_val(x))
#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
-#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT))
+#define pmd_bad(x) ((pmd_val(x) & ~(PTE_MASK | _PAGE_USER | _PAGE_PRESENT)) \
+ != (_KERNPG_TABLE & ~(_PAGE_USER | _PAGE_PRESENT)))
#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
#define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h
index e21d4ee6f2..5244e2855e 100644
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h
@@ -15,20 +15,20 @@ extern void nmi(void);
static void __init machine_specific_arch_setup(void)
{
int ret;
- struct callback_register event = {
+ static struct callback_register __initdata event = {
.type = CALLBACKTYPE_event,
.address = (unsigned long) hypervisor_callback,
};
- struct callback_register failsafe = {
+ static struct callback_register __initdata failsafe = {
.type = CALLBACKTYPE_failsafe,
.address = (unsigned long)failsafe_callback,
};
- struct callback_register syscall = {
+ static struct callback_register __initdata syscall = {
.type = CALLBACKTYPE_syscall,
.address = (unsigned long)system_call,
};
#ifdef CONFIG_X86_LOCAL_APIC
- struct callback_register nmi_cb = {
+ static struct callback_register __initdata nmi_cb = {
.type = CALLBACKTYPE_nmi,
.address = (unsigned long)nmi,
};
@@ -39,20 +39,25 @@ static void __init machine_specific_arch_setup(void)
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
if (ret == 0)
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &syscall);
+#ifdef CONFIG_XEN_COMPAT_030002
if (ret == -ENOSYS)
ret = HYPERVISOR_set_callbacks(
event.address,
failsafe.address,
syscall.address);
+#endif
BUG_ON(ret);
#ifdef CONFIG_X86_LOCAL_APIC
ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+#ifdef CONFIG_XEN_COMPAT_030002
if (ret == -ENOSYS) {
- struct xennmi_callback cb;
+ static struct xennmi_callback __initdata cb = {
+ .handler_address = (unsigned long)nmi
+ };
- cb.handler_address = nmi_cb.address;
HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
}
#endif
+#endif
}
diff --git a/linux-2.6-xen-sparse/include/linux/skbuff.h b/linux-2.6-xen-sparse/include/linux/skbuff.h
index 9ea3924ab6..07b8f3036d 100644
--- a/linux-2.6-xen-sparse/include/linux/skbuff.h
+++ b/linux-2.6-xen-sparse/include/linux/skbuff.h
@@ -974,15 +974,16 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
#define NET_IP_ALIGN 2
#endif
-extern int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc);
+extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
{
- if (!skb->data_len) {
- skb->len = len;
- skb->tail = skb->data + len;
- } else
- ___pskb_trim(skb, len, 0);
+ if (unlikely(skb->data_len)) {
+ WARN_ON(1);
+ return;
+ }
+ skb->len = len;
+ skb->tail = skb->data + len;
}
/**
@@ -992,6 +993,7 @@ static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
*
* Cut the length of a buffer down by removing data from the tail. If
* the buffer is already under the length specified it is not modified.
+ * The skb must be linear.
*/
static inline void skb_trim(struct sk_buff *skb, unsigned int len)
{
@@ -1002,12 +1004,10 @@ static inline void skb_trim(struct sk_buff *skb, unsigned int len)
static inline int __pskb_trim(struct sk_buff *skb, unsigned int len)
{
- if (!skb->data_len) {
- skb->len = len;
- skb->tail = skb->data+len;
- return 0;
- }
- return ___pskb_trim(skb, len, 1);
+ if (skb->data_len)
+ return ___pskb_trim(skb, len);
+ __skb_trim(skb, len);
+ return 0;
}
static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
diff --git a/linux-2.6-xen-sparse/include/xen/balloon.h b/linux-2.6-xen-sparse/include/xen/balloon.h
index 60d7099aa1..d26c62bef4 100644
--- a/linux-2.6-xen-sparse/include/xen/balloon.h
+++ b/linux-2.6-xen-sparse/include/xen/balloon.h
@@ -38,23 +38,13 @@
* Inform the balloon driver that it should allow some slop for device-driver
* memory activities.
*/
-void
-balloon_update_driver_allowance(
- long delta);
+void balloon_update_driver_allowance(long delta);
-/* Allocate an empty low-memory page range. */
-struct page *
-balloon_alloc_empty_page_range(
- unsigned long nr_pages);
+/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
+struct page **alloc_empty_pages_and_pagevec(int nr_pages);
+void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-/* Deallocate an empty page range, adding to the balloon. */
-void
-balloon_dealloc_empty_page_range(
- struct page *page, unsigned long nr_pages);
-
-void
-balloon_release_driver_page(
- struct page *page);
+void balloon_release_driver_page(struct page *page);
/*
* Prevent the balloon driver from changing the memory reservation during
diff --git a/linux-2.6-xen-sparse/include/xen/gnttab.h b/linux-2.6-xen-sparse/include/xen/gnttab.h
index 676fca5054..f1543c01d6 100644
--- a/linux-2.6-xen-sparse/include/xen/gnttab.h
+++ b/linux-2.6-xen-sparse/include/xen/gnttab.h
@@ -39,6 +39,7 @@
#include <linux/config.h>
#include <asm/hypervisor.h>
+#include <asm/maddr.h> /* maddr_t */
#include <xen/interface/grant_table.h>
#include <xen/features.h>
@@ -118,7 +119,7 @@ int gnttab_suspend(void);
int gnttab_resume(void);
static inline void
-gnttab_set_map_op(struct gnttab_map_grant_ref *map, unsigned long addr,
+gnttab_set_map_op(struct gnttab_map_grant_ref *map, maddr_t addr,
uint32_t flags, grant_ref_t ref, domid_t domid)
{
if (flags & GNTMAP_contains_pte)
@@ -134,7 +135,7 @@ gnttab_set_map_op(struct gnttab_map_grant_ref *map, unsigned long addr,
}
static inline void
-gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, unsigned long addr,
+gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, maddr_t addr,
uint32_t flags, grant_handle_t handle)
{
if (flags & GNTMAP_contains_pte)
diff --git a/linux-2.6-xen-sparse/include/xen/public/evtchn.h b/linux-2.6-xen-sparse/include/xen/public/evtchn.h
index 99e2948240..938d4da2bd 100644
--- a/linux-2.6-xen-sparse/include/xen/public/evtchn.h
+++ b/linux-2.6-xen-sparse/include/xen/public/evtchn.h
@@ -33,9 +33,6 @@
#ifndef __LINUX_PUBLIC_EVTCHN_H__
#define __LINUX_PUBLIC_EVTCHN_H__
-/* /dev/xen/evtchn resides at device number major=10, minor=201 */
-#define EVTCHN_MINOR 201
-
/*
* Bind a fresh port to VIRQ @virq.
* Return allocated port.
diff --git a/linux-2.6-xen-sparse/include/xen/xenbus.h b/linux-2.6-xen-sparse/include/xen/xenbus.h
index 8e259ce777..c7cb7eaa3a 100644
--- a/linux-2.6-xen-sparse/include/xen/xenbus.h
+++ b/linux-2.6-xen-sparse/include/xen/xenbus.h
@@ -38,6 +38,7 @@
#include <linux/notifier.h>
#include <linux/mutex.h>
#include <linux/completion.h>
+#include <linux/init.h>
#include <xen/interface/xen.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h>
diff --git a/linux-2.6-xen-sparse/include/xen/xencons.h b/linux-2.6-xen-sparse/include/xen/xencons.h
index fa2160d89d..ae873746aa 100644
--- a/linux-2.6-xen-sparse/include/xen/xencons.h
+++ b/linux-2.6-xen-sparse/include/xen/xencons.h
@@ -1,6 +1,9 @@
#ifndef __ASM_XENCONS_H__
#define __ASM_XENCONS_H__
+struct dom0_vga_console_info;
+void dom0_init_screen_info(const struct dom0_vga_console_info *info);
+
void xencons_force_flush(void);
void xencons_resume(void);
diff --git a/linux-2.6-xen-sparse/include/xen/xenoprof.h b/linux-2.6-xen-sparse/include/xen/xenoprof.h
new file mode 100644
index 0000000000..4c3ab0fb21
--- /dev/null
+++ b/linux-2.6-xen-sparse/include/xen/xenoprof.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * xen/xenoprof.h
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __XEN_XENOPROF_H__
+#define __XEN_XENOPROF_H__
+#ifdef CONFIG_XEN
+
+#include <asm/xenoprof.h>
+
+struct oprofile_operations;
+int xenoprofile_init(struct oprofile_operations * ops);
+void xenoprofile_exit(void);
+
+struct xenoprof_shared_buffer {
+ char *buffer;
+ struct xenoprof_arch_shared_buffer arch;
+};
+#else
+#define xenoprofile_init(ops) (-ENOSYS)
+#define xenoprofile_exit() do { } while (0)
+
+#endif /* CONFIG_XEN */
+#endif /* __XEN_XENOPROF_H__ */
diff --git a/linux-2.6-xen-sparse/lib/Makefile b/linux-2.6-xen-sparse/lib/Makefile
index 2657bb5d10..1f96de0517 100644
--- a/linux-2.6-xen-sparse/lib/Makefile
+++ b/linux-2.6-xen-sparse/lib/Makefile
@@ -45,9 +45,7 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
-ifneq ($(CONFIG_XEN_IA64_DOM0_NON_VP),y)
swiotlb-$(CONFIG_XEN) := ../arch/i386/kernel/swiotlb.o
-endif
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/linux-2.6-xen-sparse/mm/Kconfig b/linux-2.6-xen-sparse/mm/Kconfig
index c9e8c6ddb8..f54f49fbb6 100644
--- a/linux-2.6-xen-sparse/mm/Kconfig
+++ b/linux-2.6-xen-sparse/mm/Kconfig
@@ -115,7 +115,7 @@ config SPARSEMEM_EXTREME
# eventually, we can have this option just 'select SPARSEMEM'
config MEMORY_HOTPLUG
bool "Allow for memory hot-add"
- depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND
+ depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
comment "Memory hotplug is currently incompatible with Software Suspend"
depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
diff --git a/linux-2.6-xen-sparse/mm/memory.c b/linux-2.6-xen-sparse/mm/memory.c
index 1a63339203..d7319d32f9 100644
--- a/linux-2.6-xen-sparse/mm/memory.c
+++ b/linux-2.6-xen-sparse/mm/memory.c
@@ -390,7 +390,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
if (vma->vm_flags & VM_PFNMAP) {
unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
- if ((pfn == vma->vm_pgoff + off) || !pfn_valid(pfn))
+ if (pfn == vma->vm_pgoff + off)
return NULL;
if (!is_cow_mapping(vma->vm_flags))
return NULL;
@@ -405,7 +405,8 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
* Remove this test eventually!
*/
if (unlikely(!pfn_valid(pfn))) {
- print_bad_pte(vma, pte, addr);
+ if (!(vma->vm_flags & VM_RESERVED))
+ print_bad_pte(vma, pte, addr);
return NULL;
}
@@ -1534,6 +1535,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
memset(kaddr, 0, PAGE_SIZE);
kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(dst);
return;
}
diff --git a/linux-2.6-xen-sparse/mm/mmap.c b/linux-2.6-xen-sparse/mm/mmap.c
index a01e3ffb9d..f1b2f0f0ed 100644
--- a/linux-2.6-xen-sparse/mm/mmap.c
+++ b/linux-2.6-xen-sparse/mm/mmap.c
@@ -30,6 +30,10 @@
#include <asm/cacheflush.h>
#include <asm/tlb.h>
+#ifndef arch_mmap_check
+#define arch_mmap_check(addr, len, flags) (0)
+#endif
+
static void unmap_region(struct mm_struct *mm,
struct vm_area_struct *vma, struct vm_area_struct *prev,
unsigned long start, unsigned long end);
@@ -906,6 +910,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
if (!len)
return -EINVAL;
+ error = arch_mmap_check(addr, len, flags);
+ if (error)
+ return error;
+
/* Careful about overflows.. */
len = PAGE_ALIGN(len);
if (!len || len > TASK_SIZE)
@@ -1846,6 +1854,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
unsigned long flags;
struct rb_node ** rb_link, * rb_parent;
pgoff_t pgoff = addr >> PAGE_SHIFT;
+ int error;
len = PAGE_ALIGN(len);
if (!len)
@@ -1854,6 +1863,12 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
if ((addr + len) > TASK_SIZE || (addr + len) < addr)
return -EINVAL;
+ flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
+
+ error = arch_mmap_check(addr, len, flags);
+ if (error)
+ return error;
+
/*
* mlock MCL_FUTURE?
*/
@@ -1894,8 +1909,6 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
if (security_vm_enough_memory(len >> PAGE_SHIFT))
return -ENOMEM;
- flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
-
/* Can we just expand an old private anonymous mapping? */
if (vma_merge(mm, prev, addr, addr + len, flags,
NULL, NULL, pgoff, NULL))
diff --git a/linux-2.6-xen-sparse/mm/page_alloc.c b/linux-2.6-xen-sparse/mm/page_alloc.c
index c0f3c60537..f12323955a 100644
--- a/linux-2.6-xen-sparse/mm/page_alloc.c
+++ b/linux-2.6-xen-sparse/mm/page_alloc.c
@@ -951,7 +951,8 @@ restart:
alloc_flags |= ALLOC_HARDER;
if (gfp_mask & __GFP_HIGH)
alloc_flags |= ALLOC_HIGH;
- alloc_flags |= ALLOC_CPUSET;
+ if (wait)
+ alloc_flags |= ALLOC_CPUSET;
/*
* Go through the zonelist again. Let __GFP_HIGH and allocations
diff --git a/linux-2.6-xen-sparse/net/core/skbuff.c b/linux-2.6-xen-sparse/net/core/skbuff.c
index 236946bd7e..064e6277b1 100644
--- a/linux-2.6-xen-sparse/net/core/skbuff.c
+++ b/linux-2.6-xen-sparse/net/core/skbuff.c
@@ -261,11 +261,11 @@ nodata:
}
-static void skb_drop_fraglist(struct sk_buff *skb)
+static void skb_drop_list(struct sk_buff **listp)
{
- struct sk_buff *list = skb_shinfo(skb)->frag_list;
+ struct sk_buff *list = *listp;
- skb_shinfo(skb)->frag_list = NULL;
+ *listp = NULL;
do {
struct sk_buff *this = list;
@@ -274,6 +274,11 @@ static void skb_drop_fraglist(struct sk_buff *skb)
} while (list);
}
+static inline void skb_drop_fraglist(struct sk_buff *skb)
+{
+ skb_drop_list(&skb_shinfo(skb)->frag_list);
+}
+
static void skb_clone_fraglist(struct sk_buff *skb)
{
struct sk_buff *list;
@@ -604,6 +609,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
n->csum = skb->csum;
n->ip_summed = skb->ip_summed;
+ n->truesize += skb->data_len;
n->data_len = skb->data_len;
n->len = skb->len;
@@ -798,49 +804,86 @@ struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
return nskb;
}
-/* Trims skb to length len. It can change skb pointers, if "realloc" is 1.
- * If realloc==0 and trimming is impossible without change of data,
- * it is BUG().
+/* Trims skb to length len. It can change skb pointers.
*/
-int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc)
+int ___pskb_trim(struct sk_buff *skb, unsigned int len)
{
+ struct sk_buff **fragp;
+ struct sk_buff *frag;
int offset = skb_headlen(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
int i;
+ int err;
- for (i = 0; i < nfrags; i++) {
+ if (skb_cloned(skb) &&
+ unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
+ return err;
+
+ i = 0;
+ if (offset >= len)
+ goto drop_pages;
+
+ for (; i < nfrags; i++) {
int end = offset + skb_shinfo(skb)->frags[i].size;
- if (end > len) {
- if (skb_cloned(skb)) {
- BUG_ON(!realloc);
- if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
- return -ENOMEM;
- }
- if (len <= offset) {
- put_page(skb_shinfo(skb)->frags[i].page);
- skb_shinfo(skb)->nr_frags--;
- } else {
- skb_shinfo(skb)->frags[i].size = len - offset;
- }
+
+ if (end < len) {
+ offset = end;
+ continue;
+ }
+
+ skb_shinfo(skb)->frags[i++].size = len - offset;
+
+drop_pages:
+ skb_shinfo(skb)->nr_frags = i;
+
+ for (; i < nfrags; i++)
+ put_page(skb_shinfo(skb)->frags[i].page);
+
+ if (skb_shinfo(skb)->frag_list)
+ skb_drop_fraglist(skb);
+ goto done;
+ }
+
+ for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
+ fragp = &frag->next) {
+ int end = offset + frag->len;
+
+ if (skb_shared(frag)) {
+ struct sk_buff *nfrag;
+
+ nfrag = skb_clone(frag, GFP_ATOMIC);
+ if (unlikely(!nfrag))
+ return -ENOMEM;
+
+ nfrag->next = frag->next;
+ kfree_skb(frag);
+ frag = nfrag;
+ *fragp = frag;
}
- offset = end;
+
+ if (end < len) {
+ offset = end;
+ continue;
+ }
+
+ if (end > len &&
+ unlikely((err = pskb_trim(frag, len - offset))))
+ return err;
+
+ if (frag->next)
+ skb_drop_list(&frag->next);
+ break;
}
- if (offset < len) {
+done:
+ if (len > skb_headlen(skb)) {
skb->data_len -= skb->len - len;
skb->len = len;
} else {
- if (len <= skb_headlen(skb)) {
- skb->len = len;
- skb->data_len = 0;
- skb->tail = skb->data + len;
- if (skb_shinfo(skb)->frag_list && !skb_cloned(skb))
- skb_drop_fraglist(skb);
- } else {
- skb->data_len -= skb->len - len;
- skb->len = len;
- }
+ skb->len = len;
+ skb->data_len = 0;
+ skb->tail = skb->data + len;
}
return 0;
diff --git a/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch b/patches/linux-2.6.16.32/blktap-aio-16_03_06.patch
index 5f4fd6f7a9..bf3e8d63f0 100644
--- a/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch
+++ b/patches/linux-2.6.16.32/blktap-aio-16_03_06.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
---- ../pristine-linux-2.6.16-rc5/fs/aio.c 2006-03-14 14:10:10.827401387 +0000
-+++ ./fs/aio.c 2006-03-16 09:57:53.898316582 +0000
+diff -pruN ../orig-linux-2.6.16.29/fs/aio.c ./fs/aio.c
+--- ../orig-linux-2.6.16.29/fs/aio.c 2006-09-12 19:02:10.000000000 +0100
++++ ./fs/aio.c 2006-09-19 13:58:49.000000000 +0100
@@ -34,6 +34,11 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -184,10 +184,9 @@ diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
io_destroy(ioctx);
-
-diff -pruN ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
---- ../pristine-linux-2.6.16-rc5/fs/eventpoll.c 2006-01-03 03:21:10.000000000 +0000
-+++ ./fs/eventpoll.c 2006-03-16 10:04:35.469956167 +0000
+diff -pruN ../orig-linux-2.6.16.29/fs/eventpoll.c ./fs/eventpoll.c
+--- ../orig-linux-2.6.16.29/fs/eventpoll.c 2006-09-12 19:02:10.000000000 +0100
++++ ./fs/eventpoll.c 2006-09-19 13:58:49.000000000 +0100
@@ -235,8 +235,6 @@ struct ep_pqueue {
static void ep_poll_safewake_init(struct poll_safewake *psw);
@@ -262,10 +261,9 @@ diff -pruN ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
/*
* Mark the inode dirty from the very beginning,
-
-diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/aio.h ./include/linux/aio.h
---- ../pristine-linux-2.6.16-rc5/include/linux/aio.h 2006-03-14 14:10:21.597916731 +0000
-+++ ./include/linux/aio.h 2006-03-16 10:05:39.848833028 +0000
+diff -pruN ../orig-linux-2.6.16.29/include/linux/aio.h ./include/linux/aio.h
+--- ../orig-linux-2.6.16.29/include/linux/aio.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/linux/aio.h 2006-09-19 13:58:49.000000000 +0100
@@ -191,6 +191,11 @@ struct kioctx {
struct aio_ring_info ring_info;
@@ -278,10 +276,9 @@ diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/aio.h ./include/linux/aio.
};
/* prototypes */
-
-diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h ./include/linux/eventpoll.h
---- ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h 2006-01-03 03:21:10.000000000 +0000
-+++ ./include/linux/eventpoll.h 2006-03-16 10:08:51.577809317 +0000
+diff -pruN ../orig-linux-2.6.16.29/include/linux/eventpoll.h ./include/linux/eventpoll.h
+--- ../orig-linux-2.6.16.29/include/linux/eventpoll.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/linux/eventpoll.h 2006-09-19 13:58:49.000000000 +0100
@@ -86,6 +86,12 @@ static inline void eventpoll_release(str
}
diff --git a/patches/linux-2.6.16.13/device_bind.patch b/patches/linux-2.6.16.32/device_bind.patch
index 331234c89f..8cef71ecc1 100644
--- a/patches/linux-2.6.16.13/device_bind.patch
+++ b/patches/linux-2.6.16.32/device_bind.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/drivers/base/bus.c ./drivers/base/bus.c
---- ../pristine-linux-2.6.16.13/drivers/base/bus.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./drivers/base/bus.c 2006-05-04 17:41:30.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/base/bus.c ./drivers/base/bus.c
+--- ../orig-linux-2.6.16.29/drivers/base/bus.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/base/bus.c 2006-09-19 13:58:54.000000000 +0100
@@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device
up(&dev->sem);
if (dev->parent)
diff --git a/patches/linux-2.6.16.13/fix-hz-suspend.patch b/patches/linux-2.6.16.32/fix-hz-suspend.patch
index bcb79553e7..2a964ccb8c 100644
--- a/patches/linux-2.6.16.13/fix-hz-suspend.patch
+++ b/patches/linux-2.6.16.32/fix-hz-suspend.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/kernel/timer.c ./kernel/timer.c
---- ../pristine-linux-2.6.16.13/kernel/timer.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./kernel/timer.c 2006-06-29 14:34:12.788957720 +0100
+diff -pruN ../orig-linux-2.6.16.29/kernel/timer.c ./kernel/timer.c
+--- ../orig-linux-2.6.16.29/kernel/timer.c 2006-09-12 19:02:10.000000000 +0100
++++ ./kernel/timer.c 2006-09-19 13:58:58.000000000 +0100
@@ -555,6 +555,22 @@ found:
}
spin_unlock(&base->t_base.lock);
diff --git a/patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch b/patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch
index 0892117255..91e6cb5279 100644
--- a/patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch
+++ b/patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch
@@ -1,7 +1,7 @@
-diff -ru ../pristine-linux-2.6.16.13/drivers/ide/ide-lib.c ./drivers/ide/ide-lib.c
---- ../pristine-linux-2.6.16.13/drivers/ide/ide-lib.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./drivers/ide/ide-lib.c 2006-05-24 18:37:05.000000000 +0100
-@@ -410,10 +410,10 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/ide/ide-lib.c ./drivers/ide/ide-lib.c
+--- ../orig-linux-2.6.16.29/drivers/ide/ide-lib.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/ide/ide-lib.c 2006-09-19 13:59:03.000000000 +0100
+@@ -410,10 +410,10 @@ void ide_toggle_bounce(ide_drive_t *driv
{
u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */
diff --git a/patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch b/patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch
index 424e5483ad..bfcba3908a 100644
--- a/patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch
+++ b/patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/traps.c ./arch/i386/kernel/traps.c
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/traps.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/traps.c 2006-05-04 17:41:34.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/traps.c ./arch/i386/kernel/traps.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/traps.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/traps.c 2006-09-19 13:59:06.000000000 +0100
@@ -567,18 +567,11 @@ static void mem_parity_error(unsigned ch
static void io_check_error(unsigned char reason, struct pt_regs * regs)
@@ -21,9 +21,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/traps.c ./arch/i386/kern
}
static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/mach-default/mach_traps.h ./include/asm-i386/mach-default/mach_traps.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/mach-default/mach_traps.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/mach-default/mach_traps.h 2006-05-04 17:41:34.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/mach-default/mach_traps.h ./include/asm-i386/mach-default/mach_traps.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/mach-default/mach_traps.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/mach-default/mach_traps.h 2006-09-19 13:59:06.000000000 +0100
@@ -15,6 +15,18 @@ static inline void clear_mem_error(unsig
outb(reason, 0x61);
}
diff --git a/patches/linux-2.6.16.13/ipv6-no-autoconf.patch b/patches/linux-2.6.16.32/ipv6-no-autoconf.patch
index 7d2fd4d531..e0d1b8c681 100644
--- a/patches/linux-2.6.16.13/ipv6-no-autoconf.patch
+++ b/patches/linux-2.6.16.32/ipv6-no-autoconf.patch
@@ -1,11 +1,7 @@
- net/ipv6/addrconf.c | 2 ++
- 1 files changed, 2 insertions(+)
-
-Index: build/net/ipv6/addrconf.c
-===================================================================
---- build.orig/net/ipv6/addrconf.c
-+++ build/net/ipv6/addrconf.c
-@@ -2462,6 +2462,7 @@ static void addrconf_dad_start(struct in
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/addrconf.c ./net/ipv6/addrconf.c
+--- ../orig-linux-2.6.16.29/net/ipv6/addrconf.c 2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv6/addrconf.c 2006-09-19 13:59:11.000000000 +0100
+@@ -2471,6 +2471,7 @@ static void addrconf_dad_start(struct in
spin_lock_bh(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
@@ -13,7 +9,7 @@ Index: build/net/ipv6/addrconf.c
!(ifp->flags&IFA_F_TENTATIVE)) {
ifp->flags &= ~IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock);
-@@ -2546,6 +2547,7 @@ static void addrconf_dad_completed(struc
+@@ -2555,6 +2556,7 @@ static void addrconf_dad_completed(struc
if (ifp->idev->cnf.forwarding == 0 &&
ifp->idev->cnf.rtr_solicits > 0 &&
(dev->flags&IFF_LOOPBACK) == 0 &&
diff --git a/patches/linux-2.6.16.32/kasprintf.patch b/patches/linux-2.6.16.32/kasprintf.patch
new file mode 100644
index 0000000000..03e8c07ccf
--- /dev/null
+++ b/patches/linux-2.6.16.32/kasprintf.patch
@@ -0,0 +1,59 @@
+commit e905914f96e11862b130dd229f73045dad9a34e8
+Author: Jeremy Fitzhardinge <jeremy@xensource.com>
+Date: Sun Jun 25 05:49:17 2006 -0700
+
+ [PATCH] Implement kasprintf
+
+ Implement kasprintf, a kernel version of asprintf. This allocates the
+ memory required for the formatted string, including the trailing '\0'.
+ Returns NULL on allocation failure.
+
+ Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
+ Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+ Signed-off-by: Andrew Morton <akpm@osdl.org>
+ Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+
+diff --git a/include/linux/kernel.h b/include/linux/kernel.h
+index 8c21aaa..3c5e4c2 100644
+--- a/include/linux/kernel.h
++++ b/include/linux/kernel.h
+@@ -117,6 +117,8 @@ extern int scnprintf(char * buf, size_t
+ __attribute__ ((format (printf, 3, 4)));
+ extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+ __attribute__ ((format (printf, 3, 0)));
++extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
++ __attribute__ ((format (printf, 2, 3)));
+
+ extern int sscanf(const char *, const char *, ...)
+ __attribute__ ((format (scanf, 2, 3)));
+diff --git a/lib/vsprintf.c b/lib/vsprintf.c
+index f595947..797428a 100644
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -849,3 +849,26 @@ int sscanf(const char * buf, const char
+ }
+
+ EXPORT_SYMBOL(sscanf);
++
++
++/* Simplified asprintf. */
++char *kasprintf(gfp_t gfp, const char *fmt, ...)
++{
++ va_list ap;
++ unsigned int len;
++ char *p;
++
++ va_start(ap, fmt);
++ len = vsnprintf(NULL, 0, fmt, ap);
++ va_end(ap);
++
++ p = kmalloc(len+1, gfp);
++ if (!p)
++ return NULL;
++ va_start(ap, fmt);
++ vsnprintf(p, len+1, fmt, ap);
++ va_end(ap);
++ return p;
++}
++
++EXPORT_SYMBOL(kasprintf);
diff --git a/patches/linux-2.6.16.13/net-csum.patch b/patches/linux-2.6.16.32/net-csum.patch
index c99e0506b2..d5fb233077 100644
--- a/patches/linux-2.6.16.13/net-csum.patch
+++ b/patches/linux-2.6.16.32/net-csum.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c ./net/ipv4/netfilter/ip_nat_proto_tcp.c
---- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-05-16 13:28:19.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_tcp.c ./net/ipv4/netfilter/ip_nat_proto_tcp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-09-19 13:59:15.000000000 +0100
@@ -129,7 +129,12 @@ tcp_manip_pkt(struct sk_buff **pskb,
if (hdrsize < sizeof(*hdr))
return 1;
@@ -15,9 +15,9 @@ diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c ./n
ip_nat_cheat_check(oldport ^ 0xFFFF,
newport,
hdr->check));
-diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c ./net/ipv4/netfilter/ip_nat_proto_udp.c
---- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./net/ipv4/netfilter/ip_nat_proto_udp.c 2006-05-16 13:30:14.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_udp.c ./net/ipv4/netfilter/ip_nat_proto_udp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/netfilter/ip_nat_proto_udp.c 2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/netfilter/ip_nat_proto_udp.c 2006-09-19 13:59:15.000000000 +0100
@@ -113,11 +113,17 @@ udp_manip_pkt(struct sk_buff **pskb,
newport = tuple->dst.u.udp.port;
portptr = &hdr->dest;
@@ -38,9 +38,9 @@ diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c ./n
*portptr = newport;
return 1;
}
-diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/xfrm4_output.c ./net/ipv4/xfrm4_output.c
---- ../pristine-linux-2.6.16.13/net/ipv4/xfrm4_output.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./net/ipv4/xfrm4_output.c 2006-05-04 17:41:37.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c ./net/ipv4/xfrm4_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c 2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/xfrm4_output.c 2006-09-19 13:59:15.000000000 +0100
@@ -17,6 +17,8 @@
#include <net/xfrm.h>
#include <net/icmp.h>
diff --git a/patches/linux-2.6.16.13/net-gso-0-base.patch b/patches/linux-2.6.16.32/net-gso-0-base.patch
index 4c69d1e4a6..ce414f3326 100644
--- a/patches/linux-2.6.16.13/net-gso-0-base.patch
+++ b/patches/linux-2.6.16.32/net-gso-0-base.patch
@@ -1,8 +1,8 @@
-diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
-index 3c0a5ba..847cedb 100644
---- a/Documentation/networking/netdevices.txt
-+++ b/Documentation/networking/netdevices.txt
-@@ -42,9 +42,9 @@ dev->get_stats:
+Index: tmp-xxx/Documentation/networking/netdevices.txt
+===================================================================
+--- tmp-xxx.orig/Documentation/networking/netdevices.txt 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/Documentation/networking/netdevices.txt 2006-11-27 10:52:42.000000000 +0000
+@@ -42,9 +42,9 @@
Context: nominally process, but don't sleep inside an rwlock
dev->hard_start_xmit:
@@ -14,7 +14,7 @@ index 3c0a5ba..847cedb 100644
has to lock by itself when needed. It is recommended to use a try lock
for this and return -1 when the spin lock fails.
The locking there should also properly protect against
-@@ -62,12 +62,12 @@ dev->hard_start_xmit:
+@@ -62,12 +62,12 @@
Only valid when NETIF_F_LLTX is set.
dev->tx_timeout:
@@ -29,11 +29,11 @@ index 3c0a5ba..847cedb 100644
Context: BHs disabled
dev->poll:
-diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
-index 4be9769..2e7cac7 100644
---- a/drivers/block/aoe/aoenet.c
-+++ b/drivers/block/aoe/aoenet.c
-@@ -95,9 +95,8 @@ mac_addr(char addr[6])
+Index: tmp-xxx/drivers/block/aoe/aoenet.c
+===================================================================
+--- tmp-xxx.orig/drivers/block/aoe/aoenet.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/block/aoe/aoenet.c 2006-11-27 10:52:42.000000000 +0000
+@@ -95,9 +95,8 @@
static struct sk_buff *
skb_check(struct sk_buff *skb)
{
@@ -44,11 +44,11 @@ index 4be9769..2e7cac7 100644
dev_kfree_skb(skb);
return NULL;
}
-diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-index a2408d7..c90e620 100644
---- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
-@@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_
+Index: tmp-xxx/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+===================================================================
+--- tmp-xxx.orig/drivers/infiniband/ulp/ipoib/ipoib_multicast.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/infiniband/ulp/ipoib/ipoib_multicast.c 2006-11-27 10:52:42.000000000 +0000
+@@ -821,7 +821,8 @@
ipoib_mcast_stop_thread(dev, 0);
@@ -58,7 +58,7 @@ index a2408d7..c90e620 100644
spin_lock(&priv->lock);
/*
-@@ -896,7 +897,8 @@ void ipoib_mcast_restart_task(void *dev_
+@@ -896,7 +897,8 @@
}
spin_unlock(&priv->lock);
@@ -68,11 +68,11 @@ index a2408d7..c90e620 100644
/* We have to cancel outside of the spinlock */
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
-diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
-index 6711eb6..8d2351f 100644
---- a/drivers/media/dvb/dvb-core/dvb_net.c
-+++ b/drivers/media/dvb/dvb-core/dvb_net.c
-@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void
+Index: tmp-xxx/drivers/media/dvb/dvb-core/dvb_net.c
+===================================================================
+--- tmp-xxx.orig/drivers/media/dvb/dvb-core/dvb_net.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/media/dvb/dvb-core/dvb_net.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1053,7 +1053,7 @@
dvb_net_feed_stop(dev);
priv->rx_mode = RX_MODE_UNI;
@@ -81,7 +81,7 @@ index 6711eb6..8d2351f 100644
if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
-@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void
+@@ -1078,7 +1078,7 @@
}
}
@@ -90,11 +90,11 @@ index 6711eb6..8d2351f 100644
dvb_net_feed_start(dev);
}
-diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
-index dd41049..6615583 100644
---- a/drivers/net/8139cp.c
-+++ b/drivers/net/8139cp.c
-@@ -794,7 +794,7 @@ #endif
+Index: tmp-xxx/drivers/net/8139cp.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/8139cp.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/8139cp.c 2006-11-27 10:52:42.000000000 +0000
+@@ -794,7 +794,7 @@
entry = cp->tx_head;
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
if (dev->features & NETIF_F_TSO)
@@ -103,11 +103,11 @@ index dd41049..6615583 100644
if (skb_shinfo(skb)->nr_frags == 0) {
struct cp_desc *txd = &cp->tx_ring[entry];
-diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
-index a24200d..b5e39a1 100644
---- a/drivers/net/bnx2.c
-+++ b/drivers/net/bnx2.c
-@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
+Index: tmp-xxx/drivers/net/bnx2.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/bnx2.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/bnx2.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1593,7 +1593,7 @@
skb = tx_buf->skb;
#ifdef BCM_TSO
/* partial BD completions possible with TSO packets */
@@ -116,7 +116,7 @@ index a24200d..b5e39a1 100644
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
-@@ -1948,7 +1948,7 @@ bnx2_poll(struct net_device *dev, int *b
+@@ -1948,7 +1948,7 @@
return 1;
}
@@ -125,7 +125,7 @@ index a24200d..b5e39a1 100644
* from set_multicast.
*/
static void
-@@ -4403,7 +4403,7 @@ bnx2_vlan_rx_kill_vid(struct net_device
+@@ -4403,7 +4403,7 @@
}
#endif
@@ -134,7 +134,7 @@ index a24200d..b5e39a1 100644
* hard_start_xmit is pseudo-lockless - a lock is only required when
* the tx queue is full. This way, we get the benefit of lockless
* operations most of the time without the complexities to handle
-@@ -4441,7 +4441,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
+@@ -4441,7 +4441,7 @@
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
#ifdef BCM_TSO
@@ -143,11 +143,11 @@ index a24200d..b5e39a1 100644
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
-diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
-index bcf9f17..e970921 100644
---- a/drivers/net/bonding/bond_main.c
-+++ b/drivers/net/bonding/bond_main.c
-@@ -1145,8 +1145,7 @@ int bond_sethwaddr(struct net_device *bo
+Index: tmp-xxx/drivers/net/bonding/bond_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/bonding/bond_main.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/bonding/bond_main.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1145,8 +1145,7 @@
}
#define BOND_INTERSECT_FEATURES \
@@ -157,7 +157,7 @@ index bcf9f17..e970921 100644
/*
* Compute the common dev->feature set available to all slaves. Some
-@@ -1164,9 +1163,7 @@ static int bond_compute_features(struct
+@@ -1164,9 +1163,7 @@
features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
if ((features & NETIF_F_SG) &&
@@ -168,7 +168,7 @@ index bcf9f17..e970921 100644
features &= ~NETIF_F_SG;
/*
-@@ -4147,7 +4144,7 @@ static int bond_init(struct net_device *
+@@ -4147,7 +4144,7 @@
*/
bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
@@ -177,11 +177,11 @@ index bcf9f17..e970921 100644
* transmitting */
bond_dev->features |= NETIF_F_LLTX;
-diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
-index 30ff8ea..7b7d360 100644
---- a/drivers/net/chelsio/sge.c
-+++ b/drivers/net/chelsio/sge.c
-@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
+Index: tmp-xxx/drivers/net/chelsio/sge.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/chelsio/sge.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/chelsio/sge.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1419,7 +1419,7 @@
struct cpl_tx_pkt *cpl;
#ifdef NETIF_F_TSO
@@ -190,7 +190,7 @@ index 30ff8ea..7b7d360 100644
int eth_type;
struct cpl_tx_pkt_lso *hdr;
-@@ -1434,7 +1434,7 @@ #ifdef NETIF_F_TSO
+@@ -1434,7 +1434,7 @@
hdr->ip_hdr_words = skb->nh.iph->ihl;
hdr->tcp_hdr_words = skb->h.th->doff;
hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
@@ -199,11 +199,11 @@ index 30ff8ea..7b7d360 100644
hdr->len = htonl(skb->len - sizeof(*hdr));
cpl = (struct cpl_tx_pkt *)hdr;
sge->stats.tx_lso_pkts++;
-diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
-index fa29402..681d284 100644
---- a/drivers/net/e1000/e1000_main.c
-+++ b/drivers/net/e1000/e1000_main.c
-@@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO
+Index: tmp-xxx/drivers/net/e1000/e1000_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/e1000/e1000_main.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/e1000/e1000_main.c 2006-11-27 10:52:42.000000000 +0000
+@@ -2526,7 +2526,7 @@
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
@@ -212,7 +212,7 @@ index fa29402..681d284 100644
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
-@@ -2534,7 +2534,7 @@ #ifdef NETIF_F_TSO
+@@ -2534,7 +2534,7 @@
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
@@ -221,7 +221,7 @@ index fa29402..681d284 100644
if (skb->protocol == ntohs(ETH_P_IP)) {
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
-@@ -2651,7 +2651,7 @@ #ifdef NETIF_F_TSO
+@@ -2651,7 +2651,7 @@
* tso gets written back prematurely before the data is fully
* DMAd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
@@ -230,7 +230,7 @@ index fa29402..681d284 100644
tx_ring->last_tx_tso = 0;
size -= 4;
}
-@@ -2893,7 +2893,7 @@ #endif
+@@ -2893,7 +2893,7 @@
}
#ifdef NETIF_F_TSO
@@ -239,7 +239,7 @@ index fa29402..681d284 100644
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
* initiating the DMA for each buffer. The calc is:
-@@ -2935,7 +2935,7 @@ #endif
+@@ -2935,7 +2935,7 @@
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso &&
@@ -248,11 +248,11 @@ index fa29402..681d284 100644
count++;
#endif
-diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
-index 3682ec6..c35f16e 100644
---- a/drivers/net/forcedeth.c
-+++ b/drivers/net/forcedeth.c
-@@ -482,9 +482,9 @@ #define LPA_1000HALF 0x0400
+Index: tmp-xxx/drivers/net/forcedeth.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/forcedeth.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/forcedeth.c 2006-11-27 10:52:42.000000000 +0000
+@@ -482,9 +482,9 @@
* critical parts:
* - rx is (pseudo-) lockless: it relies on the single-threading provided
* by the arch code for interrupts.
@@ -264,7 +264,7 @@ index 3682ec6..c35f16e 100644
*/
/* in dev: base, irq */
-@@ -1016,7 +1016,7 @@ static void drain_ring(struct net_device
+@@ -1016,7 +1016,7 @@
/*
* nv_start_xmit: dev->hard_start_xmit function
@@ -273,7 +273,7 @@ index 3682ec6..c35f16e 100644
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
-@@ -1105,8 +1105,8 @@ static int nv_start_xmit(struct sk_buff
+@@ -1105,8 +1105,8 @@
np->tx_skbuff[nr] = skb;
#ifdef NETIF_F_TSO
@@ -284,7 +284,7 @@ index 3682ec6..c35f16e 100644
else
#endif
tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
-@@ -1203,7 +1203,7 @@ static void nv_tx_done(struct net_device
+@@ -1203,7 +1203,7 @@
/*
* nv_tx_timeout: dev->tx_timeout function
@@ -293,7 +293,7 @@ index 3682ec6..c35f16e 100644
*/
static void nv_tx_timeout(struct net_device *dev)
{
-@@ -1524,7 +1524,7 @@ static int nv_change_mtu(struct net_devi
+@@ -1524,7 +1524,7 @@
* Changing the MTU is a rare event, it shouldn't matter.
*/
disable_irq(dev->irq);
@@ -302,7 +302,7 @@ index 3682ec6..c35f16e 100644
spin_lock(&np->lock);
/* stop engines */
nv_stop_rx(dev);
-@@ -1559,7 +1559,7 @@ static int nv_change_mtu(struct net_devi
+@@ -1559,7 +1559,7 @@
nv_start_rx(dev);
nv_start_tx(dev);
spin_unlock(&np->lock);
@@ -311,7 +311,7 @@ index 3682ec6..c35f16e 100644
enable_irq(dev->irq);
}
return 0;
-@@ -1594,7 +1594,7 @@ static int nv_set_mac_address(struct net
+@@ -1594,7 +1594,7 @@
memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
if (netif_running(dev)) {
@@ -320,7 +320,7 @@ index 3682ec6..c35f16e 100644
spin_lock_irq(&np->lock);
/* stop rx engine */
-@@ -1606,7 +1606,7 @@ static int nv_set_mac_address(struct net
+@@ -1606,7 +1606,7 @@
/* restart rx engine */
nv_start_rx(dev);
spin_unlock_irq(&np->lock);
@@ -329,7 +329,7 @@ index 3682ec6..c35f16e 100644
} else {
nv_copy_mac_to_hw(dev);
}
-@@ -1615,7 +1615,7 @@ static int nv_set_mac_address(struct net
+@@ -1615,7 +1615,7 @@
/*
* nv_set_multicast: dev->set_multicast function
@@ -338,11 +338,11 @@ index 3682ec6..c35f16e 100644
*/
static void nv_set_multicast(struct net_device *dev)
{
-diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
-index 102c1f0..d12605f 100644
---- a/drivers/net/hamradio/6pack.c
-+++ b/drivers/net/hamradio/6pack.c
-@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net
+Index: tmp-xxx/drivers/net/hamradio/6pack.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/hamradio/6pack.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/hamradio/6pack.c 2006-11-27 10:52:42.000000000 +0000
+@@ -308,9 +308,9 @@
{
struct sockaddr_ax25 *sa = addr;
@@ -354,7 +354,7 @@ index 102c1f0..d12605f 100644
return 0;
}
-@@ -767,9 +767,9 @@ static int sixpack_ioctl(struct tty_stru
+@@ -767,9 +767,9 @@
break;
}
@@ -366,11 +366,11 @@ index 102c1f0..d12605f 100644
err = 0;
break;
-diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
-index dc5e9d5..5c66f5a 100644
---- a/drivers/net/hamradio/mkiss.c
-+++ b/drivers/net/hamradio/mkiss.c
-@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net
+Index: tmp-xxx/drivers/net/hamradio/mkiss.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/hamradio/mkiss.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/hamradio/mkiss.c 2006-11-27 10:52:42.000000000 +0000
+@@ -357,9 +357,9 @@
{
struct sockaddr_ax25 *sa = addr;
@@ -382,7 +382,7 @@ index dc5e9d5..5c66f5a 100644
return 0;
}
-@@ -886,9 +886,9 @@ static int mkiss_ioctl(struct tty_struct
+@@ -886,9 +886,9 @@
break;
}
@@ -394,11 +394,11 @@ index dc5e9d5..5c66f5a 100644
err = 0;
break;
-diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
-index 31fb2d7..2e222ef 100644
---- a/drivers/net/ifb.c
-+++ b/drivers/net/ifb.c
-@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev
+Index: tmp-xxx/drivers/net/ifb.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/ifb.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/ifb.c 2006-11-27 10:52:42.000000000 +0000
+@@ -76,13 +76,13 @@
dp->st_task_enter++;
if ((skb = skb_peek(&dp->tq)) == NULL) {
dp->st_txq_refl_try++;
@@ -414,7 +414,7 @@ index 31fb2d7..2e222ef 100644
} else {
/* reschedule */
dp->st_rxq_notenter++;
-@@ -110,7 +110,7 @@ static void ri_tasklet(unsigned long dev
+@@ -110,7 +110,7 @@
}
}
@@ -423,7 +423,7 @@ index 31fb2d7..2e222ef 100644
dp->st_rxq_check++;
if ((skb = skb_peek(&dp->rq)) == NULL) {
dp->tasklet_pending = 0;
-@@ -118,10 +118,10 @@ static void ri_tasklet(unsigned long dev
+@@ -118,10 +118,10 @@
netif_wake_queue(_dev);
} else {
dp->st_rxq_rsch++;
@@ -436,11 +436,11 @@ index 31fb2d7..2e222ef 100644
} else {
resched:
dp->tasklet_pending = 1;
-diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
-index a9f49f0..339d4a7 100644
---- a/drivers/net/irda/vlsi_ir.c
-+++ b/drivers/net/irda/vlsi_ir.c
-@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct s
+Index: tmp-xxx/drivers/net/irda/vlsi_ir.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/irda/vlsi_ir.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/irda/vlsi_ir.c 2006-11-27 10:52:42.000000000 +0000
+@@ -959,7 +959,7 @@
|| (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
break;
udelay(100);
@@ -449,11 +449,11 @@ index a9f49f0..339d4a7 100644
}
}
-diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
-index f9f77e4..bdab369 100644
---- a/drivers/net/ixgb/ixgb_main.c
-+++ b/drivers/net/ixgb/ixgb_main.c
-@@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO
+Index: tmp-xxx/drivers/net/ixgb/ixgb_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/ixgb/ixgb_main.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/ixgb/ixgb_main.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1163,7 +1163,7 @@
uint16_t ipcse, tucse, mss;
int err;
@@ -462,7 +462,7 @@ index f9f77e4..bdab369 100644
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
-@@ -1171,7 +1171,7 @@ #ifdef NETIF_F_TSO
+@@ -1171,7 +1171,7 @@
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
@@ -471,11 +471,11 @@ index f9f77e4..bdab369 100644
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
-diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
-index 690a1aa..9bcaa80 100644
---- a/drivers/net/loopback.c
-+++ b/drivers/net/loopback.c
-@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
+Index: tmp-xxx/drivers/net/loopback.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/loopback.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/loopback.c 2006-11-27 10:52:42.000000000 +0000
+@@ -74,7 +74,7 @@
struct iphdr *iph = skb->nh.iph;
struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
unsigned int doffset = (iph->ihl + th->doff) * 4;
@@ -484,7 +484,7 @@ index 690a1aa..9bcaa80 100644
unsigned int offset = 0;
u32 seq = ntohl(th->seq);
u16 id = ntohs(iph->id);
-@@ -139,7 +139,7 @@ #ifndef LOOPBACK_MUST_CHECKSUM
+@@ -139,7 +139,7 @@
#endif
#ifdef LOOPBACK_TSO
@@ -493,11 +493,11 @@ index 690a1aa..9bcaa80 100644
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
-diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
-index c0998ef..0fac9d5 100644
---- a/drivers/net/mv643xx_eth.c
-+++ b/drivers/net/mv643xx_eth.c
-@@ -1107,7 +1107,7 @@ static int mv643xx_eth_start_xmit(struct
+Index: tmp-xxx/drivers/net/mv643xx_eth.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/mv643xx_eth.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/mv643xx_eth.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1107,7 +1107,7 @@
#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
if (has_tiny_unaligned_frags(skb)) {
@@ -506,11 +506,11 @@ index c0998ef..0fac9d5 100644
stats->tx_dropped++;
printk(KERN_DEBUG "%s: failed to linearize tiny "
"unaligned fragment\n", dev->name);
-diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
-index 9d6d254..c9ed624 100644
---- a/drivers/net/natsemi.c
-+++ b/drivers/net/natsemi.c
-@@ -323,12 +323,12 @@ performance critical codepaths:
+Index: tmp-xxx/drivers/net/natsemi.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/natsemi.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/natsemi.c 2006-11-27 10:52:42.000000000 +0000
+@@ -323,12 +323,12 @@
The rx process only runs in the interrupt handler. Access from outside
the interrupt handler is only permitted after disable_irq().
@@ -525,11 +525,11 @@ index 9d6d254..c9ed624 100644
spin_lock_irq(&np->lock);
IV. Notes
-diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
-index 8cc0d0b..e53b313 100644
---- a/drivers/net/r8169.c
-+++ b/drivers/net/r8169.c
-@@ -2171,7 +2171,7 @@ static int rtl8169_xmit_frags(struct rtl
+Index: tmp-xxx/drivers/net/r8169.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/r8169.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/r8169.c 2006-11-27 10:52:42.000000000 +0000
+@@ -2171,7 +2171,7 @@
static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
{
if (dev->features & NETIF_F_TSO) {
@@ -538,11 +538,11 @@ index 8cc0d0b..e53b313 100644
if (mss)
return LargeSend | ((mss & MSSMask) << MSSShift);
-diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
-index b7f00d6..439f45f 100644
---- a/drivers/net/s2io.c
-+++ b/drivers/net/s2io.c
-@@ -3522,8 +3522,8 @@ #endif
+Index: tmp-xxx/drivers/net/s2io.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/s2io.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/s2io.c 2006-11-27 10:52:42.000000000 +0000
+@@ -3522,8 +3522,8 @@
txdp->Control_1 = 0;
txdp->Control_2 = 0;
#ifdef NETIF_F_TSO
@@ -553,7 +553,7 @@ index b7f00d6..439f45f 100644
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
}
-@@ -3543,10 +3543,10 @@ #endif
+@@ -3543,10 +3543,10 @@
}
frg_len = skb->len - skb->data_len;
@@ -566,7 +566,7 @@ index b7f00d6..439f45f 100644
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
-@@ -3572,7 +3572,7 @@ #endif
+@@ -3572,7 +3572,7 @@
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
@@ -575,7 +575,7 @@ index b7f00d6..439f45f 100644
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
-@@ -3587,12 +3587,12 @@ #endif
+@@ -3587,12 +3587,12 @@
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
@@ -590,7 +590,7 @@ index b7f00d6..439f45f 100644
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
-@@ -3606,7 +3606,7 @@ #ifdef NETIF_F_TSO
+@@ -3606,7 +3606,7 @@
if (mss)
val64 |= TX_FIFO_SPECIAL_FUNC;
#endif
@@ -599,11 +599,11 @@ index b7f00d6..439f45f 100644
val64 |= TX_FIFO_SPECIAL_FUNC;
writeq(val64, &tx_fifo->List_Control);
-diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
-index 0618cd5..2a55eb3 100644
---- a/drivers/net/sky2.c
-+++ b/drivers/net/sky2.c
-@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
+Index: tmp-xxx/drivers/net/sky2.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/sky2.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/sky2.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1141,7 +1141,7 @@
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
@@ -612,7 +612,7 @@ index 0618cd5..2a55eb3 100644
++count;
if (skb->ip_summed == CHECKSUM_HW)
-@@ -1197,7 +1197,7 @@ static int sky2_xmit_frame(struct sk_buf
+@@ -1213,7 +1213,7 @@
}
/* Check for TCP Segmentation Offload */
@@ -621,11 +621,11 @@ index 0618cd5..2a55eb3 100644
if (mss != 0) {
/* just drop the packet if non-linear expansion fails */
if (skb_header_cloned(skb) &&
-diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
-index caf4102..fc9164a 100644
---- a/drivers/net/tg3.c
-+++ b/drivers/net/tg3.c
-@@ -3664,7 +3664,7 @@ static int tg3_start_xmit(struct sk_buff
+Index: tmp-xxx/drivers/net/tg3.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/tg3.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/tg3.c 2006-11-27 10:52:42.000000000 +0000
+@@ -3664,7 +3664,7 @@
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
@@ -634,11 +634,11 @@ index caf4102..fc9164a 100644
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
-diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
-index 5b1af39..11de5af 100644
---- a/drivers/net/tulip/winbond-840.c
-+++ b/drivers/net/tulip/winbond-840.c
-@@ -1605,11 +1605,11 @@ #ifdef CONFIG_PM
+Index: tmp-xxx/drivers/net/tulip/winbond-840.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/tulip/winbond-840.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/tulip/winbond-840.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1605,11 +1605,11 @@
* - get_stats:
* spin_lock_irq(np->lock), doesn't touch hw if not present
* - hard_start_xmit:
@@ -653,7 +653,7 @@ index 5b1af39..11de5af 100644
* - interrupt handler
* doesn't touch hw if not present, synchronize_irq waits for
* running instances of the interrupt handler.
-@@ -1635,11 +1635,10 @@ static int w840_suspend (struct pci_dev
+@@ -1635,11 +1635,10 @@
netif_device_detach(dev);
update_csr6(dev, 0);
iowrite32(0, ioaddr + IntrEnable);
@@ -666,11 +666,11 @@ index 5b1af39..11de5af 100644
np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
-diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
-index 4c76cb7..30c48c9 100644
---- a/drivers/net/typhoon.c
-+++ b/drivers/net/typhoon.c
-@@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch
+Index: tmp-xxx/drivers/net/typhoon.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/typhoon.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/typhoon.c 2006-11-27 10:52:42.000000000 +0000
+@@ -340,7 +340,7 @@
#endif
#if defined(NETIF_F_TSO)
@@ -679,11 +679,11 @@ index 4c76cb7..30c48c9 100644
#define TSO_NUM_DESCRIPTORS 2
#define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT
#else
-diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
-index ed1f837..2eb6b5f 100644
---- a/drivers/net/via-velocity.c
-+++ b/drivers/net/via-velocity.c
-@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff
+Index: tmp-xxx/drivers/net/via-velocity.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/via-velocity.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/via-velocity.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1905,6 +1905,13 @@
int pktlen = skb->len;
@@ -697,7 +697,7 @@ index ed1f837..2eb6b5f 100644
spin_lock_irqsave(&vptr->lock, flags);
index = vptr->td_curr[qnum];
-@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff
+@@ -1920,8 +1927,6 @@
*/
if (pktlen < ETH_ZLEN) {
/* Cannot occur until ZC support */
@@ -706,7 +706,7 @@ index ed1f837..2eb6b5f 100644
pktlen = ETH_ZLEN;
memcpy(tdinfo->buf, skb->data, skb->len);
memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
-@@ -1933,7 +1938,6 @@ #ifdef VELOCITY_ZERO_COPY_SUPPORT
+@@ -1939,7 +1944,6 @@
int nfrags = skb_shinfo(skb)->nr_frags;
tdinfo->skb = skb;
if (nfrags > 6) {
@@ -714,11 +714,11 @@ index ed1f837..2eb6b5f 100644
memcpy(tdinfo->buf, skb->data, skb->len);
tdinfo->skb_dma[0] = tdinfo->buf_dma;
td_ptr->tdesc0.pktsize =
-diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
-index 6fd0bf7..75237c1 100644
---- a/drivers/net/wireless/orinoco.c
-+++ b/drivers/net/wireless/orinoco.c
-@@ -1835,7 +1835,9 @@ static int __orinoco_program_rids(struct
+Index: tmp-xxx/drivers/net/wireless/orinoco.c
+===================================================================
+--- tmp-xxx.orig/drivers/net/wireless/orinoco.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/net/wireless/orinoco.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1835,7 +1835,9 @@
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
@@ -729,11 +729,11 @@ index 6fd0bf7..75237c1 100644
return 0;
}
-diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
-index 82cb4af..57cec40 100644
---- a/drivers/s390/net/qeth_eddp.c
-+++ b/drivers/s390/net/qeth_eddp.c
-@@ -421,7 +421,7 @@ #endif /* CONFIG_QETH_VLAN */
+Index: tmp-xxx/drivers/s390/net/qeth_eddp.c
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_eddp.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/s390/net/qeth_eddp.c 2006-11-27 10:52:42.000000000 +0000
+@@ -421,7 +421,7 @@
}
tcph = eddp->skb->h.th;
while (eddp->skb_offset < eddp->skb->len) {
@@ -742,7 +742,7 @@ index 82cb4af..57cec40 100644
(int)(eddp->skb->len - eddp->skb_offset));
/* prepare qdio hdr */
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
-@@ -516,20 +516,20 @@ qeth_eddp_calc_num_pages(struct qeth_edd
+@@ -516,20 +516,20 @@
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
@@ -768,11 +768,11 @@ index 82cb4af..57cec40 100644
}
static inline struct qeth_eddp_context *
-diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
-index dba7f7f..d9cc997 100644
---- a/drivers/s390/net/qeth_main.c
-+++ b/drivers/s390/net/qeth_main.c
-@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
+Index: tmp-xxx/drivers/s390/net/qeth_main.c
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_main.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/s390/net/qeth_main.c 2006-11-27 10:52:42.000000000 +0000
+@@ -4454,7 +4454,7 @@
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
@@ -781,7 +781,7 @@ index dba7f7f..d9cc997 100644
large_send = card->options.large_send;
/*are we able to do TSO ? If so ,prepare and send it from here */
-@@ -4501,7 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
+@@ -4501,7 +4501,7 @@
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
#ifdef CONFIG_QETH_PERF_STATS
@@ -790,11 +790,11 @@ index dba7f7f..d9cc997 100644
!(large_send == QETH_LARGE_SEND_NO)) {
card->perf_stats.large_send_bytes += skb->len;
card->perf_stats.large_send_cnt++;
-diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
-index 1286dde..89cbf34 100644
---- a/drivers/s390/net/qeth_tso.h
-+++ b/drivers/s390/net/qeth_tso.h
-@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
+Index: tmp-xxx/drivers/s390/net/qeth_tso.h
+===================================================================
+--- tmp-xxx.orig/drivers/s390/net/qeth_tso.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/drivers/s390/net/qeth_tso.h 2006-11-27 10:52:42.000000000 +0000
+@@ -51,7 +51,7 @@
hdr->ext.hdr_version = 1;
hdr->ext.hdr_len = 28;
/*insert non-fix values */
@@ -803,11 +803,11 @@ index 1286dde..89cbf34 100644
hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
sizeof(struct qeth_hdr_tso));
-diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
-index 93535f0..9269df7 100644
---- a/include/linux/ethtool.h
-+++ b/include/linux/ethtool.h
-@@ -408,6 +408,8 @@ #define ETHTOOL_STSO 0x0000001f /* Set
+Index: tmp-xxx/include/linux/ethtool.h
+===================================================================
+--- tmp-xxx.orig/include/linux/ethtool.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/linux/ethtool.h 2006-11-27 10:52:42.000000000 +0000
+@@ -408,6 +408,8 @@
#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
@@ -816,11 +816,11 @@ index 93535f0..9269df7 100644
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
-diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 7fda03d..47b0965 100644
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -230,7 +230,8 @@ enum netdev_state_t
+Index: tmp-xxx/include/linux/netdevice.h
+===================================================================
+--- tmp-xxx.orig/include/linux/netdevice.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/linux/netdevice.h 2006-11-27 10:52:42.000000000 +0000
+@@ -230,7 +230,8 @@
__LINK_STATE_SCHED,
__LINK_STATE_NOCARRIER,
__LINK_STATE_RX_SCHED,
@@ -830,7 +830,7 @@ index 7fda03d..47b0965 100644
};
-@@ -306,9 +307,17 @@ #define NETIF_F_HW_VLAN_TX 128 /* Transm
+@@ -306,9 +307,17 @@
#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
@@ -850,7 +850,7 @@ index 7fda03d..47b0965 100644
struct net_device *next_sched;
-@@ -394,6 +403,9 @@ #define NETIF_F_UFO 8192
+@@ -394,6 +403,9 @@
struct list_head qdisc_list;
unsigned long tx_queue_len; /* Max frames per queue allowed */
@@ -860,7 +860,7 @@ index 7fda03d..47b0965 100644
/* ingress path synchronizer */
spinlock_t ingress_lock;
struct Qdisc *qdisc_ingress;
-@@ -402,7 +414,7 @@ #define NETIF_F_UFO 8192
+@@ -402,7 +414,7 @@
* One part is mostly used on xmit path (device)
*/
/* hard_start_xmit synchronizer */
@@ -869,7 +869,7 @@ index 7fda03d..47b0965 100644
/* cpu id of processor entered to hard_start_xmit or -1,
if nobody entered there.
*/
-@@ -527,6 +539,8 @@ struct packet_type {
+@@ -527,6 +539,8 @@
struct net_device *,
struct packet_type *,
struct net_device *);
@@ -878,7 +878,7 @@ index 7fda03d..47b0965 100644
void *af_packet_priv;
struct list_head list;
};
-@@ -693,7 +707,8 @@ extern int dev_change_name(struct net_d
+@@ -693,7 +707,8 @@
extern int dev_set_mtu(struct net_device *, int);
extern int dev_set_mac_address(struct net_device *,
struct sockaddr *);
@@ -888,7 +888,7 @@ index 7fda03d..47b0965 100644
extern void dev_init(void);
-@@ -900,11 +915,43 @@ static inline void __netif_rx_complete(s
+@@ -900,11 +915,43 @@
clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
@@ -934,7 +934,7 @@ index 7fda03d..47b0965 100644
}
/* These functions live elsewhere (drivers/net/net_init.c, but related) */
-@@ -932,6 +979,7 @@ extern int netdev_max_backlog;
+@@ -932,6 +979,7 @@
extern int weight_p;
extern int netdev_set_master(struct net_device *dev, struct net_device *master);
extern int skb_checksum_help(struct sk_buff *skb, int inward);
@@ -942,7 +942,7 @@ index 7fda03d..47b0965 100644
#ifdef CONFIG_BUG
extern void netdev_rx_csum_fault(struct net_device *dev);
#else
-@@ -951,6 +999,18 @@ #endif
+@@ -951,6 +999,18 @@
extern void linkwatch_run_queue(void);
@@ -961,11 +961,11 @@ index 7fda03d..47b0965 100644
#endif /* __KERNEL__ */
#endif /* _LINUX_DEV_H */
-diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
-index ad7cc22..b19d45d 100644
---- a/include/linux/skbuff.h
-+++ b/include/linux/skbuff.h
-@@ -134,9 +134,10 @@ struct skb_frag_struct {
+Index: tmp-xxx/include/linux/skbuff.h
+===================================================================
+--- tmp-xxx.orig/include/linux/skbuff.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/linux/skbuff.h 2006-11-27 10:52:42.000000000 +0000
+@@ -134,9 +134,10 @@
struct skb_shared_info {
atomic_t dataref;
unsigned short nr_frags;
@@ -979,7 +979,7 @@ index ad7cc22..b19d45d 100644
unsigned int ip6_frag_id;
struct sk_buff *frag_list;
skb_frag_t frags[MAX_SKB_FRAGS];
-@@ -168,6 +169,14 @@ enum {
+@@ -168,6 +169,14 @@
SKB_FCLONE_CLONE,
};
@@ -994,7 +994,7 @@ index ad7cc22..b19d45d 100644
/**
* struct sk_buff - socket buffer
* @next: Next buffer in list
-@@ -1148,18 +1157,34 @@ static inline int skb_can_coalesce(struc
+@@ -1148,18 +1157,34 @@
return 0;
}
@@ -1033,7 +1033,7 @@ index ad7cc22..b19d45d 100644
}
/**
-@@ -1254,6 +1279,7 @@ extern void skb_split(struct sk_b
+@@ -1254,6 +1279,7 @@
struct sk_buff *skb1, const u32 len);
extern void skb_release_data(struct sk_buff *skb);
@@ -1041,11 +1041,11 @@ index ad7cc22..b19d45d 100644
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
-diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
-index b94d1ad..75b5b93 100644
---- a/include/net/pkt_sched.h
-+++ b/include/net/pkt_sched.h
-@@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_ge
+Index: tmp-xxx/include/net/pkt_sched.h
+===================================================================
+--- tmp-xxx.orig/include/net/pkt_sched.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/pkt_sched.h 2006-11-27 10:52:42.000000000 +0000
+@@ -218,12 +218,13 @@
struct rtattr *tab);
extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
@@ -1062,11 +1062,11 @@ index b94d1ad..75b5b93 100644
}
extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
-diff --git a/include/net/protocol.h b/include/net/protocol.h
-index 6dc5970..0d2dcdb 100644
---- a/include/net/protocol.h
-+++ b/include/net/protocol.h
-@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS 256 /* Must be
+Index: tmp-xxx/include/net/protocol.h
+===================================================================
+--- tmp-xxx.orig/include/net/protocol.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/protocol.h 2006-11-27 10:52:42.000000000 +0000
+@@ -37,6 +37,8 @@
struct net_protocol {
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
@@ -1075,11 +1075,11 @@ index 6dc5970..0d2dcdb 100644
int no_policy;
};
-diff --git a/include/net/sock.h b/include/net/sock.h
-index f63d0d5..a8e8d21 100644
---- a/include/net/sock.h
-+++ b/include/net/sock.h
-@@ -1064,9 +1064,13 @@ static inline void sk_setup_caps(struct
+Index: tmp-xxx/include/net/sock.h
+===================================================================
+--- tmp-xxx.orig/include/net/sock.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/sock.h 2006-11-27 10:52:42.000000000 +0000
+@@ -1064,9 +1064,13 @@
{
__sk_dst_set(sk, dst);
sk->sk_route_caps = dst->dev->features;
@@ -1093,11 +1093,11 @@ index f63d0d5..a8e8d21 100644
}
}
-diff --git a/include/net/tcp.h b/include/net/tcp.h
-index 77f21c6..70e1d5f 100644
---- a/include/net/tcp.h
-+++ b/include/net/tcp.h
-@@ -552,13 +552,13 @@ #include <net/tcp_ecn.h>
+Index: tmp-xxx/include/net/tcp.h
+===================================================================
+--- tmp-xxx.orig/include/net/tcp.h 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/include/net/tcp.h 2006-11-27 10:52:42.000000000 +0000
+@@ -552,13 +552,13 @@
*/
static inline int tcp_skb_pcount(const struct sk_buff *skb)
{
@@ -1113,7 +1113,7 @@ index 77f21c6..70e1d5f 100644
}
static inline void tcp_dec_pcount_approx(__u32 *count,
-@@ -1063,6 +1063,8 @@ extern struct request_sock_ops tcp_reque
+@@ -1063,6 +1063,8 @@
extern int tcp_v4_destroy_sock(struct sock *sk);
@@ -1122,11 +1122,11 @@ index 77f21c6..70e1d5f 100644
#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
-diff --git a/net/atm/clip.c b/net/atm/clip.c
-index 1842a4e..6dc21a7 100644
---- a/net/atm/clip.c
-+++ b/net/atm/clip.c
-@@ -101,7 +101,7 @@ static void unlink_clip_vcc(struct clip_
+Index: tmp-xxx/net/atm/clip.c
+===================================================================
+--- tmp-xxx.orig/net/atm/clip.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/atm/clip.c 2006-11-27 10:52:42.000000000 +0000
+@@ -101,7 +101,7 @@
printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc);
return;
}
@@ -1135,7 +1135,7 @@ index 1842a4e..6dc21a7 100644
entry->neigh->used = jiffies;
for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
if (*walk == clip_vcc) {
-@@ -125,7 +125,7 @@ static void unlink_clip_vcc(struct clip_
+@@ -125,7 +125,7 @@
printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
"0x%p)\n",entry,clip_vcc);
out:
@@ -1144,11 +1144,11 @@ index 1842a4e..6dc21a7 100644
}
/* The neighbour entry n->lock is held. */
-diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
-index 0b33a7b..180e79b 100644
---- a/net/bridge/br_device.c
-+++ b/net/bridge/br_device.c
-@@ -146,9 +146,9 @@ static int br_set_tx_csum(struct net_dev
+Index: tmp-xxx/net/bridge/br_device.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_device.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/bridge/br_device.c 2006-11-27 10:52:42.000000000 +0000
+@@ -146,9 +146,9 @@
struct net_bridge *br = netdev_priv(dev);
if (data)
@@ -1160,7 +1160,7 @@ index 0b33a7b..180e79b 100644
br_features_recompute(br);
return 0;
-@@ -185,6 +185,6 @@ void br_dev_setup(struct net_device *dev
+@@ -185,6 +185,6 @@
dev->set_mac_address = br_set_mac_address;
dev->priv_flags = IFF_EBRIDGE;
@@ -1169,11 +1169,11 @@ index 0b33a7b..180e79b 100644
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
+ NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
}
-diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
-index 2d24fb4..00b1128 100644
---- a/net/bridge/br_forward.c
-+++ b/net/bridge/br_forward.c
-@@ -32,7 +32,7 @@ static inline int should_deliver(const s
+Index: tmp-xxx/net/bridge/br_forward.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_forward.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/bridge/br_forward.c 2006-11-27 10:52:42.000000000 +0000
+@@ -32,7 +32,7 @@
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
/* drop mtu oversized packets except tso */
@@ -1182,11 +1182,11 @@ index 2d24fb4..00b1128 100644
kfree_skb(skb);
else {
#ifdef CONFIG_BRIDGE_NETFILTER
-diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
-index f36b35e..0617146 100644
---- a/net/bridge/br_if.c
-+++ b/net/bridge/br_if.c
-@@ -385,17 +385,28 @@ void br_features_recompute(struct net_br
+Index: tmp-xxx/net/bridge/br_if.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_if.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/bridge/br_if.c 2006-11-27 10:52:42.000000000 +0000
+@@ -385,17 +385,28 @@
struct net_bridge_port *p;
unsigned long features, checksum;
@@ -1221,11 +1221,11 @@ index f36b35e..0617146 100644
}
/* called with RTNL */
-diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
-index 9e27373..588207f 100644
---- a/net/bridge/br_netfilter.c
-+++ b/net/bridge/br_netfilter.c
-@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
+Index: tmp-xxx/net/bridge/br_netfilter.c
+===================================================================
+--- tmp-xxx.orig/net/bridge/br_netfilter.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/bridge/br_netfilter.c 2006-11-27 10:52:42.000000000 +0000
+@@ -743,7 +743,7 @@
{
if (skb->protocol == htons(ETH_P_IP) &&
skb->len > skb->dev->mtu &&
@@ -1234,11 +1234,11 @@ index 9e27373..588207f 100644
return ip_fragment(skb, br_dev_queue_push_xmit);
else
return br_dev_queue_push_xmit(skb);
-diff --git a/net/core/dev.c b/net/core/dev.c
-index 12a214c..32e1056 100644
---- a/net/core/dev.c
-+++ b/net/core/dev.c
-@@ -115,6 +115,7 @@ #include <linux/wireless.h> /* Note : w
+Index: tmp-xxx/net/core/dev.c
+===================================================================
+--- tmp-xxx.orig/net/core/dev.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/dev.c 2006-11-27 10:57:31.000000000 +0000
+@@ -115,6 +115,7 @@
#include <net/iw_handler.h>
#endif /* CONFIG_NET_RADIO */
#include <asm/current.h>
@@ -1246,7 +1246,7 @@ index 12a214c..32e1056 100644
/*
* The list of packet types we will receive (as opposed to discard)
-@@ -1032,7 +1033,7 @@ static inline void net_timestamp(struct
+@@ -1032,7 +1033,7 @@
* taps currently in use.
*/
@@ -1255,7 +1255,7 @@ index 12a214c..32e1056 100644
{
struct packet_type *ptype;
-@@ -1106,6 +1107,45 @@ out:
+@@ -1106,6 +1107,45 @@
return ret;
}
@@ -1301,13 +1301,20 @@ index 12a214c..32e1056 100644
/* Take action when hardware reception checksum errors are detected. */
#ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev)
-@@ -1142,75 +1182,108 @@ #else
+@@ -1142,76 +1182,107 @@
#define illegal_highdma(dev, skb) (0)
#endif
-/* Keep head the same: replace data */
-int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
--{
++struct dev_gso_cb {
++ void (*destructor)(struct sk_buff *skb);
++};
++
++#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
++
++static void dev_gso_skb_destructor(struct sk_buff *skb)
+ {
- unsigned int size;
- u8 *data;
- long offset;
@@ -1336,6 +1343,7 @@ index 12a214c..32e1056 100644
- atomic_set(&ninfo->dataref, 1);
- ninfo->tso_size = skb_shinfo(skb)->tso_size;
- ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
+- ninfo->ufo_size = skb_shinfo(skb)->ufo_size;
- ninfo->nr_frags = 0;
- ninfo->frag_list = NULL;
-
@@ -1354,25 +1362,15 @@ index 12a214c..32e1056 100644
- skb->mac.raw += offset;
- skb->tail += offset;
- skb->data += offset;
--
++ struct dev_gso_cb *cb;
+
- /* We are no longer a clone, even if we were. */
- skb->cloned = 0;
--
-- skb->tail += skb->data_len;
-- skb->data_len = 0;
-+struct dev_gso_cb {
-+ void (*destructor)(struct sk_buff *skb);
-+};
-+
-+#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
-+
-+static void dev_gso_skb_destructor(struct sk_buff *skb)
-+{
-+ struct dev_gso_cb *cb;
-+
+ do {
+ struct sk_buff *nskb = skb->next;
-+
+
+- skb->tail += skb->data_len;
+- skb->data_len = 0;
+ skb->next = nskb->next;
+ nskb->next = NULL;
+ kfree_skb(nskb);
@@ -1402,14 +1400,13 @@ index 12a214c..32e1056 100644
+ /* Verifying header integrity only. */
+ if (!segs)
+ return 0;
-+
++
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ skb->next = segs;
+ DEV_GSO_CB(skb)->destructor = skb->destructor;
+ skb->destructor = dev_gso_skb_destructor;
-+
+ return 0;
+}
+
@@ -1469,7 +1466,7 @@ index 12a214c..32e1056 100644
} \
}
-@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
+@@ -1247,9 +1318,13 @@
struct Qdisc *q;
int rc = -ENOMEM;
@@ -1484,7 +1481,7 @@ index 12a214c..32e1056 100644
goto out_kfree_skb;
/* Fragmented skb is linearized if device does not support SG,
-@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
+@@ -1258,25 +1333,26 @@
*/
if (skb_shinfo(skb)->nr_frags &&
(!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
@@ -1514,7 +1511,7 @@ index 12a214c..32e1056 100644
/* Updates of qdisc are serialized by queue_lock.
* The struct Qdisc which is pointed to by qdisc is now a
-@@ -1309,8 +1387,8 @@ #endif
+@@ -1310,8 +1386,8 @@
/* The device has no queue. Common case for software devices:
loopback, all the sorts of tunnels...
@@ -1525,7 +1522,7 @@ index 12a214c..32e1056 100644
counters.)
However, it is possible, that they rely on protection
made by us here.
-@@ -1326,11 +1404,8 @@ #endif
+@@ -1327,11 +1403,8 @@
HARD_TX_LOCK(dev, cpu);
if (!netif_queue_stopped(dev)) {
@@ -1538,7 +1535,7 @@ index 12a214c..32e1056 100644
HARD_TX_UNLOCK(dev);
goto out;
}
-@@ -1349,13 +1424,13 @@ #endif
+@@ -1350,13 +1423,13 @@
}
rc = -ENETDOWN;
@@ -1554,7 +1551,7 @@ index 12a214c..32e1056 100644
return rc;
}
-@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
+@@ -2671,7 +2744,7 @@
BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
spin_lock_init(&dev->queue_lock);
@@ -1563,7 +1560,7 @@ index 12a214c..32e1056 100644
dev->xmit_lock_owner = -1;
#ifdef CONFIG_NET_CLS_ACT
spin_lock_init(&dev->ingress_lock);
-@@ -2714,9 +2789,7 @@ #endif
+@@ -2715,9 +2788,7 @@
/* Fix illegal SG+CSUM combinations. */
if ((dev->features & NETIF_F_SG) &&
@@ -1574,7 +1571,7 @@ index 12a214c..32e1056 100644
printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
dev->name);
dev->features &= ~NETIF_F_SG;
-@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
+@@ -3269,7 +3340,6 @@
EXPORT_SYMBOL(__dev_get_by_index);
EXPORT_SYMBOL(__dev_get_by_name);
EXPORT_SYMBOL(__dev_remove_pack);
@@ -1582,11 +1579,11 @@ index 12a214c..32e1056 100644
EXPORT_SYMBOL(dev_valid_name);
EXPORT_SYMBOL(dev_add_pack);
EXPORT_SYMBOL(dev_alloc_name);
-diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
-index 05d6085..c57d887 100644
---- a/net/core/dev_mcast.c
-+++ b/net/core/dev_mcast.c
-@@ -62,7 +62,7 @@ #include <net/arp.h>
+Index: tmp-xxx/net/core/dev_mcast.c
+===================================================================
+--- tmp-xxx.orig/net/core/dev_mcast.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/dev_mcast.c 2006-11-27 10:52:42.000000000 +0000
+@@ -62,7 +62,7 @@
* Device mc lists are changed by bh at least if IPv6 is enabled,
* so that it must be bh protected.
*
@@ -1595,7 +1592,7 @@ index 05d6085..c57d887 100644
*/
/*
-@@ -93,9 +93,9 @@ static void __dev_mc_upload(struct net_d
+@@ -93,9 +93,9 @@
void dev_mc_upload(struct net_device *dev)
{
@@ -1607,7 +1604,7 @@ index 05d6085..c57d887 100644
}
/*
-@@ -107,7 +107,7 @@ int dev_mc_delete(struct net_device *dev
+@@ -107,7 +107,7 @@
int err = 0;
struct dev_mc_list *dmi, **dmip;
@@ -1616,7 +1613,7 @@ index 05d6085..c57d887 100644
for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
/*
-@@ -139,13 +139,13 @@ int dev_mc_delete(struct net_device *dev
+@@ -139,13 +139,13 @@
*/
__dev_mc_upload(dev);
@@ -1632,7 +1629,7 @@ index 05d6085..c57d887 100644
return err;
}
-@@ -160,7 +160,7 @@ int dev_mc_add(struct net_device *dev, v
+@@ -160,7 +160,7 @@
dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC);
@@ -1641,7 +1638,7 @@ index 05d6085..c57d887 100644
for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
dmi->dmi_addrlen == alen) {
-@@ -176,7 +176,7 @@ int dev_mc_add(struct net_device *dev, v
+@@ -176,7 +176,7 @@
}
if ((dmi = dmi1) == NULL) {
@@ -1650,7 +1647,7 @@ index 05d6085..c57d887 100644
return -ENOMEM;
}
memcpy(dmi->dmi_addr, addr, alen);
-@@ -189,11 +189,11 @@ int dev_mc_add(struct net_device *dev, v
+@@ -189,11 +189,11 @@
__dev_mc_upload(dev);
@@ -1664,7 +1661,7 @@ index 05d6085..c57d887 100644
kfree(dmi1);
return err;
}
-@@ -204,7 +204,7 @@ done:
+@@ -204,7 +204,7 @@
void dev_mc_discard(struct net_device *dev)
{
@@ -1673,7 +1670,7 @@ index 05d6085..c57d887 100644
while (dev->mc_list != NULL) {
struct dev_mc_list *tmp = dev->mc_list;
-@@ -215,7 +215,7 @@ void dev_mc_discard(struct net_device *d
+@@ -215,7 +215,7 @@
}
dev->mc_count = 0;
@@ -1682,7 +1679,7 @@ index 05d6085..c57d887 100644
}
#ifdef CONFIG_PROC_FS
-@@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_fi
+@@ -250,7 +250,7 @@
struct dev_mc_list *m;
struct net_device *dev = v;
@@ -1691,7 +1688,7 @@ index 05d6085..c57d887 100644
for (m = dev->mc_list; m; m = m->next) {
int i;
-@@ -262,7 +262,7 @@ static int dev_mc_seq_show(struct seq_fi
+@@ -262,7 +262,7 @@
seq_putc(seq, '\n');
}
@@ -1700,11 +1697,11 @@ index 05d6085..c57d887 100644
return 0;
}
-diff --git a/net/core/ethtool.c b/net/core/ethtool.c
-index e6f7610..27ce168 100644
---- a/net/core/ethtool.c
-+++ b/net/core/ethtool.c
-@@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_devic
+Index: tmp-xxx/net/core/ethtool.c
+===================================================================
+--- tmp-xxx.orig/net/core/ethtool.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/ethtool.c 2006-11-27 10:52:42.000000000 +0000
+@@ -30,7 +30,7 @@
u32 ethtool_op_get_tx_csum(struct net_device *dev)
{
@@ -1713,7 +1710,7 @@ index e6f7610..27ce168 100644
}
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-@@ -551,9 +551,7 @@ static int ethtool_set_sg(struct net_dev
+@@ -551,9 +551,7 @@
return -EFAULT;
if (edata.data &&
@@ -1724,24 +1721,16 @@ index e6f7610..27ce168 100644
return -EINVAL;
return __ethtool_set_sg(dev, edata.data);
-@@ -591,7 +589,7 @@ static int ethtool_set_tso(struct net_de
+@@ -561,7 +559,7 @@
- static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
+ static int ethtool_get_tso(struct net_device *dev, char __user *useraddr)
{
- struct ethtool_value edata = { ETHTOOL_GTSO };
+ struct ethtool_value edata = { ETHTOOL_GUFO };
- if (!dev->ethtool_ops->get_ufo)
+ if (!dev->ethtool_ops->get_tso)
return -EOPNOTSUPP;
-@@ -600,6 +598,7 @@ static int ethtool_get_ufo(struct net_de
- return -EFAULT;
- return 0;
- }
-+
- static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
- {
- struct ethtool_value edata;
-@@ -615,6 +614,29 @@ static int ethtool_set_ufo(struct net_de
+@@ -616,6 +614,29 @@
return dev->ethtool_ops->set_ufo(dev, edata.data);
}
@@ -1771,7 +1760,7 @@ index e6f7610..27ce168 100644
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{
struct ethtool_test test;
-@@ -906,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
+@@ -907,6 +928,12 @@
case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr);
break;
@@ -1784,11 +1773,11 @@ index e6f7610..27ce168 100644
default:
rc = -EOPNOTSUPP;
}
-diff --git a/net/core/netpoll.c b/net/core/netpoll.c
-index ea51f8d..ec28d3b 100644
---- a/net/core/netpoll.c
-+++ b/net/core/netpoll.c
-@@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netp
+Index: tmp-xxx/net/core/netpoll.c
+===================================================================
+--- tmp-xxx.orig/net/core/netpoll.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/netpoll.c 2006-11-27 10:52:42.000000000 +0000
+@@ -273,24 +273,21 @@
do {
npinfo->tries--;
@@ -1816,11 +1805,11 @@ index ea51f8d..ec28d3b 100644
/* success */
if(!status) {
-diff --git a/net/core/pktgen.c b/net/core/pktgen.c
-index da16f8f..2380347 100644
---- a/net/core/pktgen.c
-+++ b/net/core/pktgen.c
-@@ -2582,7 +2582,7 @@ static __inline__ void pktgen_xmit(struc
+Index: tmp-xxx/net/core/pktgen.c
+===================================================================
+--- tmp-xxx.orig/net/core/pktgen.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/pktgen.c 2006-11-27 10:52:42.000000000 +0000
+@@ -2586,7 +2586,7 @@
}
}
@@ -1829,7 +1818,7 @@ index da16f8f..2380347 100644
if (!netif_queue_stopped(odev)) {
atomic_inc(&(pkt_dev->skb->users));
-@@ -2627,7 +2627,7 @@ retry_now:
+@@ -2631,7 +2631,7 @@
pkt_dev->next_tx_ns = 0;
}
@@ -1838,11 +1827,11 @@ index da16f8f..2380347 100644
/* If pkt_dev->count is zero, then run forever */
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
-diff --git a/net/core/skbuff.c b/net/core/skbuff.c
-index 2144952..46f56af 100644
---- a/net/core/skbuff.c
-+++ b/net/core/skbuff.c
-@@ -164,9 +164,9 @@ struct sk_buff *__alloc_skb(unsigned int
+Index: tmp-xxx/net/core/skbuff.c
+===================================================================
+--- tmp-xxx.orig/net/core/skbuff.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/core/skbuff.c 2006-11-27 10:58:31.000000000 +0000
+@@ -164,9 +164,9 @@
shinfo = skb_shinfo(skb);
atomic_set(&shinfo->dataref, 1);
shinfo->nr_frags = 0;
@@ -1855,31 +1844,33 @@ index 2144952..46f56af 100644
shinfo->ip6_frag_id = 0;
shinfo->frag_list = NULL;
-@@ -230,8 +230,9 @@ struct sk_buff *alloc_skb_from_cache(kme
+@@ -230,9 +230,9 @@
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
- skb_shinfo(skb)->tso_size = 0;
- skb_shinfo(skb)->tso_segs = 0;
+- skb_shinfo(skb)->ufo_size = 0;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_segs = 0;
+ skb_shinfo(skb)->gso_type = 0;
skb_shinfo(skb)->frag_list = NULL;
out:
return skb;
-@@ -501,8 +502,9 @@ #endif
+@@ -507,9 +507,9 @@
new->tc_index = old->tc_index;
#endif
atomic_set(&new->users, 1);
- skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
- skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
+- skb_shinfo(new)->ufo_size = skb_shinfo(old)->ufo_size;
+ skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
+ skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
+ skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
}
/**
-@@ -1777,6 +1779,133 @@ int skb_append_datato_frags(struct sock
+@@ -1822,6 +1822,133 @@
return 0;
}
@@ -2013,11 +2004,11 @@ index 2144952..46f56af 100644
void __init skb_init(void)
{
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
-diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
-index 44bda85..2e3323a 100644
---- a/net/decnet/dn_nsp_in.c
-+++ b/net/decnet/dn_nsp_in.c
-@@ -801,8 +801,7 @@ got_it:
+Index: tmp-xxx/net/decnet/dn_nsp_in.c
+===================================================================
+--- tmp-xxx.orig/net/decnet/dn_nsp_in.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/decnet/dn_nsp_in.c 2006-11-27 10:52:42.000000000 +0000
+@@ -801,8 +801,7 @@
* We linearize everything except data segments here.
*/
if (cb->nsp_flags & ~0x60) {
@@ -2027,11 +2018,11 @@ index 44bda85..2e3323a 100644
goto free_out;
}
-diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
-index 3407f19..a0a25e0 100644
---- a/net/decnet/dn_route.c
-+++ b/net/decnet/dn_route.c
-@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, st
+Index: tmp-xxx/net/decnet/dn_route.c
+===================================================================
+--- tmp-xxx.orig/net/decnet/dn_route.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/decnet/dn_route.c 2006-11-27 10:52:42.000000000 +0000
+@@ -629,8 +629,7 @@
padlen);
if (flags & DN_RT_PKT_CNTL) {
@@ -2041,10 +2032,10 @@ index 3407f19..a0a25e0 100644
goto dump_it;
switch(flags & DN_RT_CNTL_MSK) {
-diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
-index 97c276f..5ba719e 100644
---- a/net/ipv4/af_inet.c
-+++ b/net/ipv4/af_inet.c
+Index: tmp-xxx/net/ipv4/af_inet.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/af_inet.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/af_inet.c 2006-11-27 10:52:42.000000000 +0000
@@ -68,6 +68,7 @@
*/
@@ -2053,7 +2044,7 @@ index 97c276f..5ba719e 100644
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
-@@ -1084,6 +1085,54 @@ int inet_sk_rebuild_header(struct sock *
+@@ -1084,6 +1085,54 @@
EXPORT_SYMBOL(inet_sk_rebuild_header);
@@ -2108,7 +2099,7 @@ index 97c276f..5ba719e 100644
#ifdef CONFIG_IP_MULTICAST
static struct net_protocol igmp_protocol = {
.handler = igmp_rcv,
-@@ -1093,6 +1142,7 @@ #endif
+@@ -1093,6 +1142,7 @@
static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
@@ -2116,7 +2107,7 @@ index 97c276f..5ba719e 100644
.no_policy = 1,
};
-@@ -1138,6 +1188,7 @@ static int ipv4_proc_init(void);
+@@ -1138,6 +1188,7 @@
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
@@ -2124,11 +2115,11 @@ index 97c276f..5ba719e 100644
};
static int __init inet_init(void)
-diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
-index 8dcba38..19c3c73 100644
---- a/net/ipv4/ip_output.c
-+++ b/net/ipv4/ip_output.c
-@@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined
+Index: tmp-xxx/net/ipv4/ip_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/ip_output.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/ip_output.c 2006-11-27 10:52:42.000000000 +0000
+@@ -210,8 +210,7 @@
return dst_output(skb);
}
#endif
@@ -2138,7 +2129,7 @@ index 8dcba38..19c3c73 100644
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
-@@ -362,7 +361,7 @@ packet_routed:
+@@ -362,7 +361,7 @@
}
ip_select_ident_more(iph, &rt->u.dst, sk,
@@ -2147,7 +2138,7 @@ index 8dcba38..19c3c73 100644
/* Add an IP checksum. */
ip_send_check(iph);
-@@ -743,7 +742,8 @@ static inline int ip_ufo_append_data(str
+@@ -743,7 +742,8 @@
(length - transhdrlen));
if (!err) {
/* specify the length of each IP datagram fragment*/
@@ -2157,7 +2148,7 @@ index 8dcba38..19c3c73 100644
__skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
-@@ -839,7 +839,7 @@ int ip_append_data(struct sock *sk,
+@@ -839,7 +839,7 @@
*/
if (transhdrlen &&
length + fragheaderlen <= mtu &&
@@ -2166,7 +2157,7 @@ index 8dcba38..19c3c73 100644
!exthdrlen)
csummode = CHECKSUM_HW;
-@@ -1086,14 +1086,16 @@ ssize_t ip_append_page(struct sock *sk,
+@@ -1086,14 +1086,16 @@
inet->cork.length += size;
if ((sk->sk_protocol == IPPROTO_UDP) &&
@@ -2186,11 +2177,11 @@ index 8dcba38..19c3c73 100644
len = size;
else {
-diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
-index d64e2ec..7494823 100644
---- a/net/ipv4/ipcomp.c
-+++ b/net/ipv4/ipcomp.c
-@@ -84,7 +84,7 @@ static int ipcomp_input(struct xfrm_stat
+Index: tmp-xxx/net/ipv4/ipcomp.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/ipcomp.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/ipcomp.c 2006-11-27 10:52:42.000000000 +0000
+@@ -84,7 +84,7 @@
struct xfrm_decap_state *decap, struct sk_buff *skb)
{
u8 nexthdr;
@@ -2199,7 +2190,7 @@ index d64e2ec..7494823 100644
struct iphdr *iph;
union {
struct iphdr iph;
-@@ -92,11 +92,8 @@ static int ipcomp_input(struct xfrm_stat
+@@ -92,11 +92,8 @@
} tmp_iph;
@@ -2212,7 +2203,7 @@ index d64e2ec..7494823 100644
skb->ip_summed = CHECKSUM_NONE;
-@@ -171,10 +168,8 @@ static int ipcomp_output(struct xfrm_sta
+@@ -171,10 +168,8 @@
goto out_ok;
}
@@ -2224,11 +2215,11 @@ index d64e2ec..7494823 100644
err = ipcomp_compress(x, skb);
iph = skb->nh.iph;
-diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
-index 00aa80e..84130c9 100644
---- a/net/ipv4/tcp.c
-+++ b/net/ipv4/tcp.c
-@@ -257,6 +257,7 @@ #include <linux/smp_lock.h>
+Index: tmp-xxx/net/ipv4/tcp.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp.c 2006-11-27 10:52:42.000000000 +0000
+@@ -257,6 +257,7 @@
#include <linux/fs.h>
#include <linux/random.h>
#include <linux/bootmem.h>
@@ -2236,7 +2227,7 @@ index 00aa80e..84130c9 100644
#include <net/icmp.h>
#include <net/tcp.h>
-@@ -570,7 +571,7 @@ new_segment:
+@@ -570,7 +571,7 @@
skb->ip_summed = CHECKSUM_HW;
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
@@ -2245,7 +2236,7 @@ index 00aa80e..84130c9 100644
if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
-@@ -621,14 +622,10 @@ ssize_t tcp_sendpage(struct socket *sock
+@@ -621,14 +622,10 @@
ssize_t res;
struct sock *sk = sock->sk;
@@ -2261,7 +2252,7 @@ index 00aa80e..84130c9 100644
lock_sock(sk);
TCP_CHECK_TIMER(sk);
res = do_tcp_sendpages(sk, &page, offset, size, flags);
-@@ -725,9 +722,7 @@ new_segment:
+@@ -725,9 +722,7 @@
/*
* Check whether we can use HW checksum.
*/
@@ -2272,7 +2263,7 @@ index 00aa80e..84130c9 100644
skb->ip_summed = CHECKSUM_HW;
skb_entail(sk, tp, skb);
-@@ -823,7 +818,7 @@ new_segment:
+@@ -823,7 +818,7 @@
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
@@ -2281,7 +2272,7 @@ index 00aa80e..84130c9 100644
from += copy;
copied += copy;
-@@ -2026,6 +2021,71 @@ int tcp_getsockopt(struct sock *sk, int
+@@ -2026,6 +2021,71 @@
}
@@ -2353,11 +2344,11 @@ index 00aa80e..84130c9 100644
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;
-diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
-index e9a54ae..defe77a 100644
---- a/net/ipv4/tcp_input.c
-+++ b/net/ipv4/tcp_input.c
-@@ -1072,7 +1072,7 @@ tcp_sacktag_write_queue(struct sock *sk,
+Index: tmp-xxx/net/ipv4/tcp_input.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp_input.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp_input.c 2006-11-27 10:52:42.000000000 +0000
+@@ -1072,7 +1072,7 @@
else
pkt_len = (end_seq -
TCP_SKB_CB(skb)->seq);
@@ -2366,11 +2357,11 @@ index e9a54ae..defe77a 100644
break;
pcount = tcp_skb_pcount(skb);
}
-diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
-index 310f2e6..ee01f69 100644
---- a/net/ipv4/tcp_output.c
-+++ b/net/ipv4/tcp_output.c
-@@ -497,15 +497,17 @@ static void tcp_set_skb_tso_segs(struct
+Index: tmp-xxx/net/ipv4/tcp_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/tcp_output.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv4/tcp_output.c 2006-11-27 10:52:42.000000000 +0000
+@@ -497,15 +497,17 @@
/* Avoid the costly divide in the normal
* non-TSO case.
*/
@@ -2392,7 +2383,7 @@ index 310f2e6..ee01f69 100644
}
}
-@@ -850,7 +852,7 @@ static int tcp_init_tso_segs(struct sock
+@@ -850,7 +852,7 @@
if (!tso_segs ||
(tso_segs > 1 &&
@@ -2401,7 +2392,7 @@ index 310f2e6..ee01f69 100644
tcp_set_skb_tso_segs(sk, skb, mss_now);
tso_segs = tcp_skb_pcount(skb);
}
-@@ -1510,8 +1512,9 @@ int tcp_retransmit_skb(struct sock *sk,
+@@ -1510,8 +1512,9 @@
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) {
TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
@@ -2413,7 +2404,7 @@ index 310f2e6..ee01f69 100644
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
}
-@@ -1716,8 +1719,9 @@ void tcp_send_fin(struct sock *sk)
+@@ -1716,8 +1719,9 @@
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
TCP_SKB_CB(skb)->sacked = 0;
@@ -2425,7 +2416,7 @@ index 310f2e6..ee01f69 100644
/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
TCP_SKB_CB(skb)->seq = tp->write_seq;
-@@ -1749,8 +1753,9 @@ void tcp_send_active_reset(struct sock *
+@@ -1749,8 +1753,9 @@
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
TCP_SKB_CB(skb)->sacked = 0;
@@ -2437,7 +2428,7 @@ index 310f2e6..ee01f69 100644
/* Send it off. */
TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
-@@ -1833,8 +1838,9 @@ struct sk_buff * tcp_make_synack(struct
+@@ -1833,8 +1838,9 @@
TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
TCP_SKB_CB(skb)->sacked = 0;
@@ -2449,7 +2440,7 @@ index 310f2e6..ee01f69 100644
th->seq = htonl(TCP_SKB_CB(skb)->seq);
th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
-@@ -1937,8 +1943,9 @@ int tcp_connect(struct sock *sk)
+@@ -1937,8 +1943,9 @@
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
TCP_ECN_send_syn(sk, tp, buff);
TCP_SKB_CB(buff)->sacked = 0;
@@ -2461,7 +2452,7 @@ index 310f2e6..ee01f69 100644
buff->csum = 0;
TCP_SKB_CB(buff)->seq = tp->write_seq++;
TCP_SKB_CB(buff)->end_seq = tp->write_seq;
-@@ -2042,8 +2049,9 @@ void tcp_send_ack(struct sock *sk)
+@@ -2042,8 +2049,9 @@
buff->csum = 0;
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(buff)->sacked = 0;
@@ -2473,7 +2464,7 @@ index 310f2e6..ee01f69 100644
/* Send it off, this clears delayed acks for us. */
TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
-@@ -2078,8 +2086,9 @@ static int tcp_xmit_probe_skb(struct soc
+@@ -2078,8 +2086,9 @@
skb->csum = 0;
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(skb)->sacked = urgent;
@@ -2485,10 +2476,10 @@ index 310f2e6..ee01f69 100644
/* Use a previous sequence. This should cause the other
* end to send an ack. Don't queue or clone SKB, just
-diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
-index 32ad229..737c1db 100644
---- a/net/ipv4/xfrm4_output.c
-+++ b/net/ipv4/xfrm4_output.c
+Index: tmp-xxx/net/ipv4/xfrm4_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv4/xfrm4_output.c 2006-11-27 10:52:32.000000000 +0000
++++ tmp-xxx/net/ipv4/xfrm4_output.c 2006-11-27 10:52:42.000000000 +0000
@@ -9,6 +9,8 @@
*/
@@ -2498,7 +2489,7 @@ index 32ad229..737c1db 100644
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netfilter_ipv4.h>
-@@ -152,16 +154,10 @@ error_nolock:
+@@ -158,16 +160,10 @@
goto out_exit;
}
@@ -2516,7 +2507,7 @@ index 32ad229..737c1db 100644
while (likely((err = xfrm4_output_one(skb)) == 0)) {
nf_reset(skb);
-@@ -174,7 +170,7 @@ #endif
+@@ -180,7 +176,7 @@
return dst_output(skb);
err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
@@ -2525,7 +2516,7 @@ index 32ad229..737c1db 100644
if (unlikely(err != 1))
break;
}
-@@ -182,6 +178,48 @@ #endif
+@@ -188,6 +184,48 @@
return err;
}
@@ -2574,11 +2565,11 @@ index 32ad229..737c1db 100644
int xfrm4_output(struct sk_buff *skb)
{
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
-diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
-index 5bf70b1..cf5d17e 100644
---- a/net/ipv6/ip6_output.c
-+++ b/net/ipv6/ip6_output.c
-@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
+Index: tmp-xxx/net/ipv6/ip6_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv6/ip6_output.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv6/ip6_output.c 2006-11-27 10:52:42.000000000 +0000
+@@ -147,7 +147,7 @@
int ip6_output(struct sk_buff *skb)
{
@@ -2587,7 +2578,7 @@ index 5bf70b1..cf5d17e 100644
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
else
-@@ -829,8 +829,9 @@ static inline int ip6_ufo_append_data(st
+@@ -829,8 +829,9 @@
struct frag_hdr fhdr;
/* specify the length of each IP datagram fragment*/
@@ -2599,11 +2590,11 @@ index 5bf70b1..cf5d17e 100644
ipv6_select_ident(skb, &fhdr);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
-diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
-index d511a88..ef56d5d 100644
---- a/net/ipv6/ipcomp6.c
-+++ b/net/ipv6/ipcomp6.c
-@@ -64,7 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
+Index: tmp-xxx/net/ipv6/ipcomp6.c
+===================================================================
+--- tmp-xxx.orig/net/ipv6/ipcomp6.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv6/ipcomp6.c 2006-11-27 10:52:42.000000000 +0000
+@@ -64,7 +64,7 @@
static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
{
@@ -2612,7 +2603,7 @@ index d511a88..ef56d5d 100644
u8 nexthdr = 0;
int hdr_len = skb->h.raw - skb->nh.raw;
unsigned char *tmp_hdr = NULL;
-@@ -75,11 +75,8 @@ static int ipcomp6_input(struct xfrm_sta
+@@ -75,11 +75,8 @@
struct crypto_tfm *tfm;
int cpu;
@@ -2625,7 +2616,7 @@ index d511a88..ef56d5d 100644
skb->ip_summed = CHECKSUM_NONE;
-@@ -158,10 +155,8 @@ static int ipcomp6_output(struct xfrm_st
+@@ -158,10 +155,8 @@
goto out_ok;
}
@@ -2637,11 +2628,11 @@ index d511a88..ef56d5d 100644
/* compression */
plen = skb->len - hdr_len;
-diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
-index 8024217..39bdeec 100644
---- a/net/ipv6/xfrm6_output.c
-+++ b/net/ipv6/xfrm6_output.c
-@@ -151,7 +151,7 @@ error_nolock:
+Index: tmp-xxx/net/ipv6/xfrm6_output.c
+===================================================================
+--- tmp-xxx.orig/net/ipv6/xfrm6_output.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/ipv6/xfrm6_output.c 2006-11-27 10:52:42.000000000 +0000
+@@ -151,7 +151,7 @@
goto out_exit;
}
@@ -2650,7 +2641,7 @@ index 8024217..39bdeec 100644
{
int err;
-@@ -167,7 +167,7 @@ static int xfrm6_output_finish(struct sk
+@@ -167,7 +167,7 @@
return dst_output(skb);
err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
@@ -2659,7 +2650,7 @@ index 8024217..39bdeec 100644
if (unlikely(err != 1))
break;
}
-@@ -175,6 +175,41 @@ static int xfrm6_output_finish(struct sk
+@@ -175,6 +175,41 @@
return err;
}
@@ -2701,11 +2692,11 @@ index 8024217..39bdeec 100644
int xfrm6_output(struct sk_buff *skb)
{
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
-diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
-index 99ceb91..28c9efd 100644
---- a/net/sched/sch_generic.c
-+++ b/net/sched/sch_generic.c
-@@ -72,9 +72,9 @@ void qdisc_unlock_tree(struct net_device
+Index: tmp-xxx/net/sched/sch_generic.c
+===================================================================
+--- tmp-xxx.orig/net/sched/sch_generic.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/sched/sch_generic.c 2006-11-27 10:52:42.000000000 +0000
+@@ -72,9 +72,9 @@
dev->queue_lock serializes queue accesses for this device
AND dev->qdisc pointer itself.
@@ -2717,7 +2708,7 @@ index 99ceb91..28c9efd 100644
if one is grabbed, another must be free.
*/
-@@ -90,14 +90,17 @@ void qdisc_unlock_tree(struct net_device
+@@ -90,14 +90,17 @@
NOTE: Called under dev->queue_lock with locally disabled BH.
*/
@@ -2737,7 +2728,7 @@ index 99ceb91..28c9efd 100644
/*
* When the driver has LLTX set it does its own locking
* in start_xmit. No need to add additional overhead by
-@@ -108,7 +111,7 @@ int qdisc_restart(struct net_device *dev
+@@ -108,7 +111,7 @@
* will be requeued.
*/
if (!nolock) {
@@ -2746,7 +2737,7 @@ index 99ceb91..28c9efd 100644
collision:
/* So, someone grabbed the driver. */
-@@ -126,8 +129,6 @@ int qdisc_restart(struct net_device *dev
+@@ -126,8 +129,6 @@
__get_cpu_var(netdev_rx_stat).cpu_collision++;
goto requeue;
}
@@ -2755,7 +2746,7 @@ index 99ceb91..28c9efd 100644
}
{
-@@ -136,14 +137,11 @@ int qdisc_restart(struct net_device *dev
+@@ -136,14 +137,11 @@
if (!netif_queue_stopped(dev)) {
int ret;
@@ -2772,7 +2763,7 @@ index 99ceb91..28c9efd 100644
}
spin_lock(&dev->queue_lock);
return -1;
-@@ -157,8 +155,7 @@ int qdisc_restart(struct net_device *dev
+@@ -157,8 +155,7 @@
/* NETDEV_TX_BUSY - we need to requeue */
/* Release the driver */
if (!nolock) {
@@ -2782,7 +2773,7 @@ index 99ceb91..28c9efd 100644
}
spin_lock(&dev->queue_lock);
q = dev->qdisc;
-@@ -175,7 +172,10 @@ int qdisc_restart(struct net_device *dev
+@@ -175,7 +172,10 @@
*/
requeue:
@@ -2794,7 +2785,7 @@ index 99ceb91..28c9efd 100644
netif_schedule(dev);
return 1;
}
-@@ -183,11 +183,23 @@ requeue:
+@@ -183,11 +183,23 @@
return q->q.qlen;
}
@@ -2819,7 +2810,7 @@ index 99ceb91..28c9efd 100644
if (dev->qdisc != &noop_qdisc) {
if (netif_device_present(dev) &&
netif_running(dev) &&
-@@ -201,7 +213,7 @@ static void dev_watchdog(unsigned long a
+@@ -201,7 +213,7 @@
dev_hold(dev);
}
}
@@ -2828,7 +2819,7 @@ index 99ceb91..28c9efd 100644
dev_put(dev);
}
-@@ -225,17 +237,17 @@ void __netdev_watchdog_up(struct net_dev
+@@ -225,17 +237,17 @@
static void dev_watchdog_up(struct net_device *dev)
{
@@ -2850,7 +2841,7 @@ index 99ceb91..28c9efd 100644
}
void netif_carrier_on(struct net_device *dev)
-@@ -577,10 +589,17 @@ void dev_deactivate(struct net_device *d
+@@ -577,10 +589,17 @@
dev_watchdog_down(dev);
@@ -2870,18 +2861,18 @@ index 99ceb91..28c9efd 100644
}
void dev_init_scheduler(struct net_device *dev)
-@@ -622,6 +641,5 @@ EXPORT_SYMBOL(qdisc_create_dflt);
+@@ -622,6 +641,5 @@
EXPORT_SYMBOL(qdisc_alloc);
EXPORT_SYMBOL(qdisc_destroy);
EXPORT_SYMBOL(qdisc_reset);
-EXPORT_SYMBOL(qdisc_restart);
EXPORT_SYMBOL(qdisc_lock_tree);
EXPORT_SYMBOL(qdisc_unlock_tree);
-diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
-index 79b8ef3..4c16ad5 100644
---- a/net/sched/sch_teql.c
-+++ b/net/sched/sch_teql.c
-@@ -302,20 +302,17 @@ restart:
+Index: tmp-xxx/net/sched/sch_teql.c
+===================================================================
+--- tmp-xxx.orig/net/sched/sch_teql.c 2006-11-15 10:38:39.000000000 +0000
++++ tmp-xxx/net/sched/sch_teql.c 2006-11-27 10:52:42.000000000 +0000
+@@ -302,20 +302,17 @@
switch (teql_resolve(skb, skb_res, slave)) {
case 0:
diff --git a/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch b/patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch
index ab8812af61..db2ea2321b 100644
--- a/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch
+++ b/patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch
@@ -1,6 +1,6 @@
-diff -urp a/net/ipv4/tcp.c b/net/ipv4/tcp.c
---- a/net/ipv4/tcp.c 2006-07-25 14:42:53.194910626 +0100
-+++ b/net/ipv4/tcp.c 2006-07-25 14:41:00.955501910 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp.c ./net/ipv4/tcp.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv4/tcp.c 2006-09-19 13:59:42.000000000 +0100
@@ -2042,13 +2042,19 @@ struct sk_buff *tcp_tso_segment(struct s
if (!pskb_may_pull(skb, thlen))
goto out;
diff --git a/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch b/patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch
index d8b7ba7a75..430be5fbbf 100644
--- a/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch
+++ b/patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch
@@ -1,6 +1,6 @@
-diff -urp a/drivers/net/bnx2.c b/drivers/net/bnx2.c
---- a/drivers/net/bnx2.c 2006-07-25 14:41:00.905507519 +0100
-+++ b/drivers/net/bnx2.c 2006-07-25 14:36:00.288561400 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/bnx2.c ./drivers/net/bnx2.c
+--- ../orig-linux-2.6.16.29/drivers/net/bnx2.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/bnx2.c 2006-09-19 13:59:46.000000000 +0100
@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
skb = tx_buf->skb;
#ifdef BCM_TSO
@@ -10,9 +10,9 @@ diff -urp a/drivers/net/bnx2.c b/drivers/net/bnx2.c
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
-diff -urp a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
---- a/drivers/net/chelsio/sge.c 2006-07-25 14:41:00.908507183 +0100
-+++ b/drivers/net/chelsio/sge.c 2006-07-25 14:36:00.291561087 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c ./drivers/net/chelsio/sge.c
+--- ../orig-linux-2.6.16.29/drivers/net/chelsio/sge.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/chelsio/sge.c 2006-09-19 13:59:46.000000000 +0100
@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
struct cpl_tx_pkt *cpl;
@@ -22,9 +22,9 @@ diff -urp a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
int eth_type;
struct cpl_tx_pkt_lso *hdr;
-diff -urp a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
---- a/drivers/net/e1000/e1000_main.c 2006-07-25 14:41:00.910506958 +0100
-+++ b/drivers/net/e1000/e1000_main.c 2006-07-25 14:36:00.293560878 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c ./drivers/net/e1000/e1000_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/e1000/e1000_main.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/e1000/e1000_main.c 2006-09-19 13:59:46.000000000 +0100
@@ -2526,7 +2526,7 @@ e1000_tso(struct e1000_adapter *adapter,
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
@@ -53,9 +53,9 @@ diff -urp a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
count++;
#endif
-diff -urp a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
---- a/drivers/net/forcedeth.c 2006-07-25 14:41:00.912506734 +0100
-+++ b/drivers/net/forcedeth.c 2006-07-25 14:36:00.295560669 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/forcedeth.c ./drivers/net/forcedeth.c
+--- ../orig-linux-2.6.16.29/drivers/net/forcedeth.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/forcedeth.c 2006-09-19 13:59:46.000000000 +0100
@@ -1105,7 +1105,7 @@ static int nv_start_xmit(struct sk_buff
np->tx_skbuff[nr] = skb;
@@ -65,9 +65,9 @@ diff -urp a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
#endif
-diff -urp a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
---- a/drivers/net/ixgb/ixgb_main.c 2006-07-25 14:41:00.915506397 +0100
-+++ b/drivers/net/ixgb/ixgb_main.c 2006-07-25 14:36:00.298560355 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c ./drivers/net/ixgb/ixgb_main.c
+--- ../orig-linux-2.6.16.29/drivers/net/ixgb/ixgb_main.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/ixgb/ixgb_main.c 2006-09-19 13:59:46.000000000 +0100
@@ -1163,7 +1163,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
uint16_t ipcse, tucse, mss;
int err;
@@ -77,9 +77,9 @@ diff -urp a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
-diff -urp a/drivers/net/loopback.c b/drivers/net/loopback.c
---- a/drivers/net/loopback.c 2006-07-25 14:41:00.915506397 +0100
-+++ b/drivers/net/loopback.c 2006-07-25 14:36:00.298560355 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/loopback.c ./drivers/net/loopback.c
+--- ../orig-linux-2.6.16.29/drivers/net/loopback.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/loopback.c 2006-09-19 13:59:46.000000000 +0100
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff
#endif
@@ -89,9 +89,9 @@ diff -urp a/drivers/net/loopback.c b/drivers/net/loopback.c
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
-diff -urp a/drivers/net/sky2.c b/drivers/net/sky2.c
---- a/drivers/net/sky2.c 2006-07-25 14:41:00.924505388 +0100
-+++ b/drivers/net/sky2.c 2006-07-25 14:36:00.306559519 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/sky2.c ./drivers/net/sky2.c
+--- ../orig-linux-2.6.16.29/drivers/net/sky2.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/sky2.c 2006-09-19 13:59:46.000000000 +0100
@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
@@ -101,9 +101,9 @@ diff -urp a/drivers/net/sky2.c b/drivers/net/sky2.c
++count;
if (skb->ip_summed == CHECKSUM_HW)
-diff -urp a/drivers/net/typhoon.c b/drivers/net/typhoon.c
---- a/drivers/net/typhoon.c 2006-07-25 14:41:00.931504603 +0100
-+++ b/drivers/net/typhoon.c 2006-07-25 14:36:00.314558683 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/net/typhoon.c ./drivers/net/typhoon.c
+--- ../orig-linux-2.6.16.29/drivers/net/typhoon.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/net/typhoon.c 2006-09-19 13:59:46.000000000 +0100
@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
* If problems develop with TSO, check this first.
*/
@@ -122,9 +122,9 @@ diff -urp a/drivers/net/typhoon.c b/drivers/net/typhoon.c
first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
first_txd->numDesc++;
-diff -urp a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
---- a/drivers/s390/net/qeth_main.c 2006-07-25 14:41:00.939503705 +0100
-+++ b/drivers/s390/net/qeth_main.c 2006-07-25 14:36:00.321557952 +0100
+diff -pruN ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c ./drivers/s390/net/qeth_main.c
+--- ../orig-linux-2.6.16.29/drivers/s390/net/qeth_main.c 2006-09-19 13:59:20.000000000 +0100
++++ ./drivers/s390/net/qeth_main.c 2006-09-19 13:59:46.000000000 +0100
@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
@@ -144,9 +144,9 @@ diff -urp a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
card->perf_stats.large_send_bytes += skb->len;
card->perf_stats.large_send_cnt++;
}
-diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h
---- a/include/linux/netdevice.h 2006-07-25 14:41:00.940503593 +0100
-+++ b/include/linux/netdevice.h 2006-07-25 14:36:00.323557743 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/linux/netdevice.h ./include/linux/netdevice.h
+--- ../orig-linux-2.6.16.29/include/linux/netdevice.h 2006-09-19 13:59:20.000000000 +0100
++++ ./include/linux/netdevice.h 2006-09-19 13:59:46.000000000 +0100
@@ -541,6 +541,7 @@ struct packet_type {
struct net_device *);
struct sk_buff *(*gso_segment)(struct sk_buff *skb,
@@ -174,9 +174,9 @@ diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h
}
#endif /* __KERNEL__ */
-diff -urp a/include/linux/skbuff.h b/include/linux/skbuff.h
---- a/include/linux/skbuff.h 2006-07-25 14:41:00.941503481 +0100
-+++ b/include/linux/skbuff.h 2006-07-25 14:36:00.323557743 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/linux/skbuff.h ./include/linux/skbuff.h
+--- ../orig-linux-2.6.16.29/include/linux/skbuff.h 2006-09-19 13:59:20.000000000 +0100
++++ ./include/linux/skbuff.h 2006-09-19 13:59:46.000000000 +0100
@@ -1403,5 +1403,10 @@ static inline void nf_bridge_get(struct
static inline void nf_reset(struct sk_buff *skb) {}
#endif /* CONFIG_NETFILTER */
@@ -188,9 +188,9 @@ diff -urp a/include/linux/skbuff.h b/include/linux/skbuff.h
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SKBUFF_H */
-diff -urp a/include/net/protocol.h b/include/net/protocol.h
---- a/include/net/protocol.h 2006-07-25 14:41:00.942503369 +0100
-+++ b/include/net/protocol.h 2006-07-25 14:36:00.324557639 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/net/protocol.h ./include/net/protocol.h
+--- ../orig-linux-2.6.16.29/include/net/protocol.h 2006-09-19 13:59:20.000000000 +0100
++++ ./include/net/protocol.h 2006-09-19 13:59:46.000000000 +0100
@@ -37,6 +37,7 @@
struct net_protocol {
int (*handler)(struct sk_buff *skb);
@@ -199,9 +199,9 @@ diff -urp a/include/net/protocol.h b/include/net/protocol.h
struct sk_buff *(*gso_segment)(struct sk_buff *skb,
int features);
int no_policy;
-diff -urp a/include/net/tcp.h b/include/net/tcp.h
---- a/include/net/tcp.h 2006-07-25 14:41:00.943503256 +0100
-+++ b/include/net/tcp.h 2006-07-25 14:36:00.325557534 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/net/tcp.h ./include/net/tcp.h
+--- ../orig-linux-2.6.16.29/include/net/tcp.h 2006-09-19 13:59:20.000000000 +0100
++++ ./include/net/tcp.h 2006-09-19 13:59:46.000000000 +0100
@@ -1063,6 +1063,7 @@ extern struct request_sock_ops tcp_reque
extern int tcp_v4_destroy_sock(struct sock *sk);
@@ -210,9 +210,9 @@ diff -urp a/include/net/tcp.h b/include/net/tcp.h
extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
#ifdef CONFIG_PROC_FS
-diff -urp a/net/bridge/br_forward.c b/net/bridge/br_forward.c
---- a/net/bridge/br_forward.c 2006-07-25 14:41:00.944503144 +0100
-+++ b/net/bridge/br_forward.c 2006-07-25 14:36:00.326557430 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_forward.c ./net/bridge/br_forward.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_forward.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/bridge/br_forward.c 2006-09-19 13:59:46.000000000 +0100
@@ -32,7 +32,7 @@ static inline int should_deliver(const s
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
@@ -222,9 +222,9 @@ diff -urp a/net/bridge/br_forward.c b/net/bridge/br_forward.c
kfree_skb(skb);
else {
#ifdef CONFIG_BRIDGE_NETFILTER
-diff -urp a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
---- a/net/bridge/br_netfilter.c 2006-07-25 14:41:00.945503032 +0100
-+++ b/net/bridge/br_netfilter.c 2006-07-25 14:36:00.327557325 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c ./net/bridge/br_netfilter.c
+--- ../orig-linux-2.6.16.29/net/bridge/br_netfilter.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/bridge/br_netfilter.c 2006-09-19 13:59:46.000000000 +0100
@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
{
if (skb->protocol == htons(ETH_P_IP) &&
@@ -234,9 +234,9 @@ diff -urp a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
return ip_fragment(skb, br_dev_queue_push_xmit);
else
return br_dev_queue_push_xmit(skb);
-diff -urp a/net/core/dev.c b/net/core/dev.c
---- a/net/core/dev.c 2006-07-25 14:41:00.947502808 +0100
-+++ b/net/core/dev.c 2006-07-25 14:36:00.329557116 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.16.29/net/core/dev.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/core/dev.c 2006-09-19 13:59:46.000000000 +0100
@@ -1083,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk
unsigned int csum;
int ret = 0, offset = skb->h.raw - skb->data;
@@ -304,9 +304,9 @@ diff -urp a/net/core/dev.c b/net/core/dev.c
segs = ptype->gso_segment(skb, features);
break;
}
-diff -urp a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
---- a/net/ipv4/af_inet.c 2006-07-25 14:41:00.952502247 +0100
-+++ b/net/ipv4/af_inet.c 2006-07-25 14:36:00.334556594 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/af_inet.c ./net/ipv4/af_inet.c
+--- ../orig-linux-2.6.16.29/net/ipv4/af_inet.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv4/af_inet.c 2006-09-19 13:59:46.000000000 +0100
@@ -1085,6 +1085,40 @@ int inet_sk_rebuild_header(struct sock *
EXPORT_SYMBOL(inet_sk_rebuild_header);
@@ -364,9 +364,9 @@ diff -urp a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
.gso_segment = inet_gso_segment,
};
-diff -urp a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
---- a/net/ipv4/ip_output.c 2006-07-25 14:41:00.953502135 +0100
-+++ b/net/ipv4/ip_output.c 2006-07-25 14:36:00.335556489 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/ip_output.c ./net/ipv4/ip_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/ip_output.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv4/ip_output.c 2006-09-19 13:59:46.000000000 +0100
@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc
return dst_output(skb);
}
@@ -385,9 +385,9 @@ diff -urp a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
len = size;
else {
-diff -urp a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
---- a/net/ipv4/tcp_ipv4.c 2006-07-25 14:39:15.985080788 +0100
-+++ b/net/ipv4/tcp_ipv4.c 2006-07-25 14:36:00.339556071 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/tcp_ipv4.c ./net/ipv4/tcp_ipv4.c
+--- ../orig-linux-2.6.16.29/net/ipv4/tcp_ipv4.c 2006-09-12 19:02:10.000000000 +0100
++++ ./net/ipv4/tcp_ipv4.c 2006-09-19 13:59:46.000000000 +0100
@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk,
}
}
@@ -413,10 +413,10 @@ diff -urp a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
/*
* This routine will send an RST to the other tcp.
*
-diff -urp a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
---- a/net/ipv4/xfrm4_output.c 2006-07-25 14:41:00.958501574 +0100
-+++ b/net/ipv4/xfrm4_output.c 2006-07-25 14:36:00.341555862 +0100
-@@ -189,7 +189,7 @@ static int xfrm4_output_finish(struct sk
+diff -pruN ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c ./net/ipv4/xfrm4_output.c
+--- ../orig-linux-2.6.16.29/net/ipv4/xfrm4_output.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv4/xfrm4_output.c 2006-09-19 13:59:46.000000000 +0100
+@@ -195,7 +195,7 @@ static int xfrm4_output_finish(struct sk
}
#endif
@@ -425,9 +425,9 @@ diff -urp a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
return xfrm4_output_finish2(skb);
skb->protocol = htons(ETH_P_IP);
-diff -urp a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
---- a/net/ipv6/ip6_output.c 2006-07-25 14:41:00.959501461 +0100
-+++ b/net/ipv6/ip6_output.c 2006-07-25 14:36:00.341555862 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c ./net/ipv6/ip6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/ip6_output.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv6/ip6_output.c 2006-09-19 13:59:46.000000000 +0100
@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
int ip6_output(struct sk_buff *skb)
@@ -437,9 +437,9 @@ diff -urp a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
else
-diff -urp a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
---- a/net/ipv6/xfrm6_output.c 2006-07-25 14:41:00.960501349 +0100
-+++ b/net/ipv6/xfrm6_output.c 2006-07-25 14:36:00.342555758 +0100
+diff -pruN ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c ./net/ipv6/xfrm6_output.c
+--- ../orig-linux-2.6.16.29/net/ipv6/xfrm6_output.c 2006-09-19 13:59:20.000000000 +0100
++++ ./net/ipv6/xfrm6_output.c 2006-09-19 13:59:46.000000000 +0100
@@ -179,7 +179,7 @@ static int xfrm6_output_finish(struct sk
{
struct sk_buff *segs;
diff --git a/patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch b/patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch
index 0b3dfd2870..0c373223d8 100644
--- a/patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch
+++ b/patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch
@@ -1,6 +1,6 @@
-diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h
---- a/include/linux/netdevice.h 2006-07-25 15:16:39.314333975 +0100
-+++ b/include/linux/netdevice.h 2006-07-25 15:19:37.298320799 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/linux/netdevice.h ./include/linux/netdevice.h
+--- ../orig-linux-2.6.16.29/include/linux/netdevice.h 2006-09-19 13:59:46.000000000 +0100
++++ ./include/linux/netdevice.h 2006-09-19 14:05:28.000000000 +0100
@@ -930,10 +930,10 @@ static inline void netif_tx_lock_bh(stru
static inline int netif_tx_trylock(struct net_device *dev)
diff --git a/patches/linux-2.6.16.13/net-gso-4-kill-warnon.patch b/patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch
index caefc4a1f5..86cd7a2b47 100644
--- a/patches/linux-2.6.16.13/net-gso-4-kill-warnon.patch
+++ b/patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch
@@ -1,8 +1,6 @@
-508c578140642a641bb9b888369719c510ae2a00
-diff --git a/net/core/dev.c b/net/core/dev.c
-index e814a89..240773b 100644
---- a/net/core/dev.c
-+++ b/net/core/dev.c
+diff -pruN ../orig-linux-2.6.16.29/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.16.29/net/core/dev.c 2006-09-19 13:59:46.000000000 +0100
++++ ./net/core/dev.c 2006-09-19 14:05:32.000000000 +0100
@@ -1087,11 +1087,6 @@ int skb_checksum_help(struct sk_buff *sk
goto out_set_summed;
diff --git a/patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch b/patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch
new file mode 100644
index 0000000000..a711d0ee5f
--- /dev/null
+++ b/patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch
@@ -0,0 +1,13 @@
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 104af5d..1fa1536 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -127,7 +127,7 @@ static void tcp_measure_rcv_mss(struct s
+ /* skb->len may jitter because of SACKs, even if peer
+ * sends good full-sized frames.
+ */
+- len = skb->len;
++ len = skb_shinfo(skb)->gso_size ?: skb->len;
+ if (len >= icsk->icsk_ack.rcv_mss) {
+ icsk->icsk_ack.rcv_mss = len;
+ } else {
diff --git a/patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch b/patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch
new file mode 100644
index 0000000000..e4b709362f
--- /dev/null
+++ b/patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch
@@ -0,0 +1,292 @@
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/pci/mmconfig.c ./arch/i386/pci/mmconfig.c
+--- ../orig-linux-2.6.16.29/arch/i386/pci/mmconfig.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/pci/mmconfig.c 2006-09-21 09:35:27.000000000 +0100
+@@ -12,14 +12,22 @@
+ #include <linux/pci.h>
+ #include <linux/init.h>
+ #include <linux/acpi.h>
++#include <asm/e820.h>
+ #include "pci.h"
+
++/* aperture is up to 256MB but BIOS may reserve less */
++#define MMCONFIG_APER_MIN (2 * 1024*1024)
++#define MMCONFIG_APER_MAX (256 * 1024*1024)
++
++/* Assume systems with more busses have correct MCFG */
++#define MAX_CHECK_BUS 16
++
+ #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
+
+ /* The base address of the last MMCONFIG device accessed */
+ static u32 mmcfg_last_accessed_device;
+
+-static DECLARE_BITMAP(fallback_slots, 32);
++static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
+
+ /*
+ * Functions for accessing PCI configuration space with MMCONFIG accesses
+@@ -29,8 +37,8 @@ static u32 get_base_addr(unsigned int se
+ int cfg_num = -1;
+ struct acpi_table_mcfg_config *cfg;
+
+- if (seg == 0 && bus == 0 &&
+- test_bit(PCI_SLOT(devfn), fallback_slots))
++ if (seg == 0 && bus < MAX_CHECK_BUS &&
++ test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
+ return 0;
+
+ while (1) {
+@@ -74,8 +82,10 @@ static int pci_mmcfg_read(unsigned int s
+ unsigned long flags;
+ u32 base;
+
+- if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
++ if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
++ *value = -1;
+ return -EINVAL;
++ }
+
+ base = get_base_addr(seg, bus, devfn);
+ if (!base)
+@@ -146,30 +156,66 @@ static struct pci_raw_ops pci_mmcfg = {
+ Normally this can be expressed in the MCFG by not listing them
+ and assigning suitable _SEGs, but this isn't implemented in some BIOS.
+ Instead try to discover all devices on bus 0 that are unreachable using MM
+- and fallback for them.
+- We only do this for bus 0/seg 0 */
++ and fallback for them. */
+ static __init void unreachable_devices(void)
+ {
+- int i;
++ int i, k;
+ unsigned long flags;
+
+- for (i = 0; i < 32; i++) {
+- u32 val1;
+- u32 addr;
++ for (k = 0; k < MAX_CHECK_BUS; k++) {
++ for (i = 0; i < 32; i++) {
++ u32 val1;
++ u32 addr;
++
++ pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1);
++ if (val1 == 0xffffffff)
++ continue;
++
++ /* Locking probably not needed, but safer */
++ spin_lock_irqsave(&pci_config_lock, flags);
++ addr = get_base_addr(0, k, PCI_DEVFN(i, 0));
++ if (addr != 0)
++ pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
++ if (addr == 0 ||
++ readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
++ set_bit(i, fallback_slots);
++ printk(KERN_NOTICE
++ "PCI: No mmconfig possible on %x:%x\n", k, i);
++ }
++ spin_unlock_irqrestore(&pci_config_lock, flags);
++ }
++ }
++}
+
+- pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
+- if (val1 == 0xffffffff)
++/* NB. Ripped from arch/i386/kernel/setup.c for this Xen bugfix patch. */
++#ifdef CONFIG_XEN
++extern struct e820map machine_e820;
++#define e820 machine_e820
++#endif
++static int __init
++e820_all_mapped(unsigned long s, unsigned long e, unsigned type)
++{
++ u64 start = s;
++ u64 end = e;
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ if (type && ei->type != type)
+ continue;
+-
+- /* Locking probably not needed, but safer */
+- spin_lock_irqsave(&pci_config_lock, flags);
+- addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
+- if (addr != 0)
+- pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
+- if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1)
+- set_bit(i, fallback_slots);
+- spin_unlock_irqrestore(&pci_config_lock, flags);
++ /* is the region (part) in overlap with the current region ?*/
++ if (ei->addr >= end || ei->addr + ei->size <= start)
++ continue;
++ /* if the region is at the beginning of <start,end> we move
++ * start to the end of the region since it's ok until there
++ */
++ if (ei->addr <= start)
++ start = ei->addr + ei->size;
++ /* if start is now at or beyond end, we're done, full
++ * coverage */
++ if (start >= end)
++ return 1; /* we're done */
+ }
++ return 0;
+ }
+
+ static int __init pci_mmcfg_init(void)
+@@ -183,6 +229,15 @@ static int __init pci_mmcfg_init(void)
+ (pci_mmcfg_config[0].base_address == 0))
+ goto out;
+
++ if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
++ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
++ E820_RESERVED)) {
++ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
++ pci_mmcfg_config[0].base_address);
++ printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
++ goto out;
++ }
++
+ printk(KERN_INFO "PCI: Using MMCONFIG\n");
+ raw_pci_ops = &pci_mmcfg;
+ pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/pci/mmconfig.c ./arch/x86_64/pci/mmconfig.c
+--- ../orig-linux-2.6.16.29/arch/x86_64/pci/mmconfig.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/x86_64/pci/mmconfig.c 2006-09-21 09:35:40.000000000 +0100
+@@ -9,11 +9,19 @@
+ #include <linux/init.h>
+ #include <linux/acpi.h>
+ #include <linux/bitmap.h>
++#include <asm/e820.h>
++
+ #include "pci.h"
+
+-#define MMCONFIG_APER_SIZE (256*1024*1024)
++/* aperture is up to 256MB but BIOS may reserve less */
++#define MMCONFIG_APER_MIN (2 * 1024*1024)
++#define MMCONFIG_APER_MAX (256 * 1024*1024)
++
++/* Verify the first 16 busses. We assume that systems with more busses
++ get MCFG right. */
++#define MAX_CHECK_BUS 16
+
+-static DECLARE_BITMAP(fallback_slots, 32);
++static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS);
+
+ /* Static virtual mapping of the MMCONFIG aperture */
+ struct mmcfg_virt {
+@@ -55,7 +63,8 @@ static char __iomem *get_virt(unsigned i
+ static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+ {
+ char __iomem *addr;
+- if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
++ if (seg == 0 && bus < MAX_CHECK_BUS &&
++ test_bit(32*bus + PCI_SLOT(devfn), fallback_slots))
+ return NULL;
+ addr = get_virt(seg, bus);
+ if (!addr)
+@@ -69,8 +78,10 @@ static int pci_mmcfg_read(unsigned int s
+ char __iomem *addr;
+
+ /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
+- if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
++ if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
++ *value = -1;
+ return -EINVAL;
++ }
+
+ addr = pci_dev_base(seg, bus, devfn);
+ if (!addr)
+@@ -129,23 +140,56 @@ static struct pci_raw_ops pci_mmcfg = {
+ Normally this can be expressed in the MCFG by not listing them
+ and assigning suitable _SEGs, but this isn't implemented in some BIOS.
+ Instead try to discover all devices on bus 0 that are unreachable using MM
+- and fallback for them.
+- We only do this for bus 0/seg 0 */
++ and fallback for them. */
+ static __init void unreachable_devices(void)
+ {
+- int i;
+- for (i = 0; i < 32; i++) {
+- u32 val1;
+- char __iomem *addr;
++ int i, k;
++ /* Use the max bus number from ACPI here? */
++ for (k = 0; k < MAX_CHECK_BUS; k++) {
++ for (i = 0; i < 32; i++) {
++ u32 val1;
++ char __iomem *addr;
++
++ pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1);
++ if (val1 == 0xffffffff)
++ continue;
++ addr = pci_dev_base(0, k, PCI_DEVFN(i, 0));
++ if (addr == NULL|| readl(addr) != val1) {
++ set_bit(i + 32*k, fallback_slots);
++ printk(KERN_NOTICE
++ "PCI: No mmconfig possible on device %x:%x\n",
++ k, i);
++ }
++ }
++ }
++}
+
+- pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
+- if (val1 == 0xffffffff)
++/* NB. Ripped from arch/x86_64/kernel/e820.c for this Xen bugfix patch. */
++#ifdef CONFIG_XEN
++extern struct e820map machine_e820;
++#define e820 machine_e820
++#endif
++static int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type)
++{
++ int i;
++ for (i = 0; i < e820.nr_map; i++) {
++ struct e820entry *ei = &e820.map[i];
++ if (type && ei->type != type)
+ continue;
+- addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
+- if (addr == NULL|| readl(addr) != val1) {
+- set_bit(i, &fallback_slots);
+- }
++ /* is the region (part) in overlap with the current region ?*/
++ if (ei->addr >= end || ei->addr + ei->size <= start)
++ continue;
++
++ /* if the region is at the beginning of <start,end> we move
++ * start to the end of the region since it's ok until there
++ */
++ if (ei->addr <= start)
++ start = ei->addr + ei->size;
++ /* if start is now at or beyond end, we're done, full coverage */
++ if (start >= end)
++ return 1; /* we're done */
+ }
++ return 0;
+ }
+
+ static int __init pci_mmcfg_init(void)
+@@ -161,6 +205,15 @@ static int __init pci_mmcfg_init(void)
+ (pci_mmcfg_config[0].base_address == 0))
+ return 0;
+
++ if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
++ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
++ E820_RESERVED)) {
++ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
++ pci_mmcfg_config[0].base_address);
++ printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
++ return 0;
++ }
++
+ /* RED-PEN i386 doesn't do _nocache right now */
+ pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
+ if (pci_mmcfg_virt == NULL) {
+@@ -169,7 +222,8 @@ static int __init pci_mmcfg_init(void)
+ }
+ for (i = 0; i < pci_mmcfg_config_num; ++i) {
+ pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
+- pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
++ pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
++ MMCONFIG_APER_MAX);
+ if (!pci_mmcfg_virt[i].virt) {
+ printk("PCI: Cannot map mmconfig aperture for segment %d\n",
+ pci_mmcfg_config[i].pci_segment_group_number);
diff --git a/patches/linux-2.6.16.13/pmd-shared.patch b/patches/linux-2.6.16.32/pmd-shared.patch
index 2af0a737f4..f8123a96ba 100644
--- a/patches/linux-2.6.16.13/pmd-shared.patch
+++ b/patches/linux-2.6.16.32/pmd-shared.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/mm/pageattr.c ./arch/i386/mm/pageattr.c
---- ../pristine-linux-2.6.16.13/arch/i386/mm/pageattr.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/mm/pageattr.c 2006-05-04 17:41:40.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/mm/pageattr.c ./arch/i386/mm/pageattr.c
+--- ../orig-linux-2.6.16.29/arch/i386/mm/pageattr.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/mm/pageattr.c 2006-09-19 14:05:35.000000000 +0100
@@ -78,7 +78,7 @@ static void set_pmd_pte(pte_t *kpte, uns
unsigned long flags;
@@ -10,9 +10,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/mm/pageattr.c ./arch/i386/mm/pa
return;
spin_lock_irqsave(&pgd_lock, flags);
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/mm/pgtable.c ./arch/i386/mm/pgtable.c
---- ../pristine-linux-2.6.16.13/arch/i386/mm/pgtable.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/mm/pgtable.c 2006-05-04 17:41:40.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/mm/pgtable.c ./arch/i386/mm/pgtable.c
+--- ../orig-linux-2.6.16.29/arch/i386/mm/pgtable.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/mm/pgtable.c 2006-09-19 14:05:35.000000000 +0100
@@ -215,9 +215,10 @@ void pgd_ctor(void *pgd, kmem_cache_t *c
spin_lock_irqsave(&pgd_lock, flags);
}
@@ -85,9 +85,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/mm/pgtable.c ./arch/i386/mm/pgt
/* in the non-PAE case, free_pgtables() clears user pgd entries */
kmem_cache_free(pgd_cache, pgd);
}
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/pgtable-2level-defs.h ./include/asm-i386/pgtable-2level-defs.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/pgtable-2level-defs.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/pgtable-2level-defs.h 2006-05-04 17:41:40.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/pgtable-2level-defs.h ./include/asm-i386/pgtable-2level-defs.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/pgtable-2level-defs.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/pgtable-2level-defs.h 2006-09-19 14:05:35.000000000 +0100
@@ -1,6 +1,8 @@
#ifndef _I386_PGTABLE_2LEVEL_DEFS_H
#define _I386_PGTABLE_2LEVEL_DEFS_H
@@ -97,9 +97,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/pgtable-2level-defs.h ./
/*
* traditional i386 two-level paging structure:
*/
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/pgtable-3level-defs.h ./include/asm-i386/pgtable-3level-defs.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/pgtable-3level-defs.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/pgtable-3level-defs.h 2006-05-04 17:41:40.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/pgtable-3level-defs.h ./include/asm-i386/pgtable-3level-defs.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/pgtable-3level-defs.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/pgtable-3level-defs.h 2006-09-19 14:05:35.000000000 +0100
@@ -1,6 +1,8 @@
#ifndef _I386_PGTABLE_3LEVEL_DEFS_H
#define _I386_PGTABLE_3LEVEL_DEFS_H
diff --git a/patches/linux-2.6.16.13/rcu_needs_cpu.patch b/patches/linux-2.6.16.32/rcu_needs_cpu.patch
index f2d60f7b02..c8f3b79229 100644
--- a/patches/linux-2.6.16.13/rcu_needs_cpu.patch
+++ b/patches/linux-2.6.16.32/rcu_needs_cpu.patch
@@ -1,5 +1,17 @@
---- ../pristine-linux-2.6.16.13/kernel/rcupdate.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./kernel/rcupdate.c 2006-06-09 20:27:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/linux/rcupdate.h ./include/linux/rcupdate.h
+--- ../orig-linux-2.6.16.29/include/linux/rcupdate.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/linux/rcupdate.h 2006-09-19 14:05:39.000000000 +0100
+@@ -134,6 +134,7 @@ static inline void rcu_bh_qsctr_inc(int
+ }
+
+ extern int rcu_pending(int cpu);
++extern int rcu_needs_cpu(int cpu);
+
+ /**
+ * rcu_read_lock - mark the beginning of an RCU read-side critical section.
+diff -pruN ../orig-linux-2.6.16.29/kernel/rcupdate.c ./kernel/rcupdate.c
+--- ../orig-linux-2.6.16.29/kernel/rcupdate.c 2006-09-12 19:02:10.000000000 +0100
++++ ./kernel/rcupdate.c 2006-09-19 14:05:39.000000000 +0100
@@ -485,6 +485,20 @@ int rcu_pending(int cpu)
__rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
}
@@ -21,13 +33,3 @@
void rcu_check_callbacks(int cpu, int user)
{
if (user ||
---- ../pristine-linux-2.6.16.13/include/linux/rcupdate.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/linux/rcupdate.h 2006-06-09 20:28:57.000000000 +0100
-@@ -134,6 +134,7 @@ static inline void rcu_bh_qsctr_inc(int
- }
-
- extern int rcu_pending(int cpu);
-+extern int rcu_needs_cpu(int cpu);
-
- /**
- * rcu_read_lock - mark the beginning of an RCU read-side critical section.
diff --git a/patches/linux-2.6.16.13/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch b/patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
index 0f318dee73..31788cc3bc 100644
--- a/patches/linux-2.6.16.13/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
+++ b/patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/entry.S ./arch/i386/kernel/entry.S
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/entry.S 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/entry.S 2006-05-04 17:41:44.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S ./arch/i386/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/entry.S 2006-09-19 14:05:44.000000000 +0100
@@ -177,7 +177,7 @@ need_resched:
# sysenter call handler stub
diff --git a/patches/linux-2.6.16.13/series b/patches/linux-2.6.16.32/series
index 63774a0bd7..ef2c35842e 100644
--- a/patches/linux-2.6.16.13/series
+++ b/patches/linux-2.6.16.32/series
@@ -10,6 +10,8 @@ net-gso-1-check-dodgy.patch
net-gso-2-checksum-fix.patch
net-gso-3-fix-errorcheck.patch
net-gso-4-kill-warnon.patch
+net-gso-5-rcv-mss.patch
+pci-mmconfig-fix-from-2.6.17.patch
pmd-shared.patch
rcu_needs_cpu.patch
rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch
@@ -21,3 +23,5 @@ xenoprof-generic.patch
x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
x86-elfnote-as-preprocessor-macro.patch
+vsnprintf.patch
+kasprintf.patch
diff --git a/patches/linux-2.6.16.13/smp-alts.patch b/patches/linux-2.6.16.32/smp-alts.patch
index 0e0d597da9..fbcd4a29ac 100644
--- a/patches/linux-2.6.16.13/smp-alts.patch
+++ b/patches/linux-2.6.16.32/smp-alts.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/Kconfig ./arch/i386/Kconfig
---- ../pristine-linux-2.6.16.13/arch/i386/Kconfig 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/Kconfig 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/Kconfig ./arch/i386/Kconfig
+--- ../orig-linux-2.6.16.29/arch/i386/Kconfig 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/Kconfig 2006-09-19 14:05:48.000000000 +0100
@@ -202,6 +202,19 @@ config SMP
If you don't know what to do here, say N.
@@ -21,9 +21,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/Kconfig ./arch/i386/Kconfig
config NR_CPUS
int "Maximum number of CPUs (2-255)"
range 2 255
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/Makefile ./arch/i386/kernel/Makefile
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/Makefile 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/Makefile 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/Makefile ./arch/i386/kernel/Makefile
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/Makefile 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/Makefile 2006-09-19 14:05:48.000000000 +0100
@@ -37,6 +37,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
obj-$(CONFIG_VM86) += vm86.o
@@ -32,9 +32,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/Makefile ./arch/i386/ker
EXTRA_AFLAGS := -traditional
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/smpalts.c ./arch/i386/kernel/smpalts.c
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/smpalts.c 1970-01-01 01:00:00.000000000 +0100
-+++ ./arch/i386/kernel/smpalts.c 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/smpalts.c ./arch/i386/kernel/smpalts.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/smpalts.c 1970-01-01 01:00:00.000000000 +0100
++++ ./arch/i386/kernel/smpalts.c 2006-09-19 14:05:48.000000000 +0100
@@ -0,0 +1,85 @@
+#include <linux/kernel.h>
+#include <asm/system.h>
@@ -121,9 +121,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/smpalts.c ./arch/i386/ke
+ asm volatile ("jmp 1f\n1:");
+ mb();
+}
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/smpboot.c ./arch/i386/kernel/smpboot.c
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/smpboot.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/smpboot.c 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/smpboot.c ./arch/i386/kernel/smpboot.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/smpboot.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/smpboot.c 2006-09-19 14:05:48.000000000 +0100
@@ -1218,6 +1218,11 @@ static void __init smp_boot_cpus(unsigne
if (max_cpus <= cpucount+1)
continue;
@@ -148,9 +148,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/smpboot.c ./arch/i386/ke
local_irq_enable();
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Unleash the CPU! */
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/vmlinux.lds.S ./arch/i386/kernel/vmlinux.lds.S
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/vmlinux.lds.S 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/vmlinux.lds.S 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S ./arch/i386/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/vmlinux.lds.S 2006-09-19 14:05:48.000000000 +0100
@@ -34,6 +34,13 @@ SECTIONS
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
@@ -165,9 +165,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/vmlinux.lds.S ./arch/i38
RODATA
/* writeable */
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/atomic.h ./include/asm-i386/atomic.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/atomic.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/atomic.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/atomic.h ./include/asm-i386/atomic.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/atomic.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/atomic.h 2006-09-19 14:05:48.000000000 +0100
@@ -4,18 +4,13 @@
#include <linux/config.h>
#include <linux/compiler.h>
@@ -188,9 +188,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/atomic.h ./include/asm-i
/*
* Make sure gcc doesn't try to be clever and move things around
* on us. We need to use _exactly_ the address the user gave us,
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/bitops.h ./include/asm-i386/bitops.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/bitops.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/bitops.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/bitops.h ./include/asm-i386/bitops.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/bitops.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/bitops.h 2006-09-19 14:05:48.000000000 +0100
@@ -7,6 +7,7 @@
#include <linux/config.h>
@@ -266,9 +266,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/bitops.h ./include/asm-i
"btcl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"+m" (ADDR)
:"Ir" (nr) : "memory");
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/futex.h ./include/asm-i386/futex.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/futex.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/futex.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/futex.h ./include/asm-i386/futex.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/futex.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/futex.h 2006-09-19 14:05:48.000000000 +0100
@@ -28,7 +28,7 @@
"1: movl %2, %0\n\
movl %0, %3\n" \
@@ -287,9 +287,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/futex.h ./include/asm-i3
oldval, uaddr, oparg);
break;
case FUTEX_OP_OR:
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/rwsem.h ./include/asm-i386/rwsem.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/rwsem.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/rwsem.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/rwsem.h ./include/asm-i386/rwsem.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/rwsem.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/rwsem.h 2006-09-19 14:05:48.000000000 +0100
@@ -40,6 +40,7 @@
#include <linux/list.h>
@@ -370,9 +370,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/rwsem.h ./include/asm-i3
: "+r"(tmp), "=m"(sem->count)
: "r"(sem), "m"(sem->count)
: "memory");
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/smp_alt.h ./include/asm-i386/smp_alt.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/smp_alt.h 1970-01-01 01:00:00.000000000 +0100
-+++ ./include/asm-i386/smp_alt.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/smp_alt.h ./include/asm-i386/smp_alt.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/smp_alt.h 1970-01-01 01:00:00.000000000 +0100
++++ ./include/asm-i386/smp_alt.h 2006-09-19 14:05:48.000000000 +0100
@@ -0,0 +1,32 @@
+#ifndef __ASM_SMP_ALT_H__
+#define __ASM_SMP_ALT_H__
@@ -406,9 +406,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/smp_alt.h ./include/asm-
+#endif
+
+#endif /* __ASM_SMP_ALT_H__ */
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/spinlock.h ./include/asm-i386/spinlock.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/spinlock.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/spinlock.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/spinlock.h ./include/asm-i386/spinlock.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/spinlock.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/spinlock.h 2006-09-19 14:05:48.000000000 +0100
@@ -6,6 +6,7 @@
#include <asm/page.h>
#include <linux/config.h>
@@ -488,9 +488,9 @@ diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/spinlock.h ./include/asm
: "=m" (rw->lock) : : "memory");
}
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-i386/system.h ./include/asm-i386/system.h
---- ../pristine-linux-2.6.16.13/include/asm-i386/system.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-i386/system.h 2006-05-04 17:41:45.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-i386/system.h ./include/asm-i386/system.h
+--- ../orig-linux-2.6.16.29/include/asm-i386/system.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-i386/system.h 2006-09-19 14:05:48.000000000 +0100
@@ -5,7 +5,7 @@
#include <linux/kernel.h>
#include <asm/segment.h>
diff --git a/patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch b/patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch
index df0bc02e78..71a22017b5 100644
--- a/patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch
+++ b/patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.c ./drivers/char/tpm/tpm_atmel.c
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.c 2006-06-26 18:05:03.000000000 -0400
-+++ ./drivers/char/tpm/tpm_atmel.c 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c ./drivers/char/tpm/tpm_atmel.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_atmel.c 2006-09-19 14:05:52.000000000 +0100
@@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip
return -EIO;
@@ -151,9 +151,9 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.c ./drivers/ch
err_unreg_drv:
driver_unregister(&atml_drv);
return rc;
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.h ./drivers/char/tpm/tpm_atmel.h
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.h 2006-06-26 18:05:03.000000000 -0400
-+++ ./drivers/char/tpm/tpm_atmel.h 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h ./drivers/char/tpm/tpm_atmel.h
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_atmel.h 2006-09-19 14:05:52.000000000 +0100
@@ -28,13 +28,12 @@
#define atmel_request_region request_mem_region
#define atmel_release_region release_mem_region
@@ -214,9 +214,9 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.h ./drivers/ch
+ return ioport_map(*base, *region_size);
}
#endif
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_bios.c ./drivers/char/tpm/tpm_bios.c
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_bios.c 2006-06-26 18:05:03.000000000 -0400
-+++ ./drivers/char/tpm/tpm_bios.c 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c ./drivers/char/tpm/tpm_bios.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_bios.c 2006-09-19 14:05:52.000000000 +0100
@@ -29,6 +29,11 @@
#define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
@@ -469,9 +469,9 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_bios.c ./drivers/cha
return 0;
}
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_infineon.c ./drivers/char/tpm/tpm_infineon.c
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_infineon.c 2006-06-26 18:05:03.000000000 -0400
-+++ ./drivers/char/tpm/tpm_infineon.c 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c ./drivers/char/tpm/tpm_infineon.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_infineon.c 2006-09-19 14:05:52.000000000 +0100
@@ -15,6 +15,7 @@
* License.
*/
@@ -684,9 +684,9 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_infineon.c ./drivers
-MODULE_VERSION("1.7");
+MODULE_VERSION("1.8");
MODULE_LICENSE("GPL");
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_nsc.c ./drivers/char/tpm/tpm_nsc.c
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_nsc.c 2006-06-26 18:05:03.000000000 -0400
-+++ ./drivers/char/tpm/tpm_nsc.c 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c ./drivers/char/tpm/tpm_nsc.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c 2006-09-12 19:02:10.000000000 +0100
++++ ./drivers/char/tpm/tpm_nsc.c 2006-09-19 14:05:52.000000000 +0100
@@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip
unsigned long stop;
@@ -874,9 +874,9 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_nsc.c ./drivers/char
err_unreg_dev:
platform_device_unregister(pdev);
err_free_dev:
-diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_tis.c ./drivers/char/tpm/tpm_tis.c
---- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_tis.c 1969-12-31 19:00:00.000000000 -0500
-+++ ./drivers/char/tpm/tpm_tis.c 2006-06-26 18:16:33.000000000 -0400
+diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c ./drivers/char/tpm/tpm_tis.c
+--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c 1970-01-01 01:00:00.000000000 +0100
++++ ./drivers/char/tpm/tpm_tis.c 2006-09-19 14:05:52.000000000 +0100
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2005, 2006 IBM Corporation
@@ -1543,4 +1543,3 @@ diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_tis.c ./drivers/char
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
-
diff --git a/patches/linux-2.6.16.32/vsnprintf.patch b/patches/linux-2.6.16.32/vsnprintf.patch
new file mode 100644
index 0000000000..69a93fa5c5
--- /dev/null
+++ b/patches/linux-2.6.16.32/vsnprintf.patch
@@ -0,0 +1,211 @@
+commit f796937a062c7aeb44cd0e75e1586c8543634a7d
+Author: Jeremy Fitzhardinge <jeremy@xensource.com>
+Date: Sun Jun 25 05:49:17 2006 -0700
+
+ [PATCH] Fix bounds check in vsnprintf, to allow for a 0 size and NULL buffer
+
+ This change allows callers to use a 0-byte buffer and a NULL buffer pointer
+ with vsnprintf, so it can be used to determine how large the resulting
+ formatted string will be.
+
+ Previously the code effectively treated a size of 0 as a size of 4G (on
+ 32-bit systems), with other checks preventing it from actually trying to
+ emit the string - but the terminal \0 would still be written, which would
+ crash if the buffer is NULL.
+
+ This change changes the boundary check so that 'end' points to the putative
+ location of the terminal '\0', which is only written if size > 0.
+
+ vsnprintf still allows the buffer size to be set very large, to allow
+ unbounded buffer sizes (to implement sprintf, etc).
+
+ [akpm@osdl.org: fix long-vs-longlong confusion]
+ Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
+ Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+ Signed-off-by: Andrew Morton <akpm@osdl.org>
+ Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+
+diff --git a/lib/vsprintf.c b/lib/vsprintf.c
+index b07db5c..f595947 100644
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -187,49 +187,49 @@ static char * number(char * buf, char *
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT))) {
+ while(size-->0) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = ' ';
+ ++buf;
+ }
+ }
+ if (sign) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = sign;
+ ++buf;
+ }
+ if (type & SPECIAL) {
+ if (base==8) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = '0';
+ ++buf;
+ } else if (base==16) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = '0';
+ ++buf;
+- if (buf <= end)
++ if (buf < end)
+ *buf = digits[33];
+ ++buf;
+ }
+ }
+ if (!(type & LEFT)) {
+ while (size-- > 0) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = c;
+ ++buf;
+ }
+ }
+ while (i < precision--) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = '0';
+ ++buf;
+ }
+ while (i-- > 0) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = tmp[i];
+ ++buf;
+ }
+ while (size-- > 0) {
+- if (buf <= end)
++ if (buf < end)
+ *buf = ' ';
+ ++buf;
+ }
+@@ -272,7 +272,8 @@ int vsnprintf(char *buf, size_t size, co
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
+ /* 't' added for ptrdiff_t */
+
+- /* Reject out-of-range values early */
++ /* Reject out-of-range values early. Large positive sizes are
++ used for unknown buffer sizes. */
+ if (unlikely((int) size < 0)) {
+ /* There can be only one.. */
+ static int warn = 1;
+@@ -282,16 +283,17 @@ int vsnprintf(char *buf, size_t size, co
+ }
+
+ str = buf;
+- end = buf + size - 1;
++ end = buf + size;
+
+- if (end < buf - 1) {
+- end = ((void *) -1);
+- size = end - buf + 1;
++ /* Make sure end is always >= buf */
++ if (end < buf) {
++ end = ((void *)-1);
++ size = end - buf;
+ }
+
+ for (; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+- if (str <= end)
++ if (str < end)
+ *str = *fmt;
+ ++str;
+ continue;
+@@ -357,17 +359,17 @@ int vsnprintf(char *buf, size_t size, co
+ case 'c':
+ if (!(flags & LEFT)) {
+ while (--field_width > 0) {
+- if (str <= end)
++ if (str < end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ c = (unsigned char) va_arg(args, int);
+- if (str <= end)
++ if (str < end)
+ *str = c;
+ ++str;
+ while (--field_width > 0) {
+- if (str <= end)
++ if (str < end)
+ *str = ' ';
+ ++str;
+ }
+@@ -382,18 +384,18 @@ int vsnprintf(char *buf, size_t size, co
+
+ if (!(flags & LEFT)) {
+ while (len < field_width--) {
+- if (str <= end)
++ if (str < end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+- if (str <= end)
++ if (str < end)
+ *str = *s;
+ ++str; ++s;
+ }
+ while (len < field_width--) {
+- if (str <= end)
++ if (str < end)
+ *str = ' ';
+ ++str;
+ }
+@@ -426,7 +428,7 @@ int vsnprintf(char *buf, size_t size, co
+ continue;
+
+ case '%':
+- if (str <= end)
++ if (str < end)
+ *str = '%';
+ ++str;
+ continue;
+@@ -449,11 +451,11 @@ int vsnprintf(char *buf, size_t size, co
+ break;
+
+ default:
+- if (str <= end)
++ if (str < end)
+ *str = '%';
+ ++str;
+ if (*fmt) {
+- if (str <= end)
++ if (str < end)
+ *str = *fmt;
+ ++str;
+ } else {
+@@ -483,14 +485,13 @@ int vsnprintf(char *buf, size_t size, co
+ str = number(str, end, num, base,
+ field_width, precision, flags);
+ }
+- if (str <= end)
+- *str = '\0';
+- else if (size > 0)
+- /* don't write out a null byte if the buf size is zero */
+- *end = '\0';
+- /* the trailing null byte doesn't count towards the total
+- * ++str;
+- */
++ if (size > 0) {
++ if (str < end)
++ *str = '\0';
++ else
++ *end = '\0';
++ }
++ /* the trailing null byte doesn't count towards the total */
+ return str-buf;
+ }
+
diff --git a/patches/linux-2.6.16.13/x86-elfnote-as-preprocessor-macro.patch b/patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch
index 208573b424..3dcae42ffd 100644
--- a/patches/linux-2.6.16.13/x86-elfnote-as-preprocessor-macro.patch
+++ b/patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch
@@ -1,7 +1,6 @@
-
-diff -r 4b7cd997c08f include/linux/elfnote.h
---- a/include/linux/elfnote.h Wed Aug 23 11:48:46 2006 +0100
-+++ b/include/linux/elfnote.h Wed Aug 23 12:44:27 2006 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/linux/elfnote.h ./include/linux/elfnote.h
+--- ../orig-linux-2.6.16.29/include/linux/elfnote.h 2006-09-19 14:06:10.000000000 +0100
++++ ./include/linux/elfnote.h 2006-09-19 14:06:20.000000000 +0100
@@ -31,22 +31,24 @@
/*
* Generate a structure with the same shape as Elf{32,64}_Nhdr (which
diff --git a/patches/linux-2.6.16.13/x86-increase-interrupt-vector-range.patch b/patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch
index 1bff3be41e..0ac84e4aca 100644
--- a/patches/linux-2.6.16.13/x86-increase-interrupt-vector-range.patch
+++ b/patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch
@@ -1,6 +1,6 @@
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/entry.S ./arch/i386/kernel/entry.S
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/entry.S 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/entry.S 2006-05-04 17:41:49.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S ./arch/i386/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/entry.S 2006-09-19 14:05:44.000000000 +0100
++++ ./arch/i386/kernel/entry.S 2006-09-19 14:05:56.000000000 +0100
@@ -406,7 +406,7 @@ vector=0
ENTRY(irq_entries_start)
.rept NR_IRQS
@@ -19,9 +19,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/entry.S ./arch/i386/kern
SAVE_ALL \
movl %esp,%eax; \
call smp_/**/name; \
-diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/irq.c ./arch/i386/kernel/irq.c
---- ../pristine-linux-2.6.16.13/arch/i386/kernel/irq.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/i386/kernel/irq.c 2006-05-04 17:41:49.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/irq.c ./arch/i386/kernel/irq.c
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/irq.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/i386/kernel/irq.c 2006-09-19 14:05:56.000000000 +0100
@@ -53,8 +53,8 @@ static union irq_ctx *softirq_ctx[NR_CPU
*/
fastcall unsigned int do_IRQ(struct pt_regs *regs)
@@ -33,10 +33,10 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/i386/kernel/irq.c ./arch/i386/kernel
#ifdef CONFIG_4KSTACKS
union irq_ctx *curctx, *irqctx;
u32 *isp;
-diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/entry.S ./arch/x86_64/kernel/entry.S
---- ../pristine-linux-2.6.16.13/arch/x86_64/kernel/entry.S 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/x86_64/kernel/entry.S 2006-05-04 17:41:49.000000000 +0100
-@@ -601,7 +601,7 @@ retint_kernel:
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/entry.S ./arch/x86_64/kernel/entry.S
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/entry.S 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/entry.S 2006-09-19 14:05:56.000000000 +0100
+@@ -596,7 +596,7 @@ retint_kernel:
*/
.macro apicinterrupt num,func
INTR_FRAME
@@ -45,9 +45,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/entry.S ./arch/x86_64/
CFI_ADJUST_CFA_OFFSET 8
interrupt \func
jmp ret_from_intr
-diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/irq.c ./arch/x86_64/kernel/irq.c
---- ../pristine-linux-2.6.16.13/arch/x86_64/kernel/irq.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/x86_64/kernel/irq.c 2006-05-04 17:41:49.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/irq.c ./arch/x86_64/kernel/irq.c
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/irq.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/irq.c 2006-09-19 14:05:56.000000000 +0100
@@ -96,8 +96,8 @@ skip:
*/
asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
@@ -59,9 +59,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/irq.c ./arch/x86_64/ke
exit_idle();
irq_enter();
-diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/smp.c ./arch/x86_64/kernel/smp.c
---- ../pristine-linux-2.6.16.13/arch/x86_64/kernel/smp.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./arch/x86_64/kernel/smp.c 2006-05-04 17:41:49.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/smp.c ./arch/x86_64/kernel/smp.c
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/smp.c 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/smp.c 2006-09-19 14:05:56.000000000 +0100
@@ -135,10 +135,10 @@ asmlinkage void smp_invalidate_interrupt
cpu = smp_processor_id();
@@ -75,9 +75,9 @@ diff -pruN ../pristine-linux-2.6.16.13/arch/x86_64/kernel/smp.c ./arch/x86_64/ke
f = &per_cpu(flush_state, sender);
if (!cpu_isset(cpu, f->flush_cpumask))
-diff -pruN ../pristine-linux-2.6.16.13/include/asm-x86_64/hw_irq.h ./include/asm-x86_64/hw_irq.h
---- ../pristine-linux-2.6.16.13/include/asm-x86_64/hw_irq.h 2006-05-02 22:38:44.000000000 +0100
-+++ ./include/asm-x86_64/hw_irq.h 2006-05-04 17:41:49.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/include/asm-x86_64/hw_irq.h ./include/asm-x86_64/hw_irq.h
+--- ../orig-linux-2.6.16.29/include/asm-x86_64/hw_irq.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-x86_64/hw_irq.h 2006-09-19 14:05:56.000000000 +0100
@@ -127,7 +127,7 @@ asmlinkage void IRQ_NAME(nr); \
__asm__( \
"\n.p2align\n" \
diff --git a/patches/linux-2.6.16.13/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch b/patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
index 6f2422f517..1047ee417c 100644
--- a/patches/linux-2.6.16.13/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
+++ b/patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
@@ -1,37 +1,7 @@
-Taken from 2.6.18-rc4-mm1.
-
-From: Jeremy Fitzhardinge <jeremy@xensource.com>
-
-This patch will pack any .note.* section into a PT_NOTE segment in the output
-file.
-
-To do this, we tell ld that we need a PT_NOTE segment. This requires us to
-start explicitly mapping sections to segments, so we also need to explicitly
-create PT_LOAD segments for text and data, and map the sections to them
-appropriately. Fortunately, each section will default to its previous
-section's segment, so it doesn't take many changes to vmlinux.lds.S.
-
-This only changes i386 for now, but I presume the corresponding changes for
-other architectures will be as simple.
-
-This change also adds <linux/elfnote.h>, which defines C and Assembler macros
-for actually creating ELF notes.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
-Cc: Eric W. Biederman <ebiederm@xmission.com>
-Cc: Hollis Blanchard <hollisb@us.ibm.com>
-Signed-off-by: Andrew Morton <akpm@osdl.org>
----
-
- arch/i386/kernel/vmlinux.lds.S | 12 +++
- include/asm-generic/vmlinux.lds.h | 3
- include/linux/elfnote.h | 88 ++++++++++++++++++++++++++++
- 3 files changed, 101 insertions(+), 2 deletions(-)
-
-diff -puN arch/i386/kernel/vmlinux.lds.S~x86-put-note-sections-into-a-pt_note-segment-in-vmlinux arch/i386/kernel/vmlinux.lds.S
---- a/arch/i386/kernel/vmlinux.lds.S~x86-put-note-sections-into-a-pt_note-segment-in-vmlinux
-+++ a/arch/i386/kernel/vmlinux.lds.S
-@@ -13,6 +13,12 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386"
+diff -pruN ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S ./arch/i386/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/i386/kernel/vmlinux.lds.S 2006-09-19 14:05:48.000000000 +0100
++++ ./arch/i386/kernel/vmlinux.lds.S 2006-09-19 14:06:10.000000000 +0100
+@@ -12,6 +12,12 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386"
OUTPUT_ARCH(i386)
ENTRY(phys_startup_32)
jiffies = jiffies_64;
@@ -44,7 +14,7 @@ diff -puN arch/i386/kernel/vmlinux.lds.S~x86-put-note-sections-into-a-pt_note-se
SECTIONS
{
. = __KERNEL_START;
-@@ -26,7 +32,7 @@ SECTIONS
+@@ -25,7 +31,7 @@ SECTIONS
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
@@ -53,7 +23,7 @@ diff -puN arch/i386/kernel/vmlinux.lds.S~x86-put-note-sections-into-a-pt_note-se
_etext = .; /* End of text section */
-@@ -50,7 +56,7 @@ SECTIONS
+@@ -47,7 +53,7 @@ SECTIONS
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)
CONSTRUCTORS
@@ -62,26 +32,26 @@ diff -puN arch/i386/kernel/vmlinux.lds.S~x86-put-note-sections-into-a-pt_note-se
. = ALIGN(4096);
__nosave_begin = .;
-@@ -186,4 +192,6 @@ SECTIONS
+@@ -154,4 +160,6 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+
+ NOTES
}
-diff -puN include/asm-generic/vmlinux.lds.h~x86-put-note-sections-into-a-pt_note-segment-in-vmlinux include/asm-generic/vmlinux.lds.h
---- a/include/asm-generic/vmlinux.lds.h~x86-put-note-sections-into-a-pt_note-segment-in-vmlinux
-+++ a/include/asm-generic/vmlinux.lds.h
-@@ -194,3 +194,6 @@
+diff -pruN ../orig-linux-2.6.16.29/include/asm-generic/vmlinux.lds.h ./include/asm-generic/vmlinux.lds.h
+--- ../orig-linux-2.6.16.29/include/asm-generic/vmlinux.lds.h 2006-09-12 19:02:10.000000000 +0100
++++ ./include/asm-generic/vmlinux.lds.h 2006-09-19 14:06:10.000000000 +0100
+@@ -152,3 +152,6 @@
.stab.index 0 : { *(.stab.index) } \
.stab.indexstr 0 : { *(.stab.indexstr) } \
.comment 0 : { *(.comment) }
+
+#define NOTES \
+ .notes : { *(.note.*) } :note
-diff -puN /dev/null include/linux/elfnote.h
---- /dev/null
-+++ a/include/linux/elfnote.h
+diff -pruN ../orig-linux-2.6.16.29/include/linux/elfnote.h ./include/linux/elfnote.h
+--- ../orig-linux-2.6.16.29/include/linux/elfnote.h 1970-01-01 01:00:00.000000000 +0100
++++ ./include/linux/elfnote.h 2006-09-19 14:06:10.000000000 +0100
@@ -0,0 +1,88 @@
+#ifndef _LINUX_ELFNOTE_H
+#define _LINUX_ELFNOTE_H
@@ -171,4 +141,3 @@ diff -puN /dev/null include/linux/elfnote.h
+#endif /* __ASSEMBLER__ */
+
+#endif /* _LINUX_ELFNOTE_H */
-_
diff --git a/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch b/patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
index 9c0cd81d76..7e44d833b4 100644
--- a/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
+++ b/patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch
@@ -1,6 +1,7 @@
---- a/arch/x86_64/kernel/vmlinux.lds.S
-+++ b/arch/x86_64/kernel/vmlinux.lds.S
-@@ -13,6 +13,12 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86
+diff -pruN ../orig-linux-2.6.16.29/arch/x86_64/kernel/vmlinux.lds.S ./arch/x86_64/kernel/vmlinux.lds.S
+--- ../orig-linux-2.6.16.29/arch/x86_64/kernel/vmlinux.lds.S 2006-09-12 19:02:10.000000000 +0100
++++ ./arch/x86_64/kernel/vmlinux.lds.S 2006-09-19 14:06:15.000000000 +0100
+@@ -14,6 +14,12 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86
OUTPUT_ARCH(i386:x86-64)
ENTRY(phys_startup_64)
jiffies_64 = jiffies;
@@ -13,7 +14,7 @@
SECTIONS
{
. = __START_KERNEL;
-@@ -31,7 +37,7 @@ SECTIONS
+@@ -26,7 +32,7 @@ SECTIONS
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
@@ -22,7 +23,7 @@
/* out-of-line lock text */
.text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
-@@ -57,17 +63,10 @@ #endif
+@@ -43,17 +49,10 @@ SECTIONS
.data : AT(ADDR(.data) - LOAD_OFFSET) {
*(.data)
CONSTRUCTORS
@@ -41,7 +42,7 @@
. = ALIGN(PAGE_SIZE);
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-@@ -89,7 +88,7 @@ #define VVIRT_OFFSET (VSYSCALL_ADDR - VS
+@@ -75,7 +74,7 @@ SECTIONS
#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
. = VSYSCALL_ADDR;
@@ -50,7 +51,7 @@
__vsyscall_0 = VSYSCALL_VIRT_ADDR;
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-@@ -132,7 +131,7 @@ #undef VVIRT
+@@ -118,7 +117,7 @@ SECTIONS
. = ALIGN(8192); /* init_task */
.data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
*(.data.init_task)
@@ -59,7 +60,7 @@
. = ALIGN(4096);
.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-@@ -222,6 +221,14 @@ SECTIONS
+@@ -188,6 +187,14 @@ SECTIONS
. = ALIGN(4096);
__nosave_end = .;
@@ -74,7 +75,7 @@
_end = . ;
/* Sections to be discarded */
-@@ -235,4 +242,6 @@ #endif
+@@ -201,4 +208,6 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
diff --git a/patches/linux-2.6.16.13/xen-hotplug.patch b/patches/linux-2.6.16.32/xen-hotplug.patch
index 529cd568c1..06abdda41b 100644
--- a/patches/linux-2.6.16.13/xen-hotplug.patch
+++ b/patches/linux-2.6.16.32/xen-hotplug.patch
@@ -1,5 +1,6 @@
---- ../pristine-linux-2.6.16.13/fs/proc/proc_misc.c 2006-05-02 22:38:44.000000000 +0100
-+++ ./fs/proc/proc_misc.c 2006-05-22 15:29:34.000000000 +0100
+diff -pruN ../orig-linux-2.6.16.29/fs/proc/proc_misc.c ./fs/proc/proc_misc.c
+--- ../orig-linux-2.6.16.29/fs/proc/proc_misc.c 2006-09-12 19:02:10.000000000 +0100
++++ ./fs/proc/proc_misc.c 2006-09-19 14:06:00.000000000 +0100
@@ -433,7 +433,7 @@ static int show_stat(struct seq_file *p,
(unsigned long long)cputime64_to_clock_t(irq),
(unsigned long long)cputime64_to_clock_t(softirq),
diff --git a/patches/linux-2.6.16.13/xenoprof-generic.patch b/patches/linux-2.6.16.32/xenoprof-generic.patch
index 66b17ba2f3..7783495f70 100644
--- a/patches/linux-2.6.16.13/xenoprof-generic.patch
+++ b/patches/linux-2.6.16.32/xenoprof-generic.patch
@@ -1,6 +1,6 @@
-diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.c
---- orig/drivers/oprofile/buffer_sync.c 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/buffer_sync.c 2006-07-06 18:19:05.000000000 -0700
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/buffer_sync.c ./drivers/oprofile/buffer_sync.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/buffer_sync.c 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/buffer_sync.c 2006-11-06 15:16:52.000000000 -0800
@@ -6,6 +6,10 @@
*
* @author John Levon <levon@movementarian.org>
@@ -12,7 +12,27 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
* This is the core of the buffer management. Each
* CPU buffer is processed and entered into the
* global event buffer. Such processing is necessary
-@@ -275,15 +279,31 @@
+@@ -38,6 +42,7 @@ static cpumask_t marked_cpus = CPU_MASK_
+ static DEFINE_SPINLOCK(task_mortuary);
+ static void process_task_mortuary(void);
+
++static int cpu_current_domain[NR_CPUS];
+
+ /* Take ownership of the task struct and place it on the
+ * list for processing. Only after two full buffer syncs
+@@ -146,6 +151,11 @@ static void end_sync(void)
+ int sync_start(void)
+ {
+ int err;
++ int i;
++
++ for (i = 0; i < NR_CPUS; i++) {
++ cpu_current_domain[i] = COORDINATOR_DOMAIN;
++ }
+
+ start_cpu_work();
+
+@@ -275,15 +285,31 @@ static void add_cpu_switch(int i)
last_cookie = INVALID_COOKIE;
}
@@ -50,7 +70,7 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
static void
add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
{
-@@ -348,9 +368,9 @@
+@@ -348,9 +374,9 @@ static int add_us_sample(struct mm_struc
* for later lookup from userspace.
*/
static int
@@ -62,7 +82,7 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
add_sample_entry(s->eip, s->event);
return 1;
} else if (mm) {
-@@ -496,10 +516,11 @@
+@@ -496,15 +522,21 @@ void sync_buffer(int cpu)
struct mm_struct *mm = NULL;
struct task_struct * new;
unsigned long cookie = 0;
@@ -75,7 +95,17 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
down(&buffer_sem);
-@@ -512,16 +533,18 @@
+ add_cpu_switch(cpu);
+
++ /* We need to assign the first samples in this CPU buffer to the
++ same domain that we were processing at the last sync_buffer */
++ if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
++ add_domain_switch(cpu_current_domain[cpu]);
++ }
+ /* Remember, only we can modify tail_pos */
+
+ available = get_slots(cpu_buf);
+@@ -512,16 +544,18 @@ void sync_buffer(int cpu)
for (i = 0; i < available; ++i) {
struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
@@ -99,7 +129,7 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
} else {
struct mm_struct * oldmm = mm;
-@@ -535,11 +558,16 @@
+@@ -535,11 +569,21 @@ void sync_buffer(int cpu)
add_user_ctx_switch(new, cookie);
}
} else {
@@ -109,10 +139,15 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
- state = sb_bt_ignore;
- atomic_inc(&oprofile_stats.bt_lost_no_mapping);
+ if (domain_switch) {
++ cpu_current_domain[cpu] = s->eip;
+ add_domain_switch(s->eip);
+ domain_switch = 0;
+ } else {
-+ if (state >= sb_bt_start &&
++ if (cpu_current_domain[cpu] !=
++ COORDINATOR_DOMAIN) {
++ add_sample_entry(s->eip, s->event);
++ }
++ else if (state >= sb_bt_start &&
+ !add_sample(mm, s, cpu_mode)) {
+ if (state == sb_bt_start) {
+ state = sb_bt_ignore;
@@ -121,9 +156,21 @@ diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.
}
}
}
-diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
---- orig/drivers/oprofile/cpu_buffer.c 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/cpu_buffer.c 2006-07-06 18:19:05.000000000 -0700
+@@ -548,6 +592,11 @@ void sync_buffer(int cpu)
+ }
+ release_mm(mm);
+
++ /* We reset domain to COORDINATOR at each CPU switch */
++ if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
++ add_domain_switch(COORDINATOR_DOMAIN);
++ }
++
+ mark_done(cpu);
+
+ up(&buffer_sem);
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.c ./drivers/oprofile/cpu_buffer.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.c 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/cpu_buffer.c 2006-11-06 14:47:55.000000000 -0800
@@ -6,6 +6,10 @@
*
* @author John Levon <levon@movementarian.org>
@@ -135,7 +182,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
* Each CPU has a local buffer that stores PC value/event
* pairs. We also log context switches when we notice them.
* Eventually each CPU's buffer is processed into the global
-@@ -34,6 +38,8 @@
+@@ -34,6 +38,8 @@ static void wq_sync_buffer(void *);
#define DEFAULT_TIMER_EXPIRE (HZ / 10)
static int work_enabled;
@@ -144,7 +191,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
void free_cpu_buffers(void)
{
int i;
-@@ -58,7 +64,7 @@
+@@ -58,7 +64,7 @@ int alloc_cpu_buffers(void)
goto fail;
b->last_task = NULL;
@@ -153,7 +200,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
b->tracing = 0;
b->buffer_size = buffer_size;
b->tail_pos = 0;
-@@ -114,7 +120,7 @@
+@@ -114,7 +120,7 @@ void cpu_buffer_reset(struct oprofile_cp
* collected will populate the buffer with proper
* values to initialize the buffer
*/
@@ -162,7 +209,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
cpu_buf->last_task = NULL;
}
-@@ -164,13 +170,13 @@
+@@ -164,13 +170,13 @@ add_code(struct oprofile_cpu_buffer * bu
* because of the head/tail separation of the writer and reader
* of the CPU buffer.
*
@@ -180,7 +227,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
{
struct task_struct * task;
-@@ -181,18 +187,18 @@
+@@ -181,18 +187,18 @@ static int log_sample(struct oprofile_cp
return 0;
}
@@ -206,7 +253,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
cpu_buf->last_task = task;
add_code(cpu_buf, (unsigned long)task);
}
-@@ -269,6 +275,25 @@
+@@ -269,6 +275,25 @@ void oprofile_add_trace(unsigned long pc
add_sample(cpu_buf, pc, 0);
}
@@ -232,10 +279,10 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
/*
* This serves to avoid cpu buffer overflow, and makes sure
* the task mortuary progresses
-diff -Naur orig/drivers/oprofile/cpu_buffer.h new/drivers/oprofile/cpu_buffer.h
---- orig/drivers/oprofile/cpu_buffer.h 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/cpu_buffer.h 2006-07-06 18:19:05.000000000 -0700
-@@ -36,7 +36,7 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.h ./drivers/oprofile/cpu_buffer.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/cpu_buffer.h 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/cpu_buffer.h 2006-11-06 14:47:55.000000000 -0800
+@@ -36,7 +36,7 @@ struct oprofile_cpu_buffer {
volatile unsigned long tail_pos;
unsigned long buffer_size;
struct task_struct * last_task;
@@ -244,7 +291,7 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.h new/drivers/oprofile/cpu_buffer.h
int tracing;
struct op_sample * buffer;
unsigned long sample_received;
-@@ -51,7 +51,10 @@
+@@ -51,7 +51,10 @@ extern struct oprofile_cpu_buffer cpu_bu
void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
/* transient events for the CPU buffer -> event buffer */
@@ -257,10 +304,10 @@ diff -Naur orig/drivers/oprofile/cpu_buffer.h new/drivers/oprofile/cpu_buffer.h
+#define CPU_DOMAIN_SWITCH 4
#endif /* OPROFILE_CPU_BUFFER_H */
-diff -Naur orig/drivers/oprofile/event_buffer.h new/drivers/oprofile/event_buffer.h
---- orig/drivers/oprofile/event_buffer.h 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/event_buffer.h 2006-07-06 18:19:05.000000000 -0700
-@@ -29,15 +29,20 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/event_buffer.h ./drivers/oprofile/event_buffer.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/event_buffer.h 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/event_buffer.h 2006-11-06 14:47:55.000000000 -0800
+@@ -29,15 +29,20 @@ void wake_up_buffer_waiter(void);
#define CPU_SWITCH_CODE 2
#define COOKIE_SWITCH_CODE 3
#define KERNEL_ENTER_SWITCH_CODE 4
@@ -282,9 +329,9 @@ diff -Naur orig/drivers/oprofile/event_buffer.h new/drivers/oprofile/event_buffe
/* add data to the event buffer */
void add_event_entry(unsigned long data);
-diff -Naur orig/drivers/oprofile/oprof.c new/drivers/oprofile/oprof.c
---- orig/drivers/oprofile/oprof.c 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/oprof.c 2006-07-06 18:19:05.000000000 -0700
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprof.c ./drivers/oprofile/oprof.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprof.c 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/oprof.c 2006-11-06 14:47:55.000000000 -0800
@@ -5,6 +5,10 @@
* @remark Read the file COPYING
*
@@ -305,7 +352,7 @@ diff -Naur orig/drivers/oprofile/oprof.c new/drivers/oprofile/oprof.c
struct oprofile_operations oprofile_ops;
unsigned long oprofile_started;
-@@ -33,6 +37,32 @@
+@@ -33,6 +37,32 @@ static DECLARE_MUTEX(start_sem);
*/
static int timer = 0;
@@ -338,10 +385,10 @@ diff -Naur orig/drivers/oprofile/oprof.c new/drivers/oprofile/oprof.c
int oprofile_setup(void)
{
int err;
-diff -Naur orig/drivers/oprofile/oprof.h new/drivers/oprofile/oprof.h
---- orig/drivers/oprofile/oprof.h 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/oprof.h 2006-07-06 18:19:05.000000000 -0700
-@@ -35,5 +35,8 @@
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprof.h ./drivers/oprofile/oprof.h
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprof.h 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/oprof.h 2006-11-06 14:47:55.000000000 -0800
+@@ -35,5 +35,8 @@ void oprofile_create_files(struct super_
void oprofile_timer_init(struct oprofile_operations * ops);
int oprofile_set_backtrace(unsigned long depth);
@@ -350,9 +397,9 @@ diff -Naur orig/drivers/oprofile/oprof.h new/drivers/oprofile/oprof.h
+int oprofile_set_passive(int passive_domains[], unsigned int pdomains);
#endif /* OPROF_H */
-diff -Naur orig/drivers/oprofile/oprofile_files.c new/drivers/oprofile/oprofile_files.c
---- orig/drivers/oprofile/oprofile_files.c 2006-05-02 14:38:44.000000000 -0700
-+++ new/drivers/oprofile/oprofile_files.c 2006-07-06 18:19:05.000000000 -0700
+diff -pruN ../orig-linux-2.6.16.29/drivers/oprofile/oprofile_files.c ./drivers/oprofile/oprofile_files.c
+--- ../orig-linux-2.6.16.29/drivers/oprofile/oprofile_files.c 2006-11-06 14:46:52.000000000 -0800
++++ ./drivers/oprofile/oprofile_files.c 2006-11-06 14:47:55.000000000 -0800
@@ -5,15 +5,21 @@
* @remark Read the file COPYING
*
@@ -376,7 +423,7 @@ diff -Naur orig/drivers/oprofile/oprofile_files.c new/drivers/oprofile/oprofile_
unsigned long fs_buffer_size = 131072;
unsigned long fs_cpu_buffer_size = 8192;
unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
-@@ -117,11 +123,202 @@
+@@ -117,11 +123,202 @@ static ssize_t dump_write(struct file *
static struct file_operations dump_fops = {
.write = dump_write,
};
@@ -580,9 +627,9 @@ diff -Naur orig/drivers/oprofile/oprofile_files.c new/drivers/oprofile/oprofile_
oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
-diff -Naur orig/include/linux/oprofile.h new/include/linux/oprofile.h
---- orig/include/linux/oprofile.h 2006-05-02 14:38:44.000000000 -0700
-+++ new/include/linux/oprofile.h 2006-07-06 18:19:31.000000000 -0700
+diff -pruN ../orig-linux-2.6.16.29/include/linux/oprofile.h ./include/linux/oprofile.h
+--- ../orig-linux-2.6.16.29/include/linux/oprofile.h 2006-11-06 14:46:42.000000000 -0800
++++ ./include/linux/oprofile.h 2006-11-06 14:47:55.000000000 -0800
@@ -16,6 +16,8 @@
#include <linux/types.h>
#include <linux/spinlock.h>
@@ -592,7 +639,7 @@ diff -Naur orig/include/linux/oprofile.h new/include/linux/oprofile.h
struct super_block;
struct dentry;
-@@ -27,6 +29,11 @@
+@@ -27,6 +29,11 @@ struct oprofile_operations {
/* create any necessary configuration files in the oprofile fs.
* Optional. */
int (*create_files)(struct super_block * sb, struct dentry * root);
@@ -604,7 +651,7 @@ diff -Naur orig/include/linux/oprofile.h new/include/linux/oprofile.h
/* Do any necessary interrupt setup. Optional. */
int (*setup)(void);
/* Do any necessary interrupt shutdown. Optional. */
-@@ -68,6 +75,8 @@
+@@ -68,6 +75,8 @@ void oprofile_add_pc(unsigned long pc, i
/* add a backtrace entry, to be called from the ->backtrace callback */
void oprofile_add_trace(unsigned long eip);
diff --git a/tools/Makefile b/tools/Makefile
index d16b590fe7..fa9d63da16 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -18,6 +18,7 @@ SUBDIRS-$(VTPM_TOOLS) += vtpm
SUBDIRS-y += xenstat
SUBDIRS-y += libaio
SUBDIRS-y += blktap
+SUBDIRS-y += libfsimage
# These don't cross-compile
ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
@@ -60,7 +61,7 @@ check_clean:
$(MAKE) -C check clean
.PHONY: ioemu ioemuinstall ioemuclean
-ifdef CONFIG_IOEMU
+ifeq ($(CONFIG_IOEMU),y)
export IOEMU_DIR ?= ioemu
ioemu ioemuinstall:
[ -f $(IOEMU_DIR)/config-host.mak ] || \
diff --git a/tools/Rules.mk b/tools/Rules.mk
index bb6cdaf286..b676b423b9 100644
--- a/tools/Rules.mk
+++ b/tools/Rules.mk
@@ -5,8 +5,6 @@ all:
include $(XEN_ROOT)/Config.mk
-CONFIG_$(shell uname -s) := y
-
XEN_XC = $(XEN_ROOT)/tools/python/xen/lowlevel/xc
XEN_LIBXC = $(XEN_ROOT)/tools/libxc
XEN_XENSTORE = $(XEN_ROOT)/tools/xenstore
@@ -16,6 +14,11 @@ X11_LDPATH = -L/usr/X11R6/$(LIBDIR)
CFLAGS += -D__XEN_TOOLS__
+# Enable implicit LFS support *and* explicit LFS names.
+CFLAGS += $(shell getconf LFS_CFLAGS)
+CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+LDFLAGS += $(shell getconf LFS_LDFLAGS)
+
%.opic: %.c
$(CC) $(CPPFLAGS) -DPIC $(CFLAGS) -fPIC -c -o $@ $<
@@ -25,9 +28,9 @@ CFLAGS += -D__XEN_TOOLS__
%.o: %.cc
$(CC) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
-OS = $(shell uname -s)
+.PHONY: mk-symlinks mk-symlinks-xen mk-symlinks-$(XEN_OS)
-.PHONY: mk-symlinks mk-symlinks-xen mk-symlinks-$(OS)
+mk-symlinks-SunOS:
mk-symlinks-Linux: LINUX_ROOT=$(XEN_ROOT)/linux-2.6-xen-sparse
mk-symlinks-Linux:
@@ -44,4 +47,4 @@ mk-symlinks-xen:
mkdir -p xen/io
( cd xen/io && ln -sf ../../$(XEN_ROOT)/xen/include/public/io/*.h . )
-mk-symlinks: mk-symlinks-xen mk-symlinks-$(OS)
+mk-symlinks: mk-symlinks-xen mk-symlinks-$(XEN_OS)
diff --git a/tools/blktap/drivers/Makefile b/tools/blktap/drivers/Makefile
index 7c7d4ab27c..13ff93e1f8 100644
--- a/tools/blktap/drivers/Makefile
+++ b/tools/blktap/drivers/Makefile
@@ -3,22 +3,16 @@ include $(XEN_ROOT)/tools/Rules.mk
INCLUDES += -I.. -I../lib
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
IBIN = blktapctrl tapdisk
QCOW_UTIL = img2qcow qcow2raw qcow-create
-INSTALL_DIR = /usr/sbin
+INST_DIR = /usr/sbin
LIBAIO_DIR = ../../libaio/src
-CFLAGS += -fPIC
-CFLAGS += -Wall
CFLAGS += -Werror
CFLAGS += -Wno-unused
-CFLAGS += -g3
CFLAGS += -fno-strict-aliasing
CFLAGS += -I $(XEN_LIBXC) -I $(LIBAIO_DIR)
CFLAGS += $(INCLUDES) -I. -I../../xenstore
-CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
CFLAGS += -D_GNU_SOURCE
# Get gcc to generate the dependencies for us.
@@ -28,7 +22,7 @@ DEPS = .*.d
THREADLIB := -lpthread -lz
LIBS := -L. -L.. -L../lib
LIBS += -L$(XEN_LIBXC)
-LIBS += -lblktap
+LIBS += -lblktap -lxenctrl
LIBS += -lcrypto
LIBS += -lz
LIBS += -L$(XEN_XENSTORE) -lxenstore
@@ -61,7 +55,7 @@ img2qcow qcow2raw qcow-create: %: $(BLK-OBJS)
$(CC) $(CFLAGS) -o $* $(BLK-OBJS) $*.c $(AIOLIBS) $(LIBS)
install: all
- $(INSTALL_PROG) $(IBIN) $(QCOW_UTIL) $(DESTDIR)$(INSTALL_DIR)
+ $(INSTALL_PROG) $(IBIN) $(QCOW_UTIL) $(DESTDIR)$(INST_DIR)
clean:
rm -rf *.o *~ $(DEPS) xen TAGS $(IBIN) $(LIB) $(QCOW_UTIL)
diff --git a/tools/blktap/drivers/blktapctrl.c b/tools/blktap/drivers/blktapctrl.c
index 3e535b9fec..cb2258af42 100644
--- a/tools/blktap/drivers/blktapctrl.c
+++ b/tools/blktap/drivers/blktapctrl.c
@@ -67,16 +67,13 @@ int run = 1;
int max_timeout = MAX_TIMEOUT;
int ctlfd = 0;
+int blktap_major;
+
static int open_ctrl_socket(char *devname);
static int write_msg(int fd, int msgtype, void *ptr, void *ptr2);
static int read_msg(int fd, int msgtype, void *ptr);
static driver_list_entry_t *active_disks[MAX_DISK_TYPES];
-void sig_handler(int sig)
-{
- run = 0;
-}
-
static void init_driver_list(void)
{
int i;
@@ -108,7 +105,18 @@ static void make_blktap_dev(char *devname, int major, int minor)
if (mknod(devname, S_IFCHR|0600,
makedev(major, minor)) == 0)
DPRINTF("Created %s device\n",devname);
- } else DPRINTF("%s device already exists\n",devname);
+ } else {
+ DPRINTF("%s device already exists\n",devname);
+ /* it already exists, but is it the same major number */
+ if (((st.st_rdev>>8) & 0xff) != major) {
+ DPRINTF("%s has old major %d\n",
+ devname,
+ (unsigned int)((st.st_rdev >> 8) & 0xff));
+ /* only try again if we succed in deleting it */
+ if (!unlink(devname))
+ make_blktap_dev(devname, major, minor);
+ }
+ }
}
static int get_new_dev(int *major, int *minor, blkif_t *blkif)
@@ -159,13 +167,22 @@ static int get_tapdisk_pid(blkif_t *blkif)
return 1;
}
-static blkif_t *test_path(char *path, char **dev, int *type)
+/* Look up the disk specified by path:
+ * if found, dev points to the device string in the path
+ * type is the tapdisk driver type id
+ * blkif is the existing interface if this is a shared driver
+ * and NULL otherwise.
+ * return 0 on success, -1 on error.
+ */
+
+static int test_path(char *path, char **dev, int *type, blkif_t *blkif)
{
char *ptr, handle[10];
- int i, size;
+ int i, size, found = 0;
size = sizeof(dtypes)/sizeof(disk_info_t *);
*type = MAX_DISK_TYPES + 1;
+ blkif = NULL;
if ( (ptr = strstr(path, ":"))!=NULL) {
memcpy(handle, path, (ptr - path));
@@ -174,103 +191,81 @@ static blkif_t *test_path(char *path, char **dev, int *type)
*ptr = '\0';
DPRINTF("Detected handle: [%s]\n",handle);
- for (i = 0; i < size; i++) {
- if (strncmp(handle, dtypes[i]->handle, (ptr - path))
- ==0) {
- *type = dtypes[i]->idnum;
-
- if (dtypes[i]->single_handler == 1) {
- /* Check whether tapdisk process
- already exists */
- if (active_disks[dtypes[i]->idnum]
- == NULL) return NULL;
- else
- return active_disks[dtypes[i]->idnum]->blkif;
- }
- }
- }
- } else *dev = NULL;
-
- return NULL;
+ for (i = 0; i < size; i++)
+ if (strncmp(handle, dtypes[i]->handle,
+ (ptr - path)) ==0) {
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ *type = dtypes[i]->idnum;
+
+ if (dtypes[i]->single_handler == 1) {
+ /* Check whether tapdisk process
+ already exists */
+ if (active_disks[dtypes[i]->idnum] == NULL)
+ blkif = NULL;
+ else
+ blkif = active_disks[dtypes[i]
+ ->idnum]->blkif;
+ }
+ return 0;
+ }
+ }
+
+ /* Fall-through case, we didn't find a disk driver. */
+ DPRINTF("Unknown blktap disk type [%s]!\n",handle);
+ *dev = NULL;
+ return -1;
}
+
static void add_disktype(blkif_t *blkif, int type)
{
- driver_list_entry_t *entry, *ptr, *last;
+ driver_list_entry_t *entry, **pprev;
- if (type > MAX_DISK_TYPES) return;
+ if (type > MAX_DISK_TYPES)
+ return;
entry = malloc(sizeof(driver_list_entry_t));
entry->blkif = blkif;
- entry->next = NULL;
- ptr = active_disks[type];
+ entry->next = NULL;
- if (ptr == NULL) {
- active_disks[type] = entry;
- entry->prev = NULL;
- return;
- }
-
- while (ptr != NULL) {
- last = ptr;
- ptr = ptr->next;
- }
+ pprev = &active_disks[type];
+ while (*pprev != NULL)
+ pprev = &(*pprev)->next;
- /*We've found the end of the list*/
- last->next = entry;
- entry->prev = last;
-
- return;
+ *pprev = entry;
+ entry->pprev = pprev;
}
static int del_disktype(blkif_t *blkif)
{
- driver_list_entry_t *ptr, *cur, *last;
+ driver_list_entry_t *entry, **pprev;
int type = blkif->drivertype, count = 0, close = 0;
- if (type > MAX_DISK_TYPES) return 1;
-
- ptr = active_disks[type];
- last = NULL;
- while (ptr != NULL) {
- count++;
- if (blkif == ptr->blkif) {
- cur = ptr;
- if (ptr->next != NULL) {
- /*There's more later in the chain*/
- if (!last) {
- /*We're first in the list*/
- active_disks[type] = ptr->next;
- ptr = ptr->next;
- ptr->prev = NULL;
- }
- else {
- /*We're sandwiched*/
- last->next = ptr->next;
- ptr = ptr->next;
- ptr->prev = last;
- }
-
- } else if (last) {
- /*There's more earlier in the chain*/
- last->next = NULL;
- } else {
- /*We're the only entry*/
- active_disks[type] = NULL;
- if(dtypes[type]->single_handler == 1)
- close = 1;
- }
- DPRINTF("DEL_DISKTYPE: Freeing entry\n");
- free(cur);
- if (dtypes[type]->single_handler == 0) close = 1;
+ if (type > MAX_DISK_TYPES)
+ return 1;
- return close;
- }
- last = ptr;
- ptr = ptr->next;
+ pprev = &active_disks[type];
+ while ((*pprev != NULL) && ((*pprev)->blkif != blkif))
+ pprev = &(*pprev)->next;
+
+ if ((entry = *pprev) == NULL) {
+ DPRINTF("DEL_DISKTYPE: No match\n");
+ return 1;
}
- DPRINTF("DEL_DISKTYPE: No match\n");
- return 1;
+
+ *pprev = entry->next;
+ if (entry->next)
+ entry->next->pprev = pprev;
+
+ DPRINTF("DEL_DISKTYPE: Freeing entry\n");
+ free(entry);
+
+ /* Caller should close() if no single controller, or list is empty. */
+ return (!dtypes[type]->single_handler || (active_disks[type] == NULL));
}
static int write_msg(int fd, int msgtype, void *ptr, void *ptr2)
@@ -425,7 +420,7 @@ static int read_msg(int fd, int msgtype, void *ptr)
image->secsize = img->secsize;
image->info = img->info;
- DPRINTF("Received CTLMSG_IMG: %lu, %lu, %lu\n",
+ DPRINTF("Received CTLMSG_IMG: %llu, %lu, %u\n",
image->size, image->secsize, image->info);
if(msgtype != CTLMSG_IMG) ret = 0;
break;
@@ -487,7 +482,11 @@ int blktapctrl_new_blkif(blkif_t *blkif)
if (get_new_dev(&major, &minor, blkif)<0)
return -1;
- exist = test_path(blk->params, &ptr, &type);
+ if (test_path(blk->params, &ptr, &type, exist) != 0) {
+ DPRINTF("Error in blktap device string(%s).\n",
+ blk->params);
+ return -1;
+ }
blkif->drivertype = type;
blkif->cookie = lrand48() % MAX_RAND_VAL;
@@ -584,8 +583,8 @@ int unmap_blktapctrl(blkif_t *blkif)
if (del_disktype(blkif)) {
close(blkif->fds[WRITE]);
close(blkif->fds[READ]);
-
}
+
return 0;
}
@@ -631,9 +630,11 @@ int main(int argc, char *argv[])
struct xs_handle *h;
struct pollfd pfd[NUM_POLL_FDS];
pid_t process;
+ char buf[128];
__init_blkif();
- openlog("BLKTAPCTRL", LOG_CONS|LOG_ODELAY, LOG_DAEMON);
+ snprintf(buf, sizeof(buf), "BLKTAPCTRL[%d]", getpid());
+ openlog(buf, LOG_CONS|LOG_ODELAY, LOG_DAEMON);
daemon(0,0);
print_drivers();
@@ -644,15 +645,19 @@ int main(int argc, char *argv[])
register_new_devmap_hook(map_new_blktapctrl);
register_new_unmap_hook(unmap_blktapctrl);
- /*Attach to blktap0 */
+ /* Attach to blktap0 */
asprintf(&devname,"%s/%s0", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME);
- make_blktap_dev(devname,254,0);
+ if ((ret = xc_find_device_number("blktap0")) < 0)
+ goto open_failed;
+ blktap_major = major(ret);
+ make_blktap_dev(devname,blktap_major,0);
ctlfd = open(devname, O_RDWR);
if (ctlfd == -1) {
DPRINTF("blktap0 open failed\n");
goto open_failed;
}
+
retry:
/* Set up store connection and watch. */
h = xs_daemon_open();
@@ -666,15 +671,11 @@ int main(int argc, char *argv[])
} else goto open_failed;
}
- ret = add_blockdevice_probe_watch(h, "Domain-0");
+ ret = setup_probe_watch(h);
if (ret != 0) {
DPRINTF("Failed adding device probewatch\n");
- if (count < MAX_ATTEMPTS) {
- count++;
- sleep(2);
- xs_daemon_close(h);
- goto retry;
- } else goto open_failed;
+ xs_daemon_close(h);
+ goto open_failed;
}
ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE );
diff --git a/tools/blktap/drivers/blktapctrl.h b/tools/blktap/drivers/blktapctrl.h
index 4a5e59577e..ddcb967533 100644
--- a/tools/blktap/drivers/blktapctrl.h
+++ b/tools/blktap/drivers/blktapctrl.h
@@ -30,19 +30,19 @@
*/
-static inline long int tapdisk_get_size(blkif_t *blkif)
+static inline unsigned long long tapdisk_get_size(blkif_t *blkif)
{
image_t *img = (image_t *)blkif->prv;
return img->size;
}
-static inline long int tapdisk_get_secsize(blkif_t *blkif)
+static inline unsigned long tapdisk_get_secsize(blkif_t *blkif)
{
image_t *img = (image_t *)blkif->prv;
return img->secsize;
}
-static inline unsigned tapdisk_get_info(blkif_t *blkif)
+static inline unsigned int tapdisk_get_info(blkif_t *blkif)
{
image_t *img = (image_t *)blkif->prv;
return img->info;
diff --git a/tools/blktap/drivers/tapdisk.c b/tools/blktap/drivers/tapdisk.c
index 3190a2b219..0c9b623abe 100644
--- a/tools/blktap/drivers/tapdisk.c
+++ b/tools/blktap/drivers/tapdisk.c
@@ -79,31 +79,17 @@ static void unmap_disk(struct td_state *s)
{
tapdev_info_t *info = s->ring_info;
struct tap_disk *drv = s->drv;
- fd_list_entry_t *ptr, *prev;
+ fd_list_entry_t *entry;
drv->td_close(s);
if (info != NULL && info->mem > 0)
munmap(info->mem, getpagesize() * BLKTAP_MMAP_REGION_SIZE);
- ptr = s->fd_entry;
- prev = ptr->prev;
-
- if (prev) {
- /*There are entries earlier in the list*/
- prev->next = ptr->next;
- if (ptr->next) {
- ptr = ptr->next;
- ptr->prev = prev;
- }
- } else {
- /*We are the first entry in list*/
- if (ptr->next) {
- ptr = ptr->next;
- fd_start = ptr;
- ptr->prev = NULL;
- } else fd_start = NULL;
- }
+ entry = s->fd_entry;
+ *entry->pprev = entry->next;
+ if (entry->next)
+ entry->next->pprev = entry->pprev;
close(info->fd);
@@ -144,35 +130,29 @@ static inline int LOCAL_FD_SET(fd_set *readfds)
return 0;
}
-static inline fd_list_entry_t *add_fd_entry(int tap_fd, int io_fd[MAX_IOFD], struct td_state *s)
+static inline fd_list_entry_t *add_fd_entry(
+ int tap_fd, int io_fd[MAX_IOFD], struct td_state *s)
{
- fd_list_entry_t *ptr, *last, *entry;
+ fd_list_entry_t **pprev, *entry;
int i;
+
DPRINTF("Adding fd_list_entry\n");
/*Add to linked list*/
s->fd_entry = entry = malloc(sizeof(fd_list_entry_t));
entry->tap_fd = tap_fd;
- for (i = 0; i < MAX_IOFD; i++) entry->io_fd[i] = io_fd[i];
+ for (i = 0; i < MAX_IOFD; i++)
+ entry->io_fd[i] = io_fd[i];
entry->s = s;
entry->next = NULL;
- ptr = fd_start;
- if (ptr == NULL) {
- /*We are the first entry*/
- fd_start = entry;
- entry->prev = NULL;
- goto finish;
- }
+ pprev = &fd_start;
+ while (*pprev != NULL)
+ pprev = &(*pprev)->next;
- while (ptr != NULL) {
- last = ptr;
- ptr = ptr->next;
- }
- last->next = entry;
- entry->prev = last;
+ *pprev = entry;
+ entry->pprev = pprev;
- finish:
return entry;
}
@@ -271,7 +251,6 @@ static int read_msg(char *buf)
int length, len, msglen, tap_fd, *io_fd;
char *ptr, *path;
image_t *img;
- struct timeval timeout;
msg_hdr_t *msg;
msg_newdev_t *msg_dev;
msg_pid_t *msg_pid;
@@ -402,7 +381,6 @@ static inline int write_rsp_to_ring(struct td_state *s, blkif_response_t *rsp)
rsp_d = RING_GET_RESPONSE(&info->fe_ring, info->fe_ring.rsp_prod_pvt);
memcpy(rsp_d, rsp, sizeof(blkif_response_t));
- wmb();
info->fe_ring.rsp_prod_pvt++;
return 0;
@@ -579,17 +557,18 @@ int main(int argc, char *argv[])
{
int len, msglen, ret;
char *p, *buf;
- fd_set readfds, writefds;
- struct timeval timeout;
+ fd_set readfds, writefds;
fd_list_entry_t *ptr;
struct tap_disk *drv;
struct td_state *s;
+ char openlogbuf[128];
if (argc != 3) usage();
daemonize();
- openlog("TAPDISK", LOG_CONS|LOG_ODELAY, LOG_DAEMON);
+ snprintf(openlogbuf, sizeof(openlogbuf), "TAPDISK[%d]", getpid());
+ openlog(openlogbuf, LOG_CONS|LOG_ODELAY, LOG_DAEMON);
/*Setup signal handlers*/
signal (SIGBUS, sig_handler);
signal (SIGINT, sig_handler);
@@ -622,12 +601,9 @@ int main(int argc, char *argv[])
/*Set all tap fds*/
LOCAL_FD_SET(&readfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 1000;
-
/*Wait for incoming messages*/
ret = select(maxfds + 1, &readfds, (fd_set *) 0,
- (fd_set *) 0, &timeout);
+ (fd_set *) 0, NULL);
if (ret > 0)
{
diff --git a/tools/blktap/drivers/tapdisk.h b/tools/blktap/drivers/tapdisk.h
index 1f03156456..813c05ebe3 100644
--- a/tools/blktap/drivers/tapdisk.h
+++ b/tools/blktap/drivers/tapdisk.h
@@ -61,7 +61,6 @@
/* Things disks need to know about, these should probably be in a higher-level
* header. */
-#define MAX_REQUESTS 64
#define MAX_SEGMENTS_PER_REQ 11
#define SECTOR_SHIFT 9
#define DEFAULT_SECTOR_SIZE 512
@@ -75,9 +74,9 @@ struct td_state {
void *ring_info;
void *fd_entry;
char backing_file[1024]; /*Used by differencing disks, e.g. qcow*/
- long int sector_size;
- uint64_t size;
- long int info;
+ unsigned long sector_size;
+ unsigned long long size;
+ unsigned int info;
};
/* Prototype of the callback to activate as requests complete. */
@@ -191,9 +190,8 @@ static disk_info_t *dtypes[] = {
};
typedef struct driver_list_entry {
- void *blkif;
- void *prev;
- void *next;
+ struct blkif *blkif;
+ struct driver_list_entry **pprev, *next;
} driver_list_entry_t;
typedef struct fd_list_entry {
@@ -201,8 +199,7 @@ typedef struct fd_list_entry {
int tap_fd;
int io_fd[MAX_IOFD];
struct td_state *s;
- void *prev;
- void *next;
+ struct fd_list_entry **pprev, *next;
} fd_list_entry_t;
int qcow_create(const char *filename, uint64_t total_size,
diff --git a/tools/blktap/lib/Makefile b/tools/blktap/lib/Makefile
index 38f8ac686c..a4880d44cc 100644
--- a/tools/blktap/lib/Makefile
+++ b/tools/blktap/lib/Makefile
@@ -7,10 +7,6 @@ SONAME = libblktap.so.$(MAJOR)
BLKTAP_INSTALL_DIR = /usr/sbin
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
INCLUDES += -I. -I.. -I $(XEN_LIBXC) -I $(XEN_XENSTORE)
LIBS := -lz
@@ -21,7 +17,6 @@ SRCS += xenbus.c blkif.c xs_api.c
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -fno-strict-aliasing -fPIC
-CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
# get asprintf():
CFLAGS += -D _GNU_SOURCE
@@ -56,8 +51,8 @@ clean:
rm -rf *.a *.so* *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS
libblktap.a: $(OBJS)
- $(CC) $(CFLAGS) -Wl,-soname -Wl,$(SONAME) -shared \
- -L$(XEN_XENSTORE) -l xenstore \
+ $(CC) $(CFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,$(SONAME) $(SHLIB_CFLAGS) \
+ -L$(XEN_XENSTORE) -l xenstore \
-o libblktap.so.$(MAJOR).$(MINOR) $^ $(LIBS)
ln -sf libblktap.so.$(MAJOR).$(MINOR) libblktap.so.$(MAJOR)
ln -sf libblktap.so.$(MAJOR) libblktap.so
diff --git a/tools/blktap/lib/blktaplib.h b/tools/blktap/lib/blktaplib.h
index e1d2289ced..12f4950133 100644
--- a/tools/blktap/lib/blktaplib.h
+++ b/tools/blktap/lib/blktaplib.h
@@ -41,7 +41,7 @@
#include <sys/types.h>
#include <unistd.h>
-#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, getpagesize())
+#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, XC_PAGE_SIZE)
/* size of the extra VMA area to map in attached pages. */
#define BLKTAP_VMA_PAGES BLK_RING_SIZE
@@ -74,15 +74,16 @@ static inline int BLKTAP_MODE_VALID(unsigned long arg)
( arg == BLKTAP_MODE_INTERPOSE ) );
}
-#define MAX_REQUESTS 64
+#define MAX_REQUESTS BLK_RING_SIZE
#define BLKTAP_IOCTL_KICK 1
-#define MAX_PENDING_REQS 64
+#define MAX_PENDING_REQS BLK_RING_SIZE
#define BLKTAP_DEV_DIR "/dev/xen"
#define BLKTAP_DEV_NAME "blktap"
-#define BLKTAP_DEV_MAJOR 254
#define BLKTAP_DEV_MINOR 0
+extern int blktap_major;
+
#define BLKTAP_RING_PAGES 1 /* Front */
#define BLKTAP_MMAP_REGION_SIZE (BLKTAP_RING_PAGES + MMAP_PAGES)
@@ -96,9 +97,9 @@ typedef struct {
} pending_req_t;
struct blkif_ops {
- long int (*get_size)(struct blkif *blkif);
- long int (*get_secsize)(struct blkif *blkif);
- unsigned (*get_info)(struct blkif *blkif);
+ unsigned long long (*get_size)(struct blkif *blkif);
+ unsigned long (*get_secsize)(struct blkif *blkif);
+ unsigned int (*get_info)(struct blkif *blkif);
};
typedef struct blkif {
@@ -155,9 +156,9 @@ typedef struct domid_translate {
} domid_translate_t ;
typedef struct image {
- long int size;
- long int secsize;
- long int info;
+ unsigned long long size;
+ unsigned long secsize;
+ unsigned int info;
} image_t;
typedef struct msg_hdr {
@@ -192,13 +193,12 @@ typedef struct msg_pid {
#define CTLMSG_PID_RSP 10
/* xenstore/xenbus: */
-extern int add_blockdevice_probe_watch(struct xs_handle *h,
- const char *domname);
+#define DOMNAME "Domain-0"
+int setup_probe_watch(struct xs_handle *h);
int xs_fire_next_watch(struct xs_handle *h);
/* Abitrary values, must match the underlying driver... */
-#define MAX_PENDING_REQS 64
#define MAX_TAP_DEV 100
/* Accessing attached data page mappings */
diff --git a/tools/blktap/lib/xenbus.c b/tools/blktap/lib/xenbus.c
index 91cdd00536..d50e492784 100644
--- a/tools/blktap/lib/xenbus.c
+++ b/tools/blktap/lib/xenbus.c
@@ -166,62 +166,60 @@ static void ueblktap_setup(struct xs_handle *h, char *bepath)
goto fail;
}
- deverr = xs_gather(h, bepath, "physical-device", "%li", &pdev, NULL);
- if (!deverr) {
- DPRINTF("pdev set to %ld\n",pdev);
- if (be->pdev && be->pdev != pdev) {
- DPRINTF("changing physical-device not supported");
- goto fail;
- }
- be->pdev = pdev;
- }
-
- /*Check to see if device is to be opened read-only*/
- asprintf(&path, "%s/%s", bepath, "read-only");
- if (xs_exists(h, path))
- be->readonly = 1;
-
- if (be->blkif == NULL) {
-
- /* Front end dir is a number, which is used as the handle. */
- p = strrchr(be->frontpath, '/') + 1;
- handle = strtoul(p, NULL, 0);
-
- be->blkif = alloc_blkif(be->frontend_id);
-
- if (be->blkif == NULL)
- goto fail;
+ deverr = xs_gather(h, bepath, "physical-device", "%li", &pdev, NULL);
+ if (!deverr) {
+ DPRINTF("pdev set to %ld\n",pdev);
+ if (be->pdev && be->pdev != pdev) {
+ DPRINTF("changing physical-device not supported");
+ goto fail;
+ }
+ be->pdev = pdev;
+ }
+
+ /* Check to see if device is to be opened read-only. */
+ asprintf(&path, "%s/%s", bepath, "read-only");
+ if (xs_exists(h, path))
+ be->readonly = 1;
+
+ if (be->blkif == NULL) {
+ /* Front end dir is a number, which is used as the handle. */
+ p = strrchr(be->frontpath, '/') + 1;
+ handle = strtoul(p, NULL, 0);
+
+ be->blkif = alloc_blkif(be->frontend_id);
+ if (be->blkif == NULL)
+ goto fail;
be->blkif->be_id = get_be_id(bepath);
- /*Insert device specific info*/
- blk = malloc(sizeof(blkif_info_t));
+ /* Insert device specific info, */
+ blk = malloc(sizeof(blkif_info_t));
if (!blk) {
DPRINTF("Out of memory - blkif_info_t\n");
goto fail;
}
- er = xs_gather(h, bepath, "params", NULL, &blk->params, NULL);
- if (er)
- goto fail;
- be->blkif->info = blk;
+ er = xs_gather(h, bepath, "params", NULL, &blk->params, NULL);
+ if (er)
+ goto fail;
+ be->blkif->info = blk;
- if (deverr) {
- /*Dev number was not available, try to set manually*/
- pdev = convert_dev_name_to_num(blk->params);
- be->pdev = pdev;
- }
-
- er = blkif_init(be->blkif, handle, be->pdev, be->readonly);
+ if (deverr) {
+ /*Dev number was not available, try to set manually*/
+ pdev = convert_dev_name_to_num(blk->params);
+ be->pdev = pdev;
+ }
- if (er != 0) {
- DPRINTF("Unable to open device %s\n",blk->params);
+ er = blkif_init(be->blkif, handle, be->pdev, be->readonly);
+ if (er != 0) {
+ DPRINTF("Unable to open device %s\n",blk->params);
goto fail;
}
- DPRINTF("[BECHG]: ADDED A NEW BLKIF (%s)\n", bepath);
- }
+ DPRINTF("[BECHG]: ADDED A NEW BLKIF (%s)\n", bepath);
+ }
+
/* Supply the information about the device to xenstore */
- er = xs_printf(h, be->backpath, "sectors", "%lu",
+ er = xs_printf(h, be->backpath, "sectors", "%llu",
be->blkif->ops->get_size(be->blkif));
if (er == 0) {
@@ -283,10 +281,10 @@ static void ueblktap_probe(struct xs_handle *h, struct xenbus_watch *w,
*asserts that xenstore structure is always 7 levels deep
*e.g. /local/domain/0/backend/vbd/1/2049
*/
- len = strsep_len(bepath, '/', 7);
- if (len < 0)
- goto free_be;
- bepath[len] = '\0';
+ len = strsep_len(bepath, '/', 7);
+ if (len < 0)
+ goto free_be;
+ bepath[len] = '\0';
be = malloc(sizeof(*be));
if (!be) {
@@ -318,22 +316,21 @@ static void ueblktap_probe(struct xs_handle *h, struct xenbus_watch *w,
if ( (be != NULL) && (be->blkif != NULL) )
backend_remove(h, be);
else goto free_be;
- if (bepath)
+ if (bepath)
free(bepath);
return;
}
- /* Are we already tracking this device? */
- if (be_exists_be(bepath)) {
+ /* Are we already tracking this device? */
+ if (be_exists_be(bepath))
goto free_be;
- }
be->backpath = bepath;
- be->frontpath = frontend;
+ be->frontpath = frontend;
- list_add(&be->list, &belist);
+ list_add(&be->list, &belist);
- DPRINTF("[PROBE]\tADDED NEW DEVICE (%s)\n", bepath);
+ DPRINTF("[PROBE]\tADDED NEW DEVICE (%s)\n", bepath);
DPRINTF("\tFRONTEND (%s),(%ld)\n", frontend,be->frontend_id);
ueblktap_setup(h, bepath);
@@ -342,11 +339,10 @@ static void ueblktap_probe(struct xs_handle *h, struct xenbus_watch *w,
free_be:
if (frontend)
free(frontend);
- if (bepath)
+ if (bepath)
free(bepath);
if (be)
free(be);
- return;
}
/**
@@ -356,16 +352,10 @@ static void ueblktap_probe(struct xs_handle *h, struct xenbus_watch *w,
*are created, we initalise the state and attach a disk.
*/
-int add_blockdevice_probe_watch(struct xs_handle *h, const char *domname)
+int add_blockdevice_probe_watch(struct xs_handle *h, const char *domid)
{
- char *domid, *path;
+ char *path;
struct xenbus_watch *vbd_watch;
- int er;
-
- domid = get_dom_domid(h, domname);
-
- DPRINTF("%s: %s\n",
- domname, (domid != NULL) ? domid : "[ not found! ]");
asprintf(&path, "/local/domain/%s/backend/tap", domid);
if (path == NULL)
@@ -378,10 +368,67 @@ int add_blockdevice_probe_watch(struct xs_handle *h, const char *domname)
}
vbd_watch->node = path;
vbd_watch->callback = ueblktap_probe;
- er = register_xenbus_watch(h, vbd_watch);
- if (er == 0) {
+ if (register_xenbus_watch(h, vbd_watch) != 0) {
DPRINTF("ERROR: adding vbd probe watch %s\n", path);
return -EINVAL;
}
return 0;
}
+
+/* Asynch callback to check for /local/domain/<DOMID>/name */
+void check_dom(struct xs_handle *h, struct xenbus_watch *w,
+ const char *bepath_im)
+{
+ char *domid;
+
+ domid = get_dom_domid(h);
+ if (domid == NULL)
+ return;
+
+ add_blockdevice_probe_watch(h, domid);
+ free(domid);
+ unregister_xenbus_watch(h, w);
+}
+
+/* We must wait for xend to register /local/domain/<DOMID> */
+int watch_for_domid(struct xs_handle *h)
+{
+ struct xenbus_watch *domid_watch;
+ char *path = NULL;
+
+ asprintf(&path, "/local/domain");
+ if (path == NULL)
+ return -ENOMEM;
+
+ domid_watch = malloc(sizeof(struct xenbus_watch));
+ if (domid_watch == NULL) {
+ DPRINTF("ERROR: unable to malloc domid_watch [%s]\n", path);
+ return -EINVAL;
+ }
+
+ domid_watch->node = path;
+ domid_watch->callback = check_dom;
+
+ if (register_xenbus_watch(h, domid_watch) != 0) {
+ DPRINTF("ERROR: adding vbd probe watch %s\n", path);
+ return -EINVAL;
+ }
+
+ DPRINTF("Set async watch for /local/domain\n");
+
+ return 0;
+}
+
+int setup_probe_watch(struct xs_handle *h)
+{
+ char *domid;
+ int ret;
+
+ domid = get_dom_domid(h);
+ if (domid == NULL)
+ return watch_for_domid(h);
+
+ ret = add_blockdevice_probe_watch(h, domid);
+ free(domid);
+ return ret;
+}
diff --git a/tools/blktap/lib/xs_api.c b/tools/blktap/lib/xs_api.c
index 054e9c850a..eded38afdc 100644
--- a/tools/blktap/lib/xs_api.c
+++ b/tools/blktap/lib/xs_api.c
@@ -106,7 +106,7 @@ again:
if (!xs_transaction_end(xs, xth, ret)) {
if (ret == 0 && errno == EAGAIN)
goto again;
- else
+ else
ret = errno;
}
@@ -118,25 +118,25 @@ again:
int xs_printf(struct xs_handle *h, const char *dir, const char *node,
const char *fmt, ...)
{
- char *buf, *path;
- va_list ap;
- int ret;
+ char *buf, *path;
+ va_list ap;
+ int ret;
- va_start(ap, fmt);
- ret = vasprintf(&buf, fmt, ap);
- va_end(ap);
+ va_start(ap, fmt);
+ ret = vasprintf(&buf, fmt, ap);
+ va_end(ap);
- asprintf(&path, "%s/%s", dir, node);
+ asprintf(&path, "%s/%s", dir, node);
- if ( (path == NULL) || (buf == NULL) )
+ if ((path == NULL) || (buf == NULL))
return 0;
- ret = xs_write(h, XBT_NULL, path, buf, strlen(buf)+1);
+ ret = xs_write(h, XBT_NULL, path, buf, strlen(buf)+1);
- free(buf);
- free(path);
+ free(buf);
+ free(path);
- return ret;
+ return ret;
}
@@ -165,7 +165,7 @@ int xs_exists(struct xs_handle *h, const char *path)
* This assumes that the domain name we are looking for is unique.
* Name parameter Domain-0
*/
-char *get_dom_domid(struct xs_handle *h, const char *name)
+char *get_dom_domid(struct xs_handle *h)
{
char **e, *val, *domid = NULL;
unsigned int num, len;
@@ -179,7 +179,9 @@ char *get_dom_domid(struct xs_handle *h, const char *name)
}
e = xs_directory(h, xth, "/local/domain", &num);
-
+ if (e == NULL)
+ return NULL;
+
for (i = 0; (i < num) && (domid == NULL); i++) {
asprintf(&path, "/local/domain/%s/name", e[i]);
val = xs_read(h, xth, path, &len);
@@ -187,7 +189,7 @@ char *get_dom_domid(struct xs_handle *h, const char *name)
if (val == NULL)
continue;
- if (strcmp(val, name) == 0) {
+ if (strcmp(val, DOMNAME) == 0) {
/* match! */
asprintf(&path, "/local/domain/%s/domid", e[i]);
domid = xs_read(h, xth, path, &len);
@@ -249,12 +251,12 @@ int convert_dev_name_to_num(char *name) {
ret = BASE_DEV_VAL;
}
- free(p_sd);
- free(p_hd);
- free(p_xvd);
- free(p_plx);
- free(alpha);
-
+ free(p_sd);
+ free(p_hd);
+ free(p_xvd);
+ free(p_plx);
+ free(alpha);
+
return ret;
}
@@ -281,42 +283,39 @@ int register_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
{
/* Pointer in ascii is the token. */
char token[sizeof(watch) * 2 + 1];
- int er;
-
+
sprintf(token, "%lX", (long)watch);
- if (find_watch(token))
- {
+ if (find_watch(token)) {
DPRINTF("watch collision!\n");
return -EINVAL;
}
- er = xs_watch(h, watch->node, token);
- if (er != 0) {
- list_add(&watch->list, &watches);
- }
-
- return er;
+ if (!xs_watch(h, watch->node, token)) {
+ DPRINTF("unable to set watch!\n");
+ return -EINVAL;
+ }
+
+ list_add(&watch->list, &watches);
+
+ return 0;
}
int unregister_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
{
char token[sizeof(watch) * 2 + 1];
- int er;
sprintf(token, "%lX", (long)watch);
- if (!find_watch(token))
- {
+ if (!find_watch(token)) {
DPRINTF("no such watch!\n");
return -EINVAL;
}
-
-
- er = xs_unwatch(h, watch->node, token);
+
+ if (!xs_unwatch(h, watch->node, token))
+ DPRINTF("XENBUS Failed to release watch %s: %i\n",
+ watch->node, er);
+
list_del(&watch->list);
- if (er == 0)
- DPRINTF("XENBUS Failed to release watch %s: %i\n",
- watch->node, er);
return 0;
}
@@ -354,14 +353,10 @@ int xs_fire_next_watch(struct xs_handle *h)
token = res[XS_WATCH_TOKEN];
w = find_watch(token);
- if (!w)
- {
- DPRINTF("unregistered watch fired\n");
- goto done;
- }
- w->callback(h, w, node);
-
- done:
+ if (w)
+ w->callback(h, w, node);
+
free(res);
+
return 1;
}
diff --git a/tools/blktap/lib/xs_api.h b/tools/blktap/lib/xs_api.h
index c4183a2dde..34430dcc48 100644
--- a/tools/blktap/lib/xs_api.h
+++ b/tools/blktap/lib/xs_api.h
@@ -42,7 +42,7 @@ int xs_gather(struct xs_handle *xs, const char *dir, ...);
int xs_printf(struct xs_handle *h, const char *dir, const char *node,
const char *fmt, ...);
int xs_exists(struct xs_handle *h, const char *path);
-char *get_dom_domid(struct xs_handle *h, const char *name);
+char *get_dom_domid(struct xs_handle *h);
int convert_dev_name_to_num(char *name);
int register_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch);
int unregister_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch);
diff --git a/tools/check/check_brctl b/tools/check/check_brctl
index 6b8250f5cc..e926120235 100755
--- a/tools/check/check_brctl
+++ b/tools/check/check_brctl
@@ -1,10 +1,27 @@
-#!/bin/bash
+#!/bin/sh
# CHECK-INSTALL
-function error {
- echo
- echo ' *** Check for the bridge control utils (brctl) FAILED'
- exit 1
-}
+RC=0
-which brctl 1>/dev/null 2>&1 || error
+case ${OS} in
+OpenBSD|NetBSD|FreeBSD)
+ # These systems have a bridge builtin
+ TOOL="brconfig"
+ which ${TOOL} 1>/dev/null 2>&1 || RC=1
+ ;;
+Linux)
+ TOOL="brctl"
+ which ${TOOL} 1>/dev/null 2>&1 || RC=1
+ ;;
+*)
+ TOOL=""
+ echo "Unknown OS" && RC=1
+ ;;
+esac
+
+if test ${RC} -ne 0; then
+ echo
+ echo " *** Check for the bridge control utils (${TOOL}) FAILED"
+fi
+
+exit ${RC}
diff --git a/tools/check/check_crypto_lib b/tools/check/check_crypto_lib
new file mode 100755
index 0000000000..02e0d1821c
--- /dev/null
+++ b/tools/check/check_crypto_lib
@@ -0,0 +1,11 @@
+#!/bin/bash
+# CHECK-BUILD CHECK-INSTALL
+
+function error {
+ echo
+ echo " *** Check for crypto library FAILED"
+ exit 1
+}
+
+set -e
+ldconfig -p | grep -q libcrypto.so || error
diff --git a/tools/check/check_iproute b/tools/check/check_iproute
index c990349a9b..35af9a4c4b 100755
--- a/tools/check/check_iproute
+++ b/tools/check/check_iproute
@@ -1,11 +1,26 @@
-#!/bin/bash
+#!/bin/sh
# CHECK-INSTALL
-function error {
- echo
- echo ' *** Check for iproute (ip addr) FAILED'
- exit 1
-}
+RC=0
-ip addr list 1>/dev/null 2>&1 || error
+case ${OS} in
+OpenBSD|NetBSD|FreeBSD)
+ TOOL="ifconfig"
+ eval ${TOOL} -a 1>/dev/null 2>&1 || RC=1
+ ;;
+Linux)
+ TOOL="ip addr"
+ eval ${TOOL} list 1>/dev/null 2>&1 || RC=1
+ ;;
+*)
+ TOOL=""
+ echo "Unknown OS" && RC=1
+ ;;
+esac
+if test ${RC} -ne 0; then
+ echo
+ echo " *** Check for iproute (${TOOL}) FAILED"
+fi
+
+exit ${RC}
diff --git a/tools/check/check_openssl_devel b/tools/check/check_openssl_devel
new file mode 100755
index 0000000000..fe9d0106d7
--- /dev/null
+++ b/tools/check/check_openssl_devel
@@ -0,0 +1,11 @@
+#!/bin/bash
+# CHECK-BUILD
+
+function error {
+ echo
+ echo " *** Check for openssl headers FAILED"
+ exit 1
+}
+
+set -e
+[ -e /usr/include/openssl/md5.h ] || error
diff --git a/tools/check/check_python b/tools/check/check_python
index a30b0690a2..e56f5a9684 100755
--- a/tools/check/check_python
+++ b/tools/check/check_python
@@ -1,10 +1,13 @@
-#!/bin/bash
+#!/bin/sh
# CHECK-BUILD CHECK-INSTALL
-function error {
- echo
- echo " *** Check for Python version >= 2.2 FAILED"
- exit 1
-}
+RC=0
-python -V 2>&1 | cut -d ' ' -f 2 | grep -q '^2.[2345]' || error
+python -V 2>&1 | cut -d ' ' -f 2 | grep -q '^2.[2345]' || RC=1
+
+if test ${RC} -ne 0; then
+ echo
+ echo " *** Check for Python version >= 2.2 FAILED"
+fi
+
+exit ${RC}
diff --git a/tools/check/check_python_devel b/tools/check/check_python_devel
new file mode 100755
index 0000000000..1074f4cf07
--- /dev/null
+++ b/tools/check/check_python_devel
@@ -0,0 +1,16 @@
+#!/bin/bash
+# CHECK-BUILD
+
+function error {
+ echo
+ echo " *** Check for python development environment FAILED"
+ exit 1
+}
+
+python -c '
+import os.path, sys
+for p in sys.path:
+ if os.path.exists(p + "/config/Makefile"):
+ sys.exit(0)
+sys.exit(1)
+' || error
diff --git a/tools/check/check_hotplug b/tools/check/check_udev
index 999c7d8e2e..2dd226ac46 100644..100755
--- a/tools/check/check_hotplug
+++ b/tools/check/check_udev
@@ -3,7 +3,7 @@
function error {
echo
- echo ' *** Check for the hotplug scripts (hotplug) FAILED'
+ echo ' *** Check for udev/hotplug FAILED'
exit 1
}
[ -x "$(which udevinfo)" ] && \
diff --git a/tools/check/check_x11_devel b/tools/check/check_x11_devel
new file mode 100755
index 0000000000..7154331000
--- /dev/null
+++ b/tools/check/check_x11_devel
@@ -0,0 +1,11 @@
+#!/bin/bash
+# CHECK-BUILD
+
+function error {
+ echo
+ echo " *** Check for x11 headers FAILED"
+ exit 1
+}
+
+set -e
+[ -e /usr/include/X11/keysymdef.h ] || error
diff --git a/tools/check/check_zlib_devel b/tools/check/check_zlib_devel
index 4986b4403e..108e06a616 100755
--- a/tools/check/check_zlib_devel
+++ b/tools/check/check_zlib_devel
@@ -1,11 +1,14 @@
-#!/bin/bash
+#!/bin/sh
# CHECK-BUILD
-function error {
- echo
- echo " *** Check for zlib headers FAILED"
- exit 1
-}
+RC=0
set -e
-[ -e /usr/include/zlib.h ] || error
+test -r /usr/include/zlib.h || RC=1
+
+if test ${RC} -ne 0; then
+ echo
+ echo " *** Check for zlib headers FAILED"
+fi
+
+exit ${RC}
diff --git a/tools/check/check_zlib_lib b/tools/check/check_zlib_lib
index 8820a30371..92d879ceda 100755
--- a/tools/check/check_zlib_lib
+++ b/tools/check/check_zlib_lib
@@ -1,11 +1,14 @@
-#!/bin/bash
+#!/bin/sh
# CHECK-BUILD CHECK-INSTALL
-function error {
- echo
- echo " *** Check for zlib library FAILED"
- exit 1
-}
+RC=0
set -e
-ldconfig -p | grep -q libz.so || error
+ldconfig -v 2>&1 | grep -q libz.so || RC=1
+
+if test ${RC} -ne 0; then
+ echo
+ echo " *** Check for zlib library FAILED"
+fi
+
+exit ${RC}
diff --git a/tools/check/chk b/tools/check/chk
index 7859760bd7..d8eb2f17e3 100755
--- a/tools/check/chk
+++ b/tools/check/chk
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/bin/sh
-function usage {
+func_usage ()
+{
echo "Usage:"
- echo "\t$0 [build|install|clean]"
+ echo " $0 [build|install|clean]"
echo
echo "Check suitability for Xen build or install."
echo "Exit with 0 if OK, 1 if not."
@@ -12,7 +13,13 @@ function usage {
exit 1
}
-export PATH=${PATH}:/sbin:/usr/sbin
+PATH=${PATH}:/sbin:/usr/sbin
+OS=`uname -s`
+export PATH OS
+
+if test "${OS}" = "SunOS"; then
+ exit 0
+fi
case $1 in
build)
@@ -25,7 +32,7 @@ case $1 in
exit 0
;;
*)
- usage
+ func_usage
;;
esac
@@ -54,4 +61,4 @@ for f in check_* ; do
fi
done
-exit $failed
+exit ${failed}
diff --git a/tools/console/Makefile b/tools/console/Makefile
index cbef956c5f..f33204cfaf 100644
--- a/tools/console/Makefile
+++ b/tools/console/Makefile
@@ -5,11 +5,7 @@ include $(XEN_ROOT)/tools/Rules.mk
DAEMON_INSTALL_DIR = /usr/sbin
CLIENT_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
-CFLAGS += -Werror -g
+CFLAGS += -Werror
CFLAGS += -I $(XEN_LIBXC)
CFLAGS += -I $(XEN_XENSTORE)
@@ -26,11 +22,11 @@ clean:
xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
$(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
- -lxenctrl -lxenstore
+ $(SOCKET_LIBS) -lxenctrl -lxenstore
xenconsole: $(patsubst %.c,%.o,$(wildcard client/*.c))
$(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_XENSTORE) \
- -lxenctrl -lxenstore
+ $(SOCKET_LIBS) -lxenctrl -lxenstore
.PHONY: install
install: $(BIN)
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 8bb18cafab..25ca40372f 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -147,7 +147,7 @@ static int domain_create_tty(struct domain *dom)
int master;
bool success;
- if ((master = getpt()) == -1 ||
+ if ((master = open("/dev/ptmx",O_RDWR|O_NOCTTY)) == -1 ||
grantpt(master) == -1 || unlockpt(master) == -1) {
dolog(LOG_ERR, "Failed to create tty for domain-%d",
dom->domid);
diff --git a/tools/console/daemon/utils.c b/tools/console/daemon/utils.c
index 40c64211d2..0801a6ccd6 100644
--- a/tools/console/daemon/utils.c
+++ b/tools/console/daemon/utils.c
@@ -95,7 +95,7 @@ void daemonize(const char *pidfile)
exit(1);
}
- len = sprintf(buf, "%d\n", getpid());
+ len = sprintf(buf, "%ld\n", (long)getpid());
if (write(fd, buf, len) < 0)
exit(1);
diff --git a/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
index c87096d1c4..8b0b6d944a 100644
--- a/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
+++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c
@@ -36,8 +36,6 @@
#include <unistd.h>
#include <errno.h>
#include <xenctrl.h>
-#include <thread_db.h>
-#include <xc_ptrace.h>
#define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */
diff --git a/tools/debugger/pdb/Domain.ml b/tools/debugger/pdb/Domain.ml
deleted file mode 100644
index dc3fd2fb30..0000000000
--- a/tools/debugger/pdb/Domain.ml
+++ /dev/null
@@ -1,61 +0,0 @@
-(** Domain.ml
- *
- * domain context implementation
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Int32
-open Intel
-
-type context_t =
-{
- mutable domain : int;
- mutable vcpu : int
-}
-
-let default_context = { domain = 0; vcpu = 0 }
-
-let new_context new_dom new_vcpu = {domain = new_dom; vcpu = new_vcpu}
-
-let set_domain ctx value =
- ctx.domain <- value
-
-let set_vcpu ctx value =
- ctx.vcpu <- value
-
-let get_domain ctx =
- ctx.domain
-
-let get_vcpu ctx =
- ctx.vcpu
-
-let string_of_context ctx =
- Printf.sprintf "{domain} domain: %d, vcpu: %d"
- ctx.domain ctx.vcpu
-
-external read_register : context_t -> int -> int32 = "dom_read_register"
-external read_registers : context_t -> registers = "dom_read_registers"
-external write_register : context_t -> register -> int32 -> unit =
- "dom_write_register"
-external read_memory : context_t -> int32 -> int -> int list =
- "dom_read_memory"
-external write_memory : context_t -> int32 -> int list -> unit =
- "dom_write_memory"
-
-external continue : context_t -> unit = "dom_continue_target"
-external step : context_t -> unit = "dom_step_target"
-
-external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
- "dom_insert_memory_breakpoint"
-external remove_memory_breakpoint : context_t -> int32 -> int -> unit =
- "dom_remove_memory_breakpoint"
-
-external attach_debugger : int -> int -> unit = "dom_attach_debugger"
-external detach_debugger : int -> int -> unit = "dom_detach_debugger"
-external pause_target : int -> unit = "dom_pause_target"
-
-let pause ctx =
- pause_target ctx.domain
diff --git a/tools/debugger/pdb/Domain.mli b/tools/debugger/pdb/Domain.mli
deleted file mode 100644
index d9cf115c4f..0000000000
--- a/tools/debugger/pdb/Domain.mli
+++ /dev/null
@@ -1,39 +0,0 @@
-(** Domain.mli
- *
- * domain context interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Int32
-open Intel
-
-type context_t
-
-val default_context : context_t
-val new_context : int -> int -> context_t
-
-val set_domain : context_t -> int -> unit
-val get_domain : context_t -> int
-val set_vcpu : context_t -> int -> unit
-val get_vcpu : context_t -> int
-
-val string_of_context : context_t -> string
-
-val read_register : context_t -> int -> int32
-val read_registers : context_t -> registers
-val write_register : context_t -> register -> int32 -> unit
-val read_memory : context_t -> int32 -> int -> int list
-val write_memory : context_t -> int32 -> int list -> unit
-
-val continue : context_t -> unit
-val step : context_t -> unit
-
-val insert_memory_breakpoint : context_t -> int32 -> int -> unit
-val remove_memory_breakpoint : context_t -> int32 -> int -> unit
-
-val attach_debugger : int -> int -> unit
-val detach_debugger : int -> int -> unit
-val pause : context_t -> unit
diff --git a/tools/debugger/pdb/Intel.ml b/tools/debugger/pdb/Intel.ml
deleted file mode 100644
index 42c493ada0..0000000000
--- a/tools/debugger/pdb/Intel.ml
+++ /dev/null
@@ -1,66 +0,0 @@
-(** Intel.ml
- *
- * various sundry Intel x86 definitions
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-
-type register =
- | EAX
- | ECX
- | EDX
- | EBX
- | ESP
- | EBP
- | ESI
- | EDI
- | EIP
- | EFL
- | CS
- | SS
- | DS
- | ES
- | FS
- | GS
-
-type registers =
- { eax : int32;
- ecx : int32;
- edx : int32;
- ebx : int32;
- esp : int32;
- ebp : int32;
- esi : int32;
- edi : int32;
- eip : int32;
- efl : int32;
- cs : int32;
- ss : int32;
- ds : int32;
- es : int32;
- fs : int32;
- gs : int32
- }
-
-let null_registers =
- { eax = 0l;
- ecx = 0l;
- edx = 0l;
- ebx = 0l;
- esp = 0l;
- ebp = 0l;
- esi = 0l;
- edi = 0l;
- eip = 0l;
- efl = 0l;
- cs = 0l;
- ss = 0l;
- ds = 0l;
- es = 0l;
- fs = 0l;
- gs = 0l
- }
-
diff --git a/tools/debugger/pdb/Makefile b/tools/debugger/pdb/Makefile
deleted file mode 100644
index 03cdc486b4..0000000000
--- a/tools/debugger/pdb/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-OCAMLMAKEFILE = OCamlMakefile
-
-XEN_ROOT = ../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-# overwrite LDFLAGS from xen/tool/Rules.mk
-# otherwise, ocamlmktop gets confused.
-LDFLAGS =
-
-# force ocaml 3.08
-OCAML_ROOT = /usr/local
-OCAMLC = $(OCAML_ROOT)/bin/ocamlc
-OCAMLMKTOP = $(OCAML_ROOT)/bin/ocamlmktop
-OCAMLLIBPATH= $(OCAML_ROOT)/lib/ocaml
-
-INCLUDES += -I $(XEN_XC)
-INCLUDES += -I $(XEN_LIBXC)
-INCLUDES += -I ../libxendebug
-INCLUDES += -I ./linux-2.6-module
-INCLUDES += -I $(OCAML_ROOT)/lib/ocaml
-
-CFLAGS += $(INCLUDES)
-CFLAGS += -Werror
-CFLAGS += -g
-
-CLIBS += xc
-CLIBS += xendebug
-
-LIBDIRS += $(XEN_LIBXC)
-LIBDIRS += ../libxendebug
-
-LIBS += unix str
-
-# bc = byte-code, dc = debug byte-code
-# patches = patch linux domU source code
-.PHONY: all
-all : dc
-
-SOURCES += pdb_caml_xc.c
-SOURCES += pdb_caml_domain.c pdb_caml_process.c
-SOURCES += pdb_caml_evtchn.c pdb_caml_xcs.c pdb_xen.c
-SOURCES += Util.ml Intel.ml
-SOURCES += evtchn.ml evtchn.mli
-SOURCES += xcs.ml xcs.mli
-SOURCES += Xen_domain.ml Xen_domain.mli
-SOURCES += Domain.ml Process.ml
-SOURCES += Domain.mli Process.mli
-SOURCES += PDB.ml debugger.ml server.ml
-
-RESULT = pdb
-
-include $(OCAMLMAKEFILE)
-
-PATCHDIR = ./linux-2.6-patches
-.PHONY: patches
-patches :
- make -C $(PATCHDIR) patches
diff --git a/tools/debugger/pdb/OCamlMakefile b/tools/debugger/pdb/OCamlMakefile
deleted file mode 100644
index 0c6d23ab00..0000000000
--- a/tools/debugger/pdb/OCamlMakefile
+++ /dev/null
@@ -1,1149 +0,0 @@
-###########################################################################
-# OCamlMakefile
-# Copyright (C) 1999-2004 Markus Mottl
-#
-# For updates see:
-# http://www.oefai.at/~markus/ocaml_sources
-#
-# $Id: OCamlMakefile,v 1.1 2005/05/19 09:30:48 root Exp $
-#
-###########################################################################
-
-# Modified by damien for .glade.ml compilation
-
-# Set these variables to the names of the sources to be processed and
-# the result variable. Order matters during linkage!
-
-ifndef SOURCES
- SOURCES := foo.ml
-endif
-export SOURCES
-
-ifndef RES_CLIB_SUF
- RES_CLIB_SUF := _stubs
-endif
-export RES_CLIB_SUF
-
-ifndef RESULT
- RESULT := foo
-endif
-export RESULT
-
-export LIB_PACK_NAME
-
-ifndef DOC_FILES
- DOC_FILES := $(filter %.mli, $(SOURCES))
-endif
-export DOC_FILES
-
-export BCSUFFIX
-export NCSUFFIX
-
-ifndef TOPSUFFIX
- TOPSUFFIX := .top
-endif
-export TOPSUFFIX
-
-# Eventually set include- and library-paths, libraries to link,
-# additional compilation-, link- and ocamlyacc-flags
-# Path- and library information needs not be written with "-I" and such...
-# Define THREADS if you need it, otherwise leave it unset (same for
-# USE_CAMLP4)!
-
-export THREADS
-export VMTHREADS
-export ANNOTATE
-export USE_CAMLP4
-
-export INCDIRS
-export LIBDIRS
-export EXTLIBDIRS
-export RESULTDEPS
-export OCAML_DEFAULT_DIRS
-
-export LIBS
-export CLIBS
-
-export OCAMLFLAGS
-export OCAMLNCFLAGS
-export OCAMLBCFLAGS
-
-export OCAMLLDFLAGS
-export OCAMLNLDFLAGS
-export OCAMLBLDFLAGS
-
-ifndef OCAMLCPFLAGS
- OCAMLCPFLAGS := a
-endif
-
-export OCAMLCPFLAGS
-
-export PPFLAGS
-
-export YFLAGS
-export IDLFLAGS
-
-export OCAMLDOCFLAGS
-
-export OCAMLFIND_INSTFLAGS
-
-export DVIPSFLAGS
-
-export STATIC
-
-# Add a list of optional trash files that should be deleted by "make clean"
-export TRASH
-
-#################### variables depending on your OCaml-installation
-
-ifdef MINGW
- export MINGW
- WIN32 := 1
- CFLAGS_WIN32 := -mno-cygwin
-endif
-ifdef MSVC
- export MSVC
- WIN32 := 1
- ifndef STATIC
- CPPFLAGS_WIN32 := -DCAML_DLL
- endif
- CFLAGS_WIN32 += -nologo
- EXT_OBJ := obj
- EXT_LIB := lib
- ifeq ($(CC),gcc)
- # work around GNU Make default value
- ifdef THREADS
- CC := cl -MT
- else
- CC := cl
- endif
- endif
- ifeq ($(CXX),g++)
- # work around GNU Make default value
- CXX := $(CC)
- endif
- CFLAG_O := -Fo
-endif
-ifdef WIN32
- EXT_CXX := cpp
- EXE := .exe
-endif
-
-ifndef EXT_OBJ
- EXT_OBJ := o
-endif
-ifndef EXT_LIB
- EXT_LIB := a
-endif
-ifndef EXT_CXX
- EXT_CXX := cc
-endif
-ifndef EXE
- EXE := # empty
-endif
-ifndef CFLAG_O
- CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)!
-endif
-
-export CC
-export CXX
-export CFLAGS
-export CXXFLAGS
-export LDFLAGS
-export CPPFLAGS
-
-ifndef RPATH_FLAG
- RPATH_FLAG := -R
-endif
-export RPATH_FLAG
-
-ifndef MSVC
-ifndef PIC_CFLAGS
- PIC_CFLAGS := -fPIC
-endif
-ifndef PIC_CPPFLAGS
- PIC_CPPFLAGS := -DPIC
-endif
-endif
-
-export PIC_CFLAGS
-export PIC_CPPFLAGS
-
-BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT))
-NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT))
-TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT))
-
-ifndef OCAMLFIND
- OCAMLFIND := ocamlfind
-endif
-export OCAMLFIND
-
-ifndef OCAMLC
- OCAMLC := ocamlc
-endif
-export OCAMLC
-
-ifndef OCAMLOPT
- OCAMLOPT := ocamlopt
-endif
-export OCAMLOPT
-
-ifndef OCAMLMKTOP
- OCAMLMKTOP := ocamlmktop
-endif
-export OCAMLMKTOP
-
-ifndef OCAMLCP
- OCAMLCP := ocamlcp
-endif
-export OCAMLCP
-
-ifndef OCAMLDEP
- OCAMLDEP := ocamldep
-endif
-export OCAMLDEP
-
-ifndef OCAMLLEX
- OCAMLLEX := ocamllex
-endif
-export OCAMLLEX
-
-ifndef OCAMLYACC
- OCAMLYACC := ocamlyacc
-endif
-export OCAMLYACC
-
-ifndef OCAMLMKLIB
- OCAMLMKLIB := ocamlmklib
-endif
-export OCAMLMKLIB
-
-ifndef OCAML_GLADECC
- OCAML_GLADECC := lablgladecc2
-endif
-export OCAML_GLADECC
-
-ifndef OCAML_GLADECC_FLAGS
- OCAML_GLADECC_FLAGS :=
-endif
-export OCAML_GLADECC_FLAGS
-
-ifndef CAMELEON_REPORT
- CAMELEON_REPORT := report
-endif
-export CAMELEON_REPORT
-
-ifndef CAMELEON_REPORT_FLAGS
- CAMELEON_REPORT_FLAGS :=
-endif
-export CAMELEON_REPORT_FLAGS
-
-ifndef CAMELEON_ZOGGY
- CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo
-endif
-export CAMELEON_ZOGGY
-
-ifndef CAMELEON_ZOGGY_FLAGS
- CAMELEON_ZOGGY_FLAGS :=
-endif
-export CAMELEON_ZOGGY_FLAGS
-
-ifndef OXRIDL
- OXRIDL := oxridl
-endif
-export OXRIDL
-
-ifndef CAMLIDL
- CAMLIDL := camlidl
-endif
-export CAMLIDL
-
-ifndef CAMLIDLDLL
- CAMLIDLDLL := camlidldll
-endif
-export CAMLIDLDLL
-
-ifndef NOIDLHEADER
- MAYBE_IDL_HEADER := -header
-endif
-export NOIDLHEADER
-
-export NO_CUSTOM
-
-ifndef CAMLP4
- CAMLP4 := camlp4
-endif
-export CAMLP4
-
-ifndef REAL_OCAMLFIND
- ifdef PACKS
- ifndef CREATE_LIB
- ifdef THREADS
- PACKS += threads
- endif
- endif
- empty :=
- space := $(empty) $(empty)
- comma := ,
- ifdef PREDS
- PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS))
- PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS))
- OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES)
- # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES)
- OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
- OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
- else
- OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS))
- OCAML_DEP_PACKAGES :=
- endif
- OCAML_FIND_LINKPKG := -linkpkg
- REAL_OCAMLFIND := $(OCAMLFIND)
- endif
-endif
-
-export OCAML_FIND_PACKAGES
-export OCAML_DEP_PACKAGES
-export OCAML_FIND_LINKPKG
-export REAL_OCAMLFIND
-
-ifndef OCAMLDOC
- OCAMLDOC := ocamldoc
-endif
-export OCAMLDOC
-
-ifndef LATEX
- LATEX := latex
-endif
-export LATEX
-
-ifndef DVIPS
- DVIPS := dvips
-endif
-export DVIPS
-
-ifndef PS2PDF
- PS2PDF := ps2pdf
-endif
-export PS2PDF
-
-ifndef OCAMLMAKEFILE
- OCAMLMAKEFILE := OCamlMakefile
-endif
-export OCAMLMAKEFILE
-
-ifndef OCAMLLIBPATH
- OCAMLLIBPATH := \
- $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml)
-endif
-export OCAMLLIBPATH
-
-ifndef OCAML_LIB_INSTALL
- OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib
-endif
-export OCAML_LIB_INSTALL
-
-###########################################################################
-
-#################### change following sections only if
-#################### you know what you are doing!
-
-# delete target files when a build command fails
-.PHONY: .DELETE_ON_ERROR
-.DELETE_ON_ERROR:
-
-# for pedants using "--warn-undefined-variables"
-export MAYBE_IDL
-export REAL_RESULT
-export CAMLIDLFLAGS
-export THREAD_FLAG
-export RES_CLIB
-export MAKEDLL
-export ANNOT_FLAG
-export C_OXRIDL
-export SUBPROJS
-export CFLAGS_WIN32
-export CPPFLAGS_WIN32
-
-INCFLAGS :=
-
-SHELL := /bin/sh
-
-MLDEPDIR := ._d
-BCDIDIR := ._bcdi
-NCDIDIR := ._ncdi
-
-FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.$(EXT_CXX) %.rep %.zog %.glade
-
-FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES))
-SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED))))
-
-FILTERED_REP := $(filter %.rep, $(FILTERED))
-DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d)
-AUTO_REP := $(FILTERED_REP:.rep=.ml)
-
-FILTERED_ZOG := $(filter %.zog, $(FILTERED))
-DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d)
-AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml)
-
-FILTERED_GLADE := $(filter %.glade, $(FILTERED))
-DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d)
-AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml)
-
-FILTERED_ML := $(filter %.ml, $(FILTERED))
-DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d)
-
-FILTERED_MLI := $(filter %.mli, $(FILTERED))
-DEP_MLI := $(FILTERED_MLI:.mli=.di)
-
-FILTERED_MLL := $(filter %.mll, $(FILTERED))
-DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d)
-AUTO_MLL := $(FILTERED_MLL:.mll=.ml)
-
-FILTERED_MLY := $(filter %.mly, $(FILTERED))
-DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di)
-AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml)
-
-FILTERED_IDL := $(filter %.idl, $(FILTERED))
-DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di)
-C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c)
-ifndef NOIDLHEADER
- C_IDL += $(FILTERED_IDL:.idl=.h)
-endif
-OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ))
-AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL)
-
-FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED))
-DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di)
-AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL)
-
-FILTERED_C_CXX := $(filter %.c %.$(EXT_CXX), $(FILTERED))
-OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ))
-OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ))
-
-PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE)
-
-ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE)
-
-MLDEPS := $(filter %.d, $(ALL_DEPS))
-MLIDEPS := $(filter %.di, $(ALL_DEPS))
-BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di)
-NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di)
-
-ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED))
-
-IMPLO_INTF := $(ALLML:%.mli=%.mli.__)
-IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \
- $(basename $(file)).cmi $(basename $(file)).cmo)
-IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF))
-IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi)
-
-IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx)
-
-INTF := $(filter %.cmi, $(IMPLO_INTF))
-IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF))
-IMPL_CMX := $(IMPL_CMO:.cmo=.cmx)
-IMPL_ASM := $(IMPL_CMO:.cmo=.asm)
-IMPL_S := $(IMPL_CMO:.cmo=.s)
-
-OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX)
-OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK)
-
-EXECS := $(addsuffix $(EXE), \
- $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT)))
-ifdef WIN32
- EXECS += $(BCRESULT).dll $(NCRESULT).dll
-endif
-
-CLIB_BASE := $(RESULT)$(RES_CLIB_SUF)
-ifneq ($(strip $(OBJ_LINK)),)
- RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB)
-endif
-
-ifdef WIN32
-DLLSONAME := $(CLIB_BASE).dll
-else
-DLLSONAME := dll$(CLIB_BASE).so
-endif
-
-NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \
- $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \
- $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \
- $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \
- $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \
- $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o
-
-ifndef STATIC
- NONEXECS += $(DLLSONAME)
-endif
-
-ifndef LIBINSTALL_FILES
- LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \
- $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB)
- ifndef STATIC
- ifneq ($(strip $(OBJ_LINK)),)
- LIBINSTALL_FILES += $(DLLSONAME)
- endif
- endif
-endif
-
-export LIBINSTALL_FILES
-
-ifdef WIN32
- # some extra stuff is created while linking DLLs
- NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib
-endif
-
-TARGETS := $(EXECS) $(NONEXECS)
-
-# If there are IDL-files
-ifneq ($(strip $(FILTERED_IDL)),)
- MAYBE_IDL := -cclib -lcamlidl
-endif
-
-ifdef USE_CAMLP4
- CAMLP4PATH := \
- $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4)
- INCFLAGS := -I $(CAMLP4PATH)
- CINCFLAGS := -I$(CAMLP4PATH)
-endif
-
-DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %)
-INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %)
-CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%)
-
-ifndef MSVC
-CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \
- $(EXTLIBDIRS:%=-L%) $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) \
- $(OCAML_DEFAULT_DIRS:%=-L%)
-endif
-
-ifndef PROFILING
- INTF_OCAMLC := $(OCAMLC)
-else
- ifndef THREADS
- INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS)
- else
- # OCaml does not support profiling byte code
- # with threads (yet), therefore we force an error.
- ifndef REAL_OCAMLC
- $(error Profiling of multithreaded byte code not yet supported by OCaml)
- endif
- INTF_OCAMLC := $(OCAMLC)
- endif
-endif
-
-ifndef MSVC
-COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \
- $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \
- $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) \
- $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)
-else
-COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \
- $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \
- $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) "
-endif
-
-CLIBS_OPTS := $(CLIBS:%=-cclib -l%)
-ifdef MSVC
- ifndef STATIC
- # MSVC libraries do not have 'lib' prefix
- CLIBS_OPTS := $(CLIBS:%=-cclib %.lib)
- endif
-endif
-
-ifneq ($(strip $(OBJ_LINK)),)
- ifdef CREATE_LIB
- OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL)
- else
- OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL)
- endif
-else
- OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL)
-endif
-
-# If we have to make byte-code
-ifndef REAL_OCAMLC
- BYTE_OCAML := y
-
- # EXTRADEPS is added dependencies we have to insert for all
- # executable files we generate. Ideally it should be all of the
- # libraries we use, but it's hard to find the ones that get searched on
- # the path since I don't know the paths built into the compiler, so
- # just include the ones with slashes in their names.
- EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
- SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS)
-
- REAL_OCAMLC := $(INTF_OCAMLC)
-
- REAL_IMPL := $(IMPL_CMO)
- REAL_IMPL_INTF := $(IMPLO_INTF)
- IMPL_SUF := .cmo
-
- DEPFLAGS :=
- MAKE_DEPS := $(MLDEPS) $(BCDEPIS)
-
- ifdef CREATE_LIB
- CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
- CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
- ifndef STATIC
- ifneq ($(strip $(OBJ_LINK)),)
- MAKEDLL := $(DLLSONAME)
- ALL_LDFLAGS := -dllib $(DLLSONAME)
- endif
- endif
- endif
-
- ifndef NO_CUSTOM
- ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS))" ""
- ALL_LDFLAGS += -custom
- endif
- endif
-
- ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \
- $(COMMON_LDFLAGS) $(LIBS:%=%.cma)
- CAMLIDLDLLFLAGS :=
-
- ifdef THREADS
- ifdef VMTHREADS
- THREAD_FLAG := -vmthread
- else
- THREAD_FLAG := -thread
- endif
- ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
- ifndef CREATE_LIB
- ifndef REAL_OCAMLFIND
- ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS)
- endif
- endif
- endif
-
-# we have to make native-code
-else
- EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
- ifndef PROFILING
- SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
- PLDFLAGS :=
- else
- SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS)
- PLDFLAGS := -p
- endif
-
- REAL_IMPL := $(IMPL_CMX)
- REAL_IMPL_INTF := $(IMPLX_INTF)
- IMPL_SUF := .cmx
-
- CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS)
-
- DEPFLAGS := -native
- MAKE_DEPS := $(MLDEPS) $(NCDEPIS)
-
- ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \
- $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS)
- CAMLIDLDLLFLAGS := -opt
-
- ifndef CREATE_LIB
- ALL_LDFLAGS += $(LIBS:%=%.cmxa)
- else
- CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
- CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
- endif
-
- ifdef THREADS
- THREAD_FLAG := -thread
- ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
- ifndef CREATE_LIB
- ifndef REAL_OCAMLFIND
- ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS)
- endif
- endif
- endif
-endif
-
-export MAKE_DEPS
-
-ifdef ANNOTATE
- ANNOT_FLAG := -dtypes
-else
-endif
-
-ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \
- $(INCFLAGS) $(SPECIAL_OCAMLFLAGS)
-
-ifdef make_deps
- -include $(MAKE_DEPS)
- PRE_TARGETS :=
-endif
-
-###########################################################################
-# USER RULES
-
-# Call "OCamlMakefile QUIET=" to get rid of all of the @'s.
-QUIET=@
-
-# generates byte-code (default)
-byte-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
- REAL_RESULT="$(BCRESULT)" make_deps=yes
-bc: byte-code
-
-byte-code-nolink: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
- REAL_RESULT="$(BCRESULT)" make_deps=yes
-bcnl: byte-code-nolink
-
-top: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \
- REAL_RESULT="$(BCRESULT)" make_deps=yes
-
-# generates native-code
-
-native-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- make_deps=yes
-nc: native-code
-
-native-code-nolink: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- make_deps=yes
-ncnl: native-code-nolink
-
-# generates byte-code libraries
-byte-code-library: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(BCRESULT).cma \
- REAL_RESULT="$(BCRESULT)" \
- CREATE_LIB=yes \
- make_deps=yes
-bcl: byte-code-library
-
-# generates native-code libraries
-native-code-library: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(NCRESULT).cmxa \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- CREATE_LIB=yes \
- make_deps=yes
-ncl: native-code-library
-
-ifdef WIN32
-# generates byte-code dll
-byte-code-dll: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(BCRESULT).dll \
- REAL_RESULT="$(BCRESULT)" \
- make_deps=yes
-bcd: byte-code-dll
-
-# generates native-code dll
-native-code-dll: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(NCRESULT).dll \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- make_deps=yes
-ncd: native-code-dll
-endif
-
-# generates byte-code with debugging information
-debug-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
- REAL_RESULT="$(BCRESULT)" make_deps=yes \
- OCAMLFLAGS="-g $(OCAMLFLAGS)" \
- OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dc: debug-code
-
-debug-code-nolink: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
- REAL_RESULT="$(BCRESULT)" make_deps=yes \
- OCAMLFLAGS="-g $(OCAMLFLAGS)" \
- OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dcnl: debug-code-nolink
-
-# generates byte-code libraries with debugging information
-debug-code-library: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(BCRESULT).cma \
- REAL_RESULT="$(BCRESULT)" make_deps=yes \
- CREATE_LIB=yes \
- OCAMLFLAGS="-g $(OCAMLFLAGS)" \
- OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
-dcl: debug-code-library
-
-# generates byte-code for profiling
-profiling-byte-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
- REAL_RESULT="$(BCRESULT)" PROFILING="y" \
- make_deps=yes
-pbc: profiling-byte-code
-
-# generates native-code
-
-profiling-native-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- PROFILING="y" \
- make_deps=yes
-pnc: profiling-native-code
-
-# generates byte-code libraries
-profiling-byte-code-library: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(BCRESULT).cma \
- REAL_RESULT="$(BCRESULT)" PROFILING="y" \
- CREATE_LIB=yes \
- make_deps=yes
-pbcl: profiling-byte-code-library
-
-# generates native-code libraries
-profiling-native-code-library: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(RES_CLIB) $(NCRESULT).cmxa \
- REAL_RESULT="$(NCRESULT)" PROFILING="y" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- CREATE_LIB=yes \
- make_deps=yes
-pncl: profiling-native-code-library
-
-# packs byte-code objects
-pack-byte-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \
- REAL_RESULT="$(BCRESULT)" \
- PACK_LIB=yes make_deps=yes
-pabc: pack-byte-code
-
-# packs native-code objects
-pack-native-code: $(PRE_TARGETS)
- $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
- $(NCRESULT).cmx $(NCRESULT).o \
- REAL_RESULT="$(NCRESULT)" \
- REAL_OCAMLC="$(OCAMLOPT)" \
- PACK_LIB=yes make_deps=yes
-panc: pack-native-code
-
-# generates HTML-documentation
-htdoc: doc/$(RESULT)/html
-
-# generates Latex-documentation
-ladoc: doc/$(RESULT)/latex
-
-# generates PostScript-documentation
-psdoc: doc/$(RESULT)/latex/doc.ps
-
-# generates PDF-documentation
-pdfdoc: doc/$(RESULT)/latex/doc.pdf
-
-# generates all supported forms of documentation
-doc: htdoc ladoc psdoc pdfdoc
-
-###########################################################################
-# LOW LEVEL RULES
-
-$(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) \
- $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
- $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
- $(REAL_IMPL)
-
-nolink: $(REAL_IMPL_INTF) $(OBJ_LINK)
-
-ifdef WIN32
-$(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK)
- $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \
- -o $@ $(REAL_IMPL)
-endif
-
-%$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
- $(REAL_OCAMLFIND) $(OCAMLMKTOP) \
- $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
- $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
- $(REAL_IMPL)
-
-.SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \
- .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .$(EXT_CXX) .h .so \
- .rep .zog .glade
-
-ifndef STATIC
-ifdef MINGW
-$(DLLSONAME): $(OBJ_LINK)
- $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \
- -Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \
- $(OCAMLLIBPATH)/ocamlrun.a \
- -Wl,--export-all-symbols \
- -Wl,--no-whole-archive
-else
-ifdef MSVC
-$(DLLSONAME): $(OBJ_LINK)
- link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \
- $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \
- $(OCAMLLIBPATH)/ocamlrun.lib
-
-else
-$(DLLSONAME): $(OBJ_LINK)
- $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
- -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \
- $(OCAMLMKLIB_FLAGS)
-endif
-endif
-endif
-
-ifndef LIB_PACK_NAME
-$(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
- $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(REAL_IMPL)
-
-$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS)
- $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
- $(OCAMLNLDFLAGS) -o $@ $(REAL_IMPL)
-else
-ifdef BYTE_OCAML
-$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(REAL_IMPL)
-else
-$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmx $(REAL_IMPL)
-endif
-
-$(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
- $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(LIB_PACK_NAME).cmo
-
-$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS)
- $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
- $(OCAMLNLDFLAGS) -o $@ $(LIB_PACK_NAME).cmx
-endif
-
-$(RES_CLIB): $(OBJ_LINK)
-ifndef MSVC
- ifneq ($(strip $(OBJ_LINK)),)
- $(AR) rcs $@ $(OBJ_LINK)
- endif
-else
- ifneq ($(strip $(OBJ_LINK)),)
- lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK)
- endif
-endif
-
-.mli.cmi: $(EXTRADEPS)
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c $(THREAD_FLAG) $(ANNOT_FLAG) \
- $(OCAMLFLAGS) $(INCFLAGS) $<; \
- $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c $(THREAD_FLAG) $(ANNOT_FLAG) \
- $(OCAMLFLAGS) $(INCFLAGS) $<; \
- else \
- echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \
- $(OCAMLFLAGS) $(INCFLAGS) $<; \
- $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \
- $(OCAMLFLAGS) $(INCFLAGS) $<; \
- fi
-
-.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS)
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c $(ALL_OCAMLCFLAGS) $<; \
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c $(ALL_OCAMLCFLAGS) $<; \
- else \
- echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
- -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \
- fi
-
-ifdef PACK_LIB
-$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
- $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \
- $(OBJS_LIBS) -o $@ $(REAL_IMPL)
-endif
-
-.PRECIOUS: %.ml
-%.ml: %.mll
- $(OCAMLLEX) $<
-
-.PRECIOUS: %.ml %.mli
-%.ml %.mli: %.mly
- $(OCAMLYACC) $(YFLAGS) $<
- $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \
- if [ ! -z "$$pp" ]; then \
- mv $*.ml $*.ml.temporary; \
- echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \
- cat $*.ml.temporary >> $*.ml; \
- rm $*.ml.temporary; \
- mv $*.mli $*.mli.temporary; \
- echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \
- cat $*.mli.temporary >> $*.mli; \
- rm $*.mli.temporary; \
- fi
-
-
-.PRECIOUS: %.ml
-%.ml: %.rep
- $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $<
-
-.PRECIOUS: %.ml
-%.ml: %.zog
- $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@
-
-.PRECIOUS: %.ml
-%.ml: %.glade
- $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@
-
-.PRECIOUS: %.ml %.mli
-%.ml %.mli: %.oxridl
- $(OXRIDL) $<
-
-.PRECIOUS: %.ml %.mli %_stubs.c %.h
-%.ml %.mli %_stubs.c %.h: %.idl
- $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \
- $(CAMLIDLFLAGS) $<
- $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi
-
-.c.$(EXT_OBJ):
- $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \
- $(CPPFLAGS) $(CPPFLAGS_WIN32) \
- $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $<
-
-.$(EXT_CXX).$(EXT_OBJ):
- $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
- -I'$(OCAMLLIBPATH)' \
- $< $(CFLAG_O)$@
-
-$(MLDEPDIR)/%.d: %.ml
- $(QUIET)echo making $@ from $<
- $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
- $(DINCFLAGS) $< > $@; \
- else \
- $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
- -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
- fi
-
-$(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli
- $(QUIET)echo making $@ from $<
- $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \
- else \
- $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
- -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
- fi
-
-doc/$(RESULT)/html: $(DOC_FILES)
- rm -rf $@
- mkdir -p $@
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- echo $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
- $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
- else \
- echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -html -d $@ $(OCAMLDOCFLAGS) \
- $(INCFLAGS) $(DOC_FILES); \
- $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -html -d $@ $(OCAMLDOCFLAGS) \
- $(INCFLAGS) $(DOC_FILES); \
- fi
-
-doc/$(RESULT)/latex: $(DOC_FILES)
- rm -rf $@
- mkdir -p $@
- $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
- if [ -z "$$pp" ]; then \
- echo $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \
- $(DOC_FILES) -o $@/doc.tex; \
- $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \
- -o $@/doc.tex; \
- else \
- echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \
- $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
- $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \
- $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
- fi
-
-doc/$(RESULT)/latex/doc.ps: doc/$(RESULT)/latex
- cd doc/$(RESULT)/latex && \
- $(LATEX) doc.tex && \
- $(LATEX) doc.tex && \
- $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F)
-
-doc/$(RESULT)/latex/doc.pdf: doc/$(RESULT)/latex/doc.ps
- cd doc/$(RESULT)/latex && $(PS2PDF) $(<F)
-
-define make_subproj
-.PHONY:
-subproj_$(1):
- $$(eval $$(call PROJ_$(1)))
- $(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \
- $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \
- fi
-endef
-
-$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj))))
-
-.PHONY:
-subprojs: $(SUBPROJS:%=subproj_%)
-
-###########################################################################
-# (UN)INSTALL RULES FOR LIBRARIES
-
-.PHONY: libinstall
-libinstall: all
- $(QUIET)printf "\nInstalling library with ocamlfind\n"
- $(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES)
- $(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: libuninstall
-libuninstall:
- $(QUIET)printf "\nUninstalling library with ocamlfind\n"
- $(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT)
- $(QUIET)printf "\nUninstallation successful.\n"
-
-.PHONY: rawinstall
-rawinstall: all
- $(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n"
- -install -d $(OCAML_LIB_INSTALL)
- for i in $(LIBINSTALL_FILES); do \
- if [ -f $$i ]; then \
- install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \
- fi; \
- done
- $(QUIET)printf "\nInstallation successful.\n"
-
-.PHONY: rawuninstall
-rawuninstall:
- $(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n"
- cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES))
- $(QUIET)printf "\nUninstallation successful.\n"
-
-###########################################################################
-# MAINTAINANCE RULES
-
-.PHONY: clean
-clean::
- rm -f $(TARGETS) $(TRASH)
- rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
-
-.PHONY: cleanup
-cleanup::
- rm -f $(NONEXECS) $(TRASH)
- rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
-
-.PHONY: clean-doc
-clean-doc::
- rm -rf doc
-
-.PHONY: nobackup
-nobackup:
- rm -f *.bak *~ *.dup
diff --git a/tools/debugger/pdb/PDB.ml b/tools/debugger/pdb/PDB.ml
deleted file mode 100644
index da9ad7d2c6..0000000000
--- a/tools/debugger/pdb/PDB.ml
+++ /dev/null
@@ -1,342 +0,0 @@
-(** PDB.ml
- *
- * Dispatch debugger commands to the appropriate context
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Util
-
-exception Unimplemented of string
-exception Unknown_context of string
-exception Unknown_domain
-exception Unknown_process
-
-type context_t =
- | Void
- | Xen_virq
- | Xen_xcs
- | Xen_domain of Xen_domain.context_t
- | Domain of Domain.context_t
- | Process of Process.context_t
-
-let string_of_context ctx =
- match ctx with
- | Void -> "{void}"
- | Xen_virq -> "{Xen virq evtchn}"
- | Xen_xcs -> "{Xen xcs socket}"
- | Xen_domain d -> Xen_domain.string_of_context d
- | Domain d -> Domain.string_of_context d
- | Process p -> Process.string_of_context p
-
-
-let hash = Hashtbl.create 10
-
-
-(***************************************************************************)
-
-let find_context key =
- try
- Hashtbl.find hash key
- with
- Not_found ->
- print_endline "error: (find_context) PDB context not found";
- raise Not_found
-
-let delete_context key =
- Hashtbl.remove hash key
-
-
-(**
- find_process : Locate the socket associated with the context(s)
- matching a particular (domain, process id) pair. if there are multiple
- contexts (there shouldn't be), then return the first one.
- *)
-
-let find_process dom pid =
- let find key ctx list =
- match ctx with
- | Process p ->
- if (((Process.get_domain p) = dom) &&
- ((Process.get_process p) = pid))
- then
- key :: list
- else
- list
- | _ -> list
- in
- let sock_list = Hashtbl.fold find hash [] in
- match sock_list with
- | hd::tl -> hd
- | [] -> raise Unknown_process
-
-
-(**
- find_domain : Locate the socket associated with the context(s)
- matching a particular (domain, vcpu) pair. if there are multiple
- contexts (there shouldn't be), then return the first one.
- *)
-
-let find_domain dom vcpu =
- let find key ctx list =
- match ctx with
- | Domain d ->
- if (((Domain.get_domain d) = dom) &&
- ((Domain.get_vcpu d) = vcpu))
- then
- key :: list
- else
- list
- | _ -> list
- in
- let sock_list = Hashtbl.fold find hash [] in
- match sock_list with
- | hd::tl -> hd
- | [] -> raise Unknown_domain
-
-(**
- find_xen_domain_context : fetch the socket associated with the
- xen_domain context for a domain. if there are multiple contexts
- (there shouldn't be), then return the first one.
- *)
-
-let find_xen_domain_context domain =
- let find key ctx list =
- match ctx with
- | Xen_domain d ->
- if ((Xen_domain.get_domain d) = domain)
- then
- key :: list
- else
- list
- | _ -> list
- in
- let sock_list = Hashtbl.fold find hash [] in
- match sock_list with
- | hd::tl -> hd
- | [] -> raise Unknown_domain
-
-let attach_debugger ctx =
- match ctx with
- | Domain d -> Domain.attach_debugger (Domain.get_domain d)
- (Domain.get_vcpu d)
- | Process p ->
- begin
- let xdom_sock = find_xen_domain_context (Process.get_domain p) in
- let xdom_ctx = find_context xdom_sock in
- begin
- match xdom_ctx with
- | Xen_domain d ->
- Process.attach_debugger p d
- | _ -> failwith ("context has wrong xen domain type")
- end;
- raise No_reply
- end
- | _ -> raise (Unimplemented "attach debugger")
-
-let detach_debugger ctx =
- match ctx with
- | Domain d ->
- Domain.detach_debugger (Domain.get_domain d)
- (Domain.get_vcpu d);
- "OK"
- | Process p ->
- Process.detach_debugger p;
- raise No_reply
- | _ -> raise (Unimplemented "detach debugger")
-
-
-let debug_contexts () =
- print_endline "context list:";
- let print_context key ctx =
- match ctx with
- | Void -> print_endline (Printf.sprintf " [%s] {void}"
- (Util.get_connection_info key))
- | Xen_virq -> print_endline (Printf.sprintf " [%s] {xen virq evtchn}"
- (Util.get_connection_info key))
- | Xen_xcs -> print_endline (Printf.sprintf " [%s] {xen xcs socket}"
- (Util.get_connection_info key))
- | Xen_domain d -> print_endline (Printf.sprintf " [%s] %s"
- (Util.get_connection_info key)
- (Xen_domain.string_of_context d))
- | Domain d -> print_endline (Printf.sprintf " [%s] %s"
- (Util.get_connection_info key)
- (Domain.string_of_context d))
- | Process p -> print_endline (Printf.sprintf " [%s] %s"
- (Util.get_connection_info key)
- (Process.string_of_context p))
- in
- Hashtbl.iter print_context hash
-
-(** add_context : add a new context to the hash table.
- * if there is an existing context for the same key then it
- * is first removed implictly by the hash table replace function.
- *)
-let add_context (key:Unix.file_descr) context params =
- match context with
- | "void" -> Hashtbl.replace hash key Void
- | "xen virq" -> Hashtbl.replace hash key Xen_virq
- | "xen xcs" -> Hashtbl.replace hash key Xen_xcs
- | "domain" ->
- begin
- match params with
- | dom::vcpu::_ ->
- let d = Domain(Domain.new_context dom vcpu) in
- attach_debugger d;
- Hashtbl.replace hash key d
- | _ -> failwith "bogus parameters to domain context"
- end
- | "process" ->
- begin
- match params with
- | dom::pid::_ ->
- let p = Process(Process.new_context dom pid) in
- Hashtbl.replace hash key p;
- attach_debugger p
- | _ -> failwith "bogus parameters to process context"
- end
- | "xen domain"
- | _ -> raise (Unknown_context context)
-
-(*
- * this is really bogus. add_xen_domain_context should really
- * be a case within add_context. however, we need to pass in
- * a pointer that can only be represented as an int32.
- * this would require a different type for params... :(
- * 31 bit integers suck.
- *)
-let add_xen_domain_context (key:Unix.file_descr) dom evtchn sring =
- let d = Xen_domain.new_context dom evtchn sring in
- Hashtbl.replace hash key (Xen_domain(d))
-
-
-let add_default_context sock =
- add_context sock "void" []
-
-(***************************************************************************)
-
-(***************************************************************************)
-
-let read_register ctx register = (* register is int32 because of sscanf *)
- match ctx with
- | Void -> 0l (* default for startup *)
- | Domain d -> Domain.read_register d register
- | Process p ->
- begin
- Process.read_register p register;
- raise No_reply
- end
- | _ -> raise (Unimplemented "read registers")
-
-let read_registers ctx =
- match ctx with
- | Void -> Intel.null_registers (* default for startup *)
- | Domain d -> Domain.read_registers d
- | Process p ->
- begin
- Process.read_registers p;
- raise No_reply
- end
- | _ -> raise (Unimplemented "read registers")
-
-let write_register ctx register value =
- match ctx with
- | Domain d -> Domain.write_register d register value
- | Process p ->
- begin
- Process.write_register p register value;
- raise No_reply
- end
- | _ -> raise (Unimplemented "write register")
-
-
-let read_memory ctx addr len =
- match ctx with
- | Domain d -> Domain.read_memory d addr len
- | Process p ->
- begin
- Process.read_memory p addr len;
- raise No_reply
- end
- | _ -> raise (Unimplemented "read memory")
-
-let write_memory ctx addr values =
- match ctx with
- | Domain d -> Domain.write_memory d addr values
- | Process p ->
- begin
- Process.write_memory p addr values;
- raise No_reply
- end
- | _ -> raise (Unimplemented "write memory")
-
-
-let continue ctx =
- match ctx with
- | Domain d -> Domain.continue d
- | Process p -> Process.continue p
- | _ -> raise (Unimplemented "continue")
-
-let step ctx =
- match ctx with
- | Domain d -> Domain.step d
- | Process p -> Process.step p
- | _ -> raise (Unimplemented "step")
-
-
-let insert_memory_breakpoint ctx addr len =
- match ctx with
- | Domain d -> Domain.insert_memory_breakpoint d addr len
- | Process p ->
- begin
- Process.insert_memory_breakpoint p addr len;
- raise No_reply
- end
- | _ -> raise (Unimplemented "insert memory breakpoint")
-
-let remove_memory_breakpoint ctx addr len =
- match ctx with
- | Domain d -> Domain.remove_memory_breakpoint d addr len
- | Process p ->
- begin
- Process.remove_memory_breakpoint p addr len;
- raise No_reply
- end
- | _ -> raise (Unimplemented "remove memory breakpoint")
-
-let insert_watchpoint ctx kind addr len =
- match ctx with
-(* | Domain d -> Domain.insert_watchpoint d kind addr len TODO *)
- | Process p ->
- begin
- Process.insert_watchpoint p kind addr len;
- raise No_reply
- end
- | _ -> raise (Unimplemented "insert watchpoint")
-
-let remove_watchpoint ctx kind addr len =
- match ctx with
-(* | Domain d -> Domain.remove_watchpoint d kind addr len TODO *)
- | Process p ->
- begin
- Process.remove_watchpoint p kind addr len;
- raise No_reply
- end
- | _ -> raise (Unimplemented "remove watchpoint")
-
-
-let pause ctx =
- match ctx with
- | Domain d -> Domain.pause d
- | Process p -> Process.pause p
- | _ -> raise (Unimplemented "pause target")
-
-
-external open_debugger : unit -> unit = "open_context"
-external close_debugger : unit -> unit = "close_context"
-
-(* this is just the domains right now... expand to other contexts later *)
-external debugger_status : unit -> unit = "debugger_status"
-
diff --git a/tools/debugger/pdb/Process.ml b/tools/debugger/pdb/Process.ml
deleted file mode 100644
index ad98241de4..0000000000
--- a/tools/debugger/pdb/Process.ml
+++ /dev/null
@@ -1,79 +0,0 @@
-(** Process.ml
- *
- * process context implementation
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Int32
-open Intel
-
-type context_t =
-{
- mutable domain : int;
- mutable process : int;
- mutable evtchn : int;
- mutable ring : int32;
-}
-
-let default_context = { domain = 0; process = 0; evtchn = 0; ring = 0l }
-
-let new_context dom proc = { domain = dom; process = proc;
- evtchn = 0; ring = 0l }
-
-let string_of_context ctx =
- Printf.sprintf "{process} domain: %d, process: %d"
- ctx.domain ctx.process
-
-let set_domain ctx value =
- ctx.domain <- value;
- print_endline (Printf.sprintf "ctx.domain <- %d" ctx.domain)
-
-let set_process ctx value =
- ctx.process <- value;
- print_endline (Printf.sprintf "ctx.process <- %d" ctx.process)
-
-let get_domain ctx =
- ctx.domain
-
-let get_process ctx =
- ctx.process
-
-external _attach_debugger : context_t -> unit = "proc_attach_debugger"
-external detach_debugger : context_t -> unit = "proc_detach_debugger"
-external pause_target : context_t -> unit = "proc_pause_target"
-
-(* save the event channel and ring for the domain for future use *)
-let attach_debugger proc_ctx dom_ctx =
- print_endline (Printf.sprintf "%d %lx"
- (Xen_domain.get_evtchn dom_ctx)
- (Xen_domain.get_ring dom_ctx));
- proc_ctx.evtchn <- Xen_domain.get_evtchn dom_ctx;
- proc_ctx.ring <- Xen_domain.get_ring dom_ctx;
- _attach_debugger proc_ctx
-
-external read_register : context_t -> int -> unit = "proc_read_register"
-external read_registers : context_t -> unit = "proc_read_registers"
-external write_register : context_t -> register -> int32 -> unit =
- "proc_write_register"
-external read_memory : context_t -> int32 -> int -> unit =
- "proc_read_memory"
-external write_memory : context_t -> int32 -> int list -> unit =
- "proc_write_memory"
-
-external continue : context_t -> unit = "proc_continue_target"
-external step : context_t -> unit = "proc_step_target"
-
-external insert_memory_breakpoint : context_t -> int32 -> int -> unit =
- "proc_insert_memory_breakpoint"
-external remove_memory_breakpoint : context_t -> int32 -> int -> unit =
- "proc_remove_memory_breakpoint"
-external insert_watchpoint : context_t -> int -> int32 -> int -> unit =
- "proc_insert_watchpoint"
-external remove_watchpoint : context_t -> int -> int32 -> int -> unit =
- "proc_remove_watchpoint"
-
-let pause ctx =
- pause_target ctx
diff --git a/tools/debugger/pdb/Process.mli b/tools/debugger/pdb/Process.mli
deleted file mode 100644
index 733b681f59..0000000000
--- a/tools/debugger/pdb/Process.mli
+++ /dev/null
@@ -1,41 +0,0 @@
-(** Process.mli
- *
- * process context interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Int32
-open Intel
-
-type context_t
-
-val default_context : context_t
-val new_context : int -> int -> context_t
-
-val set_domain : context_t -> int -> unit
-val get_domain : context_t -> int
-val set_process : context_t -> int -> unit
-val get_process : context_t -> int
-
-val string_of_context : context_t -> string
-
-val attach_debugger : context_t -> Xen_domain.context_t -> unit
-val detach_debugger : context_t -> unit
-val pause : context_t -> unit
-
-val read_register : context_t -> int -> unit
-val read_registers : context_t -> unit
-val write_register : context_t -> register -> int32 -> unit
-val read_memory : context_t -> int32 -> int -> unit
-val write_memory : context_t -> int32 -> int list -> unit
-
-val continue : context_t -> unit
-val step : context_t -> unit
-
-val insert_memory_breakpoint : context_t -> int32 -> int -> unit
-val remove_memory_breakpoint : context_t -> int32 -> int -> unit
-val insert_watchpoint : context_t -> int -> int32 -> int -> unit
-val remove_watchpoint : context_t -> int -> int32 -> int -> unit
diff --git a/tools/debugger/pdb/Util.ml b/tools/debugger/pdb/Util.ml
deleted file mode 100644
index 4024b3e3cb..0000000000
--- a/tools/debugger/pdb/Util.ml
+++ /dev/null
@@ -1,165 +0,0 @@
-(** Util.ml
- *
- * various utility functions
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-let int_of_hexchar h =
- let i = int_of_char h in
- match h with
- | '0' .. '9' -> i - (int_of_char '0')
- | 'a' .. 'f' -> i - (int_of_char 'a') + 10
- | 'A' .. 'F' -> i - (int_of_char 'A') + 10
- | _ -> raise (Invalid_argument "unknown hex character")
-
-let hexchar_of_int i =
- let hexchars = [| '0'; '1'; '2'; '3'; '4'; '5'; '6'; '7';
- '8'; '9'; 'a'; 'b'; 'c'; 'd'; 'e'; 'f' |]
- in
- hexchars.(i)
-
-
-(** flip the bytes of a four byte int
- *)
-
-let flip_int num =
- let a = num mod 256
- and b = (num / 256) mod 256
- and c = (num / (256 * 256)) mod 256
- and d = (num / (256 * 256 * 256)) in
- (a * 256 * 256 * 256) + (b * 256 * 256) + (c * 256) + d
-
-
-let flip_int32 num =
- let a = Int32.logand num 0xffl
- and b = Int32.logand (Int32.shift_right_logical num 8) 0xffl
- and c = Int32.logand (Int32.shift_right_logical num 16) 0xffl
- and d = (Int32.shift_right_logical num 24) in
- (Int32.logor
- (Int32.logor (Int32.shift_left a 24) (Int32.shift_left b 16))
- (Int32.logor (Int32.shift_left c 8) d))
-
-
-let int_list_of_string_list list =
- List.map (fun x -> int_of_string x) list
-
-let int_list_of_string str len =
- let array_of_string s =
- let int_array = Array.make len 0 in
- for loop = 0 to len - 1 do
- int_array.(loop) <- (Char.code s.[loop]);
- done;
- int_array
- in
- Array.to_list (array_of_string str)
-
-
-(* remove leading and trailing whitespace from a string *)
-
-let chomp str =
- let head = Str.regexp "^[ \t\r\n]+" in
- let tail = Str.regexp "[ \t\r\n]+$" in
- let str = Str.global_replace head "" str in
- Str.global_replace tail "" str
-
-(* Stupid little parser for "<key>=<value>[,<key>=<value>]*"
- It first chops the entire command at each ',', so no ',' in key or value!
- Mucked to return a list of words for "value"
- *)
-
-let list_of_string str =
- let delim c = Str.regexp ("[ \t]*" ^ c ^ "[ \t]*") in
- let str_list = Str.split (delim " ") str in
- List.map (fun x -> chomp(x)) str_list
-
-let little_parser fn str =
- let delim c = Str.regexp ("[ \t]*" ^ c ^ "[ \t]*") in
- let str_list = Str.split (delim ",") str in
- let pair s =
- match Str.split (delim "=") s with
- | [key;value] -> fn (chomp key) (list_of_string value)
- | [key] -> fn (chomp key) []
- | _ -> failwith (Printf.sprintf "error: (little_parser) parse error [%s]" str)
- in
- List.iter pair str_list
-
-(* boolean list membership test *)
-let not_list_member the_list element =
- try
- List.find (fun x -> x = element) the_list;
- false
- with
- Not_found -> true
-
-(* a very inefficient way to remove the elements of one list from another *)
-let list_remove the_list remove_list =
- List.filter (not_list_member remove_list) the_list
-
-(* get a description of a file descriptor *)
-let get_connection_info fd =
- let get_local_info fd =
- let sockname = Unix.getsockname fd in
- match sockname with
- | Unix.ADDR_UNIX(s) -> "unix"
- | Unix.ADDR_INET(a,p) -> ((Unix.string_of_inet_addr a) ^ ":" ^
- (string_of_int p))
- and get_remote_info fd =
- let sockname = Unix.getpeername fd in
- match sockname with
- | Unix.ADDR_UNIX(s) -> s
- | Unix.ADDR_INET(a,p) -> ((Unix.string_of_inet_addr a) ^ ":" ^
- (string_of_int p))
- in
- try
- get_remote_info fd
- with
- | Unix.Unix_error (Unix.ENOTSOCK, s1, s2) ->
- let s = Unix.fstat fd in
- Printf.sprintf "dev: %d, inode: %d" s.Unix.st_dev s.Unix.st_ino
- | Unix.Unix_error (Unix.EBADF, s1, s2) ->
- let s = Unix.fstat fd in
- Printf.sprintf "dev: %d, inode: %d" s.Unix.st_dev s.Unix.st_ino
- | _ -> get_local_info fd
-
-
-(* really write a string *)
-let really_write fd str =
- let strlen = String.length str in
- let sent = ref 0 in
- while (!sent < strlen) do
- sent := !sent + (Unix.write fd str !sent (strlen - !sent))
- done
-
-let write_character fd ch =
- let str = String.create 1 in
- str.[0] <- ch;
- really_write fd str
-
-
-
-let send_reply fd reply =
- let checksum = ref 0 in
- write_character fd '$';
- for loop = 0 to (String.length reply) - 1 do
- write_character fd reply.[loop];
- checksum := !checksum + int_of_char reply.[loop]
- done;
- write_character fd '#';
- write_character fd (hexchar_of_int ((!checksum mod 256) / 16));
- write_character fd (hexchar_of_int ((!checksum mod 256) mod 16))
- (*
- * BUG NEED TO LISTEN FOR REPLY +/- AND POSSIBLY RE-TRANSMIT
- *)
-
-
-(** A few debugger commands such as step 's' and continue 'c' do
- * not immediately return a response to the debugger. In these
- * cases we raise No_reply instead.
- * This is also used by some contexts (such as Linux processes)
- * which utilize an asynchronous request / response protocol when
- * communicating with their respective backends.
- *)
-exception No_reply
diff --git a/tools/debugger/pdb/Xen_domain.ml b/tools/debugger/pdb/Xen_domain.ml
deleted file mode 100644
index 876715a32f..0000000000
--- a/tools/debugger/pdb/Xen_domain.ml
+++ /dev/null
@@ -1,43 +0,0 @@
-(** Xen_domain.ml
- *
- * domain assist for debugging processes
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-type context_t =
-{
- mutable domain : int;
- mutable evtchn : int;
- mutable pdb_front_ring : int32
-}
-
-let default_context = { domain = 0; evtchn = 0; pdb_front_ring = 0l }
-
-let new_context dom evtchn ring =
- {domain = dom; evtchn = evtchn; pdb_front_ring = ring}
-
-let set_domain ctx value =
- ctx.domain <- value
-
-let set_evtchn ctx value =
- ctx.evtchn <- value
-
-let set_ring ctx value =
- ctx.pdb_front_ring <- value
-
-let get_domain ctx =
- ctx.domain
-
-let get_evtchn ctx =
- ctx.evtchn
-
-let get_ring ctx =
- ctx.pdb_front_ring
-
-let string_of_context ctx =
- Printf.sprintf "{xen domain assist} domain: %d" ctx.domain
-
-external process_response : int32 -> int * int * string = "process_handle_response"
diff --git a/tools/debugger/pdb/Xen_domain.mli b/tools/debugger/pdb/Xen_domain.mli
deleted file mode 100644
index 29c1a446f6..0000000000
--- a/tools/debugger/pdb/Xen_domain.mli
+++ /dev/null
@@ -1,25 +0,0 @@
-(** Xen_domain.ml
- *
- * domain assist for debugging processes
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-type context_t
-
-val default_context : context_t
-val new_context : int -> int -> int32 -> context_t
-
-val set_domain : context_t -> int -> unit
-val get_domain : context_t -> int
-val set_evtchn : context_t -> int -> unit
-val get_evtchn : context_t -> int
-val set_ring : context_t -> int32 -> unit
-val get_ring : context_t -> int32
-
-val string_of_context : context_t -> string
-
-val process_response : int32 -> int * int * string
-
diff --git a/tools/debugger/pdb/debugger.ml b/tools/debugger/pdb/debugger.ml
deleted file mode 100644
index aa741a4566..0000000000
--- a/tools/debugger/pdb/debugger.ml
+++ /dev/null
@@ -1,372 +0,0 @@
-(** debugger.ml
- *
- * main debug functionality
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Intel
-open PDB
-open Util
-open Str
-
-let initialize_debugger () =
- ()
-
-let exit_debugger () =
- ()
-
-
-(**
- Detach Command
- Note: response is ignored by gdb. We leave the context in the
- hash. It will be cleaned up with the socket is closed.
- *)
-let gdb_detach ctx =
- PDB.detach_debugger ctx
-
-(**
- Kill Command
- Note: response is ignored by gdb. We leave the context in the
- hash. It will be cleaned up with the socket is closed.
- *)
-let gdb_kill () =
- ""
-
-
-
-(**
- Continue Command.
- resume the target
- *)
-let gdb_continue ctx =
- PDB.continue ctx;
- raise No_reply
-
-(**
- Step Command.
- single step the target
- *)
-let gdb_step ctx =
- PDB.step ctx;
- raise No_reply
-
-(**
- Read Register Command.
- return register as a 4-byte value.
- *)
-let gdb_read_register ctx command =
- let read_reg register =
- (Printf.sprintf "%08lx" (Util.flip_int32 (PDB.read_register ctx register)))
- in
- Scanf.sscanf command "p%x" read_reg
-
-
-(**
- Read Registers Command.
- returns 16 4-byte registers in a particular format defined by gdb.
- *)
-let gdb_read_registers ctx =
- let regs = PDB.read_registers ctx in
- let str =
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.eax)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.ecx)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.edx)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.ebx)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.esp)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.ebp)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.esi)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.edi)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.eip)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.efl)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.cs)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.ss)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.ds)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.es)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.fs)) ^
- (Printf.sprintf "%08lx" (Util.flip_int32 regs.gs)) in
- str
-
-(**
- Set Thread Command
- *)
-let gdb_set_thread command =
- "OK"
-
-
-(**
- Read Memory Packets
- *)
-let gdb_read_memory ctx command =
- let int_list_to_string i str =
- (Printf.sprintf "%02x" i) ^ str
- in
- let read_mem addr len =
- try
- let mem = PDB.read_memory ctx addr len in
- List.fold_right int_list_to_string mem ""
- with
- Failure s -> "E02"
- in
- Scanf.sscanf command "m%lx,%x" read_mem
-
-
-
-(**
- Write Memory Packets
- *)
-let gdb_write_memory ctx command =
- let write_mem addr len =
- print_endline (Printf.sprintf " gdb_write_memory %lx %x\n" addr len);
- print_endline (Printf.sprintf " [[ unimplemented ]]\n")
- in
- Scanf.sscanf command "M%lx,%d" write_mem;
- "OK"
-
-
-
-(**
- Write Register Packets
- *)
-let gdb_write_register ctx command =
- let write_reg reg goofy_val =
- let new_val = Util.flip_int32 goofy_val in
- match reg with
- | 0 -> PDB.write_register ctx EAX new_val
- | 1 -> PDB.write_register ctx ECX new_val
- | 2 -> PDB.write_register ctx EDX new_val
- | 3 -> PDB.write_register ctx EBX new_val
- | 4 -> PDB.write_register ctx ESP new_val
- | 5 -> PDB.write_register ctx EBP new_val
- | 6 -> PDB.write_register ctx ESI new_val
- | 7 -> PDB.write_register ctx EDI new_val
- | 8 -> PDB.write_register ctx EIP new_val
- | 9 -> PDB.write_register ctx EFL new_val
- | 10 -> PDB.write_register ctx CS new_val
- | 11 -> PDB.write_register ctx SS new_val
- | 12 -> PDB.write_register ctx DS new_val
- | 13 -> PDB.write_register ctx ES new_val
- | 14 -> PDB.write_register ctx FS new_val
- | 15 -> PDB.write_register ctx GS new_val
- | _ -> print_endline (Printf.sprintf "write unknown register [%d]" reg)
- in
- Scanf.sscanf command "P%x=%lx" write_reg;
- "OK"
-
-
-(**
- General Query Packets
- *)
-let gdb_query command =
- match command with
- | "qC" -> ""
- | "qOffsets" -> ""
- | "qSymbol::" -> ""
- | _ ->
- print_endline (Printf.sprintf "unknown gdb query packet [%s]" command);
- "E01"
-
-
-(**
- Write Memory Binary Packets
- *)
-let gdb_write_memory_binary ctx command =
- let write_mem addr len =
- let pos = Str.search_forward (Str.regexp ":") command 0 in
- let txt = Str.string_after command (pos + 1) in
- PDB.write_memory ctx addr (int_list_of_string txt len)
- in
- Scanf.sscanf command "X%lx,%d" write_mem;
- "OK"
-
-
-
-(**
- Last Signal Command
- *)
-let gdb_last_signal =
- "S00"
-
-
-
-
-(**
- Process PDB extensions to the GDB serial protocol.
- Changes the mutable context state.
- *)
-let pdb_extensions command sock =
- let process_extension key value =
- (* since this command can change the context,
- we need to grab it again each time *)
- let ctx = PDB.find_context sock in
- match key with
- | "status" ->
- PDB.debug_contexts ();
- (* print_endline ("debugger status");
- debugger_status ()
- *)
- | "context" ->
- PDB.add_context sock (List.hd value)
- (int_list_of_string_list (List.tl value))
- | _ -> failwith (Printf.sprintf "unknown pdb extension command [%s:%s]"
- key (List.hd value))
- in
- try
- Util.little_parser process_extension
- (String.sub command 1 ((String.length command) - 1));
- "OK"
- with
- | Unknown_context s ->
- print_endline (Printf.sprintf "unknown context [%s]" s);
- "E01"
- | Unknown_domain -> "E01"
- | Failure s -> "E01"
-
-
-(**
- Insert Breakpoint or Watchpoint Packet
- *)
-
-let bwc_watch_write = 102 (* from pdb_module.h *)
-let bwc_watch_read = 103
-let bwc_watch_access = 104
-
-let gdb_insert_bwcpoint ctx command =
- let insert cmd addr length =
- try
- match cmd with
- | 0 -> PDB.insert_memory_breakpoint ctx addr length; "OK"
- | 2 -> PDB.insert_watchpoint ctx bwc_watch_write addr length; "OK"
- | 3 -> PDB.insert_watchpoint ctx bwc_watch_read addr length; "OK"
- | 4 -> PDB.insert_watchpoint ctx bwc_watch_access addr length; "OK"
- | _ -> ""
- with
- Failure s -> "E03"
- in
- Scanf.sscanf command "Z%d,%lx,%x" insert
-
-(**
- Remove Breakpoint or Watchpoint Packet
- *)
-let gdb_remove_bwcpoint ctx command =
- let insert cmd addr length =
- try
- match cmd with
- | 0 -> PDB.remove_memory_breakpoint ctx addr length; "OK"
- | 2 -> PDB.remove_watchpoint ctx bwc_watch_write addr length; "OK"
- | 3 -> PDB.remove_watchpoint ctx bwc_watch_read addr length; "OK"
- | 4 -> PDB.remove_watchpoint ctx bwc_watch_access addr length; "OK"
- | _ -> ""
- with
- Failure s -> "E04"
- in
- Scanf.sscanf command "z%d,%lx,%d" insert
-
-(**
- Do Work!
-
- @param command char list
- *)
-
-let process_command command sock =
- let ctx = PDB.find_context sock in
- try
- match command.[0] with
- | 'c' -> gdb_continue ctx
- | 'D' -> gdb_detach ctx
- | 'g' -> gdb_read_registers ctx
- | 'H' -> gdb_set_thread command
- | 'k' -> gdb_kill ()
- | 'm' -> gdb_read_memory ctx command
- | 'M' -> gdb_write_memory ctx command
- | 'p' -> gdb_read_register ctx command
- | 'P' -> gdb_write_register ctx command
- | 'q' -> gdb_query command
- | 's' -> gdb_step ctx
- | 'x' -> pdb_extensions command sock
- | 'X' -> gdb_write_memory_binary ctx command
- | '?' -> gdb_last_signal
- | 'z' -> gdb_remove_bwcpoint ctx command
- | 'Z' -> gdb_insert_bwcpoint ctx command
- | _ ->
- print_endline (Printf.sprintf "unknown gdb command [%s]" command);
- ""
- with
- Unimplemented s ->
- print_endline (Printf.sprintf "loser. unimplemented command [%s][%s]"
- command s);
- "E03"
-
-(**
- process_xen_domain
-
- This is called whenever a domain debug assist responds to a
- pdb packet.
-*)
-
-let process_xen_domain fd =
- let channel = Evtchn.read fd in
- let ctx = find_context fd in
-
- let (dom, pid, str) =
- begin
- match ctx with
- | Xen_domain d -> Xen_domain.process_response (Xen_domain.get_ring d)
- | _ -> failwith ("process_xen_domain called without Xen_domain context")
- end
- in
- let sock = PDB.find_process dom pid in
- print_endline (Printf.sprintf "(linux) dom:%d pid:%d %s %s"
- dom pid str (Util.get_connection_info sock));
- Util.send_reply sock str;
- Evtchn.unmask fd channel (* allow next virq *)
-
-
-(**
- process_xen_virq
-
- This is called each time a virq_pdb is sent from xen to dom 0.
- It is sent by Xen when a domain hits a breakpoint.
-
- Think of this as the continuation function for a "c" or "s" command
- issued to a domain.
-*)
-
-external query_domain_stop : unit -> (int * int) list = "query_domain_stop"
-(* returns a list of paused domains : () -> (domain, vcpu) list *)
-
-let process_xen_virq fd =
- let channel = Evtchn.read fd in
- let find_pair (dom, vcpu) =
- print_endline (Printf.sprintf "checking %d.%d" dom vcpu);
- try
- let sock = PDB.find_domain dom vcpu in
- true
- with
- Unknown_domain -> false
- in
- let dom_list = query_domain_stop () in
- let (dom, vcpu) = List.find find_pair dom_list in
- let vec = 3 in
- let sock = PDB.find_domain dom vcpu in
- print_endline (Printf.sprintf "handle bkpt dom:%d vcpu:%d vec:%d %s"
- dom vcpu vec (Util.get_connection_info sock));
- Util.send_reply sock "S05";
- Evtchn.unmask fd channel (* allow next virq *)
-
-
-(**
- process_xen_xcs
-
- This is called each time the software assist residing in a backend
- domain starts up. The control message includes the address of a
- shared ring page and our end of an event channel (which indicates
- when data is available on the ring).
-*)
-
-let process_xen_xcs xcs_fd =
- let (local_evtchn_fd, evtchn, dom, ring) = Xcs.read xcs_fd in
- add_xen_domain_context local_evtchn_fd dom evtchn ring;
- local_evtchn_fd
diff --git a/tools/debugger/pdb/evtchn.ml b/tools/debugger/pdb/evtchn.ml
deleted file mode 100644
index 9cf441573a..0000000000
--- a/tools/debugger/pdb/evtchn.ml
+++ /dev/null
@@ -1,40 +0,0 @@
-(** evtchn.ml
- *
- * event channel interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-let dev_name = "/dev/xen/evtchn" (* EVTCHN_DEV_NAME *)
-let dev_major = 10 (* EVTCHN_DEV_MAJOR *)
-let dev_minor = 201 (* EVTCHN_DEV_MINOR *)
-
-let virq_pdb = 6 (* as defined VIRQ_PDB *)
-
-external bind_virq : int -> int = "evtchn_bind_virq"
-external bind_interdomain : int -> int * int = "evtchn_bind_interdomain"
-external bind : Unix.file_descr -> int -> unit = "evtchn_bind"
-external unbind : Unix.file_descr -> int -> unit = "evtchn_unbind"
-external ec_open : string -> int -> int -> Unix.file_descr = "evtchn_open"
-external read : Unix.file_descr -> int = "evtchn_read"
-external ec_close : Unix.file_descr -> unit = "evtchn_close"
-external unmask : Unix.file_descr -> int -> unit = "evtchn_unmask"
-
-let _setup () =
- let fd = ec_open dev_name dev_major dev_minor in
- fd
-
-let _bind fd port =
- bind fd port
-
-let setup () =
- let port = bind_virq virq_pdb in
- let fd = _setup() in
- _bind fd port;
- fd
-
-let teardown fd =
- unbind fd virq_pdb;
- ec_close fd
diff --git a/tools/debugger/pdb/evtchn.mli b/tools/debugger/pdb/evtchn.mli
deleted file mode 100644
index 3f9560f72c..0000000000
--- a/tools/debugger/pdb/evtchn.mli
+++ /dev/null
@@ -1,19 +0,0 @@
-(** evtchn.mli
- *
- * event channel interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-val _setup : unit -> Unix.file_descr
-val _bind : Unix.file_descr -> int -> unit
-
-val bind_interdomain : int -> int * int
-
-
-val setup : unit -> Unix.file_descr
-val read : Unix.file_descr -> int
-val teardown : Unix.file_descr -> unit
-val unmask : Unix.file_descr -> int -> unit
diff --git a/tools/debugger/pdb/linux-2.6-module/Makefile b/tools/debugger/pdb/linux-2.6-module/Makefile
deleted file mode 100644
index 9025cd85c1..0000000000
--- a/tools/debugger/pdb/linux-2.6-module/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-XEN_ROOT = ../../../..
-LINUX_DIR = linux-2.6.12-xenU
-KDIR = $(XEN_ROOT)/$(LINUX_DIR)
-
-obj-m += pdb.o
-pdb-objs += module.o
-pdb-objs += debug.o
-
-CFLAGS += -g
-CFLAGS += -Wall
-CFLAGS += -Werror
-
-.PHONY: module
-module :
-# make KBUILD_VERBOSE=1 ARCH=xen -C $(KDIR) M=$(PWD) modules
- make ARCH=xen -C $(KDIR) M=$(PWD) modules
-
-.PHONY: clean
-clean :
- make -C $(KDIR) M=$(PWD) clean
-
diff --git a/tools/debugger/pdb/linux-2.6-module/debug.c b/tools/debugger/pdb/linux-2.6-module/debug.c
deleted file mode 100644
index e53dfbc1b1..0000000000
--- a/tools/debugger/pdb/linux-2.6-module/debug.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * debug.c
- * pdb debug functionality for processes.
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <asm-i386/kdebug.h>
-#include <asm-i386/mach-xen/asm/processor.h>
-#include <asm-i386/mach-xen/asm/ptrace.h>
-#include <asm-i386/mach-xen/asm/tlbflush.h>
-#include <xen/interface/xen.h>
-#include "pdb_module.h"
-#include "pdb_debug.h"
-
-
-static int pdb_debug_fn (struct pt_regs *regs, long error_code,
- unsigned int condition);
-static int pdb_int3_fn (struct pt_regs *regs, long error_code);
-static int pdb_page_fault_fn (struct pt_regs *regs, long error_code,
- unsigned int condition);
-
-/***********************************************************************/
-
-typedef struct bwcpoint /* break/watch/catch point */
-{
- struct list_head list;
- unsigned long address;
- int length;
-
- uint8_t type; /* BWC_??? */
- uint8_t mode; /* for BWC_PAGE, the current protection mode */
- uint32_t process;
- uint8_t error; /* error occured when enabling: don't disable. */
-
- /* original values */
- uint8_t orig_bkpt; /* single byte breakpoint */
- pte_t orig_pte;
-
- struct list_head watchpt_read_list; /* read watchpoints on this page */
- struct list_head watchpt_write_list; /* write */
- struct list_head watchpt_access_list; /* access */
- struct list_head watchpt_disabled_list; /* disabled */
-
- struct bwcpoint *parent; /* watchpoint: bwc_watch (the page) */
- struct bwcpoint *watchpoint; /* bwc_watch_step: original watchpoint */
-} bwcpoint_t, *bwcpoint_p;
-
-static struct list_head bwcpoint_list = LIST_HEAD_INIT(bwcpoint_list);
-
-#define _pdb_bwcpoint_alloc(_var) \
-{ \
- if ( (_var = kmalloc(sizeof(bwcpoint_t), GFP_KERNEL)) == NULL ) \
- printk("error: unable to allocate memory %d\n", __LINE__); \
- else { \
- memset(_var, 0, sizeof(bwcpoint_t)); \
- INIT_LIST_HEAD(&_var->watchpt_read_list); \
- INIT_LIST_HEAD(&_var->watchpt_write_list); \
- INIT_LIST_HEAD(&_var->watchpt_access_list); \
- INIT_LIST_HEAD(&_var->watchpt_disabled_list); \
- } \
-}
-
-/***********************************************************************/
-
-static void _pdb_bwc_print_list (struct list_head *, char *, int);
-
-static void
-_pdb_bwc_print (bwcpoint_p bwc, char *label, int level)
-{
- printk("%s%03d 0x%08lx:0x%02x %c\n", label, bwc->type,
- bwc->address, bwc->length, bwc->error ? 'e' : '-');
-
- if ( !list_empty(&bwc->watchpt_read_list) )
- _pdb_bwc_print_list(&bwc->watchpt_read_list, "r", level);
- if ( !list_empty(&bwc->watchpt_write_list) )
- _pdb_bwc_print_list(&bwc->watchpt_write_list, "w", level);
- if ( !list_empty(&bwc->watchpt_access_list) )
- _pdb_bwc_print_list(&bwc->watchpt_access_list, "a", level);
- if ( !list_empty(&bwc->watchpt_disabled_list) )
- _pdb_bwc_print_list(&bwc->watchpt_disabled_list, "d", level);
-}
-
-static void
-_pdb_bwc_print_list (struct list_head *bwc_list, char *label, int level)
-{
- struct list_head *ptr;
- int counter = 0;
-
- list_for_each(ptr, bwc_list)
- {
- bwcpoint_p bwc = list_entry(ptr, bwcpoint_t, list);
- printk(" %s[%02d]%s ", level > 0 ? " " : "", counter++,
- level > 0 ? "" : " ");
- _pdb_bwc_print(bwc, label, level+1);
- }
-
- if (counter == 0)
- {
- printk(" empty list\n");
- }
-}
-
-void
-pdb_bwc_print_list (void)
-{
- _pdb_bwc_print_list(&bwcpoint_list, " ", 0);
-}
-
-bwcpoint_p
-pdb_search_watchpoint (uint32_t process, unsigned long address)
-{
- bwcpoint_p bwc_watch = (bwcpoint_p) 0;
- bwcpoint_p bwc_entry = (bwcpoint_p) 0;
- struct list_head *ptr;
-
- list_for_each(ptr, &bwcpoint_list) /* find bwc page entry */
- {
- bwc_watch = list_entry(ptr, bwcpoint_t, list);
- if (bwc_watch->address == (address & PAGE_MASK)) break;
- }
-
- if ( !bwc_watch )
- {
- return (bwcpoint_p) 0;
- }
-
-#define __pdb_search_watchpoint_list(__list) \
- list_for_each(ptr, (__list)) \
- { \
- bwc_entry = list_entry(ptr, bwcpoint_t, list); \
- if ( bwc_entry->process == process && \
- bwc_entry->address <= address && \
- bwc_entry->address + bwc_entry->length > address ) \
- return bwc_entry; \
- }
-
- __pdb_search_watchpoint_list(&bwc_watch->watchpt_read_list);
- __pdb_search_watchpoint_list(&bwc_watch->watchpt_write_list);
- __pdb_search_watchpoint_list(&bwc_watch->watchpt_access_list);
-
-#undef __pdb_search_watchpoint_list
-
- return (bwcpoint_p) 0;
-}
-
-/*************************************************************/
-
-int
-pdb_suspend (struct task_struct *target)
-{
- uint32_t rc = 0;
-
- force_sig(SIGSTOP, target); /* force_sig_specific ??? */
-
- return rc;
-}
-
-int
-pdb_resume (struct task_struct *target)
-{
- int rc = 0;
-
- wake_up_process(target);
-
- return rc;
-}
-
-/*
- * from linux-2.6.11/arch/i386/kernel/ptrace.c::getreg()
- */
-static unsigned long
-_pdb_get_register (struct task_struct *target, int reg)
-{
- unsigned long result = ~0UL;
- unsigned long offset;
- unsigned char *stack = 0L;
-
- switch (reg)
- {
- case LINUX_FS:
- result = target->thread.fs;
- break;
- case LINUX_GS:
- result = target->thread.gs;
- break;
- case LINUX_DS:
- case LINUX_ES:
- case LINUX_SS:
- case LINUX_CS:
- result = 0xffff;
- /* fall through */
- default:
- if (reg > LINUX_GS)
- reg -= 2;
-
- offset = reg * sizeof(long);
- offset -= sizeof(struct pt_regs);
- stack = (unsigned char *)target->thread.esp0;
- stack += offset;
- result &= *((int *)stack);
- }
-
- return result;
-}
-
-/*
- * from linux-2.6.11/arch/i386/kernel/ptrace.c::putreg()
- */
-static void
-_pdb_set_register (struct task_struct *target, int reg, unsigned long val)
-{
- unsigned long offset;
- unsigned char *stack;
- unsigned long value = val;
-
- switch (reg)
- {
- case LINUX_FS:
- target->thread.fs = value;
- return;
- case LINUX_GS:
- target->thread.gs = value;
- return;
- case LINUX_DS:
- case LINUX_ES:
- value &= 0xffff;
- break;
- case LINUX_SS:
- case LINUX_CS:
- value &= 0xffff;
- break;
- case LINUX_EFL:
- break;
- }
-
- if (reg > LINUX_GS)
- reg -= 2;
- offset = reg * sizeof(long);
- offset -= sizeof(struct pt_regs);
- stack = (unsigned char *)target->thread.esp0;
- stack += offset;
- *(unsigned long *) stack = value;
-
- return;
-}
-
-int
-pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op)
-{
- int rc = 0;
-
- switch (op->reg)
- {
- case 0: op->value = _pdb_get_register(target, LINUX_EAX); break;
- case 1: op->value = _pdb_get_register(target, LINUX_ECX); break;
- case 2: op->value = _pdb_get_register(target, LINUX_EDX); break;
- case 3: op->value = _pdb_get_register(target, LINUX_EBX); break;
- case 4: op->value = _pdb_get_register(target, LINUX_ESP); break;
- case 5: op->value = _pdb_get_register(target, LINUX_EBP); break;
- case 6: op->value = _pdb_get_register(target, LINUX_ESI); break;
- case 7: op->value = _pdb_get_register(target, LINUX_EDI); break;
- case 8: op->value = _pdb_get_register(target, LINUX_EIP); break;
- case 9: op->value = _pdb_get_register(target, LINUX_EFL); break;
-
- case 10: op->value = _pdb_get_register(target, LINUX_CS); break;
- case 11: op->value = _pdb_get_register(target, LINUX_SS); break;
- case 12: op->value = _pdb_get_register(target, LINUX_DS); break;
- case 13: op->value = _pdb_get_register(target, LINUX_ES); break;
- case 14: op->value = _pdb_get_register(target, LINUX_FS); break;
- case 15: op->value = _pdb_get_register(target, LINUX_GS); break;
- }
-
- return rc;
-}
-
-int
-pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op)
-{
- int rc = 0;
-
- op->reg[ 0] = _pdb_get_register(target, LINUX_EAX);
- op->reg[ 1] = _pdb_get_register(target, LINUX_ECX);
- op->reg[ 2] = _pdb_get_register(target, LINUX_EDX);
- op->reg[ 3] = _pdb_get_register(target, LINUX_EBX);
- op->reg[ 4] = _pdb_get_register(target, LINUX_ESP);
- op->reg[ 5] = _pdb_get_register(target, LINUX_EBP);
- op->reg[ 6] = _pdb_get_register(target, LINUX_ESI);
- op->reg[ 7] = _pdb_get_register(target, LINUX_EDI);
- op->reg[ 8] = _pdb_get_register(target, LINUX_EIP);
- op->reg[ 9] = _pdb_get_register(target, LINUX_EFL);
-
- op->reg[10] = _pdb_get_register(target, LINUX_CS);
- op->reg[11] = _pdb_get_register(target, LINUX_SS);
- op->reg[12] = _pdb_get_register(target, LINUX_DS);
- op->reg[13] = _pdb_get_register(target, LINUX_ES);
- op->reg[14] = _pdb_get_register(target, LINUX_FS);
- op->reg[15] = _pdb_get_register(target, LINUX_GS);
-
- return rc;
-}
-
-int
-pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op)
-{
- int rc = 0;
-
- _pdb_set_register(target, op->reg, op->value);
-
- return rc;
-}
-
-int
-pdb_access_memory (struct task_struct *target, unsigned long address,
- void *buffer, int length, int write)
-{
- int rc = 0;
-
- access_process_vm(target, address, buffer, length, write);
-
- return rc;
-}
-
-int
-pdb_continue (struct task_struct *target)
-{
- int rc = 0;
- unsigned long eflags;
-
- eflags = _pdb_get_register(target, LINUX_EFL);
- eflags &= ~X86_EFLAGS_TF;
- _pdb_set_register(target, LINUX_EFL, eflags);
-
- wake_up_process(target);
-
- return rc;
-}
-
-int
-pdb_step (struct task_struct *target)
-{
- int rc = 0;
- unsigned long eflags;
- bwcpoint_p bkpt;
-
- eflags = _pdb_get_register(target, LINUX_EFL);
- eflags |= X86_EFLAGS_TF;
- _pdb_set_register(target, LINUX_EFL, eflags);
-
- _pdb_bwcpoint_alloc(bkpt);
- if ( bkpt == NULL ) return -1;
-
- bkpt->process = target->pid;
- bkpt->address = 0;
- bkpt->type = BWC_DEBUG;
-
- list_add_tail(&bkpt->list, &bwcpoint_list);
-
- wake_up_process(target);
-
- return rc;
-}
-
-int
-pdb_insert_memory_breakpoint (struct task_struct *target,
- unsigned long address, uint32_t length)
-{
- int rc = 0;
- bwcpoint_p bkpt;
- uint8_t breakpoint_opcode = 0xcc;
-
- printk("insert breakpoint %d:%lx len: %d\n", target->pid, address, length);
-
- if ( length != 1 )
- {
- printk("error: breakpoint length should be 1\n");
- return -1;
- }
-
- _pdb_bwcpoint_alloc(bkpt);
- if ( bkpt == NULL ) return -1;
-
- bkpt->process = target->pid;
- bkpt->address = address;
- bkpt->type = BWC_INT3;
-
- pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_READ);
- pdb_access_memory(target, address, &breakpoint_opcode, 1, PDB_MEM_WRITE);
-
- list_add_tail(&bkpt->list, &bwcpoint_list);
-
- printk("breakpoint_set %d:%lx OLD: 0x%x\n",
- target->pid, address, bkpt->orig_bkpt);
- pdb_bwc_print_list();
-
- return rc;
-}
-
-int
-pdb_remove_memory_breakpoint (struct task_struct *target,
- unsigned long address, uint32_t length)
-{
- int rc = 0;
- bwcpoint_p bkpt = NULL;
-
- printk ("remove breakpoint %d:%lx\n", target->pid, address);
-
- struct list_head *entry;
- list_for_each(entry, &bwcpoint_list)
- {
- bkpt = list_entry(entry, bwcpoint_t, list);
- if ( target->pid == bkpt->process &&
- address == bkpt->address &&
- bkpt->type == BWC_INT3 )
- break;
- }
-
- if (entry == &bwcpoint_list)
- {
- printk ("error: no breakpoint found\n");
- return -1;
- }
-
- pdb_access_memory(target, address, &bkpt->orig_bkpt, 1, PDB_MEM_WRITE);
-
- list_del(&bkpt->list);
- kfree(bkpt);
-
- pdb_bwc_print_list();
-
- return rc;
-}
-
-#define PDB_PTE_UPDATE 1
-#define PDB_PTE_RESTORE 2
-
-int
-pdb_change_pte (struct task_struct *target, bwcpoint_p bwc, int mode)
-{
- int rc = 0;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *ptep;
-
- pgd = pgd_offset(target->mm, bwc->address);
- if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) return -1;
-
- pud = pud_offset(pgd, bwc->address);
- if (pud_none(*pud) || unlikely(pud_bad(*pud))) return -2;
-
- pmd = pmd_offset(pud, bwc->address);
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) return -3;
-
- ptep = pte_offset_map(pmd, bwc->address);
- if (!ptep) return -4;
-
- switch ( mode )
- {
- case PDB_PTE_UPDATE: /* added or removed a watchpoint. update pte. */
- {
- pte_t new_pte;
-
- if ( pte_val(bwc->parent->orig_pte) == 0 ) /* new watchpoint page */
- {
- bwc->parent->orig_pte = *ptep;
- }
-
- new_pte = bwc->parent->orig_pte;
-
- if ( !list_empty(&bwc->parent->watchpt_read_list) ||
- !list_empty(&bwc->parent->watchpt_access_list) )
- {
- new_pte = pte_rdprotect(new_pte);
- }
-
- if ( !list_empty(&bwc->parent->watchpt_write_list) ||
- !list_empty(&bwc->parent->watchpt_access_list) )
- {
- new_pte = pte_wrprotect(new_pte);
- }
-
- if ( pte_val(new_pte) != pte_val(*ptep) )
- {
- *ptep = new_pte;
- flush_tlb_mm(target->mm);
- }
- break;
- }
- case PDB_PTE_RESTORE : /* suspend watchpoint by restoring original pte */
- {
- *ptep = bwc->parent->orig_pte;
- flush_tlb_mm(target->mm);
- break;
- }
- default :
- {
- printk("(linux) unknown mode %d %d\n", mode, __LINE__);
- break;
- }
- }
-
- pte_unmap(ptep); /* can i flush the tlb before pte_unmap? */
-
- return rc;
-}
-
-int
-pdb_insert_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
-{
- int rc = 0;
-
- bwcpoint_p bwc_watch;
- bwcpoint_p bwc_entry;
- struct list_head *ptr;
- unsigned long page = watchpt->address & PAGE_MASK;
- struct list_head *watchpoint_list;
-
- printk("insert watchpoint: %d %x %x\n",
- watchpt->type, watchpt->address, watchpt->length);
-
- list_for_each(ptr, &bwcpoint_list) /* find existing bwc page entry */
- {
- bwc_watch = list_entry(ptr, bwcpoint_t, list);
-
- if (bwc_watch->address == page) goto got_bwc_watch;
- }
-
- _pdb_bwcpoint_alloc(bwc_watch); /* create new bwc:watch */
- if ( bwc_watch == NULL ) return -1;
-
- bwc_watch->type = BWC_WATCH;
- bwc_watch->process = target->pid;
- bwc_watch->address = page;
-
- list_add_tail(&bwc_watch->list, &bwcpoint_list);
-
- got_bwc_watch:
-
- switch (watchpt->type)
- {
- case BWC_WATCH_READ:
- watchpoint_list = &bwc_watch->watchpt_read_list; break;
- case BWC_WATCH_WRITE:
- watchpoint_list = &bwc_watch->watchpt_write_list; break;
- case BWC_WATCH_ACCESS:
- watchpoint_list = &bwc_watch->watchpt_access_list; break;
- default:
- printk("unknown type %d\n", watchpt->type); return -2;
- }
-
- _pdb_bwcpoint_alloc(bwc_entry); /* create new bwc:entry */
- if ( bwc_entry == NULL ) return -1;
-
- bwc_entry->process = target->pid;
- bwc_entry->address = watchpt->address;
- bwc_entry->length = watchpt->length;
- bwc_entry->type = watchpt->type;
- bwc_entry->parent = bwc_watch;
-
- list_add_tail(&bwc_entry->list, watchpoint_list);
- pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
-
- pdb_bwc_print_list();
-
- return rc;
-}
-
-int
-pdb_remove_watchpoint (struct task_struct *target, pdb_op_watchpt_p watchpt)
-{
- int rc = 0;
- bwcpoint_p bwc_watch = (bwcpoint_p) NULL;
- bwcpoint_p bwc_entry = (bwcpoint_p) NULL;
- unsigned long page = watchpt->address & PAGE_MASK;
- struct list_head *ptr;
- struct list_head *watchpoint_list;
-
- printk("remove watchpoint: %d %x %x\n",
- watchpt->type, watchpt->address, watchpt->length);
-
- list_for_each(ptr, &bwcpoint_list) /* find bwc page entry */
- {
- bwc_watch = list_entry(ptr, bwcpoint_t, list);
- if (bwc_watch->address == page) break;
- }
-
- if ( !bwc_watch )
- {
- printk("(linux) delete watchpoint: can't find bwc page 0x%08x\n",
- watchpt->address);
- return -1;
- }
-
- switch (watchpt->type)
- {
- case BWC_WATCH_READ:
- watchpoint_list = &bwc_watch->watchpt_read_list; break;
- case BWC_WATCH_WRITE:
- watchpoint_list = &bwc_watch->watchpt_write_list; break;
- case BWC_WATCH_ACCESS:
- watchpoint_list = &bwc_watch->watchpt_access_list; break;
- default:
- printk("unknown type %d\n", watchpt->type); return -2;
- }
-
- list_for_each(ptr, watchpoint_list) /* find watchpoint */
- {
- bwc_entry = list_entry(ptr, bwcpoint_t, list);
- if ( bwc_entry->address == watchpt->address &&
- bwc_entry->length == watchpt->length ) break;
- }
-
- if ( !bwc_entry ) /* or ptr == watchpoint_list */
- {
- printk("(linux) delete watchpoint: can't find watchpoint 0x%08x\n",
- watchpt->address);
- return -1;
- }
-
- list_del(&bwc_entry->list);
- pdb_change_pte(target, bwc_entry, PDB_PTE_UPDATE);
- kfree(bwc_entry);
-
-
- if ( list_empty(&bwc_watch->watchpt_read_list) &&
- list_empty(&bwc_watch->watchpt_write_list) &&
- list_empty(&bwc_watch->watchpt_access_list) )
- {
- list_del(&bwc_watch->list);
- kfree(bwc_watch);
- }
-
- pdb_bwc_print_list();
-
- return rc;
-}
-
-
-/***************************************************************/
-
-int
-pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
- void *data)
-{
- struct die_args *args = (struct die_args *)data;
-
- switch (val)
- {
- case DIE_DEBUG:
- if ( pdb_debug_fn(args->regs, args->trapnr, args->err) )
- return NOTIFY_STOP;
- break;
- case DIE_TRAP:
- if ( args->trapnr == 3 && pdb_int3_fn(args->regs, args->err) )
- return NOTIFY_STOP;
- break;
- case DIE_INT3: /* without kprobes, we should never see DIE_INT3 */
- if ( pdb_int3_fn(args->regs, args->err) )
- return NOTIFY_STOP;
- break;
- case DIE_PAGE_FAULT:
- if ( pdb_page_fault_fn(args->regs, args->trapnr, args->err) )
- return NOTIFY_STOP;
- break;
- case DIE_GPF:
- printk("---------------GPF\n");
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-
-static int
-pdb_debug_fn (struct pt_regs *regs, long error_code,
- unsigned int condition)
-{
- pdb_response_t resp;
- bwcpoint_p bkpt = NULL;
- struct list_head *entry;
-
- printk("pdb_debug_fn\n");
-
- list_for_each(entry, &bwcpoint_list)
- {
- bkpt = list_entry(entry, bwcpoint_t, list);
- if ( current->pid == bkpt->process &&
- (bkpt->type == BWC_DEBUG || /* single step */
- bkpt->type == BWC_WATCH_STEP)) /* single step over watchpoint */
- break;
- }
-
- if (entry == &bwcpoint_list)
- {
- printk("not my debug 0x%x 0x%lx\n", current->pid, regs->eip);
- return 0;
- }
-
- pdb_suspend(current);
-
- printk("(pdb) %s pid: %d, eip: 0x%08lx\n",
- bkpt->type == BWC_DEBUG ? "debug" : "watch-step",
- current->pid, regs->eip);
-
- regs->eflags &= ~X86_EFLAGS_TF;
- set_tsk_thread_flag(current, TIF_SINGLESTEP);
-
- switch (bkpt->type)
- {
- case BWC_DEBUG:
- resp.operation = PDB_OPCODE_STEP;
- break;
- case BWC_WATCH_STEP:
- {
- struct list_head *watchpoint_list;
- bwcpoint_p watch_page = bkpt->watchpoint->parent;
-
- switch (bkpt->watchpoint->type)
- {
- case BWC_WATCH_READ:
- watchpoint_list = &watch_page->watchpt_read_list; break;
- case BWC_WATCH_WRITE:
- watchpoint_list = &watch_page->watchpt_write_list; break;
- case BWC_WATCH_ACCESS:
- watchpoint_list = &watch_page->watchpt_access_list; break;
- default:
- printk("unknown type %d\n", bkpt->watchpoint->type); return 0;
- }
-
- resp.operation = PDB_OPCODE_WATCHPOINT;
- list_del_init(&bkpt->watchpoint->list);
- list_add_tail(&bkpt->watchpoint->list, watchpoint_list);
- pdb_change_pte(current, bkpt->watchpoint, PDB_PTE_UPDATE);
- pdb_bwc_print_list();
- break;
- }
- default:
- printk("unknown breakpoint type %d %d\n", __LINE__, bkpt->type);
- return 0;
- }
-
- resp.process = current->pid;
- resp.status = PDB_RESPONSE_OKAY;
-
- pdb_send_response(&resp);
-
- list_del(&bkpt->list);
- kfree(bkpt);
-
- return 1;
-}
-
-
-static int
-pdb_int3_fn (struct pt_regs *regs, long error_code)
-{
- pdb_response_t resp;
- bwcpoint_p bkpt = NULL;
- unsigned long address = regs->eip - 1;
-
- struct list_head *entry;
- list_for_each(entry, &bwcpoint_list)
- {
- bkpt = list_entry(entry, bwcpoint_t, list);
- if ( current->pid == bkpt->process &&
- address == bkpt->address &&
- bkpt->type == BWC_INT3 )
- break;
- }
-
- if (entry == &bwcpoint_list)
- {
- printk("not my int3 bkpt 0x%x 0x%lx\n", current->pid, address);
- return 0;
- }
-
- printk("(pdb) int3 pid: %d, eip: 0x%08lx\n", current->pid, address);
-
- pdb_suspend(current);
-
- resp.operation = PDB_OPCODE_CONTINUE;
- resp.process = current->pid;
- resp.status = PDB_RESPONSE_OKAY;
-
- pdb_send_response(&resp);
-
- return 1;
-}
-
-static int
-pdb_page_fault_fn (struct pt_regs *regs, long error_code,
- unsigned int condition)
-{
- unsigned long cr2;
- unsigned long cr3;
- bwcpoint_p bwc;
- bwcpoint_p watchpt;
- bwcpoint_p bkpt;
-
- __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (cr3) : );
- __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
-
- bwc = pdb_search_watchpoint(current->pid, cr2);
- if ( !bwc )
- {
- return 0; /* not mine */
- }
-
- printk("page_fault cr2:%08lx err:%lx eip:%08lx\n",
- cr2, error_code, regs->eip);
-
- /* disable the watchpoint */
- watchpt = bwc->watchpoint;
- list_del_init(&bwc->list);
- list_add_tail(&bwc->list, &bwc->parent->watchpt_disabled_list);
- pdb_change_pte(current, bwc, PDB_PTE_RESTORE);
-
- /* single step the faulting instruction */
- regs->eflags |= X86_EFLAGS_TF;
-
- /* create a bwcpoint entry so we know what to do once we regain control */
- _pdb_bwcpoint_alloc(bkpt);
- if ( bkpt == NULL ) return -1;
-
- bkpt->process = current->pid;
- bkpt->address = 0;
- bkpt->type = BWC_WATCH_STEP;
- bkpt->watchpoint = bwc;
-
- /* add to head so we see it first the next time we break */
- list_add(&bkpt->list, &bwcpoint_list);
-
- pdb_bwc_print_list();
- return 1;
-}
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/linux-2.6-module/module.c b/tools/debugger/pdb/linux-2.6-module/module.c
deleted file mode 100644
index 5ca0e025ca..0000000000
--- a/tools/debugger/pdb/linux-2.6-module/module.c
+++ /dev/null
@@ -1,337 +0,0 @@
-
-/*
- * module.c
- *
- * Handles initial registration with pdb when the pdb module starts up
- * and cleanup when the module goes away (sortof :)
- * Also receives each request from pdb in domain 0 and dispatches to the
- * appropriate debugger function.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-
-#include <asm-i386/kdebug.h>
-
-#include <xen/evtchn.h>
-#include <xen/ctrl_if.h>
-#include <xen/hypervisor.h>
-#include <xen/interface/io/domain_controller.h>
-#include <xen/interface/xen.h>
-
-#include <xen/interface/io/ring.h>
-
-#include "pdb_module.h"
-#include "pdb_debug.h"
-
-#define PDB_RING_SIZE __RING_SIZE((pdb_sring_t *)0, PAGE_SIZE)
-
-static pdb_back_ring_t pdb_ring;
-static unsigned int pdb_evtchn;
-static unsigned int pdb_irq;
-static unsigned int pdb_domain;
-
-/* work queue */
-static void pdb_work_handler(void *unused);
-static DECLARE_WORK(pdb_deferred_work, pdb_work_handler, NULL);
-
-/*
- * send response to a pdb request
- */
-void
-pdb_send_response (pdb_response_t *response)
-{
- pdb_response_t *resp;
-
- resp = RING_GET_RESPONSE(&pdb_ring, pdb_ring.rsp_prod_pvt);
-
- memcpy(resp, response, sizeof(pdb_response_t));
- resp->domain = pdb_domain;
-
- wmb(); /* Ensure other side can see the response fields. */
- pdb_ring.rsp_prod_pvt++;
- RING_PUSH_RESPONSES(&pdb_ring);
- notify_via_evtchn(pdb_evtchn);
- return;
-}
-
-/*
- * handle a debug command from the front end
- */
-static void
-pdb_process_request (pdb_request_t *request)
-{
- pdb_response_t resp;
- struct task_struct *target;
-
- read_lock(&tasklist_lock);
- target = find_task_by_pid(request->process);
- if (target)
- get_task_struct(target);
- read_unlock(&tasklist_lock);
-
- resp.operation = request->operation;
- resp.process = request->process;
-
- if (!target)
- {
- printk ("(linux) target not found 0x%x\n", request->process);
- resp.status = PDB_RESPONSE_ERROR;
- goto response;
- }
-
- switch (request->operation)
- {
- case PDB_OPCODE_PAUSE :
- pdb_suspend(target);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_ATTACH :
- pdb_suspend(target);
- pdb_domain = request->u.attach.domain;
- printk("(linux) attach dom:0x%x pid:0x%x\n",
- pdb_domain, request->process);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_DETACH :
- pdb_resume(target);
- printk("(linux) detach 0x%x\n", request->process);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_RD_REG :
- resp.u.rd_reg.reg = request->u.rd_reg.reg;
- pdb_read_register(target, &resp.u.rd_reg);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_RD_REGS :
- pdb_read_registers(target, &resp.u.rd_regs);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_WR_REG :
- pdb_write_register(target, &request->u.wr_reg);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_RD_MEM :
- pdb_access_memory(target, request->u.rd_mem.address,
- &resp.u.rd_mem.data, request->u.rd_mem.length,
- PDB_MEM_READ);
- resp.u.rd_mem.address = request->u.rd_mem.address;
- resp.u.rd_mem.length = request->u.rd_mem.length;
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_WR_MEM :
- pdb_access_memory(target, request->u.wr_mem.address,
- &request->u.wr_mem.data, request->u.wr_mem.length,
- PDB_MEM_WRITE);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_CONTINUE :
- pdb_continue(target);
- goto no_response;
- break;
- case PDB_OPCODE_STEP :
- pdb_step(target);
- resp.status = PDB_RESPONSE_OKAY;
- goto no_response;
- break;
- case PDB_OPCODE_SET_BKPT :
- pdb_insert_memory_breakpoint(target, request->u.bkpt.address,
- request->u.bkpt.length);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_CLR_BKPT :
- pdb_remove_memory_breakpoint(target, request->u.bkpt.address,
- request->u.bkpt.length);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_SET_WATCHPT :
- pdb_insert_watchpoint(target, &request->u.watchpt);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- case PDB_OPCODE_CLR_WATCHPT :
- pdb_remove_watchpoint(target, &request->u.watchpt);
- resp.status = PDB_RESPONSE_OKAY;
- break;
- default:
- printk("(pdb) unknown request operation %d\n", request->operation);
- resp.status = PDB_RESPONSE_ERROR;
- }
-
- response:
- pdb_send_response (&resp);
-
- no_response:
- return;
-}
-
-/*
- * work queue
- */
-static void
-pdb_work_handler (void *unused)
-{
- pdb_request_t *req;
- RING_IDX i, rp;
-
- rp = pdb_ring.sring->req_prod;
- rmb();
-
- for ( i = pdb_ring.req_cons;
- (i != rp) && !RING_REQUEST_CONS_OVERFLOW(&pdb_ring, i);
- i++ )
- {
- req = RING_GET_REQUEST(&pdb_ring, i);
- pdb_process_request(req);
-
- }
- pdb_ring.req_cons = i;
-}
-
-/*
- * receive a pdb request
- */
-static irqreturn_t
-pdb_interrupt (int irq, void *dev_id, struct pt_regs *ptregs)
-{
- schedule_work(&pdb_deferred_work);
-
- return IRQ_HANDLED;
-}
-
-static void
-pdb_send_connection_status(int status, unsigned long ring)
-{
- ctrl_msg_t cmsg =
- {
- .type = CMSG_DEBUG,
- .subtype = CMSG_DEBUG_CONNECTION_STATUS,
- .length = sizeof(pdb_connection_t),
- };
- pdb_connection_t *conn = (pdb_connection_t *)cmsg.msg;
-
- conn->status = status;
- conn->ring = ring;
- conn->evtchn = 0;
-
- ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
-}
-
-
-/*
- * this is called each time a message is received on the control channel
- */
-static void
-pdb_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
-{
- switch (msg->subtype)
- {
- case CMSG_DEBUG_CONNECTION_STATUS:
- /* initialize event channel created by the pdb server */
-
- pdb_evtchn = ((pdb_connection_p) msg->msg)->evtchn;
- pdb_irq = bind_evtchn_to_irq(pdb_evtchn);
-
- if ( request_irq(pdb_irq, pdb_interrupt,
- SA_SAMPLE_RANDOM, "pdb", NULL) )
- {
- printk("(pdb) request irq failed: %d %d\n", pdb_evtchn, pdb_irq);
- }
- break;
-
- default:
- printk ("(pdb) unknown xcs control message: %d\n", msg->subtype);
- break;
- }
-
- return;
-}
-
-
-/********************************************************************/
-
-static struct notifier_block pdb_exceptions_nb =
-{
- .notifier_call = pdb_exceptions_notify,
- .priority = 0x1 /* low priority */
-};
-
-
-static int __init
-pdb_initialize (void)
-{
- int err;
- pdb_sring_t *sring;
-
- printk("----\npdb initialize %s %s\n", __DATE__, __TIME__);
-
- /*
- if ( xen_start_info.flags & SIF_INITDOMAIN )
- return 1;
- */
-
- pdb_evtchn = 0;
- pdb_irq = 0;
- pdb_domain = 0;
-
- (void)ctrl_if_register_receiver(CMSG_DEBUG, pdb_ctrlif_rx,
- CALLBACK_IN_BLOCKING_CONTEXT);
-
- /* rings */
- sring = (pdb_sring_t *)__get_free_page(GFP_KERNEL);
- SHARED_RING_INIT(sring);
- BACK_RING_INIT(&pdb_ring, sring, PAGE_SIZE);
-
- /* notify pdb in dom 0 */
- pdb_send_connection_status(PDB_CONNECTION_STATUS_UP,
- virt_to_machine(pdb_ring.sring) >> PAGE_SHIFT);
-
- /* handler for int1 & int3 */
- err = register_die_notifier(&pdb_exceptions_nb);
-
- return err;
-}
-
-static void __exit
-pdb_terminate(void)
-{
- int err = 0;
-
- printk("pdb cleanup\n");
-
- (void)ctrl_if_unregister_receiver(CMSG_DEBUG, pdb_ctrlif_rx);
-
- if (pdb_irq)
- {
- free_irq(pdb_irq, NULL);
- pdb_irq = 0;
- }
-
- if (pdb_evtchn)
- {
- unbind_evtchn_from_irq(pdb_evtchn);
- pdb_evtchn = 0;
- }
-
- pdb_send_connection_status(PDB_CONNECTION_STATUS_DOWN, 0);
-
- /* handler for int1 & int3 */
- err = unregister_die_notifier(&pdb_exceptions_nb);
-
- return;
-}
-
-
-module_init(pdb_initialize);
-module_exit(pdb_terminate);
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h b/tools/debugger/pdb/linux-2.6-module/pdb_debug.h
deleted file mode 100644
index 89adbc0b0d..0000000000
--- a/tools/debugger/pdb/linux-2.6-module/pdb_debug.h
+++ /dev/null
@@ -1,47 +0,0 @@
-
-#ifndef __PDB_DEBUG_H_
-#define __PDB_DEBUG_H_
-
-/* debugger.c */
-void pdb_initialize_bwcpoint (void);
-int pdb_suspend (struct task_struct *target);
-int pdb_resume (struct task_struct *target);
-int pdb_read_register (struct task_struct *target, pdb_op_rd_reg_p op);
-int pdb_read_registers (struct task_struct *target, pdb_op_rd_regs_p op);
-int pdb_write_register (struct task_struct *target, pdb_op_wr_reg_p op);
-int pdb_read_memory (struct task_struct *target, pdb_op_rd_mem_req_p req,
- pdb_op_rd_mem_resp_p resp);
-int pdb_write_memory (struct task_struct *target, pdb_op_wr_mem_p op);
-int pdb_access_memory (struct task_struct *target, unsigned long address,
- void *buffer, int length, int write);
-int pdb_continue (struct task_struct *target);
-int pdb_step (struct task_struct *target);
-
-int pdb_insert_memory_breakpoint (struct task_struct *target,
- unsigned long address, uint32_t length);
-int pdb_remove_memory_breakpoint (struct task_struct *target,
- unsigned long address, uint32_t length);
-int pdb_insert_watchpoint (struct task_struct *target,
- pdb_op_watchpt_p watchpt);
-int pdb_remove_watchpoint (struct task_struct *target,
- pdb_op_watchpt_p watchpt);
-
-int pdb_exceptions_notify (struct notifier_block *self, unsigned long val,
- void *data);
-
-/* module.c */
-void pdb_send_response (pdb_response_t *response);
-
-#endif
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/linux-2.6-module/pdb_module.h b/tools/debugger/pdb/linux-2.6-module/pdb_module.h
deleted file mode 100644
index 472403d69e..0000000000
--- a/tools/debugger/pdb/linux-2.6-module/pdb_module.h
+++ /dev/null
@@ -1,142 +0,0 @@
-
-#ifndef __PDB_MODULE_H_
-#define __PDB_MODULE_H_
-
-#include "../pdb_caml_xen.h"
-
-#define PDB_OPCODE_PAUSE 1
-
-#define PDB_OPCODE_ATTACH 2
-typedef struct pdb_op_attach
-{
- uint32_t domain;
-} pdb_op_attach_t, *pdb_op_attach_p;
-
-#define PDB_OPCODE_DETACH 3
-
-#define PDB_OPCODE_RD_REG 4
-typedef struct pdb_op_rd_reg
-{
- uint32_t reg;
- uint32_t value;
-} pdb_op_rd_reg_t, *pdb_op_rd_reg_p;
-
-#define PDB_OPCODE_RD_REGS 5
-typedef struct pdb_op_rd_regs
-{
- uint32_t reg[GDB_REGISTER_FRAME_SIZE];
-} pdb_op_rd_regs_t, *pdb_op_rd_regs_p;
-
-#define PDB_OPCODE_WR_REG 6
-typedef struct pdb_op_wr_reg
-{
- uint32_t reg;
- uint32_t value;
-} pdb_op_wr_reg_t, *pdb_op_wr_reg_p;
-
-#define PDB_OPCODE_RD_MEM 7
-typedef struct pdb_op_rd_mem_req
-{
- uint32_t address;
- uint32_t length;
-} pdb_op_rd_mem_req_t, *pdb_op_rd_mem_req_p;
-
-typedef struct pdb_op_rd_mem_resp
-{
- uint32_t address;
- uint32_t length;
- uint8_t data[1024];
-} pdb_op_rd_mem_resp_t, *pdb_op_rd_mem_resp_p;
-
-#define PDB_OPCODE_WR_MEM 8
-typedef struct pdb_op_wr_mem
-{
- uint32_t address;
- uint32_t length;
- uint8_t data[1024]; /* arbitrary */
-} pdb_op_wr_mem_t, *pdb_op_wr_mem_p;
-
-#define PDB_OPCODE_CONTINUE 9
-#define PDB_OPCODE_STEP 10
-
-#define PDB_OPCODE_SET_BKPT 11
-#define PDB_OPCODE_CLR_BKPT 12
-typedef struct pdb_op_bkpt
-{
- uint32_t address;
- uint32_t length;
-} pdb_op_bkpt_t, *pdb_op_bkpt_p;
-
-#define PDB_OPCODE_SET_WATCHPT 13
-#define PDB_OPCODE_CLR_WATCHPT 14
-#define PDB_OPCODE_WATCHPOINT 15
-typedef struct pdb_op_watchpt
-{
-#define BWC_DEBUG 1
-#define BWC_INT3 3
-#define BWC_WATCH 100 /* pdb: watchpoint page */
-#define BWC_WATCH_STEP 101 /* pdb: watchpoint single step */
-#define BWC_WATCH_WRITE 102
-#define BWC_WATCH_READ 103
-#define BWC_WATCH_ACCESS 104
- uint32_t type;
- uint32_t address;
- uint32_t length;
-} pdb_op_watchpt_t, *pdb_op_watchpt_p;
-
-
-typedef struct
-{
- uint8_t operation; /* PDB_OPCODE_??? */
- uint32_t process;
- union
- {
- pdb_op_attach_t attach;
- pdb_op_rd_reg_t rd_reg;
- pdb_op_wr_reg_t wr_reg;
- pdb_op_rd_mem_req_t rd_mem;
- pdb_op_wr_mem_t wr_mem;
- pdb_op_bkpt_t bkpt;
- pdb_op_watchpt_t watchpt;
- } u;
-} pdb_request_t, *pdb_request_p;
-
-
-
-#define PDB_RESPONSE_OKAY 0
-#define PDB_RESPONSE_ERROR -1
-
-typedef struct {
- uint8_t operation; /* copied from request */
- uint32_t domain;
- uint32_t process;
- int16_t status; /* PDB_RESPONSE_??? */
- union
- {
- pdb_op_rd_reg_t rd_reg;
- pdb_op_rd_regs_t rd_regs;
- pdb_op_rd_mem_resp_t rd_mem;
- } u;
-} pdb_response_t, *pdb_response_p;
-
-
-DEFINE_RING_TYPES(pdb, pdb_request_t, pdb_response_t);
-
-
-/* from access_process_vm */
-#define PDB_MEM_READ 0
-#define PDB_MEM_WRITE 1
-
-#endif
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/linux-2.6-patches/Makefile b/tools/debugger/pdb/linux-2.6-patches/Makefile
deleted file mode 100644
index f2cb7f6ef5..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-XEN_ROOT = ../../../..
-LINUX_DIR = linux-2.6.12-xenU
-KDIR = $(XEN_ROOT)/$(LINUX_DIR)
-PATCH_DIR = $(CURDIR)
-
-.PHONY: patches
-patches : patches-done
-
-patches-done :
- ( for i in *.patch ; do ( cd $(KDIR) ; patch -p1 < $(PATCH_DIR)/$$i || exit 1 ) ; done )
- touch $@
diff --git a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch b/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
deleted file mode 100644
index 0efd8db532..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/i386_ksyms.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff -u linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c
---- linux-2.6.12/arch/xen/i386/kernel/i386_ksyms.c 2005-07-31 22:36:50.000000000 +0100
-+++ linux-2.6.12-pdb/arch/xen/i386/kernel/i386_ksyms.c 2005-08-01 10:57:31.000000000 +0100
-@@ -151,6 +151,7 @@
- /* TLB flushing */
- EXPORT_SYMBOL(flush_tlb_page);
- #endif
-+EXPORT_SYMBOL(flush_tlb_mm);
-
- #ifdef CONFIG_X86_IO_APIC
- EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
-@@ -172,6 +173,7 @@
- EXPORT_SYMBOL_GPL(unset_nmi_callback);
-
- EXPORT_SYMBOL(register_die_notifier);
-+EXPORT_SYMBOL(unregister_die_notifier);
- #ifdef CONFIG_HAVE_DEC_LOCK
- EXPORT_SYMBOL(_atomic_dec_and_lock);
- #endif
diff --git a/tools/debugger/pdb/linux-2.6-patches/kdebug.patch b/tools/debugger/pdb/linux-2.6-patches/kdebug.patch
deleted file mode 100644
index 8ceca41dc5..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/kdebug.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -u linux-2.6.12/include/asm-i386/kdebug.h linux-2.6.12-pdb/include/asm-i386/kdebug.h
---- linux-2.6.12/include/asm-i386/kdebug.h 2005-06-17 20:48:29.000000000 +0100
-+++ linux-2.6.12-pdb/include/asm-i386/kdebug.h 2005-08-01 11:11:53.000000000 +0100
-@@ -21,6 +21,7 @@
- If you really want to do it first unregister - then synchronize_kernel - then free.
- */
- int register_die_notifier(struct notifier_block *nb);
-+int unregister_die_notifier(struct notifier_block *nb);
- extern struct notifier_block *i386die_chain;
-
-
diff --git a/tools/debugger/pdb/linux-2.6-patches/makefile.patch b/tools/debugger/pdb/linux-2.6-patches/makefile.patch
deleted file mode 100644
index 819f853d55..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/makefile.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Naur linux-2.6.12/Makefile linux-2.6.12-pdb/Makefile
---- linux-2.6.12/Makefile 2005-08-01 01:21:21.000000000 +0100
-+++ linux-2.6.12-pdb/Makefile 2005-08-01 10:28:10.000000000 +0100
-@@ -508,7 +508,7 @@
- ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
- CFLAGS += -Os
- else
--CFLAGS += -O2
-+CFLAGS += -O
- endif
-
- #Add align options if CONFIG_CC_* is not equal to 0
diff --git a/tools/debugger/pdb/linux-2.6-patches/ptrace.patch b/tools/debugger/pdb/linux-2.6-patches/ptrace.patch
deleted file mode 100644
index 98d76c495c..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/ptrace.patch
+++ /dev/null
@@ -1,11 +0,0 @@
-diff -u linux-2.6.12/kernel/ptrace.c linux-2.6.12-pdb/kernel/ptrace.c
---- linux-2.6.12/kernel/ptrace.c 2005-06-17 20:48:29.000000000 +0100
-+++ linux-2.6.12-pdb/kernel/ptrace.c 2005-07-22 13:23:16.000000000 +0100
-@@ -239,6 +239,7 @@
-
- return buf - old_buf;
- }
-+EXPORT_SYMBOL(access_process_vm);
-
- int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
- {
diff --git a/tools/debugger/pdb/linux-2.6-patches/traps.patch b/tools/debugger/pdb/linux-2.6-patches/traps.patch
deleted file mode 100644
index 54b2ddbcb3..0000000000
--- a/tools/debugger/pdb/linux-2.6-patches/traps.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff -u linux-2.6.12/arch/xen/i386/kernel/traps.c linux-2.6.12-pdb/arch/xen/i386/kernel/traps.c
---- linux-2.6.12/arch/xen/i386/kernel/traps.c 2005-07-31 22:47:00.000000000 +0100
-+++ linux-2.6.12-pdb/arch/xen/i386/kernel/traps.c 2005-07-31 22:47:32.000000000 +0100
-@@ -102,6 +102,16 @@
- return err;
- }
-
-+int unregister_die_notifier(struct notifier_block *nb)
-+{
-+ int err = 0;
-+ unsigned long flags;
-+ spin_lock_irqsave(&die_notifier_lock, flags);
-+ err = notifier_chain_unregister(&i386die_chain, nb);
-+ spin_unlock_irqrestore(&die_notifier_lock, flags);
-+ return err;
-+}
-+
- static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
- {
- return p > (void *)tinfo &&
diff --git a/tools/debugger/pdb/pdb_caml_domain.c b/tools/debugger/pdb/pdb_caml_domain.c
deleted file mode 100644
index 15058ffb45..0000000000
--- a/tools/debugger/pdb/pdb_caml_domain.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * pdb_caml_xc.c
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * PDB's OCaml interface library for debugging domains
- */
-
-#include <xenctrl.h>
-#include <xendebug.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-#include "pdb_caml_xen.h"
-
-typedef struct
-{
- int domain;
- int vcpu;
-} context_t;
-
-#define decode_context(_ctx, _ocaml) \
-{ \
- (_ctx)->domain = Int_val(Field((_ocaml),0)); \
- (_ctx)->vcpu = Int_val(Field((_ocaml),1)); \
-}
-
-#define encode_context(_ctx, _ocaml) \
-{ \
- (_ocaml) = caml_alloc_tuple(2); \
- Store_field((_ocaml), 0, Val_int((_ctx)->domain)); \
- Store_field((_ocaml), 1, Val_int((_ctx)->vcpu)); \
-}
-
-
-/****************************************************************************/
-
-/*
- * dom_read_register : context_t -> int -> int32
- */
-value
-dom_read_register (value context, value reg)
-{
- CAMLparam2(context, reg);
- CAMLlocal1(result);
-
- int my_reg = Int_val(reg);
- cpu_user_regs_t *regs;
- context_t ctx;
-
- decode_context(&ctx, context);
-
- if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
- {
- printf("(pdb) read registers error!\n"); fflush(stdout);
- failwith("read registers error");
- }
-
- dump_regs(regs);
-
- result = caml_alloc_tuple(16);
-
- switch (my_reg)
- {
- case GDB_EAX: result = caml_copy_int32(regs->eax); break;
- case GDB_ECX: result = caml_copy_int32(regs->ecx); break;
- case GDB_EDX: result = caml_copy_int32(regs->edx); break;
- case GDB_EBX: result = caml_copy_int32(regs->ebx); break;
- case GDB_ESP: result = caml_copy_int32(regs->esp); break;
- case GDB_EBP: result = caml_copy_int32(regs->ebp); break;
- case GDB_ESI: result = caml_copy_int32(regs->esi); break;
- case GDB_EDI: result = caml_copy_int32(regs->edi); break;
- case GDB_EIP: result = caml_copy_int32(regs->eip); break;
- case GDB_EFL: result = caml_copy_int32(regs->eflags); break;
- case GDB_CS: result = caml_copy_int32(regs->cs); break;
- case GDB_SS: result = caml_copy_int32(regs->ss); break;
- case GDB_DS: result = caml_copy_int32(regs->ds); break;
- case GDB_ES: result = caml_copy_int32(regs->es); break;
- case GDB_FS: result = caml_copy_int32(regs->fs); break;
- case GDB_GS: result = caml_copy_int32(regs->gs); break;
- }
-
- CAMLreturn(result);
-}
-
-/*
- * dom_read_registers : context_t -> int32
- */
-value
-dom_read_registers (value context)
-{
- CAMLparam1(context);
- CAMLlocal1(result);
-
- cpu_user_regs_t *regs;
- context_t ctx;
-
- decode_context(&ctx, context);
-
- if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
- {
- printf("(pdb) read registers error!\n"); fflush(stdout);
- failwith("read registers error");
- }
-
- dump_regs(regs);
-
- result = caml_alloc_tuple(16);
-
- Store_field(result, 0, caml_copy_int32(regs->eax));
- Store_field(result, 1, caml_copy_int32(regs->ecx));
- Store_field(result, 2, caml_copy_int32(regs->edx));
- Store_field(result, 3, caml_copy_int32(regs->ebx));
- Store_field(result, 4, caml_copy_int32(regs->esp));
- Store_field(result, 5, caml_copy_int32(regs->ebp));
- Store_field(result, 6, caml_copy_int32(regs->esi));
- Store_field(result, 7, caml_copy_int32(regs->edi));
- Store_field(result, 8, caml_copy_int32(regs->eip));
- Store_field(result, 9, caml_copy_int32(regs->eflags));
- Store_field(result, 10, caml_copy_int32(regs->cs)); /* 16 */
- Store_field(result, 11, caml_copy_int32(regs->ss)); /* 16 */
- Store_field(result, 12, caml_copy_int32(regs->ds)); /* 16 */
- Store_field(result, 13, caml_copy_int32(regs->es)); /* 16 */
- Store_field(result, 14, caml_copy_int32(regs->fs)); /* 16 */
- Store_field(result, 15, caml_copy_int32(regs->gs)); /* 16 */
-
- CAMLreturn(result);
-}
-
-
-/*
- * dom_write_register : context_t -> register -> int32 -> unit
- */
-value
-dom_write_register (value context, value reg, value newval)
-{
- CAMLparam3(context, reg, newval);
-
- int my_reg = Int_val(reg);
- int val = Int32_val(newval);
-
- context_t ctx;
- cpu_user_regs_t *regs;
-
- printf("(pdb) write register\n");
-
- decode_context(&ctx, context);
-
- if ( xendebug_read_registers(xc_handle, ctx.domain, ctx.vcpu, &regs) )
- {
- printf("(pdb) write register (get) error!\n"); fflush(stdout);
- failwith("write register error");
- }
-
- switch (my_reg)
- {
- case GDB_EAX: regs->eax = val; break;
- case GDB_ECX: regs->ecx = val; break;
- case GDB_EDX: regs->edx = val; break;
- case GDB_EBX: regs->ebx = val; break;
-
- case GDB_ESP: regs->esp = val; break;
- case GDB_EBP: regs->ebp = val; break;
- case GDB_ESI: regs->esi = val; break;
- case GDB_EDI: regs->edi = val; break;
-
- case GDB_EIP: regs->eip = val; break;
- case GDB_EFL: regs->eflags = val; break;
-
- case GDB_CS: regs->cs = val; break;
- case GDB_SS: regs->ss = val; break;
- case GDB_DS: regs->ds = val; break;
- case GDB_ES: regs->es = val; break;
- case GDB_FS: regs->fs = val; break;
- case GDB_GS: regs->gs = val; break;
- }
-
- if ( xendebug_write_registers(xc_handle, ctx.domain, ctx.vcpu, regs) )
- {
- printf("(pdb) write register (set) error!\n"); fflush(stdout);
- failwith("write register error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * dom_read_memory : context_t -> int32 -> int -> int
- */
-value
-dom_read_memory (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
- CAMLlocal2(result, temp);
-
- context_t ctx;
- int loop;
- char *buffer;
- unsigned long my_address = Int32_val(address);
- uint32_t my_length = Int_val(length);
-
- printf ("(pdb) read memory\n");
-
- decode_context(&ctx, context);
-
- buffer = malloc(my_length);
- if ( buffer == NULL )
- {
- printf("(pdb) read memory: malloc failed.\n"); fflush(stdout);
- failwith("read memory error");
- }
-
- if ( xendebug_read_memory(xc_handle, ctx.domain, ctx.vcpu,
- my_address, my_length, buffer) )
- {
- printf("(pdb) read memory error!\n"); fflush(stdout);
- failwith("read memory error");
- }
-
- result = caml_alloc(2,0);
- if ( my_length > 0 ) /* car */
- {
- Store_field(result, 0, Val_int(buffer[my_length - 1] & 0xff));
- }
- else
-
- {
- Store_field(result, 0, Val_int(0));
- }
- Store_field(result, 1, Val_int(0)); /* cdr */
-
- for (loop = 1; loop < my_length; loop++)
- {
- temp = result;
- result = caml_alloc(2,0);
- Store_field(result, 0, Val_int(buffer[my_length - loop - 1] & 0xff));
- Store_field(result, 1, temp);
- }
-
- CAMLreturn(result);
-}
-
-/*
- * dom_write_memory : context_t -> int32 -> int list -> unit
- */
-value
-dom_write_memory (value context, value address, value val_list)
-{
- CAMLparam3(context, address, val_list);
- CAMLlocal1(node);
-
- context_t ctx;
-
- char buffer[4096]; /* a big buffer */
- unsigned long my_address;
- uint32_t length = 0;
-
- printf ("(pdb) write memory\n");
-
- decode_context(&ctx, context);
-
- node = val_list;
- if ( Int_val(node) == 0 ) /* gdb functionalty test uses empty list */
- {
- CAMLreturn(Val_unit);
- }
-
- while ( Int_val(Field(node,1)) != 0 )
- {
- buffer[length++] = Int_val(Field(node, 0));
- node = Field(node,1);
- }
- buffer[length++] = Int_val(Field(node, 0));
-
- my_address = (unsigned long) Int32_val(address);
-
- if ( xendebug_write_memory(xc_handle, ctx.domain, ctx.vcpu,
- my_address, length, buffer) )
- {
- printf("(pdb) write memory error!\n"); fflush(stdout);
- failwith("write memory error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * dom_continue_target : context_t -> unit
- */
-value
-dom_continue_target (value context)
-{
- CAMLparam1(context);
-
- context_t ctx;
-
- decode_context(&ctx, context);
-
- if ( xendebug_continue(xc_handle, ctx.domain, ctx.vcpu) )
- {
- printf("(pdb) continue\n"); fflush(stdout);
- failwith("continue");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * dom_step_target : context_t -> unit
- */
-value
-dom_step_target (value context)
-{
- CAMLparam1(context);
-
- context_t ctx;
-
- decode_context(&ctx, context);
-
- if ( xendebug_step(xc_handle, ctx.domain, ctx.vcpu) )
- {
- printf("(pdb) step\n"); fflush(stdout);
- failwith("step");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-
-/*
- * dom_insert_memory_breakpoint : context_t -> int32 -> int list -> unit
- */
-value
-dom_insert_memory_breakpoint (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- unsigned long my_address = (unsigned long) Int32_val(address);
- int my_length = Int_val(length);
-
- decode_context(&ctx, context);
-
- printf ("(pdb) insert memory breakpoint 0x%lx %d\n",
- my_address, my_length);
-
- if ( xendebug_insert_memory_breakpoint(xc_handle, ctx.domain, ctx.vcpu,
- my_address, my_length) )
- {
- printf("(pdb) error: insert memory breakpoint\n"); fflush(stdout);
- failwith("insert memory breakpoint");
- }
-
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * dom_remove_memory_breakpoint : context_t -> int32 -> int list -> unit
- */
-value
-dom_remove_memory_breakpoint (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
-
- unsigned long my_address = (unsigned long) Int32_val(address);
- int my_length = Int_val(length);
-
- printf ("(pdb) remove memory breakpoint 0x%lx %d\n",
- my_address, my_length);
-
- decode_context(&ctx, context);
-
- if ( xendebug_remove_memory_breakpoint(xc_handle,
- ctx.domain, ctx.vcpu,
- my_address, my_length) )
- {
- printf("(pdb) error: remove memory breakpoint\n"); fflush(stdout);
- failwith("remove memory breakpoint");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * dom_attach_debugger : int -> int -> unit
- */
-value
-dom_attach_debugger (value domain, value vcpu)
-{
- CAMLparam2(domain, vcpu);
-
- int my_domain = Int_val(domain);
- int my_vcpu = Int_val(vcpu);
-
- printf ("(pdb) attach domain [%d.%d]\n", my_domain, my_vcpu);
-
- if ( xendebug_attach(xc_handle, my_domain, my_vcpu) )
- {
- printf("(pdb) attach error!\n"); fflush(stdout);
- failwith("attach error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * dom_detach_debugger : int -> int -> unit
- */
-value
-dom_detach_debugger (value domain, value vcpu)
-{
- CAMLparam2(domain, vcpu);
-
- int my_domain = Int_val(domain);
- int my_vcpu = Int_val(vcpu);
-
- printf ("(pdb) detach domain [%d.%d]\n", my_domain, my_vcpu);
-
- if ( xendebug_detach(xc_handle, my_domain, my_vcpu) )
- {
- printf("(pdb) detach error!\n"); fflush(stdout);
- failwith("detach error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * dom_pause_target : int -> unit
- */
-value
-dom_pause_target (value domid)
-{
- CAMLparam1(domid);
-
- int my_domid = Int_val(domid);
-
- printf ("(pdb) pause target %d\n", my_domid);
-
- xc_domain_pause(xc_handle, my_domid);
-
- CAMLreturn(Val_unit);
-}
-
-/****************************************************************************/
-/****************************************************************************/
-
-/*
- * query_domain_stop : unit -> (int * int) list
- */
-value
-query_domain_stop (value unit)
-{
- CAMLparam1(unit);
- CAMLlocal3(result, temp, node);
-
- int max_domains = 20;
- int dom_list[max_domains];
- int loop, count;
-
- count = xendebug_query_domain_stop(xc_handle, dom_list, max_domains);
- if ( count < 0 )
- {
- printf("(pdb) query domain stop!\n"); fflush(stdout);
- failwith("query domain stop");
- }
-
- printf ("QDS [%d]: \n", count);
- for (loop = 0; loop < count; loop ++)
- printf (" %d", dom_list[loop]);
- printf ("\n");
-
- result = caml_alloc(2,0);
- if ( count > 0 ) /* car */
- {
- node = caml_alloc(2,0);
- Store_field(node, 0, Val_int(dom_list[0])); /* domain id */
- Store_field(node, 1, Val_int(0)); /* vcpu */
- Store_field(result, 0, node);
- }
- else
- {
- Store_field(result, 0, Val_int(0));
- }
- Store_field(result, 1, Val_int(0)); /* cdr */
-
- for ( loop = 1; loop < count; loop++ )
- {
- temp = result;
- result = caml_alloc(2,0);
- node = caml_alloc(2,0);
- Store_field(node, 0, Val_int(dom_list[loop])); /* domain id */
- Store_field(node, 1, Val_int(0)); /* vcpu */
- Store_field(result, 0, node);
- Store_field(result, 1, temp);
- }
-
- CAMLreturn(result);
-}
-
-/****************************************************************************/
-
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/pdb_caml_evtchn.c b/tools/debugger/pdb/pdb_caml_evtchn.c
deleted file mode 100644
index 8107814156..0000000000
--- a/tools/debugger/pdb/pdb_caml_evtchn.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * pdb_caml_evtchn.c
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * PDB's OCaml interface library for event channels
- */
-
-#include <xenctrl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-int xen_evtchn_bind (int evtchn_fd, int idx);
-int xen_evtchn_unbind (int evtchn_fd, int idx);
-
-int
-__evtchn_open (char *filename, int major, int minor)
-{
- int evtchn_fd;
- struct stat st;
-
- /* Make sure any existing device file links to correct device. */
- if ( (lstat(filename, &st) != 0) ||
- !S_ISCHR(st.st_mode) ||
- (st.st_rdev != makedev(major, minor)) )
- {
- (void)unlink(filename);
- }
-
- reopen:
- evtchn_fd = open(filename, O_RDWR);
- if ( evtchn_fd == -1 )
- {
- if ( (errno == ENOENT) &&
- ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
- (mknod(filename, S_IFCHR|0600, makedev(major,minor)) == 0) )
- {
- goto reopen;
- }
- return -errno;
- }
-
- return evtchn_fd;
-}
-
-/*
- * evtchn_open : string -> int -> int -> Unix.file_descr
- *
- * OCaml's Unix library doesn't have mknod, so it makes more sense just write
- * this in C. This code is from Keir/Andy.
- */
-value
-evtchn_open (value filename, value major, value minor)
-{
- CAMLparam3(filename, major, minor);
-
- char *myfilename = String_val(filename);
- int mymajor = Int_val(major);
- int myminor = Int_val(minor);
- int evtchn_fd;
-
- evtchn_fd = __evtchn_open(myfilename, mymajor, myminor);
-
- CAMLreturn(Val_int(evtchn_fd));
-}
-
-/*
- * evtchn_bind : Unix.file_descr -> int -> unit
- */
-value
-evtchn_bind (value fd, value idx)
-{
- CAMLparam2(fd, idx);
-
- int myfd = Int_val(fd);
- int myidx = Int_val(idx);
-
- if ( xen_evtchn_bind(myfd, myidx) < 0 )
- {
- printf("(pdb) evtchn_bind error!\n"); fflush(stdout);
- failwith("evtchn_bind error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * evtchn_unbind : Unix.file_descr -> int -> unit
- */
-value
-evtchn_unbind (value fd, value idx)
-{
- CAMLparam2(fd, idx);
-
- int myfd = Int_val(fd);
- int myidx = Int_val(idx);
-
- if ( xen_evtchn_unbind(myfd, myidx) < 0 )
- {
- printf("(pdb) evtchn_unbind error!\n"); fflush(stdout);
- failwith("evtchn_unbind error");
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * evtchn_read : Unix.file_descr -> int
- */
-value
-evtchn_read (value fd)
-{
- CAMLparam1(fd);
-
- uint16_t v;
- int bytes;
- int rc = -1;
- int myfd = Int_val(fd);
-
- while ( (bytes = read(myfd, &v, sizeof(v))) == -1 )
- {
- if ( errno == EINTR ) continue;
- rc = -errno;
- goto exit;
- }
-
- if ( bytes == sizeof(v) )
- rc = v;
-
- exit:
- CAMLreturn(Val_int(rc));
-}
-
-
-/*
- * evtchn_close : Unix.file_descr -> unit
- */
-value
-evtchn_close (value fd)
-{
- CAMLparam1(fd);
- int myfd = Int_val(fd);
-
- (void)close(myfd);
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * evtchn_unmask : Unix.file_descr -> int -> unit
- */
-value
-evtchn_unmask (value fd, value idx)
-{
- CAMLparam1(fd);
-
- int myfd = Int_val(fd);
- uint16_t myidx = Int_val(idx);
-
- (void)write(myfd, &myidx, sizeof(myidx));
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/tools/debugger/pdb/pdb_caml_process.c b/tools/debugger/pdb/pdb_caml_process.c
deleted file mode 100644
index 3d39b846a7..0000000000
--- a/tools/debugger/pdb/pdb_caml_process.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * pdb_caml_process.c
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * PDB's OCaml interface library for debugging processes
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-#include <xenctrl.h>
-#include <xen/xen.h>
-#include <xen/io/domain_controller.h>
-#include "pdb_module.h"
-#include "pdb_caml_xen.h"
-
-typedef struct
-{
- int domain;
- int process;
- int evtchn;
- pdb_front_ring_t *ring;
-} context_t;
-
-#define decode_context(_ctx, _ocaml) \
-{ \
- (_ctx)->domain = Int_val(Field((_ocaml),0)); \
- (_ctx)->process = Int_val(Field((_ocaml),1)); \
- (_ctx)->evtchn = Int_val(Field((_ocaml),2)); \
- (_ctx)->ring = (pdb_front_ring_t *)Int32_val(Field((_ocaml),3)); \
-}
-
-#define encode_context(_ctx, _ocaml) \
-{ \
- (_ocaml) = caml_alloc_tuple(2); \
- Store_field((_ocaml), 0, Val_int((_ctx)->domain)); \
- Store_field((_ocaml), 1, Val_int((_ctx)->process)); \
-}
-
-/*
- * send a request to a pdb domain backend.
- *
- * puts the request on a ring and kicks the backend using an event channel.
- */
-static void
-send_request (pdb_front_ring_t *pdb_ring, int evtchn, pdb_request_t *request)
-{
- pdb_request_t *req;
-
- req = RING_GET_REQUEST(pdb_ring, pdb_ring->req_prod_pvt);
-
- memcpy(req, request, sizeof(pdb_request_t));
-
- pdb_ring->req_prod_pvt++;
-
- RING_PUSH_REQUESTS(pdb_ring);
- xc_evtchn_send(xc_handle, evtchn);
-}
-
-/*
- * process_handle_response : int32 -> int * int * string
- *
- * A backend domain has notified pdb (via an event channel)
- * that a command has finished.
- * We read the result from the channel and formulate a response
- * as a single string. Also return the domain and process.
- */
-
-static inline unsigned int
-_flip (unsigned int orig)
-{
- return (((orig << 24) & 0xff000000) | ((orig << 8) & 0x00ff0000) |
- ((orig >> 8) & 0x0000ff00) | ((orig >> 24) & 0x000000ff));
-}
-
-value
-process_handle_response (value ring)
-{
- CAMLparam1(ring);
- CAMLlocal2(result, str);
-
- RING_IDX rp;
- pdb_response_p resp;
- pdb_front_ring_t *my_ring = (pdb_front_ring_t *)Int32_val(ring);
- char msg[2048];
- int msglen;
-
- memset(msg, 0, sizeof(msg));
-
- rp = my_ring->sring->rsp_prod;
- rmb(); /* Ensure we see queued responses up to 'rp'. */
-
- /* default response is OK unless the command has something
- more interesting to say */
- sprintf(msg, "OK");
-
- if (my_ring->rsp_cons != rp)
- {
- resp = RING_GET_RESPONSE(my_ring, my_ring->rsp_cons);
-
- switch (resp->operation)
- {
- case PDB_OPCODE_PAUSE :
- case PDB_OPCODE_ATTACH :
- case PDB_OPCODE_DETACH :
- break;
-
- case PDB_OPCODE_RD_REG :
- {
- sprintf(&msg[0], "%08x", _flip(resp->u.rd_reg.value));
- break;
- }
-
- case PDB_OPCODE_RD_REGS :
- {
- int loop;
- pdb_op_rd_regs_p regs = &resp->u.rd_regs;
-
- for (loop = 0; loop < GDB_REGISTER_FRAME_SIZE * 8; loop += 8)
- {
- sprintf(&msg[loop], "%08x", _flip(regs->reg[loop >> 3]));
- }
-
- break;
- }
- case PDB_OPCODE_WR_REG :
- {
- /* should check the return status */
- break;
- }
-
- case PDB_OPCODE_RD_MEM :
- {
- int loop;
- pdb_op_rd_mem_resp_p mem = &resp->u.rd_mem;
-
- for (loop = 0; loop < mem->length; loop ++)
- {
- sprintf(&msg[loop * 2], "%02x", mem->data[loop]);
- }
- break;
- }
- case PDB_OPCODE_WR_MEM :
- {
- /* should check the return status */
- break;
- }
-
- /* this is equivalent to process_xen_virq */
- case PDB_OPCODE_CONTINUE :
- {
- sprintf(msg, "S05");
- break;
- }
- case PDB_OPCODE_STEP :
- {
- sprintf(msg, "S05");
- break;
- }
-
- case PDB_OPCODE_SET_BKPT :
- case PDB_OPCODE_CLR_BKPT :
- case PDB_OPCODE_SET_WATCHPT :
- case PDB_OPCODE_CLR_WATCHPT :
- {
- break;
- }
-
- case PDB_OPCODE_WATCHPOINT :
- {
- sprintf(msg, "S05");
- break;
- }
-
- default :
- printf("(linux) UNKNOWN MESSAGE TYPE IN RESPONSE %d\n",
- resp->operation);
- break;
- }
-
- my_ring->rsp_cons++;
- }
-
- msglen = strlen(msg);
- result = caml_alloc(3,0);
- str = alloc_string(msglen);
- memmove(&Byte(str,0), msg, msglen);
-
- Store_field(result, 0, Val_int(resp->domain));
- Store_field(result, 1, Val_int(resp->process));
- Store_field(result, 2, str);
-
- CAMLreturn(result);
-}
-
-/*
- * proc_attach_debugger : context_t -> unit
- */
-value
-proc_attach_debugger (value context)
-{
- CAMLparam1(context);
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_ATTACH;
- req.u.attach.domain = ctx.domain;
- req.process = ctx.process;
-
- send_request (ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_detach_debugger : context_t -> unit
- */
-value
-proc_detach_debugger (value context)
-{
- CAMLparam1(context);
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- printf("(pdb) detach process [%d.%d] %d %p\n", ctx.domain, ctx.process,
- ctx.evtchn, ctx.ring);
- fflush(stdout);
-
- req.operation = PDB_OPCODE_DETACH;
- req.process = ctx.process;
-
- send_request (ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_pause_target : int -> unit
- */
-value
-proc_pause_target (value context)
-{
- CAMLparam1(context);
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- printf("(pdb) pause target %d %d\n", ctx.domain, ctx.process);
- fflush(stdout);
-
- req.operation = PDB_OPCODE_PAUSE;
- req.process = ctx.process;
-
- send_request (ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_read_register : context_t -> int -> unit
- */
-value
-proc_read_register (value context, value reg)
-{
- CAMLparam1(context);
-
- pdb_request_t req;
- context_t ctx;
- int my_reg = Int_val(reg);
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_RD_REG;
- req.process = ctx.process;
- req.u.rd_reg.reg = my_reg;
- req.u.rd_reg.value = 0;
-
- send_request (ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-
-/*
- * proc_read_registers : context_t -> unit
- */
-value
-proc_read_registers (value context)
-{
- CAMLparam1(context);
-
- pdb_request_t req;
- context_t ctx;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_RD_REGS;
- req.process = ctx.process;
-
- send_request (ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_write_register : context_t -> register -> int32 -> unit
- */
-value
-proc_write_register (value context, value reg, value newval)
-{
- CAMLparam3(context, reg, newval);
-
- int my_reg = Int_val(reg);
- unsigned long my_newval = Int32_val(newval);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_WR_REG;
- req.process = ctx.process;
- req.u.wr_reg.value = my_newval;
-
- switch (my_reg)
- {
- case GDB_EAX: req.u.wr_reg.reg = LINUX_EAX; break;
- case GDB_ECX: req.u.wr_reg.reg = LINUX_ECX; break;
- case GDB_EDX: req.u.wr_reg.reg = LINUX_EDX; break;
- case GDB_EBX: req.u.wr_reg.reg = LINUX_EBX; break;
-
- case GDB_ESP: req.u.wr_reg.reg = LINUX_ESP; break;
- case GDB_EBP: req.u.wr_reg.reg = LINUX_EBP; break;
- case GDB_ESI: req.u.wr_reg.reg = LINUX_ESI; break;
- case GDB_EDI: req.u.wr_reg.reg = LINUX_EDI; break;
-
- case GDB_EIP: req.u.wr_reg.reg = LINUX_EIP; break;
- case GDB_EFL: req.u.wr_reg.reg = LINUX_EFL; break;
-
- case GDB_CS: req.u.wr_reg.reg = LINUX_CS; break;
- case GDB_SS: req.u.wr_reg.reg = LINUX_SS; break;
- case GDB_DS: req.u.wr_reg.reg = LINUX_DS; break;
- case GDB_ES: req.u.wr_reg.reg = LINUX_ES; break;
- case GDB_FS: req.u.wr_reg.reg = LINUX_FS; break;
- case GDB_GS: req.u.wr_reg.reg = LINUX_GS; break;
- }
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_read_memory : context_t -> int32 -> int -> unit
- */
-value
-proc_read_memory (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_RD_MEM;
- req.process = ctx.process;
- req.u.rd_mem.address = Int32_val(address);
- req.u.rd_mem.length = Int_val(length);
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_write_memory : context_t -> int32 -> int list -> unit
- */
-value
-proc_write_memory (value context, value address, value val_list)
-{
- CAMLparam3(context, address, val_list);
- CAMLlocal1(node);
-
- context_t ctx;
- pdb_request_t req;
- uint32_t length = 0;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_WR_MEM;
- req.process = ctx.process;
-
- node = val_list;
- if ( Int_val(node) == 0 ) /* gdb functionalty test uses empty list */
- {
- req.u.wr_mem.address = Int32_val(address);
- req.u.wr_mem.length = 0;
- }
- else
- {
- while ( Int_val(Field(node,1)) != 0 )
- {
- req.u.wr_mem.data[length++] = Int_val(Field(node, 0));
- node = Field(node,1);
- }
- req.u.wr_mem.data[length++] = Int_val(Field(node, 0));
-
- req.u.wr_mem.address = Int32_val(address);
- req.u.wr_mem.length = length;
- }
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * proc_continue_target : context_t -> unit
- */
-value
-proc_continue_target (value context)
-{
- CAMLparam1(context);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_CONTINUE;
- req.process = ctx.process;
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * proc_step_target : context_t -> unit
- */
-value
-proc_step_target (value context)
-{
- CAMLparam1(context);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_STEP;
- req.process = ctx.process;
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-
-/*
- * proc_insert_memory_breakpoint : context_t -> int32 -> int -> unit
- */
-value
-proc_insert_memory_breakpoint (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_SET_BKPT;
- req.process = ctx.process;
- req.u.bkpt.address = (unsigned long) Int32_val(address);
- req.u.bkpt.length = Int_val(length);
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * proc_remove_memory_breakpoint : context_t -> int32 -> int -> unit
- */
-value
-proc_remove_memory_breakpoint (value context, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_CLR_BKPT;
- req.process = ctx.process;
- req.u.bkpt.address = (unsigned long) Int32_val(address);
- req.u.bkpt.length = Int_val(length);
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * proc_insert_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
- */
-value
-proc_insert_watchpoint (value context, value kind, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_SET_WATCHPT;
- req.process = ctx.process;
- req.u.watchpt.type = Int_val(kind);
- req.u.watchpt.address = (unsigned long) Int32_val(address);
- req.u.watchpt.length = Int_val(length);
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * proc_remove_watchpoint : context_t -> bwcpoint_t -> int32 -> int -> unit
- */
-value
-proc_remove_watchpoint (value context, value kind, value address, value length)
-{
- CAMLparam3(context, address, length);
-
- context_t ctx;
- pdb_request_t req;
-
- decode_context(&ctx, context);
-
- req.operation = PDB_OPCODE_CLR_WATCHPT;
- req.process = ctx.process;
- req.u.watchpt.type = Int_val(kind);
- req.u.watchpt.address = (unsigned long) Int32_val(address);
- req.u.watchpt.length = Int_val(length);
-
- send_request(ctx.ring, ctx.evtchn, &req);
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
-
diff --git a/tools/debugger/pdb/pdb_caml_xc.c b/tools/debugger/pdb/pdb_caml_xc.c
deleted file mode 100644
index 6a1fe8e492..0000000000
--- a/tools/debugger/pdb/pdb_caml_xc.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * pdb_caml_xc.c
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * PDB's OCaml interface library for debugging domains
- */
-
-#include <xenctrl.h>
-#include <xendebug.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-#include "pdb_caml_xen.h"
-
-int xc_handle = -1;
-
-
-/****************************************************************************/
-
-/*
- * open_context : unit -> unit
- */
-value
-open_context (value unit)
-{
- CAMLparam1(unit);
-
- xc_handle = xc_interface_open();
-
- if ( xc_handle < 0 )
- {
- fprintf(stderr, "(pdb) error opening xc interface: %d (%s)\n",
- errno, strerror(errno));
- }
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * close_context : unit -> unit
- */
-value
-close_context (value unit)
-{
- CAMLparam1(unit);
- int rc;
-
- if ( (rc = xc_interface_close(xc_handle)) < 0 )
- {
- fprintf(stderr, "(pdb) error closing xc interface: %d (%s)\n",
- errno, strerror(errno));
- }
-
- CAMLreturn(Val_unit);
-}
-
-
-/*********************************************************************/
-
-void
-dump_regs (cpu_user_regs_t *regs)
-{
- printf (" eax: %x\n", regs->eax);
- printf (" ecx: %x\n", regs->ecx);
- printf (" edx: %x\n", regs->edx);
- printf (" ebx: %x\n", regs->ebx);
- printf (" esp: %x\n", regs->esp);
- printf (" ebp: %x\n", regs->ebp);
- printf (" esi: %x\n", regs->esi);
- printf (" edi: %x\n", regs->edi);
- printf (" eip: %x\n", regs->eip);
- printf (" flags: %x\n", regs->eflags);
- printf (" cs: %x\n", regs->cs);
- printf (" ss: %x\n", regs->ss);
- printf (" es: %x\n", regs->es);
- printf (" ds: %x\n", regs->ds);
- printf (" fs: %x\n", regs->fs);
- printf (" gs: %x\n", regs->gs);
-
- return;
-}
-
-/*
- * debugger_status : unit -> unit
- */
-value
-debugger_status (value unit)
-{
- CAMLparam1(unit);
-
- CAMLreturn(Val_unit);
-}
-
-/****************************************************************************/
-/****************************************************************************/
-
-/*
- * evtchn_bind_virq : int -> int
- */
-value
-evtchn_bind_virq (value virq)
-{
- CAMLparam1(virq);
-
- int port;
- int my_virq = Int_val(virq);
-
- if ( xc_evtchn_bind_virq(xc_handle, my_virq, &port) < 0 )
- {
- printf("(pdb) evtchn_bind_virq error!\n"); fflush(stdout);
- failwith("evtchn_bind_virq error");
- }
-
- CAMLreturn(Val_int(port));
-}
-
-/*
- * evtchn_bind_interdomain : int -> int * int
- */
-value
-evtchn_bind_interdomain (value remote_domain)
-{
- CAMLparam1(remote_domain);
- CAMLlocal1(result);
-
- int my_remote_domain = Int_val(remote_domain);
- int local_domain = 0;
- int local_port = 0;
- int remote_port = 0;
-
- if ( xc_evtchn_bind_interdomain(xc_handle, local_domain, my_remote_domain,
- &local_port, &remote_port) < 0 )
- {
- printf("(pdb) evtchn_bind_interdomain error!\n"); fflush(stdout);
- failwith("evtchn_bind_interdomain error");
- }
-
- result = caml_alloc_tuple(2); /* FIXME */
- Store_field(result, 0, Val_int(local_port));
- Store_field(result, 1, Val_int(remote_port));
-
- CAMLreturn(result);
-}
-
-void *
-map_ring(uint32_t dom, unsigned long mfn )
-{
- return xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
- PROT_READ | PROT_WRITE, mfn);
-}
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/pdb_caml_xcs.c b/tools/debugger/pdb/pdb_caml_xcs.c
deleted file mode 100644
index d4ce1cdb4e..0000000000
--- a/tools/debugger/pdb/pdb_caml_xcs.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * xcs stuff
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * this is responsible for establishing the initial connection
- * between a backend domain and the pdb server.
- *
- * liberated from xu.c
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/un.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <xenctrl.h>
-
-#include <xen/xen.h>
-#include <xen/io/domain_controller.h>
-
-#include <arpa/inet.h>
-#include <xcs_proto.h>
-
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-static int control_fd = -1;
-
-#include "pdb_module.h"
-#include "pdb_caml_xen.h"
-
-void *map_ring(uint32_t dom, unsigned long mfn );
-
-/*
- * xcs_initialize_ring : int -> int32 -> int32
- *
- * initialize a communications ring
- * (probably belongs in a different file :)
- */
-
-value
-xcs_initialize_ring (value domain, value ring)
-{
- CAMLparam2(domain, ring);
- int my_domain = Int_val(domain);
- unsigned long my_ring = Int32_val(ring);
-
- pdb_front_ring_t *front_ring;
- pdb_sring_t *sring;
-
- front_ring = (pdb_front_ring_t *)malloc(sizeof(pdb_front_ring_t));
- if ( front_ring == NULL )
- {
- printf("(pdb) xcs initialize ring: malloc failed.\n"); fflush(stdout);
- failwith("xcs initialize ring: malloc");
- }
-
- sring = map_ring(my_domain, my_ring);
- if ( sring == NULL )
- {
- printf("(pdb) xcs initialize ring: map ring failed.\n");fflush(stdout);
- failwith("xcs initialize ring: map ring");
- }
- FRONT_RING_INIT(front_ring, sring, PAGE_SIZE);
-
- CAMLreturn(caml_copy_int32((unsigned long)front_ring));
-}
-
-
-/*
- * xcs_write_message : Unix.file_descr -> xcs_message -> unit
- *
- * ack a packet
- */
-value
-xcs_write_message (value data_fd, value msg)
-{
- CAMLparam2(data_fd, msg);
- int my_data_fd = Int_val(data_fd);
- xcs_msg_t my_msg;
- pdb_connection_p conn;
-
- my_msg.type = XCS_REQUEST;
- my_msg.u.control.remote_dom = Int_val(Field(msg,0));
- my_msg.u.control.msg.type = CMSG_DEBUG;
- my_msg.u.control.msg.subtype = CMSG_DEBUG_CONNECTION_STATUS;
- my_msg.u.control.msg.id = 0;
- my_msg.u.control.msg.length = sizeof(pdb_connection_t);
-
- conn = (pdb_connection_p)my_msg.u.control.msg.msg;
-
- conn->status = Int_val(Field(msg,1));
- conn->ring = Int32_val(Field(msg,2));
- conn->evtchn = Int_val(Field(msg,3));
-
- send(my_data_fd, &my_msg, sizeof(xcs_msg_t), 0); /* ack */
-
- CAMLreturn(Val_unit);
-}
-
-/*
- * xcs_read_message : Unix.file_descr -> xcs_message
- *
- * read pending data on xcs socket.
- */
-
-value
-xcs_read_message (value data_fd)
-{
- CAMLparam1(data_fd);
- CAMLlocal1(result);
- int my_data_fd = Int_val(data_fd);
- xcs_msg_t msg;
-
- if ( read(my_data_fd, &msg, sizeof(xcs_msg_t)) < 0 )
- {
- perror("read");
- failwith("xcs message: read");
- }
-
- switch (msg.type)
- {
- case XCS_REQUEST :
- {
- pdb_connection_p conn;
-
- if ( msg.u.control.msg.type != CMSG_DEBUG ||
- msg.u.control.msg.subtype != CMSG_DEBUG_CONNECTION_STATUS )
- {
- printf("bogus message type: %d %d\n",
- msg.u.control.msg.type, msg.u.control.msg.subtype);
- failwith("xcs message: invalid message type");
- }
-
- conn = (pdb_connection_p) msg.u.control.msg.msg;
-
- result = caml_alloc_tuple(4); /* FIXME */
- Store_field(result, 0, Val_int(msg.u.control.remote_dom)); /* domain */
- Store_field(result, 1, Val_int(conn->status)); /* status */
- Store_field(result, 2, caml_copy_int32(conn->ring)); /* ring */
- Store_field(result, 3, Val_int(0)); /* OUT: evtchn */
-
- break;
- }
- case XCS_RESPONSE :
- {
- printf("[XCS RESPONSE] type: %d, remote_dom: %d\n",
- msg.type, msg.u.control.remote_dom);
- printf("strange. we never initiate messages, so what is the ");
- printf("domain responding to?\n");
- failwith ("xcs message: resonse");
- break;
- }
- default:
- {
- printf("[XCS IGNORE] type: %d\n", msg.type);
- failwith ("xcs message: unknown");
- break;
- }
- }
-
- CAMLreturn(result);
-}
-
-/*
- * xcs_connect : string -> int -> Unix.file_descr
- */
-
-value
-xcs_connect (value path, value msg_type)
-{
- CAMLparam2(path, msg_type);
- char *my_path = String_val(path);
- int my_msg_type = Int_val(msg_type);
- struct sockaddr_un addr;
- uint32_t session_id = 0;
- int data_fd;
- int ret, len;
- xcs_msg_t msg;
-
- /* setup control channel connection to xcs */
-
- control_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if ( control_fd < 0 )
- {
- printf("error creating xcs socket!\n");
- goto fail;
- }
-
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, my_path);
- len = sizeof(addr.sun_family) + strlen(addr.sun_path) + 1;
-
- ret = connect(control_fd, (struct sockaddr *)&addr, len);
- if (ret < 0)
- {
- printf("error connecting to xcs (ctrl)! (%d)\n", errno);
- goto ctrl_fd_fail;
- }
-
- msg.type = XCS_CONNECT_CTRL;
- msg.u.connect.session_id = session_id;
- send(control_fd, &msg, sizeof(xcs_msg_t), 0);
- /* bug: this should have a timeout & error! */
- read(control_fd, &msg, sizeof(xcs_msg_t));
-
- if (msg.result != XCS_RSLT_OK)
- {
- printf("error connecting xcs control channel!\n");
- goto ctrl_fd_fail;
- }
- session_id = msg.u.connect.session_id;
-
-
- /* setup data channel connection to xcs */
-
- data_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if ( data_fd < 0 )
- {
- printf("error creating xcs data socket!\n");
- goto ctrl_fd_fail;
- }
-
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, my_path);
- len = sizeof(addr.sun_family) + strlen(addr.sun_path) + 1;
-
- ret = connect(data_fd, (struct sockaddr *)&addr, len);
- if (ret < 0)
- {
- printf("error connecting to xcs (data)! (%d)\n", errno);
- goto data_fd_fail;
- }
-
- msg.type = XCS_CONNECT_DATA;
- msg.u.connect.session_id = session_id;
- send(data_fd, &msg, sizeof(xcs_msg_t), 0);
- read(data_fd, &msg, sizeof(xcs_msg_t)); /* same bug */
-
- if ( msg.result != XCS_RSLT_OK )
- {
- printf("error connecting xcs control channel!\n");
- goto ctrl_fd_fail;
- }
-
-
-
- /* now request all messages of a particular type */
-
- msg.type = XCS_MSG_BIND;
- msg.u.bind.port = PORT_WILDCARD;
- msg.u.bind.type = my_msg_type;
- send(control_fd, &msg, sizeof(xcs_msg_t), 0);
- read(control_fd, &msg, sizeof(xcs_msg_t)); /* still buggy */
-
- if (msg.result != XCS_RSLT_OK) {
- printf ("error: MSG BIND\n");
- goto bind_fail;
- }
-
- CAMLreturn(Val_int(data_fd));
-
-bind_fail:
-data_fd_fail:
- close(data_fd);
-
-ctrl_fd_fail:
- close(control_fd);
-
-fail:
- failwith("xcs connection error"); /* should be more explicit */
-}
-
-
-/* xcs_disconnect: Unix.file_descr -> unit */
-
-value
-xcs_disconnect (value data_fd)
-{
- CAMLparam1(data_fd);
-
- int my_data_fd = Int_val(data_fd);
-
- close(my_data_fd);
- close(control_fd);
- control_fd = -1;
-
- CAMLreturn(Val_unit);
-}
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
-
diff --git a/tools/debugger/pdb/pdb_caml_xen.h b/tools/debugger/pdb/pdb_caml_xen.h
deleted file mode 100644
index c31ef8ed94..0000000000
--- a/tools/debugger/pdb/pdb_caml_xen.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * pdb_caml_xen.h
- *
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * generic xen definitions
- *
- */
-
-#ifndef _PDB_CAML_XEN_DEFINED_
-#define _PDB_CAML_XEN_DEFINED_
-
-enum gdb_registers { /* 32 */ GDB_EAX, GDB_ECX, GDB_EDX, GDB_EBX,
- GDB_ESP, GDB_EBP, GDB_ESI, GDB_EDI,
- GDB_EIP, GDB_EFL,
- /* 16 */ GDB_CS, GDB_SS, GDB_DS, GDB_ES,
- GDB_FS, GDB_GS };
-#define GDB_REGISTER_FRAME_SIZE 16
-
-/* this order comes from linux-2.6.11/include/asm-i386/ptrace.h */
-enum x86_registers { LINUX_EBX, LINUX_ECX, LINUX_EDX, LINUX_ESI, LINUX_EDI,
- LINUX_EBP, LINUX_EAX, LINUX_DS, LINUX_ES, LINUX_FS,
- LINUX_GS, LINUX_ORIG_EAX, LINUX_EIP, LINUX_CS, LINUX_EFL,
- LINUX_ESP, LINUX_SS };
-#define REGISTER_FRAME_SIZE 17
-
-
-/* hack: this is also included from the pdb linux module which
- has PAGE_SIZE defined */
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
-extern int xc_handle;
-
-void dump_regs (cpu_user_regs_t *ctx);
-
-#endif
-
diff --git a/tools/debugger/pdb/pdb_xen.c b/tools/debugger/pdb/pdb_xen.c
deleted file mode 100644
index b2c994c188..0000000000
--- a/tools/debugger/pdb/pdb_xen.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * pdb_xen.c
- *
- * alex ho
- * http://www.cl.cam.ac.uk/netos/pdb
- *
- * PDB interface library for accessing Xen
- */
-
-#include <xenctrl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/mman.h>
-
-int
-pdb_open ()
-{
- int xc_handle = xc_interface_open();
-
- if ( xc_handle < 0 )
- {
- fprintf(stderr, "(pdb) error opening xc interface: %d (%s)\n",
- errno, strerror(errno));
- }
- return xc_handle;
-}
-
-int
-pdb_close (int xc_handle)
-{
- int rc;
-
-
- if ( (rc = xc_interface_close(xc_handle)) < 0 )
- {
- fprintf(stderr, "(pdb) error closing xc interface: %d (%s)\n",
- errno, strerror(errno));
- }
- return rc;
-}
-
-
-#include <sys/ioctl.h>
-#include <xen/linux/evtchn.h>
-
-int
-xen_evtchn_bind (int evtchn_fd, int idx)
-{
- if ( ioctl(evtchn_fd, EVTCHN_BIND, idx) != 0 )
- return -errno;
-
- return 0;
-}
-
-int
-xen_evtchn_unbind (int evtchn_fd, int idx)
-{
- if ( ioctl(evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
- return -errno;
-
- return 0;
-}
-
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/tools/debugger/pdb/readme b/tools/debugger/pdb/readme
deleted file mode 100644
index 6ea537b404..0000000000
--- a/tools/debugger/pdb/readme
+++ /dev/null
@@ -1,105 +0,0 @@
-
-PDB 0.3.3
-http://www.cl.cam.ac.uk/netos/pdb
-
-Alex Ho
-August 2005
-
-
-This is the latest incarnation of the pervasive debugger.
-PDB is a remote stub for GDB. Running as a user-space
-application in domain 0, it can debug any other domain.
-
-
-+------+ tcp/ip +-------+
-| GDB |--------------| PDB |
-+------+ +-------+ +-------+
- | Dom 0 | | Dom U |
- +-------+---+-------+
- | Xen |
- +-------------------+
-
-Installation
-
-- Install OCaml 3.08 in domain 0.
- http://caml.inria.fr/download.en.html is a good place to start.
-
-- Build Xen with debugger support
- make domu_debug=y xen
-
-- (optional)
- Build the target domains with debugging symbols.
- make CONFIG_DEBUG_INFO=true CONFIG_FRAME_POINTER=false linux-2.6-xenU-build
-
- You can also change linux-2.6.12-xenU/Makefile
- CONFIG_CC_OPTIMIZE_FOR_SIZE from -O2 to -O
-
-- Build PDB
- (cd tools/debugger/libxendebug; make install)
- (cd tools/debugger/pdb; make)
-
-Usage
-
-- PDB does not currently support SMP. Please boot xen with "maxcpus=1"
-
-- Run PDB
- domain-0.xeno# ./pdb <port>
-
-- Run GDB
- hostname% gdb <xeno.bk>/dist/install/boot/vmlinux-syms-2.6.12-xenU
-
- (gdb) target remote domain-0.xeno:<port>
-
- At this point, you'll get an error message such as:
- Remote debugging using domain-0.xeno:5000
- 0x00000000 in ?? ()
- warning: shared library handler failed to enable breakpoint
- Although GDB is connected to PDB, PDB doesn't know which domain
- you'd like to debug, so it's just feeding GDB a bunch of zeros.
-
- (gdb) maint packet x context = domain <domid> <vcpu>
-
- This tells PDB that we'd like to debug a particular domain & vcpu.
- However, since we're sending the command directly to PDB, GDB doesn't
- know that we now have a proper target. We can force GDB to invalidate
- its register cache. This is optional; the next time the program
- stops GDB will query for the registers automatically.
-
- (gdb) flushreg
-
-
- the following gdb commands should work :)
-
- break
- step, stepi
- next, nexti
- continue
- print
-
-Process
-
- PDB can also debug a process running in a Linux 2.6 domain.
- You will need to patch the Linux 2.6 domain U tree to export some
- additional symbols for the pdb module
-
- % make -C linux-2.6-patches
-
- After running PDB in domain 0, insert the pdb module in dom u:
-
- % insmod linux-2.6-module/pdb.ko
-
- Load GDB with the appropriate symbols, and attach with
-
- (gdb) maint packet x context = process <domid> <pid>
-
- Read, write, and access watchpoint should also work for processes,
- use the "rwatch", "watch" and "awatch" gdb commands respectively.
-
- If you are having trouble with GDB 5.3 (i386-redhat-linux-gnu),
- try GDB 6.3 (configured with --target=i386-linux-gnu).
-
-
-To Do
-
-- watchpoints for domains
-- support for SMP
diff --git a/tools/debugger/pdb/server.ml b/tools/debugger/pdb/server.ml
deleted file mode 100644
index b2f7f0be81..0000000000
--- a/tools/debugger/pdb/server.ml
+++ /dev/null
@@ -1,241 +0,0 @@
-(** server.ml
- *
- * PDB server main loop
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Unix
-open Buffer
-open Util
-
-(**
- * connection_t: The state for each connection.
- * buffer & length contains bytes that have been read from the sock
- * but not yet parsed / processed.
- *)
-type connection_t =
-{
- fd : file_descr;
- mutable buffer : string;
- mutable length : int;
-}
-
-
-(**
- * validate_checksum: Compute and compare the checksum of a string
- * against the provided checksum using the gdb serial protocol algorithm.
- *
- *)
-let validate_checksum command checksum =
- let c0 = ref 0 in
- for loop = 0 to (String.length command - 1) do
- c0 := !c0 + int_of_char(command.[loop]);
- done;
- if (String.length checksum) = 2
- then
- let c1 = Util.int_of_hexchar(checksum.[1]) +
- Util.int_of_hexchar(checksum.[0]) * 16 in
- (!c0 mod 256) = (c1 mod 256)
- else
- false
-
-
-(**
- * process_input: Oh, joy! Someone sent us a message. Let's open the
- * envelope and see what they have to say.
- *
- * This function is a paradigm of inefficiency; it performs as many
- * string copies as possible.
- *)
-let process_input conn sock =
- let max_buffer_size = 1024 in
- let in_string = String.create max_buffer_size in
-
- let length = read sock in_string 0 max_buffer_size in
- conn.buffer <- conn.buffer ^ (String.sub in_string 0 length);
- conn.length <- conn.length + length;
- let re = Str.regexp "[^\\$]*\\$\\([^#]*\\)#\\(..\\)" in
-
- (* interrupt the target if there was a ctrl-c *)
- begin
- try
- let break = String.index conn.buffer '\003' + 1 in
- print_endline (Printf.sprintf "{{%s}}" (String.escaped conn.buffer));
-
- (* discard everything seen before the ctrl-c *)
- conn.buffer <- String.sub conn.buffer break (conn.length - break);
- conn.length <- conn.length - break;
-
- (* pause the target *)
- PDB.pause (PDB.find_context sock);
-
- (* send a code back to the debugger *)
- Util.send_reply sock "S05"
-
- with
- Not_found -> ()
- end;
-
- (* with gdb this is unlikely to loop since you ack each packet *)
- while ( Str.string_match re conn.buffer 0 ) do
- let command = Str.matched_group 1 conn.buffer in
- let checksum = Str.matched_group 2 conn.buffer in
- let match_end = Str.group_end 2 in
-
- begin
- match validate_checksum command checksum with
- | true ->
- begin
- Util.write_character sock '+';
- try
- let reply = Debugger.process_command command sock in
- print_endline (Printf.sprintf "[%s] %s -> \"%s\""
- (Util.get_connection_info sock)
- (String.escaped command)
- (String.escaped reply));
- Util.send_reply sock reply
- with
- Util.No_reply ->
- print_endline (Printf.sprintf "[%s] %s -> null"
- (Util.get_connection_info sock)
- (String.escaped command))
- end
- | false ->
- Util.write_character sock '-';
- end;
-
- conn.buffer <- String.sub conn.buffer match_end (conn.length - match_end);
- conn.length <- conn.length - match_end;
- done;
- if length = 0 then raise End_of_file
-
-
-
-(** main_server_loop.
- *
- * connection_hash is a hash (duh!) with one connection_t for each
- * open connection.
- *
- * in_list is a list of active sockets. it also contains a number
- * of magic entries:
- * - server_sock for accepting new client connections (e.g. gdb)
- * - xen_virq_sock for Xen virq asynchronous notifications (via evtchn).
- * This is used by context = domain
- * - xcs_sock for xcs messages when a new backend domain registers
- * This is used by context = process
- *)
-let main_server_loop sockaddr =
- let connection_hash = Hashtbl.create 10
- in
- let process_socket svr_sock sockets sock =
- let (new_list, closed_list) = sockets in
- if sock == svr_sock
- then
- begin
- let (new_sock, caller) = accept sock in
- print_endline (Printf.sprintf "[%s] new connection from %s"
- (Util.get_connection_info sock)
- (Util.get_connection_info new_sock));
- Hashtbl.add connection_hash new_sock
- {fd=new_sock; buffer=""; length = 0};
- PDB.add_default_context new_sock;
- (new_sock :: new_list, closed_list)
- end
- else
- begin
- try
- match PDB.find_context sock with
- | PDB.Xen_virq ->
- print_endline (Printf.sprintf "[%s] Xen virq"
- (Util.get_connection_info sock));
- Debugger.process_xen_virq sock;
- (new_list, closed_list)
- | PDB.Xen_xcs ->
- print_endline (Printf.sprintf "[%s] Xen xcs"
- (Util.get_connection_info sock));
- let new_xen_domain = Debugger.process_xen_xcs sock in
- (new_xen_domain :: new_list, closed_list)
- | PDB.Xen_domain d ->
- print_endline (Printf.sprintf "[%s] Xen domain"
- (Util.get_connection_info sock));
- Debugger.process_xen_domain sock;
- (new_list, closed_list)
- | _ ->
- let conn = Hashtbl.find connection_hash sock in
- process_input conn sock;
- (new_list, closed_list)
- with
- | Not_found ->
- print_endline "error: (main_svr_loop) context not found";
- PDB.debug_contexts ();
- raise Not_found
- | End_of_file ->
- print_endline (Printf.sprintf "[%s] close connection from %s"
- (Util.get_connection_info sock)
- (Util.get_connection_info sock));
- PDB.delete_context sock;
- Hashtbl.remove connection_hash sock;
- close sock;
- (new_list, sock :: closed_list)
- end
- in
-
- let rec helper in_list server_sock =
-
- (*
- List.iter (fun x->Printf.printf " {%s}\n"
- (Util.get_connection_info x)) in_list;
- Printf.printf "\n";
- *)
-
- let (rd_list, _, _) = select in_list [] [] (-1.0) in
- let (new_list, closed_list) = List.fold_left (process_socket server_sock)
- ([],[]) rd_list in
- let merge_list = Util.list_remove (new_list @ in_list) closed_list in
- helper merge_list server_sock
- in
-
- try
- let server_sock = socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
- setsockopt server_sock SO_REUSEADDR true;
- bind server_sock sockaddr;
- listen server_sock 2;
-
- PDB.open_debugger ();
- let xen_virq_sock = Evtchn.setup () in
- PDB.add_context xen_virq_sock "xen virq" [];
-
- let xcs_sock = Xcs.setup () in
- PDB.add_context xcs_sock "xen xcs" [];
- helper [server_sock; xen_virq_sock; xcs_sock] server_sock
- with
- | Sys.Break ->
- print_endline "break: cleaning up";
- PDB.close_debugger ();
- Hashtbl.iter (fun sock conn -> close sock) connection_hash
-(* | Unix_error(e,err,param) ->
- Printf.printf "unix error: [%s][%s][%s]\n" (error_message e) err param*)
- | Sys_error s -> Printf.printf "sys error: [%s]\n" s
- | Failure s -> Printf.printf "failure: [%s]\n" s
- | End_of_file -> Printf.printf "end of file\n"
-
-
-let get_port () =
- if (Array.length Sys.argv) = 2
- then
- int_of_string Sys.argv.(1)
- else
- begin
- print_endline (Printf.sprintf "error: %s <port>" Sys.argv.(0));
- exit 1
- end
-
-
-let main =
- let address = inet_addr_any in
- let port = get_port () in
- main_server_loop (ADDR_INET(address, port))
-
diff --git a/tools/debugger/pdb/xcs.ml b/tools/debugger/pdb/xcs.ml
deleted file mode 100644
index ce8eaee1da..0000000000
--- a/tools/debugger/pdb/xcs.ml
+++ /dev/null
@@ -1,85 +0,0 @@
-(** xcs.ml
- *
- * xen control switch interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-open Int32
-
-let xcs_path = "/var/lib/xen/xcs_socket" (* XCS_SUN_PATH *)
-let xcs_type = 11 (* CMSG_DEBUG *)
-
-
-type xcs_message =
- {
- domain : int;
- status : int;
- ring : int32;
- mutable evtchn : int;
- }
-
-external connect : string -> int -> Unix.file_descr = "xcs_connect"
-external disconnect : Unix.file_descr -> unit = "xcs_disconnect"
-external read_message : Unix.file_descr -> xcs_message = "xcs_read_message"
-external write_message : Unix.file_descr -> xcs_message -> unit =
- "xcs_write_message"
-external initialize_ring : int -> int32 -> int32 = "xcs_initialize_ring"
-
-(*
- * initialize xcs stuff
- *)
-let setup () =
- connect xcs_path xcs_type
-
-
-(*
- * adios
- *)
-let teardown fd =
- disconnect fd
-
-
-(*
- * message from a domain backend
- *)
-let read socket =
- let xcs = read_message socket in
- begin
- match xcs.status with
- | 1 -> (* PDB_CONNECTION_STATUS_UP *)
- begin
- print_endline (Printf.sprintf " new backend domain available (%d)"
- xcs.domain);
- let ring = initialize_ring xcs.domain xcs.ring in
-
- let (local_evtchn, remote_evtchn) =
- Evtchn.bind_interdomain xcs.domain in
-
- xcs.evtchn <- remote_evtchn;
- write_message socket xcs;
-
- let evtchn_fd = Evtchn._setup () in
- Evtchn._bind evtchn_fd local_evtchn;
-
- (evtchn_fd, local_evtchn, xcs.domain, ring)
- end
- | 2 -> (* PDB_CONNECTION_STATUS_DOWN *)
- begin
- (* TODO:
- unmap the ring
- unbind event channel xen_evtchn_unbind
- find the evtchn_fd for this domain and close it
- finally, need to failwith something
- *)
- print_endline (Printf.sprintf " close connection from domain %d"
- xcs.domain);
- (socket, 0, 0, 0l)
- end
- | _ ->
- failwith "xcs read: unknown xcs status"
- end
-
-
diff --git a/tools/debugger/pdb/xcs.mli b/tools/debugger/pdb/xcs.mli
deleted file mode 100644
index 2a76edfbc3..0000000000
--- a/tools/debugger/pdb/xcs.mli
+++ /dev/null
@@ -1,13 +0,0 @@
-(** xcs.mli
- *
- * xen control switch interface
- *
- * @author copyright (c) 2005 alex ho
- * @see <www.cl.cam.ac.uk/netos/pdb> pervasive debugger
- * @version 1
- *)
-
-
-val setup : unit -> Unix.file_descr
-val read : Unix.file_descr -> Unix.file_descr * int * int * int32
-val teardown : Unix.file_descr -> unit
diff --git a/tools/examples/Makefile b/tools/examples/Makefile
index cc5525c2a3..14f34135c8 100644
--- a/tools/examples/Makefile
+++ b/tools/examples/Makefile
@@ -1,11 +1,6 @@
XEN_ROOT = ../../
include $(XEN_ROOT)/tools/Rules.mk
-INSTALL = install
-INSTALL_DIR = $(INSTALL) -d -m0755
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-
# Init scripts.
XEND_INITD = init.d/xend
XENDOMAINS_INITD = init.d/xendomains
diff --git a/tools/examples/blktap b/tools/examples/blktap
index ba9f4ee52f..bc25b48be2 100644
--- a/tools/examples/blktap
+++ b/tools/examples/blktap
@@ -4,12 +4,26 @@
dir=$(dirname "$0")
. "$dir/xen-hotplug-common.sh"
+. "$dir/block-common.sh"
findCommand "$@"
-if [ "$command" == 'add' ]
+t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING')
+if [ -n "$t" ]
then
- success
+ p=$(xenstore_read "$XENBUS_PATH/params")
+ # if we have a ':', chew from head including :
+ if echo $p | grep -q \:
+ then
+ p=${p#*:}
+ fi
+fi
+file=$(readlink -f "$p") || ebusy "$p does not exist."
+
+if [ "$command" = 'add' ]
+then
+ [ -e "$file" ] || { ebusy $file does not exist; }
+ success
fi
exit 0
diff --git a/tools/examples/block b/tools/examples/block
index 14af64a66d..8ec73231bf 100644
--- a/tools/examples/block
+++ b/tools/examples/block
@@ -68,7 +68,7 @@ check_sharing()
local devmm=$(device_major_minor "$dev")
local file
- if [ "$mode" == 'w' ]
+ if [ "$mode" = 'w' ]
then
toskip="^$"
else
@@ -81,7 +81,7 @@ check_sharing()
then
local d=$(device_major_minor "$file")
- if [ "$d" == "$devmm" ]
+ if [ "$d" = "$devmm" ]
then
echo 'local'
return
@@ -96,9 +96,9 @@ check_sharing()
do
d=$(xenstore_read_default "$base_path/$dom/$dev/physical-device" "")
- if [ "$d" == "$devmm" ]
+ if [ "$d" = "$devmm" ]
then
- if [ "$mode" == 'w' ]
+ if [ "$mode" = 'w' ]
then
if ! same_vm $dom
then
@@ -109,7 +109,7 @@ check_sharing()
local m=$(xenstore_read "$base_path/$dom/$dev/mode")
m=$(canonicalise_mode "$m")
- if [ "$m" == 'w' ]
+ if [ "$m" = 'w' ]
then
if ! same_vm $dom
then
@@ -138,7 +138,7 @@ same_vm()
local othervm=$(xenstore_read_default "/local/domain/$otherdom/vm" \
"$FRONTEND_UUID")
- [ "$FRONTEND_UUID" == "$othervm" ]
+ [ "$FRONTEND_UUID" = "$othervm" ]
}
@@ -153,7 +153,7 @@ check_device_sharing()
local mode=$(canonicalise_mode "$2")
local result
- if [ "$mode" == '!' ]
+ if [ "x$mode" = 'x!' ]
then
return 0
fi
@@ -202,7 +202,7 @@ do_ebusy()
local mode="$2"
local result="$3"
- if [ "$result" == 'guest' ]
+ if [ "$result" = 'guest' ]
then
dom='a guest '
when='now'
@@ -211,7 +211,7 @@ do_ebusy()
when='by a guest'
fi
- if [ "$mode" == 'w' ]
+ if [ "$mode" = 'w' ]
then
m1=''
m2=''
@@ -266,7 +266,7 @@ case "$command" in
claim_lock "block"
- if [ "$mode" == 'w' ] && ! stat "$file" -c %A | grep -q w
+ if [ "$mode" = 'w' ] && ! stat "$file" -c %A | grep -q w
then
release_lock "block"
ebusy \
@@ -287,7 +287,7 @@ mount it read-write in a guest domain."
if [ "$f" ]
then
# $dev is in use. Check sharing.
- if [ "$mode" == '!' ]
+ if [ "x$mode" = 'x!' ]
then
continue
fi
@@ -307,7 +307,7 @@ mount it read-write in a guest domain."
do
d=$(xenstore_read_default \
"$XENBUS_BASE_PATH/$dom/$domdev/node" "")
- if [ "$d" == "$dev" ]
+ if [ "$d" = "$dev" ]
then
f=$(xenstore_read "$XENBUS_BASE_PATH/$dom/$domdev/params")
found=1
@@ -347,7 +347,7 @@ mount it read-write in a guest domain."
f=$(readlink -f "$f" || echo $(dirname "$file")/$(basename "$f"))
- if [ "$f" == "$file" ]
+ if [ "$f" = "$file" ]
then
check_file_sharing "$file" "$dev" "$mode"
fi
@@ -355,14 +355,14 @@ mount it read-write in a guest domain."
# $dev is not in use, so we'll remember it for use later; we want
# to finish the sharing check first.
- if [ "$loopdev" == '' ]
+ if [ "$loopdev" = '' ]
then
loopdev="$dev"
fi
fi
done
- if [ "$loopdev" == '' ]
+ if [ "$loopdev" = '' ]
then
fatal 'Failed to find an unused loop device'
fi
@@ -377,7 +377,6 @@ mount it read-write in a guest domain."
"")
claim_lock "block"
success
- echo happy gun \"$t\" >>/tmp/block.$$
release_lock "block"
;;
esac
diff --git a/tools/examples/external-device-migrate b/tools/examples/external-device-migrate
index 7d58454525..423c513930 100644
--- a/tools/examples/external-device-migrate
+++ b/tools/examples/external-device-migrate
@@ -55,41 +55,27 @@ function evaluate_params()
{
local step host domname typ recover filename func stype
stype=""
- while [ 1 ]; do
- if [ "$1" == "-step" ]; then
- shift
- step=$1
- elif [ "$1" == "-host" ]; then
- shift
- host=$1
- elif [ "$1" == "-domname" ]; then
- shift
- domname=$1
- elif [ "$1" == "-type" ]; then
- shift
- typ=$1
- elif [ "$1" == "-subtype" ]; then
- shift
- stype="_$1"
- elif [ "$1" == "-recover" ]; then
- recover=1
- elif [ "$1" == "-help" ]; then
- ext_dev_migrate_usage
- exit
- else
- break
- fi
- shift
+ while [ $# -ge 1 ]; do
+ case "$1" in
+ -step) step=$2; shift 2;;
+ -host) host=$2; shift 2;;
+ -domname) domname=$2; shift 2;;
+ -type) type=$2; shift 2;;
+ -subtype) subtype=$2; shift 2;;
+ -recover) recover=1; shift;;
+ -help) ext_dev_migrate_usage; exit 0;;
+ *) break;;
+ esac
done
- if [ "$step" == "" -o \
- "$host" == "" -o \
- "$typ" == "" -o \
- "$domname" == "" ]; then
- echo "Error: Parameter(s) missing (-step/-host/-type/-domname)"
- echo ""
- echo "$0 -help for usage."
- exit
+ if [ "$step" = "" -o \
+ "$host" = "" -o \
+ "$typ" = "" -o \
+ "$domname" = "" ]; then
+ echo "Error: Parameter(s) missing (-step/-host/-type/-domname)" 1>&2
+ echo "" 1>&2
+ echo "$0 -help for usage." 1>&2
+ exit 1
fi
filename="$dir/$typ$stype-migration.sh"
@@ -99,7 +85,7 @@ function evaluate_params()
fi
. "$filename"
- if [ "$recover" == "1" ]; then
+ if [ "$recover" = "1" ]; then
func="$typ"_recover
eval $func $host $domname $step $*
else
@@ -108,4 +94,4 @@ function evaluate_params()
fi
}
-evaluate_params $*
+evaluate_params "$@"
diff --git a/tools/examples/init.d/xendomains b/tools/examples/init.d/xendomains
index 358aac78df..b3722882d6 100644
--- a/tools/examples/init.d/xendomains
+++ b/tools/examples/init.d/xendomains
@@ -352,9 +352,9 @@ stop()
if test $? -ne 0; then
rc_failed $?
echo -n '!'
- kill $WDOG_PIG >/dev/null 2>&1
+ kill $WDOG_PID >/dev/null 2>&1
else
- kill $WDOG_PIG >/dev/null 2>&1
+ kill $WDOG_PID >/dev/null 2>&1
continue
fi
fi
@@ -368,7 +368,7 @@ stop()
rc_failed $?
echo -n '!'
fi
- kill $WDOG_PIG >/dev/null 2>&1
+ kill $WDOG_PID >/dev/null 2>&1
fi
done < <(xm list | grep -v '^Name')
diff --git a/tools/examples/locking.sh b/tools/examples/locking.sh
index 9dd2157452..6ff58e7e6c 100644
--- a/tools/examples/locking.sh
+++ b/tools/examples/locking.sh
@@ -21,7 +21,7 @@
LOCK_SLEEPTIME=1
LOCK_SPINNING_RETRIES=5
-LOCK_RETRIES=10
+LOCK_RETRIES=100
LOCK_BASEDIR=/var/run/xen-hotplug
diff --git a/tools/examples/vif-bridge b/tools/examples/vif-bridge
index c9d2b49316..7008210579 100755
--- a/tools/examples/vif-bridge
+++ b/tools/examples/vif-bridge
@@ -61,7 +61,7 @@ esac
handle_iptable
log debug "Successful vif-bridge $command for $vif, bridge $bridge."
-if [ "$command" == "online" ]
+if [ "$command" = "online" ]
then
success
fi
diff --git a/tools/examples/vif-common.sh b/tools/examples/vif-common.sh
index 8dc6d86ac2..50da9a4494 100644
--- a/tools/examples/vif-common.sh
+++ b/tools/examples/vif-common.sh
@@ -103,7 +103,7 @@ function handle_iptable()
if [ "$ip" != "" ]
then
local addr
- for addr in "$ip"
+ for addr in $ip
do
frob_iptable -s "$addr"
done
diff --git a/tools/examples/vif-nat b/tools/examples/vif-nat
index 0f1cb1c89f..29611654eb 100644
--- a/tools/examples/vif-nat
+++ b/tools/examples/vif-nat
@@ -72,7 +72,7 @@ dotted_quad()
}
-if [ "$ip" == "" ]
+if [ "$ip" = "" ]
then
ip=$(ip_from_dom)
fi
@@ -152,7 +152,7 @@ esac
handle_iptable
log debug "Successful vif-nat $command for $vif."
-if [ "$command" == "online" ]
+if [ "$command" = "online" ]
then
success
fi
diff --git a/tools/examples/vif-route b/tools/examples/vif-route
index 70ac49fc51..8d0fb8d76c 100755
--- a/tools/examples/vif-route
+++ b/tools/examples/vif-route
@@ -50,7 +50,7 @@ fi
handle_iptable
log debug "Successful vif-route $command for $vif."
-if [ "$command" == "online" ]
+if [ "$command" = "online" ]
then
success
fi
diff --git a/tools/examples/vtpm-common.sh b/tools/examples/vtpm-common.sh
index e5e8ddbbf5..bf50f323e3 100644
--- a/tools/examples/vtpm-common.sh
+++ b/tools/examples/vtpm-common.sh
@@ -226,7 +226,7 @@ function vtpmdb_remove_entry () {
# Returns 'resume' or 'create'
function vtpm_get_create_reason () {
local resume
- resume=$(xenstore-read $XENBUS_PATH/resume)
+ resume=$(xenstore_read $XENBUS_PATH/resume)
if [ "$resume" == "True" ]; then
echo "resume"
else
@@ -287,6 +287,8 @@ function vtpm_create_instance () {
#entry is kept in the VTPMDB file.
function vtpm_remove_instance () {
local instance reason domname
+ #Stop script execution quietly if path does not exist (anymore)
+ xenstore-exists "$XENBUS_PATH"/domain
domname=$(xenstore_read "$XENBUS_PATH"/domain)
if [ "$domname" != "" ]; then
@@ -383,7 +385,7 @@ function vtpm_domid_from_name () {
local id name ids
ids=$(xenstore-list /local/domain)
for id in $ids; do
- name=$(xenstore-read /local/domain/$id/name)
+ name=$(xenstore_read /local/domain/$id/name)
if [ "$name" == "$1" ]; then
echo "$id"
return
diff --git a/tools/examples/xen-backend.rules b/tools/examples/xen-backend.rules
index 2bd95d1a25..33064acdb6 100644
--- a/tools/examples/xen-backend.rules
+++ b/tools/examples/xen-backend.rules
@@ -5,3 +5,4 @@ SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} o
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", RUN+="$env{script} offline"
SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
KERNEL=="evtchn", NAME="xen/%k"
+KERNEL=="blktap[0-9]*", NAME="xen/%k"
diff --git a/tools/examples/xend-config.sxp b/tools/examples/xend-config.sxp
index 9dacf7d3c6..71d30bceb9 100644
--- a/tools/examples/xend-config.sxp
+++ b/tools/examples/xend-config.sxp
@@ -14,6 +14,42 @@
#(logfile /var/log/xen/xend.log)
#(loglevel DEBUG)
+
+# The Xen-API server configuration. (Please note that this server is
+# available as an UNSUPPORTED PREVIEW in Xen 3.0.4, and should not be relied
+# upon).
+#
+# This value configures the ports, interfaces, and access controls for the
+# Xen-API server. Each entry in the list starts with either unix, a port
+# number, or an address:port pair. If this is "unix", then a UDP socket is
+# opened, and this entry applies to that. If it is a port, then Xend will
+# listen on all interfaces on that TCP port, and if it is an address:port
+# pair, then Xend will listen on the specified port, using the interface with
+# the specified address.
+#
+# The subsequent string configures the user-based access control for the
+# listener in question. This can be one of "none" or "pam", indicating either
+# that users should be allowed access unconditionally, or that the local
+# Pluggable Authentication Modules configuration should be used. If this
+# string is missing or empty, then "pam" is used.
+#
+# The final string gives the host-based access control for that listener. If
+# this is missing or empty, then all connections are accepted. Otherwise,
+# this should be a space-separated sequence of regular expressions; any host
+# with a fully-qualified domain name or an IP address that matches one of
+# these regular expressions will be accepted.
+#
+# Example: listen on TCP port 9363 on all interfaces, accepting connections
+# only from machines in example.com or localhost, and allow access through
+# the unix domain socket unconditionally:
+#
+# (xen-api-server ((9363 pam '^localhost$ example\\.com$')
+# (unix none)))
+#
+# Default:
+# (xen-api-server ((unix)))
+
+
#(xend-http-server no)
#(xend-unix-server no)
#(xend-tcp-xmlrpc-server no)
@@ -51,7 +87,7 @@
# regular expressions will be accepted.
#
# For example:
-# (xend-relocation-hosts-allow '^localhost$ ^.*\.example\.org$')
+# (xend-relocation-hosts-allow '^localhost$ ^.*\\.example\\.org$')
#
#(xend-relocation-hosts-allow '')
(xend-relocation-hosts-allow '^localhost$ ^localhost\\.localdomain$')
@@ -130,3 +166,12 @@
# The tool used for initiating virtual TPM migration
#(external-migration-tool '')
+
+# The interface for VNC servers to listen on. Defaults
+# to 127.0.0.1 To restore old 'listen everywhere' behaviour
+# set this to 0.0.0.0
+#(vnc-listen '127.0.0.1')
+
+# The default password for VNC console on HVM domain.
+# Empty string is no authentication.
+(vncpasswd '')
diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm
index 731500225f..143252e65b 100644
--- a/tools/examples/xmexample.hvm
+++ b/tools/examples/xmexample.hvm
@@ -39,17 +39,18 @@ name = "ExampleHVMDomain"
#uuid = "06ed00fe-1162-4fc4-b5d8-11993ee4a8b9"
#-----------------------------------------------------------------------------
-# the number of cpus guest platform has, default=1
+# The number of cpus guest platform has, default=1
#vcpus=1
-# enable/disable HVM guest PAE, default=0 (disabled)
-#pae=0
+# Enable/disable HVM guest PAE, default=1 (enabled)
+#pae=1
-# enable/disable HVM guest ACPI, default=0 (disabled)
-#acpi=0
+# Enable/disable HVM guest ACPI, default=1 (enabled)
+#acpi=1
-# enable/disable HVM guest APIC, default=0 (disabled)
-#apic=0
+# Enable/disable HVM APIC mode, default=1 (enabled)
+# Note that this option is ignored if vcpus > 1
+#apic=1
# List of which CPUS this domain is allowed to use, default Xen picks
#cpus = "" # leave to Xen to pick
@@ -132,6 +133,11 @@ sdl=0
vnc=1
#----------------------------------------------------------------------------
+# address that should be listened on for the VNC server if vnc is set.
+# default is to use 'vnc-listen' setting from /etc/xen/xend-config.sxp
+#vnclisten="127.0.0.1"
+
+#----------------------------------------------------------------------------
# set VNC display number, default = domid
#vncdisplay=1
@@ -145,6 +151,11 @@ vnc=1
#vncconsole=0
#----------------------------------------------------------------------------
+# set password for domain's VNC console
+# default is depents on vncpasswd in xend-config.sxp
+vncpasswd=''
+
+#----------------------------------------------------------------------------
# no graphics, use serial port
#nographic=0
@@ -183,3 +194,7 @@ serial='pty'
# absolute mouse)
#usbdevice='mouse'
#usbdevice='tablet'
+
+#-----------------------------------------------------------------------------
+# Set keyboard layout, default is en-us keyboard.
+#keymap='ja'
diff --git a/tools/examples/xmexample.vti b/tools/examples/xmexample.vti
index 3a0d8e1a3a..a9ff77b4ce 100644
--- a/tools/examples/xmexample.vti
+++ b/tools/examples/xmexample.vti
@@ -95,6 +95,11 @@ vnc=0
#vncconsole=0
#----------------------------------------------------------------------------
+# set password for domain's VNC console
+# default is depents on vncpasswd in xend-config.sxp
+vncpasswd=''
+
+#----------------------------------------------------------------------------
# no graphics, use serial port
#nographic=0
@@ -129,3 +134,7 @@ serial='pty'
# absolute mouse)
#usbdevice='mouse'
#usbdevice='tablet'
+
+#-----------------------------------------------------------------------------
+# Set keyboard layout, default is en-us keyboard.
+#keymap='ja'
diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile
index 63ccb7b17e..eb734d987c 100644
--- a/tools/firmware/Makefile
+++ b/tools/firmware/Makefile
@@ -4,12 +4,11 @@ include $(XEN_ROOT)/tools/Rules.mk
# hvmloader is a 32-bit protected mode binary.
# It belongs in /usr/lib, not /usr/lib64.
TARGET := hvmloader/hvmloader
-INSTALL_DIR := $(DESTDIR)/usr/lib/xen/boot
+INST_DIR := $(DESTDIR)/usr/lib/xen/boot
SUBDIRS :=
SUBDIRS += rombios
SUBDIRS += vgabios
-SUBDIRS += acpi
SUBDIRS += vmxassist
SUBDIRS += hvmloader
@@ -29,8 +28,8 @@ all:
.PHONY: install
install: all
- [ -d $(INSTALL_DIR) ] || install -d -m0755 $(INSTALL_DIR)
- [ ! -e $(TARGET) ] || install -m0644 $(TARGET) $(INSTALL_DIR)
+ [ -d $(INST_DIR) ] || $(INSTALL_DIR) $(INST_DIR)
+ [ ! -e $(TARGET) ] || $(INSTALL_DATA) $(TARGET) $(INST_DIR)
.PHONY: clean
clean:
diff --git a/tools/firmware/acpi/Makefile b/tools/firmware/acpi/Makefile
deleted file mode 100644
index b87cb79a33..0000000000
--- a/tools/firmware/acpi/Makefile
+++ /dev/null
@@ -1,68 +0,0 @@
-#/*
-# * Copyright (c) 2004, 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.
-# *
-# */
-#
-
-XEN_ROOT = ../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-# Compiler flag
-HOSTCFLAGS += -I. -I../../libxc
-
-# TARGET
-C_SRC=$(shell ls *.c)
-H_SRC=$(shell ls *.h)
-ACPI_GEN=acpigen
-ACPI_BIN=acpi.bin
-
-IASL_VER=acpica-unix-20050513
-IASL_URL=http://developer.intel.com/technology/iapc/acpi/downloads/$(IASL_VER).tar.gz
-
-vpath iasl $(PATH)
-all:$(ACPI_BIN)
-
-acpi_dsdt.c:acpi_dsdt.asl
- $(MAKE) iasl
- iasl -tc acpi_dsdt.asl
- mv acpi_dsdt.hex acpi_dsdt.c
- echo "int DsdtLen=sizeof(AmlCode);" >> acpi_dsdt.c
- rm *.aml
-# iasl -oa -tc acpi_dsdt.asl
-
-iasl:
- @echo
- @echo "ACPI ASL compiler(iasl) is needed"
- @echo "Download Intel ACPI CA"
- @echo "If wget failed, please download and compile manually from"
- @echo "http://developer.intel.com/technology/iapc/acpi/downloads.htm"
- @echo
- wget $(IASL_URL)
- tar xzf $(IASL_VER).tar.gz
- make -C $(IASL_VER)/compiler
- install $(IASL_VER)/compiler/iasl /usr/bin/iasl
-
-$(ACPI_GEN):$(C_SRC) $(H_SRC) acpi_dsdt.c
- $(HOSTCC) -o $(ACPI_GEN) $(HOSTCFLAGS) $(shell ls *.c)
-
-$(ACPI_BIN):$(ACPI_GEN)
- ./$(ACPI_GEN) $(ACPI_BIN)
-
-clean:
- rm -rf *.o $(ACPI_GEN) $(ACPI_BIN) $(IASL_VER)
- rm -rf $(IASL_VER).tar.gz
-
-install: all
diff --git a/tools/firmware/acpi/acpi2_0.h b/tools/firmware/acpi/acpi2_0.h
deleted file mode 100644
index 709511df58..0000000000
--- a/tools/firmware/acpi/acpi2_0.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#ifndef _ACPI_2_0_H_
-#define _ACPI_2_0_H_
-
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef unsigned short uint16_t;
-typedef signed short int16_t;
-typedef unsigned int uint32_t;
-typedef signed int int32_t;
-#ifdef __i386__
-typedef unsigned long long uint64_t;
-typedef signed long long int64_t;
-#else
-typedef unsigned long uint64_t;
-typedef signed long int64_t;
-#endif
-
-#include <xen/xen.h>
-
-#pragma pack (1)
-
-//
-// common ACPI header.
-//
-
-typedef struct {
- uint32_t Signature;
- uint32_t Length;
- uint8_t Revision;
- uint8_t Checksum;
- uint8_t OemId[6];
- uint64_t OemTableId;
- uint32_t OemRevision;
- uint32_t CreatorId;
- uint32_t CreatorRevision;
-} ACPI_TABLE_HEADER;
-
-
-#define ACPI_OEM_ID {'I','N','T','E','L',' '}
-#define ACPI_OEM_TABLE_ID 0x544244 // "TBD"
-#define ACPI_OEM_REVISION 0x00000002
-#define ACPI_CREATOR_ID 0x00 // TBD
-#define ACPI_CREATOR_REVISION 0x00000002
-
-//
-// ACPI 2.0 Generic Address Space definition
-//
-typedef struct {
- uint8_t AddressSpaceId;
- uint8_t RegisterBitWidth;
- uint8_t RegisterBitOffset;
- uint8_t Reserved;
- uint64_t Address;
-} ACPI_GENERIC_ADDRESS_STRUCTURE;
-
-//
-// Generic Address Space Address IDs
-//
-#define ACPI_SYSTEM_MEMORY 0
-#define ACPI_SYSTEM_IO 1
-#define ACPI_PCI_CONFIGURATION_SPACE 2
-#define ACPI_EMBEDDED_CONTROLLER 3
-#define ACPI_SMBUS 4
-#define ACPI_FUNCTIONAL_FIXED_HARDWARE 0x7F
-
-//
-// Root System Description Pointer Structure in ACPI 1.0
-//
-typedef struct {
- uint64_t Signature;
- uint8_t Checksum;
- uint8_t OemId[6];
- uint8_t Reserved;
- uint32_t RsdtAddress;
-} ACPI_1_0_RSDP;
-
-
-//
-// Root System Description Pointer Structure
-//
-typedef struct {
- uint64_t Signature;
- uint8_t Checksum;
- uint8_t OemId[6];
- uint8_t Revision;
- uint32_t RsdtAddress;
- uint32_t Length;
- uint64_t XsdtAddress;
- uint8_t ExtendedChecksum;
- uint8_t Reserved[3];
-} ACPI_2_0_RSDP;
-
-
-//
-// The maximum number of entrys in RSDT or XSDT
-//
-#define ACPI_MAX_NUM_TABLES 2
-
-//
-// Root System Description Table (RSDT)
-//
-
-typedef struct {
- ACPI_TABLE_HEADER Header;
- uint32_t Entry[ACPI_MAX_NUM_TABLES];
-}ACPI_2_0_RSDT;
-
-//
-// RSDT Revision (as defined in ACPI 2.0 spec.)
-//
-
-#define ACPI_2_0_RSDT_REVISION 0x01
-
-//
-// Extended System Description Table (XSDT)
-//
-
-typedef struct _ACPI_2_0_XSDT{
- ACPI_TABLE_HEADER Header;
- uint64_t Entry[ACPI_MAX_NUM_TABLES];
-}ACPI_2_0_XSDT;
-#define ACPI_2_0_XSDT_REVISION 0x01
-
-//
-// Fixed ACPI Description Table Structure (FADT)
-//
-
-typedef struct {
- ACPI_TABLE_HEADER Header;
- uint32_t FirmwareCtrl;
- uint32_t Dsdt;
- uint8_t Reserved0;
- uint8_t PreferredPmProfile;
- uint16_t SciInt;
- uint32_t SmiCmd;
- uint8_t AcpiEnable;
- uint8_t AcpiDisable;
- uint8_t S4BiosReq;
- uint8_t PstateCnt;
- uint32_t Pm1aEvtBlk;
- uint32_t Pm1bEvtBlk;
- uint32_t Pm1aCntBlk;
- uint32_t Pm1bCntBlk;
- uint32_t Pm2CntBlk;
- uint32_t PmTmrBlk;
- uint32_t Gpe0Blk;
- uint32_t Gpe1Blk;
- uint8_t Pm1EvtLen;
- uint8_t Pm1CntLen;
- uint8_t Pm2CntLen;
- uint8_t PmTmrLen;
- uint8_t Gpe0BlkLen;
- uint8_t Gpe1BlkLen;
- uint8_t Gpe1Base;
- uint8_t CstCnt;
- uint16_t PLvl2Lat;
- uint16_t PLvl3Lat;
- uint16_t FlushSize;
- uint16_t FlushStride;
- uint8_t DutyOffset;
- uint8_t DutyWidth;
- uint8_t DayAlrm;
- uint8_t MonAlrm;
- uint8_t Century;
- uint16_t IaPcBootArch;
- uint8_t Reserved1;
- uint32_t Flags;
- ACPI_GENERIC_ADDRESS_STRUCTURE ResetReg;
- uint8_t ResetValue;
- uint8_t Reserved2[3];
- uint64_t XFirmwareCtrl;
- uint64_t XDsdt;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XGpe0Blk;
- ACPI_GENERIC_ADDRESS_STRUCTURE XGpe1Blk;
-} ACPI_2_0_FADT;
-#define ACPI_2_0_FADT_REVISION 0x03
-
-//
-// FADT Boot Architecture Flags
-//
-#define ACPI_LEGACY_DEVICES (1 << 0)
-#define ACPI_8042 (1 << 1)
-
-//
-// FADT Fixed Feature Flags
-//
-#define ACPI_WBINVD (1 << 0)
-#define ACPI_WBINVD_FLUSH (1 << 1)
-#define ACPI_PROC_C1 (1 << 2)
-#define ACPI_P_LVL2_UP (1 << 3)
-#define ACPI_PWR_BUTTON (1 << 4)
-#define ACPI_SLP_BUTTON (1 << 5)
-#define ACPI_FIX_RTC (1 << 6)
-#define ACPI_RTC_S4 (1 << 7)
-#define ACPI_TMR_VAL_EXT (1 << 8)
-#define ACPI_DCK_CAP (1 << 9)
-#define ACPI_RESET_REG_SUP (1 << 10)
-#define ACPI_SEALED_CASE (1 << 11)
-#define ACPI_HEADLESS (1 << 12)
-#define ACPI_CPU_SW_SLP (1 << 13)
-
-//
-// Firmware ACPI Control Structure (FACS)
-//
-typedef struct {
- uint32_t Signature;
- uint32_t Length;
- uint32_t HardwareSignature;
- uint32_t FirmwareWakingVector;
- uint32_t GlobalLock;
- uint32_t Flags;
- uint64_t XFirmwareWakingVector;
- uint8_t Version;
- uint8_t Reserved[31];
-} ACPI_2_0_FACS;
-
-#define ACPI_2_0_FACS_VERSION 0x01
-
-//
-// Multiple APIC Description Table header definition (MADT)
-//
-typedef struct {
- ACPI_TABLE_HEADER Header;
- uint32_t LocalApicAddress;
- uint32_t Flags;
-} ACPI_2_0_MADT;
-
-#define ACPI_2_0_MADT_REVISION 0x01
-
-//
-// Multiple APIC Flags
-//
-#define ACPI_PCAT_COMPAT (1 << 0)
-
-//
-// Multiple APIC Description Table APIC structure types
-//
-#define ACPI_PROCESSOR_LOCAL_APIC 0x00
-#define ACPI_IO_APIC 0x01
-#define ACPI_INTERRUPT_SOURCE_OVERRIDE 0x02
-#define ACPI_NON_MASKABLE_INTERRUPT_SOURCE 0x03
-#define ACPI_LOCAL_APIC_NMI 0x04
-#define ACPI_LOCAL_APIC_ADDRESS_OVERRIDE 0x05
-#define ACPI_IO_SAPIC 0x06
-#define ACPI_PROCESSOR_LOCAL_SAPIC 0x07
-#define ACPI_PLATFORM_INTERRUPT_SOURCES 0x08
-
-//
-// APIC Structure Definitions
-//
-
-//
-// Processor Local APIC Structure Definition
-//
-
-typedef struct {
- uint8_t Type;
- uint8_t Length;
- uint8_t AcpiProcessorId;
- uint8_t ApicId;
- uint32_t Flags;
-} ACPI_LOCAL_APIC_STRUCTURE;
-
-//
-// Local APIC Flags. All other bits are reserved and must be 0.
-//
-
-#define ACPI_LOCAL_APIC_ENABLED (1 << 0)
-
-//
-// IO APIC Structure
-//
-
-typedef struct {
- uint8_t Type;
- uint8_t Length;
- uint8_t IoApicId;
- uint8_t Reserved;
- uint32_t IoApicAddress;
- uint32_t GlobalSystemInterruptBase;
-} ACPI_IO_APIC_STRUCTURE;
-
-// Tabel Signature
-#define ACPI_2_0_RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
-
-#define ACPI_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE 0x54445344 //"DSDT"
-
-#define ACPI_2_0_FACS_SIGNATURE 0x53434146 // "FACS"
-
-#define ACPI_2_0_FADT_SIGNATURE 0x50434146 // "FADT"
-
-#define ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE 0x43495041 // "APIC"
-
-#define ACPI_2_0_RSDT_SIGNATURE 0x54445352 // "RSDT"
-
-#define ACPI_2_0_XSDT_SIGNATURE 0x54445358 // "XSDT"
-
-#pragma pack ()
-
-// The physical that acpi table reside in the guest BIOS
-//#define ACPI_PHYSICAL_ADDRESS 0xE2000
-#define ACPI_PHYSICAL_ADDRESS 0xEA000
-#define ACPI_TABLE_SIZE (4*1024) //Currently 4K is enough
-
-void
-AcpiBuildTable(uint8_t* buf);
-
-#endif
diff --git a/tools/firmware/acpi/acpi_build.c b/tools/firmware/acpi/acpi_build.c
deleted file mode 100644
index 7c58265309..0000000000
--- a/tools/firmware/acpi/acpi_build.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-
-#include "acpi2_0.h"
-#include "acpi_madt.h"
-
-extern ACPI_2_0_RSDP Rsdp;
-extern ACPI_2_0_RSDT Rsdt;
-extern ACPI_2_0_XSDT Xsdt;
-extern ACPI_2_0_FADT Fadt;
-extern ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE Madt;
-extern ACPI_2_0_FACS Facs;
-extern unsigned char *AmlCode;
-extern int DsdtLen;
-
-
-typedef struct _ACPI_TABLE_ALL{
- ACPI_2_0_RSDP *Rsdp;
- ACPI_2_0_RSDT *Rsdt;
- ACPI_2_0_XSDT *Xsdt;
- ACPI_2_0_FADT *Fadt;
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *Madt;
- ACPI_2_0_FACS *Facs;
- unsigned char* Dsdt;
- uint32_t RsdpOffset;
- uint32_t RsdtOffset;
- uint32_t XsdtOffset;
- uint32_t FadtOffset;
- uint32_t MadtOffset;
- uint32_t FacsOffset;
- uint32_t DsdtOffset;
-}ACPI_TABLE_ALL;
-
-static
-void
-MemCopy(void* src, void* dst, int len){
-
- uint8_t* src0=src;
- uint8_t* dst0=dst;
-
- while(len--){
- *(dst0++)=*(src0++);
- }
-}
-
-static
-void
-SetCheckSum(
- void* Table,
- uint32_t ChecksumOffset,
- uint32_t Length
-)
-/*
- * Routine Description:
- * Calculate Checksum and store the result in the checksum
- * filed of the table
- *
- * INPUT:
- * Table: Start pointer of table
- * ChecksumOffset: Offset of checksum field in the table
- * Length: Length of Table
- */
-{
- uint8_t Sum = 0;
- uint8_t *Ptr;
-
- Ptr=Table;
- Ptr[ChecksumOffset]=0;
- while (Length--) {
- Sum = (uint8_t)(Sum + (*Ptr++));
- }
-
- Ptr = Table;
- Ptr[ChecksumOffset] = (uint8_t) (0xff - Sum + 1);
-}
-
-//
-// FIELD_OFFSET - returns the byte offset to a field within a structure
-//
-#define FIELD_OFFSET(TYPE,Field) ((uint32_t)(&(((TYPE *) 0)->Field)))
-
-static
-void
-UpdateTable(
- ACPI_TABLE_ALL *table
-)
-/*
- * Update the ACPI table:
- * fill in the actuall physical address of RSDT, XSDT, FADT, MADT, FACS
- * Caculate the checksum
- */
-{
- // RSDP Update
- table->Rsdp->RsdtAddress = (uint32_t)(ACPI_PHYSICAL_ADDRESS+
- table->RsdtOffset);
- table->Rsdp->XsdtAddress = (uint64_t)(ACPI_PHYSICAL_ADDRESS+
- table->XsdtOffset);
- SetCheckSum(table->Rsdp,
- FIELD_OFFSET(ACPI_1_0_RSDP, Checksum),
- sizeof(ACPI_1_0_RSDP)
- );
- SetCheckSum(table->Rsdp,
- FIELD_OFFSET(ACPI_2_0_RSDP,
- ExtendedChecksum),
- sizeof(ACPI_2_0_RSDP)
- );
-
-
- //RSDT Update
- table->Rsdt->Entry[0] = (uint32_t)(ACPI_PHYSICAL_ADDRESS +
- table->FadtOffset);
- table->Rsdt->Entry[1] = (uint32_t)(ACPI_PHYSICAL_ADDRESS +
- table->MadtOffset);
- table->Rsdt->Header.Length = sizeof (ACPI_TABLE_HEADER) +
- 2*sizeof(uint32_t);
- SetCheckSum(table->Rsdt,
- FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
- table->Rsdt->Header.Length
- );
-
- //XSDT Update
- table->Xsdt->Entry[0] = (uint64_t)(ACPI_PHYSICAL_ADDRESS +
- table->FadtOffset);
- table->Xsdt->Entry[1] = (uint64_t)(ACPI_PHYSICAL_ADDRESS +
- table->MadtOffset);
- table->Xsdt->Header.Length = sizeof (ACPI_TABLE_HEADER) +
- 2*sizeof(uint64_t);
- SetCheckSum(table->Xsdt,
- FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
- table->Xsdt->Header.Length
- );
-
- // FADT Update
- table->Fadt->Dsdt = (uint32_t)(ACPI_PHYSICAL_ADDRESS +
- table->DsdtOffset);
- table->Fadt->XDsdt = (uint64_t)(ACPI_PHYSICAL_ADDRESS +
- table->DsdtOffset);
- table->Fadt->FirmwareCtrl = (uint32_t)(ACPI_PHYSICAL_ADDRESS +
- table->FacsOffset);
- table->Fadt->XFirmwareCtrl = (uint64_t)(ACPI_PHYSICAL_ADDRESS +
- table->FacsOffset);
- SetCheckSum(table->Fadt,
- FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
- sizeof(ACPI_2_0_FADT)
- );
-
- // MADT update
- SetCheckSum(table->Madt,
- FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
- sizeof(ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE)
- );
-}
-
-void
-AcpiBuildTable(uint8_t* buf)
-/*
- * Copy all the ACPI table to buffer
- * Buffer Layout:
- * FACS
- * RSDP
- * RSDT
- * XSDT
- * FADT
- * MADT
- * DSDT
- *
- */
-{
- ACPI_TABLE_ALL table;
- int offset=0;
-
- // FACS: should be 64-bit alignment
- // so it is put at the start of buffer
- // as the buffer is 64 bit alignment
- table.FacsOffset = offset;
- table.Facs = (ACPI_2_0_FACS*)(&buf[offset]);
- MemCopy(&Facs, table.Facs, sizeof(ACPI_2_0_FACS));
- offset += sizeof(ACPI_2_0_FACS);
-
- // RSDP
- table.RsdpOffset = offset;
- table.Rsdp = (ACPI_2_0_RSDP*)(&buf[offset]);
- MemCopy(&Rsdp, table.Rsdp, sizeof(ACPI_2_0_RSDP));
- offset+=sizeof(ACPI_2_0_RSDP);
-
- // RSDT
- table.RsdtOffset = offset;
- table.Rsdt = (ACPI_2_0_RSDT*)(&buf[offset]);
- MemCopy(&Rsdt, table.Rsdt, sizeof(ACPI_2_0_RSDT));
- offset+=sizeof(ACPI_2_0_RSDT);
-
- // XSDT
- table.XsdtOffset = offset;
- table.Xsdt = (ACPI_2_0_XSDT*)(&buf[offset]);
- MemCopy(&Xsdt, table.Xsdt, sizeof(ACPI_2_0_XSDT));
- offset+=sizeof(ACPI_2_0_XSDT);
-
- // FADT
- table.FadtOffset = offset;
- table.Fadt = (ACPI_2_0_FADT*)(&buf[offset]);
- MemCopy(&Fadt, table.Fadt, sizeof(ACPI_2_0_FADT));
- offset+=sizeof(ACPI_2_0_FADT);
-
- // MADT
- table.MadtOffset = offset;
- table.Madt = (ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE*)(&buf[offset]);
- MemCopy(&Madt, table.Madt, sizeof(ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE));
- offset+=sizeof(ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE);
-
- // DSDT
- table.DsdtOffset = offset;
- table.Dsdt = (unsigned char*)(&buf[offset]);
- MemCopy(&AmlCode, table.Dsdt, DsdtLen);
- offset+=DsdtLen;
-
- UpdateTable(&table);
-}
diff --git a/tools/firmware/acpi/acpi_dsdt.asl b/tools/firmware/acpi/acpi_dsdt.asl
deleted file mode 100644
index 6396de6ff1..0000000000
--- a/tools/firmware/acpi/acpi_dsdt.asl
+++ /dev/null
@@ -1,521 +0,0 @@
-//**********************************************************************//
-//*
-//* Copyright (c) 2004, 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.
-
-//**
-//** DSDT for Xen with Qemu device model
-//**
-//**
-
-DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
-{
- Name (\PMBS, 0x0C00)
- Name (\PMLN, 0x08)
- Name (\IOB1, 0x00)
- Name (\IOL1, 0x00)
- Name (\APCB, 0xFEC00000)
- Name (\APCL, 0x00010000)
- Name (\PUID, 0x00)
-
- Scope (\_PR)
- {
- Processor (CPU0, 0x00, 0x00000000, 0x00) {}
- Processor (CPU1, 0x01, 0x00000000, 0x00) {}
- Processor (CPU2, 0x02, 0x00000000, 0x00) {}
- Processor (CPU3, 0x03, 0x00000000, 0x00) {}
-
- }
-
-/* Poweroff support - ties in with qemu emulation */
-
- Name (\_S5, Package (0x04)
- {
- 0x07,
- 0x07,
- 0x00,
- 0x00
- })
-
-
- Name(PICD, 0)
-
- Method(_PIC, 1) {
-
- Store(Arg0, PICD)
- }
- Scope (\_SB)
- {
- /* Fix HCT test for 0x400 pci memory - need to report low 640 MB mem as motherboard resource */
-
- Device(MEM0) {
- Name(_HID, EISAID("PNP0C02"))
- Name(_CRS, ResourceTemplate() {
- QWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
- 0x00000000,
- 0x00000000,
- 0x0009ffff,
- 0x00000000,
- 0x000a0000)
- }
- )
- }
-
- Device (PCI0)
- {
- Name (_HID, EisaId ("PNP0A03"))
- Name (_UID, 0x00)
- Name (_ADR, 0x00)
- Name (_BBN, 0x00)
- OperationRegion (PIRP, PCI_Config, 0x3c, 0x10)
- Field(PIRP, ByteAcc, NoLock, Preserve){
- IRQ3,3,
- IRQ5,5,
- IRQ7,7,
- IRQ9,9,
- IRQA,10,
- IRQB,11
- }
-
- Method (_CRS, 0, NotSerialized)
- {
-
- Name (PRT0, ResourceTemplate ()
- {
- /* bus number is from 0 - 255*/
- WordBusNumber (ResourceConsumer, MinFixed, MaxFixed, SubDecode,
- 0x0000,
- 0x0000,
- 0x00FF,
- 0x0000,
- 0x0100)
- IO (Decode16, 0x0CF8, 0x0CF8, 0x01, 0x08)
- WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
- 0x0000,
- 0x0000,
- 0x0CF7,
- 0x0000,
- 0x0CF8)
- WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
- 0x0000,
- 0x0D00,
- 0xFFFF,
- 0x0000,
- 0xF300)
-
- /* reserve what device model consumed for PCI VGA device */
-
- DWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
- 0x00000000,
- 0xF0000000,
- 0xF1FFFFFF,
- 0x00000000,
- 0x02000000)
- DWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
- 0x00000000,
- 0xF2000000,
- 0xF2000FFF,
- 0x00000000,
- 0x00001000)
- })
- Return (PRT0)
- }
- Name(BUFA, ResourceTemplate() {
- IRQ(Level, ActiveLow, Shared) {
- 3,4,5,6,7,10,11,12,14,15}
- })
-
- Name(BUFB, Buffer(){
- 0x23, 0x00, 0x00, 0x18,
- 0x79, 0})
-
- CreateWordField(BUFB, 0x01, IRQV)
-
- Name(BUFC, Buffer(){
- 5, 7, 10, 11
- })
-
- CreateByteField(BUFC, 0x01, PIQA)
- CreateByteField(BUFC, 0x01, PIQB)
- CreateByteField(BUFC, 0x01, PIQC)
- CreateByteField(BUFC, 0x01, PIQD)
-
- Device(LNKA) {
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 1)
- Method(_STA, 0) {
- And(PIRA, 0x80, Local0)
- If(LEqual(Local0, 0x80)) {
- Return(0x09)
- }
- Else {
- Return(0x0B)
- }
- }
-
- Method(_PRS) {
-
- Return(BUFA)
- } // Method(_PRS)
-
- Method(_DIS) {
- Or(PIRA, 0x80, PIRA)
- }
-
- Method(_CRS) {
- And(PIRB, 0x0f, Local0)
- ShiftLeft(0x1, Local0, IRQV)
- Return(BUFB)
- }
-
- Method(_SRS, 1) {
- CreateWordField(ARG0, 0x01, IRQ1)
- FindSetRightBit(IRQ1, Local0)
- Decrement(Local0)
- Store(Local0, PIRA)
- } // Method(_SRS)
- }
-
- Device(LNKB){
- Name(_HID, EISAID("PNP0C0F"))
- Name(_UID, 2)
- Method(_STA, 0) {
- And(PIRB, 0x80, Local0)
- If(LEqual(Local0, 0x80)) {
- Return(0x09)
- }
- Else {
- Return(0x0B)
- }
- }
-
- Method(_PRS) {
- Return(BUFA)
- } // Method(_PRS)
-
- Method(_DIS) {
-
- Or(PIRB, 0x80, PIRB)
- }
-
- Method(_CRS) {
- And(PIRB, 0x0f, Local0)
- ShiftLeft(0x1, Local0, IRQV)
- Return(BUFB)
- } // Method(_CRS)
-
- Method(_SRS, 1) {
- CreateWordField(ARG0, 0x01, IRQ1)
- FindSetRightBit(IRQ1, Local0)
- Decrement(Local0)
- Store(Local0, PIRB)
- } // Method(_SRS)
- }
-
- Device(LNKC){
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 3)
- Method(_STA, 0) {
- And(PIRC, 0x80, Local0)
- If(LEqual(Local0, 0x80)) {
- Return(0x09)
- }
- Else {
- Return(0x0B)
- }
- }
-
- Method(_PRS) {
- Return(BUFA)
- } // Method(_PRS)
-
- Method(_DIS) {
-
- Or(PIRC, 0x80, PIRC)
- }
-
- Method(_CRS) {
- And(PIRC, 0x0f, Local0)
- ShiftLeft(0x1, Local0, IRQV)
- Return(BUFB)
- } // Method(_CRS)
-
- Method(_SRS, 1) {
- CreateWordField(ARG0, 0x01, IRQ1)
- FindSetRightBit(IRQ1, Local0)
- Decrement(Local0)
- Store(Local0, PIRC)
- } // Method(_SRS)
- }
-
- Device(LNKD) {
- Name(_HID, EISAID("PNP0C0F"))
- Name(_UID, 4)
- Method(_STA, 0) {
- And(PIRD, 0x80, Local0)
- If(LEqual(Local0, 0x80)) {
- Return(0x09)
- }
- Else {
- Return(0x0B)
- }
- }
-
- Method(_PRS) {
- Return(BUFA)
- } // Method(_PRS)
-
- Method(_DIS) {
- Or(PIRD, 0x80, PIRD)
- }
-
- Method(_CRS) {
- And(PIRD, 0x0f, Local0)
- ShiftLeft(0x1, Local0, IRQV)
- Return(BUFB)
- } // Method(_CRS)
-
- Method(_SRS, 1) {
- CreateWordField(ARG0, 0x01, IRQ1)
- FindSetRightBit(IRQ1, Local0)
- Decrement(Local0)
- Store(Local0, PIRD)
- } // Method(_SRS)
- }
- Method(_PRT,0) {
- If(PICD) {Return(PRTA)}
- Return (PRTP)
- } // end _PRT
-
- Name(PRTP, Package(){
- Package(){0x0000ffff, 0, \_SB.PCI0.LNKA, 0}, // Slot 1, INTA
- Package(){0x0000ffff, 1, \_SB.PCI0.LNKB, 0}, // Slot 1, INTB
- Package(){0x0000ffff, 2, \_SB.PCI0.LNKC, 0}, // Slot 1, INTC
- Package(){0x0000ffff, 3, \_SB.PCI0.LNKD, 0}, // Slot 1, INTD
-
- Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
- Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
- Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
- Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
-
- Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0}, // Slot 3, INTC
- Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0}, // Slot 3, INTD
- Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0}, // Slot 3, INTA
- Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0}, // Slot 3, INTB
-
- Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0}, // Slot 2, INTD
- Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0}, // Slot 2, INTA
- Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0}, // Slot 2, INTB
- Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0}, // Slot 2, INTC
-
- }
- )
- Name(PRTA, Package(){
- Package(){0x0001ffff, 0, 0, 5}, // Device 1, INTA
-
- Package(){0x0002ffff, 0, 0, 7}, // Device 2, INTA
-
- Package(){0x0003ffff, 0, 0, 10}, // Device 3, INTA
-
- Package(){0x0004ffff, 0, 0, 11}, // Device 4, INTA
-
- }
- )
-
- Device (ISA)
- {
- Name (_ADR, 0x00000000) /* device id, PCI bus num, ... */
-
- OperationRegion(PIRQ, PCI_Config, 0x60, 0x4)
- Scope(\) {
- Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
- PIRA, 8,
- PIRB, 8,
- PIRC, 8,
- PIRD, 8
- }
- }
- Device (SYSR)
- {
- Name (_HID, EisaId ("PNP0C02"))
- Name (_UID, 0x01)
- Name (CRS, ResourceTemplate ()
- {
- /* TODO: list hidden resources */
- IO (Decode16, 0x0010, 0x0010, 0x00, 0x10)
- IO (Decode16, 0x0022, 0x0022, 0x00, 0x0C)
- IO (Decode16, 0x0030, 0x0030, 0x00, 0x10)
- IO (Decode16, 0x0044, 0x0044, 0x00, 0x1C)
- IO (Decode16, 0x0062, 0x0062, 0x00, 0x02)
- IO (Decode16, 0x0065, 0x0065, 0x00, 0x0B)
- IO (Decode16, 0x0072, 0x0072, 0x00, 0x0E)
- IO (Decode16, 0x0080, 0x0080, 0x00, 0x01)
- IO (Decode16, 0x0084, 0x0084, 0x00, 0x03)
- IO (Decode16, 0x0088, 0x0088, 0x00, 0x01)
- IO (Decode16, 0x008C, 0x008C, 0x00, 0x03)
- IO (Decode16, 0x0090, 0x0090, 0x00, 0x10)
- IO (Decode16, 0x00A2, 0x00A2, 0x00, 0x1C)
- IO (Decode16, 0x00E0, 0x00E0, 0x00, 0x10)
- IO (Decode16, 0x08A0, 0x08A0, 0x00, 0x04)
- IO (Decode16, 0x0CC0, 0x0CC0, 0x00, 0x10)
- IO (Decode16, 0x04D0, 0x04D0, 0x00, 0x02)
- })
- Method (_CRS, 0, NotSerialized)
- {
- Return (CRS)
- }
- }
-
- Device (PIC)
- {
- Name (_HID, EisaId ("PNP0000"))
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x0020, 0x0020, 0x01, 0x02)
- IO (Decode16, 0x00A0, 0x00A0, 0x01, 0x02)
- IRQNoFlags () {2}
- })
- }
-
- Device (DMA0)
- {
- Name (_HID, EisaId ("PNP0200"))
- Name (_CRS, ResourceTemplate ()
- {
- DMA (Compatibility, BusMaster, Transfer8) {4}
- IO (Decode16, 0x0000, 0x0000, 0x00, 0x10)
- IO (Decode16, 0x0081, 0x0081, 0x00, 0x03)
- IO (Decode16, 0x0087, 0x0087, 0x00, 0x01)
- IO (Decode16, 0x0089, 0x0089, 0x00, 0x03)
- IO (Decode16, 0x008F, 0x008F, 0x00, 0x01)
- IO (Decode16, 0x00C0, 0x00C0, 0x00, 0x20)
- IO (Decode16, 0x0480, 0x0480, 0x00, 0x10)
- })
- }
-
- Device (TMR)
- {
- Name (_HID, EisaId ("PNP0100"))
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x0040, 0x0040, 0x00, 0x04)
- IRQNoFlags () {0}
- })
- }
-
- Device (RTC)
- {
- Name (_HID, EisaId ("PNP0B00"))
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x0070, 0x0070, 0x00, 0x02)
- IRQNoFlags () {8}
- })
- }
-
- Device (SPKR)
- {
- Name (_HID, EisaId ("PNP0800"))
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x0061, 0x0061, 0x00, 0x01)
- })
- }
-
- Device (PS2M)
- {
- Name (_HID, EisaId ("PNP0F13"))
- Name (_CID, 0x130FD041)
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
-
- Name (_CRS, ResourceTemplate ()
- {
- IRQNoFlags () {12}
- })
- }
-
- Device (PS2K)
- {
- Name (_HID, EisaId ("PNP0303"))
- Name (_CID, 0x0B03D041)
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
-
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x0060, 0x0060, 0x00, 0x01)
- IO (Decode16, 0x0064, 0x0064, 0x00, 0x01)
- IRQNoFlags () {1}
- })
- }
-
- Device (FDC0)
- {
- Name (_HID, EisaId ("PNP0700"))
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
-
- Name (_CRS, ResourceTemplate ()
- {
- IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06)
- IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01)
- IRQNoFlags () {6}
- DMA (Compatibility, NotBusMaster, Transfer8) {2}
- })
- }
-
- Device (UAR1)
- {
- Name (_HID, EisaId ("PNP0501"))
- Name (_UID, 0x01)
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
-
- Name (_CRS, ResourceTemplate()
- {
- IO (Decode16, 0x03F8, 0x03F8, 0x01, 0x08)
- IRQNoFlags () {4}
- })
- }
-
- Device (LTP1)
- {
- Name (_HID, EisaId ("PNP0400"))
- Name (_UID, 0x02)
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
-
- Name (_CRS, ResourceTemplate()
- {
- IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
- IRQNoFlags () {7}
- })
- }
- }
- }
- }
-}
-
diff --git a/tools/firmware/acpi/acpi_dsdt.c b/tools/firmware/acpi/acpi_dsdt.c
deleted file mode 100644
index ec9f5bde1e..0000000000
--- a/tools/firmware/acpi/acpi_dsdt.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- *
- * Intel ACPI Component Architecture
- * ASL Optimizing Compiler / AML Disassembler version 20050513 [Jun 8 2005]
- * Copyright (C) 2000 - 2005 Intel Corporation
- * Supports ACPI Specification Revision 3.0
- *
- * Compilation of "acpi_dsdt.asl" - Mon Aug 14 18:15:09 2006
- *
- * C source code output
- *
- */
-unsigned char AmlCode[] =
-{
- 0x44,0x53,0x44,0x54,0xBA,0x08,0x00,0x00, /* 00000000 "DSDT...." */
- 0x01,0x1D,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */
- 0x69,0x6E,0x74,0x2D,0x78,0x65,0x6E,0x00, /* 00000010 "int-xen." */
- 0xD6,0x07,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
- 0x13,0x05,0x05,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */
- 0x53,0x0B,0x00,0x0C,0x08,0x50,0x4D,0x4C, /* 00000028 "S....PML" */
- 0x4E,0x0A,0x08,0x08,0x49,0x4F,0x42,0x31, /* 00000030 "N...IOB1" */
- 0x00,0x08,0x49,0x4F,0x4C,0x31,0x00,0x08, /* 00000038 "..IOL1.." */
- 0x41,0x50,0x43,0x42,0x0C,0x00,0x00,0xC0, /* 00000040 "APCB...." */
- 0xFE,0x08,0x41,0x50,0x43,0x4C,0x0C,0x00, /* 00000048 "..APCL.." */
- 0x00,0x01,0x00,0x08,0x50,0x55,0x49,0x44, /* 00000050 "....PUID" */
- 0x00,0x10,0x39,0x5F,0x50,0x52,0x5F,0x5B, /* 00000058 "..9_PR_[" */
- 0x83,0x0B,0x43,0x50,0x55,0x30,0x00,0x00, /* 00000060 "..CPU0.." */
- 0x00,0x00,0x00,0x00,0x5B,0x83,0x0B,0x43, /* 00000068 "....[..C" */
- 0x50,0x55,0x31,0x01,0x00,0x00,0x00,0x00, /* 00000070 "PU1....." */
- 0x00,0x5B,0x83,0x0B,0x43,0x50,0x55,0x32, /* 00000078 ".[..CPU2" */
- 0x02,0x00,0x00,0x00,0x00,0x00,0x5B,0x83, /* 00000080 "......[." */
- 0x0B,0x43,0x50,0x55,0x33,0x03,0x00,0x00, /* 00000088 ".CPU3..." */
- 0x00,0x00,0x00,0x08,0x5F,0x53,0x35,0x5F, /* 00000090 "...._S5_" */
- 0x12,0x08,0x04,0x0A,0x07,0x0A,0x07,0x00, /* 00000098 "........" */
- 0x00,0x08,0x50,0x49,0x43,0x44,0x00,0x14, /* 000000A0 "..PICD.." */
- 0x0C,0x5F,0x50,0x49,0x43,0x01,0x70,0x68, /* 000000A8 "._PIC.ph" */
- 0x50,0x49,0x43,0x44,0x10,0x45,0x80,0x5F, /* 000000B0 "PICD.E._" */
- 0x53,0x42,0x5F,0x5B,0x82,0x49,0x04,0x4D, /* 000000B8 "SB_[.I.M" */
- 0x45,0x4D,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "EM0._HID" */
- 0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x43, /* 000000C8 ".A...._C" */
- 0x52,0x53,0x11,0x33,0x0A,0x30,0x8A,0x2B, /* 000000D0 "RS.3.0.+" */
- 0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000000D8 "........" */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */
- 0x00,0x00,0x00,0x00,0xFF,0xFF,0x09,0x00, /* 000000E8 "........" */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00, /* 000000F8 "........" */
- 0x00,0x00,0x00,0x00,0x79,0x00,0x5B,0x82, /* 00000100 "....y.[." */
- 0x42,0x7B,0x50,0x43,0x49,0x30,0x08,0x5F, /* 00000108 "B{PCI0._" */
- 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03, /* 00000110 "HID.A..." */
- 0x08,0x5F,0x55,0x49,0x44,0x00,0x08,0x5F, /* 00000118 "._UID.._" */
- 0x41,0x44,0x52,0x00,0x08,0x5F,0x42,0x42, /* 00000120 "ADR.._BB" */
- 0x4E,0x00,0x5B,0x80,0x50,0x49,0x52,0x50, /* 00000128 "N.[.PIRP" */
- 0x02,0x0A,0x3C,0x0A,0x10,0x5B,0x81,0x24, /* 00000130 "..<..[.$" */
- 0x50,0x49,0x52,0x50,0x01,0x49,0x52,0x51, /* 00000138 "PIRP.IRQ" */
- 0x33,0x03,0x49,0x52,0x51,0x35,0x05,0x49, /* 00000140 "3.IRQ5.I" */
- 0x52,0x51,0x37,0x07,0x49,0x52,0x51,0x39, /* 00000148 "RQ7.IRQ9" */
- 0x09,0x49,0x52,0x51,0x41,0x0A,0x49,0x52, /* 00000150 ".IRQA.IR" */
- 0x51,0x42,0x0B,0x14,0x44,0x08,0x5F,0x43, /* 00000158 "QB..D._C" */
- 0x52,0x53,0x00,0x08,0x50,0x52,0x54,0x30, /* 00000160 "RS..PRT0" */
- 0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00, /* 00000168 ".B..n..." */
- 0x02,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF, /* 00000170 "........" */
- 0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 00000178 ".....G.." */
- 0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 00000180 "........" */
- 0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 00000188 "........" */
- 0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 00000190 "........" */
- 0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 00000198 "........" */
- 0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00, /* 000001A0 "........" */
- 0x00,0x0D,0x03,0x00,0x00,0x00,0x00,0x00, /* 000001A8 "........" */
- 0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xF1,0x00, /* 000001B0 "........" */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x87, /* 000001B8 "........" */
- 0x17,0x00,0x00,0x0D,0x03,0x00,0x00,0x00, /* 000001C0 "........" */
- 0x00,0x00,0x00,0x00,0xF2,0xFF,0x0F,0x00, /* 000001C8 "........" */
- 0xF2,0x00,0x00,0x00,0x00,0x00,0x10,0x00, /* 000001D0 "........" */
- 0x00,0x79,0x00,0xA4,0x50,0x52,0x54,0x30, /* 000001D8 ".y..PRT0" */
- 0x08,0x42,0x55,0x46,0x41,0x11,0x09,0x0A, /* 000001E0 ".BUFA..." */
- 0x06,0x23,0xF8,0xDC,0x18,0x79,0x00,0x08, /* 000001E8 ".#...y.." */
- 0x42,0x55,0x46,0x42,0x11,0x09,0x0A,0x06, /* 000001F0 "BUFB...." */
- 0x23,0x00,0x00,0x18,0x79,0x00,0x8B,0x42, /* 000001F8 "#...y..B" */
- 0x55,0x46,0x42,0x01,0x49,0x52,0x51,0x56, /* 00000200 "UFB.IRQV" */
- 0x08,0x42,0x55,0x46,0x43,0x11,0x07,0x0A, /* 00000208 ".BUFC..." */
- 0x04,0x05,0x07,0x0A,0x0B,0x8C,0x42,0x55, /* 00000210 "......BU" */
- 0x46,0x43,0x01,0x50,0x49,0x51,0x41,0x8C, /* 00000218 "FC.PIQA." */
- 0x42,0x55,0x46,0x43,0x01,0x50,0x49,0x51, /* 00000220 "BUFC.PIQ" */
- 0x42,0x8C,0x42,0x55,0x46,0x43,0x01,0x50, /* 00000228 "B.BUFC.P" */
- 0x49,0x51,0x43,0x8C,0x42,0x55,0x46,0x43, /* 00000230 "IQC.BUFC" */
- 0x01,0x50,0x49,0x51,0x44,0x5B,0x82,0x48, /* 00000238 ".PIQD[.H" */
- 0x08,0x4C,0x4E,0x4B,0x41,0x08,0x5F,0x48, /* 00000240 ".LNKA._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000248 "ID.A...." */
- 0x5F,0x55,0x49,0x44,0x01,0x14,0x1C,0x5F, /* 00000250 "_UID..._" */
- 0x53,0x54,0x41,0x00,0x7B,0x50,0x49,0x52, /* 00000258 "STA.{PIR" */
- 0x41,0x0A,0x80,0x60,0xA0,0x08,0x93,0x60, /* 00000260 "A..`...`" */
- 0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4, /* 00000268 "........" */
- 0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53, /* 00000270 "...._PRS" */
- 0x00,0xA4,0x42,0x55,0x46,0x41,0x14,0x11, /* 00000278 "..BUFA.." */
- 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x49, /* 00000280 "_DIS.}PI" */
- 0x52,0x41,0x0A,0x80,0x50,0x49,0x52,0x41, /* 00000288 "RA..PIRA" */
- 0x14,0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B, /* 00000290 ".._CRS.{" */
- 0x50,0x49,0x52,0x42,0x0A,0x0F,0x60,0x79, /* 00000298 "PIRB..`y" */
- 0x01,0x60,0x49,0x52,0x51,0x56,0xA4,0x42, /* 000002A0 ".`IRQV.B" */
- 0x55,0x46,0x42,0x14,0x1B,0x5F,0x53,0x52, /* 000002A8 "UFB.._SR" */
- 0x53,0x01,0x8B,0x68,0x01,0x49,0x52,0x51, /* 000002B0 "S..h.IRQ" */
- 0x31,0x82,0x49,0x52,0x51,0x31,0x60,0x76, /* 000002B8 "1.IRQ1`v" */
- 0x60,0x70,0x60,0x50,0x49,0x52,0x41,0x5B, /* 000002C0 "`p`PIRA[" */
- 0x82,0x49,0x08,0x4C,0x4E,0x4B,0x42,0x08, /* 000002C8 ".I.LNKB." */
- 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C, /* 000002D0 "_HID.A.." */
- 0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x02, /* 000002D8 ".._UID.." */
- 0x14,0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B, /* 000002E0 ".._STA.{" */
- 0x50,0x49,0x52,0x42,0x0A,0x80,0x60,0xA0, /* 000002E8 "PIRB..`." */
- 0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09, /* 000002F0 "..`....." */
- 0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F, /* 000002F8 "......._" */
- 0x50,0x52,0x53,0x00,0xA4,0x42,0x55,0x46, /* 00000300 "PRS..BUF" */
- 0x41,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 00000308 "A.._DIS." */
- 0x7D,0x50,0x49,0x52,0x42,0x0A,0x80,0x50, /* 00000310 "}PIRB..P" */
- 0x49,0x52,0x42,0x14,0x1A,0x5F,0x43,0x52, /* 00000318 "IRB.._CR" */
- 0x53,0x00,0x7B,0x50,0x49,0x52,0x42,0x0A, /* 00000320 "S.{PIRB." */
- 0x0F,0x60,0x79,0x01,0x60,0x49,0x52,0x51, /* 00000328 ".`y.`IRQ" */
- 0x56,0xA4,0x42,0x55,0x46,0x42,0x14,0x1B, /* 00000330 "V.BUFB.." */
- 0x5F,0x53,0x52,0x53,0x01,0x8B,0x68,0x01, /* 00000338 "_SRS..h." */
- 0x49,0x52,0x51,0x31,0x82,0x49,0x52,0x51, /* 00000340 "IRQ1.IRQ" */
- 0x31,0x60,0x76,0x60,0x70,0x60,0x50,0x49, /* 00000348 "1`v`p`PI" */
- 0x52,0x42,0x5B,0x82,0x49,0x08,0x4C,0x4E, /* 00000350 "RB[.I.LN" */
- 0x4B,0x43,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000358 "KC._HID." */
- 0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49, /* 00000360 "A...._UI" */
- 0x44,0x0A,0x03,0x14,0x1C,0x5F,0x53,0x54, /* 00000368 "D...._ST" */
- 0x41,0x00,0x7B,0x50,0x49,0x52,0x43,0x0A, /* 00000370 "A.{PIRC." */
- 0x80,0x60,0xA0,0x08,0x93,0x60,0x0A,0x80, /* 00000378 ".`...`.." */
- 0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B, /* 00000380 "........" */
- 0x14,0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4, /* 00000388 ".._PRS.." */
- 0x42,0x55,0x46,0x41,0x14,0x11,0x5F,0x44, /* 00000390 "BUFA.._D" */
- 0x49,0x53,0x00,0x7D,0x50,0x49,0x52,0x43, /* 00000398 "IS.}PIRC" */
- 0x0A,0x80,0x50,0x49,0x52,0x43,0x14,0x1A, /* 000003A0 "..PIRC.." */
- 0x5F,0x43,0x52,0x53,0x00,0x7B,0x50,0x49, /* 000003A8 "_CRS.{PI" */
- 0x52,0x43,0x0A,0x0F,0x60,0x79,0x01,0x60, /* 000003B0 "RC..`y.`" */
- 0x49,0x52,0x51,0x56,0xA4,0x42,0x55,0x46, /* 000003B8 "IRQV.BUF" */
- 0x42,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 000003C0 "B.._SRS." */
- 0x8B,0x68,0x01,0x49,0x52,0x51,0x31,0x82, /* 000003C8 ".h.IRQ1." */
- 0x49,0x52,0x51,0x31,0x60,0x76,0x60,0x70, /* 000003D0 "IRQ1`v`p" */
- 0x60,0x50,0x49,0x52,0x43,0x5B,0x82,0x49, /* 000003D8 "`PIRC[.I" */
- 0x08,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 000003E0 ".LNKD._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 000003E8 "ID.A...." */
- 0x5F,0x55,0x49,0x44,0x0A,0x04,0x14,0x1C, /* 000003F0 "_UID...." */
- 0x5F,0x53,0x54,0x41,0x00,0x7B,0x50,0x49, /* 000003F8 "_STA.{PI" */
- 0x52,0x44,0x0A,0x80,0x60,0xA0,0x08,0x93, /* 00000400 "RD..`..." */
- 0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04, /* 00000408 "`......." */
- 0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52, /* 00000410 "....._PR" */
- 0x53,0x00,0xA4,0x42,0x55,0x46,0x41,0x14, /* 00000418 "S..BUFA." */
- 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000420 "._DIS.}P" */
- 0x49,0x52,0x44,0x0A,0x80,0x50,0x49,0x52, /* 00000428 "IRD..PIR" */
- 0x44,0x14,0x1A,0x5F,0x43,0x52,0x53,0x00, /* 00000430 "D.._CRS." */
- 0x7B,0x50,0x49,0x52,0x44,0x0A,0x0F,0x60, /* 00000438 "{PIRD..`" */
- 0x79,0x01,0x60,0x49,0x52,0x51,0x56,0xA4, /* 00000440 "y.`IRQV." */
- 0x42,0x55,0x46,0x42,0x14,0x1B,0x5F,0x53, /* 00000448 "BUFB.._S" */
- 0x52,0x53,0x01,0x8B,0x68,0x01,0x49,0x52, /* 00000450 "RS..h.IR" */
- 0x51,0x31,0x82,0x49,0x52,0x51,0x31,0x60, /* 00000458 "Q1.IRQ1`" */
- 0x76,0x60,0x70,0x60,0x50,0x49,0x52,0x44, /* 00000460 "v`p`PIRD" */
- 0x14,0x16,0x5F,0x50,0x52,0x54,0x00,0xA0, /* 00000468 ".._PRT.." */
- 0x0A,0x50,0x49,0x43,0x44,0xA4,0x50,0x52, /* 00000470 ".PICD.PR" */
- 0x54,0x41,0xA4,0x50,0x52,0x54,0x50,0x08, /* 00000478 "TA.PRTP." */
- 0x50,0x52,0x54,0x50,0x12,0x43,0x0E,0x10, /* 00000480 "PRTP.C.." */
- 0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x00,0x4C, /* 00000488 ".......L" */
- 0x4E,0x4B,0x41,0x00,0x12,0x0B,0x04,0x0B, /* 00000490 "NKA....." */
- 0xFF,0xFF,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 00000498 "...LNKB." */
- 0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x02, /* 000004A0 "........" */
- 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0C,0x04, /* 000004A8 "LNKC...." */
- 0x0B,0xFF,0xFF,0x0A,0x03,0x4C,0x4E,0x4B, /* 000004B0 ".....LNK" */
- 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000004B8 "D......." */
- 0x01,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 000004C0 "...LNKB." */
- 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000004C8 "........" */
- 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 000004D0 ".LNKC..." */
- 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x02, /* 000004D8 "........" */
- 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 000004E0 "LNKD...." */
- 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03,0x4C, /* 000004E8 ".......L" */
- 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000004F0 "NKA....." */
- 0xFF,0xFF,0x02,0x00,0x00,0x4C,0x4E,0x4B, /* 000004F8 ".....LNK" */
- 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000500 "C......." */
- 0x02,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 00000508 "...LNKD." */
- 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000510 "........" */
- 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000518 "..LNKA.." */
- 0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 00000520 "........" */
- 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000528 ".LNKB..." */
- 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x00,0x4C, /* 00000530 ".......L" */
- 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000538 "NKD....." */
- 0xFF,0xFF,0x03,0x00,0x01,0x4C,0x4E,0x4B, /* 00000540 ".....LNK" */
- 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000548 "A......." */
- 0x03,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000550 "....LNKB" */
- 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03, /* 00000558 "........" */
- 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000560 "...LNKC." */
- 0x08,0x50,0x52,0x54,0x41,0x12,0x32,0x04, /* 00000568 ".PRTA.2." */
- 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 00000570 "........" */
- 0x00,0x00,0x0A,0x05,0x12,0x0B,0x04,0x0C, /* 00000578 "........" */
- 0xFF,0xFF,0x02,0x00,0x00,0x00,0x0A,0x07, /* 00000580 "........" */
- 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000588 "........" */
- 0x00,0x00,0x0A,0x0A,0x12,0x0B,0x04,0x0C, /* 00000590 "........" */
- 0xFF,0xFF,0x04,0x00,0x00,0x00,0x0A,0x0B, /* 00000598 "........" */
- 0x5B,0x82,0x48,0x31,0x49,0x53,0x41,0x5F, /* 000005A0 "[.H1ISA_" */
- 0x08,0x5F,0x41,0x44,0x52,0x00,0x5B,0x80, /* 000005A8 "._ADR.[." */
- 0x50,0x49,0x52,0x51,0x02,0x0A,0x60,0x0A, /* 000005B0 "PIRQ..`." */
- 0x04,0x10,0x2E,0x5C,0x00,0x5B,0x81,0x29, /* 000005B8 "...\.[.)" */
- 0x5C,0x2F,0x04,0x5F,0x53,0x42,0x5F,0x50, /* 000005C0 "\/._SB_P" */
- 0x43,0x49,0x30,0x49,0x53,0x41,0x5F,0x50, /* 000005C8 "CI0ISA_P" */
- 0x49,0x52,0x51,0x01,0x50,0x49,0x52,0x41, /* 000005D0 "IRQ.PIRA" */
- 0x08,0x50,0x49,0x52,0x42,0x08,0x50,0x49, /* 000005D8 ".PIRB.PI" */
- 0x52,0x43,0x08,0x50,0x49,0x52,0x44,0x08, /* 000005E0 "RC.PIRD." */
- 0x5B,0x82,0x46,0x0B,0x53,0x59,0x53,0x52, /* 000005E8 "[.F.SYSR" */
- 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000005F0 "._HID.A." */
- 0x0C,0x02,0x08,0x5F,0x55,0x49,0x44,0x01, /* 000005F8 "..._UID." */
- 0x08,0x43,0x52,0x53,0x5F,0x11,0x4E,0x08, /* 00000600 ".CRS_.N." */
- 0x0A,0x8A,0x47,0x01,0x10,0x00,0x10,0x00, /* 00000608 "..G....." */
- 0x00,0x10,0x47,0x01,0x22,0x00,0x22,0x00, /* 00000610 "..G."."." */
- 0x00,0x0C,0x47,0x01,0x30,0x00,0x30,0x00, /* 00000618 "..G.0.0." */
- 0x00,0x10,0x47,0x01,0x44,0x00,0x44,0x00, /* 00000620 "..G.D.D." */
- 0x00,0x1C,0x47,0x01,0x62,0x00,0x62,0x00, /* 00000628 "..G.b.b." */
- 0x00,0x02,0x47,0x01,0x65,0x00,0x65,0x00, /* 00000630 "..G.e.e." */
- 0x00,0x0B,0x47,0x01,0x72,0x00,0x72,0x00, /* 00000638 "..G.r.r." */
- 0x00,0x0E,0x47,0x01,0x80,0x00,0x80,0x00, /* 00000640 "..G....." */
- 0x00,0x01,0x47,0x01,0x84,0x00,0x84,0x00, /* 00000648 "..G....." */
- 0x00,0x03,0x47,0x01,0x88,0x00,0x88,0x00, /* 00000650 "..G....." */
- 0x00,0x01,0x47,0x01,0x8C,0x00,0x8C,0x00, /* 00000658 "..G....." */
- 0x00,0x03,0x47,0x01,0x90,0x00,0x90,0x00, /* 00000660 "..G....." */
- 0x00,0x10,0x47,0x01,0xA2,0x00,0xA2,0x00, /* 00000668 "..G....." */
- 0x00,0x1C,0x47,0x01,0xE0,0x00,0xE0,0x00, /* 00000670 "..G....." */
- 0x00,0x10,0x47,0x01,0xA0,0x08,0xA0,0x08, /* 00000678 "..G....." */
- 0x00,0x04,0x47,0x01,0xC0,0x0C,0xC0,0x0C, /* 00000680 "..G....." */
- 0x00,0x10,0x47,0x01,0xD0,0x04,0xD0,0x04, /* 00000688 "..G....." */
- 0x00,0x02,0x79,0x00,0x14,0x0B,0x5F,0x43, /* 00000690 "..y..._C" */
- 0x52,0x53,0x00,0xA4,0x43,0x52,0x53,0x5F, /* 00000698 "RS..CRS_" */
- 0x5B,0x82,0x2B,0x50,0x49,0x43,0x5F,0x08, /* 000006A0 "[.+PIC_." */
- 0x5F,0x48,0x49,0x44,0x0B,0x41,0xD0,0x08, /* 000006A8 "_HID.A.." */
- 0x5F,0x43,0x52,0x53,0x11,0x18,0x0A,0x15, /* 000006B0 "_CRS...." */
- 0x47,0x01,0x20,0x00,0x20,0x00,0x01,0x02, /* 000006B8 "G. . ..." */
- 0x47,0x01,0xA0,0x00,0xA0,0x00,0x01,0x02, /* 000006C0 "G......." */
- 0x22,0x04,0x00,0x79,0x00,0x5B,0x82,0x47, /* 000006C8 ""..y.[.G" */
- 0x05,0x44,0x4D,0x41,0x30,0x08,0x5F,0x48, /* 000006D0 ".DMA0._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x02,0x00,0x08, /* 000006D8 "ID.A...." */
- 0x5F,0x43,0x52,0x53,0x11,0x41,0x04,0x0A, /* 000006E0 "_CRS.A.." */
- 0x3D,0x2A,0x10,0x04,0x47,0x01,0x00,0x00, /* 000006E8 "=*..G..." */
- 0x00,0x00,0x00,0x10,0x47,0x01,0x81,0x00, /* 000006F0 "....G..." */
- 0x81,0x00,0x00,0x03,0x47,0x01,0x87,0x00, /* 000006F8 "....G..." */
- 0x87,0x00,0x00,0x01,0x47,0x01,0x89,0x00, /* 00000700 "....G..." */
- 0x89,0x00,0x00,0x03,0x47,0x01,0x8F,0x00, /* 00000708 "....G..." */
- 0x8F,0x00,0x00,0x01,0x47,0x01,0xC0,0x00, /* 00000710 "....G..." */
- 0xC0,0x00,0x00,0x20,0x47,0x01,0x80,0x04, /* 00000718 "... G..." */
- 0x80,0x04,0x00,0x10,0x79,0x00,0x5B,0x82, /* 00000720 "....y.[." */
- 0x25,0x54,0x4D,0x52,0x5F,0x08,0x5F,0x48, /* 00000728 "%TMR_._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x01,0x00,0x08, /* 00000730 "ID.A...." */
- 0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000738 "_CRS...." */
- 0x47,0x01,0x40,0x00,0x40,0x00,0x00,0x04, /* 00000740 "G.@.@..." */
- 0x22,0x01,0x00,0x79,0x00,0x5B,0x82,0x25, /* 00000748 ""..y.[.%" */
- 0x52,0x54,0x43,0x5F,0x08,0x5F,0x48,0x49, /* 00000750 "RTC_._HI" */
- 0x44,0x0C,0x41,0xD0,0x0B,0x00,0x08,0x5F, /* 00000758 "D.A...._" */
- 0x43,0x52,0x53,0x11,0x10,0x0A,0x0D,0x47, /* 00000760 "CRS....G" */
- 0x01,0x70,0x00,0x70,0x00,0x00,0x02,0x22, /* 00000768 ".p.p..."" */
- 0x00,0x01,0x79,0x00,0x5B,0x82,0x22,0x53, /* 00000770 "..y.[."S" */
- 0x50,0x4B,0x52,0x08,0x5F,0x48,0x49,0x44, /* 00000778 "PKR._HID" */
- 0x0C,0x41,0xD0,0x08,0x00,0x08,0x5F,0x43, /* 00000780 ".A...._C" */
- 0x52,0x53,0x11,0x0D,0x0A,0x0A,0x47,0x01, /* 00000788 "RS....G." */
- 0x61,0x00,0x61,0x00,0x00,0x01,0x79,0x00, /* 00000790 "a.a...y." */
- 0x5B,0x82,0x31,0x50,0x53,0x32,0x4D,0x08, /* 00000798 "[.1PS2M." */
- 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0F, /* 000007A0 "_HID.A.." */
- 0x13,0x08,0x5F,0x43,0x49,0x44,0x0C,0x41, /* 000007A8 ".._CID.A" */
- 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 000007B0 "....._ST" */
- 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 000007B8 "A....._C" */
- 0x52,0x53,0x11,0x08,0x0A,0x05,0x22,0x00, /* 000007C0 "RS...."." */
- 0x10,0x79,0x00,0x5B,0x82,0x42,0x04,0x50, /* 000007C8 ".y.[.B.P" */
- 0x53,0x32,0x4B,0x08,0x5F,0x48,0x49,0x44, /* 000007D0 "S2K._HID" */
- 0x0C,0x41,0xD0,0x03,0x03,0x08,0x5F,0x43, /* 000007D8 ".A...._C" */
- 0x49,0x44,0x0C,0x41,0xD0,0x03,0x0B,0x14, /* 000007E0 "ID.A...." */
- 0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A, /* 000007E8 "._STA..." */
- 0x0F,0x08,0x5F,0x43,0x52,0x53,0x11,0x18, /* 000007F0 ".._CRS.." */
- 0x0A,0x15,0x47,0x01,0x60,0x00,0x60,0x00, /* 000007F8 "..G.`.`." */
- 0x00,0x01,0x47,0x01,0x64,0x00,0x64,0x00, /* 00000800 "..G.d.d." */
- 0x00,0x01,0x22,0x02,0x00,0x79,0x00,0x5B, /* 00000808 ".."..y.[" */
- 0x82,0x3A,0x46,0x44,0x43,0x30,0x08,0x5F, /* 00000810 ".:FDC0._" */
- 0x48,0x49,0x44,0x0C,0x41,0xD0,0x07,0x00, /* 00000818 "HID.A..." */
- 0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4, /* 00000820 ".._STA.." */
- 0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000828 "..._CRS." */
- 0x1B,0x0A,0x18,0x47,0x01,0xF0,0x03,0xF0, /* 00000830 "...G...." */
- 0x03,0x01,0x06,0x47,0x01,0xF7,0x03,0xF7, /* 00000838 "...G...." */
- 0x03,0x01,0x01,0x22,0x40,0x00,0x2A,0x04, /* 00000840 "..."@.*." */
- 0x00,0x79,0x00,0x5B,0x82,0x35,0x55,0x41, /* 00000848 ".y.[.5UA" */
- 0x52,0x31,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000850 "R1._HID." */
- 0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49, /* 00000858 "A...._UI" */
- 0x44,0x01,0x14,0x09,0x5F,0x53,0x54,0x41, /* 00000860 "D..._STA" */
- 0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 00000868 "....._CR" */
- 0x53,0x11,0x10,0x0A,0x0D,0x47,0x01,0xF8, /* 00000870 "S....G.." */
- 0x03,0xF8,0x03,0x01,0x08,0x22,0x10,0x00, /* 00000878 ".....".." */
- 0x79,0x00,0x5B,0x82,0x36,0x4C,0x54,0x50, /* 00000880 "y.[.6LTP" */
- 0x31,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000888 "1._HID.A" */
- 0xD0,0x04,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000890 "...._UID" */
- 0x0A,0x02,0x14,0x09,0x5F,0x53,0x54,0x41, /* 00000898 "...._STA" */
- 0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 000008A0 "....._CR" */
- 0x53,0x11,0x10,0x0A,0x0D,0x47,0x01,0x78, /* 000008A8 "S....G.x" */
- 0x03,0x78,0x03,0x08,0x08,0x22,0x80,0x00, /* 000008B0 ".x...".." */
- 0x79,0x00,
-};
-int DsdtLen=sizeof(AmlCode);
diff --git a/tools/firmware/acpi/acpi_facs.c b/tools/firmware/acpi/acpi_facs.c
deleted file mode 100644
index 12947d0fed..0000000000
--- a/tools/firmware/acpi/acpi_facs.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#include "acpi2_0.h"
-#include "acpi_facs.h"
-
-//
-// Firmware ACPI Control Structure
-//
-
-ACPI_2_0_FACS Facs = {
- ACPI_2_0_FACS_SIGNATURE,
- sizeof (ACPI_2_0_FACS),
-
- //
- // Hardware Signature
- //
- 0x00000000,
-
- ACPI_FIRMWARE_WAKING_VECTOR,
- ACPI_GLOBAL_LOCK,
- ACPI_FIRMWARE_CONTROL_STRUCTURE_FLAGS,
- ACPI_X_FIRMWARE_WAKING_VECTOR,
- ACPI_2_0_FACS_VERSION,
- {
- 0x00, // Reserved Fields
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- }
-};
diff --git a/tools/firmware/acpi/acpi_fadt.c b/tools/firmware/acpi/acpi_fadt.c
deleted file mode 100644
index 39b970c203..0000000000
--- a/tools/firmware/acpi/acpi_fadt.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-
-#include "acpi2_0.h"
-#include "acpi_fadt.h"
-
-//
-// Fixed ACPI Description Table
-//
-
-ACPI_2_0_FADT Fadt = {
- {
- ACPI_2_0_FADT_SIGNATURE,
- sizeof (ACPI_2_0_FADT),
- ACPI_2_0_FADT_REVISION,
- 0x00,// Checksum will be updated later
- ACPI_OEM_ID, // OEM ID
- ACPI_OEM_TABLE_ID, // OEM Table ID
- ACPI_OEM_REVISION, // OEM Revision
- ACPI_CREATOR_ID, // Creator ID
- ACPI_CREATOR_REVISION, // Creator Revision
- },
- //
- // These addresses will be updated later
- //
- 0x00000000, // Physical Address (0~4G) of the FACS
- 0x00000000, // Physical Address (0~4G) of the DSDT
-
- 0x00,
- ACPI_PREFERRED_PM_PROFILE, // Enterprise
- ACPI_SCI_INT, // IRQ 9
- ACPI_SMI_CMD,
- ACPI_ACPI_ENABLE,
- ACPI_ACPI_DISABLE,
- ACPI_S4_BIOS_REQ, // zero. not supported
- ACPI_PSTATE_CNT, // not supported
-
- ACPI_PM1A_EVT_BLK_ADDRESS, // required
- ACPI_PM1B_EVT_BLK_ADDRESS, // not supported
- ACPI_PM1A_CNT_BLK_ADDRESS, // required
- ACPI_PM1B_CNT_BLK_ADDRESS, // not supported
- ACPI_PM2_CNT_BLK_ADDRESS, // not supported
- ACPI_PM_TMR_BLK_ADDRESS, // required
- ACPI_GPE0_BLK_ADDRESS, // not supported
- ACPI_GPE1_BLK_ADDRESS, // not supported
- ACPI_PM1_EVT_LEN,
- ACPI_PM1_CNT_LEN,
- ACPI_PM2_CNT_LEN,
- ACPI_PM_TMR_LEN,
- ACPI_GPE0_BLK_LEN,
- ACPI_GPE1_BLK_LEN,
- ACPI_GPE1_BASE,
-
- ACPI_CST_CNT,
- ACPI_P_LVL2_LAT, // >100, not support C2 state
- ACPI_P_LVL3_LAT, // >1000, not support C3 state
- ACPI_FLUSH_SIZE, // not support
- ACPI_FLUSH_STRIDE, // not support
- ACPI_DUTY_OFFSET, // not support
- ACPI_DUTY_WIDTH, // not support
- ACPI_DAY_ALRM, // not support
- ACPI_MON_ALRM, // not support
- ACPI_CENTURY, // not support
- ACPI_IAPC_BOOT_ARCH,
- 0x00,
- ACPI_FIXED_FEATURE_FLAGS,
-
- //
- // Reset Register Block
- //
- { ACPI_RESET_REG_ADDRESS_SPACE_ID,
- ACPI_RESET_REG_BIT_WIDTH,
- ACPI_RESET_REG_BIT_OFFSET,
- 0x00,
- ACPI_RESET_REG_ADDRESS,
- },
-
- ACPI_RESET_VALUE,
- {
- 0x00,
- 0x00,
- 0x00,
- },
- //
- // These addresses will be updated later
- //
- 0x0000000000000000, // X_FIRMWARE_CTRL: 64bit physical address of the FACS.
- 0x0000000000000000, // X_DSDT: 64bit physical address of the DSDT.
-
- //
- // PM1a Event Register Block
- //
- {
- ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID,
- ACPI_PM1A_EVT_BLK_BIT_WIDTH,
- ACPI_PM1A_EVT_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM1A_EVT_BLK_ADDRESS,
- },
-
- //
- // PM1b Event Register Block
- //
- {
- ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID, // not support
- ACPI_PM1B_EVT_BLK_BIT_WIDTH,
- ACPI_PM1B_EVT_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM1B_EVT_BLK_ADDRESS,
- },
-
- //
- // PM1a Control Register Block
- //
- {
- ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID,
- ACPI_PM1A_CNT_BLK_BIT_WIDTH,
- ACPI_PM1A_CNT_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM1A_CNT_BLK_ADDRESS,
- },
-
- //
- // PM1b Control Register Block
- //
- {
- ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID,
- ACPI_PM1B_CNT_BLK_BIT_WIDTH,
- ACPI_PM1B_CNT_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM1B_CNT_BLK_ADDRESS,
- },
-
- //
- // PM2 Control Register Block
- //
- {
- ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID,
- ACPI_PM2_CNT_BLK_BIT_WIDTH,
- ACPI_PM2_CNT_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM2_CNT_BLK_ADDRESS,
- },
-
- //
- // PM Timer Control Register Block
- //
- {
- ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID,
- ACPI_PM_TMR_BLK_BIT_WIDTH,
- ACPI_PM_TMR_BLK_BIT_OFFSET,
- 0x00,
- ACPI_PM_TMR_BLK_ADDRESS,
- },
-
- //
- // General Purpose Event 0 Register Block
- //
- {
- ACPI_GPE0_BLK_ADDRESS_SPACE_ID,
- ACPI_GPE0_BLK_BIT_WIDTH,
- ACPI_GPE0_BLK_BIT_OFFSET,
- 0x00,
- ACPI_GPE0_BLK_ADDRESS,
- },
-
- //
- // General Purpose Event 1 Register Block
- //
- {
- ACPI_GPE1_BLK_ADDRESS_SPACE_ID,
- ACPI_GPE1_BLK_BIT_WIDTH,
- ACPI_GPE1_BLK_BIT_OFFSET,
- 0x00,
- ACPI_GPE1_BLK_ADDRESS
- }
-
-};
diff --git a/tools/firmware/acpi/acpi_fadt.h b/tools/firmware/acpi/acpi_fadt.h
deleted file mode 100644
index d1ecea5588..0000000000
--- a/tools/firmware/acpi/acpi_fadt.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#ifndef _FADT_H_
-#define _FADT_H_
-
-//
-// FADT Definitions, see ACPI 2.0 specification for details.
-//
-
-#define ACPI_OEM_FADT_REVISION 0x00000001 // TBD
-
-#define ACPI_PREFERRED_PM_PROFILE 0x00
-#define ACPI_SCI_INT 0x0009
-#define ACPI_SMI_CMD 0x00000000
-#define ACPI_ACPI_ENABLE 0x00
-#define ACPI_ACPI_DISABLE 0x00
-#define ACPI_S4_BIOS_REQ 0x00
-#define ACPI_PSTATE_CNT 0x00
-#define ACPI_GPE1_BASE 0x00
-#define ACPI_CST_CNT 0x00
-#define ACPI_P_LVL2_LAT 0x0064
-#define ACPI_P_LVL3_LAT 0X03E8
-#define ACPI_FLUSH_SIZE 0x00
-#define ACPI_FLUSH_STRIDE 0x00
-#define ACPI_DUTY_OFFSET 0x01
-#define ACPI_DUTY_WIDTH 0x00
-#define ACPI_DAY_ALRM 0x00
-#define ACPI_MON_ALRM 0x00
-#define ACPI_CENTURY 0x00
-
-//
-// IA-PC Boot Architecture Flags, see ACPI 2.0 table specification and Acpi2_0.h
-//
-#define ACPI_IAPC_BOOT_ARCH (ACPI_LEGACY_DEVICES | ACPI_8042)
-
-//
-// Fixed Feature Flags
-//
-#define ACPI_FIXED_FEATURE_FLAGS (ACPI_PROC_C1|ACPI_SLP_BUTTON|ACPI_WBINVD|ACPI_PWR_BUTTON|ACPI_FIX_RTC)
-
-//
-// PM1A Event Register Block Generic Address Information
-//
-#define ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM1A_EVT_BLK_BIT_WIDTH 0x20
-#define ACPI_PM1A_EVT_BLK_BIT_OFFSET 0x00
-#define ACPI_PM1A_EVT_BLK_ADDRESS 0x000000000000c010
-
-//
-// PM1B Event Register Block Generic Address Information
-//
-#define ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM1B_EVT_BLK_BIT_WIDTH 0x00
-#define ACPI_PM1B_EVT_BLK_BIT_OFFSET 0x00
-#define ACPI_PM1B_EVT_BLK_ADDRESS 0x0000000000000000
-
-//
-// PM1A Control Register Block Generic Address Information
-//
-#define ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM1A_CNT_BLK_BIT_WIDTH 0x10
-#define ACPI_PM1A_CNT_BLK_BIT_OFFSET 0x00
-#define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
-
-//
-// PM1B Control Register Block Generic Address Information
-//
-#define ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM1B_CNT_BLK_BIT_WIDTH 0x00
-#define ACPI_PM1B_CNT_BLK_BIT_OFFSET 0x00
-#define ACPI_PM1B_CNT_BLK_ADDRESS 0x0000000000000000
-
-//
-// PM2 Control Register Block Generic Address Information
-//
-#define ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM2_CNT_BLK_BIT_WIDTH 0x00
-#define ACPI_PM2_CNT_BLK_BIT_OFFSET 0x00
-#define ACPI_PM2_CNT_BLK_ADDRESS 0x0000000000000000
-
-//
-// Power Management Timer Control Register Block Generic Address
-// Information
-//
-#define ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_PM_TMR_BLK_BIT_WIDTH 0x20
-#define ACPI_PM_TMR_BLK_BIT_OFFSET 0x00
-#define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
-
-//
-// General Purpose Event 0 Register Block Generic Address
-// Information
-//
-
-#define ACPI_GPE0_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_GPE0_BLK_BIT_WIDTH 0x00
-#define ACPI_GPE0_BLK_BIT_OFFSET 0x00
-#define ACPI_GPE0_BLK_ADDRESS 0x00
-
-//
-// General Purpose Event 1 Register Block Generic Address
-// Information
-//
-
-#define ACPI_GPE1_BLK_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_GPE1_BLK_BIT_WIDTH 0x00
-#define ACPI_GPE1_BLK_BIT_OFFSET 0x00
-#define ACPI_GPE1_BLK_ADDRESS 0x00
-
-
-//
-// Reset Register Generic Address Information
-//
-#define ACPI_RESET_REG_ADDRESS_SPACE_ID ACPI_SYSTEM_IO
-#define ACPI_RESET_REG_BIT_WIDTH 0x08
-#define ACPI_RESET_REG_BIT_OFFSET 0x00
-#define ACPI_RESET_REG_ADDRESS 0x0000000000000CF9
-#define ACPI_RESET_VALUE 0x06
-
-//
-// Number of bytes decoded by PM1 event blocks (a and b)
-//
-#define ACPI_PM1_EVT_LEN ((ACPI_PM1A_EVT_BLK_BIT_WIDTH + ACPI_PM1B_EVT_BLK_BIT_WIDTH) / 8)
-
-//
-// Number of bytes decoded by PM1 control blocks (a and b)
-//
-#define ACPI_PM1_CNT_LEN ((ACPI_PM1A_CNT_BLK_BIT_WIDTH + ACPI_PM1B_CNT_BLK_BIT_WIDTH) / 8)
-
-//
-// Number of bytes decoded by PM2 control block
-//
-#define ACPI_PM2_CNT_LEN (ACPI_PM2_CNT_BLK_BIT_WIDTH / 8)
-
-//
-// Number of bytes decoded by PM timer block
-//
-#define ACPI_PM_TMR_LEN (ACPI_PM_TMR_BLK_BIT_WIDTH / 8)
-
-//
-// Number of bytes decoded by GPE0 block
-//
-#define ACPI_GPE0_BLK_LEN (ACPI_GPE0_BLK_BIT_WIDTH / 8)
-
-//
-// Number of bytes decoded by GPE1 block
-//
-#define ACPI_GPE1_BLK_LEN 0
-
-#endif
diff --git a/tools/firmware/acpi/acpi_gen.c b/tools/firmware/acpi/acpi_gen.c
deleted file mode 100644
index 25c0ca7917..0000000000
--- a/tools/firmware/acpi/acpi_gen.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#include "acpi2_0.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define USAGE "Usage: acpi_gen filename \n" \
- " generage acpitable and write to the binary \n" \
- " filename - the binary name\n"
-
-int main(int argc, char **argv)
-{
- char *filename;
- char buf[ACPI_TABLE_SIZE] = { 0 };
- FILE *f;
-
- if (argc < 2) {
- fprintf(stderr,"%s",USAGE);
- exit(1);
- }
-
- filename = argv[1];
-
- if ((f = fopen(filename, "w+")) == NULL) {
- fprintf(stderr,"Can not open %s", filename);
- exit(1);
- }
-
- AcpiBuildTable((uint8_t *)buf);
-
- if (fwrite(buf, ACPI_TABLE_SIZE, 1, f) < 1) {
- fprintf(stderr,"Can not write to %s\n", filename);
- exit(1);
- }
-
- return 0;
-}
diff --git a/tools/firmware/acpi/acpi_madt.c b/tools/firmware/acpi/acpi_madt.c
deleted file mode 100644
index 7a0234f1f7..0000000000
--- a/tools/firmware/acpi/acpi_madt.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#include "acpi_madt.h"
-
-//
-// Multiple APIC Description Table
-//
-
-ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE Madt = {
- {
- {
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
- sizeof (ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE),
- ACPI_2_0_MADT_REVISION,
- 0x00, // Checksum
- ACPI_OEM_ID,
- ACPI_OEM_TABLE_ID,
- ACPI_OEM_REVISION,
- ACPI_CREATOR_ID,
- ACPI_CREATOR_REVISION,
- },
- ACPI_LOCAL_APIC_ADDRESS,
- ACPI_MULTIPLE_APIC_FLAGS,
- },
-
- //
- // IO APIC
- //
- {
- {
- ACPI_IO_APIC,
- sizeof (ACPI_IO_APIC_STRUCTURE),
- 0x00,
- 0x00,
- ACPI_IO_APIC_ADDRESS_1,
- 0x0000
- }
- },
-
- //
- // LOCAL APIC Entries for up to 32 processors.
- //
- {
- {
- ACPI_PROCESSOR_LOCAL_APIC,
- sizeof (ACPI_LOCAL_APIC_STRUCTURE),
- 0x00,
- 0x00,
- 0x00000001,
- }
-
- }
-};
diff --git a/tools/firmware/acpi/acpi_madt.h b/tools/firmware/acpi/acpi_madt.h
deleted file mode 100644
index 042d3ff1a2..0000000000
--- a/tools/firmware/acpi/acpi_madt.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#ifndef _MADT_H_
-#define _MADT_H_
-
-#include "acpi2_0.h"
-
-//
-// MADT Definitions, see ACPI 2.0 specification for details
-//
-
-#define ACPI_LOCAL_APIC_ADDRESS 0xFEE00000
-
-#define ACPI_MULTIPLE_APIC_FLAGS (ACPI_PCAT_COMPAT)
-
-#define ACPI_IO_APIC_ADDRESS_1 0xFEC00000
-
-//
-// MADT structure
-//
-#pragma pack (1)
-typedef struct {
- ACPI_2_0_MADT Header;
- ACPI_IO_APIC_STRUCTURE IoApic[1];
- ACPI_LOCAL_APIC_STRUCTURE LocalApic[32];
-} ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE;
-#pragma pack ()
-
-#endif
diff --git a/tools/firmware/acpi/acpi_rsdt.c b/tools/firmware/acpi/acpi_rsdt.c
deleted file mode 100644
index 56390ef2ca..0000000000
--- a/tools/firmware/acpi/acpi_rsdt.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2004, 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.
- *
- */
-#include "acpi2_0.h"
-
-ACPI_2_0_RSDT Rsdt={
- {
- ACPI_2_0_RSDT_SIGNATURE,
- sizeof (ACPI_TABLE_HEADER), // udpated later
- ACPI_2_0_RSDT_REVISION,
- 0x0, //Checksum, updated later
- ACPI_OEM_ID,
- ACPI_OEM_TABLE_ID,
- ACPI_OEM_REVISION,
- ACPI_CREATOR_ID,
- ACPI_CREATOR_REVISION,
- },
- {0x0, 0x0}
-};
-
-ACPI_2_0_XSDT Xsdt={
- {
- ACPI_2_0_XSDT_SIGNATURE,
- sizeof (ACPI_TABLE_HEADER), //update later
- ACPI_2_0_XSDT_REVISION,
- 0x0, //Checksum, update later
- ACPI_OEM_ID,
- ACPI_OEM_TABLE_ID,
- ACPI_OEM_REVISION,
- ACPI_CREATOR_ID,
- ACPI_CREATOR_REVISION,
- },
- {0x0, 0x0},
-};
-
-
-ACPI_2_0_RSDP Rsdp={
- ACPI_2_0_RSDP_SIGNATURE,
- 0x00, // Checksum, updated in later
- ACPI_OEM_ID, // OEM ID,
- ACPI_OEM_REVISION,
- 0x0, // RSDT address, updated later
- sizeof (ACPI_2_0_RSDP),
- 0x0, // XSDT address, updated later
- 0x0, // Extended Checksum, update later
- {
- 0x0, // Reserved
- 0x0, // Reserved
- 0x0, // Reserved
- }
-};
-
-
-
diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile
index 3f9b7a95bb..4e4502d673 100644
--- a/tools/firmware/hvmloader/Makefile
+++ b/tools/firmware/hvmloader/Makefile
@@ -32,35 +32,38 @@ DEFINES =-DDEBUG
XENINC =-I$(XEN_ROOT)/tools/libxc
# Disable PIE/SSP if GCC supports them. They can break us.
-CFLAGS += $(call test-gcc-flag,$(CC),-nopie)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector-all)
+CFLAGS += $(call cc-option,$(CC),-nopie,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
OBJCOPY = objcopy
CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float
-LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
+LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
-SRCS = hvmloader.c acpi_madt.c mp_tables.c util.c smbios.c
+SRCS = hvmloader.c mp_tables.c util.c smbios.c acpi_utils.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
.PHONY: all
all: hvmloader
-hvmloader: roms.h $(SRCS)
+hvmloader: roms.h acpi/acpi.a $(SRCS)
$(CC) $(CFLAGS) -c $(SRCS)
- $(CC) $(LDFLAGS) -o hvmloader.tmp $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o hvmloader.tmp $(OBJS) acpi/acpi.a
$(OBJCOPY) hvmloader.tmp hvmloader
rm -f hvmloader.tmp
-roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../vmxassist/vmxassist.bin ../acpi/acpi.bin
+.PHONY: acpi/acpi.a
+acpi/acpi.a:
+ $(MAKE) -C acpi
+
+roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../vmxassist/vmxassist.bin
sh ./mkhex rombios ../rombios/BIOS-bochs-latest > roms.h
sh ./mkhex vgabios_stdvga ../vgabios/VGABIOS-lgpl-latest.bin >> roms.h
sh ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
sh ./mkhex vmxassist ../vmxassist/vmxassist.bin >> roms.h
- sh ./mkhex acpi ../acpi/acpi.bin >> roms.h
.PHONY: clean
clean:
rm -f roms.h acpi.h
rm -f hvmloader hvmloader.tmp hvmloader.o $(OBJS)
-
+ $(MAKE) -C acpi clean
diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
new file mode 100644
index 0000000000..9aec04735a
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2004, 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.
+#
+
+override XEN_TARGET_ARCH = x86_32
+XEN_ROOT = ../../../..
+CFLAGS := -I. -I.. -I$(XEN_ROOT)/tools/libxc
+include $(XEN_ROOT)/tools/Rules.mk
+
+C_SRC = build.c dsdt.c static_tables.c
+H_SRC = $(wildcard *.h)
+OBJS = $(patsubst %.c,%.o,$(C_SRC))
+
+IASL_VER = acpica-unix-20050513
+IASL_URL = http://developer.intel.com/technology/iapc/acpi/downloads/$(IASL_VER).tar.gz
+
+vpath iasl $(PATH)
+all: acpi.a
+
+dsdt.c: dsdt.asl
+ $(MAKE) iasl
+ iasl -tc dsdt.asl
+ mv dsdt.hex dsdt.c
+ echo "int DsdtLen=sizeof(AmlCode);" >> dsdt.c
+ rm *.aml
+
+iasl:
+ @echo
+ @echo "ACPI ASL compiler(iasl) is needed"
+ @echo "Download Intel ACPI CA"
+ @echo "If wget failed, please download and compile manually from"
+ @echo "http://developer.intel.com/technology/iapc/acpi/downloads.htm"
+ @echo
+ wget $(IASL_URL)
+ tar xzf $(IASL_VER).tar.gz
+ make -C $(IASL_VER)/compiler
+ $(INSTALL_PROG) $(IASL_VER)/compiler/iasl /usr/bin/iasl
+
+acpi.a: $(OBJS)
+ $(AR) rc $@ $(OBJS)
+
+%.o: %.c $(H_SRC)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+clean:
+ rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz
+
+install: all
diff --git a/tools/firmware/acpi/README b/tools/firmware/hvmloader/acpi/README
index 210d5bac71..210d5bac71 100644
--- a/tools/firmware/acpi/README
+++ b/tools/firmware/hvmloader/acpi/README
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
new file mode 100644
index 0000000000..62cb16eeb8
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ */
+#ifndef _ACPI_2_0_H_
+#define _ACPI_2_0_H_
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+#ifdef __i386__
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+#else
+typedef unsigned long uint64_t;
+typedef signed long int64_t;
+#endif
+
+#include <xen/xen.h>
+
+#define ASCII32(a,b,c,d) \
+ (((a) << 0) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+#define ASCII64(a,b,c,d,e,f,g,h) \
+ (((uint64_t)ASCII32(a,b,c,d)) | (((uint64_t)ASCII32(e,f,g,h)) << 32))
+
+#pragma pack (1)
+
+/*
+ * Common ACPI header.
+ */
+struct acpi_header {
+ uint32_t signature;
+ uint32_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ uint8_t oem_id[6];
+ uint64_t oem_table_id;
+ uint32_t oem_revision;
+ uint32_t creator_id;
+ uint32_t creator_revision;
+};
+
+#define ACPI_OEM_ID {'I','N','T','E','L',' '}
+#define ACPI_OEM_TABLE_ID ASCII32(' ','T','B','D')
+#define ACPI_OEM_REVISION 0x00000002
+#define ACPI_CREATOR_ID 0x00 /* TBD */
+#define ACPI_CREATOR_REVISION 0x00000002
+
+/*
+ * ACPI 2.0 Generic Address Space definition.
+ */
+struct acpi_20_generic_address {
+ uint8_t address_space_id;
+ uint8_t register_bit_width;
+ uint8_t register_bit_offset;
+ uint8_t reserved;
+ uint64_t address;
+};
+
+/*
+ * Generic Address Space Address IDs.
+ */
+#define ACPI_SYSTEM_MEMORY 0
+#define ACPI_SYSTEM_IO 1
+#define ACPI_PCI_CONFIGURATION_SPACE 2
+#define ACPI_EMBEDDED_CONTROLLER 3
+#define ACPI_SMBUS 4
+#define ACPI_FUNCTIONAL_FIXED_HARDWARE 0x7F
+
+/*
+ * Root System Description Pointer Structure in ACPI 1.0.
+ */
+struct acpi_10_rsdp {
+ uint64_t signature;
+ uint8_t checksum;
+ uint8_t oem_id[6];
+ uint8_t reserved;
+ uint32_t rsdt_address;
+};
+
+/*
+ * Root System Description Pointer Structure.
+ */
+struct acpi_20_rsdp {
+ uint64_t signature;
+ uint8_t checksum;
+ uint8_t oem_id[6];
+ uint8_t revision;
+ uint32_t rsdt_address;
+ uint32_t length;
+ uint64_t xsdt_address;
+ uint8_t extended_checksum;
+ uint8_t reserved[3];
+};
+
+/*
+ * The maximum number of entrys in RSDT or XSDT.
+ */
+#define ACPI_MAX_NUM_TABLES 5
+
+/*
+ * Root System Description Table (RSDT).
+ */
+struct acpi_20_rsdt {
+ struct acpi_header header;
+ uint32_t entry[ACPI_MAX_NUM_TABLES];
+};
+#define ACPI_2_0_RSDT_REVISION 0x01
+
+/*
+ * Extended System Description Table (XSDT).
+ */
+struct acpi_20_xsdt {
+ struct acpi_header header;
+ uint64_t entry[ACPI_MAX_NUM_TABLES];
+};
+#define ACPI_2_0_XSDT_REVISION 0x01
+
+/*
+ * TCG Hardware Interface Table (TCPA)
+ */
+
+typedef struct _ACPI_2_0_TCPA_CLIENT {
+ struct acpi_header header;
+ uint16_t PlatformClass;
+ uint32_t LAML;
+ uint64_t LASA;
+} ACPI_2_0_TCPA_CLIENT;
+
+#define ACPI_2_0_TCPA_REVISION 0x02
+#define ACPI_2_0_TCPA_LAML_SIZE (64*1024)
+
+/*
+ * Fixed ACPI Description Table Structure (FADT).
+ */
+struct acpi_20_fadt {
+ struct acpi_header header;
+ uint32_t firmware_ctrl;
+ uint32_t dsdt;
+ uint8_t reserved0;
+ uint8_t preferred_pm_profile;
+ uint16_t sci_int;
+ uint32_t smi_cmd;
+ uint8_t acpi_enable;
+ uint8_t acpi_disable;
+ uint8_t s4bios_req;
+ uint8_t pstate_cnt;
+ uint32_t pm1a_evt_blk;
+ uint32_t pm1b_evt_blk;
+ uint32_t pm1a_cnt_blk;
+ uint32_t pm1b_cnt_blk;
+ uint32_t pm2_cnt_blk;
+ uint32_t pm_tmr_blk;
+ uint32_t gpe0_blk;
+ uint32_t gpe1_blk;
+ uint8_t pm1_evt_len;
+ uint8_t pm1_cnt_len;
+ uint8_t pm2_cnt_len;
+ uint8_t pm_tmr_len;
+ uint8_t gpe0_blk_len;
+ uint8_t gpe1_blk_len;
+ uint8_t gpe1_base;
+ uint8_t cst_cnt;
+ uint16_t p_lvl2_lat;
+ uint16_t p_lvl3_lat;
+ uint16_t flush_size;
+ uint16_t flush_stride;
+ uint8_t duty_offset;
+ uint8_t duty_width;
+ uint8_t day_alrm;
+ uint8_t mon_alrm;
+ uint8_t century;
+ uint16_t iapc_boot_arch;
+ uint8_t reserved1;
+ uint32_t flags;
+ struct acpi_20_generic_address reset_reg;
+ uint8_t reset_value;
+ uint8_t reserved2[3];
+ uint64_t x_firmware_ctrl;
+ uint64_t x_dsdt;
+ struct acpi_20_generic_address x_pm1a_evt_blk;
+ struct acpi_20_generic_address x_pm1b_evt_blk;
+ struct acpi_20_generic_address x_pm1a_cnt_blk;
+ struct acpi_20_generic_address x_pm1b_cnt_blk;
+ struct acpi_20_generic_address x_pm2_cnt_blk;
+ struct acpi_20_generic_address x_pm_tmr_blk;
+ struct acpi_20_generic_address x_gpe0_blk;
+ struct acpi_20_generic_address x_gpe1_blk;
+};
+#define ACPI_2_0_FADT_REVISION 0x03
+
+/*
+ * FADT Boot Architecture Flags.
+ */
+#define ACPI_LEGACY_DEVICES (1 << 0)
+#define ACPI_8042 (1 << 1)
+
+/*
+ * FADT Fixed Feature Flags.
+ */
+#define ACPI_WBINVD (1 << 0)
+#define ACPI_WBINVD_FLUSH (1 << 1)
+#define ACPI_PROC_C1 (1 << 2)
+#define ACPI_P_LVL2_UP (1 << 3)
+#define ACPI_PWR_BUTTON (1 << 4)
+#define ACPI_SLP_BUTTON (1 << 5)
+#define ACPI_FIX_RTC (1 << 6)
+#define ACPI_RTC_S4 (1 << 7)
+#define ACPI_TMR_VAL_EXT (1 << 8)
+#define ACPI_DCK_CAP (1 << 9)
+#define ACPI_RESET_REG_SUP (1 << 10)
+#define ACPI_SEALED_CASE (1 << 11)
+#define ACPI_HEADLESS (1 << 12)
+#define ACPI_CPU_SW_SLP (1 << 13)
+
+/*
+ * Firmware ACPI Control Structure (FACS).
+ */
+struct acpi_20_facs {
+ uint32_t signature;
+ uint32_t length;
+ uint32_t hardware_signature;
+ uint32_t firmware_waking_vector;
+ uint32_t global_lock;
+ uint32_t flags;
+ uint64_t x_firmware_waking_vector;
+ uint8_t version;
+ uint8_t reserved[31];
+};
+
+#define ACPI_2_0_FACS_VERSION 0x01
+
+/*
+ * Multiple APIC Description Table header definition (MADT).
+ */
+struct acpi_20_madt {
+ struct acpi_header header;
+ uint32_t lapic_addr;
+ uint32_t flags;
+};
+
+#define ACPI_2_0_MADT_REVISION 0x01
+
+/*
+ * Multiple APIC Flags.
+ */
+#define ACPI_PCAT_COMPAT (1 << 0)
+
+/*
+ * Multiple APIC Description Table APIC structure types.
+ */
+#define ACPI_PROCESSOR_LOCAL_APIC 0x00
+#define ACPI_IO_APIC 0x01
+#define ACPI_INTERRUPT_SOURCE_OVERRIDE 0x02
+#define ACPI_NON_MASKABLE_INTERRUPT_SOURCE 0x03
+#define ACPI_LOCAL_APIC_NMI 0x04
+#define ACPI_LOCAL_APIC_ADDRESS_OVERRIDE 0x05
+#define ACPI_IO_SAPIC 0x06
+#define ACPI_PROCESSOR_LOCAL_SAPIC 0x07
+#define ACPI_PLATFORM_INTERRUPT_SOURCES 0x08
+
+/*
+ * APIC Structure Definitions.
+ */
+
+/*
+ * Processor Local APIC Structure Definition.
+ */
+struct acpi_20_madt_lapic {
+ uint8_t type;
+ uint8_t length;
+ uint8_t acpi_processor_id;
+ uint8_t apic_id;
+ uint32_t flags;
+};
+
+/*
+ * Local APIC Flags. All other bits are reserved and must be 0.
+ */
+#define ACPI_LOCAL_APIC_ENABLED (1 << 0)
+
+/*
+ * IO APIC Structure.
+ */
+struct acpi_20_madt_ioapic {
+ uint8_t type;
+ uint8_t length;
+ uint8_t ioapic_id;
+ uint8_t reserved;
+ uint32_t ioapic_addr;
+ uint32_t gsi_base;
+};
+
+struct acpi_20_madt_intsrcovr {
+ uint8_t type;
+ uint8_t length;
+ uint8_t bus;
+ uint8_t source;
+ uint32_t gsi;
+ uint16_t flags;
+};
+
+/*
+ * Table Signatures.
+ */
+#define ACPI_2_0_RSDP_SIGNATURE ASCII64('R','S','D',' ','P','T','R',' ')
+#define ACPI_2_0_FACS_SIGNATURE ASCII32('F','A','C','S')
+#define ACPI_2_0_FADT_SIGNATURE ASCII32('F','A','C','P')
+#define ACPI_2_0_MADT_SIGNATURE ASCII32('A','P','I','C')
+#define ACPI_2_0_RSDT_SIGNATURE ASCII32('R','S','D','T')
+#define ACPI_2_0_XSDT_SIGNATURE ASCII32('X','S','D','T')
+#define ACPI_2_0_TCPA_SIGNATURE ASCII32('T','C','P','A')
+
+#pragma pack ()
+
+#define ACPI_PHYSICAL_ADDRESS 0xEA000
+
+int acpi_build_tables(uint8_t *);
+
+#endif /* _ACPI_2_0_H_ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
new file mode 100644
index 0000000000..68b1e18bb0
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2006, Keir Fraser, XenSource Inc.
+ *
+ * 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 "acpi2_0.h"
+#include "../config.h"
+#include "../util.h"
+
+extern struct acpi_20_rsdp Rsdp;
+extern struct acpi_20_rsdt Rsdt;
+extern struct acpi_20_xsdt Xsdt;
+extern struct acpi_20_fadt Fadt;
+extern struct acpi_20_facs Facs;
+extern unsigned char AmlCode[];
+extern int DsdtLen;
+
+static void set_checksum(
+ void *table, uint32_t checksum_offset, uint32_t length)
+{
+ uint8_t *p, sum = 0;
+
+ p = table;
+ p[checksum_offset] = 0;
+
+ while ( length-- )
+ sum = sum + *p++;
+
+ p = table;
+ p[checksum_offset] = -sum;
+}
+
+int construct_madt(struct acpi_20_madt *madt)
+{
+ struct acpi_20_madt_intsrcovr *intsrcovr;
+ struct acpi_20_madt_ioapic *io_apic;
+ struct acpi_20_madt_lapic *lapic;
+ int i, offset = 0;
+
+ memset(madt, 0, sizeof(*madt));
+ madt->header.signature = ACPI_2_0_MADT_SIGNATURE;
+ madt->header.revision = ACPI_2_0_MADT_REVISION;
+ strncpy(madt->header.oem_id, "INTEL ", 6);
+ madt->header.oem_table_id = ACPI_OEM_TABLE_ID;
+ madt->header.oem_revision = ACPI_OEM_REVISION;
+ madt->header.creator_id = ACPI_CREATOR_ID;
+ madt->header.creator_revision = ACPI_CREATOR_REVISION;
+ madt->lapic_addr = LAPIC_BASE_ADDRESS;
+ madt->flags = ACPI_PCAT_COMPAT;
+ offset += sizeof(*madt);
+
+ intsrcovr = (struct acpi_20_madt_intsrcovr *)(madt + 1);
+ for ( i = 0; i < 16; i++ )
+ {
+ if ( !(PCI_ISA_IRQ_MASK & (1U << i)) )
+ continue;
+
+ /* PCI: active-low level-triggered */
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = ACPI_INTERRUPT_SOURCE_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = i;
+ intsrcovr->flags = 0xf;
+
+ offset += sizeof(*intsrcovr);
+ intsrcovr++;
+ }
+
+ io_apic = (struct acpi_20_madt_ioapic *)intsrcovr;
+ memset(io_apic, 0, sizeof(*io_apic));
+ io_apic->type = ACPI_IO_APIC;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->ioapic_id = IOAPIC_ID;
+ io_apic->ioapic_addr = IOAPIC_BASE_ADDRESS;
+ offset += sizeof(*io_apic);
+
+ lapic = (struct acpi_20_madt_lapic *)(io_apic + 1);
+ for ( i = 0; i < get_vcpu_nr(); i++ )
+ {
+ memset(lapic, 0, sizeof(*lapic));
+ lapic->type = ACPI_PROCESSOR_LOCAL_APIC;
+ lapic->length = sizeof(*lapic);
+ lapic->acpi_processor_id = lapic->apic_id = i + 1;
+ lapic->flags = ACPI_LOCAL_APIC_ENABLED;
+ offset += sizeof(*lapic);
+ lapic++;
+ }
+
+ madt->header.length = offset;
+ set_checksum(madt, offsetof(struct acpi_header, checksum), offset);
+
+ return offset;
+}
+
+/*
+ * Copy all the ACPI table to buffer.
+ * Buffer layout: FACS, DSDT, FADT, MADT, XSDT, RSDT, RSDP.
+ */
+int acpi_build_tables(uint8_t *buf)
+{
+ struct acpi_20_rsdp *rsdp;
+ struct acpi_20_rsdt *rsdt;
+ struct acpi_20_xsdt *xsdt;
+ struct acpi_20_fadt *fadt;
+ struct acpi_20_madt *madt = 0;
+ struct acpi_20_facs *facs;
+ unsigned char *dsdt;
+ int offset = 0, requires_madt;
+
+ requires_madt = ((get_vcpu_nr() > 1) || get_apic_mode());
+
+#define inc_offset(sz) (offset = (offset + (sz) + 15) & ~15)
+
+ facs = (struct acpi_20_facs *)&buf[offset];
+ memcpy(facs, &Facs, sizeof(struct acpi_20_facs));
+ inc_offset(sizeof(struct acpi_20_facs));
+
+ dsdt = (unsigned char *)&buf[offset];
+ memcpy(dsdt, &AmlCode, DsdtLen);
+ inc_offset(DsdtLen);
+
+ fadt = (struct acpi_20_fadt *)&buf[offset];
+ memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt));
+ inc_offset(sizeof(struct acpi_20_fadt));
+ fadt->dsdt = (unsigned long)dsdt;
+ fadt->x_dsdt = (unsigned long)dsdt;
+ fadt->firmware_ctrl = (unsigned long)facs;
+ fadt->x_firmware_ctrl = (unsigned long)facs;
+ set_checksum(fadt,
+ offsetof(struct acpi_header, checksum),
+ sizeof(struct acpi_20_fadt));
+
+ if ( requires_madt )
+ {
+ madt = (struct acpi_20_madt *)&buf[offset];
+ inc_offset(construct_madt(madt));
+ }
+
+ xsdt = (struct acpi_20_xsdt *)&buf[offset];
+ memcpy(xsdt, &Xsdt, sizeof(struct acpi_20_xsdt));
+ inc_offset(sizeof(struct acpi_20_xsdt));
+ xsdt->entry[0] = (unsigned long)fadt;
+ xsdt->header.length = sizeof(struct acpi_header) + sizeof(uint64_t);
+ if ( requires_madt )
+ {
+ xsdt->entry[1] = (unsigned long)madt;
+ xsdt->header.length += sizeof(uint64_t);
+ }
+ set_checksum(xsdt,
+ offsetof(struct acpi_header, checksum),
+ xsdt->header.length);
+
+ rsdt = (struct acpi_20_rsdt *)&buf[offset];
+ memcpy(rsdt, &Rsdt, sizeof(struct acpi_20_rsdt));
+ inc_offset(sizeof(struct acpi_20_rsdt));
+ rsdt->entry[0] = (unsigned long)fadt;
+ rsdt->header.length = sizeof(struct acpi_header) + sizeof(uint32_t);
+ if ( requires_madt )
+ {
+ rsdt->entry[1] = (unsigned long)madt;
+ rsdt->header.length += sizeof(uint32_t);
+ }
+ set_checksum(rsdt,
+ offsetof(struct acpi_header, checksum),
+ rsdt->header.length);
+
+ rsdp = (struct acpi_20_rsdp *)&buf[offset];
+ memcpy(rsdp, &Rsdp, sizeof(struct acpi_20_rsdp));
+ inc_offset(sizeof(struct acpi_20_rsdp));
+ rsdp->rsdt_address = (unsigned long)rsdt;
+ rsdp->xsdt_address = (unsigned long)xsdt;
+ set_checksum(rsdp,
+ offsetof(struct acpi_10_rsdp, checksum),
+ sizeof(struct acpi_10_rsdp));
+ set_checksum(rsdp,
+ offsetof(struct acpi_20_rsdp, extended_checksum),
+ sizeof(struct acpi_20_rsdp));
+
+#undef inc_offset
+
+ return offset;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
new file mode 100644
index 0000000000..f369c64045
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -0,0 +1,657 @@
+/******************************************************************************
+ * DSDT for Xen with Qemu device model
+ *
+ * Copyright (c) 2004, 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.
+ */
+
+DefinitionBlock ("DSDT.aml", "DSDT", 1, "INTEL","int-xen", 2006)
+{
+ Name (\PMBS, 0x0C00)
+ Name (\PMLN, 0x08)
+ Name (\IOB1, 0x00)
+ Name (\IOL1, 0x00)
+ Name (\APCB, 0xFEC00000)
+ Name (\APCL, 0x00010000)
+ Name (\PUID, 0x00)
+
+ Scope (\_PR)
+ {
+ Processor (CPU0, 0x00, 0x00000000, 0x00) {}
+ Processor (CPU1, 0x01, 0x00000000, 0x00) {}
+ Processor (CPU2, 0x02, 0x00000000, 0x00) {}
+ Processor (CPU3, 0x03, 0x00000000, 0x00) {}
+ }
+
+ /* Poweroff support - ties in with qemu emulation */
+ Name (\_S5, Package (0x04)
+ {
+ 0x07,
+ 0x07,
+ 0x00,
+ 0x00
+ })
+
+ Name(PICD, 0)
+ Method(_PIC, 1)
+ {
+ Store(Arg0, PICD)
+ }
+
+ Scope (\_SB)
+ {
+ /* Fix HCT test for 0x400 pci memory:
+ * - need to report low 640 MB mem as motherboard resource
+ */
+
+ Device(MEM0)
+ {
+ Name(_HID, EISAID("PNP0C02"))
+ Name(_CRS, ResourceTemplate() {
+ QWordMemory(
+ ResourceConsumer, PosDecode, MinFixed,
+ MaxFixed, Cacheable, ReadWrite,
+ 0x00000000,
+ 0x00000000,
+ 0x0009ffff,
+ 0x00000000,
+ 0x000a0000)
+ })
+ }
+
+ Device (PCI0)
+ {
+ Name (_HID, EisaId ("PNP0A03"))
+ Name (_UID, 0x00)
+ Name (_ADR, 0x00)
+ Name (_BBN, 0x00)
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRT0, ResourceTemplate ()
+ {
+ /* bus number is from 0 - 255*/
+ WordBusNumber(
+ ResourceConsumer, MinFixed, MaxFixed, SubDecode,
+ 0x0000,
+ 0x0000,
+ 0x00FF,
+ 0x0000,
+ 0x0100)
+ IO (Decode16, 0x0CF8, 0x0CF8, 0x01, 0x08)
+ WordIO(
+ ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ EntireRange,
+ 0x0000,
+ 0x0000,
+ 0x0CF7,
+ 0x0000,
+ 0x0CF8)
+ WordIO(
+ ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ EntireRange,
+ 0x0000,
+ 0x0D00,
+ 0xFFFF,
+ 0x0000,
+ 0xF300)
+
+ /* reserve memory for pci devices */
+ DWordMemory(
+ ResourceProducer, PosDecode, MinFixed, MaxFixed,
+ Cacheable, ReadWrite,
+ 0x00000000,
+ 0x000A0000,
+ 0x000BFFFF,
+ 0x00000000,
+ 0x00020000)
+
+ DWordMemory(
+ ResourceConsumer, PosDecode, MinFixed, MaxFixed,
+ Cacheable, ReadWrite,
+ 0x00000000,
+ 0xF0000000,
+ 0xF4FFFFFF,
+ 0x00000000,
+ 0x05000000)
+ })
+ Return (PRT0)
+ }
+
+ Name(BUFA, ResourceTemplate() {
+ IRQ(Level, ActiveLow, Shared) { 5, 6, 10, 11 }
+ })
+
+ Name(BUFB, Buffer() {
+ 0x23, 0x00, 0x00, 0x18, 0x79, 0
+ })
+
+ CreateWordField(BUFB, 0x01, IRQV)
+
+ Device(LNKA) {
+ Name(_HID, EISAID("PNP0C0F")) /* PCI interrupt link */
+ Name(_UID, 1)
+
+ Method(_STA, 0) {
+ And(PIRA, 0x80, Local0)
+ If(LEqual(Local0, 0x80)) {
+ Return(0x09)
+ } Else {
+ Return(0x0B)
+ }
+ }
+
+ Method(_PRS) {
+ Return(BUFA)
+ }
+
+ Method(_DIS) {
+ Or(PIRA, 0x80, PIRA)
+ }
+
+ Method(_CRS) {
+ And(PIRA, 0x0f, Local0)
+ ShiftLeft(0x1, Local0, IRQV)
+ Return(BUFB)
+ }
+
+ Method(_SRS, 1) {
+ CreateWordField(ARG0, 0x01, IRQ1)
+ FindSetRightBit(IRQ1, Local0)
+ Decrement(Local0)
+ Store(Local0, PIRA)
+ }
+ }
+
+ Device(LNKB) {
+ Name(_HID, EISAID("PNP0C0F")) /* PCI interrupt link */
+ Name(_UID, 2)
+
+ Method(_STA, 0) {
+ And(PIRB, 0x80, Local0)
+ If(LEqual(Local0, 0x80)) {
+ Return(0x09)
+ } Else {
+ Return(0x0B)
+ }
+ }
+
+ Method(_PRS) {
+ Return(BUFA)
+ }
+
+ Method(_DIS) {
+ Or(PIRB, 0x80, PIRB)
+ }
+
+ Method(_CRS) {
+ And(PIRB, 0x0f, Local0)
+ ShiftLeft(0x1, Local0, IRQV)
+ Return(BUFB)
+ }
+
+ Method(_SRS, 1) {
+ CreateWordField(ARG0, 0x01, IRQ1)
+ FindSetRightBit(IRQ1, Local0)
+ Decrement(Local0)
+ Store(Local0, PIRB)
+ }
+ }
+
+ Device(LNKC) {
+ Name(_HID, EISAID("PNP0C0F")) /* PCI interrupt link */
+ Name(_UID, 3)
+
+ Method(_STA, 0) {
+ And(PIRC, 0x80, Local0)
+ If(LEqual(Local0, 0x80)) {
+ Return(0x09)
+ } Else {
+ Return(0x0B)
+ }
+ }
+
+ Method(_PRS) {
+ Return(BUFA)
+ }
+
+ Method(_DIS) {
+ Or(PIRC, 0x80, PIRC)
+ }
+
+ Method(_CRS) {
+ And(PIRC, 0x0f, Local0)
+ ShiftLeft(0x1, Local0, IRQV)
+ Return(BUFB)
+ }
+
+ Method(_SRS, 1) {
+ CreateWordField(ARG0, 0x01, IRQ1)
+ FindSetRightBit(IRQ1, Local0)
+ Decrement(Local0)
+ Store(Local0, PIRC)
+ }
+ }
+
+ Device(LNKD) {
+ Name(_HID, EISAID("PNP0C0F")) /* PCI interrupt link */
+ Name(_UID, 4)
+
+ Method(_STA, 0) {
+ And(PIRD, 0x80, Local0)
+ If(LEqual(Local0, 0x80)) {
+ Return(0x09)
+ } Else {
+ Return(0x0B)
+ }
+ }
+
+ Method(_PRS) {
+ Return(BUFA)
+ }
+
+ Method(_DIS) {
+ Or(PIRD, 0x80, PIRD)
+ }
+
+ Method(_CRS) {
+ And(PIRD, 0x0f, Local0)
+ ShiftLeft(0x1, Local0, IRQV)
+ Return(BUFB)
+ }
+
+ Method(_SRS, 1) {
+ CreateWordField(ARG0, 0x01, IRQ1)
+ FindSetRightBit(IRQ1, Local0)
+ Decrement(Local0)
+ Store(Local0, PIRD)
+ }
+ }
+
+ Method(_PRT,0) {
+ If(PICD) {
+ Return(PRTA)
+ }
+ Return (PRTP)
+ }
+
+ Name(PRTP, Package() {
+ /* Device 1, INTA - INTD */
+ Package(){0x0001ffff, 0, \_SB.PCI0.LNKB, 0},
+ Package(){0x0001ffff, 1, \_SB.PCI0.LNKC, 0},
+ Package(){0x0001ffff, 2, \_SB.PCI0.LNKD, 0},
+ Package(){0x0001ffff, 3, \_SB.PCI0.LNKA, 0},
+
+ /* Device 2, INTA - INTD */
+ Package(){0x0002ffff, 0, \_SB.PCI0.LNKC, 0},
+ Package(){0x0002ffff, 1, \_SB.PCI0.LNKD, 0},
+ Package(){0x0002ffff, 2, \_SB.PCI0.LNKA, 0},
+ Package(){0x0002ffff, 3, \_SB.PCI0.LNKB, 0},
+
+ /* Device 3, INTA - INTD */
+ Package(){0x0003ffff, 0, \_SB.PCI0.LNKD, 0},
+ Package(){0x0003ffff, 1, \_SB.PCI0.LNKA, 0},
+ Package(){0x0003ffff, 2, \_SB.PCI0.LNKB, 0},
+ Package(){0x0003ffff, 3, \_SB.PCI0.LNKC, 0},
+
+ /* Device 4, INTA - INTD */
+ Package(){0x0004ffff, 0, \_SB.PCI0.LNKA, 0},
+ Package(){0x0004ffff, 1, \_SB.PCI0.LNKB, 0},
+ Package(){0x0004ffff, 2, \_SB.PCI0.LNKC, 0},
+ Package(){0x0004ffff, 3, \_SB.PCI0.LNKD, 0},
+
+ /* Device 5, INTA - INTD */
+ Package(){0x0005ffff, 0, \_SB.PCI0.LNKB, 0},
+ Package(){0x0005ffff, 1, \_SB.PCI0.LNKC, 0},
+ Package(){0x0005ffff, 2, \_SB.PCI0.LNKD, 0},
+ Package(){0x0005ffff, 3, \_SB.PCI0.LNKA, 0},
+
+ /* Device 6, INTA - INTD */
+ Package(){0x0006ffff, 0, \_SB.PCI0.LNKC, 0},
+ Package(){0x0006ffff, 1, \_SB.PCI0.LNKD, 0},
+ Package(){0x0006ffff, 2, \_SB.PCI0.LNKA, 0},
+ Package(){0x0006ffff, 3, \_SB.PCI0.LNKB, 0},
+
+ /* Device 7, INTA - INTD */
+ Package(){0x0007ffff, 0, \_SB.PCI0.LNKD, 0},
+ Package(){0x0007ffff, 1, \_SB.PCI0.LNKA, 0},
+ Package(){0x0007ffff, 2, \_SB.PCI0.LNKB, 0},
+ Package(){0x0007ffff, 3, \_SB.PCI0.LNKC, 0},
+
+ /* Device 8, INTA - INTD */
+ Package(){0x0008ffff, 0, \_SB.PCI0.LNKA, 0},
+ Package(){0x0008ffff, 1, \_SB.PCI0.LNKB, 0},
+ Package(){0x0008ffff, 2, \_SB.PCI0.LNKC, 0},
+ Package(){0x0008ffff, 3, \_SB.PCI0.LNKD, 0},
+
+ /* Device 9, INTA - INTD */
+ Package(){0x0009ffff, 0, \_SB.PCI0.LNKB, 0},
+ Package(){0x0009ffff, 1, \_SB.PCI0.LNKC, 0},
+ Package(){0x0009ffff, 2, \_SB.PCI0.LNKD, 0},
+ Package(){0x0009ffff, 3, \_SB.PCI0.LNKA, 0},
+
+ /* Device 10, INTA - INTD */
+ Package(){0x000affff, 0, \_SB.PCI0.LNKC, 0},
+ Package(){0x000affff, 1, \_SB.PCI0.LNKD, 0},
+ Package(){0x000affff, 2, \_SB.PCI0.LNKA, 0},
+ Package(){0x000affff, 3, \_SB.PCI0.LNKB, 0},
+
+ /* Device 11, INTA - INTD */
+ Package(){0x000bffff, 0, \_SB.PCI0.LNKD, 0},
+ Package(){0x000bffff, 1, \_SB.PCI0.LNKA, 0},
+ Package(){0x000bffff, 2, \_SB.PCI0.LNKB, 0},
+ Package(){0x000bffff, 3, \_SB.PCI0.LNKC, 0},
+
+ /* Device 12, INTA - INTD */
+ Package(){0x000cffff, 0, \_SB.PCI0.LNKA, 0},
+ Package(){0x000cffff, 1, \_SB.PCI0.LNKB, 0},
+ Package(){0x000cffff, 2, \_SB.PCI0.LNKC, 0},
+ Package(){0x000cffff, 3, \_SB.PCI0.LNKD, 0},
+
+ /* Device 13, INTA - INTD */
+ Package(){0x000dffff, 0, \_SB.PCI0.LNKB, 0},
+ Package(){0x000dffff, 1, \_SB.PCI0.LNKC, 0},
+ Package(){0x000dffff, 2, \_SB.PCI0.LNKD, 0},
+ Package(){0x000dffff, 3, \_SB.PCI0.LNKA, 0},
+
+ /* Device 14, INTA - INTD */
+ Package(){0x000effff, 0, \_SB.PCI0.LNKC, 0},
+ Package(){0x000effff, 1, \_SB.PCI0.LNKD, 0},
+ Package(){0x000effff, 2, \_SB.PCI0.LNKA, 0},
+ Package(){0x000effff, 3, \_SB.PCI0.LNKB, 0},
+
+ /* Device 15, INTA - INTD */
+ Package(){0x000fffff, 0, \_SB.PCI0.LNKD, 0},
+ Package(){0x000fffff, 1, \_SB.PCI0.LNKA, 0},
+ Package(){0x000fffff, 2, \_SB.PCI0.LNKB, 0},
+ Package(){0x000fffff, 3, \_SB.PCI0.LNKC, 0},
+ })
+
+ Name(PRTA, Package() {
+ /* Device 1, INTA - INTD */
+ Package(){0x0001ffff, 0, 0, 20},
+ Package(){0x0001ffff, 1, 0, 21},
+ Package(){0x0001ffff, 2, 0, 22},
+ Package(){0x0001ffff, 3, 0, 23},
+
+ /* Device 2, INTA - INTD */
+ Package(){0x0002ffff, 0, 0, 24},
+ Package(){0x0002ffff, 1, 0, 25},
+ Package(){0x0002ffff, 2, 0, 26},
+ Package(){0x0002ffff, 3, 0, 27},
+
+ /* Device 3, INTA - INTD */
+ Package(){0x0003ffff, 0, 0, 28},
+ Package(){0x0003ffff, 1, 0, 29},
+ Package(){0x0003ffff, 2, 0, 30},
+ Package(){0x0003ffff, 3, 0, 31},
+
+ /* Device 4, INTA - INTD */
+ Package(){0x0004ffff, 0, 0, 32},
+ Package(){0x0004ffff, 1, 0, 33},
+ Package(){0x0004ffff, 2, 0, 34},
+ Package(){0x0004ffff, 3, 0, 35},
+
+ /* Device 5, INTA - INTD */
+ Package(){0x0005ffff, 0, 0, 36},
+ Package(){0x0005ffff, 1, 0, 37},
+ Package(){0x0005ffff, 2, 0, 38},
+ Package(){0x0005ffff, 3, 0, 39},
+
+ /* Device 6, INTA - INTD */
+ Package(){0x0006ffff, 0, 0, 40},
+ Package(){0x0006ffff, 1, 0, 41},
+ Package(){0x0006ffff, 2, 0, 42},
+ Package(){0x0006ffff, 3, 0, 43},
+
+ /* Device 7, INTA - INTD */
+ Package(){0x0007ffff, 0, 0, 44},
+ Package(){0x0007ffff, 1, 0, 45},
+ Package(){0x0007ffff, 2, 0, 46},
+ Package(){0x0007ffff, 3, 0, 47},
+
+ /* Device 8, INTA - INTD */
+ Package(){0x0008ffff, 0, 0, 17},
+ Package(){0x0008ffff, 1, 0, 18},
+ Package(){0x0008ffff, 2, 0, 19},
+ Package(){0x0008ffff, 3, 0, 20},
+
+ /* Device 9, INTA - INTD */
+ Package(){0x0009ffff, 0, 0, 21},
+ Package(){0x0009ffff, 1, 0, 22},
+ Package(){0x0009ffff, 2, 0, 23},
+ Package(){0x0009ffff, 3, 0, 24},
+
+ /* Device 10, INTA - INTD */
+ Package(){0x000affff, 0, 0, 25},
+ Package(){0x000affff, 1, 0, 26},
+ Package(){0x000affff, 2, 0, 27},
+ Package(){0x000affff, 3, 0, 28},
+
+ /* Device 11, INTA - INTD */
+ Package(){0x000bffff, 0, 0, 29},
+ Package(){0x000bffff, 1, 0, 30},
+ Package(){0x000bffff, 2, 0, 31},
+ Package(){0x000bffff, 3, 0, 32},
+
+ /* Device 12, INTA - INTD */
+ Package(){0x000cffff, 0, 0, 33},
+ Package(){0x000cffff, 1, 0, 34},
+ Package(){0x000cffff, 2, 0, 35},
+ Package(){0x000cffff, 3, 0, 36},
+
+ /* Device 13, INTA - INTD */
+ Package(){0x000dffff, 0, 0, 37},
+ Package(){0x000dffff, 1, 0, 38},
+ Package(){0x000dffff, 2, 0, 39},
+ Package(){0x000dffff, 3, 0, 40},
+
+ /* Device 14, INTA - INTD */
+ Package(){0x000effff, 0, 0, 41},
+ Package(){0x000effff, 1, 0, 42},
+ Package(){0x000effff, 2, 0, 43},
+ Package(){0x000effff, 3, 0, 44},
+
+ /* Device 15, INTA - INTD */
+ Package(){0x000fffff, 0, 0, 45},
+ Package(){0x000fffff, 1, 0, 46},
+ Package(){0x000fffff, 2, 0, 47},
+ Package(){0x000fffff, 3, 0, 16},
+ })
+
+ Device (ISA)
+ {
+ Name (_ADR, 0x00010000) /* device 1, fn 0 */
+
+ OperationRegion(PIRQ, PCI_Config, 0x60, 0x4)
+ Scope(\) {
+ Field (\_SB.PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
+ PIRA, 8,
+ PIRB, 8,
+ PIRC, 8,
+ PIRD, 8
+ }
+ }
+ Device (SYSR)
+ {
+ Name (_HID, EisaId ("PNP0C02"))
+ Name (_UID, 0x01)
+ Name (CRS, ResourceTemplate ()
+ {
+ /* TODO: list hidden resources */
+ IO (Decode16, 0x0010, 0x0010, 0x00, 0x10)
+ IO (Decode16, 0x0022, 0x0022, 0x00, 0x0C)
+ IO (Decode16, 0x0030, 0x0030, 0x00, 0x10)
+ IO (Decode16, 0x0044, 0x0044, 0x00, 0x1C)
+ IO (Decode16, 0x0062, 0x0062, 0x00, 0x02)
+ IO (Decode16, 0x0065, 0x0065, 0x00, 0x0B)
+ IO (Decode16, 0x0072, 0x0072, 0x00, 0x0E)
+ IO (Decode16, 0x0080, 0x0080, 0x00, 0x01)
+ IO (Decode16, 0x0084, 0x0084, 0x00, 0x03)
+ IO (Decode16, 0x0088, 0x0088, 0x00, 0x01)
+ IO (Decode16, 0x008C, 0x008C, 0x00, 0x03)
+ IO (Decode16, 0x0090, 0x0090, 0x00, 0x10)
+ IO (Decode16, 0x00A2, 0x00A2, 0x00, 0x1C)
+ IO (Decode16, 0x00E0, 0x00E0, 0x00, 0x10)
+ IO (Decode16, 0x08A0, 0x08A0, 0x00, 0x04)
+ IO (Decode16, 0x0CC0, 0x0CC0, 0x00, 0x10)
+ IO (Decode16, 0x04D0, 0x04D0, 0x00, 0x02)
+ })
+ Method (_CRS, 0, NotSerialized)
+ {
+ Return (CRS)
+ }
+ }
+
+ Device (PIC)
+ {
+ Name (_HID, EisaId ("PNP0000"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0020, 0x0020, 0x01, 0x02)
+ IO (Decode16, 0x00A0, 0x00A0, 0x01, 0x02)
+ IRQNoFlags () {2}
+ })
+ }
+
+ Device (DMA0)
+ {
+ Name (_HID, EisaId ("PNP0200"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ DMA (Compatibility, BusMaster, Transfer8) {4}
+ IO (Decode16, 0x0000, 0x0000, 0x00, 0x10)
+ IO (Decode16, 0x0081, 0x0081, 0x00, 0x03)
+ IO (Decode16, 0x0087, 0x0087, 0x00, 0x01)
+ IO (Decode16, 0x0089, 0x0089, 0x00, 0x03)
+ IO (Decode16, 0x008F, 0x008F, 0x00, 0x01)
+ IO (Decode16, 0x00C0, 0x00C0, 0x00, 0x20)
+ IO (Decode16, 0x0480, 0x0480, 0x00, 0x10)
+ })
+ }
+
+ Device (TMR)
+ {
+ Name (_HID, EisaId ("PNP0100"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0040, 0x0040, 0x00, 0x04)
+ IRQNoFlags () {0}
+ })
+ }
+
+ Device (RTC)
+ {
+ Name (_HID, EisaId ("PNP0B00"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0070, 0x0070, 0x00, 0x02)
+ IRQNoFlags () {8}
+ })
+ }
+
+ Device (SPKR)
+ {
+ Name (_HID, EisaId ("PNP0800"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0061, 0x0061, 0x00, 0x01)
+ })
+ }
+
+ Device (PS2M)
+ {
+ Name (_HID, EisaId ("PNP0F13"))
+ Name (_CID, 0x130FD041)
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ IRQNoFlags () {12}
+ })
+ }
+
+ Device (PS2K)
+ {
+ Name (_HID, EisaId ("PNP0303"))
+ Name (_CID, 0x0B03D041)
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0060, 0x0060, 0x00, 0x01)
+ IO (Decode16, 0x0064, 0x0064, 0x00, 0x01)
+ IRQNoFlags () {1}
+ })
+ }
+
+ Device (FDC0)
+ {
+ Name (_HID, EisaId ("PNP0700"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x03F0, 0x03F0, 0x01, 0x06)
+ IO (Decode16, 0x03F7, 0x03F7, 0x01, 0x01)
+ IRQNoFlags () {6}
+ DMA (Compatibility, NotBusMaster, Transfer8) {2}
+ })
+ }
+
+ Device (UAR1)
+ {
+ Name (_HID, EisaId ("PNP0501"))
+ Name (_UID, 0x01)
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ Name (_CRS, ResourceTemplate()
+ {
+ IO (Decode16, 0x03F8, 0x03F8, 0x01, 0x08)
+ IRQNoFlags () {4}
+ })
+ }
+
+ Device (LTP1)
+ {
+ Name (_HID, EisaId ("PNP0400"))
+ Name (_UID, 0x02)
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ Name (_CRS, ResourceTemplate()
+ {
+ IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+ IRQNoFlags () {7}
+ })
+ }
+ }
+ }
+ }
+}
diff --git a/tools/firmware/hvmloader/acpi/dsdt.c b/tools/firmware/hvmloader/acpi/dsdt.c
new file mode 100644
index 0000000000..6eb777cd05
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/dsdt.c
@@ -0,0 +1,452 @@
+/*
+ *
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler / AML Disassembler version 20050513 [Nov 16 2006]
+ * Copyright (C) 2000 - 2005 Intel Corporation
+ * Supports ACPI Specification Revision 3.0
+ *
+ * Compilation of "dsdt.asl" - Wed Nov 22 18:26:19 2006
+ *
+ * C source code output
+ *
+ */
+unsigned char AmlCode[] =
+{
+ 0x44,0x53,0x44,0x54,0x9D,0x0D,0x00,0x00, /* 00000000 "DSDT...." */
+ 0x01,0x83,0x49,0x4E,0x54,0x45,0x4C,0x00, /* 00000008 "..INTEL." */
+ 0x69,0x6E,0x74,0x2D,0x78,0x65,0x6E,0x00, /* 00000010 "int-xen." */
+ 0xD6,0x07,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
+ 0x13,0x05,0x05,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */
+ 0x53,0x0B,0x00,0x0C,0x08,0x50,0x4D,0x4C, /* 00000028 "S....PML" */
+ 0x4E,0x0A,0x08,0x08,0x49,0x4F,0x42,0x31, /* 00000030 "N...IOB1" */
+ 0x00,0x08,0x49,0x4F,0x4C,0x31,0x00,0x08, /* 00000038 "..IOL1.." */
+ 0x41,0x50,0x43,0x42,0x0C,0x00,0x00,0xC0, /* 00000040 "APCB...." */
+ 0xFE,0x08,0x41,0x50,0x43,0x4C,0x0C,0x00, /* 00000048 "..APCL.." */
+ 0x00,0x01,0x00,0x08,0x50,0x55,0x49,0x44, /* 00000050 "....PUID" */
+ 0x00,0x10,0x39,0x5F,0x50,0x52,0x5F,0x5B, /* 00000058 "..9_PR_[" */
+ 0x83,0x0B,0x43,0x50,0x55,0x30,0x00,0x00, /* 00000060 "..CPU0.." */
+ 0x00,0x00,0x00,0x00,0x5B,0x83,0x0B,0x43, /* 00000068 "....[..C" */
+ 0x50,0x55,0x31,0x01,0x00,0x00,0x00,0x00, /* 00000070 "PU1....." */
+ 0x00,0x5B,0x83,0x0B,0x43,0x50,0x55,0x32, /* 00000078 ".[..CPU2" */
+ 0x02,0x00,0x00,0x00,0x00,0x00,0x5B,0x83, /* 00000080 "......[." */
+ 0x0B,0x43,0x50,0x55,0x33,0x03,0x00,0x00, /* 00000088 ".CPU3..." */
+ 0x00,0x00,0x00,0x08,0x5F,0x53,0x35,0x5F, /* 00000090 "...._S5_" */
+ 0x12,0x08,0x04,0x0A,0x07,0x0A,0x07,0x00, /* 00000098 "........" */
+ 0x00,0x08,0x50,0x49,0x43,0x44,0x00,0x14, /* 000000A0 "..PICD.." */
+ 0x0C,0x5F,0x50,0x49,0x43,0x01,0x70,0x68, /* 000000A8 "._PIC.ph" */
+ 0x50,0x49,0x43,0x44,0x10,0x48,0xCE,0x5F, /* 000000B0 "PICD.H._" */
+ 0x53,0x42,0x5F,0x5B,0x82,0x49,0x04,0x4D, /* 000000B8 "SB_[.I.M" */
+ 0x45,0x4D,0x30,0x08,0x5F,0x48,0x49,0x44, /* 000000C0 "EM0._HID" */
+ 0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x43, /* 000000C8 ".A...._C" */
+ 0x52,0x53,0x11,0x33,0x0A,0x30,0x8A,0x2B, /* 000000D0 "RS.3.0.+" */
+ 0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 000000D8 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */
+ 0x00,0x00,0x00,0x00,0xFF,0xFF,0x09,0x00, /* 000000E8 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F0 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00, /* 000000F8 "........" */
+ 0x00,0x00,0x00,0x00,0x79,0x00,0x5B,0x82, /* 00000100 "....y.[." */
+ 0x45,0xC9,0x50,0x43,0x49,0x30,0x08,0x5F, /* 00000108 "E.PCI0._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03, /* 00000110 "HID.A..." */
+ 0x08,0x5F,0x55,0x49,0x44,0x00,0x08,0x5F, /* 00000118 "._UID.._" */
+ 0x41,0x44,0x52,0x00,0x08,0x5F,0x42,0x42, /* 00000120 "ADR.._BB" */
+ 0x4E,0x00,0x14,0x44,0x08,0x5F,0x43,0x52, /* 00000128 "N..D._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x54,0x30,0x11, /* 00000130 "S..PRT0." */
+ 0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00,0x02, /* 00000138 "B..n...." */
+ 0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x00, /* 00000140 "........" */
+ 0x00,0x00,0x00,0x01,0x47,0x01,0xF8,0x0C, /* 00000148 "....G..." */
+ 0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00,0x01, /* 00000150 "........" */
+ 0x0C,0x03,0x00,0x00,0x00,0x00,0xF7,0x0C, /* 00000158 "........" */
+ 0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00,0x01, /* 00000160 "........" */
+ 0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF,0xFF, /* 00000168 "........" */
+ 0x00,0x00,0x00,0xF3,0x87,0x17,0x00,0x00, /* 00000170 "........" */
+ 0x0C,0x03,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000178 "........" */
+ 0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00,0x00, /* 00000180 "........" */
+ 0x00,0x00,0x00,0x00,0x02,0x00,0x87,0x17, /* 00000188 "........" */
+ 0x00,0x00,0x0D,0x03,0x00,0x00,0x00,0x00, /* 00000190 "........" */
+ 0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xF4, /* 00000198 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, /* 000001A0 "........" */
+ 0x79,0x00,0xA4,0x50,0x52,0x54,0x30,0x08, /* 000001A8 "y..PRT0." */
+ 0x42,0x55,0x46,0x41,0x11,0x09,0x0A,0x06, /* 000001B0 "BUFA...." */
+ 0x23,0x60,0x0C,0x18,0x79,0x00,0x08,0x42, /* 000001B8 "#`..y..B" */
+ 0x55,0x46,0x42,0x11,0x09,0x0A,0x06,0x23, /* 000001C0 "UFB....#" */
+ 0x00,0x00,0x18,0x79,0x00,0x8B,0x42,0x55, /* 000001C8 "...y..BU" */
+ 0x46,0x42,0x01,0x49,0x52,0x51,0x56,0x5B, /* 000001D0 "FB.IRQV[" */
+ 0x82,0x48,0x08,0x4C,0x4E,0x4B,0x41,0x08, /* 000001D8 ".H.LNKA." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C, /* 000001E0 "_HID.A.." */
+ 0x0F,0x08,0x5F,0x55,0x49,0x44,0x01,0x14, /* 000001E8 ".._UID.." */
+ 0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B,0x50, /* 000001F0 "._STA.{P" */
+ 0x49,0x52,0x41,0x0A,0x80,0x60,0xA0,0x08, /* 000001F8 "IRA..`.." */
+ 0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1, /* 00000200 ".`......" */
+ 0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50, /* 00000208 "......_P" */
+ 0x52,0x53,0x00,0xA4,0x42,0x55,0x46,0x41, /* 00000210 "RS..BUFA" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000218 ".._DIS.}" */
+ 0x50,0x49,0x52,0x41,0x0A,0x80,0x50,0x49, /* 00000220 "PIRA..PI" */
+ 0x52,0x41,0x14,0x1A,0x5F,0x43,0x52,0x53, /* 00000228 "RA.._CRS" */
+ 0x00,0x7B,0x50,0x49,0x52,0x41,0x0A,0x0F, /* 00000230 ".{PIRA.." */
+ 0x60,0x79,0x01,0x60,0x49,0x52,0x51,0x56, /* 00000238 "`y.`IRQV" */
+ 0xA4,0x42,0x55,0x46,0x42,0x14,0x1B,0x5F, /* 00000240 ".BUFB.._" */
+ 0x53,0x52,0x53,0x01,0x8B,0x68,0x01,0x49, /* 00000248 "SRS..h.I" */
+ 0x52,0x51,0x31,0x82,0x49,0x52,0x51,0x31, /* 00000250 "RQ1.IRQ1" */
+ 0x60,0x76,0x60,0x70,0x60,0x50,0x49,0x52, /* 00000258 "`v`p`PIR" */
+ 0x41,0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B, /* 00000260 "A[.I.LNK" */
+ 0x42,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000268 "B._HID.A" */
+ 0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 00000270 "...._UID" */
+ 0x0A,0x02,0x14,0x1C,0x5F,0x53,0x54,0x41, /* 00000278 "...._STA" */
+ 0x00,0x7B,0x50,0x49,0x52,0x42,0x0A,0x80, /* 00000280 ".{PIRB.." */
+ 0x60,0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4, /* 00000288 "`...`..." */
+ 0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14, /* 00000290 "........" */
+ 0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4,0x42, /* 00000298 "._PRS..B" */
+ 0x55,0x46,0x41,0x14,0x11,0x5F,0x44,0x49, /* 000002A0 "UFA.._DI" */
+ 0x53,0x00,0x7D,0x50,0x49,0x52,0x42,0x0A, /* 000002A8 "S.}PIRB." */
+ 0x80,0x50,0x49,0x52,0x42,0x14,0x1A,0x5F, /* 000002B0 ".PIRB.._" */
+ 0x43,0x52,0x53,0x00,0x7B,0x50,0x49,0x52, /* 000002B8 "CRS.{PIR" */
+ 0x42,0x0A,0x0F,0x60,0x79,0x01,0x60,0x49, /* 000002C0 "B..`y.`I" */
+ 0x52,0x51,0x56,0xA4,0x42,0x55,0x46,0x42, /* 000002C8 "RQV.BUFB" */
+ 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000002D0 ".._SRS.." */
+ 0x68,0x01,0x49,0x52,0x51,0x31,0x82,0x49, /* 000002D8 "h.IRQ1.I" */
+ 0x52,0x51,0x31,0x60,0x76,0x60,0x70,0x60, /* 000002E0 "RQ1`v`p`" */
+ 0x50,0x49,0x52,0x42,0x5B,0x82,0x49,0x08, /* 000002E8 "PIRB[.I." */
+ 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000002F0 "LNKC._HI" */
+ 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000002F8 "D.A...._" */
+ 0x55,0x49,0x44,0x0A,0x03,0x14,0x1C,0x5F, /* 00000300 "UID...._" */
+ 0x53,0x54,0x41,0x00,0x7B,0x50,0x49,0x52, /* 00000308 "STA.{PIR" */
+ 0x43,0x0A,0x80,0x60,0xA0,0x08,0x93,0x60, /* 00000310 "C..`...`" */
+ 0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4, /* 00000318 "........" */
+ 0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53, /* 00000320 "...._PRS" */
+ 0x00,0xA4,0x42,0x55,0x46,0x41,0x14,0x11, /* 00000328 "..BUFA.." */
+ 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x49, /* 00000330 "_DIS.}PI" */
+ 0x52,0x43,0x0A,0x80,0x50,0x49,0x52,0x43, /* 00000338 "RC..PIRC" */
+ 0x14,0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B, /* 00000340 ".._CRS.{" */
+ 0x50,0x49,0x52,0x43,0x0A,0x0F,0x60,0x79, /* 00000348 "PIRC..`y" */
+ 0x01,0x60,0x49,0x52,0x51,0x56,0xA4,0x42, /* 00000350 ".`IRQV.B" */
+ 0x55,0x46,0x42,0x14,0x1B,0x5F,0x53,0x52, /* 00000358 "UFB.._SR" */
+ 0x53,0x01,0x8B,0x68,0x01,0x49,0x52,0x51, /* 00000360 "S..h.IRQ" */
+ 0x31,0x82,0x49,0x52,0x51,0x31,0x60,0x76, /* 00000368 "1.IRQ1`v" */
+ 0x60,0x70,0x60,0x50,0x49,0x52,0x43,0x5B, /* 00000370 "`p`PIRC[" */
+ 0x82,0x49,0x08,0x4C,0x4E,0x4B,0x44,0x08, /* 00000378 ".I.LNKD." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C, /* 00000380 "_HID.A.." */
+ 0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A,0x04, /* 00000388 ".._UID.." */
+ 0x14,0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B, /* 00000390 ".._STA.{" */
+ 0x50,0x49,0x52,0x44,0x0A,0x80,0x60,0xA0, /* 00000398 "PIRD..`." */
+ 0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09, /* 000003A0 "..`....." */
+ 0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F, /* 000003A8 "......._" */
+ 0x50,0x52,0x53,0x00,0xA4,0x42,0x55,0x46, /* 000003B0 "PRS..BUF" */
+ 0x41,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 000003B8 "A.._DIS." */
+ 0x7D,0x50,0x49,0x52,0x44,0x0A,0x80,0x50, /* 000003C0 "}PIRD..P" */
+ 0x49,0x52,0x44,0x14,0x1A,0x5F,0x43,0x52, /* 000003C8 "IRD.._CR" */
+ 0x53,0x00,0x7B,0x50,0x49,0x52,0x44,0x0A, /* 000003D0 "S.{PIRD." */
+ 0x0F,0x60,0x79,0x01,0x60,0x49,0x52,0x51, /* 000003D8 ".`y.`IRQ" */
+ 0x56,0xA4,0x42,0x55,0x46,0x42,0x14,0x1B, /* 000003E0 "V.BUFB.." */
+ 0x5F,0x53,0x52,0x53,0x01,0x8B,0x68,0x01, /* 000003E8 "_SRS..h." */
+ 0x49,0x52,0x51,0x31,0x82,0x49,0x52,0x51, /* 000003F0 "IRQ1.IRQ" */
+ 0x31,0x60,0x76,0x60,0x70,0x60,0x50,0x49, /* 000003F8 "1`v`p`PI" */
+ 0x52,0x44,0x14,0x16,0x5F,0x50,0x52,0x54, /* 00000400 "RD.._PRT" */
+ 0x00,0xA0,0x0A,0x50,0x49,0x43,0x44,0xA4, /* 00000408 "...PICD." */
+ 0x50,0x52,0x54,0x41,0xA4,0x50,0x52,0x54, /* 00000410 "PRTA.PRT" */
+ 0x50,0x08,0x50,0x52,0x54,0x50,0x12,0x49, /* 00000418 "P.PRTP.I" */
+ 0x36,0x3C,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000420 "6<......" */
+ 0x01,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 00000428 "...LNKB." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 00000430 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000438 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x02, /* 00000440 "........" */
+ 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000448 "LNKD...." */
+ 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03,0x4C, /* 00000450 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000458 "NKA....." */
+ 0xFF,0xFF,0x02,0x00,0x00,0x4C,0x4E,0x4B, /* 00000460 ".....LNK" */
+ 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000468 "C......." */
+ 0x02,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 00000470 "...LNKD." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000478 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000480 "..LNKA.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 00000488 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000490 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x00,0x4C, /* 00000498 ".......L" */
+ 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000004A0 "NKD....." */
+ 0xFF,0xFF,0x03,0x00,0x01,0x4C,0x4E,0x4B, /* 000004A8 ".....LNK" */
+ 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000004B0 "A......." */
+ 0x03,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 000004B8 "....LNKB" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03, /* 000004C0 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 000004C8 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 000004D0 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 000004D8 ".LNKA..." */
+ 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x01,0x4C, /* 000004E0 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 000004E8 "NKB....." */
+ 0xFF,0xFF,0x04,0x00,0x0A,0x02,0x4C,0x4E, /* 000004F0 "......LN" */
+ 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000004F8 "KC......" */
+ 0xFF,0x04,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000500 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000508 "D......." */
+ 0x05,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 00000510 "...LNKB." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 00000518 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000520 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x02, /* 00000528 "........" */
+ 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000530 "LNKD...." */
+ 0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x03,0x4C, /* 00000538 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000540 "NKA....." */
+ 0xFF,0xFF,0x06,0x00,0x00,0x4C,0x4E,0x4B, /* 00000548 ".....LNK" */
+ 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000550 "C......." */
+ 0x06,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 00000558 "...LNKD." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 00000560 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000568 "..LNKA.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x0A, /* 00000570 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000578 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x07,0x00,0x00,0x4C, /* 00000580 ".......L" */
+ 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000588 "NKD....." */
+ 0xFF,0xFF,0x07,0x00,0x01,0x4C,0x4E,0x4B, /* 00000590 ".....LNK" */
+ 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000598 "A......." */
+ 0x07,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 000005A0 "....LNKB" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x07, /* 000005A8 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 000005B0 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x08,0x00, /* 000005B8 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 000005C0 ".LNKA..." */
+ 0x04,0x0C,0xFF,0xFF,0x08,0x00,0x01,0x4C, /* 000005C8 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 000005D0 "NKB....." */
+ 0xFF,0xFF,0x08,0x00,0x0A,0x02,0x4C,0x4E, /* 000005D8 "......LN" */
+ 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000005E0 "KC......" */
+ 0xFF,0x08,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000005E8 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000005F0 "D......." */
+ 0x09,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 000005F8 "...LNKB." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x09,0x00, /* 00000600 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000608 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x02, /* 00000610 "........" */
+ 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000618 "LNKD...." */
+ 0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x03,0x4C, /* 00000620 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000628 "NKA....." */
+ 0xFF,0xFF,0x0A,0x00,0x00,0x4C,0x4E,0x4B, /* 00000630 ".....LNK" */
+ 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000638 "C......." */
+ 0x0A,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 00000640 "...LNKD." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 00000648 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000650 "..LNKA.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x0A, /* 00000658 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000660 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x00,0x4C, /* 00000668 ".......L" */
+ 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000670 "NKD....." */
+ 0xFF,0xFF,0x0B,0x00,0x01,0x4C,0x4E,0x4B, /* 00000678 ".....LNK" */
+ 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000680 "A......." */
+ 0x0B,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000688 "....LNKB" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000690 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000698 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0C,0x00, /* 000006A0 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 000006A8 ".LNKA..." */
+ 0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x01,0x4C, /* 000006B0 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 000006B8 "NKB....." */
+ 0xFF,0xFF,0x0C,0x00,0x0A,0x02,0x4C,0x4E, /* 000006C0 "......LN" */
+ 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000006C8 "KC......" */
+ 0xFF,0x0C,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000006D0 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006D8 "D......." */
+ 0x0D,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 000006E0 "...LNKB." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0D,0x00, /* 000006E8 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 000006F0 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x02, /* 000006F8 "........" */
+ 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000700 "LNKD...." */
+ 0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x03,0x4C, /* 00000708 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000710 "NKA....." */
+ 0xFF,0xFF,0x0E,0x00,0x00,0x4C,0x4E,0x4B, /* 00000718 ".....LNK" */
+ 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000720 "C......." */
+ 0x0E,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 00000728 "...LNKD." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 00000730 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 00000738 "..LNKA.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x0A, /* 00000740 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000748 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x00,0x4C, /* 00000750 ".......L" */
+ 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000758 "NKD....." */
+ 0xFF,0xFF,0x0F,0x00,0x01,0x4C,0x4E,0x4B, /* 00000760 ".....LNK" */
+ 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000768 "A......." */
+ 0x0F,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000770 "....LNKB" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0F, /* 00000778 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000780 "...LNKC." */
+ 0x08,0x50,0x52,0x54,0x41,0x12,0x41,0x2F, /* 00000788 ".PRTA.A/" */
+ 0x3C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01, /* 00000790 "<......." */
+ 0x00,0x00,0x00,0x0A,0x14,0x12,0x0B,0x04, /* 00000798 "........" */
+ 0x0C,0xFF,0xFF,0x01,0x00,0x01,0x00,0x0A, /* 000007A0 "........" */
+ 0x15,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x01, /* 000007A8 "........" */
+ 0x00,0x0A,0x02,0x00,0x0A,0x16,0x12,0x0C, /* 000007B0 "........" */
+ 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03, /* 000007B8 "........" */
+ 0x00,0x0A,0x17,0x12,0x0B,0x04,0x0C,0xFF, /* 000007C0 "........" */
+ 0xFF,0x02,0x00,0x00,0x00,0x0A,0x18,0x12, /* 000007C8 "........" */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01, /* 000007D0 "........" */
+ 0x00,0x0A,0x19,0x12,0x0C,0x04,0x0C,0xFF, /* 000007D8 "........" */
+ 0xFF,0x02,0x00,0x0A,0x02,0x00,0x0A,0x1A, /* 000007E0 "........" */
+ 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 000007E8 "........" */
+ 0x0A,0x03,0x00,0x0A,0x1B,0x12,0x0B,0x04, /* 000007F0 "........" */
+ 0x0C,0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A, /* 000007F8 "........" */
+ 0x1C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03, /* 00000800 "........" */
+ 0x00,0x01,0x00,0x0A,0x1D,0x12,0x0C,0x04, /* 00000808 "........" */
+ 0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02,0x00, /* 00000810 "........" */
+ 0x0A,0x1E,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000818 "........" */
+ 0x03,0x00,0x0A,0x03,0x00,0x0A,0x1F,0x12, /* 00000820 "........" */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x00, /* 00000828 "........" */
+ 0x00,0x0A,0x20,0x12,0x0B,0x04,0x0C,0xFF, /* 00000830 ".. ....." */
+ 0xFF,0x04,0x00,0x01,0x00,0x0A,0x21,0x12, /* 00000838 "......!." */
+ 0x0C,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A, /* 00000840 "........" */
+ 0x02,0x00,0x0A,0x22,0x12,0x0C,0x04,0x0C, /* 00000848 "..."...." */
+ 0xFF,0xFF,0x04,0x00,0x0A,0x03,0x00,0x0A, /* 00000850 "........" */
+ 0x23,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x05, /* 00000858 "#......." */
+ 0x00,0x00,0x00,0x0A,0x24,0x12,0x0B,0x04, /* 00000860 "....$..." */
+ 0x0C,0xFF,0xFF,0x05,0x00,0x01,0x00,0x0A, /* 00000868 "........" */
+ 0x25,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x05, /* 00000870 "%......." */
+ 0x00,0x0A,0x02,0x00,0x0A,0x26,0x12,0x0C, /* 00000878 ".....&.." */
+ 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x03, /* 00000880 "........" */
+ 0x00,0x0A,0x27,0x12,0x0B,0x04,0x0C,0xFF, /* 00000888 "..'....." */
+ 0xFF,0x06,0x00,0x00,0x00,0x0A,0x28,0x12, /* 00000890 "......(." */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01, /* 00000898 "........" */
+ 0x00,0x0A,0x29,0x12,0x0C,0x04,0x0C,0xFF, /* 000008A0 "..)....." */
+ 0xFF,0x06,0x00,0x0A,0x02,0x00,0x0A,0x2A, /* 000008A8 ".......*" */
+ 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 000008B0 "........" */
+ 0x0A,0x03,0x00,0x0A,0x2B,0x12,0x0B,0x04, /* 000008B8 "....+..." */
+ 0x0C,0xFF,0xFF,0x07,0x00,0x00,0x00,0x0A, /* 000008C0 "........" */
+ 0x2C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x07, /* 000008C8 ",......." */
+ 0x00,0x01,0x00,0x0A,0x2D,0x12,0x0C,0x04, /* 000008D0 "....-..." */
+ 0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02,0x00, /* 000008D8 "........" */
+ 0x0A,0x2E,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 000008E0 "........" */
+ 0x07,0x00,0x0A,0x03,0x00,0x0A,0x2F,0x12, /* 000008E8 "....../." */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x00, /* 000008F0 "........" */
+ 0x00,0x0A,0x11,0x12,0x0B,0x04,0x0C,0xFF, /* 000008F8 "........" */
+ 0xFF,0x08,0x00,0x01,0x00,0x0A,0x12,0x12, /* 00000900 "........" */
+ 0x0C,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A, /* 00000908 "........" */
+ 0x02,0x00,0x0A,0x13,0x12,0x0C,0x04,0x0C, /* 00000910 "........" */
+ 0xFF,0xFF,0x08,0x00,0x0A,0x03,0x00,0x0A, /* 00000918 "........" */
+ 0x14,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x09, /* 00000920 "........" */
+ 0x00,0x00,0x00,0x0A,0x15,0x12,0x0B,0x04, /* 00000928 "........" */
+ 0x0C,0xFF,0xFF,0x09,0x00,0x01,0x00,0x0A, /* 00000930 "........" */
+ 0x16,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x09, /* 00000938 "........" */
+ 0x00,0x0A,0x02,0x00,0x0A,0x17,0x12,0x0C, /* 00000940 "........" */
+ 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x03, /* 00000948 "........" */
+ 0x00,0x0A,0x18,0x12,0x0B,0x04,0x0C,0xFF, /* 00000950 "........" */
+ 0xFF,0x0A,0x00,0x00,0x00,0x0A,0x19,0x12, /* 00000958 "........" */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01, /* 00000960 "........" */
+ 0x00,0x0A,0x1A,0x12,0x0C,0x04,0x0C,0xFF, /* 00000968 "........" */
+ 0xFF,0x0A,0x00,0x0A,0x02,0x00,0x0A,0x1B, /* 00000970 "........" */
+ 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 00000978 "........" */
+ 0x0A,0x03,0x00,0x0A,0x1C,0x12,0x0B,0x04, /* 00000980 "........" */
+ 0x0C,0xFF,0xFF,0x0B,0x00,0x00,0x00,0x0A, /* 00000988 "........" */
+ 0x1D,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000990 "........" */
+ 0x00,0x01,0x00,0x0A,0x1E,0x12,0x0C,0x04, /* 00000998 "........" */
+ 0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02,0x00, /* 000009A0 "........" */
+ 0x0A,0x1F,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 000009A8 "........" */
+ 0x0B,0x00,0x0A,0x03,0x00,0x0A,0x20,0x12, /* 000009B0 "...... ." */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x00, /* 000009B8 "........" */
+ 0x00,0x0A,0x21,0x12,0x0B,0x04,0x0C,0xFF, /* 000009C0 "..!....." */
+ 0xFF,0x0C,0x00,0x01,0x00,0x0A,0x22,0x12, /* 000009C8 "......"." */
+ 0x0C,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A, /* 000009D0 "........" */
+ 0x02,0x00,0x0A,0x23,0x12,0x0C,0x04,0x0C, /* 000009D8 "...#...." */
+ 0xFF,0xFF,0x0C,0x00,0x0A,0x03,0x00,0x0A, /* 000009E0 "........" */
+ 0x24,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0D, /* 000009E8 "$......." */
+ 0x00,0x00,0x00,0x0A,0x25,0x12,0x0B,0x04, /* 000009F0 "....%..." */
+ 0x0C,0xFF,0xFF,0x0D,0x00,0x01,0x00,0x0A, /* 000009F8 "........" */
+ 0x26,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0D, /* 00000A00 "&......." */
+ 0x00,0x0A,0x02,0x00,0x0A,0x27,0x12,0x0C, /* 00000A08 ".....'.." */
+ 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x03, /* 00000A10 "........" */
+ 0x00,0x0A,0x28,0x12,0x0B,0x04,0x0C,0xFF, /* 00000A18 "..(....." */
+ 0xFF,0x0E,0x00,0x00,0x00,0x0A,0x29,0x12, /* 00000A20 "......)." */
+ 0x0B,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01, /* 00000A28 "........" */
+ 0x00,0x0A,0x2A,0x12,0x0C,0x04,0x0C,0xFF, /* 00000A30 "..*....." */
+ 0xFF,0x0E,0x00,0x0A,0x02,0x00,0x0A,0x2B, /* 00000A38 ".......+" */
+ 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 00000A40 "........" */
+ 0x0A,0x03,0x00,0x0A,0x2C,0x12,0x0B,0x04, /* 00000A48 "....,..." */
+ 0x0C,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x0A, /* 00000A50 "........" */
+ 0x2D,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0F, /* 00000A58 "-......." */
+ 0x00,0x01,0x00,0x0A,0x2E,0x12,0x0C,0x04, /* 00000A60 "........" */
+ 0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02,0x00, /* 00000A68 "........" */
+ 0x0A,0x2F,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000A70 "./......" */
+ 0x0F,0x00,0x0A,0x03,0x00,0x0A,0x10,0x5B, /* 00000A78 ".......[" */
+ 0x82,0x4C,0x31,0x49,0x53,0x41,0x5F,0x08, /* 00000A80 ".L1ISA_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 00000A88 "_ADR...." */
+ 0x00,0x5B,0x80,0x50,0x49,0x52,0x51,0x02, /* 00000A90 ".[.PIRQ." */
+ 0x0A,0x60,0x0A,0x04,0x10,0x2E,0x5C,0x00, /* 00000A98 ".`....\." */
+ 0x5B,0x81,0x29,0x5C,0x2F,0x04,0x5F,0x53, /* 00000AA0 "[.)\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000AA8 "B_PCI0IS" */
+ 0x41,0x5F,0x50,0x49,0x52,0x51,0x01,0x50, /* 00000AB0 "A_PIRQ.P" */
+ 0x49,0x52,0x41,0x08,0x50,0x49,0x52,0x42, /* 00000AB8 "IRA.PIRB" */
+ 0x08,0x50,0x49,0x52,0x43,0x08,0x50,0x49, /* 00000AC0 ".PIRC.PI" */
+ 0x52,0x44,0x08,0x5B,0x82,0x46,0x0B,0x53, /* 00000AC8 "RD.[.F.S" */
+ 0x59,0x53,0x52,0x08,0x5F,0x48,0x49,0x44, /* 00000AD0 "YSR._HID" */
+ 0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x55, /* 00000AD8 ".A...._U" */
+ 0x49,0x44,0x01,0x08,0x43,0x52,0x53,0x5F, /* 00000AE0 "ID..CRS_" */
+ 0x11,0x4E,0x08,0x0A,0x8A,0x47,0x01,0x10, /* 00000AE8 ".N...G.." */
+ 0x00,0x10,0x00,0x00,0x10,0x47,0x01,0x22, /* 00000AF0 ".....G."" */
+ 0x00,0x22,0x00,0x00,0x0C,0x47,0x01,0x30, /* 00000AF8 "."...G.0" */
+ 0x00,0x30,0x00,0x00,0x10,0x47,0x01,0x44, /* 00000B00 ".0...G.D" */
+ 0x00,0x44,0x00,0x00,0x1C,0x47,0x01,0x62, /* 00000B08 ".D...G.b" */
+ 0x00,0x62,0x00,0x00,0x02,0x47,0x01,0x65, /* 00000B10 ".b...G.e" */
+ 0x00,0x65,0x00,0x00,0x0B,0x47,0x01,0x72, /* 00000B18 ".e...G.r" */
+ 0x00,0x72,0x00,0x00,0x0E,0x47,0x01,0x80, /* 00000B20 ".r...G.." */
+ 0x00,0x80,0x00,0x00,0x01,0x47,0x01,0x84, /* 00000B28 ".....G.." */
+ 0x00,0x84,0x00,0x00,0x03,0x47,0x01,0x88, /* 00000B30 ".....G.." */
+ 0x00,0x88,0x00,0x00,0x01,0x47,0x01,0x8C, /* 00000B38 ".....G.." */
+ 0x00,0x8C,0x00,0x00,0x03,0x47,0x01,0x90, /* 00000B40 ".....G.." */
+ 0x00,0x90,0x00,0x00,0x10,0x47,0x01,0xA2, /* 00000B48 ".....G.." */
+ 0x00,0xA2,0x00,0x00,0x1C,0x47,0x01,0xE0, /* 00000B50 ".....G.." */
+ 0x00,0xE0,0x00,0x00,0x10,0x47,0x01,0xA0, /* 00000B58 ".....G.." */
+ 0x08,0xA0,0x08,0x00,0x04,0x47,0x01,0xC0, /* 00000B60 ".....G.." */
+ 0x0C,0xC0,0x0C,0x00,0x10,0x47,0x01,0xD0, /* 00000B68 ".....G.." */
+ 0x04,0xD0,0x04,0x00,0x02,0x79,0x00,0x14, /* 00000B70 ".....y.." */
+ 0x0B,0x5F,0x43,0x52,0x53,0x00,0xA4,0x43, /* 00000B78 "._CRS..C" */
+ 0x52,0x53,0x5F,0x5B,0x82,0x2B,0x50,0x49, /* 00000B80 "RS_[.+PI" */
+ 0x43,0x5F,0x08,0x5F,0x48,0x49,0x44,0x0B, /* 00000B88 "C_._HID." */
+ 0x41,0xD0,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000B90 "A.._CRS." */
+ 0x18,0x0A,0x15,0x47,0x01,0x20,0x00,0x20, /* 00000B98 "...G. . " */
+ 0x00,0x01,0x02,0x47,0x01,0xA0,0x00,0xA0, /* 00000BA0 "...G...." */
+ 0x00,0x01,0x02,0x22,0x04,0x00,0x79,0x00, /* 00000BA8 "..."..y." */
+ 0x5B,0x82,0x47,0x05,0x44,0x4D,0x41,0x30, /* 00000BB0 "[.G.DMA0" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000BB8 "._HID.A." */
+ 0x02,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000BC0 "..._CRS." */
+ 0x41,0x04,0x0A,0x3D,0x2A,0x10,0x04,0x47, /* 00000BC8 "A..=*..G" */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x47, /* 00000BD0 ".......G" */
+ 0x01,0x81,0x00,0x81,0x00,0x00,0x03,0x47, /* 00000BD8 ".......G" */
+ 0x01,0x87,0x00,0x87,0x00,0x00,0x01,0x47, /* 00000BE0 ".......G" */
+ 0x01,0x89,0x00,0x89,0x00,0x00,0x03,0x47, /* 00000BE8 ".......G" */
+ 0x01,0x8F,0x00,0x8F,0x00,0x00,0x01,0x47, /* 00000BF0 ".......G" */
+ 0x01,0xC0,0x00,0xC0,0x00,0x00,0x20,0x47, /* 00000BF8 "...... G" */
+ 0x01,0x80,0x04,0x80,0x04,0x00,0x10,0x79, /* 00000C00 ".......y" */
+ 0x00,0x5B,0x82,0x25,0x54,0x4D,0x52,0x5F, /* 00000C08 ".[.%TMR_" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000C10 "._HID.A." */
+ 0x01,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000C18 "..._CRS." */
+ 0x10,0x0A,0x0D,0x47,0x01,0x40,0x00,0x40, /* 00000C20 "...G.@.@" */
+ 0x00,0x00,0x04,0x22,0x01,0x00,0x79,0x00, /* 00000C28 "..."..y." */
+ 0x5B,0x82,0x25,0x52,0x54,0x43,0x5F,0x08, /* 00000C30 "[.%RTC_." */
+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0B, /* 00000C38 "_HID.A.." */
+ 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x10, /* 00000C40 ".._CRS.." */
+ 0x0A,0x0D,0x47,0x01,0x70,0x00,0x70,0x00, /* 00000C48 "..G.p.p." */
+ 0x00,0x02,0x22,0x00,0x01,0x79,0x00,0x5B, /* 00000C50 ".."..y.[" */
+ 0x82,0x22,0x53,0x50,0x4B,0x52,0x08,0x5F, /* 00000C58 "."SPKR._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x08,0x00, /* 00000C60 "HID.A..." */
+ 0x08,0x5F,0x43,0x52,0x53,0x11,0x0D,0x0A, /* 00000C68 "._CRS..." */
+ 0x0A,0x47,0x01,0x61,0x00,0x61,0x00,0x00, /* 00000C70 ".G.a.a.." */
+ 0x01,0x79,0x00,0x5B,0x82,0x31,0x50,0x53, /* 00000C78 ".y.[.1PS" */
+ 0x32,0x4D,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000C80 "2M._HID." */
+ 0x41,0xD0,0x0F,0x13,0x08,0x5F,0x43,0x49, /* 00000C88 "A...._CI" */
+ 0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14,0x09, /* 00000C90 "D.A....." */
+ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000C98 "_STA...." */
+ 0x08,0x5F,0x43,0x52,0x53,0x11,0x08,0x0A, /* 00000CA0 "._CRS..." */
+ 0x05,0x22,0x00,0x10,0x79,0x00,0x5B,0x82, /* 00000CA8 "."..y.[." */
+ 0x42,0x04,0x50,0x53,0x32,0x4B,0x08,0x5F, /* 00000CB0 "B.PS2K._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x03,0x03, /* 00000CB8 "HID.A..." */
+ 0x08,0x5F,0x43,0x49,0x44,0x0C,0x41,0xD0, /* 00000CC0 "._CID.A." */
+ 0x03,0x0B,0x14,0x09,0x5F,0x53,0x54,0x41, /* 00000CC8 "...._STA" */
+ 0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 00000CD0 "....._CR" */
+ 0x53,0x11,0x18,0x0A,0x15,0x47,0x01,0x60, /* 00000CD8 "S....G.`" */
+ 0x00,0x60,0x00,0x00,0x01,0x47,0x01,0x64, /* 00000CE0 ".`...G.d" */
+ 0x00,0x64,0x00,0x00,0x01,0x22,0x02,0x00, /* 00000CE8 ".d...".." */
+ 0x79,0x00,0x5B,0x82,0x3A,0x46,0x44,0x43, /* 00000CF0 "y.[.:FDC" */
+ 0x30,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000CF8 "0._HID.A" */
+ 0xD0,0x07,0x00,0x14,0x09,0x5F,0x53,0x54, /* 00000D00 "....._ST" */
+ 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000D08 "A....._C" */
+ 0x52,0x53,0x11,0x1B,0x0A,0x18,0x47,0x01, /* 00000D10 "RS....G." */
+ 0xF0,0x03,0xF0,0x03,0x01,0x06,0x47,0x01, /* 00000D18 "......G." */
+ 0xF7,0x03,0xF7,0x03,0x01,0x01,0x22,0x40, /* 00000D20 "......"@" */
+ 0x00,0x2A,0x04,0x00,0x79,0x00,0x5B,0x82, /* 00000D28 ".*..y.[." */
+ 0x35,0x55,0x41,0x52,0x31,0x08,0x5F,0x48, /* 00000D30 "5UAR1._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000D38 "ID.A...." */
+ 0x5F,0x55,0x49,0x44,0x01,0x14,0x09,0x5F, /* 00000D40 "_UID..._" */
+ 0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08, /* 00000D48 "STA....." */
+ 0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000D50 "_CRS...." */
+ 0x47,0x01,0xF8,0x03,0xF8,0x03,0x01,0x08, /* 00000D58 "G......." */
+ 0x22,0x10,0x00,0x79,0x00,0x5B,0x82,0x36, /* 00000D60 ""..y.[.6" */
+ 0x4C,0x54,0x50,0x31,0x08,0x5F,0x48,0x49, /* 00000D68 "LTP1._HI" */
+ 0x44,0x0C,0x41,0xD0,0x04,0x00,0x08,0x5F, /* 00000D70 "D.A...._" */
+ 0x55,0x49,0x44,0x0A,0x02,0x14,0x09,0x5F, /* 00000D78 "UID...._" */
+ 0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08, /* 00000D80 "STA....." */
+ 0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000D88 "_CRS...." */
+ 0x47,0x01,0x78,0x03,0x78,0x03,0x08,0x08, /* 00000D90 "G.x.x..." */
+ 0x22,0x80,0x00,0x79,0x00,
+};
+int DsdtLen=sizeof(AmlCode);
diff --git a/tools/firmware/hvmloader/acpi/static_tables.c b/tools/firmware/hvmloader/acpi/static_tables.c
new file mode 100644
index 0000000000..0890700f7a
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi/static_tables.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2006, Keir Fraser, XenSource Inc.
+ *
+ * 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 "acpi2_0.h"
+#include "../config.h"
+#include <xen/hvm/ioreq.h>
+
+/*
+ * Firmware ACPI Control Structure (FACS).
+ */
+
+struct acpi_20_facs Facs = {
+ .signature = ACPI_2_0_FACS_SIGNATURE,
+ .length = sizeof(struct acpi_20_facs),
+ .version = ACPI_2_0_FACS_VERSION
+};
+
+
+/*
+ * Fixed ACPI Description Table (FADT).
+ */
+
+#define ACPI_PM1A_EVT_BLK_BIT_WIDTH 0x20
+#define ACPI_PM1A_EVT_BLK_BIT_OFFSET 0x00
+#define ACPI_PM1A_CNT_BLK_BIT_WIDTH 0x10
+#define ACPI_PM1A_CNT_BLK_BIT_OFFSET 0x00
+#define ACPI_PM_TMR_BLK_BIT_WIDTH 0x20
+#define ACPI_PM_TMR_BLK_BIT_OFFSET 0x00
+
+struct acpi_20_fadt Fadt = {
+ .header = {
+ .signature = ACPI_2_0_FADT_SIGNATURE,
+ .length = sizeof(struct acpi_20_fadt),
+ .revision = ACPI_2_0_FADT_REVISION,
+ .oem_id = ACPI_OEM_ID,
+ .oem_table_id = ACPI_OEM_TABLE_ID,
+ .oem_revision = ACPI_OEM_REVISION,
+ .creator_id = ACPI_CREATOR_ID,
+ .creator_revision = ACPI_CREATOR_REVISION
+ },
+
+ .sci_int = 9,
+
+ .pm1a_evt_blk = ACPI_PM1A_EVT_BLK_ADDRESS,
+ .pm1a_cnt_blk = ACPI_PM1A_CNT_BLK_ADDRESS,
+ .pm_tmr_blk = ACPI_PM_TMR_BLK_ADDRESS,
+ .pm1_evt_len = ACPI_PM1A_EVT_BLK_BIT_WIDTH / 8,
+ .pm1_cnt_len = ACPI_PM1A_CNT_BLK_BIT_WIDTH / 8,
+ .pm_tmr_len = ACPI_PM_TMR_BLK_BIT_WIDTH / 8,
+
+ .p_lvl2_lat = 0x0fff, /* >100, means we do not support C2 state */
+ .p_lvl3_lat = 0x0fff, /* >1000, means we do not support C3 state */
+ .iapc_boot_arch = ACPI_LEGACY_DEVICES | ACPI_8042,
+ .flags = (ACPI_PROC_C1 | ACPI_SLP_BUTTON |
+ ACPI_WBINVD | ACPI_PWR_BUTTON |
+ ACPI_FIX_RTC | ACPI_TMR_VAL_EXT),
+
+ .reset_reg = {
+ .address_space_id = ACPI_SYSTEM_IO,
+ .register_bit_width = 8, /* *must* be 8 */
+ .register_bit_offset = 0, /* *must* be 0 */
+ .address = 0xcf9
+ },
+ .reset_value = 6,
+
+ .x_pm1a_evt_blk = {
+ .address_space_id = ACPI_SYSTEM_IO,
+ .register_bit_width = ACPI_PM1A_EVT_BLK_BIT_WIDTH,
+ .register_bit_offset = ACPI_PM1A_EVT_BLK_BIT_OFFSET,
+ .address = ACPI_PM1A_EVT_BLK_ADDRESS,
+ },
+
+ .x_pm1a_cnt_blk = {
+ .address_space_id = ACPI_SYSTEM_IO,
+ .register_bit_width = ACPI_PM1A_CNT_BLK_BIT_WIDTH,
+ .register_bit_offset = ACPI_PM1A_CNT_BLK_BIT_OFFSET,
+ .address = ACPI_PM1A_CNT_BLK_ADDRESS,
+ },
+
+ .x_pm_tmr_blk = {
+ .address_space_id = ACPI_SYSTEM_IO,
+ .register_bit_width = ACPI_PM_TMR_BLK_BIT_WIDTH,
+ .register_bit_offset = ACPI_PM_TMR_BLK_BIT_OFFSET,
+ .address = ACPI_PM_TMR_BLK_ADDRESS,
+ }
+};
+
+struct acpi_20_rsdt Rsdt = {
+ .header = {
+ .signature = ACPI_2_0_RSDT_SIGNATURE,
+ .length = sizeof(struct acpi_header),
+ .revision = ACPI_2_0_RSDT_REVISION,
+ .oem_id = ACPI_OEM_ID,
+ .oem_table_id = ACPI_OEM_TABLE_ID,
+ .oem_revision = ACPI_OEM_REVISION,
+ .creator_id = ACPI_CREATOR_ID,
+ .creator_revision = ACPI_CREATOR_REVISION
+ }
+};
+
+struct acpi_20_xsdt Xsdt = {
+ .header = {
+ .signature = ACPI_2_0_XSDT_SIGNATURE,
+ .length = sizeof(struct acpi_header),
+ .revision = ACPI_2_0_XSDT_REVISION,
+ .oem_id = ACPI_OEM_ID,
+ .oem_table_id = ACPI_OEM_TABLE_ID,
+ .oem_revision = ACPI_OEM_REVISION,
+ .creator_id = ACPI_CREATOR_ID,
+ .creator_revision = ACPI_CREATOR_REVISION
+ }
+};
+
+
+struct acpi_20_rsdp Rsdp = {
+ .signature = ACPI_2_0_RSDP_SIGNATURE,
+ .oem_id = ACPI_OEM_ID,
+ .revision = ACPI_OEM_REVISION,
+ .length = sizeof(struct acpi_20_rsdp)
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/acpi_madt.c b/tools/firmware/hvmloader/acpi_madt.c
deleted file mode 100644
index 5a9c3063ae..0000000000
--- a/tools/firmware/hvmloader/acpi_madt.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * acpi_madt.c: Update ACPI MADT table for multiple processor guest.
- *
- * Yu Ke, ke.yu@intel.com
- * Copyright (c) 2005, 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.
- */
-
-#include "../acpi/acpi2_0.h"
-#include "../acpi/acpi_madt.h"
-#include "util.h"
-#include <xen/hvm/hvm_info_table.h>
-
-#define NULL ((void*)0)
-
-static struct hvm_info_table *table = NULL;
-
-static int validate_hvm_info(struct hvm_info_table *t)
-{
- char signature[] = "HVM INFO";
- uint8_t *ptr = (uint8_t *)t;
- uint8_t sum = 0;
- int i;
-
- /* strncmp(t->signature, "HVM INFO", 8) */
- for (i = 0; i < 8; i++) {
- if (signature[i] != t->signature[i]) {
- puts("Bad hvm info signature\n");
- return 0;
- }
- }
-
- for (i = 0; i < t->length; i++)
- sum += ptr[i];
-
- return (sum == 0);
-}
-
-/* xc_vmx_builder wrote hvm info at 0x9F800. Return it. */
-struct hvm_info_table *
-get_hvm_info_table(void)
-{
- struct hvm_info_table *t;
-
- if (table != NULL)
- return table;
-
- t = (struct hvm_info_table *)HVM_INFO_PADDR;
-
- if (!validate_hvm_info(t)) {
- puts("Bad hvm info table\n");
- return NULL;
- }
-
- table = t;
-
- return table;
-}
-
-int
-get_vcpu_nr(void)
-{
- struct hvm_info_table *t = get_hvm_info_table();
- return (t ? t->nr_vcpus : 1); /* default 1 vcpu */
-}
-
-int
-get_acpi_enabled(void)
-{
- struct hvm_info_table *t = get_hvm_info_table();
- return (t ? t->acpi_enabled : 0); /* default no acpi */
-}
-
-
-static void *
-acpi_madt_get_madt(unsigned char *acpi_start)
-{
- ACPI_2_0_RSDP *rsdp=NULL;
- ACPI_2_0_RSDT *rsdt=NULL;
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt;
-
- rsdp = (ACPI_2_0_RSDP *)(acpi_start + sizeof(ACPI_2_0_FACS));
- if (rsdp->Signature != ACPI_2_0_RSDP_SIGNATURE) {
- puts("Bad RSDP signature\n");
- return NULL;
- }
-
- rsdt= (ACPI_2_0_RSDT *)
- (acpi_start + rsdp->RsdtAddress - ACPI_PHYSICAL_ADDRESS);
- if (rsdt->Header.Signature != ACPI_2_0_RSDT_SIGNATURE) {
- puts("Bad RSDT signature\n");
- return NULL;
- }
-
- madt = (ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *)
- ( acpi_start+ rsdt->Entry[1] - ACPI_PHYSICAL_ADDRESS);
- if (madt->Header.Header.Signature !=
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE) {
- puts("Bad MADT signature \n");
- return NULL;
- }
-
- return madt;
-}
-
-static void
-set_checksum(void *start, int checksum_offset, int len)
-{
- unsigned char sum = 0;
- unsigned char *ptr;
-
- ptr = start;
- ptr[checksum_offset] = 0;
- while (len--)
- sum += *ptr++;
-
- ptr = start;
- ptr[checksum_offset] = -sum;
-}
-
-static int
-acpi_madt_set_local_apics(
- int nr_vcpu,
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt)
-{
- int i;
-
- if ((nr_vcpu > MAX_VIRT_CPUS) || (nr_vcpu < 0) || !madt)
- return -1;
-
- for (i = 0; i < nr_vcpu; i++) {
- madt->LocalApic[i].Type = ACPI_PROCESSOR_LOCAL_APIC;
- madt->LocalApic[i].Length = sizeof (ACPI_LOCAL_APIC_STRUCTURE);
- madt->LocalApic[i].AcpiProcessorId = i;
- madt->LocalApic[i].ApicId = i;
- madt->LocalApic[i].Flags = 1;
- }
-
- madt->Header.Header.Length =
- sizeof(ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE) -
- (MAX_VIRT_CPUS - nr_vcpu)* sizeof(ACPI_LOCAL_APIC_STRUCTURE);
-
- return 0;
-}
-
-#define FIELD_OFFSET(TYPE,Field) ((unsigned int)(&(((TYPE *) 0)->Field)))
-
-int acpi_madt_update(unsigned char *acpi_start)
-{
- int rc;
- ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt;
-
- madt = acpi_madt_get_madt(acpi_start);
- if (!madt)
- return -1;
-
- rc = acpi_madt_set_local_apics(get_vcpu_nr(), madt);
- if (rc != 0)
- return rc;
-
- set_checksum(
- madt, FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
- madt->Header.Header.Length);
-
- return 0;
-}
-
-/*
- * Local variables:
- * c-file-style: "linux"
- * indent-tabs-mode: t
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/tools/firmware/hvmloader/acpi_ssdt_tpm.asl b/tools/firmware/hvmloader/acpi_ssdt_tpm.asl
new file mode 100644
index 0000000000..98010a7f14
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi_ssdt_tpm.asl
@@ -0,0 +1,29 @@
+//**********************************************************************//
+//*
+//* Copyright (c) 2006, IBM 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.
+
+//* SSDT for TPM TIS Interface for Xen with Qemu device model
+
+DefinitionBlock ("SSDT_TPM.aml", "SSDT", 1, "IBM","xen", 2006)
+{
+ Device (TPM) {
+ Name (_HID, EisaId ("PNP0C31"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ Memory32Fixed (ReadWrite, 0xFED40000, 0x5000,)
+ })
+ }
+} \ No newline at end of file
diff --git a/tools/firmware/hvmloader/acpi_ssdt_tpm.h b/tools/firmware/hvmloader/acpi_ssdt_tpm.h
new file mode 100644
index 0000000000..9d943a3a36
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi_ssdt_tpm.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20060707 [Sep 11 2006]
+ * Copyright (C) 2000 - 2006 Intel Corporation
+ * Supports ACPI Specification Revision 3.0a
+ *
+ * Compilation of "acpi_ssdt_tpm.asl" - Mon Oct 30 11:28:27 2006
+ *
+ * C source code output
+ *
+ */
+unsigned char AmlCode_TPM[] =
+{
+ 0x53,0x53,0x44,0x54,0x4C,0x00,0x00,0x00, /* 00000000 "SSDTL..." */
+ 0x01,0x6D,0x49,0x42,0x4D,0x00,0x00,0x00, /* 00000008 ".mIBM..." */
+ 0x78,0x65,0x6E,0x00,0x00,0x00,0x00,0x00, /* 00000010 "xen....." */
+ 0xD6,0x07,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
+ 0x07,0x07,0x06,0x20,0x5B,0x82,0x26,0x54, /* 00000020 "... [.&T" */
+ 0x50,0x4D,0x5F,0x08,0x5F,0x48,0x49,0x44, /* 00000028 "PM_._HID" */
+ 0x0C,0x41,0xD0,0x0C,0x31,0x08,0x5F,0x43, /* 00000030 ".A..1._C" */
+ 0x52,0x53,0x11,0x11,0x0A,0x0E,0x86,0x09, /* 00000038 "RS......" */
+ 0x00,0x01,0x00,0x00,0xD4,0xFE,0x00,0x50, /* 00000040 ".......P" */
+ 0x00,0x00,0x79,0x00,
+};
diff --git a/tools/firmware/hvmloader/acpi_utils.c b/tools/firmware/hvmloader/acpi_utils.c
new file mode 100644
index 0000000000..5fd9847d4e
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi_utils.c
@@ -0,0 +1,318 @@
+/*
+ * Commonly used ACPI utility functions.
+ * Probing for devices and writing SSDT entries into XSDT and RSDT tables.
+ *
+ * Yu Ke, ke.yu@intel.com
+ * Copyright (c) 2005, Intel Corporation.
+ * Copyright (c) 2006, IBM 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.
+ */
+
+#include "acpi/acpi2_0.h"
+#include "acpi_utils.h"
+#include "util.h"
+#include <xen/hvm/e820.h>
+
+static int acpi_rsdt_add_entry_pointer(unsigned char *acpi_start,
+ unsigned char *entry);
+static int acpi_xsdt_add_entry_pointer(unsigned char *acpi_start,
+ unsigned char *entry);
+static unsigned char *acpi_xsdt_add_entry(unsigned char *acpi_start,
+ unsigned char **freemem,
+ unsigned char *limit,
+ unsigned char *table,
+ unsigned int table_size);
+
+void set_checksum(void *start, int checksum_offset, int len)
+{
+ unsigned char sum = 0;
+ unsigned char *ptr;
+
+ ptr = start;
+ ptr[checksum_offset] = 0;
+ while ( len-- )
+ sum += *ptr++;
+
+ ptr = start;
+ ptr[checksum_offset] = -sum;
+}
+
+
+#include "acpi_ssdt_tpm.h"
+static void acpi_tpm_tis_probe(unsigned char *acpi_start,
+ unsigned char **freemem,
+ unsigned char *limit)
+{
+ unsigned char *addr;
+ ACPI_2_0_TCPA_CLIENT *tcpa;
+ /* check TPM_DID, TPM_VID, TPM_RID in ioemu/hw/tpm_tis.c */
+ uint16_t tis_did_vid_rid[] = {0x0001, 0x0001, 0x0001};
+ static const ACPI_2_0_TCPA_CLIENT Tcpa = {
+ .header = {
+ .signature = ACPI_2_0_TCPA_SIGNATURE,
+ .length = sizeof(ACPI_2_0_TCPA_CLIENT),
+ .revision = ACPI_2_0_TCPA_REVISION,
+ .oem_id = {'I', 'B', 'M', ' ', ' ', ' '},
+ .oem_table_id = ASCII64(' ', ' ', ' ', ' ', ' ', 'x', 'e', 'n'),
+ .oem_revision = 1,
+ .creator_id = ASCII32('I', 'B', 'M', ' '),
+ .creator_revision = 1,
+ }
+ };
+
+ /* probe for TIS interface ... */
+ if ( memcmp((char *)(0xFED40000 + 0xF00),
+ tis_did_vid_rid,
+ sizeof(tis_did_vid_rid)) != 0 )
+ return;
+
+ printf("TIS is available\n");
+ addr = acpi_xsdt_add_entry(acpi_start, freemem, limit,
+ AmlCode_TPM, sizeof(AmlCode_TPM));
+ if ( addr == NULL )
+ return;
+
+ /* legacy systems need an RSDT entry */
+ if ( acpi_rsdt_add_entry_pointer(acpi_start, addr) != 1 )
+ return;
+
+ /* add ACPI TCPA table */
+ addr = acpi_xsdt_add_entry(acpi_start, freemem, limit,
+ (unsigned char *)&Tcpa,
+ sizeof(Tcpa));
+ if ( addr == NULL )
+ return;
+
+ tcpa = (ACPI_2_0_TCPA_CLIENT *)addr;
+ tcpa->LASA = e820_malloc(
+ ACPI_2_0_TCPA_LAML_SIZE, E820_RESERVED, (uint32_t)~0);
+ if ( tcpa->LASA )
+ {
+ tcpa->LAML = ACPI_2_0_TCPA_LAML_SIZE;
+ memset((char *)(unsigned long)tcpa->LASA,
+ 0x0,
+ tcpa->LAML);
+ set_checksum(tcpa,
+ FIELD_OFFSET(struct acpi_header, checksum),
+ tcpa->header.length);
+ }
+
+ if ( acpi_rsdt_add_entry_pointer(acpi_start, addr) != 1 )
+ return;
+}
+
+
+/*
+ * Call functions that probe for devices and have them register their
+ * SSDT entries with the XSDT and RSDT tables.
+ */
+void acpi_update(unsigned char *acpi_start,
+ unsigned long acpi_size,
+ unsigned char *limit,
+ unsigned char **freemem)
+{
+ acpi_tpm_tis_probe(acpi_start, freemem, limit);
+}
+
+
+/*
+ * Search for the RSDP in memory below the BIOS
+ */
+struct acpi_20_rsdp *acpi_rsdp_get(unsigned char *acpi_start)
+{
+ int offset = 0;
+ int found = 0;
+ static int displayed = 0;
+ struct acpi_20_rsdp *rsdp;
+
+ while ( &acpi_start[offset] < (unsigned char *)0xf0000 )
+ {
+ rsdp = (struct acpi_20_rsdp *)&acpi_start[offset];
+ if ( rsdp->signature == ACPI_2_0_RSDP_SIGNATURE )
+ {
+ found = 1;
+ break;
+ }
+ offset += 0x10;
+ }
+
+ if ( !found )
+ rsdp = NULL;
+
+ if ( !displayed )
+ {
+ if ( rsdp )
+ printf("Found RSDP at %lx\n",(long)rsdp);
+ else
+ printf("ERROR: RSDP was not found\n");
+ displayed = 1;
+ }
+
+ return rsdp;
+}
+
+
+struct acpi_20_rsdt *acpi_rsdt_get(unsigned char *acpi_start)
+{
+ struct acpi_20_rsdp *rsdp;
+ struct acpi_20_rsdt *rsdt;
+
+ rsdp = acpi_rsdp_get(acpi_start);
+ if (!rsdp)
+ return NULL;
+
+ rsdt = (struct acpi_20_rsdt *)
+ (acpi_start + rsdp->rsdt_address - ACPI_PHYSICAL_ADDRESS);
+ if ( rsdt->header.signature != ACPI_2_0_RSDT_SIGNATURE )
+ {
+ printf("Bad RSDT signature\n");
+ return NULL;
+ }
+
+ return rsdt;
+}
+
+/*
+ * Add an entry to the RSDT table given the pointer to the entry.
+ */
+static int acpi_rsdt_add_entry_pointer(unsigned char *acpi_start,
+ unsigned char *entry)
+{
+ struct acpi_20_rsdt *rsdt = acpi_rsdt_get(acpi_start);
+ int found = 0;
+ int i = 0;
+
+ /* Find an empty slot in the RSDT table. */
+ while ( i < ACPI_MAX_NUM_TABLES )
+ {
+ if ( rsdt->entry[i] == 0 )
+ {
+ found = 1;
+ break;
+ }
+ i++;
+ }
+
+ if ( found )
+ {
+ rsdt->entry[i] = (uint64_t)(unsigned long)entry;
+ rsdt->header.length =
+ sizeof(struct acpi_header) +
+ (i + 1) * sizeof(uint64_t);
+ set_checksum(rsdt,
+ FIELD_OFFSET(struct acpi_header, checksum),
+ rsdt->header.length);
+ }
+
+ return found;
+}
+
+/* Get the XSDT table. */
+struct acpi_20_xsdt *acpi_xsdt_get(unsigned char *acpi_start)
+{
+ struct acpi_20_rsdp *rsdp;
+ struct acpi_20_xsdt *xsdt;
+
+ rsdp = acpi_rsdp_get(acpi_start);
+ if (!rsdp)
+ return NULL;
+
+ xsdt = (struct acpi_20_xsdt *)
+ (acpi_start + rsdp->xsdt_address - ACPI_PHYSICAL_ADDRESS);
+ if ( xsdt->header.signature != ACPI_2_0_XSDT_SIGNATURE )
+ {
+ printf("Bad XSDT signature\n");
+ return NULL;
+ }
+ return xsdt;
+}
+
+/*
+ * Add an entry to the XSDT table given the pointer to the entry.
+ */
+static int acpi_xsdt_add_entry_pointer(unsigned char *acpi_start,
+ unsigned char *entry)
+{
+ struct acpi_20_xsdt *xsdt = acpi_xsdt_get(acpi_start);
+ int found = 0;
+ int i = 0;
+
+ /* Find an empty slot in the XSDT table. */
+ while ( i < ACPI_MAX_NUM_TABLES )
+ {
+ if ( xsdt->entry[i] == 0 )
+ {
+ found = 1;
+ break;
+ }
+ i++;
+ }
+
+ if ( found )
+ {
+ xsdt->entry[i] = (uint64_t)(unsigned long)entry;
+ xsdt->header.length =
+ sizeof(struct acpi_header) +
+ (i + 1) * sizeof(uint64_t);
+ set_checksum(xsdt,
+ FIELD_OFFSET(struct acpi_header, checksum),
+ xsdt->header.length);
+ }
+
+ return found;
+}
+
+/*
+ add an entry to the xdst table entry pointers
+ copy the given ssdt data to the current available memory at
+ freemem, if it does not exceed the limit
+ */
+static unsigned char *acpi_xsdt_add_entry(unsigned char *acpi_start,
+ unsigned char **freemem,
+ unsigned char *limit,
+ unsigned char *table,
+ unsigned int table_size)
+{
+ struct acpi_20_xsdt *xsdt = acpi_xsdt_get(acpi_start);
+ int found = 0, i = 0;
+ unsigned char *addr = NULL;
+
+ /* Check for an empty slot in the Xsdt table. */
+ while ( i < ACPI_MAX_NUM_TABLES )
+ {
+ if ( xsdt->entry[i] == 0 )
+ {
+ found = 1;
+ break;
+ }
+ i++;
+ }
+
+ if ( found )
+ {
+ /* memory below hard limit ? */
+ if ( (*freemem + table_size) <= limit )
+ {
+ addr = *freemem;
+ memcpy(addr, table, table_size);
+ printf("Copied dyn. ACPI entry to %lx\n",(long)addr);
+ *freemem += ((table_size + 0xf) & ~0xf);
+
+ acpi_xsdt_add_entry_pointer(acpi_start, addr);
+ }
+ }
+
+ return addr;
+}
diff --git a/tools/firmware/acpi/acpi_facs.h b/tools/firmware/hvmloader/acpi_utils.h
index e8c55a30ea..814fa3229d 100644
--- a/tools/firmware/acpi/acpi_facs.h
+++ b/tools/firmware/hvmloader/acpi_utils.h
@@ -1,5 +1,8 @@
/*
- * Copyright (c) 2004, Intel Corporation.
+ * Commonly used ACPI utility functions.
+ *
+ * Yu Ke, ke.yu@intel.com
+ * Copyright (c) 2005, 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,
@@ -13,20 +16,21 @@
* 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.
- *
*/
-#ifndef _FACS_H
-#define _FACS_H
+#ifndef ACPI_UTILS_H
+#define ACPI_UTILS_H
-//
-// FACS Definitions
-//
+#define FIELD_OFFSET(TYPE,Field) ((unsigned int)(&(((TYPE *) 0)->Field)))
-#define ACPI_FIRMWARE_WAKING_VECTOR 0x00000000
-#define ACPI_GLOBAL_LOCK 0x00000000
+#define NULL ((void*)0)
-#define ACPI_FIRMWARE_CONTROL_STRUCTURE_FLAGS 0x00000000
+void set_checksum(void *start, int checksum_offset, int len);
+void acpi_update(unsigned char *acpi_start,
+ unsigned long acpi_size,
+ unsigned char *limit,
+ unsigned char **freemem);
-#define ACPI_X_FIRMWARE_WAKING_VECTOR 0x0000000000000000
+struct acpi_20_rsdt *acpi_rsdt_get(unsigned char *acpi_start);
+struct acpi_20_xsdt *acpi_xsdt_get(unsigned char *acpi_start);
#endif
diff --git a/tools/firmware/hvmloader/apic_regs.h b/tools/firmware/hvmloader/apic_regs.h
new file mode 100644
index 0000000000..4c313ab526
--- /dev/null
+++ b/tools/firmware/hvmloader/apic_regs.h
@@ -0,0 +1,108 @@
+#ifndef __ASM_APICDEF_H
+#define __ASM_APICDEF_H
+
+#define APIC_DEFAULT_PHYS_BASE 0xfee00000
+
+#define APIC_ID 0x20
+#define APIC_ID_MASK (0xFFu<<24)
+#define GET_APIC_ID(x) (((x)>>24)&0xFFu)
+#define SET_APIC_ID(x) (((x)<<24))
+#define APIC_LVR 0x30
+#define APIC_LVR_MASK 0xFF00FF
+#define GET_APIC_VERSION(x) ((x)&0xFF)
+#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF)
+#define APIC_INTEGRATED(x) ((x)&0xF0)
+#define APIC_XAPIC(x) ((x) >= 0x14)
+#define APIC_TASKPRI 0x80
+#define APIC_TPRI_MASK 0xFF
+#define APIC_ARBPRI 0x90
+#define APIC_ARBPRI_MASK 0xFF
+#define APIC_PROCPRI 0xA0
+#define APIC_EOI 0xB0
+#define APIC_EIO_ACK 0x0
+#define APIC_RRR 0xC0
+#define APIC_LDR 0xD0
+#define APIC_LDR_MASK (0xFF<<24)
+#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF)
+#define SET_APIC_LOGICAL_ID(x) (((x)<<24))
+#define APIC_ALL_CPUS 0xFF
+#define APIC_DFR 0xE0
+#define APIC_DFR_CLUSTER 0x0FFFFFFFul
+#define APIC_DFR_FLAT 0xFFFFFFFFul
+#define APIC_SPIV 0xF0
+#define APIC_SPIV_FOCUS_DISABLED (1<<9)
+#define APIC_SPIV_APIC_ENABLED (1<<8)
+#define APIC_ISR 0x100
+#define APIC_TMR 0x180
+#define APIC_IRR 0x200
+#define APIC_ESR 0x280
+#define APIC_ESR_SEND_CS 0x00001
+#define APIC_ESR_RECV_CS 0x00002
+#define APIC_ESR_SEND_ACC 0x00004
+#define APIC_ESR_RECV_ACC 0x00008
+#define APIC_ESR_SENDILL 0x00020
+#define APIC_ESR_RECVILL 0x00040
+#define APIC_ESR_ILLREGA 0x00080
+#define APIC_ICR 0x300
+#define APIC_DEST_SELF 0x40000
+#define APIC_DEST_ALLINC 0x80000
+#define APIC_DEST_ALLBUT 0xC0000
+#define APIC_ICR_RR_MASK 0x30000
+#define APIC_ICR_RR_INVALID 0x00000
+#define APIC_ICR_RR_INPROG 0x10000
+#define APIC_ICR_RR_VALID 0x20000
+#define APIC_INT_LEVELTRIG 0x08000
+#define APIC_INT_ASSERT 0x04000
+#define APIC_ICR_BUSY 0x01000
+#define APIC_DEST_LOGICAL 0x00800
+#define APIC_DEST_PHYSICAL 0x00000
+#define APIC_DM_FIXED 0x00000
+#define APIC_DM_LOWEST 0x00100
+#define APIC_DM_SMI 0x00200
+#define APIC_DM_REMRD 0x00300
+#define APIC_DM_NMI 0x00400
+#define APIC_DM_INIT 0x00500
+#define APIC_DM_STARTUP 0x00600
+#define APIC_DM_EXTINT 0x00700
+#define APIC_VECTOR_MASK 0x000FF
+#define APIC_ICR2 0x310
+#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
+#define SET_APIC_DEST_FIELD(x) ((x)<<24)
+#define APIC_LVTT 0x320
+#define APIC_LVTTHMR 0x330
+#define APIC_LVTPC 0x340
+#define APIC_LVT0 0x350
+#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
+#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3)
+#define SET_APIC_TIMER_BASE(x) (((x)<<18))
+#define APIC_TIMER_BASE_CLKIN 0x0
+#define APIC_TIMER_BASE_TMBASE 0x1
+#define APIC_TIMER_BASE_DIV 0x2
+#define APIC_LVT_TIMER_PERIODIC (1<<17)
+#define APIC_LVT_MASKED (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER (1<<15)
+#define APIC_LVT_REMOTE_IRR (1<<14)
+#define APIC_INPUT_POLARITY (1<<13)
+#define APIC_SEND_PENDING (1<<12)
+#define APIC_MODE_MASK 0x700
+#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
+#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
+#define APIC_MODE_FIXED 0x0
+#define APIC_MODE_NMI 0x4
+#define APIC_MODE_EXTINT 0x7
+#define APIC_LVT1 0x360
+#define APIC_LVTERR 0x370
+#define APIC_TMICT 0x380
+#define APIC_TMCCT 0x390
+#define APIC_TDCR 0x3E0
+#define APIC_TDR_DIV_TMBASE (1<<2)
+#define APIC_TDR_DIV_1 0xB
+#define APIC_TDR_DIV_2 0x0
+#define APIC_TDR_DIV_4 0x1
+#define APIC_TDR_DIV_8 0x2
+#define APIC_TDR_DIV_16 0x3
+#define APIC_TDR_DIV_32 0x8
+#define APIC_TDR_DIV_64 0x9
+#define APIC_TDR_DIV_128 0xA
+
+#endif
diff --git a/tools/firmware/hvmloader/config.h b/tools/firmware/hvmloader/config.h
new file mode 100644
index 0000000000..18d906c4eb
--- /dev/null
+++ b/tools/firmware/hvmloader/config.h
@@ -0,0 +1,13 @@
+#ifndef __HVMLOADER_CONFIG_H__
+#define __HVMLOADER_CONFIG_H__
+
+#define IOAPIC_BASE_ADDRESS 0xfec00000
+#define IOAPIC_ID 0x00
+#define IOAPIC_VERSION 0x11
+
+#define LAPIC_BASE_ADDRESS 0xfee00000
+
+#define PCI_ISA_DEVFN 0x08 /* dev 1, fn 0 */
+#define PCI_ISA_IRQ_MASK 0x0c60U /* ISA IRQs 5,6,10,11 are PCI connected */
+
+#endif /* __HVMLOADER_CONFIG_H__ */
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index e1a1c22c20..66c113ec7c 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -1,13 +1,11 @@
/*
* hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
*
- * A quicky so that we can boot rom images as if they were a Linux kernel.
- * This code will copy the rom images (ROMBIOS/VGABIOS/VM86) into their
- * respective spaces and transfer control to VM86 to execute the BIOSes.
- *
* Leendert van Doorn, leendert@watson.ibm.com
* Copyright (c) 2005, International Business Machines Corporation.
*
+ * Copyright (c) 2006, Keir Fraser, XenSource Inc.
+ *
* 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.
@@ -22,205 +20,341 @@
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include "roms.h"
-#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+#include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "hypercall.h"
#include "util.h"
+#include "acpi_utils.h"
#include "smbios.h"
+#include "config.h"
+#include "apic_regs.h"
+#include "pci_regs.h"
#include <xen/version.h>
#include <xen/hvm/params.h>
+#include <xen/hvm/e820.h>
/* memory map */
-#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
-#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
-#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
-#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
+#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
+#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
+#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
+#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
/* invoke SVM's paged realmode support */
-#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
+#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
/*
* C runtime start off
*/
asm(
-" .text \n"
-" .globl _start \n"
-"_start: \n"
-" cld \n"
-" cli \n"
-" lgdt gdt_desr \n"
-" movl $stack_top, %esp \n"
-" movl %esp, %ebp \n"
-" call main \n"
-" jmp halt \n"
-" \n"
-"gdt_desr: \n"
-" .word gdt_end - gdt - 1 \n"
-" .long gdt \n"
-" \n"
-" .align 8 \n"
-"gdt: \n"
-" .quad 0x0000000000000000 \n"
-" .quad 0x00CF92000000FFFF \n"
-" .quad 0x00CF9A000000FFFF \n"
-"gdt_end: \n"
-" \n"
-"halt: \n"
-" sti \n"
-" jmp . \n"
-" \n"
-" .bss \n"
-" .align 8 \n"
-"stack: \n"
-" .skip 0x4000 \n"
-"stack_top: \n"
-);
-
-extern int get_acpi_enabled(void);
-extern int acpi_madt_update(unsigned char* acpi_start);
+ " .text \n"
+ " .globl _start \n"
+ "_start: \n"
+ " cld \n"
+ " cli \n"
+ " lgdt gdt_desr \n"
+ " movl $stack_top, %esp \n"
+ " movl %esp, %ebp \n"
+ " call main \n"
+ " ud2 \n"
+ " \n"
+ "gdt_desr: \n"
+ " .word gdt_end - gdt - 1 \n"
+ " .long gdt \n"
+ " \n"
+ " .align 8 \n"
+ "gdt: \n"
+ " .quad 0x0000000000000000 \n"
+ " .quad 0x00CF92000000FFFF \n"
+ " .quad 0x00CF9A000000FFFF \n"
+ "gdt_end: \n"
+ " \n"
+ " .bss \n"
+ " .align 8 \n"
+ "stack: \n"
+ " .skip 0x4000 \n"
+ "stack_top: \n"
+ );
+
extern void create_mp_tables(void);
-struct hvm_info_table *get_hvm_info_table(void);
static int
cirrus_check(void)
{
- outw(0x3C4, 0x9206);
- return inb(0x3C5) == 0x12;
+ outw(0x3C4, 0x9206);
+ return inb(0x3C5) == 0x12;
}
static int
vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
{
- int eax;
+ int eax;
- __asm__ __volatile__(
- ".byte 0x0F,0x01,0xD9"
- : "=a" (eax)
- : "a"(function),
- "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
- );
- return eax;
+ __asm__ __volatile__ (
+ ".byte 0x0F,0x01,0xD9"
+ : "=a" (eax)
+ : "a"(function),
+ "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) );
+ return eax;
}
static int
check_amd(void)
{
- char id[12];
+ char id[12];
- __asm__ __volatile__(
- "cpuid"
- : "=b" (*(int *)(&id[0])),
- "=c" (*(int *)(&id[8])),
- "=d" (*(int *)(&id[4]))
- : "a" (0)
- );
- return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
+ __asm__ __volatile__ (
+ "cpuid"
+ : "=b" (*(int *)(&id[0])),
+ "=c" (*(int *)(&id[8])),
+ "=d" (*(int *)(&id[4]))
+ : "a" (0) );
+ return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
}
static void
wrmsr(uint32_t idx, uint64_t v)
{
- __asm__ __volatile__(
- "wrmsr"
- : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
+ __asm__ __volatile__ (
+ "wrmsr"
+ : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
}
static void
init_hypercalls(void)
{
- uint32_t eax, ebx, ecx, edx;
- unsigned long i;
- char signature[13], number[13];
- xen_extraversion_t extraversion;
+ uint32_t eax, ebx, ecx, edx;
+ unsigned long i;
+ char signature[13];
+ xen_extraversion_t extraversion;
+
+ cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+
+ *(uint32_t *)(signature + 0) = ebx;
+ *(uint32_t *)(signature + 4) = ecx;
+ *(uint32_t *)(signature + 8) = edx;
+ signature[12] = '\0';
+
+ if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) )
+ {
+ printf("FATAL: Xen hypervisor not detected\n");
+ __asm__ __volatile__( "ud2" );
+ }
+
+ /* Fill in hypercall transfer pages. */
+ cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+ for ( i = 0; i < eax; i++ )
+ wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
+
+ /* Print version information. */
+ cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ printf("Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
+}
+
+static void apic_setup(void)
+{
+ /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
+ ioapic_write(0x00, IOAPIC_ID);
+
+ /* Set up Virtual Wire mode. */
+ lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
+ lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
+ lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
+}
+
+static void pci_setup(void)
+{
+ uint32_t devfn, bar_reg, bar_data, bar_sz, cmd;
+ uint32_t *base, io_base = 0xc000, mem_base = HVM_BELOW_4G_MMIO_START;
+ uint16_t class, vendor_id, device_id;
+ unsigned int bar, pin, link, isa_irq;
+
+ /* Program PCI-ISA bridge with appropriate link routes. */
+ link = 0;
+ for ( isa_irq = 0; isa_irq < 15; isa_irq++ )
+ {
+ if ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) )
+ continue;
+ pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
+ printf("PCI-ISA link %u routed to IRQ%u\n", link, isa_irq);
+ if ( link++ == 4 )
+ break;
+ }
- cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+ /* Program ELCR to match PCI-wired IRQs. */
+ outb(0x4d0, (uint8_t)(PCI_ISA_IRQ_MASK >> 0));
+ outb(0x4d1, (uint8_t)(PCI_ISA_IRQ_MASK >> 8));
- *(uint32_t *)(signature + 0) = ebx;
- *(uint32_t *)(signature + 4) = ecx;
- *(uint32_t *)(signature + 8) = edx;
- signature[12] = '\0';
+ /* Scan the PCI bus and map resources. */
+ for ( devfn = 0; devfn < 128; devfn++ )
+ {
+ class = pci_readw(devfn, PCI_CLASS_DEVICE);
+ vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
+ device_id = pci_readw(devfn, PCI_DEVICE_ID);
+ if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
+ continue;
- if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
- puts("FATAL: Xen hypervisor not detected\n");
- __asm__ __volatile__( "ud2" );
- }
+ ASSERT((devfn != PCI_ISA_DEVFN) ||
+ ((vendor_id == 0x8086) && (device_id == 0x7000)));
- cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+ switch ( class )
+ {
+ case 0x0680:
+ ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
+ /*
+ * PIIX4 ACPI PM. Special device with special PCI config space.
+ * No ordinary BARs.
+ */
+ pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
+ pci_writew(devfn, 0x22, 0x0000);
+ pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
+ pci_writew(devfn, 0x3d, 0x0001);
+ break;
+ case 0x0101:
+ /* PIIX3 IDE */
+ ASSERT((vendor_id == 0x8086) && (device_id == 0x7010));
+ pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
+ pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
+ /* fall through */
+ default:
+ /* Default memory mappings. */
+ for ( bar = 0; bar < 7; bar++ )
+ {
+ bar_reg = PCI_BASE_ADDRESS_0 + 4*bar;
+ if ( bar == 6 )
+ bar_reg = PCI_ROM_ADDRESS;
- puts("Detected Xen v");
- puts(itoa(number, eax >> 16));
- puts(".");
- puts(itoa(number, eax & 0xffff));
+ bar_data = pci_readl(devfn, bar_reg);
- cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+ pci_writel(devfn, bar_reg, ~0);
+ bar_sz = pci_readl(devfn, bar_reg);
+ if ( bar_sz == 0 )
+ continue;
- for (i = 0; i < eax; i++)
- wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
+ if ( (bar_data & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY )
+ {
+ base = &mem_base;
+ bar_sz &= PCI_BASE_ADDRESS_MEM_MASK;
+ bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
+ }
+ else
+ {
+ base = &io_base;
+ bar_sz &= PCI_BASE_ADDRESS_IO_MASK & 0xffff;
+ bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
+ }
+ bar_sz &= ~(bar_sz - 1);
- hypercall_xen_version(XENVER_extraversion, extraversion);
- puts(extraversion);
- puts("\n");
+ *base = (*base + bar_sz - 1) & ~(bar_sz - 1);
+ bar_data |= *base;
+ *base += bar_sz;
+
+ pci_writel(devfn, bar_reg, bar_data);
+ printf("pci dev %02x:%x bar %02x size %08x: %08x\n",
+ devfn>>3, devfn&7, bar_reg, bar_sz, bar_data);
+
+ /* Now enable the memory or I/O mapping. */
+ cmd = pci_readw(devfn, PCI_COMMAND);
+ if ( (bar_reg == PCI_ROM_ADDRESS) ||
+ ((bar_data & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) )
+ cmd |= PCI_COMMAND_MEMORY;
+ else
+ cmd |= PCI_COMMAND_IO;
+ pci_writew(devfn, PCI_COMMAND, cmd);
+ }
+ break;
+ }
+
+ /* Map the interrupt. */
+ pin = pci_readb(devfn, PCI_INTERRUPT_PIN);
+ if ( pin != 0 )
+ {
+ /* This is the barber's pole mapping used by Xen. */
+ link = ((pin - 1) + (devfn >> 3)) & 3;
+ isa_irq = pci_readb(PCI_ISA_DEVFN, 0x60 + link);
+ pci_writeb(devfn, PCI_INTERRUPT_LINE, isa_irq);
+ printf("pci dev %02x:%x INT%c->IRQ%u\n",
+ devfn>>3, devfn&7, 'A'+pin-1, isa_irq);
+ }
+ }
}
-int
-main(void)
+int main(void)
{
- struct xen_hvm_param hvm_param;
-
- puts("HVM Loader\n");
-
- init_hypercalls();
-
- puts("Loading ROMBIOS ...\n");
- memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
-
- hvm_param.domid = DOMID_SELF;
- hvm_param.index = HVM_PARAM_APIC_ENABLED;
- if (!hypercall_hvm_op(HVMOP_get_param, &hvm_param) && hvm_param.value)
- create_mp_tables();
-
- if (cirrus_check()) {
- puts("Loading Cirrus VGABIOS ...\n");
- memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
- vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
- } else {
- puts("Loading Standard VGABIOS ...\n");
- memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
- vgabios_stdvga, sizeof(vgabios_stdvga));
- }
-
- if (get_acpi_enabled() != 0) {
- puts("Loading ACPI ...\n");
- acpi_madt_update((unsigned char *) acpi);
- if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000) {
- /*
- * Make sure acpi table does not overlap rombios
- * currently acpi less than 8K will be OK.
- */
- memcpy((void *)ACPI_PHYSICAL_ADDRESS, acpi,
- sizeof(acpi));
- }
- }
-
- puts("Writing SMBIOS tables ...\n");
- hvm_write_smbios_tables();
-
- if (check_amd()) {
- /* AMD implies this is SVM */
- puts("SVM go ...\n");
- vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
- } else {
- puts("Loading VMXAssist ...\n");
- memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
- vmxassist, sizeof(vmxassist));
-
- puts("VMX go ...\n");
- __asm__ __volatile__(
- "jmp *%%eax"
- : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
- );
- }
-
- puts("Failed to invoke ROMBIOS\n");
- return 0;
+ int acpi_sz;
+ uint8_t *freemem;
+
+ printf("HVM Loader\n");
+
+ init_hypercalls();
+
+ printf("Writing SMBIOS tables ...\n");
+ hvm_write_smbios_tables();
+
+ printf("Loading ROMBIOS ...\n");
+ memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
+
+ apic_setup();
+ pci_setup();
+
+ if ( (get_vcpu_nr() > 1) || get_apic_mode() )
+ create_mp_tables();
+
+ if ( cirrus_check() )
+ {
+ printf("Loading Cirrus VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
+ }
+ else
+ {
+ printf("Loading Standard VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_stdvga, sizeof(vgabios_stdvga));
+ }
+
+ if ( get_acpi_enabled() != 0 )
+ {
+ printf("Loading ACPI ...\n");
+ acpi_sz = acpi_build_tables((uint8_t *)ACPI_PHYSICAL_ADDRESS);
+ freemem = (uint8_t *)ACPI_PHYSICAL_ADDRESS + acpi_sz;
+ ASSERT(freemem <= (uint8_t *)0xF0000);
+ acpi_update((unsigned char *)ACPI_PHYSICAL_ADDRESS,
+ freemem - (uint8_t *)ACPI_PHYSICAL_ADDRESS,
+ (unsigned char *)0xF0000,
+ &freemem);
+ }
+
+ if ( check_amd() )
+ {
+ /* AMD implies this is SVM */
+ printf("SVM go ...\n");
+ vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
+ }
+ else
+ {
+ printf("Loading VMXAssist ...\n");
+ memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
+ vmxassist, sizeof(vmxassist));
+
+ printf("VMX go ...\n");
+ __asm__ __volatile__(
+ "jmp *%%eax"
+ : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
+ );
+ }
+
+ printf("Failed to invoke ROMBIOS\n");
+ return 0;
}
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/mp_tables.c b/tools/firmware/hvmloader/mp_tables.c
index d836832662..9a1238e51a 100644
--- a/tools/firmware/hvmloader/mp_tables.c
+++ b/tools/firmware/hvmloader/mp_tables.c
@@ -28,6 +28,8 @@
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
+#include <acpi_utils.h>
+#include "config.h"
/* FIXME find a header that already has types defined!!! */
typedef unsigned char uint8_t;
@@ -44,11 +46,11 @@ typedef unsigned long uint64_t;
typedef signed long int64_t;
#endif
-#define ROMBIOS_SEG 0xF000
-#define ROMBIOS_BEGIN 0x000F0000
-#define ROMBIOS_SIZE 0x00010000
-#define ROMBIOS_MAXOFFSET 0x0000FFFF
-#define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
+#define ROMBIOS_SEG 0xF000
+#define ROMBIOS_BEGIN 0x000F0000
+#define ROMBIOS_SIZE 0x00010000
+#define ROMBIOS_MAXOFFSET 0x0000FFFF
+#define ROMBIOS_END (ROMBIOS_BEGIN + ROMBIOS_SIZE)
/* number of non-processor MP table entries */
#define NR_NONPROC_ENTRIES 18
@@ -77,20 +79,13 @@ typedef signed long int64_t;
#define BUS_TYPE_LENGTH 6
#define BUS_TYPE_STR_ISA "ISA "
-
-#define LAPIC_BASE_ADDR 0xFEE00000
-
-#define IOAPIC_VERSION 0x11
-#define IOAPIC_BASE_ADDR 0xFEC00000
-#define IOAPIC_FLAG_ENABLED (1U << 0)
+#define BUS_ID_ISA 0
#define INTR_TYPE_INT 0
#define INTR_TYPE_NMI 1
#define INTR_TYPE_SMI 2
#define INTR_TYPE_EXTINT 3
-#define INTR_FLAGS 0
-
#define INTR_MAX_NR 16
#include "util.h"
@@ -103,232 +98,203 @@ extern int get_vcpu_nr(void); /* for the guest's VCPU count */
/* MP Floating Pointer Structure */
struct mp_floating_pointer_struct {
- uint8_t signature[4];
- uint32_t mp_table;
- uint8_t length;
- uint8_t revision;
- uint8_t checksum;
- uint8_t feature[5];
+ uint8_t signature[4];
+ uint32_t mp_table;
+ uint8_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ uint8_t feature[5];
};
/* MP Configuration Table */
struct mp_config_table {
- uint8_t signature[4];
- uint16_t length;
- uint8_t revision;
- uint8_t checksum;
- uint8_t oem_id[8];
- uint8_t vendor_id[12];
- uint32_t oem_table;
- uint16_t oem_table_sz;
- uint16_t nr_entries;
- uint32_t lapic;
- uint16_t extended_length;
- uint8_t extended_checksum;
- uint8_t reserved;
+ uint8_t signature[4];
+ uint16_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ uint8_t oem_id[8];
+ uint8_t vendor_id[12];
+ uint32_t oem_table;
+ uint16_t oem_table_sz;
+ uint16_t nr_entries;
+ uint32_t lapic;
+ uint16_t extended_length;
+ uint8_t extended_checksum;
+ uint8_t reserved;
};
/* MP Processor Entry */
struct mp_proc_entry {
- uint8_t type;
- uint8_t lapic_id;
- uint8_t lapic_version;
- uint8_t cpu_flags;
- uint32_t cpu_signature;
- uint32_t feature_flags;
- uint8_t reserved[8];
+ uint8_t type;
+ uint8_t lapic_id;
+ uint8_t lapic_version;
+ uint8_t cpu_flags;
+ uint32_t cpu_signature;
+ uint32_t feature_flags;
+ uint8_t reserved[8];
};
/* MP Bus Entry */
struct mp_bus_entry {
- uint8_t type;
- uint8_t bus_id;
- uint8_t bus_type_str[6];
+ uint8_t type;
+ uint8_t bus_id;
+ uint8_t bus_type_str[6];
};
/* MP IOAPIC Entry */
struct mp_ioapic_entry {
- uint8_t type;
- uint8_t ioapic_id;
- uint8_t ioapic_version;
- uint8_t ioapic_flags;
- uint32_t ioapic_addr;
+ uint8_t type;
+ uint8_t ioapic_id;
+ uint8_t ioapic_version;
+ uint8_t ioapic_flags;
+ uint32_t ioapic_addr;
};
/* MP IO Interrupt Entry */
struct mp_io_intr_entry {
- uint8_t type;
- uint8_t intr_type;
- uint16_t io_intr_flags;
- uint8_t src_bus_id;
- uint8_t src_bus_irq;
- uint8_t dst_ioapic_id;
- uint8_t dst_ioapic_intin;
+ uint8_t type;
+ uint8_t intr_type;
+ uint16_t io_intr_flags;
+ uint8_t src_bus_id;
+ uint8_t src_bus_irq;
+ uint8_t dst_ioapic_id;
+ uint8_t dst_ioapic_intin;
};
/* MP Local Interrupt Entry */
struct mp_local_intr_entry {
- uint8_t type;
- uint8_t intr_type;
- uint16_t local_intr_flags;
- uint8_t src_bus_id;
- uint8_t src_bus_irq;
- uint8_t dst_lapic_id;
- uint8_t dst_lapic_lintin;
+ uint8_t type;
+ uint8_t intr_type;
+ uint16_t local_intr_flags;
+ uint8_t src_bus_id;
+ uint8_t src_bus_irq;
+ uint8_t dst_lapic_id;
+ uint8_t dst_lapic_lintin;
};
-/*
- * fill_mp_config_table - fills in the information for the MP config table
- *
- * When calculating the length and nr_entries fields, keep in mind that there
- * are always 18 non-processor entries and N processor entries
- *
- * N vcpu entries
- * 1 bus entry
- * 1 IOAPIC entry
- * + 16 IO intr. entries
- * ----------------------
- * 18 + N total entries
- */
-void fill_mp_config_table(struct mp_config_table *mpct)
+void fill_mp_config_table(struct mp_config_table *mpct, int length)
{
- int vcpu_nr;
-
- vcpu_nr = get_vcpu_nr();
-
- /* fill in the MP configuration table signature, "PCMP" */
- mpct->signature[0] = 'P';
- mpct->signature[1] = 'C';
- mpct->signature[2] = 'M';
- mpct->signature[3] = 'P';
-
- mpct->length = sizeof(struct mp_config_table)
- + vcpu_nr * sizeof(struct mp_proc_entry)
- + sizeof(struct mp_ioapic_entry)
- + sizeof(struct mp_bus_entry)
- + 16 * sizeof(struct mp_local_intr_entry);
-
- mpct->revision = 4;
-
- /*
- * We'll fill in the checksum later after all of the
- * entries have been created
- */
- mpct->checksum = 0;
-
- /* fill in the OEM ID string, "_HVMCPU_" */
- mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
- mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
- mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
-
- /* fill in the Vendor ID string, "XEN " */
- mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
- mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
- mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
- mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
- mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
- mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
-
- mpct->oem_table = 0;
- mpct->oem_table_sz = 0;
-
- mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
-
- mpct->lapic = LAPIC_BASE_ADDR;
- mpct->extended_length = 0;
- mpct->extended_checksum = 0;
-}
+ int vcpu_nr, i;
+ uint8_t checksum;
+ vcpu_nr = get_vcpu_nr();
-/* calculates the checksum for the MP configuration table */
-void fill_mp_config_table_checksum(struct mp_config_table *mpct)
-{
- int i;
- uint8_t checksum;
+ /* fill in the MP configuration table signature, "PCMP" */
+ mpct->signature[0] = 'P';
+ mpct->signature[1] = 'C';
+ mpct->signature[2] = 'M';
+ mpct->signature[3] = 'P';
- checksum = 0;
- for (i = 0; i < mpct->length; ++i)
- checksum += ((uint8_t *)(mpct))[i];
- mpct->checksum = -checksum;
-}
+ mpct->length = length;
+ mpct->revision = 4;
+
+ /* fill in the OEM ID string, "_HVMCPU_" */
+ mpct->oem_id[0] = '_'; mpct->oem_id[3] = 'M'; mpct->oem_id[6] = 'U';
+ mpct->oem_id[1] = 'H'; mpct->oem_id[4] = 'C'; mpct->oem_id[7] = '_';
+ mpct->oem_id[2] = 'V'; mpct->oem_id[5] = 'P';
+
+ /* fill in the Vendor ID string, "XEN " */
+ mpct->vendor_id[0] = 'X'; mpct->vendor_id[6] = ' ';
+ mpct->vendor_id[1] = 'E'; mpct->vendor_id[7] = ' ';
+ mpct->vendor_id[2] = 'N'; mpct->vendor_id[8] = ' ';
+ mpct->vendor_id[3] = ' '; mpct->vendor_id[9] = ' ';
+ mpct->vendor_id[4] = ' '; mpct->vendor_id[10] = ' ';
+ mpct->vendor_id[5] = ' '; mpct->vendor_id[11] = ' ';
+
+ mpct->oem_table = 0;
+ mpct->oem_table_sz = 0;
+
+ mpct->nr_entries = vcpu_nr + NR_NONPROC_ENTRIES;
+
+ mpct->lapic = LAPIC_BASE_ADDRESS;
+ mpct->extended_length = 0;
+ mpct->extended_checksum = 0;
+
+ /* Finally, fill in the checksum. */
+ mpct->checksum = checksum = 0;
+ for ( i = 0; i < length; i++ )
+ checksum += ((uint8_t *)(mpct))[i];
+ mpct->checksum = -checksum;
+}
/* fills in an MP processor entry for VCPU 'vcpu_id' */
void fill_mp_proc_entry(struct mp_proc_entry *mppe, int vcpu_id)
{
- mppe->type = ENTRY_TYPE_PROCESSOR;
- mppe->lapic_id = vcpu_id;
- mppe->lapic_version = 0x11;
- mppe->cpu_flags = CPU_FLAG_ENABLED;
- if (vcpu_id == 0)
- mppe->cpu_flags |= CPU_FLAG_BSP;
- mppe->cpu_signature = CPU_SIGNATURE;
- mppe->feature_flags = CPU_FEATURES;
+ mppe->type = ENTRY_TYPE_PROCESSOR;
+ mppe->lapic_id = vcpu_id + 1;
+ mppe->lapic_version = 0x11;
+ mppe->cpu_flags = CPU_FLAG_ENABLED;
+ if ( vcpu_id == 0 )
+ mppe->cpu_flags |= CPU_FLAG_BSP;
+ mppe->cpu_signature = CPU_SIGNATURE;
+ mppe->feature_flags = CPU_FEATURES;
}
/* fills in an MP bus entry of type 'type' and bus ID 'bus_id' */
void fill_mp_bus_entry(struct mp_bus_entry *mpbe, int bus_id, const char *type)
{
- int i;
+ int i;
- mpbe->type = ENTRY_TYPE_BUS;
- mpbe->bus_id = bus_id;
- for (i = 0; i < BUS_TYPE_LENGTH; ++i)
- mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
+ mpbe->type = ENTRY_TYPE_BUS;
+ mpbe->bus_id = bus_id;
+ for ( i = 0; i < BUS_TYPE_LENGTH; i++ )
+ mpbe->bus_type_str[i] = type[i]; /* FIXME length check? */
}
/* fills in an MP IOAPIC entry for IOAPIC 'ioapic_id' */
-void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie, int ioapic_id)
+void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie)
{
- mpie->type = ENTRY_TYPE_IOAPIC;
- mpie->ioapic_id = ioapic_id;
- mpie->ioapic_version = IOAPIC_VERSION;
- mpie->ioapic_flags = IOAPIC_FLAG_ENABLED;
- mpie->ioapic_addr = IOAPIC_BASE_ADDR;
+ mpie->type = ENTRY_TYPE_IOAPIC;
+ mpie->ioapic_id = IOAPIC_ID;
+ mpie->ioapic_version = IOAPIC_VERSION;
+ mpie->ioapic_flags = 1; /* enabled */
+ mpie->ioapic_addr = IOAPIC_BASE_ADDRESS;
}
/* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */
-void fill_mp_io_intr_entry(struct mp_io_intr_entry *mpiie,
- int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
+void fill_mp_io_intr_entry(
+ struct mp_io_intr_entry *mpiie,
+ int src_bus_id, int src_bus_irq, int ioapic_id, int dst_ioapic_intin)
{
- mpiie->type = ENTRY_TYPE_IO_INTR;
- mpiie->intr_type = INTR_TYPE_INT;
- mpiie->io_intr_flags = INTR_FLAGS;
- mpiie->src_bus_id = 0;
- mpiie->src_bus_irq = src_bus_irq;
- mpiie->dst_ioapic_id = ioapic_id;
- mpiie->dst_ioapic_intin = dst_ioapic_intin;
+ mpiie->type = ENTRY_TYPE_IO_INTR;
+ mpiie->intr_type = INTR_TYPE_INT;
+ mpiie->io_intr_flags = (PCI_ISA_IRQ_MASK & (1U<<src_bus_irq)) ? 0xf : 0x0;
+ mpiie->src_bus_id = src_bus_id;
+ mpiie->src_bus_irq = src_bus_irq;
+ mpiie->dst_ioapic_id = ioapic_id;
+ mpiie->dst_ioapic_intin = dst_ioapic_intin;
}
/* fill in the mp floating processor structure */
void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
{
- int i;
- uint8_t checksum;
-
-
- mpfps->signature[0] = '_';
- mpfps->signature[1] = 'M';
- mpfps->signature[2] = 'P';
- mpfps->signature[3] = '_';
-
- mpfps->mp_table = mpct;
- mpfps->length = 1;
- mpfps->revision = 4;
- mpfps->checksum = 0;
- for (i = 0; i < 5; ++i)
- mpfps->feature[i] = 0;
-
- /* compute the checksum for our new table */
- checksum = 0;
- for (i = 0; i < sizeof(struct mp_floating_pointer_struct); ++i)
- checksum += ((uint8_t *)(mpfps))[i];
- mpfps->checksum = -checksum;
+ int i;
+ uint8_t checksum;
+
+
+ mpfps->signature[0] = '_';
+ mpfps->signature[1] = 'M';
+ mpfps->signature[2] = 'P';
+ mpfps->signature[3] = '_';
+
+ mpfps->mp_table = mpct;
+ mpfps->length = 1;
+ mpfps->revision = 4;
+ mpfps->checksum = 0;
+ for (i = 0; i < 5; ++i)
+ mpfps->feature[i] = 0;
+
+ /* compute the checksum for our new table */
+ checksum = 0;
+ for ( i = 0; i < sizeof(struct mp_floating_pointer_struct); i++ )
+ checksum += ((uint8_t *)(mpfps))[i];
+ mpfps->checksum = -checksum;
}
@@ -340,88 +306,87 @@ void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct)
*/
void* get_mp_table_start(void)
{
- char *bios_mem;
- for (bios_mem = (char *)ROMBIOS_BEGIN;
- bios_mem != (char *)ROMBIOS_END;
- ++bios_mem)
- if (bios_mem[0] == '_' && bios_mem[1] == '_' &&
- bios_mem[2] == '_' && bios_mem[3] == 'H' &&
- bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
- bios_mem[6] == 'M' && bios_mem[7] == 'P')
- return bios_mem;
-
- return (void *)-1;
+ char *bios_mem;
+
+ for ( bios_mem = (char *)ROMBIOS_BEGIN;
+ bios_mem != (char *)ROMBIOS_END;
+ bios_mem++ )
+ {
+ if ( bios_mem[0] == '_' && bios_mem[1] == '_' &&
+ bios_mem[2] == '_' && bios_mem[3] == 'H' &&
+ bios_mem[4] == 'V' && bios_mem[5] == 'M' &&
+ bios_mem[6] == 'M' && bios_mem[7] == 'P' )
+ return bios_mem;
+ }
+
+ return NULL;
}
/* recalculate the new ROMBIOS checksum after adding MP tables */
void reset_bios_checksum(void)
{
- uint32_t i;
- uint8_t checksum;
-
- checksum = 0;
- for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
- checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
-
- *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
+ uint32_t i;
+ uint8_t checksum;
+
+ checksum = 0;
+ for (i = 0; i < ROMBIOS_MAXOFFSET; ++i)
+ checksum += ((uint8_t *)(ROMBIOS_BEGIN))[i];
+
+ *((uint8_t *)(ROMBIOS_BEGIN + ROMBIOS_MAXOFFSET)) = -checksum;
}
/* create_mp_tables - creates MP tables for the guest based upon config data */
void create_mp_tables(void)
{
- void *mp_table_base;
- char *p;
- struct mp_config_table *mp_config_table;
- int vcpu_nr;
- int i;
-
- vcpu_nr = get_vcpu_nr();
-
- puts("Creating MP tables ...\n");
-
- /* find the 'safe' place in ROMBIOS for the MP tables */
- mp_table_base = get_mp_table_start();
- if (mp_table_base == (void *)-1) {
- puts("Couldn't find start point for MP tables\n");
- return;
- }
- p = mp_table_base;
-
- fill_mp_config_table((struct mp_config_table *)p);
-
- /* save the location of the MP config table for a little later*/
- mp_config_table = (struct mp_config_table *)p;
- p += sizeof(struct mp_config_table);
-
- for (i = 0; i < vcpu_nr; ++i) {
- fill_mp_proc_entry((struct mp_proc_entry *)p, i);
- p += sizeof(struct mp_proc_entry);
- }
-
- fill_mp_bus_entry((struct mp_bus_entry *)p, 0, BUS_TYPE_STR_ISA);
- p += sizeof(struct mp_bus_entry);
-
- fill_mp_ioapic_entry((struct mp_ioapic_entry *)p, vcpu_nr);
- p += sizeof(struct mp_ioapic_entry);
-
- for (i = 0; i < INTR_MAX_NR; ++i) {
- fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
- i, vcpu_nr, i);
- p += sizeof(struct mp_io_intr_entry);
- }
-
- /* find the next 16-byte boundary to place the mp floating pointer */
- while ((unsigned long)p & 0xF)
- ++p;
-
- fill_mpfps((struct mp_floating_pointer_struct *)p,
- (uint32_t)mp_table_base);
-
- /* calculate the MP configuration table's checksum */
- fill_mp_config_table_checksum(mp_config_table);
-
- /* finally, recalculate the ROMBIOS checksum */
- reset_bios_checksum();
+ void *mp_table_base;
+ char *p;
+ int vcpu_nr, i, length;
+
+ vcpu_nr = get_vcpu_nr();
+
+ printf("Creating MP tables ...\n");
+
+ /* Find the 'safe' place in ROMBIOS for the MP tables. */
+ mp_table_base = get_mp_table_start();
+ if ( mp_table_base == NULL )
+ {
+ printf("Couldn't find start point for MP tables\n");
+ return;
+ }
+
+ p = mp_table_base + sizeof(struct mp_config_table);
+
+ for ( i = 0; i < vcpu_nr; i++ )
+ {
+ fill_mp_proc_entry((struct mp_proc_entry *)p, i);
+ p += sizeof(struct mp_proc_entry);
+ }
+
+ fill_mp_bus_entry((struct mp_bus_entry *)p, BUS_ID_ISA, BUS_TYPE_STR_ISA);
+ p += sizeof(struct mp_bus_entry);
+
+ fill_mp_ioapic_entry((struct mp_ioapic_entry *)p);
+ p += sizeof(struct mp_ioapic_entry);
+
+ for ( i = 0; i < 16; i++ )
+ {
+ if ( i == 2 ) continue; /* skip the slave PIC connection */
+ fill_mp_io_intr_entry((struct mp_io_intr_entry *)p,
+ BUS_ID_ISA, i, IOAPIC_ID, i);
+ p += sizeof(struct mp_io_intr_entry);
+ }
+
+ length = p - (char *)mp_table_base;
+
+ /* find the next 16-byte boundary to place the mp floating pointer */
+ while ( (unsigned long)p & 0xF )
+ p++;
+
+ fill_mpfps((struct mp_floating_pointer_struct *)p,
+ (uint32_t)mp_table_base);
+
+ fill_mp_config_table((struct mp_config_table *)mp_table_base, length);
+ reset_bios_checksum();
}
diff --git a/tools/firmware/hvmloader/pci_regs.h b/tools/firmware/hvmloader/pci_regs.h
new file mode 100644
index 0000000000..4309345f9a
--- /dev/null
+++ b/tools/firmware/hvmloader/pci_regs.h
@@ -0,0 +1,108 @@
+/*
+ * pci_regs.h
+ *
+ * PCI standard defines
+ * Copyright 1994, Drew Eckhardt
+ * Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ */
+
+#ifndef __HVMLOADER_PCI_REGS_H__
+#define __HVMLOADER_PCI_REGS_H__
+
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
+#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
+#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
+#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
+#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
+#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+#endif /* __HVMLOADER_PCI_REGS_H__ */
diff --git a/tools/firmware/hvmloader/smbios.c b/tools/firmware/hvmloader/smbios.c
index 57618b2098..df25999c3a 100644
--- a/tools/firmware/hvmloader/smbios.c
+++ b/tools/firmware/hvmloader/smbios.c
@@ -28,39 +28,31 @@
#include "util.h"
#include "hypercall.h"
-/* write SMBIOS tables starting at 'start', without writing more
- than 'max_size' bytes.
-
- Return the number of bytes written
-*/
static size_t
-write_smbios_tables(void *start, size_t max_size,
- uint32_t vcpus, uint64_t memsize,
- uint8_t uuid[16], char *xen_version,
- uint32_t xen_major_version, uint32_t xen_minor_version);
+write_smbios_tables(void *start,
+ uint32_t vcpus, uint64_t memsize,
+ uint8_t uuid[16], char *xen_version,
+ uint32_t xen_major_version, uint32_t xen_minor_version);
static void
get_cpu_manufacturer(char *buf, int len);
-static size_t
-smbios_table_size(uint32_t vcpus, const char *xen_version,
- const char *processor_manufacturer);
-static void *
+static void
smbios_entry_point_init(void *start,
- uint16_t max_structure_size,
- uint16_t structure_table_length,
- uint32_t structure_table_address,
- uint16_t number_of_structures);
+ uint16_t max_structure_size,
+ uint16_t structure_table_length,
+ uint32_t structure_table_address,
+ uint16_t number_of_structures);
static void *
smbios_type_0_init(void *start, const char *xen_version,
- uint32_t xen_major_version, uint32_t xen_minor_version);
+ uint32_t xen_major_version, uint32_t xen_minor_version);
static void *
smbios_type_1_init(void *start, const char *xen_version,
- uint8_t uuid[16]);
+ uint8_t uuid[16]);
static void *
smbios_type_3_init(void *start);
static void *
smbios_type_4_init(void *start, unsigned int cpu_number,
- char *cpu_manufacturer);
+ char *cpu_manufacturer);
static void *
smbios_type_16_init(void *start, uint32_t memory_size_mb);
static void *
@@ -71,109 +63,70 @@ static void *
smbios_type_20_init(void *start, uint32_t memory_size_mb);
static void *
smbios_type_32_init(void *start);
-void *
+static void *
smbios_type_127_init(void *start);
static void
get_cpu_manufacturer(char *buf, int len)
{
- char id[12];
- uint32_t eax = 0;
-
- cpuid(0, &eax, (uint32_t *)&id[0], (uint32_t *)&id[8], (uint32_t *)&id[4]);
-
- if (memcmp(id, "GenuineIntel", 12) == 0)
- strncpy(buf, "Intel", len);
- else if (memcmp(id, "AuthenticAMD", 12) == 0)
- strncpy(buf, "AMD", len);
- else
- strncpy(buf, "unknown", len);
-}
-
-
-/* Calculate the size of the SMBIOS structure table.
-*/
-static size_t
-smbios_table_size(uint32_t vcpus, const char *xen_version,
- const char *processor_manufacturer)
-{
- size_t size;
-
- /* first compute size without strings or terminating 0 bytes */
- size = sizeof(struct smbios_type_0) + sizeof(struct smbios_type_1) +
- sizeof(struct smbios_type_3) + sizeof(struct smbios_type_4)*vcpus +
- sizeof(struct smbios_type_16) + sizeof(struct smbios_type_17) +
- sizeof(struct smbios_type_19) + sizeof(struct smbios_type_20) +
- sizeof(struct smbios_type_32) + sizeof(struct smbios_type_127);
-
- /* 5 structures with no strings, 2 null bytes each */
- size += 10;
-
- /* Need to include 1 null byte per structure with strings (first
- terminating null byte comes from the string terminator of the
- last string). */
- size += 4 + vcpus;
-
- /* type 0: "Xen", xen_version, and release_date */
- size += strlen("Xen") + strlen(xen_version) + 2;
- /* type 1: "Xen", xen_version, "HVM domU", UUID as string for
- serial number */
- size += strlen("Xen") + strlen("HVM domU") + strlen(xen_version) +
- 36 + 4;
- /* type 3: "Xen" */
- size += strlen("Xen") + 1;
- /* type 4: socket designation ("CPU n"), processor_manufacturer */
- size += vcpus * (strlen("CPU n") + strlen(processor_manufacturer) + 2);
- /* Make room for two-digit CPU numbers if necessary -- doesn't handle
- vcpus > 99 */
- if (vcpus > 9)
- size += vcpus - 9;
- /* type 17: device locator string ("DIMM 1") */
- size += strlen("DIMM 1") + 1;
-
- return size;
+ char id[12];
+ uint32_t eax = 0;
+
+ cpuid(0, &eax, (uint32_t *)&id[0], (uint32_t *)&id[8],
+ (uint32_t *)&id[4]);
+
+ if (memcmp(id, "GenuineIntel", 12) == 0)
+ strncpy(buf, "Intel", len);
+ else if (memcmp(id, "AuthenticAMD", 12) == 0)
+ strncpy(buf, "AMD", len);
+ else
+ strncpy(buf, "unknown", len);
}
static size_t
-write_smbios_tables(void *start, size_t max_size,
- uint32_t vcpus, uint64_t memsize,
- uint8_t uuid[16], char *xen_version,
- uint32_t xen_major_version, uint32_t xen_minor_version)
+write_smbios_tables(void *start,
+ uint32_t vcpus, uint64_t memsize,
+ uint8_t uuid[16], char *xen_version,
+ uint32_t xen_major_version, uint32_t xen_minor_version)
{
- unsigned cpu_num;
- void *p = start;
- char cpu_manufacturer[15];
- size_t structure_table_length;
-
- get_cpu_manufacturer(cpu_manufacturer, 15);
-
-
- structure_table_length = smbios_table_size(vcpus, xen_version,
- cpu_manufacturer);
-
- if (structure_table_length + sizeof(struct smbios_entry_point) > max_size)
- return 0;
-
- p = smbios_entry_point_init(p, sizeof(struct smbios_type_4),
- structure_table_length,
- (uint32_t)start +
- sizeof(struct smbios_entry_point),
- 9 + vcpus);
-
- p = smbios_type_0_init(p, xen_version, xen_major_version,
- xen_minor_version);
- p = smbios_type_1_init(p, xen_version, uuid);
- p = smbios_type_3_init(p);
- for (cpu_num = 1; cpu_num <= vcpus; ++cpu_num)
- p = smbios_type_4_init(p, cpu_num, cpu_manufacturer);
- p = smbios_type_16_init(p, memsize);
- p = smbios_type_17_init(p, memsize);
- p = smbios_type_19_init(p, memsize);
- p = smbios_type_20_init(p, memsize);
- p = smbios_type_32_init(p);
- p = smbios_type_127_init(p);
-
- return (size_t)((char*)p - (char*)start);
+ unsigned cpu_num, nr_structs = 0, max_struct_size = 0;
+ char *p, *q;
+ char cpu_manufacturer[15];
+
+ get_cpu_manufacturer(cpu_manufacturer, 15);
+
+ p = (char *)start + sizeof(struct smbios_entry_point);
+
+#define do_struct(fn) do { \
+ q = (fn); \
+ nr_structs++; \
+ if ( (q - p) > max_struct_size ) \
+ max_struct_size = q - p; \
+ p = q; \
+} while (0)
+
+ do_struct(smbios_type_0_init(p, xen_version, xen_major_version,
+ xen_minor_version));
+ do_struct(smbios_type_1_init(p, xen_version, uuid));
+ do_struct(smbios_type_3_init(p));
+ for ( cpu_num = 1; cpu_num <= vcpus; cpu_num++ )
+ do_struct(smbios_type_4_init(p, cpu_num, cpu_manufacturer));
+ do_struct(smbios_type_16_init(p, memsize));
+ do_struct(smbios_type_17_init(p, memsize));
+ do_struct(smbios_type_19_init(p, memsize));
+ do_struct(smbios_type_20_init(p, memsize));
+ do_struct(smbios_type_32_init(p));
+ do_struct(smbios_type_127_init(p));
+
+#undef do_struct
+
+ smbios_entry_point_init(
+ start, max_struct_size,
+ (p - (char *)start) - sizeof(struct smbios_entry_point),
+ SMBIOS_PHYSICAL_ADDRESS + sizeof(struct smbios_entry_point),
+ nr_structs);
+
+ return (size_t)((char *)p - (char *)start);
}
/* This tries to figure out how much pseudo-physical memory (in MB)
@@ -189,424 +142,439 @@ write_smbios_tables(void *start, size_t max_size,
static uint64_t
get_memsize(void)
{
- struct e820entry *map = NULL;
- uint8_t num_entries = 0;
- uint64_t memsize = 0;
- uint8_t i;
-
- map = (struct e820entry *) (E820_MAP_PAGE + E820_MAP_OFFSET);
- num_entries = *((uint8_t *) (E820_MAP_PAGE + E820_MAP_NR_OFFSET));
-
- /* walk through e820map, ignoring any entries that aren't marked
- as usable or reserved. */
-
- for (i = 0; i < num_entries; i++) {
- if (map->type == E820_RAM || map->type == E820_RESERVED)
- memsize += map->size;
- map++;
- }
-
- /* Round up to the nearest MB. The user specifies domU
- pseudo-physical memory in megabytes, so not doing this
- could easily lead to reporting one less MB than the user
- specified. */
- if (memsize & ((1<<20)-1))
- memsize = (memsize >> 20) + 1;
- else
- memsize = (memsize >> 20);
-
- return memsize;
+ struct e820entry *map = NULL;
+ uint8_t num_entries = 0;
+ uint64_t memsize = 0;
+ uint8_t i;
+
+ map = (struct e820entry *) (E820_MAP_PAGE + E820_MAP_OFFSET);
+ num_entries = *((uint8_t *) (E820_MAP_PAGE + E820_MAP_NR_OFFSET));
+
+ /* walk through e820map, ignoring any entries that aren't marked
+ as usable or reserved. */
+
+ for ( i = 0; i < num_entries; i++ )
+ {
+ if (map->type == E820_RAM || map->type == E820_RESERVED)
+ memsize += map->size;
+ map++;
+ }
+
+ /* Round up to the nearest MB. The user specifies domU
+ pseudo-physical memory in megabytes, so not doing this
+ could easily lead to reporting one less MB than the user
+ specified. */
+ if ( memsize & ((1<<20)-1) )
+ memsize = (memsize >> 20) + 1;
+ else
+ memsize = (memsize >> 20);
+
+ return memsize;
}
void
hvm_write_smbios_tables(void)
{
- uint8_t uuid[16]; /* ** This will break if xen_domain_handle_t is
- not uint8_t[16]. ** */
- uint16_t xen_major_version, xen_minor_version;
- uint32_t xen_version;
- char xen_extra_version[XEN_EXTRAVERSION_LEN];
- /* guess conservatively on buffer length for Xen version string */
- char xen_version_str[80];
- /* temporary variables used to build up Xen version string */
- char *p = NULL; /* points to next point of insertion */
- unsigned len = 0; /* length of string already composed */
- char *tmp = NULL; /* holds result of itoa() */
- unsigned tmp_len; /* length of next string to add */
-
- hypercall_xen_version(XENVER_guest_handle, uuid);
-
- /* xen_version major and minor */
- xen_version = hypercall_xen_version(XENVER_version, NULL);
- xen_major_version = (uint16_t) (xen_version >> 16);
- xen_minor_version = (uint16_t) xen_version;
-
- hypercall_xen_version(XENVER_extraversion, xen_extra_version);
-
- /* build up human-readable Xen version string */
- p = xen_version_str;
- len = 0;
-
- itoa(tmp, xen_major_version);
- tmp_len = strlen(tmp);
- len += tmp_len;
- if (len >= sizeof(xen_version_str))
- goto error_out;
- strcpy(p, tmp);
- p += tmp_len;
-
- len++;
- if (len >= sizeof(xen_version_str))
- goto error_out;
- *p = '.';
- p++;
-
- itoa(tmp, xen_minor_version);
- tmp_len = strlen(tmp);
- len += tmp_len;
- if (len >= sizeof(xen_version_str))
- goto error_out;
- strcpy(p, tmp);
- p += tmp_len;
-
- tmp_len = strlen(xen_extra_version);
- len += tmp_len;
- if (len >= sizeof(xen_version_str))
- goto error_out;
- strcpy(p, xen_extra_version);
- p += tmp_len;
-
- xen_version_str[sizeof(xen_version_str)-1] = '\0';
-
- write_smbios_tables((void *) SMBIOS_PHYSICAL_ADDRESS,
- SMBIOS_SIZE_LIMIT, get_vcpu_nr(), get_memsize(),
- uuid, xen_version_str,
- xen_major_version, xen_minor_version);
- return;
+ uint8_t uuid[16]; /* ** This will break if xen_domain_handle_t is
+ not uint8_t[16]. ** */
+ uint16_t xen_major_version, xen_minor_version;
+ uint32_t xen_version;
+ char xen_extra_version[XEN_EXTRAVERSION_LEN];
+ /* guess conservatively on buffer length for Xen version string */
+ char xen_version_str[80];
+ /* temporary variables used to build up Xen version string */
+ char *p = NULL; /* points to next point of insertion */
+ unsigned len = 0; /* length of string already composed */
+ char *tmp = NULL; /* holds result of itoa() */
+ unsigned tmp_len; /* length of next string to add */
+
+ hypercall_xen_version(XENVER_guest_handle, uuid);
+
+ /* xen_version major and minor */
+ xen_version = hypercall_xen_version(XENVER_version, NULL);
+ xen_major_version = (uint16_t) (xen_version >> 16);
+ xen_minor_version = (uint16_t) xen_version;
+
+ hypercall_xen_version(XENVER_extraversion, xen_extra_version);
+
+ /* build up human-readable Xen version string */
+ p = xen_version_str;
+ len = 0;
+
+ itoa(tmp, xen_major_version);
+ tmp_len = strlen(tmp);
+ len += tmp_len;
+ if ( len >= sizeof(xen_version_str) )
+ goto error_out;
+ strcpy(p, tmp);
+ p += tmp_len;
+
+ len++;
+ if ( len >= sizeof(xen_version_str) )
+ goto error_out;
+ *p = '.';
+ p++;
+
+ itoa(tmp, xen_minor_version);
+ tmp_len = strlen(tmp);
+ len += tmp_len;
+ if ( len >= sizeof(xen_version_str) )
+ goto error_out;
+ strcpy(p, tmp);
+ p += tmp_len;
+
+ tmp_len = strlen(xen_extra_version);
+ len += tmp_len;
+ if ( len >= sizeof(xen_version_str) )
+ goto error_out;
+ strcpy(p, xen_extra_version);
+ p += tmp_len;
+
+ xen_version_str[sizeof(xen_version_str)-1] = '\0';
+
+ /* NB. 0xC0000 is a safe large memory area for scratch. */
+ len = write_smbios_tables((void *)0xC0000,
+ get_vcpu_nr(), get_memsize(),
+ uuid, xen_version_str,
+ xen_major_version, xen_minor_version);
+ if ( len > SMBIOS_SIZE_LIMIT )
+ goto error_out;
+ /* Okay, not too large: copy out of scratch to final location. */
+ memcpy((void *)SMBIOS_PHYSICAL_ADDRESS, (void *)0xC0000, len);
+
+ return;
error_out:
- puts("Could not write SMBIOS tables, error in hvmloader.c:"
- "hvm_write_smbios_tables()\n");
+ printf("Could not write SMBIOS tables, error in hvmloader.c:"
+ "hvm_write_smbios_tables()\n");
}
-static void *
+static void
smbios_entry_point_init(void *start,
- uint16_t max_structure_size,
- uint16_t structure_table_length,
- uint32_t structure_table_address,
- uint16_t number_of_structures)
+ uint16_t max_structure_size,
+ uint16_t structure_table_length,
+ uint32_t structure_table_address,
+ uint16_t number_of_structures)
{
- uint8_t sum;
- int i;
- struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
-
- strncpy(ep->anchor_string, "_SM_", 4);
- ep->length = 0x1f;
- ep->smbios_major_version = 2;
- ep->smbios_minor_version = 4;
- ep->max_structure_size = max_structure_size;
- ep->entry_point_revision = 0;
- memset(ep->formatted_area, 0, 5);
- strncpy(ep->intermediate_anchor_string, "_DMI_", 5);
+ uint8_t sum;
+ int i;
+ struct smbios_entry_point *ep = (struct smbios_entry_point *)start;
+
+ strncpy(ep->anchor_string, "_SM_", 4);
+ ep->length = 0x1f;
+ ep->smbios_major_version = 2;
+ ep->smbios_minor_version = 4;
+ ep->max_structure_size = max_structure_size;
+ ep->entry_point_revision = 0;
+ memset(ep->formatted_area, 0, 5);
+ strncpy(ep->intermediate_anchor_string, "_DMI_", 5);
- ep->structure_table_length = structure_table_length;
- ep->structure_table_address = structure_table_address;
- ep->number_of_structures = number_of_structures;
- ep->smbios_bcd_revision = 0x24;
+ ep->structure_table_length = structure_table_length;
+ ep->structure_table_address = structure_table_address;
+ ep->number_of_structures = number_of_structures;
+ ep->smbios_bcd_revision = 0x24;
- ep->checksum = 0;
- ep->intermediate_checksum = 0;
+ ep->checksum = 0;
+ ep->intermediate_checksum = 0;
- sum = 0;
- for (i = 0; i < 0x10; ++i)
- sum += ((int8_t *)start)[i];
- ep->checksum = -sum;
-
- sum = 0;
- for (i = 0x10; i < ep->length; ++i)
- sum += ((int8_t *)start)[i];
- ep->intermediate_checksum = -sum;
-
- return (char *)start + sizeof(struct smbios_entry_point);
+ sum = 0;
+ for ( i = 0; i < 0x10; i++ )
+ sum += ((int8_t *)start)[i];
+ ep->checksum = -sum;
+
+ sum = 0;
+ for ( i = 0x10; i < ep->length; i++ )
+ sum += ((int8_t *)start)[i];
+ ep->intermediate_checksum = -sum;
}
/* Type 0 -- BIOS Information */
static void *
smbios_type_0_init(void *start, const char *xen_version,
- uint32_t xen_major_version, uint32_t xen_minor_version)
+ uint32_t xen_major_version, uint32_t xen_minor_version)
{
- struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
- p->header.type = 0;
- p->header.length = sizeof(struct smbios_type_0);
- p->header.handle = 0;
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
- p->vendor_str = 1;
- p->version_str = 2;
- p->starting_address_segment = 0xe800;
- p->release_date_str = 0;
- p->rom_size = 0;
+ p->vendor_str = 1;
+ p->version_str = 2;
+ p->starting_address_segment = 0xe800;
+ p->release_date_str = 0;
+ p->rom_size = 0;
- memset(p->characteristics, 0, 8);
- p->characteristics[7] = 0x08; /* BIOS characteristics not supported */
- p->characteristics_extension_bytes[0] = 0;
- p->characteristics_extension_bytes[1] = 0;
+ memset(p->characteristics, 0, 8);
+ p->characteristics[7] = 0x08; /* BIOS characteristics not supported */
+ p->characteristics_extension_bytes[0] = 0;
+ p->characteristics_extension_bytes[1] = 0;
- p->major_release = (uint8_t) xen_major_version;
- p->minor_release = (uint8_t) xen_minor_version;
- p->embedded_controller_major = 0xff;
- p->embedded_controller_minor = 0xff;
-
- start += sizeof(struct smbios_type_0);
- strcpy((char *)start, "Xen");
- start += strlen("Xen") + 1;
- strcpy((char *)start, xen_version);
- start += strlen(xen_version) + 1;
-
- *((uint8_t *)start) = 0;
- return start + 1;
+ p->major_release = (uint8_t) xen_major_version;
+ p->minor_release = (uint8_t) xen_minor_version;
+ p->embedded_controller_major = 0xff;
+ p->embedded_controller_minor = 0xff;
+
+ start += sizeof(struct smbios_type_0);
+ strcpy((char *)start, "Xen");
+ start += strlen("Xen") + 1;
+ strcpy((char *)start, xen_version);
+ start += strlen(xen_version) + 1;
+
+ *((uint8_t *)start) = 0;
+ return start + 1;
}
/* Type 1 -- System Information */
static void *
smbios_type_1_init(void *start, const char *xen_version,
- uint8_t uuid[16])
+ uint8_t uuid[16])
{
- char uuid_str[37];
- struct smbios_type_1 *p = (struct smbios_type_1 *)start;
- p->header.type = 1;
- p->header.length = sizeof(struct smbios_type_1);
- p->header.handle = 0x100;
-
- p->manufacturer_str = 1;
- p->product_name_str = 2;
- p->version_str = 3;
- p->serial_number_str = 4;
+ char uuid_str[37];
+ struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+ p->header.type = 1;
+ p->header.length = sizeof(struct smbios_type_1);
+ p->header.handle = 0x100;
+
+ p->manufacturer_str = 1;
+ p->product_name_str = 2;
+ p->version_str = 3;
+ p->serial_number_str = 4;
- memcpy(p->uuid, uuid, 16);
+ memcpy(p->uuid, uuid, 16);
- p->wake_up_type = 0x06; /* power switch */
- p->sku_str = 0;
- p->family_str = 0;
+ p->wake_up_type = 0x06; /* power switch */
+ p->sku_str = 0;
+ p->family_str = 0;
- start += sizeof(struct smbios_type_1);
+ start += sizeof(struct smbios_type_1);
- strcpy((char *)start, "Xen");
- start += strlen("Xen") + 1;
- strcpy((char *)start, "HVM domU");
- start += strlen("HVM domU") + 1;
- strcpy((char *)start, xen_version);
- start += strlen(xen_version) + 1;
- uuid_to_string(uuid_str, uuid);
- strcpy((char *)start, uuid_str);
- start += strlen(uuid_str) + 1;
- *((uint8_t *)start) = 0;
+ strcpy((char *)start, "Xen");
+ start += strlen("Xen") + 1;
+ strcpy((char *)start, "HVM domU");
+ start += strlen("HVM domU") + 1;
+ strcpy((char *)start, xen_version);
+ start += strlen(xen_version) + 1;
+ uuid_to_string(uuid_str, uuid);
+ strcpy((char *)start, uuid_str);
+ start += strlen(uuid_str) + 1;
+ *((uint8_t *)start) = 0;
- return start+1;
+ return start+1;
}
/* Type 3 -- System Enclosure */
static void *
smbios_type_3_init(void *start)
{
- struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+ struct smbios_type_3 *p = (struct smbios_type_3 *)start;
- p->header.type = 3;
- p->header.length = sizeof(struct smbios_type_3);
- p->header.handle = 0x300;
-
- p->manufacturer_str = 1;
- p->type = 0x01; /* other */
- p->version_str = 0;
- p->serial_number_str = 0;
- p->asset_tag_str = 0;
- p->boot_up_state = 0x03; /* safe */
- p->power_supply_state = 0x03; /* safe */
- p->thermal_state = 0x03; /* safe */
- p->security_status = 0x02; /* unknown */
-
- start += sizeof(struct smbios_type_3);
+ p->header.type = 3;
+ p->header.length = sizeof(struct smbios_type_3);
+ p->header.handle = 0x300;
+
+ p->manufacturer_str = 1;
+ p->type = 0x01; /* other */
+ p->version_str = 0;
+ p->serial_number_str = 0;
+ p->asset_tag_str = 0;
+ p->boot_up_state = 0x03; /* safe */
+ p->power_supply_state = 0x03; /* safe */
+ p->thermal_state = 0x03; /* safe */
+ p->security_status = 0x02; /* unknown */
+
+ start += sizeof(struct smbios_type_3);
- strcpy((char *)start, "Xen");
- start += strlen("Xen") + 1;
- *((uint8_t *)start) = 0;
- return start+1;
+ strcpy((char *)start, "Xen");
+ start += strlen("Xen") + 1;
+ *((uint8_t *)start) = 0;
+ return start+1;
}
/* Type 4 -- Processor Information */
static void *
smbios_type_4_init(void *start, unsigned int cpu_number, char *cpu_manufacturer)
{
- char buf[80];
- struct smbios_type_4 *p = (struct smbios_type_4 *)start;
- uint32_t eax, ebx, ecx, edx;
+ char buf[80];
+ struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+ uint32_t eax, ebx, ecx, edx;
- p->header.type = 4;
- p->header.length = sizeof(struct smbios_type_4);
- p->header.handle = 0x400 + cpu_number;
+ p->header.type = 4;
+ p->header.length = sizeof(struct smbios_type_4);
+ p->header.handle = 0x400 + cpu_number;
- p->socket_designation_str = 1;
- p->processor_type = 0x03; /* CPU */
- p->processor_family = 0x01; /* other */
- p->manufacturer_str = 2;
+ p->socket_designation_str = 1;
+ p->processor_type = 0x03; /* CPU */
+ p->processor_family = 0x01; /* other */
+ p->manufacturer_str = 2;
- cpuid(1, &eax, &ebx, &ecx, &edx);
+ cpuid(1, &eax, &ebx, &ecx, &edx);
- p->cpuid[0] = eax;
- p->cpuid[1] = edx;
+ p->cpuid[0] = eax;
+ p->cpuid[1] = edx;
- p->version_str = 0;
- p->voltage = 0;
- p->external_clock = 0;
+ p->version_str = 0;
+ p->voltage = 0;
+ p->external_clock = 0;
- p->max_speed = 0; /* unknown */
- p->current_speed = 0; /* unknown */
+ p->max_speed = 0; /* unknown */
+ p->current_speed = 0; /* unknown */
- p->status = 0x41; /* socket populated, CPU enabled */
- p->upgrade = 0x01; /* other */
+ p->status = 0x41; /* socket populated, CPU enabled */
+ p->upgrade = 0x01; /* other */
- start += sizeof(struct smbios_type_4);
+ start += sizeof(struct smbios_type_4);
- strncpy(buf, "CPU ", sizeof(buf));
- if ((sizeof(buf) - strlen("CPU ")) >= 3)
- itoa(buf + strlen("CPU "), cpu_number);
+ strncpy(buf, "CPU ", sizeof(buf));
+ if ( (sizeof(buf) - strlen("CPU ")) >= 3 )
+ itoa(buf + strlen("CPU "), cpu_number);
- strcpy((char *)start, buf);
- start += strlen(buf) + 1;
+ strcpy((char *)start, buf);
+ start += strlen(buf) + 1;
- strcpy((char *)start, cpu_manufacturer);
- start += strlen(buf) + 1;
+ strcpy((char *)start, cpu_manufacturer);
+ start += strlen(cpu_manufacturer) + 1;
- *((uint8_t *)start) = 0;
- return start+1;
+ *((uint8_t *)start) = 0;
+ return start+1;
}
/* Type 16 -- Physical Memory Array */
static void *
smbios_type_16_init(void *start, uint32_t memsize)
{
- struct smbios_type_16 *p = (struct smbios_type_16*)start;
+ struct smbios_type_16 *p = (struct smbios_type_16*)start;
- p->header.type = 16;
- p->header.handle = 0x1000;
- p->header.length = sizeof(struct smbios_type_16);
+ p->header.type = 16;
+ p->header.handle = 0x1000;
+ p->header.length = sizeof(struct smbios_type_16);
- p->location = 0x01; /* other */
- p->use = 0x03; /* system memory */
- p->error_correction = 0x01; /* other */
- p->maximum_capacity = memsize * 1024;
- p->memory_error_information_handle = 0xfffe; /* none provided */
- p->number_of_memory_devices = 1;
-
- start += sizeof(struct smbios_type_16);
- *((uint16_t *)start) = 0;
- return start + 2;
+ p->location = 0x01; /* other */
+ p->use = 0x03; /* system memory */
+ p->error_correction = 0x01; /* other */
+ p->maximum_capacity = memsize * 1024;
+ p->memory_error_information_handle = 0xfffe; /* none provided */
+ p->number_of_memory_devices = 1;
+
+ start += sizeof(struct smbios_type_16);
+ *((uint16_t *)start) = 0;
+ return start + 2;
}
/* Type 17 -- Memory Device */
static void *
smbios_type_17_init(void *start, uint32_t memory_size_mb)
{
- struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+ struct smbios_type_17 *p = (struct smbios_type_17 *)start;
- p->header.type = 17;
- p->header.length = sizeof(struct smbios_type_17);
- p->header.handle = 0x1100;
-
- p->physical_memory_array_handle = 0x1000;
- p->total_width = 64;
- p->data_width = 64;
- /* truncate memory_size_mb to 16 bits and clear most significant
- bit [indicates size in MB] */
- p->size = (uint16_t) memory_size_mb & 0x7fff;
- p->form_factor = 0x09; /* DIMM */
- p->device_set = 0;
- p->device_locator_str = 1;
- p->bank_locator_str = 0;
- p->memory_type = 0x07; /* RAM */
- p->type_detail = 0;
-
- start += sizeof(struct smbios_type_17);
- strcpy((char *)start, "DIMM 1");
- start += strlen("DIMM 1") + 1;
- *((uint8_t *)start) = 0;
-
- return start+1;
+ p->header.type = 17;
+ p->header.length = sizeof(struct smbios_type_17);
+ p->header.handle = 0x1100;
+
+ p->physical_memory_array_handle = 0x1000;
+ p->total_width = 64;
+ p->data_width = 64;
+ /* truncate memory_size_mb to 16 bits and clear most significant
+ bit [indicates size in MB] */
+ p->size = (uint16_t) memory_size_mb & 0x7fff;
+ p->form_factor = 0x09; /* DIMM */
+ p->device_set = 0;
+ p->device_locator_str = 1;
+ p->bank_locator_str = 0;
+ p->memory_type = 0x07; /* RAM */
+ p->type_detail = 0;
+
+ start += sizeof(struct smbios_type_17);
+ strcpy((char *)start, "DIMM 1");
+ start += strlen("DIMM 1") + 1;
+ *((uint8_t *)start) = 0;
+
+ return start+1;
}
/* Type 19 -- Memory Array Mapped Address */
static void *
smbios_type_19_init(void *start, uint32_t memory_size_mb)
{
- struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+ struct smbios_type_19 *p = (struct smbios_type_19 *)start;
- p->header.type = 19;
- p->header.length = sizeof(struct smbios_type_19);
- p->header.handle = 0x1300;
-
- p->starting_address = 0;
- p->ending_address = (memory_size_mb-1) * 1024;
- p->memory_array_handle = 0x1000;
- p->partition_width = 1;
-
- start += sizeof(struct smbios_type_19);
- *((uint16_t *)start) = 0;
- return start + 2;
+ p->header.type = 19;
+ p->header.length = sizeof(struct smbios_type_19);
+ p->header.handle = 0x1300;
+
+ p->starting_address = 0;
+ p->ending_address = (memory_size_mb-1) * 1024;
+ p->memory_array_handle = 0x1000;
+ p->partition_width = 1;
+
+ start += sizeof(struct smbios_type_19);
+ *((uint16_t *)start) = 0;
+ return start + 2;
}
/* Type 20 -- Memory Device Mapped Address */
static void *
smbios_type_20_init(void *start, uint32_t memory_size_mb)
{
- struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+ struct smbios_type_20 *p = (struct smbios_type_20 *)start;
- p->header.type = 20;
- p->header.length = sizeof(struct smbios_type_20);
- p->header.handle = 0x1400;
+ p->header.type = 20;
+ p->header.length = sizeof(struct smbios_type_20);
+ p->header.handle = 0x1400;
- p->starting_address = 0;
- p->ending_address = (memory_size_mb-1)*1024;
- p->memory_device_handle = 0x1100;
- p->memory_array_mapped_address_handle = 0x1300;
- p->partition_row_position = 1;
- p->interleave_position = 0;
- p->interleaved_data_depth = 0;
+ p->starting_address = 0;
+ p->ending_address = (memory_size_mb-1)*1024;
+ p->memory_device_handle = 0x1100;
+ p->memory_array_mapped_address_handle = 0x1300;
+ p->partition_row_position = 1;
+ p->interleave_position = 0;
+ p->interleaved_data_depth = 0;
- start += sizeof(struct smbios_type_20);
+ start += sizeof(struct smbios_type_20);
- *((uint16_t *)start) = 0;
- return start+2;
+ *((uint16_t *)start) = 0;
+ return start+2;
}
/* Type 32 -- System Boot Information */
static void *
smbios_type_32_init(void *start)
{
- struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+ struct smbios_type_32 *p = (struct smbios_type_32 *)start;
- p->header.type = 32;
- p->header.length = sizeof(struct smbios_type_32);
- p->header.handle = 0x2000;
- memset(p->reserved, 0, 6);
- p->boot_status = 0; /* no errors detected */
+ p->header.type = 32;
+ p->header.length = sizeof(struct smbios_type_32);
+ p->header.handle = 0x2000;
+ memset(p->reserved, 0, 6);
+ p->boot_status = 0; /* no errors detected */
- start += sizeof(struct smbios_type_32);
- *((uint16_t *)start) = 0;
- return start+2;
+ start += sizeof(struct smbios_type_32);
+ *((uint16_t *)start) = 0;
+ return start+2;
}
/* Type 127 -- End of Table */
-void *
+static void *
smbios_type_127_init(void *start)
{
- struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+ struct smbios_type_127 *p = (struct smbios_type_127 *)start;
- p->header.type = 127;
- p->header.length = sizeof(struct smbios_type_127);
- p->header.handle = 0x7f00;
+ p->header.type = 127;
+ p->header.length = sizeof(struct smbios_type_127);
+ p->header.handle = 0x7f00;
- start += sizeof(struct smbios_type_127);
- *((uint16_t *)start) = 0;
- return start + 2;
+ start += sizeof(struct smbios_type_127);
+ *((uint16_t *)start) = 0;
+ return start + 2;
}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c
index 2ce5367fb9..79c9578d13 100644
--- a/tools/firmware/hvmloader/util.c
+++ b/tools/firmware/hvmloader/util.c
@@ -18,160 +18,196 @@
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
-#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+#include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
#include "util.h"
+#include "config.h"
#include <stdint.h>
+#include <xenctrl.h>
+#include <xen/hvm/hvm_info_table.h>
+
+void outb(uint16_t addr, uint8_t val)
+{
+ __asm__ __volatile__ ( "outb %%al, %%dx" :: "d"(addr), "a"(val) );
+}
void outw(uint16_t addr, uint16_t val)
{
- __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val));
+ __asm__ __volatile__ ( "outw %%ax, %%dx" :: "d"(addr), "a"(val) );
}
-void outb(uint16_t addr, uint8_t val)
+void outl(uint16_t addr, uint32_t val)
{
- __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val));
+ __asm__ __volatile__ ( "outl %%eax, %%dx" :: "d"(addr), "a"(val) );
}
uint8_t inb(uint16_t addr)
{
- uint8_t val;
- __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr));
- return val;
+ uint8_t val;
+ __asm__ __volatile__ ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) );
+ return val;
+}
+
+uint16_t inw(uint16_t addr)
+{
+ uint16_t val;
+ __asm__ __volatile__ ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) );
+ return val;
+}
+
+uint32_t inl(uint16_t addr)
+{
+ uint32_t val;
+ __asm__ __volatile__ ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) );
+ return val;
}
char *itoa(char *a, unsigned int i)
{
- unsigned int _i = i, x = 0;
+ unsigned int _i = i, x = 0;
- do {
- x++;
- _i /= 10;
- } while (_i != 0);
+ do {
+ x++;
+ _i /= 10;
+ } while ( _i != 0 );
- a += x;
- *a-- = '\0';
+ a += x;
+ *a-- = '\0';
- do {
- *a-- = (i % 10) + '0';
- i /= 10;
- } while (i != 0);
+ do {
+ *a-- = (i % 10) + '0';
+ i /= 10;
+ } while ( i != 0 );
- return a + 1;
+ return a + 1;
}
int strcmp(const char *cs, const char *ct)
{
- signed char res;
+ signed char res;
- while (((res = *cs - *ct++) == 0) && (*cs++ != '\0'))
- continue;
+ while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
+ continue;
- return res;
+ return res;
}
void *memcpy(void *dest, const void *src, unsigned n)
{
- int t0, t1, t2;
-
- __asm__ __volatile__(
- "cld\n"
- "rep; movsl\n"
- "testb $2,%b4\n"
- "je 1f\n"
- "movsw\n"
- "1: testb $1,%b4\n"
- "je 2f\n"
- "movsb\n"
- "2:"
- : "=&c" (t0), "=&D" (t1), "=&S" (t2)
- : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
- : "memory"
- );
- return dest;
+ int t0, t1, t2;
+
+ __asm__ __volatile__ (
+ "cld\n"
+ "rep; movsl\n"
+ "testb $2,%b4\n"
+ "je 1f\n"
+ "movsw\n"
+ "1: testb $1,%b4\n"
+ "je 2f\n"
+ "movsb\n"
+ "2:"
+ : "=&c" (t0), "=&D" (t1), "=&S" (t2)
+ : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
+ : "memory" );
+ return dest;
}
-void puts(const char *s)
+void *memmove(void *dest, const void *src, unsigned n)
{
- while (*s)
- outb(0xE9, *s++);
+ if ( (long)dest > (long)src )
+ {
+ n--;
+ while ( n > 0 )
+ {
+ ((char *)dest)[n] = ((char *)src)[n];
+ n--;
+ }
+ }
+ else
+ {
+ memcpy(dest, src, n);
+ }
+ return dest;
}
char *
strcpy(char *dest, const char *src)
{
- char *p = dest;
- while (*src)
- *p++ = *src++;
- *p = 0;
- return dest;
+ char *p = dest;
+ while ( *src )
+ *p++ = *src++;
+ *p = 0;
+ return dest;
}
char *
strncpy(char *dest, const char *src, unsigned n)
{
- int i = 0;
- char *p = dest;
-
- /* write non-NUL characters from src into dest until we run
- out of room in dest or encounter a NUL in src */
- while (i < n && *src) {
- *p++ = *src++;
- ++i;
- }
-
- /* pad remaining bytes of dest with NUL bytes */
- while (i < n) {
- *p++ = 0;
- ++i;
- }
-
- return dest;
+ int i = 0;
+ char *p = dest;
+
+ /* write non-NUL characters from src into dest until we run
+ out of room in dest or encounter a NUL in src */
+ while ( (i < n) && *src )
+ {
+ *p++ = *src++;
+ i++;
+ }
+
+ /* pad remaining bytes of dest with NUL bytes */
+ while ( i < n )
+ {
+ *p++ = 0;
+ i++;
+ }
+
+ return dest;
}
unsigned
strlen(const char *s)
{
- int i = 0;
- while (*s++)
- ++i;
- return i;
+ int i = 0;
+ while ( *s++ )
+ i++;
+ return i;
}
void *
memset(void *s, int c, unsigned n)
{
- uint8_t b = (uint8_t) c;
- uint8_t *p = (uint8_t *)s;
- int i;
- for (i = 0; i < n; ++i)
- *p++ = b;
- return s;
+ uint8_t b = (uint8_t) c;
+ uint8_t *p = (uint8_t *)s;
+ int i;
+ for ( i = 0; i < n; i++ )
+ *p++ = b;
+ return s;
}
int
memcmp(const void *s1, const void *s2, unsigned n)
{
- unsigned i;
- uint8_t *p1 = (uint8_t *) s1;
- uint8_t *p2 = (uint8_t *) s2;
-
- for (i = 0; i < n; ++i) {
- if (p1[i] < p2[i])
- return -1;
- else if (p1[i] > p2[i])
- return 1;
- }
-
- return 0;
+ unsigned i;
+ uint8_t *p1 = (uint8_t *) s1;
+ uint8_t *p2 = (uint8_t *) s2;
+
+ for ( i = 0; i < n; i++ )
+ {
+ if ( p1[i] < p2[i] )
+ return -1;
+ else if ( p1[i] > p2[i] )
+ return 1;
+ }
+
+ return 0;
}
void
cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
- __asm__ __volatile__(
- "cpuid"
- : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
- : "0" (idx) );
+ __asm__ __volatile__ (
+ "cpuid"
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (idx) );
}
/* Write a two-character hex representation of 'byte' to digits[].
@@ -179,18 +215,18 @@ cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
void
byte_to_hex(char *digits, uint8_t byte)
{
- uint8_t nybbel = byte >> 4;
-
- if (nybbel > 9)
- digits[0] = 'a' + nybbel-10;
- else
- digits[0] = '0' + nybbel;
-
- nybbel = byte & 0x0f;
- if (nybbel > 9)
- digits[1] = 'a' + nybbel-10;
- else
- digits[1] = '0' + nybbel;
+ uint8_t nybbel = byte >> 4;
+
+ if ( nybbel > 9 )
+ digits[0] = 'a' + nybbel-10;
+ else
+ digits[0] = '0' + nybbel;
+
+ nybbel = byte & 0x0f;
+ if ( nybbel > 9 )
+ digits[1] = 'a' + nybbel-10;
+ else
+ digits[1] = '0' + nybbel;
}
/* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
@@ -200,31 +236,326 @@ byte_to_hex(char *digits, uint8_t byte)
void
uuid_to_string(char *dest, uint8_t *uuid)
{
- int i = 0;
- char *p = dest;
-
- for (i = 0; i < 4; ++i) {
- byte_to_hex(p, uuid[i]);
- p += 2;
- }
- *p++ = '-';
- for (i = 4; i < 6; ++i) {
- byte_to_hex(p, uuid[i]);
- p += 2;
- }
- *p++ = '-';
- for (i = 6; i < 8; ++i) {
- byte_to_hex(p, uuid[i]);
- p += 2;
- }
- *p++ = '-';
- for (i = 8; i < 10; ++i) {
- byte_to_hex(p, uuid[i]);
- p += 2;
- }
- *p++ = '-';
- for (i = 10; i < 16; ++i) {
- byte_to_hex(p, uuid[i]);
- p += 2;
- }
+ int i = 0;
+ char *p = dest;
+
+ for ( i = 0; i < 4; i++ )
+ {
+ byte_to_hex(p, uuid[i]);
+ p += 2;
+ }
+ *p++ = '-';
+ for ( i = 4; i < 6; i++ )
+ {
+ byte_to_hex(p, uuid[i]);
+ p += 2;
+ }
+ *p++ = '-';
+ for ( i = 6; i < 8; i++ )
+ {
+ byte_to_hex(p, uuid[i]);
+ p += 2;
+ }
+ *p++ = '-';
+ for ( i = 8; i < 10; i++ )
+ {
+ byte_to_hex(p, uuid[i]);
+ p += 2;
+ }
+ *p++ = '-';
+ for ( i = 10; i < 16; i++ )
+ {
+ byte_to_hex(p, uuid[i]);
+ p += 2;
+ }
+ *p = '\0';
+}
+
+#include <xen/hvm/e820.h>
+#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
+#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
+uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask)
+{
+ uint64_t addr = 0;
+ int c = *E820_MAP_NR - 1;
+ struct e820entry *e820entry = (struct e820entry *)E820_MAP;
+
+ while ( c >= 0 )
+ {
+ if ( (e820entry[c].type == E820_RAM) &&
+ ((e820entry[c].addr & (~mask)) == 0) &&
+ (e820entry[c].size >= size) )
+ {
+ addr = e820entry[c].addr;
+ if ( e820entry[c].size != size )
+ {
+ (*E820_MAP_NR)++;
+ memmove(&e820entry[c+1],
+ &e820entry[c],
+ (*E820_MAP_NR - c) *
+ sizeof(struct e820entry));
+ e820entry[c].size -= size;
+ addr += e820entry[c].size;
+ c++;
+ }
+ e820entry[c].addr = addr;
+ e820entry[c].size = size;
+ e820entry[c].type = type;
+ break;
+ }
+ c--;
+ }
+ return addr;
+}
+
+uint32_t ioapic_read(uint32_t reg)
+{
+ *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
+ return *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
+}
+
+void ioapic_write(uint32_t reg, uint32_t val)
+{
+ *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
+ *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = val;
+}
+
+uint32_t lapic_read(uint32_t reg)
+{
+ return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
+}
+
+void lapic_write(uint32_t reg, uint32_t val)
+{
+ *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
+}
+
+#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
+ (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
+
+uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
+{
+ outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
+
+ switch ( len )
+ {
+ case 1: return inb(0xcfc + (reg & 3));
+ case 2: return inw(0xcfc + (reg & 2));
+ }
+
+ return inl(0xcfc);
+}
+
+void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
+{
+ outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
+
+ switch ( len )
+ {
+ case 1: outb(0xcfc + (reg & 3), val); break;
+ case 2: outw(0xcfc + (reg & 2), val); break;
+ case 4: outl(0xcfc, val); break;
+ }
+}
+
+static char *printnum(char *p, unsigned long num, int base)
+{
+ unsigned long n;
+
+ if ( (n = num/base) > 0 )
+ p = printnum(p, n, base);
+ *p++ = "0123456789abcdef"[(int)(num % base)];
+ *p = '\0';
+ return p;
+}
+
+static void _doprint(void (*put)(char), char const *fmt, va_list ap)
+{
+ register char *str, c;
+ int lflag, zflag, nflag;
+ char buffer[17];
+ unsigned value;
+ int i, slen, pad;
+
+ for ( ; *fmt != '\0'; fmt++ )
+ {
+ if ( *fmt != '%' )
+ {
+ put(*fmt);
+ continue;
+ }
+
+ pad = zflag = nflag = lflag = 0;
+ c = *++fmt;
+ if ( (c == '-') || isdigit(c) )
+ {
+ if ( c == '-' )
+ {
+ nflag = 1;
+ c = *++fmt;
+ }
+ zflag = c == '0';
+ for ( pad = 0; isdigit(c); c = *++fmt )
+ pad = (pad * 10) + c - '0';
+ }
+ if ( c == 'l' ) /* long extension */
+ {
+ lflag = 1;
+ c = *++fmt;
+ }
+ if ( (c == 'd') || (c == 'u') || (c == 'o') || (c == 'x') )
+ {
+ if ( lflag )
+ value = va_arg(ap, unsigned);
+ else
+ value = (unsigned) va_arg(ap, unsigned int);
+ str = buffer;
+ printnum(str, value,
+ c == 'o' ? 8 : (c == 'x' ? 16 : 10));
+ goto printn;
+ }
+ else if ( (c == 'O') || (c == 'D') || (c == 'X') )
+ {
+ value = va_arg(ap, unsigned);
+ str = buffer;
+ printnum(str, value,
+ c == 'O' ? 8 : (c == 'X' ? 16 : 10));
+ printn:
+ slen = strlen(str);
+ for ( i = pad - slen; i > 0; i-- )
+ put(zflag ? '0' : ' ');
+ while ( *str )
+ put(*str++);
+ }
+ else if ( c == 's' )
+ {
+ str = va_arg(ap, char *);
+ slen = strlen(str);
+ if ( nflag == 0 )
+ for ( i = pad - slen; i > 0; i-- )
+ put(' ');
+ while ( *str )
+ put(*str++);
+ if ( nflag )
+ for ( i = pad - slen; i > 0; i-- )
+ put(' ');
+ }
+ else if ( c == 'c' )
+ {
+ put(va_arg(ap, int));
+ }
+ else
+ {
+ put(*fmt);
+ }
+ }
+}
+
+static void putchar(char c)
+{
+ outb(0xe9, c);
}
+
+int printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _doprint(putchar, fmt, ap);
+ va_end(ap);
+
+ return 0;
+}
+
+int vprintf(const char *fmt, va_list ap)
+{
+ _doprint(putchar, fmt, ap);
+ return 0;
+}
+
+void __assert_failed(char *assertion, char *file, int line)
+{
+ printf("HVMLoader assertion '%s' failed at %s:%d\n",
+ assertion, file, line);
+ for ( ; ; )
+ __asm__ __volatile__ ( "ud2" );
+}
+
+void __bug(char *file, int line)
+{
+ printf("HVMLoader bug at %s:%d\n", file, line);
+ for ( ; ; )
+ __asm__ __volatile__ ( "ud2" );
+}
+
+static int validate_hvm_info(struct hvm_info_table *t)
+{
+ char signature[] = "HVM INFO";
+ uint8_t *ptr = (uint8_t *)t;
+ uint8_t sum = 0;
+ int i;
+
+ /* strncmp(t->signature, "HVM INFO", 8) */
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( signature[i] != t->signature[i] )
+ {
+ printf("Bad hvm info signature\n");
+ return 0;
+ }
+ }
+
+ for ( i = 0; i < t->length; i++ )
+ sum += ptr[i];
+
+ return (sum == 0);
+}
+
+static struct hvm_info_table *get_hvm_info_table(void)
+{
+ static struct hvm_info_table *table;
+ struct hvm_info_table *t;
+
+ if ( table != NULL )
+ return table;
+
+ t = (struct hvm_info_table *)HVM_INFO_PADDR;
+
+ if ( !validate_hvm_info(t) )
+ {
+ printf("Bad hvm info table\n");
+ return NULL;
+ }
+
+ table = t;
+
+ return table;
+}
+
+int get_vcpu_nr(void)
+{
+ struct hvm_info_table *t = get_hvm_info_table();
+ return (t ? t->nr_vcpus : 1);
+}
+
+int get_acpi_enabled(void)
+{
+ struct hvm_info_table *t = get_hvm_info_table();
+ return (t ? t->acpi_enabled : 1);
+}
+
+int get_apic_mode(void)
+{
+ struct hvm_info_table *t = get_hvm_info_table();
+ return (t ? t->apic_mode : 1);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h
index 5d21e8bc7f..4b2f874ab3 100644
--- a/tools/firmware/hvmloader/util.h
+++ b/tools/firmware/hvmloader/util.h
@@ -1,19 +1,52 @@
#ifndef __HVMLOADER_UTIL_H__
#define __HVMLOADER_UTIL_H__
+#include <stdarg.h>
+
+#undef offsetof
+#define offsetof(t, m) ((unsigned long)&((t *)0)->m)
+
+extern void __assert_failed(char *assertion, char *file, int line)
+ __attribute__((noreturn));
+#define ASSERT(p) \
+ do { if (!(p)) __assert_failed(#p, __FILE__, __LINE__); } while (0)
+extern void __bug(char *file, int line) __attribute__((noreturn));
+#define BUG() __bug()
+
/* I/O output */
+void outb(uint16_t addr, uint8_t val);
void outw(uint16_t addr, uint16_t val);
-void outb(uint16_t addr, uint8_t val);
+void outl(uint16_t addr, uint32_t val);
/* I/O input */
-uint8_t inb(uint16_t addr);
+uint8_t inb(uint16_t addr);
+uint16_t inw(uint16_t addr);
+uint32_t inl(uint16_t addr);
+
+/* APIC access */
+uint32_t ioapic_read(uint32_t reg);
+void ioapic_write(uint32_t reg, uint32_t val);
+uint32_t lapic_read(uint32_t reg);
+void lapic_write(uint32_t reg, uint32_t val);
+
+/* PCI access */
+uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len);
+#define pci_readb(devfn, reg) ((uint8_t) pci_read(devfn, reg, 1))
+#define pci_readw(devfn, reg) ((uint16_t)pci_read(devfn, reg, 2))
+#define pci_readl(devfn, reg) ((uint32_t)pci_read(devfn, reg, 4))
+void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val);
+#define pci_writeb(devfn, reg, val) (pci_write(devfn, reg, 1, (uint8_t) val))
+#define pci_writew(devfn, reg, val) (pci_write(devfn, reg, 2, (uint16_t)val))
+#define pci_writel(devfn, reg, val) (pci_write(devfn, reg, 4, (uint32_t)val))
/* Do cpuid instruction, with operation 'idx' */
void cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
-/* Return number of vcpus. */
+/* HVM-builder info. */
int get_vcpu_nr(void);
+int get_acpi_enabled(void);
+int get_apic_mode(void);
/* String and memory functions */
int strcmp(const char *cs, const char *ct);
@@ -22,6 +55,7 @@ char *strncpy(char *dest, const char *src, unsigned n);
unsigned strlen(const char *s);
int memcmp(const void *s1, const void *s2, unsigned n);
void *memcpy(void *dest, const void *src, unsigned n);
+void *memmove(void *dest, const void *src, unsigned n);
void *memset(void *s, int c, unsigned n);
char *itoa(char *a, unsigned int i);
@@ -30,12 +64,16 @@ char *itoa(char *a, unsigned int i);
void byte_to_hex(char *digits, uint8_t byte);
/* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
- string.
-
- Pre-condition: sizeof(dest) >= 37 */
+ string. Pre-condition: sizeof(dest) >= 37 */
void uuid_to_string(char *dest, uint8_t *uuid);
/* Debug output */
-void puts(const char *s);
+int printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+int vprintf(const char *fmt, va_list ap);
+
+/* Allocate region of specified type in the e820 table. */
+uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask);
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
#endif /* __HVMLOADER_UTIL_H__ */
diff --git a/tools/firmware/rombios/rombios.c b/tools/firmware/rombios/rombios.c
index b9c9d78938..7a14b46ac4 100644
--- a/tools/firmware/rombios/rombios.c
+++ b/tools/firmware/rombios/rombios.c
@@ -9103,79 +9103,79 @@ pci_routing_table_structure:
;; first slot entry PCI-to-ISA (embedded)
db 0 ;; pci bus number
db 0x08 ;; pci device number (bit 7-3)
- db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
- dw 0xdef8 ;; IRQ bitmap INTA#
- db 0x61 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
- db 0x62 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
- db 0x63 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
- db 0 ;; physical slot (0 = embedded)
- db 0 ;; reserved
- ;; second slot entry: 1st PCI slot
- db 0 ;; pci bus number
- db 0x10 ;; pci device number (bit 7-3)
- db 0x61 ;; link value INTA#
- dw 0xdef8 ;; IRQ bitmap INTA#
+ db 0x61 ;; link value INTA#: pointer into PCI2ISA config space
+ dw 0x0c60 ;; IRQ bitmap INTA#
db 0x62 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
db 0x63 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
db 0x60 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
- db 1 ;; physical slot (0 = embedded)
+ dw 0x0c60 ;; IRQ bitmap INTD#
+ db 0 ;; physical slot (0 = embedded)
db 0 ;; reserved
- ;; third slot entry: 2nd PCI slot
+ ;; second slot entry: 1st PCI slot
db 0 ;; pci bus number
- db 0x18 ;; pci device number (bit 7-3)
+ db 0x10 ;; pci device number (bit 7-3)
db 0x62 ;; link value INTA#
- dw 0xdef8 ;; IRQ bitmap INTA#
+ dw 0x0c60 ;; IRQ bitmap INTA#
db 0x63 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
db 0x60 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
db 0x61 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
- db 2 ;; physical slot (0 = embedded)
+ dw 0x0c60 ;; IRQ bitmap INTD#
+ db 1 ;; physical slot (0 = embedded)
db 0 ;; reserved
- ;; 4th slot entry: 3rd PCI slot
+ ;; third slot entry: 2nd PCI slot
db 0 ;; pci bus number
- db 0x20 ;; pci device number (bit 7-3)
+ db 0x18 ;; pci device number (bit 7-3)
db 0x63 ;; link value INTA#
- dw 0xdef8 ;; IRQ bitmap INTA#
+ dw 0x0c60 ;; IRQ bitmap INTA#
db 0x60 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
db 0x61 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
db 0x62 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
- db 3 ;; physical slot (0 = embedded)
+ dw 0x0c60 ;; IRQ bitmap INTD#
+ db 2 ;; physical slot (0 = embedded)
db 0 ;; reserved
- ;; 5th slot entry: 4rd PCI slot
+ ;; 4th slot entry: 3rd PCI slot
db 0 ;; pci bus number
- db 0x28 ;; pci device number (bit 7-3)
+ db 0x20 ;; pci device number (bit 7-3)
db 0x60 ;; link value INTA#
- dw 0xdef8 ;; IRQ bitmap INTA#
+ dw 0x0c60 ;; IRQ bitmap INTA#
db 0x61 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
db 0x62 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
db 0x63 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
- db 4 ;; physical slot (0 = embedded)
+ dw 0x0c60 ;; IRQ bitmap INTD#
+ db 3 ;; physical slot (0 = embedded)
db 0 ;; reserved
- ;; 6th slot entry: 5rd PCI slot
+ ;; 5th slot entry: 4rd PCI slot
db 0 ;; pci bus number
- db 0x30 ;; pci device number (bit 7-3)
+ db 0x28 ;; pci device number (bit 7-3)
db 0x61 ;; link value INTA#
- dw 0xdef8 ;; IRQ bitmap INTA#
+ dw 0x0c60 ;; IRQ bitmap INTA#
db 0x62 ;; link value INTB#
- dw 0xdef8 ;; IRQ bitmap INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
db 0x63 ;; link value INTC#
- dw 0xdef8 ;; IRQ bitmap INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
db 0x60 ;; link value INTD#
- dw 0xdef8 ;; IRQ bitmap INTD#
+ dw 0x0c60 ;; IRQ bitmap INTD#
+ db 4 ;; physical slot (0 = embedded)
+ db 0 ;; reserved
+ ;; 6th slot entry: 5rd PCI slot
+ db 0 ;; pci bus number
+ db 0x30 ;; pci device number (bit 7-3)
+ db 0x62 ;; link value INTA#
+ dw 0x0c60 ;; IRQ bitmap INTA#
+ db 0x63 ;; link value INTB#
+ dw 0x0c60 ;; IRQ bitmap INTB#
+ db 0x60 ;; link value INTC#
+ dw 0x0c60 ;; IRQ bitmap INTC#
+ db 0x61 ;; link value INTD#
+ dw 0x0c60 ;; IRQ bitmap INTD#
db 5 ;; physical slot (0 = embedded)
db 0 ;; reserved
diff --git a/tools/firmware/vmxassist/Makefile b/tools/firmware/vmxassist/Makefile
index 08fea45781..70f7a0e0a3 100644
--- a/tools/firmware/vmxassist/Makefile
+++ b/tools/firmware/vmxassist/Makefile
@@ -32,14 +32,13 @@ DEFINES=-DDEBUG -DTEXTADDR=$(TEXTADDR)
XENINC=-I$(XEN_ROOT)/tools/libxc
# Disable PIE/SSP if GCC supports them. They can break us.
-CFLAGS += $(call test-gcc-flag,$(CC),-nopie)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector-all)
+CFLAGS += $(call cc-option,$(CC),-nopie,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
CPP = cpp -P
OBJCOPY = objcopy -p -O binary -R .note -R .comment -R .bss -S --gap-fill=0
CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float
-LDFLAGS = -m elf_i386
OBJECTS = head.o trap.o vm86.o setup.o util.o
@@ -48,7 +47,7 @@ all: vmxassist.bin
vmxassist.bin: vmxassist.ld $(OBJECTS)
$(CPP) $(DEFINES) vmxassist.ld > vmxassist.tmp
- $(LD) -o vmxassist $(LDFLAGS) -nostdlib --fatal-warnings -N -T vmxassist.tmp $(OBJECTS)
+ $(LD) -o vmxassist $(LDFLAGS_DIRECT) -nostdlib --fatal-warnings -N -T vmxassist.tmp $(OBJECTS)
nm -n vmxassist > vmxassist.sym
$(OBJCOPY) vmxassist vmxassist.tmp
dd if=vmxassist.tmp of=vmxassist.bin ibs=512 conv=sync
diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S
index b183fac54e..a4cb614c68 100644
--- a/tools/firmware/vmxassist/head.S
+++ b/tools/firmware/vmxassist/head.S
@@ -59,7 +59,7 @@ _start16:
/* go to protected mode */
movl %cr0, %eax
- orl $CR0_PE, %eax
+ orl $(CR0_PE), %eax
movl %eax, %cr0
data32 ljmp $0x08, $1f
diff --git a/tools/firmware/vmxassist/machine.h b/tools/firmware/vmxassist/machine.h
index 82fa12965d..0ea2adfa84 100644
--- a/tools/firmware/vmxassist/machine.h
+++ b/tools/firmware/vmxassist/machine.h
@@ -36,6 +36,7 @@
#define CR4_VME (1 << 0)
#define CR4_PVI (1 << 1)
#define CR4_PSE (1 << 4)
+#define CR4_PAE (1 << 5)
#define EFLAGS_ZF (1 << 6)
#define EFLAGS_TF (1 << 8)
diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c
index 07ef70a1df..4f82ca0d9e 100644
--- a/tools/firmware/vmxassist/setup.c
+++ b/tools/firmware/vmxassist/setup.c
@@ -53,13 +53,10 @@ unsigned pgd[NR_PGD] __attribute__ ((aligned(PGSIZE))) = { 0 };
struct e820entry e820map[] = {
{ 0x0000000000000000ULL, 0x000000000009F800ULL, E820_RAM },
{ 0x000000000009F800ULL, 0x0000000000000800ULL, E820_RESERVED },
- { 0x00000000000A0000ULL, 0x0000000000020000ULL, E820_IO },
{ 0x00000000000C0000ULL, 0x0000000000040000ULL, E820_RESERVED },
{ 0x0000000000100000ULL, 0x0000000000000000ULL, E820_RAM },
- { 0x0000000000000000ULL, 0x0000000000001000ULL, E820_SHARED_PAGE },
{ 0x0000000000000000ULL, 0x0000000000003000ULL, E820_NVS },
{ 0x0000000000003000ULL, 0x000000000000A000ULL, E820_ACPI },
- { 0x00000000FEC00000ULL, 0x0000000001400000ULL, E820_IO },
};
#endif /* TEST */
diff --git a/tools/firmware/vmxassist/trap.S b/tools/firmware/vmxassist/trap.S
index 468da0a5db..30e87adb85 100644
--- a/tools/firmware/vmxassist/trap.S
+++ b/tools/firmware/vmxassist/trap.S
@@ -106,7 +106,7 @@ common_trap: /* common trap handler */
pushl %es
pushal
- movl $DATA_SELECTOR, %eax /* make sure these are sane */
+ movl $(DATA_SELECTOR), %eax /* make sure these are sane */
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
diff --git a/tools/firmware/vmxassist/util.c b/tools/firmware/vmxassist/util.c
index 0181fe702c..6ae4b25f79 100644
--- a/tools/firmware/vmxassist/util.c
+++ b/tools/firmware/vmxassist/util.c
@@ -29,6 +29,31 @@ static void putchar(int);
static char *printnum(char *, unsigned long, int);
static void _doprint(void (*)(int), char const *, va_list);
+void
+cpuid_addr_value(uint64_t addr, uint64_t *value)
+{
+ uint32_t addr_low = (uint32_t)addr;
+ uint32_t addr_high = (uint32_t)(addr >> 32);
+ uint32_t value_low, value_high;
+ static unsigned int addr_leaf;
+
+ if (!addr_leaf) {
+ unsigned int eax, ebx, ecx, edx;
+ __asm__ __volatile__(
+ "cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "0" (0x40000000));
+ addr_leaf = eax + 1;
+ }
+
+ __asm__ __volatile__(
+ "cpuid"
+ : "=c" (value_low), "=d" (value_high)
+ : "a" (addr_leaf), "0" (addr_low), "1" (addr_high)
+ : "ebx");
+
+ *value = (uint64_t)value_high << 32 | value_low;
+}
void
dump_regs(struct regs *regs)
@@ -37,14 +62,15 @@ dump_regs(struct regs *regs)
regs->eax, regs->ecx, regs->edx, regs->ebx);
printf("esp %8x ebp %8x esi %8x edi %8x\n",
regs->esp, regs->ebp, regs->esi, regs->edi);
- printf("eip %8x eflags %8x cs %8x ds %8x\n",
- regs->eip, regs->eflags, regs->cs, regs->ds);
- printf("es %8x fs %8x uss %8x uesp %8x\n",
- regs->es, regs->fs, regs->uss, regs->uesp);
+ printf("es %8x ds %8x fs %8x gs %8x\n",
+ regs->es, regs->ds, regs->fs, regs->gs);
+ printf("trapno %8x errno %8x\n", regs->trapno, regs->errno);
+ printf("eip %8x cs %8x eflags %8x\n",
+ regs->eip, regs->cs, regs->eflags);
+ printf("uesp %8x uss %8x \n",
+ regs->uesp, regs->uss);
printf("ves %8x vds %8x vfs %8x vgs %8x\n",
regs->ves, regs->vds, regs->vfs, regs->vgs);
- if (regs->trapno != -1 || regs->errno != -1)
- printf("trapno %8x errno %8x\n", regs->trapno, regs->errno);
printf("cr0 %8lx cr2 %8x cr3 %8lx cr4 %8lx\n",
(long)oldctx.cr0, get_cr2(),
diff --git a/tools/firmware/vmxassist/util.h b/tools/firmware/vmxassist/util.h
index b2ace92b8f..c426f4e846 100644
--- a/tools/firmware/vmxassist/util.h
+++ b/tools/firmware/vmxassist/util.h
@@ -31,6 +31,7 @@
struct vmx_assist_context;
+extern void cpuid_addr_value(uint64_t addr, uint64_t *value);
extern void hexdump(unsigned char *, int);
extern void dump_regs(struct regs *);
extern void dump_vmx_context(struct vmx_assist_context *);
diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c
index 52a8ae236d..5bae53ed6d 100644
--- a/tools/firmware/vmxassist/vm86.c
+++ b/tools/firmware/vmxassist/vm86.c
@@ -52,34 +52,78 @@ char *states[] = {
static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
#endif /* DEBUG */
+#define PDE_PS (1 << 7)
#define PT_ENTRY_PRESENT 0x1
-static unsigned
-guest_linear_to_real(unsigned long base, unsigned off)
+/* We only support access to <=4G physical memory due to 1:1 mapping */
+static uint64_t
+guest_linear_to_phys(uint32_t base)
{
- unsigned int gcr3 = oldctx.cr3;
- unsigned int l1_mfn;
- unsigned int l0_mfn;
+ uint32_t gcr3 = oldctx.cr3;
+ uint64_t l2_mfn;
+ uint64_t l1_mfn;
+ uint64_t l0_mfn;
if (!(oldctx.cr0 & CR0_PG))
- return base + off;
+ return base;
+
+ if (!(oldctx.cr4 & CR4_PAE)) {
+ l1_mfn = ((uint32_t *)(long)gcr3)[(base >> 22) & 0x3ff];
+ if (!(l1_mfn & PT_ENTRY_PRESENT))
+ panic("l2 entry not present\n");
+
+ if ((oldctx.cr4 & CR4_PSE) && (l1_mfn & PDE_PS)) {
+ l0_mfn = l1_mfn & 0xffc00000;
+ return l0_mfn + (base & 0x3fffff);
+ }
+
+ l1_mfn &= 0xfffff000;
+
+ l0_mfn = ((uint32_t *)(long)l1_mfn)[(base >> 12) & 0x3ff];
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
+ l0_mfn &= 0xfffff000;
+
+ return l0_mfn + (base & 0xfff);
+ } else {
+ l2_mfn = ((uint64_t *)(long)gcr3)[(base >> 30) & 0x3];
+ if (!(l2_mfn & PT_ENTRY_PRESENT))
+ panic("l3 entry not present\n");
+ l2_mfn &= 0xffffff000ULL;
+
+ if (l2_mfn & 0xf00000000ULL) {
+ printf("l2 page above 4G\n");
+ cpuid_addr_value(l2_mfn + 8 * ((base >> 21) & 0x1ff), &l1_mfn);
+ } else
+ l1_mfn = ((uint64_t *)(long)l2_mfn)[(base >> 21) & 0x1ff];
+ if (!(l1_mfn & PT_ENTRY_PRESENT))
+ panic("l2 entry not present\n");
+
+ if (l1_mfn & PDE_PS) { /* CR4.PSE is ignored in PAE mode */
+ l0_mfn = l1_mfn & 0xfffe00000ULL;
+ return l0_mfn + (base & 0x1fffff);
+ }
+
+ l1_mfn &= 0xffffff000ULL;
- l1_mfn = ((unsigned int *)gcr3)[(base >> 22) & 0x3ff ];
- if (!(l1_mfn & PT_ENTRY_PRESENT))
- panic("l2 entry not present\n");
- l1_mfn = l1_mfn & 0xfffff000 ;
+ if (l1_mfn & 0xf00000000ULL) {
+ printf("l1 page above 4G\n");
+ cpuid_addr_value(l1_mfn + 8 * ((base >> 12) & 0x1ff), &l0_mfn);
+ } else
+ l0_mfn = ((uint64_t *)(long)l1_mfn)[(base >> 12) & 0x1ff];
+ if (!(l0_mfn & PT_ENTRY_PRESENT))
+ panic("l1 entry not present\n");
- l0_mfn = ((unsigned int *)l1_mfn)[(base >> 12) & 0x3ff];
- if (!(l0_mfn & PT_ENTRY_PRESENT))
- panic("l1 entry not present\n");
- l0_mfn = l0_mfn & 0xfffff000;
+ l0_mfn &= 0xffffff000ULL;
- return l0_mfn + off + (base & 0xfff);
+ return l0_mfn + (base & 0xfff);
+ }
}
static unsigned
address(struct regs *regs, unsigned seg, unsigned off)
{
+ uint64_t gdt_phys_base;
unsigned long long entry;
unsigned seg_base, seg_limit;
unsigned entry_low, entry_high;
@@ -95,7 +139,13 @@ address(struct regs *regs, unsigned seg, unsigned off)
(mode == VM86_REAL_TO_PROTECTED && regs->cs == seg))
return ((seg & 0xFFFF) << 4) + off;
- entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[seg >> 3];
+ gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base);
+ if (gdt_phys_base != (uint32_t)gdt_phys_base) {
+ printf("gdt base address above 4G\n");
+ cpuid_addr_value(gdt_phys_base + 8 * (seg >> 3), &entry);
+ } else
+ entry = ((unsigned long long *)(long)gdt_phys_base)[seg >> 3];
+
entry_high = entry >> 32;
entry_low = entry & 0xFFFFFFFF;
@@ -763,12 +813,63 @@ pop(struct regs *regs, unsigned prefix, unsigned opc)
return 1;
}
+static int
+mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc)
+{
+ unsigned modrm = fetch8(regs);
+
+ /* Only need to emulate segment loads in real->protected mode. */
+ if (mode != VM86_REAL_TO_PROTECTED)
+ return 0;
+
+ /* Register source only. */
+ if ((modrm & 0xC0) != 0xC0)
+ goto fail;
+
+ switch ((modrm & 0x38) >> 3) {
+ case 0: /* es */
+ regs->ves = getreg16(regs, modrm);
+ saved_rm_regs.ves = 0;
+ oldctx.es_sel = regs->ves;
+ return 1;
+
+ /* case 1: cs */
+
+ case 2: /* ss */
+ regs->uss = getreg16(regs, modrm);
+ saved_rm_regs.uss = 0;
+ oldctx.ss_sel = regs->uss;
+ return 1;
+ case 3: /* ds */
+ regs->vds = getreg16(regs, modrm);
+ saved_rm_regs.vds = 0;
+ oldctx.ds_sel = regs->vds;
+ return 1;
+ case 4: /* fs */
+ regs->vfs = getreg16(regs, modrm);
+ saved_rm_regs.vfs = 0;
+ oldctx.fs_sel = regs->vfs;
+ return 1;
+ case 5: /* gs */
+ regs->vgs = getreg16(regs, modrm);
+ saved_rm_regs.vgs = 0;
+ oldctx.gs_sel = regs->vgs;
+ return 1;
+ }
+
+ fail:
+ printf("%s:%d: missed opcode %02x %02x\n",
+ __FUNCTION__, __LINE__, opc, modrm);
+ return 0;
+}
+
/*
* Emulate a segment load in protected mode
*/
static int
load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes)
{
+ uint64_t gdt_phys_base;
unsigned long long entry;
/* protected mode: use seg as index into gdt */
@@ -780,7 +881,12 @@ load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes
return 1;
}
- entry = ((unsigned long long *) guest_linear_to_real(oldctx.gdtr_base, 0))[sel >> 3];
+ gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base);
+ if (gdt_phys_base != (uint32_t)gdt_phys_base) {
+ printf("gdt base address above 4G\n");
+ cpuid_addr_value(gdt_phys_base + 8 * (sel >> 3), &entry);
+ } else
+ entry = ((unsigned long long *)(long)gdt_phys_base)[sel >> 3];
/* Check the P bit first */
if (!((entry >> (15+32)) & 0x1) && sel != 0)
@@ -811,6 +917,18 @@ load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes
}
/*
+ * Emulate a protected mode segment load, falling back to clearing it if
+ * the descriptor was invalid.
+ */
+static void
+load_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes)
+{
+ if (!load_seg(sel, base, limit, arbytes))
+ load_seg(0, base, limit, arbytes);
+}
+
+
+/*
* Transition to protected mode
*/
static void
@@ -822,63 +940,22 @@ protected_mode(struct regs *regs)
oldctx.esp = regs->uesp;
oldctx.eflags = regs->eflags;
- memset(&saved_rm_regs, 0, sizeof(struct regs));
-
/* reload all segment registers */
if (!load_seg(regs->cs, &oldctx.cs_base,
&oldctx.cs_limit, &oldctx.cs_arbytes))
panic("Invalid %%cs=0x%x for protected mode\n", regs->cs);
oldctx.cs_sel = regs->cs;
- if (load_seg(regs->ves, &oldctx.es_base,
- &oldctx.es_limit, &oldctx.es_arbytes))
- oldctx.es_sel = regs->ves;
- else {
- load_seg(0, &oldctx.es_base,
- &oldctx.es_limit, &oldctx.es_arbytes);
- oldctx.es_sel = 0;
- saved_rm_regs.ves = regs->ves;
- }
-
- if (load_seg(regs->uss, &oldctx.ss_base,
- &oldctx.ss_limit, &oldctx.ss_arbytes))
- oldctx.ss_sel = regs->uss;
- else {
- load_seg(0, &oldctx.ss_base,
- &oldctx.ss_limit, &oldctx.ss_arbytes);
- oldctx.ss_sel = 0;
- saved_rm_regs.uss = regs->uss;
- }
-
- if (load_seg(regs->vds, &oldctx.ds_base,
- &oldctx.ds_limit, &oldctx.ds_arbytes))
- oldctx.ds_sel = regs->vds;
- else {
- load_seg(0, &oldctx.ds_base,
- &oldctx.ds_limit, &oldctx.ds_arbytes);
- oldctx.ds_sel = 0;
- saved_rm_regs.vds = regs->vds;
- }
-
- if (load_seg(regs->vfs, &oldctx.fs_base,
- &oldctx.fs_limit, &oldctx.fs_arbytes))
- oldctx.fs_sel = regs->vfs;
- else {
- load_seg(0, &oldctx.fs_base,
- &oldctx.fs_limit, &oldctx.fs_arbytes);
- oldctx.fs_sel = 0;
- saved_rm_regs.vfs = regs->vfs;
- }
-
- if (load_seg(regs->vgs, &oldctx.gs_base,
- &oldctx.gs_limit, &oldctx.gs_arbytes))
- oldctx.gs_sel = regs->vgs;
- else {
- load_seg(0, &oldctx.gs_base,
- &oldctx.gs_limit, &oldctx.gs_arbytes);
- oldctx.gs_sel = 0;
- saved_rm_regs.vgs = regs->vgs;
- }
+ load_or_clear_seg(oldctx.es_sel, &oldctx.es_base,
+ &oldctx.es_limit, &oldctx.es_arbytes);
+ load_or_clear_seg(oldctx.ss_sel, &oldctx.ss_base,
+ &oldctx.ss_limit, &oldctx.ss_arbytes);
+ load_or_clear_seg(oldctx.ds_sel, &oldctx.ds_base,
+ &oldctx.ds_limit, &oldctx.ds_arbytes);
+ load_or_clear_seg(oldctx.fs_sel, &oldctx.fs_base,
+ &oldctx.fs_limit, &oldctx.fs_arbytes);
+ load_or_clear_seg(oldctx.gs_sel, &oldctx.gs_base,
+ &oldctx.gs_limit, &oldctx.gs_arbytes);
/* initialize jump environment to warp back to protected mode */
regs->cs = CODE_SELECTOR;
@@ -966,6 +1043,16 @@ set_mode(struct regs *regs, enum vm86_mode newmode)
case VM86_REAL_TO_PROTECTED:
if (mode == VM86_REAL) {
regs->eflags |= EFLAGS_TF;
+ saved_rm_regs.vds = regs->vds;
+ saved_rm_regs.ves = regs->ves;
+ saved_rm_regs.vfs = regs->vfs;
+ saved_rm_regs.vgs = regs->vgs;
+ saved_rm_regs.uss = regs->uss;
+ oldctx.ds_sel = 0;
+ oldctx.es_sel = 0;
+ oldctx.fs_sel = 0;
+ oldctx.gs_sel = 0;
+ oldctx.ss_sel = 0;
break;
} else if (mode == VM86_REAL_TO_PROTECTED) {
break;
@@ -1194,6 +1281,18 @@ pushrm(struct regs *regs, int prefix, unsigned modrm)
enum { OPC_INVALID, OPC_EMULATED };
+#define rdmsr(msr,val1,val2) \
+ __asm__ __volatile__( \
+ "rdmsr" \
+ : "=a" (val1), "=d" (val2) \
+ : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+ __asm__ __volatile__( \
+ "wrmsr" \
+ : /* no outputs */ \
+ : "c" (msr), "a" (val1), "d" (val2))
+
/*
* Emulate a single instruction, including all its prefixes. We only implement
* a small subset of the opcodes, and not all opcodes are implemented for each
@@ -1208,12 +1307,14 @@ opcode(struct regs *regs)
for (;;) {
switch ((opc = fetch8(regs))) {
- case 0x07:
- if (prefix & DATA32)
- regs->ves = pop32(regs);
- else
- regs->ves = pop16(regs);
+ case 0x07: /* pop %es */
+ regs->ves = (prefix & DATA32) ?
+ pop32(regs) : pop16(regs);
TRACE((regs, regs->eip - eip, "pop %%es"));
+ if (mode == VM86_REAL_TO_PROTECTED) {
+ saved_rm_regs.ves = 0;
+ oldctx.es_sel = regs->ves;
+ }
return OPC_EMULATED;
case 0x0F: /* two byte opcode */
@@ -1252,11 +1353,27 @@ opcode(struct regs *regs)
if (!movcr(regs, prefix, opc))
goto invalid;
return OPC_EMULATED;
+ case 0x30: /* WRMSR */
+ wrmsr(regs->ecx, regs->eax, regs->edx);
+ return OPC_EMULATED;
+ case 0x32: /* RDMSR */
+ rdmsr(regs->ecx, regs->eax, regs->edx);
+ return OPC_EMULATED;
default:
goto invalid;
}
goto invalid;
+ case 0x1F: /* pop %ds */
+ regs->vds = (prefix & DATA32) ?
+ pop32(regs) : pop16(regs);
+ TRACE((regs, regs->eip - eip, "pop %%ds"));
+ if (mode == VM86_REAL_TO_PROTECTED) {
+ saved_rm_regs.vds = 0;
+ oldctx.ds_sel = regs->vds;
+ }
+ return OPC_EMULATED;
+
case 0x26:
TRACE((regs, regs->eip - eip, "%%es:"));
prefix |= SEG_ES;
@@ -1343,6 +1460,11 @@ opcode(struct regs *regs)
goto invalid;
return OPC_EMULATED;
+ case 0x8E: /* mov r16, sreg */
+ if (!mov_to_seg(regs, prefix, opc))
+ goto invalid;
+ return OPC_EMULATED;
+
case 0x8F: /* addr32 pop r/m16 */
if ((prefix & ADDR32) == 0)
goto invalid;
@@ -1376,12 +1498,14 @@ opcode(struct regs *regs)
{
int addr, data;
int seg = segment(prefix, regs, regs->vds);
+ int offset = prefix & ADDR32? fetch32(regs) : fetch16(regs);
+
if (prefix & DATA32) {
- addr = address(regs, seg, fetch32(regs));
+ addr = address(regs, seg, offset);
data = read32(addr);
setreg32(regs, 0, data);
} else {
- addr = address(regs, seg, fetch16(regs));
+ addr = address(regs, seg, offset);
data = read16(addr);
setreg16(regs, 0, data);
}
diff --git a/tools/firmware/vmxassist/vm86.h b/tools/firmware/vmxassist/vm86.h
index 0c04dc6e73..4c6609daf0 100644
--- a/tools/firmware/vmxassist/vm86.h
+++ b/tools/firmware/vmxassist/vm86.h
@@ -33,11 +33,11 @@
#ifndef __ASSEMBLY__
struct regs {
- unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
- unsigned ds, es, fs, gs;
- unsigned trapno, errno;
- unsigned eip, cs, eflags, uesp, uss;
- unsigned ves, vds, vfs, vgs;
+ unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
+ unsigned es, ds, fs, gs;
+ unsigned trapno, errno;
+ unsigned eip, cs, eflags, uesp, uss;
+ unsigned ves, vds, vfs, vgs;
};
enum vm86_mode {
diff --git a/tools/guest-headers/Makefile b/tools/guest-headers/Makefile
index dc1456667f..1c50599a4c 100644
--- a/tools/guest-headers/Makefile
+++ b/tools/guest-headers/Makefile
@@ -1,5 +1,6 @@
-
XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
linuxsparsetree = $(XEN_ROOT)/linux-2.6-xen-sparse
.PHONY: all
@@ -8,10 +9,15 @@ all:
.PHONY: check
check:
-.PHONY: install
-install:
+.PHONY: install install-Linux install-SunOS
+
+install-Linux:
mkdir -p $(DESTDIR)/usr/include/xen/linux
install -m0644 $(linuxsparsetree)/include/xen/public/*.h $(DESTDIR)/usr/include/xen/linux
+install-SunOS:
+
+install: install-$(XEN_OS)
+
.PHONY: clean
clean:
diff --git a/tools/ioemu/Makefile.target b/tools/ioemu/Makefile.target
index c495abbf59..b35cdbaeb5 100644
--- a/tools/ioemu/Makefile.target
+++ b/tools/ioemu/Makefile.target
@@ -23,7 +23,7 @@ VPATH+=:$(SRC_PATH)/linux-user
DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
CFLAGS+=-Wall -O2 -g -fno-strict-aliasing
-SSE2 := $(call test-gcc-flag,$(CC),-msse2)
+SSE2 := $(call cc-option,$(CC),-msse2,)
ifeq ($(SSE2),-msse2)
CFLAGS += -DUSE_SSE2=1 -msse2
endif
@@ -177,7 +177,8 @@ endif
#########################################################
-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+DEFINES+=-D_GNU_SOURCE
+#-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS+=-lm
LIBS+=-L../../libxc -lxenctrl -lxenguest
LIBS+=-L../../xenstore -lxenstore
@@ -294,7 +295,11 @@ OBJS+=gdbstub.o
endif
# qemu-dm objects
+ifeq ($(ARCH),ia64)
LIBOBJS=helper2.o exec-dm.o i8259-dm.o
+else
+LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o piix_pci-dm.o
+endif
all: $(PROGS)
@@ -354,12 +359,17 @@ VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
-VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
-VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
+ifeq ($(ARCH),ia64)
+VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o piix_pci.o
+else
+VL_OBJS+= fdc.o serial.o pc.o
+endif
+VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o
VL_OBJS+= usb-uhci.o
VL_OBJS+= piix4acpi.o
VL_OBJS+= xenstore.o
VL_OBJS+= xen_platform.o
+VL_OBJS+= tpm_tis.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
@@ -398,6 +408,7 @@ ifdef CONFIG_SDL
VL_OBJS+=sdl.o
endif
VL_OBJS+=vnc.o
+VL_OBJS+=d3des.o
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
@@ -458,6 +469,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+d3des.o: d3des.c d3des.h
+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
@@ -555,10 +569,10 @@ distclean: clean
install: all
mkdir -p "$(DESTDIR)$(bindir)" "$(DESTDIR)$(configdir)"
ifneq ($(PROGS),)
- $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
+ $(INSTALL_PROG) $(PROGS) "$(DESTDIR)$(bindir)"
endif
- install -m 755 $(TARGET_PATH)/qemu-dm.debug "$(DESTDIR)$(bindir)"
- install -m 755 $(TARGET_PATH)/qemu-ifup "$(DESTDIR)$(configdir)"
+ $(INSTALL_PROG) $(TARGET_PATH)/qemu-dm.debug "$(DESTDIR)$(bindir)"
+ $(INSTALL_PROG) $(TARGET_PATH)/qemu-ifup "$(DESTDIR)$(configdir)"
ifneq ($(wildcard .depend),)
include .depend
diff --git a/tools/ioemu/d3des.c b/tools/ioemu/d3des.c
new file mode 100644
index 0000000000..eaca581653
--- /dev/null
+++ b/tools/ioemu/d3des.c
@@ -0,0 +1,434 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC. Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This software 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.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static unsigned short bytebit[8] = {
+ 01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+ 0x800000L, 0x400000L, 0x200000L, 0x100000L,
+ 0x80000L, 0x40000L, 0x20000L, 0x10000L,
+ 0x8000L, 0x4000L, 0x2000L, 0x1000L,
+ 0x800L, 0x400L, 0x200L, 0x100L,
+ 0x80L, 0x40L, 0x20L, 0x10L,
+ 0x8L, 0x4L, 0x2L, 0x1L };
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
+
+static unsigned char totrot[16] = {
+ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+ register int i, j, l, m, n;
+ unsigned char pc1m[56], pcr[56];
+ unsigned long kn[32];
+
+ for ( j = 0; j < 56; j++ ) {
+ l = pc1[j];
+ m = l & 07;
+ pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+ }
+ for( i = 0; i < 16; i++ ) {
+ if( edf == DE1 ) m = (15 - i) << 1;
+ else m = i << 1;
+ n = m + 1;
+ kn[m] = kn[n] = 0L;
+ for( j = 0; j < 28; j++ ) {
+ l = j + totrot[i];
+ if( l < 28 ) pcr[j] = pc1m[l];
+ else pcr[j] = pc1m[l - 28];
+ }
+ for( j = 28; j < 56; j++ ) {
+ l = j + totrot[i];
+ if( l < 56 ) pcr[j] = pc1m[l];
+ else pcr[j] = pc1m[l - 28];
+ }
+ for( j = 0; j < 24; j++ ) {
+ if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+ if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+ }
+ }
+ cookey(kn);
+ return;
+ }
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+ register unsigned long *cook, *raw0;
+ unsigned long dough[32];
+ register int i;
+
+ cook = dough;
+ for( i = 0; i < 16; i++, raw1++ ) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ *cook |= (*raw1 & 0x00fc0000L) >> 10;
+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+ *cook = (*raw0 & 0x0003f000L) << 12;
+ *cook |= (*raw0 & 0x0000003fL) << 16;
+ *cook |= (*raw1 & 0x0003f000L) >> 4;
+ *cook++ |= (*raw1 & 0x0000003fL);
+ }
+ usekey(dough);
+ return;
+ }
+
+void cpkey(into)
+register unsigned long *into;
+{
+ register unsigned long *from, *endp;
+
+ from = KnL, endp = &KnL[32];
+ while( from < endp ) *into++ = *from++;
+ return;
+ }
+
+void usekey(from)
+register unsigned long *from;
+{
+ register unsigned long *to, *endp;
+
+ to = KnL, endp = &KnL[32];
+ while( to < endp ) *to++ = *from++;
+ return;
+ }
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+ unsigned long work[2];
+
+ scrunch(inblock, work);
+ desfunc(work, KnL);
+ unscrun(work, outblock);
+ return;
+ }
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+ *into = (*outof++ & 0xffL) << 24;
+ *into |= (*outof++ & 0xffL) << 16;
+ *into |= (*outof++ & 0xffL) << 8;
+ *into++ |= (*outof++ & 0xffL);
+ *into = (*outof++ & 0xffL) << 24;
+ *into |= (*outof++ & 0xffL) << 16;
+ *into |= (*outof++ & 0xffL) << 8;
+ *into |= (*outof & 0xffL);
+ return;
+ }
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
+ *into++ = (unsigned char)(*outof++ & 0xffL);
+ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
+ *into = (unsigned char)(*outof & 0xffL);
+ return;
+ }
+
+static unsigned long SP1[64] = {
+ 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+ 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+ 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+ 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+ 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+ 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+ 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+ 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+ 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+ 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+ 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+ 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+ 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+ 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+ 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+ 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+ 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+ 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+ 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+ 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+ 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+ 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+ 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+ 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+ 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+ 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+ 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+ 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+ 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+ 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+ 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+ 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+ 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+ 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+ 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+ 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+ 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+ 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+ 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+ 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+ 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+ 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+ 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+ 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+ 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+ 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+ 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+ 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+ 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+ 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+ 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+ 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+ 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+ 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+ 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+ 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+ 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+ 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+ 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+ 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+ 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+ 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+ 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+ 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+ 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+ 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+ 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+ 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+ 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+ 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+ 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+ 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+ 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+ 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+ 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+ 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+ 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+ 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+ 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+ 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+ 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+ 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+ 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+ 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+ 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+ 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+ 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+ 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+ 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+ 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+ 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+ 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+ 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+ 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+ 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+ 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+ 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+ 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+ 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+ 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+ 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+ 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+ 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+ 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+ 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+ 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+ 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+ 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+ 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+ 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+ 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+ 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+ 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+ 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+ 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+ 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+ 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+ 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+ register unsigned long fval, work, right, leftt;
+ register int round;
+
+ leftt = block[0];
+ right = block[1];
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+ right ^= work;
+ leftt ^= (work << 4);
+ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+ right ^= work;
+ leftt ^= (work << 16);
+ work = ((right >> 2) ^ leftt) & 0x33333333L;
+ leftt ^= work;
+ right ^= (work << 2);
+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+ leftt ^= work;
+ right ^= (work << 8);
+ right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+ for( round = 0; round < 8; round++ ) {
+ work = (right << 28) | (right >> 4);
+ work ^= *keys++;
+ fval = SP7[ work & 0x3fL];
+ fval |= SP5[(work >> 8) & 0x3fL];
+ fval |= SP3[(work >> 16) & 0x3fL];
+ fval |= SP1[(work >> 24) & 0x3fL];
+ work = right ^ *keys++;
+ fval |= SP8[ work & 0x3fL];
+ fval |= SP6[(work >> 8) & 0x3fL];
+ fval |= SP4[(work >> 16) & 0x3fL];
+ fval |= SP2[(work >> 24) & 0x3fL];
+ leftt ^= fval;
+ work = (leftt << 28) | (leftt >> 4);
+ work ^= *keys++;
+ fval = SP7[ work & 0x3fL];
+ fval |= SP5[(work >> 8) & 0x3fL];
+ fval |= SP3[(work >> 16) & 0x3fL];
+ fval |= SP1[(work >> 24) & 0x3fL];
+ work = leftt ^ *keys++;
+ fval |= SP8[ work & 0x3fL];
+ fval |= SP6[(work >> 8) & 0x3fL];
+ fval |= SP4[(work >> 16) & 0x3fL];
+ fval |= SP2[(work >> 24) & 0x3fL];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >> 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 31) | (leftt >> 1);
+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+ right ^= work;
+ leftt ^= (work << 8);
+ work = ((leftt >> 2) ^ right) & 0x33333333L;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+ leftt ^= work;
+ right ^= (work << 4);
+ *block++ = right;
+ *block = leftt;
+ return;
+ }
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/tools/ioemu/d3des.h b/tools/ioemu/d3des.h
new file mode 100644
index 0000000000..ea3da44ce9
--- /dev/null
+++ b/tools/ioemu/d3des.h
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+ *
+ * This software 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.
+ */
+
+/* d3des.h -
+ *
+ * Headers and defines for d3des.c
+ * Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ * (GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0 0 /* MODE == encrypt */
+#define DE1 1 /* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/* hexkey[8] MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/* cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/* cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/* from[8] to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'. They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/tools/ioemu/hw/fdc.c b/tools/ioemu/hw/fdc.c
index 3890ace120..1d16cd6518 100644
--- a/tools/ioemu/hw/fdc.c
+++ b/tools/ioemu/hw/fdc.c
@@ -898,7 +898,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
fdctrl->data_len = fdctrl->fifo[8];
} else {
int tmp;
- fdctrl->data_len = 128 << fdctrl->fifo[5];
+ fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
tmp = (cur_drv->last_sect - ks + 1);
if (fdctrl->fifo[0] & 0x80)
tmp += cur_drv->last_sect;
diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c
index 8b070cc0cc..94d5beaad5 100644
--- a/tools/ioemu/hw/ide.c
+++ b/tools/ioemu/hw/ide.c
@@ -557,9 +557,9 @@ static void ide_atapi_identify(IDEState *s)
padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
- put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
+ put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
- put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
+ put_le16(p + 63, 0x07); /* mdma0-2 supported */
put_le16(p + 64, 1); /* PIO modes */
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
diff --git a/tools/ioemu/hw/ne2000.c b/tools/ioemu/hw/ne2000.c
index e23c6df069..5fe383fb2a 100644
--- a/tools/ioemu/hw/ne2000.c
+++ b/tools/ioemu/hw/ne2000.c
@@ -137,6 +137,7 @@ typedef struct NE2000State {
uint8_t curpag;
uint8_t mult[8]; /* multicast mask array */
int irq;
+ int tainted;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
@@ -226,6 +227,27 @@ static int ne2000_can_receive(void *opaque)
#define MIN_BUF_SIZE 60
+static inline int ne2000_valid_ring_addr(NE2000State *s, unsigned int addr)
+{
+ addr <<= 8;
+ return addr < s->stop && addr >= s->start;
+}
+
+static inline int ne2000_check_state(NE2000State *s)
+{
+ if (!s->tainted)
+ return 0;
+
+ if (s->start >= s->stop || s->stop > NE2000_MEM_SIZE)
+ return -EINVAL;
+
+ if (!ne2000_valid_ring_addr(s, s->curpag))
+ return -EINVAL;
+
+ s->tainted = 0;
+ return 0;
+}
+
static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
{
NE2000State *s = opaque;
@@ -239,6 +261,12 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
printf("NE2000: received len=%d\n", size);
#endif
+ if (ne2000_check_state(s))
+ return;
+
+ if (!ne2000_valid_ring_addr(s, s->boundary))
+ return;
+
if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
return;
@@ -359,9 +387,11 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
switch(offset) {
case EN0_STARTPG:
s->start = val << 8;
+ s->tainted = 1;
break;
case EN0_STOPPG:
s->stop = val << 8;
+ s->tainted = 1;
break;
case EN0_BOUNDARY:
s->boundary = val;
@@ -406,6 +436,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
break;
case EN1_CURPAG:
s->curpag = val;
+ s->tainted = 1;
break;
case EN1_MULT ... EN1_MULT + 7:
s->mult[offset - EN1_MULT] = val;
@@ -509,7 +540,7 @@ static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+ (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
}
}
@@ -539,7 +570,7 @@ static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+ (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) {
return le32_to_cpupu((uint32_t *)(s->mem + addr));
} else {
return 0xffffffff;
diff --git a/tools/ioemu/hw/pc.c b/tools/ioemu/hw/pc.c
index 5b5fd42abf..234c4722bb 100644
--- a/tools/ioemu/hw/pc.c
+++ b/tools/ioemu/hw/pc.c
@@ -875,6 +875,9 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, char *boot_device,
}
}
+ if (has_tpm_device())
+ tpm_tis_init(&pic_set_irq_new, isa_pic, 11);
+
kbd_init();
DMA_init(0);
#ifdef HAS_AUDIO
diff --git a/tools/ioemu/hw/pci.c b/tools/ioemu/hw/pci.c
index 77737c8615..cea81f7b7f 100644
--- a/tools/ioemu/hw/pci.c
+++ b/tools/ioemu/hw/pci.c
@@ -221,16 +221,23 @@ uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len)
{
uint32_t val;
+
switch(len) {
- case 1:
- val = d->config[address];
- break;
- case 2:
- val = le16_to_cpu(*(uint16_t *)(d->config + address));
- break;
default:
case 4:
- val = le32_to_cpu(*(uint32_t *)(d->config + address));
+ if (address <= 0xfc) {
+ val = le32_to_cpu(*(uint32_t *)(d->config + address));
+ break;
+ }
+ /* fall through */
+ case 2:
+ if (address <= 0xfe) {
+ val = le16_to_cpu(*(uint16_t *)(d->config + address));
+ break;
+ }
+ /* fall through */
+ case 1:
+ val = d->config[address];
break;
}
return val;
@@ -333,7 +340,8 @@ void pci_default_write_config(PCIDevice *d,
d->config[addr] = val;
}
- addr++;
+ if (++addr > 0xff)
+ break;
val >>= 8;
}
diff --git a/tools/ioemu/hw/piix4acpi.c b/tools/ioemu/hw/piix4acpi.c
index 7b75d01c64..aabd5ca7e9 100644
--- a/tools/ioemu/hw/piix4acpi.c
+++ b/tools/ioemu/hw/piix4acpi.c
@@ -398,8 +398,16 @@ void pci_piix4_acpi_init(PCIBus *bus, int devfn)
pci_conf[0x0e] = 0x00;
pci_conf[0x3d] = 0x01; /* Hardwired to PIRQA is used */
- pci_register_io_region((PCIDevice *)d, 4, 0x10,
- PCI_ADDRESS_SPACE_IO, acpi_map);
+ /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40
+ * to make shutdown work for IPF, due to IPF Guest Firmware
+ * will enumerate pci devices.
+ *
+ * TODO: if Guest Firmware or Guest OS will change this PMBA,
+ * More logic will be added.
+ */
+ pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */
+ pci_conf[0x41] = 0x1f;
+ acpi_map(d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO);
acpi_reset(d);
}
diff --git a/tools/ioemu/hw/piix_pci.c b/tools/ioemu/hw/piix_pci.c
index 051e082263..497d66898c 100644
--- a/tools/ioemu/hw/piix_pci.c
+++ b/tools/ioemu/hw/piix_pci.c
@@ -338,10 +338,14 @@ static void pci_bios_init_device(PCIDevice *d)
break;
case 0x0680:
if (vendor_id == 0x8086 && device_id == 0x7113) {
- /* PIIX4 ACPI PM */
- pci_config_writew(d, 0x20, 0x0000); /* NO smb bus IO enable in PIIX4 */
+ /*
+ * PIIX4 ACPI PM.
+ * Special device with special PCI config space. No ordinary BARs.
+ */
+ pci_config_writew(d, 0x20, 0x0000); // No smb bus IO enable
pci_config_writew(d, 0x22, 0x0000);
- goto default_map;
+ pci_config_writew(d, 0x3c, 0x0009); // Hardcoded IRQ9
+ pci_config_writew(d, 0x3d, 0x0001);
}
break;
case 0x0300:
@@ -394,14 +398,6 @@ static void pci_bios_init_device(PCIDevice *d)
pic_irq = pci_irqs[pin];
pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
}
-
- if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) {
- // PIIX4 ACPI PM
- pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4
- pci_config_writew(d, 0x22, 0x0000);
- pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9
- pci_config_writew(d, 0x3d, 0x0001);
- }
}
/*
diff --git a/tools/ioemu/hw/rtl8139.c b/tools/ioemu/hw/rtl8139.c
index c704ab8360..77e3c6d9fb 100644
--- a/tools/ioemu/hw/rtl8139.c
+++ b/tools/ioemu/hw/rtl8139.c
@@ -1999,12 +1999,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
}
- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+ if (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
{
- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+ free(s->cplus_txbuffer);
+ s->cplus_txbuffer = NULL;
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
+ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space exceeded: %d\n", s->cplus_txbuffer_offset + txsize));
}
if (!s->cplus_txbuffer)
diff --git a/tools/ioemu/hw/serial.c b/tools/ioemu/hw/serial.c
index f36beb209f..b99e774eae 100644
--- a/tools/ioemu/hw/serial.c
+++ b/tools/ioemu/hw/serial.c
@@ -22,6 +22,9 @@
* THE SOFTWARE.
*/
#include "vl.h"
+#include <sys/time.h>
+#include <time.h>
+#include <assert.h>
//#define DEBUG_SERIAL
@@ -70,6 +73,11 @@
#define UART_LSR_OE 0x02 /* Overrun error indicator */
#define UART_LSR_DR 0x01 /* Receiver data ready */
+/* Maximum retries for a single byte transmit. */
+#define WRITE_MAX_SINGLE_RETRIES 3
+/* Maximum retries for a sequence of back-to-back unsuccessful transmits. */
+#define WRITE_MAX_TOTAL_RETRIES 10
+
struct SerialState {
uint8_t divider;
uint8_t rbr; /* receive register */
@@ -90,6 +98,19 @@ struct SerialState {
int last_break_enable;
target_ulong base;
int it_shift;
+
+ /*
+ * If a character transmitted via UART cannot be written to its
+ * destination immediately we remember it here and retry a few times via
+ * a polling timer.
+ * - write_single_retries: Number of write retries for current byte.
+ * - write_total_retries: Number of write retries for back-to-back
+ * unsuccessful transmits.
+ */
+ int write_single_retries;
+ int write_total_retries;
+ char write_chr;
+ QEMUTimer *write_retry_timer;
};
static void serial_update_irq(SerialState *s)
@@ -140,10 +161,98 @@ static void serial_update_parameters(SerialState *s)
#endif
}
+/* Rate limit serial requests so that e.g. grub on a serial console
+ doesn't kill dom0. Simple token bucket. If we get some actual
+ data from the user, instantly refil the bucket. */
+
+/* How long it takes to generate a token, in microseconds. */
+#define TOKEN_PERIOD 1000
+/* Maximum and initial size of token bucket */
+#define TOKENS_MAX 100000
+
+static int tokens_avail;
+
+static void serial_get_token(void)
+{
+ static struct timeval last_refil_time;
+ static int started;
+
+ assert(tokens_avail >= 0);
+ if (!tokens_avail) {
+ struct timeval delta, now;
+ int generated;
+
+ if (!started) {
+ gettimeofday(&last_refil_time, NULL);
+ tokens_avail = TOKENS_MAX;
+ started = 1;
+ return;
+ }
+ retry:
+ gettimeofday(&now, NULL);
+ delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
+ delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
+ if (delta.tv_usec < 0) {
+ delta.tv_usec += 1000000;
+ delta.tv_sec--;
+ }
+ assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
+ if (delta.tv_usec < TOKEN_PERIOD) {
+ struct timespec ts;
+ /* Wait until at least one token is available. */
+ ts.tv_sec = TOKEN_PERIOD / 1000000;
+ ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
+ while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+ ;
+ goto retry;
+ }
+ generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
+ generated +=
+ ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
+ assert(generated > 0);
+
+ last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
+ last_refil_time.tv_sec += last_refil_time.tv_usec / 1000000;
+ last_refil_time.tv_usec %= 1000000;
+ last_refil_time.tv_sec += (generated * TOKEN_PERIOD) / 1000000;
+ if (generated > TOKENS_MAX)
+ generated = TOKENS_MAX;
+ tokens_avail = generated;
+ }
+ tokens_avail--;
+}
+
+static void serial_chr_write(void *opaque)
+{
+ SerialState *s = opaque;
+
+ /* Cancel any outstanding retry if this is a new byte. */
+ qemu_del_timer(s->write_retry_timer);
+
+ /* Retry every 100ms for 300ms total. */
+ if (qemu_chr_write(s->chr, &s->write_chr, 1) == -1) {
+ s->write_total_retries++;
+ if (s->write_single_retries++ >= WRITE_MAX_SINGLE_RETRIES)
+ fprintf(stderr, "serial: write error\n");
+ else if (s->write_total_retries <= WRITE_MAX_TOTAL_RETRIES) {
+ qemu_mod_timer(s->write_retry_timer,
+ qemu_get_clock(vm_clock) + ticks_per_sec / 10);
+ return;
+ }
+ } else {
+ s->write_total_retries = 0; /* if successful then reset counter */
+ }
+
+ /* Success: Notify guest that THR is empty. */
+ s->thr_ipending = 1;
+ s->lsr |= UART_LSR_THRE;
+ s->lsr |= UART_LSR_TEMT;
+ serial_update_irq(s);
+}
+
static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
SerialState *s = opaque;
- unsigned char ch;
addr &= 7;
#ifdef DEBUG_SERIAL
@@ -159,12 +268,9 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->thr_ipending = 0;
s->lsr &= ~UART_LSR_THRE;
serial_update_irq(s);
- ch = val;
- qemu_chr_write(s->chr, &ch, 1);
- s->thr_ipending = 1;
- s->lsr |= UART_LSR_THRE;
- s->lsr |= UART_LSR_TEMT;
- serial_update_irq(s);
+ s->write_chr = val;
+ s->write_single_retries = 0;
+ serial_chr_write(s);
}
break;
case 1:
@@ -245,9 +351,11 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
ret = s->mcr;
break;
case 5:
+ serial_get_token();
ret = s->lsr;
break;
case 6:
+ serial_get_token();
if (s->mcr & UART_MCR_LOOP) {
/* in loopback, the modem output pins are connected to the
inputs */
@@ -296,12 +404,14 @@ static int serial_can_receive1(void *opaque)
static void serial_receive1(void *opaque, const uint8_t *buf, int size)
{
SerialState *s = opaque;
+ tokens_avail = TOKENS_MAX;
serial_receive_byte(s, buf[0]);
}
static void serial_event(void *opaque, int event)
{
SerialState *s = opaque;
+ tokens_avail = TOKENS_MAX;
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
@@ -356,6 +466,7 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
s->iir = UART_IIR_NO_INT;
s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+ s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s);
register_savevm("serial", base, 1, serial_save, serial_load, s);
@@ -443,6 +554,7 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
s->base = base;
s->it_shift = it_shift;
+ s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s);
register_savevm("serial", base, 1, serial_save, serial_load, s);
diff --git a/tools/ioemu/hw/tpm_tis.c b/tools/ioemu/hw/tpm_tis.c
new file mode 100644
index 0000000000..a4d07bc67f
--- /dev/null
+++ b/tools/ioemu/hw/tpm_tis.c
@@ -0,0 +1,1114 @@
+/*
+ * tpm_tis.c - QEMU emulator for a 1.2 TPM with TIS interface
+ *
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ * David Safford <safford@us.ibm.com>
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ *
+ * Implementation of the TIS interface according to specs at
+ * https://www.trustedcomputinggroup.org/groups/pc_client/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "vl.h"
+
+//#define DEBUG_TPM
+
+#define TPM_MAX_PKT 4096
+
+#define VTPM_BAD_INSTANCE (uint32_t)0xffffffff
+
+#define TIS_ADDR_BASE 0xFED40000
+
+/* tis registers */
+#define TPM_REG_ACCESS 0x00
+#define TPM_REG_INT_ENABLE 0x08
+#define TPM_REG_INT_VECTOR 0x0c
+#define TPM_REG_INT_STATUS 0x10
+#define TPM_REG_INTF_CAPABILITY 0x14
+#define TPM_REG_STS 0x18
+#define TPM_REG_DATA_FIFO 0x24
+#define TPM_REG_DID_VID 0xf00
+#define TPM_REG_RID 0xf04
+
+#define STS_VALID (1 << 7)
+#define STS_COMMAND_READY (1 << 6)
+#define STS_TPM_GO (1 << 5)
+#define STS_DATA_AVAILABLE (1 << 4)
+#define STS_EXPECT (1 << 3)
+#define STS_RESPONSE_RETRY (1 << 1)
+
+#define ACCESS_TPM_REG_VALID_STS (1 << 7)
+#define ACCESS_ACTIVE_LOCALITY (1 << 5)
+#define ACCESS_BEEN_SEIZED (1 << 4)
+#define ACCESS_SEIZE (1 << 3)
+#define ACCESS_PENDING_REQUEST (1 << 2)
+#define ACCESS_REQUEST_USE (1 << 1)
+#define ACCESS_TPM_ESTABLISHMENT (1 << 0)
+
+#define INT_ENABLED (1 << 31)
+#define INT_DATA_AVAILABLE (1 << 0)
+#define INT_LOCALITY_CHANGED (1 << 2)
+#define INT_COMMAND_READY (1 << 7)
+
+#define INTERRUPTS_SUPPORTED (INT_LOCALITY_CHANGED | \
+ INT_DATA_AVAILABLE | \
+ INT_COMMAND_READY)
+#define CAPABILITIES_SUPPORTED ((1 << 4) | \
+ INTERRUPTS_SUPPORTED)
+
+enum {
+ STATE_IDLE = 0,
+ STATE_READY,
+ STATE_COMPLETION,
+ STATE_EXECUTION,
+ STATE_RECEPTION
+};
+
+#define NUM_LOCALITIES 5
+#define NO_LOCALITY 0xff
+
+#define IS_VALID_LOC(x) ((x) < NUM_LOCALITIES)
+
+#define TPM_DID 0x0001
+#define TPM_VID 0x0001
+#define TPM_RID 0x0001
+
+/* if the connection to the vTPM should be closed after a successfully
+ received response; set to '0' to allow keeping the connection */
+#define FORCE_CLOSE 0
+
+/* local data structures */
+
+typedef struct TPMTx {
+ int fd[2];
+} tpmTx;
+
+typedef struct TPMBuffer {
+ uint8_t instance[4]; /* instance number in network byte order */
+ uint8_t buf[TPM_MAX_PKT];
+} __attribute__((packed)) tpmBuffer;
+
+/* locality data */
+typedef struct TPMLocal {
+ uint32_t state;
+ uint8_t access;
+ uint8_t sts;
+ uint32_t inte;
+ uint32_t ints;
+} tpmLoc;
+
+/* overall state of the TPM interface; 's' marks as save upon suspension */
+typedef struct TPMState {
+ uint32_t offset; /* s */
+ tpmBuffer buffer; /* s */
+ uint8_t active_loc; /* s */
+ uint8_t aborting_locty;
+ uint8_t next_locty;
+ uint8_t irq_pending; /* s */
+ tpmLoc loc[NUM_LOCALITIES]; /* s */
+ QEMUTimer *poll_timer;
+ SetIRQFunc *set_irq;
+ void *irq_opaque;
+ int irq;
+ int poll_attempts;
+ uint32_t vtpm_instance; /* vtpm inst. number; determined from xenstore*/
+ int Transmitlayer;
+ tpmTx tpmTx;
+} tpmState;
+
+
+/* local prototypes */
+static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg);
+static int TPM_Receive(tpmState *s, tpmBuffer *buffer);
+static uint32_t vtpm_instance_from_xenstore(void);
+static void tis_poll_timer(void *opaque);
+static void tis_prep_next_interrupt(tpmState *s);
+static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask);
+static void close_vtpm_channel(tpmState *s, int force);
+static void open_vtpm_channel(tpmState *s);
+static void tis_attempt_receive(tpmState *s, uint8_t locty);
+
+/* transport layer functions: local sockets */
+static int create_local_socket(tpmState *s, uint32_t vtpm_instance);
+static int write_local_socket(tpmState *s, const tpmBuffer *);
+static int read_local_socket(tpmState *s, tpmBuffer *);
+static int close_local_socket(tpmState *s, int force);
+static int has_channel_local_socket(tpmState *s);
+#define LOCAL_SOCKET_PATH "/var/vtpm/vtpm_all.socket"
+
+
+#define NUM_TRANSPORTS 1
+
+struct vTPM_transmit {
+ int (*open) (tpmState *s, uint32_t vtpm_instance);
+ int (*write) (tpmState *s, const tpmBuffer *);
+ int (*read) (tpmState *s, tpmBuffer *);
+ int (*close) (tpmState *s, int);
+ int (*has_channel) (tpmState *s);
+} vTPMTransmit[NUM_TRANSPORTS] = {
+ { .open = create_local_socket,
+ .write = write_local_socket,
+ .read = read_local_socket,
+ .close = close_local_socket,
+ .has_channel = has_channel_local_socket,
+ }
+};
+
+
+#define IS_COMM_WITH_VTPM(s) \
+ ((s)->Transmitlayer >= 0 && \
+ vTPMTransmit[(s)->Transmitlayer].has_channel(s))
+
+
+/**********************************************************************
+ helper functions
+ *********************************************************************/
+
+static inline uint32_t tpm_get_size_from_buffer(const uint8_t *buffer)
+{
+ uint32_t len = (buffer[4] << 8) + buffer[5];
+ return len;
+}
+
+static inline void tpm_initialize_instance(tpmState *s, uint32_t instance)
+{
+ s->buffer.instance[0] = (instance >> 24) & 0xff;
+ s->buffer.instance[1] = (instance >> 16) & 0xff;
+ s->buffer.instance[2] = (instance >> 8) & 0xff;
+ s->buffer.instance[3] = (instance >> 0) & 0xff;
+}
+
+/*
+ * open communication channel with a vTPM
+ */
+static void open_vtpm_channel(tpmState *s)
+{
+ int idx;
+ /* search a usable transmit layer */
+ for (idx = 0; idx < NUM_TRANSPORTS; idx++) {
+ if (1 == vTPMTransmit[idx].open(s, s->vtpm_instance)) {
+ /* found one */
+ s->Transmitlayer = idx;
+ break;
+ }
+ }
+}
+
+/*
+ * close the communication channel with the vTPM
+ */
+static inline void close_vtpm_channel(tpmState *s, int force)
+{
+ if (1 == vTPMTransmit[s->Transmitlayer].close(s, force)) {
+ s->Transmitlayer = -1;
+ }
+}
+
+static inline uint8_t locality_from_addr(target_phys_addr_t addr)
+{
+ return (uint8_t)((addr >> 12) & 0x7);
+}
+
+
+/**********************************************************************
+ low-level transmission layer methods
+ *********************************************************************/
+
+/*
+ * the 'open' method that creates the filedescriptor for communicating
+ * only one is needed for reading and writing
+ */
+static int create_local_socket(tpmState *s, uint32_t vtpm_instance)
+{
+ int success = 1;
+ if (s->tpmTx.fd[0] < 0) {
+ s->tpmTx.fd[0] = socket(PF_LOCAL, SOCK_STREAM, 0);
+
+ if (has_channel_local_socket(s)) {
+ struct sockaddr_un addr;
+ memset(&addr, 0x0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ strcpy(addr.sun_path, LOCAL_SOCKET_PATH);
+ if (connect(s->tpmTx.fd[0],
+ (struct sockaddr *)&addr,
+ sizeof(addr)) != 0) {
+ close_local_socket(s, 1);
+ success = 0;
+ } else {
+ /* put filedescriptor in non-blocking mode for polling */
+ int flags = fcntl(s->tpmTx.fd[0], F_GETFL);
+ fcntl(s->tpmTx.fd[0], F_SETFL, flags | O_NONBLOCK);
+ }
+#ifdef DEBUG_TPM
+ if (success)
+ fprintf(logfile,"Successfully connected using local socket "
+ LOCAL_SOCKET_PATH ".\n");
+ else
+ fprintf(logfile,"Could not connect to local socket "
+ LOCAL_SOCKET_PATH ".\n");
+#endif
+ } else {
+ success = 0;
+ }
+ }
+ return success;
+}
+
+/*
+ * the 'write' method for sending requests to the vTPM
+ * four bytes with the vTPM instance number are prepended to each request
+ */
+static int write_local_socket(tpmState *s, const tpmBuffer *buffer)
+{
+ uint32_t size = tpm_get_size_from_buffer(buffer->buf);
+ int len;
+
+ len = write(s->tpmTx.fd[0],
+ buffer->instance,
+ sizeof(buffer->instance) + size);
+ if (len == sizeof(buffer->instance) + size) {
+ return len;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * the 'read' method for receiving of responses from the TPM
+ * this function expects that four bytes with the instance number
+ * are received from the vTPM
+ */
+static int read_local_socket(tpmState *s, tpmBuffer *buffer)
+{
+ int off;
+#ifdef DEBUG_TPM
+ fprintf(logfile, "Reading from fd %d\n", s->tpmTx.fd[0]);
+#endif
+ off = read(s->tpmTx.fd[0],
+ buffer->instance,
+ sizeof(buffer->instance)+TPM_MAX_PKT);
+#ifdef DEBUG_TPM
+ fprintf(logfile, "Read %d bytes\n", off);
+#endif
+ return off;
+}
+
+/*
+ * the 'close' method
+ * shut down communication with the vTPM
+ * 'force' = 1 indicates that the socket *must* be closed
+ * 'force' = 0 indicates that a connection may be maintained
+ */
+static int close_local_socket(tpmState *s, int force)
+{
+ if (force) {
+ close(s->tpmTx.fd[0]);
+#ifdef DEBUG_TPM
+ fprintf(logfile,"Closed connection with fd %d\n",s->tpmTx.fd[0]);
+#endif
+ s->tpmTx.fd[0] = -1;
+ return 1; /* socket was closed */
+ }
+#ifdef DEBUG_TPM
+ fprintf(logfile,"Keeping connection with fd %d\n",s->tpmTx.fd[0]);
+#endif
+ return 0;
+}
+
+/*
+ * the 'has_channel' method that checks whether there's a communication
+ * channel with the vTPM
+ */
+static int has_channel_local_socket(tpmState *s)
+{
+ return (s->tpmTx.fd[0] > 0);
+}
+
+/**********************************************************************/
+
+/*
+ * read a byte of response data
+ */
+static uint32_t tpm_data_read(tpmState *s, uint8_t locty)
+{
+ uint32_t ret, len;
+
+ /* try to receive data, if none are there it is ok */
+ tis_attempt_receive(s, locty);
+
+ if (s->loc[locty].state != STATE_COMPLETION) {
+ return 0xff;
+ }
+
+ len = tpm_get_size_from_buffer(s->buffer.buf);
+ ret = s->buffer.buf[s->offset++];
+ if (s->offset >= len) {
+ s->loc[locty].sts = STS_VALID ;
+ s->offset = 0;
+ }
+#ifdef DEBUG_TPM
+ fprintf(logfile,"tpm_data_read byte x%02x [%d]\n",ret,s->offset-1);
+#endif
+ return ret;
+}
+
+
+
+/* raise an interrupt if allowed */
+static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask)
+{
+ if (!s->irq_pending &&
+ (s->loc[locty].inte & INT_ENABLED) &&
+ (s->loc[locty].inte & irqmask)) {
+ if ((irqmask & s->loc[locty].ints) == 0) {
+#ifdef DEBUG_TPM
+ fprintf(logfile,"Raising IRQ for flag %08x\n",irqmask);
+#endif
+ s->set_irq(s->irq_opaque, s->irq, 1);
+ s->irq_pending = 1;
+ s->loc[locty].ints |= irqmask;
+ }
+ }
+}
+
+/* abort execution of command */
+static void tis_abort(tpmState *s)
+{
+ s->offset = 0;
+ s->active_loc = s->next_locty;
+
+ /*
+ * Need to react differently depending on who's aborting now and
+ * which locality will become active afterwards.
+ */
+ if (s->aborting_locty == s->next_locty) {
+ s->loc[s->aborting_locty].state = STATE_READY;
+ s->loc[s->aborting_locty].sts = STS_COMMAND_READY;
+ tis_raise_irq(s, s->aborting_locty, INT_COMMAND_READY);
+ }
+
+ /* locality after abort is another one than the current one */
+ if (s->aborting_locty != s->next_locty && s->next_locty != NO_LOCALITY) {
+ s->loc[s->aborting_locty].access &= ~ACCESS_ACTIVE_LOCALITY;
+ s->loc[s->next_locty].access |= ACCESS_ACTIVE_LOCALITY;
+ tis_raise_irq(s, s->next_locty, INT_LOCALITY_CHANGED);
+ }
+
+ s->aborting_locty = NO_LOCALITY; /* nobody's aborting a command anymore */
+
+ qemu_del_timer(s->poll_timer);
+}
+
+/* abort current command */
+static void tis_prep_abort(tpmState *s, uint8_t locty, uint8_t newlocty)
+{
+ s->aborting_locty = locty; /* current locality */
+ s->next_locty = newlocty; /* locality after successful abort */
+
+ /*
+ * only abort a command using an interrupt if currently executing
+ * a command AND if there's a valid connection to the vTPM.
+ */
+ if (s->loc[locty].state == STATE_EXECUTION &&
+ IS_COMM_WITH_VTPM(s)) {
+ /* start timer and inside the timer wait for the result */
+ s->poll_attempts = 0;
+ tis_prep_next_interrupt(s);
+ } else {
+ tis_abort(s);
+ }
+}
+
+
+/*
+ * Try to receive a response from the vTPM
+ */
+static void tis_attempt_receive(tpmState *s, uint8_t locty)
+{
+ /*
+ * Attempt to read from the vTPM here if
+ * - not aborting a command
+ * - command has been sent and state is 'EXECUTION' now
+ * - no data are already available (data have already been read)
+ * - there's a communication path to the vTPM established
+ */
+ if (!IS_VALID_LOC(s->aborting_locty)) {
+ if (s->loc[locty].state == STATE_EXECUTION) {
+ if (0 == (s->loc[locty].sts & STS_DATA_AVAILABLE)){
+ if (IS_COMM_WITH_VTPM(s)) {
+ int n = TPM_Receive(s, &s->buffer);
+ if (n > 0) {
+ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;
+ s->loc[locty].state = STATE_COMPLETION;
+ close_vtpm_channel(s, FORCE_CLOSE);
+ tis_raise_irq(s, locty, INT_DATA_AVAILABLE);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Read a register of the TIS interface
+ * See specs pages 33-63 for description of the registers
+ */
+static uint32_t tis_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ tpmState *s = (tpmState *)opaque;
+ uint16_t offset = addr & 0xffc;
+ uint8_t shift = (addr & 0x3) * 8;
+ uint32_t val = 0;
+ uint8_t locty = locality_from_addr(addr);
+
+ if (offset == TPM_REG_ACCESS) {
+ if (s->active_loc == locty) {
+ s->loc[locty].access |= (1 << 5);
+ } else {
+ s->loc[locty].access &= ~(1 << 5);
+ }
+ val = s->loc[locty].access;
+ } else
+ if (offset == TPM_REG_INT_ENABLE) {
+ val = s->loc[locty].inte;
+ } else
+ if (offset == TPM_REG_INT_VECTOR) {
+ val = s->irq;
+ } else
+ if (offset == TPM_REG_INT_STATUS) {
+ tis_attempt_receive(s, locty);
+ val = s->loc[locty].ints;
+ } else
+ if (offset == TPM_REG_INTF_CAPABILITY) {
+ val = CAPABILITIES_SUPPORTED;
+ } else
+ if (offset == TPM_REG_STS) { /* status register */
+ tis_attempt_receive(s, locty);
+ val = (sizeof(s->buffer.buf) - s->offset) << 8 | s->loc[locty].sts;
+ } else
+ if (offset == TPM_REG_DATA_FIFO) {
+ val = tpm_data_read(s, locty);
+ } else
+ if (offset == TPM_REG_DID_VID) {
+ val = (TPM_DID << 16) | TPM_VID;
+ } else
+ if (offset == TPM_REG_RID) {
+ val = TPM_RID;
+ }
+
+ if (shift)
+ val >>= shift;
+
+#ifdef DEBUG_TPM
+ fprintf(logfile," read(%08x) = %08x\n",
+ addr,
+ val);
+#endif
+
+ return val;
+}
+
+/*
+ * Write a value to a register of the TIS interface
+ * See specs pages 33-63 for description of the registers
+ */
+static void tis_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ tpmState* s=(tpmState*)opaque;
+ uint16_t off = addr & 0xfff;
+ uint8_t locty = locality_from_addr(addr);
+ int n, c;
+ uint32_t len;
+
+#ifdef DEBUG_TPM
+ fprintf(logfile,"write(%08x) = %08x\n",
+ addr,
+ val);
+#endif
+
+ if (off == TPM_REG_ACCESS) {
+ if (val & ACCESS_ACTIVE_LOCALITY) {
+ /* give up locality if currently owned */
+ if (s->active_loc == locty) {
+ uint8_t newlocty = NO_LOCALITY;
+ s->loc[locty].access &= ~(ACCESS_PENDING_REQUEST);
+ /* anybody wants the locality ? */
+ for (c = NUM_LOCALITIES - 1; c >= 0; c--) {
+ if (s->loc[c].access & ACCESS_REQUEST_USE) {
+ s->loc[c].access |= ACCESS_TPM_REG_VALID_STS;
+ s->loc[c].access &= ~ACCESS_REQUEST_USE;
+ newlocty = c;
+ break;
+ }
+ }
+ tis_prep_abort(s, locty, newlocty);
+ }
+ }
+ if (val & ACCESS_BEEN_SEIZED) {
+ /* clear the flag */
+ s->loc[locty].access &= ~ACCESS_BEEN_SEIZED;
+ }
+ if (val & ACCESS_SEIZE) {
+ if (locty > s->active_loc && IS_VALID_LOC(s->active_loc)) {
+ s->loc[s->active_loc].access |= ACCESS_BEEN_SEIZED;
+ s->loc[locty].access = ACCESS_TPM_REG_VALID_STS;
+ tis_prep_abort(s, s->active_loc, locty);
+ }
+ }
+ if (val & ACCESS_REQUEST_USE) {
+ if (IS_VALID_LOC(s->active_loc)) {
+ /* locality election */
+ s->loc[s->active_loc].access |= ACCESS_PENDING_REQUEST;
+ } else {
+ /* no locality active -> make this one active now */
+ s->loc[locty].access |= ACCESS_ACTIVE_LOCALITY;
+ s->active_loc = locty;
+ tis_raise_irq(s, locty, INT_LOCALITY_CHANGED);
+ }
+ }
+ } else
+ if (off == TPM_REG_INT_ENABLE) {
+ s->loc[locty].inte = (val & (INT_ENABLED | (0x3 << 3) |
+ INTERRUPTS_SUPPORTED));
+ } else
+ if (off == TPM_REG_INT_STATUS) {
+ /* clearing of interrupt flags */
+ if ((val & INTERRUPTS_SUPPORTED) &&
+ (s->loc[locty].ints & INTERRUPTS_SUPPORTED)) {
+ s->set_irq(s->irq_opaque, s->irq, 0);
+ s->irq_pending = 0;
+ }
+ s->loc[locty].ints &= ~(val & INTERRUPTS_SUPPORTED);
+ } else
+ if (off == TPM_REG_STS) {
+ if (val & STS_COMMAND_READY) {
+ if (s->loc[locty].state == STATE_IDLE) {
+ s->loc[locty].sts = STS_COMMAND_READY;
+ s->loc[locty].state = STATE_READY;
+ tis_raise_irq(s, locty, INT_COMMAND_READY);
+ } else if (s->loc[locty].state == STATE_COMPLETION ||
+ s->loc[locty].state == STATE_EXECUTION ||
+ s->loc[locty].state == STATE_RECEPTION) {
+ /* abort currently running command */
+ tis_prep_abort(s, locty, locty);
+ }
+ }
+ if (val & STS_TPM_GO) {
+ n = TPM_Send(s, &s->buffer,"tpm_data_write");
+ if (n > 0) {
+ /* sending of data was successful */
+ s->offset = 0;
+ s->loc[locty].state = STATE_EXECUTION;
+ if (s->loc[locty].inte & (INT_ENABLED | INT_DATA_AVAILABLE)) {
+ s->poll_attempts = 0;
+ tis_prep_next_interrupt(s);
+ }
+ }
+ }
+ if (val & STS_RESPONSE_RETRY) {
+ s->offset = 0;
+ }
+ } else if (off == TPM_REG_DATA_FIFO) {
+ /* data fifo */
+ if (s->loc[locty].state == STATE_IDLE ||
+ s->loc[locty].state == STATE_EXECUTION ||
+ s->loc[locty].state == STATE_COMPLETION) {
+ /* drop the byte */
+ } else {
+#ifdef TPM_DEBUG
+ fprintf(logfile,"Byte to send to TPM: %02x\n", val);
+#endif
+ s->loc[locty].state = STATE_RECEPTION;
+
+ if (s->offset < sizeof(s->buffer.buf))
+ s->buffer.buf[s->offset++] = (uint8_t)val;
+
+ if (s->offset > 5) {
+ /* we have a packet length - see if we have all of it */
+ len = tpm_get_size_from_buffer(s->buffer.buf);
+ if (len > s->offset) {
+ s->loc[locty].sts = STS_EXPECT | STS_VALID;
+ } else {
+ s->loc[locty].sts = STS_VALID;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Prepare the next interrupt for example after a command has
+ * been sent out for the purpose of receiving the response.
+ * Depending on how many interrupts (used for polling on the fd) have
+ * already been schedule, this function determines the delta in time
+ * to the next interrupt. This accomodates for commands that finish
+ * quickly.
+ */
+static void tis_prep_next_interrupt(tpmState *s)
+{
+ int64_t expiration;
+ int rate = 5; /* 5 times per second */
+
+ /*
+ poll often at the beginning for quickly finished commands,
+ then back off
+ */
+ if (s->poll_attempts < 5) {
+ rate = 20;
+ } else if (s->poll_attempts < 10) {
+ rate = 10;
+ }
+
+ expiration = qemu_get_clock(vm_clock) + (ticks_per_sec / rate);
+ qemu_mod_timer(s->poll_timer, expiration);
+ s->poll_attempts++;
+}
+
+
+/*
+ * The polling routine called when the 'timer interrupt' fires.
+ * Tries to receive a command from the vTPM.
+ */
+static void tis_poll_timer(void *opaque)
+{
+ tpmState* s=(tpmState*)opaque;
+ uint8_t locty = s->active_loc;
+
+ if (!IS_VALID_LOC(locty) ||
+ (!(s->loc[locty].inte & INT_ENABLED) &&
+ (s->aborting_locty != NO_LOCALITY)) ||
+ !IS_COMM_WITH_VTPM(s)) {
+ /* no more interrupts requested, so no more polling needed */
+ qemu_del_timer(s->poll_timer);
+ }
+
+ if (!IS_COMM_WITH_VTPM(s)) {
+ if (s->aborting_locty != NO_LOCALITY) {
+ tis_abort(s);
+ }
+ return;
+ }
+
+ if (s->aborting_locty != NO_LOCALITY) {
+ int n = TPM_Receive(s, &s->buffer);
+#ifdef DEBUG_TPM
+ fprintf(logfile,"Receiving for abort.\n");
+#endif
+ if (n > 0) {
+ close_vtpm_channel(s, FORCE_CLOSE);
+ tis_abort(s);
+#ifdef DEBUG_TPM
+ fprintf(logfile,"Abort is complete.\n");
+#endif
+ } else {
+ tis_prep_next_interrupt(s);
+ }
+ } else if (IS_VALID_LOC(locty)) {
+ if (s->loc[locty].state == STATE_EXECUTION) {
+ /* poll for result */
+ int n = TPM_Receive(s, &s->buffer);
+ if (n > 0) {
+ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;
+ s->loc[locty].state = STATE_COMPLETION;
+ close_vtpm_channel(s, FORCE_CLOSE);
+ tis_raise_irq(s, locty, INT_DATA_AVAILABLE);
+ } else {
+ /* nothing received */
+ tis_prep_next_interrupt(s);
+ }
+ }
+ }
+}
+
+
+static CPUReadMemoryFunc *tis_readfn[3]={
+ tis_mem_readl,
+ tis_mem_readl,
+ tis_mem_readl
+};
+
+static CPUWriteMemoryFunc *tis_writefn[3]={
+ tis_mem_writel,
+ tis_mem_writel,
+ tis_mem_writel
+};
+
+/*
+ * Save the internal state of this interface for later resumption.
+ * Need to get any outstanding responses from the vTPM back, so
+ * this might delay the suspend for a while.
+ */
+static void tpm_save(QEMUFile* f,void* opaque)
+{
+ tpmState* s=(tpmState*)opaque;
+ int c;
+
+ /* need to wait for outstanding requests to complete */
+ if (IS_COMM_WITH_VTPM(s)) {
+ int repeats = 30; /* 30 seconds; really should be infty */
+ while (repeats > 0 &&
+ !(s->loc[s->active_loc].sts & STS_DATA_AVAILABLE)) {
+ int n = TPM_Receive(s, &s->buffer);
+ if (n > 0) {
+ if (IS_VALID_LOC(s->active_loc)) {
+ s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE;
+ }
+ /* close the connection with the vTPM for good */
+ close_vtpm_channel(s, 1);
+ break;
+ }
+ sleep(1);
+ }
+ }
+
+ qemu_put_be32s(f,&s->offset);
+ qemu_put_buffer(f, s->buffer.buf, TPM_MAX_PKT);
+ qemu_put_8s(f, &s->active_loc);
+ qemu_put_8s(f, &s->irq_pending);
+ for (c = 0; c < NUM_LOCALITIES; c++) {
+ qemu_put_be32s(f, &s->loc[c].state);
+ qemu_put_8s(f, &s->loc[c].access);
+ qemu_put_8s(f, &s->loc[c].sts);
+ qemu_put_be32s(f, &s->loc[c].inte);
+ qemu_put_be32s(f, &s->loc[c].ints);
+ }
+}
+
+/*
+ * load TIS interface state
+ */
+static int tpm_load(QEMUFile* f,void* opaque,int version_id)
+{
+ tpmState* s=(tpmState*)opaque;
+ int c;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f,&s->offset);
+ qemu_get_buffer(f, s->buffer.buf, TPM_MAX_PKT);
+ qemu_get_8s(f, &s->active_loc);
+ qemu_get_8s(f, &s->irq_pending);
+ for (c = 0; c < NUM_LOCALITIES; c++) {
+ qemu_get_be32s(f, &s->loc[c].state);
+ qemu_get_8s(f, &s->loc[c].access);
+ qemu_get_8s(f, &s->loc[c].sts);
+ qemu_get_be32s(f, &s->loc[c].inte);
+ qemu_get_be32s(f, &s->loc[c].ints);
+ }
+
+ /* need to be able to get the instance number from the xenstore */
+ s->vtpm_instance = vtpm_instance_from_xenstore();
+ if (s->vtpm_instance == VTPM_BAD_INSTANCE)
+ return -EINVAL;
+ tpm_initialize_instance(s, s->vtpm_instance);
+
+ return 0;
+}
+
+
+typedef struct LPCtpmState {
+ tpmState tpm;
+ int mem;
+} LPCtpmState;
+
+
+/*
+ * initialize TIS interface
+ */
+void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq)
+{
+ LPCtpmState *d;
+ tpmState *s;
+ int c = 0;
+ uint32_t vtpm_in;
+
+ vtpm_in = vtpm_instance_from_xenstore();
+ /* no valid vtpm instance -> no device */
+ if (vtpm_in == VTPM_BAD_INSTANCE)
+ return;
+
+ d = qemu_mallocz(sizeof(LPCtpmState));
+ d->mem = cpu_register_io_memory(0, tis_readfn, tis_writefn, d);
+
+ if (d->mem == -1) {
+ return;
+ }
+
+ cpu_register_physical_memory(TIS_ADDR_BASE,
+ 0x1000 * NUM_LOCALITIES, d->mem);
+
+ /* initialize tpmState */
+ s = &d->tpm;
+
+ s->offset = 0;
+ s->active_loc = NO_LOCALITY;
+
+ while (c < NUM_LOCALITIES) {
+ s->loc[c].access = (1 << 7);
+ s->loc[c].sts = 0;
+ s->loc[c].inte = (1 << 3);
+ s->loc[c].ints = 0;
+ s->loc[c].state = STATE_IDLE;
+ c++;
+ }
+ s->poll_timer = qemu_new_timer(vm_clock, tis_poll_timer, s);
+ s->set_irq = set_irq;
+ s->irq_opaque = opaque;
+ s->irq = irq;
+ s->vtpm_instance = vtpm_in;
+ s->Transmitlayer = -1;
+ s->tpmTx.fd[0] = -1;
+ s->tpmTx.fd[1] = -1;
+
+ tpm_initialize_instance(s, s->vtpm_instance);
+ memset(s->buffer.buf,0,sizeof(s->buffer.buf));
+
+ register_savevm("tpm-tis", 0, 1, tpm_save, tpm_load, s);
+}
+
+/****************************************************************************/
+/* optional verbose logging of data to/from vtpm */
+/****************************************************************************/
+#ifdef DEBUG_TPM
+static void showBuff(unsigned char *buff, char *string)
+{
+ uint32_t i, len;
+
+ len = tpm_get_size_from_buffer(buff);
+ fprintf(logfile,"%s length = %d\n", string, len);
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16)) {
+ fprintf(logfile,"\n");
+ }
+ fprintf(logfile,"%.2X ", buff[i]);
+ }
+ fprintf(logfile,"\n");
+}
+#endif
+
+/****************************************************************************/
+/* Transmit request to TPM and read Response */
+/****************************************************************************/
+
+const static unsigned char tpm_failure[] = {
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x09
+};
+
+
+/*
+ * Send a TPM request.
+ */
+static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg)
+{
+ int len;
+ uint32_t size = tpm_get_size_from_buffer(buffer->buf);
+
+ /* try to establish a connection to the vTPM */
+ if ( !IS_COMM_WITH_VTPM(s)) {
+ open_vtpm_channel(s);
+ }
+
+ if ( !IS_COMM_WITH_VTPM(s)) {
+ unsigned char tag = buffer->buf[1];
+
+ /* there's a failure response from the TPM */
+ memcpy(buffer->buf, tpm_failure, sizeof(tpm_failure));
+ buffer->buf[1] = tag + 3;
+ if (IS_VALID_LOC(s->active_loc)) {
+ s->loc[s->active_loc].sts = STS_DATA_AVAILABLE | STS_VALID;
+ }
+#ifdef DEBUG_TPM
+ fprintf(logfile,"No TPM running!\n");
+#endif
+ /* the request went out ok. */
+ return sizeof(buffer->instance) + size;
+ }
+
+#ifdef DEBUG_TPM
+ showBuff(buffer->buf, "To TPM");
+#endif
+
+ len = vTPMTransmit[s->Transmitlayer].write(s, buffer);
+ if (len < 0) {
+ s->Transmitlayer = -1;
+ }
+ return len;
+}
+
+/*
+ * Try to receive data from the file descriptor. Since it is in
+ * non-blocking mode it is possible that no data are actually received -
+ * whatever calls this function needs to try again later.
+ */
+static int TPM_Receive(tpmState *s, tpmBuffer *buffer)
+{
+ int off;
+
+ off = vTPMTransmit[s->Transmitlayer].read(s, buffer);
+
+ if (off < 0) {
+ /* EAGAIN is set in errno due to non-blocking mode */
+ return -1;
+ }
+
+ if (off == 0) {
+#ifdef DEBUG_TPM
+ fprintf(logfile,"TPM GONE? errno=%d\n",errno);
+#endif
+ close_vtpm_channel(s, 1);
+ /* pretend that data are available */
+ if (IS_VALID_LOC(s->active_loc)) {
+ s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE;
+ s->loc[s->active_loc].state = STATE_COMPLETION;
+ tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE);
+ }
+ return -1;
+ }
+
+#ifdef DEBUG_TPM
+ if (off > sizeof(buffer->instance ) + 6) {
+ uint32_t size = tpm_get_size_from_buffer(buffer->buf);
+ if (size + sizeof(buffer->instance) != off) {
+ fprintf(logfile,"TPM: Packet size is bad! %d != %d\n",
+ size + sizeof(buffer->instance),
+ off);
+ } else {
+ uint32_t ret;
+ showBuff(buffer->buf, "From TPM");
+ ret = (buffer->buf[8])*256 + buffer->buf[9];
+ if (ret)
+ fprintf(logfile,"Receive failed with error %d\n", ret);
+ else
+ fprintf(logfile,"Receive succeeded. Got response of length %d (=%d)\n",
+ size, off);
+ }
+ }
+#endif
+
+ /* assuming reading in one chunk for now */
+ return off;
+}
+
+
+/****************************************************************************
+ Helper functions for reading data from the xenstore such as
+ reading virtual TPM instance information
+ ****************************************************************************/
+int has_tpm_device(void)
+{
+ int ret = 0;
+ struct xs_handle *handle = xs_daemon_open();
+ if (handle) {
+ ret = xenstore_domain_has_devtype(handle, "vtpm");
+ xs_daemon_close(handle);
+ }
+ return ret;
+}
+
+
+/*
+ * Wait until hotplug scripts have finished then read the vTPM instance
+ * number from the xenstore.
+ */
+static uint32_t vtpm_instance_from_xenstore(void)
+{
+ unsigned int num;
+ uint32_t number = VTPM_BAD_INSTANCE;
+ int end = 0;
+ char *token = "tok";
+ int subscribed = 0;
+ int ctr = 0;
+ fd_set readfds;
+
+ struct xs_handle *handle = xs_daemon_open();
+
+ FD_ZERO(&readfds);
+
+ if (handle) {
+ char **e = xenstore_domain_get_devices(handle, "vtpm", &num);
+ int fd = xs_fileno(handle);
+ FD_SET(fd, &readfds);
+ if (e) {
+ do {
+ struct timeval tv = {
+ .tv_sec = 30,
+ .tv_usec = 0,
+ };
+ /* need to make sure that the hotplug scripts have finished */
+ char *status = xenstore_read_hotplug_status(handle,
+ "vtpm",
+ e[0]);
+ if (status) {
+ if (!strcmp(status, "connected")) {
+ char *inst = xenstore_backend_read_variable(handle,
+ "vtpm",
+ e[0],
+ "instance");
+ if (1 != (sscanf(inst,"%d",&number)))
+ number = VTPM_BAD_INSTANCE;
+ free(inst);
+ } else {
+ fprintf(logfile,
+ "bad status '%s' from vtpm hotplug\n",
+ status);
+ }
+ free(status);
+ end = 1;
+ } else {
+ /* no status, yet */
+ int rc;
+ unsigned int nr;
+ char **f;
+
+ if (!subscribed) {
+ rc = xenstore_subscribe_to_hotplug_status(handle,
+ "vtpm",
+ e[0],
+ token);
+ if (rc != 0)
+ break;
+ subscribed = 1;
+ }
+ rc = select(fd+1, &readfds, NULL, NULL, &tv);
+ /* get what's available -- drain the fd */
+ f = xs_read_watch(handle, &nr);
+ ctr++;
+ free(f);
+ if (ctr > 2)
+ end = 1;
+ }
+ } while (end == 0);
+ free(e);
+ }
+ if (subscribed) {
+ /* clean up */
+ xenstore_unsubscribe_from_hotplug_status(handle,
+ "vtpm",
+ e[0],
+ token);
+ }
+ xs_daemon_close(handle);
+ }
+ if (number == VTPM_BAD_INSTANCE)
+ fprintf(logfile, "no valid vtpm instance");
+ else
+ fprintf(logfile,"vtpm instance:%d\n",number);
+ return number;
+}
diff --git a/tools/ioemu/hw/vga.c b/tools/ioemu/hw/vga.c
index bbe3e582a5..6b9317f048 100644
--- a/tools/ioemu/hw/vga.c
+++ b/tools/ioemu/hw/vga.c
@@ -1463,14 +1463,15 @@ void check_sse2(void)
*/
static void vga_draw_graphic(VGAState *s, int full_update)
{
- int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
+ int y1, y, update, linesize, y_start, double_scan, mask;
int width, height, shift_control, line_offset, bwidth;
ram_addr_t page0, page1;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
vga_draw_line_func *vga_draw_line;
-
+ ram_addr_t page_min, page_max;
+
full_update |= update_basic_params(s);
s->get_resolution(s, &width, &height);
@@ -1561,8 +1562,8 @@ static void vga_draw_graphic(VGAState *s, int full_update)
addr1 = (s->start_addr * 4);
bwidth = width * 4;
y_start = -1;
- page_min = 0x7fffffff;
- page_max = -1;
+ page_min = 0;
+ page_max = 0;
d = s->ds->data;
linesize = s->ds->linesize;
y1 = 0;
@@ -1592,9 +1593,9 @@ static void vga_draw_graphic(VGAState *s, int full_update)
if (update) {
if (y_start < 0)
y_start = y;
- if (page0 < page_min)
+ if (page_min == 0 || page0 < page_min)
page_min = page0;
- if (page1 > page_max)
+ if (page_max == 0 || page1 > page_max)
page_max = page1;
vga_draw_line(s, d, s->vram_ptr + addr, width);
if (s->cursor_draw_line)
diff --git a/tools/ioemu/hw/xen_platform.c b/tools/ioemu/hw/xen_platform.c
index 8b319858cb..a0e9f1e397 100644
--- a/tools/ioemu/hw/xen_platform.c
+++ b/tools/ioemu/hw/xen_platform.c
@@ -97,7 +97,8 @@ struct pci_config_header {
uint8_t bist; /* Built in self test */
uint32_t base_address_regs[6];
uint32_t reserved1;
- uint32_t reserved2;
+ uint16_t subsystem_vendor_id;
+ uint16_t subsystem_id;
uint32_t rom_addr;
uint32_t reserved3;
uint32_t reserved4;
@@ -116,16 +117,21 @@ void pci_xen_platform_init(PCIBus *bus)
d = pci_register_device(bus, "xen-platform", sizeof(PCIDevice), -1, NULL,
NULL);
pch = (struct pci_config_header *)d->config;
- pch->vendor_id = 0xfffd;
- pch->device_id = 0x0101;
+ pch->vendor_id = 0x5853;
+ pch->device_id = 0x0001;
pch->command = 3; /* IO and memory access */
- pch->revision = 0;
+ pch->revision = 1;
pch->api = 0;
pch->subclass = 0x80; /* Other */
pch->class = 0xff; /* Unclassified device class */
pch->header_type = 0;
pch->interrupt_pin = 1;
+ /* Microsoft WHQL requires non-zero subsystem IDs. */
+ /* http://www.pcisig.com/reflector/msg02205.html. */
+ pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id. */
+ pch->subsystem_id = 0x0001; /* Hardcode sub-id as 1. */
+
pci_register_io_region(d, 0, 0x100, PCI_ADDRESS_SPACE_IO,
platform_ioport_map);
diff --git a/tools/ioemu/keymaps/ja b/tools/ioemu/keymaps/ja
index 8fd0b9ef1b..770220c588 100644
--- a/tools/ioemu/keymaps/ja
+++ b/tools/ioemu/keymaps/ja
@@ -102,3 +102,6 @@ underscore 0x73 shift
Henkan_Mode 0x79
Katakana 0x70
Muhenkan 0x7b
+Henkan_Mode_Real 0x79
+Henkan_Mode_Ultra 0x79
+backslash_ja 0x73
diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset
index c1b29d8e19..6588314efe 100644
--- a/tools/ioemu/patches/domain-timeoffset
+++ b/tools/ioemu/patches/domain-timeoffset
@@ -1,7 +1,7 @@
Index: ioemu/hw/mc146818rtc.c
===================================================================
---- ioemu.orig/hw/mc146818rtc.c 2006-08-17 19:58:03.222720593 +0100
-+++ ioemu/hw/mc146818rtc.c 2006-08-17 19:58:08.528134087 +0100
+--- ioemu.orig/hw/mc146818rtc.c 2006-10-24 14:45:21.000000000 +0100
++++ ioemu/hw/mc146818rtc.c 2006-10-24 14:45:39.000000000 +0100
@@ -178,10 +178,27 @@
}
}
@@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c
static void rtc_copy_date(RTCState *s)
Index: ioemu/hw/pc.c
===================================================================
---- ioemu.orig/hw/pc.c 2006-08-17 19:58:08.252164595 +0100
-+++ ioemu/hw/pc.c 2006-08-17 19:58:08.529133976 +0100
+--- ioemu.orig/hw/pc.c 2006-10-24 14:45:38.000000000 +0100
++++ ioemu/hw/pc.c 2006-10-24 14:45:39.000000000 +0100
@@ -159,7 +159,7 @@
}
@@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c
QEMUMachine pc_machine = {
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:58:08.395148788 +0100
-+++ ioemu/vl.c 2006-08-17 19:58:08.532133645 +0100
+--- ioemu.orig/vl.c 2006-10-24 14:45:38.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:45:39.000000000 +0100
@@ -163,6 +163,8 @@
int xc_handle;
@@ -174,8 +174,8 @@ Index: ioemu/vl.c
if (usb_enabled) {
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:58:08.257164042 +0100
-+++ ioemu/vl.h 2006-08-17 19:58:08.532133645 +0100
+--- ioemu.orig/vl.h 2006-10-24 14:45:38.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:45:39.000000000 +0100
@@ -576,7 +576,7 @@
int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
diff --git a/tools/ioemu/patches/fix-vga-scanning-code-overflow b/tools/ioemu/patches/fix-vga-scanning-code-overflow
new file mode 100644
index 0000000000..6d934fe3f7
--- /dev/null
+++ b/tools/ioemu/patches/fix-vga-scanning-code-overflow
@@ -0,0 +1,45 @@
+Index: ioemu/hw/vga.c
+===================================================================
+--- ioemu.orig/hw/vga.c 2006-09-21 19:07:52.000000000 +0100
++++ ioemu/hw/vga.c 2006-09-21 19:08:09.000000000 +0100
+@@ -1463,14 +1463,15 @@
+ */
+ static void vga_draw_graphic(VGAState *s, int full_update)
+ {
+- int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
++ int y1, y, update, linesize, y_start, double_scan, mask;
+ int width, height, shift_control, line_offset, bwidth;
+ ram_addr_t page0, page1;
+ int disp_width, multi_scan, multi_run;
+ uint8_t *d;
+ uint32_t v, addr1, addr;
+ vga_draw_line_func *vga_draw_line;
+-
++ ram_addr_t page_min, page_max;
++
+ full_update |= update_basic_params(s);
+
+ s->get_resolution(s, &width, &height);
+@@ -1561,8 +1562,8 @@
+ addr1 = (s->start_addr * 4);
+ bwidth = width * 4;
+ y_start = -1;
+- page_min = 0x7fffffff;
+- page_max = -1;
++ page_min = 0;
++ page_max = 0;
+ d = s->ds->data;
+ linesize = s->ds->linesize;
+ y1 = 0;
+@@ -1592,9 +1593,9 @@
+ if (update) {
+ if (y_start < 0)
+ y_start = y;
+- if (page0 < page_min)
++ if (page_min == 0 || page0 < page_min)
+ page_min = page0;
+- if (page1 > page_max)
++ if (page_max == 0 || page1 > page_max)
+ page_max = page1;
+ vga_draw_line(s, d, s->vram_ptr + addr, width);
+ if (s->cursor_draw_line)
diff --git a/tools/ioemu/patches/hypervisor-rtc b/tools/ioemu/patches/hypervisor-rtc
new file mode 100644
index 0000000000..7563425e3b
--- /dev/null
+++ b/tools/ioemu/patches/hypervisor-rtc
@@ -0,0 +1,143 @@
+# HG changeset patch
+# User kfraser@localhost.localdomain
+# Node ID 71e2a165aa7f81602c569430b18ba1ea705f0b70
+# Parent da66691687dfd90c55420cfdf27f55d18cca7810
+[HVM] Move RTC emulation into the hypervisor.
+Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
+
+--- ioemu/Makefile.target Wed Oct 18 18:13:57 2006 +0100
++++ ioemu/Makefile.target Wed Oct 18 18:35:21 2006 +0100
+@@ -294,7 +294,11 @@ endif
+ endif
+
+ # qemu-dm objects
++ifeq ($(ARCH),ia64)
+ LIBOBJS=helper2.o exec-dm.o i8259-dm.o
++else
++LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o
++endif
+
+ all: $(PROGS)
+
+@@ -354,7 +358,11 @@ ifeq ($(TARGET_BASE_ARCH), i386)
+ ifeq ($(TARGET_BASE_ARCH), i386)
+ # Hardware support
+ VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
++ifeq ($(ARCH),ia64)
+ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
++else
++VL_OBJS+= fdc.o serial.o pc.o
++endif
+ VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
+ VL_OBJS+= usb-uhci.o
+ VL_OBJS+= piix4acpi.o
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ ioemu/target-i386-dm/rtc-dm.c Wed Oct 18 18:35:21 2006 +0100
+@@ -0,0 +1,107 @@
++/*
++ * QEMU MC146818 RTC 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 "vl.h"
++
++//#define DEBUG_CMOS
++
++struct RTCState {
++ uint8_t cmos_data[128];
++ uint8_t cmos_index;
++};
++
++void rtc_set_memory(RTCState *s, int addr, int val)
++{
++ if (addr >= 0 && addr <= 127)
++ s->cmos_data[addr] = val;
++}
++
++static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
++{
++ RTCState *s = opaque;
++
++ if ((addr & 1) == 0) {
++ s->cmos_index = data & 0x7f;
++ } else {
++#ifdef DEBUG_CMOS
++ printf("cmos: write index=0x%02x val=0x%02x\n",
++ s->cmos_index, data);
++#endif
++ s->cmos_data[s->cmos_index] = data;
++ }
++}
++
++static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
++{
++ RTCState *s = opaque;
++ int ret;
++ if ((addr & 1) == 0) {
++ return 0xff;
++ } else {
++ ret = s->cmos_data[s->cmos_index];
++#ifdef DEBUG_CMOS
++ printf("cmos: read index=0x%02x val=0x%02x\n",
++ s->cmos_index, ret);
++#endif
++ return ret;
++ }
++}
++
++static void rtc_save(QEMUFile *f, void *opaque)
++{
++ RTCState *s = opaque;
++
++ qemu_put_buffer(f, s->cmos_data, 128);
++ qemu_put_8s(f, &s->cmos_index);
++}
++
++static int rtc_load(QEMUFile *f, void *opaque, int version_id)
++{
++ RTCState *s = opaque;
++
++ if (version_id != 1)
++ return -EINVAL;
++
++ qemu_get_buffer(f, s->cmos_data, 128);
++ qemu_get_8s(f, &s->cmos_index);
++
++ return 0;
++}
++
++RTCState *rtc_init(int base, int irq)
++{
++ RTCState *s;
++
++ s = qemu_mallocz(sizeof(RTCState));
++ if (!s)
++ return NULL;
++
++ register_ioport_write(base, 2, 1, cmos_ioport_write, s);
++ register_ioport_read(base, 2, 1, cmos_ioport_read, s);
++
++ register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
++ return s;
++}
++
++void rtc_set_date(RTCState *s, const struct tm *tm) {}
diff --git a/tools/ioemu/patches/ide-cd-dma b/tools/ioemu/patches/ide-cd-dma
new file mode 100644
index 0000000000..d7ed5cab06
--- /dev/null
+++ b/tools/ioemu/patches/ide-cd-dma
@@ -0,0 +1,21 @@
+# HG changeset patch
+# User kfraser@localhost.localdomain
+# Node ID 1e8ba8d2117548d4f13b7b438d1e992b1815f580
+# Parent f247e0b52dda257c0000c9da5a0cdff507b3ced8
+[HVM] Enable DMA mode for CD-ROM IDE ATAPI interface.
+Signed-off-by: Winston Wang <winston.l.wang@intel.com
+
+--- ioemu/hw/ide.c Wed Oct 18 18:37:18 2006 +0100
++++ ioemu/hw/ide.c Wed Oct 18 18:41:47 2006 +0100
+@@ -557,9 +557,9 @@ static void ide_atapi_identify(IDEState
+ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+ padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
+ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
+- put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
++ put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
+ put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
+- put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
++ put_le16(p + 63, 0x07); /* mdma0-2 supported */
+ put_le16(p + 64, 1); /* PIO modes */
+ put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
+ put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
diff --git a/tools/ioemu/patches/qemu-bootorder b/tools/ioemu/patches/qemu-bootorder
index 4929db635c..e162320bdd 100644
--- a/tools/ioemu/patches/qemu-bootorder
+++ b/tools/ioemu/patches/qemu-bootorder
@@ -1,9 +1,9 @@
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-20 22:22:36.000000000 +0100
-+++ ioemu/vl.c 2006-08-20 23:22:25.000000000 +0100
-@@ -124,7 +124,7 @@
- int vncunused;
+--- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100
+@@ -125,7 +125,7 @@
+ struct sockaddr_in vnclisten_addr;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
-int boot_device = 'c';
@@ -11,7 +11,7 @@ Index: ioemu/vl.c
uint64_t ram_size;
int pit_min_timer_count = 0;
int nb_nics;
-@@ -6057,14 +6057,14 @@
+@@ -6075,14 +6075,14 @@
break;
#endif /* !CONFIG_DM */
case QEMU_OPTION_boot:
@@ -32,7 +32,7 @@ Index: ioemu/vl.c
exit(1);
}
break;
-@@ -6328,6 +6328,7 @@
+@@ -6349,6 +6349,7 @@
fd_filename[0] == '\0')
help();
@@ -40,7 +40,7 @@ Index: ioemu/vl.c
/* boot to cd by default if no hard disk */
if (hd_filename[0] == '\0' && boot_device == 'c') {
if (fd_filename[0] != '\0')
-@@ -6335,6 +6336,7 @@
+@@ -6356,6 +6357,7 @@
else
boot_device = 'd';
}
@@ -48,7 +48,7 @@ Index: ioemu/vl.c
#endif /* !CONFIG_DM */
setvbuf(stdout, NULL, _IOLBF, 0);
-@@ -6593,6 +6595,7 @@
+@@ -6614,6 +6616,7 @@
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline, initrd_filename,
timeoffset);
@@ -58,9 +58,9 @@ Index: ioemu/vl.c
if (usb_enabled) {
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-20 22:22:36.000000000 +0100
-+++ ioemu/vl.h 2006-08-20 23:22:25.000000000 +0100
-@@ -575,7 +575,7 @@
+--- ioemu.orig/vl.h 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:33:47.000000000 +0100
+@@ -578,7 +578,7 @@
#ifndef QEMU_TOOL
typedef void QEMUMachineInitFunc(uint64_t ram_size, int vga_ram_size,
@@ -69,7 +69,7 @@ Index: ioemu/vl.h
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename, time_t timeoffset);
-@@ -1020,7 +1020,7 @@
+@@ -1023,7 +1023,7 @@
uint32_t start, uint32_t count);
int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
const unsigned char *arch,
@@ -80,8 +80,8 @@ Index: ioemu/vl.h
uint32_t initrd_image, uint32_t initrd_size,
Index: ioemu/hw/pc.c
===================================================================
---- ioemu.orig/hw/pc.c 2006-08-20 22:22:36.000000000 +0100
-+++ ioemu/hw/pc.c 2006-08-20 23:27:55.000000000 +0100
+--- ioemu.orig/hw/pc.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/hw/pc.c 2006-10-24 14:33:47.000000000 +0100
@@ -158,8 +158,23 @@
rtc_set_memory(s, info_ofs + 8, sectors);
}
diff --git a/tools/ioemu/patches/qemu-cleanup b/tools/ioemu/patches/qemu-cleanup
index 033d9fcc55..2baa2e5753 100644
--- a/tools/ioemu/patches/qemu-cleanup
+++ b/tools/ioemu/patches/qemu-cleanup
@@ -1,7 +1,7 @@
Index: ioemu/hw/vga.c
===================================================================
---- ioemu.orig/hw/vga.c 2006-08-06 02:03:51.906765409 +0100
-+++ ioemu/hw/vga.c 2006-08-06 02:15:10.364150665 +0100
+--- ioemu.orig/hw/vga.c 2006-10-24 14:44:03.000000000 +0100
++++ ioemu/hw/vga.c 2006-10-24 14:45:22.000000000 +0100
@@ -1622,7 +1622,9 @@
static void vga_save(QEMUFile *f, void *opaque)
{
@@ -26,8 +26,8 @@ Index: ioemu/hw/vga.c
return -EINVAL;
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-06 02:15:01.774108287 +0100
-+++ ioemu/vl.c 2006-08-06 02:15:31.040845624 +0100
+--- ioemu.orig/vl.c 2006-10-24 14:44:08.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:45:29.000000000 +0100
@@ -39,6 +39,7 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -36,6 +36,24 @@ Index: ioemu/vl.c
#include <dirent.h>
#include <netdb.h>
#ifdef _BSD
+@@ -2932,7 +2933,7 @@
+ }
+
+ /* XXX: better tmp dir construction */
+- snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid());
++ snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid());
+ if (mkdir(smb_dir, 0700) < 0) {
+ fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
+ exit(1);
+@@ -3893,7 +3894,7 @@
+ perror("Opening pidfile");
+ exit(1);
+ }
+- fprintf(f, "%d\n", getpid());
++ fprintf(f, "%ld\n", (long)getpid());
+ fclose(f);
+ pid_filename = qemu_strdup(filename);
+ if (!pid_filename) {
@@ -5308,7 +5309,9 @@
QEMU_OPTION_d,
QEMU_OPTION_hdachs,
@@ -70,8 +88,8 @@ Index: ioemu/vl.c
fprintf(stderr, "qemu: too many network clients\n");
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-06 02:15:01.775108175 +0100
-+++ ioemu/vl.h 2006-08-06 02:15:10.368150219 +0100
+--- ioemu.orig/vl.h 2006-10-24 14:44:08.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:45:22.000000000 +0100
@@ -957,7 +957,7 @@
unsigned long vram_offset, int vram_size, int width, int height);
@@ -81,3 +99,18 @@ Index: ioemu/vl.h
void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
void slavio_pic_info(void *opaque);
void slavio_irq_info(void *opaque);
+Index: ioemu/usb-linux.c
+===================================================================
+--- ioemu.orig/usb-linux.c 2006-10-24 14:44:03.000000000 +0100
++++ ioemu/usb-linux.c 2006-10-24 14:44:08.000000000 +0100
+@@ -26,7 +26,9 @@
+ #if defined(__linux__)
+ #include <dirent.h>
+ #include <sys/ioctl.h>
+-#include <linux/compiler.h>
++/* Some versions of usbdevice_fs.h need __user to be defined for them. */
++/* This may (harmlessly) conflict with a definition in linux/compiler.h. */
++#define __user
+ #include <linux/usbdevice_fs.h>
+ #include <linux/version.h>
+
diff --git a/tools/ioemu/patches/qemu-daemonize b/tools/ioemu/patches/qemu-daemonize
index 0d19d435b4..51568fe2ff 100644
--- a/tools/ioemu/patches/qemu-daemonize
+++ b/tools/ioemu/patches/qemu-daemonize
@@ -2,9 +2,9 @@ Changes required because qemu-dm runs daemonized.
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-16 15:11:32.575865776 +0100
-+++ ioemu/vl.c 2006-08-16 15:11:36.217465702 +0100
-@@ -6036,10 +6036,11 @@
+--- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100
+@@ -6054,10 +6054,11 @@
}
break;
case QEMU_OPTION_nographic:
diff --git a/tools/ioemu/patches/qemu-logging b/tools/ioemu/patches/qemu-logging
index a2001d9ac6..b1a0cbbd06 100644
--- a/tools/ioemu/patches/qemu-logging
+++ b/tools/ioemu/patches/qemu-logging
@@ -1,7 +1,7 @@
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-06 02:15:48.550893605 +0100
-+++ ioemu/vl.c 2006-08-06 02:16:31.246133963 +0100
+--- ioemu.orig/vl.c 2006-10-24 14:36:58.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:37:03.000000000 +0100
@@ -5234,7 +5234,7 @@
"-S freeze CPU at startup (use 'c' to start execution)\n"
"-s wait gdb connection to port %d\n"
@@ -43,7 +43,7 @@ Index: ioemu/vl.c
/* default mac address of the first network interface */
+ /* init debug */
-+ sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%d.log", getpid());
++ sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%ld.log", (long)getpid());
+ cpu_set_log_filename(qemu_dm_logfilename);
+ cpu_set_log(0);
+
diff --git a/tools/ioemu/patches/qemu-pci b/tools/ioemu/patches/qemu-pci
index b4606ac695..6f052962c2 100755
--- a/tools/ioemu/patches/qemu-pci
+++ b/tools/ioemu/patches/qemu-pci
@@ -1,7 +1,8 @@
-diff -r d5eb5205ff35 tools/ioemu/hw/pci.c
---- a/tools/ioemu/hw/pci.c Thu Aug 24 16:25:49 2006 +0100
-+++ b/tools/ioemu/hw/pci.c Fri Aug 25 11:00:03 2006 +0800
-@@ -286,6 +286,7 @@ void pci_default_write_config(PCIDevice
+Index: ioemu/hw/pci.c
+===================================================================
+--- ioemu.orig/hw/pci.c 2006-09-21 11:31:14.000000000 +0100
++++ ioemu/hw/pci.c 2006-09-21 11:31:32.000000000 +0100
+@@ -286,6 +286,7 @@
case 0x0b:
case 0x0e:
case 0x10 ... 0x27: /* base */
@@ -9,7 +10,7 @@ diff -r d5eb5205ff35 tools/ioemu/hw/pci.c
case 0x30 ... 0x33: /* rom */
case 0x3d:
can_write = 0;
-@@ -318,6 +319,18 @@ void pci_default_write_config(PCIDevice
+@@ -318,6 +319,18 @@
break;
}
if (can_write) {
@@ -28,10 +29,11 @@ diff -r d5eb5205ff35 tools/ioemu/hw/pci.c
d->config[addr] = val;
}
addr++;
-diff -r d5eb5205ff35 tools/ioemu/hw/rtl8139.c
---- a/tools/ioemu/hw/rtl8139.c Thu Aug 24 16:25:49 2006 +0100
-+++ b/tools/ioemu/hw/rtl8139.c Fri Aug 25 11:00:03 2006 +0800
-@@ -3423,6 +3423,8 @@ void pci_rtl8139_init(PCIBus *bus, NICIn
+Index: ioemu/hw/rtl8139.c
+===================================================================
+--- ioemu.orig/hw/rtl8139.c 2006-09-21 11:31:14.000000000 +0100
++++ ioemu/hw/rtl8139.c 2006-09-21 11:31:32.000000000 +0100
+@@ -3423,6 +3423,8 @@
pci_conf[0x0e] = 0x00; /* header_type */
pci_conf[0x3d] = 1; /* interrupt pin 0 */
pci_conf[0x34] = 0xdc;
@@ -40,10 +42,11 @@ diff -r d5eb5205ff35 tools/ioemu/hw/rtl8139.c
s = &d->rtl8139;
-diff -r d5eb5205ff35 tools/ioemu/hw/usb-uhci.c
---- a/tools/ioemu/hw/usb-uhci.c Thu Aug 24 16:25:49 2006 +0100
-+++ b/tools/ioemu/hw/usb-uhci.c Fri Aug 25 11:00:03 2006 +0800
-@@ -659,6 +659,8 @@ void usb_uhci_init(PCIBus *bus, int devf
+Index: ioemu/hw/usb-uhci.c
+===================================================================
+--- ioemu.orig/hw/usb-uhci.c 2006-09-21 11:31:14.000000000 +0100
++++ ioemu/hw/usb-uhci.c 2006-09-21 11:31:32.000000000 +0100
+@@ -659,6 +659,8 @@
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
diff --git a/tools/ioemu/patches/qemu-target-i386-dm b/tools/ioemu/patches/qemu-target-i386-dm
index 2ce39a5287..8bf4b3ea01 100644
--- a/tools/ioemu/patches/qemu-target-i386-dm
+++ b/tools/ioemu/patches/qemu-target-i386-dm
@@ -1,7 +1,7 @@
Index: ioemu/Makefile.target
===================================================================
---- ioemu.orig/Makefile.target 2006-08-08 11:24:33.479955101 +0100
-+++ ioemu/Makefile.target 2006-08-08 11:24:39.008338255 +0100
+--- ioemu.orig/Makefile.target 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/Makefile.target 2006-10-24 14:30:56.000000000 +0100
@@ -62,6 +62,8 @@
QEMU_SYSTEM=qemu-fast
endif
@@ -32,8 +32,8 @@ Index: ioemu/Makefile.target
DEFINES += -DHAS_AUDIO
Index: ioemu/configure
===================================================================
---- ioemu.orig/configure 2006-08-08 11:24:33.480954990 +0100
-+++ ioemu/configure 2006-08-08 11:24:38.122437102 +0100
+--- ioemu.orig/configure 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/configure 2006-10-24 14:29:34.000000000 +0100
@@ -373,6 +373,8 @@
if [ "$user" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
@@ -45,8 +45,8 @@ Index: ioemu/configure
fi
Index: ioemu/monitor.c
===================================================================
---- ioemu.orig/monitor.c 2006-08-08 11:24:33.484954543 +0100
-+++ ioemu/monitor.c 2006-08-08 11:24:39.253310921 +0100
+--- ioemu.orig/monitor.c 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/monitor.c 2006-10-24 14:30:56.000000000 +0100
@@ -1262,6 +1262,10 @@
"", "show profiling information", },
{ "capture", "", do_info_capture,
@@ -60,8 +60,8 @@ Index: ioemu/monitor.c
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-08 11:24:33.486954320 +0100
-+++ ioemu/vl.c 2006-08-08 11:24:39.454288496 +0100
+--- ioemu.orig/vl.c 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:30:56.000000000 +0100
@@ -87,7 +87,7 @@
#include "exec-all.h"
@@ -98,8 +98,8 @@ Index: ioemu/vl.c
{
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-08 11:24:31.082222636 +0100
-+++ ioemu/vl.h 2006-08-08 11:24:39.454288496 +0100
+--- ioemu.orig/vl.h 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:30:56.000000000 +0100
@@ -37,6 +37,8 @@
#include <unistd.h>
#include <fcntl.h>
@@ -132,7 +132,7 @@ Index: ioemu/vl.h
Index: ioemu/target-i386-dm/cpu.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/cpu.h 2006-08-08 11:24:39.099328102 +0100
++++ ioemu/target-i386-dm/cpu.h 2006-10-24 14:30:56.000000000 +0100
@@ -0,0 +1,86 @@
+/*
+ * i386 virtual CPU header
@@ -223,7 +223,7 @@ Index: ioemu/target-i386-dm/cpu.h
Index: ioemu/target-i386-dm/exec-dm.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/exec-dm.c 2006-08-08 11:24:39.099328102 +0100
++++ ioemu/target-i386-dm/exec-dm.c 2006-10-24 14:30:56.000000000 +0100
@@ -0,0 +1,516 @@
+/*
+ * virtual page mapping and translated block handling
@@ -744,7 +744,7 @@ Index: ioemu/target-i386-dm/exec-dm.c
Index: ioemu/target-i386-dm/helper2.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/helper2.c 2006-08-08 11:24:44.888682140 +0100
++++ ioemu/target-i386-dm/helper2.c 2006-10-24 14:31:01.000000000 +0100
@@ -0,0 +1,469 @@
+/*
+ * i386 helpers (without register variable usage)
@@ -1218,7 +1218,7 @@ Index: ioemu/target-i386-dm/helper2.c
Index: ioemu/target-i386-dm/i8259-dm.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/i8259-dm.c 2006-08-08 11:24:33.505952200 +0100
++++ ioemu/target-i386-dm/i8259-dm.c 2006-10-24 13:47:23.000000000 +0100
@@ -0,0 +1,107 @@
+/* Xen 8259 stub for interrupt controller emulation
+ *
@@ -1330,7 +1330,7 @@ Index: ioemu/target-i386-dm/i8259-dm.c
Index: ioemu/target-i386-dm/qemu-dm.debug
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/qemu-dm.debug 2006-08-08 11:24:33.505952200 +0100
++++ ioemu/target-i386-dm/qemu-dm.debug 2006-10-24 13:47:23.000000000 +0100
@@ -0,0 +1,5 @@
+#!/bin/sh
+
@@ -1340,7 +1340,7 @@ Index: ioemu/target-i386-dm/qemu-dm.debug
Index: ioemu/target-i386-dm/qemu-ifup
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/target-i386-dm/qemu-ifup 2006-08-08 11:24:33.505952200 +0100
++++ ioemu/target-i386-dm/qemu-ifup 2006-10-24 13:47:23.000000000 +0100
@@ -0,0 +1,10 @@
+#!/bin/sh
+
diff --git a/tools/ioemu/patches/serial-port-rate-limit b/tools/ioemu/patches/serial-port-rate-limit
new file mode 100644
index 0000000000..17eac33951
--- /dev/null
+++ b/tools/ioemu/patches/serial-port-rate-limit
@@ -0,0 +1,116 @@
+# HG changeset patch
+# User Steven Smith <ssmith@xensource.com>
+# Node ID 1d3f52eb256e3522edc12daca91039b319dbbbe5
+# Parent b7b653e36d20811831f26bb951ea66dca5854b17
+[HVM] Rate limit guest accesses to the qemu virtual serial port. This stops
+grub's boot menu from hammering dom0.
+
+Signed-off-by: Steven Smith <sos22@cam.ac.uk>
+
+--- ioemu/hw/serial.c Mon Sep 25 16:31:02 2006 +0100
++++ ioemu/hw/serial.c Mon Sep 25 17:27:18 2006 +0100
+@@ -22,6 +22,9 @@
+ * THE SOFTWARE.
+ */
+ #include "vl.h"
++#include <sys/time.h>
++#include <time.h>
++#include <assert.h>
+
+ //#define DEBUG_SERIAL
+
+@@ -138,6 +141,67 @@ static void serial_update_parameters(Ser
+ printf("speed=%d parity=%c data=%d stop=%d\n",
+ speed, parity, data_bits, stop_bits);
+ #endif
++}
++
++/* Rate limit serial requests so that e.g. grub on a serial console
++ doesn't kill dom0. Simple token bucket. If we get some actual
++ data from the user, instantly refil the bucket. */
++
++/* How long it takes to generate a token, in microseconds. */
++#define TOKEN_PERIOD 1000
++/* Maximum and initial size of token bucket */
++#define TOKENS_MAX 100000
++
++static int tokens_avail;
++
++static void serial_get_token(void)
++{
++ static struct timeval last_refil_time;
++ static int started;
++
++ assert(tokens_avail >= 0);
++ if (!tokens_avail) {
++ struct timeval delta, now;
++ int generated;
++
++ if (!started) {
++ gettimeofday(&last_refil_time, NULL);
++ tokens_avail = TOKENS_MAX;
++ started = 1;
++ return;
++ }
++ retry:
++ gettimeofday(&now, NULL);
++ delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
++ delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
++ if (delta.tv_usec < 0) {
++ delta.tv_usec += 1000000;
++ delta.tv_sec--;
++ }
++ assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
++ if (delta.tv_usec < TOKEN_PERIOD) {
++ struct timespec ts;
++ /* Wait until at least one token is available. */
++ ts.tv_sec = TOKEN_PERIOD / 1000000;
++ ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
++ while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
++ ;
++ goto retry;
++ }
++ generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
++ generated +=
++ ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
++ assert(generated > 0);
++
++ last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
++ last_refil_time.tv_sec += last_refil_time.tv_usec / 1000000;
++ last_refil_time.tv_usec %= 1000000;
++ last_refil_time.tv_sec += (generated * TOKEN_PERIOD) / 1000000;
++ if (generated > TOKENS_MAX)
++ generated = TOKENS_MAX;
++ tokens_avail = generated;
++ }
++ tokens_avail--;
+ }
+
+ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+@@ -245,9 +309,11 @@ static uint32_t serial_ioport_read(void
+ ret = s->mcr;
+ break;
+ case 5:
++ serial_get_token();
+ ret = s->lsr;
+ break;
+ case 6:
++ serial_get_token();
+ if (s->mcr & UART_MCR_LOOP) {
+ /* in loopback, the modem output pins are connected to the
+ inputs */
+@@ -296,12 +362,14 @@ static void serial_receive1(void *opaque
+ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+ {
+ SerialState *s = opaque;
++ tokens_avail = TOKENS_MAX;
+ serial_receive_byte(s, buf[0]);
+ }
+
+ static void serial_event(void *opaque, int event)
+ {
+ SerialState *s = opaque;
++ tokens_avail = TOKENS_MAX;
+ if (event == CHR_EVENT_BREAK)
+ serial_receive_break(s);
+ }
diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series
index 133e40988a..f6459c2139 100644
--- a/tools/ioemu/patches/series
+++ b/tools/ioemu/patches/series
@@ -29,12 +29,16 @@ domain-timeoffset
acpi-support
acpi-timer-support
acpi-poweroff-support
+fix-vga-scanning-code-overflow
vnc-cleanup
vnc-fixes
+vnc-protocol-fixes
vnc-start-vncviewer
vnc-title-domain-name
vnc-access-monitor-vt
vnc-display-find-unused
+vnc-listen-specific-interface
+vnc-backoff-screen-scan
xenstore-block-device-config
xenstore-write-vnc-port
qemu-allow-disable-sdl
@@ -44,4 +48,8 @@ qemu-daemonize
xen-platform-device
qemu-bootorder
qemu-tunable-ide-write-cache
-qemu-pci -p3
+qemu-pci
+serial-port-rate-limit
+hypervisor-rtc
+ide-cd-dma
+vnc-password
diff --git a/tools/ioemu/patches/vnc-access-monitor-vt b/tools/ioemu/patches/vnc-access-monitor-vt
index ab30187259..0320a978ca 100644
--- a/tools/ioemu/patches/vnc-access-monitor-vt
+++ b/tools/ioemu/patches/vnc-access-monitor-vt
@@ -1,8 +1,8 @@
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:50:14.623519661 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:15.956372339 +0100
-@@ -32,6 +32,10 @@
+--- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100
+@@ -33,6 +33,10 @@
#include "vnc_keysym.h"
#include "keymaps.c"
@@ -13,7 +13,7 @@ Index: ioemu/vnc.c
typedef struct Buffer
{
size_t capacity;
-@@ -95,6 +99,8 @@
+@@ -96,6 +100,8 @@
int visible_h;
int slow_client;
diff --git a/tools/ioemu/patches/vnc-backoff-screen-scan b/tools/ioemu/patches/vnc-backoff-screen-scan
new file mode 100644
index 0000000000..813a63ae48
--- /dev/null
+++ b/tools/ioemu/patches/vnc-backoff-screen-scan
@@ -0,0 +1,385 @@
+Index: ioemu/vnc.c
+===================================================================
+--- ioemu.orig/vnc.c 2006-10-24 14:33:17.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:33:24.000000000 +0100
+@@ -28,7 +28,19 @@
+ #include "qemu_socket.h"
+ #include <assert.h>
+
+-#define VNC_REFRESH_INTERVAL (1000 / 30)
++/* The refresh interval starts at BASE. If we scan the buffer and
++ find no change, we increase by INC, up to MAX. If the mouse moves
++ or we get a keypress, the interval is set back to BASE. If we find
++ an update, halve the interval.
++
++ All times in milliseconds. */
++#define VNC_REFRESH_INTERVAL_BASE 30
++#define VNC_REFRESH_INTERVAL_INC 50
++#define VNC_REFRESH_INTERVAL_MAX 2000
++
++/* Wait at most one second between updates, so that we can detect a
++ minimised vncviewer reasonably quickly. */
++#define VNC_MAX_UPDATE_INTERVAL 5000
+
+ #include "vnc_keysym.h"
+ #include "keymaps.c"
+@@ -65,10 +77,11 @@
+ struct VncState
+ {
+ QEMUTimer *timer;
++ int timer_interval;
++ int64_t last_update_time;
+ int lsock;
+ int csock;
+ DisplayState *ds;
+- int need_update;
+ int width;
+ int height;
+ uint64_t *dirty_row; /* screen regions which are possibly dirty */
+@@ -99,8 +112,6 @@
+ int visible_w;
+ int visible_h;
+
+- int slow_client;
+-
+ int ctl_keys; /* Ctrl+Alt starts calibration */
+ };
+
+@@ -381,7 +392,7 @@
+ int y = 0;
+ int pitch = ds->linesize;
+ VncState *vs = ds->opaque;
+- int updating_client = !vs->slow_client;
++ int updating_client = 1;
+
+ if (src_x < vs->visible_x || src_y < vs->visible_y ||
+ dst_x < vs->visible_x || dst_y < vs->visible_y ||
+@@ -391,10 +402,8 @@
+ (dst_y + h) > (vs->visible_y + vs->visible_h))
+ updating_client = 0;
+
+- if (updating_client) {
+- vs->need_update = 1;
++ if (updating_client)
+ _vnc_update_client(vs);
+- }
+
+ if (dst_y > src_y) {
+ y = h - 1;
+@@ -446,110 +455,149 @@
+ static void _vnc_update_client(void *opaque)
+ {
+ VncState *vs = opaque;
+- int64_t now = qemu_get_clock(rt_clock);
+-
+- if (vs->need_update && vs->csock != -1) {
+- int y;
+- char *row;
+- char *old_row;
+- uint64_t width_mask;
+- int n_rectangles;
+- int saved_offset;
+- int maxx, maxy;
+- int tile_bytes = vs->depth * DP2X(vs, 1);
++ int64_t now;
++ int y;
++ char *row;
++ char *old_row;
++ uint64_t width_mask;
++ int n_rectangles;
++ int saved_offset;
++ int maxx, maxy;
++ int tile_bytes = vs->depth * DP2X(vs, 1);
+
+- qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
++ if (vs->csock == -1)
++ return;
+
+- if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
+- width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
+- else
+- width_mask = ~(0ULL);
++ now = qemu_get_clock(rt_clock);
+
+- /* Walk through the dirty map and eliminate tiles that
+- really aren't dirty */
+- row = vs->ds->data;
+- old_row = vs->old_data;
+-
+- for (y = 0; y < vs->ds->height; y++) {
+- if (vs->dirty_row[y] & width_mask) {
+- int x;
+- char *ptr, *old_ptr;
+-
+- ptr = row;
+- old_ptr = old_row;
+-
+- for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
+- if (vs->dirty_row[y] & (1ULL << x)) {
+- if (memcmp(old_ptr, ptr, tile_bytes)) {
+- vs->has_update = 1;
+- vs->update_row[y] |= (1ULL << x);
+- memcpy(old_ptr, ptr, tile_bytes);
+- }
+- vs->dirty_row[y] &= ~(1ULL << x);
+- }
++ if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
++ width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
++ else
++ width_mask = ~(0ULL);
+
+- ptr += tile_bytes;
+- old_ptr += tile_bytes;
+- }
+- }
++ /* Walk through the dirty map and eliminate tiles that really
++ aren't dirty */
++ row = vs->ds->data;
++ old_row = vs->old_data;
+
+- row += vs->ds->linesize;
+- old_row += vs->ds->linesize;
+- }
++ for (y = 0; y < vs->ds->height; y++) {
++ if (vs->dirty_row[y] & width_mask) {
++ int x;
++ char *ptr, *old_ptr;
+
+- if (!vs->has_update || vs->visible_y >= vs->ds->height ||
+- vs->visible_x >= vs->ds->width)
+- return;
++ ptr = row;
++ old_ptr = old_row;
+
+- /* Count rectangles */
+- n_rectangles = 0;
+- vnc_write_u8(vs, 0); /* msg id */
+- vnc_write_u8(vs, 0);
+- saved_offset = vs->output.offset;
+- vnc_write_u16(vs, 0);
++ for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
++ if (vs->dirty_row[y] & (1ULL << x)) {
++ if (memcmp(old_ptr, ptr, tile_bytes)) {
++ vs->has_update = 1;
++ vs->update_row[y] |= (1ULL << x);
++ memcpy(old_ptr, ptr, tile_bytes);
++ }
++ vs->dirty_row[y] &= ~(1ULL << x);
++ }
+
+- maxy = vs->visible_y + vs->visible_h;
+- if (maxy > vs->ds->height)
+- maxy = vs->ds->height;
+- maxx = vs->visible_x + vs->visible_w;
+- if (maxx > vs->ds->width)
+- maxx = vs->ds->width;
++ ptr += tile_bytes;
++ old_ptr += tile_bytes;
++ }
++ }
++
++ row += vs->ds->linesize;
++ old_row += vs->ds->linesize;
++ }
+
+- for (y = vs->visible_y; y < maxy; y++) {
+- int x;
+- int last_x = -1;
+- for (x = X2DP_DOWN(vs, vs->visible_x);
+- x < X2DP_UP(vs, maxx); x++) {
+- if (vs->update_row[y] & (1ULL << x)) {
+- if (last_x == -1)
+- last_x = x;
+- vs->update_row[y] &= ~(1ULL << x);
+- } else {
+- if (last_x != -1) {
+- int h = find_update_height(vs, y, maxy, last_x, x);
++ if (!vs->has_update || vs->visible_y >= vs->ds->height ||
++ vs->visible_x >= vs->ds->width)
++ goto backoff;
++
++ /* Count rectangles */
++ n_rectangles = 0;
++ vnc_write_u8(vs, 0); /* msg id */
++ vnc_write_u8(vs, 0);
++ saved_offset = vs->output.offset;
++ vnc_write_u16(vs, 0);
++
++ maxy = vs->visible_y + vs->visible_h;
++ if (maxy > vs->ds->height)
++ maxy = vs->ds->height;
++ maxx = vs->visible_x + vs->visible_w;
++ if (maxx > vs->ds->width)
++ maxx = vs->ds->width;
++
++ for (y = vs->visible_y; y < maxy; y++) {
++ int x;
++ int last_x = -1;
++ for (x = X2DP_DOWN(vs, vs->visible_x);
++ x < X2DP_UP(vs, maxx); x++) {
++ if (vs->update_row[y] & (1ULL << x)) {
++ if (last_x == -1)
++ last_x = x;
++ vs->update_row[y] &= ~(1ULL << x);
++ } else {
++ if (last_x != -1) {
++ int h = find_update_height(vs, y, maxy, last_x, x);
++ if (h != 0) {
+ send_framebuffer_update(vs, DP2X(vs, last_x), y,
+ DP2X(vs, (x - last_x)), h);
+ n_rectangles++;
+ }
+- last_x = -1;
+ }
++ last_x = -1;
+ }
+- if (last_x != -1) {
+- int h = find_update_height(vs, y, maxy, last_x, x);
++ }
++ if (last_x != -1) {
++ int h = find_update_height(vs, y, maxy, last_x, x);
++ if (h != 0) {
+ send_framebuffer_update(vs, DP2X(vs, last_x), y,
+ DP2X(vs, (x - last_x)), h);
+ n_rectangles++;
+ }
+ }
+- vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+- vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
++ }
++ vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
++ vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+
+- vs->has_update = 0;
+- vs->need_update = 0;
+- vnc_flush(vs);
+- vs->slow_client = 0;
+- } else
+- vs->slow_client = 1;
++ if (n_rectangles == 0)
++ goto backoff;
++
++ vs->has_update = 0;
++ vnc_flush(vs);
++ vs->last_update_time = now;
++
++ vs->timer_interval /= 2;
++ if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
++ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
++
++ return;
++
++ backoff:
++ /* No update -> back off a bit */
++ vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
++ if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
++ vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
++ if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
++ /* Send a null update. If the client is no longer
++ interested (e.g. minimised) it'll ignore this, and we
++ can stop scanning the buffer until it sends another
++ update request. */
++ /* It turns out that there's a bug in realvncviewer 4.1.2
++ which means that if you send a proper null update (with
++ no update rectangles), it gets a bit out of sync and
++ never sends any further requests, regardless of whether
++ it needs one or not. Fix this by sending a single 1x1
++ update rectangle instead. */
++ vnc_write_u8(vs, 0);
++ vnc_write_u8(vs, 0);
++ vnc_write_u16(vs, 1);
++ send_framebuffer_update(vs, 0, 0, 1, 1);
++ vnc_flush(vs);
++ vs->last_update_time = now;
++ return;
++ }
++ }
++ qemu_mod_timer(vs->timer, now + vs->timer_interval);
++ return;
+ }
+
+ static void vnc_update_client(void *opaque)
+@@ -562,8 +610,10 @@
+
+ static void vnc_timer_init(VncState *vs)
+ {
+- if (vs->timer == NULL)
++ if (vs->timer == NULL) {
+ vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
++ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
++ }
+ }
+
+ static void vnc_dpy_refresh(DisplayState *ds)
+@@ -623,7 +673,6 @@
+ vs->csock = -1;
+ buffer_reset(&vs->input);
+ buffer_reset(&vs->output);
+- vs->need_update = 0;
+ return 0;
+ }
+ return ret;
+@@ -895,7 +944,6 @@
+ int x_position, int y_position,
+ int w, int h)
+ {
+- vs->need_update = 1;
+ if (!incremental)
+ framebuffer_set_updated(vs, x_position, y_position, w, h);
+ vs->visible_x = x_position;
+@@ -1018,6 +1066,7 @@
+ {
+ int i;
+ uint16_t limit;
++ int64_t now;
+
+ switch (data[0]) {
+ case 0:
+@@ -1061,12 +1110,18 @@
+ if (len == 1)
+ return 8;
+
++ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
++ qemu_advance_timer(vs->timer,
++ qemu_get_clock(rt_clock) + vs->timer_interval);
+ key_event(vs, read_u8(data, 1), read_u32(data, 4));
+ break;
+ case 5:
+ if (len == 1)
+ return 6;
+
++ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
++ qemu_advance_timer(vs->timer,
++ qemu_get_clock(rt_clock) + vs->timer_interval);
+ pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+ break;
+ case 6:
+Index: ioemu/vl.c
+===================================================================
+--- ioemu.orig/vl.c 2006-10-24 14:33:17.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:24.000000000 +0100
+@@ -726,6 +726,12 @@
+ }
+ }
+
++void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time)
++{
++ if (ts->expire_time > expire_time || !qemu_timer_pending(ts))
++ qemu_mod_timer(ts, expire_time);
++}
++
+ /* modify the current timer so that it will be fired when current_time
+ >= expire_time. The corresponding callback will be called. */
+ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+Index: ioemu/vl.h
+===================================================================
+--- ioemu.orig/vl.h 2006-10-24 14:33:17.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:33:24.000000000 +0100
+@@ -407,6 +407,7 @@
+ void qemu_free_timer(QEMUTimer *ts);
+ void qemu_del_timer(QEMUTimer *ts);
+ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
++void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time);
+ int qemu_timer_pending(QEMUTimer *ts);
+
+ extern int64_t ticks_per_sec;
diff --git a/tools/ioemu/patches/vnc-cleanup b/tools/ioemu/patches/vnc-cleanup
index bc7ba27ca9..c09b9c6896 100644
--- a/tools/ioemu/patches/vnc-cleanup
+++ b/tools/ioemu/patches/vnc-cleanup
@@ -1,7 +1,7 @@
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:37:36.091553839 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:10.313996001 +0100
+--- ioemu.orig/vnc.c 2006-09-21 18:54:22.000000000 +0100
++++ ioemu/vnc.c 2006-09-21 19:05:39.000000000 +0100
@@ -143,13 +143,16 @@
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
{
@@ -30,7 +30,16 @@ Index: ioemu/vnc.c
if (vs->need_update && vs->csock != -1) {
int y;
-@@ -390,7 +394,7 @@
+@@ -383,6 +387,8 @@
+ int saved_offset;
+ int has_dirty = 0;
+
++ qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
++
+ vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
+
+ /* Walk through the dirty map and eliminate tiles that
+@@ -390,7 +396,7 @@
row = vs->ds->data;
old_row = vs->old_data;
@@ -39,34 +48,50 @@ Index: ioemu/vnc.c
if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
int x;
char *ptr, *old_ptr;
-@@ -415,10 +419,8 @@
+@@ -415,10 +421,8 @@
old_row += vs->ds->linesize;
}
- if (!has_dirty) {
- qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
-- return;
-- }
+ if (!has_dirty)
-+ goto out;
+ return;
+- }
/* Count rectangles */
n_rectangles = 0;
-@@ -456,7 +458,9 @@
+@@ -454,17 +458,13 @@
+ vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+ vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
vnc_flush(vs);
-
+-
}
- qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
-+
-+ out:
-+ qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
}
static void vnc_timer_init(VncState *vs)
+ {
+- if (vs->timer == NULL) {
++ if (vs->timer == NULL)
+ vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+- qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+- }
+ }
+
+ static void vnc_dpy_refresh(DisplayState *ds)
+@@ -736,6 +736,8 @@
+ old_row += vs->ds->linesize;
+ }
+ }
++
++ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+ }
+
+ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:02.410869542 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:10.316995669 +0100
+--- ioemu.orig/vl.c 2006-09-21 18:55:38.000000000 +0100
++++ ioemu/vl.c 2006-09-21 19:00:48.000000000 +0100
@@ -5120,10 +5120,10 @@
/* XXX: better handling of removal */
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
diff --git a/tools/ioemu/patches/vnc-display-find-unused b/tools/ioemu/patches/vnc-display-find-unused
index c763272c09..bb4f36a9da 100644
--- a/tools/ioemu/patches/vnc-display-find-unused
+++ b/tools/ioemu/patches/vnc-display-find-unused
@@ -1,8 +1,8 @@
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:50:15.956372339 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:17.083247783 +0100
-@@ -1183,7 +1183,7 @@
+--- ioemu.orig/vnc.c 2006-10-24 14:31:09.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:31:36.000000000 +0100
+@@ -1195,7 +1195,7 @@
}
}
@@ -11,7 +11,7 @@ Index: ioemu/vnc.c
{
struct sockaddr_in addr;
int reuse_addr, ret;
-@@ -1214,10 +1214,6 @@
+@@ -1226,10 +1226,6 @@
exit(1);
}
@@ -22,7 +22,7 @@ Index: ioemu/vnc.c
reuse_addr = 1;
ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
(const char *)&reuse_addr, sizeof(reuse_addr));
-@@ -1226,7 +1222,16 @@
+@@ -1238,7 +1234,16 @@
exit(1);
}
@@ -39,7 +39,7 @@ Index: ioemu/vnc.c
fprintf(stderr, "bind() failed\n");
exit(1);
}
-@@ -1247,6 +1252,8 @@
+@@ -1259,6 +1264,8 @@
vs->ds->dpy_refresh = vnc_dpy_refresh;
vnc_dpy_resize(vs->ds, 640, 400);
@@ -50,8 +50,8 @@ Index: ioemu/vnc.c
int vnc_start_viewer(int port)
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:13.152682236 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:17.086247452 +0100
+--- ioemu.orig/vl.c 2006-10-24 14:31:09.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:31:41.000000000 +0100
@@ -121,6 +121,7 @@
static DisplayState display_state;
int nographic;
@@ -99,7 +99,7 @@ Index: ioemu/vl.c
+ case QEMU_OPTION_vncunused:
+ vncunused++;
+ if (vnc_display == -1)
-+ vnc_display = -2;
++ vnc_display = 0;
+ break;
}
}
@@ -115,8 +115,8 @@ Index: ioemu/vl.c
} else {
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:13.153682125 +0100
-+++ ioemu/vl.h 2006-08-17 19:50:17.087247341 +0100
+--- ioemu.orig/vl.h 2006-10-24 14:31:09.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:31:36.000000000 +0100
@@ -785,7 +785,7 @@
void cocoa_display_init(DisplayState *ds, int full_screen);
diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes
index 339c4a273d..7e08920961 100644
--- a/tools/ioemu/patches/vnc-fixes
+++ b/tools/ioemu/patches/vnc-fixes
@@ -1,7 +1,7 @@
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:10.316995669 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:12.100798502 +0100
+--- ioemu.orig/vl.c 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:19:36.000000000 +0100
@@ -6534,8 +6534,10 @@
}
}
@@ -17,8 +17,8 @@ Index: ioemu/vl.c
if (use_gdbstub) {
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:50:10.313996001 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:12.101798392 +0100
+--- ioemu.orig/vnc.c 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:20:00.000000000 +0100
@@ -3,6 +3,7 @@
*
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
@@ -240,7 +240,7 @@ Index: ioemu/vnc.c
{
VncState *vs = opaque;
int64_t now = qemu_get_clock(rt_clock);
-@@ -382,12 +445,16 @@
+@@ -382,14 +445,18 @@
int y;
char *row;
char *old_row;
@@ -252,6 +252,8 @@ Index: ioemu/vnc.c
+ int maxx, maxy;
+ int tile_bytes = vs->depth * DP2X(vs, 1);
+ qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
+
- vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
+ if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
+ width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
@@ -260,7 +262,7 @@ Index: ioemu/vnc.c
/* Walk through the dirty map and eliminate tiles that
really aren't dirty */
-@@ -395,23 +462,25 @@
+@@ -397,23 +464,25 @@
old_row = vs->old_data;
for (y = 0; y < vs->ds->height; y++) {
@@ -295,17 +297,17 @@ Index: ioemu/vnc.c
}
}
-@@ -419,7 +488,8 @@
+@@ -421,7 +490,8 @@
old_row += vs->ds->linesize;
}
- if (!has_dirty)
+ if (!vs->has_update || vs->visible_y >= vs->ds->height ||
+ vs->visible_x >= vs->ds->width)
- goto out;
+ return;
/* Count rectangles */
-@@ -429,40 +499,61 @@
+@@ -431,34 +501,56 @@
saved_offset = vs->output.offset;
vnc_write_u16(vs, 0);
@@ -354,32 +356,26 @@ Index: ioemu/vnc.c
}
vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
-- vnc_flush(vs);
-
-- }
++
+ vs->has_update = 0;
+ vs->need_update = 0;
-+ vnc_flush(vs);
+ vnc_flush(vs);
+- }
+ vs->slow_client = 0;
+ } else
+ vs->slow_client = 1;
-
- out:
- qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
- }
-
++}
++
+static void vnc_update_client(void *opaque)
+{
+ VncState *vs = opaque;
+
+ vs->ds->dpy_refresh(vs->ds);
+ _vnc_update_client(vs);
-+}
-+
+ }
+
static void vnc_timer_init(VncState *vs)
- {
- if (vs->timer == NULL) {
-@@ -473,8 +564,6 @@
+@@ -469,8 +561,6 @@
static void vnc_dpy_refresh(DisplayState *ds)
{
@@ -388,7 +384,7 @@ Index: ioemu/vnc.c
vga_hw_update();
}
-@@ -510,7 +599,7 @@
+@@ -506,7 +596,7 @@
static void buffer_reset(Buffer *buffer)
{
@@ -397,7 +393,7 @@ Index: ioemu/vnc.c
}
static void buffer_append(Buffer *buffer, const void *data, size_t len)
-@@ -551,12 +640,12 @@
+@@ -547,12 +637,12 @@
if (!ret)
return;
@@ -413,7 +409,7 @@ Index: ioemu/vnc.c
}
static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
-@@ -588,11 +677,11 @@
+@@ -584,11 +674,11 @@
return;
if (!ret) {
@@ -428,7 +424,7 @@ Index: ioemu/vnc.c
}
}
-@@ -600,9 +689,9 @@
+@@ -596,9 +686,9 @@
{
buffer_reserve(&vs->output, len);
@@ -441,7 +437,7 @@ Index: ioemu/vnc.c
buffer_append(&vs->output, data, len);
}
-@@ -724,22 +813,25 @@
+@@ -720,22 +810,25 @@
do_key_event(vs, down, sym);
}
@@ -475,10 +471,10 @@ Index: ioemu/vnc.c
+ vs->visible_y = y_position;
+ vs->visible_w = w;
+ vs->visible_h = h;
- }
- static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
-@@ -845,8 +937,6 @@
+ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+ }
+@@ -843,8 +936,6 @@
}
vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
@@ -487,7 +483,16 @@ Index: ioemu/vnc.c
vga_hw_invalidate();
vga_hw_update();
-@@ -1012,11 +1102,11 @@
+@@ -924,6 +1015,8 @@
+ {
+ char pad[3] = { 0, 0, 0 };
+
++ vga_hw_update();
++
+ vs->width = vs->ds->width;
+ vs->height = vs->ds->height;
+ vnc_write_u16(vs, vs->ds->width);
+@@ -1010,11 +1103,11 @@
vnc_write(vs, "RFB 003.003\n", 12);
vnc_flush(vs);
vnc_read_when(vs, protocol_version, 12);
@@ -501,7 +506,7 @@ Index: ioemu/vnc.c
}
}
-@@ -1073,17 +1163,15 @@
+@@ -1071,17 +1164,15 @@
exit(1);
}
@@ -524,8 +529,8 @@ Index: ioemu/vnc.c
}
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:02.411869432 +0100
-+++ ioemu/vl.h 2006-08-17 19:50:12.102798281 +0100
+--- ioemu.orig/vl.h 2006-10-24 13:47:23.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:19:36.000000000 +0100
@@ -319,6 +319,7 @@
int is_graphic_console(void);
CharDriverState *text_console_init(DisplayState *ds);
diff --git a/tools/ioemu/patches/vnc-listen-specific-interface b/tools/ioemu/patches/vnc-listen-specific-interface
new file mode 100644
index 0000000000..3c42abb94c
--- /dev/null
+++ b/tools/ioemu/patches/vnc-listen-specific-interface
@@ -0,0 +1,177 @@
+# HG changeset patch
+# User Christian Limpach <Christian.Limpach@xensource.com>
+# Node ID a95dfbc8dca8ecddcb9be51d78f446b0fa461892
+# Parent 8959876abbe319963974fab21dda7185e0ad84e6
+[HVM/vncserver] Implement a 'vnclisten' option to limit the interface
+that the VNC server from qemu listens on.
+
+Defaults to only listen on 127.0.0.1
+
+The old behaviour (listen on all interfaces) can be restored, by
+- changing the system-wide default in /etc/xen/xend-config.sxp by adding:
+(vnc-listen '0.0.0.0')
+- changing individual domain config files by adding:
+vnclisten="0.0.0.0"
+
+Also allows specifying the hostname associated with an interface to limit
+to that interface.
+
+Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
+
+Index: ioemu/vl.c
+===================================================================
+--- ioemu.orig/vl.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:34:28.000000000 +0100
+@@ -122,6 +122,7 @@
+ int nographic;
+ int vncviewer;
+ int vncunused;
++struct sockaddr_in vnclisten_addr;
+ const char* keyboard_layout = NULL;
+ int64_t ticks_per_sec;
+ int boot_device = 'c';
+@@ -2777,10 +2778,22 @@
+ return -1;
+ }
+
++int parse_host(struct sockaddr_in *saddr, const char *buf)
++{
++ struct hostent *he;
++
++ if ((he = gethostbyname(buf)) != NULL) {
++ saddr->sin_addr = *(struct in_addr *)he->h_addr;
++ } else {
++ if (!inet_aton(buf, &saddr->sin_addr))
++ return -1;
++ }
++ return 0;
++}
++
+ int parse_host_port(struct sockaddr_in *saddr, const char *str)
+ {
+ char buf[512];
+- struct hostent *he;
+ const char *p, *r;
+ int port;
+
+@@ -2791,14 +2804,8 @@
+ if (buf[0] == '\0') {
+ saddr->sin_addr.s_addr = 0;
+ } else {
+- if (isdigit(buf[0])) {
+- if (!inet_aton(buf, &saddr->sin_addr))
+- return -1;
+- } else {
+- if ((he = gethostbyname(buf)) == NULL)
+- return - 1;
+- saddr->sin_addr = *(struct in_addr *)he->h_addr;
+- }
++ if (parse_host(saddr, buf) == -1)
++ return -1;
+ }
+ port = strtol(p, (char **)&r, 0);
+ if (r == p)
+@@ -5344,6 +5351,7 @@
+ "-vnc display start a VNC server on display\n"
+ "-vncviewer start a vncviewer process for this domain\n"
+ "-vncunused bind the VNC server to an unused port\n"
++ "-vnclisten bind the VNC server to this address\n"
+ "-timeoffset time offset (in seconds) from local time\n"
+ "-acpi disable or enable ACPI of HVM domain \n"
+ "\n"
+@@ -5434,6 +5442,7 @@
+ QEMU_OPTION_acpi,
+ QEMU_OPTION_vncviewer,
+ QEMU_OPTION_vncunused,
++ QEMU_OPTION_vnclisten,
+ };
+
+ typedef struct QEMUOption {
+@@ -5510,6 +5519,7 @@
+ { "vnc", HAS_ARG, QEMU_OPTION_vnc },
+ { "vncviewer", 0, QEMU_OPTION_vncviewer },
+ { "vncunused", 0, QEMU_OPTION_vncunused },
++ { "vnclisten", HAS_ARG, QEMU_OPTION_vnclisten },
+
+ /* temporary options */
+ { "usb", 0, QEMU_OPTION_usb },
+@@ -5905,6 +5915,8 @@
+
+ nb_nics = 0;
+ /* default mac address of the first network interface */
++
++ memset(&vnclisten_addr.sin_addr, 0, sizeof(vnclisten_addr.sin_addr));
+
+ /* init debug */
+ sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%d.log", getpid());
+@@ -6280,6 +6292,9 @@
+ if (vnc_display == -1)
+ vnc_display = 0;
+ break;
++ case QEMU_OPTION_vnclisten:
++ parse_host(&vnclisten_addr, optarg);
++ break;
+ }
+ }
+ }
+@@ -6493,7 +6508,7 @@
+ if (nographic) {
+ dumb_display_init(ds);
+ } else if (vnc_display != -1) {
+- vnc_display = vnc_display_init(ds, vnc_display, vncunused);
++ vnc_display = vnc_display_init(ds, vnc_display, vncunused, &vnclisten_addr);
+ if (vncviewer)
+ vnc_start_viewer(vnc_display);
+ } else {
+Index: ioemu/vl.h
+===================================================================
+--- ioemu.orig/vl.h 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:34:22.000000000 +0100
+@@ -37,6 +37,8 @@
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
++#include <sys/socket.h>
++#include <sys/types.h>
+ #include "xenctrl.h"
+ #include "xs.h"
+ #include <xen/hvm/e820.h>
+@@ -785,7 +787,7 @@
+ void cocoa_display_init(DisplayState *ds, int full_screen);
+
+ /* vnc.c */
+-int vnc_display_init(DisplayState *ds, int display, int find_unused);
++int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sockaddr_in *addr);
+ int vnc_start_viewer(int port);
+
+ /* ide.c */
+Index: ioemu/vnc.c
+===================================================================
+--- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:34:22.000000000 +0100
+@@ -1195,9 +1195,8 @@
+ }
+ }
+
+-int vnc_display_init(DisplayState *ds, int display, int find_unused)
++int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sockaddr_in *addr)
+ {
+- struct sockaddr_in addr;
+ int reuse_addr, ret;
+ VncState *vs;
+
+@@ -1235,11 +1234,10 @@
+ }
+
+ retry:
+- addr.sin_family = AF_INET;
+- addr.sin_port = htons(5900 + display);
+- memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
++ addr->sin_family = AF_INET;
++ addr->sin_port = htons(5900 + display);
+
+- if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
++ if (bind(vs->lsock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) {
+ if (find_unused && errno == EADDRINUSE) {
+ display++;
+ goto retry;
diff --git a/tools/ioemu/patches/vnc-password b/tools/ioemu/patches/vnc-password
new file mode 100644
index 0000000000..49c5d73b47
--- /dev/null
+++ b/tools/ioemu/patches/vnc-password
@@ -0,0 +1,785 @@
+# HG changeset patch
+# User kfraser@localhost.localdomain
+# Node ID 02506a7443155611d6bbf03e49fbf193e96d24db
+# Parent 328606e0705f0341bebda14cdd17962e463868e8
+[HVM] Implement password authentication of VNC connections.
+
+The specification is as mentioned at
+http://lists.xensource.com/archives/html/xen-devel/2006-09/msg00666.html
+(However, password came to describe plain text)
+
+The difference is follows.
+- protocol_authtype() without the necessity was deleted.
+- The check on the protocol version was added.
+- And, some small modification.
+
+Signed-off-by: Masami Watanabe <masami.watanabe@jp.fujitsu.com>
+
+--- ioemu/Makefile.target Fri Oct 20 09:32:16 2006 +0100
++++ ioemu/Makefile.target Fri Oct 20 09:50:09 2006 +0100
+@@ -406,6 +406,7 @@ VL_OBJS+=sdl.o
+ VL_OBJS+=sdl.o
+ endif
+ VL_OBJS+=vnc.o
++VL_OBJS+=d3des.o
+ ifdef CONFIG_COCOA
+ VL_OBJS+=cocoa.o
+ COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
+@@ -464,6 +465,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+ vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
++ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
++
++d3des.o: d3des.c d3des.h
+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
+
+ sdlaudio.o: sdlaudio.c
+--- ioemu/vl.c Fri Oct 20 09:32:16 2006 +0100
++++ ioemu/vl.c Fri Oct 20 09:50:09 2006 +0100
+@@ -170,6 +170,9 @@ time_t timeoffset = 0;
+
+ char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'};
+ extern int domid;
++
++char vncpasswd[64];
++unsigned char challenge[AUTHCHALLENGESIZE];
+
+ /***********************************************************/
+ /* x86 ISA bus support */
+@@ -5911,6 +5914,7 @@ int main(int argc, char **argv)
+ vncunused = 0;
+ kernel_filename = NULL;
+ kernel_cmdline = "";
++ *vncpasswd = '\0';
+ #ifndef CONFIG_DM
+ #ifdef TARGET_PPC
+ cdrom_index = 1;
+@@ -6559,6 +6563,10 @@ int main(int argc, char **argv)
+
+ init_ioports();
+
++ /* read vncpasswd from xenstore */
++ if (0 > xenstore_read_vncpasswd(domid))
++ exit(1);
++
+ /* terminal init */
+ if (nographic) {
+ dumb_display_init(ds);
+--- ioemu/vl.h Fri Oct 20 09:32:16 2006 +0100
++++ ioemu/vl.h Fri Oct 20 09:50:09 2006 +0100
+@@ -1211,6 +1211,7 @@ void xenstore_process_event(void *opaque
+ void xenstore_process_event(void *opaque);
+ void xenstore_check_new_media_present(int timeout);
+ void xenstore_write_vncport(int vnc_display);
++int xenstore_read_vncpasswd(int domid);
+
+ /* xen_platform.c */
+ void pci_xen_platform_init(PCIBus *bus);
+@@ -1222,4 +1223,7 @@ extern char domain_name[];
+
+ void destroy_hvm_domain(void);
+
++/* VNC Authentication */
++#define AUTHCHALLENGESIZE 16
++
+ #endif /* VL_H */
+--- ioemu/vnc.c Fri Oct 20 09:32:16 2006 +0100
++++ ioemu/vnc.c Fri Oct 20 09:50:09 2006 +0100
+@@ -44,6 +44,7 @@
+
+ #include "vnc_keysym.h"
+ #include "keymaps.c"
++#include "d3des.h"
+
+ #define XK_MISCELLANY
+ #define XK_LATIN1
+@@ -137,6 +138,9 @@ static void vnc_update_client(void *opaq
+ static void vnc_update_client(void *opaque);
+ static void vnc_client_read(void *opaque);
+ static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
++static int make_challenge(char *random, int size);
++static void set_seed(unsigned int *seedp);
++static void get_random(int len, unsigned char *buf);
+
+ #if 0
+ static inline void vnc_set_bit(uint32_t *d, int k)
+@@ -1208,23 +1212,92 @@ static int protocol_client_init(VncState
+ return 0;
+ }
+
++static int protocol_response(VncState *vs, char *client_response, size_t len)
++{
++ extern char vncpasswd[64];
++ extern unsigned char challenge[AUTHCHALLENGESIZE];
++ unsigned char cryptchallenge[AUTHCHALLENGESIZE];
++ unsigned char key[8];
++ int passwdlen, i, j;
++
++ memcpy(cryptchallenge, challenge, AUTHCHALLENGESIZE);
++
++ /* Calculate the sent challenge */
++ passwdlen = strlen(vncpasswd);
++ for (i=0; i<8; i++)
++ key[i] = i<passwdlen ? vncpasswd[i] : 0;
++ deskey(key, EN0);
++ for (j = 0; j < AUTHCHALLENGESIZE; j += 8)
++ des(cryptchallenge+j, cryptchallenge+j);
++
++ /* Check the actual response */
++ if (memcmp(cryptchallenge, client_response, AUTHCHALLENGESIZE) != 0) {
++ /* password error */
++ vnc_write_u32(vs, 1);
++ vnc_write_u32(vs, 22);
++ vnc_write(vs, "Authentication failure", 22);
++ vnc_flush(vs);
++ fprintf(stderr, "VNC Password error.\n");
++ vnc_client_error(vs);
++ return 0;
++ }
++
++ vnc_write_u32(vs, 0);
++ vnc_flush(vs);
++
++ vnc_read_when(vs, protocol_client_init, 1);
++
++ return 0;
++}
++
+ static int protocol_version(VncState *vs, char *version, size_t len)
+ {
++ extern char vncpasswd[64];
++ extern unsigned char challenge[AUTHCHALLENGESIZE];
+ char local[13];
+- int maj, min;
++ int support, maj, min;
+
+ memcpy(local, version, 12);
+ local[12] = 0;
+
++ /* protocol version check */
+ if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
++ fprintf(stderr, "Protocol version error.\n");
+ vnc_client_error(vs);
+ return 0;
+ }
+
+- vnc_write_u32(vs, 1); /* None */
+- vnc_flush(vs);
+-
+- vnc_read_when(vs, protocol_client_init, 1);
++
++ support = 0;
++ if (maj = 3) {
++ if (min == 3 || min ==4) {
++ support = 1;
++ }
++ }
++
++ if (! support) {
++ fprintf(stderr, "Client uses unsupported protocol version %d.%d.\n",
++ maj, min);
++ vnc_client_error(vs);
++ return 0;
++ }
++
++ if (*vncpasswd == '\0') {
++ /* AuthType is None */
++ vnc_write_u32(vs, 1);
++ vnc_flush(vs);
++ vnc_read_when(vs, protocol_client_init, 1);
++ } else {
++ /* AuthType is VncAuth */
++ vnc_write_u32(vs, 2);
++
++ /* Challenge-Responce authentication */
++ /* Send Challenge */
++ make_challenge(challenge, AUTHCHALLENGESIZE);
++ vnc_write(vs, challenge, AUTHCHALLENGESIZE);
++ vnc_flush(vs);
++ vnc_read_when(vs, protocol_response, AUTHCHALLENGESIZE);
++ }
+
+ return 0;
+ }
+@@ -1342,3 +1415,32 @@ int vnc_start_viewer(int port)
+ return pid;
+ }
+ }
++
++unsigned int seed;
++
++static int make_challenge(char *random, int size)
++{
++
++ set_seed(&seed);
++ get_random(size, random);
++
++ return 0;
++}
++
++static void set_seed(unsigned int *seedp)
++{
++ *seedp += (unsigned int)(time(NULL)+getpid()+getpid()*987654+rand());
++ srand(*seedp);
++
++ return;
++}
++
++static void get_random(int len, unsigned char *buf)
++{
++ int i;
++
++ for (i=0; i<len; i++)
++ buf[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
++
++ return;
++}
+--- ioemu/xenstore.c Fri Oct 20 09:32:16 2006 +0100
++++ ioemu/xenstore.c Fri Oct 20 09:50:09 2006 +0100
+@@ -213,3 +213,54 @@ void xenstore_write_vncport(int display)
+ free(portstr);
+ free(buf);
+ }
++
++int xenstore_read_vncpasswd(int domid)
++{
++ extern char vncpasswd[64];
++ char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
++ unsigned int i, len, rc = 0;
++
++ if (xsh == NULL) {
++ return -1;
++ }
++
++ path = xs_get_domain_path(xsh, domid);
++ if (path == NULL) {
++ fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
++ return -1;
++ }
++
++ pasprintf(&buf, "%s/vm", path);
++ uuid = xs_read(xsh, XBT_NULL, buf, &len);
++ if (uuid == NULL) {
++ fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
++ free(path);
++ return -1;
++ }
++
++ pasprintf(&buf, "%s/vncpasswd", uuid);
++ passwd = xs_read(xsh, XBT_NULL, buf, &len);
++ if (passwd == NULL) {
++ fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
++ free(uuid);
++ free(path);
++ return rc;
++ }
++
++ for (i=0; i<len && i<63; i++) {
++ vncpasswd[i] = passwd[i];
++ passwd[i] = '\0';
++ }
++ vncpasswd[len] = '\0';
++ pasprintf(&buf, "%s/vncpasswd", uuid);
++ if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
++ fprintf(logfile, "xs_write() vncpasswd failed.\n");
++ rc = -1;
++ }
++
++ free(passwd);
++ free(uuid);
++ free(path);
++
++ return rc;
++}
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ ioemu/d3des.c Fri Oct 20 09:50:09 2006 +0100
+@@ -0,0 +1,434 @@
++/*
++ * This is D3DES (V5.09) by Richard Outerbridge with the double and
++ * triple-length support removed for use in VNC. Also the bytebit[] array
++ * has been reversed so that the most significant bit in each byte of the
++ * key is ignored, not the least significant.
++ *
++ * These changes are:
++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
++ *
++ * This software 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.
++ */
++
++/* D3DES (V5.09) -
++ *
++ * A portable, public domain, version of the Data Encryption Standard.
++ *
++ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
++ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
++ * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
++ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
++ * for humouring me on.
++ *
++ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
++ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
++ */
++
++#include "d3des.h"
++
++static void scrunch(unsigned char *, unsigned long *);
++static void unscrun(unsigned long *, unsigned char *);
++static void desfunc(unsigned long *, unsigned long *);
++static void cookey(unsigned long *);
++
++static unsigned long KnL[32] = { 0L };
++
++static unsigned short bytebit[8] = {
++ 01, 02, 04, 010, 020, 040, 0100, 0200 };
++
++static unsigned long bigbyte[24] = {
++ 0x800000L, 0x400000L, 0x200000L, 0x100000L,
++ 0x80000L, 0x40000L, 0x20000L, 0x10000L,
++ 0x8000L, 0x4000L, 0x2000L, 0x1000L,
++ 0x800L, 0x400L, 0x200L, 0x100L,
++ 0x80L, 0x40L, 0x20L, 0x10L,
++ 0x8L, 0x4L, 0x2L, 0x1L };
++
++/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
++
++static unsigned char pc1[56] = {
++ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
++ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
++ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
++ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
++
++static unsigned char totrot[16] = {
++ 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
++
++static unsigned char pc2[48] = {
++ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
++ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
++ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
++ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
++
++void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
++unsigned char *key;
++int edf;
++{
++ register int i, j, l, m, n;
++ unsigned char pc1m[56], pcr[56];
++ unsigned long kn[32];
++
++ for ( j = 0; j < 56; j++ ) {
++ l = pc1[j];
++ m = l & 07;
++ pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
++ }
++ for( i = 0; i < 16; i++ ) {
++ if( edf == DE1 ) m = (15 - i) << 1;
++ else m = i << 1;
++ n = m + 1;
++ kn[m] = kn[n] = 0L;
++ for( j = 0; j < 28; j++ ) {
++ l = j + totrot[i];
++ if( l < 28 ) pcr[j] = pc1m[l];
++ else pcr[j] = pc1m[l - 28];
++ }
++ for( j = 28; j < 56; j++ ) {
++ l = j + totrot[i];
++ if( l < 56 ) pcr[j] = pc1m[l];
++ else pcr[j] = pc1m[l - 28];
++ }
++ for( j = 0; j < 24; j++ ) {
++ if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
++ if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
++ }
++ }
++ cookey(kn);
++ return;
++ }
++
++static void cookey(raw1)
++register unsigned long *raw1;
++{
++ register unsigned long *cook, *raw0;
++ unsigned long dough[32];
++ register int i;
++
++ cook = dough;
++ for( i = 0; i < 16; i++, raw1++ ) {
++ raw0 = raw1++;
++ *cook = (*raw0 & 0x00fc0000L) << 6;
++ *cook |= (*raw0 & 0x00000fc0L) << 10;
++ *cook |= (*raw1 & 0x00fc0000L) >> 10;
++ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
++ *cook = (*raw0 & 0x0003f000L) << 12;
++ *cook |= (*raw0 & 0x0000003fL) << 16;
++ *cook |= (*raw1 & 0x0003f000L) >> 4;
++ *cook++ |= (*raw1 & 0x0000003fL);
++ }
++ usekey(dough);
++ return;
++ }
++
++void cpkey(into)
++register unsigned long *into;
++{
++ register unsigned long *from, *endp;
++
++ from = KnL, endp = &KnL[32];
++ while( from < endp ) *into++ = *from++;
++ return;
++ }
++
++void usekey(from)
++register unsigned long *from;
++{
++ register unsigned long *to, *endp;
++
++ to = KnL, endp = &KnL[32];
++ while( to < endp ) *to++ = *from++;
++ return;
++ }
++
++void des(inblock, outblock)
++unsigned char *inblock, *outblock;
++{
++ unsigned long work[2];
++
++ scrunch(inblock, work);
++ desfunc(work, KnL);
++ unscrun(work, outblock);
++ return;
++ }
++
++static void scrunch(outof, into)
++register unsigned char *outof;
++register unsigned long *into;
++{
++ *into = (*outof++ & 0xffL) << 24;
++ *into |= (*outof++ & 0xffL) << 16;
++ *into |= (*outof++ & 0xffL) << 8;
++ *into++ |= (*outof++ & 0xffL);
++ *into = (*outof++ & 0xffL) << 24;
++ *into |= (*outof++ & 0xffL) << 16;
++ *into |= (*outof++ & 0xffL) << 8;
++ *into |= (*outof & 0xffL);
++ return;
++ }
++
++static void unscrun(outof, into)
++register unsigned long *outof;
++register unsigned char *into;
++{
++ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
++ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
++ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
++ *into++ = (unsigned char)(*outof++ & 0xffL);
++ *into++ = (unsigned char)((*outof >> 24) & 0xffL);
++ *into++ = (unsigned char)((*outof >> 16) & 0xffL);
++ *into++ = (unsigned char)((*outof >> 8) & 0xffL);
++ *into = (unsigned char)(*outof & 0xffL);
++ return;
++ }
++
++static unsigned long SP1[64] = {
++ 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
++ 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
++ 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
++ 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
++ 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
++ 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
++ 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
++ 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
++ 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
++ 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
++ 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
++ 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
++ 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
++ 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
++ 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
++
++static unsigned long SP2[64] = {
++ 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
++ 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
++ 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
++ 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
++ 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
++ 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
++ 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
++ 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
++ 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
++ 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
++ 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
++ 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
++ 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
++ 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
++ 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
++ 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
++
++static unsigned long SP3[64] = {
++ 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
++ 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
++ 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
++ 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
++ 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
++ 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
++ 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
++ 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
++ 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
++ 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
++ 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
++ 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
++ 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
++ 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
++ 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
++ 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
++
++static unsigned long SP4[64] = {
++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
++ 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
++ 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
++ 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
++ 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
++ 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
++ 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
++ 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
++ 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
++ 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
++ 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
++ 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
++ 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
++ 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
++ 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
++ 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
++
++static unsigned long SP5[64] = {
++ 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
++ 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
++ 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
++ 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
++ 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
++ 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
++ 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
++ 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
++ 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
++ 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
++ 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
++ 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
++ 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
++ 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
++ 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
++ 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
++
++static unsigned long SP6[64] = {
++ 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
++ 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
++ 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
++ 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
++ 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
++ 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
++ 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
++ 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
++ 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
++ 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
++ 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
++ 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
++ 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
++ 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
++ 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
++ 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
++
++static unsigned long SP7[64] = {
++ 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
++ 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
++ 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
++ 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
++ 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
++ 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
++ 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
++ 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
++ 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
++ 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
++ 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
++ 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
++ 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
++ 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
++ 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
++ 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
++
++static unsigned long SP8[64] = {
++ 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
++ 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
++ 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
++ 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
++ 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
++ 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
++ 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
++ 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
++ 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
++ 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
++ 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
++ 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
++ 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
++ 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
++ 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
++ 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
++
++static void desfunc(block, keys)
++register unsigned long *block, *keys;
++{
++ register unsigned long fval, work, right, leftt;
++ register int round;
++
++ leftt = block[0];
++ right = block[1];
++ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
++ right ^= work;
++ leftt ^= (work << 4);
++ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
++ right ^= work;
++ leftt ^= (work << 16);
++ work = ((right >> 2) ^ leftt) & 0x33333333L;
++ leftt ^= work;
++ right ^= (work << 2);
++ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
++ leftt ^= work;
++ right ^= (work << 8);
++ right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
++ work = (leftt ^ right) & 0xaaaaaaaaL;
++ leftt ^= work;
++ right ^= work;
++ leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
++
++ for( round = 0; round < 8; round++ ) {
++ work = (right << 28) | (right >> 4);
++ work ^= *keys++;
++ fval = SP7[ work & 0x3fL];
++ fval |= SP5[(work >> 8) & 0x3fL];
++ fval |= SP3[(work >> 16) & 0x3fL];
++ fval |= SP1[(work >> 24) & 0x3fL];
++ work = right ^ *keys++;
++ fval |= SP8[ work & 0x3fL];
++ fval |= SP6[(work >> 8) & 0x3fL];
++ fval |= SP4[(work >> 16) & 0x3fL];
++ fval |= SP2[(work >> 24) & 0x3fL];
++ leftt ^= fval;
++ work = (leftt << 28) | (leftt >> 4);
++ work ^= *keys++;
++ fval = SP7[ work & 0x3fL];
++ fval |= SP5[(work >> 8) & 0x3fL];
++ fval |= SP3[(work >> 16) & 0x3fL];
++ fval |= SP1[(work >> 24) & 0x3fL];
++ work = leftt ^ *keys++;
++ fval |= SP8[ work & 0x3fL];
++ fval |= SP6[(work >> 8) & 0x3fL];
++ fval |= SP4[(work >> 16) & 0x3fL];
++ fval |= SP2[(work >> 24) & 0x3fL];
++ right ^= fval;
++ }
++
++ right = (right << 31) | (right >> 1);
++ work = (leftt ^ right) & 0xaaaaaaaaL;
++ leftt ^= work;
++ right ^= work;
++ leftt = (leftt << 31) | (leftt >> 1);
++ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
++ right ^= work;
++ leftt ^= (work << 8);
++ work = ((leftt >> 2) ^ right) & 0x33333333L;
++ right ^= work;
++ leftt ^= (work << 2);
++ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
++ leftt ^= work;
++ right ^= (work << 16);
++ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
++ leftt ^= work;
++ right ^= (work << 4);
++ *block++ = right;
++ *block = leftt;
++ return;
++ }
++
++/* Validation sets:
++ *
++ * Single-length key, single-length plaintext -
++ * Key : 0123 4567 89ab cdef
++ * Plain : 0123 4567 89ab cde7
++ * Cipher : c957 4425 6a5e d31d
++ *
++ * Double-length key, single-length plaintext -
++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
++ * Plain : 0123 4567 89ab cde7
++ * Cipher : 7f1d 0a77 826b 8aff
++ *
++ * Double-length key, double-length plaintext -
++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210
++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
++ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
++ *
++ * Triple-length key, single-length plaintext -
++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
++ * Plain : 0123 4567 89ab cde7
++ * Cipher : de0b 7c06 ae5e 0ed5
++ *
++ * Triple-length key, double-length plaintext -
++ * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
++ * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
++ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
++ *
++ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
++ **********************************************************************/
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ ioemu/d3des.h Fri Oct 20 09:50:09 2006 +0100
+@@ -0,0 +1,51 @@
++/*
++ * This is D3DES (V5.09) by Richard Outerbridge with the double and
++ * triple-length support removed for use in VNC.
++ *
++ * These changes are:
++ * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
++ *
++ * This software 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.
++ */
++
++/* d3des.h -
++ *
++ * Headers and defines for d3des.c
++ * Graven Imagery, 1992.
++ *
++ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
++ * (GEnie : OUTER; CIS : [71755,204])
++ */
++
++#define EN0 0 /* MODE == encrypt */
++#define DE1 1 /* MODE == decrypt */
++
++extern void deskey(unsigned char *, int);
++/* hexkey[8] MODE
++ * Sets the internal key register according to the hexadecimal
++ * key contained in the 8 bytes of hexkey, according to the DES,
++ * for encryption or decryption according to MODE.
++ */
++
++extern void usekey(unsigned long *);
++/* cookedkey[32]
++ * Loads the internal key register with the data in cookedkey.
++ */
++
++extern void cpkey(unsigned long *);
++/* cookedkey[32]
++ * Copies the contents of the internal key register into the storage
++ * located at &cookedkey[0].
++ */
++
++extern void des(unsigned char *, unsigned char *);
++/* from[8] to[8]
++ * Encrypts/Decrypts (according to the key currently loaded in the
++ * internal key register) one block of eight bytes at address 'from'
++ * into the block at address 'to'. They can be the same.
++ */
++
++/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
++ ********************************************************************/
diff --git a/tools/ioemu/patches/vnc-protocol-fixes b/tools/ioemu/patches/vnc-protocol-fixes
new file mode 100644
index 0000000000..84e53614da
--- /dev/null
+++ b/tools/ioemu/patches/vnc-protocol-fixes
@@ -0,0 +1,63 @@
+# HG changeset patch
+# User Steven Smith <ssmith@xensource.com>
+# Node ID ca3abb3804f4400b24037a4366cb2ca5e51ed742
+# Parent 7fca81d456b2cb40d4effe2492f7ed1aafd32f52
+[HVM][VNC] Make sure that qemu doesn't go into an infinite loop when
+it receives certain invalid requests from the viewer.
+
+Signed-off-by: Steven Smith <sos22@cam.ac.uk>
+
+Index: ioemu/vnc.c
+===================================================================
+--- ioemu.orig/vnc.c 2006-10-24 14:28:05.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:30:11.000000000 +0100
+@@ -26,6 +26,7 @@
+
+ #include "vl.h"
+ #include "qemu_socket.h"
++#include <assert.h>
+
+ #define VNC_REFRESH_INTERVAL (1000 / 30)
+
+@@ -677,8 +678,10 @@
+ memmove(vs->input.buffer, vs->input.buffer + len,
+ vs->input.offset - len);
+ vs->input.offset -= len;
+- } else
++ } else {
++ assert(ret > vs->read_handler_expect);
+ vs->read_handler_expect = ret;
++ }
+ }
+ }
+
+@@ -961,8 +964,12 @@
+ if (len == 1)
+ return 4;
+
+- if (len == 4)
+- return 4 + (read_u16(data, 2) * 4);
++ if (len == 4) {
++ uint16_t v;
++ v = read_u16(data, 2);
++ if (v)
++ return 4 + v * 4;
++ }
+
+ limit = read_u16(data, 2);
+ for (i = 0; i < limit; i++) {
+@@ -996,8 +1003,12 @@
+ if (len == 1)
+ return 8;
+
+- if (len == 8)
+- return 8 + read_u32(data, 4);
++ if (len == 8) {
++ uint32_t v;
++ v = read_u32(data, 4);
++ if (v)
++ return 8 + v;
++ }
+
+ client_cut_text(vs, read_u32(data, 4), data + 8);
+ break;
diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer
index 662f482620..95080b9995 100644
--- a/tools/ioemu/patches/vnc-start-vncviewer
+++ b/tools/ioemu/patches/vnc-start-vncviewer
@@ -1,8 +1,8 @@
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:50:12.101798392 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:13.149682567 +0100
-@@ -1175,3 +1175,25 @@
+--- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100
+@@ -1187,3 +1187,25 @@
vnc_dpy_resize(vs->ds, 640, 400);
}
@@ -20,7 +20,7 @@ Index: ioemu/vnc.c
+ exit(1);
+
+ case 0: /* child */
-+ execlp("vncviewer", "vncviewer", s, 0);
++ execlp("vncviewer", "vncviewer", s, NULL);
+ fprintf(stderr, "vncviewer execlp failed\n");
+ exit(1);
+
@@ -30,8 +30,8 @@ Index: ioemu/vnc.c
+}
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:12.100798502 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:13.152682236 +0100
+--- ioemu.orig/vl.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:46.000000000 +0100
@@ -120,6 +120,7 @@
int bios_size;
static DisplayState display_state;
@@ -93,8 +93,8 @@ Index: ioemu/vl.c
sdl_display_init(ds, full_screen);
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:12.102798281 +0100
-+++ ioemu/vl.h 2006-08-17 19:50:13.153682125 +0100
+--- ioemu.orig/vl.h 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:33:46.000000000 +0100
@@ -786,6 +786,7 @@
/* vnc.c */
diff --git a/tools/ioemu/patches/vnc-title-domain-name b/tools/ioemu/patches/vnc-title-domain-name
index b02e8eba5a..2ba1489cf9 100644
--- a/tools/ioemu/patches/vnc-title-domain-name
+++ b/tools/ioemu/patches/vnc-title-domain-name
@@ -1,16 +1,16 @@
Index: ioemu/vnc.c
===================================================================
---- ioemu.orig/vnc.c 2006-08-17 19:50:13.149682567 +0100
-+++ ioemu/vnc.c 2006-08-17 19:50:14.623519661 +0100
-@@ -1014,6 +1014,7 @@
+--- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100
++++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100
+@@ -1024,6 +1024,7 @@
static int protocol_client_init(VncState *vs, char *data, size_t len)
{
+ size_t l;
char pad[3] = { 0, 0, 0 };
- vs->width = vs->ds->width;
-@@ -1059,8 +1060,10 @@
+ vga_hw_update();
+@@ -1071,8 +1072,10 @@
vnc_write(vs, pad, 3); /* padding */
diff --git a/tools/ioemu/patches/xen-build b/tools/ioemu/patches/xen-build
index e96999d505..8aae60d005 100644
--- a/tools/ioemu/patches/xen-build
+++ b/tools/ioemu/patches/xen-build
@@ -1,7 +1,7 @@
Index: ioemu/Makefile
===================================================================
---- ioemu.orig/Makefile 2006-08-28 20:19:23.000000000 +0100
-+++ ioemu/Makefile 2006-08-28 20:20:08.000000000 +0100
+--- ioemu.orig/Makefile 2006-10-24 14:37:25.000000000 +0100
++++ ioemu/Makefile 2006-10-24 14:37:28.000000000 +0100
@@ -1,11 +1,14 @@
# Makefile for QEMU.
@@ -85,8 +85,8 @@ Index: ioemu/Makefile
info: qemu-doc.info qemu-tech.info
Index: ioemu/Makefile.target
===================================================================
---- ioemu.orig/Makefile.target 2006-08-28 20:19:23.000000000 +0100
-+++ ioemu/Makefile.target 2006-08-28 20:19:47.000000000 +0100
+--- ioemu.orig/Makefile.target 2006-10-24 14:37:25.000000000 +0100
++++ ioemu/Makefile.target 2006-10-24 14:40:25.000000000 +0100
@@ -1,5 +1,8 @@
include config.mak
@@ -112,7 +112,7 @@ Index: ioemu/Makefile.target
endif
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing
+CFLAGS+=-Wall -O2 -g -fno-strict-aliasing
-+SSE2 := $(call test-gcc-flag,$(CC),-msse2)
++SSE2 := $(call cc-option,$(CC),-msse2,)
+ifeq ($(SSE2),-msse2)
+CFLAGS += -DUSE_SSE2=1 -msse2
+endif
@@ -149,17 +149,18 @@ Index: ioemu/Makefile.target
install: all
+ mkdir -p "$(DESTDIR)$(bindir)" "$(DESTDIR)$(configdir)"
ifneq ($(PROGS),)
- $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
+- $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
++ $(INSTALL_PROG) $(PROGS) "$(DESTDIR)$(bindir)"
endif
-+ install -m 755 $(TARGET_PATH)/qemu-dm.debug "$(DESTDIR)$(bindir)"
-+ install -m 755 $(TARGET_PATH)/qemu-ifup "$(DESTDIR)$(configdir)"
++ $(INSTALL_PROG) $(TARGET_PATH)/qemu-dm.debug "$(DESTDIR)$(bindir)"
++ $(INSTALL_PROG) $(TARGET_PATH)/qemu-ifup "$(DESTDIR)$(configdir)"
ifneq ($(wildcard .depend),)
include .depend
Index: ioemu/configure
===================================================================
---- ioemu.orig/configure 2006-08-28 20:19:23.000000000 +0100
-+++ ioemu/configure 2006-08-28 20:19:47.000000000 +0100
+--- ioemu.orig/configure 2006-10-24 14:37:25.000000000 +0100
++++ ioemu/configure 2006-10-24 14:40:20.000000000 +0100
@@ -18,8 +18,8 @@
# default parameters
diff --git a/tools/ioemu/patches/xen-platform-device b/tools/ioemu/patches/xen-platform-device
index 09dcaf6e5f..d2fcda7452 100644
--- a/tools/ioemu/patches/xen-platform-device
+++ b/tools/ioemu/patches/xen-platform-device
@@ -3,8 +3,8 @@ will come later.
Index: ioemu/Makefile.target
===================================================================
---- ioemu.orig/Makefile.target 2006-08-17 19:50:18.866050726 +0100
-+++ ioemu/Makefile.target 2006-08-17 19:55:35.776020218 +0100
+--- ioemu.orig/Makefile.target 2006-10-24 14:41:01.000000000 +0100
++++ ioemu/Makefile.target 2006-10-24 14:41:01.000000000 +0100
@@ -359,6 +359,7 @@
VL_OBJS+= usb-uhci.o
VL_OBJS+= piix4acpi.o
@@ -15,8 +15,8 @@ Index: ioemu/Makefile.target
ifeq ($(TARGET_BASE_ARCH), ppc)
Index: ioemu/hw/pc.c
===================================================================
---- ioemu.orig/hw/pc.c 2006-08-17 19:50:02.406869984 +0100
-+++ ioemu/hw/pc.c 2006-08-17 19:55:35.777020107 +0100
+--- ioemu.orig/hw/pc.c 2006-10-24 14:41:00.000000000 +0100
++++ ioemu/hw/pc.c 2006-10-24 14:41:01.000000000 +0100
@@ -823,6 +823,9 @@
}
#endif /* !CONFIG_DM */
@@ -30,8 +30,8 @@ Index: ioemu/hw/pc.c
Index: ioemu/hw/xen_platform.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/hw/xen_platform.c 2006-08-17 19:55:35.777020107 +0100
-@@ -0,0 +1,138 @@
++++ ioemu/hw/xen_platform.c 2006-10-24 14:41:04.000000000 +0100
+@@ -0,0 +1,144 @@
+/*
+ * XEN platform fake pci device, formerly known as the event channel device
+ *
@@ -131,7 +131,8 @@ Index: ioemu/hw/xen_platform.c
+ uint8_t bist; /* Built in self test */
+ uint32_t base_address_regs[6];
+ uint32_t reserved1;
-+ uint32_t reserved2;
++ uint16_t subsystem_vendor_id;
++ uint16_t subsystem_id;
+ uint32_t rom_addr;
+ uint32_t reserved3;
+ uint32_t reserved4;
@@ -150,16 +151,21 @@ Index: ioemu/hw/xen_platform.c
+ d = pci_register_device(bus, "xen-platform", sizeof(PCIDevice), -1, NULL,
+ NULL);
+ pch = (struct pci_config_header *)d->config;
-+ pch->vendor_id = 0xfffd;
-+ pch->device_id = 0x0101;
++ pch->vendor_id = 0x5853;
++ pch->device_id = 0x0001;
+ pch->command = 3; /* IO and memory access */
-+ pch->revision = 0;
++ pch->revision = 1;
+ pch->api = 0;
+ pch->subclass = 0x80; /* Other */
+ pch->class = 0xff; /* Unclassified device class */
+ pch->header_type = 0;
+ pch->interrupt_pin = 1;
+
++ /* Microsoft WHQL requires non-zero subsystem IDs. */
++ /* http://www.pcisig.com/reflector/msg02205.html. */
++ pch->subsystem_vendor_id = pch->vendor_id; /* Duplicate vendor id. */
++ pch->subsystem_id = 0x0001; /* Hardcode sub-id as 1. */
++
+ pci_register_io_region(d, 0, 0x100, PCI_ADDRESS_SPACE_IO,
+ platform_ioport_map);
+
@@ -172,9 +178,9 @@ Index: ioemu/hw/xen_platform.c
+}
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:22.278673522 +0100
-+++ ioemu/vl.h 2006-08-17 19:55:35.778019997 +0100
-@@ -1209,6 +1209,9 @@
+--- ioemu.orig/vl.h 2006-10-24 14:41:01.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:41:01.000000000 +0100
+@@ -1212,6 +1212,9 @@
void xenstore_check_new_media_present(int timeout);
void xenstore_write_vncport(int vnc_display);
diff --git a/tools/ioemu/patches/xen-support-buffered-ioreqs b/tools/ioemu/patches/xen-support-buffered-ioreqs
index 77ed854258..7865dda35b 100644
--- a/tools/ioemu/patches/xen-support-buffered-ioreqs
+++ b/tools/ioemu/patches/xen-support-buffered-ioreqs
@@ -1,8 +1,8 @@
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:22.277673633 +0100
-+++ ioemu/vl.c 2006-08-17 19:55:21.878556486 +0100
-@@ -5838,6 +5838,7 @@
+--- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100
+@@ -5854,6 +5854,7 @@
unsigned long nr_pages, tmp_nr_pages, shared_page_nr;
xen_pfn_t *page_array;
extern void *shared_page;
@@ -10,7 +10,7 @@ Index: ioemu/vl.c
char qemu_dm_logfilename[64];
-@@ -6419,6 +6420,18 @@
+@@ -6440,6 +6441,18 @@
fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n",
shared_page_nr, (uint64_t)(page_array[shared_page_nr]));
@@ -31,8 +31,8 @@ Index: ioemu/vl.c
#elif defined(__ia64__)
Index: ioemu/target-i386-dm/helper2.c
===================================================================
---- ioemu.orig/target-i386-dm/helper2.c 2006-08-17 19:49:44.491850141 +0100
-+++ ioemu/target-i386-dm/helper2.c 2006-08-17 19:50:41.490549986 +0100
+--- ioemu.orig/target-i386-dm/helper2.c 2006-10-24 14:33:45.000000000 +0100
++++ ioemu/target-i386-dm/helper2.c 2006-10-24 14:33:47.000000000 +0100
@@ -76,6 +76,10 @@
shared_iopage_t *shared_page = NULL;
diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config
index 69d32c7389..e3782d5b65 100644
--- a/tools/ioemu/patches/xenstore-block-device-config
+++ b/tools/ioemu/patches/xenstore-block-device-config
@@ -1,7 +1,7 @@
Index: ioemu/Makefile.target
===================================================================
---- ioemu.orig/Makefile.target 2006-08-17 19:50:02.405870095 +0100
-+++ ioemu/Makefile.target 2006-08-17 19:50:18.866050726 +0100
+--- ioemu.orig/Makefile.target 2006-10-24 14:31:36.000000000 +0100
++++ ioemu/Makefile.target 2006-10-24 14:33:28.000000000 +0100
@@ -358,6 +358,7 @@
VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
VL_OBJS+= usb-uhci.o
@@ -13,7 +13,7 @@ Index: ioemu/Makefile.target
Index: ioemu/xenstore.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ ioemu/xenstore.c 2006-08-17 19:50:18.867050616 +0100
++++ ioemu/xenstore.c 2006-10-24 14:33:28.000000000 +0100
@@ -0,0 +1,187 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General
@@ -204,9 +204,9 @@ Index: ioemu/xenstore.c
+}
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:17.086247452 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:18.870050284 +0100
-@@ -5243,9 +5243,11 @@
+--- ioemu.orig/vl.c 2006-10-24 14:33:24.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:28.000000000 +0100
+@@ -5256,9 +5256,11 @@
"Standard options:\n"
"-M machine select emulated machine (-M ? for list)\n"
"-fda/-fdb file use 'file' as floppy disk 0/1 image\n"
@@ -218,7 +218,7 @@ Index: ioemu/vl.c
"-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n"
"-snapshot write to temporary files instead of disk image files\n"
#ifdef TARGET_I386
-@@ -5372,11 +5374,13 @@
+@@ -5386,11 +5388,13 @@
QEMU_OPTION_M,
QEMU_OPTION_fda,
QEMU_OPTION_fdb,
@@ -232,7 +232,7 @@ Index: ioemu/vl.c
QEMU_OPTION_boot,
QEMU_OPTION_snapshot,
#ifdef TARGET_I386
-@@ -5448,11 +5452,13 @@
+@@ -5463,11 +5467,13 @@
{ "M", HAS_ARG, QEMU_OPTION_M },
{ "fda", HAS_ARG, QEMU_OPTION_fda },
{ "fdb", HAS_ARG, QEMU_OPTION_fdb },
@@ -246,7 +246,7 @@ Index: ioemu/vl.c
{ "boot", HAS_ARG, QEMU_OPTION_boot },
{ "snapshot", 0, QEMU_OPTION_snapshot },
#ifdef TARGET_I386
-@@ -5801,10 +5807,16 @@
+@@ -5817,10 +5823,16 @@
#ifdef CONFIG_GDBSTUB
int use_gdbstub, gdbstub_port;
#endif
@@ -265,7 +265,7 @@ Index: ioemu/vl.c
const char *kernel_filename, *kernel_cmdline;
DisplayState *ds = &display_state;
int cyls, heads, secs, translation;
-@@ -5865,8 +5877,10 @@
+@@ -5881,8 +5893,10 @@
initrd_filename = NULL;
for(i = 0; i < MAX_FD; i++)
fd_filename[i] = NULL;
@@ -276,7 +276,7 @@ Index: ioemu/vl.c
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
vga_ram_size = VGA_RAM_SIZE;
bios_size = BIOS_SIZE;
-@@ -5880,11 +5894,13 @@
+@@ -5896,11 +5910,13 @@
vncunused = 0;
kernel_filename = NULL;
kernel_cmdline = "";
@@ -290,7 +290,7 @@ Index: ioemu/vl.c
cyls = heads = secs = 0;
translation = BIOS_ATA_TRANSLATION_AUTO;
pstrcpy(monitor_device, sizeof(monitor_device), "vc");
-@@ -5917,7 +5933,11 @@
+@@ -5935,7 +5951,11 @@
break;
r = argv[optind];
if (r[0] != '-') {
@@ -302,7 +302,7 @@ Index: ioemu/vl.c
} else {
const QEMUOption *popt;
-@@ -5961,6 +5981,7 @@
+@@ -5979,6 +5999,7 @@
case QEMU_OPTION_initrd:
initrd_filename = optarg;
break;
@@ -310,7 +310,7 @@ Index: ioemu/vl.c
case QEMU_OPTION_hda:
case QEMU_OPTION_hdb:
case QEMU_OPTION_hdc:
-@@ -5973,6 +5994,7 @@
+@@ -5991,6 +6012,7 @@
cdrom_index = -1;
}
break;
@@ -318,7 +318,7 @@ Index: ioemu/vl.c
case QEMU_OPTION_snapshot:
snapshot = 1;
break;
-@@ -6025,11 +6047,13 @@
+@@ -6043,11 +6065,13 @@
case QEMU_OPTION_append:
kernel_cmdline = optarg;
break;
@@ -332,7 +332,7 @@ Index: ioemu/vl.c
case QEMU_OPTION_boot:
boot_device = optarg[0];
if (boot_device != 'a' &&
-@@ -6284,12 +6308,18 @@
+@@ -6305,12 +6329,18 @@
}
}
@@ -351,7 +351,7 @@ Index: ioemu/vl.c
if (!linux_boot &&
hd_filename[0] == '\0' &&
(cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
-@@ -6303,6 +6333,7 @@
+@@ -6324,6 +6354,7 @@
else
boot_device = 'd';
}
@@ -359,7 +359,7 @@ Index: ioemu/vl.c
setvbuf(stdout, NULL, _IOLBF, 0);
-@@ -6435,6 +6466,7 @@
+@@ -6456,6 +6487,7 @@
#endif /* !CONFIG_DM */
@@ -367,7 +367,7 @@ Index: ioemu/vl.c
/* we always create the cdrom drive, even if no disk is there */
bdrv_init();
if (cdrom_index >= 0) {
-@@ -6461,6 +6493,7 @@
+@@ -6482,6 +6514,7 @@
}
}
}
@@ -375,7 +375,7 @@ Index: ioemu/vl.c
/* we always create at least one floppy disk */
fd_table[0] = bdrv_new("fda");
-@@ -6539,6 +6572,8 @@
+@@ -6560,6 +6593,8 @@
}
}
@@ -386,8 +386,8 @@ Index: ioemu/vl.c
kernel_filename, kernel_cmdline, initrd_filename,
Index: ioemu/monitor.c
===================================================================
---- ioemu.orig/monitor.c 2006-08-17 19:49:44.491850141 +0100
-+++ ioemu/monitor.c 2006-08-17 19:50:18.871050174 +0100
+--- ioemu.orig/monitor.c 2006-10-24 14:31:36.000000000 +0100
++++ ioemu/monitor.c 2006-10-24 14:33:28.000000000 +0100
@@ -24,6 +24,7 @@
#include "vl.h"
#include "disas.h"
@@ -416,8 +416,8 @@ Index: ioemu/monitor.c
int i;
Index: ioemu/block.c
===================================================================
---- ioemu.orig/block.c 2006-08-17 19:37:35.865578948 +0100
-+++ ioemu/block.c 2006-08-17 19:50:18.872050063 +0100
+--- ioemu.orig/block.c 2006-10-24 14:31:36.000000000 +0100
++++ ioemu/block.c 2006-10-24 14:33:28.000000000 +0100
@@ -758,6 +758,7 @@
static void raw_close(BlockDriverState *bs)
{
@@ -428,9 +428,9 @@ Index: ioemu/block.c
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:17.087247341 +0100
-+++ ioemu/vl.h 2006-08-17 19:50:18.872050063 +0100
-@@ -1188,6 +1188,8 @@
+--- ioemu.orig/vl.h 2006-10-24 14:33:24.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:33:28.000000000 +0100
+@@ -1191,6 +1191,8 @@
void term_print_help(void);
void monitor_readline(const char *prompt, int is_password,
char *buf, int buf_size);
@@ -439,7 +439,7 @@ Index: ioemu/vl.h
/* readline.c */
typedef void ReadLineFunc(void *opaque, const char *str);
-@@ -1200,6 +1202,13 @@
+@@ -1203,6 +1205,13 @@
void readline_start(const char *prompt, int is_password,
ReadLineFunc *readline_func, void *opaque);
@@ -455,8 +455,8 @@ Index: ioemu/vl.h
extern char domain_name[];
Index: ioemu/hw/ide.c
===================================================================
---- ioemu.orig/hw/ide.c 2006-08-17 19:49:57.830375828 +0100
-+++ ioemu/hw/ide.c 2006-08-17 19:50:18.874049842 +0100
+--- ioemu.orig/hw/ide.c 2006-10-24 14:31:36.000000000 +0100
++++ ioemu/hw/ide.c 2006-10-24 14:33:28.000000000 +0100
@@ -1158,6 +1158,7 @@
} else {
ide_atapi_cmd_error(s, SENSE_NOT_READY,
diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port
index c9df265430..6db523e980 100644
--- a/tools/ioemu/patches/xenstore-write-vnc-port
+++ b/tools/ioemu/patches/xenstore-write-vnc-port
@@ -1,7 +1,7 @@
Index: ioemu/xenstore.c
===================================================================
---- ioemu.orig/xenstore.c 2006-08-17 19:50:18.867050616 +0100
-+++ ioemu/xenstore.c 2006-08-17 19:50:22.274673964 +0100
+--- ioemu.orig/xenstore.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/xenstore.c 2006-10-24 14:33:47.000000000 +0100
@@ -185,3 +185,31 @@
free(image);
free(vec);
@@ -36,10 +36,10 @@ Index: ioemu/xenstore.c
+}
Index: ioemu/vl.c
===================================================================
---- ioemu.orig/vl.c 2006-08-17 19:50:18.870050284 +0100
-+++ ioemu/vl.c 2006-08-17 19:50:22.277673633 +0100
-@@ -6529,6 +6529,7 @@
- vnc_display = vnc_display_init(ds, vnc_display, vncunused);
+--- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100
+@@ -6550,6 +6550,7 @@
+ vnc_display = vnc_display_init(ds, vnc_display, vncunused, &vnclisten_addr);
if (vncviewer)
vnc_start_viewer(vnc_display);
+ xenstore_write_vncport(vnc_display);
@@ -48,9 +48,9 @@ Index: ioemu/vl.c
sdl_display_init(ds, full_screen);
Index: ioemu/vl.h
===================================================================
---- ioemu.orig/vl.h 2006-08-17 19:50:18.872050063 +0100
-+++ ioemu/vl.h 2006-08-17 19:50:22.278673522 +0100
-@@ -1207,6 +1207,7 @@
+--- ioemu.orig/vl.h 2006-10-24 14:33:47.000000000 +0100
++++ ioemu/vl.h 2006-10-24 14:33:47.000000000 +0100
+@@ -1210,6 +1210,7 @@
int xenstore_fd(void);
void xenstore_process_event(void *opaque);
void xenstore_check_new_media_present(int timeout);
diff --git a/tools/ioemu/target-i386-dm/cpu.h b/tools/ioemu/target-i386-dm/cpu.h
index 8bc6c7bda9..dc016edd3e 100644
--- a/tools/ioemu/target-i386-dm/cpu.h
+++ b/tools/ioemu/target-i386-dm/cpu.h
@@ -55,8 +55,6 @@ typedef struct CPUX86State {
int interrupt_request;
CPU_COMMON
-
- int send_event;
} CPUX86State;
CPUX86State *cpu_x86_init(void);
diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c
index cd7af5583f..be8b280dda 100644
--- a/tools/ioemu/target-i386-dm/exec-dm.c
+++ b/tools/ioemu/target-i386-dm/exec-dm.c
@@ -32,6 +32,8 @@
#include <unistd.h>
#include <inttypes.h>
+#include <xen/hvm/e820.h>
+
#include "cpu.h"
#include "exec-all.h"
@@ -407,22 +409,36 @@ int iomem_index(target_phys_addr_t addr)
return 0;
}
+static inline int paddr_is_ram(target_phys_addr_t addr)
+{
+ /* Is this guest physical address RAM-backed? */
+#if defined(CONFIG_DM) && (defined(__i386__) || defined(__x86_64__))
+ if (ram_size <= HVM_BELOW_4G_RAM_END)
+ /* RAM is contiguous */
+ return (addr < ram_size);
+ else
+ /* There is RAM below and above the MMIO hole */
+ return ((addr < HVM_BELOW_4G_MMIO_START) ||
+ ((addr >= HVM_BELOW_4G_MMIO_START + HVM_BELOW_4G_MMIO_LENGTH)
+ && (addr < ram_size + HVM_BELOW_4G_MMIO_LENGTH)));
+#else
+ return (addr < ram_size);
+#endif
+}
+
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write)
{
int l, io_index;
uint8_t *ptr;
uint32_t val;
- target_phys_addr_t page;
- unsigned long pd;
while (len > 0) {
- page = addr & TARGET_PAGE_MASK;
- l = (page + TARGET_PAGE_SIZE) - addr;
+ /* How much can we copy before the next page boundary? */
+ l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
if (l > len)
l = len;
- pd = page;
io_index = iomem_index(addr);
if (is_write) {
if (io_index) {
@@ -442,15 +458,11 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
l = 1;
}
- } else {
- unsigned long addr1;
-
- addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
- /* RAM case */
- ptr = phys_ram_base + addr1;
- memcpy(ptr, buf, l);
+ } else if (paddr_is_ram(addr)) {
+ /* Reading from RAM */
+ memcpy(phys_ram_base + addr, buf, l);
#ifdef __ia64__
- sync_icache((unsigned long)ptr, l);
+ sync_icache((unsigned long)(phys_ram_base + addr), l);
#endif
}
} else {
@@ -471,14 +483,12 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
stb_raw(buf, val);
l = 1;
}
- } else if (addr < ram_size) {
- /* RAM case */
- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
- (addr & ~TARGET_PAGE_MASK);
- memcpy(buf, ptr, l);
+ } else if (paddr_is_ram(addr)) {
+ /* Reading from RAM */
+ memcpy(buf, phys_ram_base + addr, l);
} else {
- /* unreported MMIO space */
- memset(buf, 0xff, len);
+ /* Neither RAM nor known MMIO space */
+ memset(buf, 0xff, len);
}
}
len -= l;
diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c
index 83fc5e8f00..aa7b042561 100644
--- a/tools/ioemu/target-i386-dm/helper2.c
+++ b/tools/ioemu/target-i386-dm/helper2.c
@@ -193,10 +193,10 @@ void sp_info()
for (i = 0; i < vcpus; i++) {
req = &(shared_page->vcpu_iodata[i].vp_ioreq);
term_printf("vcpu %d: event port %d\n", i, ioreq_local_port[i]);
- term_printf(" req state: %x, pvalid: %x, addr: %"PRIx64", "
+ term_printf(" req state: %x, ptr: %x, addr: %"PRIx64", "
"data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
- req->state, req->pdata_valid, req->addr,
- req->u.data, req->count, req->size);
+ req->state, req->data_is_ptr, req->addr,
+ req->data, req->count, req->size);
term_printf(" IO totally occurred on this vcpu: %"PRIx64"\n",
req->io_count);
}
@@ -209,18 +209,19 @@ static ioreq_t *__cpu_get_ioreq(int vcpu)
req = &(shared_page->vcpu_iodata[vcpu].vp_ioreq);
- if (req->state == STATE_IOREQ_READY) {
- req->state = STATE_IOREQ_INPROCESS;
- rmb();
- return req;
+ if (req->state != STATE_IOREQ_READY) {
+ fprintf(logfile, "I/O request not ready: "
+ "%x, ptr: %x, port: %"PRIx64", "
+ "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
+ req->state, req->data_is_ptr, req->addr,
+ req->data, req->count, req->size);
+ return NULL;
}
- fprintf(logfile, "False I/O request ... in-service already: "
- "%x, pvalid: %x, port: %"PRIx64", "
- "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
- req->state, req->pdata_valid, req->addr,
- req->u.data, req->count, req->size);
- return NULL;
+ rmb(); /* see IOREQ_READY /then/ read contents of ioreq */
+
+ req->state = STATE_IOREQ_INPROCESS;
+ return req;
}
//use poll to get the port notification
@@ -305,26 +306,26 @@ void cpu_ioreq_pio(CPUState *env, ioreq_t *req)
sign = req->df ? -1 : 1;
if (req->dir == IOREQ_READ) {
- if (!req->pdata_valid) {
- req->u.data = do_inp(env, req->addr, req->size);
+ if (!req->data_is_ptr) {
+ req->data = do_inp(env, req->addr, req->size);
} else {
unsigned long tmp;
for (i = 0; i < req->count; i++) {
tmp = do_inp(env, req->addr, req->size);
- write_physical((target_phys_addr_t) req->u.pdata
+ write_physical((target_phys_addr_t) req->data
+ (sign * i * req->size),
req->size, &tmp);
}
}
} else if (req->dir == IOREQ_WRITE) {
- if (!req->pdata_valid) {
- do_outp(env, req->addr, req->size, req->u.data);
+ if (!req->data_is_ptr) {
+ do_outp(env, req->addr, req->size, req->data);
} else {
for (i = 0; i < req->count; i++) {
unsigned long tmp;
- read_physical((target_phys_addr_t) req->u.pdata
+ read_physical((target_phys_addr_t) req->data
+ (sign * i * req->size),
req->size, &tmp);
do_outp(env, req->addr, req->size, tmp);
@@ -339,18 +340,18 @@ void cpu_ioreq_move(CPUState *env, ioreq_t *req)
sign = req->df ? -1 : 1;
- if (!req->pdata_valid) {
+ if (!req->data_is_ptr) {
if (req->dir == IOREQ_READ) {
for (i = 0; i < req->count; i++) {
read_physical(req->addr
+ (sign * i * req->size),
- req->size, &req->u.data);
+ req->size, &req->data);
}
} else if (req->dir == IOREQ_WRITE) {
for (i = 0; i < req->count; i++) {
write_physical(req->addr
+ (sign * i * req->size),
- req->size, &req->u.data);
+ req->size, &req->data);
}
}
} else {
@@ -361,13 +362,13 @@ void cpu_ioreq_move(CPUState *env, ioreq_t *req)
read_physical(req->addr
+ (sign * i * req->size),
req->size, &tmp);
- write_physical((target_phys_addr_t )req->u.pdata
+ write_physical((target_phys_addr_t )req->data
+ (sign * i * req->size),
req->size, &tmp);
}
} else if (req->dir == IOREQ_WRITE) {
for (i = 0; i < req->count; i++) {
- read_physical((target_phys_addr_t) req->u.pdata
+ read_physical((target_phys_addr_t) req->data
+ (sign * i * req->size),
req->size, &tmp);
write_physical(req->addr
@@ -382,51 +383,66 @@ void cpu_ioreq_and(CPUState *env, ioreq_t *req)
{
unsigned long tmp1, tmp2;
- if (req->pdata_valid != 0)
+ if (req->data_is_ptr != 0)
+ hw_error("expected scalar value");
+
+ read_physical(req->addr, req->size, &tmp1);
+ if (req->dir == IOREQ_WRITE) {
+ tmp2 = tmp1 & (unsigned long) req->data;
+ write_physical(req->addr, req->size, &tmp2);
+ }
+ req->data = tmp1;
+}
+
+void cpu_ioreq_add(CPUState *env, ioreq_t *req)
+{
+ unsigned long tmp1, tmp2;
+
+ if (req->data_is_ptr != 0)
hw_error("expected scalar value");
read_physical(req->addr, req->size, &tmp1);
if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 & (unsigned long) req->u.data;
+ tmp2 = tmp1 + (unsigned long) req->data;
write_physical(req->addr, req->size, &tmp2);
}
- req->u.data = tmp1;
+ req->data = tmp1;
}
void cpu_ioreq_or(CPUState *env, ioreq_t *req)
{
unsigned long tmp1, tmp2;
- if (req->pdata_valid != 0)
+ if (req->data_is_ptr != 0)
hw_error("expected scalar value");
read_physical(req->addr, req->size, &tmp1);
if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 | (unsigned long) req->u.data;
+ tmp2 = tmp1 | (unsigned long) req->data;
write_physical(req->addr, req->size, &tmp2);
}
- req->u.data = tmp1;
+ req->data = tmp1;
}
void cpu_ioreq_xor(CPUState *env, ioreq_t *req)
{
unsigned long tmp1, tmp2;
- if (req->pdata_valid != 0)
+ if (req->data_is_ptr != 0)
hw_error("expected scalar value");
read_physical(req->addr, req->size, &tmp1);
if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 ^ (unsigned long) req->u.data;
+ tmp2 = tmp1 ^ (unsigned long) req->data;
write_physical(req->addr, req->size, &tmp2);
}
- req->u.data = tmp1;
+ req->data = tmp1;
}
void __handle_ioreq(CPUState *env, ioreq_t *req)
{
- if (!req->pdata_valid && req->dir == IOREQ_WRITE && req->size != 4)
- req->u.data &= (1UL << (8 * req->size)) - 1;
+ if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4)
+ req->data &= (1UL << (8 * req->size)) - 1;
switch (req->type) {
case IOREQ_TYPE_PIO:
@@ -438,6 +454,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req)
case IOREQ_TYPE_AND:
cpu_ioreq_and(env, req);
break;
+ case IOREQ_TYPE_ADD:
+ cpu_ioreq_add(env, req);
+ break;
case IOREQ_TYPE_OR:
cpu_ioreq_or(env, req);
break;
@@ -486,12 +505,19 @@ void cpu_handle_ioreq(void *opaque)
if (req) {
__handle_ioreq(env, req);
- /* No state change if state = STATE_IORESP_HOOK */
- if (req->state == STATE_IOREQ_INPROCESS) {
- mb();
- req->state = STATE_IORESP_READY;
+ if (req->state != STATE_IOREQ_INPROCESS) {
+ fprintf(logfile, "Badness in I/O request ... not in service?!: "
+ "%x, ptr: %x, port: %"PRIx64", "
+ "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
+ req->state, req->data_is_ptr, req->addr,
+ req->data, req->count, req->size);
+ destroy_hvm_domain();
+ return;
}
- env->send_event = 1;
+
+ wmb(); /* Update ioreq contents /then/ update state. */
+ req->state = STATE_IORESP_READY;
+ xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
}
}
@@ -508,8 +534,6 @@ int main_loop(void)
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env);
- env->send_event = 0;
-
while (1) {
if (vm_running) {
if (shutdown_requested)
@@ -522,11 +546,6 @@ int main_loop(void)
/* Wait up to 10 msec. */
main_loop_wait(10);
-
- if (env->send_event) {
- env->send_event = 0;
- xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]);
- }
}
destroy_hvm_domain();
return 0;
diff --git a/tools/ioemu/target-i386-dm/i8259-dm.c b/tools/ioemu/target-i386-dm/i8259-dm.c
index 3243b63b5d..333db17537 100644
--- a/tools/ioemu/target-i386-dm/i8259-dm.c
+++ b/tools/ioemu/target-i386-dm/i8259-dm.c
@@ -22,58 +22,18 @@
* THE SOFTWARE.
*/
#include "vl.h"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
-
#include "xenctrl.h"
#include <xen/hvm/ioreq.h>
#include <stdio.h>
#include "cpu.h"
#include "cpu-all.h"
-extern shared_iopage_t *shared_page;
-
struct PicState2 {
};
void pic_set_irq_new(void *opaque, int irq, int level)
{
- /* PicState2 *s = opaque; */
- global_iodata_t *gio;
- int mask;
-
- gio = &shared_page->sp_global;
- mask = 1 << irq;
- if ( gio->pic_elcr & mask ) {
- /* level */
- if ( level ) {
- atomic_clear_bit(irq, &gio->pic_clear_irr);
- atomic_set_bit(irq, &gio->pic_irr);
- cpu_single_env->send_event = 1;
- }
- else {
- atomic_clear_bit(irq, &gio->pic_irr);
- atomic_set_bit(irq, &gio->pic_clear_irr);
- cpu_single_env->send_event = 1;
- }
- }
- else {
- /* edge */
- if ( level ) {
- if ( (mask & gio->pic_last_irr) == 0 ) {
- atomic_set_bit(irq, &gio->pic_irr);
- atomic_set_bit(irq, &gio->pic_last_irr);
- cpu_single_env->send_event = 1;
- }
- }
- else {
- atomic_clear_bit(irq, &gio->pic_last_irr);
- }
- }
+ xc_hvm_set_isa_irq_level(xc_handle, domid, irq, level);
}
/* obsolete function */
diff --git a/tools/ioemu/target-i386-dm/piix_pci-dm.c b/tools/ioemu/target-i386-dm/piix_pci-dm.c
new file mode 100644
index 0000000000..e5851d3f96
--- /dev/null
+++ b/tools/ioemu/target-i386-dm/piix_pci-dm.c
@@ -0,0 +1,152 @@
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 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 "vl.h"
+typedef uint32_t pci_addr_t;
+#include "hw/pci_host.h"
+
+typedef PCIHostState I440FXState;
+
+static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ I440FXState *s = opaque;
+ s->config_reg = val;
+}
+
+static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
+{
+ I440FXState *s = opaque;
+ return s->config_reg;
+}
+
+static void i440fx_set_irq(PCIDevice *pci_dev, void *pic, int intx, int level)
+{
+ xc_hvm_set_pci_intx_level(xc_handle, domid, 0, 0, pci_dev->devfn >> 3,
+ intx, level);
+}
+
+PCIBus *i440fx_init(void)
+{
+ PCIBus *b;
+ PCIDevice *d;
+ I440FXState *s;
+
+ s = qemu_mallocz(sizeof(I440FXState));
+ b = pci_register_bus(i440fx_set_irq, NULL, 0);
+ s->bus = b;
+
+ register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
+ register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
+
+ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+ d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
+ NULL, NULL);
+
+ d->config[0x00] = 0x86; // vendor_id
+ d->config[0x01] = 0x80;
+ d->config[0x02] = 0x37; // device_id
+ d->config[0x03] = 0x12;
+ d->config[0x08] = 0x02; // revision
+ d->config[0x0a] = 0x00; // class_sub = host2pci
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x00; // header_type
+ return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+
+static PCIDevice *piix3_dev;
+
+static void piix3_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ int i;
+
+ /* Scan for updates to PCI link routes (0x60-0x63). */
+ for (i = 0; i < len; i++) {
+ uint8_t v = (val >> (8*i)) & 0xff;
+ if (v & 0x80)
+ v = 0;
+ v &= 0xf;
+ if (((address+i) >= 0x60) && ((address+i) <= 0x63))
+ xc_hvm_set_pci_link_route(xc_handle, domid, address + i - 0x60, v);
+ }
+
+ /* Hand off to default logic. */
+ pci_default_write_config(d, address, val, len);
+}
+
+static void piix3_reset(PCIDevice *d)
+{
+ uint8_t *pci_conf = d->config;
+
+ pci_conf[0x04] = 0x07; // master, memory and I/O
+ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+ pci_conf[0x4c] = 0x4d;
+ pci_conf[0x4e] = 0x03;
+ pci_conf[0x60] = 0x80;
+ pci_conf[0x61] = 0x80;
+ pci_conf[0x62] = 0x80;
+ pci_conf[0x63] = 0x80;
+ pci_conf[0x69] = 0x02;
+ pci_conf[0x70] = 0x80;
+ pci_conf[0x76] = 0x0c;
+ pci_conf[0x77] = 0x0c;
+ pci_conf[0x78] = 0x02;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa8] = 0x0f;
+}
+
+int piix3_init(PCIBus *bus)
+{
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
+ d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
+ -1, NULL, piix3_write_config);
+ register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
+
+ piix3_dev = d;
+ pci_conf = d->config;
+
+ pci_conf[0x00] = 0x86; // Intel
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ pci_conf[0x03] = 0x70;
+ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+ piix3_reset(d);
+ return d->devfn;
+}
+
+void pci_bios_init(void) {}
diff --git a/tools/ioemu/target-i386-dm/qemu-dm.debug b/tools/ioemu/target-i386-dm/qemu-dm.debug
index 3bad6d900d..cea6b57c77 100644
--- a/tools/ioemu/target-i386-dm/qemu-dm.debug
+++ b/tools/ioemu/target-i386-dm/qemu-dm.debug
@@ -1,5 +1,10 @@
#!/bin/sh
+if [ "`arch`" = "x86_64" ]; then
+ LIBDIR="lib64"
+else
+ LIBDIR="lib"
+fi
echo $* > /tmp/args
echo $DISPLAY >> /tmp/args
-exec /usr/lib/xen/bin/qemu-dm $*
+exec /usr/$LIBDIR/xen/bin/qemu-dm $*
diff --git a/tools/ioemu/target-i386-dm/rtc-dm.c b/tools/ioemu/target-i386-dm/rtc-dm.c
new file mode 100644
index 0000000000..e8be999dba
--- /dev/null
+++ b/tools/ioemu/target-i386-dm/rtc-dm.c
@@ -0,0 +1,107 @@
+/*
+ * QEMU MC146818 RTC 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 "vl.h"
+
+//#define DEBUG_CMOS
+
+struct RTCState {
+ uint8_t cmos_data[128];
+ uint8_t cmos_index;
+};
+
+void rtc_set_memory(RTCState *s, int addr, int val)
+{
+ if (addr >= 0 && addr <= 127)
+ s->cmos_data[addr] = val;
+}
+
+static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ RTCState *s = opaque;
+
+ if ((addr & 1) == 0) {
+ s->cmos_index = data & 0x7f;
+ } else {
+#ifdef DEBUG_CMOS
+ printf("cmos: write index=0x%02x val=0x%02x\n",
+ s->cmos_index, data);
+#endif
+ s->cmos_data[s->cmos_index] = data;
+ }
+}
+
+static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
+{
+ RTCState *s = opaque;
+ int ret;
+ if ((addr & 1) == 0) {
+ return 0xff;
+ } else {
+ ret = s->cmos_data[s->cmos_index];
+#ifdef DEBUG_CMOS
+ printf("cmos: read index=0x%02x val=0x%02x\n",
+ s->cmos_index, ret);
+#endif
+ return ret;
+ }
+}
+
+static void rtc_save(QEMUFile *f, void *opaque)
+{
+ RTCState *s = opaque;
+
+ qemu_put_buffer(f, s->cmos_data, 128);
+ qemu_put_8s(f, &s->cmos_index);
+}
+
+static int rtc_load(QEMUFile *f, void *opaque, int version_id)
+{
+ RTCState *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_buffer(f, s->cmos_data, 128);
+ qemu_get_8s(f, &s->cmos_index);
+
+ return 0;
+}
+
+RTCState *rtc_init(int base, int irq)
+{
+ RTCState *s;
+
+ s = qemu_mallocz(sizeof(RTCState));
+ if (!s)
+ return NULL;
+
+ register_ioport_write(base, 2, 1, cmos_ioport_write, s);
+ register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+
+ register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+ return s;
+}
+
+void rtc_set_date(RTCState *s, const struct tm *tm) {}
diff --git a/tools/ioemu/usb-linux.c b/tools/ioemu/usb-linux.c
index 0a13753d48..ef60179704 100644
--- a/tools/ioemu/usb-linux.c
+++ b/tools/ioemu/usb-linux.c
@@ -26,7 +26,9 @@
#if defined(__linux__)
#include <dirent.h>
#include <sys/ioctl.h>
-#include <linux/compiler.h>
+/* Some versions of usbdevice_fs.h need __user to be defined for them. */
+/* This may (harmlessly) conflict with a definition in linux/compiler.h. */
+#define __user
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c
index dfcb3c82d1..a2700ef313 100644
--- a/tools/ioemu/vl.c
+++ b/tools/ioemu/vl.c
@@ -122,6 +122,7 @@ static DisplayState display_state;
int nographic;
int vncviewer;
int vncunused;
+struct sockaddr_in vnclisten_addr;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
char *boot_device = NULL;
@@ -170,6 +171,9 @@ time_t timeoffset = 0;
char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'};
extern int domid;
+char vncpasswd[64];
+unsigned char challenge[AUTHCHALLENGESIZE];
+
/***********************************************************/
/* x86 ISA bus support */
@@ -725,6 +729,12 @@ void qemu_del_timer(QEMUTimer *ts)
}
}
+void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time)
+{
+ if (ts->expire_time > expire_time || !qemu_timer_pending(ts))
+ qemu_mod_timer(ts, expire_time);
+}
+
/* modify the current timer so that it will be fired when current_time
>= expire_time. The corresponding callback will be called. */
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
@@ -1674,7 +1684,7 @@ static void tty_serial_init(int fd, int speed,
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
- tty.c_oflag |= OPOST;
+ tty.c_oflag &= ~OPOST; /* no output mangling of raw serial stream */
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS);
switch(data_bits) {
@@ -2520,6 +2530,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
int is_waitconnect = 1;
const char *ptr;
struct sockaddr_in saddr;
+ int opt;
if (parse_host_port(&saddr, host_str) < 0)
goto fail;
@@ -2588,6 +2599,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
}
}
s->fd = fd;
+ opt = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
if (s->connected)
tcp_chr_connect(chr);
else
@@ -2777,10 +2790,22 @@ fail:
return -1;
}
+int parse_host(struct sockaddr_in *saddr, const char *buf)
+{
+ struct hostent *he;
+
+ if ((he = gethostbyname(buf)) != NULL) {
+ saddr->sin_addr = *(struct in_addr *)he->h_addr;
+ } else {
+ if (!inet_aton(buf, &saddr->sin_addr))
+ return -1;
+ }
+ return 0;
+}
+
int parse_host_port(struct sockaddr_in *saddr, const char *str)
{
char buf[512];
- struct hostent *he;
const char *p, *r;
int port;
@@ -2791,14 +2816,8 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str)
if (buf[0] == '\0') {
saddr->sin_addr.s_addr = 0;
} else {
- if (isdigit(buf[0])) {
- if (!inet_aton(buf, &saddr->sin_addr))
- return -1;
- } else {
- if ((he = gethostbyname(buf)) == NULL)
- return - 1;
- saddr->sin_addr = *(struct in_addr *)he->h_addr;
- }
+ if (parse_host(saddr, buf) == -1)
+ return -1;
}
port = strtol(p, (char **)&r, 0);
if (r == p)
@@ -3015,7 +3034,7 @@ void net_slirp_smb(const char *exported_dir)
}
/* XXX: better tmp dir construction */
- snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid());
+ snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid());
if (mkdir(smb_dir, 0700) < 0) {
fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
exit(1);
@@ -3982,7 +4001,7 @@ static void create_pidfile(const char *filename)
perror("Opening pidfile");
exit(1);
}
- fprintf(f, "%d\n", getpid());
+ fprintf(f, "%ld\n", (long)getpid());
fclose(f);
pid_filename = qemu_strdup(filename);
if (!pid_filename) {
@@ -5346,6 +5365,7 @@ void help(void)
"-vnc display start a VNC server on display\n"
"-vncviewer start a vncviewer process for this domain\n"
"-vncunused bind the VNC server to an unused port\n"
+ "-vnclisten bind the VNC server to this address\n"
"-timeoffset time offset (in seconds) from local time\n"
"-acpi disable or enable ACPI of HVM domain \n"
"\n"
@@ -5438,6 +5458,7 @@ enum {
QEMU_OPTION_acpi,
QEMU_OPTION_vncviewer,
QEMU_OPTION_vncunused,
+ QEMU_OPTION_vnclisten,
};
typedef struct QEMUOption {
@@ -5516,6 +5537,7 @@ const QEMUOption qemu_options[] = {
{ "vnc", HAS_ARG, QEMU_OPTION_vnc },
{ "vncviewer", 0, QEMU_OPTION_vncviewer },
{ "vncunused", 0, QEMU_OPTION_vncunused },
+ { "vnclisten", HAS_ARG, QEMU_OPTION_vnclisten },
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
@@ -5765,9 +5787,6 @@ int set_mm_mapping(int xc_handle, uint32_t domid,
unsigned long nr_pages, unsigned int address_bits,
xen_pfn_t *extent_start)
{
-#if 0
- int i;
-#endif
xc_dominfo_t info;
int err = 0;
@@ -5786,19 +5805,6 @@ int set_mm_mapping(int xc_handle, uint32_t domid,
return -1;
}
- err = xc_domain_translate_gpfn_list(xc_handle, domid, nr_pages,
- extent_start, extent_start);
- if (err) {
- fprintf(stderr, "Failed to translate gpfn list\n");
- return -1;
- }
-
-#if 0 /* Generates lots of log file output - turn on for debugging */
- for (i = 0; i < nr_pages; i++)
- fprintf(stderr, "set_map result i %x result %lx\n", i,
- extent_start[i]);
-#endif
-
return 0;
}
@@ -5895,6 +5901,7 @@ int main(int argc, char **argv)
vncunused = 0;
kernel_filename = NULL;
kernel_cmdline = "";
+ *vncpasswd = '\0';
#ifndef CONFIG_DM
#ifdef TARGET_PPC
cdrom_index = 1;
@@ -5922,9 +5929,11 @@ int main(int argc, char **argv)
nb_nics = 0;
/* default mac address of the first network interface */
+
+ memset(&vnclisten_addr.sin_addr, 0, sizeof(vnclisten_addr.sin_addr));
/* init debug */
- sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%d.log", getpid());
+ sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%ld.log", (long)getpid());
cpu_set_log_filename(qemu_dm_logfilename);
cpu_set_log(0);
@@ -6304,7 +6313,10 @@ int main(int argc, char **argv)
case QEMU_OPTION_vncunused:
vncunused++;
if (vnc_display == -1)
- vnc_display = -2;
+ vnc_display = 0;
+ break;
+ case QEMU_OPTION_vnclisten:
+ parse_host(&vnclisten_addr, optarg);
break;
}
}
@@ -6365,6 +6377,11 @@ int main(int argc, char **argv)
exit(1);
}
+#if defined (__ia64__)
+ if (ram_size > MMIO_START)
+ ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */
+#endif
+
/* init the memory */
phys_ram_size = ram_size + vga_ram_size + bios_size;
@@ -6372,11 +6389,6 @@ int main(int argc, char **argv)
xc_handle = xc_interface_open();
-#if defined (__ia64__)
- if (ram_size > MMIO_START)
- ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */
-#endif
-
nr_pages = ram_size/PAGE_SIZE;
tmp_nr_pages = nr_pages;
@@ -6395,14 +6407,8 @@ int main(int argc, char **argv)
}
#if defined(__i386__) || defined(__x86_64__)
- if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) {
- fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno);
- exit(-1);
- }
-
- if (ram_size > HVM_BELOW_4G_RAM_END)
- for (i = 0; i < nr_pages - (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT); i++)
- page_array[tmp_nr_pages - 1 - i] = page_array[nr_pages - 1 - i];
+ for ( i = 0; i < tmp_nr_pages; i++)
+ page_array[i] = i;
phys_ram_base = xc_map_foreign_batch(xc_handle, domid,
PROT_READ|PROT_WRITE, page_array,
@@ -6423,7 +6429,6 @@ int main(int argc, char **argv)
fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n",
shared_page_nr, (uint64_t)(page_array[shared_page_nr]));
- /* not yet add for IA64 */
buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
PROT_READ|PROT_WRITE,
page_array[shared_page_nr - 2]);
@@ -6440,7 +6445,7 @@ int main(int argc, char **argv)
#elif defined(__ia64__)
if (xc_ia64_get_pfn_list(xc_handle, domid, page_array,
- IO_PAGE_START >> PAGE_SHIFT, 1) != 1) {
+ IO_PAGE_START >> PAGE_SHIFT, 3) != 3) {
fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno);
exit(-1);
}
@@ -6452,6 +6457,12 @@ int main(int argc, char **argv)
fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n",
IO_PAGE_START >> PAGE_SHIFT, page_array[0]);
+ buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ page_array[2]);
+ fprintf(logfile, "Buffered IO page at pfn:%lx, mfn: %016lx\n",
+ BUFFER_IO_PAGE_START >> PAGE_SHIFT, page_array[2]);
+
if (xc_ia64_get_pfn_list(xc_handle, domid,
page_array, 0, nr_pages) != nr_pages) {
fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno);
@@ -6459,9 +6470,9 @@ int main(int argc, char **argv)
}
if (ram_size > MMIO_START) {
- for (i = 0 ; i < MEM_G >> PAGE_SHIFT; i++)
- page_array[MMIO_START >> PAGE_SHIFT + i] =
- page_array[IO_PAGE_START >> PAGE_SHIFT + 1];
+ for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++)
+ page_array[(MMIO_START >> PAGE_SHIFT) + i] =
+ page_array[(IO_PAGE_START >> PAGE_SHIFT) + 1];
}
phys_ram_base = xc_map_foreign_batch(xc_handle, domid,
@@ -6471,6 +6482,7 @@ int main(int argc, char **argv)
fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno);
exit(-1);
}
+ free(page_array);
#endif
#else /* !CONFIG_DM */
@@ -6538,11 +6550,15 @@ int main(int argc, char **argv)
init_ioports();
+ /* read vncpasswd from xenstore */
+ if (0 > xenstore_read_vncpasswd(domid))
+ exit(1);
+
/* terminal init */
if (nographic) {
dumb_display_init(ds);
} else if (vnc_display != -1) {
- vnc_display = vnc_display_init(ds, vnc_display, vncunused);
+ vnc_display = vnc_display_init(ds, vnc_display, vncunused, &vnclisten_addr);
if (vncviewer)
vnc_start_viewer(vnc_display);
xenstore_write_vncport(vnc_display);
diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h
index 2f778e67d4..4ff660c217 100644
--- a/tools/ioemu/vl.h
+++ b/tools/ioemu/vl.h
@@ -37,6 +37,8 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include "xenctrl.h"
#include "xs.h"
#include <xen/hvm/e820.h>
@@ -405,6 +407,7 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque);
void qemu_free_timer(QEMUTimer *ts);
void qemu_del_timer(QEMUTimer *ts);
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
+void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time);
int qemu_timer_pending(QEMUTimer *ts);
extern int64_t ticks_per_sec;
@@ -785,7 +788,7 @@ void sdl_display_init(DisplayState *ds, int full_screen);
void cocoa_display_init(DisplayState *ds, int full_screen);
/* vnc.c */
-int vnc_display_init(DisplayState *ds, int display, int find_unused);
+int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sockaddr_in *addr);
int vnc_start_viewer(int port);
/* ide.c */
@@ -926,6 +929,10 @@ extern int acpi_enabled;
void piix4_pm_init(PCIBus *bus, int devfn);
void acpi_bios_init(void);
+/* tpm_tis.c */
+int has_tpm_device(void);
+void tpm_tis_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
+
/* piix4acpi.c */
extern void pci_piix4_acpi_init(PCIBus *bus, int devfn);
@@ -1208,6 +1215,26 @@ int xenstore_fd(void);
void xenstore_process_event(void *opaque);
void xenstore_check_new_media_present(int timeout);
void xenstore_write_vncport(int vnc_display);
+int xenstore_read_vncpasswd(int domid);
+
+int xenstore_domain_has_devtype(struct xs_handle *handle,
+ const char *devtype);
+char **xenstore_domain_get_devices(struct xs_handle *handle,
+ const char *devtype, unsigned int *num);
+char *xenstore_read_hotplug_status(struct xs_handle *handle,
+ const char *devtype, const char *inst);
+char *xenstore_backend_read_variable(struct xs_handle *,
+ const char *devtype, const char *inst,
+ const char *var);
+int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst,
+ const char *token);
+int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst,
+ const char *token);
+
/* xen_platform.c */
void pci_xen_platform_init(PCIBus *bus);
@@ -1219,4 +1246,7 @@ extern char domain_name[];
void destroy_hvm_domain(void);
+/* VNC Authentication */
+#define AUTHCHALLENGESIZE 16
+
#endif /* VL_H */
diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c
index 129492f5e5..631754ca03 100644
--- a/tools/ioemu/vnc.c
+++ b/tools/ioemu/vnc.c
@@ -26,11 +26,25 @@
#include "vl.h"
#include "qemu_socket.h"
+#include <assert.h>
-#define VNC_REFRESH_INTERVAL (1000 / 30)
+/* The refresh interval starts at BASE. If we scan the buffer and
+ find no change, we increase by INC, up to MAX. If the mouse moves
+ or we get a keypress, the interval is set back to BASE. If we find
+ an update, halve the interval.
+
+ All times in milliseconds. */
+#define VNC_REFRESH_INTERVAL_BASE 30
+#define VNC_REFRESH_INTERVAL_INC 50
+#define VNC_REFRESH_INTERVAL_MAX 2000
+
+/* Wait at most one second between updates, so that we can detect a
+ minimised vncviewer reasonably quickly. */
+#define VNC_MAX_UPDATE_INTERVAL 5000
#include "vnc_keysym.h"
#include "keymaps.c"
+#include "d3des.h"
#define XK_MISCELLANY
#define XK_LATIN1
@@ -64,10 +78,11 @@ typedef void VncSendHextileTile(VncState *vs,
struct VncState
{
QEMUTimer *timer;
+ int timer_interval;
+ int64_t last_update_time;
int lsock;
int csock;
DisplayState *ds;
- int need_update;
int width;
int height;
uint64_t *dirty_row; /* screen regions which are possibly dirty */
@@ -98,8 +113,6 @@ struct VncState
int visible_w;
int visible_h;
- int slow_client;
-
int ctl_keys; /* Ctrl+Alt starts calibration */
};
@@ -125,6 +138,9 @@ static void _vnc_update_client(void *opaque);
static void vnc_update_client(void *opaque);
static void vnc_client_read(void *opaque);
static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h);
+static int make_challenge(char *random, int size);
+static void set_seed(unsigned int *seedp);
+static void get_random(int len, unsigned char *buf);
#if 0
static inline void vnc_set_bit(uint32_t *d, int k)
@@ -187,6 +203,8 @@ static void set_bits_in_row(VncState *vs, uint64_t *row,
mask = ~(0ULL);
h += y;
+ if (h > vs->ds->height)
+ h = vs->ds->height;
for (; y < h; y++)
row[y] |= mask;
}
@@ -380,7 +398,7 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_
int y = 0;
int pitch = ds->linesize;
VncState *vs = ds->opaque;
- int updating_client = !vs->slow_client;
+ int updating_client = 1;
if (src_x < vs->visible_x || src_y < vs->visible_y ||
dst_x < vs->visible_x || dst_y < vs->visible_y ||
@@ -390,10 +408,8 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_
(dst_y + h) > (vs->visible_y + vs->visible_h))
updating_client = 0;
- if (updating_client) {
- vs->need_update = 1;
+ if (updating_client)
_vnc_update_client(vs);
- }
if (dst_y > src_y) {
y = h - 1;
@@ -445,111 +461,149 @@ static int find_update_height(VncState *vs, int y, int maxy, int last_x, int x)
static void _vnc_update_client(void *opaque)
{
VncState *vs = opaque;
- int64_t now = qemu_get_clock(rt_clock);
-
- if (vs->need_update && vs->csock != -1) {
- int y;
- char *row;
- char *old_row;
- uint64_t width_mask;
- int n_rectangles;
- int saved_offset;
- int maxx, maxy;
- int tile_bytes = vs->depth * DP2X(vs, 1);
-
- if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
- width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
- else
- width_mask = ~(0ULL);
-
- /* Walk through the dirty map and eliminate tiles that
- really aren't dirty */
- row = vs->ds->data;
- old_row = vs->old_data;
-
- for (y = 0; y < vs->ds->height; y++) {
- if (vs->dirty_row[y] & width_mask) {
- int x;
- char *ptr, *old_ptr;
-
- ptr = row;
- old_ptr = old_row;
-
- for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
- if (vs->dirty_row[y] & (1ULL << x)) {
- if (memcmp(old_ptr, ptr, tile_bytes)) {
- vs->has_update = 1;
- vs->update_row[y] |= (1ULL << x);
- memcpy(old_ptr, ptr, tile_bytes);
- }
- vs->dirty_row[y] &= ~(1ULL << x);
- }
-
- ptr += tile_bytes;
- old_ptr += tile_bytes;
- }
- }
+ int64_t now;
+ int y;
+ char *row;
+ char *old_row;
+ uint64_t width_mask;
+ int n_rectangles;
+ int saved_offset;
+ int maxx, maxy;
+ int tile_bytes = vs->depth * DP2X(vs, 1);
- row += vs->ds->linesize;
- old_row += vs->ds->linesize;
- }
+ if (vs->csock == -1)
+ return;
- if (!vs->has_update || vs->visible_y >= vs->ds->height ||
- vs->visible_x >= vs->ds->width)
- goto out;
+ now = qemu_get_clock(rt_clock);
- /* Count rectangles */
- n_rectangles = 0;
- vnc_write_u8(vs, 0); /* msg id */
- vnc_write_u8(vs, 0);
- saved_offset = vs->output.offset;
- vnc_write_u16(vs, 0);
+ if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
+ width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
+ else
+ width_mask = ~(0ULL);
- maxy = vs->visible_y + vs->visible_h;
- if (maxy > vs->ds->height)
- maxy = vs->ds->height;
- maxx = vs->visible_x + vs->visible_w;
- if (maxx > vs->ds->width)
- maxx = vs->ds->width;
+ /* Walk through the dirty map and eliminate tiles that really
+ aren't dirty */
+ row = vs->ds->data;
+ old_row = vs->old_data;
- for (y = vs->visible_y; y < maxy; y++) {
+ for (y = 0; y < vs->ds->height; y++) {
+ if (vs->dirty_row[y] & width_mask) {
int x;
- int last_x = -1;
- for (x = X2DP_DOWN(vs, vs->visible_x);
- x < X2DP_UP(vs, maxx); x++) {
- if (vs->update_row[y] & (1ULL << x)) {
- if (last_x == -1)
- last_x = x;
- vs->update_row[y] &= ~(1ULL << x);
- } else {
- if (last_x != -1) {
- int h = find_update_height(vs, y, maxy, last_x, x);
+ char *ptr, *old_ptr;
+
+ ptr = row;
+ old_ptr = old_row;
+
+ for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
+ if (vs->dirty_row[y] & (1ULL << x)) {
+ if (memcmp(old_ptr, ptr, tile_bytes)) {
+ vs->has_update = 1;
+ vs->update_row[y] |= (1ULL << x);
+ memcpy(old_ptr, ptr, tile_bytes);
+ }
+ vs->dirty_row[y] &= ~(1ULL << x);
+ }
+
+ ptr += tile_bytes;
+ old_ptr += tile_bytes;
+ }
+ }
+
+ row += vs->ds->linesize;
+ old_row += vs->ds->linesize;
+ }
+
+ if (!vs->has_update || vs->visible_y >= vs->ds->height ||
+ vs->visible_x >= vs->ds->width)
+ goto backoff;
+
+ /* Count rectangles */
+ n_rectangles = 0;
+ vnc_write_u8(vs, 0); /* msg id */
+ vnc_write_u8(vs, 0);
+ saved_offset = vs->output.offset;
+ vnc_write_u16(vs, 0);
+
+ maxy = vs->visible_y + vs->visible_h;
+ if (maxy > vs->ds->height)
+ maxy = vs->ds->height;
+ maxx = vs->visible_x + vs->visible_w;
+ if (maxx > vs->ds->width)
+ maxx = vs->ds->width;
+
+ for (y = vs->visible_y; y < maxy; y++) {
+ int x;
+ int last_x = -1;
+ for (x = X2DP_DOWN(vs, vs->visible_x);
+ x < X2DP_UP(vs, maxx); x++) {
+ if (vs->update_row[y] & (1ULL << x)) {
+ if (last_x == -1)
+ last_x = x;
+ vs->update_row[y] &= ~(1ULL << x);
+ } else {
+ if (last_x != -1) {
+ int h = find_update_height(vs, y, maxy, last_x, x);
+ if (h != 0) {
send_framebuffer_update(vs, DP2X(vs, last_x), y,
DP2X(vs, (x - last_x)), h);
n_rectangles++;
}
- last_x = -1;
}
+ last_x = -1;
}
- if (last_x != -1) {
- int h = find_update_height(vs, y, maxy, last_x, x);
+ }
+ if (last_x != -1) {
+ int h = find_update_height(vs, y, maxy, last_x, x);
+ if (h != 0) {
send_framebuffer_update(vs, DP2X(vs, last_x), y,
DP2X(vs, (x - last_x)), h);
n_rectangles++;
}
}
- vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
- vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+ }
+ vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+ vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
- vs->has_update = 0;
- vs->need_update = 0;
- vnc_flush(vs);
- vs->slow_client = 0;
- } else
- vs->slow_client = 1;
+ if (n_rectangles == 0)
+ goto backoff;
- out:
- qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
+ vs->has_update = 0;
+ vnc_flush(vs);
+ vs->last_update_time = now;
+
+ vs->timer_interval /= 2;
+ if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+
+ return;
+
+ backoff:
+ /* No update -> back off a bit */
+ vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
+ if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
+ vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
+ if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
+ /* Send a null update. If the client is no longer
+ interested (e.g. minimised) it'll ignore this, and we
+ can stop scanning the buffer until it sends another
+ update request. */
+ /* It turns out that there's a bug in realvncviewer 4.1.2
+ which means that if you send a proper null update (with
+ no update rectangles), it gets a bit out of sync and
+ never sends any further requests, regardless of whether
+ it needs one or not. Fix this by sending a single 1x1
+ update rectangle instead. */
+ vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1);
+ send_framebuffer_update(vs, 0, 0, 1, 1);
+ vnc_flush(vs);
+ vs->last_update_time = now;
+ return;
+ }
+ }
+ qemu_mod_timer(vs->timer, now + vs->timer_interval);
+ return;
}
static void vnc_update_client(void *opaque)
@@ -564,7 +618,7 @@ static void vnc_timer_init(VncState *vs)
{
if (vs->timer == NULL) {
vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
- qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
}
}
@@ -625,7 +679,6 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
vs->csock = -1;
buffer_reset(&vs->input);
buffer_reset(&vs->output);
- vs->need_update = 0;
return 0;
}
return ret;
@@ -686,8 +739,10 @@ static void vnc_client_read(void *opaque)
memmove(vs->input.buffer, vs->input.buffer + len,
vs->input.offset - len);
vs->input.offset -= len;
- } else
+ } else {
+ assert(ret > vs->read_handler_expect);
vs->read_handler_expect = ret;
+ }
}
}
@@ -895,13 +950,14 @@ static void framebuffer_update_request(VncState *vs, int incremental,
int x_position, int y_position,
int w, int h)
{
- vs->need_update = 1;
if (!incremental)
framebuffer_set_updated(vs, x_position, y_position, w, h);
vs->visible_x = x_position;
vs->visible_y = y_position;
vs->visible_w = w;
vs->visible_h = h;
+
+ qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
}
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
@@ -1016,6 +1072,7 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len)
{
int i;
uint16_t limit;
+ int64_t now;
switch (data[0]) {
case 0:
@@ -1032,8 +1089,12 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len)
if (len == 1)
return 4;
- if (len == 4)
- return 4 + (read_u16(data, 2) * 4);
+ if (len == 4) {
+ uint16_t v;
+ v = read_u16(data, 2);
+ if (v)
+ return 4 + v * 4;
+ }
limit = read_u16(data, 2);
for (i = 0; i < limit; i++) {
@@ -1055,20 +1116,30 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len)
if (len == 1)
return 8;
+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+ qemu_advance_timer(vs->timer,
+ qemu_get_clock(rt_clock) + vs->timer_interval);
key_event(vs, read_u8(data, 1), read_u32(data, 4));
break;
case 5:
if (len == 1)
return 6;
+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+ qemu_advance_timer(vs->timer,
+ qemu_get_clock(rt_clock) + vs->timer_interval);
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
break;
case 6:
if (len == 1)
return 8;
- if (len == 8)
- return 8 + read_u32(data, 4);
+ if (len == 8) {
+ uint32_t v;
+ v = read_u32(data, 4);
+ if (v)
+ return 8 + v;
+ }
client_cut_text(vs, read_u32(data, 4), data + 8);
break;
@@ -1087,6 +1158,8 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
size_t l;
char pad[3] = { 0, 0, 0 };
+ vga_hw_update();
+
vs->width = vs->ds->width;
vs->height = vs->ds->height;
vnc_write_u16(vs, vs->ds->width);
@@ -1141,23 +1214,92 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
return 0;
}
+static int protocol_response(VncState *vs, char *client_response, size_t len)
+{
+ extern char vncpasswd[64];
+ extern unsigned char challenge[AUTHCHALLENGESIZE];
+ unsigned char cryptchallenge[AUTHCHALLENGESIZE];
+ unsigned char key[8];
+ int passwdlen, i, j;
+
+ memcpy(cryptchallenge, challenge, AUTHCHALLENGESIZE);
+
+ /* Calculate the sent challenge */
+ passwdlen = strlen(vncpasswd);
+ for (i=0; i<8; i++)
+ key[i] = i<passwdlen ? vncpasswd[i] : 0;
+ deskey(key, EN0);
+ for (j = 0; j < AUTHCHALLENGESIZE; j += 8)
+ des(cryptchallenge+j, cryptchallenge+j);
+
+ /* Check the actual response */
+ if (memcmp(cryptchallenge, client_response, AUTHCHALLENGESIZE) != 0) {
+ /* password error */
+ vnc_write_u32(vs, 1);
+ vnc_write_u32(vs, 22);
+ vnc_write(vs, "Authentication failure", 22);
+ vnc_flush(vs);
+ fprintf(stderr, "VNC Password error.\n");
+ vnc_client_error(vs);
+ return 0;
+ }
+
+ vnc_write_u32(vs, 0);
+ vnc_flush(vs);
+
+ vnc_read_when(vs, protocol_client_init, 1);
+
+ return 0;
+}
+
static int protocol_version(VncState *vs, char *version, size_t len)
{
+ extern char vncpasswd[64];
+ extern unsigned char challenge[AUTHCHALLENGESIZE];
char local[13];
- int maj, min;
+ int support, maj, min;
memcpy(local, version, 12);
local[12] = 0;
+ /* protocol version check */
if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
+ fprintf(stderr, "Protocol version error.\n");
vnc_client_error(vs);
return 0;
}
- vnc_write_u32(vs, 1); /* None */
- vnc_flush(vs);
- vnc_read_when(vs, protocol_client_init, 1);
+ support = 0;
+ if (maj = 3) {
+ if (min == 3 || min ==4) {
+ support = 1;
+ }
+ }
+
+ if (! support) {
+ fprintf(stderr, "Client uses unsupported protocol version %d.%d.\n",
+ maj, min);
+ vnc_client_error(vs);
+ return 0;
+ }
+
+ if (*vncpasswd == '\0') {
+ /* AuthType is None */
+ vnc_write_u32(vs, 1);
+ vnc_flush(vs);
+ vnc_read_when(vs, protocol_client_init, 1);
+ } else {
+ /* AuthType is VncAuth */
+ vnc_write_u32(vs, 2);
+
+ /* Challenge-Responce authentication */
+ /* Send Challenge */
+ make_challenge(challenge, AUTHCHALLENGESIZE);
+ vnc_write(vs, challenge, AUTHCHALLENGESIZE);
+ vnc_flush(vs);
+ vnc_read_when(vs, protocol_response, AUTHCHALLENGESIZE);
+ }
return 0;
}
@@ -1183,9 +1325,8 @@ static void vnc_listen_read(void *opaque)
}
}
-int vnc_display_init(DisplayState *ds, int display, int find_unused)
+int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sockaddr_in *addr)
{
- struct sockaddr_in addr;
int reuse_addr, ret;
VncState *vs;
@@ -1223,11 +1364,10 @@ int vnc_display_init(DisplayState *ds, int display, int find_unused)
}
retry:
- addr.sin_family = AF_INET;
- addr.sin_port = htons(5900 + display);
- memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(5900 + display);
- if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ if (bind(vs->lsock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) {
if (find_unused && errno == EADDRINUSE) {
display++;
goto retry;
@@ -1269,7 +1409,7 @@ int vnc_start_viewer(int port)
exit(1);
case 0: /* child */
- execlp("vncviewer", "vncviewer", s, 0);
+ execlp("vncviewer", "vncviewer", s, NULL);
fprintf(stderr, "vncviewer execlp failed\n");
exit(1);
@@ -1277,3 +1417,32 @@ int vnc_start_viewer(int port)
return pid;
}
}
+
+unsigned int seed;
+
+static int make_challenge(char *random, int size)
+{
+
+ set_seed(&seed);
+ get_random(size, random);
+
+ return 0;
+}
+
+static void set_seed(unsigned int *seedp)
+{
+ *seedp += (unsigned int)(time(NULL)+getpid()+getpid()*987654+rand());
+ srand(*seedp);
+
+ return;
+}
+
+static void get_random(int len, unsigned char *buf)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ buf[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
+
+ return;
+}
diff --git a/tools/ioemu/vnc_keysym.h b/tools/ioemu/vnc_keysym.h
index a4ac6885bf..14fe47f9e1 100644
--- a/tools/ioemu/vnc_keysym.h
+++ b/tools/ioemu/vnc_keysym.h
@@ -271,5 +271,15 @@ static name2keysym_t name2keysym[]={
{"Num_Lock", 0xff7f}, /* XK_Num_Lock */
{"Pause", 0xff13}, /* XK_Pause */
{"Escape", 0xff1b}, /* XK_Escape */
+
+ /* localized keys */
+{"BackApostrophe", 0xff21},
+{"Muhenkan", 0xff22},
+{"Katakana", 0xff25},
+{"Zenkaku_Hankaku", 0xff29},
+{"Henkan_Mode_Real", 0xff23},
+{"Henkan_Mode_Ultra", 0xff3e},
+{"backslash_ja", 0xffa5},
+
{0,0},
};
diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c
index fde469305a..21a8ed08b7 100644
--- a/tools/ioemu/xenstore.c
+++ b/tools/ioemu/xenstore.c
@@ -100,7 +100,7 @@ void xenstore_parse_domain_config(int domid)
if (strncmp(dev, "hd", 2) || strlen(dev) != 3)
continue;
hd_index = dev[2] - 'a';
- if (hd_index > MAX_DISKS)
+ if (hd_index >= MAX_DISKS)
continue;
/* read the type of the device */
if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
@@ -213,3 +213,191 @@ void xenstore_write_vncport(int display)
free(portstr);
free(buf);
}
+
+int xenstore_read_vncpasswd(int domid)
+{
+ extern char vncpasswd[64];
+ char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
+ unsigned int i, len, rc = 0;
+
+ if (xsh == NULL) {
+ return -1;
+ }
+
+ path = xs_get_domain_path(xsh, domid);
+ if (path == NULL) {
+ fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
+ return -1;
+ }
+
+ pasprintf(&buf, "%s/vm", path);
+ uuid = xs_read(xsh, XBT_NULL, buf, &len);
+ if (uuid == NULL) {
+ fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
+ free(path);
+ return -1;
+ }
+
+ pasprintf(&buf, "%s/vncpasswd", uuid);
+ passwd = xs_read(xsh, XBT_NULL, buf, &len);
+ if (passwd == NULL) {
+ fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
+ free(uuid);
+ free(path);
+ return rc;
+ }
+
+ for (i=0; i<len && i<63; i++) {
+ vncpasswd[i] = passwd[i];
+ passwd[i] = '\0';
+ }
+ vncpasswd[len] = '\0';
+ pasprintf(&buf, "%s/vncpasswd", uuid);
+ if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) {
+ fprintf(logfile, "xs_write() vncpasswd failed.\n");
+ rc = -1;
+ }
+
+ free(passwd);
+ free(uuid);
+ free(path);
+
+ return rc;
+}
+
+
+/*
+ * get all device instances of a certain type
+ */
+char **xenstore_domain_get_devices(struct xs_handle *handle,
+ const char *devtype, unsigned int *num)
+{
+ char *path;
+ char *buf = NULL;
+ char **e = NULL;
+
+ path = xs_get_domain_path(handle, domid);
+ if (path == NULL)
+ goto out;
+
+ if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
+ goto out;
+
+ e = xs_directory(handle, XBT_NULL, buf, num);
+
+ out:
+ free(path);
+ free(buf);
+ return e;
+}
+
+/*
+ * Check whether a domain has devices of the given type
+ */
+int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype)
+{
+ int rc = 0;
+ unsigned int num;
+ char **e = xenstore_domain_get_devices(handle, devtype, &num);
+ if (e)
+ rc = 1;
+ free(e);
+ return rc;
+}
+
+/*
+ * Function that creates a path to a variable of an instance of a
+ * certain device
+ */
+static char *get_device_variable_path(const char *devtype, const char *inst,
+ const char *var)
+{
+ char *buf = NULL;
+ if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s",
+ devtype,
+ domid,
+ inst,
+ var) == -1) {
+ free(buf);
+ buf = NULL;
+ }
+ return buf;
+}
+
+char *xenstore_backend_read_variable(struct xs_handle *handle,
+ const char *devtype, const char *inst,
+ const char *var)
+{
+ char *value = NULL;
+ char *buf = NULL;
+ unsigned int len;
+
+ buf = get_device_variable_path(devtype, inst, var);
+ if (NULL == buf)
+ goto out;
+
+ value = xs_read(handle, XBT_NULL, buf, &len);
+
+ free(buf);
+
+out:
+ return value;
+}
+
+/*
+ Read the hotplug status variable from the backend given the type
+ of device and its instance.
+*/
+char *xenstore_read_hotplug_status(struct xs_handle *handle,
+ const char *devtype, const char *inst)
+{
+ return xenstore_backend_read_variable(handle, devtype, inst,
+ "hotplug-status");
+}
+
+/*
+ Subscribe to the hotplug status of a device given the type of device and
+ its instance.
+ In case an error occurrs, a negative number is returned.
+ */
+int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst,
+ const char *token)
+{
+ int rc = 0;
+ char *path = get_device_variable_path(devtype, inst, "hotplug-status");
+
+ if (path == NULL)
+ return -1;
+
+ if (0 == xs_watch(handle, path, token))
+ rc = -2;
+
+ free(path);
+
+ return rc;
+}
+
+/*
+ * Unsubscribe from a subscription to the status of a hotplug variable of
+ * a device.
+ */
+int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst,
+ const char *token)
+{
+ int rc = 0;
+ char *path;
+ path = get_device_variable_path(devtype, inst, "hotplug-status");
+ if (path == NULL)
+ return -1;
+
+ if (0 == xs_unwatch(handle, path, token))
+ rc = -2;
+
+ free(path);
+
+ return rc;
+}
diff --git a/tools/libfsimage/Makefile b/tools/libfsimage/Makefile
new file mode 100644
index 0000000000..394c7f4dfa
--- /dev/null
+++ b/tools/libfsimage/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SUBDIRS-y = common ufs reiserfs
+SUBDIRS-y += $(shell ./check-libext2fs)
+
+.PHONY: all
+all install clean:
+ @set -e; for subdir in $(SUBDIRS-y); do \
+ $(MAKE) -C $$subdir $@; \
+ done
+
+distclean: clean
diff --git a/tools/libfsimage/Rules.mk b/tools/libfsimage/Rules.mk
new file mode 100644
index 0000000000..9d49c6373d
--- /dev/null
+++ b/tools/libfsimage/Rules.mk
@@ -0,0 +1,32 @@
+include $(XEN_ROOT)/tools/Rules.mk
+
+DEPS = .*.d
+
+CFLAGS += -I$(XEN_ROOT)/tools/libfsimage/common/ -Werror -Wp,-MD,.$(@F).d
+LDFLAGS += -L../common/
+
+PIC_OBJS := $(patsubst %.c,%.opic,$(LIB_SRCS-y))
+
+FSDIR-$(CONFIG_Linux) = $(LIBDIR)/fs/$(FS)
+FSDIR-$(CONFIG_SunOS)-x86_64 = lib/fs/$(FS)/64
+FSDIR-$(CONFIG_SunOS)-x86_32 = lib/fs/$(FS)/
+FSDIR-$(CONFIG_SunOS) = $(FSDIR-$(CONFIG_SunOS)-$(XEN_TARGET_ARCH))
+FSDIR = $(FSDIR-y)
+
+FSLIB = fsimage.so
+
+.PHONY: fs-all
+fs-all: $(FSLIB)
+
+.PHONY: fs-install
+fs-install: fs-all
+ $(INSTALL_DIR) $(DESTDIR)/usr/$(FSDIR)
+ $(INSTALL_PROG) $(FSLIB) $(DESTDIR)/usr/$(FSDIR)
+
+$(FSLIB): $(PIC_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(SHLIB_CFLAGS) -o $@ $^ -lfsimage $(FS_LIBDEPS)
+
+clean distclean:
+ rm -f $(PIC_OBJS) $(FSLIB)
+
+-include $(DEPS)
diff --git a/tools/libfsimage/check-libext2fs b/tools/libfsimage/check-libext2fs
new file mode 100755
index 0000000000..2f654cc4af
--- /dev/null
+++ b/tools/libfsimage/check-libext2fs
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+cat >ext2-test.c <<EOF
+#include <ext2fs/ext2fs.h>
+
+int main()
+{
+ ext2fs_open2;
+}
+EOF
+
+gcc -o ext2-test ext2-test.c -lext2fs >/dev/null 2>&1
+if [ $? = 0 ]; then
+ echo ext2fs-lib
+else
+ echo ext2fs
+fi
+
+rm -f ext2-test ext2-test.c
+
+exit 0
diff --git a/tools/libfsimage/common/Makefile b/tools/libfsimage/common/Makefile
new file mode 100644
index 0000000000..6efce44f02
--- /dev/null
+++ b/tools/libfsimage/common/Makefile
@@ -0,0 +1,46 @@
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR = 1.0
+MINOR = 0
+
+CFLAGS += -Werror -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+LDFLAGS-$(CONFIG_SunOS) = -Wl,-M -Wl,mapfile-SunOS
+LDFLAGS-$(CONFIG_Linux) = -Wl,mapfile-GNU
+LDFLAGS = $(LDFLAGS-y)
+
+LIB_SRCS-y = fsimage.c fsimage_plugin.c fsimage_grub.c
+
+PIC_OBJS := $(patsubst %.c,%.opic,$(LIB_SRCS-y))
+
+LIB = libfsimage.so libfsimage.so.$(MAJOR) libfsimage.so.$(MAJOR).$(MINOR)
+
+.PHONY: all
+all: $(LIB)
+
+.PHONY: install
+install: all
+ [ -d $(DESTDIR)/usr/$(LIBDIR) ] || $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)
+ [ -d $(DESTDIR)/usr/include ] || $(INSTALL_DIR) $(DESTDIR)/usr/include
+ $(INSTALL_PROG) libfsimage.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)
+ ln -sf libfsimage.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)/libfsimage.so.$(MAJOR)
+ ln -sf libfsimage.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libfsimage.so
+ $(INSTALL_DATA) fsimage.h $(DESTDIR)/usr/include
+ $(INSTALL_DATA) fsimage_plugin.h $(DESTDIR)/usr/include
+ $(INSTALL_DATA) fsimage_grub.h $(DESTDIR)/usr/include
+
+clean distclean:
+ rm -f $(PIC_OBJS) $(LIB)
+
+libfsimage.so: libfsimage.so.$(MAJOR)
+ ln -sf $< $@
+libfsimage.so.$(MAJOR): libfsimage.so.$(MAJOR).$(MINOR)
+ ln -sf $< $@
+
+libfsimage.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libfsimage.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ -lpthread
+
+-include $(DEPS)
+
diff --git a/tools/libfsimage/common/fsimage.c b/tools/libfsimage/common/fsimage.c
new file mode 100644
index 0000000000..a326fd7644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage.c
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "fsimage_plugin.h"
+#include "fsimage_priv.h"
+
+static pthread_mutex_t fsi_lock = PTHREAD_MUTEX_INITIALIZER;
+
+fsi_t *fsi_open_fsimage(const char *path, uint64_t off)
+{
+ fsi_t *fsi = NULL;
+ int fd;
+ int err;
+
+ if ((fd = open(path, O_RDONLY)) == -1)
+ goto fail;
+
+ if ((fsi = malloc(sizeof(*fsi))) == NULL)
+ goto fail;
+
+ fsi->f_fd = fd;
+ fsi->f_off = off;
+ fsi->f_data = NULL;
+
+ pthread_mutex_lock(&fsi_lock);
+ err = find_plugin(fsi, path);
+ pthread_mutex_unlock(&fsi_lock);
+ if (err != 0)
+ goto fail;
+
+ return (fsi);
+
+fail:
+ err = errno;
+ if (fd != -1)
+ (void) close(fd);
+ free(fsi);
+ errno = err;
+ return (NULL);
+}
+
+void fsi_close_fsimage(fsi_t *fsi)
+{
+ pthread_mutex_lock(&fsi_lock);
+ fsi->f_plugin->fp_ops->fpo_umount(fsi);
+ (void) close(fsi->f_fd);
+ fsip_fs_free(fsi);
+ pthread_mutex_unlock(&fsi_lock);
+}
+
+int fsi_file_exists(fsi_t *fsi, const char *path)
+{
+ fsi_file_t *ffi;
+
+ if ((ffi = fsi_open_file(fsi, path)) == NULL)
+ return (0);
+
+ fsi_close_file(ffi);
+ return (1);
+}
+
+fsi_file_t *fsi_open_file(fsi_t *fsi, const char *path)
+{
+ fsi_plugin_ops_t *ops;
+ fsi_file_t *ffi;
+
+ pthread_mutex_lock(&fsi_lock);
+ ops = fsi->f_plugin->fp_ops;
+ ffi = ops->fpo_open(fsi, path);
+ pthread_mutex_unlock(&fsi_lock);
+
+ return (ffi);
+}
+
+int fsi_close_file(fsi_file_t *ffi)
+{
+ fsi_plugin_ops_t *ops;
+ int err;
+
+ pthread_mutex_lock(&fsi_lock);
+ ops = ffi->ff_fsi->f_plugin->fp_ops;
+ err = ops->fpo_close(ffi);
+ pthread_mutex_unlock(&fsi_lock);
+
+ return (err);
+}
+
+ssize_t fsi_read_file(fsi_file_t *ffi, void *buf, size_t nbytes)
+{
+ fsi_plugin_ops_t *ops;
+ ssize_t ret;
+
+ pthread_mutex_lock(&fsi_lock);
+ ops = ffi->ff_fsi->f_plugin->fp_ops;
+ ret = ops->fpo_read(ffi, buf, nbytes);
+ pthread_mutex_unlock(&fsi_lock);
+
+ return (ret);
+}
+
+ssize_t fsi_pread_file(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off)
+{
+ fsi_plugin_ops_t *ops;
+ ssize_t ret;
+
+ pthread_mutex_lock(&fsi_lock);
+ ops = ffi->ff_fsi->f_plugin->fp_ops;
+ ret = ops->fpo_pread(ffi, buf, nbytes, off);
+ pthread_mutex_unlock(&fsi_lock);
+
+ return (ret);
+}
diff --git a/tools/libfsimage/common/fsimage.h b/tools/libfsimage/common/fsimage.h
new file mode 100644
index 0000000000..28165ef29d
--- /dev/null
+++ b/tools/libfsimage/common/fsimage.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_H
+#define _FSIMAGE_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <unistd.h>
+
+typedef struct fsi fsi_t;
+typedef struct fsi_file fsi_file_t;
+
+fsi_t *fsi_open_fsimage(const char *, uint64_t);
+void fsi_close_fsimage(fsi_t *);
+
+int fsi_file_exists(fsi_t *, const char *);
+fsi_file_t *fsi_open_file(fsi_t *, const char *);
+int fsi_close_file(fsi_file_t *);
+
+ssize_t fsi_read_file(fsi_file_t *, void *, size_t);
+ssize_t fsi_pread_file(fsi_file_t *, void *, size_t, uint64_t);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_H */
diff --git a/tools/libfsimage/common/fsimage_grub.c b/tools/libfsimage/common/fsimage_grub.c
new file mode 100644
index 0000000000..252445f58e
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_grub.c
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef __sun__
+#define _XOPEN_SOURCE 500
+#endif
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+
+#include "fsimage_grub.h"
+#include "fsimage_priv.h"
+
+static char *disk_read_junk;
+
+typedef struct fsig_data {
+ char fd_buf[FSYS_BUFLEN];
+} fsig_data_t;
+
+typedef struct fsig_file_data {
+ char ffd_buf[FSYS_BUFLEN];
+ uint64_t ffd_curpos;
+ uint64_t ffd_filepos;
+ uint64_t ffd_filemax;
+ int ffd_int1;
+ int ffd_int2;
+ int ffd_errnum;
+} fsig_file_data_t;
+
+fsi_file_t *
+fsig_file_alloc(fsi_t *fsi)
+{
+ fsi_file_t *ffi;
+ fsig_file_data_t *data = malloc(sizeof (fsig_file_data_t));
+
+ if (data == NULL)
+ return (NULL);
+
+ bzero(data, sizeof (fsig_file_data_t));
+ bcopy(fsig_fs_buf(fsi), data->ffd_buf, FSYS_BUFLEN);
+
+ if ((ffi = fsip_file_alloc(fsi, data)) == NULL) {
+ free(data);
+ return (NULL);
+ }
+
+ return (ffi);
+}
+
+void *
+fsig_fs_buf(fsi_t *fsi)
+{
+ fsig_data_t *data = fsip_fs_data(fsi);
+ return ((void *)data->fd_buf);
+}
+
+void *
+fsig_file_buf(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return ((void *)data->ffd_buf);
+}
+
+uint64_t *
+fsig_filepos(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return (&data->ffd_filepos);
+}
+
+uint64_t *
+fsig_filemax(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return (&data->ffd_filemax);
+}
+
+int *
+fsig_int1(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return (&data->ffd_int1);
+}
+
+int *
+fsig_int2(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return (&data->ffd_int2);
+}
+
+int *
+fsig_errnum(fsi_file_t *ffi)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ return (&data->ffd_errnum);
+}
+
+char **
+fsig_disk_read_junk(void)
+{
+ return (&disk_read_junk);
+}
+
+int
+fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset,
+ unsigned int bufsize, char *buf)
+{
+ uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)sector * 512) + offset;
+ ssize_t bytes_read = 0;
+
+ while (bufsize) {
+ ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read,
+ bufsize, (off_t)off);
+ if (ret == -1)
+ return (0);
+ if (ret == 0)
+ return (0);
+
+ bytes_read += ret;
+ bufsize -= ret;
+ }
+
+ return (1);
+}
+
+int
+fsig_substring(const char *s1, const char *s2)
+{
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ return (0);
+ s1++;
+ s2++;
+ }
+
+ if (*s1 == '\0')
+ return (-1);
+
+ return (1);
+}
+
+static int
+fsig_mount(fsi_t *fsi, const char *path)
+{
+ fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
+ fsi_file_t *ffi;
+ fsi->f_data = malloc(sizeof (fsig_data_t));
+
+ if (fsi->f_data == NULL)
+ return (-1);
+
+ if ((ffi = fsig_file_alloc(fsi)) == NULL) {
+ free(fsi->f_data);
+ fsi->f_data = NULL;
+ return (-1);
+ }
+
+ bzero(fsi->f_data, sizeof (fsig_data_t));
+
+ if (!ops->fpo_mount(ffi)) {
+ fsip_file_free(ffi);
+ free(fsi->f_data);
+ fsi->f_data = NULL;
+ return (-1);
+ }
+
+ bcopy(fsig_file_buf(ffi), fsig_fs_buf(fsi), FSYS_BUFLEN);
+ fsip_file_free(ffi);
+ return (0);
+}
+
+static int
+fsig_umount(fsi_t *fsi)
+{
+ return (0);
+}
+
+static fsi_file_t *
+fsig_open(fsi_t *fsi, const char *name)
+{
+ fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
+ char *path = strdup(name);
+ fsi_file_t *ffi = NULL;
+
+ if (path == NULL || (ffi = fsig_file_alloc(fsi)) == NULL)
+ goto out;
+
+ if (ops->fpo_dir(ffi, path) == 0) {
+ fsip_file_free(ffi);
+ ffi = NULL;
+ errno = ENOENT;
+ }
+
+out:
+ free(path);
+ return (ffi);
+}
+
+static ssize_t
+fsig_pread(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off)
+{
+ fsig_plugin_ops_t *ops = ffi->ff_fsi->f_plugin->fp_data;
+ fsig_file_data_t *data = fsip_file_data(ffi);
+
+ data->ffd_filepos = off;
+
+ if (data->ffd_filepos >= data->ffd_filemax)
+ return (0);
+
+ /* FIXME: check */
+ if (data->ffd_filepos + nbytes > data->ffd_filemax)
+ nbytes = data->ffd_filemax - data->ffd_filepos;
+
+ errnum = 0;
+ return (ops->fpo_read(ffi, buf, nbytes));
+}
+
+static ssize_t
+fsig_read(fsi_file_t *ffi, void *buf, size_t nbytes)
+{
+ fsig_file_data_t *data = fsip_file_data(ffi);
+ ssize_t ret;
+
+ ret = fsig_pread(ffi, buf, nbytes, data->ffd_curpos);
+ data->ffd_curpos = data->ffd_filepos;
+ return (ret);
+}
+
+static int
+fsig_close(fsi_file_t *ffi)
+{
+ fsip_file_free(ffi);
+ return (0);
+}
+
+static fsi_plugin_ops_t fsig_grub_ops = {
+ .fpo_version = FSIMAGE_PLUGIN_VERSION,
+ .fpo_mount = fsig_mount,
+ .fpo_umount = fsig_umount,
+ .fpo_open = fsig_open,
+ .fpo_read = fsig_read,
+ .fpo_pread = fsig_pread,
+ .fpo_close = fsig_close
+};
+
+fsi_plugin_ops_t *
+fsig_init(fsi_plugin_t *plugin, fsig_plugin_ops_t *ops)
+{
+ if (ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
+ return (NULL);
+
+ plugin->fp_data = ops;
+
+ return (&fsig_grub_ops);
+}
diff --git a/tools/libfsimage/common/fsimage_grub.h b/tools/libfsimage/common/fsimage_grub.h
new file mode 100644
index 0000000000..38db2a219c
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_grub.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_GRUB_H
+#define _FSIMAGE_GRUB_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "fsimage.h"
+#include "fsimage_plugin.h"
+
+typedef struct fsig_plugin_ops {
+ int fpo_version;
+ int (*fpo_mount)(fsi_file_t *);
+ int (*fpo_dir)(fsi_file_t *, char *);
+ int (*fpo_read)(fsi_file_t *, char *, int);
+} fsig_plugin_ops_t;
+
+#define STAGE1_5
+#define FSYS_BUFLEN 0x8000
+#define SECTOR_BITS 9
+#define SECTOR_SIZE 0x200
+
+#define FSYS_BUF (fsig_file_buf(ffi))
+#define filepos (*fsig_filepos(ffi))
+#define filemax (*fsig_filemax(ffi))
+#define devread fsig_devread
+#define substring fsig_substring
+#define errnum (*fsig_errnum(ffi))
+#define disk_read_func (*fsig_disk_read_junk())
+#define disk_read_hook (*fsig_disk_read_junk())
+#define print_possibilities 0
+
+#define grub_memset memset
+#define grub_memmove memmove
+
+extern char **fsig_disk_read_junk(void);
+
+#define ERR_FSYS_CORRUPT 1
+#define ERR_SYMLINK_LOOP 1
+#define ERR_FILELENGTH 1
+#define ERR_BAD_FILETYPE 1
+#define ERR_BAD_FILETYPE 1
+#define ERR_FILE_NOT_FOUND 1
+
+fsi_plugin_ops_t *fsig_init(fsi_plugin_t *, fsig_plugin_ops_t *);
+
+int fsig_devread(fsi_file_t *, unsigned int, unsigned int, unsigned int, char *);
+int fsig_substring(const char *, const char *);
+
+void *fsig_fs_buf(fsi_t *);
+
+fsi_file_t *fsig_file_alloc(fsi_t *);
+void *fsig_file_buf(fsi_file_t *);
+uint64_t *fsig_filepos(fsi_file_t *);
+uint64_t *fsig_filemax(fsi_file_t *);
+int *fsig_int1(fsi_file_t *);
+int *fsig_int2(fsi_file_t *);
+int *fsig_errnum(fsi_file_t *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_GRUB_H */
diff --git a/tools/libfsimage/common/fsimage_plugin.c b/tools/libfsimage/common/fsimage_plugin.c
new file mode 100644
index 0000000000..71099ba2ff
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_plugin.c
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+#include "fsimage_plugin.h"
+#include "fsimage_priv.h"
+
+static fsi_plugin_t *plugins;
+
+void
+fsip_fs_set_data(fsi_t *fsi, void *data)
+{
+ fsi->f_data = data;
+}
+
+void
+fsip_fs_free(fsi_t *fsi)
+{
+ free(fsi->f_data);
+ free(fsi);
+}
+
+fsi_file_t *
+fsip_file_alloc(fsi_t *fsi, void *data)
+{
+ fsi_file_t *ffi = malloc(sizeof (fsi_file_t));
+ if (ffi == NULL)
+ return (NULL);
+
+ bzero(ffi, sizeof (fsi_file_t));
+
+ ffi->ff_fsi = fsi;
+ ffi->ff_data = data;
+ return (ffi);
+}
+
+void
+fsip_file_free(fsi_file_t *ffi)
+{
+ free(ffi->ff_data);
+ free(ffi);
+}
+
+fsi_t *
+fsip_fs(fsi_file_t *ffi)
+{
+ return (ffi->ff_fsi);
+}
+
+uint64_t
+fsip_fs_offset(fsi_t *fsi)
+{
+ return (fsi->f_off);
+}
+
+void *
+fsip_fs_data(fsi_t *fsi)
+{
+ return (fsi->f_data);
+}
+
+void *
+fsip_file_data(fsi_file_t *ffi)
+{
+ return (ffi->ff_data);
+}
+
+static int init_plugin(const char *lib)
+{
+ fsi_plugin_init_t init;
+ fsi_plugin_t *fp = malloc(sizeof (fsi_plugin_t));
+
+ if (fp == NULL)
+ return (-1);
+
+ bzero(fp, sizeof (fsi_plugin_t));
+
+ if ((fp->fp_dlh = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+ free(fp);
+ return (0);
+ }
+
+ init = dlsym(fp->fp_dlh, "fsi_init_plugin");
+
+ if (init == NULL)
+ goto fail;
+
+ fp->fp_ops = init(FSIMAGE_PLUGIN_VERSION, fp, &fp->fp_name);
+ if (fp->fp_ops == NULL ||
+ fp->fp_ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
+ goto fail;
+
+ fp->fp_next = plugins;
+ plugins = fp;
+
+ return (0);
+fail:
+ (void) dlclose(fp->fp_dlh);
+ free(fp);
+ return (-1);
+}
+
+static int load_plugins(void)
+{
+ const char *fsdir = getenv("FSIMAGE_FSDIR");
+ const char *isadir = "";
+ struct dirent *dp = NULL;
+ struct dirent *dpp;
+ DIR *dir = NULL;
+ char *tmp = NULL;
+ size_t name_max;
+ int err;
+ int ret = -1;
+
+#ifdef __sun__
+ if (fsdir == NULL)
+ fsdir = "/usr/lib/fs";
+
+ if (sizeof(void *) == 8)
+ isadir = "64/";
+#else
+ if (fsdir == NULL) {
+ if (sizeof(void *) == 8)
+ fsdir = "/usr/lib64/fs";
+ else
+ fsdir = "/usr/lib/fs";
+ }
+#endif
+
+ if ((name_max = pathconf(fsdir, _PC_NAME_MAX)) == -1)
+ goto fail;
+
+ if ((tmp = malloc(name_max + 1)) == NULL)
+ goto fail;
+
+ if ((dp = malloc(sizeof (struct dirent) + name_max + 1)) == NULL)
+ goto fail;
+
+ if ((dir = opendir(fsdir)) == NULL)
+ goto fail;
+
+ bzero(dp, sizeof (struct dirent) + name_max + 1);
+
+ while (readdir_r(dir, dp, &dpp) == 0 && dpp != NULL) {
+ if (strcmp(dpp->d_name, ".") == 0)
+ continue;
+ if (strcmp(dpp->d_name, "..") == 0)
+ continue;
+
+ (void) snprintf(tmp, name_max, "%s/%s/%sfsimage.so", fsdir,
+ dpp->d_name, isadir);
+
+ if (init_plugin(tmp) != 0)
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ err = errno;
+ if (dir != NULL)
+ (void) closedir(dir);
+ free(tmp);
+ free(dp);
+ errno = err;
+ return (ret);
+}
+
+int find_plugin(fsi_t *fsi, const char *path)
+{
+ fsi_plugin_t *fp;
+ int ret = 0;
+
+ if (plugins == NULL && (ret = load_plugins()) != 0)
+ goto out;
+
+ for (fp = plugins; fp != NULL; fp = fp->fp_next) {
+ fsi->f_plugin = fp;
+ if (fp->fp_ops->fpo_mount(fsi, path) == 0)
+ goto out;
+ }
+
+ ret = -1;
+ errno = ENOTSUP;
+out:
+ return (ret);
+}
diff --git a/tools/libfsimage/common/fsimage_plugin.h b/tools/libfsimage/common/fsimage_plugin.h
new file mode 100644
index 0000000000..4592e08be7
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_plugin.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_PLUGIN_H
+#define _FSIMAGE_PLUGIN_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+
+#include "fsimage.h"
+
+#define FSIMAGE_PLUGIN_VERSION 1
+
+typedef struct fsi_plugin fsi_plugin_t;
+
+typedef struct fsi_plugin_ops {
+ int fpo_version;
+ int (*fpo_mount)(fsi_t *, const char *);
+ int (*fpo_umount)(fsi_t *);
+ fsi_file_t *(*fpo_open)(fsi_t *, const char *);
+ ssize_t (*fpo_read)(fsi_file_t *, void *, size_t);
+ ssize_t (*fpo_pread)(fsi_file_t *, void *, size_t, uint64_t);
+ int (*fpo_close)(fsi_file_t *);
+} fsi_plugin_ops_t;
+
+typedef fsi_plugin_ops_t *
+ (*fsi_plugin_init_t)(int, fsi_plugin_t *, const char **);
+
+void fsip_fs_set_data(fsi_t *, void *);
+void fsip_fs_free(fsi_t *);
+fsi_file_t *fsip_file_alloc(fsi_t *, void *);
+void fsip_file_free(fsi_file_t *);
+fsi_t * fsip_fs(fsi_file_t *ffi);
+uint64_t fsip_fs_offset(fsi_t *fsi);
+void *fsip_fs_data(fsi_t *);
+void *fsip_file_data(fsi_file_t *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_PLUGIN_H */
diff --git a/tools/libfsimage/common/fsimage_priv.h b/tools/libfsimage/common/fsimage_priv.h
new file mode 100644
index 0000000000..cf0dfe6612
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_priv.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_PRIV_H
+#define _FSIMAGE_PRIV_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+
+#include "fsimage.h"
+#include "fsimage_plugin.h"
+
+struct fsi_plugin {
+ const char *fp_name;
+ void *fp_dlh;
+ fsi_plugin_ops_t *fp_ops;
+ struct fsi_plugin *fp_next;
+ void *fp_data;
+};
+
+struct fsi {
+ int f_fd;
+ uint64_t f_off;
+ void *f_data;
+ fsi_plugin_t *f_plugin;
+};
+
+struct fsi_file {
+ fsi_t *ff_fsi;
+ void *ff_data;
+};
+
+int find_plugin(fsi_t *, const char *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_PRIV_H */
diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU
new file mode 100644
index 0000000000..f15060cba4
--- /dev/null
+++ b/tools/libfsimage/common/mapfile-GNU
@@ -0,0 +1,37 @@
+VERSION {
+ libfsimage.so.1.1 {
+ global:
+ fsi_open_fsimage;
+ fsi_close_fsimage;
+ fsi_file_exists;
+ fsi_open_file;
+ fsi_close_file;
+ fsi_read_file;
+ fsi_pread_file;
+
+ fsip_fs_set_data;
+ fsip_fs_free;
+ fsip_file_alloc;
+ fsip_file_free;
+ fsip_fs;
+ fsip_fs_offset;
+ fsip_fs_data;
+ fsip_file_data;
+
+ fsig_init;
+ fsig_devread;
+ fsig_substring;
+ fsig_fs_buf;
+ fsig_file_alloc;
+ fsig_file_buf;
+ fsig_filepos;
+ fsig_filemax;
+ fsig_int1;
+ fsig_int2;
+ fsig_errnum;
+ fsig_disk_read_junk;
+
+ local:
+ *;
+ };
+}
diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS
new file mode 100644
index 0000000000..1ea38bed04
--- /dev/null
+++ b/tools/libfsimage/common/mapfile-SunOS
@@ -0,0 +1,35 @@
+libfsimage.so.1.1 {
+ global:
+ fsi_open_fsimage;
+ fsi_close_fsimage;
+ fsi_file_exists;
+ fsi_open_file;
+ fsi_close_file;
+ fsi_read_file;
+ fsi_pread_file;
+
+ fsip_fs_set_data;
+ fsip_fs_free;
+ fsip_file_alloc;
+ fsip_file_free;
+ fsip_fs;
+ fsip_fs_data;
+ fsip_fs_offset;
+ fsip_file_data;
+
+ fsig_init;
+ fsig_devread;
+ fsig_substring;
+ fsig_fs_buf;
+ fsig_file_alloc;
+ fsig_file_buf;
+ fsig_filepos;
+ fsig_filemax;
+ fsig_int1;
+ fsig_int2;
+ fsig_errnum;
+ fsig_disk_read_junk;
+
+ local:
+ *;
+};
diff --git a/tools/libfsimage/ext2fs-lib/Makefile b/tools/libfsimage/ext2fs-lib/Makefile
new file mode 100644
index 0000000000..a60b3a58a5
--- /dev/null
+++ b/tools/libfsimage/ext2fs-lib/Makefile
@@ -0,0 +1,15 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = ext2fs-lib.c
+
+FS = ext2fs-lib
+
+FS_LIBDEPS = -lext2fs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ext2fs-lib/ext2fs-lib.c b/tools/libfsimage/ext2fs-lib/ext2fs-lib.c
new file mode 100644
index 0000000000..b6f60ce65f
--- /dev/null
+++ b/tools/libfsimage/ext2fs-lib/ext2fs-lib.c
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <fsimage_plugin.h>
+#include <ext2fs/ext2fs.h>
+#include <errno.h>
+#include <inttypes.h>
+
+static int
+ext2lib_mount(fsi_t *fsi, const char *name)
+{
+ int err;
+ char opts[30] = "";
+ ext2_filsys *fs;
+ uint64_t offset = fsip_fs_offset(fsi);
+
+ if (offset)
+ snprintf(opts, 29, "offset=%" PRId64, offset);
+
+ fs = malloc(sizeof (*fs));
+ if (fs == NULL)
+ return (-1);
+
+ err = ext2fs_open2(name, opts, 0, 0, 0, unix_io_manager, fs);
+
+ if (err != 0) {
+ free(fs);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ fsip_fs_set_data(fsi, fs);
+ return (0);
+}
+
+static int
+ext2lib_umount(fsi_t *fsi)
+{
+ ext2_filsys *fs = fsip_fs_data(fsi);
+ if (ext2fs_close(*fs) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ return (0);
+}
+
+fsi_file_t *
+ext2lib_open(fsi_t *fsi, const char *path)
+{
+ ext2_ino_t ino;
+ ext2_filsys *fs = fsip_fs_data(fsi);
+ ext2_file_t *f;
+ fsi_file_t *file;
+ int err;
+
+ err = ext2fs_namei_follow(*fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+ path, &ino);
+
+ if (err != 0) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ f = malloc(sizeof (*f));
+ if (f == NULL)
+ return (NULL);
+
+ err = ext2fs_file_open(*fs, ino, 0, f);
+
+ if (err != 0) {
+ free(f);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ file = fsip_file_alloc(fsi, f);
+ if (file == NULL)
+ free(f);
+ return (file);
+}
+
+ssize_t
+ext2lib_read(fsi_file_t *file, void *buf, size_t nbytes)
+{
+ ext2_file_t *f = fsip_file_data(file);
+ unsigned int n;
+ int err;
+
+ err = ext2fs_file_read(*f, buf, nbytes, &n);
+ if (err != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (n);
+}
+
+ssize_t
+ext2lib_pread(fsi_file_t *file, void *buf, size_t nbytes, uint64_t off)
+{
+ ext2_file_t *f = fsip_file_data(file);
+ __u64 tmpoff;
+ unsigned int n;
+ int err;
+
+ if ((err = ext2fs_file_llseek(*f, 0, EXT2_SEEK_CUR, &tmpoff)) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((err = ext2fs_file_llseek(*f, off, EXT2_SEEK_SET, NULL)) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ err = ext2fs_file_read(*f, buf, nbytes, &n);
+
+ ext2fs_file_llseek(*f, tmpoff, EXT2_SEEK_SET, NULL);
+
+ if (err != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (n);
+}
+
+int
+ext2lib_close(fsi_file_t *file)
+{
+ ext2_file_t *f = fsip_file_data(file);
+ ext2fs_file_close(*f);
+ free(f);
+ return (0);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+ static fsi_plugin_ops_t ops = {
+ FSIMAGE_PLUGIN_VERSION,
+ .fpo_mount = ext2lib_mount,
+ .fpo_umount = ext2lib_umount,
+ .fpo_open = ext2lib_open,
+ .fpo_read = ext2lib_read,
+ .fpo_pread = ext2lib_pread,
+ .fpo_close = ext2lib_close
+ };
+
+ *name = "ext2fs-lib";
+ return (&ops);
+}
diff --git a/tools/libfsimage/ext2fs/Makefile b/tools/libfsimage/ext2fs/Makefile
new file mode 100644
index 0000000000..43a4501f5d
--- /dev/null
+++ b/tools/libfsimage/ext2fs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_ext2fs.c
+
+FS = ext2fs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ext2fs/fsys_ext2fs.c b/tools/libfsimage/ext2fs/fsys_ext2fs.c
new file mode 100644
index 0000000000..c3749df222
--- /dev/null
+++ b/tools/libfsimage/ext2fs/fsys_ext2fs.c
@@ -0,0 +1,872 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fsimage_grub.h>
+
+#define mapblock1 (*fsig_int1(ffi))
+#define mapblock2 (*fsig_int2(ffi))
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE 1024 /* initial block size for superblock read */
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/*
+ * Constants relative to the data blocks, from ext2_fs.h
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/* include/linux/ext2_fs.h */
+struct ext2_super_block
+ {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_pad;
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ __u32 s_reserved[235]; /* Padding to the end of the block */
+ };
+
+struct ext2_group_desc
+ {
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+ };
+
+struct ext2_inode
+ {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Owner Uid */
+ __u32 i_size; /* 4: Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* 12: Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* 20: Deletion Time */
+ __u16 i_gid; /* Group Id */
+ __u16 i_links_count; /* 24: Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* 32: File flags */
+ union
+ {
+ struct
+ {
+ __u32 l_i_reserved1;
+ }
+ linux1;
+ struct
+ {
+ __u32 h_i_translator;
+ }
+ hurd1;
+ struct
+ {
+ __u32 m_i_reserved1;
+ }
+ masix1;
+ }
+ osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ __u32 i_version; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union
+ {
+ struct
+ {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u32 l_i_reserved2[2];
+ }
+ linux2;
+ struct
+ {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ }
+ hurd2;
+ struct
+ {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ }
+ masix2;
+ }
+ osd2; /* OS dependent 2 */
+ };
+
+/* linux/limits.h */
+#define NAME_MAX 255 /* # chars in a file name */
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/ext2fs.h */
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry
+ {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+ };
+
+/* linux/ext2fs.h */
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+
+/* ext2/super.c */
+#define log2(n) ffz(~(n))
+
+#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */
+#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */
+#define PATH_MAX 1024 /* include/linux/limits.h */
+#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+ ((struct ext2_super_block *)(FSYS_BUF))
+#define GROUP_DESC \
+ ((struct ext2_group_desc *) \
+ ((char *)SUPERBLOCK + sizeof(struct ext2_super_block)))
+#define INODE \
+ ((struct ext2_inode *)((caddr_t)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+#define DATABLOCK1 \
+ ((char *)((caddr_t)INODE + sizeof(struct ext2_inode)))
+#define DATABLOCK2 \
+ ((char *)((caddr_t)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+
+/* linux/ext2_fs.h */
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
+
+/* linux/ext2_fs.h */
+#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+/* kind of from ext2/super.c */
+#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s))
+/* linux/ext2fs.h */
+#define EXT2_DESC_PER_BLOCK(s) \
+ (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+/* linux/stat.h */
+#define S_IFMT 00170000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFDIR 0040000
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+
+#if defined(__i386__) || defined(__x86_64__)
+/* include/asm-i386/bitops.h */
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+#ifdef __amd64
+#define BSF "bsfq"
+#else
+#define BSF "bsfl"
+#endif
+static __inline__ unsigned long
+ffz (unsigned long word)
+{
+ __asm__ (BSF " %1,%0"
+: "=r" (word)
+: "r" (~word));
+ return word;
+}
+
+#elif defined(__ia64__)
+
+typedef unsigned long __u64;
+
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define ia64_popcnt(x) __builtin_popcountl(x)
+#else
+# define ia64_popcnt(x) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \
+ ia64_intri_res; \
+ })
+#endif
+
+static __inline__ unsigned long
+ffz (unsigned long word)
+{
+ unsigned long result;
+
+ result = ia64_popcnt(word & (~word - 1));
+ return result;
+}
+
+#elif defined(__powerpc__)
+
+#ifdef __powerpc64__
+#define PPC_CNTLZL "cntlzd"
+#else
+#define PPC_CNTLZL "cntlzw"
+#endif
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+static __inline__ int
+__ilog2(unsigned long x)
+{
+ int lz;
+
+ asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (x));
+ return BITS_PER_LONG - 1 - lz;
+}
+
+static __inline__ unsigned long
+ffz (unsigned long word)
+{
+ if ((word = ~word) == 0)
+ return BITS_PER_LONG;
+ return __ilog2(word & -word);
+}
+
+#else /* Unoptimized */
+
+static __inline__ unsigned long
+ffz (unsigned long word)
+{
+ unsigned long result;
+
+ result = 0;
+ while(word & 1)
+ {
+ result++;
+ word >>= 1;
+ }
+ return result;
+}
+#endif
+
+/* check filesystem types and read superblock into memory buffer */
+int
+ext2fs_mount (fsi_file_t *ffi)
+{
+ int retval = 1;
+
+ if (/*(((current_drive & 0x80) || (current_slice != 0))
+ && (current_slice != PC_SLICE_TYPE_EXT2FS)
+ && (current_slice != PC_SLICE_TYPE_LINUX_RAID)
+ && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
+ && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
+ || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE))
+ || */ !devread (ffi, SBLOCK, 0, sizeof (struct ext2_super_block),
+ (char *) SUPERBLOCK)
+ || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
+ retval = 0;
+
+ return retval;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+ext2_rdfsb (fsi_file_t *ffi, int fsblock, char *buffer)
+{
+#ifdef E2DEBUG
+ printf ("fsblock %d buffer %d\n", fsblock, buffer);
+#endif /* E2DEBUG */
+ return devread (ffi, fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
+ EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
+}
+
+/* from
+ ext2/inode.c:ext2_bmap()
+*/
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+ a physical block (the location in the file system) via an inode. */
+static int
+ext2fs_block_map (fsi_file_t *ffi, int logical_block)
+{
+
+#ifdef E2DEBUG
+ unsigned char *i;
+ for (i = (unsigned char *) INODE;
+ i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
+ i++)
+ {
+ printf ("%c", "0123456789abcdef"[*i >> 4]);
+ printf ("%c", "0123456789abcdef"[*i % 16]);
+ if (!((i + 1 - (unsigned char *) INODE) % 16))
+ {
+ printf ("\n");
+ }
+ else
+ {
+ printf (" ");
+ }
+ }
+ printf ("logical block %d\n", logical_block);
+#endif /* E2DEBUG */
+
+ /* if it is directly pointed to by the inode, return that physical addr */
+ if (logical_block < EXT2_NDIR_BLOCKS)
+ {
+#ifdef E2DEBUG
+ printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
+ printf ("returning %d\n", INODE->i_block[logical_block]);
+#endif /* E2DEBUG */
+ return INODE->i_block[logical_block];
+ }
+ /* else */
+ logical_block -= EXT2_NDIR_BLOCKS;
+ /* try the indirect block */
+ if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+ {
+ if (mapblock1 != 1
+ && !ext2_rdfsb (ffi, INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 1;
+ return ((__u32 *) DATABLOCK1)[logical_block];
+ }
+ /* else */
+ logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
+ /* now try the double indirect block */
+ if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
+ {
+ int bnum;
+ if (mapblock1 != 2
+ && !ext2_rdfsb (ffi, INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 2;
+ if ((bnum = (((__u32 *) DATABLOCK1)
+ [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
+ != mapblock2
+ && !ext2_rdfsb (ffi, bnum, DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock2 = bnum;
+ return ((__u32 *) DATABLOCK2)
+ [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+ }
+ /* else */
+ mapblock2 = -1;
+ logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
+ if (mapblock1 != 3
+ && !ext2_rdfsb (ffi, INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ mapblock1 = 3;
+ if (!ext2_rdfsb (ffi, ((__u32 *) DATABLOCK1)
+ [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
+ * 2)],
+ DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ if (!ext2_rdfsb (ffi, ((__u32 *) DATABLOCK2)
+ [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
+ & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
+ DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+ return ((__u32 *) DATABLOCK2)
+ [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+}
+
+/* preconditions: all preconds of ext2fs_block_map */
+int
+ext2fs_read (fsi_file_t *ffi, char *buf, int len)
+{
+ int logical_block;
+ int offset;
+ int map;
+ int ret = 0;
+ int size = 0;
+
+#ifdef E2DEBUG
+ static char hexdigit[] = "0123456789abcdef";
+ unsigned char *i;
+ for (i = (unsigned char *) INODE;
+ i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
+ i++)
+ {
+ printf ("%c", hexdigit[*i >> 4]);
+ printf ("%c", hexdigit[*i % 16]);
+ if (!((i + 1 - (unsigned char *) INODE) % 16))
+ {
+ printf ("\n");
+ }
+ else
+ {
+ printf (" ");
+ }
+ }
+#endif /* E2DEBUG */
+ while (len > 0)
+ {
+ /* find the (logical) block component of our location */
+ logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+ offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+ map = ext2fs_block_map (ffi, logical_block);
+#ifdef E2DEBUG
+ printf ("map=%d\n", map);
+#endif /* E2DEBUG */
+ if (map < 0)
+ break;
+
+ size = EXT2_BLOCK_SIZE (SUPERBLOCK);
+ size -= offset;
+ if (size > len)
+ size = len;
+
+ if (map == 0) {
+ memset ((char *) buf, 0, size);
+ } else {
+ disk_read_func = disk_read_hook;
+
+ devread (ffi, map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
+ offset, size, buf);
+
+ disk_read_func = NULL;
+ }
+
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+
+/* Based on:
+ def_blk_fops points to
+ blkdev_open, which calls (I think):
+ sys_open()
+ do_open()
+ open_namei()
+ dir_namei() which accesses current->fs->root
+ fs->root was set during original mount:
+ (something)... which calls (I think):
+ ext2_read_super()
+ iget()
+ __iget()
+ read_inode()
+ ext2_read_inode()
+ uses desc_per_block_bits, which is set in ext2_read_super()
+ also uses group descriptors loaded during ext2_read_super()
+ lookup()
+ ext2_lookup()
+ ext2_find_entry()
+ ext2_getblk()
+
+*/
+
+static inline
+int ext2_is_fast_symlink (fsi_file_t *ffi)
+{
+ int ea_blocks;
+ ea_blocks = INODE->i_file_acl ? EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE : 0;
+ return INODE->i_blocks == ea_blocks;
+}
+
+/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
+ * known as SUPERBLOCK
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, buffer known as INODE contains the
+ * inode of the file we were trying to look up
+ * side effects: messes up GROUP_DESC buffer area
+ */
+int
+ext2fs_dir (fsi_file_t *ffi, char *dirname)
+{
+ int current_ino = EXT2_ROOT_INO; /* start at the root */
+ int updir_ino = current_ino; /* the parent of the current directory */
+ int group_id; /* which group the inode is in */
+ int group_desc; /* fs pointer to that group */
+ int desc; /* index within that group */
+ int ino_blk; /* fs pointer of the inode's information */
+ int str_chk = 0; /* used to hold the results of a string compare */
+ struct ext2_group_desc *gdp;
+ struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */
+
+ char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
+ int link_count = 0;
+
+ char *rest;
+ char ch; /* temp char holder */
+
+ int off; /* offset within block of directory entry (off mod blocksize) */
+ int loc; /* location within a directory */
+ int blk; /* which data blk within dir entry (off div blocksize) */
+ long map; /* fs pointer of a particular block from dir entry */
+ struct ext2_dir_entry *dp; /* pointer to directory entry */
+#ifdef E2DEBUG
+ unsigned char *i;
+#endif /* E2DEBUG */
+
+ /* loop invariants:
+ current_ino = inode to lookup
+ dirname = pointer to filename component we are cur looking up within
+ the directory known pointed to by current_ino (if any)
+ */
+
+ while (1)
+ {
+#ifdef E2DEBUG
+ printf ("inode %d\n", current_ino);
+ printf ("dirname=%s\n", dirname);
+#endif /* E2DEBUG */
+
+ /* look up an inode */
+ group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
+ group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+ desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
+#ifdef E2DEBUG
+ printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
+ EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+ printf ("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
+#endif /* E2DEBUG */
+ if (!ext2_rdfsb (ffi,
+ (WHICH_SUPER + group_desc + SUPERBLOCK->s_first_data_block),
+ (char *)GROUP_DESC))
+ {
+ return 0;
+ }
+ gdp = GROUP_DESC;
+ ino_blk = gdp[desc].bg_inode_table +
+ (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
+ >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+#ifdef E2DEBUG
+ printf ("inode table fsblock=%d\n", ino_blk);
+#endif /* E2DEBUG */
+ if (!ext2_rdfsb (ffi, ino_blk, (char *)INODE))
+ {
+ return 0;
+ }
+
+ /* reset indirect blocks! */
+ mapblock2 = mapblock1 = -1;
+
+ raw_inode = INODE +
+ ((current_ino - 1)
+ & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
+#ifdef E2DEBUG
+ printf ("ipb=%d, sizeof(inode)=%d\n",
+ (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
+ sizeof (struct ext2_inode));
+ printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
+ printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
+ for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
+ i++)
+ {
+ printf ("%c", "0123456789abcdef"[*i >> 4]);
+ printf ("%c", "0123456789abcdef"[*i % 16]);
+ if (!((i + 1 - (unsigned char *) INODE) % 16))
+ {
+ printf ("\n");
+ }
+ else
+ {
+ printf (" ");
+ }
+ }
+ printf ("first word=%x\n", *((int *) raw_inode));
+#endif /* E2DEBUG */
+
+ /* copy inode to fixed location */
+ memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
+
+#ifdef E2DEBUG
+ printf ("first word=%x\n", *((int *) INODE));
+#endif /* E2DEBUG */
+
+ /* If we've got a symbolic link, then chase it. */
+ if (S_ISLNK (INODE->i_mode))
+ {
+ int len;
+ if (++link_count > MAX_LINK_COUNT)
+ {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+
+ /* Find out how long our remaining name is. */
+ len = 0;
+ while (dirname[len] && !isspace (dirname[len]))
+ len++;
+
+ /* Get the symlink size. */
+ filemax = (INODE->i_size);
+ if (filemax + len > sizeof (linkbuf) - 2)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ if (len)
+ {
+ /* Copy the remaining name to the end of the symlink data.
+ Note that DIRNAME and LINKBUF may overlap! */
+ memmove (linkbuf + filemax, dirname, len);
+ }
+ linkbuf[filemax + len] = '\0';
+
+ /* Read the symlink data. */
+ if (! ext2_is_fast_symlink (ffi))
+ {
+ /* Read the necessary blocks, and reset the file pointer. */
+ len = ext2fs_read (ffi, linkbuf, filemax);
+ filepos = 0;
+ if (!len)
+ return 0;
+ }
+ else
+ {
+ /* Copy the data directly from the inode. */
+ len = filemax;
+ memmove (linkbuf, (char *) INODE->i_block, len);
+ }
+
+#ifdef E2DEBUG
+ printf ("symlink=%s\n", linkbuf);
+#endif
+
+ dirname = linkbuf;
+ if (*dirname == '/')
+ {
+ /* It's an absolute link, so look it up in root. */
+ current_ino = EXT2_ROOT_INO;
+ updir_ino = current_ino;
+ }
+ else
+ {
+ /* Relative, so look it up in our parent directory. */
+ current_ino = updir_ino;
+ }
+
+ /* Try again using the new name. */
+ continue;
+ }
+
+ /* if end of filename, INODE points to the file's inode */
+ if (!*dirname || isspace (*dirname))
+ {
+ if (!S_ISREG (INODE->i_mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filemax = (INODE->i_size);
+ return 1;
+ }
+
+ /* else we have to traverse a directory */
+ updir_ino = current_ino;
+
+ /* skip over slashes */
+ while (*dirname == '/')
+ dirname++;
+
+ /* if this isn't a directory of sufficient size to hold our file, abort */
+ if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ /* skip to next slash or end of filename (space) */
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+ rest++);
+
+ /* look through this directory and find the next filename component */
+ /* invariant: rest points to slash after the next filename component */
+ *rest = 0;
+ loc = 0;
+
+ do
+ {
+
+#ifdef E2DEBUG
+ printf ("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
+#endif /* E2DEBUG */
+
+ /* if our location/byte offset into the directory exceeds the size,
+ give up */
+ if (loc >= INODE->i_size)
+ {
+ if (print_possibilities < 0)
+ {
+# if 0
+ putchar ('\n');
+# endif
+ }
+ else
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ }
+ return (print_possibilities < 0);
+ }
+
+ /* else, find the (logical) block component of our location */
+ blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+
+ /* we know which logical block of the directory entry we are looking
+ for, now we have to translate that to the physical (fs) block on
+ the disk */
+ map = ext2fs_block_map (ffi, blk);
+#ifdef E2DEBUG
+ printf ("fs block=%d\n", map);
+#endif /* E2DEBUG */
+ mapblock2 = -1;
+ if ((map < 0) || !ext2_rdfsb (ffi, map, DATABLOCK2))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ *rest = ch;
+ return 0;
+ }
+ off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+ dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
+ /* advance loc prematurely to next on-disk directory entry */
+ loc += dp->rec_len;
+
+ /* NOTE: ext2fs filenames are NOT null-terminated */
+
+#ifdef E2DEBUG
+ printf ("directory entry ino=%d\n", dp->inode);
+ if (dp->inode)
+ printf ("entry=%s\n", dp->name);
+#endif /* E2DEBUG */
+
+ if (dp->inode)
+ {
+ int saved_c = dp->name[dp->name_len];
+
+ dp->name[dp->name_len] = 0;
+ str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/'
+ && (!*dirname || str_chk <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ print_a_completion (dp->name);
+ }
+# endif
+
+ dp->name[dp->name_len] = saved_c;
+ }
+
+ }
+ while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
+
+ current_ino = dp->inode;
+ *(dirname = rest) = ch;
+ }
+ /* never get here */
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+ static fsig_plugin_ops_t ops = {
+ FSIMAGE_PLUGIN_VERSION,
+ .fpo_mount = ext2fs_mount,
+ .fpo_dir = ext2fs_dir,
+ .fpo_read = ext2fs_read
+ };
+
+ *name = "ext2fs";
+ return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/reiserfs/Makefile b/tools/libfsimage/reiserfs/Makefile
new file mode 100644
index 0000000000..c71fff8843
--- /dev/null
+++ b/tools/libfsimage/reiserfs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_reiserfs.c
+
+FS = reiserfs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/reiserfs/fsys_reiserfs.c b/tools/libfsimage/reiserfs/fsys_reiserfs.c
new file mode 100644
index 0000000000..4b99149735
--- /dev/null
+++ b/tools/libfsimage/reiserfs/fsys_reiserfs.c
@@ -0,0 +1,1318 @@
+/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fsimage_grub.h>
+
+#undef REISERDEBUG
+
+/* Some parts of this code (mainly the structures and defines) are
+ * from the original reiser fs code, as found in the linux kernel.
+ */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef unsigned long long __u64;
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/little_endian.h */
+#define __cpu_to_le64(x) ((__u64) (x))
+#define __le64_to_cpu(x) ((__u64) (x))
+#define __cpu_to_le32(x) ((__u32) (x))
+#define __le32_to_cpu(x) ((__u32) (x))
+#define __cpu_to_le16(x) ((__u16) (x))
+#define __le16_to_cpu(x) ((__u16) (x))
+
+/* include/linux/reiser_fs.h */
+/* This is the new super block of a journaling reiserfs system */
+struct reiserfs_super_block
+{
+ __u32 s_block_count; /* blocks count */
+ __u32 s_free_blocks; /* free blocks count */
+ __u32 s_root_block; /* root block number */
+ __u32 s_journal_block; /* journal block number */
+ __u32 s_journal_dev; /* journal device number */
+ __u32 s_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */
+ __u32 s_journal_trans_max; /* max number of blocks in a transaction. */
+ __u32 s_journal_magic; /* random value made on fs creation */
+ __u32 s_journal_max_batch; /* max number of blocks to batch into a trans */
+ __u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */
+ __u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */
+ __u16 s_blocksize; /* block size */
+ __u16 s_oid_maxsize; /* max size of object id array */
+ __u16 s_oid_cursize; /* current size of object id array */
+ __u16 s_state; /* valid or error */
+ char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */
+ __u16 s_tree_height; /* height of disk tree */
+ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */
+ __u16 s_version;
+ char s_unused[128]; /* zero filled by mkreiserfs */
+};
+
+#define REISERFS_MAX_SUPPORTED_VERSION 2
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+#define MAX_HEIGHT 7
+
+/* must be correct to keep the desc and commit structs at 4k */
+#define JOURNAL_TRANS_HALF 1018
+
+/* first block written in a commit. */
+struct reiserfs_journal_desc {
+ __u32 j_trans_id; /* id of commit */
+ __u32 j_len; /* length of commit. len +1 is the commit block */
+ __u32 j_mount_id; /* mount id of this trans*/
+ __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */
+ char j_magic[12];
+};
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+ __u32 j_trans_id; /* must match j_trans_id from the desc block */
+ __u32 j_len; /* ditto */
+ __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */
+ char j_digest[16]; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
+};
+
+/* this header block gets written whenever a transaction is considered
+ fully flushed, and is more recent than the last fully flushed
+ transaction.
+ fully flushed means all the log blocks and all the real blocks are
+ on disk, and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+ /* id of last fully flushed transaction */
+ __u32 j_last_flush_trans_id;
+ /* offset in the log of where to start replay after a crash */
+ __u32 j_first_unflushed_offset;
+ /* mount id to detect very old transactions */
+ __u32 j_mount_id;
+};
+
+/* magic string to find desc blocks in the journal */
+#define JOURNAL_DESC_MAGIC "ReIsErLB"
+
+
+/*
+ * directories use this key as well as old files
+ */
+struct offset_v1
+{
+ /*
+ * for regular files this is the offset to the first byte of the
+ * body, contained in the object-item, as measured from the start of
+ * the entire body of the object.
+ *
+ * for directory entries, k_offset consists of hash derived from
+ * hashing the name and using few bits (23 or more) of the resulting
+ * hash, and generation number that allows distinguishing names with
+ * hash collisions. If number of collisions overflows generation
+ * number, we return EEXIST. High order bit is 0 always
+ */
+ __u32 k_offset;
+ __u32 k_uniqueness;
+};
+
+struct offset_v2
+{
+ /*
+ * for regular files this is the offset to the first byte of the
+ * body, contained in the object-item, as measured from the start of
+ * the entire body of the object.
+ *
+ * for directory entries, k_offset consists of hash derived from
+ * hashing the name and using few bits (23 or more) of the resulting
+ * hash, and generation number that allows distinguishing names with
+ * hash collisions. If number of collisions overflows generation
+ * number, we return EEXIST. High order bit is 0 always
+ */
+ __u64 k_offset:60;
+ __u64 k_type: 4;
+};
+
+
+struct key
+{
+ /* packing locality: by default parent directory object id */
+ __u32 k_dir_id;
+ /* object identifier */
+ __u32 k_objectid;
+ /* the offset and node type (old and new form) */
+ union
+ {
+ struct offset_v1 v1;
+ struct offset_v2 v2;
+ }
+ u;
+};
+
+#define KEY_SIZE (sizeof (struct key))
+
+/* Header of a disk block. More precisely, header of a formatted leaf
+ or internal node, and not the header of an unformatted node. */
+struct block_head
+{
+ __u16 blk_level; /* Level of a block in the tree. */
+ __u16 blk_nr_item; /* Number of keys/items in a block. */
+ __u16 blk_free_space; /* Block free space in bytes. */
+ struct key blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes
+ only) */
+};
+#define BLKH_SIZE (sizeof (struct block_head))
+#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */
+
+struct item_head
+{
+ struct key ih_key; /* Everything in the tree is found by searching for it based on its key.*/
+
+ union
+ {
+ __u16 ih_free_space; /* The free space in the last unformatted node of an indirect item if this
+ is an indirect item. This equals 0xFFFF iff this is a direct item or
+ stat data item. Note that the key, not this field, is used to determine
+ the item type, and thus which field this union contains. */
+ __u16 ih_entry_count; /* Iff this is a directory item, this field equals the number of directory
+ entries in the directory item. */
+ }
+ u;
+ __u16 ih_item_len; /* total size of the item body */
+ __u16 ih_item_location; /* an offset to the item body within the block */
+ __u16 ih_version; /* ITEM_VERSION_1 for all old items,
+ ITEM_VERSION_2 for new ones.
+ Highest bit is set by fsck
+ temporary, cleaned after all done */
+};
+/* size of item header */
+#define IH_SIZE (sizeof (struct item_head))
+
+#define ITEM_VERSION_1 0
+#define ITEM_VERSION_2 1
+#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \
+ ? (ih)->ih_key.u.v1.k_offset \
+ : (ih)->ih_key.u.v2.k_offset)
+
+#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \
+ ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \
+ : (ih)->ih_key.u.v2.k_type == V2_##type)
+
+struct disk_child
+{
+ unsigned long dc_block_number; /* Disk child's block number. */
+ unsigned short dc_size; /* Disk child's used space. */
+};
+
+#define DC_SIZE (sizeof (struct disk_child))
+
+/* Stat Data on disk.
+ *
+ * Note that reiserfs has two different forms of stat data. Luckily
+ * the fields needed by grub are at the same position.
+ */
+struct stat_data
+{
+ __u16 sd_mode; /* file type, permissions */
+ __u16 sd_notused1[3]; /* fields not needed by reiserfs */
+ __u32 sd_size; /* file size */
+ __u32 sd_size_hi; /* file size high 32 bits (since version 2) */
+};
+
+struct reiserfs_de_head
+{
+ __u32 deh_offset; /* third component of the directory entry key */
+ __u32 deh_dir_id; /* objectid of the parent directory of the
+ object, that is referenced by directory entry */
+ __u32 deh_objectid;/* objectid of the object, that is referenced by
+ directory entry */
+ __u16 deh_location;/* offset of name in the whole item */
+ __u16 deh_state; /* whether 1) entry contains stat data (for
+ future), and 2) whether entry is hidden
+ (unlinked) */
+};
+
+#define DEH_SIZE (sizeof (struct reiserfs_de_head))
+
+#define DEH_Statdata (1 << 0) /* not used now */
+#define DEH_Visible (1 << 2)
+
+#define SD_OFFSET 0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+#define V1_TYPE_STAT_DATA 0x0
+#define V1_TYPE_DIRECT 0xffffffff
+#define V1_TYPE_INDIRECT 0xfffffffe
+#define V1_TYPE_DIRECTORY_MAX 0xfffffffd
+#define V2_TYPE_STAT_DATA 0
+#define V2_TYPE_INDIRECT 1
+#define V2_TYPE_DIRECT 2
+#define V2_TYPE_DIRENTRY 3
+
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+#define REISERFS_OLD_BLOCKSIZE 4096
+
+#define S_ISREG(mode) (((mode) & 0170000) == 0100000)
+#define S_ISDIR(mode) (((mode) & 0170000) == 0040000)
+#define S_ISLNK(mode) (((mode) & 0170000) == 0120000)
+
+#define PATH_MAX 1024 /* include/linux/limits.h */
+#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
+
+/* The size of the node cache */
+#define FSYSREISER_CACHE_SIZE 24*1024
+#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE
+#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3
+
+/* Info about currently opened file */
+struct fsys_reiser_fileinfo
+{
+ __u32 k_dir_id;
+ __u32 k_objectid;
+};
+
+/* In memory info about the currently mounted filesystem */
+struct fsys_reiser_info
+{
+ /* The last read item head */
+ struct item_head *current_ih;
+ /* The last read item */
+ char *current_item;
+ /* The information for the currently opened file */
+ struct fsys_reiser_fileinfo fileinfo;
+ /* The start of the journal */
+ __u32 journal_block;
+ /* The size of the journal */
+ __u32 journal_block_count;
+ /* The first valid descriptor block in journal
+ (relative to journal_block) */
+ __u32 journal_first_desc;
+
+ /* The ReiserFS version. */
+ __u16 version;
+ /* The current depth of the reiser tree. */
+ __u16 tree_depth;
+ /* SECTOR_SIZE << blocksize_shift == blocksize. */
+ __u8 blocksize_shift;
+ /* 1 << full_blocksize_shift == blocksize. */
+ __u8 fullblocksize_shift;
+ /* The reiserfs block size (must be a power of 2) */
+ __u16 blocksize;
+ /* The number of cached tree nodes */
+ __u16 cached_slots;
+ /* The number of valid transactions in journal */
+ __u16 journal_transactions;
+
+ unsigned int blocks[MAX_HEIGHT];
+ unsigned int next_key_nr[MAX_HEIGHT];
+};
+
+/* The cached s+tree blocks in FSYS_BUF, see below
+ * for a more detailed description.
+ */
+#define ROOT ((char *) FSYS_BUF)
+#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift))
+#define LEAF CACHE (DISK_LEAF_NODE_LEVEL)
+
+#define BLOCKHEAD(cache) ((struct block_head *) cache)
+#define ITEMHEAD ((struct item_head *) ((char *) LEAF + BLKH_SIZE))
+#define KEY(cache) ((struct key *) ((char *) cache + BLKH_SIZE))
+#define DC(cache) ((struct disk_child *) \
+ ((char *) cache + BLKH_SIZE + KEY_SIZE * nr_item))
+/* The fsys_reiser_info block.
+ */
+#define INFO \
+ ((struct fsys_reiser_info *) ((char *) FSYS_BUF + FSYSREISER_CACHE_SIZE))
+/*
+ * The journal cache. For each transaction it contains the number of
+ * blocks followed by the real block numbers of this transaction.
+ *
+ * If the block numbers of some transaction won't fit in this space,
+ * this list is stopped with a 0xffffffff marker and the remaining
+ * uncommitted transactions aren't cached.
+ */
+#define JOURNAL_START ((__u32 *) (INFO + 1))
+#define JOURNAL_END ((__u32 *) (FSYS_BUF + FSYS_BUFLEN))
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef __amd64
+#define BSF "bsfq"
+#else
+#define BSF "bsfl"
+#endif
+static __inline__ unsigned long
+grub_log2 (unsigned long word)
+{
+ __asm__ (BSF " %1,%0"
+ : "=r" (word)
+ : "r" (word));
+ return word;
+}
+
+#elif defined(__ia64__)
+
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define ia64_popcnt(x) __builtin_popcountl(x)
+#else
+# define ia64_popcnt(x) \
+ ({ \
+ __u64 ia64_intri_res; \
+ asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \
+ ia64_intri_res; \
+ })
+#endif
+
+static __inline__ unsigned long
+grub_log2 (unsigned long word)
+{
+ unsigned long result;
+
+ result = ia64_popcnt((word - 1) & ~word);
+ return result;
+}
+
+#elif defined(__powerpc__)
+
+#ifdef __powerpc64__
+#define PPC_CNTLZL "cntlzd"
+#else
+#define PPC_CNTLZL "cntlzw"
+#endif
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+static __inline__ int
+__ilog2(unsigned long x)
+{
+ int lz;
+
+ asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (x));
+ return BITS_PER_LONG - 1 - lz;
+}
+
+static __inline__ unsigned long
+grub_log2 (unsigned long word)
+{
+ return __ilog2(word & -word);
+}
+
+#else /* Unoptimized */
+
+static __inline__ unsigned long
+grub_log2 (unsigned long word)
+{
+ unsigned long result = 0;
+
+ while (!(word & 1UL))
+ {
+ result++;
+ word >>= 1;
+ }
+ return result;
+}
+#endif
+#define log2 grub_log2
+
+static __inline__ int
+is_power_of_two (unsigned long word)
+{
+ return (word & -word) == word;
+}
+
+static int
+journal_read (fsi_file_t *ffi, int block, int len, char *buffer)
+{
+ return devread (ffi, (INFO->journal_block + block) << INFO->blocksize_shift,
+ 0, len, buffer);
+}
+
+/* Read a block from ReiserFS file system, taking the journal into
+ * account. If the block nr is in the journal, the block from the
+ * journal taken.
+ */
+static int
+block_read (fsi_file_t *ffi, int blockNr, int start, int len, char *buffer)
+{
+ int transactions = INFO->journal_transactions;
+ int desc_block = INFO->journal_first_desc;
+ int journal_mask = INFO->journal_block_count - 1;
+ int translatedNr = blockNr;
+ __u32 *journal_table = JOURNAL_START;
+ while (transactions-- > 0)
+ {
+ int i = 0;
+ int j_len;
+ if (*journal_table != 0xffffffff)
+ {
+ /* Search for the blockNr in cached journal */
+ j_len = *journal_table++;
+ while (i++ < j_len)
+ {
+ if (*journal_table++ == blockNr)
+ {
+ journal_table += j_len - i;
+ goto found;
+ }
+ }
+ }
+ else
+ {
+ /* This is the end of cached journal marker. The remaining
+ * transactions are still on disk.
+ */
+ struct reiserfs_journal_desc desc;
+ struct reiserfs_journal_commit commit;
+
+ if (! journal_read (ffi, desc_block, sizeof (desc), (char *) &desc))
+ return 0;
+
+ j_len = desc.j_len;
+ while (i < j_len && i < JOURNAL_TRANS_HALF)
+ if (desc.j_realblock[i++] == blockNr)
+ goto found;
+
+ if (j_len >= JOURNAL_TRANS_HALF)
+ {
+ int commit_block = (desc_block + 1 + j_len) & journal_mask;
+ if (! journal_read (ffi, commit_block,
+ sizeof (commit), (char *) &commit))
+ return 0;
+ while (i < j_len)
+ if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr)
+ goto found;
+ }
+ }
+ goto not_found;
+
+ found:
+ translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask);
+#ifdef REISERDEBUG
+ printf ("block_read: block %d is mapped to journal block %d.\n",
+ blockNr, translatedNr - INFO->journal_block);
+#endif
+ /* We must continue the search, as this block may be overwritten
+ * in later transactions.
+ */
+ not_found:
+ desc_block = (desc_block + 2 + j_len) & journal_mask;
+ }
+ return devread (ffi, translatedNr << INFO->blocksize_shift, start, len, buffer);
+}
+
+/* Init the journal data structure. We try to cache as much as
+ * possible in the JOURNAL_START-JOURNAL_END space, but if it is full
+ * we can still read the rest from the disk on demand.
+ *
+ * The first number of valid transactions and the descriptor block of the
+ * first valid transaction are held in INFO. The transactions are all
+ * adjacent, but we must take care of the journal wrap around.
+ */
+static int
+journal_init (fsi_file_t *ffi)
+{
+ unsigned int block_count = INFO->journal_block_count;
+ unsigned int desc_block;
+ unsigned int commit_block;
+ unsigned int next_trans_id;
+ struct reiserfs_journal_header header;
+ struct reiserfs_journal_desc desc;
+ struct reiserfs_journal_commit commit;
+ __u32 *journal_table = JOURNAL_START;
+
+ journal_read (ffi, block_count, sizeof (header), (char *) &header);
+ desc_block = header.j_first_unflushed_offset;
+ if (desc_block >= block_count)
+ return 0;
+
+ INFO->journal_first_desc = desc_block;
+ next_trans_id = header.j_last_flush_trans_id + 1;
+
+#ifdef REISERDEBUG
+ printf ("journal_init: last flushed %d\n",
+ header.j_last_flush_trans_id);
+#endif
+
+ while (1)
+ {
+ journal_read (ffi, desc_block, sizeof (desc), (char *) &desc);
+ if (substring (JOURNAL_DESC_MAGIC, desc.j_magic)
+ || desc.j_trans_id != next_trans_id
+ || desc.j_mount_id != header.j_mount_id)
+ /* no more valid transactions */
+ break;
+
+ commit_block = (desc_block + desc.j_len + 1) & (block_count - 1);
+ journal_read (ffi, commit_block, sizeof (commit), (char *) &commit);
+ if (desc.j_trans_id != commit.j_trans_id
+ || desc.j_len != commit.j_len)
+ /* no more valid transactions */
+ break;
+
+#ifdef REISERDEBUG
+ printf ("Found valid transaction %d/%d at %d.\n",
+ desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+ next_trans_id++;
+ if (journal_table < JOURNAL_END)
+ {
+ if ((journal_table + 1 + desc.j_len) >= JOURNAL_END)
+ {
+ /* The table is almost full; mark the end of the cached
+ * journal.*/
+ *journal_table = 0xffffffff;
+ journal_table = JOURNAL_END;
+ }
+ else
+ {
+ int i;
+ /* Cache the length and the realblock numbers in the table.
+ * The block number of descriptor can easily be computed.
+ * and need not to be stored here.
+ */
+ *journal_table++ = desc.j_len;
+ for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++)
+ {
+ *journal_table++ = desc.j_realblock[i];
+#ifdef REISERDEBUG
+ printf ("block %d is in journal %d.\n",
+ desc.j_realblock[i], desc_block);
+#endif
+ }
+ for ( ; i < desc.j_len; i++)
+ {
+ *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF];
+#ifdef REISERDEBUG
+ printf ("block %d is in journal %d.\n",
+ commit.j_realblock[i-JOURNAL_TRANS_HALF],
+ desc_block);
+#endif
+ }
+ }
+ }
+ desc_block = (commit_block + 1) & (block_count - 1);
+ }
+#ifdef REISERDEBUG
+ printf ("Transaction %d/%d at %d isn't valid.\n",
+ desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+ INFO->journal_transactions
+ = next_trans_id - header.j_last_flush_trans_id - 1;
+ return errnum == 0;
+}
+
+/* check filesystem types and read superblock into memory buffer */
+int
+reiserfs_mount (fsi_file_t *ffi)
+{
+ struct reiserfs_super_block super;
+ int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+
+ if (/*part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+ || */ !devread (ffi, superblock, 0, sizeof (struct reiserfs_super_block),
+ (char *) &super)
+ || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+ || (/* check that this is not a copy inside the journal log */
+ super.s_journal_block * super.s_blocksize
+ <= REISERFS_DISK_OFFSET_IN_BYTES))
+ {
+ /* Try old super block position */
+ superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+ if (/*part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+ || */ ! devread (ffi, superblock, 0, sizeof (struct reiserfs_super_block),
+ (char *) &super))
+ return 0;
+
+ if (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+ && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+ {
+ /* pre journaling super block ? */
+ if (substring (REISERFS_SUPER_MAGIC_STRING,
+ (char*) ((char *) &super + 20)) > 0)
+ return 0;
+
+ super.s_blocksize = REISERFS_OLD_BLOCKSIZE;
+ super.s_journal_block = 0;
+ super.s_version = 0;
+ }
+ }
+
+ /* check the version number. */
+ if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION)
+ return 0;
+
+ INFO->version = super.s_version;
+ INFO->blocksize = super.s_blocksize;
+ INFO->fullblocksize_shift = log2 (super.s_blocksize);
+ INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS;
+ INFO->cached_slots =
+ (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1;
+
+#ifdef REISERDEBUG
+ printf ("reiserfs_mount: version=%d, blocksize=%d\n",
+ INFO->version, INFO->blocksize);
+#endif /* REISERDEBUG */
+
+ /* Clear node cache. */
+ memset (INFO->blocks, 0, sizeof (INFO->blocks));
+
+ if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE
+ || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE
+ || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize)
+ return 0;
+
+ /* Initialize journal code. If something fails we end with zero
+ * journal_transactions, so we don't access the journal at all.
+ */
+ INFO->journal_transactions = 0;
+ if (super.s_journal_block != 0 && super.s_journal_dev == 0)
+ {
+ INFO->journal_block = super.s_journal_block;
+ INFO->journal_block_count = super.s_journal_size;
+ if (is_power_of_two (INFO->journal_block_count))
+ journal_init (ffi);
+
+ /* Read in super block again, maybe it is in the journal */
+ block_read (ffi, superblock >> INFO->blocksize_shift,
+ 0, sizeof (struct reiserfs_super_block), (char *) &super);
+ }
+
+ if (! block_read (ffi, super.s_root_block, 0, INFO->blocksize, (char*) ROOT))
+ return 0;
+
+ INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level;
+
+#ifdef REISERDEBUG
+ printf ("root read_in: block=%d, depth=%d\n",
+ super.s_root_block, INFO->tree_depth);
+#endif /* REISERDEBUG */
+
+ if (INFO->tree_depth >= MAX_HEIGHT)
+ return 0;
+ if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL)
+ {
+ /* There is only one node in the whole filesystem,
+ * which is simultanously leaf and root */
+ memcpy (LEAF, ROOT, INFO->blocksize);
+ }
+ return 1;
+}
+
+/***************** TREE ACCESSING METHODS *****************************/
+
+/* I assume you are familiar with the ReiserFS tree, if not go to
+ * http://www.namesys.com/content_table.html
+ *
+ * My tree node cache is organized as following
+ * 0 ROOT node
+ * 1 LEAF node (if the ROOT is also a LEAF it is copied here
+ * 2-n other nodes on current path from bottom to top.
+ * if there is not enough space in the cache, the top most are
+ * omitted.
+ *
+ * I have only two methods to find a key in the tree:
+ * search_stat(dir_id, objectid) searches for the stat entry (always
+ * the first entry) of an object.
+ * next_key() gets the next key in tree order.
+ *
+ * This means, that I can only sequential reads of files are
+ * efficient, but this really doesn't hurt for grub.
+ */
+
+/* Read in the node at the current path and depth into the node cache.
+ * You must set INFO->blocks[depth] before.
+ */
+static char *
+read_tree_node (fsi_file_t *ffi, unsigned int blockNr, int depth)
+{
+ char* cache = CACHE(depth);
+ int num_cached = INFO->cached_slots;
+ if (depth < num_cached)
+ {
+ /* This is the cached part of the path. Check if same block is
+ * needed.
+ */
+ if (blockNr == INFO->blocks[depth])
+ return cache;
+ }
+ else
+ cache = CACHE(num_cached);
+
+#ifdef REISERDEBUG
+ printf (" next read_in: block=%d (depth=%d)\n",
+ blockNr, depth);
+#endif /* REISERDEBUG */
+ if (! block_read (ffi, blockNr, 0, INFO->blocksize, cache))
+ return 0;
+ /* Make sure it has the right node level */
+ if (BLOCKHEAD (cache)->blk_level != depth)
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+ INFO->blocks[depth] = blockNr;
+ return cache;
+}
+
+/* Get the next key, i.e. the key following the last retrieved key in
+ * tree order. INFO->current_ih and
+ * INFO->current_info are adapted accordingly. */
+static int
+next_key (fsi_file_t *ffi)
+{
+ int depth;
+ struct item_head *ih = INFO->current_ih + 1;
+ char *cache;
+
+#ifdef REISERDEBUG
+ printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+
+ if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item])
+ {
+ depth = DISK_LEAF_NODE_LEVEL;
+ /* The last item, was the last in the leaf node.
+ * Read in the next block
+ */
+ do
+ {
+ if (depth == INFO->tree_depth)
+ {
+ /* There are no more keys at all.
+ * Return a dummy item with MAX_KEY */
+ ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key;
+ goto found;
+ }
+ depth++;
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]);
+#endif /* REISERDEBUG */
+ }
+ while (INFO->next_key_nr[depth] == 0);
+
+ if (depth == INFO->tree_depth)
+ cache = ROOT;
+ else if (depth <= INFO->cached_slots)
+ cache = CACHE (depth);
+ else
+ {
+ cache = read_tree_node (ffi, INFO->blocks[depth], depth);
+ if (! cache)
+ return 0;
+ }
+
+ do
+ {
+ int nr_item = BLOCKHEAD (cache)->blk_nr_item;
+ int key_nr = INFO->next_key_nr[depth]++;
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item);
+#endif /* REISERDEBUG */
+ if (key_nr == nr_item)
+ /* This is the last item in this block, set the next_key_nr to 0 */
+ INFO->next_key_nr[depth] = 0;
+
+ cache = read_tree_node (ffi, DC (cache)[key_nr].dc_block_number, --depth);
+ if (! cache)
+ return 0;
+ }
+ while (depth > DISK_LEAF_NODE_LEVEL);
+
+ ih = ITEMHEAD;
+ }
+ found:
+ INFO->current_ih = ih;
+ INFO->current_item = &LEAF[ih->ih_item_location];
+#ifdef REISERDEBUG
+ printf (" new ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+ return 1;
+}
+
+/* preconditions: reiserfs_mount already executed, therefore
+ * INFO block is valid
+ * returns: 0 if error (errnum is set),
+ * nonzero iff we were able to find the key successfully.
+ * postconditions: on a nonzero return, the current_ih and
+ * current_item fields describe the key that equals the
+ * searched key. INFO->next_key contains the next key after
+ * the searched key.
+ * side effects: messes around with the cache.
+ */
+static int
+search_stat (fsi_file_t *ffi, __u32 dir_id, __u32 objectid)
+{
+ char *cache;
+ int depth;
+ int nr_item;
+ int i;
+ struct item_head *ih;
+#ifdef REISERDEBUG
+ printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid);
+#endif /* REISERDEBUG */
+
+ depth = INFO->tree_depth;
+ cache = ROOT;
+
+ while (depth > DISK_LEAF_NODE_LEVEL)
+ {
+ struct key *key;
+ nr_item = BLOCKHEAD (cache)->blk_nr_item;
+
+ key = KEY (cache);
+
+ for (i = 0; i < nr_item; i++)
+ {
+ if (key->k_dir_id > dir_id
+ || (key->k_dir_id == dir_id
+ && (key->k_objectid > objectid
+ || (key->k_objectid == objectid
+ && (key->u.v1.k_offset
+ | key->u.v1.k_uniqueness) > 0))))
+ break;
+ key++;
+ }
+
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+ INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1;
+ cache = read_tree_node (ffi, DC (cache)[i].dc_block_number, --depth);
+ if (! cache)
+ return 0;
+ }
+
+ /* cache == LEAF */
+ nr_item = BLOCKHEAD (LEAF)->blk_nr_item;
+ ih = ITEMHEAD;
+ for (i = 0; i < nr_item; i++)
+ {
+ if (ih->ih_key.k_dir_id == dir_id
+ && ih->ih_key.k_objectid == objectid
+ && ih->ih_key.u.v1.k_offset == 0
+ && ih->ih_key.u.v1.k_uniqueness == 0)
+ {
+#ifdef REISERDEBUG
+ printf (" depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+ INFO->current_ih = ih;
+ INFO->current_item = &LEAF[ih->ih_item_location];
+ return 1;
+ }
+ ih++;
+ }
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+}
+
+int
+reiserfs_read (fsi_file_t *ffi, char *buf, int len)
+{
+ unsigned int blocksize;
+ unsigned int offset;
+ unsigned int to_read;
+ char *prev_buf = buf;
+
+#ifdef REISERDEBUG
+ printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n",
+ filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1);
+#endif /* REISERDEBUG */
+
+ if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid
+ || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1)
+ {
+ search_stat (ffi, INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid);
+ goto get_next_key;
+ }
+
+ while (! errnum)
+ {
+ if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid)
+ break;
+
+ offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1;
+ blocksize = INFO->current_ih->ih_item_len;
+
+#ifdef REISERDEBUG
+ printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n",
+ filepos, len, offset, blocksize);
+#endif /* REISERDEBUG */
+
+ if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT)
+ && offset < blocksize)
+ {
+#ifdef REISERDEBUG
+ printf ("direct_read: offset=%d, blocksize=%d\n",
+ offset, blocksize);
+#endif /* REISERDEBUG */
+ to_read = blocksize - offset;
+ if (to_read > len)
+ to_read = len;
+
+ if (disk_read_hook != NULL)
+ {
+ disk_read_func = disk_read_hook;
+
+ block_read (ffi, INFO->blocks[DISK_LEAF_NODE_LEVEL],
+ (INFO->current_item - LEAF + offset), to_read, buf);
+
+ disk_read_func = NULL;
+ }
+ else
+ memcpy (buf, INFO->current_item + offset, to_read);
+ goto update_buf_len;
+ }
+ else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT))
+ {
+ blocksize = (blocksize >> 2) << INFO->fullblocksize_shift;
+#ifdef REISERDEBUG
+ printf ("indirect_read: offset=%d, blocksize=%d\n",
+ offset, blocksize);
+#endif /* REISERDEBUG */
+
+ while (offset < blocksize)
+ {
+ __u32 blocknr = ((__u32 *) INFO->current_item)
+ [offset >> INFO->fullblocksize_shift];
+ int blk_offset = offset & (INFO->blocksize-1);
+
+ to_read = INFO->blocksize - blk_offset;
+ if (to_read > len)
+ to_read = len;
+
+ disk_read_func = disk_read_hook;
+
+ /* Journal is only for meta data. Data blocks can be read
+ * directly without using block_read
+ */
+ devread (ffi, blocknr << INFO->blocksize_shift,
+ blk_offset, to_read, buf);
+
+ disk_read_func = NULL;
+ update_buf_len:
+ len -= to_read;
+ buf += to_read;
+ offset += to_read;
+ filepos += to_read;
+ if (len == 0)
+ goto done;
+ }
+ }
+ get_next_key:
+ next_key (ffi);
+ }
+ done:
+ return errnum ? 0 : buf - prev_buf;
+}
+
+
+/* preconditions: reiserfs_mount already executed, therefore
+ * INFO block is valid
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, INFO->fileinfo contains the info
+ * of the file we were trying to look up, filepos is 0 and filemax is
+ * the size of the file.
+ */
+int
+reiserfs_dir (fsi_file_t *ffi, char *dirname)
+{
+ struct reiserfs_de_head *de_head;
+ char *rest, ch;
+ __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;
+#ifndef STAGE1_5
+ int do_possibilities = 0;
+#endif /* ! STAGE1_5 */
+ char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
+ int link_count = 0;
+ int mode;
+
+ dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+ objectid = REISERFS_ROOT_OBJECTID;
+
+ while (1)
+ {
+#ifdef REISERDEBUG
+ printf ("dirname=%s\n", dirname);
+#endif /* REISERDEBUG */
+
+ /* Search for the stat info first. */
+ if (! search_stat (ffi, dir_id, objectid))
+ return 0;
+
+#ifdef REISERDEBUG
+ printf ("sd_mode=%x sd_size=%d\n",
+ ((struct stat_data *) INFO->current_item)->sd_mode,
+ ((struct stat_data *) INFO->current_item)->sd_size);
+#endif /* REISERDEBUG */
+
+ mode = ((struct stat_data *) INFO->current_item)->sd_mode;
+
+ /* If we've got a symbolic link, then chase it. */
+ if (S_ISLNK (mode))
+ {
+ int len;
+ if (++link_count > MAX_LINK_COUNT)
+ {
+ errnum = ERR_SYMLINK_LOOP;
+ return 0;
+ }
+
+ /* Get the symlink size. */
+ filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+ /* Find out how long our remaining name is. */
+ len = 0;
+ while (dirname[len] && !isspace (dirname[len]))
+ len++;
+
+ if (filemax + len > sizeof (linkbuf) - 1)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+ /* Copy the remaining name to the end of the symlink data.
+ Note that DIRNAME and LINKBUF may overlap! */
+ grub_memmove (linkbuf + filemax, dirname, len+1);
+
+ INFO->fileinfo.k_dir_id = dir_id;
+ INFO->fileinfo.k_objectid = objectid;
+ filepos = 0;
+ if (! next_key (ffi)
+ || reiserfs_read (ffi, linkbuf, filemax) != filemax)
+ {
+ if (! errnum)
+ errnum = ERR_FSYS_CORRUPT;
+ return 0;
+ }
+
+#ifdef REISERDEBUG
+ printf ("symlink=%s\n", linkbuf);
+#endif /* REISERDEBUG */
+
+ dirname = linkbuf;
+ if (*dirname == '/')
+ {
+ /* It's an absolute link, so look it up in root. */
+ dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+ objectid = REISERFS_ROOT_OBJECTID;
+ }
+ else
+ {
+ /* Relative, so look it up in our parent directory. */
+ dir_id = parent_dir_id;
+ objectid = parent_objectid;
+ }
+
+ /* Now lookup the new name. */
+ continue;
+ }
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (! *dirname || isspace (*dirname))
+ {
+ if (! S_ISREG (mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filepos = 0;
+ filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+ /* If this is a new stat data and size is > 4GB set filemax to
+ * maximum
+ */
+ if (INFO->current_ih->ih_version == ITEM_VERSION_2
+ && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0)
+ filemax = 0xffffffff;
+
+ INFO->fileinfo.k_dir_id = dir_id;
+ INFO->fileinfo.k_objectid = objectid;
+ return next_key (ffi);
+ }
+
+ /* continue with the file/directory name interpretation */
+ while (*dirname == '/')
+ dirname++;
+ if (! S_ISDIR (mode))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+ for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++);
+ *rest = 0;
+
+# ifndef STAGE1_5
+ if (print_possibilities && ch != '/')
+ do_possibilities = 1;
+# endif /* ! STAGE1_5 */
+
+ while (1)
+ {
+ char *name_end;
+ int num_entries;
+
+ if (! next_key (ffi))
+ return 0;
+#ifdef REISERDEBUG
+ printf ("ih: key %d:%d:%d:%d version:%d\n",
+ INFO->current_ih->ih_key.k_dir_id,
+ INFO->current_ih->ih_key.k_objectid,
+ INFO->current_ih->ih_key.u.v1.k_offset,
+ INFO->current_ih->ih_key.u.v1.k_uniqueness,
+ INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+
+ if (INFO->current_ih->ih_key.k_objectid != objectid)
+ break;
+
+ name_end = INFO->current_item + INFO->current_ih->ih_item_len;
+ de_head = (struct reiserfs_de_head *) INFO->current_item;
+ num_entries = INFO->current_ih->u.ih_entry_count;
+ while (num_entries > 0)
+ {
+ char *filename = INFO->current_item + de_head->deh_location;
+ char tmp = *name_end;
+ if ((de_head->deh_state & DEH_Visible))
+ {
+ int cmp;
+ /* Directory names in ReiserFS are not null
+ * terminated. We write a temporary 0 behind it.
+ * NOTE: that this may overwrite the first block in
+ * the tree cache. That doesn't hurt as long as we
+ * don't call next_key () in between.
+ */
+ *name_end = 0;
+ cmp = substring (dirname, filename);
+ *name_end = tmp;
+# ifndef STAGE1_5
+ if (do_possibilities)
+ {
+ if (cmp <= 0)
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+ *name_end = 0;
+ print_a_completion (filename);
+ *name_end = tmp;
+ }
+ }
+ else
+# endif /* ! STAGE1_5 */
+ if (cmp == 0)
+ goto found;
+ }
+ /* The beginning of this name marks the end of the next name.
+ */
+ name_end = filename;
+ de_head++;
+ num_entries--;
+ }
+ }
+
+# ifndef STAGE1_5
+ if (print_possibilities < 0)
+ return 1;
+# endif /* ! STAGE1_5 */
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+
+ found:
+
+ *rest = ch;
+ dirname = rest;
+
+ parent_dir_id = dir_id;
+ parent_objectid = objectid;
+ dir_id = de_head->deh_dir_id;
+ objectid = de_head->deh_objectid;
+ }
+}
+
+int
+reiserfs_embed (fsi_file_t *ffi, int *start_sector, int needed_sectors)
+{
+ struct reiserfs_super_block super;
+ int num_sectors;
+
+ if (! devread (ffi, REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0,
+ sizeof (struct reiserfs_super_block), (char *) &super))
+ return 0;
+
+ *start_sector = 1; /* reserve first sector for stage1 */
+ if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+ || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+ || substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) <= 0)
+ && (/* check that this is not a super block copy inside
+ * the journal log */
+ super.s_journal_block * super.s_blocksize
+ > REISERFS_DISK_OFFSET_IN_BYTES))
+ num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+ else
+ num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+
+ return (needed_sectors <= num_sectors);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+ static fsig_plugin_ops_t ops = {
+ FSIMAGE_PLUGIN_VERSION,
+ .fpo_mount = reiserfs_mount,
+ .fpo_dir = reiserfs_dir,
+ .fpo_read = reiserfs_read
+ };
+
+ *name = "reiserfs";
+ return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/ufs/Makefile b/tools/libfsimage/ufs/Makefile
new file mode 100644
index 0000000000..b7218c2b3f
--- /dev/null
+++ b/tools/libfsimage/ufs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_ufs.c
+
+FS = ufs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ufs/fsys_ufs.c b/tools/libfsimage/ufs/fsys_ufs.c
new file mode 100644
index 0000000000..f1cb917c8c
--- /dev/null
+++ b/tools/libfsimage/ufs/fsys_ufs.c
@@ -0,0 +1,276 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ * 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
+
+#include <fsimage_grub.h>
+
+#include "ufs.h"
+
+/* These are the pools of buffers, etc. */
+
+#define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
+#define INODE ((struct icommon *)(FSYS_BUF + 0x1000))
+#define DIRENT (FSYS_BUF + 0x4000)
+#define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
+#define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000)) /* 1st indirect blk */
+
+#define indirblk0 (*fsig_int1(ffi))
+#define indirblk1 (*fsig_int2(ffi))
+
+static int openi(fsi_file_t *, grub_ino_t);
+static grub_ino_t dlook(fsi_file_t *, grub_ino_t, char *);
+static grub_daddr32_t sbmap(fsi_file_t *, grub_daddr32_t);
+
+/* read superblock and check fs magic */
+int
+ufs_mount(fsi_file_t *ffi)
+{
+ if (/*! IS_PC_SLICE_TYPE_SOLARIS(current_slice) || */
+ !devread(ffi, UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
+ SUPERBLOCK->fs_magic != UFS_MAGIC)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * searching for a file, if successful, inode will be loaded in INODE
+ * The entry point should really be named ufs_open(char *pathname).
+ * For now, keep it consistent with the rest of fsys modules.
+ */
+int
+ufs_dir(fsi_file_t *ffi, char *dirname)
+{
+ grub_ino_t inode = ROOTINO; /* start from root */
+ char *fname, ch;
+
+ indirblk0 = indirblk1 = 0;
+
+ /* skip leading slashes */
+ while (*dirname == '/')
+ dirname++;
+
+ while (inode && *dirname && !isspace(*dirname)) {
+ if (!openi(ffi, inode))
+ return 0;
+
+ /* parse for next path component */
+ fname = dirname;
+ while (*dirname && !isspace(*dirname) && *dirname != '/')
+ dirname++;
+ ch = *dirname;
+ *dirname = 0; /* ensure null termination */
+
+ inode = dlook(ffi, inode, fname);
+ *dirname = ch;
+ while (*dirname == '/')
+ dirname++;
+ }
+
+ /* return 1 only if inode exists and is a regular file */
+ if (! openi(ffi, inode))
+ return (0);
+ filepos = 0;
+ filemax = INODE->ic_sizelo;
+ return (inode && ((INODE->ic_smode & IFMT) == IFREG));
+}
+
+/*
+ * This is the high-level read function.
+ */
+int
+ufs_read(fsi_file_t *ffi, char *buf, int len)
+{
+ int off, size, ret = 0, ok;
+ grub_daddr32_t lblk, dblk;
+
+ while (len) {
+ off = blkoff(SUPERBLOCK, filepos);
+ lblk = lblkno(SUPERBLOCK, filepos);
+ size = SUPERBLOCK->fs_bsize;
+ size -= off;
+ if (size > len)
+ size = len;
+
+ if ((dblk = sbmap(ffi, lblk)) <= 0) {
+ /* we are in a file hole, just zero the buf */
+ grub_memset(buf, 0, size);
+ } else {
+ disk_read_func = disk_read_hook;
+ ok = devread(ffi, fsbtodb(SUPERBLOCK, dblk),
+ off, size, buf);
+ disk_read_func = 0;
+ if (!ok)
+ return 0;
+ }
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ return (ret);
+}
+
+int
+ufs_embed (int *start_sector, int needed_sectors)
+{
+ if (needed_sectors > 14)
+ return 0;
+
+ *start_sector = 2;
+ return 1;
+}
+
+/* read inode and place content in INODE */
+static int
+openi(fsi_file_t *ffi, grub_ino_t inode)
+{
+ grub_daddr32_t dblk;
+ int off;
+
+ /* get block and byte offset into the block */
+ dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
+ off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
+
+ return (devread(ffi, dblk, off, sizeof (struct icommon), (char *)INODE));
+}
+
+/*
+ * Performs fileblock mapping. Convert file block no. to disk block no.
+ * Returns 0 when block doesn't exist and <0 when block isn't initialized
+ * (i.e belongs to a hole in the file).
+ */
+grub_daddr32_t
+sbmap(fsi_file_t *ffi, grub_daddr32_t bn)
+{
+ int level, bound, i, index;
+ grub_daddr32_t nb, blkno;
+ grub_daddr32_t *db = INODE->ic_db;
+
+ /* blocks 0..UFS_NDADDR are direct blocks */
+ if (bn < UFS_NDADDR) {
+ return db[bn];
+ }
+
+ /* determine how many levels of indirection. */
+ level = 0;
+ bn -= UFS_NDADDR;
+ bound = UFS_NINDIR(SUPERBLOCK);
+ while (bn >= bound) {
+ level++;
+ bn -= bound;
+ bound *= UFS_NINDIR(SUPERBLOCK);
+ }
+ if (level >= UFS_NIADDR) /* bn too big */
+ return ((grub_daddr32_t)0);
+
+ /* fetch the first indirect block */
+ nb = INODE->ic_ib[level];
+ if (nb == 0) {
+ return ((grub_daddr32_t)0);
+ }
+ if (indirblk0 != nb) {
+ indirblk0 = 0;
+ blkno = fsbtodb(SUPERBLOCK, nb);
+ if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
+ (char *)INDIRBLK0))
+ return (0);
+ indirblk0 = nb;
+ }
+ bound /= UFS_NINDIR(SUPERBLOCK);
+ index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
+ nb = INDIRBLK0[index];
+
+ /* fetch through the indirect blocks */
+ for (i = 1; i <= level; i++) {
+ if (indirblk1 != nb) {
+ blkno = fsbtodb(SUPERBLOCK, nb);
+ if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
+ (char *)INDIRBLK1))
+ return (0);
+ indirblk1 = nb;
+ }
+ bound /= UFS_NINDIR(SUPERBLOCK);
+ index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
+ nb = INDIRBLK1[index];
+ if (nb == 0)
+ return ((grub_daddr32_t)0);
+ }
+
+ return (nb);
+}
+
+/* search directory content for name, return inode number */
+static grub_ino_t
+dlook(fsi_file_t *ffi, grub_ino_t dir_ino, char *name)
+{
+ int loc, off;
+ grub_daddr32_t lbn, dbn, dblk;
+ struct direct *dp;
+
+ if ((INODE->ic_smode & IFMT) != IFDIR)
+ return 0;
+
+ loc = 0;
+ while (loc < INODE->ic_sizelo) {
+ /* offset into block */
+ off = blkoff(SUPERBLOCK, loc);
+ if (off == 0) { /* need to read in a new block */
+ /* get logical block number */
+ lbn = lblkno(SUPERBLOCK, loc);
+ /* resolve indrect blocks */
+ dbn = sbmap(ffi, lbn);
+ if (dbn == 0)
+ return (0);
+
+ dblk = fsbtodb(SUPERBLOCK, dbn);
+ if (!devread(ffi, dblk, 0, SUPERBLOCK->fs_bsize,
+ (char *)DIRENT)) {
+ return 0;
+ }
+ }
+
+ dp = (struct direct *)(DIRENT + off);
+ if (dp->d_ino && substring(name, dp->d_name) == 0)
+ return (dp->d_ino);
+ loc += dp->d_reclen;
+ }
+ return (0);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+ static fsig_plugin_ops_t ops = {
+ FSIMAGE_PLUGIN_VERSION,
+ .fpo_mount = ufs_mount,
+ .fpo_dir = ufs_dir,
+ .fpo_read = ufs_read
+ };
+
+ *name = "ufs";
+ return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/ufs/ufs.h b/tools/libfsimage/ufs/ufs.h
new file mode 100644
index 0000000000..4e7c736c6d
--- /dev/null
+++ b/tools/libfsimage/ufs/ufs.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _GRUB_UFS_H
+#define _GRUB_UFS_H_
+
+/* ufs specific constants */
+#define UFS_SBLOCK 16
+#define UFS_SBSIZE 8192
+#define UFS_MAGIC 0x011954
+#define ROOTINO 2 /* i number of all roots */
+#define UFS_NDADDR 12 /* direct blocks */
+#define UFS_NIADDR 3 /* indirect blocks */
+#define MAXMNTLEN 512
+#define MAXCSBUFS 32
+#define MAXNAMELEN 256
+
+/* file types */
+#define IFMT 0xf000
+#define IFREG 0x8000
+#define IFDIR 0x4000
+
+typedef unsigned char grub_uchar_t;
+typedef unsigned short grub_ushort_t;
+typedef unsigned short grub_o_mode_t;
+typedef unsigned short grub_o_uid_t;
+typedef unsigned short grub_o_gid_t;
+typedef uint32_t grub_ino_t;
+typedef int32_t grub_int32_t;
+typedef int32_t grub_uid_t;
+typedef int32_t grub_gid_t;
+typedef uint32_t grub_uint32_t;
+typedef uint32_t grub_daddr32_t;
+typedef uint32_t grub_time32_t;
+typedef struct { int val[2]; } grub_quad_t;
+
+struct timeval32 {
+ grub_time32_t tv_sec;
+ grub_int32_t tv_usec;
+};
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ *
+ * N.B. sizeof (struct csum) must be a power of two in order for
+ * the ``fs_cs'' macro to work (see below).
+ */
+struct csum {
+ grub_int32_t cs_ndir; /* number of directories */
+ grub_int32_t cs_nbfree; /* number of free blocks */
+ grub_int32_t cs_nifree; /* number of free inodes */
+ grub_int32_t cs_nffree; /* number of free frags */
+};
+
+/* Ufs super block */
+struct fs {
+ grub_uint32_t fs_link; /* linked list of file systems */
+ grub_uint32_t fs_rolled; /* logging only: fs fully rolled */
+ grub_daddr32_t fs_sblkno; /* addr of super-block in filesys */
+ grub_daddr32_t fs_cblkno; /* offset of cyl-block in filesys */
+ grub_daddr32_t fs_iblkno; /* offset of inode-blocks in filesys */
+ grub_daddr32_t fs_dblkno; /* offset of first data after cg */
+ grub_int32_t fs_cgoffset; /* cylinder group offset in cylinder */
+ grub_int32_t fs_cgmask; /* used to calc mod fs_ntrak */
+ grub_time32_t fs_time; /* last time written */
+ grub_int32_t fs_size; /* number of blocks in fs */
+ grub_int32_t fs_dsize; /* number of data blocks in fs */
+ grub_int32_t fs_ncg; /* number of cylinder groups */
+ grub_int32_t fs_bsize; /* size of basic blocks in fs */
+ grub_int32_t fs_fsize; /* size of frag blocks in fs */
+ grub_int32_t fs_frag; /* number of frags in a block in fs */
+ /* these are configuration parameters */
+ grub_int32_t fs_minfree; /* minimum percentage of free blocks */
+ grub_int32_t fs_rotdelay; /* num of ms for optimal next block */
+ grub_int32_t fs_rps; /* disk revolutions per second */
+ /* these fields can be computed from the others */
+ grub_int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
+ grub_int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
+ grub_int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
+ grub_int32_t fs_fshift; /* ``numfrags'' calc number of frags */
+ /* these are configuration parameters */
+ grub_int32_t fs_maxcontig; /* max number of contiguous blks */
+ grub_int32_t fs_maxbpg; /* max number of blks per cyl group */
+ /* these fields can be computed from the others */
+ grub_int32_t fs_fragshift; /* block to frag shift */
+ grub_int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ grub_int32_t fs_sbsize; /* actual size of super block */
+ grub_int32_t fs_csmask; /* csum block offset */
+ grub_int32_t fs_csshift; /* csum block number */
+ grub_int32_t fs_nindir; /* value of NINDIR */
+ grub_int32_t fs_inopb; /* value of INOPB */
+ grub_int32_t fs_nspf; /* value of NSPF */
+ /* yet another configuration parameter */
+ grub_int32_t fs_optim; /* optimization preference, see below */
+ /* these fields are derived from the hardware */
+ /* USL SVR4 compatibility */
+ /*
+ * * USL SVR4 compatibility
+ *
+ * There was a significant divergence here between Solaris and
+ * SVR4 for x86. By swapping these two members in the superblock,
+ * we get read-only compatibility of SVR4 filesystems. Otherwise
+ * there would be no compatibility. This change was introduced
+ * during bootstrapping of Solaris on x86. By making this ifdef'ed
+ * on byte order, we provide ongoing compatibility across all
+ * platforms with the same byte order, the highest compatibility
+ * that can be achieved.
+ */
+ grub_int32_t fs_state; /* file system state time stamp */
+ grub_int32_t fs_si; /* summary info state - lufs only */
+ grub_int32_t fs_trackskew; /* sector 0 skew, per track */
+ /* unique id for this filesystem (currently unused and unmaintained) */
+ /* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
+ /* Neither of those fields is used in the Tahoe code right now but */
+ /* there could be problems if they are. */
+ grub_int32_t fs_id[2]; /* file system id */
+ /* sizes determined by number of cylinder groups and their sizes */
+ grub_daddr32_t fs_csaddr; /* blk addr of cyl grp summary area */
+ grub_int32_t fs_cssize; /* size of cyl grp summary area */
+ grub_int32_t fs_cgsize; /* cylinder group size */
+ /* these fields are derived from the hardware */
+ grub_int32_t fs_ntrak; /* tracks per cylinder */
+ grub_int32_t fs_nsect; /* sectors per track */
+ grub_int32_t fs_spc; /* sectors per cylinder */
+ /* this comes from the disk driver partitioning */
+ grub_int32_t fs_ncyl; /* cylinders in file system */
+ /* these fields can be computed from the others */
+ grub_int32_t fs_cpg; /* cylinders per group */
+ grub_int32_t fs_ipg; /* inodes per group */
+ grub_int32_t fs_fpg; /* blocks per group * fs_frag */
+ /* this data must be re-computed after crashes */
+ struct csum fs_cstotal; /* cylinder summary information */
+ /* these fields are cleared at mount time */
+ char fs_fmod; /* super block modified flag */
+ char fs_clean; /* file system state flag */
+ char fs_ronly; /* mounted read-only flag */
+ char fs_flags; /* largefiles flag, etc. */
+ char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+ /* these fields retain the current block allocation info */
+ grub_int32_t fs_cgrotor; /* last cg searched */
+ /*
+ * The following used to be fs_csp[MAXCSBUFS]. It was not
+ * used anywhere except in old utilities. We removed this
+ * in 5.6 and expect fs_u.fs_csp to be used instead.
+ * We no longer limit fs_cssize based on MAXCSBUFS.
+ */
+ union { /* fs_cs (csum) info */
+ grub_uint32_t fs_csp_pad[MAXCSBUFS];
+ struct csum *fs_csp;
+ } fs_u;
+ grub_int32_t fs_cpc; /* cyl per cycle in postbl */
+ short fs_opostbl[16][8]; /* old rotation block list head */
+ grub_int32_t fs_sparecon[51]; /* reserved for future constants */
+ grub_int32_t fs_version; /* minor version of MTB ufs */
+ grub_int32_t fs_logbno; /* block # of embedded log */
+ grub_int32_t fs_reclaim; /* reclaim open, deleted files */
+ grub_int32_t fs_sparecon2; /* reserved for future constant */
+ /* USL SVR4 compatibility */
+ grub_int32_t fs_npsect; /* # sectors/track including spares */
+ grub_quad_t fs_qbmask; /* ~fs_bmask - for use with quad size */
+ grub_quad_t fs_qfmask; /* ~fs_fmask - for use with quad size */
+ grub_int32_t fs_postblformat; /* fmt of positional layout tables */
+ grub_int32_t fs_nrpos; /* number of rotaional positions */
+ grub_int32_t fs_postbloff; /* (short) rotation block list head */
+ grub_int32_t fs_rotbloff; /* (grub_uchar_t) blocks for each */
+ /* rotation */
+ grub_int32_t fs_magic; /* magic number */
+ grub_uchar_t fs_space[1]; /* list of blocks for each rotation */
+ /* actually longer */
+};
+
+struct icommon {
+ grub_o_mode_t ic_smode; /* 0: mode and type of file */
+ short ic_nlink; /* 2: number of links to file */
+ grub_o_uid_t ic_suid; /* 4: owner's user id */
+ grub_o_gid_t ic_sgid; /* 6: owner's group id */
+ grub_uint32_t ic_sizelo; /* 8: number of bytes in file */
+ grub_uint32_t ic_sizehi; /* 12: number of bytes in file */
+ struct timeval32 ic_atime; /* 16: time last accessed */
+ struct timeval32 ic_mtime; /* 24: time last modified */
+ struct timeval32 ic_ctime; /* 32: last time inode changed */
+ grub_daddr32_t ic_db[UFS_NDADDR]; /* 40: disk block addresses */
+ grub_daddr32_t ic_ib[UFS_NIADDR]; /* 88: indirect blocks */
+ grub_int32_t ic_flags; /* 100: cflags */
+ grub_int32_t ic_blocks; /* 104: 512 byte blocks actually held */
+ grub_int32_t ic_gen; /* 108: generation number */
+ grub_int32_t ic_shadow; /* 112: shadow inode */
+ grub_uid_t ic_uid; /* 116: long EFT version of uid */
+ grub_gid_t ic_gid; /* 120: long EFT version of gid */
+ grub_uint32_t ic_oeftflag; /* 124: extended attr directory ino, */
+ /* 0 = none */
+};
+
+struct direct {
+ grub_ino_t d_ino;
+ grub_ushort_t d_reclen;
+ grub_ushort_t d_namelen;
+ char d_name[MAXNAMELEN + 1];
+};
+
+/* inode macros */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define itoo(fs, x) ((x) % (grub_uint32_t)INOPB(fs))
+#define itog(fs, x) ((x) / (grub_uint32_t)(fs)->fs_ipg)
+#define itod(fs, x) ((grub_daddr32_t)(cgimin(fs, itog(fs, x)) + \
+ (blkstofrags((fs), \
+ ((x) % (grub_uint32_t)(fs)->fs_ipg / (grub_uint32_t)INOPB(fs))))))
+
+/* block conversion macros */
+#define UFS_NINDIR(fs) ((fs)->fs_nindir) /* # of indirects */
+#define blkoff(fs, loc) ((int)((loc & ~(fs)->fs_bmask)))
+#define lblkno(fs, loc) ((grub_int32_t)((loc) >> (fs)->fs_bshift))
+/* frag to blk */
+#define fsbtodb(fs, b) (((grub_daddr32_t)(b)) << (fs)->fs_fsbtodb)
+#define blkstofrags(fs, b) ((b) << (fs)->fs_fragshift)
+
+/* cynlinder group macros */
+#define cgbase(fs, c) ((grub_daddr32_t)((fs)->fs_fpg * (c)))
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode block */
+#define cgstart(fs, c) \
+ (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
+
+#endif /* !_GRUB_UFS_H */
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index caec7ec38a..129b867ff6 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -1,15 +1,9 @@
-
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-INSTALL_DIR = $(INSTALL) -d -m0755
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
MAJOR = 3.0
MINOR = 0
-XEN_ROOT = ../..
-include $(XEN_ROOT)/tools/Rules.mk
-
CTRL_SRCS-y :=
CTRL_SRCS-y += xc_core.c
CTRL_SRCS-y += xc_domain.c
@@ -21,8 +15,10 @@ CTRL_SRCS-y += xc_private.c
CTRL_SRCS-y += xc_sedf.c
CTRL_SRCS-y += xc_csched.c
CTRL_SRCS-y += xc_tbuf.c
-CTRL_SRCS-$(CONFIG_X86) += xc_ptrace.c xc_ptrace_core.c xc_pagetab.c
+CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c
CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c
+CTRL_SRCS-$(CONFIG_SunOS) += xc_solaris.c
+CTRL_SRCS-$(CONFIG_X86_Linux) += xc_ptrace.c xc_ptrace_core.c
GUEST_SRCS-y :=
GUEST_SRCS-y += xc_load_bin.c
@@ -35,7 +31,7 @@ GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c
-include $(XEN_TARGET_ARCH)/Makefile
-CFLAGS += -Werror
+CFLAGS += -Werror -Wmissing-prototypes
CFLAGS += -fno-strict-aliasing
CFLAGS += $(INCLUDES) -I.
@@ -123,7 +119,7 @@ libxenctrl.so.$(MAJOR): libxenctrl.so.$(MAJOR).$(MINOR)
ln -sf $< $@
libxenctrl.so.$(MAJOR).$(MINOR): $(CTRL_PIC_OBJS)
- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libxenctrl.so.$(MAJOR) -shared -o $@ $^
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^
# libxenguest
@@ -136,7 +132,7 @@ libxenguest.so.$(MAJOR): libxenguest.so.$(MAJOR).$(MINOR)
ln -sf $< $@
libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so
- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libxenguest.so.$(MAJOR) -shared -o $@ $^ -lz -lxenctrl
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz -lxenctrl
-include $(DEPS)
diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c
index 2c34b44a1d..a97b82af23 100644
--- a/tools/libxc/ia64/xc_ia64_hvm_build.c
+++ b/tools/libxc/ia64/xc_ia64_hvm_build.c
@@ -551,16 +551,31 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize,
char *image, unsigned long image_size, uint32_t vcpus,
unsigned int store_evtchn, unsigned long *store_mfn)
{
- unsigned long page_array[2];
+ unsigned long page_array[3];
shared_iopage_t *sp;
- unsigned long dom_memsize = (memsize << 20);
+ void *ioreq_buffer_page;
+ // memsize = required memsize(in configure file) + 16M
+ // dom_memsize will pass to xc_ia64_build_hob(), so must be subbed 16M
+ unsigned long dom_memsize = ((memsize - 16) << 20);
+ unsigned long nr_pages = (unsigned long)memsize << (20 - PAGE_SHIFT);
+ int rc;
DECLARE_DOMCTL;
+ // ROM size for guest firmware, ioreq page and xenstore page
+ nr_pages += 3;
+
if ((image_size > 12 * MEM_M) || (image_size & (PAGE_SIZE - 1))) {
PERROR("Guest firmware size is incorrect [%ld]?", image_size);
return -1;
}
+ rc = xc_domain_memory_increase_reservation(xc_handle, dom, nr_pages,
+ 0, 0, NULL);
+ if (rc != 0) {
+ PERROR("Could not allocate memory for HVM guest.\n");
+ goto error_out;
+ }
+
/* This will creates the physmap. */
domctl.u.arch_setup.flags = XEN_DOMAINSETUP_hvm_guest;
domctl.u.arch_setup.bp = 0;
@@ -587,7 +602,7 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize,
/* Retrieve special pages like io, xenstore, etc. */
if (xc_ia64_get_pfn_list(xc_handle, dom, page_array,
- IO_PAGE_START>>PAGE_SHIFT, 2) != 2) {
+ IO_PAGE_START>>PAGE_SHIFT, 3) != 3) {
PERROR("Could not get the page frame list");
goto error_out;
}
@@ -604,7 +619,10 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize,
memset(sp, 0, PAGE_SIZE);
munmap(sp, PAGE_SIZE);
-
+ ioreq_buffer_page = xc_map_foreign_range(xc_handle, dom,
+ PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[2]);
+ memset(ioreq_buffer_page,0,PAGE_SIZE);
+ munmap(ioreq_buffer_page, PAGE_SIZE);
return 0;
error_out:
@@ -614,7 +632,7 @@ error_out:
int
xc_hvm_build(int xc_handle, uint32_t domid, int memsize,
const char *image_name, unsigned int vcpus, unsigned int pae,
- unsigned int acpi, unsigned int apic, unsigned int store_evtchn,
+ unsigned int acpi, unsigned int store_evtchn,
unsigned long *store_mfn)
{
struct xen_domctl launch_domctl, domctl;
diff --git a/tools/libxc/ia64/xc_ia64_linux_restore.c b/tools/libxc/ia64/xc_ia64_linux_restore.c
index ef8476126b..e6aed35ead 100644
--- a/tools/libxc/ia64/xc_ia64_linux_restore.c
+++ b/tools/libxc/ia64/xc_ia64_linux_restore.c
@@ -44,11 +44,11 @@ read_page(int xc_handle, int io_fd, uint32_t dom, unsigned long pfn)
mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
PROT_READ|PROT_WRITE, pfn);
if (mem == NULL) {
- ERR("cannot map page");
+ ERROR("cannot map page");
return -1;
}
if (!read_exact(io_fd, mem, PAGE_SIZE)) {
- ERR("Error when reading from state file (5)");
+ ERROR("Error when reading from state file (5)");
return -1;
}
munmap(mem, PAGE_SIZE);
@@ -85,17 +85,17 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
if (!read_exact(io_fd, &ver, sizeof(unsigned long))) {
- ERR("Error when reading version");
+ ERROR("Error when reading version");
goto out;
}
if (ver != 1) {
- ERR("version of save doesn't match");
+ ERROR("version of save doesn't match");
goto out;
}
if (mlock(&ctxt, sizeof(ctxt))) {
/* needed for build domctl, but might as well do early */
- ERR("Unable to mlock ctxt");
+ ERROR("Unable to mlock ctxt");
return 1;
}
@@ -103,7 +103,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
domctl.cmd = XEN_DOMCTL_getdomaininfo;
domctl.domain = (domid_t)dom;
if (xc_domctl(xc_handle, &domctl) < 0) {
- ERR("Could not get information on new domain");
+ ERROR("Could not get information on new domain");
goto out;
}
shared_info_frame = domctl.u.getdomaininfo.shared_info_frame;
@@ -115,7 +115,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
if (xc_domain_memory_increase_reservation(xc_handle, dom, max_pfn,
0, 0, NULL) != 0) {
- ERR("Failed to increase reservation by %ld KB", PFN_TO_KB(max_pfn));
+ ERROR("Failed to increase reservation by %ld KB", PFN_TO_KB(max_pfn));
errno = ENOMEM;
goto out;
}
@@ -123,7 +123,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
DPRINTF("Increased domain reservation by %ld KB\n", PFN_TO_KB(max_pfn));
if (!read_exact(io_fd, &domctl.u.arch_setup, sizeof(domctl.u.arch_setup))) {
- ERR("read: domain setup");
+ ERROR("read: domain setup");
goto out;
}
@@ -141,13 +141,13 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
/* Get pages. */
page_array = malloc(max_pfn * sizeof(unsigned long));
if (page_array == NULL ) {
- ERR("Could not allocate memory");
+ ERROR("Could not allocate memory");
goto out;
}
if (xc_ia64_get_pfn_list(xc_handle, dom, page_array,
0, max_pfn) != max_pfn) {
- ERR("Could not get the page frame list");
+ ERROR("Could not get the page frame list");
goto out;
}
@@ -155,7 +155,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
while (1) {
if (!read_exact(io_fd, &mfn, sizeof(unsigned long))) {
- ERR("Error when reading batch size");
+ ERROR("Error when reading batch size");
goto out;
}
if (mfn == INVALID_MFN)
@@ -178,18 +178,18 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
int rc;
if (!read_exact(io_fd, &count, sizeof(count))) {
- ERR("Error when reading pfn count");
+ ERROR("Error when reading pfn count");
goto out;
}
pfntab = malloc(sizeof(unsigned long) * count);
if (!pfntab) {
- ERR("Out of memory");
+ ERROR("Out of memory");
goto out;
}
if (!read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) {
- ERR("Error when reading pfntab");
+ ERROR("Error when reading pfntab");
goto out;
}
@@ -211,7 +211,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
rc = xc_memory_op(xc_handle, XENMEM_decrease_reservation,
&reservation);
if (rc != 1) {
- ERR("Could not decrease reservation : %d", rc);
+ ERROR("Could not decrease reservation : %d", rc);
goto out;
}
}
@@ -221,17 +221,20 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
- ERR("Error when reading ctxt");
+ ERROR("Error when reading ctxt");
goto out;
}
+ fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt.user_regs.cr_iip,
+ ctxt.user_regs.b0);
+
/* First to initialize. */
domctl.cmd = XEN_DOMCTL_setvcpucontext;
domctl.domain = (domid_t)dom;
domctl.u.vcpucontext.vcpu = 0;
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
if (xc_domctl(xc_handle, &domctl) != 0) {
- ERR("Couldn't set vcpu context");
+ ERROR("Couldn't set vcpu context");
goto out;
}
@@ -242,19 +245,19 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
domctl.u.vcpucontext.vcpu = 0;
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
if (xc_domctl(xc_handle, &domctl) != 0) {
- ERR("Couldn't set vcpu context");
+ ERROR("Couldn't set vcpu context");
goto out;
}
/* Just a check. */
if (xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, &ctxt)) {
- ERR("Could not get vcpu context");
+ ERROR("Could not get vcpu context");
goto out;
}
/* Then get privreg page. */
if (read_page(xc_handle, io_fd, dom, ctxt.privregs_pfn) < 0) {
- ERR("Could not read vcpu privregs");
+ ERROR("Could not read vcpu privregs");
goto out;
}
@@ -262,11 +265,11 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
shared_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
PROT_READ|PROT_WRITE, shared_info_frame);
if (shared_info == NULL) {
- ERR("cannot map page");
+ ERROR("cannot map page");
goto out;
}
if (!read_exact(io_fd, shared_info, PAGE_SIZE)) {
- ERR("Error when reading shared_info page");
+ ERROR("Error when reading shared_info page");
goto out;
}
diff --git a/tools/libxc/ia64/xc_ia64_linux_save.c b/tools/libxc/ia64/xc_ia64_linux_save.c
index 0e10662935..42ec21c802 100644
--- a/tools/libxc/ia64/xc_ia64_linux_save.c
+++ b/tools/libxc/ia64/xc_ia64_linux_save.c
@@ -97,14 +97,14 @@ suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
int i = 0;
if (!(*suspend)(dom)) {
- ERR("Suspend request failed");
+ ERROR("Suspend request failed");
return -1;
}
retry:
if (xc_domain_getinfo(xc_handle, dom, 1, info) != 1) {
- ERR("Could not get domain info");
+ ERROR("Could not get domain info");
return -1;
}
@@ -115,7 +115,7 @@ retry:
// try unpausing domain, wait, and retest
xc_domain_unpause(xc_handle, dom);
- ERR("Domain was paused. Wait and re-test.");
+ ERROR("Domain was paused. Wait and re-test.");
usleep(10000); // 10ms
goto retry;
@@ -123,12 +123,12 @@ retry:
if(++i < 100) {
- ERR("Retry suspend domain.");
+ ERROR("Retry suspend domain.");
usleep(10000); // 10ms
goto retry;
}
- ERR("Unable to suspend domain.");
+ ERROR("Unable to suspend domain.");
return -1;
}
@@ -191,7 +191,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
//initialize_mbit_rate();
if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) {
- ERR("Could not get domain info");
+ ERROR("Could not get domain info");
return 1;
}
@@ -200,7 +200,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
#if 0
/* cheesy sanity check */
if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) {
- ERR("Invalid state record -- pfn count out of range: %lu",
+ ERROR("Invalid state record -- pfn count out of range: %lu",
(info.max_memkb >> (PAGE_SHIFT - 10)));
goto out;
}
@@ -210,7 +210,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
PROT_READ, shared_info_frame);
if (!live_shinfo) {
- ERR("Couldn't map live_shinfo");
+ ERROR("Couldn't map live_shinfo");
goto out;
}
@@ -218,13 +218,13 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
page_array = malloc(max_pfn * sizeof(unsigned long));
if (page_array == NULL) {
- ERR("Could not allocate memory");
+ ERROR("Could not allocate memory");
goto out;
}
/* This is expected by xm restore. */
if (!write_exact(io_fd, &max_pfn, sizeof(unsigned long))) {
- ERR("write: max_pfn");
+ ERROR("write: max_pfn");
goto out;
}
@@ -237,7 +237,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
unsigned long version = 1;
if (!write_exact(io_fd, &version, sizeof(unsigned long))) {
- ERR("write: version");
+ ERROR("write: version");
goto out;
}
}
@@ -246,12 +246,12 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
domctl.domain = (domid_t)dom;
domctl.u.arch_setup.flags = XEN_DOMAINSETUP_query;
if (xc_domctl(xc_handle, &domctl) < 0) {
- ERR("Could not get domain setup");
+ ERROR("Could not get domain setup");
goto out;
}
if (!write_exact(io_fd, &domctl.u.arch_setup,
sizeof(domctl.u.arch_setup))) {
- ERR("write: domain setup");
+ ERROR("write: domain setup");
goto out;
}
@@ -261,7 +261,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (xc_ia64_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
NULL, 0, NULL ) < 0) {
- ERR("Couldn't enable shadow mode");
+ ERROR("Couldn't enable shadow mode");
goto out;
}
@@ -272,7 +272,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
to_skip = malloc(bitmap_size);
if (!to_send || !to_skip) {
- ERR("Couldn't allocate bitmap array");
+ ERROR("Couldn't allocate bitmap array");
goto out;
}
@@ -280,11 +280,11 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
memset(to_send, 0xff, bitmap_size);
if (mlock(to_send, bitmap_size)) {
- ERR("Unable to mlock to_send");
+ ERROR("Unable to mlock to_send");
goto out;
}
if (mlock(to_skip, bitmap_size)) {
- ERR("Unable to mlock to_skip");
+ ERROR("Unable to mlock to_skip");
goto out;
}
@@ -296,7 +296,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
last_iter = 1;
if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info)) {
- ERR("Domain appears not to have suspended");
+ ERROR("Domain appears not to have suspended");
goto out;
}
@@ -315,7 +315,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Get the pfn list, as it may change. */
if (xc_ia64_get_pfn_list(xc_handle, dom, page_array,
0, max_pfn) != max_pfn) {
- ERR("Could not get the page frame list");
+ ERROR("Could not get the page frame list");
goto out;
}
@@ -326,7 +326,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (xc_ia64_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_PEEK,
to_skip, max_pfn, NULL) != max_pfn) {
- ERR("Error peeking shadow bitmap");
+ ERROR("Error peeking shadow bitmap");
goto out;
}
}
@@ -358,12 +358,12 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
if (!write_exact(io_fd, &N, sizeof(N))) {
- ERR("write: max_pfn");
+ ERROR("write: max_pfn");
goto out;
}
if (write(io_fd, mem, PAGE_SIZE) != PAGE_SIZE) {
- ERR("Error when writing to state file (5)");
+ ERROR("Error when writing to state file (5)");
goto out;
}
munmap(mem, PAGE_SIZE);
@@ -385,7 +385,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
last_iter = 1;
if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info)) {
- ERR("Domain appears not to have suspended");
+ ERROR("Domain appears not to have suspended");
goto out;
}
}
@@ -394,7 +394,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (xc_ia64_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_CLEAN,
to_send, max_pfn, NULL ) != max_pfn) {
- ERR("Error flushing shadow PT");
+ ERROR("Error flushing shadow PT");
goto out;
}
@@ -411,7 +411,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
{
unsigned long pfn = INVALID_MFN;
if (!write_exact(io_fd, &pfn, sizeof(pfn))) {
- ERR("Error when writing to state file (6)");
+ ERROR("Error when writing to state file (6)");
goto out;
}
}
@@ -427,7 +427,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
if (!write_exact(io_fd, &j, sizeof(unsigned int))) {
- ERR("Error when writing to state file (6a)");
+ ERROR("Error when writing to state file (6a)");
goto out;
}
@@ -439,7 +439,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
i++;
if (j == 1024 || i == max_pfn) {
if (!write_exact(io_fd, &pfntab, sizeof(unsigned long)*j)) {
- ERR("Error when writing to state file (6b)");
+ ERROR("Error when writing to state file (6b)");
goto out;
}
j = 0;
@@ -449,29 +449,32 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) {
- ERR("Could not get vcpu context");
+ ERROR("Could not get vcpu context");
goto out;
}
if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
- ERR("Error when writing to state file (1)");
+ ERROR("Error when writing to state file (1)");
goto out;
}
+ fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt.user_regs.cr_iip,
+ ctxt.user_regs.b0);
+
mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
PROT_READ|PROT_WRITE, ctxt.privregs_pfn);
if (mem == NULL) {
- ERR("cannot map privreg page");
+ ERROR("cannot map privreg page");
goto out;
}
if (write(io_fd, mem, PAGE_SIZE) != PAGE_SIZE) {
- ERR("Error when writing privreg to state file (5)");
+ ERROR("Error when writing privreg to state file (5)");
goto out;
}
munmap(mem, PAGE_SIZE);
if (!write_exact(io_fd, live_shinfo, PAGE_SIZE)) {
- ERR("Error when writing to state file (1)");
+ ERROR("Error when writing to state file (1)");
goto out;
}
diff --git a/tools/libxc/xc_acm.c b/tools/libxc/xc_acm.c
index f8c5482081..abe35712ed 100644
--- a/tools/libxc/xc_acm.c
+++ b/tools/libxc/xc_acm.c
@@ -14,8 +14,7 @@
#include "xc_private.h"
-
-int xc_acm_op(int xc_handle, int cmd, void *arg, size_t arg_size)
+int xc_acm_op(int xc_handle, int cmd, void *arg, unsigned long arg_size)
{
int ret = -1;
DECLARE_HYPERCALL;
@@ -24,12 +23,12 @@ int xc_acm_op(int xc_handle, int cmd, void *arg, size_t arg_size)
hypercall.arg[0] = cmd;
hypercall.arg[1] = (unsigned long) arg;
- if (mlock(arg, arg_size) != 0) {
- PERROR("xc_acm_op: arg mlock failed");
+ if (lock_pages(arg, arg_size) != 0) {
+ PERROR("xc_acm_op: arg lock failed");
goto out;
}
ret = do_xen_hypercall(xc_handle, &hypercall);
- safe_munlock(arg, arg_size);
+ unlock_pages(arg, arg_size);
out:
return ret;
}
diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c
index efaf397abf..550d5691e1 100644
--- a/tools/libxc/xc_core.c
+++ b/tools/libxc/xc_core.c
@@ -62,7 +62,7 @@ xc_domain_dumpcore_via_callback(int xc_handle,
nr_pages = info.nr_pages;
- header.xch_magic = XC_CORE_MAGIC;
+ header.xch_magic = info.hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC;
header.xch_nr_vcpus = nr_vcpus;
header.xch_nr_pages = nr_pages;
header.xch_ctxt_offset = sizeof(struct xc_core_header);
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 20b0c764c3..b63e172a22 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -12,6 +12,7 @@
int xc_domain_create(int xc_handle,
uint32_t ssidref,
xen_domain_handle_t handle,
+ uint32_t flags,
uint32_t *pdomid)
{
int err;
@@ -20,6 +21,7 @@ int xc_domain_create(int xc_handle,
domctl.cmd = XEN_DOMCTL_createdomain;
domctl.domain = (domid_t)*pdomid;
domctl.u.createdomain.ssidref = ssidref;
+ domctl.u.createdomain.flags = flags;
memcpy(domctl.u.createdomain.handle, handle, sizeof(xen_domain_handle_t));
if ( (err = do_domctl(xc_handle, &domctl)) != 0 )
return err;
@@ -72,7 +74,7 @@ int xc_domain_shutdown(int xc_handle,
arg.domain_id = domid;
arg.reason = reason;
- if ( mlock(&arg, sizeof(arg)) != 0 )
+ if ( lock_pages(&arg, sizeof(arg)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out1;
@@ -80,7 +82,7 @@ int xc_domain_shutdown(int xc_handle,
ret = do_xen_hypercall(xc_handle, &hypercall);
- safe_munlock(&arg, sizeof(arg));
+ unlock_pages(&arg, sizeof(arg));
out1:
return ret;
@@ -103,7 +105,7 @@ int xc_vcpu_setaffinity(int xc_handle,
(uint8_t *)&cpumap);
domctl.u.vcpuaffinity.cpumap.nr_cpus = sizeof(cpumap) * 8;
- if ( mlock(&cpumap, sizeof(cpumap)) != 0 )
+ if ( lock_pages(&cpumap, sizeof(cpumap)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out;
@@ -111,7 +113,7 @@ int xc_vcpu_setaffinity(int xc_handle,
ret = do_domctl(xc_handle, &domctl);
- safe_munlock(&cpumap, sizeof(cpumap));
+ unlock_pages(&cpumap, sizeof(cpumap));
out:
return ret;
@@ -134,7 +136,7 @@ int xc_vcpu_getaffinity(int xc_handle,
(uint8_t *)cpumap);
domctl.u.vcpuaffinity.cpumap.nr_cpus = sizeof(*cpumap) * 8;
- if ( mlock(cpumap, sizeof(*cpumap)) != 0 )
+ if ( lock_pages(cpumap, sizeof(*cpumap)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out;
@@ -142,7 +144,7 @@ int xc_vcpu_getaffinity(int xc_handle,
ret = do_domctl(xc_handle, &domctl);
- safe_munlock(cpumap, sizeof(*cpumap));
+ unlock_pages(cpumap, sizeof(*cpumap));
out:
return ret;
@@ -169,15 +171,16 @@ int xc_domain_getinfo(int xc_handle,
break;
info->domid = (uint16_t)domctl.domain;
- info->dying = !!(domctl.u.getdomaininfo.flags & DOMFLAGS_DYING);
- info->shutdown = !!(domctl.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN);
- info->paused = !!(domctl.u.getdomaininfo.flags & DOMFLAGS_PAUSED);
- info->blocked = !!(domctl.u.getdomaininfo.flags & DOMFLAGS_BLOCKED);
- info->running = !!(domctl.u.getdomaininfo.flags & DOMFLAGS_RUNNING);
+ info->dying = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_dying);
+ info->shutdown = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_shutdown);
+ info->paused = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_paused);
+ info->blocked = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_blocked);
+ info->running = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_running);
+ info->hvm = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hvm_guest);
info->shutdown_reason =
- (domctl.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) &
- DOMFLAGS_SHUTDOWNMASK;
+ (domctl.u.getdomaininfo.flags>>XEN_DOMINF_shutdownshift) &
+ XEN_DOMINF_shutdownmask;
if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) )
{
@@ -200,7 +203,8 @@ int xc_domain_getinfo(int xc_handle,
info++;
}
- if( !nr_doms ) return rc;
+ if ( nr_doms == 0 )
+ return rc;
return nr_doms;
}
@@ -213,7 +217,7 @@ int xc_domain_getinfolist(int xc_handle,
int ret = 0;
DECLARE_SYSCTL;
- if ( mlock(info, max_domains*sizeof(xc_domaininfo_t)) != 0 )
+ if ( lock_pages(info, max_domains*sizeof(xc_domaininfo_t)) != 0 )
return -1;
sysctl.cmd = XEN_SYSCTL_getdomaininfolist;
@@ -226,8 +230,7 @@ int xc_domain_getinfolist(int xc_handle,
else
ret = sysctl.u.getdomaininfolist.num_domains;
- if ( munlock(info, max_domains*sizeof(xc_domaininfo_t)) != 0 )
- ret = -1;
+ unlock_pages(info, max_domains*sizeof(xc_domaininfo_t));
return ret;
}
@@ -245,12 +248,12 @@ int xc_vcpu_getcontext(int xc_handle,
domctl.u.vcpucontext.vcpu = (uint16_t)vcpu;
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
- if ( (rc = mlock(ctxt, sizeof(*ctxt))) != 0 )
+ if ( (rc = lock_pages(ctxt, sizeof(*ctxt))) != 0 )
return rc;
rc = do_domctl(xc_handle, &domctl);
- safe_munlock(ctxt, sizeof(*ctxt));
+ unlock_pages(ctxt, sizeof(*ctxt));
return rc;
}
@@ -346,10 +349,10 @@ int xc_domain_memory_increase_reservation(int xc_handle,
if ( err == nr_extents )
return 0;
- if ( err > 0 )
+ if ( err >= 0 )
{
DPRINTF("Failed allocation for dom %d: "
- "%ld pages order %d addr_bits %d\n",
+ "%ld extents of order %d, addr_bits %d\n",
domid, nr_extents, extent_order, address_bits);
errno = ENOMEM;
err = -1;
@@ -385,11 +388,11 @@ int xc_domain_memory_decrease_reservation(int xc_handle,
if ( err == nr_extents )
return 0;
- if ( err > 0 )
+ if ( err >= 0 )
{
- DPRINTF("Failed deallocation for dom %d: %ld pages order %d\n",
+ DPRINTF("Failed deallocation for dom %d: %ld extents of order %d\n",
domid, nr_extents, extent_order);
- errno = EBUSY;
+ errno = EINVAL;
err = -1;
}
@@ -416,9 +419,9 @@ int xc_domain_memory_populate_physmap(int xc_handle,
if ( err == nr_extents )
return 0;
- if ( err > 0 )
+ if ( err >= 0 )
{
- DPRINTF("Failed allocation for dom %d: %ld pages order %d\n",
+ DPRINTF("Failed allocation for dom %d: %ld extents of order %d\n",
domid, nr_extents, extent_order);
errno = EBUSY;
err = -1;
@@ -427,22 +430,6 @@ int xc_domain_memory_populate_physmap(int xc_handle,
return err;
}
-int xc_domain_translate_gpfn_list(int xc_handle,
- uint32_t domid,
- unsigned long nr_gpfns,
- xen_pfn_t *gpfn_list,
- xen_pfn_t *mfn_list)
-{
- struct xen_translate_gpfn_list op = {
- .domid = domid,
- .nr_gpfns = nr_gpfns,
- };
- set_xen_guest_handle(op.gpfn_list, gpfn_list);
- set_xen_guest_handle(op.mfn_list, mfn_list);
-
- return xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &op);
-}
-
int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max)
{
DECLARE_DOMCTL;
@@ -512,12 +499,12 @@ int xc_vcpu_setcontext(int xc_handle,
domctl.u.vcpucontext.vcpu = vcpu;
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
- if ( (rc = mlock(ctxt, sizeof(*ctxt))) != 0 )
+ if ( (rc = lock_pages(ctxt, sizeof(*ctxt))) != 0 )
return rc;
rc = do_domctl(xc_handle, &domctl);
- safe_munlock(ctxt, sizeof(*ctxt));
+ unlock_pages(ctxt, sizeof(*ctxt));
return rc;
diff --git a/tools/libxc/xc_evtchn.c b/tools/libxc/xc_evtchn.c
index 8192a73c4b..8c795bce7a 100644
--- a/tools/libxc/xc_evtchn.c
+++ b/tools/libxc/xc_evtchn.c
@@ -18,16 +18,16 @@ static int do_evtchn_op(int xc_handle, int cmd, void *arg, size_t arg_size)
hypercall.arg[0] = cmd;
hypercall.arg[1] = (unsigned long)arg;
- if ( mlock(arg, arg_size) != 0 )
+ if ( lock_pages(arg, arg_size) != 0 )
{
- PERROR("do_evtchn_op: arg mlock failed");
+ PERROR("do_evtchn_op: arg lock failed");
goto out;
}
if ((ret = do_xen_hypercall(xc_handle, &hypercall)) < 0)
ERROR("do_evtchn_op: HYPERVISOR_event_channel_op failed: %d", ret);
- safe_munlock(arg, arg_size);
+ unlock_pages(arg, arg_size);
out:
return ret;
}
diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c
index dce154d7b7..1c038755cd 100644
--- a/tools/libxc/xc_hvm_build.c
+++ b/tools/libxc/xc_hvm_build.c
@@ -12,12 +12,12 @@
#include <unistd.h>
#include <zlib.h>
#include <xen/hvm/hvm_info_table.h>
-#include <xen/hvm/ioreq.h>
#include <xen/hvm/params.h>
#include <xen/hvm/e820.h>
-#define HVM_LOADER_ENTR_ADDR 0x00100000
+#define SCRATCH_PFN 0xFFFFF
+#define HVM_LOADER_ENTR_ADDR 0x00100000
static int
parseelfimage(
char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
@@ -26,8 +26,8 @@ loadelfimage(
char *elfbase, int xch, uint32_t dom, unsigned long *parray,
struct domain_setup_info *dsi);
-static void xc_set_hvm_param(int handle,
- domid_t dom, int param, unsigned long value)
+int xc_set_hvm_param(
+ int handle, domid_t dom, int param, unsigned long value)
{
DECLARE_HYPERCALL;
xen_hvm_param_t arg;
@@ -39,15 +39,31 @@ static void xc_set_hvm_param(int handle,
arg.domid = dom;
arg.index = param;
arg.value = value;
- if ( mlock(&arg, sizeof(arg)) != 0 )
- {
- PERROR("Could not lock memory for set parameter");
- return;
- }
+ if ( lock_pages(&arg, sizeof(arg)) != 0 )
+ return -1;
+ rc = do_xen_hypercall(handle, &hypercall);
+ unlock_pages(&arg, sizeof(arg));
+ return rc;
+}
+
+int xc_get_hvm_param(
+ int handle, domid_t dom, int param, unsigned long *value)
+{
+ DECLARE_HYPERCALL;
+ xen_hvm_param_t arg;
+ int rc;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_get_param;
+ hypercall.arg[1] = (unsigned long)&arg;
+ arg.domid = dom;
+ arg.index = param;
+ if ( lock_pages(&arg, sizeof(arg)) != 0 )
+ return -1;
rc = do_xen_hypercall(handle, &hypercall);
- safe_munlock(&arg, sizeof(arg));
- if (rc < 0)
- PERROR("set HVM parameter failed (%d)", rc);
+ unlock_pages(&arg, sizeof(arg));
+ *value = arg.value;
+ return rc;
}
static void build_e820map(void *e820_page, unsigned long long mem_size)
@@ -58,110 +74,67 @@ static void build_e820map(void *e820_page, unsigned long long mem_size)
unsigned char nr_map = 0;
/*
- * physical address space from HVM_BELOW_4G_RAM_END to 4G is reserved
+ * Physical address space from HVM_BELOW_4G_RAM_END to 4G is reserved
* for PCI devices MMIO. So if HVM has more than HVM_BELOW_4G_RAM_END
* RAM, memory beyond HVM_BELOW_4G_RAM_END will go to 4G above.
*/
- if ( mem_size > HVM_BELOW_4G_RAM_END ) {
+ if ( mem_size > HVM_BELOW_4G_RAM_END )
+ {
extra_mem_size = mem_size - HVM_BELOW_4G_RAM_END;
mem_size = HVM_BELOW_4G_RAM_END;
}
+ /* 0x0-0x9F000: Ordinary RAM. */
e820entry[nr_map].addr = 0x0;
e820entry[nr_map].size = 0x9F000;
e820entry[nr_map].type = E820_RAM;
nr_map++;
+ /*
+ * 0x9F000-0x9F800: SMBIOS tables.
+ * 0x9FC00-0xA0000: Extended BIOS Data Area (EBDA).
+ * TODO: SMBIOS tables should be moved higher (>=0xE0000).
+ * They are unusually low in our memory map: could cause problems?
+ */
e820entry[nr_map].addr = 0x9F000;
e820entry[nr_map].size = 0x1000;
e820entry[nr_map].type = E820_RESERVED;
nr_map++;
- e820entry[nr_map].addr = 0xA0000;
- e820entry[nr_map].size = 0x20000;
- e820entry[nr_map].type = E820_IO;
- nr_map++;
+ /*
+ * Following regions are standard regions of the PC memory map.
+ * They are not covered by e820 regions. OSes will not use as RAM.
+ * 0xA0000-0xC0000: VGA memory-mapped I/O. Not covered by E820.
+ * 0xC0000-0xE0000: 16-bit devices, expansion ROMs (inc. vgabios).
+ * TODO: hvmloader should free pages which turn out to be unused.
+ */
- e820entry[nr_map].addr = 0xF0000;
- e820entry[nr_map].size = 0x10000;
+ /*
+ * 0xE0000-0x0F0000: PC-specific area. We place ACPI tables here.
+ * We *cannot* mark as E820_ACPI, for two reasons:
+ * 1. ACPI spec. says that E820_ACPI regions below
+ * 16MB must clip INT15h 0x88 and 0xe801 queries.
+ * Our rombios doesn't do this.
+ * 2. The OS is allowed to reclaim ACPI memory after
+ * parsing the tables. But our FACS is in this
+ * region and it must not be reclaimed (it contains
+ * the ACPI global lock!).
+ * 0xF0000-0x100000: System BIOS.
+ * TODO: hvmloader should free pages which turn out to be unused.
+ */
+ e820entry[nr_map].addr = 0xE0000;
+ e820entry[nr_map].size = 0x20000;
e820entry[nr_map].type = E820_RESERVED;
nr_map++;
-/* ACPI data: 10 pages. */
-#define ACPI_DATA_PAGES 10
-/* ACPI NVS: 3 pages. */
-#define ACPI_NVS_PAGES 3
-/* buffered io page. */
-#define BUFFERED_IO_PAGES 1
-/* xenstore page. */
-#define XENSTORE_PAGES 1
-/* shared io page. */
-#define SHARED_IO_PAGES 1
-/* totally 16 static pages are reserved in E820 table */
-
- /* Most of the ram goes here */
+ /* Low RAM goes here. Remove 3 pages for ioreq, bufioreq, and xenstore. */
e820entry[nr_map].addr = 0x100000;
- e820entry[nr_map].size = mem_size - 0x100000 - PAGE_SIZE *
- (ACPI_DATA_PAGES +
- ACPI_NVS_PAGES +
- BUFFERED_IO_PAGES +
- XENSTORE_PAGES +
- SHARED_IO_PAGES);
+ e820entry[nr_map].size = mem_size - 0x100000 - PAGE_SIZE * 3;
e820entry[nr_map].type = E820_RAM;
nr_map++;
- /* Statically allocated special pages */
-
- /* For ACPI data */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE *
- (ACPI_DATA_PAGES +
- ACPI_NVS_PAGES +
- BUFFERED_IO_PAGES +
- XENSTORE_PAGES +
- SHARED_IO_PAGES);
- e820entry[nr_map].size = PAGE_SIZE * ACPI_DATA_PAGES;
- e820entry[nr_map].type = E820_ACPI;
- nr_map++;
-
- /* For ACPI NVS */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE *
- (ACPI_NVS_PAGES +
- BUFFERED_IO_PAGES +
- XENSTORE_PAGES +
- SHARED_IO_PAGES);
- e820entry[nr_map].size = PAGE_SIZE * ACPI_NVS_PAGES;
- e820entry[nr_map].type = E820_NVS;
- nr_map++;
-
- /* For buffered IO requests */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE *
- (BUFFERED_IO_PAGES +
- XENSTORE_PAGES +
- SHARED_IO_PAGES);
- e820entry[nr_map].size = PAGE_SIZE * BUFFERED_IO_PAGES;
- e820entry[nr_map].type = E820_BUFFERED_IO;
- nr_map++;
-
- /* For xenstore */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE *
- (XENSTORE_PAGES +
- SHARED_IO_PAGES);
- e820entry[nr_map].size = PAGE_SIZE * XENSTORE_PAGES;
- e820entry[nr_map].type = E820_XENSTORE;
- nr_map++;
-
- /* Shared ioreq_t page */
- e820entry[nr_map].addr = mem_size - PAGE_SIZE * SHARED_IO_PAGES;
- e820entry[nr_map].size = PAGE_SIZE * SHARED_IO_PAGES;
- e820entry[nr_map].type = E820_SHARED_PAGE;
- nr_map++;
-
- e820entry[nr_map].addr = 0xFEC00000;
- e820entry[nr_map].size = 0x1400000;
- e820entry[nr_map].type = E820_IO;
- nr_map++;
-
- if ( extra_mem_size ) {
+ if ( extra_mem_size )
+ {
e820entry[nr_map].addr = (1ULL << 32);
e820entry[nr_map].size = extra_mem_size;
e820entry[nr_map].type = E820_RAM;
@@ -171,77 +144,20 @@ static void build_e820map(void *e820_page, unsigned long long mem_size)
*(((unsigned char *)e820_page) + E820_MAP_NR_OFFSET) = nr_map;
}
-static void set_hvm_info_checksum(struct hvm_info_table *t)
-{
- uint8_t *ptr = (uint8_t *)t, sum = 0;
- unsigned int i;
-
- t->checksum = 0;
-
- for (i = 0; i < t->length; i++)
- sum += *ptr++;
-
- t->checksum = -sum;
-}
-
-/*
- * Use E820 reserved memory 0x9F800 to pass HVM info to hvmloader
- * hvmloader will use this info to set BIOS accordingly
- */
-static int set_hvm_info(int xc_handle, uint32_t dom,
- xen_pfn_t *pfn_list, unsigned int vcpus,
- unsigned int acpi)
-{
- char *va_map;
- struct hvm_info_table *va_hvm;
-
- va_map = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
- PROT_READ | PROT_WRITE,
- pfn_list[HVM_INFO_PFN]);
-
- if ( va_map == NULL )
- return -1;
-
- va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
- memset(va_hvm, 0, sizeof(*va_hvm));
-
- strncpy(va_hvm->signature, "HVM INFO", 8);
- va_hvm->length = sizeof(struct hvm_info_table);
- va_hvm->acpi_enabled = acpi;
- va_hvm->nr_vcpus = vcpus;
-
- set_hvm_info_checksum(va_hvm);
-
- munmap(va_map, PAGE_SIZE);
-
- return 0;
-}
-
static int setup_guest(int xc_handle,
uint32_t dom, int memsize,
char *image, unsigned long image_size,
- unsigned long nr_pages,
- vcpu_guest_context_t *ctxt,
- unsigned long shared_info_frame,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn)
+ vcpu_guest_context_t *ctxt)
{
xen_pfn_t *page_array = NULL;
- unsigned long count, i;
- unsigned long long ptr;
- xc_mmu_t *mmu = NULL;
-
- shared_info_t *shared_info;
+ unsigned long i, nr_pages = (unsigned long)memsize << (20 - PAGE_SHIFT);
+ unsigned long shared_page_nr;
+ struct xen_add_to_physmap xatp;
+ struct shared_info *shared_info;
void *e820_page;
-
struct domain_setup_info dsi;
uint64_t v_end;
-
- unsigned long shared_page_nr;
+ int rc;
memset(&dsi, 0, sizeof(struct domain_setup_info));
@@ -254,7 +170,6 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- /* memsize is in megabytes */
v_end = (unsigned long long)memsize << 20;
IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
@@ -279,66 +194,49 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
+ for ( i = 0; i < nr_pages; i++ )
+ page_array[i] = i;
+ for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < nr_pages; i++ )
+ page_array[i] += HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT;
+
+ /* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */
+ rc = xc_domain_memory_populate_physmap(
+ xc_handle, dom, (nr_pages > 0xa0) ? 0xa0 : nr_pages,
+ 0, 0, &page_array[0x00]);
+ if ( (rc == 0) && (nr_pages > 0xc0) )
+ rc = xc_domain_memory_populate_physmap(
+ xc_handle, dom, nr_pages - 0xc0, 0, 0, &page_array[0xc0]);
+ if ( rc != 0 )
{
- PERROR("Could not get the page frame list.\n");
+ PERROR("Could not allocate memory for HVM guest.\n");
goto error_out;
}
loadelfimage(image, xc_handle, dom, page_array, &dsi);
- if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL )
- goto error_out;
-
- /* Write the machine->phys table entries. */
- for ( count = 0; count < nr_pages; count++ )
- {
- unsigned long gpfn_count_skip;
-
- ptr = (unsigned long long)page_array[count] << PAGE_SHIFT;
-
- gpfn_count_skip = 0;
-
- /*
- * physical address space from HVM_BELOW_4G_RAM_END to 4G is reserved
- * for PCI devices MMIO. So if HVM has more than HVM_BELOW_4G_RAM_END
- * RAM, memory beyond HVM_BELOW_4G_RAM_END will go to 4G above.
- */
- if ( count >= (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT) )
- gpfn_count_skip = HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT;
-
- if ( xc_add_mmu_update(xc_handle, mmu,
- ptr | MMU_MACHPHYS_UPDATE,
- count + gpfn_count_skip) )
- goto error_out;
- }
-
- if ( set_hvm_info(xc_handle, dom, page_array, vcpus, acpi) )
- {
- ERROR("Couldn't set hvm info for HVM guest.\n");
- goto error_out;
- }
-
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae);
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_APIC_ENABLED, apic);
-
if ( (e820_page = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- page_array[E820_MAP_PAGE >> PAGE_SHIFT])) == NULL )
+ E820_MAP_PAGE >> PAGE_SHIFT)) == NULL )
goto error_out;
memset(e820_page, 0, PAGE_SIZE);
build_e820map(e820_page, v_end);
munmap(e820_page, PAGE_SIZE);
- /* shared_info page starts its life empty. */
- if ( (shared_info = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- shared_info_frame)) == NULL )
+ /* Map and initialise shared_info page. */
+ xatp.domid = dom;
+ xatp.space = XENMAPSPACE_shared_info;
+ xatp.idx = 0;
+ xatp.gpfn = SCRATCH_PFN;
+ if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) ||
+ ((shared_info = xc_map_foreign_range(
+ xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
+ SCRATCH_PFN)) == NULL) )
goto error_out;
memset(shared_info, 0, PAGE_SIZE);
- /* Mask all upcalls... */
for ( i = 0; i < MAX_VIRT_CPUS; i++ )
shared_info->vcpu_info[i].evtchn_upcall_mask = 1;
+ memset(&shared_info->evtchn_mask[0], 0xff,
+ sizeof(shared_info->evtchn_mask));
munmap(shared_info, PAGE_SIZE);
if ( v_end > HVM_BELOW_4G_RAM_END )
@@ -346,39 +244,23 @@ static int setup_guest(int xc_handle,
else
shared_page_nr = (v_end >> PAGE_SHIFT) - 1;
- *store_mfn = page_array[shared_page_nr - 1];
-
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, shared_page_nr - 1);
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn);
-
- /* Paranoia */
- /* clean the shared IO requests page */
- if ( xc_clear_domain_page(xc_handle, dom, page_array[shared_page_nr]) )
- goto error_out;
-
- /* clean the buffered IO requests page */
- if ( xc_clear_domain_page(xc_handle, dom, page_array[shared_page_nr - 2]) )
- goto error_out;
-
- if ( xc_clear_domain_page(xc_handle, dom, *store_mfn) )
+ /* Paranoia: clean pages. */
+ if ( xc_clear_domain_page(xc_handle, dom, shared_page_nr) ||
+ xc_clear_domain_page(xc_handle, dom, shared_page_nr-1) ||
+ xc_clear_domain_page(xc_handle, dom, shared_page_nr-2) )
goto error_out;
- /* Send the page update requests down to the hypervisor. */
- if ( xc_finish_mmu_updates(xc_handle, mmu) )
- goto error_out;
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, shared_page_nr-1);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, shared_page_nr-2);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, shared_page_nr);
- free(mmu);
free(page_array);
- /*
- * Initial register values:
- */
ctxt->user_regs.eip = dsi.v_kernentry;
return 0;
error_out:
- free(mmu);
free(page_array);
return -1;
}
@@ -387,19 +269,11 @@ static int xc_hvm_build_internal(int xc_handle,
uint32_t domid,
int memsize,
char *image,
- unsigned long image_size,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn)
+ unsigned long image_size)
{
- struct xen_domctl launch_domctl, domctl;
- int rc, i;
- vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
- unsigned long nr_pages;
- xen_capabilities_info_t xen_caps;
+ struct xen_domctl launch_domctl;
+ vcpu_guest_context_t ctxt;
+ int rc;
if ( (image == NULL) || (image_size == 0) )
{
@@ -407,103 +281,29 @@ static int xc_hvm_build_internal(int xc_handle,
goto error_out;
}
- if ( (rc = xc_version(xc_handle, XENVER_capabilities, &xen_caps)) != 0 )
- {
- PERROR("Failed to get xen version info");
- goto error_out;
- }
-
- if ( !strstr(xen_caps, "hvm") )
- {
- PERROR("CPU doesn't support HVM extensions or "
- "the extensions are not enabled");
- goto error_out;
- }
+ memset(&ctxt, 0, sizeof(ctxt));
- if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 )
+ if ( setup_guest(xc_handle, domid, memsize, image, image_size, &ctxt) < 0 )
{
- PERROR("Could not find total pages for domain");
+ ERROR("Error constructing guest OS");
goto error_out;
}
- if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ if ( lock_pages(&ctxt, sizeof(ctxt) ) )
{
PERROR("%s: ctxt mlock failed", __func__);
- return 1;
- }
-
- domctl.cmd = XEN_DOMCTL_getdomaininfo;
- domctl.domain = (domid_t)domid;
- if ( (xc_domctl(xc_handle, &domctl) < 0) ||
- ((uint16_t)domctl.domain != domid) )
- {
- PERROR("Could not get info on domain");
goto error_out;
}
- /* HVM domains must be put into shadow mode at the start of day */
- if ( xc_shadow_control(xc_handle, domid, XEN_DOMCTL_SHADOW_OP_ENABLE,
- NULL, 0, NULL,
- XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT |
- XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE |
- XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL,
- NULL) )
- {
- PERROR("Could not enable shadow paging for domain.\n");
- goto error_out;
- }
-
- memset(ctxt, 0, sizeof(*ctxt));
-
- ctxt->flags = VGCF_HVM_GUEST;
- if ( setup_guest(xc_handle, domid, memsize, image, image_size, nr_pages,
- ctxt, domctl.u.getdomaininfo.shared_info_frame,
- vcpus, pae, acpi, apic, store_evtchn, store_mfn) < 0)
- {
- ERROR("Error constructing guest OS");
- goto error_out;
- }
-
- /* FPU is set up to default initial state. */
- memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS;
- }
-
- /* No LDT. */
- ctxt->ldt_ents = 0;
-
- /* Use the default Xen-provided GDT. */
- ctxt->gdt_ents = 0;
-
- /* No debugging. */
- memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
-
- /* No callback handlers. */
-#if defined(__i386__)
- ctxt->event_callback_cs = FLAT_KERNEL_CS;
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_cs = FLAT_KERNEL_CS;
- ctxt->failsafe_callback_eip = 0;
-#elif defined(__x86_64__)
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_eip = 0;
- ctxt->syscall_callback_eip = 0;
-#endif
-
memset(&launch_domctl, 0, sizeof(launch_domctl));
-
launch_domctl.domain = (domid_t)domid;
launch_domctl.u.vcpucontext.vcpu = 0;
- set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, ctxt);
-
+ set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, &ctxt);
launch_domctl.cmd = XEN_DOMCTL_setvcpucontext;
rc = xc_domctl(xc_handle, &launch_domctl);
+ unlock_pages(&ctxt, sizeof(ctxt));
+
return rc;
error_out:
@@ -645,13 +445,7 @@ loadelfimage(
int xc_hvm_build(int xc_handle,
uint32_t domid,
int memsize,
- const char *image_name,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn)
+ const char *image_name)
{
char *image;
int sts;
@@ -661,10 +455,7 @@ int xc_hvm_build(int xc_handle,
((image = xc_read_image(image_name, &image_size)) == NULL) )
return -1;
- sts = xc_hvm_build_internal(xc_handle, domid, memsize,
- image, image_size,
- vcpus, pae, acpi, apic,
- store_evtchn, store_mfn);
+ sts = xc_hvm_build_internal(xc_handle, domid, memsize, image, image_size);
free(image);
@@ -681,13 +472,7 @@ int xc_hvm_build_mem(int xc_handle,
uint32_t domid,
int memsize,
const char *image_buffer,
- unsigned long image_size,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn)
+ unsigned long image_size)
{
int sts;
unsigned long img_len;
@@ -709,9 +494,7 @@ int xc_hvm_build_mem(int xc_handle,
}
sts = xc_hvm_build_internal(xc_handle, domid, memsize,
- img, img_len,
- vcpus, pae, acpi, apic,
- store_evtchn, store_mfn);
+ img, img_len);
/* xc_inflate_buffer may return the original buffer pointer (for
for already inflated buffers), so exercise some care in freeing */
diff --git a/tools/libxc/xc_linux.c b/tools/libxc/xc_linux.c
index c803b9a827..a70307a542 100644
--- a/tools/libxc/xc_linux.c
+++ b/tools/libxc/xc_linux.c
@@ -133,27 +133,95 @@ int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall)
(unsigned long)hypercall);
}
+#define MTAB "/proc/mounts"
+#define MAX_PATH 255
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+static int find_sysfsdir(char *sysfsdir)
+{
+ FILE *fp;
+ char type[MAX_PATH + 1];
+
+ if ( (fp = fopen(MTAB, "r")) == NULL )
+ return -1;
+
+ while ( fscanf(fp, "%*s %"
+ STR(MAX_PATH)
+ "s %"
+ STR(MAX_PATH)
+ "s %*s %*d %*d\n",
+ sysfsdir, type) == 2 )
+ {
+ if ( strncmp(type, "sysfs", 5) == 0 )
+ break;
+ }
+
+ fclose(fp);
+
+ return ((strncmp(type, "sysfs", 5) == 0) ? 0 : -1);
+}
+
+int xc_find_device_number(const char *name)
+{
+ FILE *fp;
+ int i, major, minor;
+ char sysfsdir[MAX_PATH + 1];
+ static char *classlist[] = { "xen", "misc" };
+
+ for ( i = 0; i < (sizeof(classlist) / sizeof(classlist[0])); i++ )
+ {
+ if ( find_sysfsdir(sysfsdir) < 0 )
+ goto not_found;
+
+ /* <base>/class/<classname>/<devname>/dev */
+ strncat(sysfsdir, "/class/", MAX_PATH);
+ strncat(sysfsdir, classlist[i], MAX_PATH);
+ strncat(sysfsdir, "/", MAX_PATH);
+ strncat(sysfsdir, name, MAX_PATH);
+ strncat(sysfsdir, "/dev", MAX_PATH);
+
+ if ( (fp = fopen(sysfsdir, "r")) != NULL )
+ goto found;
+ }
+
+ not_found:
+ errno = -ENOENT;
+ return -1;
+
+ found:
+ if ( fscanf(fp, "%d:%d", &major, &minor) != 2 )
+ {
+ fclose(fp);
+ goto not_found;
+ }
+
+ fclose(fp);
+
+ return makedev(major, minor);
+}
+
#define EVTCHN_DEV_NAME "/dev/xen/evtchn"
-#define EVTCHN_DEV_MAJOR 10
-#define EVTCHN_DEV_MINOR 201
int xc_evtchn_open(void)
{
struct stat st;
int fd;
+ int devnum;
+
+ devnum = xc_find_device_number("evtchn");
/* Make sure any existing device file links to correct device. */
- if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
- (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)))
+ if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
+ (st.st_rdev != devnum) )
(void)unlink(EVTCHN_DEV_NAME);
-reopen:
+ reopen:
if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
{
if ( (errno == ENOENT) &&
((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
- (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
- makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0) )
+ (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
goto reopen;
PERROR("Could not open event channel interface");
diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c
index 98c84da3b2..9bd4a5e3f4 100644
--- a/tools/libxc/xc_linux_build.c
+++ b/tools/libxc/xc_linux_build.c
@@ -25,17 +25,16 @@
#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
#endif
-#ifdef __ia64__
-#define get_tot_pages xc_get_max_pages
-#else
-#define get_tot_pages xc_get_tot_pages
-#endif
-
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
#define round_pgdown(_p) ((_p)&PAGE_MASK)
struct initrd_info {
enum { INITRD_none, INITRD_file, INITRD_mem } type;
+ /*
+ * .len must be filled in by the user for type==INITRD_mem. It is
+ * filled in by load_initrd() for INITRD_file and unused for
+ * INITRD_none.
+ */
unsigned long len;
union {
gzFile file_handle;
@@ -128,36 +127,48 @@ static int probeimageformat(const char *image,
return 0;
}
-int load_initrd(int xc_handle, domid_t dom,
+static int load_initrd(int xc_handle, domid_t dom,
struct initrd_info *initrd,
unsigned long physbase,
xen_pfn_t *phys_to_mach)
{
char page[PAGE_SIZE];
- unsigned long pfn_start, pfn, nr_pages;
+ unsigned long pfn_start, pfn;
if ( initrd->type == INITRD_none )
return 0;
pfn_start = physbase >> PAGE_SHIFT;
- nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
- for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
+ if ( initrd->type == INITRD_mem )
{
- if ( initrd->type == INITRD_mem )
+ unsigned long nr_pages = (initrd->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ for ( pfn = pfn_start; pfn < (pfn_start + nr_pages); pfn++ )
{
xc_copy_to_domain_page(
xc_handle, dom, phys_to_mach[pfn],
&initrd->u.mem_addr[(pfn - pfn_start) << PAGE_SHIFT]);
}
- else
+ }
+ else
+ {
+ int readlen;
+
+ pfn = pfn_start;
+ initrd->len = 0;
+
+ /* gzread returns 0 on EOF */
+ while ( (readlen = gzread(initrd->u.file_handle, page, PAGE_SIZE)) )
{
- if ( gzread(initrd->u.file_handle, page, PAGE_SIZE) == -1 )
+ if ( readlen < 0 )
{
PERROR("Error reading initrd image, could not");
return -EINVAL;
}
- xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn], page);
+
+ initrd->len += readlen;
+ xc_copy_to_domain_page(xc_handle, dom, phys_to_mach[pfn++], page);
}
}
@@ -446,8 +457,6 @@ static int setup_pg_tables_64(int xc_handle, uint32_t dom,
#endif
#ifdef __ia64__
-extern unsigned long xc_ia64_fpsr_default(void);
-
static int setup_guest(int xc_handle,
uint32_t dom,
const char *image, unsigned long image_size,
@@ -487,11 +496,24 @@ static int setup_guest(int xc_handle,
if ( rc != 0 )
goto error_out;
- dsi.v_start = round_pgdown(dsi.v_start);
- vinitrd_start = round_pgup(dsi.v_end);
- vinitrd_end = vinitrd_start + initrd->len;
- v_end = round_pgup(vinitrd_end);
+ if ( (page_array = malloc(nr_pages * sizeof(xen_pfn_t))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+ for ( i = 0; i < nr_pages; i++ )
+ page_array[i] = i;
+ if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
+ 0, 0, page_array) )
+ {
+ PERROR("Could not allocate memory for PV guest.\n");
+ goto error_out;
+ }
+
+ dsi.v_start = round_pgdown(dsi.v_start);
+ vinitrd_start = round_pgup(dsi.v_end);
start_info_mpa = (nr_pages - 3) << PAGE_SHIFT;
+ *pvke = dsi.v_kernentry;
/* Build firmware. */
memset(&domctl.u.arch_setup, 0, sizeof(domctl.u.arch_setup));
@@ -504,18 +526,19 @@ static int setup_guest(int xc_handle,
goto error_out;
start_page = dsi.v_start >> PAGE_SHIFT;
- pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT;
- if ( (page_array = malloc(pgnr * sizeof(xen_pfn_t))) == NULL )
- {
- PERROR("Could not allocate memory");
+ /* in order to get initrd->len, we need to load initrd image at first */
+ if ( load_initrd(xc_handle, dom, initrd,
+ vinitrd_start - dsi.v_start, page_array + start_page) )
goto error_out;
- }
- if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array,
- start_page, pgnr) != pgnr )
+ vinitrd_end = vinitrd_start + initrd->len;
+ v_end = round_pgup(vinitrd_end);
+ pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT;
+ if ( pgnr > nr_pages )
{
- PERROR("Could not get the page frame list");
- goto error_out;
+ PERROR("too small memory is specified. "
+ "At least %ld kb is necessary.\n",
+ pgnr << (PAGE_SHIFT - 10));
}
IPRINTF("VIRTUAL MEMORY ARRANGEMENT:\n"
@@ -527,37 +550,21 @@ static int setup_guest(int xc_handle,
_p(dsi.v_start), _p(v_end));
IPRINTF(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
- (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
- &dsi);
+ (load_funcs.loadimage)(image, image_size, xc_handle, dom,
+ page_array + start_page, &dsi);
- if ( load_initrd(xc_handle, dom, initrd,
- vinitrd_start - dsi.v_start, page_array) )
- goto error_out;
-
- *pvke = dsi.v_kernentry;
-
- /* Now need to retrieve machine pfn for system pages:
- * start_info/store/console
- */
- pgnr = 3;
- if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array,
- nr_pages - 3, pgnr) != pgnr )
- {
- PERROR("Could not get page frame for xenstore");
- goto error_out;
- }
-
- *store_mfn = page_array[1];
- *console_mfn = page_array[2];
+ *store_mfn = page_array[nr_pages - 2];
+ *console_mfn = page_array[nr_pages - 1];
IPRINTF("start_info: 0x%lx at 0x%lx, "
"store_mfn: 0x%lx at 0x%lx, "
"console_mfn: 0x%lx at 0x%lx\n",
- page_array[0], nr_pages - 3,
+ page_array[nr_pages - 3], nr_pages - 3,
*store_mfn, nr_pages - 2,
*console_mfn, nr_pages - 1);
start_info = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[0]);
+ xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ page_array[nr_pages - 3]);
memset(start_info, 0, sizeof(*start_info));
rc = xc_version(xc_handle, XENVER_version, NULL);
sprintf(start_info->magic, "xen-%i.%i-ia64", rc >> 16, rc & (0xFFFF));
@@ -659,7 +666,6 @@ static int setup_guest(int xc_handle,
int hypercall_page_defined;
start_info_t *start_info;
shared_info_t *shared_info;
- xc_mmu_t *mmu = NULL;
const char *p;
DECLARE_DOMCTL;
int rc;
@@ -701,7 +707,7 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- if (!compat_check(xc_handle, &dsi))
+ if ( !compat_check(xc_handle, &dsi) )
goto error_out;
/* Parse and validate kernel features. */
@@ -730,6 +736,28 @@ static int setup_guest(int xc_handle,
shadow_mode_enabled = test_feature_bit(XENFEAT_auto_translated_physmap,
required_features);
+ if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ for ( i = 0; i < nr_pages; i++ )
+ page_array[i] = i;
+
+ if ( xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
+ 0, 0, page_array) )
+ {
+ PERROR("Could not allocate memory for PV guest.\n");
+ goto error_out;
+ }
+
+ rc = (load_funcs.loadimage)(image, image_size,
+ xc_handle, dom, page_array,
+ &dsi);
+ if ( rc != 0 )
+ goto error_out;
+
/*
* Why do we need this? The number of page-table frames depends on the
* size of the bootstrap address space. But the size of the address space
@@ -743,9 +771,14 @@ static int setup_guest(int xc_handle,
ERROR("End of mapped kernel image too close to end of memory");
goto error_out;
}
+
vinitrd_start = v_end;
+ if ( load_initrd(xc_handle, dom, initrd,
+ vinitrd_start - dsi.v_start, page_array) )
+ goto error_out;
if ( !increment_ulong(&v_end, round_pgup(initrd->len)) )
goto error_out;
+
vphysmap_start = v_end;
if ( !increment_ulong(&v_end, round_pgup(nr_pages * sizeof(long))) )
goto error_out;
@@ -847,31 +880,8 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
- {
- PERROR("Could not allocate memory");
- goto error_out;
- }
-
- if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
- {
- PERROR("Could not get the page frame list");
- goto error_out;
- }
-
- rc = (load_funcs.loadimage)(image, image_size,
- xc_handle, dom, page_array,
- &dsi);
- if ( rc != 0 )
- goto error_out;
-
- if ( load_initrd(xc_handle, dom, initrd,
- vinitrd_start - dsi.v_start, page_array) )
- goto error_out;
-
- /* setup page tables */
#if defined(__i386__)
- if (dsi.pae_kernel != PAEKERN_no)
+ if ( dsi.pae_kernel != PAEKERN_no )
rc = setup_pg_tables_pae(xc_handle, dom, ctxt,
dsi.v_start, v_end,
page_array, vpt_start, vpt_end,
@@ -888,16 +898,16 @@ static int setup_guest(int xc_handle,
page_array, vpt_start, vpt_end,
shadow_mode_enabled);
#endif
- if (0 != rc)
+ if ( rc != 0 )
goto error_out;
-#if defined(__i386__)
/*
* Pin down l2tab addr as page dir page - causes hypervisor to provide
* correct protection for the page
*/
if ( !shadow_mode_enabled )
{
+#if defined(__i386__)
if ( dsi.pae_kernel != PAEKERN_no )
{
if ( pin_table(xc_handle, MMUEXT_PIN_L3_TABLE,
@@ -910,40 +920,24 @@ static int setup_guest(int xc_handle,
xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
goto error_out;
}
- }
-#endif
-
-#if defined(__x86_64__)
- /*
- * Pin down l4tab addr as page dir page - causes hypervisor to provide
- * correct protection for the page
- */
- if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE,
- xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
- goto error_out;
+#elif defined(__x86_64__)
+ /*
+ * Pin down l4tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ if ( pin_table(xc_handle, MMUEXT_PIN_L4_TABLE,
+ xen_cr3_to_pfn(ctxt->ctrlreg[3]), dom) )
+ goto error_out;
#endif
+ }
- if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL )
- goto error_out;
-
- /* Write the phys->machine and machine->phys table entries. */
+ /* Write the phys->machine table entries (machine->phys already done). */
physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT;
physmap = physmap_e = xc_map_foreign_range(
xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
page_array[physmap_pfn++]);
-
for ( count = 0; count < nr_pages; count++ )
{
- if ( xc_add_mmu_update(
- xc_handle, mmu,
- ((uint64_t)page_array[count] << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE,
- count) )
- {
- DPRINTF("m2p update failure p=%lx m=%"PRIx64"\n",
- count, (uint64_t)page_array[count]);
- munmap(physmap, PAGE_SIZE);
- goto error_out;
- }
*physmap_e++ = page_array[count];
if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
{
@@ -955,10 +949,6 @@ static int setup_guest(int xc_handle,
}
munmap(physmap, PAGE_SIZE);
- /* Send the page update requests down to the hypervisor. */
- if ( xc_finish_mmu_updates(xc_handle, mmu) )
- goto error_out;
-
if ( shadow_mode_enabled )
{
struct xen_add_to_physmap xatp;
@@ -1065,10 +1055,6 @@ static int setup_guest(int xc_handle,
munmap(shared_info, PAGE_SIZE);
- /* Send the page update requests down to the hypervisor. */
- if ( xc_finish_mmu_updates(xc_handle, mmu) )
- goto error_out;
-
hypercall_page = xen_elfnote_numeric(&dsi, XEN_ELFNOTE_HYPERCALL_PAGE,
&hypercall_page_defined);
if ( hypercall_page_defined )
@@ -1084,7 +1070,6 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- free(mmu);
free(page_array);
*pvsi = vstartinfo_start;
@@ -1094,7 +1079,6 @@ static int setup_guest(int xc_handle,
return 0;
error_out:
- free(mmu);
free(page_array);
return -1;
}
@@ -1102,6 +1086,7 @@ static int setup_guest(int xc_handle,
static int xc_linux_build_internal(int xc_handle,
uint32_t domid,
+ unsigned int mem_mb,
char *image,
unsigned long image_size,
struct initrd_info *initrd,
@@ -1115,9 +1100,8 @@ static int xc_linux_build_internal(int xc_handle,
{
struct xen_domctl launch_domctl;
DECLARE_DOMCTL;
- int rc, i;
- vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt;
- unsigned long nr_pages;
+ int rc;
+ struct vcpu_guest_context st_ctxt, *ctxt = &st_ctxt;
unsigned long vstartinfo_start, vkern_entry, vstack_start;
uint32_t features_bitmap[XENFEAT_NR_SUBMAPS] = { 0, };
@@ -1130,19 +1114,11 @@ static int xc_linux_build_internal(int xc_handle,
}
}
- if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 )
- {
- PERROR("Could not find total pages for domain");
- goto error_out;
- }
-
-#ifdef VALGRIND
- memset(&st_ctxt, 0, sizeof(st_ctxt));
-#endif
+ memset(ctxt, 0, sizeof(*ctxt));
- if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ if ( lock_pages(ctxt, sizeof(*ctxt) ) )
{
- PERROR("%s: ctxt mlock failed", __func__);
+ PERROR("%s: ctxt lock failed", __func__);
return 1;
}
@@ -1155,11 +1131,9 @@ static int xc_linux_build_internal(int xc_handle,
goto error_out;
}
- memset(ctxt, 0, sizeof(*ctxt));
-
if ( setup_guest(xc_handle, domid, image, image_size,
initrd,
- nr_pages,
+ mem_mb << (20 - PAGE_SHIFT),
&vstartinfo_start, &vkern_entry,
&vstack_start, ctxt, cmdline,
domctl.u.getdomaininfo.shared_info_frame,
@@ -1173,12 +1147,9 @@ static int xc_linux_build_internal(int xc_handle,
#ifdef __ia64__
/* based on new_thread in xen/arch/ia64/domain.c */
- ctxt->flags = 0;
- ctxt->user_regs.cr_ipsr = 0; /* all necessary bits filled by hypervisor */
ctxt->user_regs.cr_iip = vkern_entry;
ctxt->user_regs.cr_ifs = 1UL << 63;
ctxt->user_regs.ar_fpsr = xc_ia64_fpsr_default();
- i = 0; /* silence unused variable warning */
#else /* x86 */
/*
* Initial register values:
@@ -1202,43 +1173,11 @@ static int xc_linux_build_internal(int xc_handle,
ctxt->flags = VGCF_IN_KERNEL;
- /* FPU is set up to default initial state. */
- memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS;
- }
-
- /* No LDT. */
- ctxt->ldt_ents = 0;
-
- /* Use the default Xen-provided GDT. */
- ctxt->gdt_ents = 0;
-
- /* Ring 1 stack is the initial stack. */
- ctxt->kernel_ss = FLAT_KERNEL_SS;
- ctxt->kernel_sp = vstack_start + PAGE_SIZE;
-
- /* No debugging. */
- memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
-
- /* No callback handlers. */
-#if defined(__i386__)
- ctxt->event_callback_cs = FLAT_KERNEL_CS;
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_cs = FLAT_KERNEL_CS;
- ctxt->failsafe_callback_eip = 0;
-#elif defined(__x86_64__)
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_eip = 0;
- ctxt->syscall_callback_eip = 0;
-#endif
+ ctxt->kernel_ss = ctxt->user_regs.ss;
+ ctxt->kernel_sp = ctxt->user_regs.esp;
#endif /* x86 */
- memset( &launch_domctl, 0, sizeof(launch_domctl) );
+ memset(&launch_domctl, 0, sizeof(launch_domctl));
launch_domctl.domain = (domid_t)domid;
launch_domctl.u.vcpucontext.vcpu = 0;
@@ -1255,6 +1194,7 @@ static int xc_linux_build_internal(int xc_handle,
int xc_linux_build_mem(int xc_handle,
uint32_t domid,
+ unsigned int mem_mb,
const char *image_buffer,
unsigned long image_size,
const char *initrd,
@@ -1303,7 +1243,7 @@ int xc_linux_build_mem(int xc_handle,
}
}
- sts = xc_linux_build_internal(xc_handle, domid, img_buf, img_len,
+ sts = xc_linux_build_internal(xc_handle, domid, mem_mb, img_buf, img_len,
&initrd_info, cmdline, features, flags,
store_evtchn, store_mfn,
console_evtchn, console_mfn);
@@ -1323,6 +1263,7 @@ int xc_linux_build_mem(int xc_handle,
int xc_linux_build(int xc_handle,
uint32_t domid,
+ unsigned int mem_mb,
const char *image_name,
const char *initrd_name,
const char *cmdline,
@@ -1352,7 +1293,6 @@ int xc_linux_build(int xc_handle,
goto error_out;
}
- initrd_info.len = xc_get_filesz(fd);
if ( (initrd_info.u.file_handle = gzdopen(fd, "rb")) == NULL )
{
PERROR("Could not allocate decompression state for initrd");
@@ -1360,7 +1300,7 @@ int xc_linux_build(int xc_handle,
}
}
- sts = xc_linux_build_internal(xc_handle, domid, image, image_size,
+ sts = xc_linux_build_internal(xc_handle, domid, mem_mb, image, image_size,
&initrd_info, cmdline, features, flags,
store_evtchn, store_mfn,
console_evtchn, console_mfn);
diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c
index 6243701911..1d28226bd6 100644
--- a/tools/libxc/xc_linux_restore.c
+++ b/tools/libxc/xc_linux_restore.c
@@ -57,7 +57,7 @@ read_exact(int fd, void *buf, size_t count)
** This function inverts that operation, replacing the pfn values with
** the (now known) appropriate mfn values.
*/
-int uncanonicalize_pagetable(unsigned long type, void *page)
+static int uncanonicalize_pagetable(unsigned long type, void *page)
{
int i, pte_last;
unsigned long pfn;
@@ -79,7 +79,7 @@ int uncanonicalize_pagetable(unsigned long type, void *page)
if(pfn >= max_pfn) {
/* This "page table page" is probably not one; bail. */
- ERR("Frame number in type %lu page table is out of range: "
+ ERROR("Frame number in type %lu page table is out of range: "
"i=%d pfn=0x%lx max_pfn=%lu",
type >> 28, i, pfn, max_pfn);
return 0;
@@ -158,24 +158,24 @@ int xc_linux_restore(int xc_handle, int io_fd,
if(!get_platform_info(xc_handle, dom,
&max_mfn, &hvirt_start, &pt_levels)) {
- ERR("Unable to get platform info.");
+ ERROR("Unable to get platform info.");
return 1;
}
- if (mlock(&ctxt, sizeof(ctxt))) {
+ if (lock_pages(&ctxt, sizeof(ctxt))) {
/* needed for build domctl, but might as well do early */
- ERR("Unable to mlock ctxt");
+ ERROR("Unable to lock ctxt");
return 1;
}
if (!(p2m_frame_list = malloc(P2M_FL_SIZE))) {
- ERR("Couldn't allocate p2m_frame_list array");
+ ERROR("Couldn't allocate p2m_frame_list array");
goto out;
}
/* Read first entry of P2M list, or extended-info signature (~0UL). */
if (!read_exact(io_fd, p2m_frame_list, sizeof(long))) {
- ERR("read extended-info signature failed");
+ ERROR("read extended-info signature failed");
goto out;
}
@@ -184,7 +184,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Next 4 bytes: total size of following extended info. */
if (!read_exact(io_fd, &tot_bytes, sizeof(tot_bytes))) {
- ERR("read extended-info size failed");
+ ERROR("read extended-info size failed");
goto out;
}
@@ -195,7 +195,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* 4-character chunk signature + 4-byte remaining chunk size. */
if (!read_exact(io_fd, chunk_sig, sizeof(chunk_sig)) ||
!read_exact(io_fd, &chunk_bytes, sizeof(chunk_bytes))) {
- ERR("read extended-info chunk signature failed");
+ ERROR("read extended-info chunk signature failed");
goto out;
}
tot_bytes -= 8;
@@ -203,7 +203,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* VCPU context structure? */
if (!strncmp(chunk_sig, "vcpu", 4)) {
if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
- ERR("read extended-info vcpu context failed");
+ ERROR("read extended-info vcpu context failed");
goto out;
}
tot_bytes -= sizeof(struct vcpu_guest_context);
@@ -219,7 +219,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
if ( sz > P2M_FL_SIZE )
sz = P2M_FL_SIZE;
if (!read_exact(io_fd, p2m_frame_list, sz)) {
- ERR("read-and-discard extended-info chunk bytes failed");
+ ERROR("read-and-discard extended-info chunk bytes failed");
goto out;
}
chunk_bytes -= sz;
@@ -229,14 +229,14 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Now read the real first entry of P2M list. */
if (!read_exact(io_fd, p2m_frame_list, sizeof(long))) {
- ERR("read first entry of p2m_frame_list failed");
+ ERROR("read first entry of p2m_frame_list failed");
goto out;
}
}
/* First entry is already read into the p2m array. */
if (!read_exact(io_fd, &p2m_frame_list[1], P2M_FL_SIZE - sizeof(long))) {
- ERR("read p2m_frame_list failed");
+ ERROR("read p2m_frame_list failed");
goto out;
}
@@ -246,13 +246,13 @@ int xc_linux_restore(int xc_handle, int io_fd,
region_mfn = calloc(MAX_BATCH_SIZE, sizeof(xen_pfn_t));
if ((p2m == NULL) || (pfn_type == NULL) || (region_mfn == NULL)) {
- ERR("memory alloc failed");
+ ERROR("memory alloc failed");
errno = ENOMEM;
goto out;
}
- if (mlock(region_mfn, sizeof(xen_pfn_t) * MAX_BATCH_SIZE)) {
- ERR("Could not mlock region_mfn");
+ if (lock_pages(region_mfn, sizeof(xen_pfn_t) * MAX_BATCH_SIZE)) {
+ ERROR("Could not lock region_mfn");
goto out;
}
@@ -260,37 +260,33 @@ int xc_linux_restore(int xc_handle, int io_fd,
domctl.cmd = XEN_DOMCTL_getdomaininfo;
domctl.domain = (domid_t)dom;
if (xc_domctl(xc_handle, &domctl) < 0) {
- ERR("Could not get information on new domain");
+ ERROR("Could not get information on new domain");
goto out;
}
shared_info_frame = domctl.u.getdomaininfo.shared_info_frame;
- if(xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(max_pfn)) != 0) {
+ if (xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(max_pfn)) != 0) {
errno = ENOMEM;
goto out;
}
- if(xc_domain_memory_increase_reservation(
- xc_handle, dom, max_pfn, 0, 0, NULL) != 0) {
- ERR("Failed to increase reservation by %lx KB", PFN_TO_KB(max_pfn));
+ for ( pfn = 0; pfn < max_pfn; pfn++ )
+ p2m[pfn] = pfn;
+
+ if (xc_domain_memory_populate_physmap(xc_handle, dom, max_pfn,
+ 0, 0, p2m) != 0) {
+ ERROR("Failed to increase reservation by %lx KB", PFN_TO_KB(max_pfn));
errno = ENOMEM;
goto out;
}
DPRINTF("Increased domain reservation by %lx KB\n", PFN_TO_KB(max_pfn));
- /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
- if (xc_get_pfn_list(xc_handle, dom, p2m, max_pfn) != max_pfn) {
- ERR("Did not read correct number of frame numbers for new dom");
- goto out;
- }
-
if(!(mmu = xc_init_mmu_updates(xc_handle, dom))) {
- ERR("Could not initialise for MMU updates");
+ ERROR("Could not initialise for MMU updates");
goto out;
}
-
DPRINTF("Reloading memory pages: 0%%\n");
/*
@@ -312,7 +308,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
}
if (!read_exact(io_fd, &j, sizeof(int))) {
- ERR("Error when reading batch size");
+ ERROR("Error when reading batch size");
goto out;
}
@@ -328,12 +324,12 @@ int xc_linux_restore(int xc_handle, int io_fd,
break; /* our work here is done */
if (j > MAX_BATCH_SIZE) {
- ERR("Max batch size exceeded. Giving up.");
+ ERROR("Max batch size exceeded. Giving up.");
goto out;
}
if (!read_exact(io_fd, region_pfn_type, j*sizeof(unsigned long))) {
- ERR("Error when reading region pfn types");
+ ERROR("Error when reading region pfn types");
goto out;
}
@@ -353,7 +349,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
xc_handle, dom, PROT_WRITE, region_mfn, j);
if ( region_base == NULL )
{
- ERR("map batch failed");
+ ERROR("map batch failed");
goto out;
}
@@ -371,7 +367,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
if ( pfn > max_pfn )
{
- ERR("pfn out of range");
+ ERROR("pfn out of range");
goto out;
}
@@ -383,7 +379,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
page = verify ? (void *)buf : (region_base + i*PAGE_SIZE);
if (!read_exact(io_fd, page, PAGE_SIZE)) {
- ERR("Error when reading page (type was %lx)", pagetype);
+ ERROR("Error when reading page (type was %lx)", pagetype);
goto out;
}
@@ -422,7 +418,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
}
else if ( pagetype != XEN_DOMCTL_PFINFO_NOTAB )
{
- ERR("Bogus page type %lx page table is out of range: "
+ ERROR("Bogus page type %lx page table is out of range: "
"i=%d max_pfn=%lu", pagetype, i, max_pfn);
goto out;
@@ -455,7 +451,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
if (xc_add_mmu_update(xc_handle, mmu,
(((unsigned long long)mfn) << PAGE_SHIFT)
| MMU_MACHPHYS_UPDATE, pfn)) {
- ERR("failed machpys update mfn=%lx pfn=%lx", mfn, pfn);
+ ERROR("failed machpys update mfn=%lx pfn=%lx", mfn, pfn);
goto out;
}
} /* end of 'batch' for loop */
@@ -469,7 +465,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
* reallocations below.
*/
if (xc_finish_mmu_updates(xc_handle, mmu)) {
- ERR("Error doing finish_mmu_updates()");
+ ERROR("Error doing finish_mmu_updates()");
goto out;
}
@@ -512,7 +508,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
munmap(l3tab, PAGE_SIZE);
if (!(new_mfn=xc_make_page_below_4G(xc_handle, dom, p2m[i]))) {
- ERR("Couldn't get a page below 4GB :-(");
+ ERROR("Couldn't get a page below 4GB :-(");
goto out;
}
@@ -521,7 +517,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
(((unsigned long long)new_mfn)
<< PAGE_SHIFT) |
MMU_MACHPHYS_UPDATE, i)) {
- ERR("Couldn't m2p on PAE root pgdir");
+ ERROR("Couldn't m2p on PAE root pgdir");
goto out;
}
@@ -554,14 +550,14 @@ int xc_linux_restore(int xc_handle, int io_fd,
if (!(region_base = xc_map_foreign_batch(
xc_handle, dom, PROT_READ | PROT_WRITE,
region_mfn, j))) {
- ERR("map batch failed");
+ ERROR("map batch failed");
goto out;
}
for(k = 0; k < j; k++) {
if(!uncanonicalize_pagetable(XEN_DOMCTL_PFINFO_L1TAB,
region_base + k*PAGE_SIZE)) {
- ERR("failed uncanonicalize pt!");
+ ERROR("failed uncanonicalize pt!");
goto out;
}
}
@@ -572,7 +568,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
}
if (xc_finish_mmu_updates(xc_handle, mmu)) {
- ERR("Error doing finish_mmu_updates()");
+ ERROR("Error doing finish_mmu_updates()");
goto out;
}
}
@@ -615,7 +611,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Batch full? Then flush. */
if (nr_pins == MAX_PIN_BATCH) {
if (xc_mmuext_op(xc_handle, pin, nr_pins, dom) < 0) {
- ERR("Failed to pin batch of %d page tables", nr_pins);
+ ERROR("Failed to pin batch of %d page tables", nr_pins);
goto out;
}
nr_pins = 0;
@@ -624,7 +620,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Flush final partial batch. */
if ((nr_pins != 0) && (xc_mmuext_op(xc_handle, pin, nr_pins, dom) < 0)) {
- ERR("Failed to pin batch of %d page tables", nr_pins);
+ ERROR("Failed to pin batch of %d page tables", nr_pins);
goto out;
}
@@ -638,17 +634,17 @@ int xc_linux_restore(int xc_handle, int io_fd,
int rc;
if (!read_exact(io_fd, &count, sizeof(count))) {
- ERR("Error when reading pfn count");
+ ERROR("Error when reading pfn count");
goto out;
}
if(!(pfntab = malloc(sizeof(unsigned long) * count))) {
- ERR("Out of memory");
+ ERROR("Out of memory");
goto out;
}
if (!read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) {
- ERR("Error when reading pfntab");
+ ERROR("Error when reading pfntab");
goto out;
}
@@ -675,7 +671,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
if ((rc = xc_memory_op(xc_handle, XENMEM_decrease_reservation,
&reservation)) != count) {
- ERR("Could not decrease reservation : %d", rc);
+ ERROR("Could not decrease reservation : %d", rc);
goto out;
} else
DPRINTF("Decreased reservation by %d pages\n", count);
@@ -684,14 +680,14 @@ int xc_linux_restore(int xc_handle, int io_fd,
if (!read_exact(io_fd, &ctxt, sizeof(ctxt)) ||
!read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
- ERR("Error when reading ctxt or shared info page");
+ ERROR("Error when reading ctxt or shared info page");
goto out;
}
/* Uncanonicalise the suspend-record frame number and poke resume rec. */
pfn = ctxt.user_regs.edx;
if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
- ERR("Suspend record frame number is bad");
+ ERROR("Suspend record frame number is bad");
goto out;
}
ctxt.user_regs.edx = mfn = p2m[pfn];
@@ -709,14 +705,14 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Uncanonicalise each GDT frame number. */
if (ctxt.gdt_ents > 8192) {
- ERR("GDT entry count out of range");
+ ERROR("GDT entry count out of range");
goto out;
}
for (i = 0; i < ctxt.gdt_ents; i += 512) {
pfn = ctxt.gdt_frames[i];
if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
- ERR("GDT frame number is bad");
+ ERROR("GDT frame number is bad");
goto out;
}
ctxt.gdt_frames[i] = p2m[pfn];
@@ -726,14 +722,14 @@ int xc_linux_restore(int xc_handle, int io_fd,
pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
if (pfn >= max_pfn) {
- ERR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
+ ERROR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
pfn, max_pfn, pfn_type[pfn]);
goto out;
}
if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
- ERR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
+ ERROR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
pfn, max_pfn, pfn_type[pfn],
(unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
goto out;
@@ -757,7 +753,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
for (i = 0; i < P2M_FL_ENTRIES; i++) {
pfn = p2m_frame_list[i];
if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
- ERR("PFN-to-MFN frame number is bad");
+ ERROR("PFN-to-MFN frame number is bad");
goto out;
}
@@ -767,46 +763,13 @@ int xc_linux_restore(int xc_handle, int io_fd,
/* Copy the P2M we've constructed to the 'live' P2M */
if (!(live_p2m = xc_map_foreign_batch(xc_handle, dom, PROT_WRITE,
p2m_frame_list, P2M_FL_ENTRIES))) {
- ERR("Couldn't map p2m table");
+ ERROR("Couldn't map p2m table");
goto out;
}
memcpy(live_p2m, p2m, P2M_SIZE);
munmap(live_p2m, P2M_SIZE);
- /*
- * Safety checking of saved context:
- * 1. user_regs is fine, as Xen checks that on context switch.
- * 2. fpu_ctxt is fine, as it can't hurt Xen.
- * 3. trap_ctxt needs the code selectors checked.
- * 4. ldt base must be page-aligned, no more than 8192 ents, ...
- * 5. gdt already done, and further checking is done by Xen.
- * 6. check that kernel_ss is safe.
- * 7. pt_base is already done.
- * 8. debugregs are checked by Xen.
- * 9. callback code selectors need checking.
- */
- for ( i = 0; i < 256; i++ ) {
- ctxt.trap_ctxt[i].vector = i;
- if ((ctxt.trap_ctxt[i].cs & 3) == 0)
- ctxt.trap_ctxt[i].cs = FLAT_KERNEL_CS;
- }
- if ((ctxt.kernel_ss & 3) == 0)
- ctxt.kernel_ss = FLAT_KERNEL_DS;
-#if defined(__i386__)
- if ((ctxt.event_callback_cs & 3) == 0)
- ctxt.event_callback_cs = FLAT_KERNEL_CS;
- if ((ctxt.failsafe_callback_cs & 3) == 0)
- ctxt.failsafe_callback_cs = FLAT_KERNEL_CS;
-#endif
- if (((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
- (ctxt.ldt_ents > 8192) ||
- (ctxt.ldt_base > hvirt_start) ||
- ((ctxt.ldt_base + ctxt.ldt_ents*8) > hvirt_start)) {
- ERR("Bad LDT base or size");
- goto out;
- }
-
DPRINTF("Domain ready to be built.\n");
domctl.cmd = XEN_DOMCTL_setvcpucontext;
@@ -816,7 +779,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
rc = xc_domctl(xc_handle, &domctl);
if (rc != 0) {
- ERR("Couldn't build the domain");
+ ERROR("Couldn't build the domain");
goto out;
}
diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c
index b5008a6cee..a38f80c7fe 100644
--- a/tools/libxc/xc_linux_save.c
+++ b/tools/libxc/xc_linux_save.c
@@ -363,19 +363,19 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
int i = 0;
if (!(*suspend)(dom)) {
- ERR("Suspend request failed");
+ ERROR("Suspend request failed");
return -1;
}
retry:
if (xc_domain_getinfo(xc_handle, dom, 1, info) != 1) {
- ERR("Could not get domain info");
+ ERROR("Could not get domain info");
return -1;
}
if ( xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, ctxt))
- ERR("Could not get vcpu context");
+ ERROR("Could not get vcpu context");
if (info->shutdown && info->shutdown_reason == SHUTDOWN_suspend)
@@ -385,7 +385,7 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
// try unpausing domain, wait, and retest
xc_domain_unpause( xc_handle, dom );
- ERR("Domain was paused. Wait and re-test.");
+ ERROR("Domain was paused. Wait and re-test.");
usleep(10000); // 10ms
goto retry;
@@ -393,12 +393,12 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
if( ++i < 100 ) {
- ERR("Retry suspend domain.");
+ ERROR("Retry suspend domain.");
usleep(10000); // 10ms
goto retry;
}
- ERR("Unable to suspend domain.");
+ ERROR("Unable to suspend domain.");
return -1;
}
@@ -413,7 +413,7 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
** which entries do not require canonicalization (in particular, those
** entries which map the virtual address reserved for the hypervisor).
*/
-int canonicalize_pagetable(unsigned long type, unsigned long pfn,
+static int canonicalize_pagetable(unsigned long type, unsigned long pfn,
const void *spage, void *dpage)
{
@@ -516,25 +516,25 @@ static xen_pfn_t *xc_map_m2p(int xc_handle,
xmml.max_extents = m2p_chunks;
if (!(extent_start = malloc(m2p_chunks * sizeof(xen_pfn_t)))) {
- ERR("failed to allocate space for m2p mfns");
+ ERROR("failed to allocate space for m2p mfns");
return NULL;
}
set_xen_guest_handle(xmml.extent_start, extent_start);
if (xc_memory_op(xc_handle, XENMEM_machphys_mfn_list, &xmml) ||
(xmml.nr_extents != m2p_chunks)) {
- ERR("xc_get_m2p_mfns");
+ ERROR("xc_get_m2p_mfns");
return NULL;
}
if ((m2p = mmap(NULL, m2p_size, prot,
MAP_SHARED, xc_handle, 0)) == MAP_FAILED) {
- ERR("failed to mmap m2p");
+ ERROR("failed to mmap m2p");
return NULL;
}
if (!(entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t)))) {
- ERR("failed to allocate space for mmap entries");
+ ERROR("failed to allocate space for mmap entries");
return NULL;
}
@@ -546,7 +546,7 @@ static xen_pfn_t *xc_map_m2p(int xc_handle,
if ((rc = xc_map_foreign_ranges(xc_handle, DOMID_XEN,
entries, m2p_chunks)) < 0) {
- ERR("xc_mmap_foreign_ranges failed (rc = %d)", rc);
+ ERROR("xc_mmap_foreign_ranges failed (rc = %d)", rc);
return NULL;
}
@@ -619,23 +619,23 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if(!get_platform_info(xc_handle, dom,
&max_mfn, &hvirt_start, &pt_levels)) {
- ERR("Unable to get platform info.");
+ ERROR("Unable to get platform info.");
return 1;
}
if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) {
- ERR("Could not get domain info");
+ ERROR("Could not get domain info");
return 1;
}
- if (mlock(&ctxt, sizeof(ctxt))) {
- ERR("Unable to mlock ctxt");
+ if (lock_pages(&ctxt, sizeof(ctxt))) {
+ ERROR("Unable to lock ctxt");
return 1;
}
/* Only have to worry about vcpu 0 even for SMP */
if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) {
- ERR("Could not get vcpu context");
+ ERROR("Could not get vcpu context");
goto out;
}
shared_info_frame = info.shared_info_frame;
@@ -643,13 +643,13 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* A cheesy test to see whether the domain contains valid state. */
if (ctxt.ctrlreg[3] == 0)
{
- ERR("Domain is not in a valid Linux guest OS state");
+ ERROR("Domain is not in a valid Linux guest OS state");
goto out;
}
/* cheesy sanity check */
if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) {
- ERR("Invalid state record -- pfn count out of range: %lu",
+ ERROR("Invalid state record -- pfn count out of range: %lu",
(info.max_memkb >> (PAGE_SHIFT - 10)));
goto out;
}
@@ -657,7 +657,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Map the shared info frame */
if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
PROT_READ, shared_info_frame))) {
- ERR("Couldn't map live_shinfo");
+ ERROR("Couldn't map live_shinfo");
goto out;
}
@@ -668,7 +668,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
live_shinfo->arch.pfn_to_mfn_frame_list_list);
if (!live_p2m_frame_list_list) {
- ERR("Couldn't map p2m_frame_list_list (errno %d)", errno);
+ ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno);
goto out;
}
@@ -678,7 +678,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
P2M_FLL_ENTRIES);
if (!live_p2m_frame_list) {
- ERR("Couldn't map p2m_frame_list");
+ ERROR("Couldn't map p2m_frame_list");
goto out;
}
@@ -692,20 +692,20 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
P2M_FL_ENTRIES);
if (!live_p2m) {
- ERR("Couldn't map p2m table");
+ ERROR("Couldn't map p2m table");
goto out;
}
/* Setup the mfn_to_pfn table mapping */
if(!(live_m2p = xc_map_m2p(xc_handle, max_mfn, PROT_READ))) {
- ERR("Failed to map live M2P table");
+ ERROR("Failed to map live M2P table");
goto out;
}
/* Get a local copy of the live_P2M_frame_list */
if(!(p2m_frame_list = malloc(P2M_FL_SIZE))) {
- ERR("Couldn't allocate p2m_frame_list array");
+ ERROR("Couldn't allocate p2m_frame_list array");
goto out;
}
memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
@@ -713,8 +713,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Canonicalise the pfn-to-mfn table frame-number list. */
for (i = 0; i < max_pfn; i += fpp) {
if (!translate_mfn_to_pfn(&p2m_frame_list[i/fpp])) {
- ERR("Frame# in pfn-to-mfn frame list is not in pseudophys");
- ERR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64, i, i/fpp,
+ ERROR("Frame# in pfn-to-mfn frame list is not in pseudophys");
+ ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64, i, i/fpp,
(uint64_t)p2m_frame_list[i/fpp]);
goto out;
}
@@ -726,7 +726,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (xc_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
NULL, 0, NULL, 0, NULL) < 0) {
- ERR("Couldn't enable shadow mode");
+ ERROR("Couldn't enable shadow mode");
goto out;
}
@@ -740,7 +740,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
last_iter = 1;
if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info, &ctxt)) {
- ERR("Domain appears not to have suspended");
+ ERROR("Domain appears not to have suspended");
goto out;
}
@@ -761,20 +761,20 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
to_skip = malloc(BITMAP_SIZE);
if (!to_send || !to_fix || !to_skip) {
- ERR("Couldn't allocate to_send array");
+ ERROR("Couldn't allocate to_send array");
goto out;
}
memset(to_send, 0xff, BITMAP_SIZE);
- if (mlock(to_send, BITMAP_SIZE)) {
- ERR("Unable to mlock to_send");
+ if (lock_pages(to_send, BITMAP_SIZE)) {
+ ERROR("Unable to lock to_send");
return 1;
}
/* (to fix is local only) */
- if (mlock(to_skip, BITMAP_SIZE)) {
- ERR("Unable to mlock to_skip");
+ if (lock_pages(to_skip, BITMAP_SIZE)) {
+ ERROR("Unable to lock to_skip");
return 1;
}
@@ -785,13 +785,13 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
pfn_batch = calloc(MAX_BATCH_SIZE, sizeof(*pfn_batch));
if ((pfn_type == NULL) || (pfn_batch == NULL)) {
- ERR("failed to alloc memory for pfn_type and/or pfn_batch arrays");
+ ERROR("failed to alloc memory for pfn_type and/or pfn_batch arrays");
errno = ENOMEM;
goto out;
}
- if (mlock(pfn_type, MAX_BATCH_SIZE * sizeof(*pfn_type))) {
- ERR("Unable to mlock");
+ if (lock_pages(pfn_type, MAX_BATCH_SIZE * sizeof(*pfn_type))) {
+ ERROR("Unable to lock");
goto out;
}
@@ -817,7 +817,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Start writing out the saved-domain record. */
if (!write_exact(io_fd, &max_pfn, sizeof(unsigned long))) {
- ERR("write: max_pfn");
+ ERROR("write: max_pfn");
goto out;
}
@@ -837,13 +837,13 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
!write_exact(io_fd, &chunk_sig, 4) ||
!write_exact(io_fd, &chunk_sz, sizeof(chunk_sz)) ||
!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
- ERR("write: extended info");
+ ERROR("write: extended info");
goto out;
}
}
if (!write_exact(io_fd, p2m_frame_list, P2M_FL_SIZE)) {
- ERR("write: p2m_frame_list");
+ ERROR("write: p2m_frame_list");
goto out;
}
@@ -877,7 +877,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (!last_iter && xc_shadow_control(
xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK,
to_skip, max_pfn, NULL, 0, NULL) != max_pfn) {
- ERR("Error peeking shadow bitmap");
+ ERROR("Error peeking shadow bitmap");
goto out;
}
@@ -942,12 +942,12 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if ((region_base = xc_map_foreign_batch(
xc_handle, dom, PROT_READ, pfn_type, batch)) == 0) {
- ERR("map batch failed");
+ ERROR("map batch failed");
goto out;
}
if (xc_get_pfn_type_batch(xc_handle, dom, batch, pfn_type)) {
- ERR("get_pfn_type_batch failed");
+ ERROR("get_pfn_type_batch failed");
goto out;
}
@@ -978,12 +978,14 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
if(!write_exact(io_fd, &batch, sizeof(unsigned int))) {
- ERR("Error when writing to state file (2)");
+ ERROR("Error when writing to state file (2) (errno %d)",
+ errno);
goto out;
}
if(!write_exact(io_fd, pfn_type, sizeof(unsigned long)*j)) {
- ERR("Error when writing to state file (3)");
+ ERROR("Error when writing to state file (3) (errno %d)",
+ errno);
goto out;
}
@@ -1013,7 +1015,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
goto out;
if (ratewrite(io_fd, page, PAGE_SIZE) != PAGE_SIZE) {
- ERR("Error when writing to state file (4)");
+ ERROR("Error when writing to state file (4)"
+ " (errno %d)", errno);
goto out;
}
@@ -1021,7 +1024,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* We have a normal page: just write it directly. */
if (ratewrite(io_fd, spage, PAGE_SIZE) != PAGE_SIZE) {
- ERR("Error when writing to state file (5)");
+ ERROR("Error when writing to state file (5)"
+ " (errno %d)", errno);
goto out;
}
}
@@ -1056,7 +1060,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* send "-1" to put receiver into debug mode */
if(!write_exact(io_fd, &minusone, sizeof(int))) {
- ERR("Error when writing to state file (6)");
+ ERROR("Error when writing to state file (6) (errno %d)",
+ errno);
goto out;
}
@@ -1079,7 +1084,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info,
&ctxt)) {
- ERR("Domain appears not to have suspended");
+ ERROR("Domain appears not to have suspended");
goto out;
}
@@ -1092,7 +1097,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (xc_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_CLEAN, to_send,
max_pfn, NULL, 0, &stats) != max_pfn) {
- ERR("Error flushing shadow PT");
+ ERROR("Error flushing shadow PT");
goto out;
}
@@ -1110,7 +1115,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Zero terminate */
i = 0;
if (!write_exact(io_fd, &i, sizeof(int))) {
- ERR("Error when writing to state file (6)");
+ ERROR("Error when writing to state file (6') (errno %d)", errno);
goto out;
}
@@ -1125,7 +1130,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
if(!write_exact(io_fd, &j, sizeof(unsigned int))) {
- ERR("Error when writing to state file (6a)");
+ ERROR("Error when writing to state file (6a) (errno %d)", errno);
goto out;
}
@@ -1137,7 +1142,8 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
i++;
if (j == 1024 || i == max_pfn) {
if(!write_exact(io_fd, &pfntab, sizeof(unsigned long)*j)) {
- ERR("Error when writing to state file (6b)");
+ ERROR("Error when writing to state file (6b) (errno %d)",
+ errno);
goto out;
}
j = 0;
@@ -1148,21 +1154,21 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Canonicalise the suspend-record frame number. */
if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) ){
- ERR("Suspend record is not in range of pseudophys map");
+ ERROR("Suspend record is not in range of pseudophys map");
goto out;
}
/* Canonicalise each GDT frame number. */
for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
- ERR("GDT frame is not in range of pseudophys map");
+ ERROR("GDT frame is not in range of pseudophys map");
goto out;
}
}
/* Canonicalise the page table base pointer. */
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) ) {
- ERR("PT base is not in range of pseudophys map");
+ ERROR("PT base is not in range of pseudophys map");
goto out;
}
ctxt.ctrlreg[3] =
@@ -1170,7 +1176,7 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
if (!write_exact(io_fd, &ctxt, sizeof(ctxt)) ||
!write_exact(io_fd, live_shinfo, PAGE_SIZE)) {
- ERR("Error when writing to state file (1)");
+ ERROR("Error when writing to state file (1) (errno %d)", errno);
goto out;
}
diff --git a/tools/libxc/xc_load_elf.c b/tools/libxc/xc_load_elf.c
index 3fbd3d9ccc..9ca9759398 100644
--- a/tools/libxc/xc_load_elf.c
+++ b/tools/libxc/xc_load_elf.c
@@ -364,7 +364,7 @@ static int parseelfimage(const char *image,
if ( p != NULL && strncmp(p, "yes", 3) == 0 )
{
dsi->pae_kernel = PAEKERN_yes;
- if ( !strncmp(p+4, "[extended-cr3]", 14) )
+ if ( !strncmp(p+3, "[extended-cr3]", 14) )
dsi->pae_kernel = PAEKERN_extended_cr3;
}
}
diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c
index 7b598124c4..216dff94f8 100644
--- a/tools/libxc/xc_misc.c
+++ b/tools/libxc/xc_misc.c
@@ -5,6 +5,7 @@
*/
#include "xc_private.h"
+#include <xen/hvm/hvm_op.h>
int xc_readconsolering(int xc_handle,
char **pbuffer,
@@ -21,13 +22,13 @@ int xc_readconsolering(int xc_handle,
sysctl.u.readconsole.count = nr_chars;
sysctl.u.readconsole.clear = clear;
- if ( (ret = mlock(buffer, nr_chars)) != 0 )
+ if ( (ret = lock_pages(buffer, nr_chars)) != 0 )
return ret;
if ( (ret = do_sysctl(xc_handle, &sysctl)) == 0 )
*pnr_chars = sysctl.u.readconsole.count;
- safe_munlock(buffer, nr_chars);
+ unlock_pages(buffer, nr_chars);
return ret;
}
@@ -89,6 +90,97 @@ int xc_perfc_control(int xc_handle,
return rc;
}
+int xc_hvm_set_pci_intx_level(
+ int xc_handle, domid_t dom,
+ uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx,
+ unsigned int level)
+{
+ DECLARE_HYPERCALL;
+ struct xen_hvm_set_pci_intx_level arg;
+ int rc;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_set_pci_intx_level;
+ hypercall.arg[1] = (unsigned long)&arg;
+
+ arg.domid = dom;
+ arg.domain = domain;
+ arg.bus = bus;
+ arg.device = device;
+ arg.intx = intx;
+ arg.level = level;
+
+ if ( mlock(&arg, sizeof(arg)) != 0 )
+ {
+ PERROR("Could not lock memory");
+ return -1;
+ }
+
+ rc = do_xen_hypercall(xc_handle, &hypercall);
+
+ safe_munlock(&arg, sizeof(arg));
+
+ return rc;
+}
+
+int xc_hvm_set_isa_irq_level(
+ int xc_handle, domid_t dom,
+ uint8_t isa_irq,
+ unsigned int level)
+{
+ DECLARE_HYPERCALL;
+ struct xen_hvm_set_isa_irq_level arg;
+ int rc;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_set_isa_irq_level;
+ hypercall.arg[1] = (unsigned long)&arg;
+
+ arg.domid = dom;
+ arg.isa_irq = isa_irq;
+ arg.level = level;
+
+ if ( mlock(&arg, sizeof(arg)) != 0 )
+ {
+ PERROR("Could not lock memory");
+ return -1;
+ }
+
+ rc = do_xen_hypercall(xc_handle, &hypercall);
+
+ safe_munlock(&arg, sizeof(arg));
+
+ return rc;
+}
+
+int xc_hvm_set_pci_link_route(
+ int xc_handle, domid_t dom, uint8_t link, uint8_t isa_irq)
+{
+ DECLARE_HYPERCALL;
+ struct xen_hvm_set_pci_link_route arg;
+ int rc;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_set_pci_link_route;
+ hypercall.arg[1] = (unsigned long)&arg;
+
+ arg.domid = dom;
+ arg.link = link;
+ arg.isa_irq = isa_irq;
+
+ if ( mlock(&arg, sizeof(arg)) != 0 )
+ {
+ PERROR("Could not lock memory");
+ return -1;
+ }
+
+ rc = do_xen_hypercall(xc_handle, &hypercall);
+
+ safe_munlock(&arg, sizeof(arg));
+
+ return rc;
+}
+
/*
* Local variables:
* mode: C
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 93537ef811..d8dbb5e0dd 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -6,8 +6,25 @@
#include <inttypes.h>
#include "xc_private.h"
+#include "xg_private.h"
-/* NB: arr must be mlock'ed */
+int lock_pages(void *addr, size_t len)
+{
+ int e = 0;
+#ifndef __sun__
+ e = mlock(addr, len);
+#endif
+ return (e);
+}
+
+void unlock_pages(void *addr, size_t len)
+{
+#ifndef __sun__
+ safe_munlock(addr, len);
+#endif
+}
+
+/* NB: arr must be locked */
int xc_get_pfn_type_batch(int xc_handle,
uint32_t dom, int num, unsigned long *arr)
{
@@ -19,23 +36,6 @@ int xc_get_pfn_type_batch(int xc_handle,
return do_domctl(xc_handle, &domctl);
}
-#define GETPFN_ERR (~0U)
-unsigned int get_pfn_type(int xc_handle,
- unsigned long mfn,
- uint32_t dom)
-{
- DECLARE_DOMCTL;
- domctl.cmd = XEN_DOMCTL_getpageframeinfo;
- domctl.u.getpageframeinfo.gmfn = mfn;
- domctl.domain = (domid_t)dom;
- if ( do_domctl(xc_handle, &domctl) < 0 )
- {
- PERROR("Unexpected failure when getting page frame info!");
- return GETPFN_ERR;
- }
- return domctl.u.getpageframeinfo.type;
-}
-
int xc_mmuext_op(
int xc_handle,
struct mmuext_op *op,
@@ -51,7 +51,7 @@ int xc_mmuext_op(
hypercall.arg[2] = (unsigned long)0;
hypercall.arg[3] = (unsigned long)dom;
- if ( mlock(op, nr_ops*sizeof(*op)) != 0 )
+ if ( lock_pages(op, nr_ops*sizeof(*op)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out1;
@@ -59,7 +59,7 @@ int xc_mmuext_op(
ret = do_xen_hypercall(xc_handle, &hypercall);
- safe_munlock(op, nr_ops*sizeof(*op));
+ unlock_pages(op, nr_ops*sizeof(*op));
out1:
return ret;
@@ -79,9 +79,9 @@ static int flush_mmu_updates(int xc_handle, xc_mmu_t *mmu)
hypercall.arg[2] = 0;
hypercall.arg[3] = mmu->subject;
- if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 )
+ if ( lock_pages(mmu->updates, sizeof(mmu->updates)) != 0 )
{
- PERROR("flush_mmu_updates: mmu updates mlock failed");
+ PERROR("flush_mmu_updates: mmu updates lock_pages failed");
err = 1;
goto out;
}
@@ -94,7 +94,7 @@ static int flush_mmu_updates(int xc_handle, xc_mmu_t *mmu)
mmu->idx = 0;
- safe_munlock(mmu->updates, sizeof(mmu->updates));
+ unlock_pages(mmu->updates, sizeof(mmu->updates));
out:
return err;
@@ -134,10 +134,7 @@ int xc_memory_op(int xc_handle,
DECLARE_HYPERCALL;
struct xen_memory_reservation *reservation = arg;
struct xen_machphys_mfn_list *xmml = arg;
- struct xen_translate_gpfn_list *trans = arg;
xen_pfn_t *extent_start;
- xen_pfn_t *gpfn_list;
- xen_pfn_t *mfn_list;
long ret = -EINVAL;
hypercall.op = __HYPERVISOR_memory_op;
@@ -149,62 +146,40 @@ int xc_memory_op(int xc_handle,
case XENMEM_increase_reservation:
case XENMEM_decrease_reservation:
case XENMEM_populate_physmap:
- if ( mlock(reservation, sizeof(*reservation)) != 0 )
+ if ( lock_pages(reservation, sizeof(*reservation)) != 0 )
{
- PERROR("Could not mlock");
+ PERROR("Could not lock");
goto out1;
}
get_xen_guest_handle(extent_start, reservation->extent_start);
if ( (extent_start != NULL) &&
- (mlock(extent_start,
+ (lock_pages(extent_start,
reservation->nr_extents * sizeof(xen_pfn_t)) != 0) )
{
- PERROR("Could not mlock");
- safe_munlock(reservation, sizeof(*reservation));
+ PERROR("Could not lock");
+ unlock_pages(reservation, sizeof(*reservation));
goto out1;
}
break;
case XENMEM_machphys_mfn_list:
- if ( mlock(xmml, sizeof(*xmml)) != 0 )
+ if ( lock_pages(xmml, sizeof(*xmml)) != 0 )
{
- PERROR("Could not mlock");
+ PERROR("Could not lock");
goto out1;
}
get_xen_guest_handle(extent_start, xmml->extent_start);
- if ( mlock(extent_start,
+ if ( lock_pages(extent_start,
xmml->max_extents * sizeof(xen_pfn_t)) != 0 )
{
- PERROR("Could not mlock");
- safe_munlock(xmml, sizeof(*xmml));
+ PERROR("Could not lock");
+ unlock_pages(xmml, sizeof(*xmml));
goto out1;
}
break;
case XENMEM_add_to_physmap:
- if ( mlock(arg, sizeof(struct xen_add_to_physmap)) )
- {
- PERROR("Could not mlock");
- goto out1;
- }
- break;
- case XENMEM_translate_gpfn_list:
- if ( mlock(trans, sizeof(*trans)) != 0 )
- {
- PERROR("Could not mlock");
- goto out1;
- }
- get_xen_guest_handle(gpfn_list, trans->gpfn_list);
- if ( mlock(gpfn_list, trans->nr_gpfns * sizeof(xen_pfn_t)) != 0 )
+ if ( lock_pages(arg, sizeof(struct xen_add_to_physmap)) )
{
- PERROR("Could not mlock");
- safe_munlock(trans, sizeof(*trans));
- goto out1;
- }
- get_xen_guest_handle(mfn_list, trans->mfn_list);
- if ( mlock(mfn_list, trans->nr_gpfns * sizeof(xen_pfn_t)) != 0 )
- {
- PERROR("Could not mlock");
- safe_munlock(gpfn_list, trans->nr_gpfns * sizeof(xen_pfn_t));
- safe_munlock(trans, sizeof(*trans));
+ PERROR("Could not lock");
goto out1;
}
break;
@@ -217,27 +192,20 @@ int xc_memory_op(int xc_handle,
case XENMEM_increase_reservation:
case XENMEM_decrease_reservation:
case XENMEM_populate_physmap:
- safe_munlock(reservation, sizeof(*reservation));
+ unlock_pages(reservation, sizeof(*reservation));
get_xen_guest_handle(extent_start, reservation->extent_start);
if ( extent_start != NULL )
- safe_munlock(extent_start,
+ unlock_pages(extent_start,
reservation->nr_extents * sizeof(xen_pfn_t));
break;
case XENMEM_machphys_mfn_list:
- safe_munlock(xmml, sizeof(*xmml));
+ unlock_pages(xmml, sizeof(*xmml));
get_xen_guest_handle(extent_start, xmml->extent_start);
- safe_munlock(extent_start,
+ unlock_pages(extent_start,
xmml->max_extents * sizeof(xen_pfn_t));
break;
case XENMEM_add_to_physmap:
- safe_munlock(arg, sizeof(struct xen_add_to_physmap));
- break;
- case XENMEM_translate_gpfn_list:
- get_xen_guest_handle(mfn_list, trans->mfn_list);
- safe_munlock(mfn_list, trans->nr_gpfns * sizeof(xen_pfn_t));
- get_xen_guest_handle(gpfn_list, trans->gpfn_list);
- safe_munlock(gpfn_list, trans->nr_gpfns * sizeof(xen_pfn_t));
- safe_munlock(trans, sizeof(*trans));
+ unlock_pages(arg, sizeof(struct xen_add_to_physmap));
break;
}
@@ -279,15 +247,15 @@ int xc_get_pfn_list(int xc_handle,
memset(pfn_buf, 0, max_pfns * sizeof(xen_pfn_t));
#endif
- if ( mlock(pfn_buf, max_pfns * sizeof(xen_pfn_t)) != 0 )
+ if ( lock_pages(pfn_buf, max_pfns * sizeof(xen_pfn_t)) != 0 )
{
- PERROR("xc_get_pfn_list: pfn_buf mlock failed");
+ PERROR("xc_get_pfn_list: pfn_buf lock failed");
return -1;
}
ret = do_domctl(xc_handle, &domctl);
- safe_munlock(pfn_buf, max_pfns * sizeof(xen_pfn_t));
+ unlock_pages(pfn_buf, max_pfns * sizeof(xen_pfn_t));
#if 0
#ifdef DEBUG
@@ -344,28 +312,6 @@ int xc_clear_domain_page(int xc_handle,
return 0;
}
-unsigned long xc_get_filesz(int fd)
-{
- uint16_t sig;
- uint32_t _sz = 0;
- unsigned long sz;
-
- lseek(fd, 0, SEEK_SET);
- if ( read(fd, &sig, sizeof(sig)) != sizeof(sig) )
- return 0;
- sz = lseek(fd, 0, SEEK_END);
- if ( sig == 0x8b1f ) /* GZIP signature? */
- {
- lseek(fd, -4, SEEK_END);
- if ( read(fd, &_sz, 4) != 4 )
- return 0;
- sz = _sz;
- }
- lseek(fd, 0, SEEK_SET);
-
- return sz;
-}
-
void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
int xch, uint32_t dom, xen_pfn_t *parray,
unsigned long vstart)
@@ -419,7 +365,7 @@ int xc_version(int xc_handle, int cmd, void *arg)
break;
}
- if ( (argsize != 0) && (mlock(arg, argsize) != 0) )
+ if ( (argsize != 0) && (lock_pages(arg, argsize) != 0) )
{
PERROR("Could not lock memory for version hypercall");
return -ENOMEM;
@@ -433,7 +379,7 @@ int xc_version(int xc_handle, int cmd, void *arg)
rc = do_xen_version(xc_handle, cmd, arg);
if ( argsize != 0 )
- safe_munlock(arg, argsize);
+ unlock_pages(arg, argsize);
return rc;
}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 513daed6f9..20f7a9b445 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -30,6 +30,9 @@
#define DECLARE_SYSCTL struct xen_sysctl sysctl
#endif
+#undef PAGE_SHIFT
+#undef PAGE_SIZE
+#undef PAGE_MASK
#define PAGE_SHIFT XC_PAGE_SHIFT
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
@@ -56,11 +59,6 @@
#define PPRINTF(_f, _a...)
#endif
-#define ERR(_f, _a...) do { \
- DPRINTF(_f ": %d\n" , ## _a, errno); \
- fflush(stderr); } \
-while (0)
-
#define ERROR(_m, _a...) \
do { \
int __saved_errno = errno; \
@@ -68,6 +66,9 @@ do { \
errno = __saved_errno; \
} while (0)
+int lock_pages(void *addr, size_t len);
+void unlock_pages(void *addr, size_t len);
+
#define PERROR(_m, _a...) \
do { \
int __saved_errno = errno; \
@@ -106,7 +107,7 @@ static inline int do_domctl(int xc_handle, struct xen_domctl *domctl)
hypercall.op = __HYPERVISOR_domctl;
hypercall.arg[0] = (unsigned long)domctl;
- if ( mlock(domctl, sizeof(*domctl)) != 0 )
+ if ( lock_pages(domctl, sizeof(*domctl)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out1;
@@ -119,7 +120,7 @@ static inline int do_domctl(int xc_handle, struct xen_domctl *domctl)
" rebuild the user-space tool set?\n");
}
- safe_munlock(domctl, sizeof(*domctl));
+ unlock_pages(domctl, sizeof(*domctl));
out1:
return ret;
@@ -135,7 +136,7 @@ static inline int do_sysctl(int xc_handle, struct xen_sysctl *sysctl)
hypercall.op = __HYPERVISOR_sysctl;
hypercall.arg[0] = (unsigned long)sysctl;
- if ( mlock(sysctl, sizeof(*sysctl)) != 0 )
+ if ( lock_pages(sysctl, sizeof(*sysctl)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out1;
@@ -148,7 +149,7 @@ static inline int do_sysctl(int xc_handle, struct xen_sysctl *sysctl)
" rebuild the user-space tool set?\n");
}
- safe_munlock(sysctl, sizeof(*sysctl));
+ unlock_pages(sysctl, sizeof(*sysctl));
out1:
return ret;
@@ -157,4 +158,9 @@ static inline int do_sysctl(int xc_handle, struct xen_sysctl *sysctl)
int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
privcmd_mmap_entry_t *entries, int nr);
+void *map_domain_va_core(unsigned long domfd, int cpu, void *guest_va,
+ vcpu_guest_context_t *ctxt);
+int xc_waitdomain_core(int xc_handle, int domain, int *status,
+ int options, vcpu_guest_context_t *ctxt);
+
#endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_ptrace.c b/tools/libxc/xc_ptrace.c
index ab9c2fae45..66bbf9539b 100644
--- a/tools/libxc/xc_ptrace.c
+++ b/tools/libxc/xc_ptrace.c
@@ -1,5 +1,3 @@
-#define XC_PTRACE_PRIVATE
-
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <time.h>
@@ -38,8 +36,9 @@ static char *ptrace_names[] = {
};
#endif
-static int current_domid = -1;
-static int current_isfile;
+static int current_domid = -1;
+static int current_isfile;
+static int current_is_hvm;
static uint64_t online_cpumap;
static uint64_t regs_valid;
@@ -48,7 +47,6 @@ static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
extern int ffsll(long long int);
#define FOREACH_CPU(cpumap, i) for ( cpumap = online_cpumap; (i = ffsll(cpumap)); cpumap &= ~(1 << (index - 1)) )
-
static int
fetch_regs(int xc_handle, int cpu, int *online)
{
@@ -174,7 +172,7 @@ to_ma(int cpu,
{
unsigned long maddr = in_addr;
- if ( (ctxt[cpu].flags & VGCF_HVM_GUEST) && paging_enabled(&ctxt[cpu]) )
+ if ( current_is_hvm && paging_enabled(&ctxt[cpu]) )
maddr = page_array[maddr >> PAGE_SHIFT] << PAGE_SHIFT;
return maddr;
}
@@ -251,7 +249,7 @@ map_domain_va_pae(
if ( !(l2e & _PAGE_PRESENT) )
return NULL;
l1p = to_ma(cpu, l2e);
- l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, l1p >> PAGE_SHIFT);
+ l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l1p >> PAGE_SHIFT);
if ( l1 == NULL )
return NULL;
@@ -281,7 +279,6 @@ map_domain_va_64(
uint64_t *l4, *l3, *l2, *l1;
static void *v[MAX_VIRT_CPUS];
-
if ((ctxt[cpu].ctrlreg[4] & 0x20) == 0 ) /* legacy ia32 mode */
return map_domain_va_32(xc_handle, cpu, guest_va, perm);
@@ -309,7 +306,6 @@ map_domain_va_64(
if ( l2 == NULL )
return NULL;
- l1 = NULL;
l2e = l2[l2_table_offset(va)];
munmap(l2, PAGE_SIZE);
if ( !(l2e & _PAGE_PRESENT) )
@@ -318,11 +314,12 @@ map_domain_va_64(
if (l2e & 0x80) { /* 2M pages */
p = to_ma(cpu, (l1p + l1_table_offset(va)) << PAGE_SHIFT);
} else { /* 4K pages */
- l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, l1p >> PAGE_SHIFT);
+ l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l1p >> PAGE_SHIFT);
if ( l1 == NULL )
return NULL;
l1e = l1[l1_table_offset(va)];
+ munmap(l1, PAGE_SIZE);
if ( !(l1e & _PAGE_PRESENT) )
return NULL;
p = to_ma(cpu, l1e);
@@ -330,8 +327,6 @@ map_domain_va_64(
if ( v[cpu] != NULL )
munmap(v[cpu], PAGE_SIZE);
v[cpu] = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p >> PAGE_SHIFT);
- if (l1)
- munmap(l1, PAGE_SIZE);
if ( v[cpu] == NULL )
return NULL;
@@ -448,7 +443,7 @@ __xc_waitdomain(
goto done;
}
- if ( !(domctl.u.getdomaininfo.flags & DOMFLAGS_PAUSED) )
+ if ( !(domctl.u.getdomaininfo.flags & XEN_DOMINF_paused) )
{
nanosleep(&ts,NULL);
goto retry;
@@ -487,11 +482,11 @@ xc_ptrace(
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
if (current_isfile)
- guest_va = (unsigned long *)map_domain_va_core(current_domid,
- cpu, addr, ctxt);
+ guest_va = (unsigned long *)map_domain_va_core(
+ current_domid, cpu, addr, ctxt);
else
- guest_va = (unsigned long *)map_domain_va(xc_handle,
- cpu, addr, PROT_READ);
+ guest_va = (unsigned long *)map_domain_va(
+ xc_handle, cpu, addr, PROT_READ);
if ( guest_va == NULL )
goto out_error;
retval = *guest_va;
@@ -501,11 +496,11 @@ xc_ptrace(
case PTRACE_POKEDATA:
/* XXX assume that all CPUs have the same address space */
if (current_isfile)
- guest_va = (unsigned long *)map_domain_va_core(current_domid,
- cpu, addr, ctxt);
+ guest_va = (unsigned long *)map_domain_va_core(
+ current_domid, cpu, addr, ctxt);
else
- guest_va = (unsigned long *)map_domain_va(xc_handle,
- cpu, addr, PROT_READ|PROT_WRITE);
+ guest_va = (unsigned long *)map_domain_va(
+ xc_handle, cpu, addr, PROT_READ|PROT_WRITE);
if ( guest_va == NULL )
goto out_error;
*guest_va = (unsigned long)data;
@@ -595,10 +590,11 @@ xc_ptrace(
retval = do_domctl(xc_handle, &domctl);
if ( retval || (domctl.domain != current_domid) )
goto out_error_domctl;
- if ( domctl.u.getdomaininfo.flags & DOMFLAGS_PAUSED )
+ if ( domctl.u.getdomaininfo.flags & XEN_DOMINF_paused )
IPRINTF("domain currently paused\n");
else if ((retval = xc_domain_pause(xc_handle, current_domid)))
goto out_error_domctl;
+ current_is_hvm = !!(domctl.u.getdomaininfo.flags&XEN_DOMINF_hvm_guest);
domctl.cmd = XEN_DOMCTL_setdebugging;
domctl.domain = current_domid;
domctl.u.setdebugging.enable = 1;
@@ -611,17 +607,12 @@ xc_ptrace(
online_vcpus_changed(cpumap);
break;
- case PTRACE_SETFPREGS:
- case PTRACE_SETFPXREGS:
- case PTRACE_PEEKUSER:
- case PTRACE_POKEUSER:
- case PTRACE_SYSCALL:
- case PTRACE_KILL:
- goto out_unsupported; /* XXX not yet supported */
-
case PTRACE_TRACEME:
IPRINTF("PTRACE_TRACEME is an invalid request under Xen\n");
goto out_error;
+
+ default:
+ goto out_unsupported; /* XXX not yet supported */
}
return retval;
diff --git a/tools/libxc/xc_ptrace.h b/tools/libxc/xc_ptrace.h
index 1c3f10b1d0..baaadb5b0b 100644
--- a/tools/libxc/xc_ptrace.h
+++ b/tools/libxc/xc_ptrace.h
@@ -1,9 +1,6 @@
#ifndef XC_PTRACE_
#define XC_PTRACE_
-#include <thread_db.h>
-
-#ifdef XC_PTRACE_PRIVATE
#define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */
#define X86_CR0_PG 0x80000000 /* Paging (RW) */
#define BSD_PAGE_MASK (PAGE_SIZE-1)
@@ -160,25 +157,4 @@ struct gdb_regs {
}
#endif
-#endif
-
-typedef void (*thr_ev_handler_t)(long);
-
-void xc_register_event_handler(
- thr_ev_handler_t h,
- td_event_e e);
-
-long xc_ptrace(
- int xc_handle,
- enum __ptrace_request request,
- uint32_t domid,
- long addr,
- long data);
-
-int xc_waitdomain(
- int xc_handle,
- int domain,
- int *status,
- int options);
-
#endif /* XC_PTRACE */
diff --git a/tools/libxc/xc_ptrace_core.c b/tools/libxc/xc_ptrace_core.c
index d57da3f172..3ae69d3ac2 100644
--- a/tools/libxc/xc_ptrace_core.c
+++ b/tools/libxc/xc_ptrace_core.c
@@ -1,5 +1,3 @@
-#define XC_PTRACE_PRIVATE
-
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "xc_private.h"
@@ -9,6 +7,7 @@
/* XXX application state */
+static int current_is_hvm = 0;
static long nr_pages = 0;
static unsigned long *p2m_array = NULL;
static unsigned long *m2p_array = NULL;
@@ -26,8 +25,8 @@ map_mtop_offset(unsigned long ma)
void *
-map_domain_va_core(unsigned long domfd, int cpu, void * guest_va,
- vcpu_guest_context_t *ctxt)
+map_domain_va_core(unsigned long domfd, int cpu, void *guest_va,
+ vcpu_guest_context_t *ctxt)
{
unsigned long pde, page;
unsigned long va = (unsigned long)guest_va;
@@ -57,7 +56,7 @@ map_domain_va_core(unsigned long domfd, int cpu, void * guest_va,
}
if ((pde = cr3_virt[cpu][l2_table_offset_i386(va)]) == 0) /* logical address */
return NULL;
- if (ctxt[cpu].flags & VGCF_HVM_GUEST)
+ if (current_is_hvm)
pde = p2m_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
if (pde != pde_phys[cpu])
{
@@ -73,7 +72,7 @@ map_domain_va_core(unsigned long domfd, int cpu, void * guest_va,
}
if ((page = pde_virt[cpu][l1_table_offset_i386(va)]) == 0) /* logical address */
return NULL;
- if (ctxt[cpu].flags & VGCF_HVM_GUEST)
+ if (current_is_hvm)
page = p2m_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
if (page != page_phys[cpu])
{
@@ -106,17 +105,18 @@ xc_waitdomain_core(
int i;
xc_core_header_t header;
- if (nr_pages == 0)
+ if ( nr_pages == 0 )
{
-
if (read(domfd, &header, sizeof(header)) != sizeof(header))
return -1;
- if (header.xch_magic != XC_CORE_MAGIC) {
- IPRINTF("Magic number missmatch: 0x%08x (file) != "
- " 0x%08x (code)\n", header.xch_magic,
- XC_CORE_MAGIC);
- return -1;
+ current_is_hvm = (header.xch_magic == XC_CORE_MAGIC_HVM);
+ if ( !current_is_hvm && (header.xch_magic != XC_CORE_MAGIC) )
+ {
+ IPRINTF("Magic number missmatch: 0x%08x (file) != "
+ " 0x%08x (code)\n", header.xch_magic,
+ XC_CORE_MAGIC);
+ return -1;
}
nr_pages = header.xch_nr_pages;
diff --git a/tools/libxc/xc_solaris.c b/tools/libxc/xc_solaris.c
new file mode 100644
index 0000000000..902de64fa4
--- /dev/null
+++ b/tools/libxc/xc_solaris.c
@@ -0,0 +1,235 @@
+/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * 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, version 2 of the
+ * License.
+ */
+
+#include "xc_private.h"
+
+#include <xen/memory.h>
+#include <xen/sys/evtchn.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int xc_interface_open(void)
+{
+ int flags, saved_errno;
+ int fd = open("/dev/xen/privcmd", O_RDWR);
+
+ if ( fd == -1 )
+ {
+ PERROR("Could not obtain handle on privileged command interface");
+ return -1;
+ }
+
+ /* Although we return the file handle as the 'xc handle' the API
+ does not specify / guarentee that this integer is in fact
+ a file handle. Thus we must take responsiblity to ensure
+ it doesn't propagate (ie leak) outside the process */
+ if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+ {
+ PERROR("Could not get file handle flags");
+ goto error;
+ }
+ flags |= FD_CLOEXEC;
+ if ( fcntl(fd, F_SETFD, flags) < 0 )
+ {
+ PERROR("Could not set file handle flags");
+ goto error;
+ }
+
+ return fd;
+
+ error:
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return -1;
+}
+
+int xc_interface_close(int xc_handle)
+{
+ return close(xc_handle);
+}
+
+void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot,
+ xen_pfn_t *arr, int num)
+{
+ privcmd_mmapbatch_t ioctlx;
+ void *addr;
+ addr = mmap(NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0);
+ if ( addr == MAP_FAILED )
+ return NULL;
+
+ ioctlx.num=num;
+ ioctlx.dom=dom;
+ ioctlx.addr=(unsigned long)addr;
+ ioctlx.arr=arr;
+ if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
+ {
+ int saved_errno = errno;
+ perror("XXXXXXXX");
+ (void)munmap(addr, num*PAGE_SIZE);
+ errno = saved_errno;
+ return NULL;
+ }
+ return addr;
+
+}
+
+void *xc_map_foreign_range(int xc_handle, uint32_t dom,
+ int size, int prot,
+ unsigned long mfn)
+{
+ privcmd_mmap_t ioctlx;
+ privcmd_mmap_entry_t entry;
+ void *addr;
+ addr = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0);
+ if ( addr == MAP_FAILED )
+ return NULL;
+
+ ioctlx.num=1;
+ ioctlx.dom=dom;
+ ioctlx.entry=&entry;
+ entry.va=(unsigned long) addr;
+ entry.mfn=mfn;
+ entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
+ if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx) < 0 )
+ {
+ int saved_errno = errno;
+ (void)munmap(addr, size);
+ errno = saved_errno;
+ return NULL;
+ }
+ return addr;
+}
+
+int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
+ privcmd_mmap_entry_t *entries, int nr)
+{
+ privcmd_mmap_t ioctlx;
+
+ ioctlx.num = nr;
+ ioctlx.dom = dom;
+ ioctlx.entry = entries;
+
+ return ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx);
+}
+
+static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data)
+{
+ return ioctl(xc_handle, cmd, data);
+}
+
+int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall)
+{
+ return do_privcmd(xc_handle,
+ IOCTL_PRIVCMD_HYPERCALL,
+ (unsigned long)hypercall);
+}
+
+int xc_evtchn_open(void)
+{
+ int fd;
+
+ if ( (fd = open("/dev/xen/evtchn", O_RDWR)) == -1 )
+ {
+ PERROR("Could not open event channel interface");
+ return -1;
+ }
+
+ return fd;
+}
+
+int xc_evtchn_close(int xce_handle)
+{
+ return close(xce_handle);
+}
+
+int xc_evtchn_fd(int xce_handle)
+{
+ return xce_handle;
+}
+
+int xc_evtchn_notify(int xce_handle, evtchn_port_t port)
+{
+ struct ioctl_evtchn_notify notify;
+
+ notify.port = port;
+
+ return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, &notify);
+}
+
+evtchn_port_t xc_evtchn_bind_interdomain(int xce_handle, int domid,
+ evtchn_port_t remote_port)
+{
+ struct ioctl_evtchn_bind_interdomain bind;
+
+ bind.remote_domain = domid;
+ bind.remote_port = remote_port;
+
+ return ioctl(xce_handle, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
+}
+
+int xc_evtchn_unbind(int xce_handle, evtchn_port_t port)
+{
+ struct ioctl_evtchn_unbind unbind;
+
+ unbind.port = port;
+
+ return ioctl(xce_handle, IOCTL_EVTCHN_UNBIND, &unbind);
+}
+
+evtchn_port_t xc_evtchn_bind_virq(int xce_handle, unsigned int virq)
+{
+ struct ioctl_evtchn_bind_virq bind;
+
+ bind.virq = virq;
+
+ return ioctl(xce_handle, IOCTL_EVTCHN_BIND_VIRQ, &bind);
+}
+
+static int dorw(int fd, char *data, size_t size, int do_write)
+{
+ size_t offset = 0;
+ ssize_t len;
+
+ while ( offset < size )
+ {
+ if (do_write)
+ len = write(fd, data + offset, size - offset);
+ else
+ len = read(fd, data + offset, size - offset);
+
+ if ( len == -1 )
+ {
+ if ( errno == EINTR )
+ continue;
+ return -1;
+ }
+
+ offset += len;
+ }
+
+ return 0;
+}
+
+evtchn_port_t xc_evtchn_pending(int xce_handle)
+{
+ evtchn_port_t port;
+
+ if ( dorw(xce_handle, (char *)&port, sizeof(port), 0) == -1 )
+ return -1;
+
+ return port;
+}
+
+int xc_evtchn_unmask(int xce_handle, evtchn_port_t port)
+{
+ return dorw(xce_handle, (char *)&port, sizeof(port), 1);
+}
diff --git a/tools/libxc/xc_tbuf.c b/tools/libxc/xc_tbuf.c
index 13614f0f8a..920c5b5abd 100644
--- a/tools/libxc/xc_tbuf.c
+++ b/tools/libxc/xc_tbuf.c
@@ -57,7 +57,7 @@ int xc_tbuf_get_size(int xc_handle, unsigned long *size)
return rc;
}
-int xc_tbuf_enable(int xc_handle, size_t cnt, unsigned long *mfn,
+int xc_tbuf_enable(int xc_handle, unsigned long pages, unsigned long *mfn,
unsigned long *size)
{
DECLARE_SYSCTL;
@@ -68,7 +68,7 @@ int xc_tbuf_enable(int xc_handle, size_t cnt, unsigned long *mfn,
* set (since trace buffers cannot be reallocated). If we really have no
* buffers at all then tbuf_enable() will fail, so this is safe.
*/
- (void)xc_tbuf_set_size(xc_handle, cnt);
+ (void)xc_tbuf_set_size(xc_handle, pages);
if ( tbuf_enable(xc_handle, 1) != 0 )
return -1;
@@ -104,7 +104,7 @@ int xc_tbuf_set_cpu_mask(int xc_handle, uint32_t mask)
set_xen_guest_handle(sysctl.u.tbuf_op.cpu_mask.bitmap, (uint8_t *)&mask);
sysctl.u.tbuf_op.cpu_mask.nr_cpus = sizeof(mask) * 8;
- if ( mlock(&mask, sizeof(mask)) != 0 )
+ if ( lock_pages(&mask, sizeof(mask)) != 0 )
{
PERROR("Could not lock memory for Xen hypercall");
goto out;
@@ -112,7 +112,7 @@ int xc_tbuf_set_cpu_mask(int xc_handle, uint32_t mask)
ret = do_sysctl(xc_handle, &sysctl);
- safe_munlock(&mask, sizeof(mask));
+ unlock_pages(&mask, sizeof(mask));
out:
return ret;
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 0a5cfadd3d..c646d18ea8 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -16,7 +16,6 @@
#include <stddef.h>
#include <stdint.h>
-#include <sys/ptrace.h>
#include <xen/xen.h>
#include <xen/domctl.h>
#include <xen/sysctl.h>
@@ -48,10 +47,9 @@
#define rmb() __asm__ __volatile__ ( "lfence" : : : "memory")
#define wmb() __asm__ __volatile__ ( "" : : : "memory")
#elif defined(__ia64__)
-/* FIXME */
-#define mb()
-#define rmb()
-#define wmb()
+#define mb() __asm__ __volatile__ ("mf" ::: "memory")
+#define rmb() __asm__ __volatile__ ("mf" ::: "memory")
+#define wmb() __asm__ __volatile__ ("mf" ::: "memory")
#elif defined(__powerpc__)
/* XXX loosen these up later */
#define mb() __asm__ __volatile__ ("sync" : : : "memory")
@@ -92,6 +90,16 @@ int xc_interface_open(void);
int xc_interface_close(int xc_handle);
/*
+ * KERNEL INTERFACES
+ */
+
+/*
+ * Resolve a kernel device name (e.g., "evtchn", "blktap0") into a kernel
+ * device number. Returns -1 on error (and sets errno).
+ */
+int xc_find_device_number(const char *name);
+
+/*
* DOMAIN DEBUGGING FUNCTIONS
*/
@@ -104,36 +112,45 @@ typedef struct xc_core_header {
unsigned int xch_pages_offset;
} xc_core_header_t;
-#define XC_CORE_MAGIC 0xF00FEBED
+#define XC_CORE_MAGIC 0xF00FEBED
+#define XC_CORE_MAGIC_HVM 0xF00FEBEE
-long xc_ptrace_core(
+#ifdef __linux__
+
+#include <sys/ptrace.h>
+#include <thread_db.h>
+
+typedef void (*thr_ev_handler_t)(long);
+
+void xc_register_event_handler(
+ thr_ev_handler_t h,
+ td_event_e e);
+
+long xc_ptrace(
int xc_handle,
enum __ptrace_request request,
- uint32_t domid,
+ uint32_t domid,
long addr,
- long data,
- vcpu_guest_context_t *ctxt);
-void * map_domain_va_core(
- unsigned long domfd,
- int cpu,
- void *guest_va,
- vcpu_guest_context_t *ctxt);
-int xc_waitdomain_core(
+ long data);
+
+int xc_waitdomain(
int xc_handle,
int domain,
int *status,
- int options,
- vcpu_guest_context_t *ctxt);
+ int options);
+
+#endif /* __linux__ */
/*
* DOMAIN MANAGEMENT FUNCTIONS
*/
-typedef struct {
+typedef struct xc_dominfo {
uint32_t domid;
uint32_t ssidref;
unsigned int dying:1, crashed:1, shutdown:1,
- paused:1, blocked:1, running:1;
+ paused:1, blocked:1, running:1,
+ hvm:1;
unsigned int shutdown_reason; /* only meaningful if shutdown==1 */
unsigned long nr_pages;
unsigned long shared_info_frame;
@@ -148,6 +165,7 @@ typedef xen_domctl_getdomaininfo_t xc_domaininfo_t;
int xc_domain_create(int xc_handle,
uint32_t ssidref,
xen_domain_handle_t handle,
+ uint32_t flags,
uint32_t *pdomid);
@@ -421,12 +439,6 @@ int xc_domain_memory_populate_physmap(int xc_handle,
unsigned int address_bits,
xen_pfn_t *extent_start);
-int xc_domain_translate_gpfn_list(int xc_handle,
- uint32_t domid,
- unsigned long nr_gpfns,
- xen_pfn_t *gpfn_list,
- xen_pfn_t *mfn_list);
-
int xc_domain_ioport_permission(int xc_handle,
uint32_t domid,
uint32_t first_port,
@@ -496,6 +508,8 @@ unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
int xc_get_pfn_list(int xc_handle, uint32_t domid, xen_pfn_t *pfn_buf,
unsigned long max_pfns);
+unsigned long xc_ia64_fpsr_default(void);
+
int xc_ia64_get_pfn_list(int xc_handle, uint32_t domid,
xen_pfn_t *pfn_buf,
unsigned int start_page, unsigned int nr_pages);
@@ -536,8 +550,8 @@ long xc_get_tot_pages(int xc_handle, uint32_t domid);
* Gets the machine address of the trace pointer area and the size of the
* per CPU buffers.
*/
-int xc_tbuf_enable(int xc_handle, size_t cnt, unsigned long *mfn,
- unsigned long *size);
+int xc_tbuf_enable(int xc_handle, unsigned long pages,
+ unsigned long *mfn, unsigned long *size);
/*
* Disable tracing buffers.
@@ -590,7 +604,7 @@ int xc_add_mmu_update(int xc_handle, xc_mmu_t *mmu,
unsigned long long ptr, unsigned long long val);
int xc_finish_mmu_updates(int xc_handle, xc_mmu_t *mmu);
-int xc_acm_op(int xc_handle, int cmd, void *arg, size_t arg_size);
+int xc_acm_op(int xc_handle, int cmd, void *arg, unsigned long arg_size);
/*
* Return a handle to the event channel driver, or -1 on failure, in which case
@@ -646,4 +660,16 @@ evtchn_port_t xc_evtchn_pending(int xce_handle);
*/
int xc_evtchn_unmask(int xce_handle, evtchn_port_t port);
+int xc_hvm_set_pci_intx_level(
+ int xce_handle, domid_t dom,
+ uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx,
+ unsigned int level);
+int xc_hvm_set_isa_irq_level(
+ int xce_handle, domid_t dom,
+ uint8_t isa_irq,
+ unsigned int level);
+
+int xc_hvm_set_pci_link_route(
+ int xce_handle, domid_t dom, uint8_t link, uint8_t isa_irq);
+
#endif
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
index 948c03b509..777ee9f23b 100644
--- a/tools/libxc/xenguest.h
+++ b/tools/libxc/xenguest.h
@@ -48,8 +48,9 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
*
* @parm xc_handle a handle to an open hypervisor interface
* @parm domid the id of the domain
- * @param image_name name of the kernel image file
- * @param ramdisk_name name of the ramdisk image file
+ * @parm mem_mb memory size in megabytes
+ * @parm image_name name of the kernel image file
+ * @parm ramdisk_name name of the ramdisk image file
* @parm cmdline command line string
* @parm flags domain creation flags
* @parm store_evtchn the store event channel for this domain to use
@@ -60,6 +61,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
*/
int xc_linux_build(int xc_handle,
uint32_t domid,
+ unsigned int mem_mb,
const char *image_name,
const char *ramdisk_name,
const char *cmdline,
@@ -74,22 +76,24 @@ int xc_linux_build(int xc_handle,
* This function will create a domain for a paravirtualized Linux
* using buffers for kernel and initrd
*
- * @param xc_handle a handle to an open hypervisor interface
- * @param domid the id of the domain
- * @param image_buffer buffer containing kernel image
- * @param image_size size of the kernel image buffer
- * @param initrd_buffer name of the ramdisk image file
- * @param initrd_size size of the ramdisk buffer
- * @param cmdline command line string
- * @param flags domain creation flags
- * @param store_evtchn the store event channel for this domain to use
- * @param store_mfn returned with the mfn of the store page
- * @param console_evtchn the console event channel for this domain to use
- * @param conole_mfn returned with the mfn of the console page
+ * @parm xc_handle a handle to an open hypervisor interface
+ * @parm domid the id of the domain
+ * @parm mem_mb memory size in megabytes
+ * @parm image_buffer buffer containing kernel image
+ * @parm image_size size of the kernel image buffer
+ * @parm initrd_buffer name of the ramdisk image file
+ * @parm initrd_size size of the ramdisk buffer
+ * @parm cmdline command line string
+ * @parm flags domain creation flags
+ * @parm store_evtchn the store event channel for this domain to use
+ * @parm store_mfn returned with the mfn of the store page
+ * @parm console_evtchn the console event channel for this domain to use
+ * @parm conole_mfn returned with the mfn of the console page
* @return 0 on success, -1 on failure
*/
int xc_linux_build_mem(int xc_handle,
uint32_t domid,
+ unsigned int mem_mb,
const char *image_buffer,
unsigned long image_size,
const char *initrd_buffer,
@@ -105,24 +109,17 @@ int xc_linux_build_mem(int xc_handle,
int xc_hvm_build(int xc_handle,
uint32_t domid,
int memsize,
- const char *image_name,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn);
+ const char *image_name);
int xc_hvm_build_mem(int xc_handle,
uint32_t domid,
int memsize,
const char *image_buffer,
- unsigned long image_size,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn);
+ unsigned long image_size);
+
+int xc_set_hvm_param(
+ int handle, domid_t dom, int param, unsigned long value);
+int xc_get_hvm_param(
+ int handle, domid_t dom, int param, unsigned long *value);
#endif /* XENGUEST_H */
diff --git a/tools/libxc/xg_private.c b/tools/libxc/xg_private.c
index 083aafa7e6..1af646fc82 100644
--- a/tools/libxc/xg_private.c
+++ b/tools/libxc/xg_private.c
@@ -7,14 +7,31 @@
#include <stdlib.h>
#include <unistd.h>
#include <zlib.h>
+#include <strings.h>
#include "xg_private.h"
+int lock_pages(void *addr, size_t len)
+{
+ int e = 0;
+#ifndef __sun__
+ e = mlock(addr, len);
+#endif
+ return (e);
+}
+
+void unlock_pages(void *addr, size_t len)
+{
+#ifndef __sun__
+ safe_munlock(addr, len);
+#endif
+}
+
char *xc_read_image(const char *filename, unsigned long *size)
{
int kernel_fd = -1;
gzFile kernel_gfd = NULL;
- char *image = NULL;
+ char *image = NULL, *tmp;
unsigned int bytes;
if ( (filename == NULL) || (size == NULL) )
@@ -26,33 +43,58 @@ char *xc_read_image(const char *filename, unsigned long *size)
goto out;
}
- if ( (*size = xc_get_filesz(kernel_fd)) == 0 )
- {
- PERROR("Could not read kernel image");
- goto out;
- }
-
if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
{
PERROR("Could not allocate decompression state for state file");
goto out;
}
- if ( (image = malloc(*size)) == NULL )
+ *size = 0;
+
+#define CHUNK 1*1024*1024
+ while(1)
{
- PERROR("Could not allocate memory for kernel image");
- goto out;
+ if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
+ {
+ PERROR("Could not allocate memory for kernel image");
+ free(image);
+ image = NULL;
+ goto out;
+ }
+ image = tmp;
+
+ bytes = gzread(kernel_gfd, image + *size, CHUNK);
+ switch (bytes)
+ {
+ case -1:
+ PERROR("Error reading kernel image");
+ free(image);
+ image = NULL;
+ goto out;
+ case 0: /* EOF */
+ goto out;
+ default:
+ *size += bytes;
+ break;
+ }
}
+#undef CHUNK
- if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
+ out:
+ if ( *size == 0 )
+ {
+ PERROR("Could not read kernel image");
+ free(image);
+ image = NULL;
+ }
+ else if ( image )
{
- PERROR("Error reading kernel image, could not"
- " read the whole image (%d != %ld).", bytes, *size);
- free(image);
- image = NULL;
+ /* Shrink allocation to fit image. */
+ tmp = realloc(image, *size);
+ if ( tmp )
+ image = tmp;
}
- out:
if ( kernel_gfd != NULL )
gzclose(kernel_gfd);
else if ( kernel_fd >= 0 )
@@ -150,13 +192,7 @@ __attribute__((weak)) int xc_hvm_build(
int xc_handle,
uint32_t domid,
int memsize,
- const char *image_name,
- unsigned int vcpus,
- unsigned int pae,
- unsigned int acpi,
- unsigned int apic,
- unsigned int store_evtchn,
- unsigned long *store_mfn)
+ const char *image_name)
{
return -ENOSYS;
}
diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h
index c471e94cb6..64ac8fad48 100644
--- a/tools/libxc/xg_private.h
+++ b/tools/libxc/xg_private.h
@@ -79,10 +79,6 @@ unsigned long csum_page (void * page);
#define L4_PAGETABLE_ENTRIES 512
#endif
-#define PAGE_SHIFT XC_PAGE_SHIFT
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
typedef uint32_t l1_pgentry_32_t;
typedef uint32_t l2_pgentry_32_t;
typedef uint64_t l1_pgentry_64_t;
@@ -197,8 +193,6 @@ typedef struct mfn_mapper {
int xc_copy_to_domain_page(int xc_handle, uint32_t domid,
unsigned long dst_pfn, const char *src_page);
-unsigned long xc_get_filesz(int fd);
-
void xc_map_memcpy(unsigned long dst, const char *src, unsigned long size,
int xch, uint32_t dom, xen_pfn_t *parray,
unsigned long vstart);
diff --git a/tools/libxen/COPYING b/tools/libxen/COPYING
new file mode 100644
index 0000000000..b124cf5812
--- /dev/null
+++ b/tools/libxen/COPYING
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/tools/libxen/Makefile b/tools/libxen/Makefile
new file mode 100644
index 0000000000..88755ab6dc
--- /dev/null
+++ b/tools/libxen/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2006, XenSource Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+CFLAGS = -Iinclude \
+ $(shell xml2-config --cflags) \
+ $(shell curl-config --cflags) \
+ -W -Wall -Wmissing-prototypes -Werror -std=c99 -O2 -fPIC
+
+LDFLAGS = $(shell xml2-config --libs) \
+ $(shell curl-config --libs)
+
+test/test_bindings: test/test_bindings.o src/libxen.so
+ $(CC) $(LDFLAGS) -o $@ $< -L src -lxen
+
+src/libxen.so: $(patsubst %.c, %.o, $(wildcard src/*.c))
+ $(CC) -shared -o $@ $^
+
+.PHONY: clean
+clean:
+ rm -f `find -name *.o`
+ rm -f src/libxen.so
+ rm -f test/test_bindings
diff --git a/tools/libxen/README b/tools/libxen/README
new file mode 100644
index 0000000000..4aa9450381
--- /dev/null
+++ b/tools/libxen/README
@@ -0,0 +1,54 @@
+Xen API C Bindings
+==================
+
+This distribution is the source code to the proposed Xen API C bindings.
+
+The Xen API project will define an XML-RPC protocol for remote and local
+management of Xen-based systems, and a set of bindings for these XML-RPC calls
+into a number of languages (this package contains those to the C language).
+
+The intention is to standardise these XML-RPC calls, and then the Xen project
+will guarantee that that wire protocol will be supported for the long term.
+The bindings will also be supported in the Xen tree, giving a stable
+foundation for Xen management tools and middlewares, in particular the Xen CIM
+providers and libvirt.
+
+THIS IS A WORK IN PROGRESS. The API and bindings are under active design and
+development, and this is a snapshot release for developers only. Both the API
+and the C bindings are scheduled to be stabilised by the Xen 3.0.4 release
+i.e. October 2006 at the earliest.
+
+These bindings are open-source (LGPL), and will be committed as libraries to
+the Xen trees for all to use after the Xen 3.0.3 release.
+
+We welcome any discussion about this library and the API in general. Please
+join the Xen-API mailing list if you are interested in this project. I (Ewan
+Mellor) will collate all the feedback from that list and push out new versions
+of the document and the bindings as and when.
+
+
+URLs
+----
+
+Xen-API wiki page:
+http://wiki.xensource.com/xenwiki/XenApi
+
+Xen-API mailing list:
+ http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-api
+
+
+Usage
+-----
+
+The bindings depend upon libxml2, the XML toolkit from the GNOME project; the
+test program depends upon libcurl3 also. On Debian, you need the packages
+libxml2-dev and libcurl3-dev.
+
+To compile, type make.
+
+To run the test, do
+
+LD_LIBRARY_PATH=src ./test/test_bindings <url> <username> <password>
+
+where <url> is the fragment of the server URL that follows the http://, for
+example "localhost:8005/RPC2".
diff --git a/tools/libxen/include/xen_boot_type.h b/tools/libxen/include/xen_boot_type.h
new file mode 100644
index 0000000000..8d3bc03588
--- /dev/null
+++ b/tools/libxen/include/xen_boot_type.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_BOOT_TYPE_H
+#define XEN_BOOT_TYPE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_boot_type
+{
+ /**
+ * boot an HVM guest using an emulated BIOS
+ */
+ XEN_BOOT_TYPE_BIOS,
+
+ /**
+ * boot from inside the machine using grub
+ */
+ XEN_BOOT_TYPE_GRUB,
+
+ /**
+ * boot from an external kernel
+ */
+ XEN_BOOT_TYPE_KERNEL_EXTERNAL,
+
+ /**
+ * boot from a kernel inside the guest filesystem
+ */
+ XEN_BOOT_TYPE_KERNEL_INTERNAL
+};
+
+
+typedef struct xen_boot_type_set
+{
+ size_t size;
+ enum xen_boot_type contents[];
+} xen_boot_type_set;
+
+/**
+ * Allocate a xen_boot_type_set of the given size.
+ */
+extern xen_boot_type_set *
+xen_boot_type_set_alloc(size_t size);
+
+/**
+ * Free the given xen_boot_type_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_boot_type_set_free(xen_boot_type_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_boot_type_to_string(enum xen_boot_type val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_boot_type
+xen_boot_type_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_boot_type_internal.h b/tools/libxen/include/xen_boot_type_internal.h
new file mode 100644
index 0000000000..968dc4a9ed
--- /dev/null
+++ b/tools/libxen/include/xen_boot_type_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_boot_type. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_BOOT_TYPE_INTERNAL_H
+#define XEN_BOOT_TYPE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_boot_type_abstract_type_;
+extern const abstract_type xen_boot_type_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_common.h b/tools/libxen/include/xen_common.h
new file mode 100644
index 0000000000..9f157bc5b3
--- /dev/null
+++ b/tools/libxen/include/xen_common.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2006 XenSource, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_COMMON_H
+#define XEN_COMMON_H
+
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "xen_host_decl.h"
+
+
+typedef bool (*xen_result_func)(const void *data, size_t len,
+ void *result_handle);
+
+
+/**
+ * len does not include a terminating \0.
+ */
+typedef int (*xen_call_func)(const void *, size_t len, void *user_handle,
+ void *result_handle,
+ xen_result_func result_func);
+
+
+typedef struct
+{
+ xen_call_func call_func;
+ void *handle;
+ const char *session_id;
+ bool ok;
+ char **error_description;
+ int error_description_count;
+} xen_session;
+
+
+struct xen_task_;
+typedef struct xen_task_ * xen_task_id;
+
+
+typedef struct
+{
+ int progress;
+ long eta;
+ /* !!! RESULT */
+} xen_task_status;
+
+
+typedef struct
+{
+ int major;
+ int minor;
+ int patch;
+ char *extraversion;
+} xen_version;
+
+
+/**
+ * Free the given xen_version, and all referenced values.
+ */
+extern void xen_version_free(xen_version *version);
+
+
+/**
+ * Return the version of this client-side library. This will be the major,
+ * minor, and extraversion of the Xen release with which it was released,
+ * plus the library's own version as the patch.
+ */
+extern xen_version *xen_get_client_side_version();
+
+
+extern bool
+xen_uuid_string_to_bytes(char *uuid, char **bytes);
+
+
+extern bool
+xen_uuid_bytes_to_string(char *bytes, char **uuid);
+
+
+extern void
+xen_uuid_free(char *uuid);
+
+
+extern void
+xen_uuid_bytes_free(char *bytes);
+
+
+/**
+ * Initialise this library. Call this before starting to use this library.
+ * Note that since this library depends upon libxml2, you should also call
+ * xmlInitParser as appropriate for your program.
+ */
+extern
+void xen_init(void);
+
+
+/**
+ * Clear up this library. Call when you have finished using this library.
+ * Note that since this library depends upon libxml2, you should also call
+ * xmlCleanupParser as appropriate for your program.
+ */
+extern
+void xen_fini(void);
+
+
+/**
+ * Log in at the server, and allocate a xen_session to represent this session.
+ */
+extern xen_session *
+xen_session_login_with_password(xen_call_func call_func, void *handle,
+ const char *uname, const char *pwd);
+
+
+/**
+ * Log out at the server, and free the xen_session.
+ */
+extern void
+xen_session_logout(xen_session *session);
+
+
+/**
+ * Set *result to be a handle to the host to which this session is connected.
+ */
+extern int
+xen_session_get_this_host(xen_session *session, xen_host *result);
+
+
+#endif
diff --git a/tools/libxen/include/xen_cpu_feature.h b/tools/libxen/include/xen_cpu_feature.h
new file mode 100644
index 0000000000..6e0614a8ac
--- /dev/null
+++ b/tools/libxen/include/xen_cpu_feature.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_CPU_FEATURE_H
+#define XEN_CPU_FEATURE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_cpu_feature
+{
+ /**
+ * Onboard FPU
+ */
+ XEN_CPU_FEATURE_FPU,
+
+ /**
+ * Virtual Mode Extensions
+ */
+ XEN_CPU_FEATURE_VME,
+
+ /**
+ * Debugging Extensions
+ */
+ XEN_CPU_FEATURE_DE,
+
+ /**
+ * Page Size Extensions
+ */
+ XEN_CPU_FEATURE_PSE,
+
+ /**
+ * Time Stamp Counter
+ */
+ XEN_CPU_FEATURE_TSC,
+
+ /**
+ * Model-Specific Registers, RDMSR, WRMSR
+ */
+ XEN_CPU_FEATURE_MSR,
+
+ /**
+ * Physical Address Extensions
+ */
+ XEN_CPU_FEATURE_PAE,
+
+ /**
+ * Machine Check Architecture
+ */
+ XEN_CPU_FEATURE_MCE,
+
+ /**
+ * CMPXCHG8 instruction
+ */
+ XEN_CPU_FEATURE_CX8,
+
+ /**
+ * Onboard APIC
+ */
+ XEN_CPU_FEATURE_APIC,
+
+ /**
+ * SYSENTER/SYSEXIT
+ */
+ XEN_CPU_FEATURE_SEP,
+
+ /**
+ * Memory Type Range Registers
+ */
+ XEN_CPU_FEATURE_MTRR,
+
+ /**
+ * Page Global Enable
+ */
+ XEN_CPU_FEATURE_PGE,
+
+ /**
+ * Machine Check Architecture
+ */
+ XEN_CPU_FEATURE_MCA,
+
+ /**
+ * CMOV instruction (FCMOVCC and FCOMI too if FPU present)
+ */
+ XEN_CPU_FEATURE_CMOV,
+
+ /**
+ * Page Attribute Table
+ */
+ XEN_CPU_FEATURE_PAT,
+
+ /**
+ * 36-bit PSEs
+ */
+ XEN_CPU_FEATURE_PSE36,
+
+ /**
+ * Processor serial number
+ */
+ XEN_CPU_FEATURE_PN,
+
+ /**
+ * Supports the CLFLUSH instruction
+ */
+ XEN_CPU_FEATURE_CLFLSH,
+
+ /**
+ * Debug Trace Store
+ */
+ XEN_CPU_FEATURE_DTES,
+
+ /**
+ * ACPI via MSR
+ */
+ XEN_CPU_FEATURE_ACPI,
+
+ /**
+ * Multimedia Extensions
+ */
+ XEN_CPU_FEATURE_MMX,
+
+ /**
+ * FXSAVE and FXRSTOR instructions (fast save and restore
+ */
+ XEN_CPU_FEATURE_FXSR,
+
+ /**
+ * Streaming SIMD Extensions
+ */
+ XEN_CPU_FEATURE_XMM,
+
+ /**
+ * Streaming SIMD Extensions-2
+ */
+ XEN_CPU_FEATURE_XMM2,
+
+ /**
+ * CPU self snoop
+ */
+ XEN_CPU_FEATURE_SELFSNOOP,
+
+ /**
+ * Hyper-Threading
+ */
+ XEN_CPU_FEATURE_HT,
+
+ /**
+ * Automatic clock control
+ */
+ XEN_CPU_FEATURE_ACC,
+
+ /**
+ * IA-64 processor
+ */
+ XEN_CPU_FEATURE_IA64,
+
+ /**
+ * SYSCALL/SYSRET
+ */
+ XEN_CPU_FEATURE_SYSCALL,
+
+ /**
+ * MP Capable.
+ */
+ XEN_CPU_FEATURE_MP,
+
+ /**
+ * Execute Disable
+ */
+ XEN_CPU_FEATURE_NX,
+
+ /**
+ * AMD MMX extensions
+ */
+ XEN_CPU_FEATURE_MMXEXT,
+
+ /**
+ * Long Mode (x86-64)
+ */
+ XEN_CPU_FEATURE_LM,
+
+ /**
+ * AMD 3DNow! extensions
+ */
+ XEN_CPU_FEATURE_3DNOWEXT,
+
+ /**
+ * 3DNow!
+ */
+ XEN_CPU_FEATURE_3DNOW,
+
+ /**
+ * CPU in recovery mode
+ */
+ XEN_CPU_FEATURE_RECOVERY,
+
+ /**
+ * Longrun power control
+ */
+ XEN_CPU_FEATURE_LONGRUN,
+
+ /**
+ * LongRun table interface
+ */
+ XEN_CPU_FEATURE_LRTI,
+
+ /**
+ * Cyrix MMX extensions
+ */
+ XEN_CPU_FEATURE_CXMMX,
+
+ /**
+ * AMD K6 nonstandard MTRRs
+ */
+ XEN_CPU_FEATURE_K6_MTRR,
+
+ /**
+ * Cyrix ARRs (= MTRRs)
+ */
+ XEN_CPU_FEATURE_CYRIX_ARR,
+
+ /**
+ * Centaur MCRs (= MTRRs)
+ */
+ XEN_CPU_FEATURE_CENTAUR_MCR,
+
+ /**
+ * Opteron, Athlon64
+ */
+ XEN_CPU_FEATURE_K8,
+
+ /**
+ * Athlon
+ */
+ XEN_CPU_FEATURE_K7,
+
+ /**
+ * P3
+ */
+ XEN_CPU_FEATURE_P3,
+
+ /**
+ * P4
+ */
+ XEN_CPU_FEATURE_P4,
+
+ /**
+ * TSC ticks at a constant rate
+ */
+ XEN_CPU_FEATURE_CONSTANT_TSC,
+
+ /**
+ * FXSAVE leaks FOP/FIP/FOP
+ */
+ XEN_CPU_FEATURE_FXSAVE_LEAK,
+
+ /**
+ * Streaming SIMD Extensions-3
+ */
+ XEN_CPU_FEATURE_XMM3,
+
+ /**
+ * Monitor/Mwait support
+ */
+ XEN_CPU_FEATURE_MWAIT,
+
+ /**
+ * CPL Qualified Debug Store
+ */
+ XEN_CPU_FEATURE_DSCPL,
+
+ /**
+ * Enhanced SpeedStep
+ */
+ XEN_CPU_FEATURE_EST,
+
+ /**
+ * Thermal Monitor 2
+ */
+ XEN_CPU_FEATURE_TM2,
+
+ /**
+ * Context ID
+ */
+ XEN_CPU_FEATURE_CID,
+
+ /**
+ * CMPXCHG16B
+ */
+ XEN_CPU_FEATURE_CX16,
+
+ /**
+ * Send Task Priority Messages
+ */
+ XEN_CPU_FEATURE_XTPR,
+
+ /**
+ * on-CPU RNG present (xstore insn)
+ */
+ XEN_CPU_FEATURE_XSTORE,
+
+ /**
+ * on-CPU RNG enabled
+ */
+ XEN_CPU_FEATURE_XSTORE_EN,
+
+ /**
+ * on-CPU crypto (xcrypt insn)
+ */
+ XEN_CPU_FEATURE_XCRYPT,
+
+ /**
+ * on-CPU crypto enabled
+ */
+ XEN_CPU_FEATURE_XCRYPT_EN,
+
+ /**
+ * LAHF/SAHF in long mode
+ */
+ XEN_CPU_FEATURE_LAHF_LM,
+
+ /**
+ * If yes HyperThreading not valid
+ */
+ XEN_CPU_FEATURE_CMP_LEGACY,
+
+ /**
+ * VMX instruction set
+ */
+ XEN_CPU_FEATURE_VMX
+};
+
+
+typedef struct xen_cpu_feature_set
+{
+ size_t size;
+ enum xen_cpu_feature contents[];
+} xen_cpu_feature_set;
+
+/**
+ * Allocate a xen_cpu_feature_set of the given size.
+ */
+extern xen_cpu_feature_set *
+xen_cpu_feature_set_alloc(size_t size);
+
+/**
+ * Free the given xen_cpu_feature_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_cpu_feature_set_free(xen_cpu_feature_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_cpu_feature_to_string(enum xen_cpu_feature val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_cpu_feature
+xen_cpu_feature_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_cpu_feature_internal.h b/tools/libxen/include/xen_cpu_feature_internal.h
new file mode 100644
index 0000000000..c4616a7c5f
--- /dev/null
+++ b/tools/libxen/include/xen_cpu_feature_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_cpu_feature. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_CPU_FEATURE_INTERNAL_H
+#define XEN_CPU_FEATURE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_cpu_feature_abstract_type_;
+extern const abstract_type xen_cpu_feature_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_driver_type.h b/tools/libxen/include/xen_driver_type.h
new file mode 100644
index 0000000000..585db28979
--- /dev/null
+++ b/tools/libxen/include/xen_driver_type.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_DRIVER_TYPE_H
+#define XEN_DRIVER_TYPE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_driver_type
+{
+ /**
+ * use hardware emulation
+ */
+ XEN_DRIVER_TYPE_IOEMU,
+
+ /**
+ * use paravirtualised driver
+ */
+ XEN_DRIVER_TYPE_PARAVIRTUALISED
+};
+
+
+typedef struct xen_driver_type_set
+{
+ size_t size;
+ enum xen_driver_type contents[];
+} xen_driver_type_set;
+
+/**
+ * Allocate a xen_driver_type_set of the given size.
+ */
+extern xen_driver_type_set *
+xen_driver_type_set_alloc(size_t size);
+
+/**
+ * Free the given xen_driver_type_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_driver_type_set_free(xen_driver_type_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_driver_type_to_string(enum xen_driver_type val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_driver_type
+xen_driver_type_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_driver_type_internal.h b/tools/libxen/include/xen_driver_type_internal.h
new file mode 100644
index 0000000000..c44639f692
--- /dev/null
+++ b/tools/libxen/include/xen_driver_type_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_driver_type. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_DRIVER_TYPE_INTERNAL_H
+#define XEN_DRIVER_TYPE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_driver_type_abstract_type_;
+extern const abstract_type xen_driver_type_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_host.h b/tools/libxen/include/xen_host.h
new file mode 100644
index 0000000000..2264b603e4
--- /dev/null
+++ b/tools/libxen/include/xen_host.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_HOST_H
+#define XEN_HOST_H
+
+#include "xen_common.h"
+#include "xen_host_cpu_decl.h"
+#include "xen_host_decl.h"
+#include "xen_pif_decl.h"
+#include "xen_string_string_map.h"
+#include "xen_vm_decl.h"
+
+
+/*
+ * The host class.
+ *
+ * A physical host.
+ */
+
+
+/**
+ * Free the given xen_host. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_host_free(xen_host host);
+
+
+typedef struct xen_host_set
+{
+ size_t size;
+ xen_host *contents[];
+} xen_host_set;
+
+/**
+ * Allocate a xen_host_set of the given size.
+ */
+extern xen_host_set *
+xen_host_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_host_set_free(xen_host_set *set);
+
+
+typedef struct xen_host_record
+{
+ xen_host handle;
+ char *uuid;
+ char *name_label;
+ char *name_description;
+ xen_string_string_map *software_version;
+ struct xen_vm_record_opt_set *resident_vms;
+ struct xen_pif_record_opt_set *pifs;
+ struct xen_host_cpu_record_opt_set *host_cpus;
+} xen_host_record;
+
+/**
+ * Allocate a xen_host_record.
+ */
+extern xen_host_record *
+xen_host_record_alloc(void);
+
+/**
+ * Free the given xen_host_record, and all referenced values. The
+ * given record must have been allocated by this library.
+ */
+extern void
+xen_host_record_free(xen_host_record *record);
+
+
+typedef struct xen_host_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_host handle;
+ xen_host_record *record;
+ } u;
+} xen_host_record_opt;
+
+/**
+ * Allocate a xen_host_record_opt.
+ */
+extern xen_host_record_opt *
+xen_host_record_opt_alloc(void);
+
+/**
+ * Free the given xen_host_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_host_record_opt_free(xen_host_record_opt *record_opt);
+
+
+typedef struct xen_host_record_set
+{
+ size_t size;
+ xen_host_record *contents[];
+} xen_host_record_set;
+
+/**
+ * Allocate a xen_host_record_set of the given size.
+ */
+extern xen_host_record_set *
+xen_host_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_host_record_set_free(xen_host_record_set *set);
+
+
+
+typedef struct xen_host_record_opt_set
+{
+ size_t size;
+ xen_host_record_opt *contents[];
+} xen_host_record_opt_set;
+
+/**
+ * Allocate a xen_host_record_opt_set of the given size.
+ */
+extern xen_host_record_opt_set *
+xen_host_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_host_record_opt_set_free(xen_host_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given host. !!!
+ */
+extern bool
+xen_host_get_record(xen_session *session, xen_host_record **result, xen_host host);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_host_get_by_uuid(xen_session *session, xen_host *result, char *uuid);
+
+
+/**
+ * Create a new host instance, and return its handle.
+ */
+extern bool
+xen_host_create(xen_session *session, xen_host *result, xen_host_record *record);
+
+
+/**
+ * Destroy the specified host instance.
+ */
+extern bool
+xen_host_destroy(xen_session *session, xen_host host);
+
+
+/**
+ * Get all the host instances with the given label.
+ */
+extern bool
+xen_host_get_by_name_label(xen_session *session, struct xen_host_set **result, char *label);
+
+
+/**
+ * Get the uuid field of the given host.
+ */
+extern bool
+xen_host_get_uuid(xen_session *session, char **result, xen_host host);
+
+
+/**
+ * Get the name/label field of the given host.
+ */
+extern bool
+xen_host_get_name_label(xen_session *session, char **result, xen_host host);
+
+
+/**
+ * Get the name/description field of the given host.
+ */
+extern bool
+xen_host_get_name_description(xen_session *session, char **result, xen_host host);
+
+
+/**
+ * Get the software_version field of the given host.
+ */
+extern bool
+xen_host_get_software_version(xen_session *session, xen_string_string_map **result, xen_host host);
+
+
+/**
+ * Get the resident_VMs field of the given host.
+ */
+extern bool
+xen_host_get_resident_vms(xen_session *session, struct xen_vm_set **result, xen_host host);
+
+
+/**
+ * Get the PIFs field of the given host.
+ */
+extern bool
+xen_host_get_pifs(xen_session *session, struct xen_pif_set **result, xen_host host);
+
+
+/**
+ * Get the host_CPUs field of the given host.
+ */
+extern bool
+xen_host_get_host_cpus(xen_session *session, struct xen_host_cpu_set **result, xen_host host);
+
+
+/**
+ * Set the name/label field of the given host.
+ */
+extern bool
+xen_host_set_name_label(xen_session *session, xen_host host, char *label);
+
+
+/**
+ * Set the name/description field of the given host.
+ */
+extern bool
+xen_host_set_name_description(xen_session *session, xen_host host, char *description);
+
+
+/**
+ * Puts the host into a state in which no new VMs can be started.
+ * Currently active VMs on the host continue to execute.
+ */
+extern bool
+xen_host_disable(xen_session *session, xen_host host);
+
+
+/**
+ * Puts the host into a state in which new VMs can be started.
+ */
+extern bool
+xen_host_enable(xen_session *session, xen_host host);
+
+
+/**
+ * Shutdown the host. (This function can only be called if there are no
+ * currently running VMs on the host and it is disabled.)
+ */
+extern bool
+xen_host_shutdown(xen_session *session, xen_host host);
+
+
+/**
+ * Reboot the host. (This function can only be called if there are no
+ * currently running VMs on the host and it is disabled.)
+ */
+extern bool
+xen_host_reboot(xen_session *session, xen_host host);
+
+
+/**
+ * Return a list of all the hosts known to the system.
+ */
+extern bool
+xen_host_get_all(xen_session *session, struct xen_host_set **result);
+
+
+#endif
diff --git a/tools/libxen/include/xen_host_cpu.h b/tools/libxen/include/xen_host_cpu.h
new file mode 100644
index 0000000000..e0d4ee0c4b
--- /dev/null
+++ b/tools/libxen/include/xen_host_cpu.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_HOST_CPU_H
+#define XEN_HOST_CPU_H
+
+#include "xen_common.h"
+#include "xen_cpu_feature.h"
+#include "xen_host_cpu_decl.h"
+#include "xen_host_decl.h"
+
+
+/*
+ * The host_cpu class.
+ *
+ * A physical CPU.
+ */
+
+
+/**
+ * Free the given xen_host_cpu. The given handle must have been
+ * allocated by this library.
+ */
+extern void
+xen_host_cpu_free(xen_host_cpu host_cpu);
+
+
+typedef struct xen_host_cpu_set
+{
+ size_t size;
+ xen_host_cpu *contents[];
+} xen_host_cpu_set;
+
+/**
+ * Allocate a xen_host_cpu_set of the given size.
+ */
+extern xen_host_cpu_set *
+xen_host_cpu_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_cpu_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_host_cpu_set_free(xen_host_cpu_set *set);
+
+
+typedef struct xen_host_cpu_record
+{
+ xen_host_cpu handle;
+ char *uuid;
+ struct xen_host_record_opt *host;
+ int64_t number;
+ char *vendor;
+ int64_t speed;
+ char *modelname;
+ struct xen_cpu_feature_set *features;
+ double utilisation;
+} xen_host_cpu_record;
+
+/**
+ * Allocate a xen_host_cpu_record.
+ */
+extern xen_host_cpu_record *
+xen_host_cpu_record_alloc(void);
+
+/**
+ * Free the given xen_host_cpu_record, and all referenced values. The
+ * given record must have been allocated by this library.
+ */
+extern void
+xen_host_cpu_record_free(xen_host_cpu_record *record);
+
+
+typedef struct xen_host_cpu_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_host_cpu handle;
+ xen_host_cpu_record *record;
+ } u;
+} xen_host_cpu_record_opt;
+
+/**
+ * Allocate a xen_host_cpu_record_opt.
+ */
+extern xen_host_cpu_record_opt *
+xen_host_cpu_record_opt_alloc(void);
+
+/**
+ * Free the given xen_host_cpu_record_opt, and all referenced values.
+ * The given record_opt must have been allocated by this library.
+ */
+extern void
+xen_host_cpu_record_opt_free(xen_host_cpu_record_opt *record_opt);
+
+
+typedef struct xen_host_cpu_record_set
+{
+ size_t size;
+ xen_host_cpu_record *contents[];
+} xen_host_cpu_record_set;
+
+/**
+ * Allocate a xen_host_cpu_record_set of the given size.
+ */
+extern xen_host_cpu_record_set *
+xen_host_cpu_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_cpu_record_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_host_cpu_record_set_free(xen_host_cpu_record_set *set);
+
+
+
+typedef struct xen_host_cpu_record_opt_set
+{
+ size_t size;
+ xen_host_cpu_record_opt *contents[];
+} xen_host_cpu_record_opt_set;
+
+/**
+ * Allocate a xen_host_cpu_record_opt_set of the given size.
+ */
+extern xen_host_cpu_record_opt_set *
+xen_host_cpu_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_host_cpu_record_opt_set, and all referenced
+ * values. The given set must have been allocated by this library.
+ */
+extern void
+xen_host_cpu_record_opt_set_free(xen_host_cpu_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given host_cpu. !!!
+ */
+extern bool
+xen_host_cpu_get_record(xen_session *session, xen_host_cpu_record **result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_host_cpu_get_by_uuid(xen_session *session, xen_host_cpu *result, char *uuid);
+
+
+/**
+ * Create a new host_cpu instance, and return its handle.
+ */
+extern bool
+xen_host_cpu_create(xen_session *session, xen_host_cpu *result, xen_host_cpu_record *record);
+
+
+/**
+ * Destroy the specified host_cpu instance.
+ */
+extern bool
+xen_host_cpu_destroy(xen_session *session, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the uuid field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_uuid(xen_session *session, char **result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the host field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_host(xen_session *session, xen_host *result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the number field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_number(xen_session *session, int64_t *result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the vendor field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_vendor(xen_session *session, char **result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the speed field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_speed(xen_session *session, int64_t *result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the modelname field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_modelname(xen_session *session, char **result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the features field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_features(xen_session *session, struct xen_cpu_feature_set **result, xen_host_cpu host_cpu);
+
+
+/**
+ * Get the utilisation field of the given host_cpu.
+ */
+extern bool
+xen_host_cpu_get_utilisation(xen_session *session, double *result, xen_host_cpu host_cpu);
+
+
+#endif
diff --git a/tools/libxen/include/xen_host_cpu_decl.h b/tools/libxen/include/xen_host_cpu_decl.h
new file mode 100644
index 0000000000..1d24953ecc
--- /dev/null
+++ b/tools/libxen/include/xen_host_cpu_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_HOST_CPU_DECL_H
+#define XEN_HOST_CPU_DECL_H
+
+typedef void *xen_host_cpu;
+
+struct xen_host_cpu_set;
+struct xen_host_cpu_record;
+struct xen_host_cpu_record_set;
+struct xen_host_cpu_record_opt;
+struct xen_host_cpu_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_host_decl.h b/tools/libxen/include/xen_host_decl.h
new file mode 100644
index 0000000000..affb676869
--- /dev/null
+++ b/tools/libxen/include/xen_host_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_HOST_DECL_H
+#define XEN_HOST_DECL_H
+
+typedef void *xen_host;
+
+struct xen_host_set;
+struct xen_host_record;
+struct xen_host_record_set;
+struct xen_host_record_opt;
+struct xen_host_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_int_float_map.h b/tools/libxen/include/xen_int_float_map.h
new file mode 100644
index 0000000000..9cc4769d48
--- /dev/null
+++ b/tools/libxen/include/xen_int_float_map.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_INT_FLOAT_MAP_H
+#define XEN_INT_FLOAT_MAP_H
+
+
+#include "xen_common.h"
+
+
+typedef struct xen_int_float_map_contents
+{
+ int64_t key;
+ double val;
+} xen_int_float_map_contents;
+
+
+typedef struct xen_int_float_map
+{
+ size_t size;
+ xen_int_float_map_contents contents[];
+} xen_int_float_map;
+
+/**
+ * Allocate a xen_int_float_map of the given size.
+ */
+extern xen_int_float_map *
+xen_int_float_map_alloc(size_t size);
+
+/**
+ * Free the given xen_int_float_map, and all referenced values. The
+ * given map must have been allocated by this library.
+ */
+extern void
+xen_int_float_map_free(xen_int_float_map *map);
+
+
+#endif
diff --git a/tools/libxen/include/xen_internal.h b/tools/libxen/include/xen_internal.h
new file mode 100644
index 0000000000..043c4053f8
--- /dev/null
+++ b/tools/libxen/include/xen_internal.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 XenSource, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_INTERNAL_H
+#define XEN_INTERNAL_H
+
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+
+
+enum abstract_typename
+{
+ VOID,
+ STRING,
+ INT,
+ FLOAT,
+ BOOL,
+ DATETIME,
+ SET,
+ MAP,
+ STRUCT,
+ REF,
+ ENUM,
+ ENUMSET
+};
+
+
+typedef struct
+{
+ size_t size;
+ void *contents[];
+} arbitrary_set;
+
+
+typedef struct struct_member struct_member;
+
+
+typedef struct abstract_type
+{
+ enum abstract_typename typename;
+ const struct abstract_type *child;
+ const char * (*enum_marshaller)(int);
+ int (*enum_demarshaller)(xen_session *, const char *);
+ size_t struct_size;
+ size_t member_count;
+ const struct_member *members;
+} abstract_type;
+
+
+struct struct_member
+{
+ const char *key;
+ const struct abstract_type *type;
+ int offset;
+};
+
+
+extern const abstract_type abstract_type_string;
+extern const abstract_type abstract_type_int;
+extern const abstract_type abstract_type_float;
+extern const abstract_type abstract_type_bool;
+extern const abstract_type abstract_type_datetime;
+extern const abstract_type abstract_type_ref;
+
+extern const abstract_type abstract_type_string_set;
+extern const abstract_type abstract_type_ref_set;
+
+extern const abstract_type abstract_type_string_string_map;
+extern const abstract_type abstract_type_int_float_map;
+
+
+typedef struct abstract_value
+{
+ const abstract_type *type;
+ union
+ {
+ const char *string_val;
+ int64_t int_val;
+ int enum_val;
+ double float_val;
+ bool bool_val;
+ arbitrary_set *set_val;
+ void *struct_val;
+ time_t datetime_val;
+ } u;
+} abstract_value;
+
+
+extern void
+xen_call_(xen_session *s, const char *method_name, abstract_value params[],
+ int param_count, const abstract_type *result_type, void *value);
+
+
+#define XEN_CALL_(method_name__) \
+ xen_call_(session, method_name__, param_values, \
+ sizeof(param_values) / sizeof(param_values[0]), \
+ &result_type, result) \
+
+
+extern char *
+xen_strdup_(const char *in);
+
+
+extern int
+xen_enum_lookup_(xen_session *session, const char *str,
+ const char **lookup_table, int n);
+
+#define ENUM_LOOKUP(session__, str__, lookup_table__) \
+ xen_enum_lookup_(session__, str__, lookup_table__, \
+ sizeof(lookup_table__) / \
+ sizeof(lookup_table__[0])) \
+ \
+
+#define XEN_ALLOC(type__) \
+type__ * \
+type__ ## _alloc() \
+{ \
+ return calloc(1, sizeof(type__)); \
+} \
+
+
+#define XEN_FREE(type__) \
+void \
+type__ ## _free(type__ handle) \
+{ \
+ free(handle); \
+} \
+
+
+#define XEN_SET_ALLOC_FREE(type__) \
+type__ ## _set * \
+type__ ## _set_alloc(size_t size) \
+{ \
+ return calloc(1, sizeof(type__ ## _set) + size * sizeof(type__)); \
+} \
+ \
+void \
+type__ ## _set_free(type__ ## _set *set) \
+{ \
+ if (set == NULL) \
+ { \
+ return; \
+ } \
+ size_t n = set->size; \
+ for (size_t i = 0; i < n; i++) \
+ { \
+ type__ ## _free(set->contents[i]); \
+ } \
+ \
+ free(set); \
+} \
+
+
+#define XEN_RECORD_OPT_FREE(type__) \
+void \
+type__ ## _record_opt_free(type__ ## _record_opt *opt) \
+{ \
+ if (opt == NULL) \
+ { \
+ return; \
+ } \
+ if (opt->is_record) \
+ { \
+ type__ ## _record_free(opt->u.record); \
+ } \
+ else \
+ { \
+ type__ ## _free(opt->u.handle); \
+ } \
+ free(opt); \
+} \
+
+
+#endif
diff --git a/tools/libxen/include/xen_network.h b/tools/libxen/include/xen_network.h
new file mode 100644
index 0000000000..a25babe492
--- /dev/null
+++ b/tools/libxen/include/xen_network.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_NETWORK_H
+#define XEN_NETWORK_H
+
+#include "xen_common.h"
+#include "xen_network_decl.h"
+#include "xen_pif_decl.h"
+#include "xen_vif_decl.h"
+
+
+/*
+ * The network class.
+ *
+ * A virtual network.
+ */
+
+
+/**
+ * Free the given xen_network. The given handle must have been
+ * allocated by this library.
+ */
+extern void
+xen_network_free(xen_network network);
+
+
+typedef struct xen_network_set
+{
+ size_t size;
+ xen_network *contents[];
+} xen_network_set;
+
+/**
+ * Allocate a xen_network_set of the given size.
+ */
+extern xen_network_set *
+xen_network_set_alloc(size_t size);
+
+/**
+ * Free the given xen_network_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_network_set_free(xen_network_set *set);
+
+
+typedef struct xen_network_record
+{
+ xen_network handle;
+ char *uuid;
+ char *name_label;
+ char *name_description;
+ struct xen_vif_record_opt_set *vifs;
+ struct xen_pif_record_opt_set *pifs;
+ char *default_gateway;
+ char *default_netmask;
+} xen_network_record;
+
+/**
+ * Allocate a xen_network_record.
+ */
+extern xen_network_record *
+xen_network_record_alloc(void);
+
+/**
+ * Free the given xen_network_record, and all referenced values. The
+ * given record must have been allocated by this library.
+ */
+extern void
+xen_network_record_free(xen_network_record *record);
+
+
+typedef struct xen_network_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_network handle;
+ xen_network_record *record;
+ } u;
+} xen_network_record_opt;
+
+/**
+ * Allocate a xen_network_record_opt.
+ */
+extern xen_network_record_opt *
+xen_network_record_opt_alloc(void);
+
+/**
+ * Free the given xen_network_record_opt, and all referenced values.
+ * The given record_opt must have been allocated by this library.
+ */
+extern void
+xen_network_record_opt_free(xen_network_record_opt *record_opt);
+
+
+typedef struct xen_network_record_set
+{
+ size_t size;
+ xen_network_record *contents[];
+} xen_network_record_set;
+
+/**
+ * Allocate a xen_network_record_set of the given size.
+ */
+extern xen_network_record_set *
+xen_network_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_network_record_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_network_record_set_free(xen_network_record_set *set);
+
+
+
+typedef struct xen_network_record_opt_set
+{
+ size_t size;
+ xen_network_record_opt *contents[];
+} xen_network_record_opt_set;
+
+/**
+ * Allocate a xen_network_record_opt_set of the given size.
+ */
+extern xen_network_record_opt_set *
+xen_network_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_network_record_opt_set, and all referenced
+ * values. The given set must have been allocated by this library.
+ */
+extern void
+xen_network_record_opt_set_free(xen_network_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given network. !!!
+ */
+extern bool
+xen_network_get_record(xen_session *session, xen_network_record **result, xen_network network);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_network_get_by_uuid(xen_session *session, xen_network *result, char *uuid);
+
+
+/**
+ * Create a new network instance, and return its handle.
+ */
+extern bool
+xen_network_create(xen_session *session, xen_network *result, xen_network_record *record);
+
+
+/**
+ * Destroy the specified network instance.
+ */
+extern bool
+xen_network_destroy(xen_session *session, xen_network network);
+
+
+/**
+ * Get all the network instances with the given label.
+ */
+extern bool
+xen_network_get_by_name_label(xen_session *session, struct xen_network_set **result, char *label);
+
+
+/**
+ * Get the uuid field of the given network.
+ */
+extern bool
+xen_network_get_uuid(xen_session *session, char **result, xen_network network);
+
+
+/**
+ * Get the name/label field of the given network.
+ */
+extern bool
+xen_network_get_name_label(xen_session *session, char **result, xen_network network);
+
+
+/**
+ * Get the name/description field of the given network.
+ */
+extern bool
+xen_network_get_name_description(xen_session *session, char **result, xen_network network);
+
+
+/**
+ * Get the VIFs field of the given network.
+ */
+extern bool
+xen_network_get_vifs(xen_session *session, struct xen_vif_set **result, xen_network network);
+
+
+/**
+ * Get the PIFs field of the given network.
+ */
+extern bool
+xen_network_get_pifs(xen_session *session, struct xen_pif_set **result, xen_network network);
+
+
+/**
+ * Get the default_gateway field of the given network.
+ */
+extern bool
+xen_network_get_default_gateway(xen_session *session, char **result, xen_network network);
+
+
+/**
+ * Get the default_netmask field of the given network.
+ */
+extern bool
+xen_network_get_default_netmask(xen_session *session, char **result, xen_network network);
+
+
+/**
+ * Set the name/label field of the given network.
+ */
+extern bool
+xen_network_set_name_label(xen_session *session, xen_network network, char *label);
+
+
+/**
+ * Set the name/description field of the given network.
+ */
+extern bool
+xen_network_set_name_description(xen_session *session, xen_network network, char *description);
+
+
+/**
+ * Set the default_gateway field of the given network.
+ */
+extern bool
+xen_network_set_default_gateway(xen_session *session, xen_network network, char *default_gateway);
+
+
+/**
+ * Set the default_netmask field of the given network.
+ */
+extern bool
+xen_network_set_default_netmask(xen_session *session, xen_network network, char *default_netmask);
+
+
+/**
+ * Return a list of all the networks known to the system.
+ */
+extern bool
+xen_network_get_all(xen_session *session, struct xen_network_set **result);
+
+
+#endif
diff --git a/tools/libxen/include/xen_network_decl.h b/tools/libxen/include/xen_network_decl.h
new file mode 100644
index 0000000000..d970c2af15
--- /dev/null
+++ b/tools/libxen/include/xen_network_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_NETWORK_DECL_H
+#define XEN_NETWORK_DECL_H
+
+typedef void *xen_network;
+
+struct xen_network_set;
+struct xen_network_record;
+struct xen_network_record_set;
+struct xen_network_record_opt;
+struct xen_network_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_on_crash_behaviour.h b/tools/libxen/include/xen_on_crash_behaviour.h
new file mode 100644
index 0000000000..8286488659
--- /dev/null
+++ b/tools/libxen/include/xen_on_crash_behaviour.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_ON_CRASH_BEHAVIOUR_H
+#define XEN_ON_CRASH_BEHAVIOUR_H
+
+
+#include "xen_common.h"
+
+
+enum xen_on_crash_behaviour
+{
+ /**
+ * destroy the VM state
+ */
+ XEN_ON_CRASH_BEHAVIOUR_DESTROY,
+
+ /**
+ * record a coredump and then destroy the VM state
+ */
+ XEN_ON_CRASH_BEHAVIOUR_COREDUMP_AND_DESTROY,
+
+ /**
+ * restart the VM
+ */
+ XEN_ON_CRASH_BEHAVIOUR_RESTART,
+
+ /**
+ * record a coredump and then restart the VM
+ */
+ XEN_ON_CRASH_BEHAVIOUR_COREDUMP_AND_RESTART,
+
+ /**
+ * leave the crashed VM as-is
+ */
+ XEN_ON_CRASH_BEHAVIOUR_PRESERVE,
+
+ /**
+ * rename the crashed VM and start a new copy
+ */
+ XEN_ON_CRASH_BEHAVIOUR_RENAME_RESTART
+};
+
+
+typedef struct xen_on_crash_behaviour_set
+{
+ size_t size;
+ enum xen_on_crash_behaviour contents[];
+} xen_on_crash_behaviour_set;
+
+/**
+ * Allocate a xen_on_crash_behaviour_set of the given size.
+ */
+extern xen_on_crash_behaviour_set *
+xen_on_crash_behaviour_set_alloc(size_t size);
+
+/**
+ * Free the given xen_on_crash_behaviour_set. The given set must have
+ * been allocated by this library.
+ */
+extern void
+xen_on_crash_behaviour_set_free(xen_on_crash_behaviour_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_on_crash_behaviour_to_string(enum xen_on_crash_behaviour val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_on_crash_behaviour
+xen_on_crash_behaviour_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_on_crash_behaviour_internal.h b/tools/libxen/include/xen_on_crash_behaviour_internal.h
new file mode 100644
index 0000000000..012398b814
--- /dev/null
+++ b/tools/libxen/include/xen_on_crash_behaviour_internal.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_on_crash_behaviour. Internal to this library -- do not use from
+ * outside.
+ */
+
+
+#ifndef XEN_ON_CRASH_BEHAVIOUR_INTERNAL_H
+#define XEN_ON_CRASH_BEHAVIOUR_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_on_crash_behaviour_abstract_type_;
+extern const abstract_type xen_on_crash_behaviour_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_on_normal_exit.h b/tools/libxen/include/xen_on_normal_exit.h
new file mode 100644
index 0000000000..3897fef24c
--- /dev/null
+++ b/tools/libxen/include/xen_on_normal_exit.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_ON_NORMAL_EXIT_H
+#define XEN_ON_NORMAL_EXIT_H
+
+
+#include "xen_common.h"
+
+
+enum xen_on_normal_exit
+{
+ /**
+ * destroy the VM state
+ */
+ XEN_ON_NORMAL_EXIT_DESTROY,
+
+ /**
+ * restart the VM
+ */
+ XEN_ON_NORMAL_EXIT_RESTART
+};
+
+
+typedef struct xen_on_normal_exit_set
+{
+ size_t size;
+ enum xen_on_normal_exit contents[];
+} xen_on_normal_exit_set;
+
+/**
+ * Allocate a xen_on_normal_exit_set of the given size.
+ */
+extern xen_on_normal_exit_set *
+xen_on_normal_exit_set_alloc(size_t size);
+
+/**
+ * Free the given xen_on_normal_exit_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_on_normal_exit_set_free(xen_on_normal_exit_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_on_normal_exit_to_string(enum xen_on_normal_exit val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_on_normal_exit
+xen_on_normal_exit_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_on_normal_exit_internal.h b/tools/libxen/include/xen_on_normal_exit_internal.h
new file mode 100644
index 0000000000..3a94f8919c
--- /dev/null
+++ b/tools/libxen/include/xen_on_normal_exit_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_on_normal_exit. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_ON_NORMAL_EXIT_INTERNAL_H
+#define XEN_ON_NORMAL_EXIT_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_on_normal_exit_abstract_type_;
+extern const abstract_type xen_on_normal_exit_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_pif.h b/tools/libxen/include/xen_pif.h
new file mode 100644
index 0000000000..143ba5709a
--- /dev/null
+++ b/tools/libxen/include/xen_pif.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_PIF_H
+#define XEN_PIF_H
+
+#include "xen_common.h"
+#include "xen_host_decl.h"
+#include "xen_network_decl.h"
+#include "xen_pif_decl.h"
+
+
+/*
+ * The PIF class.
+ *
+ * A physical network interface (note separate VLANs are represented as
+ * several PIFs).
+ */
+
+
+/**
+ * Free the given xen_pif. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_pif_free(xen_pif pif);
+
+
+typedef struct xen_pif_set
+{
+ size_t size;
+ xen_pif *contents[];
+} xen_pif_set;
+
+/**
+ * Allocate a xen_pif_set of the given size.
+ */
+extern xen_pif_set *
+xen_pif_set_alloc(size_t size);
+
+/**
+ * Free the given xen_pif_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_pif_set_free(xen_pif_set *set);
+
+
+typedef struct xen_pif_record
+{
+ xen_pif handle;
+ char *uuid;
+ char *name;
+ struct xen_network_record_opt *network;
+ struct xen_host_record_opt *host;
+ char *mac;
+ int64_t mtu;
+ char *vlan;
+ double io_read_kbs;
+ double io_write_kbs;
+} xen_pif_record;
+
+/**
+ * Allocate a xen_pif_record.
+ */
+extern xen_pif_record *
+xen_pif_record_alloc(void);
+
+/**
+ * Free the given xen_pif_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_pif_record_free(xen_pif_record *record);
+
+
+typedef struct xen_pif_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_pif handle;
+ xen_pif_record *record;
+ } u;
+} xen_pif_record_opt;
+
+/**
+ * Allocate a xen_pif_record_opt.
+ */
+extern xen_pif_record_opt *
+xen_pif_record_opt_alloc(void);
+
+/**
+ * Free the given xen_pif_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_pif_record_opt_free(xen_pif_record_opt *record_opt);
+
+
+typedef struct xen_pif_record_set
+{
+ size_t size;
+ xen_pif_record *contents[];
+} xen_pif_record_set;
+
+/**
+ * Allocate a xen_pif_record_set of the given size.
+ */
+extern xen_pif_record_set *
+xen_pif_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_pif_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_pif_record_set_free(xen_pif_record_set *set);
+
+
+
+typedef struct xen_pif_record_opt_set
+{
+ size_t size;
+ xen_pif_record_opt *contents[];
+} xen_pif_record_opt_set;
+
+/**
+ * Allocate a xen_pif_record_opt_set of the given size.
+ */
+extern xen_pif_record_opt_set *
+xen_pif_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_pif_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_pif_record_opt_set_free(xen_pif_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given PIF. !!!
+ */
+extern bool
+xen_pif_get_record(xen_session *session, xen_pif_record **result, xen_pif pif);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_pif_get_by_uuid(xen_session *session, xen_pif *result, char *uuid);
+
+
+/**
+ * Create a new PIF instance, and return its handle.
+ */
+extern bool
+xen_pif_create(xen_session *session, xen_pif *result, xen_pif_record *record);
+
+
+/**
+ * Destroy the specified PIF instance.
+ */
+extern bool
+xen_pif_destroy(xen_session *session, xen_pif pif);
+
+
+/**
+ * Get the uuid field of the given PIF.
+ */
+extern bool
+xen_pif_get_uuid(xen_session *session, char **result, xen_pif pif);
+
+
+/**
+ * Get the name field of the given PIF.
+ */
+extern bool
+xen_pif_get_name(xen_session *session, char **result, xen_pif pif);
+
+
+/**
+ * Get the network field of the given PIF.
+ */
+extern bool
+xen_pif_get_network(xen_session *session, xen_network *result, xen_pif pif);
+
+
+/**
+ * Get the host field of the given PIF.
+ */
+extern bool
+xen_pif_get_host(xen_session *session, xen_host *result, xen_pif pif);
+
+
+/**
+ * Get the MAC field of the given PIF.
+ */
+extern bool
+xen_pif_get_mac(xen_session *session, char **result, xen_pif pif);
+
+
+/**
+ * Get the MTU field of the given PIF.
+ */
+extern bool
+xen_pif_get_mtu(xen_session *session, int64_t *result, xen_pif pif);
+
+
+/**
+ * Get the VLAN field of the given PIF.
+ */
+extern bool
+xen_pif_get_vlan(xen_session *session, char **result, xen_pif pif);
+
+
+/**
+ * Get the io/read_kbs field of the given PIF.
+ */
+extern bool
+xen_pif_get_io_read_kbs(xen_session *session, double *result, xen_pif pif);
+
+
+/**
+ * Get the io/write_kbs field of the given PIF.
+ */
+extern bool
+xen_pif_get_io_write_kbs(xen_session *session, double *result, xen_pif pif);
+
+
+/**
+ * Set the name field of the given PIF.
+ */
+extern bool
+xen_pif_set_name(xen_session *session, xen_pif pif, char *name);
+
+
+/**
+ * Set the network field of the given PIF.
+ */
+extern bool
+xen_pif_set_network(xen_session *session, xen_pif pif, xen_network network);
+
+
+/**
+ * Set the host field of the given PIF.
+ */
+extern bool
+xen_pif_set_host(xen_session *session, xen_pif pif, xen_host host);
+
+
+/**
+ * Set the MAC field of the given PIF.
+ */
+extern bool
+xen_pif_set_mac(xen_session *session, xen_pif pif, char *mac);
+
+
+/**
+ * Set the MTU field of the given PIF.
+ */
+extern bool
+xen_pif_set_mtu(xen_session *session, xen_pif pif, int64_t mtu);
+
+
+/**
+ * Set the VLAN field of the given PIF.
+ */
+extern bool
+xen_pif_set_vlan(xen_session *session, xen_pif pif, char *vlan);
+
+
+#endif
diff --git a/tools/libxen/include/xen_pif_decl.h b/tools/libxen/include/xen_pif_decl.h
new file mode 100644
index 0000000000..b326bea3bc
--- /dev/null
+++ b/tools/libxen/include/xen_pif_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_PIF_DECL_H
+#define XEN_PIF_DECL_H
+
+typedef void *xen_pif;
+
+struct xen_pif_set;
+struct xen_pif_record;
+struct xen_pif_record_set;
+struct xen_pif_record_opt;
+struct xen_pif_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_sr.h b/tools/libxen/include/xen_sr.h
new file mode 100644
index 0000000000..8359b5737b
--- /dev/null
+++ b/tools/libxen/include/xen_sr.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_SR_H
+#define XEN_SR_H
+
+#include "xen_common.h"
+#include "xen_sr_decl.h"
+#include "xen_vdi_decl.h"
+
+
+/*
+ * The SR class.
+ *
+ * A storage repository.
+ */
+
+
+/**
+ * Free the given xen_sr. The given handle must have been allocated by
+ * this library.
+ */
+extern void
+xen_sr_free(xen_sr sr);
+
+
+typedef struct xen_sr_set
+{
+ size_t size;
+ xen_sr *contents[];
+} xen_sr_set;
+
+/**
+ * Allocate a xen_sr_set of the given size.
+ */
+extern xen_sr_set *
+xen_sr_set_alloc(size_t size);
+
+/**
+ * Free the given xen_sr_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_sr_set_free(xen_sr_set *set);
+
+
+typedef struct xen_sr_record
+{
+ xen_sr handle;
+ char *uuid;
+ char *name_label;
+ char *name_description;
+ struct xen_vdi_record_opt_set *vdis;
+ int64_t virtual_allocation;
+ int64_t physical_utilisation;
+ int64_t physical_size;
+ char *type;
+ char *location;
+} xen_sr_record;
+
+/**
+ * Allocate a xen_sr_record.
+ */
+extern xen_sr_record *
+xen_sr_record_alloc(void);
+
+/**
+ * Free the given xen_sr_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_sr_record_free(xen_sr_record *record);
+
+
+typedef struct xen_sr_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_sr handle;
+ xen_sr_record *record;
+ } u;
+} xen_sr_record_opt;
+
+/**
+ * Allocate a xen_sr_record_opt.
+ */
+extern xen_sr_record_opt *
+xen_sr_record_opt_alloc(void);
+
+/**
+ * Free the given xen_sr_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_sr_record_opt_free(xen_sr_record_opt *record_opt);
+
+
+typedef struct xen_sr_record_set
+{
+ size_t size;
+ xen_sr_record *contents[];
+} xen_sr_record_set;
+
+/**
+ * Allocate a xen_sr_record_set of the given size.
+ */
+extern xen_sr_record_set *
+xen_sr_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_sr_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_sr_record_set_free(xen_sr_record_set *set);
+
+
+
+typedef struct xen_sr_record_opt_set
+{
+ size_t size;
+ xen_sr_record_opt *contents[];
+} xen_sr_record_opt_set;
+
+/**
+ * Allocate a xen_sr_record_opt_set of the given size.
+ */
+extern xen_sr_record_opt_set *
+xen_sr_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_sr_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_sr_record_opt_set_free(xen_sr_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given SR. !!!
+ */
+extern bool
+xen_sr_get_record(xen_session *session, xen_sr_record **result, xen_sr sr);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_sr_get_by_uuid(xen_session *session, xen_sr *result, char *uuid);
+
+
+/**
+ * Create a new SR instance, and return its handle.
+ */
+extern bool
+xen_sr_create(xen_session *session, xen_sr *result, xen_sr_record *record);
+
+
+/**
+ * Destroy the specified SR instance.
+ */
+extern bool
+xen_sr_destroy(xen_session *session, xen_sr sr);
+
+
+/**
+ * Get all the SR instances with the given label.
+ */
+extern bool
+xen_sr_get_by_name_label(xen_session *session, struct xen_sr_set **result, char *label);
+
+
+/**
+ * Get the uuid field of the given SR.
+ */
+extern bool
+xen_sr_get_uuid(xen_session *session, char **result, xen_sr sr);
+
+
+/**
+ * Get the name/label field of the given SR.
+ */
+extern bool
+xen_sr_get_name_label(xen_session *session, char **result, xen_sr sr);
+
+
+/**
+ * Get the name/description field of the given SR.
+ */
+extern bool
+xen_sr_get_name_description(xen_session *session, char **result, xen_sr sr);
+
+
+/**
+ * Get the VDIs field of the given SR.
+ */
+extern bool
+xen_sr_get_vdis(xen_session *session, struct xen_vdi_set **result, xen_sr sr);
+
+
+/**
+ * Get the virtual_allocation field of the given SR.
+ */
+extern bool
+xen_sr_get_virtual_allocation(xen_session *session, int64_t *result, xen_sr sr);
+
+
+/**
+ * Get the physical_utilisation field of the given SR.
+ */
+extern bool
+xen_sr_get_physical_utilisation(xen_session *session, int64_t *result, xen_sr sr);
+
+
+/**
+ * Get the physical_size field of the given SR.
+ */
+extern bool
+xen_sr_get_physical_size(xen_session *session, int64_t *result, xen_sr sr);
+
+
+/**
+ * Get the type field of the given SR.
+ */
+extern bool
+xen_sr_get_type(xen_session *session, char **result, xen_sr sr);
+
+
+/**
+ * Get the location field of the given SR.
+ */
+extern bool
+xen_sr_get_location(xen_session *session, char **result, xen_sr sr);
+
+
+/**
+ * Set the name/label field of the given SR.
+ */
+extern bool
+xen_sr_set_name_label(xen_session *session, xen_sr sr, char *label);
+
+
+/**
+ * Set the name/description field of the given SR.
+ */
+extern bool
+xen_sr_set_name_description(xen_session *session, xen_sr sr, char *description);
+
+
+/**
+ * Take an exact copy of the Storage Repository; the cloned storage
+ * repository has the same type as its parent
+ */
+extern bool
+xen_sr_clone(xen_session *session, xen_sr *result, xen_sr sr, char *loc, char *name);
+
+
+/**
+ * Return a list of all the SRs known to the system.
+ */
+extern bool
+xen_sr_get_all(xen_session *session, struct xen_sr_set **result);
+
+
+#endif
diff --git a/tools/libxen/include/xen_sr_decl.h b/tools/libxen/include/xen_sr_decl.h
new file mode 100644
index 0000000000..533e90c49e
--- /dev/null
+++ b/tools/libxen/include/xen_sr_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_SR_DECL_H
+#define XEN_SR_DECL_H
+
+typedef void *xen_sr;
+
+struct xen_sr_set;
+struct xen_sr_record;
+struct xen_sr_record_set;
+struct xen_sr_record_opt;
+struct xen_sr_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_string_string_map.h b/tools/libxen/include/xen_string_string_map.h
new file mode 100644
index 0000000000..e3e5f6890b
--- /dev/null
+++ b/tools/libxen/include/xen_string_string_map.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_STRING_STRING_MAP_H
+#define XEN_STRING_STRING_MAP_H
+
+
+#include "xen_common.h"
+
+
+typedef struct xen_string_string_map_contents
+{
+ char *key;
+ char *val;
+} xen_string_string_map_contents;
+
+
+typedef struct xen_string_string_map
+{
+ size_t size;
+ xen_string_string_map_contents contents[];
+} xen_string_string_map;
+
+/**
+ * Allocate a xen_string_string_map of the given size.
+ */
+extern xen_string_string_map *
+xen_string_string_map_alloc(size_t size);
+
+/**
+ * Free the given xen_string_string_map, and all referenced values.
+ * The given map must have been allocated by this library.
+ */
+extern void
+xen_string_string_map_free(xen_string_string_map *map);
+
+
+#endif
diff --git a/tools/libxen/include/xen_user.h b/tools/libxen/include/xen_user.h
new file mode 100644
index 0000000000..b426825585
--- /dev/null
+++ b/tools/libxen/include/xen_user.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_USER_H
+#define XEN_USER_H
+
+#include "xen_common.h"
+#include "xen_user_decl.h"
+
+
+/*
+ * The user class.
+ *
+ * A user of the system.
+ */
+
+
+/**
+ * Free the given xen_user. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_user_free(xen_user user);
+
+
+typedef struct xen_user_set
+{
+ size_t size;
+ xen_user *contents[];
+} xen_user_set;
+
+/**
+ * Allocate a xen_user_set of the given size.
+ */
+extern xen_user_set *
+xen_user_set_alloc(size_t size);
+
+/**
+ * Free the given xen_user_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_user_set_free(xen_user_set *set);
+
+
+typedef struct xen_user_record
+{
+ xen_user handle;
+ char *uuid;
+ char *short_name;
+ char *fullname;
+} xen_user_record;
+
+/**
+ * Allocate a xen_user_record.
+ */
+extern xen_user_record *
+xen_user_record_alloc(void);
+
+/**
+ * Free the given xen_user_record, and all referenced values. The
+ * given record must have been allocated by this library.
+ */
+extern void
+xen_user_record_free(xen_user_record *record);
+
+
+typedef struct xen_user_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_user handle;
+ xen_user_record *record;
+ } u;
+} xen_user_record_opt;
+
+/**
+ * Allocate a xen_user_record_opt.
+ */
+extern xen_user_record_opt *
+xen_user_record_opt_alloc(void);
+
+/**
+ * Free the given xen_user_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_user_record_opt_free(xen_user_record_opt *record_opt);
+
+
+typedef struct xen_user_record_set
+{
+ size_t size;
+ xen_user_record *contents[];
+} xen_user_record_set;
+
+/**
+ * Allocate a xen_user_record_set of the given size.
+ */
+extern xen_user_record_set *
+xen_user_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_user_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_user_record_set_free(xen_user_record_set *set);
+
+
+
+typedef struct xen_user_record_opt_set
+{
+ size_t size;
+ xen_user_record_opt *contents[];
+} xen_user_record_opt_set;
+
+/**
+ * Allocate a xen_user_record_opt_set of the given size.
+ */
+extern xen_user_record_opt_set *
+xen_user_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_user_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_user_record_opt_set_free(xen_user_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given user. !!!
+ */
+extern bool
+xen_user_get_record(xen_session *session, xen_user_record **result, xen_user user);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_user_get_by_uuid(xen_session *session, xen_user *result, char *uuid);
+
+
+/**
+ * Create a new user instance, and return its handle.
+ */
+extern bool
+xen_user_create(xen_session *session, xen_user *result, xen_user_record *record);
+
+
+/**
+ * Destroy the specified user instance.
+ */
+extern bool
+xen_user_destroy(xen_session *session, xen_user user);
+
+
+/**
+ * Get the uuid field of the given user.
+ */
+extern bool
+xen_user_get_uuid(xen_session *session, char **result, xen_user user);
+
+
+/**
+ * Get the short_name field of the given user.
+ */
+extern bool
+xen_user_get_short_name(xen_session *session, char **result, xen_user user);
+
+
+/**
+ * Get the fullname field of the given user.
+ */
+extern bool
+xen_user_get_fullname(xen_session *session, char **result, xen_user user);
+
+
+/**
+ * Set the fullname field of the given user.
+ */
+extern bool
+xen_user_set_fullname(xen_session *session, xen_user user, char *fullname);
+
+
+#endif
diff --git a/tools/libxen/include/xen_user_decl.h b/tools/libxen/include/xen_user_decl.h
new file mode 100644
index 0000000000..e5caae473b
--- /dev/null
+++ b/tools/libxen/include/xen_user_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_USER_DECL_H
+#define XEN_USER_DECL_H
+
+typedef void *xen_user;
+
+struct xen_user_set;
+struct xen_user_record;
+struct xen_user_record_set;
+struct xen_user_record_opt;
+struct xen_user_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_vbd.h b/tools/libxen/include/xen_vbd.h
new file mode 100644
index 0000000000..2b9d8b05eb
--- /dev/null
+++ b/tools/libxen/include/xen_vbd.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VBD_H
+#define XEN_VBD_H
+
+#include "xen_common.h"
+#include "xen_driver_type.h"
+#include "xen_vbd_decl.h"
+#include "xen_vbd_mode.h"
+#include "xen_vdi_decl.h"
+#include "xen_vm_decl.h"
+
+
+/*
+ * The VBD class.
+ *
+ * A virtual block device.
+ */
+
+
+/**
+ * Free the given xen_vbd. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_vbd_free(xen_vbd vbd);
+
+
+typedef struct xen_vbd_set
+{
+ size_t size;
+ xen_vbd *contents[];
+} xen_vbd_set;
+
+/**
+ * Allocate a xen_vbd_set of the given size.
+ */
+extern xen_vbd_set *
+xen_vbd_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vbd_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_vbd_set_free(xen_vbd_set *set);
+
+
+typedef struct xen_vbd_record
+{
+ xen_vbd handle;
+ char *uuid;
+ struct xen_vm_record_opt *vm;
+ struct xen_vdi_record_opt *vdi;
+ char *device;
+ char *image;
+ enum xen_vbd_mode mode;
+ enum xen_driver_type driver;
+ double io_read_kbs;
+ double io_write_kbs;
+} xen_vbd_record;
+
+/**
+ * Allocate a xen_vbd_record.
+ */
+extern xen_vbd_record *
+xen_vbd_record_alloc(void);
+
+/**
+ * Free the given xen_vbd_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_vbd_record_free(xen_vbd_record *record);
+
+
+typedef struct xen_vbd_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_vbd handle;
+ xen_vbd_record *record;
+ } u;
+} xen_vbd_record_opt;
+
+/**
+ * Allocate a xen_vbd_record_opt.
+ */
+extern xen_vbd_record_opt *
+xen_vbd_record_opt_alloc(void);
+
+/**
+ * Free the given xen_vbd_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_vbd_record_opt_free(xen_vbd_record_opt *record_opt);
+
+
+typedef struct xen_vbd_record_set
+{
+ size_t size;
+ xen_vbd_record *contents[];
+} xen_vbd_record_set;
+
+/**
+ * Allocate a xen_vbd_record_set of the given size.
+ */
+extern xen_vbd_record_set *
+xen_vbd_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vbd_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_vbd_record_set_free(xen_vbd_record_set *set);
+
+
+
+typedef struct xen_vbd_record_opt_set
+{
+ size_t size;
+ xen_vbd_record_opt *contents[];
+} xen_vbd_record_opt_set;
+
+/**
+ * Allocate a xen_vbd_record_opt_set of the given size.
+ */
+extern xen_vbd_record_opt_set *
+xen_vbd_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vbd_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_vbd_record_opt_set_free(xen_vbd_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given VBD. !!!
+ */
+extern bool
+xen_vbd_get_record(xen_session *session, xen_vbd_record **result, xen_vbd vbd);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_vbd_get_by_uuid(xen_session *session, xen_vbd *result, char *uuid);
+
+
+/**
+ * Create a new VBD instance, and return its handle.
+ */
+extern bool
+xen_vbd_create(xen_session *session, xen_vbd *result, xen_vbd_record *record);
+
+
+/**
+ * Destroy the specified VBD instance.
+ */
+extern bool
+xen_vbd_destroy(xen_session *session, xen_vbd vbd);
+
+
+/**
+ * Get the uuid field of the given VBD.
+ */
+extern bool
+xen_vbd_get_uuid(xen_session *session, char **result, xen_vbd vbd);
+
+
+/**
+ * Get the VM field of the given VBD.
+ */
+extern bool
+xen_vbd_get_vm(xen_session *session, xen_vm *result, xen_vbd vbd);
+
+
+/**
+ * Get the VDI field of the given VBD.
+ */
+extern bool
+xen_vbd_get_vdi(xen_session *session, xen_vdi *result, xen_vbd vbd);
+
+
+/**
+ * Get the device field of the given VBD.
+ */
+extern bool
+xen_vbd_get_device(xen_session *session, char **result, xen_vbd vbd);
+
+
+/**
+ * Get the mode field of the given VBD.
+ */
+extern bool
+xen_vbd_get_mode(xen_session *session, enum xen_vbd_mode *result, xen_vbd vbd);
+
+
+/**
+ * Get the driver field of the given VBD.
+ */
+extern bool
+xen_vbd_get_driver(xen_session *session, enum xen_driver_type *result, xen_vbd vbd);
+
+
+/**
+ * Get the io/read_kbs field of the given VBD.
+ */
+extern bool
+xen_vbd_get_io_read_kbs(xen_session *session, double *result, xen_vbd vbd);
+
+
+/**
+ * Get the io/write_kbs field of the given VBD.
+ */
+extern bool
+xen_vbd_get_io_write_kbs(xen_session *session, double *result, xen_vbd vbd);
+
+
+/**
+ * Set the VM field of the given VBD.
+ */
+extern bool
+xen_vbd_set_vm(xen_session *session, xen_vbd vbd, xen_vm vm);
+
+
+/**
+ * Set the VDI field of the given VBD.
+ */
+extern bool
+xen_vbd_set_vdi(xen_session *session, xen_vbd vbd, xen_vdi vdi);
+
+
+/**
+ * Set the device field of the given VBD.
+ */
+extern bool
+xen_vbd_set_device(xen_session *session, xen_vbd vbd, char *device);
+
+
+/**
+ * Set the mode field of the given VBD.
+ */
+extern bool
+xen_vbd_set_mode(xen_session *session, xen_vbd vbd, enum xen_vbd_mode mode);
+
+
+/**
+ * Set the driver field of the given VBD.
+ */
+extern bool
+xen_vbd_set_driver(xen_session *session, xen_vbd vbd, enum xen_driver_type driver);
+
+
+/**
+ * Change the media in the device for CDROM-like devices only. For
+ * other devices, detach the VBD and attach a new one
+ */
+extern bool
+xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vbd_decl.h b/tools/libxen/include/xen_vbd_decl.h
new file mode 100644
index 0000000000..c6877866b6
--- /dev/null
+++ b/tools/libxen/include/xen_vbd_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VBD_DECL_H
+#define XEN_VBD_DECL_H
+
+typedef void *xen_vbd;
+
+struct xen_vbd_set;
+struct xen_vbd_record;
+struct xen_vbd_record_set;
+struct xen_vbd_record_opt;
+struct xen_vbd_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_vbd_mode.h b/tools/libxen/include/xen_vbd_mode.h
new file mode 100644
index 0000000000..b0cd1c2cf3
--- /dev/null
+++ b/tools/libxen/include/xen_vbd_mode.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VBD_MODE_H
+#define XEN_VBD_MODE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_vbd_mode
+{
+ /**
+ * disk is mounted read-only
+ */
+ XEN_VBD_MODE_RO,
+
+ /**
+ * disk is mounted read-write
+ */
+ XEN_VBD_MODE_RW
+};
+
+
+typedef struct xen_vbd_mode_set
+{
+ size_t size;
+ enum xen_vbd_mode contents[];
+} xen_vbd_mode_set;
+
+/**
+ * Allocate a xen_vbd_mode_set of the given size.
+ */
+extern xen_vbd_mode_set *
+xen_vbd_mode_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vbd_mode_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_vbd_mode_set_free(xen_vbd_mode_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_vbd_mode_to_string(enum xen_vbd_mode val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_vbd_mode
+xen_vbd_mode_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vbd_mode_internal.h b/tools/libxen/include/xen_vbd_mode_internal.h
new file mode 100644
index 0000000000..3efd4a63d5
--- /dev/null
+++ b/tools/libxen/include/xen_vbd_mode_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_vbd_mode. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_VBD_MODE_INTERNAL_H
+#define XEN_VBD_MODE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_vbd_mode_abstract_type_;
+extern const abstract_type xen_vbd_mode_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_vdi.h b/tools/libxen/include/xen_vdi.h
new file mode 100644
index 0000000000..ba20f755c6
--- /dev/null
+++ b/tools/libxen/include/xen_vdi.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VDI_H
+#define XEN_VDI_H
+
+#include "xen_common.h"
+#include "xen_sr_decl.h"
+#include "xen_vbd_decl.h"
+#include "xen_vdi_decl.h"
+#include "xen_vdi_type.h"
+
+
+/*
+ * The VDI class.
+ *
+ * A virtual disk image.
+ */
+
+
+/**
+ * Free the given xen_vdi. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_vdi_free(xen_vdi vdi);
+
+
+typedef struct xen_vdi_set
+{
+ size_t size;
+ xen_vdi *contents[];
+} xen_vdi_set;
+
+/**
+ * Allocate a xen_vdi_set of the given size.
+ */
+extern xen_vdi_set *
+xen_vdi_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vdi_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_vdi_set_free(xen_vdi_set *set);
+
+
+typedef struct xen_vdi_record
+{
+ xen_vdi handle;
+ char *uuid;
+ char *name_label;
+ char *name_description;
+ struct xen_sr_record_opt *sr;
+ struct xen_vbd_record_opt_set *vbds;
+ int64_t virtual_size;
+ int64_t physical_utilisation;
+ int64_t sector_size;
+ enum xen_vdi_type type;
+ struct xen_vdi_record_opt *parent;
+ struct xen_vdi_record_opt_set *children;
+ bool sharable;
+ bool read_only;
+} xen_vdi_record;
+
+/**
+ * Allocate a xen_vdi_record.
+ */
+extern xen_vdi_record *
+xen_vdi_record_alloc(void);
+
+/**
+ * Free the given xen_vdi_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_vdi_record_free(xen_vdi_record *record);
+
+
+typedef struct xen_vdi_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_vdi handle;
+ xen_vdi_record *record;
+ } u;
+} xen_vdi_record_opt;
+
+/**
+ * Allocate a xen_vdi_record_opt.
+ */
+extern xen_vdi_record_opt *
+xen_vdi_record_opt_alloc(void);
+
+/**
+ * Free the given xen_vdi_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_vdi_record_opt_free(xen_vdi_record_opt *record_opt);
+
+
+typedef struct xen_vdi_record_set
+{
+ size_t size;
+ xen_vdi_record *contents[];
+} xen_vdi_record_set;
+
+/**
+ * Allocate a xen_vdi_record_set of the given size.
+ */
+extern xen_vdi_record_set *
+xen_vdi_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vdi_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_vdi_record_set_free(xen_vdi_record_set *set);
+
+
+
+typedef struct xen_vdi_record_opt_set
+{
+ size_t size;
+ xen_vdi_record_opt *contents[];
+} xen_vdi_record_opt_set;
+
+/**
+ * Allocate a xen_vdi_record_opt_set of the given size.
+ */
+extern xen_vdi_record_opt_set *
+xen_vdi_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vdi_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_vdi_record_opt_set_free(xen_vdi_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given VDI. !!!
+ */
+extern bool
+xen_vdi_get_record(xen_session *session, xen_vdi_record **result, xen_vdi vdi);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_vdi_get_by_uuid(xen_session *session, xen_vdi *result, char *uuid);
+
+
+/**
+ * Create a new VDI instance, and return its handle.
+ */
+extern bool
+xen_vdi_create(xen_session *session, xen_vdi *result, xen_vdi_record *record);
+
+
+/**
+ * Destroy the specified VDI instance.
+ */
+extern bool
+xen_vdi_destroy(xen_session *session, xen_vdi vdi);
+
+
+/**
+ * Get all the VDI instances with the given label.
+ */
+extern bool
+xen_vdi_get_by_name_label(xen_session *session, struct xen_vdi_set **result, char *label);
+
+
+/**
+ * Get the uuid field of the given VDI.
+ */
+extern bool
+xen_vdi_get_uuid(xen_session *session, char **result, xen_vdi vdi);
+
+
+/**
+ * Get the name/label field of the given VDI.
+ */
+extern bool
+xen_vdi_get_name_label(xen_session *session, char **result, xen_vdi vdi);
+
+
+/**
+ * Get the name/description field of the given VDI.
+ */
+extern bool
+xen_vdi_get_name_description(xen_session *session, char **result, xen_vdi vdi);
+
+
+/**
+ * Get the SR field of the given VDI.
+ */
+extern bool
+xen_vdi_get_sr(xen_session *session, xen_sr *result, xen_vdi vdi);
+
+
+/**
+ * Get the VBDs field of the given VDI.
+ */
+extern bool
+xen_vdi_get_vbds(xen_session *session, struct xen_vbd_set **result, xen_vdi vdi);
+
+
+/**
+ * Get the virtual_size field of the given VDI.
+ */
+extern bool
+xen_vdi_get_virtual_size(xen_session *session, int64_t *result, xen_vdi vdi);
+
+
+/**
+ * Get the physical_utilisation field of the given VDI.
+ */
+extern bool
+xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi vdi);
+
+
+/**
+ * Get the sector_size field of the given VDI.
+ */
+extern bool
+xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi);
+
+
+/**
+ * Get the type field of the given VDI.
+ */
+extern bool
+xen_vdi_get_type(xen_session *session, enum xen_vdi_type *result, xen_vdi vdi);
+
+
+/**
+ * Get the parent field of the given VDI.
+ */
+extern bool
+xen_vdi_get_parent(xen_session *session, xen_vdi *result, xen_vdi vdi);
+
+
+/**
+ * Get the children field of the given VDI.
+ */
+extern bool
+xen_vdi_get_children(xen_session *session, struct xen_vdi_set **result, xen_vdi vdi);
+
+
+/**
+ * Get the sharable field of the given VDI.
+ */
+extern bool
+xen_vdi_get_sharable(xen_session *session, bool *result, xen_vdi vdi);
+
+
+/**
+ * Get the read_only field of the given VDI.
+ */
+extern bool
+xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi);
+
+
+/**
+ * Set the name/label field of the given VDI.
+ */
+extern bool
+xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label);
+
+
+/**
+ * Set the name/description field of the given VDI.
+ */
+extern bool
+xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description);
+
+
+/**
+ * Set the SR field of the given VDI.
+ */
+extern bool
+xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr);
+
+
+/**
+ * Set the virtual_size field of the given VDI.
+ */
+extern bool
+xen_vdi_set_virtual_size(xen_session *session, xen_vdi vdi, int64_t virtual_size);
+
+
+/**
+ * Set the sharable field of the given VDI.
+ */
+extern bool
+xen_vdi_set_sharable(xen_session *session, xen_vdi vdi, bool sharable);
+
+
+/**
+ * Set the read_only field of the given VDI.
+ */
+extern bool
+xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only);
+
+
+/**
+ * Take an exact copy of the VDI; the snapshot lives in the same
+ * Storage Repository as its parent.
+ */
+extern bool
+xen_vdi_snapshot(xen_session *session, xen_vdi *result, xen_vdi vdi);
+
+
+/**
+ * Resize the vdi to the size.
+ */
+extern bool
+xen_vdi_resize(xen_session *session, xen_vdi vdi, int64_t size);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vdi_decl.h b/tools/libxen/include/xen_vdi_decl.h
new file mode 100644
index 0000000000..34692a2495
--- /dev/null
+++ b/tools/libxen/include/xen_vdi_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VDI_DECL_H
+#define XEN_VDI_DECL_H
+
+typedef void *xen_vdi;
+
+struct xen_vdi_set;
+struct xen_vdi_record;
+struct xen_vdi_record_set;
+struct xen_vdi_record_opt;
+struct xen_vdi_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_vdi_type.h b/tools/libxen/include/xen_vdi_type.h
new file mode 100644
index 0000000000..33ba7c61bf
--- /dev/null
+++ b/tools/libxen/include/xen_vdi_type.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VDI_TYPE_H
+#define XEN_VDI_TYPE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_vdi_type
+{
+ /**
+ * a disk that may be replaced on upgrade
+ */
+ XEN_VDI_TYPE_SYSTEM,
+
+ /**
+ * a disk that is always preserved on upgrade
+ */
+ XEN_VDI_TYPE_USER,
+
+ /**
+ * a disk that may be reformatted on upgrade
+ */
+ XEN_VDI_TYPE_EPHEMERAL
+};
+
+
+typedef struct xen_vdi_type_set
+{
+ size_t size;
+ enum xen_vdi_type contents[];
+} xen_vdi_type_set;
+
+/**
+ * Allocate a xen_vdi_type_set of the given size.
+ */
+extern xen_vdi_type_set *
+xen_vdi_type_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vdi_type_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_vdi_type_set_free(xen_vdi_type_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_vdi_type_to_string(enum xen_vdi_type val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_vdi_type
+xen_vdi_type_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vdi_type_internal.h b/tools/libxen/include/xen_vdi_type_internal.h
new file mode 100644
index 0000000000..1de23c8c83
--- /dev/null
+++ b/tools/libxen/include/xen_vdi_type_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_vdi_type. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_VDI_TYPE_INTERNAL_H
+#define XEN_VDI_TYPE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_vdi_type_abstract_type_;
+extern const abstract_type xen_vdi_type_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_vif.h b/tools/libxen/include/xen_vif.h
new file mode 100644
index 0000000000..8930a7849f
--- /dev/null
+++ b/tools/libxen/include/xen_vif.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VIF_H
+#define XEN_VIF_H
+
+#include "xen_common.h"
+#include "xen_driver_type.h"
+#include "xen_network_decl.h"
+#include "xen_vif_decl.h"
+#include "xen_vm_decl.h"
+
+
+/*
+ * The VIF class.
+ *
+ * A virtual network interface.
+ */
+
+
+/**
+ * Free the given xen_vif. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_vif_free(xen_vif vif);
+
+
+typedef struct xen_vif_set
+{
+ size_t size;
+ xen_vif *contents[];
+} xen_vif_set;
+
+/**
+ * Allocate a xen_vif_set of the given size.
+ */
+extern xen_vif_set *
+xen_vif_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vif_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_vif_set_free(xen_vif_set *set);
+
+
+typedef struct xen_vif_record
+{
+ xen_vif handle;
+ char *uuid;
+ char *name;
+ enum xen_driver_type type;
+ char *device;
+ struct xen_network_record_opt *network;
+ struct xen_vm_record_opt *vm;
+ char *mac;
+ int64_t mtu;
+ double io_read_kbs;
+ double io_write_kbs;
+} xen_vif_record;
+
+/**
+ * Allocate a xen_vif_record.
+ */
+extern xen_vif_record *
+xen_vif_record_alloc(void);
+
+/**
+ * Free the given xen_vif_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_vif_record_free(xen_vif_record *record);
+
+
+typedef struct xen_vif_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_vif handle;
+ xen_vif_record *record;
+ } u;
+} xen_vif_record_opt;
+
+/**
+ * Allocate a xen_vif_record_opt.
+ */
+extern xen_vif_record_opt *
+xen_vif_record_opt_alloc(void);
+
+/**
+ * Free the given xen_vif_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_vif_record_opt_free(xen_vif_record_opt *record_opt);
+
+
+typedef struct xen_vif_record_set
+{
+ size_t size;
+ xen_vif_record *contents[];
+} xen_vif_record_set;
+
+/**
+ * Allocate a xen_vif_record_set of the given size.
+ */
+extern xen_vif_record_set *
+xen_vif_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vif_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_vif_record_set_free(xen_vif_record_set *set);
+
+
+
+typedef struct xen_vif_record_opt_set
+{
+ size_t size;
+ xen_vif_record_opt *contents[];
+} xen_vif_record_opt_set;
+
+/**
+ * Allocate a xen_vif_record_opt_set of the given size.
+ */
+extern xen_vif_record_opt_set *
+xen_vif_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vif_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_vif_record_opt_set_free(xen_vif_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given VIF. !!!
+ */
+extern bool
+xen_vif_get_record(xen_session *session, xen_vif_record **result, xen_vif vif);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_vif_get_by_uuid(xen_session *session, xen_vif *result, char *uuid);
+
+
+/**
+ * Create a new VIF instance, and return its handle.
+ */
+extern bool
+xen_vif_create(xen_session *session, xen_vif *result, xen_vif_record *record);
+
+
+/**
+ * Destroy the specified VIF instance.
+ */
+extern bool
+xen_vif_destroy(xen_session *session, xen_vif vif);
+
+
+/**
+ * Get the uuid field of the given VIF.
+ */
+extern bool
+xen_vif_get_uuid(xen_session *session, char **result, xen_vif vif);
+
+
+/**
+ * Get the name field of the given VIF.
+ */
+extern bool
+xen_vif_get_name(xen_session *session, char **result, xen_vif vif);
+
+
+/**
+ * Get the type field of the given VIF.
+ */
+extern bool
+xen_vif_get_type(xen_session *session, enum xen_driver_type *result, xen_vif vif);
+
+
+/**
+ * Get the device field of the given VIF.
+ */
+extern bool
+xen_vif_get_device(xen_session *session, char **result, xen_vif vif);
+
+
+/**
+ * Get the network field of the given VIF.
+ */
+extern bool
+xen_vif_get_network(xen_session *session, xen_network *result, xen_vif vif);
+
+
+/**
+ * Get the VM field of the given VIF.
+ */
+extern bool
+xen_vif_get_vm(xen_session *session, xen_vm *result, xen_vif vif);
+
+
+/**
+ * Get the MAC field of the given VIF.
+ */
+extern bool
+xen_vif_get_mac(xen_session *session, char **result, xen_vif vif);
+
+
+/**
+ * Get the MTU field of the given VIF.
+ */
+extern bool
+xen_vif_get_mtu(xen_session *session, int64_t *result, xen_vif vif);
+
+
+/**
+ * Get the io/read_kbs field of the given VIF.
+ */
+extern bool
+xen_vif_get_io_read_kbs(xen_session *session, double *result, xen_vif vif);
+
+
+/**
+ * Get the io/write_kbs field of the given VIF.
+ */
+extern bool
+xen_vif_get_io_write_kbs(xen_session *session, double *result, xen_vif vif);
+
+
+/**
+ * Set the name field of the given VIF.
+ */
+extern bool
+xen_vif_set_name(xen_session *session, xen_vif vif, char *name);
+
+
+/**
+ * Set the type field of the given VIF.
+ */
+extern bool
+xen_vif_set_type(xen_session *session, xen_vif vif, enum xen_driver_type type);
+
+
+/**
+ * Set the device field of the given VIF.
+ */
+extern bool
+xen_vif_set_device(xen_session *session, xen_vif vif, char *device);
+
+
+/**
+ * Set the network field of the given VIF.
+ */
+extern bool
+xen_vif_set_network(xen_session *session, xen_vif vif, xen_network network);
+
+
+/**
+ * Set the VM field of the given VIF.
+ */
+extern bool
+xen_vif_set_vm(xen_session *session, xen_vif vif, xen_vm vm);
+
+
+/**
+ * Set the MAC field of the given VIF.
+ */
+extern bool
+xen_vif_set_mac(xen_session *session, xen_vif vif, char *mac);
+
+
+/**
+ * Set the MTU field of the given VIF.
+ */
+extern bool
+xen_vif_set_mtu(xen_session *session, xen_vif vif, int64_t mtu);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vif_decl.h b/tools/libxen/include/xen_vif_decl.h
new file mode 100644
index 0000000000..6a130f7154
--- /dev/null
+++ b/tools/libxen/include/xen_vif_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VIF_DECL_H
+#define XEN_VIF_DECL_H
+
+typedef void *xen_vif;
+
+struct xen_vif_set;
+struct xen_vif_record;
+struct xen_vif_record_set;
+struct xen_vif_record_opt;
+struct xen_vif_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_vm.h b/tools/libxen/include/xen_vm.h
new file mode 100644
index 0000000000..f589a3eea5
--- /dev/null
+++ b/tools/libxen/include/xen_vm.h
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VM_H
+#define XEN_VM_H
+
+#include "xen_boot_type.h"
+#include "xen_common.h"
+#include "xen_cpu_feature.h"
+#include "xen_host_decl.h"
+#include "xen_int_float_map.h"
+#include "xen_on_crash_behaviour.h"
+#include "xen_on_normal_exit.h"
+#include "xen_string_string_map.h"
+#include "xen_vbd_decl.h"
+#include "xen_vif_decl.h"
+#include "xen_vm_decl.h"
+#include "xen_vm_power_state.h"
+#include "xen_vtpm_decl.h"
+
+
+/*
+ * The VM class.
+ *
+ * A virtual machine (or 'guest').
+ */
+
+
+/**
+ * Free the given xen_vm. The given handle must have been allocated by
+ * this library.
+ */
+extern void
+xen_vm_free(xen_vm vm);
+
+
+typedef struct xen_vm_set
+{
+ size_t size;
+ xen_vm *contents[];
+} xen_vm_set;
+
+/**
+ * Allocate a xen_vm_set of the given size.
+ */
+extern xen_vm_set *
+xen_vm_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vm_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_vm_set_free(xen_vm_set *set);
+
+
+typedef struct xen_vm_record
+{
+ xen_vm handle;
+ char *uuid;
+ enum xen_vm_power_state power_state;
+ char *name_label;
+ char *name_description;
+ int64_t user_version;
+ bool is_a_template;
+ struct xen_host_record_opt *resident_on;
+ int64_t memory_static_max;
+ int64_t memory_dynamic_max;
+ int64_t memory_actual;
+ int64_t memory_dynamic_min;
+ int64_t memory_static_min;
+ char *vcpus_policy;
+ char *vcpus_params;
+ int64_t vcpus_number;
+ xen_int_float_map *vcpus_utilisation;
+ struct xen_cpu_feature_set *vcpus_features_required;
+ struct xen_cpu_feature_set *vcpus_features_can_use;
+ struct xen_cpu_feature_set *vcpus_features_force_on;
+ struct xen_cpu_feature_set *vcpus_features_force_off;
+ enum xen_on_normal_exit actions_after_shutdown;
+ enum xen_on_normal_exit actions_after_reboot;
+ enum xen_on_normal_exit actions_after_suspend;
+ enum xen_on_crash_behaviour actions_after_crash;
+ struct xen_vif_record_opt_set *vifs;
+ struct xen_vbd_record_opt_set *vbds;
+ struct xen_vtpm_record_opt_set *vtpms;
+ char *bios_boot;
+ bool platform_std_vga;
+ char *platform_serial;
+ bool platform_localtime;
+ bool platform_clock_offset;
+ bool platform_enable_audio;
+ char *builder;
+ enum xen_boot_type boot_method;
+ char *kernel_kernel;
+ char *kernel_initrd;
+ char *kernel_args;
+ char *grub_cmdline;
+ char *pci_bus;
+ xen_string_string_map *tools_version;
+ xen_string_string_map *otherconfig;
+} xen_vm_record;
+
+/**
+ * Allocate a xen_vm_record.
+ */
+extern xen_vm_record *
+xen_vm_record_alloc(void);
+
+/**
+ * Free the given xen_vm_record, and all referenced values. The given
+ * record must have been allocated by this library.
+ */
+extern void
+xen_vm_record_free(xen_vm_record *record);
+
+
+typedef struct xen_vm_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_vm handle;
+ xen_vm_record *record;
+ } u;
+} xen_vm_record_opt;
+
+/**
+ * Allocate a xen_vm_record_opt.
+ */
+extern xen_vm_record_opt *
+xen_vm_record_opt_alloc(void);
+
+/**
+ * Free the given xen_vm_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_vm_record_opt_free(xen_vm_record_opt *record_opt);
+
+
+typedef struct xen_vm_record_set
+{
+ size_t size;
+ xen_vm_record *contents[];
+} xen_vm_record_set;
+
+/**
+ * Allocate a xen_vm_record_set of the given size.
+ */
+extern xen_vm_record_set *
+xen_vm_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vm_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_vm_record_set_free(xen_vm_record_set *set);
+
+
+
+typedef struct xen_vm_record_opt_set
+{
+ size_t size;
+ xen_vm_record_opt *contents[];
+} xen_vm_record_opt_set;
+
+/**
+ * Allocate a xen_vm_record_opt_set of the given size.
+ */
+extern xen_vm_record_opt_set *
+xen_vm_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vm_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_vm_record_opt_set_free(xen_vm_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given VM. !!!
+ */
+extern bool
+xen_vm_get_record(xen_session *session, xen_vm_record **result, xen_vm vm);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_vm_get_by_uuid(xen_session *session, xen_vm *result, char *uuid);
+
+
+/**
+ * Create a new VM instance, and return its handle.
+ */
+extern bool
+xen_vm_create(xen_session *session, xen_vm *result, xen_vm_record *record);
+
+
+/**
+ * Destroy the specified VM. The VM is completely removed from the
+ * system. This function can only be called when the VM is in the Halted
+ * State.
+ */
+extern bool
+xen_vm_destroy(xen_session *session, xen_vm vm);
+
+
+/**
+ * Get all the VM instances with the given label.
+ */
+extern bool
+xen_vm_get_by_name_label(xen_session *session, struct xen_vm_set **result, char *label);
+
+
+/**
+ * Get the uuid field of the given VM.
+ */
+extern bool
+xen_vm_get_uuid(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the power_state field of the given VM.
+ */
+extern bool
+xen_vm_get_power_state(xen_session *session, enum xen_vm_power_state *result, xen_vm vm);
+
+
+/**
+ * Get the name/label field of the given VM.
+ */
+extern bool
+xen_vm_get_name_label(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the name/description field of the given VM.
+ */
+extern bool
+xen_vm_get_name_description(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the user_version field of the given VM.
+ */
+extern bool
+xen_vm_get_user_version(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the is_a_template field of the given VM.
+ */
+extern bool
+xen_vm_get_is_a_template(xen_session *session, bool *result, xen_vm vm);
+
+
+/**
+ * Get the resident_on field of the given VM.
+ */
+extern bool
+xen_vm_get_resident_on(xen_session *session, xen_host *result, xen_vm vm);
+
+
+/**
+ * Get the memory/static_max field of the given VM.
+ */
+extern bool
+xen_vm_get_memory_static_max(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the memory/dynamic_max field of the given VM.
+ */
+extern bool
+xen_vm_get_memory_dynamic_max(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the memory/actual field of the given VM.
+ */
+extern bool
+xen_vm_get_memory_actual(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the memory/dynamic_min field of the given VM.
+ */
+extern bool
+xen_vm_get_memory_dynamic_min(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the memory/static_min field of the given VM.
+ */
+extern bool
+xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/policy field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/params field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_params(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/number field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_number(xen_session *session, int64_t *result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/utilisation field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_utilisation(xen_session *session, xen_int_float_map **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/features/required field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_features_required(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/features/can_use field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_features_can_use(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/features/force_on field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_features_force_on(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm);
+
+
+/**
+ * Get the VCPUs/features/force_off field of the given VM.
+ */
+extern bool
+xen_vm_get_vcpus_features_force_off(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm);
+
+
+/**
+ * Get the actions/after_shutdown field of the given VM.
+ */
+extern bool
+xen_vm_get_actions_after_shutdown(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm);
+
+
+/**
+ * Get the actions/after_reboot field of the given VM.
+ */
+extern bool
+xen_vm_get_actions_after_reboot(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm);
+
+
+/**
+ * Get the actions/after_suspend field of the given VM.
+ */
+extern bool
+xen_vm_get_actions_after_suspend(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm);
+
+
+/**
+ * Get the actions/after_crash field of the given VM.
+ */
+extern bool
+xen_vm_get_actions_after_crash(xen_session *session, enum xen_on_crash_behaviour *result, xen_vm vm);
+
+
+/**
+ * Get the VIFs field of the given VM.
+ */
+extern bool
+xen_vm_get_vifs(xen_session *session, struct xen_vif_set **result, xen_vm vm);
+
+
+/**
+ * Get the VBDs field of the given VM.
+ */
+extern bool
+xen_vm_get_vbds(xen_session *session, struct xen_vbd_set **result, xen_vm vm);
+
+
+/**
+ * Get the VTPMs field of the given VM.
+ */
+extern bool
+xen_vm_get_vtpms(xen_session *session, struct xen_vtpm_set **result, xen_vm vm);
+
+
+/**
+ * Get the bios/boot field of the given VM.
+ */
+extern bool
+xen_vm_get_bios_boot(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the platform/std_VGA field of the given VM.
+ */
+extern bool
+xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm);
+
+
+/**
+ * Get the platform/serial field of the given VM.
+ */
+extern bool
+xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the platform/localtime field of the given VM.
+ */
+extern bool
+xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm);
+
+
+/**
+ * Get the platform/clock_offset field of the given VM.
+ */
+extern bool
+xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm);
+
+
+/**
+ * Get the platform/enable_audio field of the given VM.
+ */
+extern bool
+xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm);
+
+
+/**
+ * Get the builder field of the given VM.
+ */
+extern bool
+xen_vm_get_builder(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the boot_method field of the given VM.
+ */
+extern bool
+xen_vm_get_boot_method(xen_session *session, enum xen_boot_type *result, xen_vm vm);
+
+
+/**
+ * Get the kernel/kernel field of the given VM.
+ */
+extern bool
+xen_vm_get_kernel_kernel(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the kernel/initrd field of the given VM.
+ */
+extern bool
+xen_vm_get_kernel_initrd(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the kernel/args field of the given VM.
+ */
+extern bool
+xen_vm_get_kernel_args(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the grub/cmdline field of the given VM.
+ */
+extern bool
+xen_vm_get_grub_cmdline(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the PCI_bus field of the given VM.
+ */
+extern bool
+xen_vm_get_pci_bus(xen_session *session, char **result, xen_vm vm);
+
+
+/**
+ * Get the tools_version field of the given VM.
+ */
+extern bool
+xen_vm_get_tools_version(xen_session *session, xen_string_string_map **result, xen_vm vm);
+
+
+/**
+ * Get the otherConfig field of the given VM.
+ */
+extern bool
+xen_vm_get_otherconfig(xen_session *session, xen_string_string_map **result, xen_vm vm);
+
+
+/**
+ * Set the name/label field of the given VM.
+ */
+extern bool
+xen_vm_set_name_label(xen_session *session, xen_vm vm, char *label);
+
+
+/**
+ * Set the name/description field of the given VM.
+ */
+extern bool
+xen_vm_set_name_description(xen_session *session, xen_vm vm, char *description);
+
+
+/**
+ * Set the user_version field of the given VM.
+ */
+extern bool
+xen_vm_set_user_version(xen_session *session, xen_vm vm, int64_t user_version);
+
+
+/**
+ * Set the is_a_template field of the given VM.
+ */
+extern bool
+xen_vm_set_is_a_template(xen_session *session, xen_vm vm, bool is_a_template);
+
+
+/**
+ * Set the memory/dynamic_max field of the given VM.
+ */
+extern bool
+xen_vm_set_memory_dynamic_max(xen_session *session, xen_vm vm, int64_t dynamic_max);
+
+
+/**
+ * Set the memory/dynamic_min field of the given VM.
+ */
+extern bool
+xen_vm_set_memory_dynamic_min(xen_session *session, xen_vm vm, int64_t dynamic_min);
+
+
+/**
+ * Set the VCPUs/policy field of the given VM.
+ */
+extern bool
+xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy);
+
+
+/**
+ * Set the VCPUs/params field of the given VM.
+ */
+extern bool
+xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, char *params);
+
+
+/**
+ * Set the VCPUs/features/force_on field of the given VM.
+ */
+extern bool
+xen_vm_set_vcpus_features_force_on(xen_session *session, xen_vm vm, struct xen_cpu_feature_set *force_on);
+
+
+/**
+ * Set the VCPUs/features/force_off field of the given VM.
+ */
+extern bool
+xen_vm_set_vcpus_features_force_off(xen_session *session, xen_vm vm, struct xen_cpu_feature_set *force_off);
+
+
+/**
+ * Set the actions/after_shutdown field of the given VM.
+ */
+extern bool
+xen_vm_set_actions_after_shutdown(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_shutdown);
+
+
+/**
+ * Set the actions/after_reboot field of the given VM.
+ */
+extern bool
+xen_vm_set_actions_after_reboot(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_reboot);
+
+
+/**
+ * Set the actions/after_suspend field of the given VM.
+ */
+extern bool
+xen_vm_set_actions_after_suspend(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_suspend);
+
+
+/**
+ * Set the actions/after_crash field of the given VM.
+ */
+extern bool
+xen_vm_set_actions_after_crash(xen_session *session, xen_vm vm, enum xen_on_crash_behaviour after_crash);
+
+
+/**
+ * Set the bios/boot field of the given VM.
+ */
+extern bool
+xen_vm_set_bios_boot(xen_session *session, xen_vm vm, char *boot);
+
+
+/**
+ * Set the platform/std_VGA field of the given VM.
+ */
+extern bool
+xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga);
+
+
+/**
+ * Set the platform/serial field of the given VM.
+ */
+extern bool
+xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial);
+
+
+/**
+ * Set the platform/localtime field of the given VM.
+ */
+extern bool
+xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime);
+
+
+/**
+ * Set the platform/clock_offset field of the given VM.
+ */
+extern bool
+xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset);
+
+
+/**
+ * Set the platform/enable_audio field of the given VM.
+ */
+extern bool
+xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio);
+
+
+/**
+ * Set the builder field of the given VM.
+ */
+extern bool
+xen_vm_set_builder(xen_session *session, xen_vm vm, char *builder);
+
+
+/**
+ * Set the boot_method field of the given VM.
+ */
+extern bool
+xen_vm_set_boot_method(xen_session *session, xen_vm vm, enum xen_boot_type boot_method);
+
+
+/**
+ * Set the kernel/kernel field of the given VM.
+ */
+extern bool
+xen_vm_set_kernel_kernel(xen_session *session, xen_vm vm, char *kernel);
+
+
+/**
+ * Set the kernel/initrd field of the given VM.
+ */
+extern bool
+xen_vm_set_kernel_initrd(xen_session *session, xen_vm vm, char *initrd);
+
+
+/**
+ * Set the kernel/args field of the given VM.
+ */
+extern bool
+xen_vm_set_kernel_args(xen_session *session, xen_vm vm, char *args);
+
+
+/**
+ * Set the grub/cmdline field of the given VM.
+ */
+extern bool
+xen_vm_set_grub_cmdline(xen_session *session, xen_vm vm, char *cmdline);
+
+
+/**
+ * Set the otherConfig field of the given VM.
+ */
+extern bool
+xen_vm_set_otherconfig(xen_session *session, xen_vm vm, xen_string_string_map *otherconfig);
+
+
+/**
+ * Clones the specified VM, making a new VM. Clone automatically
+ * exploits the capabilities of the underlying storage repository in which the
+ * VM's disk images are stored (e.g. Copy on Write). This function can only
+ * be called when the VM is in the Halted State.
+ */
+extern bool
+xen_vm_clone(xen_session *session, xen_vm *result, xen_vm vm, char *new_name);
+
+
+/**
+ * Start the specified VM. This function can only be called with the
+ * VM is in the Halted State.
+ */
+extern bool
+xen_vm_start(xen_session *session, xen_vm vm, bool start_paused);
+
+
+/**
+ * Pause the specified VM. This can only be called when the specified
+ * VM is in the Running state.
+ */
+extern bool
+xen_vm_pause(xen_session *session, xen_vm vm);
+
+
+/**
+ * Resume the specified VM. This can only be called when the specified
+ * VM is in the Paused state.
+ */
+extern bool
+xen_vm_unpause(xen_session *session, xen_vm vm);
+
+
+/**
+ * Attempt to cleanly shutdown the specified VM. (Note: this may not be
+ * supported---e.g. if a guest agent is not installed).
+ *
+ * Once shutdown has been completed perform poweroff action specified in guest
+ * configuration.
+ */
+extern bool
+xen_vm_clean_shutdown(xen_session *session, xen_vm vm);
+
+
+/**
+ * Attempt to cleanly shutdown the specified VM (Note: this may not be
+ * supported---e.g. if a guest agent is not installed).
+ *
+ * Once shutdown has been completed perform reboot action specified in guest
+ * configuration.
+ */
+extern bool
+xen_vm_clean_reboot(xen_session *session, xen_vm vm);
+
+
+/**
+ * Stop executing the specified VM without attempting a clean shutdown.
+ * Then perform poweroff action specified in VM configuration.
+ */
+extern bool
+xen_vm_hard_shutdown(xen_session *session, xen_vm vm);
+
+
+/**
+ * Stop executing the specified VM without attempting a clean shutdown.
+ * Then perform reboot action specified in VM configuration
+ */
+extern bool
+xen_vm_hard_reboot(xen_session *session, xen_vm vm);
+
+
+/**
+ * Suspend the specified VM to disk.
+ */
+extern bool
+xen_vm_suspend(xen_session *session, xen_vm vm);
+
+
+/**
+ * Awaken the specified VM and resume it.
+ */
+extern bool
+xen_vm_resume(xen_session *session, xen_vm vm, bool start_paused);
+
+
+/**
+ * Return a list of all the VMs known to the system.
+ */
+extern bool
+xen_vm_get_all(xen_session *session, struct xen_vm_set **result);
+
+
+/**
+ * Destroy the specified VM. The VM is completely removed from the system.
+ * This function can only be called when the VM is in the Halted State.
+ */
+extern bool
+xen_vm_destroy(xen_session *session, xen_vm vm);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vm_decl.h b/tools/libxen/include/xen_vm_decl.h
new file mode 100644
index 0000000000..815b036ea5
--- /dev/null
+++ b/tools/libxen/include/xen_vm_decl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VM_DECL_H
+#define XEN_VM_DECL_H
+
+typedef void *xen_vm;
+
+struct xen_vm_set;
+struct xen_vm_record;
+struct xen_vm_record_set;
+struct xen_vm_record_opt;
+struct xen_vm_record_opt_set;
+
+#endif
diff --git a/tools/libxen/include/xen_vm_power_state.h b/tools/libxen/include/xen_vm_power_state.h
new file mode 100644
index 0000000000..3e805ed671
--- /dev/null
+++ b/tools/libxen/include/xen_vm_power_state.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VM_POWER_STATE_H
+#define XEN_VM_POWER_STATE_H
+
+
+#include "xen_common.h"
+
+
+enum xen_vm_power_state
+{
+ /**
+ * Halted
+ */
+ XEN_VM_POWER_STATE_HALTED,
+
+ /**
+ * Paused
+ */
+ XEN_VM_POWER_STATE_PAUSED,
+
+ /**
+ * Running
+ */
+ XEN_VM_POWER_STATE_RUNNING,
+
+ /**
+ * Suspended
+ */
+ XEN_VM_POWER_STATE_SUSPENDED,
+
+ /**
+ * Shutting Down
+ */
+ XEN_VM_POWER_STATE_SHUTTINGDOWN,
+
+ /**
+ * Some other unknown state
+ */
+ XEN_VM_POWER_STATE_UNKNOWN
+};
+
+
+typedef struct xen_vm_power_state_set
+{
+ size_t size;
+ enum xen_vm_power_state contents[];
+} xen_vm_power_state_set;
+
+/**
+ * Allocate a xen_vm_power_state_set of the given size.
+ */
+extern xen_vm_power_state_set *
+xen_vm_power_state_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vm_power_state_set. The given set must have been
+ * allocated by this library.
+ */
+extern void
+xen_vm_power_state_set_free(xen_vm_power_state_set *set);
+
+
+/**
+ * Return the name corresponding to the given code. This string must
+ * not be modified or freed.
+ */
+extern const char *
+xen_vm_power_state_to_string(enum xen_vm_power_state val);
+
+
+/**
+ * Return the correct code for the given string, or set the session
+ * object to failure and return an undefined value if the given string does
+ * not match a known code.
+ */
+extern enum xen_vm_power_state
+xen_vm_power_state_from_string(xen_session *session, const char *str);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vm_power_state_internal.h b/tools/libxen/include/xen_vm_power_state_internal.h
new file mode 100644
index 0000000000..2c88856c08
--- /dev/null
+++ b/tools/libxen/include/xen_vm_power_state_internal.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Declarations of the abstract types used during demarshalling of enum
+ * xen_vm_power_state. Internal to this library -- do not use from outside.
+ */
+
+
+#ifndef XEN_VM_POWER_STATE_INTERNAL_H
+#define XEN_VM_POWER_STATE_INTERNAL_H
+
+
+#include "xen_internal.h"
+
+
+extern const abstract_type xen_vm_power_state_abstract_type_;
+extern const abstract_type xen_vm_power_state_set_abstract_type_;
+
+
+#endif
diff --git a/tools/libxen/include/xen_vtpm.h b/tools/libxen/include/xen_vtpm.h
new file mode 100644
index 0000000000..f55d74217b
--- /dev/null
+++ b/tools/libxen/include/xen_vtpm.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006, IBM Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VTPM_H
+#define XEN_VTPM_H
+
+#include "xen_common.h"
+#include "xen_driver_type.h"
+#include "xen_vm_decl.h"
+#include "xen_vtpm_decl.h"
+
+
+/*
+ * The VTPM class.
+ *
+ * A virtual TPM device.
+ */
+
+
+/**
+ * Free the given xen_vtpm. The given handle must have been allocated
+ * by this library.
+ */
+extern void
+xen_vtpm_free(xen_vtpm vtpm);
+
+
+typedef struct xen_vtpm_set
+{
+ size_t size;
+ xen_vtpm *contents[];
+} xen_vtpm_set;
+
+/**
+ * Allocate a xen_vtpm_set of the given size.
+ */
+extern xen_vtpm_set *
+xen_vtpm_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vtpm_set. The given set must have been allocated
+ * by this library.
+ */
+extern void
+xen_vtpm_set_free(xen_vtpm_set *set);
+
+
+typedef struct xen_vtpm_record
+{
+ xen_vtpm handle;
+ char *uuid;
+ struct xen_vm_record_opt *vm;
+ struct xen_vm_record_opt *backend;
+ enum xen_driver_type driver;
+ int64_t instance;
+} xen_vtpm_record;
+
+/**
+ * Allocate a xen_vtpm_record.
+ */
+extern xen_vtpm_record *
+xen_vtpm_record_alloc(void);
+
+/**
+ * Free the given xen_vtpm_record, and all referenced values. The
+ * given record must have been allocated by this library.
+ */
+extern void
+xen_vtpm_record_free(xen_vtpm_record *record);
+
+
+typedef struct xen_vtpm_record_opt
+{
+ bool is_record;
+ union
+ {
+ xen_vtpm handle;
+ xen_vtpm_record *record;
+ } u;
+} xen_vtpm_record_opt;
+
+/**
+ * Allocate a xen_vtpm_record_opt.
+ */
+extern xen_vtpm_record_opt *
+xen_vtpm_record_opt_alloc(void);
+
+/**
+ * Free the given xen_vtpm_record_opt, and all referenced values. The
+ * given record_opt must have been allocated by this library.
+ */
+extern void
+xen_vtpm_record_opt_free(xen_vtpm_record_opt *record_opt);
+
+
+typedef struct xen_vtpm_record_set
+{
+ size_t size;
+ xen_vtpm_record *contents[];
+} xen_vtpm_record_set;
+
+/**
+ * Allocate a xen_vtpm_record_set of the given size.
+ */
+extern xen_vtpm_record_set *
+xen_vtpm_record_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vtpm_record_set, and all referenced values. The
+ * given set must have been allocated by this library.
+ */
+extern void
+xen_vtpm_record_set_free(xen_vtpm_record_set *set);
+
+
+
+typedef struct xen_vtpm_record_opt_set
+{
+ size_t size;
+ xen_vtpm_record_opt *contents[];
+} xen_vtpm_record_opt_set;
+
+/**
+ * Allocate a xen_vtpm_record_opt_set of the given size.
+ */
+extern xen_vtpm_record_opt_set *
+xen_vtpm_record_opt_set_alloc(size_t size);
+
+/**
+ * Free the given xen_vtpm_record_opt_set, and all referenced values.
+ * The given set must have been allocated by this library.
+ */
+extern void
+xen_vtpm_record_opt_set_free(xen_vtpm_record_opt_set *set);
+
+
+/**
+ * Get the current state of the given VTPM. !!!
+ */
+extern bool
+xen_vtpm_get_record(xen_session *session, xen_vtpm_record **result, xen_vtpm vtpm);
+
+
+/**
+ * Get a reference to the object with the specified UUID. !!!
+ */
+extern bool
+xen_vtpm_get_by_uuid(xen_session *session, xen_vtpm *result, char *uuid);
+
+
+/**
+ * Create a new VTPM instance, and return its handle.
+ */
+extern bool
+xen_vtpm_create(xen_session *session, xen_vtpm *result, xen_vtpm_record *record);
+
+
+/**
+ * Destroy the specified VTPM instance.
+ */
+extern bool
+xen_vtpm_destroy(xen_session *session, xen_vtpm vtpm);
+
+
+/**
+ * Get the uuid field of the given VTPM.
+ */
+extern bool
+xen_vtpm_get_uuid(xen_session *session, char **result, xen_vtpm vtpm);
+
+
+/**
+ * Get the VM field of the given VTPM.
+ */
+extern bool
+xen_vtpm_get_vm(xen_session *session, xen_vm *result, xen_vtpm vtpm);
+
+
+/**
+ * Get the backend field of the given VTPM.
+ */
+extern bool
+xen_vtpm_get_backend(xen_session *session, xen_vm *result, xen_vtpm vtpm);
+
+
+/**
+ * Get the driver field of the given VTPM.
+ */
+extern bool
+xen_vtpm_get_driver(xen_session *session, enum xen_driver_type *result, xen_vtpm vtpm);
+
+
+/**
+ * Get the instance field of the given VTPM.
+ */
+extern bool
+xen_vtpm_get_instance(xen_session *session, int64_t *result, xen_vtpm vtpm);
+
+
+#endif
diff --git a/tools/libxen/include/xen_vtpm_decl.h b/tools/libxen/include/xen_vtpm_decl.h
new file mode 100644
index 0000000000..7798e3856d
--- /dev/null
+++ b/tools/libxen/include/xen_vtpm_decl.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006, IBM Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef XEN_VTPM_DECL_H
+#define XEN_VTPM_DECL_H
+
+typedef void *xen_vtpm;
+
+struct xen_vtpm_set;
+struct xen_vtpm_record;
+struct xen_vtpm_record_set;
+struct xen_vtpm_record_opt;
+struct xen_vtpm_record_opt_set;
+
+#endif
diff --git a/tools/libxen/src/xen_boot_type.c b/tools/libxen/src/xen_boot_type.c
new file mode 100644
index 0000000000..798d09ac2b
--- /dev/null
+++ b/tools/libxen/src/xen_boot_type.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_boot_type.h"
+#include "xen_boot_type_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "bios",
+ "grub",
+ "kernel_external",
+ "kernel_internal"
+};
+
+
+extern xen_boot_type_set *
+xen_boot_type_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_boot_type_set) +
+ size * sizeof(enum xen_boot_type));
+}
+
+
+extern void
+xen_boot_type_set_free(xen_boot_type_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_boot_type_to_string(enum xen_boot_type val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_boot_type
+xen_boot_type_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_boot_type_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_boot_type_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_boot_type_from_string
+ };
+
+
+const abstract_type xen_boot_type_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_boot_type_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c
new file mode 100644
index 0000000000..bd370bb257
--- /dev/null
+++ b/tools/libxen/src/xen_common.c
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2006 XenSource, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xmlstring.h>
+#include <libxml/xpath.h>
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_int_float_map.h"
+#include "xen_string_string_map.h"
+
+
+static xmlXPathCompExprPtr responsePath = NULL;
+static xmlXPathCompExprPtr faultPath = NULL;
+
+
+typedef struct
+{
+ size_t size;
+ void *contents[];
+} arbitrary_map;
+
+
+typedef struct
+{
+ void *handle;
+} arbitrary_record;
+
+
+typedef struct
+{
+ bool is_record;
+ union
+ {
+ char *handle;
+ arbitrary_record *record;
+ } u;
+} arbitrary_record_opt;
+
+
+static char *
+make_body(const char *, abstract_value [], int);
+
+static void
+parse_result(xen_session *, const char *, const abstract_type *, void *);
+
+static void
+add_value(xmlNode *, const char *, const char *);
+static void
+add_param(xmlNode *, const char *, const char *);
+
+static xmlNode *
+add_param_struct(xmlNode *);
+static xmlNode *
+add_struct_array(xmlNode *, const char *);
+static void
+add_struct_member(xmlNode *, const char *, const char *, const char *);
+static void
+add_unnamed_value(xmlNode *, const char *, const char *, const char *);
+
+static void
+add_struct_value(const struct abstract_type *, void *,
+ void (*)(xmlNode *, const char *, const char *,
+ const char *),
+ const char *, xmlNode *);
+
+static void
+call_raw(xen_session *, const char *, abstract_value [], int,
+ const abstract_type *, void *);
+
+static void
+parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
+ void *);
+
+static size_t size_of_member(const abstract_type *);
+
+
+void
+xen_init(void)
+{
+ responsePath =
+ xmlXPathCompile(
+ BAD_CAST(
+ "/methodResponse/params/param/value/struct/member/value"));
+ faultPath =
+ xmlXPathCompile(
+ BAD_CAST("/methodResponse/fault/value/struct/member/value"));
+}
+
+
+void
+xen_fini(void)
+{
+ xmlXPathFreeCompExpr(responsePath);
+ xmlXPathFreeCompExpr(faultPath);
+ responsePath = NULL;
+ faultPath = NULL;
+}
+
+
+xen_session *
+xen_session_login_with_password(xen_call_func call_func, void *handle,
+ const char *uname, const char *pwd)
+{
+ abstract_value params[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uname },
+ { .type = &abstract_type_string,
+ .u.string_val = pwd }
+ };
+
+ xen_session *session = malloc(sizeof(xen_session));
+ session->call_func = call_func;
+ session->handle = handle;
+ session->session_id = NULL;
+ session->ok = true;
+ session->error_description = NULL;
+ session->error_description_count = 0;
+
+ call_raw(session, "session.login_with_password", params, 2,
+ &abstract_type_string, &session->session_id);
+
+ return session;
+}
+
+
+void
+xen_session_logout(xen_session *session)
+{
+ abstract_value params[] =
+ {
+ };
+ xen_call_(session, "session.logout", params, 0, NULL, NULL);
+
+ if (session->error_description != NULL)
+ {
+ for (int i = 0; i < session->error_description_count; i++)
+ {
+ free(session->error_description[i]);
+ }
+ free(session->error_description);
+ }
+
+ free((char *)session->session_id);
+ free(session);
+}
+
+
+int
+xen_session_get_this_host(xen_session *session, xen_host *result)
+{
+ abstract_value params[] =
+ {
+ };
+
+ xen_call_(session, "session.get_this_host", params, 0,
+ &abstract_type_string, result);
+ return session->ok;
+}
+
+
+#define X "%02x"
+#define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X X
+
+
+bool
+xen_uuid_string_to_bytes(char *uuid, char **bytes)
+{
+ unsigned int buf[16];
+
+ *bytes = NULL;
+
+ if (strlen(uuid) != 36)
+ return false;
+
+ if (16 != sscanf(uuid, UUID_FORMAT,
+ buf + 0, buf + 1, buf + 2, buf + 3,
+ buf + 4, buf + 5,
+ buf + 6, buf + 7,
+ buf + 8, buf + 9,
+ buf + 10, buf + 11, buf + 12, buf + 13, buf + 14,
+ buf + 15))
+ {
+ return false;
+ }
+
+ *bytes = malloc(16);
+ if (*bytes == NULL)
+ return false;
+
+ for (int i = 0; i < 16; i++) {
+ (*bytes)[i] = (char)buf[i];
+ }
+
+ return true;
+}
+
+
+bool
+xen_uuid_bytes_to_string(char *bytes, char **uuid)
+{
+ *uuid = malloc(37);
+ if (*uuid == NULL)
+ return false;
+
+ sprintf(*uuid, UUID_FORMAT,
+ bytes[0], bytes[1], bytes[2], bytes[3],
+ bytes[4], bytes[5],
+ bytes[6], bytes[7],
+ bytes[8], bytes[9],
+ bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
+
+ return true;
+}
+
+
+#undef UUID_FORMAT
+#undef X
+
+
+void
+xen_uuid_free(char *uuid)
+{
+ free(uuid);
+}
+
+
+void
+xen_uuid_bytes_free(char *bytes)
+{
+ free(bytes);
+}
+
+
+/**
+ * @param value A pointer to the correct location as per the given
+ * result_type. Will be populated if the call succeeds. In that case, and if
+ * value is a char **, the char * itself must be freed by the caller.
+ */
+void
+xen_call_(xen_session *s, const char *method_name,
+ abstract_value params[], int param_count,
+ const abstract_type *result_type, void *value)
+{
+ if (!s->ok)
+ {
+ return;
+ }
+
+ abstract_value *full_params =
+ malloc(sizeof(abstract_value) * (param_count + 1));
+
+ full_params[0].type = &abstract_type_string;
+ full_params[0].u.string_val = s->session_id;
+
+ memcpy(full_params + 1, params, param_count * sizeof(abstract_value));
+
+ call_raw(s, method_name, full_params, param_count + 1, result_type,
+ value);
+
+ free(full_params);
+}
+
+
+static bool
+bufferAdd(const void *data, size_t len, void *buffer)
+{
+ return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);
+}
+
+
+static void
+call_raw(xen_session *s, const char *method_name,
+ abstract_value params[], int param_count,
+ const abstract_type *result_type, void *value)
+{
+ xmlBufferPtr buffer = xmlBufferCreate();
+ char *body = make_body(method_name, params, param_count);
+ int error_code =
+ s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd);
+ free(body);
+ if (error_code)
+ {
+ char **strings = malloc(2 * sizeof(char *));
+
+ strings[0] = xen_strdup_("TRANSPORT_FAULT");
+ strings[1] = malloc(20);
+ snprintf(strings[1], 20, "%d", error_code);
+
+ s->ok = false;
+ s->error_description = strings;
+ s->error_description_count = 2;
+ }
+ else
+ {
+ parse_result(s, (char *)xmlBufferContent(buffer), result_type, value);
+ }
+ xmlBufferFree(buffer);
+}
+
+
+static void server_error(xen_session *session, const char *error_string)
+{
+ if (!session->ok)
+ {
+ /* Don't wipe out the earlier error message with this one. */
+ return;
+ }
+
+ char **strings = malloc(2 * sizeof(char *));
+
+ strings[0] = xen_strdup_("SERVER_FAULT");
+ strings[1] = xen_strdup_(error_string);
+
+ session->ok = false;
+ session->error_description = strings;
+ session->error_description_count = 2;
+}
+
+
+static void server_error_2(xen_session *session, const char *error_string,
+ const char *param)
+{
+ if (!session->ok)
+ {
+ /* Don't wipe out the earlier error message with this one. */
+ return;
+ }
+
+ char **strings = malloc(3 * sizeof(char *));
+
+ strings[0] = xen_strdup_("SERVER_FAULT_2");
+ strings[1] = xen_strdup_(error_string);
+ strings[2] = xen_strdup_(param);
+
+ session->ok = false;
+ session->error_description = strings;
+ session->error_description_count = 3;
+}
+
+
+static bool is_container_node(xmlNode *n, char *type)
+{
+ return
+ n->type == XML_ELEMENT_NODE &&
+ 0 == strcmp((char *)n->name, type) &&
+ n->children != NULL &&
+ n->children == n->last &&
+ n->children->type == XML_ELEMENT_NODE;
+}
+
+
+/**
+ * @return The contents of the given value, or NULL if this is not a node with
+ * the given type. If not NULL, the result must be freed with xmlFree().
+ */
+static xmlChar *string_from_value(xmlNode *n, char *type)
+{
+ return
+ is_container_node(n, "value") &&
+ 0 == strcmp((char *)n->children->name, type) ?
+ (n->children->children == NULL ?
+ xmlStrdup(BAD_CAST("")) :
+ xmlNodeGetContent(n->children->children)) :
+ NULL;
+}
+
+
+/**
+ * Find the name node that is a child of the given one, and return its
+ * contents, or NULL if this has no such node. If not NULL, the result must
+ * be freed with xmlFree().
+ */
+static xmlChar *string_from_name(xmlNode *n)
+{
+ xmlNode *cur = n->children;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, "name"))
+ {
+ return xmlNodeGetContent(cur);
+ }
+ cur = cur->next;
+ }
+
+ return NULL;
+}
+
+
+static int count_children(xmlNode *n, const char *name)
+{
+ int result = 0;
+ xmlNode *cur = n->children;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, name))
+ {
+ result++;
+ }
+ cur = cur->next;
+ }
+
+ return result;
+}
+
+
+static void destring(xen_session *s, xmlChar *name, const abstract_type *type,
+ void *value)
+{
+ switch (type->typename)
+ {
+ case STRING:
+ *((char **)value) = xen_strdup_((const char *)name);
+ break;
+
+ case INT:
+ *((int64_t *)value) = atoll((const char *)name);
+ break;
+
+ case FLOAT:
+ *((double *)value) = atof((const char *)name);
+ break;
+
+ default:
+ server_error(s, "Invalid Map key type");
+ }
+}
+
+
+/**
+ * result_type : STRING => value : char **, the char * is yours.
+ * result_type : ENUM => value : int *
+ * result_type : INT => value : int64_t *
+ * result_type : FLOAT => value : double *
+ * result_type : BOOL => value : bool *
+ * result_type : SET => value : arbitrary_set **, the set is yours.
+ * result_type : MAP => value : arbitrary_map **, the map is yours.
+ * result_type : OPT => value : arbitrary_record_opt **,
+ * the record is yours, the handle is filled.
+ * result_type : STRUCT => value : void **, the void * is yours.
+ */
+static void parse_into(xen_session *s, xmlNode *value_node,
+ const abstract_type *result_type, void *value,
+ int slot)
+{
+ if (result_type == NULL)
+ {
+ xmlChar *string = string_from_value(value_node, "string");
+ if (string == NULL || strcmp((char *)string, ""))
+ {
+ server_error(s,
+ "Expected Void from the server, but didn't get it");
+ }
+ else
+ {
+ free(string);
+ }
+
+ return;
+ }
+
+ switch (result_type->typename)
+ {
+ case STRING:
+ {
+ xmlChar *string = string_from_value(value_node, "string");
+ if (string == NULL)
+ {
+ server_error(
+ s, "Expected a String from the server, but didn't get one");
+ }
+ else
+ {
+ ((char **)value)[slot] = xen_strdup_((const char *)string);
+ free(string);
+ }
+ }
+ break;
+
+ case ENUM:
+ {
+ xmlChar *string = string_from_value(value_node, "string");
+ if (string == NULL)
+ {
+ server_error(
+ s, "Expected an Enum from the server, but didn't get one");
+ }
+ else
+ {
+ ((int *)value)[slot] =
+ result_type->enum_demarshaller(s, (const char *)string);
+ free(string);
+ }
+ }
+ break;
+
+ case INT:
+ {
+ xmlChar *string = string_from_value(value_node, "string");
+ if (string == NULL)
+ {
+ server_error(
+ s, "Expected an Int from the server, but didn't get one");
+ }
+ else
+ {
+ ((int64_t *)value)[slot] = (int64_t)atoll((char *)string);
+ free(string);
+ }
+ }
+ break;
+
+ case FLOAT:
+ {
+ xmlChar *string = string_from_value(value_node, "double");
+ if (string == NULL)
+ {
+ server_error(
+ s, "Expected a Float from the server, but didn't get one");
+ }
+ else
+ {
+ ((double *)value)[slot] = atof((char *)string);
+ free(string);
+ }
+ }
+ break;
+
+ case BOOL:
+ {
+ xmlChar *string = string_from_value(value_node, "boolean");
+ if (string == NULL)
+ {
+ server_error(
+ s, "Expected a Bool from the server, but didn't get one");
+ }
+ else
+ {
+ ((bool *)value)[slot] = (0 == strcmp((char *)string, "1"));
+ free(string);
+ }
+ }
+ break;
+
+ case SET:
+ {
+ if (!is_container_node(value_node, "value") ||
+ !is_container_node(value_node->children, "array"))
+ {
+ server_error(s,
+ "Expected Set from the server, but didn't get it");
+ }
+ else
+ {
+ xmlNode *data_node = value_node->children->children;
+ int n = count_children(data_node, "value");
+
+ const abstract_type *member_type = result_type->child;
+ size_t member_size = size_of_member(member_type);
+
+ arbitrary_set *set =
+ calloc(1, sizeof(arbitrary_set) + member_size * n);
+ set->size = n;
+ int i = 0;
+ xmlNode *cur = data_node->children;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, "value"))
+ {
+ parse_into(s, cur, member_type, set->contents, i);
+ i++;
+ }
+ cur = cur->next;
+ }
+
+ ((arbitrary_set **)value)[slot] = set;
+ }
+ }
+ break;
+
+ case MAP:
+ {
+ if (!is_container_node(value_node, "value") ||
+ value_node->children->type != XML_ELEMENT_NODE ||
+ 0 != strcmp((char *)value_node->children->name, "struct") ||
+ value_node->children->children == NULL)
+ {
+ server_error(s,
+ "Expected Map from the server, but didn't get it");
+ }
+ else
+ {
+ xmlNode *struct_node = value_node->children;
+ int n = count_children(struct_node, "member");
+
+ size_t struct_size = result_type->struct_size;
+
+ const struct struct_member *key_member = result_type->members;
+ const struct struct_member *val_member = result_type->members + 1;
+
+ arbitrary_map *map =
+ calloc(1, sizeof(arbitrary_map) + struct_size * n);
+ map->size = n;
+ int i = 0;
+ xmlNode *cur = struct_node->children;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, "member"))
+ {
+ if (cur->children == NULL || cur->last == cur->children)
+ {
+ server_error(s, "Malformed Map");
+ free(map);
+ return;
+ }
+
+ xmlChar *name = string_from_name(cur);
+ if (name == NULL)
+ {
+ server_error(s, "Malformed Map");
+ free(map);
+ return;
+ }
+
+ destring(s, name, key_member->type,
+ ((void *)(map + 1)) +
+ (i * struct_size) +
+ key_member->offset);
+ xmlFree(name);
+ if (!s->ok)
+ {
+ free(map);
+ return;
+ }
+
+ parse_structmap_value(s, cur, val_member->type,
+ ((void *)(map + 1)) +
+ (i * struct_size) +
+ val_member->offset);
+ if (!s->ok)
+ {
+ free(map);
+ return;
+ }
+ i++;
+ }
+ cur = cur->next;
+ }
+
+ ((arbitrary_map **)value)[slot] = map;
+ }
+ }
+ break;
+
+ case STRUCT:
+ {
+ if (!is_container_node(value_node, "value") ||
+ value_node->children->type != XML_ELEMENT_NODE ||
+ 0 != strcmp((char *)value_node->children->name, "struct") ||
+ value_node->children->children == NULL)
+ {
+ server_error(s,
+ "Expected Map from the server, but didn't get it");
+ }
+ else
+ {
+ xmlNode *struct_node = value_node->children;
+
+ void *result = calloc(1, result_type->struct_size);
+ xmlNode *cur = struct_node->children;
+
+ size_t member_count = result_type->member_count;
+
+ const struct_member **checklist =
+ malloc(sizeof(const struct_member *) * member_count);
+ int seen_count = 0;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, "member"))
+ {
+ if (cur->children == NULL || cur->last == cur->children)
+ {
+ server_error(s, "Malformed Struct");
+ free(result);
+ free(checklist);
+ return;
+ }
+
+ xmlChar *name = string_from_name(cur);
+ if (name == NULL)
+ {
+ server_error(s, "Malformed Struct");
+ free(result);
+ free(checklist);
+ return;
+ }
+
+ for (size_t i = 0; i < member_count; i++)
+ {
+ const struct_member *mem = result_type->members + i;
+
+ if (0 == strcmp((char *)name, mem->key))
+ {
+ parse_structmap_value(s, cur, mem->type,
+ result + mem->offset);
+ checklist[seen_count] = mem;
+ seen_count++;
+ break;
+ }
+ }
+
+ /* Note that we're skipping unknown fields implicitly.
+ This means that we'll be forward compatible with
+ new servers. */
+
+ xmlFree(name);
+
+ if (!s->ok)
+ {
+ free(result);
+ free(checklist);
+ return;
+ }
+ }
+ cur = cur->next;
+ }
+
+ /* Check that we've filled all fields. */
+ for (size_t i = 0; i < member_count; i++)
+ {
+ const struct_member *mem = result_type->members + i;
+ int j;
+
+ for (j = 0; j < seen_count; j++)
+ {
+ if (checklist[j] == mem)
+ {
+ break;
+ }
+ }
+
+ if (j == seen_count)
+ {
+ server_error_2(s,
+ "Struct did not contain expected field",
+ mem->key);
+ free(result);
+ free(checklist);
+ return;
+ }
+ }
+
+ free(checklist);
+ ((void **)value)[slot] = result;
+ }
+ }
+ break;
+
+ case REF:
+ {
+ arbitrary_record_opt *record_opt =
+ calloc(1, sizeof(arbitrary_record_opt));
+
+ record_opt->is_record = false;
+ parse_into(s, value_node, &abstract_type_string,
+ &(record_opt->u.handle), 0);
+
+ ((arbitrary_record_opt **)value)[slot] = record_opt;
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+
+static size_t size_of_member(const abstract_type *type)
+{
+ switch (type->typename)
+ {
+ case STRING:
+ return sizeof(char *);
+
+/*
+ case INT:
+ return sizeof(int64_t);
+
+ case FLOAT:
+ return sizeof(double);
+
+ case BOOL:
+ return sizeof(bool);
+*/
+ case ENUM:
+ return sizeof(int);
+
+ case REF:
+ return sizeof(arbitrary_record_opt *);
+
+ default:
+ assert(false);
+ }
+}
+
+
+static void parse_structmap_value(xen_session *s, xmlNode *n,
+ const abstract_type *type, void *value)
+{
+ xmlNode *cur = n->children;
+
+ while (cur != NULL)
+ {
+ if (0 == strcmp((char *)cur->name, "value"))
+ {
+ parse_into(s, cur, type, value, 0);
+ return;
+ }
+ cur = cur->next;
+ }
+
+ server_error(s, "Missing value in Map/Struct");
+}
+
+
+static void parse_fault(xen_session *session, xmlXPathContextPtr xpathCtx)
+{
+ xmlXPathObjectPtr xpathObj = xmlXPathCompiledEval(faultPath, xpathCtx);
+ if (xpathObj == NULL)
+ {
+ server_error(session, "Method response is neither result nor fault");
+ return;
+ }
+
+ if (xpathObj->type != XPATH_NODESET ||
+ xpathObj->nodesetval->nodeNr != 2)
+ {
+ xmlXPathFreeObject(xpathObj);
+ server_error(session, "Method response is neither result nor fault");
+ return;
+ }
+
+ xmlNode *fault_node0 = xpathObj->nodesetval->nodeTab[0];
+ xmlNode *fault_node1 = xpathObj->nodesetval->nodeTab[1];
+
+ xmlChar *fault_code_str = string_from_value(fault_node0, "int");
+ if (fault_code_str == NULL)
+ {
+ fault_code_str = string_from_value(fault_node0, "i4");
+ }
+ if (fault_code_str == NULL)
+ {
+ xmlXPathFreeObject(xpathObj);
+ server_error(session, "Fault code is malformed");
+ return;
+ }
+
+ xmlChar *fault_string_str = string_from_value(fault_node1, "string");
+ if (fault_string_str == NULL)
+ {
+ xmlFree(fault_code_str);
+ xmlXPathFreeObject(xpathObj);
+ server_error(session, "Fault string is malformed");
+ return;
+ }
+
+ char **strings = malloc(3 * sizeof(char *));
+
+ strings[0] = xen_strdup_("FAULT");
+ strings[1] = xen_strdup_((char *)fault_code_str);
+ strings[2] = xen_strdup_((char *)fault_string_str);
+
+ session->ok = false;
+ session->error_description = strings;
+ session->error_description_count = 3;
+
+ xmlFree(fault_code_str);
+ xmlFree(fault_string_str);
+ xmlXPathFreeObject(xpathObj);
+}
+
+
+static void parse_failure(xen_session *session, xmlNode *node)
+{
+ abstract_type error_description_type =
+ { .typename = SET,
+ .child = &abstract_type_string };
+ arbitrary_set *error_descriptions;
+
+ parse_into(session, node, &error_description_type, &error_descriptions,
+ 0);
+
+ if (session->ok)
+ {
+ session->ok = false;
+
+ char **c = (char **)error_descriptions->contents;
+ int n = error_descriptions->size;
+
+ char **strings = malloc(3 * sizeof(char *));
+ for (int i = 0; i < n; i++)
+ {
+ strings[i] = xen_strdup_(c[i]);
+ }
+
+ session->error_description_count = n;
+ session->error_description = strings;
+ }
+
+ free(error_descriptions);
+}
+
+
+/**
+ * Parameters as for xen_call_() above.
+ */
+static void parse_result(xen_session *session, const char *result,
+ const abstract_type *result_type, void *value)
+{
+ xmlDocPtr doc =
+ xmlReadMemory(result, strlen(result), "", NULL, XML_PARSE_NONET);
+
+ if (doc == NULL)
+ {
+ server_error(session, "Couldn't parse the server response");
+ return;
+ }
+
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
+ if (xpathCtx == NULL)
+ {
+ xmlFreeDoc(doc);
+ server_error(session, "Couldn't create XPath context");
+ return;
+ }
+
+ xmlXPathObjectPtr xpathObj =
+ xmlXPathCompiledEval(responsePath, xpathCtx);
+ if (xpathObj == NULL)
+ {
+ parse_fault(session, xpathCtx);
+
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return;
+ }
+
+ if (xpathObj->type != XPATH_NODESET ||
+ xpathObj->nodesetval->nodeNr != 2)
+ {
+ parse_fault(session, xpathCtx);
+
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return;
+ }
+
+ xmlNode *node0 = xpathObj->nodesetval->nodeTab[0];
+ xmlNode *node1 = xpathObj->nodesetval->nodeTab[1];
+
+ xmlChar *status_code = string_from_value(node0, "string");
+ if (status_code == NULL)
+ {
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ server_error(session, "Server response does not have a Status");
+ return;
+ }
+
+ if (strcmp((char *)status_code, "Success"))
+ {
+ parse_failure(session, node1);
+
+ xmlFree(status_code);
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return;
+ }
+
+ parse_into(session, node1, result_type, value, 0);
+
+ xmlFree(status_code);
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+}
+
+
+static char *
+make_body(const char *method_name, abstract_value params[], int param_count)
+{
+ char buf[20];
+
+ xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
+ xmlNode *methodCall = xmlNewNode(NULL, BAD_CAST "methodCall");
+ xmlDocSetRootElement(doc, methodCall);
+
+ xmlNewChild(methodCall, NULL, BAD_CAST "methodName",
+ BAD_CAST method_name);
+
+ xmlNode *params_node =
+ xmlNewChild(methodCall, NULL, BAD_CAST "params", NULL);
+
+ for (int p = 0; p < param_count; p++)
+ {
+ abstract_value *v = params + p;
+ switch (v->type->typename)
+ {
+ case STRING:
+ add_param(params_node, "string", v->u.string_val);
+ break;
+
+ case INT:
+ snprintf(buf, sizeof(buf), "%"PRId64, v->u.int_val);
+ add_param(params_node, "string", buf);
+ break;
+
+ case FLOAT:
+ snprintf(buf, sizeof(buf), "%lf", v->u.float_val);
+ add_param(params_node, "double", buf);
+ break;
+
+ case BOOL:
+ add_param(params_node, "boolean", v->u.bool_val ? "1" : "0");
+ break;
+
+ case VOID:
+ add_param(params_node, "string", "");
+ break;
+
+ case ENUM:
+ add_param(params_node, "string",
+ v->type->enum_marshaller(v->u.enum_val));
+ break;
+
+ case STRUCT:
+ {
+ size_t member_count = v->type->member_count;
+
+ xmlNode *struct_node = add_param_struct(params_node);
+
+ for (size_t i = 0; i < member_count; i++)
+ {
+ const struct struct_member *mem = v->type->members + i;
+ const char *key = mem->key;
+ void *struct_value = v->u.struct_val;
+
+ add_struct_value(mem->type, struct_value + mem->offset,
+ add_struct_member, key, struct_node);
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ }
+
+ xmlBufferPtr buffer = xmlBufferCreate();
+ xmlSaveCtxtPtr save_ctxt =
+ xmlSaveToBuffer(buffer, NULL, XML_SAVE_NO_XHTML);
+
+ if (xmlSaveDoc(save_ctxt, doc) == -1)
+ {
+ return NULL;
+ }
+
+ xmlFreeDoc(doc);
+ xmlSaveClose(save_ctxt);
+ xmlChar *content = xmlStrdup(xmlBufferContent(buffer));
+ xmlBufferFree(buffer);
+ return (char *)content;
+}
+
+
+static void
+add_struct_value(const struct abstract_type *type, void *value,
+ void (*adder)(xmlNode *node, const char *key,
+ const char *type, const char *val),
+ const char *key, xmlNode *node)
+{
+ char buf[20];
+
+ switch (type->typename)
+ {
+ case REF:
+ {
+ arbitrary_record_opt *val = *(arbitrary_record_opt **)value;
+ if (val != NULL)
+ {
+ if (val->is_record)
+ {
+ adder(node, key, "string", val->u.record->handle);
+ }
+ else
+ {
+ adder(node, key, "string", val->u.handle);
+ }
+ }
+ }
+ break;
+
+ case STRING:
+ {
+ char *val = *(char **)value;
+ if (val != NULL)
+ {
+ adder(node, key, "string", val);
+ }
+ }
+ break;
+
+ case INT:
+ {
+ int64_t val = *(int64_t *)value;
+ snprintf(buf, sizeof(buf), "%"PRId64, val);
+ adder(node, key, "string", buf);
+ }
+ break;
+
+ case FLOAT:
+ {
+ double val = *(double *)value;
+ snprintf(buf, sizeof(buf), "%lf", val);
+ adder(node, key, "double", buf);
+ }
+ break;
+
+ case BOOL:
+ {
+ bool val = *(bool *)value;
+ adder(node, key, "boolean", val ? "1" : "0");
+ }
+ break;
+
+ case ENUM:
+ {
+ int val = *(int *)value;
+ adder(node, key, "string", type->enum_marshaller(val));
+ }
+ break;
+
+ case SET:
+ {
+ const struct abstract_type *member_type = type->child;
+ size_t member_size = size_of_member(member_type);
+ arbitrary_set *set_val = *(arbitrary_set **)value;
+
+ if (set_val != NULL)
+ {
+ xmlNode *data_node = add_struct_array(node, key);
+
+ for (size_t i = 0; i < set_val->size; i++)
+ {
+ void *member_value = set_val->contents + (i * member_size);
+ add_struct_value(member_type, member_value,
+ add_unnamed_value, NULL, data_node);
+ }
+ }
+ }
+ break;
+
+ case STRUCT:
+ case MAP:
+ {
+ /* XXX Nested structures aren't supported yet, but
+ fortunately we don't need them, because we don't have
+ any "deep create" calls. This will need to be
+ fixed. We don't need maps either. */
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+
+static xmlNode *
+add_container(xmlNode *parent, const char *name)
+{
+ return xmlNewChild(parent, NULL, BAD_CAST name, NULL);
+}
+
+
+static void
+add_param(xmlNode *params_node, const char *type, const char *value)
+{
+ xmlNode *param_node = add_container(params_node, "param");
+ add_value(param_node, type, value);
+}
+
+
+static void
+add_value(xmlNode *parent, const char *type, const char *value)
+{
+ xmlNode *value_node = add_container(parent, "value");
+ xmlNewChild(value_node, NULL, BAD_CAST type, BAD_CAST value);
+}
+
+
+static void
+add_unnamed_value(xmlNode *parent, const char *name, const char *type,
+ const char *value)
+{
+ (void)name;
+ add_value(parent, type, value);
+}
+
+
+static xmlNode *
+add_param_struct(xmlNode *params_node)
+{
+ xmlNode *param_node = add_container(params_node, "param");
+ xmlNode *value_node = add_container(param_node, "value");
+
+ return xmlNewChild(value_node, NULL, BAD_CAST "struct", NULL);
+}
+
+
+static void
+add_struct_member(xmlNode *struct_node, const char *name, const char *type,
+ const char *value)
+{
+ xmlNode *member_node = add_container(struct_node, "member");
+
+ xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
+
+ add_value(member_node, type, value);
+}
+
+
+static xmlNode *
+add_struct_array(xmlNode *struct_node, const char *name)
+{
+ xmlNode *member_node = add_container(struct_node, "member");
+
+ xmlNewChild(member_node, NULL, BAD_CAST "name", BAD_CAST name);
+
+ xmlNode *value_node = add_container(member_node, "value");
+ xmlNode *array_node = add_container(value_node, "array");
+
+ return add_container(array_node, "data");
+
+}
+
+
+int xen_enum_lookup_(xen_session *session, const char *str,
+ const char **lookup_table, int n)
+{
+ if (str != NULL)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ if (0 == strcmp(str, lookup_table[i]))
+ {
+ return i;
+ }
+ }
+ }
+
+ server_error_2(session, "Bad enum string", str);
+ return 0;
+}
+
+
+char *
+xen_strdup_(const char *in)
+{
+ char *result = malloc(strlen(in) + 1);
+ strcpy(result, in);
+ return result;
+}
+
+
+const abstract_type abstract_type_string = { .typename = STRING };
+const abstract_type abstract_type_int = { .typename = INT };
+const abstract_type abstract_type_float = { .typename = FLOAT };
+const abstract_type abstract_type_bool = { .typename = BOOL };
+const abstract_type abstract_type_datetime = { .typename = DATETIME };
+const abstract_type abstract_type_ref = { .typename = REF };
+
+const abstract_type abstract_type_string_set =
+ {
+ .typename = SET,
+ .child = &abstract_type_string
+ };
+
+const abstract_type abstract_type_ref_set =
+ {
+ .typename = SET,
+ .child = &abstract_type_ref
+ };
+
+static const struct struct_member string_string_members[] =
+{
+ {
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_string_string_map_contents, key)
+ },
+ {
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_string_string_map_contents, val)
+ }
+};
+const abstract_type abstract_type_string_string_map =
+ {
+ .typename = MAP,
+ .struct_size = sizeof(xen_string_string_map_contents),
+ .members = string_string_members
+ };
+
+static struct struct_member int_float_members[] =
+{
+ {
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_int_float_map_contents, key)
+ },
+ {
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_int_float_map_contents, val)
+ }
+};
+const abstract_type abstract_type_int_float_map =
+ {
+ .typename = MAP,
+ .struct_size = sizeof(xen_int_float_map_contents),
+ .members = int_float_members
+ };
diff --git a/tools/libxen/src/xen_cpu_feature.c b/tools/libxen/src/xen_cpu_feature.c
new file mode 100644
index 0000000000..98fb64f9e3
--- /dev/null
+++ b/tools/libxen/src/xen_cpu_feature.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_cpu_feature.h"
+#include "xen_cpu_feature_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "FPU",
+ "VME",
+ "DE",
+ "PSE",
+ "TSC",
+ "MSR",
+ "PAE",
+ "MCE",
+ "CX8",
+ "APIC",
+ "SEP",
+ "MTRR",
+ "PGE",
+ "MCA",
+ "CMOV",
+ "PAT",
+ "PSE36",
+ "PN",
+ "CLFLSH",
+ "DTES",
+ "ACPI",
+ "MMX",
+ "FXSR",
+ "XMM",
+ "XMM2",
+ "SELFSNOOP",
+ "HT",
+ "ACC",
+ "IA64",
+ "SYSCALL",
+ "MP",
+ "NX",
+ "MMXEXT",
+ "LM",
+ "3DNOWEXT",
+ "3DNOW",
+ "RECOVERY",
+ "LONGRUN",
+ "LRTI",
+ "CXMMX",
+ "K6_MTRR",
+ "CYRIX_ARR",
+ "CENTAUR_MCR",
+ "K8",
+ "K7",
+ "P3",
+ "P4",
+ "CONSTANT_TSC",
+ "FXSAVE_LEAK",
+ "XMM3",
+ "MWAIT",
+ "DSCPL",
+ "EST",
+ "TM2",
+ "CID",
+ "CX16",
+ "XTPR",
+ "XSTORE",
+ "XSTORE_EN",
+ "XCRYPT",
+ "XCRYPT_EN",
+ "LAHF_LM",
+ "CMP_LEGACY",
+ "VMX"
+};
+
+
+extern xen_cpu_feature_set *
+xen_cpu_feature_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_cpu_feature_set) +
+ size * sizeof(enum xen_cpu_feature));
+}
+
+
+extern void
+xen_cpu_feature_set_free(xen_cpu_feature_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_cpu_feature_to_string(enum xen_cpu_feature val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_cpu_feature
+xen_cpu_feature_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_cpu_feature_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_cpu_feature_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_cpu_feature_from_string
+ };
+
+
+const abstract_type xen_cpu_feature_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_cpu_feature_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_driver_type.c b/tools/libxen/src/xen_driver_type.c
new file mode 100644
index 0000000000..fe95d84f0c
--- /dev/null
+++ b/tools/libxen/src/xen_driver_type.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_driver_type.h"
+#include "xen_driver_type_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "ioemu",
+ "paravirtualised"
+};
+
+
+extern xen_driver_type_set *
+xen_driver_type_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_driver_type_set) +
+ size * sizeof(enum xen_driver_type));
+}
+
+
+extern void
+xen_driver_type_set_free(xen_driver_type_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_driver_type_to_string(enum xen_driver_type val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_driver_type
+xen_driver_type_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_driver_type_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_driver_type_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_driver_type_from_string
+ };
+
+
+const abstract_type xen_driver_type_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_driver_type_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_host.c b/tools/libxen/src/xen_host.c
new file mode 100644
index 0000000000..931a0c44ce
--- /dev/null
+++ b/tools/libxen/src/xen_host.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_host.h"
+#include "xen_host_cpu.h"
+#include "xen_internal.h"
+#include "xen_pif.h"
+#include "xen_string_string_map.h"
+#include "xen_vm.h"
+
+
+XEN_FREE(xen_host)
+XEN_SET_ALLOC_FREE(xen_host)
+XEN_ALLOC(xen_host_record)
+XEN_SET_ALLOC_FREE(xen_host_record)
+XEN_ALLOC(xen_host_record_opt)
+XEN_RECORD_OPT_FREE(xen_host)
+XEN_SET_ALLOC_FREE(xen_host_record_opt)
+
+
+static const struct_member xen_host_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_record, uuid) },
+ { .key = "name_label",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_record, name_label) },
+ { .key = "name_description",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_record, name_description) },
+ { .key = "software_version",
+ .type = &abstract_type_string_string_map,
+ .offset = offsetof(xen_host_record, software_version) },
+ { .key = "resident_VMs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_host_record, resident_vms) },
+ { .key = "PIFs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_host_record, pifs) },
+ { .key = "host_CPUs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_host_record, host_cpus) }
+ };
+
+const abstract_type xen_host_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_host_record),
+ .member_count =
+ sizeof(xen_host_record_struct_members) / sizeof(struct_member),
+ .members = xen_host_record_struct_members
+ };
+
+
+void
+xen_host_record_free(xen_host_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name_label);
+ free(record->name_description);
+ xen_string_string_map_free(record->software_version);
+ xen_vm_record_opt_set_free(record->resident_vms);
+ xen_pif_record_opt_set_free(record->pifs);
+ xen_host_cpu_record_opt_set_free(record->host_cpus);
+ free(record);
+}
+
+
+bool
+xen_host_get_record(xen_session *session, xen_host_record **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = xen_host_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("host.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_host_get_by_uuid(xen_session *session, xen_host *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_host_create(xen_session *session, xen_host *result, xen_host_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_host_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host.create");
+ return session->ok;
+}
+
+
+bool
+xen_host_destroy(xen_session *session, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "host.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_get_by_name_label(xen_session *session, struct xen_host_set **result, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("host.get_by_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_name_label(xen_session *session, char **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host.get_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_name_description(xen_session *session, char **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host.get_name_description");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_software_version(xen_session *session, xen_string_string_map **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string_string_map;
+
+ *result = NULL;
+ XEN_CALL_("host.get_software_version");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_resident_vms(xen_session *session, struct xen_vm_set **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("host.get_resident_VMs");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_pifs(xen_session *session, struct xen_pif_set **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("host.get_PIFs");
+ return session->ok;
+}
+
+
+bool
+xen_host_get_host_cpus(xen_session *session, struct xen_host_cpu_set **result, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("host.get_host_CPUs");
+ return session->ok;
+}
+
+
+bool
+xen_host_set_name_label(xen_session *session, xen_host host, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host },
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ xen_call_(session, "host.set_name_label", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_set_name_description(xen_session *session, xen_host host, char *description)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host },
+ { .type = &abstract_type_string,
+ .u.string_val = description }
+ };
+
+ xen_call_(session, "host.set_name_description", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_disable(xen_session *session, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "host.disable", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_enable(xen_session *session, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "host.enable", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_shutdown(xen_session *session, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "host.shutdown", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_reboot(xen_session *session, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "host.reboot", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_get_all(xen_session *session, struct xen_host_set **result)
+{
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ xen_call_(session, "host.get_all", NULL, 0, &result_type, result);
+ return session->ok;
+}
+
+
+bool
+xen_host_get_uuid(xen_session *session, char **result, xen_host host)
+{
+ *result = session->ok ? xen_strdup_((char *)host) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_host_cpu.c b/tools/libxen/src/xen_host_cpu.c
new file mode 100644
index 0000000000..ff73dcd9b9
--- /dev/null
+++ b/tools/libxen/src/xen_host_cpu.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_cpu_feature.h"
+#include "xen_cpu_feature_internal.h"
+#include "xen_host.h"
+#include "xen_host_cpu.h"
+#include "xen_internal.h"
+
+
+XEN_FREE(xen_host_cpu)
+XEN_SET_ALLOC_FREE(xen_host_cpu)
+XEN_ALLOC(xen_host_cpu_record)
+XEN_SET_ALLOC_FREE(xen_host_cpu_record)
+XEN_ALLOC(xen_host_cpu_record_opt)
+XEN_RECORD_OPT_FREE(xen_host_cpu)
+XEN_SET_ALLOC_FREE(xen_host_cpu_record_opt)
+
+
+static const struct_member xen_host_cpu_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_cpu_record, uuid) },
+ { .key = "host",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_host_cpu_record, host) },
+ { .key = "number",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_host_cpu_record, number) },
+ { .key = "vendor",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_cpu_record, vendor) },
+ { .key = "speed",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_host_cpu_record, speed) },
+ { .key = "modelname",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_host_cpu_record, modelname) },
+ { .key = "features",
+ .type = &xen_cpu_feature_set_abstract_type_,
+ .offset = offsetof(xen_host_cpu_record, features) },
+ { .key = "utilisation",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_host_cpu_record, utilisation) }
+ };
+
+const abstract_type xen_host_cpu_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_host_cpu_record),
+ .member_count =
+ sizeof(xen_host_cpu_record_struct_members) / sizeof(struct_member),
+ .members = xen_host_cpu_record_struct_members
+ };
+
+
+void
+xen_host_cpu_record_free(xen_host_cpu_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ xen_host_record_opt_free(record->host);
+ free(record->vendor);
+ free(record->modelname);
+ xen_cpu_feature_set_free(record->features);
+ free(record);
+}
+
+
+bool
+xen_host_cpu_get_record(xen_session *session, xen_host_cpu_record **result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = xen_host_cpu_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_by_uuid(xen_session *session, xen_host_cpu *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_create(xen_session *session, xen_host_cpu *result, xen_host_cpu_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_host_cpu_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.create");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_destroy(xen_session *session, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ xen_call_(session, "host_cpu.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_host(xen_session *session, xen_host *result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_host");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_number(xen_session *session, int64_t *result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("host_cpu.get_number");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_vendor(xen_session *session, char **result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_vendor");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_speed(xen_session *session, int64_t *result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("host_cpu.get_speed");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_modelname(xen_session *session, char **result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_modelname");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_features(xen_session *session, struct xen_cpu_feature_set **result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = xen_cpu_feature_set_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("host_cpu.get_features");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_utilisation(xen_session *session, double *result, xen_host_cpu host_cpu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = host_cpu }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("host_cpu.get_utilisation");
+ return session->ok;
+}
+
+
+bool
+xen_host_cpu_get_uuid(xen_session *session, char **result, xen_host_cpu host_cpu)
+{
+ *result = session->ok ? xen_strdup_((char *)host_cpu) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_int_float_map.c b/tools/libxen/src/xen_int_float_map.c
new file mode 100644
index 0000000000..edfcb21ac2
--- /dev/null
+++ b/tools/libxen/src/xen_int_float_map.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "xen_common.h"
+#include "xen_int_float_map.h"
+#include "xen_internal.h"
+
+
+xen_int_float_map *
+xen_int_float_map_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_int_float_map) +
+ size * sizeof(struct xen_int_float_map_contents));
+}
+
+
+void
+xen_int_float_map_free(xen_int_float_map *map)
+{
+ free(map);
+}
diff --git a/tools/libxen/src/xen_network.c b/tools/libxen/src/xen_network.c
new file mode 100644
index 0000000000..4c56e6e41d
--- /dev/null
+++ b/tools/libxen/src/xen_network.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_network.h"
+#include "xen_pif.h"
+#include "xen_vif.h"
+
+
+XEN_FREE(xen_network)
+XEN_SET_ALLOC_FREE(xen_network)
+XEN_ALLOC(xen_network_record)
+XEN_SET_ALLOC_FREE(xen_network_record)
+XEN_ALLOC(xen_network_record_opt)
+XEN_RECORD_OPT_FREE(xen_network)
+XEN_SET_ALLOC_FREE(xen_network_record_opt)
+
+
+static const struct_member xen_network_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_network_record, uuid) },
+ { .key = "name_label",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_network_record, name_label) },
+ { .key = "name_description",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_network_record, name_description) },
+ { .key = "VIFs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_network_record, vifs) },
+ { .key = "PIFs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_network_record, pifs) },
+ { .key = "default_gateway",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_network_record, default_gateway) },
+ { .key = "default_netmask",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_network_record, default_netmask) }
+ };
+
+const abstract_type xen_network_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_network_record),
+ .member_count =
+ sizeof(xen_network_record_struct_members) / sizeof(struct_member),
+ .members = xen_network_record_struct_members
+ };
+
+
+void
+xen_network_record_free(xen_network_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name_label);
+ free(record->name_description);
+ xen_vif_record_opt_set_free(record->vifs);
+ xen_pif_record_opt_set_free(record->pifs);
+ free(record->default_gateway);
+ free(record->default_netmask);
+ free(record);
+}
+
+
+bool
+xen_network_get_record(xen_session *session, xen_network_record **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = xen_network_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("network.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_network_get_by_uuid(xen_session *session, xen_network *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_network_create(xen_session *session, xen_network *result, xen_network_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_network_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.create");
+ return session->ok;
+}
+
+
+bool
+xen_network_destroy(xen_session *session, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ xen_call_(session, "network.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_network_get_by_name_label(xen_session *session, struct xen_network_set **result, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("network.get_by_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_name_label(xen_session *session, char **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.get_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_name_description(xen_session *session, char **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.get_name_description");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_vifs(xen_session *session, struct xen_vif_set **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("network.get_VIFs");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_pifs(xen_session *session, struct xen_pif_set **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("network.get_PIFs");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_default_gateway(xen_session *session, char **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.get_default_gateway");
+ return session->ok;
+}
+
+
+bool
+xen_network_get_default_netmask(xen_session *session, char **result, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("network.get_default_netmask");
+ return session->ok;
+}
+
+
+bool
+xen_network_set_name_label(xen_session *session, xen_network network, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network },
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ xen_call_(session, "network.set_name_label", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_network_set_name_description(xen_session *session, xen_network network, char *description)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network },
+ { .type = &abstract_type_string,
+ .u.string_val = description }
+ };
+
+ xen_call_(session, "network.set_name_description", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_network_set_default_gateway(xen_session *session, xen_network network, char *default_gateway)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network },
+ { .type = &abstract_type_string,
+ .u.string_val = default_gateway }
+ };
+
+ xen_call_(session, "network.set_default_gateway", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_network_set_default_netmask(xen_session *session, xen_network network, char *default_netmask)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = network },
+ { .type = &abstract_type_string,
+ .u.string_val = default_netmask }
+ };
+
+ xen_call_(session, "network.set_default_netmask", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_network_get_all(xen_session *session, struct xen_network_set **result)
+{
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ xen_call_(session, "network.get_all", NULL, 0, &result_type, result);
+ return session->ok;
+}
+
+
+bool
+xen_network_get_uuid(xen_session *session, char **result, xen_network network)
+{
+ *result = session->ok ? xen_strdup_((char *)network) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_on_crash_behaviour.c b/tools/libxen/src/xen_on_crash_behaviour.c
new file mode 100644
index 0000000000..cb1d0deca9
--- /dev/null
+++ b/tools/libxen/src/xen_on_crash_behaviour.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_on_crash_behaviour.h"
+#include "xen_on_crash_behaviour_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "destroy",
+ "coredump_and_destroy",
+ "restart",
+ "coredump_and_restart",
+ "preserve",
+ "rename_restart"
+};
+
+
+extern xen_on_crash_behaviour_set *
+xen_on_crash_behaviour_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_on_crash_behaviour_set) +
+ size * sizeof(enum xen_on_crash_behaviour));
+}
+
+
+extern void
+xen_on_crash_behaviour_set_free(xen_on_crash_behaviour_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_on_crash_behaviour_to_string(enum xen_on_crash_behaviour val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_on_crash_behaviour
+xen_on_crash_behaviour_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_on_crash_behaviour_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_on_crash_behaviour_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_on_crash_behaviour_from_string
+ };
+
+
+const abstract_type xen_on_crash_behaviour_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_on_crash_behaviour_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_on_normal_exit.c b/tools/libxen/src/xen_on_normal_exit.c
new file mode 100644
index 0000000000..3cfe09766b
--- /dev/null
+++ b/tools/libxen/src/xen_on_normal_exit.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_on_normal_exit.h"
+#include "xen_on_normal_exit_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "destroy",
+ "restart"
+};
+
+
+extern xen_on_normal_exit_set *
+xen_on_normal_exit_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_on_normal_exit_set) +
+ size * sizeof(enum xen_on_normal_exit));
+}
+
+
+extern void
+xen_on_normal_exit_set_free(xen_on_normal_exit_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_on_normal_exit_to_string(enum xen_on_normal_exit val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_on_normal_exit
+xen_on_normal_exit_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_on_normal_exit_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_on_normal_exit_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_on_normal_exit_from_string
+ };
+
+
+const abstract_type xen_on_normal_exit_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_on_normal_exit_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_pif.c b/tools/libxen/src/xen_pif.c
new file mode 100644
index 0000000000..b3edd91e6d
--- /dev/null
+++ b/tools/libxen/src/xen_pif.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_host.h"
+#include "xen_internal.h"
+#include "xen_network.h"
+#include "xen_pif.h"
+
+
+XEN_FREE(xen_pif)
+XEN_SET_ALLOC_FREE(xen_pif)
+XEN_ALLOC(xen_pif_record)
+XEN_SET_ALLOC_FREE(xen_pif_record)
+XEN_ALLOC(xen_pif_record_opt)
+XEN_RECORD_OPT_FREE(xen_pif)
+XEN_SET_ALLOC_FREE(xen_pif_record_opt)
+
+
+static const struct_member xen_pif_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_pif_record, uuid) },
+ { .key = "name",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_pif_record, name) },
+ { .key = "network",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_pif_record, network) },
+ { .key = "host",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_pif_record, host) },
+ { .key = "MAC",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_pif_record, mac) },
+ { .key = "MTU",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_pif_record, mtu) },
+ { .key = "VLAN",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_pif_record, vlan) },
+ { .key = "io_read_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_pif_record, io_read_kbs) },
+ { .key = "io_write_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_pif_record, io_write_kbs) }
+ };
+
+const abstract_type xen_pif_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_pif_record),
+ .member_count =
+ sizeof(xen_pif_record_struct_members) / sizeof(struct_member),
+ .members = xen_pif_record_struct_members
+ };
+
+
+void
+xen_pif_record_free(xen_pif_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name);
+ xen_network_record_opt_free(record->network);
+ xen_host_record_opt_free(record->host);
+ free(record->mac);
+ free(record->vlan);
+ free(record);
+}
+
+
+bool
+xen_pif_get_record(xen_session *session, xen_pif_record **result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = xen_pif_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_by_uuid(xen_session *session, xen_pif *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_pif_create(xen_session *session, xen_pif *result, xen_pif_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_pif_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.create");
+ return session->ok;
+}
+
+
+bool
+xen_pif_destroy(xen_session *session, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ xen_call_(session, "PIF.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_name(xen_session *session, char **result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_name");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_network(xen_session *session, xen_network *result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_network");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_host(xen_session *session, xen_host *result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_host");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_mac(xen_session *session, char **result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_MAC");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_mtu(xen_session *session, int64_t *result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("PIF.get_MTU");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_vlan(xen_session *session, char **result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("PIF.get_VLAN");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_io_read_kbs(xen_session *session, double *result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("PIF.get_io_read_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_io_write_kbs(xen_session *session, double *result, xen_pif pif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("PIF.get_io_write_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_name(xen_session *session, xen_pif pif, char *name)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_string,
+ .u.string_val = name }
+ };
+
+ xen_call_(session, "PIF.set_name", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_network(xen_session *session, xen_pif pif, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ xen_call_(session, "PIF.set_network", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_host(xen_session *session, xen_pif pif, xen_host host)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_string,
+ .u.string_val = host }
+ };
+
+ xen_call_(session, "PIF.set_host", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_mac(xen_session *session, xen_pif pif, char *mac)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_string,
+ .u.string_val = mac }
+ };
+
+ xen_call_(session, "PIF.set_MAC", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_mtu(xen_session *session, xen_pif pif, int64_t mtu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_int,
+ .u.int_val = mtu }
+ };
+
+ xen_call_(session, "PIF.set_MTU", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_set_vlan(xen_session *session, xen_pif pif, char *vlan)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = pif },
+ { .type = &abstract_type_string,
+ .u.string_val = vlan }
+ };
+
+ xen_call_(session, "PIF.set_VLAN", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_pif_get_uuid(xen_session *session, char **result, xen_pif pif)
+{
+ *result = session->ok ? xen_strdup_((char *)pif) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_sr.c b/tools/libxen/src/xen_sr.c
new file mode 100644
index 0000000000..3c4ffb16de
--- /dev/null
+++ b/tools/libxen/src/xen_sr.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_sr.h"
+#include "xen_vdi.h"
+
+
+XEN_FREE(xen_sr)
+XEN_SET_ALLOC_FREE(xen_sr)
+XEN_ALLOC(xen_sr_record)
+XEN_SET_ALLOC_FREE(xen_sr_record)
+XEN_ALLOC(xen_sr_record_opt)
+XEN_RECORD_OPT_FREE(xen_sr)
+XEN_SET_ALLOC_FREE(xen_sr_record_opt)
+
+
+static const struct_member xen_sr_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_sr_record, uuid) },
+ { .key = "name_label",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_sr_record, name_label) },
+ { .key = "name_description",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_sr_record, name_description) },
+ { .key = "VDIs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_sr_record, vdis) },
+ { .key = "virtual_allocation",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_sr_record, virtual_allocation) },
+ { .key = "physical_utilisation",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_sr_record, physical_utilisation) },
+ { .key = "physical_size",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_sr_record, physical_size) },
+ { .key = "type",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_sr_record, type) },
+ { .key = "location",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_sr_record, location) }
+ };
+
+const abstract_type xen_sr_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_sr_record),
+ .member_count =
+ sizeof(xen_sr_record_struct_members) / sizeof(struct_member),
+ .members = xen_sr_record_struct_members
+ };
+
+
+void
+xen_sr_record_free(xen_sr_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name_label);
+ free(record->name_description);
+ xen_vdi_record_opt_set_free(record->vdis);
+ free(record->type);
+ free(record->location);
+ free(record);
+}
+
+
+bool
+xen_sr_get_record(xen_session *session, xen_sr_record **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = xen_sr_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_by_uuid(xen_session *session, xen_sr *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_sr_create(xen_session *session, xen_sr *result, xen_sr_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_sr_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.create");
+ return session->ok;
+}
+
+
+bool
+xen_sr_destroy(xen_session *session, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ xen_call_(session, "SR.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_by_name_label(xen_session *session, struct xen_sr_set **result, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_by_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_name_label(xen_session *session, char **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_name_description(xen_session *session, char **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_name_description");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_vdis(xen_session *session, struct xen_vdi_set **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_VDIs");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_virtual_allocation(xen_session *session, int64_t *result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("SR.get_virtual_allocation");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_physical_utilisation(xen_session *session, int64_t *result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("SR.get_physical_utilisation");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_physical_size(xen_session *session, int64_t *result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("SR.get_physical_size");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_type(xen_session *session, char **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_type");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_location(xen_session *session, char **result, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.get_location");
+ return session->ok;
+}
+
+
+bool
+xen_sr_set_name_label(xen_session *session, xen_sr sr, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr },
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ xen_call_(session, "SR.set_name_label", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_sr_set_name_description(xen_session *session, xen_sr sr, char *description)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr },
+ { .type = &abstract_type_string,
+ .u.string_val = description }
+ };
+
+ xen_call_(session, "SR.set_name_description", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_sr_clone(xen_session *session, xen_sr *result, xen_sr sr, char *loc, char *name)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = sr },
+ { .type = &abstract_type_string,
+ .u.string_val = loc },
+ { .type = &abstract_type_string,
+ .u.string_val = name }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("SR.clone");
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_all(xen_session *session, struct xen_sr_set **result)
+{
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ xen_call_(session, "SR.get_all", NULL, 0, &result_type, result);
+ return session->ok;
+}
+
+
+bool
+xen_sr_get_uuid(xen_session *session, char **result, xen_sr sr)
+{
+ *result = session->ok ? xen_strdup_((char *)sr) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_string_string_map.c b/tools/libxen/src/xen_string_string_map.c
new file mode 100644
index 0000000000..34f5ec4d70
--- /dev/null
+++ b/tools/libxen/src/xen_string_string_map.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_string_string_map.h"
+
+
+xen_string_string_map *
+xen_string_string_map_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_string_string_map) +
+ size * sizeof(struct xen_string_string_map_contents));
+}
+
+
+void
+xen_string_string_map_free(xen_string_string_map *map)
+{
+ if (map == NULL)
+ {
+ return;
+ }
+
+ size_t n = map->size;
+ for (size_t i = 0; i < n; i++)
+ {
+ free(map->contents[i].key);
+ free(map->contents[i].val);
+ }
+
+ free(map);
+}
diff --git a/tools/libxen/src/xen_user.c b/tools/libxen/src/xen_user.c
new file mode 100644
index 0000000000..35b80e2f66
--- /dev/null
+++ b/tools/libxen/src/xen_user.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_user.h"
+
+
+XEN_FREE(xen_user)
+XEN_SET_ALLOC_FREE(xen_user)
+XEN_ALLOC(xen_user_record)
+XEN_SET_ALLOC_FREE(xen_user_record)
+XEN_ALLOC(xen_user_record_opt)
+XEN_RECORD_OPT_FREE(xen_user)
+XEN_SET_ALLOC_FREE(xen_user_record_opt)
+
+
+static const struct_member xen_user_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_user_record, uuid) },
+ { .key = "short_name",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_user_record, short_name) },
+ { .key = "fullname",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_user_record, fullname) }
+ };
+
+const abstract_type xen_user_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_user_record),
+ .member_count =
+ sizeof(xen_user_record_struct_members) / sizeof(struct_member),
+ .members = xen_user_record_struct_members
+ };
+
+
+void
+xen_user_record_free(xen_user_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->short_name);
+ free(record->fullname);
+ free(record);
+}
+
+
+bool
+xen_user_get_record(xen_session *session, xen_user_record **result, xen_user user)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = user }
+ };
+
+ abstract_type result_type = xen_user_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("user.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_user_get_by_uuid(xen_session *session, xen_user *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("user.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_user_create(xen_session *session, xen_user *result, xen_user_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_user_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("user.create");
+ return session->ok;
+}
+
+
+bool
+xen_user_destroy(xen_session *session, xen_user user)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = user }
+ };
+
+ xen_call_(session, "user.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_user_get_short_name(xen_session *session, char **result, xen_user user)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = user }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("user.get_short_name");
+ return session->ok;
+}
+
+
+bool
+xen_user_get_fullname(xen_session *session, char **result, xen_user user)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = user }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("user.get_fullname");
+ return session->ok;
+}
+
+
+bool
+xen_user_set_fullname(xen_session *session, xen_user user, char *fullname)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = user },
+ { .type = &abstract_type_string,
+ .u.string_val = fullname }
+ };
+
+ xen_call_(session, "user.set_fullname", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_user_get_uuid(xen_session *session, char **result, xen_user user)
+{
+ *result = session->ok ? xen_strdup_((char *)user) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_vbd.c b/tools/libxen/src/xen_vbd.c
new file mode 100644
index 0000000000..c49ecf236a
--- /dev/null
+++ b/tools/libxen/src/xen_vbd.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_driver_type_internal.h"
+#include "xen_internal.h"
+#include "xen_vbd.h"
+#include "xen_vbd_mode_internal.h"
+#include "xen_vdi.h"
+#include "xen_vm.h"
+
+
+XEN_FREE(xen_vbd)
+XEN_SET_ALLOC_FREE(xen_vbd)
+XEN_ALLOC(xen_vbd_record)
+XEN_SET_ALLOC_FREE(xen_vbd_record)
+XEN_ALLOC(xen_vbd_record_opt)
+XEN_RECORD_OPT_FREE(xen_vbd)
+XEN_SET_ALLOC_FREE(xen_vbd_record_opt)
+
+
+static const struct_member xen_vbd_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vbd_record, uuid) },
+ { .key = "VM",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vbd_record, vm) },
+ { .key = "VDI",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vbd_record, vdi) },
+ { .key = "device",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vbd_record, device) },
+ { .key = "image",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vbd_record, image) },
+ { .key = "mode",
+ .type = &xen_vbd_mode_abstract_type_,
+ .offset = offsetof(xen_vbd_record, mode) },
+ { .key = "driver",
+ .type = &xen_driver_type_abstract_type_,
+ .offset = offsetof(xen_vbd_record, driver) },
+ { .key = "io_read_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_vbd_record, io_read_kbs) },
+ { .key = "io_write_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_vbd_record, io_write_kbs) }
+ };
+
+const abstract_type xen_vbd_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_vbd_record),
+ .member_count =
+ sizeof(xen_vbd_record_struct_members) / sizeof(struct_member),
+ .members = xen_vbd_record_struct_members
+ };
+
+
+void
+xen_vbd_record_free(xen_vbd_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ xen_vm_record_opt_free(record->vm);
+ xen_vdi_record_opt_free(record->vdi);
+ free(record->device);
+ free(record);
+}
+
+
+bool
+xen_vbd_get_record(xen_session *session, xen_vbd_record **result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = xen_vbd_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VBD.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_by_uuid(xen_session *session, xen_vbd *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VBD.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_create(xen_session *session, xen_vbd *result, xen_vbd_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_vbd_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VBD.create");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_destroy(xen_session *session, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ xen_call_(session, "VBD.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_vm(xen_session *session, xen_vm *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VBD.get_VM");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_vdi(xen_session *session, xen_vdi *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VBD.get_VDI");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_device(xen_session *session, char **result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VBD.get_device");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_mode(xen_session *session, enum xen_vbd_mode *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = xen_vbd_mode_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VBD.get_mode");
+ *result = xen_vbd_mode_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_driver(xen_session *session, enum xen_driver_type *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = xen_driver_type_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VBD.get_driver");
+ *result = xen_driver_type_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_io_read_kbs(xen_session *session, double *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("VBD.get_io_read_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_io_write_kbs(xen_session *session, double *result, xen_vbd vbd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("VBD.get_io_write_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_vbd_set_vm(xen_session *session, xen_vbd vbd, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VBD.set_VM", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_set_vdi(xen_session *session, xen_vbd vbd, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ xen_call_(session, "VBD.set_VDI", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_set_device(xen_session *session, xen_vbd vbd, char *device)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &abstract_type_string,
+ .u.string_val = device }
+ };
+
+ xen_call_(session, "VBD.set_device", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_set_mode(xen_session *session, xen_vbd vbd, enum xen_vbd_mode mode)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &xen_vbd_mode_abstract_type_,
+ .u.string_val = xen_vbd_mode_to_string(mode) }
+ };
+
+ xen_call_(session, "VBD.set_mode", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_set_driver(xen_session *session, xen_vbd vbd, enum xen_driver_type driver)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &xen_driver_type_abstract_type_,
+ .u.string_val = xen_driver_type_to_string(driver) }
+ };
+
+ xen_call_(session, "VBD.set_driver", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vbd },
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ xen_call_(session, "VBD.media_change", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_get_uuid(xen_session *session, char **result, xen_vbd vbd)
+{
+ *result = session->ok ? xen_strdup_((char *)vbd) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_vbd_mode.c b/tools/libxen/src/xen_vbd_mode.c
new file mode 100644
index 0000000000..e9fa71140a
--- /dev/null
+++ b/tools/libxen/src/xen_vbd_mode.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_vbd_mode.h"
+#include "xen_vbd_mode_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "RO",
+ "RW"
+};
+
+
+extern xen_vbd_mode_set *
+xen_vbd_mode_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_vbd_mode_set) +
+ size * sizeof(enum xen_vbd_mode));
+}
+
+
+extern void
+xen_vbd_mode_set_free(xen_vbd_mode_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_vbd_mode_to_string(enum xen_vbd_mode val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_vbd_mode
+xen_vbd_mode_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_vbd_mode_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_vbd_mode_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_vbd_mode_from_string
+ };
+
+
+const abstract_type xen_vbd_mode_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_vbd_mode_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_vdi.c b/tools/libxen/src/xen_vdi.c
new file mode 100644
index 0000000000..a8d157d232
--- /dev/null
+++ b/tools/libxen/src/xen_vdi.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_internal.h"
+#include "xen_sr.h"
+#include "xen_vbd.h"
+#include "xen_vdi.h"
+#include "xen_vdi_type_internal.h"
+
+
+XEN_FREE(xen_vdi)
+XEN_SET_ALLOC_FREE(xen_vdi)
+XEN_ALLOC(xen_vdi_record)
+XEN_SET_ALLOC_FREE(xen_vdi_record)
+XEN_ALLOC(xen_vdi_record_opt)
+XEN_RECORD_OPT_FREE(xen_vdi)
+XEN_SET_ALLOC_FREE(xen_vdi_record_opt)
+
+
+static const struct_member xen_vdi_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vdi_record, uuid) },
+ { .key = "name_label",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vdi_record, name_label) },
+ { .key = "name_description",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vdi_record, name_description) },
+ { .key = "SR",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vdi_record, sr) },
+ { .key = "VBDs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_vdi_record, vbds) },
+ { .key = "virtual_size",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vdi_record, virtual_size) },
+ { .key = "physical_utilisation",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vdi_record, physical_utilisation) },
+ { .key = "sector_size",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vdi_record, sector_size) },
+ { .key = "type",
+ .type = &xen_vdi_type_abstract_type_,
+ .offset = offsetof(xen_vdi_record, type) },
+ { .key = "parent",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vdi_record, parent) },
+ { .key = "children",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_vdi_record, children) },
+ { .key = "sharable",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vdi_record, sharable) },
+ { .key = "read_only",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vdi_record, read_only) }
+ };
+
+const abstract_type xen_vdi_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_vdi_record),
+ .member_count =
+ sizeof(xen_vdi_record_struct_members) / sizeof(struct_member),
+ .members = xen_vdi_record_struct_members
+ };
+
+
+void
+xen_vdi_record_free(xen_vdi_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name_label);
+ free(record->name_description);
+ xen_sr_record_opt_free(record->sr);
+ xen_vbd_record_opt_set_free(record->vbds);
+ xen_vdi_record_opt_free(record->parent);
+ xen_vdi_record_opt_set_free(record->children);
+ free(record);
+}
+
+
+bool
+xen_vdi_get_record(xen_session *session, xen_vdi_record **result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = xen_vdi_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_by_uuid(xen_session *session, xen_vdi *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_create(xen_session *session, xen_vdi *result, xen_vdi_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_vdi_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.create");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_destroy(xen_session *session, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ xen_call_(session, "VDI.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_by_name_label(xen_session *session, struct xen_vdi_set **result, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_by_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_name_label(xen_session *session, char **result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_name_description(xen_session *session, char **result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_name_description");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_sr(xen_session *session, xen_sr *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_SR");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_vbds(xen_session *session, struct xen_vbd_set **result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_VBDs");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_virtual_size(xen_session *session, int64_t *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VDI.get_virtual_size");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VDI.get_physical_utilisation");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VDI.get_sector_size");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_type(xen_session *session, enum xen_vdi_type *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = xen_vdi_type_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VDI.get_type");
+ *result = xen_vdi_type_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_parent(xen_session *session, xen_vdi *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_parent");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_children(xen_session *session, struct xen_vdi_set **result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_children");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_sharable(xen_session *session, bool *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VDI.get_sharable");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VDI.get_read_only");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ xen_call_(session, "VDI.set_name_label", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string,
+ .u.string_val = description }
+ };
+
+ xen_call_(session, "VDI.set_name_description", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string,
+ .u.string_val = sr }
+ };
+
+ xen_call_(session, "VDI.set_SR", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_virtual_size(xen_session *session, xen_vdi vdi, int64_t virtual_size)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_int,
+ .u.int_val = virtual_size }
+ };
+
+ xen_call_(session, "VDI.set_virtual_size", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_sharable(xen_session *session, xen_vdi vdi, bool sharable)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_bool,
+ .u.bool_val = sharable }
+ };
+
+ xen_call_(session, "VDI.set_sharable", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_bool,
+ .u.bool_val = read_only }
+ };
+
+ xen_call_(session, "VDI.set_read_only", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_snapshot(xen_session *session, xen_vdi *result, xen_vdi vdi)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VDI.snapshot");
+ return session->ok;
+}
+
+
+bool
+xen_vdi_resize(xen_session *session, xen_vdi vdi, int64_t size)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_int,
+ .u.int_val = size }
+ };
+
+ xen_call_(session, "VDI.resize", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_get_uuid(xen_session *session, char **result, xen_vdi vdi)
+{
+ *result = session->ok ? xen_strdup_((char *)vdi) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_vdi_type.c b/tools/libxen/src/xen_vdi_type.c
new file mode 100644
index 0000000000..90cfe8c820
--- /dev/null
+++ b/tools/libxen/src/xen_vdi_type.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_vdi_type.h"
+#include "xen_vdi_type_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "system",
+ "user",
+ "ephemeral"
+};
+
+
+extern xen_vdi_type_set *
+xen_vdi_type_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_vdi_type_set) +
+ size * sizeof(enum xen_vdi_type));
+}
+
+
+extern void
+xen_vdi_type_set_free(xen_vdi_type_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_vdi_type_to_string(enum xen_vdi_type val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_vdi_type
+xen_vdi_type_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_vdi_type_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_vdi_type_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_vdi_type_from_string
+ };
+
+
+const abstract_type xen_vdi_type_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_vdi_type_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_vif.c b/tools/libxen/src/xen_vif.c
new file mode 100644
index 0000000000..ce28626150
--- /dev/null
+++ b/tools/libxen/src/xen_vif.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_driver_type_internal.h"
+#include "xen_internal.h"
+#include "xen_network.h"
+#include "xen_vif.h"
+#include "xen_vm.h"
+
+
+XEN_FREE(xen_vif)
+XEN_SET_ALLOC_FREE(xen_vif)
+XEN_ALLOC(xen_vif_record)
+XEN_SET_ALLOC_FREE(xen_vif_record)
+XEN_ALLOC(xen_vif_record_opt)
+XEN_RECORD_OPT_FREE(xen_vif)
+XEN_SET_ALLOC_FREE(xen_vif_record_opt)
+
+
+static const struct_member xen_vif_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vif_record, uuid) },
+ { .key = "name",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vif_record, name) },
+ { .key = "type",
+ .type = &xen_driver_type_abstract_type_,
+ .offset = offsetof(xen_vif_record, type) },
+ { .key = "device",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vif_record, device) },
+ { .key = "network",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vif_record, network) },
+ { .key = "VM",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vif_record, vm) },
+ { .key = "MAC",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vif_record, mac) },
+ { .key = "MTU",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vif_record, mtu) },
+ { .key = "io_read_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_vif_record, io_read_kbs) },
+ { .key = "io_write_kbs",
+ .type = &abstract_type_float,
+ .offset = offsetof(xen_vif_record, io_write_kbs) }
+ };
+
+const abstract_type xen_vif_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_vif_record),
+ .member_count =
+ sizeof(xen_vif_record_struct_members) / sizeof(struct_member),
+ .members = xen_vif_record_struct_members
+ };
+
+
+void
+xen_vif_record_free(xen_vif_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name);
+ free(record->device);
+ xen_network_record_opt_free(record->network);
+ xen_vm_record_opt_free(record->vm);
+ free(record->mac);
+ free(record);
+}
+
+
+bool
+xen_vif_get_record(xen_session *session, xen_vif_record **result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = xen_vif_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_by_uuid(xen_session *session, xen_vif *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_vif_create(xen_session *session, xen_vif *result, xen_vif_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_vif_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.create");
+ return session->ok;
+}
+
+
+bool
+xen_vif_destroy(xen_session *session, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ xen_call_(session, "VIF.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_name(xen_session *session, char **result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_name");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_type(xen_session *session, enum xen_driver_type *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = xen_driver_type_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VIF.get_type");
+ *result = xen_driver_type_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_device(xen_session *session, char **result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_device");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_network(xen_session *session, xen_network *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_network");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_vm(xen_session *session, xen_vm *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_VM");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_mac(xen_session *session, char **result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VIF.get_MAC");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_mtu(xen_session *session, int64_t *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VIF.get_MTU");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_io_read_kbs(xen_session *session, double *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("VIF.get_io_read_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_io_write_kbs(xen_session *session, double *result, xen_vif vif)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif }
+ };
+
+ abstract_type result_type = abstract_type_float;
+
+ XEN_CALL_("VIF.get_io_write_kbs");
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_name(xen_session *session, xen_vif vif, char *name)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_string,
+ .u.string_val = name }
+ };
+
+ xen_call_(session, "VIF.set_name", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_type(xen_session *session, xen_vif vif, enum xen_driver_type type)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &xen_driver_type_abstract_type_,
+ .u.string_val = xen_driver_type_to_string(type) }
+ };
+
+ xen_call_(session, "VIF.set_type", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_device(xen_session *session, xen_vif vif, char *device)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_string,
+ .u.string_val = device }
+ };
+
+ xen_call_(session, "VIF.set_device", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_network(xen_session *session, xen_vif vif, xen_network network)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_string,
+ .u.string_val = network }
+ };
+
+ xen_call_(session, "VIF.set_network", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_vm(xen_session *session, xen_vif vif, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VIF.set_VM", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_mac(xen_session *session, xen_vif vif, char *mac)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_string,
+ .u.string_val = mac }
+ };
+
+ xen_call_(session, "VIF.set_MAC", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_set_mtu(xen_session *session, xen_vif vif, int64_t mtu)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vif },
+ { .type = &abstract_type_int,
+ .u.int_val = mtu }
+ };
+
+ xen_call_(session, "VIF.set_MTU", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_get_uuid(xen_session *session, char **result, xen_vif vif)
+{
+ *result = session->ok ? xen_strdup_((char *)vif) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c
new file mode 100644
index 0000000000..cd0271c71c
--- /dev/null
+++ b/tools/libxen/src/xen_vm.c
@@ -0,0 +1,1596 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_boot_type_internal.h"
+#include "xen_common.h"
+#include "xen_cpu_feature.h"
+#include "xen_cpu_feature_internal.h"
+#include "xen_host.h"
+#include "xen_int_float_map.h"
+#include "xen_internal.h"
+#include "xen_on_crash_behaviour_internal.h"
+#include "xen_on_normal_exit_internal.h"
+#include "xen_string_string_map.h"
+#include "xen_vbd.h"
+#include "xen_vif.h"
+#include "xen_vm.h"
+#include "xen_vm_power_state_internal.h"
+#include "xen_vtpm.h"
+
+
+XEN_FREE(xen_vm)
+XEN_SET_ALLOC_FREE(xen_vm)
+XEN_ALLOC(xen_vm_record)
+XEN_SET_ALLOC_FREE(xen_vm_record)
+XEN_ALLOC(xen_vm_record_opt)
+XEN_RECORD_OPT_FREE(xen_vm)
+XEN_SET_ALLOC_FREE(xen_vm_record_opt)
+
+
+static const struct_member xen_vm_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, uuid) },
+ { .key = "power_state",
+ .type = &xen_vm_power_state_abstract_type_,
+ .offset = offsetof(xen_vm_record, power_state) },
+ { .key = "name_label",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, name_label) },
+ { .key = "name_description",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, name_description) },
+ { .key = "user_version",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, user_version) },
+ { .key = "is_a_template",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vm_record, is_a_template) },
+ { .key = "resident_on",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vm_record, resident_on) },
+ { .key = "memory_static_max",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, memory_static_max) },
+ { .key = "memory_dynamic_max",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, memory_dynamic_max) },
+ { .key = "memory_actual",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, memory_actual) },
+ { .key = "memory_dynamic_min",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, memory_dynamic_min) },
+ { .key = "memory_static_min",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, memory_static_min) },
+ { .key = "vcpus_policy",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, vcpus_policy) },
+ { .key = "vcpus_params",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, vcpus_params) },
+ { .key = "vcpus_number",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vm_record, vcpus_number) },
+ { .key = "vcpus_utilisation",
+ .type = &abstract_type_int_float_map,
+ .offset = offsetof(xen_vm_record, vcpus_utilisation) },
+ { .key = "vcpus_features_required",
+ .type = &xen_cpu_feature_set_abstract_type_,
+ .offset = offsetof(xen_vm_record, vcpus_features_required) },
+ { .key = "vcpus_features_can_use",
+ .type = &xen_cpu_feature_set_abstract_type_,
+ .offset = offsetof(xen_vm_record, vcpus_features_can_use) },
+ { .key = "vcpus_features_force_on",
+ .type = &xen_cpu_feature_set_abstract_type_,
+ .offset = offsetof(xen_vm_record, vcpus_features_force_on) },
+ { .key = "vcpus_features_force_off",
+ .type = &xen_cpu_feature_set_abstract_type_,
+ .offset = offsetof(xen_vm_record, vcpus_features_force_off) },
+ { .key = "actions_after_shutdown",
+ .type = &xen_on_normal_exit_abstract_type_,
+ .offset = offsetof(xen_vm_record, actions_after_shutdown) },
+ { .key = "actions_after_reboot",
+ .type = &xen_on_normal_exit_abstract_type_,
+ .offset = offsetof(xen_vm_record, actions_after_reboot) },
+ { .key = "actions_after_suspend",
+ .type = &xen_on_normal_exit_abstract_type_,
+ .offset = offsetof(xen_vm_record, actions_after_suspend) },
+ { .key = "actions_after_crash",
+ .type = &xen_on_crash_behaviour_abstract_type_,
+ .offset = offsetof(xen_vm_record, actions_after_crash) },
+ { .key = "VIFs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_vm_record, vifs) },
+ { .key = "VBDs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_vm_record, vbds) },
+ { .key = "VTPMs",
+ .type = &abstract_type_ref_set,
+ .offset = offsetof(xen_vm_record, vtpms) },
+ { .key = "bios_boot",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, bios_boot) },
+ { .key = "platform_std_VGA",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vm_record, platform_std_vga) },
+ { .key = "platform_serial",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, platform_serial) },
+ { .key = "platform_localtime",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vm_record, platform_localtime) },
+ { .key = "platform_clock_offset",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vm_record, platform_clock_offset) },
+ { .key = "platform_enable_audio",
+ .type = &abstract_type_bool,
+ .offset = offsetof(xen_vm_record, platform_enable_audio) },
+ { .key = "builder",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, builder) },
+ { .key = "boot_method",
+ .type = &xen_boot_type_abstract_type_,
+ .offset = offsetof(xen_vm_record, boot_method) },
+ { .key = "kernel_kernel",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, kernel_kernel) },
+ { .key = "kernel_initrd",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, kernel_initrd) },
+ { .key = "kernel_args",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, kernel_args) },
+ { .key = "grub_cmdline",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, grub_cmdline) },
+ { .key = "PCI_bus",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vm_record, pci_bus) },
+ { .key = "tools_version",
+ .type = &abstract_type_string_string_map,
+ .offset = offsetof(xen_vm_record, tools_version) },
+ { .key = "otherConfig",
+ .type = &abstract_type_string_string_map,
+ .offset = offsetof(xen_vm_record, otherconfig) }
+ };
+
+const abstract_type xen_vm_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_vm_record),
+ .member_count =
+ sizeof(xen_vm_record_struct_members) / sizeof(struct_member),
+ .members = xen_vm_record_struct_members
+ };
+
+
+void
+xen_vm_record_free(xen_vm_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ free(record->name_label);
+ free(record->name_description);
+ xen_host_record_opt_free(record->resident_on);
+ free(record->vcpus_policy);
+ free(record->vcpus_params);
+ xen_int_float_map_free(record->vcpus_utilisation);
+ xen_cpu_feature_set_free(record->vcpus_features_required);
+ xen_cpu_feature_set_free(record->vcpus_features_can_use);
+ xen_cpu_feature_set_free(record->vcpus_features_force_on);
+ xen_cpu_feature_set_free(record->vcpus_features_force_off);
+ xen_vif_record_opt_set_free(record->vifs);
+ xen_vbd_record_opt_set_free(record->vbds);
+ xen_vtpm_record_opt_set_free(record->vtpms);
+ free(record->bios_boot);
+ free(record->platform_serial);
+ free(record->builder);
+ free(record->kernel_kernel);
+ free(record->kernel_initrd);
+ free(record->kernel_args);
+ free(record->grub_cmdline);
+ free(record->pci_bus);
+ xen_string_string_map_free(record->tools_version);
+ xen_string_string_map_free(record->otherconfig);
+ free(record);
+}
+
+
+bool
+xen_vm_get_record(xen_session *session, xen_vm_record **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_vm_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_by_uuid(xen_session *session, xen_vm *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_vm_create(xen_session *session, xen_vm *result, xen_vm_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_vm_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.create");
+ return session->ok;
+}
+
+
+bool
+xen_vm_destroy(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_by_name_label(xen_session *session, struct xen_vm_set **result, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_by_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_power_state(xen_session *session, enum xen_vm_power_state *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_vm_power_state_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_power_state");
+ *result = xen_vm_power_state_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_name_label(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_name_label");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_name_description(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_name_description");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_user_version(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_user_version");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_is_a_template(xen_session *session, bool *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VM.get_is_a_template");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_resident_on(xen_session *session, xen_host *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_resident_on");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_memory_static_max(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_memory_static_max");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_memory_dynamic_max(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_memory_dynamic_max");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_memory_actual(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_memory_actual");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_memory_dynamic_min(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_memory_dynamic_min");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_memory_static_min");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_policy");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_params(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_params");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_number(xen_session *session, int64_t *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VM.get_VCPUs_number");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_utilisation(xen_session *session, xen_int_float_map **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_int_float_map;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_utilisation");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_features_required(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_cpu_feature_set_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_features_required");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_features_can_use(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_cpu_feature_set_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_features_can_use");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_features_force_on(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_cpu_feature_set_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_features_force_on");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vcpus_features_force_off(xen_session *session, struct xen_cpu_feature_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_cpu_feature_set_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VCPUs_features_force_off");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_actions_after_shutdown(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_on_normal_exit_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_actions_after_shutdown");
+ *result = xen_on_normal_exit_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_actions_after_reboot(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_on_normal_exit_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_actions_after_reboot");
+ *result = xen_on_normal_exit_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_actions_after_suspend(xen_session *session, enum xen_on_normal_exit *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_on_normal_exit_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_actions_after_suspend");
+ *result = xen_on_normal_exit_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_actions_after_crash(xen_session *session, enum xen_on_crash_behaviour *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_on_crash_behaviour_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_actions_after_crash");
+ *result = xen_on_crash_behaviour_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vifs(xen_session *session, struct xen_vif_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VIFs");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vbds(xen_session *session, struct xen_vbd_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VBDs");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_vtpms(xen_session *session, struct xen_vtpm_set **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_VTPMs");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_bios_boot(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_bios_boot");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VM.get_platform_std_VGA");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_platform_serial");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VM.get_platform_localtime");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VM.get_platform_clock_offset");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_bool;
+
+ XEN_CALL_("VM.get_platform_enable_audio");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_builder(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_builder");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_boot_method(xen_session *session, enum xen_boot_type *result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = xen_boot_type_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VM.get_boot_method");
+ *result = xen_boot_type_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_kernel_kernel(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_kernel_kernel");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_kernel_initrd(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_kernel_initrd");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_kernel_args(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_kernel_args");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_grub_cmdline(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_grub_cmdline");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_pci_bus(xen_session *session, char **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_PCI_bus");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_tools_version(xen_session *session, xen_string_string_map **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string_string_map;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_tools_version");
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_otherconfig(xen_session *session, xen_string_string_map **result, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ abstract_type result_type = abstract_type_string_string_map;
+
+ *result = NULL;
+ XEN_CALL_("VM.get_otherConfig");
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_name_label(xen_session *session, xen_vm vm, char *label)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = label }
+ };
+
+ xen_call_(session, "VM.set_name_label", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_name_description(xen_session *session, xen_vm vm, char *description)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = description }
+ };
+
+ xen_call_(session, "VM.set_name_description", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_user_version(xen_session *session, xen_vm vm, int64_t user_version)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_int,
+ .u.int_val = user_version }
+ };
+
+ xen_call_(session, "VM.set_user_version", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_is_a_template(xen_session *session, xen_vm vm, bool is_a_template)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = is_a_template }
+ };
+
+ xen_call_(session, "VM.set_is_a_template", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_memory_dynamic_max(xen_session *session, xen_vm vm, int64_t dynamic_max)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_int,
+ .u.int_val = dynamic_max }
+ };
+
+ xen_call_(session, "VM.set_memory_dynamic_max", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_memory_dynamic_min(xen_session *session, xen_vm vm, int64_t dynamic_min)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_int,
+ .u.int_val = dynamic_min }
+ };
+
+ xen_call_(session, "VM.set_memory_dynamic_min", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = policy }
+ };
+
+ xen_call_(session, "VM.set_vcpus_policy", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, char *params)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = params }
+ };
+
+ xen_call_(session, "VM.set_vcpus_params", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_vcpus_features_force_on(xen_session *session, xen_vm vm, struct xen_cpu_feature_set *force_on)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_cpu_feature_set_abstract_type_,
+ .u.set_val = (arbitrary_set *)force_on }
+ };
+
+ xen_call_(session, "VM.set_vcpus_features_force_on", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_vcpus_features_force_off(xen_session *session, xen_vm vm, struct xen_cpu_feature_set *force_off)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_cpu_feature_set_abstract_type_,
+ .u.set_val = (arbitrary_set *)force_off }
+ };
+
+ xen_call_(session, "VM.set_vcpus_features_force_off", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_actions_after_shutdown(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_shutdown)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_on_normal_exit_abstract_type_,
+ .u.string_val = xen_on_normal_exit_to_string(after_shutdown) }
+ };
+
+ xen_call_(session, "VM.set_actions_after_shutdown", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_actions_after_reboot(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_reboot)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_on_normal_exit_abstract_type_,
+ .u.string_val = xen_on_normal_exit_to_string(after_reboot) }
+ };
+
+ xen_call_(session, "VM.set_actions_after_reboot", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_actions_after_suspend(xen_session *session, xen_vm vm, enum xen_on_normal_exit after_suspend)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_on_normal_exit_abstract_type_,
+ .u.string_val = xen_on_normal_exit_to_string(after_suspend) }
+ };
+
+ xen_call_(session, "VM.set_actions_after_suspend", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_actions_after_crash(xen_session *session, xen_vm vm, enum xen_on_crash_behaviour after_crash)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_on_crash_behaviour_abstract_type_,
+ .u.string_val = xen_on_crash_behaviour_to_string(after_crash) }
+ };
+
+ xen_call_(session, "VM.set_actions_after_crash", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_bios_boot(xen_session *session, xen_vm vm, char *boot)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = boot }
+ };
+
+ xen_call_(session, "VM.set_bios_boot", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = std_vga }
+ };
+
+ xen_call_(session, "VM.set_platform_std_vga", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = serial }
+ };
+
+ xen_call_(session, "VM.set_platform_serial", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = localtime }
+ };
+
+ xen_call_(session, "VM.set_platform_localtime", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = clock_offset }
+ };
+
+ xen_call_(session, "VM.set_platform_clock_offset", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = enable_audio }
+ };
+
+ xen_call_(session, "VM.set_platform_enable_audio", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_builder(xen_session *session, xen_vm vm, char *builder)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = builder }
+ };
+
+ xen_call_(session, "VM.set_builder", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_boot_method(xen_session *session, xen_vm vm, enum xen_boot_type boot_method)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &xen_boot_type_abstract_type_,
+ .u.string_val = xen_boot_type_to_string(boot_method) }
+ };
+
+ xen_call_(session, "VM.set_boot_method", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_kernel_kernel(xen_session *session, xen_vm vm, char *kernel)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = kernel }
+ };
+
+ xen_call_(session, "VM.set_kernel_kernel", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_kernel_initrd(xen_session *session, xen_vm vm, char *initrd)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = initrd }
+ };
+
+ xen_call_(session, "VM.set_kernel_initrd", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_kernel_args(xen_session *session, xen_vm vm, char *args)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = args }
+ };
+
+ xen_call_(session, "VM.set_kernel_args", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_grub_cmdline(xen_session *session, xen_vm vm, char *cmdline)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = cmdline }
+ };
+
+ xen_call_(session, "VM.set_grub_cmdline", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_set_otherconfig(xen_session *session, xen_vm vm, xen_string_string_map *otherconfig)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string_string_map,
+ .u.set_val = (arbitrary_set *)otherconfig }
+ };
+
+ xen_call_(session, "VM.set_otherconfig", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_clone(xen_session *session, xen_vm *result, xen_vm vm, char *new_name)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_string,
+ .u.string_val = new_name }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VM.clone");
+ return session->ok;
+}
+
+
+bool
+xen_vm_start(xen_session *session, xen_vm vm, bool start_paused)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = start_paused }
+ };
+
+ xen_call_(session, "VM.start", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_pause(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.pause", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_unpause(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.unpause", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_clean_shutdown(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.clean_shutdown", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_clean_reboot(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.clean_reboot", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_hard_shutdown(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.hard_shutdown", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_hard_reboot(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.hard_reboot", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_suspend(xen_session *session, xen_vm vm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm }
+ };
+
+ xen_call_(session, "VM.suspend", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_resume(xen_session *session, xen_vm vm, bool start_paused)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vm },
+ { .type = &abstract_type_bool,
+ .u.bool_val = start_paused }
+ };
+
+ xen_call_(session, "VM.resume", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_all(xen_session *session, struct xen_vm_set **result)
+{
+
+ abstract_type result_type = abstract_type_string_set;
+
+ *result = NULL;
+ xen_call_(session, "VM.get_all", NULL, 0, &result_type, result);
+ return session->ok;
+}
+
+
+bool
+xen_vm_get_uuid(xen_session *session, char **result, xen_vm vm)
+{
+ *result = session->ok ? xen_strdup_((char *)vm) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/src/xen_vm_power_state.c b/tools/libxen/src/xen_vm_power_state.c
new file mode 100644
index 0000000000..a9e2545c47
--- /dev/null
+++ b/tools/libxen/src/xen_vm_power_state.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "xen_internal.h"
+#include "xen_vm_power_state.h"
+#include "xen_vm_power_state_internal.h"
+
+
+/*
+ * Maintain this in the same order as the enum declaration!
+ */
+static const char *lookup_table[] =
+{
+ "Halted",
+ "Paused",
+ "Running",
+ "Suspended",
+ "ShuttingDown",
+ "Unknown"
+};
+
+
+extern xen_vm_power_state_set *
+xen_vm_power_state_set_alloc(size_t size)
+{
+ return calloc(1, sizeof(xen_vm_power_state_set) +
+ size * sizeof(enum xen_vm_power_state));
+}
+
+
+extern void
+xen_vm_power_state_set_free(xen_vm_power_state_set *set)
+{
+ free(set);
+}
+
+
+const char *
+xen_vm_power_state_to_string(enum xen_vm_power_state val)
+{
+ return lookup_table[val];
+}
+
+
+extern enum xen_vm_power_state
+xen_vm_power_state_from_string(xen_session *session, const char *str)
+{
+ return ENUM_LOOKUP(session, str, lookup_table);
+}
+
+
+const abstract_type xen_vm_power_state_abstract_type_ =
+ {
+ .typename = ENUM,
+ .enum_marshaller =
+ (const char *(*)(int))&xen_vm_power_state_to_string,
+ .enum_demarshaller =
+ (int (*)(xen_session *, const char *))&xen_vm_power_state_from_string
+ };
+
+
+const abstract_type xen_vm_power_state_set_abstract_type_ =
+ {
+ .typename = SET,
+ .child = &xen_vm_power_state_abstract_type_
+ };
+
+
diff --git a/tools/libxen/src/xen_vtpm.c b/tools/libxen/src/xen_vtpm.c
new file mode 100644
index 0000000000..eb8156a0a3
--- /dev/null
+++ b/tools/libxen/src/xen_vtpm.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006, IBM Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "xen_common.h"
+#include "xen_driver_type_internal.h"
+#include "xen_internal.h"
+#include "xen_vm.h"
+#include "xen_vtpm.h"
+
+
+XEN_FREE(xen_vtpm)
+XEN_SET_ALLOC_FREE(xen_vtpm)
+XEN_ALLOC(xen_vtpm_record)
+XEN_SET_ALLOC_FREE(xen_vtpm_record)
+XEN_ALLOC(xen_vtpm_record_opt)
+XEN_RECORD_OPT_FREE(xen_vtpm)
+XEN_SET_ALLOC_FREE(xen_vtpm_record_opt)
+
+
+static const struct_member xen_vtpm_record_struct_members[] =
+ {
+ { .key = "uuid",
+ .type = &abstract_type_string,
+ .offset = offsetof(xen_vtpm_record, uuid) },
+ { .key = "VM",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vtpm_record, vm) },
+ { .key = "backend",
+ .type = &abstract_type_ref,
+ .offset = offsetof(xen_vtpm_record, backend) },
+ { .key = "driver",
+ .type = &xen_driver_type_abstract_type_,
+ .offset = offsetof(xen_vtpm_record, driver) },
+ { .key = "instance",
+ .type = &abstract_type_int,
+ .offset = offsetof(xen_vtpm_record, instance) }
+ };
+
+const abstract_type xen_vtpm_record_abstract_type_ =
+ {
+ .typename = STRUCT,
+ .struct_size = sizeof(xen_vtpm_record),
+ .member_count =
+ sizeof(xen_vtpm_record_struct_members) / sizeof(struct_member),
+ .members = xen_vtpm_record_struct_members
+ };
+
+
+void
+xen_vtpm_record_free(xen_vtpm_record *record)
+{
+ if (record == NULL)
+ {
+ return;
+ }
+ free(record->handle);
+ free(record->uuid);
+ xen_vm_record_opt_free(record->vm);
+ xen_vm_record_opt_free(record->backend);
+ free(record);
+}
+
+
+bool
+xen_vtpm_get_record(xen_session *session, xen_vtpm_record **result, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ abstract_type result_type = xen_vtpm_record_abstract_type_;
+
+ *result = NULL;
+ XEN_CALL_("VTPM.get_record");
+
+ if (session->ok)
+ {
+ (*result)->handle = xen_strdup_((*result)->uuid);
+ }
+
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_by_uuid(xen_session *session, xen_vtpm *result, char *uuid)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = uuid }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VTPM.get_by_uuid");
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_create(xen_session *session, xen_vtpm *result, xen_vtpm_record *record)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &xen_vtpm_record_abstract_type_,
+ .u.struct_val = record }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VTPM.create");
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_destroy(xen_session *session, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ xen_call_(session, "VTPM.destroy", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_vm(xen_session *session, xen_vm *result, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VTPM.get_VM");
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_backend(xen_session *session, xen_vm *result, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ abstract_type result_type = abstract_type_string;
+
+ *result = NULL;
+ XEN_CALL_("VTPM.get_backend");
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_driver(xen_session *session, enum xen_driver_type *result, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ abstract_type result_type = xen_driver_type_abstract_type_;
+ char *result_str = NULL;
+ XEN_CALL_("VTPM.get_driver");
+ *result = xen_driver_type_from_string(session, result_str);
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_instance(xen_session *session, int64_t *result, xen_vtpm vtpm)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vtpm }
+ };
+
+ abstract_type result_type = abstract_type_int;
+
+ XEN_CALL_("VTPM.get_instance");
+ return session->ok;
+}
+
+
+bool
+xen_vtpm_get_uuid(xen_session *session, char **result, xen_vtpm vtpm)
+{
+ *result = session->ok ? xen_strdup_((char *)vtpm) : NULL;
+ return session->ok;
+}
diff --git a/tools/libxen/test/test_bindings.c b/tools/libxen/test/test_bindings.c
new file mode 100644
index 0000000000..0c47305a09
--- /dev/null
+++ b/tools/libxen/test/test_bindings.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2006 XenSource, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <curl/curl.h>
+
+#include "xen_host.h"
+#include "xen_sr.h"
+#include "xen_vbd.h"
+#include "xen_vdi.h"
+#include "xen_vm.h"
+
+
+static void usage()
+{
+ fprintf(stderr,
+"Usage:\n"
+"\n"
+" test_bindings <url> <username> <password>\n"
+"\n"
+"where\n"
+" <url> is a fragment of the server's URL, e.g. localhost:8005/RPC2;\n"
+" <username> is the username to use at the server; and\n"
+" <password> is the password.\n");
+
+ exit(EXIT_FAILURE);
+}
+
+
+static char *url;
+
+
+typedef struct
+{
+ xen_result_func func;
+ void *handle;
+} xen_comms;
+
+
+static void create_new_vm(xen_session *session);
+
+
+static size_t
+write_func(void *ptr, size_t size, size_t nmemb, xen_comms *comms)
+{
+ size_t n = size * nmemb;
+ return comms->func(ptr, n, comms->handle) ? n : 0;
+}
+
+
+static int
+call_func(const void *data, size_t len, void *user_handle,
+ void *result_handle, xen_result_func result_func)
+{
+ (void)user_handle;
+
+ CURL *curl = curl_easy_init();
+ if (!curl) {
+ return -1;
+ }
+
+ xen_comms comms = {
+ .func = result_func,
+ .handle = result_handle
+ };
+
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
+ curl_easy_setopt(curl, CURLOPT_MUTE, 1);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms);
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
+
+ CURLcode result = curl_easy_perform(curl);
+
+ curl_easy_cleanup(curl);
+
+ return result;
+}
+
+
+static void print_error(xen_session *session)
+{
+ fprintf(stderr, "Error: %d", session->error_description_count);
+ for (int i = 0; i < session->error_description_count; i++)
+ {
+ fprintf(stderr, "%s ", session->error_description[i]);
+ }
+ fprintf(stderr, "\n");
+}
+
+
+int main(int argc, char **argv)
+{
+ if (argc != 4)
+ {
+ usage();
+ }
+
+ url = argv[1];
+ char *username = argv[2];
+ char *password = argv[3];
+
+ xmlInitParser();
+ xen_init();
+ curl_global_init(CURL_GLOBAL_ALL);
+
+#define CLEANUP \
+ do { \
+ xen_session_logout(session); \
+ curl_global_cleanup(); \
+ xen_fini(); \
+ xmlCleanupParser(); \
+ } while(0) \
+
+
+ xen_session *session =
+ xen_session_login_with_password(call_func, NULL, username, password);
+
+ xen_vm vm;
+ if (!xen_vm_get_by_uuid(session, &vm,
+ "00000000-0000-0000-0000-000000000000"))
+ {
+ print_error(session);
+ CLEANUP;
+ return 1;
+ }
+
+ char *vm_uuid;
+ if (!xen_vm_get_uuid(session, &vm_uuid, vm))
+ {
+ print_error(session);
+ xen_vm_free(vm);
+ CLEANUP;
+ return 1;
+ }
+
+ char *vm_uuid_bytes;
+ if (!xen_uuid_string_to_bytes(vm_uuid, &vm_uuid_bytes))
+ {
+ fprintf(stderr, "xen_uuid_string_to_bytes failed.\n");
+ xen_uuid_free(vm_uuid);
+ xen_vm_free(vm);
+ CLEANUP;
+ return 1;
+ }
+
+ xen_vm_record *vm_record;
+ if (!xen_vm_get_record(session, &vm_record, vm))
+ {
+ print_error(session);
+ xen_uuid_bytes_free(vm_uuid_bytes);
+ xen_uuid_free(vm_uuid);
+ xen_vm_free(vm);
+ CLEANUP;
+ return 1;
+ }
+
+ xen_host host;
+ if (!xen_session_get_this_host(session, &host))
+ {
+ print_error(session);
+ xen_vm_record_free(vm_record);
+ xen_uuid_bytes_free(vm_uuid_bytes);
+ xen_uuid_free(vm_uuid);
+ xen_vm_free(vm);
+ CLEANUP;
+ return 1;
+ }
+
+ xen_string_string_map *versions;
+ if (!xen_host_get_software_version(session, &versions, host))
+ {
+ print_error(session);
+ xen_host_free(host);
+ xen_vm_record_free(vm_record);
+ xen_uuid_bytes_free(vm_uuid_bytes);
+ xen_uuid_free(vm_uuid);
+ xen_vm_free(vm);
+ CLEANUP;
+ return 1;
+ }
+
+ printf("%s.\n", vm_uuid);
+
+ fprintf(stderr, "In bytes, the VM UUID is ");
+ for (int i = 0; i < 15; i++)
+ {
+ fprintf(stderr, "%x, ", (unsigned int)vm_uuid_bytes[i]);
+ }
+ fprintf(stderr, "%x.\n", (unsigned int)vm_uuid_bytes[15]);
+
+ printf("%zd.\n", versions->size);
+
+ for (size_t i = 0; i < versions->size; i++)
+ {
+ printf("%s -> %s.\n", versions->contents[i].key,
+ versions->contents[i].val);
+ }
+
+ printf("%s.\n", vm_record->uuid);
+
+ printf("Resident on %s.\n", (char *)vm_record->resident_on->u.handle);
+
+ printf("%s.\n", xen_vm_power_state_to_string(vm_record->power_state));
+
+ for (size_t i = 0; i < vm_record->vcpus_utilisation->size; i++)
+ {
+ printf("%"PRId64" -> %lf.\n",
+ vm_record->vcpus_utilisation->contents[i].key,
+ vm_record->vcpus_utilisation->contents[i].val);
+ }
+
+ xen_uuid_bytes_free(vm_uuid_bytes);
+ xen_uuid_free(vm_uuid);
+ xen_vm_free(vm);
+
+ xen_vm_record_free(vm_record);
+
+ xen_host_free(host);
+ xen_string_string_map_free(versions);
+
+
+ create_new_vm(session);
+ if (!session->ok)
+ {
+ /* Error has been logged, just clean up. */
+ CLEANUP;
+ return 1;
+ }
+
+ CLEANUP;
+
+ return 0;
+}
+
+
+/**
+ * Creation of a new VM, using the Named Parameters idiom. Allocate the
+ * xen_vm_record here, but the sets through the library. Either
+ * allocation patterns can be used, as long as the allocation and free are
+ * paired correctly.
+ */
+static void create_new_vm(xen_session *session)
+{
+ xen_cpu_feature_set *empty_cpu_feature_set =
+ xen_cpu_feature_set_alloc(0);
+
+ xen_cpu_feature_set *force_off_cpu_feature_set =
+ xen_cpu_feature_set_alloc(1);
+ force_off_cpu_feature_set->contents[0] = XEN_CPU_FEATURE_MMX;
+
+ xen_vm_record vm_record =
+ {
+ .name_label = "NewVM",
+ .name_description = "New VM Description",
+ .user_version = 1,
+ .is_a_template = false,
+ .memory_static_max = 256,
+ .memory_dynamic_max = 256,
+ .memory_dynamic_min = 128,
+ .memory_static_min = 128,
+ .vcpus_policy = "credit",
+ .vcpus_params = "",
+ .vcpus_number = 2,
+ .vcpus_features_required = empty_cpu_feature_set,
+ .vcpus_features_can_use = empty_cpu_feature_set,
+ .vcpus_features_force_on = empty_cpu_feature_set,
+ .vcpus_features_force_off = force_off_cpu_feature_set,
+ .actions_after_shutdown = XEN_ON_NORMAL_EXIT_DESTROY,
+ .actions_after_reboot = XEN_ON_NORMAL_EXIT_RESTART,
+ .actions_after_suspend = XEN_ON_NORMAL_EXIT_DESTROY,
+ .actions_after_crash = XEN_ON_CRASH_BEHAVIOUR_PRESERVE,
+ .bios_boot = "hd(0,0)",
+ .builder = "Linux",
+ .boot_method = XEN_BOOT_TYPE_KERNEL_EXTERNAL,
+ .kernel_kernel = "vmlinuz",
+ .kernel_initrd = "initrd.img",
+ .kernel_args = ""
+ };
+
+
+ xen_vm vm;
+ xen_vm_create(session, &vm, &vm_record);
+
+ xen_cpu_feature_set_free(empty_cpu_feature_set);
+ xen_cpu_feature_set_free(force_off_cpu_feature_set);
+
+ if (!session->ok)
+ {
+ fprintf(stderr, "VM creation failed.\n");
+ print_error(session);
+ return;
+ }
+
+
+ /*
+ * Create a new disk for the new VM.
+ */
+ xen_sr_set *srs;
+ if (!xen_sr_get_by_name_label(session, &srs, "Local") ||
+ srs->size < 1)
+ {
+ fprintf(stderr, "SR lookup failed.\n");
+ print_error(session);
+ xen_vm_free(vm);
+ return;
+ }
+
+ xen_sr_record_opt sr_record =
+ {
+ .u.handle = srs->contents[0]
+ };
+ xen_vdi_record vdi0_record =
+ {
+ .name_label = "MyRootFS",
+ .name_description = "MyRootFS description",
+ .sr = &sr_record,
+ .virtual_size = (1 << 20) / 512,
+ .sector_size = 512,
+ .type = XEN_VDI_TYPE_SYSTEM,
+ .sharable = false,
+ .read_only = false
+ };
+
+ xen_vdi vdi0;
+ if (!xen_vdi_create(session, &vdi0, &vdi0_record))
+ {
+ fprintf(stderr, "VDI creation failed.\n");
+ print_error(session);
+
+ xen_sr_set_free(srs);
+ xen_vm_free(vm);
+ return;
+ }
+
+
+ xen_vm_record_opt vm_record_opt =
+ {
+ .u.handle = vm
+ };
+ xen_vdi_record_opt vdi0_record_opt =
+ {
+ .u.handle = vdi0
+ };
+ xen_vbd_record vbd0_record =
+ {
+ .vm = &vm_record_opt,
+ .vdi = &vdi0_record_opt,
+ .device = "sda1",
+ .mode = XEN_VBD_MODE_RW,
+ .driver = XEN_DRIVER_TYPE_PARAVIRTUALISED
+ };
+
+ xen_vbd vbd0;
+ if (!xen_vbd_create(session, &vbd0, &vbd0_record))
+ {
+ fprintf(stderr, "VBD creation failed.\n");
+ print_error(session);
+
+ xen_vdi_free(vdi0);
+ xen_sr_set_free(srs);
+ xen_vm_free(vm);
+ return;
+ }
+
+ char *vm_uuid;
+ char *vdi0_uuid;
+ char *vbd0_uuid;
+
+ xen_vm_get_uuid(session, &vm_uuid, vm);
+ xen_vdi_get_uuid(session, &vdi0_uuid, vdi0);
+ xen_vbd_get_uuid(session, &vbd0_uuid, vbd0);
+
+ if (!session->ok)
+ {
+ fprintf(stderr, "get_uuid call failed.\n");
+ print_error(session);
+
+ xen_uuid_free(vm_uuid);
+ xen_uuid_free(vdi0_uuid);
+ xen_uuid_free(vbd0_uuid);
+ xen_vbd_free(vbd0);
+ xen_vdi_free(vdi0);
+ xen_sr_set_free(srs);
+ xen_vm_free(vm);
+ return;
+ }
+
+ fprintf(stderr,
+ "Created a new VM, with UUID %s, VDI UUID %s, and VBD UUID %s.\n",
+ vm_uuid, vdi0_uuid, vbd0_uuid);
+
+ xen_uuid_free(vm_uuid);
+ xen_uuid_free(vdi0_uuid);
+ xen_uuid_free(vbd0_uuid);
+ xen_vbd_free(vbd0);
+ xen_vdi_free(vdi0);
+ xen_sr_set_free(srs);
+ xen_vm_free(vm);
+}
diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index eb6529f12d..13c95b56f7 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -1,7 +1,3 @@
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
XEN_ROOT=../..
include $(XEN_ROOT)/tools/Rules.mk
@@ -24,9 +20,6 @@ all: build
.PHONY: build
build: $(TARGETS)
$(MAKE) -C miniterm
-ifeq ($(CONFIG_MBOOTPACK),y)
- $(MAKE) -C mbootpack
-endif
$(MAKE) -C lomount
.PHONY: install
@@ -38,14 +31,11 @@ install: build
$(MAKE) -C lomount install
# No sense in installing miniterm on the Xen box.
# $(MAKE) -C miniterm install
-# Likewise mbootpack
-# $(MAKE) -C mbootpack install
.PHONY: clean
clean:
$(RM) *.o $(TARGETS) *~
$(MAKE) -C miniterm clean
- $(MAKE) -C mbootpack clean
$(MAKE) -C lomount clean
%.o: %.c $(HDRS) Makefile
diff --git a/tools/misc/lomount/Makefile b/tools/misc/lomount/Makefile
index 0ed470b1d3..04c928d66f 100644
--- a/tools/misc/lomount/Makefile
+++ b/tools/misc/lomount/Makefile
@@ -1,8 +1,3 @@
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-
XEN_ROOT=../../..
include $(XEN_ROOT)/tools/Rules.mk
diff --git a/tools/misc/lomount/lomount.c b/tools/misc/lomount/lomount.c
index 7b86683bef..74859e67ec 100644
--- a/tools/misc/lomount/lomount.c
+++ b/tools/misc/lomount/lomount.c
@@ -44,8 +44,6 @@ enum
ERR_MOUNT // Other failure of mount command
};
-#define _LARGEFILE_SOURCE
-#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/tools/misc/mbootpack/GPL b/tools/misc/mbootpack/GPL
deleted file mode 100644
index 5b6e7c66c2..0000000000
--- a/tools/misc/mbootpack/GPL
+++ /dev/null
@@ -1,340 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/tools/misc/mbootpack/Makefile b/tools/misc/mbootpack/Makefile
deleted file mode 100644
index 18116688f3..0000000000
--- a/tools/misc/mbootpack/Makefile
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# Makefile for mbootpack
-#
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
-XEN_ROOT=../../..
-include $(XEN_ROOT)/tools/Rules.mk
-
-.PHONY: all
-all: build
-
-.PHONY: build
-build: mbootpack
-
-.PHONY: install
-install: build
- $(INSTALL_PROG) mbootpack $(DESTDIR)/usr/bin
-
-# Tools etc.
-RM := rm -f
-GDB := gdb
-INCS := -I. -I-
-DEFS :=
-LDFLAGS :=
-CFLAGS += -Wpointer-arith -Wcast-qual -Wno-unused -Wno-format
-CFLAGS += -Wmissing-prototypes -pipe
-
-# What object files need building for the program
-OBJS := mbootpack.o buildimage.o
-
-# Get gcc to generate the dependencies for us.
-DEPFLAGS = -Wp,-MD,.$(@F).d
-DEPS = .*.d
-
-mbootpack: $(OBJS)
- $(HOSTCC) -o $@ $(filter-out %.a, $^)
-
-.PHONY: clean
-clean:
- $(RM) mbootpack *.o $(DEPS) bootsect setup bzimage_header.c bin2c
-
-bootsect: bootsect.S
- $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c bootsect.S -o bootsect.o
- $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary bootsect.o -o $@
-
-setup: setup.S
- $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c setup.S -o setup.o
- $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary setup.o -o $@
-
-bin2c: bin2c.o
- $(HOSTCC) -o $@ $^
-
-bzimage_header.c: bootsect setup bin2c
- ./bin2c -n 8 -b1 -a bzimage_bootsect bootsect > bzimage_header.c
- ./bin2c -n 8 -b1 -a bzimage_setup setup >> bzimage_header.c
-
-buildimage.c: bzimage_header.c
- @
-
-%.o: %.S
- $(HOSTCC) $(DEPFLAGS) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@
-
-%.o: %.c
- $(HOSTCC) $(DEPFLAGS) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@
-
-.PRECIOUS: $(OBJS) $(OBJS:.o=.c) $(DEPS)
-.SUFFIXES:
-
--include $(DEPS)
-
-#
-# EOF
-#
diff --git a/tools/misc/mbootpack/README b/tools/misc/mbootpack/README
deleted file mode 100644
index 07516529b4..0000000000
--- a/tools/misc/mbootpack/README
+++ /dev/null
@@ -1,77 +0,0 @@
-
-mbootpack
----------
-
-This is a utility to take a multiboot kernel and modules and repackage
-them in a form that a standard linux bootloader will be able to load them.
-It statically allocates memory addresses based on a 'standard' PC memory
-layout, and then saves the image of the loaded system, along with an
-almost-standard linux bzImage header which takes care of the start-of-day
-requirements of a multiboot kernel (setting up 32-bit protected mode, etc.)
-
-Example invocation, to package a xen VMM and xenlinux guest and initrd:
-
- mbootpack -o bzImage -m ./xenlinux -m ./initrd.img ./xen-image
-
-You can now boot the 'bzImage' file using your favourite linux bootloader.
-
-The kernel command line will be provided at boot time by the bootloader
-(you can specify a kernel command-line using the '-c' flag, but it will
-be overridden at boot time unledd the bootloder provides an entirely
-empty command line). If you wan to override the command line for the
-first module (i.e. domain 0 kernel in Xen) at boot time, append ' -- '
-and the module commadn line to the bootloader command line, e.g.:
-
- boot: bzImage com1=9600,8n1 console=com1 dom0_mem=49152 -- root=/dev/sda3 ro console=ttyS0,9600n8
-
-Everything before the '--' is passed to the kernel (xen) as its command
-line; everything after is passed to the first module (xenlinux).
-
-This is ALPHA code: there are execution paths which have *not* been
-tested, though it works for loading the Xen hypervisor using GrUB, LILO
-or SYSLINUX. Bug reports and patches are very welcome.
-
-Possible features for future versions (all look possible, if there's any
-demand for them):
-
- - support for kernels that load below 1MB
- - zImage-style compressed images
- - sane error messgaes for insane load addresses
- - support for the MULTIBOOT_VIDEO_MODE bit
- - proper support for passing E820h memory-maps from bzImage
-
-
-Tim Deegan <tjd21@cl.cam.ac.uk>, March 2005
-
-
-
-License and attributions
-------------------------
-
-The bzImage header block was originally taken from the Linux kernel.
-http://www.kernel.org/
-
-Some parts of the Multiboot loader code are based on GNU GRUB.
-mb_info.h and mb_header.h are taken from GNU GRUB.
-http://www.gnu.org/software/grub/
-
-Bin2C was written by Nicolas Doualot; I tidied it a bit for a clean compile.
-http://slubman.celeonet.fr/program.php?style=Default&project=bin2c
-
-All other code is copyright (C) 2003-2005 Tim Deegan (tjd21@cl.cam.ac.uk)
-
-mbootpack is distributed under the GNU General Public License: see "GPL"
-
-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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
diff --git a/tools/misc/mbootpack/bin2c.c b/tools/misc/mbootpack/bin2c.c
deleted file mode 100644
index 609335da7d..0000000000
--- a/tools/misc/mbootpack/bin2c.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/***************************************************************************************
- Project informations:
- Project: bin2c
- Version: 1.00
- Plateforme: PC
- Copyright: DNDD.INC
- Date: 28/03/2004
-
- File informations:
- Name: bin2c.c
- Description:Convert any file to a C array
-
- Author informations:
- Author: DOUALOT Nicolas
- E-Mail: slubman@laposte.net
- site: http://membres.lycos.fr/slubman/gp32
-***************************************************************************************/
-
-
-#include <stdio.h> /*perror */
-#include <sys/mman.h> /*PROT_READ,MAP_xxx */
-#include <fcntl.h> /*O_RDONLY */
-#include <sys/stat.h> /*stat */
-#include <stdlib.h> /*atoi */
-#include <string.h> /*strcmp */
-#include <ctype.h> /*toupper */
-
-#define VERSION "1.10"
-
-
-static void help(void)
-{
- fprintf(stdout, "\nbin2c v"VERSION"\n");
- fprintf(stdout, "Slubman DevSoft (c)2003-2004 slubman.dndd@laposte.net \n\n");
-
- fprintf(stdout, "Usage: bin2c [flags] <infile>\n\n");
-
- //fprintf(stdout, "\t-quiet :\tdon't output standard messages\n");
- //fprintf(stdout, "\t-slash :\tappend backslash at end of line\n");
- fprintf(stdout, "\t-n <count> :\tnumber of items per line\n");
- fprintf(stdout, "\t-b1 :\tgenerate unsigned char array\n");
- fprintf(stdout, "\t-b2 :\tgenerate unsigned short array\n");
- fprintf(stdout, "\t-b4 :\tgenerate unsigned long array\n");
- fprintf(stdout, "\t-a <name> :\tgenerate an array with given name\n");
- fprintf(stdout, "\t-ss <nr> :\tskip number of bytes at begin of inputfile\n");
- fprintf(stdout, "\t-se <nr> :\tskip number of bytes at end of inputfile\n");
- fprintf(stdout, "\t-lb <nr> :\tinsert an additionally linebreak every nr line\n");
- fprintf(stdout, "\t-h :\tproduce an header\n");
- fprintf(stdout, "\tinfile :\tname of infile\n");
- fprintf(stdout, "\toutfile :\tname of outfile (use \"-\" for stdout)\n\n");
-
- fprintf(stdout, " \tconverts binary file to C array data\n");
-}
-
-static void UnknownFlag(char *flag)
-{
- fprintf(stderr, "Error: unknown flag %s\n", flag);
- help();
- exit(EXIT_FAILURE);
-}
-
-static void WriteHeader(FILE * outFile, char *oFileName, char *iFileName)
-{
- // File Header
- fprintf(outFile, "/***************************************************************************************\n");
- fprintf(outFile, "* File Name:\n");
- fprintf(outFile, "* Name: %s\n", oFileName);
- fprintf(outFile, "* From: %s\n", iFileName);
- fprintf(outFile, "* Created by :bin2c v"VERSION"\n*\n");
- fprintf(outFile, "* bin2c v"VERSION":\n");
- fprintf(outFile, "* Author: DOUALOT Nicolas\n");
- fprintf(outFile, "* E-Mail: slubman.dndd@laposte.net\n");
- fprintf(outFile, "* site: http://www.slubman.linux-fan.com/\n");
- fprintf(outFile, "***************************************************************************************/\n\n");
-}
-
-int main(int argc, char *argv[])
-{
- FILE *inFile = stdin, *outFile = stdout;
- int a, i, nbLine = 0;
- unsigned char *memory;
- struct stat st;
-
- // Options
- char arrayName[255] = "array"; // Array name
- char *iFileName = NULL; // File to convert
- char *oFileName = NULL; // File to write
- int bpd = 1; // Array item length
- int lb = 0; // Array blank line each lb line(s)
- int nbCol = 15; // Nuber of items per line
- int SkeepStart = 0; // Number of byte to skip at file begining
- int SkeepEnd = 0; // Number of byte to skip at file end
- int header = 0; // Produce an header
-
- // Is there the good number of arguments
- if (argc < 2)
- {
- help();
- return 0;
- }
-
- // On récupère les arguments (Ready for more options)
- for (a = 1; a < argc; a++)
- {
- // An option
- if (argv[a][0] == '-')
- {
- // Wich flag is it ?
- switch (argv[a][1])
- {
- // Writting on stdout
- case 0:
- printf("%s\n", argv[a]);
- outFile = stdout;
- break;
-
- // ArrayName flag
- case 'a':
- strcpy(arrayName, argv[++a]);
- break;
-
- // Data type
- case 'b':
- switch (argv[a][2])
- {
- case '1':
- bpd = 1;
- break;
-
- case '2':
- bpd = 2;
- break;
-
- case '4':
- bpd = 4;
- break;
-
- default:
- UnknownFlag(argv[a]);
- }
- break;
-
- // Produce an header
- case 'h':
- header = 1;
- break;
-
- // New line each n line
- case 'l':
- switch (argv[a][2])
- {
- case 'b':
- lb = atoi(argv[++a]);
- break;
-
- default:
- UnknownFlag(argv[a]);
- }
-
- // Number of bit per line
- case 'n':
- nbCol = atoi(argv[++a]);
- break;
-
- // Skip bytes
- case 's':
- switch (argv[a][2])
- {
- // Beginig of file
- case 's':
- SkeepStart = atoi(argv[++a]);
- break;
-
- // End of file
- case 'e':
- SkeepEnd = atoi(argv[++a]);
- break;
-
- // Flag inconnu
- default:
- UnknownFlag(argv[a]);
- }
-
- // Flag inconnu
- default:
- UnknownFlag(argv[a]);
- }
- }
- // A filename
- else
- {
- if (iFileName == NULL)
- {
- iFileName = argv[a];
- if ((inFile = fopen(iFileName, "rb")) == NULL)
- {
- fprintf(stderr, "Error: can't open %s\n", iFileName);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- if (oFileName == NULL)
- {
- oFileName = argv[a];
- if ((outFile = fopen(oFileName, "wb")) == NULL)
- {
- fprintf(stderr, "Error: can't open %s\n", oFileName);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- fprintf(stderr, "Error: Too many filesnames given!\n");
- help();
- exit(EXIT_FAILURE);
- }
- }
- }
- }
-
- if (!iFileName)
- exit(EXIT_FAILURE);
-
- // Get file informations
- if (stat(iFileName, &st) != 0)
- {
- fprintf(stderr, "Error: when scanning file %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
-
- // Allocating memory
- if (!(memory = malloc(st.st_size + 3)))
- {
- memset(memory, 0, st.st_size + 3);
- fprintf(stderr, "Error: not enought memory\n");
- exit(EXIT_FAILURE);
- }
-
- // Reading the file
- if (fread(memory, 1, st.st_size, inFile) != (size_t)st.st_size)
- {
- fprintf(stderr, "Error: when reading file %s\n", argv[1]);
- fclose(inFile);
- exit(EXIT_FAILURE);
- }
- fclose(inFile);
-
- // Must produce an header
- if (header)
- {
- unsigned int i;
- char hFileName[256], *def = NULL;
- FILE *hFile = stdout;
-
- if (oFileName)
- {
- strcpy(hFileName, oFileName);
- hFileName[strlen(hFileName) - 1] = 'h';
- hFile = fopen(hFileName, "wt");
- }
-
- WriteHeader(hFile, hFileName, iFileName);
-
- // Replace all '.' by '_'
- for (i = 0; i < strlen(hFileName); i++)
- if (hFileName[i] == '.')
- hFileName[i] = '_';
- else
- hFileName[i] = toupper(hFileName[i]);
-
- // the #ifdef at the begining
- def = strrchr(hFileName, '/');
- def = def ? def + 1 : hFileName;
- fprintf(hFile, "#ifndef __%s__\n#define __%s__\n\n", def, def);
-
- // Define array size
- fprintf(hFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
-
- // Begin the array
- fprintf(hFile, "extern unsigned ");
- fprintf(hFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long");
- fprintf(hFile, "%s[", arrayName);
- fprintf(hFile, "%u];\n\n", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
-
- // the #endif at the end
- fprintf(hFile, "#endif\n\n");
-
- if (oFileName)
- fclose(hFile);
- }
-
- WriteHeader(outFile, oFileName, iFileName);
-
- // Define array size
- if (!header)
- fprintf(outFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
-
- // Begin the array
- fprintf(outFile, "unsigned ");
- fprintf(outFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long");
- fprintf(outFile, "%s[", arrayName);
- fprintf(outFile, "%u] = {\n\t", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd);
-
- // Writing file elements
- for (i = 0; i < (st.st_size - SkeepEnd - SkeepStart) / bpd; /*i+=bpd */ i++)
- {
- // We write an item of bpd byte(s)
- switch (bpd)
- {
- case 1:
- fprintf(outFile, "0x%02x", *(unsigned char *) &memory[SkeepStart + i]);
- break;
-
- case 2:
- fprintf(outFile, "0x%04x", *(unsigned short *) &memory[SkeepStart + i]);
- break;
-
- case 4:
- fprintf(outFile, "0x%08lx", *(unsigned long *) &memory[SkeepStart + i]);
- break;
- }
-
- // Must put a coma ?
- if (i != st.st_size - 1)
- fprintf(outFile, ",");
-
- // End of a line ?
- if (i && !((i + 1) % nbCol))
- {
- // -lb option
- if (lb && !((++nbLine) % lb))
- fprintf(outFile, "\n");
- fprintf(outFile, "\n\t");
- }
- // Add a space
- else
- fprintf(outFile, " ");
- }
-
- // The last line as nbCol elements
- if (((st.st_size - SkeepStart - SkeepEnd) / bpd) % nbCol)
- fprintf(outFile, "\n");
-
- // Close the array
- fprintf(outFile, "};\n");
-
- // CLose the output file
- if (outFile != stdout)
- fclose(outFile);
-
- // Free allocated memory
- free(memory);
-
- exit(EXIT_SUCCESS);
-}
diff --git a/tools/misc/mbootpack/bootsect.S b/tools/misc/mbootpack/bootsect.S
deleted file mode 100644
index 2cc9ee106c..0000000000
--- a/tools/misc/mbootpack/bootsect.S
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * bootsect.S
- *
- * This is bootsect.S from the linux 2.6.9 sources,
- * with minor changes for mbootpack.
- *
- *
- * 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, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: bootsect.S,v 1.2 2005/03/23 10:39:11 tjd21 Exp $
- *
- */
-
-#include "mbootpack.h"
-
-/*
- * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * modified by Drew Eckhardt
- * modified by Bruce Evans (bde)
- * modified by Chris Noe (May 1999) (as86 -> gas)
- * gutted by H. Peter Anvin (Jan 2003)
- *
- * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
- * addresses must be multiplied by 16 to obtain their respective linear
- * addresses. To avoid confusion, linear addresses are written using leading
- * hex while segment addresses are written as segment:offset.
- *
- */
-
-/* #include <asm/boot.h> */
-/* Definitions we should have got from there */
-#define DEF_INITSEG 0x9000
-#define DEF_SYSSEG 0x1000
-#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x7F00
-#define NORMAL_VGA 0xffff
-#define EXTENDED_VGA 0xfffe
-#define ASK_VGA 0xfffd
-
-
-/* SETUPSECTS = 4 */ /* default nr of setup-sectors */
-BOOTSEG = 0x07C0 /* original address of boot-sector */
-INITSEG = DEF_INITSEG /* we move boot here - out of the way */
-SETUPSEG = DEF_SETUPSEG /* setup starts here */
-SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
-SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
- /* to be loaded */
-ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
-SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
-
-#ifndef SVGA_MODE
-/* #define SVGA_MODE ASK_VGA */
-#define SVGA_MODE NORMAL_VGA
-#endif
-
-#ifndef RAMDISK
-#define RAMDISK 0
-#endif
-
-#ifndef ROOT_RDONLY
-#define ROOT_RDONLY 1
-#endif
-
-.code16
-.text
-
-.global _start
-_start:
-
- # Normalize the start address
- jmpl $BOOTSEG, $start2
-
-start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw $0x7c00, %sp
- sti
- cld
-
- movw $bugger_off_msg, %si
-
-msg_loop:
- lodsb
- andb %al, %al
- jz die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
-
-die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
-
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
-
-
-bugger_off_msg:
- .ascii "Direct booting from floppy is no longer supported.\r\n"
- .ascii "Please use a boot loader program instead.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot . . .\r\n"
- .byte 0
-
-
- # Kernel attributes; used by setupbegtext
-
- .org 497
-setup_sects: .byte SETUPSECTS
-root_flags: .word ROOT_RDONLY
-syssize: .word SYSSIZE
-swap_dev: .word SWAP_DEV
-ram_size: .word RAMDISK
-vid_mode: .word SVGA_MODE
-root_dev: .word ROOT_DEV
-boot_flag: .word 0xAA55
diff --git a/tools/misc/mbootpack/buildimage.c b/tools/misc/mbootpack/buildimage.c
deleted file mode 100644
index a69d214684..0000000000
--- a/tools/misc/mbootpack/buildimage.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * buildimage.c
- *
- * Takes the memory image of a loaded kernel and modules and repackages
- * it as a linux bzImage
- *
- * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk)
- *
- * 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, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: buildimage.c,v 1.2 2005/03/23 10:39:19 tjd21 Exp $
- *
- */
-
-
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <elf.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <asm/page.h>
-
-#include "mbootpack.h"
-#include "mb_header.h"
-
-
-/* We will build an image that a bzImage-capable bootloader will load like
- * this:
- *
- * ============== (0)
- * (BIOS memory)
- * --------------
- * (Bootloader)
- * --------------
- * bzImage startup code
- * MBI, command-lines, module info
- * ============== (0xa0000)
- * (memory hole)
- * ============== (0x100000)
- * Kernel and modules
- * ==============
- *
- * The bzImage startup code is mostly taken straight from the linux kernel
- * (see bootsect.S, startup.S). It does the usual unpleasant start-of-day
- * tasks to get to 32-bit protected mode, then sets registers appropriately
- * and jumps to the kernel's entry address.
- *
- * It also does some relocation to make sure the MBI is where we expect it,
- * and parses the linux command line.
- */
-
-#define BZ_SETUP_OFFSET (512 * (1 + SETUPSECTS))
-#define BZ_ENTRY_OFFSET 0x30
-#define BZ_MBI_OFFSET 0x34
-/* These *MUST* fit the offsets of entry_address and mbi_address in setup.S */
-
-/* Bring in the bzImage boot sector and setup code */
-#include "bzimage_header.c"
-
-address_t place_mbi(long int size)
-/* Find space at the top of *low* memory for the MBI and associated red tape */
-{
- address_t start;
- start = 0xa000 - size;
- if (start < 0x9000 + sizeof(bzimage_bootsect) + sizeof(bzimage_setup)) {
- printf("Fatal: command-lines too long: need %i, have %i bytes\n",
- size,
- 0x1000 - (sizeof(bzimage_bootsect) + sizeof(bzimage_setup)));
- exit(1);
- }
- if (!quiet) {
- printf("Placed MBI and strings (%p+%p)\n",
- start, size);
- }
- return start;
-}
-
-void make_bzImage(section_t *sections,
- address_t entry,
- address_t mbi,
- FILE *fp)
-/* Rework this list of sections into a bzImage and write it out to fp */
-{
- int i;
- size_t offset;
- section_t *s;
-
- /* Patch the kernel and mbi addresses into the setup code */
- *(address_t *)(bzimage_setup + BZ_ENTRY_OFFSET) = eswap(entry);
- *(address_t *)(bzimage_setup + BZ_MBI_OFFSET) = eswap(mbi);
- if (!quiet) printf("Kernel entry is %p, MBI is %p.\n", entry, mbi);
-
- /* Write out header and trampoline */
- if (fseek(fp, 0, SEEK_SET) < 0) {
- printf("Fatal: error seeking in output file: %s\n",
- strerror(errno));
- exit(1);
- }
- if (fwrite(bzimage_bootsect, sizeof(bzimage_bootsect), 1, fp) != 1) {
- printf("Fatal: error writing to output file: %s\n",
- strerror(errno));
- exit(1);
- }
- if (fwrite(bzimage_setup, sizeof(bzimage_setup), 1, fp) != 1) {
- printf("Fatal: error writing to output file: %s\n",
- strerror(errno));
- exit(1);
- }
-
- if (!quiet) printf("Wrote bzImage header: %i + %i bytes.\n",
- sizeof(bzimage_bootsect), sizeof(bzimage_setup));
-
- /* Sorted list of sections below 1MB: write them out */
- for (s = sections, i = 0; s; s = s->next) {
- if (s->start >= HIGHMEM_START) continue;
- offset = (s->start - 0x9000);
- if (fseek(fp, offset, SEEK_SET) < 0) {
- printf("Fatal: error seeking in output file: %s\n",
- strerror(errno));
- exit(1);
- }
- if (fwrite(s->buffer, s->size, 1, fp) != 1) {
- printf("Fatal: error writing to output file: %s\n",
- strerror(errno));
- exit(1);
- }
- i++;
- }
-
- if (!quiet) printf("Wrote %i low-memory sections.\n", i);
-
- /* Sorted list of sections higher than 1MB: write them out */
- for (s = sections, i = 0; s; s = s->next) {
- if (s->start < HIGHMEM_START) continue;
- offset = (s->start - HIGHMEM_START) + BZ_SETUP_OFFSET;
- if (fseek(fp, offset, SEEK_SET) < 0) {
- printf("Fatal: error seeking in output file: %s\n",
- strerror(errno));
- exit(1);
- }
- if (fwrite(s->buffer, s->size, 1, fp) != 1) {
- printf("Fatal: error writing to output file: %s\n",
- strerror(errno));
- exit(1);
- }
- i++;
- }
-
- if (!quiet) printf("Wrote %i high-memory sections.\n", i);
-}
-
-
-/*
- * EOF(buildimage.c)
- */
diff --git a/tools/misc/mbootpack/mb_header.h b/tools/misc/mbootpack/mb_header.h
deleted file mode 100644
index 21934574f3..0000000000
--- a/tools/misc/mbootpack/mb_header.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * MultiBoot Header description
- */
-
-struct multiboot_header
-{
- /* Must be MULTIBOOT_MAGIC - see below. */
- unsigned magic;
-
- /* Feature flags - see below. */
- unsigned flags;
-
- /*
- * Checksum
- *
- * The above fields plus this one must equal 0 mod 2^32.
- */
- unsigned checksum;
-
- /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
- unsigned header_addr;
- unsigned load_addr;
- unsigned load_end_addr;
- unsigned bss_end_addr;
- unsigned entry_addr;
-
- /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
- unsigned mode_type;
- unsigned width;
- unsigned height;
- unsigned depth;
-};
-
-/*
- * The entire multiboot_header must be contained
- * within the first MULTIBOOT_SEARCH bytes of the kernel image.
- */
-#define MULTIBOOT_SEARCH 8192
-#define MULTIBOOT_FOUND(addr, len) \
- (! ((addr) & 0x3) \
- && (len) >= 12 \
- && *((int *) (addr)) == MULTIBOOT_MAGIC \
- && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \
- + *((unsigned *) (addr + 8))) \
- && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \
- && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48))
-
-/* Magic value identifying the multiboot_header. */
-#define MULTIBOOT_MAGIC 0x1BADB002
-
-/*
- * Features flags for 'flags'.
- * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set
- * and it doesn't understand it, it must fail.
- */
-#define MULTIBOOT_MUSTKNOW 0x0000FFFF
-
-/* currently unsupported flags... this is a kind of version number. */
-#define MULTIBOOT_UNSUPPORTED 0x0000FFF8
-
-/* Align all boot modules on i386 page (4KB) boundaries. */
-#define MULTIBOOT_PAGE_ALIGN 0x00000001
-
-/* Must pass memory information to OS. */
-#define MULTIBOOT_MEMORY_INFO 0x00000002
-
-/* Must pass video information to OS. */
-#define MULTIBOOT_VIDEO_MODE 0x00000004
-
-/* This flag indicates the use of the address fields in the header. */
-#define MULTIBOOT_AOUT_KLUDGE 0x00010000
diff --git a/tools/misc/mbootpack/mb_info.h b/tools/misc/mbootpack/mb_info.h
deleted file mode 100644
index fb37f10ff0..0000000000
--- a/tools/misc/mbootpack/mb_info.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * The structure type "mod_list" is used by the "multiboot_info" structure.
- */
-
-struct mod_list
-{
- /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
- unsigned long mod_start;
- unsigned long mod_end;
-
- /* Module command line */
- unsigned long cmdline;
-
- /* padding to take it to 16 bytes (must be zero) */
- unsigned long pad;
-};
-
-
-/*
- * INT-15, AX=E820 style "AddressRangeDescriptor"
- * ...with a "size" parameter on the front which is the structure size - 4,
- * pointing to the next one, up until the full buffer length of the memory
- * map has been reached.
- */
-
-struct AddrRangeDesc
-{
- unsigned long size;
- unsigned long long BaseAddr;
- unsigned long long Length;
- unsigned long Type;
-
- /* unspecified optional padding... */
-};
-
-/* usable memory "Type", all others are reserved. */
-#define MB_ARD_MEMORY 1
-
-
-/* Drive Info structure. */
-struct drive_info
-{
- /* The size of this structure. */
- unsigned long size;
-
- /* The BIOS drive number. */
- unsigned char drive_number;
-
- /* The access mode (see below). */
- unsigned char drive_mode;
-
- /* The BIOS geometry. */
- unsigned short drive_cylinders;
- unsigned char drive_heads;
- unsigned char drive_sectors;
-
- /* The array of I/O ports used for the drive. */
- unsigned short drive_ports[0];
-};
-
-/* Drive Mode. */
-#define MB_DI_CHS_MODE 0
-#define MB_DI_LBA_MODE 1
-
-
-/* APM BIOS info. */
-struct apm_info
-{
- unsigned short version;
- unsigned short cseg;
- unsigned long offset;
- unsigned short cseg_16;
- unsigned short dseg_16;
- unsigned short cseg_len;
- unsigned short cseg_16_len;
- unsigned short dseg_16_len;
-};
-
-
-/*
- * MultiBoot Info description
- *
- * This is the struct passed to the boot image. This is done by placing
- * its address in the EAX register.
- */
-
-struct multiboot_info
-{
- /* MultiBoot info version number */
- unsigned long flags;
-
- /* Available memory from BIOS */
- unsigned long mem_lower;
- unsigned long mem_upper;
-
- /* "root" partition */
- unsigned long boot_device;
-
- /* Kernel command line */
- unsigned long cmdline;
-
- /* Boot-Module list */
- unsigned long mods_count;
- unsigned long mods_addr;
-
- union
- {
- struct
- {
- /* (a.out) Kernel symbol table info */
- unsigned long tabsize;
- unsigned long strsize;
- unsigned long addr;
- unsigned long pad;
- }
- a;
-
- struct
- {
- /* (ELF) Kernel section header table */
- unsigned long num;
- unsigned long size;
- unsigned long addr;
- unsigned long shndx;
- }
- e;
- }
- syms;
-
- /* Memory Mapping buffer */
- unsigned long mmap_length;
- unsigned long mmap_addr;
-
- /* Drive Info buffer */
- unsigned long drives_length;
- unsigned long drives_addr;
-
- /* ROM configuration table */
- unsigned long config_table;
-
- /* Boot Loader Name */
- unsigned long boot_loader_name;
-
- /* APM table */
- unsigned long apm_table;
-
- /* Video */
- unsigned long vbe_control_info;
- unsigned long vbe_mode_info;
- unsigned short vbe_mode;
- unsigned short vbe_interface_seg;
- unsigned short vbe_interface_off;
- unsigned short vbe_interface_len;
-};
-
-/*
- * Flags to be set in the 'flags' parameter above
- */
-
-/* is there basic lower/upper memory information? */
-#define MB_INFO_MEMORY 0x00000001
-/* is there a boot device set? */
-#define MB_INFO_BOOTDEV 0x00000002
-/* is the command-line defined? */
-#define MB_INFO_CMDLINE 0x00000004
-/* are there modules to do something with? */
-#define MB_INFO_MODS 0x00000008
-
-/* These next two are mutually exclusive */
-
-/* is there a symbol table loaded? */
-#define MB_INFO_AOUT_SYMS 0x00000010
-/* is there an ELF section header table? */
-#define MB_INFO_ELF_SHDR 0x00000020
-
-/* is there a full memory map? */
-#define MB_INFO_MEM_MAP 0x00000040
-
-/* Is there drive info? */
-#define MB_INFO_DRIVE_INFO 0x00000080
-
-/* Is there a config table? */
-#define MB_INFO_CONFIG_TABLE 0x00000100
-
-/* Is there a boot loader name? */
-#define MB_INFO_BOOT_LOADER_NAME 0x00000200
-
-/* Is there a APM table? */
-#define MB_INFO_APM_TABLE 0x00000400
-
-/* Is there video information? */
-#define MB_INFO_VIDEO_INFO 0x00000800
-
-/*
- * The following value must be present in the EAX register.
- */
-
-#define MULTIBOOT_VALID 0x2BADB002
diff --git a/tools/misc/mbootpack/mbootpack.c b/tools/misc/mbootpack/mbootpack.c
deleted file mode 100644
index 3e4cd51a99..0000000000
--- a/tools/misc/mbootpack/mbootpack.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * mbootpack.c
- *
- * Takes a multiboot image, command-line and modules, and repackages
- * them as if they were a linux kernel. Only supports a subset of
- * the multiboot info page options (enough to boot the Xen hypervisor).
- *
- * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk)
- *
- * Parts based on GNU GRUB, Copyright (C) 2000 Free Software Foundation, Inc
- *
- * 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, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: mbootpack.c,v 1.3 2005/03/23 10:38:36 tjd21 Exp tjd21 $
- *
- */
-
-#define _GNU_SOURCE
-#include "mbootpack.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <elf.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <asm/page.h>
-
-/* From GNU GRUB */
-#include "mb_header.h"
-#include "mb_info.h"
-
-
-/*
- * The plan: Marshal up the multiboot modules and strings as if we
- * were loading them into memory on a fresh ix86 PC. Attach
- * a linux bzImage header to the front, which sets up the machine
- * appropriately and then jumps to the kernel entry address.
- *
- * The memory map will be made up roughly like so:
- *
- * =============
- * multiboot information (mbi) struct
- * -------
- * kernel command line
- * -------
- * bootloader name
- * -------
- * module command lines
- * -------
- * module information structs
- * =============
- * (memory hole)
- * =============
- * kernel
- * -------------
- * module 1
- * -------------
- * module 2
- * -------------
- * .
- * .
- * .
- *
- * ==============
- *
- *
- * For allocation of memory we assume that the target machine has 'low'
- * memory from 0 to 640K and 'high' memory starting at 1M. We allocate
- * the kernel first, wherever it wants to be. After that, sections
- * are added at the next available aligned address, always in the order
- * given above, and skipping the memory hole at 640K. Allocated sections
- * are stored in a linked list of buffers.
- *
- * Re-packaging as a bzImage file happens in buildimage.c
- *
- */
-
-/* Version */
-static const char version_string[] = "mbootpack " MBOOTPACK_VERSION_STRING;
-
-/* Flags */
-int quiet = 0;
-
-/* How much of the start of a kernel we read looking for headers.
- * Must be >= MULTIBOOT_SEARCH */
-#define HEADERBUF_SIZE MULTIBOOT_SEARCH
-
-
-/* Linked list of loaded sections, and a pointer to the next
- * available space (i.e. just above the highest allocation so far). */
-static section_t *sections = NULL;
-static section_t *last_section = NULL;
-static address_t next_free_space = 0;
-
-static void usage(void)
-/* If we don't understand the command-line options */
-{
- printf(
-"Usage: mbpack [OPTIONS] kernel-image\n\n"
-" -h --help Print this text.\n"
-" -q --quiet Only output errors and warnings.\n"
-" -o --output=filename Output to filename (default \"bzImage\").\n"
-" -M --multiboot-output Produce a multiboot kernel, not a bzImage\n"
-" (sets default output file to \"mbImage\").\n"
-" -c --command-line=STRING Set the kernel command line (DEPRECATED!).\n"
-" -m --module=\"MOD arg1 arg2...\" Load module MOD with arguments \"arg1...\"\n"
-" (can be used multiple times).\n"
-"\n");
- exit(1);
-}
-
-
-static void place_kernel_section(address_t start, long int size)
-/* Place the kernel in memory, checking for the memory hole. */
-{
- if (start >= MEM_HOLE_END) {
- /* Above the memory hole: easy */
- next_free_space = MAX(next_free_space, start + size);
- if (!quiet) {
- printf("Placed kernel section (%p+%p)\n", start, size);
- }
- return;
- }
-
- if (start >= MEM_HOLE_START) {
- /* In the memory hole. Not so good */
- printf("Fatal: kernel load address (%p) is in the memory hole.\n",
- start);
- exit(1);
- }
-
- if (start + size > MEM_HOLE_START) {
- /* Too big for low memory */
- printf("Fatal: kernel (%p+%p) runs into the memory hole.\n",
- start, size);
- exit(1);
- }
-
- /* Kernel loads below the memory hole */
- next_free_space = MAX(next_free_space, start + size);
-
- if (!quiet) {
- printf("Placed kernel section (%p+%p)\n", start, size);
- }
-}
-
-
-static address_t place_section(long int size, int align)
-/* Find the next available place for this section.
- * "align" must be a power of 2 */
-{
- address_t start;
- assert(next_free_space != 0);
- assert(((~align + 1) & align) == align);
-
- start = ROUNDUP_P2(next_free_space, align);
-
- /* Check that we don't hit the memory hole */
- if (start < MEM_HOLE_END && (start + size) > MEM_HOLE_START)
- start = ROUNDUP_P2(MEM_HOLE_END, align);
-
- next_free_space = start + size;
-
- if (!quiet) {
- printf("Placed section (%p+%p), align=%p\n",
- start, size, align);
- }
- return start;
-}
-
-
-
-
-static address_t load_kernel(const char *filename)
-/* Load an elf32/multiboot kernel from this file
- * Returns the entry address for the kernel. */
-{
- unsigned int i;
- address_t start;
- size_t len;
- long int size, loadsize;
- FILE *fp;
- char *buffer;
- section_t *sec, *s;
- Elf32_Ehdr *ehdr;
- Elf32_Phdr *phdr;
- struct multiboot_header *mbh;
- struct stat sb;
-
- static char headerbuf[HEADERBUF_SIZE];
-
- /* Stat and open the file */
- if (stat(filename, &sb) != 0) {
- printf("Fatal: cannot stat %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- if ((fp = fopen(filename, "r")) == NULL) {
- printf("Fatal: cannot open %s: %s\n", filename, strerror(errno));
- exit(1);
- }
-
- /* Load the first 8k of the file */
- if (fseek(fp, 0, SEEK_SET) < 0) {
- printf("Fatal: seek error in %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- if ((len = fread(headerbuf, 1, HEADERBUF_SIZE, fp))
- < HEADERBUF_SIZE)
- {
- if (feof(fp)) /* Short file */
- {
- if (len < 12) {
- printf("Fatal: %s is too short to be a multiboot file.",
- filename);
- exit(1);
- }
- } else {
- printf("Fatal: read error in %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- }
-
- /* Sanity-check: is this file compressed? */
- if ((headerbuf[0] == '\037' &&
- (headerbuf[1] == '\235' /* .Z */ ||
- headerbuf[1] == '\213' /* .gz */)) ||
- (headerbuf[0] == 'B' && headerbuf[1] == 'Z') /* .bz[2] */) {
- printf("Warning: %s looks like a compressed file.\n"
- " You should uncompress it first!\n", filename);
- }
-
- /* Now look for a multiboot header */
- for (i = 0; i <= MIN(len - 12, MULTIBOOT_SEARCH - 12); i += 4)
- {
- mbh = (struct multiboot_header *)(headerbuf + i);
- if (eswap(mbh->magic) != MULTIBOOT_MAGIC
- || ((eswap(mbh->magic)+eswap(mbh->flags)+eswap(mbh->checksum))
- & 0xffffffff))
- {
- /* Not a multiboot header */
- continue;
- }
- if (eswap(mbh->flags) & MULTIBOOT_UNSUPPORTED) {
- /* Requires options we don't support */
- printf("Fatal: found a multiboot header, but it "
- "requires multiboot options that I\n"
- "don't understand. Sorry.\n");
- exit(1);
- }
- if (eswap(mbh->flags) & MULTIBOOT_VIDEO_MODE) {
- /* Asked for screen mode information */
- /* XXX carry on regardless */
- printf("Warning: found a multiboot header which asks "
- "for screen mode information.\n"
- " This kernel will NOT be given valid"
- "screen mode information at boot time.\n");
- }
- /* This kernel will do: place and load it */
-
- if (eswap(mbh->flags) & MULTIBOOT_AOUT_KLUDGE) {
-
- /* Load using the offsets in the multiboot header */
- if(!quiet)
- printf("Loading %s using multiboot header.\n", filename);
-
- /* How much is there? */
- start = eswap(mbh->load_addr);
- if (eswap(mbh->load_end_addr) != 0)
- loadsize = eswap(mbh->load_end_addr) - eswap(mbh->load_addr);
- else
- loadsize = sb.st_size;
-
- /* How much memory will it take up? */
- if (eswap(mbh->bss_end_addr) != 0)
- size = eswap(mbh->bss_end_addr) - eswap(mbh->load_addr);
- else
- size = loadsize;
-
- if (loadsize > size) {
- printf("Fatal: can't load %i bytes of kernel into %i bytes "
- "of memory.\n", loadsize, size);
- exit(1);
- }
-
- /* Does it fit where it wants to be? */
- place_kernel_section(start, size);
-
- /* Load the kernel */
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for kernel load failed: %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fread(buffer, loadsize, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- filename, strerror(errno));
- exit(1);
- }
- fclose(fp);
-
- /* Clear the kernel BSS */
- memset(buffer + loadsize, 0, size - loadsize);
-
- /* Start off the linked list of sections */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = NULL;
- sections = sec;
- last_section = sec;
-
- /* Done. */
- if (!quiet) printf("Loaded kernel from %s\n", filename);
- return eswap(mbh->entry_addr);
-
- } else {
-
- /* Now look for an ELF32 header */
- ehdr = (Elf32_Ehdr *)headerbuf;
- if (*(unsigned long *)ehdr != eswap(0x464c457f)
- || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
- || ehdr->e_ident[EI_CLASS] != ELFCLASS32
- || eswap(ehdr->e_machine) != EM_386)
- {
- printf("Fatal: kernel has neither ELF32/x86 nor multiboot load"
- " headers.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phoff) + eswap(ehdr->e_phnum)*sizeof(*phdr)
- > HEADERBUF_SIZE) {
- /* Don't expect this will happen with sane kernels */
- printf("Fatal: too much ELF for me. Try increasing "
- "HEADERBUF_SIZE in mbootpack.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phoff) + eswap(ehdr->e_phnum)*sizeof (*phdr)
- > len) {
- printf("Fatal: malformed ELF header overruns EOF.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phnum) <= 0) {
- printf("Fatal: ELF kernel has no program headers.\n");
- exit(1);
- }
-
- if(!quiet)
- printf("Loading %s using ELF header.\n", filename);
-
- if (eswap(ehdr->e_type) != ET_EXEC
- || eswap(ehdr->e_version) != EV_CURRENT
- || eswap(ehdr->e_phentsize) != sizeof (Elf32_Phdr)) {
- printf("Warning: funny-looking ELF header.\n");
- }
- phdr = (Elf32_Phdr *)(headerbuf + eswap(ehdr->e_phoff));
-
- /* Obey the program headers to load the kernel */
- for(i = 0; i < eswap(ehdr->e_phnum); i++) {
-
- start = eswap(phdr[i].p_paddr);
- size = eswap(phdr[i].p_memsz);
- if (eswap(phdr[i].p_type) != PT_LOAD)
- loadsize = 0;
- else
- loadsize = MIN((long int)eswap(phdr[i].p_filesz), size);
-
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for kernel load failed: %s\n",
- strerror(errno));
- exit(1);
- }
-
- /* Place the section where it wants to be */
- place_kernel_section(start, size);
-
- /* Load section from file */
- if (loadsize > 0) {
- if (fseek(fp, eswap(phdr[i].p_offset), SEEK_SET) != 0) {
- printf("Fatal: seek failed in %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fread(buffer, loadsize, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- filename, strerror(errno));
- exit(1);
- }
- }
-
- /* Clear the rest of the buffer */
- memset(buffer + loadsize, 0, size - loadsize);
-
- /* Add this section to the list (keeping it ordered) */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
-
- for(s = sections; s; s = s->next) {
- if (s->start > start) {
- sec->next = s;
- if (s->prev == NULL) {
- /* sec becomes the new first item */
- s->prev = sec;
- sections = sec;
- } else {
- /* sec goes between s->prev and s */
- sec->prev = s->prev;
- sec->prev->next = sec;
- s->prev = sec;
- }
- break;
- }
- }
- if (s == NULL) {
- /* sec becomes the new last item */
- sec->next = NULL;
- sec->prev = last_section;
- if (last_section) {
- last_section->next = sec;
- } else {
- sections = sec;
- }
- last_section = sec;
- }
- }
-
- /* Done! */
- if (!quiet) printf("Loaded kernel from %s\n", filename);
- return eswap(ehdr->e_entry);
- }
-
- }
-
- /* This is not a multiboot kernel */
- printf("Fatal: %s is not a multiboot kernel.\n", filename);
- exit(1);
-}
-
-
-
-
-int main(int argc, char **argv)
-{
- char *buffer, *imagename, *command_line, *p;
- char *mod_filename, *mod_command_line, *mod_clp;
- char *out_filename;
- section_t *sec;
- FILE *fp;
- struct stat sb;
- struct multiboot_info *mbi;
- struct mod_list *modp;
- address_t start, kernel_entry;
- long int size, mod_command_line_space, command_line_len;
- int modules, opt, mbi_reloc_offset, make_multiboot;
-
- static const char short_options[] = "hc:m:o:qM";
- static const struct option options[] = {
- { "help", 0, 0, 'h' },
- { "command-line", 1, 0, 'c' },
- { "append", 1, 0, 'c' },
- { "module", 1, 0, 'm' },
- { "output", 1, 0, 'o' },
- { "quiet", 0, 0, 'q' },
- { 0, 0, 0, 0 },
- };
-
- /* Parse the command line */
- out_filename = NULL;
- command_line = "";
- command_line_len = 0;
- modules = 0;
- mod_command_line_space = 0;
- while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1)
- {
- switch(opt) {
- case 'c':
- command_line = optarg;
- break;
- case 'm':
- modules++;
- mod_command_line_space += strlen(optarg) + 1;
- break;
- case 'o':
- out_filename = optarg;
- break;
- case 'q':
- quiet = 1;
- break;
- case 'h':
- case '?':
- default:
- usage();
- }
- }
- imagename = argv[optind];
- if (!imagename || strlen(imagename) == 0) usage();
- command_line_len = strlen(command_line) + strlen(imagename) + 2;
- /* Leave space to overwritethe command-line at boot time */
- command_line_len = MAX(command_line_len, CMD_LINE_SPACE);
- if (!out_filename) out_filename = "bzImage";
-
- /* Place and load the kernel */
- kernel_entry = load_kernel(imagename);
- assert(sections != NULL);
- assert(last_section != NULL);
- assert(next_free_space != 0);
-
- /* Next section is all the metadata between kernel and modules */
- size = ((((sizeof (struct multiboot_info)
- + command_line_len
- + strlen(version_string) + 1
- + mod_command_line_space)
- + 3 ) & ~3)
- + modules * sizeof (struct mod_list));
- /* Locate this section after the setup sectors, in *low* memory */
- start = place_mbi(size);
-
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for boot metadata failed: %s\n",
- strerror(errno));
- exit(1);
- }
-
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = last_section;
- last_section->next = sec;
- last_section = sec;
-
- /* Multiboot info struct */
- mbi = (struct multiboot_info *)buffer;
- memset(buffer, 0, sizeof (struct multiboot_info));
- mbi_reloc_offset = start - (address_t)buffer;
-
- /* Command line */
- p = (char *)(mbi + 1);
- sprintf(p, "%s %s", imagename, command_line);
- mbi->cmdline = eswap(((address_t)p) + mbi_reloc_offset);
- p += command_line_len;
-
- /* Bootloader ID */
- sprintf(p, version_string);
- mbi->boot_loader_name = eswap(((address_t)p) + mbi_reloc_offset);
- p += strlen(version_string) + 1;
-
- /* Next is space for the module command lines */
- mod_clp = p;
-
- /* Last come the module info structs */
- modp = (struct mod_list *)
- ((((address_t)p + mod_command_line_space) + 3) & ~3);
- mbi->mods_count = eswap(modules);
- mbi->mods_addr = eswap(((address_t)modp) + mbi_reloc_offset);
-
- /* Memory information will be added at boot time, by setup.S
- * or trampoline.S. */
- mbi->flags = eswap(MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME);
-
-
- /* Load the modules */
- if (modules) {
- mbi->flags = eswap(eswap(mbi->flags) | MB_INFO_MODS);
-
- /* Go back and parse the module command lines */
- optind = opterr = 1;
- while((opt = getopt_long(argc, argv,
- short_options, options, 0)) != -1)
- {
- if (opt != 'm') continue;
-
- /* Split module filename from command line */
- mod_command_line = mod_filename = optarg;
- if ((p = strchr(mod_filename, ' ')) != NULL) {
- /* See as I discard the 'const' modifier */
- *p = '\0';
- }
-
- /* Find space for it */
- if (stat(mod_filename, &sb) != 0) {
- printf("Fatal: cannot stat %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- size = sb.st_size;
- start = place_section(size, X86_PAGE_SIZE);
- /* XXX should be place_section(size, 4) if the MBH hasn't got
- * XXX MULTIBOOT_PAGE_ALIGN set, but that breaks Xen */
-
- /* Load it */
- if ((buffer = malloc(sb.st_size)) == NULL) {
- printf("Fatal: malloc failed for module load: %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fp = fopen(mod_filename, "r")) == NULL) {
- printf("Fatal: cannot open %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- if ((fread(buffer, sb.st_size, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- fclose(fp);
-
- /* Sanity-check: is this file compressed? */
- if ((buffer[0] == '\037' &&
- (buffer[1] == '\235' /* .Z */ ||
- buffer[1] == '\213' /* .gz */)) ||
- (buffer[0] == 'B' && buffer[1] == 'Z') /* .bz[2] */) {
- printf("Warning: %s looks like a compressed file.\n",
- mod_filename);
- }
-
- if (!quiet) printf("Loaded module from %s\n", mod_filename);
-
- /* Restore the command line to its former glory */
- if (p != NULL) *p = ' ';
-
- /* Fill in the module info struct */
- modp->mod_start = eswap(start);
- modp->mod_end = eswap(start + size);
- modp->cmdline = eswap((address_t)mod_clp + mbi_reloc_offset);
- modp->pad = eswap(0);
- modp++;
-
- /* Store the module command line */
- sprintf(mod_clp, "%s", mod_command_line);
- mod_clp += strlen(mod_clp) + 1;
-
- /* Add the section to the list */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = last_section;
- last_section->next = sec;
- last_section = sec;
-
- }
-
- }
-
- /* Everything is placed and loaded. Now we package it all up
- * as a bzImage */
- if ((fp = fopen(out_filename, "w")) == NULL) {
- printf("Fatal: cannot open %s: %s\n", out_filename, strerror(errno));
- exit(1);
- }
- make_bzImage(sections,
- kernel_entry,
- ((address_t)mbi) + mbi_reloc_offset,
- fp);
- fclose(fp);
-
- /* Success! */
- if(!quiet) printf("Finished.\n");
- return 0;
-}
-
-/*
- * EOF (mbootpack.c)
- */
-
diff --git a/tools/misc/mbootpack/mbootpack.h b/tools/misc/mbootpack/mbootpack.h
deleted file mode 100644
index 20fe82a403..0000000000
--- a/tools/misc/mbootpack/mbootpack.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * mbootpack.h
- *
- * Common definitions for mbootpack
- *
- * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk)
- *
- * 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, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: mbootpack.h,v 1.2 2005/03/23 10:38:37 tjd21 Exp $
- *
- */
-
-#ifndef __MBOOTPACK__H__
-#define __MBOOTPACK__H__
-
-#ifndef __MB_ASM
-
-#undef NDEBUG
-#include <stdio.h>
-
-#include <endian.h>
-#include <byteswap.h>
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define eswap(x) (x)
-#else
-#define eswap(x) \
- ({ \
- typeof(x) y = (x); \
- switch(sizeof(y)) \
- { \
- case 2: y = __bswap_16(y); break; \
- case 4: y = __bswap_32(y); break; \
- case 8: y = __bswap_64(y); break; \
- } \
- y; \
- })
-#endif
-
-/* Flags */
-extern int quiet;
-
-/* Types */
-typedef unsigned long address_t;
-
-typedef struct section_t {
- char *buffer;
- address_t start;
- long int size;
- struct section_t *prev;
- struct section_t *next;
-} section_t;
-
-/* buildimage.c */
-extern void make_bzImage(section_t *sections,
- address_t entry,
- address_t mbi,
- FILE *fp);
-
-address_t place_mbi(long int size);
-
-
-/* trampoline.S */
-extern unsigned char mb_trampoline[];
-extern unsigned char mb_trampoline_end[];
-extern volatile address_t mb_mbi_address, mb_entry_address;
-
-/* Macros */
-#define MIN(_x,_y) (((_x)<=(_y))?(_x):(_y))
-#define MAX(_x,_y) (((_x)<=(_y))?(_y):(_x))
-#define ROUNDUP_P2(_x, _a) (((_x)+((_a)-1))&(~((_a)-1)))
-
-#endif
-
-/* x86 memory: such fun */
-#define MEM_HOLE_START 0xa0000
-#define MEM_HOLE_END 0x100000
-#define HIGHMEM_START MEM_HOLE_END
-#define X86_PAGE_SIZE 0x1000
-
-/* How much command line we'll take from the bootloader. */
-#define CMD_LINE_SPACE 0x300
-
-/* Number of 512-byte sectors to load in low memory (max 7) */
-#define SETUPSECTS 7
-
-
-/* Who are we? */
-#define MBOOTPACK_VERSION_STRING "v0.2 (alpha)"
-
-#endif /* __MBOOTPACK__H__ */
-
-/*
- * EOF (mbootpack.h)
- */
-
diff --git a/tools/misc/mbootpack/setup.S b/tools/misc/mbootpack/setup.S
deleted file mode 100644
index f429312df6..0000000000
--- a/tools/misc/mbootpack/setup.S
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * bootsect.S
- *
- * This is setup.S from the linux 2.6.9 source code,
- * with heavy cuts and changes for mbootpack
- * November 2004 Tim Deegan <tjd21@cl.cam.ac.uk>
- *
- *
- * 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, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: setup.S,v 1.4 2005/03/23 10:39:03 tjd21 Exp $
- *
- */
-
-#include "mbootpack.h"
-
-/*
- * setup.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * This code asks the bios for memory/disk/other parameters, and
- * puts them in a "safe" place: 0x90000-0x901FF, ie where the
- * boot-block used to be. It is then up to the protected mode
- * system to read them from there before the area is overwritten
- * for buffer-blocks.
- *
- * Move PS/2 aux init code to psaux.c
- * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
- *
- * some changes and additional features by Christoph Niemann,
- * March 1993/June 1994 (Christoph.Niemann@linux.org)
- *
- * add APM BIOS checking by Stephen Rothwell, May 1994
- * (sfr@canb.auug.org.au)
- *
- * High load stuff, initrd support and position independency
- * by Hans Lermen & Werner Almesberger, February 1996
- * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
- *
- * Video handling moved to video.S by Martin Mares, March 1996
- * <mj@k332.feld.cvut.cz>
- *
- * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
- * parsons) to avoid loadlin confusion, July 1997
- *
- * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
- * <stiker@northlink.com>
- *
- * Fix to work around buggy BIOSes which dont use carry bit correctly
- * and/or report extended memory in CX/DX for e801h memory size detection
- * call. As a result the kernel got wrong figures. The int15/e801h docs
- * from Ralf Brown interrupt list seem to indicate AX/BX should be used
- * anyway. So to avoid breaking many machines (presumably there was a reason
- * to orginally use CX/DX instead of AX/BX), we do a kludge to see
- * if CX/DX have been changed in the e801 call and if so use AX/BX .
- * Michael Miller, April 2001 <michaelm@mjmm.org>
- *
- * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
- * by Robert Schwebel, December 2001 <robert@schwebel.de>
- */
-
-/*
-#include <linux/config.h>
-#include <asm/segment.h>
-#include <linux/version.h>
-#include <linux/compile.h>
-#include <asm/boot.h>
-#include <asm/e820.h>
-#include <asm/page.h>
-*/
-
-/* Definitions that should have come from these includes */
-#define DEF_INITSEG 0x9000
-#define DEF_SYSSEG 0x1000
-#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x7F00
-#define NORMAL_VGA 0xffff
-#define EXTENDED_VGA 0xfffe
-#define ASK_VGA 0xfffd
-#define GDT_ENTRY_BOOT_CS 2
-#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8)
-#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1)
-#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8)
-#define __PAGE_OFFSET (0xC0000000)
-#define E820MAP 0x2d0 /* our map */
-#define E820MAX 32 /* number of entries in E820MAP */
-#define E820NR 0x1e8 /* # entries in E820MAP */
-#define E820_RAM 1
-#define E820_RESERVED 2
-#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
-#define E820_NVS 4
-#define __BIG_KERNEL__
-
-
-/* Signature words to ensure LILO loaded us right */
-#define SIG1 0xAA55
-#define SIG2 0x5A5A
-
-INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
-SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
- # ... and the former contents of CS
-
-DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
-
-.code16
-.globl _start, begtext, begdata, begbss, endtext, enddata, endbss
-
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-_start:
-start:
- jmp trampoline
-
-# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
-
- .ascii "HdrS" # header signature
- .word 0x0203 # header version number (>= 0x0105)
- # or else old loadlin-1.5 will fail)
-realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
-start_sys_seg: .word SYSSEG
- .word kernel_version # pointing to kernel version string
- # above section of header is compatible
- # with loadlin-1.5 (header v1.5). Don't
- # change it.
-
-type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
- # Bootlin, SYSLX, bootsect...)
- # See Documentation/i386/boot.txt for
- # assigned ids
-
-# flags, unused bits must be zero (RFU) bit within loadflags
-loadflags:
-LOADED_HIGH = 1 # If set, the kernel is loaded high
-CAN_USE_HEAP = 0x80 # If set, the loader also has set
- # heap_end_ptr to tell how much
- # space behind setup.S can be used for
- # heap purposes.
- # Only the loader knows what is free
-#ifndef __BIG_KERNEL__
- .byte 0
-#else
- .byte LOADED_HIGH
-#endif
-
-setup_move_size: .word 0x8000 # size to move, when setup is not
- # loaded at 0x90000. We will move setup
- # to 0x90000 then just before jumping
- # into the kernel. However, only the
- # loader knows how much data behind
- # us also needs to be loaded.
-
-/* N.B. these next addresses are entirely ignored by this code -- it
- * assumes it was loaded with the 32bit code at 0x100000, and doesn't
- * touch the ramdisk. */
-code32_start: # here loaders can put a different
- # start address for 32-bit code.
-#ifndef __BIG_KERNEL__
- .long 0x1000 # 0x1000 = default for zImage
-#else
- .long 0x100000 # 0x100000 = default for big kernel
-#endif
-
-ramdisk_image: .long 0 # address of loaded ramdisk image
- # Here the loader puts the 32-bit
- # address where it loaded the image.
- # This only will be read by the kernel.
-
-ramdisk_size: .long 0 # its size in bytes
-
-bootsect_kludge:
- .long 0 # obsolete
-
-heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
- # space from here (exclusive) down to
- # end of setup code can be used by setup
- # for local heap purposes.
-
-pad1: .word 0
-cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
- # If nonzero, a 32-bit pointer
- # to the kernel command line.
- # The command line should be
- # located between the start of
- # setup and the end of low
- # memory (0xa0000), or it may
- # get overwritten before it
- # gets read. If this field is
- # used, there is no longer
- # anything magical about the
- # 0x90000 segment; the setup
- # can be located anywhere in
- # low memory 0x10000 or higher.
-
-ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
- # (Header version 0x0203 or later)
- # The highest safe address for
- # the contents of an initrd
-
-/* Add more known locations: the image builder will overwrite
- * these with the entry point and MBI location for the multiboot kernel.
- * These offsets *must* match the definitions in buildimage.c */
-
-entry_address: .long 0 # This will be offset 0x30 (0x230 from b'sect)
-mbi_address: .long 0 # This will be offset 0x34
-
-/* Storage space for the size of memory */
-highmem_size: .long 0
-
-trampoline: call start_of_setup
- .space 1024
-# End of setup header #####################################################
-
-start_of_setup:
-# Bootlin depends on this being done early
- movw $0x01500, %ax
- movb $0x81, %dl
- int $0x13
-
-#ifdef SAFE_RESET_DISK_CONTROLLER
-# Reset the disk controller.
- movw $0x0000, %ax
- movb $0x80, %dl
- int $0x13
-#endif
-
-# Set %ds = %cs, we know that SETUPSEG = %cs at this point
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-
-# Check signature at end of setup
- cmpw $SIG1, setup_sig1
- jne bad_sig
-
- cmpw $SIG2, setup_sig2
- jne bad_sig
-
- jmp good_sig1
-
-# Routine to print asciiz string at ds:si
-prtstr:
- lodsb
- andb %al, %al
- jz fin
-
- call prtchr
- jmp prtstr
-
-fin: ret
-
-# Space printing
-prtsp2: call prtspc # Print double space
-prtspc: movb $0x20, %al # Print single space (note: fall-thru)
-
-# Part of above routine, this one just prints ascii al
-prtchr: pushw %ax
- pushw %cx
- movw $7,%bx
- movw $0x01, %cx
- movb $0x0e, %ah
- int $0x10
- popw %cx
- popw %ax
- ret
-
-beep: movb $0x07, %al
- jmp prtchr
-
-no_sig_mess: .string "No setup signature found ..."
-
-good_sig1:
- jmp good_sig
-
-# We now have to find the rest of the setup code/data
-bad_sig:
- movw %cs, %ax # SETUPSEG
- subw $DELTA_INITSEG, %ax # INITSEG
- movw %ax, %ds
- xorb %bh, %bh
- movb (497), %bl # get setup sect from bootsect
- subw $4, %bx # LILO loads 4 sectors of setup
- shlw $8, %bx # convert to words (1sect=2^8 words)
- movw %bx, %cx
- shrw $3, %bx # convert to segment
- addw $SYSSEG, %bx
- movw %bx, %cs:start_sys_seg
-# Move rest of setup code/data to here
- movw $2048, %di # four sectors loaded by LILO
- subw %si, %si
- pushw %cs
- popw %es
- movw $SYSSEG, %ax
- movw %ax, %ds
- rep
- movsw
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
- cmpw $SIG1, setup_sig1
- jne no_sig
-
- cmpw $SIG2, setup_sig2
- jne no_sig
-
- jmp good_sig
-
-no_sig:
- lea no_sig_mess, %si
- call prtstr
-
-no_sig_loop:
- hlt
- jmp no_sig_loop
-
-mb_hello_mess1:
- .string "mboot"
-
-good_sig:
- lea mb_hello_mess1, %si
- call prtstr
-
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
-# Check if an old loader tries to load a big-kernel
- testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
- jz loader_ok # No, no danger for old loaders.
-
- cmpb $0, %cs:type_of_loader # Do we have a loader that
- # can deal with us?
- jnz loader_ok # Yes, continue.
-
- pushw %cs # No, we have an old loader,
- popw %ds # die.
- lea loader_panic_mess, %si
- call prtstr
-
- jmp no_sig_loop
-
-loader_panic_mess: .string "Wrong loader, giving up..."
-
-loader_ok:
-
-# Get memory size (extended mem, kB)
-
-/* We'll be storing this in highmem_size, to be copied to the mbi */
-
-# Try three different memory detection schemes. First, try
-# e820h, which lets us assemble a memory map, then try e801h,
-# which returns a 32-bit memory size, and finally 88h, which
-# returns 0-64m
-
- xorl %edx, %edx
- xorl %eax, %eax
- movl %eax, (0x1e0)
- movl %eax, highmem_size
- movb %al, (E820NR)
-
-# method E820H:
-# the memory map from hell. e820h returns memory classified into
-# a whole bunch of different types, and allows memory holes and
-# everything. We scan through this memory map and build a list
-# of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
-
-#define SMAP 0x534d4150
-
-meme820:
- xorl %ebx, %ebx # continuation counter
- movw $E820MAP, %di # point into the whitelist
- # so we can have the bios
- # directly write into it.
-
-jmpe820:
- movl $0x0000e820, %eax # e820, upper word zeroed
- movl $SMAP, %edx # ascii 'SMAP'
- movl $20, %ecx # size of the e820rec
- pushw %ds # data record.
- popw %es
- int $0x15 # make the call
- jc bail820 # fall to e801 if it fails
-
- cmpl $SMAP, %eax # check the return is `SMAP'
- jne bail820 # fall to e801 if it fails
-
-# cmpl $1, 16(%di) # is this usable memory?
-# jne again820
-
- # If this is usable memory, we save it by simply advancing %di by
- # sizeof(e820rec).
- #
-good820:
- movb (E820NR), %al # up to 32 entries
- cmpb $E820MAX, %al
- jnl bail820
-
- incb (E820NR)
- movw %di, %ax
- addw $20, %ax
- movw %ax, %di
-again820:
- cmpl $0, %ebx # check to see if
- jne jmpe820 # %ebx is set to EOF
-
-/* Multiboot spec says high mem should be the address of the first
- * upper memory hole, minus 1 MB */
- xorl %ebx, %ebx
- xorl %ecx, %ecx
- xorl %edx, %edx
- movw $E820MAP, %di # Start at the beginning
-calc_highmem_loop:
- cmpl $1, 16(%di) # is it usable memory?
- jnz calc_highmem_next
- cmpl $0, 4(%di) # is base < 4GB?
- jnz calc_highmem_next
- cmpl $0x100000, 0(%di) # is base <= 1MB?
- jg calc_highmem_next
- movl 8(%di), %ecx # Calculate base+length
- shrl $10, %ecx # in kilobytes
- movl 12(%di), %edx
- shll $22, %edx
- orl %edx, %ecx
- movl 0(%di), %edx
- shrl $10, %edx
- addl %edx, %ecx
- subl $1024, %ecx # - 1 MB
- cmpl %cs:highmem_size, %ecx
- jl calc_highmem_next
- movl %ecx, %cs:highmem_size
-calc_highmem_next:
- add $1, %bl
- add $20, %di
- cmp %bl, (E820NR)
- je calc_highmem_done
- jmp calc_highmem_loop
-calc_highmem_done:
-
-bail820:
-
-# method E801H:
-# memory size is in 1k chunksizes, to avoid confusing loadlin.
-
-meme801:
- stc # fix to work around buggy
- xorw %cx,%cx # BIOSes which dont clear/set
- xorw %dx,%dx # carry on pass/error of
- # e801h memory size call
- # or merely pass cx,dx though
- # without changing them.
- movw $0xe801, %ax
- int $0x15
- jc mem88
-
- cmpw $0x0, %cx # Kludge to handle BIOSes
- jne e801usecxdx # which report their extended
- cmpw $0x0, %dx # memory in AX/BX rather than
- jne e801usecxdx # CX/DX. The spec I have read
- movw %ax, %cx # seems to indicate AX/BX
- movw %bx, %dx # are more reasonable anyway...
-
-e801usecxdx:
- andl $0xffff, %edx # clear sign extend
- shll $6, %edx # and go from 64k to 1k chunks
- andl $0xffff, %ecx # clear sign extend
- addl %ecx, %edx
-
- cmpl %cs:highmem_size, %edx # store extended mem size
- jl mem88 # if it's bigger than
- movl %edx, %cs:highmem_size # what we already have
-
-# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
-# 64mb, depending on the bios) in ax.
-mem88:
- movb $0x88, %ah
- int $0x15
-
- andl $0xffff, %eax # clear sign extend
- cmpl %cs:highmem_size, %eax # store extended mem size
- jl have_memsize # if it's bigger than
- movl %eax, %cs:highmem_size # what we already have
-
-have_memsize:
-
-/* Culled: HDD probes, APM, speedstep */
-
-# Now we want to move to protected mode ...
- cmpw $0, %cs:realmode_swtch
- jz rmodeswtch_normal
-
- lcall *%cs:realmode_swtch
-
- jmp rmodeswtch_end
-
-rmodeswtch_normal:
- pushw %cs
- call default_switch
-
-rmodeswtch_end:
-
-/* Culled: code to take the 32bit entry address from the loader */
-/* Culled: code to relocate non-bzImage kernels */
-
- # then we load the segment descriptors
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-
-# Check whether we need to be downward compatible with version <=201
- cmpl $0, cmd_line_ptr
- jne end_move_self # loader uses version >=202 features
- cmpb $0x20, type_of_loader
- je end_move_self # bootsect loader, we know of it
-
-# Boot loader doesnt support boot protocol version 2.02.
-# If we have our code not at 0x90000, we need to move it there now.
-# We also then need to move the params behind it (commandline)
-# Because we would overwrite the code on the current IP, we move
-# it in two steps, jumping high after the first one.
- movw %cs, %ax
- cmpw $SETUPSEG, %ax
- je end_move_self
-
- cli # make sure we really have
- # interrupts disabled !
- # because after this the stack
- # should not be used
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ss, %dx
- cmpw %ax, %dx
- jb move_self_1
-
- addw $INITSEG, %dx
- subw %ax, %dx # this will go into %ss after
- # the move
-move_self_1:
- movw %ax, %ds
- movw $INITSEG, %ax # real INITSEG
- movw %ax, %es
- movw %cs:setup_move_size, %cx
- std # we have to move up, so we use
- # direction down because the
- # areas may overlap
- movw %cx, %di
- decw %di
- movw %di, %si
- subw $move_self_here+0x200, %cx
- rep
- movsb
- ljmp $SETUPSEG, $move_self_here
-
-move_self_here:
- movw $move_self_here+0x200, %cx
- rep
- movsb
- movw $SETUPSEG, %ax
- movw %ax, %ds
- movw %dx, %ss
-end_move_self: # now we are at the right place
-
-#
-# Enable A20. This is at the very best an annoying procedure.
-# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
-# AMD Elan bug fix by Robert Schwebel.
-#
-
-#if defined(CONFIG_X86_ELAN)
- movb $0x02, %al # alternate A20 gate
- outb %al, $0x92 # this works on SC410/SC520
-a20_elan_wait:
- call a20_test
- jz a20_elan_wait
- jmp a20_done
-#endif
-
-
-A20_TEST_LOOPS = 32 # Iterations per wait
-A20_ENABLE_LOOPS = 255 # Total loops to try
-
-
-#ifndef CONFIG_X86_VOYAGER
-a20_try_loop:
-
- # First, see if we are on a system with no A20 gate.
-a20_none:
- call a20_test
- jnz a20_done
-
- # Next, try the BIOS (INT 0x15, AX=0x2401)
-a20_bios:
- movw $0x2401, %ax
- pushfl # Be paranoid about flags
- int $0x15
- popfl
-
- call a20_test
- jnz a20_done
-
- # Try enabling A20 through the keyboard controller
-#endif /* CONFIG_X86_VOYAGER */
-a20_kbc:
- call empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
- call a20_test # Just in case the BIOS worked
- jnz a20_done # but had a delayed reaction.
-#endif
-
- movb $0xD1, %al # command write
- outb %al, $0x64
- call empty_8042
-
- movb $0xDF, %al # A20 on
- outb %al, $0x60
- call empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
- # Wait until a20 really *is* enabled; it can take a fair amount of
- # time on certain systems; Toshiba Tecras are known to have this
- # problem.
-a20_kbc_wait:
- xorw %cx, %cx
-a20_kbc_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_kbc_wait_loop
-
- # Final attempt: use "configuration port A"
-a20_fast:
- inb $0x92, %al # Configuration Port A
- orb $0x02, %al # "fast A20" version
- andb $0xFE, %al # don't accidentally reset
- outb %al, $0x92
-
- # Wait for configuration port A to take effect
-a20_fast_wait:
- xorw %cx, %cx
-a20_fast_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_fast_wait_loop
-
- # A20 is still not responding. Try frobbing it again.
- #
- decb (a20_tries)
- jnz a20_try_loop
-
- movw $a20_err_msg, %si
- call prtstr
-
-a20_die:
- hlt
- jmp a20_die
-
-a20_tries:
- .byte A20_ENABLE_LOOPS
-
-a20_err_msg:
- .ascii "linux: fatal error: A20 gate not responding!"
- .byte 13, 10, 0
-
- # If we get here, all is good
-a20_done:
-
-
-#endif /* CONFIG_X86_VOYAGER */
-
-/* Another print, to show protected mode and A20 are OK */
-
- jmp mb_hello_mess2_end
-mb_hello_mess2:
- .string "pack "
-mb_hello_mess2_end:
- lea mb_hello_mess2, %si
- call prtstr
-
-# set up gdt and idt
-/* lidt idt_48 # load idt with 0,0 */
-/* Multiboot kernels must set up their own IDT: leave this for now,
- * so we can print diagnostics */
-
- xorl %eax, %eax # Compute gdt_base
- movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
- shll $4, %eax
- addl $gdt, %eax
- movl %eax, (gdt_48+2)
- lgdt gdt_48 # load gdt with whatever is
- # appropriate
-
-# make sure any possible coprocessor is properly reset..
- xorw %ax, %ax
- outb %al, $0xf0
- call delay
-
- outb %al, $0xf1
- call delay
-
-
-# well, that went ok, I hope. Now we mask all interrupts - the rest
-# is done in init_IRQ().
- movb $0xFF, %al # mask all interrupts for now
- outb %al, $0xA1
- call delay
-
- movb $0xFB, %al # mask all irq's but irq2 which
- outb %al, $0x21 # is cascaded
-
-# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-# need no steenking BIOS anyway (except for the initial loading :-).
-# The BIOS-routine wants lots of unnecessary data, and it's less
-# "interesting" anyway. This is how REAL programmers do it.
-
-/* Tailor the jump below so the target is the 32bit trampoline code */
-
- xorl %eax, %eax # Calculate
- movw %cs, %ax # the linear
- shll $4, %eax # address of
- addl $trampoline32, %eax # %cs:trampoline32
- movl %eax, %cs:code32 # Stick it into the jmpi
-
- /* Load a 32-bit pointer to the entry address into %ecx */
- xorl %ecx, %ecx # Calculate
- movw %cs, %cx # the linear
- shll $4, %ecx # address of
- addl $entry_address, %ecx # %cs:entry_address
-
-# Well, now's the time to actually move into protected mode.
-
- lea mb_ready_mess, %si
- call prtstr
-
-/* May as well load this IDT now */
- lidt idt_48
-
- xorl %eax, %eax
- movw $1, %ax # protected mode (PE) bit
- lmsw %ax # This is it!
- jmp flush_instr
-flush_instr:
-
- /* Set up segment registers */
- movw $__BOOT_DS, %dx
- movw %dx, %ds
- movw %dx, %es
- movw %dx, %fs
- movw %dx, %gs
- movw %dx, %ss
-
- /* Trampoline expects this in %eax */
- movl %ecx, %eax
-
- /* Jump to the 32-bit trampoline */
-
-# NOTE: For high loaded big kernels we need a
-# jmpi 0x100000,__BOOT_CS
-#
-# but we yet haven't reloaded the CS register, so the default size
-# of the target offset still is 16 bit.
-# However, using an operand prefix (0x66), the CPU will properly
-# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
-# Manual, Mixing 16-bit and 32-bit code, page 16-6)
-
- .byte 0x66, 0xea # prefix + jmpi-opcode
-code32: .long 0x1000 # will be set to trampoline32
- # by code above.
- .word __BOOT_CS
-
-# Here's a bunch of information about your current kernel..
-
-kernel_version: .string "mbootpack changeling bzImage"
-mb_ready_mess:
- .ascii MBOOTPACK_VERSION_STRING
- .ascii "\r\n"
- .byte 0
-
-# This is the default real mode switch routine.
-# to be called just before protected mode transition
-default_switch:
- cli # no interrupts allowed !
- movb $0x80, %al # disable NMI for bootup
- # sequence
- outb %al, $0x70
- lret
-
-
-#ifndef CONFIG_X86_VOYAGER
-# This routine tests whether or not A20 is enabled. If so, it
-# exits with zf = 0.
-#
-# The memory address used, 0x200, is the int $0x80 vector, which
-# should be safe.
-
-A20_TEST_ADDR = 4*0x80
-
-a20_test:
- pushw %cx
- pushw %ax
- xorw %cx, %cx
- movw %cx, %fs # Low memory
- decw %cx
- movw %cx, %gs # High memory area
- movw $A20_TEST_LOOPS, %cx
- movw %fs:(A20_TEST_ADDR), %ax
- pushw %ax
-a20_test_wait:
- incw %ax
- movw %ax, %fs:(A20_TEST_ADDR)
- call delay # Serialize and make delay constant
- cmpw %gs:(A20_TEST_ADDR+0x10), %ax
- loope a20_test_wait
-
- popw %fs:(A20_TEST_ADDR)
- popw %ax
- popw %cx
- ret
-
-#endif /* CONFIG_X86_VOYAGER */
-
-# This routine checks that the keyboard command queue is empty
-# (after emptying the output buffers)
-#
-# Some machines have delusions that the keyboard buffer is always full
-# with no keyboard attached...
-#
-# If there is no keyboard controller, we will usually get 0xff
-# to all the reads. With each IO taking a microsecond and
-# a timeout of 100,000 iterations, this can take about half a
-# second ("delay" == outb to port 0x80). That should be ok,
-# and should also be plenty of time for a real keyboard controller
-# to empty.
-#
-
-empty_8042:
- pushl %ecx
- movl $100000, %ecx
-
-empty_8042_loop:
- decl %ecx
- jz empty_8042_end_loop
-
- call delay
-
- inb $0x64, %al # 8042 status port
- testb $1, %al # output buffer?
- jz no_output
-
- call delay
- inb $0x60, %al # read it
- jmp empty_8042_loop
-
-no_output:
- testb $2, %al # is input buffer full?
- jnz empty_8042_loop # yes - loop
-empty_8042_end_loop:
- popl %ecx
- ret
-
-# Read the cmos clock. Return the seconds in al
-gettime:
- pushw %cx
- movb $0x02, %ah
- int $0x1a
- movb %dh, %al # %dh contains the seconds
- andb $0x0f, %al
- movb %dh, %ah
- movb $0x04, %cl
- shrb %cl, %ah
- aad
- popw %cx
- ret
-
-# Delay is needed after doing I/O
-delay:
- outb %al,$0x80
- ret
-
-# Descriptor tables
-#
-# NOTE: The intel manual says gdt should be sixteen bytes aligned for
-# efficiency reasons. However, there are machines which are known not
-# to boot with misaligned GDTs, so alter this at your peril! If you alter
-# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
-# empty GDT entries (one for NULL and one reserved).
-#
-# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
-# true for the Voyager Quad CPU card which will not boot without
-# This directive. 16 byte aligment is recommended by intel.
-#
-
-
-/* The boot-time code segment is set at the jmpi above */
-/* Dont change this without checking everything still matches */
-
- .align 16
-gdt:
- .fill GDT_ENTRY_BOOT_CS,8,0
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9A00 # code read/exec
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9200 # data read/write
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-gdt_end:
- .align 4
-
- .word 0 # alignment byte
-idt_48:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- .word 0 # alignment byte
-gdt_48:
- .word gdt_end - gdt - 1 # gdt limit
- .word 0, 0 # gdt base (filled in later)
-
-# Include video setup & detection code
-
-/* #include "video.S" */
-
-.code32
-trampoline32:
- /* Here, %eax = 32-bit pointer to entry_address */
-
- /* Check if the bootloader gave us a (non-empty) command line */
- movl -8(%eax), %ebx # cmd_line_ptr
- cmpl $0, %ebx
- je no_cmd_line
- cmpb $0, 0(%ebx)
- je no_cmd_line
-
- /* Find the MBI command line */
- movl %eax, %ecx # &entry_address
- addl $(begtext-entry_address), %ecx # --> start of setup
- subl $0x9200, %ecx # --> reloc offset
- movl %ecx, %esi # (copy offset)
- movl %ecx, %ebx # (copy offset)
- addl 4(%eax), %ecx # --> current addr of MBI
- addl 16(%ecx), %ebx # --> cur. addr of MB cmdline
-
- /* Overwrite the built-in MBI kernel command line */
- movl -8(%eax), %ecx
- movl $0, %edi
-
- /* Give the kernel a 'self' word, that linux doesn't get */
- movw $0x202E, 0(%ebx) # '. '
- addl $0x2, %ebx
-
-cmd_line_copy:
- movb (%ecx, %edi), %dl
- movb %dl, (%ebx, %edi)
- inc %edi
- cmp $CMD_LINE_SPACE-3, %edi
- je cmd_line_copy_end
-
- cmpb $0x0, %dl
- jne cmd_line_copy
-cmd_line_copy_end:
- movb $0x0, (%ebx, %edi)
- subl $0x2, %ebx
-
- /* Look for '--' in the kernel command line */
-cmd_line_scan:
- inc %ebx
- cmpb $0x0, 0(%ebx)
- je no_cmd_line
- cmpl $0x202D2D20, 0(%ebx) # ' -- '
- jne cmd_line_scan
-
- /* Found it: terminate kernel's command line */
- movb $0x0, 0(%ebx)
- inc %ebx
- /* Relocate address to where it will be moved to */
- subl %esi, %ebx
-
- /* Is there a module 0? */
- movl %esi, %ecx # Reloc offset
- addl 4(%eax), %ecx # --> current addr of MBI
- cmpl $0x0, 20(%ecx) # (check module count)
- je no_cmd_line
- /* Overwrite module 0's command line */
- movl %esi, %edx # Reloc offset
- addl 24(%ecx), %edx # --> cur. add. of Module 0
- movl %ebx, 8(%edx) # --> blat mod. 0's cmdline
-no_cmd_line:
-
-
- /* Relocate the MBI from after the setup code to its proper home
- * between the MBI pointer and 0xa000 */
- movl %eax, %ecx # &entry_address
- addl $(begtext-entry_address), %ecx # --> start of setup
- subl $0x9200, %ecx # --> reloc offset
- addl 4(%eax), %ecx # --> current addr of MBI
-
- movl $0xa000, %ebx # End of MBI
- subl 4(%eax), %ebx # --> size of MBI
- movl %ebx, %edi
-
- movl 4(%eax), %ebx # Destination of MBI
-
-mbi_copy:
- dec %edi
- movb (%ecx, %edi), %dl
- movb %dl, (%ebx, %edi)
- cmp $0x0, %edi
- jne mbi_copy
-
- /* Copy memory size into MBI structure */
- movl 4(%eax), %ebx # MBI pointer
- movl 8(%eax), %ecx # highmem_size
- movl %ecx, 8(%ebx) # --> mbi.mem_upper
- movl $0x280, %ecx
- movl %ecx, 4(%ebx) # --> mbi.mem_lower
- /* Set the MB_INFO_MEMORY bit */
- orl $1, 0(%ebx)
-
- /* Recover the MBI pointer into %ebx */
- movl 4(%eax), %ebx # MBI pointer
- /* Extract the load address into %ecx */
- movl 0(%eax), %ecx
- /* Let the kernel know we're a multiboot loader */
- movl $0x2BADB002, %eax
- /* Jump to the kernel address supplied */
- jmp *%ecx
-
-# Setup signature -- must be last
-setup_sig1: .word SIG1
-setup_sig2: .word SIG2
-
-# After this point, there is some free space which is used by the video mode
-# handling code to store the temporary mode table (not used by the kernel).
-
-modelist:
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
diff --git a/tools/misc/miniterm/Makefile b/tools/misc/miniterm/Makefile
index 5b596a5f9f..1fe35f810c 100644
--- a/tools/misc/miniterm/Makefile
+++ b/tools/misc/miniterm/Makefile
@@ -1,10 +1,6 @@
XEN_ROOT:=../../..
include $(XEN_ROOT)/tools/Rules.mk
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
TARGET = miniterm
.PHONY: all
diff --git a/tools/misc/miniterm/miniterm.c b/tools/misc/miniterm/miniterm.c
index 92f8462781..3f8043da0b 100644
--- a/tools/misc/miniterm/miniterm.c
+++ b/tools/misc/miniterm/miniterm.c
@@ -32,10 +32,11 @@
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <string.h>
#define DEFAULT_BAUDRATE 115200
#define DEFAULT_SERDEVICE "/dev/ttyS0"
-#define ENDMINITERM 2 /* ctrl-b to quit miniterm */
+#define ENDMINITERM 0x1d
volatile int stop = 0;
@@ -76,7 +77,11 @@ int main(int argc, char **argv)
char *sername = DEFAULT_SERDEVICE;
struct termios oldsertio, newsertio, oldstdtio, newstdtio;
struct sigaction sa;
-
+ static char start_str[] =
+ "************ REMOTE CONSOLE: CTRL-] TO QUIT ********\r\n";
+ static char end_str[] =
+ "\n************ REMOTE CONSOLE EXITED *****************\n";
+
while ( --argc != 0 )
{
char *p = argv[argc];
@@ -121,7 +126,7 @@ int main(int argc, char **argv)
newsertio.c_iflag = IGNBRK | IGNPAR;
/* Raw output. */
- newsertio.c_oflag = 0;
+ newsertio.c_oflag = OPOST;
/* No echo and no signals. */
newsertio.c_lflag = 0;
@@ -137,7 +142,13 @@ int main(int argc, char **argv)
/* next stop echo and buffering for stdin */
tcgetattr(0,&oldstdtio);
tcgetattr(0,&newstdtio); /* get working stdtio */
- newstdtio.c_lflag &= ~(ICANON | ECHO);
+ newstdtio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ newstdtio.c_oflag &= ~OPOST;
+ newstdtio.c_cflag &= ~(CSIZE | PARENB);
+ newstdtio.c_cflag |= CS8;
+ newstdtio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ newstdtio.c_cc[VMIN]=1;
+ newstdtio.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&newstdtio);
/* Terminal settings done: now enter the main I/O loops. */
@@ -145,7 +156,7 @@ int main(int argc, char **argv)
{
case 0:
close(1); /* stdout not needed */
- for ( c = getchar(); c != ENDMINITERM ; c = getchar() )
+ for ( c = (char)getchar(); c != ENDMINITERM; c = (char)getchar() )
write(fd,&c,1);
tcsetattr(fd,TCSANOW,&oldsertio);
tcsetattr(0,TCSANOW,&oldstdtio);
@@ -158,7 +169,7 @@ int main(int argc, char **argv)
close(fd);
exit(-1);
default:
- printf("** ctrl-b quits miniterm **\n");
+ write(1, start_str, strlen(start_str));
close(0); /* stdin not needed */
sa.sa_handler = child_handler;
sa.sa_flags = 0;
@@ -166,9 +177,11 @@ int main(int argc, char **argv)
while ( !stop )
{
read(fd,&c,1); /* modem */
+ c = (char)c;
write(1,&c,1); /* stdout */
}
wait(NULL); /* wait for child to die or it will become a zombie */
+ write(1, end_str, strlen(end_str));
break;
}
diff --git a/tools/misc/xend b/tools/misc/xend
index ff58b30773..b0ee27f556 100644
--- a/tools/misc/xend
+++ b/tools/misc/xend
@@ -19,6 +19,9 @@
The daemon should reconnect to device control interfaces
and recover its state when restarted.
+
+ On Solaris, the daemons are SMF managed, and you should not attempt
+ to start xend by hand.
"""
import os
import os.path
@@ -108,9 +111,10 @@ def main():
if not sys.argv[1:]:
print 'usage: %s {start|stop|restart}' % sys.argv[0]
elif sys.argv[1] == 'start':
- start_xenstored()
- start_consoled()
- start_blktapctrl()
+ if os.uname()[0] != "SunOS":
+ start_xenstored()
+ start_consoled()
+ start_blktapctrl()
return daemon.start()
elif sys.argv[1] == 'trace_start':
start_xenstored()
diff --git a/tools/misc/xenperf.c b/tools/misc/xenperf.c
index 44fc3b445a..d970204242 100644
--- a/tools/misc/xenperf.c
+++ b/tools/misc/xenperf.c
@@ -10,7 +10,6 @@
* Description:
*/
-
#include <xenctrl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -18,14 +17,82 @@
#include <errno.h>
#include <string.h>
+#define X(name) [__HYPERVISOR_##name] = #name
+const char *hypercall_name_table[64] =
+{
+ X(set_trap_table),
+ X(mmu_update),
+ X(set_gdt),
+ X(stack_switch),
+ X(set_callbacks),
+ X(fpu_taskswitch),
+ X(sched_op_compat),
+ X(platform_op),
+ X(set_debugreg),
+ X(get_debugreg),
+ X(update_descriptor),
+ X(memory_op),
+ X(multicall),
+ X(update_va_mapping),
+ X(set_timer_op),
+ X(event_channel_op_compat),
+ X(xen_version),
+ X(console_io),
+ X(physdev_op_compat),
+ X(grant_table_op),
+ X(vm_assist),
+ X(update_va_mapping_otherdomain),
+ X(iret),
+ X(vcpu_op),
+ X(set_segment_base),
+ X(mmuext_op),
+ X(acm_op),
+ X(nmi_op),
+ X(sched_op),
+ X(callback_op),
+ X(xenoprof_op),
+ X(event_channel_op),
+ X(physdev_op),
+ X(hvm_op),
+ X(sysctl),
+ X(domctl),
+ X(kexec_op),
+ X(arch_0),
+ X(arch_1),
+ X(arch_2),
+ X(arch_3),
+ X(arch_4),
+ X(arch_5),
+ X(arch_6),
+ X(arch_7),
+};
+#undef X
+
+int lock_pages(void *addr, size_t len)
+{
+ int e = 0;
+#ifndef __sun__
+ e = mlock(addr, len);
+#endif
+ return (e);
+}
+
+void unlock_pages(void *addr, size_t len)
+{
+#ifndef __sun__
+ munlock(addr, len);
+#endif
+}
+
int main(int argc, char *argv[])
{
int i, j, xc_handle;
xc_perfc_desc_t *pcd;
- xc_perfc_val_t *pcv;
- xc_perfc_val_t *val;
- int num_desc, num_val;
- unsigned int sum, reset = 0, full = 0;
+ xc_perfc_val_t *pcv;
+ xc_perfc_val_t *val;
+ int num_desc, num_val;
+ unsigned int sum, reset = 0, full = 0, pretty = 0;
+ char hypercall_name[36];
if ( argc > 1 )
{
@@ -37,6 +104,10 @@ int main(int argc, char *argv[])
case 'f':
full = 1;
break;
+ case 'p':
+ full = 1;
+ pretty = 1;
+ break;
case 'r':
reset = 1;
break;
@@ -50,6 +121,7 @@ int main(int argc, char *argv[])
printf("%s: [-r]\n", argv[0]);
printf("no args: print digested counters\n");
printf(" -f : print full arrays/histograms\n");
+ printf(" -p : print full arrays/histograms in pretty format\n");
printf(" -r : reset counters\n");
return 0;
}
@@ -75,39 +147,39 @@ int main(int argc, char *argv[])
return 0;
}
- if ( xc_perfc_control(xc_handle, XEN_SYSCTL_PERFCOP_query,
- NULL, NULL, &num_desc, &num_val) != 0 )
- {
- fprintf(stderr, "Error getting number of perf counters: %d (%s)\n",
- errno, strerror(errno));
- return 1;
- }
+ if ( xc_perfc_control(xc_handle, XEN_SYSCTL_PERFCOP_query,
+ NULL, NULL, &num_desc, &num_val) != 0 )
+ {
+ fprintf(stderr, "Error getting number of perf counters: %d (%s)\n",
+ errno, strerror(errno));
+ return 1;
+ }
pcd = malloc(sizeof(*pcd) * num_desc);
- pcv = malloc(sizeof(*pcv) * num_val);
+ pcv = malloc(sizeof(*pcv) * num_val);
if ( pcd == NULL
- || mlock(pcd, sizeof(*pcd) * num_desc) != 0
- || pcv == NULL
- || mlock(pcd, sizeof(*pcv) * num_val) != 0)
+ || lock_pages(pcd, sizeof(*pcd) * num_desc) != 0
+ || pcv == NULL
+ || lock_pages(pcd, sizeof(*pcv) * num_val) != 0)
{
- fprintf(stderr, "Could not alloc or mlock buffers: %d (%s)\n",
+ fprintf(stderr, "Could not alloc or lock buffers: %d (%s)\n",
errno, strerror(errno));
exit(-1);
}
if ( xc_perfc_control(xc_handle, XEN_SYSCTL_PERFCOP_query,
- pcd, pcv, NULL, NULL) != 0 )
+ pcd, pcv, NULL, NULL) != 0 )
{
fprintf(stderr, "Error getting perf counter: %d (%s)\n",
errno, strerror(errno));
return 1;
}
- munlock(pcd, sizeof(*pcd) * num_desc);
- munlock(pcv, sizeof(*pcv) * num_val);
+ unlock_pages(pcd, sizeof(*pcd) * num_desc);
+ unlock_pages(pcv, sizeof(*pcv) * num_val);
- val = pcv;
+ val = pcv;
for ( i = 0; i < num_desc; i++ )
{
printf ("%-35s ", pcd[i].name);
@@ -118,11 +190,37 @@ int main(int argc, char *argv[])
printf ("T=%10u ", (unsigned int)sum);
if ( full || (pcd[i].nr_vals <= 4) )
- for ( j = 0; j < pcd[i].nr_vals; j++ )
- printf(" %10u", (unsigned int)val[j]);
+ {
+ if ( pretty && (strcmp(pcd[i].name, "hypercalls") == 0) )
+ {
+ printf("\n");
+ for( j = 0; j < pcd[i].nr_vals; j++ )
+ {
+ if ( val[j] == 0 )
+ continue;
+ if ( (j < 64) && hypercall_name_table[j] )
+ strncpy(hypercall_name, hypercall_name_table[j],
+ sizeof(hypercall_name));
+ else
+ sprintf(hypercall_name, "[%d]", j);
+ hypercall_name[sizeof(hypercall_name)-1]='\0';
+ printf("%-35s ", hypercall_name);
+ printf("%12u\n", (unsigned int)val[j]);
+ }
+ }
+ else
+ {
+ for ( j = 0; j < pcd[i].nr_vals; j++ )
+ printf(" %10u", (unsigned int)val[j]);
+ printf("\n");
+ }
+ }
+ else
+ {
+ printf("\n");
+ }
- printf("\n");
- val += pcd[i].nr_vals;
+ val += pcd[i].nr_vals;
}
return 0;
diff --git a/tools/pygrub/Makefile b/tools/pygrub/Makefile
index fab70ffc30..da75bda4b0 100644
--- a/tools/pygrub/Makefile
+++ b/tools/pygrub/Makefile
@@ -6,15 +6,17 @@ include $(XEN_ROOT)/tools/Rules.mk
all: build
.PHONY: build
build:
- CFLAGS="$(CFLAGS)" python setup.py build
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
.PHONY: install
ifndef XEN_PYTHON_NATIVE_INSTALL
install: all
- CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix=""
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix=""
+ $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xen
else
install: all
- CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
+ $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xen
endif
.PHONY: clean
diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py
index a6a8d50d03..52dcf57373 100644
--- a/tools/pygrub/setup.py
+++ b/tools/pygrub/setup.py
@@ -3,48 +3,27 @@ from distutils.ccompiler import new_compiler
import os
import sys
-extra_compile_args = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
+extra_compile_args = [ "-fno-strict-aliasing", "-Werror" ]
-fsys_mods = []
-fsys_pkgs = []
+XEN_ROOT = "../.."
-if os.path.exists("/usr/include/ext2fs/ext2_fs.h"):
- ext2defines = []
- cc = new_compiler()
- cc.add_library("ext2fs")
- if hasattr(cc, "has_function") and cc.has_function("ext2fs_open2"):
- ext2defines.append( ("HAVE_EXT2FS_OPEN2", None) )
- else:
- sys.stderr.write("WARNING: older version of e2fsprogs installed, not building full\n")
- sys.stderr.write(" disk support for ext2.\n")
-
- ext2 = Extension("grub.fsys.ext2._pyext2",
- extra_compile_args = extra_compile_args,
- libraries = ["ext2fs"],
- define_macros = ext2defines,
- sources = ["src/fsys/ext2/ext2module.c"])
- fsys_mods.append(ext2)
- fsys_pkgs.append("grub.fsys.ext2")
+fsimage = Extension("fsimage",
+ extra_compile_args = extra_compile_args,
+ include_dirs = [ XEN_ROOT + "/tools/libfsimage/common/" ],
+ library_dirs = [ XEN_ROOT + "/tools/libfsimage/common/" ],
+ libraries = ["fsimage"],
+ sources = ["src/fsimage/fsimage.c"])
-if os.path.exists("/usr/include/reiserfs/reiserfs.h"):
- reiser = Extension("grub.fsys.reiser._pyreiser",
- extra_compile_args = extra_compile_args,
- libraries = ["reiserfs"],
- sources = ["src/fsys/reiser/reisermodule.c"])
- fsys_mods.append(reiser)
- fsys_pkgs.append("grub.fsys.reiser")
+pkgs = [ 'grub' ]
-pkgs = ['grub', 'grub.fsys']
-pkgs.extend(fsys_pkgs)
setup(name='pygrub',
version='0.3',
description='Boot loader that looks a lot like grub for Xen',
author='Jeremy Katz',
author_email='katzj@redhat.com',
license='GPL',
- package_dir={'grub': 'src'},
+ package_dir={'grub': 'src', 'fsimage': 'src'},
scripts = ["src/pygrub"],
packages=pkgs,
- ext_modules = fsys_mods
+ ext_modules = [ fsimage ]
)
-
diff --git a/tools/pygrub/src/fsimage/fsimage.c b/tools/pygrub/src/fsimage/fsimage.c
new file mode 100644
index 0000000000..ad0182d691
--- /dev/null
+++ b/tools/pygrub/src/fsimage/fsimage.c
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <Python.h>
+
+#include <fsimage.h>
+#include <stdlib.h>
+
+#if (PYTHON_API_VERSION >= 1011)
+#define PY_PAD 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L
+#else
+#define PY_PAD 0L,0L,0L,0L
+#endif
+
+typedef struct fsimage_fs {
+ PyObject_HEAD
+ fsi_t *fs;
+} fsimage_fs_t;
+
+typedef struct fsimage_file {
+ PyObject_HEAD
+ fsimage_fs_t *fs;
+ fsi_file_t *file;
+} fsimage_file_t;
+
+struct foo {
+ int ref;
+ int size;
+ long hash;
+ int state;
+};
+
+static PyObject *
+fsimage_file_read(fsimage_file_t *file, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "size", "offset", NULL };
+ int bufsize;
+ int size = 0;
+ uint64_t offset = 0;
+ ssize_t bytesread = 0;
+ PyObject * buffer;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iL", kwlist,
+ &size, &offset))
+ return (NULL);
+
+ bufsize = size ? size : 4096;
+
+ if ((buffer = PyString_FromStringAndSize(NULL, bufsize)) == NULL)
+ return (NULL);
+
+ while (1) {
+ int err;
+ void *buf = PyString_AS_STRING(buffer) + bytesread;
+
+ err = fsi_pread_file(file->file, buf, bufsize,
+ bytesread + offset);
+
+ if (err == -1) {
+ Py_DECREF(buffer);
+ PyErr_SetFromErrno(PyExc_IOError);
+ return (NULL);
+ } else if (err == 0) {
+ break;
+ }
+
+ bytesread += err;
+
+ if (size != 0) {
+ bufsize -= bytesread;
+ if (bufsize == 0)
+ break;
+ } else {
+ if (_PyString_Resize(&buffer, bytesread + bufsize) < 0)
+ return (NULL);
+ }
+ }
+
+ _PyString_Resize(&buffer, bytesread);
+ return (buffer);
+}
+
+PyDoc_STRVAR(fsimage_file_read__doc__,
+ "read(file, [size=size, offset=off])\n"
+ "\n"
+ "Read size bytes (or all bytes if not set) from the given "
+ "file. If offset is specified as well, read from the given "
+ "offset.\n");
+
+static struct PyMethodDef fsimage_file_methods[] = {
+ { "read", (PyCFunction) fsimage_file_read,
+ METH_VARARGS|METH_KEYWORDS, fsimage_file_read__doc__ },
+ { NULL, NULL, 0, NULL }
+};
+
+static PyObject *
+fsimage_file_getattr(fsimage_file_t *file, char *name)
+{
+ return (Py_FindMethod(fsimage_file_methods, (PyObject *)file, name));
+}
+
+static void
+fsimage_file_dealloc(fsimage_file_t *file)
+{
+ if (file->file != NULL)
+ fsi_close_file(file->file);
+ Py_XDECREF(file->fs);
+ PyMem_DEL(file);
+}
+
+static char fsimage_file_type__doc__[] = "Filesystem image file";
+PyTypeObject fsimage_file_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "fsimage.file", /* tp_name */
+ sizeof(fsimage_file_t), /* tp_size */
+ 0, /* tp_itemsize */
+ (destructor) fsimage_file_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) fsimage_file_getattr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ fsimage_file_type__doc__,
+ PY_PAD
+};
+
+static PyObject *
+fsimage_fs_open_file(fsimage_fs_t *fs, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "name", NULL };
+ fsimage_file_t *file;
+ char *name;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+ return (NULL);
+
+ file = (fsimage_file_t *)PyObject_NEW(fsimage_file_t, &fsimage_file_type);
+
+ if (file == NULL)
+ return (NULL);
+
+ file->fs = fs;
+
+ Py_INCREF(file->fs);
+ if ((file->file = fsi_open_file(fs->fs, name)) == NULL) {
+ Py_DECREF(file->fs);
+ file->fs = NULL;
+ PyErr_SetFromErrno(PyExc_IOError);
+ return (NULL);
+ }
+
+ return ((PyObject *)file);
+}
+
+static PyObject *
+fsimage_fs_file_exists(fsimage_fs_t *fs, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "name", NULL };
+ char *name;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+ return (NULL);
+
+ if (fsi_file_exists(fs->fs, name)) {
+ Py_INCREF(Py_True);
+ return (Py_True);
+ }
+
+ Py_INCREF(Py_False);
+ return (Py_False);
+}
+
+PyDoc_STRVAR(fsimage_fs_open_file__doc__,
+ "open_file(fs, filename) - lookup name in the given fs and return the file");
+PyDoc_STRVAR(fsimage_fs_file_exists__doc__,
+ "file_exists(fs, name) - lookup name in the given fs and return "
+ "True if it exists");
+
+static struct PyMethodDef fsimage_fs_methods[] = {
+ { "open_file", (PyCFunction) fsimage_fs_open_file,
+ METH_VARARGS|METH_KEYWORDS, fsimage_fs_open_file__doc__ },
+ { "file_exists", (PyCFunction) fsimage_fs_file_exists,
+ METH_VARARGS|METH_KEYWORDS, fsimage_fs_file_exists__doc__ },
+ { NULL, NULL, 0, NULL }
+};
+
+static PyObject *
+fsimage_fs_getattr(fsimage_fs_t *fs, char *name)
+{
+ return (Py_FindMethod(fsimage_fs_methods, (PyObject *)fs, name));
+}
+
+static void
+fsimage_fs_dealloc (fsimage_fs_t *fs)
+{
+ if (fs->fs != NULL)
+ fsi_close_fsimage(fs->fs);
+ PyMem_DEL(fs);
+}
+
+PyDoc_STRVAR(fsimage_fs_type__doc__, "Filesystem image");
+
+PyTypeObject fsimage_fs_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "fsimage.fs", /* tp_name */
+ sizeof(fsimage_fs_t), /* tp_size */
+ 0, /* tp_itemsize */
+ (destructor) fsimage_fs_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) fsimage_fs_getattr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ fsimage_fs_type__doc__,
+ PY_PAD
+};
+
+static PyObject *
+fsimage_open(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "name", "offset", NULL };
+ char * name;
+ uint64_t offset = 0;
+ fsimage_fs_t *fs;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|L", kwlist,
+ &name, &offset))
+ return (NULL);
+
+ if ((fs = PyObject_NEW(fsimage_fs_t, &fsimage_fs_type)) == NULL)
+ return (NULL);
+
+ if ((fs->fs = fsi_open_fsimage(name, offset)) == NULL) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ return (NULL);
+ }
+
+ return (PyObject *)fs;
+}
+
+PyDoc_STRVAR(fsimage_open__doc__,
+ "open(name, [offset=off]) - Open the given file as a filesystem image.\n"
+ "\n"
+ "name - name of file to open.\n"
+ "offset - offset of file system within file image.\n");
+
+static struct PyMethodDef fsimage_module_methods[] = {
+ { "open", (PyCFunction)fsimage_open,
+ METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ },
+ { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC
+initfsimage(void)
+{
+ Py_InitModule("fsimage", fsimage_module_methods);
+}
diff --git a/tools/pygrub/src/fsys/__init__.py b/tools/pygrub/src/fsys/__init__.py
deleted file mode 100644
index 07e12c95b6..0000000000
--- a/tools/pygrub/src/fsys/__init__.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# Copyright 2005 Red Hat, Inc.
-# Jeremy Katz <katzj@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-import os
-import sys
-
-fstypes = {}
-
-def register_fstype(x):
- if x.name in fstypes.keys():
- return
- fstypes[x.name] = x
-
-class FileSystemType(object):
- """A simple representation for a file system that gives a fs name
- and a method for sniffing a file to see if it's of the given fstype."""
- def __init__(self):
- self.name = ""
-
- def sniff_magic(self, fn, offset = 0):
- """Look at the filesystem at fn for the appropriate magic starting at
- offset offset."""
- raise RuntimeError, "sniff_magic not implemented"
-
- def open_fs(self, fn, offset = 0):
- """Open the given filesystem and return a filesystem object."""
- raise RuntimeError, "open_fs not implemented"
-
-class FileSystem(object):
- def open(self, name, flags = 0, block_size = 0):
- """Open the fsys on name with given flags and block_size."""
- raise RuntimeError, "open not implemented"
-
- def close(self):
- """Close the fsys."""
- raise RuntimeError, "close not implemented"
-
- def open_file(self, file, flags = None):
- """Open the file 'name' with the given flags. The returned object
- should look similar to a native file object."""
- raise RuntimeError, "open_file not implemented"
-
- def file_exist(self, file):
- """Check to see if the give file is existed.
- Return true if file existed, return false otherwise."""
- raise RuntimeError, "file_exist not implemented"
-
-mydir = sys.modules['grub.fsys'].__path__[0]
-for f in os.listdir(mydir):
- if not os.path.isdir("%s/%s" %(mydir, f)):
- continue
- try:
- exec "import grub.fsys.%s" %(f,)
- except ImportError, e:
- pass
diff --git a/tools/pygrub/src/fsys/ext2/__init__.py b/tools/pygrub/src/fsys/ext2/__init__.py
deleted file mode 100644
index 4c3fe12c00..0000000000
--- a/tools/pygrub/src/fsys/ext2/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2005 Red Hat, Inc.
-# Jeremy Katz <katzj@redhat.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-from grub.fsys import register_fstype, FileSystemType
-from _pyext2 import *
-
-import os, struct
-
-class Ext2FileSystemType(FileSystemType):
- def __init__(self):
- FileSystemType.__init__(self)
- self.name = "ext2"
-
- def sniff_magic(self, fn, offset = 0):
- fd = os.open(fn, os.O_RDONLY)
- os.lseek(fd, offset, 0)
- buf = os.read(fd, 2048)
-
- if len(buf) > 1082 and \
- struct.unpack("<H", buf[1080:1082]) == (0xef53,):
- return True
- return False
-
- def open_fs(self, fn, offset = 0):
- if not self.sniff_magic(fn, offset):
- raise ValueError, "Not an ext2 filesystem"
- return Ext2Fs(fn, offset = offset)
-
-register_fstype(Ext2FileSystemType())
-
diff --git a/tools/pygrub/src/fsys/ext2/ext2module.c b/tools/pygrub/src/fsys/ext2/ext2module.c
deleted file mode 100644
index 57f1a83eaf..0000000000
--- a/tools/pygrub/src/fsys/ext2/ext2module.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * ext2module.c - simple python binding for libext2fs
- *
- * Copyright 2005 Red Hat, Inc.
- * Jeremy Katz <katzj@redhat.com>
- *
- * This software may be freely redistributed under the terms of the GNU
- * general public license.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <Python.h>
-
-#include <ext2fs/ext2fs.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#if (PYTHON_API_VERSION >= 1011)
-#define PY_PAD 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L
-#else
-#define PY_PAD 0L,0L,0L,0L
-#endif
-
-
-/* global error object */
-PyObject *Ext2Error;
-
-typedef struct _Ext2Fs Ext2Fs;
-struct _Ext2Fs {
- PyObject_HEAD;
- ext2_filsys fs;
-};
-
-typedef struct _Ext2File Ext2File;
-struct _Ext2File {
- PyObject_HEAD;
- ext2_file_t file;
-};
-
-/* ext2 file object */
-
-static PyObject *
-ext2_file_close (Ext2File *file, PyObject *args)
-{
- if (file->file != NULL)
- ext2fs_file_close(file->file);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-ext2_file_read (Ext2File *file, PyObject *args)
-{
- int err, size = 0;
- unsigned int n, total = 0;
- PyObject * buffer = NULL;
-
- if (file->file == NULL) {
- PyErr_SetString(PyExc_ValueError, "Cannot read from closed file");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|i", &size))
- return NULL;
-
- buffer = PyString_FromStringAndSize((char *) NULL, (size) ? size : 4096);
- if (buffer == NULL)
- return buffer;
-
- while (1) {
- err = ext2fs_file_read(file->file, PyString_AS_STRING(buffer) + total,
- (size) ? size : 4096, &n);
- if (err) {
- if (buffer != NULL) { Py_DECREF(buffer); }
- Py_DECREF(buffer);
- PyErr_SetString(PyExc_ValueError, "read error");
- return NULL;
- }
-
- total += n;
- if (n == 0)
- break;
-
- if (size && size == total)
- break;
-
- if (!size) {
- _PyString_Resize(&buffer, total + 4096);
- }
- }
-
- _PyString_Resize(&buffer, total);
- return buffer;
-}
-
-static void
-ext2_file_dealloc (Ext2File * file)
-{
- if (file->file != NULL)
- ext2fs_file_close(file->file);
- PyMem_DEL(file);
-}
-
-static struct PyMethodDef Ext2FileMethods[] = {
- { "close",
- (PyCFunction) ext2_file_close,
- METH_VARARGS, NULL },
- { "read",
- (PyCFunction) ext2_file_read,
- METH_VARARGS, NULL },
- { NULL, NULL, 0, NULL }
-};
-
-static PyObject *
-ext2_file_getattr (Ext2File * file, char * name)
-{
- return Py_FindMethod (Ext2FileMethods, (PyObject *) file, name);
-}
-
-static char Ext2FileType__doc__[] = "This is the ext2 filesystem object";
-PyTypeObject Ext2FileType = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /* ob_size */
- "Ext2File", /* tp_name */
- sizeof(Ext2File), /* tp_size */
- 0, /* tp_itemsize */
- (destructor) ext2_file_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- (getattrfunc) ext2_file_getattr, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- 0L, /* tp_flags */
- Ext2FileType__doc__,
- PY_PAD
-};
-
-static PyObject *
-ext2_file_open (Ext2Fs *fs, char * name, int flags)
-{
- int err;
- ext2_file_t f;
- ext2_ino_t ino;
- Ext2File * file;
-
- file = (Ext2File *) PyObject_NEW(Ext2File, &Ext2FileType);
- file->file = NULL;
-
- err = ext2fs_namei_follow(fs->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &ino);
- if (err) {
- PyErr_SetString(PyExc_ValueError, "unable to open file");
- return NULL;
- }
-
- err = ext2fs_file_open(fs->fs, ino, flags, &f);
- if (err) {
- PyErr_SetString(PyExc_ValueError, "unable to open file");
- return NULL;
- }
-
- file->file = f;
- return (PyObject *) file;
-}
-
-static PyObject *
-ext2_file_exist (Ext2Fs *fs, char * name)
-{
- int err;
- ext2_ino_t ino;
- Ext2File * file;
-
- file = (Ext2File *) PyObject_NEW(Ext2File, &Ext2FileType);
- file->file = NULL;
-
- err = ext2fs_namei_follow(fs->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &ino);
- if (err) {
- Py_INCREF(Py_False);
- return Py_False;
- }
- Py_INCREF(Py_True);
- return Py_True;
-}
-
-/* ext2fs object */
-
-static PyObject *
-ext2_fs_close (Ext2Fs *fs, PyObject *args)
-{
- if (fs->fs != NULL)
- ext2fs_close(fs->fs);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-ext2_fs_open (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "name", "flags", "superblock",
- "block_size", "offset", NULL };
- char * name;
- int flags = 0, superblock = 0, offset = 0, err;
- unsigned int block_size = 0;
- ext2_filsys efs;
-#ifdef HAVE_EXT2FS_OPEN2
- char offsetopt[30];
-#endif
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iiii", kwlist,
- &name, &flags, &superblock,
- &block_size, &offset))
- return NULL;
-
- if (fs->fs != NULL) {
- PyErr_SetString(PyExc_ValueError, "already have an fs object");
- return NULL;
- }
-
-#ifdef HAVE_EXT2FS_OPEN2
- if (offset == 0) {
- offsetopt[0] = '\0';
- }
- else {
- snprintf(offsetopt, 29, "offset=%d", offset);
- }
-
- err = ext2fs_open2(name, offsetopt, flags, superblock, block_size,
- unix_io_manager, &efs);
-#else
- if (offset != 0) {
- PyErr_SetString(PyExc_ValueError, "offset argument not supported");
- return NULL;
- }
-
- err = ext2fs_open(name, flags, superblock, block_size,
- unix_io_manager, &efs);
-#endif
- if (err) {
- PyErr_SetString(PyExc_ValueError, "unable to open filesystem");
- return NULL;
- }
-
- fs->fs = efs;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-ext2_fs_open_file (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "name", "flags", NULL };
- char * name;
- int flags = 0;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist,
- &name, &flags))
- return NULL;
-
- return ext2_file_open(fs, name, flags);
-}
-
-static PyObject *
-ext2_fs_file_exist (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "name", NULL };
- char * name;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
- return NULL;
-
- return ext2_file_exist(fs, name);
-}
-
-static void
-ext2_fs_dealloc (Ext2Fs * fs)
-{
- if (fs->fs != NULL)
- ext2fs_close(fs->fs);
- PyMem_DEL(fs);
-}
-
-static struct PyMethodDef Ext2FsMethods[] = {
- { "close",
- (PyCFunction) ext2_fs_close,
- METH_VARARGS, NULL },
- { "open",
- (PyCFunction) ext2_fs_open,
- METH_VARARGS|METH_KEYWORDS, NULL },
- { "open_file",
- (PyCFunction) ext2_fs_open_file,
- METH_VARARGS|METH_KEYWORDS, NULL },
- { "file_exist",
- (PyCFunction) ext2_fs_file_exist,
- METH_VARARGS|METH_KEYWORDS, NULL },
- { NULL, NULL, 0, NULL }
-};
-
-static PyObject *
-ext2_fs_getattr (Ext2Fs * fs, char * name)
-{
- return Py_FindMethod (Ext2FsMethods, (PyObject *) fs, name);
-}
-
-static char Ext2FsType__doc__[] = "This is the ext2 filesystem object";
-PyTypeObject Ext2FsType = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /* ob_size */
- "Ext2Fs", /* tp_name */
- sizeof(Ext2Fs), /* tp_size */
- 0, /* tp_itemsize */
- (destructor) ext2_fs_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- (getattrfunc) ext2_fs_getattr, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- 0L, /* tp_flags */
- Ext2FsType__doc__,
- PY_PAD
-};
-
-static PyObject *
-ext2_fs_new(PyObject *o, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "name", "flags", "superblock",
- "block_size", "offset", NULL };
- char * name;
- int flags = 0, superblock = 0, offset;
- unsigned int block_size = 0;
- Ext2Fs *pfs;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iiii", kwlist,
- &name, &flags, &superblock, &block_size,
- &offset))
- return NULL;
-
- pfs = (Ext2Fs *) PyObject_NEW(Ext2Fs, &Ext2FsType);
- if (pfs == NULL)
- return NULL;
- pfs->fs = NULL;
-
- if (!ext2_fs_open(pfs,
- Py_BuildValue("siiii", name, flags, superblock,
- block_size, offset), NULL))
- return NULL;
-
- return (PyObject *)pfs;
-}
-
-static struct PyMethodDef Ext2ModuleMethods[] = {
- { "Ext2Fs", (PyCFunction) ext2_fs_new, METH_VARARGS|METH_KEYWORDS, NULL },
- { NULL, NULL, 0, NULL }
-};
-
-void init_pyext2(void) {
- PyObject *m;
-
- m = Py_InitModule("_pyext2", Ext2ModuleMethods);
- /*
- * PyObject *d;
- * d = PyModule_GetDict(m);
- * o = PyObject_NEW(PyObject, yExt2FsConstructorType);
- * PyDict_SetItemString(d, "PyExt2Fs", o);
- * Py_DECREF(o);
- */
-}
diff --git a/tools/pygrub/src/fsys/ext2/test.py b/tools/pygrub/src/fsys/ext2/test.py
deleted file mode 100644
index eeb79506ee..0000000000
--- a/tools/pygrub/src/fsys/ext2/test.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/python
-
-
-import _pyext2
-import struct, os, sys
-
-fs = _pyext2.Ext2Fs("test.img")
-
-f = fs.open_file("/boot/vmlinuz-2.6.11-1.1177_FC4")
-buf = f.read()
-o = open("vmlinuz", "wb+")
-o.write(buf)
-o.close()
-
-f.close()
diff --git a/tools/pygrub/src/fsys/reiser/__init__.py b/tools/pygrub/src/fsys/reiser/__init__.py
deleted file mode 100644
index e49e7c3e0a..0000000000
--- a/tools/pygrub/src/fsys/reiser/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
-#
-# This software may be freely redistributed under the terms of the GNU
-# general public license.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-from grub.fsys import register_fstype, FileSystemType
-from _pyreiser import *
-
-import os
-
-FSMAGIC2 = 'ReIsEr2'
-FSMAGIC3 = 'ReIsEr3'
-
-class ReiserFileSystemType(FileSystemType):
- def __init__(self):
- FileSystemType.__init__(self)
- self.name = "reiser"
-
- def sniff_magic(self, fn, offset = 0):
- fd = os.open(fn, os.O_RDONLY)
- os.lseek(fd, 0x10000, 0)
- buf = os.read(fd, 0x40)
- if len(buf) == 0x40 and (buf[0x34:0x3B] in [FSMAGIC2, FSMAGIC3]) :
- return True
- return False
-
- def open_fs(self, fn, offset = 0):
- if not self.sniff_magic(fn, offset):
- raise ValueError, "Not a reiserfs filesystem"
- return ReiserFs(fn)
-
-register_fstype(ReiserFileSystemType())
-
diff --git a/tools/pygrub/src/fsys/reiser/reisermodule.c b/tools/pygrub/src/fsys/reiser/reisermodule.c
deleted file mode 100644
index 9eb4e1e638..0000000000
--- a/tools/pygrub/src/fsys/reiser/reisermodule.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * reisermodule.c - simple python binding for libreiserfs{2,3}
- *
- * Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
- *
- * This software may be freely redistributed under the terms of the GNU
- * general public license.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <Python.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <dal/file_dal.h>
-#include <reiserfs/reiserfs.h>
-
-#if (PYTHON_API_VERSION >= 1011)
-#define PY_PAD 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L
-#else
-#define PY_PAD 0L,0L,0L,0L
-#endif
-
-
-/* global error object */
-PyObject *ReiserError;
-
-typedef struct {
- PyObject_HEAD
- reiserfs_fs_t *fs;
- dal_t *dal;
-} ReiserFs;
-
-typedef struct _ReiserFile ReiserFile;
-struct _ReiserFile {
- PyObject_HEAD
- reiserfs_file_t *file;
-};
-
-void file_dal_close(dal_t *dal) {
-
- if (!dal) return;
-
- close((int)(unsigned long)dal->dev);
- dal_free(dal);
-}
-
-/* reiser file object */
-
-static PyObject *
-reiser_file_close (ReiserFile *file, PyObject *args)
-{
- if (file->file != NULL)
- {
- reiserfs_file_close(file->file);
- file->file = NULL;
- }
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-reiser_file_read (ReiserFile *file, PyObject *args)
-{
- int size = 0;
- size_t n, total = 0;
- PyObject * buffer = NULL;
-
- if (file->file == NULL) {
- PyErr_SetString(PyExc_ValueError, "Cannot read from closed file");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "|i", &size))
- return NULL;
-
- buffer = PyString_FromStringAndSize((char *) NULL, (size) ? size : 4096);
- if (buffer == NULL)
- return buffer;
-
- while (1) {
- n = reiserfs_file_read(file->file, PyString_AS_STRING(buffer) + total,
- (size) ? size : 4096);
- if (n == 0)
- break;
-
- total += n;
-
- if (size && size == total)
- break;
-
- if (!size) {
- _PyString_Resize(&buffer, total + 4096);
- }
- }
-
- _PyString_Resize(&buffer, total);
- return buffer;
-}
-
-static void
-reiser_file_dealloc (ReiserFile * file)
-{
- if (file->file != NULL) {
- reiserfs_file_close(file->file);
- file->file = NULL;
- }
- PyObject_DEL(file);
-}
-
-static struct PyMethodDef ReiserFileMethods[] = {
- { "close", (PyCFunction) reiser_file_close, METH_VARARGS, NULL },
- { "read", (PyCFunction) reiser_file_read, METH_VARARGS, NULL },
- { NULL, NULL, 0, NULL }
-};
-
-static PyObject *
-reiser_file_getattr (ReiserFile * file, char * name)
-{
- return Py_FindMethod (ReiserFileMethods, (PyObject *) file, name);
-}
-
-static char ReiserFileType__doc__[] = "This is the reiser filesystem object";
-PyTypeObject ReiserFileType = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /* ob_size */
- "ReiserFile", /* tp_name */
- sizeof(ReiserFile), /* tp_size */
- 0, /* tp_itemsize */
- (destructor) reiser_file_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- (getattrfunc) reiser_file_getattr, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- ReiserFileType__doc__,
- PY_PAD
-};
-
-static PyObject *
-reiser_file_open (ReiserFs *fs, char *name, int flags)
-{
- ReiserFile *file;
- reiserfs_file_t *f;
-
- file = (ReiserFile *) PyObject_NEW(ReiserFile, &ReiserFileType);
-
- f = reiserfs_file_open(fs->fs, name, flags);
- file->file = f;
-
- if (!f) {
- PyErr_SetString(PyExc_ValueError, "unable to open file");
- return NULL;
- }
-
- return (PyObject *) file;
-}
-
-static PyObject *
-reiser_file_exist (ReiserFs *fs, char *name)
-{
- reiserfs_file_t *f;
-
- f = reiserfs_file_open(fs->fs, name, O_RDONLY);
-
- if (!f) {
- Py_INCREF(Py_False);
- return Py_False;
- }
- reiserfs_file_close(f);
- Py_INCREF(Py_True);
- return Py_True;
-}
-
-/* reiserfs object */
-
-static PyObject *
-reiser_fs_close (ReiserFs *fs, PyObject *args)
-{
- if (fs->fs != NULL)
- {
- reiserfs_fs_close(fs->fs);
- file_dal_close(fs->dal);
- fs->fs = NULL;
- }
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-reiser_fs_open (ReiserFs *fs, PyObject *args)
-{
- char *name;
- size_t block_size = DEFAULT_BLOCK_SIZE;
- dal_t *dal;
- reiserfs_fs_t *rfs;
-
- if (!PyArg_ParseTuple(args, "s|i", &name, &block_size))
- return NULL;
-
- if (fs->fs != NULL) {
- PyErr_SetString(PyExc_ValueError, "already have an fs object");
- return NULL;
- }
-
- if (!(dal = file_dal_open(name, block_size, O_RDONLY))) {
- PyErr_SetString(PyExc_ValueError, "Couldn't create device abstraction");
- return NULL;
- }
-
- if (!(rfs = reiserfs_fs_open_fast(dal, dal))) {
- file_dal_close(dal);
- PyErr_SetString(PyExc_ValueError, "unable to open file");
- return NULL;
- }
-
- fs->fs = rfs;
- fs->dal = dal;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-reiser_fs_open_file (ReiserFs *fs, PyObject *args)
-{
- char *name;
- int flags = 0;
-
- if (!PyArg_ParseTuple(args, "s|i", &name, &flags))
- return NULL;
-
- return reiser_file_open(fs, name, flags);
-}
-
-static PyObject *
-reiser_fs_file_exist (ReiserFs *fs, PyObject *args)
-{
- char * name;
-
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
-
- return reiser_file_exist(fs, name);
-}
-
-static void
-reiser_fs_dealloc (ReiserFs * fs)
-{
- if (fs->fs != NULL)
- {
- reiserfs_fs_close(fs->fs);
- file_dal_close(fs->dal);
- fs->fs = NULL;
- }
- PyObject_DEL(fs);
-}
-
-static struct PyMethodDef ReiserFsMethods[] = {
- { "close", (PyCFunction) reiser_fs_close, METH_VARARGS, NULL },
- { "open", (PyCFunction) reiser_fs_open, METH_VARARGS, NULL },
- { "open_file", (PyCFunction) reiser_fs_open_file, METH_VARARGS, NULL },
- { "file_exist", (PyCFunction) reiser_fs_file_exist, METH_VARARGS, NULL },
- { NULL, NULL, 0, NULL }
-};
-
-static PyObject *
-reiser_fs_getattr (ReiserFs * fs, char * name)
-{
- return Py_FindMethod (ReiserFsMethods, (PyObject *) fs, name);
-}
-
-static char ReiserFsType__doc__[] = "This is the reiser filesystem object";
-
-PyTypeObject ReiserFsType = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0, /* ob_size */
- "ReiserFs", /* tp_name */
- sizeof(ReiserFs), /* tp_size */
- 0, /* tp_itemsize */
- (destructor) reiser_fs_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- (getattrfunc) reiser_fs_getattr, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- ReiserFsType__doc__,
- PY_PAD
-};
-
-static PyObject *
-reiser_fs_new(PyObject *o, PyObject *args)
-{
- char *name;
- size_t block_size = DEFAULT_BLOCK_SIZE;
- ReiserFs *pfs;
-
- if (!PyArg_ParseTuple(args, "s|i", &name, &block_size))
- return NULL;
-
- pfs = (ReiserFs *) PyObject_NEW(ReiserFs, &ReiserFsType);
- if (pfs == NULL)
- return NULL;
-
- pfs->fs = NULL;
-
- if (!reiser_fs_open(pfs, Py_BuildValue("si", name, block_size)))
- return NULL;
-
- return (PyObject *)pfs;
-}
-
-static struct PyMethodDef ReiserModuleMethods[] = {
- { "ReiserFs", (PyCFunction) reiser_fs_new, METH_VARARGS},
- { NULL, NULL, 0}
-};
-
-void init_pyreiser(void) {
- Py_InitModule("_pyreiser", ReiserModuleMethods);
-}
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
index d426289875..64a3662704 100644
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -22,10 +22,21 @@ import getopt
sys.path = [ '/usr/lib/python' ] + sys.path
+import fsimage
import grub.GrubConf
-import grub.fsys
-PYGRUB_VER = 0.4
+PYGRUB_VER = 0.5
+
+def enable_cursor(ison):
+ if ison:
+ val = 2
+ else:
+ val = 0
+
+ try:
+ curses.curs_set(val)
+ except _curses.error:
+ pass
def is_disk_image(file):
fd = os.open(file, os.O_RDONLY)
@@ -102,17 +113,21 @@ class GrubLineEditor(curses.textpad.Textbox):
elif ch == curses.ascii.SOH: # ^a
self.pos = 0
elif ch in (curses.ascii.STX,curses.KEY_LEFT):
- self.pos -= 1
+ if self.pos > 0:
+ self.pos -= 1
elif ch in (curses.ascii.BS,curses.KEY_BACKSPACE):
if self.pos > 0:
self.pos -= 1
- self.line.pop(self.pos)
+ if self.pos < len(self.line):
+ self.line.pop(self.pos)
elif ch == curses.ascii.EOT: # ^d
- self.line.pop(self.pos)
+ if self.pos < len(self.line):
+ self.line.pop(self.pos)
elif ch == curses.ascii.ENQ: # ^e
self.pos = len(self.line)
elif ch in (curses.ascii.ACK, curses.KEY_RIGHT):
- self.pos +=1
+ if self.pos < len(self.line):
+ self.pos +=1
elif ch == curses.ascii.VT: # ^k
self.line = self.line[:self.pos]
else:
@@ -141,10 +156,7 @@ class Grub:
self.screen.timeout(1000)
if hasattr(curses, 'use_default_colors'):
curses.use_default_colors()
- try:
- curses.curs_set(0)
- except _curses.error:
- pass
+ enable_cursor(False)
self.entry_win = curses.newwin(10, 74, 2, 1)
self.text_win = curses.newwin(10, 70, 12, 5)
@@ -247,6 +259,7 @@ class Grub:
self.screen.refresh()
t = GrubLineEditor(self.screen, 5, 2, line)
+ enable_cursor(True)
ret = t.edit()
if ret:
return ret
@@ -262,6 +275,7 @@ class Grub:
lines = []
while 1:
t = GrubLineEditor(self.screen, y, 2)
+ enable_cursor(True)
ret = t.edit()
if ret:
if ret in ("quit", "return"):
@@ -303,25 +317,21 @@ class Grub:
raise RuntimeError, "Unable to find active partition on disk"
# open the image and read the grub config
- fs = None
- for fstype in grub.fsys.fstypes.values():
- if fstype.sniff_magic(fn, offset):
- fs = fstype.open_fs(fn, offset)
- break
+ fs = fsimage.open(fn, offset)
if fs is not None:
grubfile = None
for f in ("/boot/grub/menu.lst", "/boot/grub/grub.conf",
"/grub/menu.lst", "/grub/grub.conf"):
- if fs.file_exist(f):
+ if fs.file_exists(f):
grubfile = f
break
if grubfile is None:
raise RuntimeError, "we couldn't find grub config file in the image provided."
f = fs.open_file(grubfile)
buf = f.read()
- f.close()
- fs.close()
+ del f
+ del fs
# then parse the grub config
self.cf.parse(buf)
else:
@@ -501,14 +511,7 @@ if __name__ == "__main__":
raise RuntimeError, "Unable to find active partition on disk"
# read the kernel and initrd onto the hostfs
- fs = None
- for fstype in grub.fsys.fstypes.values():
- if fstype.sniff_magic(file, offset):
- fs = fstype.open_fs(file, offset)
- break
-
- if fs is None:
- raise RuntimeError, "Unable to open filesystem"
+ fs = fsimage.open(file, offset)
kernel = fs.open_file(img.kernel[1],).read()
(tfd, fn) = tempfile.mkstemp(prefix="vmlinuz.", dir="/var/lib/xen")
diff --git a/tools/python/Makefile b/tools/python/Makefile
index e73d624414..6b84446ee6 100644
--- a/tools/python/Makefile
+++ b/tools/python/Makefile
@@ -6,15 +6,15 @@ all: build
.PHONY: build
build:
- CFLAGS="$(CFLAGS)" python setup.py build
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
.PHONY: install
ifndef XEN_PYTHON_NATIVE_INSTALL
install: all
- CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix="" --force
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix="" --force
else
install: all
- CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)" --force
+ CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)" --force
endif
.PHONY: test
diff --git a/tools/python/README.XendConfig b/tools/python/README.XendConfig
new file mode 100644
index 0000000000..2e677f887a
--- /dev/null
+++ b/tools/python/README.XendConfig
@@ -0,0 +1,160 @@
+XendConfig parameters
+=====================
+
+Things that are empty means there is no direct mapping.
+
+In order to make the XendConfig fully backwards compatible, it needs a
+representation of all the below parameters. Where both columns have
+values, it means we can have a direct translation.
+
+Where the Legacy Config value does not exist, it means we have to make
+up the value on whether we supported it or not.
+
+Where the Legacy config value is prefixed with an '!', it means it is
+not a direct mapping and needs a translation function.
+
+Where the Xen API config value does not exist, it means we have to add
+a parameter outside of the Xen API Configuration to support it.
+
+
+Xen API Config Legacy Config
+-------------- -------------
+uuid uuid
+power_state !state (and xc_getinfo)
+name_label name
+name_description
+user_version
+is_a_template
+resident_on
+memory_static_min memory
+memory_static_max maxmem
+memory_actual
+memory_dynamic_min
+memory_dynamic_max
+vcpus_policy !set_credit/set_sedf
+vcpus_params !set_credit/set_sedf
+vcpus_number vcpus
+vcpus_utilisation
+vcpus_features_required
+vcpus_features_can_use
+vcpus_features_force_on
+vcpus_features_force_off
+actions_after_shutdown on_poweroff
+actions_after_reboot on_reboot
+actions_after_suspend
+actions_after_crash on_crash
+
+vifs !(devices.vifs)
+ - uuid dev.uuid
+ - name
+ - type vif.type
+ - device
+ - network
+ - vm
+ - MAC vif.mac
+ - MTU
+ - io_read_kbs !vif.rate
+ - io_write_kbs !vif.rate
+ vif.bridge
+ vif.script
+ vif.ip
+ vif.vifname (backend name)
+
+vbds !(devices.vbds)
+ - uuid
+ - vm
+ - vdi
+ - device vbd.uname
+ - mode !vbd.mode
+ - driver vbd.driver
+ - io_read_kbs
+ - io_write_kbs
+
+tpm_instance tpm.instance
+tpm_backend tpm.backend
+bios_boot image.boot?
+platform_std_VGA image.stdvga
+platform_serial image.serial
+platform_localtime !localtime (bool)
+platform_clock_offset
+platform_enable_audio !image.soundhw (bool)
+builder (sxp root name)
+boot_method
+kernel_kernel kernel.kernel
+kernel_initrd kernel.ramdisk
+kernel_args !kernel.args
+grub_cmdline bootloader_args
+PCI_bus
+tools_version
+
+otherConfig
+ - image image (see image.*)
+ - shadow_memory shadow_memory
+ - security security
+ - vcpu_avail vcpu_avail
+ - features features
+ - on_xend_stop on_xend_stop
+ - on_xend_start on_xend_start
+ - start_time start_time
+ - cpus cpus (?)
+ max_vcpu_id
+
+ >> only from xc
+ - online_vcpus xc.online_vcpus
+ - status xc.status
+ - cpu_time xc.cpu_time
+ - shutdown_reason xc.shutdown_reason
+ - up_time xc.uptime
+ - crashed xc.crashed
+ - dying xc.dying
+ - shutdown xc.shutdown
+
+ image.type (linux or hvm)
+ image.root
+ image.ip
+ image.nographic
+ image.vnc
+ image.sdl
+ image.vncdisplay
+ image.vncunused
+ image.hvm.device_model
+ image.hvm.display
+ image.hvm.xauthority
+ image.hvm.vncconsole
+ image.hvm.pae
+ image.hvm.acpi (also in image.devices)
+ image.hvm.apic
+ image.hvm.devices.boot
+ image.hvm.devices.fda
+ image.hvm.devices.fdb
+ image.hvm.devices.soundhw
+ image.hvm.devices.isa
+ image.hvm.devices.vcpus?
+ image.hvm.devices.acpi
+ image.hvm.devices.usb
+ image.hvm.devices.usbdevice
+
+
+ dev.backend
+ dev.dom
+ dev.id
+
+ pci.domain
+ pci.bus
+ pci.slot
+ pci.func
+
+ pciquirk.pci_ids
+ pciquirk.pci_config_space_fields
+ pciquirk.unconstrained_dev_ids
+
+ irq.irq
+
+- vcpu (probably not needed, only in XM and generated dynamically)
+ vcpu.number
+ vcpu.online
+ vcpu.blocked
+ vcpu.running
+ vcpu.cpu_time
+ vcpu.cpu
+ vcpu.cpumap
diff --git a/tools/python/README.sxpcfg b/tools/python/README.sxpcfg
new file mode 100644
index 0000000000..9beffd6ba0
--- /dev/null
+++ b/tools/python/README.sxpcfg
@@ -0,0 +1,117 @@
+Map of all supported SXP configuration options
+----------------------------------------------
+
+uuid
+vcpus
+maxmem
+memory
+name
+on_poweroff
+on_reboot
+on_crash
+bootloader
+kernel_kernel
+kernel_initrd
+kernel_args
+localtime
+
+shadow_memory
+security
+ssidref (deprecated)
+vcpu_avail
+cpu_weight (deprecated)
+bootloader_args
+features
+on_xend_stop
+on_xend_start
+start_time
+cpu (deprecated)
+cpus
+
+(xc getinfo)
+domid
+online_vcpus
+status
+cpu_time
+shutdown_reason
+(xm list --long)
+up_time
+
+image
+ - kernel
+ - ramdisk
+ - args
+ - ip
+ - root
+ (configVNC)
+ - nographic
+ - vnc
+ - sdl
+ - vncdisplay
+ - vncunused
+ (HVM)
+ - device_model
+ - display
+ - xauthority
+ - vncconsole
+ - pae
+ - acpi
+ - apic
+ (parseDeviceModel)
+ - boot
+ - fda
+ - fdb
+ - soundhw
+ - localtime
+ - serial
+ - stdvga
+ - isa
+ - vcpus
+ - acpi
+ - usb
+ - usbdevice
+
+(all devices)
+ - backend
+ - dom
+ - id
+ - uuid
+
+vbd
+ - uname
+ - dev (ioemu:, .. etc)
+ - mode (r, w. w!)
+
+vif
+ - type
+ - mac
+ - bridge
+ - model
+ - rate
+ - vifname
+ - script
+ - ip
+
+pci
+ - domain
+ - bus
+ - slot
+ - func
+ (Xen 2.0)
+ - dev
+
+io
+ - from
+ - to
+
+tpm
+ - pref_instance
+ - instance
+
+pciquirk
+ - pci_ids
+ - pci_config_space_fields
+ - unconstrained_dev_ids
+
+irq
+ - irq
diff --git a/tools/python/scripts/README b/tools/python/scripts/README
new file mode 100644
index 0000000000..a5d87592ae
--- /dev/null
+++ b/tools/python/scripts/README
@@ -0,0 +1,49 @@
+Xen API Test
+============
+
+xapi.py is a simple command line tool to test the functionality of a
+domain lifecycle supporting, Xen API talking version of Xend.
+
+Creating a VM is slightly more work under the Xen API. The differences
+with this and xm is:
+
+1. None of the devices are created during vm-create. You must use
+ vbd-create and vif-create to attach a new device to the VM.
+
+2. VM's that are created using vm-create will not start by
+ default. You must use vm-start to "start" the domain.
+
+3. VM's that are created using vm-create will not be removed on
+ shutdown. You must remove it using vm-delete.
+
+Example Configuration Files
+---------------------------
+
+xapi.py uses a simple python configuration file similar to xm in the
+face of the lack of any other reasonable format.
+
+All the fields are directly mapped to the arguments that are in the
+Xen API constructore for the respective classes.
+
+xapi.domcfg.py: example configuration for a paravirtualised domain.
+xapi.vbdcfg.py: example configuration for a file based block device.
+xapi.vifcfg.py: example configuration for a simple bridged network
+ device.
+
+Example Session
+---------------
+
+xapi.py vm-list
+xapi.py vm-create xapi.domcfg.py
+xapi.py vbd-create <DomainName> xapi.vbdcfg.py
+xapi.py vif-create <DomainName> xapi.vifcfg.py
+
+Notes
+-----
+
+Currently lacking:
+
+1. Any real authentication. XendAuthSessions need to be filled in with
+ a proper authentication implementation either using PAM or other
+ means.
+
diff --git a/tools/python/scripts/README.lifecycle b/tools/python/scripts/README.lifecycle
new file mode 100644
index 0000000000..1e24cc03df
--- /dev/null
+++ b/tools/python/scripts/README.lifecycle
@@ -0,0 +1,136 @@
+Xend Lifecycle/XenAPI Implementation Changes
+============================================
+
+Summary of what has changed in this branch of Xend:
+
+Managed Domains
+---------------
+
+The concept of managed domains is that Xend now has the ability to
+manage the lifecycle of a domain from when it is created to being
+shutdown.
+
+XendDomain
+~~~~~~~~~~
+
+In order to support managed domains, XendDomain has been modified to
+keep the configuration in /var/lib/xend/domains/.
+
+The configuration is stored in SXP format so that it can be easily
+loaded by the current Xend. In the future, we may switch to an XML
+format similar to how XenAPI defines a VM configuration.
+
+TODO: There are still places where the device configuration or VM
+configuration can be altered but the managed domain does not save it.
+
+XendDomainInfo
+~~~~~~~~~~~~~~
+
+XendDomainInfo has changed to support this mode of operation,
+especially with domain construction and assumptions about the domain
+when it shuts down.
+
+All configuration option parsing and validation has been moved from
+XendDomainInfo to XendConfig. The purpose is so that we can abstract
+away the knowledge of SXP in XendDomainInfo. The goal is to do away
+with the bulky way of accessing SXP in Xend and moving that all to a
+more pythonic interface.
+
+The DevController stuff at the end of XendDomainInfo has also been
+moved to XendDevices because now it is needed in both XendConfig and
+XendDomainInfo.
+
+Many of the constants are moved to XendConstants which reduces the
+amount of recursive or scoped imports that occur in the code.
+
+XendConfig
+~~~~~~~~~~
+
+XendConfig is the beginnings of an interface for configuration options
+so that other parts of Xend do not need to know what format the
+configuration in. It can accept configuration passed in as parsed SXP
+format, python filename or a Xen API struct.
+
+It is a subclass of a python dictionary, and hence access to its
+functions are via the __getitem__ accessor.
+
+TODO: Define a proper interface to the XendConfig which is based on
+either the Xen API or some other flexible format.
+
+XMLRPCServer
+~~~~~~~~~~~~
+
+Changes to the busy loop in here and SrvServer so that the daemon
+shuts down cleanly. This also allows us to catch the shutdown and
+perform maintanence tasks on the domains.
+
+Replacing xendomains init.d script
+==================================
+
+Some work has gone into catching Xend's shutdown so that we can do the
+same tasks that xendomains init.d script does but natively in Xend.
+
+For instance, a new configuration option, 'on_xend_start' and
+'on_xend_stop' will allow domains that are managed by Xend to start up
+when Xend starts, and correspondingly stop when Xend stops.
+
+Xen API
+=======
+
+The new Xen API gives a standard interface to creating, configuring,
+controlling and destroying VMs and the virtual devices that belong to
+it.
+
+It also introduces the concept of Storage Repositories (SR) which are
+factories for creating disk images.
+
+XendDomain
+~~~~~~~~~~
+
+XendDomain has now separated the section for the Legacy XM XMLRPC API
+and the new Xen API.
+
+Since many things have a UUID, these are stored and represented as
+close to the existing configuration.
+
+XendDomainInfo
+~~~~~~~~~~~~~~
+
+XendDomainInfo now supports UUIDs being assigned to devices and the
+domain itself. It will preserve the UUID for managed domains.
+
+A number of new functions are now in XendDomainInfo to provide an
+interface to devices.
+
+XendNode
+~~~~~~~~
+
+Represents the Host class in the Xen API and also contains an
+incomplete representation of the physical CPUs availabel for the host.
+
+XendAuthSessions
+~~~~~~~~~~~~~~~~
+
+An abstract authenticator for the Xen API. Currently it is an empty
+implementation with rudimentary support for users. The plan is the add
+PAM based authentication.
+
+XendAPI
+~~~~~~~
+
+The guts of the Xen API implementation. Implements all the supported
+functionality of the Xen API by placing calls to the relevent objects
+like XendDomain and XendDomanInfo.
+
+The initialisation of the XendAPI object will actually install a
+number of validation decorators in order to ensure the input is
+correct. It is using some features of introspection and
+metaprogramming in Python to reduce the amount of replication in the
+code.
+
+XMLRPCServer
+~~~~~~~~~~~~
+
+The XMLRPC Server will support both the new Xen API and the old XM
+XMLRPC API. The support is clearly marked in the code.
+
diff --git a/tools/python/scripts/xapi.domcfg.py b/tools/python/scripts/xapi.domcfg.py
new file mode 100644
index 0000000000..8565bd8975
--- /dev/null
+++ b/tools/python/scripts/xapi.domcfg.py
@@ -0,0 +1,37 @@
+#
+# VM Configuration for Xen API
+#
+
+name_label = 'GentooAPI'
+name_description = 'Gentoo VM via API'
+user_version = 1
+is_a_template = False
+memory_static_max = 32
+memory_dynamic_max = 32
+memory_dynamic_min = 32
+memory_static_min = 32
+VCPUs_policy = ''
+VCPUs_params = ''
+VCPUS_features_required = ''
+VCPUs_features_can_use = ''
+VCPUs_features_force_on = ''
+VCPUs_features_force_off = ''
+actions_after_shutdown = 'destroy'
+actions_after_reboot = 'restart'
+actions_after_suspend = 'destroy'
+actions_after_crash = 'restart'
+bios_boot = ''
+platform_std_VGA = False
+platform_serial = ''
+platform_localtime = False
+platform_clock_offset = False
+platform_enable_audio = False
+builder = ''
+boot_method = '' # this will remove the kernel/initrd ??
+kernel_kernel = '/boot/vmlinuz-2.6.16.29-xen'
+kernel_initrd = '/root/initrd-2.6.16.29-xen.img'
+kernel_args = 'root=/dev/sda1 ro'
+grub_cmdline = ''
+PCI_bus = ''
+other_config = ''
+
diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py
new file mode 100644
index 0000000000..387ad0a487
--- /dev/null
+++ b/tools/python/scripts/xapi.py
@@ -0,0 +1,537 @@
+#!/usr/bin/python
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+
+import sys
+sys.path.append('/usr/lib/python')
+
+from xen.util.xmlrpclib2 import ServerProxy
+from optparse import *
+from pprint import pprint
+from types import DictType
+from getpass import getpass
+
+
+MB = 1024 * 1024
+
+HOST_INFO_FORMAT = '%-20s: %-50s'
+VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(vcpus_number)-5s'\
+ ' %(power_state)-10s %(uuid)-36s'
+SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
+ '%(type)-10s'
+VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
+ '%(sector_size)-8s'
+
+COMMANDS = {
+ 'host-info': ('', 'Get Xen Host Info'),
+ 'host-set-name': ('', 'Set host name'),
+ 'sr-list': ('', 'List all SRs'),
+ 'vbd-create': ('<domname> <pycfg> [opts]',
+ 'Create VBD attached to domname'),
+ 'vdi-create': ('<pycfg> [opts]', 'Create a VDI'),
+ 'vdi-list' : ('', 'List all VDI'),
+ 'vdi-rename': ('<vdi_uuid> <new_name>', 'Rename VDI'),
+ 'vdi-delete': ('<vdi_uuid>', 'Delete VDI'),
+ 'vif-create': ('<domname> <pycfg>', 'Create VIF attached to domname'),
+ 'vtpm-create' : ('<domname> <pycfg>', 'Create VTPM attached to domname'),
+
+ 'vm-create': ('<pycfg>', 'Create VM with python config'),
+ 'vm-destroy': ('<domname>', 'Delete VM'),
+
+ 'vm-list': ('[--long]', 'List all domains.'),
+ 'vm-name': ('<uuid>', 'Name of UUID.'),
+ 'vm-shutdown': ('<name> [opts]', 'Shutdown VM with name'),
+ 'vm-start': ('<name>', 'Start VM with name'),
+ 'vm-uuid': ('<name>', 'UUID of a domain by name.'),
+}
+
+OPTIONS = {
+ 'vm-list': [(('-l', '--long'),
+ {'action':'store_true',
+ 'help':'List all properties of VMs'})
+ ],
+ 'vm-shutdown': [(('-f', '--force'), {'help': 'Shutdown Forcefully',
+ 'action': 'store_true'})],
+
+ 'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
+ (('--description',), {'help': 'Description for VDI'}),
+ (('--sector-size',), {'type': 'int',
+ 'help': 'Sector size'}),
+ (('--virtual-size',), {'type': 'int',
+ 'help': 'Size of VDI in sectors'}),
+ (('--type',), {'choices': ['system', 'user', 'ephemeral'],
+ 'help': 'VDI type'}),
+ (('--sharable',), {'action': 'store_true',
+ 'help': 'VDI sharable'}),
+ (('--read-only',), {'action': 'store_true',
+ 'help': 'Read only'})],
+
+ 'vbd-create': [(('--VDI',), {'help': 'UUID of VDI to attach to.'}),
+ (('--mode',), {'choices': ['RO', 'RW'],
+ 'help': 'device mount mode'}),
+ (('--driver',), {'choices':['paravirtualised', 'ioemu'],
+ 'help': 'Driver for VBD'}),
+ (('--device',), {'help': 'Device name on guest domain'}),
+ (('--image',), {'help': 'Location of drive image.'})]
+
+}
+
+class OptionError(Exception):
+ pass
+
+class XenAPIError(Exception):
+ pass
+
+#
+# Extra utility functions
+#
+
+class IterableValues(Values):
+ """Better interface to the list of values from optparse."""
+
+ def __iter__(self):
+ for opt, val in self.__dict__.items():
+ if opt[0] == '_' or callable(val):
+ continue
+ yield opt, val
+
+
+def parse_args(cmd_name, args, set_defaults = False):
+ argstring, desc = COMMANDS[cmd_name]
+ parser = OptionParser(usage = 'xapi %s %s' % (cmd_name, argstring),
+ description = desc)
+ if cmd_name in OPTIONS:
+ for optargs, optkwds in OPTIONS[cmd_name]:
+ parser.add_option(*optargs, **optkwds)
+
+ if set_defaults:
+ default_values = parser.get_default_values()
+ defaults = IterableValues(default_values.__dict__)
+ else:
+ defaults = IterableValues()
+ (opts, extraargs) = parser.parse_args(args = list(args),
+ values = defaults)
+ return opts, extraargs
+
+def execute(fn, *args):
+ result = fn(*args)
+ if type(result) != DictType:
+ raise TypeError("Function returned object of type: %s" %
+ str(type(result)))
+ if 'Value' not in result:
+ raise XenAPIError(*result['ErrorDescription'])
+ return result['Value']
+
+_initialised = False
+_server = None
+_session = None
+def _connect(*args):
+ global _server, _session, _initialised
+ if not _initialised:
+ _server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock')
+ login = raw_input("Login: ")
+ password = getpass()
+ creds = (login, password)
+ _session = execute(_server.session.login_with_password, *creds)
+ _initialised = True
+ return (_server, _session)
+
+def _stringify(adict):
+ return dict([(k, str(v)) for k, v in adict.items()])
+
+def _read_python_cfg(filename):
+ cfg = {}
+ execfile(filename, {}, cfg)
+ return cfg
+
+def resolve_vm(server, session, vm_name):
+ vm_uuid = execute(server.VM.get_by_name_label, session, vm_name)
+ if not vm_uuid:
+ return None
+ else:
+ return vm_uuid[0]
+
+#
+# Actual commands
+#
+
+def xapi_host_info(*args):
+ server, session = _connect()
+ hosts = execute(server.host.get_all, session)
+ for host in hosts: # there is only one, but ..
+ hostinfo = execute(server.host.get_record, session, host)
+ print HOST_INFO_FORMAT % ('Name', hostinfo['name_label'])
+ print HOST_INFO_FORMAT % ('Version', hostinfo['software_version'])
+ print HOST_INFO_FORMAT % ('CPUs', len(hostinfo['host_CPUs']))
+ print HOST_INFO_FORMAT % ('VMs', len(hostinfo['resident_VMs']))
+ print HOST_INFO_FORMAT % ('UUID', host)
+
+def xapi_host_set_name(*args):
+ if len(args) < 1:
+ raise OptionError("No hostname specified")
+
+ server, session = _connect()
+ hosts = execute(server.host.get_all, session)
+ if len(hosts) > 0:
+ execute(server.host.set_name_label, session, hosts[0], args[0])
+ print 'Hostname: %s' % execute(server.host.get_name_label, session,
+ hosts[0])
+
+def xapi_vm_uuid(*args):
+ if len(args) < 1:
+ raise OptionError("No domain name specified")
+
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, args[0])
+ print vm_uuid
+
+def xapi_vm_name(*args):
+ if len(args) < 1:
+ raise OptionError("No UUID specified")
+
+ server, session = _connect()
+ vm_name = execute(server.VM.get_name_label, session, args[0])
+ print vm_name
+
+def xapi_vm_list(*args):
+ opts, args = parse_args('vm-list', args, set_defaults = True)
+ is_long = opts and opts.long
+
+ server, session = _connect()
+ vm_uuids = execute(server.VM.get_all, session)
+ if not is_long:
+ print VM_LIST_FORMAT % {'name_label':'Name',
+ 'memory_actual':'Mem',
+ 'vcpus_number': 'VCPUs',
+ 'power_state': 'State',
+ 'uuid': 'UUID'}
+
+ for uuid in vm_uuids:
+ vm_info = execute(server.VM.get_record, session, uuid)
+ if is_long:
+ vbds = vm_info['vbds']
+ vifs = vm_info['vifs']
+ vtpms = vm_info['vtpms']
+ vif_infos = []
+ vbd_infos = []
+ vtpm_infos = []
+ for vbd in vbds:
+ vbd_info = execute(server.VBD.get_record, session, vbd)
+ vbd_infos.append(vbd_info)
+ for vif in vifs:
+ vif_info = execute(server.VIF.get_record, session, vif)
+ vif_infos.append(vif_info)
+ for vtpm in vtpms:
+ vtpm_info = execute(server.VTPM.get_record, session, vtpm)
+ vtpm_infos.append(vtpm_info)
+ vm_info['vbds'] = vbd_infos
+ vm_info['vifs'] = vif_infos
+ vm_info['vtpms'] = vtpm_infos
+ pprint(vm_info)
+ else:
+ print VM_LIST_FORMAT % _stringify(vm_info)
+
+def xapi_vm_create(*args):
+ if len(args) < 1:
+ raise OptionError("Configuration file not specified")
+
+ filename = args[0]
+ cfg = _read_python_cfg(filename)
+
+ print 'Creating VM from %s ..' % filename
+ server, session = _connect()
+ uuid = execute(server.VM.create, session, cfg)
+ print 'Done. (%s)' % uuid
+ print uuid
+
+def xapi_vm_destroy(*args):
+ if len(args) < 1:
+ raise OptionError("No domain name specified.")
+
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, args[0])
+ print 'Destroying VM %s (%s)' % (args[0], vm_uuid)
+ success = execute(server.VM.destroy, session, vm_uuid)
+ print 'Done.'
+
+
+def xapi_vm_start(*args):
+ if len(args) < 1:
+ raise OptionError("No Domain name specified.")
+
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, args[0])
+ print 'Starting VM %s (%s)' % (args[0], vm_uuid)
+ success = execute(server.VM.start, session, vm_uuid)
+ print 'Done.'
+
+def xapi_vm_shutdown(*args):
+ opts, args = parse_args("vm-shutdown", args, set_defaults = True)
+
+ if len(args) < 1:
+ raise OptionError("No Domain name specified.")
+
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, args[0])
+ if opts.force:
+ print 'Forcefully shutting down VM %s (%s)' % (args[0], vm_uuid)
+ success = execute(server.VM.hard_shutdown, session, vm_uuid)
+ else:
+ print 'Shutting down VM %s (%s)' % (args[0], vm_uuid)
+ success = execute(server.VM.clean_shutdown, session, vm_uuid)
+ print 'Done.'
+
+def xapi_vbd_create(*args):
+ opts, args = parse_args('vbd-create', args)
+
+ if len(args) < 2:
+ raise OptionError("Configuration file and domain not specified")
+
+ domname = args[0]
+
+ if len(args) > 1:
+ filename = args[1]
+ cfg = _read_python_cfg(filename)
+ else:
+ cfg = {}
+
+ for opt, val in opts:
+ cfg[opt] = val
+
+ print 'Creating VBD ...',
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, domname)
+ cfg['VM'] = vm_uuid
+ vbd_uuid = execute(server.VBD.create, session, cfg)
+ print 'Done. (%s)' % vbd_uuid
+
+def xapi_vif_create(*args):
+ if len(args) < 2:
+ raise OptionError("Configuration file not specified")
+
+ domname = args[0]
+ filename = args[1]
+ cfg = _read_python_cfg(filename)
+
+ print 'Creating VIF from %s ..' % filename
+ server, session = _connect()
+ vm_uuid = resolve_vm(server, session, domname)
+ cfg['VM'] = vm_uuid
+ vif_uuid = execute(server.VIF.create, session, cfg)
+ print 'Done. (%s)' % vif_uuid
+
+def xapi_vdi_list(*args):
+ server, session = _connect()
+ vdis = execute(server.VDI.get_all, session)
+
+ print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
+ 'uuid' : 'UUID',
+ 'virtual_size': 'Sectors',
+ 'sector_size': 'Sector Size'}
+
+ for vdi in vdis:
+ vdi_struct = execute(server.VDI.get_record, session, vdi)
+ print VDI_LIST_FORMAT % vdi_struct
+
+def xapi_sr_list(*args):
+ server, session = _connect()
+ srs = execute(server.SR.get_all, session)
+ print SR_LIST_FORMAT % {'name_label': 'SR Label',
+ 'uuid' : 'UUID',
+ 'physical_size': 'Size',
+ 'type': 'Type'}
+ for sr in srs:
+ sr_struct = execute(server.SR.get_record, session, sr)
+ sr_struct['physical_size'] = int(sr_struct['physical_size'])/MB
+ print SR_LIST_FORMAT % sr_struct
+
+def xapi_vdi_create(*args):
+ opts, args = parse_args('vdi-create', args)
+
+ if len(args) > 0:
+ cfg = _read_python_cfg(args[0])
+ else:
+ cfg = {}
+
+ for opt, val in opts:
+ cfg[opt] = val
+
+ server, session = _connect()
+ srs = execute(server.SR.get_all, session)
+ sr = srs[0]
+ cfg['SR'] = sr
+
+ size = (cfg['virtual_size'] * cfg['sector_size'])/MB
+ print 'Creating VDI of size: %dMB ..' % size,
+ uuid = execute(server.VDI.create, session, cfg)
+ print 'Done. (%s)' % uuid
+
+def xapi_vdi_delete(*args):
+ server, session = _connect()
+ if len(args) < 1:
+ raise OptionError('Not enough arguments')
+
+ vdi_uuid = args[0]
+ print 'Deleting VDI %s' % vdi_uuid
+ result = execute(server.VDI.destroy, session, vdi_uuid)
+ print 'Done.'
+
+def xapi_vdi_rename(*args):
+ server, session = _connect()
+ if len(args) < 2:
+ raise OptionError('Not enough arguments')
+
+ vdi_uuid = args[0]
+ vdi_name = args[1]
+ print 'Renaming VDI %s to %s' % (vdi_uuid, vdi_name)
+ result = execute(server.VDI.set_name_label, session, vdi_uuid, vdi_name)
+ print 'Done.'
+
+
+def xapi_vtpm_create(*args):
+ server, session = _connect()
+ domname = args[0]
+ cfg = _read_python_cfg(args[1])
+
+ vm_uuid = resolve_vm(server, session, domname)
+ cfg['VM'] = vm_uuid
+ print "Creating vTPM with cfg = %s" % cfg
+ vtpm_uuid = execute(server.VTPM.create, session, cfg)
+ print "Done. (%s)" % vtpm_uuid
+ vtpm_id = execute(server.VTPM.get_instance, session, vtpm_uuid)
+ print "Has instance number '%s'" % vtpm_id
+ vtpm_be = execute(server.VTPM.get_backend, session, vtpm_uuid)
+ print "Has backend in '%s'" % vtpm_be
+ driver = execute(server.VTPM.get_driver, session, vtpm_uuid)
+ print "Has driver type '%s'" % driver
+ vtpm_rec = execute(server.VTPM.get_record, session, vtpm_uuid)
+ print "Has vtpm record '%s'" % vtpm_rec
+ vm = execute(server.VTPM.get_VM, session, vtpm_uuid)
+ print "Has VM '%s'" % vm
+
+
+#
+# Command Line Utils
+#
+import cmd
+import shlex
+
+class XenAPICmd(cmd.Cmd):
+ def __init__(self, server, session):
+ cmd.Cmd.__init__(self)
+ self.server = server
+ self.session = session
+ self.prompt = ">>> "
+
+ def default(self, line):
+ words = shlex.split(line)
+ if len(words) > 0:
+ cmd_name = words[0].replace('-', '_')
+ func_name = 'xapi_%s' % cmd_name
+ func = globals().get(func_name)
+ if func:
+ try:
+ args = tuple(words[1:])
+ func(*args)
+ return True
+ except SystemExit:
+ return False
+ except OptionError, e:
+ print 'Error:', str(e)
+ return False
+ except Exception, e:
+ import traceback
+ traceback.print_exc()
+ return False
+ print '*** Unknown command: %s' % words[0]
+ return False
+
+ def do_EOF(self, line):
+ print
+ sys.exit(0)
+
+ def do_help(self, line):
+ usage(print_usage = False)
+
+ def emptyline(self):
+ pass
+
+ def postcmd(self, stop, line):
+ return False
+
+ def precmd(self, line):
+ words = shlex.split(line)
+ if len(words) > 0:
+ words0 = words[0].replace('-', '_')
+ return ' '.join([words0] + words[1:])
+ else:
+ return line
+
+def shell():
+ server, session = _connect()
+ x = XenAPICmd(server, session)
+ x.cmdloop('Xen API Prompt. Type "help" for a list of functions')
+
+def usage(command = None, print_usage = True):
+ if not command:
+ if print_usage:
+ print 'Usage: xapi <subcommand> [options] [args]'
+ print
+ print 'Subcommands:'
+ print
+ sorted_commands = sorted(COMMANDS.keys())
+ for command in sorted_commands:
+ args, description = COMMANDS[command]
+ print '%-16s %-40s' % (command, description)
+ print
+ else:
+ parse_args(command, ['-h'])
+
+def main(args):
+
+ if len(args) < 1 or args[0] in ('-h', '--help', 'help'):
+ usage()
+ sys.exit(1)
+
+ subcmd = args[0]
+ subcmd_func_name = 'xapi_' + subcmd.replace('-', '_')
+ subcmd_func = globals().get(subcmd_func_name, None)
+
+ if subcmd == 'shell':
+ shell()
+ elif not subcmd_func or not callable(subcmd_func):
+ print 'Error: Unable to find subcommand \'%s\'' % subcmd
+ usage()
+ sys.exit(1)
+
+ if '-h' in args[1:] or '--help' in args[1:]:
+ usage(subcmd)
+ sys.exit(1)
+
+ try:
+ subcmd_func(*args[1:])
+ except XenAPIError, e:
+ print 'Error: %s' % str(e.args[1])
+ sys.exit(2)
+ except OptionError, e:
+ print 'Error: %s' % e
+
+ sys.exit(0)
+
+if __name__ == "__main__":
+ import sys
+ main(sys.argv[1:])
diff --git a/tools/python/scripts/xapi.vbdcfg.py b/tools/python/scripts/xapi.vbdcfg.py
new file mode 100644
index 0000000000..82dcaf8ba7
--- /dev/null
+++ b/tools/python/scripts/xapi.vbdcfg.py
@@ -0,0 +1,12 @@
+#
+# Virtual Block Device (VBD) Xen API Configuration
+#
+# Note: There is a non-API field here called "image" which is a backwards
+# compat addition so you can mount to old images.
+#
+
+VDI = ''
+device = 'sda1'
+mode = 'RW'
+driver = 'paravirtualised'
+image = 'file:/root/gentoo.amd64.img'
diff --git a/tools/python/scripts/xapi.vdicfg.py b/tools/python/scripts/xapi.vdicfg.py
new file mode 100644
index 0000000000..f694b83cf5
--- /dev/null
+++ b/tools/python/scripts/xapi.vdicfg.py
@@ -0,0 +1,7 @@
+name_label = 'VDI 1'
+name_description = ''
+virtual_size = 10 * 1024
+sector_size = 1024
+type = 'system'
+sharable = False
+read_only = False
diff --git a/tools/python/scripts/xapi.vifcfg.py b/tools/python/scripts/xapi.vifcfg.py
new file mode 100644
index 0000000000..f42122409b
--- /dev/null
+++ b/tools/python/scripts/xapi.vifcfg.py
@@ -0,0 +1,10 @@
+#
+# Virtual Network Interface Configuration for the Xen API
+#
+
+name = ''
+type = 'paravirtualised'
+#device = 'eth0' # this is the dom0 device, not domU!
+network = '' # ignored
+MAC = ''
+MTU = '1500'
diff --git a/tools/python/scripts/xapi.vtpmcfg.py b/tools/python/scripts/xapi.vtpmcfg.py
new file mode 100644
index 0000000000..7c419baa26
--- /dev/null
+++ b/tools/python/scripts/xapi.vtpmcfg.py
@@ -0,0 +1,3 @@
+type = 'paravirtualised'
+backend = 'Domain-0'
+instance = 1
diff --git a/tools/python/setup.py b/tools/python/setup.py
index 640dcef000..56dd3e4a0b 100644
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -4,8 +4,7 @@ import os
XEN_ROOT = "../.."
-extra_compile_args = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
-
+extra_compile_args = [ "-fno-strict-aliasing", "-Werror" ]
include_dirs = [ XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/xenstore",
diff --git a/tools/python/xen/lowlevel/acm/acm.c b/tools/python/xen/lowlevel/acm/acm.c
index ec39b60bb4..930c568212 100644
--- a/tools/python/xen/lowlevel/acm/acm.c
+++ b/tools/python/xen/lowlevel/acm/acm.c
@@ -147,9 +147,10 @@ static PyObject *getdecision(PyObject * self, PyObject * args)
{
char *arg1_name, *arg1, *arg2_name, *arg2, *decision = NULL;
struct acm_getdecision getdecision;
- int xc_handle;
+ int xc_handle, rc;
- if (!PyArg_ParseTuple(args, "ssss", &arg1_name, &arg1, &arg2_name, &arg2)) {
+ if (!PyArg_ParseTuple(args, "ssss", &arg1_name,
+ &arg1, &arg2_name, &arg2)) {
return NULL;
}
@@ -179,13 +180,17 @@ static PyObject *getdecision(PyObject * self, PyObject * args)
getdecision.id2.ssidref = atol(arg2);
}
- if (xc_acm_op(xc_handle, ACMOP_getdecision, &getdecision, sizeof(getdecision)) < 0) {
+ rc = xc_acm_op(xc_handle, ACMOP_getdecision,
+ &getdecision, sizeof(getdecision));
+
+ xc_interface_close(xc_handle);
+
+ if (rc < 0) {
if (errno == EACCES)
PERROR("ACM operation failed.");
+ return NULL;
}
- xc_interface_close(xc_handle);
-
if (getdecision.acm_decision == ACM_ACCESS_PERMITTED)
decision = "PERMITTED";
else if (getdecision.acm_decision == ACM_ACCESS_DENIED)
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 3137623505..2df6beaa54 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -13,10 +13,13 @@
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/mman.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "xenctrl.h"
+#include <xen/hvm/hvm_info_table.h>
+#include <xen/hvm/params.h>
/* Needed for Python versions earlier than 2.3. */
#ifndef PyMODINIT_FUNC
@@ -65,18 +68,17 @@ static PyObject *pyxc_domain_create(XcObject *self,
PyObject *args,
PyObject *kwds)
{
- uint32_t dom = 0;
- int ret, i;
- uint32_t ssidref = 0;
+ uint32_t dom = 0, ssidref = 0, flags = 0;
+ int ret, i, hvm = 0;
PyObject *pyhandle = NULL;
xen_domain_handle_t handle = {
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef };
- static char *kwd_list[] = { "dom", "ssidref", "handle", NULL };
+ static char *kwd_list[] = { "domid", "ssidref", "handle", "hvm", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiO", kwd_list,
- &dom, &ssidref, &pyhandle))
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiOi", kwd_list,
+ &dom, &ssidref, &pyhandle, &hvm))
return NULL;
if ( pyhandle != NULL )
@@ -94,7 +96,11 @@ static PyObject *pyxc_domain_create(XcObject *self,
}
}
- if ( (ret = xc_domain_create(self->xc_handle, ssidref, handle, &dom)) < 0 )
+ if ( hvm )
+ flags |= XEN_DOMCTL_CDF_hvm_guest;
+
+ if ( (ret = xc_domain_create(self->xc_handle, ssidref,
+ handle, flags, &dom)) < 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(dom);
@@ -144,7 +150,7 @@ static PyObject *pyxc_vcpu_setaffinity(XcObject *self,
uint64_t cpumap = ~0ULL;
PyObject *cpulist = NULL;
- static char *kwd_list[] = { "dom", "vcpu", "cpumap", NULL };
+ static char *kwd_list[] = { "domid", "vcpu", "cpumap", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|iO", kwd_list,
&dom, &vcpu, &cpulist) )
@@ -171,7 +177,7 @@ static PyObject *pyxc_domain_setcpuweight(XcObject *self,
uint32_t dom;
float cpuweight = 1;
- static char *kwd_list[] = { "dom", "cpuweight", NULL };
+ static char *kwd_list[] = { "domid", "cpuweight", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|f", kwd_list,
&dom, &cpuweight) )
@@ -254,11 +260,12 @@ static PyObject *pyxc_domain_getinfo(XcObject *self,
PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t));
for ( j = 0; j < sizeof(xen_domain_handle_t); j++ )
PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j]));
- info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
+ info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
",s:l,s:L,s:l,s:i,s:i}",
- "dom", info[i].domid,
+ "domid", info[i].domid,
"online_vcpus", info[i].nr_online_vcpus,
"max_vcpu_id", info[i].max_vcpu_id,
+ "hvm", info[i].hvm,
"dying", info[i].dying,
"crashed", info[i].crashed,
"shutdown", info[i].shutdown,
@@ -291,7 +298,7 @@ static PyObject *pyxc_vcpu_getinfo(XcObject *self,
int rc, i;
uint64_t cpumap;
- static char *kwd_list[] = { "dom", "vcpu", NULL };
+ static char *kwd_list[] = { "domid", "vcpu", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
&dom, &vcpu) )
@@ -331,24 +338,25 @@ static PyObject *pyxc_linux_build(XcObject *self,
char *image, *ramdisk = NULL, *cmdline = "", *features = NULL;
int flags = 0;
int store_evtchn, console_evtchn;
+ unsigned int mem_mb;
unsigned long store_mfn = 0;
unsigned long console_mfn = 0;
- static char *kwd_list[] = { "dom", "store_evtchn",
+ static char *kwd_list[] = { "domid", "store_evtchn", "memsize",
"console_evtchn", "image",
/* optional */
"ramdisk", "cmdline", "flags",
"features", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssis", kwd_list,
- &dom, &store_evtchn,
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiis|ssis", kwd_list,
+ &dom, &store_evtchn, &mem_mb,
&console_evtchn, &image,
/* optional */
&ramdisk, &cmdline, &flags,
&features) )
return NULL;
- if ( xc_linux_build(self->xc_handle, dom, image,
+ if ( xc_linux_build(self->xc_handle, dom, mem_mb, image,
ramdisk, cmdline, features, flags,
store_evtchn, &store_mfn,
console_evtchn, &console_mfn) != 0 ) {
@@ -366,26 +374,45 @@ static PyObject *pyxc_hvm_build(XcObject *self,
PyObject *kwds)
{
uint32_t dom;
+ struct hvm_info_table *va_hvm;
+ uint8_t *va_map, sum;
char *image;
- int store_evtchn;
- int memsize;
- int vcpus = 1;
- int pae = 0;
- int acpi = 0;
- int apic = 0;
- unsigned long store_mfn = 0;
+ int i, store_evtchn, memsize, vcpus = 1, pae = 0, acpi = 0, apic = 1;
+ unsigned long store_mfn;
- static char *kwd_list[] = { "dom", "store_evtchn", "memsize", "image",
- "vcpus", "pae", "acpi", "apic",
- NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiisiiii", kwd_list,
+ static char *kwd_list[] = { "domid", "store_evtchn",
+ "memsize", "image", "vcpus", "pae", "acpi",
+ "apic", NULL };
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|iiii", kwd_list,
&dom, &store_evtchn, &memsize,
&image, &vcpus, &pae, &acpi, &apic) )
return NULL;
- if ( xc_hvm_build(self->xc_handle, dom, memsize, image,
- vcpus, pae, acpi, apic, store_evtchn, &store_mfn) != 0 )
+ if ( xc_hvm_build(self->xc_handle, dom, memsize, image) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ /* Set up the HVM info table. */
+ va_map = xc_map_foreign_range(self->xc_handle, dom, PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ HVM_INFO_PFN);
+ if ( va_map == NULL )
return PyErr_SetFromErrno(xc_error);
+ va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
+ memset(va_hvm, 0, sizeof(*va_hvm));
+ strncpy(va_hvm->signature, "HVM INFO", 8);
+ va_hvm->length = sizeof(struct hvm_info_table);
+ va_hvm->acpi_enabled = acpi;
+ va_hvm->apic_mode = apic;
+ va_hvm->nr_vcpus = vcpus;
+ for ( i = 0, sum = 0; i < va_hvm->length; i++ )
+ sum += ((uint8_t *)va_hvm)[i];
+ va_hvm->checksum = -sum;
+ munmap(va_map, PAGE_SIZE);
+
+ xc_get_hvm_param(self->xc_handle, dom, HVM_PARAM_STORE_PFN, &store_mfn);
+ xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae);
+ xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_STORE_EVTCHN,
+ store_evtchn);
return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
}
@@ -397,7 +424,7 @@ static PyObject *pyxc_evtchn_alloc_unbound(XcObject *self,
uint32_t dom, remote_dom;
int port;
- static char *kwd_list[] = { "dom", "remote_dom", NULL };
+ static char *kwd_list[] = { "domid", "remote_dom", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
&dom, &remote_dom) )
@@ -416,7 +443,7 @@ static PyObject *pyxc_physdev_pci_access_modify(XcObject *self,
uint32_t dom;
int bus, dev, func, enable, ret;
- static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL };
+ static char *kwd_list[] = { "domid", "bus", "dev", "func", "enable", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list,
&dom, &bus, &dev, &func, &enable) )
@@ -557,7 +584,7 @@ static PyObject *pyxc_sedf_domain_set(XcObject *self,
uint32_t domid;
uint64_t period, slice, latency;
uint16_t extratime, weight;
- static char *kwd_list[] = { "dom", "period", "slice",
+ static char *kwd_list[] = { "domid", "period", "slice",
"latency", "extratime", "weight",NULL };
if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLhh", kwd_list,
@@ -586,7 +613,7 @@ static PyObject *pyxc_sedf_domain_get(XcObject *self, PyObject *args)
return PyErr_SetFromErrno(xc_error);
return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i,s:i}",
- "domain", domid,
+ "domid", domid,
"period", period,
"slice", slice,
"latency", latency,
@@ -647,6 +674,15 @@ static PyObject *pyxc_shadow_mem_control(PyObject *self,
return Py_BuildValue("i", mbarg);
}
+static PyObject *pyxc_sched_id_get(XcObject *self) {
+
+ int sched_id;
+ if (xc_sched_id(self->xc_handle, &sched_id) != 0)
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("i", sched_id);
+}
+
static PyObject *pyxc_sched_credit_domain_set(XcObject *self,
PyObject *args,
PyObject *kwds)
@@ -654,7 +690,7 @@ static PyObject *pyxc_sched_credit_domain_set(XcObject *self,
uint32_t domid;
uint16_t weight;
uint16_t cap;
- static char *kwd_list[] = { "dom", "weight", "cap", NULL };
+ static char *kwd_list[] = { "domid", "weight", "cap", NULL };
static char kwd_type[] = "I|HH";
struct xen_domctl_sched_credit sdom;
@@ -714,7 +750,7 @@ static PyObject *pyxc_domain_memory_increase_reservation(XcObject *self,
unsigned int extent_order = 0 , address_bits = 0;
unsigned long nr_extents;
- static char *kwd_list[] = { "dom", "mem_kb", "extent_order", "address_bits", NULL };
+ static char *kwd_list[] = { "domid", "mem_kb", "extent_order", "address_bits", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "il|ii", kwd_list,
&dom, &mem_kb, &extent_order, &address_bits) )
@@ -739,7 +775,7 @@ static PyObject *pyxc_domain_ioport_permission(XcObject *self,
uint32_t dom;
int first_port, nr_ports, allow_access, ret;
- static char *kwd_list[] = { "dom", "first_port", "nr_ports", "allow_access", NULL };
+ static char *kwd_list[] = { "domid", "first_port", "nr_ports", "allow_access", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiii", kwd_list,
&dom, &first_port, &nr_ports, &allow_access) )
@@ -762,7 +798,7 @@ static PyObject *pyxc_domain_irq_permission(PyObject *self,
uint32_t dom;
int pirq, allow_access, ret;
- static char *kwd_list[] = { "dom", "pirq", "allow_access", NULL };
+ static char *kwd_list[] = { "domid", "pirq", "allow_access", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list,
&dom, &pirq, &allow_access) )
@@ -785,7 +821,7 @@ static PyObject *pyxc_domain_iomem_permission(PyObject *self,
uint32_t dom;
unsigned long first_pfn, nr_pfns, allow_access, ret;
- static char *kwd_list[] = { "dom", "first_pfn", "nr_pfns", "allow_access", NULL };
+ static char *kwd_list[] = { "domid", "first_pfn", "nr_pfns", "allow_access", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illi", kwd_list,
&dom, &first_pfn, &nr_pfns, &allow_access) )
@@ -976,6 +1012,12 @@ static PyMethodDef pyxc_methods[] = {
" vcpus [int, 1]: Number of Virtual CPUS in domain.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
+ { "sched_id_get",
+ (PyCFunction)pyxc_sched_id_get,
+ METH_NOARGS, "\n"
+ "Get the current scheduler type in use.\n"
+ "Returns: [int] sched_id.\n" },
+
{ "sedf_domain_set",
(PyCFunction)pyxc_sedf_domain_set,
METH_KEYWORDS, "\n"
@@ -1242,6 +1284,11 @@ PyMODINIT_FUNC initxc(void)
Py_INCREF(xc_error);
PyModule_AddObject(m, "Error", xc_error);
+
+ /* Expose some libxc constants to Python */
+ PyModule_AddIntConstant(m, "XEN_SCHEDULER_SEDF", XEN_SCHEDULER_SEDF);
+ PyModule_AddIntConstant(m, "XEN_SCHEDULER_CREDIT", XEN_SCHEDULER_CREDIT);
+
}
diff --git a/tools/python/xen/util/auxbin.py b/tools/python/xen/util/auxbin.py
index 50450773dd..5d2066157c 100644
--- a/tools/python/xen/util/auxbin.py
+++ b/tools/python/xen/util/auxbin.py
@@ -21,7 +21,7 @@ LIB_64 = "/usr/lib64"
LIB_BIN_SUFFIX = "xen/bin"
## The architectures on which the LIB_64 directory is used. This
-# deliberately excludes ia64 and ppc64.
+# deliberately excludes ia64 and ppc64, and Solaris.
LIB_64_ARCHS = [ 'x86_64', 's390x', 'sparc64']
diff --git a/tools/python/xen/util/blkif.py b/tools/python/xen/util/blkif.py
index f877f65f90..363bd41dd2 100644
--- a/tools/python/xen/util/blkif.py
+++ b/tools/python/xen/util/blkif.py
@@ -7,7 +7,7 @@ from xen.xend.XendLogging import log
def expand_dev_name(name):
if not name:
return name
- if re.match( '^/dev/', name ):
+ if re.match( '^/', name ):
return name
else:
return '/dev/' + name
@@ -21,11 +21,17 @@ def blkdev_name_to_number(name):
try:
return os.stat(n).st_rdev
except Exception, ex:
- log.debug("exception looking up device number for %s: %s", name, ex)
pass
- if re.match( '/dev/sd[a-p]([1-9]|1[0-5])?', n):
- return 8 * 256 + 16 * (ord(n[7:8]) - ord('a')) + int(n[8:] or 0)
+ scsi_major = [ 8, 65, 66, 67, 68, 69, 70, 71, 128, 129, 130, 131, 132, 133, 134, 135 ]
+ if re.match( '/dev/sd[a-z]([1-9]|1[0-5])?$', n):
+ major = scsi_major[(ord(n[7:8]) - ord('a')) / 16]
+ minor = ((ord(n[7:8]) - ord('a')) % 16) * 16 + int(n[8:] or 0)
+ return major * 256 + minor
+ if re.match( '/dev/sd[a-i][a-z]([1-9]|1[0-5])?$', n):
+ major = scsi_major[((ord(n[7:8]) - ord('a') + 1) * 26 + (ord(n[8:9]) - ord('a'))) / 16 ]
+ minor = (((ord(n[7:8]) - ord('a') + 1 ) * 26 + (ord(n[8:9]) - ord('a'))) % 16) * 16 + int(n[9:] or 0)
+ return major * 256 + minor
if re.match( '/dev/hd[a-t]([1-9]|[1-5][0-9]|6[0-3])?', n):
ide_majors = [ 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 ]
@@ -53,7 +59,7 @@ def blkdev_segment(name):
"""
val = None
n = blkdev_name_to_number(name)
- if n:
+ if not n is None:
val = { 'device' : n,
'start_sector' : long(0),
'nr_sectors' : long(1L<<63),
@@ -64,9 +70,11 @@ def blkdev_uname_to_file(uname):
"""Take a blkdev uname and return the corresponding filename."""
fn = None
if uname.find(":") != -1:
- (typ, fn) = uname.split(":")
- if typ == "phy" and not fn.startswith("/dev/"):
+ (typ, fn) = uname.split(":", 1)
+ if typ == "phy" and not fn.startswith("/"):
fn = "/dev/%s" %(fn,)
+ if typ == "tap":
+ (typ, fn) = fn.split(":", 1)
return fn
def mount_mode(name):
diff --git a/tools/python/xen/util/security.py b/tools/python/xen/util/security.py
index 015de985b1..9957e7f586 100644
--- a/tools/python/xen/util/security.py
+++ b/tools/python/xen/util/security.py
@@ -31,6 +31,7 @@ from xen.util import dictio
policy_dir_prefix = "/etc/xen/acm-security/policies"
res_label_filename = policy_dir_prefix + "/resource_labels"
boot_filename = "/boot/grub/menu.lst"
+altboot_filename = "/boot/grub/grub.conf"
xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
xensec_tool = "/usr/sbin/xensec_tool"
@@ -596,12 +597,49 @@ def get_res_security_details(resource):
return (label, ssidref, policy)
+def unify_resname(resource):
+ """Makes all resource locations absolute. In case of physical
+ resources, '/dev/' is added to local file names"""
+
+ if not resource:
+ return resource
+
+ # sanity check on resource name
+ try:
+ (type, resfile) = resource.split(":", 1)
+ except:
+ err("Resource spec '%s' contains no ':' delimiter" % resource)
+
+ if type == "tap":
+ try:
+ (subtype, resfile) = resfile.split(":")
+ except:
+ err("Resource spec '%s' contains no tap subtype" % resource)
+
+ if type in ["phy", "tap"]:
+ if not resfile.startswith("/"):
+ resfile = "/dev/" + resfile
+
+ #file: resources must specified with absolute path
+ if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
+ err("Invalid resource.")
+
+ # from here on absolute file names with resources
+ if type == "tap":
+ type = type + ":" + subtype
+ resource = type + ":" + resfile
+ return resource
+
+
def res_security_check(resource, domain_label):
"""Checks if the given resource can be used by the given domain
label. Returns 1 if the resource can be used, otherwise 0.
"""
rtnval = 1
+ #build canonical resource name
+ resource = unify_resname(resource)
+
# if security is on, ask the hypervisor for a decision
if on():
(label, ssidref, policy) = get_res_security_details(resource)
diff --git a/tools/python/xen/util/xmlrpclib2.py b/tools/python/xen/util/xmlrpclib2.py
index b353b1cf00..3a3973f838 100644
--- a/tools/python/xen/util/xmlrpclib2.py
+++ b/tools/python/xen/util/xmlrpclib2.py
@@ -21,15 +21,16 @@ An enhanced XML-RPC client/server interface for Python.
"""
import string
-import types
import fcntl
+from types import *
+
from httplib import HTTPConnection, HTTP
-from xmlrpclib import Transport
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import SocketServer
import xmlrpclib, socket, os, stat
+from xen.web import connection
from xen.xend.XendLogging import log
try:
@@ -40,6 +41,23 @@ except ImportError:
# package.
ssh_enabled = False
+#
+# Convert all integers to strings as described in the Xen API
+#
+
+
+def stringify(value):
+ if isinstance(value, IntType) and not isinstance(value, BooleanType):
+ return str(value)
+ elif isinstance(value, DictType):
+ for k, v in value.items():
+ value[k] = stringify(v)
+ return value
+ elif isinstance(value, (TupleType, ListType)):
+ return [stringify(v) for v in value]
+ else:
+ return value
+
# A new ServerProxy that also supports httpu urls. An http URL comes in the
# form:
@@ -53,6 +71,11 @@ except ImportError:
class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
protocol_version = "HTTP/1.1"
+ def __init__(self, hosts_allowed, request, client_address, server):
+ self.hosts_allowed = hosts_allowed
+ SimpleXMLRPCRequestHandler.__init__(self, request, client_address,
+ server)
+
# this is inspired by SimpleXMLRPCRequestHandler's do_POST but differs
# in a few non-trivial ways
# 1) we never generate internal server errors. We let the exception
@@ -60,6 +83,11 @@ class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
# 2) we don't bother checking for a _dispatch function since we don't
# use one
def do_POST(self):
+ addrport = self.client_address
+ if not connection.hostAllowed(addrport, self.hosts_allowed):
+ self.connection.shutdown(1)
+ return
+
data = self.rfile.read(int(self.headers["content-length"]))
rsp = self.server._marshaled_dispatch(data)
@@ -81,18 +109,18 @@ class HTTPUnixConnection(HTTPConnection):
class HTTPUnix(HTTP):
_connection_class = HTTPUnixConnection
-class UnixTransport(Transport):
+class UnixTransport(xmlrpclib.Transport):
def request(self, host, handler, request_body, verbose=0):
self.__handler = handler
- return Transport.request(self, host, '/RPC2', request_body, verbose)
+ return xmlrpclib.Transport.request(self, host, '/RPC2',
+ request_body, verbose)
def make_connection(self, host):
return HTTPUnix(self.__handler)
# See _marshalled_dispatch below.
def conv_string(x):
- if (isinstance(x, types.StringType) or
- isinstance(x, unicode)):
+ if isinstance(x, StringTypes):
s = string.replace(x, "'", r"\047")
exec "s = '" + s + "'"
return s
@@ -133,9 +161,14 @@ class ServerProxy(xmlrpclib.ServerProxy):
class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
allow_reuse_address = True
- def __init__(self, addr, requestHandler=XMLRPCRequestHandler,
- logRequests=1):
- SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
+ def __init__(self, addr, allowed, requestHandler=None,
+ logRequests = 1):
+ if requestHandler is None:
+ requestHandler = XMLRPCRequestHandler
+ SimpleXMLRPCServer.__init__(self, addr,
+ (lambda x, y, z:
+ requestHandler(allowed, x, y, z)),
+ logRequests)
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
@@ -169,8 +202,7 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
# to transmit the string using Python encoding.
# Thanks to David Mertz <mertz@gnosis.cx> for the trick (buried
# in xml_pickle.py).
- if (isinstance(response, types.StringType) or
- isinstance(response, unicode)):
+ if isinstance(response, StringTypes):
response = repr(response)[1:-1]
response = (response,)
@@ -201,7 +233,7 @@ class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
class UnixXMLRPCServer(TCPXMLRPCServer):
address_family = socket.AF_UNIX
- def __init__(self, addr, logRequests):
+ def __init__(self, addr, allowed, logRequests = 1):
parent = os.path.dirname(addr)
if os.path.exists(parent):
os.chown(parent, os.geteuid(), os.getegid())
@@ -210,5 +242,6 @@ class UnixXMLRPCServer(TCPXMLRPCServer):
os.unlink(addr)
else:
os.makedirs(parent, stat.S_IRWXU)
- TCPXMLRPCServer.__init__(self, addr, UnixXMLRPCRequestHandler,
- logRequests)
+
+ TCPXMLRPCServer.__init__(self, addr, allowed,
+ UnixXMLRPCRequestHandler, logRequests)
diff --git a/tools/python/xen/web/connection.py b/tools/python/xen/web/connection.py
index cc3660d538..1bde3d1755 100644
--- a/tools/python/xen/web/connection.py
+++ b/tools/python/xen/web/connection.py
@@ -24,6 +24,8 @@ import fcntl
from errno import EAGAIN, EINTR, EWOULDBLOCK
+from xen.xend.XendLogging import log
+
"""General classes to support server and client sockets, without
specifying what kind of socket they are. There are subclasses
for TCP and unix-domain sockets (see tcp.py and unix.py).
@@ -76,7 +78,7 @@ class SocketListener:
Accepts connections and runs a thread for each one.
"""
- def __init__(self, protocol_class, hosts_allow = ''):
+ def __init__(self, protocol_class):
self.protocol_class = protocol_class
self.sock = self.createSocket()
threading.Thread(target=self.main).start()
@@ -111,3 +113,15 @@ class SocketListener:
break
finally:
self.close()
+
+
+def hostAllowed(addrport, hosts_allowed):
+ if hosts_allowed is None:
+ return True
+ else:
+ fqdn = socket.getfqdn(addrport[0])
+ for h in hosts_allowed:
+ if h.match(fqdn) or h.match(addrport[0]):
+ return True
+ log.warn("Rejected connection from %s (%s).", addrport[0], fqdn)
+ return False
diff --git a/tools/python/xen/web/tcp.py b/tools/python/xen/web/tcp.py
index 552bf4a5cc..5ef94db619 100644
--- a/tools/python/xen/web/tcp.py
+++ b/tools/python/xen/web/tcp.py
@@ -57,20 +57,10 @@ class TCPListener(connection.SocketListener):
def acceptConnection(self, sock, addrport):
addr = addrport[0]
- if self.hosts_allow is None:
- connection.SocketServerConnection(sock, self.protocol_class)
+ if connection.hostAllowed(addrport, self.hosts_allow):
+ connection.SocketServerConnection(sock, self.protocol_class)
else:
- fqdn = socket.getfqdn(addr)
- for h in self.hosts_allow:
- if h.match(fqdn) or h.match(addr):
- log.debug("Match %s %s", fqdn, h.pattern)
- connection.SocketServerConnection(sock,
- self.protocol_class)
- return
-
try:
- log.warn("Rejected connection from %s:%d (%s) for port %d.",
- addr, addrport[1], fqdn, self.port)
sock.close()
except:
pass
diff --git a/tools/python/xen/xend/Args.py b/tools/python/xen/xend/Args.py
index ad6252810d..e2193b6069 100644
--- a/tools/python/xen/xend/Args.py
+++ b/tools/python/xen/xend/Args.py
@@ -18,7 +18,7 @@
import types
import StringIO
-import sxp
+from xen.xend import sxp
class ArgError(StandardError):
pass
diff --git a/tools/python/xen/xend/PrettyPrint.py b/tools/python/xen/xend/PrettyPrint.py
index 2819f02dcf..48135771ac 100644
--- a/tools/python/xen/xend/PrettyPrint.py
+++ b/tools/python/xen/xend/PrettyPrint.py
@@ -22,7 +22,7 @@
import sys
import types
import StringIO
-import sxp
+from xen.xend import sxp
class PrettyItem:
diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py
new file mode 100644
index 0000000000..1a4cc1efc7
--- /dev/null
+++ b/tools/python/xen/xend/XendAPI.py
@@ -0,0 +1,1548 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+
+from xen.xend import XendDomain, XendDomainInfo, XendNode
+from xen.xend import XendLogging
+
+from xen.xend.XendAuthSessions import instance as auth_manager
+from xen.xend.XendAuthSessions import session_required
+from xen.xend.XendError import *
+from xen.xend.XendClient import ERROR_INVALID_DOMAIN
+from xen.xend.XendLogging import log
+
+from xen.xend.XendAPIConstants import *
+from xen.util.xmlrpclib2 import stringify
+
+AUTH_NONE = 'none'
+AUTH_PAM = 'pam'
+
+# ------------------------------------------
+# Utility Methods for Xen API Implementation
+# ------------------------------------------
+
+def xen_api_success(value):
+ """Wraps a return value in XenAPI format."""
+ return {"Status": "Success", "Value": stringify(value)}
+
+def xen_api_success_void():
+ """Return success, but caller expects no return value."""
+ return xen_api_success("")
+
+def xen_api_error(error):
+ """Wraps an error value in XenAPI format."""
+ return {"Status": "Error", "ErrorDescription": error}
+
+def xen_api_todo():
+ """Temporary method to make sure we track down all the TODOs"""
+ return {"Status": "Error", "ErrorDescription": XEND_ERROR_TODO}
+
+# ---------------------------------------------------
+# Python Method Decorators for input value validation
+# ---------------------------------------------------
+
+def trace(func, api_name = ''):
+ """Decorator to trace XMLRPC Xen API methods.
+
+ @param func: function with any parameters
+ @param api_name: name of the api call for debugging.
+ """
+ if hasattr(func, 'api'):
+ api_name = func.api
+ def trace_func(self, *args, **kwargs):
+ log.debug('%s: %s' % (api_name, args))
+ return func(self, *args, **kwargs)
+ trace_func.api = api_name
+ return trace_func
+
+def valid_host(func):
+ """Decorator to verify if host_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, host_ref)
+ @rtype: callable object
+ """
+ def check_host_ref(self, session, host_ref, *args, **kwargs):
+ xennode = XendNode.instance()
+ if type(host_ref) == type(str()) and xennode.is_valid_host(host_ref):
+ return func(self, session, host_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_HOST_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_host_ref.api = func.api
+
+ return check_host_ref
+
+def valid_host_cpu(func):
+ """Decorator to verify if host_cpu_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, host_cpu_ref)
+ @rtype: callable object
+ """
+ def check_host_cpu_ref(self, session, host_cpu_ref, *args, **kwargs):
+ xennode = XendNode.instance()
+ if type(host_cpu_ref) == type(str()) and \
+ xennode.is_valid_cpu(host_cpu_ref):
+ return func(self, session, host_cpu_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_HOST_CPU_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_host_cpu_ref.api = func.api
+
+ return check_host_cpu_ref
+
+def valid_vm(func):
+ """Decorator to verify if vm_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, vm_ref)
+ @rtype: callable object
+ """
+ def check_vm_ref(self, session, vm_ref, *args, **kwargs):
+ xendom = XendDomain.instance()
+ if type(vm_ref) == type(str()) and \
+ xendom.is_valid_vm(vm_ref):
+ return func(self, session, vm_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_VM_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_vm_ref.api = func.api
+
+ return check_vm_ref
+
+def valid_vbd(func):
+ """Decorator to verify if vbd_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, vbd_ref)
+ @rtype: callable object
+ """
+ def check_vbd_ref(self, session, vbd_ref, *args, **kwargs):
+ xendom = XendDomain.instance()
+ if type(vbd_ref) == type(str()) and \
+ xendom.is_valid_dev('vbd', vbd_ref):
+ return func(self, session, vbd_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_VBD_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_vbd_ref.api = func.api
+
+ return check_vbd_ref
+
+def valid_vif(func):
+ """Decorator to verify if vif_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, vif_ref)
+ @rtype: callable object
+ """
+ def check_vif_ref(self, session, vif_ref, *args, **kwargs):
+ xendom = XendDomain.instance()
+ if type(vif_ref) == type(str()) and \
+ xendom.is_valid_dev('vif', vif_ref):
+ return func(self, session, vif_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_VIF_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_vif_ref.api = func.api
+
+ return check_vif_ref
+
+
+def valid_vdi(func):
+ """Decorator to verify if vdi_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, vdi_ref)
+ @rtype: callable object
+ """
+ def check_vdi_ref(self, session, vdi_ref, *args, **kwargs):
+ xennode = XendNode.instance()
+ if type(vdi_ref) == type(str()) and \
+ xennode.get_sr().is_valid_vdi(vdi_ref):
+ return func(self, session, vdi_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_VDI_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_vdi_ref.api = func.api
+
+ return check_vdi_ref
+
+def valid_vtpm(func):
+ """Decorator to verify if vtpm_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, vtpm_ref)
+ @rtype: callable object
+ """
+ def check_vtpm_ref(self, session, vtpm_ref, *args, **kwargs):
+ xendom = XendDomain.instance()
+ if type(vtpm_ref) == type(str()) and \
+ xendom.is_valid_dev('vtpm', vtpm_ref):
+ return func(self, session, vtpm_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_VTPM_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_vtpm_ref.api = func.api
+
+ return check_vtpm_ref
+
+def valid_sr(func):
+ """Decorator to verify if sr_ref is valid before calling
+ method.
+
+ @param func: function with params: (self, session, sr_ref)
+ @rtype: callable object
+ """
+ def check_sr_ref(self, session, sr_ref, *args, **kwargs):
+ xennode = XendNode.instance()
+ if type(sr_ref) == type(str()) and \
+ xennode.get_sr().uuid == sr_ref:
+ return func(self, session, sr_ref, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_SR_INVALID}
+
+ # make sure we keep the 'api' attribute
+ if hasattr(func, 'api'):
+ check_sr_ref.api = func.api
+
+ return check_sr_ref
+
+# -----------------------------
+# Bridge to Legacy XM API calls
+# -----------------------------
+
+def do_vm_func(fn_name, vm_ref, *args):
+ """Helper wrapper func to abstract away from repeative code.
+
+ @param fn_name: function name for XendDomain instance
+ @type fn_name: string
+ @param vm_ref: vm_ref
+ @type vm_ref: string
+ @param *args: more arguments
+ @type *args: tuple
+ """
+ xendom = XendDomain.instance()
+ fn = getattr(xendom, fn_name)
+ xendom.do_legacy_api_with_uuid(fn, vm_ref, *args)
+ return xen_api_success_void()
+
+
+class XendAPI:
+ """Implementation of the Xen-API in Xend. Expects to be
+ used via XMLRPCServer.
+
+ All methods that need a valid session are marked with
+ a L{XendAuthManager.session_required} decorator that will
+ transparently perform the required session authentication.
+
+ We need to support Python <2.4, so we use the old decorator syntax.
+
+ All XMLRPC accessible methods require an 'api' attribute and
+ is set to the XMLRPC function name which the method implements.
+ """
+
+ def __init__(self, auth):
+ """Initialised Xen API wrapper by making sure all functions
+ have the correct validation decorators such as L{valid_host}
+ and L{session_required}.
+ """
+ self.auth = auth
+
+ classes = {
+ 'session': (session_required,),
+ 'host': (valid_host, session_required),
+ 'host_cpu': (valid_host_cpu, session_required),
+ 'VM': (valid_vm, session_required),
+ 'VBD': (valid_vbd, session_required),
+ 'VIF': (valid_vif, session_required),
+ 'VDI': (valid_vdi, session_required),
+ 'VTPM':(valid_vtpm, session_required),
+ 'SR': (valid_sr, session_required)}
+
+ # Cheat methods
+ # -------------
+ # Methods that have a trivial implementation for all classes.
+ # 1. get_by_uuid == getting by ref, so just return uuid for
+ # all get_by_uuid() methods.
+
+ for cls in classes.keys():
+ get_by_uuid = '%s_get_by_uuid' % cls.lower()
+ get_uuid = '%s_get_uuid' % cls.lower()
+ setattr(XendAPI, get_by_uuid,
+ lambda s, sess, obj_ref: xen_api_success(obj_ref))
+ setattr(XendAPI, get_uuid,
+ lambda s, sess, obj_ref: xen_api_success(obj_ref))
+
+ # 2. get_record is just getting all the attributes, so provide
+ # a fake template implementation.
+ #
+ # TODO: ...
+
+
+ # Wrapping validators around XMLRPC calls
+ # ---------------------------------------
+
+ for cls, validators in classes.items():
+ ro_attrs = getattr(self, '%s_attr_ro' % cls, [])
+ rw_attrs = getattr(self, '%s_attr_rw' % cls, [])
+ methods = getattr(self, '%s_methods' % cls, [])
+ funcs = getattr(self, '%s_funcs' % cls, [])
+
+ # wrap validators around readable class attributes
+ for attr_name in ro_attrs + rw_attrs + self.Base_attr_ro:
+ getter_name = '%s_get_%s' % (cls.lower(), attr_name.lower())
+ try:
+ getter = getattr(XendAPI, getter_name)
+ for validator in validators:
+ getter = validator(getter)
+ getter.api = '%s.get_%s' % (cls, attr_name)
+ setattr(XendAPI, getter_name, getter)
+ except AttributeError:
+ pass
+ #log.warn("API call: %s not found" % getter_name)
+
+ # wrap validators around writable class attrributes
+ for attr_name in rw_attrs + self.Base_attr_rw:
+ setter_name = '%s_set_%s' % (cls.lower(), attr_name.lower())
+ try:
+ setter = getattr(XendAPI, setter_name)
+ for validator in validators:
+ setter = validator(setter)
+ setter.api = '%s.set_%s' % (cls, attr_name)
+ setattr(XendAPI, setter_name, setter)
+ except AttributeError:
+ pass
+ #log.warn("API call: %s not found" % setter_name)
+
+ # wrap validators around methods
+ for method_name in methods + self.Base_methods:
+ method_full_name = '%s_%s' % (cls.lower(),method_name.lower())
+ try:
+ method = getattr(XendAPI, method_full_name)
+ for validator in validators:
+ method = validator(method)
+ method.api = '%s.%s' % (cls, method_name)
+ setattr(XendAPI, method_full_name, method)
+ except AttributeError:
+ pass
+ #log.warn('API call: %s not found' % method_full_name)
+
+ # wrap validators around class functions
+ for func_name in funcs + self.Base_funcs:
+ func_full_name = '%s_%s' % (cls.lower(), func_name.lower())
+ try:
+ method = getattr(XendAPI, func_full_name)
+ method = session_required(method)
+ method.api = '%s.%s' % (cls, func_name)
+ setattr(XendAPI, func_full_name, method)
+ except AttributeError:
+ pass
+ #log.warn('API call: %s not found' % func_full_name)
+
+
+ Base_attr_ro = ['uuid']
+ Base_attr_rw = []
+ Base_methods = ['destroy', 'to_XML', 'get_record']
+ Base_funcs = ['create', 'get_by_uuid', 'get_all']
+
+ # Xen API: Class Session
+ # ----------------------------------------------------------------
+ # NOTE: Left unwrapped by __init__
+
+ session_attr_ro = ['this_host', 'this_user']
+ session_methods = ['logout']
+ # session_funcs = ['login_with_password']
+
+ def session_login_with_password(self, username, password):
+ try:
+ session = (self.auth == AUTH_NONE and
+ auth_manager().login_unconditionally(username) or
+ auth_manager().login_with_password(username, password))
+ return xen_api_success(session)
+ except XendError, e:
+ return xen_api_error(XEND_ERROR_AUTHENTICATION_FAILED)
+ session_login_with_password.api = 'session.login_with_password'
+
+
+ # object methods
+ def session_logout(self, session):
+ auth_manager().logout(session)
+ return xen_api_success_void()
+ def session_destroy(self, session):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def session_get_record(self, session):
+ record = {'this_host': XendNode.instance().uuid,
+ 'this_user': auth_manager().get_user(session)}
+ return xen_api_success(record)
+ def session_to_xml(self, session):
+ return xen_api_todo()
+
+ # attributes (ro)
+ def session_get_this_host(self, session):
+ return xen_api_success(XendNode.instance().uuid)
+ def session_get_this_user(self, session):
+ user = auth_manager().get_user(session)
+ if user:
+ return xen_api_success(user)
+ return xen_api_error(XEND_ERROR_SESSION_INVALID)
+
+
+ # Xen API: Class User
+ # ----------------------------------------------------------------
+ # TODO: NOT IMPLEMENTED YET
+
+ # Xen API: Class Tasks
+ # ----------------------------------------------------------------
+ # TODO: NOT IMPLEMENTED YET
+
+ # Xen API: Class Host
+ # ----------------------------------------------------------------
+
+ host_attr_ro = ['software_version',
+ 'resident_VMs',
+ 'host_CPUs']
+
+ host_attr_rw = ['name_label',
+ 'name_description']
+
+ host_methods = ['disable',
+ 'enable',
+ 'reboot',
+ 'shutdown']
+
+ host_funcs = ['get_by_name_label']
+
+ # attributes
+ def host_get_name_label(self, session, host_ref):
+ return xen_api_success(XendNode.instance().name)
+ def host_set_name_label(self, session, host_ref, new_name):
+ XendNode.instance().set_name(new_name)
+ return xen_api_success_void()
+ def host_get_name_description(self, session, host_ref):
+ return xen_api_success(XendNode.instance().description)
+ def host_set_name_description(self, session, host_ref, new_desc):
+ XendNode.instance().set_description(new_desc)
+ return xen_api_success_void()
+ def host_get_software_version(self, session, host_ref):
+ return xen_api_success(XendNode.instance().xen_version())
+ def host_get_resident_VMs(self, session, host_ref):
+ return xen_api_success(XendDomain.instance().get_domain_refs())
+ def host_get_host_CPUs(self, session, host_ref):
+ return xen_api_success(XendNode.instance().get_host_cpu_refs())
+
+ # object methods
+ def host_destroy(self, session, host_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def host_disable(self, session, host_ref):
+ XendDomain.instance().set_allow_new_domains(False)
+ return xen_api_success_void()
+ def host_enable(self, session, host_ref):
+ XendDomain.instance().set_allow_new_domains(True)
+ return xen_api_success_void()
+ def host_reboot(self, session, host_ref):
+ if not XendDomain.instance().allow_new_domains():
+ return xen_api_error(XEND_ERROR_HOST_RUNNING)
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def host_shutdown(self, session, host_ref):
+ if not XendDomain.instance().allow_new_domains():
+ return xen_api_error(XEND_ERROR_HOST_RUNNING)
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def host_get_record(self, session, host_ref):
+ node = XendNode.instance()
+ dom = XendDomain.instance()
+ record = {'uuid': node.uuid,
+ 'name_label': node.name,
+ 'name_description': '',
+ 'software_version': node.xen_version(),
+ 'resident_VMs': dom.get_domain_refs(),
+ 'host_CPUs': node.get_host_cpu_refs()}
+ return xen_api_success(record)
+
+ # class methods
+ def host_get_all(self, session):
+ return xen_api_success((XendNode.instance().uuid,))
+ def host_create(self, session, struct):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+ # Xen API: Class Host_CPU
+ # ----------------------------------------------------------------
+
+ host_cpu_attr_ro = ['host',
+ 'number',
+ 'features',
+ 'utilisation']
+
+ # attributes
+ def host_cpu_get_uuid(self, session, host_cpu_ref):
+ uuid = XendNode.instance().get_host_cpu_uuid(host_cpu_ref)
+ return xen_api_success(uuid)
+ def host_cpu_get_host(self, session, host_cpu_ref):
+ return xen_api_success(XendNode.instance().uuid)
+ def host_cpu_get_features(self, session, host_cpu_ref):
+ features = XendNode.instance().get_host_cpu_features(host_cpu_ref)
+ return xen_api_success(features)
+ def host_cpu_get_utilisation(self, session, host_cpu_ref):
+ util = XendNode.instance().get_host_cpu_load(host_cpu_ref)
+ return xen_api_success(util)
+ def host_cpu_get_number(self, session, host_cpu_ref):
+ num = XendNode.instance().get_host_cpu_number(host_cpu_ref)
+ return xen_api_success(num)
+
+ # object methods
+ def host_cpu_destroy(self, session, host_cpu_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def host_cpu_get_record(self, session, host_cpu_ref):
+ node = XendNode.instance()
+ record = {'uuid': host_cpu_ref,
+ 'host': node.uuid,
+ 'number': node.get_host_cpu_number(host_cpu_ref),
+ 'features': node.get_host_cpu_features(host_cpu_ref),
+ 'utilisation': node.get_host_cpu_load(host_cpu_ref)}
+ return xen_api_success(record)
+ def host_cpu_to_xml(self, session, host_cpu_ref):
+ return xen_api_todo()
+
+ # class methods
+ def host_cpu_get_all(self, session):
+ return xen_api_success(XendNode.instance().get_host_cpu_refs())
+ def host_cpu_create(self, session, struct):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+
+ # Xen API: Class Network
+ # ----------------------------------------------------------------
+ # TODO: NOT IMPLEMENTED
+
+ Network_attr_ro = ['VIFs']
+ Network_attr_rw = ['name_label',
+ 'name_description',
+ 'NIC',
+ 'VLAN',
+ 'default_gateway',
+ 'default_netmask']
+
+ # Xen API: Class VM
+ # ----------------------------------------------------------------
+
+ VM_attr_ro = ['power_state',
+ 'resident_on',
+ 'memory_actual',
+ 'memory_static_max',
+ 'memory_static_min',
+ 'VCPUs_number',
+ 'VCPUs_utilisation',
+ 'VCPUs_features_required',
+ 'VCPUs_can_use',
+ 'VIFs',
+ 'VBDs',
+ 'VTPMs',
+ 'PCI_bus',
+ 'tools_version',
+ ]
+
+ VM_attr_rw = ['name_label',
+ 'name_description',
+ 'user_version',
+ 'is_a_template',
+ 'memory_dynamic_max',
+ 'memory_dynamic_min',
+ 'VCPUs_policy',
+ 'VCPUs_params',
+ 'VCPUs_features_force_on',
+ 'VCPUS_features_force_off',
+ 'actions_after_shutdown',
+ 'actions_after_reboot',
+ 'actions_after_suspend',
+ 'actions_after_crash',
+ 'bios_boot',
+ 'platform_std_VGA',
+ 'platform_serial',
+ 'platform_localtime',
+ 'platform_clock_offset',
+ 'platform_enable_audio',
+ 'platform_keymap',
+ 'builder',
+ 'boot_method',
+ 'kernel_kernel',
+ 'kernel_initrd',
+ 'kernel_args',
+ 'grub_cmdline',
+ 'otherConfig']
+
+ VM_methods = ['clone',
+ 'start',
+ 'pause',
+ 'unpause',
+ 'clean_shutdown',
+ 'clean_reboot',
+ 'hard_shutdown',
+ 'hard_reboot',
+ 'suspend',
+ 'resume']
+
+ VM_funcs = ['get_by_name_label']
+
+ # parameters required for _create()
+ VM_attr_inst = [
+ 'name_label',
+ 'name_description',
+ 'user_version',
+ 'is_a_template',
+ 'memory_static_max',
+ 'memory_dynamic_max',
+ 'memory_dynamic_min',
+ 'memory_static_min',
+ 'VCPUs_policy',
+ 'VCPUs_params',
+ 'VCPUs_features_required',
+ 'VCPUs_features_can_use',
+ 'VCPUs_features_force_on',
+ 'VCPUs_features_force_off',
+ 'actions_after_shutdown',
+ 'actions_after_reboot',
+ 'actions_after_suspend',
+ 'actions_after_crash',
+ 'bios_boot',
+ 'platform_std_VGA',
+ 'platform_serial',
+ 'platform_localtime',
+ 'platform_clock_offset',
+ 'platform_enable_audio',
+ 'platform_keymap',
+ 'builder',
+ 'boot_method',
+ 'kernel_kernel',
+ 'kernel_initrd',
+ 'kernel_args',
+ 'grub_cmdline',
+ 'PCI_bus',
+ 'otherConfig']
+
+ # attributes (ro)
+ def vm_get_power_state(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.state)
+
+ def vm_get_resident_on(self, session, vm_ref):
+ return xen_api_success(XendNode.instance().uuid)
+
+ def vm_get_memory_actual(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # unsupported by xc
+
+ def vm_get_memory_static_max(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_memory_static_max())
+
+ def vm_get_memory_static_min(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_memory_static_min())
+
+ def vm_get_VCPUs_number(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.getVCpuCount())
+
+ def vm_get_VCPUs_utilisation(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_vcpus_util())
+
+ def vm_get_VCPUs_features_required(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # unsupported by xc
+
+ def vm_get_VCPUs_can_use(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # unsupported by xc
+
+ def vm_get_VIFs(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_vifs())
+
+ def vm_get_VBDs(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_vbds())
+
+ def vm_get_VTPMs(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_vtpms())
+
+ def vm_get_PCI_bus(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # unsupported by xc
+
+ def vm_get_tools_version(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ # attributes (rw)
+ def vm_get_name_label(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.getName())
+
+ def vm_get_name_description(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_user_version(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_is_a_template(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_memory_dynamic_max(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_memory_dynamic_min(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_VCPUs_policy(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # need to access scheduler
+
+ def vm_get_VCPUs_params(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo() # need access to scheduler
+
+ def vm_get_VCPUs_features_force_on(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_VCPUs_features_force_off(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_actions_after_shutdown(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_on_shutdown())
+
+ def vm_get_actions_after_reboot(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_on_reboot())
+
+ def vm_get_actions_after_suspend(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_on_suspend())
+
+ def vm_get_actions_after_crash(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_on_crash())
+
+ def vm_get_bios_boot(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_bios_boot())
+
+ def vm_get_platform_std_VGA(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_platform_serial(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_platform_localtime(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_platform_clock_offset(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_platform_enable_audio(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_platform_keymap(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_builder(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_get_boot_method(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success('')
+
+ def vm_get_kernel_kernel(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success('')
+
+ def vm_get_kernel_initrd(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success('')
+
+ def vm_get_kernel_args(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success('')
+
+ def vm_get_grub_cmdline(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success('')
+
+ def vm_get_otherConfig(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_todo()
+
+ def vm_set_name_label(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_name_description(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_user_version(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_is_a_template(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_memory_dynamic_max(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_memory_dynamic_min(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_vcpus_policy(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_vcpus_params(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_vcpus_features_force_on(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_vcpus_features_force_off(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_actions_after_shutdown(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_actions_after_reboot(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_actions_after_suspend(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_actions_after_crash(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_bios_boot(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_platform_std_VGA(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_platform_serial(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_platform_localtime(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_platform_clock_offset(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_platform_enable_audio(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_builder(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_boot_method(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_kernel_kernel(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_kernel_initrd(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_kernel_args(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_grub_cmdline(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ def vm_set_otherConfig(self, session, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success_void()
+
+ # class methods
+ def vm_get_all(self, session):
+ refs = [d.get_uuid() for d in XendDomain.instance().list()]
+ return xen_api_success(refs)
+
+ def vm_get_by_name_label(self, session, label):
+ xendom = XendDomain.instance()
+ dom = xendom.domain_lookup_nr(label)
+ if dom:
+ return xen_api_success([dom.get_uuid()])
+ return xen_api_error(XEND_ERROR_VM_INVALID)
+
+ def vm_create(self, session, vm_struct):
+ xendom = XendDomain.instance()
+ domuuid = xendom.create_domain(vm_struct)
+ return xen_api_success(domuuid)
+
+ # object methods
+ def vm_to_xml(self, session, vm_ref):
+ return xen_api_todo()
+
+ def vm_get_record(self, session, vm_ref):
+ xendom = XendDomain.instance()
+ xeninfo = xendom.get_vm_by_uuid(vm_ref)
+ if not xeninfo:
+ return xen_api_error(XEND_ERROR_VM_INVALID)
+
+ record = {
+ 'uuid': xeninfo.get_uuid(),
+ 'power_state': xeninfo.get_power_state(),
+ 'name_label': xeninfo.getName(),
+ 'name_description': xeninfo.getName(),
+ 'user_version': 1,
+ 'is_a_template': False,
+ 'resident_on': XendNode.instance().uuid,
+ 'memory_static_min': xeninfo.get_memory_static_min(),
+ 'memory_static_max': xeninfo.get_memory_static_max(),
+ 'memory_dynamic_min': xeninfo.get_memory_static_min(),
+ 'memory_dynamic_max': xeninfo.get_memory_static_max(),
+ 'memory_actual': xeninfo.get_memory_static_min(),
+ 'vcpus_policy': xeninfo.get_vcpus_policy(),
+ 'vcpus_params': xeninfo.get_vcpus_params(),
+ 'vcpus_number': xeninfo.getVCpuCount(),
+ 'vcpus_utilisation': xeninfo.get_vcpus_util(),
+ 'vcpus_features_required': [],
+ 'vcpus_features_can_use': [],
+ 'vcpus_features_force_on': [],
+ 'vcpus_features_force_off': [],
+ 'actions_after_shutdown': xeninfo.get_on_shutdown(),
+ 'actions_after_reboot': xeninfo.get_on_reboot(),
+ 'actions_after_suspend': xeninfo.get_on_suspend(),
+ 'actions_after_crash': xeninfo.get_on_crash(),
+ 'VIFs': xeninfo.get_vifs(),
+ 'VBDs': xeninfo.get_vbds(),
+ 'VTPMs': xeninfo.get_vtpms(),
+ 'bios_boot': xeninfo.get_bios_boot(),
+ 'platform_std_VGA': xeninfo.get_platform_std_vga(),
+ 'platform_serial': xeninfo.get_platform_serial(),
+ 'platform_localtime': xeninfo.get_platform_localtime(),
+ 'platform_clock_offset': xeninfo.get_platform_clock_offset(),
+ 'platform_enable_audio': xeninfo.get_platform_enable_audio(),
+ 'platform_keymap': xeninfo.get_platform_keymap(),
+ 'builder': xeninfo.get_builder(),
+ 'boot_method': xeninfo.get_boot_method(),
+ 'kernel_kernel': xeninfo.get_kernel_image(),
+ 'kernel_initrd': xeninfo.get_kernel_initrd(),
+ 'kernel_args': xeninfo.get_kernel_args(),
+ 'grub_cmdline': xeninfo.get_grub_cmdline(),
+ 'PCI_bus': xeninfo.get_pci_bus(),
+ 'tools_version': xeninfo.get_tools_version(),
+ 'otherConfig': xeninfo.get_other_config()
+ }
+ return xen_api_success(record)
+
+ def vm_clean_reboot(self, session, vm_ref):
+ xendom = XendDomain.instance()
+ xeninfo = xendom.get_vm_by_uuid(vm_ref)
+ xeninfo.shutdown("reboot")
+ return xen_api_success_void()
+ def vm_clean_shutdown(self, session, vm_ref):
+ xendom = XendDomain.instance()
+ xeninfo = xendom.get_vm_by_uuid(vm_ref)
+ xeninfo.shutdown("poweroff")
+ return xen_api_success_void()
+ def vm_clone(self, session, vm_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def vm_destroy(self, session, vm_ref):
+ return do_vm_func("domain_delete", vm_ref)
+ def vm_hard_reboot(self, session, vm_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def vm_hard_shutdown(self, session, vm_ref):
+ return do_vm_func("domain_destroy", vm_ref)
+ def vm_pause(self, session, vm_ref):
+ return do_vm_func("domain_pause", vm_ref)
+ def vm_resume(self, session, vm_ref, start_paused):
+ return do_vm_func("domain_resume", vm_ref)
+ def vm_start(self, session, vm_ref):
+ return do_vm_func("domain_start", vm_ref)
+ def vm_suspend(self, session, vm_ref):
+ return do_vm_func("domain_suspend", vm_ref)
+ def vm_unpause(self, session, vm_ref):
+ return do_vm_func("domain_unpause", vm_ref)
+
+ # Xen API: Class VDI
+ # ----------------------------------------------------------------
+ # TODO: NOT IMPLEMENTED.
+
+ # Xen API: Class VBD
+ # ----------------------------------------------------------------
+
+ VBD_attr_ro = ['image',
+ 'IO_bandwidth_incoming_kbs',
+ 'IO_bandwidth_outgoing_kbs']
+ VBD_attr_rw = ['VM',
+ 'VDI',
+ 'device',
+ 'mode',
+ 'driver']
+
+ VBD_attr_inst = VBD_attr_rw + ['image']
+
+ # object methods
+ def vbd_get_record(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VBD_INVALID)
+ cfg = vm.get_dev_xenapi_config('vbd', vbd_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VBD_INVALID)
+ return xen_api_success(cfg)
+
+ # class methods
+ def vbd_create(self, session, vbd_struct):
+ xendom = XendDomain.instance()
+ if not xendom.is_valid_vm(vbd_struct['VM']):
+ return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+
+ dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
+ vbd_ref = ''
+ try:
+ if not vbd_struct.get('VDI', None):
+ # this is a traditional VBD without VDI and SR
+ vbd_ref = dom.create_vbd(vbd_struct)
+ else:
+ # new VBD via VDI/SR
+ vdi_ref = vbd_struct.get('VDI')
+ sr = XendNode.instance().get_sr()
+ vdi_image = sr.xen_api_get_by_uuid(vdi_ref)
+ if not vdi_image:
+ return xen_api_error(XEND_ERROR_VDI_INVALID)
+ vdi_image = vdi_image.qcow_path
+ vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image)
+ except XendError:
+ return xen_api_todo()
+
+ xendom.managed_config_save(dom)
+ return xen_api_success(vbd_ref)
+
+ # attributes (rw)
+ def vbd_get_vm(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'VM'))
+
+ def vbd_get_vdi(self, session, vbd_ref):
+ return xen_api_todo()
+
+ def vbd_get_device(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property('vbd', vbd_ref,
+ 'device'))
+ def vbd_get_mode(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property('vbd', vbd_ref,
+ 'mode'))
+ def vbd_get_driver(self, session, vbd_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property('vbd', vbd_ref,
+ 'driver'))
+
+ # Xen API: Class VIF
+ # ----------------------------------------------------------------
+
+ VIF_attr_ro = ['network_read_kbs',
+ 'network_write_kbs',
+ 'IO_bandwidth_incoming_kbs',
+ 'IO_bandwidth_outgoing_kbs']
+ VIF_attr_rw = ['name',
+ 'type',
+ 'device',
+ 'network',
+ 'VM',
+ 'MAC',
+ 'MTU']
+
+ VIF_attr_inst = VIF_attr_rw
+
+ # object methods
+ def vif_get_record(self, session, vif_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VIF_INVALID)
+ cfg = vm.get_dev_xenapi_config('vif', vif_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VIF_INVALID)
+ valid_vif_keys = self.VIF_attr_ro + self.VIF_attr_rw + \
+ self.Base_attr_ro + self.Base_attr_rw
+ for k in cfg.keys():
+ if k not in valid_vif_keys:
+ del cfg[k]
+
+ return xen_api_success(cfg)
+
+ # class methods
+ def vif_create(self, session, vif_struct):
+ xendom = XendDomain.instance()
+ if xendom.is_valid_vm(vif_struct['VM']):
+ dom = xendom.get_vm_by_uuid(vif_struct['VM'])
+ try:
+ vif_ref = dom.create_vif(vif_struct)
+ xendom.managed_config_save(dom)
+ return xen_api_success(vif_ref)
+ except XendError:
+ return xen_api_error(XEND_ERROR_TODO)
+ else:
+ return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+
+
+ # Xen API: Class VDI
+ # ----------------------------------------------------------------
+ VDI_attr_ro = ['VBDs',
+ 'physical_utilisation',
+ 'sector_size',
+ 'type',
+ 'parent',
+ 'children']
+ VDI_attr_rw = ['name_label',
+ 'name_description',
+ 'SR',
+ 'virtual_size',
+ 'sharable',
+ 'read_only']
+ VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
+
+ VDI_methods = ['snapshot']
+ VDI_funcs = ['get_by_name_label']
+
+ def vdi_get_VBDs(self, session, vdi_ref):
+ return xen_api_todo()
+
+ def vdi_get_physical_utilisation(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.get_physical_utilisation())
+
+ def vdi_get_sector_size(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.sector_size)
+
+ def vdi_get_type(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.type)
+
+ def vdi_get_parent(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.parent)
+
+ def vdi_get_children(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.children)
+
+ def vdi_get_name_label(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.name_label)
+
+ def vdi_get_name_description(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.name_description)
+
+ def vdi_get_sr(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.uuid)
+
+ def vdi_get_virtual_size(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.virtual_size)
+
+ def vdi_get_sharable(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.sharable)
+
+ def vdi_get_read_only(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ return xen_api_success(image.sharable)
+
+ def vdi_set_name_label(self, session, vdi_ref, value):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ image.name_label = value
+ return xen_api_success_void()
+
+ def vdi_set_name_description(self, session, vdi_ref, value):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ image.name_description = value
+ return xen_api_success_void()
+
+ def vdi_set_sr(self, session, vdi_ref, value):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+ def vdi_set_virtual_size(self, session, vdi_ref, value):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+ def vdi_set_sharable(self, session, vdi_ref, value):
+ return xen_api_todo()
+ def vdi_set_read_only(self, session, vdi_ref, value):
+ return xen_api_todo()
+
+ # Object Methods
+ def vdi_snapshot(self, session, vdi_ref):
+ return xen_api_todo()
+
+ def vdi_destroy(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ sr.destroy_image(vdi_ref)
+ return xen_api_success_void()
+
+ def vdi_to_xml(self, session, vdi_ref):
+ return xen_api_todo()
+
+ def vdi_get_record(self, session, vdi_ref):
+ sr = XendNode.instance().get_sr()
+ image = sr.xen_api_get_by_uuid(vdi_ref)
+ if image:
+ return xen_api_success({
+ 'uuid': vdi_ref,
+ 'name_label': image.name_label,
+ 'name_description': image.name_description,
+ 'SR': sr.uuid,
+ 'VBDs': [], # TODO
+ 'virtual_size': image.virtual_size,
+ 'physical_utilisation': image.physical_utilisation,
+ 'sector_size': image.sector_size,
+ 'type': image.type,
+ 'parent': image.parent,
+ 'children': image.children,
+ 'sharable': image.sharable,
+ 'read_only': image.read_only,
+ })
+
+ return xen_api_error(XEND_ERROR_VDI_INVALID)
+
+ # Class Functions
+ def vdi_create(self, session, vdi_struct):
+ sr = XendNode.instance().get_sr()
+ sr_ref = vdi_struct['SR']
+ if sr.uuid != sr_ref:
+ return xen_api_error(XEND_ERROR_SR_INVALID)
+
+ vdi_uuid = sr.create_image(vdi_struct)
+ return xen_api_success(vdi_uuid)
+
+ def vdi_get_all(self, session):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.list_images())
+
+ def vdi_get_by_name_label(self, session, name):
+ sr = XendNode.instance().get_sr()
+ image_uuid = sr.xen_api_get_by_name_label(name)
+ if image_uuid:
+ return xen_api_success(image_uuid)
+
+ return xen_api_error(XEND_ERROR_VDI_INVALID)
+
+
+ # Xen API: Class VTPM
+ # ----------------------------------------------------------------
+
+ VTPM_attr_rw = [ ]
+ VTPM_attr_ro = ['VM',
+ 'backend',
+ 'instance',
+ 'driver']
+
+ VTPM_attr_inst = VTPM_attr_rw
+
+ # object methods
+ def vtpm_get_record(self, session, vtpm_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ valid_vtpm_keys = self.VTPM_attr_ro + self.VTPM_attr_rw + \
+ self.Base_attr_ro + self.Base_attr_rw
+ for k in cfg.keys():
+ if k not in valid_vtpm_keys:
+ del cfg[k]
+
+ return xen_api_success(cfg)
+
+ # Class Functions
+ def vtpm_get_instance(self, session, vtpm_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ if cfg.has_key('instance'):
+ instance = cfg['instance']
+ else:
+ instance = -1
+ return xen_api_success(instance)
+
+ def vtpm_get_driver(self, session, vtpm_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ if cfg.has_key('type'):
+ driver = cfg['type']
+ else:
+ driver = "Unknown"
+ return xen_api_success(driver)
+
+ def vtpm_get_backend(self, session, vtpm_ref):
+ xendom = XendDomain.instance()
+ vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
+ if not vm:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
+ if not cfg:
+ return xen_api_error(XEND_ERROR_VTPM_INVALID)
+ if cfg.has_key('backend'):
+ backend = cfg['backend']
+ else:
+ backend = "Domain-0"
+ return xen_api_success(backend)
+
+ def vtpm_get_VM(self, session, vtpm_ref):
+ xendom = XendDomain.instance()
+ return xen_api_success(xendom.get_dev_property('vtpm', vtpm_ref, 'VM'))
+
+ # class methods
+ def vtpm_create(self, session, vtpm_struct):
+ xendom = XendDomain.instance()
+ if xendom.is_valid_vm(vtpm_struct['VM']):
+ dom = xendom.get_vm_by_uuid(vtpm_struct['VM'])
+ try:
+ vtpm_ref = dom.create_vtpm(vtpm_struct)
+ xendom.managed_config_save(dom)
+ return xen_api_success(vtpm_ref)
+ except XendError:
+ return xen_api_error(XEND_ERROR_TODO)
+ else:
+ return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+
+
+ # Xen API: Class SR
+ # ----------------------------------------------------------------
+ SR_attr_ro = ['VDIs',
+ 'virtual_allocation',
+ 'physical_utilisation',
+ 'physical_size',
+ 'type',
+ 'location']
+
+ SR_attr_rw = ['name_label',
+ 'name_description']
+
+ SR_attr_inst = ['physical_size',
+ 'type',
+ 'location',
+ 'name_label',
+ 'name_description']
+
+ SR_methods = ['clone']
+ SR_funcs = ['get_by_name_label']
+
+ # Class Functions
+ def sr_get_all(self, session):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success([sr.uuid])
+
+ def sr_get_by_name_label(self, session, label):
+ sr = XendNode.instance().get_sr()
+ if sr.name_label != label:
+ return xen_api_error(XEND_ERROR_SR_INVALID)
+ return xen_api_success([sr.uuid])
+
+ def sr_create(self, session):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+ def sr_get_by_uuid(self, session):
+ return xen_api_success(XendNode.instance().get_sr().uuid)
+
+ # Class Methods
+ def sr_clone(self, session, sr_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+ def sr_destroy(self, session, sr_ref):
+ return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
+ def sr_to_xml(self, session, sr_ref):
+ return xen_api_todo()
+
+ def sr_get_record(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success({
+ 'uuid': sr.uuid,
+ 'name_label': sr.name_label,
+ 'name_description': sr.name_description,
+ 'VDIs': sr.list_images(),
+ 'virtual_allocation': sr.used_space_bytes(),
+ 'physical_utilisation': sr.used_space_bytes(),
+ 'physical_size': sr.total_space_bytes(),
+ 'type': sr.type,
+ 'location': sr.location
+ })
+
+ # Attribute acceess
+ def sr_get_vdis(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.list_images())
+
+ def sr_get_virtual_allocation(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return sr.used_space_bytes()
+
+ def sr_get_physical_utilisation(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return sr.used_space_bytes()
+
+ def sr_get_physical_size(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return sr.total_space_bytes()
+
+ def sr_get_type(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.type)
+
+ def sr_get_location(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.location)
+
+ def sr_get_name_label(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.name_label)
+
+ def sr_get_name_description(self, session, sr_ref):
+ sr = XendNode.instance().get_sr()
+ return xen_api_success(sr.name_description)
+
+ def sr_set_name_label(self, session, sr_ref, value):
+ sr = XendNode.instance().get_sr()
+ sr.name_label = value
+ return xen_api_success_void()
+
+ def sr_set_name_description(self, session, sr_ref, value):
+ sr = XendNode.instance().get_sr()
+ sr.name_description = value
+ return xen_api_success_void()
+
+#
+# Auto generate some stubs based on XendAPI introspection
+#
+if __name__ == "__main__":
+ def output(line):
+ print ' ' + line
+
+ classes = ['VDI', 'SR']
+ for cls in classes:
+ ro_attrs = getattr(XendAPI, '%s_attr_ro' % cls, [])
+ rw_attrs = getattr(XendAPI, '%s_attr_rw' % cls, [])
+ methods = getattr(XendAPI, '%s_methods' % cls, [])
+ funcs = getattr(XendAPI, '%s_funcs' % cls, [])
+
+ ref = '%s_ref' % cls.lower()
+
+ for attr_name in ro_attrs + rw_attrs + XendAPI.Base_attr_ro:
+ getter_name = '%s_get_%s' % (cls.lower(), attr_name.lower())
+ output('def %s(self, session, %s):' % (getter_name, ref))
+ output(' return xen_api_todo()')
+
+ for attr_name in rw_attrs + XendAPI.Base_attr_rw:
+ setter_name = '%s_set_%s' % (cls.lower(), attr_name.lower())
+ output('def %s(self, session, %s, value):' % (setter_name, ref))
+ output(' return xen_api_todo()')
+
+ for method_name in methods + XendAPI.Base_methods:
+ method_full_name = '%s_%s' % (cls.lower(),method_name.lower())
+ output('def %s(self, session, %s):' % (method_full_name, ref))
+ output(' return xen_api_todo()')
+
+ for func_name in funcs + XendAPI.Base_funcs:
+ func_full_name = '%s_%s' % (cls.lower(), func_name.lower())
+ output('def %s(self, session):' % func_full_name)
+ output(' return xen_api_todo()')
diff --git a/tools/python/xen/xend/XendAPIConstants.py b/tools/python/xen/xend/XendAPIConstants.py
new file mode 100644
index 0000000000..875f948bcf
--- /dev/null
+++ b/tools/python/xen/xend/XendAPIConstants.py
@@ -0,0 +1,75 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+
+#
+# Xen API Enums
+#
+
+XEN_API_VM_POWER_STATE = [
+ 'Halted',
+ 'Paused',
+ 'Running',
+ 'Suspended',
+ 'ShuttingDown',
+ 'Unknown'
+]
+
+XEN_API_VM_POWER_STATE_HALTED = 0
+XEN_API_VM_POWER_STATE_PAUSED = 1
+XEN_API_VM_POWER_STATE_RUNNING = 2
+XEN_API_VM_POWER_STATE_SUSPENDED = 3
+XEN_API_VM_POWER_STATE_SHUTTINGDOWN = 4
+XEN_API_VM_POWER_STATE_UNKNOWN = 5
+
+XEN_API_CPU_FEATURE = [
+ 'FPU', 'VME', 'DE', 'PSE', 'TSC', 'MSR', 'PAE'
+ 'MCE', 'CX8', 'APIC', 'SEP', 'MTRR', 'PGE', 'MCA',
+ 'CMOV', 'PAT', 'PSE36', 'PN', 'CLFLSH', 'DTES',
+ 'ACPI', 'MMX', 'FXCR', 'XMM', 'XMM2', 'SELFSNOOP',
+ 'HT', 'ACC', 'IA64', 'SYSCALL', 'MP', 'NX', 'MMXEXT',
+ 'LM', '3DNOWEXT', '3DNOW', 'RECOVERY', 'LONGRUN',
+ 'LRTI', 'CXMMX', 'K6_MTRR', 'CYRIX_ARR', 'CENTAUR_MCR',
+ 'K8', 'K7', 'P3', 'P4', 'CONSTANT_TSC', 'FXSAVE_LEAK',
+ 'XMM3', 'MWAIT', 'DSCPL', 'EST', 'TM2', 'CID', 'CX16',
+ 'XTPR', 'XSTORE', 'XSTORE_EN', 'XCRYPT', 'XCRYPT_EN',
+ 'LAHF_LM', 'CMP_LEGACY'
+]
+
+XEN_API_ON_NORMAL_EXIT = [
+ 'destroy',
+ 'restart',
+]
+
+XEN_API_ON_CRASH_BEHAVIOUR = [
+ 'destroy',
+ 'coredump_and_destroy',
+ 'restart',
+ 'coredump_and_restart',
+ 'preserve',
+ 'rename_restart'
+]
+
+XEN_API_BOOT_TYPE = [
+ 'bios',
+ 'grub',
+ 'kernel_external',
+ 'kernel_internal'
+]
+
+XEN_API_VBD_MODE = ['RO', 'RW']
+XEN_API_VDI_TYPE = ['system', 'user', 'ephemeral']
+XEN_API_DRIVER_TYPE = ['ioemu', 'paravirtualised']
diff --git a/tools/python/xen/xend/XendAuthSessions.py b/tools/python/xen/xend/XendAuthSessions.py
new file mode 100644
index 0000000000..616724b96b
--- /dev/null
+++ b/tools/python/xen/xend/XendAuthSessions.py
@@ -0,0 +1,145 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+
+import time
+
+from xen.xend import uuid
+from xen.xend.XendError import *
+from xen.xend.XendLogging import log
+
+try:
+ import PAM
+except ImportError:
+ log.warn("python-pam is required for XenAPI support.")
+
+class XendAuthSessions:
+ """Keeps track of Xen API Login Sessions using PAM.
+
+ Note: Login sessions are not valid across instances of Xend.
+ """
+ def __init__(self):
+ self.sessions = {}
+
+ def init(self):
+ pass
+
+ def login_unconditionally(self, username):
+ """Returns a session UUID if valid.
+
+ @rtype: string
+ @return: Session UUID
+ """
+ new_session = uuid.createString()
+ self.sessions[new_session] = (username, time.time())
+ return new_session
+
+ def login_with_password(self, username, password):
+ """Returns a session UUID if valid, otherwise raises an error.
+
+ @raises XendError: If login fails.
+ @rtype: string
+ @return: Session UUID
+ """
+ if self.is_authorized(username, password):
+ return login_unconditionally(username)
+
+ raise XendError("Login failed")
+
+ def logout(self, session):
+ """Delete session of it exists."""
+ if self.is_session_valid(session):
+ del self.sessions[session]
+
+ def is_session_valid(self, session):
+ """Returns true is session is valid."""
+ if type(session) == type(str()):
+ return (session in self.sessions)
+ return False
+
+ def is_authorized(self, username, password):
+ """Returns true is a user is authorised via PAM.
+
+ Note: We use the 'login' PAM stack rather than inventing
+ our own.
+
+ @rtype: boolean
+ """
+ pam_auth = None
+ try:
+ pam_auth = PAM.pam()
+ except NameError:
+ # if PAM doesn't exist, let's ignore it
+ return False
+
+ pam_auth.start("login")
+ pam_auth.set_item(PAM.PAM_USER, username)
+
+ def _pam_conv(auth, query_list, user_data):
+ resp = []
+ for i in range(len(query_list)):
+ query, qtype = query_list[i]
+ if qtype == PAM.PAM_PROMPT_ECHO_ON:
+ resp.append((username, 0))
+ elif qtype == PAM.PAM_PROMPT_ECHO_OFF:
+ resp.append((password, 0))
+ else:
+ return None
+ return resp
+
+ pam_auth.set_item(PAM.PAM_CONV, _pam_conv)
+
+ try:
+ pam_auth.authenticate()
+ pam_auth.acct_mgmt()
+ except PAM.error, resp:
+ return False
+ except Exception, e:
+ log.warn("Error with PAM: %s" % str(e))
+ return False
+ else:
+ return True
+
+ def get_user(self, session):
+ try:
+ return self.sessions[session][0]
+ except (KeyError, IndexError):
+ return None
+
+
+def instance():
+ """Singleton constructor. Use this instead of the class constructor.
+ """
+ global inst
+ try:
+ inst
+ except:
+ inst = XendAuthSessions()
+ inst.init()
+ return inst
+
+# Handy Authentication Decorators
+# -------------------------------
+def session_required(func):
+ def check_session(self, session, *args, **kwargs):
+ if instance().is_session_valid(session):
+ return func(self, session, *args, **kwargs)
+ else:
+ return {'Status': 'Failure',
+ 'ErrorDescription': XEND_ERROR_SESSION_INVALID}
+ return check_session
+
+
diff --git a/tools/python/xen/xend/XendBootloader.py b/tools/python/xen/xend/XendBootloader.py
index 9c062e4c4b..879b39806d 100644
--- a/tools/python/xen/xend/XendBootloader.py
+++ b/tools/python/xen/xend/XendBootloader.py
@@ -14,7 +14,8 @@
import os, select, errno
import random
-import sxp
+import shlex
+from xen.xend import sxp
from XendLogging import log
from XendError import VmError
@@ -37,7 +38,7 @@ def bootloader(blexec, disk, quiet = 0, blargs = None, imgcfg = None):
raise VmError(msg)
while True:
- fifo = "/var/lib/xen/xenbl.%s" %(random.randint(0, 32000),)
+ fifo = "/var/lib/xen/xenbl.%s" % random.randint(0, 32000)
if not os.path.exists(fifo):
break
os.mkfifo(fifo, 0600)
@@ -47,9 +48,9 @@ def bootloader(blexec, disk, quiet = 0, blargs = None, imgcfg = None):
args = [ blexec ]
if quiet:
args.append("-q")
- args.append("--output=%s" %(fifo,))
+ args.append("--output=%s" % fifo)
if blargs is not None:
- args.extend(blargs.split())
+ args.extend(shlex.split(blargs))
args.append(disk)
try:
diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py
index c0c5e48d48..b7c964d70a 100644
--- a/tools/python/xen/xend/XendCheckpoint.py
+++ b/tools/python/xen/xend/XendCheckpoint.py
@@ -8,21 +8,18 @@
import os
import re
import string
-import sxp
import threading
from struct import pack, unpack, calcsize
from xen.util.xpopen import xPopen3
-
import xen.util.auxbin
-
import xen.lowlevel.xc
-import balloon
-from XendError import XendError
-from XendLogging import log
-from XendDomainInfo import DEV_MIGRATE_STEP1, DEV_MIGRATE_STEP2
-from XendDomainInfo import DEV_MIGRATE_STEP3
+from xen.xend import balloon, sxp
+from xen.xend.XendError import XendError, VmError
+from xen.xend.XendLogging import log
+from xen.xend.XendConstants import *
+from xen.xend.XendConfig import XendConfig
SIGNATURE = "LinuxGuestRecord"
XC_SAVE = "xc_save"
@@ -40,20 +37,20 @@ def write_exact(fd, buf, errmsg):
if os.write(fd, buf) != len(buf):
raise XendError(errmsg)
+
def read_exact(fd, size, errmsg):
buf = ''
while size != 0:
- str = os.read(fd, size)
- if not len(str):
+ readstr = os.read(fd, size)
+ if not len(readstr):
log.error("read_exact: EOF trying to read %d (buf='%s')" % \
(size, buf))
raise XendError(errmsg)
- size = size - len(str)
- buf = buf + str
+ size = size - len(readstr)
+ buf = buf + readstr
return buf
-
def save(fd, dominfo, network, live, dst):
write_exact(fd, SIGNATURE, "could not write guest state file: signature")
@@ -100,9 +97,17 @@ def save(fd, dominfo, network, live, dst):
forkHelper(cmd, fd, saveInputHandler, False)
dominfo.destroyDomain()
+ try:
+ dominfo.setName(domain_name)
+ except VmError:
+ # Ignore this. The name conflict (hopefully) arises because we
+ # are doing localhost migration; if we are doing a suspend of a
+ # persistent VM, we need the rename, and don't expect the
+ # conflict. This needs more thought.
+ pass
except Exception, exn:
- log.exception("Save failed on domain %s (%d).", domain_name,
+ log.exception("Save failed on domain %s (%s).", domain_name,
dominfo.getDomid())
try:
dominfo.setName(domain_name)
@@ -111,7 +116,7 @@ def save(fd, dominfo, network, live, dst):
raise Exception, exn
-def restore(xd, fd):
+def restore(xd, fd, dominfo = None, paused = False):
signature = read_exact(fd, len(SIGNATURE),
"not a valid guest state file: signature read")
if signature != SIGNATURE:
@@ -131,7 +136,11 @@ def restore(xd, fd):
vmconfig = p.get_val()
- dominfo = xd.restore_(vmconfig)
+ if dominfo:
+ dominfo.update(XendConfig(sxp = vmconfig), refresh = False)
+ dominfo.resume()
+ else:
+ dominfo = xd.restore_(vmconfig)
store_port = dominfo.getStorePort()
console_port = dominfo.getConsolePort()
@@ -161,9 +170,10 @@ def restore(xd, fd):
if handler.store_mfn is None or handler.console_mfn is None:
raise XendError('Could not read store/console MFN')
- #Block until src closes connection
- os.read(fd, 1)
- dominfo.unpause()
+ os.read(fd, 1) # Wait for source to close connection
+ dominfo.waitForDevices() # Wait for backends to set up
+ if not paused:
+ dominfo.unpause()
dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
@@ -233,4 +243,9 @@ def slurp(infile):
if line == "":
break
else:
- log.error('%s', line.strip())
+ line = line.strip()
+ m = re.match(r"^ERROR: (.*)", line)
+ if m is None:
+ log.info('%s', line)
+ else:
+ log.error('%s', m.group(1))
diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py
index 0477aa6180..ef727c2676 100644
--- a/tools/python/xen/xend/XendClient.py
+++ b/tools/python/xen/xend/XendClient.py
@@ -22,6 +22,7 @@ import os
import sys
XML_RPC_SOCKET = "/var/run/xend/xmlrpc.sock"
+XEN_API_SOCKET = "/var/run/xend/xen-api.sock"
ERROR_INTERNAL = 1
ERROR_GENERIC = 2
diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py
new file mode 100644
index 0000000000..da7898c72c
--- /dev/null
+++ b/tools/python/xen/xend/XendConfig.py
@@ -0,0 +1,947 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd
+#============================================================================
+
+import re
+import time
+import types
+
+from xen.xend import sxp
+from xen.xend import uuid
+from xen.xend.XendError import VmError
+from xen.xend.XendDevices import XendDevices
+from xen.xend.XendLogging import log
+from xen.xend.PrettyPrint import prettyprintstring
+from xen.xend.XendConstants import DOM_STATE_HALTED
+
+"""
+XendConfig API
+
+ XendConfig will try to mirror as closely the Xen API VM Struct
+ providing a backwards compatibility mode for SXP dumping, loading.
+
+"""
+
+
+LEGACY_CFG_TO_XENAPI_CFG = {
+ 'uuid': 'uuid',
+ 'vcpus': 'vcpus_number',
+ 'maxmem': 'memory_static_max',
+ 'memory': 'memory_static_min',
+ 'name': 'name_label',
+ 'on_poweroff': 'actions_after_shutdown',
+ 'on_reboot': 'actions_after_reboot',
+ 'on_crash': 'actions_after_crash',
+ 'bootloader': 'boot_method',
+ 'kernel_kernel': 'kernel_kernel',
+ 'kernel_initrd': 'kernel_initrd',
+ 'kernel_args': 'kernel_args',
+ }
+
+XENAPI_CFG_CUSTOM_TRANSLATE = [
+ 'vifs',
+ 'vbds',
+ ]
+
+XENAPI_HVM_CFG = {
+ 'platform_std_vga': 'std-vga',
+ 'platform_serial' : 'serial',
+ 'platform_localtime': 'localtime',
+ 'platform_enable_audio': 'soundhw',
+ 'platform_keymap' : 'keymap',
+}
+
+XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [
+ 'name_description',
+ 'user_version',
+ 'is_a_template',
+ 'memory_dynamic_min',
+ 'memory_dynamic_max',
+ 'memory_actual',
+ 'vcpus_policy',
+ 'vcpus_params',
+ 'vcpus_features_required',
+ 'vcpus_features_can_use',
+ 'vcpus_features_force_on',
+ 'vcpus_features_force_off',
+ 'actions_after_suspend',
+ 'bios_boot',
+ 'platform_std_vga',
+ 'platform_serial',
+ 'platform_localtime',
+ 'platform_clock_offset',
+ 'platform_enable_audio',
+ 'platform_keymap',
+ 'builder',
+ 'grub_cmdline',
+ 'pci_bus',
+ 'otherconfig'
+ ]
+
+
+# configuration params that need to be converted to ints
+# since the XMLRPC transport for Xen API does not use
+# 32 bit ints but string representation of 64 bit ints.
+XENAPI_INT_CFG = [
+ 'user_version',
+ 'vcpus_number',
+ 'memory_static_min',
+ 'memory_static_max',
+ 'memory_dynamic_min',
+ 'memory_dynamic_max',
+ 'tpm_instance',
+ 'tpm_backend',
+]
+
+##
+## Xend Configuration Parameters
+##
+
+
+# All parameters of VMs that may be configured on-the-fly, or at start-up.
+VM_CONFIG_ENTRIES = [
+ ('name', str),
+ ('on_crash', str),
+ ('on_poweroff', str),
+ ('on_reboot', str),
+ ('on_xend_start', str),
+ ('on_xend_stop', str),
+]
+
+# All entries written to the store. This is VM_CONFIG_ENTRIES, plus those
+# entries written to the store that cannot be reconfigured on-the-fly.
+VM_STORE_ENTRIES = [
+ ('uuid', str),
+ ('vcpus', int),
+ ('vcpu_avail', int),
+ ('memory', int),
+ ('maxmem', int),
+ ('start_time', float),
+]
+
+VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES
+
+# Configuration entries that we expect to round-trip -- be read from the
+# config file or xc, written to save-files (i.e. through sxpr), and reused as
+# config on restart or restore, all without munging. Some configuration
+# entries are munged for backwards compatibility reasons, or because they
+# don't come out of xc in the same form as they are specified in the config
+# file, so those are handled separately.
+
+ROUNDTRIPPING_CONFIG_ENTRIES = [
+ ('uuid', str),
+ ('vcpus', int),
+ ('vcpu_avail', int),
+ ('cpu_cap', int),
+ ('cpu_weight', int),
+ ('memory', int),
+ ('shadow_memory', int),
+ ('maxmem', int),
+ ('bootloader', str),
+ ('bootloader_args', str),
+ ('features', str),
+ ('localtime', int),
+]
+ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES
+
+## Static Configuration
+
+STATIC_CONFIG_ENTRIES = [
+ ('cpu', int),
+ ('cpus', str),
+ ('image', list),
+ ('security', list), # TODO: what if null?
+]
+
+DEPRECATED_ENTRIES = [
+ ('restart', str),
+]
+
+##
+## Config Choices
+##
+
+CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
+CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
+ 'crashed', 'dying')
+
+##
+## Defaults
+##
+
+def DEFAULT_VCPUS(info):
+ if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1
+ else: return 1
+
+DEFAULT_CONFIGURATION = (
+ ('uuid', lambda info: uuid.createString()),
+ ('name', lambda info: 'Domain-' + info['uuid']),
+
+ ('on_poweroff', lambda info: 'destroy'),
+ ('on_reboot', lambda info: 'restart'),
+ ('on_crash', lambda info: 'restart'),
+ ('features', lambda info: ''),
+
+
+ ('memory', lambda info: 0),
+ ('shadow_memory',lambda info: 0),
+ ('maxmem', lambda info: 0),
+ ('bootloader', lambda info: None),
+ ('bootloader_args', lambda info: None),
+ ('backend', lambda info: []),
+ ('device', lambda info: {}),
+ ('image', lambda info: None),
+ ('security', lambda info: []),
+ ('on_xend_start', lambda info: 'ignore'),
+ ('on_xend_stop', lambda info: 'ignore'),
+
+ ('cpus', lambda info: []),
+ ('cpu_cap', lambda info: 0),
+ ('cpu_weight', lambda info: 256),
+ ('vcpus', lambda info: DEFAULT_VCPUS(info)),
+ ('online_vcpus', lambda info: info['vcpus']),
+ ('max_vcpu_id', lambda info: info['vcpus']-1),
+ ('vcpu_avail', lambda info: (1<<info['vcpus'])-1),
+
+ # New for Xen API
+ ('kernel_kernel', lambda info: ''),
+ ('kernel_initrd', lambda info: ''),
+ ('kernel_args', lambda info: ''),
+
+)
+
+class XendConfigError(VmError):
+ def __str__(self):
+ return 'Invalid Configuration: %s' % str(self.value)
+
+##
+## XendConfig SXP Config Compat
+##
+
+class XendSXPConfig:
+ def get_domid(self):
+ pass
+ def get_handle(self):
+ return self['uuid']
+
+
+##
+## XendConfig Class (an extended dictionary)
+##
+
+class XendConfig(dict):
+ """ Generic Configuration Parser accepting SXP, Python or XML.
+ This is a dictionary-like object that is populated.
+
+ @ivar legacy: dictionary holding legacy xen domain info
+ @ivar xenapi: dictionary holding xen api config info
+ """
+
+ def __init__(self, filename = None, fd = None,
+ sxp = None, xml = None, pycfg = None, xenapi_vm = None,
+ cfg = {}):
+ """Constructor. Provide either the filename, fd or sxp.
+
+ @keyword filename: filename of an SXP file
+ @keyword fd: file descriptor of an SXP file
+ @keyword sxp: a list of list of a parsed SXP
+ @keyword xml: an XML tree object
+ @keyword xenapi_vm: a struct passed from an XMLRPC call (Xen API)
+ @keyword cfg: a dictionary of configuration (eg. from xc)
+ """
+ format = 'unknown'
+
+ self.xenapi = {}
+
+ if filename and not fd:
+ fd = open(filename, 'r')
+
+ if fd:
+ format = self._detect_format(fd)
+
+ if fd:
+ if format == 'sxp':
+ sxp = self._read_sxp(fd)
+ elif format == 'python' and filename != None:
+ pycfg = self._read_python(filename)
+ elif format == 'python' and filename == None:
+ raise XendConfigError("Python files must be passed as a "
+ "filename rather than file descriptor.")
+ elif format == 'xml':
+ xml = self._read_xml(fd)
+ else:
+ raise XendConfigError("Unable to determine format of file")
+
+ if sxp:
+ cfg = self._populate_from_sxp(sxp)
+ if xml:
+ cfg = self._populate_from_xml(xml)
+ if pycfg:
+ cfg = self._populate_from_python_config(pycfg)
+ if xenapi_vm:
+ cfg = self._populate_from_xenapi_vm(xenapi_vm)
+
+ if cfg:
+ self.update(cfg)
+
+ if xenapi_vm:
+ self.xenapi.update(xenapi_vm)
+
+ log.debug('XendConfig: %s' % str(self))
+ self.validate()
+
+ #
+ # Xen API Attribute Access
+ #
+
+ def __getattr__(self, name):
+ try:
+ return dict.__getattr__(self, name)
+ except AttributeError:
+ try:
+ return self.__dict__['xenapi'][name]
+ except KeyError:
+ raise AttributeError("XendConfig Xen API has no attribute "
+ "'%s'" % name)
+
+
+ def __setattr__(self, name, value):
+ try:
+ return dict.__setattr__(self, name, value)
+ except AttributeError:
+ self.xenapi[name] = value
+ #self.set_legacy_api_with_xen_api_value(name, value)
+
+ def __delattr__(self, name):
+ try:
+ dict.__delattr__(self, name)
+ except AttributeError:
+ del self.xenapi[name]
+ #self.del_legacy_api_with_xen_api_key(name)
+
+
+ """
+ #
+ # Legacy API Attribute Access
+ #
+
+ def __getitem__(self, key):
+ try:
+ return self.legacy[key]
+ except KeyError:
+ raise AttributeError, "XendConfig Legacy has no attribute '%s'"\
+ % key
+
+ def __setitem__(self, key, value):
+ self.legacy[key] = value
+ self.set_xen_api_with_legacy_api_value(key, value)
+
+ def __delitem__(self, key):
+ del self.legacy[key]
+ self.del_xen_api_with_legacy_api_key(key)
+ """
+
+
+ def _detect_format(self, fd):
+ """Detect the format of the configuration passed.
+
+ @param fd: file descriptor of contents to detect
+ @rtype: string, 'sxp', 'xml', 'python' or 'unknown'
+ """
+ format = 'unknown'
+
+ fd.seek(0)
+ for line in fd:
+ stripped = line.strip()
+ if stripped:
+ if re.search(r'^\(', stripped):
+ format = 'sxp'
+ elif re.search(r'^\<?xml', stripped):
+ format = 'xml'
+ else:
+ format = 'python'
+ break
+
+ fd.seek(0)
+ return format
+
+ def _read_sxp(self, fd):
+ """ Read and parse SXP (from SXP to list of lists)
+
+ @rtype: list of lists.
+ """
+ try:
+ parsed = sxp.parse(fd)[0]
+ return parsed
+ except:
+ raise
+ return None
+
+ def _read_xml(self, fd):
+ """TODO: Read and parse XML (from XML to dict)
+
+ @rtype: dict
+ """
+ raise NotImplementedError
+
+ def _read_python(self, filename):
+ """Read and parse python module that represents the config.
+
+ @rtype: dict
+ """
+ cfg_globals = {}
+ execfile(filename, cfg_globals, {})
+ return cfg_globals
+
+ def _populate_from_sxp(self, parsed):
+ """ Populate this XendConfig using the parsed SXP.
+
+ @rtype: dictionary
+ """
+ cfg = {}
+
+ # First step is to convert deprecated options to
+ # current equivalents.
+
+ restart = sxp.child_value(parsed, 'restart')
+ if restart:
+ if restart == 'onreboot':
+ cfg['on_poweroff'] = 'destroy'
+ cfg['on_reboot'] = 'restart'
+ cfg['on_crash'] = 'destroy'
+ elif restart == 'always':
+ for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
+ cfg[opt] = 'restart'
+ elif restart == 'never':
+ for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
+ cfg[opt] = 'never'
+ else:
+ log.warn('Ignoring unrecognised value for deprecated option:'
+ 'restart = \'%s\'', restart)
+
+ # Only extract options we know about.
+ all_params = VM_CONFIG_ENTRIES + ROUNDTRIPPING_CONFIG_ENTRIES + \
+ STATIC_CONFIG_ENTRIES
+
+ for key, typeconv in all_params:
+ val = sxp.child_value(parsed, key)
+ if val:
+ try:
+ cfg[key] = typeconv(val)
+ except ValueError:
+ pass
+
+ # Manually extract other complex configuration
+ # options.
+
+ cfg['backend'] = []
+ for c in sxp.children(parsed, 'backend'):
+ cfg['backend'].append(sxp.name(sxp.child0(c)))
+
+ # Parsing the device SXP's. In most cases, the SXP looks
+ # like this:
+ #
+ # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
+ #
+ # However, for PCI devices it looks like this:
+ #
+ # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
+ #
+ # It seems the reasoning for this difference is because
+ # pciif.py needs all the PCI device configurations at
+ # the same time when creating the devices.
+ #
+ # To further complicate matters, Xen 2.0 configuration format
+ # uses the following for pci device configuration:
+ #
+ # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
+ #
+ # Hence we deal with pci device configurations outside of
+ # the regular device parsing.
+
+ cfg['device'] = {}
+ for dev in sxp.children(parsed, 'device'):
+ config = sxp.child0(dev)
+ dev_type = sxp.name(config)
+ dev_info = {}
+
+ if dev_type == 'pci':
+ continue
+
+ for opt, val in config[1:]:
+ dev_info[opt] = val
+ log.debug("XendConfig: reading device: %s" % dev_info)
+ # create uuid if it doesn't
+ dev_uuid = dev_info.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ cfg['device'][dev_uuid] = (dev_type, dev_info)
+
+ # deal with PCI device configurations if they exist
+ for dev in sxp.children(parsed, 'device'):
+ config = sxp.child0(dev)
+ dev_type = sxp.name(config)
+
+ if dev_type != 'pci':
+ continue
+
+ dev_attr = sxp.child_value(config, 'dev')
+ if isinstance(dev_attr, (types.ListType, types.TupleType)):
+ for pci_dev in sxp.children(config, 'dev'):
+ dev_info = {}
+ for opt, val in pci_dev[1:]:
+ dev_info[opt] = val
+ log.debug("XendConfig: reading device: %s" % dev_info)
+ dev_uuid = dev_info.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ cfg['device'][dev_uuid] = (dev_type, dev_info)
+
+ else: # Xen 2.0 PCI device configuration
+ for opt, val in config[1:]:
+ dev_info[opt] = val
+ log.debug("XendConfig: reading device: %s" % dev_info)
+ # create uuid if it doesn't
+ dev_uuid = dev_info.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ cfg['device'][dev_uuid] = (dev_type, dev_info)
+
+ # Extract missing data from configuration entries
+ if 'image' in cfg:
+ image_vcpus = sxp.child_value(cfg['image'], 'vcpus')
+ if image_vcpus is not None:
+ try:
+ if 'vcpus' not in cfg:
+ cfg['vcpus'] = int(image_vcpus)
+ elif cfg['vcpus'] != int(image_vcpus):
+ cfg['vcpus'] = int(image_vcpus)
+ log.warn('Overriding vcpus from %d to %d using image'
+ 'vcpus value.', cfg['vcpus'])
+ except ValueError, e:
+ raise XendConfigError('integer expeceted: %s: %s' %
+ str(cfg['image']), e)
+
+ # Deprecated cpu configuration
+ if 'cpu' in cfg:
+ if 'cpus' in cfg:
+ cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
+ else:
+ cfg['cpus'] = str(cfg['cpu'])
+
+ # convert 'cpus' string to list of ints
+ # 'cpus' supports a list of ranges (0-3), seperated by
+ # commas, and negation, (^1).
+ # Precedence is settled by order of the string:
+ # "0-3,^1" -> [0,2,3]
+ # "0-3,^1,1" -> [0,1,2,3]
+ try:
+ if 'cpus' in cfg:
+ cpus = []
+ for c in cfg['cpus'].split(','):
+ if c.find('-') != -1:
+ (x, y) = c.split('-')
+ for i in range(int(x), int(y)+1):
+ cpus.append(int(i))
+ else:
+ # remove this element from the list
+ if c[0] == '^':
+ cpus = [x for x in cpus if x != int(c[1:])]
+ else:
+ cpus.append(int(c))
+
+ cfg['cpus'] = cpus
+ except ValueError, e:
+ raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
+
+ # Parse image SXP outside of image.py
+ # - used to be only done in image.py
+ if 'image' in cfg:
+ cfg['kernel_kernel'] = sxp.child_value(cfg['image'], 'kernel','')
+ cfg['kernel_initrd'] = sxp.child_value(cfg['image'], 'ramdisk','')
+ kernel_args = sxp.child_value(cfg['image'], 'args', '')
+
+ # attempt to extract extra arguments from SXP config
+ arg_ip = sxp.child_value(cfg['image'], 'ip')
+ if arg_ip: kernel_args += ' ip=%s' % arg_ip
+ arg_root = sxp.child_value(cfg['image'], 'root')
+ if arg_root: kernel_args += ' root=%s' % arg_root
+
+ cfg['kernel_args'] = kernel_args
+
+ # TODO: get states
+ old_state = sxp.child_value(parsed, 'state')
+ if old_state:
+ for i in range(len(CONFIG_OLD_DOM_STATES)):
+ cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
+
+ # Xen API extra cfgs
+ # ------------------
+ cfg['vif_refs'] = []
+ cfg['vbd_refs'] = []
+ cfg['vtpm_refs'] = []
+ for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
+ if dev_type == 'vif':
+ cfg['vif_refs'].append(dev_uuid)
+ elif dev_type in ('vbd','tap'):
+ cfg['vbd_refs'].append(dev_uuid)
+ elif dev_type == 'vtpm':
+ cfg['vtpm_refs'].append(dev_uuid)
+
+ return cfg
+
+
+ def _populate_from_xenapi_vm(self, xenapi_vm):
+ cfg = {}
+
+ for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+ try:
+ if apikey in XENAPI_INT_CFG:
+ cfg[cfgkey] = int(xenapi_vm[apikey])
+ else:
+ cfg[cfgkey] = xenapi_vm[apikey]
+ except KeyError:
+ pass
+
+ # Reconstruct image SXP
+ # TODO: get rid of SXP altogether from here
+ sxp_image = ['linux']
+ if xenapi_vm['kernel_kernel']:
+ sxp_image.append(['kernel', xenapi_vm['kernel_kernel']])
+ if xenapi_vm['kernel_initrd']:
+ sxp_image.append(['ramdisk', xenapi_vm['kernel_initrd']])
+ if xenapi_vm['kernel_args']:
+ sxp_image.append(['args', xenapi_vm['kernel_args']])
+
+ cfg['image'] = prettyprintstring(sxp_image)
+
+ # make sure device structures are there.
+ if 'device' not in cfg:
+ cfg['device'] = {}
+ if 'vif_refs' not in cfg:
+ cfg['vif_refs'] = []
+ if 'vbd_refs' not in cfg:
+ cfg['vbd_refs'] = []
+ if 'vtpm_refs' not in cfg:
+ cfg['vtpm_refs'] = []
+
+ return cfg
+
+
+ def _sync_xen_api_from_legacy_api(self):
+ """ Sync all the attributes that is supported by the Xen API
+ from the legacy API configuration.
+ """
+ for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+ if cfgkey in self:
+ self.xenapi[apikey] = self[cfgkey]
+
+ def _sync_legacy_api_from_xen_api(self):
+ for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+ if apikey in self.xenapi:
+ self[cfgkey] = self.xenapi[apikey]
+
+
+ def _populate_from_xml(self, parsed_xml):
+ raise NotImplementedError
+
+ def _populate_from_python_config(self, parsed_py):
+ raise NotImplementedError
+
+ def _get_old_state_string(self):
+ state_string = ''
+ for state_name in CONFIG_OLD_DOM_STATES:
+ on_off = self.get(state_name, 0)
+ if on_off:
+ state_string += state_name[0]
+ else:
+ state_string += '-'
+
+ return state_string
+
+ def get_sxp(self, domain = None, ignore_devices = False, ignore = []):
+ """ Get SXP representation of this config object.
+
+ @keyword domain: (optional) XendDomainInfo to get extra information
+ from such as domid and running devices.
+ @type domain: XendDomainInfo
+ @keyword ignore: (optional) list of 'keys' that we do not want
+ to export.
+ @type ignore: list of strings
+ @rtype: list of list (SXP representation)
+ """
+ sxpr = ['domain']
+
+ # TODO: domid/dom is the same thing but called differently
+ # depending if it is from xenstore or sxpr.
+
+ if domain.getDomid() is not None:
+ sxpr.append(['domid', domain.getDomid()])
+
+ for cfg, typefunc in ROUNDTRIPPING_CONFIG_ENTRIES:
+ if cfg in self:
+ if self[cfg] is not None:
+ sxpr.append([cfg, self[cfg]])
+
+ if 'image' in self and self['image'] is not None:
+ sxpr.append(['image', self['image']])
+ if 'security' in self and self['security']:
+ sxpr.append(['security', self['security']])
+ if 'shutdown_reason' in self:
+ sxpr.append(['shutdown_reason', self['shutdown_reason']])
+ if 'cpu_time' in self:
+ sxpr.append(['cpu_time', self['cpu_time']/1e9])
+
+ sxpr.append(['online_vcpus', self['online_vcpus']])
+
+ if 'start_time' in self:
+ uptime = time.time() - self['start_time']
+ sxpr.append(['up_time', str(uptime)])
+ sxpr.append(['start_time', str(self['start_time'])])
+
+ if domain:
+ sxpr.append(['status', str(domain.state)])
+ else:
+ sxpr.append(['status', str(DOM_STATE_HALTED)])
+
+ if domain.getDomid() is not None:
+ sxpr.append(['state', self._get_old_state_string()])
+
+ sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max',
+ self['memory'])])
+
+ # For save/restore migration
+ if domain:
+ if domain.store_mfn:
+ sxpr.append(['store_mfn', domain.store_mfn])
+ if domain.console_mfn:
+ sxpr.append(['console_mfn', domain.console_mfn])
+
+ # Marshall devices (running or from configuration)
+ if not ignore_devices:
+ for cls in XendDevices.valid_devices():
+ found = False
+
+ # figure if there is a device that is running
+ if domain:
+ try:
+ controller = domain.getDeviceController(cls)
+ configs = controller.configurations()
+ for config in configs:
+ sxpr.append(['device', config])
+ found = True
+ except:
+ log.exception("dumping sxp from device controllers")
+ pass
+
+ # if we didn't find that device, check the existing config
+ # for a device in the same class
+ if not found:
+ for dev_type, dev_info in self.all_devices_sxpr():
+ if dev_type == cls:
+ sxpr.append(['device', dev_info])
+
+ return sxpr
+
+ def validate(self):
+ """ Validate the configuration and fill in missing configuration
+ with defaults.
+ """
+
+ # Fill in default values
+ for key, default_func in DEFAULT_CONFIGURATION:
+ if key not in self or self[key] == None:
+ self[key] = default_func(self)
+
+ # Basic sanity checks
+ if 'image' in self and isinstance(self['image'], str):
+ self['image'] = sxp.from_string(self['image'])
+ if 'security' in self and isinstance(self['security'], str):
+ self['security'] = sxp.from_string(self['security'])
+ if self['memory'] == 0 and 'mem_kb' in self:
+ self['memory'] = (self['mem_kb'] + 1023)/1024
+ if self['memory'] <= 0:
+ raise XendConfigError('Invalid memory size: %s' %
+ str(self['memory']))
+
+ self['maxmem'] = max(self['memory'], self['maxmem'])
+
+ # convert mem_kb from domain_getinfo to something more descriptive
+ if 'mem_kb' in self:
+ self['memory_dynamic_max'] = (self['mem_kb'] + 1023)/1024
+
+ # Verify devices
+ for d_uuid, (d_type, d_info) in self['device'].items():
+ if d_type not in XendDevices.valid_devices() and \
+ d_type not in XendDevices.pseudo_devices():
+ raise XendConfigError('Invalid device (%s)' % d_type)
+
+ # Verify restart modes
+ for event in ('on_poweroff', 'on_reboot', 'on_crash'):
+ if self[event] not in CONFIG_RESTART_MODES:
+ raise XendConfigError('Invalid restart event: %s = %s' % \
+ (event, str(self[event])))
+
+ # Verify that {vif,vbd}_refs are here too
+ if 'vif_refs' not in self:
+ self['vif_refs'] = []
+ if 'vbd_refs' not in self:
+ self['vbd_refs'] = []
+ if 'vtpm_refs' not in self:
+ self['vtpm_refs'] = []
+
+ def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
+ if dev_type not in XendDevices.valid_devices() and \
+ dev_type not in XendDevices.pseudo_devices():
+ raise XendConfigError("XendConfig: %s not a valid device type" %
+ dev_type)
+
+ if cfg_sxp == None and cfg_xenapi == None:
+ raise XendConfigError("XendConfig: device_add requires some "
+ "config.")
+
+ if cfg_sxp:
+ log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
+ if cfg_xenapi:
+ log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
+
+ if cfg_sxp:
+ dev_info = {}
+
+ try:
+ for opt, val in cfg_sxp[1:]:
+ dev_info[opt] = val
+ except ValueError:
+ pass # SXP has no options for this device
+
+ # create uuid if it doesn't exist
+ dev_uuid = dev_info.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ self['device'][dev_uuid] = (dev_type, dev_info)
+ if dev_type in ('vif', 'vbd'):
+ self['%s_refs' % dev_type].append(dev_uuid)
+ elif dev_type in ('tap',):
+ self['vbd_refs'].append(dev_uuid)
+ return dev_uuid
+
+ if cfg_xenapi:
+ dev_info = {}
+ if dev_type == 'vif':
+ if cfg_xenapi.get('MAC'): # don't add if blank
+ dev_info['mac'] = cfg_xenapi.get('MAC')
+ # vifname is the name on the guest, not dom0
+ # TODO: we don't have the ability to find that out or
+ # change it from dom0
+ #if cfg_xenapi.get('device'): # don't add if blank
+ # dev_info['vifname'] = cfg_xenapi.get('device')
+ if cfg_xenapi.get('type'):
+ dev_info['type'] = cfg_xenapi.get('type')
+
+ dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ self['device'][dev_uuid] = (dev_type, dev_info)
+ self['vif_refs'].append(dev_uuid)
+ return dev_uuid
+
+ elif dev_type == 'vbd':
+ dev_info['uname'] = cfg_xenapi.get('image', None)
+ dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+ if cfg_xenapi.get('mode') == 'RW':
+ dev_info['mode'] = 'w'
+ else:
+ dev_info['mode'] = 'r'
+
+ dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ self['device'][dev_uuid] = (dev_type, dev_info)
+ self['vbd_refs'].append(dev_uuid)
+ return dev_uuid
+
+ elif dev_type == 'vtpm':
+ if cfg_xenapi.get('type'):
+ dev_info['type'] = cfg_xenapi.get('type')
+ dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ self['device'][dev_uuid] = (dev_type, dev_info)
+ self['vtpm_refs'].append(dev_uuid)
+ return dev_uuid
+
+ elif dev_type == 'tap':
+ dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
+ dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+
+ if cfg_xenapi.get('mode') == 'RW':
+ dev_info['mode'] = 'w'
+ else:
+ dev_info['mode'] = 'r'
+
+ dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+ dev_info['uuid'] = dev_uuid
+ self['device'][dev_uuid] = (dev_type, dev_info)
+ self['vbd_refs'].append(dev_uuid)
+ return dev_uuid
+
+ return ''
+
+ def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
+ """Get Device SXPR by either giving the device UUID or (type, config).
+
+ @rtype: list of lists
+ @return: device config sxpr
+ """
+ sxpr = []
+ if dev_uuid != None and dev_uuid in self['device']:
+ dev_type, dev_info = self['device'][dev_uuid]
+
+ if dev_type == None or dev_info == None:
+ raise XendConfigError("Required either UUID or device type and "
+ "configuration dictionary.")
+
+ sxpr.append(dev_type)
+ config = [(opt, val) for opt, val in dev_info.items()]
+ sxpr += config
+
+ return sxpr
+
+ def all_devices_sxpr(self):
+ """Returns the SXPR for all devices in the current configuration."""
+ sxprs = []
+ pci_devs = []
+ for dev_type, dev_info in self['device'].values():
+ if dev_type == 'pci': # special case for pci devices
+ pci_devs.append(dev_info)
+ else:
+ sxpr = self.device_sxpr(dev_type = dev_type,
+ dev_info = dev_info)
+ sxprs.append((dev_type, sxpr))
+
+ # if we have any pci_devs, we parse them differently into
+ # one single pci SXP entry.
+ if pci_devs:
+ sxpr = ['pci',]
+ for dev_info in pci_devs:
+ dev_sxpr = self.device_sxpr(dev_type = 'dev',
+ dev_info = dev_info)
+ sxpr.append(dev_sxpr)
+ sxprs.append(('pci', sxpr))
+
+ return sxprs
+
+
+#
+# debugging
+#
+
+if __name__ == "__main__":
+ pass
+
diff --git a/tools/python/xen/xend/XendConstants.py b/tools/python/xen/xend/XendConstants.py
new file mode 100644
index 0000000000..96f7a22d7e
--- /dev/null
+++ b/tools/python/xen/xend/XendConstants.py
@@ -0,0 +1,102 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+
+from xen.xend.XendAPIConstants import *
+
+#
+# Shutdown codes and reasons.
+#
+
+DOMAIN_POWEROFF = 0
+DOMAIN_REBOOT = 1
+DOMAIN_SUSPEND = 2
+DOMAIN_CRASH = 3
+DOMAIN_HALT = 4
+
+DOMAIN_SHUTDOWN_REASONS = {
+ DOMAIN_POWEROFF: "poweroff",
+ DOMAIN_REBOOT : "reboot",
+ DOMAIN_SUSPEND : "suspend",
+ DOMAIN_CRASH : "crash",
+ DOMAIN_HALT : "halt"
+}
+
+restart_modes = [
+ "restart",
+ "destroy",
+ "preserve",
+ "rename-restart"
+ ]
+
+DOM_STATES = [
+ 'halted',
+ 'paused',
+ 'running',
+ 'suspended',
+ 'shutdown',
+ 'unknown',
+]
+
+DOM_STATE_HALTED = XEN_API_VM_POWER_STATE_HALTED
+DOM_STATE_PAUSED = XEN_API_VM_POWER_STATE_PAUSED
+DOM_STATE_RUNNING = XEN_API_VM_POWER_STATE_RUNNING
+DOM_STATE_SUSPENDED = XEN_API_VM_POWER_STATE_SUSPENDED
+DOM_STATE_SHUTDOWN = XEN_API_VM_POWER_STATE_SHUTTINGDOWN
+DOM_STATE_UNKNOWN = XEN_API_VM_POWER_STATE_UNKNOWN
+
+DOM_STATES_OLD = [
+ 'running',
+ 'blocked',
+ 'paused',
+ 'shutdown',
+ 'crashed',
+ 'dying'
+ ]
+
+STATE_DOM_OK = 1
+STATE_DOM_SHUTDOWN = 2
+
+SHUTDOWN_TIMEOUT = 30.0
+
+ZOMBIE_PREFIX = 'Zombie-'
+
+"""Minimum time between domain restarts in seconds."""
+MINIMUM_RESTART_TIME = 20
+
+RESTART_IN_PROGRESS = 'xend/restart_in_progress'
+
+#
+# Device migration stages (eg. XendDomainInfo, XendCheckpoint, server.tpmif)
+#
+
+DEV_MIGRATE_TEST = 0
+DEV_MIGRATE_STEP1 = 1
+DEV_MIGRATE_STEP2 = 2
+DEV_MIGRATE_STEP3 = 3
+
+#
+# VTPM-related constants
+#
+
+VTPM_DELETE_SCRIPT = '/etc/xen/scripts/vtpm-delete'
+
+#
+# Xenstore Constants
+#
+
+XS_VMROOT = "/vm/"
+
diff --git a/tools/python/xen/xend/XendDevices.py b/tools/python/xen/xend/XendDevices.py
new file mode 100644
index 0000000000..ce91e28271
--- /dev/null
+++ b/tools/python/xen/xend/XendDevices.py
@@ -0,0 +1,83 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd
+#============================================================================
+
+#
+# A collection of DevControllers
+#
+
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif
+from xen.xend.server.BlktapController import BlktapController
+
+class XendDevices:
+ """ An ugly halfway point between the module local device name
+ to class map we used to have in XendDomainInfo and something
+ slightly more managable.
+
+ This class should contain all the functions that have to do
+ with managing devices in Xend. Right now it is only a factory
+ function.
+ """
+
+ controllers = {
+ 'vbd': blkif.BlkifController,
+ 'vif': netif.NetifController,
+ 'vtpm': tpmif.TPMifController,
+ 'pci': pciif.PciController,
+ 'ioports': iopif.IOPortsController,
+ 'irq': irqif.IRQController,
+ 'usb': usbif.UsbifController,
+ 'tap': BlktapController,
+ }
+
+ #@classmethod
+ def valid_devices(cls):
+ return cls.controllers.keys()
+ valid_devices = classmethod(valid_devices)
+
+ #@classmethod
+ def pseudo_devices(cls):
+ return ['console']
+ pseudo_devices = classmethod(pseudo_devices)
+
+ #@classmethod
+ def make_controller(cls, name, domain):
+ """Factory function to make device controllers per domain.
+
+ @param name: device class name in L{VALID_DEVICES}
+ @type name: String
+ @param domain: domain this controller is handling devices for.
+ @type domain: XendDomainInfo
+ @return: DevController of class 'name' or None
+ @rtype: subclass of DevController
+ """
+ if name in cls.controllers.keys():
+ cls.controllers[name].deviceClass = name
+ return cls.controllers[name](domain)
+ return None
+
+ make_controller = classmethod(make_controller)
+
+ def destroy_device_state(cls, domain):
+ """Destroy the state of (external) devices. This is necessary
+ to do when a VM's configuration is destroyed.
+
+ @param domain: domain this controller is handling devices for.
+ @type domain: XendDomainInfo
+ """
+ tpmif.destroy_vtpmstate(domain.getName())
+
+ destroy_device_state = classmethod(destroy_device_state)
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
index e9eb8981d2..4d84bc14e6 100644
--- a/tools/python/xen/xend/XendDomain.py
+++ b/tools/python/xen/xend/XendDomain.py
@@ -22,45 +22,73 @@
Needs to be persistent for one uptime.
"""
-import logging
import os
+import shutil
import socket
-import sys
import threading
import xen.lowlevel.xc
-import XendDomainInfo
-from xen.xend import XendRoot
-from xen.xend import XendCheckpoint
-from xen.xend.XendError import XendError, XendInvalidDomain
+from xen.xend import XendRoot, XendCheckpoint, XendDomainInfo
+from xen.xend.PrettyPrint import prettyprint
+from xen.xend.XendConfig import XendConfig
+from xen.xend.XendError import XendError, XendInvalidDomain, VmError
from xen.xend.XendLogging import log
+from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE
+from xen.xend.XendConstants import XS_VMROOT
+from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_PAUSED
+from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED
+from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
+from xen.xend.XendDevices import XendDevices
+
from xen.xend.xenstore.xstransact import xstransact
from xen.xend.xenstore.xswatch import xswatch
from xen.util import security
-
+from xen.xend import uuid
xc = xen.lowlevel.xc.xc()
-xroot = XendRoot.instance()
-
+xroot = XendRoot.instance()
__all__ = [ "XendDomain" ]
-PRIV_DOMAIN = 0
-VMROOT = '/vm/'
+CACHED_CONFIG_FILE = 'config.sxp'
+CHECK_POINT_FILE = 'checkpoint.chk'
+DOM0_UUID = "00000000-0000-0000-0000-000000000000"
+DOM0_NAME = "Domain-0"
+DOM0_ID = 0
+
+POWER_STATE_NAMES = dict([(x, XEN_API_VM_POWER_STATE[x])
+ for x in [DOM_STATE_HALTED,
+ DOM_STATE_PAUSED,
+ DOM_STATE_RUNNING,
+ DOM_STATE_SUSPENDED,
+ DOM_STATE_SHUTDOWN,
+ DOM_STATE_UNKNOWN]])
+POWER_STATE_ALL = 'all'
class XendDomain:
"""Index of all domains. Singleton.
+
+ @ivar domains: map of domains indexed by domid
+ @type domains: dict of XendDomainInfo
+ @ivar managed_domains: domains that are not running and managed by Xend
+ @type managed_domains: dict of XendDomainInfo indexed by uuid
+ @ivar domains_lock: lock that must be held when manipulating self.domains
+ @type domains_lock: threaading.RLock
+ @ivar _allow_new_domains: Flag to set that allows creating of new domains.
+ @type _allow_new_domains: boolean
"""
- ## public:
-
def __init__(self):
self.domains = {}
+ self.managed_domains = {}
self.domains_lock = threading.RLock()
+ # xen api instance vars
+ # TODO: nothing uses this at the moment
+ self._allow_new_domains = True
# This must be called only the once, by instance() below. It is separate
# from the constructor because XendDomainInfo calls back into this class
@@ -68,85 +96,281 @@ class XendDomain:
# instance() must be able to return a valid instance of this class even
# during this initialisation.
def init(self):
- xstransact.Mkdir(VMROOT)
- xstransact.SetPermissions(VMROOT, { 'dom' : PRIV_DOMAIN })
+ """Singleton initialisation function."""
+
+ dom_path = self._managed_path()
+ try:
+ os.stat(dom_path)
+ except OSError:
+ log.info("Making %s", dom_path)
+ os.makedirs(dom_path, 0755)
+
+ xstransact.Mkdir(XS_VMROOT)
+ xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID})
self.domains_lock.acquire()
try:
- self._add_domain(
- XendDomainInfo.recreate(self.xen_domains()[PRIV_DOMAIN],
- True))
- self.dom0_setup()
+ try:
+ dom0info = [d for d in self._running_domains() \
+ if d.get('domid') == DOM0_ID][0]
+
+ dom0info['name'] = DOM0_NAME
+ dom0 = XendDomainInfo.recreate(dom0info, True)
+ self._add_domain(dom0)
+ except IndexError:
+ raise XendError('Unable to find Domain 0')
+
+ self._setDom0CPUCount()
# This watch registration needs to be before the refresh call, so
# that we're sure that we haven't missed any releases, but inside
# the domains_lock, as we don't want the watch to fire until after
# the refresh call has completed.
- xswatch("@introduceDomain", self.onChangeDomain)
- xswatch("@releaseDomain", self.onChangeDomain)
-
- self.refresh(True)
+ xswatch("@introduceDomain", self._on_domains_changed)
+ xswatch("@releaseDomain", self._on_domains_changed)
+
+ self._init_domains()
finally:
self.domains_lock.release()
+
+ def _on_domains_changed(self, _):
+ """ Callback method when xenstore changes.
- def list(self):
- """Get list of domain objects.
+ Calls refresh which will keep the local cache of domains
+ in sync.
- @return: domain objects
+ @rtype: int
+ @return: 1
"""
self.domains_lock.acquire()
try:
- self.refresh()
- return self.domains.values()
+ self._refresh()
finally:
self.domains_lock.release()
+ return 1
+ def _init_domains(self):
+ """Does the initial scan of managed and active domains to
+ populate self.domains.
- def list_sorted(self):
- """Get list of domain objects, sorted by name.
+ Note: L{XendDomainInfo._checkName} will call back into XendDomain
+ to make sure domain name is not a duplicate.
- @return: domain objects
"""
- doms = self.list()
- doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
- return doms
+ self.domains_lock.acquire()
+ try:
+ running = self._running_domains()
+ managed = self._managed_domains()
- def list_names(self):
- """Get list of domain names.
+ # add all active domains
+ for dom in running:
+ if dom['dying'] == 1:
+ log.warn('Ignoring dying domain %d from now on' %
+ dom['domid'])
+ continue
- @return: domain names
- """
- doms = self.list_sorted()
- return map(lambda x: x.getName(), doms)
+ if dom['domid'] != DOM0_ID:
+ try:
+ new_dom = XendDomainInfo.recreate(dom, False)
+ self._add_domain(new_dom)
+ except Exception:
+ log.exception("Failed to create reference to running "
+ "domain id: %d" % dom['domid'])
+
+ # add all managed domains as dormant domains.
+ for dom in managed:
+ dom_uuid = dom.get('uuid')
+ if not dom_uuid:
+ continue
+
+ dom_name = dom.get('name', 'Domain-%s' % dom_uuid)
+ try:
+ running_dom = self.domain_lookup_nr(dom_name)
+ if not running_dom:
+ # instantiate domain if not started.
+ new_dom = XendDomainInfo.createDormant(dom)
+ self._managed_domain_register(new_dom)
+ else:
+ self._managed_domain_register(running_dom)
+ except Exception:
+ log.exception("Failed to create reference to managed "
+ "domain: %s" % dom_name)
+ finally:
+ self.domains_lock.release()
- ## private:
- def onChangeDomain(self, _):
- self.domains_lock.acquire()
+ # -----------------------------------------------------------------
+ # Getting managed domains storage path names
+
+ def _managed_path(self, domuuid = None):
+ """Returns the path of the directory where managed domain
+ information is stored.
+
+ @keyword domuuid: If not None, will return the path to the domain
+ otherwise, will return the path containing
+ the directories which represent each domain.
+ @type: None or String.
+ @rtype: String
+ @return: Path.
+ """
+ dom_path = xroot.get_xend_domains_path()
+ if domuuid:
+ dom_path = os.path.join(dom_path, domuuid)
+ return dom_path
+
+ def _managed_config_path(self, domuuid):
+ """Returns the path to the configuration file of a managed domain.
+
+ @param domname: Domain uuid
+ @type domname: String
+ @rtype: String
+ @return: path to config file.
+ """
+ return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE)
+
+ def _managed_check_point_path(self, domuuid):
+ """Returns absolute path to check point file for managed domain.
+
+ @param domuuid: Name of managed domain
+ @type domname: String
+ @rtype: String
+ @return: Path
+ """
+ return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE)
+
+ def _managed_config_remove(self, domuuid):
+ """Removes a domain configuration from managed list
+
+ @param domuuid: Name of managed domain
+ @type domname: String
+ @raise XendError: fails to remove the domain.
+ """
+ config_path = self._managed_path(domuuid)
try:
- self.refresh()
- finally:
- self.domains_lock.release()
- return 1
+ if os.path.exists(config_path) and os.path.isdir(config_path):
+ shutil.rmtree(config_path)
+ except IOError:
+ log.exception('managed_config_remove failed removing conf')
+ raise XendError("Unable to remove managed configuration"
+ " for domain: %s" % domuuid)
+
+ def managed_config_save(self, dominfo):
+ """Save a domain's configuration to disk
+
+ @param domninfo: Managed domain to save.
+ @type dominfo: XendDomainInfo
+ @raise XendError: fails to save configuration.
+ @rtype: None
+ """
+ if not self.is_domain_managed(dominfo):
+ return # refuse to save configuration this domain isn't managed
+
+ if dominfo:
+ domains_dir = self._managed_path()
+ dom_uuid = dominfo.get_uuid()
+ domain_config_dir = self._managed_path(dom_uuid)
+
+ # make sure the domain dir exists
+ if not os.path.exists(domains_dir):
+ os.makedirs(domains_dir, 0755)
+ elif not os.path.isdir(domains_dir):
+ log.error("xend_domain_dir is not a directory.")
+ raise XendError("Unable to save managed configuration "
+ "because %s is not a directory." %
+ domains_dir)
+
+ if not os.path.exists(domain_config_dir):
+ try:
+ os.makedirs(domain_config_dir, 0755)
+ except IOError:
+ log.exception("Failed to create directory: %s" %
+ domain_config_dir)
+ raise XendError("Failed to create directory: %s" %
+ domain_config_dir)
+
+ try:
+ sxp_cache_file = open(self._managed_config_path(dom_uuid),'w')
+ prettyprint(dominfo.sxpr(), sxp_cache_file, width = 78)
+ sxp_cache_file.close()
+ except:
+ log.exception("Error occurred saving configuration file " +
+ "to %s" % domain_config_dir)
+ try:
+ self._managed_domain_remove(dom_uuid)
+ except:
+ pass
+ raise XendError("Failed to save configuration file to: %s" %
+ domain_config_dir)
+ else:
+ log.warn("Trying to save configuration for invalid domain")
+
+ def _managed_domains(self):
+ """ Returns list of domains that are managed.
+
+ Expects to be protected by domains_lock.
- def xen_domains(self):
- """Get table of domains indexed by id from xc. Expects to be
- protected by the domains_lock.
+ @rtype: list of XendConfig
+ @return: List of domain configurations that are managed.
"""
- domlist = xc.domain_getinfo()
- doms = {}
- for d in domlist:
- domid = d['dom']
- doms[domid] = d
+ dom_path = self._managed_path()
+ dom_uuids = os.listdir(dom_path)
+ doms = []
+ for dom_uuid in dom_uuids:
+ try:
+ cfg_file = self._managed_config_path(dom_uuid)
+ cfg = XendConfig(filename = cfg_file)
+ if cfg.get('uuid') != dom_uuid:
+ # something is wrong with the SXP
+ log.error("UUID mismatch in stored configuration: %s" %
+ cfg_file)
+ continue
+ doms.append(cfg)
+ except Exception:
+ log.exception('Unable to open or parse config.sxp: %s' % \
+ cfg_file)
return doms
+ def _managed_domain_unregister(self, dom):
+ try:
+ if self.is_domain_managed(dom):
+ self._managed_config_remove(dom.get_uuid())
+ del self.managed_domains[dom.get_uuid()]
+ except ValueError:
+ log.warn("Domain is not registered: %s" % dom.get_uuid())
+
+ def _managed_domain_register(self, dom):
+ self.managed_domains[dom.get_uuid()] = dom
- def dom0_setup(self):
- """Expects to be protected by the domains_lock."""
- dom0 = self.domains[PRIV_DOMAIN]
+ def is_domain_managed(self, dom = None):
+ return (dom.get_uuid() in self.managed_domains)
+
+ # End of Managed Domain Access
+ # --------------------------------------------------------------------
+
+ def _running_domains(self):
+ """Get table of domains indexed by id from xc.
+
+ @requires: Expects to be protected by domains_lock.
+ @rtype: list of dicts
+ @return: A list of dicts representing the running domains.
+ """
+ try:
+ return xc.domain_getinfo()
+ except RuntimeError, e:
+ log.exception("Unable to get domain information.")
+ return {}
+
+ def _setDom0CPUCount(self):
+ """Sets the number of VCPUs dom0 has. Retreived from the
+ Xend configuration, L{XendRoot}.
+
+ @requires: Expects to be protected by domains_lock.
+ @rtype: None
+ """
+ dom0 = self.privilegedDomain()
# get max number of vcpus to use for dom0 from config
target = int(xroot.get_dom0_vcpus())
@@ -157,245 +381,693 @@ class XendDomain:
dom0.setVCpuCount(target)
- def _add_domain(self, info):
- """Add the given domain entry to this instance's internal cache.
+ def _refresh(self):
+ """Refresh the domain list. Needs to be called when
+ either xenstore has changed or when a method requires
+ up to date information (like uptime, cputime stats).
+
Expects to be protected by the domains_lock.
+
+ @rtype: None
"""
- self.domains[info.getDomid()] = info
+ running = self._running_domains()
+ # Add domains that are not already tracked but running in Xen,
+ # and update domain state for those that are running and tracked.
+ for dom in running:
+ domid = dom['domid']
+ if domid in self.domains:
+ self.domains[domid].update(dom)
+ elif domid not in self.domains and dom['dying'] != 1:
+ try:
+ new_dom = XendDomainInfo.recreate(dom, False)
+ self._add_domain(new_dom)
+ except VmError:
+ log.exception("Unable to recreate domain")
+ try:
+ xc.domain_destroy(domid)
+ except:
+ log.exception("Hard destruction of domain failed: %d" %
+ domid)
- def _delete_domain(self, domid):
- """Remove the given domain from this instance's internal cache.
- Expects to be protected by the domains_lock.
- """
- info = self.domains.get(domid)
- if info:
- del self.domains[domid]
- info.cleanupDomain()
+ # update information for all running domains
+ # - like cpu_time, status, dying, etc.
+ # remove domains that are not running from active domain list.
+ # The list might have changed by now, because the update call may
+ # cause new domains to be added, if the domain has rebooted. We get
+ # the list again.
+ running = self._running_domains()
+ running_domids = [d['domid'] for d in running if d['dying'] != 1]
+ for domid, dom in self.domains.items():
+ if domid not in running_domids and domid != DOM0_ID:
+ self._remove_domain(dom, domid)
- def refresh(self, initialising = False):
- """Refresh domain list from Xen. Expects to be protected by the
- domains_lock.
- @param initialising True if this is the first refresh after starting
- Xend. This does not change this method's behaviour, except for
- logging.
+ def _add_domain(self, info):
+ """Add a domain to the list of running domains
+
+ @requires: Expects to be protected by the domains_lock.
+ @param info: XendDomainInfo of a domain to be added.
+ @type info: XendDomainInfo
"""
- doms = self.xen_domains()
- for d in self.domains.values():
- info = doms.get(d.getDomid())
- if info:
- d.update(info)
- else:
- self._delete_domain(d.getDomid())
- for d in doms:
- if d not in self.domains:
- if doms[d]['dying']:
- log.log(initialising and logging.ERROR or logging.DEBUG,
- 'Cannot recreate information for dying domain %d.'
- ' Xend will ignore this domain from now on.',
- doms[d]['dom'])
- elif d == PRIV_DOMAIN:
- log.fatal(
- "No record of privileged domain %d! Terminating.", d)
- sys.exit(1)
- else:
- try:
- self._add_domain(
- XendDomainInfo.recreate(doms[d], False))
- except:
- log.exception(
- "Failed to recreate information for domain "
- "%d. Destroying it in the hope of "
- "recovery.", d)
- try:
- xc.domain_destroy(d)
- except:
- log.exception('Destruction of %d failed.', d)
+ log.debug("Adding Domain: %s" % info.getDomid())
+ self.domains[info.getDomid()] = info
+ def _remove_domain(self, info, domid = None):
+ """Remove the domain from the list of running domains
+
+ @requires: Expects to be protected by the domains_lock.
+ @param info: XendDomainInfo of a domain to be removed.
+ @type info: XendDomainInfo
+ """
+ if info:
+ if domid == None:
+ domid = info.getDomid()
- ## public:
+ if info.state != DOM_STATE_HALTED:
+ info.cleanupDomain()
+
+ if domid in self.domains:
+ del self.domains[domid]
+ else:
+ log.warning("Attempted to remove non-existent domain.")
- def domain_create(self, config):
- """Create a domain from a configuration.
+ def restore_(self, config):
+ """Create a domain as part of the restore process. This is called
+ only from L{XendCheckpoint}.
- @param config: configuration
- @return: domain
+ A restore request comes into XendDomain through L{domain_restore}
+ or L{domain_restore_fd}. That request is
+ forwarded immediately to XendCheckpoint which, when it is ready, will
+ call this method. It is necessary to come through here rather than go
+ directly to L{XendDomainInfo.restore} because we need to
+ serialise the domain creation process, but cannot lock
+ domain_restore_fd as a whole, otherwise we will deadlock waiting for
+ the old domain to die.
+
+ @param config: Configuration of domain to restore
+ @type config: SXP Object (eg. list of lists)
"""
self.domains_lock.acquire()
try:
- dominfo = XendDomainInfo.create(config)
+ security.refresh_ssidref(config)
+ dominfo = XendDomainInfo.restore(config)
self._add_domain(dominfo)
return dominfo
finally:
self.domains_lock.release()
- def domain_configure(self, config):
- """Configure an existing domain.
-
- @param vmconfig: vm configuration
+ def domain_lookup(self, domid):
+ """Look up given I{domid} in the list of managed and running
+ domains.
+
+ @note: Will cause a refresh before lookup up domains, for
+ a version that does not need to re-read xenstore
+ use L{domain_lookup_nr}.
+
+ @param domid: Domain ID or Domain Name.
+ @type domid: int or string
+ @return: Found domain.
+ @rtype: XendDomainInfo
+ @raise XendError: If domain is not found.
"""
- # !!!
- raise XendError("Unsupported")
+ self.domains_lock.acquire()
+ try:
+ self._refresh()
+ dom = self.domain_lookup_nr(domid)
+ if not dom:
+ raise XendError("No domain named '%s'." % str(domid))
+ return dom
+ finally:
+ self.domains_lock.release()
- def domain_restore(self, src):
- """Restore a domain from file.
- @param src: source file
- """
+ def domain_lookup_nr(self, domid):
+ """Look up given I{domid} in the list of managed and running
+ domains.
+ @param domid: Domain ID or Domain Name.
+ @type domid: int or string
+ @return: Found domain.
+ @rtype: XendDomainInfo or None
+ """
+ self.domains_lock.acquire()
try:
- fd = os.open(src, os.O_RDONLY)
+ # lookup by name
+ match = [dom for dom in self.domains.values() \
+ if dom.getName() == domid]
+ if match:
+ return match[0]
+
+ match = [dom for dom in self.managed_domains.values() \
+ if dom.getName() == domid]
+ if match:
+ return match[0]
+
+ # lookup by id
try:
- return self.domain_restore_fd(fd)
- finally:
- os.close(fd)
- except OSError, ex:
- raise XendError("can't read guest state file %s: %s" %
- (src, ex[1]))
+ if int(domid) in self.domains:
+ return self.domains[int(domid)]
+ except ValueError:
+ pass
- def domain_restore_fd(self, fd):
- """Restore a domain from the given file descriptor."""
+ # lookup by uuid for running domains
+ match = [dom for dom in self.domains.values() \
+ if dom.get_uuid() == domid]
+ if match:
+ return match[0]
- try:
- return XendCheckpoint.restore(self, fd)
- except:
- # I don't really want to log this exception here, but the error
- # handling in the relocation-socket handling code (relocate.py) is
- # poor, so we need to log this for debugging.
- log.exception("Restore failed")
- raise XendError("Restore failed")
+ # lookup by uuid for inactive managed domains
+ if domid in self.managed_domains:
+ return self.managed_domains[domid]
+ return None
+ finally:
+ self.domains_lock.release()
- def restore_(self, config):
- """Create a domain as part of the restore process. This is called
- only from {@link XendCheckpoint}.
+ def privilegedDomain(self):
+ """ Get the XendDomainInfo of a dom0
- A restore request comes into XendDomain through {@link
- #domain_restore} or {@link #domain_restore_fd}. That request is
- forwarded immediately to XendCheckpoint which, when it is ready, will
- call this method. It is necessary to come through here rather than go
- directly to {@link XendDomainInfo.restore} because we need to
- serialise the domain creation process, but cannot lock
- domain_restore_fd as a whole, otherwise we will deadlock waiting for
- the old domain to die.
+ @rtype: XendDomainInfo
"""
self.domains_lock.acquire()
try:
- security.refresh_ssidref(config)
- dominfo = XendDomainInfo.restore(config)
- self._add_domain(dominfo)
- return dominfo
+ return self.domains[DOM0_ID]
finally:
self.domains_lock.release()
+ def cleanup_domains(self):
+ """Clean up domains that are marked as autostop.
+ Should be called when Xend goes down. This is currently
+ called from L{xen.xend.servers.XMLRPCServer}.
- def domain_lookup(self, domid):
+ """
+ log.debug('cleanup_domains')
self.domains_lock.acquire()
try:
- self.refresh()
- return self.domains.get(domid)
+ for dom in self.domains.values():
+ if dom.getName() == DOM0_NAME:
+ continue
+
+ if dom.state == DOM_STATE_RUNNING:
+ shutdownAction = dom.info.get('on_xend_stop', 'ignore')
+ if shutdownAction == 'shutdown':
+ log.debug('Shutting down domain: %s' % dom.getName())
+ dom.shutdown("poweroff")
+ elif shutdownAction == 'suspend':
+ self.domain_suspend(dom.getName())
finally:
self.domains_lock.release()
- def domain_lookup_nr(self, domid):
+
+ # ----------------------------------------------------------------
+ # Xen API
+
+
+ def set_allow_new_domains(self, allow_new_domains):
+ self._allow_new_domains = allow_new_domains
+
+ def allow_new_domains(self):
+ return self._allow_new_domains
+
+ def get_domain_refs(self):
+ result = []
+ try:
+ self.domains_lock.acquire()
+ result = [d.get_uuid() for d in self.domains.values()]
+ result += self.managed_domains.keys()
+ return result
+ finally:
+ self.domains_lock.release()
+
+ def get_vm_by_uuid(self, vm_uuid):
+ self.domains_lock.acquire()
+ try:
+ for dom in self.domains.values():
+ if dom.get_uuid() == vm_uuid:
+ return dom
+
+ if vm_uuid in self.managed_domains:
+ return self.managed_domains[vm_uuid]
+
+ return None
+ finally:
+ self.domains_lock.release()
+
+ def get_vm_with_dev_uuid(self, klass, dev_uuid):
self.domains_lock.acquire()
try:
- return self.domains.get(domid)
+ for dom in self.domains.values() + self.managed_domains.values():
+ if dom.has_device(klass, dev_uuid):
+ return dom
+ return None
finally:
self.domains_lock.release()
+ def get_dev_property_by_uuid(self, klass, dev_uuid, field):
+ self.domains_lock.acquire()
+ try:
+ dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
+ if not dom:
+ return None
+
+ value = dom.get_device_property(klass, dev_uuid, field)
+ return value
+ except ValueError, e:
+ pass
+
+ return None
+
+ def is_valid_vm(self, vm_ref):
+ return (self.get_vm_by_uuid(vm_ref) != None)
+
+ def is_valid_dev(self, klass, dev_uuid):
+ return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
- def domain_lookup_by_name_or_id(self, name):
+ def do_legacy_api_with_uuid(self, fn, vm_uuid, *args):
self.domains_lock.acquire()
try:
- self.refresh()
- return self.domain_lookup_by_name_or_id_nr(name)
+ for domid, dom in self.domains.items():
+ if dom.get_uuid == vm_uuid:
+ return fn(domid, *args)
+
+ if vm_uuid in self.managed_domains:
+ domid = self.managed_domains[vm_uuid].getDomid()
+ if domid == None:
+ domid = self.managed_domains[vm_uuid].getName()
+ return fn(domid, *args)
+
+ raise XendInvalidDomain("Domain does not exist")
finally:
self.domains_lock.release()
+
+ def create_domain(self, xenapi_vm):
+ self.domains_lock.acquire()
+ try:
+ try:
+ xeninfo = XendConfig(xenapi_vm = xenapi_vm)
+ dominfo = XendDomainInfo.createDormant(xeninfo)
+ log.debug("Creating new managed domain: %s: %s" %
+ (dominfo.getName(), dominfo.get_uuid()))
+ self._managed_domain_register(dominfo)
+ self.managed_config_save(dominfo)
+ return dominfo.get_uuid()
+ except XendError, e:
+ raise
+ except Exception, e:
+ raise XendError(str(e))
+ finally:
+ self.domains_lock.release()
- def domain_lookup_by_name_or_id_nr(self, name):
+ def rename_domain(self, dom, new_name):
self.domains_lock.acquire()
try:
- dominfo = self.domain_lookup_by_name_nr(name)
+ old_name = dom.getName()
+ dom.setName(new_name)
- if dominfo:
- return dominfo
+ finally:
+ self.domains_lock.release()
+
+
+ #
+ # End of Xen API
+ # ----------------------------------------------------------------
+
+ # ------------------------------------------------------------
+ # Xen Legacy API
+
+ def list(self, state = DOM_STATE_RUNNING):
+ """Get list of domain objects.
+
+ @param: the state in which the VMs should be -- one of the
+ DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
+ @return: domains
+ @rtype: list of XendDomainInfo
+ """
+ if type(state) == int:
+ state = POWER_STATE_NAMES[state]
+ state = state.lower()
+
+ self.domains_lock.acquire()
+ try:
+ self._refresh()
+
+ # active domains
+ active_domains = self.domains.values()
+ active_uuids = [d.get_uuid() for d in active_domains]
+
+ # inactive domains
+ inactive_domains = []
+ for dom_uuid, dom in self.managed_domains.items():
+ if dom_uuid not in active_uuids:
+ inactive_domains.append(dom)
+
+ if state == POWER_STATE_ALL:
+ return active_domains + inactive_domains
else:
+ return filter(lambda x:
+ POWER_STATE_NAMES[x.state].lower() == state,
+ active_domains + inactive_domains)
+ finally:
+ self.domains_lock.release()
+
+
+ def list_sorted(self, state = DOM_STATE_RUNNING):
+ """Get list of domain objects, sorted by name.
+
+ @param: the state in which the VMs should be -- one of the
+ DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
+ @return: domain objects
+ @rtype: list of XendDomainInfo
+ """
+ doms = self.list(state)
+ doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
+ return doms
+
+ def list_names(self, state = DOM_STATE_RUNNING):
+ """Get list of domain names.
+
+ @param: the state in which the VMs should be -- one of the
+ DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
+ @return: domain names
+ @rtype: list of strings.
+ """
+ return [d.getName() for d in self.list_sorted(state)]
+
+ def domain_suspend(self, domname):
+ """Suspends a domain that is persistently managed by Xend
+
+ @param domname: Domain Name
+ @type domname: string
+ @rtype: None
+ @raise XendError: Failure during checkpointing.
+ """
+
+ try:
+ dominfo = self.domain_lookup_nr(domname)
+ if not dominfo:
+ raise XendInvalidDomain(domname)
+
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot save privileged domain %s" % domname)
+
+ if dominfo.state != DOM_STATE_RUNNING:
+ raise XendError("Cannot suspend domain that is not running.")
+
+ dom_uuid = dominfo.get_uuid()
+
+ if not os.path.exists(self._managed_config_path(dom_uuid)):
+ raise XendError("Domain is not managed by Xend lifecycle " +
+ "support.")
+
+ path = self._managed_check_point_path(dom_uuid)
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
+ try:
+ # For now we don't support 'live checkpoint'
+ XendCheckpoint.save(fd, dominfo, False, False, path)
+ finally:
+ os.close(fd)
+ except OSError, ex:
+ raise XendError("can't write guest state file %s: %s" %
+ (path, ex[1]))
+
+ def domain_resume(self, domname):
+ """Resumes a domain that is persistently managed by Xend.
+
+ @param domname: Domain Name
+ @type domname: string
+ @rtype: None
+ @raise XendError: If failed to restore.
+ """
+ self.domains_lock.acquire()
+ try:
+ try:
+ dominfo = self.domain_lookup_nr(domname)
+
+ if not dominfo:
+ raise XendInvalidDomain(domname)
+
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot save privileged domain %s" % domname)
+
+ if dominfo.state != DOM_STATE_HALTED:
+ raise XendError("Cannot suspend domain that is not running.")
+
+ dom_uuid = dominfo.get_uuid()
+ chkpath = self._managed_check_point_path(dom_uuid)
+ if not os.path.exists(chkpath):
+ raise XendError("Domain was not suspended by Xend")
+
+ # Restore that replaces the existing XendDomainInfo
try:
- return self.domains.get(int(name))
- except ValueError:
- return None
+ log.debug('Current DomainInfo state: %d' % dominfo.state)
+ XendCheckpoint.restore(self,
+ os.open(chkpath, os.O_RDONLY),
+ dominfo)
+ self._add_domain(dominfo)
+ os.unlink(chkpath)
+ except OSError, ex:
+ raise XendError("Failed to read stored checkpoint file")
+ except IOError, ex:
+ raise XendError("Failed to delete checkpoint file")
+ except Exception, ex:
+ log.exception("Exception occurred when resuming")
+ raise XendError("Error occurred when resuming: %s" % str(ex))
finally:
self.domains_lock.release()
- def domain_lookup_by_name_nr(self, name):
+ def domain_create(self, config):
+ """Create a domain from a configuration.
+
+ @param config: configuration
+ @type config: SXP Object (list of lists)
+ @rtype: XendDomainInfo
+ """
self.domains_lock.acquire()
try:
- matching = filter(lambda d: d.getName() == name,
- self.domains.values())
- n = len(matching)
- if n == 1:
- return matching[0]
- return None
+ self._refresh()
+
+ dominfo = XendDomainInfo.create(config)
+ self._add_domain(dominfo)
+ self.domain_sched_credit_set(dominfo.getDomid(),
+ dominfo.getWeight(),
+ dominfo.getCap())
+ return dominfo
finally:
self.domains_lock.release()
- def privilegedDomain(self):
+ def domain_new(self, config):
+ """Create a domain from a configuration but do not start it.
+
+ @param config: configuration
+ @type config: SXP Object (list of lists)
+ @rtype: XendDomainInfo
+ """
self.domains_lock.acquire()
try:
- return self.domains[PRIV_DOMAIN]
+ try:
+ xeninfo = XendConfig(sxp = config)
+ dominfo = XendDomainInfo.createDormant(xeninfo)
+ log.debug("Creating new managed domain: %s" %
+ dominfo.getName())
+ self._managed_domain_register(dominfo)
+ self.managed_config_save(dominfo)
+ # no return value because it isn't meaningful for client
+ except XendError, e:
+ raise
+ except Exception, e:
+ raise XendError(str(e))
finally:
self.domains_lock.release()
-
- def domain_unpause(self, domid):
- """Unpause domain execution."""
+ def domain_start(self, domid):
+ """Start a managed domain
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
- if not dominfo:
- raise XendInvalidDomain(str(domid))
+ @require: Domain must not be running.
+ @param domid: Domain name or domain ID.
+ @type domid: string or int
+ @rtype: None
+ @raise XendError: If domain is still running
+ @rtype: None
+ """
+ self.domains_lock.acquire()
+ try:
+ self._refresh()
- if dominfo.getDomid() == PRIV_DOMAIN:
- raise XendError("Cannot unpause privileged domain %s" % domid)
+ dominfo = self.domain_lookup_nr(domid)
+ if not dominfo:
+ raise XendInvalidDomain(str(domid))
+ if dominfo.state != DOM_STATE_HALTED:
+ raise XendError("Domain is already running")
+
+ dominfo.start(is_managed = True)
+ self._add_domain(dominfo)
+ finally:
+ self.domains_lock.release()
+
+
+ def domain_delete(self, domid):
+ """Remove a managed domain from database
+
+ @require: Domain must not be running.
+ @param domid: Domain name or domain ID.
+ @type domid: string or int
+ @rtype: None
+ @raise XendError: If domain is still running
+ """
+ self.domains_lock.acquire()
+ try:
+ try:
+ dominfo = self.domain_lookup_nr(domid)
+ if not dominfo:
+ raise XendInvalidDomain(str(domid))
+
+ if dominfo.state != DOM_STATE_HALTED:
+ raise XendError("Domain is still running")
+
+ self._managed_domain_unregister(dominfo)
+ self._remove_domain(dominfo)
+ XendDevices.destroy_device_state(dominfo)
+ except Exception, ex:
+ raise XendError(str(ex))
+ finally:
+ self.domains_lock.release()
+
+
+ def domain_configure(self, config):
+ """Configure an existing domain.
+
+ @param vmconfig: vm configuration
+ @type vmconfig: SXP Object (list of lists)
+ @todo: Not implemented
+ """
+ # !!!
+ raise XendError("Unsupported")
+
+ def domain_restore(self, src, paused=False):
+ """Restore a domain from file.
+
+ @param src: filename of checkpoint file to restore from
+ @type src: string
+ @return: Restored domain
+ @rtype: XendDomainInfo
+ @raise XendError: Failure to restore domain
+ """
+ try:
+ fd = os.open(src, os.O_RDONLY)
+ try:
+ return self.domain_restore_fd(fd, paused=paused)
+ finally:
+ os.close(fd)
+ except OSError, ex:
+ raise XendError("can't read guest state file %s: %s" %
+ (src, ex[1]))
+
+ def domain_restore_fd(self, fd, paused=False):
+ """Restore a domain from the given file descriptor.
+
+ @param fd: file descriptor of the checkpoint file
+ @type fd: File object
+ @rtype: XendDomainInfo
+ @raise XendError: if failed to restore
+ """
+
+ try:
+ return XendCheckpoint.restore(self, fd, paused=paused)
+ except:
+ # I don't really want to log this exception here, but the error
+ # handling in the relocation-socket handling code (relocate.py) is
+ # poor, so we need to log this for debugging.
+ log.exception("Restore failed")
+ raise XendError("Restore failed")
+
+ def domain_unpause(self, domid):
+ """Unpause domain execution.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: None
+ @raise XendError: Failed to unpause
+ @raise XendInvalidDomain: Domain is not valid
+ """
try:
+ dominfo = self.domain_lookup_nr(domid)
+ if not dominfo:
+ raise XendInvalidDomain(str(domid))
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot unpause privileged domain %s" % domid)
log.info("Domain %s (%d) unpaused.", dominfo.getName(),
- dominfo.getDomid())
- return dominfo.unpause()
+ int(dominfo.getDomid()))
+ dominfo.unpause()
+ except XendInvalidDomain:
+ log.exception("domain_unpause")
+ raise
except Exception, ex:
+ log.exception("domain_unpause")
raise XendError(str(ex))
-
def domain_pause(self, domid):
- """Pause domain execution."""
+ """Pause domain execution.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: None
+ @raise XendError: Failed to pause
+ @raise XendInvalidDomain: Domain is not valid
+ """
+ try:
+ dominfo = self.domain_lookup_nr(domid)
+ if not dominfo:
+ raise XendInvalidDomain(str(domid))
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot pause privileged domain %s" % domid)
+ log.info("Domain %s (%d) paused.", dominfo.getName(),
+ int(dominfo.getDomid()))
+ dominfo.pause()
+ except XendInvalidDomain:
+ log.exception("domain_pause")
+ raise
+ except Exception, ex:
+ log.exception("domain_pause")
+ raise XendError(str(ex))
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ def domain_dump(self, domid, filename, live, crash):
+ """Dump domain core."""
+
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
- if dominfo.getDomid() == PRIV_DOMAIN:
- raise XendError("Cannot pause privileged domain %s" % domid)
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot dump core for privileged domain %s" % domid)
try:
- log.info("Domain %s (%d) paused.", dominfo.getName(),
- dominfo.getDomid())
- return dominfo.pause()
+ log.info("Domain core dump requested for domain %s (%d) "
+ "live=%d crash=%d.",
+ dominfo.getName(), dominfo.getDomid(), live, crash)
+ return dominfo.dumpCore(filename)
except Exception, ex:
raise XendError(str(ex))
-
def domain_destroy(self, domid):
- """Terminate domain immediately."""
+ """Terminate domain immediately.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: None
+ @raise XendError: Failed to destroy
+ @raise XendInvalidDomain: Domain is not valid
+ """
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
- if dominfo and dominfo.getDomid() == PRIV_DOMAIN:
+ dominfo = self.domain_lookup_nr(domid)
+ if dominfo and dominfo.getDomid() == DOM0_ID:
raise XendError("Cannot destroy privileged domain %s" % domid)
if dominfo:
@@ -403,18 +1075,35 @@ class XendDomain:
else:
try:
val = xc.domain_destroy(int(domid))
- except Exception, ex:
- raise XendInvalidDomain(str(domid))
+ except ValueError:
+ raise XendInvalidDomain(domid)
+ except Exception, e:
+ raise XendError(str(e))
+
return val
def domain_migrate(self, domid, dst, live=False, resource=0, port=0):
- """Start domain migration."""
+ """Start domain migration.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @param dst: Destination IP address
+ @type dst: string
+ @keyword port: relocation port on destination
+ @type port: int
+ @keyword live: Live migration
+ @type live: bool
+ @keyword resource: not used??
+ @rtype: None
+ @raise XendError: Failed to migrate
+ @raise XendInvalidDomain: Domain is not valid
+ """
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
- if dominfo.getDomid() == PRIV_DOMAIN:
+ if dominfo.getDomid() == DOM0_ID:
raise XendError("Cannot migrate privileged domain %s" % domid)
""" The following call may raise a XendError exception """
@@ -441,21 +1130,26 @@ class XendDomain:
def domain_save(self, domid, dst):
"""Start saving a domain to file.
- @param dst: destination file
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @param dst: Destination filename
+ @type dst: string
+ @rtype: None
+ @raise XendError: Failed to save domain
+ @raise XendInvalidDomain: Domain is not valid
"""
-
try:
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
- if dominfo.getDomid() == PRIV_DOMAIN:
- raise XendError("Cannot save privileged domain %s" % domid)
+ if dominfo.getDomid() == DOM0_ID:
+ raise XendError("Cannot save privileged domain %i" % domid)
fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
try:
# For now we don't support 'live checkpoint'
- return XendCheckpoint.save(fd, dominfo, False, False, dst)
+ XendCheckpoint.save(fd, dominfo, False, False, dst)
finally:
os.close(fd)
except OSError, ex:
@@ -465,22 +1159,41 @@ class XendDomain:
def domain_pincpu(self, domid, vcpu, cpumap):
"""Set which cpus vcpu can use
- @param cpumap: string repr of list of usable cpus
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @param vcpu: vcpu to pin to
+ @type vcpu: int
+ @param cpumap: string repr of usable cpus
+ @type cpumap: string
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
- try:
- return xc.vcpu_setaffinity(dominfo.getDomid(), vcpu, cpumap)
- except Exception, ex:
- raise XendError(str(ex))
+ # if vcpu is keyword 'all', apply the cpumap to all vcpus
+ vcpus = [ vcpu ]
+ if str(vcpu).lower() == "all":
+ vcpus = range(0, int(dominfo.getVCpuCount()))
+
+ # set the same cpumask for all vcpus
+ rc = 0
+ for v in vcpus:
+ try:
+ rc = xc.vcpu_setaffinity(dominfo.getDomid(), int(v), cpumap)
+ except Exception, ex:
+ raise XendError(str(ex))
+ return rc
def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
weight):
"""Set Simple EDF scheduler parameters for a domain.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
try:
@@ -491,15 +1204,20 @@ class XendDomain:
def domain_cpu_sedf_get(self, domid):
"""Get Simple EDF scheduler parameters for a domain.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: SXP object
+ @return: The parameters for Simple EDF schedule for a domain.
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
try:
sedf_info = xc.sedf_domain_get(dominfo.getDomid())
# return sxpr
return ['sedf',
- ['domain', sedf_info['domain']],
+ ['domid', sedf_info['domid']],
['period', sedf_info['period']],
['slice', sedf_info['slice']],
['latency', sedf_info['latency']],
@@ -510,7 +1228,14 @@ class XendDomain:
raise XendError(str(ex))
def domain_shadow_control(self, domid, op):
- """Shadow page control."""
+ """Shadow page control.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @param op: operation
+ @type op: int
+ @rtype: 0
+ """
dominfo = self.domain_lookup(domid)
try:
return xc.shadow_control(dominfo.getDomid(), op)
@@ -518,7 +1243,13 @@ class XendDomain:
raise XendError(str(ex))
def domain_shadow_mem_get(self, domid):
- """Get shadow pagetable memory allocation."""
+ """Get shadow pagetable memory allocation.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: int
+ @return: shadow memory in MB
+ """
dominfo = self.domain_lookup(domid)
try:
return xc.shadow_mem_control(dominfo.getDomid())
@@ -526,7 +1257,15 @@ class XendDomain:
raise XendError(str(ex))
def domain_shadow_mem_set(self, domid, mb):
- """Set shadow pagetable memory allocation."""
+ """Set shadow pagetable memory allocation.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @param mb: shadow memory to set in MB
+ @type: mb: int
+ @rtype: int
+ @return: shadow memory in MB
+ """
dominfo = self.domain_lookup(domid)
try:
return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
@@ -535,8 +1274,13 @@ class XendDomain:
def domain_sched_credit_get(self, domid):
"""Get credit scheduler parameters for a domain.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @rtype: dict with keys 'weight' and 'cap'
+ @return: credit scheduler parameters
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
try:
@@ -544,24 +1288,48 @@ class XendDomain:
except Exception, ex:
raise XendError(str(ex))
- def domain_sched_credit_set(self, domid, weight, cap):
+ def domain_sched_credit_set(self, domid, weight = None, cap = None):
"""Set credit scheduler parameters for a domain.
+
+ @param domid: Domain ID or Name
+ @type domid: int or string.
+ @type weight: int
+ @type cap: int
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
try:
+ if weight is None:
+ weight = int(0)
+ elif weight < 1 or weight > 65535:
+ raise XendError("weight is out of range")
+
+ if cap is None:
+ cap = int(~0)
+ elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
+ raise XendError("cap is out of range")
+
+ assert type(weight) == int
+ assert type(cap) == int
+
return xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
except Exception, ex:
+ log.exception(ex)
raise XendError(str(ex))
def domain_maxmem_set(self, domid, mem):
"""Set the memory limit for a domain.
+ @param domid: Domain ID or Name
+ @type domid: int or string.
@param mem: memory limit (in MiB)
- @return: 0 on success, -1 on error
+ @type mem: int
+ @raise XendError: fail to set memory
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
maxmem = int(mem) * 1024
@@ -575,9 +1343,10 @@ class XendDomain:
@param first: first IO port
@param last: last IO port
- @return: 0 on success, -1 on error
+ @raise XendError: failed to set range
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
nr_ports = last - first + 1
@@ -594,9 +1363,10 @@ class XendDomain:
@param first: first IO port
@param last: last IO port
- @return: 0 on success, -1 on error
+ @raise XendError: failed to set range
+ @rtype: 0
"""
- dominfo = self.domain_lookup_by_name_or_id_nr(domid)
+ dominfo = self.domain_lookup_nr(domid)
if not dominfo:
raise XendInvalidDomain(str(domid))
nr_ports = last - first + 1
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 6a7ad82f9a..958c5cf8f8 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -24,82 +24,33 @@ Author: Mike Wray <mike.wray@hp.com>
"""
-import errno
import logging
-import string
import time
import threading
+import re
+import copy
import os
+from types import StringTypes
import xen.lowlevel.xc
from xen.util import asserts
from xen.util.blkif import blkdev_uname_to_file
from xen.util import security
-import balloon
-import image
-import sxp
-import uuid
-import XendDomain
-import XendRoot
+
+from xen.xend import balloon, sxp, uuid, image, arch
+from xen.xend import XendRoot, XendNode
from xen.xend.XendBootloader import bootloader
+from xen.xend.XendConfig import XendConfig
from xen.xend.XendError import XendError, VmError
-
+from xen.xend.XendDevices import XendDevices
from xen.xend.xenstore.xstransact import xstransact, complete
from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
from xen.xend.xenstore.xswatch import xswatch
+from xen.xend.XendConstants import *
+from xen.xend.XendAPIConstants import *
-from xen.xend import arch
-
-"""Shutdown code for poweroff."""
-DOMAIN_POWEROFF = 0
-
-"""Shutdown code for reboot."""
-DOMAIN_REBOOT = 1
-
-"""Shutdown code for suspend."""
-DOMAIN_SUSPEND = 2
-
-"""Shutdown code for crash."""
-DOMAIN_CRASH = 3
-
-"""Shutdown code for halt."""
-DOMAIN_HALT = 4
-
-"""Map shutdown codes to strings."""
-shutdown_reasons = {
- DOMAIN_POWEROFF: "poweroff",
- DOMAIN_REBOOT : "reboot",
- DOMAIN_SUSPEND : "suspend",
- DOMAIN_CRASH : "crash",
- DOMAIN_HALT : "halt"
- }
-
-restart_modes = [
- "restart",
- "destroy",
- "preserve",
- "rename-restart"
- ]
-
-STATE_DOM_OK = 1
-STATE_DOM_SHUTDOWN = 2
-
-SHUTDOWN_TIMEOUT = 30.0
-
-ZOMBIE_PREFIX = 'Zombie-'
-
-"""Constants for the different stages of ext. device migration """
-DEV_MIGRATE_TEST = 0
-DEV_MIGRATE_STEP1 = 1
-DEV_MIGRATE_STEP2 = 2
-DEV_MIGRATE_STEP3 = 3
-
-"""Minimum time between domain restarts in seconds."""
-MINIMUM_RESTART_TIME = 20
-
-RESTART_IN_PROGRESS = 'xend/restart_in_progress'
-
+MIGRATE_TIMEOUT = 30.0
xc = xen.lowlevel.xc.xc()
xroot = XendRoot.instance()
@@ -107,7 +58,6 @@ xroot = XendRoot.instance()
log = logging.getLogger("xend.XendDomainInfo")
#log.setLevel(logging.TRACE)
-
##
# All parameters of VMs that may be configured on-the-fly, or at start-up.
#
@@ -130,7 +80,8 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [
('uuid', str),
('vcpus', int),
('vcpu_avail', int),
- ('cpu_weight', float),
+ ('cpu_cap', int),
+ ('cpu_weight', int),
('memory', int),
('shadow_memory', int),
('maxmem', int),
@@ -155,6 +106,8 @@ VM_STORE_ENTRIES = [
('shadow_memory', int),
('maxmem', int),
('start_time', float),
+ ('on_xend_start', str),
+ ('on_xend_stop', str),
]
VM_STORE_ENTRIES += VM_CONFIG_PARAMS
@@ -180,77 +133,102 @@ VM_STORE_ENTRIES += VM_CONFIG_PARAMS
def create(config):
- """Create a VM from a configuration.
+ """Creates and start a VM using the supplied configuration.
+ (called from XMLRPCServer directly)
- @param config configuration
- @raise: VmError for invalid configuration
+ @param config: A configuration object involving lists of tuples.
+ @type config: list of lists, eg ['vm', ['image', 'xen.gz']]
+
+ @rtype: XendDomainInfo
+ @return: A up and running XendDomainInfo instance
+ @raise VmError: Invalid configuration or failure to start.
"""
log.debug("XendDomainInfo.create(%s)", config)
-
- vm = XendDomainInfo(parseConfig(config))
+ vm = XendDomainInfo(XendConfig(sxp = config))
try:
- vm.construct()
- vm.initDomain()
- vm.storeVmDetails()
- vm.storeDomDetails()
- vm.registerWatches()
- vm.refreshShutdown()
- return vm
+ vm.start()
except:
log.exception('Domain construction failed')
vm.destroy()
raise
+ return vm
-def recreate(xeninfo, priv):
+def recreate(info, priv):
"""Create the VM object for an existing domain. The domain must not
be dying, as the paths in the store should already have been removed,
- and asking us to recreate them causes problems."""
+ and asking us to recreate them causes problems.
+
+ @param xeninfo: Parsed configuration
+ @type xeninfo: Dictionary
+ @param priv: TODO, unknown, something to do with memory
+ @type priv: bool
+
+ @rtype: XendDomainInfo
+ @return: A up and running XendDomainInfo instance
+ @raise VmError: Invalid configuration.
+ @raise XendError: Errors with configuration.
+ """
- log.debug("XendDomainInfo.recreate(%s)", xeninfo)
+ log.debug("XendDomainInfo.recreate(%s)", info)
- assert not xeninfo['dying']
+ assert not info['dying']
- domid = xeninfo['dom']
+ xeninfo = XendConfig(cfg = info)
+ domid = xeninfo['domid']
uuid1 = xeninfo['handle']
xeninfo['uuid'] = uuid.toString(uuid1)
+ needs_reinitialising = False
+
dompath = GetDomainPath(domid)
if not dompath:
- raise XendError(
- 'No domain path in store for existing domain %d' % domid)
-
- log.info("Recreating domain %d, UUID %s.", domid, xeninfo['uuid'])
+ raise XendError('No domain path in store for existing '
+ 'domain %d' % domid)
+
+ log.info("Recreating domain %d, UUID %s. at %s" %
+ (domid, xeninfo['uuid'], dompath))
+
+ # need to verify the path and uuid if not Domain-0
+ # if the required uuid and vm aren't set, then that means
+ # we need to recreate the dom with our own values
+ #
+ # NOTE: this is probably not desirable, really we should just
+ # abort or ignore, but there may be cases where xenstore's
+ # entry disappears (eg. xenstore-rm /)
+ #
try:
vmpath = xstransact.Read(dompath, "vm")
if not vmpath:
- raise XendError(
- 'No vm path in store for existing domain %d' % domid)
+ log.warn('/local/domain/%d/vm is missing. recreate is '
+ 'confused, trying our best to recover' % domid)
+ needs_reinitialising = True
+ raise XendError('reinit')
+
uuid2_str = xstransact.Read(vmpath, "uuid")
if not uuid2_str:
- raise XendError(
- 'No vm/uuid path in store for existing domain %d' % domid)
-
+ log.warn('%s/uuid/ is missing. recreate is confused, '
+ 'trying our best to recover' % vmpath)
+ needs_reinitialising = True
+ raise XendError('reinit')
+
uuid2 = uuid.fromString(uuid2_str)
-
if uuid1 != uuid2:
- raise XendError(
- 'Uuid in store does not match uuid for existing domain %d: '
- '%s != %s' % (domid, uuid2_str, xeninfo['uuid']))
-
- vm = XendDomainInfo(xeninfo, domid, dompath, True, priv)
-
- except Exception, exn:
- if priv:
- log.warn(str(exn))
-
- vm = XendDomainInfo(xeninfo, domid, dompath, True, priv)
- vm.recreateDom()
- vm.removeVm()
- vm.storeVmDetails()
- vm.storeDomDetails()
-
- vm.registerWatches()
+ log.warn('UUID in /vm does not match the UUID in /dom/%d.'
+ 'Trying out best to recover' % domid)
+ needs_reinitialising = True
+ except XendError:
+ pass # our best shot at 'goto' in python :)
+
+ vm = XendDomainInfo(xeninfo, domid, dompath, augment = True, priv = priv)
+
+ if needs_reinitialising:
+ vm._recreateDom()
+ vm._removeVm()
+ vm._storeVmDetails()
+ vm._storeDomDetails()
+
+ vm._registerWatches()
vm.refreshShutdown(xeninfo)
return vm
@@ -258,144 +236,52 @@ def recreate(xeninfo, priv):
def restore(config):
"""Create a domain and a VM object to do a restore.
- @param config: domain configuration
+ @param config: Domain configuration object
+ @type config: list of lists. (see C{create})
+
+ @rtype: XendDomainInfo
+ @return: A up and running XendDomainInfo instance
+ @raise VmError: Invalid configuration or failure to start.
+ @raise XendError: Errors with configuration.
"""
log.debug("XendDomainInfo.restore(%s)", config)
-
- vm = XendDomainInfo(parseConfig(config), None, None, False, False, True)
+ vm = XendDomainInfo(XendConfig(sxp = config), resume = True)
try:
- vm.construct()
- vm.storeVmDetails()
- vm.createDevices()
- vm.createChannels()
- vm.storeDomDetails()
- vm.endRestore()
+ vm.resume()
return vm
except:
vm.destroy()
raise
-
-def parseConfig(config):
- def get_cfg(name, conv = None):
- val = sxp.child_value(config, name)
-
- if conv and not val is None:
- try:
- return conv(val)
- except TypeError, exn:
- raise VmError(
- 'Invalid setting %s = %s in configuration: %s' %
- (name, val, str(exn)))
- else:
- return val
-
-
- log.debug("parseConfig: config is %s", config)
-
- result = {}
-
- for e in ROUNDTRIPPING_CONFIG_ENTRIES:
- result[e[0]] = get_cfg(e[0], e[1])
-
- result['cpu'] = get_cfg('cpu', int)
- result['cpus'] = get_cfg('cpus', str)
- result['image'] = get_cfg('image')
- tmp_security = get_cfg('security')
- if tmp_security:
- result['security'] = tmp_security
-
- try:
- if result['image']:
- v = sxp.child_value(result['image'], 'vcpus')
- if result['vcpus'] is None and v is not None:
- result['vcpus'] = int(v)
- elif v is not None and int(v) != result['vcpus']:
- log.warn(('Image VCPUs setting overrides vcpus=%d elsewhere.'
- ' Using %s VCPUs for VM %s.') %
- (result['vcpus'], v, result['uuid']))
- result['vcpus'] = int(v)
- except TypeError, exn:
- raise VmError(
- 'Invalid configuration setting: vcpus = %s: %s' %
- (sxp.child_value(result['image'], 'vcpus', 1), str(exn)))
-
- try:
- # support legacy config files with 'cpu' parameter
- # NB: prepending to list to support previous behavior
- # where 'cpu' parameter pinned VCPU0.
- if result['cpu']:
- if result['cpus']:
- result['cpus'] = "%s,%s" % (str(result['cpu']), result['cpus'])
- else:
- result['cpus'] = str(result['cpu'])
-
- # convert 'cpus' string to list of ints
- # 'cpus' supports a list of ranges (0-3), seperated by
- # commas, and negation, (^1).
- # Precedence is settled by order of the string:
- # "0-3,^1" -> [0,2,3]
- # "0-3,^1,1" -> [0,1,2,3]
- if result['cpus']:
- cpus = []
- for c in result['cpus'].split(','):
- if c.find('-') != -1:
- (x,y) = c.split('-')
- for i in range(int(x),int(y)+1):
- cpus.append(int(i))
- else:
- # remove this element from the list
- if c[0] == '^':
- cpus = [x for x in cpus if x != int(c[1:])]
- else:
- cpus.append(int(c))
-
- result['cpus'] = cpus
-
- except ValueError, exn:
- raise VmError(
- 'Invalid configuration setting: cpus = %s: %s' %
- (result['cpus'], exn))
-
- result['backend'] = []
- for c in sxp.children(config, 'backend'):
- result['backend'].append(sxp.name(sxp.child0(c)))
-
- result['device'] = []
- for d in sxp.children(config, 'device'):
- c = sxp.child0(d)
- result['device'].append((sxp.name(c), c))
-
- # Configuration option "restart" is deprecated. Parse it, but
- # let on_xyz override it if they are present.
- restart = get_cfg('restart')
- if restart:
- def handle_restart(event, val):
- if result[event] is None:
- result[event] = val
-
- if restart == "onreboot":
- handle_restart('on_poweroff', 'destroy')
- handle_restart('on_reboot', 'restart')
- handle_restart('on_crash', 'destroy')
- elif restart == "always":
- handle_restart('on_poweroff', 'restart')
- handle_restart('on_reboot', 'restart')
- handle_restart('on_crash', 'restart')
- elif restart == "never":
- handle_restart('on_poweroff', 'destroy')
- handle_restart('on_reboot', 'destroy')
- handle_restart('on_crash', 'destroy')
- else:
- log.warn("Ignoring malformed and deprecated config option "
- "restart = %s", restart)
-
- log.debug("parseConfig: result is %s", result)
- return result
-
+def createDormant(xeninfo):
+ """Create a dormant/inactive XenDomainInfo without creating VM.
+ This is for creating instances of persistent domains that are not
+ yet start.
+
+ @param xeninfo: Parsed configuration
+ @type xeninfo: dictionary
+
+ @rtype: XendDomainInfo
+ @return: A up and running XendDomainInfo instance
+ @raise XendError: Errors with configuration.
+ """
+
+ log.debug("XendDomainInfo.createDormant(%s)", xeninfo)
+
+ # domid does not make sense for non-running domains.
+ xeninfo.pop('domid', None)
+ vm = XendDomainInfo(XendConfig(cfg = xeninfo))
+ return vm
def domain_by_name(name):
+ """Get domain by name
+
+ @params name: Name of the domain
+ @type name: string
+ @return: XendDomainInfo or None
+ """
+ from xen.xend import XendDomain
return XendDomain.instance().domain_lookup_by_name_nr(name)
@@ -407,17 +293,19 @@ def shutdown_reason(code):
@return: shutdown reason
@rtype: string
"""
- return shutdown_reasons.get(code, "?")
+ return DOMAIN_SHUTDOWN_REASONS.get(code, "?")
def dom_get(dom):
"""Get info from xen for an existing domain.
@param dom: domain id
+ @type dom: int
@return: info or None
+ @rtype: dictionary
"""
try:
domlist = xc.domain_getinfo(dom, 1)
- if domlist and dom == domlist[0]['dom']:
+ if domlist and dom == domlist[0]['domid']:
return domlist[0]
except Exception, err:
# ignore missing domain
@@ -426,32 +314,87 @@ def dom_get(dom):
class XendDomainInfo:
-
+ """An object represents a domain.
+
+ @TODO: try to unify dom and domid, they mean the same thing, but
+ xc refers to it as dom, and everywhere else, including
+ xenstore it is domid. The best way is to change xc's
+ python interface.
+
+ @ivar info: Parsed configuration
+ @type info: dictionary
+ @ivar domid: Domain ID (if VM has started)
+ @type domid: int or None
+ @ivar vmpath: XenStore path to this VM.
+ @type vmpath: string
+ @ivar dompath: XenStore path to this Domain.
+ @type dompath: string
+ @ivar image: Reference to the VM Image.
+ @type image: xen.xend.image.ImageHandler
+ @ivar store_port: event channel to xenstored
+ @type store_port: int
+ @ivar console_port: event channel to xenconsoled
+ @type console_port: int
+ @ivar store_mfn: xenstored mfn
+ @type store_mfn: int
+ @ivar console_mfn: xenconsoled mfn
+ @type console_mfn: int
+ @ivar vmWatch: reference to a watch on the xenstored vmpath
+ @type vmWatch: xen.xend.xenstore.xswatch
+ @ivar shutdownWatch: reference to watch on the xenstored domain shutdown
+ @type shutdownWatch: xen.xend.xenstore.xswatch
+ @ivar shutdownStartTime: UNIX Time when domain started shutting down.
+ @type shutdownStartTime: float or None
+ @ivar state: Domain state
+ @type state: enum(DOM_STATE_HALTED, DOM_STATE_RUNNING, ...)
+ @ivar state_updated: lock for self.state
+ @type state_updated: threading.Condition
+ @ivar refresh_shutdown_lock: lock for polling shutdown state
+ @type refresh_shutdown_lock: threading.Condition
+ @ivar _deviceControllers: device controller cache for this domain
+ @type _deviceControllers: dict 'string' to DevControllers
+ """
+
def __init__(self, info, domid = None, dompath = None, augment = False,
priv = False, resume = False):
+ """Constructor for a domain
+
+ @param info: parsed configuration
+ @type info: dictionary
+ @keyword domid: Set initial domain id (if any)
+ @type domid: int
+ @keyword dompath: Set initial dompath (if any)
+ @type dompath: string
+ @keyword augment: Augment given info with xenstored VM info
+ @type augment: bool
+ @keyword priv: Is a privledged domain (Dom 0) (TODO: really?)
+ @type priv: bool
+ @keyword resume: Is this domain being resumed?
+ @type resume: bool
+ """
self.info = info
-
- if not self.infoIsSet('uuid'):
- self.info['uuid'] = uuid.toString(uuid.create())
-
- if domid is not None:
- self.domid = domid
- elif 'dom' in info:
- self.domid = int(info['dom'])
+ if domid == None:
+ self.domid = self.info.get('domid')
else:
- self.domid = None
-
- self.vmpath = XendDomain.VMROOT + self.info['uuid']
+ self.domid = domid
+
+ #REMOVE: uuid is now generated in XendConfig
+ #if not self._infoIsSet('uuid'):
+ # self.info['uuid'] = uuid.toString(uuid.create())
+
+ #REMOVE: domid logic can be shortened
+ #if domid is not None:
+ # self.domid = domid
+ #elif info.has_key('dom'):
+ # self.domid = int(info['dom'])
+ #else:
+ # self.domid = None
+
+ self.vmpath = XS_VMROOT + self.info['uuid']
self.dompath = dompath
- if augment:
- self.augmentInfo(priv)
-
- self.validateInfo()
-
self.image = None
- self.security = None
self.store_port = None
self.store_mfn = None
self.console_port = None
@@ -459,269 +402,287 @@ class XendDomainInfo:
self.vmWatch = None
self.shutdownWatch = None
-
self.shutdownStartTime = None
-
- self.state = STATE_DOM_OK
+
+ self.state = DOM_STATE_HALTED
self.state_updated = threading.Condition()
self.refresh_shutdown_lock = threading.Condition()
+ self._deviceControllers = {}
+
+ for state in DOM_STATES_OLD:
+ self.info[state] = 0
+
+ if augment:
+ self._augmentInfo(priv)
+
+ self._checkName(self.info['name'])
self.setResume(resume)
+
- ## private:
+ #
+ # Public functions available through XMLRPC
+ #
- def readVMDetails(self, params):
- """Read the specified parameters from the store.
+
+ def start(self, is_managed = False):
+ """Attempts to start the VM by do the appropriate
+ initialisation if it not started.
"""
- try:
- return self.gatherVm(*params)
- except ValueError:
- # One of the int/float entries in params has a corresponding store
- # entry that is invalid. We recover, because older versions of
- # Xend may have put the entry there (memory/target, for example),
- # but this is in general a bad situation to have reached.
- log.exception(
- "Store corrupted at %s! Domain %d's configuration may be "
- "affected.", self.vmpath, self.domid)
- return []
+ from xen.xend import XendDomain
+ if self.state == DOM_STATE_HALTED:
+ try:
+ self._constructDomain()
+ self._initDomain()
+ self._storeVmDetails()
+ self._storeDomDetails()
+ self._registerWatches()
+ self.refreshShutdown()
+ self.unpause()
+
+ # save running configuration if XendDomains believe domain is
+ # persistent
+ if is_managed:
+ xendomains = XendDomain.instance()
+ xendomains.managed_config_save(self)
+ except:
+ log.exception('VM start failed')
+ self.destroy()
+ raise
+ else:
+ raise XendError('VM already running')
- def storeChanged(self, _):
- log.trace("XendDomainInfo.storeChanged");
+ def resume(self):
+ """Resumes a domain that has come back from suspension."""
+ if self.state in (DOM_STATE_HALTED, DOM_STATE_SUSPENDED):
+ try:
+ self._constructDomain()
+ self._storeVmDetails()
+ self._createDevices()
+ self._createChannels()
+ self._storeDomDetails()
+ self._endRestore()
+ except:
+ log.exception('VM resume failed')
+ raise
+ else:
+ raise XendError('VM already running')
- changed = False
+ def shutdown(self, reason):
+ """Shutdown a domain by signalling this via xenstored."""
+ log.debug('XendDomainInfo.shutdown')
+ if self.state in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
+ raise XendError('Domain cannot be shutdown')
+
+ if self.domid == 0:
+ raise XendError('Domain 0 cannot be shutdown')
- def f(x, y):
- if y is not None and self.info[x[0]] != y:
- self.info[x[0]] = y
- changed = True
+ if not reason in DOMAIN_SHUTDOWN_REASONS.values():
+ raise XendError('Invalid reason: %s' % reason)
+ self._storeDom("control/shutdown", reason)
+
+ def pause(self):
+ """Pause domain
+
+ @raise XendError: Failed pausing a domain
+ """
+ try:
+ xc.domain_pause(self.domid)
+ self._stateSet(DOM_STATE_PAUSED)
+ except Exception, ex:
+ raise XendError("Domain unable to be paused: %s" % str(ex))
- map(f, VM_CONFIG_PARAMS, self.readVMDetails(VM_CONFIG_PARAMS))
+ def unpause(self):
+ """Unpause domain
+
+ @raise XendError: Failed unpausing a domain
+ """
+ try:
+ xc.domain_unpause(self.domid)
+ self._stateSet(DOM_STATE_RUNNING)
+ except Exception, ex:
+ raise XendError("Domain unable to be unpaused: %s" % str(ex))
- im = self.readVm('image')
- current_im = self.info['image']
- if (im is not None and
- (current_im is None or sxp.to_string(current_im) != im)):
- self.info['image'] = sxp.from_string(im)
- changed = True
+ def send_sysrq(self, key):
+ """ Send a Sysrq equivalent key via xenstored."""
+ asserts.isCharConvertible(key)
+ self._storeDom("control/sysrq", '%c' % key)
- if changed:
- # Update the domain section of the store, as this contains some
- # parameters derived from the VM configuration.
- self.storeDomDetails()
+ def device_create(self, dev_config):
+ """Create a new device.
- return 1
+ @param dev_config: device configuration
+ @type dev_config: dictionary (parsed config)
+ """
+ log.debug("XendDomainInfo.device_create: %s" % dev_config)
+ dev_type = sxp.name(dev_config)
+ devid = self._createDevice(dev_type, dev_config)
+ self.info.device_add(dev_type, cfg_sxp = dev_config)
+ self._waitForDevice(dev_type, devid)
+ return self.getDeviceController(dev_type).sxpr(devid)
+
+ def device_configure(self, dev_config, devid = None):
+ """Configure an existing device.
+
+ @param dev_config: device configuration
+ @type dev_config: dictionary (parsed config)
+ @param devid: device id
+ @type devid: int
+ """
+ deviceClass = sxp.name(dev_config)
+ self._reconfigureDevice(deviceClass, devid, dev_config)
+ def waitForDevices(self):
+ """Wait for this domain's configured devices to connect.
- def augmentInfo(self, priv):
- """Augment self.info, as given to us through {@link #recreate}, with
- values taken from the store. This recovers those values known to xend
- but not to the hypervisor.
+ @raise VmError: if any device fails to initialise.
"""
- def useIfNeeded(name, val):
- if not self.infoIsSet(name) and val is not None:
- self.info[name] = val
+ for devclass in XendDevices.valid_devices():
+ self.getDeviceController(devclass).waitForDevices()
- if priv:
- entries = VM_STORE_ENTRIES[:]
- entries.remove(('memory', int))
- entries.remove(('maxmem', int))
- else:
- entries = VM_STORE_ENTRIES
- entries.append(('image', str))
- entries.append(('security', str))
+ def destroyDevice(self, deviceClass, devid):
+ try:
+ devid = int(devid)
+ except ValueError:
+ # devid is not a number, let's search for it in xenstore.
+ devicePath = '%s/device/%s' % (self.dompath, deviceClass)
+ for entry in xstransact.List(devicePath):
+ backend = xstransact.Read('%s/%s' % (devicePath, entry),
+ "backend")
+ devName = xstransact.Read(backend, "dev")
+ if devName == devid:
+ # We found the integer matching our devid, use it instead
+ devid = entry
+ break
+
+ return self.getDeviceController(deviceClass).destroyDevice(devid)
- map(lambda x, y: useIfNeeded(x[0], y), entries,
- self.readVMDetails(entries))
- device = []
- for c in controllerClasses:
- devconfig = self.getDeviceConfigurations(c)
- if devconfig:
- device.extend(map(lambda x: (c, x), devconfig))
- useIfNeeded('device', device)
+ def getDeviceSxprs(self, deviceClass):
+ return self.getDeviceController(deviceClass).sxprs()
- def validateInfo(self):
- """Validate and normalise the info block. This has either been parsed
- by parseConfig, or received from xc through recreate and augmented by
- the current store contents.
+ def setMemoryTarget(self, target):
+ """Set the memory target of this domain.
+ @param target: In MiB.
"""
- def defaultInfo(name, val):
- if not self.infoIsSet(name):
- self.info[name] = val()
+ log.debug("Setting memory target of domain %s (%d) to %d MiB.",
+ self.info['name'], self.domid, target)
+
+ if target <= 0:
+ raise XendError('Invalid memory size')
+
+ self.info['memory'] = target
+ self.storeVm("memory", target)
+ self._storeDom("memory/target", target << 10)
+ def getVCPUInfo(self):
try:
- defaultInfo('name', lambda: "Domain-%d" % self.domid)
- defaultInfo('on_poweroff', lambda: "destroy")
- defaultInfo('on_reboot', lambda: "restart")
- defaultInfo('on_crash', lambda: "restart")
- defaultInfo('features', lambda: "")
- defaultInfo('cpu', lambda: None)
- defaultInfo('cpus', lambda: [])
- defaultInfo('cpu_weight', lambda: 1.0)
-
- # some domains don't have a config file (e.g. dom0 )
- # to set number of vcpus so we derive available cpus
- # from max_vcpu_id which is present for running domains.
- if not self.infoIsSet('vcpus') and self.infoIsSet('max_vcpu_id'):
- avail = int(self.info['max_vcpu_id'])+1
- else:
- avail = int(1)
+ # We include the domain name and ID, to help xm.
+ sxpr = ['domain',
+ ['domid', self.domid],
+ ['name', self.info['name']],
+ ['vcpu_count', self.info['online_vcpus']]]
- defaultInfo('vcpus', lambda: avail)
- defaultInfo('online_vcpus', lambda: self.info['vcpus'])
- defaultInfo('max_vcpu_id', lambda: self.info['vcpus']-1)
- defaultInfo('vcpu_avail', lambda: (1 << self.info['vcpus']) - 1)
+ for i in range(0, self.info['max_vcpu_id']+1):
+ info = xc.vcpu_getinfo(self.domid, i)
+
+ sxpr.append(['vcpu',
+ ['number', i],
+ ['online', info['online']],
+ ['blocked', info['blocked']],
+ ['running', info['running']],
+ ['cpu_time', info['cpu_time'] / 1e9],
+ ['cpu', info['cpu']],
+ ['cpumap', info['cpumap']]])
- defaultInfo('memory', lambda: 0)
- defaultInfo('shadow_memory', lambda: 0)
- defaultInfo('maxmem', lambda: 0)
- defaultInfo('bootloader', lambda: None)
- defaultInfo('bootloader_args', lambda: None)
- defaultInfo('backend', lambda: [])
- defaultInfo('device', lambda: [])
- defaultInfo('image', lambda: None)
- defaultInfo('security', lambda: None)
+ return sxpr
- self.check_name(self.info['name'])
+ except RuntimeError, exn:
+ raise XendError(str(exn))
- if isinstance(self.info['image'], str):
- self.info['image'] = sxp.from_string(self.info['image'])
+ #
+ # internal functions ... TODO: re-categorised
+ #
- if isinstance(self.info['security'], str):
- self.info['security'] = sxp.from_string(self.info['security'])
+ def _augmentInfo(self, priv):
+ """Augment self.info, as given to us through L{recreate}, with
+ values taken from the store. This recovers those values known
+ to xend but not to the hypervisor.
+ """
+ def useIfNeeded(name, val):
+ if not self._infoIsSet(name) and val is not None:
+ self.info[name] = val
- if self.info['memory'] == 0:
- if self.infoIsSet('mem_kb'):
- self.info['memory'] = (self.info['mem_kb'] + 1023) / 1024
+ if priv:
+ entries = VM_STORE_ENTRIES[:]
+ entries.remove(('memory', int))
+ entries.remove(('maxmem', int))
+ else:
+ entries = VM_STORE_ENTRIES
+ entries.append(('image', str))
+ entries.append(('security', str))
- if self.info['maxmem'] < self.info['memory']:
- self.info['maxmem'] = self.info['memory']
+ map(lambda x, y: useIfNeeded(x[0], y), entries,
+ self._readVMDetails(entries))
- for (n, c) in self.info['device']:
- if not n or not c or n not in controllerClasses:
- raise VmError('invalid device (%s, %s)' %
- (str(n), str(c)))
+ devices = []
- for event in ['on_poweroff', 'on_reboot', 'on_crash']:
- if self.info[event] not in restart_modes:
- raise VmError('invalid restart event: %s = %s' %
- (event, str(self.info[event])))
+ for devclass in XendDevices.valid_devices():
+ devconfig = self.getDeviceController(devclass).configurations()
+ if devconfig:
+ devices.extend(map(lambda conf: (devclass, conf), devconfig))
- except KeyError, exn:
- log.exception(exn)
- raise VmError('Unspecified domain detail: %s' % exn)
+ if not self.info['device'] and devices is not None:
+ for device in devices:
+ self.info.device_add(device[0], cfg_sxp = device)
+ #
+ # Function to update xenstore /vm/*
+ #
- def readVm(self, *args):
+ def _readVm(self, *args):
return xstransact.Read(self.vmpath, *args)
- def writeVm(self, *args):
+ def _writeVm(self, *args):
return xstransact.Write(self.vmpath, *args)
- def removeVm(self, *args):
+ def _removeVm(self, *args):
return xstransact.Remove(self.vmpath, *args)
- def gatherVm(self, *args):
+ def _gatherVm(self, *args):
return xstransact.Gather(self.vmpath, *args)
-
- ## public:
-
def storeVm(self, *args):
return xstransact.Store(self.vmpath, *args)
+ #
+ # Function to update xenstore /dom/*
+ #
- ## private:
-
- def readDom(self, *args):
+ def _readDom(self, *args):
return xstransact.Read(self.dompath, *args)
- def writeDom(self, *args):
+ def _writeDom(self, *args):
return xstransact.Write(self.dompath, *args)
-
- ## public:
-
- def removeDom(self, *args):
+ def _removeDom(self, *args):
return xstransact.Remove(self.dompath, *args)
- def recreateDom(self):
- complete(self.dompath, lambda t: self._recreateDom(t))
+ def _storeDom(self, *args):
+ return xstransact.Store(self.dompath, *args)
+
+ def _recreateDom(self):
+ complete(self.dompath, lambda t: self._recreateDomFunc(t))
- def _recreateDom(self, t):
+ def _recreateDomFunc(self, t):
t.remove()
t.mkdir()
t.set_permissions({ 'dom' : self.domid })
+ t.write('vm', self.vmpath)
-
- ## private:
-
- def storeDom(self, *args):
- return xstransact.Store(self.dompath, *args)
-
-
- ## public:
-
- def completeRestore(self, store_mfn, console_mfn):
-
- log.debug("XendDomainInfo.completeRestore")
-
- self.store_mfn = store_mfn
- self.console_mfn = console_mfn
-
- self.introduceDomain()
- self.storeDomDetails()
- self.registerWatches()
- self.refreshShutdown()
-
- log.debug("XendDomainInfo.completeRestore done")
-
-
- def storeVmDetails(self):
- to_store = {}
-
- for k in VM_STORE_ENTRIES:
- if self.infoIsSet(k[0]):
- to_store[k[0]] = str(self.info[k[0]])
-
- if self.infoIsSet('image'):
- to_store['image'] = sxp.to_string(self.info['image'])
-
- if self.infoIsSet('security'):
- security = self.info['security']
- to_store['security'] = sxp.to_string(security)
- for idx in range(0, len(security)):
- if security[idx][0] == 'access_control':
- to_store['security/access_control'] = sxp.to_string([ security[idx][1] , security[idx][2] ])
- for aidx in range(1, len(security[idx])):
- if security[idx][aidx][0] == 'label':
- to_store['security/access_control/label'] = security[idx][aidx][1]
- if security[idx][aidx][0] == 'policy':
- to_store['security/access_control/policy'] = security[idx][aidx][1]
- if security[idx][0] == 'ssidref':
- to_store['security/ssidref'] = str(security[idx][1])
-
- if not self.readVm('xend/restart_count'):
- to_store['xend/restart_count'] = str(0)
-
- log.debug("Storing VM details: %s", to_store)
-
- self.writeVm(to_store)
- self.setVmPermissions()
-
-
- def setVmPermissions(self):
- """Allow the guest domain to read its UUID. We don't allow it to
- access any other entry, for security."""
- xstransact.SetPermissions('%s/uuid' % self.vmpath,
- { 'dom' : self.domid,
- 'read' : True,
- 'write' : False })
-
-
- def storeDomDetails(self):
+ def _storeDomDetails(self):
to_store = {
'domid': str(self.domid),
'vm': self.vmpath,
@@ -739,16 +700,13 @@ class XendDomainInfo:
f('store/port', self.store_port)
f('store/ring-ref', self.store_mfn)
- to_store.update(self.vcpuDomDetails())
+ to_store.update(self._vcpuDomDetails())
log.debug("Storing domain details: %s", to_store)
- self.writeDom(to_store)
+ self._writeDom(to_store)
-
- ## private:
-
- def vcpuDomDetails(self):
+ def _vcpuDomDetails(self):
def availability(n):
if self.info['vcpu_avail'] & (1 << n):
return 'online'
@@ -760,25 +718,80 @@ class XendDomainInfo:
result["cpu/%d/availability" % v] = availability(v)
return result
+ #
+ # xenstore watches
+ #
- ## public:
-
- def registerWatches(self):
+ def _registerWatches(self):
"""Register a watch on this VM's entries in the store, and the
domain's control/shutdown node, so that when they are changed
externally, we keep up to date. This should only be called by {@link
#create}, {@link #recreate}, or {@link #restore}, once the domain's
details have been written, but before the new instance is returned."""
- self.vmWatch = xswatch(self.vmpath, self.storeChanged)
+ self.vmWatch = xswatch(self.vmpath, self._storeChanged)
self.shutdownWatch = xswatch(self.dompath + '/control/shutdown',
- self.handleShutdownWatch)
+ self._handleShutdownWatch)
+
+ def _storeChanged(self, _):
+ log.trace("XendDomainInfo.storeChanged");
+
+ changed = False
+
+ def f(x, y):
+ if y is not None and self.info[x[0]] != y:
+ self.info[x[0]] = y
+ changed = True
+
+ map(f, VM_CONFIG_PARAMS, self._readVMDetails(VM_CONFIG_PARAMS))
+
+ im = self._readVm('image')
+ current_im = self.info['image']
+ if (im is not None and
+ (current_im is None or sxp.to_string(current_im) != im)):
+ self.info['image'] = sxp.from_string(im)
+ changed = True
+
+ if changed:
+ # Update the domain section of the store, as this contains some
+ # parameters derived from the VM configuration.
+ self._storeDomDetails()
+
+ return 1
+
+ def _handleShutdownWatch(self, _):
+ log.debug('XendDomainInfo.handleShutdownWatch')
+
+ reason = self._readDom('control/shutdown')
+
+ if reason and reason != 'suspend':
+ sst = self._readDom('xend/shutdown_start_time')
+ now = time.time()
+ if sst:
+ self.shutdownStartTime = float(sst)
+ timeout = float(sst) + SHUTDOWN_TIMEOUT - now
+ else:
+ self.shutdownStartTime = now
+ self._storeDom('xend/shutdown_start_time', now)
+ timeout = SHUTDOWN_TIMEOUT
+
+ log.trace(
+ "Scheduling refreshShutdown on domain %d in %ds.",
+ self.domid, timeout)
+ threading.Timer(timeout, self.refreshShutdown).start()
+
+ return True
+
+
+ #
+ # Public Attributes for the VM
+ #
def getDomid(self):
return self.domid
def setName(self, name):
- self.check_name(name)
+ self._checkName(name)
self.info['name'] = name
self.storeVm("name", name)
@@ -788,12 +801,13 @@ class XendDomainInfo:
def getDomainPath(self):
return self.dompath
+ def getShutdownReason(self):
+ return self._readDom('control/shutdown')
def getStorePort(self):
"""For use only by image.py and XendCheckpoint.py."""
return self.store_port
-
def getConsolePort(self):
"""For use only by image.py and XendCheckpoint.py"""
return self.console_port
@@ -805,11 +819,10 @@ class XendDomainInfo:
def getVCpuCount(self):
return self.info['vcpus']
-
def setVCpuCount(self, vcpus):
self.info['vcpu_avail'] = (1 << vcpus) - 1
self.storeVm('vcpu_avail', self.info['vcpu_avail'])
- self.writeDom(self.vcpuDomDetails())
+ self._writeDom(self._vcpuDomDetails())
def getLabel(self):
return security.get_security_info(self.info, 'label')
@@ -821,21 +834,29 @@ class XendDomainInfo:
def getResume(self):
return "%s" % self.info['resume']
- def endRestore(self):
- self.setResume(False)
+ def getCap(self):
+ return self.info['cpu_cap']
+
+ def getWeight(self):
+ return self.info['cpu_weight']
def setResume(self, state):
self.info['resume'] = state
def getRestartCount(self):
- return self.readVm('xend/restart_count')
+ return self._readVm('xend/restart_count')
def refreshShutdown(self, xeninfo = None):
+ """ Checks the domain for whether a shutdown is required.
+
+ Called from XendDomainInfo and also image.py for HVM images.
+ """
+
# If set at the end of this method, a restart is required, with the
# given reason. This restart has to be done out of the scope of
# refresh_shutdown_lock.
restart_reason = None
-
+
self.refresh_shutdown_lock.acquire()
try:
if xeninfo is None:
@@ -849,6 +870,7 @@ class XendDomainInfo:
# VM may have migrated to a different domain on this
# machine.
self.cleanupDomain()
+ self._stateSet(DOM_STATE_HALTED)
return
if xeninfo['dying']:
@@ -860,10 +882,11 @@ class XendDomainInfo:
# holding the pages, by calling cleanupDomain. We can't
# clean up the VM, as above.
self.cleanupDomain()
+ self._stateSet(DOM_STATE_SHUTDOWN)
return
elif xeninfo['crashed']:
- if self.readDom('xend/shutdown_completed'):
+ if self._readDom('xend/shutdown_completed'):
# We've seen this shutdown already, but we are preserving
# the domain for debugging. Leave it alone.
return
@@ -875,9 +898,11 @@ class XendDomainInfo:
self.dumpCore()
restart_reason = 'crash'
+ self._stateSet(DOM_STATE_HALTED)
elif xeninfo['shutdown']:
- if self.readDom('xend/shutdown_completed'):
+ self._stateSet(DOM_STATE_SHUTDOWN)
+ if self._readDom('xend/shutdown_completed'):
# We've seen this shutdown already, but we are preserving
# the domain for debugging. Leave it alone.
return
@@ -888,16 +913,16 @@ class XendDomainInfo:
log.info('Domain has shutdown: name=%s id=%d reason=%s.',
self.info['name'], self.domid, reason)
- self.clearRestart()
+ self._clearRestart()
if reason == 'suspend':
- self.state_set(STATE_DOM_SHUTDOWN)
+ self._stateSet(DOM_STATE_SUSPENDED)
# Don't destroy the domain. XendCheckpoint will do
# this once it has finished. However, stop watching
# the VM path now, otherwise we will end up with one
# watch for the old domain, and one for the new.
- self.unwatchVm()
- elif reason in ['poweroff', 'reboot']:
+ self._unwatchVm()
+ elif reason in ('poweroff', 'reboot'):
restart_reason = reason
else:
self.destroy()
@@ -910,7 +935,11 @@ class XendDomainInfo:
else:
# Domain is alive. If we are shutting it down, then check
# the timeout on that, and destroy it if necessary.
-
+ if xeninfo['paused']:
+ self._stateSet(DOM_STATE_PAUSED)
+ else:
+ self._stateSet(DOM_STATE_RUNNING)
+
if self.shutdownStartTime:
timeout = (SHUTDOWN_TIMEOUT - time.time() +
self.shutdownStartTime)
@@ -923,323 +952,280 @@ class XendDomainInfo:
self.refresh_shutdown_lock.release()
if restart_reason:
- self.maybeRestart(restart_reason)
+ self._maybeRestart(restart_reason)
- def handleShutdownWatch(self, _):
- log.debug('XendDomainInfo.handleShutdownWatch')
-
- reason = self.readDom('control/shutdown')
+ #
+ # Restart functions - handling whether we come back up on shutdown.
+ #
- if reason and reason != 'suspend':
- sst = self.readDom('xend/shutdown_start_time')
- now = time.time()
- if sst:
- self.shutdownStartTime = float(sst)
- timeout = float(sst) + SHUTDOWN_TIMEOUT - now
- else:
- self.shutdownStartTime = now
- self.storeDom('xend/shutdown_start_time', now)
- timeout = SHUTDOWN_TIMEOUT
+ def _clearRestart(self):
+ self._removeDom("xend/shutdown_start_time")
- log.trace(
- "Scheduling refreshShutdown on domain %d in %ds.",
- self.domid, timeout)
- threading.Timer(timeout, self.refreshShutdown).start()
- return True
-
-
- def shutdown(self, reason):
- if not reason in shutdown_reasons.values():
- raise XendError('Invalid reason: %s' % reason)
- if self.domid == 0:
- raise XendError("Can't specify Domain-0")
- self.storeDom("control/shutdown", reason)
-
-
- ## private:
-
- def clearRestart(self):
- self.removeDom("xend/shutdown_start_time")
-
-
- def maybeRestart(self, reason):
+ def _maybeRestart(self, reason):
# Dispatch to the correct method based upon the configured on_{reason}
# behaviour.
{"destroy" : self.destroy,
- "restart" : self.restart,
- "preserve" : self.preserve,
- "rename-restart" : self.renameRestart}[self.info['on_' + reason]]()
-
-
- def renameRestart(self):
- self.restart(True)
-
+ "restart" : self._restart,
+ "preserve" : self._preserve,
+ "rename-restart" : self._renameRestart}[self.info['on_' + reason]]()
- def dumpCore(self):
- """Create a core dump for this domain. Nothrow guarantee."""
-
- try:
- corefile = "/var/xen/dump/%s.%s.core" % (self.info['name'],
- self.domid)
- xc.domain_dumpcore(self.domid, corefile)
-
- except:
- log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s",
- self.domid, self.info['name'])
+ def _renameRestart(self):
+ self._restart(True)
- ## public:
+ def _restart(self, rename = False):
+ """Restart the domain after it has exited.
- def setMemoryTarget(self, target):
- """Set the memory target of this domain.
- @param target In MiB.
+ @param rename True if the old domain is to be renamed and preserved,
+ False if it is to be destroyed.
"""
- log.debug("Setting memory target of domain %s (%d) to %d MiB.",
- self.info['name'], self.domid, target)
+ from xen.xend import XendDomain
- self.info['memory'] = target
- self.storeVm("memory", target)
- self.storeDom("memory/target", target << 10)
-
-
- def update(self, info = None):
- """Update with info from xc.domain_getinfo().
- """
-
- log.trace("XendDomainInfo.update(%s) on domain %d", info, self.domid)
- if not info:
- info = dom_get(self.domid)
- if not info:
- return
-
- #manually update ssidref / security fields
- if security.on() and info.has_key('ssidref'):
- if (info['ssidref'] != 0) and self.info.has_key('security'):
- security_field = self.info['security']
- if not security_field:
- #create new security element
- self.info.update({'security': [['ssidref', str(info['ssidref'])]]})
- #ssidref field not used any longer
- info.pop('ssidref')
-
- self.info.update(info)
- self.validateInfo()
- self.refreshShutdown(info)
-
- log.trace("XendDomainInfo.update done on domain %d: %s", self.domid,
- self.info)
+ self._configureBootloader()
+ config = self.sxpr()
+ if self._infoIsSet('cpus') and len(self.info['cpus']) != 0:
+ config.append(['cpus', reduce(lambda x, y: str(x) + "," + str(y),
+ self.info['cpus'])])
- ## private:
+ if self._readVm(RESTART_IN_PROGRESS):
+ log.error('Xend failed during restart of domain %s. '
+ 'Refusing to restart to avoid loops.',
+ str(self.domid))
+ self.destroy()
+ return
- def state_set(self, state):
- self.state_updated.acquire()
- try:
- if self.state != state:
- self.state = state
- self.state_updated.notifyAll()
- finally:
- self.state_updated.release()
+ old_domid = self.domid
+ self._writeVm(RESTART_IN_PROGRESS, 'True')
+ now = time.time()
+ rst = self._readVm('xend/previous_restart_time')
+ if rst:
+ rst = float(rst)
+ timeout = now - rst
+ if timeout < MINIMUM_RESTART_TIME:
+ log.error(
+ 'VM %s restarting too fast (%f seconds since the last '
+ 'restart). Refusing to restart to avoid loops.',
+ self.info['name'], timeout)
+ self.destroy()
+ return
- ## public:
+ self._writeVm('xend/previous_restart_time', str(now))
- def waitForShutdown(self):
- self.state_updated.acquire()
try:
- while self.state == STATE_DOM_OK:
- self.state_updated.wait()
- finally:
- self.state_updated.release()
+ if rename:
+ self._preserveForRestart()
+ else:
+ self._unwatchVm()
+ self.destroyDomain()
+ # new_dom's VM will be the same as this domain's VM, except where
+ # the rename flag has instructed us to call preserveForRestart.
+ # In that case, it is important that we remove the
+ # RESTART_IN_PROGRESS node from the new domain, not the old one,
+ # once the new one is available.
- def __str__(self):
- s = "<domain"
- s += " id=" + str(self.domid)
- s += " name=" + self.info['name']
- s += " memory=" + str(self.info['memory'])
- s += ">"
- return s
+ new_dom = None
+ try:
+ new_dom = XendDomain.instance().domain_create(config)
+ new_dom.unpause()
+ rst_cnt = self._readVm('xend/restart_count')
+ rst_cnt = int(rst_cnt) + 1
+ self._writeVm('xend/restart_count', str(rst_cnt))
+ new_dom._removeVm(RESTART_IN_PROGRESS)
+ except:
+ if new_dom:
+ new_dom._removeVm(RESTART_IN_PROGRESS)
+ new_dom.destroy()
+ else:
+ self._removeVm(RESTART_IN_PROGRESS)
+ raise
+ except:
+ log.exception('Failed to restart domain %s.', str(old_domid))
- __repr__ = __str__
+ def _preserveForRestart(self):
+ """Preserve a domain that has been shut down, by giving it a new UUID,
+ cloning the VM details, and giving it a new name. This allows us to
+ keep this domain for debugging, but restart a new one in its place
+ preserving the restart semantics (name and UUID preserved).
+ """
+
+ new_uuid = uuid.createString()
+ new_name = 'Domain-%s' % new_uuid
+ log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
+ self.info['name'], self.domid, self.info['uuid'],
+ new_name, new_uuid)
+ self._unwatchVm()
+ self._releaseDevices()
+ self.info['name'] = new_name
+ self.info['uuid'] = new_uuid
+ self.vmpath = XS_VMROOT + new_uuid
+ self._storeVmDetails()
+ self._preserve()
- ## private:
+ def _preserve(self):
+ log.info("Preserving dead domain %s (%d).", self.info['name'],
+ self.domid)
+ self._unwatchVm()
+ self._storeDom('xend/shutdown_completed', 'True')
+ self._stateSet(DOM_STATE_HALTED)
- def createDevice(self, deviceClass, devconfig):
- return self.getDeviceController(deviceClass).createDevice(devconfig)
+ #
+ # Debugging ..
+ #
+ def dumpCore(self, corefile = None):
+ """Create a core dump for this domain. Nothrow guarantee."""
+
+ try:
+ if not corefile:
+ this_time = time.strftime("%Y-%m%d-%H%M.%S", time.localtime())
+ corefile = "/var/xen/dump/%s-%s.%s.core" % (this_time,
+ self.info['name'], self.domid)
+
+ if os.path.isdir(corefile):
+ raise XendError("Cannot dump core in a directory: %s" %
+ corefile)
+
+ xc.domain_dumpcore(self.domid, corefile)
+ except RuntimeError, ex:
+ corefile_incomp = corefile+'-incomplete'
+ os.rename(corefile, corefile_incomp)
+ log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s",
+ self.domid, self.info['name'])
+ raise XendError("Failed to dump core: %s" % str(ex))
- def waitForDevices_(self, deviceClass):
- return self.getDeviceController(deviceClass).waitForDevices()
+ #
+ # Device creation/deletion functions
+ #
+ def _createDevice(self, deviceClass, devConfig):
+ return self.getDeviceController(deviceClass).createDevice(devConfig)
- def waitForDevice(self, deviceClass, devid):
+ def _waitForDevice(self, deviceClass, devid):
return self.getDeviceController(deviceClass).waitForDevice(devid)
-
- def reconfigureDevice(self, deviceClass, devid, devconfig):
+ def _reconfigureDevice(self, deviceClass, devid, devconfig):
return self.getDeviceController(deviceClass).reconfigureDevice(
devid, devconfig)
+ def _createDevices(self):
+ """Create the devices for a vm.
- ## public:
-
- def destroyDevice(self, deviceClass, devid):
- if type(devid) is str:
- devicePath = '%s/device/%s' % (self.dompath, deviceClass)
- for entry in xstransact.List(devicePath):
- backend = xstransact.Read('%s/%s' % (devicePath, entry), "backend")
- devName = xstransact.Read(backend, "dev")
- if devName == devid:
- # We found the integer matching our devid, use it instead
- devid = entry
- break
- return self.getDeviceController(deviceClass).destroyDevice(devid)
-
-
- def getDeviceSxprs(self, deviceClass):
- return self.getDeviceController(deviceClass).sxprs()
-
+ @raise: VmError for invalid devices
+ """
+ for (devclass, config) in self.info.all_devices_sxpr():
+ if devclass in XendDevices.valid_devices():
+ log.info("createDevice: %s : %s" % (devclass, config))
+ self._createDevice(devclass, config)
- ## private:
+ if self.image:
+ self.image.createDeviceModel()
- def getDeviceConfigurations(self, deviceClass):
- return self.getDeviceController(deviceClass).configurations()
+ def _releaseDevices(self):
+ """Release all domain's devices. Nothrow guarantee."""
+ while True:
+ t = xstransact("%s/device" % self.dompath)
+ for devclass in XendDevices.valid_devices():
+ for dev in t.list(devclass):
+ try:
+ t.remove(dev)
+ except:
+ # Log and swallow any exceptions in removal --
+ # there's nothing more we can do.
+ log.exception(
+ "Device release failed: %s; %s; %s",
+ self.info['name'], devclass, dev)
+ if t.commit():
+ break
def getDeviceController(self, name):
- if name not in controllerClasses:
- raise XendError("unknown device type: " + str(name))
-
- return controllerClasses[name](self)
-
-
- ## public:
-
- def sxpr(self):
- sxpr = ['domain',
- ['domid', self.domid]]
-
- for e in ROUNDTRIPPING_CONFIG_ENTRIES:
- if self.infoIsSet(e[0]):
- sxpr.append([e[0], self.info[e[0]]])
-
- if self.infoIsSet('image'):
- sxpr.append(['image', self.info['image']])
-
- if self.infoIsSet('security'):
- sxpr.append(['security', self.info['security']])
-
- for cls in controllerClasses:
- for config in self.getDeviceConfigurations(cls):
- sxpr.append(['device', config])
-
- def stateChar(name):
- if name in self.info:
- if self.info[name]:
- return name[0]
- else:
- return '-'
- else:
- return '?'
-
- state = reduce(
- lambda x, y: x + y,
- map(stateChar,
- ['running', 'blocked', 'paused', 'shutdown', 'crashed',
- 'dying']))
-
- sxpr.append(['state', state])
- if self.infoIsSet('shutdown'):
- reason = shutdown_reason(self.info['shutdown_reason'])
- sxpr.append(['shutdown_reason', reason])
- if self.infoIsSet('cpu_time'):
- sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
- sxpr.append(['online_vcpus', self.info['online_vcpus']])
-
- if self.infoIsSet('start_time'):
- up_time = time.time() - self.info['start_time']
- sxpr.append(['up_time', str(up_time) ])
- sxpr.append(['start_time', str(self.info['start_time']) ])
-
- if self.store_mfn:
- sxpr.append(['store_mfn', self.store_mfn])
- if self.console_mfn:
- sxpr.append(['console_mfn', self.console_mfn])
+ """Get the device controller for this domain, and if it
+ doesn't exist, create it.
- return sxpr
+ @param name: device class name
+ @type name: string
+ @rtype: subclass of DevController
+ """
+ if name not in self._deviceControllers:
+ devController = XendDevices.make_controller(name, self)
+ if not devController:
+ raise XendError("Unknown device type: %s" % name)
+ self._deviceControllers[name] = devController
+
+ return self._deviceControllers[name]
+
+ #
+ # Migration functions (public)
+ #
+ def testMigrateDevices(self, network, dst):
+ """ Notify all device about intention of migration
+ @raise: XendError for a device that cannot be migrated
+ """
+ for (n, c) in self.info.all_devices_sxpr():
+ rc = self.migrateDevice(n, c, network, dst, DEV_MIGRATE_TEST)
+ if rc != 0:
+ raise XendError("Device of type '%s' refuses migration." % n)
- def getVCPUInfo(self):
+ def migrateDevices(self, network, dst, step, domName=''):
+ """Notify the devices about migration
+ """
+ ctr = 0
try:
- # We include the domain name and ID, to help xm.
- sxpr = ['domain',
- ['domid', self.domid],
- ['name', self.info['name']],
- ['vcpu_count', self.info['online_vcpus']]]
+ for (dev_type, dev_conf) in self.info.all_devices_sxpr():
+ self.migrateDevice(dev_type, dev_conf, network, dst,
+ step, domName)
+ ctr = ctr + 1
+ except:
+ for dev_type, dev_conf in self.info.all_devices_sxpr():
+ if ctr == 0:
+ step = step - 1
+ ctr = ctr - 1
+ self._recoverMigrateDevice(dev_type, dev_conf, network,
+ dst, step, domName)
+ raise
- for i in range(0, self.info['max_vcpu_id']+1):
- info = xc.vcpu_getinfo(self.domid, i)
+ def migrateDevice(self, deviceClass, deviceConfig, network, dst,
+ step, domName=''):
+ return self.getDeviceController(deviceClass).migrate(deviceConfig,
+ network, dst, step, domName)
- sxpr.append(['vcpu',
- ['number', i],
- ['online', info['online']],
- ['blocked', info['blocked']],
- ['running', info['running']],
- ['cpu_time', info['cpu_time'] / 1e9],
- ['cpu', info['cpu']],
- ['cpumap', info['cpumap']]])
+ def _recoverMigrateDevice(self, deviceClass, deviceConfig, network,
+ dst, step, domName=''):
+ return self.getDeviceController(deviceClass).recover_migrate(
+ deviceConfig, network, dst, step, domName)
- return sxpr
-
- except RuntimeError, exn:
- raise XendError(str(exn))
-
## private:
- def check_name(self, name):
- """Check if a vm name is valid. Valid names contain alphabetic characters,
- digits, or characters in '_-.:/+'.
- The same name cannot be used for more than one vm at the same time.
-
- @param name: name
- @raise: VmError if invalid
- """
- if name is None or name == '':
- raise VmError('missing vm name')
- for c in name:
- if c in string.digits: continue
- if c in '_-.:/+': continue
- if c in string.ascii_letters: continue
- raise VmError('invalid vm name')
-
- dominfo = domain_by_name(name)
- if not dominfo:
- return
- if self.domid is None:
- raise VmError("VM name '%s' already in use by domain %d" %
- (name, dominfo.domid))
- if dominfo.domid != self.domid:
- raise VmError("VM name '%s' is used in both domains %d and %d" %
- (name, self.domid, dominfo.domid))
-
-
- def construct(self):
+ def _constructDomain(self):
"""Construct the domain.
@raise: VmError on error
"""
- log.debug('XendDomainInfo.construct: %s',
- self.domid)
+ log.debug('XendDomainInfo.constructDomain')
+
+ hvm = (self._infoIsSet('image') and
+ sxp.name(self.info['image']) == "hvm")
+ if hvm:
+ info = xc.xeninfo()
+ if not 'hvm' in info['xen_caps']:
+ raise VmError("HVM guest support is unavailable: is VT/AMD-V "
+ "supported by your CPU and enabled in your "
+ "BIOS?")
self.domid = xc.domain_create(
- dom = 0, ssidref = security.get_security_info(self.info, 'ssidref'),
- handle = uuid.fromString(self.info['uuid']))
+ domid = 0,
+ ssidref = security.get_security_info(self.info, 'ssidref'),
+ handle = uuid.fromString(self.info['uuid']),
+ hvm = int(hvm))
if self.domid < 0:
raise VmError('Creating domain failed: name=%s' %
@@ -1247,13 +1233,13 @@ class XendDomainInfo:
self.dompath = GetDomainPath(self.domid)
- self.recreateDom()
+ self._recreateDom()
# Set maximum number of vcpus in domain
xc.domain_max_vcpus(self.domid, int(self.info['vcpus']))
- def introduceDomain(self):
+ def _introduceDomain(self):
assert self.domid is not None
assert self.store_mfn is not None
assert self.store_port is not None
@@ -1264,25 +1250,25 @@ class XendDomainInfo:
raise XendError(str(exn))
- def initDomain(self):
+ def _initDomain(self):
log.debug('XendDomainInfo.initDomain: %s %s',
self.domid,
self.info['cpu_weight'])
# if we have a boot loader but no image, then we need to set things
# up by running the boot loader non-interactively
- if self.infoIsSet('bootloader') and not self.infoIsSet('image'):
- self.configure_bootloader()
+ if self._infoIsSet('bootloader') and not self._infoIsSet('image'):
+ self._configureBootloader()
- if not self.infoIsSet('image'):
+ if not self._infoIsSet('image'):
raise VmError('Missing image in configuration')
try:
self.image = image.create(self,
self.info['image'],
- self.info['device'])
+ self.info.all_devices_sxpr())
- localtime = self.info['localtime']
+ localtime = self.info.get('localtime', 0)
if localtime is not None and localtime == 1:
xc.domain_set_time_offset(self.domid)
@@ -1297,10 +1283,7 @@ class XendDomainInfo:
# Use architecture- and image-specific calculations to determine
# the various headrooms necessary, given the raw configured
- # values.
- # reservation, maxmem, memory, and shadow are all in KiB.
- reservation = self.image.getRequiredInitialReservation(
- self.info['memory'] * 1024)
+ # values. maxmem, memory, and shadow are all in KiB.
maxmem = self.image.getRequiredAvailableMemory(
self.info['maxmem'] * 1024)
memory = self.image.getRequiredAvailableMemory(
@@ -1323,11 +1306,7 @@ class XendDomainInfo:
shadow_cur = xc.shadow_mem_control(self.domid, shadow / 1024)
self.info['shadow_memory'] = shadow_cur
- # initial memory reservation
- xc.domain_memory_increase_reservation(self.domid, reservation, 0,
- 0)
-
- self.createChannels()
+ self._createChannels()
channel_details = self.image.createImage()
@@ -1335,21 +1314,24 @@ class XendDomainInfo:
if 'console_mfn' in channel_details:
self.console_mfn = channel_details['console_mfn']
- self.introduceDomain()
+ self._introduceDomain()
- self.createDevices()
+ self._createDevices()
- if self.info['bootloader']:
+ if self.info['bootloader'] not in [None, 'kernel_external']:
self.image.cleanupBootloading()
self.info['start_time'] = time.time()
+ self._stateSet(DOM_STATE_RUNNING)
except RuntimeError, exn:
+ log.exception("XendDomainInfo.initDomain: exception occurred")
+ if self.info['bootloader'] not in [None, 'kernel_external'] \
+ and self.image is not None:
+ self.image.cleanupBootloading()
raise VmError(str(exn))
- ## public:
-
def cleanupDomain(self):
"""Cleanup domain resources; release devices. Idempotent. Nothrow
guarantee."""
@@ -1358,7 +1340,7 @@ class XendDomainInfo:
try:
self.unwatchShutdown()
- self.release_devices()
+ self._releaseDevices()
if self.image:
try:
@@ -1369,48 +1351,15 @@ class XendDomainInfo:
self.image = None
try:
- self.removeDom()
+ self._removeDom()
except:
log.exception("Removing domain path failed.")
- try:
- if not self.info['name'].startswith(ZOMBIE_PREFIX):
- self.info['name'] = ZOMBIE_PREFIX + self.info['name']
- except:
- log.exception("Renaming Zombie failed.")
-
- self.state_set(STATE_DOM_SHUTDOWN)
+ self._stateSet(DOM_STATE_HALTED)
finally:
self.refresh_shutdown_lock.release()
- def cleanupVm(self):
- """Cleanup VM resources. Idempotent. Nothrow guarantee."""
-
- self.unwatchVm()
-
- try:
- self.removeVm()
- except:
- log.exception("Removing VM path failed.")
-
-
- ## private:
-
- def unwatchVm(self):
- """Remove the watch on the VM path, if any. Idempotent. Nothrow
- guarantee."""
-
- try:
- try:
- if self.vmWatch:
- self.vmWatch.unwatch()
- finally:
- self.vmWatch = None
- except:
- log.exception("Unwatching VM path failed.")
-
-
def unwatchShutdown(self):
"""Remove the watch on the domain's control/shutdown node, if any.
Idempotent. Nothrow guarantee. Expects to be protected by the
@@ -1425,84 +1374,142 @@ class XendDomainInfo:
except:
log.exception("Unwatching control/shutdown failed.")
+ def waitForShutdown(self):
+ self.state_updated.acquire()
+ try:
+ while self.state in (DOM_STATE_RUNNING,DOM_STATE_PAUSED):
+ self.state_updated.wait()
+ finally:
+ self.state_updated.release()
+
+
+ #
+ # TODO: recategorise - called from XendCheckpoint
+ #
- ## public:
+ def completeRestore(self, store_mfn, console_mfn):
+
+ log.debug("XendDomainInfo.completeRestore")
+
+ self.store_mfn = store_mfn
+ self.console_mfn = console_mfn
+
+ self._introduceDomain()
+ self._storeDomDetails()
+ self._registerWatches()
+ self.refreshShutdown()
+
+ log.debug("XendDomainInfo.completeRestore done")
+
+
+ def _endRestore(self):
+ self.setResume(False)
+
+ #
+ # VM Destroy
+ #
def destroy(self):
"""Cleanup VM and destroy domain. Nothrow guarantee."""
- log.debug("XendDomainInfo.destroy: domid=%s", self.domid)
+ log.debug("XendDomainInfo.destroy: domid=%s", str(self.domid))
- self.cleanupVm()
+ self._cleanupVm()
if self.dompath is not None:
- self.destroyDomain()
+ self.destroyDomain()
def destroyDomain(self):
- log.debug("XendDomainInfo.destroyDomain(%s)", self.domid)
+ log.debug("XendDomainInfo.destroyDomain(%s)", str(self.domid))
try:
if self.domid is not None:
xc.domain_destroy(self.domid)
+ self.domid = None
+ for state in DOM_STATES_OLD:
+ self.info[state] = 0
except:
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
self.cleanupDomain()
- ## private:
+ #
+ # Channels for xenstore and console
+ #
- def release_devices(self):
- """Release all domain's devices. Nothrow guarantee."""
-
- while True:
- t = xstransact("%s/device" % self.dompath)
- for n in controllerClasses.keys():
- for d in t.list(n):
- try:
- t.remove(d)
- except:
- # Log and swallow any exceptions in removal --
- # there's nothing more we can do.
- log.exception(
- "Device release failed: %s; %s; %s",
- self.info['name'], n, d)
- if t.commit():
- break
-
-
- def createChannels(self):
+ def _createChannels(self):
"""Create the channels to the domain.
"""
- self.store_port = self.createChannel()
- self.console_port = self.createChannel()
+ self.store_port = self._createChannel()
+ self.console_port = self._createChannel()
- def createChannel(self):
+ def _createChannel(self):
"""Create an event channel to the domain.
"""
try:
- return xc.evtchn_alloc_unbound(dom=self.domid, remote_dom=0)
+ return xc.evtchn_alloc_unbound(domid=self.domid, remote_dom=0)
except:
log.exception("Exception in alloc_unbound(%d)", self.domid)
raise
+ #
+ # Bootloader configuration
+ #
- ## public:
+ def _configureBootloader(self):
+ """Run the bootloader if we're configured to do so."""
+ if not self.info['bootloader']:
+ return
+ blcfg = None
+ # FIXME: this assumes that we want to use the first disk device
+ for (n, c) in self.info.all_devices_sxpr():
+ if not n or not c or not(n in ["vbd", "tap"]):
+ continue
+ disk = sxp.child_value(c, "uname")
+ if disk is None:
+ continue
+ fn = blkdev_uname_to_file(disk)
+ blcfg = bootloader(self.info['bootloader'], fn, 1,
+ self.info['bootloader_args'],
+ self.info['image'])
+ break
+ if blcfg is None:
+ msg = "Had a bootloader specified, but can't find disk"
+ log.error(msg)
+ raise VmError(msg)
+ self.info['image'] = blcfg
- def createDevices(self):
- """Create the devices for a vm.
+ #
+ # VM Functions
+ #
- @raise: VmError for invalid devices
+ def _readVMDetails(self, params):
+ """Read the specified parameters from the store.
"""
+ try:
+ return self._gatherVm(*params)
+ except ValueError:
+ # One of the int/float entries in params has a corresponding store
+ # entry that is invalid. We recover, because older versions of
+ # Xend may have put the entry there (memory/target, for example),
+ # but this is in general a bad situation to have reached.
+ log.exception(
+ "Store corrupted at %s! Domain %d's configuration may be "
+ "affected.", self.vmpath, self.domid)
+ return []
- for (n, c) in self.info['device']:
- self.createDevice(n, c)
+ def _cleanupVm(self):
+ """Cleanup VM resources. Idempotent. Nothrow guarantee."""
- if self.image:
- self.image.createDeviceModel()
+ self._unwatchVm()
+
+ try:
+ self._removeVm()
+ except:
+ log.exception("Removing VM path failed.")
- ## public:
def checkLiveMigrateMemory(self):
""" Make sure there's enough memory to migrate this domain """
@@ -1517,22 +1524,27 @@ class XendDomainInfo:
if overhead_kb > 0:
balloon.free(overhead_kb)
- def testMigrateDevices(self, network, dst):
- """ Notify all device about intention of migration
- @raise: XendError for a device that cannot be migrated
- """
- for (n, c) in self.info['device']:
- rc = self.migrateDevice(n, c, network, dst, DEV_MIGRATE_TEST)
- if rc != 0:
- raise XendError("Device of type '%s' refuses migration." % n)
+ def _unwatchVm(self):
+ """Remove the watch on the VM path, if any. Idempotent. Nothrow
+ guarantee."""
+ try:
+ try:
+ if self.vmWatch:
+ self.vmWatch.unwatch()
+ finally:
+ self.vmWatch = None
+ except:
+ log.exception("Unwatching VM path failed.")
def testDeviceComplete(self):
""" For Block IO migration safety we must ensure that
the device has shutdown correctly, i.e. all blocks are
flushed to disk
"""
+ start = time.time()
while True:
test = 0
+ diff = time.time() - start
for i in self.getDeviceController('vbd').deviceIDs():
test = 1
log.info("Dev %s still active, looping...", i)
@@ -1540,239 +1552,439 @@ class XendDomainInfo:
if test == 0:
break
+ if diff >= MIGRATE_TIMEOUT:
+ log.info("Dev still active but hit max loop timeout")
+ break
- def migrateDevices(self, network, dst, step, domName=''):
- """Notify the devices about migration
- """
- ctr = 0
- try:
- for (n, c) in self.info['device']:
- self.migrateDevice(n, c, network, dst, step, domName)
- ctr = ctr + 1
- except:
- for (n, c) in self.info['device']:
- if ctr == 0:
- step = step - 1
- ctr = ctr - 1
- self.recoverMigrateDevice(n, c, network, dst, step, domName)
- raise
+ def _storeVmDetails(self):
+ to_store = {}
- def migrateDevice(self, deviceClass, deviceConfig, network, dst,
- step, domName=''):
- return self.getDeviceController(deviceClass).migrate(deviceConfig,
- network, dst, step, domName)
+ for k in VM_STORE_ENTRIES:
+ if self._infoIsSet(k[0]):
+ to_store[k[0]] = str(self.info[k[0]])
- def recoverMigrateDevice(self, deviceClass, deviceConfig, network,
- dst, step, domName=''):
- return self.getDeviceController(deviceClass).recover_migrate(
- deviceConfig, network, dst, step, domName)
+ if self._infoIsSet('image'):
+ to_store['image'] = sxp.to_string(self.info['image'])
- def waitForDevices(self):
- """Wait for this domain's configured devices to connect.
+ if self._infoIsSet('security'):
+ secinfo = self.info['security']
+ to_store['security'] = sxp.to_string(secinfo)
+ for idx in range(0, len(secinfo)):
+ if secinfo[idx][0] == 'access_control':
+ to_store['security/access_control'] = sxp.to_string(
+ [secinfo[idx][1], secinfo[idx][2]])
+ for aidx in range(1, len(secinfo[idx])):
+ if secinfo[idx][aidx][0] == 'label':
+ to_store['security/access_control/label'] = \
+ secinfo[idx][aidx][1]
+ if secinfo[idx][aidx][0] == 'policy':
+ to_store['security/access_control/policy'] = \
+ secinfo[idx][aidx][1]
+ if secinfo[idx][0] == 'ssidref':
+ to_store['security/ssidref'] = str(secinfo[idx][1])
+
+
+ if not self._readVm('xend/restart_count'):
+ to_store['xend/restart_count'] = str(0)
- @raise: VmError if any device fails to initialise.
- """
- for c in controllerClasses:
- self.waitForDevices_(c)
+ log.debug("Storing VM details: %s", to_store)
+ self._writeVm(to_store)
+ self._setVmPermissions()
- def device_create(self, dev_config):
- """Create a new device.
- @param dev_config: device configuration
- """
- dev_type = sxp.name(dev_config)
- devid = self.createDevice(dev_type, dev_config)
- self.waitForDevice(dev_type, devid)
- self.info['device'].append((dev_type, dev_config))
- return self.getDeviceController(dev_type).sxpr(devid)
+ def _setVmPermissions(self):
+ """Allow the guest domain to read its UUID. We don't allow it to
+ access any other entry, for security."""
+ xstransact.SetPermissions('%s/uuid' % self.vmpath,
+ { 'dom' : self.domid,
+ 'read' : True,
+ 'write' : False })
+ #
+ # Utility functions
+ #
- def device_configure(self, dev_config):
- """Configure an existing device.
- @param dev_config: device configuration
- """
- deviceClass = sxp.name(dev_config)
- self.reconfigureDevice(deviceClass, None, dev_config)
+ def _stateSet(self, state):
+ self.state_updated.acquire()
+ try:
+ if self.state != state:
+ self.state = state
+ self.state_updated.notifyAll()
+ finally:
+ self.state_updated.release()
+ def _infoIsSet(self, name):
+ return name in self.info and self.info[name] is not None
- def pause(self):
- xc.domain_pause(self.domid)
+ def _checkName(self, name):
+ """Check if a vm name is valid. Valid names contain alphabetic
+ characters, digits, or characters in '_-.:/+'.
+ The same name cannot be used for more than one vm at the same time.
+ @param name: name
+ @raise: VmError if invalid
+ """
+ from xen.xend import XendDomain
+
+ if name is None or name == '':
+ raise VmError('Missing VM Name')
- def unpause(self):
- xc.domain_unpause(self.domid)
+ if not re.search(r'^[A-Za-z0-9_\-\.\:\/\+]+$', name):
+ raise VmError('Invalid VM Name')
+ dom = XendDomain.instance().domain_lookup_nr(name)
+ if dom and dom != self and not dom.info['dying']:
+ raise VmError("VM name '%s' already exists" % name)
+
- ## private:
+ def update(self, info = None, refresh = True):
+ """Update with info from xc.domain_getinfo().
+ """
+ log.trace("XendDomainInfo.update(%s) on domain %s", info,
+ str(self.domid))
+
+ if not info:
+ info = dom_get(self.domid)
+ if not info:
+ return
+
+ #manually update ssidref / security fields
+ if security.on() and info.has_key('ssidref'):
+ if (info['ssidref'] != 0) and self.info.has_key('security'):
+ security_field = self.info['security']
+ if not security_field:
+ #create new security element
+ self.info.update({'security':
+ [['ssidref', str(info['ssidref'])]]})
+ #ssidref field not used any longer
+ if 'ssidref' in info:
+ info.pop('ssidref')
- def restart(self, rename = False):
- """Restart the domain after it has exited.
+ # make sure state is reset for info
+ # TODO: we should eventually get rid of old_dom_states
- @param rename True if the old domain is to be renamed and preserved,
- False if it is to be destroyed.
- """
+ self.info.update(info)
+ self.info.validate()
- self.configure_bootloader()
- config = self.sxpr()
+ if refresh:
+ self.refreshShutdown(info)
- if self.infoIsSet('cpus') and len(self.info['cpus']) != 0:
- config.append(['cpus', reduce(lambda x, y: str(x) + "," + str(y),
- self.info['cpus'])])
+ log.trace("XendDomainInfo.update done on domain %s: %s",
+ str(self.domid), self.info)
- if self.readVm(RESTART_IN_PROGRESS):
- log.error('Xend failed during restart of domain %d. '
- 'Refusing to restart to avoid loops.',
- self.domid)
- self.destroy()
- return
+ def sxpr(self, ignore_store = False):
+ result = self.info.get_sxp(domain = self,
+ ignore_devices = ignore_store)
- self.writeVm(RESTART_IN_PROGRESS, 'True')
+ if not ignore_store and self.dompath:
+ vnc_port = self._readDom('console/vnc-port')
+ if vnc_port is not None:
+ result.append(['device',
+ ['console', ['vnc-port', str(vnc_port)]]])
- now = time.time()
- rst = self.readVm('xend/previous_restart_time')
- if rst:
- rst = float(rst)
- timeout = now - rst
- if timeout < MINIMUM_RESTART_TIME:
- log.error(
- 'VM %s restarting too fast (%f seconds since the last '
- 'restart). Refusing to restart to avoid loops.',
- self.info['name'], timeout)
- self.destroy()
- return
+ return result
+
+ # Xen API
+ # ----------------------------------------------------------------
+
+ def get_uuid(self):
+ dom_uuid = self.info.get('uuid')
+ if not dom_uuid: # if it doesn't exist, make one up
+ dom_uuid = uuid.createString()
+ self.info['uuid'] = dom_uuid
+ return dom_uuid
+
+ def get_memory_static_max(self):
+ return self.info['maxmem']
+ def get_memory_static_min(self):
+ return self.info['memory']
+ def get_vcpus_policy(self):
+ sched_id = xc.sched_id_get()
+ if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
+ return 'sedf'
+ elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
+ return 'credit'
+ else:
+ return 'unknown'
+ def get_vcpus_params(self):
+ return '' # TODO
+ def get_power_state(self):
+ return XEN_API_VM_POWER_STATE[self.state]
+ def get_bios_boot(self):
+ return '' # TODO
+ def get_platform_std_vga(self):
+ return False
+ def get_platform_serial(self):
+ return '' # TODO
+ def get_platform_localtime(self):
+ return False # TODO
+ def get_platform_clock_offset(self):
+ return False # TODO
+ def get_platform_enable_audio(self):
+ return False # TODO
+ def get_builder(self):
+ return 'Linux' # TODO
+ def get_boot_method(self):
+ bootloader = self.info['bootloader']
+ if not bootloader or bootloader not in XEN_API_BOOT_TYPE:
+ return 'kernel_external'
+ return bootloader
+
+ def get_kernel_image(self):
+ return self.info['kernel_kernel']
+ def get_kernel_initrd(self):
+ return self.info['kernel_initrd']
+ def get_kernel_args(self):
+ return self.info['kernel_args']
+ def get_grub_cmdline(self):
+ return '' # TODO
+ def get_pci_bus(self):
+ return 0 # TODO
+ def get_tools_version(self):
+ return {} # TODO
+ def get_other_config(self):
+ return {} # TODO
+
+ def get_on_shutdown(self):
+ after_shutdown = self.info.get('on_poweroff')
+ if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT:
+ return XEN_API_ON_NORMAL_EXIT[-1]
+ return after_shutdown
+
+ def get_on_reboot(self):
+ after_reboot = self.info.get('on_reboot')
+ if not after_reboot or after_reboot not in XEN_API_ON_NORMAL_EXIT:
+ return XEN_API_ON_NORMAL_EXIT[-1]
+ return after_reboot
+
+ def get_on_suspend(self):
+ after_suspend = self.info.get('on_suspend') # TODO: not supported
+ if not after_suspend or after_suspend not in XEN_API_ON_NORMAL_EXIT:
+ return XEN_API_ON_NORMAL_EXIT[-1]
+ return after_suspend
+
+ def get_on_crash(self):
+ after_crash = self.info.get('on_crash')
+ if not after_crash or after_crash not in XEN_API_ON_CRASH_BEHAVIOUR:
+ return XEN_API_ON_CRASH_BEHAVIOUR[0]
+ return after_crash
+
+ def get_dev_config_by_uuid(self, dev_class, dev_uuid):
+ """ Get's a device configuration either from XendConfig or
+ from the DevController.
+
+ @param dev_class: device class, either, 'vbd' or 'vif'
+ @param dev_uuid: device UUID
+
+ @rtype: dictionary
+ """
+ dev_type_config = self.info['device'].get(dev_uuid)
+
+ # shortcut if the domain isn't started because
+ # the devcontrollers will have no better information
+ # than XendConfig.
+ if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
+ if dev_type_config:
+ return copy.deepcopy(dev_type_config[1])
+ return None
+
+ # instead of using dev_class, we use the dev_type
+ # that is from XendConfig.
+ # This will accomdate 'tap' as well as 'vbd'
+ dev_type = dev_type_config[0]
+
+ controller = self.getDeviceController(dev_type)
+ if not controller:
+ return None
+
+ all_configs = controller.getAllDeviceConfigurations()
+ if not all_configs:
+ return None
+
+ dev_config = copy.deepcopy(dev_type_config[1])
+ for _devid, _devcfg in all_configs.items():
+ if _devcfg.get('uuid') == dev_uuid:
+ dev_config.update(_devcfg)
+ dev_config['id'] = _devid
+ return dev_config
+
+ return dev_config
+
+ def get_dev_xenapi_config(self, dev_class, dev_uuid):
+ config = self.get_dev_config_by_uuid(dev_class, dev_uuid)
+ if not config:
+ return {}
+
+ config['VM'] = self.get_uuid()
+
+ if dev_class == 'vif':
+ if not config.has_key('name'):
+ config['name'] = config.get('vifname', '')
+ if not config.has_key('MAC'):
+ config['MAC'] = config.get('mac', '')
+ if not config.has_key('type'):
+ config['type'] = 'paravirtualised'
+ if not config.has_key('device'):
+ devid = config.get('id')
+ if devid != None:
+ config['device'] = 'eth%d' % devid
+ else:
+ config['device'] = ''
+
+ config['network'] = '' # Invalid for Xend
+ config['MTU'] = 1500 # TODO
+ config['network_read_kbs'] = 0.0
+ config['network_write_kbs'] = 0.0
+ config['IO_bandwidth_incoming_kbs'] = 0.0
+ config['IO_bandwidth_outgoing_kbs'] = 0.0
+
+ if dev_class =='vbd':
+ config['VDI'] = '' # TODO
+ config['device'] = config.get('dev', '')
+ config['driver'] = 'paravirtualised' # TODO
+ config['image'] = config.get('uname', '')
+ config['IO_bandwidth_incoming_kbs'] = 0.0
+ config['IO_bandwidth_outgoing_kbs'] = 0.0
+ if config['mode'] == 'r':
+ config['mode'] = 'RO'
+ else:
+ config['mode'] = 'RW'
+
+ if dev_class == 'vtpm':
+ config['driver'] = 'paravirtualised' # TODO
- self.writeVm('xend/previous_restart_time', str(now))
+ return config
+ def get_dev_property(self, dev_class, dev_uuid, field):
+ config = self.get_dev_xenapi_config(dev_class, dev_uuid)
try:
- if rename:
- self.preserveForRestart()
- else:
- self.unwatchVm()
- self.destroyDomain()
+ return config[field]
+ except KeyError:
+ raise XendError('Invalid property for device: %s' % field)
+
+ def get_vcpus_util(self):
+ # TODO: this returns the total accum cpu time, rather than util
+ # TODO: spec says that key is int, however, python does not allow
+ # non-string keys to dictionaries.
+ vcpu_util = {}
+ if 'max_vcpu_id' in self.info and self.domid != None:
+ for i in range(0, self.info['max_vcpu_id']+1):
+ info = xc.vcpu_getinfo(self.domid, i)
+ vcpu_util[str(i)] = info['cpu_time']/1000000000.0
+
+ return vcpu_util
- # new_dom's VM will be the same as this domain's VM, except where
- # the rename flag has instructed us to call preserveForRestart.
- # In that case, it is important that we remove the
- # RESTART_IN_PROGRESS node from the new domain, not the old one,
- # once the new one is available.
+ def get_vifs(self):
+ return self.info.get('vif_refs', [])
- new_dom = None
- try:
- new_dom = XendDomain.instance().domain_create(config)
- new_dom.unpause()
- rst_cnt = self.readVm('xend/restart_count')
- rst_cnt = int(rst_cnt) + 1
- self.writeVm('xend/restart_count', str(rst_cnt))
- new_dom.removeVm(RESTART_IN_PROGRESS)
- except:
- if new_dom:
- new_dom.removeVm(RESTART_IN_PROGRESS)
- new_dom.destroy()
- else:
- self.removeVm(RESTART_IN_PROGRESS)
- raise
- except:
- log.exception('Failed to restart domain %d.', self.domid)
+ def get_vbds(self):
+ return self.info.get('vbd_refs', [])
+ def get_vtpms(self):
+ return self.info.get('vtpm_refs', [])
- def preserveForRestart(self):
- """Preserve a domain that has been shut down, by giving it a new UUID,
- cloning the VM details, and giving it a new name. This allows us to
- keep this domain for debugging, but restart a new one in its place
- preserving the restart semantics (name and UUID preserved).
+ def create_vbd(self, xenapi_vbd):
+ """Create a VBD device from the passed struct in Xen API format.
+
+ @return: uuid of the device
+ @rtype: string
"""
+
+ dev_uuid = self.info.device_add('vbd', cfg_xenapi = xenapi_vbd)
+ if not dev_uuid:
+ raise XendError('Failed to create device')
- new_name = self.generateUniqueName()
- new_uuid = uuid.toString(uuid.create())
- log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
- self.info['name'], self.domid, self.info['uuid'],
- new_name, new_uuid)
- self.unwatchVm()
- self.release_devices()
- self.info['name'] = new_name
- self.info['uuid'] = new_uuid
- self.vmpath = XendDomain.VMROOT + new_uuid
- self.storeVmDetails()
- self.preserve()
+ if self.state in (XEN_API_VM_POWER_STATE_RUNNING,):
+ sxpr = self.info.device_sxpr(dev_uuid)
+ devid = self.getDeviceController('vbd').createDevice(sxpr)
+ raise XendError("Device creation failed")
+ return dev_uuid
- def preserve(self):
- log.info("Preserving dead domain %s (%d).", self.info['name'],
- self.domid)
- self.unwatchVm()
- self.storeDom('xend/shutdown_completed', 'True')
- self.state_set(STATE_DOM_SHUTDOWN)
+ def create_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
+ """Create a VBD using a VDI from XendStorageRepository.
+ @param xenapi_vbd: vbd struct from the Xen API
+ @param vdi_image_path: VDI UUID
+ @rtype: string
+ @return: uuid of the device
+ """
+ xenapi_vbd['image'] = vdi_image_path
+ log.debug('create_vbd_with_vdi: %s' % xenapi_vbd)
+ dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
+ if not dev_uuid:
+ raise XendError('Failed to create device')
- # private:
+ if self.state in (XEN_API_VM_POWER_STATE_RUNNING,):
+ sxpr = self.info.device_sxpr(dev_uuid)
+ devid = self.getDeviceController('tap').createDevice(sxpr)
+ raise XendError("Device creation failed")
- def generateUniqueName(self):
- n = 1
- while True:
- name = "%s-%d" % (self.info['name'], n)
- try:
- self.check_name(name)
- return name
- except VmError:
- n += 1
+ return dev_uuid
+ def create_vif(self, xenapi_vif):
+ """Create VIF device from the passed struct in Xen API format.
- def configure_bootloader(self):
- """Run the bootloader if we're configured to do so."""
- if not self.info['bootloader']:
- return
- blcfg = None
- # FIXME: this assumes that we want to use the first disk device
- for (n,c) in self.info['device']:
- if not n or not c or n != "vbd":
- continue
- disk = sxp.child_value(c, "uname")
- if disk is None:
- continue
- fn = blkdev_uname_to_file(disk)
- blcfg = bootloader(self.info['bootloader'], fn, 1,
- self.info['bootloader_args'],
- self.info['image'])
- break
- if blcfg is None:
- msg = "Had a bootloader specified, but can't find disk"
- log.error(msg)
- raise VmError(msg)
- self.info['image'] = blcfg
+ @param xenapi_vif: Xen API VIF Struct.
+ @rtype: string
+ @return: UUID
+ """
+ dev_uuid = self.info.device_add('vif', cfg_xenapi = xenapi_vif)
+ if not dev_uuid:
+ raise XendError('Failed to create device')
+
+ if self.state in (DOM_STATE_HALTED,):
+ sxpr = self.info.device_sxpr(dev_uuid)
+ devid = self.getDeviceController('vif').createDevice(sxpr)
+ raise XendError("Device creation failed")
+ return dev_uuid
- def send_sysrq(self, key):
- asserts.isCharConvertible(key)
+ def create_vtpm(self, xenapi_vtpm):
+ """Create a VTPM device from the passed struct in Xen API format.
- self.storeDom("control/sysrq", '%c' % key)
+ @return: uuid of the device
+ @rtype: string
+ """
+ if self.state not in (DOM_STATE_HALTED,):
+ raise VmError("Can only add vTPM to a halted domain.")
+ if self.get_vtpms() != []:
+ raise VmError('Domain already has a vTPM.')
+ dev_uuid = self.info.device_add('vtpm', cfg_xenapi = xenapi_vtpm)
+ if not dev_uuid:
+ raise XendError('Failed to create device')
- def infoIsSet(self, name):
- return name in self.info and self.info[name] is not None
+ return dev_uuid
+ def has_device(self, dev_class, dev_uuid):
+ return (dev_uuid in self.info['%s_refs' % dev_class])
-#============================================================================
-# Register device controllers and their device config types.
+ """
+ def stateChar(name):
+ if name in self.info:
+ if self.info[name]:
+ return name[0]
+ else:
+ return '-'
+ else:
+ return '?'
-"""A map from device-class names to the subclass of DevController that
-implements the device control specific to that device-class."""
-controllerClasses = {}
+ state = reduce(lambda x, y: x + y, map(stateChar, DOM_STATES_OLD))
+
+ sxpr.append(['state', state])
-def addControllerClass(device_class, cls):
- """Register a subclass of DevController to handle the named device-class.
+ if self.store_mfn:
+ sxpr.append(['store_mfn', self.store_mfn])
+ if self.console_mfn:
+ sxpr.append(['console_mfn', self.console_mfn])
"""
- cls.deviceClass = device_class
- controllerClasses[device_class] = cls
-
-
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif
-from xen.xend.server.BlktapController import BlktapController
-addControllerClass('vbd', blkif.BlkifController)
-addControllerClass('vif', netif.NetifController)
-addControllerClass('vtpm', tpmif.TPMifController)
-addControllerClass('pci', pciif.PciController)
-addControllerClass('ioports', iopif.IOPortsController)
-addControllerClass('irq', irqif.IRQController)
-addControllerClass('usb', usbif.UsbifController)
-addControllerClass('tap', BlktapController)
+
+ def __str__(self):
+ return '<domain id=%s name=%s memory=%s state=%s>' % \
+ (str(self.domid), self.info['name'],
+ str(self.info['memory']), DOM_STATES[self.state])
+
+ __repr__ = __str__
+
diff --git a/tools/python/xen/xend/XendError.py b/tools/python/xen/xend/XendError.py
index f78a71f031..5947145267 100644
--- a/tools/python/xen/xend/XendError.py
+++ b/tools/python/xen/xend/XendError.py
@@ -34,6 +34,20 @@ class XendError(Fault):
class VmError(XendError):
"""Vm construction error."""
-
pass
+
+XEND_ERROR_AUTHENTICATION_FAILED = ('ELUSER', 'Authentication Failed')
+XEND_ERROR_SESSION_INVALID = ('EPERMDENIED', 'Session Invalid')
+XEND_ERROR_DOMAIN_INVALID = ('EINVALIDDOMAIN', 'Domain Invalid')
+XEND_ERROR_HOST_INVALID = ('EINVALIDHOST', 'Host Invalid')
+XEND_ERROR_HOST_RUNNING = ('EHOSTRUNNING', 'Host is still Running')
+XEND_ERROR_HOST_CPU_INVALID = ('EHOSTCPUINVALID', 'Host CPU Invalid')
+XEND_ERROR_UNSUPPORTED = ('EUNSUPPORTED', 'Method Unsupported')
+XEND_ERROR_VM_INVALID = ('EVMINVALID', 'VM Invalid')
+XEND_ERROR_VBD_INVALID = ('EVBDINVALID', 'VBD Invalid')
+XEND_ERROR_VIF_INVALID = ('EVIFINVALID', 'VIF Invalid')
+XEND_ERROR_VTPM_INVALID = ('EVTPMINVALID', 'VTPM Invalid')
+XEND_ERROR_VDI_INVALID = ('EVDIINVALID', 'VDI Invalid')
+XEND_ERROR_SR_INVALID = ('ESRINVALID', 'SR Invalid')
+XEND_ERROR_TODO = ('ETODO', 'Lazy Programmer Error')
diff --git a/tools/python/xen/xend/XendNode.py b/tools/python/xen/xend/XendNode.py
index 54cb30628a..8850a71ce3 100644
--- a/tools/python/xen/xend/XendNode.py
+++ b/tools/python/xen/xend/XendNode.py
@@ -13,22 +13,40 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (c) 2006 Xensource Inc.
#============================================================================
-"""Handler for node operations.
- Has some persistent state:
- - logs
- - notification urls
-
-"""
-
import os
+import socket
import xen.lowlevel.xc
+from xen.xend import uuid
+from xen.xend.XendError import XendError
+from xen.xend.XendStorageRepository import XendStorageRepository
class XendNode:
-
+ """XendNode - Represents a Domain 0 Host."""
+
def __init__(self):
self.xc = xen.lowlevel.xc.xc()
+ self.uuid = uuid.createString()
+ self.cpus = {}
+ self.name = socket.gethostname()
+ self.desc = ""
+ self.sr = XendStorageRepository()
+
+ physinfo = self.physinfo_dict()
+ cpu_count = physinfo['nr_cpus']
+ cpu_features = physinfo['hw_caps']
+
+ for i in range(cpu_count):
+ # construct uuid by appending extra bit on the host.
+ # since CPUs belong to a host.
+ cpu_uuid = self.uuid + '-%04d' % i
+ cpu_info = {'uuid': cpu_uuid,
+ 'host': self.uuid,
+ 'number': i,
+ 'features': cpu_features}
+ self.cpus[cpu_uuid] = cpu_info
def shutdown(self):
return 0
@@ -39,6 +57,88 @@ class XendNode:
def notify(self, _):
return 0
+ #
+ # Ref validation
+ #
+
+ def is_valid_host(self, host_ref):
+ return (host_ref == self.uuid)
+
+ def is_valid_cpu(self, cpu_ref):
+ return (cpu_ref in self.cpus)
+
+ #
+ # Storage Repo
+ #
+
+ def get_sr(self):
+ return self.sr
+
+ #
+ # Host Functions
+ #
+
+ def xen_version(self):
+ info = self.xc.xeninfo()
+ try:
+ from xen import VERSION
+ return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
+ 'Xend': VERSION}
+ except (ImportError, AttributeError):
+ return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
+ 'Xend': '3.0.3'}
+
+ def get_name(self):
+ return self.name
+
+ def set_name(self, new_name):
+ self.name = new_name
+
+ def get_description(self):
+ return self.desc
+
+ def set_description(self, new_desc):
+ self.desc = new_desc
+
+ #
+ # Host CPU Functions
+ #
+
+ def get_host_cpu_by_uuid(self, host_cpu_uuid):
+ if host_cpu_uuid in self.cpus:
+ return host_cpu_uuid
+ raise XendError('Invalid CPU UUID')
+
+ def get_host_cpu_refs(self):
+ return self.cpus.keys()
+
+ def get_host_cpu_uuid(self, host_cpu_ref):
+ if host_cpu_ref in self.cpus:
+ return host_cpu_ref
+ else:
+ raise XendError('Invalid CPU Reference')
+
+ def get_host_cpu_features(self, host_cpu_ref):
+ try:
+ return self.cpus[host_cpu_ref]['features']
+ except KeyError:
+ raise XendError('Invalid CPU Reference')
+
+ def get_host_cpu_number(self, host_cpu_ref):
+ try:
+ return self.cpus[host_cpu_ref]['number']
+ except KeyError:
+ raise XendError('Invalid CPU Reference')
+
+ def get_host_cpu_load(self, host_cpu_ref):
+ return 0.0
+
+
+
+ #
+ # Getting host information.
+ #
+
def info(self):
return (self.nodeinfo() + self.physinfo() + self.xeninfo() +
self.xendinfo())
@@ -96,8 +196,21 @@ class XendNode:
return [[k, info[k]] for k in ITEM_ORDER]
def xendinfo(self):
- return [['xend_config_format', 2]]
-
+ return [['xend_config_format', 3]]
+
+ # dictionary version of *info() functions to get rid of
+ # SXPisms.
+ def nodeinfo_dict(self):
+ return dict(self.nodeinfo())
+ def xendinfo_dict(self):
+ return dict(self.xendinfo())
+ def xeninfo_dict(self):
+ return dict(self.xeninfo())
+ def physinfo_dict(self):
+ return dict(self.physinfo())
+ def info_dict(self):
+ return dict(self.info())
+
def instance():
global inst
diff --git a/tools/python/xen/xend/XendProtocol.py b/tools/python/xen/xend/XendProtocol.py
index cb1e0f7f99..f09f6762d3 100644
--- a/tools/python/xen/xend/XendProtocol.py
+++ b/tools/python/xen/xend/XendProtocol.py
@@ -22,7 +22,7 @@ import time
import types
from encode import *
-import sxp
+from xen.xend import sxp
from xen.xend import XendRoot
diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py
index 6e87dc6274..baeb8afd4c 100644
--- a/tools/python/xen/xend/XendRoot.py
+++ b/tools/python/xen/xend/XendRoot.py
@@ -30,11 +30,8 @@ import os.path
import string
import sys
-import XendLogging
-from XendError import XendError
-
-import sxp
-
+from xen.xend import sxp, osdep, XendLogging
+from xen.xend.XendError import XendError
class XendRoot:
"""Root of the management classes."""
@@ -46,10 +43,10 @@ class XendRoot:
config_var = "XEND_CONFIG"
"""Where network control scripts live."""
- network_script_dir = "/etc/xen/scripts"
+ network_script_dir = osdep.scripts_dir
"""Where block control scripts live."""
- block_script_dir = "/etc/xen/scripts"
+ block_script_dir = osdep.scripts_dir
"""Default path to the log file. """
logfile_default = "/var/log/xen/xend.log"
@@ -57,6 +54,9 @@ class XendRoot:
"""Default level of information to be logged."""
loglevel_default = 'DEBUG'
+ """Default Xen-API server configuration. """
+ xen_api_server_default = [['unix']]
+
"""Default for the flag indicating whether xend should run an http server
(deprecated)."""
xend_http_server_default = 'no'
@@ -96,6 +96,14 @@ class XendRoot:
dom0_vcpus_default = '0'
+ vncpasswd_default = None
+
+ """Default interface to listen for VNC connections on"""
+ xend_vnc_listen_default = '127.0.0.1'
+
+ """Default session storage path."""
+ xend_domains_path_default = '/var/lib/xend/domains'
+
components = {}
def __init__(self):
@@ -184,21 +192,30 @@ class XendRoot:
except Exception:
raise XendError("invalid xend config %s: expected int: %s" % (name, v))
+ def get_xen_api_server(self):
+ """Get the Xen-API server configuration.
+ """
+ return self.get_config_value('xen-api-server',
+ self.xen_api_server_default)
+
def get_xend_http_server(self):
"""Get the flag indicating whether xend should run an http server.
"""
return self.get_config_bool("xend-http-server", self.xend_http_server_default)
def get_xend_tcp_xmlrpc_server(self):
- return self.get_config_bool("xend-tcp-xmlrpc-server", self.xend_tcp_xmlrpc_server_default)
+ return self.get_config_bool("xend-tcp-xmlrpc-server",
+ self.xend_tcp_xmlrpc_server_default)
def get_xend_unix_xmlrpc_server(self):
- return self.get_config_bool("xend-unix-xmlrpc-server", self.xend_unix_xmlrpc_server_default)
+ return self.get_config_bool("xend-unix-xmlrpc-server",
+ self.xend_unix_xmlrpc_server_default)
def get_xend_relocation_server(self):
"""Get the flag indicating whether xend should run a relocation server.
"""
- return self.get_config_bool("xend-relocation-server", self.xend_relocation_server_default)
+ return self.get_config_bool("xend-relocation-server",
+ self.xend_relocation_server_default)
def get_xend_port(self):
"""Get the port xend listens at for its HTTP interface.
@@ -208,7 +225,8 @@ class XendRoot:
def get_xend_relocation_port(self):
"""Get the port xend listens at for connection to its relocation server.
"""
- return self.get_config_int('xend-relocation-port', self.xend_relocation_port_default)
+ return self.get_config_int('xend-relocation-port',
+ self.xend_relocation_port_default)
def get_xend_relocation_hosts_allow(self):
return self.get_config_value("xend-relocation-hosts-allow",
@@ -240,6 +258,11 @@ class XendRoot:
"""
return self.get_config_value("xend-unix-path", self.xend_unix_path_default)
+ def get_xend_domains_path(self):
+ """ Get the path for persistent domain configuration storage
+ """
+ return self.get_config_value("xend-domains-path", self.xend_domains_path_default)
+
def get_network_script(self):
"""@return the script used to alter the network configuration when
Xend starts and stops, or None if no such script is specified."""
@@ -272,6 +295,13 @@ class XendRoot:
def get_console_limit(self):
return self.get_config_int('console-limit', 1024)
+ def get_vnclisten_address(self):
+ return self.get_config_value('vnc-listen', self.xend_vnc_listen_default)
+
+ def get_vncpasswd_default(self):
+ return self.get_config_value('vncpasswd',
+ self.vncpasswd_default)
+
def instance():
"""Get an instance of XendRoot.
Use this instead of the constructor.
diff --git a/tools/python/xen/xend/XendStorageRepository.py b/tools/python/xen/xend/XendStorageRepository.py
new file mode 100644
index 0000000000..d906f5b5fd
--- /dev/null
+++ b/tools/python/xen/xend/XendStorageRepository.py
@@ -0,0 +1,358 @@
+#!/usr/bin/python
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+#
+# The default QCOW Xen API Storage Repository
+#
+
+import os
+import commands
+import threading
+
+from xen.xend import uuid
+from xen.xend.XendError import XendError
+from xen.xend.XendVDI import *
+
+XEND_STORAGE_MAX_IGNORE = -1
+XEND_STORAGE_DIR = "/var/lib/xend/storage/"
+XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
+XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
+QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create %d %s"
+
+MB = 1024 *1024
+
+class DeviceInvalidError(Exception):
+ pass
+
+class XendStorageRepository:
+ """A simple file backed QCOW Storage Repository.
+
+ This class exposes the interface to create VDI's via the
+ Xen API. The backend is a file-backed QCOW format that is stored
+ in XEND_STORAGE_DIR or any that is specified in the constructor.
+
+ The actual images are created in the format <uuid>.img and <uuid>.qcow.
+ """
+
+ def __init__(self, storage_dir = XEND_STORAGE_DIR,
+ storage_max = XEND_STORAGE_MAX_IGNORE):
+ """
+ @keyword storage_dir: Where the images will be stored.
+ @type storage_dir: string
+ @keyword storage_max: Maximum disk space to use in bytes.
+ @type storage_max: int
+
+ @ivar storage_free: storage space free for this repository
+ @ivar images: mapping of all the images.
+ @type images: dictionary by image uuid.
+ @ivar lock: lock to provide thread safety.
+ """
+
+ self.storage_dir = storage_dir
+ self.storage_max = storage_max
+ self.storage_free = 0
+ self.images = {}
+
+ # XenAPI Parameters
+ self.uuid = self._sr_uuid()
+ self.type = "qcow-file"
+ self.location = self.storage_dir
+ self.name_label = "Local"
+ self.name_description = "Xend Storage Repository"
+
+ self.lock = threading.RLock()
+ self._refresh()
+
+ def _sr_uuid(self):
+ uuid_file = os.path.join(XEND_STORAGE_DIR, 'uuid')
+ try:
+ if uuid_file and os.path.exists(uuid_file):
+ return open(uuid_file, 'r').read().strip()
+ else:
+ new_uuid = uuid.createString()
+ open(uuid_file, 'w').write(new_uuid + '\n')
+ return new_uuid
+ except IOError:
+ # TODO: log warning
+ pass
+
+ return uuid.createString()
+
+ def _refresh(self):
+ """Internal function that refreshes the state of the disk and
+ updates the list of images available.
+ """
+ self.lock.acquire()
+ try:
+ # create directory if /var/lib/xend/storage does not exist
+ if not os.path.exists(XEND_STORAGE_DIR):
+ os.makedirs(XEND_STORAGE_DIR)
+ os.chmod(XEND_STORAGE_DIR, 0700)
+
+ # scan the directory and populate self.images
+ total_used = 0
+ seen_images = []
+ for filename in os.listdir(XEND_STORAGE_DIR):
+ if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
+ image_uuid = filename[:-5]
+ seen_images.append(image_uuid)
+
+ # add this image if we haven't seen it before
+ if image_uuid not in self.images:
+ qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
+ cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
+ qcow_path = os.path.join(XEND_STORAGE_DIR, qcow_file)
+ cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_file)
+
+ qcow_size = os.stat(qcow_path).st_size
+
+ # TODO: no way to stat virtual size of qcow
+ vdi = XendQCOWVDI(image_uuid, self.uuid,
+ qcow_path, cfg_path,
+ qcow_size, qcow_size)
+
+ if cfg_path and os.path.exists(cfg_path):
+ vdi.load_config(cfg_path)
+
+ self.images[image_uuid] = vdi
+ total_used += qcow_size
+
+ # remove images that aren't valid
+ for image_uuid in self.images.keys():
+ if image_uuid not in seen_images:
+ try:
+ os.unlink(self.images[image_uuid].qcow_path)
+ except OSError:
+ pass
+ del self.images[image_uuid]
+
+ # update free storage if we have to track that
+ if self.storage_max != XEND_STORAGE_MAX_IGNORE:
+ self.storage_free = self.storage_max - total_used
+ else:
+ self.storage_free = self._get_free_space()
+
+ finally:
+ self.lock.release()
+
+ def _get_free_space(self):
+ """Returns the amount of free space in bytes available in the storage
+ partition. Note that this may not be used if the storage repository
+ is initialised with a maximum size in storage_max.
+
+ @rtype: int
+ """
+ stfs = os.statvfs(self.storage_dir)
+ return stfs.f_bavail * stfs.f_frsize
+
+ def _has_space_available_for(self, size_bytes):
+ """Returns whether there is enough space for an image in the
+ partition which the storage_dir resides on.
+
+ @rtype: bool
+ """
+ if self.storage_max != -1:
+ return self.storage_free
+
+ bytes_free = self._get_free_space()
+ try:
+ if size_bytes < bytes_free:
+ return True
+ except DeviceInvalidError:
+ pass
+ return False
+
+ def _create_image_files(self, desired_size_bytes):
+ """Create an image and return its assigned UUID.
+
+ @param desired_size_kb: Desired image size in KB.
+ @type desired_size_kb: int
+ @rtype: string
+ @return: uuid
+
+ @raises XendError: If an error occurs.
+ """
+ self.lock.acquire()
+ try:
+ if not self._has_space_available_for(desired_size_bytes):
+ raise XendError("Not enough space")
+
+ image_uuid = uuid.createString()
+ qcow_path = os.path.join(XEND_STORAGE_DIR,
+ XEND_STORAGE_QCOW_FILENAME % image_uuid)
+
+ if qcow_path and os.path.exists(qcow_path):
+ raise XendError("Image with same UUID alreaady exists:" %
+ image_uuid)
+
+ cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)
+ rc, output = commands.getstatusoutput(cmd)
+
+ if rc != 0:
+ # cleanup the image file
+ os.unlink(qcow_path)
+ raise XendError("Failed to create QCOW Image: %s" % output)
+
+ self._refresh()
+ return image_uuid
+ finally:
+ self.lock.release()
+
+ def destroy_image(self, image_uuid):
+ """Destroy an image that is managed by this storage repository.
+
+ @param image_uuid: Image UUID
+ @type image_uuid: String
+ @rtype: String
+ """
+ self.lock.acquire()
+ try:
+ if image_uuid in self.images:
+ # TODO: check if it is being used?
+ qcow_path = self.images[image_uuid].qcow_path
+ cfg_path = self.images[image_uuid].cfg_path
+ try:
+ os.unlink(qcow_path)
+ if cfg_path and os.path.exists(cfg_path):
+ os.unlink(cfg_path)
+ except OSError:
+ # TODO: log warning
+ pass
+ del self.images[image_uuid]
+ return True
+ finally:
+ self.lock.release()
+
+ return False
+
+ def list_images(self):
+ """ List all the available images by UUID.
+
+ @rtype: list of strings.
+ @return: list of UUIDs
+ """
+ self.lock.acquire()
+ try:
+ return self.images.keys()
+ finally:
+ self.lock.release()
+
+ def free_space_bytes(self):
+ """Returns the amount of available space in KB.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ return self.storage_free
+ finally:
+ self.lock.release()
+
+ def total_space_bytes(self):
+ """Returns the total usable space of the storage repo in KB.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ if self.storage_max != XEND_STORAGE_MAX_IGNORE:
+ return self.storage_max
+ else:
+ return self.free_space_bytes() + self.used_space_bytes()
+ finally:
+ self.lock.release()
+
+ def used_space_bytes(self):
+ """Returns the total amount of space used by this storage repository.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ total_used = 0
+ for val in self.images.values():
+ total_used += val.physical_utilisation
+ return total_used
+ finally:
+ self.lock.release()
+
+ def is_valid_vdi(self, vdi_uuid):
+ return (vdi_uuid in self.images)
+
+ def create_image(self, vdi_struct):
+ image_uuid = None
+ try:
+ sector_count = int(vdi_struct.get('virtual_size', 0))
+ sector_size = int(vdi_struct.get('sector_size', 1024))
+ size_bytes = (sector_count * sector_size)
+
+ image_uuid = self._create_image_files(size_bytes)
+ image = self.images[image_uuid]
+ image_cfg = {
+ 'sector_size': sector_size,
+ 'virtual_size': sector_count,
+ 'type': vdi_struct.get('type', 'system'),
+ 'name_label': vdi_struct.get('name_label', ''),
+ 'name_description': vdi_struct.get('name_description', ''),
+ 'sharable': bool(vdi_struct.get('sharable', False)),
+ 'read_only': bool(vdi_struct.get('read_only', False)),
+ }
+
+ # load in configuration from vdi_struct
+ image.load_config_dict(image_cfg)
+
+ # save configuration to file
+ cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
+ cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_filename)
+ image.save_config(cfg_path)
+
+ except Exception, e:
+ # cleanup before raising exception
+ if image_uuid:
+ self.destroy_image(image_uuid)
+
+ raise
+
+ return image_uuid
+
+ def xen_api_get_by_label(self, label):
+ self.lock.acquire()
+ try:
+ for image_uuid, val in self.images.values():
+ if val.name_label == label:
+ return image_uuid
+ return None
+ finally:
+ self.lock.release()
+
+ def xen_api_get_by_uuid(self, image_uuid):
+ self.lock.acquire()
+ try:
+ return self.images.get(image_uuid)
+ finally:
+ self.lock.release()
+
+
+# remove everything below this line!!
+if __name__ == "__main__":
+ xsr = XendStorageRepository()
+ print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
+ print "Create Image:",
+ print xsr._create_image_files(10 * MB)
+ print 'Delete all images:'
+ for image_uuid in xsr.list_images():
+ print image_uuid,
+ xsr._destroy_image_files(image_uuid)
+
+ print
diff --git a/tools/python/xen/xend/XendVDI.py b/tools/python/xen/xend/XendVDI.py
new file mode 100644
index 0000000000..22a1616360
--- /dev/null
+++ b/tools/python/xen/xend/XendVDI.py
@@ -0,0 +1,155 @@
+#!/usr/bin/python
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd.
+#============================================================================
+#
+# Representation of a Xen API VDI
+#
+
+import os
+
+from xen.util.xmlrpclib2 import stringify
+from xmlrpclib import dumps, loads
+
+KB = 1024
+MB = 1024 * 1024
+
+class AutoSaveObject(object):
+
+ def __init__(self):
+ self.cfg_path = None
+ self.auto_save = True
+ object
+
+ def save_config(self, cfg_file = None):
+ raise NotImplementedError()
+
+ def __setattr__(self, name, value):
+ """A very simple way of making sure all attribute changes are
+ flushed to disk.
+ """
+ object.__setattr__(self, name, value)
+ if name != 'auto_save' and getattr(self, 'auto_save', False):
+ self.save_config()
+
+class XendVDI(AutoSaveObject):
+ """Generic Xen API compatible VDI representation.
+
+ @cvar SAVED_CFG: list of configuration attributes to save.
+ @cvar SAVED_CFG_INT: list of configurations that should be ints.
+ """
+
+ SAVED_CFG = ['name_label',
+ 'name_description',
+ 'sector_size',
+ 'virtual_size',
+ 'physical_utilisation',
+ 'parent',
+ 'children',
+ 'sharable',
+ 'read_only']
+
+ SAVED_CFG_INT = ['sector_size', 'virtual_size', 'physical_utilisation']
+
+ def __init__(self, uuid, sr_uuid):
+ self.uuid = uuid
+ self.sr_uuid = sr_uuid
+ self.name_label = ""
+ self.name_description = ""
+ self.sector_size = 1024
+ self.virtual_size = 0
+ self.physical_utilisation = 0
+ self.parent = None
+ self.children = []
+ self.sharable = False
+ self.read_only = False
+ self.type = "system"
+
+ def load_config_dict(self, cfg):
+ """Loads configuration into the object from a dict.
+
+ @param cfg: configuration dict
+ @type cfg: dict
+ """
+ self.auto_save = False
+ for key in self.SAVED_CFG:
+ if key in cfg:
+ if key in self.SAVED_CFG_INT:
+ setattr(self, key, int(cfg[key]))
+ else:
+ setattr(self, key, cfg[key])
+ self.auto_save = True
+
+ def load_config(self, cfg_path):
+ """Loads configuration from an XMLRPC parameter format.
+
+ @param cfg_path: configuration file path
+ @type cfg_path: type
+ @rtype: bool
+ @return: Successful or not.
+ """
+ try:
+ cfg, _ = loads(open(cfg_path).read())
+ cfg = cfg[0]
+ self.load_config_dict(cfg)
+ self.cfg_path = cfg_path
+ except IOError, e:
+ return False
+
+ return True
+
+ def save_config(self, cfg_path = None):
+ """Saves configuration at give path in XMLRPC parameter format.
+
+ If cfg_path is not give, it defaults to the where the VDI
+ configuration as loaded if it load_config was called.
+
+ @keyword cfg_path: optional configuration file path
+ @rtype: bool
+ @return: Successful or not.
+ """
+ try:
+ if not cfg_path and not self.cfg_path:
+ return False
+
+ if not cfg_path:
+ cfg_path = self.cfg_path
+
+ cfg = {}
+ for key in self.SAVED_CFG:
+ try:
+ cfg[key] = getattr(self, key)
+ except AttributeError:
+ pass
+ open(cfg_path, 'w').write(dumps((stringify(cfg),),
+ allow_none = True))
+ except IOError, e:
+ return False
+
+ return True
+
+class XendQCOWVDI(XendVDI):
+
+ def __init__(self, uuid, sr_uuid, qcow_path, cfg_path, vsize, psize):
+ XendVDI.__init__(self, uuid, sr_uuid)
+ self.auto_save = False
+ self.qcow_path = qcow_path
+ self.cfg_path = cfg_path
+ self.physical_utilisation = psize
+ self.virtual_size = vsize
+ self.sector_size = 512
+ self.auto_save = True
+
diff --git a/tools/python/xen/xend/arch.py b/tools/python/xen/xend/arch.py
index 85e6547401..a556c0e6cf 100644
--- a/tools/python/xen/xend/arch.py
+++ b/tools/python/xen/xend/arch.py
@@ -25,6 +25,7 @@ _types = {
"i586": "x86",
"i686": "x86",
"x86_64": "x86",
+ "i86pc": "x86",
"ia64": "ia64",
"ppc": "powerpc",
"ppc64": "powerpc",
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index 941e01749f..546e6eca38 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -20,10 +20,11 @@
import os, string
import re
import math
+import signal
import xen.lowlevel.xc
from xen.xend import sxp
-from xen.xend.XendError import VmError
+from xen.xend.XendError import VmError, XendError
from xen.xend.XendLogging import log
from xen.xend.server.netif import randomMAC
from xen.xend.xenstore.xswatch import xswatch
@@ -151,13 +152,13 @@ class ImageHandler:
necessary."""
return mem_kb
- def getRequiredInitialReservation(self, mem_kb):
+ def getRequiredInitialReservation(self):
"""@param mem_kb The configured memory, in KiB.
@return The corresponding required amount of memory to be free, also
in KiB. This is normally the same as getRequiredAvailableMemory, but
architecture- or image-specific code may override this to
add headroom where necessary."""
- return self.getRequiredAvailableMemory(mem_kb)
+ return self.getRequiredAvailableMemory(self.vm.getMemoryTarget())
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
"""@param shadow_mem_kb The configured shadow memory, in KiB.
@@ -188,7 +189,10 @@ class LinuxImageHandler(ImageHandler):
store_evtchn = self.vm.getStorePort()
console_evtchn = self.vm.getConsolePort()
- log.debug("dom = %d", self.vm.getDomid())
+ mem_mb = self.getRequiredInitialReservation() / 1024
+
+ log.debug("domid = %d", self.vm.getDomid())
+ log.debug("memsize = %d", mem_mb)
log.debug("image = %s", self.kernel)
log.debug("store_evtchn = %d", store_evtchn)
log.debug("console_evtchn = %d", console_evtchn)
@@ -197,7 +201,8 @@ class LinuxImageHandler(ImageHandler):
log.debug("vcpus = %d", self.vm.getVCpuCount())
log.debug("features = %s", self.vm.getFeatures())
- return xc.linux_build(dom = self.vm.getDomid(),
+ return xc.linux_build(domid = self.vm.getDomid(),
+ memsize = mem_mb,
image = self.kernel,
store_evtchn = store_evtchn,
console_evtchn = console_evtchn,
@@ -217,7 +222,10 @@ class PPC_LinuxImageHandler(LinuxImageHandler):
store_evtchn = self.vm.getStorePort()
console_evtchn = self.vm.getConsolePort()
- log.debug("dom = %d", self.vm.getDomid())
+ mem_mb = self.getRequiredInitialReservation() / 1024
+
+ log.debug("domid = %d", self.vm.getDomid())
+ log.debug("memsize = %d", mem_mb)
log.debug("image = %s", self.kernel)
log.debug("store_evtchn = %d", store_evtchn)
log.debug("console_evtchn = %d", console_evtchn)
@@ -228,7 +236,8 @@ class PPC_LinuxImageHandler(LinuxImageHandler):
devtree = FlatDeviceTree.build(self)
- return xc.linux_build(dom = self.vm.getDomid(),
+ return xc.linux_build(domid = self.vm.getDomid(),
+ memsize = mem_mb,
image = self.kernel,
store_evtchn = store_evtchn,
console_evtchn = console_evtchn,
@@ -239,12 +248,17 @@ class PPC_LinuxImageHandler(LinuxImageHandler):
class HVMImageHandler(ImageHandler):
+ def __init__(self, vm, imageConfig, deviceConfig):
+ ImageHandler.__init__(self, vm, imageConfig, deviceConfig)
+ self.shutdownWatch = None
+
def configure(self, imageConfig, deviceConfig):
ImageHandler.configure(self, imageConfig, deviceConfig)
info = xc.xeninfo()
if not 'hvm' in info['xen_caps']:
- raise VmError("Not an HVM capable platform, we stop creating!")
+ raise VmError("HVM guest support is unavailable: is VT/AMD-V "
+ "supported by your CPU and enabled in your BIOS?")
self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
self.device_model = sxp.child_value(imageConfig, 'device_model')
@@ -262,18 +276,19 @@ class HVMImageHandler(ImageHandler):
self.dmargs += self.configVNC(imageConfig)
- self.pae = int(sxp.child_value(imageConfig, 'pae', 0))
-
- self.acpi = int(sxp.child_value(imageConfig, 'acpi', 0))
- self.apic = int(sxp.child_value(imageConfig, 'apic', 0))
+ self.pae = int(sxp.child_value(imageConfig, 'pae', 1))
+ self.acpi = int(sxp.child_value(imageConfig, 'acpi', 1))
+ self.apic = int(sxp.child_value(imageConfig, 'apic', 1))
def buildDomain(self):
store_evtchn = self.vm.getStorePort()
- log.debug("dom = %d", self.vm.getDomid())
+ mem_mb = self.getRequiredInitialReservation() / 1024
+
+ log.debug("domid = %d", self.vm.getDomid())
log.debug("image = %s", self.kernel)
log.debug("store_evtchn = %d", store_evtchn)
- log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
+ log.debug("memsize = %d", mem_mb)
log.debug("vcpus = %d", self.vm.getVCpuCount())
log.debug("pae = %d", self.pae)
log.debug("acpi = %d", self.acpi)
@@ -281,10 +296,10 @@ class HVMImageHandler(ImageHandler):
self.register_shutdown_watch()
- return xc.hvm_build(dom = self.vm.getDomid(),
+ return xc.hvm_build(domid = self.vm.getDomid(),
image = self.kernel,
store_evtchn = store_evtchn,
- memsize = self.vm.getMemoryTarget() / 1024,
+ memsize = mem_mb,
vcpus = self.vm.getVCpuCount(),
pae = self.pae,
acpi = self.acpi,
@@ -295,13 +310,14 @@ class HVMImageHandler(ImageHandler):
def parseDeviceModelArgs(self, imageConfig, deviceConfig):
dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
'localtime', 'serial', 'stdvga', 'isa', 'vcpus',
- 'acpi', 'usb', 'usbdevice']
+ 'acpi', 'usb', 'usbdevice', 'keymap' ]
ret = []
for a in dmargs:
v = sxp.child_value(imageConfig, a)
# python doesn't allow '-' in variable names
if a == 'stdvga': a = 'std-vga'
+ if a == 'keymap': a = 'k'
# Handle booleans gracefully
if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']:
@@ -311,6 +327,11 @@ class HVMImageHandler(ImageHandler):
if v:
ret.append("-%s" % a)
ret.append("%s" % v)
+
+ if a in ['fda', 'fdb' ]:
+ if v:
+ if not os.path.isabs(v):
+ raise VmError("Floppy file %s does not exist." % v)
log.debug("args: %s, val: %s" % (a,v))
# Handle disk/network related options
@@ -340,10 +361,6 @@ class HVMImageHandler(ImageHandler):
(nics, mac, model))
ret.append("-net")
ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
- if name == 'vtpm':
- instance = sxp.child_value(info, 'pref_instance')
- ret.append("-instance")
- ret.append("%s" % instance)
return ret
def configVNC(self, config):
@@ -352,16 +369,41 @@ class HVMImageHandler(ImageHandler):
sdl = sxp.child_value(config, 'sdl')
ret = []
nographic = sxp.child_value(config, 'nographic')
+
+ # get password from VM config (if password omitted, None)
+ vncpasswd_vmconfig = sxp.child_value(config, 'vncpasswd')
+
if nographic:
ret.append('-nographic')
return ret
+
if vnc:
- vncdisplay = sxp.child_value(config, 'vncdisplay',
- int(self.vm.getDomid()))
- ret = ret + ['-vnc', '%d' % vncdisplay, '-k', 'en-us']
+ vncdisplay = int(sxp.child_value(config, 'vncdisplay',
+ self.vm.getDomid()))
+
vncunused = sxp.child_value(config, 'vncunused')
if vncunused:
ret += ['-vncunused']
+ else:
+ ret += ['-vnc', '%d' % vncdisplay]
+
+ vnclisten = sxp.child_value(config, 'vnclisten')
+ if not(vnclisten):
+ vnclisten = (xen.xend.XendRoot.instance().
+ get_vnclisten_address())
+ if vnclisten:
+ ret += ['-vnclisten', vnclisten]
+
+ vncpasswd = vncpasswd_vmconfig
+ if vncpasswd is None:
+ vncpasswd = (xen.xend.XendRoot.instance().
+ get_vncpasswd_default())
+ if vncpasswd is None:
+ raise VmError('vncpasswd is not set up in ' +
+ 'VMconfig and xend-config.')
+ if vncpasswd != '':
+ self.vm.storeVm("vncpasswd", vncpasswd)
+
return ret
def createDeviceModel(self):
@@ -371,7 +413,7 @@ class HVMImageHandler(ImageHandler):
#todo: Error handling
args = [self.device_model]
args = args + ([ "-d", "%d" % self.vm.getDomid(),
- "-m", "%s" % (self.vm.getMemoryTarget() / 1024)])
+ "-m", "%s" % (self.getRequiredInitialReservation() / 1024)])
args = args + self.dmargs
env = dict(os.environ)
if self.display:
@@ -386,7 +428,6 @@ class HVMImageHandler(ImageHandler):
def destroy(self):
self.unregister_shutdown_watch();
- import signal
if not self.pid:
return
os.kill(self.pid, signal.SIGKILL)
@@ -415,14 +456,18 @@ class HVMImageHandler(ImageHandler):
""" watch call back on node control/shutdown,
if node changed, this function will be called
"""
- from xen.xend.XendDomainInfo import shutdown_reasons
+ from xen.xend.XendConstants import DOMAIN_SHUTDOWN_REASONS
xd = xen.xend.XendDomain.instance()
- vm = xd.domain_lookup( self.vm.getDomid() )
+ try:
+ vm = xd.domain_lookup( self.vm.getDomid() )
+ except XendError:
+ # domain isn't registered, no need to clean it up.
+ return
- reason = vm.readDom('control/shutdown')
+ reason = vm.getShutdownReason()
log.debug("hvm_shutdown fired, shutdown reason=%s", reason)
- for x in shutdown_reasons.keys():
- if shutdown_reasons[x] == reason:
+ for x in DOMAIN_SHUTDOWN_REASONS.keys():
+ if DOMAIN_SHUTDOWN_REASONS[x] == reason:
vm.info['shutdown'] = 1
vm.info['shutdown_reason'] = x
vm.refreshShutdown(vm.info)
@@ -436,7 +481,7 @@ class IA64_HVM_ImageHandler(HVMImageHandler):
def getRequiredAvailableMemory(self, mem_kb):
page_kb = 16
# ROM size for guest firmware, ioreq page and xenstore page
- extra_pages = 1024 + 2
+ extra_pages = 1024 + 3
return mem_kb + extra_pages * page_kb
def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
@@ -449,25 +494,18 @@ class X86_HVM_ImageHandler(HVMImageHandler):
def getRequiredAvailableMemory(self, mem_kb):
# Add 8 MiB overhead for QEMU's video RAM.
- return self.getRequiredInitialReservation(mem_kb) + 8192
-
- def getRequiredInitialReservation(self, mem_kb):
- page_kb = 4
- # This was derived emperically:
- # 2.4 MB overhead per 1024 MB RAM
- # + 4 to avoid low-memory condition
- extra_mb = (2.4/1024) * (mem_kb/1024.0) + 4;
- extra_pages = int( math.ceil( extra_mb*1024 / page_kb ))
- return mem_kb + extra_pages * page_kb
+ return mem_kb + 8192
- def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
- # The given value is the configured value -- we need to include the
- # overhead due to getRequiredInitialReservation.
- maxmem_kb = self.getRequiredInitialReservation(maxmem_kb)
+ def getRequiredInitialReservation(self):
+ return self.vm.getMemoryTarget()
- # 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than
- # the minimum that Xen would allocate if no value were given.
- return max(1024 * self.vm.getVCpuCount() + maxmem_kb / 256,
+ def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb):
+ # 256 pages (1MB) per vcpu,
+ # plus 1 page per MiB of RAM for the P2M map,
+ # plus 1 page per MiB of RAM to shadow the resident processes.
+ # This is higher than the minimum that Xen would allocate if no value
+ # were given (but the Xen minimum is for safety, not performance).
+ return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)),
shadow_mem_kb)
diff --git a/tools/python/xen/xend/osdep.py b/tools/python/xen/xend/osdep.py
new file mode 100644
index 0000000000..35af7c55af
--- /dev/null
+++ b/tools/python/xen/xend/osdep.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+import os
+
+_scripts_dir = {
+ "Linux": "/etc/xen/scripts",
+ "SunOS": "/usr/lib/xen/scripts",
+}
+
+_xend_autorestart = {
+ "Linux": True,
+ "SunOS": False,
+}
+
+def _get(var, default=None):
+ return var.get(os.uname()[0], default)
+
+scripts_dir = _get(_scripts_dir, "/etc/xen/scripts")
+xend_autorestart = _get(_xend_autorestart)
diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py
index e90008dbc0..cbe3b18845 100644
--- a/tools/python/xen/xend/server/DevController.py
+++ b/tools/python/xen/xend/server/DevController.py
@@ -25,7 +25,7 @@ from xen.xend.XendLogging import log
from xen.xend.xenstore.xstransact import xstransact, complete
from xen.xend.xenstore.xswatch import xswatch
-DEVICE_CREATE_TIMEOUT = 10
+DEVICE_CREATE_TIMEOUT = 100
HOTPLUG_STATUS_NODE = "hotplug-status"
HOTPLUG_ERROR_NODE = "hotplug-error"
HOTPLUG_STATUS_ERROR = "error"
@@ -88,9 +88,9 @@ class DevController:
xd = xen.xend.XendDomain.instance()
backdom_name = sxp.child_value(config, 'backend')
if backdom_name is None:
- backdom = xen.xend.XendDomain.PRIV_DOMAIN
+ backdom = xen.xend.XendDomain.DOM0_ID
else:
- bd = xd.domain_lookup_by_name_or_id_nr(backdom_name)
+ bd = xd.domain_lookup_nr(backdom_name)
backdom = bd.getDomid()
count = 0
while True:
@@ -141,7 +141,6 @@ class DevController:
def waitForDevices(self):
log.debug("Waiting for devices %s.", self.deviceClass)
-
return map(self.waitForDevice, self.deviceIDs())
@@ -221,13 +220,15 @@ class DevController:
"""@return an s-expression giving the current configuration of the
specified device. This would be suitable for giving to {@link
#createDevice} in order to recreate that device."""
-
- backdomid = xstransact.Read(self.frontendPath(devid), "backend-id")
- if backdomid is None:
- raise VmError("Device %s not connected" % devid)
-
- return [self.deviceClass, ['backend', int(backdomid)]]
-
+ configDict = self.getDeviceConfiguration(devid)
+ sxpr = [self.deviceClass]
+ for key, val in configDict.items():
+ if type(val) == type(list()):
+ for v in val:
+ sxpr.append([key, v])
+ else:
+ sxpr.append([key, val])
+ return sxpr
def sxprs(self):
"""@return an s-expression describing all the devices of this
@@ -243,6 +244,25 @@ class DevController:
'id', devid]]
+ def getDeviceConfiguration(self, devid):
+ """Returns the configuration of a device.
+
+ @note: Similar to L{configuration} except it returns a dict.
+ @return: dict
+ """
+ backdomid = xstransact.Read(self.frontendPath(devid), "backend-id")
+ if backdomid is None:
+ raise VmError("Device %s not connected" % devid)
+
+ return {'backend': int(backdomid)}
+
+ def getAllDeviceConfigurations(self):
+ all_configs = {}
+ for devid in self.deviceIDs():
+ config_dict = self.getDeviceConfiguration(devid)
+ all_configs[devid] = config_dict
+ return all_configs
+
## protected:
def getDeviceDetails(self, config):
@@ -387,7 +407,7 @@ class DevController:
backdom_name = sxp.child_value(config, 'backend')
if backdom_name:
- backdom = xd.domain_lookup_by_name_or_id_nr(backdom_name)
+ backdom = xd.domain_lookup_nr(backdom_name)
else:
backdom = xd.privilegedDomain()
@@ -435,7 +455,9 @@ class DevController:
def backendPath(self, backdom, devid):
- """@param backdom [XendDomainInfo] The backend domain info."""
+ """Construct backend path given the backend domain and device id.
+
+ @param backdom [XendDomainInfo] The backend domain info."""
return "%s/backend/%s/%s/%d" % (backdom.getDomainPath(),
self.deviceClass,
@@ -450,10 +472,11 @@ class DevController:
return "%s/device/%s" % (self.vm.getDomainPath(), self.deviceClass)
def backendRoot(self):
- import xen.xend.XendDomain
- from xen.xend.xenstore.xsutil import GetDomainPath
- backdom = xen.xend.XendDomain.PRIV_DOMAIN
- return "%s/backend/%s/%s" % (GetDomainPath(backdom), self.deviceClass, self.vm.getDomid())
+ """Construct backend root path assuming backend is domain 0."""
+ from xen.xend.XendDomain import DOM0_ID
+ from xen.xend.xenstore.xsutil import GetDomainPath
+ return "%s/backend/%s/%s" % (GetDomainPath(DOM0_ID),
+ self.deviceClass, self.vm.getDomid())
def frontendMiscPath(self):
return "%s/device-misc/%s" % (self.vm.getDomainPath(),
diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py
index 3f3a90d15a..864c371552 100644
--- a/tools/python/xen/xend/server/SrvDaemon.py
+++ b/tools/python/xen/xend/server/SrvDaemon.py
@@ -9,6 +9,7 @@ import os
import signal
import sys
import threading
+import time
import linecache
import pwd
import re
@@ -17,6 +18,7 @@ import traceback
import xen.lowlevel.xc
from xen.xend.XendLogging import log
+from xen.xend import osdep
import relocate
import SrvServer
@@ -105,12 +107,14 @@ class Daemon:
os.close(2)
if XEND_DEBUG:
os.open('/dev/null', os.O_RDONLY)
- os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
+ os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND)
os.dup(1)
else:
os.open('/dev/null', os.O_RDWR)
os.dup(0)
- os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
+ os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND)
+ print >>sys.stderr, ("Xend started at %s." %
+ time.asctime(time.localtime()))
def start(self, trace=0):
@@ -168,8 +172,14 @@ class Daemon:
# ready to receive requests. All subsequent restarts we don't
# want this behaviour, or the pipe will eventually fill up, so
# we just pass None into run in subsequent cases (by clearing w
- # in the parent of the first fork).
+ # in the parent of the first fork). On some operating systems,
+ # restart is managed externally, so we won't fork, and just exit.
while True:
+
+ if not osdep.xend_autorestart:
+ self.run(os.fdopen(w, 'w'))
+ break
+
pid = self.fork_pid()
if pid:
if w is not None:
@@ -195,6 +205,8 @@ class Daemon:
sig)
else:
self.run(w and os.fdopen(w, 'w') or None)
+ # if we reach here, the child should quit.
+ os._exit(0)
return ret
@@ -287,9 +299,17 @@ class Daemon:
log.info("Xend changeset: %s.", xinfo['xen_changeset'])
del xc
+ try:
+ from xen import VERSION
+ log.info("Xend version: %s", VERSION)
+ except ImportError:
+ log.info("Xend version: Unknown.")
+
relocate.listenRelocation()
servers = SrvServer.create()
servers.start(status)
+ del servers
+
except Exception, ex:
print >>sys.stderr, 'Exception starting xend:', ex
if XEND_DEBUG:
diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py
index d369aa68ad..82998e4d98 100644
--- a/tools/python/xen/xend/server/SrvDomain.py
+++ b/tools/python/xen/xend/server/SrvDomain.py
@@ -82,6 +82,18 @@ class SrvDomain(SrvDir):
def do_save(self, _, req):
return self.xd.domain_save(self.dom.domid, req.args['file'][0])
+ def op_dump(self, op, req):
+ self.acceptCommand(req)
+ return req.threadRequest(self.do_dump, op, req)
+
+ def do_dump(self, _, req):
+ fn = FormFn(self.xd.domain_dump,
+ [['dom', 'int'],
+ ['file', 'str'],
+ ['live', 'int'],
+ ['crash', 'int']])
+ return fn(req.args, {'dom': self.dom.domid})
+
def op_migrate(self, op, req):
return req.threadRequest(self.do_migrate, op, req)
@@ -97,7 +109,7 @@ class SrvDomain(SrvDir):
def op_pincpu(self, _, req):
fn = FormFn(self.xd.domain_pincpu,
[['dom', 'int'],
- ['vcpu', 'int'],
+ ['vcpu', 'str'],
['cpumap', 'str']])
val = fn(req.args, {'dom': self.dom.domid})
return val
diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py
index d0bf999261..fe97b29aef 100644
--- a/tools/python/xen/xend/server/SrvDomainDir.py
+++ b/tools/python/xen/xend/server/SrvDomainDir.py
@@ -39,7 +39,7 @@ class SrvDomainDir(SrvDir):
self.xd = XendDomain.instance()
def domain(self, x):
- dom = self.xd.domain_lookup_by_name_or_id(x)
+ dom = self.xd.domain_lookup(x)
if not dom:
raise XendError('No such domain ' + str(x))
return SrvDomain(dom)
diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py
index 1826561db9..934e6d300b 100644
--- a/tools/python/xen/xend/server/SrvServer.py
+++ b/tools/python/xen/xend/server/SrvServer.py
@@ -41,20 +41,22 @@
# todo Support command-line args.
import fcntl
+import re
import time
+import signal
from threading import Thread
from xen.web.httpserver import HttpServer, UnixHttpServer
-from xen.xend import XendRoot
+from xen.xend import XendRoot, XendAPI
from xen.xend import Vifctl
from xen.xend.XendLogging import log
+from xen.xend.XendClient import XEN_API_SOCKET
from xen.web.SrvDir import SrvDir
from SrvRoot import SrvRoot
from XMLRPCServer import XMLRPCServer
-
xroot = XendRoot.instance()
@@ -62,10 +64,20 @@ class XendServers:
def __init__(self):
self.servers = []
+ self.cleaningUp = False
def add(self, server):
self.servers.append(server)
+ def cleanup(self, signum = 0, frame = None):
+ log.debug("SrvServer.cleanup()")
+ self.cleaningUp = True
+ for server in self.servers:
+ try:
+ server.shutdown()
+ except:
+ pass
+
def start(self, status):
# Running the network script will spawn another process, which takes
# the status fd with it unless we set FD_CLOEXEC. Failing to do this
@@ -76,7 +88,9 @@ class XendServers:
Vifctl.network('start')
threads = []
for server in self.servers:
- thread = Thread(target=server.run)
+ thread = Thread(target=server.run, name=server.__class__.__name__)
+ if isinstance(server, HttpServer):
+ thread.setDaemon(True)
thread.start()
threads.append(thread)
@@ -100,8 +114,28 @@ class XendServers:
status.write('0')
status.close()
- for t in threads:
- t.join()
+ # Prepare to catch SIGTERM (received when 'xend stop' is executed)
+ # and call each server's cleanup if possible
+ signal.signal(signal.SIGTERM, self.cleanup)
+
+ # Interruptible Thread.join - Python Bug #1167930
+ # Replaces: for t in threads: t.join()
+ # Reason: The above will cause python signal handlers to be
+ # blocked so we're not able to catch SIGTERM in any
+ # way for cleanup
+ runningThreads = threads
+ while len(runningThreads) > 0:
+ try:
+ for t in threads:
+ t.join(1.0)
+ runningThreads = [t for t in threads
+ if t.isAlive() and not t.isDaemon()]
+ if self.cleaningUp and len(runningThreads) > 0:
+ log.debug("Waiting for %s." %
+ [x.getName() for x in runningThreads])
+ except:
+ pass
+
def create():
root = SrvDir()
@@ -116,9 +150,42 @@ def create():
log.info('unix path=' + path)
servers.add(UnixHttpServer(root, path))
+ api_cfg = xroot.get_xen_api_server()
+ if api_cfg:
+ try:
+ addrs = [(str(x[0]).split(':'),
+ len(x) > 1 and x[1] or XendAPI.AUTH_NONE,
+ len(x) > 2 and x[2] and map(re.compile, x[2].split(" "))
+ or None)
+ for x in api_cfg]
+ for addrport, auth, allowed in addrs:
+ if auth not in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]:
+ log.error('Xen-API server configuration %s is invalid, ' +
+ 'as %s is not a valid authentication type.',
+ api_cfg, auth)
+ break
+
+ if len(addrport) == 1:
+ if addrport[0] == 'unix':
+ servers.add(XMLRPCServer(auth,
+ path = XEN_API_SOCKET,
+ hosts_allowed = allowed))
+ else:
+ servers.add(
+ XMLRPCServer(auth, True, '', int(addrport[0]),
+ hosts_allowed = allowed))
+ else:
+ addr, port = addrport
+ servers.add(XMLRPCServer(auth, True, addr, int(port),
+ hosts_allowed = allowed))
+ except ValueError, exn:
+ log.error('Xen-API server configuration %s is invalid.', api_cfg)
+ except TypeError, exn:
+ log.error('Xen-API server configuration %s is invalid.', api_cfg)
+
if xroot.get_xend_tcp_xmlrpc_server():
- servers.add(XMLRPCServer(True))
+ servers.add(XMLRPCServer(XendAPI.AUTH_PAM, True))
if xroot.get_xend_unix_xmlrpc_server():
- servers.add(XMLRPCServer())
+ servers.add(XMLRPCServer(XendAPI.AUTH_PAM))
return servers
diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py
index d075ec7e5e..45540995bd 100644
--- a/tools/python/xen/xend/server/XMLRPCServer.py
+++ b/tools/python/xen/xend/server/XMLRPCServer.py
@@ -16,56 +16,59 @@
# Copyright (C) 2006 XenSource Ltd.
#============================================================================
+import types
import xmlrpclib
-
-from xen.xend import XendDomain, XendDomainInfo, XendNode, \
- XendLogging, XendDmesg
from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer
-from xen.xend.XendClient import XML_RPC_SOCKET, ERROR_INVALID_DOMAIN
-from xen.xend.XendError import *
+from xen.xend import XendAPI, XendDomain, XendDomainInfo, XendNode
+from xen.xend import XendLogging, XendDmesg
+from xen.xend.XendClient import XML_RPC_SOCKET
+from xen.xend.XendConstants import DOM_STATE_RUNNING
from xen.xend.XendLogging import log
-from types import ListType
-
-def lookup(domid):
- info = XendDomain.instance().domain_lookup_by_name_or_id(domid)
- if not info:
- raise XendInvalidDomain(str(domid))
- return info
-
-def dispatch(domid, fn, args):
- info = lookup(domid)
- return getattr(info, fn)(*args)
+from xen.xend.XendError import XendInvalidDomain
# vcpu_avail is a long and is not needed by the clients. It's far easier
# to just remove it then to try and marshal the long.
def fixup_sxpr(sexpr):
ret = []
for k in sexpr:
- if type(k) is ListType:
+ if type(k) in (types.ListType, types.TupleType):
if len(k) != 2 or k[0] != 'vcpu_avail':
ret.append(fixup_sxpr(k))
else:
ret.append(k)
return ret
-def domain(domid):
+def lookup(domid):
+ info = XendDomain.instance().domain_lookup(domid)
+ if not info:
+ raise XendInvalidDomain(str(domid))
+ return info
+
+def dispatch(domid, fn, args):
info = lookup(domid)
- return fixup_sxpr(info.sxpr())
+ return getattr(info, fn)(*args)
+
+def domain(domid, full = 0):
+ info = lookup(domid)
+ return fixup_sxpr(info.sxpr(not full))
+
+def domains(detail = True, full = False):
+ return domains_with_state(detail, DOM_STATE_RUNNING, full)
-def domains(detail=1):
- if detail < 1:
- return XendDomain.instance().list_names()
+def domains_with_state(detail, state, full):
+ if detail:
+ domains = XendDomain.instance().list_sorted(state)
+ return map(lambda dom: fixup_sxpr(dom.sxpr(not full)), domains)
else:
- domains = XendDomain.instance().list_sorted()
- return map(lambda dom: fixup_sxpr(dom.sxpr()), domains)
+ return XendDomain.instance().list_names(state)
def domain_create(config):
info = XendDomain.instance().domain_create(config)
return fixup_sxpr(info.sxpr())
-def domain_restore(src):
- info = XendDomain.instance().domain_restore(src)
+def domain_restore(src, paused=False):
+ info = XendDomain.instance().domain_restore(src, paused)
return fixup_sxpr(info.sxpr())
def get_log():
@@ -75,8 +78,8 @@ def get_log():
finally:
f.close()
-methods = ['device_create', 'device_configure', 'destroyDevice',
- 'getDeviceSxprs',
+methods = ['device_create', 'device_configure',
+ 'destroyDevice','getDeviceSxprs',
'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
'send_sysrq', 'getVCPUInfo', 'waitForDevices',
'getRestartCount']
@@ -84,25 +87,59 @@ methods = ['device_create', 'device_configure', 'destroyDevice',
exclude = ['domain_create', 'domain_restore']
class XMLRPCServer:
- def __init__(self, use_tcp=False):
- self.ready = False
+ def __init__(self, auth, use_tcp=False, host = "localhost", port = 8006,
+ path = XML_RPC_SOCKET, hosts_allowed = None):
self.use_tcp = use_tcp
+ self.port = port
+ self.host = host
+ self.path = path
+ self.hosts_allowed = hosts_allowed
+
+ self.ready = False
+ self.running = True
+ self.auth = auth
+ self.xenapi = XendAPI.XendAPI(auth)
def run(self):
+ authmsg = (self.auth == XendAPI.AUTH_NONE and
+ "; authentication has been disabled for this server." or
+ ".")
+
if self.use_tcp:
- # bind to something fixed for now as we may eliminate
- # tcp support completely.
- self.server = TCPXMLRPCServer(("localhost", 8005), logRequests=False)
+ log.info("Opening TCP XML-RPC server on %s%d%s",
+ self.host and '%s:' % self.host or
+ 'all interfaces, port ',
+ self.port, authmsg)
+ self.server = TCPXMLRPCServer((self.host, self.port),
+ self.hosts_allowed,
+ logRequests = False)
else:
- self.server = UnixXMLRPCServer(XML_RPC_SOCKET, False)
+ log.info("Opening Unix domain socket XML-RPC server on %s%s",
+ self.path, authmsg)
+ self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
+ logRequests = False)
+
+
+ # Register Xen API Functions
+ # -------------------------------------------------------------------
+ # exportable functions are ones that do not begin with '_'
+ # and has the 'api' attribute.
+
+ for meth_name in dir(self.xenapi):
+ meth = getattr(self.xenapi, meth_name)
+ if meth_name[0] != '_' and callable(meth) and hasattr(meth, 'api'):
+ self.server.register_function(meth, getattr(meth, 'api'))
+
+ # Legacy deprecated xm xmlrpc api
+ # --------------------------------------------------------------------
# Functions in XendDomainInfo
for name in methods:
fn = eval("lambda domid, *args: dispatch(domid, '%s', args)"%name)
self.server.register_function(fn, "xend.domain.%s" % name)
- # Functions in XendDomain
inst = XendDomain.instance()
+
for name in dir(inst):
fn = getattr(inst, name)
if name.startswith("domain_") and callable(fn):
@@ -120,10 +157,28 @@ class XMLRPCServer:
# A few special cases
self.server.register_function(domain, 'xend.domain')
self.server.register_function(domains, 'xend.domains')
+ self.server.register_function(domains_with_state,
+ 'xend.domains_with_state')
self.server.register_function(get_log, 'xend.node.log')
self.server.register_function(domain_create, 'xend.domain.create')
self.server.register_function(domain_restore, 'xend.domain.restore')
self.server.register_introspection_functions()
self.ready = True
- self.server.serve_forever()
+
+ # Custom runloop so we can cleanup when exiting.
+ # -----------------------------------------------------------------
+ try:
+ self.server.socket.settimeout(1.0)
+ while self.running:
+ self.server.handle_request()
+ finally:
+ self.cleanup()
+
+ def cleanup(self):
+ log.debug("XMLRPCServer.cleanup()")
+
+ def shutdown(self):
+ self.running = False
+ self.ready = False
+
diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py
index 927e062e11..6bd49acfc9 100644
--- a/tools/python/xen/xend/server/blkif.py
+++ b/tools/python/xen/xend/server/blkif.py
@@ -16,7 +16,6 @@
# Copyright (C) 2005, 2006 XenSource Inc.
#============================================================================
-
import re
import string
@@ -24,10 +23,8 @@ from xen.util import blkif
from xen.util import security
from xen.xend import sxp
from xen.xend.XendError import VmError
-
from xen.xend.server.DevController import DevController
-
class BlkifController(DevController):
"""Block device interface controller. Handles all block devices
for a domain.
@@ -38,12 +35,10 @@ class BlkifController(DevController):
"""
DevController.__init__(self, vm)
-
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- uname = sxp.child_value(config, 'uname')
-
- dev = sxp.child_value(config, 'dev')
+ uname = sxp.child_value(config, 'uname', '')
+ dev = sxp.child_value(config, 'dev', '')
if 'ioemu:' in dev:
(_, dev) = string.split(dev, ':', 1)
@@ -74,6 +69,10 @@ class BlkifController(DevController):
'mode' : mode
}
+ uuid = sxp.child_value(config, 'uuid')
+ if uuid:
+ back['uuid'] = uuid
+
if security.on():
(label, ssidref, policy) = security.get_res_security_details(uname)
back.update({'acm_label' : label,
@@ -81,6 +80,9 @@ class BlkifController(DevController):
'acm_policy' : policy})
devid = blkif.blkdev_name_to_number(dev)
+ if devid is None:
+ raise VmError('Unable to find number for device (%s)' % (dev))
+
front = { 'virtual-device' : "%i" % devid,
'device-type' : dev_type
}
@@ -105,27 +107,30 @@ class BlkifController(DevController):
(self.deviceClass, devid, config))
- def configuration(self, devid):
- """@see DevController.configuration"""
-
- result = DevController.configuration(self, devid)
-
- (dev, typ, params, mode) = self.readBackend(devid,
- 'dev', 'type', 'params',
- 'mode')
+ def getDeviceConfiguration(self, devid):
+ """Returns the configuration of a device.
+ @note: Similar to L{configuration} except it returns a dict.
+ @return: dict
+ """
+ config = DevController.getDeviceConfiguration(self, devid)
+ devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode',
+ 'uuid')
+ dev, typ, params, mode, uuid = devinfo
+
if dev:
- (dev_type) = self.readFrontend(devid, 'device-type')
+ dev_type = self.readFrontend(devid, 'device-type')
if dev_type:
- dev += ":" + dev_type
- result.append(['dev', dev])
+ dev += ':' + dev_type
+ config['dev'] = dev
if typ and params:
- result.append(['uname', typ + ":" + params])
+ config['uname'] = typ +':' + params
if mode:
- result.append(['mode', mode])
-
- return result
+ config['mode'] = mode
+ if uuid:
+ config['uuid'] = uuid
+ return config
def destroyDevice(self, devid):
"""@see DevController.destroyDevice"""
diff --git a/tools/python/xen/xend/server/iopif.py b/tools/python/xen/xend/server/iopif.py
index 67575f2158..96651a7c95 100644
--- a/tools/python/xen/xend/server/iopif.py
+++ b/tools/python/xen/xend/server/iopif.py
@@ -20,7 +20,7 @@
import types
-import xen.lowlevel.xc;
+import xen.lowlevel.xc
from xen.xend import sxp
from xen.xend.XendError import VmError
@@ -72,7 +72,7 @@ class IOPortsController(DevController):
raise VmError('ioports: Invalid i/o range: %s - %s' %
(io_from, io_to))
- rc = xc.domain_ioport_permission(dom = self.getDomid(),
+ rc = xc.domain_ioport_permission(domid = self.getDomid(),
first_port = io_from,
nr_ports = io_to - io_from + 1,
allow_access = True)
diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py
index 98a2d21a00..6e539dbab9 100644
--- a/tools/python/xen/xend/server/irqif.py
+++ b/tools/python/xen/xend/server/irqif.py
@@ -23,7 +23,7 @@
import types
-import xen.lowlevel.xc;
+import xen.lowlevel.xc
from xen.xend import sxp
from xen.xend.XendError import VmError
diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py
index 94016e3628..4c7e359617 100644
--- a/tools/python/xen/xend/server/netif.py
+++ b/tools/python/xen/xend/server/netif.py
@@ -26,13 +26,10 @@ import re
from xen.xend import sxp
from xen.xend import XendRoot
-
from xen.xend.server.DevController import DevController
-
xroot = XendRoot.instance()
-
def randomMAC():
"""Generate a random MAC address.
@@ -139,7 +136,6 @@ class NetifController(DevController):
def __init__(self, vm):
DevController.__init__(self, vm)
-
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
@@ -157,6 +153,7 @@ class NetifController(DevController):
mac = sxp.child_value(config, 'mac')
vifname = sxp.child_value(config, 'vifname')
rate = sxp.child_value(config, 'rate')
+ uuid = sxp.child_value(config, 'uuid')
ipaddr = _get_config_ipaddr(config)
devid = self.allocateDeviceID()
@@ -182,34 +179,37 @@ class NetifController(DevController):
back['vifname'] = vifname
if rate:
back['rate'] = parseRate(rate)
+ if uuid:
+ back['uuid'] = uuid
return (devid, back, front)
- def configuration(self, devid):
+ def getDeviceConfiguration(self, devid):
"""@see DevController.configuration"""
- result = DevController.configuration(self, devid)
-
- (script, ip, bridge, mac, typ, vifname, rate) = self.readBackend(
- devid, 'script', 'ip', 'bridge', 'mac', 'type', 'vifname', 'rate')
+ result = DevController.getDeviceConfiguration(self, devid)
+ devinfo = self.readBackend(devid, 'script', 'ip', 'bridge',
+ 'mac', 'type', 'vifname', 'rate', 'uuid')
+ (script, ip, bridge, mac, typ, vifname, rate, uuid) = devinfo
if script:
- result.append(['script',
- script.replace(xroot.network_script_dir + os.sep,
- "")])
+ network_script_dir = xroot.network_script_dir + os.sep
+ result['script'] = script.replace(network_script_dir, "")
if ip:
- for i in ip.split(" "):
- result.append(['ip', i])
+ result['ip'] = ip.split(" ")
if bridge:
- result.append(['bridge', bridge])
+ result['bridge'] = bridge
if mac:
- result.append(['mac', mac])
+ result['mac'] = mac
if typ:
- result.append(['type', typ])
+ result['type'] = typ
if vifname:
- result.append(['vifname', vifname])
+ result['vifname'] = vifname
if rate:
- result.append(['rate', formatRate(rate)])
+ result['rate'] = formatRate(rate)
+ if uuid:
+ result['uuid'] = uuid
return result
+
diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py
index c6ffcd55e7..eaab90529f 100644
--- a/tools/python/xen/xend/server/pciif.py
+++ b/tools/python/xen/xend/server/pciif.py
@@ -65,7 +65,7 @@ class PciController(DevController):
else:
return default
- if isinstance(val, types.StringType):
+ if isinstance(val, types.StringTypes):
return int(val, 16)
else:
return val
@@ -79,7 +79,7 @@ class PciController(DevController):
back = {}
val = sxp.child_value(config, 'dev')
- if isinstance(val, list):
+ if isinstance(val, (types.ListType, types.TupleType)):
pcidevid = 0
for dev_config in sxp.children(config, 'dev'):
domain = get_param(dev_config, 'domain', 0)
@@ -89,7 +89,7 @@ class PciController(DevController):
self.setupDevice(domain, bus, slot, func)
- back['dev-%i'%(pcidevid)]="%04x:%02x:%02x.%02x"% \
+ back['dev-%i' % pcidevid]="%04x:%02x:%02x.%02x"% \
(domain, bus, slot, func)
pcidevid+=1
@@ -109,30 +109,55 @@ class PciController(DevController):
return (0, back, {})
- def configuration(self, devid):
- """@see DevController.configuration"""
-
- result = DevController.configuration(self, devid)
-
- (num_devs) = self.readBackend(devid, 'num_devs')
-
+ def getDeviceConfiguration(self, devid):
+ result = DevController.getDeviceConfiguration(self, devid)
+ num_devs = self.readBackend(devid, 'num_devs')
+ pci_devs = []
+
for i in range(int(num_devs)):
- (dev_config) = self.readBackend(devid, 'dev-%d'%(i))
+ dev_config = self.readBackend(devid, 'dev-%d' % i)
- pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
- r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
- r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
- r"(?P<func>[0-9a-fA-F]{1,2})", dev_config)
+ pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" +
+ r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" +
+ r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" +
+ r"(?P<func>[0-9a-fA-F]{1,2})", dev_config)
+
if pci_match!=None:
- pci_dev_info = pci_match.groupdict('0')
- result.append( ['dev', \
- ['domain', '0x'+pci_dev_info['domain']], \
- ['bus', '0x'+pci_dev_info['bus']], \
- ['slot', '0x'+pci_dev_info['slot']], \
- ['func', '0x'+pci_dev_info['func']]])
+ pci_dev_info = pci_match.groupdict()
+ pci_devs.append({'domain': '0x%(domain)s' % pci_dev_info,
+ 'bus': '0x%(bus)s' % pci_dev_info,
+ 'slot': '0x%(slot)s' % pci_dev_info,
+ 'func': '0x%(func)s' % pci_dev_info})
+ result['dev'] = pci_devs
return result
+ def configuration(self, devid):
+ """Returns SXPR for devices on domain.
+
+ @note: we treat this dict especially to convert to
+ SXP because it is not a straight dict of strings."""
+
+ configDict = self.getDeviceConfiguration(devid)
+ sxpr = [self.deviceClass]
+
+ # remove devs
+ devs = configDict.pop('dev', [])
+ for dev in devs:
+ dev_sxpr = ['dev']
+ for dev_item in dev.items():
+ dev_sxpr.append(list(dev_item))
+ sxpr.append(dev_sxpr)
+
+ for key, val in configDict.items():
+ if type(val) == type(list()):
+ for v in val:
+ sxpr.append([key, v])
+ else:
+ sxpr.append([key, val])
+
+ return sxpr
+
def setupDevice(self, domain, bus, slot, func):
""" Attach I/O resources for device to frontend domain
"""
@@ -155,9 +180,9 @@ class PciController(DevController):
PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain,
bus, slot, func)
- for (start, size) in dev.ioports:
+ for (start, size) in dev.ioports:
log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
- rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start,
+ rc = xc.domain_ioport_permission(domid = fe_domid, first_port = start,
nr_ports = size, allow_access = True)
if rc<0:
raise VmError(('pci: failed to configure I/O ports on device '+
@@ -171,7 +196,7 @@ class PciController(DevController):
log.debug('pci: enabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
(start,size,start_pfn,nr_pfns))
- rc = xc.domain_iomem_permission(dom = fe_domid,
+ rc = xc.domain_iomem_permission(domid = fe_domid,
first_pfn = start_pfn,
nr_pfns = nr_pfns,
allow_access = True)
@@ -181,7 +206,7 @@ class PciController(DevController):
if dev.irq>0:
log.debug('pci: enabling irq %d'%dev.irq)
- rc = xc.domain_irq_permission(dom = fe_domid, pirq = dev.irq,
+ rc = xc.domain_irq_permission(domid = fe_domid, pirq = dev.irq,
allow_access = True)
if rc<0:
raise VmError(('pci: failed to configure irq on device '+
diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py
index f3315416b6..494a197b8e 100644
--- a/tools/python/xen/xend/server/tpmif.py
+++ b/tools/python/xen/xend/server/tpmif.py
@@ -22,19 +22,20 @@
"""
from xen.xend import sxp
+from xen.xend import XendRoot
from xen.xend.XendLogging import log
from xen.xend.XendError import XendError
-from xen.xend import XendRoot
-from xen.xend.XendDomainInfo import DEV_MIGRATE_TEST
-
+from xen.xend.XendConstants import DEV_MIGRATE_TEST, VTPM_DELETE_SCRIPT
from xen.xend.server.DevController import DevController
import os
import re
-
xroot = XendRoot.instance()
+def destroy_vtpmstate(name):
+ if os.path.exists(VTPM_DELETE_SCRIPT):
+ os.system(VTPM_DELETE_SCRIPT + " " + name)
class TPMifController(DevController):
"""TPM interface controller. Handles all TPM devices for a domain.
@@ -52,22 +53,37 @@ class TPMifController(DevController):
if inst == -1:
inst = int(sxp.child_value(config, 'instance' , '0'))
- log.info("The domain has a TPM with instance %d and devid %d.",
+ typ = sxp.child_value(config, 'type')
+ uuid = sxp.child_value(config, 'uuid')
+
+ log.info("The domain has a TPM with pref. instance %d and devid %d.",
inst, devid)
back = { 'pref_instance' : "%i" % inst,
'resume' : "%s" % (self.vm.getResume()) }
+ if typ:
+ back['type'] = typ
+ if uuid:
+ back['uuid'] = uuid
+
front = { 'handle' : "%i" % devid }
return (devid, back, front)
- def configuration(self, devid):
-
- result = DevController.configuration(self, devid)
+ def getDeviceConfiguration(self, devid):
+ """Returns the configuration of a device"""
+ result = DevController.getDeviceConfiguration(self, devid)
- instance = self.readBackend(devid, 'instance')
+ (instance, uuid, type) = \
+ self.readBackend(devid, 'instance',
+ 'uuid',
+ 'type')
if instance:
- result.append(['instance', instance])
+ result['instance'] = instance
+ if uuid:
+ result['uuid'] = uuid
+ if type:
+ result['type'] = type
return result
diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py
index e37adfb119..a9e9adf17f 100644
--- a/tools/python/xen/xend/sxp.py
+++ b/tools/python/xen/xend/sxp.py
@@ -267,10 +267,14 @@ class Parser:
elif c == 'x':
self.state.fn = self.state_hex
self.state.val = 0
- else:
+ elif c in string.octdigits:
self.state.fn = self.state_octal
self.state.val = 0
self.input_char(c)
+ else:
+ # ignore escape if it doesn't match anything we know
+ self.state.parent.buf += '\\'
+ self.pop_state()
def state_octal(self, c):
def octaldigit(c):
@@ -375,7 +379,7 @@ def atomp(sxpr):
def show(sxpr, out=sys.stdout):
"""Print an sxpr in bracketed (lisp-style) syntax.
"""
- if isinstance(sxpr, types.ListType):
+ if isinstance(sxpr, (types.ListType, types.TupleType)):
out.write(k_list_open)
i = 0
for x in sxpr:
@@ -393,7 +397,7 @@ def show(sxpr, out=sys.stdout):
def show_xml(sxpr, out=sys.stdout):
"""Print an sxpr in XML syntax.
"""
- if isinstance(sxpr, types.ListType):
+ if isinstance(sxpr, (types.ListType, types.TupleType)):
element = name(sxpr)
out.write('<%s' % element)
for attr in attributes(sxpr):
@@ -416,7 +420,7 @@ def elementp(sxpr, elt=None):
sxpr sxpr
elt element type
"""
- return (isinstance(sxpr, types.ListType)
+ return (isinstance(sxpr, (types.ListType, types.TupleType))
and len(sxpr)
and (None == elt or sxpr[0] == elt))
@@ -432,7 +436,7 @@ def name(sxpr):
val = None
if isinstance(sxpr, types.StringType):
val = sxpr
- elif isinstance(sxpr, types.ListType) and len(sxpr):
+ elif isinstance(sxpr, (types.ListType, types.TupleType)) and len(sxpr):
val = sxpr[0]
return val
@@ -444,7 +448,7 @@ def attributes(sxpr):
returns attribute list
"""
val = []
- if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
+ if isinstance(sxpr, (types.ListType, types.TupleType)) and len(sxpr) > 1:
attr = sxpr[1]
if elementp(attr, k_attr_open):
val = attr[1:]
@@ -474,7 +478,7 @@ def children(sxpr, elt=None):
returns children (filtered by elt if specified)
"""
val = []
- if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
+ if isinstance(sxpr, (types.ListType, types.TupleType)) and len(sxpr) > 1:
i = 1
x = sxpr[i]
if elementp(x, k_attr_open):
@@ -563,7 +567,7 @@ def with_id(sxpr, id, val=None):
return s-exp or val
"""
- if isinstance(sxpr, types.ListType):
+ if isinstance(sxpr, (types.ListType, types.TupleType)):
for n in sxpr:
if has_id(n, id):
val = n
@@ -583,7 +587,7 @@ def child_with_id(sxpr, id, val=None):
return s-exp or val
"""
- if isinstance(sxpr, types.ListType):
+ if isinstance(sxpr, (types.ListType, types.TupleType)):
for n in sxpr:
if has_id(n, id):
val = n
@@ -605,7 +609,7 @@ def elements(sxpr, ctxt=None):
yield (sxpr, ctxt)
i = 0
for n in children(sxpr):
- if isinstance(n, types.ListType):
+ if isinstance(n, (types.ListType, types.TupleType)):
# Calling elements() recursively does not generate recursively,
# it just returns a generator object. So we must iterate over it.
for v in elements(n, (i, sxpr, ctxt)):
diff --git a/tools/python/xen/xend/uuid.py b/tools/python/xen/xend/uuid.py
index 401540bc6e..7fe52cb335 100644
--- a/tools/python/xen/xend/uuid.py
+++ b/tools/python/xen/xend/uuid.py
@@ -54,10 +54,6 @@ def getUuidRandom():
uuidFactory = getUuidRandom
-def create():
- return uuidFactory()
-
-
def toString(u):
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
"%02x" * 6]) % tuple(u)
@@ -65,3 +61,9 @@ def toString(u):
def fromString(s):
s = s.replace('-', '')
return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ]
+
+def create():
+ return uuidFactory()
+
+def createString():
+ return toString(create())
diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py
index 0a11c35978..af176da433 100644
--- a/tools/python/xen/xm/addlabel.py
+++ b/tools/python/xen/xm/addlabel.py
@@ -19,19 +19,23 @@
"""Labeling a domain configuration file or a resoruce.
"""
-import sys, os
+import os
+import sys
+
from xen.util import dictio
from xen.util import security
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm addlabel <label> dom <configfile> [<policy>]"
- print " xm addlabel <label> res <resource> [<policy>]\n"
- print " This program adds an acm_label entry into the 'configfile'"
- print " for a domain or to the global resource label file for a"
- print " resource. It derives the policy from the running hypervisor"
- print " if it is not given (optional parameter). If a label already"
- print " exists for the given domain or resource, then addlabel fails.\n"
- security.err("Usage")
+def help():
+ return """
+ Format: xm addlabel <label> dom <configfile> [<policy>]
+ xm addlabel <label> res <resource> [<policy>]
+
+ This program adds an acm_label entry into the 'configfile'
+ for a domain or to the global resource label file for a
+ resource. It derives the policy from the running hypervisor
+ if it is not given (optional parameter). If a label already
+ exists for the given domain or resource, then addlabel fails."""
def validate_config_file(configfile):
@@ -68,13 +72,8 @@ def add_resource_label(label, resource, policyref):
# sanity check: make sure this label can be instantiated later on
ssidref = security.label2ssidref(label, policyref, 'res')
- # sanity check on resource name
- (type, file) = resource.split(":")
- if type == "phy":
- file = "/dev/" + file
- if not os.path.exists(file):
- print "Invalid resource '"+resource+"'"
- return
+ #build canonical resource name
+ resource = security.unify_resname(resource)
# see if this resource is already in the file
access_control = {}
@@ -111,44 +110,45 @@ def add_domain_label(label, configfile, policyref):
config_fd.close()
-def main (argv):
- try:
- policyref = None
- if len(argv) not in [4,5]:
- usage()
- return
-
- label = argv[1]
-
- if len(argv) == 5:
- policyref = argv[4]
- elif security.on():
- policyref = security.active_policy
- else:
- security.err("No active policy. Policy must be specified in command line.")
-
- if argv[2].lower() == "dom":
- configfile = argv[3]
- if configfile[0] != '/':
- for prefix in [".", "/etc/xen"]:
- configfile = prefix + "/" + configfile
- if os.path.isfile(configfile):
- break
- if not validate_config_file(configfile):
- usage()
- else:
- add_domain_label(label, configfile, policyref)
- elif argv[2].lower() == "res":
- resource = argv[3]
- add_resource_label(label, resource, policyref)
+def main(argv):
+ policyref = None
+ if len(argv) not in (4, 5):
+ raise OptionError('Needs either 2 or 3 arguments')
+
+ label = argv[1]
+
+ if len(argv) == 5:
+ policyref = argv[4]
+ elif security.on():
+ policyref = security.active_policy
+ else:
+ raise OptionError("No active policy. Must specify policy on the "
+ "command line.")
+
+ if argv[2].lower() == "dom":
+ configfile = argv[3]
+ if configfile[0] != '/':
+ for prefix in [".", "/etc/xen"]:
+ configfile = prefix + "/" + configfile
+ if os.path.isfile(configfile):
+ break
+ if not validate_config_file(configfile):
+ raise OptionError('Invalid config file')
else:
- usage()
-
- except security.ACMError:
- sys.exit(-1)
-
-
+ add_domain_label(label, configfile, policyref)
+ elif argv[2].lower() == "res":
+ resource = argv[3]
+ add_resource_label(label, resource, policyref)
+ else:
+ raise OptionError('Need to specify either "dom" or "res" as '
+ 'object to add label to.')
+
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
+
diff --git a/tools/python/xen/xm/cfgbootpolicy.py b/tools/python/xen/xm/cfgbootpolicy.py
index f62e4c7a8d..328541e560 100644
--- a/tools/python/xen/xm/cfgbootpolicy.py
+++ b/tools/python/xen/xm/cfgbootpolicy.py
@@ -14,6 +14,7 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer <sailer@us.ibm.com>
+# Contributions: Stefan Berger <stefanb@us.ibm.com>
#============================================================================
"""Configuring a security policy into the boot configuration
"""
@@ -24,70 +25,60 @@ import tempfile
import os, stat
import shutil
import string
-from xen.util.security import ACMError, err
-from xen.util.security import policy_dir_prefix, boot_filename, xen_title_re
-from xen.util.security import any_title_re, xen_kernel_re, kernel_ver_re, any_module_re
+import re
+from xen.util.security import err
+from xen.util.security import policy_dir_prefix, xen_title_re
+from xen.util.security import boot_filename, altboot_filename
+from xen.util.security import any_title_re, xen_kernel_re, any_module_re
from xen.util.security import empty_line_re, binary_name_re, policy_name_re
-
-
-def usage():
- print "\nUsage: xm cfgbootpolicy <policy> [<kernelversion>]\n"
- print " Adds a 'module' line to the Xen grub.conf entry"
- print " so that xen boots into a specific access control"
- print " policy. If kernelversion is not given, then this"
- print " script tries to determine it by looking for a grub"
- print " entry with a line kernel xen.* If there are multiple"
- print " Xen entries, then it must be called with an explicit"
- print " version (it will fail otherwise).\n"
- err("Usage")
-
-
-
-def determine_kernelversion(user_specified):
- within_xen_title = 0
- within_xen_entry = 0
- version_list = []
- guess_version = None
-
- grub_fd = open(boot_filename)
- for line in grub_fd:
- if xen_title_re.match(line):
- within_xen_title = 1
- elif within_xen_title and xen_kernel_re.match(line):
- within_xen_entry = 1
- elif within_xen_title and within_xen_entry and kernel_ver_re.match(line):
- for i in line.split():
- if (i.find("vmlinuz-") >= 0):
- # skip start until "vmlinuz-"
- guess_version = i[i.find("vmlinuz-") + len("vmlinuz-"):]
- if user_specified:
- if (guess_version == user_specified):
- version_list.append(guess_version)
- else:
- version_list.append(guess_version)
- elif len(line.split()) > 0:
- if line.split()[0] == "title":
- within_xen_title = 0
- within_xen_entry = 0
- if len(version_list) > 1:
- err("Cannot decide between entries for kernels %s" % version_list)
- elif len(version_list) == 0:
- err("Cannot find a boot entry candidate (please create a Xen boot entry first).")
+from xen.xm.opts import OptionError
+
+def help():
+ return """
+ Adds a 'module' line to the Xen grub configuration file entry
+ so that Xen boots with a specific access control policy. If
+ boot-title is not given, then this script tries to determine
+ it by looking for a title starting with \"XEN\". If there are
+ multiple entries matching, then it must be called with the unique
+ beginning of the title's name.\n"""
+
+def strip_title(line):
+ """
+ strips whitespace left and right and cuts 'title'
+ """
+ s_title = string.strip(line)
+ pos = string.index(s_title, "title")
+ if pos >= 0:
+ return s_title[pos+6:]
else:
- return version_list[0]
+ return s_title
-
-def insert_policy(boot_file, kernel_version, policy_name):
+def insert_policy(boot_file, alt_boot_file, user_title, policy_name):
"""
inserts policy binary file as last line of the grub entry
- matching the kernel_version version
+ matching the user_title or default title
"""
+ if user_title:
+ #replace "(" by "\(" and ")" by "\)" for matching
+ user_title = string.replace(user_title, "(", "\(")
+ user_title = string.replace(user_title, ")", "\)")
+ user_title_re = re.compile("\s*title\s+.*%s" \
+ % user_title, re.IGNORECASE)
+ else:
+ user_title_re = xen_title_re
+
within_xen_title = 0
within_xen_entry = 0
insert_at_end_of_entry = 0
path_prefix = ''
+ this_title = ''
+ extended_titles = []
(tmp_fd, tmp_grub) = tempfile.mkstemp()
+ #First check whether menu.lst exists
+ if not os.path.isfile(boot_file):
+ #take alternate boot file (grub.conf) instead
+ boot_file = alt_boot_file
#follow symlink since menue.lst might be linked to grub.conf
if stat.S_ISLNK(os.lstat(boot_file)[stat.ST_MODE]):
new_name = os.readlink(boot_file)
@@ -98,30 +89,33 @@ def insert_policy(boot_file, kernel_version, policy_name):
path[len(path)-1] = new_name
boot_file = '/'.join(path)
if not os.path.exists(boot_file):
- err("Boot file \'" + boot_file + "\' not found.")
+ err("Boot file \'%s\' not found." % boot_file)
grub_fd = open(boot_file)
for line in grub_fd:
- if xen_title_re.match(line):
+ if user_title_re.match(line):
+ this_title = strip_title(line)
within_xen_title = 1
elif within_xen_title and xen_kernel_re.match(line):
- within_xen_entry = 1
- elif within_xen_title and within_xen_entry and kernel_ver_re.match(line):
- for i in line.split():
- if (i.find("vmlinuz-") >= 0):
- if kernel_version == i[i.find("vmlinuz-") + len("vmlinuz-"):]:
- insert_at_end_of_entry = 1
- path_prefix = i[0:i.find("vmlinuz-")]
+ insert_at_end_of_entry = 1
+ #use prefix from xen.gz path for policy
+ path_prefix = line.split()[1]
+ idx = path_prefix.rfind('/')
+ if idx >= 0:
+ path_prefix = path_prefix[0:idx+1]
+ else:
+ path_prefix = ''
elif any_module_re.match(line) and insert_at_end_of_entry:
if binary_name_re.match(line):
#delete existing policy module line
line=''
elif any_title_re.match(line):
within_xen_title = 0
- within_xen_entry = 0
- if (empty_line_re.match(line) or any_title_re.match(line)) and insert_at_end_of_entry:
+ if (empty_line_re.match(line) or any_title_re.match(line)) and \
+ insert_at_end_of_entry:
#newline or new title: we insert the policy module line here
os.write(tmp_fd, "\tmodule " + path_prefix + policy_name + ".bin\n")
+ extended_titles.append(this_title)
insert_at_end_of_entry = 0
#write the line that was read (except potential existing policy entry)
os.write(tmp_fd, line)
@@ -129,58 +123,64 @@ def insert_policy(boot_file, kernel_version, policy_name):
if insert_at_end_of_entry:
#last entry, no empty line at end of file
os.write(tmp_fd, "\tmodule " + path_prefix + policy_name + ".bin\n")
+ extended_titles.append(this_title)
- #temp file might be destroyed when closing it, first copy ...
+ #if more than one entry was changed, abort
+ if len(extended_titles) > 1:
+ err("Following boot entries matched: %s. \nPlease specify "
+ "unique part of the boot title." % extended_titles)
+ if len(extended_titles) == 0:
+ err("Boot entry not found. Please specify unique part "
+ "of the boot title.")
+
+ #temp file might be destroyed when closing it, first copy it
shutil.move(boot_file, boot_file+"_save")
shutil.copyfile(tmp_grub, boot_file)
os.close(tmp_fd)
- #temp file did not disappear on my system ...
+ #sometimes the temp file does not disappear
try:
os.remove(tmp_grub)
except:
pass
-
+ return extended_titles[0]
def main(argv):
- try:
- user_kver = None
- policy = None
- if len(argv) == 2:
- policy = argv[1]
- elif len(argv) == 3:
- policy = argv[1]
- user_kver = argv[2]
+ user_kver = None
+ user_title = None
+ if len(argv) == 2:
+ policy = argv[1]
+ elif len(argv) == 3:
+ policy = argv[1]
+ user_title = argv[2]
+ else:
+ raise OptionError('Invalid number of arguments')
+
+ if not policy_name_re.match(policy):
+ raise OptionError("Illegal policy name: '%s'" % policy)
+
+ policy_file = '/'.join([policy_dir_prefix] + policy.split('.'))
+ src_binary_policy_file = policy_file + ".bin"
+ #check if .bin exists or if policy file exists
+ if not os.path.isfile(src_binary_policy_file):
+ if not os.path.isfile(policy_file + "-security_policy.xml"):
+ raise OptionError("Unknown policy '%s'" % policy)
else:
- usage()
-
- if not policy_name_re.match(policy):
- err("Illegal policy name \'" + policy + "\'")
-
- policy_file = policy_dir_prefix + "/" + string.join(string.split(policy, "."), "/")
- src_binary_policy_file = policy_file + ".bin"
- #check if .bin exists or if policy file exists
- if not os.path.isfile(src_binary_policy_file):
- if not os.path.isfile(policy_file + "-security_policy.xml"):
- err("Unknown policy \'" + policy +"\'")
- else:
- err("Cannot find binary file for policy \'" + policy +
- "\'. Please use makepolicy to create binary file.")
- dst_binary_policy_file = "/boot/" + policy + ".bin"
- shutil.copyfile(src_binary_policy_file, dst_binary_policy_file)
-
- kernel_version = determine_kernelversion(user_kver)
- insert_policy(boot_filename, kernel_version, policy)
- print "Boot entry created and \'%s\' copied to /boot" % (policy + ".bin")
-
- except ACMError:
- sys.exit(-1)
- except:
- traceback.print_exc(limit=1)
- sys.exit(-1)
-
-
+ err_msg = "Cannot find binary file for policy '%s'." % policy
+ err_msg += " Please use makepolicy to create binary file."
+ raise OptionError(err_msg)
+
+ dst_binary_policy_file = "/boot/" + policy + ".bin"
+ shutil.copyfile(src_binary_policy_file, dst_binary_policy_file)
+
+ entryname = insert_policy(boot_filename, altboot_filename,
+ user_title, policy)
+ print "Boot entry '%s' extended and \'%s\' copied to /boot" \
+ % (entryname, policy + ".bin")
if __name__ == '__main__':
- main(sys.argv)
-
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: ' + str(e) + '\n')
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/console.py b/tools/python/xen/xm/console.py
index 95f5a3a0e3..f971644fe9 100644
--- a/tools/python/xen/xm/console.py
+++ b/tools/python/xen/xm/console.py
@@ -18,9 +18,7 @@
XENCONSOLE = "xenconsole"
-
import xen.util.auxbin
-
def execConsole(domid):
xen.util.auxbin.execute(XENCONSOLE, [str(domid)])
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 9d5048e445..e1df262c8f 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -25,7 +25,6 @@ import sys
import socket
import re
import xmlrpclib
-import traceback
from xen.xend import sxp
from xen.xend import PrettyPrint
@@ -57,7 +56,8 @@ gopts.opt('help', short='h',
gopts.opt('help_config',
fn=set_true, default=0,
- use="Print help for the configuration script.")
+ use="Print the available configuration variables (vars) for the "
+ "configuration script.")
gopts.opt('quiet', short='q',
fn=set_true, default=0,
@@ -65,35 +65,36 @@ gopts.opt('quiet', short='q',
gopts.opt('path', val='PATH',
fn=set_value, default='.:/etc/xen',
- use="""Search path for configuration scripts.
- The value of PATH is a colon-separated directory list.""")
+ use="Search path for configuration scripts. "
+ "The value of PATH is a colon-separated directory list.")
gopts.opt('defconfig', short='f', val='FILE',
fn=set_value, default='xmdefconfig',
- use="""Use the given Python configuration script.
- The configuration script is loaded after arguments have been processed.
- Each command-line option sets a configuration variable named after
- its long option name, and these variables are placed in the
- environment of the script before it is loaded.
- Variables for options that may be repeated have list values.
- Other variables can be set using VAR=VAL on the command line.
-
- After the script is loaded, option values that were not set on the
- command line are replaced by the values set in the script.""")
+ use="Use the given Python configuration script."
+ "The configuration script is loaded after arguments have been "
+ "processed. Each command-line option sets a configuration "
+ "variable named after its long option name, and these "
+ "variables are placed in the environment of the script before "
+ "it is loaded. Variables for options that may be repeated have "
+ "list values. Other variables can be set using VAR=VAL on the "
+ "command line. "
+ "After the script is loaded, option values that were not set "
+ "on the command line are replaced by the values set in the script.")
gopts.default('defconfig')
gopts.opt('config', short='F', val='FILE',
fn=set_value, default=None,
- use="""Domain configuration to use (SXP).
- SXP is the underlying configuration format used by Xen.
- SXP configurations can be hand-written or generated from Python configuration
- scripts, using the -n (dryrun) option to print the configuration.""")
+ use="Domain configuration to use (SXP).\n"
+ "SXP is the underlying configuration format used by Xen.\n"
+ "SXP configurations can be hand-written or generated from Python "
+ "configuration scripts, using the -n (dryrun) option to print "
+ "the configuration.")
gopts.opt('dryrun', short='n',
fn=set_true, default=0,
- use="""Dry run - print the configuration but don't create the domain.
- Loads the configuration script, creates the SXP configuration and prints it.""")
+ use="Dry run - prints the resulting configuration in SXP but "
+ "does not create the domain.")
gopts.opt('paused', short='p',
fn=set_true, default=0,
@@ -103,20 +104,22 @@ gopts.opt('console_autoconnect', short='c',
fn=set_true, default=0,
use="Connect to the console after the domain is created.")
+gopts.var('vncpasswd', val='NAME',
+ fn=set_value, default=None,
+ use="Password for VNC console on HVM domain.")
+
gopts.var('vncviewer', val='no|yes',
fn=set_bool, default=None,
- use="""Spawn a vncviewer listening for a vnc server in the domain.
- The address of the vncviewer is passed to the domain on the kernel command
- line using 'VNC_SERVER=<host>:<port>'. The port used by vnc is 5500 + DISPLAY.
- A display value with a free port is chosen if possible.
- Only valid when vnc=1.
- """)
+ use="Spawn a vncviewer listening for a vnc server in the domain.\n"
+ "The address of the vncviewer is passed to the domain on the "
+ "kernel command line using 'VNC_SERVER=<host>:<port>'. The port "
+ "used by vnc is 5500 + DISPLAY. A display value with a free port "
+ "is chosen if possible.\nOnly valid when vnc=1.")
gopts.var('vncconsole', val='no|yes',
fn=set_bool, default=None,
- use="""Spawn a vncviewer process for the domain's graphical console.
- Only valid when vnc=1.
- """)
+ use="Spawn a vncviewer process for the domain's graphical console.\n"
+ "Only valid when vnc=1.")
gopts.var('name', val='NAME',
fn=set_value, default=None,
@@ -171,25 +174,29 @@ gopts.var('cpus', val='CPUS',
use="CPUS to run the domain on.")
gopts.var('pae', val='PAE',
- fn=set_int, default=0,
+ fn=set_int, default=1,
use="Disable or enable PAE of HVM domain.")
gopts.var('acpi', val='ACPI',
- fn=set_int, default=0,
+ fn=set_int, default=1,
use="Disable or enable ACPI of HVM domain.")
gopts.var('apic', val='APIC',
- fn=set_int, default=0,
- use="Disable or enable APIC of HVM domain.")
+ fn=set_int, default=1,
+ use="Disable or enable APIC mode.")
gopts.var('vcpus', val='VCPUS',
fn=set_int, default=1,
use="# of Virtual CPUS in domain.")
+gopts.var('cpu_cap', val='CAP',
+ fn=set_int, default=None,
+ use="""Set the maximum amount of cpu.
+ CAP is a percentage that fixes the maximum amount of cpu.""")
+
gopts.var('cpu_weight', val='WEIGHT',
- fn=set_float, default=None,
- use="""Set the new domain's cpu weight.
- WEIGHT is a float that controls the domain's share of the cpu.""")
+ fn=set_int, default=None,
+ use="""Set the cpu time ratio to be allocated to the domain.""")
gopts.var('restart', val='onreboot|always|never',
fn=set_value, default=None,
@@ -292,7 +299,7 @@ gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,ba
This option may be repeated to add more than one vif.
Specifying vifs will increase the number of interfaces as needed.""")
-gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
+gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
fn=append_value, default=[],
use="""Add a TPM interface. On the backend side use the given
instance as virtual TPM instance. The given number is merely the
@@ -300,7 +307,11 @@ gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
which instance number will actually be assigned to the domain.
The associtation between virtual machine and the TPM instance
number can be found in /etc/xen/vtpm.db. Use the backend in the
- given domain.""")
+ given domain.
+ The type parameter can be used to select a specific driver type
+ that the VM can use. To prevent a fully virtualized domain (HVM)
+ from being able to access an emulated device model, you may specify
+ 'paravirtualized' here.""")
gopts.var('access_control', val="policy=POLICY,label=LABEL",
fn=append_value, default=[],
@@ -380,6 +391,10 @@ gopts.var('localtime', val='no|yes',
fn=set_bool, default=0,
use="Is RTC set to localtime?")
+gopts.var('keymap', val='FILE',
+ fn=set_value, default='',
+ use="Set keyboard layout used")
+
gopts.var('usb', val='no|yes',
fn=set_bool, default=0,
use="Emulate USB devices?")
@@ -416,6 +431,10 @@ gopts.var('vncdisplay', val='',
fn=set_value, default=None,
use="""VNC display to use""")
+gopts.var('vnclisten', val='',
+ fn=set_value, default=None,
+ use="""Address for VNC server to listen on.""")
+
gopts.var('vncunused', val='',
fn=set_bool, default=1,
use="""Try to find an unused port for the VNC server.
@@ -440,6 +459,17 @@ gopts.var('uuid', val='',
addresses for virtual network interfaces. This must be a unique
value across the entire cluster.""")
+gopts.var('on_xend_start', val='ignore|start',
+ fn=set_value, default='ignore',
+ use='Action to perform when xend starts')
+
+gopts.var('on_xend_stop', val='continue|shutdown|suspend',
+ fn=set_value, default="ignore",
+ use="""Behaviour when Xend stops:
+ - ignore: Domain continues to run;
+ - shutdown: Domain is shutdown;
+ - suspend: Domain is suspended;
+ """)
def err(msg):
"""Print an error to stderr and exit.
@@ -490,7 +520,6 @@ def configure_disks(config_devs, vals):
"""Create the config for disks (virtual block devices).
"""
for (uname, dev, mode, backend) in vals.disk:
-
if uname.startswith('tap:'):
cls = 'tap'
else:
@@ -576,27 +605,28 @@ def configure_vtpm(config_devs, vals):
"""Create the config for virtual TPM interfaces.
"""
vtpm = vals.vtpm
- vtpm_n = 1
- for idx in range(0, vtpm_n):
- if idx < len(vtpm):
- d = vtpm[idx]
- instance = d.get('instance')
- if instance == "VTPMD":
- instance = "0"
- else:
- if instance != None:
- try:
- if int(instance) == 0:
- err('VM config error: vTPM instance must not be 0.')
- except ValueError:
- err('Vm config error: could not parse instance number.')
- backend = d.get('backend')
- config_vtpm = ['vtpm']
- if instance:
- config_vtpm.append(['pref_instance', instance])
- if backend:
- config_vtpm.append(['backend', backend])
- config_devs.append(['device', config_vtpm])
+ if len(vtpm) > 0:
+ d = vtpm[0]
+ instance = d.get('instance')
+ if instance == "VTPMD":
+ instance = "0"
+ else:
+ if instance != None:
+ try:
+ if int(instance) == 0:
+ err('VM config error: vTPM instance must not be 0.')
+ except ValueError:
+ err('Vm config error: could not parse instance number.')
+ backend = d.get('backend')
+ typ = d.get('type')
+ config_vtpm = ['vtpm']
+ if instance:
+ config_vtpm.append(['pref_instance', instance])
+ if backend:
+ config_vtpm.append(['backend', backend])
+ if typ:
+ config_vtpm.append(['type', type])
+ config_devs.append(['device', config_vtpm])
def configure_vifs(config_devs, vals):
@@ -636,11 +666,13 @@ def configure_hvm(config_image, vals):
"""
args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb',
'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
- 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'sdl', 'display',
- 'acpi', 'apic', 'xauthority', 'usb', 'usbdevice' ]
+ 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
+ 'sdl', 'display', 'xauthority',
+ 'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ]
for a in args:
- if (vals.__dict__[a]):
+ if a in vals.__dict__ and vals.__dict__[a] is not None:
config_image.append([a, vals.__dict__[a]])
+ config_image.append(['vncpasswd', vals.vncpasswd])
def run_bootloader(vals, config_image):
if not os.access(vals.bootloader, os.X_OK):
@@ -671,8 +703,9 @@ def make_config(vals):
config.append([n, v])
map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
- 'restart', 'on_poweroff', 'on_reboot', 'on_crash',
- 'vcpus', 'features'])
+ 'restart', 'on_poweroff',
+ 'on_reboot', 'on_crash', 'vcpus', 'features',
+ 'on_xend_start', 'on_xend_stop'])
if vals.uuid is not None:
config.append(['uuid', vals.uuid])
@@ -680,6 +713,8 @@ def make_config(vals):
config.append(['cpu', vals.cpu])
if vals.cpus is not None:
config.append(['cpus', vals.cpus])
+ if vals.cpu_cap is not None:
+ config.append(['cpu_cap', vals.cpu_cap])
if vals.cpu_weight is not None:
config.append(['cpu_weight', vals.cpu_weight])
if vals.blkif:
@@ -696,7 +731,7 @@ def make_config(vals):
config_image = run_bootloader(vals, config_image)
config.append(['bootloader', vals.bootloader])
if vals.bootargs:
- config.append(['bootloader_args'], vals.bootargs)
+ config.append(['bootloader_args', vals.bootargs])
config.append(['image', config_image])
config_devs = []
@@ -851,7 +886,6 @@ def choose_vnc_display():
if port in ports: continue
return d
return None
-
vncpid = None
def daemonize(prog, args):
@@ -885,7 +919,6 @@ def daemonize(prog, args):
w.write(str(pid2 or 0))
w.close()
os._exit(0)
-
os.close(w)
r = os.fdopen(r)
daemon_pid = int(r.read())
@@ -904,6 +937,7 @@ def spawn_vnc(display):
vncpid = daemonize("vncviewer", vncargs)
if vncpid == 0:
return 0
+
return VNC_BASE_PORT + display
def preprocess_vnc(vals):
@@ -1019,11 +1053,10 @@ def get_xauthority():
def parseCommandLine(argv):
gopts.reset()
args = gopts.parse(argv)
- if gopts.vals.help:
- gopts.usage()
- if gopts.vals.help or gopts.vals.help_config:
- gopts.load_defconfig(help=1)
+
if gopts.vals.help or gopts.vals.help_config:
+ if gopts.vals.help_config:
+ print gopts.val_usage()
return (None, None)
if not gopts.vals.display:
@@ -1091,7 +1124,6 @@ def check_domain_label(config, verbose):
return answer
-
def config_security_check(config, verbose):
"""Checks each resource listed in the config to see if the active
policy will permit creation of a new domain using the config.
@@ -1139,13 +1171,17 @@ def config_security_check(config, verbose):
except security.ACMError:
print " %s: DENIED" % (resource)
(res_label, res_policy) = security.get_res_label(resource)
- print " --> res:"+res_label+" ("+res_policy+")"
- print " --> dom:"+domain_label+" ("+domain_policy+")"
+ if not res_label:
+ res_label = ""
+ print " --> res: %s (%s)" % (str(res_label),
+ str(res_policy))
+ print " --> dom: %s (%s)" % (str(domain_label),
+ str(domain_policy))
+
answer = 0
return answer
-
def create_security_check(config):
passed = 0
try:
@@ -1158,7 +1194,9 @@ def create_security_check(config):
sys.exit(-1)
return passed
-
+
+def help():
+ return str(gopts)
def main(argv):
try:
@@ -1170,17 +1208,20 @@ def main(argv):
return
if type(config) == str:
+ try:
config = sxp.parse(file(config))[0]
+ except IOError, exn:
+ raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
if not create_security_check(config):
- err("Security configuration prevents domain from starting.")
+ raise security.ACMError('Security Configuration prevents domain from starting')
else:
dom = make_domain(opts, config)
if opts.vals.console_autoconnect:
- console.execConsole(dom)
-
+ console.execConsole(dom)
+
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/dry-run.py b/tools/python/xen/xm/dry-run.py
index 924235c392..9aa56d2f94 100644
--- a/tools/python/xen/xm/dry-run.py
+++ b/tools/python/xen/xm/dry-run.py
@@ -22,38 +22,36 @@ import sys
from xen.util import security
from xen.xm import create
from xen.xend import sxp
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm dry-run <configfile>\n"
- print "This program checks each resource listed in the configfile"
- print "to see if the domain created by the configfile can access"
- print "the resources. The status of each resource is listed"
- print "individually along with the final security decision.\n"
- security.err("Usage")
-
+def help():
+ return """
+ This program checks each resource listed in the configfile
+ to see if the domain created by the configfile can access
+ the resources. The status of each resource is listed
+ individually along with the final security decision."""
def main (argv):
- try:
- if len(argv) != 2:
- usage()
-
- passed = 0
- (opts, config) = create.parseCommandLine(argv)
- if create.check_domain_label(config, verbose=1):
- if create.config_security_check(config, verbose=1):
- passed = 1
- else:
- print "Checking resources: (skipped)"
-
- if passed:
- print "Dry Run: PASSED"
- else:
- print "Dry Run: FAILED"
- sys.exit(-1)
-
- except security.ACMError:
+ if len(argv) != 2:
+ raise OptionError('Invalid number of arguments')
+
+ passed = 0
+ (opts, config) = create.parseCommandLine(argv)
+ if create.check_domain_label(config, verbose=1):
+ if create.config_security_check(config, verbose=1):
+ passed = 1
+ else:
+ print "Checking resources: (skipped)"
+
+ if passed:
+ print "Dry Run: PASSED"
+ else:
+ print "Dry Run: FAILED"
sys.exit(-1)
-
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/dumppolicy.py b/tools/python/xen/xm/dumppolicy.py
index 9df36611be..c57e8e4ad5 100644
--- a/tools/python/xen/xm/dumppolicy.py
+++ b/tools/python/xen/xm/dumppolicy.py
@@ -19,27 +19,24 @@
"""
import sys
from xen.util.security import ACMError, err, dump_policy
+from xen.xm.opts import OptionError
-
-def usage():
- print "\nUsage: xm dumppolicy\n"
- print " Retrieve and print currently enforced"
- print " hypervisor policy information (low-level).\n"
- err("Usage")
-
+def help():
+ return """
+ Retrieve and print currently enforced hypervisor policy information
+ (low-level)."""
def main(argv):
- try:
- if len(argv) != 1:
- usage()
-
- dump_policy()
-
- except ACMError:
- sys.exit(-1)
+ if len(argv) != 1:
+ raise OptionError("No arguments expected.")
+ dump_policy()
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/getlabel.py b/tools/python/xen/xm/getlabel.py
index 3450d2799c..3be98e82c3 100644
--- a/tools/python/xen/xm/getlabel.py
+++ b/tools/python/xen/xm/getlabel.py
@@ -21,23 +21,27 @@
import sys, os, re
from xen.util import dictio
from xen.util import security
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm getlabel dom <configfile>"
- print " xm getlabel res <resource>\n"
- print " This program shows the label for a domain or resource.\n"
- security.err("Usage")
-
+def help():
+ return """
+ Usage: xm getlabel dom <configfile>
+ xm getlabel res <resource>
+
+ This program shows the label for a domain or resource."""
def get_resource_label(resource):
"""Gets the resource label
"""
+ #build canonical resource name
+ resource = security.unify_resname(resource)
+
# read in the resource file
file = security.res_label_filename
try:
access_control = dictio.dict_read("resources", file)
except:
- security.err("Resource label file not found")
+ raise OptionError("Resource label file not found")
# get the entry and print label
if access_control.has_key(resource):
@@ -45,23 +49,22 @@ def get_resource_label(resource):
label = access_control[resource][1]
print "policy="+policy+",label="+label
else:
- security.err("Resource not labeled")
+ raise security.ACMError("Resource not labeled")
def get_domain_label(configfile):
# open the domain config file
fd = None
- file = None
if configfile[0] == '/':
fd = open(configfile, "rb")
else:
for prefix in [".", "/etc/xen"]:
- file = prefix + "/" + configfile
- if os.path.isfile(file):
- fd = open(file, "rb")
+ abs_file = prefix + "/" + configfile
+ if os.path.isfile(abs_file):
+ fd = open(abs_file, "rb")
break
if not fd:
- security.err("Configuration file '"+configfile+"' not found.")
+ raise OptionError("Configuration file '%s' not found." % configfile)
# read in the domain config file, finding the label line
ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
@@ -79,7 +82,7 @@ def get_domain_label(configfile):
# send error message if we didn't find anything
if acline == "":
- security.err("Domain not labeled")
+ raise security.ACMError("Domain not labeled")
# print out the label
(title, data) = acline.split("=", 1)
@@ -89,24 +92,25 @@ def get_domain_label(configfile):
print data
-def main (argv):
- try:
- if len(argv) != 3:
- usage()
-
- if argv[1].lower() == "dom":
- configfile = argv[2]
- get_domain_label(configfile)
- elif argv[1].lower() == "res":
- resource = argv[2]
- get_resource_label(resource)
- else:
- usage()
-
- except security.ACMError:
- sys.exit(-1)
+def main(argv):
+ if len(argv) != 3:
+ raise OptionError('Requires 2 arguments')
+
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ get_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ get_resource_label(resource)
+ else:
+ raise OptionError('First subcommand argument must be "dom" or "res"')
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
+
diff --git a/tools/python/xen/xm/labels.py b/tools/python/xen/xm/labels.py
index 6536b5e27d..d84b211800 100644
--- a/tools/python/xen/xm/labels.py
+++ b/tools/python/xen/xm/labels.py
@@ -23,49 +23,46 @@ import traceback
import string
from xen.util.security import ACMError, err, list_labels, active_policy
from xen.util.security import vm_label_re, res_label_re, all_label_re
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm labels [<policy>] [<type=dom|res|any>]\n"
- print " Prints labels of the specified type (default is dom)"
- print " that are defined in policy (default is current"
- print " hypervisor policy).\n"
- err("Usage")
+def help():
+ return """
+ Prints labels of the specified type (default is dom)
+ that are defined in policy (default is current hypervisor policy)."""
def main(argv):
- try:
- policy = None
- type = None
- for i in argv[1:]:
- i_s = string.split(i, '=')
- if len(i_s) > 1:
- if (i_s[0] == 'type') and (len(i_s) == 2):
- if not type:
- type = i_s[1]
- else:
- usage()
- else:
- usage()
- else:
- if not policy:
- policy = i
- else:
- usage()
-
- if not policy:
- policy = active_policy
- if active_policy in ['NULL', 'INACTIVE', 'DEFAULT']:
- err("No policy active. Please specify the <policy> parameter.")
+ policy = None
+ ptype = None
+ for arg in argv[1:]:
+ key_val = arg.split('=')
+ if len(key_val) == 2 and key_val[0] == 'type':
+ if ptype:
+ raise OptionError('type is definied twice')
+ ptype = key_val[1].lower()
- if not type or (type in ['DOM', 'dom']):
- condition = vm_label_re
- elif type in ['RES', 'res']:
- condition = res_label_re
- elif type in ['ANY', 'any']:
- condition = all_label_re
+ elif len(key_val) == 1:
+ if policy:
+ raise OptionError('policy is defined twice')
+ policy = arg
else:
- err("Unknown label type \'" + type + "\'")
+ raise OptionError('Unrecognised option: %s' % arg)
+
+ if not policy:
+ policy = active_policy
+ if active_policy in ['NULL', 'INACTIVE', 'DEFAULT']:
+ raise OptionError('No policy active, you must specify a <policy>')
+
+ if not ptype or ptype == 'dom':
+ condition = vm_label_re
+ elif ptype == 'res':
+ condition = res_label_re
+ elif ptype == 'any':
+ condition = all_label_re
+ else:
+ err("Unknown label type \'" + ptype + "\'")
+ try:
labels = list_labels(policy, condition)
labels.sort()
for label in labels:
@@ -74,9 +71,7 @@ def main(argv):
except ACMError:
sys.exit(-1)
except:
- traceback.print_exc(limit=1)
- sys.exit(-1)
-
+ traceback.print_exc(limit = 1)
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/loadpolicy.py b/tools/python/xen/xm/loadpolicy.py
index 3eb0e28e75..807859c02d 100644
--- a/tools/python/xen/xm/loadpolicy.py
+++ b/tools/python/xen/xm/loadpolicy.py
@@ -21,28 +21,22 @@
import sys
import traceback
from xen.util.security import ACMError, err, load_policy
+from xen.xm.opts import OptionError
-
-def usage():
- print "\nUsage: xm loadpolicy <policy>\n"
- print " Load the compiled binary (.bin) policy"
- print " into the running hypervisor.\n"
- err("Usage")
+def help():
+ return """Load the compiled binary (.bin) policy into the running
+ hypervisor."""
def main(argv):
- try:
- if len(argv) != 2:
- usage()
- load_policy(argv[1])
-
- except ACMError:
- sys.exit(-1)
- except:
- traceback.print_exc(limit=1)
- sys.exit(-1)
-
+ if len(argv) != 2:
+ raise OptionError('No policy defined')
+
+ load_policy(argv[1])
if __name__ == '__main__':
- main(sys.argv)
-
-
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
+
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index a489498969..0b7a728cd7 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -22,28 +22,28 @@
"""Grand unified management application for Xen.
"""
import os
-import os.path
import sys
import re
import getopt
import socket
-import warnings
-warnings.filterwarnings('ignore', category=FutureWarning)
+import traceback
import xmlrpclib
import traceback
import datetime
+from select import select
-import xen.xend.XendProtocol
+import warnings
+warnings.filterwarnings('ignore', category=FutureWarning)
from xen.xend import PrettyPrint
from xen.xend import sxp
-from xen.xm.opts import *
-
-import console
-import xen.xend.XendClient
+from xen.xend import XendClient
from xen.xend.XendClient import server
+from xen.xend.XendConstants import *
+
+from xen.xm.opts import OptionError, Opts, wrap, set_true
+from xen.xm import console
from xen.util import security
-from select import select
# getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
# getopt.getopt if gnu_getopt is not available. This will mean that options
@@ -51,93 +51,174 @@ from select import select
if not hasattr(getopt, 'gnu_getopt'):
getopt.gnu_getopt = getopt.getopt
+# General help message
+
+USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \
+ "Control, list, and manipulate Xen guest instances.\n"
+
+USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \
+ 'For more help on \'xm\' see the xm(1) man page.\n' \
+ 'For more help on \'xm create\' see the xmdomain.cfg(5) '\
+ ' man page.\n'
-# Strings for shorthelp
-console_help = "console <DomId> Attach to domain DomId's console."
-create_help = """create [-c] <ConfigFile>
- [Name=Value].. Create a domain based on Config File"""
-destroy_help = "destroy <DomId> Terminate a domain immediately"
-help_help = "help Display this message"
-list_help = "list [--long] [DomId, ...] List information about domains"
-list_label_help = "list [--label] [DomId, ...] List information about domains including their labels"
-
-mem_max_help = "mem-max <DomId> <Mem> Set maximum memory reservation for a domain"
-mem_set_help = "mem-set <DomId> <Mem> Adjust the current memory usage for a domain"
-migrate_help = "migrate <DomId> <Host> Migrate a domain to another machine"
-pause_help = "pause <DomId> Pause execution of a domain"
-reboot_help = "reboot <DomId> [-w][-a] Reboot a domain"
-restore_help = "restore <File> Create a domain from a saved state file"
-save_help = "save <DomId> <File> Save domain state (and config) to file"
-shutdown_help ="shutdown <DomId> [-w][-a][-R|-H] Shutdown a domain"
-top_help = "top Monitor system and domains in real-time"
-unpause_help = "unpause <DomId> Unpause a paused domain"
-uptime_help = "uptime [-s|--short] [DomId, ...] List uptime for domains"
-
-help_spacer = """
- """
-
-# Strings for longhelp
-sysrq_help = "sysrq <DomId> <letter> Send a sysrq to a domain"
-domid_help = "domid <DomName> Converts a domain name to a domain id"
-domname_help = "domname <DomId> Convert a domain id to a domain name"
-vcpu_set_help = """vcpu-set <DomId> <VCPUs> Set the number of active VCPUs for a domain
- within the range allowed by the domain
- configuration"""
-vcpu_list_help = "vcpu-list <DomId> List the VCPUs for a domain (or all domains)"
-vcpu_pin_help = "vcpu-pin <DomId> <VCPU> <CPUs> Set which cpus a VCPU can use"
-dmesg_help = "dmesg [-c|--clear] Read or clear Xen's message buffer"
-info_help = "info Get information about the xen host"
-rename_help = "rename <DomId> <New Name> Rename a domain"
-log_help = "log Print the xend log"
-sched_sedf_help = "sched-sedf [DOM] [OPTIONS] Show|Set simple EDF parameters\n" + \
-" -p, --period Relative deadline(ms).\n\
- -s, --slice Worst-case execution time(ms)\n\
- (slice < period).\n\
- -l, --latency scaled period(ms) in case the domain\n\
- is doing heavy I/O.\n\
- -e, --extra flag (0/1) which controls whether the\n\
- domain can run in extra-time\n\
- -w, --weight mutually exclusive with period/slice and\n\
- specifies another way of setting a domain's\n\
- cpu period/slice."
-
-sched_credit_help = "sched-credit Set or get credit scheduler parameters"
-block_attach_help = """block-attach <DomId> <BackDev> <FrontDev> <Mode>
- [BackDomId] Create a new virtual block device"""
-block_detach_help = """block-detach <DomId> <DevId> Destroy a domain's virtual block device,
- where <DevId> may either be the device ID
- or the device name as mounted in the guest"""
-
-block_list_help = "block-list <DomId> [--long] List virtual block devices for a domain"
-block_configure_help = """block-configure <DomId> <BackDev> <FrontDev> <Mode>
- [BackDomId] Change block device configuration"""
-network_attach_help = """network-attach <DomID> [script=<script>] [ip=<ip>] [mac=<mac>]
- [bridge=<bridge>] [backend=<backDomID>]
- Create a new virtual network device """
-network_detach_help = """network-detach <DomId> <DevId> Destroy a domain's virtual network
- device, where <DevId> is the device ID."""
-
-network_list_help = "network-list <DomId> [--long] List virtual network interfaces for a domain"
-vnet_list_help = "vnet-list [-l|--long] list vnets"
-vnet_create_help = "vnet-create <config> create a vnet from a config file"
-vnet_delete_help = "vnet-delete <vnetid> delete a vnet"
-vtpm_list_help = "vtpm-list <DomId> [--long] list virtual TPM devices"
-addlabel_help = "addlabel <label> dom <configfile> Add security label to domain\n <label> res <resource> or resource"
-rmlabel_help = "rmlabel dom <configfile> Remove security label from domain\n res <resource> or resource"
-getlabel_help = "getlabel dom <configfile> Show security label for domain\n res <resource> or resource"
-dry_run_help = "dry-run <configfile> Tests if domain can access its resources"
-resources_help = "resources Show info for each labeled resource"
-cfgbootpolicy_help = "cfgbootpolicy <policy> Add policy to boot configuration "
-dumppolicy_help = "dumppolicy Print hypervisor ACM state information"
-loadpolicy_help = "loadpolicy <policy> Load binary policy into hypervisor"
-makepolicy_help = "makepolicy <policy> Build policy and create .bin/.map files"
-labels_help = "labels [policy] [type=DOM|..] List <type> labels for (active) policy."
-serve_help = "serve Proxy Xend XML-RPC over stdio"
-
-short_command_list = [
+# Help strings are indexed by subcommand name in this way:
+# 'subcommand': (argstring, description)
+
+SUBCOMMAND_HELP = {
+ # common commands
+
+ 'console' : ('[-q|--quiet] <Domain>',
+ 'Attach to <Domain>\'s console.'),
+ 'create' : ('<ConfigFile> [options] [vars]',
+ 'Create a domain based on <ConfigFile>.'),
+ 'destroy' : ('<Domain>',
+ 'Terminate a domain immediately.'),
+ 'help' : ('', 'Display this message.'),
+ 'list' : ('[options] [Domain, ...]',
+ 'List information about all/some domains.'),
+ 'mem-max' : ('<Domain> <Mem>',
+ 'Set the maximum amount reservation for a domain.'),
+ 'mem-set' : ('<Domain> <Mem>',
+ 'Set the current memory usage for a domain.'),
+ 'migrate' : ('<Domain> <Host>',
+ 'Migrate a domain to another machine.'),
+ 'pause' : ('<Domain>', 'Pause execution of a domain.'),
+ 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'),
+ 'restore' : ('<CheckpointFile> [-p]',
+ 'Restore a domain from a saved state.'),
+ 'save' : ('<Domain> <CheckpointFile>',
+ 'Save a domain state to restore later.'),
+ 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'),
+ 'top' : ('', 'Monitor a host and the domains in real time.'),
+ 'unpause' : ('<Domain>', 'Unpause a paused domain.'),
+ 'uptime' : ('[-s] <Domain>', 'Print uptime for a domain.'),
+
+ # Life cycle xm commands
+ 'new' : ('<ConfigFile> [options] [vars]',
+ 'Adds a domain to Xend domain management'),
+ 'delete' : ('<DomainName>',
+ 'Remove a domain from Xend domain management.'),
+ 'start' : ('<DomainName>', 'Start a Xend managed domain'),
+ 'resume' : ('<DomainName>', 'Resume a Xend managed domain'),
+ 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'),
+
+ # less used commands
+
+ 'dmesg' : ('[-c|--clear]',
+ 'Read and/or clear Xend\'s message buffer.'),
+ 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'),
+ 'domname' : ('<DomId>', 'Convert a domain id to domain name.'),
+ 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]',
+ 'Dump core for a specific domain.'),
+ 'info' : ('', 'Get information about Xen host.'),
+ 'log' : ('', 'Print Xend log'),
+ 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'),
+ 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'),
+ 'sched-credit': ('-d <Domain> [-w[=WEIGHT]|-c[=CAP]]',
+ 'Get/set credit scheduler parameters.'),
+ 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
+ 'vcpu-list' : ('[<Domain>]',
+ 'List the VCPUs for a domain or all domains.'),
+ 'vcpu-pin' : ('<Domain> <VCPU> <CPUs>',
+ 'Set which CPUs a VCPU can use.'),
+ 'vcpu-set' : ('<Domain> <vCPUs>',
+ 'Set the number of active VCPUs for allowed for the'
+ ' domain.'),
+
+ # device commands
+
+ 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode>',
+ 'Create a new virtual block device.'),
+ 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomId]',
+ 'Change block device configuration'),
+ 'block-detach' : ('<Domain> <DevId>',
+ 'Destroy a domain\'s virtual block device.'),
+ 'block-list' : ('<Domain> [--long]',
+ 'List virtual block devices for a domain.'),
+ 'network-attach': ('<Domain> [--script=<script>] [--ip=<ip>] '
+ '[--mac=<mac>]',
+ 'Create a new virtual network device.'),
+ 'network-detach': ('<Domain> <DevId>',
+ 'Destroy a domain\'s virtual network device.'),
+ 'network-list' : ('<Domain> [--long]',
+ 'List virtual network interfaces for a domain.'),
+ 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'),
+ 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
+ 'vnet-list' : ('[-l|--long]', 'List Vnets.'),
+ 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
+
+ # security
+
+ 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>} [<policy>]',
+ 'Add security label to domain.'),
+ 'rmlabel' : ('{dom <ConfigFile>|res <Resource>}',
+ 'Remove a security label from domain.'),
+ 'getlabel' : ('{dom <ConfigFile>|res <Resource>}',
+ 'Show security label for domain or resource.'),
+ 'dry-run' : ('<ConfigFile>',
+ 'Test if a domain can access its resources.'),
+ 'resources' : ('', 'Show info for each labeled resource.'),
+ 'cfgbootpolicy' : ('<policy> [boot-title]',
+ 'Add policy to boot configuration.'),
+ 'dumppolicy' : ('', 'Print hypervisor ACM state information.'),
+ 'loadpolicy' : ('<policy.bin>', 'Load binary policy into hypervisor.'),
+ 'makepolicy' : ('<policy>', 'Build policy and create .bin/.map '
+ 'files.'),
+ 'labels' : ('[policy] [type=dom|res|any]',
+ 'List <type> labels for (active) policy.'),
+ 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'),
+}
+
+SUBCOMMAND_OPTIONS = {
+ 'sched-sedf': (
+ ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'),
+ ('-s [MS]', '--slice[=MS]' ,
+ 'Worst-case execution time(ms). (slice < period)'),
+ ('-l [MS]', '--latency[=MS]',
+ 'Scaled period (ms) when domain performs heavy I/O'),
+ ('-e [FLAG]', '--extra[=FLAG]',
+ 'Flag (0 or 1) controls if domain can run in extra time.'),
+ ('-w [FLOAT]', '--weight[=FLOAT]',
+ 'CPU Period/slice (do not set with --period/--slice)'),
+ ),
+ 'sched-credit': (
+ ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'),
+ ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'),
+ ('-c CAP', '--cap=CAP', 'Cap (int)'),
+ ),
+ 'list': (
+ ('-l', '--long', 'Output all VM details in SXP'),
+ ('', '--label', 'Include security labels'),
+ ('', '--state=<state>', 'Select only VMs with the specified state'),
+ ),
+ 'console': (
+ ('-q', '--quiet', 'Do not print an error message if the domain does not exist'),
+ ),
+ 'dmesg': (
+ ('-c', '--clear', 'Clear dmesg buffer'),
+ ),
+ 'vnet-list': (
+ ('-l', '--long', 'List Vnets as SXP'),
+ ),
+ 'network-list': (
+ ('-l', '--long', 'List resources as SXP'),
+ ),
+ 'dump-core': (
+ ('-L', '--live', 'Dump core without pausing the domain'),
+ ('-C', '--crash', 'Crash domain after dumping core'),
+ ),
+ 'restore': (
+ ('-p', '--paused', 'Do not unpause domain after restoring it'),
+ ),
+}
+
+common_commands = [
"console",
"create",
+ "new",
+ "delete",
"destroy",
+ "dump-core",
"help",
"list",
"mem-set",
@@ -145,8 +226,11 @@ short_command_list = [
"pause",
"reboot",
"restore",
+ "resume",
"save",
"shutdown",
+ "start",
+ "suspend",
"top",
"unpause",
"uptime",
@@ -156,11 +240,13 @@ short_command_list = [
domain_commands = [
"console",
"create",
+ "new",
+ "delete",
"destroy",
"domid",
"domname",
+ "dump-core",
"list",
- "list_label",
"mem-max",
"mem-set",
"migrate",
@@ -168,8 +254,11 @@ domain_commands = [
"reboot",
"rename",
"restore",
+ "resume",
"save",
"shutdown",
+ "start",
+ "suspend",
"sysrq",
"top",
"unpause",
@@ -218,67 +307,110 @@ acm_commands = [
"makepolicy",
"loadpolicy",
"cfgbootpolicy",
- "dumppolicy"
+ "dumppolicy",
]
all_commands = (domain_commands + host_commands + scheduler_commands +
device_commands + vnet_commands + acm_commands)
+####################################################################
+#
+# Help/usage printing functions
+#
+####################################################################
-def commandToHelp(cmd):
- return eval(cmd.replace("-", "_") + "_help")
-
-
-shorthelp = """Usage: xm <subcommand> [args]
- Control, list, and manipulate Xen guest instances
-
-xm common subcommands:
- """ + help_spacer.join(map(commandToHelp, short_command_list)) + """
-
-<DomName> can be substituted for <DomId> in xm subcommands.
-
-For a complete list of subcommands run 'xm help --long'
-For more help on xm see the xm(1) man page
-For more help on xm create, see the xmdomain.cfg(5) man page"""
-
-longhelp = """Usage: xm <subcommand> [args]
- Control, list, and manipulate Xen guest instances
-
-xm full list of subcommands:
-
- Domain Commands:
- """ + help_spacer.join(map(commandToHelp, domain_commands)) + """
-
- Xen Host Commands:
- """ + help_spacer.join(map(commandToHelp, host_commands)) + """
-
- Scheduler Commands:
- """ + help_spacer.join(map(commandToHelp, scheduler_commands)) + """
-
- Virtual Device Commands:
- """ + help_spacer.join(map(commandToHelp, device_commands)) + """
-
- Vnet commands:
- """ + help_spacer.join(map(commandToHelp, vnet_commands)) + """
-
- Access Control commands:
- """ + help_spacer.join(map(commandToHelp, acm_commands)) + """
-
-<DomName> can be substituted for <DomId> in xm subcommands.
+def cmdHelp(cmd):
+ """Print help for a specific subcommand."""
+
+ for fc in SUBCOMMAND_HELP.keys():
+ if fc[:len(cmd)] == cmd:
+ cmd = fc
+ break
+
+ try:
+ args, desc = SUBCOMMAND_HELP[cmd]
+ except KeyError:
+ shortHelp()
+ return
+
+ print 'Usage: xm %s %s' % (cmd, args)
+ print
+ print desc
+
+ try:
+ # If options help message is defined, print this.
+ for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]:
+ if shortopt and longopt:
+ optdesc = '%s, %s' % (shortopt, longopt)
+ elif shortopt:
+ optdesc = shortopt
+ elif longopt:
+ optdesc = longopt
+
+ wrapped_desc = wrap(desc, 43)
+ print ' %-30s %-43s' % (optdesc, wrapped_desc[0])
+ for line in wrapped_desc[1:]:
+ print ' ' * 33 + line
+ print
+ except KeyError:
+ # if the command is an external module, we grab usage help
+ # from the module itself.
+ if cmd in IMPORTED_COMMANDS:
+ try:
+ cmd_module = __import__(cmd, globals(), locals(), 'xen.xm')
+ cmd_usage = getattr(cmd_module, "help", None)
+ if cmd_usage:
+ print cmd_usage()
+ except ImportError:
+ pass
+
+def shortHelp():
+ """Print out generic help when xm is called without subcommand."""
+
+ print USAGE_HELP
+ print 'Common \'xm\' commands:\n'
+
+ for command in common_commands:
+ try:
+ args, desc = SUBCOMMAND_HELP[command]
+ except KeyError:
+ continue
+ wrapped_desc = wrap(desc, 50)
+ print ' %-20s %-50s' % (command, wrapped_desc[0])
+ for line in wrapped_desc[1:]:
+ print ' ' * 22 + line
+
+ print
+ print USAGE_FOOTER
+ print 'For a complete list of subcommands run \'xm help\'.'
+
+def longHelp():
+ """Print out full help when xm is called with xm --help or xm help"""
+
+ print USAGE_HELP
+ print 'xm full list of subcommands:\n'
+
+ for command in all_commands:
+ try:
+ args, desc = SUBCOMMAND_HELP[command]
+ except KeyError:
+ continue
-For a short list of subcommands run 'xm help'
-For more help on xm see the xm(1) man page
-For more help on xm create, see the xmdomain.cfg(5) man page"""
+ wrapped_desc = wrap(desc, 50)
+ print ' %-20s %-50s' % (command, wrapped_desc[0])
+ for line in wrapped_desc[1:]:
+ print ' ' * 22 + line
-# array for xm help <command>
-help = {
- "--long": longhelp
- }
+ print
+ print USAGE_FOOTER
-for command in all_commands:
- # create is handled specially
- if (command != 'create'):
- help[command] = commandToHelp(command)
+def usage(cmd = None):
+ """ Print help usage information and exits """
+ if cmd:
+ cmdHelp(cmd)
+ else:
+ shortHelp()
+ sys.exit(1)
####################################################################
@@ -293,7 +425,7 @@ def arg_check(args, name, lo, hi = -1):
if hi == -1:
if n != lo:
err("'xm %s' requires %d argument%s.\n" % (name, lo,
- lo > 1 and 's' or ''))
+ lo == 1 and '' or 's'))
usage(name)
else:
if n < lo or n > hi:
@@ -340,42 +472,67 @@ def err(msg):
def xm_save(args):
arg_check(args, "save", 2)
- dom = args[0] # TODO: should check if this exists
+ try:
+ dominfo = parse_doms_info(server.xend.domain(args[0]))
+ except xmlrpclib.Fault, ex:
+ raise ex
+
+ domid = dominfo['domid']
savefile = os.path.abspath(args[1])
if not os.access(os.path.dirname(savefile), os.W_OK):
err("xm save: Unable to create file %s" % savefile)
sys.exit(1)
- server.xend.domain.save(dom, savefile)
+ server.xend.domain.save(domid, savefile)
def xm_restore(args):
- arg_check(args, "restore", 1)
+ arg_check(args, "restore", 1, 2)
+
+ try:
+ (options, params) = getopt.gnu_getopt(args, 'p', ['paused'])
+ except getopt.GetoptError, opterr:
+ err(opterr)
+ sys.exit(1)
- savefile = os.path.abspath(args[0])
+ paused = False
+ for (k, v) in options:
+ if k in ['-p', '--paused']:
+ paused = True
+
+ if len(params) != 1:
+ err("Wrong number of parameters")
+ usage('restore')
+ sys.exit(1)
+
+ savefile = os.path.abspath(params[0])
if not os.access(savefile, os.R_OK):
err("xm restore: Unable to read file %s" % savefile)
sys.exit(1)
- server.xend.domain.restore(savefile)
+ server.xend.domain.restore(savefile, paused)
-def getDomains(domain_names):
+def getDomains(domain_names, state, full = 0):
if domain_names:
- return map(server.xend.domain, domain_names)
+ return [server.xend.domain(dom, full) for dom in domain_names]
else:
- return server.xend.domains(1)
+ return server.xend.domains_with_state(True, state, full)
def xm_list(args):
use_long = 0
show_vcpus = 0
show_labels = 0
+ state = 'all'
try:
- (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus','label'])
+ (options, params) = getopt.gnu_getopt(args, 'lv',
+ ['long','vcpus','label',
+ 'state='])
except getopt.GetoptError, opterr:
err(opterr)
+ usage('list')
sys.exit(1)
for (k, v) in options:
@@ -385,6 +542,12 @@ def xm_list(args):
show_vcpus = 1
if k in ['--label']:
show_labels = 1
+ if k in ['--state']:
+ state = v
+
+ if state != 'all' and len(params) > 0:
+ raise OptionError(
+ "You may specify either a state or a particular VM, but not both")
if show_vcpus:
print >>sys.stderr, (
@@ -392,7 +555,7 @@ def xm_list(args):
xm_vcpu_list(params)
return
- doms = getDomains(params)
+ doms = getDomains(params, state, use_long)
if use_long:
map(PrettyPrint.prettyprint, doms)
@@ -405,13 +568,16 @@ def xm_list(args):
def parse_doms_info(info):
def get_info(n, t, d):
return t(sxp.child_value(info, n, d))
+
+ def get_status(n, t, d):
+ return DOM_STATES[t(sxp.child_value(info, n, d))]
return {
- 'dom' : get_info('domid', int, -1),
+ 'domid' : get_info('domid', str, ''),
'name' : get_info('name', str, '??'),
- 'mem' : get_info('memory', int, 0),
+ 'mem' : get_info('memory_dynamic_max', int, 0),
'vcpus' : get_info('online_vcpus', int, 0),
- 'state' : get_info('state', str, '??'),
+ 'state' : get_info('state', str, ''),
'cpu_time' : get_info('cpu_time', float, 0),
'up_time' : get_info('up_time', float, -1),
'seclabel' : security.get_security_printlabel(info),
@@ -423,7 +589,7 @@ def parse_sedf_info(info):
return t(sxp.child_value(info, n, d))
return {
- 'dom' : get_info('domain', int, -1),
+ 'domid' : get_info('domid', int, -1),
'period' : get_info('period', int, -1),
'slice' : get_info('slice', int, -1),
'latency' : get_info('latency', int, -1),
@@ -431,34 +597,40 @@ def parse_sedf_info(info):
'weight' : get_info('weight', int, -1),
}
-
def xm_brief_list(doms):
- print 'Name ID Mem(MiB) VCPUs State Time(s)'
+ print '%-40s %3s %5s %5s %10s %9s' % \
+ ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)')
+
+ format = "%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s " \
+ "%(cpu_time)8.1f"
+
for dom in doms:
d = parse_doms_info(dom)
- print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f" % d)
-
+ print format % d
def xm_label_list(doms):
+ print '%-32s %3s %5s %5s %5s %9s %-8s' % \
+ ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
+
output = []
- print 'Name ID Mem(MiB) VCPUs State Time(s) Label'
+ format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
+ '%(cpu_time)8.1f %(seclabel)9s'
+
for dom in doms:
d = parse_doms_info(dom)
- l = "%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f " % d
if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
- if d['seclabel']:
- line = (l, d['seclabel'])
- else:
- line = (l, "ERROR")
+ if not d['seclabel']:
+ d['seclabel'] = 'ERROR'
elif security.active_policy in ['DEFAULT']:
- line = (l, "DEFAULT")
+ d['seclabel'] = 'DEFAULT'
else:
- line = (l, "INACTIVE")
- output.append(line)
+ d['seclabel'] = 'INACTIVE'
+ output.append((format % d, d['seclabel']))
+
#sort by labels
output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
- for l in output:
- print l[0] + l[1]
+ for line, label in output:
+ print line
def xm_vcpu_list(args):
@@ -469,7 +641,11 @@ def xm_vcpu_list(args):
doms = server.xend.domains(False)
dominfo = map(server.xend.domain.getVCPUInfo, doms)
- print 'Name ID VCPU CPU State Time(s) CPU Affinity'
+ print '%-32s %3s %5s %5s %5s %9s %s' % \
+ ('Name', 'ID', 'VCPUs', 'CPU', 'State', 'Time(s)', 'CPU Affinity')
+
+ format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \
+ ' %(cpu_time)8.1f %(cpumap)s'
for dom in dominfo:
def get_info(n):
@@ -563,11 +739,28 @@ def xm_vcpu_list(args):
c = "-"
s = "--p"
- print (
- "%(name)-32s %(domid)3d %(number)4d %(c)3s %(s)-3s %(cpu_time)7.1f %(cpumap)s" %
- locals())
+ print format % locals()
+def xm_start(args):
+ arg_check(args, "start", 1)
+ dom = args[0]
+ server.xend.domain.start(dom)
+def xm_delete(args):
+ arg_check(args, "delete", 1)
+ dom = args[0]
+ server.xend.domain.delete(dom)
+
+def xm_suspend(args):
+ arg_check(args, "suspend", 1)
+ dom = args[0]
+ server.xend.domain.suspend(dom)
+
+def xm_resume(args):
+ arg_check(args, "resume", 1)
+ dom = args[0]
+ server.xend.domain.resume(dom)
+
def xm_reboot(args):
arg_check(args, "reboot", 1, 3)
from xen.xm import shutdown
@@ -590,35 +783,75 @@ def xm_unpause(args):
server.xend.domain.unpause(dom)
+def xm_dump_core(args):
+ live = False
+ crash = False
+ try:
+ (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash'])
+ for (k, v) in options:
+ if k in ('-L', '--live'):
+ live = True
+ if k in ('-C', '--crash'):
+ crash = True
+
+ if len(params) not in (1, 2):
+ raise OptionError("Expects 1 or 2 argument(s)")
+ except getopt.GetoptError, e:
+ raise OptionError(str(e))
+
+ dom = params[0]
+ if len(params) == 2:
+ filename = os.path.abspath(params[1])
+ else:
+ filename = None
+
+ if not live:
+ server.xend.domain.pause(dom)
+
+ try:
+ print "Dumping core of domain: %s ..." % str(dom)
+ server.xend.domain.dump(dom, filename, live, crash)
+ finally:
+ if not live:
+ server.xend.domain.unpause(dom)
+
+ if crash:
+ print "Destroying domain: %s ..." % str(dom)
+ server.xend.domain.destroy(dom)
+
def xm_rename(args):
arg_check(args, "rename", 2)
-
+
server.xend.domain.setName(args[0], args[1])
-def xm_subcommand(command, args):
+def xm_importcommand(command, args):
cmd = __import__(command, globals(), locals(), 'xen.xm')
cmd.main([command] + args)
#############################################################
-def cpu_make_map(cpulist):
- cpus = []
- for c in cpulist.split(','):
- if c.find('-') != -1:
- (x,y) = c.split('-')
- for i in range(int(x),int(y)+1):
- cpus.append(int(i))
- else:
- cpus.append(int(c))
- cpus.sort()
- return cpus
-
def xm_vcpu_pin(args):
arg_check(args, "vcpu-pin", 3)
+ def cpu_make_map(cpulist):
+ cpus = []
+ for c in cpulist.split(','):
+ if c.find('-') != -1:
+ (x,y) = c.split('-')
+ for i in range(int(x),int(y)+1):
+ cpus.append(int(i))
+ else:
+ # remove this element from the list
+ if c[0] == '^':
+ cpus = [x for x in cpus if x != int(c[1:])]
+ else:
+ cpus.append(int(c))
+ cpus.sort()
+ return cpus
+
dom = args[0]
- vcpu = int(args[1])
+ vcpu = args[1]
cpumap = cpu_make_map(args[2])
server.xend.domain.pincpu(dom, vcpu, cpumap)
@@ -677,11 +910,12 @@ def xm_sched_sedf(args):
info['period'] = ns_to_ms(info['period'])
info['slice'] = ns_to_ms(info['slice'])
info['latency'] = ns_to_ms(info['latency'])
- print( ("%(name)-32s %(dom)3d %(period)9.1f %(slice)9.1f" +
+ print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" +
" %(latency)7.1f %(extratime)6d %(weight)6d") % info)
def domid_match(domid, info):
- return domid is None or domid == info['name'] or domid == str(info['dom'])
+ return domid is None or domid == info['name'] or \
+ domid == str(info['domid'])
# we want to just display current info if no parameters are passed
if len(args) == 0:
@@ -715,20 +949,26 @@ def xm_sched_sedf(args):
elif k in ['-w', '--weight']:
opts['weight'] = v
+ doms = filter(lambda x : domid_match(domid, x),
+ [parse_doms_info(dom)
+ for dom in getDomains(None, 'running')])
+
# print header if we aren't setting any parameters
if len(opts.keys()) == 0:
- print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s'%('Name','ID','Period(ms)',
- 'Slice(ms)', 'Lat(ms)',
- 'Extra','Weight')
-
- doms = filter(lambda x : domid_match(domid, x),
- [parse_doms_info(dom) for dom in getDomains("")])
+ print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \
+ ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)',
+ 'Extra','Weight')
+
for d in doms:
# fetch current values so as not to clobber them
- sedf_info = \
- parse_sedf_info(server.xend.domain.cpu_sedf_get(d['dom']))
- sedf_info['name'] = d['name']
+ try:
+ sedf_raw = server.xend.domain.cpu_sedf_get(d['domid'])
+ except xmlrpclib.Fault:
+ # domain does not support sched-sedf?
+ sedf_raw = {}
+ sedf_info = parse_sedf_info(sedf_raw)
+ sedf_info['name'] = d['name']
# update values in case of call to set
if len(opts.keys()) > 0:
for k in opts.keys():
@@ -738,7 +978,7 @@ def xm_sched_sedf(args):
v = map(int, [sedf_info['period'], sedf_info['slice'],
sedf_info['latency'],sedf_info['extratime'],
sedf_info['weight']])
- rv = server.xend.domain.cpu_sedf_set(d['dom'], *v)
+ rv = server.xend.domain.cpu_sedf_set(d['domid'], *v)
if int(rv) != 0:
err("Failed to set sedf parameters (rv=%d)."%(rv))
@@ -747,17 +987,14 @@ def xm_sched_sedf(args):
print_sedf(sedf_info)
def xm_sched_credit(args):
- usage_msg = """sched-credit: Set or get credit scheduler parameters
- Usage:
-
- sched-credit -d domain [-w weight] [-c cap]
- """
+ """Get/Set options for Credit Scheduler."""
+
try:
- opts, args = getopt.getopt(args[0:], "d:w:c:",
+ opts, params = getopt.getopt(args, "d:w:c:",
["domain=", "weight=", "cap="])
- except getopt.GetoptError:
- # print help information and exit:
- print usage_msg
+ except getopt.GetoptError, opterr:
+ err(opterr)
+ usage('sched-credit')
sys.exit(1)
domain = None
@@ -774,20 +1011,16 @@ def xm_sched_credit(args):
if domain is None:
# place holder for system-wide scheduler parameters
- print usage_msg
+ err("No domain given.")
+ usage('sched-credit')
sys.exit(1)
if weight is None and cap is None:
print server.xend.domain.sched_credit_get(domain)
else:
- if weight is None:
- weight = int(0)
- if cap is None:
- cap = int(~0)
-
- err = server.xend.domain.sched_credit_set(domain, weight, cap)
- if err != 0:
- print err
+ result = server.xend.domain.sched_credit_set(domain, weight, cap)
+ if result != 0:
+ err(str(result))
def xm_info(args):
arg_check(args, "info", 0)
@@ -801,13 +1034,46 @@ def xm_info(args):
print "%-23s:" % x[0], x[1]
def xm_console(args):
- arg_check(args, "console", 1)
+ arg_check(args, "console", 1, 2)
- dom = args[0]
- info = server.xend.domain(dom)
+ quiet = False;
+
+ try:
+ (options, params) = getopt.gnu_getopt(args, 'q', ['quiet'])
+ except getopt.GetoptError, opterr:
+ err(opterr)
+ sys.exit(1)
+
+ for (k, v) in options:
+ if k in ['-q', '--quiet']:
+ quiet = True
+ else:
+ assert False
+
+ if len(params) != 1:
+ err('No domain given')
+ usage('console')
+ sys.exit(1)
+
+ dom = params[0]
+
+ try:
+ info = server.xend.domain(dom)
+ except:
+ if quiet:
+ sys.exit(1)
+ else:
+ raise
domid = int(sxp.child_value(info, 'domid', '-1'))
+ if domid == -1:
+ if quiet:
+ sys.exit(1)
+ else:
+ raise Exception("Domain is not started")
+
console.execConsole(domid)
+
def xm_uptime(args):
short_mode = 0
@@ -821,14 +1087,14 @@ def xm_uptime(args):
if k in ['-s', '--short']:
short_mode = 1
- doms = getDomains(params)
+ doms = getDomains(params, 'running')
if short_mode == 0:
print 'Name ID Uptime'
for dom in doms:
d = parse_doms_info(dom)
- if d['dom'] > 0:
+ if d['domid'] > 0:
uptime = int(round(d['up_time']))
else:
f=open('/proc/uptime', 'r')
@@ -855,13 +1121,19 @@ def xm_uptime(args):
if short_mode:
now = datetime.datetime.now()
upstring = now.strftime(" %H:%M:%S") + " up " + upstring
- upstring += ", " + d['name'] + " (" + str(d['dom']) + ")"
+ upstring += ", " + d['name'] + " (" + str(d['domid']) + ")"
else:
upstring += ':%(seconds)02d' % vars()
- upstring = ("%(name)-32s %(dom)3d " % d) + upstring
+ upstring = ("%(name)-32s %(domid)3d " % d) + upstring
print upstring
+def xm_sysrq(args):
+ arg_check(args, "sysrq", 2)
+ dom = args[0]
+ req = args[1]
+ server.xend.domain.send_sysrq(dom, req)
+
def xm_top(args):
arg_check(args, "top", 0)
@@ -870,23 +1142,23 @@ def xm_top(args):
def xm_dmesg(args):
arg_check(args, "dmesg", 0, 1)
- gopts = Opts(use="""[-c|--clear]
-
-Read Xen's message buffer (boot output, warning and error messages) or clear
-its contents if the [-c|--clear] flag is specified.
-""")
-
- gopts.opt('clear', short='c',
- fn=set_true, default=0,
- use="Clear the contents of the Xen message buffer.")
- # Work around for gopts
- myargs = args
- myargs.insert(0, 'dmesg')
- gopts.parse(myargs)
- if not (1 <= len(myargs) <= 2):
- err('Invalid arguments: ' + str(myargs))
-
- if not gopts.vals.clear:
+ try:
+ (options, params) = getopt.gnu_getopt(args, 'c', ['clear'])
+ except getopt.GetoptError, opterr:
+ err(opterr)
+ sys.exit(1)
+
+ use_clear = 0
+ for (k, v) in options:
+ if k in ['-c', '--clear']:
+ use_clear = 1
+
+ if len(params) :
+ err("No parameter required")
+ usage('dmesg')
+ sys.exit(1)
+
+ if not use_clear:
print server.xend.node.dmesg.info()
else:
server.xend.node.dmesg.clear()
@@ -902,7 +1174,7 @@ def xm_serve(args):
from fcntl import fcntl, F_SETFL
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- s.connect(xen.xend.XendClient.XML_RPC_SOCKET)
+ s.connect(XendClient.XML_RPC_SOCKET)
fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK)
while True:
@@ -1048,7 +1320,7 @@ def parse_block_configuration(args):
cls = 'tap'
else:
cls = 'vbd'
-
+
vbd = [cls,
['uname', args[1]],
['dev', args[2]],
@@ -1057,19 +1329,12 @@ def parse_block_configuration(args):
vbd.append(['backend', args[4]])
# verify that policy permits attaching this resource
- try:
- if security.on():
- dominfo = server.xend.domain(dom)
- label = security.get_security_printlabel(dominfo)
- else:
- label = None
- security.res_security_check(args[1], label)
- except security.ACMError, e:
- print e.value
- sys.exit(1)
- except:
- traceback.print_exc(limit=1)
- sys.exit(1)
+ if security.on():
+ dominfo = server.xend.domain(dom)
+ label = security.get_security_printlabel(dominfo)
+ else:
+ label = None
+ security.res_security_check(args[1], label)
return (dom, vbd)
@@ -1165,15 +1430,21 @@ commands = {
# xenstat commands
"top": xm_top,
# domain commands
+ "delete": xm_delete,
"destroy": xm_destroy,
"domid": xm_domid,
"domname": xm_domname,
+ "dump-core": xm_dump_core,
+ "reboot": xm_reboot,
"rename": xm_rename,
"restore": xm_restore,
+ "resume": xm_resume,
"save": xm_save,
- "reboot": xm_reboot,
"shutdown": xm_shutdown,
+ "start": xm_start,
+ "sysrq": xm_sysrq,
"uptime": xm_uptime,
+ "suspend": xm_suspend,
"list": xm_list,
# memory commands
"mem-max": xm_mem_max,
@@ -1211,24 +1482,24 @@ commands = {
}
## The commands supported by a separate argument parser in xend.xm.
-subcommands = [
+IMPORTED_COMMANDS = [
'create',
+ 'new',
'migrate',
- 'sysrq',
'labels',
+ 'cfgbootpolicy',
+ 'makepolicy',
+ 'loadpolicy',
+ 'dumppolicy',
'addlabel',
'rmlabel',
'getlabel',
'dry-run',
'resources',
- 'cfgbootpolicy',
- 'makepolicy',
- 'loadpolicy',
- 'dumppolicy'
]
-for c in subcommands:
- commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
+for c in IMPORTED_COMMANDS:
+ commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
aliases = {
"balloon": "mem-set",
@@ -1246,11 +1517,18 @@ def xm_lookup_cmd(cmd):
elif aliases.has_key(cmd):
deprecated(cmd,aliases[cmd])
return commands[aliases[cmd]]
+ elif cmd == 'help':
+ longHelp()
+ sys.exit(0)
else:
- if len( cmd ) > 1:
- matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
- if len( matched_commands ) == 1:
- return matched_commands[0][1]
+ # simulate getopt's prefix matching behaviour
+ if len(cmd) > 1:
+ same_prefix_cmds = [commands[c] for c in commands.keys() \
+ if c[:len(cmd)] == cmd]
+ # only execute if there is only 1 match
+ if len(same_prefix_cmds) == 1:
+ return same_prefix_cmds[0]
+
err('Sub Command %s not found!' % cmd)
usage()
@@ -1258,27 +1536,18 @@ def deprecated(old,new):
print >>sys.stderr, (
"Command %s is deprecated. Please use xm %s instead." % (old, new))
-def usage(cmd=None):
- if cmd == 'create':
- mycmd = xm_lookup_cmd(cmd)
- mycmd( ['--help'] )
- sys.exit(1)
- if help.has_key(cmd):
- print " " + help[cmd]
- else:
- print shorthelp
- sys.exit(1)
-
def main(argv=sys.argv):
if len(argv) < 2:
usage()
-
- if re.compile('-*help').match(argv[1]):
- if len(argv) > 2:
- usage(argv[2])
- else:
- usage()
- sys.exit(0)
+
+ # intercept --help(-h) and output our own help
+ for help in ['--help', '-h']:
+ if help in argv[1:]:
+ if help == argv[1]:
+ longHelp()
+ else:
+ usage(argv[1])
+ sys.exit(0)
cmd = xm_lookup_cmd(argv[1])
@@ -1291,9 +1560,9 @@ def main(argv=sys.argv):
usage()
except socket.error, ex:
if os.geteuid() != 0:
- err("Most commands need root access. Please try again as root.")
+ err("Most commands need root access. Please try again as root.")
else:
- err("Error connecting to xend: %s. Is xend running?" % ex[1])
+ err("Unable to connect to xend: %s. Is xend running?" % ex[1])
sys.exit(1)
except KeyboardInterrupt:
print "Interrupted."
@@ -1302,16 +1571,16 @@ def main(argv=sys.argv):
if os.geteuid() != 0:
err("Most commands need root access. Please try again as root.")
else:
- err("Error connecting to xend: %s." % ex[1])
+ err("Unable to connect to xend: %s." % ex[1])
sys.exit(1)
except SystemExit:
sys.exit(1)
except xmlrpclib.Fault, ex:
- if ex.faultCode == xen.xend.XendClient.ERROR_INVALID_DOMAIN:
- print >>sys.stderr, (
- "Error: the domain '%s' does not exist." % ex.faultString)
+ if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
+ err("Domain '%s' does not exist." % ex.faultString)
else:
- print >>sys.stderr, "Error: %s" % ex.faultString
+ err(ex.faultString)
+ usage(argv[1])
sys.exit(1)
except xmlrpclib.ProtocolError, ex:
if ex.errcode == -1:
@@ -1326,6 +1595,15 @@ def main(argv=sys.argv):
except (ValueError, OverflowError):
err("Invalid argument.")
usage(argv[1])
+ sys.exit(1)
+ except OptionError, e:
+ err(str(e))
+ usage(argv[1])
+ print e.usage()
+ sys.exit(1)
+ except security.ACMError, e:
+ err(str(e))
+ sys.exit(1)
except:
print "Unexpected error:", sys.exc_info()[0]
print
diff --git a/tools/python/xen/xm/makepolicy.py b/tools/python/xen/xm/makepolicy.py
index 191566804d..1a81a14eaa 100644
--- a/tools/python/xen/xm/makepolicy.py
+++ b/tools/python/xen/xm/makepolicy.py
@@ -20,7 +20,7 @@
import sys
import traceback
from xen.util.security import ACMError, err, make_policy
-
+from xen.xm.opts import OptionError
def usage():
print "\nUsage: xm makepolicy <policy>\n"
@@ -29,22 +29,17 @@ def usage():
err("Usage")
-
def main(argv):
- try:
- if len(argv) != 2:
- usage()
- make_policy(argv[1])
-
- except ACMError:
- sys.exit(-1)
- except:
- traceback.print_exc(limit=1)
- sys.exit(-1)
-
+ if len(argv) != 2:
+ raise OptionError('No XML policy file specified')
+ make_policy(argv[1])
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/migrate.py b/tools/python/xen/xm/migrate.py
index 2b229c2632..b362ae9057 100644
--- a/tools/python/xen/xm/migrate.py
+++ b/tools/python/xen/xm/migrate.py
@@ -46,19 +46,17 @@ gopts.opt('resource', short='r', val='MBIT',
fn=set_int, default=0,
use="Set level of resource usage for migration.")
-def help(argv):
- gopts.argv = argv
- gopts.usage()
+def help():
+ return str(gopts)
def main(argv):
opts = gopts
args = opts.parse(argv)
- if opts.vals.help:
- opts.usage()
- return
+
if len(args) != 2:
- opts.usage()
- sys.exit(1)
+ raise OptionError('Invalid number of arguments')
+
dom = args[0]
dst = args[1]
- server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.resource, opts.vals.port)
+ server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.resource,
+ opts.vals.port)
diff --git a/tools/python/xen/xm/new.py b/tools/python/xen/xm/new.py
new file mode 100644
index 0000000000..fec2fc76e6
--- /dev/null
+++ b/tools/python/xen/xm/new.py
@@ -0,0 +1,68 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd
+#============================================================================
+
+import os
+import xmlrpclib
+
+from xen.xend import PrettyPrint
+from xen.xend import sxp
+from xen.xend import XendClient
+from xen.xend.XendClient import server
+
+from xen.xm.opts import *
+from xen.xm.create import *
+
+def make_unstarted_domain(opts, config):
+ """Create an unstarted domain.
+
+ @param opts: options
+ @param config: configuration
+ """
+ try:
+ server.xend.domain.new(config)
+ except xmlrpclib.Fault, ex:
+ import signal
+ if vncpid:
+ os.kill(vncpid, signal.SIGKILL)
+ if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN:
+ err("the domain '%s' does not exist." % ex.faultString)
+ else:
+ err("%s" % ex.faultString)
+ except Exception, ex:
+ import signal
+ if vncpid:
+ os.kill(vncpid, signal.SIGKILL)
+ err(str(ex))
+
+
+def main(argv):
+ try:
+ (opts, config) = parseCommandLine(argv)
+ except StandardError, ex:
+ err(str(ex))
+
+ if not opts:
+ return
+
+ if opts.vals.dryrun:
+ PrettyPrint.prettyprint(config)
+ else:
+ make_unstarted_domain(opts, config)
+
+if __name__ == '__main__':
+ main(sys.argv)
+
diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py
index e75af798ae..1eac629aa1 100644
--- a/tools/python/xen/xm/opts.py
+++ b/tools/python/xen/xm/opts.py
@@ -24,6 +24,42 @@ import os.path
import sys
import types
+def _line_wrap(text, width = 70):
+ lines = []
+ current_line = ''
+ words = text.strip().split()
+ while words:
+ word = words.pop(0)
+ if len(current_line) + len(word) + 1 < width:
+ current_line += word + ' '
+ else:
+ lines.append(current_line.strip())
+ current_line = word + ' '
+
+ if current_line:
+ lines.append(current_line.strip())
+ return lines
+
+def wrap(text, width = 70):
+ """ Really basic textwrap. Useful because textwrap is not available
+ for Python 2.2, and textwrap.wrap ignores newlines in Python 2.3+.
+ """
+ if len(text) < width:
+ return [text]
+
+ lines = []
+ for line in text.split('\n'):
+ lines += _line_wrap(line, width)
+ return lines
+
+class OptionError(Exception):
+ """Denotes an error in option parsing."""
+ def __init__(self, message, usage = ''):
+ self.message = message
+ self.usage = usage
+ def __str__(self):
+ return self.message
+
class Opt:
"""An individual option.
"""
@@ -72,7 +108,21 @@ class Opt:
def __repr__(self):
return self.name + '=' + str(self.specified_val)
- __str__ = __repr__
+ def __str__(self):
+ """ Formats the option into:
+ '-k, --key description'
+ """
+ PARAM_WIDTH = 20
+ if self.val:
+ keys = ', '.join(['%s=%s' % (k, self.val) for k in self.optkeys])
+ else:
+ keys = ', '.join(self.optkeys)
+ desc = wrap(self.use, 55)
+ if len(keys) > PARAM_WIDTH:
+ desc = [''] + desc
+
+ wrapped = ('\n' + ' ' * (PARAM_WIDTH + 1)).join(desc)
+ return keys.ljust(PARAM_WIDTH + 1) + wrapped
def set(self, value):
"""Set the option value.
@@ -243,8 +293,24 @@ class Opts:
def __repr__(self):
return '\n'.join(map(str, self.options))
- __str__ = __repr__
-
+ def __str__(self):
+ options = [s for s in self.options if s.optkeys[0][0] == '-']
+ output = ''
+ if options:
+ output += '\nOptions:\n\n'
+ output += '\n'.join([str(o) for o in options])
+ output += '\n'
+ return output
+
+ def val_usage(self):
+ optvals = [s for s in self.options if s.optkeys[0][0] != '-']
+ output = ''
+ if optvals:
+ output += '\nValues:\n\n'
+ output += '\n'.join([str(o) for o in optvals])
+ output += '\n'
+ return output
+
def opt(self, name, **args):
"""Add an option.
@@ -338,14 +404,14 @@ class Opts:
self.short_opts(),
self.long_opts())
except getopt.GetoptError, err:
- self.err(str(err))
+ raise OptionError(str(err), self.use)
+ #self.err(str(err))
for (k, v) in xvals:
for opt in self.options:
if opt.specify(k, v): break
else:
- print >>sys.stderr, "Error: Unknown option:", k
- self.usage()
+ raise OptionError('Unknown option: %s' % k, self.use)
if not args:
break
@@ -390,10 +456,10 @@ class Opts:
def usage(self):
print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
print
- for opt in self.options:
- opt.show()
- print
if self.options:
+ for opt in self.options:
+ opt.show()
+ print
print
def var_usage(self):
@@ -422,12 +488,16 @@ class Opts:
p = os.path.join(x, self.vals.defconfig)
else:
p = self.vals.defconfig
+ if not p.startswith('/'):
+ p = os.path.join(os.path.curdir, p)
if os.path.exists(p):
self.info('Using config file "%s".' % p)
self.load(p, help)
break
else:
- self.err('Cannot open config file "%s"' % self.vals.defconfig)
+ raise OptionError('Unable to open config file: %s' % \
+ self.vals.defconfig,
+ self.use)
def load(self, defconfig, help):
"""Load a defconfig file. Local variables in the file
@@ -450,6 +520,10 @@ class Opts:
exec cmd in globs, locs
try:
execfile(defconfig, globs, locs)
+ except SyntaxError,e:
+ raise SyntaxError, \
+ "Errors were found at line %d while processing %s:\n\t%s"\
+ %(e.lineno,defconfig,e.text)
except:
if not help: raise
if help:
@@ -478,9 +552,9 @@ def set_false(opt, k, v):
def set_bool(opt, k, v):
"""Set a boolean option.
"""
- if v in ['yes']:
+ if v in ('yes', 'y'):
opt.set(1)
- elif v in ['no']:
+ elif v in ('no', 'n'):
opt.set(0)
else:
opt.opts.err('Invalid value:' +v)
diff --git a/tools/python/xen/xm/resources.py b/tools/python/xen/xm/resources.py
index c3a83a5f29..52db568501 100644
--- a/tools/python/xen/xm/resources.py
+++ b/tools/python/xen/xm/resources.py
@@ -21,13 +21,12 @@
import sys
from xen.util import dictio
from xen.util import security
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm resource\n"
- print " This program lists information for each resource in the"
- print " global resource label file\n"
- security.err("Usage")
-
+def help():
+ return """
+ This program lists information for each resource in the
+ global resource label file."""
def print_resource_data(access_control):
"""Prints out a resource dictionary to stdout
@@ -38,24 +37,21 @@ def print_resource_data(access_control):
print " policy: "+policy
print " label: "+label
-
def main (argv):
+ if len(argv) > 1:
+ raise OptionError("No arguments required")
+
try:
- if len(argv) != 1:
- usage()
-
- try:
- file = security.res_label_filename
- access_control = dictio.dict_read("resources", file)
- except:
- security.err("Error reading resource file.")
-
- print_resource_data(access_control)
+ filename = security.res_label_filename
+ access_control = dictio.dict_read("resources", filename)
+ except:
+ raise OptionError("Resource file not found")
- except security.ACMError:
- sys.exit(-1)
+ print_resource_data(access_control)
if __name__ == '__main__':
- main(sys.argv)
-
-
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/rmlabel.py b/tools/python/xen/xm/rmlabel.py
index e9df1ad573..0869c6c874 100644
--- a/tools/python/xen/xm/rmlabel.py
+++ b/tools/python/xen/xm/rmlabel.py
@@ -21,33 +21,38 @@
import sys, os, re
from xen.util import dictio
from xen.util import security
+from xen.xm.opts import OptionError
-def usage():
- print "\nUsage: xm rmlabel dom <configfile>"
- print " xm rmlabel res <resource>\n"
- print " This program removes an acm_label entry from the 'configfile'"
- print " for a domain or from the global resource label file for a"
- print " resource. If the label does not exist for the given domain or"
- print " resource, then rmlabel fails.\n"
- security.err("Usage")
+def help():
+ return """
+ Example: xm rmlabel dom <configfile>
+ xm rmlabel res <resource>
+
+ This program removes an acm_label entry from the 'configfile'
+ for a domain or from the global resource label file for a
+ resource. If the label does not exist for the given domain or
+ resource, then rmlabel fails."""
def rm_resource_label(resource):
"""Removes a resource label from the global resource label file.
"""
+ #build canonical resource name
+ resource = security.unify_resname(resource)
+
# read in the resource file
file = security.res_label_filename
try:
access_control = dictio.dict_read("resources", file)
except:
- security.err("Resource file not found, cannot remove label!")
+ raise security.ACMError("Resource file not found, cannot remove label!")
# remove the entry and update file
if access_control.has_key(resource):
del access_control[resource]
dictio.dict_write(access_control, "resources", file)
else:
- security.err("Resource not labeled.")
+ raise security.ACMError("Resource not labeled")
def rm_domain_label(configfile):
@@ -55,7 +60,8 @@ def rm_domain_label(configfile):
fd = None
file = None
if configfile[0] == '/':
- fd = open(configfile, "rb")
+ file = configfile
+ fd = open(file, "rb")
else:
for prefix in [".", "/etc/xen"]:
file = prefix + "/" + configfile
@@ -63,8 +69,8 @@ def rm_domain_label(configfile):
fd = open(file, "rb")
break
if not fd:
- security.err("Configuration file '"+configfile+"' not found.")
-
+ raise OptionError("Configuration file '%s' not found." % configfile)
+
# read in the domain config file, removing label
ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
ac_exit_re = re.compile(".*'\].*")
@@ -84,7 +90,7 @@ def rm_domain_label(configfile):
# send error message if we didn't find anything to remove
if not removed:
- security.err("Domain not labeled.")
+ raise security.ACMError('Domain not labeled')
# write the data back out to the file
fd = open(file, "wb")
@@ -93,24 +99,25 @@ def rm_domain_label(configfile):
def main (argv):
- try:
- if len(argv) != 3:
- usage()
-
- if argv[1].lower() == "dom":
- configfile = argv[2]
- rm_domain_label(configfile)
- elif argv[1].lower() == "res":
- resource = argv[2]
- rm_resource_label(resource)
- else:
- usage()
- except security.ACMError:
- sys.exit(-1)
+ if len(argv) != 3:
+ raise OptionError('Requires 2 arguments')
+
+ if argv[1].lower() not in ('dom', 'res'):
+ raise OptionError('Unrecognised type argument: %s' % argv[1])
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ rm_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ rm_resource_label(resource)
if __name__ == '__main__':
- main(sys.argv)
+ try:
+ main(sys.argv)
+ except Exception, e:
+ sys.stderr.write('Error: %s\n' % str(e))
+ sys.exit(-1)
diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py
index 1fe7fbede5..a63c3523ca 100644
--- a/tools/python/xen/xm/shutdown.py
+++ b/tools/python/xen/xm/shutdown.py
@@ -120,7 +120,6 @@ def main(argv):
opts = gopts
args = opts.parse(argv)
if opts.vals.help:
- opts.usage()
return
if opts.vals.all:
main_all(opts, args)
diff --git a/tools/python/xen/xm/sysrq.py b/tools/python/xen/xm/sysrq.py
deleted file mode 100644
index 67db732757..0000000000
--- a/tools/python/xen/xm/sysrq.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# (C) Matthew Bloch <matthew@bytemark.co.uk> 2004
-# Copyright (C) 2005 XenSource Ltd
-
-"""Domain sysrq.
-"""
-
-from xen.xend.XendClient import server
-from xen.xm.opts import *
-
-gopts = Opts(use="""[DOM] [letter]
-
-Sends a Linux sysrq to a domain.
-""")
-
-gopts.opt('help', short='h',
- fn=set_true, default=0,
- use="Print this help.")
-
-def main(argv):
- opts = gopts
- args = opts.parse(argv)
- if opts.vals.help:
- opts.usage()
- return
-
- # no options for the moment
- if len(args) != 2:
- opts.usage()
- sys.exit(1)
- dom = args[0]
- req = ord(args[1][0])
- server.xend.domain.send_sysrq(dom, req)
diff --git a/tools/security/example.txt b/tools/security/example.txt
deleted file mode 100644
index c9afe88714..0000000000
--- a/tools/security/example.txt
+++ /dev/null
@@ -1,376 +0,0 @@
-##
-# example.txt <description to the xen access control architecture>
-#
-# Author:
-# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
-# 04/07/2006 update to using labels instead of ssidref
-#
-#
-# This file introduces into the tools to manage policies
-# and to label domains and resources.
-##
-
-We will show how to install and use the example one of the client_v1
-policies. Other policies work similarly. Feedback welcome!
-
-
-
-1. Using xm tools to translate example.chwall_ste.client_v1 policy:
-===================================================================
-
-#xm makepolicy example.chwall_ste.client_v1
-
-By default, the tool looks in directory /etc/xen/acm-security/policies
-for a directory that matches the policy name
-(here:example/chwall_ste/client_v1-security_policy.xml) to find the
-policy files. The '-d' option can be used to override the default
-/etc/xen/acm-security/policies policy-root directory.
-
-The default policy directory structure under /etc/xen/acm-security (and
-the Xen security tool build directory - tools/security) looks like:
-
-policies
-|-- security_policy.xsd
-|-- example
- |-- chwall
- | |-- client_v1-security_policy.xml
- |
- |-- chwall_ste
- | |-- client_v1-security_policy.xml
- |
- |-- ste
- |-- client_v1-security_policy.xml
-
-The security_policy.xsd file contains the schema against which the
-policy files must validate during translation.
-
-The policy files, ending in -security_policy.xml, define the policies,
-the types known to the policies, and the label definitions that group
-types together and make them easier to use for users.
-
-After executing the above 'xm makepolicy' command, you will find 2 new
-files in the /etc/xen/acm-security/policies/example/chwall_ste
-sub-directory:
-
- client_v1.map ... this file includes the mapping
- of names from the xml files into their binary code representation.
-
- client_v1.bin ... this is the binary policy file, the result of
- parsing the xml files and using the mapping to create a binary
- version that can be loaded into the hypervisor.
-
-
-
-2. Loading and activating the policy:
-=====================================
-
-We assume that xen is already configured for security;
-please refer to install.txt for instructions.
-
-To activate the policy from the command line:
-
-# xm loadpolicy example.chwall_ste.client_v1
-
-See install.txt for how to install a policy at boot time. This the
-recommended default. You can only load a policy if the currently
-enforced policy is "DEFAULT", a minimal startup policy, or if the
-currently enforced policy has the same name as the new one. Support
-for dynamic policy changes at run-time are a current working item.
-
-
-3. Labeling domains:
-====================
-
-a) Labeling Domain0:
-
-The chwall_ste-security_label_template.xml file includes an attribute
-"bootstrap", which is set to the label name that will be assigned to
-Dom0 (this label will be mapped to ssidref 1/1, the default for Dom0).
-
-b) Labeling User Domains (domains started from dom0 using xm commands):
-
-We distinguish two kinds of labels: a) VM labels (for domains) and RES
-Labels (for resources). We focus here on VM labels. Resource labels
-will be supported later.
-
-To list all available domain labels of a policy, use:
- #xm labels example.chwall_ste.client_v1
-
-To list all available labels including resource labels (their support
-is current work), use:
-
- #xm labels example.chwall_ste.client_v1 type=any
-
-The policy parameter is optional. The currently enforced hypervisor
-policy is used by default.
-
-If you would like to assign the dom_HomeBanking label to one of your user domains,
-look at the hypothetical domain configuration contained in /etc/xen/homebanking.xm:
-
- #------FOR HOME/ONLINE BANKING---------
- kernel = "/boot/vmlinuz-2.6.16-xen"
- ramdisk="/boot/U1_ramdisk.img"
- memory = 164
- name = "homebanking"
- vif=['']
- dhcp = "dhcp"
- #-------------------------
-
-Now we label this domain (policy name is optional, see above):
-
- # xm addlabel homebanking.xm dom_HomeBanking example.chwall_ste.client_v1
-
-The domain configuration should look now like:
-
- # cat homebanking.xm
- #------FOR HOME/ONLINE BANKING---------
- kernel = "/boot/vmlinuz-2.6.16-xen"
- ramdisk="/boot/U1_ramdisk.img"
- memory = 164
- name = "homebanking"
- vif=['']
- dhcp = "dhcp"
- access_control = ['policy=example.chwall_ste.client_v1, label=dom_HomeBanking']
-
-You can see the access_control line that was added to the
-configuration. This label will be translated into a local ssidref when
-a domain is created or resumed (also after migration and
-live-migration). The ssidref is a local security reference that is
-used inside the hypervisor instead of the security label for
-efficiency reasons. Since the same label can be mapped onto different
-ssidrefs in different policy translations (e.g., if the position of
-the label definition is changed in the policy file) or on different
-systems, the ssidref is re-calculated from the label each time a
-domain is instantiated or re-instantiated.
-
-Currently, the labels are not held in the hypervisor but only in
-.map files in the /etc/xen/acm-security/policies subdirectories. Only
-ssidrefs are known inside the hypervisr. This of course can change in
-the future.
-
-
-4. Starting a labeled domain
-============================
-
-Now, start the domain:
-
- #xm create homebanking.xm
- Using config file "homebanking.xm".
- Started domain fun
-
-
-[root@941e-4 VMconfigs]# xm list --label
-
-Name ID Mem(MiB) VCPUs State Time(s) Label
-fun 1 64 1 -b---- 5.9 dom_HomeBanking
-Domain-0 0 1954 1 r----- 1321.4 dom_SystemManagement
-
-
-
-If you label another domain configuration as dom_Fun and if
-you try to start it afterwards, this create will fail.
-
-Why? -- Because the running 'homebanking' domain has the chinese
-wall type "cw_Sensitive". The new domain 'fun' has the chinese wall
-label "cw_Distrusted". These domains are not allowed to run simultaneously
-on the same system because of the defined conflict set
-
- <conflictset name="Protection1">
- <type>cw_Sensitive</type>
- <type>cw_Distrusted</type>
- </conflictset>
-
-(in client_v1-security_policy.xml), which says that only one of the
-types cw_Sensitive and cw_Distrusted can run at a time.
-
-If you save or shutdown the 'homebanking' domain, you will be able to
-start the 'fun' domain. You can look into the Xen log to see if a
-domain was denied to start because of the access control framework
-with the command 'xm dmesg'.
-
-It is important (and usually non-trivial) to define the labels in a
-way that the semantics of the labels are enforced and supported by the
-types and the conflict sets. Usually, a workload abstraction seems
-helpful on the hypervisor level.
-
-Note: While the chinese wall policy enforcement is complete, the type
-enforcement is currently enforced inside the Xen hypervisor
-only. Therefore, only point-to-point sharing with regard to the type
-enforcement is currently controlled. Enforcing the STE policy while
-sharing virtual resources is ongoing work and assumed to be complete
-by year end as well as enforcing the STE policy for network traffic
-routed through dom0.
-
-
-5. Adding your own policies
-===========================
-
-Writing your own policy (e.g. "mypolicy.chwall.test") requires the policy
-definition (types etc.) and the label definitions. Any policy name
-must have chwall, ste, or chwall_ste in its name. This is used by the
-configuration tool to identify existing binary policy entries in the
-boot configuration file (menu.lst, grub.con). This part should, of
-course, be consistent with policy type that is defined.
-
-First, you create
-/etc/xen/acm-security/policies/mypolicy/chwall/test-security_policy.xml.
-
-You need to keep to the schema as defined in
-/etc/xen/acm-security/security_policy.xsd since the translation tools
-are written against this schema.
-
-You can hand-edit the xml files to create your policy or you can use the
-xensec_gen utility.
-
-
-6. Generating policy files using xensec_gen:
-============================================
-
-The xensec_gen utility starts a web-server that can be used to generate the
-XML policy files needed to create a policy.
-
-By default, xensec_gen runs as a daemon and listens on port 7777 for HTTP
-requests. The xensec_gen command supports command line options to change the
-listen port, run in the foreground, and a few others. Type 'xensec_gen -h'
-to see the full list of options available.
-
-Once the xensec_gen utility is running, point a browser at the host and port
-on which the utility is running (e.g. http://localhost:7777/). You will be
-presented with a web page that allows you to create or modify the XML policy
-file:
-
- - The Security Policy types section allows you to create or modify
- the policy types and conflict set definitions
-
- - The Security Policy Labeling section allows you to create or modify a
- label definitions
-
-The policy generation tool allows you to modify an existing policy
-definition or create a new policy definition file. To modify an
-existing policy definition, enter the full path to the existing file
-(the "Browse" button can be used to aid in this) in the Policy File
-entry field. To create a new policy definition file leave the Policy
-File entry field blank. At this point click the "Create" button to
-begin modifying or creating your policy definition.
-
- Security Policy Types Section
- -----------------------------
-
-You will then be presented with a web page. The upper part of it will
-allow you to create either Simple Type Enforcement types or Chinese
-Wall types or both, as well as Chinese Wall conflict type sets.
-
- As an example:
- - To add a Simple Type Enforcement type:
- - Enter the name of a new type under the Simple Type Enforcement Types
- section in the entry field above the "New" button.
- - Click the "New" button and the type will be added to the list of defined
- Simple Type Enforcement types.
- - To remove a Simple Type Enforcement type:
- - Click on the type to be removed in the list of defined Simple Type
- Enforcement types.
- - Click the "Delete" button to remove the type.
-
- Follow the same process to add Chinese Wall types. If you define Chinese Wall
- types you need to define at least one Chinese Wall Conflict Set. The Chinese
- Wall Conflict Set will allow you to add Chinese Wall types from the list of
- defined Chinese Wall types.
-
- Security Policy Labeling:
- -------------------------
-
- The security policy label section of the web page allows you to create labels
- for classes of virtual machines. The input policy type definitions on the upper
- part of the web page will provide the available types (Simple Type Enforcement
- and/or Chinese Wall) that can be assigned to a virtual machine class.
-
- As an example:
- - To add a Virtual Machine class (the name entered will become the label
- that will be used to identify the class):
- - Enter the name of a new class under the Virtual Machine Classes section
- in the entry field above the "New" button.
- - Click the "New" button and the class will be added to the table of defined
- Virtual Machine classes.
- - To remove a Virtual Machine class:
- - Click the "Delete" link associated with the class in the table of Virtual
- Machine classes.
-
- Once you have defined one or more Virtual Machine classes, you will be able to
- add any of the defined Simple Type Enforcement types or Chinese Wall types to a
- particular Virtual Machine.
-
- You must also define which Virtual Machine class is to be associated with the
- bootstrap domain (or Dom0 domain). By default, the first Virtual Machine class
- created will be associated as the bootstrap domain.
-
- To save your policy definition file, click on the "Generate XML" button
- on the top of the page. This will present you with a dialog box to save the
- generated XML file on your system. The default name will be
- security_policy.xml which you should change to follow the policy file
- naming conventions based on the policy name that you choose to use.
-
- To get a feel for the tool, you could use one of the example policy definitions
- files from /etc/xen/acm-security/policies/example as input.
-
-
-7. Hypervisor - OS Security Interface
-=====================================
-
-We currently provide 2 hypercalls through which user operating systems
-can interact with the hypervisor Access Control Module. Examples of
-using them are under "xen_root"/tools/security/python/xensec_tools:
-
-
-I) acm_getdecision -i domainid -l labelname
- Call this example script without arguments to show its usage
- information.
-
- This script enables a domain to retrieve an access control decision
- regarding the STE policy from the hypervisor. It will be used to
- control access to virtual/real resources in hosting domains.
-
- The script can be provided with any combination of domain ids or
- labelnames. Before calling into the hypervisor, labels are translated
- into ssidrefs. The hypervisor then retrieves for any domain id
- paramter the ssidref before deciding access.
-
- Example:
- #/etc/xen/acm-security/scripts/acm_getdecision -l dom_Fun
- -l dom_SystemManagement
- PERMITTED
-
- #/etc/xen/acm-security/scripts/acm_getdecision -i 0 -i 1
- PERMITTED
-
- #/etc/xen/acm-security/scripts/acm_getdecision -i 0 -l dom_Fun
- PERMITTED
-
- #/etc/xen/acm-security/scripts/acm_getdecision -i 0 -l no_label
- ACMError: Label 'nolabel' not found.
-
- Now, assume domain 123454 does not exist:
- #/etc/xen/acm-security/scripts/acm_getdecision -i 123454 -l dom_Fun
- ACMError: Cannot determine decision (Invalid parameter).
-
- Return values:
- * DENIED: access is denied based on the current hypervisor
- policy
-
- * PERMITTED: access is permitted based on the current
-
- * Exception ACMError: one of the parameters was illegal,
- i.e. an unknown label or a
- non-existing domain id
-
-I) acm_getlabel -i domainid
- Retrieves the label of a runing domain. This function can be used
- by domains to determine their own label or (if authorized) the label
- other domains.
-
- Example (result is broken up into different lines to simplify description):
- # /etc/xen/acm-security/scripts/acm_getlabel -i 0
- ('example.chwall.client_v1', <--- policy describing labels etc.
- 'dom_SystemManagement', <--- label name of the domain
- 'CHINESE WALL', <--- policy type
- 65537) <--- hypervisor internal ssidref
-
diff --git a/tools/security/install.txt b/tools/security/install.txt
deleted file mode 100644
index ebdf84f7d4..0000000000
--- a/tools/security/install.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-##
-# install.txt <description to the xen access control architecture>
-#
-# Author:
-# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
-# 03/18/2006 update: new labeling
-#
-#
-# This file shows how to activate and install the access control
-# framework for Xen.
-##
-
-
-INSTALLING A SECURITY POLICY IN XEN
-===================================
-
-By default, the access control architecture is disabled in Xen. To
-enable the access control architecture in Xen follow the steps below.
-This description assumes that you want to install the Chinese Wall and
-Simple Type Enforcement policy. Some file names need to be replaced
-below to activate the Chinese Wall OR the Type Enforcement policy
-exclusively (chwall_ste --> {chwall, ste}).
-
-0. build and install the xm man page. It includes the description of
- available management commands for the security policy for Xen and
- the labeling of domains. If not installed by default, you can make
- and install the xm man page as follows:
- # cd "xen_root"/doc
- # make install
- Then, use man xm to read it:
- # man xm
-
-1. enable access control in Xen
- # cd "xen_root"
- # edit/xemacs/vi Config.mk
-
- change the lines:
- ACM_SECURITY ?= n
- to:
- ACM_SECURITY ?= y
-
- Now the hypervisor will boot into the policy that is specified
- in the grub configuration. If you would like to boot into a
- specific policy (even if you can't specify a boot policy but
- need to set the policy later using the 'xensec_tool
- loadpolicy'), then use the other config parameter to change
- from NULL to any other default policy, e.g.:
- ACM_DEFAULT_SECURITY_POLICY ?= ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY
-
- # make dist
- # ./install.sh
-
-2. Build acm and policy tools and create boot-able policy:
- # cd tools/security
- # make install
-
- For description of the following commands, please see the xm
- man page (docs/man1/xm.1). If it is not built, then you can
- create it manually: cd "xen_root"/docs; make; man man1/xm.1
-
- Step1: Building binary version of an example policy:
- # xm makepolicy example.chwall_ste.client_v1
- # xm cfgbootpolicy example.chwall_ste.client_v1
-
- Please verify boot entry in /boot/grub/grub.conf (or menu.lst):
- title Xen (2.6.16)
- root (hd0,0)
- kernel /xen.gz dom0_mem=2000000 console=vga
- module /vmlinuz-2.6.16-xen ro root=/dev/VolGroup00/LogVol00 rhgb
- module /initrd-2.6.165-xen-U.img
- module /example.chwall_ste.client_v1.bin
-
-3. reboot into the newly compiled hypervisor
-
- after boot
- # xm dmesg should show an entry about the policy being loaded
- during the boot process
-
- # xm dumppolicy
- should print the new binary policy representation
- including the policy name example.chwall_ste.client_v1
-
- # xm list --label
- should show security label names behind the running domains
-
-For more information about how to use the security-enabled Xen, see
-the examples.txt file in this directory.
diff --git a/tools/security/policy.txt b/tools/security/policy.txt
index 4888577a1a..493d1f2e55 100644
--- a/tools/security/policy.txt
+++ b/tools/security/policy.txt
@@ -1,131 +1,13 @@
##
-# policy.txt <description to the Xen access control architecture>
+# policy.txt <description to the sHype/Xen access control architecture>
#
# Author:
-# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
+# Reiner Sailer 08/30/2006 <sailer@watson.ibm.com>
#
#
-# This file gives an overview of the security policies currently
-# provided and also gives some reasoning about how to assign
-# labels to domains.
+# This file gives an overview of the example security policies.
##
-Xen access control policies
-
-
-General explanation of supported security policies:
-=====================================================
-
-We have implemented the mandatory access control architecture of our
-hypervisor security architecture (sHype) for the Xen hypervisor. It
-controls communication (in Xen: event channels, grant tables) between
-Virtual Machines (from here on called domains) and through this the
-virtual block devices, networking, and shared memory are implemented
-on top of these communication means. While we have implemented the
-described policies and access control architecture for other
-hypervisor systems, we will describe below specifically its
-implementation and use in the Xen hypervisor. The policy enforcement
-is called mandatory regarding user domains since the policy it is
-given by the security administration and enforced independently of the
-user domains by the Xen hypervisor in cooperation with the domain
-management.
-
-The access control architecture consists of three parts:
-
-i) The access control policy determines the "command set" of the ACM
-and the hooks with which they can be configured to constrain the
-sharing of virtual resources. The current access control architecture
-implemented for Xen supports two policies: Chinese Wall and Simple
-Type Enforcement, which we describe in turn below.
-
-
-ii) The actually enforced policy instantiation uses the policy
-language (i) to configure the Xen access control in a way that suits
-the specific application (home desktop environment, company desktop,
-Web server system, etc.). We have defined an exemplary policy
-instantiation for Chinese Wall (chwall policy) and Simple Type
-Enforcement (ste policy) for a desktop system. We offer these policies
-in combination since they are controlling orthogonal events.
-
-
-iii) The access control module (ACM) and related hooks are part of the
-core hypervisor and their controls cannot be bypassed by domains. The
-ACM and hooks are the active security components. We refer to
-publications that describe how access control is enforced in the Xen
-hypervisor using the ACM (access decision) and the hooks (decision
-enforcement) inserted into the setup of event channels and grant
-tables, and into domain operations (create, destroy, save, restore,
-migrate). These controls decide based on the active policy
-configuration (see i. and ii.) if the operation proceeds of if the
-operation is aborted (denied).
-
-In general, security policy instantiations in the Xen access control
-framework are defined by XML policy files. Each security policy has
-exactly one file including all the information the hypervisor needs to
-enforce the policy.
-
-The name of a policy is unique and consists of a colon-separated list
-of names, which can be translated into the location (subtree) where
-this policy must be located. The last part of the name is the file
-name pre-fix for the policy xml file. The preceding name parts are
-translated into the local path relative to the global policy root
-(/etc/xen/acm-security/policies) pointing to the policy xml file. For
-example: example.chwall_ste.client_v1 denotes the policy file
-example/chwall_ste/client_v1-security_policy.xml relative to the
-global policy root directory.
-
-Every security policy has its own sub-directory under the global
-policy root directory /etc/xen/acm-security/policies, which is
-installed during the Xen installation or can be manually installed
-(when switching from a "security disabled" Xen to a "security enabled"
-Xen AFTER configuring security, see install.txt) by the command
-sequence:
-
- cd "Xen-root"/tools/security/policies; make install
-
-We will describe those files for our example policy (Chinese Wall and
-Simple Type Enforcement) in more detail as we go along. Eventually, we
-will move towards a system installation where the policies will reside
-under /etc.
-
-
-CHINESE WALL
-============
-
-The Chinese Wall policy enables the user to define "which workloads
-(domain payloads) cannot run on a single physical system at the same
-time". Why would we want to prevent workloads from running at the same
-time on the same system? This supports requirements that can (but
-don't have to) be rooted in the measure of trust into the isolation of
-different domains that share the same hardware. Since the access
-control architecture aims at high performance and non-intrusive
-implementation, it currently does not address covert (timing) channels
-and aims at medium assurance. Users can apply the Chinese Wall policy
-to guarantee an air-gap between very sensitive payloads both regarding
-covert information channels and regarding resource starvation.
-
-To enable the CW control, each domain is labeled with a set of Chinese
-Wall types and CW Conflict Sets are defined which include those CW
-types that cannot run simultaneously on the same hardware. This
-interpretation of conflict sets is the only policy rule for the Chines
-Wall policy.
-
-This is enforced by controlling the start of domains according to
-their assigned CW worload types. Domains with Chinese Wall types that
-appear in a common conflict set are running mutually exclusive on a
-platform, i.e., once a domain with one of the cw-types of a conflict
-set is running, no domain with another cw-type of the same conflict
-set can start until the first domain is destroyed, paused, or migrated
-away from the physical system (this assumes that such a partition can
-no longer be observed). The idea is to assign cw-types according to
-the type of payload that a domain runs and to use the Chinese Wall
-policy to ensure that payload types can be differentiated by the
-hypervisor and can be prevented from being executed on the same system
-at the same time. Using the flexible CW policy maintains system
-consolidation and workload-balancing while introducing guaranteed
-constraints where necessary.
-
-
Example of a Chinese Wall Policy Instantiation
----------------------------------------------
@@ -233,13 +115,12 @@ Currently in Xen, Dom0 controls all hardware, needs to communicate
with all domains during their setup, and intercepts all communication
between domains. Consequently, Dom0 needs to be assigned all types
used and must be completely trusted to maintain the separation of
-informatio ncoming from domains with different STE types. Thus a
+information coming from domains with different STE types. Thus a
refactoring of Dom0 is recommended for stronger confinement
guarantees.
Domain --> RESOURCES Access
'''''''''''''''''''''''''''
-(current work)
We define for each resource that we want to distinguish a separate STE
type. Each STE type is assigned to the respective resource and to
@@ -266,8 +147,7 @@ maximum security benefit from sHype.
Example of a Simple Type Enforcement Policy Instantiation
---------------------------------------------------------
-
-We define the following types:
+The example policies define the following types:
* ste_SystemManagement identifies workloads (and domains that runs
them) that must share information to accomplish the management of the
@@ -384,19 +264,18 @@ Xen components and these components use a single consistent policy to
co-operatively enforce the policy. In the storage domain example, we
have three components that co-operate:
-1. The ACM module inside the hypervisor enforces: communication between
-user domains and the storage domain (only domains including types
-ste_PersonalFinances or ste_InternetInsecure can communicate with the
-storage domain and request access to logical resource). This confines
-the sharing to the types assigned to the storage domain.
+1. The ACM module inside the hypervisor enforces: communication
+between user domains and the storage domain (only domains including
+types ste_PersonalFinances or ste_InternetInsecure can communicate
+with the storage domain and request access to logical resource). This
+confines the sharing to the types assigned to the storage domain.
-2. The domain management will enforce (work in progress): assignment of
-real resources (hda) to domains (storage domain) that share a
-type with the resource.
+2. The domain management enforces: assignment of real resources (hda)
+to domains (storage domain) that share a type with the resource.
-3. If the storage domain serves multiple STE types (as in our example),
-it enforces (work in progress): that domains can access (mount)
-logical resources only if they share an STE type with the respective
+3. If the storage domain serves multiple STE types (as in our
+example), it enforces: that domains can access (mount) logical
+resources only if they share an STE type with the respective
resource. In our example, domains with the STE type
ste_PersonalFinances can request access (mount) to logical resource
hda1 from the storage domain.
@@ -406,8 +285,8 @@ see the minimal set of types assigned to our domain manageing disk
drive hda for serving logical disk partitions exclusively to
dom_HomeBanking and dom_Fun.
-Similary, network domains can confine access to the network or
-network communication between user domains.
+Similary, network domains can confine access to the network or network
+communication between user domains.
As a result, device domains (e.g., storage domain, network domain)
must be simple and small to ensure their correct co-operation in the
diff --git a/tools/security/policytools.txt b/tools/security/policytools.txt
new file mode 100644
index 0000000000..fb863f4722
--- /dev/null
+++ b/tools/security/policytools.txt
@@ -0,0 +1,148 @@
+##
+# policytools.txt
+# <description to the sHype/Xen policy management tools>
+#
+# Author:
+# Reiner Sailer 08/31/2006 <sailer@watson.ibm.com>
+#
+#
+##
+
+This file describes the Xen-tools to create and maintain security
+policies for the sHype/Xen access control module.
+
+A security policy (e.g. "example.chwall_ste.test") is defined in
+XML. Read in the user manual about the naming of policies. The policy
+name is used by the Xen management tools to identify existing
+policies. Creating the security policy means creating a policy
+description in XML:
+/etc/xen/acm-security/policies/example/chwall_ste/test-security_policy.xml.
+
+The policy XML description must follow the XML schema definition in
+/etc/xen/acm-security/policies/security_policy.xsd. The policy tools
+are written against this schema; they will create and refine policies
+that conform to this scheme.
+
+Two tools are provided to help creating security policies:
+
+
+1. xensec_ezpolicy: The starting point for writing security policies.
+===================
+
+This wxPython-based GUI tool is meant to create very quickly a
+starting point for a workload protection security policy. Please start
+the tool (xensec_ezpolicy) and press <CTRL-h> for usage explanations.
+The Xen User guide explains its usage at an example in chapter
+"sHype/Xen Access Control".
+
+The output of the tool is a security policy that is fully operable. It
+is sufficient to create policies that demonstrate how sHype/ACM works.
+
+However, it defines only a basic set of security labels assuming that
+Domain0 hosts and virtualizes all hardware (storage etc.). Use
+xensec_gen to refine this policy and tailor it to your requirements.
+
+
+2. xensec_gen: The tool to refine a basic security policy:
+==============
+
+The xensec_gen utility starts a web-server that can be used to
+generate the XML policy files needed to create or maintain a
+policy. It can be pre-loaded with a policy file created by
+xensec_ezpolicy.
+
+By default, xensec_gen runs as a daemon and listens on port 7777 for
+HTTP requests. The xensec_gen command supports command line options
+to change the listen port, run in the foreground, and a few others.
+Type 'xensec_gen -h' to see the full list of options available.
+
+Once the xensec_gen utility is running, point a browser at the host
+and port on which the utility is running (e.g. http://localhost:7777).
+You will be presented with a web page that allows you to create or
+modify the XML policy file:
+
+ - The Security Policy types section allows you to create or modify
+the policy types and conflict set definitions
+
+ - The Security Policy Labeling section allows you to create or
+modify label definitions
+
+The policy generation tool allows you to modify an existing policy
+definition or create a new policy definition file. To modify an
+existing policy definition, enter the full path to the existing file
+(the "Browse" button can be used to aid in this) in the Policy File
+entry field. To create a new policy definition file leave the Policy
+File entry field blank. At this point click the "Create" button to
+begin modifying or creating your policy definition.
+
+ Security Policy Types Section
+ -----------------------------
+
+You will then be presented with a web page. The upper part of it will
+allow you to create either Simple Type Enforcement types or Chinese
+Wall types or both, as well as Chinese Wall conflict sets.
+
+As an example, to add a Simple Type Enforcement type:
+
+- Enter the name of a new type under the Simple Type Enforcement Types
+section in the entry field above the "New" button.
+
+- Click the "New" button and the type will be added to the list of
+defined Simple Type Enforcement types.
+
+To remove a Simple Type Enforcement type:
+
+- Click on the type to be removed in the list of defined Simple Type
+Enforcement types.
+
+- Click the "Delete" button to remove the type.
+
+Follow the same process to add Chinese Wall types. The Chinese Wall
+Conflict Set allows you to add Chinese Wall types from the list of
+defined Chinese Wall types.
+
+
+ Security Policy Labels:
+ -------------------------
+
+The security policy label section of the web page allows you to create
+labels for classes of virtual machines and resources. The input
+policy type definitions on the upper part of the web page will provide
+the available types (Simple Type Enforcement and/or Chinese Wall) that
+can be assigned to a virtual machine class. Resource classes only
+include simple type enforcement types; the Chinese Wall policy does
+apply only to virtual machines.
+
+As an example, to add a Virtual Machine class (the name entered will
+become the label that will be used to identify the class):
+
+- Enter the name of a new class under the Virtual Machine Classes
+section in the entry field above the "New" button.
+
+- Click the "New" button and the class will be added to the table of
+defined Virtual Machine classes.
+
+To remove a Virtual Machine class:
+
+- Click the "Delete" link associated with the class in the table of
+Virtual Machine classes.
+
+Once you have defined one or more Virtual Machine classes, you will
+be able to add any of the defined Simple Type Enforcement types or
+Chinese Wall types to a particular Virtual Machine.
+
+If you create a new policy, you must also define which Virtual Machine
+class is to be associated with the bootstrap domain (or Dom0 domain).
+By default, the first Virtual Machine class created will be associated
+as the bootstrap domain.
+
+To save your policy definition file, click on the "Generate XML"
+button on the top of the page. This will present you with a dialog
+box to save the generated XML file on your system. The default name
+will be security_policy.xml which you should change to follow the
+policy file naming conventions based on the policy name that you
+choose to use.
+
+To get a feel for the tool, you could use one of the example policy
+definitions files from /etc/xen/acm-security/policies/example as
+input or a policy created by the xensec_ezpolicy tool.
diff --git a/tools/security/readme.txt b/tools/security/readme.txt
index 9d8e18a4ec..991359a53a 100644
--- a/tools/security/readme.txt
+++ b/tools/security/readme.txt
@@ -1,34 +1,33 @@
##
-# readme.txt <description to the xen access control architecture>
+# readme.txt <description to the sHype/Xen access control architecture>
#
# Author:
-# Reiner Sailer 08/15/2005 <sailer@watson.ibm.com>
+# Reiner Sailer 08/30/2006 <sailer@watson.ibm.com>
#
#
# This file is a toc for information regarding
# the access control policy and tools in Xen.
##
-1. 'xm' man page
+1. Xen User Guide
- describes the commands related to Xen management, including the
- commands to manage security policies and labels. Read the access
- control subcommand section of the xm manual first. If it is not
- built by default, check install.txt.
+ describes how to configure, install, and deploy the sHype Access
+ Control Module in Xen. See chapter "sHype/Xen Access Control".
-2. policy.txt:
+2. 'xm' man page
- describes the general reasoning and examples for access
- control policies in Xen
+ describes the commands related to Xen management, including the
+ commands to manage security policies and labels. Read the access
+ control subcommand section of the xm manual first.
+3. policy.txt
-3. install.txt
+ describes examples for access control policies in Xen. First read
+ the policy description in the Xen User Guide.
- describes the activation of the access control framework
- in Xen
-4. example.txt
+4. policytools.txt
- describes the available tools for managing security policies
- in Xen and the tools to label domains
+ describes the available tools for creating and managing security
+ policies in Xen.
diff --git a/tools/security/secpol_tool.c b/tools/security/secpol_tool.c
index 901beae9d5..470de4f25b 100644
--- a/tools/security/secpol_tool.c
+++ b/tools/security/secpol_tool.c
@@ -43,6 +43,8 @@
fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
errno, strerror(errno))
+#define ALIGN8(x) (void *)(((long)(x) + 7) & ~7)
+
void usage(char *progname)
{
printf("Usage: %s ACTION\n"
@@ -182,14 +184,14 @@ void acm_dump_policy_buffer(void *buf, int buflen)
ntohl(pol->secondary_buffer_offset));
switch (ntohl(pol->primary_policy_code)) {
case ACM_CHINESE_WALL_POLICY:
- acm_dump_chinesewall_buffer(buf +
- ntohl(pol->primary_buffer_offset),
+ acm_dump_chinesewall_buffer(ALIGN8(buf +
+ ntohl(pol->primary_buffer_offset)),
ntohl(pol->len) -
ntohl(pol->primary_buffer_offset));
break;
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
- acm_dump_ste_buffer(buf + ntohl(pol->primary_buffer_offset),
+ acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->primary_buffer_offset)),
ntohl(pol->len) -
ntohl(pol->primary_buffer_offset));
break;
@@ -204,14 +206,14 @@ void acm_dump_policy_buffer(void *buf, int buflen)
switch (ntohl(pol->secondary_policy_code)) {
case ACM_CHINESE_WALL_POLICY:
- acm_dump_chinesewall_buffer(buf +
- ntohl(pol->secondary_buffer_offset),
+ acm_dump_chinesewall_buffer(ALIGN8(buf +
+ ntohl(pol->secondary_buffer_offset)),
ntohl(pol->len) -
ntohl(pol->secondary_buffer_offset));
break;
case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
- acm_dump_ste_buffer(buf + ntohl(pol->secondary_buffer_offset),
+ acm_dump_ste_buffer(ALIGN8(buf + ntohl(pol->secondary_buffer_offset)),
ntohl(pol->len) -
ntohl(pol->secondary_buffer_offset));
break;
diff --git a/tools/security/secpol_xml2bin.c b/tools/security/secpol_xml2bin.c
index 477991f28c..c316250e41 100644
--- a/tools/security/secpol_xml2bin.c
+++ b/tools/security/secpol_xml2bin.c
@@ -979,13 +979,15 @@ unsigned char *write_policy_reference_binary(u_int32_t * len_pr)
unsigned char *buf, *ptr;
struct acm_policy_reference_buffer *pr_header;
u_int32_t len;
+ u_int32_t name_len;
if (policy_reference_name == NULL) {
printf("ERROR: No policy reference name found.\n");
exit(EXIT_FAILURE);
}
- len = (sizeof(struct acm_policy_reference_buffer) +
- strlen(policy_reference_name) + 1);
+ name_len = strlen(policy_reference_name) + 1; /* strend '\0' */
+ len = sizeof(struct acm_policy_reference_buffer) + name_len;
+ len = (len + 7) & ~7; /* Alignment. */
buf = malloc(len);
ptr = buf;
@@ -994,9 +996,9 @@ unsigned char *write_policy_reference_binary(u_int32_t * len_pr)
("ERROR: out of memory allocating label reference buffer.\n");
exit(EXIT_FAILURE);
}
+ memset (buf, 0, len);
pr_header = (struct acm_policy_reference_buffer *) buf;
- pr_header->len =
- htonl(strlen(policy_reference_name) + 1 /* strend \'0' */ );
+ pr_header->len = htonl(name_len);
ptr += sizeof(struct acm_policy_reference_buffer);
strcpy((char *) ptr, policy_reference_name);
diff --git a/tools/vnet/doc/Makefile b/tools/vnet/doc/Makefile
index 67f70ab68d..38accfa7f6 100644
--- a/tools/vnet/doc/Makefile
+++ b/tools/vnet/doc/Makefile
@@ -1,12 +1,11 @@
#!/usr/bin/make -f
# -*- mode: Makefile; -*-
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
VERSION = 1.0
HEADER = Vnet
-INSTALL = install
-INSTALL_DIR = $(INSTALL) -d -m0755
-
PS2PDF := ps2pdf
DVIPS := dvips
LATEX := latex
diff --git a/tools/vnet/doc/man/vn.pod.1 b/tools/vnet/doc/man/vn.pod.1
index d204ed7f66..6d4d550f76 100644
--- a/tools/vnet/doc/man/vn.pod.1
+++ b/tools/vnet/doc/man/vn.pod.1
@@ -105,7 +105,7 @@ the vnet device to it.
=item B<-v | --vnetif> I<vnetifname>
Use I<vnetifname> as the name for the vnet device. If this option
-is not specified the default isto name the device vnifN where N
+is not specified the default is to name the device vnifN where N
is the last field of the vnet id as 4 hex characters.
For example vnif0004. Network device names can be at
most 14 characters.
@@ -173,4 +173,4 @@ Copyright (C) 2006 Mike Wray <mike.wray@hp.com>.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version. \ No newline at end of file
+(at your option) any later version.
diff --git a/tools/vnet/examples/Makefile b/tools/vnet/examples/Makefile
index ba605ca318..c3aab0c70e 100644
--- a/tools/vnet/examples/Makefile
+++ b/tools/vnet/examples/Makefile
@@ -1,9 +1,7 @@
# -*- mode: Makefile; -*-
#============================================================================
-
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
XEN_SCRIPT_DIR = $(DESTDIR)/etc/xen/scripts
diff --git a/tools/vnet/libxutil/Makefile b/tools/vnet/libxutil/Makefile
index 757e5567d6..80cbe4443e 100644
--- a/tools/vnet/libxutil/Makefile
+++ b/tools/vnet/libxutil/Makefile
@@ -3,11 +3,6 @@ export VNET_ROOT = $(shell cd .. && pwd)
include $(VNET_ROOT)/Make.env
endif
-INSTALL = install
-INSTALL_DATA = $(INSTALL) -m0644
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
include $(XEN_ROOT)/tools/Rules.mk
LIB_SRCS :=
@@ -30,6 +25,8 @@ LIB_OBJS := $(LIB_SRCS:.c=.o)
PIC_OBJS := $(LIB_SRCS:.c=.opic)
CFLAGS += -Werror -fno-strict-aliasing
+CFLAGS += -O3
+#CFLAGS += -g
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
@@ -58,7 +55,7 @@ libxutil.so.$(MAJOR): libxutil.so.$(MAJOR).$(MINOR)
ln -sf $^ $@
libxutil.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
- $(CC) $(CFLAGS) -Wl,-soname -Wl,libxutil.so.$(MAJOR) -shared -o $@ $^
+ $(CC) $(CFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxutil.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^
libxutil.a: $(LIB_OBJS)
$(AR) rc $@ $^
diff --git a/tools/vnet/libxutil/hash_table.c b/tools/vnet/libxutil/hash_table.c
index e1630dc187..1e2af26bb0 100644
--- a/tools/vnet/libxutil/hash_table.c
+++ b/tools/vnet/libxutil/hash_table.c
@@ -116,7 +116,7 @@ acceptable. Do NOT use for cryptographic purposes.
--------------------------------------------------------------------
*/
-ub4 hash(const ub1 *k, ub4 length, ub4 initval)
+static inline ub4 _hash(const ub1 *k, ub4 length, ub4 initval)
//register ub1 *k; /* the key */
//register ub4 length; /* the length of the key */
//register ub4 initval; /* the previous hash, or an arbitrary value */
@@ -160,6 +160,11 @@ ub4 hash(const ub1 *k, ub4 length, ub4 initval)
/*-------------------------------------------- report the result */
return c;
}
+
+ub4 hash(const ub1 *k, ub4 length, ub4 initval){
+ return _hash(k, length, initval);
+}
+
/*============================================================================*/
/** Get the bucket for a hashcode in a hash table.
@@ -381,6 +386,9 @@ inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
* @return 1 if equal, 0 otherwise
*/
inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
+ if(table->key_size){
+ return memcmp(key1, key2, table->key_size) == 0;
+ }
return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1 == key2);
}
@@ -393,6 +401,9 @@ inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
* @return hashcode
*/
inline Hashcode HashTable_key_hash(HashTable *table, void *key){
+ if(table->key_size){
+ return _hash(key, table->key_size, 0);
+ }
return (table->key_hash_fn
? table->key_hash_fn(key)
: hash_hvoid(0, &key, sizeof(key)));
diff --git a/tools/vnet/libxutil/hash_table.h b/tools/vnet/libxutil/hash_table.h
index 84a135a357..beae2fb05e 100644
--- a/tools/vnet/libxutil/hash_table.h
+++ b/tools/vnet/libxutil/hash_table.h
@@ -96,6 +96,7 @@ struct HashTable {
int buckets_n;
/** Number of entries in the table. */
int entry_count;
+ unsigned long key_size;
/** Function to free keys and values in entries. */
TableFreeFn *entry_free_fn;
/** Function to hash keys. */
diff --git a/tools/vnet/scripts/Makefile b/tools/vnet/scripts/Makefile
index 077d6b6224..24f6f35880 100644
--- a/tools/vnet/scripts/Makefile
+++ b/tools/vnet/scripts/Makefile
@@ -1,9 +1,7 @@
# -*- mode: Makefile; -*-
#============================================================================
-
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
SBIN_DIR = $(DESTDIR)/usr/sbin
diff --git a/tools/vnet/vnet-module/Makefile.ver b/tools/vnet/vnet-module/Makefile.ver
index 2529bb9405..2567f9242f 100644
--- a/tools/vnet/vnet-module/Makefile.ver
+++ b/tools/vnet/vnet-module/Makefile.ver
@@ -18,27 +18,32 @@
# 59 Temple Place, suite 330, Boston, MA 02111-1307 USA
#============================================================================
-LINUX_SERIES ?=2.6
-KERNEL_MINOR ?=-xen0
+LINUX_SERIES?=2.6
+KERNEL_MINOR=-xen
-LINUX_VERSION ?= $(shell (/bin/ls -ld $(XEN_ROOT)/pristine-linux-$(LINUX_SERIES).* 2>/dev/null) | \
+LINUX_VERSION?=$(shell (/bin/ls -d $(XEN_ROOT)/pristine-linux-$(LINUX_SERIES).* 2>/dev/null) | \
sed -e 's!^.*linux-\(.\+\)!\1!' )
ifeq ($(LINUX_VERSION),)
$(error Kernel source for linux $(LINUX_SERIES) not found)
endif
-KERNEL_VERSION =$(LINUX_VERSION)$(KERNEL_MINOR)
+KERNEL_VERSION=$(LINUX_VERSION)$(KERNEL_MINOR)
-KERNEL_SRC ?= $(XEN_ROOT)/linux-$(KERNEL_VERSION)
+KERNEL_SRC?=$(shell cd $(XEN_ROOT)/linux-$(KERNEL_VERSION) && pwd)
+
+ifeq ($(KERNEL_SRC),)
+$(error Kernel source for kernel $(KERNEL_VERSION) not found)
+endif
# Get the full kernel release version from its makefile, as the source path
# may not have the extraversion, e.g. linux-2.6.12-xen0 may contain release 2.6.12.6-xen0.
-KERNEL_RELEASE = $(shell make -s -C $(KERNEL_SRC) kernelrelease || \
- make -f $(shell pwd)/Makefile.kver -s -C $(KERNEL_SRC) kernelrelease )
+KERNEL_RELEASE=$(shell make -s -C $(KERNEL_SRC) kernelrelease)
-KERNEL_MODULE_DIR = /lib/modules/$(KERNEL_RELEASE)/kernel
+KERNEL_MODULE_DIR=/lib/modules/$$(KERNEL_RELEASE)/kernel
-$(warning KERNEL_SRC $(KERNEL_SRC))
-#$(warning KERNEL_VERSION $(KERNEL_VERSION))
-$(warning KERNEL_RELEASE $(KERNEL_RELEASE))
+$(warning KERNEL_SRC $(KERNEL_SRC))
+$(warning LINUX_VERSION $(LINUX_VERSION))
+$(warning KERNEL_VERSION $(KERNEL_VERSION))
+$(warning KERNEL_RELEASE $(KERNEL_RELEASE))
+$(warning KERNEL_ MODULE_DIR $(KERNEL_MODULE_DIR))
diff --git a/tools/vnet/vnet-module/esp.c b/tools/vnet/vnet-module/esp.c
index 29449faa6b..f18d1b1523 100644
--- a/tools/vnet/vnet-module/esp.c
+++ b/tools/vnet/vnet-module/esp.c
@@ -104,7 +104,7 @@ void __exit esp_module_exit(void){
* @param block size to round to a multiple of
* @return rounded value
*/
-static inline int roundup(int n, int block){
+static inline int roundupto(int n, int block){
if(block <= 1) return n;
block--;
return (n + block) & ~block;
@@ -312,9 +312,9 @@ static int esp_sa_send(SAState *sa, struct sk_buff *skb, Tunnel *tunnel){
// header and IP header.
plaintext_n = skb->len - ETH_HLEN - ip_n;
// Add size of padding fields.
- ciphertext_n = roundup(plaintext_n + ESP_PAD_N, esp->cipher.block_n);
+ ciphertext_n = roundupto(plaintext_n + ESP_PAD_N, esp->cipher.block_n);
if(esp->cipher.pad_n > 0){
- ciphertext_n = roundup(ciphertext_n, esp->cipher.pad_n);
+ ciphertext_n = roundupto(ciphertext_n, esp->cipher.pad_n);
}
extra_n = ciphertext_n - plaintext_n;
iv_n = esp->cipher.iv_n;
@@ -502,9 +502,9 @@ static u32 esp_sa_size(SAState *sa, int data_n){
// Have to add some padding for alignment even if pad_n is zero.
ESPState *esp = sa->data;
- data_n = roundup(data_n + ESP_PAD_N, esp->cipher.block_n);
+ data_n = roundupto(data_n + ESP_PAD_N, esp->cipher.block_n);
if(esp->cipher.pad_n > 0){
- data_n = roundup(data_n, esp->cipher.pad_n);
+ data_n = roundupto(data_n, esp->cipher.pad_n);
}
data_n += esp->digest.icv_n;
//data_n += esp->cipher.iv_n;
@@ -607,7 +607,7 @@ static int esp_cipher_init(SAState *sa, ESPState *esp){
err = -EINVAL;
goto exit;
}
- esp->cipher.key_n = roundup(sa->cipher.bits, 8);
+ esp->cipher.key_n = roundupto(sa->cipher.bits, 8);
// If cipher is null must use ECB because CBC algo does not support blocksize 1.
if(strcmp(sa->cipher.name, "cipher_null")){
cipher_mode = CRYPTO_TFM_MODE_ECB;
@@ -617,7 +617,7 @@ static int esp_cipher_init(SAState *sa, ESPState *esp){
err = -ENOMEM;
goto exit;
}
- esp->cipher.block_n = roundup(crypto_tfm_alg_blocksize(esp->cipher.tfm), 4);
+ esp->cipher.block_n = roundupto(crypto_tfm_alg_blocksize(esp->cipher.tfm), 4);
esp->cipher.iv_n = crypto_tfm_alg_ivsize(esp->cipher.tfm);
esp->cipher.pad_n = 0;
if(esp->cipher.iv_n){
@@ -643,7 +643,7 @@ static int esp_digest_init(SAState *sa, ESPState *esp){
dprintf(">\n");
esp->digest.key = sa->digest.key;
- esp->digest.key_n = bits_to_bytes(roundup(sa->digest.bits, 8));
+ esp->digest.key_n = bits_to_bytes(roundupto(sa->digest.bits, 8));
esp->digest.tfm = crypto_alloc_tfm(sa->digest.name, 0);
if(!esp->digest.tfm){
err = -ENOMEM;
diff --git a/tools/vnet/vnet-module/etherip.c b/tools/vnet/vnet-module/etherip.c
index 2548d1a80a..3e531c7fbe 100644
--- a/tools/vnet/vnet-module/etherip.c
+++ b/tools/vnet/vnet-module/etherip.c
@@ -128,9 +128,27 @@ static void etherip_tunnel_close(Tunnel *tunnel){
}
+static inline int skb_make_headroom(struct sk_buff **pskb, struct sk_buff *skb, int head_n){
+ int err = 0;
+ dprintf("> skb=%p headroom=%d head_n=%d\n", skb, skb_headroom(skb), head_n);
+ if(head_n > skb_headroom(skb) || skb_cloned(skb) || skb_shared(skb)){
+ // Expand header the way GRE does.
+ struct sk_buff *new_skb = skb_realloc_headroom(skb, head_n + 16);
+ if(!new_skb){
+ err = -ENOMEM;
+ goto exit;
+ }
+ kfree_skb(skb);
+ *pskb = new_skb;
+ } else {
+ *pskb = skb;
+ }
+ exit:
+ return err;
+}
+
/** Send a packet via an etherip tunnel.
- * Adds etherip header, new ip header, new ethernet header around
- * ethernet frame.
+ * Adds etherip header and new ip header around ethernet frame.
*
* @param tunnel tunnel
* @param skb packet
@@ -150,7 +168,7 @@ static int etherip_tunnel_send(Tunnel *tunnel, struct sk_buff *skb){
if(etherip_in_udp){
head_n += vnet_n + udp_n;
}
- err = skb_make_room(&skb, skb, head_n, 0);
+ err = skb_make_headroom(&skb, skb, head_n);
if(err) goto exit;
// Null the pointer as we are pushing a new IP header.
@@ -219,6 +237,20 @@ int etherip_tunnel_create(VnetId *vnet, VarpAddr *addr, Tunnel *base, Tunnel **t
return Tunnel_create(etherip_tunnel_type, vnet, addr, base, tunnel);
}
+#if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER)
+/** We need our own copy of this as it is no longer exported from the bridge module.
+ */
+static inline void _nf_bridge_save_header(struct sk_buff *skb){
+ int header_size = 16;
+
+ // Were using this modified to use h_proto instead of skb->protocol.
+ if(skb->protocol == htons(ETH_P_8021Q)){
+ header_size = 18;
+ }
+ memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
+}
+#endif
+
/** Do etherip receive processing.
* Strips the etherip header to extract the ethernet frame, sets
* the vnet from the header and re-receives the frame.
@@ -320,10 +352,9 @@ int etherip_protocol_recv(struct sk_buff *skb){
skb->dst = NULL;
nf_reset(skb);
#ifdef CONFIG_BRIDGE_NETFILTER
- // Stop the eth header being clobbered by nf_bridge_maybe_copy_header().
- // Were using this modified to use h_proto instead of skb->protocol.
if(skb->nf_bridge){
- nf_bridge_save_header(skb);
+ // Stop the eth header being clobbered by nf_bridge_maybe_copy_header().
+ _nf_bridge_save_header(skb);
}
#endif
#endif // __KERNEL__
diff --git a/tools/vnet/vnet-module/tunnel.c b/tools/vnet/vnet-module/tunnel.c
index 49b8cdce48..3403e3dcde 100644
--- a/tools/vnet/vnet-module/tunnel.c
+++ b/tools/vnet/vnet-module/tunnel.c
@@ -51,6 +51,12 @@ rwlock_t tunnel_table_lock = RW_LOCK_UNLOCKED;
#define tunnel_write_lock(flags) write_lock_irqsave(&tunnel_table_lock, (flags))
#define tunnel_write_unlock(flags) write_unlock_irqrestore(&tunnel_table_lock, (flags))
+void Tunnel_free(Tunnel *tunnel){
+ tunnel->type->close(tunnel);
+ Tunnel_decref(tunnel->base);
+ kfree(tunnel);
+}
+
void Tunnel_print(Tunnel *tunnel){
if(tunnel){
iprintf("Tunnel<%p base=%p ref=%02d type=%s>\n",
@@ -136,6 +142,7 @@ int Tunnel_init(void){
goto exit;
}
tunnel_table->entry_free_fn = tunnel_table_entry_free_fn;
+ tunnel_table->key_size = sizeof(TunnelKey);
tunnel_table->key_hash_fn = tunnel_table_key_hash_fn;
tunnel_table->key_equal_fn = tunnel_table_key_equal_fn;
exit:
diff --git a/tools/vnet/vnet-module/tunnel.h b/tools/vnet/vnet-module/tunnel.h
index 23c72027c4..c363eca51a 100644
--- a/tools/vnet/vnet-module/tunnel.h
+++ b/tools/vnet/vnet-module/tunnel.h
@@ -70,6 +70,8 @@ typedef struct Tunnel {
struct Tunnel *base;
} Tunnel;
+extern void Tunnel_free(struct Tunnel *tunnel);
+
/** Decrement the reference count, freeing if zero.
*
* @param tunnel tunnel (may be null)
@@ -77,9 +79,7 @@ typedef struct Tunnel {
static inline void Tunnel_decref(struct Tunnel *tunnel){
if(!tunnel) return;
if(atomic_dec_and_test(&tunnel->refcount)){
- tunnel->type->close(tunnel);
- Tunnel_decref(tunnel->base);
- kfree(tunnel);
+ Tunnel_free(tunnel);
}
}
@@ -87,7 +87,7 @@ static inline void Tunnel_decref(struct Tunnel *tunnel){
*
* @param tunnel tunnel (may be null)
*/
-static inline void Tunnel_incref(Tunnel *tunnel){
+static inline void Tunnel_incref(struct Tunnel *tunnel){
if(!tunnel) return;
atomic_inc(&tunnel->refcount);
}
diff --git a/tools/vnet/vnet-module/varp.c b/tools/vnet/vnet-module/varp.c
index c1d2c63237..94c2f7569b 100644
--- a/tools/vnet/vnet-module/varp.c
+++ b/tools/vnet/vnet-module/varp.c
@@ -849,6 +849,7 @@ VarpTable * VarpTable_new(void){
if(!vtable) goto exit;
vtable->table = HashTable_new(VARP_TABLE_BUCKETS);
if(!vtable->table) goto exit;
+ vtable->table->key_size = sizeof(VarpKey);
vtable->table->key_equal_fn = varp_key_equal_fn;
vtable->table->key_hash_fn = varp_key_hash_fn;
vtable->table->entry_free_fn = varp_entry_free_fn;
@@ -1529,8 +1530,12 @@ void varp_exit(void){
dprintf("<\n");
}
+#ifdef MODULE_PARM
MODULE_PARM(varp_mcaddr, "s");
-MODULE_PARM_DESC(varp_mcaddr, "VARP multicast address");
-
MODULE_PARM(varp_device, "s");
+#else
+module_param(varp_mcaddr, charp, 0644);
+module_param(varp_device, charp, 0644);
+#endif
+MODULE_PARM_DESC(varp_mcaddr, "VARP multicast address");
MODULE_PARM_DESC(varp_device, "VARP network device");
diff --git a/tools/vnet/vnet-module/varp_socket.c b/tools/vnet/vnet-module/varp_socket.c
index 7ad14a37f2..7b2ef9f938 100644
--- a/tools/vnet/vnet-module/varp_socket.c
+++ b/tools/vnet/vnet-module/varp_socket.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+ * Copyright (C) 2004, 2005, 2006 Mike Wray <mike.wray@hp.com>
*
* 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
@@ -36,7 +36,7 @@
/* Get macros needed to define system calls as functions in the kernel. */
#define __KERNEL_SYSCALLS__
-static int errno;
+int errno=0;
#include <linux/unistd.h>
#define MODULE_NAME "VARP"
@@ -73,8 +73,14 @@ static inline _syscall3(int, fcntl,
/* Replicate the user-space socket API.
* The parts we need anyway.
+ *
+ * Some architectures use socketcall() to multiplex the socket-related calls,
+ * but others define individual syscalls instead.
+ * Architectures using socketcall() define __ARCH_WANT_SYS_SOCKETCALL.
*/
+#ifdef __ARCH_WANT_SYS_SOCKETCALL
+
/* Define the socketcall() syscall.
* Multiplexes all the socket-related calls.
*
@@ -180,6 +186,66 @@ int getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len){
return socketcall(SYS_GETSOCKNAME, args);
}
+#else /* !__ARCH_WANT_SYS_SOCKETCALL */
+
+/* No socketcall - define the individual syscalls. */
+
+static inline _syscall3(int, socket,
+ int, family,
+ int, type,
+ int, protocol);
+
+static inline _syscall3(int, bind,
+ int, fd,
+ struct sockaddr *, umyaddr,
+ int, addrlen);
+
+static inline _syscall3(int, connect,
+ int, fd,
+ struct sockaddr *, uservaddr,
+ int, addrlen);
+
+static inline _syscall6(int, sendto,
+ int, fd,
+ void *, buff,
+ size_t, len,
+ unsigned, flags,
+ struct sockaddr *, addr,
+ int, addr_len);
+
+static inline _syscall6(int, recvfrom,
+ int, fd,
+ void *, ubuf,
+ size_t, size,
+ unsigned, flags,
+ struct sockaddr *, addr,
+ int *, addr_len);
+
+static inline _syscall5(int, setsockopt,
+ int, fd,
+ int, level,
+ int, optname,
+ void *, optval,
+ int, optlen);
+
+static inline _syscall5(int, getsockopt,
+ int, fd,
+ int, level,
+ int, optname,
+ void *, optval,
+ int *, optlen);
+
+static inline _syscall2(int, shutdown,
+ int, fd,
+ int, how);
+
+static inline _syscall3(int, getsockname,
+ int, fd,
+ struct sockaddr *, usockaddr,
+ int *, usockaddr_len);
+
+#endif /* __ARCH_WANT_SYS_SOCKETCALL */
+
/*============================================================================*/
/** Socket flags. */
enum VsockFlag {
@@ -418,9 +484,7 @@ int varp_ucast_open(uint32_t addr, u16 port, int *val){
* an error.
*/
static int handle_varp_skb(struct sk_buff *skb){
- static int count = 0;
int err = 0;
- count++;
switch(skb->pkt_type){
case PACKET_BROADCAST:
case PACKET_MULTICAST:
diff --git a/tools/vnet/vnet-module/vif.c b/tools/vnet/vnet-module/vif.c
index 25c1eec292..1175f01196 100644
--- a/tools/vnet/vnet-module/vif.c
+++ b/tools/vnet/vnet-module/vif.c
@@ -366,6 +366,7 @@ int vif_init(void){
goto exit;
}
vif_table->entry_free_fn = vif_entry_free_fn;
+ vif_table->key_size = sizeof(VifKey);
vif_table->key_hash_fn = vif_key_hash_fn;
vif_table->key_equal_fn = vif_key_equal_fn;
diff --git a/tools/vnet/vnet-module/vnet.c b/tools/vnet/vnet-module/vnet.c
index c1359ab9f9..23855d5399 100644
--- a/tools/vnet/vnet-module/vnet.c
+++ b/tools/vnet/vnet-module/vnet.c
@@ -318,6 +318,7 @@ int vnet_table_init(void){
err = -ENOMEM;
goto exit;
}
+ vnet_table->key_size = sizeof(VnetId);
vnet_table->key_equal_fn = vnet_key_equal_fn;
vnet_table->key_hash_fn = vnet_key_hash_fn;
vnet_table->entry_free_fn = vnet_entry_free_fn;
@@ -431,14 +432,14 @@ inline int _skb_xmit(struct sk_buff *skb, uint32_t saddr){
ip_send_check(skb->nh.iph);
- if(1){
+#if 1
// Output to skb destination. Will use ip_output(), which fragments.
// Slightly slower than neigh_compat_output() (marginal - 1%).
err = dst_output(skb);
- } else {
+#else
// Sends direct to device via dev_queue_xmit(). No fragmentation?
err = neigh_compat_output(skb);
- }
+#endif
#if 0
if(needs_frags){
@@ -447,6 +448,7 @@ inline int _skb_xmit(struct sk_buff *skb, uint32_t saddr){
err = ip_finish_output(skb);
}
#endif
+
exit:
dprintf("< err=%d\n", err);
return err;
@@ -691,7 +693,12 @@ module_init(vnet_module_init);
module_exit(vnet_module_exit);
MODULE_LICENSE("GPL");
+#ifdef MODULE_PARM
MODULE_PARM(vnet_encaps, "s");
+#else
+module_param(vnet_encaps, charp, 0644);
+#endif
+
MODULE_PARM_DESC(vnet_encaps, "Vnet encapsulation: etherip or udp.");
#endif
diff --git a/tools/vnet/vnet-module/vnet_dev.c b/tools/vnet/vnet-module/vnet_dev.c
index fbfd3e0bf6..6f79efdb5f 100644
--- a/tools/vnet/vnet-module/vnet_dev.c
+++ b/tools/vnet/vnet-module/vnet_dev.c
@@ -49,8 +49,12 @@
#undef DEBUG
#include "debug.h"
-#ifndef CONFIG_BRIDGE
-#warning Should configure ethernet bridging in kernel Network Options
+#if !defined(CONFIG_BRIDGE) && !defined(CONFIG_BRIDGE_MODULE)
+#warning Should configure Ethernet Bridging in kernel Network Options
+#endif
+
+#ifndef CONFIG_BRIDGE_NETFILTER
+#warning Should configure CONFIG_BRIDGE_NETFILTER in kernel
#endif
static void vnet_dev_destructor(struct net_device *dev){
@@ -254,7 +258,7 @@ static int vnet_dev_setup(Vnet *vnet, struct net_device *dev){
return err;
}
-static inline int roundup(int n, int k){
+static inline int roundupto(int n, int k){
return k * ((n + k - 1) / k);
}
@@ -275,7 +279,7 @@ int vnet_dev_add(Vnet *vnet){
vnet->header_n += sizeof(struct VnetMsgHdr);
vnet->header_n += sizeof(struct udphdr);
}
- vnet->header_n = roundup(vnet->header_n, 4);
+ vnet->header_n = roundupto(vnet->header_n, 4);
dev = alloc_netdev(0, vnet->device, vnet_dev_init);
if(!dev){
err = -ENOMEM;
diff --git a/tools/vnet/vnet-module/vnet_eval.c b/tools/vnet/vnet-module/vnet_eval.c
index fda0ac847d..d0d8902e5f 100644
--- a/tools/vnet/vnet-module/vnet_eval.c
+++ b/tools/vnet/vnet-module/vnet_eval.c
@@ -188,7 +188,7 @@ int eval_vnet_add(Sxpr exp, IOStream *out, void *data){
if(err) goto exit;
child_string(exp, ovnetif, &device);
if(!device){
- snprintf(dev, IFNAMSIZ-1, "vnif%04x", ntohs(vnet.u.vnet16[7]));
+ snprintf(dev, IFNAMSIZ-1, "vnif%04x", ntohs(vnet.u.vnet16[VNETID_SIZE16 - 1]));
device = dev;
}
csecurity = sxpr_child_value(exp, osecurity, intern("none"));
diff --git a/tools/vnet/vnet-module/vnet_forward.c b/tools/vnet/vnet-module/vnet_forward.c
index 43b857e069..2064d7890d 100644
--- a/tools/vnet/vnet-module/vnet_forward.c
+++ b/tools/vnet/vnet-module/vnet_forward.c
@@ -370,6 +370,7 @@ int vnet_forward_init(void){
err = -ENOMEM;
goto exit;
}
+ vnet_peer_table->key_size = sizeof(struct VarpAddr);
vnet_peer_table->key_equal_fn = peer_key_equal_fn;
vnet_peer_table->key_hash_fn = peer_key_hash_fn;
vnet_peer_table->entry_free_fn = peer_entry_free_fn;
diff --git a/tools/vnet/vnetd/Makefile b/tools/vnet/vnetd/Makefile
index fe54c21bd1..530284c218 100644
--- a/tools/vnet/vnetd/Makefile
+++ b/tools/vnet/vnetd/Makefile
@@ -24,7 +24,8 @@ all: vnetd
#----------------------------------------------------------------------------
-include $(XEN_ROOT)/tools/Rules.mk
+# Comment out when outside xen.
+#include $(XEN_ROOT)/tools/Rules.mk
VNETD_INSTALL_DIR = /usr/sbin
@@ -43,6 +44,7 @@ CPPFLAGS += -D USE_GC
CPPFLAGS += -D __ARCH_I386_ATOMIC__
#----------------------------------------------------------------------------
+CFLAGS += -O3
CFLAGS += $(INCLUDES) $(LIBS)
LDFLAGS += $(LIBS)
@@ -108,7 +110,7 @@ vnetd: $(VNETD_OBJ)
.PHONY: install
install: vnetd
mkdir -p $(DESTDIR)$(VNETD_INSTALL_DIR)
- install -m 0755 vnetd $(DESTDIR)$(VNETD_INSTALL_DIR)
+ $(INSTALL_PROG) vnetd $(DESTDIR)$(VNETD_INSTALL_DIR)
.PHONY: clean
clean:
diff --git a/tools/vnet/vnetd/vnetd.c b/tools/vnet/vnetd/vnetd.c
index 18ed329934..1000272527 100644
--- a/tools/vnet/vnetd/vnetd.c
+++ b/tools/vnet/vnetd/vnetd.c
@@ -196,7 +196,7 @@ int vnet_dev_add(struct Vnet *vnet){
if(err){
wprintf("> Unable to open tap device.\n"
"The tun module must be loaded and\n"
- "the vnet kernel module must not be loaded.");
+ "the vnet kernel module must not be loaded.\n");
deallocate(dev);
goto exit;
}
@@ -764,7 +764,7 @@ static int vnetd_getopts(Vnetd *vnetd, int argc, char *argv[]){
*
* @param vnetd vnetd
*/
-int vnetd_init(Vnetd *vnetd, int argc, char *argv[]){
+static int vnetd_init(Vnetd *vnetd, int argc, char *argv[]){
int err = 0;
// Use etherip-in-udp encapsulation.
@@ -791,7 +791,7 @@ int vnetd_init(Vnetd *vnetd, int argc, char *argv[]){
return err;
}
-void vnet_select(Vnetd *vnetd, SelectSet *set){
+static void vnet_select(Vnetd *vnetd, SelectSet *set){
HashTable_for_decl(entry);
HashTable_for_each(entry, vnetd->vnet_table){
@@ -803,7 +803,7 @@ void vnet_select(Vnetd *vnetd, SelectSet *set){
}
}
-void vnet_handle(Vnetd *vnetd, SelectSet *set){
+static void vnet_handle(Vnetd *vnetd, SelectSet *set){
HashTable_for_decl(entry);
HashTable_for_each(entry, vnetd->vnet_table){
@@ -820,7 +820,7 @@ void vnet_handle(Vnetd *vnetd, SelectSet *set){
}
}
-int vnetd_handle_udp(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
+static int vnetd_handle_udp(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
int err = 0, n = 0;
struct sockaddr_in peer, dest;
socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest);
@@ -851,7 +851,7 @@ int vnetd_handle_udp(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
return err;
}
-int vnetd_handle_etherip(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
+static int vnetd_handle_etherip(Vnetd *vnetd, struct sockaddr_in *addr, int sock){
int err = 0, n = 0;
struct sockaddr_in peer, dest;
socklen_t peer_n = sizeof(peer), dest_n = sizeof(dest);
@@ -883,7 +883,7 @@ typedef struct ConnClient {
Parser *parser;
} ConnClient;
-int conn_handle_fn(Conn *conn, int mode){
+static int conn_handle_fn(Conn *conn, int mode){
int err;
ConnClient *client = conn->data;
char data[1024] = {};
@@ -923,12 +923,12 @@ int conn_handle_fn(Conn *conn, int mode){
return (err < 0 ? err : 0);
}
-int vnetd_handle_unix(Vnetd *vnetd, int sock){
+static int vnetd_handle_unix(Vnetd *vnetd, int sock){
int err;
ConnClient *client = NULL;
Conn *conn = NULL;
struct sockaddr_un peer = {};
- int peer_n = sizeof(peer);
+ socklen_t peer_n = sizeof(peer);
int peersock;
peersock = accept(sock, (struct sockaddr *)&peer, &peer_n);
@@ -956,7 +956,7 @@ int vnetd_handle_unix(Vnetd *vnetd, int sock){
return err;
}
-void vnetd_select(Vnetd *vnetd, SelectSet *set){
+static void vnetd_select(Vnetd *vnetd, SelectSet *set){
SelectSet_add(set, vnetd->unix_sock, SELECT_READ);
SelectSet_add(set, vnetd->udp_sock, SELECT_READ);
SelectSet_add(set, vnetd->mcast_sock, SELECT_READ);
@@ -967,7 +967,7 @@ void vnetd_select(Vnetd *vnetd, SelectSet *set){
ConnList_select(vnetd->conns, set);
}
-void vnetd_handle(Vnetd *vnetd, SelectSet *set){
+static void vnetd_handle(Vnetd *vnetd, SelectSet *set){
if(SelectSet_in_read(set, vnetd->unix_sock)){
vnetd_handle_unix(vnetd, vnetd->unix_sock);
}
@@ -995,7 +995,7 @@ void vnetd_handle(Vnetd *vnetd, SelectSet *set){
*/
static unsigned timer_alarms = 0;
-int vnetd_main(Vnetd *vnetd){
+static int vnetd_main(Vnetd *vnetd){
int err = 0;
SelectSet _set = {}, *set = &_set;
struct timeval _timeout = {}, *timeout = &_timeout;
@@ -1030,12 +1030,12 @@ int vnetd_main(Vnetd *vnetd){
return err;
}
-int getsockaddr(int sock, struct sockaddr_in *addr){
+static int getsockaddr(int sock, struct sockaddr_in *addr){
socklen_t addr_n = sizeof(struct sockaddr_in);
return getsockname(sock, (struct sockaddr*)addr, &addr_n);
}
-int vnetd_etherip_sock(Vnetd *vnetd){
+static int vnetd_etherip_sock(Vnetd *vnetd){
int err = 0;
if(!vnetd->etherip) goto exit;
@@ -1051,7 +1051,7 @@ int vnetd_etherip_sock(Vnetd *vnetd){
return err;
}
-int vnetd_udp_sock(Vnetd *vnetd){
+static int vnetd_udp_sock(Vnetd *vnetd){
int err;
uint32_t mcaddr = vnetd_mcast_addr(vnetd);
@@ -1087,7 +1087,7 @@ int vnetd_udp_sock(Vnetd *vnetd){
return err;
}
-int vnetd_raw_sock(Vnetd *vnetd){
+static int vnetd_raw_sock(Vnetd *vnetd){
int err;
err = vnetd_raw_socket(vnetd, IPPROTO_RAW,
@@ -1101,7 +1101,7 @@ int vnetd_raw_sock(Vnetd *vnetd){
return err;
}
-int vnetd_unix_sock(Vnetd *vnetd){
+static int vnetd_unix_sock(Vnetd *vnetd){
int err = 0;
struct sockaddr_un addr = { .sun_family = AF_UNIX };
socklen_t addr_n;
diff --git a/tools/vtpm/Rules.mk b/tools/vtpm/Rules.mk
index 9ce85dc316..8eb1a3c343 100644
--- a/tools/vtpm/Rules.mk
+++ b/tools/vtpm/Rules.mk
@@ -5,11 +5,6 @@ include $(XEN_ROOT)/tools/Rules.mk
# Tool definitions
#
-# Installation program and options
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
# Xen tools installation directory
TOOLS_INSTALL_DIR = $(DESTDIR)/usr/bin
diff --git a/tools/vtpm_manager/Rules.mk b/tools/vtpm_manager/Rules.mk
index 3435afed38..68c2a26ff7 100644
--- a/tools/vtpm_manager/Rules.mk
+++ b/tools/vtpm_manager/Rules.mk
@@ -5,11 +5,6 @@ include $(XEN_ROOT)/tools/Rules.mk
# Tool definitions
#
-# Installation program and options
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
# Xen tools installation directory
TOOLS_INSTALL_DIR = $(DESTDIR)/usr/bin
diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile
index 24031a1688..6022505577 100644
--- a/tools/xcutils/Makefile
+++ b/tools/xcutils/Makefile
@@ -8,10 +8,6 @@
# Copyright (C) 2005 by Christian Limpach
#
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Rules.mk
@@ -37,7 +33,7 @@ all: build
build: $(PROGRAMS)
$(PROGRAMS): %: %.o
- $(LINK.o) $^ $(LDLIBS) -o $@
+ $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@
.PHONY: install
install: build
diff --git a/tools/xcutils/readnotes.c b/tools/xcutils/readnotes.c
index af4162a558..cbd177a88f 100644
--- a/tools/xcutils/readnotes.c
+++ b/tools/xcutils/readnotes.c
@@ -56,7 +56,8 @@ static void print_numeric_note(const char *prefix,Elf_Nhdr *note)
prefix, *(uint64_t *)ELFNOTE_DESC(note));
break;
default:
- printf("%s: unknown data size %#x\n", prefix, note->n_descsz);
+ printf("%s: unknown data size %#lx\n", prefix,
+ (unsigned long)note->n_descsz);
break;
}
}
@@ -301,7 +302,8 @@ int main(int argc, char **argv)
print_string_note("FEATURES", note);
break;
default:
- printf("unknown note type %#x\n", note->n_type);
+ printf("unknown note type %#lx\n",
+ (unsigned long)note->n_type);
break;
}
}
diff --git a/tools/xenmon/Makefile b/tools/xenmon/Makefile
index 3d46dbe548..c1f4cd3f46 100644
--- a/tools/xenmon/Makefile
+++ b/tools/xenmon/Makefile
@@ -10,17 +10,12 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-
-sbindir=/usr/sbin
-
XEN_ROOT=../..
include $(XEN_ROOT)/tools/Rules.mk
-CFLAGS += -Werror -g
+sbindir=/usr/sbin
+
+CFLAGS += -Werror
CFLAGS += -I $(XEN_XC)
CFLAGS += -I $(XEN_LIBXC)
LDFLAGS += -L $(XEN_LIBXC)
diff --git a/tools/xenmon/xenmon.py b/tools/xenmon/xenmon.py
index 402b6b4e18..d828834a10 100644
--- a/tools/xenmon/xenmon.py
+++ b/tools/xenmon/xenmon.py
@@ -653,7 +653,6 @@ def writelog():
# start xenbaked
def start_xenbaked():
global options
- global args
os.system("killall -9 xenbaked")
# assumes that xenbaked is in your path
@@ -672,9 +671,17 @@ def main():
parser = setup_cmdline_parser()
(options, args) = parser.parse_args()
+
+ if len(args):
+ parser.error("No parameter required")
if options.mspersample < 0:
parser.error("option --ms_per_sample: invalid negative value: '%d'" %
options.mspersample)
+ # If --ms_per_sample= is too large, no data may be logged.
+ if not options.live and options.duration != 0 and \
+ options.mspersample > options.duration * 1000:
+ parser.error("option --ms_per_sample: too large (> %d ms)" %
+ (options.duration * 1000))
start_xenbaked()
if options.live:
diff --git a/tools/xenstat/libxenstat/Makefile b/tools/xenstat/libxenstat/Makefile
index 7eea316133..8cb77f17bc 100644
--- a/tools/xenstat/libxenstat/Makefile
+++ b/tools/xenstat/libxenstat/Makefile
@@ -16,10 +16,6 @@ XEN_ROOT=../../..
include $(XEN_ROOT)/tools/Rules.mk
LINUX_ROOT := $(XEN_ROOT)/linux-2.6-xen-sparse
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755 -D
-INSTALL_DATA = $(INSTALL) -m0644 -D
-
prefix=/usr
includedir=$(prefix)/include
libdir=$(prefix)/lib
@@ -34,7 +30,7 @@ LIB=src/libxenstat.a
SHLIB=src/libxenstat.so.$(MAJOR).$(MINOR)
SHLIB_LINKS=src/libxenstat.so.$(MAJOR) src/libxenstat.so
OBJECTS=src/xenstat.o
-SONAME_FLAGS=-Wl,-soname -Wl,libxenstat.so.$(MAJOR)
+SONAME_FLAGS=-Wl,$(SONAME_LDFLAG) -Wl,libxenstat.so.$(MAJOR)
WARN_FLAGS=-Wall -Werror
@@ -49,7 +45,7 @@ $(LIB): $(OBJECTS)
$(RANLIB) $@
$(SHLIB): $(OBJECTS)
- $(CC) $(CFLAGS) $(LDFLAGS) $(SONAME_FLAGS) -shared -o $@ $(OBJECTS) \
+ $(CC) $(CFLAGS) $(LDFLAGS) $(SONAME_FLAGS) $(SHLIB_CFLAGS) -o $@ $(OBJECTS) \
-lxenstore -lxenctrl
src/xenstat.o: src/xenstat.c src/xenstat.h
@@ -101,7 +97,7 @@ $(PYSRC) $(PYMOD): bindings/swig/xenstat.i
swig -python $(SWIG_FLAGS) -outdir $(@D) -o $(PYSRC) $<
$(PYLIB): $(PYSRC)
- $(CC) $(CFLAGS) $(LDFLAGS) $(PYTHON_FLAGS) -shared -lxenstat -o $@ $<
+ $(CC) $(CFLAGS) $(LDFLAGS) $(PYTHON_FLAGS) $(SHLIB_CFLAGS) -lxenstat -o $@ $<
python-bindings: $(PYLIB) $(PYMOD)
@@ -122,7 +118,7 @@ $(PERLSRC) $(PERLMOD): bindings/swig/xenstat.i
swig -perl $(SWIG_FLAGS) -outdir $(@D) -o $(PERLSRC) $<
$(PERLLIB): $(PERLSRC)
- $(CC) $(CFLAGS) $(LDFLAGS) $(PERL_FLAGS) -shared -lxenstat -o $@ $<
+ $(CC) $(CFLAGS) $(LDFLAGS) $(PERL_FLAGS) $(SHLIB_CFLAGS) -lxenstat -o $@ $<
.PHONY: perl-bindings
perl-bindings: $(PERLLIB) $(PERLMOD)
diff --git a/tools/xenstat/libxenstat/src/xenstat.c b/tools/xenstat/libxenstat/src/xenstat.c
index 4af20372d3..8857bd1c27 100644
--- a/tools/xenstat/libxenstat/src/xenstat.c
+++ b/tools/xenstat/libxenstat/src/xenstat.c
@@ -449,36 +449,36 @@ unsigned int xenstat_domain_ssid(xenstat_domain * domain)
/* Get domain states */
unsigned int xenstat_domain_dying(xenstat_domain * domain)
{
- return (domain->state & DOMFLAGS_DYING) == DOMFLAGS_DYING;
+ return (domain->state & XEN_DOMINF_dying) == XEN_DOMINF_dying;
}
unsigned int xenstat_domain_crashed(xenstat_domain * domain)
{
- return ((domain->state & DOMFLAGS_SHUTDOWN) == DOMFLAGS_SHUTDOWN)
- && (((domain->state >> DOMFLAGS_SHUTDOWNSHIFT)
- & DOMFLAGS_SHUTDOWNMASK) == SHUTDOWN_crash);
+ return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
+ && (((domain->state >> XEN_DOMINF_shutdownshift)
+ & XEN_DOMINF_shutdownmask) == SHUTDOWN_crash);
}
unsigned int xenstat_domain_shutdown(xenstat_domain * domain)
{
- return ((domain->state & DOMFLAGS_SHUTDOWN) == DOMFLAGS_SHUTDOWN)
- && (((domain->state >> DOMFLAGS_SHUTDOWNSHIFT)
- & DOMFLAGS_SHUTDOWNMASK) != SHUTDOWN_crash);
+ return ((domain->state & XEN_DOMINF_shutdown) == XEN_DOMINF_shutdown)
+ && (((domain->state >> XEN_DOMINF_shutdownshift)
+ & XEN_DOMINF_shutdownmask) != SHUTDOWN_crash);
}
unsigned int xenstat_domain_paused(xenstat_domain * domain)
{
- return (domain->state & DOMFLAGS_PAUSED) == DOMFLAGS_PAUSED;
+ return (domain->state & XEN_DOMINF_paused) == XEN_DOMINF_paused;
}
unsigned int xenstat_domain_blocked(xenstat_domain * domain)
{
- return (domain->state & DOMFLAGS_BLOCKED) == DOMFLAGS_BLOCKED;
+ return (domain->state & XEN_DOMINF_blocked) == XEN_DOMINF_blocked;
}
unsigned int xenstat_domain_running(xenstat_domain * domain)
{
- return (domain->state & DOMFLAGS_RUNNING) == DOMFLAGS_RUNNING;
+ return (domain->state & XEN_DOMINF_running) == XEN_DOMINF_running;
}
/* Get the number of networks for a given domain */
diff --git a/tools/xenstat/xentop/Makefile b/tools/xenstat/xentop/Makefile
index 273cb31e4e..2248bfb3c3 100644
--- a/tools/xenstat/xentop/Makefile
+++ b/tools/xenstat/xentop/Makefile
@@ -18,10 +18,6 @@ ifneq ($(XENSTAT_XENTOP),y)
all install xentop:
else
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755 -D
-INSTALL_DATA = $(INSTALL) -m0644 -D
-
prefix=/usr
mandir=$(prefix)/share/man
man1dir=$(mandir)/man1
@@ -29,7 +25,7 @@ sbindir=$(prefix)/sbin
CFLAGS += -DGCC_PRINTF -Wall -Werror -I$(XEN_LIBXENSTAT)
LDFLAGS += -L$(XEN_LIBXENSTAT)
-LDLIBS += -lxenstat -lncurses
+LDLIBS += -lxenstat $(CURSES_LIBS) $(SOCKET_LIBS)
.PHONY: all
all: xentop
@@ -37,6 +33,7 @@ all: xentop
.PHONY: install
install: xentop xentop.1
$(INSTALL_PROG) xentop $(DESTDIR)$(sbindir)/xentop
+ $(INSTALL_DIR) $(DESTDIR)$(man1dir)
$(INSTALL_DATA) xentop.1 $(DESTDIR)$(man1dir)/xentop.1
endif
diff --git a/tools/xenstat/xentop/xentop.1 b/tools/xenstat/xentop/xentop.1
index c7a856bed1..b925a3795f 100644
--- a/tools/xenstat/xentop/xentop.1
+++ b/tools/xenstat/xentop/xentop.1
@@ -47,6 +47,9 @@ seconds between updates (default 3)
\fB\-n\fR, \fB\-\-networks\fR
output network information
.TP
+\fB\-x\fR, \fB\-\-vbds\fR
+output vbd block device data
+.TP
\fB\-r\fR, \fB\-\-repeat\-header\fR
repeat table header before each domain
.TP
diff --git a/tools/xenstat/xentop/xentop.c b/tools/xenstat/xentop/xentop.c
index b808bfa497..b772f951fb 100644
--- a/tools/xenstat/xentop/xentop.c
+++ b/tools/xenstat/xentop/xentop.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
@@ -186,6 +187,8 @@ char prompt_val[PROMPT_VAL_LEN];
int prompt_val_len = 0;
void (*prompt_complete_func)(char *);
+static WINDOW *cwin;
+
/*
* Function definitions
*/
@@ -201,7 +204,7 @@ static void usage(const char *program)
"-V, --version output version information and exit\n"
"-d, --delay=SECONDS seconds between updates (default 3)\n"
"-n, --networks output vif network data\n"
- "-b, --vbds output vbd block device data\n"
+ "-x, --vbds output vbd block device data\n"
"-r, --repeat-header repeat table header before each domain\n"
"-v, --vcpus output vcpu data\n"
"-b, --batch output in batch mode, no user input accepted\n"
@@ -222,7 +225,7 @@ static void version(void)
/* Clean up any open resources */
static void cleanup(void)
{
- if(!isendwin())
+ if(cwin != NULL && !isendwin())
endwin();
if(prev_node != NULL)
xenstat_free_node(prev_node);
@@ -235,7 +238,7 @@ static void cleanup(void)
/* Display the given message and gracefully exit */
static void fail(const char *str)
{
- if(!isendwin())
+ if(cwin != NULL && !isendwin())
endwin();
fprintf(stderr, str);
exit(1);
@@ -266,7 +269,7 @@ static void print(const char *fmt, ...)
if (!batch) {
if((current_row() < lines()-1)) {
va_start(args, fmt);
- vw_printw(stdscr, fmt, args);
+ vwprintw(stdscr, (char *)fmt, args);
va_end(args);
}
} else {
@@ -280,7 +283,7 @@ static void print(const char *fmt, ...)
static void attr_addstr(int attr, const char *str)
{
attron(attr);
- addstr(str);
+ addstr((char *)str);
attroff(attr);
}
@@ -973,7 +976,7 @@ int main(int argc, char **argv)
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "networks", no_argument, NULL, 'n' },
- { "vbds", no_argument, NULL, 'x' },
+ { "vbds", no_argument, NULL, 'x' },
{ "repeat-header", no_argument, NULL, 'r' },
{ "vcpus", no_argument, NULL, 'v' },
{ "delay", required_argument, NULL, 'd' },
@@ -1028,14 +1031,16 @@ int main(int argc, char **argv)
if (!batch) {
/* Begin curses stuff */
- initscr();
+ cwin = initscr();
start_color();
cbreak();
noecho();
nonl();
keypad(stdscr, TRUE);
halfdelay(5);
+#ifndef __sun__
use_default_colors();
+#endif
init_pair(1, -1, COLOR_YELLOW);
do {
@@ -1060,7 +1065,7 @@ int main(int argc, char **argv)
break;
} while (1);
}
-
+
/* Cleanup occurs in cleanup(), so no work to do here. */
return 0;
diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile
index 279a5a5354..a18347d4b1 100644
--- a/tools/xenstore/Makefile
+++ b/tools/xenstore/Makefile
@@ -5,13 +5,8 @@ XEN_LIBXC = $(XEN_ROOT)/tools/libxc
MAJOR = 3.0
MINOR = 0
-INSTALL = install
-INSTALL_DATA = $(INSTALL) -m0644
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-
PROFILE=#-pg
-BASECFLAGS=-Wall -g -Werror
+BASECFLAGS=-Werror
# Make gcc generate dependencies.
BASECFLAGS += -Wp,-MD,.$(@F).d
PROG_DEP = .*.d
@@ -32,39 +27,40 @@ CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS))
XENSTORED_OBJS = xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o tdb.o hashtable.o
-XENSTORED_Linux = xenstored_linux.o
+XENSTORED_OBJS_$(CONFIG_Linux) = xenstored_linux.o
+XENSTORED_OBJS_$(CONFIG_SunOS) = xenstored_solaris.o
-XENSTORED_OBJS += $(XENSTORED_$(OS))
+XENSTORED_OBJS += $(XENSTORED_OBJS_y)
.PHONY: all
all: libxenstore.so libxenstore.a xenstored $(CLIENTS) xs_tdb_dump xenstore-control xenstore-ls
test_interleaved_transactions: test_interleaved_transactions.o
- $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
.PHONY: testcode
testcode: xs_test xenstored_test xs_random
xenstored: $(XENSTORED_OBJS)
- $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl $(SOCKET_LIBS) -o $@
$(CLIENTS): xenstore-%: xenstore_%.o libxenstore.so
- $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore $(SOCKET_LIBS) -o $@
$(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c
$(COMPILE.c) -DCLIENT_$(*F) -o $@ $<
xenstore-control: xenstore_control.o libxenstore.so
- $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore $(SOCKET_LIBS) -o $@
xenstore-ls: xsls.o libxenstore.so
- $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore $(SOCKET_LIBS) -o $@
xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o
- $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o
- $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
xs_test xs_random xs_stress xs_crashme: LDFLAGS+=-lpthread
xs_test: xs_test.o xs_lib.o utils.o
@@ -95,7 +91,7 @@ libxenstore.so.$(MAJOR): libxenstore.so.$(MAJOR).$(MINOR)
ln -sf $< $@
libxenstore.so.$(MAJOR).$(MINOR): xs.opic xs_lib.opic
- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libxenstore.so.$(MAJOR) -shared -o $@ $^ -lpthread
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenstore.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ -lpthread
libxenstore.a: xs.o xs_lib.o
$(AR) rcs libxenstore.a $^
diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c
index 811c6acb6a..c34dcbfc70 100644
--- a/tools/xenstore/xenstore_client.c
+++ b/tools/xenstore/xenstore_client.c
@@ -267,12 +267,13 @@ int
main(int argc, char **argv)
{
struct xs_handle *xsh;
- xs_transaction_t xth;
+ xs_transaction_t xth = XBT_NULL;
int ret = 0, socket = 0;
int prefix = 0;
int tidy = 0;
int upto = 0;
int recurse = 0;
+ int transaction;
while (1) {
int c, index = 0;
@@ -339,18 +340,28 @@ main(int argc, char **argv)
}
#endif
+#if defined(CLIENT_read)
+ transaction = (argc - optind) > 1;
+#elif defined(CLIENT_write)
+ transaction = (argc - optind) > 2;
+#else
+ transaction = 1;
+#endif
+
xsh = socket ? xs_daemon_open() : xs_domain_open();
if (xsh == NULL)
err(1, socket ? "xs_daemon_open" : "xs_domain_open");
again:
- xth = xs_transaction_start(xsh);
- if (xth == XBT_NULL)
- errx(1, "couldn't start transaction");
+ if (transaction) {
+ xth = xs_transaction_start(xsh);
+ if (xth == XBT_NULL)
+ errx(1, "couldn't start transaction");
+ }
ret = perform(optind, argc, argv, xsh, xth, prefix, tidy, upto, recurse);
- if (!xs_transaction_end(xsh, xth, ret)) {
+ if (transaction && !xs_transaction_end(xsh, xth, ret)) {
if (ret == 0 && errno == EAGAIN) {
output_pos = 0;
goto again;
diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c
index 2511e4a5fc..5ac4dd3b0f 100644
--- a/tools/xenstore/xenstored_core.c
+++ b/tools/xenstore/xenstored_core.c
@@ -575,8 +575,10 @@ struct node *get_node(struct connection *conn,
/* If we don't have permission, we don't have node. */
if (node) {
if ((perm_for_conn(conn, node->perms, node->num_perms) & perm)
- != perm)
+ != perm) {
+ errno = EACCES;
node = NULL;
+ }
}
/* Clean up errno if they weren't supposed to know. */
if (!node)
@@ -789,7 +791,7 @@ static void delete_node_single(struct connection *conn, struct node *node)
corrupt(conn, "Could not delete '%s'", node->name);
return;
}
- domain_entry_dec(conn);
+ domain_entry_dec(conn, node);
}
/* Must not be / */
@@ -840,7 +842,7 @@ static struct node *construct_node(struct connection *conn, const char *name)
node->children = node->data = NULL;
node->childlen = node->datalen = 0;
node->parent = parent;
- domain_entry_inc(conn);
+ domain_entry_inc(conn, node);
return node;
}
@@ -876,7 +878,7 @@ static struct node *create_node(struct connection *conn,
* something goes wrong. */
for (i = node; i; i = i->parent) {
if (!write_node(conn, i)) {
- domain_entry_dec(conn);
+ domain_entry_dec(conn, i);
return NULL;
}
talloc_set_destructor(i, destroy_node);
@@ -1106,6 +1108,7 @@ static void do_get_perms(struct connection *conn, const char *name)
static void do_set_perms(struct connection *conn, struct buffered_data *in)
{
unsigned int num;
+ struct xs_permissions *perms;
char *name, *permstr;
struct node *node;
@@ -1127,12 +1130,24 @@ static void do_set_perms(struct connection *conn, struct buffered_data *in)
return;
}
- node->perms = talloc_array(node, struct xs_permissions, num);
- node->num_perms = num;
- if (!xs_strings_to_perms(node->perms, num, permstr)) {
+ perms = talloc_array(node, struct xs_permissions, num);
+ if (!xs_strings_to_perms(perms, num, permstr)) {
send_error(conn, errno);
return;
}
+
+ /* Unprivileged domains may not change the owner. */
+ if (domain_is_unprivileged(conn) &&
+ perms[0].id != node->perms[0].id) {
+ send_error(conn, EPERM);
+ return;
+ }
+
+ domain_entry_dec(conn, node);
+ node->perms = perms;
+ node->num_perms = num;
+ domain_entry_inc(conn, node);
+
if (!write_node(conn, node)) {
send_error(conn, errno);
return;
@@ -1688,7 +1703,7 @@ static void write_pidfile(const char *pidfile)
if (lockf(fd, F_TLOCK, 0) == -1)
exit(0);
- len = sprintf(buf, "%d\n", getpid());
+ len = sprintf(buf, "%ld\n", (long)getpid());
if (write(fd, buf, len) != len)
barf_perror("Writing pid file %s", pidfile);
}
@@ -1901,7 +1916,7 @@ int main(int argc, char *argv[])
restore_existing_connections();
if (outputpid) {
- printf("%i\n", getpid());
+ printf("%ld\n", (long)getpid());
fflush(stdout);
}
@@ -1924,6 +1939,9 @@ int main(int argc, char *argv[])
/* Get ready to listen to the tools. */
max = initialize_set(&inset, &outset, *sock, *ro_sock);
+ /* Tell the kernel we're up and running. */
+ xenbus_notify_running();
+
/* Main loop. */
/* FIXME: Rewrite so noone can starve. */
for (;;) {
diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h
index 0849e7ba78..d46d77f026 100644
--- a/tools/xenstore/xenstored_core.h
+++ b/tools/xenstore/xenstored_core.h
@@ -172,6 +172,9 @@ void *xenbus_map(void);
/* Return the event channel used by xenbus. */
evtchn_port_t xenbus_evtchn(void);
+/* Tell the kernel xenstored is running. */
+void xenbus_notify_running(void);
+
#endif /* _XENSTORED_CORE_H */
/*
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index 40cc20386a..d21ae7b9c7 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -501,18 +501,35 @@ int domain_init(void)
return xce_handle;
}
-void domain_entry_inc(struct connection *conn)
+void domain_entry_inc(struct connection *conn, struct node *node)
{
- if (!conn || !conn->domain)
+ struct domain *d;
+
+ if (!conn)
return;
- conn->domain->nbentry++;
+
+ if (node->perms && node->perms[0].id != conn->id) {
+ d = find_domain_by_domid(node->perms[0].id);
+ if (d)
+ d->nbentry++;
+ }
+ else if (conn->domain) {
+ conn->domain->nbentry++;
+ }
}
-void domain_entry_dec(struct connection *conn)
+void domain_entry_dec(struct connection *conn, struct node *node)
{
- if (!conn || !conn->domain)
+ struct domain *d;
+
+ if (!conn)
return;
- if (conn->domain->nbentry)
+
+ if (node->perms && node->perms[0].id != conn->id) {
+ d = find_domain_by_domid(node->perms[0].id);
+ if (d && d->nbentry)
+ d->nbentry--;
+ } else if (conn->domain && conn->domain->nbentry)
conn->domain->nbentry--;
}
diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h
index 38f26b52de..4acf61bbac 100644
--- a/tools/xenstore/xenstored_domain.h
+++ b/tools/xenstore/xenstored_domain.h
@@ -50,8 +50,8 @@ bool domain_can_write(struct connection *conn);
bool domain_is_unprivileged(struct connection *conn);
/* Quota manipulation */
-void domain_entry_inc(struct connection *conn);
-void domain_entry_dec(struct connection *conn);
+void domain_entry_inc(struct connection *conn, struct node *);
+void domain_entry_dec(struct connection *conn, struct node *);
int domain_entry(struct connection *conn);
void domain_watch_inc(struct connection *conn);
void domain_watch_dec(struct connection *conn);
diff --git a/tools/xenstore/xenstored_linux.c b/tools/xenstore/xenstored_linux.c
index dabc5ff1a4..5460ca5573 100644
--- a/tools/xenstore/xenstored_linux.c
+++ b/tools/xenstore/xenstored_linux.c
@@ -67,3 +67,7 @@ void *xenbus_map(void)
return addr;
}
+
+void xenbus_notify_running(void)
+{
+}
diff --git a/tools/xenstore/xenstored_solaris.c b/tools/xenstore/xenstored_solaris.c
new file mode 100644
index 0000000000..376a00081b
--- /dev/null
+++ b/tools/xenstore/xenstored_solaris.c
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ *
+ * 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, version 2 of the
+ * License.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <xen/sys/xenbus.h>
+
+#include "xenstored_core.h"
+
+evtchn_port_t xenbus_evtchn(void)
+{
+ int fd;
+ evtchn_port_t port;
+
+ fd = open("/dev/xen/xenbus", O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ port = ioctl(fd, IOCTL_XENBUS_XENSTORE_EVTCHN);
+
+ close(fd);
+ return port;
+}
+
+void *xenbus_map(void)
+{
+ int fd;
+ void *addr;
+
+ fd = open("/dev/xen/xenbus", O_RDWR);
+ if (fd == -1)
+ return NULL;
+
+ addr = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, 0);
+
+ if (addr == MAP_FAILED)
+ addr = NULL;
+
+ close(fd);
+
+ return addr;
+}
+
+void xenbus_notify_running(void)
+{
+ int fd;
+
+ fd = open("/dev/xen/xenbus", O_RDONLY);
+
+ (void) ioctl(fd, IOCTL_XENBUS_NOTIFY_UP);
+
+ close(fd);
+}
diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c
index fb20287f99..69cc520bb9 100644
--- a/tools/xenstore/xenstored_transaction.c
+++ b/tools/xenstore/xenstored_transaction.c
@@ -133,7 +133,7 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in)
return;
}
- if (conn->transaction_started > quota_max_transaction) {
+ if (conn->id && conn->transaction_started > quota_max_transaction) {
send_error(conn, ENOSPC);
return;
}
diff --git a/tools/xenstore/xs_lib.c b/tools/xenstore/xs_lib.c
index 750d1823cf..0afe87d325 100644
--- a/tools/xenstore/xs_lib.c
+++ b/tools/xenstore/xs_lib.c
@@ -76,7 +76,14 @@ const char *xs_daemon_socket_ro(void)
const char *xs_domain_dev(void)
{
char *s = getenv("XENSTORED_PATH");
- return (s ? s : "/proc/xen/xenbus");
+ if (s)
+ return s;
+
+#ifdef __linux__
+ return "/proc/xen/xenbus";
+#else
+ return "/dev/xen/xenbus";
+#endif
}
/* Simple routines for writing to sockets, etc. */
diff --git a/tools/xenstore/xsls.c b/tools/xenstore/xsls.c
index 4d3b1aa1af..cf5ff6e7e6 100644
--- a/tools/xenstore/xsls.c
+++ b/tools/xenstore/xsls.c
@@ -6,6 +6,7 @@
#include <getopt.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <termios.h>
static int max_width = 80;
static int desired_width = 60;
@@ -93,14 +94,8 @@ void usage(int argc, char *argv[])
int main(int argc, char *argv[])
{
struct winsize ws;
- int ret;
- int c;
- int show_perm = 0;
-
- struct xs_handle *xsh = xs_daemon_open();
-
- if (xsh == NULL)
- err(1, "xs_daemon_open");
+ int ret, c, socket = 0, show_perm = 0;
+ struct xs_handle *xsh;
#define PAD 2
@@ -109,12 +104,15 @@ int main(int argc, char *argv[])
if (!ret)
max_width = ws.ws_col - PAD;
- while (0 < (c = getopt(argc, argv, "p"))) {
+ while (0 < (c = getopt(argc, argv, "ps"))) {
switch (c) {
case 'p':
show_perm = 1;
max_width -= 16;
break;
+ case 's':
+ socket = 1;
+ break;
case ':':
case '?':
default:
@@ -123,6 +121,10 @@ int main(int argc, char *argv[])
}
}
+ xsh = socket ? xs_daemon_open() : xs_domain_open();
+ if (xsh == NULL)
+ err(1, socket ? "xs_daemon_open" : "xs_domain_open");
+
print_dir(xsh, (argc - optind) == 1 ? argv[optind] : "/", 0, show_perm);
return 0;
diff --git a/tools/xentrace/Makefile b/tools/xentrace/Makefile
index 0ab5e4c060..ce8e4904a8 100644
--- a/tools/xentrace/Makefile
+++ b/tools/xentrace/Makefile
@@ -1,12 +1,7 @@
-INSTALL = install
-INSTALL_PROG = $(INSTALL) -m0755
-INSTALL_DIR = $(INSTALL) -d -m0755
-INSTALL_DATA = $(INSTALL) -m0644
-
XEN_ROOT=../..
include $(XEN_ROOT)/tools/Rules.mk
-CFLAGS += -Werror -D_LARGEFILE64_SOURCE
+CFLAGS += -Werror
CFLAGS += -I $(XEN_XC)
CFLAGS += -I $(XEN_LIBXC)
diff --git a/tools/xentrace/formats b/tools/xentrace/formats
index 96ba53212c..3460a5f99f 100644
--- a/tools/xentrace/formats
+++ b/tools/xentrace/formats
@@ -1,3 +1,5 @@
+0x0001f001 CPU%(cpu)d %(tsc)d lost_records 0x%(1)08x
+
0x0002f001 CPU%(cpu)d %(tsc)d sched_add_domain [ domid = 0x%(1)08x, edomid = 0x%(2)08x ]
0x0002f002 CPU%(cpu)d %(tsc)d sched_rem_domain [ domid = 0x%(1)08x, edomid = 0x%(2)08x ]
0x0002f003 CPU%(cpu)d %(tsc)d domain_sleep [ domid = 0x%(1)08x, edomid = 0x%(2)08x ]
@@ -12,10 +14,29 @@
0x0002f00c CPU%(cpu)d %(tsc)d t_timer_fn
0x0002f00d CPU%(cpu)d %(tsc)d dom_timer_fn
-0x00080001 CPU%(cpu)d %(tsc)d VMX_VMEXIT [ domid = 0x%(1)08x, eip = 0x%(2)08x, reason = 0x%(3)08x ]
-0x00080002 CPU%(cpu)d %(tsc)d VMX_VECTOR [ domid = 0x%(1)08x, eip = 0x%(2)08x, vector = 0x%(3)08x ]
-0x00080003 CPU%(cpu)d %(tsc)d VMX_INT [ domid = 0x%(1)08x, trap = 0x%(2)08x, va = 0x%(3)08x ]
+0x00080001 CPU%(cpu)d %(tsc)d VMX_VMEXIT [ domid = 0x%(1)08x, eip = 0x%(2)08x, reason = 0x%(3)08x ]
+0x00084001 CPU%(cpu)d %(tsc)d VMX_INTR [ domid = 0x%(1)08x, trap = 0x%(2)08x, va = 0x%(3)08x ]
+
+0x00081001 CPU%(cpu)d %(tsc)d VMEXIT_0 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082001 CPU%(cpu)d %(tsc)d VMENTRY_0 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+
+0x00081002 CPU%(cpu)d %(tsc)d VMEXIT_1 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082002 CPU%(cpu)d %(tsc)d VMENTRY_1 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+
+0x00081003 CPU%(cpu)d %(tsc)d VMEXIT_2 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082003 CPU%(cpu)d %(tsc)d VMENTRY_2 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+
+0x00081004 CPU%(cpu)d %(tsc)d VMEXIT_3 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082004 CPU%(cpu)d %(tsc)d VMENTRY_3 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+
+0x00081005 CPU%(cpu)d %(tsc)d VMEXIT_4 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082005 CPU%(cpu)d %(tsc)d VMENTRY_4 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+
+0x00081006 CPU%(cpu)d %(tsc)d VMEXIT_5 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082006 CPU%(cpu)d %(tsc)d VMENTRY_5 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
-0x00081001 CPU%(cpu)d %(tsc)d VMEXIT 0x%(1)08x 0x%(2)08x 0x%(3)08x
-0x00081002 CPU%(cpu)d %(tsc)d VMENTRY 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+0x00081007 CPU%(cpu)d %(tsc)d VMEXIT_6 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082007 CPU%(cpu)d %(tsc)d VMENTRY_6 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
+0x00081008 CPU%(cpu)d %(tsc)d VMEXIT_7 0x%(1)08x 0x%(2)08x 0x%(3)08x
+0x00082008 CPU%(cpu)d %(tsc)d VMENTRY_7 0x%(1)08x 0x%(2)08x 0x%(3)08x 0x%(4)08x 0x%(5)08x
diff --git a/tools/xentrace/xenctx.c b/tools/xentrace/xenctx.c
index 190670ea74..3071e3bb43 100644
--- a/tools/xentrace/xenctx.c
+++ b/tools/xentrace/xenctx.c
@@ -268,16 +268,68 @@ void print_ctx(vcpu_guest_context_t *ctx1)
}
#elif defined(__ia64__)
+
+#define PTE_ED_SHIFT 52
+#define PTE_ED_MASK 1
+#define PTE_PPN_SHIFT 12
+#define PTE_PPN_MASK 0x3fffffffff
+#define PTE_AR_SHIFT 9
+#define PTE_AR_MASK 7
+#define PTE_PL_SHIFT 7
+#define PTE_PL_MASK 3
+#define PTE_D_SHIFT 6
+#define PTE_D_MASK 1
+#define PTE_A_SHIFT 5
+#define PTE_A_MASK 1
+#define PTE_MA_SHIFT 2
+#define PTE_MA_MASK 7
+#define PTE_P_SHIFT 0
+#define PTE_P_MASK 1
+#define ITIR_KEY_SHIFT 8
+#define ITIR_KEY_MASK 0xffffff
+#define ITIR_PS_SHIFT 2
+#define ITIR_PS_MASK 0x3f
+#define ITIR_PS_MIN 12
+#define ITIR_PS_MAX 28
+#define RR_RID_SHIFT 8
+#define RR_RID_MASK 0xffffff
+
void print_ctx(vcpu_guest_context_t *ctx1)
{
struct cpu_user_regs *regs = &ctx1->user_regs;
-
- printf("iip: %016lx ", regs->cr_iip);
+ struct vcpu_extra_regs *er = &ctx1->extra_regs;
+ int i, ps_val, ma_val;
+ unsigned long pa;
+
+ const char ps[][5] = {" 4K", " 8K", " 16K", " ",
+ " 64K", " ", "256K", " ",
+ " 1M", " ", " 4M", " ",
+ " 16M", " ", " 64M", " ",
+ "256M"};
+ const char ma[][4] = {"WB ", " ", " ", " ",
+ "UC ", "UCE", "WC ", "Nat"};
+
+ printf(" iip: %016lx ", regs->cr_iip);
print_symbol(regs->cr_iip);
printf("\n");
- printf("psr: %016lu ", regs->cr_ipsr);
- printf(" b0: %016lx\n", regs->b0);
+ printf(" ipsr: %016lx ", regs->cr_ipsr);
+ printf(" b0: %016lx\n", regs->b0);
+ printf(" b6: %016lx ", regs->b6);
+ printf(" b7: %016lx\n", regs->b7);
+ printf(" cr_ifs: %016lx ", regs->cr_ifs);
+ printf(" ar_unat: %016lx\n", regs->ar_unat);
+ printf(" ar_pfs: %016lx ", regs->ar_pfs);
+ printf(" ar_rsc: %016lx\n", regs->ar_rsc);
+ printf(" ar_rnat: %016lx ", regs->ar_rnat);
+ printf(" ar_bspstore: %016lx\n", regs->ar_bspstore);
+ printf(" ar_fpsr: %016lx ", regs->ar_fpsr);
+ printf(" event_callback_ip: %016lx\n", er->event_callback_ip);
+ printf(" pr: %016lx ", regs->pr);
+ printf(" loadrs: %016lx\n", regs->loadrs);
+ printf(" iva: %016lx ", er->iva);
+ printf(" dcr: %016lx\n", er->dcr);
+ printf("\n");
printf(" r1: %016lx\n", regs->r1);
printf(" r2: %016lx ", regs->r2);
printf(" r3: %016lx\n", regs->r3);
@@ -310,6 +362,52 @@ void print_ctx(vcpu_guest_context_t *ctx1)
printf(" r30: %016lx ", regs->r30);
printf(" r31: %016lx\n", regs->r31);
+ printf("\n itr: P rid va pa ps ed pl "
+ "ar a d ma key\n");
+ for (i = 0; i < 8; i++) {
+ ps_val = er->itrs[i].itir >> ITIR_PS_SHIFT & ITIR_PS_MASK;
+ ma_val = er->itrs[i].pte >> PTE_MA_SHIFT & PTE_MA_MASK;
+ pa = (er->itrs[i].pte >> PTE_PPN_SHIFT & PTE_PPN_MASK) <<
+ PTE_PPN_SHIFT;
+ pa = (pa >> ps_val) << ps_val;
+ printf(" [%d] %ld %06lx %016lx %013lx %02x %s %ld %ld %ld %ld "
+ "%ld %d %s %06lx\n", i,
+ er->itrs[i].pte >> PTE_P_SHIFT & PTE_P_MASK,
+ er->itrs[i].rid >> RR_RID_SHIFT & RR_RID_MASK,
+ er->itrs[i].vadr, pa, ps_val,
+ ((ps_val >= ITIR_PS_MIN && ps_val <= ITIR_PS_MAX) ?
+ ps[ps_val - ITIR_PS_MIN] : " "),
+ er->itrs[i].pte >> PTE_ED_SHIFT & PTE_ED_MASK,
+ er->itrs[i].pte >> PTE_PL_SHIFT & PTE_PL_MASK,
+ er->itrs[i].pte >> PTE_AR_SHIFT & PTE_AR_MASK,
+ er->itrs[i].pte >> PTE_A_SHIFT & PTE_A_MASK,
+ er->itrs[i].pte >> PTE_D_SHIFT & PTE_D_MASK,
+ ma_val, ma[ma_val],
+ er->itrs[i].itir >> ITIR_KEY_SHIFT & ITIR_KEY_MASK);
+ }
+ printf("\n dtr: P rid va pa ps ed pl "
+ "ar a d ma key\n");
+ for (i = 0; i < 8; i++) {
+ ps_val = er->dtrs[i].itir >> ITIR_PS_SHIFT & ITIR_PS_MASK;
+ ma_val = er->dtrs[i].pte >> PTE_MA_SHIFT & PTE_MA_MASK;
+ pa = (er->dtrs[i].pte >> PTE_PPN_SHIFT & PTE_PPN_MASK) <<
+ PTE_PPN_SHIFT;
+ pa = (pa >> ps_val) << ps_val;
+ printf(" [%d] %ld %06lx %016lx %013lx %02x %s %ld %ld %ld %ld "
+ "%ld %d %s %06lx\n", i,
+ er->dtrs[i].pte >> PTE_P_SHIFT & PTE_P_MASK,
+ er->dtrs[i].rid >> RR_RID_SHIFT & RR_RID_MASK,
+ er->dtrs[i].vadr, pa, ps_val,
+ ((ps_val >= ITIR_PS_MIN && ps_val <= ITIR_PS_MAX) ?
+ ps[ps_val - ITIR_PS_MIN] : " "),
+ er->dtrs[i].pte >> PTE_ED_SHIFT & PTE_ED_MASK,
+ er->dtrs[i].pte >> PTE_PL_SHIFT & PTE_PL_MASK,
+ er->dtrs[i].pte >> PTE_AR_SHIFT & PTE_AR_MASK,
+ er->dtrs[i].pte >> PTE_A_SHIFT & PTE_A_MASK,
+ er->dtrs[i].pte >> PTE_D_SHIFT & PTE_D_MASK,
+ ma_val, ma[ma_val],
+ er->dtrs[i].itir >> ITIR_KEY_SHIFT & ITIR_KEY_MASK);
+ }
}
#endif
diff --git a/tools/xm-test/README b/tools/xm-test/README
index 62897748d8..9157f7681d 100644
--- a/tools/xm-test/README
+++ b/tools/xm-test/README
@@ -45,7 +45,7 @@ special files, this process must be done as root:
NB: If you have the initrd.img from another installation of xm-test,
you can copy it into the ramdisk directory to eliminate the need to
rebuild it. If you do this, there is no need to run 'make' again.
-Simply copy the initrd-X.Y.img file into ramdisk/ and then run:
+Simply copy the initrd-X.Y-ARCH.img file into ramdisk/ and then run:
# make existing
@@ -53,7 +53,7 @@ Or, you can run:
# INITRD="http://url.of.initrd.repo/" make existing
You do not need to include the name of the image itself in the url,
-however, an initrd with the right name (initrd.X.Y.img) and version
+however, an initrd with the right name (initrd.X.Y-ARCH.img) and version
number must exist at that location. The script will determine which
version of the initrd it needs and try to download the right file from
that location.
@@ -112,6 +112,38 @@ Xm-test will look for disk.img in the ramdisk directory when run by
default.
+BUILDING for ACM Security Testing
+=================================
+
+A number of tests have been added to test the access control module (ACM)
+in the Xen hypervisor and the tools for supporting ACM. Those tests are
+located in the security-acm directory. If ACM support is compiled into Xen
+(see the user guide for how to do this) those tests can be run with the
+following command from the xm-test directory
+
+./runtest.sh [...] -g security <report>
+
+Some of these tests will work even without support of ACM by Xen.
+
+The xm test suite has been extended to support labeling of resources
+as required by the existing tests. However, by default the test suite
+is not allowed to automatically label resources since this may affect
+existing labels. To enable this, the test suite must be configured with
+the following parameter passed to the configure scripts (in addition to
+any other desired parameters)
+
+./configure --enable-full-labeling
+
+To revoke the privilege at a later time run the configure scripts without
+this parameter:
+
+./configure
+
+If a 'make' has previously been run for building the test suite, it is not
+necessary to run 'make' again just for enabling or disabling the automatic
+labeling of resources.
+
+
Running
=======
diff --git a/tools/xm-test/configure.ac b/tools/xm-test/configure.ac
index 5183162f82..87df5cd6bd 100644
--- a/tools/xm-test/configure.ac
+++ b/tools/xm-test/configure.ac
@@ -1,19 +1,20 @@
# xm-test configure.ac input script
# Basic header information
-AC_INIT([xm-test], [0.8.0])
+AC_INIT([xm-test], [1.1.0])
AM_INIT_AUTOMAKE([1.7 foreign])
+MK=''; AC_SUBST(MK)
+
# Check for dependencies
AC_PROG_CC
#AC_PROG_INSTALL
AC_CHECK_PROG([LILO], lilo, lilo, "no", [$PATH])
-# Right now, we can assume that the lib/ and ramdisk/ directories
-# are two levels above the tests
+# Right now, we can assume that the lib/ directory
+# is two levels above the tests
TESTLIB=../../lib
-RD_PATH=../../ramdisk
-TENV="PYTHONPATH=$PYTHONPATH:$TESTLIB RD_PATH=$RD_PATH"
+TENV="PYTHONPATH=$PYTHONPATH:$TESTLIB"
AC_ARG_ENABLE(hvm-support,
[[ --enable-hvm-support enable hardware virtual machine assist]],
@@ -38,6 +39,20 @@ fi
AM_CONDITIONAL(HVM, test x$ENABLE_HVM = xTrue)
AC_SUBST(ENABLE_HVM)
+AC_ARG_ENABLE(full-labeling,
+ [[ --enable-full-labeling allows the test suite to label all resources]],
+ [
+ ENABLE_LABELING=True
+ ],[
+ ENABLE_LABELING=False
+ ])
+
+if test "x$ENABLE_LABELING" = "xTrue"; then
+ echo "ACM_LABEL_RESOURCES = True" > lib/XmTestLib/acm_config.py
+else
+ rm -f lib/XmTestLib/acm_config.py*
+fi
+
# Network needs to know ips to use: dhcp or a range of IPs in the form
# of: 192.168.1.1-192.168.1.100
# If not dhcp, a netmask and network address must be supplied. Defaults to
@@ -127,6 +142,7 @@ AC_CONFIG_FILES([
tests/restore/Makefile
tests/save/Makefile
tests/sched-credit/Makefile
+ tests/security-acm/Makefile
tests/sedf/Makefile
tests/shutdown/Makefile
tests/sysrq/Makefile
diff --git a/tools/xm-test/grouptest/default b/tools/xm-test/grouptest/default
index d4af74057d..d82ca73d21 100644
--- a/tools/xm-test/grouptest/default
+++ b/tools/xm-test/grouptest/default
@@ -22,6 +22,7 @@ reboot
restore
save
sched-credit
+security-acm
shutdown
sysrq
unpause
diff --git a/tools/xm-test/grouptest/security b/tools/xm-test/grouptest/security
new file mode 100644
index 0000000000..4d5c8b941d
--- /dev/null
+++ b/tools/xm-test/grouptest/security
@@ -0,0 +1 @@
+security-acm
diff --git a/tools/xm-test/lib/XmTestLib/Console.py b/tools/xm-test/lib/XmTestLib/Console.py
index 5507d3b1ec..b92f32bb3b 100755
--- a/tools/xm-test/lib/XmTestLib/Console.py
+++ b/tools/xm-test/lib/XmTestLib/Console.py
@@ -31,6 +31,7 @@ import termios
import fcntl
import select
+import arch
from Test import *
TIMEDOUT = 1
@@ -120,6 +121,7 @@ class XmConsole:
def __getprompt(self, fd):
timeout = 0
bytes = 0
+ buffer = ""
while timeout < 180:
# eat anything while total bytes less than limit else raise RUNAWAY
while (not self.limit) or (bytes < self.limit):
@@ -130,6 +132,7 @@ class XmConsole:
if self.debugMe:
sys.stdout.write(foo)
bytes += 1
+ buffer += foo
except Exception, exn:
raise ConsoleError(str(exn))
else:
@@ -137,6 +140,8 @@ class XmConsole:
else:
raise ConsoleError("Console run-away (exceeded %i bytes)"
% self.limit, RUNAWAY)
+ # Check to see if the buffer contains anything interetsing
+ arch.checkBuffer(buffer)
# press enter
os.write(self.consoleFd, "\n")
# look for prompt
diff --git a/tools/xm-test/lib/XmTestLib/XenDomain.py b/tools/xm-test/lib/XmTestLib/XenDomain.py
index cbe93f805d..40aaebf9b4 100644
--- a/tools/xm-test/lib/XmTestLib/XenDomain.py
+++ b/tools/xm-test/lib/XmTestLib/XenDomain.py
@@ -20,33 +20,23 @@
import sys
import commands
-import os
import re
import time
from Xm import *
+from arch import *
from Test import *
from config import *
from Console import *
from XenDevice import *
+from acm import *
-BLOCK_ROOT_DEV = "hda"
-
-def getDeviceModel():
- """Get the path to the device model based on
- the architecture reported in uname"""
- arch = os.uname()[4]
- if re.search("64", arch):
- return "/usr/lib64/xen/bin/qemu-dm"
- else:
- return "/usr/lib/xen/bin/qemu-dm"
def getDefaultKernel():
- """Get the path to the default DomU kernel"""
- dom0Ver = commands.getoutput("uname -r");
- domUVer = dom0Ver.replace("xen0", "xenU");
-
- return "/boot/vmlinuz-" + domUVer;
+ return arch.getDefaultKernel()
+
+def getRdPath():
+ return arch.getRdPath()
def getUniqueName():
"""Get a uniqueish name for use in a domain"""
@@ -55,43 +45,8 @@ def getUniqueName():
test_name = re.sub("\.test", "", test_name)
test_name = re.sub("[\/\.]", "", test_name)
name = "%s-%i" % (test_name, unixtime)
-
- return name
-def getRdPath():
- rdpath = os.environ.get("RD_PATH")
- if not rdpath:
- rdpath = "../../ramdisk"
- rdpath = os.path.abspath(rdpath)
-
- return rdpath
-
-ParavirtDefaults = {"memory" : 64,
- "vcpus" : 1,
- "kernel" : getDefaultKernel(),
- "root" : "/dev/ram0",
- "ramdisk" : getRdPath() + "/initrd.img"
- }
-HVMDefaults = {"memory" : 64,
- "vcpus" : 1,
- "acpi" : 0,
- "apic" : 0,
- "disk" : ["file:%s/disk.img,ioemu:%s,w!" %
- (getRdPath(), BLOCK_ROOT_DEV)],
- "kernel" : "/usr/lib/xen/boot/hvmloader",
- "builder" : "hvm",
- "sdl" : 0,
- "vnc" : 0,
- "vncviewer" : 0,
- "nographic" : 1,
- "serial" : "pty",
- "device_model" : getDeviceModel()
- }
-
-if ENABLE_HVM_SUPPORT:
- configDefaults = HVMDefaults
-else:
- configDefaults = ParavirtDefaults
+ return name
class XenConfig:
"""An object to help create a xen-compliant config file"""
@@ -102,6 +57,9 @@ class XenConfig:
self.defaultOpts["disk"] = []
self.defaultOpts["vif"] = []
self.defaultOpts["vtpm"] = []
+ if isACMEnabled():
+ #A default so every VM can start with ACM enabled
+ self.defaultOpts["access_control"] = ['policy=xm-test,label=red']
self.opts = self.defaultOpts
@@ -129,6 +87,7 @@ class XenConfig:
output = file(filename, "w")
output.write(self.toString())
output.close()
+ ACMPrepareSystem(self.opts)
def __str__(self):
"""When used as a string, we represent ourself by a config
@@ -140,8 +99,12 @@ class XenConfig:
def setOpt(self, name, value):
"""Set an option in the config"""
- if name in self.opts.keys() and isinstance(self.opts[name], list) and not isinstance(value, list):
+ if name in self.opts.keys() and isinstance(self.opts[name] ,
+ list) and not isinstance(value, list):
self.opts[name] = [value]
+ # "extra" is special so append to it.
+ elif name == "extra" and name in self.opts.keys():
+ self.opts[name] += " %s" % (value)
else:
self.opts[name] = value
@@ -177,7 +140,7 @@ class DomainError(Exception):
self.errorcode = int(errorcode)
except Exception, e:
self.errorcode = -1
-
+
def __str__(self):
return str(self.msg)
@@ -199,7 +162,7 @@ class XenDomain:
self.devices = {}
self.netEnv = "bridge"
- # Set domain type, either PV for ParaVirt domU or HVM for
+ # Set domain type, either PV for ParaVirt domU or HVM for
# FullVirt domain
if ENABLE_HVM_SUPPORT:
self.type = "HVM"
@@ -332,7 +295,8 @@ class XenDomain:
class XmTestDomain(XenDomain):
- def __init__(self, name=None, extraConfig=None, baseConfig=configDefaults):
+ def __init__(self, name=None, extraConfig=None,
+ baseConfig=arch.configDefaults):
"""Create a new xm-test domain
@param name: The requested domain name
@param extraConfig: Additional configuration options
@@ -351,11 +315,12 @@ class XmTestDomain(XenDomain):
XenDomain.__init__(self, config.getOpt("name"), config=config)
def minSafeMem(self):
- return 32
+ return arch.minSafeMem
class XmTestNetDomain(XmTestDomain):
- def __init__(self, name=None, extraConfig=None, baseConfig=configDefaults):
+ def __init__(self, name=None, extraConfig=None,
+ baseConfig=arch.configDefaults):
"""Create a new xm-test domain with one network device
@param name: The requested domain name
@param extraConfig: Additional configuration options
diff --git a/tools/xm-test/lib/XmTestLib/acm.py b/tools/xm-test/lib/XmTestLib/acm.py
new file mode 100644
index 0000000000..a0d8a43c09
--- /dev/null
+++ b/tools/xm-test/lib/XmTestLib/acm.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+"""
+ Copyright (C) International Business Machines Corp., 2006
+ Author: Stefan Berger <stefanb@us.ibm.com>
+
+ 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; under version 2 of the License.
+
+ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+from Test import *
+from xen.util import security
+
+try:
+ from acm_config import *
+except:
+ ACM_LABEL_RESOURCES = False
+
+labeled_resources = {}
+acm_verbose = False
+
+def isACMEnabled():
+ return security.on()
+
+
+def ACMLoadPolicy(policy='xm-test'):
+ s, o = traceCommand("xm makepolicy %s" % (policy))
+ if s != 0:
+ FAIL("Need to be able to do 'xm makepolicy %s' but could not" %
+ (policy))
+ s, o = traceCommand("xm loadpolicy %s" % (policy))
+ if s != 0:
+ FAIL("Could not load the required policy '%s'.\n"
+ "Start the system without any policy.\n%s" %
+ (policy, o))
+
+def ACMPrepareSystem(resources):
+ if isACMEnabled():
+ ACMLoadPolicy()
+ ACMLabelResources(resources)
+
+def ACMLabelResources(resources):
+ for k, v in resources.items():
+ if k == "disk":
+ for vv in v:
+ res = vv.split(',')[0]
+ ACMLabelResource(res)
+
+# Applications may label resources explicitly by calling this function
+def ACMLabelResource(resource, label='red'):
+ if acm_verbose:
+ print "labeling resource %s with label %s" % (resource, label)
+ if not ACM_LABEL_RESOURCES:
+ SKIP("Skipping test since not allowed to label resources in "
+ "test suite")
+ if not isACMResourceLabeled(resource):
+ ACMUnlabelResource(resource)
+ s, o = traceCommand("xm addlabel %s res %s" % (label, resource))
+ if s != 0:
+ FAIL("Could not add label to resource")
+ else:
+ labeled_resources["%s" % resource] = 1
+
+
+# Application may remove a label from a resource. It has to call this
+# function and must do so once a resource for re-labeling a resource
+def ACMUnlabelResource(resource):
+ s, o = traceCommand("xm rmlabel res %s" % (resource))
+ labeled_resources["%s" % resource] = 0
+
+
+def isACMResourceLabeled(resource):
+ """ Check whether a resource has been labeled using this API
+ and while running the application """
+ try:
+ if labeled_resources["%s" % resource] == 1:
+ if acm_verbose:
+ print "resource %s already labeled!" % resource
+ return True
+ except:
+ return False
+ return False
diff --git a/tools/xm-test/lib/XmTestLib/arch.py b/tools/xm-test/lib/XmTestLib/arch.py
new file mode 100644
index 0000000000..331ede5414
--- /dev/null
+++ b/tools/xm-test/lib/XmTestLib/arch.py
@@ -0,0 +1,148 @@
+#!/usr/bin/python
+"""
+ arch.py - Encapsulate all logic regarding what type of hardware xen
+ is running on to make adding new platforms easier.
+
+ Copyright (C) 2006 Tony Breeds IBM Corporation
+
+ 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; under version 2 of the License.
+
+ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+
+import os
+import re
+import config
+import commands
+
+from Test import *
+
+BLOCK_ROOT_DEV = "hda"
+
+# This isn't truly platform related but it makes the code tidier
+def getRdPath():
+ """Locate the full path to ramdisks needed by domUs"""
+ rdpath = os.environ.get("RD_PATH")
+ if not rdpath:
+ rdpath = "../../ramdisk"
+ rdpath = os.path.abspath(rdpath)
+
+ return rdpath
+
+# Begin: Intel ia32 and ia64 as well as AMD 32-bit and 64-bit processors
+def ia_checkBuffer(buffer):
+ return
+
+def ia_minSafeMem():
+ return 32
+
+def ia_getDeviceModel():
+ """Get the path to the device model based on
+ the architecture reported in uname"""
+ architecture = os.uname()[4]
+ if re.search("64", architecture):
+ return "/usr/lib64/xen/bin/qemu-dm"
+ else:
+ return "/usr/lib/xen/bin/qemu-dm"
+
+def ia_getDefaultKernel():
+ """Get the path to the default DomU kernel"""
+ dom0Ver = commands.getoutput("uname -r");
+ domUVer = dom0Ver.replace("xen0", "xenU");
+
+ return "/boot/vmlinuz-" + domUVer;
+
+ia_ParavirtDefaults = {"memory" : 64,
+ "vcpus" : 1,
+ "kernel" : ia_getDefaultKernel(),
+ "root" : "/dev/ram0",
+ "ramdisk" : getRdPath() + "/initrd.img",
+}
+ia_HVMDefaults = {"memory" : 64,
+ "vcpus" : 1,
+ "acpi" : 0,
+ "disk" : ["file:%s/disk.img,ioemu:%s,w!" %
+ (getRdPath(), BLOCK_ROOT_DEV)],
+ "kernel" : "/usr/lib/xen/boot/hvmloader",
+ "builder" : "hvm",
+ "sdl" : 0,
+ "vnc" : 0,
+ "vncviewer" : 0,
+ "nographic" : 1,
+ "serial" : "pty",
+ "device_model" : ia_getDeviceModel(),
+}
+# End : Intel ia32 and ia64 as well as AMD 32-bit and 64-bit processors
+
+# Begin: PowerPC
+def ppc_checkBuffer(buffer):
+ checks = [
+ {"pattern" : re.compile("^\d+:mon>\s*$", re.MULTILINE),
+ "message" : "domain trapped into XMON"},
+ ]
+
+ for i in range(0, len(checks)):
+ check=checks[i]
+ if check.get('pattern').search(buffer):
+ FAIL(check.get('message'))
+
+ return
+
+def ppc_minSafeMem():
+ return 64
+
+def ppc_getDefaultKernel():
+ """Get the path to the default DomU kernel"""
+ dom0Ver = commands.getoutput("uname -r");
+ domUVer = dom0Ver.replace("xen0", "xenU");
+
+ return "/boot/vmlinux-" + domUVer;
+
+ppc_ParavirtDefaults = {"memory" : 64,
+ "vcpus" : 1,
+ "kernel" : ppc_getDefaultKernel(),
+ "root" : "/dev/ram0",
+ "ramdisk" : getRdPath() + "/initrd.img",
+ "extra" : "xencons=tty128 console=tty128",
+}
+# End : PowerPC
+
+"""Convert from uname specification to a more general platform."""
+_uname_to_arch_map = {
+ "i386" : "x86",
+ "i486" : "x86",
+ "i586" : "x86",
+ "i686" : "x86",
+ "x86_64": "x86_64",
+ "ia64" : "ia64",
+ "ppc" : "powerpc",
+ "ppc64" : "powerpc",
+}
+
+# Lookup current platform.
+_arch = _uname_to_arch_map.get(os.uname()[4], "Unknown")
+if _arch == "x86" or _arch == "x86_64" or _arch == "ia64":
+ minSafeMem = ia_minSafeMem
+ getDefaultKernel = ia_getDefaultKernel
+ checkBuffer = ia_checkBuffer
+ if config.ENABLE_HVM_SUPPORT:
+ configDefaults = ia_HVMDefaults
+ else:
+ configDefaults = ia_ParavirtDefaults
+elif _arch == "powerpc":
+ minSafeMem = ppc_minSafeMem
+ getDefaultKernel = ppc_getDefaultKernel
+ checkBuffer = ppc_checkBuffer
+ configDefaults = ppc_ParavirtDefaults
+else:
+ raise ValueError, "Unknown architecture!"
diff --git a/tools/xm-test/lib/XmTestLib/block_utils.py b/tools/xm-test/lib/XmTestLib/block_utils.py
index 38c5d20d5f..c315c17bd1 100644
--- a/tools/xm-test/lib/XmTestLib/block_utils.py
+++ b/tools/xm-test/lib/XmTestLib/block_utils.py
@@ -6,6 +6,7 @@
import time
from XmTestLib import *
+from acm import *
import xen.util.blkif
@@ -26,6 +27,7 @@ def get_state(domain, devname):
def block_attach(domain, phy, virt):
+ ACMLabelResource(phy)
status, output = traceCommand("xm block-attach %s %s %s w" %
(domain.getName(), phy, virt))
if status != 0:
diff --git a/tools/xm-test/lib/XmTestReport/OSReport.py b/tools/xm-test/lib/XmTestReport/OSReport.py
index c73f9c7821..cb4759ea3b 100644
--- a/tools/xm-test/lib/XmTestReport/OSReport.py
+++ b/tools/xm-test/lib/XmTestReport/OSReport.py
@@ -29,6 +29,7 @@ import re
import os
import commands
import sys
+import arch
class Machine:
@@ -89,8 +90,6 @@ class Machine:
self.values = {}
self.errors = 0
- cpuValues = {"model_name" : "Unknown",
- "flags" : "Unknown"}
xenValues = {"nr_cpus" : "Unknown",
"nr_nodes" : "Unknown",
"sockets_per_node" : "Unknown",
@@ -100,12 +99,7 @@ class Machine:
"total_memory" : "Unknown"}
xen = self.__getXenInfo(xenValues)
- cpu = self.__getCpuInfo(cpuValues)
-
- if cpu["model_name"] == "Unknown":
- cpuValues={"arch" : "Unknown",
- "features": "Unknown"}
- cpu=self.__getCpuInfo(cpuValues)
+ cpu = self.__getCpuInfo(arch.cpuValues)
for k in xen.keys():
self.values[k] = xen[k]
diff --git a/tools/xm-test/lib/XmTestReport/arch.py b/tools/xm-test/lib/XmTestReport/arch.py
new file mode 100644
index 0000000000..965e7fb9c6
--- /dev/null
+++ b/tools/xm-test/lib/XmTestReport/arch.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+"""
+ arch.py - Encapsulate all logic regarding what type of hardware xen
+ is running on to make adding new platforms easier.
+
+ Copyright (C) 2006 Tony Breeds IBM Corporation
+
+ 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; under version 2 of the License.
+
+ 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+
+import os
+
+"""Convert from uname specification to a more general platform."""
+_uname_to_arch_map = {
+ "i386" : "x86",
+ "i486" : "x86",
+ "i586" : "x86",
+ "i686" : "x86",
+ "x86_64": "x86_64",
+ "ia64" : "ia64",
+ "ppc" : "powerpc",
+ "ppc64" : "powerpc",
+}
+
+_arch = _uname_to_arch_map.get(os.uname()[4], "Unknown")
+if _arch == "x86":
+ cpuValues = {"model_name" : "Unknown",
+ "flags" : "Unknown"}
+elif _arch == "x86_64":
+ cpuValues = {"model_name" : "Unknown",
+ "flags" : "Unknown"}
+elif _arch == "ia64":
+ cpuValues = {"arch" : "Unknown",
+ "features" : "Unknown"}
+elif _arch == "powerpc":
+ cpuValues = {"cpu" : "Unknown",
+ "platform" : "Unknown",
+ "revision" : "Unknown"}
+else:
+ raise ValueError, "Unknown architecture!"
diff --git a/tools/xm-test/ramdisk/Makefile.am b/tools/xm-test/ramdisk/Makefile.am
index 032212403a..14bfc9267c 100644
--- a/tools/xm-test/ramdisk/Makefile.am
+++ b/tools/xm-test/ramdisk/Makefile.am
@@ -1,19 +1,39 @@
+#
+# make existing:
+#
+# Download a pre-built ramdisk.
+# INITRD = <Directory to download ramdisk from>
+#
+# make initrd.img:
+#
+# Make a ramdisk from scratch.
+# BR_URL = <The URL of the Buildroot source code>
+# BR_SNAPSHOT = 1 Set BR_URL to the upstream Buildroot daily snapshot.
+# BR_ARCH = <The build architecture for the initrd>
+#
+
INITRD ?= http://xm-test.xensource.com/ramdisks
-EXTRA_DIST = skel configs patches
+BR_ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e 's/ppc\(64\)*/powerpc/')
+
+@MK@ifdef BR_SNAPSHOT
+@MK@ BR_URL = http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
+@MK@else
+@MK@ BR_URL = http://xm-test.xensource.com/ramdisks/buildroot-20061023.tar.bz2
+@MK@endif
+BR_TAR = $(notdir $(BR_URL))
-BR_TAR = buildroot-20060606.tar.bz2
-BR_URL = http://buildroot.uclibc.org/downloads/snapshots/$(BR_TAR)
-#BR_URL = http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
BR_SRC = buildroot
-BR_IMG = $(BR_SRC)/rootfs.i386.ext2
+BR_IMG = $(BR_SRC)/rootfs.$(BR_ARCH).ext2
-BR_ROOT = build_i386/root
+BR_ROOT = build_$(BR_ARCH)/root
+
+EXTRA_DIST = skel configs patches
HVM_SCRIPT = bin/create_disk_image
XMTEST_MAJ_VER = $(shell echo @PACKAGE_VERSION@ | perl -pe 's/(\d+)\.(\d+)\.\d+/\1.\2/')
-XMTEST_VER_IMG = initrd-$(XMTEST_MAJ_VER).img
+XMTEST_VER_IMG = initrd-$(XMTEST_MAJ_VER)-$(BR_ARCH).img
EXTRA_ROOT_DIRS = sys
@@ -30,7 +50,7 @@ $(BR_SRC): $(BR_TAR)
tar xjf $(BR_TAR)
$(BR_IMG): $(BR_SRC)
- cp configs/buildroot $(BR_SRC)/.config
+ cp configs/buildroot-$(BR_ARCH) $(BR_SRC)/.config
cp configs/busybox $(BR_SRC)/package/busybox/busybox.config
cp configs/uClibc $(BR_SRC)/toolchain/uClibc/uClibc.config
(for i in patches/buildroot/*.patch; do \
@@ -42,7 +62,7 @@ $(XMTEST_VER_IMG): $(BR_IMG)
(cd skel; mkdir -p $(EXTRA_ROOT_DIRS); tar cf - .) \
| (cd $(BR_SRC)/$(BR_ROOT); tar xvf -)
cd $(BR_SRC) && make
- cp $(BR_IMG) initrd-$(XMTEST_MAJ_VER).img
+ cp $(BR_IMG) $(XMTEST_VER_IMG)
initrd.img: $(XMTEST_VER_IMG)
ln -sf $(XMTEST_VER_IMG) initrd.img
diff --git a/tools/xm-test/ramdisk/README-XenSource-initrd-1.0-img b/tools/xm-test/ramdisk/README-XenSource-initrd-1.0-img
new file mode 100644
index 0000000000..80ac26be79
--- /dev/null
+++ b/tools/xm-test/ramdisk/README-XenSource-initrd-1.0-img
@@ -0,0 +1,46 @@
+XenSource xm-test 1.0 initrds
+=============================
+
+http://xm-test.xensource.com/ramdisks/initrd-1.0-i386.img and
+http://xm-test.xensource.com/ramdisks/initrd-1.0-powerpc.img are initrds
+suitable for use with Xen's xm-test regression testing suite. They has been
+built and provided by XenSource, for the convenience of Xen users. xm-test
+initrds may be mixed across minor xm-test versions, but not across major
+versions; this initrd is suitable for all 1.0.x versions of xm-test (as
+shipped with the Xen unstable tree for a short while between Xen 3.0.3 and
+Xen 3.0.4).
+
+In order to use one of these initrds, run "./autogen; ./configure; make
+existing" inside the xm-test directory, and the appropriate initrd for your
+architecture will be downloaded automatically. Alternatively, if you have
+already downloaded that file, place it into the xm-test/ramdisk directory and
+run the same command. In either case, runtest.sh can then be used as normal.
+See xm-test/README for more details.
+
+These initrds were built using the infrastructure provided by xm-test. Each
+is a full guest operating system and filesystem, and as such includes a large
+number of pieces of software. The source code for the majority of these are
+included in full inside the file
+http://xm-test.xensource.com/ramdisks/<INITRD>-buildroot.tar.bz2, where
+<INITRD> is either initrd-1.0-i386 or initrd-1.0-powerpc as appropriate, or
+alongside this file. Copyright statements and licences are contained therein.
+The remaining source code is included in the Xen distribution, at
+http://www.xensource.com/xen/downloads/archives.html. The configurations used
+for BusyBox, uClibc, and Buildroot are available as
+http://xm-test.xensource.com/ramdisks/<INITRD>-busybox-config,
+http://xm-test.xensource.com/ramdisks/<INITRD>-uClibc-config, and
+http://xm-test.xensource.com/ramdisks/<INITRD>-buildroot-config respectively,
+or alongside this file.
+
+XenSource and the Xen contributors are grateful to the authors of these
+software packages for their contributions to free and open-source software.
+
+
+Buildroot and BusyBox are Copyright (c) Erik Andersen <andersen@codepoet.org>.
+BusyBox is licensed under the GNU General Public License (GPL). A copy of
+this license is available in the file GPL-2,
+http://xm-test.xensource.com/ramdisks/GPL-2, or alongside this file.
+
+uClibc is licensed under the GNU Lesser General Public License (LGPL). A copy
+of this license is available in the file
+http://xm-test.xensource.com/ramdisks/LGPL-2, or alongside this file.
diff --git a/tools/xm-test/ramdisk/README-XenSource-initrd-1.1-img b/tools/xm-test/ramdisk/README-XenSource-initrd-1.1-img
new file mode 100644
index 0000000000..526c601ccc
--- /dev/null
+++ b/tools/xm-test/ramdisk/README-XenSource-initrd-1.1-img
@@ -0,0 +1,45 @@
+XenSource xm-test 1.1 initrds
+=============================
+
+http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img and
+http://xm-test.xensource.com/ramdisks/initrd-1.1-powerpc.img are initrds
+suitable for use with Xen's xm-test regression testing suite. They has been
+built and provided by XenSource, for the convenience of Xen users. xm-test
+initrds may be mixed across minor xm-test versions, but not across major
+versions; this initrd is suitable for all 1.1.x versions of xm-test (as
+shipped with Xen 3.0.4 and the unstable tree leading up to that release).
+
+In order to use one of these initrds, run "./autogen; ./configure; make
+existing" inside the xm-test directory, and the appropriate initrd for your
+architecture will be downloaded automatically. Alternatively, if you have
+already downloaded that file, place it into the xm-test/ramdisk directory and
+run the same command. In either case, runtest.sh can then be used as normal.
+See xm-test/README for more details.
+
+These initrds were built using the infrastructure provided by xm-test. Each
+is a full guest operating system and filesystem, and as such includes a large
+number of pieces of software. The source code for the majority of these are
+included in full inside the file
+http://xm-test.xensource.com/ramdisks/<INITRD>-buildroot.tar.bz2, where
+<INITRD> is either initrd-1.1-i386 or initrd-1.1-powerpc as appropriate, or
+alongside this file. Copyright statements and licences are contained therein.
+The remaining source code is included in the Xen distribution, at
+http://www.xensource.com/xen/downloads/archives.html. The configurations used
+for BusyBox, uClibc, and Buildroot are available as
+http://xm-test.xensource.com/ramdisks/<INITRD>-busybox-config,
+http://xm-test.xensource.com/ramdisks/<INITRD>-uClibc-config, and
+http://xm-test.xensource.com/ramdisks/<INITRD>-buildroot-config respectively,
+or alongside this file.
+
+XenSource and the Xen contributors are grateful to the authors of these
+software packages for their contributions to free and open-source software.
+
+
+Buildroot and BusyBox are Copyright (c) Erik Andersen <andersen@codepoet.org>.
+BusyBox is licensed under the GNU General Public License (GPL). A copy of
+this license is available in the file GPL-2,
+http://xm-test.xensource.com/ramdisks/GPL-2, or alongside this file.
+
+uClibc is licensed under the GNU Lesser General Public License (LGPL). A copy
+of this license is available in the file
+http://xm-test.xensource.com/ramdisks/LGPL-2, or alongside this file.
diff --git a/tools/xm-test/ramdisk/configs/buildroot b/tools/xm-test/ramdisk/configs/buildroot-i386
index 1c550f15bc..284f4cf9ce 100644
--- a/tools/xm-test/ramdisk/configs/buildroot
+++ b/tools/xm-test/ramdisk/configs/buildroot-i386
@@ -13,6 +13,7 @@ BR2_i386=y
# BR2_nios2 is not set
# BR2_powerpc is not set
# BR2_sh is not set
+# BR2_sh64 is not set
# BR2_sparc is not set
# BR2_x86_64 is not set
BR2_x86_i386=y
@@ -27,6 +28,7 @@ BR2_ENDIAN="LITTLE"
#
BR2_WGET="wget --passive-ftp"
BR2_SVN="svn co"
+BR2_ZCAT="zcat"
BR2_TAR_OPTIONS=""
BR2_DL_DIR="$(BASE_DIR)/dl"
BR2_SOURCEFORGE_MIRROR="easynews"
@@ -34,6 +36,7 @@ BR2_STAGING_DIR="$(BUILD_DIR)/staging_dir"
BR2_TOPDIR_PREFIX=""
BR2_TOPDIR_SUFFIX=""
BR2_GNU_BUILD_SUFFIX="pc-linux-gnu"
+BR2_GNU_TARGET_SUFFIX="linux-uclibc"
BR2_JLEVEL=1
#
@@ -50,6 +53,7 @@ BR2_JLEVEL=1
# BR2_KERNEL_HEADERS_2_6_9 is not set
# BR2_KERNEL_HEADERS_2_6_11 is not set
BR2_KERNEL_HEADERS_2_6_12=y
+# BR2_KERNEL_HEADERS_2_6_18 is not set
BR2_DEFAULT_KERNEL_HEADERS="2.6.12"
#
@@ -68,14 +72,17 @@ BR2_PTHREADS_OLD=y
# BR2_BINUTILS_VERSION_2_14_90_0_8 is not set
# BR2_BINUTILS_VERSION_2_15 is not set
# BR2_BINUTILS_VERSION_2_15_94_0_2_2 is not set
-# BR2_BINUTILS_VERSION_2_15_97 is not set
# BR2_BINUTILS_VERSION_2_16_1 is not set
# BR2_BINUTILS_VERSION_2_16_90_0_3 is not set
-# BR2_BINUTILS_VERSION_2_16_91_0_3 is not set
-# BR2_BINUTILS_VERSION_2_16_91_0_4 is not set
# BR2_BINUTILS_VERSION_2_16_91_0_5 is not set
# BR2_BINUTILS_VERSION_2_16_91_0_6 is not set
BR2_BINUTILS_VERSION_2_16_91_0_7=y
+# BR2_BINUTILS_VERSION_2_17 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_2 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_3 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_4 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_5 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_6 is not set
BR2_BINUTILS_VERSION="2.16.91.0.7"
BR2_EXTRA_BINUTILS_CONFIG_OPTIONS=""
@@ -94,6 +101,7 @@ BR2_GCC_VERSION_3_4_6=y
# BR2_GCC_VERSION_4_0_2 is not set
# BR2_GCC_VERSION_4_0_3 is not set
# BR2_GCC_VERSION_4_1_0 is not set
+# BR2_GCC_VERSION_4_1_1 is not set
# BR2_GCC_VERSION_4_2 is not set
# BR2_GCC_IS_SNAP is not set
BR2_GCC_VERSION="3.4.6"
@@ -101,6 +109,7 @@ BR2_GCC_VERSION="3.4.6"
BR2_EXTRA_GCC_CONFIG_OPTIONS=""
# BR2_INSTALL_LIBSTDCPP is not set
# BR2_INSTALL_OBJC is not set
+# BR2_GCC_SHARED_LIBGCC is not set
#
# Ccache Options
@@ -118,6 +127,7 @@ BR2_CCACHE=y
# elf2flt
#
# BR2_ELF2FLT is not set
+# BR2_MKLIBS is not set
#
# Common Toolchain Options
@@ -179,6 +189,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
# BR2_PACKAGE_DIRECTFB is not set
# BR2_PACKAGE_DISTCC is not set
# BR2_PACKAGE_DM is not set
+# BR2_PACKAGE_DMRAID is not set
# BR2_PACKAGE_DNSMASQ is not set
# BR2_PACKAGE_DROPBEAR is not set
# BR2_PACKAGE_ETHTOOL is not set
@@ -191,6 +202,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
# BR2_PACKAGE_LIBINTL is not set
# BR2_PACKAGE_GZIP is not set
# BR2_PACKAGE_HASERL is not set
+# BR2_PACKAGE_HDPARM is not set
# BR2_PACKAGE_HOSTAP is not set
# BR2_PACKAGE_HOTPLUG is not set
# BR2_PACKAGE_IOSTAT is not set
@@ -213,10 +225,12 @@ BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
# BR2_PACKAGE_LIGHTTPD is not set
# BR2_PACKAGE_LINKS is not set
# BR2_PACKAGE_LRZSZ is not set
+# BR2_PACKAGE_LSOF is not set
# BR2_PACKAGE_LTP-TESTSUITE is not set
# BR2_PACKAGE_LTT is not set
# BR2_PACKAGE_LVM2 is not set
# BR2_PACKAGE_LZO is not set
+# BR2_PACKAGE_LZMA is not set
# BR2_PACKAGE_M4 is not set
# BR2_PACKAGE_MDADM is not set
# BR2_PACKAGE_MEMTESTER is not set
@@ -230,6 +244,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
# BR2_PACKAGE_MROUTED is not set
# BR2_PACKAGE_MTD is not set
# BR2_PACKAGE_NANO is not set
+# BR2_PACKAGE_NBD is not set
# BR2_PACKAGE_NCURSES is not set
# BR2_PACKAGE_NETKITBASE is not set
# BR2_PACKAGE_NETKITTELNET is not set
@@ -241,6 +256,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
# BR2_PACKAGE_OPENSSL is not set
# BR2_PACKAGE_OPENVPN is not set
# BR2_PACKAGE_PCIUTILS is not set
+# BR2_PACKAGE_PKGCONFIG is not set
# BR2_PACKAGE_PORTAGE is not set
# BR2_PACKAGE_PORTMAP is not set
# BR2_PACKAGE_PPPD is not set
@@ -259,6 +275,7 @@ BR2_QTE_TMAKE_VERSION="1.13"
# BR2_PACKAGE_SLANG is not set
# BR2_PACKAGE_SMARTMONTOOLS is not set
# BR2_PACKAGE_SOCAT is not set
+# BR2_PACKAGE_SQLITE is not set
# BR2_PACKAGE_STRACE is not set
# BR2_PACKAGE_SUDO is not set
# BR2_PACKAGE_SYSKLOGD is not set
@@ -283,7 +300,6 @@ BR2_QTE_TMAKE_VERSION="1.13"
# BR2_PACKAGE_WIPE is not set
# BR2_PACKAGE_WIRELESS_TOOLS is not set
# BR2_PACKAGE_XFSPROGS is not set
-# BR2_PACKAGE_XORG is not set
# BR2_PACKAGE_ZLIB is not set
BR2_PACKAGE_HPING=y
diff --git a/tools/xm-test/ramdisk/configs/buildroot-powerpc b/tools/xm-test/ramdisk/configs/buildroot-powerpc
new file mode 100644
index 0000000000..f0a64ffd5c
--- /dev/null
+++ b/tools/xm-test/ramdisk/configs/buildroot-powerpc
@@ -0,0 +1,338 @@
+#
+# Automatically generated make config: don't edit
+#
+BR2_HAVE_DOT_CONFIG=y
+# BR2_alpha is not set
+# BR2_arm is not set
+# BR2_armeb is not set
+# BR2_cris is not set
+# BR2_i386 is not set
+# BR2_m68k is not set
+# BR2_mips is not set
+# BR2_mipsel is not set
+# BR2_nios2 is not set
+BR2_powerpc=y
+# BR2_sh is not set
+# BR2_sh64 is not set
+# BR2_sparc is not set
+# BR2_x86_64 is not set
+BR2_ARCH="powerpc"
+BR2_ENDIAN="BIG"
+
+#
+# Build options
+#
+BR2_WGET="wget --passive-ftp"
+BR2_SVN="svn co"
+BR2_ZCAT="zcat"
+BR2_TAR_OPTIONS=""
+BR2_DL_DIR="$(BASE_DIR)/dl"
+BR2_SOURCEFORGE_MIRROR="easynews"
+BR2_STAGING_DIR="$(BUILD_DIR)/staging_dir"
+BR2_TOPDIR_PREFIX=""
+BR2_TOPDIR_SUFFIX=""
+BR2_GNU_BUILD_SUFFIX="pc-linux-gnu"
+BR2_GNU_TARGET_SUFFIX="linux-uclibc"
+BR2_JLEVEL=1
+
+#
+# Toolchain Options
+#
+
+#
+# Kernel Header Options
+#
+# BR2_KERNEL_HEADERS_2_4_25 is not set
+# BR2_KERNEL_HEADERS_2_4_27 is not set
+# BR2_KERNEL_HEADERS_2_4_29 is not set
+# BR2_KERNEL_HEADERS_2_4_31 is not set
+# BR2_KERNEL_HEADERS_2_6_9 is not set
+# BR2_KERNEL_HEADERS_2_6_11 is not set
+BR2_KERNEL_HEADERS_2_6_12=y
+# BR2_KERNEL_HEADERS_2_6_18 is not set
+BR2_DEFAULT_KERNEL_HEADERS="2.6.12"
+
+#
+# uClibc Options
+#
+# BR2_UCLIBC_VERSION_SNAPSHOT is not set
+# BR2_ENABLE_LOCALE is not set
+# BR2_PTHREADS_NONE is not set
+# BR2_PTHREADS is not set
+BR2_PTHREADS_OLD=y
+# BR2_PTHREADS_NATIVE is not set
+
+#
+# Binutils Options
+#
+# BR2_BINUTILS_VERSION_2_14_90_0_8 is not set
+# BR2_BINUTILS_VERSION_2_15 is not set
+# BR2_BINUTILS_VERSION_2_15_94_0_2_2 is not set
+# BR2_BINUTILS_VERSION_2_16_1 is not set
+# BR2_BINUTILS_VERSION_2_16_90_0_3 is not set
+# BR2_BINUTILS_VERSION_2_16_91_0_5 is not set
+# BR2_BINUTILS_VERSION_2_16_91_0_6 is not set
+# BR2_BINUTILS_VERSION_2_16_91_0_7 is not set
+BR2_BINUTILS_VERSION_2_17=y
+# BR2_BINUTILS_VERSION_2_17_50_0_2 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_3 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_4 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_5 is not set
+# BR2_BINUTILS_VERSION_2_17_50_0_6 is not set
+BR2_BINUTILS_VERSION="2.17"
+BR2_EXTRA_BINUTILS_CONFIG_OPTIONS=""
+
+#
+# Gcc Options
+#
+# BR2_GCC_VERSION_3_3_5 is not set
+# BR2_GCC_VERSION_3_3_6 is not set
+BR2_GCC_VERSION_3_4_2=y
+# BR2_GCC_VERSION_3_4_3 is not set
+# BR2_GCC_VERSION_3_4_4 is not set
+# BR2_GCC_VERSION_3_4_5 is not set
+# BR2_GCC_VERSION_3_4_6 is not set
+# BR2_GCC_VERSION_4_0_0 is not set
+# BR2_GCC_VERSION_4_0_1 is not set
+# BR2_GCC_VERSION_4_0_2 is not set
+# BR2_GCC_VERSION_4_0_3 is not set
+# BR2_GCC_VERSION_4_1_0 is not set
+# BR2_GCC_VERSION_4_1_1 is not set
+# BR2_GCC_VERSION_4_2 is not set
+# BR2_GCC_IS_SNAP is not set
+BR2_GCC_VERSION="3.4.2"
+# BR2_GCC_USE_SJLJ_EXCEPTIONS is not set
+BR2_EXTRA_GCC_CONFIG_OPTIONS=""
+# BR2_INSTALL_LIBSTDCPP is not set
+# BR2_INSTALL_OBJC is not set
+# BR2_GCC_SHARED_LIBGCC is not set
+
+#
+# Ccache Options
+#
+BR2_CCACHE=y
+
+#
+# Gdb Options
+#
+# BR2_PACKAGE_GDB is not set
+# BR2_PACKAGE_GDB_SERVER is not set
+# BR2_PACKAGE_GDB_HOST is not set
+
+#
+# elf2flt
+#
+# BR2_ELF2FLT is not set
+# BR2_MKLIBS is not set
+
+#
+# Common Toolchain Options
+#
+# BR2_PACKAGE_SSTRIP_TARGET is not set
+# BR2_PACKAGE_SSTRIP_HOST is not set
+BR2_ENABLE_MULTILIB=y
+BR2_LARGEFILE=y
+# BR2_SOFT_FLOAT is not set
+BR2_TARGET_OPTIMIZATION="-Os -pipe"
+BR2_CROSS_TOOLCHAIN_TARGET_UTILS=y
+
+#
+# Package Selection for the target
+#
+
+#
+# The default minimal system
+#
+BR2_PACKAGE_BUSYBOX=y
+# BR2_PACKAGE_BUSYBOX_SNAPSHOT is not set
+BR2_PACKAGE_BUSYBOX_INSTALL_SYMLINKS=y
+BR2_PACKAGE_BUSYBOX_CONFIG="package/busybox/busybox.config"
+
+#
+# The minimum needed to build a uClibc development system
+#
+# BR2_PACKAGE_BASH is not set
+# BR2_PACKAGE_BZIP2 is not set
+# BR2_PACKAGE_COREUTILS is not set
+# BR2_PACKAGE_DIFFUTILS is not set
+# BR2_PACKAGE_ED is not set
+# BR2_PACKAGE_FINDUTILS is not set
+# BR2_PACKAGE_FLEX is not set
+# BR2_PACKAGE_GAWK is not set
+# BR2_PACKAGE_GCC_TARGET is not set
+# BR2_PACKAGE_CCACHE_TARGET is not set
+# BR2_PACKAGE_GREP is not set
+# BR2_PACKAGE_MAKE is not set
+# BR2_PACKAGE_PATCH is not set
+# BR2_PACKAGE_SED is not set
+# BR2_PACKAGE_TAR is not set
+
+#
+# Other stuff
+#
+# BR2_PACKAGE_ACPID is not set
+# BR2_PACKAGE_ASTERISK is not set
+# BR2_PACKAGE_AT is not set
+# BR2_PACKAGE_AUTOCONF is not set
+# BR2_PACKAGE_AUTOMAKE is not set
+# BR2_PACKAGE_BERKELEYDB is not set
+# BR2_PACKAGE_BIND is not set
+# BR2_PACKAGE_BISON is not set
+# BR2_PACKAGE_BOA is not set
+# BR2_PACKAGE_BRIDGE is not set
+# BR2_PACKAGE_CUSTOMIZE is not set
+# BR2_PACKAGE_ISC_DHCP is not set
+# BR2_PACKAGE_DIALOG is not set
+# BR2_PACKAGE_DIRECTFB is not set
+# BR2_PACKAGE_DISTCC is not set
+# BR2_PACKAGE_DM is not set
+# BR2_PACKAGE_DMRAID is not set
+# BR2_PACKAGE_DNSMASQ is not set
+# BR2_PACKAGE_DROPBEAR is not set
+# BR2_PACKAGE_ETHTOOL is not set
+# BR2_PACKAGE_EXPAT is not set
+# BR2_PACKAGE_E2FSPROGS is not set
+# BR2_PACKAGE_FAKEROOT is not set
+# BR2_PACKAGE_FILE is not set
+# BR2_PACKAGE_FREETYPE is not set
+# BR2_PACKAGE_GETTEXT is not set
+# BR2_PACKAGE_LIBINTL is not set
+# BR2_PACKAGE_GZIP is not set
+# BR2_PACKAGE_HASERL is not set
+# BR2_PACKAGE_HDPARM is not set
+# BR2_PACKAGE_HOSTAP is not set
+# BR2_PACKAGE_HOTPLUG is not set
+# BR2_PACKAGE_IOSTAT is not set
+# BR2_PACKAGE_IPROUTE2 is not set
+# BR2_PACKAGE_IPSEC_TOOLS is not set
+# BR2_PACKAGE_IPTABLES is not set
+# BR2_PACKAGE_JPEG is not set
+# BR2_PACKAGE_LESS is not set
+# BR2_PACKAGE_LIBCGI is not set
+# BR2_PACKAGE_LIBCGICC is not set
+# BR2_PACKAGE_LIBELF is not set
+# BR2_PACKAGE_LIBFLOAT is not set
+# BR2_PACKAGE_LIBGLIB12 is not set
+# BR2_PACKAGE_LIBMAD is not set
+# BR2_PACKAGE_LIBPCAP is not set
+# BR2_PACKAGE_LIBPNG is not set
+# BR2_PACKAGE_LIBSYSFS is not set
+# BR2_PACKAGE_LIBTOOL is not set
+# BR2_PACKAGE_LIBUSB is not set
+# BR2_PACKAGE_LIGHTTPD is not set
+# BR2_PACKAGE_LINKS is not set
+# BR2_PACKAGE_LRZSZ is not set
+# BR2_PACKAGE_LSOF is not set
+# BR2_PACKAGE_LTP-TESTSUITE is not set
+# BR2_PACKAGE_LTT is not set
+# BR2_PACKAGE_LVM2 is not set
+# BR2_PACKAGE_LZO is not set
+# BR2_PACKAGE_LZMA is not set
+# BR2_PACKAGE_M4 is not set
+# BR2_PACKAGE_MDADM is not set
+# BR2_PACKAGE_MEMTESTER is not set
+# BR2_PACKAGE_MICROCOM is not set
+# BR2_PACKAGE_MICROPERL is not set
+# BR2_PACKAGE_MICROWIN is not set
+# BR2_PACKAGE_MKDOSFS is not set
+# BR2_PACKAGE_MODULE_INIT_TOOLS is not set
+# BR2_PACKAGE_MODUTILS is not set
+# BR2_PACKAGE_MPG123 is not set
+# BR2_PACKAGE_MROUTED is not set
+# BR2_PACKAGE_MTD is not set
+# BR2_PACKAGE_NANO is not set
+# BR2_PACKAGE_NBD is not set
+# BR2_PACKAGE_NCURSES is not set
+# BR2_PACKAGE_NETKITBASE is not set
+# BR2_PACKAGE_NETKITTELNET is not set
+# BR2_PACKAGE_NETSNMP is not set
+# BR2_PACKAGE_NEWT is not set
+# BR2_PACKAGE_NTP is not set
+# BR2_PACKAGE_OPENNTPD is not set
+# BR2_PACKAGE_OPENSSH is not set
+# BR2_PACKAGE_OPENSSL is not set
+# BR2_PACKAGE_OPENVPN is not set
+# BR2_PACKAGE_PCIUTILS is not set
+# BR2_PACKAGE_PKGCONFIG is not set
+# BR2_PACKAGE_PORTAGE is not set
+# BR2_PACKAGE_PORTMAP is not set
+# BR2_PACKAGE_PPPD is not set
+# BR2_PACKAGE_PROCPS is not set
+# BR2_PACKAGE_PSMISC is not set
+# BR2_PACKAGE_PYTHON is not set
+# BR2_PACKAGE_QTE is not set
+BR2_QTE_TMAKE_VERSION="1.13"
+# BR2_PACKAGE_RAIDTOOLS is not set
+# BR2_READLINE is not set
+# BR2_PACKAGE_RSYNC is not set
+# BR2_PACKAGE_RUBY is not set
+# BR2_PACKAGE_RXVT is not set
+# BR2_PACKAGE_SDL is not set
+# BR2_PACKAGE_SFDISK is not set
+# BR2_PACKAGE_SLANG is not set
+# BR2_PACKAGE_SMARTMONTOOLS is not set
+# BR2_PACKAGE_SOCAT is not set
+# BR2_PACKAGE_SQLITE is not set
+# BR2_PACKAGE_STRACE is not set
+# BR2_PACKAGE_SUDO is not set
+# BR2_PACKAGE_SYSKLOGD is not set
+# BR2_PACKAGE_SYSVINIT is not set
+# BR2_PACKAGE_TCL is not set
+# BR2_PACKAGE_TCPDUMP is not set
+# BR2_PACKAGE_TFTPD is not set
+# BR2_PACKAGE_THTTPD is not set
+# BR2_PACKAGE_TINYLOGIN is not set
+# BR2_PACKAGE_TINYX is not set
+# BR2_PACKAGE_TN5250 is not set
+# BR2_PACKAGE_TTCP is not set
+# BR2_PACKAGE_UDEV is not set
+# BR2_PACKAGE_UDHCP is not set
+# BR2_PACKAGE_UEMACS is not set
+# BR2_PACKAGE_USBUTILS is not set
+# BR2_PACKAGE_UTIL-LINUX is not set
+# BR2_PACKAGE_VALGRIND is not set
+# BR2_PACKAGE_VTUN is not set
+# BR2_PACKAGE_WGET is not set
+# BR2_PACKAGE_WHICH is not set
+# BR2_PACKAGE_WIPE is not set
+# BR2_PACKAGE_WIRELESS_TOOLS is not set
+# BR2_PACKAGE_XFSPROGS is not set
+# BR2_PACKAGE_ZLIB is not set
+BR2_PACKAGE_HPING=y
+
+#
+# Target Options
+#
+
+#
+# filesystem for target device
+#
+# BR2_TARGET_ROOTFS_CRAMFS is not set
+# BR2_TARGET_ROOTFS_CLOOP is not set
+BR2_TARGET_ROOTFS_EXT2=y
+BR2_TARGET_ROOTFS_EXT2_BLOCKS=0
+BR2_TARGET_ROOTFS_EXT2_INODES=0
+BR2_TARGET_ROOTFS_EXT2_RESBLKS=0
+BR2_TARGET_ROOTFS_EXT2_SQUASH=y
+BR2_TARGET_ROOTFS_EXT2_OUTPUT="$(IMAGE).ext2"
+# BR2_TARGET_ROOTFS_EXT2_GZ is not set
+BR2_TARGET_ROOTFS_EXT2_COPYTO=""
+# BR2_TARGET_ROOTFS_JFFS2 is not set
+# BR2_TARGET_ROOTFS_SQUASHFS is not set
+# BR2_TARGET_ROOTFS_TAR is not set
+
+#
+# bootloader for target device
+#
+# BR2_TARGET_YABOOT is not set
+
+#
+# Board Support Options
+#
+
+#
+# Generic System Support
+#
+# BR2_TARGET_GENERIC_ACCESS_POINT is not set
+# BR2_TARGET_GENERIC_FIREWALL is not set
+# BR2_TARGET_GENERIC_DEV_SYSTEM is not set
diff --git a/tools/xm-test/ramdisk/make-release.sh b/tools/xm-test/ramdisk/make-release.sh
new file mode 100644
index 0000000000..5aa3831181
--- /dev/null
+++ b/tools/xm-test/ramdisk/make-release.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+if [ "$1" == "" ]
+then
+ arch=""
+elif [ "$1" == "powerpc" ]
+then
+ arch="BR_ARCH=powerpc"
+else
+ echo "Invalid architecture specified." >&2
+ exit 1
+fi
+
+set -eu
+
+tempdir=$(mktemp -d)
+
+dir=$(dirname "$0")
+
+cd $(dirname "$dir")
+
+./autogen
+./configure
+
+cd "$dir"
+
+rm -Rf buildroot
+make $arch initrd.img
+
+initrd=$(readlink "initrd.img")
+prefix=$(basename "$initrd" ".img")
+arch=$(echo "$prefix" | sed -e 's/.*-//')
+
+cp "$initrd" "$tempdir"
+
+cp "buildroot/.config" "$tempdir/$prefix-buildroot-config"
+cp "buildroot/package/busybox/busybox.config" "$tempdir/$prefix-busybox-config"
+cp "buildroot/toolchain/uClibc/uClibc.config" "$tempdir/$prefix-uClibc-config"
+
+mv "buildroot" "$tempdir/buildroot-$arch"
+cd $tempdir
+rm -Rf "buildroot-$arch"/toolchain_build*
+rm -Rf "buildroot-$arch"/build_*
+tar cjf "$prefix-buildroot.tar.bz2" "buildroot-$arch"
+rm -Rf "buildroot-$arch"
+
+echo -e "\n\nYour release is in $tempdir."
diff --git a/tools/xm-test/ramdisk/patches/buildroot/add_xvd_devices.patch b/tools/xm-test/ramdisk/patches/buildroot/add_xvd_devices.patch
new file mode 100644
index 0000000000..25d073da68
--- /dev/null
+++ b/tools/xm-test/ramdisk/patches/buildroot/add_xvd_devices.patch
@@ -0,0 +1,13 @@
+--- buildroot/target/generic/device_table.txt~ 2006-10-26 17:38:04.000000000 +1000
++++ buildroot/target/generic/device_table.txt 2006-10-26 17:37:08.000000000 +1000
+@@ -169,3 +169,10 @@
+ #/dev/mcd b 640 0 0 23 0 0 0 -
+ #/dev/optcd b 640 0 0 17 0 0 0 -
+
++# Xen Virtual Block Devices
++/dev/xvda b 640 0 0 202 0 0 0 -
++/dev/xvda b 640 0 0 202 1 1 1 4
++/dev/xvdb b 640 0 0 202 16 0 0 -
++/dev/xvdb b 640 0 0 202 17 1 1 4
++/dev/xvdc b 640 0 0 202 32 0 0 -
++/dev/xvdc b 640 0 0 202 33 1 1 4
diff --git a/tools/xm-test/runtest.sh b/tools/xm-test/runtest.sh
index 9e11824b80..22c0736bf2 100755
--- a/tools/xm-test/runtest.sh
+++ b/tools/xm-test/runtest.sh
@@ -76,9 +76,17 @@ runnable_tests() {
# using the right version
realrd=$(readlink ramdisk/initrd.img)
eval $(./lib/XmTestReport/xmtest.py)
- rrdver="initrd-${XM_TEST_MAJ}.${XM_TEST_MIN}.img"
- if [ "$realrd" != "$rrdver" ]; then
- echo "Error: ramdisk/initrd.img is from an old version"
+ ARCH=$(uname -m | sed -e s/i.86/i386/ -e 's/ppc\(64\)*/powerpc/')
+ rrdver="initrd-${XM_TEST_MAJ}.${XM_TEST_MIN}-${ARCH}.img"
+ exp_flag=0
+ realarch=`echo $realrd | awk -F- '{print $3}' | awk -F. '{print $1}'`
+ rrdarch=`echo $rrdver | awk -F- '{print $3}' | awk -F. '{print $1}'`
+ if [ "$realarch" = "i386" -a "$rrdarch" = "x86_64" ]; then
+ exp_flag=1
+ fi
+ if [ $exp_flag -eq 0 -a "$realrd" != "$rrdver" ]; then
+ echo "Error: ramdisk/initrd.img is from an old version, or is not for this "
+ echo "architecture ($ARCH)."
echo "You need to build a ramdisk from at least ${XM_TEST_MAJ}.${XM_TEST_MIN}"
exit 1
fi
@@ -133,7 +141,11 @@ get_contact_info() {
run_tests() {
groupentered=$1
output=$2
+ report=$3
+ startfile=${report}.start
+ stopfile=${report}.stop
+ date -R > $startfile
exec < grouptest/$groupentered
while read casename testlist; do
echo Running $casename tests...
@@ -147,6 +159,7 @@ run_tests() {
fi
done
+ date -R > $stopfile
}
@@ -156,7 +169,10 @@ make_text_reports() {
failures=$2
output=$3
reportfile=$4
+ report=$5
summary=summary.tmp
+ startfile=${report}.start
+ stopfile=${report}.stop
echo "Making PASS/FAIL report ($passfail)..."
cat $OUTPUT | egrep '(REASON|PASS|FAIL|XPASS|XFAIL|SKIP)' | perl -pe 's/^(PASS|FAIL|XPASS|XFAIL)(.+)$/$1$2\n/' > $passfail
@@ -167,7 +183,12 @@ make_text_reports() {
NUMFAIL=`grep -c FAIL $output`
NUMXPASS=`grep -c XPASS $output`
NUMXFAIL=`grep -c XFAIL $output`
+ START=`cat $startfile`
+ STOP=`cat $stopfile`
cat > $summary << EOF
+Xm-test timing summary:
+ Run Started : $START
+ Run Stoped : $STOP
Xm-test execution summary:
PASS: $NUMPASS
FAIL: $NUMFAIL
@@ -197,6 +218,11 @@ run=yes
unsafe=no
GROUPENTERED=default
+if [ -d /etc/xen/acm-security/policies ]; then
+ cp -f tests/security-acm/xm-test-security_policy.xml \
+ /etc/xen/acm-security/policies
+fi
+
# Resolve options
while [ $# -gt 0 ]
do
@@ -289,8 +315,8 @@ if [ "$run" != "no" ]; then
if [ "$unsafe" = "no" ]; then
make_environment_report $OSREPORTTEMP $PROGREPORTTEMP
fi
- run_tests $GROUPENTERED $OUTPUT
- make_text_reports $PASSFAIL $FAILURES $OUTPUT $TXTREPORT
+ run_tests $GROUPENTERED $OUTPUT $REPORT
+ make_text_reports $PASSFAIL $FAILURES $OUTPUT $TXTREPORT $REPORT
if [ "$unsafe" = "no" ]; then
make_result_report $OUTPUT $RESULTREPORTTEMP
cat $OSREPORTTEMP $PROGREPORTTEMP $RESULTREPORTTEMP > $XMLREPORT
diff --git a/tools/xm-test/tests/Makefile.am b/tools/xm-test/tests/Makefile.am
index c01cdd244d..0ba9076a1d 100644
--- a/tools/xm-test/tests/Makefile.am
+++ b/tools/xm-test/tests/Makefile.am
@@ -19,6 +19,7 @@ SUBDIRS = \
pause \
reboot \
sched-credit \
+ security-acm \
sedf \
shutdown \
sysrq \
diff --git a/tools/xm-test/tests/block-create/01_block_attach_device_pos.py b/tools/xm-test/tests/block-create/01_block_attach_device_pos.py
index 13e6a5efb8..5bbf1232b3 100644
--- a/tools/xm-test/tests/block-create/01_block_attach_device_pos.py
+++ b/tools/xm-test/tests/block-create/01_block_attach_device_pos.py
@@ -32,12 +32,12 @@ except ConsoleError, e:
FAIL(str(e))
-block_attach(domain, "phy:ram1", "sdb1")
+block_attach(domain, "phy:ram1", "xvda1")
-try:
- run = console.runCmd("cat /proc/partitions")
+try:
+ run = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
- FAIL(str(e))
+ FAIL(str(e))
# Close the console
domain.closeConsole()
@@ -45,5 +45,5 @@ domain.closeConsole()
# Stop the domain (nice shutdown)
domain.stop()
-if not re.search("sdb1",run["output"]):
+if not re.search("xvda1",run["output"]):
FAIL("Device is not actually connected to the domU")
diff --git a/tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py b/tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py
index b4e7c6974a..e70f58398b 100644
--- a/tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py
+++ b/tools/xm-test/tests/block-create/02_block_attach_file_device_pos.py
@@ -32,10 +32,10 @@ except ConsoleError, e:
FAIL(str(e))
-block_attach(domain, "file:/dev/ram1", "sdb2")
+block_attach(domain, "file:/dev/ram1", "xvda1")
try:
- run = console.runCmd("cat /proc/partitions")
+ run = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
FAIL(str(e))
@@ -45,5 +45,5 @@ domain.closeConsole()
# Stop the domain (nice shutdown)
domain.stop()
-if not re.search("sdb2",run["output"]):
- FAIL("Device is not actually connected to the domU")
+if not re.search("xvda1",run["output"]):
+ FAIL("Device is not actually connected to the domU")
diff --git a/tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py b/tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py
index 6d9eb513fe..2e258840c4 100644
--- a/tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py
+++ b/tools/xm-test/tests/block-create/04_block_attach_device_repeatedly_pos.py
@@ -30,14 +30,14 @@ except ConsoleError, e:
FAIL(str(e))
for i in range(10):
- status, output = traceCommand("xm block-attach %s phy:ram1 sdb1 w" % domain.getName())
- if i == 0 and status != 0:
- FAIL("xm block attach returned invalid %i != 0" % status)
- if i > 0 and status == 0:
- FAIL("xm block-attach (repeat) returned invalid %i > 0" % status)
- run = console.runCmd("cat /proc/partitions")
- if not re.search("sdb1", run['output']):
- FAIL("Device is not actually attached to domU")
+ status, output = traceCommand("xm block-attach %s phy:ram1 xvda1 w" % domain.getName())
+ if i == 0 and status != 0:
+ FAIL("xm block attach returned invalid %i != 0" % status)
+ if i > 0 and status == 0:
+ FAIL("xm block-attach (repeat) returned invalid %i > 0" % status)
+ run = console.runCmd("cat /proc/partitions")
+ if not re.search("xvda1", run['output']):
+ FAIL("Device is not actually attached to domU")
# Close the console
domain.closeConsole()
diff --git a/tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py b/tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py
index db406fecd4..325e160937 100644
--- a/tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py
+++ b/tools/xm-test/tests/block-create/05_block_attach_and_dettach_device_repeatedly_pos.py
@@ -32,15 +32,15 @@ except ConsoleError, e:
for i in range(10):
- block_attach(domain, "phy:ram1", "sdb1")
- run = console.runCmd("cat /proc/partitions")
- if not re.search("sdb1", run["output"]):
- FAIL("Failed to attach block device: /proc/partitions does not show that!")
-
- block_detach(domain, "sdb1")
- run = console.runCmd("cat /proc/partitions")
- if re.search("sdb1", run["output"]):
- FAIL("Failed to dettach block device: /proc/partitions still showing that!")
+ block_attach(domain, "phy:ram1", "xvda1")
+ run = console.runCmd("cat /proc/partitions")
+ if not re.search("xvda1", run["output"]):
+ FAIL("Failed to attach block device: /proc/partitions does not show that!")
+
+ block_detach(domain, "xvda1")
+ run = console.runCmd("cat /proc/partitions")
+ if re.search("xvda1", run["output"]):
+ FAIL("Failed to dettach block device: /proc/partitions still showing that!")
# Close the console
domain.closeConsole()
diff --git a/tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py b/tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py
index edfeba1643..958b13e1ea 100644
--- a/tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py
+++ b/tools/xm-test/tests/block-create/06_block_attach_baddomain_neg.py
@@ -8,13 +8,11 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("Block-attach not supported for HVM domains")
-status, output = traceCommand("xm block-attach NOT-EXIST phy:ram1 sdb1 w")
+status, output = traceCommand("xm block-attach NOT-EXIST phy:ram1 xvda1 w")
eyecatcher = "Error"
where = output.find(eyecatcher)
if status == 0:
- FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
+ FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
elif where == -1:
- FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
-
-
+ FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
diff --git a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
index f2043d7dd3..3e9f0f2514 100644
--- a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
+++ b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
@@ -30,18 +30,18 @@ except ConsoleError, e:
FAIL(str(e))
-status, output = traceCommand("xm block-attach %s phy:NOT-EXIST sdb1 w" % domain.getName())
+status, output = traceCommand("xm block-attach %s phy:NOT-EXIST xvda1 w" % domain.getName())
eyecatcher = "Error"
where = output.find(eyecatcher)
if status == 0:
- FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
+ FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
elif where == -1:
- FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
+ FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
try:
- run = console.runCmd("cat /proc/partitions")
+ run = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
- FAIL(str(e))
+ FAIL(str(e))
# Close the console
domain.closeConsole()
@@ -49,5 +49,5 @@ domain.closeConsole()
# Stop the domain (nice shutdown)
domain.stop()
-if re.search("sdb1",run["output"]):
- FAIL("Non existent Device was connected to the domU")
+if re.search("xvda1",run["output"]):
+ FAIL("Non existent Device was connected to the domU")
diff --git a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
index b1c776d71a..802e101147 100644
--- a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
+++ b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
@@ -29,18 +29,18 @@ except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
-status, output = traceCommand("xm block-attach %s file:/dev/NOT-EXIST sdb1 w" % domain.getName())
+status, output = traceCommand("xm block-attach %s file:/dev/NOT-EXIST xvda1 w" % domain.getName())
eyecatcher = "Error"
where = output.find(eyecatcher)
if status == 0:
- FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
+ FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
elif where == -1:
- FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
-
+ FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
+
try:
- run = console.runCmd("cat /proc/partitions")
+ run = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
- FAIL(str(e))
+ FAIL(str(e))
# Close the console
domain.closeConsole()
@@ -48,5 +48,5 @@ domain.closeConsole()
# Stop the domain (nice shutdown)
domain.stop()
-if re.search("sdb1",run["output"]):
- FAIL("Non existent Device was connected to the domU")
+if re.search("xvda1",run["output"]):
+ FAIL("Non existent Device was connected to the domU")
diff --git a/tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py b/tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py
index b997379a25..b97b70c499 100644
--- a/tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py
+++ b/tools/xm-test/tests/block-create/09_block_attach_and_dettach_device_check_data_pos.py
@@ -12,7 +12,7 @@ if ENABLE_HVM_SUPPORT:
SKIP("Block-attach not supported for HVM domains")
# Create a domain (default XmTestDomain, with our ramdisk)
-domain = XmTestDomain()
+domain = XmTestDomain(extraConfig={"extra":"rw"})
try:
console = domain.start()
@@ -35,27 +35,27 @@ if s != 0:
FAIL("mke2fs returned %i != 0" % s)
for i in range(10):
- block_attach(domain, "phy:ram1", "hda1")
- run = console.runCmd("cat /proc/partitions")
- if not re.search("hda1", run["output"]):
- FAIL("Failed to attach block device: /proc/partitions does not show that!")
-
- console.runCmd("mkdir -p /mnt/hda1; mount /dev/hda1 /mnt/hda1")
-
- if i:
- run = console.runCmd("cat /mnt/hda1/myfile | grep %s" % (i-1))
- if run['return']:
- FAIL("File created was lost or not updated!")
-
- console.runCmd("echo \"%s\" > /mnt/hda1/myfile" % i)
- run = console.runCmd("cat /mnt/hda1/myfile")
- print run['output']
- console.runCmd("umount /mnt/hda1")
-
- block_detach(domain, "hda1")
- run = console.runCmd("cat /proc/partitions")
- if re.search("hda1", run["output"]):
- FAIL("Failed to dettach block device: /proc/partitions still showing that!")
+ block_attach(domain, "phy:ram1", "xvda1")
+ run = console.runCmd("cat /proc/partitions")
+ if not re.search("xvda1", run["output"]):
+ FAIL("Failed to attach block device: /proc/partitions does not show that!")
+
+ console.runCmd("mkdir -p /mnt/xvda1; mount /dev/xvda1 /mnt/xvda1")
+
+ if i:
+ run = console.runCmd("cat /mnt/xvda1/myfile | grep %s" % (i-1))
+ if run['return']:
+ FAIL("File created was lost or not updated!")
+
+ console.runCmd("echo \"%s\" > /mnt/xvda1/myfile" % i)
+ run = console.runCmd("cat /mnt/xvda1/myfile")
+ print run['output']
+ console.runCmd("umount /mnt/xvda1")
+
+ block_detach(domain, "xvda1")
+ run = console.runCmd("cat /proc/partitions")
+ if re.search("xvda1", run["output"]):
+ FAIL("Failed to dettach block device: /proc/partitions still showing that!")
# Close the console
domain.closeConsole()
diff --git a/tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py b/tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py
index 833f75c21a..3ac6078388 100644
--- a/tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py
+++ b/tools/xm-test/tests/block-create/10_block_attach_dettach_multiple_devices.py
@@ -15,7 +15,7 @@ from XmTestLib.block_utils import *
def availableRamdisks():
i = 0
while os.access("/dev/ram%d" % i, os.F_OK ):
- i += 1
+ i += 1
return i
@@ -36,7 +36,7 @@ def detach(devname):
return -2, "Failed to detach block device: /proc/partitions still showing that!"
return 0, None
-
+
if ENABLE_HVM_SUPPORT:
SKIP("Block-attach not supported for HVM domains")
@@ -69,22 +69,22 @@ while i < ramdisks or devices:
op = random.randint(0,1) # 1 = attach, 0 = detach
if (not devices or op) and i < ramdisks:
i += 1
- devname = "/dev/hda%d" % i
- phy = "/dev/ram%d" % i
- print "Attaching %s to %s" % (devname, phy)
- status, msg = attach( phy, devname )
- if status:
- FAIL(msg)
- else:
- devices.append(devname)
+ devname = "/dev/xvda%d" % i
+ phy = "/dev/ram%d" % i
+ print "Attaching %s to %s" % (devname, phy)
+ status, msg = attach( phy, devname )
+ if status:
+ FAIL(msg)
+ else:
+ devices.append(devname)
elif devices:
devname = random.choice(devices)
- devices.remove(devname)
- print "Detaching %s" % devname
- status, msg = detach(devname)
- if status:
- FAIL(msg)
+ devices.remove(devname)
+ print "Detaching %s" % devname
+ status, msg = detach(devname)
+ if status:
+ FAIL(msg)
# Close the console
domain.closeConsole()
diff --git a/tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py b/tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py
index 43f55e234c..1b8a289394 100644
--- a/tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py
+++ b/tools/xm-test/tests/block-create/11_block_attach_shared_dom0.py
@@ -24,7 +24,7 @@ if s != 0:
# Now try to start a DomU with write access to /dev/ram0
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
domain = XmTestDomain(extraConfig=config);
diff --git a/tools/xm-test/tests/block-create/12_block_attach_shared_domU.py b/tools/xm-test/tests/block-create/12_block_attach_shared_domU.py
index 362e5039e8..79c9571f8c 100644
--- a/tools/xm-test/tests/block-create/12_block_attach_shared_domU.py
+++ b/tools/xm-test/tests/block-create/12_block_attach_shared_domU.py
@@ -8,7 +8,7 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("Block-attach not supported for HVM domains")
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
dom1 = XmTestDomain(extraConfig=config)
dom2 = XmTestDomain(dom1.getName() + "-2",
diff --git a/tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py b/tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py
index 835dfa9b1d..1d056841cc 100644
--- a/tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py
+++ b/tools/xm-test/tests/block-destroy/01_block-destroy_btblock_pos.py
@@ -9,7 +9,7 @@ from XmTestLib.block_utils import block_detach
if ENABLE_HVM_SUPPORT:
SKIP("Block-detach not supported for HVM domains")
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
domain = XmTestDomain(extraConfig=config)
try:
@@ -21,7 +21,7 @@ except DomainError, e:
try:
console.setHistorySaveCmds(value=True)
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
run2 = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
FAIL(str(e))
@@ -29,10 +29,10 @@ except ConsoleError, e:
if run["return"] != 0:
FAIL("block device isn't attached; can't detach!")
-block_detach(domain, "hda1")
+block_detach(domain, "xvda1")
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py b/tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py
index 47ff9a6fe5..cf6329228a 100644
--- a/tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py
+++ b/tools/xm-test/tests/block-destroy/02_block-destroy_rtblock_pos.py
@@ -18,9 +18,9 @@ except DomainError, e:
print e.extra
FAIL("Unable to create domain")
-block_attach(domain, "phy:/dev/ram0", "hda1")
+block_attach(domain, "phy:/dev/ram0", "xvda1")
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
@@ -28,9 +28,9 @@ except ConsoleError, e:
if run["return"] != 0:
FAIL("Failed to verify that block dev is attached")
-block_detach(domain, "hda1")
+block_detach(domain, "xvda1")
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py b/tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py
index eea2027771..d7df7ac317 100644
--- a/tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py
+++ b/tools/xm-test/tests/block-destroy/04_block-destroy_nonattached_neg.py
@@ -19,7 +19,7 @@ except DomainError, e:
print e.extra
FAIL("Unable to create domain")
-status, output = traceCommand("xm block-detach %s sda1" % domain.getId())
+status, output = traceCommand("xm block-detach %s xvda1" % domain.getId())
eyecatcher1 = "Error:"
eyecatcher2 = "Traceback"
diff --git a/tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py b/tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py
index d77e587c33..7e3d9904da 100644
--- a/tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py
+++ b/tools/xm-test/tests/block-destroy/05_block-destroy_byname_pos.py
@@ -9,7 +9,7 @@ from XmTestLib.block_utils import block_detach
if ENABLE_HVM_SUPPORT:
SKIP("Block-detach not supported for HVM domains")
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
domain = XmTestDomain(extraConfig=config)
try:
@@ -20,7 +20,7 @@ except DomainError, e:
FAIL("Unable to create domain")
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
run2 = console.runCmd("cat /proc/partitions")
except ConsoleError, e:
FAIL(str(e))
@@ -28,10 +28,10 @@ except ConsoleError, e:
if run["return"] != 0:
FAIL("block device isn't attached; can't detach!")
-block_detach(domain, "hda1")
+block_detach(domain, "xvda1")
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py b/tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py
index 38d60a92c1..292db063d6 100644
--- a/tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py
+++ b/tools/xm-test/tests/block-destroy/06_block-destroy_check_list_pos.py
@@ -12,7 +12,7 @@ def checkXmLongList(domain):
s, o = traceCommand("xm list --long %s" % domain.getName())
if s != 0:
FAIL("xm list --long <dom> failed")
- if re.search("hda1", o):
+ if re.search("xvda1", o):
return True
else:
return False
@@ -27,12 +27,12 @@ try:
except DomainError,e:
FAIL(str(e))
-block_attach(domain, "phy:/dev/ram0", "hda1")
+block_attach(domain, "phy:/dev/ram0", "xvda1")
if not checkXmLongList(domain):
- FAIL("xm long list does not show that hda1 was attached")
+ FAIL("xm long list does not show that xvda1 was attached")
-block_detach(domain, "hda1")
+block_detach(domain, "xvda1")
if checkXmLongList(domain):
- FAIL("xm long list does not show that hda1 was removed")
+ FAIL("xm long list does not show that xvda1 was removed")
diff --git a/tools/xm-test/tests/block-integrity/01_block_device_read_verify.py b/tools/xm-test/tests/block-integrity/01_block_device_read_verify.py
index b4f03da628..28531f1559 100644
--- a/tools/xm-test/tests/block-integrity/01_block_device_read_verify.py
+++ b/tools/xm-test/tests/block-integrity/01_block_device_read_verify.py
@@ -33,10 +33,10 @@ s, o = traceCommand("md5sum /dev/ram1")
dom0_md5sum_match = re.search(r"^[\dA-Fa-f]{32}", o, re.M)
-block_attach(domain, "phy:ram1", "hda1")
+block_attach(domain, "phy:ram1", "xvda1")
try:
- run = console.runCmd("md5sum /dev/hda1")
+ run = console.runCmd("md5sum /dev/xvda1")
except ConsoleError, e:
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-integrity/02_block_device_write_verify.py b/tools/xm-test/tests/block-integrity/02_block_device_write_verify.py
index f8fa19aa8b..ed791a008a 100644
--- a/tools/xm-test/tests/block-integrity/02_block_device_write_verify.py
+++ b/tools/xm-test/tests/block-integrity/02_block_device_write_verify.py
@@ -28,12 +28,12 @@ except DomainError, e:
console.setHistorySaveCmds(value=True)
-block_attach(domain, "phy:ram1", "hda1")
+block_attach(domain, "phy:ram1", "xvda1")
console.setTimeout(120)
try:
- run = console.runCmd("dd if=/dev/urandom bs=512 count=`cat /sys/block/hda1/size` | tee /dev/hda1 | md5sum")
+ run = console.runCmd("dd if=/dev/urandom bs=512 count=`cat /sys/block/xvda1/size` | tee /dev/xvda1 | md5sum")
except ConsoleError, e:
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-list/01_block-list_pos.py b/tools/xm-test/tests/block-list/01_block-list_pos.py
index 05df76c189..2b19208d97 100644
--- a/tools/xm-test/tests/block-list/01_block-list_pos.py
+++ b/tools/xm-test/tests/block-list/01_block-list_pos.py
@@ -11,7 +11,7 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("Block-list not supported for HVM domains")
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
domain = XmTestDomain(extraConfig=config)
try:
@@ -22,7 +22,7 @@ except DomainError, e:
FAIL("Unable to create domain")
status, output = traceCommand("xm block-list %s" % domain.getId())
-eyecatcher = "769"
+eyecatcher = "51713"
where = output.find(eyecatcher)
if status != 0:
FAIL("xm block-list returned bad status, expected 0, status is %i" % status)
@@ -31,7 +31,7 @@ elif where < 0:
#Verify the block device on DomainU
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py b/tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py
index 256b44d951..8ad0df3a0c 100644
--- a/tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py
+++ b/tools/xm-test/tests/block-list/02_block-list_attachbd_pos.py
@@ -22,11 +22,11 @@ except DomainError, e:
FAIL("Unable to create domain")
#Attach one virtual block device to domainU
-block_attach(domain, "phy:/dev/ram0", "hda1")
+block_attach(domain, "phy:/dev/ram0", "xvda1")
#Verify block-list on Domain0
status, output = traceCommand("xm block-list %s" % domain.getId())
-eyecatcher = "769"
+eyecatcher = "51713"
where = output.find(eyecatcher)
if status != 0:
FAIL("xm block-list returned bad status, expected 0, status is %i" % status)
@@ -35,7 +35,7 @@ elif where < 0 :
#Verify attached block device on DomainU
try:
- run = console.runCmd("cat /proc/partitions | grep hda1")
+ run = console.runCmd("cat /proc/partitions | grep xvda1")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py b/tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py
index 1556b065ef..b128ec1bba 100644
--- a/tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py
+++ b/tools/xm-test/tests/block-list/03_block-list_anotherbd_pos.py
@@ -11,7 +11,7 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("Block-list not supported for HVM domains")
-config = {"disk":"phy:/dev/ram0,hda1,w"}
+config = {"disk":"phy:/dev/ram0,xvda1,w"}
domain = XmTestDomain(extraConfig=config)
try:
@@ -26,14 +26,14 @@ if status != 0:
FAIL("Fail to list block device")
#Add another virtual block device to the domain
-status, output = traceCommand("xm block-attach %s phy:/dev/ram1 hda2 w" % domain.getId())
+status, output = traceCommand("xm block-attach %s phy:/dev/ram1 xvda2 w" % domain.getId())
if status != 0:
FAIL("Fail to attach block device")
#Verify block-list on Domain0
status, output = traceCommand("xm block-list %s" % domain.getId())
-eyecatcher1 = "769"
-eyecatcher2 = "770"
+eyecatcher1 = "51713"
+eyecatcher2 = "51714"
where1 = output.find(eyecatcher1)
where2 = output.find(eyecatcher2)
if status != 0:
@@ -43,7 +43,7 @@ elif (where1 < 0) and (where2 < 0):
#Verify attached block device on DomainU
try:
- run = console.runCmd("cat /proc/partitions | grep hda1;cat /proc/partitions | grep hda2")
+ run = console.runCmd("cat /proc/partitions | grep xvda1;cat /proc/partitions | grep xvda2")
except ConsoleError, e:
saveLog(console.getHistory())
FAIL(str(e))
diff --git a/tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py b/tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py
index db2c54104d..8d3bf08c42 100644
--- a/tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py
+++ b/tools/xm-test/tests/block-list/06_block-list_checkremove_pos.py
@@ -22,39 +22,39 @@ if s != 0:
if o:
FAIL("block-list without devices reported something!")
-block_attach(domain, "phy:/dev/ram0", "hda1")
+block_attach(domain, "phy:/dev/ram0", "xvda1")
s, o = traceCommand("xm block-list %s" % domain.getName())
if s != 0:
FAIL("block-list failed")
-if o.find("769") == -1:
+if o.find("51713") == -1:
FAIL("block-list didn't show the block device I just attached!")
-block_attach(domain, "phy:/dev/ram1", "hda2")
+block_attach(domain, "phy:/dev/ram1", "xvda2")
s, o = traceCommand("xm block-list %s" % domain.getName())
if s != 0:
FAIL("block-list failed")
-if o.find("770") == -1:
+if o.find("51714") == -1:
FAIL("block-list didn't show the other block device I just attached!")
-block_detach(domain, "hda1")
+block_detach(domain, "xvda1")
s, o = traceCommand("xm block-list %s" % domain.getName())
if s != 0:
FAIL("block-list failed after detaching a device")
-if o.find("769") != -1:
- FAIL("hda1 still shown in block-list after detach!")
-if o.find("770") == -1:
- FAIL("hda2 not shown after detach of hda1!")
+if o.find("51713") != -1:
+ FAIL("xvda1 still shown in block-list after detach!")
+if o.find("51714") == -1:
+ FAIL("xvda2 not shown after detach of xvda1!")
-block_detach(domain, "hda2")
+block_detach(domain, "xvda2")
s, o = traceCommand("xm block-list %s" % domain.getName())
if s != 0:
FAIL("block-list failed after detaching another device")
-if o.find("770") != -1:
- FAIL("hda2 still shown in block-list after detach!")
+if o.find("51714") != -1:
+ FAIL("xvda2 still shown in block-list after detach!")
if o:
FAIL("block-list still shows something after all devices detached!")
diff --git a/tools/xm-test/tests/create/07_create_mem64_pos.py b/tools/xm-test/tests/create/07_create_mem64_pos.py
index ae2f84adb1..1a27d55722 100644
--- a/tools/xm-test/tests/create/07_create_mem64_pos.py
+++ b/tools/xm-test/tests/create/07_create_mem64_pos.py
@@ -42,7 +42,7 @@ if eyecatcher1 != "True":
FAIL("Failed to verify that a 64MB domain started")
eyecatcher2 = getDomMem(domain_mem64.getName())
-if eyecatcher2 != 64:
+if eyecatcher2 not in range(62, 65):
FAIL("Started domain with 64MB, but it got %i MB" % eyecatcher2)
#stop the domain (nice shutdown)
diff --git a/tools/xm-test/tests/create/08_create_mem128_pos.py b/tools/xm-test/tests/create/08_create_mem128_pos.py
index 0d50006b36..85d35173c7 100644
--- a/tools/xm-test/tests/create/08_create_mem128_pos.py
+++ b/tools/xm-test/tests/create/08_create_mem128_pos.py
@@ -42,7 +42,7 @@ if eyecatcher1 != "True":
FAIL("Failed to verify that a 128MB domain started")
eyecatcher2 = getDomMem(domain_mem128.getName())
-if eyecatcher2 != 128:
+if eyecatcher2 not in range(126, 129):
FAIL("Started domain with 128MB, but it got %i MB" % eyecatcher2)
#stop the domain (nice shutdown)
diff --git a/tools/xm-test/tests/create/09_create_mem256_pos.py b/tools/xm-test/tests/create/09_create_mem256_pos.py
index c926d62de8..28db3dade2 100644
--- a/tools/xm-test/tests/create/09_create_mem256_pos.py
+++ b/tools/xm-test/tests/create/09_create_mem256_pos.py
@@ -42,7 +42,7 @@ if eyecatcher1 != "True":
FAIL("Failed to verify that a 256MB domain started")
eyecatcher2 = getDomMem(domain_mem256.getName())
-if eyecatcher2 != 256:
+if eyecatcher2 not in range(254, 257):
FAIL("Started domain with 256MB, but it got %i MB" % eyecatcher2)
#stop the domain (nice shutdown)
diff --git a/tools/xm-test/tests/create/11_create_concurrent_pos.py b/tools/xm-test/tests/create/11_create_concurrent_pos.py
index ad5f297719..fd8f4dd3bf 100644
--- a/tools/xm-test/tests/create/11_create_concurrent_pos.py
+++ b/tools/xm-test/tests/create/11_create_concurrent_pos.py
@@ -16,7 +16,7 @@ else:
MAX_DOMS = 50
MIN_DOMS = 5
-MEM_PER_DOM = 24
+MEM_PER_DOM = minSafeMem()
domains = []
console = []
diff --git a/tools/xm-test/tests/create/12_create_concurrent_stress_pos.py b/tools/xm-test/tests/create/12_create_concurrent_stress_pos.py
index 06b125083f..5235491d88 100644
--- a/tools/xm-test/tests/create/12_create_concurrent_stress_pos.py
+++ b/tools/xm-test/tests/create/12_create_concurrent_stress_pos.py
@@ -8,11 +8,18 @@ from XmTestLib import *
import time
DOMS=5
-MEM=32
+MEM=minSafeMem()
DUR=60
domains = []
+free_mem = int(getInfo("free_memory"))
+NUM_DOMS = int(free_mem / MEM)
+
+if NUM_DOMS < DOMS:
+ SKIP("Need %i MB of RAM to start %i@%iMB domains! (%i MB avail)" %
+ (DOMS * MEM, DOMS, MEM, free_mem))
+
for i in range(0,DOMS):
dom = XmTestDomain(extraConfig={"memory" : MEM})
diff --git a/tools/xm-test/tests/create/14_create_blockroot_pos.py b/tools/xm-test/tests/create/14_create_blockroot_pos.py
index 58eeb2b9b3..79dd622b5a 100644
--- a/tools/xm-test/tests/create/14_create_blockroot_pos.py
+++ b/tools/xm-test/tests/create/14_create_blockroot_pos.py
@@ -18,17 +18,12 @@ rdpath = getRdPath()
# print "Using %s" % output
if ENABLE_HVM_SUPPORT:
- domain = XmTestDomain(name="14_create_blockroot")
+ config = None
else:
- config = {"memory" : "64",
- "root" : "/dev/hda1",
- "name" : "14_create_blockroot",
- "kernel" : getDefaultKernel(),
+ config = {"root" : "/dev/hda1",
"disk" : "file:%s/initrd.img,hda1,w" % rdpath
}
- domConfig = XenConfig()
- domConfig.setOpts(config)
- domain = XenDomain(name=domConfig.getOpt("name"), config=domConfig)
+domain = XmTestDomain(name="14_create_blockroot", extraConfig=config)
try:
console = domain.start()
diff --git a/tools/xm-test/tests/create/15_create_smallmem_pos.py b/tools/xm-test/tests/create/15_create_smallmem_pos.py
index faca03336b..d7797c6bd2 100644
--- a/tools/xm-test/tests/create/15_create_smallmem_pos.py
+++ b/tools/xm-test/tests/create/15_create_smallmem_pos.py
@@ -5,8 +5,8 @@
from XmTestLib import *
-# 32MBs is the default lower limit for creating domains, it should work
-MEM = 32
+# Create a domain with the minimum memory allocation
+MEM = minSafeMem()
domain = XmTestDomain(extraConfig={"memory": MEM,
"extra" :"mem=%iM" % MEM})
diff --git a/tools/xm-test/tests/create/16_create_smallmem_neg.py b/tools/xm-test/tests/create/16_create_smallmem_neg.py
index 9990add78c..6a3f417fe9 100644
--- a/tools/xm-test/tests/create/16_create_smallmem_neg.py
+++ b/tools/xm-test/tests/create/16_create_smallmem_neg.py
@@ -3,6 +3,7 @@
# Copyright (C) International Business Machines Corp., 2005
# Author: Dan Smith <danms@us.ibm.com>
+import re
from XmTestLib import *
# This is under the default lower limit of 32 and we expect this test
@@ -16,13 +17,14 @@ try:
console = domain.start()
console.runCmd("ls")
except DomainError, e:
- FAIL("Unable to start a domain with %i MB" % MEM)
+ if not re.search('^Error: Domain memory must be at least \d+ KB', e.extra):
+ # PPC gracefully fails like this, rather than crashing.
+ FAIL("Unable to start a domain with %i MB" % MEM)
except ConsoleError, e:
if e.reason == RUNAWAY:
print "Domain with %i MB has runaway console as expected" % MEM
- else:
- print "Starting a domain with %i MB failed as expected" % MEM
else:
FAIL("Starting a console with %i MB passed, expected test to fail" % MEM)
+print "Starting a domain with %i MB failed as expected" % MEM
domain.destroy()
diff --git a/tools/xm-test/tests/network-attach/04_network_attach_baddomain_neg.py b/tools/xm-test/tests/network-attach/04_network_attach_baddomain_neg.py
index 838d66c32a..f69adb6e82 100644
--- a/tools/xm-test/tests/network-attach/04_network_attach_baddomain_neg.py
+++ b/tools/xm-test/tests/network-attach/04_network_attach_baddomain_neg.py
@@ -10,8 +10,6 @@ status, output = traceCommand("xm network-attach NOT-EXIST")
eyecatcher = "Error"
where = output.find(eyecatcher)
if status == 0:
- FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
+ FAIL("xm network-attach returned bad status, expected non 0, status is: %i" % status )
elif where == -1:
- FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
-
-
+ FAIL("xm network-attach returned bad output, expected Error, output is: %s" % output )
diff --git a/tools/xm-test/tests/security-acm/01_security-acm_basic.py b/tools/xm-test/tests/security-acm/01_security-acm_basic.py
new file mode 100644
index 0000000000..6459bb9fd8
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/01_security-acm_basic.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A couple of simple tests that test ACM security extensions
+# for the xm tool. The following xm subcommands are tested:
+#
+# - makepolicy
+# - labels
+# - rmlabel
+# - addlabel
+# - getlabel
+# - resources
+
+from XmTestLib import *
+from xen.util import security
+import commands
+import os
+import re
+
+testpolicy = "xm-test"
+testlabel = "blue"
+vmconfigfile = "/tmp/xm-test.conf"
+testresource = "phy:ram0"
+
+if not isACMEnabled():
+ SKIP("Not running this test since ACM not enabled.")
+
+status, output = traceCommand("xm makepolicy %s" % (testpolicy))
+if status != 0 or output != "":
+ FAIL("'xm makepolicy' failed with status %d and output\n%s" %
+ (status,output));
+
+status, output = traceCommand("xm labels %s" % (testpolicy))
+if status != 0:
+ FAIL("'xm labels' failed with status %d.\n" % status)
+
+#Need to get a vm config file - just have it written to a file
+domain = XmTestDomain()
+domain.config.write(vmconfigfile)
+
+#Whatever label it might have - remove it
+status, output = traceCommand("xm rmlabel dom %s" %
+ (vmconfigfile))
+
+status, output = traceCommand("xm addlabel %s dom %s %s" %
+ (testlabel, vmconfigfile, testpolicy))
+if status != 0:
+ FAIL("'xm addlabel' failed with status %d.\n" % status)
+
+status, output = traceCommand("xm getlabel dom %s" %
+ (vmconfigfile))
+
+if status != 0:
+ FAIL("'xm getlabel' failed with status %d, output:\n%s" %
+ (status, output))
+if output != "policy=%s,label=%s" % (testpolicy,testlabel):
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+
+status, output = traceCommand("xm rmlabel dom %s" %
+ (vmconfigfile))
+
+if status != 0:
+ FAIL("'xm rmlabel' failed with status %d, output: \n%s" %
+ (status,output))
+if output != "":
+ FAIL("Received unexpected output from 'xm rmlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm getlabel dom %s" %
+ (vmconfigfile))
+
+if output != "Error: 'Domain not labeled'":
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+#Whatever label the resource might have, remove it
+status, output = traceCommand("xm rmlabel res %s" %
+ (testresource))
+
+status, output = traceCommand("xm addlabel %s res %s %s" %
+ (testlabel, testresource, testpolicy))
+if status != 0:
+ FAIL("'xm addlabel' on resource failed with status %d.\n" % status)
+
+status, output = traceCommand("xm getlabel res %s" % (testresource))
+
+if status != 0:
+ FAIL("'xm getlabel' on resource failed with status %d, output:\n%s" %
+ (status, output))
+if output != "policy=%s,label=%s" % (testpolicy,testlabel):
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm resources")
+
+if status != 0:
+ FAIL("'xm resources' did not run properly")
+if not re.search(security.unify_resname(testresource), output):
+ FAIL("'xm resources' did not show the tested resource '%s'." %
+ testresource)
+
+status, output = traceCommand("xm rmlabel res %s" %
+ (testresource))
+
+if status != 0:
+ FAIL("'xm rmlabel' on resource failed with status %d, output: \n%s" %
+ (status,output))
+if output != "":
+ FAIL("Received unexpected output from 'xm rmlabel': \n%s" %
+ (output))
+
+status, output = traceCommand("xm getlabel res %s" %
+ (testresource))
+
+if output != "Error: 'Resource not labeled'":
+ FAIL("Received unexpected output from 'xm getlabel': \n%s" %
+ (output))
diff --git a/tools/xm-test/tests/security-acm/02_security-acm_dom_start.py b/tools/xm-test/tests/security-acm/02_security-acm_dom_start.py
new file mode 100644
index 0000000000..4aac09d2fc
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/02_security-acm_dom_start.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# Simple test that starts two labeled domains; both domains should start
+#
+# The following xm subcommands are tested:
+# - dumppolicy
+# - labels
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "green"
+testlabel2 = "red"
+
+status, output = traceCommand("xm labels")
+
+labels = ["SystemManagement", "blue", "red", "green"]
+for l in labels:
+ if not re.search(l, output):
+ FAIL("Label '%s' not found in current policy!", l)
+
+status, output = traceCommand("xm dumppolicy")
+if status != 0:
+ FAIL("'xm dumppolicy' returned an error code.")
+lines = ["ssidref 0: 00 00 00 00",
+ "ssidref 1: 01 00 00 00",
+ "ssidref 2: 00 01 00 00",
+ "ssidref 3: 00 00 01 00",
+ "ssidref 4: 00 00 00 01"]
+for l in lines:
+ if not re.search(l, output):
+ FAIL("Could not find '%s' in output of 'xm dumppolicy'" % l)
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+verbose = True
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+try:
+ domain2.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 2nd labeled test domain.")
+
+domain2.destroy()
+domain1.destroy()
diff --git a/tools/xm-test/tests/security-acm/03_security-acm_dom_conflict.py b/tools/xm-test/tests/security-acm/03_security-acm_dom_conflict.py
new file mode 100644
index 0000000000..4aef380de5
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/03_security-acm_dom_conflict.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A test that exercises the conflict set of the chinese wall policy.
+# Start a first domain and then a second one. The second one is
+# expected NOT to be starteable.
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "blue"
+testlabel2 = "red"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("PERMITTED", output):
+ FAIL("'xm dry-run' did not succeed.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+try:
+ domain2.start(noConsole=True)
+ # Should never get here!
+ FAIL("Could start a domain in a conflict set - "
+ "this should not be possible")
+except DomainError, e:
+ #This is exactly what we want in this case
+ status = 0
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if status != 0:
+ FAIL("'xm dry-run' failed.")
+if not re.search("PERMITTED", output):
+ FAIL("'xm dry-run' did not show that operation was permitted.")
+
+domain1.destroy()
diff --git a/tools/xm-test/tests/security-acm/04_security-acm_dom_res.py b/tools/xm-test/tests/security-acm/04_security-acm_dom_res.py
new file mode 100644
index 0000000000..367016339f
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/04_security-acm_dom_res.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# Simple test that starts two labeled domains using labeled resources each
+#
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "green"
+resource1 = "phy:ram0"
+testlabel2 = "red"
+resource2 = "phy:/dev/ram1"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1),
+ "disk" :"%s,hda1,w" % (resource1)}
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+# Explicity label the resource
+ACMLabelResource(resource1, testlabel1)
+
+try:
+ domain1.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 1st labeled test domain.")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("%s: PERMITTED" % resource1, output):
+ FAIL("'xm dry-run' did not succeed.")
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel2),
+ "disk" :"%s,hda1,w" % (resource2)}
+
+domain2 = XmTestDomain(name="domain-%s" % testlabel2,
+ extraConfig=config)
+
+# Explicity label the resource
+ACMLabelResource(resource2, testlabel2)
+
+try:
+ domain2.start(noConsole=True)
+except DomainError, e:
+ if verbose:
+ print e.extra
+ FAIL("Unable to start 2nd labeled test domain.")
+
+# Verify with xm dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+
+if status != 0:
+ FAIL("'xm dry-run' failed")
+if not re.search("%s: PERMITTED" % resource2, output):
+ FAIL("'xm dry-run' did not succeed.")
+
+domain2.destroy()
+domain1.destroy()
diff --git a/tools/xm-test/tests/security-acm/05_security-acm_dom_res_conf.py b/tools/xm-test/tests/security-acm/05_security-acm_dom_res_conf.py
new file mode 100644
index 0000000000..89c6b5974c
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/05_security-acm_dom_res_conf.py
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#
+# A test that tries to start a domain using a resource that it is
+# not supposed to be able to use due to its labeling
+
+from XmTestLib import *
+from acm_utils import *
+import commands
+import os
+
+testlabel1 = "blue"
+resource1 = "phy:ram0"
+
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1),
+ "disk" :"%s,hda1,w" % (resource1)}
+
+domain1 = XmTestDomain(name="domain-%s" % testlabel1,
+ extraConfig=config)
+
+ACMLabelResource(resource1,"red")
+
+try:
+ domain1.start(noConsole=True)
+ # Should never get here
+ FAIL("Could start domain with resource that it is not supposed to access.")
+except DomainError, e:
+ #That's exactly what we want to have in this case
+ dummy = 0
+
+# Verify via dry-run
+status, output = traceCommand("xm dry-run /tmp/xm-test.conf | "
+ "grep -v \"Dry Run\"")
+if not re.search("%s: DENIED" %resource1, output):
+ FAIL("'xm dry-run' did not show expected result that operation was NOT "
+ "permitted: \n%s" % output)
diff --git a/tools/xm-test/tests/security-acm/06_security-acm_dom_block_attach.py b/tools/xm-test/tests/security-acm/06_security-acm_dom_block_attach.py
new file mode 100644
index 0000000000..f3908f7820
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/06_security-acm_dom_block_attach.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2005
+# Author: Stefan Berger <stefanb@us.ibm.com>
+# Based on block-create/01_block_attach_device_pos.py
+#
+# Create a domain and attach 2 resources to it. The first resource
+# should be attacheable, the 2nd one should not be due to the label it has.
+
+import re
+from XmTestLib import *
+from XmTestLib import block_utils
+from acm_utils import *
+
+testlabel1 = "blue"
+resource1 = "phy:ram1"
+resourcelabel1 = "blue"
+resource2 = "phy:/dev/ram0"
+resourcelabel2 = "red"
+
+if ENABLE_HVM_SUPPORT:
+ SKIP("Block-attach not supported for HVM domains")
+
+# Create a domain (default XmTestDomain, with our ramdisk)
+config = {"access_control":"policy=%s,label=%s" % (testpolicy,testlabel1)}
+
+domain = XmTestDomain(extraConfig=config)
+
+try:
+ console = domain.start()
+except DomainError, e:
+ FAIL(str(e))
+
+# Attach a console to it
+try:
+ console.setHistorySaveCmds(value=True)
+ # Run 'ls'
+ run = console.runCmd("ls")
+except ConsoleError, e:
+ saveLog(console.getHistory())
+ FAIL(str(e))
+
+
+# Explicitly label the 1st resource
+ACMLabelResource(resource1, resourcelabel1)
+block_utils.block_attach(domain, resource1, "sdb1")
+
+try:
+ run1 = console.runCmd("cat /proc/partitions")
+except ConsoleError, e:
+ FAIL(str(e))
+
+#Explicitly label the 2nd resource
+ACMLabelResource(resource2, resourcelabel2)
+#Cannot call block_attach here since we legally may fail the command
+status, output = traceCommand("xm block-attach %s %s %s w" %
+ (domain.getName(), resource2, "sdb2" ))
+
+for i in range(10):
+ if block_utils.get_state(domain, "sdb2") == 4:
+ break
+ time.sleep(1)
+
+try:
+ run2 = console.runCmd("cat /proc/partitions")
+except ConsoleError, e:
+ FAIL(str(e))
+
+# Close the console
+domain.closeConsole()
+
+# Stop the domain (nice shutdown)
+domain.stop()
+
+if not re.search("sdb1",run1["output"]):
+ FAIL("Labeled device 'sdb1' is not actually connected to the domU")
+
+if not re.search("sdb1",run2["output"]):
+ FAIL("Labeled device 'sdb1' has disappeared?!")
+
+if re.search("sdb2",run2["output"]):
+ FAIL("Labeled device 'sdb2' is connected to the domU but should not be")
diff --git a/tools/xm-test/tests/security-acm/Makefile.am b/tools/xm-test/tests/security-acm/Makefile.am
new file mode 100644
index 0000000000..7b691712f2
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/Makefile.am
@@ -0,0 +1,28 @@
+SUBDIRS =
+
+TESTS = 01_security-acm_basic.test \
+ 02_security-acm_dom_start.test \
+ 03_security-acm_dom_conflict.test \
+ 04_security-acm_dom_res.test \
+ 05_security-acm_dom_res_conf.test \
+ 06_security-acm_dom_block_attach.test
+
+XFAIL_TESTS =
+
+EXTRA_DIST = $(TESTS) $(XFAIL_TESTS) acm_utils.py
+TESTS_ENVIRONMENT=@TENV@
+
+%.test: %.py
+ cp $< $@
+ chmod +x $@
+ @if [ -d /etc/xen/acm-security/policies ]; then \
+ cp -f xm-test-security_policy.xml \
+ /etc/xen/acm-security/policies; \
+ fi;
+
+clean-local: am_config_clean-local
+
+am_config_clean-local:
+ rm -f *test
+ rm -f *log
+ rm -f *~
diff --git a/tools/xm-test/tests/security-acm/acm_utils.py b/tools/xm-test/tests/security-acm/acm_utils.py
new file mode 100644
index 0000000000..29608a38a4
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/acm_utils.py
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+
+# Copyright (C) International Business Machines Corp., 2006
+# Author: Stefan Berger <stefanb@us.ibm.com>
+
+from XmTestLib import *
+from XmTestLib.acm import *
+
+testpolicy = "xm-test"
+vmconfigfile = "/tmp/xm-test.conf"
+
+if not isACMEnabled():
+ SKIP("Not running this test since ACM not enabled.")
+
+ACMLoadPolicy(testpolicy)
diff --git a/tools/xm-test/tests/security-acm/xm-test-security_policy.xml b/tools/xm-test/tests/security-acm/xm-test-security_policy.xml
new file mode 100644
index 0000000000..b1736dbdf2
--- /dev/null
+++ b/tools/xm-test/tests/security-acm/xm-test-security_policy.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Auto-generated by ezPolicy -->
+<SecurityPolicyDefinition xmlns="http://www.ibm.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ibm.com ../../security_policy.xsd ">
+ <PolicyHeader>
+ <PolicyName>xm-test</PolicyName>
+ <Date>Fri Sep 29 14:44:38 2006</Date>
+ </PolicyHeader>
+
+ <SimpleTypeEnforcement>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ </SimpleTypeEnforcement>
+
+ <ChineseWall priority="PrimaryPolicyComponent">
+ <ChineseWallTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </ChineseWallTypes>
+
+ <ConflictSets>
+ <Conflict name="RER">
+ <Type>blue</Type>
+ <Type>red</Type>
+ </Conflict>
+ </ConflictSets>
+ </ChineseWall>
+
+ <SecurityLabelTemplate>
+ <SubjectLabels bootstrap="SystemManagement">
+ <VirtualMachineLabel>
+ <Name>SystemManagement</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ <Type>green</Type>
+ <Type>red</Type>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>SystemManagement</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>green</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>green</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>green</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>red</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>red</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>red</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+
+ <VirtualMachineLabel>
+ <Name>blue</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ <ChineseWallTypes>
+ <Type>blue</Type>
+ </ChineseWallTypes>
+ </VirtualMachineLabel>
+ </SubjectLabels>
+
+ <ObjectLabels>
+ <ResourceLabel>
+ <Name>SystemManagement</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>SystemManagement</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>green</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>green</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>red</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>red</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+
+ <ResourceLabel>
+ <Name>blue</Name>
+ <SimpleTypeEnforcementTypes>
+ <Type>blue</Type>
+ </SimpleTypeEnforcementTypes>
+ </ResourceLabel>
+ </ObjectLabels>
+ </SecurityLabelTemplate>
+</SecurityPolicyDefinition>
diff --git a/tools/xm-test/tests/vtpm/06_vtpm-susp_res_pcrs.py b/tools/xm-test/tests/vtpm/06_vtpm-susp_res_pcrs.py
index 9ac1ef5a9c..42661b83d8 100644
--- a/tools/xm-test/tests/vtpm/06_vtpm-susp_res_pcrs.py
+++ b/tools/xm-test/tests/vtpm/06_vtpm-susp_res_pcrs.py
@@ -42,7 +42,7 @@ except ConsoleError, e:
FAIL("Error while creating /dev/tpm0")
try:
- run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
+ run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > seq; cat seq > /dev/tpm0")
except ConsoleError, e:
saveLog(console.getHistory())
vtpm_cleanup(domName)
diff --git a/tools/xm-test/tests/vtpm/07_vtpm-mig_pcrs.py b/tools/xm-test/tests/vtpm/07_vtpm-mig_pcrs.py
index f8c437c9f9..f86e050519 100644
--- a/tools/xm-test/tests/vtpm/07_vtpm-mig_pcrs.py
+++ b/tools/xm-test/tests/vtpm/07_vtpm-mig_pcrs.py
@@ -43,7 +43,7 @@ except ConsoleError, e:
FAIL("Error while creating /dev/tpm0")
try:
- run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
+ run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > seq; cat seq > /dev/tpm0")
except ConsoleError, e:
saveLog(console.getHistory())
vtpm_cleanup(domName)
diff --git a/tools/xm-test/tests/vtpm/08_vtpm-mig_pcrs.py b/tools/xm-test/tests/vtpm/08_vtpm-mig_pcrs.py
index 5872e5a7d4..f1b460c0e2 100644
--- a/tools/xm-test/tests/vtpm/08_vtpm-mig_pcrs.py
+++ b/tools/xm-test/tests/vtpm/08_vtpm-mig_pcrs.py
@@ -43,7 +43,7 @@ except ConsoleError, e:
FAIL("Error while creating /dev/tpm0")
try:
- run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > /dev/tpm0")
+ run = console.runCmd("echo -ne \"\\x00\\xc1\\x00\\x00\\x00\\x22\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\0xf\\x10\\x11\\x12\\x13\\x14\" > seq; cat seq > /dev/tpm0")
except ConsoleError, e:
saveLog(console.getHistory())
vtpm_cleanup(domName)
diff --git a/tools/xm-test/tests/vtpm/vtpm_utils.py b/tools/xm-test/tests/vtpm/vtpm_utils.py
index 01a60f90c6..0af46574c9 100644
--- a/tools/xm-test/tests/vtpm/vtpm_utils.py
+++ b/tools/xm-test/tests/vtpm/vtpm_utils.py
@@ -8,12 +8,10 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("vtpm tests not supported for HVM domains")
-if not os.path.exists("/dev/tpm0"):
- SKIP("This machine has no hardware TPM; cannot run this test")
-
status, output = traceCommand("ps aux | grep vtpm_manager | grep -v grep")
if output == "":
- FAIL("virtual TPM manager must be started to run this test")
+ SKIP("virtual TPM manager must be started to run this test; might "
+ "need /dev/tpm0")
def vtpm_cleanup(domName):
traceCommand("/etc/xen/scripts/vtpm-delete %s" % domName)
diff --git a/unmodified_drivers/linux-2.6/Makefile b/unmodified_drivers/linux-2.6/Makefile
index 95d558f77b..119016f531 100644
--- a/unmodified_drivers/linux-2.6/Makefile
+++ b/unmodified_drivers/linux-2.6/Makefile
@@ -4,3 +4,4 @@ obj-m += platform-pci/
obj-m += xenbus/
obj-m += blkfront/
obj-m += netfront/
+obj-m += util/
diff --git a/unmodified_drivers/linux-2.6/README b/unmodified_drivers/linux-2.6/README
index 3d57a8e8a6..f5ad4dbabe 100644
--- a/unmodified_drivers/linux-2.6/README
+++ b/unmodified_drivers/linux-2.6/README
@@ -2,6 +2,6 @@ To build, run ./mkbuildtree and then
make -C /path/to/kernel/source M=$PWD modules
-You get four modules, xen-evtchn-pci.ko, xenbus.ko, xen-vbd.ko, and
-xen-vnif.ko. Load xen-evtchn-pci first, then xenbus, and then
+You get four modules, xen-platform-pci.ko, xenbus.ko, xen-vbd.ko, and
+xen-vnif.ko. Load xen-platform-pci first, then xenbus, and then
whichever of xen-vbd and xen-vnif you happen to need.
diff --git a/unmodified_drivers/linux-2.6/blkfront/Makefile b/unmodified_drivers/linux-2.6/blkfront/Makefile
new file mode 100644
index 0000000000..64e7acd194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/blkfront/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(KERNELRELEASE),)
+include $(src)/Kbuild
+endif
diff --git a/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopmd.h b/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopmd.h
new file mode 100644
index 0000000000..ebde567575
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopmd.h
@@ -0,0 +1,14 @@
+#ifndef _PGTABLE_NOPMD_H
+#define _PGTABLE_NOPMD_H
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
+#error "This version of Linux should not need compat pgtable-nopmd.h"
+#endif
+
+#define pud_t pgd_t
+#define pud_offset(d, va) d
+#define pud_none(pud) 0
+#define pud_present(pud) 1
+#define PTRS_PER_PUD 1
+
+#endif /* _PGTABLE_NOPMD_H */
diff --git a/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopud.h b/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopud.h
new file mode 100644
index 0000000000..05c9675760
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/compat-include/asm-generic/pgtable-nopud.h
@@ -0,0 +1,15 @@
+#ifndef _PGTABLE_NOPUD_H
+#define _PGTABLE_NOPUD_H
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
+#error "This version of Linux should not need compat pgtable-nopud.h"
+#endif
+
+#define pud_t pgd_t
+#define pud_offset(d, va) d
+#define pud_none(pud) 0
+#define pud_present(pud) 1
+#define pud_bad(pud) 0
+#define PTRS_PER_PUD 1
+
+#endif /* _PGTABLE_NOPUD_H */
diff --git a/unmodified_drivers/linux-2.6/compat-include/linux/io.h b/unmodified_drivers/linux-2.6/compat-include/linux/io.h
new file mode 100644
index 0000000000..10499023a5
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/compat-include/linux/io.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_IO_H
+#define _LINUX_IO_H
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#error "This version of Linux should not need compat linux/io.h"
+#endif
+
+#include <asm/io.h>
+
+#endif
diff --git a/unmodified_drivers/linux-2.6/compat-include/linux/mutex.h b/unmodified_drivers/linux-2.6/compat-include/linux/mutex.h
new file mode 100644
index 0000000000..fcb4a899c7
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/compat-include/linux/mutex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006 Cisco Systems. All rights reserved.
+ *
+ * This file is released under the GPLv2.
+ */
+
+/* mutex compatibility for pre-2.6.16 kernels */
+
+#ifndef __LINUX_MUTEX_H
+#define __LINUX_MUTEX_H
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#error "This version of Linux should not need compat mutex.h"
+#endif
+
+#include <linux/version.h>
+#include <asm/semaphore.h>
+
+#define mutex semaphore
+#define DEFINE_MUTEX(foo) DECLARE_MUTEX(foo)
+#define mutex_init(foo) init_MUTEX(foo)
+#define mutex_lock(foo) down(foo)
+#define mutex_lock_interruptible(foo) down_interruptible(foo)
+/* this function follows the spin_trylock() convention, so *
+ * it is negated to the down_trylock() return values! Be careful */
+#define mutex_trylock(foo) !down_trylock(foo)
+#define mutex_unlock(foo) up(foo)
+
+#endif /* __LINUX_MUTEX_H */
diff --git a/unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h b/unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h
new file mode 100644
index 0000000000..4a5aa7f9f9
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h
@@ -0,0 +1,72 @@
+#ifndef COMPAT_INCLUDE_XEN_PLATFORM_COMPAT_H
+#define COMPAT_INCLUDE_XEN_PLATFORM_COMPAT_H
+
+#include <linux/version.h>
+
+#include <linux/spinlock.h>
+
+#if defined(__LINUX_COMPILER_H) && !defined(__always_inline)
+#define __always_inline inline
+#endif
+
+#if defined(__LINUX_SPINLOCK_H) && !defined(DEFINE_SPINLOCK)
+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
+#endif
+
+#if defined(_LINUX_INIT_H) && !defined(__init)
+#define __init
+#endif
+
+#if defined(__LINUX_CACHE_H) && !defined(__read_mostly)
+#define __read_mostly
+#endif
+
+#if defined(_LINUX_SKBUFF_H) && !defined(NET_IP_ALIGN)
+#define NET_IP_ALIGN 0
+#endif
+
+#if defined(_LINUX_ERR_H) && !defined(IS_ERR_VALUE)
+#define IS_ERR_VALUE(x) unlikely((x) > (unsigned long)-1000L)
+#endif
+
+#if defined(_ASM_IA64_PGTABLE_H) && !defined(_PGTABLE_NOPUD_H)
+#include <asm-generic/pgtable-nopud.h>
+#endif
+
+/* Some kernels have this typedef backported so we cannot reliably
+ * detect based on version number, hence we forcibly #define it.
+ */
+#if defined(__LINUX_TYPES_H) || defined(__LINUX_GFP_H)
+#define gfp_t unsigned
+#endif
+
+#if defined(_LINUX_FS_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define nonseekable_open(inode, filp) /* Nothing to do */
+#endif
+
+#if defined(_LINUX_MM_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+unsigned long vmalloc_to_pfn(void *addr);
+#endif
+
+#if defined(__LINUX_COMPLETION_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout);
+#endif
+
+#if defined(_LINUX_SCHED_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+signed long schedule_timeout_interruptible(signed long timeout);
+#endif
+
+#if defined(_LINUX_SLAB_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+void *kzalloc(size_t size, int flags);
+#endif
+
+#if defined(_LINUX_BLKDEV_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#define end_that_request_last(req, uptodate) end_that_request_last(req)
+#endif
+
+#if defined(_LINUX_KERNEL_H) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#endif
+
+#endif
diff --git a/unmodified_drivers/linux-2.6/mkbuildtree b/unmodified_drivers/linux-2.6/mkbuildtree
index 76e228cbe9..ddcc13c75e 100644..100755
--- a/unmodified_drivers/linux-2.6/mkbuildtree
+++ b/unmodified_drivers/linux-2.6/mkbuildtree
@@ -1,5 +1,13 @@
#! /bin/sh
+if [ $1 ]; then
+ uname="$1"
+else
+ uname=`uname -m`
+ echo "Defaulting to this machine's architecture, $uname, for linking."
+ echo "This may be overridden on the command line (i386,x86_64,ia64)."
+fi
+
C=$PWD
XEN=$C/../../xen
@@ -14,42 +22,47 @@ done
ln -sf ${XL}/drivers/xen/core/gnttab.c platform-pci
ln -sf ${XL}/drivers/xen/core/features.c platform-pci
ln -sf ${XL}/drivers/xen/core/xen_proc.c xenbus
+ln -sf ${XL}/drivers/xen/core/reboot.c util
mkdir -p include
mkdir -p include/xen
mkdir -p include/public
mkdir -p include/asm
+mkdir -p include/asm/xen
lndir -silent ${XL}/include/xen include/xen
-ln -sf ${XEN}/include/public include/xen/interface
+ln -nsf ${XEN}/include/public include/xen/interface
# Need to be quite careful here: we don't want the files we link in to
# risk overriding the native Linux ones (in particular, system.h must
# be native and not xenolinux).
-uname=`uname -m`
case "$uname"
in
"x86_64")
- ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypervisor.h include/asm
- ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypercall.h include/asm
- ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/synch_bitops.h include/asm
- ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/maddr.h include/asm
- ln -sf ${XL}/include/asm-i386 include/asm-i386
- ;;
+ ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypervisor.h include/asm
+ ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/hypercall.h include/asm
+ ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/synch_bitops.h include/asm
+ ln -sf ${XL}/include/asm-x86_64/mach-xen/asm/maddr.h include/asm
+ ln -sf ${XL}/include/asm-i386 include/asm-i386
+ ;;
i[34567]86)
- ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypervisor.h include/asm
- ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypercall.h include/asm
- ln -sf ${XL}/include/asm-i386/mach-xen/asm/synch_bitops.h include/asm
- ln -sf ${XL}/include/asm-i386/mach-xen/asm/maddr.h include/asm
- ;;
+ ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypervisor.h include/asm
+ ln -sf ${XL}/include/asm-i386/mach-xen/asm/hypercall.h include/asm
+ ln -sf ${XL}/include/asm-i386/mach-xen/asm/synch_bitops.h include/asm
+ ln -sf ${XL}/include/asm-i386/mach-xen/asm/maddr.h include/asm
+ ;;
"ia64")
- ln -sf ${XL}/include/asm-ia64/hypervisor.h include/asm
- ln -sf ${XL}/include/asm-ia64/hypercall.h include/asm
- ln -sf ${XL}/include/asm-ia64/synch_bitops.h include/asm
- ln -sf ${XL}/include/asm-ia64/maddr.h include/asm
- ;;
+ ln -sf ${XL}/include/asm-ia64/hypervisor.h include/asm
+ ln -sf ${XL}/include/asm-ia64/hypercall.h include/asm
+ ln -sf ${XL}/include/asm-ia64/synch_bitops.h include/asm
+ ln -sf ${XL}/include/asm-ia64/maddr.h include/asm
+ ln -sf ${XL}/include/asm-ia64/xen/xcom_hcall.h include/asm/xen
+ ln -sf ${XL}/include/asm-ia64/xen/xencomm.h include/asm/xen
+ ln -sf ${XL}/arch/ia64/xen/xcom_mini.c platform-pci
+ ln -sf ${XL}/arch/ia64/xen/xencomm.c platform-pci
+ ;;
*)
- echo unknown architecture $uname
- exit 1
- ;;
+ echo unknown architecture $uname
+ exit 1
+ ;;
esac
diff --git a/unmodified_drivers/linux-2.6/netfront/Makefile b/unmodified_drivers/linux-2.6/netfront/Makefile
new file mode 100644
index 0000000000..64e7acd194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/netfront/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(KERNELRELEASE),)
+include $(src)/Kbuild
+endif
diff --git a/unmodified_drivers/linux-2.6/overrides.mk b/unmodified_drivers/linux-2.6/overrides.mk
index 74ef12c4c9..53a96d87a4 100644
--- a/unmodified_drivers/linux-2.6/overrides.mk
+++ b/unmodified_drivers/linux-2.6/overrides.mk
@@ -9,4 +9,4 @@ EXTRA_CFLAGS += -DCONFIG_XEN_SHADOW_MODE -DCONFIG_XEN_SHADOW_TRANSLATE
EXTRA_CFLAGS += -DCONFIG_XEN_BLKDEV_GRANT -DXEN_EVTCHN_MASK_OPS
EXTRA_CFLAGS += -DCONFIG_XEN_NETDEV_GRANT_RX -DCONFIG_XEN_NETDEV_GRANT_TX
EXTRA_CFLAGS += -D__XEN_INTERFACE_VERSION__=0x00030202
-EXTRA_CFLAGS += -I$(M)/include
+EXTRA_CFLAGS += -I$(M)/include -I$(M)/compat-include -DHAVE_XEN_PLATFORM_COMPAT_H
diff --git a/unmodified_drivers/linux-2.6/platform-pci/Kbuild b/unmodified_drivers/linux-2.6/platform-pci/Kbuild
index a4c1961a8a..a44e50e94c 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/Kbuild
+++ b/unmodified_drivers/linux-2.6/platform-pci/Kbuild
@@ -4,4 +4,9 @@ obj-m := xen-platform-pci.o
EXTRA_CFLAGS += -I$(M)/platform-pci
-xen-platform-pci-objs := evtchn.o platform-pci.o gnttab.o xen_support.o features.o
+xen-platform-pci-objs := evtchn.o platform-pci.o gnttab.o xen_support.o features.o platform-compat.o
+
+# Can we do better ?
+ifeq ($(ARCH),ia64)
+ xen-platform-pci-objs += xcom_mini.o xencomm.o
+endif
diff --git a/unmodified_drivers/linux-2.6/platform-pci/Makefile b/unmodified_drivers/linux-2.6/platform-pci/Makefile
new file mode 100644
index 0000000000..64e7acd194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(KERNELRELEASE),)
+include $(src)/Kbuild
+endif
diff --git a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c
index a38c50c1c4..e328cf9663 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c
+++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c
@@ -36,6 +36,10 @@
#include <xen/features.h>
#include "platform-pci.h"
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
void *shared_info_area;
#define MAX_EVTCHN 256
@@ -128,7 +132,7 @@ EXPORT_SYMBOL(notify_remote_via_irq);
irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned int l1i, l2i, port;
+ unsigned int l1i, port;
int cpu = smp_processor_id();
irqreturn_t(*handler) (int, void *, struct pt_regs *);
shared_info_t *s = shared_info_area;
@@ -136,38 +140,28 @@ irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned long l1, l2;
v->evtchn_upcall_pending = 0;
- /* NB. No need for a barrier here -- XCHG is a barrier
- * on x86. */
+ /* NB. No need for a barrier here -- XCHG is a barrier on x86. */
l1 = xchg(&v->evtchn_pending_sel, 0);
- while (l1 != 0)
- {
+ while (l1 != 0) {
l1i = __ffs(l1);
l1 &= ~(1 << l1i);
-
- l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
- while (l2 != 0)
- {
- l2i = __ffs(l2);
-
- port = (l1i * BITS_PER_LONG) + l2i;
+ while ((l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i])) {
+ port = (l1i * BITS_PER_LONG) + __ffs(l2);
synch_clear_bit(port, &s->evtchn_pending[0]);
if ((handler = evtchns[port].handler) != NULL)
- {
handler(port, evtchns[port].dev_id,
regs);
- }
else
- {
- printk(KERN_WARNING "unexpected event channel upcall on port %d!\n", port);
- }
- l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
+ printk(KERN_WARNING "unexpected event channel "
+ "upcall on port %d!\n", port);
}
}
+
return IRQ_HANDLED;
}
void force_evtchn_callback(void)
{
- evtchn_interrupt(0, NULL, NULL);
+ (void)HYPERVISOR_xen_version(0, NULL);
}
EXPORT_SYMBOL(force_evtchn_callback);
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-compat.c b/unmodified_drivers/linux-2.6/platform-pci/platform-compat.c
new file mode 100644
index 0000000000..5a0bb9bce8
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-compat.c
@@ -0,0 +1,139 @@
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <xen/platform-compat.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
+static int system_state = 1;
+EXPORT_SYMBOL(system_state);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
+size_t strcspn(const char *s, const char *reject)
+{
+ const char *p;
+ const char *r;
+ size_t count = 0;
+
+ for (p = s; *p != '\0'; ++p) {
+ for (r = reject; *r != '\0'; ++r) {
+ if (*p == *r)
+ return count;
+ }
+ ++count;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL(strcspn);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+/*
+ * Map a vmalloc()-space virtual address to the physical page frame number.
+ */
+unsigned long vmalloc_to_pfn(void * vmalloc_addr)
+{
+ return page_to_pfn(vmalloc_to_page(vmalloc_addr));
+}
+EXPORT_SYMBOL(vmalloc_to_pfn);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout)
+{
+ might_sleep();
+
+ spin_lock_irq(&x->wait.lock);
+ if (!x->done) {
+ DECLARE_WAITQUEUE(wait, current);
+
+ wait.flags |= WQ_FLAG_EXCLUSIVE;
+ __add_wait_queue_tail(&x->wait, &wait);
+ do {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&x->wait.lock);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irq(&x->wait.lock);
+ if (!timeout) {
+ __remove_wait_queue(&x->wait, &wait);
+ goto out;
+ }
+ } while (!x->done);
+ __remove_wait_queue(&x->wait, &wait);
+ }
+ x->done--;
+out:
+ spin_unlock_irq(&x->wait.lock);
+ return timeout;
+}
+EXPORT_SYMBOL(wait_for_completion_timeout);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
+/*
+ fake do_exit using complete_and_exit
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+asmlinkage NORET_TYPE void do_exit(long code)
+#else
+fastcall NORET_TYPE void do_exit(long code)
+#endif
+{
+ complete_and_exit(NULL, code);
+}
+EXPORT_SYMBOL_GPL(do_exit);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+signed long schedule_timeout_interruptible(signed long timeout)
+{
+ __set_current_state(TASK_INTERRUPTIBLE);
+ return schedule_timeout(timeout);
+}
+EXPORT_SYMBOL(schedule_timeout_interruptible);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+/**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ */
+void *kzalloc(size_t size, int flags)
+{
+ void *ret = kmalloc(size, flags);
+ if (ret)
+ memset(ret, 0, size);
+ return ret;
+}
+EXPORT_SYMBOL(kzalloc);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+/* Simplified asprintf. */
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ unsigned int len;
+ char *p, dummy[1];
+
+ va_start(ap, fmt);
+ len = vsnprintf(dummy, 0, fmt, ap);
+ va_end(ap);
+
+ p = kmalloc(len + 1, gfp);
+ if (!p)
+ return NULL;
+ va_start(ap, fmt);
+ vsprintf(p, fmt, ap);
+ va_end(ap);
+ return p;
+}
+EXPORT_SYMBOL(kasprintf);
+#endif
diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
index 2bb4dbd5b4..3a2453a25c 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
+++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c
@@ -33,11 +33,19 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/hypervisor.h>
+#include <asm/pgtable.h>
#include <xen/interface/memory.h>
#include <xen/features.h>
+#ifdef __ia64__
+#include <asm/xen/xencomm.h>
+#endif
#include "platform-pci.h"
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
#define DRV_NAME "xen-platform-pci"
#define DRV_VERSION "0.10"
#define DRV_RELDATE "03/03/2005"
@@ -59,6 +67,10 @@ static int __init init_xen_info(void)
struct xen_add_to_physmap xatp;
extern void *shared_info_area;
+#ifdef __ia64__
+ xencomm_init();
+#endif
+
setup_xen_features();
shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
@@ -167,10 +179,24 @@ static int get_hypercall_stubs(void)
#define get_hypercall_stubs() (0)
#endif
+static int get_callback_irq(struct pci_dev *pdev)
+{
+#ifdef __ia64__
+ int irq;
+ for (irq = 0; irq < 16; irq++) {
+ if (isa_irq_to_vector(irq) == pdev->irq)
+ return irq;
+ }
+ return 0;
+#else /* !__ia64__ */
+ return pdev->irq;
+#endif
+}
+
static int __devinit platform_pci_init(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i, ret;
+ int i, ret, callback_irq;
long ioaddr, iolen;
long mmio_addr, mmio_len;
@@ -184,7 +210,9 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
mmio_addr = pci_resource_start(pdev, 1);
mmio_len = pci_resource_len(pdev, 1);
- if (mmio_addr == 0 || ioaddr == 0) {
+ callback_irq = get_callback_irq(pdev);
+
+ if (mmio_addr == 0 || ioaddr == 0 || callback_irq == 0) {
printk(KERN_WARNING DRV_NAME ":no resources found\n");
return -ENOENT;
}
@@ -219,7 +247,7 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
goto out;
}
- if ((ret = set_callback_irq(pdev->irq)))
+ if ((ret = set_callback_irq(callback_irq)))
goto out;
out:
@@ -231,11 +259,13 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
return ret;
}
-#define XEN_PLATFORM_VENDOR_ID 0xfffd
-#define XEN_PLATFORM_DEVICE_ID 0x0101
+#define XEN_PLATFORM_VENDOR_ID 0x5853
+#define XEN_PLATFORM_DEVICE_ID 0x0001
static struct pci_device_id platform_pci_tbl[] __devinitdata = {
{XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ /* Continue to recognise the old ID for now */
+ {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};
diff --git a/unmodified_drivers/linux-2.6/platform-pci/xen_support.c b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c
index b1a903b1c7..423d2f2e24 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/xen_support.c
+++ b/unmodified_drivers/linux-2.6/platform-pci/xen_support.c
@@ -26,6 +26,10 @@
#include <asm/hypervisor.h>
#include "platform-pci.h"
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
void xen_machphys_update(unsigned long mfn, unsigned long pfn)
{
BUG();
diff --git a/unmodified_drivers/linux-2.6/util/Kbuild b/unmodified_drivers/linux-2.6/util/Kbuild
new file mode 100644
index 0000000000..35495d8194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/util/Kbuild
@@ -0,0 +1,3 @@
+include $(M)/overrides.mk
+
+obj-m := reboot.o
diff --git a/unmodified_drivers/linux-2.6/util/Makefile b/unmodified_drivers/linux-2.6/util/Makefile
new file mode 100644
index 0000000000..64e7acd194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/util/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(KERNELRELEASE),)
+include $(src)/Kbuild
+endif
diff --git a/unmodified_drivers/linux-2.6/xenbus/Makefile b/unmodified_drivers/linux-2.6/xenbus/Makefile
new file mode 100644
index 0000000000..64e7acd194
--- /dev/null
+++ b/unmodified_drivers/linux-2.6/xenbus/Makefile
@@ -0,0 +1,3 @@
+ifneq ($(KERNELRELEASE),)
+include $(src)/Kbuild
+endif
diff --git a/xen/COPYING b/xen/COPYING
index fb8fcc90fc..43f972ee5e 100644
--- a/xen/COPYING
+++ b/xen/COPYING
@@ -9,15 +9,17 @@ Foundation, but the instance of code that it refers to (the Xen
virtual machine monitor) is copyrighted by me and others who actually
wrote it.
-Further note that the guest-OS interfacing header files, which
-includes all files within the subdirectory include/public, are
-*not* covered by the GPL but by a much weaker license:
- include/public/COPYING
-
-Also note that the only valid version of the GPL as far as Xen is
-concerned is _this_ particular version of the license (i.e., *only*
-v2, not v2.2 or v3.x or whatever), unless explicitly otherwise
-stated.
+A few files are licensed under both GPL and a weaker BSD-style
+license. This includes all files within the subdirectory
+include/public, as described in include/public/COPYING. All such files
+include the non-GPL license text as a source-code comment. Although
+the license text refers generically to "the software", the non-GPL
+license applies *only* to those source files that explicitly include
+the non-GPL license text.
+
+Note that the only valid version of the GPL as far as Xen is concerned
+is _this_ particular version of the license (i.e., *only* v2, not v2.2
+or v3.x or whatever), unless explicitly otherwise stated.
-- Keir Fraser (on behalf of the Xen team)
diff --git a/xen/Makefile b/xen/Makefile
index 6f6d888e70..0c06e081fe 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -2,7 +2,7 @@
# All other places this is stored (eg. compile.h) should be autogenerated.
export XEN_VERSION = 3
export XEN_SUBVERSION = 0
-export XEN_EXTRAVERSION ?= -unstable
+export XEN_EXTRAVERSION ?= -unstable$(XEN_VENDORVERSION)
export XEN_FULLVERSION = $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION)
-include xen-version
@@ -93,14 +93,14 @@ include/xen/acm_policy.h:
include/xen/compile.h: include/xen/compile.h.in
@sed -e 's/@@date@@/$(shell LC_ALL=C date)/g' \
-e 's/@@time@@/$(shell LC_ALL=C date +%T)/g' \
- -e 's/@@whoami@@/$(shell whoami)/g' \
+ -e 's/@@whoami@@/$(USER)/g' \
-e 's/@@domain@@/$(shell ([ -x /bin/dnsdomainname ] && /bin/dnsdomainname) || ([ -x /bin/domainname ] && /bin/domainname || echo [unknown]))/g' \
-e 's/@@hostname@@/$(shell hostname)/g' \
- -e 's|@@compiler@@|$(shell $(CC) $(CFLAGS) -v 2>&1 | tail -n 1 | sed -e "s;|;/;")|g' \
+ -e 's!@@compiler@@!$(shell $(CC) $(CFLAGS) -v 2>&1 | grep -i "gcc.*version")!g' \
-e 's/@@version@@/$(XEN_VERSION)/g' \
-e 's/@@subversion@@/$(XEN_SUBVERSION)/g' \
-e 's/@@extraversion@@/$(XEN_EXTRAVERSION)/g' \
- -e 's!@@changeset@@!$(shell ((hg parents || head -n 7 ../ChangeLog || echo date: unavailable) | awk '{FS="changeset:[ ]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null)!g' \
+ -e 's!@@changeset@@!$(shell ((hg parents --template "{date|date} {rev}:{node|short}" >/dev/null && hg parents --template "{date|date} {rev}:{node|short}") || echo "unavailable") 2>/dev/null)!g' \
< include/xen/compile.h.in > $@.new
tools/figlet/figlet -d tools/figlet Xen $(XEN_FULLVERSION) >> $@.new
@mv -f $@.new $@
@@ -123,19 +123,29 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s
SUBDIRS = acm arch/$(TARGET_ARCH) common drivers
define all_sources
- ( find include/asm-$(TARGET_ARCH) -name SCCS -prune -o -name '*.h' -print; \
- find include -type d -name SCCS -prune -o \( -name "asm-*" -o \
- -name config \) -prune -o -name '*.h' -print; \
- find $(SUBDIRS) -name SCCS -prune -o -name '*.[chS]' -print )
+ ( find include/asm-$(TARGET_ARCH) -name '*.h' -print; \
+ find include -name 'asm-*' -prune -o -name '*.h' -print; \
+ find $(SUBDIRS) -name '*.[chS]' -print )
+endef
+
+define set_exuberant_flags
+ exuberant_flags=`$1 --version 2>/dev/null | grep -iq exuberant && \
+ echo "-I __initdata,__exitdata,__acquires,__releases \
+ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
+ --extra=+f --c-kinds=+px"`
endef
.PHONY: _TAGS
_TAGS:
- rm -f TAGS && $(all_sources) | xargs etags -a
+ rm -f TAGS; \
+ $(call set_exuberant_flags,etags); \
+ $(all_sources) | xargs etags $$exuberant_flags -a
.PHONY: _tags
_tags:
- rm -f TAGS && $(all_sources) | xargs ctags -a
+ rm -f tags; \
+ $(call set_exuberant_flags,ctags); \
+ $(all_sources) | xargs ctags $$exuberant_flags -a
.PHONY: _cscope
_cscope:
@@ -144,7 +154,7 @@ _cscope:
.PHONY: MAP
MAP:
- $(NM) $(TARGET) | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+ $(NM) -n $(TARGET) | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' > System.map
.PHONY: FORCE
FORCE:
diff --git a/xen/Rules.mk b/xen/Rules.mk
index e319ffb619..08c26aca44 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -24,9 +24,11 @@ endif
override COMPILE_SUBARCH := $(XEN_COMPILE_ARCH)
override TARGET_SUBARCH := $(XEN_TARGET_ARCH)
override COMPILE_ARCH := $(shell echo $(XEN_COMPILE_ARCH) | \
- sed -e 's/\(x86\|powerpc\).*/\1/')
+ sed -e 's/x86.*/x86/' \
+ -e 's/powerpc.*/powerpc/')
override TARGET_ARCH := $(shell echo $(XEN_TARGET_ARCH) | \
- sed -e 's/\(x86\|powerpc\).*/\1/')
+ sed -e 's/x86.*/x86/' \
+ -e 's/powerpc.*/powerpc/')
TARGET := $(BASEDIR)/xen
@@ -35,10 +37,6 @@ HDRS += $(wildcard $(BASEDIR)/include/public/*.h)
HDRS += $(wildcard $(BASEDIR)/include/asm-$(TARGET_ARCH)/*.h)
HDRS += $(wildcard $(BASEDIR)/include/asm-$(TARGET_ARCH)/$(TARGET_SUBARCH)/*.h)
-INSTALL := install
-INSTALL_DATA := $(INSTALL) -m0644
-INSTALL_DIR := $(INSTALL) -d -m0755
-
include $(BASEDIR)/arch/$(TARGET_ARCH)/Rules.mk
# Do not depend on auto-generated header files.
@@ -65,8 +63,16 @@ endif
AFLAGS-y += -D__ASSEMBLY__
ALL_OBJS := $(ALL_OBJS-y)
+
CFLAGS := $(strip $(CFLAGS) $(CFLAGS-y))
+
+# Most CFLAGS are safe for assembly files:
+# -std=gnu{89,99} gets confused by #-prefixed end-of-line comments
AFLAGS := $(strip $(AFLAGS) $(AFLAGS-y))
+AFLAGS += $(patsubst -std=gnu%,,$(CFLAGS))
+
+# LDFLAGS are only passed directly to $(LD)
+LDFLAGS := $(strip $(LDFLAGS) $(LDFLAGS_DIRECT))
include Makefile
@@ -104,10 +110,11 @@ _clean_%/: FORCE
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.S $(HDRS) Makefile
- $(CC) $(CFLAGS) $(AFLAGS) -c $< -o $@
+ $(CC) $(AFLAGS) -c $< -o $@
%.i: %.c $(HDRS) Makefile
$(CPP) $(CFLAGS) $< -o $@
+# -std=gnu{89,99} gets confused by # as an end-of-line comment marker
%.s: %.S $(HDRS) Makefile
- $(CPP) $(CFLAGS) $(AFLAGS) $< -o $@
+ $(CPP) $(AFLAGS) $< -o $@
diff --git a/xen/acm/acm_chinesewall_hooks.c b/xen/acm/acm_chinesewall_hooks.c
index 8071cec1be..98aea6e428 100644
--- a/xen/acm/acm_chinesewall_hooks.c
+++ b/xen/acm/acm_chinesewall_hooks.c
@@ -154,6 +154,8 @@ static int chwall_dump_policy(u8 * buf, u32 buf_size)
ret = ntohl(chwall_buf->chwall_conflict_aggregate_offset) +
sizeof(domaintype_t) * chwall_bin_pol.max_types;
+ ret = (ret + 7) & ~7;
+
if (buf_size < ret)
return -EINVAL;
diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c
index bafb177c3d..fdac3dd3e5 100644
--- a/xen/acm/acm_core.c
+++ b/xen/acm/acm_core.c
@@ -60,7 +60,7 @@ struct acm_operations *acm_secondary_ops = NULL;
/* acm global binary policy (points to 'local' primary and secondary policies */
struct acm_binary_policy acm_bin_pol;
/* acm binary policy lock */
-rwlock_t acm_bin_pol_rwlock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(acm_bin_pol_rwlock);
/* until we have endian support in Xen, we discover it at runtime */
u8 little_endian = 1;
@@ -100,9 +100,11 @@ acm_dump_policy_reference(u8 *buf, u32 buf_size)
struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf;
int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1;
+ ret = (ret + 7) & ~7;
if (buf_size < ret)
return -EINVAL;
+ memset(buf, 0, ret);
pr_buf->len = htonl(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */
strcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)),
acm_bin_pol.policy_reference_name);
@@ -187,85 +189,58 @@ acm_init_binary_policy(u32 policy_code)
return ret;
}
+int
+acm_is_policy(char *buf, unsigned long len)
+{
+ struct acm_policy_buffer *pol;
+
+ if (buf == NULL || len < sizeof(struct acm_policy_buffer))
+ return 0;
+
+ pol = (struct acm_policy_buffer *)buf;
+ return ntohl(pol->magic) == ACM_MAGIC;
+}
+
+
static int
-acm_setup(unsigned int *initrdidx,
- const multiboot_info_t *mbi,
- unsigned long initial_images_start)
+acm_setup(char *policy_start,
+ unsigned long policy_len)
{
- int i;
- module_t *mod = (module_t *)__va(mbi->mods_addr);
int rc = ACM_OK;
+ struct acm_policy_buffer *pol;
+
+ if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer))
+ return rc;
- if (mbi->mods_count > 1)
- *initrdidx = 1;
+ pol = (struct acm_policy_buffer *)policy_start;
+ if (ntohl(pol->magic) != ACM_MAGIC)
+ return rc;
- /*
- * Try all modules and see whichever could be the binary policy.
- * Adjust the initrdidx if module[1] is the binary policy.
- */
- for (i = mbi->mods_count-1; i >= 1; i--)
+ rc = do_acm_set_policy((void *)policy_start, (u32)policy_len);
+ if (rc == ACM_OK)
+ {
+ printkd("Policy len 0x%lx, start at %p.\n",policy_len,policy_start);
+ }
+ else
{
- struct acm_policy_buffer *pol;
- char *_policy_start;
- unsigned long _policy_len;
-#if defined(__i386__)
- _policy_start = (char *)(initial_images_start + (mod[i].mod_start-mod[0].mod_start));
-#elif defined(__x86_64__)
- _policy_start = __va(initial_images_start + (mod[i].mod_start-mod[0].mod_start));
-#else
-#error Architecture unsupported by sHype
-#endif
- _policy_len = mod[i].mod_end - mod[i].mod_start;
- if (_policy_len < sizeof(struct acm_policy_buffer))
- continue; /* not a policy */
-
- pol = (struct acm_policy_buffer *)_policy_start;
- if (ntohl(pol->magic) == ACM_MAGIC)
- {
- rc = do_acm_set_policy((void *)_policy_start,
- (u32)_policy_len);
- if (rc == ACM_OK)
- {
- printkd("Policy len 0x%lx, start at %p.\n",_policy_len,_policy_start);
- if (i == 1)
- {
- if (mbi->mods_count > 2)
- {
- *initrdidx = 2;
- }
- else {
- *initrdidx = 0;
- }
- }
- else
- {
- *initrdidx = 1;
- }
- break;
- }
- else
- {
- printk("Invalid policy. %d.th module line.\n", i+1);
- /* load default policy later */
- acm_active_security_policy = ACM_POLICY_UNDEFINED;
- }
- } /* end if a binary policy definition, i.e., (ntohl(pol->magic) == ACM_MAGIC ) */
+ printk("Invalid policy.\n");
+ /* load default policy later */
+ acm_active_security_policy = ACM_POLICY_UNDEFINED;
}
return rc;
}
int
-acm_init(unsigned int *initrdidx,
- const multiboot_info_t *mbi,
- unsigned long initial_images_start)
+acm_init(char *policy_start,
+ unsigned long policy_len)
{
int ret = ACM_OK;
acm_set_endian();
/* first try to load the boot policy (uses its own locks) */
- acm_setup(initrdidx, mbi, initial_images_start);
+ acm_setup(policy_start, policy_len);
if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
{
diff --git a/xen/acm/acm_simple_type_enforcement_hooks.c b/xen/acm/acm_simple_type_enforcement_hooks.c
index 0f8c8c3818..77e1062408 100644
--- a/xen/acm/acm_simple_type_enforcement_hooks.c
+++ b/xen/acm/acm_simple_type_enforcement_hooks.c
@@ -150,6 +150,8 @@ ste_dump_policy(u8 *buf, u32 buf_size) {
ret = ntohl(ste_buf->ste_ssid_offset) +
sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
+ ret = (ret + 7) & ~7;
+
if (buf_size < ret)
return -EINVAL;
diff --git a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile
index 1c95e6203d..7d297f0c22 100644
--- a/xen/arch/ia64/Makefile
+++ b/xen/arch/ia64/Makefile
@@ -4,22 +4,27 @@ subdir-y += linux
subdir-y += linux-xen
$(TARGET)-syms: linux-xen/head.o $(ALL_OBJS) xen.lds.s
+ $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o
$(LD) $(LDFLAGS) -T xen.lds.s -N \
- -Map map.out linux-xen/head.o $(ALL_OBJS) -o $@
+ -Map map.out linux-xen/head.o $(ALL_OBJS) \
+ $(BASEDIR)/common/symbols-dummy.o -o $@
$(NM) -n $@ | $(BASEDIR)/tools/symbols > $(BASEDIR)/xen-syms.S
$(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/xen-syms.o
$(LD) $(LDFLAGS) -T xen.lds.s -N \
- -Map map.out linux-xen/head.o $(ALL_OBJS) $(BASEDIR)/xen-syms.o -o $@
+ -Map map.out linux-xen/head.o $(ALL_OBJS) \
+ $(BASEDIR)/xen-syms.o -o $@
$(NM) -n $@ | $(BASEDIR)/tools/symbols >$(BASEDIR)/xen-syms.S
$(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/xen-syms.o
$(LD) $(LDFLAGS) -T xen.lds.s -N \
- -Map map.out linux-xen/head.o $(ALL_OBJS) $(BASEDIR)/xen-syms.o -o $@
+ -Map map.out linux-xen/head.o $(ALL_OBJS) \
+ $(BASEDIR)/xen-syms.o -o $@
rm -f $(BASEDIR)/xen-syms.S $(BASEDIR)/xen-syms.o
$(TARGET): $(TARGET)-syms
$(OBJCOPY) -R .note -R .comment -S $(TARGET)-syms $@
- $(NM) -n $(TARGET)-syms | grep -v '\( [aUw] \)\|\(__crc_\)\|\( \$[adt]\)'\
- > $(BASEDIR)/System.map
+ $(NM) -n $(TARGET)-syms | \
+ grep -v '\( [aUw] \)\|\(__crc_\)\|\( \$[adt]\)' \
+ > $(BASEDIR)/System.map
# Headers do not depend on auto-generated header, but object files do.
HDRS := $(subst $(BASEDIR)/include/asm-ia64/asm-xsi-offsets.h,,$(HDRS))
@@ -54,8 +59,6 @@ $(BASEDIR)/include/asm-ia64/.offsets.h.stamp:
[ -e $(BASEDIR)/include/asm-ia64/xen ] \
|| ln -sf $(BASEDIR)/include/asm-ia64/linux $(BASEDIR)/include/asm-ia64/xen
# Link to HVM files in Xen for ia64/vti
- [ -e $(BASEDIR)/include/asm-ia64/hvm ] \
- || mkdir $(BASEDIR)/include/asm-ia64/hvm
[ -e $(BASEDIR)/include/asm-ia64/hvm/support.h ] \
|| ln -sf ../../../include/asm-x86/hvm/support.h $(BASEDIR)/include/asm-ia64/hvm/support.h
[ -e $(BASEDIR)/include/asm-ia64/hvm/io.h ] \
@@ -78,4 +81,7 @@ clean::
rm -f asm-xsi-offsets.s $(BASEDIR)/include/asm-ia64/asm-xsi-offsets.h
rm -f $(BASEDIR)/System.map
rm -f vmx/hvm_*.c
- rm -rf $(BASEDIR)/include/asm-ia64/hvm
+ rm -f $(BASEDIR)/include/asm-ia64/hvm/support.h
+ rm -f $(BASEDIR)/include/asm-ia64/hvm/io.h
+ rm -f $(BASEDIR)/include/asm-ia64/hvm/vpic.h
+ rm -f $(BASEDIR)/include/asm-ia64/hvm/vioapic.h
diff --git a/xen/arch/ia64/Rules.mk b/xen/arch/ia64/Rules.mk
index 3c8663c90b..8f69704d7d 100644
--- a/xen/arch/ia64/Rules.mk
+++ b/xen/arch/ia64/Rules.mk
@@ -5,6 +5,11 @@ HAS_ACPI := y
HAS_VGA := y
VALIDATE_VT ?= n
no_warns ?= n
+xen_ia64_expose_p2m ?= y
+xen_ia64_pervcpu_vhpt ?= y
+xen_ia64_tlb_track ?= y
+xen_ia64_tlb_track_cnt ?= n
+xen_ia64_tlbflush_clock ?= y
ifneq ($(COMPILE_ARCH),$(TARGET_ARCH))
CROSS_COMPILE ?= /usr/local/sp_env/v2.2.5/i686/bin/ia64-unknown-linux-
@@ -13,8 +18,6 @@ endif
# Used only by linux/Makefile.
AFLAGS_KERNEL += -mconstant-gp -nostdinc $(CPPFLAGS)
-# Note: .S -> .o rule uses AFLAGS and CFLAGS.
-
CFLAGS += -nostdinc -fno-builtin -fno-common -fno-strict-aliasing
CFLAGS += -mconstant-gp
#CFLAGS += -O3 # -O3 over-inlines making debugging tough!
@@ -36,6 +39,21 @@ CFLAGS += -g
ifeq ($(VALIDATE_VT),y)
CFLAGS += -DVALIDATE_VT
endif
+ifeq ($(xen_ia64_expose_p2m),y)
+CFLAGS += -DCONFIG_XEN_IA64_EXPOSE_P2M
+endif
+ifeq ($(xen_ia64_pervcpu_vhpt),y)
+CFLAGS += -DCONFIG_XEN_IA64_PERVCPU_VHPT
+endif
+ifeq ($(xen_ia64_tlb_track),y)
+CFLAGS += -DCONFIG_XEN_IA64_TLB_TRACK
+endif
+ifeq ($(xen_ia64_tlb_track_cnt),y)
+CFLAGS += -DCONFIG_TLB_TRACK_CNT
+endif
+ifeq ($(xen_ia64_tlbflush_clock),y)
+CFLAGS += -DCONFIG_XEN_IA64_TLBFLUSH_CLOCK
+endif
ifeq ($(no_warns),y)
CFLAGS += -Wa,--fatal-warnings -Werror -Wno-uninitialized
endif
diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c
index 67b5725c56..356e8f9359 100644
--- a/xen/arch/ia64/asm-offsets.c
+++ b/xen/arch/ia64/asm-offsets.c
@@ -37,6 +37,9 @@ void foo(void)
DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET, offsetof (struct ia64_mca_cpu, init_stack));
BLANK();
+ DEFINE(VCPU_VTM_OFFSET_OFS, offsetof(struct vcpu, arch.arch_vmx.vtm.vtm_offset));
+ DEFINE(VCPU_VTM_LAST_ITC_OFS, offsetof(struct vcpu, arch.arch_vmx.vtm.last_itc));
+ DEFINE(VCPU_VRR0_OFS, offsetof(struct vcpu, arch.arch_vmx.vrr[0]));
#ifdef VTI_DEBUG
DEFINE(IVT_CUR_OFS, offsetof(struct vcpu, arch.arch_vmx.ivt_current));
DEFINE(IVT_DBG_OFS, offsetof(struct vcpu, arch.arch_vmx.ivt_debug));
@@ -139,6 +142,7 @@ void foo(void)
DEFINE(SWITCH_MPTA_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.mpta));
DEFINE(IA64_PT_REGS_R16_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f));
DEFINE(IA64_VCPU_FLAGS_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.flags));
+ DEFINE(IA64_VCPU_MODE_FLAGS_OFFSET,offsetof(struct vcpu, arch.mode_flags));
BLANK();
diff --git a/xen/arch/ia64/linux-xen/Makefile b/xen/arch/ia64/linux-xen/Makefile
index 29a6ff5efc..b7f8257579 100644
--- a/xen/arch/ia64/linux-xen/Makefile
+++ b/xen/arch/ia64/linux-xen/Makefile
@@ -16,3 +16,5 @@ obj-y += tlb.o
obj-y += unaligned.o
obj-y += unwind.o
obj-y += iosapic.o
+obj-y += numa.o
+obj-y += mm_numa.o
diff --git a/xen/arch/ia64/linux-xen/README.origin b/xen/arch/ia64/linux-xen/README.origin
index e0a13fe7cf..9a489bca74 100644
--- a/xen/arch/ia64/linux-xen/README.origin
+++ b/xen/arch/ia64/linux-xen/README.origin
@@ -15,6 +15,8 @@ mca.c -> linux/arch/ia64/kernel/mca.c
mca_asm.S -> linux/arch/ia64/kernel/mca_asm.S
minstate.h -> linux/arch/ia64/kernel/minstate.h
mm_contig.c -> linux/arch/ia64/mm/contig.c
+mm_numa.c -> linux/arch/ia64/mm/numa.c
+numa.c -> linux/arch/ia64/kernel/numa.c
pal.S -> linux/arch/ia64/kernel/pal.S
process-linux-xen.c -> linux/arch/ia64/kernel/process.c
sal.c -> linux/arch/ia64/kernel/sal.c
diff --git a/xen/arch/ia64/linux-xen/efi.c b/xen/arch/ia64/linux-xen/efi.c
index 93910059cf..09644fccc7 100644
--- a/xen/arch/ia64/linux-xen/efi.c
+++ b/xen/arch/ia64/linux-xen/efi.c
@@ -216,6 +216,7 @@ STUB_SET_VARIABLE(virt, id)
STUB_GET_NEXT_HIGH_MONO_COUNT(virt, id)
STUB_RESET_SYSTEM(virt, id)
+#ifndef XEN
void
efi_gettimeofday (struct timespec *ts)
{
@@ -228,6 +229,7 @@ efi_gettimeofday (struct timespec *ts)
ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
ts->tv_nsec = tm.nanosecond;
}
+#endif
static int
is_available_memory (efi_memory_desc_t *md)
diff --git a/xen/arch/ia64/linux-xen/entry.S b/xen/arch/ia64/linux-xen/entry.S
index d80be440a3..2c73fc5d2b 100644
--- a/xen/arch/ia64/linux-xen/entry.S
+++ b/xen/arch/ia64/linux-xen/entry.S
@@ -262,13 +262,15 @@ GLOBAL_ENTRY(ia64_switch_to)
#endif
rsm psr.ic // interrupts (psr.i) are already disabled here
movl r25=PAGE_KERNEL
+ movl r26 = IA64_GRANULE_SHIFT << 2
;;
srlz.d
or r23=r25,r20 // construct PA | page properties
- mov r25=IA64_GRANULE_SHIFT<<2
+ ptr.d in0, r26 // to purge dtr[IA64_TR_VHPT]
;;
- mov cr.itir=r25
+ mov cr.itir=r26
mov cr.ifa=in0 // VA of next task...
+ srlz.d
;;
mov r25=IA64_TR_CURRENT_STACK
#ifdef XEN
diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c
index 1e4a86061b..64151f3a4e 100644
--- a/xen/arch/ia64/linux-xen/mca.c
+++ b/xen/arch/ia64/linux-xen/mca.c
@@ -80,6 +80,7 @@
#ifdef XEN
#include <xen/symbols.h>
#include <xen/mm.h>
+#include <xen/console.h>
#endif
#if defined(IA64_MCA_DEBUG_INFO)
@@ -1219,12 +1220,6 @@ void
ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
{
pal_min_state_area_t *ms;
-#ifdef XEN
- int cpu = smp_processor_id();
-
- printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n",
- ia64_sal_to_os_handoff_state[cpu].proc_state_param);
-#endif
#ifndef XEN
oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */
@@ -1240,6 +1235,12 @@ ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
*/
ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61));
#else
+ int cpu = smp_processor_id();
+
+ console_start_sync();
+ printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n",
+ ia64_sal_to_os_handoff_state[cpu].proc_state_param);
+
/* Xen virtual address in region 7. */
ms = __va((pal_min_state_area_t *)(ia64_sal_to_os_handoff_state[cpu].pal_min_state));
#endif
diff --git a/xen/arch/ia64/linux-xen/minstate.h b/xen/arch/ia64/linux-xen/minstate.h
index b229b2d417..5c582e2a40 100644
--- a/xen/arch/ia64/linux-xen/minstate.h
+++ b/xen/arch/ia64/linux-xen/minstate.h
@@ -38,6 +38,8 @@
*/
#ifdef XEN
# define MINSTATE_START_SAVE_MIN_PHYS \
+(pKStk) tbit.z pKStk,pUStk=r29,IA64_PSR_VM_BIT; \
+ ;; \
(pKStk) movl r3=THIS_CPU(ia64_mca_data);; \
(pKStk) tpa r3 = r3;; \
(pKStk) ld8 r3 = [r3];; \
diff --git a/xen/arch/ia64/linux-xen/mm_contig.c b/xen/arch/ia64/linux-xen/mm_contig.c
index 3a0ca725bf..b3a0983648 100644
--- a/xen/arch/ia64/linux-xen/mm_contig.c
+++ b/xen/arch/ia64/linux-xen/mm_contig.c
@@ -308,4 +308,4 @@ paging_init (void)
#endif /* !CONFIG_VIRTUAL_MEM_MAP */
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
-#endif
+#endif /* XEN */
diff --git a/xen/arch/ia64/linux-xen/mm_numa.c b/xen/arch/ia64/linux-xen/mm_numa.c
new file mode 100644
index 0000000000..c1b919bf40
--- /dev/null
+++ b/xen/arch/ia64/linux-xen/mm_numa.c
@@ -0,0 +1,75 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * This file contains NUMA specific variables and functions which can
+ * be split away from DISCONTIGMEM and are used on NUMA machines with
+ * contiguous memory.
+ *
+ * 2002/08/07 Erich Focht <efocht@ess.nec.de>
+ */
+
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#ifndef XEN
+#include <linux/node.h>
+#endif
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/mmzone.h>
+#include <asm/numa.h>
+
+
+/*
+ * The following structures are usually initialized by ACPI or
+ * similar mechanisms and describe the NUMA characteristics of the machine.
+ */
+int num_node_memblks;
+struct node_memblk_s node_memblk[NR_NODE_MEMBLKS];
+struct node_cpuid_s node_cpuid[NR_CPUS];
+/*
+ * This is a matrix with "distances" between nodes, they should be
+ * proportional to the memory access latency ratios.
+ */
+u8 numa_slit[MAX_NUMNODES * MAX_NUMNODES];
+
+/* Identify which cnode a physical address resides on */
+int
+paddr_to_nid(unsigned long paddr)
+{
+ int i;
+
+ for (i = 0; i < num_node_memblks; i++)
+ if (paddr >= node_memblk[i].start_paddr &&
+ paddr < node_memblk[i].start_paddr + node_memblk[i].size)
+ break;
+
+ return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
+}
+
+#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_NUMA)
+/*
+ * Because of holes evaluate on section limits.
+ * If the section of memory exists, then return the node where the section
+ * resides. Otherwise return node 0 as the default. This is used by
+ * SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where
+ * the section resides.
+ */
+int early_pfn_to_nid(unsigned long pfn)
+{
+ int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec;
+
+ for (i = 0; i < num_node_memblks; i++) {
+ ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT;
+ esec = (node_memblk[i].start_paddr + node_memblk[i].size +
+ ((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT;
+ if (section >= ssec && section < esec)
+ return node_memblk[i].nid;
+ }
+
+ return 0;
+}
+#endif
diff --git a/xen/arch/ia64/linux-xen/numa.c b/xen/arch/ia64/linux-xen/numa.c
new file mode 100644
index 0000000000..35d6fd48bf
--- /dev/null
+++ b/xen/arch/ia64/linux-xen/numa.c
@@ -0,0 +1,67 @@
+/*
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ia64 kernel NUMA specific stuff
+ *
+ * Copyright (C) 2002 Erich Focht <efocht@ess.nec.de>
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ * Jesse Barnes <jbarnes@sgi.com>
+ */
+#ifdef XEN
+#include <xen/types.h>
+#endif
+#include <linux/config.h>
+#include <linux/topology.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+#ifdef XEN
+#include <xen/nodemask.h>
+#endif
+
+#ifdef XEN
+nodemask_t node_online_map = { { [0] = 1UL } };
+#endif
+
+u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_to_node_map);
+
+cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+
+/**
+ * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays
+ *
+ * Build cpu to node mapping and initialize the per node cpu masks using
+ * info from the node_cpuid array handed to us by ACPI.
+ */
+void __init build_cpu_to_node_map(void)
+{
+ int cpu, i, node;
+
+ for(node=0; node < MAX_NUMNODES; node++)
+ cpus_clear(node_to_cpu_mask[node]);
+
+ for(cpu = 0; cpu < NR_CPUS; ++cpu) {
+ node = -1;
+ for (i = 0; i < NR_CPUS; ++i)
+ if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
+ node = node_cpuid[i].nid;
+ break;
+ }
+ cpu_to_node_map[cpu] = (node >= 0) ? node : 0;
+ if (node >= 0)
+ cpu_set(cpu, node_to_cpu_mask[node]);
+ }
+}
diff --git a/xen/arch/ia64/linux-xen/sal.c b/xen/arch/ia64/linux-xen/sal.c
index ad81a29ad8..59cc613bbb 100644
--- a/xen/arch/ia64/linux-xen/sal.c
+++ b/xen/arch/ia64/linux-xen/sal.c
@@ -16,8 +16,10 @@
#ifdef XEN
#include <linux/smp.h>
+#include <asm/hw_irq.h>
#include <xen/lib.h>
#endif
+#include <asm/delay.h>
#include <asm/page.h>
#include <asm/sal.h>
#include <asm/pal.h>
@@ -218,6 +220,77 @@ chk_nointroute_opt(void)
static void __init sal_desc_ap_wakeup(void *p) { }
#endif
+/*
+ * HP rx5670 firmware polls for interrupts during SAL_CACHE_FLUSH by reading
+ * cr.ivr, but it never writes cr.eoi. This leaves any interrupt marked as
+ * "in-service" and masks other interrupts of equal or lower priority.
+ *
+ * HP internal defect reports: F1859, F2775, F3031.
+ */
+static int sal_cache_flush_drops_interrupts;
+
+static void __init
+check_sal_cache_flush (void)
+{
+ unsigned long flags, itv;
+ int cpu;
+ u64 vector;
+
+ cpu = get_cpu();
+ local_irq_save(flags);
+
+ /*
+ * Schedule a timer interrupt, wait until it's reported, and see if
+ * SAL_CACHE_FLUSH drops it.
+ */
+ itv = ia64_get_itv();
+ BUG_ON((itv & (1 << 16)) == 0);
+
+ ia64_set_itv(IA64_TIMER_VECTOR);
+ ia64_set_itm(ia64_get_itc() + 1000);
+
+ while (!ia64_get_irr(IA64_TIMER_VECTOR))
+ cpu_relax();
+
+ ia64_sal_cache_flush(3);
+
+ if (ia64_get_irr(IA64_TIMER_VECTOR)) {
+ vector = ia64_get_ivr();
+ ia64_eoi();
+ } else {
+ sal_cache_flush_drops_interrupts = 1;
+ printk(KERN_ERR "SAL: SAL_CACHE_FLUSH drops interrupts; "
+ "PAL_CACHE_FLUSH will be used instead\n");
+ ia64_eoi();
+ }
+
+ ia64_set_itv(itv);
+ local_irq_restore(flags);
+ put_cpu();
+}
+
+s64
+ia64_sal_cache_flush (u64 cache_type)
+{
+ struct ia64_sal_retval isrv;
+
+ if (sal_cache_flush_drops_interrupts) {
+ unsigned long flags;
+ u64 progress;
+ s64 rc;
+
+ progress = 0;
+ local_irq_save(flags);
+ rc = ia64_pal_cache_flush(cache_type,
+ PAL_CACHE_FLUSH_INVALIDATE, &progress, NULL);
+ local_irq_restore(flags);
+ return rc;
+ }
+
+ SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0);
+ return isrv.status;
+}
+
void __init
ia64_sal_init (struct ia64_sal_systab *systab)
{
@@ -271,6 +344,8 @@ ia64_sal_init (struct ia64_sal_systab *systab)
}
p += SAL_DESC_SIZE(*p);
}
+
+ check_sal_cache_flush();
}
int
diff --git a/xen/arch/ia64/linux-xen/setup.c b/xen/arch/ia64/linux-xen/setup.c
index 6d03910fc7..e725b1c960 100644
--- a/xen/arch/ia64/linux-xen/setup.c
+++ b/xen/arch/ia64/linux-xen/setup.c
@@ -803,7 +803,7 @@ cpu_init (void)
cpu_data = per_cpu_init();
#ifdef XEN
- printf ("cpu_init: current=%p\n", current);
+ printk("cpu_init: current=%p\n", current);
#endif
/*
diff --git a/xen/arch/ia64/linux-xen/smpboot.c b/xen/arch/ia64/linux-xen/smpboot.c
index ac96fb8cc9..4450ce9260 100644
--- a/xen/arch/ia64/linux-xen/smpboot.c
+++ b/xen/arch/ia64/linux-xen/smpboot.c
@@ -650,7 +650,8 @@ clear_cpu_sibling_map(int cpu)
for_each_cpu_mask(i, cpu_core_map[cpu])
cpu_clear(cpu, cpu_core_map[i]);
- cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE;
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
}
static void
diff --git a/xen/arch/ia64/linux-xen/tlb.c b/xen/arch/ia64/linux-xen/tlb.c
index 9859923b77..2a6bffffb3 100644
--- a/xen/arch/ia64/linux-xen/tlb.c
+++ b/xen/arch/ia64/linux-xen/tlb.c
@@ -111,7 +111,10 @@ void
local_flush_tlb_all (void)
{
unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
-
+#ifdef XEN
+ /* increment flush clock before mTLB flush */
+ u32 flush_time = tlbflush_clock_inc_and_return();
+#endif
addr = local_cpu_data->ptce_base;
count0 = local_cpu_data->ptce_count[0];
count1 = local_cpu_data->ptce_count[1];
@@ -128,6 +131,10 @@ local_flush_tlb_all (void)
}
local_irq_restore(flags);
ia64_srlz_i(); /* srlz.i implies srlz.d */
+#ifdef XEN
+ /* update after mTLB flush. */
+ tlbflush_update_time(&__get_cpu_var(tlbflush_time), flush_time);
+#endif
}
EXPORT_SYMBOL(local_flush_tlb_all);
diff --git a/xen/arch/ia64/linux-xen/unaligned.c b/xen/arch/ia64/linux-xen/unaligned.c
index 9ef5d42470..86ecbd9374 100644
--- a/xen/arch/ia64/linux-xen/unaligned.c
+++ b/xen/arch/ia64/linux-xen/unaligned.c
@@ -304,7 +304,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned
unsigned long *bsp, *bspstore, *addr, *rnat_addr;
unsigned long *kbs = (void *) current + IA64_RBS_OFFSET;
unsigned long nat_mask;
- unsigned long old_rsc,new_rsc;
+ unsigned long old_rsc, new_rsc, psr;
unsigned long rnat;
long sof = (regs->cr_ifs) & 0x7f;
long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
@@ -321,16 +321,17 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned
ridx = rotate_reg(sor, rrb_gr, ridx);
old_rsc=ia64_get_rsc();
- new_rsc=old_rsc&(~0x3);
+ /* put RSC to lazy mode, and set loadrs 0 */
+ new_rsc = old_rsc & (~0x3fff0003);
ia64_set_rsc(new_rsc);
+ bsp = kbs + (regs->loadrs >> 19); /* 16 + 3 */
- bspstore = (unsigned long*)ia64_get_bspstore();
- bsp =kbs + (regs->loadrs >> 19);//16+3
-
- addr = ia64_rse_skip_regs(bsp, -sof + ridx);
+ addr = ia64_rse_skip_regs(bsp, -sof + ridx);
nat_mask = 1UL << ia64_rse_slot_num(addr);
- rnat_addr = ia64_rse_rnat_addr(addr);
-
+ rnat_addr = ia64_rse_rnat_addr(addr);
+
+ local_irq_save(psr);
+ bspstore = (unsigned long*)ia64_get_bspstore();
if(addr >= bspstore){
ia64_flushrs ();
@@ -358,6 +359,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned
ia64_set_bspstore (bspstore);
ia64_set_rnat(rnat);
}
+ local_irq_restore(psr);
ia64_set_rsc(old_rsc);
}
diff --git a/xen/arch/ia64/tools/p2m_expose/Makefile b/xen/arch/ia64/tools/p2m_expose/Makefile
new file mode 100644
index 0000000000..d346326d05
--- /dev/null
+++ b/xen/arch/ia64/tools/p2m_expose/Makefile
@@ -0,0 +1,28 @@
+ifneq ($(KERNELRELEASE),)
+obj-m += expose_p2m.o
+else
+PWD := $(shell pwd)
+TOPDIR ?= $(abspath $(PWD)/../../../../..)
+KDIR ?= $(TOPDIR)/linux-$(shell awk '/^LINUX_VER\>/{print $$3}' $(TOPDIR)/buildconfigs/mk.linux-2.6-xen)-xen
+#CROSS_COMPILE ?= ia64-unknown-linux-
+#ARCH ?= ia64
+
+ifneq ($(O),)
+OPT_O := O=$(realpath $(O))
+endif
+
+ifneq ($(V),)
+OPT_V := V=$(V)
+endif
+
+ifneq ($(ARCH),)
+OPT_ARCH := ARCH=$(ARCH)
+endif
+
+ifneq ($(CROSS_COMPILE),)
+OPT_CORSS_COMPILE := CROSS_COMPILE=$(CROSS_COMPILE)
+endif
+
+default:
+ $(MAKE) -C $(KDIR) $(OPT_O) $(OPT_V) $(OPT_CORSS_COMPILE) $(OPT_ARCH) M=$(PWD)
+endif
diff --git a/xen/arch/ia64/tools/p2m_expose/README.p2m_expose b/xen/arch/ia64/tools/p2m_expose/README.p2m_expose
new file mode 100644
index 0000000000..3b51e11305
--- /dev/null
+++ b/xen/arch/ia64/tools/p2m_expose/README.p2m_expose
@@ -0,0 +1,12 @@
+This directory contains Linux kernel module for p2m exposure test/benchmark.
+
+1. build kernel module
+ - At fist build, linux-xen as usual
+ - then type just 'make' in this directory, then you'll have expose_p2m.ko.
+ See Makefile for details.
+
+2. test, benchmark.
+ - type 'insmod expose_p2m.ko' on the system.
+ Then the result is printed out to your console.
+ insmod fails with EINVAL so that you don't have to execute rmmod.
+
diff --git a/xen/arch/ia64/tools/p2m_expose/expose_p2m.c b/xen/arch/ia64/tools/p2m_expose/expose_p2m.c
new file mode 100644
index 0000000000..26e0b5188e
--- /dev/null
+++ b/xen/arch/ia64/tools/p2m_expose/expose_p2m.c
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * arch/ia64/xen/expose_p2m.c
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hypercall.h>
+#include <asm/hypervisor.h>
+
+#define printd(fmt, ...) printk("%s:%d " fmt, __func__, __LINE__, \
+ ##__VA_ARGS__)
+
+// copied from arch/ia64/mm/tlb.c. it isn't exported.
+void
+local_flush_tlb_all (void)
+{
+ unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
+
+ addr = local_cpu_data->ptce_base;
+ count0 = local_cpu_data->ptce_count[0];
+ count1 = local_cpu_data->ptce_count[1];
+ stride0 = local_cpu_data->ptce_stride[0];
+ stride1 = local_cpu_data->ptce_stride[1];
+
+ local_irq_save(flags);
+ for (i = 0; i < count0; ++i) {
+ for (j = 0; j < count1; ++j) {
+ ia64_ptce(addr);
+ addr += stride1;
+ }
+ addr += stride0;
+ }
+ local_irq_restore(flags);
+ ia64_srlz_i(); /* srlz.i implies srlz.d */
+}
+
+static void
+do_p2m(unsigned long (*conv)(unsigned long),
+ const char* msg, const char* prefix,
+ unsigned long start_gpfn, unsigned end_gpfn, unsigned long stride)
+{
+ struct timeval before_tv;
+ struct timeval after_tv;
+ unsigned long gpfn;
+ unsigned long mfn;
+ unsigned long count;
+ nsec_t nsec;
+
+ count = 0;
+ do_gettimeofday(&before_tv);
+ for (gpfn = start_gpfn; gpfn < end_gpfn; gpfn += stride) {
+ mfn = (*conv)(gpfn);
+ count++;
+ }
+ do_gettimeofday(&after_tv);
+ nsec = timeval_to_ns(&after_tv) - timeval_to_ns(&before_tv);
+ printk("%s stride %4ld %s: %9ld / %6ld = %5ld nsec\n",
+ msg, stride, prefix,
+ nsec, count, nsec/count);
+}
+
+
+static void
+do_with_hypercall(const char* msg,
+ unsigned long start_gpfn, unsigned long end_gpfn,
+ unsigned long stride)
+{
+ do_p2m(&HYPERVISOR_phystomach, msg, "hypercall",
+ start_gpfn, end_gpfn, stride);
+}
+
+static void
+do_with_table(const char* msg,
+ unsigned long start_gpfn, unsigned long end_gpfn,
+ unsigned long stride)
+{
+ do_p2m(&p2m_phystomach, msg, "p2m table",
+ start_gpfn, end_gpfn, stride);
+}
+
+static int __init
+expose_p2m_init(void)
+{
+ unsigned long gpfn;
+ unsigned long mfn;
+ unsigned long p2m_mfn;
+
+ int error_count = 0;
+
+ const int strides[] = {
+ PTRS_PER_PTE, PTRS_PER_PTE/2, PTRS_PER_PTE/3, PTRS_PER_PTE/4,
+ L1_CACHE_BYTES/sizeof(pte_t), 1
+ };
+ int i;
+
+
+#if 0
+ printd("about to call p2m_expose_init()\n");
+ if (p2m_expose_init() < 0) {
+ printd("p2m_expose_init() failed\n");
+ return -EINVAL;
+ }
+ printd("p2m_expose_init() success\n");
+#else
+ if (!p2m_initialized) {
+ printd("p2m exposure isn't initialized\n");
+ return -EINVAL;
+ }
+#endif
+
+ printd("p2m expose test begins\n");
+ for (gpfn = p2m_min_low_pfn; gpfn < p2m_max_low_pfn; gpfn++) {
+ mfn = HYPERVISOR_phystomach(gpfn);
+ p2m_mfn = p2m_phystomach(gpfn);
+ if (mfn != p2m_mfn) {
+ printd("gpfn 0x%016lx "
+ "mfn 0x%016lx p2m_mfn 0x%016lx\n",
+ gpfn, mfn, p2m_mfn);
+ printd("mpaddr 0x%016lx "
+ "maddr 0x%016lx p2m_maddr 0x%016lx\n",
+ gpfn << PAGE_SHIFT,
+ mfn << PAGE_SHIFT, p2m_mfn << PAGE_SHIFT);
+
+ error_count++;
+ if (error_count > 16) {
+ printk("too many errors\n");
+ return -EINVAL;
+ }
+ }
+ }
+ printd("p2m expose test done!\n");
+
+ printk("type "
+ "stride "
+ "type : "
+ " nsec / count = "
+ "nsec per conv\n");
+ for (i = 0; i < sizeof(strides)/sizeof(strides[0]); i++) {
+ int stride = strides[i];
+ local_flush_tlb_all();
+ do_with_hypercall("cold tlb",
+ p2m_min_low_pfn, p2m_max_low_pfn, stride);
+ do_with_hypercall("warm tlb",
+ p2m_min_low_pfn, p2m_max_low_pfn, stride);
+
+ local_flush_tlb_all();
+ do_with_table("cold tlb",
+ p2m_min_low_pfn, p2m_max_low_pfn, stride);
+ do_with_table("warm tlb",
+ p2m_min_low_pfn, p2m_max_low_pfn, stride);
+ }
+
+ return -EINVAL;
+}
+
+static void __exit
+expose_p2m_cleanup(void)
+{
+}
+
+module_init(expose_p2m_init);
+module_exit(expose_p2m_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Isaku Yamahata <yamahata@valinux.co.jp>");
diff --git a/xen/arch/ia64/vmx/Makefile b/xen/arch/ia64/vmx/Makefile
index 9e90d955c9..5be2b4321c 100644
--- a/xen/arch/ia64/vmx/Makefile
+++ b/xen/arch/ia64/vmx/Makefile
@@ -17,3 +17,4 @@ obj-y += vmx_vcpu.o
obj-y += vmx_virt.o
obj-y += vmx_vsa.o
obj-y += vtlb.o
+obj-y += optvfault.o
diff --git a/xen/arch/ia64/vmx/mm.c b/xen/arch/ia64/vmx/mm.c
deleted file mode 100644
index 814df3dd8a..0000000000
--- a/xen/arch/ia64/vmx/mm.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/******************************************************************************
- * arch/ia64/mm.c
- *
- * Copyright (c) 2002-2005 K A Fraser
- * Copyright (c) 2004 Christian Limpach
- * Copyright (c) 2005, Intel Corporation.
- * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
- *
- * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * A description of the x86 page table API:
- *
- * Domains trap to do_mmu_update with a list of update requests.
- * This is a list of (ptr, val) pairs, where the requested operation
- * is *ptr = val.
- *
- * Reference counting of pages:
- * ----------------------------
- * Each page has two refcounts: tot_count and type_count.
- *
- * TOT_COUNT is the obvious reference count. It counts all uses of a
- * physical page frame by a domain, including uses as a page directory,
- * a page table, or simple mappings via a PTE. This count prevents a
- * domain from releasing a frame back to the free pool when it still holds
- * a reference to it.
- *
- * TYPE_COUNT is more subtle. A frame can be put to one of three
- * mutually-exclusive uses: it might be used as a page directory, or a
- * page table, or it may be mapped writable by the domain [of course, a
- * frame may not be used in any of these three ways!].
- * So, type_count is a count of the number of times a frame is being
- * referred to in its current incarnation. Therefore, a page can only
- * change its type when its type count is zero.
- *
- * Pinning the page type:
- * ----------------------
- * The type of a page can be pinned/unpinned with the commands
- * MMUEXT_[UN]PIN_L?_TABLE. Each page can be pinned exactly once (that is,
- * pinning is not reference counted, so it can't be nested).
- * This is useful to prevent a page's type count falling to zero, at which
- * point safety checks would need to be carried out next time the count
- * is increased again.
- *
- * A further note on writable page mappings:
- * -----------------------------------------
- * For simplicity, the count of writable mappings for a page may not
- * correspond to reality. The 'writable count' is incremented for every
- * PTE which maps the page with the _PAGE_RW flag set. However, for
- * write access to be possible the page directory entry must also have
- * its _PAGE_RW bit set. We do not check this as it complicates the
- * reference counting considerably [consider the case of multiple
- * directory entries referencing a single page table, some with the RW
- * bit set, others not -- it starts getting a bit messy].
- * In normal use, this simplification shouldn't be a problem.
- * However, the logic can be added if required.
- *
- * One more note on read-only page mappings:
- * -----------------------------------------
- * We want domains to be able to map pages for read-only access. The
- * main reason is that page tables and directories should be readable
- * by a domain, but it would not be safe for them to be writable.
- * However, domains have free access to rings 1 & 2 of the Intel
- * privilege model. In terms of page protection, these are considered
- * to be part of 'supervisor mode'. The WP bit in CR0 controls whether
- * read-only restrictions are respected in supervisor mode -- if the
- * bit is clear then any mapped page is writable.
- *
- * We get round this by always setting the WP bit and disallowing
- * updates to it. This is very unlikely to cause a problem for guest
- * OS's, which will generally use the WP bit to simplify copy-on-write
- * implementation (in that case, OS wants a fault when it writes to
- * an application-supplied buffer).
- */
-
-#include <xen/config.h>
-//#include <public/xen.h>
-#include <xen/init.h>
-#include <xen/lib.h>
-#include <xen/mm.h>
-#include <xen/errno.h>
-#include <asm/vmx_vcpu.h>
-#include <asm/vmmu.h>
-#include <asm/regionreg.h>
-#include <asm/vmx_mm_def.h>
-/*
- uregs->ptr is virtual address
- uregs->val is pte value
- */
-int vmx_do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom)
-{
- int i,cmd;
- u64 mfn, gpfn;
- VCPU *vcpu;
- mmu_update_t req;
- /* ia64_rr rr; */
- thash_cb_t *hcb;
- /* thash_data_t entry={0},*ovl; */
- vcpu = current;
- /* search_section_t sections; */
- hcb = vmx_vcpu_get_vtlb(vcpu);
- for ( i = 0; i < count; i++ )
- {
- copy_from_user(&req, ureqs, sizeof(req));
- cmd = req.ptr&3;
- req.ptr &= ~3;
-/*
- if(cmd ==MMU_NORMAL_PT_UPDATE){
- entry.page_flags = req.val;
- entry.locked = 1;
- entry.tc = 1;
- entry.cl = DSIDE_TLB;
- rr = vmx_vcpu_rr(vcpu, req.ptr);
- entry.ps = rr.ps;
- entry.key = rr.rid;
- entry.rid = rr.rid;
- entry.vadr = PAGEALIGN(req.ptr,entry.ps);
- sections.tr = 1;
- sections.tc = 0;
- ovl = thash_find_overlap(hcb, &entry, sections);
- if (ovl) {
- // generate MCA.
- panic("Tlb conflict!!");
- return -1;
- }
- thash_purge_and_insert(hcb, &entry, req.ptr);
- }else
- */
- if(cmd == MMU_MACHPHYS_UPDATE){
- mfn = req.ptr >>PAGE_SHIFT;
- gpfn = req.val;
- set_machinetophys(mfn,gpfn);
- }else{
- printf("Unkown command of mmu_update:ptr: %lx,val: %lx \n",req.ptr,req.val);
- while(1);
- }
- ureqs ++;
- }
- return 0;
-}
diff --git a/xen/arch/ia64/vmx/mmio.c b/xen/arch/ia64/vmx/mmio.c
index 95e7ec0351..1d6347ef9e 100644
--- a/xen/arch/ia64/vmx/mmio.c
+++ b/xen/arch/ia64/vmx/mmio.c
@@ -52,6 +52,70 @@ struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base)
#define PIB_OFST_INTA 0x1E0000
#define PIB_OFST_XTP 0x1E0008
+#define HVM_BUFFERED_IO_RANGE_NR 1
+
+struct hvm_buffered_io_range {
+ unsigned long start_addr;
+ unsigned long length;
+};
+
+static struct hvm_buffered_io_range buffered_stdvga_range = {0xA0000, 0x20000};
+static struct hvm_buffered_io_range
+*hvm_buffered_io_ranges[HVM_BUFFERED_IO_RANGE_NR] =
+{
+ &buffered_stdvga_range
+};
+
+int hvm_buffered_io_intercept(ioreq_t *p)
+{
+ struct vcpu *v = current;
+ spinlock_t *buffered_io_lock;
+ buffered_iopage_t *buffered_iopage =
+ (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va);
+ unsigned long tmp_write_pointer = 0;
+ int i;
+
+ /* ignore READ ioreq_t! */
+ if ( p->dir == IOREQ_READ )
+ return 0;
+
+ for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) {
+ if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr &&
+ p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr +
+ hvm_buffered_io_ranges[i]->length )
+ break;
+ }
+
+ if ( i == HVM_BUFFERED_IO_RANGE_NR )
+ return 0;
+
+ buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock;
+ spin_lock(buffered_io_lock);
+
+ if ( buffered_iopage->write_pointer - buffered_iopage->read_pointer ==
+ (unsigned long)IOREQ_BUFFER_SLOT_NUM ) {
+ /* the queue is full.
+ * send the iopacket through the normal path.
+ * NOTE: The arithimetic operation could handle the situation for
+ * write_pointer overflow.
+ */
+ spin_unlock(buffered_io_lock);
+ return 0;
+ }
+
+ tmp_write_pointer = buffered_iopage->write_pointer % IOREQ_BUFFER_SLOT_NUM;
+
+ memcpy(&buffered_iopage->ioreq[tmp_write_pointer], p, sizeof(ioreq_t));
+
+ /*make the ioreq_t visible before write_pointer*/
+ wmb();
+ buffered_iopage->write_pointer++;
+
+ spin_unlock(buffered_io_lock);
+
+ return 1;
+}
+
static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value);
static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma)
@@ -80,7 +144,7 @@ static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma)
}
}
else { // upper half
- printf("IPI-UHF write %lx\n",pib_off);
+ printk("IPI-UHF write %lx\n",pib_off);
panic_domain(NULL,"Not support yet for SM-VP\n");
}
break;
@@ -114,7 +178,7 @@ static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma)
}
else {
#ifdef IPI_DEBUG
- printf("IPI-LHF read %lx\n",pib_off);
+ printk("IPI-LHF read %lx\n",pib_off);
#endif
*(uint64_t *)dest = 0; // TODO for SM-VP
}
@@ -125,7 +189,7 @@ static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma)
}
else {
#ifdef IPI_DEBUG
- printf("IPI-UHF read %lx\n",pib_off);
+ printk("IPI-UHF read %lx\n",pib_off);
#endif
*(uint8_t *)dest = 0; // TODO for SM-VP
}
@@ -150,16 +214,20 @@ static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
p->count = 1;
p->dir = dir;
if(dir==IOREQ_WRITE) //write;
- p->u.data = *val;
- p->pdata_valid = 0;
+ p->data = *val;
+ p->data_is_ptr = 0;
p->type = 1;
p->df = 0;
p->io_count++;
-
+ if(hvm_buffered_io_intercept(p)){
+ p->state = STATE_IORESP_READY;
+ vmx_io_assist(v);
+ return ;
+ }else
vmx_send_assist_req(v);
if(dir==IOREQ_READ){ //read
- *val=p->u.data;
+ *val=p->data;
}
return;
}
@@ -181,8 +249,8 @@ static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
p->count = 1;
p->dir = dir;
if(dir==IOREQ_WRITE) //write;
- p->u.data = *val;
- p->pdata_valid = 0;
+ p->data = *val;
+ p->data_is_ptr = 0;
p->type = 0;
p->df = 0;
@@ -190,15 +258,15 @@ static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir)
vmx_send_assist_req(v);
if(dir==IOREQ_READ){ //read
- *val=p->u.data;
+ *val=p->data;
}
#ifdef DEBUG_PCI
if(dir==IOREQ_WRITE)
if(p->addr == 0xcf8UL)
- printk("Write 0xcf8, with val [0x%lx]\n", p->u.data);
+ printk("Write 0xcf8, with val [0x%lx]\n", p->data);
else
if(p->addr == 0xcfcUL)
- printk("Read 0xcfc, with val [0x%lx]\n", p->u.data);
+ printk("Read 0xcfc, with val [0x%lx]\n", p->data);
#endif //DEBUG_PCI
return;
}
@@ -312,6 +380,24 @@ memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s)
}
*/
+/*
+ * To inject INIT to guest, we must set the PAL_INIT entry
+ * and set psr to switch to physical mode
+ */
+#define PAL_INIT_ENTRY 0x80000000ffffffa0
+#define PSR_SET_BITS (IA64_PSR_DT | IA64_PSR_IT | IA64_PSR_RT | \
+ IA64_PSR_IC | IA64_PSR_RI)
+
+static void vmx_inject_guest_pal_init(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ uint64_t psr = vmx_vcpu_get_psr(vcpu);
+
+ regs->cr_iip = PAL_INIT_ENTRY;
+
+ psr = psr & (~PSR_SET_BITS);
+ vmx_vcpu_set_psr(vcpu,psr);
+}
/*
* Deliver IPI message. (Only U-VP is supported now)
@@ -321,7 +407,7 @@ memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s)
static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector)
{
#ifdef IPI_DEBUG
- printf ("deliver_ipi %lx %lx\n",dm,vector);
+ printk ("deliver_ipi %lx %lx\n",dm,vector);
#endif
switch ( dm ) {
case 0: // INT
@@ -335,8 +421,7 @@ static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector)
vmx_vcpu_pend_interrupt (vcpu, 2);
break;
case 5: // INIT
- // TODO -- inject guest INIT
- panic_domain (NULL, "Inject guest INIT!\n");
+ vmx_inject_guest_pal_init(vcpu);
break;
case 7: // ExtINT
vmx_vcpu_pend_interrupt (vcpu, 0);
@@ -387,7 +472,7 @@ static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value)
memset (&c, 0, sizeof (c));
if (arch_set_info_guest (targ, &c) != 0) {
- printf ("arch_boot_vcpu: failure\n");
+ printk ("arch_boot_vcpu: failure\n");
return;
}
/* First or next rendez-vous: set registers. */
@@ -397,11 +482,11 @@ static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value)
if (test_and_clear_bit(_VCPUF_down,&targ->vcpu_flags)) {
vcpu_wake(targ);
- printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
+ printk ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
targ->vcpu_id, targ_regs->cr_iip);
}
else
- printf ("arch_boot_vcpu: huu, already awaken!");
+ printk ("arch_boot_vcpu: huu, already awaken!");
}
else {
int running = test_bit(_VCPUF_running,&targ->vcpu_flags);
@@ -428,7 +513,7 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
IA64_BUNDLE bundle;
int slot, dir=0, inst_type;
size_t size;
- u64 data, value,post_update, slot1a, slot1b, temp;
+ u64 data, post_update, slot1a, slot1b, temp;
INST64 inst;
regs=vcpu_regs(vcpu);
if (IA64_RETRY == __vmx_get_domain_bundle(regs->cr_iip, &bundle)) {
@@ -454,7 +539,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
vcpu_get_gr_nat(vcpu,inst.M4.r2,&data);
}else if((inst.M1.x6>>2)<0xb){ // read
dir=IOREQ_READ;
- vcpu_get_gr_nat(vcpu,inst.M1.r1,&value);
}
}
// Integer Load + Reg update
@@ -462,7 +546,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
inst_type = SL_INTEGER;
dir = IOREQ_READ; //write
size = (inst.M2.x6&0x3);
- vcpu_get_gr_nat(vcpu,inst.M2.r1,&value);
vcpu_get_gr_nat(vcpu,inst.M2.r3,&temp);
vcpu_get_gr_nat(vcpu,inst.M2.r2,&post_update);
temp += post_update;
@@ -485,7 +568,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
}else if((inst.M3.x6>>2)<0xb){ // read
dir=IOREQ_READ;
- vcpu_get_gr_nat(vcpu,inst.M3.r1,&value);
vcpu_get_gr_nat(vcpu,inst.M3.r3,&temp);
post_update = (inst.M3.i<<7)+inst.M3.imm7;
if(inst.M3.s)
@@ -597,13 +679,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma)
mmio_access(vcpu, padr, &data, size, ma, dir);
}else{
mmio_access(vcpu, padr, &data, size, ma, dir);
- if(size==1)
- data = (value & 0xffffffffffffff00U) | (data & 0xffU);
- else if(size==2)
- data = (value & 0xffffffffffff0000U) | (data & 0xffffU);
- else if(size==4)
- data = (value & 0xffffffff00000000U) | (data & 0xffffffffU);
-
if(inst_type==SL_INTEGER){ //gp
vcpu_set_gr(vcpu,inst.M1.r1,data,0);
}else{
diff --git a/xen/arch/ia64/vmx/optvfault.S b/xen/arch/ia64/vmx/optvfault.S
new file mode 100644
index 0000000000..4a268f9a5d
--- /dev/null
+++ b/xen/arch/ia64/vmx/optvfault.S
@@ -0,0 +1,841 @@
+/*
+ * arch/ia64/vmx/optvfault.S
+ * optimize virtualization fault handler
+ *
+ * Copyright (C) 2006 Intel Co
+ * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com>
+ */
+
+#include <linux/config.h>
+#include <asm/asmmacro.h>
+#include <asm/kregs.h>
+#include <asm/offsets.h>
+#include <asm/percpu.h>
+#include <asm/processor.h>
+#include <asm/vmx_vpd.h>
+#include <asm/vmx_pal_vsa.h>
+#include <asm/asm-offsets.h>
+
+#define ACCE_MOV_FROM_AR
+#define ACCE_MOV_FROM_RR
+#define ACCE_MOV_TO_RR
+#define ACCE_RSM
+#define ACCE_SSM
+#define ACCE_MOV_TO_PSR
+
+//mov r1=ar3
+GLOBAL_ENTRY(vmx_asm_mov_from_ar)
+#ifndef ACCE_MOV_FROM_AR
+ br.many vmx_virtualization_fault_back
+#endif
+ add r18=VCPU_VTM_OFFSET_OFS,r21
+ add r16=VCPU_VTM_LAST_ITC_OFS,r21
+ extr.u r17=r25,6,7
+ ;;
+ ld8 r18=[r18]
+ mov r19=ar.itc
+ mov r24=b0
+ ;;
+ ld8 r16=[r16]
+ add r19=r19,r18
+ movl r20=asm_mov_to_reg
+ ;;
+ adds r30=vmx_resume_to_guest-asm_mov_to_reg,r20
+ shladd r17=r17,4,r20
+ cmp.gtu p6,p0=r16,r19
+ ;;
+ (p6) mov r19=r16
+ mov b0=r17
+ br.sptk.few b0
+ ;;
+END(vmx_asm_mov_from_ar)
+
+
+// mov r1=rr[r3]
+GLOBAL_ENTRY(vmx_asm_mov_from_rr)
+#ifndef ACCE_MOV_FROM_RR
+ br.many vmx_virtualization_fault_back
+#endif
+ extr.u r16=r25,20,7
+ extr.u r17=r25,6,7
+ movl r20=asm_mov_from_reg
+ ;;
+ adds r30=vmx_asm_mov_from_rr_back_1-asm_mov_from_reg,r20
+ shladd r16=r16,4,r20
+ mov r24=b0
+ ;;
+ add r27=VCPU_VRR0_OFS,r21
+ mov b0=r16
+ br.many b0
+ ;;
+vmx_asm_mov_from_rr_back_1:
+ adds r30=vmx_resume_to_guest-asm_mov_from_reg,r20
+ adds r22=asm_mov_to_reg-asm_mov_from_reg,r20
+ shr.u r26=r19,61
+ ;;
+ shladd r17=r17,4,r22
+ shladd r27=r26,3,r27
+ ;;
+ ld8 r19=[r27]
+ mov b0=r17
+ br.many b0
+END(vmx_asm_mov_from_rr)
+
+
+// mov rr[r3]=r2
+GLOBAL_ENTRY(vmx_asm_mov_to_rr)
+#ifndef ACCE_MOV_TO_RR
+ br.many vmx_virtualization_fault_back
+#endif
+ extr.u r16=r25,20,7
+ extr.u r17=r25,13,7
+ movl r20=asm_mov_from_reg
+ ;;
+ adds r30=vmx_asm_mov_to_rr_back_1-asm_mov_from_reg,r20
+ shladd r16=r16,4,r20
+ mov r22=b0
+ ;;
+ add r27=VCPU_VRR0_OFS,r21
+ mov b0=r16
+ br.many b0
+ ;;
+vmx_asm_mov_to_rr_back_1:
+ adds r30=vmx_asm_mov_to_rr_back_2-asm_mov_from_reg,r20
+ shr.u r23=r19,61
+ shladd r17=r17,4,r20
+ ;;
+ //if rr7, go back
+ cmp.eq p6,p0=7,r23
+ mov b0=r22
+ (p6) br.cond.dpnt.many vmx_virtualization_fault_back
+ ;;
+ mov r28=r19
+ mov b0=r17
+ br.many b0
+vmx_asm_mov_to_rr_back_2:
+ adds r30=vmx_resume_to_guest-asm_mov_from_reg,r20
+ shladd r27=r23,3,r27
+ ;; // +starting_rid
+ st8 [r27]=r19
+ mov b0=r30
+ ;;
+ adds r16=IA64_VCPU_STARTING_RID_OFFSET,r21
+ ;;
+ ld4 r16=[r16]
+ ;;
+ shl r16=r16,8
+ ;;
+ add r19=r19,r16
+ ;; //mangling rid 1 and 3
+ extr.u r16=r19,8,8
+ extr.u r17=r19,24,8
+ extr.u r18=r19,2,6
+ ;;
+ dep r19=r16,r19,24,8
+ ;;
+ dep r19=r17,r19,8,8
+ ;; //set ve 1
+ dep r19=-1,r19,0,1
+ cmp.lt p6,p0=14,r18
+ ;;
+ (p6) mov r18=14
+ ;;
+ (p6) dep r19=r18,r19,2,6
+ ;;
+ cmp.eq p6,p0=0,r23
+ ;;
+ cmp.eq.or p6,p0=4,r23
+ ;;
+ adds r16=IA64_VCPU_MODE_FLAGS_OFFSET,r21
+ (p6) adds r17=IA64_VCPU_META_SAVED_RR0_OFFSET,r21
+ ;;
+ ld4 r16=[r16]
+ cmp.eq p7,p0=r0,r0
+ (p6) shladd r17=r23,1,r17
+ ;;
+ (p6) st8 [r17]=r19
+ (p6) tbit.nz p6,p7=r16,0
+ ;;
+ (p7) mov rr[r28]=r19
+ mov r24=r22
+ br.many b0
+END(vmx_asm_mov_to_rr)
+
+
+//rsm
+GLOBAL_ENTRY(vmx_asm_rsm)
+#ifndef ACCE_RSM
+ br.many vmx_virtualization_fault_back
+#endif
+ add r16=IA64_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,6,21
+ extr.u r27=r25,31,2
+ ;;
+ ld8 r16=[r16]
+ extr.u r28=r25,36,1
+ dep r26=r27,r26,21,2
+ ;;
+ add r17=VPD_VPSR_START_OFFSET,r16
+ add r22=IA64_VCPU_MODE_FLAGS_OFFSET,r21
+ //r26 is imm24
+ dep r26=r28,r26,23,1
+ ;;
+ ld8 r18=[r17]
+ movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI
+ ld4 r23=[r22]
+ sub r27=-1,r26
+ mov r24=b0
+ ;;
+ mov r20=cr.ipsr
+ or r28=r27,r28
+ and r19=r18,r27
+ ;;
+ st8 [r17]=r19
+ and r20=r20,r28
+ ;;
+ mov cr.ipsr=r20
+ tbit.nz p6,p0=r23,0
+ ;;
+ tbit.z.or p6,p0=r26,IA64_PSR_DT_BIT
+ (p6) br.dptk vmx_resume_to_guest
+ ;;
+ add r26=IA64_VCPU_META_RR0_OFFSET,r21
+ add r27=IA64_VCPU_META_RR0_OFFSET+8,r21
+ dep r23=-1,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ mov rr[r28]=r27
+ br.many vmx_resume_to_guest
+END(vmx_asm_rsm)
+
+
+//ssm
+GLOBAL_ENTRY(vmx_asm_ssm)
+#ifndef ACCE_SSM
+ br.many vmx_virtualization_fault_back
+#endif
+ add r16=IA64_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,6,21
+ extr.u r27=r25,31,2
+ ;;
+ ld8 r16=[r16]
+ extr.u r28=r25,36,1
+ dep r26=r27,r26,21,2
+ ;; //r26 is imm24
+ add r27=VPD_VPSR_START_OFFSET,r16
+ dep r26=r28,r26,23,1
+ ;; //r19 vpsr
+ ld8 r29=[r27]
+ mov r24=b0
+ ;;
+ add r22=IA64_VCPU_MODE_FLAGS_OFFSET,r21
+ mov r20=cr.ipsr
+ or r19=r29,r26
+ ;;
+ ld4 r23=[r22]
+ st8 [r27]=r19
+ or r20=r20,r26
+ ;;
+ mov cr.ipsr=r20
+ movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT
+ ;;
+ and r19=r28,r19
+ tbit.z p6,p0=r23,0
+ ;;
+ cmp.ne.or p6,p0=r28,r19
+ (p6) br.dptk vmx_asm_ssm_1
+ ;;
+ add r26=IA64_VCPU_META_SAVED_RR0_OFFSET,r21
+ add r27=IA64_VCPU_META_SAVED_RR0_OFFSET+8,r21
+ dep r23=0,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ mov rr[r28]=r27
+ ;;
+ srlz.i
+ ;;
+vmx_asm_ssm_1:
+ tbit.nz p6,p0=r29,IA64_PSR_I_BIT
+ ;;
+ tbit.z.or p6,p0=r19,IA64_PSR_I_BIT
+ (p6) br.dptk vmx_resume_to_guest
+ ;;
+ add r29=VPD_VTPR_START_OFFSET,r16
+ add r30=VPD_VHPI_START_OFFSET,r16
+ ;;
+ ld8 r29=[r29]
+ ld8 r30=[r30]
+ ;;
+ extr.u r17=r29,4,4
+ extr.u r18=r29,16,1
+ ;;
+ dep r17=r18,r17,4,1
+ ;;
+ cmp.gt p6,p0=r30,r17
+ (p6) br.dpnt.few vmx_asm_dispatch_vexirq
+ br.many vmx_resume_to_guest
+END(vmx_asm_ssm)
+
+
+//mov psr.l=r2
+GLOBAL_ENTRY(vmx_asm_mov_to_psr)
+#ifndef ACCE_MOV_TO_PSR
+ br.many vmx_virtualization_fault_back
+#endif
+ add r16=IA64_VPD_BASE_OFFSET,r21
+ extr.u r26=r25,13,7 //r2
+ ;;
+ ld8 r16=[r16]
+ movl r20=asm_mov_from_reg
+ ;;
+ adds r30=vmx_asm_mov_to_psr_back-asm_mov_from_reg,r20
+ shladd r26=r26,4,r20
+ mov r24=b0
+ ;;
+ add r27=VPD_VPSR_START_OFFSET,r16
+ mov b0=r26
+ br.many b0
+ ;;
+vmx_asm_mov_to_psr_back:
+ ld8 r17=[r27]
+ add r22=IA64_VCPU_MODE_FLAGS_OFFSET,r21
+ dep r19=0,r19,32,32
+ ;;
+ ld4 r23=[r22]
+ dep r18=0,r17,0,32
+ ;;
+ add r30=r18,r19
+ movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT
+ ;;
+ st8 [r27]=r30
+ and r27=r28,r30
+ and r29=r28,r17
+ ;;
+ cmp.eq p5,p0=r29,r27
+ cmp.eq p6,p7=r28,r27
+ (p5) br.many vmx_asm_mov_to_psr_1
+ ;;
+ //virtual to physical
+ (p7) add r26=IA64_VCPU_META_RR0_OFFSET,r21
+ (p7) add r27=IA64_VCPU_META_RR0_OFFSET+8,r21
+ (p7) dep r23=-1,r23,0,1
+ ;;
+ //physical to virtual
+ (p6) add r26=IA64_VCPU_META_SAVED_RR0_OFFSET,r21
+ (p6) add r27=IA64_VCPU_META_SAVED_RR0_OFFSET+8,r21
+ (p6) dep r23=0,r23,0,1
+ ;;
+ ld8 r26=[r26]
+ ld8 r27=[r27]
+ st4 [r22]=r23
+ dep.z r28=4,61,3
+ ;;
+ mov rr[r0]=r26
+ mov rr[r28]=r27
+ ;;
+ srlz.i
+ ;;
+vmx_asm_mov_to_psr_1:
+ mov r20=cr.ipsr
+ movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI+IA64_PSR_RT
+ ;;
+ or r19=r19,r28
+ dep r20=0,r20,0,32
+ ;;
+ add r20=r19,r20
+ mov b0=r24
+ ;;
+ mov cr.ipsr=r20
+ cmp.ne p6,p0=r0,r0
+ ;;
+ tbit.nz.or p6,p0=r17,IA64_PSR_I_BIT
+ tbit.z.or p6,p0=r30,IA64_PSR_I_BIT
+ (p6) br.dpnt.few vmx_resume_to_guest
+ ;;
+ add r29=VPD_VTPR_START_OFFSET,r16
+ add r30=VPD_VHPI_START_OFFSET,r16
+ ;;
+ ld8 r29=[r29]
+ ld8 r30=[r30]
+ ;;
+ extr.u r17=r29,4,4
+ extr.u r18=r29,16,1
+ ;;
+ dep r17=r18,r17,4,1
+ ;;
+ cmp.gt p6,p0=r30,r17
+ (p6) br.dpnt.few vmx_asm_dispatch_vexirq
+ br.many vmx_resume_to_guest
+END(vmx_asm_mov_to_psr)
+
+
+ENTRY(vmx_asm_dispatch_vexirq)
+//increment iip
+ mov r16=cr.ipsr
+ ;;
+ extr.u r17=r16,IA64_PSR_RI_BIT,2
+ tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1
+ ;;
+ (p6) mov r18=cr.iip
+ (p6) mov r17=r0
+ (p7) add r17=1,r17
+ ;;
+ (p6) add r18=0x10,r18
+ dep r16=r17,r16,IA64_PSR_RI_BIT,2
+ ;;
+ (p6) mov cr.iip=r18
+ mov cr.ipsr=r16
+ br.many vmx_dispatch_vexirq
+END(vmx_asm_dispatch_vexirq)
+
+
+#define MOV_TO_REG0 \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ ;; \
+};
+
+
+#define MOV_TO_REG(n) \
+{; \
+ mov r##n##=r19; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+};
+
+
+#define MOV_FROM_REG(n) \
+{; \
+ mov r19=r##n##; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+};
+
+
+#define MOV_TO_BANK0_REG(n) \
+ENTRY_MIN_ALIGN(asm_mov_to_bank0_reg##n##); \
+{; \
+ mov r26=r2; \
+ mov r2=r19; \
+ bsw.1; \
+ ;; \
+}; \
+{; \
+ mov r##n##=r2; \
+ nop.b 0x0; \
+ bsw.0; \
+ ;; \
+}; \
+{; \
+ mov r2=r26; \
+ mov b0=r30; \
+ br.sptk.many b0; \
+ ;; \
+}; \
+END(asm_mov_to_bank0_reg##n##)
+
+
+#define MOV_FROM_BANK0_REG(n) \
+ENTRY_MIN_ALIGN(asm_mov_from_bank0_reg##n##); \
+{; \
+ mov r26=r2; \
+ nop.b 0x0; \
+ bsw.1; \
+ ;; \
+}; \
+{; \
+ mov r2=r##n##; \
+ nop.b 0x0; \
+ bsw.0; \
+ ;; \
+}; \
+{; \
+ mov r19=r2; \
+ mov r2=r26; \
+ mov b0=r30; \
+}; \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many b0; \
+ ;; \
+}; \
+END(asm_mov_from_bank0_reg##n##)
+
+
+#define JMP_TO_MOV_TO_BANK0_REG(n) \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many asm_mov_to_bank0_reg##n##; \
+ ;; \
+}
+
+
+#define JMP_TO_MOV_FROM_BANK0_REG(n) \
+{; \
+ nop.b 0x0; \
+ nop.b 0x0; \
+ br.sptk.many asm_mov_from_bank0_reg##n##; \
+ ;; \
+}
+
+
+MOV_FROM_BANK0_REG(16)
+MOV_FROM_BANK0_REG(17)
+MOV_FROM_BANK0_REG(18)
+MOV_FROM_BANK0_REG(19)
+MOV_FROM_BANK0_REG(20)
+MOV_FROM_BANK0_REG(21)
+MOV_FROM_BANK0_REG(22)
+MOV_FROM_BANK0_REG(23)
+MOV_FROM_BANK0_REG(24)
+MOV_FROM_BANK0_REG(25)
+MOV_FROM_BANK0_REG(26)
+MOV_FROM_BANK0_REG(27)
+MOV_FROM_BANK0_REG(28)
+MOV_FROM_BANK0_REG(29)
+MOV_FROM_BANK0_REG(30)
+MOV_FROM_BANK0_REG(31)
+
+
+// mov from reg table
+ENTRY(asm_mov_from_reg)
+ MOV_FROM_REG(0)
+ MOV_FROM_REG(1)
+ MOV_FROM_REG(2)
+ MOV_FROM_REG(3)
+ MOV_FROM_REG(4)
+ MOV_FROM_REG(5)
+ MOV_FROM_REG(6)
+ MOV_FROM_REG(7)
+ MOV_FROM_REG(8)
+ MOV_FROM_REG(9)
+ MOV_FROM_REG(10)
+ MOV_FROM_REG(11)
+ MOV_FROM_REG(12)
+ MOV_FROM_REG(13)
+ MOV_FROM_REG(14)
+ MOV_FROM_REG(15)
+ JMP_TO_MOV_FROM_BANK0_REG(16)
+ JMP_TO_MOV_FROM_BANK0_REG(17)
+ JMP_TO_MOV_FROM_BANK0_REG(18)
+ JMP_TO_MOV_FROM_BANK0_REG(19)
+ JMP_TO_MOV_FROM_BANK0_REG(20)
+ JMP_TO_MOV_FROM_BANK0_REG(21)
+ JMP_TO_MOV_FROM_BANK0_REG(22)
+ JMP_TO_MOV_FROM_BANK0_REG(23)
+ JMP_TO_MOV_FROM_BANK0_REG(24)
+ JMP_TO_MOV_FROM_BANK0_REG(25)
+ JMP_TO_MOV_FROM_BANK0_REG(26)
+ JMP_TO_MOV_FROM_BANK0_REG(27)
+ JMP_TO_MOV_FROM_BANK0_REG(28)
+ JMP_TO_MOV_FROM_BANK0_REG(29)
+ JMP_TO_MOV_FROM_BANK0_REG(30)
+ JMP_TO_MOV_FROM_BANK0_REG(31)
+ MOV_FROM_REG(32)
+ MOV_FROM_REG(33)
+ MOV_FROM_REG(34)
+ MOV_FROM_REG(35)
+ MOV_FROM_REG(36)
+ MOV_FROM_REG(37)
+ MOV_FROM_REG(38)
+ MOV_FROM_REG(39)
+ MOV_FROM_REG(40)
+ MOV_FROM_REG(41)
+ MOV_FROM_REG(42)
+ MOV_FROM_REG(43)
+ MOV_FROM_REG(44)
+ MOV_FROM_REG(45)
+ MOV_FROM_REG(46)
+ MOV_FROM_REG(47)
+ MOV_FROM_REG(48)
+ MOV_FROM_REG(49)
+ MOV_FROM_REG(50)
+ MOV_FROM_REG(51)
+ MOV_FROM_REG(52)
+ MOV_FROM_REG(53)
+ MOV_FROM_REG(54)
+ MOV_FROM_REG(55)
+ MOV_FROM_REG(56)
+ MOV_FROM_REG(57)
+ MOV_FROM_REG(58)
+ MOV_FROM_REG(59)
+ MOV_FROM_REG(60)
+ MOV_FROM_REG(61)
+ MOV_FROM_REG(62)
+ MOV_FROM_REG(63)
+ MOV_FROM_REG(64)
+ MOV_FROM_REG(65)
+ MOV_FROM_REG(66)
+ MOV_FROM_REG(67)
+ MOV_FROM_REG(68)
+ MOV_FROM_REG(69)
+ MOV_FROM_REG(70)
+ MOV_FROM_REG(71)
+ MOV_FROM_REG(72)
+ MOV_FROM_REG(73)
+ MOV_FROM_REG(74)
+ MOV_FROM_REG(75)
+ MOV_FROM_REG(76)
+ MOV_FROM_REG(77)
+ MOV_FROM_REG(78)
+ MOV_FROM_REG(79)
+ MOV_FROM_REG(80)
+ MOV_FROM_REG(81)
+ MOV_FROM_REG(82)
+ MOV_FROM_REG(83)
+ MOV_FROM_REG(84)
+ MOV_FROM_REG(85)
+ MOV_FROM_REG(86)
+ MOV_FROM_REG(87)
+ MOV_FROM_REG(88)
+ MOV_FROM_REG(89)
+ MOV_FROM_REG(90)
+ MOV_FROM_REG(91)
+ MOV_FROM_REG(92)
+ MOV_FROM_REG(93)
+ MOV_FROM_REG(94)
+ MOV_FROM_REG(95)
+ MOV_FROM_REG(96)
+ MOV_FROM_REG(97)
+ MOV_FROM_REG(98)
+ MOV_FROM_REG(99)
+ MOV_FROM_REG(100)
+ MOV_FROM_REG(101)
+ MOV_FROM_REG(102)
+ MOV_FROM_REG(103)
+ MOV_FROM_REG(104)
+ MOV_FROM_REG(105)
+ MOV_FROM_REG(106)
+ MOV_FROM_REG(107)
+ MOV_FROM_REG(108)
+ MOV_FROM_REG(109)
+ MOV_FROM_REG(110)
+ MOV_FROM_REG(111)
+ MOV_FROM_REG(112)
+ MOV_FROM_REG(113)
+ MOV_FROM_REG(114)
+ MOV_FROM_REG(115)
+ MOV_FROM_REG(116)
+ MOV_FROM_REG(117)
+ MOV_FROM_REG(118)
+ MOV_FROM_REG(119)
+ MOV_FROM_REG(120)
+ MOV_FROM_REG(121)
+ MOV_FROM_REG(122)
+ MOV_FROM_REG(123)
+ MOV_FROM_REG(124)
+ MOV_FROM_REG(125)
+ MOV_FROM_REG(126)
+ MOV_FROM_REG(127)
+END(asm_mov_from_reg)
+
+
+/* must be in bank 0
+ * parameter:
+ * r31: pr
+ * r24: b0
+ */
+ENTRY(vmx_resume_to_guest)
+ mov r16=cr.ipsr
+ movl r20=__vsa_base
+ ;;
+ ld8 r20=[r20]
+ adds r19=IA64_VPD_BASE_OFFSET,r21
+ ;;
+ ld8 r25=[r19]
+ extr.u r17=r16,IA64_PSR_RI_BIT,2
+ tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1
+ ;;
+ (p6) mov r18=cr.iip
+ (p6) mov r17=r0
+ ;;
+ (p6) add r18=0x10,r18
+ (p7) add r17=1,r17
+ ;;
+ (p6) mov cr.iip=r18
+ dep r16=r17,r16,IA64_PSR_RI_BIT,2
+ ;;
+ mov cr.ipsr=r16
+ adds r19= VPD_VPSR_START_OFFSET,r25
+ add r28=PAL_VPS_RESUME_NORMAL,r20
+ add r29=PAL_VPS_RESUME_HANDLER,r20
+ ;;
+ ld8 r19=[r19]
+ mov b0=r29
+ cmp.ne p6,p7 = r0,r0
+ ;;
+ tbit.z p6,p7 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic
+ ;;
+ (p6) ld8 r26=[r25]
+ (p7) mov b0=r28
+ mov pr=r31,-2
+ br.sptk.many b0 // call pal service
+ ;;
+END(vmx_resume_to_guest)
+
+
+MOV_TO_BANK0_REG(16)
+MOV_TO_BANK0_REG(17)
+MOV_TO_BANK0_REG(18)
+MOV_TO_BANK0_REG(19)
+MOV_TO_BANK0_REG(20)
+MOV_TO_BANK0_REG(21)
+MOV_TO_BANK0_REG(22)
+MOV_TO_BANK0_REG(23)
+MOV_TO_BANK0_REG(24)
+MOV_TO_BANK0_REG(25)
+MOV_TO_BANK0_REG(26)
+MOV_TO_BANK0_REG(27)
+MOV_TO_BANK0_REG(28)
+MOV_TO_BANK0_REG(29)
+MOV_TO_BANK0_REG(30)
+MOV_TO_BANK0_REG(31)
+
+
+// mov to reg table
+ENTRY(asm_mov_to_reg)
+ MOV_TO_REG0
+ MOV_TO_REG(1)
+ MOV_TO_REG(2)
+ MOV_TO_REG(3)
+ MOV_TO_REG(4)
+ MOV_TO_REG(5)
+ MOV_TO_REG(6)
+ MOV_TO_REG(7)
+ MOV_TO_REG(8)
+ MOV_TO_REG(9)
+ MOV_TO_REG(10)
+ MOV_TO_REG(11)
+ MOV_TO_REG(12)
+ MOV_TO_REG(13)
+ MOV_TO_REG(14)
+ MOV_TO_REG(15)
+ JMP_TO_MOV_TO_BANK0_REG(16)
+ JMP_TO_MOV_TO_BANK0_REG(17)
+ JMP_TO_MOV_TO_BANK0_REG(18)
+ JMP_TO_MOV_TO_BANK0_REG(19)
+ JMP_TO_MOV_TO_BANK0_REG(20)
+ JMP_TO_MOV_TO_BANK0_REG(21)
+ JMP_TO_MOV_TO_BANK0_REG(22)
+ JMP_TO_MOV_TO_BANK0_REG(23)
+ JMP_TO_MOV_TO_BANK0_REG(24)
+ JMP_TO_MOV_TO_BANK0_REG(25)
+ JMP_TO_MOV_TO_BANK0_REG(26)
+ JMP_TO_MOV_TO_BANK0_REG(27)
+ JMP_TO_MOV_TO_BANK0_REG(28)
+ JMP_TO_MOV_TO_BANK0_REG(29)
+ JMP_TO_MOV_TO_BANK0_REG(30)
+ JMP_TO_MOV_TO_BANK0_REG(31)
+ MOV_TO_REG(32)
+ MOV_TO_REG(33)
+ MOV_TO_REG(34)
+ MOV_TO_REG(35)
+ MOV_TO_REG(36)
+ MOV_TO_REG(37)
+ MOV_TO_REG(38)
+ MOV_TO_REG(39)
+ MOV_TO_REG(40)
+ MOV_TO_REG(41)
+ MOV_TO_REG(42)
+ MOV_TO_REG(43)
+ MOV_TO_REG(44)
+ MOV_TO_REG(45)
+ MOV_TO_REG(46)
+ MOV_TO_REG(47)
+ MOV_TO_REG(48)
+ MOV_TO_REG(49)
+ MOV_TO_REG(50)
+ MOV_TO_REG(51)
+ MOV_TO_REG(52)
+ MOV_TO_REG(53)
+ MOV_TO_REG(54)
+ MOV_TO_REG(55)
+ MOV_TO_REG(56)
+ MOV_TO_REG(57)
+ MOV_TO_REG(58)
+ MOV_TO_REG(59)
+ MOV_TO_REG(60)
+ MOV_TO_REG(61)
+ MOV_TO_REG(62)
+ MOV_TO_REG(63)
+ MOV_TO_REG(64)
+ MOV_TO_REG(65)
+ MOV_TO_REG(66)
+ MOV_TO_REG(67)
+ MOV_TO_REG(68)
+ MOV_TO_REG(69)
+ MOV_TO_REG(70)
+ MOV_TO_REG(71)
+ MOV_TO_REG(72)
+ MOV_TO_REG(73)
+ MOV_TO_REG(74)
+ MOV_TO_REG(75)
+ MOV_TO_REG(76)
+ MOV_TO_REG(77)
+ MOV_TO_REG(78)
+ MOV_TO_REG(79)
+ MOV_TO_REG(80)
+ MOV_TO_REG(81)
+ MOV_TO_REG(82)
+ MOV_TO_REG(83)
+ MOV_TO_REG(84)
+ MOV_TO_REG(85)
+ MOV_TO_REG(86)
+ MOV_TO_REG(87)
+ MOV_TO_REG(88)
+ MOV_TO_REG(89)
+ MOV_TO_REG(90)
+ MOV_TO_REG(91)
+ MOV_TO_REG(92)
+ MOV_TO_REG(93)
+ MOV_TO_REG(94)
+ MOV_TO_REG(95)
+ MOV_TO_REG(96)
+ MOV_TO_REG(97)
+ MOV_TO_REG(98)
+ MOV_TO_REG(99)
+ MOV_TO_REG(100)
+ MOV_TO_REG(101)
+ MOV_TO_REG(102)
+ MOV_TO_REG(103)
+ MOV_TO_REG(104)
+ MOV_TO_REG(105)
+ MOV_TO_REG(106)
+ MOV_TO_REG(107)
+ MOV_TO_REG(108)
+ MOV_TO_REG(109)
+ MOV_TO_REG(110)
+ MOV_TO_REG(111)
+ MOV_TO_REG(112)
+ MOV_TO_REG(113)
+ MOV_TO_REG(114)
+ MOV_TO_REG(115)
+ MOV_TO_REG(116)
+ MOV_TO_REG(117)
+ MOV_TO_REG(118)
+ MOV_TO_REG(119)
+ MOV_TO_REG(120)
+ MOV_TO_REG(121)
+ MOV_TO_REG(122)
+ MOV_TO_REG(123)
+ MOV_TO_REG(124)
+ MOV_TO_REG(125)
+ MOV_TO_REG(126)
+ MOV_TO_REG(127)
+END(asm_mov_to_reg)
diff --git a/xen/arch/ia64/vmx/pal_emul.c b/xen/arch/ia64/vmx/pal_emul.c
index 2c88fb34e2..8f3c9400d4 100644
--- a/xen/arch/ia64/vmx/pal_emul.c
+++ b/xen/arch/ia64/vmx/pal_emul.c
@@ -17,509 +17,46 @@
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
-
-#include <asm/vmx_vcpu.h>
+
+#include <xen/lib.h>
+#include <asm/vcpu.h>
+#include <asm/dom_fw.h>
#include <asm/pal.h>
#include <asm/sal.h>
-#include <asm/dom_fw.h>
-#include <asm/tlb.h>
-#include <asm/vmx_mm_def.h>
-#include <xen/hypercall.h>
-#include <public/sched.h>
-
-/*
- * Handy macros to make sure that the PAL return values start out
- * as something meaningful.
- */
-#define INIT_PAL_STATUS_UNIMPLEMENTED(x) \
- { \
- x.status = PAL_STATUS_UNIMPLEMENTED; \
- x.v0 = 0; \
- x.v1 = 0; \
- x.v2 = 0; \
- }
-
-#define INIT_PAL_STATUS_SUCCESS(x) \
- { \
- x.status = PAL_STATUS_SUCCESS; \
- x.v0 = 0; \
- x.v1 = 0; \
- x.v2 = 0; \
- }
-
-static void
-get_pal_parameters(VCPU *vcpu, UINT64 *gr29, UINT64 *gr30, UINT64 *gr31) {
-
- vcpu_get_gr_nat(vcpu,29,gr29);
- vcpu_get_gr_nat(vcpu,30,gr30);
- vcpu_get_gr_nat(vcpu,31,gr31);
-}
-
-static void
-set_pal_result(VCPU *vcpu,struct ia64_pal_retval result) {
-
- vcpu_set_gr(vcpu,8, result.status,0);
- vcpu_set_gr(vcpu,9, result.v0,0);
- vcpu_set_gr(vcpu,10, result.v1,0);
- vcpu_set_gr(vcpu,11, result.v2,0);
-}
-
-static void
-set_sal_result(VCPU *vcpu,struct sal_ret_values result) {
-
- vcpu_set_gr(vcpu,8, result.r8,0);
- vcpu_set_gr(vcpu,9, result.r9,0);
- vcpu_set_gr(vcpu,10, result.r10,0);
- vcpu_set_gr(vcpu,11, result.r11,0);
-}
-
-static struct ia64_pal_retval
-pal_cache_flush(VCPU *vcpu) {
- UINT64 gr28,gr29, gr30, gr31;
- struct ia64_pal_retval result;
-
- get_pal_parameters(vcpu, &gr29, &gr30, &gr31);
- vcpu_get_gr_nat(vcpu, 28, &gr28);
-
- /* Always call Host Pal in int=1 */
- gr30 = gr30 & ~0x2UL;
-
- /*
- * Call Host PAL cache flush
- * Clear psr.ic when call PAL_CACHE_FLUSH
- */
- result = ia64_pal_call_static(gr28 ,gr29, gr30, gr31, 1);
-
- /* If host PAL call is interrupted, then loop to complete it */
-// while (result.status == 1)
-// ia64_pal_call_static(gr28 ,gr29, gr30, result.v1, 1LL);
-//
- if (result.status != 0)
- panic_domain(vcpu_regs(vcpu), "PAL_CACHE_FLUSH ERROR, "
- "status %ld", result.status);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_vm_tr_read(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_prefetch_visibility(VCPU *vcpu) {
- /* Due to current MM virtualization algorithm,
- * We do not allow guest to change mapping attribute.
- * Thus we will not support PAL_PREFETCH_VISIBILITY
- */
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_platform_addr(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_SUCCESS(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_halt(VCPU *vcpu) {
- //bugbug: to be implement.
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_halt_light(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- if (!is_unmasked_irq(vcpu))
- do_sched_op_compat(SCHEDOP_block, 0);
-
- INIT_PAL_STATUS_SUCCESS(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_read(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_write(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_bus_get_features(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_summary(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_init(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_SUCCESS(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_cache_prot_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_mem_attrib(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_debug_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_fixed_addr(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_freq_base(VCPU *vcpu) {
- struct ia64_pal_retval result;
- struct ia64_sal_retval isrv;
-
- PAL_CALL(result,PAL_FREQ_BASE, 0, 0, 0);
- /*
- * PAL_FREQ_BASE may not be implemented in some platforms,
- * call SAL instead.
- */
- if (result.v0 == 0) {
- SAL_CALL(isrv, SAL_FREQ_BASE,
- SAL_FREQ_BASE_PLATFORM, 0, 0, 0, 0, 0, 0);
- result.status = isrv.status;
- result.v0 = isrv.v0;
- result.v1 = result.v2 = 0;
- }
- return result;
-}
-
-static struct ia64_pal_retval
-pal_freq_ratios(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
- return result;
-}
-
-static struct ia64_pal_retval
-pal_halt_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_logical_to_physica(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_perf_mon_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_proc_get_features(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_ptce_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_register_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_rse_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_test_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_vm_summary(VCPU *vcpu) {
- pal_vm_info_1_u_t vminfo1;
- pal_vm_info_2_u_t vminfo2;
- struct ia64_pal_retval result;
-
- PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0);
- if (!result.status) {
- vminfo1.pvi1_val = result.v0;
- vminfo1.pal_vm_info_1_s.max_itr_entry = NITRS -1;
- vminfo1.pal_vm_info_1_s.max_dtr_entry = NDTRS -1;
- result.v0 = vminfo1.pvi1_val;
- vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB;
- vminfo2.pal_vm_info_2_s.rid_size =
- current->domain->arch.rid_bits;
- result.v1 = vminfo2.pvi2_val;
- }
- return result;
-}
-
-static struct ia64_pal_retval
-pal_vm_info(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
-
-static struct ia64_pal_retval
-pal_vm_page_size(VCPU *vcpu) {
- struct ia64_pal_retval result;
-
- INIT_PAL_STATUS_UNIMPLEMENTED(result);
-
- return result;
-}
void
-pal_emul(VCPU *vcpu) {
- UINT64 gr28;
+pal_emul(struct vcpu *vcpu)
+{
+ u64 gr28, gr29, gr30, gr31;
struct ia64_pal_retval result;
- vcpu_get_gr_nat(vcpu,28,&gr28); //bank1
-
- perfc_incrc(vmx_pal_emul);
- switch (gr28) {
- case PAL_CACHE_FLUSH:
- result = pal_cache_flush(vcpu);
- break;
-
- case PAL_PREFETCH_VISIBILITY:
- result = pal_prefetch_visibility(vcpu);
- break;
-
- case PAL_VM_TR_READ:
- result = pal_vm_tr_read(vcpu);
- break;
-
- case PAL_HALT:
- result = pal_halt(vcpu);
- break;
-
- case PAL_HALT_LIGHT:
- result = pal_halt_light(vcpu);
- break;
-
- case PAL_CACHE_READ:
- result = pal_cache_read(vcpu);
- break;
+ vcpu_get_gr_nat(vcpu, 28, &gr28); //bank1
- case PAL_CACHE_WRITE:
- result = pal_cache_write(vcpu);
- break;
+ /* FIXME: works only for static calling convention ? */
+ vcpu_get_gr_nat(vcpu, 29, &gr29);
+ vcpu_get_gr_nat(vcpu, 30, &gr30);
+ vcpu_get_gr_nat(vcpu, 31, &gr31);
- case PAL_PLATFORM_ADDR:
- result = pal_platform_addr(vcpu);
- break;
-
- case PAL_FREQ_RATIOS:
- result = pal_freq_ratios(vcpu);
- break;
-
- case PAL_FREQ_BASE:
- result = pal_freq_base(vcpu);
- break;
-
- case PAL_BUS_GET_FEATURES :
- result = pal_bus_get_features(vcpu);
- break;
-
- case PAL_CACHE_SUMMARY :
- result = pal_cache_summary(vcpu);
- break;
-
- case PAL_CACHE_INIT :
- result = pal_cache_init(vcpu);
- break;
-
- case PAL_CACHE_INFO :
- result = pal_cache_info(vcpu);
- break;
-
- case PAL_CACHE_PROT_INFO :
- result = pal_cache_prot_info(vcpu);
- break;
-
- case PAL_MEM_ATTRIB :
- result = pal_mem_attrib(vcpu);
- break;
-
- case PAL_DEBUG_INFO :
- result = pal_debug_info(vcpu);
- break;
-
- case PAL_FIXED_ADDR :
- result = pal_fixed_addr(vcpu);
- break;
-
- case PAL_HALT_INFO :
- result = pal_halt_info(vcpu);
- break;
-
- case PAL_LOGICAL_TO_PHYSICAL :
- result = pal_logical_to_physica(vcpu);
- break;
-
- case PAL_PERF_MON_INFO :
- result = pal_perf_mon_info(vcpu);
- break;
-
- case PAL_PROC_GET_FEATURES:
- result = pal_proc_get_features(vcpu);
- break;
-
- case PAL_PTCE_INFO :
- result = pal_ptce_info(vcpu);
- break;
-
- case PAL_REGISTER_INFO :
- result = pal_register_info(vcpu);
- break;
-
- case PAL_RSE_INFO :
- result = pal_rse_info(vcpu);
- break;
-
- case PAL_TEST_PROC :
- result = pal_test_info(vcpu);
- break;
-
- case PAL_VM_SUMMARY :
- result = pal_vm_summary(vcpu);
- break;
-
- case PAL_VM_INFO :
- result = pal_vm_info(vcpu);
- break;
-
- case PAL_VM_PAGE_SIZE :
- result = pal_vm_page_size(vcpu);
- break;
+ perfc_incrc(vmx_pal_emul);
+ result = xen_pal_emulator(gr28, gr29, gr30, gr31);
- default:
- panic_domain(vcpu_regs(vcpu),"pal_emul(): guest "
- "call unsupported pal" );
- }
- set_pal_result(vcpu, result);
+ vcpu_set_gr(vcpu, 8, result.status, 0);
+ vcpu_set_gr(vcpu, 9, result.v0, 0);
+ vcpu_set_gr(vcpu, 10, result.v1, 0);
+ vcpu_set_gr(vcpu, 11, result.v2, 0);
}
void
-sal_emul(VCPU *v) {
+sal_emul(struct vcpu *v)
+{
struct sal_ret_values result;
result = sal_emulator(vcpu_get_gr(v, 32), vcpu_get_gr(v, 33),
vcpu_get_gr(v, 34), vcpu_get_gr(v, 35),
vcpu_get_gr(v, 36), vcpu_get_gr(v, 37),
vcpu_get_gr(v, 38), vcpu_get_gr(v, 39));
- set_sal_result(v, result);
+
+ vcpu_set_gr(v, 8, result.r8, 0);
+ vcpu_set_gr(v, 9, result.r9, 0);
+ vcpu_set_gr(v, 10, result.r10, 0);
+ vcpu_set_gr(v, 11, result.r11, 0);
}
diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c
index 0bc909f127..3a6d85a36a 100644
--- a/xen/arch/ia64/vmx/vlsapic.c
+++ b/xen/arch/ia64/vmx/vlsapic.c
@@ -49,14 +49,67 @@
* Update the checked last_itc.
*/
-extern void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim,
- UINT64 vector,REGS *regs);
+extern void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim,
+ u64 vector, REGS *regs);
static void update_last_itc(vtime_t *vtm, uint64_t cur_itc)
{
vtm->last_itc = cur_itc;
}
/*
+ * Next for vLSapic
+ */
+
+#define NMI_VECTOR 2
+#define ExtINT_VECTOR 0
+#define NULL_VECTOR -1
+
+static void update_vhpi(VCPU *vcpu, int vec)
+{
+ u64 vhpi;
+
+ if (vec == NULL_VECTOR)
+ vhpi = 0;
+ else if (vec == NMI_VECTOR)
+ vhpi = 32;
+ else if (vec == ExtINT_VECTOR)
+ vhpi = 16;
+ else
+ vhpi = vec >> 4;
+
+ VCPU(vcpu,vhpi) = vhpi;
+ // TODO: Add support for XENO
+ if (VCPU(vcpu,vac).a_int)
+ ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT,
+ (uint64_t)vcpu->arch.privregs, 0, 0, 0, 0, 0, 0);
+}
+
+
+/*
+ * May come from virtualization fault or
+ * nested host interrupt.
+ */
+static int vmx_vcpu_unpend_interrupt(VCPU *vcpu, uint8_t vector)
+{
+ uint64_t spsr;
+ int ret;
+
+ if (vector & ~0xff) {
+ dprintk(XENLOG_WARNING, "vmx_vcpu_pend_interrupt: bad vector\n");
+ return -1;
+ }
+
+ local_irq_save(spsr);
+ ret = test_and_clear_bit(vector, &VCPU(vcpu, irr[0]));
+ local_irq_restore(spsr);
+
+ if (ret)
+ vcpu->arch.irq_new_pending = 1;
+
+ return ret;
+}
+
+/*
* ITC value saw in guest (host+offset+drift).
*/
static uint64_t now_itc(vtime_t *vtm)
@@ -66,14 +119,11 @@ static uint64_t now_itc(vtime_t *vtm)
if ( vtm->vtm_local_drift ) {
// guest_itc -= vtm->vtm_local_drift;
}
- if ( (long)(guest_itc - vtm->last_itc) > 0 ) {
+ if (guest_itc >= vtm->last_itc)
return guest_itc;
-
- }
- else {
+ else
/* guest ITC backwarded due after LP switch */
return vtm->last_itc;
- }
}
/*
@@ -81,36 +131,42 @@ static uint64_t now_itc(vtime_t *vtm)
*/
static void vtm_reset(VCPU *vcpu)
{
- uint64_t cur_itc;
- vtime_t *vtm;
-
- vtm=&(vcpu->arch.arch_vmx.vtm);
- vtm->vtm_offset = 0;
+ int i;
+ u64 vtm_offset;
+ VCPU *v;
+ struct domain *d = vcpu->domain;
+ vtime_t *vtm = &VMX(vcpu, vtm);
+
+ if (vcpu->vcpu_id == 0) {
+ vtm_offset = 0UL - ia64_get_itc();
+ for (i = MAX_VIRT_CPUS - 1; i >= 0; i--) {
+ if ((v = d->vcpu[i]) != NULL) {
+ VMX(v, vtm).vtm_offset = vtm_offset;
+ VMX(v, vtm).last_itc = 0;
+ }
+ }
+ }
vtm->vtm_local_drift = 0;
VCPU(vcpu, itm) = 0;
VCPU(vcpu, itv) = 0x10000;
- cur_itc = ia64_get_itc();
- vtm->last_itc = vtm->vtm_offset + cur_itc;
+ vtm->last_itc = 0;
}
/* callback function when vtm_timer expires */
static void vtm_timer_fn(void *data)
{
- vtime_t *vtm;
- VCPU *vcpu = data;
- u64 cur_itc,vitv;
+ VCPU *vcpu = data;
+ vtime_t *vtm = &VMX(vcpu, vtm);
+ u64 vitv;
vitv = VCPU(vcpu, itv);
- if ( !ITV_IRQ_MASK(vitv) ){
- vmx_vcpu_pend_interrupt(vcpu, vitv & 0xff);
+ if (!ITV_IRQ_MASK(vitv)) {
+ vmx_vcpu_pend_interrupt(vcpu, ITV_VECTOR(vitv));
vcpu_unblock(vcpu);
- }
- vtm=&(vcpu->arch.arch_vmx.vtm);
- cur_itc = now_itc(vtm);
- // vitm =VCPU(vcpu, itm);
- //fire_itc2 = cur_itc;
- //fire_itm2 = vitm;
- update_last_itc(vtm,cur_itc); // pseudo read to update vITC
+ } else
+ vtm->pending = 1;
+
+ update_last_itc(vtm, VCPU(vcpu, itm)); // update vITC
}
void vtm_init(VCPU *vcpu)
@@ -118,7 +174,7 @@ void vtm_init(VCPU *vcpu)
vtime_t *vtm;
uint64_t itc_freq;
- vtm=&(vcpu->arch.arch_vmx.vtm);
+ vtm = &VMX(vcpu, vtm);
itc_freq = local_cpu_data->itc_freq;
vtm->cfg_max_jump=itc_freq*MAX_JUMP_STEP/1000;
@@ -132,10 +188,9 @@ void vtm_init(VCPU *vcpu)
*/
uint64_t vtm_get_itc(VCPU *vcpu)
{
- uint64_t guest_itc;
- vtime_t *vtm;
+ uint64_t guest_itc;
+ vtime_t *vtm = &VMX(vcpu, vtm);
- vtm=&(vcpu->arch.arch_vmx.vtm);
guest_itc = now_itc(vtm);
return guest_itc;
}
@@ -143,24 +198,28 @@ uint64_t vtm_get_itc(VCPU *vcpu)
void vtm_set_itc(VCPU *vcpu, uint64_t new_itc)
{
- uint64_t vitm, vitv;
- vtime_t *vtm;
- vitm = VCPU(vcpu,itm);
- vitv = VCPU(vcpu,itv);
- vtm=&(vcpu->arch.arch_vmx.vtm);
- if(vcpu->vcpu_id == 0){
- vtm->vtm_offset = new_itc - ia64_get_itc();
- vtm->last_itc = new_itc;
- }
- else{
- vtm->vtm_offset = vcpu->domain->vcpu[0]->arch.arch_vmx.vtm.vtm_offset;
- new_itc=vtm->vtm_offset + ia64_get_itc();
- vtm->last_itc = new_itc;
+ int i;
+ uint64_t vitm, vtm_offset;
+ vtime_t *vtm;
+ VCPU *v;
+ struct domain *d = vcpu->domain;
+
+ vitm = VCPU(vcpu, itm);
+ vtm = &VMX(vcpu, vtm);
+ if (vcpu->vcpu_id == 0) {
+ vtm_offset = new_itc - ia64_get_itc();
+ for (i = MAX_VIRT_CPUS - 1; i >= 0; i--) {
+ if ((v = d->vcpu[i]) != NULL) {
+ VMX(v, vtm).vtm_offset = vtm_offset;
+ VMX(v, vtm).last_itc = 0;
+ }
+ }
}
- if(vitm < new_itc){
- clear_bit(ITV_VECTOR(vitv), &VCPU(vcpu, irr[0]));
+ vtm->last_itc = 0;
+ if (vitm <= new_itc)
stop_timer(&vtm->vtm_timer);
- }
+ else
+ vtm_set_itm(vcpu, vitm);
}
@@ -172,16 +231,16 @@ void vtm_set_itm(VCPU *vcpu, uint64_t val)
{
vtime_t *vtm;
uint64_t vitv, cur_itc, expires;
+
vitv = VCPU(vcpu, itv);
- vtm=&(vcpu->arch.arch_vmx.vtm);
- // TODO; need to handle VHPI in future
- clear_bit(ITV_VECTOR(vitv), &VCPU(vcpu, irr[0]));
- VCPU(vcpu,itm)=val;
- cur_itc =now_itc(vtm);
- if(time_before(val, cur_itc))
- val = cur_itc;
- if(val > vtm->last_itc){
+ vtm = &VMX(vcpu, vtm);
+ VCPU(vcpu, itm) = val;
+ if (val > vtm->last_itc) {
+ cur_itc = now_itc(vtm);
+ if (time_before(val, cur_itc))
+ val = cur_itc;
expires = NOW() + cycle_to_ns(val-cur_itc) + TIMER_SLOP;
+ vmx_vcpu_unpend_interrupt(vcpu, ITV_VECTOR(vitv));
set_timer(&vtm->vtm_timer, expires);
}else{
stop_timer(&vtm->vtm_timer);
@@ -191,14 +250,13 @@ void vtm_set_itm(VCPU *vcpu, uint64_t val)
void vtm_set_itv(VCPU *vcpu, uint64_t val)
{
- uint64_t olditv;
- olditv = VCPU(vcpu, itv);
+ vtime_t *vtm = &VMX(vcpu, vtm);
+
VCPU(vcpu, itv) = val;
- if(ITV_IRQ_MASK(val)){
- clear_bit(ITV_VECTOR(olditv), &VCPU(vcpu, irr[0]));
- }else if(ITV_VECTOR(olditv)!=ITV_VECTOR(val)){
- if(test_and_clear_bit(ITV_VECTOR(olditv), &VCPU(vcpu, irr[0])))
- set_bit(ITV_VECTOR(val), &VCPU(vcpu, irr[0]));
+
+ if (!ITV_IRQ_MASK(val) && vtm->pending) {
+ vmx_vcpu_pend_interrupt(vcpu, ITV_VECTOR(val));
+ vtm->pending = 0;
}
}
@@ -272,95 +330,27 @@ void vtm_domain_in(VCPU *vcpu)
}
*/
-/*
- * Next for vLSapic
- */
-
-#define NMI_VECTOR 2
-#define ExtINT_VECTOR 0
-#define NULL_VECTOR -1
-static void update_vhpi(VCPU *vcpu, int vec)
-{
- u64 vhpi;
- if ( vec == NULL_VECTOR ) {
- vhpi = 0;
- }
- else if ( vec == NMI_VECTOR ) { // NMI
- vhpi = 32;
- } else if (vec == ExtINT_VECTOR) { //ExtINT
- vhpi = 16;
- }
- else {
- vhpi = vec >> 4;
- }
-
- VCPU(vcpu,vhpi) = vhpi;
- // TODO: Add support for XENO
- if ( VCPU(vcpu,vac).a_int ) {
- ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT,
- (uint64_t) &(vcpu->arch.privregs), 0, 0,0,0,0,0);
- }
-}
-
#ifdef V_IOSAPIC_READY
-/* Assist to check virtual interrupt lines */
-void vmx_virq_line_assist(struct vcpu *v)
-{
- global_iodata_t *spg = &get_sp(v->domain)->sp_global;
- uint16_t *virq_line, irqs;
-
- virq_line = &spg->pic_irr;
- if (*virq_line) {
- do {
- irqs = *(volatile uint16_t*)virq_line;
- } while ((uint16_t)cmpxchg(virq_line, irqs, 0) != irqs);
- hvm_vioapic_do_irqs(v->domain, irqs);
- }
-
- virq_line = &spg->pic_clear_irr;
- if (*virq_line) {
- do {
- irqs = *(volatile uint16_t*)virq_line;
- } while ((uint16_t)cmpxchg(virq_line, irqs, 0) != irqs);
- hvm_vioapic_do_irqs_clear(v->domain, irqs);
- }
-}
-
-void vmx_virq_line_init(struct domain *d)
+int vlapic_match_logical_addr(struct vlapic *vlapic, uint16_t dest)
{
- global_iodata_t *spg = &get_sp(d)->sp_global;
-
- spg->pic_elcr = 0xdef8; /* Level/Edge trigger mode */
- spg->pic_irr = 0;
- spg->pic_last_irr = 0;
- spg->pic_clear_irr = 0;
-}
-
-int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint16_t dest)
-{
- return (VLAPIC_ID(s->lapic_info[number]) == dest);
+ return (VLAPIC_ID(vlapic) == dest);
}
struct vlapic* apic_round_robin(struct domain *d,
- uint8_t dest_mode,
uint8_t vector,
uint32_t bitmap)
{
- uint8_t bit;
- hvm_vioapic_t *s;
+ uint8_t bit = 0;
if (!bitmap) {
printk("<apic_round_robin> no bit on bitmap\n");
return NULL;
}
- s = &d->arch.vmx_platform.vioapic;
- for (bit = 0; bit < s->lapic_count; bit++) {
- if (bitmap & (1 << bit))
- return s->lapic_info[bit];
- }
+ while (!(bitmap & (1 << bit)))
+ bit++;
- return NULL;
+ return vcpu_vlapic(d->vcpu[bit]);
}
#endif
@@ -387,9 +377,8 @@ void vlsapic_reset(VCPU *vcpu)
#ifdef V_IOSAPIC_READY
vcpu->arch.arch_vmx.vlapic.vcpu = vcpu;
- hvm_vioapic_add_lapic(&vcpu->arch.arch_vmx.vlapic, vcpu);
#endif
- DPRINTK("VLSAPIC inservice base=%p\n", &VLSAPIC_INSVC(vcpu,0) );
+ dprintk(XENLOG_INFO, "VLSAPIC inservice base=%p\n", &VLSAPIC_INSVC(vcpu,0) );
}
/*
@@ -518,22 +507,26 @@ int vmx_vcpu_pend_interrupt(VCPU *vcpu, uint8_t vector)
int ret;
if (vector & ~0xff) {
- DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n");
+ gdprintk(XENLOG_INFO, "vmx_vcpu_pend_interrupt: bad vector\n");
return -1;
}
local_irq_save(spsr);
ret = test_and_set_bit(vector, &VCPU(vcpu, irr[0]));
local_irq_restore(spsr);
- vcpu->arch.irq_new_pending = 1;
+
+ if (!ret)
+ vcpu->arch.irq_new_pending = 1;
+
return ret;
}
+
/*
* Add batch of pending interrupt.
* The interrupt source is contained in pend_irr[0-3] with
* each bits stand for one interrupt.
*/
-void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr)
+void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, u64 *pend_irr)
{
uint64_t spsr;
int i;
@@ -559,14 +552,13 @@ void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr)
*/
int vmx_check_pending_irq(VCPU *vcpu)
{
- uint64_t spsr, mask;
- int h_pending, h_inservice;
- uint64_t isr;
- IA64_PSR vpsr;
+ int mask, h_pending, h_inservice;
+ uint64_t isr;
+ IA64_PSR vpsr;
REGS *regs=vcpu_regs(vcpu);
- local_irq_save(spsr);
h_pending = highest_pending_irq(vcpu);
if ( h_pending == NULL_VECTOR ) {
+ update_vhpi(vcpu, NULL_VECTOR);
h_pending = SPURIOUS_VECTOR;
goto chk_irq_exit;
}
@@ -578,13 +570,11 @@ int vmx_check_pending_irq(VCPU *vcpu)
isr = vpsr.val & IA64_PSR_RI;
if ( !vpsr.ic )
panic_domain(regs,"Interrupt when IC=0\n");
+ update_vhpi(vcpu, h_pending);
+ vmx_reflect_interruption(0, isr, 0, 12, regs); // EXT IRQ
+ } else if (mask == IRQ_MASKED_BY_INSVC) {
if (VCPU(vcpu, vhpi))
update_vhpi(vcpu, NULL_VECTOR);
- vmx_reflect_interruption(0,isr,0, 12, regs ); // EXT IRQ
- }
- else if ( mask == IRQ_MASKED_BY_INSVC ) {
- // cann't inject VHPI
-// DPRINTK("IRQ masked by higher inservice\n");
}
else {
// masked by vpsr.i or vtpr.
@@ -592,7 +582,6 @@ int vmx_check_pending_irq(VCPU *vcpu)
}
chk_irq_exit:
- local_irq_restore(spsr);
return h_pending;
}
@@ -602,17 +591,13 @@ chk_irq_exit:
void guest_write_eoi(VCPU *vcpu)
{
int vec;
- uint64_t spsr;
vec = highest_inservice_irq(vcpu);
if ( vec == NULL_VECTOR )
- panic_domain(vcpu_regs(vcpu),"Wrong vector to EOI\n");
- local_irq_save(spsr);
+ panic_domain(vcpu_regs(vcpu), "Wrong vector to EOI\n");
VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63));
- local_irq_restore(spsr);
VCPU(vcpu, eoi)=0; // overwrite the data
vcpu->arch.irq_new_pending=1;
-// vmx_check_pending_irq(vcpu);
}
int is_unmasked_irq(VCPU *vcpu)
@@ -631,23 +616,21 @@ int is_unmasked_irq(VCPU *vcpu)
uint64_t guest_read_vivr(VCPU *vcpu)
{
- int vec, h_inservice;
- uint64_t spsr;
-
- local_irq_save(spsr);
+ int vec, h_inservice, mask;
vec = highest_pending_irq(vcpu);
h_inservice = highest_inservice_irq(vcpu);
- if ( vec == NULL_VECTOR ||
- irq_masked(vcpu, vec, h_inservice) != IRQ_NO_MASKED ) {
- local_irq_restore(spsr);
+ mask = irq_masked(vcpu, vec, h_inservice);
+ if (vec == NULL_VECTOR || mask == IRQ_MASKED_BY_INSVC) {
+ if (VCPU(vcpu, vhpi))
+ update_vhpi(vcpu, NULL_VECTOR);
+ return IA64_SPURIOUS_INT_VECTOR;
+ }
+ if (mask == IRQ_MASKED_BY_VTPR) {
+ update_vhpi(vcpu, vec);
return IA64_SPURIOUS_INT_VECTOR;
}
-
VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63));
- VCPU(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63));
- if (VCPU(vcpu, vhpi))
- update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write
- local_irq_restore(spsr);
+ vmx_vcpu_unpend_interrupt(vcpu, vec);
return (uint64_t)vec;
}
@@ -657,7 +640,6 @@ static void generate_exirq(VCPU *vcpu)
uint64_t isr;
REGS *regs=vcpu_regs(vcpu);
vpsr.val = VCPU(vcpu, vpsr);
- update_vhpi(vcpu, NULL_VECTOR);
isr = vpsr.val & IA64_PSR_RI;
if ( !vpsr.ic )
panic_domain(regs,"Interrupt when IC=0\n");
@@ -669,7 +651,6 @@ void vhpi_detection(VCPU *vcpu)
uint64_t threshold,vhpi;
tpr_t vtpr;
IA64_PSR vpsr;
-
vpsr.val = VCPU(vcpu, vpsr);
vtpr.val = VCPU(vcpu, tpr);
@@ -683,9 +664,27 @@ void vhpi_detection(VCPU *vcpu)
void vmx_vexirq(VCPU *vcpu)
{
- static uint64_t vexirq_count=0;
-
- vexirq_count ++;
- printk("Virtual ex-irq %ld\n", vexirq_count);
generate_exirq (vcpu);
}
+
+
+void vmx_vioapic_set_irq(struct domain *d, int irq, int level)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&d->arch.arch_vmx.virq_assist_lock, flags);
+ vioapic_set_irq(d, irq, level);
+ spin_unlock_irqrestore(&d->arch.arch_vmx.virq_assist_lock, flags);
+}
+
+int vmx_vlapic_set_irq(VCPU *v, uint8_t vec, uint8_t trig)
+{
+ int ret;
+ int running = test_bit(_VCPUF_running, &v->vcpu_flags);
+
+ ret = vmx_vcpu_pend_interrupt(v, vec);
+ vcpu_unblock(v);
+ if (running)
+ smp_send_event_check_cpu(v->processor);
+ return ret;
+}
diff --git a/xen/arch/ia64/vmx/vmmu.c b/xen/arch/ia64/vmx/vmmu.c
index 9412810f3d..aaf4055674 100644
--- a/xen/arch/ia64/vmx/vmmu.c
+++ b/xen/arch/ia64/vmx/vmmu.c
@@ -341,9 +341,9 @@ fetch_code(VCPU *vcpu, u64 gip, IA64_BUNDLE *pbundle)
ia64_ptcl(gip, ARCH_PAGE_SHIFT << 2);
return IA64_RETRY;
}
- mfn = tlb->ppn >> (PAGE_SHIFT - ARCH_PAGE_SHIFT);
maddr = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) |
(gip & (PSIZE(tlb->ps) - 1));
+ mfn = maddr >> PAGE_SHIFT;
}
page = mfn_to_page(mfn);
@@ -363,7 +363,7 @@ fetch_code(VCPU *vcpu, u64 gip, IA64_BUNDLE *pbundle)
return IA64_NO_FAULT;
}
-IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, u64 pte, u64 itir, u64 ifa)
{
#ifdef VTLB_DEBUG
int slot;
@@ -382,7 +382,7 @@ IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
return IA64_NO_FAULT;
}
-IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, u64 pte, u64 itir, u64 ifa)
{
u64 gpfn;
#ifdef VTLB_DEBUG
@@ -456,7 +456,15 @@ IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
}
#endif
pte &= ~PAGE_FLAGS_RV_MASK;
- thash_purge_entries(vcpu, va, ps);
+
+ /* This is a bad workaround
+ In Linux, region 7 use 16M pagesize and is identity mapped.
+ VHPT page size is 16K in XEN. If purge VHPT while guest insert 16M,
+ it will iteratively purge VHPT 1024 times, which makes XEN/IPF very
+ slow. XEN doesn't purge VHPT
+ */
+ if (ps != _PAGE_SIZE_16M)
+ thash_purge_entries(vcpu, va, ps);
gpfn = (pte & _PAGE_PPN_MASK)>> PAGE_SHIFT;
if (VMX_DOMAIN(vcpu) && __gpfn_is_io(vcpu->domain, gpfn))
pte |= VTLB_PTE_IO;
@@ -470,7 +478,7 @@ IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa)
-IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 ifa,UINT64 ps)
+IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,u64 ifa, u64 ps)
{
int index;
u64 va;
@@ -483,7 +491,7 @@ IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 ifa,UINT64 ps)
return IA64_NO_FAULT;
}
-IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 ifa,UINT64 ps)
+IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu, u64 ifa, u64 ps)
{
int index;
u64 va;
@@ -496,7 +504,7 @@ IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 ifa,UINT64 ps)
return IA64_NO_FAULT;
}
-IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 va, UINT64 ps)
+IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, u64 va, u64 ps)
{
va = PAGEALIGN(va, ps);
thash_purge_entries(vcpu, va, ps);
@@ -504,19 +512,19 @@ IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 va, UINT64 ps)
}
-IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 va)
+IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, u64 va)
{
thash_purge_all(vcpu);
return IA64_NO_FAULT;
}
-IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 va, UINT64 ps)
+IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, u64 va, u64 ps)
{
vmx_vcpu_ptc_ga(vcpu, va, ps);
return IA64_ILLOP_FAULT;
}
/*
-IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps)
+IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps)
{
vmx_vcpu_ptc_l(vcpu, va, ps);
return IA64_NO_FAULT;
@@ -554,7 +562,7 @@ static void ptc_ga_remote_func (void *varg)
}
-IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps)
+IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps)
{
struct domain *d = vcpu->domain;
@@ -588,7 +596,7 @@ IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps)
}
-IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
+IA64FAULT vmx_vcpu_thash(VCPU *vcpu, u64 vadr, u64 *pval)
{
PTA vpta;
ia64_rr vrr;
@@ -608,7 +616,7 @@ IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
}
-IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
+IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, u64 vadr, u64 *pval)
{
ia64_rr vrr;
PTA vpta;
@@ -624,12 +632,12 @@ IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
-IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, u64 vadr, u64 *padr)
{
thash_data_t *data;
ISR visr,pt_isr;
REGS *regs;
- u64 vhpt_adr;
+ u64 vhpt_adr, madr;
IA64_PSR vpsr;
regs=vcpu_regs(vcpu);
pt_isr.val=VMX(vcpu,cr_isr);
@@ -637,42 +645,37 @@ IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
visr.ei=pt_isr.ei;
visr.ir=pt_isr.ir;
vpsr.val = VCPU(vcpu, vpsr);
- if(vpsr.ic==0){
- visr.ni=1;
- }
visr.na=1;
data = vtlb_lookup(vcpu, vadr, DSIDE_TLB);
if(data){
if(data->p==0){
- visr.na=1;
vcpu_set_isr(vcpu,visr.val);
- page_not_present(vcpu, vadr);
+ data_page_not_present(vcpu, vadr);
return IA64_FAULT;
}else if(data->ma == VA_MATTR_NATPAGE){
- visr.na = 1;
vcpu_set_isr(vcpu, visr.val);
dnat_page_consumption(vcpu, vadr);
return IA64_FAULT;
}else{
*padr = ((data->ppn >> (data->ps - 12)) << data->ps) |
- (vadr & (PSIZE(data->ps) - 1));
+ (vadr & (PSIZE(data->ps) - 1));
return IA64_NO_FAULT;
}
}
data = vhpt_lookup(vadr);
if(data){
if(data->p==0){
- visr.na=1;
vcpu_set_isr(vcpu,visr.val);
- page_not_present(vcpu, vadr);
+ data_page_not_present(vcpu, vadr);
return IA64_FAULT;
}else if(data->ma == VA_MATTR_NATPAGE){
- visr.na = 1;
vcpu_set_isr(vcpu, visr.val);
dnat_page_consumption(vcpu, vadr);
return IA64_FAULT;
}else{
- *padr = (get_gpfn_from_mfn(arch_to_xen_ppn(data->ppn)) << PAGE_SHIFT) | (vadr & (PAGE_SIZE - 1));
+ madr = (data->ppn >> (data->ps - 12) << data->ps) |
+ (vadr & (PSIZE(data->ps) - 1));
+ *padr = __mpa_to_gpa(madr);
return IA64_NO_FAULT;
}
}
@@ -717,7 +720,7 @@ IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
}
}
-IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
+IA64FAULT vmx_vcpu_tak(VCPU *vcpu, u64 vadr, u64 *key)
{
thash_data_t *data;
PTA vpta;
@@ -734,52 +737,3 @@ IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
}
return IA64_NO_FAULT;
}
-
-/*
- * [FIXME] Is there any effective way to move this routine
- * into vmx_uaccess.h? struct exec_domain is incomplete type
- * in that way...
- *
- * This is the interface to lookup virtual TLB, and then
- * return corresponding machine address in 2nd parameter.
- * The 3rd parameter contains how many bytes mapped by
- * matched vTLB entry, thus to allow caller copy more once.
- *
- * If failed to lookup, -EFAULT is returned. Or else reutrn
- * 0. All upper domain access utilities rely on this routine
- * to determine the real machine address.
- *
- * Yes, put_user and get_user seems to somhow slow upon it.
- * However it's the necessary steps for any vmx domain virtual
- * address, since that's difference address space as HV's one.
- * Later some short-circuit may be created for special case
- */
-long
-__domain_va_to_ma(unsigned long va, unsigned long* ma, unsigned long *len)
-{
- unsigned long mpfn, gpfn, m, n = *len;
- unsigned long end; /* end of the area mapped by current entry */
- thash_data_t *entry;
- struct vcpu *v = current;
-
- entry = vtlb_lookup(v, va, DSIDE_TLB);
- if (entry == NULL)
- return -EFAULT;
-
- gpfn =(entry->ppn>>(PAGE_SHIFT-12));
- gpfn =PAGEALIGN(gpfn,(entry->ps-PAGE_SHIFT));
- gpfn = gpfn | POFFSET(va>>PAGE_SHIFT,(entry->ps-PAGE_SHIFT));
-
- mpfn = gmfn_to_mfn(v->domain, gpfn);
- m = (mpfn<<PAGE_SHIFT) | (va & (PAGE_SIZE - 1));
- /* machine address may be not continuous */
- end = PAGEALIGN(m, PAGE_SHIFT) + PAGE_SIZE;
- /*end = PAGEALIGN(m, entry->ps) + PSIZE(entry->ps);*/
- /* Current entry can't map all requested area */
- if ((m + n) > end)
- n = end - m;
-
- *ma = m;
- *len = n;
- return 0;
-}
diff --git a/xen/arch/ia64/vmx/vmx_entry.S b/xen/arch/ia64/vmx/vmx_entry.S
index 53b00d9019..fa2a53670f 100644
--- a/xen/arch/ia64/vmx/vmx_entry.S
+++ b/xen/arch/ia64/vmx/vmx_entry.S
@@ -669,7 +669,7 @@ GLOBAL_ENTRY(vmx_switch_rr7)
// re-pin mappings for guest_vhpt
- mov r24=IA64_TR_PERVP_VHPT
+ mov r24=IA64_TR_VHPT
movl r25=PAGE_KERNEL
;;
or loc5 = r25,loc5 // construct PA | page properties
diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c
index bc3c6e7cab..dcb571e042 100644
--- a/xen/arch/ia64/vmx/vmx_hypercall.c
+++ b/xen/arch/ia64/vmx/vmx_hypercall.c
@@ -34,6 +34,7 @@
#include <public/version.h>
#include <asm/dom_fw.h>
#include <xen/domain.h>
+#include <asm/vmx.h>
long
do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
@@ -78,8 +79,33 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
break;
}
+ case HVMOP_set_irq_level:
+ {
+ struct xen_hvm_set_irq_level op;
+ struct domain *d;
+
+ if (copy_from_guest(&op, arg, 1))
+ return -EFAULT;
+
+ if (!IS_PRIV(current->domain))
+ return -EPERM;
+
+ d = find_domain_by_id(op.domid);
+ if (d == NULL)
+ return -ESRCH;
+
+ rc = -EINVAL;
+ if (is_hvm_domain(d)) {
+ vmx_vioapic_set_irq(d, op.irq, op.level);
+ rc = 0;
+ }
+
+ put_domain(d);
+ break;
+ }
+
default:
- DPRINTK("Bad HVM op %ld.\n", op);
+ gdprintk(XENLOG_INFO, "Bad HVM op %ld.\n", op);
rc = -ENOSYS;
}
return rc;
diff --git a/xen/arch/ia64/vmx/vmx_init.c b/xen/arch/ia64/vmx/vmx_init.c
index df1bc94de0..03b7af7b9c 100644
--- a/xen/arch/ia64/vmx/vmx_init.c
+++ b/xen/arch/ia64/vmx/vmx_init.c
@@ -183,7 +183,6 @@ static vpd_t *alloc_vpd(void)
mregs->vac.a_cover = 1;
mregs->vac.a_bsw = 1;
mregs->vac.a_int = 1;
-
mregs->vdc.d_vmsw = 1;
return vpd;
@@ -276,9 +275,9 @@ static void vmx_create_event_channels(struct vcpu *v)
for_each_vcpu(v->domain, o) {
p = get_vio(v->domain, o->vcpu_id);
o->arch.arch_vmx.xen_port = p->vp_eport =
- alloc_unbound_xen_event_channel(o, 0);
- DPRINTK("Allocated port %d for hvm.\n",
- o->arch.arch_vmx.xen_port);
+ alloc_unbound_xen_event_channel(o, 0);
+ gdprintk(XENLOG_INFO, "Allocated port %ld for hvm.\n",
+ o->arch.arch_vmx.xen_port);
}
}
}
@@ -306,8 +305,8 @@ vmx_final_setup_guest(struct vcpu *v)
/* Per-domain vTLB and vhpt implementation. Now vmx domain will stick
* to this solution. Maybe it can be deferred until we know created
* one as vmx domain */
-#ifndef HASH_VHPT
- init_domain_tlb(v);
+#ifndef HASH_VHPT
+ init_domain_tlb(v);
#endif
vmx_create_event_channels(v);
@@ -322,8 +321,6 @@ vmx_final_setup_guest(struct vcpu *v)
vlsapic_reset(v);
vtm_init(v);
- /* One more step to enable interrupt assist */
- set_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags);
/* Set up guest 's indicator for VTi domain*/
set_bit(ARCH_VMX_DOMAIN, &v->arch.arch_vmx.flags);
}
@@ -362,56 +359,58 @@ static const io_range_t io_ranges[] = {
{PIB_START, PIB_SIZE, GPFN_PIB},
};
-/* Reseve 1 page for shared I/O and 1 page for xenstore. */
-#define VMX_SYS_PAGES (2 + (GFW_SIZE >> PAGE_SHIFT))
-#define VMX_CONFIG_PAGES(d) ((d)->max_pages - VMX_SYS_PAGES)
+/* Reseve 1 page for shared I/O ,1 page for xenstore and 1 page for buffer I/O. */
+#define VMX_SYS_PAGES (3 + (GFW_SIZE >> PAGE_SHIFT))
+/* If we support maxmem for domVTi, we should change from tot_page to max_pages.
+ * #define VMX_CONFIG_PAGES(d) ((d)->max_pages - VMX_SYS_PAGES)
+ */
+#define VMX_CONFIG_PAGES(d) ((d)->tot_pages - VMX_SYS_PAGES)
static void vmx_build_physmap_table(struct domain *d)
{
unsigned long i, j, start, tmp, end, mfn;
struct list_head *list_ent = d->page_list.next;
- ASSERT(d->max_pages == d->tot_pages);
-
/* Mark I/O ranges */
for (i = 0; i < (sizeof(io_ranges) / sizeof(io_range_t)); i++) {
- for (j = io_ranges[i].start;
- j < io_ranges[i].start + io_ranges[i].size;
- j += PAGE_SIZE)
- __assign_domain_page(d, j, io_ranges[i].type, ASSIGN_writable);
+ for (j = io_ranges[i].start;
+ j < io_ranges[i].start + io_ranges[i].size; j += PAGE_SIZE)
+ (void)__assign_domain_page(d, j, io_ranges[i].type,
+ ASSIGN_writable);
}
/* Map normal memory below 3G */
end = VMX_CONFIG_PAGES(d) << PAGE_SHIFT;
tmp = end < MMIO_START ? end : MMIO_START;
for (i = 0; (i < tmp) && (list_ent != &d->page_list); i += PAGE_SIZE) {
- mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
- list_ent = mfn_to_page(mfn)->list.next;
- if (VGA_IO_START <= i && i < VGA_IO_START + VGA_IO_SIZE)
- continue;
- assign_domain_page(d, i, mfn << PAGE_SHIFT);
+ mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
+ list_ent = mfn_to_page(mfn)->list.next;
+ if (VGA_IO_START <= i && i < VGA_IO_START + VGA_IO_SIZE)
+ continue;
+ assign_domain_page(d, i, mfn << PAGE_SHIFT);
}
ASSERT(list_ent != &d->page_list);
/* Map normal memory beyond 4G */
if (unlikely(end > MMIO_START)) {
- start = 4 * MEM_G;
- end = start + (end - 3 * MEM_G);
- for (i = start;
- (i < end) && (list_ent != &d->page_list); i += PAGE_SIZE) {
- mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
- assign_domain_page(d, i, mfn << PAGE_SHIFT);
- list_ent = mfn_to_page(mfn)->list.next;
- }
- ASSERT(list_ent != &d->page_list);
+ start = 4 * MEM_G;
+ end = start + (end - 3 * MEM_G);
+ for (i = start;
+ (i < end) && (list_ent != &d->page_list); i += PAGE_SIZE) {
+ mfn = page_to_mfn(list_entry(list_ent,
+ struct page_info, list));
+ assign_domain_page(d, i, mfn << PAGE_SHIFT);
+ list_ent = mfn_to_page(mfn)->list.next;
+ }
+ ASSERT(list_ent != &d->page_list);
}
/* Map guest firmware */
for (i = GFW_START; (i < GFW_START + GFW_SIZE) &&
- (list_ent != &d->page_list); i += PAGE_SIZE) {
- mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
- assign_domain_page(d, i, mfn << PAGE_SHIFT);
- list_ent = mfn_to_page(mfn)->list.next;
+ (list_ent != &d->page_list); i += PAGE_SIZE) {
+ mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
+ assign_domain_page(d, i, mfn << PAGE_SHIFT);
+ list_ent = mfn_to_page(mfn)->list.next;
}
ASSERT(list_ent != &d->page_list);
@@ -424,8 +423,12 @@ static void vmx_build_physmap_table(struct domain *d)
mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
assign_domain_page(d, STORE_PAGE_START, mfn << PAGE_SHIFT);
list_ent = mfn_to_page(mfn)->list.next;
- ASSERT(list_ent == &d->page_list);
+ ASSERT(list_ent != &d->page_list);
+ mfn = page_to_mfn(list_entry(list_ent, struct page_info, list));
+ assign_domain_page(d, BUFFER_IO_PAGE_START, mfn << PAGE_SHIFT);
+ list_ent = mfn_to_page(mfn)->list.next;
+ ASSERT(list_ent == &d->page_list);
}
void vmx_setup_platform(struct domain *d)
@@ -436,6 +439,10 @@ void vmx_setup_platform(struct domain *d)
d->arch.vmx_platform.shared_page_va =
(unsigned long)__va(__gpa_to_mpa(d, IO_PAGE_START));
+ /* For buffered IO requests. */
+ spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
+ d->arch.hvm_domain.buffered_io_va =
+ (unsigned long)__va(__gpa_to_mpa(d, BUFFER_IO_PAGE_START));
/* TEMP */
d->arch.vmx_platform.pib_base = 0xfee00000UL;
@@ -443,16 +450,13 @@ void vmx_setup_platform(struct domain *d)
/* Only open one port for I/O and interrupt emulation */
memset(&d->shared_info->evtchn_mask[0], 0xff,
- sizeof(d->shared_info->evtchn_mask));
+ sizeof(d->shared_info->evtchn_mask));
/* initiate spinlock for pass virq */
spin_lock_init(&d->arch.arch_vmx.virq_assist_lock);
- /* Initialize the virtual interrupt lines */
- vmx_virq_line_init(d);
-
/* Initialize iosapic model within hypervisor */
- hvm_vioapic_init(d);
+ vioapic_init(d);
}
void vmx_do_launch(struct vcpu *v)
diff --git a/xen/arch/ia64/vmx/vmx_interrupt.c b/xen/arch/ia64/vmx/vmx_interrupt.c
index c1f6392c41..211aa93b36 100644
--- a/xen/arch/ia64/vmx/vmx_interrupt.c
+++ b/xen/arch/ia64/vmx/vmx_interrupt.c
@@ -383,14 +383,29 @@ dnat_page_consumption (VCPU *vcpu, uint64_t vadr)
/* Deal with
* Page not present vector
*/
-void
-page_not_present(VCPU *vcpu, u64 vadr)
+static void
+__page_not_present(VCPU *vcpu, u64 vadr)
{
/* If vPSR.ic, IFA, ITIR */
set_ifa_itir_iha (vcpu, vadr, 1, 1, 0);
inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR);
}
+
+void
+data_page_not_present(VCPU *vcpu, u64 vadr)
+{
+ __page_not_present(vcpu, vadr);
+}
+
+
+void
+inst_page_not_present(VCPU *vcpu, u64 vadr)
+{
+ __page_not_present(vcpu, vadr);
+}
+
+
/* Deal with
* Data access rights vector
*/
diff --git a/xen/arch/ia64/vmx/vmx_ivt.S b/xen/arch/ia64/vmx/vmx_ivt.S
index 876c942165..755539c09c 100644
--- a/xen/arch/ia64/vmx/vmx_ivt.S
+++ b/xen/arch/ia64/vmx/vmx_ivt.S
@@ -95,6 +95,7 @@
#define VMX_FAULT(n) \
vmx_fault_##n:; \
+ mov r19=n;; \
br.sptk.many dispatch_to_fault_handler; \
;; \
@@ -106,7 +107,7 @@ vmx_fault_##n:; \
;; \
tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \
(p7)br.sptk.many vmx_dispatch_reflection; \
- VMX_FAULT(n); \
+ br.sptk.many dispatch_to_fault_handler; \
GLOBAL_ENTRY(vmx_panic)
@@ -172,13 +173,17 @@ vmx_itlb_loop:
ld8 r27 = [r18]
ld8 r29 = [r28]
;;
- st8 [r16] = r29
- st8 [r28] = r22
+ st8 [r16] = r29, VLE_ITIR_OFFSET - VLE_TITAG_OFFSET
+ st8 [r28] = r22, VLE_ITIR_OFFSET - VLE_TITAG_OFFSET
extr.u r19 = r27, 56, 4
;;
+ ld8 r29 = [r16]
+ ld8 r22 = [r28]
dep r27 = r0, r27, 56, 4
dep r25 = r19, r25, 56, 4
;;
+ st8 [r16] = r22
+ st8 [r28] = r29
st8 [r18] = r25
st8 [r17] = r27
;;
@@ -246,13 +251,17 @@ vmx_dtlb_loop:
ld8 r27 = [r18]
ld8 r29 = [r28]
;;
- st8 [r16] = r29
- st8 [r28] = r22
+ st8 [r16] = r29, VLE_ITIR_OFFSET - VLE_TITAG_OFFSET
+ st8 [r28] = r22, VLE_ITIR_OFFSET - VLE_TITAG_OFFSET
extr.u r19 = r27, 56, 4
;;
+ ld8 r29 = [r16]
+ ld8 r22 = [r28]
dep r27 = r0, r27, 56, 4
dep r25 = r19, r25, 56, 4
;;
+ st8 [r16] = r22
+ st8 [r28] = r29
st8 [r18] = r25
st8 [r17] = r27
;;
@@ -772,12 +781,28 @@ ENTRY(vmx_single_step_trap)
VMX_REFLECT(36)
END(vmx_single_step_trap)
+ .global vmx_virtualization_fault_back
.org vmx_ia64_ivt+0x6100
/////////////////////////////////////////////////////////////////////////////////////////
// 0x6100 Entry 37 (size 16 bundles) Virtualization Fault
ENTRY(vmx_virtualization_fault)
// VMX_DBG_FAULT(37)
mov r31=pr
+ ;;
+ cmp.eq p6,p0=EVENT_MOV_FROM_AR,r24
+ cmp.eq p7,p0=EVENT_MOV_FROM_RR,r24
+ cmp.eq p8,p0=EVENT_MOV_TO_RR,r24
+ cmp.eq p9,p0=EVENT_RSM,r24
+ cmp.eq p10,p0=EVENT_SSM,r24
+ cmp.eq p11,p0=EVENT_MOV_TO_PSR,r24
+ (p6) br.dptk.many vmx_asm_mov_from_ar
+ (p7) br.dptk.many vmx_asm_mov_from_rr
+ (p8) br.dptk.many vmx_asm_mov_to_rr
+ (p9) br.dptk.many vmx_asm_rsm
+ (p10) br.dptk.many vmx_asm_ssm
+ (p11) br.dptk.many vmx_asm_mov_to_psr
+ ;;
+vmx_virtualization_fault_back:
mov r19=37
adds r16 = IA64_VCPU_CAUSE_OFFSET,r21
adds r17 = IA64_VCPU_OPCODE_OFFSET,r21
@@ -1049,7 +1074,7 @@ ENTRY(vmx_dispatch_virtualization_fault)
END(vmx_dispatch_virtualization_fault)
-ENTRY(vmx_dispatch_vexirq)
+GLOBAL_ENTRY(vmx_dispatch_vexirq)
VMX_SAVE_MIN_WITH_COVER_R19
alloc r14=ar.pfs,0,0,1,0
mov out0=r13
diff --git a/xen/arch/ia64/vmx/vmx_phy_mode.c b/xen/arch/ia64/vmx/vmx_phy_mode.c
index 8745721d54..ce4fd9036c 100644
--- a/xen/arch/ia64/vmx/vmx_phy_mode.c
+++ b/xen/arch/ia64/vmx/vmx_phy_mode.c
@@ -100,24 +100,20 @@ int mm_switch_table[8][8] = {
void
physical_mode_init(VCPU *vcpu)
{
- vcpu->arch.old_rsc = 0;
vcpu->arch.mode_flags = GUEST_IN_PHY;
}
extern void vmx_switch_rr7(unsigned long ,shared_info_t*,void *,void *,void *);
void
-physical_tlb_miss(VCPU *vcpu, u64 vadr)
+physical_tlb_miss(VCPU *vcpu, u64 vadr, int type)
{
u64 pte;
ia64_rr rr;
rr.rrval = ia64_get_rr(vadr);
pte = vadr& _PAGE_PPN_MASK;
- if (vadr >> 63)
- pte = pte | PHY_PAGE_UC;
- else
- pte = pte | PHY_PAGE_WB;
- thash_vhpt_insert(vcpu, pte, (rr.ps << 2), vadr);
+ pte = pte | PHY_PAGE_WB;
+ thash_vhpt_insert(vcpu, pte, (rr.ps << 2), vadr, type);
return;
}
@@ -126,10 +122,16 @@ void
vmx_init_all_rr(VCPU *vcpu)
{
VMX(vcpu, vrr[VRN0]) = 0x38;
+ // enable vhpt in guest physical mode
+ vcpu->arch.metaphysical_rr0 |= 1;
+ vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(vcpu, 0x38);
VMX(vcpu, vrr[VRN1]) = 0x38;
VMX(vcpu, vrr[VRN2]) = 0x38;
VMX(vcpu, vrr[VRN3]) = 0x38;
VMX(vcpu, vrr[VRN4]) = 0x38;
+ // enable vhpt in guest physical mode
+ vcpu->arch.metaphysical_rr4 |= 1;
+ vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(vcpu, 0x38);
VMX(vcpu, vrr[VRN5]) = 0x38;
VMX(vcpu, vrr[VRN6]) = 0x38;
VMX(vcpu, vrr[VRN7]) = 0x738;
@@ -141,11 +143,9 @@ void
vmx_load_all_rr(VCPU *vcpu)
{
unsigned long psr;
- ia64_rr phy_rr;
local_irq_save(psr);
-
/* WARNING: not allow co-exist of both virtual mode and physical
* mode in same region
*/
@@ -154,24 +154,16 @@ vmx_load_all_rr(VCPU *vcpu)
panic_domain(vcpu_regs(vcpu),
"Unexpected domain switch in phy emul\n");
}
- phy_rr.rrval = vcpu->arch.metaphysical_rr0;
- //phy_rr.ps = PAGE_SHIFT;
- phy_rr.ve = 1;
-
- ia64_set_rr((VRN0 << VRN_SHIFT), phy_rr.rrval);
+ ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->arch.metaphysical_rr0);
ia64_dv_serialize_data();
- phy_rr.rrval = vcpu->arch.metaphysical_rr4;
- //phy_rr.ps = PAGE_SHIFT;
- phy_rr.ve = 1;
-
- ia64_set_rr((VRN4 << VRN_SHIFT), phy_rr.rrval);
+ ia64_set_rr((VRN4 << VRN_SHIFT), vcpu->arch.metaphysical_rr4);
ia64_dv_serialize_data();
} else {
ia64_set_rr((VRN0 << VRN_SHIFT),
- vrrtomrr(vcpu, VMX(vcpu, vrr[VRN0])));
+ vcpu->arch.metaphysical_saved_rr0);
ia64_dv_serialize_data();
ia64_set_rr((VRN4 << VRN_SHIFT),
- vrrtomrr(vcpu, VMX(vcpu, vrr[VRN4])));
+ vcpu->arch.metaphysical_saved_rr4);
ia64_dv_serialize_data();
}
@@ -208,22 +200,12 @@ vmx_load_all_rr(VCPU *vcpu)
void
switch_to_physical_rid(VCPU *vcpu)
{
- UINT64 psr;
- ia64_rr phy_rr, mrr;
-
+ u64 psr;
/* Save original virtual mode rr[0] and rr[4] */
psr=ia64_clear_ic();
- phy_rr.rrval = vcpu->domain->arch.metaphysical_rr0;
- mrr.rrval = ia64_get_rr(VRN0 << VRN_SHIFT);
- phy_rr.ps = mrr.ps;
- phy_rr.ve = 1;
- ia64_set_rr(VRN0<<VRN_SHIFT, phy_rr.rrval);
+ ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_rr0);
ia64_srlz_d();
- phy_rr.rrval = vcpu->domain->arch.metaphysical_rr4;
- mrr.rrval = ia64_get_rr(VRN4 << VRN_SHIFT);
- phy_rr.ps = mrr.ps;
- phy_rr.ve = 1;
- ia64_set_rr(VRN4<<VRN_SHIFT, phy_rr.rrval);
+ ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_rr4);
ia64_srlz_d();
ia64_set_psr(psr);
@@ -235,16 +217,11 @@ switch_to_physical_rid(VCPU *vcpu)
void
switch_to_virtual_rid(VCPU *vcpu)
{
- UINT64 psr;
- ia64_rr mrr;
-
+ u64 psr;
psr=ia64_clear_ic();
-
- vcpu_get_rr(vcpu,VRN0<<VRN_SHIFT,&mrr.rrval);
- ia64_set_rr(VRN0<<VRN_SHIFT, vrrtomrr(vcpu, mrr.rrval));
+ ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0);
ia64_srlz_d();
- vcpu_get_rr(vcpu,VRN4<<VRN_SHIFT,&mrr.rrval);
- ia64_set_rr(VRN4<<VRN_SHIFT, vrrtomrr(vcpu, mrr.rrval));
+ ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4);
ia64_srlz_d();
ia64_set_psr(psr);
ia64_srlz_i();
@@ -260,39 +237,35 @@ void
switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr)
{
int act;
- REGS * regs=vcpu_regs(vcpu);
act = mm_switch_action(old_psr, new_psr);
perfc_incra(vmx_switch_mm_mode, act);
switch (act) {
case SW_V2P:
-// printf("V -> P mode transition: (0x%lx -> 0x%lx)\n",
+// printk("V -> P mode transition: (0x%lx -> 0x%lx)\n",
// old_psr.val, new_psr.val);
- vcpu->arch.old_rsc = regs->ar_rsc;
switch_to_physical_rid(vcpu);
/*
* Set rse to enforced lazy, to prevent active rse save/restor when
* guest physical mode.
*/
- regs->ar_rsc &= ~(IA64_RSC_MODE);
vcpu->arch.mode_flags |= GUEST_IN_PHY;
break;
case SW_P2V:
-// printf("P -> V mode transition: (0x%lx -> 0x%lx)\n",
+// printk("P -> V mode transition: (0x%lx -> 0x%lx)\n",
// old_psr.val, new_psr.val);
switch_to_virtual_rid(vcpu);
/*
* recover old mode which is saved when entering
* guest physical mode
*/
- regs->ar_rsc = vcpu->arch.old_rsc;
vcpu->arch.mode_flags &= ~GUEST_IN_PHY;
break;
case SW_SELF:
- printf("Switch to self-0x%lx!!! MM mode doesn't change...\n",
+ printk("Switch to self-0x%lx!!! MM mode doesn't change...\n",
old_psr.val);
break;
case SW_NOP:
-// printf("No action required for mode transition: (0x%lx -> 0x%lx)\n",
+// printk("No action required for mode transition: (0x%lx -> 0x%lx)\n",
// old_psr.val, new_psr.val);
break;
default:
@@ -366,10 +339,9 @@ prepare_if_physical_mode(VCPU *vcpu)
void
recover_if_physical_mode(VCPU *vcpu)
{
- if (is_physical_mode(vcpu)) {
- vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL;
+ if (is_physical_mode(vcpu))
switch_to_physical_rid(vcpu);
- }
+ vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL;
return;
}
diff --git a/xen/arch/ia64/vmx/vmx_process.c b/xen/arch/ia64/vmx/vmx_process.c
index 7867fd3993..3526175cbd 100644
--- a/xen/arch/ia64/vmx/vmx_process.c
+++ b/xen/arch/ia64/vmx/vmx_process.c
@@ -66,7 +66,7 @@ extern unsigned long handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigne
#define DOMN_PAL_REQUEST 0x110000
#define DOMN_SAL_REQUEST 0x110001
-static UINT64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000, 0x1400,0x1800,
+static u64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000,0x1400,0x1800,
0x1c00,0x2000,0x2400,0x2800,0x2c00,0x3000,0x3400,0x3800,0x3c00,0x4000,
0x4400,0x4800,0x4c00,0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,
0x5700,0x5800,0x5900,0x5a00,0x5b00,0x5c00,0x5d00,0x5e00,0x5f00,0x6000,
@@ -78,24 +78,35 @@ static UINT64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000, 0x1400,0x1800,
-void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim,
- UINT64 vector,REGS *regs)
+void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim,
+ u64 vector, REGS *regs)
{
+ u64 status;
VCPU *vcpu = current;
- UINT64 vpsr = VCPU(vcpu, vpsr);
+ u64 vpsr = VCPU(vcpu, vpsr);
vector=vec2off[vector];
if(!(vpsr&IA64_PSR_IC)&&(vector!=IA64_DATA_NESTED_TLB_VECTOR)){
panic_domain(regs, "Guest nested fault vector=%lx!\n", vector);
}
else{ // handle fpswa emulation
// fp fault
- if(vector == IA64_FP_FAULT_VECTOR && !handle_fpu_swa(1, regs, isr)){
- vmx_vcpu_increment_iip(vcpu);
- return;
+ if (vector == IA64_FP_FAULT_VECTOR) {
+ status = handle_fpu_swa(1, regs, isr);
+ if (!status) {
+ vmx_vcpu_increment_iip(vcpu);
+ return;
+ } else if (IA64_RETRY == status)
+ return;
}
//fp trap
- else if(vector == IA64_FP_TRAP_VECTOR && !handle_fpu_swa(0, regs, isr)){
- return;
+ else if (vector == IA64_FP_TRAP_VECTOR) {
+ status = handle_fpu_swa(0, regs, isr);
+ if (!status)
+ return;
+ else if (IA64_RETRY == status) {
+ vmx_vcpu_decrement_iip(vcpu);
+ return;
+ }
}
}
VCPU(vcpu,isr)=isr;
@@ -187,7 +198,7 @@ void leave_hypervisor_tail(struct pt_regs *regs)
{
struct domain *d = current->domain;
struct vcpu *v = current;
- int callback_irq;
+
// FIXME: Will this work properly if doing an RFI???
if (!is_idle_domain(d) ) { // always comes from guest
// struct pt_regs *user_regs = vcpu_regs(current);
@@ -198,10 +209,6 @@ void leave_hypervisor_tail(struct pt_regs *regs)
// if (user_regs != regs)
// printk("WARNING: checking pending interrupt in nested interrupt!!!\n");
- /* VMX Domain N has other interrupt source, saying DM */
- if (test_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags))
- vmx_intr_assist(v);
-
/* FIXME: Check event pending indicator, and set
* pending bit if necessary to inject back to guest.
* Should be careful about window between this check
@@ -215,11 +222,14 @@ void leave_hypervisor_tail(struct pt_regs *regs)
// v->arch.irq_new_pending = 1;
// }
- callback_irq = d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
- if (callback_irq != 0 && local_events_need_delivery()) {
- /*inject para-device call back irq*/
- v->vcpu_info->evtchn_upcall_mask = 1;
- vmx_vcpu_pend_interrupt(v, callback_irq);
+ if (v->vcpu_id == 0) {
+ int callback_irq =
+ d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
+ if (callback_irq != 0 && local_events_need_delivery()) {
+ /*inject para-device call back irq*/
+ v->vcpu_info->evtchn_upcall_mask = 1;
+ vmx_vcpu_pend_interrupt(v, callback_irq);
+ }
}
if ( v->arch.irq_new_pending ) {
@@ -228,10 +238,7 @@ void leave_hypervisor_tail(struct pt_regs *regs)
vmx_check_pending_irq(v);
return;
}
- if (VCPU(v, vac).a_int) {
- vhpi_detection(v);
- return;
- }
+
if (v->arch.irq_new_condition) {
v->arch.irq_new_condition = 0;
vhpi_detection(v);
@@ -239,7 +246,7 @@ void leave_hypervisor_tail(struct pt_regs *regs)
}
}
-extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr);
+extern ia64_rr vmx_vcpu_rr(VCPU *vcpu, u64 vadr);
static int vmx_handle_lds(REGS* regs)
{
@@ -252,34 +259,34 @@ IA64FAULT
vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs)
{
IA64_PSR vpsr;
- int type=ISIDE_TLB;
+ int type;
u64 vhpt_adr, gppa, pteval, rr, itir;
ISR misr;
-// REGS *regs;
+ PTA vpta;
thash_data_t *data;
VCPU *v = current;
-#ifdef VTLB_DEBUG
- check_vtlb_sanity(vtlb);
- dump_vtlb(vtlb);
-#endif
+
vpsr.val = VCPU(v, vpsr);
- misr.val=VMX(v,cr_isr);
+ misr.val = VMX(v,cr_isr);
+
+ if (vec == 1)
+ type = ISIDE_TLB;
+ else if (vec == 2)
+ type = DSIDE_TLB;
+ else
+ panic_domain(regs, "wrong vec:%lx\n", vec);
if(is_physical_mode(v)&&(!(vadr<<1>>62))){
if(vec==2){
- if(v->domain!=dom0&&__gpfn_is_io(v->domain,(vadr<<1)>>(PAGE_SHIFT+1))){
+ if (v->domain != dom0
+ && __gpfn_is_io(v->domain, (vadr << 1) >> (PAGE_SHIFT + 1))) {
emulate_io_inst(v,((vadr<<1)>>1),4); // UC
return IA64_FAULT;
}
}
- physical_tlb_miss(v, vadr);
+ physical_tlb_miss(v, vadr, type);
return IA64_FAULT;
}
- if(vec == 1) type = ISIDE_TLB;
- else if(vec == 2) type = DSIDE_TLB;
- else panic_domain(regs,"wrong vec:%lx\n",vec);
-
-// prepare_if_physical_mode(v);
if((data=vtlb_lookup(v, vadr,type))!=0){
if (v->domain != dom0 && type == DSIDE_TLB) {
@@ -295,98 +302,109 @@ vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs)
return IA64_FAULT;
}
}
- thash_vhpt_insert(v,data->page_flags, data->itir ,vadr);
+ thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type);
}else if(type == DSIDE_TLB){
+
if (misr.sp)
return vmx_handle_lds(regs);
+
if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){
if(vpsr.ic){
vcpu_set_isr(v, misr.val);
alt_dtlb(v, vadr);
return IA64_FAULT;
} else{
- if(misr.sp){
- //TODO lds emulation
- //panic("Don't support speculation load");
- return vmx_handle_lds(regs);
- }else{
- nested_dtlb(v);
- return IA64_FAULT;
- }
+ nested_dtlb(v);
+ return IA64_FAULT;
}
- } else{
- vmx_vcpu_thash(v, vadr, &vhpt_adr);
- if(!guest_vhpt_lookup(vhpt_adr, &pteval)){
- if ((pteval & _PAGE_P) &&
- ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST)) {
- vcpu_get_rr(v, vadr, &rr);
- itir = rr&(RR_RID_MASK | RR_PS_MASK);
- thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB);
- return IA64_NO_FAULT;
- }
- if(vpsr.ic){
+ }
+
+ vmx_vcpu_get_pta(v, &vpta.val);
+ if (vpta.vf) {
+ /* Long format is not yet supported. */
+ if (vpsr.ic) {
+ vcpu_set_isr(v, misr.val);
+ dtlb_fault(v, vadr);
+ return IA64_FAULT;
+ } else {
+ nested_dtlb(v);
+ return IA64_FAULT;
+ }
+ }
+
+ vmx_vcpu_thash(v, vadr, &vhpt_adr);
+ if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
+ /* VHPT successfully read. */
+ if (!(pteval & _PAGE_P)) {
+ if (vpsr.ic) {
vcpu_set_isr(v, misr.val);
dtlb_fault(v, vadr);
return IA64_FAULT;
- }else{
- if(misr.sp){
- //TODO lds emulation
- //panic("Don't support speculation load");
- return vmx_handle_lds(regs);
- }else{
- nested_dtlb(v);
- return IA64_FAULT;
- }
- }
- }else{
- if(vpsr.ic){
- vcpu_set_isr(v, misr.val);
- dvhpt_fault(v, vadr);
+ } else {
+ nested_dtlb(v);
return IA64_FAULT;
- }else{
- if(misr.sp){
- //TODO lds emulation
- //panic("Don't support speculation load");
- return vmx_handle_lds(regs);
- }else{
- nested_dtlb(v);
- return IA64_FAULT;
- }
}
+ } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) {
+ vcpu_get_rr(v, vadr, &rr);
+ itir = rr & (RR_RID_MASK | RR_PS_MASK);
+ thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB);
+ return IA64_NO_FAULT;
+ } else if (vpsr.ic) {
+ vcpu_set_isr(v, misr.val);
+ dtlb_fault(v, vadr);
+ return IA64_FAULT;
+ }else{
+ nested_dtlb(v);
+ return IA64_FAULT;
+ }
+ } else {
+ /* Can't read VHPT. */
+ if (vpsr.ic) {
+ vcpu_set_isr(v, misr.val);
+ dvhpt_fault(v, vadr);
+ return IA64_FAULT;
+ } else {
+ nested_dtlb(v);
+ return IA64_FAULT;
}
}
}else if(type == ISIDE_TLB){
+
+ if (!vpsr.ic)
+ misr.ni = 1;
if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){
- if(!vpsr.ic){
- misr.ni=1;
- }
vcpu_set_isr(v, misr.val);
alt_itlb(v, vadr);
return IA64_FAULT;
- } else{
- vmx_vcpu_thash(v, vadr, &vhpt_adr);
- if(!guest_vhpt_lookup(vhpt_adr, &pteval)){
- if (pteval & _PAGE_P){
- vcpu_get_rr(v, vadr, &rr);
- itir = rr&(RR_RID_MASK | RR_PS_MASK);
- thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB);
- return IA64_NO_FAULT;
- }
- if(!vpsr.ic){
- misr.ni=1;
- }
- vcpu_set_isr(v, misr.val);
- itlb_fault(v, vadr);
- return IA64_FAULT;
- }else{
- if(!vpsr.ic){
- misr.ni=1;
- }
+ }
+
+ vmx_vcpu_get_pta(v, &vpta.val);
+ if (vpta.vf) {
+ /* Long format is not yet supported. */
+ vcpu_set_isr(v, misr.val);
+ itlb_fault(v, vadr);
+ return IA64_FAULT;
+ }
+
+
+ vmx_vcpu_thash(v, vadr, &vhpt_adr);
+ if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
+ /* VHPT successfully read. */
+ if (pteval & _PAGE_P) {
+ vcpu_get_rr(v, vadr, &rr);
+ itir = rr & (RR_RID_MASK | RR_PS_MASK);
+ thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB);
+ return IA64_NO_FAULT;
+ } else {
vcpu_set_isr(v, misr.val);
- ivhpt_fault(v, vadr);
+ inst_page_not_present(v, vadr);
return IA64_FAULT;
}
+ } else {
+ vcpu_set_isr(v, misr.val);
+ ivhpt_fault(v, vadr);
+ return IA64_FAULT;
}
}
return IA64_NO_FAULT;
diff --git a/xen/arch/ia64/vmx/vmx_support.c b/xen/arch/ia64/vmx/vmx_support.c
index 70b9dd7321..ea7e24afe8 100644
--- a/xen/arch/ia64/vmx/vmx_support.c
+++ b/xen/arch/ia64/vmx/vmx_support.c
@@ -49,7 +49,7 @@ void vmx_io_assist(struct vcpu *v)
p = &vio->vp_ioreq;
if (p->state == STATE_IORESP_READY) {
- p->state = STATE_INVALID;
+ p->state = STATE_IOREQ_NONE;
}
else {
/* Can't block here, for the same reason as other places to
@@ -60,33 +60,12 @@ void vmx_io_assist(struct vcpu *v)
}
}
-/*
- * VMX domainN has two types of interrupt source: lsapic model within
- * HV, and device model within domain 0 (service OS). There're another
- * pending array in share page, manipulated by device model directly.
- * To conform to VT-i spec, we have to sync pending bits in shared page
- * into VPD. This has to be done before checking pending interrupt at
- * resume to guest. For domain 0, all the interrupt sources come from
- * HV, which then doesn't require this assist.
- */
-void vmx_intr_assist(struct vcpu *v)
-{
-#ifdef V_IOSAPIC_READY
- /* Confirm virtual interrupt line signals, and set pending bits in vpd */
- if (spin_trylock(&v->domain->arch.arch_vmx.virq_assist_lock)) {
- vmx_virq_line_assist(v);
- spin_unlock(&v->domain->arch.arch_vmx.virq_assist_lock);
- }
-#endif
- return;
-}
-
void vmx_send_assist_req(struct vcpu *v)
{
ioreq_t *p;
p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
- if (unlikely(p->state != STATE_INVALID)) {
+ if (unlikely(p->state != STATE_IOREQ_NONE)) {
/* This indicates a bug in the device model. Crash the
domain. */
printk("Device model set bad IO state %d.\n", p->state);
@@ -116,8 +95,7 @@ void vmx_send_assist_req(struct vcpu *v)
break;
}
- /* I want to call __enter_scheduler() only */
- do_sched_op_compat(SCHEDOP_yield, 0);
+ raise_softirq(SCHEDULE_SOFTIRQ);
mb();
}
diff --git a/xen/arch/ia64/vmx/vmx_vcpu.c b/xen/arch/ia64/vmx/vmx_vcpu.c
index e6824d3ec9..322afe3542 100644
--- a/xen/arch/ia64/vmx/vmx_vcpu.c
+++ b/xen/arch/ia64/vmx/vmx_vcpu.c
@@ -82,7 +82,7 @@ void
vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value)
{
- UINT64 mask;
+ u64 mask;
REGS *regs;
IA64_PSR old_psr, new_psr;
old_psr.val=VCPU(vcpu, vpsr);
@@ -172,6 +172,21 @@ IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu)
}
+IA64FAULT vmx_vcpu_decrement_iip(VCPU *vcpu)
+{
+ REGS *regs = vcpu_regs(vcpu);
+ IA64_PSR *ipsr = (IA64_PSR *)&regs->cr_ipsr;
+
+ if (ipsr->ri == 0) {
+ ipsr->ri = 2;
+ regs->cr_iip -= 16;
+ } else {
+ ipsr->ri--;
+ }
+ return (IA64_NO_FAULT);
+}
+
+
IA64FAULT vmx_vcpu_cover(VCPU *vcpu)
{
REGS *regs = vcpu_regs(vcpu);
@@ -193,23 +208,36 @@ vmx_vcpu_get_plat(VCPU *vcpu)
-IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, u64 reg, u64 val)
{
ia64_rr oldrr,newrr;
extern void * pal_vaddr;
+ u64 rrval;
vcpu_get_rr(vcpu, reg, &oldrr.rrval);
newrr.rrval=val;
if (newrr.rid >= (1 << vcpu->domain->arch.rid_bits))
panic_domain (NULL, "use of invalid rid %x\n", newrr.rid);
- VMX(vcpu,vrr[reg>>61]) = val;
- switch((u64)(reg>>61)) {
+ VMX(vcpu,vrr[reg>>VRN_SHIFT]) = val;
+ switch((u64)(reg>>VRN_SHIFT)) {
case VRN7:
vmx_switch_rr7(vrrtomrr(vcpu,val),vcpu->domain->shared_info,
(void *)vcpu->arch.privregs,
(void *)vcpu->arch.vhpt.hash, pal_vaddr );
break;
+ case VRN4:
+ rrval = vrrtomrr(vcpu,val);
+ vcpu->arch.metaphysical_saved_rr4 = rrval;
+ if (!is_physical_mode(vcpu))
+ ia64_set_rr(reg,rrval);
+ break;
+ case VRN0:
+ rrval = vrrtomrr(vcpu,val);
+ vcpu->arch.metaphysical_saved_rr0 = rrval;
+ if (!is_physical_mode(vcpu))
+ ia64_set_rr(reg,rrval);
+ break;
default:
ia64_set_rr(reg,vrrtomrr(vcpu,val));
break;
@@ -224,14 +252,14 @@ IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val)
VCPU protection key register access routines
**************************************************************************/
-IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, u64 reg, u64 *pval)
{
- UINT64 val = (UINT64)ia64_get_pkr(reg);
+ u64 val = (u64)ia64_get_pkr(reg);
*pval = val;
return (IA64_NO_FAULT);
}
-IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, u64 reg, u64 val)
{
ia64_set_pkr(reg,val);
return (IA64_NO_FAULT);
@@ -246,7 +274,7 @@ check_entry(u64 va, u64 ps, char *str)
va == 0x600000000000C000UL ) {
stop();
}
- if (tlb_debug) printf("%s at %lx %lx\n", str, va, 1UL<<ps);
+ if (tlb_debug) printk("%s at %lx %lx\n", str, va, 1UL<<ps);
}
#endif
@@ -267,7 +295,7 @@ u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa)
IA64FAULT vmx_vcpu_rfi(VCPU *vcpu)
{
// TODO: Only allowed for current vcpu
- UINT64 ifs, psr;
+ u64 ifs, psr;
REGS *regs = vcpu_regs(vcpu);
psr = VCPU(vcpu,ipsr);
if (psr & IA64_PSR_BN)
@@ -285,7 +313,7 @@ IA64FAULT vmx_vcpu_rfi(VCPU *vcpu)
#if 0
IA64FAULT
-vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val)
+vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, u64 *val)
{
IA64_PSR vpsr;
@@ -338,7 +366,7 @@ vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat)
#endif
#if 0
IA64FAULT
-vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val)
+vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, u64 * val)
{
REGS *regs=vcpu_regs(vcpu);
int nat;
@@ -385,18 +413,18 @@ vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat)
This function gets guest PSR
*/
-UINT64 vmx_vcpu_get_psr(VCPU *vcpu)
+u64 vmx_vcpu_get_psr(VCPU *vcpu)
{
- UINT64 mask;
+ u64 mask;
REGS *regs = vcpu_regs(vcpu);
mask = IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL |
IA64_PSR_MFH | IA64_PSR_CPL | IA64_PSR_RI;
return (VCPU(vcpu, vpsr) & ~mask) | (regs->cr_ipsr & mask);
}
-IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
+IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, u64 imm24)
{
- UINT64 vpsr;
+ u64 vpsr;
vpsr = vmx_vcpu_get_psr(vcpu);
vpsr &= (~imm24);
vmx_vcpu_set_psr(vcpu, vpsr);
@@ -404,9 +432,9 @@ IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
}
-IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24)
+IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, u64 imm24)
{
- UINT64 vpsr;
+ u64 vpsr;
vpsr = vmx_vcpu_get_psr(vcpu);
vpsr |= imm24;
vmx_vcpu_set_psr(vcpu, vpsr);
@@ -414,7 +442,7 @@ IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24)
}
-IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val)
+IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, u64 val)
{
val = (val & MASK(0, 32)) | (vmx_vcpu_get_psr(vcpu) & MASK(32, 32));
vmx_vcpu_set_psr(vcpu, val);
diff --git a/xen/arch/ia64/vmx/vmx_virt.c b/xen/arch/ia64/vmx/vmx_virt.c
index 6fcb37090a..54c2e67b25 100644
--- a/xen/arch/ia64/vmx/vmx_virt.c
+++ b/xen/arch/ia64/vmx/vmx_virt.c
@@ -32,7 +32,7 @@
#include <asm/vmx_phy_mode.h>
void
-ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause)
+ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, u64 * cause)
{
*cause=0;
switch (slot_type) {
@@ -144,20 +144,20 @@ ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause)
IA64FAULT vmx_emul_rsm(VCPU *vcpu, INST64 inst)
{
- UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+ u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm;
return vmx_vcpu_reset_psr_sm(vcpu,imm24);
}
IA64FAULT vmx_emul_ssm(VCPU *vcpu, INST64 inst)
{
- UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+ u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm;
return vmx_vcpu_set_psr_sm(vcpu,imm24);
}
IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst)
{
- UINT64 tgt = inst.M33.r1;
- UINT64 val;
+ u64 tgt = inst.M33.r1;
+ u64 val;
/*
if ((fault = vmx_vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT)
@@ -174,7 +174,7 @@ IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst)
*/
IA64FAULT vmx_emul_mov_to_psr(VCPU *vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
if(vcpu_get_gr_nat(vcpu, inst.M35.r2, &val) != IA64_NO_FAULT)
panic_domain(vcpu_regs(vcpu),"get_psr nat bit fault\n");
@@ -566,7 +566,7 @@ IA64FAULT vmx_emul_tak(VCPU *vcpu, INST64 inst)
IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst)
{
- UINT64 itir, ifa, pte, slot;
+ u64 itir, ifa, pte, slot;
#ifdef VMAL_NO_FAULT_CHECK
IA64_PSR vpsr;
vpsr.val=vmx_vcpu_get_psr(vcpu);
@@ -623,7 +623,7 @@ IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst)
IA64FAULT vmx_emul_itr_i(VCPU *vcpu, INST64 inst)
{
- UINT64 itir, ifa, pte, slot;
+ u64 itir, ifa, pte, slot;
#ifdef VMAL_NO_FAULT_CHECK
ISR isr;
IA64_PSR vpsr;
@@ -691,7 +691,7 @@ IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte)
return IA64_FAULT;
}
- UINT64 fault;
+ u64 fault;
ISR isr;
if ( vpsr.cpl != 0) {
/* Inject Privileged Operation fault into guest */
@@ -729,7 +729,7 @@ IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte)
IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst)
{
- UINT64 itir, ifa, pte;
+ u64 itir, ifa, pte;
if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) {
return IA64_FAULT;
@@ -740,7 +740,7 @@ IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst)
IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst)
{
- UINT64 itir, ifa, pte;
+ u64 itir, ifa, pte;
if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) {
return IA64_FAULT;
@@ -757,7 +757,7 @@ IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst)
IA64FAULT vmx_emul_mov_to_ar_imm(VCPU *vcpu, INST64 inst)
{
// I27 and M30 are identical for these fields
- UINT64 imm;
+ u64 imm;
if(inst.M30.ar3!=44){
panic_domain(vcpu_regs(vcpu),"Can't support ar register other than itc");
@@ -1277,8 +1277,8 @@ IA64FAULT vmx_emul_mov_to_cr(VCPU *vcpu, INST64 inst)
IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst)
{
- UINT64 tgt = inst.M33.r1;
- UINT64 val;
+ u64 tgt = inst.M33.r1;
+ u64 val;
IA64FAULT fault;
#ifdef CHECK_FAULT
IA64_PSR vpsr;
@@ -1353,7 +1353,7 @@ vmx_emulate(VCPU *vcpu, REGS *regs)
{
IA64FAULT status;
INST64 inst;
- UINT64 iip, cause, opcode;
+ u64 iip, cause, opcode;
iip = regs->cr_iip;
cause = VMX(vcpu,cause);
opcode = VMX(vcpu,opcode);
@@ -1364,7 +1364,7 @@ vmx_emulate(VCPU *vcpu, REGS *regs)
#endif
#if 0
if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) {
- printf ("VMAL decode error: cause - %lx; op - %lx\n",
+ printk ("VMAL decode error: cause - %lx; op - %lx\n",
cause, opcode );
return;
}
@@ -1381,7 +1381,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) {
else if (slot == 1)
inst.inst = bundle.slot1a + (bundle.slot1b<<18);
else if (slot == 2) inst.inst = bundle.slot2;
- else printf("priv_handle_op: illegal slot: %d\n", slot);
+ else printk("priv_handle_op: illegal slot: %d\n", slot);
slot_type = slot_types[bundle.template][slot];
ia64_priv_decoder(slot_type, inst, &cause);
if(cause==0){
@@ -1554,7 +1554,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) {
status=vmx_emul_mov_from_cpuid(vcpu, inst);
break;
case EVENT_VMSW:
- printf ("Unimplemented instruction %ld\n", cause);
+ printk ("Unimplemented instruction %ld\n", cause);
status=IA64_FAULT;
break;
default:
diff --git a/xen/arch/ia64/vmx/vtlb.c b/xen/arch/ia64/vmx/vtlb.c
index 4fb31a0ec2..f85c9e63b4 100644
--- a/xen/arch/ia64/vmx/vtlb.c
+++ b/xen/arch/ia64/vmx/vtlb.c
@@ -178,11 +178,23 @@ static void vmx_vhpt_insert(thash_cb_t *hcb, u64 pte, u64 itir, u64 ifa)
return;
}
-void thash_vhpt_insert(VCPU *v, u64 pte, u64 itir, u64 va)
+void thash_vhpt_insert(VCPU *v, u64 pte, u64 itir, u64 va, int type)
{
- u64 phy_pte;
+ u64 phy_pte, psr;
+ ia64_rr mrr;
+
+ mrr.rrval = ia64_get_rr(va);
phy_pte=translate_phy_pte(v, &pte, itir, va);
- vmx_vhpt_insert(vcpu_get_vhpt(v), phy_pte, itir, va);
+
+ if (itir_ps(itir) >= mrr.ps) {
+ vmx_vhpt_insert(vcpu_get_vhpt(v), phy_pte, itir, va);
+ } else {
+ phy_pte &= ~PAGE_FLAGS_RV_MASK;
+ psr = ia64_clear_ic();
+ ia64_itc(type + 1, va, phy_pte, itir_ps(itir));
+ ia64_set_psr(psr);
+ ia64_srlz_i();
+ }
}
/*
* vhpt lookup
@@ -191,7 +203,7 @@ void thash_vhpt_insert(VCPU *v, u64 pte, u64 itir, u64 va)
thash_data_t * vhpt_lookup(u64 va)
{
thash_data_t *hash, *head;
- u64 tag, pte;
+ u64 tag, pte, itir;
head = (thash_data_t *)ia64_thash(va);
hash=head;
tag = ia64_ttag(va);
@@ -207,6 +219,9 @@ thash_data_t * vhpt_lookup(u64 va)
tag = hash->etag;
hash->etag = head->etag;
head->etag = tag;
+ itir = hash->itir;
+ hash->itir = head->itir;
+ head->itir = itir;
head->len = hash->len;
hash->len=0;
return head;
@@ -218,20 +233,13 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte)
{
u64 ret;
thash_data_t * data;
- PTA vpta;
data = vhpt_lookup(iha);
if (data == NULL) {
data = vtlb_lookup(current, iha, DSIDE_TLB);
if (data != NULL)
- thash_vhpt_insert(current, data->page_flags, data->itir ,iha);
- }
-
- /* VHPT long format is not read. */
- vmx_vcpu_get_pta(current, &vpta.val);
- if (vpta.vf == 1) {
- *pte = 0;
- return 0;
+ thash_vhpt_insert(current, data->page_flags, data->itir,
+ iha, DSIDE_TLB);
}
asm volatile ("rsm psr.ic|psr.i;;"
@@ -615,7 +623,8 @@ void thash_init(thash_cb_t *hcb, u64 sz)
head=hcb->hash;
num = (hcb->hash_sz/sizeof(thash_data_t));
do{
- head->itir = PAGE_SHIFT<<2;
+ head->page_flags = 0;
+ head->itir = 0;
head->etag = 1UL<<63;
head->next = 0;
head++;
@@ -625,11 +634,12 @@ void thash_init(thash_cb_t *hcb, u64 sz)
hcb->cch_freelist = p = hcb->cch_buf;
num = (hcb->cch_sz/sizeof(thash_data_t))-1;
do{
- p->itir = PAGE_SHIFT<<2;
+ p->page_flags = 0;
+ p->itir = 0;
p->next =p+1;
p++;
num--;
}while(num);
- p->itir = PAGE_SHIFT<<2;
+ p->itir = 0;
p->next = NULL;
}
diff --git a/xen/arch/ia64/xen/Makefile b/xen/arch/ia64/xen/Makefile
index b51029f043..87f22f0966 100644
--- a/xen/arch/ia64/xen/Makefile
+++ b/xen/arch/ia64/xen/Makefile
@@ -25,5 +25,9 @@ obj-y += xensetup.o
obj-y += xentime.o
obj-y += flushd.o
obj-y += privop_stat.o
+obj-y += xenpatch.o
+obj-y += xencomm.o
obj-$(crash_debug) += gdbstub.o
+obj-$(xen_ia64_tlb_track) += tlb_track.o
+obj-$(xen_ia64_tlbflush_clock) += flushtlb.o
diff --git a/xen/arch/ia64/xen/acpi.c b/xen/arch/ia64/xen/acpi.c
index af1748f1cb..516a6741c0 100644
--- a/xen/arch/ia64/xen/acpi.c
+++ b/xen/arch/ia64/xen/acpi.c
@@ -53,6 +53,7 @@
#include <asm/hw_irq.h>
#ifdef XEN
#include <xen/errno.h>
+#include <xen/nodemask.h>
#endif
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -457,6 +458,7 @@ acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma)
num_node_memblks++;
}
+static unsigned int numnodes;
void __init
acpi_numa_arch_fixup (void)
{
diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c
index 8bb24010ce..8d53e43ff3 100644
--- a/xen/arch/ia64/xen/dom0_ops.c
+++ b/xen/arch/ia64/xen/dom0_ops.c
@@ -22,8 +22,9 @@
#include <asm/dom_fw.h>
#include <xen/iocap.h>
#include <xen/errno.h>
+#include <xen/nodemask.h>
-void build_physmap_table(struct domain *d);
+#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
extern unsigned long total_pages;
@@ -115,7 +116,6 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
vmx_setup_platform(d);
}
else {
- build_physmap_table(d);
dom_fw_setup(d, ds->bp, ds->maxmem);
if (ds->xsi_va)
d->arch.shared_info_va = ds->xsi_va;
@@ -171,7 +171,7 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
}
break;
default:
- printf("arch_do_domctl: unrecognized domctl: %d!!!\n",op->cmd);
+ printk("arch_do_domctl: unrecognized domctl: %d!!!\n",op->cmd);
ret = -ENOSYS;
}
@@ -179,17 +179,26 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
return ret;
}
+/*
+ * Temporarily disable the NUMA PHYSINFO code until the rest of the
+ * changes are upstream.
+ */
+#undef IA64_NUMA_PHYSINFO
+
long arch_do_sysctl(xen_sysctl_t *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
{
long ret = 0;
- if ( !IS_PRIV(current->domain) )
- return -EPERM;
-
switch ( op->cmd )
{
case XEN_SYSCTL_physinfo:
{
+#ifdef IA64_NUMA_PHYSINFO
+ int i;
+ node_data_t *chunks;
+ u64 *map, cpu_to_node_map[MAX_NUMNODES];
+#endif
+
xen_sysctl_physinfo_t *pi = &op->u.physinfo;
pi->threads_per_core =
@@ -198,20 +207,77 @@ long arch_do_sysctl(xen_sysctl_t *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl)
cpus_weight(cpu_core_map[0]) / pi->threads_per_core;
pi->sockets_per_node =
num_online_cpus() / cpus_weight(cpu_core_map[0]);
- pi->nr_nodes = 1;
+#ifndef IA64_NUMA_PHYSINFO
+ pi->nr_nodes = 1;
+#endif
pi->total_pages = total_pages;
pi->free_pages = avail_domheap_pages();
pi->cpu_khz = local_cpu_data->proc_freq / 1000;
memset(pi->hw_cap, 0, sizeof(pi->hw_cap));
//memcpy(pi->hw_cap, boot_cpu_data.x86_capability, NCAPINTS*4);
ret = 0;
+
+#ifdef IA64_NUMA_PHYSINFO
+ /* fetch memory_chunk pointer from guest */
+ get_xen_guest_handle(chunks, pi->memory_chunks);
+
+ printk("chunks=%p, num_node_memblks=%u\n", chunks, num_node_memblks);
+ /* if it is set, fill out memory chunk array */
+ if (chunks != NULL) {
+ if (num_node_memblks == 0) {
+ /* Non-NUMA machine. Put pseudo-values. */
+ node_data_t data;
+ data.node_start_pfn = 0;
+ data.node_spanned_pages = total_pages;
+ data.node_id = 0;
+ /* copy memory chunk structs to guest */
+ if (copy_to_guest_offset(pi->memory_chunks, 0, &data, 1)) {
+ ret = -EFAULT;
+ break;
+ }
+ } else {
+ for (i = 0; i < num_node_memblks && i < PUBLIC_MAXCHUNKS; i++) {
+ node_data_t data;
+ data.node_start_pfn = node_memblk[i].start_paddr >>
+ PAGE_SHIFT;
+ data.node_spanned_pages = node_memblk[i].size >> PAGE_SHIFT;
+ data.node_id = node_memblk[i].nid;
+ /* copy memory chunk structs to guest */
+ if (copy_to_guest_offset(pi->memory_chunks, i, &data, 1)) {
+ ret = -EFAULT;
+ break;
+ }
+ }
+ }
+ }
+ /* set number of notes */
+ pi->nr_nodes = num_online_nodes();
+
+ /* fetch cpu_to_node pointer from guest */
+ get_xen_guest_handle(map, pi->cpu_to_node);
+
+ /* if set, fill out cpu_to_node array */
+ if (map != NULL) {
+ /* copy cpu to node mapping to domU */
+ memset(cpu_to_node_map, 0, sizeof(cpu_to_node_map));
+ for (i = 0; i < num_online_cpus(); i++) {
+ cpu_to_node_map[i] = cpu_to_node(i);
+ if (copy_to_guest_offset(pi->cpu_to_node, i,
+ &(cpu_to_node_map[i]), 1)) {
+ ret = -EFAULT;
+ break;
+ }
+ }
+ }
+#endif
+
if ( copy_to_guest(u_sysctl, op, 1) )
ret = -EFAULT;
}
break;
default:
- printf("arch_do_sysctl: unrecognized sysctl: %d!!!\n",op->cmd);
+ printk("arch_do_sysctl: unrecognized sysctl: %d!!!\n",op->cmd);
ret = -ENOSYS;
}
@@ -252,10 +318,12 @@ do_dom0vp_op(unsigned long cmd,
case IA64_DOM0VP_phystomach:
ret = ____lookup_domain_mpa(d, arg0 << PAGE_SHIFT);
if (ret == INVALID_MFN) {
- DPRINTK("%s:%d INVALID_MFN ret: 0x%lx\n", __func__, __LINE__, ret);
+ dprintk(XENLOG_INFO, "%s: INVALID_MFN ret: 0x%lx\n",
+ __func__, ret);
} else {
ret = (ret & _PFN_MASK) >> PAGE_SHIFT;//XXX pte_pfn()
}
+ perfc_incrc(dom0vp_phystomach);
break;
case IA64_DOM0VP_machtophys:
if (!mfn_valid(arg0)) {
@@ -263,6 +331,7 @@ do_dom0vp_op(unsigned long cmd,
break;
}
ret = get_gpfn_from_mfn(arg0);
+ perfc_incrc(dom0vp_machtophys);
break;
case IA64_DOM0VP_zap_physmap:
ret = dom0vp_zap_physmap(d, arg0, (unsigned int)arg1);
@@ -271,9 +340,12 @@ do_dom0vp_op(unsigned long cmd,
ret = dom0vp_add_physmap(d, arg0, arg1, (unsigned int)arg2,
(domid_t)arg3);
break;
+ case IA64_DOM0VP_expose_p2m:
+ ret = dom0vp_expose_p2m(d, arg0, arg1, arg2, arg3);
+ break;
default:
ret = -1;
- printf("unknown dom0_vp_op 0x%lx\n", cmd);
+ printk("unknown dom0_vp_op 0x%lx\n", cmd);
break;
}
diff --git a/xen/arch/ia64/xen/dom_fw.c b/xen/arch/ia64/xen/dom_fw.c
index 1aa8b42c7f..91b618ee88 100644
--- a/xen/arch/ia64/xen/dom_fw.c
+++ b/xen/arch/ia64/xen/dom_fw.c
@@ -55,9 +55,9 @@ extern unsigned long running_on_sim;
tables->func_ptrs[pfn++] = 0; \
} while (0)
-// allocate a page for fw
-// build_physmap_table() which is called by new_thread()
-// does for domU.
+/* allocate a page for fw
+ * guest_setup() @ libxc/xc_linux_build.c does for domU
+ */
static inline void
assign_new_domain_page_if_dom0(struct domain *d, unsigned long mpaddr)
{
@@ -204,9 +204,9 @@ print_md(efi_memory_desc_t *md)
size = md->num_pages << EFI_PAGE_SHIFT;
if (size > ONE_MB)
- printf ("(%luMB)\n", size >> 20);
+ printk ("(%luMB)\n", size >> 20);
else
- printf ("(%luKB)\n", size >> 10);
+ printk ("(%luKB)\n", size >> 10);
}
static u32 lsapic_nbr;
@@ -574,7 +574,7 @@ complete_dom0_memmap(struct domain *d,
default:
/* Print a warning but continue. */
- printf("complete_dom0_memmap: warning: "
+ printk("complete_dom0_memmap: warning: "
"unhandled MDT entry type %u\n", md->type);
}
}
@@ -634,9 +634,10 @@ complete_dom0_memmap(struct domain *d,
sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t),
efi_mdt_cmp, NULL);
- // dom0 doesn't need build_physmap_table()
- // see arch_set_info_guest()
- // instead we allocate pages manually.
+ /* setup_guest() @ libxc/xc_linux_build() arranges memory for domU.
+ * however no one arranges memory for dom0,
+ * instead we allocate pages manually.
+ */
for (i = 0; i < num_mds; i++) {
md = &tables->efi_memmap[i];
if (md->phys_addr > maxmem)
@@ -734,47 +735,47 @@ dom_fw_init(struct domain *d,
/* Write messages to the console. */
touch_acpi_table();
- printf("Domain0 EFI passthrough:");
+ printk("Domain0 EFI passthrough:");
if (efi.mps) {
tables->efi_tables[i].guid = MPS_TABLE_GUID;
tables->efi_tables[i].table = __pa(efi.mps);
- printf(" MPS=0x%lx",tables->efi_tables[i].table);
+ printk(" MPS=0x%lx",tables->efi_tables[i].table);
i++;
}
if (efi.acpi20) {
tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;
tables->efi_tables[i].table = __pa(efi.acpi20);
- printf(" ACPI 2.0=0x%lx",tables->efi_tables[i].table);
+ printk(" ACPI 2.0=0x%lx",tables->efi_tables[i].table);
i++;
}
if (efi.acpi) {
tables->efi_tables[i].guid = ACPI_TABLE_GUID;
tables->efi_tables[i].table = __pa(efi.acpi);
- printf(" ACPI=0x%lx",tables->efi_tables[i].table);
+ printk(" ACPI=0x%lx",tables->efi_tables[i].table);
i++;
}
if (efi.smbios) {
tables->efi_tables[i].guid = SMBIOS_TABLE_GUID;
tables->efi_tables[i].table = __pa(efi.smbios);
- printf(" SMBIOS=0x%lx",tables->efi_tables[i].table);
+ printk(" SMBIOS=0x%lx",tables->efi_tables[i].table);
i++;
}
if (efi.hcdp) {
tables->efi_tables[i].guid = HCDP_TABLE_GUID;
tables->efi_tables[i].table = __pa(efi.hcdp);
- printf(" HCDP=0x%lx",tables->efi_tables[i].table);
+ printk(" HCDP=0x%lx",tables->efi_tables[i].table);
i++;
}
- printf("\n");
+ printk("\n");
} else {
- printf("DomainU EFI build up:");
+ printk("DomainU EFI build up:");
tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;
tables->efi_tables[i].table = FW_ACPI_BASE_PADDR;
- printf(" ACPI 2.0=0x%lx",tables->efi_tables[i].table);
+ printk(" ACPI 2.0=0x%lx",tables->efi_tables[i].table);
i++;
- printf("\n");
+ printk("\n");
}
/* fill in the SAL system table: */
diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c
index 17ca6ff40e..ec0d415a05 100644
--- a/xen/arch/ia64/xen/domain.c
+++ b/xen/arch/ia64/xen/domain.c
@@ -46,26 +46,21 @@
#include <asm/regionreg.h>
#include <asm/dom_fw.h>
#include <asm/shadow.h>
+#include <xen/guest_access.h>
+#include <asm/tlb_track.h>
unsigned long dom0_size = 512*1024*1024;
-unsigned long dom0_align = 64*1024*1024;
/* dom0_max_vcpus: maximum number of VCPUs to create for dom0. */
static unsigned int dom0_max_vcpus = 1;
integer_param("dom0_max_vcpus", dom0_max_vcpus);
-extern int opt_dom0_vcpus_pin;
extern unsigned long running_on_sim;
extern char dom0_command_line[];
-/* FIXME: where these declarations should be there ? */
-extern void serial_input_init(void);
+/* forward declaration */
static void init_switch_stack(struct vcpu *v);
-extern void vmx_do_launch(struct vcpu *);
-
-/* this belongs in include/asm, but there doesn't seem to be a suitable place */
-extern struct vcpu *ia64_switch_to (struct vcpu *next_task);
/* Address of vpsr.i (in fact evtchn_upcall_mask) of current vcpu.
This is a Xen virtual address. */
@@ -74,33 +69,68 @@ DEFINE_PER_CPU(int *, current_psr_ic_addr);
#include <xen/sched-if.h>
-static void flush_vtlb_for_context_switch(struct vcpu* vcpu)
+static void
+ia64_disable_vhpt_walker(void)
+{
+ // disable VHPT. ia64_new_rr7() might cause VHPT
+ // fault without this because it flushes dtr[IA64_TR_VHPT]
+ // (VHPT_SIZE_LOG2 << 2) is just for avoid
+ // Reserved Register/Field fault.
+ ia64_set_pta(VHPT_SIZE_LOG2 << 2);
+}
+
+static void flush_vtlb_for_context_switch(struct vcpu* prev, struct vcpu* next)
{
int cpu = smp_processor_id();
- int last_vcpu_id = vcpu->domain->arch.last_vcpu[cpu].vcpu_id;
- int last_processor = vcpu->arch.last_processor;
+ int last_vcpu_id, last_processor;
+
+ if (!is_idle_domain(prev->domain))
+ tlbflush_update_time
+ (&prev->domain->arch.last_vcpu[cpu].tlbflush_timestamp,
+ tlbflush_current_time());
- if (is_idle_domain(vcpu->domain))
+ if (is_idle_domain(next->domain))
return;
-
- vcpu->domain->arch.last_vcpu[cpu].vcpu_id = vcpu->vcpu_id;
- vcpu->arch.last_processor = cpu;
- if ((last_vcpu_id != vcpu->vcpu_id &&
+ last_vcpu_id = next->domain->arch.last_vcpu[cpu].vcpu_id;
+ last_processor = next->arch.last_processor;
+
+ next->domain->arch.last_vcpu[cpu].vcpu_id = next->vcpu_id;
+ next->arch.last_processor = cpu;
+
+ if ((last_vcpu_id != next->vcpu_id &&
last_vcpu_id != INVALID_VCPU_ID) ||
- (last_vcpu_id == vcpu->vcpu_id &&
+ (last_vcpu_id == next->vcpu_id &&
last_processor != cpu &&
last_processor != INVALID_PROCESSOR)) {
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+ u32 last_tlbflush_timestamp =
+ next->domain->arch.last_vcpu[cpu].tlbflush_timestamp;
+#endif
+ int vhpt_is_flushed = 0;
// if the vTLB implementation was changed,
// the followings must be updated either.
- if (VMX_DOMAIN(vcpu)) {
+ if (VMX_DOMAIN(next)) {
// currently vTLB for vt-i domian is per vcpu.
// so any flushing isn't needed.
+ } else if (HAS_PERVCPU_VHPT(next->domain)) {
+ // nothing to do
+ } else {
+ if (NEED_FLUSH(__get_cpu_var(vhpt_tlbflush_timestamp),
+ last_tlbflush_timestamp)) {
+ local_vhpt_flush();
+ vhpt_is_flushed = 1;
+ }
+ }
+ if (vhpt_is_flushed || NEED_FLUSH(__get_cpu_var(tlbflush_time),
+ last_tlbflush_timestamp)) {
+ local_flush_tlb_all();
+ perfc_incrc(tlbflush_clock_cswitch_purge);
} else {
- vhpt_flush();
+ perfc_incrc(tlbflush_clock_cswitch_skip);
}
- local_flush_tlb_all();
+ perfc_incrc(flush_vtlb_for_context_switch);
}
}
@@ -109,15 +139,15 @@ void schedule_tail(struct vcpu *prev)
extern char ia64_ivt;
context_saved(prev);
+ ia64_disable_vhpt_walker();
if (VMX_DOMAIN(current)) {
vmx_do_launch(current);
migrate_timer(&current->arch.arch_vmx.vtm.vtm_timer,
current->processor);
} else {
ia64_set_iva(&ia64_ivt);
- ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) |
- VHPT_ENABLED);
load_region_regs(current);
+ ia64_set_pta(vcpu_pta(current));
vcpu_load_kernel_regs(current);
__ia64_per_cpu_var(current_psr_i_addr) = &current->domain->
shared_info->vcpu_info[current->vcpu_id].evtchn_upcall_mask;
@@ -125,13 +155,12 @@ void schedule_tail(struct vcpu *prev)
(current->domain->arch.shared_info_va + XSI_PSR_IC_OFS);
migrate_timer(&current->arch.hlt_timer, current->processor);
}
- flush_vtlb_for_context_switch(current);
+ flush_vtlb_for_context_switch(prev, current);
}
void context_switch(struct vcpu *prev, struct vcpu *next)
{
uint64_t spsr;
- uint64_t pta;
local_irq_save(spsr);
@@ -149,6 +178,8 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
}
if (VMX_DOMAIN(next))
vmx_load_state(next);
+
+ ia64_disable_vhpt_walker();
/*ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);*/
prev = ia64_switch_to(next);
@@ -168,9 +199,8 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
nd = current->domain;
if (!is_idle_domain(nd)) {
- ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) |
- VHPT_ENABLED);
load_region_regs(current);
+ ia64_set_pta(vcpu_pta(current));
vcpu_load_kernel_regs(current);
vcpu_set_next_timer(current);
if (vcpu_timer_expired(current))
@@ -184,14 +214,12 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
* walker. Then all accesses happen within idle context will
* be handled by TR mapping and identity mapping.
*/
- pta = ia64_get_pta();
- ia64_set_pta(pta & ~VHPT_ENABLED);
__ia64_per_cpu_var(current_psr_i_addr) = NULL;
__ia64_per_cpu_var(current_psr_ic_addr) = NULL;
}
}
- flush_vtlb_for_context_switch(current);
local_irq_restore(spsr);
+ flush_vtlb_for_context_switch(prev, current);
context_saved(prev);
}
@@ -247,33 +275,61 @@ void hlt_timer_fn(void *data)
vcpu_unblock(v);
}
-struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id)
+void relinquish_vcpu_resources(struct vcpu *v)
+{
+ if (HAS_PERVCPU_VHPT(v->domain))
+ pervcpu_vhpt_free(v);
+ if (v->arch.privregs != NULL) {
+ free_xenheap_pages(v->arch.privregs,
+ get_order_from_shift(XMAPPEDREGS_SHIFT));
+ v->arch.privregs = NULL;
+ }
+ kill_timer(&v->arch.hlt_timer);
+}
+
+struct vcpu *alloc_vcpu_struct(void)
{
struct vcpu *v;
struct thread_info *ti;
+ static int first_allocation = 1;
- /* Still keep idle vcpu0 static allocated at compilation, due
- * to some code from Linux still requires it in early phase.
- */
- if (is_idle_domain(d) && !vcpu_id)
- v = idle_vcpu[0];
- else {
- if ((v = alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER)) == NULL)
- return NULL;
- memset(v, 0, sizeof(*v));
-
- ti = alloc_thread_info(v);
- /* Clear thread_info to clear some important fields, like
- * preempt_count
- */
- memset(ti, 0, sizeof(struct thread_info));
- init_switch_stack(v);
+ if (first_allocation) {
+ first_allocation = 0;
+ /* Still keep idle vcpu0 static allocated at compilation, due
+ * to some code from Linux still requires it in early phase.
+ */
+ return idle_vcpu[0];
}
+ if ((v = alloc_xenheap_pages(KERNEL_STACK_SIZE_ORDER)) == NULL)
+ return NULL;
+ memset(v, 0, sizeof(*v));
+
+ ti = alloc_thread_info(v);
+ /* Clear thread_info to clear some important fields, like
+ * preempt_count
+ */
+ memset(ti, 0, sizeof(struct thread_info));
+ init_switch_stack(v);
+
+ return v;
+}
+
+void free_vcpu_struct(struct vcpu *v)
+{
+ free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER);
+}
+
+int vcpu_initialise(struct vcpu *v)
+{
+ struct domain *d = v->domain;
+ int rc, order, i;
+
if (!is_idle_domain(d)) {
if (!d->arch.is_vti) {
- int order;
- int i;
+ if (HAS_PERVCPU_VHPT(d))
+ if ((rc = pervcpu_vhpt_alloc(v)) != 0)
+ return rc;
/* Create privregs page only if not VTi. */
order = get_order_from_shift(XMAPPEDREGS_SHIFT);
@@ -283,6 +339,9 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id)
for (i = 0; i < (1 << order); i++)
share_xen_page_with_guest(virt_to_page(v->arch.privregs) +
i, d, XENSHARE_writable);
+
+ tlbflush_update_time(&v->arch.tlbflush_timestamp,
+ tlbflush_current_time());
}
v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0;
@@ -306,32 +365,20 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id)
v->arch.breakimm = d->arch.breakimm;
v->arch.last_processor = INVALID_PROCESSOR;
}
- if (!VMX_DOMAIN(v)){
+
+ if (!VMX_DOMAIN(v))
init_timer(&v->arch.hlt_timer, hlt_timer_fn, v,
first_cpu(cpu_online_map));
- }
- return v;
-}
-
-void relinquish_vcpu_resources(struct vcpu *v)
-{
- if (v->arch.privregs != NULL) {
- free_xenheap_pages(v->arch.privregs,
- get_order_from_shift(XMAPPEDREGS_SHIFT));
- v->arch.privregs = NULL;
- }
- kill_timer(&v->arch.hlt_timer);
+ return 0;
}
-void free_vcpu_struct(struct vcpu *v)
+void vcpu_destroy(struct vcpu *v)
{
- if (VMX_DOMAIN(v))
+ if (v->domain->arch.is_vti)
vmx_relinquish_vcpu_resources(v);
else
relinquish_vcpu_resources(v);
-
- free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER);
}
static void init_switch_stack(struct vcpu *v)
@@ -351,6 +398,11 @@ static void init_switch_stack(struct vcpu *v)
memset(v->arch._thread.fph,0,sizeof(struct ia64_fpreg)*96);
}
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+static int opt_pervcpu_vhpt = 1;
+integer_param("pervcpu_vhpt", opt_pervcpu_vhpt);
+#endif
+
int arch_domain_create(struct domain *d)
{
int i;
@@ -365,6 +417,13 @@ int arch_domain_create(struct domain *d)
if (is_idle_domain(d))
return 0;
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ d->arch.has_pervcpu_vhpt = opt_pervcpu_vhpt;
+ dprintk(XENLOG_WARNING, "%s:%d domain %d pervcpu_vhpt %d\n",
+ __func__, __LINE__, d->domain_id, d->arch.has_pervcpu_vhpt);
+#endif
+ if (tlb_track_create(d) < 0)
+ goto fail_nomem1;
d->shared_info = alloc_xenheap_pages(get_order_from_shift(XSI_SHIFT));
if (d->shared_info == NULL)
goto fail_nomem;
@@ -373,7 +432,6 @@ int arch_domain_create(struct domain *d)
share_xen_page_with_guest(virt_to_page((char *)d->shared_info + i),
d, XENSHARE_writable);
- d->max_pages = (128UL*1024*1024)/PAGE_SIZE; // 128MB default // FIXME
/* We may also need emulation rid for region4, though it's unlikely
* to see guest issue uncacheable access in metaphysical mode. But
* keep such info here may be more sane.
@@ -389,10 +447,12 @@ int arch_domain_create(struct domain *d)
d->arch.ioport_caps = rangeset_new(d, "I/O Ports",
RANGESETF_prettyprint_hex);
- printf ("arch_domain_create: domain=%p\n", d);
+ printk ("arch_domain_create: domain=%p\n", d);
return 0;
fail_nomem:
+ tlb_track_destroy(d);
+fail_nomem1:
if (d->arch.mm.pgd != NULL)
pgd_free(d->arch.mm.pgd);
if (d->shared_info != NULL)
@@ -408,6 +468,8 @@ void arch_domain_destroy(struct domain *d)
if (d->arch.shadow_bitmap != NULL)
xfree(d->arch.shadow_bitmap);
+ tlb_track_destroy(d);
+
/* Clear vTLB for the next domain. */
domain_flush_tlb_vhpt(d);
@@ -566,21 +628,6 @@ void domain_relinquish_resources(struct domain *d)
xfree(d->arch.sal_data);
}
-void build_physmap_table(struct domain *d)
-{
- struct list_head *list_ent = d->page_list.next;
- unsigned long mfn, i = 0;
-
- while(list_ent != &d->page_list) {
- mfn = page_to_mfn(list_entry(
- list_ent, struct page_info, list));
- assign_domain_page(d, i << PAGE_SHIFT, mfn << PAGE_SHIFT);
-
- i++;
- list_ent = mfn_to_page(mfn)->list.next;
- }
-}
-
unsigned long
domain_set_shared_info_va (unsigned long va)
{
@@ -599,7 +646,7 @@ domain_set_shared_info_va (unsigned long va)
/* Note: this doesn't work well if other cpus are already running.
However this is part of the spec :-) */
- printf ("Domain set shared_info_va to 0x%016lx\n", va);
+ printk ("Domain set shared_info_va to 0x%016lx\n", va);
d->arch.shared_info_va = va;
for_each_vcpu (d, v1) {
@@ -626,7 +673,8 @@ int shadow_mode_control(struct domain *d, xen_domctl_shadow_op_t *sc)
//struct vcpu *v;
if (unlikely(d == current->domain)) {
- DPRINTK("Don't try to do a shadow op on yourself!\n");
+ gdprintk(XENLOG_INFO,
+ "Don't try to do a shadow op on yourself!\n");
return -EINVAL;
}
@@ -845,23 +893,6 @@ void alloc_dom0(void)
" (try e.g. dom0_mem=256M or dom0_mem=65536K)\n");
}
- /* Check dom0 align. */
- if ((dom0_align - 1) & dom0_align) { /* not a power of two */
- panic("dom0_align (%lx) must be power of two, boot aborted"
- " (try e.g. dom0_align=256M or dom0_align=65536K)\n",
- dom0_align);
- }
- if (dom0_align < PAGE_SIZE) {
- panic("dom0_align must be >= %ld, boot aborted"
- " (try e.g. dom0_align=256M or dom0_align=65536K)\n",
- PAGE_SIZE);
- }
- if (dom0_size % dom0_align) {
- dom0_size = (dom0_size / dom0_align + 1) * dom0_align;
- printf("dom0_size rounded up to %ld, due to dom0_align=%lx\n",
- dom0_size,dom0_align);
- }
-
if (running_on_sim) {
dom0_size = 128*1024*1024; //FIXME: Should be configurable
}
@@ -916,7 +947,7 @@ int construct_dom0(struct domain *d,
struct page_info *page = NULL;
#endif
-//printf("construct_dom0: starting\n");
+//printk("construct_dom0: starting\n");
/* Sanity! */
BUG_ON(d != dom0);
@@ -1020,13 +1051,10 @@ int construct_dom0(struct domain *d,
if (dom0_max_vcpus > MAX_VIRT_CPUS)
dom0_max_vcpus = MAX_VIRT_CPUS;
- printf ("Dom0 max_vcpus=%d\n", dom0_max_vcpus);
- for ( i = 1; i < dom0_max_vcpus; i++ ) {
+ printk ("Dom0 max_vcpus=%d\n", dom0_max_vcpus);
+ for ( i = 1; i < dom0_max_vcpus; i++ )
if (alloc_vcpu(d, i, i) == NULL)
- printf ("Cannot allocate dom0 vcpu %d\n", i);
- else if (opt_dom0_vcpus_pin)
- d->vcpu[i]->cpu_affinity = cpumask_of_cpu(i);
- }
+ printk ("Cannot allocate dom0 vcpu %d\n", i);
/* Copy the OS image. */
loaddomainelfimage(d,image_start);
@@ -1105,9 +1133,6 @@ int construct_dom0(struct domain *d,
physdev_init_dom0(d);
- // FIXME: Hack for keyboard input
- //serial_input_init();
-
return 0;
}
@@ -1115,7 +1140,7 @@ void machine_restart(char * __unused)
{
console_start_sync();
if (running_on_sim)
- printf ("machine_restart called. spinning...\n");
+ printk ("machine_restart called. spinning...\n");
else
(*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
while(1);
@@ -1127,7 +1152,7 @@ void machine_halt(void)
{
console_start_sync();
if (running_on_sim)
- printf ("machine_halt called. spinning...\n");
+ printk ("machine_halt called. spinning...\n");
else
cpu_halt();
while(1);
@@ -1143,13 +1168,6 @@ void sync_vcpu_execstate(struct vcpu *v)
static void parse_dom0_mem(char *s)
{
- dom0_size = parse_size_and_unit(s);
+ dom0_size = parse_size_and_unit(s, NULL);
}
custom_param("dom0_mem", parse_dom0_mem);
-
-
-static void parse_dom0_align(char *s)
-{
- dom0_align = parse_size_and_unit(s);
-}
-custom_param("dom0_align", parse_dom0_align);
diff --git a/xen/arch/ia64/xen/faults.c b/xen/arch/ia64/xen/faults.c
index f2e3a1bef7..05aea16fc2 100644
--- a/xen/arch/ia64/xen/faults.c
+++ b/xen/arch/ia64/xen/faults.c
@@ -31,6 +31,7 @@
#include <asm/asm-xsi-offsets.h>
#include <asm/shadow.h>
#include <asm/uaccess.h>
+#include <asm/p2m_entry.h>
extern void die_if_kernel(char *str, struct pt_regs *regs, long err);
/* FIXME: where these declarations shold be there ? */
@@ -43,54 +44,58 @@ extern IA64FAULT ia64_hypercall(struct pt_regs *regs);
IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \
IA64_PSR_IT | IA64_PSR_BN)
-#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
- IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \
- IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
- IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \
- IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
- IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
-
+#define DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
+ IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI | \
+ IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
+ IA64_PSR_CPL| IA64_PSR_MC | IA64_PSR_IS | \
+ IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
+ IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
extern void do_ssc(unsigned long ssc, struct pt_regs *regs);
// should never panic domain... if it does, stack may have been overrun
-void check_bad_nested_interruption(unsigned long isr, struct pt_regs *regs, unsigned long vector)
+void check_bad_nested_interruption(unsigned long isr, struct pt_regs *regs,
+ unsigned long vector)
{
struct vcpu *v = current;
- if (!(PSCB(v,ipsr) & IA64_PSR_DT)) {
- panic_domain(regs,"psr.dt off, trying to deliver nested dtlb!\n");
+ if (!(PSCB(v, ipsr) & IA64_PSR_DT)) {
+ panic_domain(regs,
+ "psr.dt off, trying to deliver nested dtlb!\n");
}
vector &= ~0xf;
if (vector != IA64_DATA_TLB_VECTOR &&
vector != IA64_ALT_DATA_TLB_VECTOR &&
vector != IA64_VHPT_TRANS_VECTOR) {
- panic_domain(regs,"psr.ic off, delivering fault=%lx,ipsr=%lx,iip=%lx,ifa=%lx,isr=%lx,PSCB.iip=%lx\n",
- vector,regs->cr_ipsr,regs->cr_iip,PSCB(v,ifa),isr,PSCB(v,iip));
+ panic_domain(regs, "psr.ic off, delivering fault=%lx,"
+ "ipsr=%lx,iip=%lx,ifa=%lx,isr=%lx,PSCB.iip=%lx\n",
+ vector, regs->cr_ipsr, regs->cr_iip, PSCB(v, ifa),
+ isr, PSCB(v, iip));
}
}
-void reflect_interruption(unsigned long isr, struct pt_regs *regs, unsigned long vector)
+void reflect_interruption(unsigned long isr, struct pt_regs *regs,
+ unsigned long vector)
{
struct vcpu *v = current;
- if (!PSCB(v,interrupt_collection_enabled))
- check_bad_nested_interruption(isr,regs,vector);
- PSCB(v,unat) = regs->ar_unat; // not sure if this is really needed?
- PSCB(v,precover_ifs) = regs->cr_ifs;
+ if (!PSCB(v, interrupt_collection_enabled))
+ check_bad_nested_interruption(isr, regs, vector);
+ PSCB(v, unat) = regs->ar_unat; // not sure if this is really needed?
+ PSCB(v, precover_ifs) = regs->cr_ifs;
vcpu_bsw0(v);
- PSCB(v,ipsr) = vcpu_get_ipsr_int_state(v,regs->cr_ipsr);
- PSCB(v,isr) = isr;
- PSCB(v,iip) = regs->cr_iip;
- PSCB(v,ifs) = 0;
- PSCB(v,incomplete_regframe) = 0;
+ PSCB(v, ipsr) = vcpu_get_ipsr_int_state(v, regs->cr_ipsr);
+ PSCB(v, isr) = isr;
+ PSCB(v, iip) = regs->cr_iip;
+ PSCB(v, ifs) = 0;
+ PSCB(v, incomplete_regframe) = 0;
- regs->cr_iip = ((unsigned long) PSCBX(v,iva) + vector) & ~0xffUL;
+ regs->cr_iip = ((unsigned long)PSCBX(v, iva) + vector) & ~0xffUL;
regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
regs->r31 = current->domain->arch.shared_info_va + XSI_IPSR_OFS;
v->vcpu_info->evtchn_upcall_mask = 1;
- PSCB(v,interrupt_collection_enabled) = 0;
+ PSCB(v, interrupt_collection_enabled) = 0;
perfc_incra(slow_reflect, vector >> 8);
}
@@ -104,13 +109,15 @@ void reflect_extint(struct pt_regs *regs)
static int first_extint = 1;
if (first_extint) {
- printf("Delivering first extint to domain: isr=0x%lx, iip=0x%lx\n", isr, regs->cr_iip);
+ printk("Delivering first extint to domain: isr=0x%lx, "
+ "iip=0x%lx\n", isr, regs->cr_iip);
first_extint = 0;
}
if (vcpu_timer_pending_early(v))
-printf("*#*#*#* about to deliver early timer to domain %d!!!\n",v->domain->domain_id);
- PSCB(current,itir) = 0;
- reflect_interruption(isr,regs,IA64_EXTINT_VECTOR);
+ printk("*#*#*#* about to deliver early timer to domain %d!!\n",
+ v->domain->domain_id);
+ PSCB(current, itir) = 0;
+ reflect_interruption(isr, regs, IA64_EXTINT_VECTOR);
}
void reflect_event(struct pt_regs *regs)
@@ -127,24 +134,25 @@ void reflect_event(struct pt_regs *regs)
if (!event_pending(v))
return;
- if (!PSCB(v,interrupt_collection_enabled))
- printf("psr.ic off, delivering event, ipsr=%lx,iip=%lx,isr=%lx,viip=0x%lx\n",
+ if (!PSCB(v, interrupt_collection_enabled))
+ printk("psr.ic off, delivering event, ipsr=%lx,iip=%lx,"
+ "isr=%lx,viip=0x%lx\n",
regs->cr_ipsr, regs->cr_iip, isr, PSCB(v, iip));
- PSCB(v,unat) = regs->ar_unat; // not sure if this is really needed?
- PSCB(v,precover_ifs) = regs->cr_ifs;
+ PSCB(v, unat) = regs->ar_unat; // not sure if this is really needed?
+ PSCB(v, precover_ifs) = regs->cr_ifs;
vcpu_bsw0(v);
- PSCB(v,ipsr) = vcpu_get_ipsr_int_state(v,regs->cr_ipsr);
- PSCB(v,isr) = isr;
- PSCB(v,iip) = regs->cr_iip;
- PSCB(v,ifs) = 0;
- PSCB(v,incomplete_regframe) = 0;
+ PSCB(v, ipsr) = vcpu_get_ipsr_int_state(v, regs->cr_ipsr);
+ PSCB(v, isr) = isr;
+ PSCB(v, iip) = regs->cr_iip;
+ PSCB(v, ifs) = 0;
+ PSCB(v, incomplete_regframe) = 0;
regs->cr_iip = v->arch.event_callback_ip;
regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
regs->r31 = current->domain->arch.shared_info_va + XSI_IPSR_OFS;
v->vcpu_info->evtchn_upcall_mask = 1;
- PSCB(v,interrupt_collection_enabled) = 0;
+ PSCB(v, interrupt_collection_enabled) = 0;
}
// ONLY gets called from ia64_leave_kernel
@@ -158,25 +166,25 @@ void deliver_pending_interrupt(struct pt_regs *regs)
if (!is_idle_domain(d) && user_mode(regs)) {
if (vcpu_deliverable_interrupts(v))
reflect_extint(regs);
- else if (PSCB(v,pending_interruption))
+ else if (PSCB(v, pending_interruption))
++pending_false_positive;
}
}
-static int
-handle_lazy_cover(struct vcpu *v, struct pt_regs *regs)
+static int handle_lazy_cover(struct vcpu *v, struct pt_regs *regs)
{
- if (!PSCB(v,interrupt_collection_enabled)) {
- PSCB(v,ifs) = regs->cr_ifs;
- PSCB(v,incomplete_regframe) = 1;
+ if (!PSCB(v, interrupt_collection_enabled)) {
+ PSCB(v, ifs) = regs->cr_ifs;
+ PSCB(v, incomplete_regframe) = 1;
regs->cr_ifs = 0;
perfc_incrc(lazy_cover);
- return(1); // retry same instruction with cr.ifs off
+ return 1; // retry same instruction with cr.ifs off
}
- return(0);
+ return 0;
}
-void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
+void ia64_do_page_fault(unsigned long address, unsigned long isr,
+ struct pt_regs *regs, unsigned long itir)
{
unsigned long iip = regs->cr_iip, iha;
// FIXME should validate address here
@@ -187,23 +195,28 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_reg
u64 logps;
if ((isr & IA64_ISR_SP)
- || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
- {
+ || ((isr & IA64_ISR_NA)
+ && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
/*
- * This fault was due to a speculative load or lfetch.fault, set the "ed"
- * bit in the psr to ensure forward progress. (Target register will get a
- * NaT for ld.s, lfetch will be canceled.)
+ * This fault was due to a speculative load or lfetch.fault,
+ * set the "ed" bit in the psr to ensure forward progress.
+ * (Target register will get a NaT for ld.s, lfetch will be
+ * canceled.)
*/
ia64_psr(regs)->ed = 1;
return;
}
again:
- fault = vcpu_translate(current,address,is_data,&pteval,&itir,&iha);
+ fault = vcpu_translate(current, address, is_data, &pteval,
+ &itir, &iha);
if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) {
struct p2m_entry entry;
- pteval = translate_domain_pte(pteval, address, itir, &logps, &entry);
- vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,logps);
+ unsigned long m_pteval;
+ m_pteval = translate_domain_pte(pteval, address, itir,
+ &logps, &entry);
+ vcpu_itc_no_srlz(current, (is_data ? 2 : 1) | 4,
+ address, m_pteval, pteval, logps, &entry);
if ((fault == IA64_USE_TLB && !current->arch.dtlb.pte.p) ||
p2m_entry_retry(&entry)) {
/* dtlb has been purged in-between. This dtlb was
@@ -221,17 +234,18 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_reg
if (is_ptc_l_needed)
vcpu_ptc_l(current, address, logps);
- if (!user_mode (regs)) {
+ if (!user_mode(regs)) {
/* The fault occurs inside Xen. */
if (!ia64_done_with_exception(regs)) {
// should never happen. If it does, region 0 addr may
// indicate a bad xen pointer
printk("*** xen_handle_domain_access: exception table"
- " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n",
- iip, address);
- panic_domain(regs,"*** xen_handle_domain_access: exception table"
- " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n",
- iip, address);
+ " lookup failed, iip=0x%lx, addr=0x%lx, "
+ "spinning...\n", iip, address);
+ panic_domain(regs, "*** xen_handle_domain_access: "
+ "exception table lookup failed, "
+ "iip=0x%lx, addr=0x%lx, spinning...\n",
+ iip, address);
}
return;
}
@@ -239,45 +253,47 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_reg
if ((isr & IA64_ISR_IR) && handle_lazy_cover(current, regs))
return;
- if (!PSCB(current,interrupt_collection_enabled)) {
- check_bad_nested_interruption(isr,regs,fault);
- //printf("Delivering NESTED DATA TLB fault\n");
+ if (!PSCB(current, interrupt_collection_enabled)) {
+ check_bad_nested_interruption(isr, regs, fault);
+ //printk("Delivering NESTED DATA TLB fault\n");
fault = IA64_DATA_NESTED_TLB_VECTOR;
- regs->cr_iip = ((unsigned long) PSCBX(current,iva) + fault) & ~0xffUL;
- regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
+ regs->cr_iip =
+ ((unsigned long)PSCBX(current, iva) + fault) & ~0xffUL;
+ regs->cr_ipsr =
+ (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
// NOTE: nested trap must NOT pass PSCB address
//regs->r31 = (unsigned long) &PSCB(current);
perfc_incra(slow_reflect, fault >> 8);
return;
}
- PSCB(current,itir) = itir;
- PSCB(current,iha) = iha;
- PSCB(current,ifa) = address;
+ PSCB(current, itir) = itir;
+ PSCB(current, iha) = iha;
+ PSCB(current, ifa) = address;
reflect_interruption(isr, regs, fault);
}
fpswa_interface_t *fpswa_interface = 0;
-void trap_init (void)
+void trap_init(void)
{
if (ia64_boot_param->fpswa)
- /* FPSWA fixup: make the interface pointer a virtual address: */
+ /* FPSWA fixup: make the interface pointer a virtual address */
fpswa_interface = __va(ia64_boot_param->fpswa);
else
printk("No FPSWA supported.\n");
}
static fpswa_ret_t
-fp_emulate (int fp_fault, void *bundle, unsigned long *ipsr,
- unsigned long *fpsr, unsigned long *isr, unsigned long *pr,
- unsigned long *ifs, struct pt_regs *regs)
+fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr,
+ unsigned long *fpsr, unsigned long *isr, unsigned long *pr,
+ unsigned long *ifs, struct pt_regs *regs)
{
fp_state_t fp_state;
fpswa_ret_t ret;
if (!fpswa_interface)
- return ((fpswa_ret_t) {-1, 0, 0, 0});
+ return (fpswa_ret_t) {-1, 0, 0, 0};
memset(&fp_state, 0, sizeof(fp_state_t));
@@ -286,7 +302,7 @@ fp_emulate (int fp_fault, void *bundle, unsigned long *ipsr,
* kernel, so set those bits in the mask and set the low volatile
* pointer to point to these registers.
*/
- fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */
+ fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */
fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) &regs->f6;
/*
@@ -300,8 +316,8 @@ fp_emulate (int fp_fault, void *bundle, unsigned long *ipsr,
* unsigned long *pifs,
* void *fp_state);
*/
- ret = (*fpswa_interface->fpswa)(fp_fault, bundle,
- ipsr, fpsr, isr, pr, ifs, &fp_state);
+ ret = (*fpswa_interface->fpswa) (fp_fault, bundle,
+ ipsr, fpsr, isr, pr, ifs, &fp_state);
return ret;
}
@@ -310,7 +326,7 @@ fp_emulate (int fp_fault, void *bundle, unsigned long *ipsr,
* Handle floating-point assist faults and traps for domain.
*/
unsigned long
-handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
+handle_fpu_swa(int fp_fault, struct pt_regs *regs, unsigned long isr)
{
struct vcpu *v = current;
IA64_BUNDLE bundle;
@@ -320,7 +336,8 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
fault_ip = regs->cr_iip;
/*
* When the FP trap occurs, the trapping instruction is completed.
- * If ipsr.ri == 0, there is the trapping instruction in previous bundle.
+ * If ipsr.ri == 0, there is the trapping instruction in previous
+ * bundle.
*/
if (!fp_fault && (ia64_psr(regs)->ri == 0))
fault_ip -= 16;
@@ -328,8 +345,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
if (VMX_DOMAIN(current)) {
if (IA64_RETRY == __vmx_get_domain_bundle(fault_ip, &bundle))
return IA64_RETRY;
- }
- else
+ } else
bundle = __get_domain_bundle(fault_ip);
if (!bundle.i64[0] && !bundle.i64[1]) {
@@ -344,20 +360,20 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
if (ret.status) {
PSCBX(v, fpswa_ret) = ret;
printk("%s(%s): fp_emulate() returned %ld\n",
- __FUNCTION__, fp_fault?"fault":"trap", ret.status);
+ __FUNCTION__, fp_fault ? "fault" : "trap", ret.status);
}
return ret.status;
}
void
-ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
- unsigned long iim, unsigned long itir, unsigned long arg5,
- unsigned long arg6, unsigned long arg7, unsigned long stack)
+ia64_fault(unsigned long vector, unsigned long isr, unsigned long ifa,
+ unsigned long iim, unsigned long itir, unsigned long arg5,
+ unsigned long arg6, unsigned long arg7, unsigned long stack)
{
- struct pt_regs *regs = (struct pt_regs *) &stack;
+ struct pt_regs *regs = (struct pt_regs *)&stack;
unsigned long code;
- static const char * const reason[] = {
+ static const char *const reason[] = {
"IA-64 Illegal Operation fault",
"IA-64 Privileged Operation fault",
"IA-64 Privileged Register fault",
@@ -370,123 +386,123 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
"Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
};
- printf("ia64_fault, vector=0x%lx, ifa=0x%016lx, iip=0x%016lx, ipsr=0x%016lx, isr=0x%016lx\n",
- vector, ifa, regs->cr_iip, regs->cr_ipsr, isr);
-
+ printk("ia64_fault, vector=0x%lx, ifa=0x%016lx, iip=0x%016lx, "
+ "ipsr=0x%016lx, isr=0x%016lx\n", vector, ifa,
+ regs->cr_iip, regs->cr_ipsr, isr);
- if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
+ if ((isr & IA64_ISR_NA) &&
+ ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
/*
- * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel
- * the lfetch.
+ * This fault was due to lfetch.fault, set "ed" bit in the
+ * psr to cancel the lfetch.
*/
ia64_psr(regs)->ed = 1;
- printf("ia64_fault: handled lfetch.fault\n");
+ printk("ia64_fault: handled lfetch.fault\n");
return;
}
switch (vector) {
- case 0:
+ case 0:
printk("VHPT Translation.\n");
break;
-
- case 4:
+
+ case 4:
printk("Alt DTLB.\n");
break;
-
- case 6:
+
+ case 6:
printk("Instruction Key Miss.\n");
break;
- case 7:
+ case 7:
printk("Data Key Miss.\n");
break;
- case 8:
+ case 8:
printk("Dirty-bit.\n");
break;
- case 20:
+ case 20:
printk("Page Not Found.\n");
break;
- case 21:
+ case 21:
printk("Key Permission.\n");
break;
- case 22:
+ case 22:
printk("Instruction Access Rights.\n");
break;
- case 24: /* General Exception */
+ case 24: /* General Exception */
code = (isr >> 4) & 0xf;
printk("General Exception: %s%s.\n", reason[code],
- (code == 3) ? ((isr & (1UL << 37)) ? " (RSE access)" :
+ (code == 3) ? ((isr & (1UL << 37)) ? " (RSE access)" :
" (data access)") : "");
if (code == 8) {
-# ifdef CONFIG_IA64_PRINT_HAZARDS
- printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n",
- current->comm, current->pid,
- regs->cr_iip + ia64_psr(regs)->ri,
- regs->pr);
-# endif
- printf("ia64_fault: returning on hazard\n");
+#ifdef CONFIG_IA64_PRINT_HAZARDS
+ printk("%s[%d]: possible hazard @ ip=%016lx "
+ "(pr = %016lx)\n", current->comm, current->pid,
+ regs->cr_iip + ia64_psr(regs)->ri, regs->pr);
+#endif
+ printk("ia64_fault: returning on hazard\n");
return;
}
break;
- case 25:
+ case 25:
printk("Disabled FP-Register.\n");
break;
- case 26:
+ case 26:
printk("NaT consumption.\n");
break;
- case 29:
+ case 29:
printk("Debug.\n");
break;
- case 30:
+ case 30:
printk("Unaligned Reference.\n");
break;
- case 31:
+ case 31:
printk("Unsupported data reference.\n");
break;
- case 32:
+ case 32:
printk("Floating-Point Fault.\n");
break;
- case 33:
+ case 33:
printk("Floating-Point Trap.\n");
break;
- case 34:
+ case 34:
printk("Lower Privilege Transfer Trap.\n");
break;
- case 35:
+ case 35:
printk("Taken Branch Trap.\n");
break;
- case 36:
+ case 36:
printk("Single Step Trap.\n");
break;
-
- case 45:
+
+ case 45:
printk("IA-32 Exception.\n");
break;
- case 46:
+ case 46:
printk("IA-32 Intercept.\n");
break;
- case 47:
+ case 47:
printk("IA-32 Interrupt.\n");
break;
- default:
+ default:
printk("Fault %lu\n", vector);
break;
}
@@ -497,65 +513,65 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
unsigned long running_on_sim = 0;
-
/* Also read in hyperprivop.S */
int first_break = 0;
void
-ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim)
+ia64_handle_break(unsigned long ifa, struct pt_regs *regs, unsigned long isr,
+ unsigned long iim)
{
struct domain *d = current->domain;
struct vcpu *v = current;
IA64FAULT vector;
- if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant
- do_ssc(vcpu_get_gr(current,36), regs);
- }
+ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant
+ do_ssc(vcpu_get_gr(current, 36), regs);
+ }
#ifdef CRASH_DEBUG
else if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) {
if (iim == 0)
show_registers(regs);
- debugger_trap_fatal(0 /* don't care */, regs);
- }
+ debugger_trap_fatal(0 /* don't care */ , regs);
+ }
#endif
- else if (iim == d->arch.breakimm &&
- ia64_get_cpl(regs->cr_ipsr) == 2) {
+ else if (iim == d->arch.breakimm && ia64_get_cpl(regs->cr_ipsr) == 2) {
/* by default, do not continue */
v->arch.hypercall_continuation = 0;
if ((vector = ia64_hypercall(regs)) == IA64_NO_FAULT) {
if (!PSCBX(v, hypercall_continuation))
vcpu_increment_iip(current);
- }
- else reflect_interruption(isr, regs, vector);
- }
- else if (!PSCB(v,interrupt_collection_enabled)) {
- if (ia64_hyperprivop(iim,regs))
+ } else
+ reflect_interruption(isr, regs, vector);
+ } else if (!PSCB(v, interrupt_collection_enabled)) {
+ if (ia64_hyperprivop(iim, regs))
vcpu_increment_iip(current);
- }
- else {
- if (iim == 0)
+ } else {
+ if (iim == 0)
die_if_kernel("bug check", regs, iim);
- PSCB(v,iim) = iim;
- reflect_interruption(isr,regs,IA64_BREAK_VECTOR);
+ PSCB(v, iim) = iim;
+ reflect_interruption(isr, regs, IA64_BREAK_VECTOR);
}
}
void
-ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir)
+ia64_handle_privop(unsigned long ifa, struct pt_regs *regs, unsigned long isr,
+ unsigned long itir)
{
IA64FAULT vector;
- vector = priv_emulate(current,regs,isr);
+ vector = priv_emulate(current, regs, isr);
if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) {
// Note: if a path results in a vector to reflect that requires
// iha/itir (e.g. vcpu_force_data_miss), they must be set there
- reflect_interruption(isr,regs,vector);
+ reflect_interruption(isr, regs, vector);
}
}
void
-ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector)
+ia64_handle_reflection(unsigned long ifa, struct pt_regs *regs,
+ unsigned long isr, unsigned long iim,
+ unsigned long vector)
{
struct vcpu *v = current;
unsigned long check_lazy_cover = 0;
@@ -563,102 +579,125 @@ ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long i
unsigned long status;
/* Following faults shouldn'g be seen from Xen itself */
- BUG_ON (!(psr & IA64_PSR_CPL));
-
- switch(vector) {
- case 8:
- vector = IA64_DIRTY_BIT_VECTOR; break;
- case 9:
- vector = IA64_INST_ACCESS_BIT_VECTOR; break;
- case 10:
+ BUG_ON(!(psr & IA64_PSR_CPL));
+
+ switch (vector) {
+ case 8:
+ vector = IA64_DIRTY_BIT_VECTOR;
+ break;
+ case 9:
+ vector = IA64_INST_ACCESS_BIT_VECTOR;
+ break;
+ case 10:
check_lazy_cover = 1;
- vector = IA64_DATA_ACCESS_BIT_VECTOR; break;
- case 20:
+ vector = IA64_DATA_ACCESS_BIT_VECTOR;
+ break;
+ case 20:
check_lazy_cover = 1;
- vector = IA64_PAGE_NOT_PRESENT_VECTOR; break;
- case 22:
- vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break;
- case 23:
+ vector = IA64_PAGE_NOT_PRESENT_VECTOR;
+ break;
+ case 22:
+ vector = IA64_INST_ACCESS_RIGHTS_VECTOR;
+ break;
+ case 23:
check_lazy_cover = 1;
- vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break;
- case 25:
+ vector = IA64_DATA_ACCESS_RIGHTS_VECTOR;
+ break;
+ case 25:
vector = IA64_DISABLED_FPREG_VECTOR;
break;
- case 26:
+ case 26:
if (((isr >> 4L) & 0xfL) == 1) {
/* Fault is due to a register NaT consumption fault. */
//regs->eml_unat = 0; FIXME: DO WE NEED THIS??
- printf("ia64_handle_reflection: handling regNaT fault\n");
- vector = IA64_NAT_CONSUMPTION_VECTOR; break;
+ printk("ia64_handle_reflection: handling regNaT "
+ "fault\n");
+ vector = IA64_NAT_CONSUMPTION_VECTOR;
+ break;
}
#if 1
// pass null pointer dereferences through with no error
// but retain debug output for non-zero ifa
if (!ifa) {
- vector = IA64_NAT_CONSUMPTION_VECTOR; break;
+ vector = IA64_NAT_CONSUMPTION_VECTOR;
+ break;
}
#endif
#ifdef CONFIG_PRIVIFY
/* Some privified operations are coded using reg+64 instead
of reg. */
- printf("*** NaT fault... attempting to handle as privop\n");
- printf("isr=%016lx, ifa=%016lx, iip=%016lx, ipsr=%016lx\n",
+ printk("*** NaT fault... attempting to handle as privop\n");
+ printk("isr=%016lx, ifa=%016lx, iip=%016lx, ipsr=%016lx\n",
isr, ifa, regs->cr_iip, psr);
//regs->eml_unat = 0; FIXME: DO WE NEED THIS???
// certain NaT faults are higher priority than privop faults
- vector = priv_emulate(v,regs,isr);
+ vector = priv_emulate(v, regs, isr);
if (vector == IA64_NO_FAULT) {
- printf("*** Handled privop masquerading as NaT fault\n");
+ printk("*** Handled privop masquerading as NaT "
+ "fault\n");
return;
}
#endif
- vector = IA64_NAT_CONSUMPTION_VECTOR; break;
- case 27:
- //printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc());
- PSCB(current,iim) = iim;
- vector = IA64_SPECULATION_VECTOR; break;
- case 30:
+ vector = IA64_NAT_CONSUMPTION_VECTOR;
+ break;
+ case 27:
+ //printk("*** Handled speculation vector, itc=%lx!\n",
+ // ia64_get_itc());
+ PSCB(current, iim) = iim;
+ vector = IA64_SPECULATION_VECTOR;
+ break;
+ case 30:
// FIXME: Should we handle unaligned refs in Xen??
- vector = IA64_UNALIGNED_REF_VECTOR; break;
- case 32:
+ vector = IA64_UNALIGNED_REF_VECTOR;
+ break;
+ case 32:
status = handle_fpu_swa(1, regs, isr);
if (!status) {
- vcpu_increment_iip(v);
- return;
+ vcpu_increment_iip(v);
+ return;
}
// fetch code fail
if (IA64_RETRY == status)
return;
- printf("ia64_handle_reflection: handling FP fault\n");
- vector = IA64_FP_FAULT_VECTOR; break;
- case 33:
+ printk("ia64_handle_reflection: handling FP fault\n");
+ vector = IA64_FP_FAULT_VECTOR;
+ break;
+ case 33:
status = handle_fpu_swa(0, regs, isr);
if (!status)
return;
// fetch code fail
if (IA64_RETRY == status)
return;
- printf("ia64_handle_reflection: handling FP trap\n");
- vector = IA64_FP_TRAP_VECTOR; break;
- case 34:
- printf("ia64_handle_reflection: handling lowerpriv trap\n");
- vector = IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR; break;
- case 35:
- printf("ia64_handle_reflection: handling taken branch trap\n");
- vector = IA64_TAKEN_BRANCH_TRAP_VECTOR; break;
- case 36:
- printf("ia64_handle_reflection: handling single step trap\n");
- vector = IA64_SINGLE_STEP_TRAP_VECTOR; break;
-
- default:
- printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector);
- while(vector);
+ printk("ia64_handle_reflection: handling FP trap\n");
+ vector = IA64_FP_TRAP_VECTOR;
+ break;
+ case 34:
+ printk("ia64_handle_reflection: handling lowerpriv trap\n");
+ vector = IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR;
+ break;
+ case 35:
+ printk("ia64_handle_reflection: handling taken branch trap\n");
+ vector = IA64_TAKEN_BRANCH_TRAP_VECTOR;
+ break;
+ case 36:
+ printk("ia64_handle_reflection: handling single step trap\n");
+ vector = IA64_SINGLE_STEP_TRAP_VECTOR;
+ break;
+
+ default:
+ printk("ia64_handle_reflection: unhandled vector=0x%lx\n",
+ vector);
+ while (vector)
+ /* spin */;
return;
}
- if (check_lazy_cover && (isr & IA64_ISR_IR) && handle_lazy_cover(v, regs)) return;
- PSCB(current,ifa) = ifa;
- PSCB(current,itir) = vcpu_get_itir_on_fault(v,ifa);
- reflect_interruption(isr,regs,vector);
+ if (check_lazy_cover && (isr & IA64_ISR_IR) &&
+ handle_lazy_cover(v, regs))
+ return;
+ PSCB(current, ifa) = ifa;
+ PSCB(current, itir) = vcpu_get_itir_on_fault(v, ifa);
+ reflect_interruption(isr, regs, vector);
}
void
@@ -677,7 +716,7 @@ ia64_shadow_fault(unsigned long ifa, unsigned long itir,
- reflecting or not the fault (the virtual Dirty bit must be
extracted to decide).
Unfortunatly these informations are not immediatly available!
- */
+ */
/* Extract the metaphysical address.
Try to get it from VHPT and M2P as we need the flags. */
@@ -687,8 +726,7 @@ ia64_shadow_fault(unsigned long ifa, unsigned long itir,
/* The VHPT entry is valid. */
gpfn = get_gpfn_from_mfn((pte & _PAGE_PPN_MASK) >> PAGE_SHIFT);
BUG_ON(gpfn == INVALID_M2P_ENTRY);
- }
- else {
+ } else {
unsigned long itir, iha;
IA64FAULT fault;
@@ -711,14 +749,14 @@ ia64_shadow_fault(unsigned long ifa, unsigned long itir,
}
/* Set the dirty bit in the bitmap. */
- shadow_mark_page_dirty (d, gpfn);
+ shadow_mark_page_dirty(d, gpfn);
/* Update the local TC/VHPT and decides wether or not the fault should
be reflected.
SMP note: we almost ignore the other processors. The shadow_bitmap
has been atomically updated. If the dirty fault happen on another
processor, it will do its job.
- */
+ */
if (pte != 0) {
/* We will know how to handle the fault. */
@@ -729,21 +767,19 @@ ia64_shadow_fault(unsigned long ifa, unsigned long itir,
cpu VHPT owner can write page_flags. */
if (vlfe)
vlfe->page_flags = pte | _PAGE_D;
-
+
/* Purge the TC locally.
It will be reloaded from the VHPT iff the
VHPT entry is still valid. */
ia64_ptcl(ifa, PAGE_SHIFT << 2);
atomic64_inc(&d->arch.shadow_fault_count);
- }
- else {
+ } else {
/* Reflect.
In this case there is no need to purge. */
ia64_handle_reflection(ifa, regs, isr, 0, 8);
}
- }
- else {
+ } else {
/* We don't know wether or not the fault must be
reflected. The VHPT entry is not valid. */
/* FIXME: in metaphysical mode, we could do an ITC now. */
diff --git a/xen/arch/ia64/xen/flushtlb.c b/xen/arch/ia64/xen/flushtlb.c
new file mode 100644
index 0000000000..0c77c1b6df
--- /dev/null
+++ b/xen/arch/ia64/xen/flushtlb.c
@@ -0,0 +1,117 @@
+/******************************************************************************
+ * flushtlb.c
+ * based on x86 flushtlb.c
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <xen/sched.h>
+#include <xen/softirq.h>
+#include <asm/vcpu.h>
+#include <asm/vhpt.h>
+#include <asm/flushtlb.h>
+
+/* Debug builds: Wrap frequently to stress-test the wrap logic. */
+#ifdef NDEBUG
+#define WRAP_MASK (0xFFFFFFFFU)
+#else
+#define WRAP_MASK (0x000003FFU)
+#endif
+
+volatile u32 tlbflush_clock = 1U; /* 1 greater than tlbflush_time. */
+DEFINE_PER_CPU(volatile u32, tlbflush_time);
+
+u32
+tlbflush_clock_inc_and_return(void)
+{
+ u32 t, t1, t2;
+
+ t = tlbflush_clock;
+ do {
+ t1 = t2 = t;
+ /* Clock wrapped: someone else is leading a global TLB shootdown. */
+ if (unlikely(t1 == 0))
+ return t2;
+ t2 = (t + 1) & WRAP_MASK;
+ t = ia64_cmpxchg(acq, &tlbflush_clock, t1, t2, sizeof(tlbflush_clock));
+ } while (unlikely(t != t1));
+
+ /* Clock wrapped: we will lead a global TLB shootdown. */
+ if (unlikely(t2 == 0))
+ raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ);
+
+ return t2;
+}
+
+void
+new_tlbflush_clock_period(void)
+{
+ /*
+ *XXX TODO
+ * If flushing all vcpu's vhpt takes too long, it can be done backgroundly.
+ * In such case tlbflush time comparison is done using only 31bit
+ * similar to linux jiffies comparison.
+ * vhpt should be flushed gradually before wraping 31bits.
+ *
+ * Sample calculation.
+ * Currently Xen/IA64 can create up to 64 domains at the same time.
+ * Vhpt size is currently 64KB. (This might be changed later though)
+ * Suppose each domains have 4 vcpus (or 16 vcpus).
+ * then the memory size which must be flushed is 16MB (64MB).
+ */
+ struct domain* d;
+ struct vcpu* v;
+ /* flush all vhpt of vcpu of all existing domain. */
+ read_lock(&domlist_lock);
+ for_each_domain(d) {
+ for_each_vcpu(d, v) {
+ vcpu_purge_tr_entry(&PSCBX(v,dtlb));
+ vcpu_purge_tr_entry(&PSCBX(v,itlb));
+ }
+ }
+ smp_mb();
+ for_each_domain(d) {
+ for_each_vcpu(d, v) {
+ if (HAS_PERVCPU_VHPT(v->domain))
+ vcpu_vhpt_flush(v);
+ }
+ }
+ read_unlock(&domlist_lock);
+ /* unlock has release semantics */
+
+ /* flush all vhpt of physical cpu and mTLB */
+ on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1);
+
+ /*
+ * if global TLB shootdown is finished, increment tlbflush_time
+ * atomic operation isn't necessary because we know that tlbflush_clock
+ * stays 0.
+ */
+ tlbflush_clock++;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c
index 77f1b288da..28d827e975 100644
--- a/xen/arch/ia64/xen/fw_emul.c
+++ b/xen/arch/ia64/xen/fw_emul.c
@@ -16,7 +16,6 @@
*
*/
#include <xen/config.h>
-#include <xen/console.h>
#include <asm/system.h>
#include <asm/pgalloc.h>
@@ -27,8 +26,13 @@
#include <public/sched.h>
#include "hpsim_ssc.h"
#include <asm/vcpu.h>
+#include <asm/vmx_vcpu.h>
#include <asm/dom_fw.h>
#include <asm/uaccess.h>
+#include <xen/console.h>
+#include <xen/hypercall.h>
+
+static DEFINE_SPINLOCK(efi_time_services_lock);
extern unsigned long running_on_sim;
@@ -73,20 +77,20 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
r9 = value;
}
else
- printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
+ printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
break;
case SAL_PCI_CONFIG_WRITE:
if (current->domain == dom0) {
if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
(in4 > 1) ||
(in2 > 8) || (in2 & (in2-1)))
- printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
+ printk("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
in1,in4,in2,in3);
// note that args are in a different order!!
status = ia64_sal_pci_config_write(in1,in4,in2,in3);
}
else
- printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
+ printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
break;
case SAL_SET_VECTORS:
if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
@@ -102,7 +106,7 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
}
}
else
- printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
+ printk("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
in1);
break;
case SAL_GET_STATE_INFO:
@@ -119,10 +123,10 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
/* Noop. */
break;
case SAL_MC_RENDEZ:
- printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
+ printk("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
break;
case SAL_MC_SET_PARAMS:
- printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
+ printk("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
break;
case SAL_CACHE_FLUSH:
if (1) {
@@ -139,13 +143,13 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
}
break;
case SAL_CACHE_INIT:
- printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
+ printk("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
break;
case SAL_UPDATE_PAL:
- printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
+ printk("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
break;
default:
- printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
+ printk("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
status = -1;
break;
}
@@ -173,6 +177,10 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
break;
case PAL_FREQ_BASE:
status = ia64_pal_freq_base(&r9);
+ if (status == PAL_STATUS_UNIMPLEMENTED) {
+ status = ia64_sal_freq_base(0, &r9, &r10);
+ r10 = 0;
+ }
break;
case PAL_PROC_GET_FEATURES:
status = ia64_pal_proc_get_features(&r9,&r10,&r11);
@@ -212,10 +220,22 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
status = ia64_pal_cache_summary(&r9,&r10);
break;
case PAL_VM_SUMMARY:
- {
+ if (VMX_DOMAIN(current)) {
+ pal_vm_info_1_u_t v1;
+ pal_vm_info_2_u_t v2;
+ status = ia64_pal_vm_summary((pal_vm_info_1_u_t *)&v1,
+ (pal_vm_info_2_u_t *)&v2);
+ v1.pal_vm_info_1_s.max_itr_entry = NITRS - 1;
+ v1.pal_vm_info_1_s.max_dtr_entry = NDTRS - 1;
+ v2.pal_vm_info_2_s.impl_va_msb -= 1;
+ v2.pal_vm_info_2_s.rid_size =
+ current->domain->arch.rid_bits;
+ r9 = v1.pvi1_val;
+ r10 = v2.pvi2_val;
+ } else {
/* Use xen-specific values.
hash_tag_id is somewhat random! */
- const pal_vm_info_1_u_t v1 =
+ static const pal_vm_info_1_u_t v1 =
{.pal_vm_info_1_s =
{ .vw = 1,
.phys_add_size = 44,
@@ -232,17 +252,22 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
.num_tc_levels = 1
#endif
}};
- const pal_vm_info_2_u_t v2 =
- { .pal_vm_info_2_s =
- { .impl_va_msb = 50,
- .rid_size = current->domain->arch.rid_bits,
- .reserved = 0 }};
+ pal_vm_info_2_u_t v2;
+ v2.pvi2_val = 0;
+ v2.pal_vm_info_2_s.rid_size =
+ current->domain->arch.rid_bits;
+ v2.pal_vm_info_2_s.impl_va_msb = 50;
r9 = v1.pvi1_val;
r10 = v2.pvi2_val;
status = PAL_STATUS_SUCCESS;
}
break;
case PAL_VM_INFO:
+ if (VMX_DOMAIN(current)) {
+ status = ia64_pal_vm_info(in1, in2,
+ (pal_tc_info_u_t *)&r9, &r10);
+ break;
+ }
#ifdef VHPT_GLOBAL
if (in1 == 0 && in2 == 2) {
/* Level 1: VHPT */
@@ -294,9 +319,20 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
status = ia64_pal_register_info(in1, &r9, &r10);
break;
case PAL_CACHE_FLUSH:
- /* FIXME */
- printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
- BUG();
+ /* Always call Host Pal in int=0 */
+ in2 &= ~PAL_CACHE_FLUSH_CHK_INTRS;
+
+ /*
+ * Call Host PAL cache flush
+ * Clear psr.ic when call PAL_CACHE_FLUSH
+ */
+ r10 = in3;
+ status = ia64_pal_cache_flush(in1, in2, &r10, &r9);
+
+ if (status != 0)
+ panic_domain(NULL, "PAL_CACHE_FLUSH ERROR, "
+ "status %lx", status);
+
break;
case PAL_PERF_MON_INFO:
{
@@ -343,15 +379,26 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
}
break;
case PAL_HALT:
- if (current->domain == dom0) {
- printf ("Domain0 halts the machine\n");
- console_start_sync();
- (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
- }
- else
- domain_shutdown (current->domain,
- SHUTDOWN_poweroff);
- break;
+ if (current->domain == dom0) {
+ printk ("Domain0 halts the machine\n");
+ console_start_sync();
+ (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
+ }
+ else
+ domain_shutdown(current->domain, SHUTDOWN_poweroff);
+ break;
+ case PAL_HALT_LIGHT:
+ if (VMX_DOMAIN(current)) {
+ /* Called by VTI. */
+ if (!is_unmasked_irq(current))
+ do_sched_op_compat(SCHEDOP_block, 0);
+ status = PAL_STATUS_SUCCESS;
+ }
+ break;
+ case PAL_PLATFORM_ADDR:
+ if (VMX_DOMAIN(current))
+ status = PAL_STATUS_SUCCESS;
+ break;
default:
printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
index);
@@ -400,7 +447,6 @@ efi_emulate_get_time(
struct page_info *tc_page = NULL;
efi_status_t status = 0;
- //printf("efi_get_time(%016lx,%016lx) called\n", tv_addr, tc_addr);
tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);
if (*fault != IA64_NO_FAULT)
goto errout;
@@ -410,9 +456,9 @@ efi_emulate_get_time(
goto errout;
}
- //printf("efi_get_time(%016lx,%016lx) translated to xen virtual address\n", tv, tc);
+ spin_lock(&efi_time_services_lock);
status = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
- //printf("efi_get_time returns %lx\n", status);
+ spin_unlock(&efi_time_services_lock);
errout:
if (tc_page != NULL)
@@ -438,7 +484,9 @@ efi_emulate_set_time(
if (*fault != IA64_NO_FAULT)
goto errout;
+ spin_lock(&efi_time_services_lock);
status = (*efi.set_time)((efi_time_t *)tv);
+ spin_unlock(&efi_time_services_lock);
errout:
if (tv_page != NULL)
@@ -473,9 +521,11 @@ efi_emulate_get_wakeup_time(
if (*fault != IA64_NO_FAULT)
goto errout;
+ spin_lock(&efi_time_services_lock);
status = (*efi.get_wakeup_time)((efi_bool_t *)enabled,
(efi_bool_t *)pending,
(efi_time_t *)tv);
+ spin_unlock(&efi_time_services_lock);
errout:
if (e_page != NULL)
@@ -506,8 +556,10 @@ efi_emulate_set_wakeup_time(
goto errout;
}
+ spin_lock(&efi_time_services_lock);
status = (*efi.set_wakeup_time)((efi_bool_t)enabled,
(efi_time_t *)tv);
+ spin_unlock(&efi_time_services_lock);
errout:
if (tv_page != NULL)
@@ -666,14 +718,14 @@ efi_emulate_set_virtual_address_map(
fpswa_interface_t *fpswa_inf = d->arch.fpswa_inf;
if (descriptor_version != EFI_MEMDESC_VERSION) {
- printf ("efi_emulate_set_virtual_address_map: memory "
+ printk ("efi_emulate_set_virtual_address_map: memory "
"descriptor version unmatched (%d vs %d)\n",
(int)descriptor_version, EFI_MEMDESC_VERSION);
return EFI_INVALID_PARAMETER;
}
if (descriptor_size != sizeof(efi_memory_desc_t)) {
- printf ("efi_emulate_set_virtual_address_map: memory descriptor size unmatched\n");
+ printk ("efi_emulate_set_virtual_address_map: memory descriptor size unmatched\n");
return EFI_INVALID_PARAMETER;
}
@@ -686,7 +738,7 @@ efi_emulate_set_virtual_address_map(
for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
if (copy_from_user(&entry, p, sizeof(efi_memory_desc_t))) {
- printf ("efi_emulate_set_virtual_address_map: copy_from_user() fault. addr=0x%p\n", p);
+ printk ("efi_emulate_set_virtual_address_map: copy_from_user() fault. addr=0x%p\n", p);
return EFI_UNSUPPORTED;
}
@@ -814,7 +866,7 @@ efi_emulator (struct pt_regs *regs, IA64FAULT *fault)
status = EFI_UNSUPPORTED;
break;
default:
- printf("unknown ia64 fw hypercall %lx\n", regs->r2);
+ printk("unknown ia64 fw hypercall %lx\n", regs->r2);
status = EFI_UNSUPPORTED;
}
@@ -835,7 +887,7 @@ do_ssc(unsigned long ssc, struct pt_regs *regs)
case SSC_PUTCHAR:
buf[0] = arg0;
buf[1] = '\0';
- printf(buf);
+ printk(buf);
break;
case SSC_GETCHAR:
retval = ia64_ssc(0,0,0,0,ssc);
@@ -848,7 +900,7 @@ do_ssc(unsigned long ssc, struct pt_regs *regs)
/**/ stat = (struct ssc_disk_stat *)__va(arg0);
///**/ if (stat->fd == last_fd) stat->count = last_count;
/**/ stat->count = last_count;
-//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
+//if (last_count >= PAGE_SIZE) printk("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
///**/ retval = ia64_ssc(arg0,0,0,0,ssc);
/**/ retval = 0;
}
@@ -857,7 +909,7 @@ do_ssc(unsigned long ssc, struct pt_regs *regs)
break;
case SSC_OPEN:
arg1 = vcpu_get_gr(current,33); // access rights
-if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
+if (!running_on_sim) { printk("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; }
if (arg0) { // metaphysical address
arg0 = translate_domain_mpaddr(arg0, NULL);
retval = ia64_ssc(arg0,arg1,0,0,ssc);
@@ -867,7 +919,7 @@ if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring
break;
case SSC_WRITE:
case SSC_READ:
-//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n");
+//if (ssc == SSC_WRITE) printk("DOING AN SSC_WRITE\n");
arg1 = vcpu_get_gr(current,33);
arg2 = vcpu_get_gr(current,34);
arg3 = vcpu_get_gr(current,35);
@@ -883,7 +935,7 @@ if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring
/**/ last_fd = arg1;
/**/ last_count = len;
mpaddr = req->addr;
-//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
+//if (last_count >= PAGE_SIZE) printk("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
retval = 0;
if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
// do partial page first
@@ -894,7 +946,7 @@ if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring
arg3 += req->len; // file offset
/**/ last_stat.fd = last_fd;
/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
-//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
+//if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
}
if (retval >= 0) while (len > 0) {
req->addr = translate_domain_mpaddr(mpaddr, NULL);
@@ -905,27 +957,27 @@ if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring
// TEMP REMOVED AGAIN arg3 += req->len; // file offset
/**/ last_stat.fd = last_fd;
/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
-//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
+//if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
}
// set it back to the original value
req->len = last_count;
}
else retval = -1L;
vcpu_set_gr(current,8,retval,0);
-//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval);
+//if (last_count >= PAGE_SIZE) printk("retval=%x\n",retval);
break;
case SSC_CONNECT_INTERRUPT:
arg1 = vcpu_get_gr(current,33);
arg2 = vcpu_get_gr(current,34);
arg3 = vcpu_get_gr(current,35);
- if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
+ if (!running_on_sim) { printk("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; }
(void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
break;
case SSC_NETDEV_PROBE:
vcpu_set_gr(current,8,-1L,0);
break;
default:
- printf("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n",
+ printk("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n",
ssc, regs->cr_iip, regs->b0);
while(1);
break;
diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c
index 17ad53bd71..effa38ef99 100644
--- a/xen/arch/ia64/xen/hypercall.c
+++ b/xen/arch/ia64/xen/hypercall.c
@@ -32,7 +32,6 @@
#include <xen/event.h>
#include <xen/perfc.h>
-static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop);
static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg);
static long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg);
@@ -54,10 +53,10 @@ const hypercall_t ia64_hypercall_table[NR_hypercalls] =
(hypercall_t)do_multicall,
(hypercall_t)do_ni_hypercall, /* do_update_va_mapping */
(hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */
- (hypercall_t)do_event_channel_op_compat,
+ (hypercall_t)do_ni_hypercall,
(hypercall_t)do_xen_version,
(hypercall_t)do_console_io,
- (hypercall_t)do_physdev_op_compat,
+ (hypercall_t)do_ni_hypercall,
(hypercall_t)do_grant_table_op, /* 20 */
(hypercall_t)do_ni_hypercall, /* do_vm_assist */
(hypercall_t)do_ni_hypercall, /* do_update_va_mapping_othe */
@@ -108,19 +107,6 @@ static IA64FAULT
xen_hypercall (struct pt_regs *regs)
{
uint32_t cmd = (uint32_t)regs->r2;
- struct vcpu *v = current;
-
- if (cmd == __HYPERVISOR_grant_table_op) {
- XEN_GUEST_HANDLE(void) uop;
-
- v->arch.hypercall_param.va = regs->r15;
- v->arch.hypercall_param.pa1 = regs->r17;
- v->arch.hypercall_param.pa2 = regs->r18;
- set_xen_guest_handle(uop, (void *)regs->r15);
- regs->r8 = do_grant_table_op(regs->r14, uop, regs->r16);
- v->arch.hypercall_param.va = 0;
- return IA64_NO_FAULT;
- }
if (cmd < NR_hypercalls) {
perfc_incra(hypercalls, cmd);
@@ -133,7 +119,21 @@ xen_hypercall (struct pt_regs *regs)
regs->r19);
} else
regs->r8 = -ENOSYS;
+
+ return IA64_NO_FAULT;
+}
+static IA64FAULT
+xen_fast_hypercall (struct pt_regs *regs)
+{
+ uint32_t cmd = (uint32_t)regs->r2;
+ switch (cmd) {
+ case __HYPERVISOR_ia64_fast_eoi:
+ regs->r8 = pirq_guest_eoi(current->domain, regs->r14);
+ break;
+ default:
+ regs->r8 = -ENOSYS;
+ }
return IA64_NO_FAULT;
}
@@ -163,7 +163,7 @@ fw_hypercall_ipi (struct pt_regs *regs)
memset (&c, 0, sizeof (c));
if (arch_set_info_guest (targ, &c) != 0) {
- printf ("arch_boot_vcpu: failure\n");
+ printk ("arch_boot_vcpu: failure\n");
return;
}
}
@@ -177,11 +177,11 @@ fw_hypercall_ipi (struct pt_regs *regs)
if (test_and_clear_bit(_VCPUF_down,
&targ->vcpu_flags)) {
vcpu_wake(targ);
- printf ("arch_boot_vcpu: vcpu %d awaken\n",
+ printk ("arch_boot_vcpu: vcpu %d awaken\n",
targ->vcpu_id);
}
else
- printf ("arch_boot_vcpu: huu, already awaken!\n");
+ printk ("arch_boot_vcpu: huu, already awaken!\n");
}
else {
int running = test_bit(_VCPUF_running,
@@ -201,8 +201,8 @@ fw_hypercall_fpswa (struct vcpu *v)
return PSCBX(v, fpswa_ret);
}
-static IA64FAULT
-fw_hypercall (struct pt_regs *regs)
+IA64FAULT
+ia64_hypercall(struct pt_regs *regs)
{
struct vcpu *v = current;
struct sal_ret_values x;
@@ -213,8 +213,14 @@ fw_hypercall (struct pt_regs *regs)
perfc_incra(fw_hypercall, index >> 8);
switch (index) {
- case FW_HYPERCALL_PAL_CALL:
- //printf("*** PAL hypercall: index=%d\n",regs->r28);
+ case FW_HYPERCALL_XEN:
+ return xen_hypercall(regs);
+
+ case FW_HYPERCALL_XEN_FAST:
+ return xen_fast_hypercall(regs);
+
+ case FW_HYPERCALL_PAL_CALL:
+ //printk("*** PAL hypercall: index=%d\n",regs->r28);
//FIXME: This should call a C routine
#if 0
// This is very conservative, but avoids a possible
@@ -229,7 +235,7 @@ fw_hypercall (struct pt_regs *regs)
event_pending(v)) {
perfc_incrc(idle_when_pending);
vcpu_pend_unspecified_interrupt(v);
-//printf("idle w/int#%d pending!\n",pi);
+//printk("idle w/int#%d pending!\n",pi);
//this shouldn't happen, but it apparently does quite a bit! so don't
//allow it to happen... i.e. if a domain has an interrupt pending and
//it tries to halt itself because it thinks it is idle, just return here
@@ -264,7 +270,7 @@ fw_hypercall (struct pt_regs *regs)
regs->r10 = y.v1; regs->r11 = y.v2;
}
break;
- case FW_HYPERCALL_SAL_CALL:
+ case FW_HYPERCALL_SAL_CALL:
x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
vcpu_get_gr(v,34),vcpu_get_gr(v,35),
vcpu_get_gr(v,36),vcpu_get_gr(v,37),
@@ -272,46 +278,35 @@ fw_hypercall (struct pt_regs *regs)
regs->r8 = x.r8; regs->r9 = x.r9;
regs->r10 = x.r10; regs->r11 = x.r11;
break;
- case FW_HYPERCALL_SAL_RETURN:
+ case FW_HYPERCALL_SAL_RETURN:
if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) )
vcpu_sleep_nosync(v);
break;
- case FW_HYPERCALL_EFI_CALL:
+ case FW_HYPERCALL_EFI_CALL:
efi_ret_value = efi_emulator (regs, &fault);
if (fault != IA64_NO_FAULT) return fault;
regs->r8 = efi_ret_value;
break;
- case FW_HYPERCALL_IPI:
+ case FW_HYPERCALL_IPI:
fw_hypercall_ipi (regs);
break;
- case FW_HYPERCALL_SET_SHARED_INFO_VA:
+ case FW_HYPERCALL_SET_SHARED_INFO_VA:
regs->r8 = domain_set_shared_info_va (regs->r28);
break;
- case FW_HYPERCALL_FPSWA:
+ case FW_HYPERCALL_FPSWA:
fpswa_ret = fw_hypercall_fpswa (v);
regs->r8 = fpswa_ret.status;
regs->r9 = fpswa_ret.err0;
regs->r10 = fpswa_ret.err1;
regs->r11 = fpswa_ret.err2;
break;
- default:
- printf("unknown ia64 fw hypercall %lx\n", regs->r2);
+ default:
+ printk("unknown ia64 fw hypercall %lx\n", regs->r2);
regs->r8 = do_ni_hypercall();
}
return IA64_NO_FAULT;
}
-IA64FAULT
-ia64_hypercall (struct pt_regs *regs)
-{
- unsigned long index = regs->r2;
-
- if (index >= FW_HYPERCALL_FIRST_ARCH)
- return fw_hypercall (regs);
- else
- return xen_hypercall (regs);
-}
-
unsigned long hypercall_create_continuation(
unsigned int op, const char *format, ...)
{
@@ -465,28 +460,6 @@ static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
return ret;
}
-/* Legacy hypercall (as of 0x00030202). */
-static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop)
-{
- struct physdev_op op;
-
- if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
- return -EFAULT;
-
- return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
-}
-
-/* Legacy hypercall (as of 0x00030202). */
-long do_event_channel_op_compat(XEN_GUEST_HANDLE(evtchn_op_t) uop)
-{
- struct evtchn_op op;
-
- if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
- return -EFAULT;
-
- return do_event_channel_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
-}
-
static long register_guest_callback(struct callback_register *reg)
{
long ret = 0;
diff --git a/xen/arch/ia64/xen/hyperprivop.S b/xen/arch/ia64/xen/hyperprivop.S
index eb3ad25bc2..12408d902e 100644
--- a/xen/arch/ia64/xen/hyperprivop.S
+++ b/xen/arch/ia64/xen/hyperprivop.S
@@ -203,7 +203,7 @@ END(fast_hyperprivop)
// give up for now if: ipsr.be==1, ipsr.pp==1
// from reflect_interruption, don't need to:
-// - printf first extint (debug only)
+// - printk first extint (debug only)
// - check for interrupt collection enabled (routine will force on)
// - set ifa (not valid for extint)
// - set iha (not valid for extint)
diff --git a/xen/arch/ia64/xen/irq.c b/xen/arch/ia64/xen/irq.c
index 98f11cad11..6211e9b418 100644
--- a/xen/arch/ia64/xen/irq.c
+++ b/xen/arch/ia64/xen/irq.c
@@ -377,7 +377,8 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
{
if ( desc->action != NULL )
{
- DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n",
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. In use by '%s'.\n",
irq, desc->action->name);
rc = -EBUSY;
goto out;
@@ -386,7 +387,9 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
action = xmalloc(irq_guest_action_t);
if ( (desc->action = (struct irqaction *)action) == NULL )
{
- DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. Out of memory.\n",
+ irq);
rc = -ENOMEM;
goto out;
}
@@ -410,7 +413,8 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
}
else if ( !will_share || !action->shareable )
{
- DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n",
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. Will not share with others.\n",
irq);
rc = -EBUSY;
goto out;
@@ -418,7 +422,9 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
if ( action->nr_guests == IRQ_MAX_GUESTS )
{
- DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq);
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. Already at max share.\n",
+ irq);
rc = -EBUSY;
goto out;
}
@@ -481,7 +487,7 @@ xen_debug_irq(unsigned long vector, struct pt_regs *regs)
firstirq = 0;
}
if (firsttime[vector]) {
- printf("**** (entry) First received int on vector=%lu,itc=%lx\n",
+ printk("**** (entry) First received int on vector=%lu,itc=%lx\n",
(unsigned long) vector, ia64_get_itc());
firsttime[vector] = 0;
}
diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c
index e00a71599c..e3134ec7e1 100644
--- a/xen/arch/ia64/xen/mm.c
+++ b/xen/arch/ia64/xen/mm.c
@@ -36,7 +36,7 @@
*
* operations on this structure:
* - global tlb purge
- * vcpu_ptc_g(), vcpu_ptc_ga() and domain_page_flush()
+ * vcpu_ptc_g(), vcpu_ptc_ga() and domain_page_flush_and_put()
* I.e. callers of domain_flush_vtlb_range() and domain_flush_vtlb_all()
* These functions invalidate VHPT entry and vcpu->arch.{i, d}tlb
*
@@ -172,13 +172,16 @@
#include <asm/vhpt.h>
#include <asm/vcpu.h>
#include <asm/shadow.h>
+#include <asm/p2m_entry.h>
+#include <asm/tlb_track.h>
#include <linux/efi.h>
#include <xen/guest_access.h>
#include <asm/page.h>
#include <public/memory.h>
-static void domain_page_flush(struct domain* d, unsigned long mpaddr,
- unsigned long old_mfn, unsigned long new_mfn);
+static void domain_page_flush_and_put(struct domain* d, unsigned long mpaddr,
+ volatile pte_t* ptep, pte_t old_pte,
+ struct page_info* page);
extern unsigned long ia64_iobase;
@@ -227,7 +230,8 @@ try_to_clear_PGC_allocate(struct domain* d, struct page_info* page)
if (unlikely(!(x & PGC_allocated)) || unlikely(_nd != _d)) {
struct domain* nd = unpickle_domptr(_nd);
if (nd == NULL) {
- DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+ gdprintk(XENLOG_INFO, "gnttab_transfer: "
+ "Bad page %p: ed=%p(%u) 0x%x, "
"sd=%p 0x%x,"
" caf=%016lx, taf=%" PRtype_info "\n",
(void *) page_to_mfn(page),
@@ -396,6 +400,13 @@ gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
{
unsigned long pte;
+ // This function may be called from __gnttab_copy()
+ // during domain destruction with VNIF copy receiver.
+ // ** FIXME: This is not SMP-safe yet about p2m table. **
+ if (unlikely(d->arch.mm.pgd == NULL)) {
+ BUG();
+ return INVALID_MFN;
+ }
pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT, NULL);
if (!pte) {
panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n");
@@ -435,7 +446,8 @@ u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps,
arflags2 = pteval2 & _PAGE_AR_MASK;
if (arflags != _PAGE_AR_R && arflags2 == _PAGE_AR_R) {
#if 0
- DPRINTK("%s:%d "
+ dprintk(XENLOG_WARNING,
+ "%s:%d "
"pteval 0x%lx arflag 0x%lx address 0x%lx itir 0x%lx "
"pteval2 0x%lx arflags2 0x%lx mpaddr 0x%lx\n",
__func__, __LINE__,
@@ -460,7 +472,7 @@ u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps,
This can happen when domU tries to touch i/o
port space. Also prevents possible address
aliasing issues. */
- printf("Warning: UC to WB for mpaddr=%lx\n", mpaddr);
+ printk("Warning: UC to WB for mpaddr=%lx\n", mpaddr);
pteval = (pteval & ~_PAGE_MA_MASK) | _PAGE_MA_WB;
}
break;
@@ -702,6 +714,22 @@ void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
}
#endif
+unsigned long
+xencomm_paddr_to_maddr(unsigned long paddr)
+{
+ struct vcpu *v = current;
+ struct domain *d = v->domain;
+ u64 pa;
+
+ pa = ____lookup_domain_mpa(d, paddr);
+ if (pa == INVALID_MFN) {
+ printk("%s: called with bad memory address: 0x%lx - iip=%lx\n",
+ __func__, paddr, vcpu_regs(v)->cr_iip);
+ return 0;
+ }
+ return __va_ul((pa & _PFN_MASK) | (paddr & ~PAGE_MASK));
+}
+
/* Allocate a new page for domain and map it to the specified metaphysical
address. */
static struct page_info *
@@ -715,7 +743,7 @@ __assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte)
p = alloc_domheap_page(d);
if (unlikely(!p)) {
- printf("assign_new_domain_page: Can't alloc!!!! Aaaargh!\n");
+ printk("assign_new_domain_page: Can't alloc!!!! Aaaargh!\n");
return(p);
}
@@ -726,7 +754,7 @@ __assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte)
&& maddr < __get_cpu_var(vhpt_pend))) {
/* FIXME: how can this happen ?
vhpt is allocated by alloc_domheap_page. */
- printf("assign_new_domain_page: reassigned vhpt page %lx!!\n",
+ printk("assign_new_domain_page: reassigned vhpt page %lx!!\n",
maddr);
}
@@ -737,7 +765,8 @@ __assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte)
// because set_pte_rel() has release semantics
set_pte_rel(pte,
pfn_pte(maddr >> PAGE_SHIFT,
- __pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX)));
+ __pgprot(_PAGE_PGC_ALLOCATED | __DIRTY_BITS |
+ _PAGE_PL_2 | _PAGE_AR_RWX)));
smp_mb();
return p;
@@ -776,15 +805,19 @@ flags_to_prot (unsigned long flags)
res |= flags & ASSIGN_readonly ? _PAGE_AR_R: _PAGE_AR_RWX;
res |= flags & ASSIGN_nocache ? _PAGE_MA_UC: _PAGE_MA_WB;
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+ res |= flags & ASSIGN_tlb_track ? _PAGE_TLB_TRACKING: 0;
+#endif
+ res |= flags & ASSIGN_pgc_allocated ? _PAGE_PGC_ALLOCATED: 0;
return res;
}
/* map a physical address to the specified metaphysical addr */
-// flags: currently only ASSIGN_readonly, ASSIGN_nocache
+// flags: currently only ASSIGN_readonly, ASSIGN_nocache, ASSIGN_tlb_tack
// This is called by assign_domain_mmio_page().
// So accessing to pte is racy.
-void
+int
__assign_domain_page(struct domain *d,
unsigned long mpaddr, unsigned long physaddr,
unsigned long flags)
@@ -800,8 +833,25 @@ __assign_domain_page(struct domain *d,
old_pte = __pte(0);
new_pte = pfn_pte(physaddr >> PAGE_SHIFT, __pgprot(prot));
ret_pte = ptep_cmpxchg_rel(&d->arch.mm, mpaddr, pte, old_pte, new_pte);
- if (pte_val(ret_pte) == pte_val(old_pte))
+ if (pte_val(ret_pte) == pte_val(old_pte)) {
smp_mb();
+ return 0;
+ }
+
+ // dom0 tries to map real machine's I/O region, but failed.
+ // It is very likely that dom0 doesn't boot correctly because
+ // it can't access I/O. So complain here.
+ if ((flags & ASSIGN_nocache) &&
+ (pte_pfn(ret_pte) != (physaddr >> PAGE_SHIFT) ||
+ !(pte_val(ret_pte) & _PAGE_MA_UC)))
+ printk("%s:%d WARNING can't assign page domain 0x%p id %d\n"
+ "\talready assigned pte_val 0x%016lx\n"
+ "\tmpaddr 0x%016lx physaddr 0x%016lx flags 0x%lx\n",
+ __func__, __LINE__,
+ d, d->domain_id, pte_val(ret_pte),
+ mpaddr, physaddr, flags);
+
+ return -EAGAIN;
}
/* get_page() and map a physical address to the specified metaphysical addr */
@@ -818,7 +868,8 @@ assign_domain_page(struct domain *d,
set_gpfn_from_mfn(physaddr >> PAGE_SHIFT, mpaddr >> PAGE_SHIFT);
// because __assign_domain_page() uses set_pte_rel() which has
// release semantics, smp_mb() isn't needed.
- __assign_domain_page(d, mpaddr, physaddr, ASSIGN_writable);
+ (void)__assign_domain_page(d, mpaddr, physaddr,
+ ASSIGN_writable | ASSIGN_pgc_allocated);
}
int
@@ -841,8 +892,8 @@ ioports_permit_access(struct domain *d, unsigned long fp, unsigned long lp)
lp_offset = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp));
for (off = fp_offset; off <= lp_offset; off += PAGE_SIZE)
- __assign_domain_page(d, IO_PORTS_PADDR + off,
- __pa(ia64_iobase) + off, ASSIGN_nocache);
+ (void)__assign_domain_page(d, IO_PORTS_PADDR + off,
+ __pa(ia64_iobase) + off, ASSIGN_nocache);
return 0;
}
@@ -911,7 +962,7 @@ assign_domain_same_page(struct domain *d,
//XXX optimization
unsigned long end = PAGE_ALIGN(mpaddr + size);
for (mpaddr &= PAGE_MASK; mpaddr < end; mpaddr += PAGE_SIZE) {
- __assign_domain_page(d, mpaddr, mpaddr, flags);
+ (void)__assign_domain_page(d, mpaddr, mpaddr, flags);
}
}
@@ -933,8 +984,8 @@ efi_mmio(unsigned long physaddr, unsigned long size)
if (start <= physaddr && physaddr < end) {
if ((physaddr + size) > end) {
- DPRINTK("%s:%d physaddr 0x%lx size = 0x%lx\n",
- __func__, __LINE__, physaddr, size);
+ gdprintk(XENLOG_INFO, "%s: physaddr 0x%lx size = 0x%lx\n",
+ __func__, physaddr, size);
return 0;
}
@@ -968,13 +1019,13 @@ assign_domain_mmio_page(struct domain *d,
unsigned long mpaddr, unsigned long size)
{
if (size == 0) {
- DPRINTK("%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
+ gdprintk(XENLOG_INFO, "%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
__func__, d, mpaddr, size);
}
if (!efi_mmio(mpaddr, size)) {
#ifndef NDEBUG
- DPRINTK("%s:%d domain %p mpaddr 0x%lx size = 0x%lx\n",
- __func__, __LINE__, d, mpaddr, size);
+ gdprintk(XENLOG_INFO, "%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
+ __func__, d, mpaddr, size);
#endif
return -EINVAL;
}
@@ -987,15 +1038,37 @@ assign_domain_mach_page(struct domain *d,
unsigned long mpaddr, unsigned long size,
unsigned long flags)
{
+ BUG_ON(flags & ASSIGN_pgc_allocated);
assign_domain_same_page(d, mpaddr, size, flags);
return mpaddr;
}
+static void
+domain_put_page(struct domain* d, unsigned long mpaddr,
+ volatile pte_t* ptep, pte_t old_pte, int clear_PGC_allocate)
+{
+ unsigned long mfn = pte_pfn(old_pte);
+ struct page_info* page = mfn_to_page(mfn);
+
+ if (pte_pgc_allocated(old_pte)) {
+ if (page_get_owner(page) == d || page_get_owner(page) == NULL) {
+ BUG_ON(get_gpfn_from_mfn(mfn) != (mpaddr >> PAGE_SHIFT));
+ set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
+ } else {
+ BUG();
+ }
+
+ if (clear_PGC_allocate)
+ try_to_clear_PGC_allocate(d, page);
+ }
+ domain_page_flush_and_put(d, mpaddr, ptep, old_pte, page);
+}
+
// caller must get_page(mfn_to_page(mfn)) before call.
// caller must call set_gpfn_from_mfn() before call if necessary.
// because set_gpfn_from_mfn() result must be visible before pte xchg
// caller must use memory barrier. NOTE: xchg has acquire semantics.
-// flags: currently only ASSIGN_readonly
+// flags: ASSIGN_xxx
static void
assign_domain_page_replace(struct domain *d, unsigned long mpaddr,
unsigned long mfn, unsigned long flags)
@@ -1021,20 +1094,10 @@ assign_domain_page_replace(struct domain *d, unsigned long mpaddr,
// => create_host_mapping()
// => assign_domain_page_replace()
if (mfn != old_mfn) {
- struct page_info* old_page = mfn_to_page(old_mfn);
-
- if (page_get_owner(old_page) == d ||
- page_get_owner(old_page) == NULL) {
- BUG_ON(get_gpfn_from_mfn(old_mfn) != (mpaddr >> PAGE_SHIFT));
- set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY);
- }
-
- domain_page_flush(d, mpaddr, old_mfn, mfn);
-
- try_to_clear_PGC_allocate(d, old_page);
- put_page(old_page);
+ domain_put_page(d, mpaddr, pte, old_pte, 1);
}
}
+ perfc_incrc(assign_domain_page_replace);
}
// caller must get_page(new_page) before
@@ -1048,7 +1111,7 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr,
struct mm_struct *mm = &d->arch.mm;
volatile pte_t* pte;
unsigned long old_mfn;
- unsigned long old_arflags;
+ unsigned long old_prot;
pte_t old_pte;
unsigned long new_mfn;
unsigned long new_prot;
@@ -1058,12 +1121,13 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr,
pte = lookup_alloc_domain_pte(d, mpaddr);
again:
- old_arflags = pte_val(*pte) & ~_PAGE_PPN_MASK;
+ old_prot = pte_val(*pte) & ~_PAGE_PPN_MASK;
old_mfn = page_to_mfn(old_page);
- old_pte = pfn_pte(old_mfn, __pgprot(old_arflags));
+ old_pte = pfn_pte(old_mfn, __pgprot(old_prot));
if (!pte_present(old_pte)) {
- DPRINTK("%s: old_pte 0x%lx old_arflags 0x%lx old_mfn 0x%lx\n",
- __func__, pte_val(old_pte), old_arflags, old_mfn);
+ gdprintk(XENLOG_INFO,
+ "%s: old_pte 0x%lx old_prot 0x%lx old_mfn 0x%lx\n",
+ __func__, pte_val(old_pte), old_prot, old_mfn);
return -EINVAL;
}
@@ -1078,23 +1142,25 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr,
goto again;
}
- DPRINTK("%s: old_pte 0x%lx old_arflags 0x%lx old_mfn 0x%lx "
+ gdprintk(XENLOG_INFO,
+ "%s: old_pte 0x%lx old_prot 0x%lx old_mfn 0x%lx "
"ret_pte 0x%lx ret_mfn 0x%lx\n",
__func__,
- pte_val(old_pte), old_arflags, old_mfn,
+ pte_val(old_pte), old_prot, old_mfn,
pte_val(ret_pte), pte_pfn(ret_pte));
return -EINVAL;
}
BUG_ON(!pte_mem(old_pte));
+ BUG_ON(!pte_pgc_allocated(old_pte));
BUG_ON(page_get_owner(old_page) != d);
BUG_ON(get_gpfn_from_mfn(old_mfn) != (mpaddr >> PAGE_SHIFT));
BUG_ON(old_mfn == new_mfn);
set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY);
- domain_page_flush(d, mpaddr, old_mfn, new_mfn);
- put_page(old_page);
+ domain_page_flush_and_put(d, mpaddr, pte, old_pte, old_page);
+ perfc_incrc(assign_domain_pge_cmpxchg_rel);
return 0;
}
@@ -1137,7 +1203,7 @@ zap_domain_page_one(struct domain *d, unsigned long mpaddr, unsigned long mfn)
goto again;
}
- DPRINTK("%s: old_pte 0x%lx old_arflags 0x%lx mfn 0x%lx "
+ gdprintk(XENLOG_INFO, "%s: old_pte 0x%lx old_arflags 0x%lx mfn 0x%lx "
"ret_pte 0x%lx ret_mfn 0x%lx\n",
__func__,
pte_val(old_pte), old_arflags, mfn,
@@ -1150,23 +1216,13 @@ zap_domain_page_one(struct domain *d, unsigned long mpaddr, unsigned long mfn)
page = mfn_to_page(mfn);
BUG_ON((page->count_info & PGC_count_mask) == 0);
- if (page_get_owner(page) == d ||
- page_get_owner(page) == NULL) {
- // exchange_memory() calls
- // steal_page()
- // page owner is set to NULL
- // guest_physmap_remove_page()
- // zap_domain_page_one()
- BUG_ON(get_gpfn_from_mfn(mfn) != (mpaddr >> PAGE_SHIFT));
- set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
- }
-
- domain_page_flush(d, mpaddr, mfn, INVALID_MFN);
-
- if (page_get_owner(page) != NULL) {
- try_to_clear_PGC_allocate(d, page);
- }
- put_page(page);
+ // exchange_memory() calls
+ // steal_page()
+ // page owner is set to NULL
+ // guest_physmap_remove_page()
+ // zap_domain_page_one()
+ domain_put_page(d, mpaddr, pte, old_pte, (page_get_owner(page) != NULL));
+ perfc_incrc(zap_dcomain_page_one);
}
unsigned long
@@ -1179,6 +1235,7 @@ dom0vp_zap_physmap(struct domain *d, unsigned long gpfn,
}
zap_domain_page_one(d, gpfn << PAGE_SHIFT, INVALID_MFN);
+ perfc_incrc(dom0vp_zap_physmap);
return 0;
}
@@ -1190,7 +1247,7 @@ dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn,
struct domain* rd;
/* Not allowed by a domain. */
- if (flags & ASSIGN_nocache)
+ if (flags & (ASSIGN_nocache | ASSIGN_pgc_allocated))
return -EINVAL;
rd = find_domain_by_id(domid);
@@ -1203,7 +1260,7 @@ dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn,
rd = dom_io;
break;
default:
- DPRINTK("d 0x%p domid %d "
+ gdprintk(XENLOG_INFO, "d 0x%p domid %d "
"pgfn 0x%lx mfn 0x%lx flags 0x%lx domid %d\n",
d, d->domain_id, gpfn, mfn, flags, domid);
return -ESRCH;
@@ -1224,11 +1281,134 @@ dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn,
get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY);
assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, flags);
//don't update p2m table because this page belongs to rd, not d.
+ perfc_incrc(dom0vp_add_physmap);
out1:
put_domain(rd);
return error;
}
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+static struct page_info* p2m_pte_zero_page = NULL;
+
+void
+expose_p2m_init(void)
+{
+ pte_t* pte;
+
+ pte = pte_alloc_one_kernel(NULL, 0);
+ BUG_ON(pte == NULL);
+ smp_mb();// make contents of the page visible.
+ p2m_pte_zero_page = virt_to_page(pte);
+}
+
+static int
+expose_p2m_page(struct domain* d, unsigned long mpaddr, struct page_info* page)
+{
+ // we can't get_page(page) here.
+ // pte page is allocated form xen heap.(see pte_alloc_one_kernel().)
+ // so that the page has NULL page owner and it's reference count
+ // is useless.
+ // see also relinquish_pte()'s page_get_owner() == NULL check.
+ BUG_ON(page_get_owner(page) != NULL);
+
+ return __assign_domain_page(d, mpaddr, page_to_maddr(page),
+ ASSIGN_readonly);
+}
+
+// It is possible to optimize loop, But this isn't performance critical.
+unsigned long
+dom0vp_expose_p2m(struct domain* d,
+ unsigned long conv_start_gpfn,
+ unsigned long assign_start_gpfn,
+ unsigned long expose_size, unsigned long granule_pfn)
+{
+ unsigned long expose_num_pfn = expose_size >> PAGE_SHIFT;
+ unsigned long i;
+ volatile pte_t* conv_pte;
+ volatile pte_t* assign_pte;
+
+ if ((expose_size % PAGE_SIZE) != 0 ||
+ (granule_pfn % PTRS_PER_PTE) != 0 ||
+ (expose_num_pfn % PTRS_PER_PTE) != 0 ||
+ (conv_start_gpfn % granule_pfn) != 0 ||
+ (assign_start_gpfn % granule_pfn) != 0 ||
+ (expose_num_pfn % granule_pfn) != 0) {
+ gdprintk(XENLOG_INFO,
+ "%s conv_start_gpfn 0x%016lx assign_start_gpfn 0x%016lx "
+ "expose_size 0x%016lx granulte_pfn 0x%016lx\n", __func__,
+ conv_start_gpfn, assign_start_gpfn, expose_size, granule_pfn);
+ return -EINVAL;
+ }
+
+ if (granule_pfn != PTRS_PER_PTE) {
+ gdprintk(XENLOG_INFO,
+ "%s granule_pfn 0x%016lx PTRS_PER_PTE 0x%016lx\n",
+ __func__, granule_pfn, PTRS_PER_PTE);
+ return -ENOSYS;
+ }
+
+ // allocate pgd, pmd.
+ i = conv_start_gpfn;
+ while (i < expose_num_pfn) {
+ conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) <<
+ PAGE_SHIFT);
+ if (conv_pte == NULL) {
+ i++;
+ continue;
+ }
+
+ assign_pte = lookup_alloc_domain_pte(d, (assign_start_gpfn <<
+ PAGE_SHIFT) + i * sizeof(pte_t));
+ if (assign_pte == NULL) {
+ gdprintk(XENLOG_INFO, "%s failed to allocate pte page\n", __func__);
+ return -ENOMEM;
+ }
+
+ // skip to next pte page
+ i += PTRS_PER_PTE;
+ i &= ~(PTRS_PER_PTE - 1);
+ }
+
+ // expose pte page
+ i = 0;
+ while (i < expose_num_pfn) {
+ conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) <<
+ PAGE_SHIFT);
+ if (conv_pte == NULL) {
+ i++;
+ continue;
+ }
+
+ if (expose_p2m_page(d, (assign_start_gpfn << PAGE_SHIFT) +
+ i * sizeof(pte_t), virt_to_page(conv_pte)) < 0) {
+ gdprintk(XENLOG_INFO, "%s failed to assign page\n", __func__);
+ return -EAGAIN;
+ }
+
+ // skip to next pte page
+ i += PTRS_PER_PTE;
+ i &= ~(PTRS_PER_PTE - 1);
+ }
+
+ // expose p2m_pte_zero_page
+ for (i = 0; i < expose_num_pfn / PTRS_PER_PTE + 1; i++) {
+ assign_pte = lookup_noalloc_domain_pte(d, (assign_start_gpfn + i) <<
+ PAGE_SHIFT);
+ BUG_ON(assign_pte == NULL);
+ if (pte_present(*assign_pte)) {
+ continue;
+ }
+ if (expose_p2m_page(d, (assign_start_gpfn + i) << PAGE_SHIFT,
+ p2m_pte_zero_page) < 0) {
+ gdprintk(XENLOG_INFO, "%s failed to assign zero-pte page\n", __func__);
+ return -EAGAIN;
+ }
+ }
+
+ return 0;
+}
+#endif
+
// grant table host mapping
// mpaddr: host_addr: pseudo physical address
// mfn: frame: machine page frame
@@ -1243,7 +1423,7 @@ create_grant_host_mapping(unsigned long gpaddr,
if (flags & (GNTMAP_device_map |
GNTMAP_application_map | GNTMAP_contains_pte)) {
- DPRINTK("%s: flags 0x%x\n", __func__, flags);
+ gdprintk(XENLOG_INFO, "%s: flags 0x%x\n", __func__, flags);
return GNTST_general_error;
}
@@ -1251,10 +1431,13 @@ create_grant_host_mapping(unsigned long gpaddr,
page = mfn_to_page(mfn);
ret = get_page(page, page_get_owner(page));
BUG_ON(ret == 0);
- BUG_ON(page_get_owner(mfn_to_page(mfn)) == d &&
- get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY);
- assign_domain_page_replace(d, gpaddr, mfn, (flags & GNTMAP_readonly)?
- ASSIGN_readonly: ASSIGN_writable);
+ assign_domain_page_replace(d, gpaddr, mfn,
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+ ASSIGN_tlb_track |
+#endif
+ ((flags & GNTMAP_readonly) ?
+ ASSIGN_readonly : ASSIGN_writable));
+ perfc_incrc(create_grant_host_mapping);
return GNTST_okay;
}
@@ -1264,29 +1447,32 @@ destroy_grant_host_mapping(unsigned long gpaddr,
unsigned long mfn, unsigned int flags)
{
struct domain* d = current->domain;
+ unsigned long gpfn = gpaddr >> PAGE_SHIFT;
volatile pte_t* pte;
unsigned long cur_arflags;
pte_t cur_pte;
pte_t new_pte;
pte_t old_pte;
- struct page_info* page;
+ struct page_info* page = mfn_to_page(mfn);
if (flags & (GNTMAP_application_map | GNTMAP_contains_pte)) {
- DPRINTK("%s: flags 0x%x\n", __func__, flags);
+ gdprintk(XENLOG_INFO, "%s: flags 0x%x\n", __func__, flags);
return GNTST_general_error;
}
pte = lookup_noalloc_domain_pte(d, gpaddr);
if (pte == NULL) {
- DPRINTK("%s: gpaddr 0x%lx mfn 0x%lx\n", __func__, gpaddr, mfn);
+ gdprintk(XENLOG_INFO, "%s: gpaddr 0x%lx mfn 0x%lx\n",
+ __func__, gpaddr, mfn);
return GNTST_general_error;
}
again:
cur_arflags = pte_val(*pte) & ~_PAGE_PPN_MASK;
cur_pte = pfn_pte(mfn, __pgprot(cur_arflags));
- if (!pte_present(cur_pte)) {
- DPRINTK("%s: gpaddr 0x%lx mfn 0x%lx cur_pte 0x%lx\n",
+ if (!pte_present(cur_pte) ||
+ (page_get_owner(page) == d && get_gpfn_from_mfn(mfn) == gpfn)) {
+ gdprintk(XENLOG_INFO, "%s: gpaddr 0x%lx mfn 0x%lx cur_pte 0x%lx\n",
__func__, gpaddr, mfn, pte_val(cur_pte));
return GNTST_general_error;
}
@@ -1294,7 +1480,8 @@ destroy_grant_host_mapping(unsigned long gpaddr,
old_pte = ptep_cmpxchg_rel(&d->arch.mm, gpaddr, pte, cur_pte, new_pte);
if (unlikely(!pte_present(old_pte))) {
- DPRINTK("%s: gpaddr 0x%lx mfn 0x%lx cur_pte 0x%lx old_pte 0x%lx\n",
+ gdprintk(XENLOG_INFO, "%s: gpaddr 0x%lx mfn 0x%lx"
+ " cur_pte 0x%lx old_pte 0x%lx\n",
__func__, gpaddr, mfn, pte_val(cur_pte), pte_val(old_pte));
return GNTST_general_error;
}
@@ -1302,18 +1489,19 @@ destroy_grant_host_mapping(unsigned long gpaddr,
if (pte_pfn(old_pte) == mfn) {
goto again;
}
- DPRINTK("%s gpaddr 0x%lx mfn 0x%lx cur_pte 0x%lx old_pte 0x%lx\n",
+ gdprintk(XENLOG_INFO, "%s gpaddr 0x%lx mfn 0x%lx cur_pte "
+ "0x%lx old_pte 0x%lx\n",
__func__, gpaddr, mfn, pte_val(cur_pte), pte_val(old_pte));
return GNTST_general_error;
}
BUG_ON(pte_pfn(old_pte) != mfn);
- domain_page_flush(d, gpaddr, mfn, INVALID_MFN);
-
- page = mfn_to_page(mfn);
- BUG_ON(page_get_owner(page) == d);//try_to_clear_PGC_allocate(d, page) is not needed.
- put_page(page);
+ /* try_to_clear_PGC_allocate(d, page) is not needed. */
+ BUG_ON(page_get_owner(page) == d &&
+ get_gpfn_from_mfn(mfn) == gpfn);
+ domain_page_flush_and_put(d, gpaddr, pte, old_pte, page);
+ perfc_incrc(destroy_grant_host_mapping);
return GNTST_okay;
}
@@ -1333,7 +1521,8 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
u64 x, nx, y;
if (page_get_owner(page) != d) {
- DPRINTK("%s d 0x%p owner 0x%p\n", __func__, d, page_get_owner(page));
+ gdprintk(XENLOG_INFO, "%s d 0x%p owner 0x%p\n",
+ __func__, d, page_get_owner(page));
return -1;
}
@@ -1345,7 +1534,7 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
new = alloc_domheap_page(d);
if (new == NULL) {
- DPRINTK("alloc_domheap_page() failed\n");
+ gdprintk(XENLOG_INFO, "alloc_domheap_page() failed\n");
return -1;
}
// zero out pages for security reasons
@@ -1367,13 +1556,16 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
// has release semantics.
ret = assign_domain_page_cmpxchg_rel(d, gpfn << PAGE_SHIFT, page, new,
- ASSIGN_writable);
+ ASSIGN_writable |
+ ASSIGN_pgc_allocated);
if (ret < 0) {
- DPRINTK("assign_domain_page_cmpxchg_rel failed %d\n", ret);
+ gdprintk(XENLOG_INFO, "assign_domain_page_cmpxchg_rel failed %d\n",
+ ret);
set_gpfn_from_mfn(new_mfn, INVALID_M2P_ENTRY);
free_domheap_page(new);
return -1;
}
+ perfc_incrc(steal_page_refcount);
}
spin_lock(&d->page_alloc_lock);
@@ -1392,10 +1584,12 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
// page->u.inused._domain = 0;
_nd = x >> 32;
- if (unlikely(!(memflags & MEMF_no_refcount) &&
+ if (
+ // when !MEMF_no_refcount, page might be put_page()'d or
+ // it will be put_page()'d later depending on queued.
+ unlikely(!(memflags & MEMF_no_refcount) &&
((x & (PGC_count_mask | PGC_allocated)) !=
(1 | PGC_allocated))) ||
-
// when MEMF_no_refcount, page isn't de-assigned from
// this domain yet. So count_info = 2
unlikely((memflags & MEMF_no_refcount) &&
@@ -1405,7 +1599,8 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
unlikely(_nd != _d)) {
struct domain* nd = unpickle_domptr(_nd);
if (nd == NULL) {
- DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+ gdprintk(XENLOG_INFO, "gnttab_transfer: "
+ "Bad page %p: ed=%p(%u) 0x%x, "
"sd=%p 0x%x,"
" caf=%016lx, taf=%" PRtype_info
" memflags 0x%x\n",
@@ -1416,7 +1611,8 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
page->u.inuse.type_info,
memflags);
} else {
- DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u) 0x%x, "
+ gdprintk(XENLOG_WARNING, "gnttab_transfer: "
+ "Bad page %p: ed=%p(%u) 0x%x, "
"sd=%p(%u) 0x%x,"
" caf=%016lx, taf=%" PRtype_info
" memflags 0x%x\n",
@@ -1443,6 +1639,7 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags)
list_del(&page->list);
spin_unlock(&d->page_alloc_lock);
+ perfc_incrc(steal_page);
return 0;
}
@@ -1457,9 +1654,12 @@ guest_physmap_add_page(struct domain *d, unsigned long gpfn,
BUG_ON(ret == 0);
set_gpfn_from_mfn(mfn, gpfn);
smp_mb();
- assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, ASSIGN_writable);
+ assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn,
+ ASSIGN_writable | ASSIGN_pgc_allocated);
//BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> PAGE_SHIFT));
+
+ perfc_incrc(guest_physmap_add_page);
}
void
@@ -1468,18 +1668,87 @@ guest_physmap_remove_page(struct domain *d, unsigned long gpfn,
{
BUG_ON(mfn == 0);//XXX
zap_domain_page_one(d, gpfn << PAGE_SHIFT, mfn);
+ perfc_incrc(guest_physmap_remove_page);
}
-//XXX sledgehammer.
-// flush finer range.
static void
-domain_page_flush(struct domain* d, unsigned long mpaddr,
- unsigned long old_mfn, unsigned long new_mfn)
+domain_page_flush_and_put(struct domain* d, unsigned long mpaddr,
+ volatile pte_t* ptep, pte_t old_pte,
+ struct page_info* page)
{
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+ struct tlb_track_entry* entry;
+#endif
+
if (shadow_mode_enabled(d))
shadow_mark_page_dirty(d, mpaddr >> PAGE_SHIFT);
+#ifndef CONFIG_XEN_IA64_TLB_TRACK
+ //XXX sledgehammer.
+ // flush finer range.
domain_flush_vtlb_all();
+ put_page(page);
+#else
+ switch (tlb_track_search_and_remove(d->arch.tlb_track,
+ ptep, old_pte, &entry)) {
+ case TLB_TRACK_NOT_TRACKED:
+ // dprintk(XENLOG_WARNING, "%s TLB_TRACK_NOT_TRACKED\n", __func__);
+ /* This page is zapped from this domain
+ * by memory decrease or exchange or dom0vp_zap_physmap.
+ * I.e. the page is zapped for returning this page to xen
+ * (balloon driver or DMA page allocation) or
+ * foreign domain mapped page is unmapped from the domain.
+ * In the former case the page is to be freed so that
+ * we can defer freeing page to batch.
+ * In the latter case the page is unmapped so that
+ * we need to flush it. But to optimize it, we
+ * queue the page and flush vTLB only once.
+ * I.e. The caller must call dfree_flush() explicitly.
+ */
+ domain_flush_vtlb_all();
+ put_page(page);
+ break;
+ case TLB_TRACK_NOT_FOUND:
+ // dprintk(XENLOG_WARNING, "%s TLB_TRACK_NOT_FOUND\n", __func__);
+ /* This page is zapped from this domain
+ * by grant table page unmap.
+ * Luckily the domain that mapped this page didn't
+ * access this page so that we don't have to flush vTLB.
+ * Probably the domain did only DMA.
+ */
+ /* do nothing */
+ put_page(page);
+ break;
+ case TLB_TRACK_FOUND:
+ // dprintk(XENLOG_WARNING, "%s TLB_TRACK_FOUND\n", __func__);
+ /* This page is zapped from this domain
+ * by grant table page unmap.
+ * Fortunately this page is accessced via only one virtual
+ * memory address. So it is easy to flush it.
+ */
+ domain_flush_vtlb_track_entry(d, entry);
+ tlb_track_free_entry(d->arch.tlb_track, entry);
+ put_page(page);
+ break;
+ case TLB_TRACK_MANY:
+ gdprintk(XENLOG_INFO, "%s TLB_TRACK_MANY\n", __func__);
+ /* This page is zapped from this domain
+ * by grant table page unmap.
+ * Unfortunately this page is accessced via many virtual
+ * memory address (or too many times with single virtual address).
+ * So we abondaned to track virtual addresses.
+ * full vTLB flush is necessary.
+ */
+ domain_flush_vtlb_all();
+ put_page(page);
+ break;
+ case TLB_TRACK_AGAIN:
+ gdprintk(XENLOG_ERR, "%s TLB_TRACK_AGAIN\n", __func__);
+ BUG();
+ break;
+ }
+#endif
+ perfc_incrc(domain_page_flush_and_put);
}
int
@@ -1536,7 +1805,7 @@ void domain_cache_flush (struct domain *d, int sync_only)
}
}
}
- //printf ("domain_cache_flush: %d %d pages\n", d->domain_id, nbr_page);
+ //printk ("domain_cache_flush: %d %d pages\n", d->domain_id, nbr_page);
}
#ifdef VERBOSE
@@ -1627,13 +1896,6 @@ void put_page_type(struct page_info *page)
nx &= ~PGT_validated;
}
}
- else if ( unlikely(((nx & (PGT_pinned | PGT_count_mask)) ==
- (PGT_pinned | 1)) &&
- ((nx & PGT_type_mask) != PGT_writable_page)) )
- {
- /* Page is now only pinned. Make the back pointer mutable again. */
- nx |= PGT_va_mutable;
- }
}
while ( unlikely((y = cmpxchg_rel(&page->u.inuse.type_info, x, nx)) != x) );
}
@@ -1643,6 +1905,8 @@ int get_page_type(struct page_info *page, u32 type)
{
u32 nx, x, y = page->u.inuse.type_info;
+ ASSERT(!(type & ~PGT_type_mask));
+
again:
do {
x = y;
@@ -1654,29 +1918,25 @@ int get_page_type(struct page_info *page, u32 type)
}
else if ( unlikely((x & PGT_count_mask) == 0) )
{
- if ( (x & (PGT_type_mask|PGT_va_mask)) != type )
+ if ( (x & PGT_type_mask) != type )
{
- if ( (x & PGT_type_mask) != (type & PGT_type_mask) )
+ /*
+ * On type change we check to flush stale TLB entries. This
+ * may be unnecessary (e.g., page was GDT/LDT) but those
+ * circumstances should be very rare.
+ */
+ cpumask_t mask =
+ page_get_owner(page)->domain_dirty_cpumask;
+ tlbflush_filter(mask, page->tlbflush_timestamp);
+
+ if ( unlikely(!cpus_empty(mask)) )
{
- /*
- * On type change we check to flush stale TLB
- * entries. This may be unnecessary (e.g., page
- * was GDT/LDT) but those circumstances should be
- * very rare.
- */
- cpumask_t mask =
- page_get_owner(page)->domain_dirty_cpumask;
- tlbflush_filter(mask, page->tlbflush_timestamp);
-
- if ( unlikely(!cpus_empty(mask)) )
- {
- perfc_incrc(need_flush_tlb_flush);
- flush_tlb_mask(mask);
- }
+ perfc_incrc(need_flush_tlb_flush);
+ flush_tlb_mask(mask);
}
/* We lose existing type, back pointer, and validity. */
- nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated);
+ nx &= ~(PGT_type_mask | PGT_validated);
nx |= type;
/* No special validation needed for writable pages. */
@@ -1685,46 +1945,22 @@ int get_page_type(struct page_info *page, u32 type)
nx |= PGT_validated;
}
}
- else
+ else if ( unlikely((x & PGT_type_mask) != type) )
{
- if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) )
- {
- if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) )
- {
- if ( ((x & PGT_type_mask) != PGT_l2_page_table) ||
- ((type & PGT_type_mask) != PGT_l1_page_table) )
- MEM_LOG("Bad type (saw %08x != exp %08x) "
- "for mfn %016lx (pfn %016lx)",
- x, type, page_to_mfn(page),
- get_gpfn_from_mfn(page_to_mfn(page)));
- return 0;
- }
- else if ( (x & PGT_va_mask) == PGT_va_mutable )
- {
- /* The va backpointer is mutable, hence we update it. */
- nx &= ~PGT_va_mask;
- nx |= type; /* we know the actual type is correct */
- }
- else if ( ((type & PGT_va_mask) != PGT_va_mutable) &&
- ((type & PGT_va_mask) != (x & PGT_va_mask)) )
- {
-#ifdef CONFIG_X86_PAE
- /* We use backptr as extra typing. Cannot be unknown. */
- if ( (type & PGT_type_mask) == PGT_l2_page_table )
- return 0;
-#endif
- /* This table is possibly mapped at multiple locations. */
- nx &= ~PGT_va_mask;
- nx |= PGT_va_unknown;
- }
- }
- if ( unlikely(!(x & PGT_validated)) )
- {
- /* Someone else is updating validation of this page. Wait... */
- while ( (y = page->u.inuse.type_info) == x )
- cpu_relax();
- goto again;
- }
+ if ( ((x & PGT_type_mask) != PGT_l2_page_table) ||
+ (type != PGT_l1_page_table) )
+ MEM_LOG("Bad type (saw %08x != exp %08x) "
+ "for mfn %016lx (pfn %016lx)",
+ x, type, page_to_mfn(page),
+ get_gpfn_from_mfn(page_to_mfn(page)));
+ return 0;
+ }
+ else if ( unlikely(!(x & PGT_validated)) )
+ {
+ /* Someone else is updating validation of this page. Wait... */
+ while ( (y = page->u.inuse.type_info) == x )
+ cpu_relax();
+ goto again;
}
}
while ( unlikely((y = cmpxchg_acq(&page->u.inuse.type_info, x, nx)) != x) );
diff --git a/xen/arch/ia64/xen/privop.c b/xen/arch/ia64/xen/privop.c
index 31e1ebc198..f3949842f1 100644
--- a/xen/arch/ia64/xen/privop.c
+++ b/xen/arch/ia64/xen/privop.c
@@ -9,13 +9,13 @@
#include <asm/privop.h>
#include <asm/vcpu.h>
#include <asm/processor.h>
-#include <asm/delay.h> // Debug only
+#include <asm/delay.h> // Debug only
#include <asm/dom_fw.h>
#include <asm/vhpt.h>
#include <asm/bundle.h>
#include <xen/perfc.h>
-long priv_verbose=0;
+long priv_verbose = 0;
unsigned long privop_trace = 0;
/* Set to 1 to handle privified instructions from the privify tool. */
@@ -29,200 +29,213 @@ static const int privify_en = 1;
Privileged operation emulation routines
**************************************************************************/
-static IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_rfi(VCPU * vcpu, INST64 inst)
{
return vcpu_rfi(vcpu);
}
-static IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_bsw0(VCPU * vcpu, INST64 inst)
{
return vcpu_bsw0(vcpu);
}
-static IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_bsw1(VCPU * vcpu, INST64 inst)
{
return vcpu_bsw1(vcpu);
}
-static IA64FAULT priv_cover(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_cover(VCPU * vcpu, INST64 inst)
{
return vcpu_cover(vcpu);
}
-static IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptc_l(VCPU * vcpu, INST64 inst)
{
- UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
- UINT64 log_range;
+ u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3);
+ u64 log_range;
- log_range = ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
- return vcpu_ptc_l(vcpu,vadr,log_range);
+ log_range = ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_l(vcpu, vadr, log_range);
}
-static IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptc_e(VCPU * vcpu, INST64 inst)
{
- UINT src = inst.M28.r3;
+ unsigned int src = inst.M28.r3;
// NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64)
if (privify_en && src > 63)
- return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64)));
- return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src));
+ return vcpu_fc(vcpu, vcpu_get_gr(vcpu, src - 64));
+ return vcpu_ptc_e(vcpu, vcpu_get_gr(vcpu, src));
}
-static IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptc_g(VCPU * vcpu, INST64 inst)
{
- UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
- UINT64 addr_range;
+ u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3);
+ u64 addr_range;
- addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
- return vcpu_ptc_g(vcpu,vadr,addr_range);
+ addr_range = 1 << ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_g(vcpu, vadr, addr_range);
}
-static IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptc_ga(VCPU * vcpu, INST64 inst)
{
- UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
- UINT64 addr_range;
+ u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3);
+ u64 addr_range;
- addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
- return vcpu_ptc_ga(vcpu,vadr,addr_range);
+ addr_range = 1 << ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2);
+ return vcpu_ptc_ga(vcpu, vadr, addr_range);
}
-static IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptr_d(VCPU * vcpu, INST64 inst)
{
- UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
- UINT64 log_range;
+ u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3);
+ u64 log_range;
- log_range = (vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2;
- return vcpu_ptr_d(vcpu,vadr,log_range);
+ log_range = (vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2;
+ return vcpu_ptr_d(vcpu, vadr, log_range);
}
-static IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ptr_i(VCPU * vcpu, INST64 inst)
{
- UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
- UINT64 log_range;
+ u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3);
+ u64 log_range;
- log_range = (vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2;
- return vcpu_ptr_i(vcpu,vadr,log_range);
+ log_range = (vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2;
+ return vcpu_ptr_i(vcpu, vadr, log_range);
}
-static IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_tpa(VCPU * vcpu, INST64 inst)
{
- UINT64 padr;
- UINT fault;
- UINT src = inst.M46.r3;
+ u64 padr;
+ unsigned int fault;
+ unsigned int src = inst.M46.r3;
// NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64)
if (privify_en && src > 63)
- fault = vcpu_ttag(vcpu,vcpu_get_gr(vcpu,src-64),&padr);
- else fault = vcpu_tpa(vcpu,vcpu_get_gr(vcpu,src),&padr);
+ fault = vcpu_ttag(vcpu, vcpu_get_gr(vcpu, src - 64), &padr);
+ else
+ fault = vcpu_tpa(vcpu, vcpu_get_gr(vcpu, src), &padr);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M46.r1, padr, 0);
- else return fault;
+ else
+ return fault;
}
-static IA64FAULT priv_tak(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_tak(VCPU * vcpu, INST64 inst)
{
- UINT64 key;
- UINT fault;
- UINT src = inst.M46.r3;
+ u64 key;
+ unsigned int fault;
+ unsigned int src = inst.M46.r3;
// NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64)
if (privify_en && src > 63)
- fault = vcpu_thash(vcpu,vcpu_get_gr(vcpu,src-64),&key);
- else fault = vcpu_tak(vcpu,vcpu_get_gr(vcpu,src),&key);
+ fault = vcpu_thash(vcpu, vcpu_get_gr(vcpu, src - 64), &key);
+ else
+ fault = vcpu_tak(vcpu, vcpu_get_gr(vcpu, src), &key);
if (fault == IA64_NO_FAULT)
- return vcpu_set_gr(vcpu, inst.M46.r1, key,0);
- else return fault;
+ return vcpu_set_gr(vcpu, inst.M46.r1, key, 0);
+ else
+ return fault;
}
/************************************
* Insert translation register/cache
************************************/
-static IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_itr_d(VCPU * vcpu, INST64 inst)
{
- UINT64 fault, itir, ifa, pte, slot;
+ u64 fault, itir, ifa, pte, slot;
- //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- pte = vcpu_get_gr(vcpu,inst.M42.r2);
- slot = vcpu_get_gr(vcpu,inst.M42.r3);
+ //if (!vcpu_get_psr_ic(vcpu))
+ // return IA64_ILLOP_FAULT;
+ fault = vcpu_get_itir(vcpu, &itir);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ fault = vcpu_get_ifa(vcpu, &ifa);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ pte = vcpu_get_gr(vcpu, inst.M42.r2);
+ slot = vcpu_get_gr(vcpu, inst.M42.r3);
- return (vcpu_itr_d(vcpu,slot,pte,itir,ifa));
+ return vcpu_itr_d(vcpu, slot, pte, itir, ifa);
}
-static IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_itr_i(VCPU * vcpu, INST64 inst)
{
- UINT64 fault, itir, ifa, pte, slot;
+ u64 fault, itir, ifa, pte, slot;
- //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- pte = vcpu_get_gr(vcpu,inst.M42.r2);
- slot = vcpu_get_gr(vcpu,inst.M42.r3);
+ //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT;
+ fault = vcpu_get_itir(vcpu, &itir);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ fault = vcpu_get_ifa(vcpu, &ifa);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ pte = vcpu_get_gr(vcpu, inst.M42.r2);
+ slot = vcpu_get_gr(vcpu, inst.M42.r3);
- return (vcpu_itr_i(vcpu,slot,pte,itir,ifa));
+ return vcpu_itr_i(vcpu, slot, pte, itir, ifa);
}
-static IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_itc_d(VCPU * vcpu, INST64 inst)
{
- UINT64 fault, itir, ifa, pte;
+ u64 fault, itir, ifa, pte;
- //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- pte = vcpu_get_gr(vcpu,inst.M41.r2);
+ //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT;
+ fault = vcpu_get_itir(vcpu, &itir);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ fault = vcpu_get_ifa(vcpu, &ifa);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ pte = vcpu_get_gr(vcpu, inst.M41.r2);
- return (vcpu_itc_d(vcpu,pte,itir,ifa));
+ return vcpu_itc_d(vcpu, pte, itir, ifa);
}
-static IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_itc_i(VCPU * vcpu, INST64 inst)
{
- UINT64 fault, itir, ifa, pte;
+ u64 fault, itir, ifa, pte;
- //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
- return(IA64_ILLOP_FAULT);
- pte = vcpu_get_gr(vcpu,inst.M41.r2);
+ //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT;
+ fault = vcpu_get_itir(vcpu, &itir);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ fault = vcpu_get_ifa(vcpu, &ifa);
+ if (fault != IA64_NO_FAULT)
+ return IA64_ILLOP_FAULT;
+ pte = vcpu_get_gr(vcpu, inst.M41.r2);
- return (vcpu_itc_i(vcpu,pte,itir,ifa));
+ return vcpu_itc_i(vcpu, pte, itir, ifa);
}
/*************************************
* Moves to semi-privileged registers
*************************************/
-static IA64FAULT priv_mov_to_ar_imm(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_ar_imm(VCPU * vcpu, INST64 inst)
{
// I27 and M30 are identical for these fields
- UINT64 ar3 = inst.M30.ar3;
- UINT64 imm = vcpu_get_gr(vcpu,inst.M30.imm);
- return (vcpu_set_ar(vcpu,ar3,imm));
+ u64 ar3 = inst.M30.ar3;
+ u64 imm = vcpu_get_gr(vcpu, inst.M30.imm);
+ return vcpu_set_ar(vcpu, ar3, imm);
}
-static IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_ar_reg(VCPU * vcpu, INST64 inst)
{
// I26 and M29 are identical for these fields
- UINT64 ar3 = inst.M29.ar3;
+ u64 ar3 = inst.M29.ar3;
if (privify_en && inst.M29.r2 > 63 && inst.M29.ar3 < 8) {
// privified mov from kr
- UINT64 val;
- if (vcpu_get_ar(vcpu,ar3,&val) != IA64_ILLOP_FAULT)
- return vcpu_set_gr(vcpu, inst.M29.r2-64, val,0);
- else return IA64_ILLOP_FAULT;
- }
- else {
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2);
- return (vcpu_set_ar(vcpu,ar3,r2));
+ u64 val;
+ if (vcpu_get_ar(vcpu, ar3, &val) != IA64_ILLOP_FAULT)
+ return vcpu_set_gr(vcpu, inst.M29.r2 - 64, val, 0);
+ else
+ return IA64_ILLOP_FAULT;
+ } else {
+ u64 r2 = vcpu_get_gr(vcpu, inst.M29.r2);
+ return vcpu_set_ar(vcpu, ar3, r2);
}
}
@@ -230,177 +243,205 @@ static IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst)
* Moves to privileged registers
********************************/
-static IA64FAULT priv_mov_to_pkr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_pkr(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_pkr(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_pkr(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_rr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_rr(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_rr(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_rr(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_dbr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_dbr(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_dbr(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_dbr(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_ibr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_ibr(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_ibr(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_ibr(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_pmc(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_pmc(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_pmc(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_pmc(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_pmd(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_pmd(VCPU * vcpu, INST64 inst)
{
- UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
- UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
- return (vcpu_set_pmd(vcpu,r3,r2));
+ u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3);
+ u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2);
+ return vcpu_set_pmd(vcpu, r3, r2);
}
-static IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_cr(VCPU * vcpu, INST64 inst)
{
- UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2);
+ u64 val = vcpu_get_gr(vcpu, inst.M32.r2);
perfc_incra(mov_to_cr, inst.M32.cr3);
switch (inst.M32.cr3) {
- case 0: return vcpu_set_dcr(vcpu,val);
- case 1: return vcpu_set_itm(vcpu,val);
- case 2: return vcpu_set_iva(vcpu,val);
- case 8: return vcpu_set_pta(vcpu,val);
- case 16:return vcpu_set_ipsr(vcpu,val);
- case 17:return vcpu_set_isr(vcpu,val);
- case 19:return vcpu_set_iip(vcpu,val);
- case 20:return vcpu_set_ifa(vcpu,val);
- case 21:return vcpu_set_itir(vcpu,val);
- case 22:return vcpu_set_iipa(vcpu,val);
- case 23:return vcpu_set_ifs(vcpu,val);
- case 24:return vcpu_set_iim(vcpu,val);
- case 25:return vcpu_set_iha(vcpu,val);
- case 64:return vcpu_set_lid(vcpu,val);
- case 65:return IA64_ILLOP_FAULT;
- case 66:return vcpu_set_tpr(vcpu,val);
- case 67:return vcpu_set_eoi(vcpu,val);
- case 68:return IA64_ILLOP_FAULT;
- case 69:return IA64_ILLOP_FAULT;
- case 70:return IA64_ILLOP_FAULT;
- case 71:return IA64_ILLOP_FAULT;
- case 72:return vcpu_set_itv(vcpu,val);
- case 73:return vcpu_set_pmv(vcpu,val);
- case 74:return vcpu_set_cmcv(vcpu,val);
- case 80:return vcpu_set_lrr0(vcpu,val);
- case 81:return vcpu_set_lrr1(vcpu,val);
- default: return IA64_ILLOP_FAULT;
+ case 0:
+ return vcpu_set_dcr(vcpu, val);
+ case 1:
+ return vcpu_set_itm(vcpu, val);
+ case 2:
+ return vcpu_set_iva(vcpu, val);
+ case 8:
+ return vcpu_set_pta(vcpu, val);
+ case 16:
+ return vcpu_set_ipsr(vcpu, val);
+ case 17:
+ return vcpu_set_isr(vcpu, val);
+ case 19:
+ return vcpu_set_iip(vcpu, val);
+ case 20:
+ return vcpu_set_ifa(vcpu, val);
+ case 21:
+ return vcpu_set_itir(vcpu, val);
+ case 22:
+ return vcpu_set_iipa(vcpu, val);
+ case 23:
+ return vcpu_set_ifs(vcpu, val);
+ case 24:
+ return vcpu_set_iim(vcpu, val);
+ case 25:
+ return vcpu_set_iha(vcpu, val);
+ case 64:
+ return vcpu_set_lid(vcpu, val);
+ case 65:
+ return IA64_ILLOP_FAULT;
+ case 66:
+ return vcpu_set_tpr(vcpu, val);
+ case 67:
+ return vcpu_set_eoi(vcpu, val);
+ case 68:
+ return IA64_ILLOP_FAULT;
+ case 69:
+ return IA64_ILLOP_FAULT;
+ case 70:
+ return IA64_ILLOP_FAULT;
+ case 71:
+ return IA64_ILLOP_FAULT;
+ case 72:
+ return vcpu_set_itv(vcpu, val);
+ case 73:
+ return vcpu_set_pmv(vcpu, val);
+ case 74:
+ return vcpu_set_cmcv(vcpu, val);
+ case 80:
+ return vcpu_set_lrr0(vcpu, val);
+ case 81:
+ return vcpu_set_lrr1(vcpu, val);
+ default:
+ return IA64_ILLOP_FAULT;
}
}
-static IA64FAULT priv_rsm(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_rsm(VCPU * vcpu, INST64 inst)
{
- UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
- return vcpu_reset_psr_sm(vcpu,imm24);
+ u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm;
+ return vcpu_reset_psr_sm(vcpu, imm24);
}
-static IA64FAULT priv_ssm(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_ssm(VCPU * vcpu, INST64 inst)
{
- UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
- return vcpu_set_psr_sm(vcpu,imm24);
+ u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm;
+ return vcpu_set_psr_sm(vcpu, imm24);
}
/**
* @todo Check for reserved bits and return IA64_RSVDREG_FAULT.
*/
-static IA64FAULT priv_mov_to_psr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_to_psr(VCPU * vcpu, INST64 inst)
{
- UINT64 val = vcpu_get_gr(vcpu, inst.M35.r2);
- return vcpu_set_psr_l(vcpu,val);
+ u64 val = vcpu_get_gr(vcpu, inst.M35.r2);
+ return vcpu_set_psr_l(vcpu, val);
}
/**********************************
* Moves from privileged registers
**********************************/
-static IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_rr(VCPU * vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
IA64FAULT fault;
- UINT64 reg;
-
- reg = vcpu_get_gr(vcpu,inst.M43.r3);
+ u64 reg;
+
+ reg = vcpu_get_gr(vcpu, inst.M43.r3);
if (privify_en && inst.M43.r1 > 63) {
// privified mov from cpuid
- fault = vcpu_get_cpuid(vcpu,reg,&val);
+ fault = vcpu_get_cpuid(vcpu, reg, &val);
if (fault == IA64_NO_FAULT)
- return vcpu_set_gr(vcpu, inst.M43.r1-64, val, 0);
- }
- else {
- fault = vcpu_get_rr(vcpu,reg,&val);
+ return vcpu_set_gr(vcpu, inst.M43.r1 - 64, val, 0);
+ } else {
+ fault = vcpu_get_rr(vcpu, reg, &val);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M43.r1, val, 0);
}
return fault;
}
-static IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_pkr(VCPU * vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
IA64FAULT fault;
-
- fault = vcpu_get_pkr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+
+ fault = vcpu_get_pkr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M43.r1, val, 0);
- else return fault;
+ else
+ return fault;
}
-static IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_dbr(VCPU * vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
IA64FAULT fault;
-
- fault = vcpu_get_dbr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+
+ fault = vcpu_get_dbr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M43.r1, val, 0);
- else return fault;
+ else
+ return fault;
}
-static IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_ibr(VCPU * vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
IA64FAULT fault;
-
- fault = vcpu_get_ibr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+
+ fault = vcpu_get_ibr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M43.r1, val, 0);
- else return fault;
+ else
+ return fault;
}
-static IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_pmc(VCPU * vcpu, INST64 inst)
{
- UINT64 val;
+ u64 val;
IA64FAULT fault;
- UINT64 reg;
-
- reg = vcpu_get_gr(vcpu,inst.M43.r3);
+ u64 reg;
+
+ reg = vcpu_get_gr(vcpu, inst.M43.r3);
if (privify_en && inst.M43.r1 > 63) {
// privified mov from pmd
- fault = vcpu_get_pmd(vcpu,reg,&val);
+ fault = vcpu_get_pmd(vcpu, reg, &val);
if (fault == IA64_NO_FAULT)
- return vcpu_set_gr(vcpu, inst.M43.r1-64, val, 0);
- }
- else {
- fault = vcpu_get_pmc(vcpu,reg,&val);
+ return vcpu_set_gr(vcpu, inst.M43.r1 - 64, val, 0);
+ } else {
+ fault = vcpu_get_pmc(vcpu, reg, &val);
if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, inst.M43.r1, val, 0);
}
@@ -410,55 +451,84 @@ static IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst)
#define cr_get(cr) \
((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \
vcpu_set_gr(vcpu, tgt, val, 0) : fault;
-
-static IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst)
+
+static IA64FAULT priv_mov_from_cr(VCPU * vcpu, INST64 inst)
{
- UINT64 tgt = inst.M33.r1;
- UINT64 val;
+ u64 tgt = inst.M33.r1;
+ u64 val;
IA64FAULT fault;
perfc_incra(mov_from_cr, inst.M33.cr3);
switch (inst.M33.cr3) {
- case 0: return cr_get(dcr);
- case 1: return cr_get(itm);
- case 2: return cr_get(iva);
- case 8: return cr_get(pta);
- case 16:return cr_get(ipsr);
- case 17:return cr_get(isr);
- case 19:return cr_get(iip);
- case 20:return cr_get(ifa);
- case 21:return cr_get(itir);
- case 22:return cr_get(iipa);
- case 23:return cr_get(ifs);
- case 24:return cr_get(iim);
- case 25:return cr_get(iha);
- case 64:return cr_get(lid);
- case 65:return cr_get(ivr);
- case 66:return cr_get(tpr);
- case 67:return vcpu_set_gr(vcpu,tgt,0L,0);
- case 68:return cr_get(irr0);
- case 69:return cr_get(irr1);
- case 70:return cr_get(irr2);
- case 71:return cr_get(irr3);
- case 72:return cr_get(itv);
- case 73:return cr_get(pmv);
- case 74:return cr_get(cmcv);
- case 80:return cr_get(lrr0);
- case 81:return cr_get(lrr1);
- default: return IA64_ILLOP_FAULT;
+ case 0:
+ return cr_get(dcr);
+ case 1:
+ return cr_get(itm);
+ case 2:
+ return cr_get(iva);
+ case 8:
+ return cr_get(pta);
+ case 16:
+ return cr_get(ipsr);
+ case 17:
+ return cr_get(isr);
+ case 19:
+ return cr_get(iip);
+ case 20:
+ return cr_get(ifa);
+ case 21:
+ return cr_get(itir);
+ case 22:
+ return cr_get(iipa);
+ case 23:
+ return cr_get(ifs);
+ case 24:
+ return cr_get(iim);
+ case 25:
+ return cr_get(iha);
+ case 64:
+ return cr_get(lid);
+ case 65:
+ return cr_get(ivr);
+ case 66:
+ return cr_get(tpr);
+ case 67:
+ return vcpu_set_gr(vcpu, tgt, 0L, 0);
+ case 68:
+ return cr_get(irr0);
+ case 69:
+ return cr_get(irr1);
+ case 70:
+ return cr_get(irr2);
+ case 71:
+ return cr_get(irr3);
+ case 72:
+ return cr_get(itv);
+ case 73:
+ return cr_get(pmv);
+ case 74:
+ return cr_get(cmcv);
+ case 80:
+ return cr_get(lrr0);
+ case 81:
+ return cr_get(lrr1);
+ default:
+ return IA64_ILLOP_FAULT;
}
return IA64_ILLOP_FAULT;
}
-static IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst)
+static IA64FAULT priv_mov_from_psr(VCPU * vcpu, INST64 inst)
{
- UINT64 tgt = inst.M33.r1;
- UINT64 val;
+ u64 tgt = inst.M33.r1;
+ u64 val;
IA64FAULT fault;
- if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT)
+ fault = vcpu_get_psr(vcpu, &val);
+ if (fault == IA64_NO_FAULT)
return vcpu_set_gr(vcpu, tgt, val, 0);
- else return fault;
+ else
+ return fault;
}
/**************************************************************************
@@ -483,28 +553,28 @@ static const IA64_SLOT_TYPE slot_types[0x20][3] = {
};
// pointer to privileged emulation function
-typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst);
+typedef IA64FAULT(*PPEFCN) (VCPU * vcpu, INST64 inst);
static const PPEFCN Mpriv_funcs[64] = {
- priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr,
- priv_mov_to_pmc, priv_mov_to_pmd, 0, 0,
- 0, priv_ptc_l, priv_ptc_g, priv_ptc_ga,
- priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i,
- priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr, priv_mov_from_pkr,
- priv_mov_from_pmc, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, priv_tpa, priv_tak,
- 0, 0, 0, 0,
- priv_mov_from_cr, priv_mov_from_psr, 0, 0,
- 0, 0, 0, 0,
- priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i,
- 0, 0, 0, 0,
- priv_ptc_e, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr,
+ priv_mov_to_pmc, priv_mov_to_pmd, 0, 0,
+ 0, priv_ptc_l, priv_ptc_g, priv_ptc_ga,
+ priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i,
+ priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr,
+ priv_mov_from_pkr,
+ priv_mov_from_pmc, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, priv_tpa, priv_tak,
+ 0, 0, 0, 0,
+ priv_mov_from_cr, priv_mov_from_psr, 0, 0,
+ 0, 0, 0, 0,
+ priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i,
+ 0, 0, 0, 0,
+ priv_ptc_e, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
};
-static IA64FAULT
-priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
+static IA64FAULT priv_handle_op(VCPU * vcpu, REGS * regs, int privlvl)
{
IA64_BUNDLE bundle;
int slot;
@@ -512,85 +582,97 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
INST64 inst;
PPEFCN pfunc;
unsigned long ipsr = regs->cr_ipsr;
- UINT64 iip = regs->cr_iip;
+ u64 iip = regs->cr_iip;
int x6;
-
+
// make a local copy of the bundle containing the privop
if (!vcpu_get_domain_bundle(vcpu, regs, iip, &bundle)) {
//return vcpu_force_data_miss(vcpu, regs->cr_iip);
return vcpu_force_inst_miss(vcpu, regs->cr_iip);
}
-
#if 0
- if (iip==0xa000000100001820) {
+ if (iip == 0xa000000100001820) {
static int firstpagefault = 1;
if (firstpagefault) {
- printf("*** First time to domain page fault!\n"); firstpagefault=0;
+ printk("*** First time to domain page fault!\n");
+ firstpagefault = 0;
}
}
#endif
if (privop_trace) {
static long i = 400;
- //if (i > 0) printf("priv_handle_op: at 0x%lx\n",iip);
- if (i > 0) printf("priv_handle_op: privop trace at 0x%lx, itc=%lx, itm=%lx\n",
- iip,ia64_get_itc(),ia64_get_itm());
+ //if (i > 0) printk("priv_handle_op: at 0x%lx\n",iip);
+ if (i > 0)
+ printk("priv_handle_op: privop trace at 0x%lx, "
+ "itc=%lx, itm=%lx\n",
+ iip, ia64_get_itc(), ia64_get_itm());
i--;
}
slot = ((struct ia64_psr *)&ipsr)->ri;
- if (!slot) inst.inst = (bundle.i64[0]>>5) & MASK_41;
+ if (!slot)
+ inst.inst = (bundle.i64[0] >> 5) & MASK_41;
else if (slot == 1)
- inst.inst = ((bundle.i64[0]>>46) | bundle.i64[1]<<18) & MASK_41;
- else if (slot == 2) inst.inst = (bundle.i64[1]>>23) & MASK_41;
- else printf("priv_handle_op: illegal slot: %d\n", slot);
+ inst.inst =
+ ((bundle.i64[0] >> 46) | bundle.i64[1] << 18) & MASK_41;
+ else if (slot == 2)
+ inst.inst = (bundle.i64[1] >> 23) & MASK_41;
+ else
+ printk("priv_handle_op: illegal slot: %d\n", slot);
slot_type = slot_types[bundle.template][slot];
if (priv_verbose) {
- printf("priv_handle_op: checking bundle at 0x%lx (op=0x%016lx) slot %d (type=%d)\n",
- iip, (UINT64)inst.inst, slot, slot_type);
+ printk("priv_handle_op: checking bundle at 0x%lx "
+ "(op=0x%016lx) slot %d (type=%d)\n",
+ iip, (u64) inst.inst, slot, slot_type);
}
if (slot_type == B && inst.generic.major == 0 && inst.B8.x6 == 0x0) {
// break instr for privified cover
- }
- else if (privlvl != 2) return (IA64_ILLOP_FAULT);
+ } else if (privlvl != 2)
+ return IA64_ILLOP_FAULT;
switch (slot_type) {
- case M:
+ case M:
if (inst.generic.major == 0) {
#if 0
if (inst.M29.x6 == 0 && inst.M29.x3 == 0) {
privcnt.cover++;
- return priv_cover(vcpu,inst);
+ return priv_cover(vcpu, inst);
}
#endif
- if (inst.M29.x3 != 0) break;
+ if (inst.M29.x3 != 0)
+ break;
if (inst.M30.x4 == 8 && inst.M30.x2 == 2) {
perfc_incrc(mov_to_ar_imm);
- return priv_mov_to_ar_imm(vcpu,inst);
+ return priv_mov_to_ar_imm(vcpu, inst);
}
if (inst.M44.x4 == 6) {
perfc_incrc(ssm);
- return priv_ssm(vcpu,inst);
+ return priv_ssm(vcpu, inst);
}
if (inst.M44.x4 == 7) {
perfc_incrc(rsm);
- return priv_rsm(vcpu,inst);
+ return priv_rsm(vcpu, inst);
}
break;
- }
- else if (inst.generic.major != 1) break;
+ } else if (inst.generic.major != 1)
+ break;
x6 = inst.M29.x6;
if (x6 == 0x2a) {
if (privify_en && inst.M29.r2 > 63 && inst.M29.ar3 < 8)
perfc_incrc(mov_from_ar); // privified mov from kr
else
perfc_incrc(mov_to_ar_reg);
- return priv_mov_to_ar_reg(vcpu,inst);
+ return priv_mov_to_ar_reg(vcpu, inst);
}
- if (inst.M29.x3 != 0) break;
- if (!(pfunc = Mpriv_funcs[x6])) break;
- if (x6 == 0x1e || x6 == 0x1f) { // tpa or tak are "special"
+ if (inst.M29.x3 != 0)
+ break;
+ if (!(pfunc = Mpriv_funcs[x6]))
+ break;
+ if (x6 == 0x1e || x6 == 0x1f) { // tpa or tak are "special"
if (privify_en && inst.M46.r3 > 63) {
- if (x6 == 0x1e) x6 = 0x1b;
- else x6 = 0x1a;
+ if (x6 == 0x1e)
+ x6 = 0x1b;
+ else
+ x6 = 0x1a;
}
}
if (privify_en && x6 == 52 && inst.M28.r3 > 63)
@@ -599,61 +681,66 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
perfc_incrc(cpuid);
else
perfc_incra(misc_privop, x6);
- return (*pfunc)(vcpu,inst);
+ return (*pfunc) (vcpu, inst);
break;
- case B:
- if (inst.generic.major != 0) break;
+ case B:
+ if (inst.generic.major != 0)
+ break;
if (inst.B8.x6 == 0x08) {
IA64FAULT fault;
perfc_incrc(rfi);
- fault = priv_rfi(vcpu,inst);
- if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS;
+ fault = priv_rfi(vcpu, inst);
+ if (fault == IA64_NO_FAULT)
+ fault = IA64_RFI_IN_PROGRESS;
return fault;
}
if (inst.B8.x6 == 0x0c) {
perfc_incrc(bsw0);
- return priv_bsw0(vcpu,inst);
+ return priv_bsw0(vcpu, inst);
}
if (inst.B8.x6 == 0x0d) {
perfc_incrc(bsw1);
- return priv_bsw1(vcpu,inst);
+ return priv_bsw1(vcpu, inst);
}
if (inst.B8.x6 == 0x0) {
// break instr for privified cover
perfc_incrc(cover);
- return priv_cover(vcpu,inst);
+ return priv_cover(vcpu, inst);
}
break;
- case I:
- if (inst.generic.major != 0) break;
+ case I:
+ if (inst.generic.major != 0)
+ break;
#if 0
if (inst.I26.x6 == 0 && inst.I26.x3 == 0) {
perfc_incrc(cover);
- return priv_cover(vcpu,inst);
+ return priv_cover(vcpu, inst);
}
#endif
- if (inst.I26.x3 != 0) break; // I26.x3 == I27.x3
+ if (inst.I26.x3 != 0)
+ break; // I26.x3 == I27.x3
if (inst.I26.x6 == 0x2a) {
if (privify_en && inst.I26.r2 > 63 && inst.I26.ar3 < 8)
- perfc_incrc(mov_from_ar); // privified mov from kr
- else
+ perfc_incrc(mov_from_ar); // privified mov from kr
+ else
perfc_incrc(mov_to_ar_reg);
- return priv_mov_to_ar_reg(vcpu,inst);
+ return priv_mov_to_ar_reg(vcpu, inst);
}
if (inst.I27.x6 == 0x0a) {
perfc_incrc(mov_to_ar_imm);
- return priv_mov_to_ar_imm(vcpu,inst);
+ return priv_mov_to_ar_imm(vcpu, inst);
}
break;
- default:
+ default:
break;
}
- //printf("We who are about do die salute you\n");
- printf("priv_handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d), ipsr=0x%lx\n",
- iip, (UINT64)inst.inst, slot, slot_type, ipsr);
- //printf("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip));
- //thread_mozambique("privop fault\n");
- return (IA64_ILLOP_FAULT);
+ //printk("We who are about do die salute you\n");
+ printk("priv_handle_op: can't handle privop at 0x%lx (op=0x%016lx) "
+ "slot %d (type=%d), ipsr=0x%lx\n",
+ iip, (u64) inst.inst, slot, slot_type, ipsr);
+ //printk("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip));
+ //thread_mozambique("privop fault\n");
+ return IA64_ILLOP_FAULT;
}
/** Emulate a privileged operation.
@@ -666,142 +753,139 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
* @param isrcode interrupt service routine code
* @return fault
*/
-IA64FAULT
-priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr)
+IA64FAULT priv_emulate(VCPU * vcpu, REGS * regs, u64 isr)
{
IA64FAULT fault;
- UINT64 ipsr = regs->cr_ipsr;
- UINT64 isrcode = (isr >> 4) & 0xf;
+ u64 ipsr = regs->cr_ipsr;
+ u64 isrcode = (isr >> 4) & 0xf;
int privlvl;
// handle privops masked as illops? and breaks (6)
if (isrcode != 1 && isrcode != 2 && isrcode != 0 && isrcode != 6) {
- printf("priv_emulate: isrcode != 0 or 1 or 2\n");
- printf("priv_emulate: returning ILLOP, not implemented!\n");
- while (1);
+ printk("priv_emulate: isrcode != 0 or 1 or 2\n");
+ printk("priv_emulate: returning ILLOP, not implemented!\n");
+ while (1) ;
return IA64_ILLOP_FAULT;
}
//if (isrcode != 1 && isrcode != 2) return 0;
privlvl = ia64_get_cpl(ipsr);
// its OK for a privified-cover to be executed in user-land
- fault = priv_handle_op(vcpu,regs,privlvl);
- if ((fault == IA64_NO_FAULT) || (fault == IA64_EXTINT_VECTOR)) { // success!!
+ fault = priv_handle_op(vcpu, regs, privlvl);
+ if ((fault == IA64_NO_FAULT) || (fault == IA64_EXTINT_VECTOR)) {
+ // success!!
// update iip/ipsr to point to the next instruction
(void)vcpu_increment_iip(vcpu);
}
if (fault == IA64_ILLOP_FAULT)
- printf("priv_emulate: priv_handle_op fails, "
- "isr=0x%lx iip=%lx\n",isr, regs->cr_iip);
+ printk("priv_emulate: priv_handle_op fails, "
+ "isr=0x%lx iip=%lx\n", isr, regs->cr_iip);
return fault;
}
/* hyperprivops are generally executed in assembly (with physical psr.ic off)
* so this code is primarily used for debugging them */
-int
-ia64_hyperprivop(unsigned long iim, REGS *regs)
+int ia64_hyperprivop(unsigned long iim, REGS * regs)
{
struct vcpu *v = current;
- UINT64 val;
- UINT64 itir, ifa;
+ u64 val;
+ u64 itir, ifa;
if (!iim || iim > HYPERPRIVOP_MAX) {
panic_domain(regs, "bad hyperprivop: iim=%lx, iip=0x%lx\n",
- iim, regs->cr_iip);
+ iim, regs->cr_iip);
return 1;
}
perfc_incra(slow_hyperprivop, iim);
- switch(iim) {
- case HYPERPRIVOP_RFI:
- (void)vcpu_rfi(v);
+ switch (iim) {
+ case HYPERPRIVOP_RFI:
+ vcpu_rfi(v);
return 0; // don't update iip
- case HYPERPRIVOP_RSM_DT:
- (void)vcpu_reset_psr_dt(v);
+ case HYPERPRIVOP_RSM_DT:
+ vcpu_reset_psr_dt(v);
return 1;
- case HYPERPRIVOP_SSM_DT:
- (void)vcpu_set_psr_dt(v);
+ case HYPERPRIVOP_SSM_DT:
+ vcpu_set_psr_dt(v);
return 1;
- case HYPERPRIVOP_COVER:
- (void)vcpu_cover(v);
+ case HYPERPRIVOP_COVER:
+ vcpu_cover(v);
return 1;
- case HYPERPRIVOP_ITC_D:
- (void)vcpu_get_itir(v,&itir);
- (void)vcpu_get_ifa(v,&ifa);
- (void)vcpu_itc_d(v,regs->r8,itir,ifa);
+ case HYPERPRIVOP_ITC_D:
+ vcpu_get_itir(v, &itir);
+ vcpu_get_ifa(v, &ifa);
+ vcpu_itc_d(v, regs->r8, itir, ifa);
return 1;
- case HYPERPRIVOP_ITC_I:
- (void)vcpu_get_itir(v,&itir);
- (void)vcpu_get_ifa(v,&ifa);
- (void)vcpu_itc_i(v,regs->r8,itir,ifa);
+ case HYPERPRIVOP_ITC_I:
+ vcpu_get_itir(v, &itir);
+ vcpu_get_ifa(v, &ifa);
+ vcpu_itc_i(v, regs->r8, itir, ifa);
return 1;
- case HYPERPRIVOP_SSM_I:
- (void)vcpu_set_psr_i(v);
+ case HYPERPRIVOP_SSM_I:
+ vcpu_set_psr_i(v);
return 1;
- case HYPERPRIVOP_GET_IVR:
- (void)vcpu_get_ivr(v,&val);
+ case HYPERPRIVOP_GET_IVR:
+ vcpu_get_ivr(v, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_GET_TPR:
- (void)vcpu_get_tpr(v,&val);
+ case HYPERPRIVOP_GET_TPR:
+ vcpu_get_tpr(v, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_SET_TPR:
- (void)vcpu_set_tpr(v,regs->r8);
+ case HYPERPRIVOP_SET_TPR:
+ vcpu_set_tpr(v, regs->r8);
return 1;
- case HYPERPRIVOP_EOI:
- (void)vcpu_set_eoi(v,0L);
+ case HYPERPRIVOP_EOI:
+ vcpu_set_eoi(v, 0L);
return 1;
- case HYPERPRIVOP_SET_ITM:
- (void)vcpu_set_itm(v,regs->r8);
+ case HYPERPRIVOP_SET_ITM:
+ vcpu_set_itm(v, regs->r8);
return 1;
- case HYPERPRIVOP_THASH:
- (void)vcpu_thash(v,regs->r8,&val);
+ case HYPERPRIVOP_THASH:
+ vcpu_thash(v, regs->r8, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_PTC_GA:
- (void)vcpu_ptc_ga(v,regs->r8,(1L << ((regs->r9 & 0xfc) >> 2)));
+ case HYPERPRIVOP_PTC_GA:
+ vcpu_ptc_ga(v, regs->r8, (1L << ((regs->r9 & 0xfc) >> 2)));
return 1;
- case HYPERPRIVOP_ITR_D:
- (void)vcpu_get_itir(v,&itir);
- (void)vcpu_get_ifa(v,&ifa);
- (void)vcpu_itr_d(v,regs->r8,regs->r9,itir,ifa);
+ case HYPERPRIVOP_ITR_D:
+ vcpu_get_itir(v, &itir);
+ vcpu_get_ifa(v, &ifa);
+ vcpu_itr_d(v, regs->r8, regs->r9, itir, ifa);
return 1;
- case HYPERPRIVOP_GET_RR:
- (void)vcpu_get_rr(v,regs->r8,&val);
+ case HYPERPRIVOP_GET_RR:
+ vcpu_get_rr(v, regs->r8, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_SET_RR:
- (void)vcpu_set_rr(v,regs->r8,regs->r9);
+ case HYPERPRIVOP_SET_RR:
+ vcpu_set_rr(v, regs->r8, regs->r9);
return 1;
- case HYPERPRIVOP_SET_KR:
- (void)vcpu_set_ar(v,regs->r8,regs->r9);
+ case HYPERPRIVOP_SET_KR:
+ vcpu_set_ar(v, regs->r8, regs->r9);
return 1;
- case HYPERPRIVOP_FC:
- (void)vcpu_fc(v,regs->r8);
+ case HYPERPRIVOP_FC:
+ vcpu_fc(v, regs->r8);
return 1;
- case HYPERPRIVOP_GET_CPUID:
- (void)vcpu_get_cpuid(v,regs->r8,&val);
+ case HYPERPRIVOP_GET_CPUID:
+ vcpu_get_cpuid(v, regs->r8, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_GET_PMD:
- (void)vcpu_get_pmd(v,regs->r8,&val);
+ case HYPERPRIVOP_GET_PMD:
+ vcpu_get_pmd(v, regs->r8, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_GET_EFLAG:
- (void)vcpu_get_ar(v,24,&val);
+ case HYPERPRIVOP_GET_EFLAG:
+ vcpu_get_ar(v, 24, &val);
regs->r8 = val;
return 1;
- case HYPERPRIVOP_SET_EFLAG:
- (void)vcpu_set_ar(v,24,regs->r8);
+ case HYPERPRIVOP_SET_EFLAG:
+ vcpu_set_ar(v, 24, regs->r8);
return 1;
- case HYPERPRIVOP_RSM_BE:
- (void)vcpu_reset_psr_sm(v, IA64_PSR_BE);
+ case HYPERPRIVOP_RSM_BE:
+ vcpu_reset_psr_sm(v, IA64_PSR_BE);
return 1;
- case HYPERPRIVOP_GET_PSR:
- (void)vcpu_get_psr(v, &val);
+ case HYPERPRIVOP_GET_PSR:
+ vcpu_get_psr(v, &val);
regs->r8 = val;
return 1;
}
return 0;
}
-
-
diff --git a/xen/arch/ia64/xen/regionreg.c b/xen/arch/ia64/xen/regionreg.c
index 58c89201fb..b4d1d56b97 100644
--- a/xen/arch/ia64/xen/regionreg.c
+++ b/xen/arch/ia64/xen/regionreg.c
@@ -17,7 +17,7 @@
#include <asm/vcpu.h>
/* Defined in xemasm.S */
-extern void ia64_new_rr7(unsigned long rid, void *shared_info, void *shared_arch_info, unsigned long shared_info_va, unsigned long p_vhpt);
+extern void ia64_new_rr7(unsigned long rid, void *shared_info, void *shared_arch_info, unsigned long shared_info_va, unsigned long va_vhpt);
/* RID virtualization mechanism is really simple: domains have less rid bits
than the host and the host rid space is shared among the domains. (Values
@@ -106,7 +106,7 @@ void init_rid_allocator (void)
/* Due to RID mangling, we expect 24 RID bits!
This test should be removed if RID mangling is removed/modified. */
if (implemented_rid_bits != 24) {
- printf ("RID mangling expected 24 RID bits, got only %d!\n",
+ printk ("RID mangling expected 24 RID bits, got only %d!\n",
implemented_rid_bits);
BUG();
}
@@ -117,14 +117,14 @@ void init_rid_allocator (void)
/* Check for too small values. */
if (domain_rid_bits_default < IA64_MIN_IMPL_RID_BITS) {
- printf ("Default domain rid bits %d is too small, use %d\n",
+ printk ("Default domain rid bits %d is too small, use %d\n",
domain_rid_bits_default, IA64_MIN_IMPL_RID_BITS);
domain_rid_bits_default = IA64_MIN_IMPL_RID_BITS;
}
log_blocks = (implemented_rid_bits - IA64_MIN_IMPL_RID_BITS);
- printf ("Maximum number of domains: %d; %d RID bits per domain\n",
+ printk ("Maximum number of domains: %d; %d RID bits per domain\n",
(1 << (implemented_rid_bits - domain_rid_bits_default)) - 1,
domain_rid_bits_default);
@@ -185,7 +185,7 @@ int allocate_rid_range(struct domain *d, unsigned long ridbits)
d->arch.metaphysical_rr0 = allocate_metaphysical_rr(d, 0);
d->arch.metaphysical_rr4 = allocate_metaphysical_rr(d, 1);
- printf("### domain %p: rid=%x-%x mp_rid=%x\n",
+ printk("### domain %p: rid=%x-%x mp_rid=%x\n",
d, d->arch.starting_rid, d->arch.ending_rid,
d->arch.starting_mp_rid);
@@ -260,7 +260,7 @@ int set_one_rr(unsigned long rr, unsigned long val)
} else if (rreg == 7) {
ia64_new_rr7(vmMangleRID(newrrv.rrval),v->domain->shared_info,
v->arch.privregs, v->domain->arch.shared_info_va,
- __get_cpu_var(vhpt_paddr));
+ __va_ul(vcpu_vhpt_maddr(v)));
} else {
set_rr(rr,newrrv.rrval);
}
diff --git a/xen/arch/ia64/xen/tlb_track.c b/xen/arch/ia64/xen/tlb_track.c
new file mode 100644
index 0000000000..07816a4acb
--- /dev/null
+++ b/xen/arch/ia64/xen/tlb_track.c
@@ -0,0 +1,507 @@
+/******************************************************************************
+ * tlb_track.c
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <asm/tlb_track.h>
+#include <asm/p2m_entry.h>
+#include <asm/vmx_mm_def.h> /* for IA64_RR_SHIFT */
+#include <asm/vmx_vcpu.h> /* for VRN7 */
+#include <asm/vcpu.h> /* for PSCB() */
+
+#define CONFIG_TLB_TRACK_DEBUG
+#ifdef CONFIG_TLB_TRACK_DEBUG
+# define tlb_track_printd(fmt, ...) \
+ printk("%s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__)
+#else
+# define tlb_track_printd(fmt, ...) do { } while (0)
+#endif
+
+static int
+tlb_track_allocate_entries(struct tlb_track* tlb_track)
+{
+ struct page_info* entry_page;
+ struct tlb_track_entry* track_entries;
+ unsigned int allocated;
+ unsigned long i;
+
+ BUG_ON(tlb_track->num_free > 0);
+ if (tlb_track->num_entries >= tlb_track->limit) {
+ dprintk(XENLOG_WARNING, "%s: num_entries %d limit %d\n",
+ __func__, tlb_track->num_entries, tlb_track->limit);
+ return -ENOMEM;
+ }
+ entry_page = alloc_domheap_page(NULL);
+ if (entry_page == NULL) {
+ dprintk(XENLOG_WARNING,
+ "%s: domheap page failed. num_entries %d limit %d\n",
+ __func__, tlb_track->num_entries, tlb_track->limit);
+ return -ENOMEM;
+ }
+
+ list_add(&entry_page->list, &tlb_track->page_list);
+ track_entries = (struct tlb_track_entry*)page_to_virt(entry_page);
+ allocated = PAGE_SIZE / sizeof(track_entries[0]);
+ tlb_track->num_entries += allocated;
+ tlb_track->num_free += allocated;
+ for (i = 0; i < allocated; i++) {
+ list_add(&track_entries[i].list, &tlb_track->free_list);
+ // tlb_track_printd("track_entries[%ld] 0x%p\n", i, &track_entries[i]);
+ }
+ tlb_track_printd("allocated %d num_entries %d num_free %d\n",
+ allocated, tlb_track->num_entries, tlb_track->num_free);
+ return 0;
+}
+
+
+int
+tlb_track_create(struct domain* d)
+{
+ struct tlb_track* tlb_track = NULL;
+ struct page_info* hash_page = NULL;
+ unsigned int hash_size;
+ unsigned int hash_shift;
+ unsigned int i;
+
+ tlb_track = xmalloc(struct tlb_track);
+ if (tlb_track == NULL)
+ goto out;
+
+ hash_page = alloc_domheap_page(NULL);
+ if (hash_page == NULL)
+ goto out;
+
+ spin_lock_init(&tlb_track->free_list_lock);
+ INIT_LIST_HEAD(&tlb_track->free_list);
+ tlb_track->limit = TLB_TRACK_LIMIT_ENTRIES;
+ tlb_track->num_entries = 0;
+ tlb_track->num_free = 0;
+ INIT_LIST_HEAD(&tlb_track->page_list);
+ if (tlb_track_allocate_entries(tlb_track) < 0)
+ goto out;
+
+ spin_lock_init(&tlb_track->hash_lock);
+ /* XXX hash size optimization */
+ hash_size = PAGE_SIZE / sizeof(tlb_track->hash[0]);
+ for (hash_shift = 0; (1 << (hash_shift + 1)) < hash_size; hash_shift++)
+ /* nothing */;
+ tlb_track->hash_size = (1 << hash_shift);
+ tlb_track->hash_shift = hash_shift;
+ tlb_track->hash_mask = (1 << hash_shift) - 1;
+ tlb_track->hash = page_to_virt(hash_page);
+ for (i = 0; i < tlb_track->hash_size; i++)
+ INIT_LIST_HEAD(&tlb_track->hash[i]);
+
+ smp_mb(); /* make initialization visible before use. */
+ d->arch.tlb_track = tlb_track;
+ printk("%s:%d hash 0x%p hash_size %d \n",
+ __func__, __LINE__, tlb_track->hash, tlb_track->hash_size);
+
+ return 0;
+
+out:
+ if (hash_page != NULL)
+ free_domheap_page(hash_page);
+
+ if (tlb_track != NULL)
+ xfree(tlb_track);
+
+ return -ENOMEM;
+}
+
+void
+tlb_track_destroy(struct domain* d)
+{
+ struct tlb_track* tlb_track = d->arch.tlb_track;
+ struct page_info* page;
+ struct page_info* next;
+
+ spin_lock(&tlb_track->free_list_lock);
+ BUG_ON(tlb_track->num_free != tlb_track->num_entries);
+
+ list_for_each_entry_safe(page, next, &tlb_track->page_list, list) {
+ list_del(&page->list);
+ free_domheap_page(page);
+ }
+
+ free_domheap_page(virt_to_page(tlb_track->hash));
+ xfree(tlb_track);
+ // d->tlb_track = NULL;
+}
+
+static struct tlb_track_entry*
+tlb_track_get_entry(struct tlb_track* tlb_track)
+{
+ struct tlb_track_entry* entry = NULL;
+ spin_lock(&tlb_track->free_list_lock);
+ if (tlb_track->num_free == 0)
+ (void)tlb_track_allocate_entries(tlb_track);
+
+ if (tlb_track->num_free > 0) {
+ BUG_ON(list_empty(&tlb_track->free_list));
+ entry = list_entry(tlb_track->free_list.next,
+ struct tlb_track_entry, list);
+ tlb_track->num_free--;
+ list_del(&entry->list);
+ }
+ spin_unlock(&tlb_track->free_list_lock);
+ return entry;
+}
+
+void
+tlb_track_free_entry(struct tlb_track* tlb_track,
+ struct tlb_track_entry* entry)
+{
+ spin_lock(&tlb_track->free_list_lock);
+ list_add(&entry->list, &tlb_track->free_list);
+ tlb_track->num_free++;
+ spin_unlock(&tlb_track->free_list_lock);
+}
+
+
+#include <linux/hash.h>
+/* XXX hash function. */
+static struct list_head*
+tlb_track_hash_head(struct tlb_track* tlb_track, volatile pte_t* ptep)
+{
+ unsigned long hash = hash_long((unsigned long)ptep, tlb_track->hash_shift);
+ BUG_ON(hash >= tlb_track->hash_size);
+ BUG_ON((hash & tlb_track->hash_mask) != hash);
+ return &tlb_track->hash[hash];
+}
+
+static int
+tlb_track_pte_zapped(pte_t old_pte, pte_t ret_pte)
+{
+ if (pte_pfn(old_pte) != pte_pfn(ret_pte) ||
+ (pte_val(old_pte) & ~(_PFN_MASK | _PAGE_TLB_TRACK_MASK)) !=
+ (pte_val(ret_pte) & ~(_PFN_MASK | _PAGE_TLB_TRACK_MASK))) {
+ /* Other thread zapped the p2m entry. */
+ return 1;
+ }
+ return 0;
+}
+
+static TLB_TRACK_RET_T
+tlb_track_insert_or_dirty(struct tlb_track* tlb_track, struct mm_struct* mm,
+ volatile pte_t* ptep, pte_t old_pte,
+ unsigned long vaddr, unsigned long rid)
+{
+ unsigned long mfn = pte_pfn(old_pte);
+ struct list_head* head = tlb_track_hash_head(tlb_track, ptep);
+ struct tlb_track_entry* entry;
+ struct tlb_track_entry* new_entry = NULL;
+ unsigned long bit_to_be_set = _PAGE_TLB_INSERTED;
+ pte_t new_pte;
+ pte_t ret_pte;
+
+ struct vcpu* v = current;
+ TLB_TRACK_RET_T ret = TLB_TRACK_NOT_FOUND;
+
+#if 0 /* this is done at vcpu_tlb_track_insert_or_dirty() */
+ perfc_incrc(tlb_track_iod);
+ if (!pte_tlb_tracking(old_pte)) {
+ perfc_incrc(tlb_track_iod_not_tracked);
+ return TLB_TRACK_NOT_TRACKED;
+ }
+#endif
+ if (pte_tlb_inserted_many(old_pte)) {
+ perfc_incrc(tlb_track_iod_tracked_many);
+ return TLB_TRACK_MANY;
+ }
+
+ /* vaddr must be normalized so that it is in vrn7 and page aligned. */
+ BUG_ON((vaddr >> IA64_RR_SHIFT) != VRN7);
+ BUG_ON((vaddr & ~PAGE_MASK) != 0);
+#if 0
+ tlb_track_printd("\n"
+ "\tmfn 0x%016lx\n"
+ "\told_pte 0x%016lx ptep 0x%p\n"
+ "\tptep_val 0x%016lx vaddr 0x%016lx rid %ld\n"
+ "\ttlb_track 0x%p head 0x%p\n",
+ mfn,
+ pte_val(old_pte), ptep, pte_val(*ptep),
+ vaddr, rid,
+ tlb_track, head);
+#endif
+
+ again:
+ /*
+ * zapping side may zap the p2m entry and then remove tlb track entry
+ * non-atomically. We may see the stale tlb track entry here.
+ * p2m_entry_retry() handles such a case.
+ * Or other thread may zap the p2m entry and remove tlb track entry
+ * and inserted new tlb track entry.
+ */
+ spin_lock(&tlb_track->hash_lock);
+ list_for_each_entry(entry, head, list) {
+ if (entry->ptep != ptep)
+ continue;
+
+ if (pte_pfn(entry->pte_val) == mfn) {
+ // tlb_track_entry_printf(entry);
+ if (entry->vaddr == vaddr && entry->rid == rid) {
+ // tlb_track_printd("TLB_TRACK_FOUND\n");
+ ret = TLB_TRACK_FOUND;
+ perfc_incrc(tlb_track_iod_found);
+#ifdef CONFIG_TLB_TRACK_CNT
+ entry->cnt++;
+ if (entry->cnt > TLB_TRACK_CNT_FORCE_MANY) {
+ /*
+ * heuristics:
+ * If a page is used to transfer data by dev channel,
+ * it would be unmapped with small amount access
+ * (once or twice tlb insert) after real device
+ * I/O completion. It would be short period.
+ * However this page seems to be accessed many times.
+ * We guess that this page is used I/O ring
+ * so that tracking this entry might be useless.
+ */
+ // tlb_track_entry_printf(entry);
+ // tlb_track_printd("cnt = %ld\n", entry->cnt);
+ perfc_incrc(tlb_track_iod_force_many);
+ goto force_many;
+ }
+#endif
+ goto found;
+ } else {
+#ifdef CONFIG_TLB_TRACK_CNT
+ force_many:
+#endif
+ if (!pte_tlb_inserted(old_pte)) {
+ printk("%s:%d racy update\n", __func__, __LINE__);
+ old_pte = __pte(pte_val(old_pte) | _PAGE_TLB_INSERTED);
+ }
+ new_pte = __pte(pte_val(old_pte) | _PAGE_TLB_INSERTED_MANY);
+ ret_pte = ptep_cmpxchg_rel(mm, vaddr, ptep, old_pte, new_pte);
+ if (pte_val(ret_pte) != pte_val(old_pte)) {
+ // tlb_track_printd("TLB_TRACK_AGAIN\n");
+ ret = TLB_TRACK_AGAIN;
+ perfc_incrc(tlb_track_iod_again);
+ } else {
+ // tlb_track_printd("TLB_TRACK_MANY del entry 0x%p\n",
+ // entry);
+ ret = TLB_TRACK_MANY;
+ list_del(&entry->list);
+ // tlb_track_entry_printf(entry);
+ perfc_incrc(tlb_track_iod_tracked_many_del);
+ }
+ goto out;
+ }
+ }
+
+ /*
+ * Other thread changed the p2m entry and removed and inserted new
+ * tlb tracn entry after we get old_pte, but before we get
+ * spinlock.
+ */
+ // tlb_track_printd("TLB_TRACK_AGAIN\n");
+ ret = TLB_TRACK_AGAIN;
+ perfc_incrc(tlb_track_iod_again);
+ goto out;
+ }
+
+ entry = NULL; // prevent freeing entry.
+ if (pte_tlb_inserted(old_pte)) {
+ /* Other thread else removed the tlb_track_entry after we got old_pte
+ before we got spin lock. */
+ ret = TLB_TRACK_AGAIN;
+ perfc_incrc(tlb_track_iod_again);
+ goto out;
+ }
+ if (new_entry == NULL && bit_to_be_set == _PAGE_TLB_INSERTED) {
+ spin_unlock(&tlb_track->hash_lock);
+ new_entry = tlb_track_get_entry(tlb_track);
+ if (new_entry == NULL) {
+ tlb_track_printd("get_entry failed\n");
+ /* entry can't be allocated.
+ fall down into full flush mode. */
+ bit_to_be_set |= _PAGE_TLB_INSERTED_MANY;
+ perfc_incrc(tlb_track_iod_new_failed);
+ }
+ // tlb_track_printd("new_entry 0x%p\n", new_entry);
+ perfc_incrc(tlb_track_iod_new_entry);
+ goto again;
+ }
+
+ BUG_ON(pte_tlb_inserted_many(old_pte));
+ new_pte = __pte(pte_val(old_pte) | bit_to_be_set);
+ ret_pte = ptep_cmpxchg_rel(mm, vaddr, ptep, old_pte, new_pte);
+ if (pte_val(old_pte) != pte_val(ret_pte)) {
+ if (tlb_track_pte_zapped(old_pte, ret_pte)) {
+ // tlb_track_printd("zapped TLB_TRACK_AGAIN\n");
+ ret = TLB_TRACK_AGAIN;
+ perfc_incrc(tlb_track_iod_again);
+ goto out;
+ }
+
+ /* Other thread set _PAGE_TLB_INSERTED and/or _PAGE_TLB_INSERTED_MANY */
+ if (pte_tlb_inserted_many(ret_pte)) {
+ /* Other thread already set _PAGE_TLB_INSERTED_MANY and
+ removed the entry. */
+ // tlb_track_printd("iserted TLB_TRACK_MANY\n");
+ BUG_ON(!pte_tlb_inserted(ret_pte));
+ ret = TLB_TRACK_MANY;
+ perfc_incrc(tlb_track_iod_new_many);
+ goto out;
+ }
+ BUG_ON(pte_tlb_inserted(ret_pte));
+ BUG();
+ }
+ if (new_entry) {
+ // tlb_track_printd("iserting new_entry 0x%p\n", new_entry);
+ entry = new_entry;
+ new_entry = NULL;
+
+ entry->ptep = ptep;
+ entry->pte_val = old_pte;
+ entry->vaddr = vaddr;
+ entry->rid = rid;
+ cpus_clear(entry->pcpu_dirty_mask);
+ vcpus_clear(entry->vcpu_dirty_mask);
+ list_add(&entry->list, head);
+
+#ifdef CONFIG_TLB_TRACK_CNT
+ entry->cnt = 0;
+#endif
+ perfc_incrc(tlb_track_iod_insert);
+ // tlb_track_entry_printf(entry);
+ } else {
+ goto out;
+ }
+
+ found:
+ BUG_ON(v->processor >= NR_CPUS);
+ cpu_set(v->processor, entry->pcpu_dirty_mask);
+ BUG_ON(v->vcpu_id >= NR_CPUS);
+ vcpu_set(v->vcpu_id, entry->vcpu_dirty_mask);
+ perfc_incrc(tlb_track_iod_dirtied);
+
+ out:
+ spin_unlock(&tlb_track->hash_lock);
+ if (ret == TLB_TRACK_MANY && entry != NULL)
+ tlb_track_free_entry(tlb_track, entry);
+ if (new_entry != NULL)
+ tlb_track_free_entry(tlb_track, new_entry);
+ return ret;
+}
+
+void
+__vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr,
+ struct p2m_entry* entry)
+{
+ unsigned long vrn = vaddr >> IA64_RR_SHIFT;
+ unsigned long rid = PSCB(vcpu, rrs[vrn]);
+ TLB_TRACK_RET_T ret;
+
+ /* normalize vrn7
+ When linux dom0 case, vrn7 is the most common case. */
+ vaddr |= VRN7 << VRN_SHIFT;
+ vaddr &= PAGE_MASK;
+ ret = tlb_track_insert_or_dirty(vcpu->domain->arch.tlb_track,
+ &vcpu->domain->arch.mm,
+ entry->ptep, entry->used,
+ vaddr, rid);
+ if (ret == TLB_TRACK_AGAIN)
+ p2m_entry_set_retry(entry);
+}
+
+TLB_TRACK_RET_T
+tlb_track_search_and_remove(struct tlb_track* tlb_track,
+ volatile pte_t* ptep, pte_t old_pte,
+ struct tlb_track_entry** entryp)
+{
+ unsigned long mfn = pte_pfn(old_pte);
+ struct list_head* head = tlb_track_hash_head(tlb_track, ptep);
+ struct tlb_track_entry* entry;
+
+ perfc_incrc(tlb_track_sar);
+ if (!pte_tlb_tracking(old_pte)) {
+ perfc_incrc(tlb_track_sar_not_tracked);
+ return TLB_TRACK_NOT_TRACKED;
+ }
+ if (!pte_tlb_inserted(old_pte)) {
+ BUG_ON(pte_tlb_inserted_many(old_pte));
+ perfc_incrc(tlb_track_sar_not_found);
+ return TLB_TRACK_NOT_FOUND;
+ }
+ if (pte_tlb_inserted_many(old_pte)) {
+ BUG_ON(!pte_tlb_inserted(old_pte));
+ perfc_incrc(tlb_track_sar_many);
+ return TLB_TRACK_MANY;
+ }
+
+ spin_lock(&tlb_track->hash_lock);
+ list_for_each_entry(entry, head, list) {
+ if (entry->ptep != ptep)
+ continue;
+
+ if (pte_pfn(entry->pte_val) == mfn) {
+ list_del(&entry->list);
+ spin_unlock(&tlb_track->hash_lock);
+ *entryp = entry;
+ perfc_incrc(tlb_track_sar_found);
+ // tlb_track_entry_printf(entry);
+#ifdef CONFIG_TLB_TRACK_CNT
+ // tlb_track_printd("cnt = %ld\n", entry->cnt);
+#endif
+ return TLB_TRACK_FOUND;
+ }
+ BUG();
+ }
+ BUG();
+ spin_unlock(&tlb_track->hash_lock);
+ return TLB_TRACK_NOT_TRACKED;
+}
+
+/* for debug */
+void
+__tlb_track_entry_printf(const char* func, int line,
+ const struct tlb_track_entry* entry)
+{
+ char pcpumask_buf[NR_CPUS + 1];
+ char vcpumask_buf[MAX_VIRT_CPUS + 1];
+ cpumask_scnprintf(pcpumask_buf, sizeof(pcpumask_buf),
+ entry->pcpu_dirty_mask);
+ vcpumask_scnprintf(vcpumask_buf, sizeof(vcpumask_buf),
+ entry->vcpu_dirty_mask);
+ printk("%s:%d\n"
+ "\tmfn 0x%016lx\n"
+ "\told_pte 0x%016lx ptep 0x%p\n"
+ "\tpte_val 0x%016lx vaddr 0x%016lx rid %ld\n"
+ "\tpcpu_dirty_mask %s vcpu_dirty_mask %s\n"
+ "\tentry 0x%p\n",
+ func, line,
+ pte_pfn(entry->pte_val),
+ pte_val(entry->pte_val), entry->ptep, pte_val(*entry->ptep),
+ entry->vaddr, entry->rid,
+ pcpumask_buf, vcpumask_buf,
+ entry);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/ia64/xen/vcpu.c b/xen/arch/ia64/xen/vcpu.c
index cab06b2576..bc5784fff0 100644
--- a/xen/arch/ia64/xen/vcpu.c
+++ b/xen/arch/ia64/xen/vcpu.c
@@ -24,29 +24,35 @@
#include <asm/bundle.h>
#include <asm/privop_stat.h>
#include <asm/uaccess.h>
+#include <asm/p2m_entry.h>
+#include <asm/tlb_track.h>
/* FIXME: where these declarations should be there ? */
-extern void getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs);
-extern void setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs);
-extern void getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs);
+extern void getreg(unsigned long regnum, unsigned long *val, int *nat,
+ struct pt_regs *regs);
+extern void setreg(unsigned long regnum, unsigned long val, int nat,
+ struct pt_regs *regs);
+extern void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval,
+ struct pt_regs *regs);
-extern void setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs);
+extern void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval,
+ struct pt_regs *regs);
-typedef union {
+typedef union {
struct ia64_psr ia64_psr;
unsigned long i64;
} PSR;
// this def for vcpu_regs won't work if kernel stack is present
-//#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs
+//#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs
-#define TRUE 1
-#define FALSE 0
+#define TRUE 1
+#define FALSE 0
#define IA64_PTA_SZ_BIT 2
#define IA64_PTA_VF_BIT 8
#define IA64_PTA_BASE_BIT 15
#define IA64_PTA_LFMT (1UL << IA64_PTA_VF_BIT)
-#define IA64_PTA_SZ(x) (x##UL << IA64_PTA_SZ_BIT)
+#define IA64_PTA_SZ(x) (x##UL << IA64_PTA_SZ_BIT)
unsigned long vcpu_verbose = 0;
@@ -54,23 +60,23 @@ unsigned long vcpu_verbose = 0;
VCPU general register access routines
**************************************************************************/
#ifdef XEN
-UINT64
-vcpu_get_gr(VCPU *vcpu, unsigned long reg)
+u64 vcpu_get_gr(VCPU * vcpu, unsigned long reg)
{
REGS *regs = vcpu_regs(vcpu);
- UINT64 val;
+ u64 val;
- if (!reg) return 0;
- getreg(reg,&val,0,regs); // FIXME: handle NATs later
+ if (!reg)
+ return 0;
+ getreg(reg, &val, 0, regs); // FIXME: handle NATs later
return val;
}
-IA64FAULT
-vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val)
+
+IA64FAULT vcpu_get_gr_nat(VCPU * vcpu, unsigned long reg, u64 * val)
{
REGS *regs = vcpu_regs(vcpu);
int nat;
- getreg(reg,val,&nat,regs); // FIXME: handle NATs later
+ getreg(reg, val, &nat, regs); // FIXME: handle NATs later
if (nat)
return IA64_NAT_CONSUMPTION_VECTOR;
return 0;
@@ -79,32 +85,33 @@ vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val)
// returns:
// IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault
// IA64_NO_FAULT otherwise
-IA64FAULT
-vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value, int nat)
+IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value, int nat)
{
REGS *regs = vcpu_regs(vcpu);
long sof = (regs->cr_ifs) & 0x7f;
- if (!reg) return IA64_ILLOP_FAULT;
- if (reg >= sof + 32) return IA64_ILLOP_FAULT;
- setreg(reg,value,nat,regs); // FIXME: handle NATs later
+ if (!reg)
+ return IA64_ILLOP_FAULT;
+ if (reg >= sof + 32)
+ return IA64_ILLOP_FAULT;
+ setreg(reg, value, nat, regs); // FIXME: handle NATs later
return IA64_NO_FAULT;
}
IA64FAULT
-vcpu_get_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val)
+vcpu_get_fpreg(VCPU * vcpu, unsigned long reg, struct ia64_fpreg * val)
{
REGS *regs = vcpu_regs(vcpu);
- getfpreg(reg,val,regs); // FIXME: handle NATs later
+ getfpreg(reg, val, regs); // FIXME: handle NATs later
return IA64_NO_FAULT;
}
IA64FAULT
-vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val)
+vcpu_set_fpreg(VCPU * vcpu, unsigned long reg, struct ia64_fpreg * val)
{
REGS *regs = vcpu_regs(vcpu);
- if(reg > 1)
- setfpreg(reg,val,regs); // FIXME: handle NATs later
+ if (reg > 1)
+ setfpreg(reg, val, regs); // FIXME: handle NATs later
return IA64_NO_FAULT;
}
@@ -112,38 +119,39 @@ vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val)
// returns:
// IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault
// IA64_NO_FAULT otherwise
-IA64FAULT
-vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value)
+IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value)
{
REGS *regs = vcpu_regs(vcpu);
long sof = (regs->cr_ifs) & 0x7f;
- if (!reg) return IA64_ILLOP_FAULT;
- if (reg >= sof + 32) return IA64_ILLOP_FAULT;
- setreg(reg,value,0,regs); // FIXME: handle NATs later
+ if (!reg)
+ return IA64_ILLOP_FAULT;
+ if (reg >= sof + 32)
+ return IA64_ILLOP_FAULT;
+ setreg(reg, value, 0, regs); // FIXME: handle NATs later
return IA64_NO_FAULT;
}
#endif
-void vcpu_init_regs (struct vcpu *v)
+void vcpu_init_regs(struct vcpu *v)
{
struct pt_regs *regs;
- regs = vcpu_regs (v);
+ regs = vcpu_regs(v);
if (VMX_DOMAIN(v)) {
/* dt/rt/it:1;i/ic:1, si:1, vm/bn:1, ac:1 */
/* Need to be expanded as macro */
regs->cr_ipsr = 0x501008826008;
} else {
regs->cr_ipsr = ia64_getreg(_IA64_REG_PSR)
- | IA64_PSR_BITS_TO_SET | IA64_PSR_BN;
+ | IA64_PSR_BITS_TO_SET | IA64_PSR_BN;
regs->cr_ipsr &= ~(IA64_PSR_BITS_TO_CLEAR
| IA64_PSR_RI | IA64_PSR_IS);
// domain runs at PL2
regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT;
}
- regs->cr_ifs = 1UL << 63; /* or clear? */
+ regs->cr_ifs = 1UL << 63; /* or clear? */
regs->ar_fpsr = FPSR_DEFAULT;
if (VMX_DOMAIN(v)) {
@@ -153,13 +161,13 @@ void vcpu_init_regs (struct vcpu *v)
VCPU(v, dcr) = 0;
} else {
init_all_rr(v);
- regs->ar_rsc |= (2 << 2); /* force PL2/3 */
+ regs->ar_rsc |= (2 << 2); /* force PL2/3 */
VCPU(v, banknum) = 1;
VCPU(v, metaphysical_mode) = 1;
VCPU(v, interrupt_mask_addr) =
- (unsigned char *)v->domain->arch.shared_info_va +
- INT_ENABLE_OFFSET(v);
- VCPU(v, itv) = (1 << 16); /* timer vector masked */
+ (unsigned char *)v->domain->arch.shared_info_va +
+ INT_ENABLE_OFFSET(v);
+ VCPU(v, itv) = (1 << 16); /* timer vector masked */
}
v->arch.domain_itm_last = -1L;
@@ -169,7 +177,7 @@ void vcpu_init_regs (struct vcpu *v)
VCPU privileged application register access routines
**************************************************************************/
-void vcpu_load_kernel_regs(VCPU *vcpu)
+void vcpu_load_kernel_regs(VCPU * vcpu)
{
ia64_set_kr(0, VCPU(vcpu, krs[0]));
ia64_set_kr(1, VCPU(vcpu, krs[1]));
@@ -184,26 +192,33 @@ void vcpu_load_kernel_regs(VCPU *vcpu)
/* GCC 4.0.2 seems not to be able to suppress this call!. */
#define ia64_setreg_unknown_kr() return IA64_ILLOP_FAULT
-IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_ar(VCPU * vcpu, u64 reg, u64 val)
{
- if (reg == 44) return (vcpu_set_itc(vcpu,val));
- else if (reg == 27) return (IA64_ILLOP_FAULT);
+ if (reg == 44)
+ return vcpu_set_itc(vcpu, val);
+ else if (reg == 27)
+ return IA64_ILLOP_FAULT;
else if (reg == 24)
- printf("warning: setting ar.eflg is a no-op; no IA-32 support\n");
- else if (reg > 7) return (IA64_ILLOP_FAULT);
+ printk("warning: setting ar.eflg is a no-op; no IA-32 "
+ "support\n");
+ else if (reg > 7)
+ return IA64_ILLOP_FAULT;
else {
- PSCB(vcpu,krs[reg]) = val;
- ia64_set_kr(reg,val);
+ PSCB(vcpu, krs[reg]) = val;
+ ia64_set_kr(reg, val);
}
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val)
+IA64FAULT vcpu_get_ar(VCPU * vcpu, u64 reg, u64 * val)
{
if (reg == 24)
- printf("warning: getting ar.eflg is a no-op; no IA-32 support\n");
- else if (reg > 7) return (IA64_ILLOP_FAULT);
- else *val = PSCB(vcpu,krs[reg]);
+ printk("warning: getting ar.eflg is a no-op; no IA-32 "
+ "support\n");
+ else if (reg > 7)
+ return IA64_ILLOP_FAULT;
+ else
+ *val = PSCB(vcpu, krs[reg]);
return IA64_NO_FAULT;
}
@@ -211,24 +226,25 @@ IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val)
VCPU processor status register access routines
**************************************************************************/
-void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode)
+void vcpu_set_metaphysical_mode(VCPU * vcpu, BOOLEAN newmode)
{
/* only do something if mode changes */
- if (!!newmode ^ !!PSCB(vcpu,metaphysical_mode)) {
- PSCB(vcpu,metaphysical_mode) = newmode;
- if (newmode) set_metaphysical_rr0();
- else if (PSCB(vcpu,rrs[0]) != -1)
- set_one_rr(0, PSCB(vcpu,rrs[0]));
+ if (!!newmode ^ !!PSCB(vcpu, metaphysical_mode)) {
+ PSCB(vcpu, metaphysical_mode) = newmode;
+ if (newmode)
+ set_metaphysical_rr0();
+ else if (PSCB(vcpu, rrs[0]) != -1)
+ set_one_rr(0, PSCB(vcpu, rrs[0]));
}
}
-IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu)
+IA64FAULT vcpu_reset_psr_dt(VCPU * vcpu)
{
- vcpu_set_metaphysical_mode(vcpu,TRUE);
+ vcpu_set_metaphysical_mode(vcpu, TRUE);
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
+IA64FAULT vcpu_reset_psr_sm(VCPU * vcpu, u64 imm24)
{
struct ia64_psr psr, imm, *ipsr;
REGS *regs = vcpu_regs(vcpu);
@@ -236,189 +252,261 @@ IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
//PRIVOP_COUNT_ADDR(regs,_RSM);
// TODO: All of these bits need to be virtualized
// TODO: Only allowed for current vcpu
- __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory");
ipsr = (struct ia64_psr *)&regs->cr_ipsr;
imm = *(struct ia64_psr *)&imm24;
// interrupt flag
if (imm.i)
- vcpu->vcpu_info->evtchn_upcall_mask = 1;
- if (imm.ic) PSCB(vcpu,interrupt_collection_enabled) = 0;
+ vcpu->vcpu_info->evtchn_upcall_mask = 1;
+ if (imm.ic)
+ PSCB(vcpu, interrupt_collection_enabled) = 0;
// interrupt collection flag
//if (imm.ic) PSCB(vcpu,interrupt_delivery_enabled) = 0;
// just handle psr.up and psr.pp for now
- if (imm24 & ~(IA64_PSR_BE | IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP
- | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT
- | IA64_PSR_DFL | IA64_PSR_DFH))
- return (IA64_ILLOP_FAULT);
- if (imm.dfh) ipsr->dfh = 0;
- if (imm.dfl) ipsr->dfl = 0;
+ if (imm24 & ~(IA64_PSR_BE | IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP |
+ IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT |
+ IA64_PSR_DFL | IA64_PSR_DFH))
+ return IA64_ILLOP_FAULT;
+ if (imm.dfh)
+ ipsr->dfh = 0;
+ if (imm.dfl)
+ ipsr->dfl = 0;
if (imm.pp) {
ipsr->pp = 1;
psr.pp = 1; // priv perf ctrs always enabled
- PSCB(vcpu,vpsr_pp) = 0; // but fool the domain if it gets psr
+ PSCB(vcpu, vpsr_pp) = 0; // but fool the domain if it gets psr
}
- if (imm.up) { ipsr->up = 0; psr.up = 0; }
- if (imm.sp) { ipsr->sp = 0; psr.sp = 0; }
- if (imm.be) ipsr->be = 0;
- if (imm.dt) vcpu_set_metaphysical_mode(vcpu,TRUE);
- __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+ if (imm.up) {
+ ipsr->up = 0;
+ psr.up = 0;
+ }
+ if (imm.sp) {
+ ipsr->sp = 0;
+ psr.sp = 0;
+ }
+ if (imm.be)
+ ipsr->be = 0;
+ if (imm.dt)
+ vcpu_set_metaphysical_mode(vcpu, TRUE);
+ __asm__ __volatile(";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
return IA64_NO_FAULT;
}
-
-IA64FAULT vcpu_set_psr_dt(VCPU *vcpu)
+IA64FAULT vcpu_set_psr_dt(VCPU * vcpu)
{
- vcpu_set_metaphysical_mode(vcpu,FALSE);
+ vcpu_set_metaphysical_mode(vcpu, FALSE);
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_psr_i(VCPU *vcpu)
+IA64FAULT vcpu_set_psr_i(VCPU * vcpu)
{
vcpu->vcpu_info->evtchn_upcall_mask = 0;
- PSCB(vcpu,interrupt_collection_enabled) = 1;
+ PSCB(vcpu, interrupt_collection_enabled) = 1;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24)
+IA64FAULT vcpu_set_psr_sm(VCPU * vcpu, u64 imm24)
{
struct ia64_psr psr, imm, *ipsr;
REGS *regs = vcpu_regs(vcpu);
- UINT64 mask, enabling_interrupts = 0;
+ u64 mask, enabling_interrupts = 0;
//PRIVOP_COUNT_ADDR(regs,_SSM);
// TODO: All of these bits need to be virtualized
- __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory");
imm = *(struct ia64_psr *)&imm24;
ipsr = (struct ia64_psr *)&regs->cr_ipsr;
// just handle psr.sp,pp and psr.i,ic (and user mask) for now
- mask = IA64_PSR_PP|IA64_PSR_SP|IA64_PSR_I|IA64_PSR_IC|IA64_PSR_UM |
- IA64_PSR_DT|IA64_PSR_DFL|IA64_PSR_DFH;
- if (imm24 & ~mask) return (IA64_ILLOP_FAULT);
- if (imm.dfh) ipsr->dfh = 1;
- if (imm.dfl) ipsr->dfl = 1;
+ mask =
+ IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_UM |
+ IA64_PSR_DT | IA64_PSR_DFL | IA64_PSR_DFH;
+ if (imm24 & ~mask)
+ return IA64_ILLOP_FAULT;
+ if (imm.dfh)
+ ipsr->dfh = 1;
+ if (imm.dfl)
+ ipsr->dfl = 1;
if (imm.pp) {
ipsr->pp = 1;
psr.pp = 1;
- PSCB(vcpu,vpsr_pp) = 1;
+ PSCB(vcpu, vpsr_pp) = 1;
+ }
+ if (imm.sp) {
+ ipsr->sp = 1;
+ psr.sp = 1;
}
- if (imm.sp) { ipsr->sp = 1; psr.sp = 1; }
if (imm.i) {
if (vcpu->vcpu_info->evtchn_upcall_mask) {
-//printf("vcpu_set_psr_sm: psr.ic 0->1\n");
+//printk("vcpu_set_psr_sm: psr.ic 0->1\n");
enabling_interrupts = 1;
}
vcpu->vcpu_info->evtchn_upcall_mask = 0;
}
- if (imm.ic) PSCB(vcpu,interrupt_collection_enabled) = 1;
+ if (imm.ic)
+ PSCB(vcpu, interrupt_collection_enabled) = 1;
// TODO: do this faster
- if (imm.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
- if (imm.mfh) { ipsr->mfh = 1; psr.mfh = 1; }
- if (imm.ac) { ipsr->ac = 1; psr.ac = 1; }
- if (imm.up) { ipsr->up = 1; psr.up = 1; }
+ if (imm.mfl) {
+ ipsr->mfl = 1;
+ psr.mfl = 1;
+ }
+ if (imm.mfh) {
+ ipsr->mfh = 1;
+ psr.mfh = 1;
+ }
+ if (imm.ac) {
+ ipsr->ac = 1;
+ psr.ac = 1;
+ }
+ if (imm.up) {
+ ipsr->up = 1;
+ psr.up = 1;
+ }
if (imm.be) {
- printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
- return (IA64_ILLOP_FAULT);
+ printk("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return IA64_ILLOP_FAULT;
}
- if (imm.dt) vcpu_set_metaphysical_mode(vcpu,FALSE);
- __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+ if (imm.dt)
+ vcpu_set_metaphysical_mode(vcpu, FALSE);
+ __asm__ __volatile(";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
if (enabling_interrupts &&
- vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
- PSCB(vcpu,pending_interruption) = 1;
+ vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
+ PSCB(vcpu, pending_interruption) = 1;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_psr_l(VCPU * vcpu, u64 val)
{
struct ia64_psr psr, newpsr, *ipsr;
REGS *regs = vcpu_regs(vcpu);
- UINT64 enabling_interrupts = 0;
+ u64 enabling_interrupts = 0;
// TODO: All of these bits need to be virtualized
- __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+ __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory");
newpsr = *(struct ia64_psr *)&val;
ipsr = (struct ia64_psr *)&regs->cr_ipsr;
// just handle psr.up and psr.pp for now
- //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP)) return (IA64_ILLOP_FAULT);
+ //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP))
+ // return IA64_ILLOP_FAULT;
// however trying to set other bits can't be an error as it is in ssm
- if (newpsr.dfh) ipsr->dfh = 1;
- if (newpsr.dfl) ipsr->dfl = 1;
+ if (newpsr.dfh)
+ ipsr->dfh = 1;
+ if (newpsr.dfl)
+ ipsr->dfl = 1;
if (newpsr.pp) {
- ipsr->pp = 1; psr.pp = 1;
- PSCB(vcpu,vpsr_pp) = 1;
+ ipsr->pp = 1;
+ psr.pp = 1;
+ PSCB(vcpu, vpsr_pp) = 1;
+ } else {
+ ipsr->pp = 1;
+ psr.pp = 1;
+ PSCB(vcpu, vpsr_pp) = 0;
}
- else {
- ipsr->pp = 1; psr.pp = 1;
- PSCB(vcpu,vpsr_pp) = 0;
+ if (newpsr.up) {
+ ipsr->up = 1;
+ psr.up = 1;
+ }
+ if (newpsr.sp) {
+ ipsr->sp = 1;
+ psr.sp = 1;
}
- if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
- if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; }
if (newpsr.i) {
if (vcpu->vcpu_info->evtchn_upcall_mask)
enabling_interrupts = 1;
vcpu->vcpu_info->evtchn_upcall_mask = 0;
}
- if (newpsr.ic) PSCB(vcpu,interrupt_collection_enabled) = 1;
- if (newpsr.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
- if (newpsr.mfh) { ipsr->mfh = 1; psr.mfh = 1; }
- if (newpsr.ac) { ipsr->ac = 1; psr.ac = 1; }
- if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
- if (newpsr.dt && newpsr.rt) vcpu_set_metaphysical_mode(vcpu,FALSE);
- else vcpu_set_metaphysical_mode(vcpu,TRUE);
+ if (newpsr.ic)
+ PSCB(vcpu, interrupt_collection_enabled) = 1;
+ if (newpsr.mfl) {
+ ipsr->mfl = 1;
+ psr.mfl = 1;
+ }
+ if (newpsr.mfh) {
+ ipsr->mfh = 1;
+ psr.mfh = 1;
+ }
+ if (newpsr.ac) {
+ ipsr->ac = 1;
+ psr.ac = 1;
+ }
+ if (newpsr.up) {
+ ipsr->up = 1;
+ psr.up = 1;
+ }
+ if (newpsr.dt && newpsr.rt)
+ vcpu_set_metaphysical_mode(vcpu, FALSE);
+ else
+ vcpu_set_metaphysical_mode(vcpu, TRUE);
if (newpsr.be) {
- printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
- return (IA64_ILLOP_FAULT);
+ printk("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return IA64_ILLOP_FAULT;
}
if (enabling_interrupts &&
- vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
- PSCB(vcpu,pending_interruption) = 1;
+ vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
+ PSCB(vcpu, pending_interruption) = 1;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_psr(VCPU * vcpu, u64 * pval)
{
REGS *regs = vcpu_regs(vcpu);
struct ia64_psr newpsr;
newpsr = *(struct ia64_psr *)&regs->cr_ipsr;
- if (newpsr.cpl == 2) newpsr.cpl = 0;
- if (!vcpu->vcpu_info->evtchn_upcall_mask) newpsr.i = 1;
- else newpsr.i = 0;
- if (PSCB(vcpu,interrupt_collection_enabled)) newpsr.ic = 1;
- else newpsr.ic = 0;
- if (PSCB(vcpu,metaphysical_mode)) newpsr.dt = 0;
- else newpsr.dt = 1;
- if (PSCB(vcpu,vpsr_pp)) newpsr.pp = 1;
- else newpsr.pp = 0;
+ if (newpsr.cpl == 2)
+ newpsr.cpl = 0;
+ if (!vcpu->vcpu_info->evtchn_upcall_mask)
+ newpsr.i = 1;
+ else
+ newpsr.i = 0;
+ if (PSCB(vcpu, interrupt_collection_enabled))
+ newpsr.ic = 1;
+ else
+ newpsr.ic = 0;
+ if (PSCB(vcpu, metaphysical_mode))
+ newpsr.dt = 0;
+ else
+ newpsr.dt = 1;
+ if (PSCB(vcpu, vpsr_pp))
+ newpsr.pp = 1;
+ else
+ newpsr.pp = 0;
*pval = *(unsigned long *)&newpsr;
return IA64_NO_FAULT;
}
-BOOLEAN vcpu_get_psr_ic(VCPU *vcpu)
+BOOLEAN vcpu_get_psr_ic(VCPU * vcpu)
{
- return !!PSCB(vcpu,interrupt_collection_enabled);
+ return !!PSCB(vcpu, interrupt_collection_enabled);
}
-BOOLEAN vcpu_get_psr_i(VCPU *vcpu)
+BOOLEAN vcpu_get_psr_i(VCPU * vcpu)
{
return !vcpu->vcpu_info->evtchn_upcall_mask;
}
-UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr)
+u64 vcpu_get_ipsr_int_state(VCPU * vcpu, u64 prevpsr)
{
- UINT64 dcr = PSCBX(vcpu,dcr);
+ u64 dcr = PSCBX(vcpu, dcr);
PSR psr;
- //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...\n",prevpsr);
+ //printk("*** vcpu_get_ipsr_int_state (0x%016lx)...\n",prevpsr);
psr.i64 = prevpsr;
- psr.ia64_psr.be = 0; if (dcr & IA64_DCR_BE) psr.ia64_psr.be = 1;
- psr.ia64_psr.pp = 0; if (dcr & IA64_DCR_PP) psr.ia64_psr.pp = 1;
- psr.ia64_psr.ic = PSCB(vcpu,interrupt_collection_enabled);
+ psr.ia64_psr.be = 0;
+ if (dcr & IA64_DCR_BE)
+ psr.ia64_psr.be = 1;
+ psr.ia64_psr.pp = 0;
+ if (dcr & IA64_DCR_PP)
+ psr.ia64_psr.pp = 1;
+ psr.ia64_psr.ic = PSCB(vcpu, interrupt_collection_enabled);
psr.ia64_psr.i = !vcpu->vcpu_info->evtchn_upcall_mask;
- psr.ia64_psr.bn = PSCB(vcpu,banknum);
- psr.ia64_psr.dt = 1; psr.ia64_psr.it = 1; psr.ia64_psr.rt = 1;
- if (psr.ia64_psr.cpl == 2) psr.ia64_psr.cpl = 0; // !!!! fool domain
+ psr.ia64_psr.bn = PSCB(vcpu, banknum);
+ psr.ia64_psr.dt = 1;
+ psr.ia64_psr.it = 1;
+ psr.ia64_psr.rt = 1;
+ if (psr.ia64_psr.cpl == 2)
+ psr.ia64_psr.cpl = 0; // !!!! fool domain
// psr.pk = 1;
- //printf("returns 0x%016lx...\n",psr.i64);
+ //printk("returns 0x%016lx...\n",psr.i64);
return psr.i64;
}
@@ -426,223 +514,227 @@ UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr)
VCPU control register access routines
**************************************************************************/
-IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_dcr(VCPU * vcpu, u64 * pval)
{
//verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu,iip));
// Reads of cr.dcr on Xen always have the sign bit set, so
// a domain can differentiate whether it is running on SP or not
- *pval = PSCBX(vcpu,dcr) | 0x8000000000000000L;
- return (IA64_NO_FAULT);
+ *pval = PSCBX(vcpu, dcr) | 0x8000000000000000L;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_iva(VCPU * vcpu, u64 * pval)
{
- if(VMX_DOMAIN(vcpu)){
- *pval = PSCB(vcpu,iva) & ~0x7fffL;
- }else{
- *pval = PSCBX(vcpu,iva) & ~0x7fffL;
- }
- return (IA64_NO_FAULT);
+ if (VMX_DOMAIN(vcpu))
+ *pval = PSCB(vcpu, iva) & ~0x7fffL;
+ else
+ *pval = PSCBX(vcpu, iva) & ~0x7fffL;
+
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_pta(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,pta);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, pta);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_ipsr(VCPU * vcpu, u64 * pval)
{
//REGS *regs = vcpu_regs(vcpu);
//*pval = regs->cr_ipsr;
- *pval = PSCB(vcpu,ipsr);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, ipsr);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_isr(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,isr);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, isr);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_iip(VCPU * vcpu, u64 * pval)
{
//REGS *regs = vcpu_regs(vcpu);
//*pval = regs->cr_iip;
- *pval = PSCB(vcpu,iip);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, iip);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_ifa(VCPU * vcpu, u64 * pval)
{
PRIVOP_COUNT_ADDR(vcpu_regs(vcpu), privop_inst_get_ifa);
- *pval = PSCB(vcpu,ifa);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, ifa);
+ return IA64_NO_FAULT;
}
-unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr)
+unsigned long vcpu_get_rr_ps(VCPU * vcpu, u64 vadr)
{
ia64_rr rr;
- rr.rrval = PSCB(vcpu,rrs)[vadr>>61];
- return(rr.ps);
+ rr.rrval = PSCB(vcpu, rrs)[vadr >> 61];
+ return rr.ps;
}
-unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr)
+unsigned long vcpu_get_rr_rid(VCPU * vcpu, u64 vadr)
{
ia64_rr rr;
- rr.rrval = PSCB(vcpu,rrs)[vadr>>61];
- return(rr.rid);
+ rr.rrval = PSCB(vcpu, rrs)[vadr >> 61];
+ return rr.rid;
}
-unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa)
+unsigned long vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa)
{
ia64_rr rr;
rr.rrval = 0;
- rr.ps = vcpu_get_rr_ps(vcpu,ifa);
- rr.rid = vcpu_get_rr_rid(vcpu,ifa);
- return (rr.rrval);
+ rr.ps = vcpu_get_rr_ps(vcpu, ifa);
+ rr.rid = vcpu_get_rr_rid(vcpu, ifa);
+ return rr.rrval;
}
-
-IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_itir(VCPU * vcpu, u64 * pval)
{
- UINT64 val = PSCB(vcpu,itir);
+ u64 val = PSCB(vcpu, itir);
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_iipa(VCPU * vcpu, u64 * pval)
{
- UINT64 val = PSCB(vcpu,iipa);
+ u64 val = PSCB(vcpu, iipa);
// SP entry code does not save iipa yet nor does it get
// properly delivered in the pscb
-// printf("*** vcpu_get_iipa: cr.iipa not fully implemented yet!!\n");
+// printk("*** vcpu_get_iipa: cr.iipa not fully implemented yet!!\n");
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_ifs(VCPU * vcpu, u64 * pval)
{
//PSCB(vcpu,ifs) = PSCB(vcpu)->regs.cr_ifs;
//*pval = PSCB(vcpu,regs).cr_ifs;
- *pval = PSCB(vcpu,ifs);
- PSCB(vcpu,incomplete_regframe) = 0;
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, ifs);
+ PSCB(vcpu, incomplete_regframe) = 0;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_iim(VCPU * vcpu, u64 * pval)
{
- UINT64 val = PSCB(vcpu,iim);
+ u64 val = PSCB(vcpu, iim);
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_iha(VCPU * vcpu, u64 * pval)
{
PRIVOP_COUNT_ADDR(vcpu_regs(vcpu), privop_inst_thash);
- *pval = PSCB(vcpu,iha);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, iha);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_dcr(VCPU * vcpu, u64 val)
{
// Reads of cr.dcr on SP always have the sign bit set, so
// a domain can differentiate whether it is running on SP or not
// Thus, writes of DCR should ignore the sign bit
//verbose("vcpu_set_dcr: called\n");
- PSCBX(vcpu,dcr) = val & ~0x8000000000000000L;
- return (IA64_NO_FAULT);
+ PSCBX(vcpu, dcr) = val & ~0x8000000000000000L;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_iva(VCPU * vcpu, u64 val)
{
- if(VMX_DOMAIN(vcpu)){
- PSCB(vcpu,iva) = val & ~0x7fffL;
- }else{
- PSCBX(vcpu,iva) = val & ~0x7fffL;
- }
- return (IA64_NO_FAULT);
+ if (VMX_DOMAIN(vcpu))
+ PSCB(vcpu, iva) = val & ~0x7fffL;
+ else
+ PSCBX(vcpu, iva) = val & ~0x7fffL;
+
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_pta(VCPU * vcpu, u64 val)
{
if (val & IA64_PTA_LFMT) {
- printf("*** No support for VHPT long format yet!!\n");
- return (IA64_ILLOP_FAULT);
+ printk("*** No support for VHPT long format yet!!\n");
+ return IA64_ILLOP_FAULT;
}
- if (val & (0x3f<<9)) /* reserved fields */ return IA64_RSVDREG_FAULT;
- if (val & 2) /* reserved fields */ return IA64_RSVDREG_FAULT;
- PSCB(vcpu,pta) = val;
+ if (val & (0x3f << 9)) /* reserved fields */
+ return IA64_RSVDREG_FAULT;
+ if (val & 2) /* reserved fields */
+ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu, pta) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_ipsr(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,ipsr) = val;
+ PSCB(vcpu, ipsr) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_isr(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,isr) = val;
+ PSCB(vcpu, isr) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_iip(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,iip) = val;
+ PSCB(vcpu, iip) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_increment_iip(VCPU *vcpu)
+IA64FAULT vcpu_increment_iip(VCPU * vcpu)
{
REGS *regs = vcpu_regs(vcpu);
struct ia64_psr *ipsr = (struct ia64_psr *)&regs->cr_ipsr;
- if (ipsr->ri == 2) { ipsr->ri=0; regs->cr_iip += 16; }
- else ipsr->ri++;
- return (IA64_NO_FAULT);
+ if (ipsr->ri == 2) {
+ ipsr->ri = 0;
+ regs->cr_iip += 16;
+ } else
+ ipsr->ri++;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_ifa(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,ifa) = val;
+ PSCB(vcpu, ifa) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_itir(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,itir) = val;
+ PSCB(vcpu, itir) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_iipa(VCPU * vcpu, u64 val)
{
// SP entry code does not save iipa yet nor does it get
// properly delivered in the pscb
-// printf("*** vcpu_set_iipa: cr.iipa not fully implemented yet!!\n");
- PSCB(vcpu,iipa) = val;
+// printk("*** vcpu_set_iipa: cr.iipa not fully implemented yet!!\n");
+ PSCB(vcpu, iipa) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_ifs(VCPU * vcpu, u64 val)
{
//REGS *regs = vcpu_regs(vcpu);
- PSCB(vcpu,ifs) = val;
+ PSCB(vcpu, ifs) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_iim(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,iim) = val;
+ PSCB(vcpu, iim) = val;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_iha(VCPU * vcpu, u64 val)
{
- PSCB(vcpu,iha) = val;
+ PSCB(vcpu, iha) = val;
return IA64_NO_FAULT;
}
@@ -650,28 +742,29 @@ IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val)
VCPU interrupt control register access routines
**************************************************************************/
-void vcpu_pend_unspecified_interrupt(VCPU *vcpu)
+void vcpu_pend_unspecified_interrupt(VCPU * vcpu)
{
- PSCB(vcpu,pending_interruption) = 1;
+ PSCB(vcpu, pending_interruption) = 1;
}
-void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector)
+void vcpu_pend_interrupt(VCPU * vcpu, u64 vector)
{
if (vector & ~0xff) {
- printf("vcpu_pend_interrupt: bad vector\n");
+ printk("vcpu_pend_interrupt: bad vector\n");
return;
}
if (vcpu->arch.event_callback_ip) {
- printf("Deprecated interface. Move to new event based solution\n");
+ printk("Deprecated interface. Move to new event based "
+ "solution\n");
return;
}
-
- if ( VMX_DOMAIN(vcpu) ) {
- set_bit(vector,VCPU(vcpu,irr));
+
+ if (VMX_DOMAIN(vcpu)) {
+ set_bit(vector, VCPU(vcpu, irr));
} else {
- set_bit(vector,PSCBX(vcpu,irr));
- PSCB(vcpu,pending_interruption) = 1;
+ set_bit(vector, PSCBX(vcpu, irr));
+ PSCB(vcpu, pending_interruption) = 1;
}
}
@@ -684,9 +777,9 @@ void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector)
* semantics of "mov rx=cr.ivr" ignore the setting of the psr.i bit,
* this routine also ignores pscb.interrupt_delivery_enabled
* and this must be checked independently; see vcpu_deliverable interrupts() */
-UINT64 vcpu_check_pending_interrupts(VCPU *vcpu)
+u64 vcpu_check_pending_interrupts(VCPU * vcpu)
{
- UINT64 *p, *r, bits, bitnum, mask, i, vector;
+ u64 *p, *r, bits, bitnum, mask, i, vector;
if (vcpu->arch.event_callback_ip)
return SPURIOUS_VECTOR;
@@ -695,89 +788,91 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu)
* event injection without handle. Later guest may throw out
* the event itself.
*/
-check_start:
- if (event_pending(vcpu) &&
- !test_bit(vcpu->domain->shared_info->arch.evtchn_vector,
- &PSCBX(vcpu, insvc[0])))
- vcpu_pend_interrupt(vcpu, vcpu->domain->shared_info->arch.evtchn_vector);
-
- p = &PSCBX(vcpu,irr[3]);
- r = &PSCBX(vcpu,insvc[3]);
- for (i = 3; ; p--, r--, i--) {
- bits = *p ;
- if (bits) break; // got a potential interrupt
+ check_start:
+ if (event_pending(vcpu) &&
+ !test_bit(vcpu->domain->shared_info->arch.evtchn_vector,
+ &PSCBX(vcpu, insvc[0])))
+ vcpu_pend_interrupt(vcpu,
+ vcpu->domain->shared_info->arch.
+ evtchn_vector);
+
+ p = &PSCBX(vcpu, irr[3]);
+ r = &PSCBX(vcpu, insvc[3]);
+ for (i = 3 ;; p--, r--, i--) {
+ bits = *p;
+ if (bits)
+ break; // got a potential interrupt
if (*r) {
// nothing in this word which is pending+inservice
// but there is one inservice which masks lower
return SPURIOUS_VECTOR;
}
if (i == 0) {
- // checked all bits... nothing pending+inservice
+ // checked all bits... nothing pending+inservice
return SPURIOUS_VECTOR;
}
}
// have a pending,deliverable interrupt... see if it is masked
bitnum = ia64_fls(bits);
-//printf("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...\n",bitnum);
- vector = bitnum+(i*64);
+//printk("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...\n",bitnum);
+ vector = bitnum + (i * 64);
mask = 1L << bitnum;
/* sanity check for guest timer interrupt */
- if (vector == (PSCB(vcpu,itv) & 0xff)) {
+ if (vector == (PSCB(vcpu, itv) & 0xff)) {
uint64_t now = ia64_get_itc();
- if (now < PSCBX(vcpu,domain_itm)) {
+ if (now < PSCBX(vcpu, domain_itm)) {
// printk("Ooops, pending guest timer before its due\n");
- PSCBX(vcpu,irr[i]) &= ~mask;
+ PSCBX(vcpu, irr[i]) &= ~mask;
goto check_start;
}
}
-//printf("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...\n",vector);
+//printk("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...\n",vector);
if (*r >= mask) {
// masked by equal inservice
-//printf("but masked by equal inservice\n");
+//printk("but masked by equal inservice\n");
return SPURIOUS_VECTOR;
}
- if (PSCB(vcpu,tpr) & IA64_TPR_MMI) {
+ if (PSCB(vcpu, tpr) & IA64_TPR_MMI) {
// tpr.mmi is set
-//printf("but masked by tpr.mmi\n");
+//printk("but masked by tpr.mmi\n");
return SPURIOUS_VECTOR;
}
- if (((PSCB(vcpu,tpr) & IA64_TPR_MIC) + 15) >= vector) {
+ if (((PSCB(vcpu, tpr) & IA64_TPR_MIC) + 15) >= vector) {
//tpr.mic masks class
-//printf("but masked by tpr.mic\n");
+//printk("but masked by tpr.mic\n");
return SPURIOUS_VECTOR;
}
-
-//printf("returned to caller\n");
+//printk("returned to caller\n");
return vector;
}
-UINT64 vcpu_deliverable_interrupts(VCPU *vcpu)
+u64 vcpu_deliverable_interrupts(VCPU * vcpu)
{
return (vcpu_get_psr_i(vcpu) &&
vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR);
}
-UINT64 vcpu_deliverable_timer(VCPU *vcpu)
+u64 vcpu_deliverable_timer(VCPU * vcpu)
{
return (vcpu_get_psr_i(vcpu) &&
- vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu,itv));
+ vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu, itv));
}
-IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_lid(VCPU * vcpu, u64 * pval)
{
/* Use EID=0, ID=vcpu_id. */
*pval = vcpu->vcpu_id << 24;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_ivr(VCPU * vcpu, u64 * pval)
{
int i;
- UINT64 vector, mask;
+ u64 vector, mask;
#define HEARTBEAT_FREQ 16 // period in seconds
#ifdef HEARTBEAT_FREQ
-#define N_DOMS 16 // period in seconds
+#define N_DOMS 16 // period in seconds
#if 0
static long count[N_DOMS] = { 0 };
#endif
@@ -789,257 +884,269 @@ IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval)
static char firsttime[256];
if (firstivr) {
int i;
- for (i=0;i<256;i++) firsttime[i]=1;
- firstivr=0;
+ for (i = 0; i < 256; i++)
+ firsttime[i] = 1;
+ firstivr = 0;
}
#endif
vector = vcpu_check_pending_interrupts(vcpu);
if (vector == SPURIOUS_VECTOR) {
- PSCB(vcpu,pending_interruption) = 0;
+ PSCB(vcpu, pending_interruption) = 0;
*pval = vector;
return IA64_NO_FAULT;
}
#ifdef HEARTBEAT_FREQ
- if (domid >= N_DOMS) domid = N_DOMS-1;
+ if (domid >= N_DOMS)
+ domid = N_DOMS - 1;
#if 0
- if (vector == (PSCB(vcpu,itv) & 0xff)) {
- if (!(++count[domid] & ((HEARTBEAT_FREQ*1024)-1))) {
- printf("Dom%d heartbeat... ticks=%lx,nonticks=%lx\n",
- domid, count[domid], nonclockcount[domid]);
- //count[domid] = 0;
- //dump_runq();
- }
+ if (vector == (PSCB(vcpu, itv) & 0xff)) {
+ if (!(++count[domid] & ((HEARTBEAT_FREQ * 1024) - 1))) {
+ printk("Dom%d heartbeat... ticks=%lx,nonticks=%lx\n",
+ domid, count[domid], nonclockcount[domid]);
+ //count[domid] = 0;
+ //dump_runq();
+ }
}
#endif
- else nonclockcount[domid]++;
+ else
+ nonclockcount[domid]++;
#endif
// now have an unmasked, pending, deliverable vector!
// getting ivr has "side effects"
#ifdef IRQ_DEBUG
if (firsttime[vector]) {
- printf("*** First get_ivr on vector=%lu,itc=%lx\n",
- vector,ia64_get_itc());
- firsttime[vector]=0;
+ printk("*** First get_ivr on vector=%lu,itc=%lx\n",
+ vector, ia64_get_itc());
+ firsttime[vector] = 0;
}
#endif
/* if delivering a timer interrupt, remember domain_itm, which
* needs to be done before clearing irr
*/
- if (vector == (PSCB(vcpu,itv) & 0xff)) {
- PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm);
+ if (vector == (PSCB(vcpu, itv) & 0xff)) {
+ PSCBX(vcpu, domain_itm_last) = PSCBX(vcpu, domain_itm);
}
i = vector >> 6;
mask = 1L << (vector & 0x3f);
-//printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %lu\n",vector);
- PSCBX(vcpu,insvc[i]) |= mask;
- PSCBX(vcpu,irr[i]) &= ~mask;
+//printk("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %lu\n",vector);
+ PSCBX(vcpu, insvc[i]) |= mask;
+ PSCBX(vcpu, irr[i]) &= ~mask;
//PSCB(vcpu,pending_interruption)--;
*pval = vector;
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_tpr(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,tpr);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, tpr);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_eoi(VCPU * vcpu, u64 * pval)
{
- *pval = 0L; // reads of eoi always return 0
- return (IA64_NO_FAULT);
+ *pval = 0L; // reads of eoi always return 0
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_irr0(VCPU * vcpu, u64 * pval)
{
*pval = PSCBX(vcpu, irr[0]);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_irr1(VCPU * vcpu, u64 * pval)
{
*pval = PSCBX(vcpu, irr[1]);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_irr2(VCPU * vcpu, u64 * pval)
{
*pval = PSCBX(vcpu, irr[2]);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_irr3(VCPU * vcpu, u64 * pval)
{
*pval = PSCBX(vcpu, irr[3]);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_itv(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,itv);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, itv);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_pmv(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,pmv);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, pmv);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_cmcv(VCPU * vcpu, u64 * pval)
{
- *pval = PSCB(vcpu,cmcv);
- return (IA64_NO_FAULT);
+ *pval = PSCB(vcpu, cmcv);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_lrr0(VCPU * vcpu, u64 * pval)
{
// fix this when setting values other than m-bit is supported
- printf("vcpu_get_lrr0: Unmasked interrupts unsupported\n");
+ printk("vcpu_get_lrr0: Unmasked interrupts unsupported\n");
*pval = (1L << 16);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_lrr1(VCPU * vcpu, u64 * pval)
{
// fix this when setting values other than m-bit is supported
- printf("vcpu_get_lrr1: Unmasked interrupts unsupported\n");
+ printk("vcpu_get_lrr1: Unmasked interrupts unsupported\n");
*pval = (1L << 16);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_lid(VCPU * vcpu, u64 val)
{
- printf("vcpu_set_lid: Setting cr.lid is unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_set_lid: Setting cr.lid is unsupported\n");
+ return IA64_ILLOP_FAULT;
}
-IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_tpr(VCPU * vcpu, u64 val)
{
- if (val & 0xff00) return IA64_RSVDREG_FAULT;
- PSCB(vcpu,tpr) = val;
+ if (val & 0xff00)
+ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu, tpr) = val;
/* This can unmask interrupts. */
if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
- PSCB(vcpu,pending_interruption) = 1;
- return (IA64_NO_FAULT);
+ PSCB(vcpu, pending_interruption) = 1;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_eoi(VCPU * vcpu, u64 val)
{
- UINT64 *p, bits, vec, bitnum;
+ u64 *p, bits, vec, bitnum;
int i;
- p = &PSCBX(vcpu,insvc[3]);
- for (i = 3; (i >= 0) && !(bits = *p); i--, p--);
+ p = &PSCBX(vcpu, insvc[3]);
+ for (i = 3; (i >= 0) && !(bits = *p); i--, p--)
+ ;
if (i < 0) {
- printf("Trying to EOI interrupt when none are in-service.\n");
+ printk("Trying to EOI interrupt when none are in-service.\n");
return IA64_NO_FAULT;
}
bitnum = ia64_fls(bits);
- vec = bitnum + (i*64);
+ vec = bitnum + (i * 64);
/* clear the correct bit */
bits &= ~(1L << bitnum);
*p = bits;
/* clearing an eoi bit may unmask another pending interrupt... */
- if (!vcpu->vcpu_info->evtchn_upcall_mask) { // but only if enabled...
+ if (!vcpu->vcpu_info->evtchn_upcall_mask) { // but only if enabled...
// worry about this later... Linux only calls eoi
// with interrupts disabled
- printf("Trying to EOI interrupt with interrupts enabled\n");
+ printk("Trying to EOI interrupt with interrupts enabled\n");
}
if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
- PSCB(vcpu,pending_interruption) = 1;
-//printf("YYYYY vcpu_set_eoi: Successful\n");
- return (IA64_NO_FAULT);
+ PSCB(vcpu, pending_interruption) = 1;
+//printk("YYYYY vcpu_set_eoi: Successful\n");
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_lrr0(VCPU * vcpu, u64 val)
{
if (!(val & (1L << 16))) {
- printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+ return IA64_ILLOP_FAULT;
}
// no place to save this state but nothing to do anyway
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_lrr1(VCPU * vcpu, u64 val)
{
if (!(val & (1L << 16))) {
- printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+ return IA64_ILLOP_FAULT;
}
// no place to save this state but nothing to do anyway
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_itv(VCPU * vcpu, u64 val)
{
/* Check reserved fields. */
if (val & 0xef00)
- return (IA64_ILLOP_FAULT);
- PSCB(vcpu,itv) = val;
+ return IA64_ILLOP_FAULT;
+ PSCB(vcpu, itv) = val;
if (val & 0x10000) {
/* Disable itm. */
- PSCBX(vcpu,domain_itm) = 0;
- }
- else vcpu_set_next_timer(vcpu);
- return (IA64_NO_FAULT);
+ PSCBX(vcpu, domain_itm) = 0;
+ } else
+ vcpu_set_next_timer(vcpu);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_pmv(VCPU * vcpu, u64 val)
{
- if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
- PSCB(vcpu,pmv) = val;
- return (IA64_NO_FAULT);
+ if (val & 0xef00) /* reserved fields */
+ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu, pmv) = val;
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_cmcv(VCPU * vcpu, u64 val)
{
- if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
- PSCB(vcpu,cmcv) = val;
- return (IA64_NO_FAULT);
+ if (val & 0xef00) /* reserved fields */
+ return IA64_RSVDREG_FAULT;
+ PSCB(vcpu, cmcv) = val;
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU temporary register access routines
**************************************************************************/
-UINT64 vcpu_get_tmp(VCPU *vcpu, UINT64 index)
+u64 vcpu_get_tmp(VCPU * vcpu, u64 index)
{
- if (index > 7) return 0;
- return PSCB(vcpu,tmp[index]);
+ if (index > 7)
+ return 0;
+ return PSCB(vcpu, tmp[index]);
}
-void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val)
+void vcpu_set_tmp(VCPU * vcpu, u64 index, u64 val)
{
- if (index <= 7) PSCB(vcpu,tmp[index]) = val;
+ if (index <= 7)
+ PSCB(vcpu, tmp[index]) = val;
}
/**************************************************************************
Interval timer routines
**************************************************************************/
-BOOLEAN vcpu_timer_disabled(VCPU *vcpu)
+BOOLEAN vcpu_timer_disabled(VCPU * vcpu)
{
- UINT64 itv = PSCB(vcpu,itv);
- return(!itv || !!(itv & 0x10000));
+ u64 itv = PSCB(vcpu, itv);
+ return (!itv || !!(itv & 0x10000));
}
-BOOLEAN vcpu_timer_inservice(VCPU *vcpu)
+BOOLEAN vcpu_timer_inservice(VCPU * vcpu)
{
- UINT64 itv = PSCB(vcpu,itv);
- return (test_bit(itv, PSCBX(vcpu,insvc)));
+ u64 itv = PSCB(vcpu, itv);
+ return test_bit(itv, PSCBX(vcpu, insvc));
}
-BOOLEAN vcpu_timer_expired(VCPU *vcpu)
+BOOLEAN vcpu_timer_expired(VCPU * vcpu)
{
- unsigned long domain_itm = PSCBX(vcpu,domain_itm);
+ unsigned long domain_itm = PSCBX(vcpu, domain_itm);
unsigned long now = ia64_get_itc();
- if (!domain_itm) return FALSE;
- if (now < domain_itm) return FALSE;
- if (vcpu_timer_disabled(vcpu)) return FALSE;
+ if (!domain_itm)
+ return FALSE;
+ if (now < domain_itm)
+ return FALSE;
+ if (vcpu_timer_disabled(vcpu))
+ return FALSE;
return TRUE;
}
@@ -1047,31 +1154,32 @@ void vcpu_safe_set_itm(unsigned long val)
{
unsigned long epsilon = 100;
unsigned long flags;
- UINT64 now = ia64_get_itc();
+ u64 now = ia64_get_itc();
local_irq_save(flags);
while (1) {
-//printf("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now);
+//printk("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now);
ia64_set_itm(val);
- if (val > (now = ia64_get_itc())) break;
+ if (val > (now = ia64_get_itc()))
+ break;
val = now + epsilon;
epsilon <<= 1;
}
local_irq_restore(flags);
}
-void vcpu_set_next_timer(VCPU *vcpu)
+void vcpu_set_next_timer(VCPU * vcpu)
{
- UINT64 d = PSCBX(vcpu,domain_itm);
- //UINT64 s = PSCBX(vcpu,xen_itm);
- UINT64 s = local_cpu_data->itm_next;
- UINT64 now = ia64_get_itc();
+ u64 d = PSCBX(vcpu, domain_itm);
+ //u64 s = PSCBX(vcpu,xen_itm);
+ u64 s = local_cpu_data->itm_next;
+ u64 now = ia64_get_itc();
/* gloss over the wraparound problem for now... we know it exists
* but it doesn't matter right now */
if (is_idle_domain(vcpu->domain)) {
-// printf("****** vcpu_set_next_timer called during idle!!\n");
+// printk("****** vcpu_set_next_timer called during idle!!\n");
vcpu_safe_set_itm(s);
return;
}
@@ -1079,87 +1187,87 @@ void vcpu_set_next_timer(VCPU *vcpu)
if (d && (d > now) && (d < s)) {
vcpu_safe_set_itm(d);
//using_domain_as_itm++;
- }
- else {
+ } else {
vcpu_safe_set_itm(s);
//using_xen_as_itm++;
}
}
-IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_itm(VCPU * vcpu, u64 val)
{
//UINT now = ia64_get_itc();
//if (val < now) val = now + 1000;
-//printf("*** vcpu_set_itm: called with %lx\n",val);
- PSCBX(vcpu,domain_itm) = val;
+//printk("*** vcpu_set_itm: called with %lx\n",val);
+ PSCBX(vcpu, domain_itm) = val;
vcpu_set_next_timer(vcpu);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val)
+IA64FAULT vcpu_set_itc(VCPU * vcpu, u64 val)
{
#define DISALLOW_SETTING_ITC_FOR_NOW
#ifdef DISALLOW_SETTING_ITC_FOR_NOW
static int did_print;
if (!did_print) {
- printf("vcpu_set_itc: Setting ar.itc is currently disabled\n");
- printf("(this message is only displayed one)\n");
+ printk("vcpu_set_itc: Setting ar.itc is currently disabled\n");
+ printk("(this message is only displayed one)\n");
did_print = 1;
}
#else
- UINT64 oldnow = ia64_get_itc();
- UINT64 olditm = PSCBX(vcpu,domain_itm);
+ u64 oldnow = ia64_get_itc();
+ u64 olditm = PSCBX(vcpu, domain_itm);
unsigned long d = olditm - oldnow;
unsigned long x = local_cpu_data->itm_next - oldnow;
- UINT64 newnow = val, min_delta;
+ u64 newnow = val, min_delta;
local_irq_disable();
if (olditm) {
-printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d);
- PSCBX(vcpu,domain_itm) = newnow + d;
+ printk("**** vcpu_set_itc(%lx): vitm changed to %lx\n", val,
+ newnow + d);
+ PSCBX(vcpu, domain_itm) = newnow + d;
}
local_cpu_data->itm_next = newnow + x;
- d = PSCBX(vcpu,domain_itm);
+ d = PSCBX(vcpu, domain_itm);
x = local_cpu_data->itm_next;
ia64_set_itc(newnow);
if (d && (d > newnow) && (d < x)) {
vcpu_safe_set_itm(d);
//using_domain_as_itm++;
- }
- else {
+ } else {
vcpu_safe_set_itm(x);
//using_xen_as_itm++;
}
local_irq_enable();
#endif
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_itm(VCPU * vcpu, u64 * pval)
{
//FIXME: Implement this
- printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n");
- return (IA64_NO_FAULT);
- //return (IA64_ILLOP_FAULT);
+ printk("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n");
+ return IA64_NO_FAULT;
+ //return IA64_ILLOP_FAULT;
}
-IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval)
+IA64FAULT vcpu_get_itc(VCPU * vcpu, u64 * pval)
{
//TODO: Implement this
- printf("vcpu_get_itc: Getting ar.itc is unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_get_itc: Getting ar.itc is unsupported\n");
+ return IA64_ILLOP_FAULT;
}
-void vcpu_pend_timer(VCPU *vcpu)
+void vcpu_pend_timer(VCPU * vcpu)
{
- UINT64 itv = PSCB(vcpu,itv) & 0xff;
+ u64 itv = PSCB(vcpu, itv) & 0xff;
- if (vcpu_timer_disabled(vcpu)) return;
+ if (vcpu_timer_disabled(vcpu))
+ return;
//if (vcpu_timer_inservice(vcpu)) return;
- if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) {
+ if (PSCBX(vcpu, domain_itm_last) == PSCBX(vcpu, domain_itm)) {
// already delivered an interrupt for this so
// don't deliver another
return;
@@ -1177,13 +1285,15 @@ void vcpu_pend_timer(VCPU *vcpu)
}
// returns true if ready to deliver a timer interrupt too early
-UINT64 vcpu_timer_pending_early(VCPU *vcpu)
+u64 vcpu_timer_pending_early(VCPU * vcpu)
{
- UINT64 now = ia64_get_itc();
- UINT64 itm = PSCBX(vcpu,domain_itm);
+ u64 now = ia64_get_itc();
+ u64 itm = PSCBX(vcpu, domain_itm);
- if (vcpu_timer_disabled(vcpu)) return 0;
- if (!itm) return 0;
+ if (vcpu_timer_disabled(vcpu))
+ return 0;
+ if (!itm)
+ return 0;
return (vcpu_deliverable_timer(vcpu) && (now < itm));
}
@@ -1191,120 +1301,129 @@ UINT64 vcpu_timer_pending_early(VCPU *vcpu)
Privileged operation emulation routines
**************************************************************************/
-static void
-vcpu_force_tlb_miss(VCPU* vcpu, UINT64 ifa)
+static void vcpu_force_tlb_miss(VCPU * vcpu, u64 ifa)
{
PSCB(vcpu, ifa) = ifa;
PSCB(vcpu, itir) = vcpu_get_itir_on_fault(vcpu, ifa);
vcpu_thash(current, ifa, &PSCB(current, iha));
}
-IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa)
+IA64FAULT vcpu_force_inst_miss(VCPU * vcpu, u64 ifa)
{
vcpu_force_tlb_miss(vcpu, ifa);
- return (vcpu_get_rr_ve(vcpu, ifa)? IA64_INST_TLB_VECTOR: IA64_ALT_INST_TLB_VECTOR);
+ return vcpu_get_rr_ve(vcpu, ifa) ? IA64_INST_TLB_VECTOR :
+ IA64_ALT_INST_TLB_VECTOR;
}
-IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa)
+IA64FAULT vcpu_force_data_miss(VCPU * vcpu, u64 ifa)
{
vcpu_force_tlb_miss(vcpu, ifa);
- return (vcpu_get_rr_ve(vcpu, ifa)? IA64_DATA_TLB_VECTOR: IA64_ALT_DATA_TLB_VECTOR);
+ return vcpu_get_rr_ve(vcpu, ifa) ? IA64_DATA_TLB_VECTOR :
+ IA64_ALT_DATA_TLB_VECTOR;
}
-IA64FAULT vcpu_rfi(VCPU *vcpu)
+IA64FAULT vcpu_rfi(VCPU * vcpu)
{
// TODO: Only allowed for current vcpu
PSR psr;
- UINT64 int_enable, regspsr = 0;
- UINT64 ifs;
+ u64 int_enable, regspsr = 0;
+ u64 ifs;
REGS *regs = vcpu_regs(vcpu);
extern void dorfirfi(void);
- psr.i64 = PSCB(vcpu,ipsr);
- if (psr.ia64_psr.cpl < 3) psr.ia64_psr.cpl = 2;
+ psr.i64 = PSCB(vcpu, ipsr);
+ if (psr.ia64_psr.cpl < 3)
+ psr.ia64_psr.cpl = 2;
int_enable = psr.ia64_psr.i;
- if (psr.ia64_psr.ic) PSCB(vcpu,interrupt_collection_enabled) = 1;
- if (psr.ia64_psr.dt && psr.ia64_psr.rt && psr.ia64_psr.it) vcpu_set_metaphysical_mode(vcpu,FALSE);
- else vcpu_set_metaphysical_mode(vcpu,TRUE);
- psr.ia64_psr.ic = 1; psr.ia64_psr.i = 1;
- psr.ia64_psr.dt = 1; psr.ia64_psr.rt = 1; psr.ia64_psr.it = 1;
+ if (psr.ia64_psr.ic)
+ PSCB(vcpu, interrupt_collection_enabled) = 1;
+ if (psr.ia64_psr.dt && psr.ia64_psr.rt && psr.ia64_psr.it)
+ vcpu_set_metaphysical_mode(vcpu, FALSE);
+ else
+ vcpu_set_metaphysical_mode(vcpu, TRUE);
+ psr.ia64_psr.ic = 1;
+ psr.ia64_psr.i = 1;
+ psr.ia64_psr.dt = 1;
+ psr.ia64_psr.rt = 1;
+ psr.ia64_psr.it = 1;
psr.ia64_psr.bn = 1;
//psr.pk = 1; // checking pkeys shouldn't be a problem but seems broken
if (psr.ia64_psr.be) {
- printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
- return (IA64_ILLOP_FAULT);
+ printk("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+ return IA64_ILLOP_FAULT;
}
- PSCB(vcpu,incomplete_regframe) = 0; // is this necessary?
- ifs = PSCB(vcpu,ifs);
+ PSCB(vcpu, incomplete_regframe) = 0; // is this necessary?
+ ifs = PSCB(vcpu, ifs);
//if ((ifs & regs->cr_ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
//if ((ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
if (ifs & regs->cr_ifs & 0x8000000000000000L) {
// TODO: validate PSCB(vcpu,iip)
// TODO: PSCB(vcpu,ipsr) = psr;
- PSCB(vcpu,ipsr) = psr.i64;
+ PSCB(vcpu, ipsr) = psr.i64;
// now set up the trampoline
regs->cr_iip = *(unsigned long *)dorfirfi; // function pointer!!
- __asm__ __volatile ("mov %0=psr;;":"=r"(regspsr)::"memory");
- regs->cr_ipsr = regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN);
- }
- else {
+ __asm__ __volatile("mov %0=psr;;":"=r"(regspsr)::"memory");
+ regs->cr_ipsr =
+ regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN);
+ } else {
regs->cr_ipsr = psr.i64;
- regs->cr_iip = PSCB(vcpu,iip);
+ regs->cr_iip = PSCB(vcpu, iip);
}
- PSCB(vcpu,interrupt_collection_enabled) = 1;
+ PSCB(vcpu, interrupt_collection_enabled) = 1;
vcpu_bsw1(vcpu);
vcpu->vcpu_info->evtchn_upcall_mask = !int_enable;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_cover(VCPU *vcpu)
+IA64FAULT vcpu_cover(VCPU * vcpu)
{
// TODO: Only allowed for current vcpu
REGS *regs = vcpu_regs(vcpu);
- if (!PSCB(vcpu,interrupt_collection_enabled)) {
- if (!PSCB(vcpu,incomplete_regframe))
- PSCB(vcpu,ifs) = regs->cr_ifs;
- else PSCB(vcpu,incomplete_regframe) = 0;
+ if (!PSCB(vcpu, interrupt_collection_enabled)) {
+ if (!PSCB(vcpu, incomplete_regframe))
+ PSCB(vcpu, ifs) = regs->cr_ifs;
+ else
+ PSCB(vcpu, incomplete_regframe) = 0;
}
regs->cr_ifs = 0;
- return (IA64_NO_FAULT);
-}
-
-IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
-{
- UINT64 pta = PSCB(vcpu,pta);
- UINT64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT;
- UINT64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT)-1);
- UINT64 Mask = (1L << pta_sz) - 1;
- UINT64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff;
- UINT64 compMask_60_15 = ~Mask_60_15;
- UINT64 rr_ps = vcpu_get_rr_ps(vcpu,vadr);
- UINT64 VHPT_offset = (vadr >> rr_ps) << 3;
- UINT64 VHPT_addr1 = vadr & 0xe000000000000000L;
- UINT64 VHPT_addr2a =
- ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15;
- UINT64 VHPT_addr2b =
- ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15;
- UINT64 VHPT_addr3 = VHPT_offset & 0x7fff;
- UINT64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) |
- VHPT_addr3;
+ return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval)
+{
+ u64 pta = PSCB(vcpu, pta);
+ u64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT;
+ u64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT) - 1);
+ u64 Mask = (1L << pta_sz) - 1;
+ u64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff;
+ u64 compMask_60_15 = ~Mask_60_15;
+ u64 rr_ps = vcpu_get_rr_ps(vcpu, vadr);
+ u64 VHPT_offset = (vadr >> rr_ps) << 3;
+ u64 VHPT_addr1 = vadr & 0xe000000000000000L;
+ u64 VHPT_addr2a =
+ ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15;
+ u64 VHPT_addr2b =
+ ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15;
+ u64 VHPT_addr3 = VHPT_offset & 0x7fff;
+ u64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) |
+ VHPT_addr3;
//verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr);
*pval = VHPT_addr;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+IA64FAULT vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * padr)
{
- printf("vcpu_ttag: ttag instruction unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_ttag: ttag instruction unsupported\n");
+ return IA64_ILLOP_FAULT;
}
-int warn_region0_address = 0; // FIXME later: tie to a boot parameter?
+int warn_region0_address = 0; // FIXME later: tie to a boot parameter?
/* Return TRUE iff [b1,e1] and [b2,e2] partially or fully overlaps. */
-static inline int range_overlap (u64 b1, u64 e1, u64 b2, u64 e2)
+static inline int range_overlap(u64 b1, u64 e1, u64 b2, u64 e2)
{
return (b1 <= e2) && (e1 >= b2);
}
@@ -1312,45 +1431,53 @@ static inline int range_overlap (u64 b1, u64 e1, u64 b2, u64 e2)
/* Crash domain if [base, base + page_size] and Xen virtual space overlaps.
Note: LSBs of base inside page_size are ignored. */
static inline void
-check_xen_space_overlap (const char *func, u64 base, u64 page_size)
+check_xen_space_overlap(const char *func, u64 base, u64 page_size)
{
+ /* Overlaps can occur only in region 7.
+ (This is an optimization to bypass all the checks). */
+ if (REGION_NUMBER(base) != 7)
+ return;
+
/* Mask LSBs of base. */
base &= ~(page_size - 1);
/* FIXME: ideally an MCA should be generated... */
- if (range_overlap (HYPERVISOR_VIRT_START, HYPERVISOR_VIRT_END,
- base, base + page_size))
- panic_domain (NULL, "%s on Xen virtual space (%lx)\n",
- func, base);
+ if (range_overlap(HYPERVISOR_VIRT_START, HYPERVISOR_VIRT_END,
+ base, base + page_size)
+ || range_overlap(current->domain->arch.shared_info_va,
+ current->domain->arch.shared_info_va
+ + XSI_SIZE + XMAPPEDREGS_SIZE,
+ base, base + page_size))
+ panic_domain(NULL, "%s on Xen virtual space (%lx)\n",
+ func, base);
}
// FIXME: also need to check && (!trp->key || vcpu_pkr_match(trp->key))
-static inline int vcpu_match_tr_entry_no_p(TR_ENTRY *trp, UINT64 ifa, UINT64 rid)
+static inline int vcpu_match_tr_entry_no_p(TR_ENTRY * trp, u64 ifa,
+ u64 rid)
{
- return trp->rid == rid
- && ifa >= trp->vadr
- && ifa <= (trp->vadr + (1L << trp->ps) - 1);
+ return trp->rid == rid
+ && ifa >= trp->vadr && ifa <= (trp->vadr + (1L << trp->ps) - 1);
}
-static inline int vcpu_match_tr_entry(TR_ENTRY *trp, UINT64 ifa, UINT64 rid)
+static inline int vcpu_match_tr_entry(TR_ENTRY * trp, u64 ifa, u64 rid)
{
return trp->pte.p && vcpu_match_tr_entry_no_p(trp, ifa, rid);
}
static inline int
-vcpu_match_tr_entry_range(TR_ENTRY *trp, UINT64 rid, u64 b, u64 e)
+vcpu_match_tr_entry_range(TR_ENTRY * trp, u64 rid, u64 b, u64 e)
{
return trp->rid == rid
- && trp->pte.p
- && range_overlap (b, e,
- trp->vadr, trp->vadr + (1L << trp->ps) - 1);
+ && trp->pte.p
+ && range_overlap(b, e, trp->vadr, trp->vadr + (1L << trp->ps) - 1);
}
-static TR_ENTRY*
-vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data)
+static TR_ENTRY *vcpu_tr_lookup(VCPU * vcpu, unsigned long va, u64 rid,
+ BOOLEAN is_data)
{
- unsigned char* regions;
+ unsigned char *regions;
TR_ENTRY *trp;
int tr_max;
int i;
@@ -1359,12 +1486,12 @@ vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data)
// data
regions = &vcpu->arch.dtr_regions;
trp = vcpu->arch.dtrs;
- tr_max = sizeof(vcpu->arch.dtrs)/sizeof(vcpu->arch.dtrs[0]);
+ tr_max = sizeof(vcpu->arch.dtrs) / sizeof(vcpu->arch.dtrs[0]);
} else {
// instruction
regions = &vcpu->arch.itr_regions;
trp = vcpu->arch.itrs;
- tr_max = sizeof(vcpu->arch.itrs)/sizeof(vcpu->arch.itrs[0]);
+ tr_max = sizeof(vcpu->arch.itrs) / sizeof(vcpu->arch.itrs[0]);
}
if (!vcpu_quick_region_check(*regions, va)) {
@@ -1382,13 +1509,14 @@ vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data)
// 0: failure
// 1: success
int
-vcpu_get_domain_bundle(VCPU* vcpu, REGS* regs, UINT64 gip, IA64_BUNDLE* bundle)
+vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip,
+ IA64_BUNDLE * bundle)
{
- UINT64 gpip;// guest pseudo phyiscal ip
+ u64 gpip; // guest pseudo phyiscal ip
unsigned long vaddr;
- struct page_info* page;
+ struct page_info *page;
-again:
+ again:
#if 0
// Currently xen doesn't track psr.it bits.
// it assumes always psr.it = 1.
@@ -1401,7 +1529,7 @@ again:
unsigned long rr = PSCB(vcpu, rrs)[region];
unsigned long rid = rr & RR_RID_MASK;
BOOLEAN swap_rr0;
- TR_ENTRY* trp;
+ TR_ENTRY *trp;
// vcpu->arch.{i, d}tlb are volatile,
// copy its value to the variable, tr, before use.
@@ -1416,7 +1544,9 @@ again:
// Last itc.i value is cached to PSCBX(vcpu, itlb).
tr = PSCBX(vcpu, itlb);
if (vcpu_match_tr_entry(&tr, gip, rid)) {
- //DPRINTK("%s gip 0x%lx gpip 0x%lx\n", __func__, gip, gpip);
+ //dprintk(XENLOG_WARNING,
+ // "%s gip 0x%lx gpip 0x%lx\n", __func__,
+ // gip, gpip);
goto found;
}
trp = vcpu_tr_lookup(vcpu, gip, rid, 1);
@@ -1442,47 +1572,47 @@ again:
set_metaphysical_rr0();
}
if (bundle->i64[0] == 0 && bundle->i64[1] == 0) {
- DPRINTK("%s gip 0x%lx\n", __func__, gip);
+ dprintk(XENLOG_INFO, "%s gip 0x%lx\n", __func__, gip);
return 0;
}
return 1;
-
+
found:
gpip = ((tr.pte.ppn >> (tr.ps - 12)) << tr.ps) |
(gip & ((1 << tr.ps) - 1));
}
-
+
vaddr = (unsigned long)domain_mpa_to_imva(vcpu->domain, gpip);
page = virt_to_page(vaddr);
if (get_page(page, vcpu->domain) == 0) {
if (page_get_owner(page) != vcpu->domain) {
// This page might be a page granted by another
// domain.
- panic_domain(regs,
- "domain tries to execute foreign domain "
- "page which might be mapped by grant "
- "table.\n");
+ panic_domain(regs, "domain tries to execute foreign "
+ "domain page which might be mapped by "
+ "grant table.\n");
}
goto again;
}
- *bundle = *((IA64_BUNDLE*)vaddr);
+ *bundle = *((IA64_BUNDLE *) vaddr);
put_page(page);
return 1;
}
-IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir, UINT64 *iha)
+IA64FAULT vcpu_translate(VCPU * vcpu, u64 address, BOOLEAN is_data,
+ u64 * pteval, u64 * itir, u64 * iha)
{
unsigned long region = address >> 61;
unsigned long pta, rid, rr;
union pte_flags pte;
TR_ENTRY *trp;
- if (PSCB(vcpu,metaphysical_mode) && !(!is_data && region)) {
+ if (PSCB(vcpu, metaphysical_mode) && !(!is_data && region)) {
// dom0 may generate an uncacheable physical address (msb=1)
if (region && ((region != 4) || (vcpu->domain != dom0))) {
// FIXME: This seems to happen even though it shouldn't. Need to track
// this down, but since it has been apparently harmless, just flag it for now
-// panic_domain(vcpu_regs(vcpu),
+// panic_domain(vcpu_regs(vcpu),
/*
* Guest may execute itc.d and rfi with psr.dt=0
@@ -1490,29 +1620,29 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
* At this time PSCB(vcpu,metaphysical_mode)=1,
* region=5,VMM need to handle this tlb miss as if
* PSCB(vcpu,metaphysical_mode)=0
- */
- printk("vcpu_translate: bad physical address: 0x%lx at %lx\n",
- address, vcpu_regs (vcpu)->cr_iip);
+ */
+ printk("vcpu_translate: bad physical address: 0x%lx "
+ "at %lx\n", address, vcpu_regs(vcpu)->cr_iip);
} else {
- *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS |
- _PAGE_PL_2 | _PAGE_AR_RWX;
+ *pteval = (address & _PAGE_PPN_MASK) |
+ __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX;
*itir = PAGE_SHIFT << 2;
perfc_incrc(phys_translate);
return IA64_NO_FAULT;
}
- }
- else if (!region && warn_region0_address) {
+ } else if (!region && warn_region0_address) {
REGS *regs = vcpu_regs(vcpu);
- unsigned long viip = PSCB(vcpu,iip);
- unsigned long vipsr = PSCB(vcpu,ipsr);
+ unsigned long viip = PSCB(vcpu, iip);
+ unsigned long vipsr = PSCB(vcpu, ipsr);
unsigned long iip = regs->cr_iip;
unsigned long ipsr = regs->cr_ipsr;
- printk("vcpu_translate: bad address 0x%lx, viip=0x%lx, vipsr=0x%lx, iip=0x%lx, ipsr=0x%lx continuing\n",
- address, viip, vipsr, iip, ipsr);
+ printk("vcpu_translate: bad address 0x%lx, viip=0x%lx, "
+ "vipsr=0x%lx, iip=0x%lx, ipsr=0x%lx continuing\n",
+ address, viip, vipsr, iip, ipsr);
}
- rr = PSCB(vcpu,rrs)[region];
+ rr = PSCB(vcpu, rrs)[region];
rid = rr & RR_RID_MASK;
if (is_data) {
trp = vcpu_tr_lookup(vcpu, address, rid, 1);
@@ -1524,7 +1654,7 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
}
}
// FIXME?: check itr's for data accesses too, else bad things happen?
- /* else */ {
+ /* else */ {
trp = vcpu_tr_lookup(vcpu, address, rid, 0);
if (trp != NULL) {
*pteval = trp->pte.val;
@@ -1538,8 +1668,8 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
// FIXME?: check dtlb for inst accesses too, else bad things happen?
trp = &vcpu->arch.dtlb;
pte = trp->pte;
- if (/* is_data && */ pte.p
- && vcpu_match_tr_entry_no_p(trp,address,rid)) {
+ if ( /* is_data && */ pte.p
+ && vcpu_match_tr_entry_no_p(trp, address, rid)) {
*pteval = pte.val;
*itir = trp->itir;
perfc_incrc(dtlb_translate);
@@ -1547,10 +1677,10 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
}
/* check guest VHPT */
- pta = PSCB(vcpu,pta);
+ pta = PSCB(vcpu, pta);
if (pta & IA64_PTA_VF) { /* long format VHPT - not implemented */
- panic_domain(vcpu_regs(vcpu),"can't do long format VHPT\n");
- //return (is_data ? IA64_DATA_TLB_VECTOR:IA64_INST_TLB_VECTOR);
+ panic_domain(vcpu_regs(vcpu), "can't do long format VHPT\n");
+ //return is_data ? IA64_DATA_TLB_VECTOR:IA64_INST_TLB_VECTOR;
}
*itir = rr & (RR_RID_MASK | RR_PS_MASK);
@@ -1558,24 +1688,25 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
// xenlinux depends on it so should document it as part of PV interface
vcpu_thash(vcpu, address, iha);
if (!(rr & RR_VE_MASK) || !(pta & IA64_PTA_VE))
- return (is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR);
+ return is_data ? IA64_ALT_DATA_TLB_VECTOR :
+ IA64_ALT_INST_TLB_VECTOR;
/* avoid recursively walking (short format) VHPT */
if (((address ^ pta) & ((itir_mask(pta) << 3) >> 3)) == 0)
- return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR);
+ return is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR;
- if (!__access_ok (*iha)
+ if (!__access_ok(*iha)
|| __copy_from_user(&pte, (void *)(*iha), sizeof(pte)) != 0)
// virtual VHPT walker "missed" in TLB
return IA64_VHPT_FAULT;
/*
- * Optimisation: this VHPT walker aborts on not-present pages
- * instead of inserting a not-present translation, this allows
- * vectoring directly to the miss handler.
- */
+ * Optimisation: this VHPT walker aborts on not-present pages
+ * instead of inserting a not-present translation, this allows
+ * vectoring directly to the miss handler.
+ */
if (!pte.p)
- return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR);
+ return is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR;
/* found mapping in guest VHPT! */
*itir = rr & RR_PS_MASK;
@@ -1584,25 +1715,24 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+IA64FAULT vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr)
{
- UINT64 pteval, itir, mask, iha;
+ u64 pteval, itir, mask, iha;
IA64FAULT fault;
fault = vcpu_translate(vcpu, vadr, TRUE, &pteval, &itir, &iha);
- if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB)
- {
+ if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) {
mask = itir_mask(itir);
*padr = (pteval & _PAGE_PPN_MASK & mask) | (vadr & ~mask);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
- return vcpu_force_data_miss(vcpu,vadr);
+ return vcpu_force_data_miss(vcpu, vadr);
}
-IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
+IA64FAULT vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key)
{
- printf("vcpu_tak: tak instruction unsupported\n");
- return (IA64_ILLOP_FAULT);
+ printk("vcpu_tak: tak instruction unsupported\n");
+ return IA64_ILLOP_FAULT;
// HACK ALERT: tak does a thash for now
//return vcpu_thash(vcpu,vadr,key);
}
@@ -1611,84 +1741,84 @@ IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
VCPU debug breakpoint register access routines
**************************************************************************/
-IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val)
{
// TODO: unimplemented DBRs return a reserved register fault
// TODO: Should set Logical CPU state, not just physical
- ia64_set_dbr(reg,val);
- return (IA64_NO_FAULT);
+ ia64_set_dbr(reg, val);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val)
{
// TODO: unimplemented IBRs return a reserved register fault
// TODO: Should set Logical CPU state, not just physical
- ia64_set_ibr(reg,val);
- return (IA64_NO_FAULT);
+ ia64_set_ibr(reg, val);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval)
{
// TODO: unimplemented DBRs return a reserved register fault
- UINT64 val = ia64_get_dbr(reg);
+ u64 val = ia64_get_dbr(reg);
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval)
{
// TODO: unimplemented IBRs return a reserved register fault
- UINT64 val = ia64_get_ibr(reg);
+ u64 val = ia64_get_ibr(reg);
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU performance monitor register access routines
**************************************************************************/
-IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val)
{
// TODO: Should set Logical CPU state, not just physical
// NOTE: Writes to unimplemented PMC registers are discarded
#ifdef DEBUG_PFMON
-printf("vcpu_set_pmc(%x,%lx)\n",reg,val);
+ printk("vcpu_set_pmc(%x,%lx)\n", reg, val);
#endif
- ia64_set_pmc(reg,val);
- return (IA64_NO_FAULT);
+ ia64_set_pmc(reg, val);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val)
{
// TODO: Should set Logical CPU state, not just physical
// NOTE: Writes to unimplemented PMD registers are discarded
#ifdef DEBUG_PFMON
-printf("vcpu_set_pmd(%x,%lx)\n",reg,val);
+ printk("vcpu_set_pmd(%x,%lx)\n", reg, val);
#endif
- ia64_set_pmd(reg,val);
- return (IA64_NO_FAULT);
+ ia64_set_pmd(reg, val);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval)
{
// NOTE: Reads from unimplemented PMC registers return zero
- UINT64 val = (UINT64)ia64_get_pmc(reg);
+ u64 val = (u64) ia64_get_pmc(reg);
#ifdef DEBUG_PFMON
-printf("%lx=vcpu_get_pmc(%x)\n",val,reg);
+ printk("%lx=vcpu_get_pmc(%x)\n", val, reg);
#endif
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval)
{
// NOTE: Reads from unimplemented PMD registers return zero
- UINT64 val = (UINT64)ia64_get_pmd(reg);
+ u64 val = (u64) ia64_get_pmd(reg);
#ifdef DEBUG_PFMON
-printf("%lx=vcpu_get_pmd(%x)\n",val,reg);
+ printk("%lx=vcpu_get_pmd(%x)\n", val, reg);
#endif
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
/**************************************************************************
@@ -1707,167 +1837,183 @@ do{ \
"r"(runat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); \
}while(0)
-IA64FAULT vcpu_bsw0(VCPU *vcpu)
+IA64FAULT vcpu_bsw0(VCPU * vcpu)
{
// TODO: Only allowed for current vcpu
REGS *regs = vcpu_regs(vcpu);
unsigned long *r = &regs->r16;
- unsigned long *b0 = &PSCB(vcpu,bank0_regs[0]);
- unsigned long *b1 = &PSCB(vcpu,bank1_regs[0]);
+ unsigned long *b0 = &PSCB(vcpu, bank0_regs[0]);
+ unsigned long *b1 = &PSCB(vcpu, bank1_regs[0]);
unsigned long *runat = &regs->eml_unat;
- unsigned long *b0unat = &PSCB(vcpu,vbnat);
- unsigned long *b1unat = &PSCB(vcpu,vnat);
+ unsigned long *b0unat = &PSCB(vcpu, vbnat);
+ unsigned long *b1unat = &PSCB(vcpu, vnat);
unsigned long i;
- if(VMX_DOMAIN(vcpu)){
- if(VCPU(vcpu,vpsr)&IA64_PSR_BN){
- for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; }
- vcpu_bsw0_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT);
- VCPU(vcpu,vpsr) &= ~IA64_PSR_BN;
- }
- }else{
- if (PSCB(vcpu,banknum)) {
- for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; }
- vcpu_bsw0_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT);
- PSCB(vcpu,banknum) = 0;
- }
- }
- return (IA64_NO_FAULT);
-}
-
-#define vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT) \
-do{ \
- __asm__ __volatile__ ( \
- ";;extr.u %0 = %3,%6,16;;\n" \
- "dep %1 = %0, %1, 16, 16;;\n" \
- "st8 [%4] = %1\n" \
- "extr.u %0 = %2, 0, 16;;\n" \
- "dep %3 = %0, %3, %6, 16;;\n" \
- "st8 [%5] = %3\n" \
- ::"r"(i),"r"(*b0unat),"r"(*b1unat),"r"(*runat),"r"(b0unat), \
- "r"(runat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); \
-}while(0)
+ if (VMX_DOMAIN(vcpu)) {
+ if (VCPU(vcpu, vpsr) & IA64_PSR_BN) {
+ for (i = 0; i < 16; i++) {
+ *b1++ = *r;
+ *r++ = *b0++;
+ }
+ vcpu_bsw0_unat(i, b0unat, b1unat, runat,
+ IA64_PT_REGS_R16_SLOT);
+ VCPU(vcpu, vpsr) &= ~IA64_PSR_BN;
+ }
+ } else {
+ if (PSCB(vcpu, banknum)) {
+ for (i = 0; i < 16; i++) {
+ *b1++ = *r;
+ *r++ = *b0++;
+ }
+ vcpu_bsw0_unat(i, b0unat, b1unat, runat,
+ IA64_PT_REGS_R16_SLOT);
+ PSCB(vcpu, banknum) = 0;
+ }
+ }
+ return IA64_NO_FAULT;
+}
+
+#define vcpu_bsw1_unat(i, b0unat, b1unat, runat, IA64_PT_REGS_R16_SLOT) \
+do { \
+ __asm__ __volatile__ (";;extr.u %0 = %3,%6,16;;\n" \
+ "dep %1 = %0, %1, 16, 16;;\n" \
+ "st8 [%4] = %1\n" \
+ "extr.u %0 = %2, 0, 16;;\n" \
+ "dep %3 = %0, %3, %6, 16;;\n" \
+ "st8 [%5] = %3\n" \
+ ::"r"(i), "r"(*b0unat), "r"(*b1unat), \
+ "r"(*runat), "r"(b0unat), "r"(runat), \
+ "i"(IA64_PT_REGS_R16_SLOT): "memory"); \
+} while(0)
-IA64FAULT vcpu_bsw1(VCPU *vcpu)
+IA64FAULT vcpu_bsw1(VCPU * vcpu)
{
// TODO: Only allowed for current vcpu
REGS *regs = vcpu_regs(vcpu);
unsigned long *r = &regs->r16;
- unsigned long *b0 = &PSCB(vcpu,bank0_regs[0]);
- unsigned long *b1 = &PSCB(vcpu,bank1_regs[0]);
+ unsigned long *b0 = &PSCB(vcpu, bank0_regs[0]);
+ unsigned long *b1 = &PSCB(vcpu, bank1_regs[0]);
unsigned long *runat = &regs->eml_unat;
- unsigned long *b0unat = &PSCB(vcpu,vbnat);
- unsigned long *b1unat = &PSCB(vcpu,vnat);
+ unsigned long *b0unat = &PSCB(vcpu, vbnat);
+ unsigned long *b1unat = &PSCB(vcpu, vnat);
unsigned long i;
- if(VMX_DOMAIN(vcpu)){
- if(!(VCPU(vcpu,vpsr)&IA64_PSR_BN)){
- for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; }
- vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT);
- VCPU(vcpu,vpsr) |= IA64_PSR_BN;
- }
- }else{
- if (!PSCB(vcpu,banknum)) {
- for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; }
- vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT);
- PSCB(vcpu,banknum) = 1;
- }
- }
- return (IA64_NO_FAULT);
+ if (VMX_DOMAIN(vcpu)) {
+ if (!(VCPU(vcpu, vpsr) & IA64_PSR_BN)) {
+ for (i = 0; i < 16; i++) {
+ *b0++ = *r;
+ *r++ = *b1++;
+ }
+ vcpu_bsw1_unat(i, b0unat, b1unat, runat,
+ IA64_PT_REGS_R16_SLOT);
+ VCPU(vcpu, vpsr) |= IA64_PSR_BN;
+ }
+ } else {
+ if (!PSCB(vcpu, banknum)) {
+ for (i = 0; i < 16; i++) {
+ *b0++ = *r;
+ *r++ = *b1++;
+ }
+ vcpu_bsw1_unat(i, b0unat, b1unat, runat,
+ IA64_PT_REGS_R16_SLOT);
+ PSCB(vcpu, banknum) = 1;
+ }
+ }
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU cpuid access routines
**************************************************************************/
-
-IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval)
{
// FIXME: This could get called as a result of a rsvd-reg fault
// if reg > 3
- switch(reg) {
- case 0:
- memcpy(pval,"Xen/ia64",8);
+ switch (reg) {
+ case 0:
+ memcpy(pval, "Xen/ia64", 8);
break;
- case 1:
+ case 1:
*pval = 0;
break;
- case 2:
+ case 2:
*pval = 0;
break;
- case 3:
+ case 3:
*pval = ia64_get_cpuid(3);
break;
- case 4:
+ case 4:
*pval = ia64_get_cpuid(4);
break;
- default:
+ default:
if (reg > (ia64_get_cpuid(3) & 0xff))
return IA64_RSVDREG_FAULT;
*pval = ia64_get_cpuid(reg);
break;
}
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU region register access routines
**************************************************************************/
-unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr)
+unsigned long vcpu_get_rr_ve(VCPU * vcpu, u64 vadr)
{
ia64_rr rr;
- rr.rrval = PSCB(vcpu,rrs)[vadr>>61];
- return(rr.ve);
+ rr.rrval = PSCB(vcpu, rrs)[vadr >> 61];
+ return rr.ve;
}
-IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val)
{
- PSCB(vcpu,rrs)[reg>>61] = val;
+ PSCB(vcpu, rrs)[reg >> 61] = val;
// warning: set_one_rr() does it "live"
- set_one_rr(reg,val);
- return (IA64_NO_FAULT);
+ set_one_rr(reg, val);
+ return IA64_NO_FAULT;
}
-IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_rr(VCPU * vcpu, u64 reg, u64 * pval)
{
- if(VMX_DOMAIN(vcpu)){
- *pval = VMX(vcpu,vrr[reg>>61]);
- }else{
- *pval = PSCB(vcpu,rrs)[reg>>61];
- }
- return (IA64_NO_FAULT);
+ if (VMX_DOMAIN(vcpu))
+ *pval = VMX(vcpu, vrr[reg >> 61]);
+ else
+ *pval = PSCB(vcpu, rrs)[reg >> 61];
+
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU protection key register access routines
**************************************************************************/
-IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval)
{
#ifndef PKR_USE_FIXED
printk("vcpu_get_pkr: called, not implemented yet\n");
return IA64_ILLOP_FAULT;
#else
- UINT64 val = (UINT64)ia64_get_pkr(reg);
+ u64 val = (u64) ia64_get_pkr(reg);
*pval = val;
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
#endif
}
-IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val)
+IA64FAULT vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val)
{
#ifndef PKR_USE_FIXED
printk("vcpu_set_pkr: called, not implemented yet\n");
return IA64_ILLOP_FAULT;
#else
-// if (reg >= NPKRS) return (IA64_ILLOP_FAULT);
+// if (reg >= NPKRS)
+// return IA64_ILLOP_FAULT;
vcpu->pkrs[reg] = val;
- ia64_set_pkr(reg,val);
- return (IA64_NO_FAULT);
+ ia64_set_pkr(reg, val);
+ return IA64_NO_FAULT;
#endif
}
@@ -1876,21 +2022,22 @@ IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val)
**************************************************************************/
static void
-vcpu_set_tr_entry_rid(TR_ENTRY *trp, UINT64 pte,
- UINT64 itir, UINT64 ifa, UINT64 rid)
+vcpu_set_tr_entry_rid(TR_ENTRY * trp, u64 pte,
+ u64 itir, u64 ifa, u64 rid)
{
- UINT64 ps;
+ u64 ps;
union pte_flags new_pte;
trp->itir = itir;
trp->rid = rid;
ps = trp->ps;
new_pte.val = pte;
- if (new_pte.pl < 2) new_pte.pl = 2;
+ if (new_pte.pl < 2)
+ new_pte.pl = 2;
trp->vadr = ifa & ~0xfff;
- if (ps > 12) { // "ignore" relevant low-order bits
- new_pte.ppn &= ~((1UL<<(ps-12))-1);
- trp->vadr &= ~((1UL<<ps)-1);
+ if (ps > 12) { // "ignore" relevant low-order bits
+ new_pte.ppn &= ~((1UL << (ps - 12)) - 1);
+ trp->vadr &= ~((1UL << ps) - 1);
}
/* Atomic write. */
@@ -1898,25 +2045,26 @@ vcpu_set_tr_entry_rid(TR_ENTRY *trp, UINT64 pte,
}
static inline void
-vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa)
+vcpu_set_tr_entry(TR_ENTRY * trp, u64 pte, u64 itir, u64 ifa)
{
vcpu_set_tr_entry_rid(trp, pte, itir, ifa,
- VCPU(current, rrs[ifa>>61]) & RR_RID_MASK);
+ VCPU(current, rrs[ifa >> 61]) & RR_RID_MASK);
}
-IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte,
- UINT64 itir, UINT64 ifa)
+IA64FAULT vcpu_itr_d(VCPU * vcpu, u64 slot, u64 pte,
+ u64 itir, u64 ifa)
{
TR_ENTRY *trp;
- if (slot >= NDTRS) return IA64_RSVDREG_FAULT;
+ if (slot >= NDTRS)
+ return IA64_RSVDREG_FAULT;
vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb));
- trp = &PSCBX(vcpu,dtrs[slot]);
-//printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa);
- vcpu_set_tr_entry(trp,pte,itir,ifa);
- vcpu_quick_region_set(PSCBX(vcpu,dtr_regions),ifa);
+ trp = &PSCBX(vcpu, dtrs[slot]);
+//printk("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa);
+ vcpu_set_tr_entry(trp, pte, itir, ifa);
+ vcpu_quick_region_set(PSCBX(vcpu, dtr_regions), ifa);
/*
* FIXME According to spec, vhpt should be purged, but this
@@ -1930,19 +2078,20 @@ IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte,
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte,
- UINT64 itir, UINT64 ifa)
+IA64FAULT vcpu_itr_i(VCPU * vcpu, u64 slot, u64 pte,
+ u64 itir, u64 ifa)
{
TR_ENTRY *trp;
- if (slot >= NITRS) return IA64_RSVDREG_FAULT;
+ if (slot >= NITRS)
+ return IA64_RSVDREG_FAULT;
vcpu_purge_tr_entry(&PSCBX(vcpu, itlb));
- trp = &PSCBX(vcpu,itrs[slot]);
-//printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa);
- vcpu_set_tr_entry(trp,pte,itir,ifa);
- vcpu_quick_region_set(PSCBX(vcpu,itr_regions),ifa);
+ trp = &PSCBX(vcpu, itrs[slot]);
+//printk("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa);
+ vcpu_set_tr_entry(trp, pte, itir, ifa);
+ vcpu_quick_region_set(PSCBX(vcpu, itr_regions), ifa);
/*
* FIXME According to spec, vhpt should be purged, but this
@@ -1956,13 +2105,13 @@ IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte,
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, u64 pte,
+IA64FAULT vcpu_set_itr(VCPU * vcpu, u64 slot, u64 pte,
u64 itir, u64 ifa, u64 rid)
{
TR_ENTRY *trp;
if (slot >= NITRS)
- return IA64_RSVDREG_FAULT;
+ return IA64_RSVDREG_FAULT;
trp = &PSCBX(vcpu, itrs[slot]);
vcpu_set_tr_entry_rid(trp, pte, itir, ifa, rid);
@@ -1975,7 +2124,7 @@ IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, u64 pte,
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, u64 pte,
+IA64FAULT vcpu_set_dtr(VCPU * vcpu, u64 slot, u64 pte,
u64 itir, u64 ifa, u64 rid)
{
TR_ENTRY *trp;
@@ -1998,63 +2147,72 @@ IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, u64 pte,
VCPU translation cache access routines
**************************************************************************/
-void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 mp_pte, UINT64 logps)
+void
+vcpu_itc_no_srlz(VCPU * vcpu, u64 IorD, u64 vaddr, u64 pte,
+ u64 mp_pte, u64 logps, struct p2m_entry *entry)
{
unsigned long psr;
- unsigned long ps = (vcpu->domain==dom0) ? logps : PAGE_SHIFT;
+ unsigned long ps = (vcpu->domain == dom0) ? logps : PAGE_SHIFT;
- check_xen_space_overlap ("itc", vaddr, 1UL << logps);
+ check_xen_space_overlap("itc", vaddr, 1UL << logps);
// FIXME, must be inlined or potential for nested fault here!
- if ((vcpu->domain==dom0) && (logps < PAGE_SHIFT))
- panic_domain (NULL, "vcpu_itc_no_srlz: domain trying to use "
- "smaller page size!\n");
+ if ((vcpu->domain == dom0) && (logps < PAGE_SHIFT))
+ panic_domain(NULL, "vcpu_itc_no_srlz: domain trying to use "
+ "smaller page size!\n");
BUG_ON(logps > PAGE_SHIFT);
+ vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry);
psr = ia64_clear_ic();
- ia64_itc(IorD,vaddr,pte,ps); // FIXME: look for bigger mappings
+ ia64_itc(IorD, vaddr, pte, ps); // FIXME: look for bigger mappings
ia64_set_psr(psr);
// ia64_srlz_i(); // no srls req'd, will rfi later
#ifdef VHPT_GLOBAL
- if (vcpu->domain==dom0 && ((vaddr >> 61) == 7)) {
+ if (vcpu->domain == dom0 && ((vaddr >> 61) == 7)) {
// FIXME: this is dangerous... vhpt_flush_address ensures these
// addresses never get flushed. More work needed if this
// ever happens.
-//printf("vhpt_insert(%p,%p,%p)\n",vaddr,pte,1L<<logps);
- if (logps > PAGE_SHIFT) vhpt_multiple_insert(vaddr,pte,logps);
- else vhpt_insert(vaddr,pte,logps<<2);
+//printk("vhpt_insert(%p,%p,%p)\n",vaddr,pte,1L<<logps);
+ if (logps > PAGE_SHIFT)
+ vhpt_multiple_insert(vaddr, pte, logps);
+ else
+ vhpt_insert(vaddr, pte, logps << 2);
}
// even if domain pagesize is larger than PAGE_SIZE, just put
// PAGE_SIZE mapping in the vhpt for now, else purging is complicated
- else vhpt_insert(vaddr,pte,PAGE_SHIFT<<2);
+ else
+ vhpt_insert(vaddr, pte, PAGE_SHIFT << 2);
#endif
- if ((mp_pte == -1UL) || (IorD & 0x4)) // don't place in 1-entry TLB
+ if (IorD & 0x4) /* don't place in 1-entry TLB */
return;
if (IorD & 0x1) {
- vcpu_set_tr_entry(&PSCBX(vcpu,itlb),mp_pte,ps<<2,vaddr);
+ vcpu_set_tr_entry(&PSCBX(vcpu, itlb), mp_pte, ps << 2, vaddr);
}
if (IorD & 0x2) {
- vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),mp_pte,ps<<2,vaddr);
+ vcpu_set_tr_entry(&PSCBX(vcpu, dtlb), mp_pte, ps << 2, vaddr);
}
}
-IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+IA64FAULT vcpu_itc_d(VCPU * vcpu, u64 pte, u64 itir, u64 ifa)
{
unsigned long pteval, logps = itir_ps(itir);
- BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode));
+ BOOLEAN swap_rr0 = (!(ifa >> 61) && PSCB(vcpu, metaphysical_mode));
struct p2m_entry entry;
if (logps < PAGE_SHIFT)
- panic_domain (NULL, "vcpu_itc_d: domain trying to use "
- "smaller page size!\n");
+ panic_domain(NULL, "vcpu_itc_d: domain trying to use "
+ "smaller page size!\n");
-again:
+ again:
//itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry);
- if (!pteval) return IA64_ILLOP_FAULT;
- if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0]));
- vcpu_itc_no_srlz(vcpu,2,ifa,pteval,pte,logps);
- if (swap_rr0) set_metaphysical_rr0();
+ if (!pteval)
+ return IA64_ILLOP_FAULT;
+ if (swap_rr0)
+ set_one_rr(0x0, PSCB(vcpu, rrs[0]));
+ vcpu_itc_no_srlz(vcpu, 2, ifa, pteval, pte, logps, &entry);
+ if (swap_rr0)
+ set_metaphysical_rr0();
if (p2m_entry_retry(&entry)) {
vcpu_flush_tlb_vhpt_range(ifa, logps);
goto again;
@@ -2062,22 +2220,25 @@ again:
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+IA64FAULT vcpu_itc_i(VCPU * vcpu, u64 pte, u64 itir, u64 ifa)
{
unsigned long pteval, logps = itir_ps(itir);
- BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode));
+ BOOLEAN swap_rr0 = (!(ifa >> 61) && PSCB(vcpu, metaphysical_mode));
struct p2m_entry entry;
if (logps < PAGE_SHIFT)
- panic_domain (NULL, "vcpu_itc_i: domain trying to use "
- "smaller page size!\n");
-again:
+ panic_domain(NULL, "vcpu_itc_i: domain trying to use "
+ "smaller page size!\n");
+ again:
//itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry);
- if (!pteval) return IA64_ILLOP_FAULT;
- if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0]));
- vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,pte,logps);
- if (swap_rr0) set_metaphysical_rr0();
+ if (!pteval)
+ return IA64_ILLOP_FAULT;
+ if (swap_rr0)
+ set_one_rr(0x0, PSCB(vcpu, rrs[0]));
+ vcpu_itc_no_srlz(vcpu, 1, ifa, pteval, pte, logps, &entry);
+ if (swap_rr0)
+ set_metaphysical_rr0();
if (p2m_entry_retry(&entry)) {
vcpu_flush_tlb_vhpt_range(ifa, logps);
goto again;
@@ -2085,18 +2246,18 @@ again:
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range)
+IA64FAULT vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 log_range)
{
BUG_ON(vcpu != current);
- check_xen_space_overlap ("ptc_l", vadr, 1UL << log_range);
+ check_xen_space_overlap("ptc_l", vadr, 1UL << log_range);
/* Purge TC */
- vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb));
- vcpu_purge_tr_entry(&PSCBX(vcpu,itlb));
-
+ vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb));
+ vcpu_purge_tr_entry(&PSCBX(vcpu, itlb));
+
/* Purge all tlb and vhpt */
- vcpu_flush_tlb_vhpt_range (vadr, log_range);
+ vcpu_flush_tlb_vhpt_range(vadr, log_range);
return IA64_NO_FAULT;
}
@@ -2107,13 +2268,13 @@ IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range)
// access rights fault, we have to translate the virtual address to a
// physical address (possibly via a metaphysical address) and do the fc
// on the physical address, which is guaranteed to flush the same cache line
-IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr)
+IA64FAULT vcpu_fc(VCPU * vcpu, u64 vadr)
{
// TODO: Only allowed for current vcpu
- UINT64 mpaddr, paddr;
+ u64 mpaddr, paddr;
IA64FAULT fault;
-again:
+ again:
fault = vcpu_tpa(vcpu, vadr, &mpaddr);
if (fault == IA64_NO_FAULT) {
struct p2m_entry entry;
@@ -2125,7 +2286,7 @@ again:
return fault;
}
-IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr)
+IA64FAULT vcpu_ptc_e(VCPU * vcpu, u64 vadr)
{
// Note that this only needs to be called once, i.e. the
// architected loop to purge the entire TLB, should use
@@ -2136,27 +2297,27 @@ IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr)
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range)
+IA64FAULT vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 addr_range)
{
printk("vcpu_ptc_g: called, not implemented yet\n");
return IA64_ILLOP_FAULT;
}
-IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+IA64FAULT vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 addr_range)
{
// FIXME: validate not flushing Xen addresses
// if (Xen address) return(IA64_ILLOP_FAULT);
// FIXME: ??breaks if domain PAGE_SIZE < Xen PAGE_SIZE
-//printf("######## vcpu_ptc_ga(%p,%p) ##############\n",vadr,addr_range);
+//printk("######## vcpu_ptc_ga(%p,%p) ##############\n",vadr,addr_range);
- check_xen_space_overlap ("ptc_ga", vadr, addr_range);
+ check_xen_space_overlap("ptc_ga", vadr, addr_range);
- domain_flush_vtlb_range (vcpu->domain, vadr, addr_range);
+ domain_flush_vtlb_range(vcpu->domain, vadr, addr_range);
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 log_range)
+IA64FAULT vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 log_range)
{
unsigned long region = vadr >> 61;
u64 addr_range = 1UL << log_range;
@@ -2165,29 +2326,30 @@ IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 log_range)
TR_ENTRY *trp;
BUG_ON(vcpu != current);
- check_xen_space_overlap ("ptr_d", vadr, 1UL << log_range);
+ check_xen_space_overlap("ptr_d", vadr, 1UL << log_range);
- rr = PSCB(vcpu,rrs)[region];
+ rr = PSCB(vcpu, rrs)[region];
rid = rr & RR_RID_MASK;
/* Purge TC */
- vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb));
+ vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb));
/* Purge tr and recompute dtr_regions. */
vcpu->arch.dtr_regions = 0;
for (trp = vcpu->arch.dtrs, i = NDTRS; i; i--, trp++)
- if (vcpu_match_tr_entry_range (trp,rid, vadr, vadr+addr_range))
+ if (vcpu_match_tr_entry_range
+ (trp, rid, vadr, vadr + addr_range))
vcpu_purge_tr_entry(trp);
else if (trp->pte.p)
vcpu_quick_region_set(vcpu->arch.dtr_regions,
trp->vadr);
- vcpu_flush_tlb_vhpt_range (vadr, log_range);
+ vcpu_flush_tlb_vhpt_range(vadr, log_range);
return IA64_NO_FAULT;
}
-IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 log_range)
+IA64FAULT vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 log_range)
{
unsigned long region = vadr >> 61;
u64 addr_range = 1UL << log_range;
@@ -2196,49 +2358,25 @@ IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 log_range)
TR_ENTRY *trp;
BUG_ON(vcpu != current);
- check_xen_space_overlap ("ptr_i", vadr, 1UL << log_range);
+ check_xen_space_overlap("ptr_i", vadr, 1UL << log_range);
- rr = PSCB(vcpu,rrs)[region];
+ rr = PSCB(vcpu, rrs)[region];
rid = rr & RR_RID_MASK;
/* Purge TC */
- vcpu_purge_tr_entry(&PSCBX(vcpu,itlb));
+ vcpu_purge_tr_entry(&PSCBX(vcpu, itlb));
/* Purge tr and recompute itr_regions. */
vcpu->arch.itr_regions = 0;
for (trp = vcpu->arch.itrs, i = NITRS; i; i--, trp++)
- if (vcpu_match_tr_entry_range (trp,rid, vadr, vadr+addr_range))
+ if (vcpu_match_tr_entry_range
+ (trp, rid, vadr, vadr + addr_range))
vcpu_purge_tr_entry(trp);
else if (trp->pte.p)
vcpu_quick_region_set(vcpu->arch.itr_regions,
trp->vadr);
- vcpu_flush_tlb_vhpt_range (vadr, log_range);
+ vcpu_flush_tlb_vhpt_range(vadr, log_range);
return IA64_NO_FAULT;
}
-
-int ia64_map_hypercall_param(void)
-{
- struct vcpu *v = current;
- struct domain *d = current->domain;
- u64 vaddr = v->arch.hypercall_param.va & PAGE_MASK;
- volatile pte_t* pte;
-
- if (v->arch.hypercall_param.va == 0)
- return FALSE;
- pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa1);
- if (!pte || !pte_present(*pte))
- return FALSE;
- vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte), -1UL, PAGE_SHIFT);
- if (v->arch.hypercall_param.pa2) {
- vaddr += PAGE_SIZE;
- pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa2);
- if (pte && pte_present(*pte)) {
- vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte),
- -1UL, PAGE_SHIFT);
- }
- }
- ia64_srlz_d();
- return TRUE;
-}
diff --git a/xen/arch/ia64/xen/vhpt.c b/xen/arch/ia64/xen/vhpt.c
index f8db5c6e17..05382370cc 100644
--- a/xen/arch/ia64/xen/vhpt.c
+++ b/xen/arch/ia64/xen/vhpt.c
@@ -3,6 +3,10 @@
*
* Copyright (C) 2004 Hewlett-Packard Co
* Dan Magenheimer <dan.magenheimer@hp.com>
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ * per vcpu vhpt support
*/
#include <linux/config.h>
#include <linux/kernel.h>
@@ -14,28 +18,57 @@
#include <asm/page.h>
#include <asm/vhpt.h>
#include <asm/vcpu.h>
+#include <asm/vcpumask.h>
#include <asm/vmmu.h>
/* Defined in tlb.c */
-extern void ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits);
+extern void ia64_global_tlb_purge(u64 start, u64 end, u64 nbits);
extern long running_on_sim;
DEFINE_PER_CPU (unsigned long, vhpt_paddr);
DEFINE_PER_CPU (unsigned long, vhpt_pend);
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+DEFINE_PER_CPU(volatile u32, vhpt_tlbflush_timestamp);
+#endif
-void vhpt_flush(void)
+static void
+__vhpt_flush(unsigned long vhpt_maddr)
{
- struct vhpt_lf_entry *v = __va(__ia64_per_cpu_var(vhpt_paddr));
+ struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr);
int i;
for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++)
v->ti_tag = INVALID_TI_TAG;
}
-static void vhpt_erase(void)
+void
+local_vhpt_flush(void)
+{
+ /* increment flush clock before flush */
+ u32 flush_time = tlbflush_clock_inc_and_return();
+ __vhpt_flush(__ia64_per_cpu_var(vhpt_paddr));
+ /* this must be after flush */
+ tlbflush_update_time(&__get_cpu_var(vhpt_tlbflush_timestamp),
+ flush_time);
+ perfc_incrc(local_vhpt_flush);
+}
+
+void
+vcpu_vhpt_flush(struct vcpu* v)
{
- struct vhpt_lf_entry *v = (struct vhpt_lf_entry *)VHPT_ADDR;
+ /* increment flush clock before flush */
+ u32 flush_time = tlbflush_clock_inc_and_return();
+ __vhpt_flush(vcpu_vhpt_maddr(v));
+ /* this must be after flush */
+ tlbflush_update_time(&v->arch.tlbflush_timestamp, flush_time);
+ perfc_incrc(vcpu_vhpt_flush);
+}
+
+static void
+vhpt_erase(unsigned long vhpt_maddr)
+{
+ struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr);
int i;
for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) {
@@ -47,17 +80,6 @@ static void vhpt_erase(void)
// initialize cache too???
}
-
-static void vhpt_map(unsigned long pte)
-{
- unsigned long psr;
-
- psr = ia64_clear_ic();
- ia64_itr(0x2, IA64_TR_VHPT, VHPT_ADDR, pte, VHPT_SIZE_LOG2);
- ia64_set_psr(psr);
- ia64_srlz_i();
-}
-
void vhpt_insert (unsigned long vadr, unsigned long pte, unsigned long logps)
{
struct vhpt_lf_entry *vlfe = (struct vhpt_lf_entry *)ia64_thash(vadr);
@@ -87,7 +109,7 @@ void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long
// only a few times/second, so OK for now.
// An alternate solution would be to just insert the one
// 16KB in the vhpt (but with the full mapping)?
- //printf("vhpt_multiple_insert: logps-PAGE_SHIFT==%d,"
+ //printk("vhpt_multiple_insert: logps-PAGE_SHIFT==%d,"
//"va=%p, pa=%p, pa-masked=%p\n",
//logps-PAGE_SHIFT,vaddr,pte&_PFN_MASK,
//(pte&_PFN_MASK)&~mask);
@@ -102,7 +124,7 @@ void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long
void vhpt_init(void)
{
- unsigned long paddr, pte;
+ unsigned long paddr;
struct page_info *page;
#if !VHPT_ENABLED
return;
@@ -120,16 +142,85 @@ void vhpt_init(void)
panic("vhpt_init: bad VHPT alignment!\n");
__get_cpu_var(vhpt_paddr) = paddr;
__get_cpu_var(vhpt_pend) = paddr + (1 << VHPT_SIZE_LOG2) - 1;
- printf("vhpt_init: vhpt paddr=0x%lx, end=0x%lx\n",
+ printk("vhpt_init: vhpt paddr=0x%lx, end=0x%lx\n",
paddr, __get_cpu_var(vhpt_pend));
- pte = pte_val(pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL));
- vhpt_map(pte);
- ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) |
- VHPT_ENABLED);
- vhpt_erase();
+ vhpt_erase(paddr);
+ // we don't enable VHPT here.
+ // context_switch() or schedule_tail() does it.
+}
+
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+int
+pervcpu_vhpt_alloc(struct vcpu *v)
+{
+ unsigned long vhpt_size_log2 = VHPT_SIZE_LOG2;
+
+ v->arch.vhpt_entries =
+ (1UL << vhpt_size_log2) / sizeof(struct vhpt_lf_entry);
+ v->arch.vhpt_page =
+ alloc_domheap_pages(NULL, vhpt_size_log2 - PAGE_SHIFT, 0);
+ if (!v->arch.vhpt_page)
+ return -ENOMEM;
+
+ v->arch.vhpt_maddr = page_to_maddr(v->arch.vhpt_page);
+ if (v->arch.vhpt_maddr & ((1 << VHPT_SIZE_LOG2) - 1))
+ panic("pervcpu_vhpt_init: bad VHPT alignment!\n");
+
+ v->arch.pta.val = 0; // to zero reserved bits
+ v->arch.pta.ve = 1; // enable vhpt
+ v->arch.pta.size = VHPT_SIZE_LOG2;
+ v->arch.pta.vf = 1; // long format
+ v->arch.pta.base = __va_ul(v->arch.vhpt_maddr) >> 15;
+
+ vhpt_erase(v->arch.vhpt_maddr);
+ smp_mb(); // per vcpu vhpt may be used by another physical cpu.
+ return 0;
}
+void
+pervcpu_vhpt_free(struct vcpu *v)
+{
+ free_domheap_pages(v->arch.vhpt_page, VHPT_SIZE_LOG2 - PAGE_SHIFT);
+}
+#endif
+
+void
+domain_purge_swtc_entries(struct domain *d)
+{
+ struct vcpu* v;
+ for_each_vcpu(d, v) {
+ if (!test_bit(_VCPUF_initialised, &v->vcpu_flags))
+ continue;
+
+ /* Purge TC entries.
+ FIXME: clear only if match. */
+ vcpu_purge_tr_entry(&PSCBX(v,dtlb));
+ vcpu_purge_tr_entry(&PSCBX(v,itlb));
+ }
+}
+
+void
+domain_purge_swtc_entries_vcpu_dirty_mask(struct domain* d,
+ vcpumask_t vcpu_dirty_mask)
+{
+ int vcpu;
+
+ for_each_vcpu_mask(vcpu, vcpu_dirty_mask) {
+ struct vcpu* v = d->vcpu[vcpu];
+ if (!test_bit(_VCPUF_initialised, &v->vcpu_flags))
+ continue;
+
+ /* Purge TC entries.
+ FIXME: clear only if match. */
+ vcpu_purge_tr_entry(&PSCBX(v, dtlb));
+ vcpu_purge_tr_entry(&PSCBX(v, itlb));
+ }
+}
+// SMP: we can't assume v == current, vcpu might move to another physical cpu.
+// So memory barrier is necessary.
+// if we can guranttee that vcpu can run on only this physical cpu
+// (e.g. vcpu == current), smp_mb() is unnecessary.
void vcpu_flush_vtlb_all(struct vcpu *v)
{
if (VMX_DOMAIN(v)) {
@@ -137,6 +228,7 @@ void vcpu_flush_vtlb_all(struct vcpu *v)
grant_table share page from guest_physmap_remove_page()
in arch_memory_op() XENMEM_add_to_physmap to realize
PV-on-HVM feature. */
+ /* FIXME: This is not SMP-safe yet about p2m table */
/* Purge vTLB for VT-i domain */
thash_purge_all(v);
}
@@ -144,9 +236,14 @@ void vcpu_flush_vtlb_all(struct vcpu *v)
/* First VCPU tlb. */
vcpu_purge_tr_entry(&PSCBX(v,dtlb));
vcpu_purge_tr_entry(&PSCBX(v,itlb));
+ smp_mb();
/* Then VHPT. */
- vhpt_flush();
+ if (HAS_PERVCPU_VHPT(v->domain))
+ vcpu_vhpt_flush(v);
+ else
+ local_vhpt_flush();
+ smp_mb();
/* Then mTLB. */
local_flush_tlb_all();
@@ -155,6 +252,8 @@ void vcpu_flush_vtlb_all(struct vcpu *v)
/* We could clear bit in d->domain_dirty_cpumask only if domain d in
not running on this processor. There is currently no easy way to
check this. */
+
+ perfc_incrc(vcpu_flush_vtlb_all);
}
static void __vcpu_flush_vtlb_all(void *vcpu)
@@ -174,32 +273,60 @@ void domain_flush_vtlb_all (void)
if (v->processor == cpu)
vcpu_flush_vtlb_all(v);
else
+ // SMP: it is racy to reference v->processor.
+ // vcpu scheduler may move this vcpu to another
+ // physicall processor, and change the value
+ // using plain store.
+ // We may be seeing the old value of it.
+ // In such case, flush_vtlb_for_context_switch()
+ // takes care of mTLB flush.
smp_call_function_single(v->processor,
__vcpu_flush_vtlb_all,
v, 1, 1);
}
+ perfc_incrc(domain_flush_vtlb_all);
}
-static void cpu_flush_vhpt_range (int cpu, u64 vadr, u64 addr_range)
+// Callers may need to call smp_mb() before/after calling this.
+// Be carefull.
+static void
+__flush_vhpt_range(unsigned long vhpt_maddr, u64 vadr, u64 addr_range)
{
- void *vhpt_base = __va(per_cpu(vhpt_paddr, cpu));
+ void *vhpt_base = __va(vhpt_maddr);
while ((long)addr_range > 0) {
/* Get the VHPT entry. */
- unsigned int off = ia64_thash(vadr) - VHPT_ADDR;
- volatile struct vhpt_lf_entry *v;
- v = vhpt_base + off;
+ unsigned int off = ia64_thash(vadr) -
+ __va_ul(vcpu_vhpt_maddr(current));
+ struct vhpt_lf_entry *v = vhpt_base + off;
v->ti_tag = INVALID_TI_TAG;
addr_range -= PAGE_SIZE;
vadr += PAGE_SIZE;
}
}
+static void
+cpu_flush_vhpt_range(int cpu, u64 vadr, u64 addr_range)
+{
+ __flush_vhpt_range(per_cpu(vhpt_paddr, cpu), vadr, addr_range);
+}
+
+static void
+vcpu_flush_vhpt_range(struct vcpu* v, u64 vadr, u64 addr_range)
+{
+ __flush_vhpt_range(vcpu_vhpt_maddr(v), vadr, addr_range);
+}
+
void vcpu_flush_tlb_vhpt_range (u64 vadr, u64 log_range)
{
- cpu_flush_vhpt_range (current->processor, vadr, 1UL << log_range);
+ if (HAS_PERVCPU_VHPT(current->domain))
+ vcpu_flush_vhpt_range(current, vadr, 1UL << log_range);
+ else
+ cpu_flush_vhpt_range(current->processor,
+ vadr, 1UL << log_range);
ia64_ptcl(vadr, log_range << 2);
ia64_srlz_i();
+ perfc_incrc(vcpu_flush_tlb_vhpt_range);
}
void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range)
@@ -209,39 +336,138 @@ void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range)
#if 0
// this only seems to occur at shutdown, but it does occur
if ((!addr_range) || addr_range & (addr_range - 1)) {
- printf("vhpt_flush_address: weird range, spinning...\n");
+ printk("vhpt_flush_address: weird range, spinning...\n");
while(1);
}
#endif
- for_each_vcpu (d, v) {
- if (!test_bit(_VCPUF_initialised, &v->vcpu_flags))
- continue;
-
- /* Purge TC entries.
- FIXME: clear only if match. */
- vcpu_purge_tr_entry(&PSCBX(v,dtlb));
- vcpu_purge_tr_entry(&PSCBX(v,itlb));
- }
+ domain_purge_swtc_entries(d);
smp_mb();
for_each_vcpu (d, v) {
if (!test_bit(_VCPUF_initialised, &v->vcpu_flags))
continue;
- /* Invalidate VHPT entries. */
- cpu_flush_vhpt_range (v->processor, vadr, addr_range);
+ if (HAS_PERVCPU_VHPT(d)) {
+ vcpu_flush_vhpt_range(v, vadr, addr_range);
+ } else {
+ // SMP: it is racy to reference v->processor.
+ // vcpu scheduler may move this vcpu to another
+ // physicall processor, and change the value
+ // using plain store.
+ // We may be seeing the old value of it.
+ // In such case, flush_vtlb_for_context_switch()
+ /* Invalidate VHPT entries. */
+ cpu_flush_vhpt_range(v->processor, vadr, addr_range);
+ }
}
// ptc.ga has release semantics.
/* ptc.ga */
ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT);
+ perfc_incrc(domain_flush_vtlb_range);
}
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+#include <asm/tlb_track.h>
+#include <asm/vmx_vcpu.h>
+void
+__domain_flush_vtlb_track_entry(struct domain* d,
+ const struct tlb_track_entry* entry)
+{
+ unsigned long rr7_rid;
+ int swap_rr0 = 0;
+ unsigned long old_rid;
+ unsigned long vaddr = entry->vaddr;
+ struct vcpu* v;
+ int cpu;
+ int vcpu;
+ int local_purge = 1;
+
+ BUG_ON((vaddr >> VRN_SHIFT) != VRN7);
+ /*
+ * heuristic:
+ * dom0linux accesses grant mapped pages via the kernel
+ * straight mapped area and it doesn't change rr7 rid.
+ * So it is likey that rr7 == entry->rid so that
+ * we can avoid rid change.
+ * When blktap is supported, this heuristic should be revised.
+ */
+ vcpu_get_rr(current, VRN7 << VRN_SHIFT, &rr7_rid);
+ if (likely(rr7_rid == entry->rid)) {
+ perfc_incrc(tlb_track_use_rr7);
+ } else {
+ swap_rr0 = 1;
+ vaddr = (vaddr << 3) >> 3;// force vrn0
+ perfc_incrc(tlb_track_swap_rr0);
+ }
+
+ // tlb_track_entry_printf(entry);
+ if (swap_rr0) {
+ vcpu_get_rr(current, 0, &old_rid);
+ vcpu_set_rr(current, 0, entry->rid);
+ }
+
+ if (HAS_PERVCPU_VHPT(d)) {
+ for_each_vcpu_mask(vcpu, entry->vcpu_dirty_mask) {
+ v = d->vcpu[vcpu];
+ if (!test_bit(_VCPUF_initialised, &v->vcpu_flags))
+ continue;
+
+ /* Invalidate VHPT entries. */
+ vcpu_flush_vhpt_range(v, vaddr, PAGE_SIZE);
+
+ /*
+ * current->processor == v->processor
+ * is racy. we may see old v->processor and
+ * a new physical processor of v might see old
+ * vhpt entry and insert tlb.
+ */
+ if (v != current)
+ local_purge = 0;
+ }
+ } else {
+ for_each_cpu_mask(cpu, entry->pcpu_dirty_mask) {
+ /* Invalidate VHPT entries. */
+ cpu_flush_vhpt_range(cpu, vaddr, PAGE_SIZE);
+
+ if (d->vcpu[cpu] != current)
+ local_purge = 0;
+ }
+ }
+
+ /* ptc.ga */
+ if (local_purge) {
+ ia64_ptcl(vaddr, PAGE_SHIFT << 2);
+ perfc_incrc(domain_flush_vtlb_local);
+ } else {
+ /* ptc.ga has release semantics. */
+ ia64_global_tlb_purge(vaddr, vaddr + PAGE_SIZE, PAGE_SHIFT);
+ perfc_incrc(domain_flush_vtlb_global);
+ }
+
+ if (swap_rr0) {
+ vcpu_set_rr(current, 0, old_rid);
+ }
+ perfc_incrc(domain_flush_vtlb_track_entry);
+}
+
+void
+domain_flush_vtlb_track_entry(struct domain* d,
+ const struct tlb_track_entry* entry)
+{
+ domain_purge_swtc_entries_vcpu_dirty_mask(d, entry->vcpu_dirty_mask);
+ smp_mb();
+
+ __domain_flush_vtlb_track_entry(d, entry);
+}
+
+#endif
+
static void flush_tlb_vhpt_all (struct domain *d)
{
/* First VHPT. */
- vhpt_flush ();
+ local_vhpt_flush ();
/* Then mTLB. */
local_flush_tlb_all ();
@@ -250,7 +476,10 @@ static void flush_tlb_vhpt_all (struct domain *d)
void domain_flush_tlb_vhpt(struct domain *d)
{
/* Very heavy... */
- on_each_cpu ((void (*)(void *))flush_tlb_vhpt_all, d, 1, 1);
+ if (HAS_PERVCPU_VHPT(d) || d->arch.is_vti)
+ on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1);
+ else
+ on_each_cpu((void (*)(void *))flush_tlb_vhpt_all, d, 1, 1);
cpus_clear (d->domain_dirty_cpumask);
}
diff --git a/xen/arch/ia64/xen/xen.lds.S b/xen/arch/ia64/xen/xen.lds.S
index 3884f80679..96cd1ce14f 100644
--- a/xen/arch/ia64/xen/xen.lds.S
+++ b/xen/arch/ia64/xen/xen.lds.S
@@ -173,6 +173,9 @@ SECTIONS
* kernel data
*/
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET)
+ { *(.data.read_mostly) }
+
.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET)
{ *(.data.cacheline_aligned) }
diff --git a/xen/arch/ia64/xen/xenasm.S b/xen/arch/ia64/xen/xenasm.S
index 0f0cff9620..af5f31c5b2 100644
--- a/xen/arch/ia64/xen/xenasm.S
+++ b/xen/arch/ia64/xen/xenasm.S
@@ -26,10 +26,11 @@
// void *shared_info, /* in1 */
// void *shared_arch_info, /* in2 */
// unsigned long shared_info_va, /* in3 */
-// unsigned long p_vhpt) /* in4 */
+// unsigned long va_vhpt) /* in4 */
//Local usage:
// loc0=rp, loc1=ar.pfs, loc2=percpu_paddr, loc3=psr, loc4=ar.rse
// loc5=pal_vaddr, loc6=xen_paddr, loc7=shared_archinfo_paddr,
+// r16, r19, r20 are used by ia64_switch_mode_{phys, virt}()
GLOBAL_ENTRY(ia64_new_rr7)
// FIXME? not sure this unwind statement is correct...
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1)
@@ -118,16 +119,31 @@ GLOBAL_ENTRY(ia64_new_rr7)
// VHPT
#if VHPT_ENABLED
- mov r24=VHPT_SIZE_LOG2<<2
- movl r22=VHPT_ADDR
+#if IA64_GRANULE_SHIFT < VHPT_SIZE_LOG2
+#error "it must be that VHPT_SIZE_LOG2 <= IA64_GRANULE_SHIFT"
+#endif
+ // unless overlaps with KERNEL_TR and IA64_TR_CURRENT_STACK
+ dep r14=0,in4,0,KERNEL_TR_PAGE_SHIFT
+ dep r15=0,in4,0,IA64_GRANULE_SHIFT
+ dep r21=0,r13,0,IA64_GRANULE_SHIFT
+ ;;
+ cmp.eq p7,p0=r17,r14
+ cmp.eq p8,p0=r15,r21
+(p7) br.cond.sptk .vhpt_overlaps
+(p8) br.cond.sptk .vhpt_overlaps
mov r21=IA64_TR_VHPT
+ dep r22=0,r15,60,4 // physical address of
+ // va_vhpt & ~(IA64_GRANULE_SIZE - 1)
+ mov r24=IA64_GRANULE_SHIFT<<2
;;
- ptr.d r22,r24
- or r23=in4,r26 // construct PA | page properties
+ ptr.d r15,r24
+ or r23=r22,r26 // construct PA | page properties
mov cr.itir=r24
- mov cr.ifa=r22
+ mov cr.ifa=r15
+ srlz.d
;;
itr.d dtr[r21]=r23 // wire in new mapping...
+.vhpt_overlaps:
#endif
// Shared info
diff --git a/xen/arch/ia64/xen/xencomm.c b/xen/arch/ia64/xen/xencomm.c
new file mode 100644
index 0000000000..3b8e40b5b3
--- /dev/null
+++ b/xen/arch/ia64/xen/xencomm.c
@@ -0,0 +1,387 @@
+/*
+ * 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 (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Tristan Gingold <tristan.gingold@bull.net>
+ */
+
+#include <xen/config.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+#include <asm/guest_access.h>
+#include <public/xen.h>
+#include <public/xencomm.h>
+#include <xen/errno.h>
+
+#undef DEBUG
+#ifdef DEBUG
+static int xencomm_debug = 1; /* extremely verbose */
+#else
+#define xencomm_debug 0
+#endif
+
+static int
+xencomm_copy_chunk_from(
+ unsigned long to,
+ unsigned long paddr,
+ unsigned int len)
+{
+ unsigned long maddr;
+ struct page_info *page;
+
+ while (1) {
+ maddr = xencomm_paddr_to_maddr(paddr);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n", maddr, len, to);
+ if (maddr == 0)
+ return -EFAULT;
+
+ page = virt_to_page(maddr);
+ if (get_page(page, current->domain) == 0) {
+ if (page_get_owner(page) != current->domain) {
+ /* This page might be a page granted by another domain */
+ panic_domain(NULL, "copy_from_guest from foreign domain\n");
+ }
+ /* Try again. */
+ continue;
+ }
+ memcpy((void *)to, (void *)maddr, len);
+ put_page(page);
+ return 0;
+ }
+}
+
+/**
+ * xencomm_copy_from_guest: Copy a block of data from domain space.
+ * @to: Machine address.
+ * @from: Physical address to a xencomm buffer descriptor.
+ * @n: Number of bytes to copy.
+ * @skip: Number of bytes from the start to skip.
+ *
+ * Copy data from domain to hypervisor.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long
+xencomm_copy_from_guest(
+ void *to,
+ const void *from,
+ unsigned int n,
+ unsigned int skip)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ unsigned int from_pos = 0;
+ unsigned int to_pos = 0;
+ unsigned int i = 0;
+
+ if (xencomm_debug)
+ printk("xencomm_copy_from_guest: from=%lx+%u n=%u\n",
+ (unsigned long)from, skip, n);
+
+ if (XENCOMM_IS_INLINE(from)) {
+ unsigned long src_paddr = XENCOMM_INLINE_ADDR(from);
+
+ src_paddr += skip;
+
+ while (n > 0) {
+ unsigned int chunksz;
+ unsigned int bytes;
+ int res;
+
+ chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
+
+ bytes = min(chunksz, n);
+
+ res = xencomm_copy_chunk_from((unsigned long)to, src_paddr, bytes);
+ if (res != 0)
+ return -EFAULT;
+ src_paddr += bytes;
+ to += bytes;
+ n -= bytes;
+ }
+
+ /* Always successful. */
+ return 0;
+ }
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)from);
+ if (desc_addr == 0)
+ return -EFAULT;
+
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s: error: %p magic was 0x%x\n",
+ __func__, desc, desc->magic);
+ return -EFAULT;
+ }
+
+ /* iterate through the descriptor, copying up to a page at a time */
+ while ((to_pos < n) && (i < desc->nr_addrs)) {
+ unsigned long src_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ if (src_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
+ pgoffset = src_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, skip);
+ from_pos += chunk_skip;
+ chunksz -= chunk_skip;
+ skip -= chunk_skip;
+
+ if (skip == 0) {
+ unsigned int bytes = min(chunksz, n - to_pos);
+ int res;
+
+ if (xencomm_debug > 1)
+ printk ("src_paddr=%lx i=%d, skip=%d\n",
+ src_paddr, i, chunk_skip);
+
+ res = xencomm_copy_chunk_from((unsigned long)to + to_pos,
+ src_paddr + chunk_skip, bytes);
+ if (res != 0)
+ return -EFAULT;
+
+ from_pos += bytes;
+ to_pos += bytes;
+ }
+
+ i++;
+ }
+
+ return n - to_pos;
+}
+
+static int
+xencomm_copy_chunk_to(
+ unsigned long paddr,
+ unsigned long from,
+ unsigned int len)
+{
+ unsigned long maddr;
+ struct page_info *page;
+
+ while (1) {
+ maddr = xencomm_paddr_to_maddr(paddr);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n", from, len, maddr);
+ if (maddr == 0)
+ return -EFAULT;
+
+ page = virt_to_page(maddr);
+ if (get_page(page, current->domain) == 0) {
+ if (page_get_owner(page) != current->domain) {
+ /* This page might be a page granted by another domain */
+ panic_domain(NULL, "copy_to_guest to foreign domain\n");
+ }
+ /* Try again. */
+ continue;
+ }
+ memcpy((void *)maddr, (void *)from, len);
+ put_page(page);
+ return 0;
+ }
+}
+
+/**
+ * xencomm_copy_to_guest: Copy a block of data to domain space.
+ * @to: Physical address to xencomm buffer descriptor.
+ * @from: Machine address.
+ * @n: Number of bytes to copy.
+ * @skip: Number of bytes from the start to skip.
+ *
+ * Copy data from hypervisor to domain.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long
+xencomm_copy_to_guest(
+ void *to,
+ const void *from,
+ unsigned int n,
+ unsigned int skip)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ unsigned int from_pos = 0;
+ unsigned int to_pos = 0;
+ unsigned int i = 0;
+
+ if (xencomm_debug)
+ printk ("xencomm_copy_to_guest: to=%lx+%u n=%u\n",
+ (unsigned long)to, skip, n);
+
+ if (XENCOMM_IS_INLINE(to)) {
+ unsigned long dest_paddr = XENCOMM_INLINE_ADDR(to);
+
+ dest_paddr += skip;
+
+ while (n > 0) {
+ unsigned int chunksz;
+ unsigned int bytes;
+ int res;
+
+ chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
+
+ bytes = min(chunksz, n);
+
+ res = xencomm_copy_chunk_to(dest_paddr, (unsigned long)from, bytes);
+ if (res != 0)
+ return res;
+
+ dest_paddr += bytes;
+ from += bytes;
+ n -= bytes;
+ }
+
+ /* Always successful. */
+ return 0;
+ }
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)to);
+ if (desc_addr == 0)
+ return -EFAULT;
+
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
+ return -EFAULT;
+ }
+
+ /* iterate through the descriptor, copying up to a page at a time */
+ while ((from_pos < n) && (i < desc->nr_addrs)) {
+ unsigned long dest_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ if (dest_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
+ pgoffset = dest_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, skip);
+ to_pos += chunk_skip;
+ chunksz -= chunk_skip;
+ skip -= chunk_skip;
+ dest_paddr += chunk_skip;
+
+ if (skip == 0) {
+ unsigned int bytes = min(chunksz, n - from_pos);
+ int res;
+
+ res = xencomm_copy_chunk_to(dest_paddr,
+ (unsigned long)from + from_pos, bytes);
+ if (res != 0)
+ return res;
+
+ from_pos += bytes;
+ to_pos += bytes;
+ }
+
+ i++;
+ }
+ return n - from_pos;
+}
+
+/* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
+ * exhausted pages to XENCOMM_INVALID. */
+void *
+xencomm_add_offset(
+ void *handle,
+ unsigned int bytes)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ int i = 0;
+
+ if (XENCOMM_IS_INLINE(handle))
+ return (void *)((unsigned long)handle + bytes);
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)handle);
+ if (desc_addr == 0)
+ return NULL;
+
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
+ return NULL;
+ }
+
+ /* iterate through the descriptor incrementing addresses */
+ while ((bytes > 0) && (i < desc->nr_addrs)) {
+ unsigned long dest_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ if (dest_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
+ pgoffset = dest_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, bytes);
+ if (chunk_skip == chunksz) {
+ /* exhausted this page */
+ desc->address[i] = XENCOMM_INVALID;
+ } else {
+ desc->address[i] += chunk_skip;
+ }
+ bytes -= chunk_skip;
+
+ i++;
+ }
+ return handle;
+}
+
+int
+xencomm_handle_is_null(
+ void *ptr)
+{
+ if (XENCOMM_IS_INLINE(ptr))
+ return XENCOMM_INLINE_ADDR(ptr) == 0;
+ else {
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)ptr);
+ if (desc_addr == 0)
+ return 1;
+
+ desc = (struct xencomm_desc *)desc_addr;
+ return (desc->nr_addrs == 0);
+ }
+}
diff --git a/xen/arch/ia64/xen/xenmem.c b/xen/arch/ia64/xen/xenmem.c
index 49b6c55588..c837f0fb4b 100644
--- a/xen/arch/ia64/xen/xenmem.c
+++ b/xen/arch/ia64/xen/xenmem.c
@@ -17,10 +17,19 @@
#include <linux/efi.h>
#include <asm/pgalloc.h>
-extern pgd_t frametable_pg_dir[];
+extern unsigned long frametable_pg_dir[];
-#define frametable_pgd_offset(addr) \
- (frametable_pg_dir + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)))
+#define FRAMETABLE_PGD_OFFSET(ADDR) \
+ (frametable_pg_dir + (((ADDR) >> PGDIR_SHIFT) & \
+ ((1UL << (PAGE_SHIFT - 3)) - 1)))
+
+#define FRAMETABLE_PMD_OFFSET(PGD, ADDR) \
+ __va((unsigned long *)(PGD) + (((ADDR) >> PMD_SHIFT) & \
+ ((1UL << (PAGE_SHIFT - 3)) - 1)))
+
+#define FRAMETABLE_PTE_OFFSET(PMD, ADDR) \
+ (pte_t *)__va((unsigned long *)(PMD) + (((ADDR) >> PAGE_SHIFT) & \
+ ((1UL << (PAGE_SHIFT - 3)) - 1)))
static unsigned long table_size;
static int opt_contig_mem = 0;
@@ -29,13 +38,13 @@ boolean_param("contig_mem", opt_contig_mem);
#define opt_contig_mem 1
#endif
-struct page_info *frame_table;
+struct page_info *frame_table __read_mostly;
unsigned long max_page;
/*
* Set up the page tables.
*/
-volatile unsigned long *mpt_table;
+volatile unsigned long *mpt_table __read_mostly;
void
paging_init (void)
@@ -72,7 +81,7 @@ paging_init (void)
#ifdef CONFIG_VIRTUAL_FRAME_TABLE
-static inline void *
+static unsigned long
alloc_dir_page(void)
{
unsigned long mfn = alloc_boot_pages(1, 1);
@@ -82,7 +91,7 @@ alloc_dir_page(void)
++table_size;
dir = mfn << PAGE_SHIFT;
memset(__va(dir), 0, PAGE_SIZE);
- return (void *)dir;
+ return dir;
}
static inline unsigned long
@@ -100,15 +109,33 @@ alloc_table_page(unsigned long fill)
return mfn;
}
+static void
+create_page_table(unsigned long start_page, unsigned long end_page,
+ unsigned long fill)
+{
+ unsigned long address;
+ unsigned long *dir;
+ pte_t *pteptr;
+
+ for (address = start_page; address < end_page; address += PAGE_SIZE) {
+ dir = FRAMETABLE_PGD_OFFSET(address);
+ if (!*dir)
+ *dir = alloc_dir_page();
+ dir = FRAMETABLE_PMD_OFFSET(*dir, address);
+ if (!*dir)
+ *dir = alloc_dir_page();
+ pteptr = FRAMETABLE_PTE_OFFSET(*dir, address);
+ if (pte_none(*pteptr))
+ set_pte(pteptr, pfn_pte(alloc_table_page(fill),
+ PAGE_KERNEL));
+ }
+}
+
static int
create_frametable_page_table (u64 start, u64 end, void *arg)
{
- unsigned long address, start_page, end_page;
struct page_info *map_start, *map_end;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
+ unsigned long start_page, end_page;
map_start = frame_table + (__pa(start) >> PAGE_SHIFT);
map_end = frame_table + (__pa(end) >> PAGE_SHIFT);
@@ -116,23 +143,7 @@ create_frametable_page_table (u64 start, u64 end, void *arg)
start_page = (unsigned long) map_start & PAGE_MASK;
end_page = PAGE_ALIGN((unsigned long) map_end);
- for (address = start_page; address < end_page; address += PAGE_SIZE) {
- pgd = frametable_pgd_offset(address);
- if (pgd_none(*pgd))
- pgd_populate(NULL, pgd, alloc_dir_page());
- pud = pud_offset(pgd, address);
-
- if (pud_none(*pud))
- pud_populate(NULL, pud, alloc_dir_page());
- pmd = pmd_offset(pud, address);
-
- if (pmd_none(*pmd))
- pmd_populate_kernel(NULL, pmd, alloc_dir_page());
- pte = pte_offset_kernel(pmd, address);
-
- if (pte_none(*pte))
- set_pte(pte, pfn_pte(alloc_table_page(0), PAGE_KERNEL));
- }
+ create_page_table(start_page, end_page, 0L);
return 0;
}
@@ -140,11 +151,7 @@ static int
create_mpttable_page_table (u64 start, u64 end, void *arg)
{
unsigned long map_start, map_end;
- unsigned long address, start_page, end_page;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
+ unsigned long start_page, end_page;
map_start = (unsigned long)(mpt_table + (__pa(start) >> PAGE_SHIFT));
map_end = (unsigned long)(mpt_table + (__pa(end) >> PAGE_SHIFT));
@@ -152,23 +159,7 @@ create_mpttable_page_table (u64 start, u64 end, void *arg)
start_page = map_start & PAGE_MASK;
end_page = PAGE_ALIGN(map_end);
- for (address = start_page; address < end_page; address += PAGE_SIZE) {
- pgd = frametable_pgd_offset(address);
- if (pgd_none(*pgd))
- pgd_populate(NULL, pgd, alloc_dir_page());
- pud = pud_offset(pgd, address);
-
- if (pud_none(*pud))
- pud_populate(NULL, pud, alloc_dir_page());
- pmd = pmd_offset(pud, address);
-
- if (pmd_none(*pmd))
- pmd_populate_kernel(NULL, pmd, alloc_dir_page());
- pte = pte_offset_kernel(pmd, address);
-
- if (pte_none(*pte))
- set_pte(pte, pfn_pte(alloc_table_page(INVALID_M2P_ENTRY), PAGE_KERNEL));
- }
+ create_page_table(start_page, end_page, INVALID_M2P_ENTRY);
return 0;
}
diff --git a/xen/arch/ia64/xen/xenmisc.c b/xen/arch/ia64/xen/xenmisc.c
index e9bb00c480..051f78ee30 100644
--- a/xen/arch/ia64/xen/xenmisc.c
+++ b/xen/arch/ia64/xen/xenmisc.c
@@ -165,6 +165,10 @@ void arch_dump_domain_info(struct domain *d)
{
}
+void arch_dump_vcpu_info(struct vcpu *v)
+{
+}
+
void audit_domains_key(unsigned char key)
{
}
@@ -175,13 +179,13 @@ void panic_domain(struct pt_regs *regs, const char *fmt, ...)
char buf[256];
struct vcpu *v = current;
- printf("$$$$$ PANIC in domain %d (k6=0x%lx): ",
+ printk("$$$$$ PANIC in domain %d (k6=0x%lx): ",
v->domain->domain_id,
__get_cpu_var(cpu_kr)._kr[IA64_KR_CURRENT]);
va_start(args, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- printf(buf);
+ printk(buf);
if (regs) show_registers(regs);
if (regs) {
debugger_trap_fatal(0 /* don't care */, regs);
diff --git a/xen/arch/ia64/xen/xenpatch.c b/xen/arch/ia64/xen/xenpatch.c
new file mode 100644
index 0000000000..561e48d28e
--- /dev/null
+++ b/xen/arch/ia64/xen/xenpatch.c
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * xenpatch.c
+ * Copyright (c) 2006 Silicon Graphics Inc.
+ * Jes Sorensen <jes@sgi.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.
+ *
+ * Parts of this based on code from arch/ia64/kernel/patch.c
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <asm/xensystem.h>
+#include <asm/intrinsics.h>
+
+/*
+ * This was adapted from code written by Tony Luck:
+ *
+ * The 64-bit value in a "movl reg=value" is scattered between the two words of the bundle
+ * like this:
+ *
+ * 6 6 5 4 3 2 1
+ * 3210987654321098765432109876543210987654321098765432109876543210
+ * ABBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCDEEEEEFFFFFFFFFGGGGGGG
+ *
+ * CCCCCCCCCCCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ * xxxxAFFFFFFFFFEEEEEDxGGGGGGGxxxxxxxxxxxxxBBBBBBBBBBBBBBBBBBBBBBB
+ */
+static u64
+get_imm64 (u64 insn_addr)
+{
+ u64 *p = (u64 *) (insn_addr & -16); /* mask out slot number */
+
+ return ( (p[1] & 0x0800000000000000UL) << 4) | /*A*/
+ ((p[1] & 0x00000000007fffffUL) << 40) | /*B*/
+ ((p[0] & 0xffffc00000000000UL) >> 24) | /*C*/
+ ((p[1] & 0x0000100000000000UL) >> 23) | /*D*/
+ ((p[1] & 0x0003e00000000000UL) >> 29) | /*E*/
+ ((p[1] & 0x07fc000000000000UL) >> 43) | /*F*/
+ ((p[1] & 0x000007f000000000UL) >> 36); /*G*/
+}
+
+/* Patch instruction with "val" where "mask" has 1 bits. */
+void
+ia64_patch (u64 insn_addr, u64 mask, u64 val)
+{
+ u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16);
+#define insn_mask ((1UL << 41) - 1)
+ unsigned long shift;
+
+ b0 = b[0]; b1 = b[1];
+ /* 5 bits of template, then 3 x 41-bit instructions */
+ shift = 5 + 41 * (insn_addr % 16);
+ if (shift >= 64) {
+ m1 = mask << (shift - 64);
+ v1 = val << (shift - 64);
+ } else {
+ m0 = mask << shift; m1 = mask >> (64 - shift);
+ v0 = val << shift; v1 = val >> (64 - shift);
+ b[0] = (b0 & ~m0) | (v0 & m0);
+ }
+ b[1] = (b1 & ~m1) | (v1 & m1);
+}
+
+void
+ia64_patch_imm64 (u64 insn_addr, u64 val)
+{
+ /* The assembler may generate offset pointing to either slot 1
+ or slot 2 for a long (2-slot) instruction, occupying slots 1
+ and 2. */
+ insn_addr &= -16UL;
+ ia64_patch(insn_addr + 2, 0x01fffefe000UL,
+ (((val & 0x8000000000000000UL) >> 27) | /* bit 63 -> 36 */
+ ((val & 0x0000000000200000UL) << 0) | /* bit 21 -> 21 */
+ ((val & 0x00000000001f0000UL) << 6) | /* bit 16 -> 22 */
+ ((val & 0x000000000000ff80UL) << 20) | /* bit 7 -> 27 */
+ ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */));
+ ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
+}
+
+extern char frametable_miss;
+extern unsigned long xen_pstart;
+
+/*
+ * Add more patch points in seperate functions as appropriate
+ */
+
+static void xen_patch_frametable_miss(u64 offset)
+{
+ u64 addr, val;
+
+ addr = (u64)&frametable_miss;
+ val = get_imm64(addr) + offset;
+ ia64_patch_imm64(addr, val);
+}
+
+
+void xen_patch_kernel(void)
+{
+ unsigned long patch_offset;
+
+ patch_offset = xen_pstart - (KERNEL_START - PAGE_OFFSET);
+
+ printk("Xen patching physical address access by offset: "
+ "0x%lx\n", patch_offset);
+
+ xen_patch_frametable_miss(patch_offset);
+
+ ia64_sync_i();
+ ia64_srlz_i();
+}
diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c
index 12c6850aa7..76f28e0d15 100644
--- a/xen/arch/ia64/xen/xensetup.c
+++ b/xen/arch/ia64/xen/xensetup.c
@@ -18,6 +18,7 @@
#include <xen/domain.h>
#include <xen/serial.h>
#include <xen/trace.h>
+#include <xen/keyhandler.h>
#include <asm/meminit.h>
#include <asm/page.h>
#include <asm/setup.h>
@@ -38,7 +39,6 @@ extern unsigned long domain0_ready;
int find_max_pfn (unsigned long, unsigned long, void *);
/* FIXME: which header these declarations should be there ? */
-extern void initialize_keytable(void);
extern long is_platform_hp_ski(void);
extern void early_setup_arch(char **);
extern void late_setup_arch(char **);
@@ -48,10 +48,7 @@ extern void setup_per_cpu_areas(void);
extern void mem_init(void);
extern void init_IRQ(void);
extern void trap_init(void);
-
-/* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */
-unsigned int opt_dom0_vcpus_pin = 0;
-boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
+extern void xen_patch_kernel(void);
/* opt_nosmp: If true, secondary processors are ignored. */
static int opt_nosmp = 0;
@@ -85,6 +82,7 @@ unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB;
unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE;
extern long running_on_sim;
unsigned long xen_pstart;
+void *xen_heap_start __read_mostly;
static int
xen_count_pages(u64 start, u64 end, void *arg)
@@ -188,8 +186,8 @@ efi_print(void)
for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) {
md = p;
- printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
- i, md->type, md->attribute, md->phys_addr,
+ printk("mem%02u: type=%2u, attr=0x%016lx, range=[0x%016lx-0x%016lx) "
+ "(%luMB)\n", i, md->type, md->attribute, md->phys_addr,
md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
md->num_pages >> (20 - EFI_PAGE_SHIFT));
}
@@ -246,7 +244,6 @@ md_overlaps(efi_memory_desc_t *md, unsigned long phys_addr)
void start_kernel(void)
{
char *cmdline;
- void *heap_start;
unsigned long nr_pages;
unsigned long dom0_memory_start, dom0_memory_size;
unsigned long dom0_initrd_start, dom0_initrd_size;
@@ -297,6 +294,8 @@ void start_kernel(void)
printk("xen image pstart: 0x%lx, xenheap pend: 0x%lx\n",
xen_pstart, xenheap_phys_end);
+ xen_patch_kernel();
+
kern_md = md = efi_get_md(xen_pstart);
md_end = __pa(ia64_imva(&_end));
relo_start = xenheap_phys_end;
@@ -390,13 +389,13 @@ void start_kernel(void)
/* first find highest page frame number */
max_page = 0;
efi_memmap_walk(find_max_pfn, &max_page);
- printf("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page);
+ printk("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page);
efi_print();
- heap_start = memguard_init(ia64_imva(&_end));
- printf("Before heap_start: %p\n", heap_start);
- heap_start = __va(init_boot_allocator(__pa(heap_start)));
- printf("After heap_start: %p\n", heap_start);
+ xen_heap_start = memguard_init(ia64_imva(&_end));
+ printk("Before xen_heap_start: %p\n", xen_heap_start);
+ xen_heap_start = __va(init_boot_allocator(__pa(xen_heap_start)));
+ printk("After xen_heap_start: %p\n", xen_heap_start);
efi_memmap_walk(filter_rsvd_memory, init_boot_pages);
efi_memmap_walk(xen_count_pages, &nr_pages);
@@ -414,16 +413,16 @@ void start_kernel(void)
end_boot_allocator();
- init_xenheap_pages(__pa(heap_start), xenheap_phys_end);
+ init_xenheap_pages(__pa(xen_heap_start), xenheap_phys_end);
printk("Xen heap: %luMB (%lukB)\n",
- (xenheap_phys_end-__pa(heap_start)) >> 20,
- (xenheap_phys_end-__pa(heap_start)) >> 10);
+ (xenheap_phys_end-__pa(xen_heap_start)) >> 20,
+ (xenheap_phys_end-__pa(xen_heap_start)) >> 10);
late_setup_arch(&cmdline);
scheduler_init();
idle_vcpu[0] = (struct vcpu*) ia64_r13;
- idle_domain = domain_create(IDLE_DOMAIN_ID);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
BUG();
@@ -500,12 +499,14 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
efi.hcdp = NULL;
}
+ expose_p2m_init();
+
/* Create initial domain 0. */
- dom0 = domain_create(0);
+ dom0 = domain_create(0, 0);
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
- set_bit(_DOMF_privileged, &dom0->domain_flags);
+ dom0->is_privileged = 1;
/*
* We're going to setup domain0 using the module(s) that we stashed safely
@@ -521,10 +522,6 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
0) != 0)
panic("Could not set up DOM0 guest OS\n");
- /* PIN domain0 VCPU 0 on CPU 0. */
- if (opt_dom0_vcpus_pin)
- dom0->vcpu[0]->cpu_affinity = cpumask_of_cpu(0);
-
if (!running_on_sim) // slow on ski and pages are pre-initialized to zero
scrub_heap_pages();
diff --git a/xen/arch/ia64/xen/xentime.c b/xen/arch/ia64/xen/xentime.c
index 0ebce66c29..7a118de384 100644
--- a/xen/arch/ia64/xen/xentime.c
+++ b/xen/arch/ia64/xen/xentime.c
@@ -39,7 +39,7 @@ seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED;
#define TIME_KEEPER_ID 0
unsigned long domain0_ready = 0;
static s_time_t stime_irq = 0x0; /* System time at last 'time update' */
-unsigned long itc_scale, ns_scale;
+unsigned long itc_scale __read_mostly, ns_scale __read_mostly;
unsigned long itc_at_irq;
/* We don't expect an absolute cycle value here, since then no way
@@ -109,14 +109,13 @@ void
xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long new_itm, old_itc;
- int f_setitm = 0;
#if 0
#define HEARTBEAT_FREQ 16 // period in seconds
#ifdef HEARTBEAT_FREQ
static long count = 0;
if (!(++count & ((HEARTBEAT_FREQ*1024)-1))) {
- printf("Heartbeat... iip=%p\n", /*",psr.i=%d,pend=%d\n", */
+ printk("Heartbeat... iip=%p\n", /*",psr.i=%d,pend=%d\n", */
regs->cr_iip /*,
!current->vcpu_info->evtchn_upcall_mask,
VCPU(current,pending_interruption) */);
@@ -125,20 +124,9 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
#endif
#endif
- if (!is_idle_domain(current->domain)&&!VMX_DOMAIN(current))
- if (vcpu_timer_expired(current)) {
- vcpu_pend_timer(current);
- // ensure another timer interrupt happens even if domain doesn't
- vcpu_set_next_timer(current);
- f_setitm = 1;
- }
new_itm = local_cpu_data->itm_next;
-
- if (f_setitm && !time_after(ia64_get_itc(), new_itm))
- return;
-
- while (1) {
+ while (time_after(ia64_get_itc(), new_itm)) {
new_itm += local_cpu_data->itm_delta;
if (smp_processor_id() == TIME_KEEPER_ID) {
@@ -148,27 +136,32 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
* another CPU. We need to avoid to SMP race by acquiring the
* xtime_lock.
*/
-//#ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN
write_seqlock(&xtime_lock);
-//#endif
#ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN
do_timer(regs);
#endif
- local_cpu_data->itm_next = new_itm;
-
- /* Updates system time (nanoseconds since boot). */
+ /* Updates system time (nanoseconds since boot). */
old_itc = itc_at_irq;
itc_at_irq = ia64_get_itc();
stime_irq += cycle_to_ns(itc_at_irq - old_itc);
-//#ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN
write_sequnlock(&xtime_lock);
-//#endif
- } else
- local_cpu_data->itm_next = new_itm;
+ }
- if (time_after(new_itm, ia64_get_itc()))
- break;
+ local_cpu_data->itm_next = new_itm;
+
+ }
+
+ if (!is_idle_domain(current->domain) && !VMX_DOMAIN(current)) {
+ if (vcpu_timer_expired(current)) {
+ vcpu_pend_timer(current);
+ } else {
+ // ensure another timer interrupt happens
+ // even if domain doesn't
+ vcpu_set_next_timer(current);
+ raise_softirq(TIMER_SOFTIRQ);
+ return;
+ }
}
do {
diff --git a/xen/arch/powerpc/Makefile b/xen/arch/powerpc/Makefile
index ce855e2e42..5db65c2c7c 100644
--- a/xen/arch/powerpc/Makefile
+++ b/xen/arch/powerpc/Makefile
@@ -101,7 +101,8 @@ TARGET_OPTS = $(OMAGIC) -Wl,-Ttext,$(xen_link_base),-T,xen.lds
TARGET_OPTS += start.o $(ALL_OBJS)
.xen-syms: start.o $(ALL_OBJS) xen.lds
- $(CC) $(CFLAGS) $(TARGET_OPTS) -o $@
+ $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o
+ $(CC) $(CFLAGS) $(TARGET_OPTS) $(BASEDIR)/common/symbols-dummy.o -o $@
NM=$(CROSS_COMPILE)nm
new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi)
@@ -140,7 +141,7 @@ asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c $(HDRS)
$(CC) $(CFLAGS) -S -o $@ $<
xen.lds: xen.lds.S $(HDRS)
- $(CC) $(CFLAGS) -P -E $(AFLAGS) -o $@ $<
+ $(CC) -P -E $(AFLAGS) -o $@ $<
dom0.bin: $(DOM0_IMAGE)
cp $< $@
diff --git a/xen/arch/powerpc/backtrace.c b/xen/arch/powerpc/backtrace.c
index ec35d38d9a..0ea2b679de 100644
--- a/xen/arch/powerpc/backtrace.c
+++ b/xen/arch/powerpc/backtrace.c
@@ -93,13 +93,13 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
const char *name = NULL;
unsigned long offset, size;
- printf(REG, address);
+ printk(REG, address);
name = symbols_lookup(address, &size, &offset, namebuf);
if (name) {
- printf("%s%s+%#lx/%#lx", mid, name, offset, size);
+ printk("%s%s+%#lx/%#lx", mid, name, offset, size);
}
- printf("%s", after);
+ printk("%s", after);
}
static void backtrace(
@@ -114,13 +114,13 @@ static void backtrace(
do {
if (sp > xenheap_phys_end) {
if (sp != 0)
- printf("SP (%lx) is not in xen space\n", sp);
+ printk("SP (%lx) is not in xen space\n", sp);
break;
}
if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
|| !mread(sp, &newsp, sizeof(unsigned long))) {
- printf("Couldn't read stack frame at %lx\n", sp);
+ printk("Couldn't read stack frame at %lx\n", sp);
break;
}
@@ -147,17 +147,17 @@ static void backtrace(
printip = 0;
} else if (lr < xenheap_phys_end
&& !(fnstart <= lr && lr < fnend)) {
- printf("[link register ] ");
+ printk("[link register ] ");
xmon_print_symbol(lr, " ", "\n");
}
if (printip) {
- printf("["REG"] ", sp);
+ printk("["REG"] ", sp);
xmon_print_symbol(ip, " ", " (unreliable)\n");
}
pc = lr = 0;
} else {
- printf("["REG"] ", sp);
+ printk("["REG"] ", sp);
xmon_print_symbol(ip, " ", "\n");
}
@@ -167,11 +167,11 @@ static void backtrace(
&& marker == REG_FRAME_MARKER) {
if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
!= sizeof(regs)) {
- printf("Couldn't read registers at %lx\n",
+ printk("Couldn't read registers at %lx\n",
sp + REGS_OFFSET);
break;
}
- printf("--- Exception: %x %s at ", regs.entry_vector,
+ printk("--- Exception: %x %s at ", regs.entry_vector,
getvecname(TRAP(&regs)));
pc = regs.pc;
lr = regs.lr;
diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c
index 29bdd54ba8..636713a8b7 100644
--- a/xen/arch/powerpc/domain.c
+++ b/xen/arch/powerpc/domain.c
@@ -97,44 +97,45 @@ void arch_domain_destroy(struct domain *d)
void machine_halt(void)
{
- printf("machine_halt called: spinning....\n");
+ printk("machine_halt called: spinning....\n");
console_start_sync();
while(1);
}
void machine_restart(char * __unused)
{
- printf("machine_restart called: spinning....\n");
+ printk("machine_restart called: spinning....\n");
console_start_sync();
while(1);
}
-struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id)
+struct vcpu *alloc_vcpu_struct(void)
{
struct vcpu *v;
-
- if ( (v = xmalloc(struct vcpu)) == NULL )
- return NULL;
-
- memset(v, 0, sizeof(*v));
- v->vcpu_id = vcpu_id;
-
+ if ( (v = xmalloc(struct vcpu)) != NULL )
+ memset(v, 0, sizeof(*v));
return v;
}
void free_vcpu_struct(struct vcpu *v)
{
- BUG_ON(v->next_in_list != NULL);
- if ( v->vcpu_id != 0 )
- v->domain->vcpu[v->vcpu_id - 1]->next_in_list = NULL;
xfree(v);
}
+int vcpu_initialise(struct vcpu *v)
+{
+ return 0;
+}
+
+void vcpu_destroy(struct vcpu *v)
+{
+}
+
int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_t *c)
{
memcpy(&v->arch.ctxt, &c->user_regs, sizeof(c->user_regs));
- printf("Domain[%d].%d: initializing\n",
+ printk("Domain[%d].%d: initializing\n",
v->domain->domain_id, v->vcpu_id);
if (v->domain->arch.htab.order == 0)
@@ -186,7 +187,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
unsigned int cpu = smp_processor_id();
#if 0
- printf("%s: dom %x to dom %x\n", __func__, prev->domain->domain_id,
+ printk("%s: dom %x to dom %x\n", __func__, prev->domain->domain_id,
next->domain->domain_id);
#endif
@@ -286,6 +287,10 @@ void arch_dump_domain_info(struct domain *d)
{
}
+void arch_dump_vcpu_info(struct vcpu *v)
+{
+}
+
extern void sleep(void);
static void safe_halt(void)
{
diff --git a/xen/arch/powerpc/domain_build.c b/xen/arch/powerpc/domain_build.c
index 7858cb3c50..cc439ae51d 100644
--- a/xen/arch/powerpc/domain_build.c
+++ b/xen/arch/powerpc/domain_build.c
@@ -40,7 +40,7 @@ static void parse_dom0_mem(char *s)
{
unsigned long long bytes;
- bytes = parse_size_and_unit(s);
+ bytes = parse_size_and_unit(s, NULL);
dom0_nrpages = bytes >> PAGE_SHIFT;
}
custom_param("dom0_mem", parse_dom0_mem);
diff --git a/xen/arch/powerpc/mm.c b/xen/arch/powerpc/mm.c
index 530a64fb47..1df18669d3 100644
--- a/xen/arch/powerpc/mm.c
+++ b/xen/arch/powerpc/mm.c
@@ -86,12 +86,6 @@ void put_page_type(struct page_info *page)
/* Record TLB information for flush later. */
page->tlbflush_timestamp = tlbflush_current_time();
}
- else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) ==
- (PGT_pinned | 1)) )
- {
- /* Page is now only pinned. Make the back pointer mutable again. */
- nx |= PGT_va_mutable;
- }
}
while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
}
@@ -101,6 +95,8 @@ int get_page_type(struct page_info *page, unsigned long type)
{
unsigned long nx, x, y = page->u.inuse.type_info;
+ ASSERT(!(type & ~PGT_type_mask));
+
again:
do {
x = y;
@@ -112,29 +108,25 @@ int get_page_type(struct page_info *page, unsigned long type)
}
else if ( unlikely((x & PGT_count_mask) == 0) )
{
- if ( (x & (PGT_type_mask|PGT_va_mask)) != type )
+ if ( (x & PGT_type_mask) != type )
{
- if ( (x & PGT_type_mask) != (type & PGT_type_mask) )
+ /*
+ * On type change we check to flush stale TLB entries. This
+ * may be unnecessary (e.g., page was GDT/LDT) but those
+ * circumstances should be very rare.
+ */
+ cpumask_t mask =
+ page_get_owner(page)->domain_dirty_cpumask;
+ tlbflush_filter(mask, page->tlbflush_timestamp);
+
+ if ( unlikely(!cpus_empty(mask)) )
{
- /*
- * On type change we check to flush stale TLB
- * entries. This may be unnecessary (e.g., page
- * was GDT/LDT) but those circumstances should be
- * very rare.
- */
- cpumask_t mask =
- page_get_owner(page)->domain_dirty_cpumask;
- tlbflush_filter(mask, page->tlbflush_timestamp);
-
- if ( unlikely(!cpus_empty(mask)) )
- {
- perfc_incrc(need_flush_tlb_flush);
- flush_tlb_mask(mask);
- }
+ perfc_incrc(need_flush_tlb_flush);
+ flush_tlb_mask(mask);
}
/* We lose existing type, back pointer, and validity. */
- nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated);
+ nx &= ~(PGT_type_mask | PGT_validated);
nx |= type;
/* No special validation needed for writable pages. */
@@ -143,36 +135,16 @@ int get_page_type(struct page_info *page, unsigned long type)
nx |= PGT_validated;
}
}
- else
+ else if ( unlikely((x & PGT_type_mask) != type) )
{
- if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) )
- {
- if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) )
- {
- return 0;
- }
- else if ( (x & PGT_va_mask) == PGT_va_mutable )
- {
- /* The va backpointer is mutable, hence we update it. */
- nx &= ~PGT_va_mask;
- nx |= type; /* we know the actual type is correct */
- }
- else if ( (type & PGT_va_mask) != PGT_va_mutable )
- {
- ASSERT((type & PGT_va_mask) != (x & PGT_va_mask));
-
- /* This table is possibly mapped at multiple locations. */
- nx &= ~PGT_va_mask;
- nx |= PGT_va_unknown;
- }
- }
- if ( unlikely(!(x & PGT_validated)) )
- {
- /* Someone else is updating validation of this page. Wait... */
- while ( (y = page->u.inuse.type_info) == x )
- cpu_relax();
- goto again;
- }
+ return 0;
+ }
+ if ( unlikely(!(x & PGT_validated)) )
+ {
+ /* Someone else is updating validation of this page. Wait... */
+ while ( (y = page->u.inuse.type_info) == x )
+ cpu_relax();
+ goto again;
}
}
while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
@@ -296,7 +268,7 @@ int allocate_rma(struct domain *d, unsigned int order)
d->arch.rma_page = alloc_domheap_pages(d, order, 0);
if (d->arch.rma_page == NULL) {
- DPRINTK("Could not allocate order=%d RMA for domain %u\n",
+ gdprintk(XENLOG_INFO, "Could not allocate order=%d RMA for domain %u\n",
order, d->domain_id);
return -ENOMEM;
}
@@ -344,8 +316,7 @@ ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
int t = PFN_TYPE_NONE;
/* quick tests first */
- if (test_bit(_DOMF_privileged, &d->domain_flags) &&
- cpu_io_mfn(pfn)) {
+ if (d->is_privileged && cpu_io_mfn(pfn)) {
t = PFN_TYPE_IO;
mfn = pfn;
} else {
@@ -369,8 +340,7 @@ ulong pfn2mfn(struct domain *d, ulong pfn, int *type)
if (t == PFN_TYPE_NONE) {
/* This hack allows dom0 to map all memory, necessary to
* initialize domU state. */
- if (test_bit(_DOMF_privileged, &d->domain_flags) &&
- mfn_valid(pfn)) {
+ if (d->is_privileged && mfn_valid(pfn)) {
struct page_info *pg;
/* page better be allocated to some domain but not the caller */
diff --git a/xen/arch/powerpc/of-devwalk.c b/xen/arch/powerpc/of-devwalk.c
index d39a8df73a..dc57ab7ebe 100644
--- a/xen/arch/powerpc/of-devwalk.c
+++ b/xen/arch/powerpc/of-devwalk.c
@@ -35,7 +35,7 @@ void ofd_prop_print(
if ( path[0] == '/' && path[1] == '\0' ) {
path = "";
}
- printf("%s: %s/%s: 0x%lx\n", head, path, name, sz);
+ printk("%s: %s/%s: 0x%lx\n", head, path, name, sz);
#define DEBUG_PROP
#ifdef DEBUG_PROP
@@ -56,24 +56,24 @@ void ofd_prop_print(
}
if ( isstr > 0 ) {
- printf("%s: \t%s\n", head, b);
+ printk("%s: \t%s\n", head, b);
} else if ( sz != 0 ) {
- printf("%s: \t0x", head);
+ printk("%s: \t0x", head);
for ( i = 0; i < sz; i++ ) {
if ( (i % 4) == 0 && i != 0 ) {
if ( (i % 16) == 0 && i != 0 ) {
- printf("\n%s: \t0x", head);
+ printk("\n%s: \t0x", head);
} else {
- printf(" 0x");
+ printk(" 0x");
}
}
if (b[i] < 0x10) {
- printf("0");
+ printk("0");
}
- printf("%x", b[i]);
+ printk("%x", b[i]);
}
- printf("\n");
+ printk("\n");
}
#else
(void)prop;
@@ -95,7 +95,7 @@ void ofd_dump_props(void *mem, ofdn_t n, int dump)
}
if (dump & OFD_DUMP_NAMES) {
- printf("of_walk: %s: phandle 0x%x\n", path, n);
+ printk("of_walk: %s: phandle 0x%x\n", path, n);
}
p = ofd_nextprop(mem, n, NULL, name);
diff --git a/xen/arch/powerpc/papr/xlate.c b/xen/arch/powerpc/papr/xlate.c
index 01a0e89664..7ea5a39d5f 100644
--- a/xen/arch/powerpc/papr/xlate.c
+++ b/xen/arch/powerpc/papr/xlate.c
@@ -174,7 +174,7 @@ static void h_enter(struct cpu_user_regs *regs)
if (mtype == PFN_TYPE_IO) {
/* only a privilaged dom can access outside IO space */
- if ( !test_bit(_DOMF_privileged, &d->domain_flags) ) {
+ if ( !d->is_privileged ) {
regs->gprs[3] = H_Privilege;
printk("%s: unprivileged access to physical page: 0x%lx\n",
__func__, pfn);
diff --git a/xen/arch/powerpc/powerpc64/domain.c b/xen/arch/powerpc/powerpc64/domain.c
index 2714a7917b..f9633ccfbd 100644
--- a/xen/arch/powerpc/powerpc64/domain.c
+++ b/xen/arch/powerpc/powerpc64/domain.c
@@ -112,7 +112,7 @@ void save_segments(struct vcpu *v)
slb_entry[i].slb_esid = esid;
#ifdef SLB_DEBUG
if (vsid != 0) {
- printf("%s: DOM[0x%x]: S%02d: 0x%016lx 0x%016lx\n",
+ printk("%s: DOM[0x%x]: S%02d: 0x%016lx 0x%016lx\n",
__func__, v->domain->domain_id, i, vsid, esid);
}
#endif
@@ -146,7 +146,7 @@ void load_segments(struct vcpu *v)
#ifdef SLB_DEBUG
if (vsid != 0) {
- printf("%s: DOM[0x%x]: R%02d: 0x%016lx 0x%016lx\n",
+ printk("%s: DOM[0x%x]: R%02d: 0x%016lx 0x%016lx\n",
__func__, v->domain->domain_id, i, vsid, esid);
}
#endif
@@ -173,6 +173,6 @@ void dump_segments(int valid)
if (valid && !(esid & SLB_ESID_VALID))
continue;
- printf("S%02d: 0x%016lx 0x%016lx\n", i, vsid, esid);
+ printk("S%02d: 0x%016lx 0x%016lx\n", i, vsid, esid);
}
}
diff --git a/xen/arch/powerpc/setup.c b/xen/arch/powerpc/setup.c
index eb75a30bd4..5c839f698e 100644
--- a/xen/arch/powerpc/setup.c
+++ b/xen/arch/powerpc/setup.c
@@ -87,9 +87,6 @@ struct ns16550_defaults ns16550;
extern char __per_cpu_start[], __per_cpu_data_end[], __per_cpu_end[];
-/* move us to a header file */
-extern void initialize_keytable(void);
-
volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
int is_kernel_text(unsigned long addr)
@@ -160,7 +157,7 @@ static void __init start_of_day(void)
scheduler_init();
/* create idle domain */
- idle_domain = domain_create(IDLE_DOMAIN_ID);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
if ((idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL))
BUG();
set_current(idle_domain->vcpu[0]);
@@ -345,7 +342,7 @@ static void __init __start_xen(multiboot_info_t *mbi)
start_of_day();
/* Create initial domain 0. */
- dom0 = domain_create(0);
+ dom0 = domain_create(0, 0);
if (dom0 == NULL)
panic("Error creating domain 0\n");
dom0->max_pages = ~0U;
@@ -358,8 +355,9 @@ static void __init __start_xen(multiboot_info_t *mbi)
* need to make sure Dom0's vVCPU 0 is pinned to the CPU */
dom0->vcpu[0]->cpu_affinity = cpumask_of_cpu(0);
- set_bit(_DOMF_privileged, &dom0->domain_flags);
- /* post-create hooks sets security label */
+ dom0->is_privileged = 1;
+
+ /* Post-create hook sets security label. */
acm_post_domain0_create(dom0->domain_id);
cmdline = (char *)(mod[0].string ? __va((ulong)mod[0].string) : NULL);
diff --git a/xen/arch/powerpc/shadow.c b/xen/arch/powerpc/shadow.c
index 3694d27e77..3d33433c0f 100644
--- a/xen/arch/powerpc/shadow.c
+++ b/xen/arch/powerpc/shadow.c
@@ -120,14 +120,14 @@ int shadow_domctl(struct domain *d,
{
if ( unlikely(d == current->domain) )
{
- DPRINTK("Don't try to do a shadow op on yourself!\n");
+ gdprintk(XENLOG_INFO, "Don't try to do a shadow op on yourself!\n");
return -EINVAL;
}
switch ( sc->op )
{
case XEN_DOMCTL_SHADOW_OP_OFF:
- DPRINTK("Shadow is mandatory!\n");
+ gdprintk(XENLOG_INFO, "Shadow is mandatory!\n");
return -EINVAL;
case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
diff --git a/xen/arch/powerpc/usercopy.c b/xen/arch/powerpc/usercopy.c
index 48ab7579de..d653ed1a05 100644
--- a/xen/arch/powerpc/usercopy.c
+++ b/xen/arch/powerpc/usercopy.c
@@ -249,6 +249,11 @@ int xencomm_add_offset(void *handle, unsigned int bytes)
unsigned int chunksz;
unsigned int chunk_skip;
+ if (dest_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
pgoffset = dest_paddr % PAGE_SIZE;
chunksz = PAGE_SIZE - pgoffset;
@@ -260,6 +265,8 @@ int xencomm_add_offset(void *handle, unsigned int bytes)
desc->address[i] += chunk_skip;
}
bytes -= chunk_skip;
+
+ i++;
}
return 0;
}
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 991fa436b3..89cc508d02 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -28,12 +28,14 @@ obj-y += microcode.o
obj-y += mm.o
obj-y += mpparse.o
obj-y += nmi.o
+obj-y += numa.o
obj-y += physdev.o
obj-y += rwlock.o
obj-y += setup.o
obj-y += shutdown.o
obj-y += smp.o
obj-y += smpboot.o
+obj-y += srat.o
obj-y += string.o
obj-y += sysctl.o
obj-y += time.o
@@ -46,26 +48,30 @@ obj-$(crash_debug) += gdbstub.o
$(TARGET): $(TARGET)-syms boot/mkelf32
./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \
- `$(NM) $(TARGET)-syms | sort | tail -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'`
+ `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'`
$(TARGET)-syms: boot/$(TARGET_SUBARCH).o $(ALL_OBJS) xen.lds
+ $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o
$(LD) $(LDFLAGS) -T xen.lds -N \
- boot/$(TARGET_SUBARCH).o $(ALL_OBJS) -o $@
- $(NM) -n $@ | $(BASEDIR)/tools/symbols >$(BASEDIR)/xen-syms.S
- $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/xen-syms.o
+ boot/$(TARGET_SUBARCH).o $(ALL_OBJS) \
+ $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0
+ $(NM) -n $(@D)/.$(@F).0 | $(BASEDIR)/tools/symbols >$(@D)/.$(@F).0.S
+ $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o
$(LD) $(LDFLAGS) -T xen.lds -N \
- boot/$(TARGET_SUBARCH).o $(ALL_OBJS) $(BASEDIR)/xen-syms.o -o $@
- $(NM) -n $@ | $(BASEDIR)/tools/symbols >$(BASEDIR)/xen-syms.S
- $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/xen-syms.o
+ boot/$(TARGET_SUBARCH).o $(ALL_OBJS) \
+ $(@D)/.$(@F).0.o -o $(@D)/.$(@F).1
+ $(NM) -n $(@D)/.$(@F).1 | $(BASEDIR)/tools/symbols >$(@D)/.$(@F).1.S
+ $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o
$(LD) $(LDFLAGS) -T xen.lds -N \
- boot/$(TARGET_SUBARCH).o $(ALL_OBJS) $(BASEDIR)/xen-syms.o -o $@
- rm -f $(BASEDIR)/xen-syms.S $(BASEDIR)/xen-syms.o
+ boot/$(TARGET_SUBARCH).o $(ALL_OBJS) \
+ $(@D)/.$(@F).1.o -o $@
+ rm -f $(@D)/.$(@F).[0-9]*
asm-offsets.s: $(TARGET_SUBARCH)/asm-offsets.c $(HDRS)
$(CC) $(CFLAGS) -S -o $@ $<
xen.lds: $(TARGET_SUBARCH)/xen.lds.S $(HDRS)
- $(CC) $(CFLAGS) -P -E -Ui386 $(AFLAGS) -o $@ $<
+ $(CC) -P -E -Ui386 $(AFLAGS) -o $@ $<
boot/mkelf32: boot/mkelf32.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
@@ -73,3 +79,4 @@ boot/mkelf32: boot/mkelf32.c
.PHONY: clean
clean::
rm -f asm-offsets.s xen.lds boot/*.o boot/*~ boot/core boot/mkelf32
+ rm -f $(BASEDIR)/.xen-syms.[0-9]*
diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk
index 32c8e02695..899f28129c 100644
--- a/xen/arch/x86/Rules.mk
+++ b/xen/arch/x86/Rules.mk
@@ -3,6 +3,7 @@
HAS_ACPI := y
HAS_VGA := y
+xenoprof := y
#
# If you change any of these configuration options then you must
@@ -11,41 +12,44 @@ HAS_VGA := y
pae ?= n
supervisor_mode_kernel ?= n
-CFLAGS += -nostdinc -fno-builtin -fno-common -fno-strict-aliasing
-CFLAGS += -iwithprefix include -Werror -Wno-pointer-arith -pipe
-CFLAGS += -I$(BASEDIR)/include
-CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-generic
-CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-default
+# Solaris grabs stdarg.h and friends from the system include directory.
+ifneq ($(XEN_OS),SunOS)
+CFLAGS += -nostdinc
+endif
+
+CFLAGS += -fno-builtin -fno-common -fno-strict-aliasing
+CFLAGS += -iwithprefix include -Werror -Wno-pointer-arith -pipe
+CFLAGS += -I$(BASEDIR)/include
+CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-generic
+CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-default
# Prevent floating-point variables from creeping into Xen.
-CFLAGS += -msoft-float
+CFLAGS += -msoft-float
# Disable PIE/SSP if GCC supports them. They can break us.
-CFLAGS += $(call test-gcc-flag,$(CC),-nopie)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector)
-CFLAGS += $(call test-gcc-flag,$(CC),-fno-stack-protector-all)
+CFLAGS += $(call cc-option,$(CC),-nopie,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
ifeq ($(TARGET_SUBARCH)$(pae),x86_32y)
-CFLAGS += -DCONFIG_X86_PAE=1
+CFLAGS += -DCONFIG_X86_PAE=1
endif
ifeq ($(supervisor_mode_kernel),y)
-CFLAGS += -DCONFIG_X86_SUPERVISOR_MODE_KERNEL=1
+CFLAGS += -DCONFIG_X86_SUPERVISOR_MODE_KERNEL=1
endif
ifeq ($(XEN_TARGET_ARCH),x86_32)
-LDFLAGS += -m elf_i386
x86_32 := y
x86_64 := n
endif
ifeq ($(TARGET_SUBARCH),x86_64)
-CFLAGS += -mno-red-zone -fpic -fno-reorder-blocks
-CFLAGS += -fno-asynchronous-unwind-tables
+CFLAGS += -mno-red-zone -fpic -fno-reorder-blocks
+CFLAGS += -fno-asynchronous-unwind-tables
# -fvisibility=hidden reduces -fpic cost, if it's available
-CFLAGS += $(shell $(CC) -v --help 2>&1 | grep " -fvisibility=" | \
- grep -q hidden && echo "-fvisibility=hidden")
-LDFLAGS += -m elf_x86_64
+CFLAGS += $(call cc-option,$(CC),-fvisibility=hidden,)
+CFLAGS := $(subst -fvisibility=hidden,-DGCC_HAS_VISIBILITY_ATTRIBUTE,$(CFLAGS))
x86_32 := n
x86_64 := y
endif
diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c
index 11bd6e14b4..76f329d372 100644
--- a/xen/arch/x86/acpi/boot.c
+++ b/xen/arch/x86/acpi/boot.c
@@ -106,7 +106,7 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
unsigned long base, offset, mapped_size;
int idx;
- if (phys + size < 8 * 1024 * 1024)
+ if (phys + size < 8 * 1024 * 1024)
return __va(phys);
offset = phys & (PAGE_SIZE - 1);
@@ -132,7 +132,7 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
#ifdef CONFIG_X86_LOCAL_APIC
static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
{
- struct acpi_table_madt *madt = NULL;
+ struct acpi_table_madt *madt = NULL;
if (!phys_addr || !size)
return -EINVAL;
@@ -147,18 +147,18 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
acpi_lapic_addr = (u64) madt->lapic_address;
printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
- madt->lapic_address);
+ madt->lapic_address);
}
acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
-
+
return 0;
}
static int __init
acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
{
- struct acpi_table_lapic *processor = NULL;
+ struct acpi_table_lapic *processor = NULL;
processor = (struct acpi_table_lapic *)header;
@@ -167,10 +167,17 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
acpi_table_print_madt_entry(header);
- /* Register even disabled CPUs for cpu hotplug */
-
- x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
+ /* Record local apic id only when enabled */
+ if (processor->flags.enabled)
+ x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
+ /*
+ * We need to register disabled CPU as well to permit
+ * counting disabled CPUs. This allows us to size
+ * cpus_possible_map more accurately, to permit
+ * to not preallocating memory for all NR_CPUS
+ * when we use CPU hotplug.
+ */
mp_register_lapic(processor->id, /* APIC ID */
processor->flags.enabled); /* Enabled? */
@@ -224,7 +231,7 @@ acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
if (BAD_MADT_ENTRY(ioapic, end))
return -EINVAL;
-
+
acpi_table_print_madt_entry(header);
mp_register_ioapic(ioapic->id,
@@ -281,8 +288,8 @@ acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
static unsigned long __init
acpi_scan_rsdp(unsigned long start, unsigned long length)
{
- unsigned long offset = 0;
- unsigned long sig_len = sizeof("RSD PTR ") - 1;
+ unsigned long offset = 0;
+ unsigned long sig_len = sizeof("RSD PTR ") - 1;
/*
* Scan all 16-byte boundaries of the physical memory region for the
@@ -302,7 +309,7 @@ static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
struct acpi_table_sbf *sb;
if (!phys_addr || !size)
- return -EINVAL;
+ return -EINVAL;
sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size);
if (!sb) {
@@ -310,12 +317,11 @@ static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
return -ENODEV;
}
- sbf_port = sb->sbf_cmos; /* Save CMOS port */
+ sbf_port = sb->sbf_cmos; /* Save CMOS port */
return 0;
}
-
#ifdef CONFIG_HPET_TIMER
static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
@@ -349,7 +355,7 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
hpet_address = hpet_tbl->addr.addrl;
printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
- hpet_tbl->id, hpet_address);
+ hpet_tbl->id, hpet_address);
}
#endif /* X86 */
@@ -410,17 +416,16 @@ static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
return 0;
}
-
unsigned long __init acpi_find_rsdp(void)
{
- unsigned long rsdp_phys = 0;
+ unsigned long rsdp_phys = 0;
#if 0
if (efi_enabled) {
- if (efi.acpi20)
- return __pa(efi.acpi20);
- else if (efi.acpi)
- return __pa(efi.acpi);
+ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+ return efi.acpi20;
+ else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+ return efi.acpi;
}
#endif
/*
@@ -443,6 +448,9 @@ static int __init acpi_parse_madt_lapic_entries(void)
{
int count;
+ if (!cpu_has_apic)
+ return -ENODEV;
+
/*
* Note that the LAPIC address is obtained from the MADT (32-bit value)
* and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
@@ -460,8 +468,8 @@ static int __init acpi_parse_madt_lapic_entries(void)
mp_register_lapic_address(acpi_lapic_addr);
count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
- MAX_APICS);
- if (!count) {
+ MAX_APICS);
+ if (!count) {
printk(KERN_ERR PREFIX "No LAPIC entries present\n");
/* TBD: Cleanup to allow fallback to MPS */
return -ENODEV;
@@ -499,14 +507,17 @@ static int __init acpi_parse_madt_ioapic_entries(void)
*/
if (acpi_disabled || acpi_noirq) {
return -ENODEV;
- }
+ }
+
+ if (!cpu_has_apic)
+ return -ENODEV;
/*
- * if "noapic" boot option, don't look for IO-APICs
+ * if "noapic" boot option, don't look for IO-APICs
*/
if (skip_ioapic_setup) {
printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
- "due to 'noapic' option.\n");
+ "due to 'noapic' option.\n");
return -ENODEV;
}
@@ -852,7 +863,7 @@ int __init acpi_boot_table_init(void)
* One exception: acpi=ht continues far enough to enumerate LAPICs
*/
if (acpi_disabled && !acpi_ht)
- return 1;
+ return 1;
/*
* Initialize the ACPI boot-time table parser.
@@ -884,7 +895,6 @@ int __init acpi_boot_table_init(void)
return 0;
}
-
int __init acpi_boot_init(void)
{
/*
@@ -892,7 +902,7 @@ int __init acpi_boot_init(void)
* One exception: acpi=ht continues far enough to enumerate LAPICs
*/
if (acpi_disabled && !acpi_ht)
- return 1;
+ return 1;
acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
@@ -910,4 +920,3 @@ int __init acpi_boot_init(void)
return 0;
}
-
diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c
index 325da60484..f6a79a7d2f 100644
--- a/xen/arch/x86/apic.c
+++ b/xen/arch/x86/apic.c
@@ -1,5 +1,5 @@
/*
- * based on linux-2.6.11/arch/i386/kernel/apic.c
+ * based on linux-2.6.17.13/arch/i386/kernel/apic.c
*
* Local APIC handling, local APIC timers
*
@@ -50,6 +50,18 @@ int apic_verbosity;
static void apic_pm_activate(void);
+int modern_apic(void)
+{
+ unsigned int lvr, version;
+ /* AMD systems use old APIC versions, so check the CPU */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 >= 0xf)
+ return 1;
+ lvr = apic_read(APIC_LVR);
+ version = GET_APIC_VERSION(lvr);
+ return version >= 0x14;
+}
+
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves.
@@ -64,8 +76,10 @@ void ack_bad_irq(unsigned int irq)
* holds up an irq slot - in excessive cases (when multiple
* unexpected vectors occur) that might lock up the APIC
* completely.
+ * But only ack when the APIC is enabled -AK
*/
- ack_APIC_irq();
+ if (cpu_has_apic)
+ ack_APIC_irq();
}
void __init apic_intr_init(void)
@@ -91,12 +105,21 @@ int using_apic_timer = 0;
static int enabled_via_apicbase;
+void enable_NMI_through_LVT0 (void * dummy)
+{
+ unsigned int v, ver;
+
+ ver = apic_read(APIC_LVR);
+ ver = GET_APIC_VERSION(ver);
+ v = APIC_DM_NMI; /* unmask and set to NMI */
+ if (!APIC_INTEGRATED(ver)) /* 82489DX */
+ v |= APIC_LVT_LEVEL_TRIGGER;
+ apic_write_around(APIC_LVT0, v);
+}
+
int get_physical_broadcast(void)
{
- unsigned int lvr, version;
- lvr = apic_read(APIC_LVR);
- version = GET_APIC_VERSION(lvr);
- if (!APIC_INTEGRATED(version) || version >= 0x14)
+ if (modern_apic())
return 0xff;
else
return 0xf;
@@ -323,9 +346,9 @@ int __init verify_local_APIC(void)
void __init sync_Arb_IDs(void)
{
- /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
- unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
- if (ver >= 0x14) /* P4 or higher */
+ /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1
+ And not needed on AMD */
+ if (modern_apic())
return;
/*
* Wait for idle.
@@ -389,6 +412,7 @@ void __init init_bsp_APIC(void)
void __devinit setup_local_APIC(void)
{
unsigned long oldvalue, value, ver, maxlvt;
+ int i, j;
/* Pound the ESR really hard over the head with a big hammer - mbligh */
if (esr_disable) {
@@ -426,6 +450,25 @@ void __devinit setup_local_APIC(void)
apic_write_around(APIC_TASKPRI, value);
/*
+ * After a crash, we no longer service the interrupts and a pending
+ * interrupt from previous kernel might still have ISR bit set.
+ *
+ * Most probably by now CPU has serviced that pending interrupt and
+ * it might not have done the ack_APIC_irq() because it thought,
+ * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
+ * does not clear the ISR bit and cpu thinks it has already serivced
+ * the interrupt. Hence a vector might get locked. It was noticed
+ * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
+ */
+ for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+ value = apic_read(APIC_ISR + i*0x10);
+ for (j = 31; j >= 0; j--) {
+ if (value & (1<<j))
+ ack_APIC_irq();
+ }
+ }
+
+ /*
* Now that we are all set up, enable the APIC
*/
value = apic_read(APIC_SPIV);
@@ -536,6 +579,29 @@ void __devinit setup_local_APIC(void)
apic_pm_activate();
}
+/*
+ * If Linux enabled the LAPIC against the BIOS default
+ * disable it down before re-entering the BIOS on shutdown.
+ * Otherwise the BIOS may get confused and not power-off.
+ * Additionally clear all LVT entries before disable_local_APIC
+ * for the case where Linux didn't enable the LAPIC.
+ */
+void lapic_shutdown(void)
+{
+ unsigned long flags;
+
+ if (!cpu_has_apic)
+ return;
+
+ local_irq_save(flags);
+ clear_local_APIC();
+
+ if (enabled_via_apicbase)
+ disable_local_APIC();
+
+ local_irq_restore(flags);
+}
+
static void apic_pm_activate(void) { }
/*
@@ -1086,6 +1152,7 @@ int __init APIC_init_uniprocessor (void)
if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
+ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
return -1;
}
@@ -1093,6 +1160,14 @@ int __init APIC_init_uniprocessor (void)
connect_bsp_APIC();
+ /*
+ * Hack: In case of kdump, after a crash, kernel might be booting
+ * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid
+ * might be zero if read from MP tables. Get it from LAPIC.
+ */
+#ifdef CONFIG_CRASH_DUMP
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
+#endif
phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
setup_local_APIC();
diff --git a/xen/arch/x86/boot/mkelf32.c b/xen/arch/x86/boot/mkelf32.c
index 53cc514295..18e52b5836 100644
--- a/xen/arch/x86/boot/mkelf32.c
+++ b/xen/arch/x86/boot/mkelf32.c
@@ -90,6 +90,11 @@ static Elf32_Shdr out_shdr[] = {
}
};
+/* Some system header files define these macros and pollute our namespace. */
+#undef swap16
+#undef swap32
+#undef swap64
+
#define swap16(_v) ((((u16)(_v)>>8)&0xff)|(((u16)(_v)&0xff)<<8))
#define swap32(_v) (((u32)swap16((u16)(_v))<<16)|(u32)swap16((u32)((_v)>>16)))
#define swap64(_v) (((u64)swap32((u32)(_v))<<32)|(u64)swap32((u32)((_v)>>32)))
diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S
index 2e56403b66..e0f2e09643 100644
--- a/xen/arch/x86/boot/x86_32.S
+++ b/xen/arch/x86/boot/x86_32.S
@@ -185,7 +185,7 @@ ignore_int:
mov %eax,%ds
mov %eax,%es
pushl $int_msg
- call printf
+ call printk
1: jmp 1b
/*** STACK LOCATION ***/
@@ -196,21 +196,16 @@ ENTRY(stack_start)
/*** DESCRIPTOR TABLES ***/
-.globl idt
-.globl gdt
-
ALIGN
.word 0
idt_descr:
.word 256*8-1
-idt:
.long idt_table
.word 0
gdt_descr:
.word LAST_RESERVED_GDT_BYTE
-gdt:
.long gdt_table - FIRST_RESERVED_GDT_BYTE
.word 0
@@ -218,28 +213,24 @@ nopaging_gdt_descr:
.word LAST_RESERVED_GDT_BYTE
.long gdt_table - FIRST_RESERVED_GDT_BYTE - __PAGE_OFFSET
- .org 0x1000
-/* NB. Rings != 0 get access up to 0xFC400000. This allows access to the */
-/* machine->physical mapping table. Ring 0 can access all memory. */
+ .align PAGE_SIZE, 0
+/* NB. Rings != 0 get access up to MACH2PHYS_VIRT_END. This allows access to */
+/* the machine->physical mapping table. Ring 0 can access all memory. */
+#define GUEST_DESC(d) \
+ .long ((MACH2PHYS_VIRT_END - 1) >> 12) & 0xffff, \
+ ((MACH2PHYS_VIRT_END - 1) >> 12) & (0xf << 16) | (d)
ENTRY(gdt_table)
.quad 0x0000000000000000 /* unused */
.quad 0x00cf9a000000ffff /* 0xe008 ring 0 4.00GB code at 0x0 */
.quad 0x00cf92000000ffff /* 0xe010 ring 0 4.00GB data at 0x0 */
-#ifdef CONFIG_X86_PAE
- .quad 0x00cfba00000067ff
- .quad 0x00cfb200000067ff
- .quad 0x00cffa00000067ff
- .quad 0x00cff200000067ff
-#else
- .quad 0x00cfba000000c3ff /* 0xe019 ring 1 3.95GB code at 0x0 */
- .quad 0x00cfb2000000c3ff /* 0xe021 ring 1 3.95GB data at 0x0 */
- .quad 0x00cffa000000c3ff /* 0xe02b ring 3 3.95GB code at 0x0 */
- .quad 0x00cff2000000c3ff /* 0xe033 ring 3 3.95GB data at 0x0 */
-#endif
+ GUEST_DESC(0x00c0ba00) /* 0xe019 ring 1 3.xxGB code at 0x0 */
+ GUEST_DESC(0x00c0b200) /* 0xe021 ring 1 3.xxGB data at 0x0 */
+ GUEST_DESC(0x00c0fa00) /* 0xe02b ring 3 3.xxGB code at 0x0 */
+ GUEST_DESC(0x00c0f200) /* 0xe033 ring 3 3.xxGB data at 0x0 */
.quad 0x0000000000000000 /* unused */
.fill 2*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
- .org 0x2000
+ .align PAGE_SIZE, 0
#ifdef CONFIG_X86_PAE
ENTRY(idle_pg_table)
diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S
index a7d0310b31..5a8a111b59 100644
--- a/xen/arch/x86/boot/x86_64.S
+++ b/xen/arch/x86/boot/x86_64.S
@@ -10,6 +10,8 @@
.text
.code32
+#define SYM_PHYS(sym) (sym - __PAGE_OFFSET)
+
ENTRY(start)
ENTRY(stext)
ENTRY(_stext)
@@ -24,15 +26,14 @@ ENTRY(_stext)
/* Checksum: must be the negated sum of the first two fields. */
.long -0x1BADB005
- .org 0x010
- .asciz "ERR: Not a 64-bit CPU!"
- .org 0x028
- .asciz "ERR: Not a Multiboot bootloader!"
+.Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!"
+.Lbad_ldr_msg: .asciz "ERR: Not a Multiboot bootloader!"
+
bad_cpu:
- mov $0x100010,%esi # Error message
+ mov $(SYM_PHYS(.Lbad_cpu_msg)),%esi # Error message
jmp print_err
not_multiboot:
- mov $0x100028,%esi # Error message
+ mov $(SYM_PHYS(.Lbad_ldr_msg)),%esi # Error message
print_err:
mov $0xB8000,%edi # VGA framebuffer
1: mov (%esi),%bl
@@ -55,7 +56,7 @@ __start:
cli
/* Set up a few descriptors: on entry only CS is guaranteed good. */
- lgdt %cs:0x100306 # nopaging_gdt_descr
+ lgdt %cs:SYM_PHYS(nopaging_gdt_descr)
mov $(__HYPERVISOR_DS32),%ecx
mov %ecx,%ds
mov %ecx,%es
@@ -68,7 +69,7 @@ __start:
jne not_multiboot
/* Save the Multiboot info structure for later use. */
- mov %ebx,0x100300 # multiboot_ptr
+ mov %ebx,SYM_PHYS(multiboot_ptr)
/* We begin by interrogating the CPU for the presence of long mode. */
mov $0x80000000,%eax
@@ -79,7 +80,7 @@ __start:
cpuid
bt $29,%edx # Long mode feature?
jnc bad_cpu
- mov %edx,0x100310 # cpuid_ext_features
+ mov %edx,SYM_PHYS(cpuid_ext_features)
skip_boot_checks:
/* Set up FPU. */
@@ -90,7 +91,7 @@ skip_boot_checks:
mov %ecx,%cr4
/* Load pagetable base register. */
- mov $0x102000,%eax /* idle_pg_table */
+ mov $SYM_PHYS(idle_pg_table),%eax
mov %eax,%cr3
/* Set up EFER (Extended Feature Enable Register). */
@@ -98,7 +99,7 @@ skip_boot_checks:
rdmsr
btsl $_EFER_LME,%eax /* Long Mode */
btsl $_EFER_SCE,%eax /* SYSCALL/SYSRET */
- mov 0x100310,%edi
+ mov SYM_PHYS(cpuid_ext_features),%edi
btl $20,%edi /* CPUID 0x80000001, EDX[20] */
jnc 1f
btsl $_EFER_NX,%eax /* No-Execute */
@@ -109,11 +110,10 @@ skip_boot_checks:
jmp 1f
1: /* Now in compatibility mode. Long-jump into 64-bit mode. */
- ljmp $(__HYPERVISOR_CS64),$0x100200
+ ljmp $(__HYPERVISOR_CS64),$SYM_PHYS(start64)
.code64
- .org 0x0200
-
+start64:
/* Install relocated selectors (FS/GS unused). */
lgdt gdt_descr(%rip)
@@ -186,39 +186,32 @@ ignore_int:
cld
leaq int_msg(%rip),%rdi
xorl %eax,%eax
- call printf
+ call printk
1: jmp 1b
/*** DESCRIPTOR TABLES ***/
-.globl idt
-.globl gdt
-
- .org 0x300
- .code32
-
-multiboot_ptr: /* 0x300 */
+ .align 8, 0xCC
+multiboot_ptr:
.long 0
.word 0
-nopaging_gdt_descr: /* 0x306 */
+nopaging_gdt_descr:
.word LAST_RESERVED_GDT_BYTE
.quad gdt_table - FIRST_RESERVED_GDT_BYTE - __PAGE_OFFSET
-cpuid_ext_features: /* 0x310 */
+cpuid_ext_features:
.long 0
.word 0
gdt_descr:
.word LAST_RESERVED_GDT_BYTE
-gdt:
.quad gdt_table - FIRST_RESERVED_GDT_BYTE
.word 0,0,0
idt_descr:
.word 256*16-1
-idt:
.quad idt_table
ENTRY(stack_start)
@@ -227,7 +220,7 @@ ENTRY(stack_start)
high_start:
.quad __high_start
- .org 0x1000
+ .align PAGE_SIZE, 0
ENTRY(gdt_table)
.quad 0x0000000000000000 /* unused */
.quad 0x00cf9a000000ffff /* 0xe008 ring 0 code, compatibility */
@@ -240,7 +233,7 @@ ENTRY(gdt_table)
.fill 4*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
/* Initial PML4 -- level-4 page table. */
- .org 0x2000
+ .align PAGE_SIZE, 0
ENTRY(idle_pg_table)
ENTRY(idle_pg_table_4)
.quad idle_pg_table_l3 - __PAGE_OFFSET + 7 # PML4[0]
@@ -248,12 +241,12 @@ ENTRY(idle_pg_table_4)
.quad idle_pg_table_l3 - __PAGE_OFFSET + 7 # PML4[262]
/* Initial PDP -- level-3 page table. */
- .org 0x3000
+ .align PAGE_SIZE, 0
ENTRY(idle_pg_table_l3)
.quad idle_pg_table_l2 - __PAGE_OFFSET + 7
/* Initial PDE -- level-2 page table. Maps first 1GB physical memory. */
- .org 0x4000
+ .align PAGE_SIZE, 0
ENTRY(idle_pg_table_l2)
.macro identmap from=0, count=512
.if \count-1
@@ -265,8 +258,7 @@ ENTRY(idle_pg_table_l2)
.endm
identmap
- .org 0x4000 + PAGE_SIZE
- .code64
+ .align PAGE_SIZE, 0
.section ".bss.stack_aligned","w"
ENTRY(cpu0_stack)
diff --git a/xen/arch/x86/cpu/mcheck/Makefile b/xen/arch/x86/cpu/mcheck/Makefile
index fbf8f0a177..a5cbb02b7b 100644
--- a/xen/arch/x86/cpu/mcheck/Makefile
+++ b/xen/arch/x86/cpu/mcheck/Makefile
@@ -2,6 +2,6 @@ obj-y += k7.o
obj-y += mce.o
obj-y += non-fatal.o
obj-y += p4.o
-obj-y += p5.o
-obj-y += p6.o
-obj-y += winchip.o
+obj-$(x86_32) += p5.o
+obj-$(x86_32) += p6.o
+obj-$(x86_32) += winchip.o
diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c
index 68a8ff59ed..4714eb3013 100644
--- a/xen/arch/x86/cpu/mcheck/mce.c
+++ b/xen/arch/x86/cpu/mcheck/mce.c
@@ -39,18 +39,22 @@ void mcheck_init(struct cpuinfo_x86 *c)
break;
case X86_VENDOR_INTEL:
+#ifndef CONFIG_X86_64
if (c->x86==5)
intel_p5_mcheck_init(c);
if (c->x86==6)
intel_p6_mcheck_init(c);
+#endif
if (c->x86==15)
intel_p4_mcheck_init(c);
break;
+#ifndef CONFIG_X86_64
case X86_VENDOR_CENTAUR:
if (c->x86==5)
winchip_mcheck_init(c);
break;
+#endif
default:
break;
diff --git a/xen/arch/x86/cpu/mtrr/Makefile b/xen/arch/x86/cpu/mtrr/Makefile
index 445138aa3c..213a7787af 100644
--- a/xen/arch/x86/cpu/mtrr/Makefile
+++ b/xen/arch/x86/cpu/mtrr/Makefile
@@ -1,6 +1,6 @@
-obj-y += amd.o
-obj-y += centaur.o
-obj-y += cyrix.o
+obj-$(x86_32) += amd.o
+obj-$(x86_32) += centaur.o
+obj-$(x86_32) += cyrix.o
obj-y += generic.o
obj-y += main.o
obj-y += state.o
diff --git a/xen/arch/x86/cpu/mtrr/main.c b/xen/arch/x86/cpu/mtrr/main.c
index 5684d40c89..72cab7be1b 100644
--- a/xen/arch/x86/cpu/mtrr/main.c
+++ b/xen/arch/x86/cpu/mtrr/main.c
@@ -64,7 +64,11 @@ struct mtrr_ops * mtrr_if = NULL;
static void set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type);
+#ifndef CONFIG_X86_64
extern int arr3_protected;
+#else
+#define arr3_protected 0
+#endif
static char *mtrr_strings[MTRR_NUM_TYPES] =
{
@@ -539,9 +543,11 @@ extern void centaur_init_mtrr(void);
static void __init init_ifs(void)
{
+#ifndef CONFIG_X86_64
amd_init_mtrr();
cyrix_init_mtrr();
centaur_init_mtrr();
+#endif
}
/* The suspend/resume methods are only for CPU without MTRR. CPU using generic
@@ -593,6 +599,7 @@ void __init mtrr_bp_init(void)
size_and_mask = 0;
}
} else {
+#ifndef CONFIG_X86_64
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
if (cpu_has_k6_mtrr) {
@@ -619,6 +626,7 @@ void __init mtrr_bp_init(void)
default:
break;
}
+#endif
}
if (mtrr_if) {
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 7acb3b7cea..75d5284aeb 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -114,53 +114,69 @@ void dump_pageframe_info(struct domain *d)
}
}
-struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id)
+struct vcpu *alloc_vcpu_struct(void)
{
struct vcpu *v;
+ if ( (v = xmalloc(struct vcpu)) != NULL )
+ memset(v, 0, sizeof(*v));
+ return v;
+}
- if ( (v = xmalloc(struct vcpu)) == NULL )
- return NULL;
+void free_vcpu_struct(struct vcpu *v)
+{
+ xfree(v);
+}
- memset(v, 0, sizeof(*v));
+int vcpu_initialise(struct vcpu *v)
+{
+ struct domain *d = v->domain;
+ int rc;
v->arch.flags = TF_kernel_mode;
- if ( is_idle_domain(d) )
+ if ( is_hvm_domain(d) )
{
- v->arch.schedule_tail = continue_idle_domain;
- v->arch.cr3 = __pa(idle_pg_table);
+ if ( (rc = hvm_vcpu_initialise(v)) != 0 )
+ return rc;
}
else
{
v->arch.schedule_tail = continue_nonidle_domain;
- }
+ v->arch.ctxt_switch_from = paravirt_ctxt_switch_from;
+ v->arch.ctxt_switch_to = paravirt_ctxt_switch_to;
- v->arch.ctxt_switch_from = paravirt_ctxt_switch_from;
- v->arch.ctxt_switch_to = paravirt_ctxt_switch_to;
+ if ( is_idle_domain(d) )
+ {
+ v->arch.schedule_tail = continue_idle_domain;
+ v->arch.cr3 = __pa(idle_pg_table);
+ }
+ }
v->arch.perdomain_ptes =
- d->arch.mm_perdomain_pt + (vcpu_id << GDT_LDT_VCPU_SHIFT);
+ d->arch.mm_perdomain_pt + (v->vcpu_id << GDT_LDT_VCPU_SHIFT);
pae_l3_cache_init(&v->arch.pae_l3_cache);
- return v;
+ return 0;
}
-void free_vcpu_struct(struct vcpu *v)
+void vcpu_destroy(struct vcpu *v)
{
- xfree(v);
}
int arch_domain_create(struct domain *d)
{
+#ifdef __x86_64__
+ struct page_info *pg;
+#endif
l1_pgentry_t gdt_l1e;
int vcpuid, pdpt_order;
- int i;
+ int i, rc = -ENOMEM;
pdpt_order = get_order_from_bytes(PDPT_L1_ENTRIES * sizeof(l1_pgentry_t));
d->arch.mm_perdomain_pt = alloc_xenheap_pages(pdpt_order);
if ( d->arch.mm_perdomain_pt == NULL )
- goto fail_nomem;
+ goto fail;
memset(d->arch.mm_perdomain_pt, 0, PAGE_SIZE << pdpt_order);
/*
@@ -181,19 +197,17 @@ int arch_domain_create(struct domain *d)
#else /* __x86_64__ */
- d->arch.mm_perdomain_l2 = alloc_xenheap_page();
- d->arch.mm_perdomain_l3 = alloc_xenheap_page();
- if ( (d->arch.mm_perdomain_l2 == NULL) ||
- (d->arch.mm_perdomain_l3 == NULL) )
- goto fail_nomem;
-
- memset(d->arch.mm_perdomain_l2, 0, PAGE_SIZE);
+ if ( (pg = alloc_domheap_page(NULL)) == NULL )
+ goto fail;
+ d->arch.mm_perdomain_l2 = clear_page(page_to_virt(pg));
for ( i = 0; i < (1 << pdpt_order); i++ )
d->arch.mm_perdomain_l2[l2_table_offset(PERDOMAIN_VIRT_START)+i] =
l2e_from_page(virt_to_page(d->arch.mm_perdomain_pt)+i,
__PAGE_HYPERVISOR);
- memset(d->arch.mm_perdomain_l3, 0, PAGE_SIZE);
+ if ( (pg = alloc_domheap_page(NULL)) == NULL )
+ goto fail;
+ d->arch.mm_perdomain_l3 = clear_page(page_to_virt(pg));
d->arch.mm_perdomain_l3[l3_table_offset(PERDOMAIN_VIRT_START)] =
l3e_from_page(virt_to_page(d->arch.mm_perdomain_l2),
__PAGE_HYPERVISOR);
@@ -205,37 +219,46 @@ int arch_domain_create(struct domain *d)
INIT_LIST_HEAD(&d->arch.shadow.freelists[i]);
INIT_LIST_HEAD(&d->arch.shadow.p2m_freelist);
INIT_LIST_HEAD(&d->arch.shadow.p2m_inuse);
- INIT_LIST_HEAD(&d->arch.shadow.toplevel_shadows);
+ INIT_LIST_HEAD(&d->arch.shadow.pinned_shadows);
if ( !is_idle_domain(d) )
{
d->arch.ioport_caps =
rangeset_new(d, "I/O Ports", RANGESETF_prettyprint_hex);
if ( d->arch.ioport_caps == NULL )
- goto fail_nomem;
+ goto fail;
if ( (d->shared_info = alloc_xenheap_page()) == NULL )
- goto fail_nomem;
+ goto fail;
memset(d->shared_info, 0, PAGE_SIZE);
share_xen_page_with_guest(
virt_to_page(d->shared_info), d, XENSHARE_writable);
}
- return 0;
+ return is_hvm_domain(d) ? hvm_domain_initialise(d) : 0;
- fail_nomem:
+ fail:
free_xenheap_page(d->shared_info);
#ifdef __x86_64__
- free_xenheap_page(d->arch.mm_perdomain_l2);
- free_xenheap_page(d->arch.mm_perdomain_l3);
+ free_domheap_page(virt_to_page(d->arch.mm_perdomain_l2));
+ free_domheap_page(virt_to_page(d->arch.mm_perdomain_l3));
#endif
free_xenheap_pages(d->arch.mm_perdomain_pt, pdpt_order);
- return -ENOMEM;
+ return rc;
}
void arch_domain_destroy(struct domain *d)
{
+ struct vcpu *v;
+
+ if ( is_hvm_domain(d) )
+ {
+ for_each_vcpu ( d, v )
+ hvm_vcpu_destroy(v);
+ hvm_domain_destroy(d);
+ }
+
shadow_final_teardown(d);
free_xenheap_pages(
@@ -243,8 +266,8 @@ void arch_domain_destroy(struct domain *d)
get_order_from_bytes(PDPT_L1_ENTRIES * sizeof(l1_pgentry_t)));
#ifdef __x86_64__
- free_xenheap_page(d->arch.mm_perdomain_l2);
- free_xenheap_page(d->arch.mm_perdomain_l3);
+ free_domheap_page(virt_to_page(d->arch.mm_perdomain_l2));
+ free_domheap_page(virt_to_page(d->arch.mm_perdomain_l3));
#endif
free_xenheap_page(d->shared_info);
@@ -258,7 +281,7 @@ int arch_set_info_guest(
unsigned long cr3_pfn = INVALID_MFN;
int i, rc;
- if ( !(c->flags & VGCF_HVM_GUEST) )
+ if ( !is_hvm_vcpu(v) )
{
fixup_guest_stack_selector(c->user_regs.ss);
fixup_guest_stack_selector(c->kernel_ss);
@@ -271,16 +294,20 @@ int arch_set_info_guest(
for ( i = 0; i < 256; i++ )
fixup_guest_code_selector(c->trap_ctxt[i].cs);
+
+ /* LDT safety checks. */
+ if ( ((c->ldt_base & (PAGE_SIZE-1)) != 0) ||
+ (c->ldt_ents > 8192) ||
+ !array_access_ok(c->ldt_base, c->ldt_ents, LDT_ENTRY_SIZE) )
+ return -EINVAL;
}
- else if ( !hvm_enabled )
- return -EINVAL;
clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
- if ( c->flags & VGCF_I387_VALID )
+ if ( c->flags & VGCF_i387_valid )
set_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
v->arch.flags &= ~TF_kernel_mode;
- if ( (c->flags & VGCF_IN_KERNEL) || (c->flags & VGCF_HVM_GUEST) )
+ if ( (c->flags & VGCF_in_kernel) || is_hvm_vcpu(v)/*???*/ )
v->arch.flags |= TF_kernel_mode;
memcpy(&v->arch.guest_context, c, sizeof(*c));
@@ -291,7 +318,7 @@ int arch_set_info_guest(
init_int80_direct_trap(v);
- if ( !(c->flags & VGCF_HVM_GUEST) )
+ if ( !is_hvm_vcpu(v) )
{
/* IOPL privileges are virtualised. */
v->arch.iopl = (v->arch.guest_context.user_regs.eflags >> 12) & 3;
@@ -300,7 +327,7 @@ int arch_set_info_guest(
/* Ensure real hardware interrupts are enabled. */
v->arch.guest_context.user_regs.eflags |= EF_IE;
}
- else if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
+ else
{
hvm_load_cpu_guest_regs(v, &v->arch.guest_context.user_regs);
}
@@ -316,30 +343,23 @@ int arch_set_info_guest(
if ( v->vcpu_id == 0 )
d->vm_assist = c->vm_assist;
- if ( !(c->flags & VGCF_HVM_GUEST) )
+ if ( !is_hvm_vcpu(v) )
{
- cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
- v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
- }
+ if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 )
+ return rc;
- if ( (rc = (int)set_gdt(v, c->gdt_frames, c->gdt_ents)) != 0 )
- return rc;
-
- if ( c->flags & VGCF_HVM_GUEST )
- {
- v->arch.guest_table = pagetable_null();
+ cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c->ctrlreg[3]));
- if ( !hvm_initialize_guest_resources(v) )
- return -EINVAL;
- }
- else
- {
- if ( !get_page_and_type(mfn_to_page(cr3_pfn), d,
- PGT_base_page_table) )
+ if ( shadow_mode_refcounts(d)
+ ? !get_page(mfn_to_page(cr3_pfn), d)
+ : !get_page_and_type(mfn_to_page(cr3_pfn), d,
+ PGT_base_page_table) )
{
destroy_gdt(v);
return -EINVAL;
}
+
+ v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
}
/* Shadow: make sure the domain has enough shadow memory to
@@ -376,20 +396,27 @@ arch_do_vcpu_op(
case VCPUOP_register_runstate_memory_area:
{
struct vcpu_register_runstate_memory_area area;
+ struct vcpu_runstate_info runstate;
rc = -EFAULT;
if ( copy_from_guest(&area, arg, 1) )
break;
- if ( !access_ok(area.addr.v, sizeof(*area.addr.v)) )
+ if ( !guest_handle_okay(area.addr.h, 1) )
break;
rc = 0;
- v->runstate_guest = area.addr.v;
+ v->runstate_guest = area.addr.h;
if ( v == current )
- __copy_to_user(v->runstate_guest, &v->runstate,
- sizeof(v->runstate));
+ {
+ __copy_to_guest(v->runstate_guest, &v->runstate, 1);
+ }
+ else
+ {
+ vcpu_runstate_get(v, &runstate);
+ __copy_to_guest(v->runstate_guest, &runstate, 1);
+ }
break;
}
@@ -402,33 +429,6 @@ arch_do_vcpu_op(
return rc;
}
-void new_thread(struct vcpu *d,
- unsigned long start_pc,
- unsigned long start_stack,
- unsigned long start_info)
-{
- struct cpu_user_regs *regs = &d->arch.guest_context.user_regs;
-
- /*
- * Initial register values:
- * DS,ES,FS,GS = FLAT_KERNEL_DS
- * CS:EIP = FLAT_KERNEL_CS:start_pc
- * SS:ESP = FLAT_KERNEL_SS:start_stack
- * ESI = start_info
- * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
- */
- regs->ds = regs->es = regs->fs = regs->gs = FLAT_KERNEL_DS;
- regs->ss = FLAT_KERNEL_SS;
- regs->cs = FLAT_KERNEL_CS;
- regs->eip = start_pc;
- regs->esp = start_stack;
- regs->esi = start_info;
-
- __save_flags(regs->eflags);
- regs->eflags |= X86_EFLAGS_IF;
-}
-
-
#ifdef __x86_64__
#define loadsegment(seg,value) ({ \
@@ -554,7 +554,8 @@ static void load_segments(struct vcpu *n)
put_user(regs->r11, rsp-10) |
put_user(regs->rcx, rsp-11) )
{
- DPRINTK("Error while creating failsafe callback frame.\n");
+ gdprintk(XENLOG_ERR, "Error while creating failsafe "
+ "callback frame.\n");
domain_crash(n->domain);
}
@@ -565,9 +566,9 @@ static void load_segments(struct vcpu *n)
regs->entry_vector = TRAP_syscall;
regs->rflags &= ~(X86_EFLAGS_AC|X86_EFLAGS_VM|X86_EFLAGS_RF|
X86_EFLAGS_NT|X86_EFLAGS_TF);
- regs->ss = __GUEST_SS;
+ regs->ss = FLAT_KERNEL_SS;
regs->rsp = (unsigned long)(rsp-11);
- regs->cs = __GUEST_CS;
+ regs->cs = FLAT_KERNEL_CS;
regs->rip = nctxt->failsafe_callback_eip;
}
}
@@ -734,7 +735,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
/* Re-enable interrupts before restoring state which may fault. */
local_irq_enable();
- if ( !hvm_guest(next) )
+ if ( !is_hvm_vcpu(next) )
{
load_LDT(next);
load_segments(next);
@@ -744,9 +745,8 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
context_saved(prev);
/* Update per-VCPU guest runstate shared memory area (if registered). */
- if ( next->runstate_guest != NULL )
- __copy_to_user(next->runstate_guest, &next->runstate,
- sizeof(next->runstate));
+ if ( !guest_handle_is_null(next->runstate_guest) )
+ __copy_to_guest(next->runstate_guest, &next->runstate, 1);
schedule_tail(next);
BUG();
@@ -824,7 +824,7 @@ unsigned long hypercall_create_continuation(
#if defined(__i386__)
regs->eax = op;
- if ( supervisor_mode_kernel || hvm_guest(current) )
+ if ( supervisor_mode_kernel || is_hvm_vcpu(current) )
regs->eip &= ~31; /* re-execute entire hypercall entry stub */
else
regs->eip -= 2; /* re-execute 'int 0x82' */
@@ -952,15 +952,15 @@ void domain_relinquish_resources(struct domain *d)
pfn = pagetable_get_pfn(v->arch.guest_table_user);
if ( pfn != 0 )
{
- put_page_and_type(mfn_to_page(pfn));
+ if ( shadow_mode_refcounts(d) )
+ put_page(mfn_to_page(pfn));
+ else
+ put_page_and_type(mfn_to_page(pfn));
v->arch.guest_table_user = pagetable_null();
}
#endif
}
- if ( d->vcpu[0] && hvm_guest(d->vcpu[0]) )
- hvm_relinquish_guest_resources(d);
-
/* Tear down shadow mode stuff. */
shadow_teardown(d);
@@ -998,6 +998,20 @@ void arch_dump_domain_info(struct domain *d)
}
}
+void arch_dump_vcpu_info(struct vcpu *v)
+{
+ if ( shadow_mode_enabled(v->domain) )
+ {
+ if ( v->arch.shadow.mode )
+ printk(" shadowed %u-on-%u, %stranslated\n",
+ v->arch.shadow.mode->guest_levels,
+ v->arch.shadow.mode->shadow_levels,
+ shadow_vcpu_mode_translate(v) ? "" : "not ");
+ else
+ printk(" not shadowed\n");
+ }
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c
index dd44e827f4..bb597b2a50 100644
--- a/xen/arch/x86/domain_build.c
+++ b/xen/arch/x86/domain_build.c
@@ -33,28 +33,45 @@
extern unsigned long initial_images_nrpages(void);
extern void discard_initial_images(void);
-static long dom0_nrpages;
+static long dom0_nrpages, dom0_min_nrpages, dom0_max_nrpages = LONG_MAX;
/*
- * dom0_mem:
- * If +ve:
- * * The specified amount of memory is allocated to domain 0.
- * If -ve:
- * * All of memory is allocated to domain 0, minus the specified amount.
- * If not specified:
- * * All of memory is allocated to domain 0, minus 1/16th which is reserved
- * for uses such as DMA buffers (the reservation is clamped to 128MB).
+ * dom0_mem=[min:<min_amt>,][max:<max_amt>,][<amt>]
+ *
+ * <min_amt>: The minimum amount of memory which should be allocated for dom0.
+ * <max_amt>: The maximum amount of memory which should be allocated for dom0.
+ * <amt>: The precise amount of memory to allocate for dom0.
+ *
+ * Notes:
+ * 1. <amt> is clamped from below by <min_amt> and from above by available
+ * memory and <max_amt>
+ * 2. <min_amt> is clamped from above by available memory and <max_amt>
+ * 3. <min_amt> is ignored if it is greater than <max_amt>
+ * 4. If <amt> is not specified, it is calculated as follows:
+ * "All of memory is allocated to domain 0, minus 1/16th which is reserved
+ * for uses such as DMA buffers (the reservation is clamped to 128MB)."
+ *
+ * Each value can be specified as positive or negative:
+ * If +ve: The specified amount is an absolute value.
+ * If -ve: The specified amount is subtracted from total available memory.
*/
+static long parse_amt(char *s, char **ps)
+{
+ long pages = parse_size_and_unit((*s == '-') ? s+1 : s, ps) >> PAGE_SHIFT;
+ return (*s == '-') ? -pages : pages;
+}
static void parse_dom0_mem(char *s)
{
- unsigned long long bytes;
- char *t = s;
- if ( *s == '-' )
- t++;
- bytes = parse_size_and_unit(t);
- dom0_nrpages = bytes >> PAGE_SHIFT;
- if ( *s == '-' )
- dom0_nrpages = -dom0_nrpages;
+ do {
+ if ( !strncmp(s, "min:", 4) )
+ dom0_min_nrpages = parse_amt(s+4, &s);
+ else if ( !strncmp(s, "max:", 4) )
+ dom0_max_nrpages = parse_amt(s+4, &s);
+ else
+ dom0_nrpages = parse_amt(s, &s);
+ if ( *s != ',' )
+ break;
+ } while ( *s++ == ',' );
}
custom_param("dom0_mem", parse_dom0_mem);
@@ -74,10 +91,11 @@ string_param("dom0_ioports_disable", opt_dom0_ioports_disable);
#define L3_PROT (_PAGE_PRESENT)
#elif defined(__x86_64__)
/* Allow ring-3 access in long mode as guest cannot use ring 1. */
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define BASE_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#define L1_PROT (BASE_PROT|_PAGE_GUEST_KERNEL)
+#define L2_PROT (BASE_PROT|_PAGE_DIRTY)
+#define L3_PROT (BASE_PROT|_PAGE_DIRTY)
+#define L4_PROT (BASE_PROT|_PAGE_DIRTY)
#endif
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
@@ -102,6 +120,35 @@ static struct page_info *alloc_chunk(struct domain *d, unsigned long max_pages)
return page;
}
+static unsigned long compute_dom0_nr_pages(void)
+{
+ unsigned long avail = avail_domheap_pages() + initial_images_nrpages();
+
+ /*
+ * If domain 0 allocation isn't specified, reserve 1/16th of available
+ * memory for things like DMA buffers. This reservation is clamped to
+ * a maximum of 128MB.
+ */
+ if ( dom0_nrpages == 0 )
+ {
+ dom0_nrpages = avail;
+ dom0_nrpages = min(dom0_nrpages / 16, 128L << (20 - PAGE_SHIFT));
+ dom0_nrpages = -dom0_nrpages;
+ }
+
+ /* Negative memory specification means "all memory - specified amount". */
+ if ( dom0_nrpages < 0 ) dom0_nrpages += avail;
+ if ( dom0_min_nrpages < 0 ) dom0_min_nrpages += avail;
+ if ( dom0_max_nrpages < 0 ) dom0_max_nrpages += avail;
+
+ /* Clamp dom0 memory according to min/max limits and available memory. */
+ dom0_nrpages = max(dom0_nrpages, dom0_min_nrpages);
+ dom0_nrpages = min(dom0_nrpages, dom0_max_nrpages);
+ dom0_nrpages = min(dom0_nrpages, (long)avail);
+
+ return dom0_nrpages;
+}
+
static void process_dom0_ioports_disable(void)
{
unsigned long io_from, io_to;
@@ -202,6 +249,7 @@ int construct_dom0(struct domain *d,
char *cmdline)
{
int i, rc, dom0_pae, xen_pae, order;
+ struct cpu_user_regs *regs;
unsigned long pfn, mfn;
unsigned long nr_pages;
unsigned long nr_pt_pages;
@@ -268,24 +316,7 @@ int construct_dom0(struct domain *d,
d->max_pages = ~0U;
- /*
- * If domain 0 allocation isn't specified, reserve 1/16th of available
- * memory for things like DMA buffers. This reservation is clamped to
- * a maximum of 128MB.
- */
- if ( dom0_nrpages == 0 )
- {
- dom0_nrpages = avail_domheap_pages() + initial_images_nrpages();
- dom0_nrpages = min(dom0_nrpages / 16, 128L << (20 - PAGE_SHIFT));
- dom0_nrpages = -dom0_nrpages;
- }
-
- /* Negative memory specification means "all memory - specified amount". */
- if ( dom0_nrpages < 0 )
- nr_pages = avail_domheap_pages() + initial_images_nrpages() +
- dom0_nrpages;
- else
- nr_pages = dom0_nrpages;
+ nr_pages = compute_dom0_nr_pages();
if ( (rc = parseelfimage(&dsi)) != 0 )
return rc;
@@ -400,30 +431,18 @@ int construct_dom0(struct domain *d,
_p(dsi.v_start), _p(v_end));
printk(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry));
- if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
+ if ( ((v_end - dsi.v_start)>>PAGE_SHIFT) > nr_pages )
{
printk("Initial guest OS requires too much space\n"
"(%luMB is greater than %luMB limit)\n",
- (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+ (v_end-dsi.v_start)>>20, nr_pages>>(20-PAGE_SHIFT));
return -ENOMEM;
}
mpt_alloc = (vpt_start - dsi.v_start) +
(unsigned long)pfn_to_paddr(alloc_spfn);
- /*
- * We're basically forcing default RPLs to 1, so that our "what privilege
- * level are we returning to?" logic works.
- */
- v->arch.guest_context.kernel_ss = FLAT_KERNEL_SS;
- for ( i = 0; i < 256; i++ )
- v->arch.guest_context.trap_ctxt[i].cs = FLAT_KERNEL_CS;
-
#if defined(__i386__)
-
- v->arch.guest_context.failsafe_callback_cs = FLAT_KERNEL_CS;
- v->arch.guest_context.event_callback_cs = FLAT_KERNEL_CS;
-
/*
* Protect the lowest 1GB of memory. We use a temporary mapping there
* from which we copy the kernel and ramdisk images.
@@ -510,15 +529,13 @@ int construct_dom0(struct domain *d,
case 1 ... 4:
page->u.inuse.type_info &= ~PGT_type_mask;
page->u.inuse.type_info |= PGT_l2_page_table;
- page->u.inuse.type_info |=
- (count-1) << PGT_va_shift;
+ if ( count == 4 )
+ page->u.inuse.type_info |= PGT_pae_xen_l2;
get_page(page, d); /* an extra ref because of readable mapping */
break;
default:
page->u.inuse.type_info &= ~PGT_type_mask;
page->u.inuse.type_info |= PGT_l1_page_table;
- page->u.inuse.type_info |=
- ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-5))<<PGT_va_shift;
get_page(page, d); /* an extra ref because of readable mapping */
break;
}
@@ -544,8 +561,6 @@ int construct_dom0(struct domain *d,
{
page->u.inuse.type_info &= ~PGT_type_mask;
page->u.inuse.type_info |= PGT_l1_page_table;
- page->u.inuse.type_info |=
- ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-1))<<PGT_va_shift;
/*
* No longer writable: decrement the type_count.
@@ -671,6 +686,8 @@ int construct_dom0(struct domain *d,
if ( opt_dom0_max_vcpus == 0 )
opt_dom0_max_vcpus = num_online_cpus();
+ if ( opt_dom0_max_vcpus > num_online_cpus() )
+ opt_dom0_max_vcpus = num_online_cpus();
if ( opt_dom0_max_vcpus > MAX_VIRT_CPUS )
opt_dom0_max_vcpus = MAX_VIRT_CPUS;
printk("Dom0 has maximum %u VCPUs\n", opt_dom0_max_vcpus);
@@ -788,7 +805,22 @@ int construct_dom0(struct domain *d,
set_bit(_VCPUF_initialised, &v->vcpu_flags);
- new_thread(v, dsi.v_kernentry, vstack_end, vstartinfo_start);
+ /*
+ * Initial register values:
+ * DS,ES,FS,GS = FLAT_KERNEL_DS
+ * CS:EIP = FLAT_KERNEL_CS:start_pc
+ * SS:ESP = FLAT_KERNEL_SS:start_stack
+ * ESI = start_info
+ * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
+ */
+ regs = &v->arch.guest_context.user_regs;
+ regs->ds = regs->es = regs->fs = regs->gs = FLAT_KERNEL_DS;
+ regs->ss = FLAT_KERNEL_SS;
+ regs->cs = FLAT_KERNEL_CS;
+ regs->eip = dsi.v_kernentry;
+ regs->esp = vstack_end;
+ regs->esi = vstartinfo_start;
+ regs->eflags = X86_EFLAGS_IF;
if ( opt_dom0_shadow )
if ( shadow_test_enable(d) == 0 )
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 912a7c4252..d78e3b18ce 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -22,6 +22,7 @@
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
#include <asm/processor.h>
+#include <public/hvm/e820.h>
long arch_do_domctl(
struct xen_domctl *domctl,
@@ -222,6 +223,7 @@ long arch_do_domctl(
ret = 0;
spin_lock(&d->page_alloc_lock);
+
list_ent = d->page_list.next;
for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
{
@@ -235,6 +237,7 @@ long arch_do_domctl(
}
list_ent = mfn_to_page(mfn)->list.next;
}
+
spin_unlock(&d->page_alloc_lock);
domctl->u.getmemlist.num_pfns = i;
@@ -291,7 +294,7 @@ void arch_getdomaininfo_ctxt(
{
memcpy(c, &v->arch.guest_context, sizeof(*c));
- if ( hvm_guest(v) )
+ if ( is_hvm_vcpu(v) )
{
hvm_store_cpu_guest_regs(v, &c->user_regs, c->ctrlreg);
}
@@ -304,11 +307,9 @@ void arch_getdomaininfo_ctxt(
c->flags = 0;
if ( test_bit(_VCPUF_fpu_initialised, &v->vcpu_flags) )
- c->flags |= VGCF_I387_VALID;
+ c->flags |= VGCF_i387_valid;
if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
- c->flags |= VGCF_IN_KERNEL;
- if ( hvm_guest(v) )
- c->flags |= VGCF_HVM_GUEST;
+ c->flags |= VGCF_in_kernel;
c->ctrlreg[3] = xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table));
diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c
index bbc147139c..b12eb68c87 100644
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -6,7 +6,7 @@
/* opt_mem: Limit of physical RAM. Any RAM beyond this point is ignored. */
unsigned long long opt_mem;
-static void parse_mem(char *s) { opt_mem = parse_size_and_unit(s); }
+static void parse_mem(char *s) { opt_mem = parse_size_and_unit(s, NULL); }
custom_param("mem", parse_mem);
struct e820map e820;
diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c
index 053c767b39..c578c835f4 100644
--- a/xen/arch/x86/extable.c
+++ b/xen/arch/x86/extable.c
@@ -74,7 +74,7 @@ search_pre_exception_table(struct cpu_user_regs *regs)
unsigned long addr = (unsigned long)regs->eip;
unsigned long fixup = search_one_table(
__start___pre_ex_table, __stop___pre_ex_table-1, addr);
- DPRINTK("Pre-exception: %p -> %p\n", _p(addr), _p(fixup));
+ dprintk(XENLOG_INFO, "Pre-exception: %p -> %p\n", _p(addr), _p(fixup));
#ifdef PERF_COUNTERS
if ( fixup )
perfc_incrc(exception_fixed);
diff --git a/xen/arch/x86/flushtlb.c b/xen/arch/x86/flushtlb.c
index e3415dd3dd..fc3f1f3a4a 100644
--- a/xen/arch/x86/flushtlb.c
+++ b/xen/arch/x86/flushtlb.c
@@ -4,13 +4,14 @@
* TLB flushes are timestamped using a global virtual 'clock' which ticks
* on any TLB flush on any processor.
*
- * Copyright (c) 2003-2004, K A Fraser
+ * Copyright (c) 2003-2006, K A Fraser
*/
#include <xen/config.h>
#include <xen/sched.h>
#include <xen/softirq.h>
#include <asm/flushtlb.h>
+#include <asm/page.h>
/* Debug builds: Wrap frequently to stress-test the wrap logic. */
#ifdef NDEBUG
@@ -22,21 +23,17 @@
u32 tlbflush_clock = 1U;
DEFINE_PER_CPU(u32, tlbflush_time);
-void write_cr3(unsigned long cr3)
+/*
+ * pre_flush(): Increment the virtual TLB-flush clock. Returns new clock value.
+ *
+ * This must happen *before* we flush the TLB. If we do it after, we race other
+ * CPUs invalidating PTEs. For example, a page invalidated after the flush
+ * might get the old timestamp, but this CPU can speculatively fetch the
+ * mapping into its TLB after the flush but before inc'ing the clock.
+ */
+static u32 pre_flush(void)
{
u32 t, t1, t2;
- unsigned long flags;
-
- /* This non-reentrant function is sometimes called in interrupt context. */
- local_irq_save(flags);
-
- /*
- * STEP 1. Increment the virtual clock *before* flushing the TLB.
- * If we do it after, we race other CPUs invalidating PTEs.
- * (e.g., a page invalidated after the flush might get the old
- * timestamp, but this CPU can speculatively fetch the mapping
- * into its TLB after the flush but before inc'ing the clock).
- */
t = tlbflush_clock;
do {
@@ -52,26 +49,68 @@ void write_cr3(unsigned long cr3)
if ( unlikely(t2 == 0) )
raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ);
- /*
- * STEP 2. Update %CR3, thereby flushing the TLB.
- */
-
skip_clocktick:
+ return t2;
+}
+
+/*
+ * post_flush(): Update this CPU's timestamp with specified clock value.
+ *
+ * Note that this happens *after* flushing the TLB, as otherwise we can race a
+ * NEED_FLUSH() test on another CPU. (e.g., other CPU sees the updated CPU
+ * stamp and so does not force a synchronous TLB flush, but the flush in this
+ * function hasn't yet occurred and so the TLB might be stale). The ordering
+ * would only actually matter if this function were interruptible, and
+ * something that abuses the stale mapping could exist in an interrupt
+ * handler. In fact neither of these is the case, so really we are being ultra
+ * paranoid.
+ */
+static void post_flush(u32 t)
+{
+ this_cpu(tlbflush_time) = t;
+}
+
+void write_cr3(unsigned long cr3)
+{
+ unsigned long flags;
+ u32 t;
+
+ /* This non-reentrant function is sometimes called in interrupt context. */
+ local_irq_save(flags);
+
+ t = pre_flush();
+
+#ifdef USER_MAPPINGS_ARE_GLOBAL
+ __pge_off();
+ __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
+ __pge_on();
+#else
__asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
+#endif
+
+ post_flush(t);
+
+ local_irq_restore(flags);
+}
+
+void local_flush_tlb(void)
+{
+ unsigned long flags;
+ u32 t;
+
+ /* This non-reentrant function is sometimes called in interrupt context. */
+ local_irq_save(flags);
+
+ t = pre_flush();
+
+#ifdef USER_MAPPINGS_ARE_GLOBAL
+ __pge_off();
+ __pge_on();
+#else
+ __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (read_cr3()) : "memory" );
+#endif
- /*
- * STEP 3. Update this CPU's timestamp. Note that this happens *after*
- * flushing the TLB, as otherwise we can race a NEED_FLUSH() test
- * on another CPU. (e.g., other CPU sees the updated CPU stamp and
- * so does not force a synchronous TLB flush, but the flush in this
- * function hasn't yet occurred and so the TLB might be stale).
- * The ordering would only actually matter if this function were
- * interruptible, and something that abuses the stale mapping could
- * exist in an interrupt handler. In fact neither of these is the
- * case, so really we are being ultra paranoid.
- */
-
- this_cpu(tlbflush_time) = t2;
+ post_flush(t);
local_irq_restore(flags);
}
diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
index bc2cc1bf18..a4aef978af 100644
--- a/xen/arch/x86/hvm/Makefile
+++ b/xen/arch/x86/hvm/Makefile
@@ -3,9 +3,13 @@ subdir-y += vmx
obj-y += hvm.o
obj-y += i8254.o
-obj-y += i8259.o
+obj-y += instrlen.o
obj-y += intercept.o
obj-y += io.o
+obj-y += irq.o
obj-y += platform.o
+obj-y += pmtimer.o
+obj-y += rtc.o
obj-y += vioapic.o
obj-y += vlapic.o
+obj-y += vpic.o
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 0a7aa015d4..463d207fea 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -40,8 +40,10 @@
#include <asm/processor.h>
#include <asm/types.h>
#include <asm/msr.h>
+#include <asm/mc146818rtc.h>
#include <asm/spinlock.h>
#include <asm/hvm/hvm.h>
+#include <asm/hvm/vpt.h>
#include <asm/hvm/support.h>
#include <public/sched.h>
#include <public/hvm/ioreq.h>
@@ -55,374 +57,350 @@ integer_param("hvm_debug", opt_hvm_debug_level);
struct hvm_function_table hvm_funcs;
-static void hvm_zap_mmio_range(
- struct domain *d, unsigned long pfn, unsigned long nr_pfn)
-{
- unsigned long i;
-
- ASSERT(d == current->domain);
-
- for ( i = 0; i < nr_pfn; i++ )
- {
- if ( pfn + i >= 0xfffff )
- break;
-
- if ( VALID_MFN(gmfn_to_mfn(d, pfn + i)) )
- guest_remove_page(d, pfn + i);
- }
-}
-
-static void e820_zap_iommu_callback(struct domain *d,
- struct e820entry *e,
- void *ign)
+void hvm_stts(struct vcpu *v)
{
- if ( e->type == E820_IO )
- hvm_zap_mmio_range(d, e->addr >> PAGE_SHIFT, e->size >> PAGE_SHIFT);
+ /* FPU state already dirty? Then no need to setup_fpu() lazily. */
+ if ( !test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
+ hvm_funcs.stts(v);
}
-static void e820_foreach(struct domain *d,
- void (*cb)(struct domain *d,
- struct e820entry *e,
- void *data),
- void *data)
+void hvm_set_guest_time(struct vcpu *v, u64 gtime)
{
- int i;
- unsigned char e820_map_nr;
- struct e820entry *e820entry;
- unsigned char *p;
- unsigned long mfn;
-
- mfn = gmfn_to_mfn(d, E820_MAP_PAGE >> PAGE_SHIFT);
- if ( mfn == INVALID_MFN )
- {
- printk("Can not find E820 memory map page for HVM domain.\n");
- domain_crash_synchronous();
- }
-
- p = map_domain_page(mfn);
- if ( p == NULL )
- {
- printk("Can not map E820 memory map page for HVM domain.\n");
- domain_crash_synchronous();
- }
-
- e820_map_nr = *(p + E820_MAP_NR_OFFSET);
- e820entry = (struct e820entry *)(p + E820_MAP_OFFSET);
-
- for ( i = 0; i < e820_map_nr; i++ )
- cb(d, e820entry + i, data);
+ u64 host_tsc;
- unmap_domain_page(p);
-}
+ rdtscll(host_tsc);
-static void hvm_zap_iommu_pages(struct domain *d)
-{
- e820_foreach(d, e820_zap_iommu_callback, NULL);
+ v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
+ hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
}
-static void e820_map_io_shared_callback(struct domain *d,
- struct e820entry *e,
- void *data)
+u64 hvm_get_guest_time(struct vcpu *v)
{
- unsigned long *mfn = data;
- if ( e->type == E820_SHARED_PAGE )
- {
- ASSERT(*mfn == INVALID_MFN);
- *mfn = gmfn_to_mfn(d, e->addr >> PAGE_SHIFT);
- }
-}
+ u64 host_tsc;
-static void e820_map_buffered_io_callback(struct domain *d,
- struct e820entry *e,
- void *data)
-{
- unsigned long *mfn = data;
- if ( e->type == E820_BUFFERED_IO ) {
- ASSERT(*mfn == INVALID_MFN);
- *mfn = gmfn_to_mfn(d, e->addr >> PAGE_SHIFT);
- }
+ rdtscll(host_tsc);
+ return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
}
-void hvm_map_io_shared_pages(struct vcpu *v)
+void hvm_freeze_time(struct vcpu *v)
{
- unsigned long mfn;
- void *p;
- struct domain *d = v->domain;
-
- if ( d->arch.hvm_domain.shared_page_va ||
- d->arch.hvm_domain.buffered_io_va )
- return;
-
- mfn = INVALID_MFN;
- e820_foreach(d, e820_map_io_shared_callback, &mfn);
-
- if ( mfn == INVALID_MFN )
- {
- printk("Can not find io request shared page for HVM domain.\n");
- domain_crash_synchronous();
- }
-
- p = map_domain_page_global(mfn);
- if ( p == NULL )
- {
- printk("Can not map io request shared page for HVM domain.\n");
- domain_crash_synchronous();
- }
-
- d->arch.hvm_domain.shared_page_va = (unsigned long)p;
-
- mfn = INVALID_MFN;
- e820_foreach(d, e820_map_buffered_io_callback, &mfn);
- if ( mfn != INVALID_MFN ) {
- p = map_domain_page_global(mfn);
- if ( p )
- d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
- }
-}
+ struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
-void hvm_create_event_channels(struct vcpu *v)
-{
- vcpu_iodata_t *p;
- struct vcpu *o;
-
- if ( v->vcpu_id == 0 ) {
- /* Ugly: create event channels for every vcpu when vcpu 0
- starts, so that they're available for ioemu to bind to. */
- for_each_vcpu(v->domain, o) {
- p = get_vio(v->domain, o->vcpu_id);
- o->arch.hvm_vcpu.xen_port = p->vp_eport =
- alloc_unbound_xen_event_channel(o, 0);
- DPRINTK("Allocated port %d for hvm.\n", o->arch.hvm_vcpu.xen_port);
+ if ( pt->enabled && pt->first_injected
+ && (v->vcpu_id == pt->bind_vcpu)
+ && !v->arch.hvm_vcpu.guest_time ) {
+ v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
+ if ( !test_bit(_VCPUF_blocked, &v->vcpu_flags) )
+ {
+ stop_timer(&pt->timer);
+ rtc_freeze(v);
}
}
}
-
-void hvm_stts(struct vcpu *v)
+void hvm_migrate_timers(struct vcpu *v)
{
- /* FPU state already dirty? Then no need to setup_fpu() lazily. */
- if ( test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
- return;
-
- hvm_funcs.stts(v);
-}
+ struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
+ struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
-void hvm_set_guest_time(struct vcpu *v, u64 gtime)
-{
- u64 host_tsc;
-
- rdtscll(host_tsc);
-
- v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
- hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
+ if ( pt->enabled )
+ {
+ migrate_timer(&pt->timer, v->processor);
+ }
+ migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
+ migrate_timer(&vpmt->timer, v->processor);
+ rtc_migrate_timers(v);
}
void hvm_do_resume(struct vcpu *v)
{
ioreq_t *p;
- struct periodic_time *pt =
- &v->domain->arch.hvm_domain.pl_time.periodic_tm;
+ struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
hvm_stts(v);
- /* pick up the elapsed PIT ticks and re-enable pit_timer */
- if ( pt->enabled && pt->first_injected ) {
- if ( v->arch.hvm_vcpu.guest_time ) {
+ /* Pick up the elapsed PIT ticks and re-enable pit_timer. */
+ if ( pt->enabled && (v->vcpu_id == pt->bind_vcpu) && pt->first_injected )
+ {
+ if ( v->arch.hvm_vcpu.guest_time )
+ {
hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
v->arch.hvm_vcpu.guest_time = 0;
}
pickup_deactive_ticks(pt);
}
+ /* Re-enable the RTC timer if needed */
+ rtc_thaw(v);
+
+ /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
- wait_on_xen_event_channel(v->arch.hvm.xen_port,
- p->state != STATE_IOREQ_READY &&
- p->state != STATE_IOREQ_INPROCESS);
- if ( p->state == STATE_IORESP_READY )
- hvm_io_assist(v);
- if ( p->state != STATE_INVALID ) {
- printf("Weird HVM iorequest state %d.\n", p->state);
- domain_crash(v->domain);
+ while ( p->state != STATE_IOREQ_NONE )
+ {
+ switch ( p->state )
+ {
+ case STATE_IORESP_READY: /* IORESP_READY -> NONE */
+ hvm_io_assist(v);
+ break;
+ case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY */
+ case STATE_IOREQ_INPROCESS:
+ wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port,
+ (p->state != STATE_IOREQ_READY) &&
+ (p->state != STATE_IOREQ_INPROCESS));
+ break;
+ default:
+ gdprintk(XENLOG_ERR, "Weird HVM iorequest state %d.\n", p->state);
+ domain_crash_synchronous();
+ }
}
}
-void hvm_release_assist_channel(struct vcpu *v)
+int hvm_domain_initialise(struct domain *d)
{
- free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);
-}
+ int rc;
+ if ( !hvm_enabled )
+ {
+ gdprintk(XENLOG_WARNING, "Attempt to create a HVM guest "
+ "on a non-VT/AMDV platform.\n");
+ return -EINVAL;
+ }
-void hvm_setup_platform(struct domain* d)
+ spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
+ spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
+ spin_lock_init(&d->arch.hvm_domain.irq.lock);
+
+ rc = shadow_enable(d, SHM2_refcounts|SHM2_translate|SHM2_external);
+ if ( rc != 0 )
+ return rc;
+
+ vpic_init(d);
+ vioapic_init(d);
+
+ return 0;
+}
+
+void hvm_domain_destroy(struct domain *d)
{
- struct hvm_domain *platform;
- struct vcpu *v=current;
+ kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
+ rtc_deinit(d);
+ pmtimer_deinit(d);
- if ( !hvm_guest(v) || (v->vcpu_id != 0) )
- return;
+ if ( d->arch.hvm_domain.shared_page_va )
+ unmap_domain_page_global(
+ (void *)d->arch.hvm_domain.shared_page_va);
- hvm_zap_iommu_pages(d);
+ if ( d->arch.hvm_domain.buffered_io_va )
+ unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
+}
- platform = &d->arch.hvm_domain;
- pic_init(&platform->vpic, pic_irq_request, &platform->interrupt_request);
- register_pic_io_hook();
+int hvm_vcpu_initialise(struct vcpu *v)
+{
+ struct hvm_domain *platform;
+ int rc;
+
+ if ( (rc = vlapic_init(v)) != 0 )
+ return rc;
- if ( hvm_apic_support(d) )
+ if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 )
{
- spin_lock_init(&d->arch.hvm_domain.round_robin_lock);
- hvm_vioapic_init(d);
+ vlapic_destroy(v);
+ return rc;
}
- spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
+ /* Create ioreq event channel. */
+ v->arch.hvm_vcpu.xen_port = alloc_unbound_xen_event_channel(v, 0);
+ if ( get_sp(v->domain) && get_vio(v->domain, v->vcpu_id) )
+ get_vio(v->domain, v->vcpu_id)->vp_eport =
+ v->arch.hvm_vcpu.xen_port;
+
+ if ( v->vcpu_id != 0 )
+ return 0;
+
+ /* XXX Below should happen in hvm_domain_initialise(). */
+ platform = &v->domain->arch.hvm_domain;
init_timer(&platform->pl_time.periodic_tm.timer,
pt_timer_fn, v, v->processor);
pit_init(v, cpu_khz);
+ rtc_init(v, RTC_PORT(0), RTC_IRQ);
+ pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
+
+ /* Init guest TSC to start from zero. */
+ hvm_set_guest_time(v, 0);
+
+ return 0;
}
-void pic_irq_request(void *data, int level)
+void hvm_vcpu_destroy(struct vcpu *v)
{
- int *interrupt_request = data;
- *interrupt_request = level;
+ vlapic_destroy(v);
+ hvm_funcs.vcpu_destroy(v);
+
+ /* Event channel is already freed by evtchn_destroy(). */
+ /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/
}
-void hvm_pic_assist(struct vcpu *v)
+int cpu_get_interrupt(struct vcpu *v, int *type)
{
- global_iodata_t *spg;
- u16 *virq_line, irqs;
- struct hvm_virpic *pic = &v->domain->arch.hvm_domain.vpic;
-
- spg = &get_sp(v->domain)->sp_global;
- virq_line = &spg->pic_clear_irr;
- if ( *virq_line ) {
- do {
- irqs = *(volatile u16*)virq_line;
- } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs );
- do_pic_irqs_clear(pic, irqs);
- }
- virq_line = &spg->pic_irr;
- if ( *virq_line ) {
- do {
- irqs = *(volatile u16*)virq_line;
- } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs );
- do_pic_irqs(pic, irqs);
- }
+ int vector;
+
+ if ( (vector = cpu_get_apic_interrupt(v, type)) != -1 )
+ return vector;
+
+ if ( (v->vcpu_id == 0) &&
+ ((vector = cpu_get_pic_interrupt(v, type)) != -1) )
+ return vector;
+
+ return -1;
}
-u64 hvm_get_guest_time(struct vcpu *v)
+static void hvm_vcpu_down(void)
{
- u64 host_tsc;
-
- rdtscll(host_tsc);
- return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
+ struct vcpu *v = current;
+ struct domain *d = v->domain;
+ int online_count = 0;
+
+ gdprintk(XENLOG_INFO, "DOM%d/VCPU%d: going offline.\n",
+ d->domain_id, v->vcpu_id);
+
+ /* Doesn't halt us immediately, but we'll never return to guest context. */
+ set_bit(_VCPUF_down, &v->vcpu_flags);
+ vcpu_sleep_nosync(v);
+
+ /* Any other VCPUs online? ... */
+ LOCK_BIGLOCK(d);
+ for_each_vcpu ( d, v )
+ if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
+ online_count++;
+ UNLOCK_BIGLOCK(d);
+
+ /* ... Shut down the domain if not. */
+ if ( online_count == 0 )
+ {
+ gdprintk(XENLOG_INFO, "DOM%d: all CPUs offline -- powering off.\n",
+ d->domain_id);
+ domain_shutdown(d, SHUTDOWN_poweroff);
+ }
}
-int cpu_get_interrupt(struct vcpu *v, int *type)
+void hvm_send_assist_req(struct vcpu *v)
{
- int intno;
- struct hvm_virpic *s = &v->domain->arch.hvm_domain.vpic;
- unsigned long flags;
-
- if ( (intno = cpu_get_apic_interrupt(v, type)) != -1 ) {
- /* set irq request if a PIC irq is still pending */
- /* XXX: improve that */
- spin_lock_irqsave(&s->lock, flags);
- pic_update_irq(s);
- spin_unlock_irqrestore(&s->lock, flags);
- return intno;
+ ioreq_t *p;
+
+ p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
+ if ( unlikely(p->state != STATE_IOREQ_NONE) )
+ {
+ /* This indicates a bug in the device model. Crash the domain. */
+ gdprintk(XENLOG_ERR, "Device model set bad IO state %d.\n", p->state);
+ domain_crash_synchronous();
}
- /* read the irq from the PIC */
- if ( v->vcpu_id == 0 && (intno = cpu_get_pic_interrupt(v, type)) != -1 )
- return intno;
- return -1;
+ prepare_wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port);
+
+ /*
+ * Following happens /after/ blocking and setting up ioreq contents.
+ * prepare_wait_on_xen_event_channel() is an implicit barrier.
+ */
+ p->state = STATE_IOREQ_READY;
+ notify_via_xen_event_channel(v->arch.hvm_vcpu.xen_port);
}
-#include <asm/hvm/vmx/vmx.h>
void hvm_hlt(unsigned long rflags)
{
- struct vcpu *v = current;
- struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
- s_time_t next_pit = -1, next_wakeup;
-
/*
- * Detect machine shutdown. Only do this for vcpu 0, to avoid potentially
- * shutting down the domain early. If we halt with interrupts disabled,
- * that's a pretty sure sign that we want to shut down. In a real
- * processor, NMIs are the only way to break out of this.
+ * If we halt with interrupts disabled, that's a pretty sure sign that we
+ * want to shut down. In a real processor, NMIs are the only way to break
+ * out of this.
*/
- if ( (v->vcpu_id == 0) && !(rflags & X86_EFLAGS_IF) )
- {
- printk("D%d: HLT with interrupts disabled -- shutting down.\n",
- current->domain->domain_id);
- domain_shutdown(current->domain, SHUTDOWN_poweroff);
- return;
- }
+ if ( unlikely(!(rflags & X86_EFLAGS_IF)) )
+ return hvm_vcpu_down();
- if ( !v->vcpu_id )
- next_pit = get_scheduled(v, pt->irq, pt);
- next_wakeup = get_apictime_scheduled(v);
- if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 )
- next_wakeup = next_pit;
- if ( next_wakeup != - 1 )
- set_timer(&current->arch.hvm_vcpu.hlt_timer, next_wakeup);
do_sched_op_compat(SCHEDOP_block, 0);
}
/*
- * Copy from/to guest virtual.
+ * __hvm_copy():
+ * @buf = hypervisor buffer
+ * @addr = guest address to copy to/from
+ * @size = number of bytes to copy
+ * @dir = copy *to* guest (TRUE) or *from* guest (FALSE)?
+ * @virt = addr is *virtual* (TRUE) or *guest physical* (FALSE)?
+ * Returns number of bytes failed to copy (0 == complete success).
*/
-int hvm_copy(void *buf, unsigned long vaddr, int size, int dir)
+static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt)
{
- struct vcpu *v = current;
- unsigned long gfn;
unsigned long mfn;
- char *addr;
- int count;
+ char *p;
+ int count, todo;
- while (size > 0) {
- count = PAGE_SIZE - (vaddr & ~PAGE_MASK);
- if (count > size)
- count = size;
+ todo = size;
+ while ( todo > 0 )
+ {
+ count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo);
- gfn = shadow_gva_to_gfn(v, vaddr);
- mfn = mfn_x(sh_vcpu_gfn_to_mfn(v, gfn));
+ if ( virt )
+ mfn = get_mfn_from_gpfn(shadow_gva_to_gfn(current, addr));
+ else
+ mfn = get_mfn_from_gpfn(addr >> PAGE_SHIFT);
- if (mfn == INVALID_MFN)
- return 0;
+ if ( mfn == INVALID_MFN )
+ return todo;
- addr = (char *)map_domain_page(mfn) + (vaddr & ~PAGE_MASK);
+ p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK);
- if (dir == HVM_COPY_IN)
- memcpy(buf, addr, count);
+ if ( dir )
+ memcpy(p, buf, count); /* dir == TRUE: *to* guest */
else
- memcpy(addr, buf, count);
+ memcpy(buf, p, count); /* dir == FALSE: *from guest */
- unmap_domain_page(addr);
+ unmap_domain_page(p);
- vaddr += count;
- buf += count;
- size -= count;
+ addr += count;
+ buf += count;
+ todo -= count;
}
- return 1;
+ return 0;
}
-/*
- * HVM specific printbuf. Mostly used for hvmloader chit-chat.
- */
+int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size)
+{
+ return __hvm_copy(buf, paddr, size, 1, 0);
+}
+
+int hvm_copy_from_guest_phys(void *buf, paddr_t paddr, int size)
+{
+ return __hvm_copy(buf, paddr, size, 0, 0);
+}
+
+int hvm_copy_to_guest_virt(unsigned long vaddr, void *buf, int size)
+{
+ return __hvm_copy(buf, vaddr, size, 1, 1);
+}
+
+int hvm_copy_from_guest_virt(void *buf, unsigned long vaddr, int size)
+{
+ return __hvm_copy(buf, vaddr, size, 0, 1);
+}
+
+
+/* HVM specific printbuf. Mostly used for hvmloader chit-chat. */
void hvm_print_line(struct vcpu *v, const char c)
{
- int *index = &v->domain->arch.hvm_domain.pbuf_index;
- char *pbuf = v->domain->arch.hvm_domain.pbuf;
-
- if (*index == HVM_PBUF_SIZE-2 || c == '\n') {
- if (*index == HVM_PBUF_SIZE-2)
- pbuf[(*index)++] = c;
- pbuf[*index] = '\0';
- printk("(GUEST: %u) %s\n", v->domain->domain_id, pbuf);
- *index = 0;
- } else
- pbuf[(*index)++] = c;
+ struct hvm_domain *hd = &v->domain->arch.hvm_domain;
+
+ spin_lock(&hd->pbuf_lock);
+ hd->pbuf[hd->pbuf_idx++] = c;
+ if ( (hd->pbuf_idx == (sizeof(hd->pbuf) - 2)) || (c == '\n') )
+ {
+ if ( c != '\n' )
+ hd->pbuf[hd->pbuf_idx++] = '\n';
+ hd->pbuf[hd->pbuf_idx] = '\0';
+ printk(XENLOG_G_DEBUG "HVM%u: %s", v->domain->domain_id, hd->pbuf);
+ hd->pbuf_idx = 0;
+ }
+ spin_unlock(&hd->pbuf_lock);
}
typedef unsigned long hvm_hypercall_t(
@@ -435,7 +413,7 @@ typedef unsigned long hvm_hypercall_t(
#if defined(__i386__)
-static hvm_hypercall_t *hvm_hypercall_table[] = {
+static hvm_hypercall_t *hvm_hypercall_table[NR_hypercalls] = {
HYPERCALL(memory_op),
HYPERCALL(multicall),
HYPERCALL(xen_version),
@@ -453,7 +431,7 @@ void hvm_do_hypercall(struct cpu_user_regs *pregs)
if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] )
{
- DPRINTK("HVM vcpu %d:%d did a bad hypercall %d.\n",
+ gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d did a bad hypercall %d.\n",
current->domain->domain_id, current->vcpu_id,
pregs->eax);
pregs->eax = -ENOSYS;
@@ -499,7 +477,7 @@ static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg)
}
default:
- DPRINTK("memory_op %d.\n", cmd);
+ gdprintk(XENLOG_WARNING, "memory_op %d.\n", cmd);
rc = -ENOSYS;
break;
}
@@ -532,7 +510,7 @@ void hvm_do_hypercall(struct cpu_user_regs *pregs)
pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */
if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] )
{
- DPRINTK("HVM vcpu %d:%d did a bad hypercall %ld.\n",
+ gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d did a bad hypercall %ld.\n",
current->domain->domain_id, current->vcpu_id,
pregs->rax);
pregs->rax = -ENOSYS;
@@ -579,22 +557,32 @@ int hvm_bringup_ap(int vcpuid, int trampoline_vector)
struct vcpu_guest_context *ctxt;
int rc = 0;
- /* current must be HVM domain BSP */
- if ( !(hvm_guest(bsp) && bsp->vcpu_id == 0) ) {
- printk("Not calling hvm_bringup_ap from BSP context.\n");
- domain_crash_synchronous();
+ BUG_ON(!is_hvm_domain(d));
+
+ if ( bsp->vcpu_id != 0 )
+ {
+ gdprintk(XENLOG_ERR, "Not calling hvm_bringup_ap from BSP context.\n");
+ domain_crash(bsp->domain);
+ return -EINVAL;
}
if ( (v = d->vcpu[vcpuid]) == NULL )
return -ENOENT;
- if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL ) {
- printk("Failed to allocate memory in hvm_bringup_ap.\n");
+ if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
+ {
+ gdprintk(XENLOG_ERR,
+ "Failed to allocate memory in hvm_bringup_ap.\n");
return -ENOMEM;
}
hvm_init_ap_context(ctxt, vcpuid, trampoline_vector);
+ /* Sync AP's TSC with BSP's. */
+ v->arch.hvm_vcpu.cache_tsc_offset =
+ v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset;
+ hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
+
LOCK_BIGLOCK(d);
rc = -EEXIST;
if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
@@ -602,15 +590,136 @@ int hvm_bringup_ap(int vcpuid, int trampoline_vector)
UNLOCK_BIGLOCK(d);
if ( rc != 0 )
- printk("AP %d bringup failed in boot_vcpu %x.\n", vcpuid, rc);
- else {
- if ( test_and_clear_bit(_VCPUF_down, &d->vcpu[vcpuid]->vcpu_flags) )
- vcpu_wake(d->vcpu[vcpuid]);
- printk("AP %d bringup suceeded.\n", vcpuid);
+ {
+ gdprintk(XENLOG_ERR,
+ "AP %d bringup failed in boot_vcpu %x.\n", vcpuid, rc);
+ goto out;
}
+ if ( test_and_clear_bit(_VCPUF_down, &d->vcpu[vcpuid]->vcpu_flags) )
+ vcpu_wake(d->vcpu[vcpuid]);
+ gdprintk(XENLOG_INFO, "AP %d bringup suceeded.\n", vcpuid);
+
+ out:
xfree(ctxt);
+ return rc;
+}
+
+static int hvmop_set_pci_intx_level(
+ XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t) uop)
+{
+ struct xen_hvm_set_pci_intx_level op;
+ struct domain *d;
+ int rc;
+
+ if ( copy_from_guest(&op, uop, 1) )
+ return -EFAULT;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) )
+ return -EINVAL;
+
+ d = find_domain_by_id(op.domid);
+ if ( d == NULL )
+ return -ESRCH;
+
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto out;
+
+ rc = 0;
+ switch ( op.level )
+ {
+ case 0:
+ hvm_pci_intx_deassert(d, op.device, op.intx);
+ break;
+ case 1:
+ hvm_pci_intx_assert(d, op.device, op.intx);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ out:
+ put_domain(d);
+ return rc;
+}
+
+static int hvmop_set_isa_irq_level(
+ XEN_GUEST_HANDLE(xen_hvm_set_isa_irq_level_t) uop)
+{
+ struct xen_hvm_set_isa_irq_level op;
+ struct domain *d;
+ int rc;
+
+ if ( copy_from_guest(&op, uop, 1) )
+ return -EFAULT;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( op.isa_irq > 15 )
+ return -EINVAL;
+ d = find_domain_by_id(op.domid);
+ if ( d == NULL )
+ return -ESRCH;
+
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto out;
+
+ rc = 0;
+ switch ( op.level )
+ {
+ case 0:
+ hvm_isa_irq_deassert(d, op.isa_irq);
+ break;
+ case 1:
+ hvm_isa_irq_assert(d, op.isa_irq);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ out:
+ put_domain(d);
+ return rc;
+}
+
+static int hvmop_set_pci_link_route(
+ XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t) uop)
+{
+ struct xen_hvm_set_pci_link_route op;
+ struct domain *d;
+ int rc;
+
+ if ( copy_from_guest(&op, uop, 1) )
+ return -EFAULT;
+
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( (op.link > 3) || (op.isa_irq > 15) )
+ return -EINVAL;
+
+ d = find_domain_by_id(op.domid);
+ if ( d == NULL )
+ return -ESRCH;
+
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto out;
+
+ rc = 0;
+ hvm_set_pci_link_route(d, op.link, op.isa_irq);
+
+ out:
+ put_domain(d);
return rc;
}
@@ -626,6 +735,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
{
struct xen_hvm_param a;
struct domain *d;
+ struct vcpu *v;
+ unsigned long mfn;
+ void *p;
if ( copy_from_guest(&a, arg, 1) )
return -EFAULT;
@@ -649,8 +761,44 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
return -EPERM;
}
+ rc = -EINVAL;
+ if ( !is_hvm_domain(d) )
+ goto param_fail;
+
if ( op == HVMOP_set_param )
{
+ switch ( a.index )
+ {
+ case HVM_PARAM_IOREQ_PFN:
+ if ( d->arch.hvm_domain.shared_page_va )
+ goto param_fail;
+ mfn = gmfn_to_mfn(d, a.value);
+ if ( mfn == INVALID_MFN )
+ goto param_fail;
+ p = map_domain_page_global(mfn);
+ if ( p == NULL )
+ goto param_fail;
+ d->arch.hvm_domain.shared_page_va = (unsigned long)p;
+ /* Initialise evtchn port info if VCPUs already created. */
+ for_each_vcpu ( d, v )
+ get_vio(d, v->vcpu_id)->vp_eport =
+ v->arch.hvm_vcpu.xen_port;
+ break;
+ case HVM_PARAM_BUFIOREQ_PFN:
+ if ( d->arch.hvm_domain.buffered_io_va )
+ goto param_fail;
+ mfn = gmfn_to_mfn(d, a.value);
+ if ( mfn == INVALID_MFN )
+ goto param_fail;
+ p = map_domain_page_global(mfn);
+ if ( p == NULL )
+ goto param_fail;
+ d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
+ break;
+ case HVM_PARAM_CALLBACK_IRQ:
+ hvm_set_callback_gsi(d, a.value);
+ break;
+ }
d->arch.hvm_domain.params[a.index] = a.value;
rc = 0;
}
@@ -660,13 +808,29 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
}
+ param_fail:
put_domain(d);
break;
}
+ case HVMOP_set_pci_intx_level:
+ rc = hvmop_set_pci_intx_level(
+ guest_handle_cast(arg, xen_hvm_set_pci_intx_level_t));
+ break;
+
+ case HVMOP_set_isa_irq_level:
+ rc = hvmop_set_isa_irq_level(
+ guest_handle_cast(arg, xen_hvm_set_isa_irq_level_t));
+ break;
+
+ case HVMOP_set_pci_link_route:
+ rc = hvmop_set_pci_link_route(
+ guest_handle_cast(arg, xen_hvm_set_pci_link_route_t));
+ break;
+
default:
{
- DPRINTK("Bad HVM op %ld.\n", op);
+ gdprintk(XENLOG_WARNING, "Bad HVM op %ld.\n", op);
rc = -ENOSYS;
break;
}
diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c
index 6b817293b9..516c114907 100644
--- a/xen/arch/x86/hvm/i8254.c
+++ b/xen/arch/x86/hvm/i8254.c
@@ -38,7 +38,7 @@
#include <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
#include <asm/current.h>
/* Enable DEBUG_PIT may cause guest calibration inaccuracy */
@@ -49,7 +49,6 @@
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
-#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
static int handle_pit_io(ioreq_t *p);
static int handle_speaker_io(ioreq_t *p);
@@ -77,17 +76,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
return res.ll;
}
-/*
- * get processor time.
- * unit: TSC
- */
-int64_t hvm_get_clock(struct vcpu *v)
-{
- uint64_t gtsc;
- gtsc = hvm_get_guest_time(v);
- return gtsc;
-}
-
static int pit_get_count(PITChannelState *s)
{
uint64_t d;
@@ -215,11 +203,11 @@ static inline void pit_load_count(PITChannelState *s, int val)
switch (s->mode) {
case 2:
/* create periodic time */
- s->pt = create_periodic_time (s, period, 0, 0);
+ s->pt = create_periodic_time (period, 0, 0, pit_time_fired, s);
break;
case 1:
/* create one shot time */
- s->pt = create_periodic_time (s, period, 0, 1);
+ s->pt = create_periodic_time (period, 0, 1, pit_time_fired, s);
#ifdef DEBUG_PIT
printk("HVM_PIT: create one shot time.\n");
#endif
@@ -386,9 +374,9 @@ void pit_init(struct vcpu *v, unsigned long cpu_khz)
s++; s->vcpu = v;
s++; s->vcpu = v;
- register_portio_handler(PIT_BASE, 4, handle_pit_io);
+ register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io);
/* register the speaker port */
- register_portio_handler(0x61, 1, handle_speaker_io);
+ register_portio_handler(v->domain, 0x61, 1, handle_speaker_io);
ticks_per_sec(v) = cpu_khz * (int64_t)1000;
#ifdef DEBUG_PIT
printk("HVM_PIT: guest frequency =%lld\n", (long long)ticks_per_sec(v));
@@ -404,17 +392,17 @@ static int handle_pit_io(ioreq_t *p)
struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit);
if (p->size != 1 ||
- p->pdata_valid ||
+ p->data_is_ptr ||
p->type != IOREQ_TYPE_PIO){
printk("HVM_PIT:wrong PIT IO!\n");
return 1;
}
if (p->dir == 0) {/* write */
- pit_ioport_write(vpit, p->addr, p->u.data);
+ pit_ioport_write(vpit, p->addr, p->data);
} else if (p->dir == 1) { /* read */
if ( (p->addr & 3) != 3 ) {
- p->u.data = pit_ioport_read(vpit, p->addr);
+ p->data = pit_ioport_read(vpit, p->addr);
} else {
printk("HVM_PIT: read A1:A0=3!\n");
}
@@ -446,16 +434,16 @@ static int handle_speaker_io(ioreq_t *p)
struct PITState *vpit = &(v->domain->arch.hvm_domain.pl_time.vpit);
if (p->size != 1 ||
- p->pdata_valid ||
+ p->data_is_ptr ||
p->type != IOREQ_TYPE_PIO){
printk("HVM_SPEAKER:wrong SPEAKER IO!\n");
return 1;
}
if (p->dir == 0) {/* write */
- speaker_ioport_write(vpit, p->addr, p->u.data);
+ speaker_ioport_write(vpit, p->addr, p->data);
} else if (p->dir == 1) {/* read */
- p->u.data = speaker_ioport_read(vpit, p->addr);
+ p->data = speaker_ioport_read(vpit, p->addr);
}
return 1;
diff --git a/xen/arch/x86/hvm/i8259.c b/xen/arch/x86/hvm/i8259.c
deleted file mode 100644
index f3c5aaffe8..0000000000
--- a/xen/arch/x86/hvm/i8259.c
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * QEMU 8259 interrupt controller emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2005 Intel Corperation
- *
- * 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 <xen/config.h>
-#include <xen/types.h>
-#include <xen/mm.h>
-#include <xen/xmalloc.h>
-#include <xen/lib.h>
-#include <xen/errno.h>
-#include <xen/sched.h>
-#include <asm/hvm/hvm.h>
-#include <asm/hvm/io.h>
-#include <asm/hvm/support.h>
-#include <asm/current.h>
-
-/* set irq level. If an edge is detected, then the IRR is set to 1 */
-/* Caller must hold vpic lock */
-static inline void pic_set_irq1(PicState *s, int irq, int level)
-{
- int mask;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- mask = 1 << irq;
- if (s->elcr & mask) {
- /* level triggered */
- if (level) {
- s->irr |= mask;
- s->last_irr |= mask;
- } else {
- s->irr &= ~mask;
- s->last_irr &= ~mask;
- }
- } else {
- /* edge triggered */
- if (level) {
- if ((s->last_irr & mask) == 0) {
- s->irr |= mask;
- }
- s->last_irr |= mask;
- } else {
- s->last_irr &= ~mask;
- }
- }
-}
-
-/* return the highest priority found in mask (highest = smallest
- number). Return 8 if no irq */
-/* Caller must hold vpic lock */
-static inline int get_priority(PicState *s, int mask)
-{
- int priority;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- if (mask == 0)
- return 8;
- priority = 0;
- while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
- priority++;
- return priority;
-}
-
-/* return the pic wanted interrupt. return -1 if none */
-/* Caller must hold vpic lock */
-static int pic_get_irq(PicState *s)
-{
- int mask, cur_priority, priority;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- mask = s->irr & ~s->imr;
- priority = get_priority(s, mask);
- if (priority == 8)
- return -1;
- /* compute current priority. If special fully nested mode on the
- master, the IRQ coming from the slave is not taken into account
- for the priority computation. */
- mask = s->isr;
- if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
- mask &= ~(1 << 2);
- cur_priority = get_priority(s, mask);
- if (priority < cur_priority) {
- /* higher priority found: an irq should be generated */
- return (priority + s->priority_add) & 7;
- } else {
- return -1;
- }
-}
-
-/* raise irq to CPU if necessary. must be called every time the active
- irq may change */
-/* XXX: should not export it, but it is needed for an APIC kludge */
-/* Caller must hold vpic lock */
-void pic_update_irq(struct hvm_virpic *s)
-{
- int irq2, irq;
-
- BUG_ON(!spin_is_locked(&s->lock));
-
- /* first look at slave pic */
- irq2 = pic_get_irq(&s->pics[1]);
- if (irq2 >= 0) {
- /* if irq request by slave pic, signal master PIC */
- pic_set_irq1(&s->pics[0], 2, 1);
- pic_set_irq1(&s->pics[0], 2, 0);
- }
- /* look at requested irq */
- irq = pic_get_irq(&s->pics[0]);
- if (irq >= 0) {
- s->irq_request(s->irq_request_opaque, 1);
- }
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
- struct hvm_virpic *s = opaque;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- hvm_vioapic_set_irq(current->domain, irq, level);
- pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
- /* used for IOAPIC irqs */
- if (s->alt_irq_func)
- s->alt_irq_func(s->alt_irq_opaque, irq, level);
- pic_update_irq(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-void do_pic_irqs (struct hvm_virpic *s, uint16_t irqs)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->pics[1].irr |= (uint8_t)(irqs >> 8);
- s->pics[0].irr |= (uint8_t) irqs;
- hvm_vioapic_do_irqs(current->domain, irqs);
- pic_update_irq(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-void do_pic_irqs_clear (struct hvm_virpic *s, uint16_t irqs)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->pics[1].irr &= ~(uint8_t)(irqs >> 8);
- s->pics[0].irr &= ~(uint8_t) irqs;
- hvm_vioapic_do_irqs_clear(current->domain, irqs);
- pic_update_irq(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* obsolete function */
-void pic_set_irq(struct hvm_virpic *isa_pic, int irq, int level)
-{
- pic_set_irq_new(isa_pic, irq, level);
-}
-
-/* acknowledge interrupt 'irq' */
-/* Caller must hold vpic lock */
-static inline void pic_intack(PicState *s, int irq)
-{
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- if (s->auto_eoi) {
- if (s->rotate_on_auto_eoi)
- s->priority_add = (irq + 1) & 7;
- } else {
- s->isr |= (1 << irq);
- }
- /* We don't clear a level sensitive interrupt here */
- if (!(s->elcr & (1 << irq)))
- s->irr &= ~(1 << irq);
-}
-
-int pic_read_irq(struct hvm_virpic *s)
-{
- int irq, irq2, intno;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- irq = pic_get_irq(&s->pics[0]);
- if (irq >= 0) {
- pic_intack(&s->pics[0], irq);
- if (irq == 2) {
- irq2 = pic_get_irq(&s->pics[1]);
- if (irq2 >= 0) {
- pic_intack(&s->pics[1], irq2);
- } else {
- /* spurious IRQ on slave controller */
- irq2 = 7;
- }
- intno = s->pics[1].irq_base + irq2;
- irq = irq2 + 8;
- } else {
- intno = s->pics[0].irq_base + irq;
- }
- } else {
- /* spurious IRQ on host controller */
- printk("spurious IRQ irq got=%d\n",irq);
- irq = 7;
- intno = s->pics[0].irq_base + irq;
- }
- pic_update_irq(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
- return intno;
-}
-
-/* Caller must hold vpic lock */
-static void update_shared_irr(struct hvm_virpic *s, PicState *c)
-{
- uint8_t *pl, *pe;
-
- BUG_ON(!spin_is_locked(&s->lock));
-
- get_sp(current->domain)->sp_global.pic_elcr =
- s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
- pl =(uint8_t*)&get_sp(current->domain)->sp_global.pic_last_irr;
- pe =(uint8_t*)&get_sp(current->domain)->sp_global.pic_elcr;
- if ( c == &s->pics[0] ) {
- *pl = c->last_irr;
- *pe = c->elcr;
- }
- else {
- *(pl+1) = c->last_irr;
- *(pe+1) = c->elcr;
- }
-}
-
-/* Caller must hold vpic lock */
-static void pic_reset(void *opaque)
-{
- PicState *s = opaque;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- s->last_irr = 0;
- s->irr = 0;
- s->imr = 0;
- s->isr = 0;
- s->priority_add = 0;
- s->irq_base = 0;
- s->read_reg_select = 0;
- s->poll = 0;
- s->special_mask = 0;
- s->init_state = 0;
- s->auto_eoi = 0;
- s->rotate_on_auto_eoi = 0;
- s->special_fully_nested_mode = 0;
- s->init4 = 0;
- s->elcr = 0;
-}
-
-/* Caller must hold vpic lock */
-static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- PicState *s = opaque;
- int priority, cmd, irq;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- addr &= 1;
- if (addr == 0) {
- if (val & 0x10) {
- /* init */
- pic_reset(s);
- update_shared_irr(s->pics_state, s);
- /* deassert a pending interrupt */
- s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
- s->init_state = 1;
- s->init4 = val & 1;
- if (val & 0x02)
- hw_error("single mode not supported");
- if (val & 0x08)
- hw_error("level sensitive irq not supported");
- } else if (val & 0x08) {
- if (val & 0x04)
- s->poll = 1;
- if (val & 0x02)
- s->read_reg_select = val & 1;
- if (val & 0x40)
- s->special_mask = (val >> 5) & 1;
- } else {
- cmd = val >> 5;
- switch(cmd) {
- case 0:
- case 4:
- s->rotate_on_auto_eoi = cmd >> 2;
- break;
- case 1: /* end of interrupt */
- case 5:
- priority = get_priority(s, s->isr);
- if (priority != 8) {
- irq = (priority + s->priority_add) & 7;
- s->isr &= ~(1 << irq);
- if (cmd == 5)
- s->priority_add = (irq + 1) & 7;
- pic_update_irq(s->pics_state);
- }
- break;
- case 3:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- pic_update_irq(s->pics_state);
- break;
- case 6:
- s->priority_add = (val + 1) & 7;
- pic_update_irq(s->pics_state);
- break;
- case 7:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- s->priority_add = (irq + 1) & 7;
- pic_update_irq(s->pics_state);
- break;
- default:
- /* no operation */
- break;
- }
- }
- } else {
- switch(s->init_state) {
- case 0:
- /* normal mode */
- s->imr = val;
- pic_update_irq(s->pics_state);
- break;
- case 1:
- s->irq_base = val & 0xf8;
- s->init_state = 2;
- break;
- case 2:
- if (s->init4) {
- s->init_state = 3;
- } else {
- s->init_state = 0;
- }
- break;
- case 3:
- s->special_fully_nested_mode = (val >> 4) & 1;
- s->auto_eoi = (val >> 1) & 1;
- s->init_state = 0;
- break;
- }
- }
-}
-
-/* Caller must hold vpic lock */
-static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
-{
- int ret;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- ret = pic_get_irq(s);
- if (ret >= 0) {
- if (addr1 >> 7) {
- s->pics_state->pics[0].isr &= ~(1 << 2);
- s->pics_state->pics[0].irr &= ~(1 << 2);
- }
- s->irr &= ~(1 << ret);
- s->isr &= ~(1 << ret);
- if (addr1 >> 7 || ret != 2)
- pic_update_irq(s->pics_state);
- } else {
- ret = 0x07;
- pic_update_irq(s->pics_state);
- }
-
- return ret;
-}
-
-/* Caller must hold vpic lock */
-static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
-{
- PicState *s = opaque;
- unsigned int addr;
- int ret;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- addr = addr1;
- addr &= 1;
- if (s->poll) {
- ret = pic_poll_read(s, addr1);
- s->poll = 0;
- } else {
- if (addr == 0) {
- if (s->read_reg_select)
- ret = s->isr;
- else
- ret = s->irr;
- } else {
- ret = s->imr;
- }
- }
- return ret;
-}
-
-/* memory mapped interrupt status */
-/* XXX: may be the same than pic_read_rq() */
-uint32_t pic_intack_read(struct hvm_virpic *s)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- ret = pic_poll_read(&s->pics[0], 0x00);
- if (ret == 2)
- ret = pic_poll_read(&s->pics[1], 0x80) + 8;
- /* Prepare for ISR read */
- s->pics[0].read_reg_select = 1;
- spin_unlock_irqrestore(&s->lock, flags);
-
- return ret;
-}
-
-static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-/* Caller must hold vpic lock */
-{
- PicState *s = opaque;
-
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- s->elcr = val & s->elcr_mask;
-}
-
-static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
-{
- PicState *s = opaque;
- return s->elcr;
-}
-
-/* XXX: add generic master/slave system */
-/* Caller must hold vpic lock */
-static void pic_init1(int io_addr, int elcr_addr, PicState *s)
-{
- BUG_ON(!spin_is_locked(&s->pics_state->lock));
-
- pic_reset(s);
-}
-
-void pic_init(struct hvm_virpic *s, void (*irq_request)(void *, int),
- void *irq_request_opaque)
-{
- unsigned long flags;
-
- memset(s, 0, sizeof(*s));
- spin_lock_init(&s->lock);
- s->pics[0].pics_state = s;
- s->pics[1].pics_state = s;
- spin_lock_irqsave(&s->lock, flags);
- pic_init1(0x20, 0x4d0, &s->pics[0]);
- pic_init1(0xa0, 0x4d1, &s->pics[1]);
- spin_unlock_irqrestore(&s->lock, flags);
- s->pics[0].elcr_mask = 0xf8;
- s->pics[1].elcr_mask = 0xde;
- s->irq_request = irq_request;
- s->irq_request_opaque = irq_request_opaque;
-}
-
-void pic_set_alt_irq_func(struct hvm_virpic *s,
- void (*alt_irq_func)(void *, int, int),
- void *alt_irq_opaque)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->alt_irq_func = alt_irq_func;
- s->alt_irq_opaque = alt_irq_opaque;
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int intercept_pic_io(ioreq_t *p)
-{
- struct hvm_virpic *pic;
- struct vcpu *v = current;
- uint32_t data;
- unsigned long flags;
-
- if ( p->size != 1 || p->count != 1) {
- printk("PIC_IO wrong access size %d!\n", (int)p->size);
- return 1;
- }
- pic = &v->domain->arch.hvm_domain.vpic;
- if ( p->dir == 0 ) {
- if(p->pdata_valid)
- hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_IN);
- else
- data = p->u.data;
- spin_lock_irqsave(&pic->lock, flags);
- pic_ioport_write((void*)&pic->pics[p->addr>>7],
- (uint32_t) p->addr, (uint32_t) (data & 0xff));
- spin_unlock_irqrestore(&pic->lock, flags);
- }
- else {
- spin_lock_irqsave(&pic->lock, flags);
- data = pic_ioport_read(
- (void*)&pic->pics[p->addr>>7], (uint32_t) p->addr);
- spin_unlock_irqrestore(&pic->lock, flags);
- if(p->pdata_valid)
- hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_OUT);
- else
- p->u.data = (u64)data;
- }
- return 1;
-}
-
-static int intercept_elcr_io(ioreq_t *p)
-{
- struct hvm_virpic *s;
- struct vcpu *v = current;
- uint32_t data;
- unsigned long flags;
-
- if ( p->size != 1 || p->count != 1 ) {
- printk("PIC_IO wrong access size %d!\n", (int)p->size);
- return 1;
- }
-
- s = &v->domain->arch.hvm_domain.vpic;
- if ( p->dir == 0 ) {
- if(p->pdata_valid)
- hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_IN);
- else
- data = p->u.data;
- spin_lock_irqsave(&s->lock, flags);
- elcr_ioport_write((void*)&s->pics[p->addr&1],
- (uint32_t) p->addr, (uint32_t)( data & 0xff));
- get_sp(current->domain)->sp_global.pic_elcr =
- s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- else {
- data = (u64) elcr_ioport_read(
- (void*)&s->pics[p->addr&1], (uint32_t) p->addr);
- if(p->pdata_valid)
- hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_OUT);
- else
- p->u.data = (u64)data;
-
- }
- return 1;
-}
-void register_pic_io_hook (void)
-{
- register_portio_handler(0x20, 2, intercept_pic_io);
- register_portio_handler(0x4d0, 1, intercept_elcr_io);
- register_portio_handler(0xa0, 2, intercept_pic_io);
- register_portio_handler(0x4d1, 1, intercept_elcr_io);
-}
-
-
-/* IRQ handling */
-int cpu_get_pic_interrupt(struct vcpu *v, int *type)
-{
- int intno;
- struct hvm_virpic *s = &v->domain->arch.hvm_domain.vpic;
- struct hvm_domain *plat = &v->domain->arch.hvm_domain;
-
- if ( !vlapic_accept_pic_intr(v) )
- return -1;
-
- if (cmpxchg(&plat->interrupt_request, 1, 0) != 1)
- return -1;
-
- /* read the irq from the PIC */
- intno = pic_read_irq(s);
- *type = APIC_DM_EXTINT;
- return intno;
-}
-
-int is_pit_irq(struct vcpu *v, int irq, int type)
-{
- int pit_vec;
-
- if (type == APIC_DM_EXTINT)
- pit_vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
- else
- pit_vec =
- v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
-
- return (irq == pit_vec);
-}
-
-int is_irq_enabled(struct vcpu *v, int irq)
-{
- struct hvm_virpic *vpic=&v->domain->arch.hvm_domain.vpic;
-
- if ( irq & 8 ) {
- return !( (1 << (irq&7)) & vpic->pics[1].imr);
- }
- else {
- return !( (1 << irq) & vpic->pics[0].imr);
- }
-}
-
diff --git a/xen/arch/x86/hvm/svm/instrlen.c b/xen/arch/x86/hvm/instrlen.c
index f7c78d0461..85ee70c9de 100644
--- a/xen/arch/x86/hvm/svm/instrlen.c
+++ b/xen/arch/x86/hvm/instrlen.c
@@ -10,25 +10,21 @@
*/
/*
- * TODO: the way in which we use svm_instrlen is very inefficient as is now
- * stands. It will be worth while to return the actual instruction buffer
+ * TODO: The way in which we use hvm_instruction_length is very inefficient as
+ * it now stands. It will be worthwhile to return the actual instruction buffer
* along with the instruction length since one of the reasons we are getting
* the instruction length is to know how many instruction bytes we need to
* fetch.
*/
#include <xen/config.h>
-#include <xen/types.h>
-#include <xen/lib.h>
+#include <xen/sched.h>
#include <xen/mm.h>
-#include <asm/regs.h>
-#define DPRINTF DPRINTK
#include <asm-x86/x86_emulate.h>
/* read from guest memory */
extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,
int length);
-extern void svm_dump_inst(unsigned long eip);
/*
* Opcode effective-address decode tables.
@@ -124,9 +120,7 @@ static uint8_t opcode_table[256] = {
ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
ByteOp|ImplicitOps, ImplicitOps,
/* 0xB0 - 0xBF */
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xC0 - 0xC7 */
ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
@@ -198,68 +192,52 @@ static uint8_t twobyte_table[256] = {
};
/*
- * insn_fetch - fetch the next 1 to 4 bytes from instruction stream
- *
- * @_type: u8, u16, u32, s8, s16, or s32
- * @_size: 1, 2, or 4 bytes
- * @_eip: address to fetch from guest memory
- * @_length: updated! increments the current instruction length counter by _size
- *
- * INTERNAL this is used internally by svm_instrlen to fetch the next byte,
- * word, or dword from guest memory at location _eip. we currently use a local
- * unsigned long as the storage buffer since the most bytes we're gonna get
- * is limited to 4.
+ * insn_fetch - fetch the next byte from instruction stream
*/
-#define insn_fetch(_type, _size, _eip, _length) \
-({ unsigned long _x; \
- if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \
- (unsigned long)(_eip), _size)) \
- != _size) \
- goto done; \
- (_eip) += (_size); \
- (_length) += (_size); \
- (_type)_x; \
+#define insn_fetch() \
+({ uint8_t _x; \
+ if ( length >= 15 ) \
+ return -1; \
+ if ( inst_copy_from_guest(&_x, pc, 1) != 1 ) { \
+ gdprintk(XENLOG_WARNING, \
+ "Cannot read from address %lx (eip %lx, mode %d)\n", \
+ pc, org_pc, mode); \
+ return -1; \
+ } \
+ pc += 1; \
+ length += 1; \
+ _x; \
})
-
/**
- * svn_instrlen - returns the current instructions length
+ * hvm_instruction_length - returns the current instructions length
*
- * @regs: guest register state
+ * @org_pc: guest instruction pointer
* @mode: guest operating mode
*
* EXTERNAL this routine calculates the length of the current instruction
- * pointed to by eip. The guest state is _not_ changed by this routine.
+ * pointed to by org_pc. The guest state is _not_ changed by this routine.
*/
-int svm_instrlen(struct cpu_user_regs *regs, int mode)
+int hvm_instruction_length(unsigned long org_pc, int mode)
{
- uint8_t b, d, twobyte = 0, rex_prefix = 0;
- uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
- unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
- int rc = 0;
+ uint8_t b, d, twobyte = 0, rex_prefix = 0, modrm_reg = 0;
+ unsigned int op_default, op_bytes, ad_default, ad_bytes, tmp;
int length = 0;
- unsigned int tmp;
-
- /* Shadow copy of register state. Committed on successful emulation. */
- struct cpu_user_regs _regs = *regs;
-
- /* include CS for 16-bit modes */
- if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16)
- _regs.eip += (_regs.cs << 4);
+ unsigned long pc = org_pc;
switch ( mode )
{
case X86EMUL_MODE_REAL:
case X86EMUL_MODE_PROT16:
- op_bytes = ad_bytes = 2;
+ op_bytes = op_default = ad_bytes = ad_default = 2;
break;
case X86EMUL_MODE_PROT32:
- op_bytes = ad_bytes = 4;
+ op_bytes = op_default = ad_bytes = ad_default = 4;
break;
#ifdef __x86_64__
case X86EMUL_MODE_PROT64:
- op_bytes = 4;
- ad_bytes = 8;
+ op_bytes = op_default = 4;
+ ad_bytes = ad_default = 8;
break;
#endif
default:
@@ -267,18 +245,18 @@ int svm_instrlen(struct cpu_user_regs *regs, int mode)
}
/* Legacy prefixes. */
- for ( i = 0; i < 8; i++ )
+ for ( ; ; )
{
- switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) )
+ switch ( b = insn_fetch() )
{
case 0x66: /* operand-size override */
- op_bytes ^= 6; /* switch between 2/4 bytes */
+ op_bytes = op_default ^ 6; /* switch between 2/4 bytes */
break;
case 0x67: /* address-size override */
if ( mode == X86EMUL_MODE_PROT64 )
- ad_bytes ^= 12; /* switch between 4/8 bytes */
+ ad_bytes = ad_default ^ 12; /* switch between 4/8 bytes */
else
- ad_bytes ^= 6; /* switch between 2/4 bytes */
+ ad_bytes = ad_default ^ 6; /* switch between 2/4 bytes */
break;
case 0x2e: /* CS override */
case 0x3e: /* DS override */
@@ -286,37 +264,30 @@ int svm_instrlen(struct cpu_user_regs *regs, int mode)
case 0x64: /* FS override */
case 0x65: /* GS override */
case 0x36: /* SS override */
- break;
case 0xf0: /* LOCK */
- lock_prefix = 1;
- break;
case 0xf3: /* REP/REPE/REPZ */
- rep_prefix = 1;
- break;
case 0xf2: /* REPNE/REPNZ */
break;
+#ifdef __x86_64__
+ case 0x40 ... 0x4f:
+ if ( mode == X86EMUL_MODE_PROT64 )
+ {
+ rex_prefix = b;
+ continue;
+ }
+ /* FALLTHRU */
+#endif
default:
goto done_prefixes;
}
+ rex_prefix = 0;
}
done_prefixes:
- /* Note quite the same as 80386 real mode, but hopefully good enough. */
- if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) {
- printf("sonofabitch!! we don't support 32-bit addresses in realmode\n");
- goto cannot_emulate;
- }
-
/* REX prefix. */
- if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
- {
- rex_prefix = b;
- if ( b & 8 )
- op_bytes = 8; /* REX.W */
- modrm_reg = (b & 4) << 1; /* REX.R */
- /* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
- }
+ if ( rex_prefix & 8 )
+ op_bytes = 8; /* REX.W */
+ /* REX.B, REX.R, and REX.X do not need to be decoded. */
/* Opcode byte(s). */
d = opcode_table[b];
@@ -326,7 +297,7 @@ done_prefixes:
if ( b == 0x0f )
{
twobyte = 1;
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
+ b = insn_fetch();
d = twobyte_table[b];
}
@@ -338,14 +309,14 @@ done_prefixes:
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
- modrm = insn_fetch(uint8_t, 1, _regs.eip, length);
- modrm_mod |= (modrm & 0xc0) >> 6;
- modrm_reg |= (modrm & 0x38) >> 3;
- modrm_rm |= (modrm & 0x07);
+ uint8_t modrm = insn_fetch();
+ uint8_t modrm_mod = (modrm & 0xc0) >> 6;
+ uint8_t modrm_rm = (modrm & 0x07);
+ modrm_reg = (modrm & 0x38) >> 3;
if ( modrm_mod == 3 )
{
- DPRINTF("Cannot parse ModRM.mod == 3.\n");
+ gdprintk(XENLOG_WARNING, "Cannot parse ModRM.mod == 3.\n");
goto cannot_emulate;
}
@@ -358,16 +329,16 @@ done_prefixes:
if ( modrm_rm == 6 )
{
length += 2;
- _regs.eip += 2; /* skip disp16 */
+ pc += 2; /* skip disp16 */
}
break;
case 1:
length += 1;
- _regs.eip += 1; /* skip disp8 */
+ pc += 1; /* skip disp8 */
break;
case 2:
length += 2;
- _regs.eip += 2; /* skip disp16 */
+ pc += 2; /* skip disp16 */
break;
}
}
@@ -378,33 +349,34 @@ done_prefixes:
{
case 0:
if ( (modrm_rm == 4) &&
- (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7)
- == 5) )
+ ((insn_fetch() & 7) == 5) )
{
length += 4;
- _regs.eip += 4; /* skip disp32 specified by SIB.base */
+ pc += 4; /* skip disp32 specified by SIB.base */
}
else if ( modrm_rm == 5 )
{
length += 4;
- _regs.eip += 4; /* skip disp32 */
+ pc += 4; /* skip disp32 */
}
break;
case 1:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1, _regs.eip, length);
+ length += 1;
+ pc += 1;
}
length += 1;
- _regs.eip += 1; /* skip disp8 */
+ pc += 1; /* skip disp8 */
break;
case 2:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1, _regs.eip, length);
+ length += 1;
+ pc += 1;
}
length += 4;
- _regs.eip += 4; /* skip disp32 */
+ pc += 4; /* skip disp32 */
break;
}
}
@@ -425,15 +397,12 @@ done_prefixes:
tmp = (d & ByteOp) ? 1 : op_bytes;
if ( tmp == 8 ) tmp = 4;
/* NB. Immediates are sign-extended as necessary. */
- switch ( tmp )
- {
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
- }
+ length += tmp;
+ pc += tmp;
break;
case SrcImmByte:
- insn_fetch(int8_t, 1, _regs.eip, length);
+ length += 1;
+ pc += 1;
break;
}
@@ -442,13 +411,9 @@ done_prefixes:
switch ( b )
{
- case 0xa0 ... 0xa1: /* mov */
- length += ad_bytes;
- _regs.eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2 ... 0xa3: /* mov */
+ case 0xa0 ... 0xa3: /* mov */
length += ad_bytes;
- _regs.eip += ad_bytes; /* skip dst displacement */
+ pc += ad_bytes; /* skip src/dst displacement */
break;
case 0xf6 ... 0xf7: /* Grp3 */
switch ( modrm_reg )
@@ -457,23 +422,19 @@ done_prefixes:
/* Special case in Grp3: test has an immediate source operand. */
tmp = (d & ByteOp) ? 1 : op_bytes;
if ( tmp == 8 ) tmp = 4;
- switch ( tmp )
- {
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
- }
- goto done;
+ length += tmp;
+ pc += tmp;
+ break;
}
break;
}
done:
- return length;
+ return length < 16 ? length : -1;
cannot_emulate:
- DPRINTF("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n",
- b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode);
- svm_dump_inst(_regs.eip);
+ gdprintk(XENLOG_WARNING,
+ "Cannot emulate %02x at address %lx (%lx, mode %d)\n",
+ b, pc - 1, org_pc, mode);
return -1;
}
diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c
index a2cd37c364..ea93a59f8e 100644
--- a/xen/arch/x86/hvm/intercept.c
+++ b/xen/arch/x86/hvm/intercept.c
@@ -61,49 +61,39 @@ static inline void hvm_mmio_access(struct vcpu *v,
hvm_mmio_read_t read_handler,
hvm_mmio_write_t write_handler)
{
- ioreq_t *req;
- vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id);
unsigned int tmp1, tmp2;
unsigned long data;
- if (vio == NULL) {
- printk("vlapic_access: bad shared page\n");
- domain_crash_synchronous();
- }
-
- req = &vio->vp_ioreq;
-
- switch (req->type) {
+ switch ( p->type ) {
case IOREQ_TYPE_COPY:
{
- int sign = (req->df) ? -1 : 1, i;
-
- if (!req->pdata_valid) {
- if (req->dir == IOREQ_READ){
- req->u.data = read_handler(v, req->addr, req->size);
- } else { /* req->dir != IOREQ_READ */
- write_handler(v, req->addr, req->size, req->u.data);
- }
- } else { /* !req->pdata_valid */
- if (req->dir == IOREQ_READ) {
- for (i = 0; i < req->count; i++) {
+ if ( !p->data_is_ptr ) {
+ if ( p->dir == IOREQ_READ )
+ p->data = read_handler(v, p->addr, p->size);
+ else /* p->dir == IOREQ_WRITE */
+ write_handler(v, p->addr, p->size, p->data);
+ } else { /* p->data_is_ptr */
+ int i, sign = (p->df) ? -1 : 1;
+
+ if ( p->dir == IOREQ_READ ) {
+ for ( i = 0; i < p->count; i++ ) {
data = read_handler(v,
- req->addr + (sign * i * req->size),
- req->size);
- hvm_copy(&data,
- (unsigned long)p->u.pdata + (sign * i * req->size),
- p->size,
- HVM_COPY_OUT);
+ p->addr + (sign * i * p->size),
+ p->size);
+ (void)hvm_copy_to_guest_phys(
+ p->data + (sign * i * p->size),
+ &data,
+ p->size);
}
- } else { /* !req->dir == IOREQ_READ */
- for (i = 0; i < req->count; i++) {
- hvm_copy(&data,
- (unsigned long)p->u.pdata + (sign * i * req->size),
- p->size,
- HVM_COPY_IN);
+ } else {/* p->dir == IOREQ_WRITE */
+ for ( i = 0; i < p->count; i++ ) {
+ (void)hvm_copy_from_guest_phys(
+ &data,
+ p->data + (sign * i * p->size),
+ p->size);
write_handler(v,
- req->addr + (sign * i * req->size),
- req->size, data);
+ p->addr + (sign * i * p->size),
+ p->size, data);
}
}
}
@@ -111,44 +101,53 @@ static inline void hvm_mmio_access(struct vcpu *v,
}
case IOREQ_TYPE_AND:
- tmp1 = read_handler(v, req->addr, req->size);
- if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 & (unsigned long) req->u.data;
- write_handler(v, req->addr, req->size, tmp2);
+ tmp1 = read_handler(v, p->addr, p->size);
+ if ( p->dir == IOREQ_WRITE ) {
+ tmp2 = tmp1 & (unsigned long) p->data;
+ write_handler(v, p->addr, p->size, tmp2);
}
- req->u.data = tmp1;
+ p->data = tmp1;
+ break;
+
+ case IOREQ_TYPE_ADD:
+ tmp1 = read_handler(v, p->addr, p->size);
+ if (p->dir == IOREQ_WRITE) {
+ tmp2 = tmp1 + (unsigned long) p->data;
+ write_handler(v, p->addr, p->size, tmp2);
+ }
+ p->data = tmp1;
break;
case IOREQ_TYPE_OR:
- tmp1 = read_handler(v, req->addr, req->size);
- if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 | (unsigned long) req->u.data;
- write_handler(v, req->addr, req->size, tmp2);
+ tmp1 = read_handler(v, p->addr, p->size);
+ if ( p->dir == IOREQ_WRITE ) {
+ tmp2 = tmp1 | (unsigned long) p->data;
+ write_handler(v, p->addr, p->size, tmp2);
}
- req->u.data = tmp1;
+ p->data = tmp1;
break;
case IOREQ_TYPE_XOR:
- tmp1 = read_handler(v, req->addr, req->size);
- if (req->dir == IOREQ_WRITE) {
- tmp2 = tmp1 ^ (unsigned long) req->u.data;
- write_handler(v, req->addr, req->size, tmp2);
+ tmp1 = read_handler(v, p->addr, p->size);
+ if ( p->dir == IOREQ_WRITE ) {
+ tmp2 = tmp1 ^ (unsigned long) p->data;
+ write_handler(v, p->addr, p->size, tmp2);
}
- req->u.data = tmp1;
+ p->data = tmp1;
break;
case IOREQ_TYPE_XCHG:
- /*
+ /*
* Note that we don't need to be atomic here since VCPU is accessing
* its own local APIC.
*/
- tmp1 = read_handler(v, req->addr, req->size);
- write_handler(v, req->addr, req->size, (unsigned long) req->u.data);
- req->u.data = tmp1;
+ tmp1 = read_handler(v, p->addr, p->size);
+ write_handler(v, p->addr, p->size, (unsigned long) p->data);
+ p->data = tmp1;
break;
default:
- printk("error ioreq type for local APIC %x\n", req->type);
+ printk("hvm_mmio_access: error ioreq type %x\n", p->type);
domain_crash_synchronous();
break;
}
@@ -209,18 +208,17 @@ int hvm_mmio_intercept(ioreq_t *p)
struct vcpu *v = current;
int i;
- /* XXX currently only APIC use intercept */
- if ( !hvm_apic_support(v->domain) )
- return 0;
-
- for ( i = 0; i < HVM_MMIO_HANDLER_NR; i++ ) {
- if ( hvm_mmio_handlers[i]->check_handler(v, p->addr) ) {
+ for ( i = 0; i < HVM_MMIO_HANDLER_NR; i++ )
+ {
+ if ( hvm_mmio_handlers[i]->check_handler(v, p->addr) )
+ {
hvm_mmio_access(v, p,
hvm_mmio_handlers[i]->read_handler,
hvm_mmio_handlers[i]->write_handler);
return 1;
}
}
+
return 0;
}
@@ -248,18 +246,14 @@ int hvm_io_intercept(ioreq_t *p, int type)
return 0;
}
-int register_io_handler(unsigned long addr, unsigned long size,
- intercept_action_t action, int type)
+int register_io_handler(
+ struct domain *d, unsigned long addr, unsigned long size,
+ intercept_action_t action, int type)
{
- struct vcpu *v = current;
- struct hvm_io_handler *handler =
- &(v->domain->arch.hvm_domain.io_handler);
+ struct hvm_io_handler *handler = &d->arch.hvm_domain.io_handler;
int num = handler->num_slot;
- if (num >= MAX_IO_HANDLER) {
- printk("no extra space, register io interceptor failed!\n");
- domain_crash_synchronous();
- }
+ BUG_ON(num >= MAX_IO_HANDLER);
handler->hdl_list[num].addr = addr;
handler->hdl_list[num].size = size;
@@ -270,14 +264,6 @@ int register_io_handler(unsigned long addr, unsigned long size,
return 1;
}
-/* hooks function for the HLT instruction emulation wakeup */
-void hlt_timer_fn(void *data)
-{
- struct vcpu *v = data;
-
- hvm_prod_vcpu(v);
-}
-
static __inline__ void missed_ticks(struct periodic_time *pt)
{
s_time_t missed_ticks;
@@ -300,16 +286,19 @@ static __inline__ void missed_ticks(struct periodic_time *pt)
void pt_timer_fn(void *data)
{
struct vcpu *v = data;
- struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+ struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
pt->pending_intr_nr++;
pt->scheduled += pt->period;
- /* pick up missed timer tick */
+ /* Pick up missed timer ticks. */
missed_ticks(pt);
- if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) {
+
+ /* No need to run the timer while a VCPU is descheduled. */
+ if ( test_bit(_VCPUF_running, &v->vcpu_flags) )
set_timer(&pt->timer, pt->scheduled);
- }
+
+ vcpu_kick(v);
}
/* pick up missed timer ticks at deactive time */
@@ -325,20 +314,18 @@ void pickup_deactive_ticks(struct periodic_time *pt)
* period: fire frequency in ns.
*/
struct periodic_time * create_periodic_time(
- PITChannelState *s,
u32 period,
char irq,
- char one_shot)
+ char one_shot,
+ time_cb *cb,
+ void *data)
{
- struct vcpu *v = s->vcpu;
- struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+ struct periodic_time *pt = &(current->domain->arch.hvm_domain.pl_time.periodic_tm);
if ( pt->enabled ) {
- if ( v->vcpu_id != 0 ) {
- printk("HVM_PIT: start 2nd periodic time on non BSP!\n");
- }
stop_timer (&pt->timer);
pt->enabled = 0;
}
+ pt->bind_vcpu = 0; /* timer interrupt delivered to BSP by default */
pt->pending_intr_nr = 0;
pt->first_injected = 0;
if (period < 900000) { /* < 0.9 ms */
@@ -355,7 +342,8 @@ struct periodic_time * create_periodic_time(
pt->scheduled = NOW() + period;
set_timer (&pt->timer,pt->scheduled);
pt->enabled = 1;
- pt->priv = s;
+ pt->cb = cb;
+ pt->priv = data;
return pt;
}
diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
index ea564d2a2c..2006f09cb5 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -35,7 +35,7 @@
#include <asm/shadow.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
#include <asm/hvm/vpic.h>
#include <asm/hvm/vlapic.h>
@@ -81,9 +81,7 @@ static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *r
regs->ebx |= ((value & 0xFF) << 8);
break;
default:
- printk("Error: size:%x, index:%x are invalid!\n", size, index);
- domain_crash_synchronous();
- break;
+ goto crash;
}
break;
case WORD:
@@ -121,9 +119,7 @@ static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *r
regs->edi |= (value & 0xFFFF);
break;
default:
- printk("Error: size:%x, index:%x are invalid!\n", size, index);
- domain_crash_synchronous();
- break;
+ goto crash;
}
break;
case LONG:
@@ -153,15 +149,13 @@ static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *r
regs->edi = value;
break;
default:
- printk("Error: size:%x, index:%x are invalid!\n", size, index);
- domain_crash_synchronous();
- break;
+ goto crash;
}
break;
default:
- printk("Error: size:%x, index:%x are invalid!\n", size, index);
+ crash:
+ gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n", size, index);
domain_crash_synchronous();
- break;
}
}
#else
@@ -184,7 +178,7 @@ static inline void __set_reg_value(unsigned long *reg, int size, long value)
*reg = value;
break;
default:
- printk("Error: <__set_reg_value>: size:%x is invalid\n", size);
+ gdprintk(XENLOG_ERR, "size:%x is invalid\n", size);
domain_crash_synchronous();
}
}
@@ -226,7 +220,8 @@ static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *r
regs->rbx |= ((value & 0xFF) << 8);
break;
default:
- printk("Error: size:%x, index:%x are invalid!\n", size, index);
+ gdprintk(XENLOG_ERR, "size:%x, index:%x are invalid!\n",
+ size, index);
domain_crash_synchronous();
break;
}
@@ -283,7 +278,7 @@ static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *r
__set_reg_value(&regs->r15, size, value);
break;
default:
- printk("Error: <set_reg_value> Invalid index\n");
+ gdprintk(XENLOG_ERR, "Invalid index\n");
domain_crash_synchronous();
}
return;
@@ -365,22 +360,22 @@ static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p,
unsigned long old_eax;
int sign = p->df ? -1 : 1;
- if ( p->pdata_valid || (pio_opp->flags & OVERLAP) )
+ if ( p->data_is_ptr || (pio_opp->flags & OVERLAP) )
{
if ( pio_opp->flags & REPZ )
regs->ecx -= p->count;
+
if ( p->dir == IOREQ_READ )
{
- regs->edi += sign * p->count * p->size;
if ( pio_opp->flags & OVERLAP )
{
- unsigned long addr = regs->edi;
- if (hvm_realmode(current))
- addr += regs->es << 4;
- if (sign > 0)
- addr -= p->size;
- hvm_copy(&p->u.data, addr, p->size, HVM_COPY_OUT);
+ unsigned long addr = pio_opp->addr;
+ if ( hvm_paging_enabled(current) )
+ (void)hvm_copy_to_guest_virt(addr, &p->data, p->size);
+ else
+ (void)hvm_copy_to_guest_phys(addr, &p->data, p->size);
}
+ regs->edi += sign * p->count * p->size;
}
else /* p->dir == IOREQ_WRITE */
{
@@ -394,18 +389,19 @@ static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p,
switch ( p->size )
{
case 1:
- regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
+ regs->eax = (old_eax & 0xffffff00) | (p->data & 0xff);
break;
case 2:
- regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
+ regs->eax = (old_eax & 0xffff0000) | (p->data & 0xffff);
break;
case 4:
- regs->eax = (p->u.data & 0xffffffff);
+ regs->eax = (p->data & 0xffffffff);
break;
default:
printk("Error: %s unknown port size\n", __FUNCTION__);
domain_crash_synchronous();
}
+ TRACE_VMEXIT(3, regs->eax);
}
}
@@ -425,7 +421,7 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
case INSTR_MOV:
if (dst & REGISTER) {
index = operand_index(dst);
- set_reg_value(size, index, 0, regs, p->u.data);
+ set_reg_value(size, index, 0, regs, p->data);
}
break;
@@ -433,15 +429,15 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
if (dst & REGISTER) {
switch (size) {
case BYTE:
- p->u.data &= 0xFFULL;
+ p->data &= 0xFFULL;
break;
case WORD:
- p->u.data &= 0xFFFFULL;
+ p->data &= 0xFFFFULL;
break;
case LONG:
- p->u.data &= 0xFFFFFFFFULL;
+ p->data &= 0xFFFFFFFFULL;
break;
default:
@@ -449,7 +445,7 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
domain_crash_synchronous();
}
index = operand_index(dst);
- set_reg_value(operand_size(dst), index, 0, regs, p->u.data);
+ set_reg_value(operand_size(dst), index, 0, regs, p->data);
}
break;
@@ -457,21 +453,21 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
if (dst & REGISTER) {
switch (size) {
case BYTE:
- p->u.data &= 0xFFULL;
- if ( p->u.data & 0x80ULL )
- p->u.data |= 0xFFFFFFFFFFFFFF00ULL;
+ p->data &= 0xFFULL;
+ if ( p->data & 0x80ULL )
+ p->data |= 0xFFFFFFFFFFFFFF00ULL;
break;
case WORD:
- p->u.data &= 0xFFFFULL;
- if ( p->u.data & 0x8000ULL )
- p->u.data |= 0xFFFFFFFFFFFF0000ULL;
+ p->data &= 0xFFFFULL;
+ if ( p->data & 0x8000ULL )
+ p->data |= 0xFFFFFFFFFFFF0000ULL;
break;
case LONG:
- p->u.data &= 0xFFFFFFFFULL;
- if ( p->u.data & 0x80000000ULL )
- p->u.data |= 0xFFFFFFFF00000000ULL;
+ p->data &= 0xFFFFFFFFULL;
+ if ( p->data & 0x80000000ULL )
+ p->data |= 0xFFFFFFFF00000000ULL;
break;
default:
@@ -479,25 +475,28 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
domain_crash_synchronous();
}
index = operand_index(dst);
- set_reg_value(operand_size(dst), index, 0, regs, p->u.data);
+ set_reg_value(operand_size(dst), index, 0, regs, p->data);
}
break;
case INSTR_MOVS:
sign = p->df ? -1 : 1;
- regs->esi += sign * p->count * p->size;
- regs->edi += sign * p->count * p->size;
+
+ if (mmio_opp->flags & REPZ)
+ regs->ecx -= p->count;
if ((mmio_opp->flags & OVERLAP) && p->dir == IOREQ_READ) {
- unsigned long addr = regs->edi;
+ unsigned long addr = mmio_opp->addr;
- if (sign > 0)
- addr -= p->size;
- hvm_copy(&p->u.data, addr, p->size, HVM_COPY_OUT);
+ if (hvm_paging_enabled(current))
+ (void)hvm_copy_to_guest_virt(addr, &p->data, p->size);
+ else
+ (void)hvm_copy_to_guest_phys(addr, &p->data, p->size);
}
- if (mmio_opp->flags & REPZ)
- regs->ecx -= p->count;
+ regs->esi += sign * p->count * p->size;
+ regs->edi += sign * p->count * p->size;
+
break;
case INSTR_STOS:
@@ -518,14 +517,29 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
if (src & REGISTER) {
index = operand_index(src);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data & value;
+ diff = (unsigned long) p->data & value;
} else if (src & IMMEDIATE) {
value = mmio_opp->immediate;
- diff = (unsigned long) p->u.data & value;
+ diff = (unsigned long) p->data & value;
} else if (src & MEMORY) {
index = operand_index(dst);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data & value;
+ diff = (unsigned long) p->data & value;
+ set_reg_value(size, index, 0, regs, diff);
+ }
+
+ case INSTR_ADD:
+ if (src & REGISTER) {
+ index = operand_index(src);
+ value = get_reg_value(size, index, 0, regs);
+ diff = (unsigned long) p->data + value;
+ } else if (src & IMMEDIATE) {
+ value = mmio_opp->immediate;
+ diff = (unsigned long) p->data + value;
+ } else if (src & MEMORY) {
+ index = operand_index(dst);
+ value = get_reg_value(size, index, 0, regs);
+ diff = (unsigned long) p->data + value;
set_reg_value(size, index, 0, regs, diff);
}
@@ -545,14 +559,14 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
if (src & REGISTER) {
index = operand_index(src);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data | value;
+ diff = (unsigned long) p->data | value;
} else if (src & IMMEDIATE) {
value = mmio_opp->immediate;
- diff = (unsigned long) p->u.data | value;
+ diff = (unsigned long) p->data | value;
} else if (src & MEMORY) {
index = operand_index(dst);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data | value;
+ diff = (unsigned long) p->data | value;
set_reg_value(size, index, 0, regs, diff);
}
@@ -572,14 +586,14 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
if (src & REGISTER) {
index = operand_index(src);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data ^ value;
+ diff = (unsigned long) p->data ^ value;
} else if (src & IMMEDIATE) {
value = mmio_opp->immediate;
- diff = (unsigned long) p->u.data ^ value;
+ diff = (unsigned long) p->data ^ value;
} else if (src & MEMORY) {
index = operand_index(dst);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data ^ value;
+ diff = (unsigned long) p->data ^ value;
set_reg_value(size, index, 0, regs, diff);
}
@@ -596,17 +610,20 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
break;
case INSTR_CMP:
+ case INSTR_SUB:
if (src & REGISTER) {
index = operand_index(src);
value = get_reg_value(size, index, 0, regs);
- diff = (unsigned long) p->u.data - value;
+ diff = (unsigned long) p->data - value;
} else if (src & IMMEDIATE) {
value = mmio_opp->immediate;
- diff = (unsigned long) p->u.data - value;
+ diff = (unsigned long) p->data - value;
} else if (src & MEMORY) {
index = operand_index(dst);
value = get_reg_value(size, index, 0, regs);
- diff = value - (unsigned long) p->u.data;
+ diff = value - (unsigned long) p->data;
+ if ( mmio_opp->instr == INSTR_SUB )
+ set_reg_value(size, index, 0, regs, diff);
}
/*
@@ -615,9 +632,9 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
*/
regs->eflags &= ~(X86_EFLAGS_CF|X86_EFLAGS_PF|X86_EFLAGS_AF|
X86_EFLAGS_ZF|X86_EFLAGS_SF|X86_EFLAGS_OF);
- set_eflags_CF(size, value, (unsigned long) p->u.data, regs);
- set_eflags_OF(size, diff, value, (unsigned long) p->u.data, regs);
- set_eflags_AF(size, diff, value, (unsigned long) p->u.data, regs);
+ set_eflags_CF(size, value, (unsigned long) p->data, regs);
+ set_eflags_OF(size, diff, value, (unsigned long) p->data, regs);
+ set_eflags_AF(size, diff, value, (unsigned long) p->data, regs);
set_eflags_ZF(size, diff, regs);
set_eflags_SF(size, diff, regs);
set_eflags_PF(size, diff, regs);
@@ -633,7 +650,7 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
index = operand_index(dst);
value = get_reg_value(size, index, 0, regs);
}
- diff = (unsigned long) p->u.data & value;
+ diff = (unsigned long) p->data & value;
/*
* Sets the SF, ZF, and PF status flags. CF and OF are set to 0
@@ -653,7 +670,7 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
}
else if ( src & IMMEDIATE )
value = mmio_opp->immediate;
- if (p->u.data & (1 << (value & ((1 << 5) - 1))))
+ if (p->data & (1 << (value & ((1 << 5) - 1))))
regs->eflags |= X86_EFLAGS_CF;
else
regs->eflags &= ~X86_EFLAGS_CF;
@@ -663,10 +680,10 @@ static void hvm_mmio_assist(struct cpu_user_regs *regs, ioreq_t *p,
case INSTR_XCHG:
if (src & REGISTER) {
index = operand_index(src);
- set_reg_value(size, index, 0, regs, p->u.data);
+ set_reg_value(size, index, 0, regs, p->data);
} else {
index = operand_index(dst);
- set_reg_value(size, index, 0, regs, p->u.data);
+ set_reg_value(size, index, 0, regs, p->data);
}
break;
}
@@ -677,7 +694,8 @@ void hvm_interrupt_post(struct vcpu *v, int vector, int type)
struct periodic_time *pt =
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
- if ( is_pit_irq(v, vector, type) ) {
+ if ( pt->enabled && v->vcpu_id == pt->bind_vcpu
+ && is_periodic_irq(v, vector, type) ) {
if ( !pt->first_injected ) {
pt->pending_intr_nr = 0;
pt->last_plt_gtime = hvm_get_guest_time(v);
@@ -688,8 +706,9 @@ void hvm_interrupt_post(struct vcpu *v, int vector, int type)
pt->pending_intr_nr--;
pt->last_plt_gtime += pt->period_cycles;
hvm_set_guest_time(v, pt->last_plt_gtime);
- pit_time_fired(v, pt->priv);
}
+ if (pt->cb)
+ pt->cb(v, pt->priv);
}
switch(type) {
@@ -712,27 +731,27 @@ void hvm_io_assist(struct vcpu *v)
io_opp = &v->arch.hvm_vcpu.io_op;
regs = &io_opp->io_context;
+ vio = get_vio(v->domain, v->vcpu_id);
- vio = get_vio(v->domain, v->vcpu_id);
-
- if ( vio == 0 ) {
- printf("bad shared page: %lx\n", (unsigned long)vio);
+ p = &vio->vp_ioreq;
+ if ( p->state != STATE_IORESP_READY )
+ {
+ gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
domain_crash_synchronous();
}
- p = &vio->vp_ioreq;
+ rmb(); /* see IORESP_READY /then/ read contents of ioreq */
- if ( p->state == STATE_IORESP_READY ) {
- p->state = STATE_INVALID;
- if ( p->type == IOREQ_TYPE_PIO )
- hvm_pio_assist(regs, p, io_opp);
- else
- hvm_mmio_assist(regs, p, io_opp);
+ p->state = STATE_IOREQ_NONE;
- /* Copy register changes back into current guest state. */
- hvm_load_cpu_guest_regs(v, regs);
- memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES);
- }
+ if ( p->type == IOREQ_TYPE_PIO )
+ hvm_pio_assist(regs, p, io_opp);
+ else
+ hvm_mmio_assist(regs, p, io_opp);
+
+ /* Copy register changes back into current guest state. */
+ hvm_load_cpu_guest_regs(v, regs);
+ memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES);
}
/*
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
new file mode 100644
index 0000000000..b65799b2aa
--- /dev/null
+++ b/xen/arch/x86/hvm/irq.c
@@ -0,0 +1,227 @@
+/******************************************************************************
+ * irq.c
+ *
+ * Interrupt distribution and delivery logic.
+ *
+ * Copyright (c) 2006, K A Fraser, XenSource Inc.
+ *
+ * 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 <xen/config.h>
+#include <xen/types.h>
+#include <xen/event.h>
+#include <xen/sched.h>
+#include <asm/hvm/domain.h>
+
+void hvm_pci_intx_assert(
+ struct domain *d, unsigned int device, unsigned int intx)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ unsigned int gsi, link, isa_irq;
+
+ ASSERT((device <= 31) && (intx <= 3));
+
+ spin_lock(&hvm_irq->lock);
+
+ if ( __test_and_set_bit(device*4 + intx, &hvm_irq->pci_intx) )
+ goto out;
+
+ gsi = hvm_pci_intx_gsi(device, intx);
+ if ( hvm_irq->gsi_assert_count[gsi]++ == 0 )
+ vioapic_irq_positive_edge(d, gsi);
+
+ link = hvm_pci_intx_link(device, intx);
+ isa_irq = hvm_irq->pci_link_route[link];
+ if ( (hvm_irq->pci_link_assert_count[link]++ == 0) && isa_irq &&
+ (hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, isa_irq);
+ vpic_irq_positive_edge(d, isa_irq);
+ }
+
+ out:
+ spin_unlock(&hvm_irq->lock);
+}
+
+void hvm_pci_intx_deassert(
+ struct domain *d, unsigned int device, unsigned int intx)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ unsigned int gsi, link, isa_irq;
+
+ ASSERT((device <= 31) && (intx <= 3));
+
+ spin_lock(&hvm_irq->lock);
+
+ if ( !__test_and_clear_bit(device*4 + intx, &hvm_irq->pci_intx) )
+ goto out;
+
+ gsi = hvm_pci_intx_gsi(device, intx);
+ --hvm_irq->gsi_assert_count[gsi];
+
+ link = hvm_pci_intx_link(device, intx);
+ isa_irq = hvm_irq->pci_link_route[link];
+ if ( (--hvm_irq->pci_link_assert_count[link] == 0) && isa_irq &&
+ (--hvm_irq->gsi_assert_count[isa_irq] == 0) )
+ vpic_irq_negative_edge(d, isa_irq);
+
+ out:
+ spin_unlock(&hvm_irq->lock);
+}
+
+void hvm_isa_irq_assert(
+ struct domain *d, unsigned int isa_irq)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ ASSERT(isa_irq <= 15);
+
+ spin_lock(&hvm_irq->lock);
+
+ if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq) &&
+ (hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, isa_irq);
+ vpic_irq_positive_edge(d, isa_irq);
+ }
+
+ spin_unlock(&hvm_irq->lock);
+}
+
+void hvm_isa_irq_deassert(
+ struct domain *d, unsigned int isa_irq)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+ ASSERT(isa_irq <= 15);
+
+ spin_lock(&hvm_irq->lock);
+
+ if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq) &&
+ (--hvm_irq->gsi_assert_count[isa_irq] == 0) )
+ vpic_irq_negative_edge(d, isa_irq);
+
+ spin_unlock(&hvm_irq->lock);
+}
+
+void hvm_set_callback_irq_level(void)
+{
+ struct vcpu *v = current;
+ struct domain *d = v->domain;
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ unsigned int gsi = hvm_irq->callback_gsi;
+
+ /* Fast lock-free tests. */
+ if ( (v->vcpu_id != 0) || (gsi == 0) )
+ return;
+
+ spin_lock(&hvm_irq->lock);
+
+ gsi = hvm_irq->callback_gsi;
+ if ( gsi == 0 )
+ goto out;
+
+ if ( local_events_need_delivery() )
+ {
+ if ( !__test_and_set_bit(0, &hvm_irq->callback_irq_wire) &&
+ (hvm_irq->gsi_assert_count[gsi]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, gsi);
+ if ( gsi <= 15 )
+ vpic_irq_positive_edge(d, gsi);
+ }
+ }
+ else
+ {
+ if ( __test_and_clear_bit(0, &hvm_irq->callback_irq_wire) &&
+ (--hvm_irq->gsi_assert_count[gsi] == 0) )
+ {
+ if ( gsi <= 15 )
+ vpic_irq_negative_edge(d, gsi);
+ }
+ }
+
+ out:
+ spin_unlock(&hvm_irq->lock);
+}
+
+void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ u8 old_isa_irq;
+
+ ASSERT((link <= 3) && (isa_irq <= 15));
+
+ spin_lock(&hvm_irq->lock);
+
+ old_isa_irq = hvm_irq->pci_link_route[link];
+ if ( old_isa_irq == isa_irq )
+ goto out;
+ hvm_irq->pci_link_route[link] = isa_irq;
+
+ if ( hvm_irq->pci_link_assert_count[link] == 0 )
+ goto out;
+
+ if ( old_isa_irq && (--hvm_irq->gsi_assert_count[old_isa_irq] == 0) )
+ vpic_irq_negative_edge(d, isa_irq);
+
+ if ( isa_irq && (hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, isa_irq);
+ vpic_irq_positive_edge(d, isa_irq);
+ }
+
+ out:
+ spin_unlock(&hvm_irq->lock);
+
+ dprintk(XENLOG_G_INFO, "Dom%u PCI link %u changed %u -> %u\n",
+ d->domain_id, link, old_isa_irq, isa_irq);
+}
+
+void hvm_set_callback_gsi(struct domain *d, unsigned int gsi)
+{
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ unsigned int old_gsi;
+
+ if ( gsi >= ARRAY_SIZE(hvm_irq->gsi_assert_count) )
+ gsi = 0;
+
+ spin_lock(&hvm_irq->lock);
+
+ old_gsi = hvm_irq->callback_gsi;
+ if ( old_gsi == gsi )
+ goto out;
+ hvm_irq->callback_gsi = gsi;
+
+ if ( !test_bit(0, &hvm_irq->callback_irq_wire) )
+ goto out;
+
+ if ( old_gsi && (--hvm_irq->gsi_assert_count[old_gsi] == 0) )
+ if ( old_gsi <= 15 )
+ vpic_irq_negative_edge(d, old_gsi);
+
+ if ( gsi && (hvm_irq->gsi_assert_count[gsi]++ == 0) )
+ {
+ vioapic_irq_positive_edge(d, gsi);
+ if ( gsi <= 15 )
+ vpic_irq_positive_edge(d, gsi);
+ }
+
+ out:
+ spin_unlock(&hvm_irq->lock);
+
+ dprintk(XENLOG_G_INFO, "Dom%u callback GSI changed %u -> %u\n",
+ d->domain_id, old_gsi, gsi);
+}
diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c
index 0e4ac486b7..46eab76175 100644
--- a/xen/arch/x86/hvm/platform.c
+++ b/xen/arch/x86/hvm/platform.c
@@ -28,8 +28,10 @@
#include <xen/trace.h>
#include <xen/sched.h>
#include <asm/regs.h>
+#include <asm/x86_emulate.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
+#include <asm/hvm/io.h>
#include <public/hvm/ioreq.h>
#include <xen/lib.h>
@@ -39,10 +41,13 @@
#define DECODE_success 1
#define DECODE_failure 0
+#define mk_operand(size_reg, index, seg, flag) \
+ (((size_reg) << 24) | ((index) << 16) | ((seg) << 8) | (flag))
+
#if defined (__x86_64__)
static inline long __get_reg_value(unsigned long reg, int size)
{
- switch(size) {
+ switch ( size ) {
case BYTE_64:
return (char)(reg & 0xFF);
case WORD:
@@ -52,15 +57,15 @@ static inline long __get_reg_value(unsigned long reg, int size)
case QUAD:
return (long)(reg);
default:
- printf("Error: (__get_reg_value) Invalid reg size\n");
+ printk("Error: (__get_reg_value) Invalid reg size\n");
domain_crash_synchronous();
}
}
long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
{
- if (size == BYTE) {
- switch (index) {
+ if ( size == BYTE ) {
+ switch ( index ) {
case 0: /* %al */
return (char)(regs->rax & 0xFF);
case 1: /* %cl */
@@ -78,13 +83,13 @@ long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
case 7: /* %bh */
return (char)((regs->rbx & 0xFF00) >> 8);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
/* NOTREACHED */
}
- switch (index) {
+ switch ( index ) {
case 0: return __get_reg_value(regs->rax, size);
case 1: return __get_reg_value(regs->rcx, size);
case 2: return __get_reg_value(regs->rdx, size);
@@ -102,28 +107,28 @@ long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
case 14: return __get_reg_value(regs->r14, size);
case 15: return __get_reg_value(regs->r15, size);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
#elif defined (__i386__)
static inline long __get_reg_value(unsigned long reg, int size)
{
- switch(size) {
+ switch ( size ) {
case WORD:
return (short)(reg & 0xFFFF);
case LONG:
return (int)(reg & 0xFFFFFFFF);
default:
- printf("Error: (__get_reg_value) Invalid reg size\n");
+ printk("Error: (__get_reg_value) Invalid reg size\n");
domain_crash_synchronous();
}
}
long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
{
- if (size == BYTE) {
- switch (index) {
+ if ( size == BYTE ) {
+ switch ( index ) {
case 0: /* %al */
return (char)(regs->eax & 0xFF);
case 1: /* %cl */
@@ -141,12 +146,12 @@ long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
case 7: /* %bh */
return (char)((regs->ebx & 0xFF00) >> 8);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
- switch (index) {
+ switch ( index ) {
case 0: return __get_reg_value(regs->eax, size);
case 1: return __get_reg_value(regs->ecx, size);
case 2: return __get_reg_value(regs->edx, size);
@@ -156,26 +161,30 @@ long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs)
case 6: return __get_reg_value(regs->esi, size);
case 7: return __get_reg_value(regs->edi, size);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
#endif
static inline unsigned char *check_prefix(unsigned char *inst,
- struct instruction *thread_inst, unsigned char *rex_p)
+ struct hvm_io_op *mmio_op,
+ unsigned char *ad_size,
+ unsigned char *op_size,
+ unsigned char *seg_sel,
+ unsigned char *rex_p)
{
- while (1) {
- switch (*inst) {
+ while ( 1 ) {
+ switch ( *inst ) {
/* rex prefix for em64t instructions */
- case 0x40 ... 0x4e:
+ case 0x40 ... 0x4f:
*rex_p = *inst;
break;
case 0xf3: /* REPZ */
- thread_inst->flags = REPZ;
+ mmio_op->flags = REPZ;
break;
case 0xf2: /* REPNZ */
- thread_inst->flags = REPNZ;
+ mmio_op->flags = REPNZ;
break;
case 0xf0: /* LOCK */
break;
@@ -185,12 +194,13 @@ static inline unsigned char *check_prefix(unsigned char *inst,
case 0x26: /* ES */
case 0x64: /* FS */
case 0x65: /* GS */
- thread_inst->seg_sel = *inst;
+ *seg_sel = *inst;
break;
case 0x66: /* 32bit->16bit */
- thread_inst->op_size = WORD;
+ *op_size = WORD;
break;
case 0x67:
+ *ad_size = WORD;
break;
default:
return inst;
@@ -199,7 +209,7 @@ static inline unsigned char *check_prefix(unsigned char *inst,
}
}
-static inline unsigned long get_immediate(int op16,const unsigned char *inst, int op_size)
+static inline unsigned long get_immediate(int ad_size, const unsigned char *inst, int op_size)
{
int mod, reg, rm;
unsigned long val = 0;
@@ -210,16 +220,19 @@ static inline unsigned long get_immediate(int op16,const unsigned char *inst, in
rm = *inst & 7;
inst++; //skip ModR/M byte
- if (mod != 3 && rm == 4) {
+ if ( ad_size != WORD && mod != 3 && rm == 4 ) {
+ rm = *inst & 7;
inst++; //skip SIB byte
}
- switch(mod) {
+ switch ( mod ) {
case 0:
- if (rm == 5 || rm == 4) {
- if (op16)
+ if ( ad_size == WORD ) {
+ if ( rm == 6 )
inst = inst + 2; //disp16, skip 2 bytes
- else
+ }
+ else {
+ if ( rm == 5 )
inst = inst + 4; //disp32, skip 4 bytes
}
break;
@@ -227,17 +240,17 @@ static inline unsigned long get_immediate(int op16,const unsigned char *inst, in
inst++; //disp8, skip 1 byte
break;
case 2:
- if (op16)
+ if ( ad_size == WORD )
inst = inst + 2; //disp16, skip 2 bytes
else
inst = inst + 4; //disp32, skip 4 bytes
break;
}
- if (op_size == QUAD)
+ if ( op_size == QUAD )
op_size = LONG;
- for (i = 0; i < op_size; i++) {
+ for ( i = 0; i < op_size; i++ ) {
val |= (*inst++ & 0xff) << (8 * i);
}
@@ -257,7 +270,7 @@ static inline int get_index(const unsigned char *inst, unsigned char rex)
rex_b = rex & 1;
//Only one operand in the instruction is register
- if (mod == 3) {
+ if ( mod == 3 ) {
return (rm + (rex_b << 3));
} else {
return (reg + (rex_r << 3));
@@ -265,53 +278,51 @@ static inline int get_index(const unsigned char *inst, unsigned char rex)
return 0;
}
-static void init_instruction(struct instruction *mmio_inst)
+static void init_instruction(struct hvm_io_op *mmio_op)
{
- mmio_inst->instr = 0;
- mmio_inst->op_size = 0;
- mmio_inst->immediate = 0;
- mmio_inst->seg_sel = 0;
+ mmio_op->instr = 0;
- mmio_inst->operand[0] = 0;
- mmio_inst->operand[1] = 0;
+ mmio_op->flags = 0;
- mmio_inst->flags = 0;
+ mmio_op->operand[0] = 0;
+ mmio_op->operand[1] = 0;
+ mmio_op->immediate = 0;
}
-#define GET_OP_SIZE_FOR_BYTE(op_size) \
+#define GET_OP_SIZE_FOR_BYTE(size_reg) \
do { \
- if (rex) \
- op_size = BYTE_64; \
+ if ( rex ) \
+ (size_reg) = BYTE_64; \
else \
- op_size = BYTE; \
- } while(0)
+ (size_reg) = BYTE; \
+ } while( 0 )
#define GET_OP_SIZE_FOR_NONEBYTE(op_size) \
do { \
- if (rex & 0x8) \
- op_size = QUAD; \
- else if (op_size != WORD) \
- op_size = LONG; \
- } while(0)
+ if ( rex & 0x8 ) \
+ (op_size) = QUAD; \
+ else if ( (op_size) != WORD ) \
+ (op_size) = LONG; \
+ } while( 0 )
/*
* Decode mem,accumulator operands (as in <opcode> m8/m16/m32, al,ax,eax)
*/
-static int mem_acc(unsigned char size, struct instruction *instr)
+static inline int mem_acc(unsigned char size, struct hvm_io_op *mmio)
{
- instr->operand[0] = mk_operand(size, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(size, 0, 0, REGISTER);
+ mmio->operand[0] = mk_operand(size, 0, 0, MEMORY);
+ mmio->operand[1] = mk_operand(size, 0, 0, REGISTER);
return DECODE_success;
}
/*
* Decode accumulator,mem operands (as in <opcode> al,ax,eax, m8/m16/m32)
*/
-static int acc_mem(unsigned char size, struct instruction *instr)
+static inline int acc_mem(unsigned char size, struct hvm_io_op *mmio)
{
- instr->operand[0] = mk_operand(size, 0, 0, REGISTER);
- instr->operand[1] = mk_operand(size, 0, 0, MEMORY);
+ mmio->operand[0] = mk_operand(size, 0, 0, REGISTER);
+ mmio->operand[1] = mk_operand(size, 0, 0, MEMORY);
return DECODE_success;
}
@@ -319,12 +330,12 @@ static int acc_mem(unsigned char size, struct instruction *instr)
* Decode mem,reg operands (as in <opcode> r32/16, m32/16)
*/
static int mem_reg(unsigned char size, unsigned char *opcode,
- struct instruction *instr, unsigned char rex)
+ struct hvm_io_op *mmio_op, unsigned char rex)
{
int index = get_index(opcode + 1, rex);
- instr->operand[0] = mk_operand(size, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(size, index, 0, REGISTER);
+ mmio_op->operand[0] = mk_operand(size, 0, 0, MEMORY);
+ mmio_op->operand[1] = mk_operand(size, index, 0, REGISTER);
return DECODE_success;
}
@@ -332,248 +343,310 @@ static int mem_reg(unsigned char size, unsigned char *opcode,
* Decode reg,mem operands (as in <opcode> m32/16, r32/16)
*/
static int reg_mem(unsigned char size, unsigned char *opcode,
- struct instruction *instr, unsigned char rex)
+ struct hvm_io_op *mmio_op, unsigned char rex)
{
int index = get_index(opcode + 1, rex);
- instr->operand[0] = mk_operand(size, index, 0, REGISTER);
- instr->operand[1] = mk_operand(size, 0, 0, MEMORY);
+ mmio_op->operand[0] = mk_operand(size, index, 0, REGISTER);
+ mmio_op->operand[1] = mk_operand(size, 0, 0, MEMORY);
return DECODE_success;
}
-static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *instr)
+static int mmio_decode(int mode, unsigned char *opcode,
+ struct hvm_io_op *mmio_op,
+ unsigned char *ad_size, unsigned char *op_size,
+ unsigned char *seg_sel)
{
unsigned char size_reg = 0;
unsigned char rex = 0;
int index;
- init_instruction(instr);
+ *ad_size = 0;
+ *op_size = 0;
+ *seg_sel = 0;
+ init_instruction(mmio_op);
+
+ opcode = check_prefix(opcode, mmio_op, ad_size, op_size, seg_sel, &rex);
+
+ switch ( mode ) {
+ case X86EMUL_MODE_REAL: /* meaning is reversed */
+ case X86EMUL_MODE_PROT16:
+ if ( *op_size == WORD )
+ *op_size = LONG;
+ else if ( *op_size == LONG )
+ *op_size = WORD;
+ else if ( *op_size == 0 )
+ *op_size = WORD;
+ if ( *ad_size == WORD )
+ *ad_size = LONG;
+ else if ( *ad_size == LONG )
+ *ad_size = WORD;
+ else if ( *ad_size == 0 )
+ *ad_size = WORD;
+ break;
+ case X86EMUL_MODE_PROT32:
+ if ( *op_size == 0 )
+ *op_size = LONG;
+ if ( *ad_size == 0 )
+ *ad_size = LONG;
+ break;
+#ifdef __x86_64__
+ case X86EMUL_MODE_PROT64:
+ if ( *op_size == 0 )
+ *op_size = rex & 0x8 ? QUAD : LONG;
+ if ( *ad_size == 0 )
+ *ad_size = QUAD;
+ break;
+#endif
+ }
- opcode = check_prefix(opcode, instr, &rex);
+ /* the operands order in comments conforms to AT&T convention */
- if (realmode) { /* meaning is reversed */
- if (instr->op_size == WORD)
- instr->op_size = LONG;
- else if (instr->op_size == LONG)
- instr->op_size = WORD;
- else if (instr->op_size == 0)
- instr->op_size = WORD;
- }
+ switch ( *opcode ) {
+
+ case 0x00: /* add r8, m8 */
+ mmio_op->instr = INSTR_ADD;
+ *op_size = BYTE;
+ GET_OP_SIZE_FOR_BYTE(size_reg);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
- switch (*opcode) {
- case 0x0A: /* or r8, m8 */
- instr->instr = INSTR_OR;
- instr->op_size = BYTE;
+ case 0x0A: /* or m8, r8 */
+ mmio_op->instr = INSTR_OR;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_reg(size_reg, opcode, instr, rex);
+ return mem_reg(size_reg, opcode, mmio_op, rex);
case 0x0B: /* or m32/16, r32/16 */
- instr->instr = INSTR_OR;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return mem_reg(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_OR;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_reg(*op_size, opcode, mmio_op, rex);
case 0x20: /* and r8, m8 */
- instr->instr = INSTR_AND;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_AND;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return reg_mem(size_reg, opcode, instr, rex);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
case 0x21: /* and r32/16, m32/16 */
- instr->instr = INSTR_AND;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return reg_mem(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_AND;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
case 0x22: /* and m8, r8 */
- instr->instr = INSTR_AND;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_AND;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_reg(size_reg, opcode, instr, rex);
+ return mem_reg(size_reg, opcode, mmio_op, rex);
case 0x23: /* and m32/16, r32/16 */
- instr->instr = INSTR_AND;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return mem_reg(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_AND;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_reg(*op_size, opcode, mmio_op, rex);
+
+ case 0x2B: /* sub m32/16, r32/16 */
+ mmio_op->instr = INSTR_SUB;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_reg(*op_size, opcode, mmio_op, rex);
case 0x30: /* xor r8, m8 */
- instr->instr = INSTR_XOR;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_XOR;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return reg_mem(size_reg, opcode, instr, rex);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
case 0x31: /* xor r32/16, m32/16 */
- instr->instr = INSTR_XOR;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return reg_mem(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_XOR;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
+
+ case 0x32: /* xor m8, r8 */
+ mmio_op->instr = INSTR_XOR;
+ *op_size = BYTE;
+ GET_OP_SIZE_FOR_BYTE(size_reg);
+ return mem_reg(size_reg, opcode, mmio_op, rex);
- case 0x32: /* xor m8, r8*/
- instr->instr = INSTR_XOR;
- instr->op_size = BYTE;
+ case 0x38: /* cmp r8, m8 */
+ mmio_op->instr = INSTR_CMP;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_reg(size_reg, opcode, instr, rex);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
case 0x39: /* cmp r32/16, m32/16 */
- instr->instr = INSTR_CMP;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return reg_mem(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_CMP;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
+
+ case 0x3A: /* cmp m8, r8 */
+ mmio_op->instr = INSTR_CMP;
+ *op_size = BYTE;
+ GET_OP_SIZE_FOR_BYTE(size_reg);
+ return mem_reg(size_reg, opcode, mmio_op, rex);
case 0x3B: /* cmp m32/16, r32/16 */
- instr->instr = INSTR_CMP;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return mem_reg(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_CMP;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_reg(*op_size, opcode, mmio_op, rex);
case 0x80:
case 0x81:
case 0x83:
- {
- unsigned char ins_subtype = (opcode[1] >> 3) & 7;
+ {
+ unsigned char ins_subtype = (opcode[1] >> 3) & 7;
- if (opcode[0] == 0x80) {
- GET_OP_SIZE_FOR_BYTE(size_reg);
- instr->op_size = BYTE;
- } else if (opcode[0] == 0x81) {
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- size_reg = instr->op_size;
- } else if (opcode[0] == 0x83) {
- GET_OP_SIZE_FOR_NONEBYTE(size_reg);
- instr->op_size = size_reg;
- }
-
- /* opcode 0x83 always has a single byte operand */
- if (opcode[0] == 0x83)
- instr->immediate =
- (signed char)get_immediate(realmode, opcode+1, BYTE);
- else
- instr->immediate =
- get_immediate(realmode, opcode+1, instr->op_size);
-
- instr->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
- instr->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
-
- switch (ins_subtype) {
- case 7: /* cmp $imm, m32/16 */
- instr->instr = INSTR_CMP;
- return DECODE_success;
-
- case 1: /* or $imm, m32/16 */
- instr->instr = INSTR_OR;
- return DECODE_success;
-
- default:
- printf("%x/%x, This opcode isn't handled yet!\n",
- *opcode, ins_subtype);
- return DECODE_failure;
- }
+ if ( opcode[0] == 0x80 ) {
+ *op_size = BYTE;
+ GET_OP_SIZE_FOR_BYTE(size_reg);
+ } else {
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ size_reg = *op_size;
}
- case 0x84: /* test m8, r8 */
- instr->instr = INSTR_TEST;
- instr->op_size = BYTE;
+ /* opcode 0x83 always has a single byte operand */
+ if ( opcode[0] == 0x83 )
+ mmio_op->immediate =
+ (signed char)get_immediate(*ad_size, opcode + 1, BYTE);
+ else
+ mmio_op->immediate =
+ get_immediate(*ad_size, opcode + 1, *op_size);
+
+ mmio_op->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
+ mmio_op->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
+
+ switch ( ins_subtype ) {
+ case 7: /* cmp $imm, m32/16 */
+ mmio_op->instr = INSTR_CMP;
+ return DECODE_success;
+
+ case 1: /* or $imm, m32/16 */
+ mmio_op->instr = INSTR_OR;
+ return DECODE_success;
+
+ default:
+ printk("%x/%x, This opcode isn't handled yet!\n",
+ *opcode, ins_subtype);
+ return DECODE_failure;
+ }
+ }
+
+ case 0x84: /* test r8, m8 */
+ mmio_op->instr = INSTR_TEST;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_reg(size_reg, opcode, instr, rex);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
- case 0x87: /* xchg {r/m16|r/m32}, {m/r16|m/r32} */
- instr->instr = INSTR_XCHG;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- if (((*(opcode+1)) & 0xc7) == 5)
- return reg_mem(instr->op_size, opcode, instr, rex);
- else
- return mem_reg(instr->op_size, opcode, instr, rex);
+ case 0x85: /* test r16/32, m16/32 */
+ mmio_op->instr = INSTR_TEST;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
+
+ case 0x86: /* xchg m8, r8 */
+ mmio_op->instr = INSTR_XCHG;
+ *op_size = BYTE;
+ GET_OP_SIZE_FOR_BYTE(size_reg);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
+
+ case 0x87: /* xchg m16/32, r16/32 */
+ mmio_op->instr = INSTR_XCHG;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
case 0x88: /* mov r8, m8 */
- instr->instr = INSTR_MOV;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_MOV;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return reg_mem(size_reg, opcode, instr, rex);
+ return reg_mem(size_reg, opcode, mmio_op, rex);
case 0x89: /* mov r32/16, m32/16 */
- instr->instr = INSTR_MOV;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return reg_mem(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_MOV;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return reg_mem(*op_size, opcode, mmio_op, rex);
case 0x8A: /* mov m8, r8 */
- instr->instr = INSTR_MOV;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_MOV;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_reg(size_reg, opcode, instr, rex);
+ return mem_reg(size_reg, opcode, mmio_op, rex);
case 0x8B: /* mov m32/16, r32/16 */
- instr->instr = INSTR_MOV;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return mem_reg(instr->op_size, opcode, instr, rex);
+ mmio_op->instr = INSTR_MOV;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_reg(*op_size, opcode, mmio_op, rex);
case 0xA0: /* mov <addr>, al */
- instr->instr = INSTR_MOV;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_MOV;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return mem_acc(size_reg, instr);
+ return mem_acc(size_reg, mmio_op);
case 0xA1: /* mov <addr>, ax/eax */
- instr->instr = INSTR_MOV;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return mem_acc(instr->op_size, instr);
+ mmio_op->instr = INSTR_MOV;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return mem_acc(*op_size, mmio_op);
case 0xA2: /* mov al, <addr> */
- instr->instr = INSTR_MOV;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_MOV;
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- return acc_mem(size_reg, instr);
+ return acc_mem(size_reg, mmio_op);
case 0xA3: /* mov ax/eax, <addr> */
- instr->instr = INSTR_MOV;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- return acc_mem(instr->op_size, instr);
+ mmio_op->instr = INSTR_MOV;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ return acc_mem(*op_size, mmio_op);
case 0xA4: /* movsb */
- instr->instr = INSTR_MOVS;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_MOVS;
+ *op_size = BYTE;
return DECODE_success;
case 0xA5: /* movsw/movsl */
- instr->instr = INSTR_MOVS;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_MOVS;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
return DECODE_success;
case 0xAA: /* stosb */
- instr->instr = INSTR_STOS;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_STOS;
+ *op_size = BYTE;
return DECODE_success;
case 0xAB: /* stosw/stosl */
- instr->instr = INSTR_STOS;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_STOS;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
return DECODE_success;
case 0xAC: /* lodsb */
- instr->instr = INSTR_LODS;
- instr->op_size = BYTE;
+ mmio_op->instr = INSTR_LODS;
+ *op_size = BYTE;
return DECODE_success;
case 0xAD: /* lodsw/lodsl */
- instr->instr = INSTR_LODS;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_LODS;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
return DECODE_success;
case 0xC6:
- if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm8, m8 */
- instr->instr = INSTR_MOV;
- instr->op_size = BYTE;
+ if ( ((opcode[1] >> 3) & 7) == 0 ) { /* mov $imm8, m8 */
+ mmio_op->instr = INSTR_MOV;
+ *op_size = BYTE;
- instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE);
- instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
- instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
+ mmio_op->operand[0] = mk_operand(*op_size, 0, 0, IMMEDIATE);
+ mmio_op->immediate =
+ get_immediate(*ad_size, opcode + 1, *op_size);
+ mmio_op->operand[1] = mk_operand(*op_size, 0, 0, MEMORY);
return DECODE_success;
} else
return DECODE_failure;
case 0xC7:
- if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm16/32, m16/32 */
- instr->instr = INSTR_MOV;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ if ( ((opcode[1] >> 3) & 7) == 0 ) { /* mov $imm16/32, m16/32 */
+ mmio_op->instr = INSTR_MOV;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
- instr->operand[0] = mk_operand(instr->op_size, 0, 0, IMMEDIATE);
- instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
- instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
+ mmio_op->operand[0] = mk_operand(*op_size, 0, 0, IMMEDIATE);
+ mmio_op->immediate =
+ get_immediate(*ad_size, opcode + 1, *op_size);
+ mmio_op->operand[1] = mk_operand(*op_size, 0, 0, MEMORY);
return DECODE_success;
} else
@@ -581,20 +654,21 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
case 0xF6:
case 0xF7:
- if (((opcode[1] >> 3) & 7) == 0) { /* test $imm8/16/32, m8/16/32 */
- instr->instr = INSTR_TEST;
+ if ( ((opcode[1] >> 3) & 7) == 0 ) { /* test $imm8/16/32, m8/16/32 */
+ mmio_op->instr = INSTR_TEST;
- if (opcode[0] == 0xF6) {
+ if ( opcode[0] == 0xF6 ) {
+ *op_size = BYTE;
GET_OP_SIZE_FOR_BYTE(size_reg);
- instr->op_size = BYTE;
} else {
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- size_reg = instr->op_size;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ size_reg = *op_size;
}
- instr->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
- instr->immediate = get_immediate(realmode, opcode+1, instr->op_size);
- instr->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
+ mmio_op->operand[0] = mk_operand(size_reg, 0, 0, IMMEDIATE);
+ mmio_op->immediate =
+ get_immediate(*ad_size, opcode + 1, *op_size);
+ mmio_op->operand[1] = mk_operand(size_reg, 0, 0, MEMORY);
return DECODE_success;
} else
@@ -604,147 +678,130 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
break;
default:
- printf("%x, This opcode isn't handled yet!\n", *opcode);
+ printk("%x, This opcode isn't handled yet!\n", *opcode);
return DECODE_failure;
}
- switch (*++opcode) {
+ switch ( *++opcode ) {
case 0xB6: /* movzx m8, r16/r32/r64 */
- instr->instr = INSTR_MOVZX;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_MOVZX;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
index = get_index(opcode + 1, rex);
- instr->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
+ mmio_op->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
+ mmio_op->operand[1] = mk_operand(*op_size, index, 0, REGISTER);
return DECODE_success;
- case 0xB7: /* movzx m16/m32, r32/r64 */
- instr->instr = INSTR_MOVZX;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ case 0xB7: /* movzx m16, r32/r64 */
+ mmio_op->instr = INSTR_MOVZX;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
index = get_index(opcode + 1, rex);
- if (rex & 0x8)
- instr->operand[0] = mk_operand(LONG, 0, 0, MEMORY);
- else
- instr->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
+ mmio_op->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
+ mmio_op->operand[1] = mk_operand(*op_size, index, 0, REGISTER);
return DECODE_success;
case 0xBE: /* movsx m8, r16/r32/r64 */
- instr->instr = INSTR_MOVSX;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_MOVSX;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
index = get_index(opcode + 1, rex);
- instr->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
+ mmio_op->operand[0] = mk_operand(BYTE, 0, 0, MEMORY);
+ mmio_op->operand[1] = mk_operand(*op_size, index, 0, REGISTER);
return DECODE_success;
case 0xBF: /* movsx m16, r32/r64 */
- instr->instr = INSTR_MOVSX;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
+ mmio_op->instr = INSTR_MOVSX;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
index = get_index(opcode + 1, rex);
- instr->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
- instr->operand[1] = mk_operand(instr->op_size, index, 0, REGISTER);
+ mmio_op->operand[0] = mk_operand(WORD, 0, 0, MEMORY);
+ mmio_op->operand[1] = mk_operand(*op_size, index, 0, REGISTER);
return DECODE_success;
case 0xA3: /* bt r32, m32 */
- instr->instr = INSTR_BT;
+ mmio_op->instr = INSTR_BT;
index = get_index(opcode + 1, rex);
- instr->op_size = LONG;
- instr->operand[0] = mk_operand(instr->op_size, index, 0, REGISTER);
- instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
+ *op_size = LONG;
+ mmio_op->operand[0] = mk_operand(*op_size, index, 0, REGISTER);
+ mmio_op->operand[1] = mk_operand(*op_size, 0, 0, MEMORY);
return DECODE_success;
case 0xBA:
- if (((opcode[1] >> 3) & 7) == 4) /* BT $imm8, m16/32/64 */
+ if ( ((opcode[1] >> 3) & 7) == 4 ) /* BT $imm8, m16/32/64 */
{
- instr->instr = INSTR_BT;
- GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
- instr->immediate =
- (signed char)get_immediate(realmode, opcode+1, BYTE);
- instr->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE);
- instr->operand[1] = mk_operand(instr->op_size, 0, 0, MEMORY);
+ mmio_op->instr = INSTR_BT;
+ GET_OP_SIZE_FOR_NONEBYTE(*op_size);
+ mmio_op->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE);
+ mmio_op->immediate =
+ (signed char)get_immediate(*ad_size, opcode + 1, BYTE);
+ mmio_op->operand[1] = mk_operand(*op_size, 0, 0, MEMORY);
return DECODE_success;
}
else
{
- printf("0f %x, This opcode subtype isn't handled yet\n", *opcode);
+ printk("0f %x, This opcode subtype isn't handled yet\n", *opcode);
return DECODE_failure;
}
default:
- printf("0f %x, This opcode isn't handled yet\n", *opcode);
+ printk("0f %x, This opcode isn't handled yet\n", *opcode);
return DECODE_failure;
}
}
int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip, int inst_len)
{
- if (inst_len > MAX_INST_LEN || inst_len <= 0)
+ if ( inst_len > MAX_INST_LEN || inst_len <= 0 )
return 0;
- if (!hvm_copy(buf, guest_eip, inst_len, HVM_COPY_IN))
+ if ( hvm_copy_from_guest_virt(buf, guest_eip, inst_len) )
return 0;
return inst_len;
}
-static void hvm_send_assist_req(struct vcpu *v)
-{
- ioreq_t *p;
-
- p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
- if ( unlikely(p->state != STATE_INVALID) ) {
- /* This indicates a bug in the device model. Crash the
- domain. */
- printf("Device model set bad IO state %d.\n", p->state);
- domain_crash(v->domain);
- return;
- }
- wmb();
- p->state = STATE_IOREQ_READY;
- notify_via_xen_event_channel(v->arch.hvm_vcpu.xen_port);
-}
-
-
-/* Wake up a vcpu whihc is waiting for interrupts to come in */
-void hvm_prod_vcpu(struct vcpu *v)
-{
- vcpu_unblock(v);
-}
-
-void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
- unsigned long count, int size, long value, int dir, int pvalid)
+void send_pio_req(unsigned long port, unsigned long count, int size,
+ long value, int dir, int df, int value_is_ptr)
{
struct vcpu *v = current;
vcpu_iodata_t *vio;
ioreq_t *p;
+ if ( size == 0 || count == 0 ) {
+ printk("null pio request? port %lx, count %lx, "
+ "size %d, value %lx, dir %d, value_is_ptr %d.\n",
+ port, count, size, value, dir, value_is_ptr);
+ }
+
vio = get_vio(v->domain, v->vcpu_id);
- if (vio == NULL) {
+ if ( vio == NULL ) {
printk("bad shared page: %lx\n", (unsigned long) vio);
domain_crash_synchronous();
}
p = &vio->vp_ioreq;
- if ( p->state != STATE_INVALID )
- printf("WARNING: send pio with something already pending (%d)?\n",
+ if ( p->state != STATE_IOREQ_NONE )
+ printk("WARNING: send pio with something already pending (%d)?\n",
p->state);
+
p->dir = dir;
- p->pdata_valid = pvalid;
+ p->data_is_ptr = value_is_ptr;
p->type = IOREQ_TYPE_PIO;
p->size = size;
p->addr = port;
p->count = count;
- p->df = regs->eflags & EF_DF ? 1 : 0;
+ p->df = df;
p->io_count++;
- if (pvalid) {
- if (hvm_paging_enabled(current))
- p->u.data = shadow_gva_to_gpa(current, value);
+ if ( value_is_ptr ) /* get physical address of data */
+ {
+ if ( hvm_paging_enabled(current) )
+ p->data = shadow_gva_to_gpa(current, value);
else
- p->u.pdata = (void *) value; /* guest VA == guest PA */
- } else
- p->u.data = value;
+ p->data = value; /* guest VA == guest PA */
+ }
+ else if ( dir == IOREQ_WRITE )
+ p->data = value;
- if (hvm_portio_intercept(p)) {
+ if ( hvm_portio_intercept(p) )
+ {
p->state = STATE_IORESP_READY;
hvm_io_assist(v);
return;
@@ -753,48 +810,54 @@ void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
hvm_send_assist_req(v);
}
-void send_mmio_req(
- unsigned char type, unsigned long gpa,
- unsigned long count, int size, long value, int dir, int pvalid)
+static void send_mmio_req(unsigned char type, unsigned long gpa,
+ unsigned long count, int size, long value,
+ int dir, int df, int value_is_ptr)
{
struct vcpu *v = current;
vcpu_iodata_t *vio;
ioreq_t *p;
- struct cpu_user_regs *regs;
- regs = &current->arch.hvm_vcpu.io_op.io_context;
+ if ( size == 0 || count == 0 ) {
+ printk("null mmio request? type %d, gpa %lx, "
+ "count %lx, size %d, value %lx, dir %d, value_is_ptr %d.\n",
+ type, gpa, count, size, value, dir, value_is_ptr);
+ }
vio = get_vio(v->domain, v->vcpu_id);
if (vio == NULL) {
- printf("bad shared page\n");
+ printk("bad shared page\n");
domain_crash_synchronous();
}
p = &vio->vp_ioreq;
- if ( p->state != STATE_INVALID )
- printf("WARNING: send mmio with something already pending (%d)?\n",
+ if ( p->state != STATE_IOREQ_NONE )
+ printk("WARNING: send mmio with something already pending (%d)?\n",
p->state);
p->dir = dir;
- p->pdata_valid = pvalid;
+ p->data_is_ptr = value_is_ptr;
p->type = type;
p->size = size;
p->addr = gpa;
p->count = count;
- p->df = regs->eflags & EF_DF ? 1 : 0;
+ p->df = df;
p->io_count++;
- if (pvalid) {
- if (hvm_paging_enabled(v))
- p->u.data = shadow_gva_to_gpa(v, value);
+ if ( value_is_ptr )
+ {
+ if ( hvm_paging_enabled(v) )
+ p->data = shadow_gva_to_gpa(v, value);
else
- p->u.pdata = (void *) value; /* guest VA == guest PA */
- } else
- p->u.data = value;
+ p->data = value; /* guest VA == guest PA */
+ }
+ else
+ p->data = value;
- if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) ) {
+ if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) )
+ {
p->state = STATE_IORESP_READY;
hvm_io_assist(v);
return;
@@ -803,164 +866,186 @@ void send_mmio_req(
hvm_send_assist_req(v);
}
-static void mmio_operands(int type, unsigned long gpa, struct instruction *inst,
- struct hvm_io_op *mmio_opp, struct cpu_user_regs *regs)
+static void mmio_operands(int type, unsigned long gpa,
+ struct hvm_io_op *mmio_op,
+ unsigned char op_size)
{
unsigned long value = 0;
- int index, size_reg;
+ int df, index, size_reg;
+ struct cpu_user_regs *regs = &mmio_op->io_context;
- size_reg = operand_size(inst->operand[0]);
+ df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
- mmio_opp->flags = inst->flags;
- mmio_opp->instr = inst->instr;
- mmio_opp->operand[0] = inst->operand[0]; /* source */
- mmio_opp->operand[1] = inst->operand[1]; /* destination */
- mmio_opp->immediate = inst->immediate;
+ size_reg = operand_size(mmio_op->operand[0]);
- if (inst->operand[0] & REGISTER) { /* dest is memory */
- index = operand_index(inst->operand[0]);
+ if ( mmio_op->operand[0] & REGISTER ) { /* dest is memory */
+ index = operand_index(mmio_op->operand[0]);
value = get_reg_value(size_reg, index, 0, regs);
- send_mmio_req(type, gpa, 1, inst->op_size, value, IOREQ_WRITE, 0);
- } else if (inst->operand[0] & IMMEDIATE) { /* dest is memory */
- value = inst->immediate;
- send_mmio_req(type, gpa, 1, inst->op_size, value, IOREQ_WRITE, 0);
- } else if (inst->operand[0] & MEMORY) { /* dest is register */
+ send_mmio_req(type, gpa, 1, op_size, value, IOREQ_WRITE, df, 0);
+ } else if ( mmio_op->operand[0] & IMMEDIATE ) { /* dest is memory */
+ value = mmio_op->immediate;
+ send_mmio_req(type, gpa, 1, op_size, value, IOREQ_WRITE, df, 0);
+ } else if ( mmio_op->operand[0] & MEMORY ) { /* dest is register */
/* send the request and wait for the value */
- if ( (inst->instr == INSTR_MOVZX) || (inst->instr == INSTR_MOVSX) )
- send_mmio_req(type, gpa, 1, size_reg, 0, IOREQ_READ, 0);
+ if ( (mmio_op->instr == INSTR_MOVZX) ||
+ (mmio_op->instr == INSTR_MOVSX) )
+ send_mmio_req(type, gpa, 1, size_reg, 0, IOREQ_READ, df, 0);
else
- send_mmio_req(type, gpa, 1, inst->op_size, 0, IOREQ_READ, 0);
+ send_mmio_req(type, gpa, 1, op_size, 0, IOREQ_READ, df, 0);
} else {
- printf("mmio_operands: invalid operand\n");
+ printk("%s: invalid dest mode.\n", __func__);
domain_crash_synchronous();
}
}
#define GET_REPEAT_COUNT() \
- (mmio_inst.flags & REPZ ? (realmode ? regs->ecx & 0xFFFF : regs->ecx) : 1)
+ (mmio_op->flags & REPZ ? (ad_size == WORD ? regs->ecx & 0xFFFF : regs->ecx) : 1)
-void handle_mmio(unsigned long va, unsigned long gpa)
+void handle_mmio(unsigned long gpa)
{
unsigned long inst_addr;
- struct hvm_io_op *mmio_opp;
+ struct hvm_io_op *mmio_op;
struct cpu_user_regs *regs;
- struct instruction mmio_inst;
- unsigned char inst[MAX_INST_LEN];
- int i, realmode, ret, inst_len;
+ unsigned char inst[MAX_INST_LEN], ad_size, op_size, seg_sel;
+ int i, mode, df, inst_len;
struct vcpu *v = current;
- mmio_opp = &v->arch.hvm_vcpu.io_op;
- regs = &mmio_opp->io_context;
+ mmio_op = &v->arch.hvm_vcpu.io_op;
+ regs = &mmio_op->io_context;
/* Copy current guest state into io instruction state structure. */
memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES);
hvm_store_cpu_guest_regs(v, regs, NULL);
- if ((inst_len = hvm_instruction_length(v)) <= 0) {
- printf("handle_mmio: failed to get instruction length\n");
+ df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
+
+ mode = hvm_guest_x86_mode(v);
+ inst_addr = hvm_get_segment_base(v, seg_cs) + regs->eip;
+ inst_len = hvm_instruction_length(inst_addr, mode);
+ if ( inst_len <= 0 )
+ {
+ printk("handle_mmio: failed to get instruction length\n");
domain_crash_synchronous();
}
- realmode = hvm_realmode(v);
- if (realmode)
- inst_addr = (regs->cs << 4) + regs->eip;
- else
- inst_addr = regs->eip;
-
memset(inst, 0, MAX_INST_LEN);
- ret = inst_copy_from_guest(inst, inst_addr, inst_len);
- if (ret != inst_len) {
- printf("handle_mmio: failed to copy instruction\n");
+ if ( inst_copy_from_guest(inst, inst_addr, inst_len) != inst_len ) {
+ printk("handle_mmio: failed to copy instruction\n");
domain_crash_synchronous();
}
- init_instruction(&mmio_inst);
-
- if (hvm_decode(realmode, inst, &mmio_inst) == DECODE_failure) {
- printf("handle_mmio: failed to decode instruction\n");
- printf("mmio opcode: va 0x%lx, gpa 0x%lx, len %d:",
- va, gpa, inst_len);
- for (i = 0; i < inst_len; i++)
- printf(" %02x", inst[i] & 0xFF);
- printf("\n");
+ if ( mmio_decode(mode, inst, mmio_op, &ad_size, &op_size, &seg_sel)
+ == DECODE_failure ) {
+ printk("handle_mmio: failed to decode instruction\n");
+ printk("mmio opcode: gpa 0x%lx, len %d:", gpa, inst_len);
+ for ( i = 0; i < inst_len; i++ )
+ printk(" %02x", inst[i] & 0xFF);
+ printk("\n");
domain_crash_synchronous();
}
regs->eip += inst_len; /* advance %eip */
- switch (mmio_inst.instr) {
+ switch ( mmio_op->instr ) {
case INSTR_MOV:
- mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mmio_opp, regs);
+ mmio_operands(IOREQ_TYPE_COPY, gpa, mmio_op, op_size);
break;
case INSTR_MOVS:
{
unsigned long count = GET_REPEAT_COUNT();
- unsigned long size = mmio_inst.op_size;
- int sign = regs->eflags & EF_DF ? -1 : 1;
- unsigned long addr = 0;
- int dir;
+ int sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;
+ unsigned long addr;
+ int dir, size = op_size;
+
+ ASSERT(count);
/* determine non-MMIO address */
- if (realmode) {
- if (((regs->es << 4) + (regs->edi & 0xFFFF)) == va) {
- dir = IOREQ_WRITE;
- addr = (regs->ds << 4) + (regs->esi & 0xFFFF);
- } else {
- dir = IOREQ_READ;
- addr = (regs->es << 4) + (regs->edi & 0xFFFF);
- }
- } else {
- if (va == regs->edi) {
- dir = IOREQ_WRITE;
- addr = regs->esi;
- } else {
- dir = IOREQ_READ;
- addr = regs->edi;
+ addr = regs->edi;
+ if ( ad_size == WORD )
+ addr &= 0xFFFF;
+ addr += hvm_get_segment_base(v, seg_es);
+ if ( addr == gpa )
+ {
+ enum segment seg;
+
+ dir = IOREQ_WRITE;
+ addr = regs->esi;
+ if ( ad_size == WORD )
+ addr &= 0xFFFF;
+ switch ( seg_sel )
+ {
+ case 0x26: seg = seg_es; break;
+ case 0x2e: seg = seg_cs; break;
+ case 0x36: seg = seg_ss; break;
+ case 0:
+ case 0x3e: seg = seg_ds; break;
+ case 0x64: seg = seg_fs; break;
+ case 0x65: seg = seg_gs; break;
+ default: domain_crash_synchronous();
}
+ addr += hvm_get_segment_base(v, seg);
}
+ else
+ dir = IOREQ_READ;
- mmio_opp->flags = mmio_inst.flags;
- mmio_opp->instr = mmio_inst.instr;
+ if ( addr & (size - 1) )
+ gdprintk(XENLOG_WARNING,
+ "Unaligned ioport access: %lx, %d\n", addr, size);
/*
* In case of a movs spanning multiple pages, we break the accesses
* up into multiple pages (the device model works with non-continguous
* physical guest pages). To copy just one page, we adjust %ecx and
- * do not advance %eip so that the next "rep movs" copies the next page.
+ * do not advance %eip so that the next rep;movs copies the next page.
* Unaligned accesses, for example movsl starting at PGSZ-2, are
* turned into a single copy where we handle the overlapping memory
* copy ourself. After this copy succeeds, "rep movs" is executed
* again.
*/
- if ((addr & PAGE_MASK) != ((addr + sign * (size - 1)) & PAGE_MASK)) {
+ if ( (addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK) ) {
unsigned long value = 0;
- mmio_opp->flags |= OVERLAP;
+ gdprintk(XENLOG_WARNING,
+ "Single io request in a movs crossing page boundary.\n");
+ mmio_op->flags |= OVERLAP;
- regs->eip -= inst_len; /* do not advance %eip */
+ if ( dir == IOREQ_WRITE ) {
+ if ( hvm_paging_enabled(v) )
+ (void)hvm_copy_from_guest_virt(&value, addr, size);
+ else
+ (void)hvm_copy_from_guest_phys(&value, addr, size);
+ } else
+ mmio_op->addr = addr;
+
+ if ( count != 1 )
+ regs->eip -= inst_len; /* do not advance %eip */
- if (dir == IOREQ_WRITE)
- hvm_copy(&value, addr, size, HVM_COPY_IN);
- send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, size, value, dir, 0);
+ send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, size, value, dir, df, 0);
} else {
- if ((addr & PAGE_MASK) != ((addr + sign * (count * size - 1)) & PAGE_MASK)) {
+ unsigned long last_addr = sign > 0 ? addr + count * size - 1
+ : addr - (count - 1) * size;
+
+ if ( (addr & PAGE_MASK) != (last_addr & PAGE_MASK) )
+ {
regs->eip -= inst_len; /* do not advance %eip */
- if (sign > 0)
+ if ( sign > 0 )
count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
else
- count = (addr & ~PAGE_MASK) / size;
+ count = (addr & ~PAGE_MASK) / size + 1;
}
- send_mmio_req(IOREQ_TYPE_COPY, gpa, count, size, addr, dir, 1);
+ ASSERT(count);
+
+ send_mmio_req(IOREQ_TYPE_COPY, gpa, count, size, addr, dir, df, 1);
}
break;
}
case INSTR_MOVZX:
case INSTR_MOVSX:
- mmio_operands(IOREQ_TYPE_COPY, gpa, &mmio_inst, mmio_opp, regs);
+ mmio_operands(IOREQ_TYPE_COPY, gpa, mmio_op, op_size);
break;
case INSTR_STOS:
@@ -968,10 +1053,8 @@ void handle_mmio(unsigned long va, unsigned long gpa)
* Since the destination is always in (contiguous) mmio space we don't
* need to break it up into pages.
*/
- mmio_opp->flags = mmio_inst.flags;
- mmio_opp->instr = mmio_inst.instr;
send_mmio_req(IOREQ_TYPE_COPY, gpa,
- GET_REPEAT_COUNT(), mmio_inst.op_size, regs->eax, IOREQ_WRITE, 0);
+ GET_REPEAT_COUNT(), op_size, regs->eax, IOREQ_WRITE, df, 0);
break;
case INSTR_LODS:
@@ -979,91 +1062,79 @@ void handle_mmio(unsigned long va, unsigned long gpa)
* Since the source is always in (contiguous) mmio space we don't
* need to break it up into pages.
*/
- mmio_opp->flags = mmio_inst.flags;
- mmio_opp->instr = mmio_inst.instr;
send_mmio_req(IOREQ_TYPE_COPY, gpa,
- GET_REPEAT_COUNT(), mmio_inst.op_size, 0, IOREQ_READ, 0);
+ GET_REPEAT_COUNT(), op_size, 0, IOREQ_READ, df, 0);
break;
case INSTR_OR:
- mmio_operands(IOREQ_TYPE_OR, gpa, &mmio_inst, mmio_opp, regs);
+ mmio_operands(IOREQ_TYPE_OR, gpa, mmio_op, op_size);
break;
case INSTR_AND:
- mmio_operands(IOREQ_TYPE_AND, gpa, &mmio_inst, mmio_opp, regs);
+ mmio_operands(IOREQ_TYPE_AND, gpa, mmio_op, op_size);
+ break;
+
+ case INSTR_ADD:
+ mmio_operands(IOREQ_TYPE_ADD, gpa, mmio_op, op_size);
break;
case INSTR_XOR:
- mmio_operands(IOREQ_TYPE_XOR, gpa, &mmio_inst, mmio_opp, regs);
+ mmio_operands(IOREQ_TYPE_XOR, gpa, mmio_op, op_size);
break;
case INSTR_CMP: /* Pass through */
case INSTR_TEST:
- mmio_opp->flags = mmio_inst.flags;
- mmio_opp->instr = mmio_inst.instr;
- mmio_opp->operand[0] = mmio_inst.operand[0]; /* source */
- mmio_opp->operand[1] = mmio_inst.operand[1]; /* destination */
- mmio_opp->immediate = mmio_inst.immediate;
-
+ case INSTR_SUB:
/* send the request and wait for the value */
- send_mmio_req(IOREQ_TYPE_COPY, gpa, 1,
- mmio_inst.op_size, 0, IOREQ_READ, 0);
+ send_mmio_req(IOREQ_TYPE_COPY, gpa, 1, op_size, 0, IOREQ_READ, df, 0);
break;
case INSTR_BT:
- {
- unsigned long value = 0;
- int index, size;
-
- mmio_opp->instr = mmio_inst.instr;
- mmio_opp->operand[0] = mmio_inst.operand[0]; /* bit offset */
- mmio_opp->operand[1] = mmio_inst.operand[1]; /* bit base */
+ {
+ unsigned long value = 0;
+ int index, size;
- if ( mmio_inst.operand[0] & REGISTER )
- {
- index = operand_index(mmio_inst.operand[0]);
- size = operand_size(mmio_inst.operand[0]);
- value = get_reg_value(size, index, 0, regs);
- }
- else if ( mmio_inst.operand[0] & IMMEDIATE )
- {
- mmio_opp->immediate = mmio_inst.immediate;
- value = mmio_inst.immediate;
- }
- send_mmio_req(IOREQ_TYPE_COPY, gpa + (value >> 5), 1,
- mmio_inst.op_size, 0, IOREQ_READ, 0);
- break;
+ if ( mmio_op->operand[0] & REGISTER )
+ {
+ index = operand_index(mmio_op->operand[0]);
+ size = operand_size(mmio_op->operand[0]);
+ value = get_reg_value(size, index, 0, regs);
+ }
+ else if ( mmio_op->operand[0] & IMMEDIATE )
+ {
+ mmio_op->immediate = mmio_op->immediate;
+ value = mmio_op->immediate;
}
+ send_mmio_req(IOREQ_TYPE_COPY, gpa + (value >> 5), 1,
+ op_size, 0, IOREQ_READ, df, 0);
+ break;
+ }
case INSTR_XCHG:
- mmio_opp->flags = mmio_inst.flags;
- mmio_opp->instr = mmio_inst.instr;
- mmio_opp->operand[0] = mmio_inst.operand[0]; /* source */
- mmio_opp->operand[1] = mmio_inst.operand[1]; /* destination */
- if ( mmio_inst.operand[0] & REGISTER ) {
+ if ( mmio_op->operand[0] & REGISTER ) {
long value;
- unsigned long operand = mmio_inst.operand[0];
+ unsigned long operand = mmio_op->operand[0];
value = get_reg_value(operand_size(operand),
operand_index(operand), 0,
regs);
/* send the request and wait for the value */
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
- mmio_inst.op_size, value, IOREQ_WRITE, 0);
+ op_size, value, IOREQ_WRITE, df, 0);
} else {
/* the destination is a register */
long value;
- unsigned long operand = mmio_inst.operand[1];
+ unsigned long operand = mmio_op->operand[1];
value = get_reg_value(operand_size(operand),
operand_index(operand), 0,
regs);
/* send the request and wait for the value */
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
- mmio_inst.op_size, value, IOREQ_WRITE, 0);
+ op_size, value, IOREQ_WRITE, df, 0);
}
break;
default:
- printf("Unhandled MMIO instruction\n");
+ printk("Unhandled MMIO instruction\n");
domain_crash_synchronous();
}
}
@@ -1082,7 +1153,7 @@ unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len)
return 0;
}
- return !hvm_copy((void *)from, (unsigned long)to, len, HVM_COPY_OUT);
+ return hvm_copy_to_guest_virt((unsigned long)to, (void *)from, len);
}
unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
@@ -1093,7 +1164,7 @@ unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
return 0;
}
- return !hvm_copy(to, (unsigned long)from, len, HVM_COPY_IN);
+ return hvm_copy_from_guest_virt(to, (unsigned long)from, len);
}
/*
diff --git a/xen/arch/x86/hvm/pmtimer.c b/xen/arch/x86/hvm/pmtimer.c
new file mode 100644
index 0000000000..b435fbdf9f
--- /dev/null
+++ b/xen/arch/x86/hvm/pmtimer.c
@@ -0,0 +1,63 @@
+#include <asm/hvm/vpt.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+
+#define TMR_STS (1 << 0)
+static void pmt_update_status(void *opaque)
+{
+ PMTState *s = opaque;
+ s->pm1_status |= TMR_STS;
+
+ /* TODO: When TMR_EN == 1, generate a SCI event */
+
+ set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER);
+}
+
+static int handle_pmt_io(ioreq_t *p)
+{
+ struct vcpu *v = current;
+ PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+ uint64_t curr_gtime;
+
+ if (p->size != 4 ||
+ p->data_is_ptr ||
+ p->type != IOREQ_TYPE_PIO){
+ printk("HVM_PMT: wrong PM timer IO\n");
+ return 1;
+ }
+
+ if (p->dir == 0) { /* write */
+ /* PM_TMR_BLK is read-only */
+ return 1;
+ } else if (p->dir == 1) { /* read */
+ curr_gtime = hvm_get_guest_time(s->vcpu);
+ s->pm1_timer += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
+ p->data = s->pm1_timer;
+ s->last_gtime = curr_gtime;
+ return 1;
+ }
+ return 0;
+}
+
+void pmtimer_init(struct vcpu *v, int base)
+{
+ PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+
+ s->pm1_timer = 0;
+ s->pm1_status = 0;
+ s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v);
+ s->vcpu = v;
+
+ init_timer(&s->timer, pmt_update_status, s, v->processor);
+ /* ACPI supports a 32-bit power management timer */
+ set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER);
+
+ register_portio_handler(v->domain, base, 4, handle_pmt_io);
+}
+
+void pmtimer_deinit(struct domain *d)
+{
+ PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
+
+ kill_timer(&s->timer);
+}
diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c
new file mode 100644
index 0000000000..1f26dc9252
--- /dev/null
+++ b/xen/arch/x86/hvm/rtc.c
@@ -0,0 +1,436 @@
+/*
+ * QEMU MC146818 RTC 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 <asm/mc146818rtc.h>
+#include <asm/hvm/vpt.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+#include <asm/current.h>
+
+/* #define DEBUG_RTC */
+
+/* Callback that fires the RTC's periodic interrupt */
+void rtc_pie_callback(void *opaque)
+{
+ RTCState *s = opaque;
+ /* Record that we have fired */
+ s->cmos_data[RTC_REG_C] |= (RTC_IRQF|RTC_PF); /* 0xc0 */
+ /* Fire */
+ hvm_isa_irq_assert(s->vcpu->domain, s->irq);
+ /* Remember to fire again */
+ s->next_pie = NOW() + s->period;
+ set_timer(&s->pie_timer, s->next_pie);
+}
+
+/* Enable/configure/disable the periodic timer based on the RTC_PIE and
+ * RTC_RATE_SELECT settings */
+static void rtc_timer_update(RTCState *s)
+{
+ int period_code;
+ int period;
+
+ period_code = s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT;
+ if ( (period_code != 0) && (s->cmos_data[RTC_REG_B] & RTC_PIE) )
+ {
+ if ( period_code <= 2 )
+ period_code += 7;
+
+ period = 1 << (period_code - 1); /* period in 32 Khz cycles */
+ period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
+ s->period = period;
+#ifdef DEBUG_RTC
+ printk("HVM_RTC: period = %uns\n", period);
+#endif
+ s->next_pie = NOW() + s->period;
+ set_timer(&s->pie_timer, s->next_pie);
+ }
+ else
+ {
+ stop_timer(&s->pie_timer);
+ }
+}
+
+static void rtc_set_time(RTCState *s);
+
+static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ RTCState *s = opaque;
+
+ if ( (addr & 1) == 0 )
+ {
+ s->cmos_index = data & 0x7f;
+ return (s->cmos_index < RTC_SIZE);
+ }
+
+ if (s->cmos_index >= RTC_SIZE)
+ return 0;
+
+#ifdef DEBUG_RTC
+ printk("HVM_RTC: write index=0x%02x val=0x%02x\n",
+ s->cmos_index, data);
+#endif
+
+ switch ( s->cmos_index )
+ {
+ case RTC_SECONDS_ALARM:
+ case RTC_MINUTES_ALARM:
+ case RTC_HOURS_ALARM:
+ s->cmos_data[s->cmos_index] = data;
+ break;
+ case RTC_SECONDS:
+ case RTC_MINUTES:
+ case RTC_HOURS:
+ case RTC_DAY_OF_WEEK:
+ case RTC_DAY_OF_MONTH:
+ case RTC_MONTH:
+ case RTC_YEAR:
+ s->cmos_data[s->cmos_index] = data;
+ /* if in set mode, do not update the time */
+ if ( !(s->cmos_data[RTC_REG_B] & RTC_SET) )
+ rtc_set_time(s);
+ break;
+ case RTC_REG_A:
+ /* UIP bit is read only */
+ s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
+ (s->cmos_data[RTC_REG_A] & RTC_UIP);
+ rtc_timer_update(s);
+ break;
+ case RTC_REG_B:
+ if ( data & RTC_SET )
+ {
+ /* set mode: reset UIP mode */
+ s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
+ data &= ~RTC_UIE;
+ }
+ else
+ {
+ /* if disabling set mode, update the time */
+ if ( s->cmos_data[RTC_REG_B] & RTC_SET )
+ rtc_set_time(s);
+ }
+ s->cmos_data[RTC_REG_B] = data;
+ rtc_timer_update(s);
+ break;
+ case RTC_REG_C:
+ case RTC_REG_D:
+ /* cannot write to them */
+ break;
+ }
+
+ return 1;
+}
+
+static inline int to_bcd(RTCState *s, int a)
+{
+ if ( s->cmos_data[RTC_REG_B] & 0x04 )
+ return a;
+ else
+ return ((a / 10) << 4) | (a % 10);
+}
+
+static inline int from_bcd(RTCState *s, int a)
+{
+ if ( s->cmos_data[RTC_REG_B] & 0x04 )
+ return a;
+ else
+ return ((a >> 4) * 10) + (a & 0x0f);
+}
+
+static void rtc_set_time(RTCState *s)
+{
+ struct tm *tm = &s->current_tm;
+
+ tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
+ tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
+ tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
+ if ( !(s->cmos_data[RTC_REG_B] & 0x02) &&
+ (s->cmos_data[RTC_HOURS] & 0x80) )
+ tm->tm_hour += 12;
+ tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
+ tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
+ tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
+ tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
+}
+
+static void rtc_copy_date(RTCState *s)
+{
+ const struct tm *tm = &s->current_tm;
+
+ s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
+ s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
+ if ( s->cmos_data[RTC_REG_B] & RTC_24H )
+ {
+ /* 24 hour format */
+ s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
+ }
+ else
+ {
+ /* 12 hour format */
+ s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
+ if ( tm->tm_hour >= 12 )
+ s->cmos_data[RTC_HOURS] |= 0x80;
+ }
+ s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
+ s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
+ s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
+ s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
+}
+
+/* month is between 0 and 11. */
+static int get_days_in_month(int month, int year)
+{
+ static const int days_tab[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ int d;
+ if ( (unsigned)month >= 12 )
+ return 31;
+ d = days_tab[month];
+ if ( month == 1 )
+ if ( (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) )
+ d++;
+ return d;
+}
+
+/* update 'tm' to the next second */
+static void rtc_next_second(struct tm *tm)
+{
+ int days_in_month;
+
+ tm->tm_sec++;
+ if ((unsigned)tm->tm_sec >= 60) {
+ tm->tm_sec = 0;
+ tm->tm_min++;
+ if ((unsigned)tm->tm_min >= 60) {
+ tm->tm_min = 0;
+ tm->tm_hour++;
+ if ((unsigned)tm->tm_hour >= 24) {
+ tm->tm_hour = 0;
+ /* next day */
+ tm->tm_wday++;
+ if ((unsigned)tm->tm_wday >= 7)
+ tm->tm_wday = 0;
+ days_in_month = get_days_in_month(tm->tm_mon,
+ tm->tm_year + 1900);
+ tm->tm_mday++;
+ if (tm->tm_mday < 1) {
+ tm->tm_mday = 1;
+ } else if (tm->tm_mday > days_in_month) {
+ tm->tm_mday = 1;
+ tm->tm_mon++;
+ if (tm->tm_mon >= 12) {
+ tm->tm_mon = 0;
+ tm->tm_year++;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void rtc_update_second(void *opaque)
+{
+ RTCState *s = opaque;
+
+ /* if the oscillator is not in normal operation, we do not update */
+ if ( (s->cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ )
+ {
+ s->next_second_time += 1000000000ULL;
+ set_timer(&s->second_timer, s->next_second_time);
+ }
+ else
+ {
+ rtc_next_second(&s->current_tm);
+
+ if ( !(s->cmos_data[RTC_REG_B] & RTC_SET) )
+ s->cmos_data[RTC_REG_A] |= RTC_UIP;
+
+ /* Delay time before update cycle */
+ set_timer(&s->second_timer2, s->next_second_time + 244000);
+ }
+}
+
+static void rtc_update_second2(void *opaque)
+{
+ RTCState *s = opaque;
+
+ if ( !(s->cmos_data[RTC_REG_B] & RTC_SET) )
+ rtc_copy_date(s);
+
+ /* check alarm */
+ if ( s->cmos_data[RTC_REG_B] & RTC_AIE )
+ {
+ if ( ((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
+ from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) ==
+ s->current_tm.tm_sec) &&
+ ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
+ from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) ==
+ s->current_tm.tm_min) &&
+ ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
+ from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) ==
+ s->current_tm.tm_hour) )
+ {
+ s->cmos_data[RTC_REG_C] |= 0xa0;
+ hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
+ hvm_isa_irq_assert(s->vcpu->domain, s->irq);
+ }
+ }
+
+ /* update ended interrupt */
+ if ( s->cmos_data[RTC_REG_B] & RTC_UIE )
+ {
+ s->cmos_data[RTC_REG_C] |= 0x90;
+ hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
+ hvm_isa_irq_assert(s->vcpu->domain, s->irq);
+ }
+
+ /* clear update in progress bit */
+ s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
+
+ s->next_second_time += 1000000000ULL;
+ set_timer(&s->second_timer, s->next_second_time);
+}
+
+static uint32_t rtc_ioport_read(void *opaque, uint32_t addr)
+{
+ RTCState *s = opaque;
+ int ret;
+
+ if ( (addr & 1) == 0 )
+ return 0xff;
+
+ switch ( s->cmos_index )
+ {
+ case RTC_SECONDS:
+ case RTC_MINUTES:
+ case RTC_HOURS:
+ case RTC_DAY_OF_WEEK:
+ case RTC_DAY_OF_MONTH:
+ case RTC_MONTH:
+ case RTC_YEAR:
+ ret = s->cmos_data[s->cmos_index];
+ break;
+ case RTC_REG_A:
+ ret = s->cmos_data[s->cmos_index];
+ break;
+ case RTC_REG_C:
+ ret = s->cmos_data[s->cmos_index];
+ hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
+ s->cmos_data[RTC_REG_C] = 0x00;
+ break;
+ default:
+ ret = s->cmos_data[s->cmos_index];
+ break;
+ }
+
+#ifdef DEBUG_RTC
+ printk("HVM_RTC: read index=0x%02x val=0x%02x\n",
+ s->cmos_index, ret);
+#endif
+
+ return ret;
+}
+
+static int handle_rtc_io(ioreq_t *p)
+{
+ struct vcpu *v = current;
+ struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
+
+ if ( (p->size != 1) || p->data_is_ptr || (p->type != IOREQ_TYPE_PIO) )
+ {
+ printk("HVM_RTC: wrong RTC IO!\n");
+ return 1;
+ }
+
+ if ( p->dir == 0 ) /* write */
+ {
+ if ( rtc_ioport_write(vrtc, p->addr, p->data & 0xFF) )
+ return 1;
+ }
+ else if ( (p->dir == 1) && (vrtc->cmos_index < RTC_SIZE) ) /* read */
+ {
+ p->data = rtc_ioport_read(vrtc, p->addr);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Stop the periodic interrupts from this RTC */
+void rtc_freeze(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ stop_timer(&s->pie_timer);
+}
+
+/* Start them again */
+void rtc_thaw(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ if ( (s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT) /* Period is not zero */
+ && (s->cmos_data[RTC_REG_B] & RTC_PIE) )
+ set_timer(&s->pie_timer, s->next_pie);
+}
+
+/* Move the RTC timers on to this vcpu's current cpu */
+void rtc_migrate_timers(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ migrate_timer(&s->second_timer, v->processor);
+ migrate_timer(&s->second_timer2, v->processor);
+ migrate_timer(&s->pie_timer, v->processor);
+}
+
+void rtc_init(struct vcpu *v, int base, int irq)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+
+ s->vcpu = v;
+ s->irq = irq;
+ s->cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */
+ s->cmos_data[RTC_REG_B] = RTC_24H;
+ s->cmos_data[RTC_REG_C] = 0;
+ s->cmos_data[RTC_REG_D] = RTC_VRT;
+
+ s->current_tm = gmtime(get_localtime(v->domain));
+ rtc_copy_date(s);
+
+ init_timer(&s->second_timer, rtc_update_second, s, v->processor);
+ init_timer(&s->second_timer2, rtc_update_second2, s, v->processor);
+ init_timer(&s->pie_timer, rtc_pie_callback, s, v->processor);
+
+ s->next_second_time = NOW() + 1000000000ULL;
+ set_timer(&s->second_timer2, s->next_second_time);
+
+ register_portio_handler(v->domain, base, 2, handle_rtc_io);
+}
+
+void rtc_deinit(struct domain *d)
+{
+ RTCState *s = &d->arch.hvm_domain.pl_time.vrtc;
+
+ kill_timer(&s->second_timer);
+ kill_timer(&s->second_timer2);
+ kill_timer(&s->pie_timer);
+}
diff --git a/xen/arch/x86/hvm/svm/Makefile b/xen/arch/x86/hvm/svm/Makefile
index e3baf066a0..523fd0bd2a 100644
--- a/xen/arch/x86/hvm/svm/Makefile
+++ b/xen/arch/x86/hvm/svm/Makefile
@@ -2,7 +2,6 @@ subdir-$(x86_32) += x86_32
subdir-$(x86_64) += x86_64
obj-y += emulate.o
-obj-y += instrlen.o
obj-y += intr.o
obj-y += svm.o
obj-y += vmcb.o
diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
index 194a8be7fc..504bafe7db 100644
--- a/xen/arch/x86/hvm/svm/emulate.c
+++ b/xen/arch/x86/hvm/svm/emulate.c
@@ -145,8 +145,8 @@ static inline u64 hv_is_canonical(u64 addr)
unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
- struct cpu_user_regs *regs, const u8 prefix, const u8 *operand,
- u8 *size)
+ struct cpu_user_regs *regs, const u8 prefix, int inst_len,
+ const u8 *operand, u8 *size)
{
unsigned long effective_addr = (unsigned long) -1;
u8 length, modrm_mod, modrm_rm;
@@ -191,17 +191,8 @@ unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
*size = 1;
break;
}
-
- CHECK_LENGTH64(*size + (u8)sizeof(u32));
-
- memcpy (&disp, operand + 1, sizeof (u32));
- *size += sizeof (u32);
- if (vmcb->cs.attributes.fields.l) // 64-bit mode
- return vmcb->rip + disp;
- else
- return disp;
-
#if __x86_64__
+ /* FALLTHRU */
case 0xD:
if (0 < modrm_mod)
{
@@ -209,19 +200,20 @@ unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
effective_addr = regs->r13;
break;
}
+#endif
CHECK_LENGTH64(*size + (u8)sizeof(u32));
memcpy (&disp, operand + 1, sizeof (u32));
*size += sizeof (u32);
+#if __x86_64__
/* 64-bit mode */
- if (vmcb->cs.attributes.fields.l)
- return vmcb->rip + disp;
- else
- return disp;
-
+ if (vmcb->cs.attributes.fields.l && (vmcb->efer & EFER_LMA))
+ return vmcb->rip + inst_len + *size + disp;
#endif
+ return disp;
+
default:
effective_addr = DECODE_GPR_VALUE(vmcb, regs, modrm_rm);
@@ -341,7 +333,11 @@ unsigned long svm_rip2pointer(struct vmcb_struct *vmcb)
* %cs is update, but fortunately, base contain the valid base address
* no matter what kind of addressing is used.
*/
- return vmcb->cs.base + vmcb->rip;
+ unsigned long p = vmcb->cs.base + vmcb->rip;
+ if (!(vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA))
+ return (u32)p; /* mask to 32 bits */
+ /* NB. Should mask to 16 bits if in real mode or 16-bit protected mode. */
+ return p;
}
diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c
index d053c6d122..e42438aadb 100644
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -43,15 +43,11 @@
* to be suitable for SVM.
*/
-static inline int svm_inject_extint(struct vcpu *v, int trap, int error_code)
+static inline int svm_inject_extint(struct vcpu *v, int trap)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- vintr_t intr;
+ vintr_t intr = vmcb->vintr;
- ASSERT(vmcb);
-
- /* Save all fields */
- intr = vmcb->vintr;
/* Update only relevant fields */
intr.fields.irq = 1;
intr.fields.intr_masking = 1;
@@ -59,108 +55,106 @@ static inline int svm_inject_extint(struct vcpu *v, int trap, int error_code)
intr.fields.prio = 0xF;
intr.fields.ign_tpr = 1;
vmcb->vintr = intr;
-// printf( "IRQ = %d\n", trap );
+
return 0;
}
-
+
asmlinkage void svm_intr_assist(void)
{
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
struct hvm_domain *plat=&v->domain->arch.hvm_domain;
struct periodic_time *pt = &plat->pl_time.periodic_tm;
- struct hvm_virpic *pic= &plat->vpic;
- int callback_irq;
int intr_type = APIC_DM_EXTINT;
int intr_vector = -1;
int re_injecting = 0;
- unsigned long rflags;
-
- ASSERT(vmcb);
/* Check if an Injection is active */
/* Previous Interrupt delivery caused this Intercept? */
- if (vmcb->exitintinfo.fields.v && (vmcb->exitintinfo.fields.type == 0)) {
+ if ( vmcb->exitintinfo.fields.v && (vmcb->exitintinfo.fields.type == 0) )
+ {
v->arch.hvm_svm.saved_irq_vector = vmcb->exitintinfo.fields.vector;
-// printk("Injecting PF#: saving IRQ from ExitInfo\n");
vmcb->exitintinfo.bytes = 0;
re_injecting = 1;
}
- /* Guest's interrputs masked? */
- rflags = vmcb->rflags;
- if (irq_masked(rflags)) {
- HVM_DBG_LOG(DBG_LEVEL_1, "Guest IRQs masked: rflags: %lx", rflags);
- /* bail out, we won't be injecting an interrupt this time */
+ /*
+ * If event requires injecting then do not inject int.
+ */
+ if ( unlikely(v->arch.hvm_svm.inject_event) )
+ {
+ v->arch.hvm_svm.inject_event = 0;
return;
}
-
+
+ /*
+ * Create a 'fake' virtual interrupt on to intercept as soon
+ * as the guest _can_ take interrupts.
+ */
+ if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow )
+ {
+ vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
+ svm_inject_extint(v, 0x0); /* actual vector doesn't really matter */
+ return;
+ }
+
/* Previous interrupt still pending? */
- if (vmcb->vintr.fields.irq) {
-// printk("Re-injecting IRQ from Vintr\n");
+ if ( vmcb->vintr.fields.irq )
+ {
intr_vector = vmcb->vintr.fields.vector;
vmcb->vintr.bytes = 0;
re_injecting = 1;
}
/* Pending IRQ saved at last VMExit? */
- else if ( v->arch.hvm_svm.saved_irq_vector >= 0) {
-// printk("Re-Injecting saved IRQ\n");
+ else if ( v->arch.hvm_svm.saved_irq_vector >= 0 )
+ {
intr_vector = v->arch.hvm_svm.saved_irq_vector;
v->arch.hvm_svm.saved_irq_vector = -1;
re_injecting = 1;
}
/* Now let's check for newer interrrupts */
- else {
-
- if ( v->vcpu_id == 0 )
- hvm_pic_assist(v);
-
-
- if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) {
- pic_set_irq(pic, pt->irq, 0);
- pic_set_irq(pic, pt->irq, 1);
- }
-
- callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
- if ( callback_irq != 0 &&
- local_events_need_delivery() ) {
- /*inject para-device call back irq*/
- v->vcpu_info->evtchn_upcall_mask = 1;
- pic_set_irq(pic, callback_irq, 0);
- pic_set_irq(pic, callback_irq, 1);
- }
+ else
+ {
+ if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr )
+ {
+ hvm_isa_irq_deassert(current->domain, pt->irq);
+ hvm_isa_irq_assert(current->domain, pt->irq);
+ }
- if ( cpu_has_pending_irq(v) )
- intr_vector = cpu_get_interrupt(v, &intr_type);
+ hvm_set_callback_irq_level();
+ if ( cpu_has_pending_irq(v) )
+ intr_vector = cpu_get_interrupt(v, &intr_type);
}
/* have we got an interrupt to inject? */
- if (intr_vector >= 0) {
- switch (intr_type) {
- case APIC_DM_EXTINT:
- case APIC_DM_FIXED:
- case APIC_DM_LOWEST:
- /* Re-injecting a PIT interruptt? */
- if (re_injecting &&
- is_pit_irq(v, intr_vector, intr_type)) {
- ++pt->pending_intr_nr;
- }
- /* let's inject this interrupt */
- TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0);
- svm_inject_extint(v, intr_vector, VMX_DELIVER_NO_ERROR_CODE);
- hvm_interrupt_post(v, intr_vector, intr_type);
- break;
- case APIC_DM_SMI:
- case APIC_DM_NMI:
- case APIC_DM_INIT:
- case APIC_DM_STARTUP:
- default:
- printk("Unsupported interrupt type: %d\n", intr_type);
- BUG();
- break;
- }
+ if ( intr_vector < 0 )
+ return;
+
+ switch ( intr_type )
+ {
+ case APIC_DM_EXTINT:
+ case APIC_DM_FIXED:
+ case APIC_DM_LOWEST:
+ /* Re-injecting a PIT interruptt? */
+ if ( re_injecting && pt->enabled &&
+ is_periodic_irq(v, intr_vector, intr_type) )
+ ++pt->pending_intr_nr;
+ /* let's inject this interrupt */
+ TRACE_3D(TRC_VMX_INTR, v->domain->domain_id, intr_vector, 0);
+ svm_inject_extint(v, intr_vector);
+ break;
+ case APIC_DM_SMI:
+ case APIC_DM_NMI:
+ case APIC_DM_INIT:
+ case APIC_DM_STARTUP:
+ default:
+ printk("Unsupported interrupt type: %d\n", intr_type);
+ BUG();
+ break;
}
+
+ hvm_interrupt_post(v, intr_vector, intr_type);
}
/*
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 59ccbb1dd0..a9cc9e9325 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -44,6 +44,7 @@
#include <asm/hvm/svm/emulate.h>
#include <asm/hvm/svm/vmmcall.h>
#include <asm/hvm/svm/intr.h>
+#include <asm/x86_emulate.h>
#include <public/sched.h>
#define SVM_EXTRA_DEBUG
@@ -53,18 +54,13 @@
/* External functions. We should move these to some suitable header file(s) */
-extern void do_nmi(struct cpu_user_regs *, unsigned long);
extern int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip,
int inst_len);
extern asmlinkage void do_IRQ(struct cpu_user_regs *);
-extern void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
- unsigned long count, int size, long value, int dir, int pvalid);
-extern int svm_instrlen(struct cpu_user_regs *regs, int mode);
extern void svm_dump_inst(unsigned long eip);
extern int svm_dbg_on;
void svm_dump_regs(const char *from, struct cpu_user_regs *regs);
-static void svm_relinquish_guest_resources(struct domain *d);
static int svm_do_vmmcall_reset_to_realmode(struct vcpu *v,
struct cpu_user_regs *regs);
@@ -195,6 +191,7 @@ static inline void svm_inject_exception(struct vcpu *v, int trap,
ASSERT(vmcb->eventinj.fields.v == 0);
vmcb->eventinj = event;
+ v->arch.hvm_svm.inject_event=1;
}
static void stop_svm(void)
@@ -216,11 +213,8 @@ static void stop_svm(void)
free_vmcb(root_vmcb[cpu]);
root_vmcb[cpu] = NULL;
root_vmcb_pa[cpu] = 0;
-
- printk("AMD SVM Extension is disabled.\n");
}
-
static void svm_store_cpu_guest_regs(
struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs)
{
@@ -258,6 +252,22 @@ static int svm_paging_enabled(struct vcpu *v)
return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
}
+static int svm_pae_enabled(struct vcpu *v)
+{
+ unsigned long cr4;
+
+ if(!svm_paging_enabled(v))
+ return 0;
+
+ cr4 = v->arch.hvm_svm.cpu_shadow_cr4;
+
+ return (cr4 & X86_CR4_PAE);
+}
+
+static int svm_long_mode_enabled(struct vcpu *v)
+{
+ return test_bit(SVM_CPU_STATE_LMA_ENABLED, &v->arch.hvm_svm.cpu_state);
+}
#define IS_CANO_ADDRESS(add) 1
@@ -267,10 +277,10 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs)
struct vcpu *vc = current;
struct vmcb_struct *vmcb = vc->arch.hvm_svm.vmcb;
- switch (regs->ecx)
+ switch ((u32)regs->ecx)
{
case MSR_EFER:
- msr_content = vmcb->efer;
+ msr_content = vmcb->efer;
msr_content &= ~EFER_SVME;
break;
@@ -305,50 +315,50 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs)
return 0;
}
- HVM_DBG_LOG(DBG_LEVEL_2, "mode_do_msr_read: msr_content: %"PRIx64"\n",
+ HVM_DBG_LOG(DBG_LEVEL_2, "msr_content: %"PRIx64"\n",
msr_content);
- regs->eax = msr_content & 0xffffffff;
- regs->edx = msr_content >> 32;
+ regs->eax = (u32)(msr_content >> 0);
+ regs->edx = (u32)(msr_content >> 32);
return 1;
}
static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
{
- u64 msr_content = regs->eax | ((u64)regs->edx << 32);
- struct vcpu *vc = current;
- struct vmcb_struct *vmcb = vc->arch.hvm_svm.vmcb;
+ u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
+ struct vcpu *v = current;
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- HVM_DBG_LOG(DBG_LEVEL_1, "mode_do_msr_write msr %lx "
- "msr_content %"PRIx64"\n",
- (unsigned long)regs->ecx, msr_content);
+ HVM_DBG_LOG(DBG_LEVEL_1, "msr %x msr_content %"PRIx64"\n",
+ (u32)regs->ecx, msr_content);
- switch (regs->ecx)
+ switch ( (u32)regs->ecx )
{
case MSR_EFER:
#ifdef __x86_64__
/* offending reserved bit will cause #GP */
if ( msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE) )
{
- printk("trying to set reserved bit in EFER\n");
- svm_inject_exception(vc, TRAP_gp_fault, 1, 0);
+ printk("Trying to set reserved bit in EFER: %"PRIx64"\n",
+ msr_content);
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
return 0;
}
/* LME: 0 -> 1 */
if ( msr_content & EFER_LME &&
- !test_bit(SVM_CPU_STATE_LME_ENABLED, &vc->arch.hvm_svm.cpu_state))
+ !test_bit(SVM_CPU_STATE_LME_ENABLED, &v->arch.hvm_svm.cpu_state))
{
- if ( svm_paging_enabled(vc) ||
+ if ( svm_paging_enabled(v) ||
!test_bit(SVM_CPU_STATE_PAE_ENABLED,
- &vc->arch.hvm_svm.cpu_state) )
+ &v->arch.hvm_svm.cpu_state) )
{
- printk("trying to set LME bit when "
+ printk("Trying to set LME bit when "
"in paging mode or PAE bit is not set\n");
- svm_inject_exception(vc, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
return 0;
}
- set_bit(SVM_CPU_STATE_LME_ENABLED, &vc->arch.hvm_svm.cpu_state);
+ set_bit(SVM_CPU_STATE_LME_ENABLED, &v->arch.hvm_svm.cpu_state);
}
/* We have already recorded that we want LME, so it will be set
@@ -363,13 +373,13 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
case MSR_FS_BASE:
case MSR_GS_BASE:
- if (!(SVM_LONG_GUEST(vc)))
- domain_crash_synchronous();
+ if ( !svm_long_mode_enabled(v) )
+ goto exit_and_crash;
if (!IS_CANO_ADDRESS(msr_content))
{
HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write\n");
- svm_inject_exception(vc, TRAP_gp_fault, 1, 0);
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
}
if (regs->ecx == MSR_FS_BASE)
@@ -401,7 +411,13 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
default:
return 0;
}
+
return 1;
+
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Fatal error writing MSR %lx\n", (long)regs->ecx);
+ domain_crash(v->domain);
+ return 1; /* handled */
}
@@ -410,20 +426,23 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
#define savedebug(_v,_reg) \
__asm__ __volatile__ ("mov %%db" #_reg ",%0" : : "r" ((_v)->debugreg[_reg]))
-
static inline void svm_save_dr(struct vcpu *v)
{
- if (v->arch.hvm_vcpu.flag_dr_dirty)
- {
- /* clear the DR dirty flag and re-enable intercepts for DR accesses */
- v->arch.hvm_vcpu.flag_dr_dirty = 0;
- v->arch.hvm_svm.vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
-
- savedebug(&v->arch.guest_context, 0);
- savedebug(&v->arch.guest_context, 1);
- savedebug(&v->arch.guest_context, 2);
- savedebug(&v->arch.guest_context, 3);
- }
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+ if ( !v->arch.hvm_vcpu.flag_dr_dirty )
+ return;
+
+ /* Clear the DR dirty flag and re-enable intercepts for DR accesses. */
+ v->arch.hvm_vcpu.flag_dr_dirty = 0;
+ v->arch.hvm_svm.vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
+
+ savedebug(&v->arch.guest_context, 0);
+ savedebug(&v->arch.guest_context, 1);
+ savedebug(&v->arch.guest_context, 2);
+ savedebug(&v->arch.guest_context, 3);
+ v->arch.guest_context.debugreg[6] = vmcb->dr6;
+ v->arch.guest_context.debugreg[7] = vmcb->dr7;
}
@@ -433,17 +452,13 @@ static inline void __restore_debug_registers(struct vcpu *v)
loaddebug(&v->arch.guest_context, 1);
loaddebug(&v->arch.guest_context, 2);
loaddebug(&v->arch.guest_context, 3);
+ /* DR6 and DR7 are loaded from the VMCB. */
}
static inline void svm_restore_dr(struct vcpu *v)
{
- struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-
- if (!vmcb)
- return;
-
- if (unlikely(vmcb->dr7 & 0xFF))
+ if ( unlikely(v->arch.guest_context.debugreg[7] & 0xFF) )
__restore_debug_registers(v);
}
@@ -456,21 +471,19 @@ static int svm_realmode(struct vcpu *v)
return (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
}
-int svm_guest_x86_mode(struct vcpu *v)
+static int svm_guest_x86_mode(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- unsigned long cr0 = vmcb->cr0, eflags = vmcb->rflags, mode;
- /* check which operating mode the guest is running */
- if( vmcb->efer & EFER_LMA )
- mode = vmcb->cs.attributes.fields.l ? 8 : 4;
- else
- mode = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE) ? 2 : 4;
- return mode;
-}
-int svm_instruction_length(struct vcpu *v)
-{
- return svm_instrlen(guest_cpu_user_regs(), svm_guest_x86_mode(v));
+ if ( vmcb->efer & EFER_LMA )
+ return (vmcb->cs.attributes.fields.l ?
+ X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+
+ if ( svm_realmode(v) )
+ return X86EMUL_MODE_REAL;
+
+ return (vmcb->cs.attributes.fields.db ?
+ X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
}
void svm_update_host_cr3(struct vcpu *v)
@@ -496,6 +509,30 @@ unsigned long svm_get_ctrl_reg(struct vcpu *v, unsigned int num)
return 0; /* dummy */
}
+static unsigned long svm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+ int long_mode = 0;
+
+#ifdef __x86_64__
+ long_mode = vmcb->cs.attributes.fields.l && (vmcb->efer & EFER_LMA);
+#endif
+ switch ( seg )
+ {
+ case seg_cs: return long_mode ? 0 : vmcb->cs.base;
+ case seg_ds: return long_mode ? 0 : vmcb->ds.base;
+ case seg_es: return long_mode ? 0 : vmcb->es.base;
+ case seg_fs: return vmcb->fs.base;
+ case seg_gs: return vmcb->gs.base;
+ case seg_ss: return long_mode ? 0 : vmcb->ss.base;
+ case seg_tr: return vmcb->tr.base;
+ case seg_gdtr: return vmcb->gdtr.base;
+ case seg_idtr: return vmcb->idtr.base;
+ case seg_ldtr: return vmcb->ldtr.base;
+ }
+ BUG();
+ return 0;
+}
/* Make sure that xen intercepts any FP accesses from current */
static void svm_stts(struct vcpu *v)
@@ -522,30 +559,10 @@ static void svm_set_tsc_offset(struct vcpu *v, u64 offset)
}
-/* SVM-specific intitialization code for VCPU application processors */
-static void svm_init_ap_context(struct vcpu_guest_context *ctxt,
- int vcpuid, int trampoline_vector)
+static void svm_init_ap_context(
+ struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector)
{
- int i;
- struct vcpu *v, *bsp = current;
- struct domain *d = bsp->domain;
- cpu_user_regs_t *regs;;
-
-
- if ((v = d->vcpu[vcpuid]) == NULL)
- {
- printk("vcpuid %d is invalid! good-bye.\n", vcpuid);
- domain_crash_synchronous();
- }
- regs = &v->arch.guest_context.user_regs;
-
memset(ctxt, 0, sizeof(*ctxt));
- for (i = 0; i < 256; ++i)
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS;
- }
-
/*
* We execute the trampoline code in real mode. The trampoline vector
@@ -554,7 +571,6 @@ static void svm_init_ap_context(struct vcpu_guest_context *ctxt,
*/
ctxt->user_regs.eip = 0x0;
ctxt->user_regs.cs = (trampoline_vector << 8);
- ctxt->flags = VGCF_HVM_GUEST;
}
static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
@@ -684,7 +700,7 @@ static void svm_load_cpu_user_regs(struct vcpu *v, struct cpu_user_regs *regs)
vmcb->rax = regs->eax;
vmcb->ss.sel = regs->ss;
vmcb->rsp = regs->esp;
- vmcb->rflags = regs->eflags;
+ vmcb->rflags = regs->eflags | 2UL;
vmcb->cs.sel = regs->cs;
vmcb->rip = regs->eip;
if (regs->eflags & EF_TF)
@@ -699,40 +715,13 @@ static void svm_load_cpu_guest_regs(
svm_load_cpu_user_regs(v, regs);
}
-int svm_long_mode_enabled(struct vcpu *v)
-{
- return SVM_LONG_GUEST(v);
-}
-
-
-
static void arch_svm_do_launch(struct vcpu *v)
{
- cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
- int error;
-
-#if 0
- if (svm_dbg_on)
- printk("Do launch\n");
-#endif
- error = construct_vmcb(&v->arch.hvm_svm, regs);
- if ( error < 0 )
- {
- if (v->vcpu_id == 0) {
- printk("Failed to construct a new VMCB for BSP.\n");
- } else {
- printk("Failed to construct a new VMCB for AP %d\n", v->vcpu_id);
- }
- domain_crash_synchronous();
- }
-
svm_do_launch(v);
-#if 0
- if (svm_dbg_on)
- svm_dump_host_regs(__func__);
-#endif
- if (v->vcpu_id != 0)
+
+ if ( v->vcpu_id != 0 )
{
+ cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
u16 cs_sel = regs->cs;
/*
* This is the launch of an AP; set state so that we begin executing
@@ -748,20 +737,9 @@ static void arch_svm_do_launch(struct vcpu *v)
reset_stack_and_jump(svm_asm_do_launch);
}
-static void svm_freeze_time(struct vcpu *v)
-{
- struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
-
- if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) {
- v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
- stop_timer(&(pt->timer));
- }
-}
-
-
static void svm_ctxt_switch_from(struct vcpu *v)
{
- svm_freeze_time(v);
+ hvm_freeze_time(v);
svm_save_dr(v);
}
@@ -781,41 +759,32 @@ static void svm_ctxt_switch_to(struct vcpu *v)
svm_restore_dr(v);
}
-
-static void svm_final_setup_guest(struct vcpu *v)
+static int svm_vcpu_initialise(struct vcpu *v)
{
- struct domain *d = v->domain;
+ int rc;
v->arch.schedule_tail = arch_svm_do_launch;
v->arch.ctxt_switch_from = svm_ctxt_switch_from;
v->arch.ctxt_switch_to = svm_ctxt_switch_to;
- if ( v != d->vcpu[0] )
- return;
+ v->arch.hvm_svm.saved_irq_vector = -1;
- if ( !shadow_mode_external(d) )
+ if ( (rc = svm_create_vmcb(v)) != 0 )
{
- DPRINTK("Can't init HVM for dom %u vcpu %u: "
- "not in shadow external mode\n", d->domain_id, v->vcpu_id);
- domain_crash(d);
+ dprintk(XENLOG_WARNING,
+ "Failed to create VMCB for vcpu %d: err=%d.\n",
+ v->vcpu_id, rc);
+ return rc;
}
- /*
- * Required to do this once per domain
- * TODO: add a seperate function to do these.
- */
- memset(&d->shared_info->evtchn_mask[0], 0xff,
- sizeof(d->shared_info->evtchn_mask));
+ return 0;
}
-
-static int svm_initialize_guest_resources(struct vcpu *v)
+static void svm_vcpu_destroy(struct vcpu *v)
{
- svm_final_setup_guest(v);
- return 1;
+ svm_destroy_vmcb(v);
}
-
int start_svm(void)
{
u32 eax, ecx, edx;
@@ -829,7 +798,15 @@ int start_svm(void)
if (!(test_bit(X86_FEATURE_SVME, &boot_cpu_data.x86_capability)))
return 0;
-
+
+ /* check whether SVM feature is disabled in BIOS */
+ rdmsr(MSR_K8_VM_CR, eax, edx);
+ if ( eax & K8_VMCR_SVME_DISABLE )
+ {
+ printk("AMD SVM Extension is disabled in BIOS.\n");
+ return 0;
+ }
+
if (!(hsa[cpu] = alloc_host_save_area()))
return 0;
@@ -855,18 +832,18 @@ int start_svm(void)
/* Setup HVM interfaces */
hvm_funcs.disable = stop_svm;
- hvm_funcs.initialize_guest_resources = svm_initialize_guest_resources;
- hvm_funcs.relinquish_guest_resources = svm_relinquish_guest_resources;
+ hvm_funcs.vcpu_initialise = svm_vcpu_initialise;
+ hvm_funcs.vcpu_destroy = svm_vcpu_destroy;
hvm_funcs.store_cpu_guest_regs = svm_store_cpu_guest_regs;
hvm_funcs.load_cpu_guest_regs = svm_load_cpu_guest_regs;
- hvm_funcs.realmode = svm_realmode;
hvm_funcs.paging_enabled = svm_paging_enabled;
hvm_funcs.long_mode_enabled = svm_long_mode_enabled;
+ hvm_funcs.pae_enabled = svm_pae_enabled;
hvm_funcs.guest_x86_mode = svm_guest_x86_mode;
- hvm_funcs.instruction_length = svm_instruction_length;
hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg;
+ hvm_funcs.get_segment_base = svm_get_segment_base;
hvm_funcs.update_host_cr3 = svm_update_host_cr3;
@@ -881,50 +858,6 @@ int start_svm(void)
return 1;
}
-
-static void svm_relinquish_guest_resources(struct domain *d)
-{
- struct vcpu *v;
-
- for_each_vcpu ( d, v )
- {
- if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
- continue;
-
- destroy_vmcb(&v->arch.hvm_svm);
- kill_timer(&v->arch.hvm_vcpu.hlt_timer);
- if ( hvm_apic_support(v->domain) && (VLAPIC(v) != NULL) )
- {
- kill_timer( &(VLAPIC(v)->vlapic_timer) );
- xfree(VLAPIC(v));
- }
- }
-
- kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
-
- if ( d->arch.hvm_domain.shared_page_va )
- unmap_domain_page_global(
- (void *)d->arch.hvm_domain.shared_page_va);
-
- if ( d->arch.hvm_domain.buffered_io_va )
- unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
-}
-
-
-static void svm_migrate_timers(struct vcpu *v)
-{
- struct periodic_time *pt =
- &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
-
- if ( pt->enabled ) {
- migrate_timer( &pt->timer, v->processor );
- migrate_timer( &v->arch.hvm_vcpu.hlt_timer, v->processor );
- }
- if ( hvm_apic_support(v->domain) && VLAPIC( v ))
- migrate_timer( &(VLAPIC(v)->vlapic_timer ), v->processor );
-}
-
-
void arch_svm_do_resume(struct vcpu *v)
{
/* pinning VCPU to a different core? */
@@ -937,14 +870,12 @@ void arch_svm_do_resume(struct vcpu *v)
printk("VCPU core pinned: %d to %d\n",
v->arch.hvm_svm.launch_core, smp_processor_id() );
v->arch.hvm_svm.launch_core = smp_processor_id();
- svm_migrate_timers( v );
+ hvm_migrate_timers( v );
hvm_do_resume( v );
reset_stack_and_jump( svm_asm_do_resume );
}
}
-
-
static int svm_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
{
struct vcpu *v = current;
@@ -996,11 +927,12 @@ static void svm_do_general_protection_fault(struct vcpu *v,
error_code = vmcb->exitinfo1;
if (vmcb->idtr.limit == 0) {
- printf("Huh? We got a GP Fault with an invalid IDTR!\n");
+ printk("Huh? We got a GP Fault with an invalid IDTR!\n");
svm_dump_vmcb(__func__, vmcb);
svm_dump_regs(__func__, regs);
- svm_dump_inst(vmcb->rip);
- __hvm_bug(regs);
+ svm_dump_inst(svm_rip2pointer(vmcb));
+ domain_crash(v->domain);
+ return;
}
HVM_DBG_LOG(DBG_LEVEL_1,
@@ -1041,95 +973,72 @@ static void svm_vmexit_do_cpuid(struct vmcb_struct *vmcb, unsigned long input,
(unsigned long)regs->ecx, (unsigned long)regs->edx,
(unsigned long)regs->esi, (unsigned long)regs->edi);
- cpuid(input, &eax, &ebx, &ecx, &edx);
-
- if (input == 0x00000001)
+ if ( !cpuid_hypervisor_leaves(input, &eax, &ebx, &ecx, &edx) )
{
- if ( !hvm_apic_support(v->domain) ||
- !vlapic_global_enabled((VLAPIC(v))) )
+ cpuid(input, &eax, &ebx, &ecx, &edx);
+ if (input == 0x00000001 || input == 0x80000001 )
{
- /* Since the apic is disabled, avoid any confusion
- about SMP cpus being available */
- clear_bit(X86_FEATURE_APIC, &edx);
- }
-
+ if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
+ {
+ /* Since the apic is disabled, avoid any confusion
+ about SMP cpus being available */
+ clear_bit(X86_FEATURE_APIC, &edx);
+ }
#if CONFIG_PAGING_LEVELS >= 3
- if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
+ if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
#endif
- clear_bit(X86_FEATURE_PAE, &edx);
- clear_bit(X86_FEATURE_PSE36, &edx);
-
- /* Clear out reserved bits. */
- ecx &= ~SVM_VCPU_CPUID_L1_ECX_RESERVED;
- edx &= ~SVM_VCPU_CPUID_L1_EDX_RESERVED;
+ {
+ clear_bit(X86_FEATURE_PAE, &edx);
+ if (input == 0x80000001 )
+ clear_bit(X86_FEATURE_NX & 31, &edx);
+ }
+ clear_bit(X86_FEATURE_PSE36, &edx);
+ if (input == 0x00000001 )
+ {
+ /* Clear out reserved bits. */
+ ecx &= ~SVM_VCPU_CPUID_L1_ECX_RESERVED;
+ edx &= ~SVM_VCPU_CPUID_L1_EDX_RESERVED;
- clear_bit(X86_FEATURE_MWAIT & 31, &ecx);
+ clear_bit(X86_FEATURE_MWAIT & 31, &ecx);
- /* Guest should only see one logical processor.
- * See details on page 23 of AMD CPUID Specification.
- */
- clear_bit(X86_FEATURE_HT, &edx); /* clear the hyperthread bit */
- ebx &= 0xFF00FFFF; /* clear the logical processor count when HTT=0 */
- ebx |= 0x00010000; /* set to 1 just for precaution */
+ /* Guest should only see one logical processor.
+ * See details on page 23 of AMD CPUID Specification.
+ */
+ clear_bit(X86_FEATURE_HT, &edx); /* clear the hyperthread bit */
+ ebx &= 0xFF00FFFF; /* clear the logical processor count when HTT=0 */
+ ebx |= 0x00010000; /* set to 1 just for precaution */
+ }
+ else
+ {
+ /* Clear the Cmp_Legacy bit
+ * This bit is supposed to be zero when HTT = 0.
+ * See details on page 23 of AMD CPUID Specification.
+ */
+ clear_bit(X86_FEATURE_CMP_LEGACY & 31, &ecx);
+ /* Make SVM feature invisible to the guest. */
+ clear_bit(X86_FEATURE_SVME & 31, &ecx);
+#ifdef __i386__
+ /* Mask feature for Intel ia32e or AMD long mode. */
+ clear_bit(X86_FEATURE_LAHF_LM & 31, &ecx);
- /* Disable machine check architecture */
- clear_bit(X86_FEATURE_MCA, &edx);
- clear_bit(X86_FEATURE_MCE, &edx);
- }
- else if ( (input > 0x00000005) && (input < 0x80000000) )
- {
- if ( !cpuid_hypervisor_leaves(input, &eax, &ebx, &ecx, &edx) )
+ clear_bit(X86_FEATURE_LM & 31, &edx);
+ clear_bit(X86_FEATURE_SYSCALL & 31, &edx);
+#endif
+ /* So far, we do not support 3DNow for the guest. */
+ clear_bit(X86_FEATURE_3DNOW & 31, &edx);
+ clear_bit(X86_FEATURE_3DNOWEXT & 31, &edx);
+ }
+ }
+ else if ( ( input == 0x80000007 ) || ( input == 0x8000000A ) )
+ {
+ /* Mask out features of power management and SVM extension. */
eax = ebx = ecx = edx = 0;
- }
- else if ( input == 0x80000001 )
- {
- /* We duplicate some CPUID_00000001 code because many bits of
- CPUID_80000001_EDX overlaps with CPUID_00000001_EDX. */
-
- if ( !hvm_apic_support(v->domain) ||
- !vlapic_global_enabled((VLAPIC(v))) )
+ }
+ else if ( input == 0x80000008 )
{
- /* Since the apic is disabled, avoid any confusion
- about SMP cpus being available */
- clear_bit(X86_FEATURE_APIC, &edx);
+ /* Make sure Number of CPU core is 1 when HTT=0 */
+ ecx &= 0xFFFFFF00;
}
-
- /* Clear the Cmp_Legacy bit
- * This bit is supposed to be zero when HTT = 0.
- * See details on page 23 of AMD CPUID Specification.
- */
- clear_bit(X86_FEATURE_CMP_LEGACY & 31, &ecx);
-
-#ifdef __i386__
- /* Mask feature for Intel ia32e or AMD long mode. */
- clear_bit(X86_FEATURE_LAHF_LM & 31, &ecx);
-
- clear_bit(X86_FEATURE_LM & 31, &edx);
- clear_bit(X86_FEATURE_SYSCALL & 31, &edx);
-#endif
-
-
-#if CONFIG_PAGING_LEVELS >= 3
- if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
-#endif
- clear_bit(X86_FEATURE_PAE, &edx);
- clear_bit(X86_FEATURE_PSE36, &edx);
-
- /* Make SVM feature invisible to the guest. */
- clear_bit(X86_FEATURE_SVME & 31, &ecx);
-
- /* So far, we do not support 3DNow for the guest. */
- clear_bit(X86_FEATURE_3DNOW & 31, &edx);
- clear_bit(X86_FEATURE_3DNOWEXT & 31, &edx);
- }
- else if ( ( input == 0x80000007 ) || ( input == 0x8000000A ) )
- {
- /* Mask out features of power management and SVM extension. */
- eax = ebx = ecx = edx = 0;
- }
- else if ( input == 0x80000008 )
- {
- ecx &= 0xFFFFFF00; /* Make sure Number of CPU core is 1 when HTT=0 */
}
regs->eax = (unsigned long)eax;
@@ -1254,8 +1163,9 @@ static void svm_get_prefix_info(
if (inst_copy_from_guest(inst, svm_rip2pointer(vmcb), sizeof(inst))
!= MAX_INST_LEN)
{
- printk("%s: get guest instruction failed\n", __func__);
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "get guest instruction failed\n");
+ domain_crash(current->domain);
+ return;
}
for (i = 0; i < MAX_INST_LEN; i++)
@@ -1318,22 +1228,20 @@ static void svm_get_prefix_info(
/* Get the address of INS/OUTS instruction */
static inline int svm_get_io_address(
- struct vcpu *v,
- struct cpu_user_regs *regs, unsigned int dir,
+ struct vcpu *v, struct cpu_user_regs *regs,
+ unsigned int size, ioio_info_t info,
unsigned long *count, unsigned long *addr)
{
unsigned long reg;
- unsigned int asize = 0;
- unsigned int isize;
- int long_mode;
- ioio_info_t info;
+ unsigned int asize, isize;
+ int long_mode = 0;
segment_selector_t *seg = NULL;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- info.bytes = vmcb->exitinfo1;
-
+#ifdef __x86_64__
/* If we're in long mode, we shouldn't check the segment presence & limit */
long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA;
+#endif
/* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit.
* l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit.
@@ -1351,28 +1259,32 @@ static inline int svm_get_io_address(
isize --;
if (isize > 1)
- {
- svm_get_prefix_info(vmcb, dir, &seg, &asize);
- }
-
- ASSERT(dir == IOREQ_READ || dir == IOREQ_WRITE);
+ svm_get_prefix_info(vmcb, info.fields.type, &seg, &asize);
- if (dir == IOREQ_WRITE)
+ if (info.fields.type == IOREQ_WRITE)
{
reg = regs->esi;
if (!seg) /* If no prefix, used DS. */
seg = &vmcb->ds;
+ if (!long_mode && (seg->attributes.fields.type & 0xa) == 0x8) {
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ return 0;
+ }
}
else
{
reg = regs->edi;
seg = &vmcb->es; /* Note: This is ALWAYS ES. */
+ if (!long_mode && (seg->attributes.fields.type & 0xa) != 0x2) {
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ return 0;
+ }
}
/* If the segment isn't present, give GP fault! */
if (!long_mode && !seg->attributes.fields.p)
{
- svm_inject_exception(v, TRAP_gp_fault, 1, seg->sel);
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
return 0;
}
@@ -1386,19 +1298,65 @@ static inline int svm_get_io_address(
*addr = reg;
*count = regs->ecx;
}
+ if (!info.fields.rep)
+ *count = 1;
- if (!long_mode) {
- if (*addr > seg->limit)
+ if (!long_mode)
+ {
+ ASSERT(*addr == (u32)*addr);
+ if ((u32)(*addr + size - 1) < (u32)*addr ||
+ (seg->attributes.fields.type & 0xc) != 0x4 ?
+ *addr + size - 1 > seg->limit :
+ *addr <= seg->limit)
{
- svm_inject_exception(v, TRAP_gp_fault, 1, seg->sel);
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
return 0;
- }
- else
+ }
+
+ /* Check the limit for repeated instructions, as above we checked only
+ the first instance. Truncate the count if a limit violation would
+ occur. Note that the checking is not necessary for page granular
+ segments as transfers crossing page boundaries will be broken up
+ anyway. */
+ if (!seg->attributes.fields.g && *count > 1)
{
- *addr += seg->base;
+ if ((seg->attributes.fields.type & 0xc) != 0x4)
+ {
+ /* expand-up */
+ if (!(regs->eflags & EF_DF))
+ {
+ if (*addr + *count * size - 1 < *addr ||
+ *addr + *count * size - 1 > seg->limit)
+ *count = (seg->limit + 1UL - *addr) / size;
+ }
+ else
+ {
+ if (*count - 1 > *addr / size)
+ *count = *addr / size + 1;
+ }
+ }
+ else
+ {
+ /* expand-down */
+ if (!(regs->eflags & EF_DF))
+ {
+ if (*count - 1 > -(s32)*addr / size)
+ *count = -(s32)*addr / size + 1UL;
+ }
+ else
+ {
+ if (*addr < (*count - 1) * size ||
+ *addr - (*count - 1) * size <= seg->limit)
+ *count = (*addr - seg->limit - 1) / size + 1;
+ }
+ }
+ ASSERT(*count);
}
+
+ *addr += seg->base;
}
-
+ else if (seg == &vmcb->fs || seg == &vmcb->gs)
+ *addr += seg->base;
return 1;
}
@@ -1409,7 +1367,7 @@ static void svm_io_instruction(struct vcpu *v)
struct cpu_user_regs *regs;
struct hvm_io_op *pio_opp;
unsigned int port;
- unsigned int size, dir;
+ unsigned int size, dir, df;
ioio_info_t info;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -1428,6 +1386,8 @@ static void svm_io_instruction(struct vcpu *v)
port = info.fields.port; /* port used to be addr */
dir = info.fields.type; /* direction */
+ df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
+
if (info.fields.sz32)
size = 4;
else if (info.fields.sz16)
@@ -1444,9 +1404,9 @@ static void svm_io_instruction(struct vcpu *v)
if (info.fields.str)
{
unsigned long addr, count;
- int sign = regs->eflags & EF_DF ? -1 : 1;
+ int sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;
- if (!svm_get_io_address(v, regs, dir, &count, &addr))
+ if (!svm_get_io_address(v, regs, size, info, &count, &addr))
{
/* We failed to get a valid address, so don't do the IO operation -
* it would just get worse if we do! Hopefully the guest is handing
@@ -1460,10 +1420,6 @@ static void svm_io_instruction(struct vcpu *v)
{
pio_opp->flags |= REPZ;
}
- else
- {
- count = 1;
- }
/*
* Handle string pio instructions that cross pages or that
@@ -1474,25 +1430,37 @@ static void svm_io_instruction(struct vcpu *v)
unsigned long value = 0;
pio_opp->flags |= OVERLAP;
+ pio_opp->addr = addr;
- if (dir == IOREQ_WRITE)
- hvm_copy(&value, addr, size, HVM_COPY_IN);
+ if (dir == IOREQ_WRITE) /* OUTS */
+ {
+ if (hvm_paging_enabled(current))
+ (void)hvm_copy_from_guest_virt(&value, addr, size);
+ else
+ (void)hvm_copy_from_guest_phys(&value, addr, size);
+ }
- send_pio_req(regs, port, 1, size, value, dir, 0);
+ if (count == 1)
+ regs->eip = vmcb->exitinfo2;
+
+ send_pio_req(port, 1, size, value, dir, df, 0);
}
else
{
- if ((addr & PAGE_MASK) != ((addr + count * size - 1) & PAGE_MASK))
+ unsigned long last_addr = sign > 0 ? addr + count * size - 1
+ : addr - (count - 1) * size;
+
+ if ((addr & PAGE_MASK) != (last_addr & PAGE_MASK))
{
if (sign > 0)
count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
else
- count = (addr & ~PAGE_MASK) / size;
+ count = (addr & ~PAGE_MASK) / size + 1;
}
else
regs->eip = vmcb->exitinfo2;
- send_pio_req(regs, port, count, size, addr, dir, 1);
+ send_pio_req(port, count, size, addr, dir, df, 1);
}
}
else
@@ -1506,7 +1474,7 @@ static void svm_io_instruction(struct vcpu *v)
if (port == 0xe9 && dir == IOREQ_WRITE && size == 1)
hvm_print_line(v, regs->eax); /* guest debug output */
- send_pio_req(regs, port, 1, size, regs->eax, dir, 0);
+ send_pio_req(port, 1, size, regs->eax, dir, df, 0);
}
}
@@ -1523,7 +1491,7 @@ static int svm_set_cr0(unsigned long value)
/* We don't want to lose PG. ET is reserved and should be always be 1*/
paging_enabled = svm_paging_enabled(v);
value |= X86_CR0_ET;
- vmcb->cr0 = value | X86_CR0_PG;
+ vmcb->cr0 = value | X86_CR0_PG | X86_CR0_WP;
v->arch.hvm_svm.cpu_shadow_cr0 = value;
/* TS cleared? Then initialise FPU now. */
@@ -1538,12 +1506,13 @@ static int svm_set_cr0(unsigned long value)
if ((value & X86_CR0_PE) && (value & X86_CR0_PG) && !paging_enabled)
{
/* The guest CR3 must be pointing to the guest physical. */
- if (!VALID_MFN(mfn =
- get_mfn_from_gpfn(v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT))
- || !get_page(mfn_to_page(mfn), v->domain))
+ mfn = get_mfn_from_gpfn(v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain))
{
- printk("Invalid CR3 value = %lx\n", v->arch.hvm_svm.cpu_cr3);
- domain_crash_synchronous(); /* need to take a clean path */
+ gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n",
+ v->arch.hvm_svm.cpu_cr3, mfn);
+ domain_crash(v->domain);
+ return 0;
}
#if defined(__x86_64__)
@@ -1557,11 +1526,9 @@ static int svm_set_cr0(unsigned long value)
if (test_bit(SVM_CPU_STATE_LME_ENABLED, &v->arch.hvm_svm.cpu_state))
{
- /* Here the PAE is should to be opened */
HVM_DBG_LOG(DBG_LEVEL_1, "Enable the Long mode\n");
- set_bit(SVM_CPU_STATE_LMA_ENABLED,
- &v->arch.hvm_svm.cpu_state);
- vmcb->efer |= (EFER_LMA | EFER_LME);
+ set_bit(SVM_CPU_STATE_LMA_ENABLED, &v->arch.hvm_svm.cpu_state);
+ vmcb->efer |= EFER_LMA | EFER_LME;
}
#endif /* __x86_64__ */
@@ -1602,6 +1569,11 @@ static int svm_set_cr0(unsigned long value)
}
else if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PE )
{
+ if ( svm_long_mode_enabled(v) )
+ {
+ vmcb->efer &= ~EFER_LMA;
+ clear_bit(SVM_CPU_STATE_LMA_ENABLED, &v->arch.hvm_svm.cpu_state);
+ }
/* we should take care of this kind of situation */
shadow_update_paging_modes(v);
vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
@@ -1618,12 +1590,13 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
{
unsigned long value = 0;
struct vcpu *v = current;
+ struct vlapic *vlapic = vcpu_vlapic(v);
struct vmcb_struct *vmcb;
vmcb = v->arch.hvm_svm.vmcb;
ASSERT(vmcb);
- switch (cr)
+ switch ( cr )
{
case 0:
value = v->arch.hvm_svm.cpu_shadow_cr0;
@@ -1641,18 +1614,16 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
case 4:
value = (unsigned long) v->arch.hvm_svm.cpu_shadow_cr4;
if (svm_dbg_on)
- printk( "CR4 read=%lx\n", value );
+ printk("CR4 read=%lx\n", value);
break;
case 8:
-#if 0
- value = vmcb->m_cr8;
-#else
- ASSERT(0);
-#endif
+ value = (unsigned long)vlapic_get_reg(vlapic, APIC_TASKPRI);
+ value = (value & 0xF0) >> 4;
break;
default:
- __hvm_bug(regs);
+ domain_crash(v->domain);
+ return;
}
set_reg(gp, value, regs, vmcb);
@@ -1672,13 +1643,11 @@ static inline int svm_pgbit_test(struct vcpu *v)
*/
static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
{
- unsigned long value;
- unsigned long old_cr;
+ unsigned long value, old_cr, old_base_mfn, mfn;
struct vcpu *v = current;
+ struct vlapic *vlapic = vcpu_vlapic(v);
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- ASSERT(vmcb);
-
value = get_reg(gpreg, regs, vmcb);
HVM_DBG_LOG(DBG_LEVEL_1, "mov_to_cr: CR%d, value = %lx,", cr, value);
@@ -1692,8 +1661,6 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
return svm_set_cr0(value);
case 3:
- {
- unsigned long old_base_mfn, mfn;
if (svm_dbg_on)
printk("CR3 write =%lx \n", value );
/* If paging is not enabled yet, simply copy the value to CR3. */
@@ -1713,7 +1680,7 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
*/
mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT);
if (mfn != pagetable_get_pfn(v->arch.guest_table))
- __hvm_bug(regs);
+ goto bad_cr3;
shadow_update_cr3(v);
}
else
@@ -1723,13 +1690,9 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
* first.
*/
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx", value);
- if (((value >> PAGE_SHIFT) > v->domain->max_pages)
- || !VALID_MFN(mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT))
- || !get_page(mfn_to_page(mfn), v->domain))
- {
- printk("Invalid CR3 value=%lx\n", value);
- domain_crash_synchronous(); /* need to take a clean path */
- }
+ mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain))
+ goto bad_cr3;
old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
v->arch.guest_table = pagetable_from_pfn(mfn);
@@ -1737,19 +1700,14 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
if (old_base_mfn)
put_page(mfn_to_page(old_base_mfn));
- /*
- * arch.shadow_table should now hold the next CR3 for shadow
- */
v->arch.hvm_svm.cpu_cr3 = value;
update_cr3(v);
vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx", value);
}
break;
- }
case 4: /* CR4 */
- {
if (svm_dbg_on)
printk( "write cr4=%lx, cr0=%lx\n",
value, v->arch.hvm_svm.cpu_shadow_cr0 );
@@ -1762,14 +1720,10 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
/* The guest is a 32-bit PAE guest. */
#if CONFIG_PAGING_LEVELS >= 3
unsigned long mfn, old_base_mfn;
-
- if ( !VALID_MFN(mfn = get_mfn_from_gpfn(
- v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT)) ||
+ mfn = get_mfn_from_gpfn(v->arch.hvm_svm.cpu_cr3 >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) ||
!get_page(mfn_to_page(mfn), v->domain) )
- {
- printk("Invalid CR3 value = %lx", v->arch.hvm_svm.cpu_cr3);
- domain_crash_synchronous(); /* need to take a clean path */
- }
+ goto bad_cr3;
/*
* Now arch.guest_table points to machine physical.
@@ -1786,10 +1740,6 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
- /*
- * arch->shadow_table should hold the next CR3 for shadow
- */
-
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"Update CR3 value = %lx, mfn = %lx",
v->arch.hvm_svm.cpu_cr3, mfn);
@@ -1819,14 +1769,23 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
shadow_update_paging_modes(v);
}
break;
- }
+
+ case 8:
+ vlapic_set_reg(vlapic, APIC_TASKPRI, ((value & 0x0F) << 4));
+ break;
default:
- printk("invalid cr: %d\n", cr);
- __hvm_bug(regs);
+ gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);
+ domain_crash(v->domain);
+ return 0;
}
return 1;
+
+ bad_cr3:
+ gdprintk(XENLOG_ERR, "Invalid CR3\n");
+ domain_crash(v->domain);
+ return 0;
}
@@ -1856,12 +1815,12 @@ static int svm_cr_access(struct vcpu *v, unsigned int cr, unsigned int type,
where the prefix lives later on */
index = skip_prefix_bytes(buffer, sizeof(buffer));
- if (type == TYPE_MOV_TO_CR)
+ if ( type == TYPE_MOV_TO_CR )
{
inst_len = __get_instruction_length_from_list(
vmcb, list_a, ARR_SIZE(list_a), &buffer[index], &match);
}
- else
+ else /* type == TYPE_MOV_FROM_CR */
{
inst_len = __get_instruction_length_from_list(
vmcb, list_b, ARR_SIZE(list_b), &buffer[index], &match);
@@ -1929,8 +1888,7 @@ static int svm_cr_access(struct vcpu *v, unsigned int cr, unsigned int type,
break;
default:
- __hvm_bug(regs);
- break;
+ BUG();
}
ASSERT(inst_len);
@@ -1946,22 +1904,18 @@ static inline void svm_do_msr_access(
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
int inst_len;
u64 msr_content=0;
- u32 eax, edx;
+ u32 ecx = regs->ecx, eax, edx;
ASSERT(vmcb);
- HVM_DBG_LOG(DBG_LEVEL_1, "svm_do_msr_access: ecx=%lx, eax=%lx, edx=%lx, "
- "exitinfo = %lx", (unsigned long)regs->ecx,
- (unsigned long)regs->eax, (unsigned long)regs->edx,
+ HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x, exitinfo = %lx",
+ ecx, (u32)regs->eax, (u32)regs->edx,
(unsigned long)vmcb->exitinfo1);
/* is it a read? */
if (vmcb->exitinfo1 == 0)
{
- inst_len = __get_instruction_length(vmcb, INSTR_RDMSR, NULL);
-
- regs->edx = 0;
- switch (regs->ecx) {
+ switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER:
msr_content = hvm_get_guest_time(v);
break;
@@ -1975,31 +1929,36 @@ static inline void svm_do_msr_access(
msr_content = vmcb->sysenter_eip;
break;
case MSR_IA32_APICBASE:
- msr_content = VLAPIC(v) ? VLAPIC(v)->apic_base_msr : 0;
+ msr_content = vcpu_vlapic(v)->apic_base_msr;
break;
default:
if (long_mode_do_msr_read(regs))
goto done;
- if ( rdmsr_hypervisor_regs(regs->ecx, &eax, &edx) )
+ if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
+ rdmsr_safe(ecx, eax, edx) == 0 )
{
regs->eax = eax;
regs->edx = edx;
goto done;
}
-
- rdmsr_safe(regs->ecx, regs->eax, regs->edx);
- break;
+ svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+ return;
}
regs->eax = msr_content & 0xFFFFFFFF;
regs->edx = msr_content >> 32;
+
+ done:
+ HVM_DBG_LOG(DBG_LEVEL_1, "returns: ecx=%x, eax=%lx, edx=%lx",
+ ecx, (unsigned long)regs->eax, (unsigned long)regs->edx);
+
+ inst_len = __get_instruction_length(vmcb, INSTR_RDMSR, NULL);
}
else
{
- inst_len = __get_instruction_length(vmcb, INSTR_WRMSR, NULL);
- msr_content = (regs->eax & 0xFFFFFFFF) | ((u64)regs->edx << 32);
+ msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
- switch (regs->ecx)
+ switch (ecx)
{
case MSR_IA32_TIME_STAMP_COUNTER:
hvm_set_guest_time(v, msr_content);
@@ -2014,21 +1973,16 @@ static inline void svm_do_msr_access(
vmcb->sysenter_eip = msr_content;
break;
case MSR_IA32_APICBASE:
- vlapic_msr_set(VLAPIC(v), msr_content);
+ vlapic_msr_set(vcpu_vlapic(v), msr_content);
break;
default:
if ( !long_mode_do_msr_write(regs) )
- wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx);
+ wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
break;
}
- }
-
- done:
- HVM_DBG_LOG(DBG_LEVEL_1, "svm_do_msr_access returns: "
- "ecx=%lx, eax=%lx, edx=%lx",
- (unsigned long)regs->ecx, (unsigned long)regs->eax,
- (unsigned long)regs->edx);
+ inst_len = __get_instruction_length(vmcb, INSTR_WRMSR, NULL);
+ }
__update_guest_eip(vmcb, inst_len);
}
@@ -2109,16 +2063,15 @@ void svm_handle_invlpg(const short invlpga, struct cpu_user_regs *regs)
int inst_len;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- ASSERT(vmcb);
/*
* Unknown how many bytes the invlpg instruction will take. Use the
* maximum instruction length here
*/
if (inst_copy_from_guest(opcode, svm_rip2pointer(vmcb), length) < length)
{
- printk("svm_handle_invlpg (): Error reading memory %d bytes\n",
- length);
- __hvm_bug(regs);
+ gdprintk(XENLOG_ERR, "Error reading memory %d bytes\n", length);
+ domain_crash(v->domain);
+ return;
}
if (invlpga)
@@ -2145,10 +2098,10 @@ void svm_handle_invlpg(const short invlpga, struct cpu_user_regs *regs)
/*
* Decode memory operand of the instruction including ModRM, SIB, and
- * displacement to get effecticve address and length in bytes. Assume
+ * displacement to get effective address and length in bytes. Assume
* the system in either 32- or 64-bit mode.
*/
- g_vaddr = get_effective_addr_modrm64(vmcb, regs, prefix,
+ g_vaddr = get_effective_addr_modrm64(vmcb, regs, prefix, inst_len,
&opcode[inst_len], &length);
inst_len += length;
@@ -2186,7 +2139,7 @@ static int svm_do_vmmcall_reset_to_realmode(struct vcpu *v,
vmcb->tsc_offset = 0;
/* VMCB State */
- vmcb->cr0 = X86_CR0_ET | X86_CR0_PG;
+ vmcb->cr0 = X86_CR0_ET | X86_CR0_PG | X86_CR0_WP;
v->arch.hvm_svm.cpu_shadow_cr0 = X86_CR0_ET;
vmcb->cr2 = 0;
@@ -2278,7 +2231,7 @@ static int svm_do_vmmcall(struct vcpu *v, struct cpu_user_regs *regs)
/* VMMCALL sanity check */
if ( vmcb->cpl > get_vmmcall_cpl(regs->edi) )
{
- printf("VMMCALL CPL check failed\n");
+ printk("VMMCALL CPL check failed\n");
return -1;
}
@@ -2288,7 +2241,7 @@ static int svm_do_vmmcall(struct vcpu *v, struct cpu_user_regs *regs)
case VMMCALL_RESET_TO_REALMODE:
if ( svm_do_vmmcall_reset_to_realmode(v, regs) )
{
- printf("svm_do_vmmcall_reset_to_realmode() failed\n");
+ printk("svm_do_vmmcall_reset_to_realmode() failed\n");
return -1;
}
/* since we just reset the VMCB, return without adjusting
@@ -2296,7 +2249,7 @@ static int svm_do_vmmcall(struct vcpu *v, struct cpu_user_regs *regs)
return 0;
case VMMCALL_DEBUG:
- printf("DEBUG features not implemented yet\n");
+ printk("DEBUG features not implemented yet\n");
break;
default:
break;
@@ -2324,19 +2277,19 @@ void svm_dump_inst(unsigned long eip)
ptr = eip & ~0xff;
len = 0;
- if (hvm_copy(opcode, ptr, sizeof(opcode), HVM_COPY_IN))
+ if (hvm_copy_from_guest_virt(opcode, ptr, sizeof(opcode)) == 0)
len = sizeof(opcode);
- printf("Code bytes around(len=%d) %lx:", len, eip);
+ printk("Code bytes around(len=%d) %lx:", len, eip);
for (i = 0; i < len; i++)
{
if ((i & 0x0f) == 0)
- printf("\n%08lx:", ptr+i);
+ printk("\n%08lx:", ptr+i);
- printf("%02x ", opcode[i]);
+ printk("%02x ", opcode[i]);
}
- printf("\n");
+ printk("\n");
}
@@ -2344,9 +2297,9 @@ void svm_dump_regs(const char *from, struct cpu_user_regs *regs)
{
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- unsigned long pt = pagetable_get_paddr(v->arch.shadow_table);
+ unsigned long pt = v->arch.hvm_vcpu.hw_cr3;
- printf("%s: guest registers from %s:\n", __func__, from);
+ printk("%s: guest registers from %s:\n", __func__, from);
#if defined (__x86_64__)
printk("rax: %016lx rbx: %016lx rcx: %016lx\n",
regs->rax, regs->rbx, regs->rcx);
@@ -2361,15 +2314,15 @@ void svm_dump_regs(const char *from, struct cpu_user_regs *regs)
printk("r15: %016lx cr0: %016lx cr3: %016lx\n",
regs->r15, v->arch.hvm_svm.cpu_shadow_cr0, vmcb->cr3);
#else
- printf("eax: %08x, ebx: %08x, ecx: %08x, edx: %08x\n",
+ printk("eax: %08x, ebx: %08x, ecx: %08x, edx: %08x\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
- printf("edi: %08x, esi: %08x, ebp: %08x, esp: %08x\n",
+ printk("edi: %08x, esi: %08x, ebp: %08x, esp: %08x\n",
regs->edi, regs->esi, regs->ebp, regs->esp);
- printf("%s: guest cr0: %lx\n", __func__,
+ printk("%s: guest cr0: %lx\n", __func__,
v->arch.hvm_svm.cpu_shadow_cr0);
- printf("guest CR3 = %llx\n", vmcb->cr3);
+ printk("guest CR3 = %llx\n", vmcb->cr3);
#endif
- printf("%s: pt = %lx\n", __func__, pt);
+ printk("%s: pt = %lx\n", __func__, pt);
}
@@ -2378,12 +2331,12 @@ void svm_dump_host_regs(const char *from)
struct vcpu *v = current;
unsigned long pt = pt = pagetable_get_paddr(v->arch.monitor_table);
unsigned long cr3, cr0;
- printf("Host registers at %s\n", from);
+ printk("Host registers at %s\n", from);
__asm__ __volatile__ ("\tmov %%cr0,%0\n"
"\tmov %%cr3,%1\n"
: "=r" (cr0), "=r"(cr3));
- printf("%s: pt = %lx, cr3 = %lx, cr0 = %lx\n", __func__, pt, cr3, cr0);
+ printk("%s: pt = %lx, cr3 = %lx, cr0 = %lx\n", __func__, pt, cr3, cr0);
}
#ifdef SVM_EXTRA_DEBUG
@@ -2526,10 +2479,10 @@ void walk_shadow_and_guest_pt(unsigned long gva)
l1_pgentry_t spte;
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- unsigned long gpa;
+ paddr_t gpa;
gpa = shadow_gva_to_gpa(current, gva);
- printk( "gva = %lx, gpa=%lx, gCR3=%x\n", gva, gpa, (u32)vmcb->cr3 );
+ printk("gva = %lx, gpa=%"PRIpaddr", gCR3=%x\n", gva, gpa, (u32)vmcb->cr3);
if( !svm_paging_enabled(v) || mmio_space(gpa) )
return;
@@ -2563,9 +2516,7 @@ void walk_shadow_and_guest_pt(unsigned long gva)
#endif /* SVM_WALK_GUEST_PAGES */
-
-
-asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
+asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
{
unsigned int exit_reason;
unsigned long eip;
@@ -2577,15 +2528,14 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
ASSERT(vmcb);
exit_reason = vmcb->exitcode;
- save_svm_cpu_user_regs(v, &regs);
-
- vmcb->tlb_control = 1;
+ save_svm_cpu_user_regs(v, regs);
+ v->arch.hvm_svm.inject_event = 0;
if (exit_reason == VMEXIT_INVALID)
{
svm_dump_vmcb(__func__, vmcb);
- domain_crash_synchronous();
+ goto exit_and_crash;
}
#ifdef SVM_EXTRA_DEBUG
@@ -2601,26 +2551,26 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
if (svm_paging_enabled(v) &&
!mmio_space(shadow_gva_to_gpa(current, vmcb->exitinfo2)))
{
- printk("I%08ld,ExC=%s(%d),IP=%x:%llx,"
- "I1=%llx,I2=%llx,INT=%llx, "
- "gpa=%llx\n", intercepts_counter,
- exit_reasons[exit_reason], exit_reason, regs.cs,
- (unsigned long long) regs.rip,
- (unsigned long long) vmcb->exitinfo1,
- (unsigned long long) vmcb->exitinfo2,
- (unsigned long long) vmcb->exitintinfo.bytes,
- (unsigned long long) shadow_gva_to_gpa(current, vmcb->exitinfo2));
+ printk("I%08ld,ExC=%s(%d),IP=%x:%"PRIx64","
+ "I1=%"PRIx64",I2=%"PRIx64",INT=%"PRIx64", "
+ "gpa=%"PRIx64"\n", intercepts_counter,
+ exit_reasons[exit_reason], exit_reason, regs->cs,
+ (u64)regs->rip,
+ (u64)vmcb->exitinfo1,
+ (u64)vmcb->exitinfo2,
+ (u64)vmcb->exitintinfo.bytes,
+ (u64)shadow_gva_to_gpa(current, vmcb->exitinfo2));
}
else
{
- printk("I%08ld,ExC=%s(%d),IP=%x:%llx,"
- "I1=%llx,I2=%llx,INT=%llx\n",
+ printk("I%08ld,ExC=%s(%d),IP=%x:%"PRIx64","
+ "I1=%"PRIx64",I2=%"PRIx64",INT=%"PRIx64"\n",
intercepts_counter,
- exit_reasons[exit_reason], exit_reason, regs.cs,
- (unsigned long long) regs.rip,
- (unsigned long long) vmcb->exitinfo1,
- (unsigned long long) vmcb->exitinfo2,
- (unsigned long long) vmcb->exitintinfo.bytes );
+ exit_reasons[exit_reason], exit_reason, regs->cs,
+ (u64)regs->rip,
+ (u64)vmcb->exitinfo1,
+ (u64)vmcb->exitinfo2,
+ (u64)vmcb->exitintinfo.bytes );
}
}
else if ( svm_dbg_on
@@ -2630,24 +2580,24 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
if (exit_reasons[exit_reason])
{
- printk("I%08ld,ExC=%s(%d),IP=%x:%llx,"
- "I1=%llx,I2=%llx,INT=%llx\n",
+ printk("I%08ld,ExC=%s(%d),IP=%x:%"PRIx64","
+ "I1=%"PRIx64",I2=%"PRIx64",INT=%"PRIx64"\n",
intercepts_counter,
- exit_reasons[exit_reason], exit_reason, regs.cs,
- (unsigned long long) regs.rip,
- (unsigned long long) vmcb->exitinfo1,
- (unsigned long long) vmcb->exitinfo2,
- (unsigned long long) vmcb->exitintinfo.bytes);
+ exit_reasons[exit_reason], exit_reason, regs->cs,
+ (u64)regs->rip,
+ (u64)vmcb->exitinfo1,
+ (u64)vmcb->exitinfo2,
+ (u64)vmcb->exitintinfo.bytes);
}
else
{
- printk("I%08ld,ExC=%d(0x%x),IP=%x:%llx,"
- "I1=%llx,I2=%llx,INT=%llx\n",
- intercepts_counter, exit_reason, exit_reason, regs.cs,
- (unsigned long long) regs.rip,
- (unsigned long long) vmcb->exitinfo1,
- (unsigned long long) vmcb->exitinfo2,
- (unsigned long long) vmcb->exitintinfo.bytes);
+ printk("I%08ld,ExC=%d(0x%x),IP=%x:%"PRIx64","
+ "I1=%"PRIx64",I2=%"PRIx64",INT=%"PRIx64"\n",
+ intercepts_counter, exit_reason, exit_reason, regs->cs,
+ (u64)regs->rip,
+ (u64)vmcb->exitinfo1,
+ (u64)vmcb->exitinfo2,
+ (u64)vmcb->exitintinfo.bytes);
}
}
@@ -2672,14 +2622,14 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
if (do_debug)
{
printk("%s:+ guest_table = 0x%08x, monitor_table = 0x%08x, "
- "shadow_table = 0x%08x\n",
+ "hw_cr3 = 0x%16lx\n",
__func__,
(int) v->arch.guest_table.pfn,
(int) v->arch.monitor_table.pfn,
- (int) v->arch.shadow_table.pfn);
+ (long unsigned int) v->arch.hvm_vcpu.hw_cr3);
svm_dump_vmcb(__func__, vmcb);
- svm_dump_regs(__func__, &regs);
+ svm_dump_regs(__func__, regs);
svm_dump_inst(svm_rip2pointer(vmcb));
}
@@ -2709,18 +2659,17 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
case VMEXIT_EXCEPTION_DB:
{
#ifdef XEN_DEBUGGER
- svm_debug_save_cpu_user_regs(&regs);
- pdb_handle_exception(1, &regs, 1);
- svm_debug_restore_cpu_user_regs(&regs);
+ svm_debug_save_cpu_user_regs(regs);
+ pdb_handle_exception(1, regs, 1);
+ svm_debug_restore_cpu_user_regs(regs);
#else
- svm_store_cpu_user_regs(&regs, v);
+ svm_store_cpu_user_regs(regs, v);
domain_pause_for_debugger();
#endif
}
break;
case VMEXIT_NMI:
- do_nmi(&regs, 0);
break;
case VMEXIT_SMI:
@@ -2740,9 +2689,9 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
case VMEXIT_EXCEPTION_BP:
#ifdef XEN_DEBUGGER
- svm_debug_save_cpu_user_regs(&regs);
- pdb_handle_exception(3, &regs, 1);
- svm_debug_restore_cpu_user_regs(&regs);
+ svm_debug_save_cpu_user_regs(regs);
+ pdb_handle_exception(3, regs, 1);
+ svm_debug_restore_cpu_user_regs(regs);
#else
if ( test_bit(_DOMF_debugging, &v->domain->domain_flags) )
domain_pause_for_debugger();
@@ -2757,29 +2706,29 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
case VMEXIT_EXCEPTION_GP:
/* This should probably not be trapped in the future */
- regs.error_code = vmcb->exitinfo1;
- svm_do_general_protection_fault(v, &regs);
+ regs->error_code = vmcb->exitinfo1;
+ svm_do_general_protection_fault(v, regs);
break;
case VMEXIT_EXCEPTION_PF:
{
unsigned long va;
va = vmcb->exitinfo2;
- regs.error_code = vmcb->exitinfo1;
+ regs->error_code = vmcb->exitinfo1;
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx",
- (unsigned long)regs.eax, (unsigned long)regs.ebx,
- (unsigned long)regs.ecx, (unsigned long)regs.edx,
- (unsigned long)regs.esi, (unsigned long)regs.edi);
+ (unsigned long)regs->eax, (unsigned long)regs->ebx,
+ (unsigned long)regs->ecx, (unsigned long)regs->edx,
+ (unsigned long)regs->esi, (unsigned long)regs->edi);
- if (!(error = svm_do_page_fault(va, &regs)))
+ if (!(error = svm_do_page_fault(va, regs)))
{
/* Inject #PG using Interruption-Information Fields */
- svm_inject_exception(v, TRAP_page_fault, 1, regs.error_code);
+ svm_inject_exception(v, TRAP_page_fault, 1, regs->error_code);
v->arch.hvm_svm.cpu_cr2 = va;
vmcb->cr2 = va;
- TRACE_3D(TRC_VMX_INT, v->domain->domain_id,
+ TRACE_3D(TRC_VMX_INTR, v->domain->domain_id,
VMEXIT_EXCEPTION_PF, va);
}
break;
@@ -2788,11 +2737,16 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
case VMEXIT_EXCEPTION_DF:
/* Debug info to hopefully help debug WHY the guest double-faulted. */
svm_dump_vmcb(__func__, vmcb);
- svm_dump_regs(__func__, &regs);
+ svm_dump_regs(__func__, regs);
svm_dump_inst(svm_rip2pointer(vmcb));
svm_inject_exception(v, TRAP_double_fault, 1, 0);
break;
+ case VMEXIT_VINTR:
+ vmcb->vintr.fields.irq = 0;
+ vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR;
+ break;
+
case VMEXIT_INTR:
break;
@@ -2805,11 +2759,10 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
break;
case VMEXIT_TASK_SWITCH:
- __hvm_bug(&regs);
- break;
+ goto exit_and_crash;
case VMEXIT_CPUID:
- svm_vmexit_do_cpuid(vmcb, regs.eax, &regs);
+ svm_vmexit_do_cpuid(vmcb, regs->eax, regs);
break;
case VMEXIT_HLT:
@@ -2817,60 +2770,60 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
break;
case VMEXIT_INVLPG:
- svm_handle_invlpg(0, &regs);
+ svm_handle_invlpg(0, regs);
break;
case VMEXIT_INVLPGA:
- svm_handle_invlpg(1, &regs);
+ svm_handle_invlpg(1, regs);
break;
case VMEXIT_VMMCALL:
- svm_do_vmmcall(v, &regs);
+ svm_do_vmmcall(v, regs);
break;
case VMEXIT_CR0_READ:
- svm_cr_access(v, 0, TYPE_MOV_FROM_CR, &regs);
+ svm_cr_access(v, 0, TYPE_MOV_FROM_CR, regs);
break;
case VMEXIT_CR2_READ:
- svm_cr_access(v, 2, TYPE_MOV_FROM_CR, &regs);
+ svm_cr_access(v, 2, TYPE_MOV_FROM_CR, regs);
break;
case VMEXIT_CR3_READ:
- svm_cr_access(v, 3, TYPE_MOV_FROM_CR, &regs);
+ svm_cr_access(v, 3, TYPE_MOV_FROM_CR, regs);
break;
case VMEXIT_CR4_READ:
- svm_cr_access(v, 4, TYPE_MOV_FROM_CR, &regs);
+ svm_cr_access(v, 4, TYPE_MOV_FROM_CR, regs);
break;
case VMEXIT_CR8_READ:
- svm_cr_access(v, 8, TYPE_MOV_FROM_CR, &regs);
+ svm_cr_access(v, 8, TYPE_MOV_FROM_CR, regs);
break;
case VMEXIT_CR0_WRITE:
- svm_cr_access(v, 0, TYPE_MOV_TO_CR, &regs);
+ svm_cr_access(v, 0, TYPE_MOV_TO_CR, regs);
break;
case VMEXIT_CR2_WRITE:
- svm_cr_access(v, 2, TYPE_MOV_TO_CR, &regs);
+ svm_cr_access(v, 2, TYPE_MOV_TO_CR, regs);
break;
case VMEXIT_CR3_WRITE:
- svm_cr_access(v, 3, TYPE_MOV_TO_CR, &regs);
+ svm_cr_access(v, 3, TYPE_MOV_TO_CR, regs);
local_flush_tlb();
break;
case VMEXIT_CR4_WRITE:
- svm_cr_access(v, 4, TYPE_MOV_TO_CR, &regs);
+ svm_cr_access(v, 4, TYPE_MOV_TO_CR, regs);
break;
case VMEXIT_CR8_WRITE:
- svm_cr_access(v, 8, TYPE_MOV_TO_CR, &regs);
+ svm_cr_access(v, 8, TYPE_MOV_TO_CR, regs);
break;
case VMEXIT_DR0_WRITE ... VMEXIT_DR7_WRITE:
- svm_dr_access(v, &regs);
+ svm_dr_access(v, regs);
break;
case VMEXIT_IOIO:
@@ -2878,20 +2831,20 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
break;
case VMEXIT_MSR:
- svm_do_msr_access(v, &regs);
+ svm_do_msr_access(v, regs);
break;
case VMEXIT_SHUTDOWN:
- printk("Guest shutdown exit\n");
- domain_crash_synchronous();
- break;
+ gdprintk(XENLOG_ERR, "Guest shutdown exit\n");
+ goto exit_and_crash;
default:
- printk("unexpected VMEXIT: exit reason = 0x%x, exitinfo1 = %llx, "
- "exitinfo2 = %llx\n", exit_reason,
- (unsigned long long)vmcb->exitinfo1,
- (unsigned long long)vmcb->exitinfo2);
- __hvm_bug(&regs); /* should not happen */
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "unexpected VMEXIT: exit reason = 0x%x, "
+ "exitinfo1 = %"PRIx64", exitinfo2 = %"PRIx64"\n",
+ exit_reason,
+ (u64)vmcb->exitinfo1, (u64)vmcb->exitinfo2);
+ domain_crash(v->domain);
break;
}
@@ -2899,21 +2852,19 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs regs)
if (do_debug)
{
printk("%s: Done switch on vmexit_code\n", __func__);
- svm_dump_regs(__func__, &regs);
+ svm_dump_regs(__func__, regs);
}
if (do_debug)
{
printk("vmexit_handler():- guest_table = 0x%08x, "
- "monitor_table = 0x%08x, shadow_table = 0x%08x\n",
+ "monitor_table = 0x%08x, hw_cr3 = 0x%16x\n",
(int)v->arch.guest_table.pfn,
(int)v->arch.monitor_table.pfn,
- (int)v->arch.shadow_table.pfn);
+ (int)v->arch.hvm_vcpu.hw_cr3);
printk("svm_vmexit_handler: Returning\n");
}
#endif
-
- return;
}
asmlinkage void svm_load_cr2(void)
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index b3e3cd13c9..f00372440e 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -38,73 +38,64 @@
#include <xen/keyhandler.h>
extern int svm_dbg_on;
-extern int asidpool_assign_next( struct vmcb_struct *vmcb, int retire_current,
- int oldcore, int newcore);
+extern int asidpool_assign_next(
+ struct vmcb_struct *vmcb, int retire_current, int oldcore, int newcore);
#define GUEST_SEGMENT_LIMIT 0xffffffff
#define IOPM_SIZE (12 * 1024)
#define MSRPM_SIZE (8 * 1024)
-/* VMCBs and HSAs are architecturally defined to be a 4K page each */
-#define VMCB_ORDER 0
-#define HSA_ORDER 0
-
-
struct vmcb_struct *alloc_vmcb(void)
{
- struct vmcb_struct *vmcb = alloc_xenheap_pages(VMCB_ORDER);
+ struct vmcb_struct *vmcb;
- if (!vmcb) {
- printk("Warning: failed to allocate vmcb.\n");
+ vmcb = alloc_xenheap_page();
+ if ( vmcb == NULL )
+ {
+ printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
return NULL;
}
- memset(vmcb, 0, (PAGE_SIZE << VMCB_ORDER));
+ memset(vmcb, 0, PAGE_SIZE);
return vmcb;
}
-
void free_vmcb(struct vmcb_struct *vmcb)
{
- ASSERT(vmcb);
- free_xenheap_pages(vmcb, VMCB_ORDER);
+ free_xenheap_page(vmcb);
}
-
struct host_save_area *alloc_host_save_area(void)
{
- struct host_save_area *hsa = alloc_xenheap_pages(HSA_ORDER);
+ struct host_save_area *hsa;
- if (!hsa) {
- printk("Warning: failed to allocate vmcb.\n");
+ hsa = alloc_xenheap_page();
+ if ( hsa == NULL )
+ {
+ printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
return NULL;
}
- memset(hsa, 0, (PAGE_SIZE << HSA_ORDER));
+ memset(hsa, 0, PAGE_SIZE);
return hsa;
}
-
void free_host_save_area(struct host_save_area *hsa)
{
- ASSERT(hsa);
- free_xenheap_pages(hsa, HSA_ORDER);
+ free_xenheap_page(hsa);
}
-
-/* Set up intercepts to exit the guest into the hypervisor when we want it. */
-static int construct_vmcb_controls(struct arch_svm_struct *arch_svm)
+static int construct_vmcb(struct vcpu *v)
{
- struct vmcb_struct *vmcb;
- u32 *iopm;
- u32 *msrpm;
-
- vmcb = arch_svm->vmcb;
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
+ struct vmcb_struct *vmcb = arch_svm->vmcb;
+ segment_attributes_t attrib;
- ASSERT(vmcb);
+ /* Always flush the TLB on VMRUN. */
+ vmcb->tlb_control = 1;
- /* mask off all general 1 intercepts except those listed here */
+ /* SVM intercepts. */
vmcb->general1_intercepts =
GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI |
GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT |
@@ -112,75 +103,46 @@ static int construct_vmcb_controls(struct arch_svm_struct *arch_svm)
GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG |
GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT |
GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT;
-
- /* turn on the general 2 intercepts */
vmcb->general2_intercepts =
GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL |
GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE |
GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI |
GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
- /* read or write all debug registers 0 - 15 */
+ /* Intercept all debug-register writes. */
vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
- /* RD/WR all control registers 0 - 15, but not read CR2 */
+ /* Intercept all control-register accesses, except to CR2. */
vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
- /* The following is for I/O and MSR permision map */
- iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
- if (iopm)
+ /* I/O and MSR permission bitmaps. */
+ arch_svm->iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
+ arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
+ if ( (arch_svm->iopm == NULL) || (arch_svm->msrpm == NULL) )
{
- memset(iopm, 0xff, IOPM_SIZE);
- clear_bit(PC_DEBUG_PORT, iopm);
+ free_xenheap_pages(arch_svm->iopm, get_order_from_bytes(IOPM_SIZE));
+ free_xenheap_pages(arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
+ return -ENOMEM;
}
- msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
- if (msrpm)
- memset(msrpm, 0xff, MSRPM_SIZE);
+ memset(arch_svm->iopm, 0xff, IOPM_SIZE);
+ clear_bit(PC_DEBUG_PORT, arch_svm->iopm);
+ memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
+ vmcb->iopm_base_pa = (u64)virt_to_maddr(arch_svm->iopm);
+ vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
- arch_svm->iopm = iopm;
- arch_svm->msrpm = msrpm;
-
- if (! iopm || ! msrpm)
- return 1;
-
- vmcb->iopm_base_pa = (u64) virt_to_maddr(iopm);
- vmcb->msrpm_base_pa = (u64) virt_to_maddr(msrpm);
-
- return 0;
-}
-
-
-/*
- * Initially set the same environement as host.
- */
-static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm,
- struct cpu_user_regs *regs )
-{
- int error = 0;
- unsigned long crn;
- segment_attributes_t attrib;
- unsigned long dr7;
- unsigned long eflags;
- unsigned long shadow_cr;
- struct vmcb_struct *vmcb = arch_svm->vmcb;
-
- /* Allows IRQs to be shares */
+ /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
vmcb->vintr.fields.intr_masking = 1;
- /* Set up event injection entry in VMCB. Just clear it. */
+ /* Initialise event injection to no-op. */
vmcb->eventinj.bytes = 0;
- /* TSC */
+ /* TSC. */
vmcb->tsc_offset = 0;
- vmcb->cs.sel = regs->cs;
- vmcb->es.sel = regs->es;
- vmcb->ss.sel = regs->ss;
- vmcb->ds.sel = regs->ds;
- vmcb->fs.sel = regs->fs;
- vmcb->gs.sel = regs->gs;
-
- /* Guest segment Limits. 64K for real mode*/
+ /* Guest EFER: *must* contain SVME or VMRUN will fail. */
+ vmcb->efer = EFER_SVME;
+
+ /* Guest segment limits. */
vmcb->cs.limit = GUEST_SEGMENT_LIMIT;
vmcb->es.limit = GUEST_SEGMENT_LIMIT;
vmcb->ss.limit = GUEST_SEGMENT_LIMIT;
@@ -188,7 +150,7 @@ static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm,
vmcb->fs.limit = GUEST_SEGMENT_LIMIT;
vmcb->gs.limit = GUEST_SEGMENT_LIMIT;
- /* Base address for segments */
+ /* Guest segment bases. */
vmcb->cs.base = 0;
vmcb->es.base = 0;
vmcb->ss.base = 0;
@@ -196,269 +158,179 @@ static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm,
vmcb->fs.base = 0;
vmcb->gs.base = 0;
- /* Guest Interrupt descriptor table */
- vmcb->idtr.base = 0;
- vmcb->idtr.limit = 0;
-
- /* Set up segment attributes */
+ /* Guest segment AR bytes. */
attrib.bytes = 0;
attrib.fields.type = 0x3; /* type = 3 */
- attrib.fields.s = 1; /* code or data, i.e. not system */
- attrib.fields.dpl = 0; /* DPL = 0 */
- attrib.fields.p = 1; /* segment present */
- attrib.fields.db = 1; /* 32-bit */
- attrib.fields.g = 1; /* 4K pages in limit */
-
- /* Data selectors */
+ attrib.fields.s = 1; /* code or data, i.e. not system */
+ attrib.fields.dpl = 0; /* DPL = 0 */
+ attrib.fields.p = 1; /* segment present */
+ attrib.fields.db = 1; /* 32-bit */
+ attrib.fields.g = 1; /* 4K pages in limit */
vmcb->es.attributes = attrib;
vmcb->ss.attributes = attrib;
vmcb->ds.attributes = attrib;
vmcb->fs.attributes = attrib;
vmcb->gs.attributes = attrib;
-
- /* Code selector */
- attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
+ attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
vmcb->cs.attributes = attrib;
- /* Guest Global descriptor table */
+ /* Guest IDT. */
+ vmcb->idtr.base = 0;
+ vmcb->idtr.limit = 0;
+
+ /* Guest GDT. */
vmcb->gdtr.base = 0;
vmcb->gdtr.limit = 0;
- /* Guest Local Descriptor Table */
- attrib.fields.s = 0; /* not code or data segement */
- attrib.fields.type = 0x2; /* LDT */
- attrib.fields.db = 0; /* 16-bit */
- attrib.fields.g = 0;
- vmcb->ldtr.attributes = attrib;
+ /* Guest LDT. */
+ vmcb->ldtr.sel = 0;
+ vmcb->ldtr.base = 0;
+ vmcb->ldtr.limit = 0;
+ vmcb->ldtr.attributes.bytes = 0;
+ /* Guest TSS. */
attrib.fields.type = 0xb; /* 32-bit TSS (busy) */
vmcb->tr.attributes = attrib;
vmcb->tr.base = 0;
vmcb->tr.limit = 0xff;
- __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) :);
- vmcb->cr0 = crn;
-
- /* Initally PG, PE are not set*/
- shadow_cr = vmcb->cr0;
- shadow_cr &= ~X86_CR0_PG;
- arch_svm->cpu_shadow_cr0 = shadow_cr;
-
- /* CR3 is set in svm_final_setup_guest */
+ /* Guest CR0. */
+ vmcb->cr0 = read_cr0();
+ arch_svm->cpu_shadow_cr0 = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS);
+ vmcb->cr0 |= X86_CR0_WP;
- __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) :);
- crn &= ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
- arch_svm->cpu_shadow_cr4 = crn;
- vmcb->cr4 = crn | SVM_CR4_HOST_MASK;
+ /* Guest CR4. */
+ arch_svm->cpu_shadow_cr4 =
+ read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
+ vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK;
- vmcb->rsp = 0;
- vmcb->rip = regs->eip;
-
- eflags = regs->eflags & ~HVM_EFLAGS_RESERVED_0; /* clear 0s */
- eflags |= HVM_EFLAGS_RESERVED_1; /* set 1s */
-
- vmcb->rflags = eflags;
+ shadow_update_paging_modes(v);
+ vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
- __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
- vmcb->dr7 = dr7;
+ arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
- return error;
+ return 0;
}
-
-/*
- * destroy the vmcb.
- */
-
-void destroy_vmcb(struct arch_svm_struct *arch_svm)
+int svm_create_vmcb(struct vcpu *v)
{
- if(arch_svm->vmcb != NULL)
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
+ int rc;
+
+ if ( (arch_svm->vmcb = alloc_vmcb()) == NULL )
{
- asidpool_retire(arch_svm->vmcb, arch_svm->asid_core);
- free_vmcb(arch_svm->vmcb);
- }
- if(arch_svm->iopm != NULL) {
- free_xenheap_pages(
- arch_svm->iopm, get_order_from_bytes(IOPM_SIZE));
- arch_svm->iopm = NULL;
+ printk("Failed to create a new VMCB\n");
+ return -ENOMEM;
}
- if(arch_svm->msrpm != NULL) {
- free_xenheap_pages(
- arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
- arch_svm->msrpm = NULL;
+
+ if ( (rc = construct_vmcb(v)) != 0 )
+ {
+ free_vmcb(arch_svm->vmcb);
+ arch_svm->vmcb = NULL;
+ return rc;
}
- arch_svm->vmcb = NULL;
-}
+ arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb);
-/*
- * construct the vmcb.
- */
+ return 0;
+}
-int construct_vmcb(struct arch_svm_struct *arch_svm,
- struct cpu_user_regs *regs)
+void svm_destroy_vmcb(struct vcpu *v)
{
- int error;
- long rc=0;
-
- memset(arch_svm, 0, sizeof(struct arch_svm_struct));
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
- if (!(arch_svm->vmcb = alloc_vmcb())) {
- printk("Failed to create a new VMCB\n");
- rc = -ENOMEM;
- goto err_out;
+ if ( arch_svm->vmcb != NULL )
+ {
+ asidpool_retire(arch_svm->vmcb, arch_svm->asid_core);
+ free_vmcb(arch_svm->vmcb);
}
- arch_svm->vmcb_pa = (u64) virt_to_maddr(arch_svm->vmcb);
-
- if ((error = construct_vmcb_controls(arch_svm)))
+ if ( arch_svm->iopm != NULL )
{
- printk("construct_vmcb: construct_vmcb_controls failed\n");
- rc = -EINVAL;
- goto err_out;
+ free_xenheap_pages(
+ arch_svm->iopm, get_order_from_bytes(IOPM_SIZE));
+ arch_svm->iopm = NULL;
}
- /* guest selectors */
- if ((error = construct_init_vmcb_guest(arch_svm, regs)))
+ if ( arch_svm->msrpm != NULL )
{
- printk("construct_vmcb: construct_vmcb_guest failed\n");
- rc = -EINVAL;
- goto err_out;
+ free_xenheap_pages(
+ arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
+ arch_svm->msrpm = NULL;
}
- arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
- if (regs->eflags & EF_TF)
- arch_svm->vmcb->exception_intercepts |= EXCEPTION_BITMAP_DB;
- else
- arch_svm->vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_DB;
-
- return 0;
-
-err_out:
- destroy_vmcb(arch_svm);
- return rc;
+ arch_svm->vmcb = NULL;
}
-
void svm_do_launch(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
int core = smp_processor_id();
- ASSERT(vmcb);
- /* Update CR3, GDT, LDT, TR */
hvm_stts(v);
/* current core is the one we intend to perform the VMRUN on */
v->arch.hvm_svm.launch_core = v->arch.hvm_svm.asid_core = core;
clear_bit(ARCH_SVM_VMCB_ASSIGN_ASID, &v->arch.hvm_svm.flags);
- if ( !asidpool_assign_next( vmcb, 0, core, core ))
+ if ( !asidpool_assign_next(vmcb, 0, core, core) )
BUG();
- if (v->vcpu_id == 0)
- hvm_setup_platform(v->domain);
-
- if (hvm_apic_support(v->domain))
- vlapic_init(v);
- init_timer(&v->arch.hvm_vcpu.hlt_timer, hlt_timer_fn, v, v->processor);
-
- vmcb->ldtr.sel = 0;
- vmcb->ldtr.base = 0;
- vmcb->ldtr.limit = 0;
- vmcb->ldtr.attributes.bytes = 0;
-
- vmcb->efer = EFER_SVME; /* Make sure VMRUN won't return with -1 */
-
- if (svm_dbg_on)
- {
- unsigned long pt;
- pt = pagetable_get_paddr(v->arch.shadow_table);
- printk("%s: shadow_table = %lx\n", __func__, pt);
- pt = pagetable_get_paddr(v->arch.guest_table);
- printk("%s: guest_table = %lx\n", __func__, pt);
- pt = pagetable_get_paddr(v->domain->arch.phys_table);
- printk("%s: phys_table = %lx\n", __func__, pt);
- }
-
- /* Set cr3 from hw_cr3 even when guest-visible paging is not enabled */
- vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
-
- if (svm_dbg_on)
- {
- printk("%s: cr3 = %lx ", __func__, (unsigned long)vmcb->cr3);
- printk("init_guest_table: guest_table = 0x%08x, monitor_table = 0x%08x,"
- " shadow_table = 0x%08x\n", (int)v->arch.guest_table.pfn,
- (int)v->arch.monitor_table.pfn, (int)v->arch.shadow_table.pfn);
- }
-
v->arch.schedule_tail = arch_svm_do_resume;
-
- v->arch.hvm_svm.saved_irq_vector = -1;
-
- hvm_set_guest_time(v, 0);
-
- if (svm_dbg_on)
- svm_dump_vmcb(__func__, vmcb);
-
- vmcb->tlb_control = 1;
}
-
-
static void svm_dump_sel(char *name, segment_selector_t *s)
{
- printf("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
+ printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
name, s->sel, s->attributes.bytes, s->limit,
(unsigned long long)s->base);
}
-
void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb)
{
- printf("Dumping guest's current state at %s...\n", from);
- printf("Size of VMCB = %d, address = %p\n",
+ printk("Dumping guest's current state at %s...\n", from);
+ printk("Size of VMCB = %d, address = %p\n",
(int) sizeof(struct vmcb_struct), vmcb);
- printf("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
+ printk("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
"exception_intercepts = 0x%08x\n",
vmcb->cr_intercepts, vmcb->dr_intercepts,
vmcb->exception_intercepts);
- printf("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
+ printk("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
vmcb->general1_intercepts, vmcb->general2_intercepts);
- printf("iopm_base_pa = %016llx msrpm_base_pa = 0x%016llx tsc_offset = "
+ printk("iopm_base_pa = %016llx msrpm_base_pa = 0x%016llx tsc_offset = "
"0x%016llx\n",
(unsigned long long) vmcb->iopm_base_pa,
(unsigned long long) vmcb->msrpm_base_pa,
(unsigned long long) vmcb->tsc_offset);
- printf("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
+ printk("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
"0x%016llx\n", vmcb->tlb_control,
(unsigned long long) vmcb->vintr.bytes,
(unsigned long long) vmcb->interrupt_shadow);
- printf("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
+ printk("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
(unsigned long long) vmcb->exitcode,
(unsigned long long) vmcb->exitintinfo.bytes);
- printf("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
+ printk("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
(unsigned long long) vmcb->exitinfo1,
(unsigned long long) vmcb->exitinfo2);
- printf("np_enable = 0x%016llx guest_asid = 0x%03x\n",
+ printk("np_enable = 0x%016llx guest_asid = 0x%03x\n",
(unsigned long long) vmcb->np_enable, vmcb->guest_asid);
- printf("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
+ printk("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
vmcb->cpl, (unsigned long long) vmcb->efer,
(unsigned long long) vmcb->star, (unsigned long long) vmcb->lstar);
- printf("CR0 = 0x%016llx CR2 = 0x%016llx\n",
+ printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
(unsigned long long) vmcb->cr0, (unsigned long long) vmcb->cr2);
- printf("CR3 = 0x%016llx CR4 = 0x%016llx\n",
+ printk("CR3 = 0x%016llx CR4 = 0x%016llx\n",
(unsigned long long) vmcb->cr3, (unsigned long long) vmcb->cr4);
- printf("RSP = 0x%016llx RIP = 0x%016llx\n",
+ printk("RSP = 0x%016llx RIP = 0x%016llx\n",
(unsigned long long) vmcb->rsp, (unsigned long long) vmcb->rip);
- printf("RAX = 0x%016llx RFLAGS=0x%016llx\n",
+ printk("RAX = 0x%016llx RFLAGS=0x%016llx\n",
(unsigned long long) vmcb->rax, (unsigned long long) vmcb->rflags);
- printf("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
+ printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
(unsigned long long) vmcb->dr6, (unsigned long long) vmcb->dr7);
- printf("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
+ printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
(unsigned long long) vmcb->cstar,
(unsigned long long) vmcb->sfmask);
- printf("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
+ printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
(unsigned long long) vmcb->kerngsbase,
(unsigned long long) vmcb->g_pat);
@@ -481,20 +353,14 @@ static void vmcb_dump(unsigned char ch)
struct vcpu *v;
printk("*********** VMCB Areas **************\n");
- for_each_domain(d) {
+ for_each_domain ( d )
+ {
+ if ( !is_hvm_domain(d) )
+ continue;
printk("\n>>> Domain %d <<<\n", d->domain_id);
- for_each_vcpu(d, v) {
-
- /*
- * Presumably, if a domain is not an HVM guest,
- * the very first CPU will not pass this test
- */
- if (!hvm_guest(v)) {
- printk("\t\tNot HVM guest\n");
- break;
- }
+ for_each_vcpu ( d, v )
+ {
printk("\tVCPU %d\n", v->vcpu_id);
-
svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
}
}
diff --git a/xen/arch/x86/hvm/svm/x86_32/exits.S b/xen/arch/x86/hvm/svm/x86_32/exits.S
index 4ad89d032d..2cd913e16b 100644
--- a/xen/arch/x86/hvm/svm/x86_32/exits.S
+++ b/xen/arch/x86/hvm/svm/x86_32/exits.S
@@ -34,7 +34,7 @@
* At VMExit time the processor saves the guest selectors, esp, eip,
* and eflags. Therefore we don't save them, but simply decrement
* the kernel stack pointer to make it consistent with the stack frame
- * at usual interruption time. The eflags of the host is not saved by VMX,
+ * at usual interruption time. The eflags of the host is not saved by AMD-V,
* and we set it to the fixed value.
*
* We also need the room, especially because orig_eax field is used
@@ -89,8 +89,8 @@
#define CLGI .byte 0x0F,0x01,0xDD
ENTRY(svm_asm_do_launch)
- sti
CLGI
+ sti
GET_CURRENT(%ebx)
movl VCPU_svm_vmcb(%ebx), %ecx
movl 24(%esp), %eax
@@ -126,7 +126,12 @@ ENTRY(svm_asm_do_launch)
HVM_SAVE_ALL_NOSEGREGS
STGI
+.globl svm_stgi_label;
+svm_stgi_label:
+ movl %esp,%eax
+ push %eax
call svm_vmexit_handler
+ addl $4,%esp
jmp svm_asm_do_resume
ALIGN
@@ -134,9 +139,6 @@ ENTRY(svm_asm_do_launch)
ENTRY(svm_asm_do_resume)
svm_test_all_events:
GET_CURRENT(%ebx)
- pushl %ebx
- call hvm_do_resume
- addl $4, %esp
/*test_all_events:*/
xorl %ecx,%ecx
notl %ecx
@@ -150,9 +152,8 @@ svm_restore_all_guest:
call svm_intr_assist
call svm_asid
call svm_load_cr2
- sti
/*
- * Check if we are going back to SVM-based VM
+ * Check if we are going back to AMD-V based VM
* By this time, all the setups in the VMCB must be complete.
*/
jmp svm_asm_do_launch
diff --git a/xen/arch/x86/hvm/svm/x86_64/exits.S b/xen/arch/x86/hvm/svm/x86_64/exits.S
index 248a58f131..0c9aa641a3 100644
--- a/xen/arch/x86/hvm/svm/x86_64/exits.S
+++ b/xen/arch/x86/hvm/svm/x86_64/exits.S
@@ -1,5 +1,5 @@
/*
- * exits.S: SVM architecture-specific exit handling.
+ * exits.S: AMD-V architecture-specific exit handling.
* Copyright (c) 2004, Intel Corporation.
* Copyright (c) 2005, AMD Corporation.
*
@@ -34,7 +34,7 @@
* At VMExit time the processor saves the guest selectors, rsp, rip,
* and rflags. Therefore we don't save them, but simply decrement
* the kernel stack pointer to make it consistent with the stack frame
- * at usual interruption time. The rflags of the host is not saved by VMX,
+ * at usual interruption time. The rflags of the host is not saved by AMD-V,
* and we set it to the fixed value.
*
* We also need the room, especially because orig_eax field is used
@@ -99,8 +99,8 @@
#define CLGI .byte 0x0F,0x01,0xDD
ENTRY(svm_asm_do_launch)
- sti
CLGI
+ sti
GET_CURRENT(%rbx)
movq VCPU_svm_vmcb(%rbx), %rcx
movq UREGS_rax(%rsp), %rax
@@ -144,14 +144,15 @@ ENTRY(svm_asm_do_launch)
VMLOAD
STGI
+.globl svm_stgi_label;
+svm_stgi_label:
+ movq %rsp,%rdi
call svm_vmexit_handler
jmp svm_asm_do_resume
ENTRY(svm_asm_do_resume)
svm_test_all_events:
GET_CURRENT(%rbx)
- movq %rbx, %rdi
- call hvm_do_resume
/*test_all_events:*/
cli # tests must not race interrupts
/*test_softirqs:*/
@@ -164,10 +165,9 @@ svm_restore_all_guest:
call svm_intr_assist
call svm_asid
call svm_load_cr2
- sti
/*
- * Check if we are going back to VMX-based VM
- * By this time, all the setups in the VMCS must be complete.
+ * Check if we are going back to AMD-V based VM
+ * By this time, all the setups in the VMCB must be complete.
*/
jmp svm_asm_do_launch
diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c
index 2999bfe4f1..f986d5ca1d 100644
--- a/xen/arch/x86/hvm/vioapic.c
+++ b/xen/arch/x86/hvm/vioapic.c
@@ -1,31 +1,29 @@
/*
-* Copyright (C) 2001 MandrakeSoft S.A.
-*
-* MandrakeSoft S.A.
-* 43, rue d'Aboukir
-* 75002 Paris - France
-* http://www.linux-mandrake.com/
-* http://www.mandrakesoft.com/
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation; either
-* version 2 of the License, or (at your option) any later version.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
-* Yunhong Jiang <yunhong.jiang@intel.com>
-* Ported to xen by using virtual IRQ line.
-*/
+ * Copyright (C) 2001 MandrakeSoft S.A.
+ *
+ * MandrakeSoft S.A.
+ * 43, rue d'Aboukir
+ * 75002 Paris - France
+ * http://www.linux-mandrake.com/
+ * http://www.mandrakesoft.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Yunhong Jiang <yunhong.jiang@intel.com>
+ * Ported to xen by using virtual IRQ line.
+ */
#include <xen/config.h>
#include <xen/types.h>
@@ -37,8 +35,10 @@
#include <public/hvm/ioreq.h>
#include <asm/hvm/io.h>
#include <asm/hvm/vpic.h>
+#include <asm/hvm/vlapic.h>
#include <asm/hvm/support.h>
#include <asm/current.h>
+#include <asm/event.h>
/* HACK: Route IRQ0 only to VCPU0 to prevent time jumps. */
#define IRQ0_SPECIAL_ROUTING 1
@@ -47,189 +47,182 @@
#define opt_hvm_debug_level opt_vmx_debug_level
#endif
-static void ioapic_enable(hvm_vioapic_t *s, uint8_t enable)
-{
- if (enable)
- s->flags |= IOAPIC_ENABLE_FLAG;
- else
- s->flags &= ~IOAPIC_ENABLE_FLAG;
-}
+static void vioapic_deliver(struct vioapic *vioapic, int irq);
-#ifdef HVM_DOMAIN_SAVE_RESTORE
-void ioapic_save(QEMUFile* f, void* opaque)
-{
- printk("no implementation for ioapic_save\n");
-}
-
-int ioapic_load(QEMUFile* f, void* opaque, int version_id)
-{
- printk("no implementation for ioapic_load\n");
- return 0;
-}
-#endif
-
-static unsigned long hvm_vioapic_read_indirect(struct hvm_vioapic *s,
- unsigned long addr,
- unsigned long length)
+static unsigned long vioapic_read_indirect(struct vioapic *vioapic,
+ unsigned long addr,
+ unsigned long length)
{
unsigned long result = 0;
- ASSERT(s);
-
- switch (s->ioregsel) {
- case IOAPIC_REG_VERSION:
- result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16)
- | (IOAPIC_VERSION_ID & 0xff));
- break;
-
-#ifndef __ia64__
- case IOAPIC_REG_APIC_ID:
- result = ((s->id & 0xf) << 24);
+ switch ( vioapic->ioregsel )
+ {
+ case VIOAPIC_REG_VERSION:
+ result = ((((VIOAPIC_NUM_PINS-1) & 0xff) << 16)
+ | (VIOAPIC_VERSION_ID & 0xff));
break;
- case IOAPIC_REG_ARB_ID:
- /* XXX how arb_id used on p4? */
- result = ((s->arb_id & 0xf) << 24);
+#if !VIOAPIC_IS_IOSAPIC
+ case VIOAPIC_REG_APIC_ID:
+ case VIOAPIC_REG_ARB_ID:
+ result = ((vioapic->id & 0xf) << 24);
break;
#endif
default:
- {
- uint32_t redir_index = 0;
- uint64_t redir_content = 0;
-
- redir_index = (s->ioregsel - 0x10) >> 1;
-
- if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) {
- redir_content = s->redirtbl[redir_index].value;
+ {
+ uint32_t redir_index = (vioapic->ioregsel - 0x10) >> 1;
+ uint64_t redir_content;
- result = (s->ioregsel & 0x1)?
- (redir_content >> 32) & 0xffffffff :
- redir_content & 0xffffffff;
- } else {
- printk("apic_mem_readl:undefined ioregsel %x\n",
- s->ioregsel);
- domain_crash_synchronous();
- }
+ if ( redir_index >= VIOAPIC_NUM_PINS )
+ {
+ gdprintk(XENLOG_WARNING, "apic_mem_readl:undefined ioregsel %x\n",
+ vioapic->ioregsel);
break;
}
- } /* switch */
+
+ redir_content = vioapic->redirtbl[redir_index].bits;
+ result = (vioapic->ioregsel & 0x1)?
+ (redir_content >> 32) & 0xffffffff :
+ redir_content & 0xffffffff;
+ break;
+ }
+ }
return result;
}
-static unsigned long hvm_vioapic_read(struct vcpu *v,
- unsigned long addr,
- unsigned long length)
+static unsigned long vioapic_read(struct vcpu *v,
+ unsigned long addr,
+ unsigned long length)
{
- struct hvm_vioapic *s = &(v->domain->arch.hvm_domain.vioapic);
- uint32_t result = 0;
+ struct vioapic *vioapic = domain_vioapic(v->domain);
+ uint32_t result;
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "hvm_vioapic_read addr %lx\n", addr);
-
- ASSERT(s);
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "vioapic_read addr %lx\n", addr);
addr &= 0xff;
- switch (addr) {
- case IOAPIC_REG_SELECT:
- result = s->ioregsel;
+ switch ( addr )
+ {
+ case VIOAPIC_REG_SELECT:
+ result = vioapic->ioregsel;
break;
- case IOAPIC_REG_WINDOW:
- result = hvm_vioapic_read_indirect(s, addr, length);
+ case VIOAPIC_REG_WINDOW:
+ result = vioapic_read_indirect(vioapic, addr, length);
break;
default:
- break;
+ result = 0;
+ break;
}
return result;
}
-static void hvm_vioapic_update_imr(struct hvm_vioapic *s, int index)
+static void vioapic_write_redirent(
+ struct vioapic *vioapic, unsigned int idx, int top_word, uint32_t val)
{
- if (s->redirtbl[index].RedirForm.mask)
- set_bit(index, &s->imr);
- else
- clear_bit(index, &s->imr);
+ struct domain *d = vioapic_domain(vioapic);
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ union vioapic_redir_entry *pent, ent;
+
+ spin_lock(&hvm_irq->lock);
+
+ pent = &vioapic->redirtbl[idx];
+ ent = *pent;
+
+ if ( top_word )
+ {
+ /* Contains only the dest_id. */
+ ent.bits = (uint32_t)ent.bits | ((uint64_t)val << 32);
+ }
+ else
+ {
+ /* Remote IRR and Delivery Status are read-only. */
+ ent.bits = ((ent.bits >> 32) << 32) | val;
+ ent.fields.delivery_status = 0;
+ ent.fields.remote_irr = pent->fields.remote_irr;
+ }
+
+ *pent = ent;
+
+ if ( (ent.fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
+ !ent.fields.mask &&
+ !ent.fields.remote_irr &&
+ hvm_irq->gsi_assert_count[idx] )
+ {
+ pent->fields.remote_irr = 1;
+ vioapic_deliver(vioapic, idx);
+ }
+
+ spin_unlock(&hvm_irq->lock);
}
-static void hvm_vioapic_write_indirect(struct hvm_vioapic *s,
- unsigned long addr,
- unsigned long length,
- unsigned long val)
+static void vioapic_write_indirect(
+ struct vioapic *vioapic, unsigned long addr,
+ unsigned long length, unsigned long val)
{
- switch (s->ioregsel) {
- case IOAPIC_REG_VERSION:
- printk("hvm_vioapic_write_indirect: version register read only\n");
+ switch ( vioapic->ioregsel )
+ {
+ case VIOAPIC_REG_VERSION:
+ /* Writes are ignored. */
break;
-#ifndef __ia64__
- case IOAPIC_REG_APIC_ID:
- s->id = (val >> 24) & 0xf;
+#if !VIOAPIC_IS_IOSAPIC
+ case VIOAPIC_REG_APIC_ID:
+ vioapic->id = (val >> 24) & 0xf;
break;
- case IOAPIC_REG_ARB_ID:
- s->arb_id = val;
+ case VIOAPIC_REG_ARB_ID:
break;
#endif
default:
+ {
+ uint32_t redir_index = (vioapic->ioregsel - 0x10) >> 1;
+
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "vioapic_write_indirect "
+ "change redir index %x val %lx\n",
+ redir_index, val);
+
+ if ( redir_index >= VIOAPIC_NUM_PINS )
{
- uint32_t redir_index = 0;
-
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "hvm_vioapic_write_indirect "
- "change redir index %x val %lx\n",
- redir_index, val);
-
- redir_index = (s->ioregsel - 0x10) >> 1;
-
- if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) {
- uint64_t redir_content;
-
- redir_content = s->redirtbl[redir_index].value;
-
- if (s->ioregsel & 0x1)
- redir_content = (((uint64_t)val & 0xffffffff) << 32) |
- (redir_content & 0xffffffff);
- else
- redir_content = ((redir_content >> 32) << 32) |
- (val & 0xffffffff);
- s->redirtbl[redir_index].value = redir_content;
- hvm_vioapic_update_imr(s, redir_index);
- } else {
- printk("hvm_vioapic_write_indirect "
- "error register %x\n", s->ioregsel);
- }
+ gdprintk(XENLOG_WARNING, "vioapic_write_indirect "
+ "error register %x\n", vioapic->ioregsel);
break;
}
- } /* switch */
+
+ vioapic_write_redirent(
+ vioapic, redir_index, vioapic->ioregsel&1, val);
+ break;
+ }
+ }
}
-static void hvm_vioapic_write(struct vcpu *v,
- unsigned long addr,
- unsigned long length,
- unsigned long val)
+static void vioapic_write(struct vcpu *v,
+ unsigned long addr,
+ unsigned long length,
+ unsigned long val)
{
- hvm_vioapic_t *s = &(v->domain->arch.hvm_domain.vioapic);
-
- ASSERT(s);
+ struct vioapic *vioapic = domain_vioapic(v->domain);
addr &= 0xff;
- switch (addr) {
- case IOAPIC_REG_SELECT:
- s->ioregsel = val;
+ switch ( addr )
+ {
+ case VIOAPIC_REG_SELECT:
+ vioapic->ioregsel = val;
break;
- case IOAPIC_REG_WINDOW:
- hvm_vioapic_write_indirect(s, addr, length, val);
+ case VIOAPIC_REG_WINDOW:
+ vioapic_write_indirect(vioapic, addr, length, val);
break;
-#ifdef __ia64__
- case IOAPIC_REG_EOI:
- ioapic_update_EOI(v->domain, val);
+#if VIOAPIC_IS_IOSAPIC
+ case VIOAPIC_REG_EOI:
+ vioapic_update_EOI(v->domain, val);
break;
#endif
@@ -238,210 +231,135 @@ static void hvm_vioapic_write(struct vcpu *v,
}
}
-static int hvm_vioapic_range(struct vcpu *v, unsigned long addr)
+static int vioapic_range(struct vcpu *v, unsigned long addr)
{
- hvm_vioapic_t *s = &(v->domain->arch.hvm_domain.vioapic);
+ struct vioapic *vioapic = domain_vioapic(v->domain);
- if ((s->flags & IOAPIC_ENABLE_FLAG) &&
- (addr >= s->base_address &&
- (addr < s->base_address + IOAPIC_MEM_LENGTH)))
- return 1;
- else
- return 0;
+ return ((addr >= vioapic->base_address &&
+ (addr < vioapic->base_address + VIOAPIC_MEM_LENGTH)));
}
struct hvm_mmio_handler vioapic_mmio_handler = {
- .check_handler = hvm_vioapic_range,
- .read_handler = hvm_vioapic_read,
- .write_handler = hvm_vioapic_write
+ .check_handler = vioapic_range,
+ .read_handler = vioapic_read,
+ .write_handler = vioapic_write
};
-static void hvm_vioapic_reset(hvm_vioapic_t *s)
-{
- int i;
-
- memset(s, 0, sizeof(hvm_vioapic_t));
-
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- s->redirtbl[i].RedirForm.mask = 0x1;
- hvm_vioapic_update_imr(s, i);
- }
-}
-
-static void ioapic_update_config(hvm_vioapic_t *s,
- unsigned long address,
- uint8_t enable)
+static void ioapic_inj_irq(
+ struct vioapic *vioapic,
+ struct vlapic *target,
+ uint8_t vector,
+ uint8_t trig_mode,
+ uint8_t delivery_mode)
{
- ASSERT(s);
-
- ioapic_enable(s, enable);
-
- if (address != s->base_address)
- s->base_address = address;
-}
-
-static int ioapic_inj_irq(hvm_vioapic_t *s,
- struct vlapic * target,
- uint8_t vector,
- uint8_t trig_mode,
- uint8_t delivery_mode)
-{
- int result = 0;
-
- ASSERT(s && target);
-
HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_inj_irq "
- "irq %d trig %d delive mode %d\n",
- vector, trig_mode, delivery_mode);
+ "irq %d trig %d delive mode %d\n",
+ vector, trig_mode, delivery_mode);
- switch (delivery_mode) {
+ switch ( delivery_mode )
+ {
case dest_Fixed:
case dest_LowestPrio:
- if (vlapic_set_irq(target, vector, trig_mode) && (trig_mode == 1))
- printk("<ioapic_inj_irq> level interrupt happen before cleared\n");
- result = 1;
- break;
- default:
- printk("<ioapic_inj_irq> error delivery mode %d\n",
- delivery_mode);
- break;
- }
-
- return result;
-}
-
-#ifndef __ia64__
-static int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest)
-{
- int result = 0;
- uint32_t logical_dest = vlapic_get_reg(s->lapic_info[number], APIC_LDR);
-
- ASSERT(s && s->lapic_info[number]);
-
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_match_logical_addr "
- "number %i dest %x\n",
- number, dest);
-
- switch (vlapic_get_reg(s->lapic_info[number], APIC_DFR))
- {
- case APIC_DFR_FLAT:
- result =
- (dest & GET_APIC_LOGICAL_ID(logical_dest)) != 0;
- break;
- case APIC_DFR_CLUSTER:
- /* Should we support flat cluster mode ?*/
- if ( (GET_APIC_LOGICAL_ID(logical_dest) >> 4
- == ((dest >> 0x4) & 0xf)) &&
- (logical_dest & (dest & 0xf)) )
- result = 1;
+ if ( vlapic_set_irq(target, vector, trig_mode) )
+ vcpu_kick(vlapic_vcpu(target));
break;
default:
- printk("error DFR value for %x local apic\n", number);
+ gdprintk(XENLOG_WARNING, "error delivery mode %d\n", delivery_mode);
break;
}
-
- return result;
}
-#else
-extern int ioapic_match_logical_addr(hvm_vioapic_t *s, int number, uint8_t dest);
-#endif
-static uint32_t ioapic_get_delivery_bitmask(hvm_vioapic_t *s,
- uint16_t dest,
- uint8_t dest_mode,
- uint8_t vector,
- uint8_t delivery_mode)
+static uint32_t ioapic_get_delivery_bitmask(
+ struct vioapic *vioapic, uint16_t dest, uint8_t dest_mode)
{
uint32_t mask = 0;
- int i;
+ struct vcpu *v;
HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask "
- "dest %d dest_mode %d "
- "vector %d del_mode %d, lapic_count %d\n",
- dest, dest_mode, vector, delivery_mode, s->lapic_count);
+ "dest %d dest_mode %d\n", dest, dest_mode);
- ASSERT(s);
-
- if ( dest_mode == 0 )
+ if ( dest_mode == 0 ) /* Physical mode. */
{
- /* Physical mode. */
- for ( i = 0; i < s->lapic_count; i++ )
+ if ( dest == 0xFF ) /* Broadcast. */
{
- if ( VLAPIC_ID(s->lapic_info[i]) == dest )
- {
- mask = 1 << i;
- break;
- }
+ for_each_vcpu ( vioapic_domain(vioapic), v )
+ mask |= 1 << v->vcpu_id;
+ goto out;
}
- /* Broadcast. */
- if ( dest == 0xFF )
+ for_each_vcpu ( vioapic_domain(vioapic), v )
{
- for ( i = 0; i < s->lapic_count; i++ )
- mask |= ( 1 << i );
- }
- }
- else
- {
- /* Logical destination. Call match_logical_addr for each APIC. */
- if ( dest != 0 )
- {
- for ( i = 0; i < s->lapic_count; i++ )
+ if ( VLAPIC_ID(vcpu_vlapic(v)) == dest )
{
- if ( s->lapic_info[i] &&
- ioapic_match_logical_addr(s, i, dest) )
- mask |= (1<<i);
+ mask = 1 << v->vcpu_id;
+ break;
}
}
}
+ else if ( dest != 0 ) /* Logical mode, MDA non-zero. */
+ {
+ for_each_vcpu ( vioapic_domain(vioapic), v )
+ if ( vlapic_match_logical_addr(vcpu_vlapic(v), dest) )
+ mask |= 1 << v->vcpu_id;
+ }
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask "
- "mask %x\n", mask);
-
+ out:
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask mask %x\n",
+ mask);
return mask;
}
-static void ioapic_deliver(hvm_vioapic_t *s, int irqno)
+static void vioapic_deliver(struct vioapic *vioapic, int irq)
{
- uint16_t dest = s->redirtbl[irqno].RedirForm.dest_id;
- uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode;
- uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode;
- uint8_t vector = s->redirtbl[irqno].RedirForm.vector;
- uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod;
+ uint16_t dest = vioapic->redirtbl[irq].fields.dest_id;
+ uint8_t dest_mode = vioapic->redirtbl[irq].fields.dest_mode;
+ uint8_t delivery_mode = vioapic->redirtbl[irq].fields.delivery_mode;
+ uint8_t vector = vioapic->redirtbl[irq].fields.vector;
+ uint8_t trig_mode = vioapic->redirtbl[irq].fields.trig_mode;
uint32_t deliver_bitmask;
+ struct vlapic *target;
+ struct vcpu *v;
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC,
- "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n",
- dest, dest_mode, delivery_mode, vector, trig_mode);
+ ASSERT(spin_is_locked(&vioapic_domain(vioapic)->arch.hvm_domain.irq.lock));
- deliver_bitmask = ioapic_get_delivery_bitmask(
- s, dest, dest_mode, vector, delivery_mode);
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC,
+ "dest=%x dest_mode=%x delivery_mode=%x "
+ "vector=%x trig_mode=%x\n",
+ dest, dest_mode, delivery_mode, vector, trig_mode);
- if (!deliver_bitmask) {
+ deliver_bitmask = ioapic_get_delivery_bitmask(vioapic, dest, dest_mode);
+ if ( !deliver_bitmask )
+ {
HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic deliver "
- "no target on destination\n");
-
+ "no target on destination\n");
return;
}
- switch (delivery_mode) {
+ switch ( delivery_mode )
+ {
case dest_LowestPrio:
{
- struct vlapic* target;
-
#ifdef IRQ0_SPECIAL_ROUTING
- if (irqno == 0)
- target = s->lapic_info[0];
+ /* Force round-robin to pick VCPU 0 */
+ if ( irq == 0 )
+ {
+ v = vioapic_domain(vioapic)->vcpu[0];
+ target = v ? vcpu_vlapic(v) : NULL;
+ }
else
#endif
- target = apic_round_robin(s->domain, dest_mode,
+ target = apic_round_robin(vioapic_domain(vioapic),
vector, deliver_bitmask);
- if (target)
- ioapic_inj_irq(s, target, vector, trig_mode, delivery_mode);
+ if ( target != NULL )
+ {
+ ioapic_inj_irq(vioapic, target, vector, trig_mode, delivery_mode);
+ }
else
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC,
- "null round robin mask %x vector %x delivery_mode %x\n",
- deliver_bitmask, vector, dest_LowestPrio);
+ {
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "null round robin: "
+ "mask=%x vector=%x delivery_mode=%x\n",
+ deliver_bitmask, vector, dest_LowestPrio);
+ }
break;
}
@@ -449,19 +367,23 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno)
case dest_ExtINT:
{
uint8_t bit;
- for (bit = 0; bit < s->lapic_count; bit++) {
- if (deliver_bitmask & (1 << bit)) {
+ for ( bit = 0; deliver_bitmask != 0; bit++ )
+ {
+ if ( !(deliver_bitmask & (1 << bit)) )
+ continue;
+ deliver_bitmask &= ~(1 << bit);
#ifdef IRQ0_SPECIAL_ROUTING
- if ( (irqno == 0) && (bit !=0) )
- {
- printk("PIT irq to bit %x\n", bit);
- domain_crash_synchronous();
- }
+ /* Do not deliver timer interrupts to VCPU != 0 */
+ if ( (irq == 0) && (bit != 0) )
+ v = vioapic_domain(vioapic)->vcpu[0];
+ else
#endif
- if (s->lapic_info[bit]) {
- ioapic_inj_irq(s, s->lapic_info[bit],
- vector, trig_mode, delivery_mode);
- }
+ v = vioapic_domain(vioapic)->vcpu[bit];
+ if ( v != NULL )
+ {
+ target = vcpu_vlapic(v);
+ ioapic_inj_irq(vioapic, target, vector,
+ trig_mode, delivery_mode);
}
}
break;
@@ -472,174 +394,85 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno)
case dest_INIT:
case dest__reserved_2:
default:
- printk("Not support delivey mode %d\n", delivery_mode);
+ gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n",
+ delivery_mode);
break;
}
}
-static int ioapic_get_highest_irq(hvm_vioapic_t *s)
+void vioapic_irq_positive_edge(struct domain *d, unsigned int irq)
{
- uint32_t irqs = s->irr & ~s->isr & ~s->imr;
- return fls(irqs) - 1;
-}
-
-static void service_ioapic(hvm_vioapic_t *s)
-{
- int irqno;
-
- while ((irqno = ioapic_get_highest_irq(s)) != -1) {
+ struct vioapic *vioapic = domain_vioapic(d);
+ union vioapic_redir_entry *ent;
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "service_ioapic "
- "highest irqno %x\n", irqno);
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_irq_positive_edge irq %x", irq);
- if (!test_bit(irqno, &s->imr)) {
- ioapic_deliver(s, irqno);
- }
-
- if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) {
- s->isr |= (1 << irqno);
- }
+ ASSERT(irq < VIOAPIC_NUM_PINS);
+ ASSERT(spin_is_locked(&d->arch.hvm_domain.irq.lock));
- s->irr &= ~(1 << irqno);
- }
-}
-
-void hvm_vioapic_do_irqs(struct domain *d, uint16_t irqs)
-{
- hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
-
- if (!hvm_apic_support(d))
- return;
-
- s->irr |= irqs & ~s->imr;
- service_ioapic(s);
-}
-
-void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs)
-{
- hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
-
- if (!hvm_apic_support(d))
+ ent = &vioapic->redirtbl[irq];
+ if ( ent->fields.mask )
return;
- s->irr &= ~irqs;
- service_ioapic(s);
-}
-
-void hvm_vioapic_set_irq(struct domain *d, int irq, int level)
-{
- hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
-
- if (!hvm_apic_support(d))
- return ;
-
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq "
- "irq %x level %x\n", irq, level);
-
- if (irq < 0 || irq >= IOAPIC_NUM_PINS) {
- printk("ioapic_set_irq irq %x is illegal\n", irq);
- domain_crash_synchronous();
+ if ( ent->fields.trig_mode == VIOAPIC_EDGE_TRIG )
+ {
+ vioapic_deliver(vioapic, irq);
}
-
- if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask)
- return;
-
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "hvm_vioapic_set_irq entry %x "
- "vector %x deliver_mod %x destmode %x delivestatus %x "
- "polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n",
- irq,
- s->redirtbl[irq].RedirForm.vector,
- s->redirtbl[irq].RedirForm.deliver_mode,
- s->redirtbl[irq].RedirForm.destmode,
- s->redirtbl[irq].RedirForm.delivestatus,
- s->redirtbl[irq].RedirForm.polarity,
- s->redirtbl[irq].RedirForm.remoteirr,
- s->redirtbl[irq].RedirForm.trigmod,
- s->redirtbl[irq].RedirForm.mask,
- s->redirtbl[irq].RedirForm.dest_id);
-
- if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
- uint32_t bit = 1 << irq;
- if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) {
- if (level)
- s->irr |= bit;
- else
- s->irr &= ~bit;
- } else {
- if (level)
- /* XXX No irr clear for edge interrupt */
- s->irr |= bit;
- }
+ else if ( !ent->fields.remote_irr )
+ {
+ ent->fields.remote_irr = 1;
+ vioapic_deliver(vioapic, irq);
}
-
- service_ioapic(s);
}
-/* XXX If level interrupt, use vector->irq table for performance */
-static int get_redir_num(hvm_vioapic_t *s, int vector)
+static int get_eoi_gsi(struct vioapic *vioapic, int vector)
{
- int i = 0;
-
- ASSERT(s);
+ int i;
- for(i = 0; i < IOAPIC_NUM_PINS; i++) {
- if (s->redirtbl[i].RedirForm.vector == vector)
+ for ( i = 0; i < VIOAPIC_NUM_PINS; i++ )
+ if ( vioapic->redirtbl[i].fields.vector == vector )
return i;
- }
return -1;
}
-void ioapic_update_EOI(struct domain *d, int vector)
+void vioapic_update_EOI(struct domain *d, int vector)
{
- hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
- int redir_num;
+ struct vioapic *vioapic = domain_vioapic(d);
+ struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ union vioapic_redir_entry *ent;
+ int gsi;
- if ((redir_num = get_redir_num(s, vector)) == -1) {
- printk("Can't find redir item for %d EOI \n", vector);
- return;
- }
+ spin_lock(&hvm_irq->lock);
- if (!test_and_clear_bit(redir_num, &s->isr)) {
- printk("redir %d not set for %d EOI\n", redir_num, vector);
- return;
+ if ( (gsi = get_eoi_gsi(vioapic, vector)) == -1 )
+ {
+ gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector);
+ goto out;
}
-}
-int hvm_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v)
-{
- hvm_vioapic_t *s = &(v->domain->arch.hvm_domain.vioapic);
+ ent = &vioapic->redirtbl[gsi];
- if (v->vcpu_id != s->lapic_count) {
- printk("hvm_vioapic_add_lapic "
- "cpu_id not match vcpu_id %x lapic_count %x\n",
- v->vcpu_id, s->lapic_count);
- domain_crash_synchronous();
+ ent->fields.remote_irr = 0;
+ if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
+ !ent->fields.mask &&
+ hvm_irq->gsi_assert_count[gsi] )
+ {
+ ent->fields.remote_irr = 1;
+ vioapic_deliver(vioapic, gsi);
}
- /* update count later for race condition on interrupt */
- s->lapic_info[s->lapic_count] = vlapic;
- s->lapic_count ++;
-
- return s->lapic_count;
+ out:
+ spin_unlock(&hvm_irq->lock);
}
-hvm_vioapic_t * hvm_vioapic_init(struct domain *d)
+void vioapic_init(struct domain *d)
{
- int i = 0;
- hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
-
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "hvm_vioapic_init\n");
-
- hvm_vioapic_reset(s);
-
- s->domain = d;
-
- for (i = 0; i < MAX_LAPIC_NUM; i++)
- s->lapic_info[i] = NULL;
-
- /* Remove after GFW ready */
- ioapic_update_config(s, IOAPIC_DEFAULT_BASE_ADDRESS, 1);
+ struct vioapic *vioapic = domain_vioapic(d);
+ int i;
- return s;
+ memset(vioapic, 0, sizeof(*vioapic));
+ for ( i = 0; i < VIOAPIC_NUM_PINS; i++ )
+ vioapic->redirtbl[i].fields.mask = 1;
+ vioapic->base_address = VIOAPIC_DEFAULT_BASE_ADDRESS;
}
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index a3ed24a491..1c6bef005e 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -2,6 +2,7 @@
* vlapic.c: virtualize LAPIC for HVM vcpus.
*
* Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -29,20 +30,26 @@
#include <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
-
#include <xen/lib.h>
#include <xen/sched.h>
#include <asm/current.h>
#include <public/hvm/ioreq.h>
#include <public/hvm/params.h>
-/* XXX remove this definition after GFW enabled */
-#define VLAPIC_NO_BIOS
+#define VLAPIC_VERSION 0x00050014
+#define VLAPIC_LVT_NUM 6
extern u32 get_apic_bus_cycle(void);
#define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000)
+#define LVT_MASK \
+ APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
+
+#define LINT_MASK \
+ LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
+ APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
+
static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
{
/* LVTT */
@@ -57,9 +64,75 @@ static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
LVT_MASK
};
-int hvm_apic_support(struct domain *d)
+/* Following could belong in apicdef.h */
+#define APIC_SHORT_MASK 0xc0000
+#define APIC_DEST_NOSHORT 0x0
+#define APIC_DEST_MASK 0x800
+
+#define vlapic_lvt_enabled(vlapic, lvt_type) \
+ (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED))
+
+#define vlapic_lvt_vector(vlapic, lvt_type) \
+ (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
+
+#define vlapic_lvt_dm(vlapic, lvt_type) \
+ (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
+
+#define vlapic_lvtt_period(vlapic) \
+ (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
+
+#define vlapic_base_address(vlapic) \
+ (vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE)
+
+static int vlapic_reset(struct vlapic *vlapic);
+
+/*
+ * Generic APIC bitmap vector update & search routines.
+ */
+
+#define VEC_POS(v) ((v)%32)
+#define REG_POS(v) (((v)/32)* 0x10)
+#define vlapic_test_and_set_vector(vec, bitmap) \
+ test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_test_and_clear_vector(vec, bitmap) \
+ test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_set_vector(vec, bitmap) \
+ set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_clear_vector(vec, bitmap) \
+ clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+
+static int vlapic_find_highest_vector(u32 *bitmap)
{
- return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED];
+ int word_offset = MAX_VECTOR / 32;
+
+ /* Work backwards through the bitmap (first 32-bit word in every four). */
+ while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) )
+ continue;
+
+ return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32);
+}
+
+
+/*
+ * IRR-specific bitmap update & search routines.
+ */
+
+static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
+}
+
+static void vlapic_set_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ vlapic_set_vector(vector, vlapic->regs + APIC_IRR);
+}
+
+static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
}
int vlapic_find_highest_irr(struct vlapic *vlapic)
@@ -72,12 +145,23 @@ int vlapic_find_highest_irr(struct vlapic *vlapic)
return result;
}
+int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
+{
+ int ret;
+
+ ret = !vlapic_test_and_set_irr(vec, vlapic);
+ if ( trig )
+ vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
+
+ /* We may need to wake up target vcpu, besides set pending bit here */
+ return ret;
+}
+
s_time_t get_apictime_scheduled(struct vcpu *v)
{
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
- if ( !hvm_apic_support(v->domain) ||
- !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
+ if ( !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
return -1;
return vlapic->vlapic_timer.expires;
@@ -93,26 +177,19 @@ int vlapic_find_highest_isr(struct vlapic *vlapic)
return result;
}
-uint32_t vlapic_update_ppr(struct vlapic *vlapic)
+uint32_t vlapic_get_ppr(struct vlapic *vlapic)
{
uint32_t tpr, isrv, ppr;
int isr;
- tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
-
- isr = vlapic_find_highest_isr(vlapic);
-
- if ( isr != -1 )
- isrv = (isr >> 4) & 0xf; /* ditto */
- else
- isrv = 0;
+ tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
+ isr = vlapic_find_highest_isr(vlapic);
+ isrv = (isr != -1) ? isr : 0;
- if ( (tpr >> 4) >= isrv )
+ if ( (tpr & 0xf0) >= (isrv & 0xf0) )
ppr = tpr & 0xff;
else
- ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */
-
- vlapic_set_reg(vlapic, APIC_PROCPRI, ppr);
+ ppr = isrv & 0xf0;
HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
"vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.",
@@ -121,61 +198,55 @@ uint32_t vlapic_update_ppr(struct vlapic *vlapic)
return ppr;
}
-/* This only for fixed delivery mode */
-static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
- int short_hand, int dest, int dest_mode,
- int delivery_mode)
+int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
{
int result = 0;
- struct vlapic *target = VLAPIC(v);
+ uint8_t logical_id;
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
- "dest_mode 0x%x, short_hand 0x%x, delivery_mode 0x%x.",
- target, source, dest, dest_mode, short_hand, delivery_mode);
+ logical_id = GET_APIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
- if ( unlikely(target == NULL) &&
- ((delivery_mode != APIC_DM_INIT) &&
- (delivery_mode != APIC_DM_STARTUP) &&
- (delivery_mode != APIC_DM_NMI)) )
+ switch ( vlapic_get_reg(vlapic, APIC_DFR) )
{
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, "
- "delivery_mode 0x%x, dest 0x%x.\n", v, delivery_mode, dest);
- return result;
+ case APIC_DFR_FLAT:
+ if ( logical_id & mda )
+ result = 1;
+ break;
+ case APIC_DFR_CLUSTER:
+ if ( ((logical_id >> 4) == (mda >> 0x4)) && (logical_id & mda & 0xf) )
+ result = 1;
+ break;
+ default:
+ gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d\n",
+ vlapic_vcpu(vlapic)->vcpu_id);
+ break;
}
- switch ( short_hand ) {
- case APIC_DEST_NOSHORT: /* no shorthand */
- if ( !dest_mode ) /* Physical */
+ return result;
+}
+
+static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
+ int short_hand, int dest, int dest_mode)
+{
+ int result = 0;
+ struct vlapic *target = vcpu_vlapic(v);
+
+ HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
+ "dest_mode 0x%x, short_hand 0x%x\n",
+ target, source, dest, dest_mode, short_hand);
+
+ switch ( short_hand )
+ {
+ case APIC_DEST_NOSHORT:
+ if ( dest_mode == 0 )
{
- result = ( ((target != NULL) ?
- GET_APIC_ID(vlapic_get_reg(target, APIC_ID)):
- v->vcpu_id)) == dest;
+ /* Physical mode. */
+ if ( (dest == 0xFF) || (dest == VLAPIC_ID(target)) )
+ result = 1;
}
- else /* Logical */
+ else
{
- uint32_t ldr;
- if ( target == NULL )
- break;
- ldr = vlapic_get_reg(target, APIC_LDR);
-
- /* Flat mode */
- if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT)
- {
- result = GET_APIC_LOGICAL_ID(ldr) & dest;
- }
- else
- {
- if ( (delivery_mode == APIC_DM_LOWEST) &&
- (dest == 0xff) )
- {
- /* What shall we do now? */
- printk("Broadcast IPI with lowest priority "
- "delivery mode\n");
- domain_crash_synchronous();
- }
- result = (GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ?
- (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0;
- }
+ /* Logical mode. */
+ result = vlapic_match_logical_addr(target, dest);
}
break;
@@ -194,87 +265,83 @@ static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
break;
default:
+ gdprintk(XENLOG_WARNING, "Bad dest shorthand value %x\n", short_hand);
break;
}
return result;
}
-/*
- * Add a pending IRQ into lapic.
- * Return 1 if successfully added and 0 if discarded.
- */
+/* Add a pending IRQ into lapic. */
static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
int vector, int level, int trig_mode)
{
int result = 0;
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
- switch ( delivery_mode ) {
+ switch ( delivery_mode )
+ {
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
/* FIXME add logic for vcpu on reset */
- if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
+ if ( unlikely(!vlapic_enabled(vlapic)) )
break;
- if ( vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR) &&
- trig_mode)
+ if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
{
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "level trig mode repeatedly for vector %d\n", vector);
+ "level trig mode repeatedly for vector %d\n", vector);
break;
}
if ( trig_mode )
{
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "level trig mode for vector %d\n", vector);
+ "level trig mode for vector %d\n", vector);
vlapic_set_vector(vector, vlapic->regs + APIC_TMR);
}
- hvm_prod_vcpu(v);
+
+ vcpu_kick(v);
result = 1;
break;
case APIC_DM_REMRD:
- printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
+ gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3\n");
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
- /* Fixme */
- printk("TODO: for guest SMI/NMI\n");
+ gdprintk(XENLOG_WARNING, "Ignoring guest SMI/NMI\n");
break;
case APIC_DM_INIT:
- if ( trig_mode && !(level & APIC_INT_ASSERT) ) //Deassert
- printk("This hvm_vlapic is for P4, no work for De-assert init\n");
- else
+ /* No work on INIT de-assert for P4-type APIC. */
+ if ( trig_mode && !(level & APIC_INT_ASSERT) )
+ break;
+ /* FIXME How to check the situation after vcpu reset? */
+ if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
{
- /* FIXME How to check the situation after vcpu reset? */
- if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
- {
- printk("Reset hvm vcpu not supported yet\n");
- domain_crash_synchronous();
- }
- v->arch.hvm_vcpu.init_sipi_sipi_state =
- HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
- result = 1;
+ gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n");
+ goto exit_and_crash;
}
+ v->arch.hvm_vcpu.init_sipi_sipi_state =
+ HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
+ result = 1;
break;
case APIC_DM_STARTUP:
if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
- HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
+ HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
break;
v->arch.hvm_vcpu.init_sipi_sipi_state =
- HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
+ HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
{
- printk("SIPI for initialized vcpu vcpuid %x\n", v->vcpu_id);
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "SIPI for initialized vcpu %x\n", v->vcpu_id);
+ goto exit_and_crash;
}
if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
@@ -282,66 +349,39 @@ static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
break;
default:
- printk("TODO: not support interrupt type %x\n", delivery_mode);
- domain_crash_synchronous();
- break;
+ gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode %x\n",
+ delivery_mode);
+ goto exit_and_crash;
}
return result;
+
+ exit_and_crash:
+ domain_crash(v->domain);
+ return 0;
}
-/*
- * This function is used by both ioapic and local APIC
- * The bitmap is for vcpu_id
- */
-struct vlapic *apic_round_robin(struct domain *d,
- uint8_t dest_mode,
- uint8_t vector,
- uint32_t bitmap)
+/* This function is used by both ioapic and lapic.The bitmap is for vcpu_id. */
+struct vlapic *apic_round_robin(
+ struct domain *d, uint8_t vector, uint32_t bitmap)
{
int next, old;
- struct vlapic* target = NULL;
+ struct vlapic *target = NULL;
- if ( dest_mode == 0 ) //Physical mode
- {
- printk("<apic_round_robin> lowest priority for physical mode.\n");
- return NULL;
- }
-
- if ( !bitmap )
- {
- printk("<apic_round_robin> no bit set in bitmap.\n");
- return NULL;
- }
-
- spin_lock(&d->arch.hvm_domain.round_robin_lock);
+ old = next = d->arch.hvm_domain.irq.round_robin_prev_vcpu;
- old = next = d->arch.hvm_domain.round_info[vector];
-
- /* the vcpu array is arranged according to vcpu_id */
- do
- {
+ do {
if ( ++next == MAX_VIRT_CPUS )
next = 0;
- if ( d->vcpu[next] == NULL ||
- !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) )
+ if ( (d->vcpu[next] == NULL) || !test_bit(next, &bitmap) )
continue;
-
- if ( test_bit(next, &bitmap) )
- {
- target = d->vcpu[next]->arch.hvm_vcpu.vlapic;
-
- if ( target == NULL || !vlapic_enabled(target) )
- {
- printk("warning: targe round robin local apic disabled\n");
- /* XXX should we domain crash?? Or should we return NULL */
- }
+ target = vcpu_vlapic(d->vcpu[next]);
+ if ( vlapic_enabled(target) )
break;
- }
+ target = NULL;
} while ( next != old );
- d->arch.hvm_domain.round_info[vector] = next;
- spin_unlock(&d->arch.hvm_domain.round_robin_lock);
+ d->arch.hvm_domain.irq.round_robin_prev_vcpu = next;
return target;
}
@@ -350,31 +390,14 @@ void vlapic_EOI_set(struct vlapic *vlapic)
{
int vector = vlapic_find_highest_isr(vlapic);
- /* Not every write EOI will has correpsoning ISR,
- one example is when Kernel check timer on setup_IO_APIC */
+ /* Some EOI writes may not have a matching to an in-service interrupt. */
if ( vector == -1 )
- return ;
+ return;
vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
- vlapic_update_ppr(vlapic);
if ( vlapic_test_and_clear_vector(vector, vlapic->regs + APIC_TMR) )
- ioapic_update_EOI(vlapic->domain, vector);
-}
-
-static int vlapic_check_vector(struct vlapic *vlapic,
- uint32_t dm, uint32_t vector)
-{
- if ( (dm == APIC_DM_FIXED) && (vector < 16) )
- {
- vlapic->err_status |= 0x40;
- vlapic_accept_irq(vlapic->vcpu, APIC_DM_FIXED,
- vlapic_lvt_vector(vlapic, APIC_LVTERR), 0, 0);
- printk("<vlapic_check_vector>: check failed "
- " dm %x vector %x\n", dm, vector);
- return 0;
- }
- return 1;
+ vioapic_update_EOI(vlapic_domain(vlapic), vector);
}
static void vlapic_ipi(struct vlapic *vlapic)
@@ -387,12 +410,12 @@ static void vlapic_ipi(struct vlapic *vlapic)
unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
unsigned int level = icr_low & APIC_INT_ASSERT;
unsigned int dest_mode = icr_low & APIC_DEST_MASK;
- unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
+ unsigned int delivery_mode =icr_low & APIC_MODE_MASK;
unsigned int vector = icr_low & APIC_VECTOR_MASK;
struct vlapic *target;
- struct vcpu *v = NULL;
- uint32_t lpr_map=0;
+ struct vcpu *v;
+ uint32_t lpr_map = 0;
HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
@@ -400,12 +423,11 @@ static void vlapic_ipi(struct vlapic *vlapic)
icr_high, icr_low, short_hand, dest,
trig_mode, level, dest_mode, delivery_mode, vector);
- for_each_vcpu ( vlapic->domain, v )
+ for_each_vcpu ( vlapic_domain(vlapic), v )
{
- if ( vlapic_match_dest(v, vlapic, short_hand,
- dest, dest_mode, delivery_mode) )
+ if ( vlapic_match_dest(v, vlapic, short_hand, dest, dest_mode) )
{
- if ( delivery_mode == APIC_DM_LOWEST)
+ if ( delivery_mode == APIC_DM_LOWEST )
set_bit(v->vcpu_id, &lpr_map);
else
vlapic_accept_irq(v, delivery_mode,
@@ -413,13 +435,11 @@ static void vlapic_ipi(struct vlapic *vlapic)
}
}
- if ( delivery_mode == APIC_DM_LOWEST)
+ if ( delivery_mode == APIC_DM_LOWEST )
{
- v = vlapic->vcpu;
- target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
-
- if ( target )
- vlapic_accept_irq(target->vcpu, delivery_mode,
+ target = apic_round_robin(vlapic_domain(v), vector, lpr_map);
+ if ( target != NULL )
+ vlapic_accept_irq(vlapic_vcpu(target), delivery_mode,
vector, level, trig_mode);
}
}
@@ -430,8 +450,6 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
s_time_t passed, now = NOW();
uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT);
- ASSERT(vlapic != NULL);
-
if ( unlikely(now <= vlapic->timer_last_update) )
{
passed = ~0x0LL - vlapic->timer_last_update + now;
@@ -440,8 +458,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
else
passed = now - vlapic->timer_last_update;
- counter_passed = passed /
- (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
+ counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor);
tmcct -= counter_passed;
@@ -450,7 +467,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
if ( unlikely(!vlapic_lvtt_period(vlapic)) )
{
tmcct = 0;
- // FIXME: should we add interrupt here?
+ /* FIXME: should we add interrupt here? */
}
else
{
@@ -473,27 +490,32 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
return tmcct;
}
+static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
+{
+ /* Only bits 0, 1 and 3 are settable; others are MBZ. */
+ val &= 0xb;
+ vlapic_set_reg(vlapic, APIC_TDCR, val);
+
+ /* Update the demangled timer_divisor. */
+ val = ((val & 3) | ((val & 8) >> 1)) + 1;
+ vlapic->timer_divisor = 1 << (val & 7);
+}
+
static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
unsigned int len, unsigned int *result)
{
- ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR);
+ ASSERT((len == 4) && (offset > 0) && (offset <= APIC_TDCR));
- *result = 0;
-
- switch ( offset ) {
- case APIC_ARBPRI:
- printk("access local APIC ARBPRI register which is for P6\n");
+ switch ( offset )
+ {
+ case APIC_PROCPRI:
+ *result = vlapic_get_ppr(vlapic);
break;
- case APIC_TMCCT: //Timer CCR
+ case APIC_TMCCT: /* Timer CCR */
*result = vlapic_get_tmcct(vlapic);
break;
- case APIC_ESR:
- vlapic->err_write_count = 0;
- *result = vlapic_get_reg(vlapic, offset);
- break;
-
default:
*result = vlapic_get_reg(vlapic, offset);
break;
@@ -506,10 +528,10 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
unsigned int alignment;
unsigned int tmp;
unsigned long result;
- struct vlapic *vlapic = VLAPIC(v);
- unsigned int offset = address - vlapic->base_address;
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ unsigned int offset = address - vlapic_base_address(vlapic);
- if ( offset > APIC_TDCR)
+ if ( offset > APIC_TDCR )
return 0;
/* some bugs on kernel cause read this with byte*/
@@ -521,7 +543,8 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
alignment = offset & 0x3;
vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
- switch ( len ) {
+ switch ( len )
+ {
case 1:
result = *((unsigned char *)&tmp + alignment);
break;
@@ -537,22 +560,26 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
break;
default:
- printk("Local APIC read with len=0x%lx, should be 4 instead.\n", len);
- domain_crash_synchronous();
- break;
+ gdprintk(XENLOG_ERR, "Local APIC read with len=0x%lx, "
+ "should be 4 instead.\n", len);
+ goto exit_and_crash;
}
HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
"and the result is 0x%lx.", offset, len, result);
return result;
+
+ exit_and_crash:
+ domain_crash(v->domain);
+ return 0;
}
static void vlapic_write(struct vcpu *v, unsigned long address,
unsigned long len, unsigned long val)
{
- struct vlapic *vlapic = VLAPIC(v);
- unsigned int offset = address - vlapic->base_address;
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ unsigned int offset = address - vlapic_base_address(vlapic);
if ( offset != 0xb0 )
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
@@ -560,61 +587,54 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
offset, len, val);
/*
- * According to IA 32 Manual, all resgiters should be accessed with
- * 32 bits alignment.
+ * According to the IA32 Manual, all accesses should be 32 bits.
+ * Some OSes do 8- or 16-byte accesses, however.
*/
if ( len != 4 )
{
unsigned int tmp;
unsigned char alignment;
- /* Some kernels do will access with byte/word alignment */
- printk("Notice: Local APIC write with len = %lx\n",len);
+ gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
+
alignment = offset & 0x3;
tmp = vlapic_read(v, offset & ~0x3, 4);
- switch ( len ) {
+
+ switch ( len )
+ {
case 1:
- /* XXX the saddr is a tmp variable from caller, so should be ok
- But we should still change the following ref to val to
- local variable later */
val = (tmp & ~(0xff << (8*alignment))) |
((val & 0xff) << (8*alignment));
break;
case 2:
- if ( alignment != 0x0 && alignment != 0x2 )
+ if ( alignment & 1 )
{
- printk("alignment error for vlapic with len == 2\n");
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "Uneven alignment error for "
+ "2-byte vlapic access\n");
+ goto exit_and_crash;
}
val = (tmp & ~(0xffff << (8*alignment))) |
((val & 0xffff) << (8*alignment));
break;
- case 3:
- /* will it happen? */
- printk("vlapic_write with len = 3 !!!\n");
- domain_crash_synchronous();
- break;
-
default:
- printk("Local APIC write with len = %lx, should be 4 instead\n", len);
- domain_crash_synchronous();
- break;
+ gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
+ "should be 4 instead\n", len);
+ exit_and_crash:
+ domain_crash(v->domain);
+ return;
}
}
offset &= 0xff0;
- switch ( offset ) {
- case APIC_ID: /* Local APIC ID */
- vlapic_set_reg(vlapic, APIC_ID, val);
- break;
-
+ switch ( offset )
+ {
case APIC_TASKPRI:
vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
- vlapic_update_ppr(vlapic);
+ vlapic->flush_tpr_threshold = 1;
break;
case APIC_EOI:
@@ -632,12 +652,12 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
case APIC_SPIV:
vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
- if ( !( val & APIC_SPIV_APIC_ENABLED) )
+ if ( !(val & APIC_SPIV_APIC_ENABLED) )
{
int i;
uint32_t lvt_val;
- vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
+ vlapic->disabled |= VLAPIC_SW_DISABLED;
for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
{
@@ -645,24 +665,16 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
lvt_val | APIC_LVT_MASKED);
}
-
- if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
- == APIC_DM_EXTINT )
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
}
else
{
- vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
- if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
- == APIC_DM_EXTINT )
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
+ vlapic->disabled &= ~VLAPIC_SW_DISABLED;
+ vlapic->flush_tpr_threshold = 1;
}
break;
case APIC_ESR:
- vlapic->err_write_count = !vlapic->err_write_count;
- if ( !vlapic->err_write_count )
- vlapic->err_status = 0;
+ /* Nothing to do. */
break;
case APIC_ICR:
@@ -675,95 +687,60 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
break;
- case APIC_LVTT: // LVT Timer Reg
- case APIC_LVTTHMR: // LVT Thermal Monitor
- case APIC_LVTPC: // LVT Performance Counter
- case APIC_LVT0: // LVT LINT0 Reg
- case APIC_LVT1: // LVT Lint1 Reg
- case APIC_LVTERR: // LVT Error Reg
- {
- if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
- val |= APIC_LVT_MASKED;
-
- val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
-
- vlapic_set_reg(vlapic, offset, val);
-
- /* On hardware, when write vector less than 0x20 will error */
- if ( !(val & APIC_LVT_MASKED) )
- vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic, offset),
- vlapic_lvt_vector(vlapic, offset));
-
- if ( !vlapic->vcpu_id && (offset == APIC_LVT0) )
- {
- if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
- if ( val & APIC_LVT_MASKED)
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- else
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- else
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- }
-
- }
+ case APIC_LVTT: /* LVT Timer Reg */
+ case APIC_LVTTHMR: /* LVT Thermal Monitor */
+ case APIC_LVTPC: /* LVT Performance Counter */
+ case APIC_LVT0: /* LVT LINT0 Reg */
+ case APIC_LVT1: /* LVT Lint1 Reg */
+ case APIC_LVTERR: /* LVT Error Reg */
+ if ( vlapic_sw_disabled(vlapic) )
+ val |= APIC_LVT_MASKED;
+ val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
+ vlapic_set_reg(vlapic, offset, val);
break;
case APIC_TMICT:
- {
- s_time_t now = NOW(), offset;
+ {
+ s_time_t now = NOW(), offset;
- stop_timer(&vlapic->vlapic_timer);
+ stop_timer(&vlapic->vlapic_timer);
- vlapic_set_reg(vlapic, APIC_TMICT, val);
- vlapic_set_reg(vlapic, APIC_TMCCT, val);
- vlapic->timer_last_update = now;
+ vlapic_set_reg(vlapic, APIC_TMICT, val);
+ vlapic_set_reg(vlapic, APIC_TMCCT, val);
+ vlapic->timer_last_update = now;
- offset = APIC_BUS_CYCLE_NS *
- vlapic->timer_divide_count * val;
+ offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val;
- set_timer(&vlapic->vlapic_timer, now + offset);
+ set_timer(&vlapic->vlapic_timer, now + offset);
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
- "timer initial count 0x%x, offset 0x%016"PRIx64", "
- "expire @ 0x%016"PRIx64".",
- APIC_BUS_CYCLE_NS, now,
- vlapic_get_reg(vlapic, APIC_TMICT),
- offset, now + offset);
- }
- break;
+ HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
+ "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
+ "timer initial count 0x%x, offset 0x%016"PRIx64", "
+ "expire @ 0x%016"PRIx64".",
+ APIC_BUS_CYCLE_NS, now,
+ vlapic_get_reg(vlapic, APIC_TMICT),
+ offset, now + offset);
+ }
+ break;
case APIC_TDCR:
- {
- unsigned int tmp1, tmp2;
-
- tmp1 = val & 0xf;
- tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
- vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
-
- vlapic_set_reg(vlapic, APIC_TDCR, val);
-
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
- vlapic->timer_divide_count);
- }
+ vlapic_set_tdcr(vlapic, val & 0xb);
+ HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
+ vlapic->timer_divisor);
break;
default:
- printk("Local APIC Write to read-only register\n");
+ gdprintk(XENLOG_WARNING,
+ "Local APIC Write to read-only register 0x%x\n", offset);
break;
}
}
static int vlapic_range(struct vcpu *v, unsigned long addr)
{
- struct vlapic *vlapic = VLAPIC(v);
-
- if ( vlapic_global_enabled(vlapic) &&
- (addr >= vlapic->base_address) &&
- (addr < vlapic->base_address + VLOCAL_APIC_MEM_LENGTH) )
- return 1;
-
- return 0;
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ unsigned long offset = addr - vlapic_base_address(vlapic);
+ return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
}
struct hvm_mmio_handler vlapic_mmio_handler = {
@@ -774,32 +751,28 @@ struct hvm_mmio_handler vlapic_mmio_handler = {
void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
{
- /* When apic disabled */
- if ( vlapic == NULL )
- return;
-
- if ( vlapic->vcpu_id )
- value &= ~MSR_IA32_APICBASE_BSP;
+ if ( (vlapic->apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
+ {
+ if ( value & MSR_IA32_APICBASE_ENABLE )
+ {
+ vlapic_reset(vlapic);
+ vlapic->disabled &= ~VLAPIC_HW_DISABLED;
+ }
+ else
+ {
+ vlapic->disabled |= VLAPIC_HW_DISABLED;
+ }
+ }
vlapic->apic_base_msr = value;
- vlapic->base_address = vlapic->apic_base_msr &
- MSR_IA32_APICBASE_BASE;
-
- /* with FSB delivery interrupt, we can restart APIC functionality */
- if ( !(value & MSR_IA32_APICBASE_ENABLE) )
- set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
- else
- clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
- vlapic->apic_base_msr, vlapic->base_address);
+ "apic base msr is 0x%016"PRIx64".", vlapic->apic_base_msr);
}
void vlapic_timer_fn(void *data)
{
struct vlapic *vlapic = data;
- struct vcpu *v;
uint32_t timer_vector;
s_time_t now;
@@ -807,14 +780,13 @@ void vlapic_timer_fn(void *data)
!vlapic_lvt_enabled(vlapic, APIC_LVTT)) )
return;
- v = vlapic->vcpu;
timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT);
now = NOW();
vlapic->timer_last_update = now;
- if ( vlapic_test_and_set_vector(timer_vector, vlapic->regs + APIC_IRR) )
- vlapic->intr_pending_count[timer_vector]++;
+ if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
+ vlapic->timer_pending_count++;
if ( vlapic_lvtt_period(vlapic) )
{
@@ -823,20 +795,14 @@ void vlapic_timer_fn(void *data)
vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
- offset = APIC_BUS_CYCLE_NS *
- vlapic->timer_divide_count * tmict;
+ offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict;
set_timer(&vlapic->vlapic_timer, now + offset);
}
else
vlapic_set_reg(vlapic, APIC_TMCCT, 0);
-#if 0
- if ( test_bit(_VCPUF_running, &v->vcpu_flags) )
- {
- /* TODO: add guest time handling here */
- }
-#endif
+ vcpu_kick(vlapic_vcpu(vlapic));
HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
"now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
@@ -846,225 +812,159 @@ void vlapic_timer_fn(void *data)
vlapic_get_reg(vlapic, APIC_TMCCT));
}
-#if 0
-static int
-vlapic_check_direct_intr(struct vcpu *v, int * mode)
-{
- struct vlapic *vlapic = VLAPIC(v);
- int type;
-
- type = fls(vlapic->direct_intr.deliver_mode) - 1;
- if ( type == -1 )
- return -1;
-
- *mode = type;
- return 0;
-}
-#endif
-
int vlapic_accept_pic_intr(struct vcpu *v)
{
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
- return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
+ /*
+ * Only CPU0 is wired to the 8259A. INTA cycles occur if LINT0 is set up
+ * accept ExtInts, or if the LAPIC is disabled (so LINT0 behaves as INTR).
+ */
+ return ((v->vcpu_id == 0) &&
+ (((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
+ vlapic_hw_disabled(vlapic)));
}
int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
{
- struct vlapic *vlapic = VLAPIC(v);
-
- if ( vlapic && vlapic_enabled(vlapic) )
- {
- int highest_irr = vlapic_find_highest_irr(vlapic);
-
- if ( highest_irr != -1 &&
- ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) )
- {
- if ( highest_irr < 0x10 )
- {
- uint32_t err_vector;
-
- vlapic->err_status |= 0x20;
- err_vector = vlapic_lvt_vector(vlapic, APIC_LVTERR);
-
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "Sending an illegal vector 0x%x.", highest_irr);
-
- vlapic_set_vector(err_vector, vlapic->regs + APIC_IRR);
- highest_irr = err_vector;
- }
-
- *mode = APIC_DM_FIXED;
- return highest_irr;
- }
- }
- return -1;
-}
+ struct vlapic *vlapic = vcpu_vlapic(v);
+ int highest_irr;
-int cpu_has_apic_interrupt(struct vcpu* v)
-{
- struct vlapic *vlapic = VLAPIC(v);
+ if ( !vlapic_enabled(vlapic) )
+ return -1;
- if (vlapic && vlapic_enabled(vlapic)) {
- int highest_irr = vlapic_find_highest_irr(vlapic);
+ highest_irr = vlapic_find_highest_irr(vlapic);
+ if ( (highest_irr == -1) ||
+ ((highest_irr & 0xF0) <= vlapic_get_ppr(vlapic)) )
+ return -1;
- if ( highest_irr != -1 &&
- ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) {
- return 1;
- }
- }
- return 0;
+ *mode = APIC_DM_FIXED;
+ return highest_irr;
}
/* check to see if there is pending interrupt */
int cpu_has_pending_irq(struct vcpu *v)
{
struct hvm_domain *plat = &v->domain->arch.hvm_domain;
+ int dummy;
/* APIC */
- if ( cpu_has_apic_interrupt(v) ) return 1;
-
+ if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
+ return 1;
+
/* PIC */
- if ( !vlapic_accept_pic_intr(v) ) return 0;
+ if ( !vlapic_accept_pic_intr(v) )
+ return 0;
- return plat->interrupt_request;
+ return plat->irq.vpic[0].int_output;
}
void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
{
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
- if ( unlikely(vlapic == NULL) )
- return;
-
- switch ( deliver_mode ) {
+ switch ( deliver_mode )
+ {
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
- vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
- vlapic_update_ppr(vlapic);
-
- if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
+ vlapic_clear_irr(vector, vlapic);
+ if ( (vector == vlapic_lvt_vector(vlapic, APIC_LVTT)) &&
+ (vlapic->timer_pending_count != 0) )
{
- vlapic->intr_pending_count[vector]--;
- if ( vlapic->intr_pending_count[vector] > 0 )
- vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
+ vlapic->timer_pending_count--;
+ vlapic_set_irr(vector, vlapic);
}
break;
- /*XXX deal with these later */
case APIC_DM_REMRD:
- printk("Ignore deliver mode 3 in vlapic_post_injection\n");
+ gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3.\n");
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
case APIC_DM_INIT:
case APIC_DM_STARTUP:
- vlapic->direct_intr.deliver_mode &= (1 << (deliver_mode >> 8));
break;
default:
- printk("<vlapic_post_injection> invalid deliver mode\n");
+ gdprintk(XENLOG_WARNING, "Invalid delivery mode\n");
break;
}
}
+/* Reset the VLPAIC back to its power-on/reset state. */
static int vlapic_reset(struct vlapic *vlapic)
{
- struct vcpu *v;
+ struct vcpu *v = vlapic_vcpu(vlapic);
int i;
- ASSERT( vlapic != NULL );
-
- v = vlapic->vcpu;
-
- ASSERT( v != NULL );
-
- vlapic->domain = v->domain;
-
- vlapic->vcpu_id = v->vcpu_id;
+ vlapic_set_reg(vlapic, APIC_ID, (v->vcpu_id + 1) << 24);
+ vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
- vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
+ for ( i = 0; i < 8; i++ )
+ {
+ vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
+ vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
+ vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
+ }
+ vlapic_set_reg(vlapic, APIC_ICR, 0);
+ vlapic_set_reg(vlapic, APIC_ICR2, 0);
+ vlapic_set_reg(vlapic, APIC_LDR, 0);
+ vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
+ vlapic_set_reg(vlapic, APIC_TMICT, 0);
+ vlapic_set_reg(vlapic, APIC_TMCCT, 0);
+ vlapic_set_tdcr(vlapic, 0);
- vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
+ vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
- vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
-
vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
+ vlapic->disabled |= VLAPIC_SW_DISABLED;
- vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
-
- if ( v->vcpu_id == 0 )
- vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
-
- vlapic->base_address = vlapic->apic_base_msr &
- MSR_IA32_APICBASE_BASE;
-
- hvm_vioapic_add_lapic(vlapic, v);
-
- init_timer(&vlapic->vlapic_timer,
- vlapic_timer_fn, vlapic, v->processor);
-
-#ifdef VLAPIC_NO_BIOS
- /*
- * XXX According to mp sepcific, BIOS will enable LVT0/1,
- * remove it after BIOS enabled
- */
- if ( !v->vcpu_id )
- {
- vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
- vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- }
-#endif
-
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
- "base_address=0x%0lx.",
- v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
- vlapic->apic_base_msr, vlapic->base_address);
+ vlapic->flush_tpr_threshold = 1;
return 1;
}
int vlapic_init(struct vcpu *v)
{
- struct vlapic *vlapic = NULL;
-
- ASSERT( v != NULL );
+ struct vlapic *vlapic = vcpu_vlapic(v);
HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
- vlapic = xmalloc_bytes(sizeof(struct vlapic));
- if ( vlapic == NULL )
- {
- printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
- return -ENOMEM;
- }
-
- memset(vlapic, 0, sizeof(struct vlapic));
-
vlapic->regs_page = alloc_domheap_page(NULL);
if ( vlapic->regs_page == NULL )
{
- printk("malloc vlapic regs error for vcpu %x\n", v->vcpu_id);
+ dprintk(XENLOG_ERR, "malloc vlapic regs error for vcpu %x\n",
+ v->vcpu_id);
xfree(vlapic);
return -ENOMEM;
}
vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
-
memset(vlapic->regs, 0, PAGE_SIZE);
- VLAPIC(v) = vlapic;
+ vlapic_reset(vlapic);
- vlapic->vcpu = v;
+ vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+ if ( v->vcpu_id == 0 )
+ vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
- vlapic_reset(vlapic);
+ init_timer(&vlapic->vlapic_timer,
+ vlapic_timer_fn, vlapic, v->processor);
return 0;
}
+
+void vlapic_destroy(struct vcpu *v)
+{
+ struct vlapic *vlapic = vcpu_vlapic(v);
+
+ kill_timer(&vlapic->vlapic_timer);
+ unmap_domain_page_global(vlapic->regs);
+ free_domheap_page(vlapic->regs_page);
+}
diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/io.c
index f5133b3ce2..2f3cf623b1 100644
--- a/xen/arch/x86/hvm/vmx/io.c
+++ b/xen/arch/x86/hvm/vmx/io.c
@@ -63,11 +63,31 @@ disable_irq_window(struct vcpu *v)
static inline int is_interruptibility_state(void)
{
- int interruptibility;
- __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
- return interruptibility;
+ return __vmread(GUEST_INTERRUPTIBILITY_INFO);
}
+#ifdef __x86_64__
+static void update_tpr_threshold(struct vlapic *vlapic)
+{
+ int max_irr, tpr;
+
+ /* Clear the work-to-do flag /then/ do the work. */
+ vlapic->flush_tpr_threshold = 0;
+ mb();
+
+ if ( !vlapic_enabled(vlapic) ||
+ ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) )
+ {
+ __vmwrite(TPR_THRESHOLD, 0);
+ return;
+ }
+
+ tpr = vlapic_get_reg(vlapic, APIC_TASKPRI) & 0xF0;
+ __vmwrite(TPR_THRESHOLD, (max_irr > tpr) ? (tpr >> 4) : (max_irr >> 4));
+}
+#else
+#define update_tpr_threshold(v) ((void)0)
+#endif
asmlinkage void vmx_intr_assist(void)
{
@@ -75,51 +95,50 @@ asmlinkage void vmx_intr_assist(void)
int highest_vector;
unsigned long eflags;
struct vcpu *v = current;
+ struct vlapic *vlapic = vcpu_vlapic(v);
struct hvm_domain *plat=&v->domain->arch.hvm_domain;
struct periodic_time *pt = &plat->pl_time.periodic_tm;
- struct hvm_virpic *pic= &plat->vpic;
- int callback_irq;
unsigned int idtv_info_field;
unsigned long inst_len;
int has_ext_irq;
- if ( v->vcpu_id == 0 )
- hvm_pic_assist(v);
-
- if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr ) {
- pic_set_irq(pic, pt->irq, 0);
- pic_set_irq(pic, pt->irq, 1);
+ if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr )
+ {
+ hvm_isa_irq_deassert(current->domain, pt->irq);
+ hvm_isa_irq_assert(current->domain, pt->irq);
}
- callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
- if ( callback_irq != 0 &&
- local_events_need_delivery() ) {
- /*inject para-device call back irq*/
- v->vcpu_info->evtchn_upcall_mask = 1;
- pic_set_irq(pic, callback_irq, 0);
- pic_set_irq(pic, callback_irq, 1);
- }
+ hvm_set_callback_irq_level();
+
+ if ( vlapic->flush_tpr_threshold )
+ update_tpr_threshold(vlapic);
has_ext_irq = cpu_has_pending_irq(v);
- if (unlikely(v->arch.hvm_vmx.vector_injected)) {
+ if ( unlikely(v->arch.hvm_vmx.vector_injected) )
+ {
v->arch.hvm_vmx.vector_injected=0;
if (unlikely(has_ext_irq)) enable_irq_window(v);
return;
}
- __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
- if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
+ /* This could be moved earlier in the VMX resume sequence. */
+ idtv_info_field = __vmread(IDT_VECTORING_INFO_FIELD);
+ if ( unlikely(idtv_info_field & INTR_INFO_VALID_MASK) )
+ {
__vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
- __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+ /*
+ * Safe: the length will only be interpreted for software exceptions
+ * and interrupts. If we get here then delivery of some event caused a
+ * fault, and this always results in defined VM_EXIT_INSTRUCTION_LEN.
+ */
+ inst_len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe */
__vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
- if (unlikely(idtv_info_field & 0x800)) { /* valid error code */
- unsigned long error_code;
- __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
- __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
- }
+ if (unlikely(idtv_info_field & 0x800)) /* valid error code */
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ __vmread(IDT_VECTORING_ERROR_CODE));
if (unlikely(has_ext_irq))
enable_irq_window(v);
@@ -128,28 +147,35 @@ asmlinkage void vmx_intr_assist(void)
return;
}
- if (likely(!has_ext_irq)) return;
+ if ( likely(!has_ext_irq) )
+ return;
- if (unlikely(is_interruptibility_state())) {
+ if ( unlikely(is_interruptibility_state()) )
+ {
/* pre-cleared for emulated instruction */
enable_irq_window(v);
HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
return;
}
- __vmread(GUEST_RFLAGS, &eflags);
- if (irq_masked(eflags)) {
+ eflags = __vmread(GUEST_RFLAGS);
+ if ( irq_masked(eflags) )
+ {
enable_irq_window(v);
return;
}
highest_vector = cpu_get_interrupt(v, &intr_type);
- switch (intr_type) {
+ if ( highest_vector < 0 )
+ return;
+
+ switch ( intr_type )
+ {
case APIC_DM_EXTINT:
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
vmx_inject_extint(v, highest_vector, VMX_DELIVER_NO_ERROR_CODE);
- TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
+ TRACE_3D(TRC_VMX_INTR, v->domain->domain_id, highest_vector, 0);
break;
case APIC_DM_SMI:
@@ -163,7 +189,6 @@ asmlinkage void vmx_intr_assist(void)
}
hvm_interrupt_post(v, highest_vector, intr_type);
- return;
}
/*
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 5c80d7e89a..cee05bc552 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -37,36 +37,119 @@
#include <xen/keyhandler.h>
#include <asm/shadow.h>
-static int vmcs_size;
-static int vmcs_order;
+/* Basic flags for Pin-based VM-execution controls. */
+#define MONITOR_PIN_BASED_EXEC_CONTROLS \
+ ( PIN_BASED_EXT_INTR_MASK | \
+ PIN_BASED_NMI_EXITING )
+
+/* Basic flags for CPU-based VM-execution controls. */
+#ifdef __x86_64__
+#define MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH \
+ ( CPU_BASED_CR8_LOAD_EXITING | \
+ CPU_BASED_CR8_STORE_EXITING )
+#else
+#define MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH 0
+#endif
+#define MONITOR_CPU_BASED_EXEC_CONTROLS \
+ ( MONITOR_CPU_BASED_EXEC_CONTROLS_SUBARCH | \
+ CPU_BASED_HLT_EXITING | \
+ CPU_BASED_INVDPG_EXITING | \
+ CPU_BASED_MWAIT_EXITING | \
+ CPU_BASED_MOV_DR_EXITING | \
+ CPU_BASED_UNCOND_IO_EXITING | \
+ CPU_BASED_USE_TSC_OFFSETING )
+
+/* Basic flags for VM-Exit controls. */
+#ifdef __x86_64__
+#define MONITOR_VM_EXIT_CONTROLS_SUBARCH VM_EXIT_IA32E_MODE
+#else
+#define MONITOR_VM_EXIT_CONTROLS_SUBARCH 0
+#endif
+#define MONITOR_VM_EXIT_CONTROLS \
+ ( MONITOR_VM_EXIT_CONTROLS_SUBARCH | \
+ VM_EXIT_ACK_INTR_ON_EXIT )
+
+/* Basic flags for VM-Entry controls. */
+#define MONITOR_VM_ENTRY_CONTROLS 0x00000000
+
+/* Dynamic (run-time adjusted) execution control flags. */
+static u32 vmx_pin_based_exec_control;
+static u32 vmx_cpu_based_exec_control;
+static u32 vmx_vmexit_control;
+static u32 vmx_vmentry_control;
+
static u32 vmcs_revision_id;
-void vmx_init_vmcs_config(void)
+static u32 adjust_vmx_controls(u32 ctrls, u32 msr)
{
u32 vmx_msr_low, vmx_msr_high;
- if ( vmcs_size )
- return;
+ rdmsr(msr, vmx_msr_low, vmx_msr_high);
+
+ /* Bit == 0 means must be zero. */
+ BUG_ON(ctrls & ~vmx_msr_high);
+
+ /* Bit == 1 means must be one. */
+ ctrls |= vmx_msr_low;
+
+ return ctrls;
+}
+
+void vmx_init_vmcs_config(void)
+{
+ u32 vmx_msr_low, vmx_msr_high;
+ u32 _vmx_pin_based_exec_control;
+ u32 _vmx_cpu_based_exec_control;
+ u32 _vmx_vmexit_control;
+ u32 _vmx_vmentry_control;
+
+ _vmx_pin_based_exec_control =
+ adjust_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
+ MSR_IA32_VMX_PINBASED_CTLS_MSR);
+ _vmx_cpu_based_exec_control =
+ adjust_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
+ MSR_IA32_VMX_PROCBASED_CTLS_MSR);
+ _vmx_vmexit_control =
+ adjust_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
+ MSR_IA32_VMX_EXIT_CTLS_MSR);
+ _vmx_vmentry_control =
+ adjust_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
+ MSR_IA32_VMX_ENTRY_CTLS_MSR);
rdmsr(MSR_IA32_VMX_BASIC_MSR, vmx_msr_low, vmx_msr_high);
- vmcs_revision_id = vmx_msr_low;
+ if ( smp_processor_id() == 0 )
+ {
+ vmcs_revision_id = vmx_msr_low;
+ vmx_pin_based_exec_control = _vmx_pin_based_exec_control;
+ vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control;
+ vmx_vmexit_control = _vmx_vmexit_control;
+ vmx_vmentry_control = _vmx_vmentry_control;
+ }
+ else
+ {
+ BUG_ON(vmcs_revision_id != vmx_msr_low);
+ BUG_ON(vmx_pin_based_exec_control != _vmx_pin_based_exec_control);
+ BUG_ON(vmx_cpu_based_exec_control != _vmx_cpu_based_exec_control);
+ BUG_ON(vmx_vmexit_control != _vmx_vmexit_control);
+ BUG_ON(vmx_vmentry_control != _vmx_vmentry_control);
+ }
- vmcs_size = vmx_msr_high & 0x1fff;
- vmcs_order = get_order_from_bytes(vmcs_size);
+ /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
+ BUG_ON((vmx_msr_high & 0x1fff) > PAGE_SIZE);
}
static struct vmcs_struct *vmx_alloc_vmcs(void)
{
struct vmcs_struct *vmcs;
- if ( (vmcs = alloc_xenheap_pages(vmcs_order)) == NULL )
+ if ( (vmcs = alloc_xenheap_page()) == NULL )
{
- DPRINTK("Failed to allocate VMCS.\n");
+ gdprintk(XENLOG_WARNING, "Failed to allocate VMCS.\n");
return NULL;
}
- memset(vmcs, 0, vmcs_size); /* don't remove this */
+ memset(vmcs, 0, PAGE_SIZE);
vmcs->vmcs_revision_id = vmcs_revision_id;
return vmcs;
@@ -74,7 +157,7 @@ static struct vmcs_struct *vmx_alloc_vmcs(void)
static void vmx_free_vmcs(struct vmcs_struct *vmcs)
{
- free_xenheap_pages(vmcs, vmcs_order);
+ free_xenheap_page(vmcs);
}
static void __vmx_clear_vmcs(void *info)
@@ -110,13 +193,7 @@ void vmx_vmcs_enter(struct vcpu *v)
{
/*
* NB. We must *always* run an HVM VCPU on its own VMCS, except for
- * vmx_vmcs_enter/exit critical regions. This leads to some XXX TODOs XXX:
- * 1. Move construct_vmcs() much earlier, to domain creation or
- * context initialisation.
- * 2. VMPTRLD as soon as we context-switch to a HVM VCPU.
- * 3. VMCS destruction needs to happen later (from domain_destroy()).
- * We can relax this a bit if a paused VCPU always commits its
- * architectural state to a software structure.
+ * vmx_vmcs_enter/exit critical regions.
*/
if ( v == current )
return;
@@ -135,7 +212,7 @@ void vmx_vmcs_exit(struct vcpu *v)
/* Don't confuse arch_vmx_do_resume (for @v or @current!) */
vmx_clear_vmcs(v);
- if ( hvm_guest(current) )
+ if ( is_hvm_vcpu(current) )
vmx_load_vmcs(current);
spin_unlock(&v->arch.hvm_vmx.vmcs_lock);
@@ -152,35 +229,7 @@ void vmx_free_host_vmcs(struct vmcs_struct *vmcs)
vmx_free_vmcs(vmcs);
}
-static inline int construct_vmcs_controls(struct arch_vmx_struct *arch_vmx)
-{
- int error = 0;
-
- error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
- MONITOR_PIN_BASED_EXEC_CONTROLS);
-
- error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
-
- error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
-
- error |= __vmwrite(IO_BITMAP_A, virt_to_maddr(arch_vmx->io_bitmap_a));
- error |= __vmwrite(IO_BITMAP_B, virt_to_maddr(arch_vmx->io_bitmap_b));
-
-#ifdef CONFIG_X86_PAE
- /* On PAE bitmaps may in future be above 4GB. Write high words. */
- error |= __vmwrite(IO_BITMAP_A_HIGH,
- (paddr_t)virt_to_maddr(arch_vmx->io_bitmap_a) >> 32);
- error |= __vmwrite(IO_BITMAP_B_HIGH,
- (paddr_t)virt_to_maddr(arch_vmx->io_bitmap_b) >> 32);
-#endif
-
- return error;
-}
-
-#define GUEST_LAUNCH_DS 0x08
-#define GUEST_LAUNCH_CS 0x10
#define GUEST_SEGMENT_LIMIT 0xffffffff
-#define HOST_SEGMENT_LIMIT 0xffffffff
struct host_execution_env {
/* selectors */
@@ -208,7 +257,7 @@ struct host_execution_env {
static void vmx_set_host_env(struct vcpu *v)
{
- unsigned int tr, cpu, error = 0;
+ unsigned int tr, cpu;
struct host_execution_env host_env;
struct Xgt_desc_struct desc;
@@ -216,128 +265,97 @@ static void vmx_set_host_env(struct vcpu *v)
__asm__ __volatile__ ("sidt (%0) \n" :: "a"(&desc) : "memory");
host_env.idtr_limit = desc.size;
host_env.idtr_base = desc.address;
- error |= __vmwrite(HOST_IDTR_BASE, host_env.idtr_base);
+ __vmwrite(HOST_IDTR_BASE, host_env.idtr_base);
__asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&desc) : "memory");
host_env.gdtr_limit = desc.size;
host_env.gdtr_base = desc.address;
- error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
+ __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
__asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory");
host_env.tr_selector = tr;
host_env.tr_limit = sizeof(struct tss_struct);
host_env.tr_base = (unsigned long) &init_tss[cpu];
- error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
- error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
- error |= __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
+ __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
+ __vmwrite(HOST_TR_BASE, host_env.tr_base);
+ __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
}
-static void vmx_do_launch(struct vcpu *v)
+static void construct_vmcs(struct vcpu *v)
{
-/* Update CR3, CR0, CR4, GDT, LDT, TR */
- unsigned int error = 0;
unsigned long cr0, cr4;
+ union vmcs_arbytes arbytes;
- if (v->vcpu_id == 0)
- hvm_setup_platform(v->domain);
-
- __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (cr0) : );
+ vmx_vmcs_enter(v);
- error |= __vmwrite(GUEST_CR0, cr0);
- cr0 &= ~X86_CR0_PG;
- error |= __vmwrite(CR0_READ_SHADOW, cr0);
- error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
- MONITOR_CPU_BASED_EXEC_CONTROLS);
- v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS;
+ /* VMCS controls. */
+ __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control);
+ __vmwrite(VM_EXIT_CONTROLS, vmx_vmexit_control);
+ __vmwrite(VM_ENTRY_CONTROLS, vmx_vmentry_control);
+ __vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmx_cpu_based_exec_control);
+ v->arch.hvm_vcpu.u.vmx.exec_control = vmx_cpu_based_exec_control;
- __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : );
+ /* Host data selectors. */
+ __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
+ __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
+ __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);
+#if defined(__i386__)
+ __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS);
+ __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS);
+ __vmwrite(HOST_FS_BASE, 0);
+ __vmwrite(HOST_GS_BASE, 0);
+#elif defined(__x86_64__)
+ {
+ unsigned long msr;
+ rdmsrl(MSR_FS_BASE, msr); __vmwrite(HOST_FS_BASE, msr);
+ rdmsrl(MSR_GS_BASE, msr); __vmwrite(HOST_GS_BASE, msr);
+ }
+#endif
- error |= __vmwrite(GUEST_CR4, cr4 & ~X86_CR4_PSE);
- cr4 &= ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
+ /* Host control registers. */
+ __vmwrite(HOST_CR0, read_cr0());
+ __vmwrite(HOST_CR4, read_cr4());
- error |= __vmwrite(CR4_READ_SHADOW, cr4);
+ /* Host CS:RIP. */
+ __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
+ __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler);
- hvm_stts(v);
+ /* MSR intercepts. */
+ __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
+ __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
+ __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
+ __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
+ __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
- if(hvm_apic_support(v->domain))
- vlapic_init(v);
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
- vmx_set_host_env(v);
- init_timer(&v->arch.hvm_vcpu.hlt_timer, hlt_timer_fn, v, v->processor);
+ __vmwrite(CR0_GUEST_HOST_MASK, ~0UL);
+ __vmwrite(CR4_GUEST_HOST_MASK, ~0UL);
- error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
- error |= __vmwrite(GUEST_LDTR_BASE, 0);
- error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
+ __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
+ __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
- error |= __vmwrite(GUEST_TR_BASE, 0);
- error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
+ __vmwrite(CR3_TARGET_COUNT, 0);
- shadow_update_paging_modes(v);
- printk("%s(): GUEST_CR3<=%08lx, HOST_CR3<=%08lx\n",
- __func__, v->arch.hvm_vcpu.hw_cr3, v->arch.cr3);
- __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
- __vmwrite(HOST_CR3, v->arch.cr3);
+ __vmwrite(GUEST_ACTIVITY_STATE, 0);
- v->arch.schedule_tail = arch_vmx_do_resume;
+ /* Guest segment bases. */
+ __vmwrite(GUEST_ES_BASE, 0);
+ __vmwrite(GUEST_SS_BASE, 0);
+ __vmwrite(GUEST_DS_BASE, 0);
+ __vmwrite(GUEST_FS_BASE, 0);
+ __vmwrite(GUEST_GS_BASE, 0);
+ __vmwrite(GUEST_CS_BASE, 0);
- /* init guest tsc to start from 0 */
- hvm_set_guest_time(v, 0);
-}
+ /* Guest segment limits. */
+ __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
-/*
- * Initially set the same environement as host.
- */
-static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs)
-{
- int error = 0;
- union vmcs_arbytes arbytes;
- unsigned long dr7;
- unsigned long eflags;
-
- /* MSR */
- error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
- error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
-
- error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
- error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
- error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
- /* interrupt */
- error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
- /* mask */
- error |= __vmwrite(CR0_GUEST_HOST_MASK, -1UL);
- error |= __vmwrite(CR4_GUEST_HOST_MASK, -1UL);
-
- error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
- error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
-
- /* TSC */
- error |= __vmwrite(CR3_TARGET_COUNT, 0);
-
- /* Guest Selectors */
- error |= __vmwrite(GUEST_ES_SELECTOR, GUEST_LAUNCH_DS);
- error |= __vmwrite(GUEST_SS_SELECTOR, GUEST_LAUNCH_DS);
- error |= __vmwrite(GUEST_DS_SELECTOR, GUEST_LAUNCH_DS);
- error |= __vmwrite(GUEST_FS_SELECTOR, GUEST_LAUNCH_DS);
- error |= __vmwrite(GUEST_GS_SELECTOR, GUEST_LAUNCH_DS);
- error |= __vmwrite(GUEST_CS_SELECTOR, GUEST_LAUNCH_CS);
-
- /* Guest segment bases */
- error |= __vmwrite(GUEST_ES_BASE, 0);
- error |= __vmwrite(GUEST_SS_BASE, 0);
- error |= __vmwrite(GUEST_DS_BASE, 0);
- error |= __vmwrite(GUEST_FS_BASE, 0);
- error |= __vmwrite(GUEST_GS_BASE, 0);
- error |= __vmwrite(GUEST_CS_BASE, 0);
-
- /* Guest segment Limits */
- error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
- error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
- error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
- error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
- error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
- error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
-
- /* Guest segment AR bytes */
+ /* Guest segment AR bytes. */
arbytes.bytes = 0;
arbytes.fields.seg_type = 0x3; /* type = 3 */
arbytes.fields.s = 1; /* code or data, i.e. not system */
@@ -346,146 +364,88 @@ static inline int construct_init_vmcs_guest(cpu_user_regs_t *regs)
arbytes.fields.default_ops_size = 1; /* 32-bit */
arbytes.fields.g = 1;
arbytes.fields.null_bit = 0; /* not null */
-
- error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
- error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
- error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
- error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
- error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
-
+ __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
arbytes.fields.seg_type = 0xb; /* type = 0xb */
- error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
- /* Guest GDT */
- error |= __vmwrite(GUEST_GDTR_BASE, 0);
- error |= __vmwrite(GUEST_GDTR_LIMIT, 0);
+ /* Guest GDT. */
+ __vmwrite(GUEST_GDTR_BASE, 0);
+ __vmwrite(GUEST_GDTR_LIMIT, 0);
- /* Guest IDT */
- error |= __vmwrite(GUEST_IDTR_BASE, 0);
- error |= __vmwrite(GUEST_IDTR_LIMIT, 0);
+ /* Guest IDT. */
+ __vmwrite(GUEST_IDTR_BASE, 0);
+ __vmwrite(GUEST_IDTR_LIMIT, 0);
- /* Guest LDT & TSS */
+ /* Guest LDT and TSS. */
arbytes.fields.s = 0; /* not code or data segement */
arbytes.fields.seg_type = 0x2; /* LTD */
arbytes.fields.default_ops_size = 0; /* 16-bit */
arbytes.fields.g = 0;
- error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
-
+ __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
- error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
- /* CR3 is set in vmx_final_setup_guest */
-
- error |= __vmwrite(GUEST_RSP, 0);
- error |= __vmwrite(GUEST_RIP, regs->eip);
+ __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
- /* Guest EFLAGS */
- eflags = regs->eflags & ~HVM_EFLAGS_RESERVED_0; /* clear 0s */
- eflags |= HVM_EFLAGS_RESERVED_1; /* set 1s */
- error |= __vmwrite(GUEST_RFLAGS, eflags);
-
- error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
- __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
- error |= __vmwrite(GUEST_DR7, dr7);
- error |= __vmwrite(VMCS_LINK_POINTER, ~0UL);
+ __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+ __vmwrite(GUEST_DR7, 0);
+ __vmwrite(VMCS_LINK_POINTER, ~0UL);
#if defined(__i386__)
- error |= __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL);
-#endif
-
- return error;
-}
-
-static inline int construct_vmcs_host(void)
-{
- int error = 0;
-#ifdef __x86_64__
- unsigned long fs_base;
- unsigned long gs_base;
+ __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL);
#endif
- unsigned long crn;
-
- /* Host Selectors */
- error |= __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);
- error |= __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
- error |= __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
-#if defined(__i386__)
- error |= __vmwrite(HOST_FS_SELECTOR, __HYPERVISOR_DS);
- error |= __vmwrite(HOST_GS_SELECTOR, __HYPERVISOR_DS);
- error |= __vmwrite(HOST_FS_BASE, 0);
- error |= __vmwrite(HOST_GS_BASE, 0);
-#else
- rdmsrl(MSR_FS_BASE, fs_base);
- rdmsrl(MSR_GS_BASE, gs_base);
- error |= __vmwrite(HOST_FS_BASE, fs_base);
- error |= __vmwrite(HOST_GS_BASE, gs_base);
-
-#endif
- error |= __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
-
- __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) : );
- error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
-
- /* CR3 is set in vmx_final_setup_hostos */
- __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) : );
- error |= __vmwrite(HOST_CR4, crn);
-
- error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
-#ifdef __x86_64__
- /* TBD: support cr8 for 64-bit guest */
- __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
+ __vmwrite(EXCEPTION_BITMAP, MONITOR_DEFAULT_EXCEPTION_BITMAP);
+
+ /* Guest CR0. */
+ cr0 = read_cr0();
+ v->arch.hvm_vmx.cpu_cr0 = cr0;
+ __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0);
+ v->arch.hvm_vmx.cpu_shadow_cr0 = cr0 & ~(X86_CR0_PG | X86_CR0_TS);
+ __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0);
+
+ /* Guest CR4. */
+ cr4 = read_cr4();
+ __vmwrite(GUEST_CR4, cr4 & ~X86_CR4_PSE);
+ v->arch.hvm_vmx.cpu_shadow_cr4 =
+ cr4 & ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
+ __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4);
+
+#ifdef __x86_64__
+ /* VLAPIC TPR optimisation. */
+ v->arch.hvm_vcpu.u.vmx.exec_control |= CPU_BASED_TPR_SHADOW;
+ v->arch.hvm_vcpu.u.vmx.exec_control &=
+ ~(CPU_BASED_CR8_STORE_EXITING | CPU_BASED_CR8_LOAD_EXITING);
+ __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vcpu.u.vmx.exec_control);
+ __vmwrite(VIRTUAL_APIC_PAGE_ADDR,
+ page_to_maddr(vcpu_vlapic(v)->regs_page));
__vmwrite(TPR_THRESHOLD, 0);
- __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
#endif
- return error;
-}
+ __vmwrite(GUEST_LDTR_SELECTOR, 0);
+ __vmwrite(GUEST_LDTR_BASE, 0);
+ __vmwrite(GUEST_LDTR_LIMIT, 0);
-/*
- * the working VMCS pointer has been set properly
- * just before entering this function.
- */
-static int construct_vmcs(struct vcpu *v,
- cpu_user_regs_t *regs)
-{
- struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
- int error;
-
- if ( (error = construct_vmcs_controls(arch_vmx)) ) {
- printk("construct_vmcs: construct_vmcs_controls failed.\n");
- return error;
- }
-
- /* host selectors */
- if ( (error = construct_vmcs_host()) ) {
- printk("construct_vmcs: construct_vmcs_host failed.\n");
- return error;
- }
+ __vmwrite(GUEST_TR_BASE, 0);
+ __vmwrite(GUEST_TR_LIMIT, 0xff);
- /* guest selectors */
- if ( (error = construct_init_vmcs_guest(regs)) ) {
- printk("construct_vmcs: construct_vmcs_guest failed.\n");
- return error;
- }
-
- if ( (error = __vmwrite(EXCEPTION_BITMAP,
- MONITOR_DEFAULT_EXCEPTION_BITMAP)) ) {
- printk("construct_vmcs: setting exception bitmap failed.\n");
- return error;
- }
-
- if ( regs->eflags & EF_TF )
- error = __vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
- else
- error = __vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
+ shadow_update_paging_modes(v);
+ __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
+ __vmwrite(HOST_CR3, v->arch.cr3);
- return error;
+ vmx_vmcs_exit(v);
}
int vmx_create_vmcs(struct vcpu *v)
{
if ( (v->arch.hvm_vmx.vmcs = vmx_alloc_vmcs()) == NULL )
return -ENOMEM;
+
__vmx_clear_vmcs(v);
+
+ construct_vmcs(v);
+
return 0;
}
@@ -498,30 +458,22 @@ void vmx_destroy_vmcs(struct vcpu *v)
vmx_clear_vmcs(v);
- free_xenheap_pages(arch_vmx->io_bitmap_a, IO_BITMAP_ORDER);
- free_xenheap_pages(arch_vmx->io_bitmap_b, IO_BITMAP_ORDER);
-
- arch_vmx->io_bitmap_a = NULL;
- arch_vmx->io_bitmap_b = NULL;
-
vmx_free_vmcs(arch_vmx->vmcs);
arch_vmx->vmcs = NULL;
}
void vm_launch_fail(unsigned long eflags)
{
- unsigned long error;
- __vmread(VM_INSTRUCTION_ERROR, &error);
+ unsigned long error = __vmread(VM_INSTRUCTION_ERROR);
printk("<vm_launch_fail> error code %lx\n", error);
- __hvm_bug(guest_cpu_user_regs());
+ domain_crash_synchronous();
}
void vm_resume_fail(unsigned long eflags)
{
- unsigned long error;
- __vmread(VM_INSTRUCTION_ERROR, &error);
+ unsigned long error = __vmread(VM_INSTRUCTION_ERROR);
printk("<vm_resume_fail> error code %lx\n", error);
- __hvm_bug(guest_cpu_user_regs());
+ domain_crash_synchronous();
}
void arch_vmx_do_resume(struct vcpu *v)
@@ -534,7 +486,7 @@ void arch_vmx_do_resume(struct vcpu *v)
{
vmx_clear_vmcs(v);
vmx_load_vmcs(v);
- vmx_migrate_timers(v);
+ hvm_migrate_timers(v);
vmx_set_host_env(v);
}
@@ -542,34 +494,13 @@ void arch_vmx_do_resume(struct vcpu *v)
reset_stack_and_jump(vmx_asm_do_vmentry);
}
-void arch_vmx_do_launch(struct vcpu *v)
-{
- cpu_user_regs_t *regs = &current->arch.guest_context.user_regs;
-
- vmx_load_vmcs(v);
-
- if ( construct_vmcs(v, regs) < 0 )
- {
- if ( v->vcpu_id == 0 ) {
- printk("Failed to construct VMCS for BSP.\n");
- } else {
- printk("Failed to construct VMCS for AP %d.\n", v->vcpu_id);
- }
- domain_crash_synchronous();
- }
-
- vmx_do_launch(v);
- reset_stack_and_jump(vmx_asm_do_vmentry);
-}
-
-
/* Dump a section of VMCS */
static void print_section(char *header, uint32_t start,
uint32_t end, int incr)
{
uint32_t addr, j;
unsigned long val;
- int code;
+ int code, rc;
char *fmt[4] = {"0x%04lx ", "0x%016lx ", "0x%08lx ", "0x%016lx "};
char *err[4] = {"------ ", "------------------ ",
"---------- ", "------------------ "};
@@ -585,7 +516,8 @@ static void print_section(char *header, uint32_t start,
if (!(j&3))
printk("\n\t\t0x%08x: ", addr);
- if (!__vmread(addr, &val))
+ val = __vmread_safe(addr, &rc);
+ if (rc == 0)
printk(fmt[code], val);
else
printk("%s", err[code]);
@@ -618,20 +550,14 @@ static void vmcs_dump(unsigned char ch)
struct vcpu *v;
printk("*********** VMCS Areas **************\n");
- for_each_domain(d) {
+ for_each_domain ( d )
+ {
+ if ( !is_hvm_domain(d) )
+ continue;
printk("\n>>> Domain %d <<<\n", d->domain_id);
- for_each_vcpu(d, v) {
-
- /*
- * Presumably, if a domain is not an HVM guest,
- * the very first CPU will not pass this test
- */
- if (!hvm_guest(v)) {
- printk("\t\tNot HVM guest\n");
- break;
- }
+ for_each_vcpu ( d, v )
+ {
printk("\tVCPU %d\n", v->vcpu_id);
-
vmx_vmcs_enter(v);
vmcs_dump_vcpu();
vmx_vmcs_exit(v);
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index a1e562e929..2925c06087 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -45,216 +45,99 @@
#include <public/hvm/ioreq.h>
#include <asm/hvm/vpic.h>
#include <asm/hvm/vlapic.h>
-
-extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
-
-static DEFINE_PER_CPU(unsigned long, trace_values[5]);
-#define TRACE_VMEXIT(index,value) this_cpu(trace_values)[index]=value
+#include <asm/x86_emulate.h>
static void vmx_ctxt_switch_from(struct vcpu *v);
static void vmx_ctxt_switch_to(struct vcpu *v);
-static int vmx_initialize_guest_resources(struct vcpu *v)
+static int vmx_vcpu_initialise(struct vcpu *v)
{
- struct domain *d = v->domain;
- struct vcpu *vc;
- void *io_bitmap_a, *io_bitmap_b;
int rc;
- v->arch.schedule_tail = arch_vmx_do_launch;
+ spin_lock_init(&v->arch.hvm_vmx.vmcs_lock);
+
+ v->arch.schedule_tail = arch_vmx_do_resume;
v->arch.ctxt_switch_from = vmx_ctxt_switch_from;
v->arch.ctxt_switch_to = vmx_ctxt_switch_to;
- if ( v->vcpu_id != 0 )
- return 1;
-
- if ( !shadow_mode_external(d) )
- {
- DPRINTK("Can't init HVM for dom %u vcpu %u: "
- "not in shadow external mode\n",
- d->domain_id, v->vcpu_id);
- domain_crash(d);
- }
-
- for_each_vcpu ( d, vc )
+ if ( (rc = vmx_create_vmcs(v)) != 0 )
{
- memset(&vc->arch.hvm_vmx, 0, sizeof(struct arch_vmx_struct));
-
- if ( (rc = vmx_create_vmcs(vc)) != 0 )
- {
- DPRINTK("Failed to create VMCS for vcpu %d: err=%d.\n",
- vc->vcpu_id, rc);
- return 0;
- }
-
- spin_lock_init(&vc->arch.hvm_vmx.vmcs_lock);
-
- if ( (io_bitmap_a = alloc_xenheap_pages(IO_BITMAP_ORDER)) == NULL )
- {
- DPRINTK("Failed to allocate io bitmap b for vcpu %d.\n",
- vc->vcpu_id);
- return 0;
- }
-
- if ( (io_bitmap_b = alloc_xenheap_pages(IO_BITMAP_ORDER)) == NULL )
- {
- DPRINTK("Failed to allocate io bitmap b for vcpu %d.\n",
- vc->vcpu_id);
- return 0;
- }
-
- memset(io_bitmap_a, 0xff, 0x1000);
- memset(io_bitmap_b, 0xff, 0x1000);
-
- /* don't bother debug port access */
- clear_bit(PC_DEBUG_PORT, io_bitmap_a);
-
- vc->arch.hvm_vmx.io_bitmap_a = io_bitmap_a;
- vc->arch.hvm_vmx.io_bitmap_b = io_bitmap_b;
-
+ dprintk(XENLOG_WARNING,
+ "Failed to create VMCS for vcpu %d: err=%d.\n",
+ v->vcpu_id, rc);
+ return rc;
}
- /*
- * Required to do this once per domain XXX todo: add a seperate function
- * to do these.
- */
- memset(&d->shared_info->evtchn_mask[0], 0xff,
- sizeof(d->shared_info->evtchn_mask));
-
- return 1;
+ return 0;
}
-static void vmx_relinquish_guest_resources(struct domain *d)
+static void vmx_vcpu_destroy(struct vcpu *v)
{
- struct vcpu *v;
-
- for_each_vcpu ( d, v )
- {
- vmx_destroy_vmcs(v);
- if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
- continue;
- kill_timer(&v->arch.hvm_vcpu.hlt_timer);
- if ( hvm_apic_support(v->domain) && (VLAPIC(v) != NULL) )
- {
- kill_timer(&VLAPIC(v)->vlapic_timer);
- unmap_domain_page_global(VLAPIC(v)->regs);
- free_domheap_page(VLAPIC(v)->regs_page);
- xfree(VLAPIC(v));
- }
- hvm_release_assist_channel(v);
- }
-
- kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
-
- if ( d->arch.hvm_domain.shared_page_va )
- unmap_domain_page_global(
- (void *)d->arch.hvm_domain.shared_page_va);
-
- if ( d->arch.hvm_domain.buffered_io_va )
- unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
+ vmx_destroy_vmcs(v);
}
#ifdef __x86_64__
-static DEFINE_PER_CPU(struct vmx_msr_state, percpu_msr);
+static DEFINE_PER_CPU(struct vmx_msr_state, host_msr_state);
-static u32 msr_data_index[VMX_MSR_COUNT] =
+static u32 msr_index[VMX_MSR_COUNT] =
{
MSR_LSTAR, MSR_STAR, MSR_CSTAR,
MSR_SYSCALL_MASK, MSR_EFER,
};
-static void vmx_save_segments(struct vcpu *v)
+static void vmx_save_host_msrs(void)
{
- rdmsrl(MSR_SHADOW_GS_BASE, v->arch.hvm_vmx.msr_content.shadow_gs);
-}
-
-/*
- * To avoid MSR save/restore at every VM exit/entry time, we restore
- * the x86_64 specific MSRs at domain switch time. Since those MSRs are
- * are not modified once set for generic domains, we don't save them,
- * but simply reset them to the values set at percpu_traps_init().
- */
-static void vmx_load_msrs(void)
-{
- struct vmx_msr_state *host_state = &this_cpu(percpu_msr);
- int i;
-
- while ( host_state->flags )
- {
- i = find_first_set_bit(host_state->flags);
- wrmsrl(msr_data_index[i], host_state->msr_items[i]);
- clear_bit(i, &host_state->flags);
- }
-}
-
-static void vmx_save_init_msrs(void)
-{
- struct vmx_msr_state *host_state = &this_cpu(percpu_msr);
+ struct vmx_msr_state *host_msr_state = &this_cpu(host_msr_state);
int i;
for ( i = 0; i < VMX_MSR_COUNT; i++ )
- rdmsrl(msr_data_index[i], host_state->msr_items[i]);
+ rdmsrl(msr_index[i], host_msr_state->msrs[i]);
}
-#define CASE_READ_MSR(address) \
- case MSR_ ## address: \
- msr_content = msr->msr_items[VMX_INDEX_MSR_ ## address]; \
- break
-
-#define CASE_WRITE_MSR(address) \
- case MSR_ ## address: \
- { \
- msr->msr_items[VMX_INDEX_MSR_ ## address] = msr_content; \
- if (!test_bit(VMX_INDEX_MSR_ ## address, &msr->flags)) { \
- set_bit(VMX_INDEX_MSR_ ## address, &msr->flags); \
- } \
- wrmsrl(MSR_ ## address, msr_content); \
- set_bit(VMX_INDEX_MSR_ ## address, &host_state->flags); \
- } \
- break
+#define CASE_READ_MSR(address) \
+ case MSR_ ## address: \
+ msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_ ## address]; \
+ break
+
+#define CASE_WRITE_MSR(address) \
+ case MSR_ ## address: \
+ guest_msr_state->msrs[VMX_INDEX_MSR_ ## address] = msr_content; \
+ if ( !test_bit(VMX_INDEX_MSR_ ## address, &guest_msr_state->flags) )\
+ set_bit(VMX_INDEX_MSR_ ## address, &guest_msr_state->flags); \
+ wrmsrl(MSR_ ## address, msr_content); \
+ set_bit(VMX_INDEX_MSR_ ## address, &host_msr_state->flags); \
+ break
#define IS_CANO_ADDRESS(add) 1
static inline int long_mode_do_msr_read(struct cpu_user_regs *regs)
{
u64 msr_content = 0;
struct vcpu *v = current;
- struct vmx_msr_state *msr = &v->arch.hvm_vmx.msr_content;
+ struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state;
- switch ( regs->ecx ) {
+ switch ( (u32)regs->ecx ) {
case MSR_EFER:
HVM_DBG_LOG(DBG_LEVEL_2, "EFER msr_content 0x%"PRIx64, msr_content);
- msr_content = msr->msr_items[VMX_INDEX_MSR_EFER];
-
- /* the following code may be not needed */
- if ( test_bit(VMX_CPU_STATE_LME_ENABLED, &v->arch.hvm_vmx.cpu_state) )
- msr_content |= EFER_LME;
- else
- msr_content &= ~EFER_LME;
-
- if ( VMX_LONG_GUEST(v) )
- msr_content |= EFER_LMA;
- else
- msr_content &= ~EFER_LMA;
+ msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_EFER];
break;
case MSR_FS_BASE:
- if ( !(VMX_LONG_GUEST(v)) )
- /* XXX should it be GP fault */
- domain_crash_synchronous();
+ if ( !(vmx_long_mode_enabled(v)) )
+ goto exit_and_crash;
- __vmread(GUEST_FS_BASE, &msr_content);
+ msr_content = __vmread(GUEST_FS_BASE);
break;
case MSR_GS_BASE:
- if ( !(VMX_LONG_GUEST(v)) )
- domain_crash_synchronous();
+ if ( !(vmx_long_mode_enabled(v)) )
+ goto exit_and_crash;
- __vmread(GUEST_GS_BASE, &msr_content);
+ msr_content = __vmread(GUEST_GS_BASE);
break;
case MSR_SHADOW_GS_BASE:
- msr_content = msr->shadow_gs;
+ msr_content = guest_msr_state->shadow_gs;
break;
CASE_READ_MSR(STAR);
@@ -268,56 +151,66 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs)
HVM_DBG_LOG(DBG_LEVEL_2, "msr_content: 0x%"PRIx64, msr_content);
- regs->eax = msr_content & 0xffffffff;
- regs->edx = msr_content >> 32;
+ regs->eax = (u32)(msr_content >> 0);
+ regs->edx = (u32)(msr_content >> 32);
return 1;
+
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Fatal error reading MSR %lx\n", (long)regs->ecx);
+ domain_crash(v->domain);
+ return 1; /* handled */
}
static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
{
- u64 msr_content = regs->eax | ((u64)regs->edx << 32);
+ u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
struct vcpu *v = current;
- struct vmx_msr_state *msr = &v->arch.hvm_vmx.msr_content;
- struct vmx_msr_state *host_state = &this_cpu(percpu_msr);
+ struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state;
+ struct vmx_msr_state *host_msr_state = &this_cpu(host_msr_state);
- HVM_DBG_LOG(DBG_LEVEL_1, "msr 0x%lx msr_content 0x%"PRIx64"\n",
- (unsigned long)regs->ecx, msr_content);
+ HVM_DBG_LOG(DBG_LEVEL_1, "msr 0x%x msr_content 0x%"PRIx64"\n",
+ (u32)regs->ecx, msr_content);
- switch ( regs->ecx ) {
+ switch ( (u32)regs->ecx ) {
case MSR_EFER:
/* offending reserved bit will cause #GP */
if ( msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE) )
{
- printk("trying to set reserved bit in EFER\n");
+ printk("Trying to set reserved bit in EFER: %"PRIx64"\n",
+ msr_content);
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
return 0;
}
- /* LME: 0 -> 1 */
- if ( msr_content & EFER_LME &&
- !test_bit(VMX_CPU_STATE_LME_ENABLED, &v->arch.hvm_vmx.cpu_state) )
+ if ( (msr_content & EFER_LME)
+ && !(guest_msr_state->msrs[VMX_INDEX_MSR_EFER] & EFER_LME) )
{
- if ( vmx_paging_enabled(v) ||
- !test_bit(VMX_CPU_STATE_PAE_ENABLED,
- &v->arch.hvm_vmx.cpu_state) )
+ if ( unlikely(vmx_paging_enabled(v)) )
{
- printk("trying to set LME bit when "
- "in paging mode or PAE bit is not set\n");
+ printk("Trying to set EFER.LME with paging enabled\n");
+ vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
+ return 0;
+ }
+ }
+ else if ( !(msr_content & EFER_LME)
+ && (guest_msr_state->msrs[VMX_INDEX_MSR_EFER] & EFER_LME) )
+ {
+ if ( unlikely(vmx_paging_enabled(v)) )
+ {
+ printk("Trying to clear EFER.LME with paging enabled\n");
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
return 0;
}
-
- set_bit(VMX_CPU_STATE_LME_ENABLED, &v->arch.hvm_vmx.cpu_state);
}
- msr->msr_items[VMX_INDEX_MSR_EFER] = msr_content;
+ guest_msr_state->msrs[VMX_INDEX_MSR_EFER] = msr_content;
break;
case MSR_FS_BASE:
case MSR_GS_BASE:
- if ( !(VMX_LONG_GUEST(v)) )
- domain_crash_synchronous();
+ if ( !vmx_long_mode_enabled(v) )
+ goto exit_and_crash;
if ( !IS_CANO_ADDRESS(msr_content) )
{
@@ -334,10 +227,10 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
break;
case MSR_SHADOW_GS_BASE:
- if ( !(VMX_LONG_GUEST(v)) )
- domain_crash_synchronous();
+ if ( !(vmx_long_mode_enabled(v)) )
+ goto exit_and_crash;
- v->arch.hvm_vmx.msr_content.shadow_gs = msr_content;
+ v->arch.hvm_vmx.msr_state.shadow_gs = msr_content;
wrmsrl(MSR_SHADOW_GS_BASE, msr_content);
break;
@@ -351,42 +244,64 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
}
return 1;
+
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Fatal error writing MSR %lx\n", (long)regs->ecx);
+ domain_crash(v->domain);
+ return 1; /* handled */
}
-static void vmx_restore_msrs(struct vcpu *v)
+/*
+ * To avoid MSR save/restore at every VM exit/entry time, we restore
+ * the x86_64 specific MSRs at domain switch time. Since these MSRs
+ * are not modified once set for para domains, we don't save them,
+ * but simply reset them to values set in percpu_traps_init().
+ */
+static void vmx_restore_host_msrs(void)
{
- int i = 0;
- struct vmx_msr_state *guest_state;
- struct vmx_msr_state *host_state;
- unsigned long guest_flags ;
+ struct vmx_msr_state *host_msr_state = &this_cpu(host_msr_state);
+ int i;
+
+ while ( host_msr_state->flags )
+ {
+ i = find_first_set_bit(host_msr_state->flags);
+ wrmsrl(msr_index[i], host_msr_state->msrs[i]);
+ clear_bit(i, &host_msr_state->flags);
+ }
+}
+
+static void vmx_restore_guest_msrs(struct vcpu *v)
+{
+ struct vmx_msr_state *guest_msr_state, *host_msr_state;
+ unsigned long guest_flags;
+ int i;
+
+ guest_msr_state = &v->arch.hvm_vmx.msr_state;
+ host_msr_state = &this_cpu(host_msr_state);
- guest_state = &v->arch.hvm_vmx.msr_content;;
- host_state = &this_cpu(percpu_msr);
+ wrmsrl(MSR_SHADOW_GS_BASE, guest_msr_state->shadow_gs);
- wrmsrl(MSR_SHADOW_GS_BASE, guest_state->shadow_gs);
- guest_flags = guest_state->flags;
- if (!guest_flags)
+ guest_flags = guest_msr_state->flags;
+ if ( !guest_flags )
return;
- while (guest_flags){
+ while ( guest_flags ) {
i = find_first_set_bit(guest_flags);
HVM_DBG_LOG(DBG_LEVEL_2,
- "restore guest's index %d msr %lx with %lx\n",
- i, (unsigned long)msr_data_index[i],
- (unsigned long)guest_state->msr_items[i]);
- set_bit(i, &host_state->flags);
- wrmsrl(msr_data_index[i], guest_state->msr_items[i]);
+ "restore guest's index %d msr %x with value %lx",
+ i, msr_index[i], guest_msr_state->msrs[i]);
+ set_bit(i, &host_msr_state->flags);
+ wrmsrl(msr_index[i], guest_msr_state->msrs[i]);
clear_bit(i, &guest_flags);
}
}
#else /* __i386__ */
-#define vmx_save_segments(v) ((void)0)
-#define vmx_load_msrs() ((void)0)
-#define vmx_restore_msrs(v) ((void)0)
-#define vmx_save_init_msrs() ((void)0)
+#define vmx_save_host_msrs() ((void)0)
+#define vmx_restore_host_msrs() ((void)0)
+#define vmx_restore_guest_msrs(v) ((void)0)
static inline int long_mode_do_msr_read(struct cpu_user_regs *regs)
{
@@ -400,27 +315,27 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs)
#endif /* __i386__ */
-#define loaddebug(_v,_reg) \
+#define loaddebug(_v,_reg) \
__asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
-#define savedebug(_v,_reg) \
+#define savedebug(_v,_reg) \
__asm__ __volatile__ ("mov %%db" #_reg ",%0" : : "r" ((_v)->debugreg[_reg]))
static inline void vmx_save_dr(struct vcpu *v)
{
- if ( v->arch.hvm_vcpu.flag_dr_dirty )
- {
- savedebug(&v->arch.guest_context, 0);
- savedebug(&v->arch.guest_context, 1);
- savedebug(&v->arch.guest_context, 2);
- savedebug(&v->arch.guest_context, 3);
- savedebug(&v->arch.guest_context, 6);
-
- v->arch.hvm_vcpu.flag_dr_dirty = 0;
-
- v->arch.hvm_vcpu.u.vmx.exec_control |= CPU_BASED_MOV_DR_EXITING;
- __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
- v->arch.hvm_vcpu.u.vmx.exec_control);
- }
+ if ( !v->arch.hvm_vcpu.flag_dr_dirty )
+ return;
+
+ /* Clear the DR dirty flag and re-enable intercepts for DR accesses. */
+ v->arch.hvm_vcpu.flag_dr_dirty = 0;
+ v->arch.hvm_vcpu.u.vmx.exec_control |= CPU_BASED_MOV_DR_EXITING;
+ __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vcpu.u.vmx.exec_control);
+
+ savedebug(&v->arch.guest_context, 0);
+ savedebug(&v->arch.guest_context, 1);
+ savedebug(&v->arch.guest_context, 2);
+ savedebug(&v->arch.guest_context, 3);
+ savedebug(&v->arch.guest_context, 6);
+ v->arch.guest_context.debugreg[7] = __vmread(GUEST_DR7);
}
static inline void __restore_debug_registers(struct vcpu *v)
@@ -431,7 +346,7 @@ static inline void __restore_debug_registers(struct vcpu *v)
loaddebug(&v->arch.guest_context, 3);
/* No 4 and 5 */
loaddebug(&v->arch.guest_context, 6);
- /* DR7 is loaded from the vmcs. */
+ /* DR7 is loaded from the VMCS. */
}
/*
@@ -439,64 +354,41 @@ static inline void __restore_debug_registers(struct vcpu *v)
* need to be restored if their value is going to affect execution -- i.e.,
* if one of the breakpoints is enabled. So mask out all bits that don't
* enable some breakpoint functionality.
- *
- * This is in part necessary because bit 10 of DR7 is hardwired to 1, so a
- * simple if( guest_dr7 ) will always return true. As long as we're masking,
- * we might as well do it right.
*/
#define DR7_ACTIVE_MASK 0xff
static inline void vmx_restore_dr(struct vcpu *v)
{
- unsigned long guest_dr7;
-
- __vmread(GUEST_DR7, &guest_dr7);
-
- /* Assumes guest does not have DR access at time of context switch. */
- if ( unlikely(guest_dr7 & DR7_ACTIVE_MASK) )
+ /* NB. __vmread() is not usable here, so we cannot read from the VMCS. */
+ if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
__restore_debug_registers(v);
}
-static void vmx_freeze_time(struct vcpu *v)
-{
- struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
-
- if ( pt->enabled && pt->first_injected && !v->arch.hvm_vcpu.guest_time ) {
- v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
- stop_timer(&(pt->timer));
- }
-}
-
static void vmx_ctxt_switch_from(struct vcpu *v)
{
- vmx_freeze_time(v);
- vmx_save_segments(v);
- vmx_load_msrs();
+ hvm_freeze_time(v);
+
+ /* NB. MSR_SHADOW_GS_BASE may be changed by swapgs instrucion in guest,
+ * so we must save it. */
+ rdmsrl(MSR_SHADOW_GS_BASE, v->arch.hvm_vmx.msr_state.shadow_gs);
+
+ vmx_restore_host_msrs();
vmx_save_dr(v);
}
static void vmx_ctxt_switch_to(struct vcpu *v)
{
- vmx_restore_msrs(v);
+ vmx_restore_guest_msrs(v);
vmx_restore_dr(v);
}
static void stop_vmx(void)
{
- if (read_cr4() & X86_CR4_VMXE)
- __vmxoff();
-}
-
-void vmx_migrate_timers(struct vcpu *v)
-{
- struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+ if ( !(read_cr4() & X86_CR4_VMXE) )
+ return;
- if ( pt->enabled ) {
- migrate_timer(&pt->timer, v->processor);
- migrate_timer(&v->arch.hvm_vcpu.hlt_timer, v->processor);
- }
- if ( hvm_apic_support(v->domain) && VLAPIC(v))
- migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor);
+ __vmxoff();
+ clear_in_cr4(X86_CR4_VMXE);
}
static void vmx_store_cpu_guest_regs(
@@ -506,23 +398,23 @@ static void vmx_store_cpu_guest_regs(
if ( regs != NULL )
{
- __vmread(GUEST_RFLAGS, &regs->eflags);
- __vmread(GUEST_SS_SELECTOR, &regs->ss);
- __vmread(GUEST_CS_SELECTOR, &regs->cs);
- __vmread(GUEST_DS_SELECTOR, &regs->ds);
- __vmread(GUEST_ES_SELECTOR, &regs->es);
- __vmread(GUEST_GS_SELECTOR, &regs->gs);
- __vmread(GUEST_FS_SELECTOR, &regs->fs);
- __vmread(GUEST_RIP, &regs->eip);
- __vmread(GUEST_RSP, &regs->esp);
+ regs->eflags = __vmread(GUEST_RFLAGS);
+ regs->ss = __vmread(GUEST_SS_SELECTOR);
+ regs->cs = __vmread(GUEST_CS_SELECTOR);
+ regs->ds = __vmread(GUEST_DS_SELECTOR);
+ regs->es = __vmread(GUEST_ES_SELECTOR);
+ regs->gs = __vmread(GUEST_GS_SELECTOR);
+ regs->fs = __vmread(GUEST_FS_SELECTOR);
+ regs->eip = __vmread(GUEST_RIP);
+ regs->esp = __vmread(GUEST_RSP);
}
if ( crs != NULL )
{
- __vmread(CR0_READ_SHADOW, &crs[0]);
+ crs[0] = v->arch.hvm_vmx.cpu_shadow_cr0;
crs[2] = v->arch.hvm_vmx.cpu_cr2;
- __vmread(GUEST_CR3, &crs[3]);
- __vmread(CR4_READ_SHADOW, &crs[4]);
+ crs[3] = __vmread(GUEST_CR3);
+ crs[4] = v->arch.hvm_vmx.cpu_shadow_cr4;
}
vmx_vmcs_exit(v);
@@ -542,29 +434,26 @@ static void vmx_store_cpu_guest_regs(
*/
static void fixup_vm86_seg_bases(struct cpu_user_regs *regs)
{
- int err = 0;
unsigned long base;
- err |= __vmread(GUEST_ES_BASE, &base);
+ base = __vmread(GUEST_ES_BASE);
if (regs->es << 4 != base)
- err |= __vmwrite(GUEST_ES_BASE, regs->es << 4);
- err |= __vmread(GUEST_CS_BASE, &base);
+ __vmwrite(GUEST_ES_BASE, regs->es << 4);
+ base = __vmread(GUEST_CS_BASE);
if (regs->cs << 4 != base)
- err |= __vmwrite(GUEST_CS_BASE, regs->cs << 4);
- err |= __vmread(GUEST_SS_BASE, &base);
+ __vmwrite(GUEST_CS_BASE, regs->cs << 4);
+ base = __vmread(GUEST_SS_BASE);
if (regs->ss << 4 != base)
- err |= __vmwrite(GUEST_SS_BASE, regs->ss << 4);
- err |= __vmread(GUEST_DS_BASE, &base);
+ __vmwrite(GUEST_SS_BASE, regs->ss << 4);
+ base = __vmread(GUEST_DS_BASE);
if (regs->ds << 4 != base)
- err |= __vmwrite(GUEST_DS_BASE, regs->ds << 4);
- err |= __vmread(GUEST_FS_BASE, &base);
+ __vmwrite(GUEST_DS_BASE, regs->ds << 4);
+ base = __vmread(GUEST_FS_BASE);
if (regs->fs << 4 != base)
- err |= __vmwrite(GUEST_FS_BASE, regs->fs << 4);
- err |= __vmread(GUEST_GS_BASE, &base);
+ __vmwrite(GUEST_FS_BASE, regs->fs << 4);
+ base = __vmread(GUEST_GS_BASE);
if (regs->gs << 4 != base)
- err |= __vmwrite(GUEST_GS_BASE, regs->gs << 4);
-
- BUG_ON(err);
+ __vmwrite(GUEST_GS_BASE, regs->gs << 4);
}
static void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs)
@@ -579,7 +468,8 @@ static void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs)
__vmwrite(GUEST_RSP, regs->esp);
- __vmwrite(GUEST_RFLAGS, regs->eflags);
+ /* NB. Bit 1 of RFLAGS must be set for VMENTRY to succeed. */
+ __vmwrite(GUEST_RFLAGS, regs->eflags | 2UL);
if (regs->eflags & EF_TF)
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_DB);
else
@@ -593,15 +483,6 @@ static void vmx_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *regs)
vmx_vmcs_exit(v);
}
-static int vmx_instruction_length(struct vcpu *v)
-{
- unsigned long inst_len;
-
- if (__vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len))
- return 0;
- return inst_len;
-}
-
static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num)
{
switch ( num )
@@ -620,13 +501,40 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num)
return 0; /* dummy */
}
+static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ unsigned long base = 0;
+ int long_mode = 0;
+ ASSERT(v == current);
+
+#ifdef __x86_64__
+ if ( vmx_long_mode_enabled(v) &&
+ (__vmread(GUEST_CS_AR_BYTES) & (1u<<13)) )
+ long_mode = 1;
+#endif
+
+ switch ( seg )
+ {
+ case seg_cs: if ( !long_mode ) base = __vmread(GUEST_CS_BASE); break;
+ case seg_ds: if ( !long_mode ) base = __vmread(GUEST_DS_BASE); break;
+ case seg_es: if ( !long_mode ) base = __vmread(GUEST_ES_BASE); break;
+ case seg_fs: base = __vmread(GUEST_FS_BASE); break;
+ case seg_gs: base = __vmread(GUEST_GS_BASE); break;
+ case seg_ss: if ( !long_mode ) base = __vmread(GUEST_SS_BASE); break;
+ case seg_tr: base = __vmread(GUEST_TR_BASE); break;
+ case seg_gdtr: base = __vmread(GUEST_GDTR_BASE); break;
+ case seg_idtr: base = __vmread(GUEST_IDTR_BASE); break;
+ case seg_ldtr: base = __vmread(GUEST_LDTR_BASE); break;
+ default: BUG(); break;
+ }
+
+ return base;
+}
/* Make sure that xen intercepts any FP accesses from current */
static void vmx_stts(struct vcpu *v)
{
- unsigned long cr0;
-
/* VMX depends on operating on the current vcpu */
ASSERT(v == current);
@@ -636,77 +544,35 @@ static void vmx_stts(struct vcpu *v)
* then this is not necessary: no FPU activity can occur until the guest
* clears CR0.TS, and we will initialise the FPU when that happens.
*/
- __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
- if ( !(cr0 & X86_CR0_TS) )
+ if ( !(v->arch.hvm_vmx.cpu_shadow_cr0 & X86_CR0_TS) )
{
- __vmread_vcpu(v, GUEST_CR0, &cr0);
- __vmwrite(GUEST_CR0, cr0 | X86_CR0_TS);
+ v->arch.hvm_vmx.cpu_cr0 |= X86_CR0_TS;
+ __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0);
__vm_set_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
}
}
-
static void vmx_set_tsc_offset(struct vcpu *v, u64 offset)
{
- /* VMX depends on operating on the current vcpu */
- ASSERT(v == current);
-
+ vmx_vmcs_enter(v);
__vmwrite(TSC_OFFSET, offset);
#if defined (__i386__)
__vmwrite(TSC_OFFSET_HIGH, offset >> 32);
#endif
+ vmx_vmcs_exit(v);
}
-
-
-/* SMP VMX guest support */
-static void vmx_init_ap_context(struct vcpu_guest_context *ctxt,
- int vcpuid, int trampoline_vector)
+static void vmx_init_ap_context(
+ struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector)
{
- int i;
-
memset(ctxt, 0, sizeof(*ctxt));
-
- /*
- * Initial register values:
- */
ctxt->user_regs.eip = VMXASSIST_BASE;
ctxt->user_regs.edx = vcpuid;
ctxt->user_regs.ebx = trampoline_vector;
-
- ctxt->flags = VGCF_HVM_GUEST;
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS;
- }
-
- /* No callback handlers. */
-#if defined(__i386__)
- ctxt->event_callback_cs = FLAT_KERNEL_CS;
- ctxt->failsafe_callback_cs = FLAT_KERNEL_CS;
-#endif
}
void do_nmi(struct cpu_user_regs *);
-static int check_vmx_controls(u32 ctrls, u32 msr)
-{
- u32 vmx_msr_low, vmx_msr_high;
-
- rdmsr(msr, vmx_msr_low, vmx_msr_high);
- if ( (ctrls < vmx_msr_low) || (ctrls > vmx_msr_high) )
- {
- printk("Insufficient VMX capability 0x%x, "
- "msr=0x%x,low=0x%8x,high=0x%x\n",
- ctrls, msr, vmx_msr_low, vmx_msr_high);
- return 0;
- }
- return 1;
-}
-
static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
{
char *p;
@@ -729,6 +595,41 @@ static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
}
+static int vmx_realmode(struct vcpu *v)
+{
+ unsigned long rflags;
+
+ ASSERT(v == current);
+
+ rflags = __vmread(GUEST_RFLAGS);
+ return rflags & X86_EFLAGS_VM;
+}
+
+static int vmx_guest_x86_mode(struct vcpu *v)
+{
+ unsigned long cs_ar_bytes;
+
+ ASSERT(v == current);
+
+ cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES);
+
+ if ( vmx_long_mode_enabled(v) )
+ return ((cs_ar_bytes & (1u<<13)) ?
+ X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+
+ if ( vmx_realmode(v) )
+ return X86EMUL_MODE_REAL;
+
+ return ((cs_ar_bytes & (1u<<14)) ?
+ X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
+}
+
+static int vmx_pae_enabled(struct vcpu *v)
+{
+ unsigned long cr4 = v->arch.hvm_vmx.cpu_shadow_cr4;
+ return (vmx_paging_enabled(v) && (cr4 & X86_CR4_PAE));
+}
+
/* Setup HVM interfaces */
static void vmx_setup_hvm_funcs(void)
{
@@ -737,18 +638,18 @@ static void vmx_setup_hvm_funcs(void)
hvm_funcs.disable = stop_vmx;
- hvm_funcs.initialize_guest_resources = vmx_initialize_guest_resources;
- hvm_funcs.relinquish_guest_resources = vmx_relinquish_guest_resources;
+ hvm_funcs.vcpu_initialise = vmx_vcpu_initialise;
+ hvm_funcs.vcpu_destroy = vmx_vcpu_destroy;
hvm_funcs.store_cpu_guest_regs = vmx_store_cpu_guest_regs;
hvm_funcs.load_cpu_guest_regs = vmx_load_cpu_guest_regs;
- hvm_funcs.realmode = vmx_realmode;
hvm_funcs.paging_enabled = vmx_paging_enabled;
hvm_funcs.long_mode_enabled = vmx_long_mode_enabled;
+ hvm_funcs.pae_enabled = vmx_pae_enabled;
hvm_funcs.guest_x86_mode = vmx_guest_x86_mode;
- hvm_funcs.instruction_length = vmx_instruction_length;
hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg;
+ hvm_funcs.get_segment_base = vmx_get_segment_base;
hvm_funcs.update_host_cr3 = vmx_update_host_cr3;
@@ -770,7 +671,7 @@ int start_vmx(void)
*/
boot_cpu_data.x86_capability[4] = cpuid_ecx(1);
- if (!(test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability)))
+ if ( !test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability) )
return 0;
rdmsr(IA32_FEATURE_CONTROL_MSR, eax, edx);
@@ -790,34 +691,23 @@ int start_vmx(void)
IA32_FEATURE_CONTROL_MSR_ENABLE_VMXON, 0);
}
- if ( !check_vmx_controls(MONITOR_PIN_BASED_EXEC_CONTROLS,
- MSR_IA32_VMX_PINBASED_CTLS_MSR) )
- return 0;
- if ( !check_vmx_controls(MONITOR_CPU_BASED_EXEC_CONTROLS,
- MSR_IA32_VMX_PROCBASED_CTLS_MSR) )
- return 0;
- if ( !check_vmx_controls(MONITOR_VM_EXIT_CONTROLS,
- MSR_IA32_VMX_EXIT_CTLS_MSR) )
- return 0;
- if ( !check_vmx_controls(MONITOR_VM_ENTRY_CONTROLS,
- MSR_IA32_VMX_ENTRY_CTLS_MSR) )
- return 0;
-
set_in_cr4(X86_CR4_VMXE);
vmx_init_vmcs_config();
-
- if(!smp_processor_id())
+
+ if ( smp_processor_id() == 0 )
setup_vmcs_dump();
if ( (vmcs = vmx_alloc_host_vmcs()) == NULL )
{
+ clear_in_cr4(X86_CR4_VMXE);
printk("Failed to allocate host VMCS\n");
return 0;
}
if ( __vmxon(virt_to_maddr(vmcs)) )
{
+ clear_in_cr4(X86_CR4_VMXE);
printk("VMXON failed\n");
vmx_free_host_vmcs(vmcs);
return 0;
@@ -825,7 +715,7 @@ int start_vmx(void)
printk("VMXON is done\n");
- vmx_save_init_msrs();
+ vmx_save_host_msrs();
vmx_setup_hvm_funcs();
@@ -836,17 +726,21 @@ int start_vmx(void)
/*
* Not all cases receive valid value in the VM-exit instruction length field.
+ * Callers must know what they're doing!
*/
-#define __get_instruction_length(len) \
- __vmread(VM_EXIT_INSTRUCTION_LEN, &(len)); \
- if ((len) < 1 || (len) > 15) \
- __hvm_bug(&regs);
+static int __get_instruction_length(void)
+{
+ int len;
+ len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe: callers audited */
+ BUG_ON((len < 1) || (len > 15));
+ return len;
+}
static void inline __update_guest_eip(unsigned long inst_len)
{
unsigned long current_eip;
- __vmread(GUEST_RIP, &current_eip);
+ current_eip = __vmread(GUEST_RIP);
__vmwrite(GUEST_RIP, current_eip + inst_len);
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
}
@@ -859,8 +753,8 @@ static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
{
unsigned long eip, cs;
- __vmread(GUEST_CS_BASE, &cs);
- __vmread(GUEST_RIP, &eip);
+ cs = __vmread(GUEST_CS_BASE);
+ eip = __vmread(GUEST_RIP);
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"vmx_do_page_fault = 0x%lx, cs_base=%lx, "
"eip = %lx, error_code = %lx\n",
@@ -870,11 +764,11 @@ static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
result = shadow_fault(va, regs);
- TRACE_VMEXIT (2,result);
+ TRACE_VMEXIT(2, result);
#if 0
if ( !result )
{
- __vmread(GUEST_RIP, &eip);
+ eip = __vmread(GUEST_RIP);
printk("vmx pgfault to guest va=%lx eip=%lx\n", va, eip);
}
#endif
@@ -884,24 +778,21 @@ static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
static void vmx_do_no_device_fault(void)
{
- unsigned long cr0;
struct vcpu *v = current;
setup_fpu(current);
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
/* Disable TS in guest CR0 unless the guest wants the exception too. */
- __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
- if ( !(cr0 & X86_CR0_TS) )
+ if ( !(v->arch.hvm_vmx.cpu_shadow_cr0 & X86_CR0_TS) )
{
- __vmread_vcpu(v, GUEST_CR0, &cr0);
- cr0 &= ~X86_CR0_TS;
- __vmwrite(GUEST_CR0, cr0);
+ v->arch.hvm_vmx.cpu_cr0 &= ~X86_CR0_TS;
+ __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0);
}
}
#define bitmaskof(idx) (1U << ((idx)&31))
-static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
+static void vmx_do_cpuid(struct cpu_user_regs *regs)
{
unsigned int input = (unsigned int)regs->eax;
unsigned int count = (unsigned int)regs->ecx;
@@ -909,7 +800,7 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
unsigned long eip;
struct vcpu *v = current;
- __vmread(GUEST_RIP, &eip);
+ eip = __vmread(GUEST_RIP);
HVM_DBG_LOG(DBG_LEVEL_3, "(eax) 0x%08lx, (ebx) 0x%08lx, "
"(ecx) 0x%08lx, (edx) 0x%08lx, (esi) 0x%08lx, (edi) 0x%08lx",
@@ -920,7 +811,35 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
if ( input == CPUID_LEAF_0x4 )
{
cpuid_count(input, count, &eax, &ebx, &ecx, &edx);
- eax &= NUM_CORES_RESET_MASK;
+ eax &= NUM_CORES_RESET_MASK;
+ }
+ else if ( input == 0x40000003 )
+ {
+ /*
+ * NB. Unsupported interface for private use of VMXASSIST only.
+ * Note that this leaf lives at <max-hypervisor-leaf> + 1.
+ */
+ u64 value = ((u64)regs->edx << 32) | (u32)regs->ecx;
+ unsigned long mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT);
+ char *p;
+
+ gdprintk(XENLOG_INFO, "Input address is 0x%"PRIx64".\n", value);
+
+ /* 8-byte aligned valid pseudophys address from vmxassist, please. */
+ if ( (value & 7) || (mfn == INVALID_MFN) ||
+ !v->arch.hvm_vmx.vmxassist_enabled )
+ {
+ domain_crash(v->domain);
+ return;
+ }
+
+ p = map_domain_page(mfn);
+ value = *((uint64_t *)(p + (value & (PAGE_SIZE - 1))));
+ unmap_domain_page(p);
+
+ gdprintk(XENLOG_INFO, "Output value is 0x%"PRIx64".\n", value);
+ ecx = (u32)(value >> 0);
+ edx = (u32)(value >> 32);
}
else if ( !cpuid_hypervisor_leaves(input, &eax, &ebx, &ecx, &edx) )
{
@@ -928,25 +847,19 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
if ( input == CPUID_LEAF_0x1 )
{
- /* mask off reserved bits */
+ /* Mask off reserved bits. */
ecx &= ~VMX_VCPU_CPUID_L1_ECX_RESERVED;
- if ( !hvm_apic_support(v->domain) ||
- !vlapic_global_enabled((VLAPIC(v))) )
- {
- /* Since the apic is disabled, avoid any
- confusion about SMP cpus being available */
-
+ if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
clear_bit(X86_FEATURE_APIC, &edx);
- }
-
+
#if CONFIG_PAGING_LEVELS >= 3
if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
#endif
clear_bit(X86_FEATURE_PAE, &edx);
clear_bit(X86_FEATURE_PSE36, &edx);
- ebx &= NUM_THREADS_RESET_MASK;
+ ebx &= NUM_THREADS_RESET_MASK;
/* Unsupportable for virtualised CPUs. */
ecx &= ~(bitmaskof(X86_FEATURE_VMXE) |
@@ -959,7 +872,7 @@ static void vmx_vmexit_do_cpuid(struct cpu_user_regs *regs)
bitmaskof(X86_FEATURE_ACPI) |
bitmaskof(X86_FEATURE_ACC) );
}
- else if ( ( input == CPUID_LEAF_0x6 )
+ else if ( ( input == CPUID_LEAF_0x6 )
|| ( input == CPUID_LEAF_0x9 )
|| ( input == CPUID_LEAF_0xA ))
{
@@ -1026,14 +939,14 @@ static void vmx_dr_access(unsigned long exit_qualification,
* Invalidate the TLB for va. Invalidate the shadow page corresponding
* the address va.
*/
-static void vmx_vmexit_do_invlpg(unsigned long va)
+static void vmx_do_invlpg(unsigned long va)
{
unsigned long eip;
struct vcpu *v = current;
- __vmread(GUEST_RIP, &eip);
+ eip = __vmread(GUEST_RIP);
- HVM_DBG_LOG(DBG_LEVEL_VMMU, "vmx_vmexit_do_invlpg: eip=%lx, va=%lx",
+ HVM_DBG_LOG(DBG_LEVEL_VMMU, "eip=%lx, va=%lx",
eip, va);
/*
@@ -1044,67 +957,119 @@ static void vmx_vmexit_do_invlpg(unsigned long va)
}
-static int check_for_null_selector(unsigned long eip)
+static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len,
+ enum segment seg, unsigned long *base,
+ u32 *limit, u32 *ar_bytes)
{
- unsigned char inst[MAX_INST_LEN];
- unsigned long sel;
- int i, inst_len;
- int inst_copy_from_guest(unsigned char *, unsigned long, int);
-
- __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
- memset(inst, 0, MAX_INST_LEN);
- if (inst_copy_from_guest(inst, eip, inst_len) != inst_len) {
- printf("check_for_null_selector: get guest instruction failed\n");
- domain_crash_synchronous();
- }
+ enum vmcs_field ar_field, base_field, limit_field;
- for (i = 0; i < inst_len; i++) {
- switch (inst[i]) {
- case 0xf3: /* REPZ */
- case 0xf2: /* REPNZ */
- case 0xf0: /* LOCK */
- case 0x66: /* data32 */
- case 0x67: /* addr32 */
- continue;
- case 0x2e: /* CS */
- __vmread(GUEST_CS_SELECTOR, &sel);
- break;
- case 0x36: /* SS */
- __vmread(GUEST_SS_SELECTOR, &sel);
- break;
- case 0x26: /* ES */
- __vmread(GUEST_ES_SELECTOR, &sel);
- break;
- case 0x64: /* FS */
- __vmread(GUEST_FS_SELECTOR, &sel);
- break;
- case 0x65: /* GS */
- __vmread(GUEST_GS_SELECTOR, &sel);
- break;
- case 0x3e: /* DS */
- /* FALLTHROUGH */
- default:
- /* DS is the default */
- __vmread(GUEST_DS_SELECTOR, &sel);
+ *base = 0;
+ *limit = 0;
+ if ( seg != seg_es )
+ {
+ unsigned char inst[MAX_INST_LEN];
+ int i;
+ extern int inst_copy_from_guest(unsigned char *, unsigned long, int);
+
+ if ( !long_mode )
+ eip += __vmread(GUEST_CS_BASE);
+ memset(inst, 0, MAX_INST_LEN);
+ if ( inst_copy_from_guest(inst, eip, inst_len) != inst_len )
+ {
+ gdprintk(XENLOG_ERR, "Get guest instruction failed\n");
+ domain_crash(current->domain);
+ return 0;
+ }
+
+ for ( i = 0; i < inst_len; i++ )
+ {
+ switch ( inst[i] )
+ {
+ case 0xf3: /* REPZ */
+ case 0xf2: /* REPNZ */
+ case 0xf0: /* LOCK */
+ case 0x66: /* data32 */
+ case 0x67: /* addr32 */
+#ifdef __x86_64__
+ case 0x40 ... 0x4f: /* REX */
+#endif
+ continue;
+ case 0x2e: /* CS */
+ seg = seg_cs;
+ continue;
+ case 0x36: /* SS */
+ seg = seg_ss;
+ continue;
+ case 0x26: /* ES */
+ seg = seg_es;
+ continue;
+ case 0x64: /* FS */
+ seg = seg_fs;
+ continue;
+ case 0x65: /* GS */
+ seg = seg_gs;
+ continue;
+ case 0x3e: /* DS */
+ seg = seg_ds;
+ continue;
+ }
}
- return sel == 0 ? 1 : 0;
}
- return 0;
-}
+ switch ( seg )
+ {
+ case seg_cs:
+ ar_field = GUEST_CS_AR_BYTES;
+ base_field = GUEST_CS_BASE;
+ limit_field = GUEST_CS_LIMIT;
+ break;
+ case seg_ds:
+ ar_field = GUEST_DS_AR_BYTES;
+ base_field = GUEST_DS_BASE;
+ limit_field = GUEST_DS_LIMIT;
+ break;
+ case seg_es:
+ ar_field = GUEST_ES_AR_BYTES;
+ base_field = GUEST_ES_BASE;
+ limit_field = GUEST_ES_LIMIT;
+ break;
+ case seg_fs:
+ ar_field = GUEST_FS_AR_BYTES;
+ base_field = GUEST_FS_BASE;
+ limit_field = GUEST_FS_LIMIT;
+ break;
+ case seg_gs:
+ ar_field = GUEST_FS_AR_BYTES;
+ base_field = GUEST_FS_BASE;
+ limit_field = GUEST_FS_LIMIT;
+ break;
+ case seg_ss:
+ ar_field = GUEST_GS_AR_BYTES;
+ base_field = GUEST_GS_BASE;
+ limit_field = GUEST_GS_LIMIT;
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ if ( !long_mode || seg == seg_fs || seg == seg_gs )
+ {
+ *base = __vmread(base_field);
+ *limit = __vmread(limit_field);
+ }
+ *ar_bytes = __vmread(ar_field);
-extern void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
- unsigned long count, int size, long value,
- int dir, int pvalid);
+ return !(*ar_bytes & 0x10000);
+}
static void vmx_io_instruction(unsigned long exit_qualification,
unsigned long inst_len)
{
struct cpu_user_regs *regs;
struct hvm_io_op *pio_opp;
- unsigned long eip, cs, eflags;
- unsigned long port, size, dir;
- int vm86;
+ unsigned int port, size;
+ int dir, df, vm86;
pio_opp = &current->arch.hvm_vcpu.io_op;
pio_opp->instr = INSTR_PIO;
@@ -1116,180 +1081,262 @@ static void vmx_io_instruction(unsigned long exit_qualification,
memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES);
hvm_store_cpu_guest_regs(current, regs, NULL);
- eip = regs->eip;
- cs = regs->cs;
- eflags = regs->eflags;
+ vm86 = regs->eflags & X86_EFLAGS_VM ? 1 : 0;
+ df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
- vm86 = eflags & X86_EFLAGS_VM ? 1 : 0;
-
- HVM_DBG_LOG(DBG_LEVEL_IO,
- "vmx_io_instruction: vm86 %d, eip=%lx:%lx, "
+ HVM_DBG_LOG(DBG_LEVEL_IO, "vm86 %d, eip=%x:%lx, "
"exit_qualification = %lx",
- vm86, cs, eip, exit_qualification);
+ vm86, regs->cs, (unsigned long)regs->eip, exit_qualification);
- if (test_bit(6, &exit_qualification))
+ if ( test_bit(6, &exit_qualification) )
port = (exit_qualification >> 16) & 0xFFFF;
else
port = regs->edx & 0xffff;
+
TRACE_VMEXIT(1, port);
+
size = (exit_qualification & 7) + 1;
dir = test_bit(3, &exit_qualification); /* direction */
- if (test_bit(4, &exit_qualification)) { /* string instruction */
- unsigned long addr, count = 1;
- int sign = regs->eflags & EF_DF ? -1 : 1;
+ if ( test_bit(4, &exit_qualification) ) { /* string instruction */
+ unsigned long addr, count = 1, base;
+ u32 ar_bytes, limit;
+ int sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;
+ int long_mode = 0;
- __vmread(GUEST_LINEAR_ADDRESS, &addr);
+ ar_bytes = __vmread(GUEST_CS_AR_BYTES);
+#ifdef __x86_64__
+ if ( vmx_long_mode_enabled(current) && (ar_bytes & (1u<<13)) )
+ long_mode = 1;
+#endif
+ addr = __vmread(GUEST_LINEAR_ADDRESS);
+
+ if ( test_bit(5, &exit_qualification) ) { /* "rep" prefix */
+ pio_opp->flags |= REPZ;
+ count = regs->ecx;
+ if ( !long_mode && (vm86 || !(ar_bytes & (1u<<14))) )
+ count &= 0xFFFF;
+ }
/*
* In protected mode, guest linear address is invalid if the
* selector is null.
*/
- if (!vm86 && check_for_null_selector(eip))
- addr = dir == IOREQ_WRITE ? regs->esi : regs->edi;
+ if ( !vmx_check_descriptor(long_mode, regs->eip, inst_len,
+ dir == IOREQ_WRITE ? seg_ds : seg_es,
+ &base, &limit, &ar_bytes) ) {
+ if ( !long_mode ) {
+ vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
+ return;
+ }
+ addr = dir == IOREQ_WRITE ? base + regs->esi : regs->edi;
+ }
- if (test_bit(5, &exit_qualification)) { /* "rep" prefix */
- pio_opp->flags |= REPZ;
- count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
+ if ( !long_mode ) {
+ unsigned long ea = addr - base;
+
+ /* Segment must be readable for outs and writeable for ins. */
+ if ( dir == IOREQ_WRITE ? (ar_bytes & 0xa) == 0x8
+ : (ar_bytes & 0xa) != 0x2 ) {
+ vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
+ return;
+ }
+
+ /* Offset must be within limits. */
+ ASSERT(ea == (u32)ea);
+ if ( (u32)(ea + size - 1) < (u32)ea ||
+ (ar_bytes & 0xc) != 0x4 ? ea + size - 1 > limit
+ : ea <= limit )
+ {
+ vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
+ return;
+ }
+
+ /* Check the limit for repeated instructions, as above we checked
+ only the first instance. Truncate the count if a limit violation
+ would occur. Note that the checking is not necessary for page
+ granular segments as transfers crossing page boundaries will be
+ broken up anyway. */
+ if ( !(ar_bytes & (1u<<15)) && count > 1 )
+ {
+ if ( (ar_bytes & 0xc) != 0x4 )
+ {
+ /* expand-up */
+ if ( !df )
+ {
+ if ( ea + count * size - 1 < ea ||
+ ea + count * size - 1 > limit )
+ count = (limit + 1UL - ea) / size;
+ }
+ else
+ {
+ if ( count - 1 > ea / size )
+ count = ea / size + 1;
+ }
+ }
+ else
+ {
+ /* expand-down */
+ if ( !df )
+ {
+ if ( count - 1 > -(s32)ea / size )
+ count = -(s32)ea / size + 1UL;
+ }
+ else
+ {
+ if ( ea < (count - 1) * size ||
+ ea - (count - 1) * size <= limit )
+ count = (ea - limit - 1) / size + 1;
+ }
+ }
+ ASSERT(count);
+ }
}
/*
* Handle string pio instructions that cross pages or that
* are unaligned. See the comments in hvm_domain.c/handle_mmio()
*/
- if ((addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK)) {
+ if ( (addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK) ) {
unsigned long value = 0;
pio_opp->flags |= OVERLAP;
- if (dir == IOREQ_WRITE)
- hvm_copy(&value, addr, size, HVM_COPY_IN);
- send_pio_req(regs, port, 1, size, value, dir, 0);
+
+ if ( dir == IOREQ_WRITE ) /* OUTS */
+ {
+ if ( hvm_paging_enabled(current) )
+ (void)hvm_copy_from_guest_virt(&value, addr, size);
+ else
+ (void)hvm_copy_from_guest_phys(&value, addr, size);
+ } else
+ pio_opp->addr = addr;
+
+ if ( count == 1 )
+ regs->eip += inst_len;
+
+ send_pio_req(port, 1, size, value, dir, df, 0);
} else {
- if ((addr & PAGE_MASK) != ((addr + count * size - 1) & PAGE_MASK)) {
- if (sign > 0)
+ unsigned long last_addr = sign > 0 ? addr + count * size - 1
+ : addr - (count - 1) * size;
+
+ if ( (addr & PAGE_MASK) != (last_addr & PAGE_MASK) )
+ {
+ if ( sign > 0 )
count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
else
- count = (addr & ~PAGE_MASK) / size;
+ count = (addr & ~PAGE_MASK) / size + 1;
} else
regs->eip += inst_len;
- send_pio_req(regs, port, count, size, addr, dir, 1);
+ send_pio_req(port, count, size, addr, dir, df, 1);
}
} else {
- if (port == 0xe9 && dir == IOREQ_WRITE && size == 1)
+ if ( port == 0xe9 && dir == IOREQ_WRITE && size == 1 )
hvm_print_line(current, regs->eax); /* guest debug output */
+ if ( dir == IOREQ_WRITE )
+ TRACE_VMEXIT(2, regs->eax);
+
regs->eip += inst_len;
- send_pio_req(regs, port, 1, size, regs->eax, dir, 0);
+ send_pio_req(port, 1, size, regs->eax, dir, df, 0);
}
}
-int
-vmx_world_save(struct vcpu *v, struct vmx_assist_context *c)
+static void vmx_world_save(struct vcpu *v, struct vmx_assist_context *c)
{
- unsigned long inst_len;
- int error = 0;
+ /* NB. Skip transition instruction. */
+ c->eip = __vmread(GUEST_RIP);
+ c->eip += __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */
- error |= __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
- error |= __vmread(GUEST_RIP, &c->eip);
- c->eip += inst_len; /* skip transition instruction */
- error |= __vmread(GUEST_RSP, &c->esp);
- error |= __vmread(GUEST_RFLAGS, &c->eflags);
+ c->esp = __vmread(GUEST_RSP);
+ c->eflags = __vmread(GUEST_RFLAGS);
- error |= __vmread(CR0_READ_SHADOW, &c->cr0);
+ c->cr0 = v->arch.hvm_vmx.cpu_shadow_cr0;
c->cr3 = v->arch.hvm_vmx.cpu_cr3;
- error |= __vmread(CR4_READ_SHADOW, &c->cr4);
-
- error |= __vmread(GUEST_IDTR_LIMIT, &c->idtr_limit);
- error |= __vmread(GUEST_IDTR_BASE, &c->idtr_base);
-
- error |= __vmread(GUEST_GDTR_LIMIT, &c->gdtr_limit);
- error |= __vmread(GUEST_GDTR_BASE, &c->gdtr_base);
-
- error |= __vmread(GUEST_CS_SELECTOR, &c->cs_sel);
- error |= __vmread(GUEST_CS_LIMIT, &c->cs_limit);
- error |= __vmread(GUEST_CS_BASE, &c->cs_base);
- error |= __vmread(GUEST_CS_AR_BYTES, &c->cs_arbytes.bytes);
-
- error |= __vmread(GUEST_DS_SELECTOR, &c->ds_sel);
- error |= __vmread(GUEST_DS_LIMIT, &c->ds_limit);
- error |= __vmread(GUEST_DS_BASE, &c->ds_base);
- error |= __vmread(GUEST_DS_AR_BYTES, &c->ds_arbytes.bytes);
-
- error |= __vmread(GUEST_ES_SELECTOR, &c->es_sel);
- error |= __vmread(GUEST_ES_LIMIT, &c->es_limit);
- error |= __vmread(GUEST_ES_BASE, &c->es_base);
- error |= __vmread(GUEST_ES_AR_BYTES, &c->es_arbytes.bytes);
-
- error |= __vmread(GUEST_SS_SELECTOR, &c->ss_sel);
- error |= __vmread(GUEST_SS_LIMIT, &c->ss_limit);
- error |= __vmread(GUEST_SS_BASE, &c->ss_base);
- error |= __vmread(GUEST_SS_AR_BYTES, &c->ss_arbytes.bytes);
-
- error |= __vmread(GUEST_FS_SELECTOR, &c->fs_sel);
- error |= __vmread(GUEST_FS_LIMIT, &c->fs_limit);
- error |= __vmread(GUEST_FS_BASE, &c->fs_base);
- error |= __vmread(GUEST_FS_AR_BYTES, &c->fs_arbytes.bytes);
-
- error |= __vmread(GUEST_GS_SELECTOR, &c->gs_sel);
- error |= __vmread(GUEST_GS_LIMIT, &c->gs_limit);
- error |= __vmread(GUEST_GS_BASE, &c->gs_base);
- error |= __vmread(GUEST_GS_AR_BYTES, &c->gs_arbytes.bytes);
-
- error |= __vmread(GUEST_TR_SELECTOR, &c->tr_sel);
- error |= __vmread(GUEST_TR_LIMIT, &c->tr_limit);
- error |= __vmread(GUEST_TR_BASE, &c->tr_base);
- error |= __vmread(GUEST_TR_AR_BYTES, &c->tr_arbytes.bytes);
-
- error |= __vmread(GUEST_LDTR_SELECTOR, &c->ldtr_sel);
- error |= __vmread(GUEST_LDTR_LIMIT, &c->ldtr_limit);
- error |= __vmread(GUEST_LDTR_BASE, &c->ldtr_base);
- error |= __vmread(GUEST_LDTR_AR_BYTES, &c->ldtr_arbytes.bytes);
-
- return !error;
+ c->cr4 = v->arch.hvm_vmx.cpu_shadow_cr4;
+
+ c->idtr_limit = __vmread(GUEST_IDTR_LIMIT);
+ c->idtr_base = __vmread(GUEST_IDTR_BASE);
+
+ c->gdtr_limit = __vmread(GUEST_GDTR_LIMIT);
+ c->gdtr_base = __vmread(GUEST_GDTR_BASE);
+
+ c->cs_sel = __vmread(GUEST_CS_SELECTOR);
+ c->cs_limit = __vmread(GUEST_CS_LIMIT);
+ c->cs_base = __vmread(GUEST_CS_BASE);
+ c->cs_arbytes.bytes = __vmread(GUEST_CS_AR_BYTES);
+
+ c->ds_sel = __vmread(GUEST_DS_SELECTOR);
+ c->ds_limit = __vmread(GUEST_DS_LIMIT);
+ c->ds_base = __vmread(GUEST_DS_BASE);
+ c->ds_arbytes.bytes = __vmread(GUEST_DS_AR_BYTES);
+
+ c->es_sel = __vmread(GUEST_ES_SELECTOR);
+ c->es_limit = __vmread(GUEST_ES_LIMIT);
+ c->es_base = __vmread(GUEST_ES_BASE);
+ c->es_arbytes.bytes = __vmread(GUEST_ES_AR_BYTES);
+
+ c->ss_sel = __vmread(GUEST_SS_SELECTOR);
+ c->ss_limit = __vmread(GUEST_SS_LIMIT);
+ c->ss_base = __vmread(GUEST_SS_BASE);
+ c->ss_arbytes.bytes = __vmread(GUEST_SS_AR_BYTES);
+
+ c->fs_sel = __vmread(GUEST_FS_SELECTOR);
+ c->fs_limit = __vmread(GUEST_FS_LIMIT);
+ c->fs_base = __vmread(GUEST_FS_BASE);
+ c->fs_arbytes.bytes = __vmread(GUEST_FS_AR_BYTES);
+
+ c->gs_sel = __vmread(GUEST_GS_SELECTOR);
+ c->gs_limit = __vmread(GUEST_GS_LIMIT);
+ c->gs_base = __vmread(GUEST_GS_BASE);
+ c->gs_arbytes.bytes = __vmread(GUEST_GS_AR_BYTES);
+
+ c->tr_sel = __vmread(GUEST_TR_SELECTOR);
+ c->tr_limit = __vmread(GUEST_TR_LIMIT);
+ c->tr_base = __vmread(GUEST_TR_BASE);
+ c->tr_arbytes.bytes = __vmread(GUEST_TR_AR_BYTES);
+
+ c->ldtr_sel = __vmread(GUEST_LDTR_SELECTOR);
+ c->ldtr_limit = __vmread(GUEST_LDTR_LIMIT);
+ c->ldtr_base = __vmread(GUEST_LDTR_BASE);
+ c->ldtr_arbytes.bytes = __vmread(GUEST_LDTR_AR_BYTES);
}
-int
-vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c)
+static int vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c)
{
- unsigned long mfn, old_cr4, old_base_mfn;
- int error = 0;
+ unsigned long mfn, old_base_mfn;
- error |= __vmwrite(GUEST_RIP, c->eip);
- error |= __vmwrite(GUEST_RSP, c->esp);
- error |= __vmwrite(GUEST_RFLAGS, c->eflags);
+ __vmwrite(GUEST_RIP, c->eip);
+ __vmwrite(GUEST_RSP, c->esp);
+ __vmwrite(GUEST_RFLAGS, c->eflags);
- error |= __vmwrite(CR0_READ_SHADOW, c->cr0);
+ v->arch.hvm_vmx.cpu_shadow_cr0 = c->cr0;
+ __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0);
- if (!vmx_paging_enabled(v))
+ if ( !vmx_paging_enabled(v) )
goto skip_cr3;
- if (c->cr3 == v->arch.hvm_vmx.cpu_cr3) {
+ if ( c->cr3 == v->arch.hvm_vmx.cpu_cr3 )
+ {
/*
* This is simple TLB flush, implying the guest has
* removed some translation or changed page attributes.
* We simply invalidate the shadow.
*/
mfn = get_mfn_from_gpfn(c->cr3 >> PAGE_SHIFT);
- if (mfn != pagetable_get_pfn(v->arch.guest_table)) {
- printk("Invalid CR3 value=%x", c->cr3);
- domain_crash_synchronous();
- return 0;
- }
- } else {
+ if ( mfn != pagetable_get_pfn(v->arch.guest_table) )
+ goto bad_cr3;
+ }
+ else
+ {
/*
* If different, make a shadow. Check if the PDBR is valid
* first.
*/
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %x", c->cr3);
- if ((c->cr3 >> PAGE_SHIFT) > v->domain->max_pages) {
- printk("Invalid CR3 value=%x", c->cr3);
- domain_crash_synchronous();
- return 0;
- }
mfn = get_mfn_from_gpfn(c->cr3 >> PAGE_SHIFT);
- if(!get_page(mfn_to_page(mfn), v->domain))
- return 0;
+ if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
+ goto bad_cr3;
old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
v->arch.guest_table = pagetable_from_pfn(mfn);
if (old_base_mfn)
@@ -1301,78 +1348,81 @@ vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c)
}
skip_cr3:
-
- shadow_update_paging_modes(v);
- if (!vmx_paging_enabled(v))
+ if ( !vmx_paging_enabled(v) )
HVM_DBG_LOG(DBG_LEVEL_VMMU, "switching to vmxassist. use phys table");
else
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %x", c->cr3);
+
+ __vmwrite(GUEST_CR4, (c->cr4 | VMX_CR4_HOST_MASK));
+ v->arch.hvm_vmx.cpu_shadow_cr4 = c->cr4;
+ __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4);
+
+ __vmwrite(GUEST_IDTR_LIMIT, c->idtr_limit);
+ __vmwrite(GUEST_IDTR_BASE, c->idtr_base);
+
+ __vmwrite(GUEST_GDTR_LIMIT, c->gdtr_limit);
+ __vmwrite(GUEST_GDTR_BASE, c->gdtr_base);
+
+ __vmwrite(GUEST_CS_SELECTOR, c->cs_sel);
+ __vmwrite(GUEST_CS_LIMIT, c->cs_limit);
+ __vmwrite(GUEST_CS_BASE, c->cs_base);
+ __vmwrite(GUEST_CS_AR_BYTES, c->cs_arbytes.bytes);
+
+ __vmwrite(GUEST_DS_SELECTOR, c->ds_sel);
+ __vmwrite(GUEST_DS_LIMIT, c->ds_limit);
+ __vmwrite(GUEST_DS_BASE, c->ds_base);
+ __vmwrite(GUEST_DS_AR_BYTES, c->ds_arbytes.bytes);
+
+ __vmwrite(GUEST_ES_SELECTOR, c->es_sel);
+ __vmwrite(GUEST_ES_LIMIT, c->es_limit);
+ __vmwrite(GUEST_ES_BASE, c->es_base);
+ __vmwrite(GUEST_ES_AR_BYTES, c->es_arbytes.bytes);
+
+ __vmwrite(GUEST_SS_SELECTOR, c->ss_sel);
+ __vmwrite(GUEST_SS_LIMIT, c->ss_limit);
+ __vmwrite(GUEST_SS_BASE, c->ss_base);
+ __vmwrite(GUEST_SS_AR_BYTES, c->ss_arbytes.bytes);
+
+ __vmwrite(GUEST_FS_SELECTOR, c->fs_sel);
+ __vmwrite(GUEST_FS_LIMIT, c->fs_limit);
+ __vmwrite(GUEST_FS_BASE, c->fs_base);
+ __vmwrite(GUEST_FS_AR_BYTES, c->fs_arbytes.bytes);
+
+ __vmwrite(GUEST_GS_SELECTOR, c->gs_sel);
+ __vmwrite(GUEST_GS_LIMIT, c->gs_limit);
+ __vmwrite(GUEST_GS_BASE, c->gs_base);
+ __vmwrite(GUEST_GS_AR_BYTES, c->gs_arbytes.bytes);
+
+ __vmwrite(GUEST_TR_SELECTOR, c->tr_sel);
+ __vmwrite(GUEST_TR_LIMIT, c->tr_limit);
+ __vmwrite(GUEST_TR_BASE, c->tr_base);
+ __vmwrite(GUEST_TR_AR_BYTES, c->tr_arbytes.bytes);
+
+ __vmwrite(GUEST_LDTR_SELECTOR, c->ldtr_sel);
+ __vmwrite(GUEST_LDTR_LIMIT, c->ldtr_limit);
+ __vmwrite(GUEST_LDTR_BASE, c->ldtr_base);
+ __vmwrite(GUEST_LDTR_AR_BYTES, c->ldtr_arbytes.bytes);
+
+ shadow_update_paging_modes(v);
__vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
+ return 0;
- error |= __vmread(CR4_READ_SHADOW, &old_cr4);
- error |= __vmwrite(GUEST_CR4, (c->cr4 | VMX_CR4_HOST_MASK));
- error |= __vmwrite(CR4_READ_SHADOW, c->cr4);
-
- error |= __vmwrite(GUEST_IDTR_LIMIT, c->idtr_limit);
- error |= __vmwrite(GUEST_IDTR_BASE, c->idtr_base);
-
- error |= __vmwrite(GUEST_GDTR_LIMIT, c->gdtr_limit);
- error |= __vmwrite(GUEST_GDTR_BASE, c->gdtr_base);
-
- error |= __vmwrite(GUEST_CS_SELECTOR, c->cs_sel);
- error |= __vmwrite(GUEST_CS_LIMIT, c->cs_limit);
- error |= __vmwrite(GUEST_CS_BASE, c->cs_base);
- error |= __vmwrite(GUEST_CS_AR_BYTES, c->cs_arbytes.bytes);
-
- error |= __vmwrite(GUEST_DS_SELECTOR, c->ds_sel);
- error |= __vmwrite(GUEST_DS_LIMIT, c->ds_limit);
- error |= __vmwrite(GUEST_DS_BASE, c->ds_base);
- error |= __vmwrite(GUEST_DS_AR_BYTES, c->ds_arbytes.bytes);
-
- error |= __vmwrite(GUEST_ES_SELECTOR, c->es_sel);
- error |= __vmwrite(GUEST_ES_LIMIT, c->es_limit);
- error |= __vmwrite(GUEST_ES_BASE, c->es_base);
- error |= __vmwrite(GUEST_ES_AR_BYTES, c->es_arbytes.bytes);
-
- error |= __vmwrite(GUEST_SS_SELECTOR, c->ss_sel);
- error |= __vmwrite(GUEST_SS_LIMIT, c->ss_limit);
- error |= __vmwrite(GUEST_SS_BASE, c->ss_base);
- error |= __vmwrite(GUEST_SS_AR_BYTES, c->ss_arbytes.bytes);
-
- error |= __vmwrite(GUEST_FS_SELECTOR, c->fs_sel);
- error |= __vmwrite(GUEST_FS_LIMIT, c->fs_limit);
- error |= __vmwrite(GUEST_FS_BASE, c->fs_base);
- error |= __vmwrite(GUEST_FS_AR_BYTES, c->fs_arbytes.bytes);
-
- error |= __vmwrite(GUEST_GS_SELECTOR, c->gs_sel);
- error |= __vmwrite(GUEST_GS_LIMIT, c->gs_limit);
- error |= __vmwrite(GUEST_GS_BASE, c->gs_base);
- error |= __vmwrite(GUEST_GS_AR_BYTES, c->gs_arbytes.bytes);
-
- error |= __vmwrite(GUEST_TR_SELECTOR, c->tr_sel);
- error |= __vmwrite(GUEST_TR_LIMIT, c->tr_limit);
- error |= __vmwrite(GUEST_TR_BASE, c->tr_base);
- error |= __vmwrite(GUEST_TR_AR_BYTES, c->tr_arbytes.bytes);
-
- error |= __vmwrite(GUEST_LDTR_SELECTOR, c->ldtr_sel);
- error |= __vmwrite(GUEST_LDTR_LIMIT, c->ldtr_limit);
- error |= __vmwrite(GUEST_LDTR_BASE, c->ldtr_base);
- error |= __vmwrite(GUEST_LDTR_AR_BYTES, c->ldtr_arbytes.bytes);
-
- return !error;
+ bad_cr3:
+ gdprintk(XENLOG_ERR, "Invalid CR3 value=%x", c->cr3);
+ return -EINVAL;
}
enum { VMX_ASSIST_INVOKE = 0, VMX_ASSIST_RESTORE };
-int
-vmx_assist(struct vcpu *v, int mode)
+static int vmx_assist(struct vcpu *v, int mode)
{
struct vmx_assist_context c;
u32 magic;
u32 cp;
/* make sure vmxassist exists (this is not an error) */
- if (!hvm_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&magic, VMXASSIST_MAGIC_OFFSET,
+ sizeof(magic)))
return 0;
if (magic != VMXASSIST_MAGIC)
return 0;
@@ -1386,48 +1436,49 @@ vmx_assist(struct vcpu *v, int mode)
*/
case VMX_ASSIST_INVOKE:
/* save the old context */
- if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp)))
goto error;
if (cp != 0) {
- if (!vmx_world_save(v, &c))
- goto error;
- if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_OUT))
+ vmx_world_save(v, &c);
+ if (hvm_copy_to_guest_phys(cp, &c, sizeof(c)))
goto error;
}
/* restore the new context, this should activate vmxassist */
- if (!hvm_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp)))
goto error;
if (cp != 0) {
- if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&c, cp, sizeof(c)))
goto error;
- if (!vmx_world_restore(v, &c))
+ if ( vmx_world_restore(v, &c) != 0 )
goto error;
+ v->arch.hvm_vmx.vmxassist_enabled = 1;
return 1;
}
break;
/*
- * Restore the VMXASSIST_OLD_CONTEXT that was saved by VMX_ASSIST_INVOKE
- * above.
+ * Restore the VMXASSIST_OLD_CONTEXT that was saved by
+ * VMX_ASSIST_INVOKE above.
*/
case VMX_ASSIST_RESTORE:
/* save the old context */
- if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp)))
goto error;
if (cp != 0) {
- if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN))
+ if (hvm_copy_from_guest_phys(&c, cp, sizeof(c)))
goto error;
- if (!vmx_world_restore(v, &c))
+ if ( vmx_world_restore(v, &c) != 0 )
goto error;
+ v->arch.hvm_vmx.vmxassist_enabled = 0;
return 1;
}
break;
}
error:
- printf("Failed to transfer to vmxassist\n");
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "Failed to transfer to vmxassist\n");
+ domain_crash(v->domain);
return 0;
}
@@ -1444,7 +1495,7 @@ static int vmx_set_cr0(unsigned long value)
/*
* CR0: We don't want to lose PE and PG.
*/
- __vmread_vcpu(v, CR0_READ_SHADOW, &old_cr0);
+ old_cr0 = v->arch.hvm_vmx.cpu_shadow_cr0;
paging_enabled = (old_cr0 & X86_CR0_PE) && (old_cr0 & X86_CR0_PG);
/* TS cleared? Then initialise FPU now. */
@@ -1454,8 +1505,12 @@ static int vmx_set_cr0(unsigned long value)
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
}
- __vmwrite(GUEST_CR0, value | X86_CR0_PE | X86_CR0_PG | X86_CR0_NE);
- __vmwrite(CR0_READ_SHADOW, value);
+ v->arch.hvm_vmx.cpu_cr0 = (value | X86_CR0_PE | X86_CR0_PG
+ | X86_CR0_NE | X86_CR0_WP);
+ __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0);
+
+ v->arch.hvm_vmx.cpu_shadow_cr0 = value;
+ __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0);
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx\n", value);
@@ -1465,36 +1520,33 @@ static int vmx_set_cr0(unsigned long value)
* Trying to enable guest paging.
* The guest CR3 must be pointing to the guest physical.
*/
- if ( !VALID_MFN(mfn = get_mfn_from_gpfn(
- v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)) ||
- !get_page(mfn_to_page(mfn), v->domain) )
+ mfn = get_mfn_from_gpfn(v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
{
- printk("Invalid CR3 value = %lx (mfn=%lx)\n",
- v->arch.hvm_vmx.cpu_cr3, mfn);
- domain_crash_synchronous(); /* need to take a clean path */
+ gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n",
+ v->arch.hvm_vmx.cpu_cr3, mfn);
+ domain_crash(v->domain);
+ return 0;
}
#if defined(__x86_64__)
- if ( test_bit(VMX_CPU_STATE_LME_ENABLED,
- &v->arch.hvm_vmx.cpu_state) &&
- !test_bit(VMX_CPU_STATE_PAE_ENABLED,
- &v->arch.hvm_vmx.cpu_state) )
+ if ( vmx_lme_is_set(v) )
{
- HVM_DBG_LOG(DBG_LEVEL_1, "Enable paging before PAE enabled\n");
- vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
- }
-
- if ( test_bit(VMX_CPU_STATE_LME_ENABLED,
- &v->arch.hvm_vmx.cpu_state) )
- {
- /* Here the PAE is should be opened */
- HVM_DBG_LOG(DBG_LEVEL_1, "Enable long mode\n");
- set_bit(VMX_CPU_STATE_LMA_ENABLED,
- &v->arch.hvm_vmx.cpu_state);
-
- __vmread(VM_ENTRY_CONTROLS, &vm_entry_value);
- vm_entry_value |= VM_ENTRY_CONTROLS_IA32E_MODE;
- __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
+ if ( !(v->arch.hvm_vmx.cpu_shadow_cr4 & X86_CR4_PAE) )
+ {
+ HVM_DBG_LOG(DBG_LEVEL_1, "Guest enabled paging "
+ "with EFER.LME set but not CR4.PAE\n");
+ vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
+ }
+ else
+ {
+ HVM_DBG_LOG(DBG_LEVEL_1, "Enabling long mode\n");
+ v->arch.hvm_vmx.msr_state.msrs[VMX_INDEX_MSR_EFER]
+ |= EFER_LMA;
+ vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
+ vm_entry_value |= VM_ENTRY_IA32E_MODE;
+ __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
+ }
}
#endif
@@ -1541,35 +1593,32 @@ static int vmx_set_cr0(unsigned long value)
* Disable paging here.
* Same to PE == 1 && PG == 0
*/
- if ( test_bit(VMX_CPU_STATE_LMA_ENABLED,
- &v->arch.hvm_vmx.cpu_state) )
+ if ( vmx_long_mode_enabled(v) )
{
- clear_bit(VMX_CPU_STATE_LMA_ENABLED,
- &v->arch.hvm_vmx.cpu_state);
- __vmread(VM_ENTRY_CONTROLS, &vm_entry_value);
- vm_entry_value &= ~VM_ENTRY_CONTROLS_IA32E_MODE;
+ v->arch.hvm_vmx.msr_state.msrs[VMX_INDEX_MSR_EFER]
+ &= ~EFER_LMA;
+ vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
+ vm_entry_value &= ~VM_ENTRY_IA32E_MODE;
__vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
}
}
- if ( vmx_assist(v, VMX_ASSIST_INVOKE) ) {
- set_bit(VMX_CPU_STATE_ASSIST_ENABLED, &v->arch.hvm_vmx.cpu_state);
- __vmread(GUEST_RIP, &eip);
+ if ( vmx_assist(v, VMX_ASSIST_INVOKE) )
+ {
+ eip = __vmread(GUEST_RIP);
HVM_DBG_LOG(DBG_LEVEL_1,
"Transfering control to vmxassist %%eip 0x%lx\n", eip);
return 0; /* do not update eip! */
}
- } else if ( test_bit(VMX_CPU_STATE_ASSIST_ENABLED,
- &v->arch.hvm_vmx.cpu_state) )
+ }
+ else if ( v->arch.hvm_vmx.vmxassist_enabled )
{
- __vmread(GUEST_RIP, &eip);
+ eip = __vmread(GUEST_RIP);
HVM_DBG_LOG(DBG_LEVEL_1,
"Enabling CR0.PE at %%eip 0x%lx\n", eip);
if ( vmx_assist(v, VMX_ASSIST_RESTORE) )
{
- clear_bit(VMX_CPU_STATE_ASSIST_ENABLED,
- &v->arch.hvm_vmx.cpu_state);
- __vmread(GUEST_RIP, &eip);
+ eip = __vmread(GUEST_RIP);
HVM_DBG_LOG(DBG_LEVEL_1,
"Restoring to %%eip 0x%lx\n", eip);
return 0; /* do not update eip! */
@@ -1577,8 +1626,15 @@ static int vmx_set_cr0(unsigned long value)
}
else if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PE )
{
- __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
+ if ( vmx_long_mode_enabled(v) )
+ {
+ v->arch.hvm_vmx.msr_state.msrs[VMX_INDEX_MSR_EFER] &= ~EFER_LMA;
+ vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
+ vm_entry_value &= ~VM_ENTRY_IA32E_MODE;
+ __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
+ }
shadow_update_paging_modes(v);
+ __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
}
return 1;
@@ -1613,12 +1669,12 @@ static int vmx_set_cr0(unsigned long value)
*/
static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
{
- unsigned long value;
- unsigned long old_cr;
+ unsigned long value, old_cr, old_base_mfn, mfn;
struct vcpu *v = current;
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
- switch ( gp ) {
+ switch ( gp )
+ {
CASE_GET_REG(EAX, eax);
CASE_GET_REG(ECX, ecx);
CASE_GET_REG(EDX, edx);
@@ -1628,22 +1684,25 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
CASE_GET_REG(EDI, edi);
CASE_EXTEND_GET_REG;
case REG_ESP:
- __vmread(GUEST_RSP, &value);
+ value = __vmread(GUEST_RSP);
break;
default:
- printk("invalid gp: %d\n", gp);
- __hvm_bug(regs);
+ gdprintk(XENLOG_ERR, "invalid gp: %d\n", gp);
+ goto exit_and_crash;
}
+ TRACE_VMEXIT(1, TYPE_MOV_TO_CR);
+ TRACE_VMEXIT(2, cr);
+ TRACE_VMEXIT(3, value);
+
HVM_DBG_LOG(DBG_LEVEL_1, "CR%d, value = %lx", cr, value);
- switch ( cr ) {
+ switch ( cr )
+ {
case 0:
return vmx_set_cr0(value);
- case 3:
- {
- unsigned long old_base_mfn, mfn;
+ case 3:
/*
* If paging is not enabled yet, simply copy the value to CR3.
*/
@@ -1663,7 +1722,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
*/
mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT);
if (mfn != pagetable_get_pfn(v->arch.guest_table))
- __hvm_bug(regs);
+ goto bad_cr3;
shadow_update_cr3(v);
} else {
/*
@@ -1671,13 +1730,9 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
* first.
*/
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx", value);
- if ( ((value >> PAGE_SHIFT) > v->domain->max_pages ) ||
- !VALID_MFN(mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT)) ||
- !get_page(mfn_to_page(mfn), v->domain) )
- {
- printk("Invalid CR3 value=%lx", value);
- domain_crash_synchronous(); /* need to take a clean path */
- }
+ mfn = get_mfn_from_gpfn(value >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
+ goto bad_cr3;
old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
v->arch.guest_table = pagetable_from_pfn(mfn);
if (old_base_mfn)
@@ -1692,29 +1747,21 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
__vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr3);
}
break;
- }
+
case 4: /* CR4 */
- {
- __vmread(CR4_READ_SHADOW, &old_cr);
+ old_cr = v->arch.hvm_vmx.cpu_shadow_cr4;
- if ( value & X86_CR4_PAE && !(old_cr & X86_CR4_PAE) )
+ if ( (value & X86_CR4_PAE) && !(old_cr & X86_CR4_PAE) )
{
- set_bit(VMX_CPU_STATE_PAE_ENABLED, &v->arch.hvm_vmx.cpu_state);
-
if ( vmx_pgbit_test(v) )
{
/* The guest is a 32-bit PAE guest. */
#if CONFIG_PAGING_LEVELS >= 3
unsigned long mfn, old_base_mfn;
-
- if ( !VALID_MFN(mfn = get_mfn_from_gpfn(
- v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT)) ||
+ mfn = get_mfn_from_gpfn(v->arch.hvm_vmx.cpu_cr3 >> PAGE_SHIFT);
+ if ( !mfn_valid(mfn) ||
!get_page(mfn_to_page(mfn), v->domain) )
- {
- printk("Invalid CR3 value = %lx", v->arch.hvm_vmx.cpu_cr3);
- domain_crash_synchronous(); /* need to take a clean path */
- }
-
+ goto bad_cr3;
/*
* Now arch.guest_table points to machine physical.
@@ -1739,18 +1786,19 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
#endif
}
}
- else if ( value & X86_CR4_PAE )
- set_bit(VMX_CPU_STATE_PAE_ENABLED, &v->arch.hvm_vmx.cpu_state);
- else
+ else if ( !(value & X86_CR4_PAE) )
{
- if ( test_bit(VMX_CPU_STATE_LMA_ENABLED, &v->arch.hvm_vmx.cpu_state) )
+ if ( unlikely(vmx_long_mode_enabled(v)) )
+ {
+ HVM_DBG_LOG(DBG_LEVEL_1, "Guest cleared CR4.PAE while "
+ "EFER.LMA is set\n");
vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
-
- clear_bit(VMX_CPU_STATE_PAE_ENABLED, &v->arch.hvm_vmx.cpu_state);
+ }
}
__vmwrite(GUEST_CR4, value| VMX_CR4_HOST_MASK);
- __vmwrite(CR4_READ_SHADOW, value);
+ v->arch.hvm_vmx.cpu_shadow_cr4 = value;
+ __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4);
/*
* Writing to CR4 to modify the PSE, PGE, or PAE flag invalidates
@@ -1759,19 +1807,24 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs)
if ( (old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE) )
shadow_update_paging_modes(v);
break;
- }
+
case 8:
- {
vlapic_set_reg(vlapic, APIC_TASKPRI, ((value & 0x0F) << 4));
- vlapic_update_ppr(vlapic);
break;
- }
+
default:
- printk("invalid cr: %d\n", gp);
- __hvm_bug(regs);
+ gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);
+ domain_crash(v->domain);
+ return 0;
}
return 1;
+
+ bad_cr3:
+ gdprintk(XENLOG_ERR, "Invalid CR3\n");
+ exit_and_crash:
+ domain_crash(v->domain);
+ return 0;
}
/*
@@ -1781,17 +1834,21 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
{
unsigned long value = 0;
struct vcpu *v = current;
- struct vlapic *vlapic = VLAPIC(v);
+ struct vlapic *vlapic = vcpu_vlapic(v);
- if ( cr != 3 && cr != 8)
- __hvm_bug(regs);
-
- if ( cr == 3 )
- value = (unsigned long) v->arch.hvm_vmx.cpu_cr3;
- else if ( cr == 8 )
+ switch ( cr )
{
+ case 3:
+ value = (unsigned long)v->arch.hvm_vmx.cpu_cr3;
+ break;
+ case 8:
value = (unsigned long)vlapic_get_reg(vlapic, APIC_TASKPRI);
value = (value & 0xF0) >> 4;
+ break;
+ default:
+ gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);
+ domain_crash(v->domain);
+ break;
}
switch ( gp ) {
@@ -1809,13 +1866,19 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
break;
default:
printk("invalid gp: %d\n", gp);
- __hvm_bug(regs);
+ domain_crash(v->domain);
+ break;
}
+ TRACE_VMEXIT(1, TYPE_MOV_FROM_CR);
+ TRACE_VMEXIT(2, cr);
+ TRACE_VMEXIT(3, value);
+
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR%d, value = %lx", cr, value);
}
-static int vmx_cr_access(unsigned long exit_qualification, struct cpu_user_regs *regs)
+static int vmx_cr_access(unsigned long exit_qualification,
+ struct cpu_user_regs *regs)
{
unsigned int gp, cr;
unsigned long value;
@@ -1825,109 +1888,110 @@ static int vmx_cr_access(unsigned long exit_qualification, struct cpu_user_regs
case TYPE_MOV_TO_CR:
gp = exit_qualification & CONTROL_REG_ACCESS_REG;
cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
- TRACE_VMEXIT(1,TYPE_MOV_TO_CR);
- TRACE_VMEXIT(2,cr);
- TRACE_VMEXIT(3,gp);
return mov_to_cr(gp, cr, regs);
case TYPE_MOV_FROM_CR:
gp = exit_qualification & CONTROL_REG_ACCESS_REG;
cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
- TRACE_VMEXIT(1,TYPE_MOV_FROM_CR);
- TRACE_VMEXIT(2,cr);
- TRACE_VMEXIT(3,gp);
mov_from_cr(cr, gp, regs);
break;
case TYPE_CLTS:
- TRACE_VMEXIT(1,TYPE_CLTS);
+ TRACE_VMEXIT(1, TYPE_CLTS);
/* We initialise the FPU now, to avoid needing another vmexit. */
setup_fpu(v);
__vm_clear_bit(EXCEPTION_BITMAP, EXCEPTION_BITMAP_NM);
- __vmread_vcpu(v, GUEST_CR0, &value);
- value &= ~X86_CR0_TS; /* clear TS */
- __vmwrite(GUEST_CR0, value);
+ v->arch.hvm_vmx.cpu_cr0 &= ~X86_CR0_TS; /* clear TS */
+ __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0);
- __vmread_vcpu(v, CR0_READ_SHADOW, &value);
- value &= ~X86_CR0_TS; /* clear TS */
- __vmwrite(CR0_READ_SHADOW, value);
+ v->arch.hvm_vmx.cpu_shadow_cr0 &= ~X86_CR0_TS; /* clear TS */
+ __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0);
break;
case TYPE_LMSW:
- TRACE_VMEXIT(1,TYPE_LMSW);
- __vmread_vcpu(v, CR0_READ_SHADOW, &value);
+ value = v->arch.hvm_vmx.cpu_shadow_cr0;
value = (value & ~0xF) |
(((exit_qualification & LMSW_SOURCE_DATA) >> 16) & 0xF);
+ TRACE_VMEXIT(1, TYPE_LMSW);
+ TRACE_VMEXIT(2, value);
return vmx_set_cr0(value);
break;
default:
- __hvm_bug(regs);
- break;
+ BUG();
}
+
return 1;
}
-static inline void vmx_do_msr_read(struct cpu_user_regs *regs)
+static inline int vmx_do_msr_read(struct cpu_user_regs *regs)
{
u64 msr_content = 0;
- u32 eax, edx;
+ u32 ecx = regs->ecx, eax, edx;
struct vcpu *v = current;
- HVM_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read: ecx=%lx, eax=%lx, edx=%lx",
- (unsigned long)regs->ecx, (unsigned long)regs->eax,
- (unsigned long)regs->edx);
- switch (regs->ecx) {
+ HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x",
+ ecx, (u32)regs->eax, (u32)regs->edx);
+
+ switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER:
msr_content = hvm_get_guest_time(v);
break;
case MSR_IA32_SYSENTER_CS:
- __vmread(GUEST_SYSENTER_CS, (u32 *)&msr_content);
+ msr_content = (u32)__vmread(GUEST_SYSENTER_CS);
break;
case MSR_IA32_SYSENTER_ESP:
- __vmread(GUEST_SYSENTER_ESP, &msr_content);
+ msr_content = __vmread(GUEST_SYSENTER_ESP);
break;
case MSR_IA32_SYSENTER_EIP:
- __vmread(GUEST_SYSENTER_EIP, &msr_content);
+ msr_content = __vmread(GUEST_SYSENTER_EIP);
break;
case MSR_IA32_APICBASE:
- msr_content = VLAPIC(v) ? VLAPIC(v)->apic_base_msr : 0;
+ msr_content = vcpu_vlapic(v)->apic_base_msr;
break;
default:
- if (long_mode_do_msr_read(regs))
- return;
+ if ( long_mode_do_msr_read(regs) )
+ goto done;
- if ( rdmsr_hypervisor_regs(regs->ecx, &eax, &edx) )
+ if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) ||
+ rdmsr_safe(ecx, eax, edx) == 0 )
{
regs->eax = eax;
regs->edx = edx;
- return;
+ goto done;
}
-
- rdmsr_safe(regs->ecx, regs->eax, regs->edx);
- return;
+ vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
+ return 0;
}
regs->eax = msr_content & 0xFFFFFFFF;
regs->edx = msr_content >> 32;
- HVM_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read returns: "
- "ecx=%lx, eax=%lx, edx=%lx",
- (unsigned long)regs->ecx, (unsigned long)regs->eax,
+done:
+ HVM_DBG_LOG(DBG_LEVEL_1, "returns: ecx=%x, eax=%lx, edx=%lx",
+ ecx, (unsigned long)regs->eax,
(unsigned long)regs->edx);
+ return 1;
}
-static inline void vmx_do_msr_write(struct cpu_user_regs *regs)
+static inline int vmx_do_msr_write(struct cpu_user_regs *regs)
{
+ u32 ecx = regs->ecx;
u64 msr_content;
struct vcpu *v = current;
- HVM_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_write: ecx=%lx, eax=%lx, edx=%lx",
- (unsigned long)regs->ecx, (unsigned long)regs->eax,
- (unsigned long)regs->edx);
+ HVM_DBG_LOG(DBG_LEVEL_1, "ecx=%x, eax=%x, edx=%x",
+ ecx, (u32)regs->eax, (u32)regs->edx);
- msr_content = (regs->eax & 0xFFFFFFFF) | ((u64)regs->edx << 32);
+ msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
- switch (regs->ecx) {
+ switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER:
+ {
+ struct periodic_time *pt =
+ &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+ if ( pt->enabled && pt->first_injected
+ && v->vcpu_id == pt->bind_vcpu )
+ pt->first_injected = 0;
+ }
hvm_set_guest_time(v, msr_content);
break;
case MSR_IA32_SYSENTER_CS:
@@ -1940,31 +2004,27 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs)
__vmwrite(GUEST_SYSENTER_EIP, msr_content);
break;
case MSR_IA32_APICBASE:
- vlapic_msr_set(VLAPIC(v), msr_content);
+ vlapic_msr_set(vcpu_vlapic(v), msr_content);
break;
default:
if ( !long_mode_do_msr_write(regs) )
- wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx);
+ wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx);
break;
}
- HVM_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_write returns: "
- "ecx=%lx, eax=%lx, edx=%lx",
- (unsigned long)regs->ecx, (unsigned long)regs->eax,
- (unsigned long)regs->edx);
+ return 1;
}
-void vmx_vmexit_do_hlt(void)
+static void vmx_do_hlt(void)
{
unsigned long rflags;
- __vmread(GUEST_RFLAGS, &rflags);
+ rflags = __vmread(GUEST_RFLAGS);
hvm_hlt(rflags);
}
-static inline void vmx_vmexit_do_extint(struct cpu_user_regs *regs)
+static inline void vmx_do_extint(struct cpu_user_regs *regs)
{
unsigned int vector;
- int error;
asmlinkage void do_IRQ(struct cpu_user_regs *);
fastcall void smp_apic_timer_interrupt(struct cpu_user_regs *);
@@ -1977,12 +2037,11 @@ static inline void vmx_vmexit_do_extint(struct cpu_user_regs *regs)
fastcall void smp_thermal_interrupt(struct cpu_user_regs *regs);
#endif
- if ((error = __vmread(VM_EXIT_INTR_INFO, &vector))
- && !(vector & INTR_INFO_VALID_MASK))
- __hvm_bug(regs);
+ vector = __vmread(VM_EXIT_INTR_INFO);
+ BUG_ON(!(vector & INTR_INFO_VALID_MASK));
vector &= INTR_INFO_VECTOR_MASK;
- TRACE_VMEXIT(1,vector);
+ TRACE_VMEXIT(1, vector);
switch(vector) {
case LOCAL_TIMER_VECTOR:
@@ -2018,40 +2077,40 @@ static inline void vmx_vmexit_do_extint(struct cpu_user_regs *regs)
#if defined (__x86_64__)
void store_cpu_user_regs(struct cpu_user_regs *regs)
{
- __vmread(GUEST_SS_SELECTOR, &regs->ss);
- __vmread(GUEST_RSP, &regs->rsp);
- __vmread(GUEST_RFLAGS, &regs->rflags);
- __vmread(GUEST_CS_SELECTOR, &regs->cs);
- __vmread(GUEST_DS_SELECTOR, &regs->ds);
- __vmread(GUEST_ES_SELECTOR, &regs->es);
- __vmread(GUEST_RIP, &regs->rip);
+ regs->ss = __vmread(GUEST_SS_SELECTOR);
+ regs->rsp = __vmread(GUEST_RSP);
+ regs->rflags = __vmread(GUEST_RFLAGS);
+ regs->cs = __vmread(GUEST_CS_SELECTOR);
+ regs->ds = __vmread(GUEST_DS_SELECTOR);
+ regs->es = __vmread(GUEST_ES_SELECTOR);
+ regs->rip = __vmread(GUEST_RIP);
}
#elif defined (__i386__)
void store_cpu_user_regs(struct cpu_user_regs *regs)
{
- __vmread(GUEST_SS_SELECTOR, &regs->ss);
- __vmread(GUEST_RSP, &regs->esp);
- __vmread(GUEST_RFLAGS, &regs->eflags);
- __vmread(GUEST_CS_SELECTOR, &regs->cs);
- __vmread(GUEST_DS_SELECTOR, &regs->ds);
- __vmread(GUEST_ES_SELECTOR, &regs->es);
- __vmread(GUEST_RIP, &regs->eip);
+ regs->ss = __vmread(GUEST_SS_SELECTOR);
+ regs->esp = __vmread(GUEST_RSP);
+ regs->eflags = __vmread(GUEST_RFLAGS);
+ regs->cs = __vmread(GUEST_CS_SELECTOR);
+ regs->ds = __vmread(GUEST_DS_SELECTOR);
+ regs->es = __vmread(GUEST_ES_SELECTOR);
+ regs->eip = __vmread(GUEST_RIP);
}
-#endif
+#endif
#ifdef XEN_DEBUGGER
void save_cpu_user_regs(struct cpu_user_regs *regs)
{
- __vmread(GUEST_SS_SELECTOR, &regs->xss);
- __vmread(GUEST_RSP, &regs->esp);
- __vmread(GUEST_RFLAGS, &regs->eflags);
- __vmread(GUEST_CS_SELECTOR, &regs->xcs);
- __vmread(GUEST_RIP, &regs->eip);
-
- __vmread(GUEST_GS_SELECTOR, &regs->xgs);
- __vmread(GUEST_FS_SELECTOR, &regs->xfs);
- __vmread(GUEST_ES_SELECTOR, &regs->xes);
- __vmread(GUEST_DS_SELECTOR, &regs->xds);
+ regs->xss = __vmread(GUEST_SS_SELECTOR);
+ regs->esp = __vmread(GUEST_RSP);
+ regs->eflags = __vmread(GUEST_RFLAGS);
+ regs->xcs = __vmread(GUEST_CS_SELECTOR);
+ regs->eip = __vmread(GUEST_RIP);
+
+ regs->xgs = __vmread(GUEST_GS_SELECTOR);
+ regs->xfs = __vmread(GUEST_FS_SELECTOR);
+ regs->xes = __vmread(GUEST_ES_SELECTOR);
+ regs->xds = __vmread(GUEST_DS_SELECTOR);
}
void restore_cpu_user_regs(struct cpu_user_regs *regs)
@@ -2069,21 +2128,57 @@ void restore_cpu_user_regs(struct cpu_user_regs *regs)
}
#endif
-asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
+static void vmx_reflect_exception(struct vcpu *v)
+{
+ int error_code, intr_info, vector;
+
+ intr_info = __vmread(VM_EXIT_INTR_INFO);
+ vector = intr_info & 0xff;
+ if ( intr_info & INTR_INFO_DELIVER_CODE_MASK )
+ error_code = __vmread(VM_EXIT_INTR_ERROR_CODE);
+ else
+ error_code = VMX_DELIVER_NO_ERROR_CODE;
+
+#ifndef NDEBUG
+ {
+ unsigned long rip;
+
+ rip = __vmread(GUEST_RIP);
+ HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, error_code = %x",
+ rip, error_code);
+ }
+#endif /* NDEBUG */
+
+ /*
+ * According to Intel Virtualization Technology Specification for
+ * the IA-32 Intel Architecture (C97063-002 April 2005), section
+ * 2.8.3, SW_EXCEPTION should be used for #BP and #OV, and
+ * HW_EXCEPTION used for everything else. The main difference
+ * appears to be that for SW_EXCEPTION, the EIP/RIP is incremented
+ * by VM_ENTER_INSTRUCTION_LEN bytes, whereas for HW_EXCEPTION,
+ * it is not.
+ */
+ if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_SW_EXCEPTION )
+ {
+ int ilen = __get_instruction_length(); /* Safe: software exception */
+ vmx_inject_sw_exception(v, vector, ilen);
+ }
+ else
+ {
+ vmx_inject_hw_exception(v, vector, error_code);
+ }
+}
+
+asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs)
{
unsigned int exit_reason;
- unsigned long exit_qualification, rip, inst_len = 0;
+ unsigned long exit_qualification, inst_len = 0;
struct vcpu *v = current;
- __vmread(VM_EXIT_REASON, &exit_reason);
+ exit_reason = __vmread(VM_EXIT_REASON);
perfc_incra(vmexits, exit_reason);
- if ( (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT) &&
- (exit_reason != EXIT_REASON_VMCALL) &&
- (exit_reason != EXIT_REASON_IO_INSTRUCTION) )
- HVM_DBG_LOG(DBG_LEVEL_0, "exit reason = %x", exit_reason);
-
if ( exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT )
local_irq_enable();
@@ -2091,7 +2186,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
{
unsigned int failed_vmentry_reason = exit_reason & 0xFFFF;
- __vmread(EXIT_QUALIFICATION, &exit_qualification);
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
printk("Failed vm entry (exit reason 0x%x) ", exit_reason);
switch ( failed_vmentry_reason ) {
case EXIT_REASON_INVALID_GUEST_STATE:
@@ -2111,12 +2206,13 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
printk("************* VMCS Area **************\n");
vmcs_dump_vcpu();
printk("**************************************\n");
- domain_crash_synchronous();
+ goto exit_and_crash;
}
- TRACE_VMEXIT(0,exit_reason);
+ TRACE_VMEXIT(0, exit_reason);
- switch ( exit_reason ) {
+ switch ( exit_reason )
+ {
case EXIT_REASON_EXCEPTION_NMI:
{
/*
@@ -2124,41 +2220,39 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
* (1) We can get an exception (e.g. #PG) in the guest, or
* (2) NMI
*/
- unsigned int vector;
- unsigned long va;
+ unsigned int intr_info, vector;
+
+ intr_info = __vmread(VM_EXIT_INTR_INFO);
+ BUG_ON(!(intr_info & INTR_INFO_VALID_MASK));
- if ( __vmread(VM_EXIT_INTR_INFO, &vector) ||
- !(vector & INTR_INFO_VALID_MASK) )
- domain_crash_synchronous();
- vector &= INTR_INFO_VECTOR_MASK;
+ vector = intr_info & INTR_INFO_VECTOR_MASK;
- TRACE_VMEXIT(1,vector);
+ TRACE_VMEXIT(1, vector);
perfc_incra(cause_vector, vector);
- switch ( vector ) {
+ switch ( vector )
+ {
#ifdef XEN_DEBUGGER
case TRAP_debug:
{
- save_cpu_user_regs(&regs);
- pdb_handle_exception(1, &regs, 1);
- restore_cpu_user_regs(&regs);
+ save_cpu_user_regs(regs);
+ pdb_handle_exception(1, regs, 1);
+ restore_cpu_user_regs(regs);
break;
}
case TRAP_int3:
{
- save_cpu_user_regs(&regs);
- pdb_handle_exception(3, &regs, 1);
- restore_cpu_user_regs(&regs);
+ save_cpu_user_regs(regs);
+ pdb_handle_exception(3, regs, 1);
+ restore_cpu_user_regs(regs);
break;
}
#else
case TRAP_debug:
{
- void store_cpu_user_regs(struct cpu_user_regs *regs);
-
if ( test_bit(_DOMF_debugging, &v->domain->domain_flags) )
{
- store_cpu_user_regs(&regs);
+ store_cpu_user_regs(regs);
domain_pause_for_debugger();
__vm_clear_bit(GUEST_PENDING_DBG_EXCEPTIONS,
PENDING_DEBUG_EXC_BS);
@@ -2188,30 +2282,33 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
}
case TRAP_page_fault:
{
- __vmread(EXIT_QUALIFICATION, &va);
- __vmread(VM_EXIT_INTR_ERROR_CODE, &regs.error_code);
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ regs->error_code = __vmread(VM_EXIT_INTR_ERROR_CODE);
- TRACE_VMEXIT(3,regs.error_code);
- TRACE_VMEXIT(4,va);
+ TRACE_VMEXIT(3, regs->error_code);
+ TRACE_VMEXIT(4, exit_qualification);
HVM_DBG_LOG(DBG_LEVEL_VMMU,
"eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx",
- (unsigned long)regs.eax, (unsigned long)regs.ebx,
- (unsigned long)regs.ecx, (unsigned long)regs.edx,
- (unsigned long)regs.esi, (unsigned long)regs.edi);
+ (unsigned long)regs->eax, (unsigned long)regs->ebx,
+ (unsigned long)regs->ecx, (unsigned long)regs->edx,
+ (unsigned long)regs->esi, (unsigned long)regs->edi);
- if ( !vmx_do_page_fault(va, &regs) ) {
- /*
- * Inject #PG using Interruption-Information Fields
- */
- vmx_inject_hw_exception(v, TRAP_page_fault, regs.error_code);
- v->arch.hvm_vmx.cpu_cr2 = va;
- TRACE_3D(TRC_VMX_INT, v->domain->domain_id, TRAP_page_fault, va);
+ if ( !vmx_do_page_fault(exit_qualification, regs) )
+ {
+ /* Inject #PG using Interruption-Information Fields. */
+ vmx_inject_hw_exception(v, TRAP_page_fault, regs->error_code);
+ v->arch.hvm_vmx.cpu_cr2 = exit_qualification;
+ TRACE_3D(TRC_VMX_INTR, v->domain->domain_id,
+ TRAP_page_fault, exit_qualification);
}
break;
}
case TRAP_nmi:
- do_nmi(&regs);
+ if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI )
+ do_nmi(regs); /* Real NMI, vector 2: normal processing. */
+ else
+ vmx_reflect_exception(v);
break;
default:
vmx_reflect_exception(v);
@@ -2220,96 +2317,83 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
break;
}
case EXIT_REASON_EXTERNAL_INTERRUPT:
- vmx_vmexit_do_extint(&regs);
+ vmx_do_extint(regs);
break;
case EXIT_REASON_TRIPLE_FAULT:
- domain_crash_synchronous();
- break;
+ goto exit_and_crash;
case EXIT_REASON_PENDING_INTERRUPT:
- /*
- * Not sure exactly what the purpose of this is. The only bits set
- * and cleared at this point are CPU_BASED_VIRTUAL_INTR_PENDING.
- * (in io.c:{enable,disable}_irq_window(). So presumably we want to
- * set it to the original value...
- */
+ /* Disable the interrupt window. */
v->arch.hvm_vcpu.u.vmx.exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
- v->arch.hvm_vcpu.u.vmx.exec_control |=
- (MONITOR_CPU_BASED_EXEC_CONTROLS & CPU_BASED_VIRTUAL_INTR_PENDING);
__vmwrite(CPU_BASED_VM_EXEC_CONTROL,
v->arch.hvm_vcpu.u.vmx.exec_control);
break;
case EXIT_REASON_TASK_SWITCH:
- domain_crash_synchronous();
- break;
+ goto exit_and_crash;
case EXIT_REASON_CPUID:
- vmx_vmexit_do_cpuid(&regs);
- __get_instruction_length(inst_len);
+ inst_len = __get_instruction_length(); /* Safe: CPUID */
__update_guest_eip(inst_len);
+ vmx_do_cpuid(regs);
break;
case EXIT_REASON_HLT:
- __get_instruction_length(inst_len);
+ inst_len = __get_instruction_length(); /* Safe: HLT */
__update_guest_eip(inst_len);
- vmx_vmexit_do_hlt();
+ vmx_do_hlt();
break;
case EXIT_REASON_INVLPG:
{
- unsigned long va;
-
- __vmread(EXIT_QUALIFICATION, &va);
- vmx_vmexit_do_invlpg(va);
- __get_instruction_length(inst_len);
+ inst_len = __get_instruction_length(); /* Safe: INVLPG */
__update_guest_eip(inst_len);
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ vmx_do_invlpg(exit_qualification);
+ TRACE_VMEXIT(4, exit_qualification);
break;
}
case EXIT_REASON_VMCALL:
{
- __get_instruction_length(inst_len);
- __vmread(GUEST_RIP, &rip);
- __vmread(EXIT_QUALIFICATION, &exit_qualification);
-
- hvm_do_hypercall(&regs);
+ inst_len = __get_instruction_length(); /* Safe: VMCALL */
__update_guest_eip(inst_len);
+ hvm_do_hypercall(regs);
break;
}
case EXIT_REASON_CR_ACCESS:
{
- __vmread(GUEST_RIP, &rip);
- __get_instruction_length(inst_len);
- __vmread(EXIT_QUALIFICATION, &exit_qualification);
-
- HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, inst_len =%lx, exit_qualification = %lx",
- rip, inst_len, exit_qualification);
- if ( vmx_cr_access(exit_qualification, &regs) )
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ inst_len = __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */
+ if ( vmx_cr_access(exit_qualification, regs) )
__update_guest_eip(inst_len);
- TRACE_VMEXIT(3,regs.error_code);
- TRACE_VMEXIT(4,exit_qualification);
+ TRACE_VMEXIT(4, exit_qualification);
break;
}
case EXIT_REASON_DR_ACCESS:
- __vmread(EXIT_QUALIFICATION, &exit_qualification);
- vmx_dr_access(exit_qualification, &regs);
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ vmx_dr_access(exit_qualification, regs);
break;
case EXIT_REASON_IO_INSTRUCTION:
- __vmread(EXIT_QUALIFICATION, &exit_qualification);
- __get_instruction_length(inst_len);
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ inst_len = __get_instruction_length(); /* Safe: IN, INS, OUT, OUTS */
vmx_io_instruction(exit_qualification, inst_len);
- TRACE_VMEXIT(4,exit_qualification);
+ TRACE_VMEXIT(4, exit_qualification);
break;
case EXIT_REASON_MSR_READ:
- __get_instruction_length(inst_len);
- vmx_do_msr_read(&regs);
- __update_guest_eip(inst_len);
+ inst_len = __get_instruction_length(); /* Safe: RDMSR */
+ if ( vmx_do_msr_read(regs) )
+ __update_guest_eip(inst_len);
+ TRACE_VMEXIT(1, regs->ecx);
+ TRACE_VMEXIT(2, regs->eax);
+ TRACE_VMEXIT(3, regs->edx);
break;
case EXIT_REASON_MSR_WRITE:
- vmx_do_msr_write(&regs);
- __get_instruction_length(inst_len);
- __update_guest_eip(inst_len);
+ inst_len = __get_instruction_length(); /* Safe: WRMSR */
+ if ( vmx_do_msr_write(regs) )
+ __update_guest_eip(inst_len);
+ TRACE_VMEXIT(1, regs->ecx);
+ TRACE_VMEXIT(2, regs->eax);
+ TRACE_VMEXIT(3, regs->edx);
break;
case EXIT_REASON_MWAIT_INSTRUCTION:
case EXIT_REASON_MONITOR_INSTRUCTION:
case EXIT_REASON_PAUSE_INSTRUCTION:
- domain_crash_synchronous();
- break;
+ goto exit_and_crash;
case EXIT_REASON_VMCLEAR:
case EXIT_REASON_VMLAUNCH:
case EXIT_REASON_VMPTRLD:
@@ -2324,39 +2408,38 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs)
vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE);
break;
+ case EXIT_REASON_TPR_BELOW_THRESHOLD:
+ vcpu_vlapic(v)->flush_tpr_threshold = 1;
+ break;
+
default:
- domain_crash_synchronous(); /* should not happen */
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Bad vmexit (reason %x)\n", exit_reason);
+ domain_crash(v->domain);
+ break;
}
}
-asmlinkage void vmx_load_cr2(void)
+asmlinkage void vmx_trace_vmentry(void)
{
struct vcpu *v = current;
-
- local_irq_disable();
- asm volatile("mov %0,%%cr2": :"r" (v->arch.hvm_vmx.cpu_cr2));
-}
-
-asmlinkage void vmx_trace_vmentry (void)
-{
- TRACE_5D(TRC_VMX_VMENTRY,
- this_cpu(trace_values)[0],
- this_cpu(trace_values)[1],
- this_cpu(trace_values)[2],
- this_cpu(trace_values)[3],
- this_cpu(trace_values)[4]);
- TRACE_VMEXIT(0,9);
- TRACE_VMEXIT(1,9);
- TRACE_VMEXIT(2,9);
- TRACE_VMEXIT(3,9);
- TRACE_VMEXIT(4,9);
- return;
+ TRACE_5D(TRC_VMX_VMENTRY + current->vcpu_id,
+ v->arch.hvm_vcpu.hvm_trace_values[0],
+ v->arch.hvm_vcpu.hvm_trace_values[1],
+ v->arch.hvm_vcpu.hvm_trace_values[2],
+ v->arch.hvm_vcpu.hvm_trace_values[3],
+ v->arch.hvm_vcpu.hvm_trace_values[4]);
+
+ TRACE_VMEXIT(0, 0);
+ TRACE_VMEXIT(1, 0);
+ TRACE_VMEXIT(2, 0);
+ TRACE_VMEXIT(3, 0);
+ TRACE_VMEXIT(4, 0);
}
asmlinkage void vmx_trace_vmexit (void)
{
- TRACE_3D(TRC_VMX_VMEXIT,0,0,0);
- return;
+ TRACE_3D(TRC_VMX_VMEXIT + current->vcpu_id, 0, 0, 0);
}
/*
diff --git a/xen/arch/x86/hvm/vmx/x86_32/exits.S b/xen/arch/x86/hvm/vmx/x86_32/exits.S
index 80a05bf9da..144dd174d4 100644
--- a/xen/arch/x86/hvm/vmx/x86_32/exits.S
+++ b/xen/arch/x86/hvm/vmx/x86_32/exits.S
@@ -82,7 +82,10 @@ ENTRY(vmx_asm_vmexit_handler)
/* selectors are restored/saved by VMX */
HVM_SAVE_ALL_NOSEGREGS
call vmx_trace_vmexit
+ movl %esp,%eax
+ push %eax
call vmx_vmexit_handler
+ addl $4,%esp
jmp vmx_asm_do_vmentry
ALIGN
@@ -94,9 +97,6 @@ vmx_process_softirqs:
ALIGN
ENTRY(vmx_asm_do_vmentry)
GET_CURRENT(%ebx)
- pushl %ebx
- call hvm_do_resume
- addl $4, %esp
cli # tests must not race interrupts
movl VCPU_processor(%ebx),%eax
@@ -105,7 +105,8 @@ ENTRY(vmx_asm_do_vmentry)
jnz vmx_process_softirqs
call vmx_intr_assist
- call vmx_load_cr2
+ movl VCPU_vmx_cr2(%ebx),%eax
+ movl %eax,%cr2
call vmx_trace_vmentry
cmpl $0,VCPU_vmx_launched(%ebx)
diff --git a/xen/arch/x86/hvm/vmx/x86_64/exits.S b/xen/arch/x86/hvm/vmx/x86_64/exits.S
index b996fa1a39..d427ac2cd5 100644
--- a/xen/arch/x86/hvm/vmx/x86_64/exits.S
+++ b/xen/arch/x86/hvm/vmx/x86_64/exits.S
@@ -93,6 +93,7 @@ ENTRY(vmx_asm_vmexit_handler)
/* selectors are restored/saved by VMX */
HVM_SAVE_ALL_NOSEGREGS
call vmx_trace_vmexit
+ movq %rsp,%rdi
call vmx_vmexit_handler
jmp vmx_asm_do_vmentry
@@ -105,8 +106,6 @@ vmx_process_softirqs:
ALIGN
ENTRY(vmx_asm_do_vmentry)
GET_CURRENT(%rbx)
- movq %rbx, %rdi
- call hvm_do_resume
cli # tests must not race interrupts
movl VCPU_processor(%rbx),%eax
@@ -116,7 +115,8 @@ ENTRY(vmx_asm_do_vmentry)
jnz vmx_process_softirqs
call vmx_intr_assist
- call vmx_load_cr2
+ movq VCPU_vmx_cr2(%rbx),%rax
+ movq %rax,%cr2
call vmx_trace_vmentry
cmpl $0,VCPU_vmx_launched(%rbx)
diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c
new file mode 100644
index 0000000000..268bf8234d
--- /dev/null
+++ b/xen/arch/x86/hvm/vpic.c
@@ -0,0 +1,463 @@
+/*
+ * i8259 interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005 Intel Corperation
+ * Copyright (c) 2006 Keir Fraser, XenSource Inc.
+ *
+ * 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 <xen/config.h>
+#include <xen/types.h>
+#include <xen/event.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+
+#define vpic_domain(v) (container_of((v), struct domain, \
+ arch.hvm_domain.irq.vpic[!vpic->is_master]))
+#define __vpic_lock(v) &container_of((v), struct hvm_irq, \
+ vpic[!(v)->is_master])->lock
+#define vpic_lock(v) spin_lock(__vpic_lock(v))
+#define vpic_unlock(v) spin_unlock(__vpic_lock(v))
+#define vpic_is_locked(v) spin_is_locked(__vpic_lock(v))
+#define vpic_elcr_mask(v) (vpic->is_master ? (uint8_t)0xf8 : (uint8_t)0xde);
+
+/* Return the highest priority found in mask. Return 8 if none. */
+#define VPIC_PRIO_NONE 8
+static int vpic_get_priority(struct vpic *vpic, uint8_t mask)
+{
+ int prio;
+
+ ASSERT(vpic_is_locked(vpic));
+
+ if ( mask == 0 )
+ return VPIC_PRIO_NONE;
+
+ /* prio = ffs(mask ROL vpic->priority_add); */
+ asm ( "rol %%cl,%b1 ; bsf %1,%0"
+ : "=r" (prio) : "r" ((uint32_t)mask), "c" (vpic->priority_add) );
+ return prio;
+}
+
+/* Return the PIC's highest priority pending interrupt. Return -1 if none. */
+static int vpic_get_highest_priority_irq(struct vpic *vpic)
+{
+ int cur_priority, priority, irq;
+ uint8_t mask;
+
+ ASSERT(vpic_is_locked(vpic));
+
+ mask = vpic->irr & ~vpic->imr;
+ priority = vpic_get_priority(vpic, mask);
+ if ( priority == VPIC_PRIO_NONE )
+ return -1;
+
+ irq = (priority + vpic->priority_add) & 7;
+
+ /*
+ * Compute current priority. If special fully nested mode on the master,
+ * the IRQ coming from the slave is not taken into account for the
+ * priority computation. In special mask mode, masked interrupts do not
+ * block lower-priority interrupts even if their IS bit is set.
+ */
+ mask = vpic->isr;
+ if ( vpic->special_fully_nested_mode && vpic->is_master && (irq == 2) )
+ mask &= ~(1 << 2);
+ if ( vpic->special_mask_mode )
+ mask &= ~vpic->imr;
+ cur_priority = vpic_get_priority(vpic, mask);
+
+ /* If a higher priority is found then an irq should be generated. */
+ return (priority < cur_priority) ? irq : -1;
+}
+
+static void vpic_update_int_output(struct vpic *vpic)
+{
+ int irq;
+
+ ASSERT(vpic_is_locked(vpic));
+
+ irq = vpic_get_highest_priority_irq(vpic);
+ if ( vpic->int_output == (irq >= 0) )
+ return;
+
+ /* INT line transition L->H or H->L. */
+ vpic->int_output = !vpic->int_output;
+
+ if ( vpic->int_output )
+ {
+ if ( vpic->is_master )
+ {
+ /* Master INT line is connected to VCPU0's VLAPIC LVT0. */
+ struct vcpu *v = vpic_domain(vpic)->vcpu[0];
+ if ( (v != NULL) && vlapic_accept_pic_intr(v) )
+ vcpu_kick(v);
+ }
+ else
+ {
+ /* Assert slave line in master PIC. */
+ (--vpic)->irr |= 1 << 2;
+ vpic_update_int_output(vpic);
+ }
+ }
+ else if ( !vpic->is_master )
+ {
+ /* Clear slave line in master PIC. */
+ (--vpic)->irr &= ~(1 << 2);
+ vpic_update_int_output(vpic);
+ }
+}
+
+static void __vpic_intack(struct vpic *vpic, int irq)
+{
+ uint8_t mask = 1 << irq;
+
+ ASSERT(vpic_is_locked(vpic));
+
+ /* Edge-triggered: clear the IRR (forget the edge). */
+ if ( !(vpic->elcr & mask) )
+ vpic->irr &= ~mask;
+
+ if ( !vpic->auto_eoi )
+ vpic->isr |= mask;
+ else if ( vpic->rotate_on_auto_eoi )
+ vpic->priority_add = (irq + 1) & 7;
+
+ vpic_update_int_output(vpic);
+}
+
+static int vpic_intack(struct vpic *vpic)
+{
+ int irq = -1;
+
+ vpic_lock(vpic);
+
+ if ( !vpic->int_output )
+ goto out;
+
+ irq = vpic_get_highest_priority_irq(vpic);
+ BUG_ON(irq < 0);
+ __vpic_intack(vpic, irq);
+
+ if ( (irq == 2) && vpic->is_master )
+ {
+ vpic++; /* Slave PIC */
+ irq = vpic_get_highest_priority_irq(vpic);
+ BUG_ON(irq < 0);
+ __vpic_intack(vpic, irq);
+ irq += 8;
+ }
+
+ out:
+ vpic_unlock(vpic);
+ return irq;
+}
+
+static void vpic_ioport_write(struct vpic *vpic, uint32_t addr, uint32_t val)
+{
+ int priority, cmd, irq;
+ uint8_t mask;
+
+ vpic_lock(vpic);
+
+ addr &= 1;
+ if ( addr == 0 )
+ {
+ if ( val & 0x10 )
+ {
+ /* ICW1 */
+ /* Clear edge-sensing logic. */
+ vpic->irr &= vpic->elcr;
+
+ /* No interrupts masked or in service. */
+ vpic->imr = vpic->isr = 0;
+
+ /* IR7 is lowest priority. */
+ vpic->priority_add = 0;
+ vpic->rotate_on_auto_eoi = 0;
+
+ vpic->special_mask_mode = 0;
+ vpic->readsel_isr = 0;
+ vpic->poll = 0;
+
+ if ( !(val & 1) )
+ {
+ /* NO ICW4: ICW4 features are cleared. */
+ vpic->auto_eoi = 0;
+ vpic->special_fully_nested_mode = 0;
+ }
+
+ vpic->init_state = ((val & 3) << 2) | 1;
+ }
+ else if ( val & 0x08 )
+ {
+ /* OCW3 */
+ if ( val & 0x04 )
+ vpic->poll = 1;
+ if ( val & 0x02 )
+ vpic->readsel_isr = val & 1;
+ if ( val & 0x40 )
+ vpic->special_mask_mode = (val >> 5) & 1;
+ }
+ else
+ {
+ /* OCW2 */
+ cmd = val >> 5;
+ switch ( cmd )
+ {
+ case 0: /* Rotate in AEOI Mode (Clear) */
+ case 4: /* Rotate in AEOI Mode (Set) */
+ vpic->rotate_on_auto_eoi = cmd >> 2;
+ break;
+ case 1: /* Non-Specific EOI */
+ case 5: /* Non-Specific EOI & Rotate */
+ mask = vpic->isr;
+ if ( vpic->special_mask_mode )
+ mask &= ~vpic->imr; /* SMM: ignore masked IRs. */
+ priority = vpic_get_priority(vpic, mask);
+ if ( priority == VPIC_PRIO_NONE )
+ break;
+ irq = (priority + vpic->priority_add) & 7;
+ vpic->isr &= ~(1 << irq);
+ if ( cmd == 5 )
+ vpic->priority_add = (irq + 1) & 7;
+ break;
+ case 3: /* Specific EOI */
+ case 7: /* Specific EOI & Rotate */
+ irq = val & 7;
+ vpic->isr &= ~(1 << irq);
+ if ( cmd == 7 )
+ vpic->priority_add = (irq + 1) & 7;
+ break;
+ case 6: /* Set Priority */
+ vpic->priority_add = (val + 1) & 7;
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch ( vpic->init_state & 3 )
+ {
+ case 0:
+ /* OCW1 */
+ vpic->imr = val;
+ break;
+ case 1:
+ /* ICW2 */
+ vpic->irq_base = val & 0xf8;
+ vpic->init_state++;
+ if ( !(vpic->init_state & 8) )
+ break; /* CASCADE mode: wait for write to ICW3. */
+ /* SNGL mode: fall through (no ICW3). */
+ case 2:
+ /* ICW3 */
+ vpic->init_state++;
+ if ( !(vpic->init_state & 4) )
+ vpic->init_state = 0; /* No ICW4: init done */
+ break;
+ case 3:
+ /* ICW4 */
+ vpic->special_fully_nested_mode = (val >> 4) & 1;
+ vpic->auto_eoi = (val >> 1) & 1;
+ vpic->init_state = 0;
+ break;
+ }
+ }
+
+ vpic_update_int_output(vpic);
+
+ vpic_unlock(vpic);
+}
+
+static uint32_t vpic_ioport_read(struct vpic *vpic, uint32_t addr)
+{
+ if ( vpic->poll )
+ {
+ vpic->poll = 0;
+ return vpic_intack(vpic);
+ }
+
+ if ( (addr & 1) == 0 )
+ return (vpic->readsel_isr ? vpic->isr : vpic->irr);
+
+ return vpic->imr;
+}
+
+static int vpic_intercept_pic_io(ioreq_t *p)
+{
+ struct vpic *vpic;
+ uint32_t data;
+
+ if ( (p->size != 1) || (p->count != 1) )
+ {
+ gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size);
+ return 1;
+ }
+
+ vpic = &current->domain->arch.hvm_domain.irq.vpic[p->addr >> 7];
+
+ if ( p->dir == IOREQ_WRITE )
+ {
+ if ( p->data_is_ptr )
+ (void)hvm_copy_from_guest_phys(&data, p->data, p->size);
+ else
+ data = p->data;
+ vpic_ioport_write(vpic, (uint32_t)p->addr, (uint8_t)data);
+ }
+ else
+ {
+ data = vpic_ioport_read(vpic, (uint32_t)p->addr);
+ if ( p->data_is_ptr )
+ (void)hvm_copy_to_guest_phys(p->data, &data, p->size);
+ else
+ p->data = (u64)data;
+ }
+
+ return 1;
+}
+
+static int vpic_intercept_elcr_io(ioreq_t *p)
+{
+ struct vpic *vpic;
+ uint32_t data;
+
+ if ( (p->size != 1) || (p->count != 1) )
+ {
+ gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size);
+ return 1;
+ }
+
+ vpic = &current->domain->arch.hvm_domain.irq.vpic[p->addr & 1];
+
+ if ( p->dir == IOREQ_WRITE )
+ {
+ if ( p->data_is_ptr )
+ (void)hvm_copy_from_guest_phys(&data, p->data, p->size);
+ else
+ data = p->data;
+
+ /* Some IRs are always edge trig. Slave IR is always level trig. */
+ data &= vpic_elcr_mask(vpic);
+ if ( vpic->is_master )
+ data |= 1 << 2;
+ vpic->elcr = data;
+ }
+ else
+ {
+ /* Reader should not see hardcoded level-triggered slave IR. */
+ data = vpic->elcr & vpic_elcr_mask(vpic);
+
+ if ( p->data_is_ptr )
+ (void)hvm_copy_to_guest_phys(p->data, &data, p->size);
+ else
+ p->data = data;
+ }
+
+ return 1;
+}
+
+void vpic_init(struct domain *d)
+{
+ struct vpic *vpic;
+
+ /* Master PIC. */
+ vpic = &d->arch.hvm_domain.irq.vpic[0];
+ memset(vpic, 0, sizeof(*vpic));
+ vpic->is_master = 1;
+ vpic->elcr = 1 << 2;
+ register_portio_handler(d, 0x20, 2, vpic_intercept_pic_io);
+ register_portio_handler(d, 0x4d0, 1, vpic_intercept_elcr_io);
+
+ /* Slave PIC. */
+ vpic++;
+ memset(vpic, 0, sizeof(*vpic));
+ register_portio_handler(d, 0xa0, 2, vpic_intercept_pic_io);
+ register_portio_handler(d, 0x4d1, 1, vpic_intercept_elcr_io);
+}
+
+void vpic_irq_positive_edge(struct domain *d, int irq)
+{
+ struct vpic *vpic = &d->arch.hvm_domain.irq.vpic[irq >> 3];
+ uint8_t mask = 1 << (irq & 7);
+
+ ASSERT(irq <= 15);
+ ASSERT(vpic_is_locked(vpic));
+
+ if ( irq == 2 )
+ return;
+
+ vpic->irr |= mask;
+ if ( !(vpic->imr & mask) )
+ vpic_update_int_output(vpic);
+}
+
+void vpic_irq_negative_edge(struct domain *d, int irq)
+{
+ struct vpic *vpic = &d->arch.hvm_domain.irq.vpic[irq >> 3];
+ uint8_t mask = 1 << (irq & 7);
+
+ ASSERT(irq <= 15);
+ ASSERT(vpic_is_locked(vpic));
+
+ if ( irq == 2 )
+ return;
+
+ vpic->irr &= ~mask;
+ if ( !(vpic->imr & mask) )
+ vpic_update_int_output(vpic);
+}
+
+int cpu_get_pic_interrupt(struct vcpu *v, int *type)
+{
+ int irq, vector;
+ struct vpic *vpic = &v->domain->arch.hvm_domain.irq.vpic[0];
+
+ if ( !vlapic_accept_pic_intr(v) || !vpic->int_output )
+ return -1;
+
+ irq = vpic_intack(vpic);
+ if ( irq == -1 )
+ return -1;
+
+ vector = vpic[irq >> 3].irq_base + (irq & 7);
+ *type = APIC_DM_EXTINT;
+ return vector;
+}
+
+int is_periodic_irq(struct vcpu *v, int irq, int type)
+{
+ int vec;
+ struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
+
+ if ( pt->irq != 0 )
+ return 0;
+
+ if ( type == APIC_DM_EXTINT )
+ vec = v->domain->arch.hvm_domain.irq.vpic[0].irq_base;
+ else
+ vec = domain_vioapic(v->domain)->redirtbl[0].fields.vector;
+
+ return (irq == vec);
+}
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
index ebfc37fa7b..899f80da3b 100644
--- a/xen/arch/x86/i387.c
+++ b/xen/arch/x86/i387.c
@@ -14,6 +14,7 @@
#include <asm/processor.h>
#include <asm/hvm/support.h>
#include <asm/i387.h>
+#include <asm/asm_defns.h>
void init_fpu(void)
{
@@ -41,11 +42,11 @@ void save_init_fpu(struct vcpu *v)
#else /* __x86_64__ */
/*
* The only way to force fxsaveq on a wide range of gas versions. On
- * older versions the rex64 prefix works only if we force an addressing
- * mode that doesn't require extended registers.
+ * older versions the rex64 prefix works only if we force an
+ * addressing mode that doesn't require extended registers.
*/
__asm__ __volatile__ (
- "rex64/fxsave (%1)"
+ REX64_PREFIX "fxsave (%1)"
: "=m" (*fpu_ctxt) : "cdaSDb" (fpu_ctxt) );
#endif
@@ -95,7 +96,7 @@ void restore_fpu(struct vcpu *v)
"1: fxrstor %0 \n"
#else /* __x86_64__ */
/* See above for why the operands/constraints are this way. */
- "1: rex64/fxrstor (%2) \n"
+ "1: " REX64_PREFIX "fxrstor (%2)\n"
#endif
".section .fixup,\"ax\" \n"
"2: push %%"__OP"ax \n"
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index c25f6b5d27..d56351e7aa 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -269,13 +269,10 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
int pin;
struct irq_pin_list *entry = irq_2_pin + irq;
unsigned int apicid_value;
- cpumask_t tmp;
-
- cpus_and(tmp, cpumask, cpu_online_map);
- if (cpus_empty(tmp))
- tmp = TARGET_CPUS;
- cpus_and(cpumask, tmp, CPU_MASK_ALL);
+ cpus_and(cpumask, cpumask, cpu_online_map);
+ if (cpus_empty(cpumask))
+ cpumask = TARGET_CPUS;
apicid_value = cpu_mask_to_apicid(cpumask);
/* Prepare to do the io_apic_write */
@@ -1143,7 +1140,8 @@ static void __init setup_ioapic_ids_from_mpc(void)
* Don't check I/O APIC IDs for xAPIC systems. They have
* no meaning without the serial APIC bus.
*/
- if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && boot_cpu_data.x86 < 15))
+ if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ || APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
return;
/*
@@ -1639,6 +1637,8 @@ static inline void unlock_ExtINT_logic(void)
spin_unlock_irqrestore(&ioapic_lock, flags);
}
+int timer_uses_ioapic_pin_0;
+
/*
* This code may look a bit paranoid, but it's supposed to cooperate with
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
@@ -1678,6 +1678,9 @@ static inline void check_timer(void)
pin2 = ioapic_i8259.pin;
apic2 = ioapic_i8259.apic;
+ if (pin1 == 0)
+ timer_uses_ioapic_pin_0 = 1;
+
printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
vector, apic1, pin1, apic2, pin2);
@@ -1977,7 +1980,8 @@ int ioapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval)
}
#define WARN_BOGUS_WRITE(f, a...) \
- DPRINTK("\n%s: apic=%d, pin=%d, old_irq=%d, new_irq=%d\n" \
+ dprintk(XENLOG_INFO, "\n%s: " \
+ "apic=%d, pin=%d, old_irq=%d, new_irq=%d\n" \
"%s: old_entry=%08x, new_entry=%08x\n" \
"%s: " f, __FUNCTION__, apic, pin, old_irq, new_irq, \
__FUNCTION__, *(u32 *)&old_rte, *(u32 *)&new_rte, \
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 36853ae67f..1821a56e24 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -351,11 +351,15 @@ int pirq_acktype(int irq)
desc = &irq_desc[vector];
+ if ( desc->handler == &no_irq_type )
+ return ACKTYPE_NONE;
+
/*
- * Edge-triggered IO-APIC interrupts need no final acknowledgement:
- * we ACK early during interrupt processing.
+ * Edge-triggered IO-APIC and LAPIC interrupts need no final
+ * acknowledgement: we ACK early during interrupt processing.
*/
- if ( !strcmp(desc->handler->typename, "IO-APIC-edge") )
+ if ( !strcmp(desc->handler->typename, "IO-APIC-edge") ||
+ !strcmp(desc->handler->typename, "local-APIC-edge") )
return ACKTYPE_NONE;
/*
@@ -376,7 +380,9 @@ int pirq_acktype(int irq)
return ACKTYPE_NONE; /* edge-triggered => no final EOI */
}
+ printk("Unknown PIC type '%s' for IRQ %d\n", desc->handler->typename, irq);
BUG();
+
return 0;
}
@@ -426,7 +432,8 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
{
if ( desc->action != NULL )
{
- DPRINTK("Cannot bind IRQ %d to guest. In use by '%s'.\n",
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. In use by '%s'.\n",
irq, desc->action->name);
rc = -EBUSY;
goto out;
@@ -435,7 +442,9 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
action = xmalloc(irq_guest_action_t);
if ( (desc->action = (struct irqaction *)action) == NULL )
{
- DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
+ gdprintk(XENLOG_INFO,
+ "Cannot bind IRQ %d to guest. Out of memory.\n",
+ irq);
rc = -ENOMEM;
goto out;
}
@@ -444,7 +453,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
action->in_flight = 0;
action->shareable = will_share;
action->ack_type = pirq_acktype(irq);
- action->cpu_eoi_map = CPU_MASK_NONE;
+ cpus_clear(action->cpu_eoi_map);
desc->depth = 0;
desc->status |= IRQ_GUEST;
@@ -458,7 +467,8 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
}
else if ( !will_share || !action->shareable )
{
- DPRINTK("Cannot bind IRQ %d to guest. Will not share with others.\n",
+ gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "
+ "Will not share with others.\n",
irq);
rc = -EBUSY;
goto out;
@@ -478,7 +488,8 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
if ( action->nr_guests == IRQ_MAX_GUESTS )
{
- DPRINTK("Cannot bind IRQ %d to guest. Already at max share.\n", irq);
+ gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "
+ "Already at max share.\n", irq);
rc = -EBUSY;
goto out;
}
diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
index 9c4b4d66f8..3dcac7d124 100644
--- a/xen/arch/x86/microcode.c
+++ b/xen/arch/x86/microcode.c
@@ -455,7 +455,7 @@ out:
return error;
}
-int microcode_update(void *buf, unsigned long len)
+int microcode_update(XEN_GUEST_HANDLE(void) buf, unsigned long len)
{
int ret;
@@ -464,10 +464,15 @@ int microcode_update(void *buf, unsigned long len)
return -EINVAL;
}
+ if (len != (typeof(user_buffer_size))len) {
+ printk(KERN_ERR "microcode: too much data\n");
+ return -E2BIG;
+ }
+
mutex_lock(&microcode_mutex);
- user_buffer = (void __user *) buf;
- user_buffer_size = (int) len;
+ user_buffer = buf.p;
+ user_buffer_size = len;
ret = do_microcode_update();
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 541938c073..6980960a71 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -108,13 +108,7 @@
#include <asm/e820.h>
#include <public/memory.h>
-#ifdef VERBOSE
-#define MEM_LOG(_f, _a...) \
- printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \
- current->domain->domain_id , __LINE__ , ## _a )
-#else
-#define MEM_LOG(_f, _a...) ((void)0)
-#endif
+#define MEM_LOG(_f, _a...) gdprintk(XENLOG_WARNING , _f "\n" , ## _a)
/*
* PTE updates can be done with ordinary writes except:
@@ -427,42 +421,30 @@ int map_ldt_shadow_page(unsigned int off)
unsigned long gmfn, mfn;
l1_pgentry_t l1e, nl1e;
unsigned long gva = v->arch.guest_context.ldt_base + (off << PAGE_SHIFT);
- int res;
-
-#if defined(__x86_64__)
- /* If in user mode, switch to kernel mode just to read LDT mapping. */
- int user_mode = !(v->arch.flags & TF_kernel_mode);
-#define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)
-#elif defined(__i386__)
-#define TOGGLE_MODE() ((void)0)
-#endif
+ int okay;
BUG_ON(unlikely(in_irq()));
- TOGGLE_MODE();
- __copy_from_user(&l1e, &linear_pg_table[l1_linear_offset(gva)],
- sizeof(l1e));
- TOGGLE_MODE();
-
+ guest_get_eff_kern_l1e(v, gva, &l1e);
if ( unlikely(!(l1e_get_flags(l1e) & _PAGE_PRESENT)) )
return 0;
gmfn = l1e_get_pfn(l1e);
mfn = gmfn_to_mfn(d, gmfn);
- if ( unlikely(!VALID_MFN(mfn)) )
+ if ( unlikely(!mfn_valid(mfn)) )
return 0;
- res = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page);
+ okay = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page);
- if ( !res && unlikely(shadow_mode_refcounts(d)) )
+ if ( !okay && unlikely(shadow_mode_refcounts(d)) )
{
shadow_lock(d);
shadow_remove_write_access(d->vcpu[0], _mfn(mfn), 0, 0);
- res = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page);
+ okay = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page);
shadow_unlock(d);
}
- if ( unlikely(!res) )
+ if ( unlikely(!okay) )
return 0;
nl1e = l1e_from_pfn(mfn, l1e_get_flags(l1e) | _PAGE_RW);
@@ -590,8 +572,9 @@ get_page_from_l1e(
if ( !iomem_access_permitted(d, mfn, mfn) )
{
- MEM_LOG("Non-privileged (%u) attempt to map I/O space %08lx",
- d->domain_id, mfn);
+ if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */
+ MEM_LOG("Non-privileged (%u) attempt to map I/O space %08lx",
+ d->domain_id, mfn);
return 0;
}
@@ -625,8 +608,7 @@ get_page_from_l1e(
/* NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'. */
static int
get_page_from_l2e(
- l2_pgentry_t l2e, unsigned long pfn,
- struct domain *d, unsigned long vaddr)
+ l2_pgentry_t l2e, unsigned long pfn, struct domain *d)
{
int rc;
@@ -639,10 +621,7 @@ get_page_from_l2e(
return 0;
}
- vaddr >>= L2_PAGETABLE_SHIFT;
- vaddr <<= PGT_va_shift;
- rc = get_page_and_type_from_pagenr(
- l2e_get_pfn(l2e), PGT_l1_page_table | vaddr, d);
+ rc = get_page_and_type_from_pagenr(l2e_get_pfn(l2e), PGT_l1_page_table, d);
#if CONFIG_PAGING_LEVELS == 2
if ( unlikely(!rc) )
rc = get_linear_pagetable(l2e, pfn, d);
@@ -654,8 +633,7 @@ get_page_from_l2e(
#if CONFIG_PAGING_LEVELS >= 3
static int
get_page_from_l3e(
- l3_pgentry_t l3e, unsigned long pfn,
- struct domain *d, unsigned long vaddr)
+ l3_pgentry_t l3e, unsigned long pfn, struct domain *d)
{
int rc;
@@ -668,11 +646,7 @@ get_page_from_l3e(
return 0;
}
- vaddr >>= L3_PAGETABLE_SHIFT;
- vaddr <<= PGT_va_shift;
- rc = get_page_and_type_from_pagenr(
- l3e_get_pfn(l3e),
- PGT_l2_page_table | vaddr, d);
+ rc = get_page_and_type_from_pagenr(l3e_get_pfn(l3e), PGT_l2_page_table, d);
return rc;
}
#endif /* 3 level */
@@ -680,8 +654,7 @@ get_page_from_l3e(
#if CONFIG_PAGING_LEVELS >= 4
static int
get_page_from_l4e(
- l4_pgentry_t l4e, unsigned long pfn,
- struct domain *d, unsigned long vaddr)
+ l4_pgentry_t l4e, unsigned long pfn, struct domain *d)
{
int rc;
@@ -694,11 +667,7 @@ get_page_from_l4e(
return 0;
}
- vaddr >>= L4_PAGETABLE_SHIFT;
- vaddr <<= PGT_va_shift;
- rc = get_page_and_type_from_pagenr(
- l4e_get_pfn(l4e),
- PGT_l3_page_table | vaddr, d);
+ rc = get_page_and_type_from_pagenr(l4e_get_pfn(l4e), PGT_l3_page_table, d);
if ( unlikely(!rc) )
rc = get_linear_pagetable(l4e, pfn, d);
@@ -708,11 +677,30 @@ get_page_from_l4e(
#endif /* 4 level */
#ifdef __x86_64__
+
+#ifdef USER_MAPPINGS_ARE_GLOBAL
+#define adjust_guest_l1e(pl1e) \
+ do { \
+ if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) ) \
+ { \
+ /* _PAGE_GUEST_KERNEL page cannot have the Global bit set. */ \
+ if ( (l1e_get_flags((pl1e)) & (_PAGE_GUEST_KERNEL|_PAGE_GLOBAL)) \
+ == (_PAGE_GUEST_KERNEL|_PAGE_GLOBAL) ) \
+ MEM_LOG("Global bit is set to kernel page %lx", \
+ l1e_get_pfn((pl1e))); \
+ if ( !(l1e_get_flags((pl1e)) & _PAGE_USER) ) \
+ l1e_add_flags((pl1e), (_PAGE_GUEST_KERNEL|_PAGE_USER)); \
+ if ( !(l1e_get_flags((pl1e)) & _PAGE_GUEST_KERNEL) ) \
+ l1e_add_flags((pl1e), (_PAGE_GLOBAL|_PAGE_USER)); \
+ } \
+ } while ( 0 )
+#else
#define adjust_guest_l1e(pl1e) \
- do { \
+ do { \
if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) ) \
l1e_add_flags((pl1e), _PAGE_USER); \
} while ( 0 )
+#endif
#define adjust_guest_l2e(pl2e) \
do { \
@@ -731,10 +719,13 @@ get_page_from_l4e(
if ( likely(l4e_get_flags((pl4e)) & _PAGE_PRESENT) ) \
l4e_add_flags((pl4e), _PAGE_USER); \
} while ( 0 )
-#else
+
+#else /* !defined(__x86_64__) */
+
#define adjust_guest_l1e(_p) ((void)0)
#define adjust_guest_l2e(_p) ((void)0)
#define adjust_guest_l3e(_p) ((void)0)
+
#endif
void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
@@ -877,8 +868,8 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e)
/*
* The Xen-private mappings include linear mappings. The L2 thus cannot
* be shared by multiple L3 tables. The test here is adequate because:
- * 1. Cannot appear in slots != 3 because the page would then then have
- * unknown va backpointer, which get_page_type() explicitly disallows.
+ * 1. Cannot appear in slots != 3 because get_page_type() checks the
+ * PGT_pae_xen_l2 flag, which is asserted iff the L2 appears in slot 3
* 2. Cannot appear in another page table's L3:
* a. alloc_l3_table() calls this function and this check will fail
* b. mod_l3_entry() disallows updates to slot 3 in an existing table
@@ -888,6 +879,7 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e)
page = l3e_get_page(l3e3);
BUG_ON(page->u.inuse.type_info & PGT_pinned);
BUG_ON((page->u.inuse.type_info & PGT_count_mask) == 0);
+ BUG_ON(!(page->u.inuse.type_info & PGT_pae_xen_l2));
if ( (page->u.inuse.type_info & PGT_count_mask) != 1 )
{
MEM_LOG("PAE L3 3rd slot is shared");
@@ -949,61 +941,17 @@ static void pae_flush_pgd(
flush_tlb_mask(d->domain_dirty_cpumask);
}
-static inline int l1_backptr(
- unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type)
-{
- unsigned long l2_backptr = l2_type & PGT_va_mask;
- ASSERT(l2_backptr != PGT_va_unknown);
- ASSERT(l2_backptr != PGT_va_mutable);
- *backptr =
- ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) |
- (offset_in_l2 << L2_PAGETABLE_SHIFT);
- return 1;
-}
-
#elif CONFIG_X86_64
# define create_pae_xen_mappings(pl3e) (1)
# define pae_flush_pgd(mfn, idx, nl3e) ((void)0)
-
-static inline int l1_backptr(
- unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type)
-{
- unsigned long l2_backptr = l2_type & PGT_va_mask;
- ASSERT(l2_backptr != PGT_va_unknown);
- ASSERT(l2_backptr != PGT_va_mutable);
- *backptr = ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) |
- (offset_in_l2 << L2_PAGETABLE_SHIFT);
- return 1;
-}
-
-static inline int l2_backptr(
- unsigned long *backptr, unsigned long offset_in_l3, unsigned long l3_type)
-{
- unsigned long l3_backptr = l3_type & PGT_va_mask;
- ASSERT(l3_backptr != PGT_va_unknown);
- ASSERT(l3_backptr != PGT_va_mutable);
- *backptr = ((l3_backptr >> PGT_va_shift) << L4_PAGETABLE_SHIFT) |
- (offset_in_l3 << L3_PAGETABLE_SHIFT);
- return 1;
-}
-
-static inline int l3_backptr(
- unsigned long *backptr, unsigned long offset_in_l4, unsigned long l4_type)
-{
- *backptr = (offset_in_l4 << L4_PAGETABLE_SHIFT);
- return 1;
-}
#else
# define create_pae_xen_mappings(pl3e) (1)
-# define l1_backptr(bp,l2o,l2t) \
- ({ *(bp) = (unsigned long)(l2o) << L2_PAGETABLE_SHIFT; 1; })
#endif
static int alloc_l2_table(struct page_info *page, unsigned long type)
{
struct domain *d = page_get_owner(page);
unsigned long pfn = page_to_mfn(page);
- unsigned long vaddr;
l2_pgentry_t *pl2e;
int i;
@@ -1013,10 +961,8 @@ static int alloc_l2_table(struct page_info *page, unsigned long type)
for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
{
- if ( !l1_backptr(&vaddr, i, type) )
- goto fail;
if ( is_guest_l2_slot(type, i) &&
- unlikely(!get_page_from_l2e(pl2e[i], pfn, d, vaddr)) )
+ unlikely(!get_page_from_l2e(pl2e[i], pfn, d)) )
goto fail;
adjust_guest_l2e(pl2e[i]);
@@ -1051,11 +997,10 @@ static int alloc_l2_table(struct page_info *page, unsigned long type)
#if CONFIG_PAGING_LEVELS >= 3
-static int alloc_l3_table(struct page_info *page, unsigned long type)
+static int alloc_l3_table(struct page_info *page)
{
struct domain *d = page_get_owner(page);
unsigned long pfn = page_to_mfn(page);
- unsigned long vaddr;
l3_pgentry_t *pl3e;
int i;
@@ -1079,14 +1024,21 @@ static int alloc_l3_table(struct page_info *page, unsigned long type)
pl3e = map_domain_page(pfn);
for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )
{
-#if CONFIG_PAGING_LEVELS >= 4
- if ( !l2_backptr(&vaddr, i, type) )
- goto fail;
-#else
- vaddr = (unsigned long)i << L3_PAGETABLE_SHIFT;
+#ifdef CONFIG_X86_PAE
+ if ( i == 3 )
+ {
+ if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) ||
+ (l3e_get_flags(pl3e[i]) & L3_DISALLOW_MASK) ||
+ !get_page_and_type_from_pagenr(l3e_get_pfn(pl3e[i]),
+ PGT_l2_page_table |
+ PGT_pae_xen_l2,
+ d) )
+ goto fail;
+ }
+ else
#endif
if ( is_guest_l3_slot(i) &&
- unlikely(!get_page_from_l3e(pl3e[i], pfn, d, vaddr)) )
+ unlikely(!get_page_from_l3e(pl3e[i], pfn, d)) )
goto fail;
adjust_guest_l3e(pl3e[i]);
@@ -1108,27 +1060,23 @@ static int alloc_l3_table(struct page_info *page, unsigned long type)
return 0;
}
#else
-#define alloc_l3_table(page, type) (0)
+#define alloc_l3_table(page) (0)
#endif
#if CONFIG_PAGING_LEVELS >= 4
-static int alloc_l4_table(struct page_info *page, unsigned long type)
+static int alloc_l4_table(struct page_info *page)
{
struct domain *d = page_get_owner(page);
unsigned long pfn = page_to_mfn(page);
l4_pgentry_t *pl4e = page_to_virt(page);
- unsigned long vaddr;
int i;
ASSERT(!shadow_mode_refcounts(d));
for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
{
- if ( !l3_backptr(&vaddr, i, type) )
- goto fail;
-
if ( is_guest_l4_slot(i) &&
- unlikely(!get_page_from_l4e(pl4e[i], pfn, d, vaddr)) )
+ unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) )
goto fail;
adjust_guest_l4e(pl4e[i]);
@@ -1156,7 +1104,7 @@ static int alloc_l4_table(struct page_info *page, unsigned long type)
return 0;
}
#else
-#define alloc_l4_table(page, type) (0)
+#define alloc_l4_table(page) (0)
#endif
@@ -1190,6 +1138,8 @@ static void free_l2_table(struct page_info *page)
put_page_from_l2e(pl2e[i], pfn);
unmap_domain_page(pl2e);
+
+ page->u.inuse.type_info &= ~PGT_pae_xen_l2;
}
@@ -1266,7 +1216,7 @@ static inline int update_l1e(l1_pgentry_t *pl1e,
}
}
#endif
- if ( unlikely(shadow_mode_enabled(v->domain)) )
+ if ( unlikely(shadow_mode_enabled(v->domain)) && rv )
{
shadow_validate_guest_entry(v, _mfn(gl1mfn), pl1e);
shadow_unlock(v->domain);
@@ -1285,8 +1235,15 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e,
if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) )
return 0;
+ if ( unlikely(shadow_mode_refcounts(d)) )
+ return update_l1e(pl1e, ol1e, nl1e, gl1mfn, current);
+
if ( l1e_get_flags(nl1e) & _PAGE_PRESENT )
{
+ /* Translate foreign guest addresses. */
+ nl1e = l1e_from_pfn(gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(nl1e)),
+ l1e_get_flags(nl1e));
+
if ( unlikely(l1e_get_flags(nl1e) & L1_DISALLOW_MASK) )
{
MEM_LOG("Bad L1 flags %x",
@@ -1357,7 +1314,6 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
unsigned long type)
{
l2_pgentry_t ol2e;
- unsigned long vaddr = 0;
if ( unlikely(!is_guest_l2_slot(type,pgentry_ptr_to_slot(pl2e))) )
{
@@ -1383,8 +1339,7 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT))
return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn);
- if ( unlikely(!l1_backptr(&vaddr, pgentry_ptr_to_slot(pl2e), type)) ||
- unlikely(!get_page_from_l2e(nl2e, pfn, current->domain, vaddr)) )
+ if ( unlikely(!get_page_from_l2e(nl2e, pfn, current->domain)) )
return 0;
if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn)) )
@@ -1407,11 +1362,9 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
/* Update the L3 entry at pl3e to new value nl3e. pl3e is within frame pfn. */
static int mod_l3_entry(l3_pgentry_t *pl3e,
l3_pgentry_t nl3e,
- unsigned long pfn,
- unsigned long type)
+ unsigned long pfn)
{
l3_pgentry_t ol3e;
- unsigned long vaddr;
int okay;
if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) )
@@ -1447,16 +1400,8 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT))
return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn);
-#if CONFIG_PAGING_LEVELS >= 4
- if ( unlikely(!l2_backptr(&vaddr, pgentry_ptr_to_slot(pl3e), type)) ||
- unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) )
- return 0;
-#else
- vaddr = (((unsigned long)pl3e & ~PAGE_MASK) / sizeof(l3_pgentry_t))
- << L3_PAGETABLE_SHIFT;
- if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) )
+ if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain)) )
return 0;
-#endif
if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn)) )
{
@@ -1485,11 +1430,9 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
/* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */
static int mod_l4_entry(l4_pgentry_t *pl4e,
l4_pgentry_t nl4e,
- unsigned long pfn,
- unsigned long type)
+ unsigned long pfn)
{
l4_pgentry_t ol4e;
- unsigned long vaddr;
if ( unlikely(!is_guest_l4_slot(pgentry_ptr_to_slot(pl4e))) )
{
@@ -1515,8 +1458,7 @@ static int mod_l4_entry(l4_pgentry_t *pl4e,
if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT))
return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn);
- if ( unlikely(!l3_backptr(&vaddr, pgentry_ptr_to_slot(pl4e), type)) ||
- unlikely(!get_page_from_l4e(nl4e, pfn, current->domain, vaddr)) )
+ if ( unlikely(!get_page_from_l4e(nl4e, pfn, current->domain)) )
return 0;
if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn)) )
@@ -1540,7 +1482,8 @@ int alloc_page_type(struct page_info *page, unsigned long type)
{
struct domain *owner = page_get_owner(page);
- if ( owner != NULL )
+ /* A page table is dirtied when its type count becomes non-zero. */
+ if ( likely(owner != NULL) )
mark_dirty(owner, page_to_mfn(page));
switch ( type & PGT_type_mask )
@@ -1550,9 +1493,9 @@ int alloc_page_type(struct page_info *page, unsigned long type)
case PGT_l2_page_table:
return alloc_l2_table(page, type);
case PGT_l3_page_table:
- return alloc_l3_table(page, type);
+ return alloc_l3_table(page);
case PGT_l4_page_table:
- return alloc_l4_table(page, type);
+ return alloc_l4_table(page);
case PGT_gdt_page:
case PGT_ldt_page:
return alloc_segdesc_page(page);
@@ -1581,21 +1524,17 @@ void free_page_type(struct page_info *page, unsigned long type)
*/
this_cpu(percpu_mm_info).deferred_ops |= DOP_FLUSH_ALL_TLBS;
- if ( unlikely(shadow_mode_enabled(owner)
- && !shadow_lock_is_acquired(owner)) )
+ if ( unlikely(shadow_mode_enabled(owner)) )
{
- /* Raw page tables are rewritten during save/restore. */
- if ( !shadow_mode_translate(owner) )
- mark_dirty(owner, page_to_mfn(page));
+ /* A page table is dirtied when its type count becomes zero. */
+ mark_dirty(owner, page_to_mfn(page));
if ( shadow_mode_refcounts(owner) )
return;
gmfn = mfn_to_gmfn(owner, page_to_mfn(page));
ASSERT(VALID_M2P(gmfn));
- shadow_lock(owner);
shadow_remove_all_shadows(owner->vcpu[0], _mfn(gmfn));
- shadow_unlock(owner);
}
}
@@ -1640,15 +1579,6 @@ void put_page_type(struct page_info *page)
ASSERT((x & PGT_count_mask) != 0);
- /*
- * The page should always be validated while a reference is held. The
- * exception is during domain destruction, when we forcibly invalidate
- * page-table pages if we detect a referential loop.
- * See domain.c:relinquish_list().
- */
- ASSERT((x & PGT_validated) ||
- test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
-
if ( unlikely((nx & PGT_count_mask) == 0) )
{
if ( unlikely((nx & PGT_type_mask) <= PGT_l4_page_table) &&
@@ -1669,14 +1599,16 @@ void put_page_type(struct page_info *page)
nx &= ~PGT_validated;
}
- /* Record TLB information for flush later. */
- page->tlbflush_timestamp = tlbflush_current_time();
- }
- else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) ==
- (PGT_pinned|PGT_l1_page_table|1)) )
- {
- /* Page is now only pinned. Make the back pointer mutable again. */
- nx |= PGT_va_mutable;
+ /*
+ * Record TLB information for flush later. We do not stamp page
+ * tables when running in shadow mode:
+ * 1. Pointless, since it's the shadow pt's which must be tracked.
+ * 2. Shadow mode reuses this field for shadowed page tables to
+ * store flags info -- we don't want to conflict with that.
+ */
+ if ( !(shadow_mode_enabled(page_get_owner(page)) &&
+ (page->count_info & PGC_page_table)) )
+ page->tlbflush_timestamp = tlbflush_current_time();
}
}
while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
@@ -1687,6 +1619,8 @@ int get_page_type(struct page_info *page, unsigned long type)
{
unsigned long nx, x, y = page->u.inuse.type_info;
+ ASSERT(!(type & ~(PGT_type_mask | PGT_pae_xen_l2)));
+
again:
do {
x = y;
@@ -1698,29 +1632,36 @@ int get_page_type(struct page_info *page, unsigned long type)
}
else if ( unlikely((x & PGT_count_mask) == 0) )
{
- if ( (x & (PGT_type_mask|PGT_va_mask)) != type )
+ struct domain *d = page_get_owner(page);
+
+ /* Never allow a shadowed frame to go from type count 0 to 1 */
+ if ( d && shadow_mode_enabled(d) )
+ shadow_remove_all_shadows(d->vcpu[0], _mfn(page_to_mfn(page)));
+
+ ASSERT(!(x & PGT_pae_xen_l2));
+ if ( (x & PGT_type_mask) != type )
{
- if ( (x & PGT_type_mask) != (type & PGT_type_mask) )
+ /*
+ * On type change we check to flush stale TLB entries. This
+ * may be unnecessary (e.g., page was GDT/LDT) but those
+ * circumstances should be very rare.
+ */
+ cpumask_t mask = d->domain_dirty_cpumask;
+
+ /* Don't flush if the timestamp is old enough */
+ tlbflush_filter(mask, page->tlbflush_timestamp);
+
+ if ( unlikely(!cpus_empty(mask)) &&
+ /* Shadow mode: track only writable pages. */
+ (!shadow_mode_enabled(page_get_owner(page)) ||
+ ((nx & PGT_type_mask) == PGT_writable_page)) )
{
- /*
- * On type change we check to flush stale TLB
- * entries. This may be unnecessary (e.g., page
- * was GDT/LDT) but those circumstances should be
- * very rare.
- */
- cpumask_t mask =
- page_get_owner(page)->domain_dirty_cpumask;
- tlbflush_filter(mask, page->tlbflush_timestamp);
-
- if ( unlikely(!cpus_empty(mask)) )
- {
- perfc_incrc(need_flush_tlb_flush);
- flush_tlb_mask(mask);
- }
+ perfc_incrc(need_flush_tlb_flush);
+ flush_tlb_mask(mask);
}
/* We lose existing type, back pointer, and validity. */
- nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated);
+ nx &= ~(PGT_type_mask | PGT_validated);
nx |= type;
/* No special validation needed for writable pages. */
@@ -1729,51 +1670,23 @@ int get_page_type(struct page_info *page, unsigned long type)
nx |= PGT_validated;
}
}
- else
+ else if ( unlikely((x & (PGT_type_mask|PGT_pae_xen_l2)) != type) )
{
- if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) )
- {
- if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) )
- {
- if ( ((x & PGT_type_mask) != PGT_l2_page_table) ||
- ((type & PGT_type_mask) != PGT_l1_page_table) )
- MEM_LOG("Bad type (saw %" PRtype_info
- " != exp %" PRtype_info ") "
- "for mfn %lx (pfn %lx)",
- x, type, page_to_mfn(page),
- get_gpfn_from_mfn(page_to_mfn(page)));
- return 0;
- }
- else if ( (x & PGT_va_mask) == PGT_va_mutable )
- {
- /* The va backpointer is mutable, hence we update it. */
- nx &= ~PGT_va_mask;
- nx |= type; /* we know the actual type is correct */
- }
- else if ( (type & PGT_va_mask) != PGT_va_mutable )
- {
- ASSERT((type & PGT_va_mask) != (x & PGT_va_mask));
-#ifdef CONFIG_X86_PAE
- /* We use backptr as extra typing. Cannot be unknown. */
- if ( (type & PGT_type_mask) == PGT_l2_page_table )
- return 0;
-#endif
- /* Fixme: add code to propagate va_unknown to subtables. */
- if ( ((type & PGT_type_mask) >= PGT_l2_page_table) &&
- !shadow_mode_refcounts(page_get_owner(page)) )
- return 0;
- /* This table is possibly mapped at multiple locations. */
- nx &= ~PGT_va_mask;
- nx |= PGT_va_unknown;
- }
- }
- if ( unlikely(!(x & PGT_validated)) )
- {
- /* Someone else is updating validation of this page. Wait... */
- while ( (y = page->u.inuse.type_info) == x )
- cpu_relax();
- goto again;
- }
+ if ( ((x & PGT_type_mask) != PGT_l2_page_table) ||
+ (type != PGT_l1_page_table) )
+ MEM_LOG("Bad type (saw %" PRtype_info
+ " != exp %" PRtype_info ") "
+ "for mfn %lx (pfn %lx)",
+ x, type, page_to_mfn(page),
+ get_gpfn_from_mfn(page_to_mfn(page)));
+ return 0;
+ }
+ else if ( unlikely(!(x & PGT_validated)) )
+ {
+ /* Someone else is updating validation of this page. Wait... */
+ while ( (y = page->u.inuse.type_info) == x )
+ cpu_relax();
+ goto again;
}
}
while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
@@ -1807,8 +1720,8 @@ int new_guest_cr3(unsigned long mfn)
int okay;
unsigned long old_base_mfn;
- if ( hvm_guest(v) && !hvm_paging_enabled(v) )
- domain_crash_synchronous();
+ if ( is_hvm_domain(d) && !hvm_paging_enabled(v) )
+ return 0;
if ( shadow_mode_refcounts(d) )
{
@@ -1905,12 +1818,17 @@ static int set_foreigndom(domid_t domid)
if ( likely(domid == DOMID_SELF) )
goto out;
- if ( domid == d->domain_id )
+ if ( unlikely(domid == d->domain_id) )
{
MEM_LOG("Dom %u tried to specify itself as foreign domain",
d->domain_id);
okay = 0;
}
+ else if ( unlikely(shadow_mode_translate(d)) )
+ {
+ MEM_LOG("Cannot mix foreign mappings with translated domains");
+ okay = 0;
+ }
else if ( !IS_PRIV(d) )
{
switch ( domid )
@@ -1979,7 +1897,7 @@ int do_mmuext_op(
{
struct mmuext_op op;
int rc = 0, i = 0, okay;
- unsigned long mfn, type;
+ unsigned long mfn = 0, gmfn = 0, type;
unsigned int done = 0;
struct page_info *page;
struct vcpu *v = current;
@@ -2024,25 +1942,32 @@ int do_mmuext_op(
}
okay = 1;
- mfn = op.arg1.mfn;
+ gmfn = op.arg1.mfn;
+ mfn = gmfn_to_mfn(FOREIGNDOM, gmfn);
page = mfn_to_page(mfn);
switch ( op.cmd )
{
case MMUEXT_PIN_L1_TABLE:
- type = PGT_l1_page_table | PGT_va_mutable;
+ type = PGT_l1_page_table;
goto pin_page;
case MMUEXT_PIN_L2_TABLE:
+ type = PGT_l2_page_table;
+ goto pin_page;
+
case MMUEXT_PIN_L3_TABLE:
- case MMUEXT_PIN_L4_TABLE:
- /* Ignore pinning of subdirectories. */
- if ( (op.cmd - MMUEXT_PIN_L1_TABLE) != (CONFIG_PAGING_LEVELS - 1) )
- break;
+ type = PGT_l3_page_table;
+ goto pin_page;
- type = PGT_root_page_table;
+ case MMUEXT_PIN_L4_TABLE:
+ type = PGT_l4_page_table;
pin_page:
+ /* Ignore pinning of invalid paging levels. */
+ if ( (op.cmd - MMUEXT_PIN_L1_TABLE) > (CONFIG_PAGING_LEVELS - 1) )
+ break;
+
if ( shadow_mode_refcounts(FOREIGNDOM) )
break;
@@ -2061,7 +1986,10 @@ int do_mmuext_op(
okay = 0;
break;
}
-
+
+ /* A page is dirtied when its pin status is set. */
+ mark_dirty(d, mfn);
+
break;
case MMUEXT_UNPIN_TABLE:
@@ -2078,12 +2006,8 @@ int do_mmuext_op(
{
put_page_and_type(page);
put_page(page);
- if ( shadow_mode_enabled(d) )
- {
- shadow_lock(d);
- shadow_remove_all_shadows(v, _mfn(mfn));
- shadow_unlock(d);
- }
+ /* A page is dirtied when its pin status is cleared. */
+ mark_dirty(d, mfn);
}
else
{
@@ -2094,7 +2018,6 @@ int do_mmuext_op(
break;
case MMUEXT_NEW_BASEPTR:
- mfn = gmfn_to_mfn(current->domain, mfn);
okay = new_guest_cr3(mfn);
this_cpu(percpu_mm_info).deferred_ops &= ~DOP_FLUSH_TLB;
break;
@@ -2103,8 +2026,13 @@ int do_mmuext_op(
case MMUEXT_NEW_USER_BASEPTR:
okay = 1;
if (likely(mfn != 0))
- okay = get_page_and_type_from_pagenr(
- mfn, PGT_root_page_table, d);
+ {
+ if ( shadow_mode_refcounts(d) )
+ okay = get_page_from_pagenr(mfn, d);
+ else
+ okay = get_page_and_type_from_pagenr(
+ mfn, PGT_root_page_table, d);
+ }
if ( unlikely(!okay) )
{
MEM_LOG("Error while installing new mfn %lx", mfn);
@@ -2115,7 +2043,12 @@ int do_mmuext_op(
pagetable_get_pfn(v->arch.guest_table_user);
v->arch.guest_table_user = pagetable_from_pfn(mfn);
if ( old_mfn != 0 )
- put_page_and_type(mfn_to_page(old_mfn));
+ {
+ if ( shadow_mode_refcounts(d) )
+ put_page(mfn_to_page(old_mfn));
+ else
+ put_page_and_type(mfn_to_page(old_mfn));
+ }
}
break;
#endif
@@ -2135,7 +2068,7 @@ int do_mmuext_op(
{
unsigned long vmask;
cpumask_t pmask;
- if ( unlikely(get_user(vmask, (unsigned long *)op.arg2.vcpumask)) )
+ if ( unlikely(copy_from_guest(&vmask, op.arg2.vcpumask, 1)) )
{
okay = 0;
break;
@@ -2202,13 +2135,14 @@ int do_mmuext_op(
default:
MEM_LOG("Invalid extended pt command 0x%x", op.cmd);
+ rc = -ENOSYS;
okay = 0;
break;
}
if ( unlikely(!okay) )
{
- rc = -EINVAL;
+ rc = rc ? rc : -EINVAL;
break;
}
@@ -2219,9 +2153,11 @@ int do_mmuext_op(
process_deferred_ops();
/* Add incremental work we have done to the @done output parameter. */
- done += i;
if ( unlikely(!guest_handle_is_null(pdone)) )
+ {
+ done += i;
copy_to_guest(pdone, &done, 1);
+ }
UNLOCK_BIGLOCK(d);
return rc;
@@ -2321,12 +2257,12 @@ int do_mmu_update(
{
if ( shadow_mode_refcounts(d) )
{
- DPRINTK("mmu update on shadow-refcounted domain!");
+ MEM_LOG("mmu update on shadow-refcounted domain!");
break;
}
if ( unlikely(!get_page_type(
- page, type_info & (PGT_type_mask|PGT_va_mask))) )
+ page, type_info & (PGT_type_mask|PGT_pae_xen_l2))) )
goto not_a_pt;
switch ( type_info & PGT_type_mask )
@@ -2348,7 +2284,7 @@ int do_mmu_update(
case PGT_l3_page_table:
{
l3_pgentry_t l3e = l3e_from_intpte(req.val);
- okay = mod_l3_entry(va, l3e, mfn, type_info);
+ okay = mod_l3_entry(va, l3e, mfn);
}
break;
#endif
@@ -2356,7 +2292,7 @@ int do_mmu_update(
case PGT_l4_page_table:
{
l4_pgentry_t l4e = l4e_from_intpte(req.val);
- okay = mod_l4_entry(va, l4e, mfn, type_info);
+ okay = mod_l4_entry(va, l4e, mfn);
}
break;
#endif
@@ -2405,13 +2341,15 @@ int do_mmu_update(
break;
}
- if ( shadow_mode_translate(FOREIGNDOM) )
- shadow_guest_physmap_add_page(FOREIGNDOM, gpfn, mfn);
- else
- set_gpfn_from_mfn(mfn, gpfn);
+ if ( unlikely(shadow_mode_translate(FOREIGNDOM)) )
+ {
+ MEM_LOG("Mach-phys update on shadow-translate guest");
+ break;
+ }
+
+ set_gpfn_from_mfn(mfn, gpfn);
okay = 1;
- // Mark the new gfn dirty...
mark_dirty(FOREIGNDOM, mfn);
put_page(mfn_to_page(mfn));
@@ -2419,12 +2357,14 @@ int do_mmu_update(
default:
MEM_LOG("Invalid page update command %x", cmd);
+ rc = -ENOSYS;
+ okay = 0;
break;
}
if ( unlikely(!okay) )
{
- rc = -EINVAL;
+ rc = rc ? rc : -EINVAL;
break;
}
@@ -2438,9 +2378,11 @@ int do_mmu_update(
process_deferred_ops();
/* Add incremental work we have done to the @done output parameter. */
- done += i;
if ( unlikely(!guest_handle_is_null(pdone)) )
+ {
+ done += i;
copy_to_guest(pdone, &done, 1);
+ }
UNLOCK_BIGLOCK(d);
return rc;
@@ -2448,13 +2390,13 @@ int do_mmu_update(
static int create_grant_pte_mapping(
- unsigned long pte_addr, l1_pgentry_t nl1e, struct vcpu *v)
+ uint64_t pte_addr, l1_pgentry_t nl1e, struct vcpu *v)
{
int rc = GNTST_okay;
void *va;
unsigned long gmfn, mfn;
struct page_info *page;
- u32 type_info;
+ u32 type;
l1_pgentry_t ol1e;
struct domain *d = v->domain;
@@ -2472,12 +2414,11 @@ static int create_grant_pte_mapping(
}
va = map_domain_page(mfn);
- va = (void *)((unsigned long)va + (pte_addr & ~PAGE_MASK));
+ va = (void *)((unsigned long)va + ((unsigned long)pte_addr & ~PAGE_MASK));
page = mfn_to_page(mfn);
- type_info = page->u.inuse.type_info;
- if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) ||
- !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) )
+ type = page->u.inuse.type_info & PGT_type_mask;
+ if ( (type != PGT_l1_page_table) || !get_page_type(page, type) )
{
MEM_LOG("Grant map attempted to update a non-L1 page");
rc = GNTST_general_error;
@@ -2505,13 +2446,13 @@ static int create_grant_pte_mapping(
}
static int destroy_grant_pte_mapping(
- unsigned long addr, unsigned long frame, struct domain *d)
+ uint64_t addr, unsigned long frame, struct domain *d)
{
int rc = GNTST_okay;
void *va;
unsigned long gmfn, mfn;
struct page_info *page;
- u32 type_info;
+ u32 type;
l1_pgentry_t ol1e;
gmfn = addr >> PAGE_SHIFT;
@@ -2524,12 +2465,11 @@ static int destroy_grant_pte_mapping(
}
va = map_domain_page(mfn);
- va = (void *)((unsigned long)va + (addr & ~PAGE_MASK));
+ va = (void *)((unsigned long)va + ((unsigned long)addr & ~PAGE_MASK));
page = mfn_to_page(mfn);
- type_info = page->u.inuse.type_info;
- if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) ||
- !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) )
+ type = page->u.inuse.type_info & PGT_type_mask;
+ if ( (type != PGT_l1_page_table) || !get_page_type(page, type) )
{
MEM_LOG("Grant map attempted to update a non-L1 page");
rc = GNTST_general_error;
@@ -2546,7 +2486,7 @@ static int destroy_grant_pte_mapping(
/* Check that the virtual address supplied is actually mapped to frame. */
if ( unlikely((l1e_get_intpte(ol1e) >> PAGE_SHIFT) != frame) )
{
- MEM_LOG("PTE entry %lx for address %lx doesn't match frame %lx",
+ MEM_LOG("PTE entry %lx for address %"PRIx64" doesn't match frame %lx",
(unsigned long)l1e_get_intpte(ol1e), addr, frame);
put_page_type(page);
rc = GNTST_general_error;
@@ -2578,17 +2518,26 @@ static int create_grant_va_mapping(
{
l1_pgentry_t *pl1e, ol1e;
struct domain *d = v->domain;
+ unsigned long gl1mfn;
+ int okay;
ASSERT(spin_is_locked(&d->big_lock));
adjust_guest_l1e(nl1e);
- pl1e = &linear_pg_table[l1_linear_offset(va)];
-
- if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) ||
- !update_l1e(pl1e, ol1e, nl1e,
- l2e_get_pfn(__linear_l2_table[l2_linear_offset(va)]), v) )
+ pl1e = guest_map_l1e(v, va, &gl1mfn);
+ if ( !pl1e )
+ {
+ MEM_LOG("Could not find L1 PTE for address %lx", va);
return GNTST_general_error;
+ }
+ ol1e = *pl1e;
+ okay = update_l1e(pl1e, ol1e, nl1e, gl1mfn, v);
+ guest_unmap_l1e(v, pl1e);
+ pl1e = NULL;
+
+ if ( !okay )
+ return GNTST_general_error;
if ( !shadow_mode_refcounts(d) )
put_page_from_l1e(ol1e, d);
@@ -2597,43 +2546,44 @@ static int create_grant_va_mapping(
}
static int destroy_grant_va_mapping(
- unsigned long addr, unsigned long frame, struct domain *d)
+ unsigned long addr, unsigned long frame, struct vcpu *v)
{
l1_pgentry_t *pl1e, ol1e;
+ unsigned long gl1mfn;
+ int rc = 0;
- pl1e = &linear_pg_table[l1_linear_offset(addr)];
-
- if ( unlikely(__get_user(ol1e.l1, &pl1e->l1) != 0) )
+ pl1e = guest_map_l1e(v, addr, &gl1mfn);
+ if ( !pl1e )
{
- MEM_LOG("Could not find PTE entry for address %lx", addr);
+ MEM_LOG("Could not find L1 PTE for address %lx", addr);
return GNTST_general_error;
}
+ ol1e = *pl1e;
- /*
- * Check that the virtual address supplied is actually mapped to
- * frame.
- */
+ /* Check that the virtual address supplied is actually mapped to frame. */
if ( unlikely(l1e_get_pfn(ol1e) != frame) )
{
MEM_LOG("PTE entry %lx for address %lx doesn't match frame %lx",
l1e_get_pfn(ol1e), addr, frame);
- return GNTST_general_error;
+ rc = GNTST_general_error;
+ goto out;
}
/* Delete pagetable entry. */
- if ( unlikely(!update_l1e(pl1e, ol1e, l1e_empty(),
- l2e_get_pfn(__linear_l2_table[l2_linear_offset(addr)]),
- d->vcpu[0] /* Change for per-vcpu shadows */)) )
+ if ( unlikely(!update_l1e(pl1e, ol1e, l1e_empty(), gl1mfn, v)) )
{
MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
- return GNTST_general_error;
+ rc = GNTST_general_error;
+ goto out;
}
- return 0;
+ out:
+ guest_unmap_l1e(v, pl1e);
+ return rc;
}
int create_grant_host_mapping(
- unsigned long addr, unsigned long frame, unsigned int flags)
+ uint64_t addr, unsigned long frame, unsigned int flags)
{
l1_pgentry_t pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
@@ -2648,11 +2598,11 @@ int create_grant_host_mapping(
}
int destroy_grant_host_mapping(
- unsigned long addr, unsigned long frame, unsigned int flags)
+ uint64_t addr, unsigned long frame, unsigned int flags)
{
if ( flags & GNTMAP_contains_pte )
return destroy_grant_pte_mapping(addr, frame, current->domain);
- return destroy_grant_va_mapping(addr, frame, current->domain);
+ return destroy_grant_va_mapping(addr, frame, current);
}
int steal_page(
@@ -2674,7 +2624,7 @@ int steal_page(
x = y;
if (unlikely((x & (PGC_count_mask|PGC_allocated)) !=
(1 | PGC_allocated)) || unlikely(_nd != _d)) {
- DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p,"
+ MEM_LOG("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p,"
" caf=%08x, taf=%" PRtype_info "\n",
(void *) page_to_mfn(page),
d, d->domain_id, unpickle_domptr(_nd), x,
@@ -2708,7 +2658,8 @@ int do_update_va_mapping(unsigned long va, u64 val64,
l1_pgentry_t val = l1e_from_intpte(val64);
struct vcpu *v = current;
struct domain *d = v->domain;
- unsigned long vmask, bmap_ptr;
+ l1_pgentry_t *pl1e;
+ unsigned long vmask, bmap_ptr, gl1mfn;
cpumask_t pmask;
int rc = 0;
@@ -2717,35 +2668,17 @@ int do_update_va_mapping(unsigned long va, u64 val64,
if ( unlikely(!__addr_ok(va) && !shadow_mode_external(d)) )
return -EINVAL;
- if ( unlikely(shadow_mode_refcounts(d)) )
- {
- DPRINTK("Grant op on a shadow-refcounted domain\n");
- return -EINVAL;
- }
-
LOCK_BIGLOCK(d);
- if ( likely(rc == 0) && unlikely(shadow_mode_enabled(d)) )
- {
- if ( unlikely(this_cpu(percpu_mm_info).foreign &&
- (shadow_mode_translate(d) ||
- shadow_mode_translate(
- this_cpu(percpu_mm_info).foreign))) )
- {
- /*
- * The foreign domain's pfn's are in a different namespace. There's
- * not enough information in just a gpte to figure out how to
- * (re-)shadow this entry.
- */
- domain_crash(d);
- }
- }
+ pl1e = guest_map_l1e(v, va, &gl1mfn);
- if ( unlikely(!mod_l1_entry(
- &linear_pg_table[l1_linear_offset(va)], val,
- l2e_get_pfn(__linear_l2_table[l2_linear_offset(va)]))) )
+ if ( unlikely(!pl1e || !mod_l1_entry(pl1e, val, gl1mfn)) )
rc = -EINVAL;
-
+
+ if ( pl1e )
+ guest_unmap_l1e(v, pl1e);
+ pl1e = NULL;
+
switch ( flags & UVMF_FLUSHTYPE_MASK )
{
case UVMF_TLB_FLUSH:
@@ -2914,8 +2847,8 @@ long do_update_descriptor(u64 pa, u64 desc)
LOCK_BIGLOCK(dom);
- if ( !VALID_MFN(mfn = gmfn_to_mfn(dom, gmfn)) ||
- (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
+ mfn = gmfn_to_mfn(dom, gmfn);
+ if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
!mfn_valid(mfn) ||
!check_descriptor(&d) )
{
@@ -3107,7 +3040,7 @@ static int ptwr_emulated_update(
unsigned int bytes,
unsigned int do_cmpxchg)
{
- unsigned long pfn;
+ unsigned long gmfn, mfn;
struct page_info *page;
l1_pgentry_t pte, ol1e, nl1e, *pl1e;
struct vcpu *v = current;
@@ -3147,15 +3080,17 @@ static int ptwr_emulated_update(
}
/* Read the PTE that maps the page being updated. */
- if ( __copy_from_user(&pte, &linear_pg_table[l1_linear_offset(addr)],
- sizeof(pte)) )
+ guest_get_eff_l1e(v, addr, &pte);
+ if ( unlikely(!(l1e_get_flags(pte) & _PAGE_PRESENT)) )
{
- MEM_LOG("ptwr_emulate: Cannot read thru linear_pg_table");
+ MEM_LOG("%s: Cannot get L1 PTE for guest address %lx",
+ __func__, addr);
return X86EMUL_UNHANDLEABLE;
}
- pfn = l1e_get_pfn(pte);
- page = mfn_to_page(pfn);
+ gmfn = l1e_get_pfn(pte);
+ mfn = gmfn_to_mfn(d, gmfn);
+ page = mfn_to_page(mfn);
/* We are looking only for read-only mappings of p.t. pages. */
ASSERT((l1e_get_flags(pte) & (_PAGE_RW|_PAGE_PRESENT)) == _PAGE_PRESENT);
@@ -3165,7 +3100,7 @@ static int ptwr_emulated_update(
/* Check the new PTE. */
nl1e = l1e_from_intpte(val);
- if ( unlikely(!get_page_from_l1e(nl1e, d)) )
+ if ( unlikely(!get_page_from_l1e(gl1e_to_ml1e(d, nl1e), d)) )
{
if ( (CONFIG_PAGING_LEVELS == 3) &&
(bytes == 4) &&
@@ -3178,7 +3113,7 @@ static int ptwr_emulated_update(
* zap the PRESENT bit on the assumption the bottom half will be
* written immediately after we return to the guest.
*/
- MEM_LOG("ptwr_emulate: fixing up invalid PAE PTE %"PRIpte"\n",
+ MEM_LOG("ptwr_emulate: fixing up invalid PAE PTE %"PRIpte,
l1e_get_intpte(nl1e));
l1e_remove_flags(nl1e, _PAGE_PRESENT);
}
@@ -3204,13 +3139,13 @@ static int ptwr_emulated_update(
if ( shadow_mode_enabled(d) )
shadow_unlock(d);
unmap_domain_page(pl1e);
- put_page_from_l1e(nl1e, d);
+ put_page_from_l1e(gl1e_to_ml1e(d, nl1e), d);
return X86EMUL_CMPXCHG_FAILED;
}
- if ( unlikely(shadow_mode_enabled(v->domain)) )
+ if ( unlikely(shadow_mode_enabled(d)) )
{
shadow_validate_guest_entry(v, _mfn(page_to_mfn(page)), pl1e);
- shadow_unlock(v->domain);
+ shadow_unlock(d);
}
}
else
@@ -3223,7 +3158,7 @@ static int ptwr_emulated_update(
unmap_domain_page(pl1e);
/* Finally, drop the old PTE. */
- put_page_from_l1e(ol1e, d);
+ put_page_from_l1e(gl1e_to_ml1e(d, ol1e), d);
return X86EMUL_CONTINUE;
}
@@ -3272,13 +3207,13 @@ static struct x86_emulate_ops ptwr_emulate_ops = {
};
/* Write page fault handler: check if guest is trying to modify a PTE. */
-int ptwr_do_page_fault(struct domain *d, unsigned long addr,
+int ptwr_do_page_fault(struct vcpu *v, unsigned long addr,
struct cpu_user_regs *regs)
{
+ struct domain *d = v->domain;
unsigned long pfn;
struct page_info *page;
l1_pgentry_t pte;
- l2_pgentry_t *pl2e, l2e;
struct x86_emulate_ctxt emul_ctxt;
LOCK_BIGLOCK(d);
@@ -3287,13 +3222,9 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr,
* Attempt to read the PTE that maps the VA being accessed. By checking for
* PDE validity in the L2 we avoid many expensive fixups in __get_user().
*/
- pl2e = &__linear_l2_table[l2_linear_offset(addr)];
- if ( __copy_from_user(&l2e, pl2e, sizeof(l2e)) ||
- !(l2e_get_flags(l2e) & _PAGE_PRESENT) ||
- __copy_from_user(&pte, &linear_pg_table[l1_linear_offset(addr)],
- sizeof(pte)) )
+ guest_get_eff_l1e(v, addr, &pte);
+ if ( !(l1e_get_flags(pte) & _PAGE_PRESENT) )
goto bail;
-
pfn = l1e_get_pfn(pte);
page = mfn_to_page(pfn);
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index 664b09f209..cad0ea4cc9 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -21,8 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define SHADOW 1
-
#include <xen/config.h>
#include <xen/types.h>
#include <xen/mm.h>
@@ -77,35 +75,27 @@ sh_x86_emulate_read_std(unsigned long addr,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
- struct vcpu *v = current;
- if ( hvm_guest(v) )
+ *val = 0;
+ // XXX -- this is WRONG.
+ // It entirely ignores the permissions in the page tables.
+ // In this case, that is only a user vs supervisor access check.
+ //
+ if ( hvm_copy_from_guest_virt(val, addr, bytes) == 0 )
{
- *val = 0;
- // XXX -- this is WRONG.
- // It entirely ignores the permissions in the page tables.
- // In this case, that is only a user vs supervisor access check.
- //
- if ( hvm_copy(val, addr, bytes, HVM_COPY_IN) )
- {
#if 0
- SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
- v->domain->domain_id, v->vcpu_id,
- addr, *val, bytes);
+ struct vcpu *v = current;
+ SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
+ v->domain->domain_id, v->vcpu_id,
+ addr, *val, bytes);
#endif
- return X86EMUL_CONTINUE;
- }
-
- /* If we got here, there was nothing mapped here, or a bad GFN
- * was mapped here. This should never happen: we're here because
- * of a write fault at the end of the instruction we're emulating. */
- SHADOW_PRINTK("read failed to va %#lx\n", addr);
- return X86EMUL_PROPAGATE_FAULT;
- }
- else
- {
- SHADOW_PRINTK("this operation is not emulated yet\n");
- return X86EMUL_UNHANDLEABLE;
+ return X86EMUL_CONTINUE;
}
+
+ /* If we got here, there was nothing mapped here, or a bad GFN
+ * was mapped here. This should never happen: we're here because
+ * of a write fault at the end of the instruction we're emulating. */
+ SHADOW_PRINTK("read failed to va %#lx\n", addr);
+ return X86EMUL_PROPAGATE_FAULT;
}
static int
@@ -114,33 +104,26 @@ sh_x86_emulate_write_std(unsigned long addr,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
- struct vcpu *v = current;
#if 0
+ struct vcpu *v = current;
SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
v->domain->domain_id, v->vcpu_id, addr, val, bytes);
#endif
- if ( hvm_guest(v) )
- {
- // XXX -- this is WRONG.
- // It entirely ignores the permissions in the page tables.
- // In this case, that includes user vs supervisor, and
- // write access.
- //
- if ( hvm_copy(&val, addr, bytes, HVM_COPY_OUT) )
- return X86EMUL_CONTINUE;
-
- /* If we got here, there was nothing mapped here, or a bad GFN
- * was mapped here. This should never happen: we're here because
- * of a write fault at the end of the instruction we're emulating,
- * which should be handled by sh_x86_emulate_write_emulated. */
- SHADOW_PRINTK("write failed to va %#lx\n", addr);
- return X86EMUL_PROPAGATE_FAULT;
- }
- else
- {
- SHADOW_PRINTK("this operation is not emulated yet\n");
- return X86EMUL_UNHANDLEABLE;
- }
+
+ // XXX -- this is WRONG.
+ // It entirely ignores the permissions in the page tables.
+ // In this case, that includes user vs supervisor, and
+ // write access.
+ //
+ if ( hvm_copy_to_guest_virt(addr, &val, bytes) == 0 )
+ return X86EMUL_CONTINUE;
+
+ /* If we got here, there was nothing mapped here, or a bad GFN
+ * was mapped here. This should never happen: we're here because
+ * of a write fault at the end of the instruction we're emulating,
+ * which should be handled by sh_x86_emulate_write_emulated. */
+ SHADOW_PRINTK("write failed to va %#lx\n", addr);
+ return X86EMUL_PROPAGATE_FAULT;
}
static int
@@ -154,15 +137,7 @@ sh_x86_emulate_write_emulated(unsigned long addr,
SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
v->domain->domain_id, v->vcpu_id, addr, val, bytes);
#endif
- if ( hvm_guest(v) )
- {
- return v->arch.shadow.mode->x86_emulate_write(v, addr, &val, bytes, ctxt);
- }
- else
- {
- SHADOW_PRINTK("this operation is not emulated yet\n");
- return X86EMUL_UNHANDLEABLE;
- }
+ return v->arch.shadow.mode->x86_emulate_write(v, addr, &val, bytes, ctxt);
}
static int
@@ -177,16 +152,8 @@ sh_x86_emulate_cmpxchg_emulated(unsigned long addr,
SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n",
v->domain->domain_id, v->vcpu_id, addr, old, new, bytes);
#endif
- if ( hvm_guest(v) )
- {
- return v->arch.shadow.mode->x86_emulate_cmpxchg(v, addr, old, new,
- bytes, ctxt);
- }
- else
- {
- SHADOW_PRINTK("this operation is not emulated yet\n");
- return X86EMUL_UNHANDLEABLE;
- }
+ return v->arch.shadow.mode->x86_emulate_cmpxchg(v, addr, old, new,
+ bytes, ctxt);
}
static int
@@ -203,16 +170,8 @@ sh_x86_emulate_cmpxchg8b_emulated(unsigned long addr,
v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo,
new_hi, new_lo, ctxt);
#endif
- if ( hvm_guest(v) )
- {
- return v->arch.shadow.mode->x86_emulate_cmpxchg8b(v, addr, old_lo, old_hi,
- new_lo, new_hi, ctxt);
- }
- else
- {
- SHADOW_PRINTK("this operation is not emulated yet\n");
- return X86EMUL_UNHANDLEABLE;
- }
+ return v->arch.shadow.mode->x86_emulate_cmpxchg8b(v, addr, old_lo, old_hi,
+ new_lo, new_hi, ctxt);
}
@@ -225,45 +184,27 @@ struct x86_emulate_ops shadow_emulator_ops = {
.cmpxchg8b_emulated = sh_x86_emulate_cmpxchg8b_emulated,
};
-
/**************************************************************************/
/* Code for "promoting" a guest page to the point where the shadow code is
* willing to let it be treated as a guest page table. This generally
* involves making sure there are no writable mappings available to the guest
* for this page.
*/
-void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type)
+void shadow_promote(struct vcpu *v, mfn_t gmfn, unsigned int type)
{
struct page_info *page = mfn_to_page(gmfn);
- unsigned long type_info;
- ASSERT(valid_mfn(gmfn));
+ ASSERT(mfn_valid(gmfn));
/* We should never try to promote a gmfn that has writeable mappings */
ASSERT(shadow_remove_write_access(v, gmfn, 0, 0) == 0);
- // Is the page already shadowed?
+ /* Is the page already shadowed? */
if ( !test_and_set_bit(_PGC_page_table, &page->count_info) )
- {
- // No prior shadow exists...
-
- // Grab a type-ref. We don't really care if we are racing with another
- // vcpu or not, or even what kind of type we get; we just want the type
- // count to be > 0.
- //
- do {
- type_info =
- page->u.inuse.type_info & (PGT_type_mask | PGT_va_mask);
- } while ( !get_page_type(page, type_info) );
-
- // Now that the type ref is non-zero, we can safely use the
- // shadow_flags.
- //
page->shadow_flags = 0;
- }
- ASSERT(!test_bit(type >> PGC_SH_type_shift, &page->shadow_flags));
- set_bit(type >> PGC_SH_type_shift, &page->shadow_flags);
+ ASSERT(!test_bit(type, &page->shadow_flags));
+ set_bit(type, &page->shadow_flags);
}
void shadow_demote(struct vcpu *v, mfn_t gmfn, u32 type)
@@ -271,16 +212,14 @@ void shadow_demote(struct vcpu *v, mfn_t gmfn, u32 type)
struct page_info *page = mfn_to_page(gmfn);
ASSERT(test_bit(_PGC_page_table, &page->count_info));
- ASSERT(test_bit(type >> PGC_SH_type_shift, &page->shadow_flags));
+ ASSERT(test_bit(type, &page->shadow_flags));
- clear_bit(type >> PGC_SH_type_shift, &page->shadow_flags);
+ clear_bit(type, &page->shadow_flags);
if ( (page->shadow_flags & SHF_page_type_mask) == 0 )
{
- // release the extra type ref
- put_page_type(page);
-
- // clear the is-a-page-table bit.
+ /* tlbflush timestamp field is valid again */
+ page->tlbflush_timestamp = tlbflush_current_time();
clear_bit(_PGC_page_table, &page->count_info);
}
}
@@ -289,7 +228,7 @@ void shadow_demote(struct vcpu *v, mfn_t gmfn, u32 type)
/* Validate a pagetable change from the guest and update the shadows.
* Returns a bitmask of SHADOW_SET_* flags. */
-static int
+int
__shadow_validate_guest_entry(struct vcpu *v, mfn_t gmfn,
void *entry, u32 size)
{
@@ -344,11 +283,8 @@ __shadow_validate_guest_entry(struct vcpu *v, mfn_t gmfn,
if ( page->shadow_flags & SHF_L2H_PAE )
result |= SHADOW_INTERNAL_NAME(sh_map_and_validate_gl2he, 3, 3)
(v, gmfn, entry, size);
- if ( page->shadow_flags & SHF_L3_PAE )
- result |= SHADOW_INTERNAL_NAME(sh_map_and_validate_gl3e, 3, 3)
- (v, gmfn, entry, size);
#else /* 32-bit non-PAE hypervisor does not support PAE guests */
- ASSERT((page->shadow_flags & (SHF_L3_PAE|SHF_L2_PAE|SHF_L1_PAE)) == 0);
+ ASSERT((page->shadow_flags & (SHF_L2H_PAE|SHF_L2_PAE|SHF_L1_PAE)) == 0);
#endif
#if CONFIG_PAGING_LEVELS >= 4
@@ -389,7 +325,9 @@ shadow_validate_guest_entry(struct vcpu *v, mfn_t gmfn, void *entry)
void
shadow_validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
void *entry, u32 size)
-/* This is the entry point for emulated writes to pagetables in HVM guests */
+/* This is the entry point for emulated writes to pagetables in HVM guests and
+ * PV translated guests.
+ */
{
struct domain *d = v->domain;
int rc;
@@ -402,8 +340,11 @@ shadow_validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
if ( rc & SHADOW_SET_ERROR )
{
/* This page is probably not a pagetable any more: tear it out of the
- * shadows, along with any tables that reference it */
- shadow_remove_all_shadows_and_parents(v, gmfn);
+ * shadows, along with any tables that reference it.
+ * Since the validate call above will have made a "safe" (i.e. zero)
+ * shadow entry, we can let the domain live even if we can't fully
+ * unshadow the page. */
+ sh_remove_shadows(v, gmfn, 0, 0);
}
}
@@ -411,94 +352,19 @@ shadow_validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
/**************************************************************************/
/* Memory management for shadow pages. */
-/* Meaning of the count_info field in shadow pages
- * ----------------------------------------------
- *
- * A count of all references to this page from other shadow pages and
- * guest CR3s (a.k.a. v->arch.shadow.table).
- *
- * The top bits hold the shadow type and the pinned bit. Top-level
- * shadows are pinned so that they don't disappear when not in a CR3
- * somewhere.
- *
- * We don't need to use get|put_page for this as the updates are all
- * protected by the shadow lock. We can't use get|put_page for this
- * as the size of the count on shadow pages is different from that on
- * normal guest pages.
- */
-
-/* Meaning of the type_info field in shadow pages
- * ----------------------------------------------
- *
- * type_info use depends on the shadow type (from count_info)
- *
- * PGC_SH_none : This page is in the shadow free pool. type_info holds
- * the chunk order for our freelist allocator.
- *
- * PGC_SH_l*_shadow : This page is in use as a shadow. type_info
- * holds the mfn of the guest page being shadowed,
- *
- * PGC_SH_fl1_*_shadow : This page is being used to shatter a superpage.
- * type_info holds the gfn being shattered.
- *
- * PGC_SH_monitor_table : This page is part of a monitor table.
- * type_info is not used.
- */
-
-/* Meaning of the _domain field in shadow pages
- * --------------------------------------------
- *
- * In shadow pages, this field will always have its least significant bit
- * set. This ensures that all attempts to get_page() will fail (as all
- * valid pickled domain pointers have a zero for their least significant bit).
- * Instead, the remaining upper bits are used to record the shadow generation
- * counter when the shadow was created.
- */
-
-/* Meaning of the shadow_flags field
- * ----------------------------------
- *
- * In guest pages that are shadowed, one bit for each kind of shadow they have.
- *
- * In shadow pages, will be used for holding a representation of the populated
- * entries in this shadow (either a min/max, or a bitmap, or ...)
- *
- * In monitor-table pages, holds the level of the particular page (to save
- * spilling the shadow types into an extra bit by having three types of monitor
- * page).
- */
-
-/* Meaning of the list_head struct in shadow pages
- * -----------------------------------------------
- *
- * In free shadow pages, this is used to hold the free-lists of chunks.
- *
- * In top-level shadow tables, this holds a linked-list of all top-level
- * shadows (used for recovering memory and destroying shadows).
- *
- * In lower-level shadows, this holds the physical address of a higher-level
- * shadow entry that holds a reference to this shadow (or zero).
- */
-
/* Allocating shadow pages
* -----------------------
*
- * Most shadow pages are allocated singly, but there are two cases where we
- * need to allocate multiple pages together.
- *
- * 1: Shadowing 32-bit guest tables on PAE or 64-bit shadows.
- * A 32-bit guest l1 table covers 4MB of virtuial address space,
- * and needs to be shadowed by two PAE/64-bit l1 tables (covering 2MB
- * of virtual address space each). Similarly, a 32-bit guest l2 table
- * (4GB va) needs to be shadowed by four PAE/64-bit l2 tables (1GB va
- * each). These multi-page shadows are contiguous and aligned;
- * functions for handling offsets into them are defined in shadow.c
- * (shadow_l1_index() etc.)
+ * Most shadow pages are allocated singly, but there is one case where
+ * we need to allocate multiple pages together: shadowing 32-bit guest
+ * tables on PAE or 64-bit shadows. A 32-bit guest l1 table covers 4MB
+ * of virtuial address space, and needs to be shadowed by two PAE/64-bit
+ * l1 tables (covering 2MB of virtual address space each). Similarly, a
+ * 32-bit guest l2 table (4GB va) needs to be shadowed by four
+ * PAE/64-bit l2 tables (1GB va each). These multi-page shadows are
+ * contiguous and aligned; functions for handling offsets into them are
+ * defined in shadow.c (shadow_l1_index() etc.)
*
- * 2: Shadowing PAE top-level pages. Each guest page that contains
- * any PAE top-level pages requires two shadow pages to shadow it.
- * They contain alternating l3 tables and pae_l3_bookkeeping structs.
- *
* This table shows the allocation behaviour of the different modes:
*
* Xen paging 32b pae pae 64b 64b 64b
@@ -508,7 +374,7 @@ shadow_validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
*
* sl1 size 4k 8k 4k 8k 4k 4k
* sl2 size 4k 16k 4k 16k 4k 4k
- * sl3 size - - 8k - 8k 4k
+ * sl3 size - - - - - 4k
* sl4 size - - - - - 4k
*
* We allocate memory from xen in four-page units and break them down
@@ -540,39 +406,32 @@ unsigned int shadow_min_acceptable_pages(struct domain *d)
vcpu_count++;
return (vcpu_count * 128);
-}
-
-/* Using the type_info field to store freelist order */
-#define SH_PFN_ORDER(_p) ((_p)->u.inuse.type_info)
-#define SH_SET_PFN_ORDER(_p, _o) \
- do { (_p)->u.inuse.type_info = (_o); } while (0)
-
+}
/* Figure out the order of allocation needed for a given shadow type */
static inline u32
-shadow_order(u32 shadow_type)
+shadow_order(unsigned int shadow_type)
{
#if CONFIG_PAGING_LEVELS > 2
static const u32 type_to_order[16] = {
- 0, /* PGC_SH_none */
- 1, /* PGC_SH_l1_32_shadow */
- 1, /* PGC_SH_fl1_32_shadow */
- 2, /* PGC_SH_l2_32_shadow */
- 0, /* PGC_SH_l1_pae_shadow */
- 0, /* PGC_SH_fl1_pae_shadow */
- 0, /* PGC_SH_l2_pae_shadow */
- 0, /* PGC_SH_l2h_pae_shadow */
- 1, /* PGC_SH_l3_pae_shadow */
- 0, /* PGC_SH_l1_64_shadow */
- 0, /* PGC_SH_fl1_64_shadow */
- 0, /* PGC_SH_l2_64_shadow */
- 0, /* PGC_SH_l3_64_shadow */
- 0, /* PGC_SH_l4_64_shadow */
- 2, /* PGC_SH_p2m_table */
- 0 /* PGC_SH_monitor_table */
+ 0, /* SH_type_none */
+ 1, /* SH_type_l1_32_shadow */
+ 1, /* SH_type_fl1_32_shadow */
+ 2, /* SH_type_l2_32_shadow */
+ 0, /* SH_type_l1_pae_shadow */
+ 0, /* SH_type_fl1_pae_shadow */
+ 0, /* SH_type_l2_pae_shadow */
+ 0, /* SH_type_l2h_pae_shadow */
+ 0, /* SH_type_l1_64_shadow */
+ 0, /* SH_type_fl1_64_shadow */
+ 0, /* SH_type_l2_64_shadow */
+ 0, /* SH_type_l3_64_shadow */
+ 0, /* SH_type_l4_64_shadow */
+ 2, /* SH_type_p2m_table */
+ 0 /* SH_type_monitor_table */
};
- u32 type = (shadow_type & PGC_SH_type_mask) >> PGC_SH_type_shift;
- return type_to_order[type];
+ ASSERT(shadow_type < 16);
+ return type_to_order[shadow_type];
#else /* 32-bit Xen only ever shadows 32-bit guests on 32-bit shadows. */
return 0;
#endif
@@ -594,10 +453,10 @@ static inline int chunk_is_available(struct domain *d, int order)
* non-Xen mappings in this top-level shadow mfn */
void shadow_unhook_mappings(struct vcpu *v, mfn_t smfn)
{
- struct page_info *pg = mfn_to_page(smfn);
- switch ( (pg->count_info & PGC_SH_type_mask) >> PGC_SH_type_shift )
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
+ switch ( sp->type )
{
- case PGC_SH_l2_32_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_32_shadow:
#if CONFIG_PAGING_LEVELS == 2
SHADOW_INTERNAL_NAME(sh_unhook_32b_mappings,2,2)(v,smfn);
#else
@@ -605,19 +464,18 @@ void shadow_unhook_mappings(struct vcpu *v, mfn_t smfn)
#endif
break;
#if CONFIG_PAGING_LEVELS >= 3
- case PGC_SH_l3_pae_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_pae_shadow:
+ case SH_type_l2h_pae_shadow:
SHADOW_INTERNAL_NAME(sh_unhook_pae_mappings,3,3)(v,smfn);
break;
#endif
#if CONFIG_PAGING_LEVELS >= 4
- case PGC_SH_l4_64_shadow >> PGC_SH_type_shift:
+ case SH_type_l4_64_shadow:
SHADOW_INTERNAL_NAME(sh_unhook_64b_mappings,4,4)(v,smfn);
break;
#endif
default:
- SHADOW_PRINTK("top-level shadow has bad type %08lx\n",
- (unsigned long)((pg->count_info & PGC_SH_type_mask)
- >> PGC_SH_type_shift));
+ SHADOW_PRINTK("top-level shadow has bad type %08x\n", sp->type);
BUG();
}
}
@@ -632,32 +490,29 @@ void shadow_prealloc(struct domain *d, unsigned int order)
{
/* Need a vpcu for calling unpins; for now, since we don't have
* per-vcpu shadows, any will do */
- struct vcpu *v = d->vcpu[0];
+ struct vcpu *v, *v2;
struct list_head *l, *t;
- struct page_info *pg;
+ struct shadow_page_info *sp;
+ cpumask_t flushmask = CPU_MASK_NONE;
mfn_t smfn;
+ int i;
if ( chunk_is_available(d, order) ) return;
- /* Stage one: walk the list of top-level pages, unpinning them */
+ v = current;
+ if ( v->domain != d )
+ v = d->vcpu[0];
+ ASSERT(v != NULL);
+
+ /* Stage one: walk the list of pinned pages, unpinning them */
perfc_incrc(shadow_prealloc_1);
- list_for_each_backwards_safe(l, t, &d->arch.shadow.toplevel_shadows)
+ list_for_each_backwards_safe(l, t, &d->arch.shadow.pinned_shadows)
{
- pg = list_entry(l, struct page_info, list);
- smfn = page_to_mfn(pg);
+ sp = list_entry(l, struct shadow_page_info, list);
+ smfn = shadow_page_to_mfn(sp);
-#if CONFIG_PAGING_LEVELS >= 3
- if ( (pg->count_info & PGC_SH_type_mask) == PGC_SH_l3_pae_shadow )
- {
- /* For PAE, we need to unpin each subshadow on this shadow */
- SHADOW_INTERNAL_NAME(sh_unpin_all_l3_subshadows,3,3)(v, smfn);
- }
- else
-#endif /* 32-bit code always takes this branch */
- {
- /* Unpin this top-level shadow */
- sh_unpin(v, smfn);
- }
+ /* Unpin this top-level shadow */
+ sh_unpin(v, smfn);
/* See if that freed up a chunk of appropriate size */
if ( chunk_is_available(d, order) ) return;
@@ -667,25 +522,24 @@ void shadow_prealloc(struct domain *d, unsigned int order)
* loaded in cr3 on some vcpu. Walk them, unhooking the non-Xen
* mappings. */
perfc_incrc(shadow_prealloc_2);
- v = current;
- if ( v->domain != d )
- v = d->vcpu[0];
- /* Walk the list from the tail: recently used toplevels have been pulled
- * to the head */
- list_for_each_backwards_safe(l, t, &d->arch.shadow.toplevel_shadows)
- {
- pg = list_entry(l, struct page_info, list);
- smfn = page_to_mfn(pg);
- shadow_unhook_mappings(v, smfn);
-
- /* Need to flush TLB if we've altered our own tables */
- if ( !shadow_mode_external(d)
- && pagetable_get_pfn(current->arch.shadow_table) == mfn_x(smfn) )
- local_flush_tlb();
-
- /* See if that freed up a chunk of appropriate size */
- if ( chunk_is_available(d, order) ) return;
- }
+
+ for_each_vcpu(d, v2)
+ for ( i = 0 ; i < 4 ; i++ )
+ {
+ if ( !pagetable_is_null(v2->arch.shadow_table[i]) )
+ {
+ shadow_unhook_mappings(v,
+ pagetable_get_mfn(v2->arch.shadow_table[i]));
+ cpus_or(flushmask, v2->vcpu_dirty_cpumask, flushmask);
+
+ /* See if that freed up a chunk of appropriate size */
+ if ( chunk_is_available(d, order) )
+ {
+ flush_tlb_mask(flushmask);
+ return;
+ }
+ }
+ }
/* Nothing more we can do: all remaining shadows are of pages that
* hold Xen mappings for some vcpu. This can never happen. */
@@ -698,6 +552,61 @@ void shadow_prealloc(struct domain *d, unsigned int order)
BUG();
}
+/* Deliberately free all the memory we can: this will tear down all of
+ * this domain's shadows */
+static void shadow_blow_tables(struct domain *d)
+{
+ struct list_head *l, *t;
+ struct shadow_page_info *sp;
+ struct vcpu *v = d->vcpu[0];
+ mfn_t smfn;
+ int i;
+
+ /* Pass one: unpin all pinned pages */
+ list_for_each_backwards_safe(l,t, &d->arch.shadow.pinned_shadows)
+ {
+ sp = list_entry(l, struct shadow_page_info, list);
+ smfn = shadow_page_to_mfn(sp);
+ sh_unpin(v, smfn);
+ }
+
+ /* Second pass: unhook entries of in-use shadows */
+ for_each_vcpu(d, v)
+ for ( i = 0 ; i < 4 ; i++ )
+ if ( !pagetable_is_null(v->arch.shadow_table[i]) )
+ shadow_unhook_mappings(v,
+ pagetable_get_mfn(v->arch.shadow_table[i]));
+
+ /* Make sure everyone sees the unshadowings */
+ flush_tlb_mask(d->domain_dirty_cpumask);
+}
+
+
+#ifndef NDEBUG
+/* Blow all shadows of all shadowed domains: this can be used to cause the
+ * guest's pagetables to be re-shadowed if we suspect that the shadows
+ * have somehow got out of sync */
+static void shadow_blow_all_tables(unsigned char c)
+{
+ struct domain *d;
+ printk("'%c' pressed -> blowing all shadow tables\n", c);
+ for_each_domain(d)
+ if ( shadow_mode_enabled(d) && d->vcpu[0] != NULL )
+ {
+ shadow_lock(d);
+ shadow_blow_tables(d);
+ shadow_unlock(d);
+ }
+}
+
+/* Register this function in the Xen console keypress table */
+static __init int shadow_blow_tables_keyhandler_init(void)
+{
+ register_keyhandler('S', shadow_blow_all_tables,"reset shadow pagetables");
+ return 0;
+}
+__initcall(shadow_blow_tables_keyhandler_init);
+#endif /* !NDEBUG */
/* Allocate another shadow's worth of (contiguous, aligned) pages,
* and fill in the type and backpointer fields of their page_infos.
@@ -706,7 +615,7 @@ mfn_t shadow_alloc(struct domain *d,
u32 shadow_type,
unsigned long backpointer)
{
- struct page_info *pg = NULL;
+ struct shadow_page_info *sp = NULL;
unsigned int order = shadow_order(shadow_type);
cpumask_t mask;
void *p;
@@ -714,51 +623,54 @@ mfn_t shadow_alloc(struct domain *d,
ASSERT(shadow_lock_is_acquired(d));
ASSERT(order <= SHADOW_MAX_ORDER);
- ASSERT(shadow_type != PGC_SH_none);
+ ASSERT(shadow_type != SH_type_none);
perfc_incrc(shadow_alloc);
/* Find smallest order which can satisfy the request. */
for ( i = order; i <= SHADOW_MAX_ORDER; i++ )
if ( !list_empty(&d->arch.shadow.freelists[i]) )
{
- pg = list_entry(d->arch.shadow.freelists[i].next,
- struct page_info, list);
- list_del(&pg->list);
+ sp = list_entry(d->arch.shadow.freelists[i].next,
+ struct shadow_page_info, list);
+ list_del(&sp->list);
/* We may have to halve the chunk a number of times. */
while ( i != order )
{
i--;
- SH_SET_PFN_ORDER(pg, i);
- list_add_tail(&pg->list, &d->arch.shadow.freelists[i]);
- pg += 1 << i;
+ sp->order = i;
+ list_add_tail(&sp->list, &d->arch.shadow.freelists[i]);
+ sp += 1 << i;
}
d->arch.shadow.free_pages -= 1 << order;
/* Init page info fields and clear the pages */
for ( i = 0; i < 1<<order ; i++ )
{
- pg[i].u.inuse.type_info = backpointer;
- pg[i].count_info = shadow_type;
- pg[i].shadow_flags = 0;
- INIT_LIST_HEAD(&pg[i].list);
/* Before we overwrite the old contents of this page,
* we need to be sure that no TLB holds a pointer to it. */
mask = d->domain_dirty_cpumask;
- tlbflush_filter(mask, pg[i].tlbflush_timestamp);
+ tlbflush_filter(mask, sp[i].tlbflush_timestamp);
if ( unlikely(!cpus_empty(mask)) )
{
perfc_incrc(shadow_alloc_tlbflush);
flush_tlb_mask(mask);
}
/* Now safe to clear the page for reuse */
- p = sh_map_domain_page(page_to_mfn(pg+i));
+ p = sh_map_domain_page(shadow_page_to_mfn(sp+i));
ASSERT(p != NULL);
clear_page(p);
sh_unmap_domain_page(p);
+ INIT_LIST_HEAD(&sp[i].list);
+ sp[i].type = shadow_type;
+ sp[i].pinned = 0;
+ sp[i].logdirty = 0;
+ sp[i].count = 0;
+ sp[i].backpointer = backpointer;
+ sp[i].next_shadow = NULL;
perfc_incr(shadow_alloc_count);
}
- return page_to_mfn(pg);
+ return shadow_page_to_mfn(sp);
}
/* If we get here, we failed to allocate. This should never happen.
@@ -773,7 +685,7 @@ mfn_t shadow_alloc(struct domain *d,
/* Return some shadow pages to the pool. */
void shadow_free(struct domain *d, mfn_t smfn)
{
- struct page_info *pg = mfn_to_page(smfn);
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
u32 shadow_type;
unsigned long order;
unsigned long mask;
@@ -782,22 +694,31 @@ void shadow_free(struct domain *d, mfn_t smfn)
ASSERT(shadow_lock_is_acquired(d));
perfc_incrc(shadow_free);
- shadow_type = pg->count_info & PGC_SH_type_mask;
- ASSERT(shadow_type != PGC_SH_none);
- ASSERT(shadow_type != PGC_SH_p2m_table);
+ shadow_type = sp->type;
+ ASSERT(shadow_type != SH_type_none);
+ ASSERT(shadow_type != SH_type_p2m_table);
order = shadow_order(shadow_type);
d->arch.shadow.free_pages += 1 << order;
for ( i = 0; i < 1<<order; i++ )
{
+#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
+ struct vcpu *v;
+ for_each_vcpu(d, v)
+ {
+ /* No longer safe to look for a writeable mapping in this shadow */
+ if ( v->arch.shadow.last_writeable_pte_smfn == mfn_x(smfn) + i )
+ v->arch.shadow.last_writeable_pte_smfn = 0;
+ }
+#endif
/* Strip out the type: this is now a free shadow page */
- pg[i].count_info = 0;
+ sp[i].type = 0;
/* Remember the TLB timestamp so we will know whether to flush
* TLBs when we reuse the page. Because the destructors leave the
* contents of the pages in place, we can delay TLB flushes until
* just before the allocator hands the page out again. */
- pg[i].tlbflush_timestamp = tlbflush_current_time();
+ sp[i].tlbflush_timestamp = tlbflush_current_time();
perfc_decr(shadow_alloc_count);
}
@@ -805,30 +726,28 @@ void shadow_free(struct domain *d, mfn_t smfn)
while ( order < SHADOW_MAX_ORDER )
{
mask = 1 << order;
- if ( (mfn_x(page_to_mfn(pg)) & mask) ) {
+ if ( (mfn_x(shadow_page_to_mfn(sp)) & mask) ) {
/* Merge with predecessor block? */
- if ( (((pg-mask)->count_info & PGC_SH_type_mask) != PGT_none)
- || (SH_PFN_ORDER(pg-mask) != order) )
+ if ( ((sp-mask)->type != PGT_none) || ((sp-mask)->order != order) )
break;
- list_del(&(pg-mask)->list);
- pg -= mask;
+ list_del(&(sp-mask)->list);
+ sp -= mask;
} else {
/* Merge with successor block? */
- if ( (((pg+mask)->count_info & PGC_SH_type_mask) != PGT_none)
- || (SH_PFN_ORDER(pg+mask) != order) )
+ if ( ((sp+mask)->type != PGT_none) || ((sp+mask)->order != order) )
break;
- list_del(&(pg+mask)->list);
+ list_del(&(sp+mask)->list);
}
order++;
}
- SH_SET_PFN_ORDER(pg, order);
- list_add_tail(&pg->list, &d->arch.shadow.freelists[order]);
+ sp->order = order;
+ list_add_tail(&sp->list, &d->arch.shadow.freelists[order]);
}
/* Divert some memory from the pool to be used by the p2m mapping.
* This action is irreversible: the p2m mapping only ever grows.
- * That's OK because the p2m table only exists for external domains,
+ * That's OK because the p2m table only exists for translated domains,
* and those domains can't ever turn off shadow mode.
* Also, we only ever allocate a max-order chunk, so as to preserve
* the invariant that shadow_prealloc() always works.
@@ -847,12 +766,17 @@ shadow_alloc_p2m_pages(struct domain *d)
< (shadow_min_acceptable_pages(d) + (1<<SHADOW_MAX_ORDER)) )
return 0; /* Not enough shadow memory: need to increase it first */
- pg = mfn_to_page(shadow_alloc(d, PGC_SH_p2m_table, 0));
+ pg = mfn_to_page(shadow_alloc(d, SH_type_p2m_table, 0));
d->arch.shadow.p2m_pages += (1<<SHADOW_MAX_ORDER);
d->arch.shadow.total_pages -= (1<<SHADOW_MAX_ORDER);
for (i = 0; i < (1<<SHADOW_MAX_ORDER); i++)
{
- /* Unlike shadow pages, mark p2m pages as owned by the domain */
+ /* Unlike shadow pages, mark p2m pages as owned by the domain.
+ * Marking the domain as the owner would normally allow the guest to
+ * create mappings of these pages, but these p2m pages will never be
+ * in the domain's guest-physical address space, and so that is not
+ * believed to be a concern.
+ */
page_set_owner(&pg[i], d);
list_add_tail(&pg[i].list, &d->arch.shadow.p2m_freelist);
}
@@ -864,6 +788,7 @@ mfn_t
shadow_alloc_p2m_page(struct domain *d)
{
struct list_head *entry;
+ struct page_info *pg;
mfn_t mfn;
void *p;
@@ -873,8 +798,9 @@ shadow_alloc_p2m_page(struct domain *d)
entry = d->arch.shadow.p2m_freelist.next;
list_del(entry);
list_add_tail(entry, &d->arch.shadow.p2m_inuse);
- mfn = page_to_mfn(list_entry(entry, struct page_info, list));
- sh_get_ref(mfn, 0);
+ pg = list_entry(entry, struct page_info, list);
+ pg->count_info = 1;
+ mfn = page_to_mfn(pg);
p = sh_map_domain_page(mfn);
clear_page(p);
sh_unmap_domain_page(p);
@@ -974,15 +900,26 @@ p2m_next_level(struct domain *d, mfn_t *table_mfn, void **table,
#if CONFIG_PAGING_LEVELS == 3
if (type == PGT_l2_page_table)
{
+ struct vcpu *v;
/* We have written to the p2m l3: need to sync the per-vcpu
* copies of it in the monitor tables */
p2m_install_entry_in_monitors(d, (l3_pgentry_t *)p2m_entry);
+ /* Also, any vcpus running on shadows of the p2m need to
+ * reload their CR3s so the change propagates to the shadow */
+ ASSERT(shadow_lock_is_acquired(d));
+ for_each_vcpu(d, v)
+ {
+ if ( pagetable_get_pfn(v->arch.guest_table)
+ == pagetable_get_pfn(d->arch.phys_table)
+ && v->arch.shadow.mode != NULL )
+ v->arch.shadow.mode->update_cr3(v);
+ }
}
#endif
/* The P2M can be shadowed: keep the shadows synced */
- if ( d->vcpu[0] )
+ if ( d->vcpu[0] != NULL )
(void)__shadow_validate_guest_entry(d->vcpu[0], *table_mfn,
- p2m_entry, sizeof *p2m_entry);
+ p2m_entry, sizeof *p2m_entry);
}
*table_mfn = _mfn(l1e_get_pfn(*p2m_entry));
next = sh_map_domain_page(*table_mfn);
@@ -1030,14 +967,19 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
0, L1_PAGETABLE_ENTRIES);
ASSERT(p2m_entry);
- if ( valid_mfn(mfn) )
+ if ( mfn_valid(mfn) )
*p2m_entry = l1e_from_pfn(mfn_x(mfn), __PAGE_HYPERVISOR|_PAGE_USER);
else
*p2m_entry = l1e_empty();
+ /* Track the highest gfn for which we have ever had a valid mapping */
+ if ( mfn_valid(mfn) && (gfn > d->arch.max_mapped_pfn) )
+ d->arch.max_mapped_pfn = gfn;
+
/* The P2M can be shadowed: keep the shadows synced */
- (void) __shadow_validate_guest_entry(d->vcpu[0], table_mfn,
- p2m_entry, sizeof *p2m_entry);
+ if ( d->vcpu[0] != NULL )
+ (void)__shadow_validate_guest_entry(
+ d->vcpu[0], table_mfn, p2m_entry, sizeof(*p2m_entry));
sh_unmap_domain_page(table);
@@ -1054,9 +996,11 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
static int
shadow_alloc_p2m_table(struct domain *d)
{
- mfn_t p2m_top;
+ mfn_t p2m_top, mfn;
struct list_head *entry;
+ struct page_info *page;
unsigned int page_count = 0;
+ unsigned long gfn;
SHADOW_PRINTK("allocating p2m table\n");
ASSERT(pagetable_get_pfn(d->arch.phys_table) == 0);
@@ -1080,13 +1024,19 @@ shadow_alloc_p2m_table(struct domain *d)
SHADOW_PRINTK("populating p2m table\n");
+ /* Initialise physmap tables for slot zero. Other code assumes this. */
+ gfn = 0;
+ mfn = _mfn(INVALID_MFN);
+ if ( !shadow_set_p2m_entry(d, gfn, mfn) )
+ goto error;
+
for ( entry = d->page_list.next;
entry != &d->page_list;
entry = entry->next )
{
- struct page_info *page = list_entry(entry, struct page_info, list);
- mfn_t mfn = page_to_mfn(page);
- unsigned long gfn = get_gpfn_from_mfn(mfn_x(mfn));
+ page = list_entry(entry, struct page_info, list);
+ mfn = page_to_mfn(page);
+ gfn = get_gpfn_from_mfn(mfn_x(mfn));
page_count++;
if (
#ifdef __x86_64__
@@ -1096,15 +1046,16 @@ shadow_alloc_p2m_table(struct domain *d)
#endif
&& gfn != INVALID_M2P_ENTRY
&& !shadow_set_p2m_entry(d, gfn, mfn) )
- {
- SHADOW_PRINTK("failed to initialize p2m table, gfn=%05lx, mfn=%" SH_PRI_mfn "\n",
- gfn, mfn_x(mfn));
- return 0;
- }
+ goto error;
}
SHADOW_PRINTK("p2m table initialised (%u pages)\n", page_count);
return 1;
+
+ error:
+ SHADOW_PRINTK("failed to initialize p2m table, gfn=%05lx, mfn=%"
+ SH_PRI_mfn "\n", gfn, mfn_x(mfn));
+ return 0;
}
mfn_t
@@ -1120,12 +1071,9 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
mfn = pagetable_get_mfn(d->arch.phys_table);
-#if CONFIG_PAGING_LEVELS > 2
- if ( gpfn >= (RO_MPT_VIRT_END-RO_MPT_VIRT_START) / sizeof(l1_pgentry_t) )
- /* This pfn is higher than the p2m map can hold */
+ if ( gpfn > d->arch.max_mapped_pfn )
+ /* This pfn is higher than the highest the p2m map currently holds */
return _mfn(INVALID_MFN);
-#endif
-
#if CONFIG_PAGING_LEVELS >= 4
{
@@ -1198,7 +1146,7 @@ static void shadow_p2m_teardown(struct domain *d)
pg = list_entry(entry, struct page_info, list);
list_del(entry);
/* Should have just the one ref we gave it in alloc_p2m_page() */
- if ( (pg->count_info & PGC_SH_count_mask) != 1 )
+ if ( (pg->count_info & PGC_count_mask) != 1 )
{
SHADOW_PRINTK("Odd p2m page count c=%#x t=%"PRtype_info"\n",
pg->count_info, pg->u.inuse.type_info);
@@ -1233,7 +1181,7 @@ static unsigned int set_sh_allocation(struct domain *d,
unsigned int pages,
int *preempted)
{
- struct page_info *pg;
+ struct shadow_page_info *sp;
unsigned int lower_bound;
int j;
@@ -1255,8 +1203,9 @@ static unsigned int set_sh_allocation(struct domain *d,
if ( d->arch.shadow.total_pages < pages )
{
/* Need to allocate more memory from domheap */
- pg = alloc_domheap_pages(NULL, SHADOW_MAX_ORDER, 0);
- if ( pg == NULL )
+ sp = (struct shadow_page_info *)
+ alloc_domheap_pages(NULL, SHADOW_MAX_ORDER, 0);
+ if ( sp == NULL )
{
SHADOW_PRINTK("failed to allocate shadow pages.\n");
return -ENOMEM;
@@ -1265,11 +1214,15 @@ static unsigned int set_sh_allocation(struct domain *d,
d->arch.shadow.total_pages += 1<<SHADOW_MAX_ORDER;
for ( j = 0; j < 1<<SHADOW_MAX_ORDER; j++ )
{
- pg[j].u.inuse.type_info = 0; /* Free page */
- pg[j].tlbflush_timestamp = 0; /* Not in any TLB */
+ sp[j].type = 0;
+ sp[j].pinned = 0;
+ sp[j].logdirty = 0;
+ sp[j].count = 0;
+ sp[j].mbz = 0;
+ sp[j].tlbflush_timestamp = 0; /* Not in any TLB */
}
- SH_SET_PFN_ORDER(pg, SHADOW_MAX_ORDER);
- list_add_tail(&pg->list,
+ sp->order = SHADOW_MAX_ORDER;
+ list_add_tail(&sp->list,
&d->arch.shadow.freelists[SHADOW_MAX_ORDER]);
}
else if ( d->arch.shadow.total_pages > pages )
@@ -1277,12 +1230,12 @@ static unsigned int set_sh_allocation(struct domain *d,
/* Need to return memory to domheap */
shadow_prealloc(d, SHADOW_MAX_ORDER);
ASSERT(!list_empty(&d->arch.shadow.freelists[SHADOW_MAX_ORDER]));
- pg = list_entry(d->arch.shadow.freelists[SHADOW_MAX_ORDER].next,
- struct page_info, list);
- list_del(&pg->list);
+ sp = list_entry(d->arch.shadow.freelists[SHADOW_MAX_ORDER].next,
+ struct shadow_page_info, list);
+ list_del(&sp->list);
d->arch.shadow.free_pages -= 1<<SHADOW_MAX_ORDER;
d->arch.shadow.total_pages -= 1<<SHADOW_MAX_ORDER;
- free_domheap_pages(pg, SHADOW_MAX_ORDER);
+ free_domheap_pages((struct page_info *)sp, SHADOW_MAX_ORDER);
}
/* Check to see if we need to yield and try again */
@@ -1313,17 +1266,22 @@ unsigned int shadow_set_allocation(struct domain *d,
}
/**************************************************************************/
-/* Hash table for storing the guest->shadow mappings */
+/* Hash table for storing the guest->shadow mappings.
+ * The table itself is an array of pointers to shadows; the shadows are then
+ * threaded on a singly-linked list of shadows with the same hash value */
+
+#define SHADOW_HASH_BUCKETS 251
+/* Other possibly useful primes are 509, 1021, 2039, 4093, 8191, 16381 */
/* Hash function that takes a gfn or mfn, plus another byte of type info */
typedef u32 key_t;
-static inline key_t sh_hash(unsigned long n, u8 t)
+static inline key_t sh_hash(unsigned long n, unsigned int t)
{
unsigned char *p = (unsigned char *)&n;
key_t k = t;
int i;
for ( i = 0; i < sizeof(n) ; i++ ) k = (u32)p[i] + (k<<6) + (k<<16) - k;
- return k;
+ return k % SHADOW_HASH_BUCKETS;
}
#if SHADOW_AUDIT & (SHADOW_AUDIT_HASH|SHADOW_AUDIT_HASH_FULL)
@@ -1333,49 +1291,50 @@ static inline key_t sh_hash(unsigned long n, u8 t)
static void sh_hash_audit_bucket(struct domain *d, int bucket)
/* Audit one bucket of the hash table */
{
- struct shadow_hash_entry *e, *x;
- struct page_info *pg;
+ struct shadow_page_info *sp, *x;
if ( !(SHADOW_AUDIT_ENABLE) )
return;
- e = &d->arch.shadow.hash_table[bucket];
- if ( e->t == 0 ) return; /* Bucket is empty */
- while ( e )
+ sp = d->arch.shadow.hash_table[bucket];
+ while ( sp )
{
- /* Empty link? */
- BUG_ON( e->t == 0 );
+ /* Not a shadow? */
+ BUG_ON( sp->mbz != 0 );
/* Bogus type? */
- BUG_ON( e->t > (PGC_SH_max_shadow >> PGC_SH_type_shift) );
+ BUG_ON( sp->type == 0 );
+ BUG_ON( sp->type > SH_type_max_shadow );
/* Wrong bucket? */
- BUG_ON( sh_hash(e->n, e->t) % SHADOW_HASH_BUCKETS != bucket );
+ BUG_ON( sh_hash(sp->backpointer, sp->type) != bucket );
/* Duplicate entry? */
- for ( x = e->next; x; x = x->next )
- BUG_ON( x->n == e->n && x->t == e->t );
- /* Bogus MFN? */
- BUG_ON( !valid_mfn(e->smfn) );
- pg = mfn_to_page(e->smfn);
- /* Not a shadow? */
- BUG_ON( page_get_owner(pg) != 0 );
- /* Wrong kind of shadow? */
- BUG_ON( (pg->count_info & PGC_SH_type_mask) >> PGC_SH_type_shift
- != e->t );
- /* Bad backlink? */
- BUG_ON( pg->u.inuse.type_info != e->n );
- if ( e->t != (PGC_SH_fl1_32_shadow >> PGC_SH_type_shift)
- && e->t != (PGC_SH_fl1_pae_shadow >> PGC_SH_type_shift)
- && e->t != (PGC_SH_fl1_64_shadow >> PGC_SH_type_shift) )
+ for ( x = sp->next_shadow; x; x = x->next_shadow )
+ BUG_ON( x->backpointer == sp->backpointer && x->type == sp->type );
+ /* Follow the backpointer to the guest pagetable */
+ if ( sp->type != SH_type_fl1_32_shadow
+ && sp->type != SH_type_fl1_pae_shadow
+ && sp->type != SH_type_fl1_64_shadow )
{
+ struct page_info *gpg = mfn_to_page(_mfn(sp->backpointer));
/* Bad shadow flags on guest page? */
- BUG_ON( !(mfn_to_page(_mfn(e->n))->shadow_flags & (1<<e->t)) );
+ BUG_ON( !(gpg->shadow_flags & (1<<sp->type)) );
+ /* Bad type count on guest page? */
+ if ( (gpg->u.inuse.type_info & PGT_type_mask) == PGT_writable_page
+ && (gpg->u.inuse.type_info & PGT_count_mask) != 0 )
+ {
+ SHADOW_ERROR("MFN %#lx shadowed (by %#"SH_PRI_mfn")"
+ " but has typecount %#lx\n",
+ sp->backpointer, mfn_x(shadow_page_to_mfn(sp)),
+ gpg->u.inuse.type_info);
+ BUG();
+ }
}
/* That entry was OK; on we go */
- e = e->next;
+ sp = sp->next_shadow;
}
}
#else
-#define sh_hash_audit_bucket(_d, _b)
+#define sh_hash_audit_bucket(_d, _b) do {} while(0)
#endif /* Hashtable bucket audit */
@@ -1396,75 +1355,22 @@ static void sh_hash_audit(struct domain *d)
}
#else
-#define sh_hash_audit(_d)
+#define sh_hash_audit(_d) do {} while(0)
#endif /* Hashtable bucket audit */
-/* Memory management interface for bucket allocation.
- * These ought to come out of shadow memory, but at least on 32-bit
- * machines we are forced to allocate them from xenheap so that we can
- * address them. */
-static struct shadow_hash_entry *sh_alloc_hash_entry(struct domain *d)
-{
- struct shadow_hash_entry *extra, *x;
- int i;
-
- /* We need to allocate a new node. Ensure the free list is not empty.
- * Allocate new entries in units the same size as the original table. */
- if ( unlikely(d->arch.shadow.hash_freelist == NULL) )
- {
- size_t sz = sizeof(void *) + (SHADOW_HASH_BUCKETS * sizeof(*x));
- extra = xmalloc_bytes(sz);
-
- if ( extra == NULL )
- {
- /* No memory left! */
- SHADOW_ERROR("xmalloc() failed when allocating hash buckets.\n");
- domain_crash_synchronous();
- }
- memset(extra, 0, sz);
-
- /* Record the allocation block so it can be correctly freed later. */
- *((struct shadow_hash_entry **)&extra[SHADOW_HASH_BUCKETS]) =
- d->arch.shadow.hash_allocations;
- d->arch.shadow.hash_allocations = &extra[0];
-
- /* Thread a free chain through the newly-allocated nodes. */
- for ( i = 0; i < (SHADOW_HASH_BUCKETS - 1); i++ )
- extra[i].next = &extra[i+1];
- extra[i].next = NULL;
-
- /* Add the new nodes to the free list. */
- d->arch.shadow.hash_freelist = &extra[0];
- }
-
- /* Allocate a new node from the free list. */
- x = d->arch.shadow.hash_freelist;
- d->arch.shadow.hash_freelist = x->next;
- return x;
-}
-
-static void sh_free_hash_entry(struct domain *d, struct shadow_hash_entry *e)
-{
- /* Mark the bucket as empty and return it to the free list */
- e->t = 0;
- e->next = d->arch.shadow.hash_freelist;
- d->arch.shadow.hash_freelist = e;
-}
-
-
/* Allocate and initialise the table itself.
* Returns 0 for success, 1 for error. */
static int shadow_hash_alloc(struct domain *d)
{
- struct shadow_hash_entry *table;
+ struct shadow_page_info **table;
ASSERT(shadow_lock_is_acquired(d));
ASSERT(!d->arch.shadow.hash_table);
- table = xmalloc_array(struct shadow_hash_entry, SHADOW_HASH_BUCKETS);
+ table = xmalloc_array(struct shadow_page_info *, SHADOW_HASH_BUCKETS);
if ( !table ) return 1;
memset(table, 0,
- SHADOW_HASH_BUCKETS * sizeof (struct shadow_hash_entry));
+ SHADOW_HASH_BUCKETS * sizeof (struct shadow_page_info *));
d->arch.shadow.hash_table = table;
return 0;
}
@@ -1473,35 +1379,20 @@ static int shadow_hash_alloc(struct domain *d)
* This function does not care whether the table is populated. */
static void shadow_hash_teardown(struct domain *d)
{
- struct shadow_hash_entry *a, *n;
-
ASSERT(shadow_lock_is_acquired(d));
ASSERT(d->arch.shadow.hash_table);
- /* Return the table itself */
xfree(d->arch.shadow.hash_table);
d->arch.shadow.hash_table = NULL;
-
- /* Return any extra allocations */
- a = d->arch.shadow.hash_allocations;
- while ( a )
- {
- /* We stored a linked-list pointer at the end of each allocation */
- n = *((struct shadow_hash_entry **)(&a[SHADOW_HASH_BUCKETS]));
- xfree(a);
- a = n;
- }
- d->arch.shadow.hash_allocations = NULL;
- d->arch.shadow.hash_freelist = NULL;
}
-mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, u8 t)
+mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, unsigned int t)
/* Find an entry in the hash table. Returns the MFN of the shadow,
* or INVALID_MFN if it doesn't exist */
{
struct domain *d = v->domain;
- struct shadow_hash_entry *p, *x, *head;
+ struct shadow_page_info *sp, *prev;
key_t key;
ASSERT(shadow_lock_is_acquired(d));
@@ -1512,58 +1403,50 @@ mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, u8 t)
perfc_incrc(shadow_hash_lookups);
key = sh_hash(n, t);
+ sh_hash_audit_bucket(d, key);
- x = head = &d->arch.shadow.hash_table[key % SHADOW_HASH_BUCKETS];
- p = NULL;
-
- sh_hash_audit_bucket(d, key % SHADOW_HASH_BUCKETS);
-
- do
+ sp = d->arch.shadow.hash_table[key];
+ prev = NULL;
+ while(sp)
{
- ASSERT(x->t || ((x == head) && (x->next == NULL)));
-
- if ( x->n == n && x->t == t )
+ if ( sp->backpointer == n && sp->type == t )
{
- /* Pull-to-front if 'x' isn't already the head item */
- if ( unlikely(x != head) )
+ /* Pull-to-front if 'sp' isn't already the head item */
+ if ( unlikely(sp != d->arch.shadow.hash_table[key]) )
{
if ( unlikely(d->arch.shadow.hash_walking != 0) )
/* Can't reorder: someone is walking the hash chains */
- return x->smfn;
+ return shadow_page_to_mfn(sp);
else
{
- /* Delete 'x' from list and reinsert after head. */
- p->next = x->next;
- x->next = head->next;
- head->next = x;
-
- /* Swap 'x' contents with head contents. */
- SWAP(head->n, x->n);
- SWAP(head->t, x->t);
- SWAP(head->smfn, x->smfn);
+ ASSERT(prev);
+ /* Delete sp from the list */
+ prev->next_shadow = sp->next_shadow;
+ /* Re-insert it at the head of the list */
+ sp->next_shadow = d->arch.shadow.hash_table[key];
+ d->arch.shadow.hash_table[key] = sp;
}
}
else
{
perfc_incrc(shadow_hash_lookup_head);
}
- return head->smfn;
+ return shadow_page_to_mfn(sp);
}
-
- p = x;
- x = x->next;
+ prev = sp;
+ sp = sp->next_shadow;
}
- while ( x != NULL );
perfc_incrc(shadow_hash_lookup_miss);
return _mfn(INVALID_MFN);
}
-void shadow_hash_insert(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn)
+void shadow_hash_insert(struct vcpu *v, unsigned long n, unsigned int t,
+ mfn_t smfn)
/* Put a mapping (n,t)->smfn into the hash table */
{
struct domain *d = v->domain;
- struct shadow_hash_entry *x, *head;
+ struct shadow_page_info *sp;
key_t key;
ASSERT(shadow_lock_is_acquired(d));
@@ -1574,38 +1457,22 @@ void shadow_hash_insert(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn)
perfc_incrc(shadow_hash_inserts);
key = sh_hash(n, t);
-
- head = &d->arch.shadow.hash_table[key % SHADOW_HASH_BUCKETS];
-
- sh_hash_audit_bucket(d, key % SHADOW_HASH_BUCKETS);
-
- /* If the bucket is empty then insert the new page as the head item. */
- if ( head->t == 0 )
- {
- head->n = n;
- head->t = t;
- head->smfn = smfn;
- ASSERT(head->next == NULL);
- }
- else
- {
- /* Insert a new entry directly after the head item. */
- x = sh_alloc_hash_entry(d);
- x->n = n;
- x->t = t;
- x->smfn = smfn;
- x->next = head->next;
- head->next = x;
- }
+ sh_hash_audit_bucket(d, key);
- sh_hash_audit_bucket(d, key % SHADOW_HASH_BUCKETS);
+ /* Insert this shadow at the top of the bucket */
+ sp = mfn_to_shadow_page(smfn);
+ sp->next_shadow = d->arch.shadow.hash_table[key];
+ d->arch.shadow.hash_table[key] = sp;
+
+ sh_hash_audit_bucket(d, key);
}
-void shadow_hash_delete(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn)
+void shadow_hash_delete(struct vcpu *v, unsigned long n, unsigned int t,
+ mfn_t smfn)
/* Excise the mapping (n,t)->smfn from the hash table */
{
struct domain *d = v->domain;
- struct shadow_hash_entry *p, *x, *head;
+ struct shadow_page_info *sp, *x;
key_t key;
ASSERT(shadow_lock_is_acquired(d));
@@ -1616,54 +1483,31 @@ void shadow_hash_delete(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn)
perfc_incrc(shadow_hash_deletes);
key = sh_hash(n, t);
-
- head = &d->arch.shadow.hash_table[key % SHADOW_HASH_BUCKETS];
-
- sh_hash_audit_bucket(d, key % SHADOW_HASH_BUCKETS);
-
- /* Match on head item? */
- if ( head->n == n && head->t == t )
- {
- if ( (x = head->next) != NULL )
- {
- /* Overwrite head with contents of following node. */
- head->n = x->n;
- head->t = x->t;
- head->smfn = x->smfn;
-
- /* Delete following node. */
- head->next = x->next;
- sh_free_hash_entry(d, x);
- }
- else
- {
- /* This bucket is now empty. Initialise the head node. */
- head->t = 0;
- }
- }
+ sh_hash_audit_bucket(d, key);
+
+ sp = mfn_to_shadow_page(smfn);
+ if ( d->arch.shadow.hash_table[key] == sp )
+ /* Easy case: we're deleting the head item. */
+ d->arch.shadow.hash_table[key] = sp->next_shadow;
else
{
- /* Not at the head; need to walk the chain */
- p = head;
- x = head->next;
-
- while(1)
+ /* Need to search for the one we want */
+ x = d->arch.shadow.hash_table[key];
+ while ( 1 )
{
ASSERT(x); /* We can't have hit the end, since our target is
* still in the chain somehwere... */
- if ( x->n == n && x->t == t )
+ if ( x->next_shadow == sp )
{
- /* Delete matching node. */
- p->next = x->next;
- sh_free_hash_entry(d, x);
+ x->next_shadow = sp->next_shadow;
break;
}
- p = x;
- x = x->next;
+ x = x->next_shadow;
}
}
+ sp->next_shadow = NULL;
- sh_hash_audit_bucket(d, key % SHADOW_HASH_BUCKETS);
+ sh_hash_audit_bucket(d, key);
}
typedef int (*hash_callback_t)(struct vcpu *v, mfn_t smfn, mfn_t other_mfn);
@@ -1683,27 +1527,27 @@ static void hash_foreach(struct vcpu *v,
{
int i, done = 0;
struct domain *d = v->domain;
- struct shadow_hash_entry *x;
+ struct shadow_page_info *x;
/* Say we're here, to stop hash-lookups reordering the chains */
ASSERT(shadow_lock_is_acquired(d));
ASSERT(d->arch.shadow.hash_walking == 0);
d->arch.shadow.hash_walking = 1;
- callback_mask &= ~1; /* Never attempt to call back on empty buckets */
for ( i = 0; i < SHADOW_HASH_BUCKETS; i++ )
{
/* WARNING: This is not safe against changes to the hash table.
* The callback *must* return non-zero if it has inserted or
* deleted anything from the hash (lookups are OK, though). */
- for ( x = &d->arch.shadow.hash_table[i]; x; x = x->next )
+ for ( x = d->arch.shadow.hash_table[i]; x; x = x->next_shadow )
{
- if ( callback_mask & (1 << x->t) )
+ if ( callback_mask & (1 << x->type) )
{
- ASSERT(x->t <= 15);
- ASSERT(callbacks[x->t] != NULL);
- if ( (done = callbacks[x->t](v, x->smfn, callback_mfn)) != 0 )
- break;
+ ASSERT(x->type <= 15);
+ ASSERT(callbacks[x->type] != NULL);
+ done = callbacks[x->type](v, shadow_page_to_mfn(x),
+ callback_mfn);
+ if ( done ) break;
}
}
if ( done ) break;
@@ -1719,69 +1563,66 @@ static void hash_foreach(struct vcpu *v,
void sh_destroy_shadow(struct vcpu *v, mfn_t smfn)
{
- struct page_info *pg = mfn_to_page(smfn);
- u32 t = pg->count_info & PGC_SH_type_mask;
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
+ unsigned int t = sp->type;
SHADOW_PRINTK("smfn=%#lx\n", mfn_x(smfn));
/* Double-check, if we can, that the shadowed page belongs to this
* domain, (by following the back-pointer). */
- ASSERT(t == PGC_SH_fl1_32_shadow ||
- t == PGC_SH_fl1_pae_shadow ||
- t == PGC_SH_fl1_64_shadow ||
- t == PGC_SH_monitor_table ||
- (page_get_owner(mfn_to_page(_mfn(pg->u.inuse.type_info)))
+ ASSERT(t == SH_type_fl1_32_shadow ||
+ t == SH_type_fl1_pae_shadow ||
+ t == SH_type_fl1_64_shadow ||
+ t == SH_type_monitor_table ||
+ (page_get_owner(mfn_to_page(_mfn(sp->backpointer)))
== v->domain));
/* The down-shifts here are so that the switch statement is on nice
* small numbers that the compiler will enjoy */
- switch ( t >> PGC_SH_type_shift )
+ switch ( t )
{
#if CONFIG_PAGING_LEVELS == 2
- case PGC_SH_l1_32_shadow >> PGC_SH_type_shift:
- case PGC_SH_fl1_32_shadow >> PGC_SH_type_shift:
+ case SH_type_l1_32_shadow:
+ case SH_type_fl1_32_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l1_shadow, 2, 2)(v, smfn);
break;
- case PGC_SH_l2_32_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_32_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l2_shadow, 2, 2)(v, smfn);
break;
#else /* PAE or 64bit */
- case PGC_SH_l1_32_shadow >> PGC_SH_type_shift:
- case PGC_SH_fl1_32_shadow >> PGC_SH_type_shift:
+ case SH_type_l1_32_shadow:
+ case SH_type_fl1_32_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l1_shadow, 3, 2)(v, smfn);
break;
- case PGC_SH_l2_32_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_32_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l2_shadow, 3, 2)(v, smfn);
break;
#endif
#if CONFIG_PAGING_LEVELS >= 3
- case PGC_SH_l1_pae_shadow >> PGC_SH_type_shift:
- case PGC_SH_fl1_pae_shadow >> PGC_SH_type_shift:
+ case SH_type_l1_pae_shadow:
+ case SH_type_fl1_pae_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l1_shadow, 3, 3)(v, smfn);
break;
- case PGC_SH_l2_pae_shadow >> PGC_SH_type_shift:
- case PGC_SH_l2h_pae_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_pae_shadow:
+ case SH_type_l2h_pae_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l2_shadow, 3, 3)(v, smfn);
break;
- case PGC_SH_l3_pae_shadow >> PGC_SH_type_shift:
- SHADOW_INTERNAL_NAME(sh_destroy_l3_shadow, 3, 3)(v, smfn);
- break;
#endif
#if CONFIG_PAGING_LEVELS >= 4
- case PGC_SH_l1_64_shadow >> PGC_SH_type_shift:
- case PGC_SH_fl1_64_shadow >> PGC_SH_type_shift:
+ case SH_type_l1_64_shadow:
+ case SH_type_fl1_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l1_shadow, 4, 4)(v, smfn);
break;
- case PGC_SH_l2_64_shadow >> PGC_SH_type_shift:
+ case SH_type_l2_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l2_shadow, 4, 4)(v, smfn);
break;
- case PGC_SH_l3_64_shadow >> PGC_SH_type_shift:
+ case SH_type_l3_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l3_shadow, 4, 4)(v, smfn);
break;
- case PGC_SH_l4_64_shadow >> PGC_SH_type_shift:
+ case SH_type_l4_64_shadow:
SHADOW_INTERNAL_NAME(sh_destroy_l4_shadow, 4, 4)(v, smfn);
break;
#endif
@@ -1822,7 +1663,6 @@ int shadow_remove_write_access(struct vcpu *v, mfn_t gmfn,
#endif
NULL, /* l2_pae */
NULL, /* l2h_pae */
- NULL, /* l3_pae */
#if CONFIG_PAGING_LEVELS >= 4
SHADOW_INTERNAL_NAME(sh_remove_write_access,4,4), /* l1_64 */
SHADOW_INTERNAL_NAME(sh_remove_write_access,4,4), /* fl1_64 */
@@ -1838,12 +1678,12 @@ int shadow_remove_write_access(struct vcpu *v, mfn_t gmfn,
};
static unsigned int callback_mask =
- 1 << (PGC_SH_l1_32_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_32_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_l1_pae_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_pae_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_l1_64_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_64_shadow >> PGC_SH_type_shift)
+ 1 << SH_type_l1_32_shadow
+ | 1 << SH_type_fl1_32_shadow
+ | 1 << SH_type_l1_pae_shadow
+ | 1 << SH_type_fl1_pae_shadow
+ | 1 << SH_type_l1_64_shadow
+ | 1 << SH_type_fl1_64_shadow
;
struct page_info *pg = mfn_to_page(gmfn);
@@ -1879,12 +1719,11 @@ int shadow_remove_write_access(struct vcpu *v, mfn_t gmfn,
unsigned long gfn;
/* Heuristic: there is likely to be only one writeable mapping,
* and that mapping is likely to be in the current pagetable,
- * either in the guest's linear map (linux, windows) or in a
- * magic slot used to map high memory regions (linux HIGHTPTE) */
+ * in the guest's linear map (on non-HIGHPTE linux and windows)*/
#define GUESS(_a, _h) do { \
- if ( v->arch.shadow.mode->guess_wrmap(v, (_a), gmfn) ) \
- perfc_incrc(shadow_writeable_h_ ## _h); \
+ if ( v->arch.shadow.mode->guess_wrmap(v, (_a), gmfn) ) \
+ perfc_incrc(shadow_writeable_h_ ## _h); \
if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 ) \
return 1; \
} while (0)
@@ -1926,17 +1765,44 @@ int shadow_remove_write_access(struct vcpu *v, mfn_t gmfn,
case 3: GUESS(0x70381C00000UL + (fault_addr >> 27), 3); break;
}
- /* Linux direct map at 0xffff810000000000 */
+ /* 64bit Linux direct map at 0xffff810000000000; older kernels
+ * had it at 0x0000010000000000UL */
gfn = sh_mfn_to_gfn(v->domain, gmfn);
GUESS(0xffff810000000000UL + (gfn << PAGE_SHIFT), 4);
+ GUESS(0x0000010000000000UL + (gfn << PAGE_SHIFT), 4);
}
#endif /* CONFIG_PAGING_LEVELS >= 4 */
#endif /* CONFIG_PAGING_LEVELS >= 3 */
#undef GUESS
+ }
+
+ if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 )
+ return 1;
+ /* Second heuristic: on HIGHPTE linux, there are two particular PTEs
+ * (entries in the fixmap) where linux maps its pagetables. Since
+ * we expect to hit them most of the time, we start the search for
+ * the writeable mapping by looking at the same MFN where the last
+ * brute-force search succeeded. */
+
+ if ( v->arch.shadow.last_writeable_pte_smfn != 0 )
+ {
+ unsigned long old_count = (pg->u.inuse.type_info & PGT_count_mask);
+ mfn_t last_smfn = _mfn(v->arch.shadow.last_writeable_pte_smfn);
+ int shtype = mfn_to_shadow_page(last_smfn)->type;
+
+ if ( callbacks[shtype] )
+ callbacks[shtype](v, last_smfn, gmfn);
+
+ if ( (pg->u.inuse.type_info & PGT_count_mask) != old_count )
+ perfc_incrc(shadow_writeable_h_5);
}
-#endif
+
+ if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 )
+ return 1;
+
+#endif /* SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC */
/* Brute-force search of all the shadows, by walking the hash */
perfc_incrc(shadow_writeable_bf);
@@ -1986,7 +1852,6 @@ int shadow_remove_all_mappings(struct vcpu *v, mfn_t gmfn)
#endif
NULL, /* l2_pae */
NULL, /* l2h_pae */
- NULL, /* l3_pae */
#if CONFIG_PAGING_LEVELS >= 4
SHADOW_INTERNAL_NAME(sh_remove_all_mappings,4,4), /* l1_64 */
SHADOW_INTERNAL_NAME(sh_remove_all_mappings,4,4), /* fl1_64 */
@@ -2002,12 +1867,12 @@ int shadow_remove_all_mappings(struct vcpu *v, mfn_t gmfn)
};
static unsigned int callback_mask =
- 1 << (PGC_SH_l1_32_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_32_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_l1_pae_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_pae_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_l1_64_shadow >> PGC_SH_type_shift)
- | 1 << (PGC_SH_fl1_64_shadow >> PGC_SH_type_shift)
+ 1 << SH_type_l1_32_shadow
+ | 1 << SH_type_fl1_32_shadow
+ | 1 << SH_type_l1_pae_shadow
+ | 1 << SH_type_fl1_pae_shadow
+ | 1 << SH_type_l1_64_shadow
+ | 1 << SH_type_fl1_64_shadow
;
perfc_incrc(shadow_mappings);
@@ -2051,33 +1916,34 @@ static int sh_remove_shadow_via_pointer(struct vcpu *v, mfn_t smfn)
/* Follow this shadow's up-pointer, if it has one, and remove the reference
* found there. Returns 1 if that was the only reference to this shadow */
{
- struct page_info *pg = mfn_to_page(smfn);
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
mfn_t pmfn;
void *vaddr;
int rc;
- ASSERT((pg->count_info & PGC_SH_type_mask) > 0);
- ASSERT((pg->count_info & PGC_SH_type_mask) < PGC_SH_max_shadow);
- ASSERT((pg->count_info & PGC_SH_type_mask) != PGC_SH_l2_32_shadow);
- ASSERT((pg->count_info & PGC_SH_type_mask) != PGC_SH_l3_pae_shadow);
- ASSERT((pg->count_info & PGC_SH_type_mask) != PGC_SH_l4_64_shadow);
+ ASSERT(sp->type > 0);
+ ASSERT(sp->type < SH_type_max_shadow);
+ ASSERT(sp->type != SH_type_l2_32_shadow);
+ ASSERT(sp->type != SH_type_l2_pae_shadow);
+ ASSERT(sp->type != SH_type_l2h_pae_shadow);
+ ASSERT(sp->type != SH_type_l4_64_shadow);
- if (pg->up == 0) return 0;
- pmfn = _mfn(pg->up >> PAGE_SHIFT);
- ASSERT(valid_mfn(pmfn));
+ if (sp->up == 0) return 0;
+ pmfn = _mfn(sp->up >> PAGE_SHIFT);
+ ASSERT(mfn_valid(pmfn));
vaddr = sh_map_domain_page(pmfn);
ASSERT(vaddr);
- vaddr += pg->up & (PAGE_SIZE-1);
+ vaddr += sp->up & (PAGE_SIZE-1);
ASSERT(l1e_get_pfn(*(l1_pgentry_t *)vaddr) == mfn_x(smfn));
/* Is this the only reference to this shadow? */
- rc = ((pg->count_info & PGC_SH_count_mask) == 1) ? 1 : 0;
+ rc = (sp->count == 1) ? 1 : 0;
/* Blank the offending entry */
- switch ((pg->count_info & PGC_SH_type_mask))
+ switch (sp->type)
{
- case PGC_SH_l1_32_shadow:
- case PGC_SH_l2_32_shadow:
+ case SH_type_l1_32_shadow:
+ case SH_type_l2_32_shadow:
#if CONFIG_PAGING_LEVELS == 2
SHADOW_INTERNAL_NAME(sh_clear_shadow_entry,2,2)(v, vaddr, pmfn);
#else
@@ -2085,17 +1951,16 @@ static int sh_remove_shadow_via_pointer(struct vcpu *v, mfn_t smfn)
#endif
break;
#if CONFIG_PAGING_LEVELS >=3
- case PGC_SH_l1_pae_shadow:
- case PGC_SH_l2_pae_shadow:
- case PGC_SH_l2h_pae_shadow:
- case PGC_SH_l3_pae_shadow:
+ case SH_type_l1_pae_shadow:
+ case SH_type_l2_pae_shadow:
+ case SH_type_l2h_pae_shadow:
SHADOW_INTERNAL_NAME(sh_clear_shadow_entry,3,3)(v, vaddr, pmfn);
break;
#if CONFIG_PAGING_LEVELS >= 4
- case PGC_SH_l1_64_shadow:
- case PGC_SH_l2_64_shadow:
- case PGC_SH_l3_64_shadow:
- case PGC_SH_l4_64_shadow:
+ case SH_type_l1_64_shadow:
+ case SH_type_l2_64_shadow:
+ case SH_type_l3_64_shadow:
+ case SH_type_l4_64_shadow:
SHADOW_INTERNAL_NAME(sh_clear_shadow_entry,4,4)(v, vaddr, pmfn);
break;
#endif
@@ -2112,17 +1977,20 @@ static int sh_remove_shadow_via_pointer(struct vcpu *v, mfn_t smfn)
return rc;
}
-void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all)
+void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all)
/* Remove the shadows of this guest page.
- * If all != 0, find all shadows, if necessary by walking the tables.
- * Otherwise, just try the (much faster) heuristics, which will remove
- * at most one reference to each shadow of the page. */
+ * If fast != 0, just try the quick heuristic, which will remove
+ * at most one reference to each shadow of the page. Otherwise, walk
+ * all the shadow tables looking for refs to shadows of this gmfn.
+ * If all != 0, kill the domain if we can't find all the shadows.
+ * (all != 0 implies fast == 0)
+ */
{
struct page_info *pg;
mfn_t smfn;
u32 sh_flags;
unsigned char t;
-
+
/* Dispatch table for getting per-type functions: each level must
* be called with the function to remove a lower-level shadow. */
static hash_callback_t callbacks[16] = {
@@ -2139,11 +2007,9 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all)
#if CONFIG_PAGING_LEVELS >= 3
SHADOW_INTERNAL_NAME(sh_remove_l1_shadow,3,3), /* l2_pae */
SHADOW_INTERNAL_NAME(sh_remove_l1_shadow,3,3), /* l2h_pae */
- SHADOW_INTERNAL_NAME(sh_remove_l2_shadow,3,3), /* l3_pae */
#else
NULL, /* l2_pae */
NULL, /* l2h_pae */
- NULL, /* l3_pae */
#endif
NULL, /* l1_64 */
NULL, /* fl1_64 */
@@ -2163,25 +2029,25 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all)
/* Another lookup table, for choosing which mask to use */
static unsigned int masks[16] = {
0, /* none */
- 1 << (PGC_SH_l2_32_shadow >> PGC_SH_type_shift), /* l1_32 */
+ 1 << SH_type_l2_32_shadow, /* l1_32 */
0, /* fl1_32 */
0, /* l2_32 */
- ((1 << (PGC_SH_l2h_pae_shadow >> PGC_SH_type_shift))
- | (1 << (PGC_SH_l2_pae_shadow >> PGC_SH_type_shift))), /* l1_pae */
+ ((1 << SH_type_l2h_pae_shadow)
+ | (1 << SH_type_l2_pae_shadow)), /* l1_pae */
0, /* fl1_pae */
- 1 << (PGC_SH_l3_pae_shadow >> PGC_SH_type_shift), /* l2_pae */
- 1 << (PGC_SH_l3_pae_shadow >> PGC_SH_type_shift), /* l2h_pae */
- 0, /* l3_pae */
- 1 << (PGC_SH_l2_64_shadow >> PGC_SH_type_shift), /* l1_64 */
+ 0, /* l2_pae */
+ 0, /* l2h_pae */
+ 1 << SH_type_l2_64_shadow, /* l1_64 */
0, /* fl1_64 */
- 1 << (PGC_SH_l3_64_shadow >> PGC_SH_type_shift), /* l2_64 */
- 1 << (PGC_SH_l4_64_shadow >> PGC_SH_type_shift), /* l3_64 */
+ 1 << SH_type_l3_64_shadow, /* l2_64 */
+ 1 << SH_type_l4_64_shadow, /* l3_64 */
0, /* l4_64 */
0, /* p2m */
0 /* unused */
};
ASSERT(shadow_lock_is_acquired(v->domain));
+ ASSERT(!(all && fast));
pg = mfn_to_page(gmfn);
@@ -2200,56 +2066,46 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all)
* This call to hash_foreach() looks dangerous but is in fact OK: each
* call will remove at most one shadow, and terminate immediately when
* it does remove it, so we never walk the hash after doing a deletion. */
-#define DO_UNSHADOW(_type) do { \
- t = (_type) >> PGC_SH_type_shift; \
- smfn = shadow_hash_lookup(v, mfn_x(gmfn), t); \
- if ( !sh_remove_shadow_via_pointer(v, smfn) && all ) \
- hash_foreach(v, masks[t], callbacks, smfn); \
-} while (0)
-
- /* Top-level shadows need to be unpinned */
-#define DO_UNPIN(_type) do { \
- t = (_type) >> PGC_SH_type_shift; \
- smfn = shadow_hash_lookup(v, mfn_x(gmfn), t); \
- if ( mfn_to_page(smfn)->count_info & PGC_SH_pinned ) \
- sh_unpin(v, smfn); \
- if ( (_type) == PGC_SH_l3_pae_shadow ) \
- SHADOW_INTERNAL_NAME(sh_unpin_all_l3_subshadows,3,3)(v, smfn); \
+#define DO_UNSHADOW(_type) do { \
+ t = (_type); \
+ smfn = shadow_hash_lookup(v, mfn_x(gmfn), t); \
+ if ( sh_type_is_pinnable(v, t) ) \
+ sh_unpin(v, smfn); \
+ else \
+ sh_remove_shadow_via_pointer(v, smfn); \
+ if ( (pg->count_info & PGC_page_table) && !fast ) \
+ hash_foreach(v, masks[t], callbacks, smfn); \
} while (0)
- if ( sh_flags & SHF_L1_32 ) DO_UNSHADOW(PGC_SH_l1_32_shadow);
- if ( sh_flags & SHF_L2_32 ) DO_UNPIN(PGC_SH_l2_32_shadow);
+ if ( sh_flags & SHF_L1_32 ) DO_UNSHADOW(SH_type_l1_32_shadow);
+ if ( sh_flags & SHF_L2_32 ) DO_UNSHADOW(SH_type_l2_32_shadow);
#if CONFIG_PAGING_LEVELS >= 3
- if ( sh_flags & SHF_L1_PAE ) DO_UNSHADOW(PGC_SH_l1_pae_shadow);
- if ( sh_flags & SHF_L2_PAE ) DO_UNSHADOW(PGC_SH_l2_pae_shadow);
- if ( sh_flags & SHF_L2H_PAE ) DO_UNSHADOW(PGC_SH_l2h_pae_shadow);
- if ( sh_flags & SHF_L3_PAE ) DO_UNPIN(PGC_SH_l3_pae_shadow);
+ if ( sh_flags & SHF_L1_PAE ) DO_UNSHADOW(SH_type_l1_pae_shadow);
+ if ( sh_flags & SHF_L2_PAE ) DO_UNSHADOW(SH_type_l2_pae_shadow);
+ if ( sh_flags & SHF_L2H_PAE ) DO_UNSHADOW(SH_type_l2h_pae_shadow);
#if CONFIG_PAGING_LEVELS >= 4
- if ( sh_flags & SHF_L1_64 ) DO_UNSHADOW(PGC_SH_l1_64_shadow);
- if ( sh_flags & SHF_L2_64 ) DO_UNSHADOW(PGC_SH_l2_64_shadow);
- if ( sh_flags & SHF_L3_64 ) DO_UNSHADOW(PGC_SH_l3_64_shadow);
- if ( sh_flags & SHF_L4_64 ) DO_UNPIN(PGC_SH_l4_64_shadow);
+ if ( sh_flags & SHF_L1_64 ) DO_UNSHADOW(SH_type_l1_64_shadow);
+ if ( sh_flags & SHF_L2_64 ) DO_UNSHADOW(SH_type_l2_64_shadow);
+ if ( sh_flags & SHF_L3_64 ) DO_UNSHADOW(SH_type_l3_64_shadow);
+ if ( sh_flags & SHF_L4_64 ) DO_UNSHADOW(SH_type_l4_64_shadow);
#endif
#endif
#undef DO_UNSHADOW
-#undef DO_UNPIN
-
-
-#if CONFIG_PAGING_LEVELS > 2
- /* We may have caused some PAE l3 entries to change: need to
- * fix up the copies of them in various places */
- if ( sh_flags & (SHF_L2_PAE|SHF_L2H_PAE) )
- sh_pae_recopy(v->domain);
-#endif
/* If that didn't catch the shadows, something is wrong */
- if ( all && (pg->count_info & PGC_page_table) )
+ if ( !fast && (pg->count_info & PGC_page_table) )
{
- SHADOW_ERROR("can't find all shadows of mfn %05lx (shadow_flags=%08x)\n",
+ SHADOW_ERROR("can't find all shadows of mfn %05lx "
+ "(shadow_flags=%08lx)\n",
mfn_x(gmfn), pg->shadow_flags);
- domain_crash(v->domain);
+ if ( all )
+ domain_crash(v->domain);
}
+
+ /* Need to flush TLBs now, so that linear maps are safe next time we
+ * take a fault. */
+ flush_tlb_mask(v->domain->domain_dirty_cpumask);
}
void
@@ -2286,20 +2142,11 @@ void sh_update_paging_modes(struct vcpu *v)
// - changes in CR0.PG, CR4.PAE, CR4.PSE, or CR4.PGE
//
- // Avoid determining the current shadow mode for uninitialized CPUs, as
- // we can not yet determine whether it is an HVM or PV domain.
- //
- if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
- {
- printk("%s: postponing determination of shadow mode\n", __func__);
- return;
- }
-
// First, tear down any old shadow tables held by this vcpu.
//
shadow_detach_old_tables(v);
- if ( !hvm_guest(v) )
+ if ( !is_hvm_domain(d) )
{
///
/// PV guest
@@ -2316,6 +2163,7 @@ void sh_update_paging_modes(struct vcpu *v)
#else
#error unexpected paging mode
#endif
+ v->arch.shadow.translate_enabled = !!shadow_mode_translate(d);
}
else
{
@@ -2325,10 +2173,9 @@ void sh_update_paging_modes(struct vcpu *v)
ASSERT(shadow_mode_translate(d));
ASSERT(shadow_mode_external(d));
- v->arch.shadow.hvm_paging_enabled = !!hvm_paging_enabled(v);
- if ( !v->arch.shadow.hvm_paging_enabled )
+ v->arch.shadow.translate_enabled = !!hvm_paging_enabled(v);
+ if ( !v->arch.shadow.translate_enabled )
{
-
/* Set v->arch.guest_table to use the p2m map, and choose
* the appropriate shadow mode */
old_guest_table = pagetable_get_mfn(v->arch.guest_table);
@@ -2369,7 +2216,7 @@ void sh_update_paging_modes(struct vcpu *v)
}
else
#endif
- if ( hvm_get_guest_ctrl_reg(v, 4) & X86_CR4_PAE )
+ if ( hvm_pae_enabled(v) )
{
#if CONFIG_PAGING_LEVELS >= 3
// 32-bit PAE mode guest...
@@ -2403,13 +2250,14 @@ void sh_update_paging_modes(struct vcpu *v)
if ( v->arch.shadow.mode != old_mode )
{
- SHADOW_PRINTK("new paging mode: d=%u v=%u g=%u s=%u "
- "(was g=%u s=%u)\n",
- d->domain_id, v->vcpu_id,
- v->arch.shadow.mode->guest_levels,
- v->arch.shadow.mode->shadow_levels,
- old_mode ? old_mode->guest_levels : 0,
- old_mode ? old_mode->shadow_levels : 0);
+ SHADOW_PRINTK("new paging mode: d=%u v=%u pe=%d g=%u s=%u "
+ "(was g=%u s=%u)\n",
+ d->domain_id, v->vcpu_id,
+ is_hvm_domain(d) ? !!hvm_paging_enabled(v) : 1,
+ v->arch.shadow.mode->guest_levels,
+ v->arch.shadow.mode->shadow_levels,
+ old_mode ? old_mode->guest_levels : 0,
+ old_mode ? old_mode->shadow_levels : 0);
if ( old_mode &&
(v->arch.shadow.mode->shadow_levels !=
old_mode->shadow_levels) )
@@ -2472,7 +2320,7 @@ static void sh_new_mode(struct domain *d, u32 new_mode)
sh_update_paging_modes(v);
}
-static int shadow_enable(struct domain *d, u32 mode)
+int shadow_enable(struct domain *d, u32 mode)
/* Turn on "permanent" shadow features: external, translate, refcount.
* Can only be called once on a domain, and these features cannot be
* disabled.
@@ -2489,6 +2337,7 @@ static int shadow_enable(struct domain *d, u32 mode)
/* Sanity check the arguments */
if ( (d == current->domain) ||
shadow_mode_enabled(d) ||
+ ((mode & SHM2_translate) && !(mode & SHM2_refcounts)) ||
((mode & SHM2_external) && !(mode & SHM2_translate)) )
{
rv = -EINVAL;
@@ -2538,13 +2387,19 @@ static int shadow_enable(struct domain *d, u32 mode)
goto out;
}
+#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
+ /* We assume we're dealing with an older 64bit linux guest until we
+ * see the guest use more than one l4 per vcpu. */
+ d->arch.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL;
+#endif
+
/* Update the bits */
sh_new_mode(d, mode);
shadow_audit_p2m(d);
out:
shadow_unlock(d);
domain_unpause(d);
- return 0;
+ return rv;
}
void shadow_teardown(struct domain *d)
@@ -2569,7 +2424,7 @@ void shadow_teardown(struct domain *d)
if ( shadow_mode_external(d) )
{
mfn = pagetable_get_mfn(v->arch.monitor_table);
- if ( valid_mfn(mfn) && (mfn_x(mfn) != 0) )
+ if ( mfn_valid(mfn) && (mfn_x(mfn) != 0) )
shadow_destroy_monitor_table(v, mfn);
v->arch.monitor_table = pagetable_null();
}
@@ -2732,7 +2587,7 @@ int shadow_test_enable(struct domain *d)
if ( shadow_mode_enabled(d) )
{
SHADOW_ERROR("Don't support enabling test mode"
- "on already shadowed doms\n");
+ " on already shadowed doms\n");
ret = -EINVAL;
goto out;
}
@@ -2805,7 +2660,7 @@ static int shadow_log_dirty_enable(struct domain *d)
if ( shadow_mode_enabled(d) )
{
SHADOW_ERROR("Don't (yet) support enabling log-dirty"
- "on already shadowed doms\n");
+ " on already shadowed doms\n");
ret = -EINVAL;
goto out;
}
@@ -2857,15 +2712,18 @@ sh_p2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn)
if ( v->domain != d )
v = d->vcpu[0];
-
SHADOW_DEBUG(P2M, "removing gfn=%#lx mfn=%#lx\n", gfn, mfn);
ASSERT(mfn_x(sh_gfn_to_mfn(d, gfn)) == mfn);
//ASSERT(sh_mfn_to_gfn(d, mfn) == gfn);
- shadow_remove_all_shadows_and_parents(v, _mfn(mfn));
- if ( shadow_remove_all_mappings(v, _mfn(mfn)) )
- flush_tlb_mask(d->domain_dirty_cpumask);
+ if ( v != NULL )
+ {
+ shadow_remove_all_shadows_and_parents(v, _mfn(mfn));
+ if ( shadow_remove_all_mappings(v, _mfn(mfn)) )
+ flush_tlb_mask(d->domain_dirty_cpumask);
+ }
+
shadow_set_p2m_entry(d, gfn, _mfn(INVALID_MFN));
set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
}
@@ -2885,31 +2743,32 @@ void
shadow_guest_physmap_add_page(struct domain *d, unsigned long gfn,
unsigned long mfn)
{
- struct vcpu *v;
unsigned long ogfn;
mfn_t omfn;
if ( !shadow_mode_translate(d) )
return;
- v = current;
- if ( v->domain != d )
- v = d->vcpu[0];
-
shadow_lock(d);
shadow_audit_p2m(d);
SHADOW_DEBUG(P2M, "adding gfn=%#lx mfn=%#lx\n", gfn, mfn);
omfn = sh_gfn_to_mfn(d, gfn);
- if ( valid_mfn(omfn) )
+ if ( mfn_valid(omfn) )
{
/* Get rid of the old mapping, especially any shadows */
- shadow_remove_all_shadows_and_parents(v, omfn);
- if ( shadow_remove_all_mappings(v, omfn) )
- flush_tlb_mask(d->domain_dirty_cpumask);
+ struct vcpu *v = current;
+ if ( v->domain != d )
+ v = d->vcpu[0];
+ if ( v != NULL )
+ {
+ shadow_remove_all_shadows_and_parents(v, omfn);
+ if ( shadow_remove_all_mappings(v, omfn) )
+ flush_tlb_mask(d->domain_dirty_cpumask);
+ }
set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);
- }
+ }
ogfn = sh_mfn_to_gfn(d, _mfn(mfn));
if (
@@ -2924,7 +2783,7 @@ shadow_guest_physmap_add_page(struct domain *d, unsigned long gfn,
/* This machine frame is already mapped at another physical address */
SHADOW_DEBUG(P2M, "aliased! mfn=%#lx, old gfn=%#lx, new gfn=%#lx\n",
mfn, ogfn, gfn);
- if ( valid_mfn(omfn = sh_gfn_to_mfn(d, ogfn)) )
+ if ( mfn_valid(omfn = sh_gfn_to_mfn(d, ogfn)) )
{
SHADOW_DEBUG(P2M, "old gfn=%#lx -> mfn %#lx\n",
ogfn , mfn_x(omfn));
@@ -2972,17 +2831,10 @@ static int shadow_log_dirty_op(
if ( clean )
{
- struct list_head *l, *t;
- struct page_info *pg;
-
/* Need to revoke write access to the domain's pages again.
* In future, we'll have a less heavy-handed approach to this,
* but for now, we just unshadow everything except Xen. */
- list_for_each_safe(l, t, &d->arch.shadow.toplevel_shadows)
- {
- pg = list_entry(l, struct page_info, list);
- shadow_unhook_mappings(d->vcpu[0], page_to_mfn(pg));
- }
+ shadow_blow_tables(d);
d->arch.shadow.fault_count = 0;
d->arch.shadow.dirty_count = 0;
@@ -3036,7 +2888,7 @@ void sh_do_mark_dirty(struct domain *d, mfn_t gmfn)
ASSERT(shadow_lock_is_acquired(d));
ASSERT(shadow_mode_log_dirty(d));
- if ( !valid_mfn(gmfn) )
+ if ( !mfn_valid(gmfn) )
return;
ASSERT(d->arch.shadow.dirty_bitmap != NULL);
@@ -3092,7 +2944,7 @@ int shadow_domctl(struct domain *d,
if ( unlikely(d == current->domain) )
{
- DPRINTK("Don't try to do a shadow op on yourself!\n");
+ gdprintk(XENLOG_INFO, "Don't try to do a shadow op on yourself!\n");
return -EINVAL;
}
@@ -3102,6 +2954,8 @@ int shadow_domctl(struct domain *d,
if ( shadow_mode_log_dirty(d) )
if ( (rc = shadow_log_dirty_disable(d)) != 0 )
return rc;
+ if ( is_hvm_domain(d) )
+ return -EINVAL;
if ( d->arch.shadow.mode & SHM2_enable )
if ( (rc = shadow_test_disable(d)) != 0 )
return rc;
@@ -3169,7 +3023,6 @@ void shadow_audit_tables(struct vcpu *v)
SHADOW_INTERNAL_NAME(sh_audit_fl1_table,3,3), /* fl1_pae */
SHADOW_INTERNAL_NAME(sh_audit_l2_table,3,3), /* l2_pae */
SHADOW_INTERNAL_NAME(sh_audit_l2_table,3,3), /* l2h_pae */
- SHADOW_INTERNAL_NAME(sh_audit_l3_table,3,3), /* l3_pae */
#if CONFIG_PAGING_LEVELS >= 4
SHADOW_INTERNAL_NAME(sh_audit_l1_table,4,4), /* l1_64 */
SHADOW_INTERNAL_NAME(sh_audit_fl1_table,4,4), /* fl1_64 */
@@ -3194,7 +3047,7 @@ void shadow_audit_tables(struct vcpu *v)
{
case 2: mask = (SHF_L1_32|SHF_FL1_32|SHF_L2_32); break;
case 3: mask = (SHF_L1_PAE|SHF_FL1_PAE|SHF_L2_PAE
- |SHF_L2H_PAE|SHF_L3_PAE); break;
+ |SHF_L2H_PAE); break;
case 4: mask = (SHF_L1_64|SHF_FL1_64|SHF_L2_64
|SHF_L3_64|SHF_L4_64); break;
default: BUG();
@@ -3284,13 +3137,14 @@ void shadow_audit_p2m(struct domain *d)
set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY);
}
- if ( test_linear )
+ if ( test_linear && (gfn <= d->arch.max_mapped_pfn) )
{
- lp2mfn = get_mfn_from_gpfn(gfn);
- if ( lp2mfn != mfn_x(p2mfn) )
+ lp2mfn = gfn_to_mfn_current(gfn);
+ if ( mfn_x(lp2mfn) != mfn_x(p2mfn) )
{
SHADOW_PRINTK("linear mismatch gfn %#lx -> mfn %#lx "
- "(!= mfn %#lx)\n", gfn, lp2mfn, p2mfn);
+ "(!= mfn %#lx)\n", gfn,
+ mfn_x(lp2mfn), mfn_x(p2mfn));
}
}
@@ -3355,7 +3209,7 @@ void shadow_audit_p2m(struct domain *d)
if ( !(l1e_get_flags(l1e[i1]) & _PAGE_PRESENT) )
continue;
mfn = l1e_get_pfn(l1e[i1]);
- ASSERT(valid_mfn(_mfn(mfn)));
+ ASSERT(mfn_valid(_mfn(mfn)));
m2pfn = get_gpfn_from_mfn(mfn);
if ( m2pfn != gfn )
{
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index ace6a258f3..c582b82b51 100644
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -21,22 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// DESIGN QUESTIONS:
-// Why use subshadows for PAE guests?
-// - reduces pressure in the hash table
-// - reduces shadow size (64-vs-4096 bytes of shadow for 32 bytes of guest L3)
-// - would need to find space in the page_info to store 7 more bits of
-// backpointer
-// - independent shadows of 32 byte chunks makes it non-obvious how to quickly
-// figure out when to demote the guest page from l3 status
-//
-// PAE Xen HVM guests are restricted to 8GB of pseudo-physical address space.
-// - Want to map the P2M table into the 16MB RO_MPT hole in Xen's address
-// space for both PV and HVM guests.
-//
-
-#define SHADOW 1
-
#include <xen/config.h>
#include <xen/types.h>
#include <xen/mm.h>
@@ -52,14 +36,7 @@
#include "private.h"
#include "types.h"
-/* The first cut: an absolutely synchronous, trap-and-emulate version,
- * supporting only HVM guests (and so only "external" shadow mode).
- *
- * THINGS TO DO LATER:
- *
- * FIX GVA_TO_GPA
- * The current interface returns an unsigned long, which is not big enough
- * to hold a physical address in PAE. Should return a gfn instead.
+/* THINGS TO DO LATER:
*
* TEARDOWN HEURISTICS
* Also: have a heuristic for when to destroy a previous paging-mode's
@@ -76,14 +53,6 @@
* l3-and-l2h-only shadow mode for PAE PV guests that would allow them
* to share l2h pages again.
*
- * PAE L3 COPYING
- * In this code, we copy all 32 bytes of a PAE L3 every time we change an
- * entry in it, and every time we change CR3. We copy it for the linear
- * mappings (ugh! PAE linear mappings) and we copy it to the low-memory
- * buffer so it fits in CR3. Maybe we can avoid some of this recopying
- * by using the shadow directly in some places.
- * Also, for SMP, need to actually respond to seeing shadow.pae_flip_pending.
- *
* GUEST_WALK_TABLES TLB FLUSH COALESCE
* guest_walk_tables can do up to three remote TLB flushes as it walks to
* the first l1 of a new pagetable. Should coalesce the flushes to the end,
@@ -119,33 +88,24 @@ static char *fetch_type_names[] = {
};
#endif
-/* XXX forward declarations */
-#if (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3)
-static unsigned long hvm_pae_copy_root(struct vcpu *v, l3_pgentry_t *l3tab, int clear_res);
-#endif
-static inline void sh_update_linear_entries(struct vcpu *v);
-
/**************************************************************************/
/* Hash table mapping from guest pagetables to shadows
*
* Normal case: maps the mfn of a guest page to the mfn of its shadow page.
* FL1's: maps the *gfn* of the start of a superpage to the mfn of a
* shadow L1 which maps its "splinters".
- * PAE CR3s: maps the 32-byte aligned, 32-bit CR3 value to the mfn of the
- * PAE L3 info page for that CR3 value.
*/
static inline mfn_t
get_fl1_shadow_status(struct vcpu *v, gfn_t gfn)
/* Look for FL1 shadows in the hash table */
{
- mfn_t smfn = shadow_hash_lookup(v, gfn_x(gfn),
- PGC_SH_fl1_shadow >> PGC_SH_type_shift);
+ mfn_t smfn = shadow_hash_lookup(v, gfn_x(gfn), SH_type_fl1_shadow);
- if ( unlikely(shadow_mode_log_dirty(v->domain) && valid_mfn(smfn)) )
+ if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) )
{
- struct page_info *page = mfn_to_page(smfn);
- if ( !(page->count_info & PGC_SH_log_dirty) )
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
+ if ( !(sp->logdirty) )
shadow_convert_to_log_dirty(v, smfn);
}
@@ -156,14 +116,13 @@ static inline mfn_t
get_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
/* Look for shadows in the hash table */
{
- mfn_t smfn = shadow_hash_lookup(v, mfn_x(gmfn),
- shadow_type >> PGC_SH_type_shift);
+ mfn_t smfn = shadow_hash_lookup(v, mfn_x(gmfn), shadow_type);
perfc_incrc(shadow_get_shadow_status);
- if ( unlikely(shadow_mode_log_dirty(v->domain) && valid_mfn(smfn)) )
+ if ( unlikely(shadow_mode_log_dirty(v->domain) && mfn_valid(smfn)) )
{
- struct page_info *page = mfn_to_page(smfn);
- if ( !(page->count_info & PGC_SH_log_dirty) )
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
+ if ( !(sp->logdirty) )
shadow_convert_to_log_dirty(v, smfn);
}
@@ -175,16 +134,15 @@ set_fl1_shadow_status(struct vcpu *v, gfn_t gfn, mfn_t smfn)
/* Put an FL1 shadow into the hash table */
{
SHADOW_PRINTK("gfn=%"SH_PRI_gfn", type=%08x, smfn=%05lx\n",
- gfn_x(gfn), PGC_SH_fl1_shadow, mfn_x(smfn));
+ gfn_x(gfn), SH_type_fl1_shadow, mfn_x(smfn));
if ( unlikely(shadow_mode_log_dirty(v->domain)) )
// mark this shadow as a log dirty shadow...
- set_bit(_PGC_SH_log_dirty, &mfn_to_page(smfn)->count_info);
+ mfn_to_shadow_page(smfn)->logdirty = 1;
else
- clear_bit(_PGC_SH_log_dirty, &mfn_to_page(smfn)->count_info);
+ mfn_to_shadow_page(smfn)->logdirty = 0;
- shadow_hash_insert(v, gfn_x(gfn),
- PGC_SH_fl1_shadow >> PGC_SH_type_shift, smfn);
+ shadow_hash_insert(v, gfn_x(gfn), SH_type_fl1_shadow, smfn);
}
static inline void
@@ -200,15 +158,14 @@ set_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type, mfn_t smfn)
if ( unlikely(shadow_mode_log_dirty(d)) )
// mark this shadow as a log dirty shadow...
- set_bit(_PGC_SH_log_dirty, &mfn_to_page(smfn)->count_info);
+ mfn_to_shadow_page(smfn)->logdirty = 1;
else
- clear_bit(_PGC_SH_log_dirty, &mfn_to_page(smfn)->count_info);
+ mfn_to_shadow_page(smfn)->logdirty = 0;
res = get_page(mfn_to_page(gmfn), d);
ASSERT(res == 1);
- shadow_hash_insert(v, mfn_x(gmfn), shadow_type >> PGC_SH_type_shift,
- smfn);
+ shadow_hash_insert(v, mfn_x(gmfn), shadow_type, smfn);
}
static inline void
@@ -216,10 +173,8 @@ delete_fl1_shadow_status(struct vcpu *v, gfn_t gfn, mfn_t smfn)
/* Remove a shadow from the hash table */
{
SHADOW_PRINTK("gfn=%"SH_PRI_gfn", type=%08x, smfn=%05lx\n",
- gfn_x(gfn), PGC_SH_fl1_shadow, mfn_x(smfn));
-
- shadow_hash_delete(v, gfn_x(gfn),
- PGC_SH_fl1_shadow >> PGC_SH_type_shift, smfn);
+ gfn_x(gfn), SH_type_fl1_shadow, mfn_x(smfn));
+ shadow_hash_delete(v, gfn_x(gfn), SH_type_fl1_shadow, smfn);
}
static inline void
@@ -229,8 +184,7 @@ delete_shadow_status(struct vcpu *v, mfn_t gmfn, u32 shadow_type, mfn_t smfn)
SHADOW_PRINTK("d=%d, v=%d, gmfn=%05lx, type=%08x, smfn=%05lx\n",
v->domain->domain_id, v->vcpu_id,
mfn_x(gmfn), shadow_type, mfn_x(smfn));
- shadow_hash_delete(v, mfn_x(gmfn),
- shadow_type >> PGC_SH_type_shift, smfn);
+ shadow_hash_delete(v, mfn_x(gmfn), shadow_type, smfn);
put_page(mfn_to_page(gmfn));
}
@@ -242,14 +196,14 @@ guest_supports_superpages(struct vcpu *v)
{
/* The _PAGE_PSE bit must be honoured in HVM guests, whenever
* CR4.PSE is set or the guest is in PAE or long mode */
- return (hvm_guest(v) && (GUEST_PAGING_LEVELS != 2
+ return (is_hvm_vcpu(v) && (GUEST_PAGING_LEVELS != 2
|| (hvm_get_guest_ctrl_reg(v, 4) & X86_CR4_PSE)));
}
static inline int
guest_supports_nx(struct vcpu *v)
{
- if ( !hvm_guest(v) )
+ if ( !is_hvm_vcpu(v) )
return cpu_has_nx;
// XXX - fix this!
@@ -287,7 +241,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op)
/* Walk down to the l3e */
if ( !(guest_l4e_get_flags(*gw->l4e) & _PAGE_PRESENT) ) return 0;
gw->l3mfn = vcpu_gfn_to_mfn(v, guest_l4e_get_gfn(*gw->l4e));
- if ( !valid_mfn(gw->l3mfn) ) return 1;
+ if ( !mfn_valid(gw->l3mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op && shadow_remove_write_access(v, gw->l3mfn, 3, va) != 0 )
flush_tlb_mask(v->domain->domain_dirty_cpumask);
@@ -301,7 +255,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op)
/* Walk down to the l2e */
if ( !(guest_l3e_get_flags(*gw->l3e) & _PAGE_PRESENT) ) return 0;
gw->l2mfn = vcpu_gfn_to_mfn(v, guest_l3e_get_gfn(*gw->l3e));
- if ( !valid_mfn(gw->l2mfn) ) return 1;
+ if ( !mfn_valid(gw->l2mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op && shadow_remove_write_access(v, gw->l2mfn, 2, va) != 0 )
flush_tlb_mask(v->domain->domain_dirty_cpumask);
@@ -342,7 +296,7 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op)
{
/* Not a superpage: carry on and find the l1e. */
gw->l1mfn = vcpu_gfn_to_mfn(v, guest_l2e_get_gfn(*gw->l2e));
- if ( !valid_mfn(gw->l1mfn) ) return 1;
+ if ( !mfn_valid(gw->l1mfn) ) return 1;
/* This mfn is a pagetable: make sure the guest can't write to it. */
if ( guest_op
&& shadow_remove_write_access(v, gw->l1mfn, 1, va) != 0 )
@@ -431,36 +385,34 @@ static void sh_audit_gw(struct vcpu *v, walk_t *gw)
if ( !(SHADOW_AUDIT_ENABLE) )
return;
-#if GUEST_PAGING_LEVELS >= 3 /* PAE or 64... */
#if GUEST_PAGING_LEVELS >= 4 /* 64-bit only... */
- if ( valid_mfn(gw->l4mfn)
- && valid_mfn((smfn = get_shadow_status(v, gw->l4mfn,
- PGC_SH_l4_shadow))) )
+ if ( mfn_valid(gw->l4mfn)
+ && mfn_valid((smfn = get_shadow_status(v, gw->l4mfn,
+ SH_type_l4_shadow))) )
(void) sh_audit_l4_table(v, smfn, _mfn(INVALID_MFN));
-#endif /* PAE or 64... */
- if ( valid_mfn(gw->l3mfn)
- && valid_mfn((smfn = get_shadow_status(v, gw->l3mfn,
- PGC_SH_l3_shadow))) )
+ if ( mfn_valid(gw->l3mfn)
+ && mfn_valid((smfn = get_shadow_status(v, gw->l3mfn,
+ SH_type_l3_shadow))) )
(void) sh_audit_l3_table(v, smfn, _mfn(INVALID_MFN));
-#endif /* All levels... */
- if ( valid_mfn(gw->l2mfn) )
+#endif /* PAE or 64... */
+ if ( mfn_valid(gw->l2mfn) )
{
- if ( valid_mfn((smfn = get_shadow_status(v, gw->l2mfn,
- PGC_SH_l2_shadow))) )
+ if ( mfn_valid((smfn = get_shadow_status(v, gw->l2mfn,
+ SH_type_l2_shadow))) )
(void) sh_audit_l2_table(v, smfn, _mfn(INVALID_MFN));
#if GUEST_PAGING_LEVELS == 3
- if ( valid_mfn((smfn = get_shadow_status(v, gw->l2mfn,
- PGC_SH_l2h_shadow))) )
+ if ( mfn_valid((smfn = get_shadow_status(v, gw->l2mfn,
+ SH_type_l2h_shadow))) )
(void) sh_audit_l2_table(v, smfn, _mfn(INVALID_MFN));
#endif
}
- if ( valid_mfn(gw->l1mfn)
- && valid_mfn((smfn = get_shadow_status(v, gw->l1mfn,
- PGC_SH_l1_shadow))) )
+ if ( mfn_valid(gw->l1mfn)
+ && mfn_valid((smfn = get_shadow_status(v, gw->l1mfn,
+ SH_type_l1_shadow))) )
(void) sh_audit_l1_table(v, smfn, _mfn(INVALID_MFN));
else if ( gw->l2e
&& (guest_l2e_get_flags(*gw->l2e) & _PAGE_PSE)
- && valid_mfn(
+ && mfn_valid(
(smfn = get_fl1_shadow_status(v, guest_l2e_get_gfn(*gw->l2e)))) )
(void) sh_audit_fl1_table(v, smfn, _mfn(INVALID_MFN));
}
@@ -485,30 +437,31 @@ static u32 guest_set_ad_bits(struct vcpu *v,
unsigned int level,
fetch_type_t ft)
{
- u32 flags, shflags, bit;
- struct page_info *pg;
+ u32 flags;
int res = 0;
- ASSERT(valid_mfn(gmfn)
- && (sh_mfn_is_a_page_table(gmfn)
- || ((mfn_to_page(gmfn)->u.inuse.type_info & PGT_count_mask)
- == 0)));
ASSERT(ep && !(((unsigned long)ep) & ((sizeof *ep) - 1)));
ASSERT(level <= GUEST_PAGING_LEVELS);
- ASSERT(ft == ft_demand_read || ft == ft_demand_write);
ASSERT(shadow_lock_is_acquired(v->domain));
flags = guest_l1e_get_flags(*ep);
- /* PAE l3s do not have A and D bits */
- if ( unlikely(GUEST_PAGING_LEVELS == 3 && level == 3) )
+ /* Only set A and D bits for guest-initiated accesses */
+ if ( !(ft & FETCH_TYPE_DEMAND) )
return flags;
- /* Need the D bit as well for writes, in l1es and 32bit/PAE PSE l2es. */
+ ASSERT(mfn_valid(gmfn)
+ && (sh_mfn_is_a_page_table(gmfn)
+ || ((mfn_to_page(gmfn)->u.inuse.type_info & PGT_count_mask)
+ == 0)));
+
+ /* PAE l3s do not have A and D bits */
+ ASSERT(GUEST_PAGING_LEVELS > 3 || level != 3);
+
+ /* Need the D bit as well for writes, in L1es and PSE L2es. */
if ( ft == ft_demand_write
- && (level == 1 ||
- (level == 2 && GUEST_PAGING_LEVELS < 4
- && (flags & _PAGE_PSE) && guest_supports_superpages(v))) )
+ && (level == 1 ||
+ (level == 2 && (flags & _PAGE_PSE) && guest_supports_superpages(v))) )
{
if ( (flags & (_PAGE_DIRTY | _PAGE_ACCESSED))
== (_PAGE_DIRTY | _PAGE_ACCESSED) )
@@ -526,77 +479,78 @@ static u32 guest_set_ad_bits(struct vcpu *v,
/* Set the bit(s) */
sh_mark_dirty(v->domain, gmfn);
- SHADOW_DEBUG(A_AND_D, "gfn = %"SH_PRI_gfn", "
- "old flags = %#x, new flags = %#x\n",
- guest_l1e_get_gfn(*ep), guest_l1e_get_flags(*ep), flags);
+ SHADOW_DEBUG(A_AND_D, "gfn = %" SH_PRI_gfn ", "
+ "old flags = %#x, new flags = %#x\n",
+ gfn_x(guest_l1e_get_gfn(*ep)), guest_l1e_get_flags(*ep),
+ flags);
*ep = guest_l1e_from_gfn(guest_l1e_get_gfn(*ep), flags);
- /* May need to propagate this change forward to other kinds of shadow */
- pg = mfn_to_page(gmfn);
- if ( !sh_mfn_is_a_page_table(gmfn) )
+ /* Propagate this change to any other shadows of the page
+ * (only necessary if there is more than one shadow) */
+ if ( mfn_to_page(gmfn)->count_info & PGC_page_table )
{
- /* This guest pagetable is not yet shadowed at all. */
- // MAF: I think this assert is busted... If this gmfn has not yet
- // been promoted, then it seems perfectly reasonable for there to be
- // outstanding type refs to it...
- /* TJD: No. If the gmfn has not been promoted, we must at least
- * have recognised that it is a pagetable, and pulled write access.
- * The type count should only be non-zero if it is actually a page
- * table. The test above was incorrect, though, so I've fixed it. */
- ASSERT((pg->u.inuse.type_info & PGT_count_mask) == 0);
- return flags;
+ u32 shflags = mfn_to_page(gmfn)->shadow_flags & SHF_page_type_mask;
+ /* More than one type bit set in shadow-flags? */
+ if ( shflags & ~(1UL << find_first_set_bit(shflags)) )
+ res = __shadow_validate_guest_entry(v, gmfn, ep, sizeof(*ep));
}
- shflags = pg->shadow_flags & SHF_page_type_mask;
- while ( shflags )
- {
- bit = find_first_set_bit(shflags);
- ASSERT(shflags & (1u << bit));
- shflags &= ~(1u << bit);
- if ( !(pg->shadow_flags & (1u << bit)) )
- continue;
- switch ( bit )
- {
- case PGC_SH_type_to_index(PGC_SH_l1_shadow):
- if (level != 1)
- res |= sh_map_and_validate_gl1e(v, gmfn, ep, sizeof (*ep));
- break;
- case PGC_SH_type_to_index(PGC_SH_l2_shadow):
- if (level != 2)
- res |= sh_map_and_validate_gl2e(v, gmfn, ep, sizeof (*ep));
- break;
-#if GUEST_PAGING_LEVELS == 3 /* PAE only */
- case PGC_SH_type_to_index(PGC_SH_l2h_shadow):
- if (level != 2)
- res |= sh_map_and_validate_gl2he(v, gmfn, ep, sizeof (*ep));
- break;
-#endif
-#if GUEST_PAGING_LEVELS >= 3 /* PAE or 64... */
- case PGC_SH_type_to_index(PGC_SH_l3_shadow):
- if (level != 3)
- res |= sh_map_and_validate_gl3e(v, gmfn, ep, sizeof (*ep));
- break;
-#if GUEST_PAGING_LEVELS >= 4 /* 64-bit only... */
- case PGC_SH_type_to_index(PGC_SH_l4_shadow):
- if (level != 4)
- res |= sh_map_and_validate_gl4e(v, gmfn, ep, sizeof (*ep));
- break;
-#endif
-#endif
- default:
- SHADOW_ERROR("mfn %"SH_PRI_mfn" is shadowed in multiple "
- "modes: A&D bits may be out of sync (flags=%#x).\n",
- mfn_x(gmfn), pg->shadow_flags);
- /* XXX Shadows in other modes will not be updated, so will
- * have their A and D bits out of sync. */
- }
- }
-
/* We should never need to flush the TLB or recopy PAE entries */
- ASSERT( res == 0 || res == SHADOW_SET_CHANGED );
+ ASSERT((res == 0) || (res == SHADOW_SET_CHANGED));
+
return flags;
}
+#if (CONFIG_PAGING_LEVELS == GUEST_PAGING_LEVELS) && (CONFIG_PAGING_LEVELS == SHADOW_PAGING_LEVELS)
+void *
+sh_guest_map_l1e(struct vcpu *v, unsigned long addr,
+ unsigned long *gl1mfn)
+{
+ void *pl1e = NULL;
+ walk_t gw;
+
+ ASSERT(shadow_mode_translate(v->domain));
+
+ // XXX -- this is expensive, but it's easy to cobble together...
+ // FIXME!
+
+ shadow_lock(v->domain);
+ guest_walk_tables(v, addr, &gw, 1);
+
+ if ( gw.l2e &&
+ (guest_l2e_get_flags(*gw.l2e) & _PAGE_PRESENT) &&
+ !(guest_supports_superpages(v) && (guest_l2e_get_flags(*gw.l2e) & _PAGE_PSE)) )
+ {
+ if ( gl1mfn )
+ *gl1mfn = mfn_x(gw.l1mfn);
+ pl1e = map_domain_page(mfn_x(gw.l1mfn)) +
+ (guest_l1_table_offset(addr) * sizeof(guest_l1e_t));
+ }
+
+ unmap_walk(v, &gw);
+ shadow_unlock(v->domain);
+
+ return pl1e;
+}
+
+void
+sh_guest_get_eff_l1e(struct vcpu *v, unsigned long addr, void *eff_l1e)
+{
+ walk_t gw;
+
+ ASSERT(shadow_mode_translate(v->domain));
+
+ // XXX -- this is expensive, but it's easy to cobble together...
+ // FIXME!
+
+ shadow_lock(v->domain);
+ guest_walk_tables(v, addr, &gw, 1);
+ *(guest_l1e_t *)eff_l1e = gw.eff_l1e;
+ unmap_walk(v, &gw);
+ shadow_unlock(v->domain);
+}
+#endif /* CONFIG==SHADOW==GUEST */
+
/**************************************************************************/
/* Functions to compute the correct index into a shadow page, given an
* index into the guest page (as returned by guest_get_index()).
@@ -657,38 +611,14 @@ shadow_l2_index(mfn_t *smfn, u32 guest_index)
#endif
}
-#if GUEST_PAGING_LEVELS >= 3
+#if GUEST_PAGING_LEVELS >= 4
static inline u32
shadow_l3_index(mfn_t *smfn, u32 guest_index)
{
-#if GUEST_PAGING_LEVELS == 3
- u32 group_id;
-
- // Because we use twice the space in L3 shadows as was consumed in guest
- // L3s, the number of guest entries per shadow page is
- // SHADOW_L2_PAGETABLE_ENTRIES/2. (Note this is *not*
- // SHADOW_L3_PAGETABLE_ENTRIES, which in this case is 4...)
- //
- *smfn = _mfn(mfn_x(*smfn) +
- (guest_index / (SHADOW_L2_PAGETABLE_ENTRIES / 2)));
-
- // We store PAE L3 shadows in groups of 4, alternating shadows and
- // pae_l3_bookkeeping structs. So the effective shadow index is
- // the the group_id * 8 + the offset within the group.
- //
- guest_index %= (SHADOW_L2_PAGETABLE_ENTRIES / 2);
- group_id = guest_index / 4;
- return (group_id * 8) + (guest_index % 4);
-#else
return guest_index;
-#endif
}
-#endif // GUEST_PAGING_LEVELS >= 3
-
-#if GUEST_PAGING_LEVELS >= 4
-
static inline u32
shadow_l4_index(mfn_t *smfn, u32 guest_index)
{
@@ -699,182 +629,156 @@ shadow_l4_index(mfn_t *smfn, u32 guest_index)
/**************************************************************************/
-/* Functions which compute shadow entries from their corresponding guest
- * entries.
- *
- * These are the "heart" of the shadow code.
- *
- * There are two sets of these: those that are called on demand faults (read
- * faults and write faults), and those that are essentially called to
- * "prefetch" (or propagate) entries from the guest into the shadow. The read
- * fault and write fault are handled as two separate cases for L1 entries (due
- * to the _PAGE_DIRTY bit handling), but for L[234], they are grouped together
- * into the respective demand_fault functions.
+/* Function which computes shadow entries from their corresponding guest
+ * entries. This is the "heart" of the shadow code. It operates using
+ * level-1 shadow types, but handles all levels of entry.
+ * Don't call it directly, but use the four wrappers below.
*/
-#define CHECK(_cond) \
-do { \
- if (unlikely(!(_cond))) \
- { \
- printk("%s %s %d ASSERTION (%s) FAILED\n", \
- __func__, __FILE__, __LINE__, #_cond); \
- return -1; \
- } \
-} while (0);
-
-// The function below tries to capture all of the flag manipulation for the
-// demand and propagate functions into one place.
-//
-static always_inline u32
-sh_propagate_flags(struct vcpu *v, mfn_t target_mfn,
- u32 gflags, guest_l1e_t *guest_entry_ptr, mfn_t gmfn,
- int mmio, int level, fetch_type_t ft)
+static always_inline void
+_sh_propagate(struct vcpu *v,
+ void *guest_entry_ptr,
+ mfn_t guest_table_mfn,
+ mfn_t target_mfn,
+ void *shadow_entry_ptr,
+ int level,
+ fetch_type_t ft,
+ int mmio)
{
+ guest_l1e_t *gp = guest_entry_ptr;
+ shadow_l1e_t *sp = shadow_entry_ptr;
struct domain *d = v->domain;
u32 pass_thru_flags;
- u32 sflags;
-
- // XXX -- might want to think about PAT support for HVM guests...
+ u32 gflags, sflags;
-#ifndef NDEBUG
- // MMIO can only occur from L1e's
- //
- if ( mmio )
- CHECK(level == 1);
+ /* We don't shadow PAE l3s */
+ ASSERT(GUEST_PAGING_LEVELS > 3 || level != 3);
- // We should always have a pointer to the guest entry if it's a non-PSE
- // non-MMIO demand access.
- if ( ft & FETCH_TYPE_DEMAND )
- CHECK(guest_entry_ptr || level == 1);
-#endif
+ if ( mfn_valid(guest_table_mfn) )
+ /* Handle A and D bit propagation into the guest */
+ gflags = guest_set_ad_bits(v, guest_table_mfn, gp, level, ft);
+ else
+ {
+ /* Must be an fl1e or a prefetch */
+ ASSERT(level==1 || !(ft & FETCH_TYPE_DEMAND));
+ gflags = guest_l1e_get_flags(*gp);
+ }
- // A not-present guest entry has a special signature in the shadow table,
- // so that we do not have to consult the guest tables multiple times...
- //
if ( unlikely(!(gflags & _PAGE_PRESENT)) )
- return _PAGE_SHADOW_GUEST_NOT_PRESENT;
-
- // Must have a valid target_mfn, unless this is mmio, or unless this is a
- // prefetch. In the case of a prefetch, an invalid mfn means that we can
- // not usefully shadow anything, and so we return early.
- //
- if ( !valid_mfn(target_mfn) )
{
- CHECK((ft == ft_prefetch) || mmio);
- if ( !mmio )
- return 0;
+ /* If a guest l1 entry is not present, shadow with the magic
+ * guest-not-present entry. */
+ if ( level == 1 )
+ *sp = sh_l1e_gnp();
+ else
+ *sp = shadow_l1e_empty();
+ goto done;
}
- // PAE does not allow NX, RW, USER, ACCESSED, or DIRTY bits in its L3e's...
- //
- if ( (SHADOW_PAGING_LEVELS == 3) && (level == 3) )
- pass_thru_flags = _PAGE_PRESENT;
- else
+ if ( level == 1 && mmio )
{
- pass_thru_flags = (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_USER |
- _PAGE_RW | _PAGE_PRESENT);
- if ( guest_supports_nx(v) )
- pass_thru_flags |= _PAGE_NX_BIT;
+ /* Guest l1e maps MMIO space */
+ *sp = sh_l1e_mmio(guest_l1e_get_gfn(*gp), gflags);
+ goto done;
}
- // PAE guests can not put NX, RW, USER, ACCESSED, or DIRTY bits into their
- // L3e's; they are all implied. So we emulate them here.
+ // Must have a valid target_mfn, unless this is a prefetch. In the
+ // case of a prefetch, an invalid mfn means that we can not usefully
+ // shadow anything, and so we return early.
//
- if ( (GUEST_PAGING_LEVELS == 3) && (level == 3) )
- gflags = pass_thru_flags;
+ if ( !mfn_valid(target_mfn) )
+ {
+ ASSERT((ft == ft_prefetch));
+ *sp = shadow_l1e_empty();
+ goto done;
+ }
// Propagate bits from the guest to the shadow.
// Some of these may be overwritten, below.
// Since we know the guest's PRESENT bit is set, we also set the shadow's
// SHADOW_PRESENT bit.
//
- sflags = (gflags & pass_thru_flags) | _PAGE_SHADOW_PRESENT;
-
- // Copy the guest's RW bit into the SHADOW_RW bit.
- //
- if ( gflags & _PAGE_RW )
- sflags |= _PAGE_SHADOW_RW;
+ pass_thru_flags = (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_USER |
+ _PAGE_RW | _PAGE_PRESENT);
+ if ( guest_supports_nx(v) )
+ pass_thru_flags |= _PAGE_NX_BIT;
+ sflags = gflags & pass_thru_flags;
// Set the A&D bits for higher level shadows.
// Higher level entries do not, strictly speaking, have dirty bits, but
// since we use shadow linear tables, each of these entries may, at some
// point in time, also serve as a shadow L1 entry.
- // By setting both the A&D bits in each of these, we eliminate the burden
+ // By setting both the A&D bits in each of these, we eliminate the burden
// on the hardware to update these bits on initial accesses.
//
if ( (level > 1) && !((SHADOW_PAGING_LEVELS == 3) && (level == 3)) )
sflags |= _PAGE_ACCESSED | _PAGE_DIRTY;
-
- // Set the A and D bits in the guest entry, if we need to.
- if ( guest_entry_ptr && (ft & FETCH_TYPE_DEMAND) )
- gflags = guest_set_ad_bits(v, gmfn, guest_entry_ptr, level, ft);
-
// If the A or D bit has not yet been set in the guest, then we must
// prevent the corresponding kind of access.
//
- if ( unlikely(!((GUEST_PAGING_LEVELS == 3) && (level == 3)) &&
- !(gflags & _PAGE_ACCESSED)) )
+ if ( unlikely(!(gflags & _PAGE_ACCESSED)) )
sflags &= ~_PAGE_PRESENT;
- /* D bits exist in l1es, and 32bit/PAE PSE l2es, but not 64bit PSE l2es */
- if ( unlikely( ((level == 1)
- || ((level == 2) && (GUEST_PAGING_LEVELS < 4)
- && guest_supports_superpages(v) &&
- (gflags & _PAGE_PSE)))
- && !(gflags & _PAGE_DIRTY)) )
+ /* D bits exist in L1es and PSE L2es */
+ if ( unlikely(((level == 1) ||
+ ((level == 2) &&
+ (gflags & _PAGE_PSE) &&
+ guest_supports_superpages(v)))
+ && !(gflags & _PAGE_DIRTY)) )
sflags &= ~_PAGE_RW;
- // MMIO caching
+ // shadow_mode_log_dirty support
//
- // MMIO mappings are marked as not present, but we set the SHADOW_MMIO bit
- // to cache the fact that this entry is in MMIO space.
+ // Only allow the guest write access to a page a) on a demand fault,
+ // or b) if the page is already marked as dirty.
//
- if ( (level == 1) && mmio )
+ if ( unlikely((level == 1) && shadow_mode_log_dirty(d)) )
{
- sflags &= ~(_PAGE_PRESENT);
- sflags |= _PAGE_SHADOW_MMIO;
+ if ( ft & FETCH_TYPE_WRITE )
+ sh_mark_dirty(d, target_mfn);
+ else if ( !sh_mfn_is_dirty(d, target_mfn) )
+ sflags &= ~_PAGE_RW;
}
- else
+
+ // protect guest page tables
+ //
+ if ( unlikely((level == 1) && sh_mfn_is_a_page_table(target_mfn)) )
{
- // shadow_mode_log_dirty support
- //
- // Only allow the guest write access to a page a) on a demand fault,
- // or b) if the page is already marked as dirty.
- //
- if ( unlikely((level == 1) &&
- !(ft & FETCH_TYPE_WRITE) &&
- shadow_mode_log_dirty(d) &&
- !sh_mfn_is_dirty(d, target_mfn)) )
+ if ( shadow_mode_trap_reads(d) )
{
- sflags &= ~_PAGE_RW;
+ // if we are trapping both reads & writes, then mark this page
+ // as not present...
+ //
+ sflags &= ~_PAGE_PRESENT;
}
-
- // protect guest page tables
- //
- if ( unlikely((level == 1) &&
- sh_mfn_is_a_page_table(target_mfn)) )
+ else
{
- if ( shadow_mode_trap_reads(d) )
- {
- // if we are trapping both reads & writes, then mark this page
- // as not present...
- //
- sflags &= ~_PAGE_PRESENT;
- }
- else
- {
- // otherwise, just prevent any writes...
- //
- sflags &= ~_PAGE_RW;
- }
+ // otherwise, just prevent any writes...
+ //
+ sflags &= ~_PAGE_RW;
}
}
- return sflags;
+ // PV guests in 64-bit mode use two different page tables for user vs
+ // supervisor permissions, making the guest's _PAGE_USER bit irrelevant.
+ // It is always shadowed as present...
+ if ( (GUEST_PAGING_LEVELS == 4) && !is_hvm_domain(d) )
+ {
+ sflags |= _PAGE_USER;
+ }
+
+ *sp = shadow_l1e_from_mfn(target_mfn, sflags);
+ done:
+ SHADOW_DEBUG(PROPAGATE,
+ "%s level %u guest %" SH_PRI_gpte " shadow %" SH_PRI_pte "\n",
+ fetch_type_names[ft], level, gp->l1, sp->l1);
}
-#undef CHECK
+
+/* These four wrappers give us a little bit of type-safety back around the
+ * use of void-* pointers in _sh_propagate(), and allow the compiler to
+ * optimize out some level checks. */
#if GUEST_PAGING_LEVELS >= 4
static void
@@ -882,137 +786,45 @@ l4e_propagate_from_guest(struct vcpu *v,
guest_l4e_t *gl4e,
mfn_t gl4mfn,
mfn_t sl3mfn,
- shadow_l4e_t *sl4p,
+ shadow_l4e_t *sl4e,
fetch_type_t ft)
{
- u32 gflags = guest_l4e_get_flags(*gl4e);
- u32 sflags = sh_propagate_flags(v, sl3mfn, gflags, (guest_l1e_t *) gl4e,
- gl4mfn, 0, 4, ft);
-
- *sl4p = shadow_l4e_from_mfn(sl3mfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "%s gl4e=%" SH_PRI_gpte " sl4e=%" SH_PRI_pte "\n",
- fetch_type_names[ft], gl4e->l4, sl4p->l4);
- ASSERT(sflags != -1);
+ _sh_propagate(v, gl4e, gl4mfn, sl3mfn, sl4e, 4, ft, 0);
}
-#endif // GUEST_PAGING_LEVELS >= 4
-#if GUEST_PAGING_LEVELS >= 3
static void
l3e_propagate_from_guest(struct vcpu *v,
guest_l3e_t *gl3e,
mfn_t gl3mfn,
mfn_t sl2mfn,
- shadow_l3e_t *sl3p,
+ shadow_l3e_t *sl3e,
fetch_type_t ft)
{
- u32 gflags = guest_l3e_get_flags(*gl3e);
- u32 sflags = sh_propagate_flags(v, sl2mfn, gflags, (guest_l1e_t *) gl3e,
- gl3mfn, 0, 3, ft);
-
- *sl3p = shadow_l3e_from_mfn(sl2mfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "%s gl3e=%" SH_PRI_gpte " sl3e=%" SH_PRI_pte "\n",
- fetch_type_names[ft], gl3e->l3, sl3p->l3);
- ASSERT(sflags != -1);
+ _sh_propagate(v, gl3e, gl3mfn, sl2mfn, sl3e, 3, ft, 0);
}
-#endif // GUEST_PAGING_LEVELS >= 3
+#endif // GUEST_PAGING_LEVELS >= 4
static void
l2e_propagate_from_guest(struct vcpu *v,
guest_l2e_t *gl2e,
mfn_t gl2mfn,
- mfn_t sl1mfn,
- shadow_l2e_t *sl2p,
+ mfn_t sl1mfn,
+ shadow_l2e_t *sl2e,
fetch_type_t ft)
{
- u32 gflags = guest_l2e_get_flags(*gl2e);
- u32 sflags = sh_propagate_flags(v, sl1mfn, gflags, (guest_l1e_t *) gl2e,
- gl2mfn, 0, 2, ft);
-
- *sl2p = shadow_l2e_from_mfn(sl1mfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "%s gl2e=%" SH_PRI_gpte " sl2e=%" SH_PRI_pte "\n",
- fetch_type_names[ft], gl2e->l2, sl2p->l2);
- ASSERT(sflags != -1);
+ _sh_propagate(v, gl2e, gl2mfn, sl1mfn, sl2e, 2, ft, 0);
}
-static inline int
-l1e_read_fault(struct vcpu *v, walk_t *gw, mfn_t gmfn, shadow_l1e_t *sl1p,
- int mmio)
-/* returns 1 if emulation is required, and 0 otherwise */
-{
- struct domain *d = v->domain;
- u32 gflags = guest_l1e_get_flags(gw->eff_l1e);
- u32 sflags = sh_propagate_flags(v, gmfn, gflags, gw->l1e, gw->l1mfn,
- mmio, 1, ft_demand_read);
-
- if ( shadow_mode_trap_reads(d) && !mmio && sh_mfn_is_a_page_table(gmfn) )
- {
- // emulation required!
- *sl1p = shadow_l1e_empty();
- return 1;
- }
-
- *sl1p = shadow_l1e_from_mfn(gmfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "va=%p eff_gl1e=%" SH_PRI_gpte " sl1e=%" SH_PRI_pte "\n",
- (void *)gw->va, gw->eff_l1e.l1, sl1p->l1);
-
- ASSERT(sflags != -1);
- return 0;
-}
-
-static inline int
-l1e_write_fault(struct vcpu *v, walk_t *gw, mfn_t gmfn, shadow_l1e_t *sl1p,
- int mmio)
-/* returns 1 if emulation is required, and 0 otherwise */
-{
- struct domain *d = v->domain;
- u32 gflags = guest_l1e_get_flags(gw->eff_l1e);
- u32 sflags = sh_propagate_flags(v, gmfn, gflags, gw->l1e, gw->l1mfn,
- mmio, 1, ft_demand_write);
-
- sh_mark_dirty(d, gmfn);
-
- if ( !mmio && sh_mfn_is_a_page_table(gmfn) )
- {
- // emulation required!
- *sl1p = shadow_l1e_empty();
- return 1;
- }
-
- *sl1p = shadow_l1e_from_mfn(gmfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "va=%p eff_gl1e=%" SH_PRI_gpte " sl1e=%" SH_PRI_pte "\n",
- (void *)gw->va, gw->eff_l1e.l1, sl1p->l1);
-
- ASSERT(sflags != -1);
- return 0;
-}
-
-static inline void
-l1e_propagate_from_guest(struct vcpu *v, guest_l1e_t gl1e, shadow_l1e_t *sl1p,
+static void
+l1e_propagate_from_guest(struct vcpu *v,
+ guest_l1e_t *gl1e,
+ mfn_t gl1mfn,
+ mfn_t gmfn,
+ shadow_l1e_t *sl1e,
+ fetch_type_t ft,
int mmio)
{
- gfn_t gfn = guest_l1e_get_gfn(gl1e);
- mfn_t gmfn = (mmio) ? _mfn(gfn_x(gfn)) : vcpu_gfn_to_mfn(v, gfn);
- u32 gflags = guest_l1e_get_flags(gl1e);
- u32 sflags = sh_propagate_flags(v, gmfn, gflags, 0, _mfn(INVALID_MFN),
- mmio, 1, ft_prefetch);
-
- *sl1p = shadow_l1e_from_mfn(gmfn, sflags);
-
- SHADOW_DEBUG(PROPAGATE,
- "gl1e=%" SH_PRI_gpte " sl1e=%" SH_PRI_pte "\n",
- gl1e.l1, sl1p->l1);
-
- ASSERT(sflags != -1);
+ _sh_propagate(v, gl1e, gl1mfn, gmfn, sl1e, 1, ft, mmio);
}
@@ -1020,14 +832,6 @@ l1e_propagate_from_guest(struct vcpu *v, guest_l1e_t gl1e, shadow_l1e_t *sl1p,
/* These functions update shadow entries (and do bookkeeping on the shadow
* tables they are in). It is intended that they are the only
* functions which ever write (non-zero) data onto a shadow page.
- *
- * They return a set of flags:
- * SHADOW_SET_CHANGED -- we actually wrote a new value to the shadow.
- * SHADOW_SET_FLUSH -- the caller must cause a TLB flush.
- * SHADOW_SET_ERROR -- the input is not a valid entry (for example, if
- * shadow_get_page_from_l1e() fails).
- * SHADOW_SET_L3PAE_RECOPY -- one or more vcpu's need to have their local
- * copies of their PAE L3 entries re-copied.
*/
static inline void safe_write_entry(void *dst, void *src)
@@ -1087,9 +891,6 @@ shadow_write_entries(void *d, void *s, int entries, mfn_t mfn)
safe_write_entry(dst++, src++);
if ( map != NULL ) sh_unmap_domain_page(map);
-
- /* XXX TODO:
- * Update min/max field in page_info struct of this mfn */
}
static inline int
@@ -1114,16 +915,13 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
int res;
mfn_t mfn;
struct domain *owner;
- shadow_l1e_t sanitized_sl1e =
- shadow_l1e_remove_flags(sl1e, _PAGE_SHADOW_RW | _PAGE_SHADOW_PRESENT);
- //ASSERT(shadow_l1e_get_flags(sl1e) & _PAGE_PRESENT);
- //ASSERT((shadow_l1e_get_flags(sl1e) & L1_DISALLOW_MASK) == 0);
+ ASSERT(!sh_l1e_is_magic(sl1e));
if ( !shadow_mode_refcounts(d) )
return 1;
- res = get_page_from_l1e(sanitized_sl1e, d);
+ res = get_page_from_l1e(sl1e, d);
// If a privileged domain is attempting to install a map of a page it does
// not own, we let it succeed anyway.
@@ -1131,11 +929,11 @@ shadow_get_page_from_l1e(shadow_l1e_t sl1e, struct domain *d)
if ( unlikely(!res) &&
IS_PRIV(d) &&
!shadow_mode_translate(d) &&
- valid_mfn(mfn = shadow_l1e_get_mfn(sl1e)) &&
+ mfn_valid(mfn = shadow_l1e_get_mfn(sl1e)) &&
(owner = page_get_owner(mfn_to_page(mfn))) &&
(d != owner) )
{
- res = get_page_from_l1e(sanitized_sl1e, owner);
+ res = get_page_from_l1e(sl1e, owner);
SHADOW_PRINTK("privileged domain %d installs map of mfn %05lx "
"which is owned by domain %d: %s\n",
d->domain_id, mfn_x(mfn), owner->domain_id,
@@ -1166,7 +964,7 @@ static int shadow_set_l4e(struct vcpu *v,
shadow_l4e_t new_sl4e,
mfn_t sl4mfn)
{
- int flags = 0;
+ int flags = 0, ok;
shadow_l4e_t old_sl4e;
paddr_t paddr;
ASSERT(sl4e != NULL);
@@ -1180,8 +978,17 @@ static int shadow_set_l4e(struct vcpu *v,
if ( shadow_l4e_get_flags(new_sl4e) & _PAGE_PRESENT )
{
/* About to install a new reference */
- sh_get_ref(shadow_l4e_get_mfn(new_sl4e), paddr);
- }
+ mfn_t sl3mfn = shadow_l4e_get_mfn(new_sl4e);
+ ok = sh_get_ref(v, sl3mfn, paddr);
+ /* Are we pinning l3 shadows to handle wierd linux behaviour? */
+ if ( sh_type_is_pinnable(v, SH_type_l3_64_shadow) )
+ ok |= sh_pin(v, sl3mfn);
+ if ( !ok )
+ {
+ domain_crash(v->domain);
+ return SHADOW_SET_ERROR;
+ }
+ }
/* Write the new entry */
shadow_write_entries(sl4e, &new_sl4e, 1, sl4mfn);
@@ -1201,9 +1008,7 @@ static int shadow_set_l4e(struct vcpu *v,
}
return flags;
}
-#endif /* GUEST_PAGING_LEVELS >= 4 */
-#if GUEST_PAGING_LEVELS >= 3
static int shadow_set_l3e(struct vcpu *v,
shadow_l3e_t *sl3e,
shadow_l3e_t new_sl3e,
@@ -1220,38 +1025,18 @@ static int shadow_set_l3e(struct vcpu *v,
paddr = ((((paddr_t)mfn_x(sl3mfn)) << PAGE_SHIFT)
| (((unsigned long)sl3e) & ~PAGE_MASK));
- if ( shadow_l3e_get_flags(new_sl3e) & _PAGE_PRESENT )
- {
+ if ( shadow_l3e_get_flags(new_sl3e) & _PAGE_PRESENT )
/* About to install a new reference */
- sh_get_ref(shadow_l3e_get_mfn(new_sl3e), paddr);
- }
+ if ( !sh_get_ref(v, shadow_l3e_get_mfn(new_sl3e), paddr) )
+ {
+ domain_crash(v->domain);
+ return SHADOW_SET_ERROR;
+ }
/* Write the new entry */
shadow_write_entries(sl3e, &new_sl3e, 1, sl3mfn);
flags |= SHADOW_SET_CHANGED;
-#if GUEST_PAGING_LEVELS == 3
- /* We wrote a guest l3e in a PAE pagetable. This table is copied in
- * the linear pagetable entries of its l2s, and may also be copied
- * to a low memory location to make it fit in CR3. Report that we
- * need to resync those copies (we can't wait for the guest to flush
- * the TLB because it might be an increase in rights). */
- {
- struct vcpu *vcpu;
-
- struct pae_l3_bookkeeping *info = sl3p_to_info(sl3e);
- for_each_vcpu(v->domain, vcpu)
- {
- if (info->vcpus & (1 << vcpu->vcpu_id))
- {
- // Remember that this flip/update needs to occur.
- vcpu->arch.shadow.pae_flip_pending = 1;
- flags |= SHADOW_SET_L3PAE_RECOPY;
- }
- }
- }
-#endif
-
if ( shadow_l3e_get_flags(old_sl3e) & _PAGE_PRESENT )
{
/* We lost a reference to an old mfn. */
@@ -1266,7 +1051,7 @@ static int shadow_set_l3e(struct vcpu *v,
}
return flags;
}
-#endif /* GUEST_PAGING_LEVELS >= 3 */
+#endif /* GUEST_PAGING_LEVELS >= 4 */
static int shadow_set_l2e(struct vcpu *v,
shadow_l2e_t *sl2e,
@@ -1297,10 +1082,12 @@ static int shadow_set_l2e(struct vcpu *v,
| (((unsigned long)sl2e) & ~PAGE_MASK));
if ( shadow_l2e_get_flags(new_sl2e) & _PAGE_PRESENT )
- {
/* About to install a new reference */
- sh_get_ref(shadow_l2e_get_mfn(new_sl2e), paddr);
- }
+ if ( !sh_get_ref(v, shadow_l2e_get_mfn(new_sl2e), paddr) )
+ {
+ domain_crash(v->domain);
+ return SHADOW_SET_ERROR;
+ }
/* Write the new entry */
#if GUEST_PAGING_LEVELS == 2 && SHADOW_PAGING_LEVELS > 2
@@ -1347,7 +1134,8 @@ static int shadow_set_l1e(struct vcpu *v,
if ( old_sl1e.l1 == new_sl1e.l1 ) return 0; /* Nothing to do */
- if ( shadow_l1e_get_flags(new_sl1e) & _PAGE_PRESENT )
+ if ( (shadow_l1e_get_flags(new_sl1e) & _PAGE_PRESENT)
+ && !sh_l1e_is_magic(new_sl1e) )
{
/* About to install a new reference */
if ( shadow_mode_refcounts(d) ) {
@@ -1364,7 +1152,8 @@ static int shadow_set_l1e(struct vcpu *v,
shadow_write_entries(sl1e, &new_sl1e, 1, sl1mfn);
flags |= SHADOW_SET_CHANGED;
- if ( shadow_l1e_get_flags(old_sl1e) & _PAGE_PRESENT )
+ if ( (shadow_l1e_get_flags(old_sl1e) & _PAGE_PRESENT)
+ && !sh_l1e_is_magic(old_sl1e) )
{
/* We lost a reference to an old mfn. */
/* N.B. Unlike higher-level sets, never need an extra flush
@@ -1381,80 +1170,6 @@ static int shadow_set_l1e(struct vcpu *v,
/**************************************************************************/
-/* These functions take a vcpu and a virtual address, and return a pointer
- * to the appropriate level N entry from the shadow tables.
- * If the necessary tables are not present in the shadow, they return NULL. */
-
-/* N.B. The use of GUEST_PAGING_LEVELS here is correct. If the shadow has
- * more levels than the guest, the upper levels are always fixed and do not
- * reflect any information from the guest, so we do not use these functions
- * to access them. */
-
-#if GUEST_PAGING_LEVELS >= 4
-static shadow_l4e_t *
-shadow_get_l4e(struct vcpu *v, unsigned long va)
-{
- /* Reading the top level table is always valid. */
- return sh_linear_l4_table(v) + shadow_l4_linear_offset(va);
-}
-#endif /* GUEST_PAGING_LEVELS >= 4 */
-
-
-#if GUEST_PAGING_LEVELS >= 3
-static shadow_l3e_t *
-shadow_get_l3e(struct vcpu *v, unsigned long va)
-{
-#if GUEST_PAGING_LEVELS >= 4 /* 64bit... */
- /* Get the l4 */
- shadow_l4e_t *sl4e = shadow_get_l4e(v, va);
- ASSERT(sl4e != NULL);
- if ( !(shadow_l4e_get_flags(*sl4e) & _PAGE_PRESENT) )
- return NULL;
- ASSERT(valid_mfn(shadow_l4e_get_mfn(*sl4e)));
- /* l4 was present; OK to get the l3 */
- return sh_linear_l3_table(v) + shadow_l3_linear_offset(va);
-#else /* PAE... */
- /* Top level is always mapped */
- ASSERT(v->arch.shadow_vtable);
- return ((shadow_l3e_t *)v->arch.shadow_vtable) + shadow_l3_linear_offset(va);
-#endif
-}
-#endif /* GUEST_PAGING_LEVELS >= 3 */
-
-
-static shadow_l2e_t *
-shadow_get_l2e(struct vcpu *v, unsigned long va)
-{
-#if GUEST_PAGING_LEVELS >= 3 /* 64bit/PAE... */
- /* Get the l3 */
- shadow_l3e_t *sl3e = shadow_get_l3e(v, va);
- if ( sl3e == NULL || !(shadow_l3e_get_flags(*sl3e) & _PAGE_PRESENT) )
- return NULL;
- ASSERT(valid_mfn(shadow_l3e_get_mfn(*sl3e)));
- /* l3 was present; OK to get the l2 */
-#endif
- return sh_linear_l2_table(v) + shadow_l2_linear_offset(va);
-}
-
-
-#if 0 // avoid the compiler warning for now...
-
-static shadow_l1e_t *
-shadow_get_l1e(struct vcpu *v, unsigned long va)
-{
- /* Get the l2 */
- shadow_l2e_t *sl2e = shadow_get_l2e(v, va);
- if ( sl2e == NULL || !(shadow_l2e_get_flags(*sl2e) & _PAGE_PRESENT) )
- return NULL;
- ASSERT(valid_mfn(shadow_l2e_get_mfn(*sl2e)));
- /* l2 was present; OK to get the l1 */
- return sh_linear_l1_table(v) + shadow_l1_linear_offset(va);
-}
-
-#endif
-
-
-/**************************************************************************/
/* Macros to walk pagetables. These take the shadow of a pagetable and
* walk every "interesting" entry. That is, they don't touch Xen mappings,
* and for 32-bit l2s shadowed onto PAE or 64-bit, they only touch every
@@ -1479,14 +1194,12 @@ static inline void increment_ptr_to_guest_entry(void *ptr)
}
/* All kinds of l1: touch all entries */
-#define _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
+#define _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
do { \
int _i; \
shadow_l1e_t *_sp = map_shadow_page((_sl1mfn)); \
- ASSERT((mfn_to_page(_sl1mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l1_shadow \
- || (mfn_to_page(_sl1mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_fl1_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl1mfn)->type == SH_type_l1_shadow \
+ || mfn_to_shadow_page(_sl1mfn)->type == SH_type_fl1_shadow); \
for ( _i = 0; _i < SHADOW_L1_PAGETABLE_ENTRIES; _i++ ) \
{ \
(_sl1e) = _sp + _i; \
@@ -1500,18 +1213,18 @@ do { \
/* 32-bit l1, on PAE or 64-bit shadows: need to walk both pages of shadow */
#if GUEST_PAGING_LEVELS == 2 && SHADOW_PAGING_LEVELS > 2
-#define SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
+#define SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
do { \
int __done = 0; \
- _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, \
+ _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, \
({ (__done = _done); }), _code); \
_sl1mfn = _mfn(mfn_x(_sl1mfn) + 1); \
if ( !__done ) \
- _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, \
+ _SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, \
({ (__done = _done); }), _code); \
} while (0)
#else /* Everything else; l1 shadows are only one page */
-#define SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
+#define SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code) \
_SHADOW_FOREACH_L1E(_sl1mfn, _sl1e, _gl1p, _done, _code)
#endif
@@ -1519,11 +1232,10 @@ do { \
#if GUEST_PAGING_LEVELS == 2 && SHADOW_PAGING_LEVELS > 2
/* 32-bit l2 on PAE/64: four pages, touch every second entry, and avoid Xen */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
do { \
int _i, _j, __done = 0; \
- ASSERT((mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l2_32_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_32_shadow); \
for ( _j = 0; _j < 4 && !__done; _j++ ) \
{ \
shadow_l2e_t *_sp = map_shadow_page(_sl2mfn); \
@@ -1546,12 +1258,11 @@ do { \
#elif GUEST_PAGING_LEVELS == 2
/* 32-bit on 32-bit: avoid Xen entries */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
do { \
int _i; \
shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
- ASSERT((mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l2_32_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_32_shadow); \
for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
if ( (!(_xen)) \
|| \
@@ -1569,18 +1280,15 @@ do { \
#elif GUEST_PAGING_LEVELS == 3
/* PAE: if it's an l2h, don't touch Xen mappings */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
do { \
int _i; \
shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
- ASSERT((mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l2_pae_shadow \
- || (mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l2h_pae_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_pae_shadow \
+ || mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2h_pae_shadow);\
for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
if ( (!(_xen)) \
- || ((mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- != PGC_SH_l2h_pae_shadow) \
+ || mfn_to_shadow_page(_sl2mfn)->type != SH_type_l2h_pae_shadow\
|| ((_i + (3 * SHADOW_L2_PAGETABLE_ENTRIES)) \
< (HYPERVISOR_VIRT_START >> SHADOW_L2_PAGETABLE_SHIFT)) ) \
{ \
@@ -1596,12 +1304,11 @@ do { \
#else
/* 64-bit l2: touch all entries */
-#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L2E(_sl2mfn, _sl2e, _gl2p, _done, _xen, _code) \
do { \
int _i; \
shadow_l2e_t *_sp = map_shadow_page((_sl2mfn)); \
- ASSERT((mfn_to_page(_sl2mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l2_64_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl2mfn)->type == SH_type_l2_64_shadow); \
for ( _i = 0; _i < SHADOW_L2_PAGETABLE_ENTRIES; _i++ ) \
{ \
(_sl2e) = _sp + _i; \
@@ -1615,59 +1322,14 @@ do { \
#endif /* different kinds of l2 */
-#if GUEST_PAGING_LEVELS == 3
-
-/* PAE l3 subshadow: touch all entries (FOREACH_L2E will find Xen l2es). */
-#define SHADOW_FOREACH_L3E_SUB(_sl3e, _gl3p, _done, _code) \
-do { \
- int _i; \
- for ( _i = 0; _i < 4; _i++ ) \
- { \
- if ( shadow_l3e_get_flags(*(_sl3e)) & _PAGE_PRESENT ) \
- {_code} \
- if ( _done ) break; \
- _sl3e++; \
- increment_ptr_to_guest_entry(_gl3p); \
- } \
-} while (0)
-
-/* PAE l3 full shadow: call subshadow walk on all valid l3 subshadows */
-#define SHADOW_FOREACH_L3E(_sl3mfn, _sl3e, _gl3p, _done, _code) \
-do { \
- int _i, _j, _k, __done = 0; \
- ASSERT((mfn_to_page(_sl3mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l3_pae_shadow); \
- /* The subshadows are split, 64 on each page of the shadow */ \
- for ( _j = 0; _j < 2 && !__done; _j++ ) \
- { \
- void *_sp = sh_map_domain_page(_sl3mfn); \
- for ( _i = 0; _i < 64; _i++ ) \
- { \
- /* Every second 32-byte region is a bookkeeping entry */ \
- _sl3e = (shadow_l3e_t *)(_sp + (64 * _i)); \
- if ( (sl3p_to_info(_sl3e))->refcount > 0 ) \
- SHADOW_FOREACH_L3E_SUB(_sl3e, _gl3p, \
- ({ __done = (_done); __done; }), \
- _code); \
- else \
- for ( _k = 0 ; _k < 4 ; _k++ ) \
- increment_ptr_to_guest_entry(_gl3p); \
- if ( __done ) break; \
- } \
- sh_unmap_domain_page(_sp); \
- _sl3mfn = _mfn(mfn_x(_sl3mfn) + 1); \
- } \
-} while (0)
-
-#elif GUEST_PAGING_LEVELS == 4
+#if GUEST_PAGING_LEVELS == 4
/* 64-bit l3: touch all entries */
-#define SHADOW_FOREACH_L3E(_sl3mfn, _sl3e, _gl3p, _done, _code) \
+#define SHADOW_FOREACH_L3E(_sl3mfn, _sl3e, _gl3p, _done, _code) \
do { \
int _i; \
shadow_l3e_t *_sp = map_shadow_page((_sl3mfn)); \
- ASSERT((mfn_to_page(_sl3mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l3_64_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl3mfn)->type == SH_type_l3_64_shadow); \
for ( _i = 0; _i < SHADOW_L3_PAGETABLE_ENTRIES; _i++ ) \
{ \
(_sl3e) = _sp + _i; \
@@ -1680,12 +1342,11 @@ do { \
} while (0)
/* 64-bit l4: avoid Xen mappings */
-#define SHADOW_FOREACH_L4E(_sl4mfn, _sl4e, _gl4p, _done, _xen, _code) \
+#define SHADOW_FOREACH_L4E(_sl4mfn, _sl4e, _gl4p, _done, _xen, _code) \
do { \
int _i; \
shadow_l4e_t *_sp = map_shadow_page((_sl4mfn)); \
- ASSERT((mfn_to_page(_sl4mfn)->count_info & PGC_SH_type_mask) \
- == PGC_SH_l4_64_shadow); \
+ ASSERT(mfn_to_shadow_page(_sl4mfn)->type == SH_type_l4_64_shadow); \
for ( _i = 0; _i < SHADOW_L4_PAGETABLE_ENTRIES; _i++ ) \
{ \
if ( (!(_xen)) || is_guest_l4_slot(_i) ) \
@@ -1707,8 +1368,6 @@ do { \
/**************************************************************************/
/* Functions to install Xen mappings and linear mappings in shadow pages */
-static mfn_t sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type);
-
// XXX -- this function should probably be moved to shadow-common.c, but that
// probably wants to wait until the shadow types have been moved from
// shadow-types.h to shadow-private.h
@@ -1734,11 +1393,21 @@ void sh_install_xen_entries_in_l4(struct vcpu *v, mfn_t gl4mfn, mfn_t sl4mfn)
__PAGE_HYPERVISOR);
/* Linear mapping */
- sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
- shadow_l4e_from_mfn(gl4mfn, __PAGE_HYPERVISOR);
sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
shadow_l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR);
+ if ( shadow_mode_translate(v->domain) && !shadow_mode_external(v->domain) )
+ {
+ // linear tables may not be used with translated PV guests
+ sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
+ shadow_l4e_empty();
+ }
+ else
+ {
+ sl4e[shadow_l4_table_offset(LINEAR_PT_VIRT_START)] =
+ shadow_l4e_from_mfn(gl4mfn, __PAGE_HYPERVISOR);
+ }
+
if ( shadow_mode_translate(v->domain) )
{
/* install domain-specific P2M table */
@@ -1781,7 +1450,15 @@ void sh_install_xen_entries_in_l2h(struct vcpu *v,
/* We don't set up a linear mapping here because we can't until this
* l2h is installed in an l3e. sh_update_linear_entries() handles
- * the linear mappings when the l3 is loaded. */
+ * the linear mappings when CR3 (and so the fourth l3e) is loaded.
+ * We zero them here, just as a safety measure.
+ */
+ for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ )
+ sl2e[shadow_l2_table_offset(LINEAR_PT_VIRT_START) + i] =
+ shadow_l2e_empty();
+ for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ )
+ sl2e[shadow_l2_table_offset(SH_LINEAR_PT_VIRT_START) + i] =
+ shadow_l2e_empty();
if ( shadow_mode_translate(d) )
{
@@ -1802,31 +1479,6 @@ void sh_install_xen_entries_in_l2h(struct vcpu *v,
sh_unmap_domain_page(sl2e);
}
-
-void sh_install_xen_entries_in_l3(struct vcpu *v, mfn_t gl3mfn, mfn_t sl3mfn)
-{
- shadow_l3e_t *sl3e;
- guest_l3e_t *gl3e = v->arch.guest_vtable;
- shadow_l3e_t new_sl3e;
- gfn_t l2gfn;
- mfn_t l2gmfn, l2smfn;
- int r;
-
- ASSERT(!shadow_mode_external(v->domain));
- ASSERT(guest_l3e_get_flags(gl3e[3]) & _PAGE_PRESENT);
- l2gfn = guest_l3e_get_gfn(gl3e[3]);
- l2gmfn = sh_gfn_to_mfn(v->domain, gfn_x(l2gfn));
- l2smfn = get_shadow_status(v, l2gmfn, PGC_SH_l2h_shadow);
- if ( !valid_mfn(l2smfn) )
- {
- l2smfn = sh_make_shadow(v, l2gmfn, PGC_SH_l2h_shadow);
- }
- l3e_propagate_from_guest(v, &gl3e[3], gl3mfn, l2smfn, &new_sl3e,
- ft_prefetch);
- sl3e = sh_map_domain_page(sl3mfn);
- r = shadow_set_l3e(v, &sl3e[3], new_sl3e, sl3mfn);
- sh_unmap_domain_page(sl3e);
-}
#endif
@@ -1854,11 +1506,21 @@ void sh_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn)
__PAGE_HYPERVISOR);
/* Linear mapping */
- sl2e[shadow_l2_table_offset(LINEAR_PT_VIRT_START)] =
- shadow_l2e_from_mfn(gl2mfn, __PAGE_HYPERVISOR);
sl2e[shadow_l2_table_offset(SH_LINEAR_PT_VIRT_START)] =
shadow_l2e_from_mfn(sl2mfn, __PAGE_HYPERVISOR);
+ if ( shadow_mode_translate(v->domain) && !shadow_mode_external(v->domain) )
+ {
+ // linear tables may not be used with translated PV guests
+ sl2e[shadow_l2_table_offset(LINEAR_PT_VIRT_START)] =
+ shadow_l2e_empty();
+ }
+ else
+ {
+ sl2e[shadow_l2_table_offset(LINEAR_PT_VIRT_START)] =
+ shadow_l2e_from_mfn(gl2mfn, __PAGE_HYPERVISOR);
+ }
+
if ( shadow_mode_translate(d) )
{
/* install domain-specific P2M table */
@@ -1873,8 +1535,6 @@ void sh_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn)
-
-
/**************************************************************************/
/* Create a shadow of a given guest page.
*/
@@ -1885,9 +1545,50 @@ sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
SHADOW_DEBUG(MAKE_SHADOW, "(%05lx, %u)=>%05lx\n",
mfn_x(gmfn), shadow_type, mfn_x(smfn));
- if ( shadow_type != PGC_SH_guest_root_type )
+ if ( shadow_type != SH_type_l2_32_shadow
+ && shadow_type != SH_type_l2_pae_shadow
+ && shadow_type != SH_type_l2h_pae_shadow
+ && shadow_type != SH_type_l4_64_shadow )
/* Lower-level shadow, not yet linked form a higher level */
- mfn_to_page(smfn)->up = 0;
+ mfn_to_shadow_page(smfn)->up = 0;
+
+#if GUEST_PAGING_LEVELS == 4
+#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
+ if ( shadow_type == SH_type_l4_64_shadow &&
+ unlikely(v->domain->arch.shadow.opt_flags & SHOPT_LINUX_L3_TOPLEVEL) )
+ {
+ /* We're shadowing a new l4, but we've been assuming the guest uses
+ * only one l4 per vcpu and context switches using an l4 entry.
+ * Count the number of active l4 shadows. If there are enough
+ * of them, decide that this isn't an old linux guest, and stop
+ * pinning l3es. This is not very quick but it doesn't happen
+ * very often. */
+ struct list_head *l, *t;
+ struct shadow_page_info *sp;
+ struct vcpu *v2;
+ int l4count = 0, vcpus = 0;
+ list_for_each(l, &v->domain->arch.shadow.pinned_shadows)
+ {
+ sp = list_entry(l, struct shadow_page_info, list);
+ if ( sp->type == SH_type_l4_64_shadow )
+ l4count++;
+ }
+ for_each_vcpu ( v->domain, v2 )
+ vcpus++;
+ if ( l4count > 2 * vcpus )
+ {
+ /* Unpin all the pinned l3 tables, and don't pin any more. */
+ list_for_each_safe(l, t, &v->domain->arch.shadow.pinned_shadows)
+ {
+ sp = list_entry(l, struct shadow_page_info, list);
+ if ( sp->type == SH_type_l3_64_shadow )
+ sh_unpin(v, shadow_page_to_mfn(sp));
+ }
+ v->domain->arch.shadow.opt_flags &= ~SHOPT_LINUX_L3_TOPLEVEL;
+ }
+ }
+#endif
+#endif
// Create the Xen mappings...
if ( !shadow_mode_external(v->domain) )
@@ -1895,17 +1596,15 @@ sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
switch (shadow_type)
{
#if CONFIG_PAGING_LEVELS == 4 && GUEST_PAGING_LEVELS == 4
- case PGC_SH_l4_shadow:
+ case SH_type_l4_shadow:
sh_install_xen_entries_in_l4(v, gmfn, smfn); break;
#endif
#if CONFIG_PAGING_LEVELS == 3 && GUEST_PAGING_LEVELS == 3
- case PGC_SH_l3_shadow:
- sh_install_xen_entries_in_l3(v, gmfn, smfn); break;
- case PGC_SH_l2h_shadow:
+ case SH_type_l2h_shadow:
sh_install_xen_entries_in_l2h(v, smfn); break;
#endif
#if CONFIG_PAGING_LEVELS == 2 && GUEST_PAGING_LEVELS == 2
- case PGC_SH_l2_shadow:
+ case SH_type_l2_shadow:
sh_install_xen_entries_in_l2(v, gmfn, smfn); break;
#endif
default: /* Do nothing */ break;
@@ -1922,7 +1621,7 @@ sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
static mfn_t
make_fl1_shadow(struct vcpu *v, gfn_t gfn)
{
- mfn_t smfn = shadow_alloc(v->domain, PGC_SH_fl1_shadow,
+ mfn_t smfn = shadow_alloc(v->domain, SH_type_fl1_shadow,
(unsigned long) gfn_x(gfn));
SHADOW_DEBUG(MAKE_SHADOW, "(%" SH_PRI_gfn ")=>%" SH_PRI_mfn "\n",
@@ -1944,7 +1643,7 @@ sh_make_monitor_table(struct vcpu *v)
{
struct domain *d = v->domain;
mfn_t m4mfn;
- m4mfn = shadow_alloc(d, PGC_SH_monitor_table, 0);
+ m4mfn = shadow_alloc(d, SH_type_monitor_table, 0);
sh_install_xen_entries_in_l4(v, m4mfn, m4mfn);
/* Remember the level of this table */
mfn_to_page(m4mfn)->shadow_flags = 4;
@@ -1954,7 +1653,7 @@ sh_make_monitor_table(struct vcpu *v)
{
mfn_t m3mfn;
l4_pgentry_t *l4e;
- m3mfn = shadow_alloc(d, PGC_SH_monitor_table, 0);
+ m3mfn = shadow_alloc(d, SH_type_monitor_table, 0);
mfn_to_page(m3mfn)->shadow_flags = 3;
l4e = sh_map_domain_page(m4mfn);
l4e[0] = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR);
@@ -1973,13 +1672,13 @@ sh_make_monitor_table(struct vcpu *v)
l2_pgentry_t *l2e;
int i;
- m3mfn = shadow_alloc(d, PGC_SH_monitor_table, 0);
+ m3mfn = shadow_alloc(d, SH_type_monitor_table, 0);
/* Remember the level of this table */
mfn_to_page(m3mfn)->shadow_flags = 3;
// Install a monitor l2 table in slot 3 of the l3 table.
// This is used for all Xen entries, including linear maps
- m2mfn = shadow_alloc(d, PGC_SH_monitor_table, 0);
+ m2mfn = shadow_alloc(d, SH_type_monitor_table, 0);
mfn_to_page(m2mfn)->shadow_flags = 2;
l3e = sh_map_domain_page(m3mfn);
l3e[3] = l3e_from_pfn(mfn_x(m2mfn), _PAGE_PRESENT);
@@ -2003,7 +1702,7 @@ sh_make_monitor_table(struct vcpu *v)
{
struct domain *d = v->domain;
mfn_t m2mfn;
- m2mfn = shadow_alloc(d, PGC_SH_monitor_table, 0);
+ m2mfn = shadow_alloc(d, SH_type_monitor_table, 0);
sh_install_xen_entries_in_l2(v, m2mfn, m2mfn);
/* Remember the level of this table */
mfn_to_page(m2mfn)->shadow_flags = 2;
@@ -2022,69 +1721,62 @@ sh_make_monitor_table(struct vcpu *v)
* they are needed. The "demand" argument is non-zero when handling
* a demand fault (so we know what to do about accessed bits &c).
* If the necessary tables are not present in the guest, they return NULL. */
+
+/* N.B. The use of GUEST_PAGING_LEVELS here is correct. If the shadow has
+ * more levels than the guest, the upper levels are always fixed and do not
+ * reflect any information from the guest, so we do not use these functions
+ * to access them. */
+
#if GUEST_PAGING_LEVELS >= 4
static shadow_l4e_t * shadow_get_and_create_l4e(struct vcpu *v,
walk_t *gw,
mfn_t *sl4mfn)
{
/* There is always a shadow of the top level table. Get it. */
- *sl4mfn = pagetable_get_mfn(v->arch.shadow_table);
+ *sl4mfn = pagetable_get_mfn(v->arch.shadow_table[0]);
/* Reading the top level table is always valid. */
return sh_linear_l4_table(v) + shadow_l4_linear_offset(gw->va);
}
-#endif /* GUEST_PAGING_LEVELS >= 4 */
-
-#if GUEST_PAGING_LEVELS >= 3
static shadow_l3e_t * shadow_get_and_create_l3e(struct vcpu *v,
walk_t *gw,
mfn_t *sl3mfn,
fetch_type_t ft)
{
-#if GUEST_PAGING_LEVELS >= 4 /* 64bit... */
mfn_t sl4mfn;
shadow_l4e_t *sl4e;
- if ( !valid_mfn(gw->l3mfn) ) return NULL; /* No guest page. */
+ if ( !mfn_valid(gw->l3mfn) ) return NULL; /* No guest page. */
/* Get the l4e */
sl4e = shadow_get_and_create_l4e(v, gw, &sl4mfn);
ASSERT(sl4e != NULL);
if ( shadow_l4e_get_flags(*sl4e) & _PAGE_PRESENT )
{
*sl3mfn = shadow_l4e_get_mfn(*sl4e);
- ASSERT(valid_mfn(*sl3mfn));
+ ASSERT(mfn_valid(*sl3mfn));
}
else
{
int r;
shadow_l4e_t new_sl4e;
/* No l3 shadow installed: find and install it. */
- *sl3mfn = get_shadow_status(v, gw->l3mfn, PGC_SH_l3_shadow);
- if ( !valid_mfn(*sl3mfn) )
+ *sl3mfn = get_shadow_status(v, gw->l3mfn, SH_type_l3_shadow);
+ if ( !mfn_valid(*sl3mfn) )
{
/* No l3 shadow of this page exists at all: make one. */
- *sl3mfn = sh_make_shadow(v, gw->l3mfn, PGC_SH_l3_shadow);
+ *sl3mfn = sh_make_shadow(v, gw->l3mfn, SH_type_l3_shadow);
}
/* Install the new sl3 table in the sl4e */
l4e_propagate_from_guest(v, gw->l4e, gw->l4mfn,
*sl3mfn, &new_sl4e, ft);
r = shadow_set_l4e(v, sl4e, new_sl4e, sl4mfn);
ASSERT((r & SHADOW_SET_FLUSH) == 0);
+ if ( r & SHADOW_SET_ERROR )
+ return NULL;
}
/* Now follow it down a level. Guaranteed to succeed. */
return sh_linear_l3_table(v) + shadow_l3_linear_offset(gw->va);
-#else /* PAE... */
- /* There is always a shadow of the top level table. Get it. */
- *sl3mfn = pagetable_get_mfn(v->arch.shadow_table);
- /* This next line is important: the shadow l3 table is in an 8k
- * shadow and we need to return the right mfn of the pair. This call
- * will set it for us as a side-effect. */
- (void) shadow_l3_index(sl3mfn, guest_index(gw->l3e));
- ASSERT(v->arch.shadow_vtable);
- return ((shadow_l3e_t *)v->arch.shadow_vtable)
- + shadow_l3_table_offset(gw->va);
-#endif /* GUEST_PAGING_LEVELS >= 4 */
}
-#endif /* GUEST_PAGING_LEVELS >= 3 */
+#endif /* GUEST_PAGING_LEVELS >= 4 */
static shadow_l2e_t * shadow_get_and_create_l2e(struct vcpu *v,
@@ -2092,45 +1784,52 @@ static shadow_l2e_t * shadow_get_and_create_l2e(struct vcpu *v,
mfn_t *sl2mfn,
fetch_type_t ft)
{
-#if GUEST_PAGING_LEVELS >= 3 /* PAE or 64bit... */
+#if GUEST_PAGING_LEVELS >= 4 /* 64bit... */
mfn_t sl3mfn = _mfn(INVALID_MFN);
shadow_l3e_t *sl3e;
- if ( !valid_mfn(gw->l2mfn) ) return NULL; /* No guest page. */
+ if ( !mfn_valid(gw->l2mfn) ) return NULL; /* No guest page. */
/* Get the l3e */
sl3e = shadow_get_and_create_l3e(v, gw, &sl3mfn, ft);
- ASSERT(sl3e != NULL); /* Since we know guest PT is valid this far */
+ if ( sl3e == NULL ) return NULL;
if ( shadow_l3e_get_flags(*sl3e) & _PAGE_PRESENT )
{
*sl2mfn = shadow_l3e_get_mfn(*sl3e);
- ASSERT(valid_mfn(*sl2mfn));
+ ASSERT(mfn_valid(*sl2mfn));
}
else
{
int r;
shadow_l3e_t new_sl3e;
/* No l2 shadow installed: find and install it. */
- *sl2mfn = get_shadow_status(v, gw->l2mfn, PGC_SH_l2_shadow);
- if ( !valid_mfn(*sl2mfn) )
+ *sl2mfn = get_shadow_status(v, gw->l2mfn, SH_type_l2_shadow);
+ if ( !mfn_valid(*sl2mfn) )
{
/* No l2 shadow of this page exists at all: make one. */
- *sl2mfn = sh_make_shadow(v, gw->l2mfn, PGC_SH_l2_shadow);
+ *sl2mfn = sh_make_shadow(v, gw->l2mfn, SH_type_l2_shadow);
}
/* Install the new sl2 table in the sl3e */
l3e_propagate_from_guest(v, gw->l3e, gw->l3mfn,
*sl2mfn, &new_sl3e, ft);
r = shadow_set_l3e(v, sl3e, new_sl3e, sl3mfn);
ASSERT((r & SHADOW_SET_FLUSH) == 0);
-#if GUEST_PAGING_LEVELS == 3
- /* Need to sync up the linear maps, as we are about to use them */
- ASSERT( r & SHADOW_SET_L3PAE_RECOPY );
- sh_pae_recopy(v->domain);
-#endif
+ if ( r & SHADOW_SET_ERROR )
+ return NULL;
}
/* Now follow it down a level. Guaranteed to succeed. */
return sh_linear_l2_table(v) + shadow_l2_linear_offset(gw->va);
+#elif GUEST_PAGING_LEVELS == 3 /* PAE... */
+ /* We never demand-shadow PAE l3es: they are only created in
+ * sh_update_cr3(). Check if the relevant sl3e is present. */
+ shadow_l3e_t *sl3e = ((shadow_l3e_t *)&v->arch.shadow.l3table)
+ + shadow_l3_linear_offset(gw->va);
+ if ( !(shadow_l3e_get_flags(*sl3e) & _PAGE_PRESENT) )
+ return NULL;
+ *sl2mfn = shadow_l3e_get_mfn(*sl3e);
+ ASSERT(mfn_valid(*sl2mfn));
+ return sh_linear_l2_table(v) + shadow_l2_linear_offset(gw->va);
#else /* 32bit... */
/* There is always a shadow of the top level table. Get it. */
- *sl2mfn = pagetable_get_mfn(v->arch.shadow_table);
+ *sl2mfn = pagetable_get_mfn(v->arch.shadow_table[0]);
/* This next line is important: the guest l2 has a 16k
* shadow, we need to return the right mfn of the four. This
* call will set it for us as a side-effect. */
@@ -2152,10 +1851,15 @@ static shadow_l1e_t * shadow_get_and_create_l1e(struct vcpu *v,
/* Get the l2e */
sl2e = shadow_get_and_create_l2e(v, gw, &sl2mfn, ft);
if ( sl2e == NULL ) return NULL;
- if ( shadow_l2e_get_flags(*sl2e) & _PAGE_PRESENT )
+ /* Install the sl1 in the l2e if it wasn't there or if we need to
+ * re-do it to fix a PSE dirty bit. */
+ if ( shadow_l2e_get_flags(*sl2e) & _PAGE_PRESENT
+ && likely(ft != ft_demand_write
+ || (guest_l2e_get_flags(*gw->l2e) & _PAGE_DIRTY)
+ || !(guest_l2e_get_flags(*gw->l2e) & _PAGE_PSE)) )
{
*sl1mfn = shadow_l2e_get_mfn(*sl2e);
- ASSERT(valid_mfn(*sl1mfn));
+ ASSERT(mfn_valid(*sl1mfn));
}
else
{
@@ -2169,7 +1873,7 @@ static shadow_l1e_t * shadow_get_and_create_l1e(struct vcpu *v,
/* Splintering a superpage */
gfn_t l2gfn = guest_l2e_get_gfn(*gw->l2e);
*sl1mfn = get_fl1_shadow_status(v, l2gfn);
- if ( !valid_mfn(*sl1mfn) )
+ if ( !mfn_valid(*sl1mfn) )
{
/* No fl1 shadow of this superpage exists at all: make one. */
*sl1mfn = make_fl1_shadow(v, l2gfn);
@@ -2178,12 +1882,12 @@ static shadow_l1e_t * shadow_get_and_create_l1e(struct vcpu *v,
else
{
/* Shadowing an actual guest l1 table */
- if ( !valid_mfn(gw->l2mfn) ) return NULL; /* No guest page. */
- *sl1mfn = get_shadow_status(v, gw->l1mfn, PGC_SH_l1_shadow);
- if ( !valid_mfn(*sl1mfn) )
+ if ( !mfn_valid(gw->l2mfn) ) return NULL; /* No guest page. */
+ *sl1mfn = get_shadow_status(v, gw->l1mfn, SH_type_l1_shadow);
+ if ( !mfn_valid(*sl1mfn) )
{
/* No l1 shadow of this page exists at all: make one. */
- *sl1mfn = sh_make_shadow(v, gw->l1mfn, PGC_SH_l1_shadow);
+ *sl1mfn = sh_make_shadow(v, gw->l1mfn, SH_type_l1_shadow);
}
}
/* Install the new sl1 table in the sl2e */
@@ -2191,6 +1895,8 @@ static shadow_l1e_t * shadow_get_and_create_l1e(struct vcpu *v,
*sl1mfn, &new_sl2e, ft);
r = shadow_set_l2e(v, sl2e, new_sl2e, sl2mfn);
ASSERT((r & SHADOW_SET_FLUSH) == 0);
+ if ( r & SHADOW_SET_ERROR )
+ return NULL;
/* This next line is important: in 32-on-PAE and 32-on-64 modes,
* the guest l1 table has an 8k shadow, and we need to return
* the right mfn of the pair. This call will set it for us as a
@@ -2218,21 +1924,18 @@ static shadow_l1e_t * shadow_get_and_create_l1e(struct vcpu *v,
void sh_destroy_l4_shadow(struct vcpu *v, mfn_t smfn)
{
shadow_l4e_t *sl4e;
- u32 t = mfn_to_page(smfn)->count_info & PGC_SH_type_mask;
+ u32 t = mfn_to_shadow_page(smfn)->type;
mfn_t gmfn, sl4mfn;
int xen_mappings;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
- ASSERT(t == PGC_SH_l4_shadow);
+ ASSERT(t == SH_type_l4_shadow);
/* Record that the guest page isn't shadowed any more (in this type) */
- gmfn = _mfn(mfn_to_page(smfn)->u.inuse.type_info);
+ gmfn = _mfn(mfn_to_shadow_page(smfn)->backpointer);
delete_shadow_status(v, gmfn, t, smfn);
shadow_demote(v, gmfn, t);
- /* Take this shadow off the list of root shadows */
- list_del_init(&mfn_to_page(smfn)->list);
-
/* Decrement refcounts of all the old entries */
xen_mappings = (!shadow_mode_external(v->domain));
sl4mfn = smfn;
@@ -2240,35 +1943,29 @@ void sh_destroy_l4_shadow(struct vcpu *v, mfn_t smfn)
if ( shadow_l4e_get_flags(*sl4e) & _PAGE_PRESENT )
{
sh_put_ref(v, shadow_l4e_get_mfn(*sl4e),
- (((paddr_t)mfn_x(sl4mfn)) << PAGE_SHIFT)
- | ((unsigned long)sl4e & ~PAGE_MASK));
+ (((paddr_t)mfn_x(sl4mfn)) << PAGE_SHIFT)
+ | ((unsigned long)sl4e & ~PAGE_MASK));
}
});
/* Put the memory back in the pool */
shadow_free(v->domain, smfn);
}
-#endif
-#if GUEST_PAGING_LEVELS >= 3
void sh_destroy_l3_shadow(struct vcpu *v, mfn_t smfn)
{
shadow_l3e_t *sl3e;
- u32 t = mfn_to_page(smfn)->count_info & PGC_SH_type_mask;
+ u32 t = mfn_to_shadow_page(smfn)->type;
mfn_t gmfn, sl3mfn;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
- ASSERT(t == PGC_SH_l3_shadow);
+ ASSERT(t == SH_type_l3_shadow);
/* Record that the guest page isn't shadowed any more (in this type) */
- gmfn = _mfn(mfn_to_page(smfn)->u.inuse.type_info);
+ gmfn = _mfn(mfn_to_shadow_page(smfn)->backpointer);
delete_shadow_status(v, gmfn, t, smfn);
shadow_demote(v, gmfn, t);
-#if GUEST_PAGING_LEVELS == 3
- /* Take this shadow off the list of root shadows */
- list_del_init(&mfn_to_page(smfn)->list);
-#endif
/* Decrement refcounts of all the old entries */
sl3mfn = smfn;
@@ -2282,81 +1979,32 @@ void sh_destroy_l3_shadow(struct vcpu *v, mfn_t smfn)
/* Put the memory back in the pool */
shadow_free(v->domain, smfn);
}
-#endif
-
-
-#if GUEST_PAGING_LEVELS == 3
-static void sh_destroy_l3_subshadow(struct vcpu *v,
- shadow_l3e_t *sl3e)
-/* Tear down just a single 4-entry l3 on a 2-page l3 shadow. */
-{
- int i;
- ASSERT((unsigned long)sl3e % (4 * sizeof (shadow_l3e_t)) == 0);
- for ( i = 0; i < GUEST_L3_PAGETABLE_ENTRIES; i++ )
- if ( shadow_l3e_get_flags(sl3e[i]) & _PAGE_PRESENT )
- sh_put_ref(v, shadow_l3e_get_mfn(sl3e[i]),
- maddr_from_mapped_domain_page(sl3e));
-}
-#endif
+#endif /* GUEST_PAGING_LEVELS >= 4 */
-#if (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3)
-void sh_unpin_all_l3_subshadows(struct vcpu *v, mfn_t smfn)
-/* Walk a full PAE l3 shadow, unpinning all of the subshadows on it */
-{
- int i, j;
- struct pae_l3_bookkeeping *bk;
-
- ASSERT((mfn_to_page(smfn)->count_info & PGC_SH_type_mask)
- == PGC_SH_l3_pae_shadow);
- /* The subshadows are split, 64 on each page of the shadow */
- for ( i = 0; i < 2; i++ )
- {
- void *p = sh_map_domain_page(_mfn(mfn_x(smfn) + i));
- for ( j = 0; j < 64; j++ )
- {
- /* Every second 32-byte region is a bookkeeping entry */
- bk = (struct pae_l3_bookkeeping *)(p + (64 * j) + 32);
- if ( bk->pinned )
- sh_unpin_l3_subshadow(v, (shadow_l3e_t *)(p + (64*j)), smfn);
- /* Check whether we've just freed the whole shadow */
- if ( (mfn_to_page(smfn)->count_info & PGC_SH_count_mask) == 0 )
- {
- sh_unmap_domain_page(p);
- return;
- }
- }
- sh_unmap_domain_page(p);
- }
-}
-#endif
void sh_destroy_l2_shadow(struct vcpu *v, mfn_t smfn)
{
shadow_l2e_t *sl2e;
- u32 t = mfn_to_page(smfn)->count_info & PGC_SH_type_mask;
+ u32 t = mfn_to_shadow_page(smfn)->type;
mfn_t gmfn, sl2mfn;
int xen_mappings;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
- ASSERT(t == PGC_SH_l2_shadow
- || t == PGC_SH_l2h_pae_shadow);
+ ASSERT(t == SH_type_l2_shadow
+ || t == SH_type_l2h_pae_shadow);
/* Record that the guest page isn't shadowed any more (in this type) */
- gmfn = _mfn(mfn_to_page(smfn)->u.inuse.type_info);
+ gmfn = _mfn(mfn_to_shadow_page(smfn)->backpointer);
delete_shadow_status(v, gmfn, t, smfn);
shadow_demote(v, gmfn, t);
-#if GUEST_PAGING_LEVELS == 2
- /* Take this shadow off the list of root shadows */
- list_del_init(&mfn_to_page(smfn)->list);
-#endif
/* Decrement refcounts of all the old entries */
sl2mfn = smfn;
xen_mappings = (!shadow_mode_external(v->domain) &&
((GUEST_PAGING_LEVELS == 2) ||
((GUEST_PAGING_LEVELS == 3) &&
- (t == PGC_SH_l2h_pae_shadow))));
+ (t == SH_type_l2h_pae_shadow))));
SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, xen_mappings, {
if ( shadow_l2e_get_flags(*sl2e) & _PAGE_PRESENT )
sh_put_ref(v, shadow_l2e_get_mfn(*sl2e),
@@ -2372,21 +2020,21 @@ void sh_destroy_l1_shadow(struct vcpu *v, mfn_t smfn)
{
struct domain *d = v->domain;
shadow_l1e_t *sl1e;
- u32 t = mfn_to_page(smfn)->count_info & PGC_SH_type_mask;
+ u32 t = mfn_to_shadow_page(smfn)->type;
SHADOW_DEBUG(DESTROY_SHADOW,
"%s(%05lx)\n", __func__, mfn_x(smfn));
- ASSERT(t == PGC_SH_l1_shadow || t == PGC_SH_fl1_shadow);
+ ASSERT(t == SH_type_l1_shadow || t == SH_type_fl1_shadow);
/* Record that the guest page isn't shadowed any more (in this type) */
- if ( t == PGC_SH_fl1_shadow )
+ if ( t == SH_type_fl1_shadow )
{
- gfn_t gfn = _gfn(mfn_to_page(smfn)->u.inuse.type_info);
+ gfn_t gfn = _gfn(mfn_to_shadow_page(smfn)->backpointer);
delete_fl1_shadow_status(v, gfn, smfn);
}
else
{
- mfn_t gmfn = _mfn(mfn_to_page(smfn)->u.inuse.type_info);
+ mfn_t gmfn = _mfn(mfn_to_shadow_page(smfn)->backpointer);
delete_shadow_status(v, gmfn, t, smfn);
shadow_demote(v, gmfn, t);
}
@@ -2396,7 +2044,8 @@ void sh_destroy_l1_shadow(struct vcpu *v, mfn_t smfn)
/* Decrement refcounts of all the old entries */
mfn_t sl1mfn = smfn;
SHADOW_FOREACH_L1E(sl1mfn, sl1e, 0, 0, {
- if ( shadow_l1e_get_flags(*sl1e) & _PAGE_PRESENT )
+ if ( (shadow_l1e_get_flags(*sl1e) & _PAGE_PRESENT)
+ && !sh_l1e_is_magic(*sl1e) )
shadow_put_page_from_l1e(*sl1e, d);
});
}
@@ -2409,8 +2058,7 @@ void sh_destroy_l1_shadow(struct vcpu *v, mfn_t smfn)
void sh_destroy_monitor_table(struct vcpu *v, mfn_t mmfn)
{
struct domain *d = v->domain;
- ASSERT((mfn_to_page(mmfn)->count_info & PGC_SH_type_mask)
- == PGC_SH_monitor_table);
+ ASSERT(mfn_to_shadow_page(mmfn)->type == SH_type_monitor_table);
#if (CONFIG_PAGING_LEVELS == 4) && (SHADOW_PAGING_LEVELS != 4)
/* Need to destroy the l3 monitor page in slot 0 too */
@@ -2456,31 +2104,14 @@ void sh_unhook_32b_mappings(struct vcpu *v, mfn_t sl2mfn)
#elif GUEST_PAGING_LEVELS == 3
-void sh_unhook_pae_mappings(struct vcpu *v, mfn_t sl3mfn)
-/* Walk a full PAE l3 shadow, unhooking entries from all the subshadows */
+void sh_unhook_pae_mappings(struct vcpu *v, mfn_t sl2mfn)
+/* Walk a PAE l2 shadow, unhooking entries from all the subshadows */
{
- shadow_l3e_t *sl3e;
- SHADOW_FOREACH_L3E(sl3mfn, sl3e, 0, 0, {
- if ( (shadow_l3e_get_flags(*sl3e) & _PAGE_PRESENT) ) {
- mfn_t sl2mfn = shadow_l3e_get_mfn(*sl3e);
- if ( (mfn_to_page(sl2mfn)->count_info & PGC_SH_type_mask)
- == PGC_SH_l2h_pae_shadow )
- {
- /* High l2: need to pick particular l2es to unhook */
- shadow_l2e_t *sl2e;
- SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, 1, {
- (void) shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
- });
- }
- else
- {
- /* Normal l2: can safely unhook the whole l3e */
- (void) shadow_set_l3e(v, sl3e, shadow_l3e_empty(), sl3mfn);
- }
- }
+ shadow_l2e_t *sl2e;
+ int xen_mappings = !shadow_mode_external(v->domain);
+ SHADOW_FOREACH_L2E(sl2mfn, sl2e, 0, 0, xen_mappings, {
+ (void) shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
});
- /* We've changed PAE L3 entries: must sync up various copies of them */
- sh_pae_recopy(v->domain);
}
#elif GUEST_PAGING_LEVELS == 4
@@ -2522,19 +2153,44 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se)
{
gfn_t gl3gfn = guest_l4e_get_gfn(*new_gl4e);
mfn_t gl3mfn = vcpu_gfn_to_mfn(v, gl3gfn);
- if ( valid_mfn(gl3mfn) )
- sl3mfn = get_shadow_status(v, gl3mfn, PGC_SH_l3_shadow);
+ if ( mfn_valid(gl3mfn) )
+ sl3mfn = get_shadow_status(v, gl3mfn, SH_type_l3_shadow);
else
result |= SHADOW_SET_ERROR;
}
l4e_propagate_from_guest(v, new_gl4e, _mfn(INVALID_MFN),
sl3mfn, &new_sl4e, ft_prefetch);
+
+ // check for updates to xen reserved slots
+ if ( !shadow_mode_external(v->domain) )
+ {
+ int shadow_index = (((unsigned long)sl4p & ~PAGE_MASK) /
+ sizeof(shadow_l4e_t));
+ int reserved_xen_slot = !is_guest_l4_slot(shadow_index);
+
+ if ( unlikely(reserved_xen_slot) )
+ {
+ // attempt by the guest to write to a xen reserved slot
+ //
+ SHADOW_PRINTK("%s out-of-range update "
+ "sl4mfn=%05lx index=0x%x val=%" SH_PRI_pte "\n",
+ __func__, mfn_x(sl4mfn), shadow_index, new_sl4e.l4);
+ if ( shadow_l4e_get_flags(new_sl4e) & _PAGE_PRESENT )
+ {
+ SHADOW_ERROR("out-of-range l4e update\n");
+ result |= SHADOW_SET_ERROR;
+ }
+
+ // do not call shadow_set_l4e...
+ return result;
+ }
+ }
+
result |= shadow_set_l4e(v, sl4p, new_sl4e, sl4mfn);
return result;
}
-#endif // GUEST_PAGING_LEVELS >= 4
-#if GUEST_PAGING_LEVELS >= 3
+
static int validate_gl3e(struct vcpu *v, void *new_ge, mfn_t sl3mfn, void *se)
{
shadow_l3e_t new_sl3e;
@@ -2545,22 +2201,12 @@ static int validate_gl3e(struct vcpu *v, void *new_ge, mfn_t sl3mfn, void *se)
perfc_incrc(shadow_validate_gl3e_calls);
-#if (SHADOW_PAGING_LEVELS == 3) && (GUEST_PAGING_LEVELS == 3)
- {
- /* If we've updated a subshadow which is unreferenced then
- we don't care what value is being written - bail. */
- struct pae_l3_bookkeeping *info = sl3p_to_info(se);
- if(!info->refcount)
- return result;
- }
-#endif
-
if ( guest_l3e_get_flags(*new_gl3e) & _PAGE_PRESENT )
{
gfn_t gl2gfn = guest_l3e_get_gfn(*new_gl3e);
mfn_t gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
- if ( valid_mfn(gl2mfn) )
- sl2mfn = get_shadow_status(v, gl2mfn, PGC_SH_l2_shadow);
+ if ( mfn_valid(gl2mfn) )
+ sl2mfn = get_shadow_status(v, gl2mfn, SH_type_l2_shadow);
else
result |= SHADOW_SET_ERROR;
}
@@ -2568,16 +2214,9 @@ static int validate_gl3e(struct vcpu *v, void *new_ge, mfn_t sl3mfn, void *se)
sl2mfn, &new_sl3e, ft_prefetch);
result |= shadow_set_l3e(v, sl3p, new_sl3e, sl3mfn);
-#if GUEST_PAGING_LEVELS == 3
- /* We have changed a PAE l3 entry: need to sync up the possible copies
- * of it */
- if ( result & SHADOW_SET_L3PAE_RECOPY )
- sh_pae_recopy(v->domain);
-#endif
-
return result;
}
-#endif // GUEST_PAGING_LEVELS >= 3
+#endif // GUEST_PAGING_LEVELS >= 4
static int validate_gl2e(struct vcpu *v, void *new_ge, mfn_t sl2mfn, void *se)
{
@@ -2603,21 +2242,62 @@ static int validate_gl2e(struct vcpu *v, void *new_ge, mfn_t sl2mfn, void *se)
// for superpage fl1's here, but this is *not* on the demand path,
// so we'll hold off trying that for now...
//
- if ( !valid_mfn(sl1mfn) )
+ if ( !mfn_valid(sl1mfn) )
sl1mfn = make_fl1_shadow(v, gl1gfn);
#endif
}
else
{
mfn_t gl1mfn = vcpu_gfn_to_mfn(v, gl1gfn);
- if ( valid_mfn(gl1mfn) )
- sl1mfn = get_shadow_status(v, gl1mfn, PGC_SH_l1_shadow);
+ if ( mfn_valid(gl1mfn) )
+ sl1mfn = get_shadow_status(v, gl1mfn, SH_type_l1_shadow);
else
result |= SHADOW_SET_ERROR;
}
}
l2e_propagate_from_guest(v, new_gl2e, _mfn(INVALID_MFN),
sl1mfn, &new_sl2e, ft_prefetch);
+
+ // check for updates to xen reserved slots in PV guests...
+ // XXX -- need to revisit this for PV 3-on-4 guests.
+ //
+#if SHADOW_PAGING_LEVELS < 4
+#if CONFIG_PAGING_LEVELS == SHADOW_PAGING_LEVELS
+ if ( !shadow_mode_external(v->domain) )
+ {
+ int shadow_index = (((unsigned long)sl2p & ~PAGE_MASK) /
+ sizeof(shadow_l2e_t));
+ int reserved_xen_slot;
+
+#if SHADOW_PAGING_LEVELS == 3
+ reserved_xen_slot =
+ ((mfn_to_shadow_page(sl2mfn)->type == SH_type_l2h_pae_shadow) &&
+ (shadow_index
+ >= (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES-1))));
+#else /* SHADOW_PAGING_LEVELS == 2 */
+ reserved_xen_slot = (shadow_index >= L2_PAGETABLE_FIRST_XEN_SLOT);
+#endif
+
+ if ( unlikely(reserved_xen_slot) )
+ {
+ // attempt by the guest to write to a xen reserved slot
+ //
+ SHADOW_PRINTK("%s out-of-range update "
+ "sl2mfn=%05lx index=0x%x val=%" SH_PRI_pte "\n",
+ __func__, mfn_x(sl2mfn), shadow_index, new_sl2e.l2);
+ if ( shadow_l2e_get_flags(new_sl2e) & _PAGE_PRESENT )
+ {
+ SHADOW_ERROR("out-of-range l2e update\n");
+ result |= SHADOW_SET_ERROR;
+ }
+
+ // do not call shadow_set_l2e...
+ return result;
+ }
+ }
+#endif /* CONFIG_PAGING_LEVELS == SHADOW_PAGING_LEVELS */
+#endif /* SHADOW_PAGING_LEVELS < 4 */
+
result |= shadow_set_l2e(v, sl2p, new_sl2e, sl2mfn);
return result;
@@ -2629,16 +2309,17 @@ static int validate_gl1e(struct vcpu *v, void *new_ge, mfn_t sl1mfn, void *se)
guest_l1e_t *new_gl1e = new_ge;
shadow_l1e_t *sl1p = se;
gfn_t gfn;
- mfn_t mfn;
- int result = 0;
+ mfn_t gmfn;
+ int result = 0, mmio;
perfc_incrc(shadow_validate_gl1e_calls);
gfn = guest_l1e_get_gfn(*new_gl1e);
- mfn = vcpu_gfn_to_mfn(v, gfn);
+ gmfn = vcpu_gfn_to_mfn(v, gfn);
- l1e_propagate_from_guest(v, *new_gl1e, &new_sl1e,
- /* mmio? */ !valid_mfn(mfn));
+ mmio = (is_hvm_vcpu(v) && shadow_vcpu_mode_translate(v) && !mfn_valid(gmfn));
+ l1e_propagate_from_guest(v, new_gl1e, _mfn(INVALID_MFN), gmfn, &new_sl1e,
+ ft_prefetch, mmio);
result |= shadow_set_l1e(v, sl1p, new_sl1e, sl1mfn);
return result;
@@ -2671,7 +2352,7 @@ sh_map_and_validate(struct vcpu *v, mfn_t gmfn,
/* Map the shadow page */
smfn = get_shadow_status(v, gmfn, sh_type);
- ASSERT(valid_mfn(smfn)); /* Otherwise we would not have been called */
+ ASSERT(mfn_valid(smfn)); /* Otherwise we would not have been called */
guest_idx = guest_index(new_gp);
map_mfn = smfn;
shadow_idx = shadow_index(&map_mfn, guest_idx);
@@ -2708,7 +2389,7 @@ sh_map_and_validate_gl4e(struct vcpu *v, mfn_t gl4mfn,
{
#if GUEST_PAGING_LEVELS >= 4
return sh_map_and_validate(v, gl4mfn, new_gl4p, size,
- PGC_SH_l4_shadow,
+ SH_type_l4_shadow,
shadow_l4_index,
validate_gl4e);
#else // ! GUEST_PAGING_LEVELS >= 4
@@ -2722,12 +2403,12 @@ int
sh_map_and_validate_gl3e(struct vcpu *v, mfn_t gl3mfn,
void *new_gl3p, u32 size)
{
-#if GUEST_PAGING_LEVELS >= 3
+#if GUEST_PAGING_LEVELS >= 4
return sh_map_and_validate(v, gl3mfn, new_gl3p, size,
- PGC_SH_l3_shadow,
+ SH_type_l3_shadow,
shadow_l3_index,
validate_gl3e);
-#else // ! GUEST_PAGING_LEVELS >= 3
+#else // ! GUEST_PAGING_LEVELS >= 4
SHADOW_PRINTK("called in wrong paging mode!\n");
BUG();
return 0;
@@ -2739,7 +2420,7 @@ sh_map_and_validate_gl2e(struct vcpu *v, mfn_t gl2mfn,
void *new_gl2p, u32 size)
{
return sh_map_and_validate(v, gl2mfn, new_gl2p, size,
- PGC_SH_l2_shadow,
+ SH_type_l2_shadow,
shadow_l2_index,
validate_gl2e);
}
@@ -2750,7 +2431,7 @@ sh_map_and_validate_gl2he(struct vcpu *v, mfn_t gl2mfn,
{
#if GUEST_PAGING_LEVELS == 3
return sh_map_and_validate(v, gl2mfn, new_gl2p, size,
- PGC_SH_l2h_shadow,
+ SH_type_l2h_shadow,
shadow_l2_index,
validate_gl2e);
#else /* Non-PAE guests don't have different kinds of l2 table */
@@ -2765,7 +2446,7 @@ sh_map_and_validate_gl1e(struct vcpu *v, mfn_t gl1mfn,
void *new_gl1p, u32 size)
{
return sh_map_and_validate(v, gl1mfn, new_gl1p, size,
- PGC_SH_l1_shadow,
+ SH_type_l1_shadow,
shadow_l1_index,
validate_gl1e);
}
@@ -2788,36 +2469,11 @@ static inline void check_for_early_unshadow(struct vcpu *v, mfn_t gmfn)
sh_mfn_is_a_page_table(gmfn) )
{
u32 flags = mfn_to_page(gmfn)->shadow_flags;
- mfn_t smfn;
- if ( !(flags & (SHF_L2_32|SHF_L3_PAE|SHF_L4_64)) )
+ if ( !(flags & (SHF_L2_32|SHF_L2_PAE|SHF_L2H_PAE|SHF_L4_64)) )
{
perfc_incrc(shadow_early_unshadow);
- sh_remove_shadows(v, gmfn, 0 /* Can fail to unshadow */ );
- return;
- }
- /* SHF_unhooked_mappings is set to make sure we only unhook
- * once in a single batch of updates. It is reset when this
- * top-level page is loaded into CR3 again */
- if ( !(flags & SHF_unhooked_mappings) )
- {
- perfc_incrc(shadow_early_unshadow_top);
- mfn_to_page(gmfn)->shadow_flags |= SHF_unhooked_mappings;
- if ( flags & SHF_L2_32 )
- {
- smfn = get_shadow_status(v, gmfn, PGC_SH_l2_32_shadow);
- shadow_unhook_mappings(v, smfn);
- }
- if ( flags & SHF_L3_PAE )
- {
- smfn = get_shadow_status(v, gmfn, PGC_SH_l3_pae_shadow);
- shadow_unhook_mappings(v, smfn);
- }
- if ( flags & SHF_L4_64 )
- {
- smfn = get_shadow_status(v, gmfn, PGC_SH_l4_64_shadow);
- shadow_unhook_mappings(v, smfn);
- }
- }
+ sh_remove_shadows(v, gmfn, 1, 0 /* Fast, can fail to unshadow */ );
+ }
}
v->arch.shadow.last_emulated_mfn = mfn_x(gmfn);
#endif
@@ -2834,6 +2490,80 @@ static inline void reset_early_unshadow(struct vcpu *v)
/**************************************************************************/
+/* Optimization: Prefetch multiple L1 entries. This is called after we have
+ * demand-faulted a shadow l1e in the fault handler, to see if it's
+ * worth fetching some more.
+ */
+
+#if SHADOW_OPTIMIZATIONS & SHOPT_PREFETCH
+
+/* XXX magic number */
+#define PREFETCH_DISTANCE 32
+
+static void sh_prefetch(struct vcpu *v, walk_t *gw,
+ shadow_l1e_t *ptr_sl1e, mfn_t sl1mfn)
+{
+ int i, dist, mmio;
+ gfn_t gfn;
+ mfn_t gmfn;
+ guest_l1e_t gl1e;
+ shadow_l1e_t sl1e;
+ u32 gflags;
+
+ /* Prefetch no further than the end of the _shadow_ l1 MFN */
+ dist = (PAGE_SIZE - ((unsigned long)ptr_sl1e & ~PAGE_MASK)) / sizeof sl1e;
+ /* And no more than a maximum fetches-per-fault */
+ if ( dist > PREFETCH_DISTANCE )
+ dist = PREFETCH_DISTANCE;
+
+ for ( i = 1; i < dist ; i++ )
+ {
+ /* No point in prefetching if there's already a shadow */
+ if ( ptr_sl1e[i].l1 != 0 )
+ break;
+
+ if ( gw->l1e )
+ {
+ /* Normal guest page; grab the next guest entry */
+ gl1e = gw->l1e[i];
+ /* Not worth continuing if we hit an entry that will need another
+ * fault for A/D-bit propagation anyway */
+ gflags = guest_l1e_get_flags(gl1e);
+ if ( (gflags & _PAGE_PRESENT)
+ && (!(gflags & _PAGE_ACCESSED)
+ || ((gflags & _PAGE_RW) && !(gflags & _PAGE_DIRTY))) )
+ break;
+ }
+ else
+ {
+ /* Fragmented superpage, unless we've been called wrongly */
+ ASSERT(guest_l2e_get_flags(*gw->l2e) & _PAGE_PSE);
+ /* Increment the l1e's GFN by the right number of guest pages */
+ gl1e = guest_l1e_from_gfn(
+ _gfn(gfn_x(guest_l1e_get_gfn(gw->eff_l1e)) + i),
+ guest_l1e_get_flags(gw->eff_l1e));
+ }
+
+ /* Look at the gfn that the l1e is pointing at */
+ gfn = guest_l1e_get_gfn(gl1e);
+ gmfn = vcpu_gfn_to_mfn(v, gfn);
+ mmio = ( is_hvm_vcpu(v)
+ && shadow_vcpu_mode_translate(v)
+ && mmio_space(gfn_to_paddr(gfn)) );
+
+ /* Propagate the entry. Safe to use a pointer to our local
+ * gl1e, since this is not a demand-fetch so there will be no
+ * write-back to the guest. */
+ l1e_propagate_from_guest(v, &gl1e, _mfn(INVALID_MFN),
+ gmfn, &sl1e, ft_prefetch, mmio);
+ (void) shadow_set_l1e(v, ptr_sl1e + i, sl1e, sl1mfn);
+ }
+}
+
+#endif /* SHADOW_OPTIMIZATIONS & SHOPT_PREFETCH */
+
+
+/**************************************************************************/
/* Entry points into the shadow code */
/* Called from pagefault handler in Xen, and from the HVM trap handlers
@@ -2852,21 +2582,79 @@ static int sh_page_fault(struct vcpu *v,
mfn_t gmfn, sl1mfn=_mfn(0);
shadow_l1e_t sl1e, *ptr_sl1e;
paddr_t gpa;
- struct cpu_user_regs emul_regs;
struct x86_emulate_ctxt emul_ctxt;
int r, mmio;
fetch_type_t ft = 0;
+ SHADOW_PRINTK("d:v=%u:%u va=%#lx err=%u\n",
+ v->domain->domain_id, v->vcpu_id, va, regs->error_code);
+
//
// XXX: Need to think about eventually mapping superpages directly in the
// shadow (when possible), as opposed to splintering them into a
// bunch of 4K maps.
//
- shadow_lock(d);
+#if (SHADOW_OPTIMIZATIONS & SHOPT_FAST_FAULT_PATH) && SHADOW_PAGING_LEVELS > 2
+ if ( (regs->error_code & PFEC_reserved_bit) )
+ {
+ /* The only reasons for reserved bits to be set in shadow entries
+ * are the two "magic" shadow_l1e entries. */
+ if ( likely((__copy_from_user(&sl1e,
+ (sh_linear_l1_table(v)
+ + shadow_l1_linear_offset(va)),
+ sizeof(sl1e)) == 0)
+ && sh_l1e_is_magic(sl1e)) )
+ {
+ if ( sh_l1e_is_gnp(sl1e) )
+ {
+ if ( likely(!is_hvm_domain(d) ||
+ shadow_vcpu_mode_translate(v)) )
+ {
+ /* Not-present in a guest PT: pass to the guest as
+ * a not-present fault (by flipping two bits). */
+ ASSERT(regs->error_code & PFEC_page_present);
+ regs->error_code ^= (PFEC_reserved_bit|PFEC_page_present);
+ perfc_incrc(shadow_fault_fast_gnp);
+ SHADOW_PRINTK("fast path not-present\n");
+ return 0;
+ }
+ else
+ {
+ /* Not-present in the P2M: MMIO */
+ gpa = va;
+ }
+ }
+ else
+ {
+ /* Magic MMIO marker: extract gfn for MMIO address */
+ ASSERT(sh_l1e_is_mmio(sl1e));
+ gpa = (((paddr_t)(gfn_x(sh_l1e_mmio_get_gfn(sl1e))))
+ << PAGE_SHIFT)
+ | (va & ~PAGE_MASK);
+ }
+ perfc_incrc(shadow_fault_fast_mmio);
+ SHADOW_PRINTK("fast path mmio %#"PRIpaddr"\n", gpa);
+ reset_early_unshadow(v);
+ handle_mmio(gpa);
+ return EXCRET_fault_fixed;
+ }
+ else
+ {
+ /* This should be exceptionally rare: another vcpu has fixed
+ * the tables between the fault and our reading the l1e.
+ * Fall through to the normal fault handing logic */
+ perfc_incrc(shadow_fault_fast_fail);
+ SHADOW_PRINTK("fast path false alarm!\n");
+ /* Don't pass the reserved-bit bit: if we look at the fault
+ * below and decide to pass it to the guest, the reserved-bit
+ * bit won't make sense there. */
+ regs->error_code &= ~PFEC_reserved_bit;
+ }
+ }
+#endif /* SHOPT_FAST_FAULT_PATH */
- SHADOW_PRINTK("d:v=%u:%u va=%#lx err=%u\n",
- v->domain->domain_id, v->vcpu_id, va, regs->error_code);
+ shadow_lock(d);
shadow_audit_tables(v);
@@ -2887,7 +2675,7 @@ static int sh_page_fault(struct vcpu *v,
//
if ( unlikely(!(guest_l1e_get_flags(gw.eff_l1e) & _PAGE_PRESENT)) )
{
- if ( hvm_guest(v) && !shadow_vcpu_mode_translate(v) )
+ if ( is_hvm_domain(d) && !shadow_vcpu_mode_translate(v) )
{
/* Not present in p2m map, means this is mmio */
gpa = va;
@@ -2899,7 +2687,7 @@ static int sh_page_fault(struct vcpu *v,
}
// All levels of the guest page table are now known to be present.
- accumulated_gflags = accumulate_guest_flags(&gw);
+ accumulated_gflags = accumulate_guest_flags(v, &gw);
// Check for attempts to access supervisor-only pages from user mode,
// i.e. ring 3. Such errors are not caused or dealt with by the shadow
@@ -2914,8 +2702,9 @@ static int sh_page_fault(struct vcpu *v,
}
// Was it a write fault?
- //
- if ( regs->error_code & PFEC_write_access )
+ ft = ((regs->error_code & PFEC_write_access)
+ ? ft_demand_write : ft_demand_read);
+ if ( ft == ft_demand_write )
{
if ( unlikely(!(accumulated_gflags & _PAGE_RW)) )
{
@@ -2940,26 +2729,19 @@ static int sh_page_fault(struct vcpu *v,
}
}
- /* Is this an MMIO access? */
+ /* What mfn is the guest trying to access? */
gfn = guest_l1e_get_gfn(gw.eff_l1e);
- mmio = ( hvm_guest(v)
- && shadow_vcpu_mode_translate(v)
- && mmio_space(gfn_to_paddr(gfn)) );
+ gmfn = vcpu_gfn_to_mfn(v, gfn);
+ mmio = (is_hvm_domain(d)
+ && shadow_vcpu_mode_translate(v)
+ && mmio_space(gfn_to_paddr(gfn)));
- /* For MMIO, the shadow holds the *gfn*; for normal accesses, it holds
- * the equivalent mfn. */
- if ( mmio )
- gmfn = _mfn(gfn_x(gfn));
- else
+ if ( !mmio && !mfn_valid(gmfn) )
{
- gmfn = vcpu_gfn_to_mfn(v, gfn);
- if ( !valid_mfn(gmfn) )
- {
- perfc_incrc(shadow_fault_bail_bad_gfn);
- SHADOW_PRINTK("BAD gfn=%"SH_PRI_gfn" gmfn=%"SH_PRI_mfn"\n",
- gfn_x(gfn), mfn_x(gmfn));
- goto not_a_shadow_fault;
- }
+ perfc_incrc(shadow_fault_bail_bad_gfn);
+ SHADOW_PRINTK("BAD gfn=%"SH_PRI_gfn" gmfn=%"SH_PRI_mfn"\n",
+ gfn_x(gfn), mfn_x(gmfn));
+ goto not_a_shadow_fault;
}
/* Make sure there is enough free shadow memory to build a chain of
@@ -2970,33 +2752,42 @@ static int sh_page_fault(struct vcpu *v,
/* Acquire the shadow. This must happen before we figure out the rights
* for the shadow entry, since we might promote a page here. */
- // XXX -- this code will need to change somewhat if/when the shadow code
- // can directly map superpages...
- ft = ((regs->error_code & PFEC_write_access) ?
- ft_demand_write : ft_demand_read);
ptr_sl1e = shadow_get_and_create_l1e(v, &gw, &sl1mfn, ft);
- ASSERT(ptr_sl1e);
+ if ( unlikely(ptr_sl1e == NULL) )
+ {
+ /* Couldn't get the sl1e! Since we know the guest entries
+ * are OK, this can only have been caused by a failed
+ * shadow_set_l*e(), which will have crashed the guest.
+ * Get out of the fault handler immediately. */
+ ASSERT(test_bit(_DOMF_dying, &d->domain_flags));
+ shadow_unlock(d);
+ return 0;
+ }
- /* Calculate the shadow entry */
- if ( ft == ft_demand_write )
+ /* Calculate the shadow entry and write it */
+ l1e_propagate_from_guest(v, (gw.l1e) ? gw.l1e : &gw.eff_l1e, gw.l1mfn,
+ gmfn, &sl1e, ft, mmio);
+ r = shadow_set_l1e(v, ptr_sl1e, sl1e, sl1mfn);
+
+#if SHADOW_OPTIMIZATIONS & SHOPT_PREFETCH
+ /* Prefetch some more shadow entries */
+ sh_prefetch(v, &gw, ptr_sl1e, sl1mfn);
+#endif
+
+ /* Need to emulate accesses to page tables */
+ if ( sh_mfn_is_a_page_table(gmfn) )
{
- if ( l1e_write_fault(v, &gw, gmfn, &sl1e, mmio) )
+ if ( ft == ft_demand_write )
{
perfc_incrc(shadow_fault_emulate_write);
goto emulate;
}
+ else if ( shadow_mode_trap_reads(d) && ft == ft_demand_read )
+ {
+ perfc_incrc(shadow_fault_emulate_read);
+ goto emulate;
+ }
}
- else if ( l1e_read_fault(v, &gw, gmfn, &sl1e, mmio) )
- {
- perfc_incrc(shadow_fault_emulate_read);
- goto emulate;
- }
-
- /* Quick sanity check: we never make an MMIO entry that's got the
- * _PAGE_PRESENT flag set in it. */
- ASSERT(!mmio || !(shadow_l1e_get_flags(sl1e) & _PAGE_PRESENT));
-
- r = shadow_set_l1e(v, ptr_sl1e, sl1e, sl1mfn);
if ( mmio )
{
@@ -3004,13 +2795,6 @@ static int sh_page_fault(struct vcpu *v,
goto mmio;
}
-#if 0
- if ( !(r & SHADOW_SET_CHANGED) )
- debugtrace_printk("%s: shadow_set_l1e(va=%p, sl1e=%" SH_PRI_pte
- ") did not change anything\n",
- __func__, gw.va, l1e_get_intpte(sl1e));
-#endif
-
perfc_incrc(shadow_fault_fixed);
d->arch.shadow.fault_count++;
reset_early_unshadow(v);
@@ -3024,22 +2808,26 @@ static int sh_page_fault(struct vcpu *v,
return EXCRET_fault_fixed;
emulate:
-
/* Take the register set we were called with */
- emul_regs = *regs;
- if ( hvm_guest(v) )
- {
- /* Add the guest's segment selectors, rip, rsp. rflags */
- hvm_store_cpu_guest_regs(v, &emul_regs, NULL);
- }
- emul_ctxt.regs = &emul_regs;
- emul_ctxt.cr2 = va;
- emul_ctxt.mode = hvm_guest(v) ? hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST;
+ if ( is_hvm_domain(d) )
+ hvm_store_cpu_guest_regs(v, regs, NULL);
+ emul_ctxt.regs = regs;
+ emul_ctxt.cr2 = va;
+ emul_ctxt.mode = (is_hvm_domain(d) ?
+ hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST);
- SHADOW_PRINTK("emulate: eip=%#lx\n", emul_regs.eip);
+ SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip);
v->arch.shadow.propagate_fault = 0;
- if ( x86_emulate_memop(&emul_ctxt, &shadow_emulator_ops) )
+
+ /*
+ * We do not emulate user writes. Instead we use them as a hint that the
+ * page is no longer a page table. This behaviour differs from native, but
+ * it seems very unlikely that any OS grants user access to page tables.
+ * We also disallow guest PTE updates from within Xen.
+ */
+ if ( (regs->error_code & PFEC_user_mode) || !guest_mode(regs) ||
+ x86_emulate_memop(&emul_ctxt, &shadow_emulator_ops) )
{
SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n",
mfn_x(gmfn));
@@ -3052,51 +2840,28 @@ static int sh_page_fault(struct vcpu *v,
* guest to loop on the same page fault. */
goto done;
}
+
+ /* Emulation triggered another page fault? */
if ( v->arch.shadow.propagate_fault )
- {
- /* Emulation triggered another page fault */
goto not_a_shadow_fault;
- }
/* Emulator has changed the user registers: write back */
- if ( hvm_guest(v) )
- {
- /* Write back the guest's segment selectors, rip, rsp. rflags */
- hvm_load_cpu_guest_regs(v, &emul_regs);
- /* And don't overwrite those in the caller's regs. */
- emul_regs.eip = regs->eip;
- emul_regs.cs = regs->cs;
- emul_regs.eflags = regs->eflags;
- emul_regs.esp = regs->esp;
- emul_regs.ss = regs->ss;
- emul_regs.es = regs->es;
- emul_regs.ds = regs->ds;
- emul_regs.fs = regs->fs;
- emul_regs.gs = regs->gs;
- }
- *regs = emul_regs;
+ if ( is_hvm_domain(d) )
+ hvm_load_cpu_guest_regs(v, regs);
goto done;
mmio:
+ if ( !guest_mode(regs) )
+ goto not_a_shadow_fault;
perfc_incrc(shadow_fault_mmio);
- if ( !hvm_apic_support(d) && (gpa >= 0xFEC00000) )
- {
- /* Need to deal with these disabled-APIC accesses, as
- * handle_mmio() apparently does not currently do that. */
- /* TJD: What about it, then? For now, I'm turning this BUG()
- * into a domain_crash() since we don't want to kill Xen. */
- SHADOW_ERROR("disabled-APIC access: not supported\n.");
- domain_crash(d);
- }
sh_audit_gw(v, &gw);
unmap_walk(v, &gw);
- SHADOW_PRINTK("mmio\n");
+ SHADOW_PRINTK("mmio %#"PRIpaddr"\n", gpa);
shadow_audit_tables(v);
reset_early_unshadow(v);
shadow_unlock(d);
- sh_log_mmio(v, gpa);
- handle_mmio(va, gpa);
+ handle_mmio(gpa);
return EXCRET_fault_fixed;
not_a_shadow_fault:
@@ -3116,27 +2881,62 @@ sh_invlpg(struct vcpu *v, unsigned long va)
* instruction should be issued on the hardware, or 0 if it's safe not
* to do so. */
{
- shadow_l2e_t *ptr_sl2e = shadow_get_l2e(v, va);
+ shadow_l2e_t sl2e;
+
+ perfc_incrc(shadow_invlpg);
- // XXX -- might be a good thing to prefetch the va into the shadow
+ /* First check that we can safely read the shadow l2e. SMP/PAE linux can
+ * run as high as 6% of invlpg calls where we haven't shadowed the l2
+ * yet. */
+#if SHADOW_PAGING_LEVELS == 4
+ {
+ shadow_l3e_t sl3e;
+ if ( !(shadow_l4e_get_flags(
+ sh_linear_l4_table(v)[shadow_l4_linear_offset(va)])
+ & _PAGE_PRESENT) )
+ return 0;
+ /* This must still be a copy-from-user because we don't have the
+ * shadow lock, and the higher-level shadows might disappear
+ * under our feet. */
+ if ( __copy_from_user(&sl3e, (sh_linear_l3_table(v)
+ + shadow_l3_linear_offset(va)),
+ sizeof (sl3e)) != 0 )
+ {
+ perfc_incrc(shadow_invlpg_fault);
+ return 0;
+ }
+ if ( (!shadow_l3e_get_flags(sl3e) & _PAGE_PRESENT) )
+ return 0;
+ }
+#elif SHADOW_PAGING_LEVELS == 3
+ if ( !(l3e_get_flags(v->arch.shadow.l3table[shadow_l3_linear_offset(va)])
+ & _PAGE_PRESENT) )
+ // no need to flush anything if there's no SL2...
+ return 0;
+#endif
- // no need to flush anything if there's no SL2...
- //
- if ( !ptr_sl2e )
+ /* This must still be a copy-from-user because we don't have the shadow
+ * lock, and the higher-level shadows might disappear under our feet. */
+ if ( __copy_from_user(&sl2e,
+ sh_linear_l2_table(v) + shadow_l2_linear_offset(va),
+ sizeof (sl2e)) != 0 )
+ {
+ perfc_incrc(shadow_invlpg_fault);
return 0;
+ }
// If there's nothing shadowed for this particular sl2e, then
// there is no need to do an invlpg, either...
//
- if ( !(shadow_l2e_get_flags(*ptr_sl2e) & _PAGE_PRESENT) )
+ if ( !(shadow_l2e_get_flags(sl2e) & _PAGE_PRESENT) )
return 0;
// Check to see if the SL2 is a splintered superpage...
// If so, then we'll need to flush the entire TLB (because that's
// easier than invalidating all of the individual 4K pages).
//
- if ( (mfn_to_page(shadow_l2e_get_mfn(*ptr_sl2e))->count_info &
- PGC_SH_type_mask) == PGC_SH_fl1_shadow )
+ if ( mfn_to_shadow_page(shadow_l2e_get_mfn(sl2e))->type
+ == SH_type_fl1_shadow )
{
local_flush_tlb();
return 0;
@@ -3161,7 +2961,7 @@ sh_gva_to_gfn(struct vcpu *v, unsigned long va)
}
-static unsigned long
+static paddr_t
sh_gva_to_gpa(struct vcpu *v, unsigned long va)
/* Called to translate a guest virtual address to what the *guest*
* pagetables would map it to. */
@@ -3170,38 +2970,10 @@ sh_gva_to_gpa(struct vcpu *v, unsigned long va)
if ( gfn == INVALID_GFN )
return 0;
else
- return (gfn << PAGE_SHIFT) | (va & ~PAGE_MASK);
+ return (((paddr_t)gfn) << PAGE_SHIFT) + (va & ~PAGE_MASK);
}
-// XXX -- should this be in this file?
-// Or should it be moved to shadow-common.c?
-//
-/* returns a lowmem machine address of the copied HVM L3 root table
- * If clear_res != 0, then clear the PAE-l3 reserved bits in the copy,
- * otherwise blank out any entries with reserved bits in them. */
-#if (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3)
-static unsigned long
-hvm_pae_copy_root(struct vcpu *v, l3_pgentry_t *l3tab, int clear_res)
-{
- int i, f;
- int res = (_PAGE_RW|_PAGE_NX_BIT|_PAGE_USER|_PAGE_ACCESSED|_PAGE_DIRTY);
- l3_pgentry_t new_l3e, *copy = v->arch.hvm_vcpu.hvm_lowmem_l3tab;
- memcpy(copy, l3tab, 4 * sizeof(l3_pgentry_t));
- for ( i = 0; i < 4; i++ )
- {
- f = l3e_get_flags(l3tab[i]);
- if ( (f & _PAGE_PRESENT) && (!(f & res) || clear_res) )
- new_l3e = l3e_from_pfn(l3e_get_pfn(l3tab[i]), f & ~res);
- else
- new_l3e = l3e_empty();
- safe_write_entry(&copy[i], &new_l3e);
- }
- return __pa(copy);
-}
-#endif
-
-
static inline void
sh_update_linear_entries(struct vcpu *v)
/* Sync up all the linear mappings for this vcpu's pagetables */
@@ -3255,7 +3027,7 @@ sh_update_linear_entries(struct vcpu *v)
if ( v == current )
{
__linear_l4_table[l4_linear_offset(SH_LINEAR_PT_VIRT_START)] =
- l4e_from_pfn(pagetable_get_pfn(v->arch.shadow_table),
+ l4e_from_pfn(pagetable_get_pfn(v->arch.shadow_table[0]),
__PAGE_HYPERVISOR);
}
else
@@ -3263,7 +3035,7 @@ sh_update_linear_entries(struct vcpu *v)
l4_pgentry_t *ml4e;
ml4e = sh_map_domain_page(pagetable_get_mfn(v->arch.monitor_table));
ml4e[l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
- l4e_from_pfn(pagetable_get_pfn(v->arch.shadow_table),
+ l4e_from_pfn(pagetable_get_pfn(v->arch.shadow_table[0]),
__PAGE_HYPERVISOR);
sh_unmap_domain_page(ml4e);
}
@@ -3304,13 +3076,8 @@ sh_update_linear_entries(struct vcpu *v)
sh_unmap_domain_page(ml4e);
}
-#if GUEST_PAGING_LEVELS == 2
/* Shadow l3 tables are made up by update_cr3 */
- sl3e = v->arch.hvm_vcpu.hvm_lowmem_l3tab;
-#else
- /* Always safe to use shadow_vtable, because it's globally mapped */
- sl3e = v->arch.shadow_vtable;
-#endif
+ sl3e = v->arch.shadow.l3table;
for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ )
{
@@ -3344,56 +3111,63 @@ sh_update_linear_entries(struct vcpu *v)
l2_pgentry_t *l2e, new_l2e;
shadow_l3e_t *guest_l3e = NULL, *shadow_l3e;
int i;
+ int unmap_l2e = 0;
#if GUEST_PAGING_LEVELS == 2
/* Shadow l3 tables were built by update_cr3 */
if ( shadow_mode_external(d) )
- shadow_l3e = v->arch.hvm_vcpu.hvm_lowmem_l3tab;
+ shadow_l3e = (shadow_l3e_t *)&v->arch.shadow.l3table;
else
BUG(); /* PV 2-on-3 is not supported yet */
#else /* GUEST_PAGING_LEVELS == 3 */
- /* Always safe to use *_vtable, because they're globally mapped */
- shadow_l3e = v->arch.shadow_vtable;
+ shadow_l3e = (shadow_l3e_t *)&v->arch.shadow.l3table;
+ /* Always safe to use guest_vtable, because it's globally mapped */
guest_l3e = v->arch.guest_vtable;
#endif /* GUEST_PAGING_LEVELS */
/* Choose where to write the entries, using linear maps if possible */
- if ( v == current && shadow_mode_external(d) )
+ if ( shadow_mode_external(d) )
{
- /* From the monitor tables, it's safe to use linear maps to update
- * monitor l2s */
- l2e = __linear_l2_table + (3 * L2_PAGETABLE_ENTRIES);
+ if ( v == current )
+ {
+ /* From the monitor tables, it's safe to use linear maps
+ * to update monitor l2s */
+ l2e = __linear_l2_table + (3 * L2_PAGETABLE_ENTRIES);
+ }
+ else
+ {
+ /* Map the monitor table's high l2 */
+ l3_pgentry_t *l3e;
+ l3e = sh_map_domain_page(
+ pagetable_get_mfn(v->arch.monitor_table));
+ ASSERT(l3e_get_flags(l3e[3]) & _PAGE_PRESENT);
+ l2e = sh_map_domain_page(_mfn(l3e_get_pfn(l3e[3])));
+ unmap_l2e = 1;
+ sh_unmap_domain_page(l3e);
+ }
}
- else if ( shadow_mode_external(d) )
- {
- /* Map the monitor table's high l2 */
- l3_pgentry_t *l3e;
- l3e = sh_map_domain_page(
- pagetable_get_mfn(v->arch.monitor_table));
- ASSERT(l3e_get_flags(l3e[3]) & _PAGE_PRESENT);
- l2e = sh_map_domain_page(_mfn(l3e_get_pfn(l3e[3])));
- sh_unmap_domain_page(l3e);
- }
else
{
/* Map the shadow table's high l2 */
ASSERT(shadow_l3e_get_flags(shadow_l3e[3]) & _PAGE_PRESENT);
l2e = sh_map_domain_page(shadow_l3e_get_mfn(shadow_l3e[3]));
+ unmap_l2e = 1;
}
-
- if ( !shadow_mode_external(d) )
+ /* Write linear mapping of guest (only in PV, and only when
+ * not translated). */
+ if ( !shadow_mode_translate(d) )
{
- /* Write linear mapping of guest. */
for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ )
- {
- new_l2e = (shadow_l3e_get_flags(guest_l3e[i]) & _PAGE_PRESENT)
- ? l2e_from_pfn(mfn_x(shadow_l3e_get_mfn(guest_l3e[i])),
- __PAGE_HYPERVISOR)
- : l2e_empty();
+ {
+ new_l2e =
+ ((shadow_l3e_get_flags(guest_l3e[i]) & _PAGE_PRESENT)
+ ? l2e_from_pfn(mfn_x(shadow_l3e_get_mfn(guest_l3e[i])),
+ __PAGE_HYPERVISOR)
+ : l2e_empty());
safe_write_entry(
&l2e[l2_table_offset(LINEAR_PT_VIRT_START) + i],
&new_l2e);
@@ -3412,9 +3186,8 @@ sh_update_linear_entries(struct vcpu *v)
&new_l2e);
}
- if ( v != current || !shadow_mode_external(d) )
+ if ( unmap_l2e )
sh_unmap_domain_page(l2e);
-
}
#elif CONFIG_PAGING_LEVELS == 2
@@ -3429,7 +3202,7 @@ sh_update_linear_entries(struct vcpu *v)
if ( v == current )
{
__linear_l2_table[l2_linear_offset(SH_LINEAR_PT_VIRT_START)] =
- l2e_from_pfn(pagetable_get_pfn(v->arch.shadow_table),
+ l2e_from_pfn(pagetable_get_pfn(v->arch.shadow_table[0]),
__PAGE_HYPERVISOR);
}
else
@@ -3437,7 +3210,7 @@ sh_update_linear_entries(struct vcpu *v)
l2_pgentry_t *ml2e;
ml2e = sh_map_domain_page(pagetable_get_mfn(v->arch.monitor_table));
ml2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] =
- l2e_from_pfn(pagetable_get_pfn(v->arch.shadow_table),
+ l2e_from_pfn(pagetable_get_pfn(v->arch.shadow_table[0]),
__PAGE_HYPERVISOR);
sh_unmap_domain_page(ml2e);
}
@@ -3449,138 +3222,131 @@ sh_update_linear_entries(struct vcpu *v)
}
-// XXX -- should this be in this file?
-// Or should it be moved to shadow-common.c?
-//
-#if (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3)
-void sh_pae_recopy(struct domain *d)
-/* Called whenever we write to the l3 entries of a PAE pagetable which
- * is currently in use. Each vcpu that is using the table needs to
- * resync its copies of the l3s in linear maps and any low-memory
- * copies it might have made for fitting into 32bit CR3.
- * Since linear maps are also resynced when we change CR3, we don't
- * need to worry about changes to PAE l3es that are not currently in use.*/
-{
- struct vcpu *v;
- cpumask_t flush_mask = CPU_MASK_NONE;
- ASSERT(shadow_lock_is_acquired(d));
-
- for_each_vcpu(d, v)
- {
- if ( !v->arch.shadow.pae_flip_pending )
- continue;
-
- cpu_set(v->processor, flush_mask);
-
- SHADOW_PRINTK("d=%u v=%u\n", v->domain->domain_id, v->vcpu_id);
-
- /* This vcpu has a copy in its linear maps */
- sh_update_linear_entries(v);
- if ( hvm_guest(v) )
- {
- /* This vcpu has a copy in its HVM PAE l3 */
- v->arch.hvm_vcpu.hw_cr3 =
- hvm_pae_copy_root(v, v->arch.shadow_vtable,
- !shadow_vcpu_mode_translate(v));
- }
-#if CONFIG_PAGING_LEVELS == 3
- else
- {
- /* This vcpu might have copied the l3 to below 4GB */
- if ( v->arch.cr3 >> PAGE_SHIFT
- != pagetable_get_pfn(v->arch.shadow_table) )
- {
- /* Recopy to where that copy is. */
- int i;
- l3_pgentry_t *dst, *src;
- dst = __va(v->arch.cr3 & ~0x1f); /* Mask cache control bits */
- src = v->arch.shadow_vtable;
- for ( i = 0 ; i < 4 ; i++ )
- safe_write_entry(dst + i, src + i);
- }
- }
-#endif
- v->arch.shadow.pae_flip_pending = 0;
- }
-
- flush_tlb_mask(flush_mask);
-}
-#endif /* (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3) */
-
-
-/* removes:
- * vcpu->arch.guest_vtable
- * vcpu->arch.shadow_table
- * vcpu->arch.shadow_vtable
+/* Removes vcpu->arch.guest_vtable and vcpu->arch.shadow_table[].
* Does all appropriate management/bookkeeping/refcounting/etc...
*/
static void
sh_detach_old_tables(struct vcpu *v)
{
+ struct domain *d = v->domain;
mfn_t smfn;
+ int i = 0;
////
//// vcpu->arch.guest_vtable
////
- if ( (shadow_mode_external(v->domain) || (GUEST_PAGING_LEVELS == 3)) &&
- v->arch.guest_vtable )
+ if ( v->arch.guest_vtable )
{
- // Q: why does this need to use (un)map_domain_page_*global* ?
- sh_unmap_domain_page_global(v->arch.guest_vtable);
+#if GUEST_PAGING_LEVELS == 4
+ if ( shadow_mode_external(d) || shadow_mode_translate(d) )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
+#elif GUEST_PAGING_LEVELS == 3
+ if ( 1 || shadow_mode_external(d) || shadow_mode_translate(d) )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
+#elif GUEST_PAGING_LEVELS == 2
+ if ( shadow_mode_external(d) || shadow_mode_translate(d) )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
+#endif
v->arch.guest_vtable = NULL;
}
////
- //// vcpu->arch.shadow_table
+ //// vcpu->arch.shadow_table[]
////
- smfn = pagetable_get_mfn(v->arch.shadow_table);
- if ( mfn_x(smfn) )
- {
- ASSERT(v->arch.shadow_vtable);
+
#if GUEST_PAGING_LEVELS == 3
- // PAE guests do not (necessarily) use an entire page for their
- // 4-entry L3s, so we have to deal with them specially.
- //
- sh_put_ref_l3_subshadow(v, v->arch.shadow_vtable, smfn);
-#else
- sh_put_ref(v, smfn, 0);
+ /* PAE guests have four shadow_table entries */
+ for ( i = 0 ; i < 4 ; i++ )
#endif
+ {
+ smfn = pagetable_get_mfn(v->arch.shadow_table[i]);
+ if ( mfn_x(smfn) )
+ sh_put_ref(v, smfn, 0);
+ v->arch.shadow_table[i] = pagetable_null();
+ }
+}
-#if (SHADOW_PAGING_LEVELS == 3) && (GUEST_PAGING_LEVELS == 3)
- {
- struct pae_l3_bookkeeping *info =
- sl3p_to_info(v->arch.shadow_vtable);
- ASSERT(test_bit(v->vcpu_id, &info->vcpus));
- clear_bit(v->vcpu_id, &info->vcpus);
- }
+/* Set up the top-level shadow and install it in slot 'slot' of shadow_table */
+static void
+sh_set_toplevel_shadow(struct vcpu *v,
+ int slot,
+ mfn_t gmfn,
+ unsigned int root_type)
+{
+ mfn_t smfn;
+ pagetable_t old_entry, new_entry;
+
+ struct domain *d = v->domain;
+
+ /* Remember the old contents of this slot */
+ old_entry = v->arch.shadow_table[slot];
+
+ /* Now figure out the new contents: is this a valid guest MFN? */
+ if ( !mfn_valid(gmfn) )
+ {
+ new_entry = pagetable_null();
+ goto install_new_entry;
+ }
+
+ /* Guest mfn is valid: shadow it and install the shadow */
+ smfn = get_shadow_status(v, gmfn, root_type);
+ if ( !mfn_valid(smfn) )
+ {
+ /* Make sure there's enough free shadow memory. */
+ shadow_prealloc(d, SHADOW_MAX_ORDER);
+ /* Shadow the page. */
+ smfn = sh_make_shadow(v, gmfn, root_type);
+ }
+ ASSERT(mfn_valid(smfn));
+
+#if SHADOW_OPTIMIZATIONS & SHOPT_EARLY_UNSHADOW
+ /* Once again OK to unhook entries from this table if we see fork/exit */
+ ASSERT(sh_mfn_is_a_page_table(gmfn));
+ mfn_to_page(gmfn)->shadow_flags &= ~SHF_unhooked_mappings;
#endif
- v->arch.shadow_table = pagetable_null();
+
+ /* Pin the shadow and put it (back) on the list of top-level shadows */
+ if ( sh_pin(v, smfn) == 0 )
+ {
+ SHADOW_ERROR("can't pin %#lx as toplevel shadow\n", mfn_x(smfn));
+ domain_crash(v->domain);
}
- ////
- //// vcpu->arch.shadow_vtable
- ////
- if ( (shadow_mode_external(v->domain) || (GUEST_PAGING_LEVELS == 3)) &&
- v->arch.shadow_vtable )
+ /* Take a ref to this page: it will be released in sh_detach_old_tables()
+ * or the next call to set_toplevel_shadow() */
+ if ( !sh_get_ref(v, smfn, 0) )
{
- // Q: why does this need to use (un)map_domain_page_*global* ?
- /* A: so sh_update_linear_entries can operate on other vcpus */
- sh_unmap_domain_page_global(v->arch.shadow_vtable);
- v->arch.shadow_vtable = NULL;
+ SHADOW_ERROR("can't install %#lx as toplevel shadow\n", mfn_x(smfn));
+ domain_crash(v->domain);
}
+
+ new_entry = pagetable_from_mfn(smfn);
+
+ install_new_entry:
+ /* Done. Install it */
+ SHADOW_PRINTK("%u/%u [%u] gmfn %#"SH_PRI_mfn" smfn %#"SH_PRI_mfn"\n",
+ GUEST_PAGING_LEVELS, SHADOW_PAGING_LEVELS, slot,
+ mfn_x(gmfn), mfn_x(pagetable_get_mfn(new_entry)));
+ v->arch.shadow_table[slot] = new_entry;
+
+ /* Decrement the refcount of the old contents of this slot */
+ if ( !pagetable_is_null(old_entry) )
+ sh_put_ref(v, pagetable_get_mfn(old_entry), 0);
}
+
static void
sh_update_cr3(struct vcpu *v)
-/* Updates vcpu->arch.shadow_table after the guest has changed CR3.
+/* Updates vcpu->arch.cr3 after the guest has changed CR3.
* Paravirtual guests should set v->arch.guest_table (and guest_table_user,
* if appropriate).
- * HVM guests should also set hvm_get_guest_cntl_reg(v, 3)...
+ * HVM guests should also make sure hvm_get_guest_cntl_reg(v, 3) works,
+ * and read vcpu->arch.hvm_vcpu.hw_cr3 afterwards.
*/
{
struct domain *d = v->domain;
- mfn_t gmfn, smfn;
+ mfn_t gmfn;
#if GUEST_PAGING_LEVELS == 3
u32 guest_idx=0;
#endif
@@ -3594,7 +3360,7 @@ sh_update_cr3(struct vcpu *v)
#ifndef NDEBUG
/* Double-check that the HVM code has sent us a sane guest_table */
- if ( hvm_guest(v) )
+ if ( is_hvm_domain(d) )
{
gfn_t gfn;
@@ -3605,7 +3371,7 @@ sh_update_cr3(struct vcpu *v)
{
gfn = _gfn(paddr_to_pfn(hvm_get_guest_ctrl_reg(v, 3)));
gmfn = vcpu_gfn_to_mfn(v, gfn);
- ASSERT(valid_mfn(gmfn));
+ ASSERT(mfn_valid(gmfn));
ASSERT(pagetable_get_pfn(v->arch.guest_table) == mfn_x(gmfn));
}
else
@@ -3630,9 +3396,7 @@ sh_update_cr3(struct vcpu *v)
#endif
gmfn = pagetable_get_mfn(v->arch.guest_table);
- sh_detach_old_tables(v);
-
- if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
+ if ( !is_hvm_domain(d) && !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
{
ASSERT(v->arch.cr3 == 0);
return;
@@ -3641,9 +3405,20 @@ sh_update_cr3(struct vcpu *v)
////
//// vcpu->arch.guest_vtable
////
+#if GUEST_PAGING_LEVELS == 4
+ if ( shadow_mode_external(d) || shadow_mode_translate(d) )
+ {
+ if ( v->arch.guest_vtable )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
+ v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
+ }
+ else
+ v->arch.guest_vtable = __linear_l4_table;
+#elif GUEST_PAGING_LEVELS == 3
+ if ( v->arch.guest_vtable )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
if ( shadow_mode_external(d) )
{
-#if GUEST_PAGING_LEVELS == 3
if ( shadow_vcpu_mode_translate(v) )
/* Paging enabled: find where in the page the l3 table is */
guest_idx = guest_index((void *)hvm_get_guest_ctrl_reg(v, 3));
@@ -3654,25 +3429,25 @@ sh_update_cr3(struct vcpu *v)
// Ignore the low 2 bits of guest_idx -- they are really just
// cache control.
guest_idx &= ~3;
+
// XXX - why does this need a global map?
v->arch.guest_vtable =
(guest_l3e_t *)sh_map_domain_page_global(gmfn) + guest_idx;
-#else
- // XXX - why does this need a global map?
- v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
-#endif
}
else
+ v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
+#elif GUEST_PAGING_LEVELS == 2
+ if ( shadow_mode_external(d) || shadow_mode_translate(d) )
{
-#ifdef __x86_64__
- v->arch.guest_vtable = __linear_l4_table;
-#elif GUEST_PAGING_LEVELS == 3
- // XXX - why does this need a global map?
+ if ( v->arch.guest_vtable )
+ sh_unmap_domain_page_global(v->arch.guest_vtable);
v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
-#else
+ }
+ else
v->arch.guest_vtable = __linear_l2_table;
+#else
+#error this should never happen
#endif
- }
#if 0
printk("%s %s %d gmfn=%05lx guest_vtable=%p\n",
@@ -3680,148 +3455,122 @@ sh_update_cr3(struct vcpu *v)
#endif
////
- //// vcpu->arch.shadow_table
+ //// vcpu->arch.shadow_table[]
////
- smfn = get_shadow_status(v, gmfn, PGC_SH_guest_root_type);
- if ( valid_mfn(smfn) )
- {
- /* Pull this root shadow to the front of the list of roots. */
- list_del(&mfn_to_page(smfn)->list);
- list_add(&mfn_to_page(smfn)->list, &d->arch.shadow.toplevel_shadows);
- }
- else
- {
- /* This guest MFN is a pagetable. Must revoke write access. */
- if ( shadow_remove_write_access(v, gmfn, GUEST_PAGING_LEVELS, 0)
- != 0 )
- flush_tlb_mask(d->domain_dirty_cpumask);
- /* Make sure there's enough free shadow memory. */
- shadow_prealloc(d, SHADOW_MAX_ORDER);
- /* Shadow the page. */
- smfn = sh_make_shadow(v, gmfn, PGC_SH_guest_root_type);
- list_add(&mfn_to_page(smfn)->list, &d->arch.shadow.toplevel_shadows);
- }
- ASSERT(valid_mfn(smfn));
- v->arch.shadow_table = pagetable_from_mfn(smfn);
-
-#if SHADOW_OPTIMIZATIONS & SHOPT_EARLY_UNSHADOW
- /* Once again OK to unhook entries from this table if we see fork/exit */
- ASSERT(sh_mfn_is_a_page_table(gmfn));
- mfn_to_page(gmfn)->shadow_flags &= ~SHF_unhooked_mappings;
-#endif
-
- ////
- //// vcpu->arch.shadow_vtable
- ////
- if ( shadow_mode_external(d) )
+ /* We revoke write access to the new guest toplevel page(s) before we
+ * replace the old shadow pagetable(s), so that we can safely use the
+ * (old) shadow linear maps in the writeable mapping heuristics. */
+#if GUEST_PAGING_LEVELS == 2
+ if ( shadow_remove_write_access(v, gmfn, 2, 0) != 0 )
+ flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow);
+#elif GUEST_PAGING_LEVELS == 3
+ /* PAE guests have four shadow_table entries, based on the
+ * current values of the guest's four l3es. */
{
-#if (SHADOW_PAGING_LEVELS == 3) && (GUEST_PAGING_LEVELS == 3)
- mfn_t adjusted_smfn = smfn;
- u32 shadow_idx = shadow_l3_index(&adjusted_smfn, guest_idx);
- // Q: why does this need to use (un)map_domain_page_*global* ?
- v->arch.shadow_vtable =
- (shadow_l3e_t *)sh_map_domain_page_global(adjusted_smfn) +
- shadow_idx;
-#else
- // Q: why does this need to use (un)map_domain_page_*global* ?
- v->arch.shadow_vtable = sh_map_domain_page_global(smfn);
-#endif
+ int i, flush = 0;
+ gfn_t gl2gfn;
+ mfn_t gl2mfn;
+ guest_l3e_t *gl3e = (guest_l3e_t*)v->arch.guest_vtable;
+ /* First, make all four entries read-only. */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
+ {
+ gl2gfn = guest_l3e_get_gfn(gl3e[i]);
+ gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+ flush |= shadow_remove_write_access(v, gl2mfn, 2, 0);
+ }
+ }
+ if ( flush )
+ flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ /* Now install the new shadows. */
+ for ( i = 0; i < 4; i++ )
+ {
+ if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
+ {
+ gl2gfn = guest_l3e_get_gfn(gl3e[i]);
+ gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+ sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3)
+ ? SH_type_l2h_shadow
+ : SH_type_l2_shadow);
+ }
+ }
}
- else
- {
-#if SHADOW_PAGING_LEVELS == 4
- v->arch.shadow_vtable = __sh_linear_l4_table;
-#elif GUEST_PAGING_LEVELS == 3
- // XXX - why does this need a global map?
- v->arch.shadow_vtable = sh_map_domain_page_global(smfn);
+#elif GUEST_PAGING_LEVELS == 4
+ if ( shadow_remove_write_access(v, gmfn, 4, 0) != 0 )
+ flush_tlb_mask(v->domain->domain_dirty_cpumask);
+ sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow);
#else
- v->arch.shadow_vtable = __sh_linear_l2_table;
+#error This should never happen
#endif
- }
- ////
- //// Take a ref to the new shadow table, and pin it.
- ////
- //
- // This ref is logically "held" by v->arch.shadow_table entry itself.
- // Release the old ref.
- //
-#if GUEST_PAGING_LEVELS == 3
- // PAE guests do not (necessarily) use an entire page for their
- // 4-entry L3s, so we have to deal with them specially.
- //
- // XXX - might want to revisit this if/when we do multiple compilation for
- // HVM-vs-PV guests, as PAE PV guests could get away without doing
- // subshadows.
- //
- sh_get_ref_l3_subshadow(v->arch.shadow_vtable, smfn);
- sh_pin_l3_subshadow(v->arch.shadow_vtable, smfn);
-#else
- sh_get_ref(smfn, 0);
- sh_pin(smfn);
+#if (CONFIG_PAGING_LEVELS == 3) && (GUEST_PAGING_LEVELS == 3)
#endif
-#if (SHADOW_PAGING_LEVELS == 3) && (GUEST_PAGING_LEVELS == 3)
- // PAE 3-on-3 shadows have to keep track of which vcpu's are using
- // which l3 subshadow, in order handle the SHADOW_SET_L3PAE_RECOPY
- // case from validate_gl3e(). Search for SHADOW_SET_L3PAE_RECOPY
- // in the code for more info.
- //
- {
- struct pae_l3_bookkeeping *info =
- sl3p_to_info(v->arch.shadow_vtable);
- ASSERT(!test_bit(v->vcpu_id, &info->vcpus));
- set_bit(v->vcpu_id, &info->vcpus);
- }
+ ///
+ /// v->arch.shadow.l3table
+ ///
+#if SHADOW_PAGING_LEVELS == 3
+ {
+ mfn_t smfn;
+ int i;
+ for ( i = 0; i < 4; i++ )
+ {
+#if GUEST_PAGING_LEVELS == 2
+ /* 2-on-3: make a PAE l3 that points at the four-page l2 */
+ smfn = _mfn(pagetable_get_pfn(v->arch.shadow_table[0]) + i);
+#else
+ /* 3-on-3: make a PAE l3 that points at the four l2 pages */
+ smfn = pagetable_get_mfn(v->arch.shadow_table[i]);
#endif
+ v->arch.shadow.l3table[i] =
+ (mfn_x(smfn) == 0)
+ ? shadow_l3e_empty()
+ : shadow_l3e_from_mfn(smfn, _PAGE_PRESENT);
+ }
+ }
+#endif /* SHADOW_PAGING_LEVELS == 3 */
- debugtrace_printk("%s cr3 gmfn=%05lx smfn=%05lx\n",
- __func__, gmfn, smfn);
///
- /// v->arch.cr3 and, if appropriate, v->arch.hvm_vcpu.hw_cr3
+ /// v->arch.cr3
///
if ( shadow_mode_external(d) )
{
- ASSERT(hvm_guest(v));
make_cr3(v, pagetable_get_pfn(v->arch.monitor_table));
-
-#if (GUEST_PAGING_LEVELS == 2) && (SHADOW_PAGING_LEVELS != 2)
-#if SHADOW_PAGING_LEVELS != 3
-#error unexpected combination of GUEST and SHADOW paging levels
-#endif
- /* 2-on-3: make a PAE l3 table that points at the four-page l2 */
- {
- mfn_t smfn = pagetable_get_mfn(v->arch.shadow_table);
- int i;
-
- ASSERT(v->arch.hvm_vcpu.hw_cr3 ==
- virt_to_maddr(v->arch.hvm_vcpu.hvm_lowmem_l3tab));
- for (i = 0; i < 4; i++)
- {
- v->arch.hvm_vcpu.hvm_lowmem_l3tab[i] =
- shadow_l3e_from_mfn(_mfn(mfn_x(smfn)+i), _PAGE_PRESENT);
- }
- }
-#elif (GUEST_PAGING_LEVELS == 3) && (SHADOW_PAGING_LEVELS == 3)
- /* 3-on-3: copy the shadow l3 to slots that are below 4GB.
- * If paging is disabled, clear l3e reserved bits; otherwise
- * remove entries that have reserved bits set. */
- v->arch.hvm_vcpu.hw_cr3 =
- hvm_pae_copy_root(v, v->arch.shadow_vtable,
- !shadow_vcpu_mode_translate(v));
-#else
- /* 2-on-2 or 4-on-4: just put the shadow top-level into cr3 */
- v->arch.hvm_vcpu.hw_cr3 =
- pagetable_get_paddr(v->arch.shadow_table);
-#endif
}
else // not shadow_mode_external...
{
/* We don't support PV except guest == shadow == config levels */
BUG_ON(GUEST_PAGING_LEVELS != SHADOW_PAGING_LEVELS);
- make_cr3(v, pagetable_get_pfn(v->arch.shadow_table));
+#if SHADOW_PAGING_LEVELS == 3
+ /* 2-on-3 or 3-on-3: Use the PAE shadow l3 table we just fabricated.
+ * Don't use make_cr3 because (a) we know it's below 4GB, and
+ * (b) it's not necessarily page-aligned, and make_cr3 takes a pfn */
+ ASSERT(virt_to_maddr(&v->arch.shadow.l3table) <= 0xffffffe0ULL);
+ v->arch.cr3 = virt_to_maddr(&v->arch.shadow.l3table);
+#else
+ /* 2-on-2 or 4-on-4: Just use the shadow top-level directly */
+ make_cr3(v, pagetable_get_pfn(v->arch.shadow_table[0]));
+#endif
+ }
+
+
+ ///
+ /// v->arch.hvm_vcpu.hw_cr3
+ ///
+ if ( shadow_mode_external(d) )
+ {
+ ASSERT(is_hvm_domain(d));
+#if SHADOW_PAGING_LEVELS == 3
+ /* 2-on-3 or 3-on-3: Use the PAE shadow l3 table we just fabricated */
+ v->arch.hvm_vcpu.hw_cr3 = virt_to_maddr(&v->arch.shadow.l3table);
+#else
+ /* 2-on-2 or 4-on-4: Just use the shadow top-level directly */
+ v->arch.hvm_vcpu.hw_cr3 = pagetable_get_paddr(v->arch.shadow_table[0]);
+#endif
}
/* Fix up the linear pagetable mappings */
@@ -3839,26 +3588,25 @@ static int sh_guess_wrmap(struct vcpu *v, unsigned long vaddr, mfn_t gmfn)
{
shadow_l1e_t sl1e, *sl1p;
shadow_l2e_t *sl2p;
-#if GUEST_PAGING_LEVELS >= 3
+#if SHADOW_PAGING_LEVELS >= 3
shadow_l3e_t *sl3p;
-#if GUEST_PAGING_LEVELS >= 4
+#if SHADOW_PAGING_LEVELS >= 4
shadow_l4e_t *sl4p;
#endif
#endif
mfn_t sl1mfn;
-
+ int r;
/* Carefully look in the shadow linear map for the l1e we expect */
- if ( v->arch.shadow_vtable == NULL ) return 0;
-#if GUEST_PAGING_LEVELS >= 4
+#if SHADOW_PAGING_LEVELS >= 4
sl4p = sh_linear_l4_table(v) + shadow_l4_linear_offset(vaddr);
if ( !(shadow_l4e_get_flags(*sl4p) & _PAGE_PRESENT) )
return 0;
sl3p = sh_linear_l3_table(v) + shadow_l3_linear_offset(vaddr);
if ( !(shadow_l3e_get_flags(*sl3p) & _PAGE_PRESENT) )
return 0;
-#elif GUEST_PAGING_LEVELS == 3
- sl3p = ((shadow_l3e_t *) v->arch.shadow_vtable)
+#elif SHADOW_PAGING_LEVELS == 3
+ sl3p = ((shadow_l3e_t *) v->arch.shadow.l3table)
+ shadow_l3_linear_offset(vaddr);
if ( !(shadow_l3e_get_flags(*sl3p) & _PAGE_PRESENT) )
return 0;
@@ -3876,7 +3624,8 @@ static int sh_guess_wrmap(struct vcpu *v, unsigned long vaddr, mfn_t gmfn)
/* Found it! Need to remove its write permissions. */
sl1mfn = shadow_l2e_get_mfn(*sl2p);
sl1e = shadow_l1e_remove_flags(sl1e, _PAGE_RW);
- shadow_set_l1e(v, sl1p, sl1e, sl1mfn);
+ r = shadow_set_l1e(v, sl1p, sl1e, sl1mfn);
+ ASSERT( !(r & SHADOW_SET_ERROR) );
return 1;
}
#endif
@@ -3887,6 +3636,7 @@ int sh_remove_write_access(struct vcpu *v, mfn_t sl1mfn, mfn_t readonly_mfn)
shadow_l1e_t *sl1e;
int done = 0;
int flags;
+ mfn_t base_sl1mfn = sl1mfn; /* Because sl1mfn changes in the foreach */
SHADOW_FOREACH_L1E(sl1mfn, sl1e, 0, done,
{
@@ -3895,7 +3645,12 @@ int sh_remove_write_access(struct vcpu *v, mfn_t sl1mfn, mfn_t readonly_mfn)
&& (flags & _PAGE_RW)
&& (mfn_x(shadow_l1e_get_mfn(*sl1e)) == mfn_x(readonly_mfn)) )
{
- shadow_set_l1e(v, sl1e, shadow_l1e_empty(), sl1mfn);
+ shadow_l1e_t ro_sl1e = shadow_l1e_remove_flags(*sl1e, _PAGE_RW);
+ (void) shadow_set_l1e(v, sl1e, ro_sl1e, sl1mfn);
+#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
+ /* Remember the last shadow that we shot a writeable mapping in */
+ v->arch.shadow.last_writeable_pte_smfn = mfn_x(base_sl1mfn);
+#endif
if ( (mfn_to_page(readonly_mfn)->u.inuse.type_info
& PGT_count_mask) == 0 )
/* This breaks us cleanly out of the FOREACH macro */
@@ -3919,7 +3674,7 @@ int sh_remove_all_mappings(struct vcpu *v, mfn_t sl1mfn, mfn_t target_mfn)
if ( (flags & _PAGE_PRESENT)
&& (mfn_x(shadow_l1e_get_mfn(*sl1e)) == mfn_x(target_mfn)) )
{
- shadow_set_l1e(v, sl1e, shadow_l1e_empty(), sl1mfn);
+ (void) shadow_set_l1e(v, sl1e, shadow_l1e_empty(), sl1mfn);
if ( (mfn_to_page(target_mfn)->count_info & PGC_count_mask) == 0 )
/* This breaks us cleanly out of the FOREACH macro */
done = 1;
@@ -3934,22 +3689,20 @@ int sh_remove_all_mappings(struct vcpu *v, mfn_t sl1mfn, mfn_t target_mfn)
void sh_clear_shadow_entry(struct vcpu *v, void *ep, mfn_t smfn)
/* Blank out a single shadow entry */
{
- switch (mfn_to_page(smfn)->count_info & PGC_SH_type_mask)
+ switch ( mfn_to_shadow_page(smfn)->type )
{
- case PGC_SH_l1_shadow:
- shadow_set_l1e(v, ep, shadow_l1e_empty(), smfn); break;
- case PGC_SH_l2_shadow:
+ case SH_type_l1_shadow:
+ (void) shadow_set_l1e(v, ep, shadow_l1e_empty(), smfn); break;
+ case SH_type_l2_shadow:
#if GUEST_PAGING_LEVELS == 3
- case PGC_SH_l2h_shadow:
+ case SH_type_l2h_shadow:
#endif
- shadow_set_l2e(v, ep, shadow_l2e_empty(), smfn); break;
-#if GUEST_PAGING_LEVELS >= 3
- case PGC_SH_l3_shadow:
- shadow_set_l3e(v, ep, shadow_l3e_empty(), smfn); break;
+ (void) shadow_set_l2e(v, ep, shadow_l2e_empty(), smfn); break;
#if GUEST_PAGING_LEVELS >= 4
- case PGC_SH_l4_shadow:
- shadow_set_l4e(v, ep, shadow_l4e_empty(), smfn); break;
-#endif
+ case SH_type_l3_shadow:
+ (void) shadow_set_l3e(v, ep, shadow_l3e_empty(), smfn); break;
+ case SH_type_l4_shadow:
+ (void) shadow_set_l4e(v, ep, shadow_l4e_empty(), smfn); break;
#endif
default: BUG(); /* Called with the wrong kind of shadow. */
}
@@ -3971,8 +3724,8 @@ int sh_remove_l1_shadow(struct vcpu *v, mfn_t sl2mfn, mfn_t sl1mfn)
if ( (flags & _PAGE_PRESENT)
&& (mfn_x(shadow_l2e_get_mfn(*sl2e)) == mfn_x(sl1mfn)) )
{
- shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
- if ( (mfn_to_page(sl1mfn)->count_info & PGC_SH_type_mask) == 0 )
+ (void) shadow_set_l2e(v, sl2e, shadow_l2e_empty(), sl2mfn);
+ if ( mfn_to_shadow_page(sl1mfn)->type == 0 )
/* This breaks us cleanly out of the FOREACH macro */
done = 1;
}
@@ -3980,7 +3733,7 @@ int sh_remove_l1_shadow(struct vcpu *v, mfn_t sl2mfn, mfn_t sl1mfn)
return done;
}
-#if GUEST_PAGING_LEVELS >= 3
+#if GUEST_PAGING_LEVELS >= 4
int sh_remove_l2_shadow(struct vcpu *v, mfn_t sl3mfn, mfn_t sl2mfn)
/* Remove all mappings of this l2 shadow from this l3 shadow */
{
@@ -3994,8 +3747,8 @@ int sh_remove_l2_shadow(struct vcpu *v, mfn_t sl3mfn, mfn_t sl2mfn)
if ( (flags & _PAGE_PRESENT)
&& (mfn_x(shadow_l3e_get_mfn(*sl3e)) == mfn_x(sl2mfn)) )
{
- shadow_set_l3e(v, sl3e, shadow_l3e_empty(), sl3mfn);
- if ( (mfn_to_page(sl2mfn)->count_info & PGC_SH_type_mask) == 0 )
+ (void) shadow_set_l3e(v, sl3e, shadow_l3e_empty(), sl3mfn);
+ if ( mfn_to_shadow_page(sl2mfn)->type == 0 )
/* This breaks us cleanly out of the FOREACH macro */
done = 1;
}
@@ -4003,7 +3756,6 @@ int sh_remove_l2_shadow(struct vcpu *v, mfn_t sl3mfn, mfn_t sl2mfn)
return done;
}
-#if GUEST_PAGING_LEVELS >= 4
int sh_remove_l3_shadow(struct vcpu *v, mfn_t sl4mfn, mfn_t sl3mfn)
/* Remove all mappings of this l3 shadow from this l4 shadow */
{
@@ -4017,8 +3769,8 @@ int sh_remove_l3_shadow(struct vcpu *v, mfn_t sl4mfn, mfn_t sl3mfn)
if ( (flags & _PAGE_PRESENT)
&& (mfn_x(shadow_l4e_get_mfn(*sl4e)) == mfn_x(sl3mfn)) )
{
- shadow_set_l4e(v, sl4e, shadow_l4e_empty(), sl4mfn);
- if ( (mfn_to_page(sl3mfn)->count_info & PGC_SH_type_mask) == 0 )
+ (void) shadow_set_l4e(v, sl4e, shadow_l4e_empty(), sl4mfn);
+ if ( mfn_to_shadow_page(sl3mfn)->type == 0 )
/* This breaks us cleanly out of the FOREACH macro */
done = 1;
}
@@ -4026,7 +3778,6 @@ int sh_remove_l3_shadow(struct vcpu *v, mfn_t sl4mfn, mfn_t sl3mfn)
return done;
}
#endif /* 64bit guest */
-#endif /* PAE guest */
/**************************************************************************/
/* Handling HVM guest writes to pagetables */
@@ -4045,7 +3796,7 @@ static inline void * emulate_map_dest(struct vcpu *v,
mfn_t mfn;
guest_walk_tables(v, vaddr, &gw, 1);
- flags = accumulate_guest_flags(&gw);
+ flags = accumulate_guest_flags(v, &gw);
gfn = guest_l1e_get_gfn(gw.eff_l1e);
mfn = vcpu_gfn_to_mfn(v, gfn);
sh_audit_gw(v, &gw);
@@ -4059,13 +3810,10 @@ static inline void * emulate_map_dest(struct vcpu *v,
v->arch.shadow.propagate_fault = 1;
return NULL;
}
-
- if ( !valid_mfn(mfn) )
- {
- /* Attempted a write to a bad gfn. This should never happen:
- * after all, we're here because this write is to a page table. */
- BUG();
- }
+
+ /* Attempted a write to a bad gfn? This should never happen:
+ * after all, we're here because this write is to a page table. */
+ BUG_ON(!mfn_valid(mfn));
ASSERT(sh_mfn_is_a_page_table(mfn));
*mfnp = mfn;
@@ -4076,27 +3824,26 @@ int
sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src,
u32 bytes, struct x86_emulate_ctxt *ctxt)
{
+ mfn_t mfn;
+ void *addr;
+
+ if ( vaddr & (bytes-1) )
+ return X86EMUL_UNHANDLEABLE;
+
ASSERT(shadow_lock_is_acquired(v->domain));
- while ( bytes > 0 )
- {
- mfn_t mfn;
- int bytes_on_page;
- void *addr;
-
- bytes_on_page = PAGE_SIZE - (vaddr & ~PAGE_MASK);
- if ( bytes_on_page > bytes )
- bytes_on_page = bytes;
-
- if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
- memcpy(addr, src, bytes_on_page);
- shadow_validate_guest_pt_write(v, mfn, addr, bytes_on_page);
- bytes -= bytes_on_page;
- /* If we are writing zeros to this page, might want to unshadow */
- if ( *(u8 *)addr == 0 )
- check_for_early_unshadow(v, mfn);
- sh_unmap_domain_page(addr);
- }
+ ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE);
+
+ if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL )
+ return X86EMUL_PROPAGATE_FAULT;
+
+ memcpy(addr, src, bytes);
+ shadow_validate_guest_pt_write(v, mfn, addr, bytes);
+
+ /* If we are writing zeros to this page, might want to unshadow */
+ if ( likely(bytes >= 4) && (*(u32 *)addr == 0) )
+ check_for_early_unshadow(v, mfn);
+
+ sh_unmap_domain_page(addr);
shadow_audit_tables(v);
return X86EMUL_CONTINUE;
}
@@ -4112,12 +3859,15 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
int rv = X86EMUL_CONTINUE;
ASSERT(shadow_lock_is_acquired(v->domain));
- ASSERT(bytes <= sizeof (unsigned long));
+ ASSERT(bytes <= sizeof(unsigned long));
+
+ if ( vaddr & (bytes-1) )
+ return X86EMUL_UNHANDLEABLE;
if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL )
return X86EMUL_PROPAGATE_FAULT;
- switch (bytes)
+ switch ( bytes )
{
case 1: prev = cmpxchg(((u8 *)addr), old, new); break;
case 2: prev = cmpxchg(((u16 *)addr), old, new); break;
@@ -4128,7 +3878,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
prev = ~old;
}
- if ( (prev == old) )
+ if ( prev == old )
shadow_validate_guest_pt_write(v, mfn, addr, bytes);
else
rv = X86EMUL_CMPXCHG_FAILED;
@@ -4138,12 +3888,11 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
vaddr, prev, old, new, *(unsigned long *)addr, bytes);
/* If we are writing zeros to this page, might want to unshadow */
- if ( *(u8 *)addr == 0 )
+ if ( likely(bytes >= 4) && (*(u32 *)addr == 0) )
check_for_early_unshadow(v, mfn);
sh_unmap_domain_page(addr);
shadow_audit_tables(v);
- check_for_early_unshadow(v, mfn);
return rv;
}
@@ -4160,6 +3909,9 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr,
ASSERT(shadow_lock_is_acquired(v->domain));
+ if ( vaddr & 7 )
+ return X86EMUL_UNHANDLEABLE;
+
if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL )
return X86EMUL_PROPAGATE_FAULT;
@@ -4167,18 +3919,17 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr,
new = (((u64) new_hi) << 32) | (u64) new_lo;
prev = cmpxchg(((u64 *)addr), old, new);
- if ( (prev == old) )
+ if ( prev == old )
shadow_validate_guest_pt_write(v, mfn, addr, 8);
else
rv = X86EMUL_CMPXCHG_FAILED;
/* If we are writing zeros to this page, might want to unshadow */
- if ( *(u8 *)addr == 0 )
+ if ( *(u32 *)addr == 0 )
check_for_early_unshadow(v, mfn);
sh_unmap_domain_page(addr);
shadow_audit_tables(v);
- check_for_early_unshadow(v, mfn);
return rv;
}
@@ -4212,24 +3963,24 @@ static char * sh_audit_flags(struct vcpu *v, int level,
{
if ( (sflags & _PAGE_PRESENT) && !(gflags & _PAGE_PRESENT) )
return "shadow is present but guest is not present";
- if ( (sflags & _PAGE_GLOBAL) && !hvm_guest(v) )
+ if ( (sflags & _PAGE_GLOBAL) && !is_hvm_vcpu(v) )
return "global bit set in PV shadow";
- if ( (level == 1 || (level == 2 && (gflags & _PAGE_PSE)))
- && ((sflags & _PAGE_DIRTY) && !(gflags & _PAGE_DIRTY)) )
- return "dirty bit not propagated";
if ( level == 2 && (sflags & _PAGE_PSE) )
return "PS bit set in shadow";
#if SHADOW_PAGING_LEVELS == 3
if ( level == 3 ) return NULL; /* All the other bits are blank in PAEl3 */
#endif
+ if ( (sflags & _PAGE_PRESENT) && !(gflags & _PAGE_ACCESSED) )
+ return "accessed bit not propagated";
+ if ( (level == 1 || (level == 2 && (gflags & _PAGE_PSE)))
+ && ((sflags & _PAGE_RW) && !(gflags & _PAGE_DIRTY)) )
+ return "dirty bit not propagated";
if ( (sflags & _PAGE_USER) != (gflags & _PAGE_USER) )
return "user/supervisor bit does not match";
if ( (sflags & _PAGE_NX_BIT) != (gflags & _PAGE_NX_BIT) )
return "NX bit does not match";
if ( (sflags & _PAGE_RW) && !(gflags & _PAGE_RW) )
return "shadow grants write access but guest does not";
- if ( (sflags & _PAGE_ACCESSED) && !(gflags & _PAGE_ACCESSED) )
- return "accessed bit not propagated";
return NULL;
}
@@ -4257,25 +4008,48 @@ int sh_audit_l1_table(struct vcpu *v, mfn_t sl1mfn, mfn_t x)
gfn_t gfn;
char *s;
int done = 0;
-
+
/* Follow the backpointer */
- gl1mfn = _mfn(mfn_to_page(sl1mfn)->u.inuse.type_info);
+ gl1mfn = _mfn(mfn_to_shadow_page(sl1mfn)->backpointer);
gl1e = gp = sh_map_domain_page(gl1mfn);
SHADOW_FOREACH_L1E(sl1mfn, sl1e, &gl1e, done, {
- s = sh_audit_flags(v, 1, guest_l1e_get_flags(*gl1e),
- shadow_l1e_get_flags(*sl1e));
- if ( s ) AUDIT_FAIL(1, "%s", s);
-
- if ( SHADOW_AUDIT & SHADOW_AUDIT_ENTRIES_MFNS )
+ if ( sh_l1e_is_magic(*sl1e) )
{
- gfn = guest_l1e_get_gfn(*gl1e);
- mfn = shadow_l1e_get_mfn(*sl1e);
- gmfn = audit_gfn_to_mfn(v, gfn, gl1mfn);
- if ( mfn_x(gmfn) != mfn_x(mfn) )
- AUDIT_FAIL(1, "bad translation: gfn %" SH_PRI_gfn
- " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn "\n",
- gfn_x(gfn), mfn_x(gmfn), mfn_x(mfn));
+#if (SHADOW_OPTIMIZATIONS & SHOPT_FAST_FAULT_PATH) && SHADOW_PAGING_LEVELS > 2
+ if ( sh_l1e_is_gnp(*sl1e) )
+ {
+ if ( guest_l1e_get_flags(*gl1e) & _PAGE_PRESENT )
+ AUDIT_FAIL(1, "shadow is GNP magic but guest is present");
+ }
+ else
+ {
+ ASSERT(sh_l1e_is_mmio(*sl1e));
+ gfn = sh_l1e_mmio_get_gfn(*sl1e);
+ if ( gfn_x(gfn) != gfn_x(guest_l1e_get_gfn(*gl1e)) )
+ AUDIT_FAIL(1, "shadow MMIO gfn is %" SH_PRI_gfn
+ " but guest gfn is %" SH_PRI_gfn,
+ gfn_x(gfn),
+ gfn_x(guest_l1e_get_gfn(*gl1e)));
+ }
+#endif
+ }
+ else
+ {
+ s = sh_audit_flags(v, 1, guest_l1e_get_flags(*gl1e),
+ shadow_l1e_get_flags(*sl1e));
+ if ( s ) AUDIT_FAIL(1, "%s", s);
+
+ if ( SHADOW_AUDIT & SHADOW_AUDIT_ENTRIES_MFNS )
+ {
+ gfn = guest_l1e_get_gfn(*gl1e);
+ mfn = shadow_l1e_get_mfn(*sl1e);
+ gmfn = audit_gfn_to_mfn(v, gfn, gl1mfn);
+ if ( mfn_x(gmfn) != mfn_x(mfn) )
+ AUDIT_FAIL(1, "bad translation: gfn %" SH_PRI_gfn
+ " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn,
+ gfn_x(gfn), mfn_x(gmfn), mfn_x(mfn));
+ }
}
});
sh_unmap_domain_page(gp);
@@ -4298,7 +4072,8 @@ int sh_audit_fl1_table(struct vcpu *v, mfn_t sl1mfn, mfn_t x)
if ( !(f == 0
|| f == (_PAGE_PRESENT|_PAGE_USER|_PAGE_RW|
_PAGE_ACCESSED|_PAGE_DIRTY)
- || f == (_PAGE_PRESENT|_PAGE_USER|_PAGE_ACCESSED|_PAGE_DIRTY)) )
+ || f == (_PAGE_PRESENT|_PAGE_USER|_PAGE_ACCESSED|_PAGE_DIRTY)
+ || sh_l1e_is_magic(*sl1e)) )
AUDIT_FAIL(1, "fl1e has bad flags");
});
return 0;
@@ -4317,7 +4092,7 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
#endif
/* Follow the backpointer */
- gl2mfn = _mfn(mfn_to_page(sl2mfn)->u.inuse.type_info);
+ gl2mfn = _mfn(mfn_to_shadow_page(sl2mfn)->backpointer);
gl2e = gp = sh_map_domain_page(gl2mfn);
SHADOW_FOREACH_L2E(sl2mfn, sl2e, &gl2e, done, xen_mappings, {
@@ -4332,11 +4107,11 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
gmfn = (guest_l2e_get_flags(*gl2e) & _PAGE_PSE)
? get_fl1_shadow_status(v, gfn)
: get_shadow_status(v, audit_gfn_to_mfn(v, gfn, gl2mfn),
- PGC_SH_l1_shadow);
+ SH_type_l1_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(2, "bad translation: gfn %" SH_PRI_gfn
" (--> %" SH_PRI_mfn ")"
- " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn "\n",
+ " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn,
gfn_x(gfn),
(guest_l2e_get_flags(*gl2e) & _PAGE_PSE) ? 0
: mfn_x(audit_gfn_to_mfn(v, gfn, gl2mfn)),
@@ -4347,7 +4122,7 @@ int sh_audit_l2_table(struct vcpu *v, mfn_t sl2mfn, mfn_t x)
return 0;
}
-#if GUEST_PAGING_LEVELS >= 3
+#if GUEST_PAGING_LEVELS >= 4
int sh_audit_l3_table(struct vcpu *v, mfn_t sl3mfn, mfn_t x)
{
guest_l3e_t *gl3e, *gp;
@@ -4358,7 +4133,7 @@ int sh_audit_l3_table(struct vcpu *v, mfn_t sl3mfn, mfn_t x)
int done = 0;
/* Follow the backpointer */
- gl3mfn = _mfn(mfn_to_page(sl3mfn)->u.inuse.type_info);
+ gl3mfn = _mfn(mfn_to_shadow_page(sl3mfn)->backpointer);
gl3e = gp = sh_map_domain_page(gl3mfn);
SHADOW_FOREACH_L3E(sl3mfn, sl3e, &gl3e, done, {
@@ -4374,20 +4149,18 @@ int sh_audit_l3_table(struct vcpu *v, mfn_t sl3mfn, mfn_t x)
(GUEST_PAGING_LEVELS == 3
&& !shadow_mode_external(v->domain)
&& (guest_index(gl3e) % 4) == 3)
- ? PGC_SH_l2h_pae_shadow
- : PGC_SH_l2_shadow);
+ ? SH_type_l2h_pae_shadow
+ : SH_type_l2_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(3, "bad translation: gfn %" SH_PRI_gfn
- " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn "\n",
+ " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn,
gfn_x(gfn), mfn_x(gmfn), mfn_x(mfn));
}
});
sh_unmap_domain_page(gp);
return 0;
}
-#endif /* GUEST_PAGING_LEVELS >= 3 */
-#if GUEST_PAGING_LEVELS >= 4
int sh_audit_l4_table(struct vcpu *v, mfn_t sl4mfn, mfn_t x)
{
guest_l4e_t *gl4e, *gp;
@@ -4399,7 +4172,7 @@ int sh_audit_l4_table(struct vcpu *v, mfn_t sl4mfn, mfn_t x)
int xen_mappings = !shadow_mode_external(v->domain);
/* Follow the backpointer */
- gl4mfn = _mfn(mfn_to_page(sl4mfn)->u.inuse.type_info);
+ gl4mfn = _mfn(mfn_to_shadow_page(sl4mfn)->backpointer);
gl4e = gp = sh_map_domain_page(gl4mfn);
SHADOW_FOREACH_L4E(sl4mfn, sl4e, &gl4e, done, xen_mappings,
{
@@ -4412,10 +4185,10 @@ int sh_audit_l4_table(struct vcpu *v, mfn_t sl4mfn, mfn_t x)
gfn = guest_l4e_get_gfn(*gl4e);
mfn = shadow_l4e_get_mfn(*sl4e);
gmfn = get_shadow_status(v, audit_gfn_to_mfn(v, gfn, gl4mfn),
- PGC_SH_l3_shadow);
+ SH_type_l3_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(4, "bad translation: gfn %" SH_PRI_gfn
- " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn "\n",
+ " --> %" SH_PRI_mfn " != mfn %" SH_PRI_mfn,
gfn_x(gfn), mfn_x(gmfn), mfn_x(mfn));
}
});
@@ -4449,6 +4222,8 @@ struct shadow_paging_mode sh_paging_mode = {
.x86_emulate_cmpxchg8b = sh_x86_emulate_cmpxchg8b,
.make_monitor_table = sh_make_monitor_table,
.destroy_monitor_table = sh_destroy_monitor_table,
+ .guest_map_l1e = sh_guest_map_l1e,
+ .guest_get_eff_l1e = sh_guest_get_eff_l1e,
#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
.guess_wrmap = sh_guess_wrmap,
#endif
diff --git a/xen/arch/x86/mm/shadow/multi.h b/xen/arch/x86/mm/shadow/multi.h
index 26a4675a71..2cc61b830f 100644
--- a/xen/arch/x86/mm/shadow/multi.h
+++ b/xen/arch/x86/mm/shadow/multi.h
@@ -50,10 +50,6 @@ extern void
SHADOW_INTERNAL_NAME(sh_destroy_l4_shadow, SHADOW_LEVELS, GUEST_LEVELS)(
struct vcpu *v, mfn_t smfn);
-extern void
-SHADOW_INTERNAL_NAME(sh_unpin_all_l3_subshadows, 3, 3)
- (struct vcpu *v, mfn_t smfn);
-
extern void
SHADOW_INTERNAL_NAME(sh_unhook_32b_mappings, SHADOW_LEVELS, GUEST_LEVELS)
(struct vcpu *v, mfn_t sl2mfn);
@@ -103,6 +99,13 @@ SHADOW_INTERNAL_NAME(sh_audit_l4_table, SHADOW_LEVELS, GUEST_LEVELS)
(struct vcpu *v, mfn_t sl4mfn, mfn_t x);
#endif
+extern void *
+SHADOW_INTERNAL_NAME(sh_guest_map_l1e, CONFIG_PAGING_LEVELS, CONFIG_PAGING_LEVELS)
+ (struct vcpu *v, unsigned long va, unsigned long *gl1mfn);
+extern void
+SHADOW_INTERNAL_NAME(sh_guest_get_eff_l1e, CONFIG_PAGING_LEVELS, CONFIG_PAGING_LEVELS)
+ (struct vcpu *v, unsigned long va, void *eff_l1e);
+
#if SHADOW_LEVELS == GUEST_LEVELS
extern mfn_t
SHADOW_INTERNAL_NAME(sh_make_monitor_table, SHADOW_LEVELS, GUEST_LEVELS)
diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h
index eeb2d86342..61493b552d 100644
--- a/xen/arch/x86/mm/shadow/private.h
+++ b/xen/arch/x86/mm/shadow/private.h
@@ -33,111 +33,6 @@
/******************************************************************************
- * Definitions for the use of the "available" bits in the shadow PTEs.
- *
- * Review of the low 12 bits of a shadow page table entry:
- *
- * in a guest: in a shadow:
- * Bit 11: _PAGE_AVAIL2, aka _PAGE_GNTTAB
- * Bit 10: _PAGE_AVAIL1 _PAGE_SHADOW_RW ("SW" below)
- * Bit 9: _PAGE_AVAIL0 _PAGE_SHADOW_PRESENT ("SP" below)
- * Bit 8: _PAGE_GLOBAL _PAGE_SHADOW_MMIO ("MMIO" below),
- * aka _PAGE_SHADOW_GUEST_NOT_PRESENT
- * Bit 7: _PAGE_PSE, aka _PAGE_PAT
- * Bit 6: _PAGE_DIRTY
- * Bit 5: _PAGE_ACCESSED
- * Bit 4: _PAGE_PCD
- * Bit 3: _PAGE_PWT
- * Bit 2: _PAGE_USER
- * Bit 1: _PAGE_RW ("GW" below)
- * Bit 0: _PAGE_PRESENT ("GP" below)
- *
- * Given a guest entry, as shown below, we can expect the following in the
- * corresponding shadow entry:
- *
- * Guest entry Shadow entry Commentary
- * ----------- ---------------- ---------------------------------------------
- * Maps
- * GP GW IO GP SP GW SW MMIO
- * -- -- ---- -- -- -- -- ----
- * - - - 0 0 0 0 0 The guest entry has not yet been shadowed.
- * 0 - - 0 0 0 0 1 The guest entry is marked not-present.
- * 1 1 no ? 1 ? 1 0 Writable entry in the guest.
- * 1 0 no ? 1 0 0 0 Read-only entry in the guest.
- * 1 1 yes 0 1 ? 1 1 Writable MMIO mapping in the guest.
- * 1 0 yes 0 1 0 0 1 Read-only MMIO mapping in the guest.
- *
- * Normally, we would expect that GP=1 in the guest to imply GP=1 in the
- * shadow, and similarly for GW=1. However, various functionality that may be
- * implemented via the shadow can cause GP or GW to be cleared in such cases.
- * A & D bit emulation is a prime example of such functionality.
- *
- * If _PAGE_SHADOW_PRESENT is zero, then the _PAGE_PRESENT bit in that same
- * entry will always be zero, too.
-
- * Bit 11 is used in debug builds as the _PAGE_GNTTAB bit in PV guests. It is
- * currently available for random (ab)use in shadow entries.
- *
- * Bit 8 (the global bit) could be propagated from an HVM guest to the shadow,
- * but currently there is no benefit, as the guest's TLB is flushed on every
- * transition of CR3 anyway due to the HVM exit/re-entry.
- *
- * In shadow entries in which the _PAGE_SHADOW_PRESENT is set, bit 8 is used
- * as the _PAGE_SHADOW_MMIO bit. In such entries, if _PAGE_SHADOW_MMIO is
- * set, then the entry contains the *gfn* directly from the corresponding
- * guest entry (not an mfn!!).
- *
- * Bit 7 is set in a guest L2 to signify a superpage entry. The current
- * shadow code splinters superpage mappings into 512 or 1024 4K mappings; the
- * resulting shadow L1 table is called an FL1. Note that there is no guest
- * page that corresponds to an FL1.
- *
- * Bit 7 in a guest L1 is the PAT2 bit. Currently we do not support PAT in
- * this shadow code.
- *
- * Bit 6 is the dirty bit.
- *
- * Bit 5 is the accessed bit.
- *
- * Bit 4 is the cache disable bit. If set in a guest, the hardware is
- * supposed to refuse to cache anything found via this entry. It can be set
- * in an L4e, L3e, L2e, or L1e. This shadow code currently does not support
- * cache disable bits. They are silently ignored.
- *
- * Bit 4 is a guest L1 is also the PAT1 bit. Currently we do not support PAT
- * in this shadow code.
- *
- * Bit 3 is the cache write-thru bit. If set in a guest, the hardware is
- * supposed to use write-thru instead of write-back caching for anything found
- * via this entry. It can be set in an L4e, L3e, L2e, or L1e. This shadow
- * code currently does not support cache write-thru bits. They are silently
- * ignored.
- *
- * Bit 3 is a guest L1 is also the PAT0 bit. Currently we do not support PAT
- * in this shadow code.
- *
- * Bit 2 is the user bit.
- *
- * Bit 1 is the read-write bit.
- *
- * Bit 0 is the present bit.
- */
-
-// Copy of the _PAGE_RW bit from the guest's PTE, appropriately zero'ed by
-// the appropriate shadow rules.
-#define _PAGE_SHADOW_RW _PAGE_AVAIL1
-
-// Copy of the _PAGE_PRESENT bit from the guest's PTE
-#define _PAGE_SHADOW_PRESENT _PAGE_AVAIL0
-
-// The matching guest entry maps MMIO space
-#define _PAGE_SHADOW_MMIO _PAGE_GLOBAL
-
-// Shadow flags value used when the guest is not present
-#define _PAGE_SHADOW_GUEST_NOT_PRESENT _PAGE_GLOBAL
-
-
-/******************************************************************************
* Debug and error-message output
*/
#define SHADOW_PRINTK(_f, _a...) \
@@ -151,13 +46,13 @@
} while (0)
// The flags for use with SHADOW_DEBUG:
-#define SHADOW_DEBUG_PROPAGATE 0
-#define SHADOW_DEBUG_MAKE_SHADOW 0
-#define SHADOW_DEBUG_DESTROY_SHADOW 0
+#define SHADOW_DEBUG_PROPAGATE 1
+#define SHADOW_DEBUG_MAKE_SHADOW 1
+#define SHADOW_DEBUG_DESTROY_SHADOW 1
#define SHADOW_DEBUG_P2M 0
-#define SHADOW_DEBUG_A_AND_D 0
-#define SHADOW_DEBUG_EMULATE 0
-#define SHADOW_DEBUG_LOGDIRTY 1
+#define SHADOW_DEBUG_A_AND_D 1
+#define SHADOW_DEBUG_EMULATE 1
+#define SHADOW_DEBUG_LOGDIRTY 0
/******************************************************************************
@@ -178,77 +73,6 @@ extern void shadow_audit_p2m(struct domain *d);
/******************************************************************************
- * Mechanism for double-checking the optimized pagefault path: this
- * structure contains a record of actions taken by the fault handling
- * code. In paranoid mode, the fast-path code fills out one of these
- * structures (but doesn't take any actual action) and then the normal
- * path fills in another. When the fault handler finishes, the
- * two are compared */
-
-#ifdef SHADOW_OPTIMIZATION_PARANOIA
-
-typedef struct shadow_action_log sh_log_t;
-struct shadow_action_log {
- paddr_t ad[CONFIG_PAGING_LEVELS]; /* A & D bits propagated here */
- paddr_t mmio; /* Address of an mmio operation */
- int rv; /* Result of the fault handler */
-};
-
-/* There are two logs, one for the fast path, one for the normal path */
-enum sh_log_type { log_slow = 0, log_fast= 1 };
-
-/* Alloc and zero the logs */
-static inline void sh_init_log(struct vcpu *v)
-{
- if ( unlikely(!v->arch.shadow.action_log) )
- v->arch.shadow.action_log = xmalloc_array(sh_log_t, 2);
- ASSERT(v->arch.shadow.action_log);
- memset(v->arch.shadow.action_log, 0, 2 * sizeof (sh_log_t));
-}
-
-/* Log an A&D-bit update */
-static inline void sh_log_ad(struct vcpu *v, paddr_t e, unsigned int level)
-{
- v->arch.shadow.action_log[v->arch.shadow.action_index].ad[level] = e;
-}
-
-/* Log an MMIO address */
-static inline void sh_log_mmio(struct vcpu *v, paddr_t m)
-{
- v->arch.shadow.action_log[v->arch.shadow.action_index].mmio = m;
-}
-
-/* Log the result */
-static inline void sh_log_rv(struct vcpu *v, int rv)
-{
- v->arch.shadow.action_log[v->arch.shadow.action_index].rv = rv;
-}
-
-/* Set which mode we're in */
-static inline void sh_set_log_mode(struct vcpu *v, enum sh_log_type t)
-{
- v->arch.shadow.action_index = t;
-}
-
-/* Know not to take action, because we're only checking the mechanism */
-static inline int sh_take_no_action(struct vcpu *v)
-{
- return (v->arch.shadow.action_index == log_fast);
-}
-
-#else /* Non-paranoid mode: these logs do not exist */
-
-#define sh_init_log(_v) do { (void)(_v); } while(0)
-#define sh_set_log_mode(_v,_t) do { (void)(_v); } while(0)
-#define sh_log_ad(_v,_e,_l) do { (void)(_v),(void)(_e),(void)(_l); } while (0)
-#define sh_log_mmio(_v,_m) do { (void)(_v),(void)(_m); } while (0)
-#define sh_log_rv(_v,_r) do { (void)(_v),(void)(_r); } while (0)
-#define sh_take_no_action(_v) (((void)(_v)), 0)
-
-#endif /* SHADOW_OPTIMIZATION_PARANOIA */
-
-
-/******************************************************************************
* Macro for dealing with the naming of the internal names of the
* shadow code's external entry points.
*/
@@ -305,6 +129,129 @@ static inline int sh_take_no_action(struct vcpu *v)
#undef SHADOW_LEVELS
#endif /* CONFIG_PAGING_LEVELS == 4 */
+/******************************************************************************
+ * Page metadata for shadow pages.
+ */
+
+struct shadow_page_info
+{
+ union {
+ /* When in use, guest page we're a shadow of */
+ unsigned long backpointer;
+ /* When free, order of the freelist we're on */
+ unsigned int order;
+ };
+ union {
+ /* When in use, next shadow in this hash chain */
+ struct shadow_page_info *next_shadow;
+ /* When free, TLB flush time when freed */
+ u32 tlbflush_timestamp;
+ };
+ struct {
+ unsigned int type:4; /* What kind of shadow is this? */
+ unsigned int pinned:1; /* Is the shadow pinned? */
+ unsigned int logdirty:1; /* Was it made in log-dirty mode? */
+ unsigned int count:26; /* Reference count */
+ u32 mbz; /* Must be zero: this is where the owner
+ * field lives in a non-shadow page */
+ } __attribute__((packed));
+ union {
+ /* For unused shadow pages, a list of pages of this order;
+ * for pinnable shadows, if pinned, a list of other pinned shadows
+ * (see sh_type_is_pinnable() below for the definition of
+ * "pinnable" shadow types). */
+ struct list_head list;
+ /* For non-pinnable shadows, a higher entry that points at us */
+ paddr_t up;
+ };
+};
+
+/* The structure above *must* be the same size as a struct page_info
+ * from mm.h, since we'll be using the same space in the frametable.
+ * Also, the mbz field must line up with the owner field of normal
+ * pages, so they look properly like anonymous/xen pages. */
+static inline void shadow_check_page_struct_offsets(void) {
+ BUILD_BUG_ON(sizeof (struct shadow_page_info)
+ != sizeof (struct page_info));
+ BUILD_BUG_ON(offsetof(struct shadow_page_info, mbz)
+ != offsetof(struct page_info, u.inuse._domain));
+};
+
+/* Shadow type codes */
+#define SH_type_none (0U) /* on the shadow free list */
+#define SH_type_min_shadow (1U)
+#define SH_type_l1_32_shadow (1U) /* shadowing a 32-bit L1 guest page */
+#define SH_type_fl1_32_shadow (2U) /* L1 shadow for a 32b 4M superpage */
+#define SH_type_l2_32_shadow (3U) /* shadowing a 32-bit L2 guest page */
+#define SH_type_l1_pae_shadow (4U) /* shadowing a pae L1 page */
+#define SH_type_fl1_pae_shadow (5U) /* L1 shadow for pae 2M superpg */
+#define SH_type_l2_pae_shadow (6U) /* shadowing a pae L2-low page */
+#define SH_type_l2h_pae_shadow (7U) /* shadowing a pae L2-high page */
+#define SH_type_l1_64_shadow (8U) /* shadowing a 64-bit L1 page */
+#define SH_type_fl1_64_shadow (9U) /* L1 shadow for 64-bit 2M superpg */
+#define SH_type_l2_64_shadow (10U) /* shadowing a 64-bit L2 page */
+#define SH_type_l3_64_shadow (11U) /* shadowing a 64-bit L3 page */
+#define SH_type_l4_64_shadow (12U) /* shadowing a 64-bit L4 page */
+#define SH_type_max_shadow (12U)
+#define SH_type_p2m_table (13U) /* in use as the p2m table */
+#define SH_type_monitor_table (14U) /* in use as a monitor table */
+#define SH_type_unused (15U)
+
+/*
+ * What counts as a pinnable shadow?
+ */
+
+static inline int sh_type_is_pinnable(struct vcpu *v, unsigned int t)
+{
+ /* Top-level shadow types in each mode can be pinned, so that they
+ * persist even when not currently in use in a guest CR3 */
+ if ( t == SH_type_l2_32_shadow
+ || t == SH_type_l2_pae_shadow
+ || t == SH_type_l2h_pae_shadow
+ || t == SH_type_l4_64_shadow )
+ return 1;
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL)
+ /* Early 64-bit linux used three levels of pagetables for the guest
+ * and context switched by changing one l4 entry in a per-cpu l4
+ * page. When we're shadowing those kernels, we have to pin l3
+ * shadows so they don't just evaporate on every context switch.
+ * For all other guests, we'd rather use the up-pointer field in l3s. */
+ if ( unlikely((v->domain->arch.shadow.opt_flags & SHOPT_LINUX_L3_TOPLEVEL)
+ && CONFIG_PAGING_LEVELS >= 4
+ && t == SH_type_l3_64_shadow) )
+ return 1;
+#endif
+
+ /* Everything else is not pinnable, and can use the "up" pointer */
+ return 0;
+}
+
+/*
+ * Definitions for the shadow_flags field in page_info.
+ * These flags are stored on *guest* pages...
+ * Bits 1-13 are encodings for the shadow types.
+ */
+#define SHF_page_type_mask \
+ (((1u << (SH_type_max_shadow + 1u)) - 1u) - \
+ ((1u << SH_type_min_shadow) - 1u))
+
+#define SHF_L1_32 (1u << SH_type_l1_32_shadow)
+#define SHF_FL1_32 (1u << SH_type_fl1_32_shadow)
+#define SHF_L2_32 (1u << SH_type_l2_32_shadow)
+#define SHF_L1_PAE (1u << SH_type_l1_pae_shadow)
+#define SHF_FL1_PAE (1u << SH_type_fl1_pae_shadow)
+#define SHF_L2_PAE (1u << SH_type_l2_pae_shadow)
+#define SHF_L2H_PAE (1u << SH_type_l2h_pae_shadow)
+#define SHF_L1_64 (1u << SH_type_l1_64_shadow)
+#define SHF_FL1_64 (1u << SH_type_fl1_64_shadow)
+#define SHF_L2_64 (1u << SH_type_l2_64_shadow)
+#define SHF_L3_64 (1u << SH_type_l3_64_shadow)
+#define SHF_L4_64 (1u << SH_type_l4_64_shadow)
+
+/* Used for hysteresis when automatically unhooking mappings on fork/exit */
+#define SHF_unhooked_mappings (1u<<31)
+
/******************************************************************************
* Various function declarations
@@ -314,9 +261,11 @@ static inline int sh_take_no_action(struct vcpu *v)
extern struct x86_emulate_ops shadow_emulator_ops;
/* Hash table functions */
-mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, u8 t);
-void shadow_hash_insert(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn);
-void shadow_hash_delete(struct vcpu *v, unsigned long n, u8 t, mfn_t smfn);
+mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, unsigned int t);
+void shadow_hash_insert(struct vcpu *v,
+ unsigned long n, unsigned int t, mfn_t smfn);
+void shadow_hash_delete(struct vcpu *v,
+ unsigned long n, unsigned int t, mfn_t smfn);
/* shadow promotion */
void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type);
@@ -336,29 +285,39 @@ void shadow_convert_to_log_dirty(struct vcpu *v, mfn_t smfn);
* non-Xen mappings in this top-level shadow mfn */
void shadow_unhook_mappings(struct vcpu *v, mfn_t smfn);
-/* Re-sync copies of PAE shadow L3 tables if they have been changed */
-void sh_pae_recopy(struct domain *d);
-
/* Install the xen mappings in various flavours of shadow */
void sh_install_xen_entries_in_l4(struct vcpu *v, mfn_t gl4mfn, mfn_t sl4mfn);
void sh_install_xen_entries_in_l2h(struct vcpu *v, mfn_t sl2hmfn);
-void sh_install_xen_entries_in_l3(struct vcpu *v, mfn_t gl3mfn, mfn_t sl3mfn);
void sh_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn);
/******************************************************************************
+ * Flags used in the return value of the shadow_set_lXe() functions...
+ */
+
+/* We actually wrote something new to the shadow */
+#define SHADOW_SET_CHANGED 0x1
+/* Caller should flush TLBs to clear the old entry */
+#define SHADOW_SET_FLUSH 0x2
+/* Something went wrong: the shadow entry was invalid or refcount failed */
+#define SHADOW_SET_ERROR 0x4
+
+
+/******************************************************************************
* MFN/page-info handling
*/
// Override mfn_to_page from asm/page.h, which was #include'd above,
// in order to make it work with our mfn type.
#undef mfn_to_page
-#define mfn_to_page(_mfn) (frame_table + mfn_x(_mfn))
+#define mfn_to_page(_m) (frame_table + mfn_x(_m))
+#define mfn_to_shadow_page(_m) ((struct shadow_page_info *)mfn_to_page(_m))
// Override page_to_mfn from asm/page.h, which was #include'd above,
// in order to make it work with our mfn type.
#undef page_to_mfn
#define page_to_mfn(_pg) (_mfn((_pg) - frame_table))
+#define shadow_page_to_mfn(_spg) (page_to_mfn((struct page_info *)_spg))
// Override mfn_valid from asm/page.h, which was #include'd above,
// in order to make it work with our mfn type.
@@ -369,28 +328,24 @@ void sh_install_xen_entries_in_l2(struct vcpu *v, mfn_t gl2mfn, mfn_t sl2mfn);
static inline void *
sh_map_domain_page(mfn_t mfn)
{
- /* XXX Using the monitor-table as a map will happen here */
return map_domain_page(mfn_x(mfn));
}
static inline void
sh_unmap_domain_page(void *p)
{
- /* XXX Using the monitor-table as a map will happen here */
unmap_domain_page(p);
}
static inline void *
sh_map_domain_page_global(mfn_t mfn)
{
- /* XXX Using the monitor-table as a map will happen here */
return map_domain_page_global(mfn_x(mfn));
}
static inline void
sh_unmap_domain_page_global(void *p)
{
- /* XXX Using the monitor-table as a map will happen here */
unmap_domain_page_global(p);
}
@@ -419,7 +374,7 @@ sh_mfn_is_a_page_table(mfn_t gmfn)
struct domain *owner;
unsigned long type_info;
- if ( !valid_mfn(gmfn) )
+ if ( !mfn_valid(gmfn) )
return 0;
owner = page_get_owner(page);
@@ -433,38 +388,41 @@ sh_mfn_is_a_page_table(mfn_t gmfn)
/**************************************************************************/
-/* Shadow-page refcounting. See comment in shadow-common.c about the
- * use of struct page_info fields for shadow pages */
+/* Shadow-page refcounting. */
void sh_destroy_shadow(struct vcpu *v, mfn_t smfn);
/* Increase the refcount of a shadow page. Arguments are the mfn to refcount,
* and the physical address of the shadow entry that holds the ref (or zero
- * if the ref is held by something else) */
-static inline void sh_get_ref(mfn_t smfn, paddr_t entry_pa)
+ * if the ref is held by something else).
+ * Returns 0 for failure, 1 for success. */
+static inline int sh_get_ref(struct vcpu *v, mfn_t smfn, paddr_t entry_pa)
{
u32 x, nx;
- struct page_info *page = mfn_to_page(smfn);
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
ASSERT(mfn_valid(smfn));
- x = page->count_info & PGC_SH_count_mask;
+ x = sp->count;
nx = x + 1;
- if ( unlikely(nx & ~PGC_SH_count_mask) )
+ if ( unlikely(nx >= 1U<<26) )
{
SHADOW_PRINTK("shadow ref overflow, gmfn=%" PRtype_info " smfn=%lx\n",
- page->u.inuse.type_info, mfn_x(smfn));
- domain_crash_synchronous();
+ sp->backpointer, mfn_x(smfn));
+ return 0;
}
/* Guarded by the shadow lock, so no need for atomic update */
- page->count_info &= ~PGC_SH_count_mask;
- page->count_info |= nx;
+ sp->count = nx;
/* We remember the first shadow entry that points to each shadow. */
- if ( entry_pa != 0 && page->up == 0 )
- page->up = entry_pa;
+ if ( entry_pa != 0
+ && sh_type_is_pinnable(v, sp->type)
+ && sp->up == 0 )
+ sp->up = entry_pa;
+
+ return 1;
}
@@ -473,114 +431,81 @@ static inline void sh_get_ref(mfn_t smfn, paddr_t entry_pa)
static inline void sh_put_ref(struct vcpu *v, mfn_t smfn, paddr_t entry_pa)
{
u32 x, nx;
- struct page_info *page = mfn_to_page(smfn);
+ struct shadow_page_info *sp = mfn_to_shadow_page(smfn);
ASSERT(mfn_valid(smfn));
- ASSERT(page_get_owner(page) == NULL);
+ ASSERT(sp->mbz == 0);
/* If this is the entry in the up-pointer, remove it */
- if ( entry_pa != 0 && page->up == entry_pa )
- page->up = 0;
+ if ( entry_pa != 0
+ && sh_type_is_pinnable(v, sp->type)
+ && sp->up == entry_pa )
+ sp->up = 0;
- x = page->count_info & PGC_SH_count_mask;
+ x = sp->count;
nx = x - 1;
if ( unlikely(x == 0) )
{
- SHADOW_PRINTK("shadow ref underflow, smfn=%lx oc=%08x t=%"
- PRtype_info "\n",
- mfn_x(smfn),
- page->count_info & PGC_SH_count_mask,
- page->u.inuse.type_info);
- domain_crash_synchronous();
+ SHADOW_ERROR("shadow ref underflow, smfn=%lx oc=%08x t=%#x\n",
+ mfn_x(smfn), sp->count, sp->type);
+ BUG();
}
/* Guarded by the shadow lock, so no need for atomic update */
- page->count_info &= ~PGC_SH_count_mask;
- page->count_info |= nx;
+ sp->count = nx;
if ( unlikely(nx == 0) )
sh_destroy_shadow(v, smfn);
}
-/* Pin a shadow page: take an extra refcount and set the pin bit. */
-static inline void sh_pin(mfn_t smfn)
+/* Pin a shadow page: take an extra refcount, set the pin bit,
+ * and put the shadow at the head of the list of pinned shadows.
+ * Returns 0 for failure, 1 for success. */
+static inline int sh_pin(struct vcpu *v, mfn_t smfn)
{
- struct page_info *page;
+ struct shadow_page_info *sp;
ASSERT(mfn_valid(smfn));
- page = mfn_to_page(smfn);
- if ( !(page->count_info & PGC_SH_pinned) )
+ sp = mfn_to_shadow_page(smfn);
+ ASSERT(sh_type_is_pinnable(v, sp->type));
+ if ( sp->pinned )
+ {
+ /* Already pinned: take it out of the pinned-list so it can go
+ * at the front */
+ list_del(&sp->list);
+ }
+ else
{
- sh_get_ref(smfn, 0);
- page->count_info |= PGC_SH_pinned;
+ /* Not pinned: pin it! */
+ if ( !sh_get_ref(v, smfn, 0) )
+ return 0;
+ sp->pinned = 1;
}
+ /* Put it at the head of the list of pinned shadows */
+ list_add(&sp->list, &v->domain->arch.shadow.pinned_shadows);
+ return 1;
}
-/* Unpin a shadow page: unset the pin bit and release the extra ref. */
+/* Unpin a shadow page: unset the pin bit, take the shadow off the list
+ * of pinned shadows, and release the extra ref. */
static inline void sh_unpin(struct vcpu *v, mfn_t smfn)
{
- struct page_info *page;
+ struct shadow_page_info *sp;
ASSERT(mfn_valid(smfn));
- page = mfn_to_page(smfn);
- if ( page->count_info & PGC_SH_pinned )
+ sp = mfn_to_shadow_page(smfn);
+ ASSERT(sh_type_is_pinnable(v, sp->type));
+ if ( sp->pinned )
{
- page->count_info &= ~PGC_SH_pinned;
+ sp->pinned = 0;
+ list_del(&sp->list);
+ sp->up = 0; /* in case this stops being a pinnable type in future */
sh_put_ref(v, smfn, 0);
}
}
-/**************************************************************************/
-/* Guest physmap (p2m) support */
-
-/* Read our own P2M table, checking in the linear pagetables first to be
- * sure that we will succeed. Call this function if you expect it to
- * fail often, as it avoids page faults. If you expect to succeed, use
- * vcpu_gfn_to_mfn, which copy_from_user()s the entry */
-static inline mfn_t
-vcpu_gfn_to_mfn_nofault(struct vcpu *v, unsigned long gfn)
-{
- unsigned long entry_addr = (unsigned long) &phys_to_machine_mapping[gfn];
-#if CONFIG_PAGING_LEVELS >= 4
- l4_pgentry_t *l4e;
- l3_pgentry_t *l3e;
-#endif
- l2_pgentry_t *l2e;
- l1_pgentry_t *l1e;
-
- ASSERT(current == v);
- if ( !shadow_vcpu_mode_translate(v) )
- return _mfn(gfn);
-
-#if CONFIG_PAGING_LEVELS > 2
- if ( gfn >= (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t) )
- /* This pfn is higher than the p2m map can hold */
- return _mfn(INVALID_MFN);
-#endif
-
- /* Walk the linear pagetables. Note that this is *not* the same as
- * the walk in sh_gfn_to_mfn_foreign, which is walking the p2m map */
-#if CONFIG_PAGING_LEVELS >= 4
- l4e = __linear_l4_table + l4_linear_offset(entry_addr);
- if ( !(l4e_get_flags(*l4e) & _PAGE_PRESENT) ) return _mfn(INVALID_MFN);
- l3e = __linear_l3_table + l3_linear_offset(entry_addr);
- if ( !(l3e_get_flags(*l3e) & _PAGE_PRESENT) ) return _mfn(INVALID_MFN);
-#endif
- l2e = __linear_l2_table + l2_linear_offset(entry_addr);
- if ( !(l2e_get_flags(*l2e) & _PAGE_PRESENT) ) return _mfn(INVALID_MFN);
- l1e = __linear_l1_table + l1_linear_offset(entry_addr);
- if ( !(l1e_get_flags(*l1e) & _PAGE_PRESENT) ) return _mfn(INVALID_MFN);
-
- /* Safe to look at this part of the table */
- if ( l1e_get_flags(phys_to_machine_mapping[gfn]) & _PAGE_PRESENT )
- return _mfn(l1e_get_pfn(phys_to_machine_mapping[gfn]));
-
- return _mfn(INVALID_MFN);
-}
-
-
#endif /* _XEN_SHADOW_PRIVATE_H */
/*
diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h
index bf1b2ce763..4aed70aa8c 100644
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -205,19 +205,21 @@ static inline shadow_l4e_t shadow_l4e_from_mfn(mfn_t mfn, u32 flags)
__sh_linear_l1_table; \
})
+// XXX -- these should not be conditional on is_hvm_vcpu(v), but rather on
+// shadow_mode_external(d)...
+//
#define sh_linear_l2_table(v) ({ \
ASSERT(current == (v)); \
((shadow_l2e_t *) \
- (hvm_guest(v) ? __linear_l1_table : __sh_linear_l1_table) + \
+ (is_hvm_vcpu(v) ? __linear_l1_table : __sh_linear_l1_table) + \
shadow_l1_linear_offset(SH_LINEAR_PT_VIRT_START)); \
})
-// shadow linear L3 and L4 tables only exist in 4 level paging...
-#if SHADOW_PAGING_LEVELS == 4
+#if SHADOW_PAGING_LEVELS >= 4
#define sh_linear_l3_table(v) ({ \
ASSERT(current == (v)); \
((shadow_l3e_t *) \
- (hvm_guest(v) ? __linear_l2_table : __sh_linear_l2_table) + \
+ (is_hvm_vcpu(v) ? __linear_l2_table : __sh_linear_l2_table) + \
shadow_l2_linear_offset(SH_LINEAR_PT_VIRT_START)); \
})
@@ -226,7 +228,7 @@ static inline shadow_l4e_t shadow_l4e_from_mfn(mfn_t mfn, u32 flags)
#define sh_linear_l4_table(v) ({ \
ASSERT(current == (v)); \
((l4_pgentry_t *) \
- (hvm_guest(v) ? __linear_l3_table : __sh_linear_l3_table) + \
+ (is_hvm_vcpu(v) ? __linear_l3_table : __sh_linear_l3_table) + \
shadow_l3_linear_offset(SH_LINEAR_PT_VIRT_START)); \
})
#endif
@@ -279,9 +281,9 @@ static inline guest_l2e_t guest_l2e_from_gfn(gfn_t gfn, u32 flags)
#define guest_l2_table_offset(a) l2_table_offset_32(a)
/* The shadow types needed for the various levels. */
-#define PGC_SH_l1_shadow PGC_SH_l1_32_shadow
-#define PGC_SH_l2_shadow PGC_SH_l2_32_shadow
-#define PGC_SH_fl1_shadow PGC_SH_fl1_32_shadow
+#define SH_type_l1_shadow SH_type_l1_32_shadow
+#define SH_type_l2_shadow SH_type_l2_32_shadow
+#define SH_type_fl1_shadow SH_type_fl1_32_shadow
#else /* GUEST_PAGING_LEVELS != 2 */
@@ -379,17 +381,16 @@ static inline guest_l4e_t guest_l4e_from_gfn(gfn_t gfn, u32 flags)
/* The shadow types needed for the various levels. */
#if GUEST_PAGING_LEVELS == 3
-#define PGC_SH_l1_shadow PGC_SH_l1_pae_shadow
-#define PGC_SH_fl1_shadow PGC_SH_fl1_pae_shadow
-#define PGC_SH_l2_shadow PGC_SH_l2_pae_shadow
-#define PGC_SH_l2h_shadow PGC_SH_l2h_pae_shadow
-#define PGC_SH_l3_shadow PGC_SH_l3_pae_shadow
+#define SH_type_l1_shadow SH_type_l1_pae_shadow
+#define SH_type_fl1_shadow SH_type_fl1_pae_shadow
+#define SH_type_l2_shadow SH_type_l2_pae_shadow
+#define SH_type_l2h_shadow SH_type_l2h_pae_shadow
#else
-#define PGC_SH_l1_shadow PGC_SH_l1_64_shadow
-#define PGC_SH_fl1_shadow PGC_SH_fl1_64_shadow
-#define PGC_SH_l2_shadow PGC_SH_l2_64_shadow
-#define PGC_SH_l3_shadow PGC_SH_l3_64_shadow
-#define PGC_SH_l4_shadow PGC_SH_l4_64_shadow
+#define SH_type_l1_shadow SH_type_l1_64_shadow
+#define SH_type_fl1_shadow SH_type_fl1_64_shadow
+#define SH_type_l2_shadow SH_type_l2_64_shadow
+#define SH_type_l3_shadow SH_type_l3_64_shadow
+#define SH_type_l4_shadow SH_type_l4_64_shadow
#endif
#endif /* GUEST_PAGING_LEVELS != 2 */
@@ -402,20 +403,21 @@ valid_gfn(gfn_t m)
return VALID_GFN(gfn_x(m));
}
-#if GUEST_PAGING_LEVELS == 2
-#define PGC_SH_guest_root_type PGC_SH_l2_32_shadow
-#elif GUEST_PAGING_LEVELS == 3
-#define PGC_SH_guest_root_type PGC_SH_l3_pae_shadow
-#else
-#define PGC_SH_guest_root_type PGC_SH_l4_64_shadow
-#endif
-
/* Translation between mfns and gfns */
+
+// vcpu-specific version of gfn_to_mfn(). This is where we hide the dirty
+// little secret that, for hvm guests with paging disabled, nearly all of the
+// shadow code actually think that the guest is running on *untranslated* page
+// tables (which is actually domain->phys_table).
+//
+
static inline mfn_t
vcpu_gfn_to_mfn(struct vcpu *v, gfn_t gfn)
{
- return sh_vcpu_gfn_to_mfn(v, gfn_x(gfn));
-}
+ if ( !shadow_vcpu_mode_translate(v) )
+ return _mfn(gfn_x(gfn));
+ return sh_gfn_to_mfn(v->domain, gfn_x(gfn));
+}
static inline gfn_t
mfn_to_gfn(struct domain *d, mfn_t mfn)
@@ -487,8 +489,6 @@ struct shadow_walk_t
#define sh_map_and_validate_gl1e INTERNAL_NAME(sh_map_and_validate_gl1e)
#define sh_destroy_l4_shadow INTERNAL_NAME(sh_destroy_l4_shadow)
#define sh_destroy_l3_shadow INTERNAL_NAME(sh_destroy_l3_shadow)
-#define sh_destroy_l3_subshadow INTERNAL_NAME(sh_destroy_l3_subshadow)
-#define sh_unpin_all_l3_subshadows INTERNAL_NAME(sh_unpin_all_l3_subshadows)
#define sh_destroy_l2_shadow INTERNAL_NAME(sh_destroy_l2_shadow)
#define sh_destroy_l1_shadow INTERNAL_NAME(sh_destroy_l1_shadow)
#define sh_unhook_32b_mappings INTERNAL_NAME(sh_unhook_32b_mappings)
@@ -507,10 +507,22 @@ struct shadow_walk_t
#define sh_guess_wrmap INTERNAL_NAME(sh_guess_wrmap)
#define sh_clear_shadow_entry INTERNAL_NAME(sh_clear_shadow_entry)
+/* The sh_guest_(map|get)_* functions only depends on the number of config
+ * levels
+ */
+#define sh_guest_map_l1e \
+ SHADOW_INTERNAL_NAME(sh_guest_map_l1e, \
+ CONFIG_PAGING_LEVELS, \
+ CONFIG_PAGING_LEVELS)
+#define sh_guest_get_eff_l1e \
+ SHADOW_INTERNAL_NAME(sh_guest_get_eff_l1e, \
+ CONFIG_PAGING_LEVELS, \
+ CONFIG_PAGING_LEVELS)
+
/* sh_make_monitor_table only depends on the number of shadow levels */
-#define sh_make_monitor_table \
- SHADOW_INTERNAL_NAME(sh_make_monitor_table, \
- SHADOW_PAGING_LEVELS, \
+#define sh_make_monitor_table \
+ SHADOW_INTERNAL_NAME(sh_make_monitor_table, \
+ SHADOW_PAGING_LEVELS, \
SHADOW_PAGING_LEVELS)
#define sh_destroy_monitor_table \
SHADOW_INTERNAL_NAME(sh_destroy_monitor_table, \
@@ -518,115 +530,6 @@ struct shadow_walk_t
SHADOW_PAGING_LEVELS)
-#if GUEST_PAGING_LEVELS == 3
-/*
- * Accounting information stored in the shadow of PAE Guest L3 pages.
- * Because these "L3 pages" are only 32-bytes, it is inconvenient to keep
- * various refcounts, etc., on the page_info of their page. We provide extra
- * bookkeeping space in the shadow itself, and this is the structure
- * definition for that bookkeeping information.
- */
-struct pae_l3_bookkeeping {
- u32 vcpus; /* bitmap of which vcpus are currently storing
- * copies of this 32-byte page */
- u32 refcount; /* refcount for this 32-byte page */
- u8 pinned; /* is this 32-byte page pinned or not? */
-};
-
-// Convert a shadow entry pointer into a pae_l3_bookkeeping pointer.
-#define sl3p_to_info(_ptr) ((struct pae_l3_bookkeeping *) \
- (((unsigned long)(_ptr) & ~31) + 32))
-
-static void sh_destroy_l3_subshadow(struct vcpu *v,
- shadow_l3e_t *sl3e);
-
-/* Increment a subshadow ref
- * Called with a pointer to the subshadow, and the mfn of the
- * *first* page of the overall shadow. */
-static inline void sh_get_ref_l3_subshadow(shadow_l3e_t *sl3e, mfn_t smfn)
-{
- struct pae_l3_bookkeeping *bk = sl3p_to_info(sl3e);
-
- /* First ref to the subshadow takes a ref to the full shadow */
- if ( bk->refcount == 0 )
- sh_get_ref(smfn, 0);
- if ( unlikely(++(bk->refcount) == 0) )
- {
- SHADOW_PRINTK("shadow l3 subshadow ref overflow, smfn=%" SH_PRI_mfn " sh=%p\n",
- mfn_x(smfn), sl3e);
- domain_crash_synchronous();
- }
-}
-
-/* Decrement a subshadow ref.
- * Called with a pointer to the subshadow, and the mfn of the
- * *first* page of the overall shadow. Calling this may cause the
- * entire shadow to disappear, so the caller must immediately unmap
- * the pointer after calling. */
-static inline void sh_put_ref_l3_subshadow(struct vcpu *v,
- shadow_l3e_t *sl3e,
- mfn_t smfn)
-{
- struct pae_l3_bookkeeping *bk;
-
- bk = sl3p_to_info(sl3e);
-
- ASSERT(bk->refcount > 0);
- if ( --(bk->refcount) == 0 )
- {
- /* Need to destroy this subshadow */
- sh_destroy_l3_subshadow(v, sl3e);
- /* Last ref to the subshadow had a ref to the full shadow */
- sh_put_ref(v, smfn, 0);
- }
-}
-
-/* Pin a subshadow
- * Called with a pointer to the subshadow, and the mfn of the
- * *first* page of the overall shadow. */
-static inline void sh_pin_l3_subshadow(shadow_l3e_t *sl3e, mfn_t smfn)
-{
- struct pae_l3_bookkeeping *bk = sl3p_to_info(sl3e);
-
-#if 0
- debugtrace_printk("%s smfn=%05lx offset=%ld\n",
- __func__, mfn_x(smfn),
- ((unsigned long)sl3e & ~PAGE_MASK) / 64);
-#endif
-
- if ( !bk->pinned )
- {
- bk->pinned = 1;
- sh_get_ref_l3_subshadow(sl3e, smfn);
- }
-}
-
-/* Unpin a sub-shadow.
- * Called with a pointer to the subshadow, and the mfn of the
- * *first* page of the overall shadow. Calling this may cause the
- * entire shadow to disappear, so the caller must immediately unmap
- * the pointer after calling. */
-static inline void sh_unpin_l3_subshadow(struct vcpu *v,
- shadow_l3e_t *sl3e,
- mfn_t smfn)
-{
- struct pae_l3_bookkeeping *bk = sl3p_to_info(sl3e);
-
-#if 0
- debugtrace_printk("%s smfn=%05lx offset=%ld\n",
- __func__, mfn_x(smfn),
- ((unsigned long)sl3e & ~PAGE_MASK) / 64);
-#endif
-
- if ( bk->pinned )
- {
- bk->pinned = 0;
- sh_put_ref_l3_subshadow(v, sl3e, smfn);
- }
-}
-
-#endif /* GUEST_PAGING_LEVELS == 3 */
-
#if SHADOW_PAGING_LEVELS == 3
#define MFN_FITS_IN_HVM_CR3(_MFN) !(mfn_x(_MFN) >> 20)
#endif
@@ -652,7 +555,7 @@ static inline void sh_unpin_l3_subshadow(struct vcpu *v,
#endif /* GUEST_PAGING_LEVELS >= 3 */
static inline u32
-accumulate_guest_flags(walk_t *gw)
+accumulate_guest_flags(struct vcpu *v, walk_t *gw)
{
u32 accumulated_flags;
@@ -674,12 +577,89 @@ accumulate_guest_flags(walk_t *gw)
accumulated_flags &= guest_l4e_get_flags(*gw->l4e) ^ _PAGE_NX_BIT;
#endif
- // Finally, revert the NX bit back to its original polarity
+ // Revert the NX bit back to its original polarity
accumulated_flags ^= _PAGE_NX_BIT;
+ // In 64-bit PV guests, the _PAGE_USER bit is implied in all guest
+ // entries (since even the guest kernel runs in ring 3).
+ //
+ if ( (GUEST_PAGING_LEVELS == 4) && !is_hvm_vcpu(v) )
+ accumulated_flags |= _PAGE_USER;
+
return accumulated_flags;
}
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_FAST_FAULT_PATH) && SHADOW_PAGING_LEVELS > 2
+/******************************************************************************
+ * We implement a "fast path" for two special cases: faults that require
+ * MMIO emulation, and faults where the guest PTE is not present. We
+ * record these as shadow l1 entries that have reserved bits set in
+ * them, so we can spot them immediately in the fault handler and handle
+ * them without needing to hold the shadow lock or walk the guest
+ * pagetables.
+ *
+ * This is only feasible for PAE and 64bit Xen: 32-bit non-PAE PTEs don't
+ * have reserved bits that we can use for this.
+ */
+
+#define SH_L1E_MAGIC 0xffffffff00000000ULL
+static inline int sh_l1e_is_magic(shadow_l1e_t sl1e)
+{
+ return ((sl1e.l1 & SH_L1E_MAGIC) == SH_L1E_MAGIC);
+}
+
+/* Guest not present: a single magic value */
+static inline shadow_l1e_t sh_l1e_gnp(void)
+{
+ return (shadow_l1e_t){ -1ULL };
+}
+
+static inline int sh_l1e_is_gnp(shadow_l1e_t sl1e)
+{
+ return (sl1e.l1 == sh_l1e_gnp().l1);
+}
+
+/* MMIO: an invalid PTE that contains the GFN of the equivalent guest l1e.
+ * We store 28 bits of GFN in bits 4:32 of the entry.
+ * The present bit is set, and the U/S and R/W bits are taken from the guest.
+ * Bit 3 is always 0, to differentiate from gnp above. */
+#define SH_L1E_MMIO_MAGIC 0xffffffff00000001ULL
+#define SH_L1E_MMIO_MAGIC_MASK 0xffffffff00000009ULL
+#define SH_L1E_MMIO_GFN_MASK 0x00000000fffffff0ULL
+#define SH_L1E_MMIO_GFN_SHIFT 4
+
+static inline shadow_l1e_t sh_l1e_mmio(gfn_t gfn, u32 gflags)
+{
+ return (shadow_l1e_t) { (SH_L1E_MMIO_MAGIC
+ | (gfn_x(gfn) << SH_L1E_MMIO_GFN_SHIFT)
+ | (gflags & (_PAGE_USER|_PAGE_RW))) };
+}
+
+static inline int sh_l1e_is_mmio(shadow_l1e_t sl1e)
+{
+ return ((sl1e.l1 & SH_L1E_MMIO_MAGIC_MASK) == SH_L1E_MMIO_MAGIC);
+}
+
+static inline gfn_t sh_l1e_mmio_get_gfn(shadow_l1e_t sl1e)
+{
+ return _gfn((sl1e.l1 & SH_L1E_MMIO_GFN_MASK) >> SH_L1E_MMIO_GFN_SHIFT);
+}
+
+static inline u32 sh_l1e_mmio_get_flags(shadow_l1e_t sl1e)
+{
+ return (u32)((sl1e.l1 & (_PAGE_USER|_PAGE_RW)));
+}
+
+#else
+
+#define sh_l1e_gnp() shadow_l1e_empty()
+#define sh_l1e_mmio(_gfn, _flags) shadow_l1e_empty()
+#define sh_l1e_is_magic(_e) (0)
+
+#endif /* SHOPT_FAST_FAULT_PATH */
+
+
#endif /* _XEN_SHADOW_TYPES_H */
/*
diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c
index 7141b55f27..c39ea42b6b 100644
--- a/xen/arch/x86/mpparse.c
+++ b/xen/arch/x86/mpparse.c
@@ -35,13 +35,7 @@
/* Have we found an MP table */
int smp_found_config;
-unsigned int __devinitdata maxcpus = NR_CPUS;
-
-#ifdef CONFIG_HOTPLUG_CPU
-#define CPU_HOTPLUG_ENABLED (1)
-#else
-#define CPU_HOTPLUG_ENABLED (0)
-#endif
+unsigned int __initdata maxcpus = NR_CPUS;
/*
* Various Linux-internal data structures created from the
@@ -73,9 +67,8 @@ unsigned int def_to_bigsmp = 0;
/* Processor that is doing the boot up */
unsigned int boot_cpu_physical_apicid = -1U;
-unsigned int boot_cpu_logical_apicid = -1U;
/* Internal processor count */
-static unsigned int __initdata num_processors;
+static unsigned int __devinitdata num_processors;
/* Bitmask of physically existing CPUs */
physid_mask_t phys_cpu_present_map;
@@ -107,24 +100,9 @@ static int __init mpf_checksum(unsigned char *mp, int len)
* doing this ....
*/
-static int mpc_record;
+static int mpc_record;
static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;
-#ifdef CONFIG_X86_NUMAQ
-static int MP_valid_apicid(int apicid, int version)
-{
- return hweight_long(apicid & 0xf) == 1 && (apicid >> 4) != 0xf;
-}
-#else
-static int MP_valid_apicid(int apicid, int version)
-{
- if (version >= 0x14)
- return apicid < 0xff;
- else
- return apicid < 0xf;
-}
-#endif
-
static void __devinit MP_processor_info (struct mpc_config_processor *m)
{
int ver, apicid;
@@ -190,12 +168,6 @@ static void __devinit MP_processor_info (struct mpc_config_processor *m)
ver = m->mpc_apicver;
- if (!MP_valid_apicid(apicid, ver)) {
- printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n",
- m->mpc_apicid, MAX_APICS);
- return;
- }
-
/*
* Validate version
*/
@@ -225,7 +197,7 @@ static void __devinit MP_processor_info (struct mpc_config_processor *m)
cpu_set(num_processors, cpu_possible_map);
num_processors++;
- if (CPU_HOTPLUG_ENABLED || (num_processors > 8)) {
+ if (num_processors > 8) {
/*
* No need for processor or APIC checks: physical delivery
* (bigsmp) mode should always work.
@@ -244,6 +216,15 @@ static void __init MP_bus_info (struct mpc_config_bus *m)
mpc_oem_bus_info(m, str, translation_table[mpc_record]);
+#if 0 /* size of mpc_busid (8 bits) makes this check unnecessary */
+ if (m->mpc_busid >= MAX_MP_BUSSES) {
+ printk(KERN_WARNING "MP table busid value (%d) for bustype %s "
+ " is too large, max. supported is %d\n",
+ m->mpc_busid, str, MAX_MP_BUSSES - 1);
+ return;
+ }
+#endif
+
if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) {
mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) {
@@ -931,7 +912,8 @@ void __init mp_register_ioapic (
mp_ioapics[idx].mpc_apicaddr = address;
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
- if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 < 15))
+ if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ && !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
tmpid = io_apic_get_unique_id(idx, id);
else
tmpid = id;
@@ -1007,7 +989,6 @@ void __init mp_override_legacy_irq (
return;
}
-
void __init mp_config_acpi_legacy_irqs (void)
{
struct mpc_config_intsrc intsrc;
@@ -1139,7 +1120,17 @@ int mp_register_gsi (u32 gsi, int triggering, int polarity)
*/
int irq = gsi;
if (gsi < MAX_GSI_NUM) {
- if (gsi > 15)
+ /*
+ * Retain the VIA chipset work-around (gsi > 15), but
+ * avoid a problem where the 8254 timer (IRQ0) is setup
+ * via an override (so it's not on pin 0 of the ioapic),
+ * and at the same time, the pin 0 interrupt is a PCI
+ * type. The gsi > 15 test could cause these two pins
+ * to be shared as IRQ0, and they are not shareable.
+ * So test for this condition, and if necessary, avoid
+ * the pin collision.
+ */
+ if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
gsi = pci_irq++;
#ifdef CONFIG_ACPI_BUS
/*
diff --git a/xen/arch/x86/numa.c b/xen/arch/x86/numa.c
new file mode 100644
index 0000000000..d332320af6
--- /dev/null
+++ b/xen/arch/x86/numa.c
@@ -0,0 +1,308 @@
+/*
+ * Generic VM initialization for x86-64 NUMA setups.
+ * Copyright 2002,2003 Andi Kleen, SuSE Labs.
+ * Adapted for Xen: Ryan Harper <ryanh@us.ibm.com>
+ */
+
+#include <xen/mm.h>
+#include <xen/string.h>
+#include <xen/init.h>
+#include <xen/ctype.h>
+#include <xen/nodemask.h>
+#include <xen/numa.h>
+#include <xen/keyhandler.h>
+#include <xen/time.h>
+#include <xen/smp.h>
+#include <asm/acpi.h>
+
+static int numa_setup(char *s);
+custom_param("numa", numa_setup);
+
+#ifndef Dprintk
+#define Dprintk(x...)
+#endif
+
+/* from proto.h */
+#define round_up(x,y) ((((x)+(y))-1) & (~((y)-1)))
+
+struct node_data node_data[MAX_NUMNODES];
+
+int memnode_shift;
+u8 memnodemap[NODEMAPSIZE];
+
+unsigned char cpu_to_node[NR_CPUS] __read_mostly = {
+ [0 ... NR_CPUS-1] = NUMA_NO_NODE
+};
+unsigned char apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
+ [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+};
+cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly;
+
+nodemask_t node_online_map = { { [0] = 1UL } };
+
+/* Default NUMA to off for now. acpi=on required to enable it. */
+int numa_off __initdata = 1;
+
+int acpi_numa __initdata;
+
+/*
+ * Given a shift value, try to populate memnodemap[]
+ * Returns :
+ * 1 if OK
+ * 0 if memnodmap[] too small (of shift too small)
+ * -1 if node overlap or lost ram (shift too big)
+ */
+static int __init
+populate_memnodemap(const struct node *nodes, int numnodes, int shift)
+{
+ int i;
+ int res = -1;
+ unsigned long addr, end;
+
+ if (shift >= 64)
+ return -1;
+ memset(memnodemap, 0xff, sizeof(memnodemap));
+ for (i = 0; i < numnodes; i++) {
+ addr = nodes[i].start;
+ end = nodes[i].end;
+ if (addr >= end)
+ continue;
+ if ((end >> shift) >= NODEMAPSIZE)
+ return 0;
+ do {
+ if (memnodemap[addr >> shift] != 0xff)
+ return -1;
+ memnodemap[addr >> shift] = i;
+ addr += (1UL << shift);
+ } while (addr < end);
+ res = 1;
+ }
+ return res;
+}
+
+int __init compute_hash_shift(struct node *nodes, int numnodes)
+{
+ int shift = 20;
+
+ while (populate_memnodemap(nodes, numnodes, shift + 1) >= 0)
+ shift++;
+
+ printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n",
+ shift);
+
+ if (populate_memnodemap(nodes, numnodes, shift) != 1) {
+ printk(KERN_INFO
+ "Your memory is not aligned you need to rebuild your kernel "
+ "with a bigger NODEMAPSIZE shift=%d\n",
+ shift);
+ return -1;
+ }
+ return shift;
+}
+
+/* initialize NODE_DATA given nodeid and start/end */
+void __init setup_node_bootmem(int nodeid, u64 start, u64 end)
+{
+ unsigned long start_pfn, end_pfn;
+
+ start_pfn = start >> PAGE_SHIFT;
+ end_pfn = end >> PAGE_SHIFT;
+
+ NODE_DATA(nodeid)->node_id = nodeid;
+ NODE_DATA(nodeid)->node_start_pfn = start_pfn;
+ NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn;
+
+ node_set_online(nodeid);
+}
+
+void __init numa_init_array(void)
+{
+ int rr, i;
+ /* There are unfortunately some poorly designed mainboards around
+ that only connect memory to a single CPU. This breaks the 1:1 cpu->node
+ mapping. To avoid this fill in the mapping for all possible
+ CPUs, as the number of CPUs is not known yet.
+ We round robin the existing nodes. */
+ rr = first_node(node_online_map);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_to_node[i] != NUMA_NO_NODE)
+ continue;
+ numa_set_node(i, rr);
+ rr = next_node(rr, node_online_map);
+ if (rr == MAX_NUMNODES)
+ rr = first_node(node_online_map);
+ }
+
+}
+
+#ifdef CONFIG_NUMA_EMU
+static int numa_fake __initdata = 0;
+
+/* Numa emulation */
+static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+{
+ int i;
+ struct node nodes[MAX_NUMNODES];
+ unsigned long sz = ((end_pfn - start_pfn)<<PAGE_SHIFT) / numa_fake;
+
+ /* Kludge needed for the hash function */
+ if (hweight64(sz) > 1) {
+ unsigned long x = 1;
+ while ((x << 1) < sz)
+ x <<= 1;
+ if (x < sz/2)
+ printk(KERN_ERR "Numa emulation unbalanced. Complain to maintainer\n");
+ sz = x;
+ }
+
+ memset(&nodes,0,sizeof(nodes));
+ for (i = 0; i < numa_fake; i++) {
+ nodes[i].start = (start_pfn<<PAGE_SHIFT) + i*sz;
+ if (i == numa_fake-1)
+ sz = (end_pfn<<PAGE_SHIFT) - nodes[i].start;
+ nodes[i].end = nodes[i].start + sz;
+ printk(KERN_INFO "Faking node %d at %"PRIx64"-%"PRIx64" (%"PRIu64"MB)\n",
+ i,
+ nodes[i].start, nodes[i].end,
+ (nodes[i].end - nodes[i].start) >> 20);
+ node_set_online(i);
+ }
+ memnode_shift = compute_hash_shift(nodes, numa_fake);
+ if (memnode_shift < 0) {
+ memnode_shift = 0;
+ printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n");
+ return -1;
+ }
+ for_each_online_node(i)
+ setup_node_bootmem(i, nodes[i].start, nodes[i].end);
+ numa_init_array();
+ return 0;
+}
+#endif
+
+void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+{
+ int i;
+
+#ifdef CONFIG_NUMA_EMU
+ if (numa_fake && !numa_emulation(start_pfn, end_pfn))
+ return;
+#endif
+
+#ifdef CONFIG_ACPI_NUMA
+ if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
+ end_pfn << PAGE_SHIFT))
+ return;
+#endif
+
+ printk(KERN_INFO "%s\n",
+ numa_off ? "NUMA turned off" : "No NUMA configuration found");
+
+ printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
+ start_pfn << PAGE_SHIFT,
+ end_pfn << PAGE_SHIFT);
+ /* setup dummy node covering all memory */
+ memnode_shift = 63;
+ memnodemap[0] = 0;
+ nodes_clear(node_online_map);
+ node_set_online(0);
+ for (i = 0; i < NR_CPUS; i++)
+ numa_set_node(i, 0);
+ node_to_cpumask[0] = cpumask_of_cpu(0);
+ setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+}
+
+__cpuinit void numa_add_cpu(int cpu)
+{
+ set_bit(cpu, &node_to_cpumask[cpu_to_node(cpu)]);
+}
+
+void __cpuinit numa_set_node(int cpu, int node)
+{
+ cpu_to_node[cpu] = node;
+}
+
+/* [numa=off] */
+static __init int numa_setup(char *opt)
+{
+ if (!strncmp(opt,"off",3))
+ numa_off = 1;
+ if (!strncmp(opt,"on",2))
+ numa_off = 0;
+#ifdef CONFIG_NUMA_EMU
+ if(!strncmp(opt, "fake=", 5)) {
+ numa_off = 0;
+ numa_fake = simple_strtoul(opt+5,NULL,0); ;
+ if (numa_fake >= MAX_NUMNODES)
+ numa_fake = MAX_NUMNODES;
+ }
+#endif
+#ifdef CONFIG_ACPI_NUMA
+ if (!strncmp(opt,"noacpi",6)) {
+ numa_off = 0;
+ acpi_numa = -1;
+ }
+#endif
+ return 1;
+}
+
+/*
+ * Setup early cpu_to_node.
+ *
+ * Populate cpu_to_node[] only if x86_cpu_to_apicid[],
+ * and apicid_to_node[] tables have valid entries for a CPU.
+ * This means we skip cpu_to_node[] initialisation for NUMA
+ * emulation and faking node case (when running a kernel compiled
+ * for NUMA on a non NUMA box), which is OK as cpu_to_node[]
+ * is already initialized in a round robin manner at numa_init_array,
+ * prior to this call, and this initialization is good enough
+ * for the fake NUMA cases.
+ */
+void __init init_cpu_to_node(void)
+{
+ int i;
+ for (i = 0; i < NR_CPUS; i++) {
+ u8 apicid = x86_cpu_to_apicid[i];
+ if (apicid == BAD_APICID)
+ continue;
+ if (apicid_to_node[apicid] == NUMA_NO_NODE)
+ continue;
+ numa_set_node(i,apicid_to_node[apicid]);
+ }
+}
+
+EXPORT_SYMBOL(cpu_to_node);
+EXPORT_SYMBOL(node_to_cpumask);
+EXPORT_SYMBOL(memnode_shift);
+EXPORT_SYMBOL(memnodemap);
+EXPORT_SYMBOL(node_data);
+
+static void dump_numa(unsigned char key)
+{
+ s_time_t now = NOW();
+ int i;
+
+ printk("'%c' pressed -> dumping numa info (now-0x%X:%08X)\n", key,
+ (u32)(now>>32), (u32)now);
+
+ for_each_online_node(i) {
+ unsigned long pa = (NODE_DATA(i)->node_start_pfn + 1)<< PAGE_SHIFT;
+ printk("idx%d -> NODE%d start->%lu size->%lu\n",
+ i, NODE_DATA(i)->node_id,
+ NODE_DATA(i)->node_start_pfn,
+ NODE_DATA(i)->node_spanned_pages);
+ /* sanity check phys_to_nid() */
+ printk("phys_to_nid(%lx) -> %d should be %d\n", pa, phys_to_nid(pa),
+ NODE_DATA(i)->node_id);
+ }
+ for_each_online_cpu(i)
+ printk("CPU%d -> NODE%d\n", i, cpu_to_node[i]);
+}
+
+static __init int register_numa_trigger(void)
+{
+ register_keyhandler('u', dump_numa, "dump numa info");
+ return 0;
+}
+__initcall(register_numa_trigger);
+
diff --git a/xen/arch/x86/oprofile/nmi_int.c b/xen/arch/x86/oprofile/nmi_int.c
index 24a1fea86e..15e2818edb 100644
--- a/xen/arch/x86/oprofile/nmi_int.c
+++ b/xen/arch/x86/oprofile/nmi_int.c
@@ -33,7 +33,6 @@ static unsigned long saved_lvtpc[NR_CPUS];
#define VIRQ_BITMASK_SIZE (MAX_OPROF_DOMAINS/32 + 1)
extern int active_domains[MAX_OPROF_DOMAINS];
extern unsigned int adomains;
-extern struct domain *primary_profiler;
extern struct domain *adomain_ptrs[MAX_OPROF_DOMAINS];
extern unsigned long virq_ovf_pending[VIRQ_BITMASK_SIZE];
extern int is_active(struct domain *d);
@@ -269,8 +268,12 @@ static int __init p4_init(char * cpu_type)
{
__u8 cpu_model = current_cpu_data.x86_model;
- if ((cpu_model > 6) || (cpu_model == 5))
+ if ((cpu_model > 6) || (cpu_model == 5)) {
+ printk("xenoprof: Initialization failed. "
+ "Intel processor model %d for pentium 4 family is not "
+ "supported\n", cpu_model);
return 0;
+ }
#ifndef CONFIG_SMP
strncpy (cpu_type, "i386/p4", XENOPROF_CPU_TYPE_SIZE - 1);
@@ -301,18 +304,24 @@ static int __init ppro_init(char *cpu_type)
{
__u8 cpu_model = current_cpu_data.x86_model;
- if (cpu_model > 0xd)
+ if (cpu_model > 15) {
+ printk("xenoprof: Initialization failed. "
+ "Intel processor model %d for P6 class family is not "
+ "supported\n", cpu_model);
return 0;
-
- if (cpu_model == 9) {
+ }
+ else if (cpu_model == 15)
+ strncpy (cpu_type, "i386/core_2", XENOPROF_CPU_TYPE_SIZE - 1);
+ else if (cpu_model == 14)
+ strncpy (cpu_type, "i386/core", XENOPROF_CPU_TYPE_SIZE - 1);
+ else if (cpu_model == 9)
strncpy (cpu_type, "i386/p6_mobile", XENOPROF_CPU_TYPE_SIZE - 1);
- } else if (cpu_model > 5) {
+ else if (cpu_model > 5)
strncpy (cpu_type, "i386/piii", XENOPROF_CPU_TYPE_SIZE - 1);
- } else if (cpu_model > 2) {
+ else if (cpu_model > 2)
strncpy (cpu_type, "i386/pii", XENOPROF_CPU_TYPE_SIZE - 1);
- } else {
+ else
strncpy (cpu_type, "i386/ppro", XENOPROF_CPU_TYPE_SIZE - 1);
- }
model = &op_ppro_spec;
return 1;
@@ -324,13 +333,15 @@ int nmi_init(int *num_events, int *is_primary, char *cpu_type)
__u8 family = current_cpu_data.x86;
int prim = 0;
- if (!cpu_has_apic)
+ if (!cpu_has_apic) {
+ printk("xenoprof: Initialization failed. No apic.\n");
return -ENODEV;
+ }
- if (primary_profiler == NULL) {
+ if (xenoprof_primary_profiler == NULL) {
/* For now, only dom0 can be the primary profiler */
if (current->domain->domain_id == 0) {
- primary_profiler = current->domain;
+ xenoprof_primary_profiler = current->domain;
prim = 1;
}
}
@@ -344,6 +355,9 @@ int nmi_init(int *num_events, int *is_primary, char *cpu_type)
switch (family) {
default:
+ printk("xenoprof: Initialization failed. "
+ "AMD processor family %d is not "
+ "supported\n", family);
return -ENODEV;
case 6:
model = &op_athlon_spec;
@@ -375,11 +389,17 @@ int nmi_init(int *num_events, int *is_primary, char *cpu_type)
break;
default:
+ printk("xenoprof: Initialization failed. "
+ "Intel processor family %d is not "
+ "supported\n", family);
return -ENODEV;
}
break;
default:
+ printk("xenoprof: Initialization failed. "
+ "Unsupported processor. Unknown vendor %d\n",
+ vendor);
return -ENODEV;
}
diff --git a/xen/arch/x86/oprofile/op_model_athlon.c b/xen/arch/x86/oprofile/op_model_athlon.c
index c946c1ea8e..1d8f9668f4 100644
--- a/xen/arch/x86/oprofile/op_model_athlon.c
+++ b/xen/arch/x86/oprofile/op_model_athlon.c
@@ -18,6 +18,7 @@
#include <xen/sched.h>
#include <asm/regs.h>
#include <asm/current.h>
+#include <asm/hvm/support.h>
#include "op_x86_model.h"
#include "op_counter.h"
@@ -44,7 +45,11 @@ static unsigned long reset_value[NUM_COUNTERS];
extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
int mode, int event);
-
+extern int xenoprofile_get_mode(struct vcpu *v,
+ struct cpu_user_regs * const regs);
+
+extern char svm_stgi_label[];
+
static void athlon_fill_in_addresses(struct op_msrs * const msrs)
{
msrs->counters[0].addr = MSR_K7_PERFCTR0;
@@ -97,10 +102,9 @@ static void athlon_setup_ctrs(struct op_msrs const * const msrs)
}
}
-
static int athlon_check_ctrs(unsigned int const cpu,
- struct op_msrs const * const msrs,
- struct cpu_user_regs * const regs)
+ struct op_msrs const * const msrs,
+ struct cpu_user_regs * const regs)
{
unsigned int low, high;
@@ -108,11 +112,19 @@ static int athlon_check_ctrs(unsigned int const cpu,
int ovf = 0;
unsigned long eip = regs->eip;
int mode = 0;
-
- if (guest_kernel_mode(current, regs))
- mode = 1;
- else if (ring_0(regs))
- mode = 2;
+ struct vcpu *v = current;
+ struct cpu_user_regs tmp_regs;
+
+ if (!guest_mode(regs) &&
+ (regs->eip == (unsigned long)svm_stgi_label)) {
+ /* SVM guest was running when NMI occurred */
+ hvm_store_cpu_guest_regs(v, &tmp_regs, NULL);
+ eip = tmp_regs.eip;
+ mode = xenoprofile_get_mode(v, &tmp_regs);
+ } else {
+ eip = regs->eip;
+ mode = xenoprofile_get_mode(v, regs);
+ }
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
diff --git a/xen/arch/x86/oprofile/op_model_p4.c b/xen/arch/x86/oprofile/op_model_p4.c
index 018124eaf9..c285ea1d41 100644
--- a/xen/arch/x86/oprofile/op_model_p4.c
+++ b/xen/arch/x86/oprofile/op_model_p4.c
@@ -620,9 +620,10 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
}
}
-
extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
int mode, int event);
+extern int xenoprofile_get_mode(struct vcpu *v,
+ struct cpu_user_regs * const regs);
static int p4_check_ctrs(unsigned int const cpu,
struct op_msrs const * const msrs,
@@ -632,12 +633,7 @@ static int p4_check_ctrs(unsigned int const cpu,
int i;
int ovf = 0;
unsigned long eip = regs->eip;
- int mode = 0;
-
- if (guest_kernel_mode(current, regs))
- mode = 1;
- else if (ring_0(regs))
- mode = 2;
+ int mode = xenoprofile_get_mode(current, regs);
stag = get_stagger();
diff --git a/xen/arch/x86/oprofile/op_model_ppro.c b/xen/arch/x86/oprofile/op_model_ppro.c
index b982443928..139f4571bf 100644
--- a/xen/arch/x86/oprofile/op_model_ppro.c
+++ b/xen/arch/x86/oprofile/op_model_ppro.c
@@ -88,9 +88,10 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
}
}
-
extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
int mode, int event);
+extern int xenoprofile_get_mode(struct vcpu *v,
+ struct cpu_user_regs * const regs);
static int ppro_check_ctrs(unsigned int const cpu,
struct op_msrs const * const msrs,
@@ -100,13 +101,8 @@ static int ppro_check_ctrs(unsigned int const cpu,
int i;
int ovf = 0;
unsigned long eip = regs->eip;
- int mode = 0;
+ int mode = xenoprofile_get_mode(current, regs);
- if ( guest_kernel_mode(current, regs) )
- mode = 1;
- else if ( ring_0(regs) )
- mode = 2;
-
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
diff --git a/xen/arch/x86/oprofile/xenoprof.c b/xen/arch/x86/oprofile/xenoprof.c
index 479d9c5060..a15c8917ed 100644
--- a/xen/arch/x86/oprofile/xenoprof.c
+++ b/xen/arch/x86/oprofile/xenoprof.c
@@ -2,668 +2,48 @@
* Copyright (C) 2005 Hewlett-Packard Co.
* written by Aravind Menon & Jose Renato Santos
* (email: xenoprof@groups.hp.com)
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ * x86 specific part
*/
#include <xen/guest_access.h>
#include <xen/sched.h>
#include <public/xenoprof.h>
+#include <asm/hvm/support.h>
#include "op_counter.h"
-/* Limit amount of pages used for shared buffer (per domain) */
-#define MAX_OPROF_SHARED_PAGES 32
-
-struct domain *active_domains[MAX_OPROF_DOMAINS];
-int active_ready[MAX_OPROF_DOMAINS];
-unsigned int adomains;
-
-struct domain *passive_domains[MAX_OPROF_DOMAINS];
-unsigned int pdomains;
-
-unsigned int activated;
-struct domain *primary_profiler;
-int xenoprof_state = XENOPROF_IDLE;
-
-u64 total_samples;
-u64 invalid_buffer_samples;
-u64 corrupted_buffer_samples;
-u64 lost_samples;
-u64 active_samples;
-u64 passive_samples;
-u64 idle_samples;
-u64 others_samples;
-
-
-extern int nmi_init(int *num_events, int *is_primary, char *cpu_type);
-extern int nmi_reserve_counters(void);
-extern int nmi_setup_events(void);
-extern int nmi_enable_virq(void);
-extern int nmi_start(void);
-extern void nmi_stop(void);
-extern void nmi_disable_virq(void);
-extern void nmi_release_counters(void);
-
-int is_active(struct domain *d)
-{
- struct xenoprof *x = d->xenoprof;
- return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE));
-}
-
-int is_passive(struct domain *d)
-{
- struct xenoprof *x = d->xenoprof;
- return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE));
-}
-
-int is_profiled(struct domain *d)
-{
- return (is_active(d) || is_passive(d));
-}
-
-static void xenoprof_reset_stat(void)
-{
- total_samples = 0;
- invalid_buffer_samples = 0;
- corrupted_buffer_samples = 0;
- lost_samples = 0;
- active_samples = 0;
- passive_samples = 0;
- idle_samples = 0;
- others_samples = 0;
-}
-
-static void xenoprof_reset_buf(struct domain *d)
-{
- int j;
- struct xenoprof_buf *buf;
-
- if ( d->xenoprof == NULL )
- {
- printk("xenoprof_reset_buf: ERROR - Unexpected "
- "Xenoprof NULL pointer \n");
- return;
- }
-
- for ( j = 0; j < MAX_VIRT_CPUS; j++ )
- {
- buf = d->xenoprof->vcpu[j].buffer;
- if ( buf != NULL )
- {
- buf->event_head = 0;
- buf->event_tail = 0;
- }
- }
-}
-
-char *alloc_xenoprof_buf(struct domain *d, int npages)
-{
- char *rawbuf;
- int i, order;
-
- /* allocate pages to store sample buffer shared with domain */
- order = get_order_from_pages(npages);
- rawbuf = alloc_xenheap_pages(order);
- if ( rawbuf == NULL )
- {
- printk("alloc_xenoprof_buf(): memory allocation failed\n");
- return 0;
- }
-
- /* Share pages so that kernel can map it */
- for ( i = 0; i < npages; i++ )
- share_xen_page_with_guest(
- virt_to_page(rawbuf + i * PAGE_SIZE),
- d, XENSHARE_writable);
-
- return rawbuf;
-}
-
-int alloc_xenoprof_struct(struct domain *d, int max_samples, int is_passive)
-{
- struct vcpu *v;
- int nvcpu, npages, bufsize, max_bufsize;
- int i;
-
- d->xenoprof = xmalloc(struct xenoprof);
-
- if ( d->xenoprof == NULL )
- {
- printk ("alloc_xenoprof_struct(): memory "
- "allocation (xmalloc) failed\n");
- return -ENOMEM;
- }
-
- memset(d->xenoprof, 0, sizeof(*d->xenoprof));
-
- nvcpu = 0;
- for_each_vcpu ( d, v )
- nvcpu++;
-
- /* reduce buffer size if necessary to limit pages allocated */
- bufsize = sizeof(struct xenoprof_buf) +
- (max_samples - 1) * sizeof(struct event_log);
- max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu;
- if ( bufsize > max_bufsize )
- {
- bufsize = max_bufsize;
- max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) /
- sizeof(struct event_log) ) + 1;
- }
-
- npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1;
-
- d->xenoprof->rawbuf = alloc_xenoprof_buf(is_passive ? dom0 : d, npages);
-
- if ( d->xenoprof->rawbuf == NULL )
- {
- xfree(d->xenoprof);
- d->xenoprof = NULL;
- return -ENOMEM;
- }
-
- d->xenoprof->npages = npages;
- d->xenoprof->nbuf = nvcpu;
- d->xenoprof->bufsize = bufsize;
- d->xenoprof->domain_ready = 0;
- d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
-
- /* Update buffer pointers for active vcpus */
- i = 0;
- for_each_vcpu ( d, v )
- {
- d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples;
- d->xenoprof->vcpu[v->vcpu_id].buffer =
- (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize];
- d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples;
- d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id;
-
- i++;
- /* in the unlikely case that the number of active vcpus changes */
- if ( i >= nvcpu )
- break;
- }
-
- return 0;
-}
-
-void free_xenoprof_pages(struct domain *d)
-{
- struct xenoprof *x;
- int order;
-
- x = d->xenoprof;
- if ( x == NULL )
- return;
-
- if ( x->rawbuf != NULL )
- {
- order = get_order_from_pages(x->npages);
- free_xenheap_pages(x->rawbuf, order);
- }
-
- xfree(x);
- d->xenoprof = NULL;
-}
-
-int active_index(struct domain *d)
-{
- int i;
-
- for ( i = 0; i < adomains; i++ )
- if ( active_domains[i] == d )
- return i;
-
- return -1;
-}
-
-int set_active(struct domain *d)
-{
- int ind;
- struct xenoprof *x;
-
- ind = active_index(d);
- if ( ind < 0 )
- return -EPERM;
-
- x = d->xenoprof;
- if ( x == NULL )
- return -EPERM;
-
- x->domain_ready = 1;
- x->domain_type = XENOPROF_DOMAIN_ACTIVE;
- active_ready[ind] = 1;
- activated++;
-
- return 0;
-}
-
-int reset_active(struct domain *d)
-{
- int ind;
- struct xenoprof *x;
-
- ind = active_index(d);
- if ( ind < 0 )
- return -EPERM;
-
- x = d->xenoprof;
- if ( x == NULL )
- return -EPERM;
-
- x->domain_ready = 0;
- x->domain_type = XENOPROF_DOMAIN_IGNORED;
- active_ready[ind] = 0;
- active_domains[ind] = NULL;
- activated--;
- put_domain(d);
-
- if ( activated <= 0 )
- adomains = 0;
-
- return 0;
-}
-
-void reset_passive(struct domain *d)
-{
- struct xenoprof *x;
-
- if (d==0)
- return;
-
- x = d->xenoprof;
- if ( x == NULL )
- return;
-
- x->domain_type = XENOPROF_DOMAIN_IGNORED;
-
- return;
-}
-
-void reset_active_list(void)
+int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg)
{
- int i;
+ struct xenoprof_counter counter;
- for ( i = 0; i < adomains; i++ )
- {
- if ( active_ready[i] )
- {
- reset_active(active_domains[i]);
- }
- }
-
- adomains = 0;
- activated = 0;
-}
-
-void reset_passive_list(void)
-{
- int i;
-
- for ( i = 0; i < pdomains; i++ )
- {
- reset_passive(passive_domains[i]);
- put_domain(passive_domains[i]);
- passive_domains[i] = NULL;
- }
-
- pdomains = 0;
-}
-
-int add_active_list (domid_t domid)
-{
- struct domain *d;
-
- if ( adomains >= MAX_OPROF_DOMAINS )
- return -E2BIG;
-
- d = find_domain_by_id(domid);
- if ( d == NULL )
- return -EINVAL;
-
- active_domains[adomains] = d;
- active_ready[adomains] = 0;
- adomains++;
-
- return 0;
-}
-
-int add_passive_list(XEN_GUEST_HANDLE(void) arg)
-{
- struct xenoprof_passive passive;
- struct domain *d;
- int ret = 0;
-
- if ( pdomains >= MAX_OPROF_DOMAINS )
- return -E2BIG;
-
- if ( copy_from_guest(&passive, arg, 1) )
- return -EFAULT;
-
- d = find_domain_by_id(passive.domain_id);
- if ( d == NULL )
- return -EINVAL;
-
- if ( (d->xenoprof == NULL) &&
- ((ret = alloc_xenoprof_struct(d, passive.max_samples, 1)) < 0) ) {
- put_domain(d);
- return -ENOMEM;
- }
-
- d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE;
- passive.nbuf = d->xenoprof->nbuf;
- passive.bufsize = d->xenoprof->bufsize;
- passive.buf_maddr = __pa(d->xenoprof->rawbuf);
-
- if ( copy_to_guest(arg, &passive, 1) ) {
- put_domain(d);
- return -EFAULT;
- }
-
- passive_domains[pdomains] = d;
- pdomains++;
-
- return ret;
-}
-
-void xenoprof_log_event(
- struct vcpu *vcpu, unsigned long eip, int mode, int event)
-{
- struct xenoprof_vcpu *v;
- struct xenoprof_buf *buf;
- int head;
- int tail;
- int size;
-
-
- total_samples++;
-
- /* ignore samples of un-monitored domains */
- /* Count samples in idle separate from other unmonitored domains */
- if ( !is_profiled(vcpu->domain) )
- {
- others_samples++;
- return;
- }
-
- v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id];
-
- /* Sanity check. Should never happen */
- if ( v->buffer == NULL )
- {
- invalid_buffer_samples++;
- return;
- }
-
- buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer;
-
- head = buf->event_head;
- tail = buf->event_tail;
- size = v->event_size;
-
- /* make sure indexes in shared buffer are sane */
- if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
- {
- corrupted_buffer_samples++;
- return;
- }
-
- if ( (head == tail - 1) || (head == size - 1 && tail == 0) )
- {
- buf->lost_samples++;
- lost_samples++;
- }
- else
- {
- buf->event_log[head].eip = eip;
- buf->event_log[head].mode = mode;
- buf->event_log[head].event = event;
- head++;
- if ( head >= size )
- head = 0;
- buf->event_head = head;
- if ( is_active(vcpu->domain) )
- active_samples++;
- else
- passive_samples++;
- if ( mode == 0 )
- buf->user_samples++;
- else if ( mode == 1 )
- buf->kernel_samples++;
- else
- buf->xen_samples++;
- }
-}
-
-int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg)
-{
- struct xenoprof_init xenoprof_init;
- int ret;
-
- if ( copy_from_guest(&xenoprof_init, arg, 1) )
+ if ( copy_from_guest(&counter, arg, 1) )
return -EFAULT;
- if ( (ret = nmi_init(&xenoprof_init.num_events,
- &xenoprof_init.is_primary,
- xenoprof_init.cpu_type)) )
- return ret;
-
- if ( copy_to_guest(arg, &xenoprof_init, 1) )
- return -EFAULT;
+ if ( counter.ind > OP_MAX_COUNTER )
+ return -E2BIG;
- if ( xenoprof_init.is_primary )
- primary_profiler = current->domain;
+ counter_config[counter.ind].count = counter.count;
+ counter_config[counter.ind].enabled = counter.enabled;
+ counter_config[counter.ind].event = counter.event;
+ counter_config[counter.ind].kernel = counter.kernel;
+ counter_config[counter.ind].user = counter.user;
+ counter_config[counter.ind].unit_mask = counter.unit_mask;
return 0;
}
-int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg)
+int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs)
{
- struct xenoprof_get_buffer xenoprof_get_buffer;
- struct domain *d = current->domain;
- int ret;
-
- if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) )
- return -EFAULT;
-
- /*
- * We allocate xenoprof struct and buffers only at first time xenoprof_get_buffer
- * is called. Memory is then kept until domain is destroyed.
- */
- if ( (d->xenoprof == NULL) &&
- ((ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0)) < 0) )
- return ret;
-
- xenoprof_reset_buf(d);
-
- d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
- d->xenoprof->domain_ready = 0;
- if ( primary_profiler == current->domain )
- d->xenoprof->is_primary = 1;
- else
- d->xenoprof->is_primary = 0;
-
- xenoprof_get_buffer.nbuf = d->xenoprof->nbuf;
- xenoprof_get_buffer.bufsize = d->xenoprof->bufsize;
- xenoprof_get_buffer.buf_maddr = __pa(d->xenoprof->rawbuf);
-
- if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) )
- return -EFAULT;
-
- return 0;
-}
-
-#define PRIV_OP(op) ( (op == XENOPROF_set_active) \
- || (op == XENOPROF_reserve_counters) \
- || (op == XENOPROF_setup_events) \
- || (op == XENOPROF_start) \
- || (op == XENOPROF_stop) \
- || (op == XENOPROF_release_counters) \
- || (op == XENOPROF_shutdown))
-
-int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
-{
- int ret = 0;
-
- if ( PRIV_OP(op) && (current->domain != primary_profiler) )
- {
- printk("xenoprof: dom %d denied privileged operation %d\n",
- current->domain->domain_id, op);
- return -EPERM;
- }
-
- switch ( op )
- {
- case XENOPROF_init:
- ret = xenoprof_op_init(arg);
- break;
-
- case XENOPROF_get_buffer:
- ret = xenoprof_op_get_buffer(arg);
- break;
-
- case XENOPROF_reset_active_list:
- {
- reset_active_list();
- ret = 0;
- break;
- }
- case XENOPROF_reset_passive_list:
- {
- reset_passive_list();
- ret = 0;
- break;
- }
- case XENOPROF_set_active:
- {
- domid_t domid;
- if ( xenoprof_state != XENOPROF_IDLE )
- return -EPERM;
- if ( copy_from_guest(&domid, arg, 1) )
- return -EFAULT;
- ret = add_active_list(domid);
- break;
- }
- case XENOPROF_set_passive:
- {
- if ( xenoprof_state != XENOPROF_IDLE )
- return -EPERM;
- ret = add_passive_list(arg);
- break;
- }
- case XENOPROF_reserve_counters:
- if ( xenoprof_state != XENOPROF_IDLE )
- return -EPERM;
- ret = nmi_reserve_counters();
- if ( !ret )
- xenoprof_state = XENOPROF_COUNTERS_RESERVED;
- break;
-
- case XENOPROF_counter:
- {
- struct xenoprof_counter counter;
- if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED )
- return -EPERM;
- if ( adomains == 0 )
- return -EPERM;
-
- if ( copy_from_guest(&counter, arg, 1) )
- return -EFAULT;
-
- if ( counter.ind > OP_MAX_COUNTER )
- return -E2BIG;
-
- counter_config[counter.ind].count = (unsigned long) counter.count;
- counter_config[counter.ind].enabled = (unsigned long) counter.enabled;
- counter_config[counter.ind].event = (unsigned long) counter.event;
- counter_config[counter.ind].kernel = (unsigned long) counter.kernel;
- counter_config[counter.ind].user = (unsigned long) counter.user;
- counter_config[counter.ind].unit_mask = (unsigned long) counter.unit_mask;
-
- ret = 0;
- break;
- }
-
- case XENOPROF_setup_events:
- if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED )
- return -EPERM;
- ret = nmi_setup_events();
- if ( !ret )
- xenoprof_state = XENOPROF_READY;
- break;
-
- case XENOPROF_enable_virq:
- {
- int i;
- if ( current->domain == primary_profiler )
- {
- nmi_enable_virq();
- xenoprof_reset_stat();
- for ( i = 0; i < pdomains; i++ ) {
- xenoprof_reset_buf(passive_domains[i]);
- }
- }
- xenoprof_reset_buf(current->domain);
- ret = set_active(current->domain);
- break;
- }
-
- case XENOPROF_start:
- ret = -EPERM;
- if ( (xenoprof_state == XENOPROF_READY) &&
- (activated == adomains) )
- ret = nmi_start();
-
- if ( ret == 0 )
- xenoprof_state = XENOPROF_PROFILING;
- break;
-
- case XENOPROF_stop:
- if ( xenoprof_state != XENOPROF_PROFILING )
- return -EPERM;
- nmi_stop();
- xenoprof_state = XENOPROF_READY;
- break;
-
- case XENOPROF_disable_virq:
- if ( (xenoprof_state == XENOPROF_PROFILING) &&
- (is_active(current->domain)) )
- return -EPERM;
- ret = reset_active(current->domain);
- break;
-
- case XENOPROF_release_counters:
- ret = -EPERM;
- if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) ||
- (xenoprof_state == XENOPROF_READY) )
- {
- xenoprof_state = XENOPROF_IDLE;
- nmi_release_counters();
- nmi_disable_virq();
- reset_passive_list();
- ret = 0;
- }
- break;
-
- case XENOPROF_shutdown:
- ret = -EPERM;
- if ( xenoprof_state == XENOPROF_IDLE )
- {
- activated = 0;
- adomains=0;
- primary_profiler = NULL;
- ret = 0;
- }
- break;
-
- default:
- ret = -EINVAL;
- }
+ if ( !guest_mode(regs) )
+ return 2;
- if ( ret < 0 )
- printk("xenoprof: operation %d failed for dom %d (status : %d)\n",
- op, current->domain->domain_id, ret);
+ if ( is_hvm_vcpu(v) )
+ return ((regs->cs & 3) != 3);
- return ret;
+ return guest_kernel_mode(v, regs);
}
/*
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index 2d4841a039..d24aad62aa 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -125,7 +125,7 @@ long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
if ( copy_from_guest(&set_iobitmap, arg, 1) != 0 )
break;
ret = -EINVAL;
- if ( !access_ok(set_iobitmap.bitmap, IOBMP_BYTES) ||
+ if ( !guest_handle_okay(set_iobitmap.bitmap, IOBMP_BYTES) ||
(set_iobitmap.nr_ports > 65536) )
break;
ret = 0;
@@ -135,7 +135,7 @@ long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
}
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index 098c847112..7d2ee6f496 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -58,12 +58,13 @@ long do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
op->u.add_memtype.nr_mfns,
op->u.add_memtype.type,
1);
- if ( ret > 0 )
+ if ( ret >= 0 )
{
op->u.add_memtype.handle = 0;
op->u.add_memtype.reg = ret;
- (void)copy_to_guest(u_xenpf_op, op, 1);
- ret = 0;
+ ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
+ if ( ret != 0 )
+ mtrr_del_page(ret, 0, 0);
}
}
break;
@@ -75,7 +76,7 @@ long do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
&& (int)op->u.del_memtype.reg >= 0)
{
ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
- if (ret > 0)
+ if ( ret > 0 )
ret = 0;
}
else
@@ -96,16 +97,15 @@ long do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
op->u.read_memtype.mfn = mfn;
op->u.read_memtype.nr_mfns = nr_mfns;
op->u.read_memtype.type = type;
- (void)copy_to_guest(u_xenpf_op, op, 1);
- ret = 0;
+ ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
}
}
break;
case XENPF_microcode_update:
{
- extern int microcode_update(void *buf, unsigned long len);
- ret = microcode_update(op->u.microcode.data.p,
+ extern int microcode_update(XEN_GUEST_HANDLE(void), unsigned long len);
+ ret = microcode_update(op->u.microcode.data,
op->u.microcode.length);
}
break;
@@ -125,7 +125,7 @@ long do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
case QUIRK_IOAPIC_GOOD_REGSEL:
#ifndef sis_apic_bug
sis_apic_bug = (quirk_id == QUIRK_IOAPIC_BAD_REGSEL);
- DPRINTK("Domain 0 says that IO-APIC REGSEL is %s\n",
+ dprintk(XENLOG_INFO, "Domain 0 says that IO-APIC REGSEL is %s\n",
sis_apic_bug ? "bad" : "good");
#else
BUG_ON(sis_apic_bug != (quirk_id == QUIRK_IOAPIC_BAD_REGSEL));
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 6507d6fa86..e144b6ca47 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1,4 +1,3 @@
-
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
@@ -16,6 +15,8 @@
#include <xen/gdbstub.h>
#include <xen/percpu.h>
#include <xen/hypercall.h>
+#include <xen/keyhandler.h>
+#include <xen/numa.h>
#include <public/version.h>
#include <asm/bitops.h>
#include <asm/smp.h>
@@ -29,6 +30,7 @@
extern void dmi_scan_machine(void);
extern void generic_apic_probe(void);
+extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
/*
* opt_xenheap_megabytes: Size of Xen heap in megabytes, excluding the
@@ -81,7 +83,6 @@ extern void arch_init_memory(void);
extern void init_IRQ(void);
extern void trap_init(void);
extern void early_time_init(void);
-extern void initialize_keytable(void);
extern void early_cpu_init(void);
struct tss_struct init_tss[NR_CPUS];
@@ -203,6 +204,44 @@ static void __init percpu_free_unused_areas(void)
#endif
}
+/* Fetch acm policy module from multiboot modules. */
+static void extract_acm_policy(
+ multiboot_info_t *mbi,
+ unsigned int *initrdidx,
+ char **_policy_start,
+ unsigned long *_policy_len)
+{
+ int i;
+ module_t *mod = (module_t *)__va(mbi->mods_addr);
+ unsigned long start, policy_len;
+ char *policy_start;
+
+ /*
+ * Try all modules and see whichever could be the binary policy.
+ * Adjust the initrdidx if module[1] is the binary policy.
+ */
+ for ( i = mbi->mods_count-1; i >= 1; i-- )
+ {
+ start = initial_images_start + (mod[i].mod_start-mod[0].mod_start);
+#if defined(__i386__)
+ policy_start = (char *)start;
+#elif defined(__x86_64__)
+ policy_start = __va(start);
+#endif
+ policy_len = mod[i].mod_end - mod[i].mod_start;
+ if ( acm_is_policy(policy_start, policy_len) )
+ {
+ printk("Policy len 0x%lx, start at %p - module %d.\n",
+ policy_len, policy_start, i);
+ *_policy_start = policy_start;
+ *_policy_len = policy_len;
+ if ( i == 1 )
+ *initrdidx = (mbi->mods_count > 2) ? 2 : 0;
+ break;
+ }
+ }
+}
+
static void __init init_idle_domain(void)
{
struct domain *idle_domain;
@@ -210,7 +249,7 @@ static void __init init_idle_domain(void)
/* Domain creation requires that scheduler structures are initialised. */
scheduler_init();
- idle_domain = domain_create(IDLE_DOMAIN_ID);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
BUG();
@@ -220,11 +259,27 @@ static void __init init_idle_domain(void)
setup_idle_pagetable();
}
+static void srat_detect_node(int cpu)
+{
+ unsigned node;
+ u8 apicid = x86_cpu_to_apicid[cpu];
+
+ node = apicid_to_node[apicid];
+ if ( node == NUMA_NO_NODE )
+ node = 0;
+ numa_set_node(cpu, node);
+
+ if ( acpi_numa > 0 )
+ printk(KERN_INFO "CPU %d APIC %d -> Node %d\n", cpu, apicid, node);
+}
+
void __init __start_xen(multiboot_info_t *mbi)
{
char __cmdline[] = "", *cmdline = __cmdline;
unsigned long _initrd_start = 0, _initrd_len = 0;
unsigned int initrdidx = 1;
+ char *_policy_start = NULL;
+ unsigned long _policy_len = 0;
module_t *mod = (module_t *)__va(mbi->mods_addr);
unsigned long nr_pages, modules_length;
paddr_t s, e;
@@ -257,7 +312,7 @@ void __init __start_xen(multiboot_info_t *mbi)
init_console();
- printf("Command line: %s\n", cmdline);
+ printk("Command line: %s\n", cmdline);
/* Check that we have at least one Multiboot module. */
if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
@@ -273,6 +328,13 @@ void __init __start_xen(multiboot_info_t *mbi)
EARLY_FAIL();
}
+ /*
+ * Since there are some stubs getting built on the stacks which use
+ * direct calls/jumps, the heap must be confined to the lower 2G so
+ * that those branches can reach their targets.
+ */
+ if ( opt_xenheap_megabytes > 2048 )
+ opt_xenheap_megabytes = 2048;
xenheap_phys_end = opt_xenheap_megabytes << 20;
if ( mbi->flags & MBI_MEMMAP )
@@ -301,7 +363,7 @@ void __init __start_xen(multiboot_info_t *mbi)
e820_raw[e820_raw_nr].size =
((u64)map->length_high << 32) | (u64)map->length_low;
e820_raw[e820_raw_nr].type =
- (map->type > E820_SHARED_PAGE) ? E820_RESERVED : map->type;
+ (map->type > E820_NVS) ? E820_RESERVED : map->type;
e820_raw_nr++;
bytes += map->size + 4;
@@ -439,6 +501,12 @@ void __init __start_xen(multiboot_info_t *mbi)
init_frametable();
+ acpi_boot_table_init();
+
+ acpi_numa_init();
+
+ numa_initmem_init(0, max_page);
+
end_boot_allocator();
/* Initialise the Xen heap, skipping RAM holes. */
@@ -490,9 +558,10 @@ void __init __start_xen(multiboot_info_t *mbi)
generic_apic_probe();
- acpi_boot_table_init();
acpi_boot_init();
+ init_cpu_to_node();
+
if ( smp_found_config )
get_smp_config();
@@ -543,6 +612,11 @@ void __init __start_xen(multiboot_info_t *mbi)
break;
if ( !cpu_online(i) )
__cpu_up(i);
+
+ /* Set up cpu_to_node[]. */
+ srat_detect_node(i);
+ /* Set up node_to_cpumask based on cpu_to_node[]. */
+ numa_add_cpu(i);
}
printk("Brought up %ld CPUs\n", (long)num_online_cpus());
@@ -559,16 +633,20 @@ void __init __start_xen(multiboot_info_t *mbi)
if ( opt_watchdog )
watchdog_enable();
+ /* Extract policy from multiboot. */
+ extract_acm_policy(mbi, &initrdidx, &_policy_start, &_policy_len);
+
/* initialize access control security module */
- acm_init(&initrdidx, mbi, initial_images_start);
+ acm_init(_policy_start, _policy_len);
/* Create initial domain 0. */
- dom0 = domain_create(0);
+ dom0 = domain_create(0, 0);
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
- set_bit(_DOMF_privileged, &dom0->domain_flags);
- /* post-create hooks sets security label */
+ dom0->is_privileged = 1;
+
+ /* Post-create hook sets security label. */
acm_post_domain0_create(dom0->domain_id);
/* Grab the DOM0 command line. */
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index 27dc4daf87..2d14240039 100644
--- a/xen/arch/x86/smp.c
+++ b/xen/arch/x86/smp.c
@@ -21,6 +21,7 @@
#include <asm/smpboot.h>
#include <asm/hardirq.h>
#include <asm/ipi.h>
+#include <asm/hvm/hvm.h>
#include <mach_apic.h>
/*
@@ -306,6 +307,7 @@ static void stop_this_cpu (void *dummy)
local_irq_disable();
disable_local_APIC();
+ hvm_disable();
for ( ; ; )
__asm__ __volatile__ ( "hlt" );
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 39cbbd9282..f7d8712563 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -43,6 +43,7 @@
#include <xen/delay.h>
#include <xen/softirq.h>
#include <xen/serial.h>
+#include <xen/numa.h>
#include <asm/current.h>
#include <asm/mc146818rtc.h>
#include <asm/desc.h>
@@ -628,7 +629,7 @@ u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICI
static void map_cpu_to_logical_apicid(void)
{
int cpu = smp_processor_id();
- int apicid = logical_smp_processor_id();
+ int apicid = hard_smp_processor_id();
cpu_2_logical_apicid[cpu] = apicid;
map_cpu_to_node(cpu, apicid_to_node(apicid));
@@ -982,7 +983,6 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
* Cycle through the processors sending APIC IPIs to boot each.
*/
-static int boot_cpu_logical_apicid;
/* Where the IO area was mapped on multiquad, always 0 otherwise */
void *xquad_portio;
#ifdef CONFIG_X86_NUMAQ
@@ -1004,7 +1004,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
print_cpu_info(&cpu_data[0]);
boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
- boot_cpu_logical_apicid = logical_smp_processor_id();
x86_cpu_to_apicid[0] = boot_cpu_physical_apicid;
/*current_thread_info()->cpu = 0;*/
diff --git a/xen/arch/x86/srat.c b/xen/arch/x86/srat.c
new file mode 100644
index 0000000000..ea462e222b
--- /dev/null
+++ b/xen/arch/x86/srat.c
@@ -0,0 +1,315 @@
+/*
+ * ACPI 3.0 based NUMA setup
+ * Copyright 2004 Andi Kleen, SuSE Labs.
+ *
+ * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
+ *
+ * Called from acpi_numa_init while reading the SRAT and SLIT tables.
+ * Assumes all memory regions belonging to a single proximity domain
+ * are in one chunk. Holes between them will be included in the node.
+ *
+ * Adapted for Xen: Ryan Harper <ryanh@us.ibm.com>
+ */
+
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/inttypes.h>
+#include <xen/nodemask.h>
+#include <xen/acpi.h>
+#include <xen/numa.h>
+#include <asm/page.h>
+
+static struct acpi_table_slit *acpi_slit;
+
+static nodemask_t nodes_parsed __initdata;
+static nodemask_t nodes_found __initdata;
+static struct node nodes[MAX_NUMNODES] __initdata;
+static u8 pxm2node[256] = { [0 ... 255] = 0xff };
+
+/* Too small nodes confuse the VM badly. Usually they result
+ from BIOS bugs. */
+#define NODE_MIN_SIZE (4*1024*1024)
+
+static int node_to_pxm(int n);
+
+int pxm_to_node(int pxm)
+{
+ if ((unsigned)pxm >= 256)
+ return -1;
+ /* Extend 0xff to (int)-1 */
+ return (signed char)pxm2node[pxm];
+}
+
+static __init int setup_node(int pxm)
+{
+ unsigned node = pxm2node[pxm];
+ if (node == 0xff) {
+ if (nodes_weight(nodes_found) >= MAX_NUMNODES)
+ return -1;
+ node = first_unset_node(nodes_found);
+ node_set(node, nodes_found);
+ pxm2node[pxm] = node;
+ }
+ return pxm2node[pxm];
+}
+
+static __init int conflicting_nodes(u64 start, u64 end)
+{
+ int i;
+ for_each_node_mask(i, nodes_parsed) {
+ struct node *nd = &nodes[i];
+ if (nd->start == nd->end)
+ continue;
+ if (nd->end > start && nd->start < end)
+ return i;
+ if (nd->end == end && nd->start == start)
+ return i;
+ }
+ return -1;
+}
+
+static __init void cutoff_node(int i, u64 start, u64 end)
+{
+ struct node *nd = &nodes[i];
+ if (nd->start < start) {
+ nd->start = start;
+ if (nd->end < nd->start)
+ nd->start = nd->end;
+ }
+ if (nd->end > end) {
+ nd->end = end;
+ if (nd->start > nd->end)
+ nd->start = nd->end;
+ }
+}
+
+static __init void bad_srat(void)
+{
+ int i;
+ printk(KERN_ERR "SRAT: SRAT not used.\n");
+ acpi_numa = -1;
+ for (i = 0; i < MAX_LOCAL_APIC; i++)
+ apicid_to_node[i] = NUMA_NO_NODE;
+}
+
+static __init inline int srat_disabled(void)
+{
+ return numa_off || acpi_numa < 0;
+}
+
+/*
+ * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
+ * up the NUMA heuristics which wants the local node to have a smaller
+ * distance than the others.
+ * Do some quick checks here and only use the SLIT if it passes.
+ */
+static __init int slit_valid(struct acpi_table_slit *slit)
+{
+ int i, j;
+ int d = slit->localities;
+ for (i = 0; i < d; i++) {
+ for (j = 0; j < d; j++) {
+ u8 val = slit->entry[d*i + j];
+ if (i == j) {
+ if (val != 10)
+ return 0;
+ } else if (val <= 10)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Callback for SLIT parsing */
+void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
+{
+ if (!slit_valid(slit)) {
+ printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
+ return;
+ }
+ acpi_slit = slit;
+}
+
+/* Callback for Proximity Domain -> LAPIC mapping */
+void __init
+acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+{
+ int pxm, node;
+ if (srat_disabled())
+ return;
+ if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) { bad_srat();
+ return;
+ }
+ if (pa->flags.enabled == 0)
+ return;
+ pxm = pa->proximity_domain;
+ node = setup_node(pxm);
+ if (node < 0) {
+ printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
+ bad_srat();
+ return;
+ }
+ apicid_to_node[pa->apic_id] = node;
+ acpi_numa = 1;
+ printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
+ pxm, pa->apic_id, node);
+}
+
+/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
+void __init
+acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+{
+ struct node *nd;
+ u64 start, end;
+ int node, pxm;
+ int i;
+
+ if (srat_disabled())
+ return;
+ if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) {
+ bad_srat();
+ return;
+ }
+ if (ma->flags.enabled == 0)
+ return;
+ start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
+ end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
+ pxm = ma->proximity_domain;
+ node = setup_node(pxm);
+ if (node < 0) {
+ printk(KERN_ERR "SRAT: Too many proximity domains.\n");
+ bad_srat();
+ return;
+ }
+ /* It is fine to add this area to the nodes data it will be used later*/
+ if (ma->flags.hot_pluggable == 1)
+ printk(KERN_INFO "SRAT: hot plug zone found %"PRIx64" - %"PRIx64" \n",
+ start, end);
+ i = conflicting_nodes(start, end);
+ if (i == node) {
+ printk(KERN_WARNING
+ "SRAT: Warning: PXM %d (%"PRIx64"-%"PRIx64") overlaps with itself (%"
+ PRIx64"-%"PRIx64")\n", pxm, start, end, nodes[i].start, nodes[i].end);
+ } else if (i >= 0) {
+ printk(KERN_ERR
+ "SRAT: PXM %d (%"PRIx64"-%"PRIx64") overlaps with PXM %d (%"
+ PRIx64"-%"PRIx64")\n", pxm, start, end, node_to_pxm(i),
+ nodes[i].start, nodes[i].end);
+ bad_srat();
+ return;
+ }
+ nd = &nodes[node];
+ if (!node_test_and_set(node, nodes_parsed)) {
+ nd->start = start;
+ nd->end = end;
+ } else {
+ if (start < nd->start)
+ nd->start = start;
+ if (nd->end < end)
+ nd->end = end;
+ }
+ printk(KERN_INFO "SRAT: Node %u PXM %u %"PRIx64"-%"PRIx64"\n", node, pxm,
+ nd->start, nd->end);
+}
+
+/* Sanity check to catch more bad SRATs (they are amazingly common).
+ Make sure the PXMs cover all memory. */
+static int nodes_cover_memory(void)
+{
+ int i;
+ u64 pxmram, e820ram;
+
+ pxmram = 0;
+ for_each_node_mask(i, nodes_parsed) {
+ u64 s = nodes[i].start >> PAGE_SHIFT;
+ u64 e = nodes[i].end >> PAGE_SHIFT;
+ pxmram += e - s;
+ }
+
+ e820ram = max_page;
+ /* We seem to lose 3 pages somewhere. Allow a bit of slack. */
+ if ((long)(e820ram - pxmram) >= 1*1024*1024) {
+ printk(KERN_ERR "SRAT: PXMs only cover %"PRIu64"MB of your %"
+ PRIu64"MB e820 RAM. Not used.\n",
+ (pxmram << PAGE_SHIFT) >> 20,
+ (e820ram << PAGE_SHIFT) >> 20);
+ return 0;
+ }
+ return 1;
+}
+
+static void unparse_node(int node)
+{
+ int i;
+ node_clear(node, nodes_parsed);
+ for (i = 0; i < MAX_LOCAL_APIC; i++) {
+ if (apicid_to_node[i] == node)
+ apicid_to_node[i] = NUMA_NO_NODE;
+ }
+}
+
+void __init acpi_numa_arch_fixup(void) {}
+
+/* Use the information discovered above to actually set up the nodes. */
+int __init acpi_scan_nodes(u64 start, u64 end)
+{
+ int i;
+
+ /* First clean up the node list */
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ cutoff_node(i, start, end);
+ if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE)
+ unparse_node(i);
+ }
+
+ if (acpi_numa <= 0)
+ return -1;
+
+ if (!nodes_cover_memory()) {
+ bad_srat();
+ return -1;
+ }
+
+ memnode_shift = compute_hash_shift(nodes, MAX_NUMNODES);
+ if (memnode_shift < 0) {
+ printk(KERN_ERR
+ "SRAT: No NUMA node hash function found. Contact maintainer\n");
+ bad_srat();
+ return -1;
+ }
+
+ /* Finally register nodes */
+ for_each_node_mask(i, nodes_parsed)
+ setup_node_bootmem(i, nodes[i].start, nodes[i].end);
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_to_node[i] == NUMA_NO_NODE)
+ continue;
+ if (!node_isset(cpu_to_node[i], nodes_parsed))
+ numa_set_node(i, NUMA_NO_NODE);
+ }
+ numa_init_array();
+ return 0;
+}
+
+static int node_to_pxm(int n)
+{
+ int i;
+ if (pxm2node[n] == n)
+ return n;
+ for (i = 0; i < 256; i++)
+ if (pxm2node[i] == n)
+ return i;
+ return 0;
+}
+
+int __node_distance(int a, int b)
+{
+ int index;
+
+ if (!acpi_slit)
+ return a == b ? 10 : 20;
+ index = acpi_slit->localities * node_to_pxm(a);
+ return acpi_slit->entry[index + node_to_pxm(b)];
+}
+
+EXPORT_SYMBOL(__node_distance);
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 6191af3ef3..970a742efc 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -919,6 +919,13 @@ void send_timer_event(struct vcpu *v)
send_guest_vcpu_virq(v, VIRQ_TIMER);
}
+/* Return secs after 00:00:00 localtime, 1 January, 1970. */
+unsigned long get_localtime(struct domain *d)
+{
+ return wc_sec + (wc_nsec + NOW()) / 1000000000ULL
+ + d->time_offset_seconds;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 07486ddcdd..87f3f79491 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -134,7 +134,7 @@ static void show_guest_stack(struct cpu_user_regs *regs)
int i;
unsigned long *stack, addr;
- if ( hvm_guest(current) )
+ if ( is_hvm_vcpu(current) )
return;
if ( vm86_mode(regs) )
@@ -331,15 +331,9 @@ void show_execution_state(struct cpu_user_regs *regs)
show_stack(regs);
}
-/*
- * This is called for faults at very unexpected times (e.g., when interrupts
- * are disabled). In such situations we can't do much that is safe. We try to
- * print out some tracing and then we just spin.
- */
-asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
+char *trapstr(int trapnr)
{
- int cpu = smp_processor_id();
- static char *trapstr[] = {
+ static char *strings[] = {
"divide error", "debug", "nmi", "bkpt", "overflow", "bounds",
"invalid opcode", "device not available", "double fault",
"coprocessor segment", "invalid tss", "segment not found",
@@ -348,6 +342,19 @@ asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
"machine check", "simd error"
};
+ if ( (trapnr < 0) || (trapnr >= ARRAY_SIZE(strings)) )
+ return "???";
+
+ return strings[trapnr];
+}
+
+/*
+ * This is called for faults at very unexpected times (e.g., when interrupts
+ * are disabled). In such situations we can't do much that is safe. We try to
+ * print out some tracing and then we just spin.
+ */
+asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
+{
watchdog_disable();
console_start_sync();
@@ -360,54 +367,58 @@ asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
show_page_walk(cr2);
}
- printk("************************************\n");
- printk("CPU%d FATAL TRAP %d (%s), ERROR_CODE %04x%s.\n",
- cpu, trapnr, trapstr[trapnr], regs->error_code,
- (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT");
- printk("System shutting down -- need manual reset.\n");
- printk("************************************\n");
-
- (void)debugger_trap_fatal(trapnr, regs);
-
- /* Lock up the console to prevent spurious output from other CPUs. */
- console_force_lock();
-
- /* Wait for manual reset. */
- machine_halt();
+ panic("FATAL TRAP: vector = %d (%s)\n"
+ "[error_code=%04x] %s\n",
+ trapnr, trapstr(trapnr), regs->error_code,
+ (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT");
}
-static inline int do_trap(int trapnr, char *str,
- struct cpu_user_regs *regs,
- int use_error_code)
+static int do_guest_trap(
+ int trapnr, const struct cpu_user_regs *regs, int use_error_code)
{
struct vcpu *v = current;
- struct trap_bounce *tb = &v->arch.trap_bounce;
- struct trap_info *ti;
- unsigned long fixup;
-
- DEBUGGER_trap_entry(trapnr, regs);
+ struct trap_bounce *tb;
+ const struct trap_info *ti;
- if ( !guest_mode(regs) )
- goto xen_fault;
+ tb = &v->arch.trap_bounce;
+ ti = &v->arch.guest_context.trap_ctxt[trapnr];
- ti = &current->arch.guest_context.trap_ctxt[trapnr];
tb->flags = TBF_EXCEPTION;
tb->cs = ti->cs;
tb->eip = ti->address;
+
if ( use_error_code )
{
tb->flags |= TBF_EXCEPTION_ERRCODE;
tb->error_code = regs->error_code;
}
+
if ( TI_GET_IF(ti) )
tb->flags |= TBF_INTERRUPT;
+
+ if ( unlikely(null_trap_bounce(tb)) )
+ gdprintk(XENLOG_WARNING, "Unhandled %s fault/trap [#%d] in "
+ "domain %d on VCPU %d [ec=%04x]\n",
+ trapstr(trapnr), trapnr, v->domain->domain_id, v->vcpu_id,
+ regs->error_code);
+
return 0;
+}
+
+static inline int do_trap(
+ int trapnr, struct cpu_user_regs *regs, int use_error_code)
+{
+ unsigned long fixup;
- xen_fault:
+ DEBUGGER_trap_entry(trapnr, regs);
+
+ if ( guest_mode(regs) )
+ return do_guest_trap(trapnr, regs, use_error_code);
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
- DPRINTK("Trap %d: %p -> %p\n", trapnr, _p(regs->eip), _p(fixup));
+ dprintk(XENLOG_ERR, "Trap %d: %p -> %p\n",
+ trapnr, _p(regs->eip), _p(fixup));
regs->eip = fixup;
return 0;
}
@@ -415,34 +426,34 @@ static inline int do_trap(int trapnr, char *str,
DEBUGGER_trap_fatal(trapnr, regs);
show_execution_state(regs);
- panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
+ panic("FATAL TRAP: vector = %d (%s)\n"
"[error_code=%04x]\n",
- smp_processor_id(), trapnr, str, regs->error_code);
+ trapnr, trapstr(trapnr), regs->error_code);
return 0;
}
-#define DO_ERROR_NOCODE(trapnr, str, name) \
+#define DO_ERROR_NOCODE(trapnr, name) \
asmlinkage int do_##name(struct cpu_user_regs *regs) \
{ \
- return do_trap(trapnr, str, regs, 0); \
+ return do_trap(trapnr, regs, 0); \
}
-#define DO_ERROR(trapnr, str, name) \
+#define DO_ERROR(trapnr, name) \
asmlinkage int do_##name(struct cpu_user_regs *regs) \
{ \
- return do_trap(trapnr, str, regs, 1); \
+ return do_trap(trapnr, regs, 1); \
}
-DO_ERROR_NOCODE( 0, "divide error", divide_error)
-DO_ERROR_NOCODE( 4, "overflow", overflow)
-DO_ERROR_NOCODE( 5, "bounds", bounds)
-DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
-DO_ERROR(10, "invalid TSS", invalid_TSS)
-DO_ERROR(11, "segment not present", segment_not_present)
-DO_ERROR(12, "stack segment", stack_segment)
-DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
-DO_ERROR(17, "alignment check", alignment_check)
-DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
+DO_ERROR_NOCODE(TRAP_divide_error, divide_error)
+DO_ERROR_NOCODE(TRAP_overflow, overflow)
+DO_ERROR_NOCODE(TRAP_bounds, bounds)
+DO_ERROR_NOCODE(TRAP_copro_seg, coprocessor_segment_overrun)
+DO_ERROR( TRAP_invalid_tss, invalid_TSS)
+DO_ERROR( TRAP_no_segment, segment_not_present)
+DO_ERROR( TRAP_stack_error, stack_segment)
+DO_ERROR_NOCODE(TRAP_copro_error, coprocessor_error)
+DO_ERROR( TRAP_alignment_check, alignment_check)
+DO_ERROR_NOCODE(TRAP_simd_error, simd_coprocessor_error)
int rdmsr_hypervisor_regs(
uint32_t idx, uint32_t *eax, uint32_t *edx)
@@ -475,7 +486,8 @@ int wrmsr_hypervisor_regs(
if ( idx > 0 )
{
- DPRINTK("Dom%d: Out of range index %u to MSR %08x\n",
+ gdprintk(XENLOG_WARNING,
+ "Dom%d: Out of range index %u to MSR %08x\n",
d->domain_id, idx, 0x40000000);
return 0;
}
@@ -485,7 +497,8 @@ int wrmsr_hypervisor_regs(
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
- DPRINTK("Dom%d: Bad GMFN %lx (MFN %lx) to MSR %08x\n",
+ gdprintk(XENLOG_WARNING,
+ "Dom%d: Bad GMFN %lx (MFN %lx) to MSR %08x\n",
d->domain_id, gmfn, mfn, 0x40000000);
return 0;
}
@@ -607,9 +620,6 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
asmlinkage int do_invalid_op(struct cpu_user_regs *regs)
{
- struct vcpu *v = current;
- struct trap_bounce *tb = &v->arch.trap_bounce;
- struct trap_info *ti;
int rc;
DEBUGGER_trap_entry(TRAP_invalid_op, regs);
@@ -627,46 +637,27 @@ asmlinkage int do_invalid_op(struct cpu_user_regs *regs)
}
DEBUGGER_trap_fatal(TRAP_invalid_op, regs);
show_execution_state(regs);
- panic("CPU%d FATAL TRAP: vector = %d (invalid opcode)\n",
- smp_processor_id(), TRAP_invalid_op);
+ panic("FATAL TRAP: vector = %d (invalid opcode)\n", TRAP_invalid_op);
}
if ( (rc = emulate_forced_invalid_op(regs)) != 0 )
return rc;
- ti = &current->arch.guest_context.trap_ctxt[TRAP_invalid_op];
- tb->flags = TBF_EXCEPTION;
- tb->cs = ti->cs;
- tb->eip = ti->address;
- if ( TI_GET_IF(ti) )
- tb->flags |= TBF_INTERRUPT;
-
- return 0;
+ return do_guest_trap(TRAP_invalid_op, regs, 0);
}
asmlinkage int do_int3(struct cpu_user_regs *regs)
{
- struct vcpu *v = current;
- struct trap_bounce *tb = &v->arch.trap_bounce;
- struct trap_info *ti;
-
DEBUGGER_trap_entry(TRAP_int3, regs);
if ( !guest_mode(regs) )
{
DEBUGGER_trap_fatal(TRAP_int3, regs);
show_execution_state(regs);
- panic("CPU%d FATAL TRAP: vector = 3 (Int3)\n", smp_processor_id());
+ panic("FATAL TRAP: vector = 3 (Int3)\n");
}
- ti = &current->arch.guest_context.trap_ctxt[TRAP_int3];
- tb->flags = TBF_EXCEPTION;
- tb->cs = ti->cs;
- tb->eip = ti->address;
- if ( TI_GET_IF(ti) )
- tb->flags |= TBF_INTERRUPT;
-
- return 0;
+ return do_guest_trap(TRAP_int3, regs, 0);
}
asmlinkage int do_machine_check(struct cpu_user_regs *regs)
@@ -696,17 +687,17 @@ void propagate_page_fault(unsigned long addr, u16 error_code)
tb->eip = ti->address;
if ( TI_GET_IF(ti) )
tb->flags |= TBF_INTERRUPT;
+ if ( unlikely(null_trap_bounce(tb)) )
+ {
+ printk("Unhandled page fault in domain %d on VCPU %d (ec=%04X)\n",
+ v->domain->domain_id, v->vcpu_id, error_code);
+ show_page_walk(addr);
+ }
}
static int handle_gdt_ldt_mapping_fault(
unsigned long offset, struct cpu_user_regs *regs)
{
- extern int map_ldt_shadow_page(unsigned int);
-
- struct vcpu *v = current;
- struct domain *d = v->domain;
- int ret;
-
/* Which vcpu's area did we fault in, and is it in the ldt sub-area? */
unsigned int is_ldt_area = (offset >> (GDT_LDT_VCPU_VA_SHIFT-1)) & 1;
unsigned int vcpu_area = (offset >> GDT_LDT_VCPU_VA_SHIFT);
@@ -720,18 +711,15 @@ static int handle_gdt_ldt_mapping_fault(
if ( likely(is_ldt_area) )
{
/* LDT fault: Copy a mapping from the guest's LDT, if it is valid. */
- LOCK_BIGLOCK(d);
- ret = map_ldt_shadow_page(offset >> PAGE_SHIFT);
- UNLOCK_BIGLOCK(d);
-
- if ( unlikely(ret == 0) )
+ if ( unlikely(map_ldt_shadow_page(offset >> PAGE_SHIFT) == 0) )
{
/* In hypervisor mode? Leave it to the #PF handler to fix up. */
if ( !guest_mode(regs) )
return 0;
/* In guest mode? Propagate #PF to guest, with adjusted %cr2. */
propagate_page_fault(
- v->arch.guest_context.ldt_base + offset, regs->error_code);
+ current->arch.guest_context.ldt_base + offset,
+ regs->error_code);
}
}
else
@@ -784,7 +772,7 @@ static int __spurious_page_fault(
#if CONFIG_PAGING_LEVELS >= 4
l4t = map_domain_page(mfn);
- l4e = l4t[l4_table_offset(addr)];
+ l4e = l4e_read_atomic(&l4t[l4_table_offset(addr)]);
mfn = l4e_get_pfn(l4e);
unmap_domain_page(l4t);
if ( ((l4e_get_flags(l4e) & required_flags) != required_flags) ||
@@ -797,7 +785,7 @@ static int __spurious_page_fault(
#ifdef CONFIG_X86_PAE
l3t += (cr3 & 0xFE0UL) >> 3;
#endif
- l3e = l3t[l3_table_offset(addr)];
+ l3e = l3e_read_atomic(&l3t[l3_table_offset(addr)]);
mfn = l3e_get_pfn(l3e);
unmap_domain_page(l3t);
#ifdef CONFIG_X86_PAE
@@ -811,7 +799,7 @@ static int __spurious_page_fault(
#endif
l2t = map_domain_page(mfn);
- l2e = l2t[l2_table_offset(addr)];
+ l2e = l2e_read_atomic(&l2t[l2_table_offset(addr)]);
mfn = l2e_get_pfn(l2e);
unmap_domain_page(l2t);
if ( ((l2e_get_flags(l2e) & required_flags) != required_flags) ||
@@ -824,7 +812,7 @@ static int __spurious_page_fault(
}
l1t = map_domain_page(mfn);
- l1e = l1t[l1_table_offset(addr)];
+ l1e = l1e_read_atomic(&l1t[l1_table_offset(addr)]);
mfn = l1e_get_pfn(l1e);
unmap_domain_page(l1t);
if ( ((l1e_get_flags(l1e) & required_flags) != required_flags) ||
@@ -832,17 +820,18 @@ static int __spurious_page_fault(
return 0;
spurious:
- DPRINTK("Spurious fault in domain %u:%u at addr %lx, e/c %04x\n",
+ dprintk(XENLOG_WARNING, "Spurious fault in domain %u:%u "
+ "at addr %lx, e/c %04x\n",
current->domain->domain_id, current->vcpu_id,
addr, regs->error_code);
#if CONFIG_PAGING_LEVELS >= 4
- DPRINTK(" l4e = %"PRIpte"\n", l4e_get_intpte(l4e));
+ dprintk(XENLOG_WARNING, " l4e = %"PRIpte"\n", l4e_get_intpte(l4e));
#endif
#if CONFIG_PAGING_LEVELS >= 3
- DPRINTK(" l3e = %"PRIpte"\n", l3e_get_intpte(l3e));
+ dprintk(XENLOG_WARNING, " l3e = %"PRIpte"\n", l3e_get_intpte(l3e));
#endif
- DPRINTK(" l2e = %"PRIpte"\n", l2e_get_intpte(l2e));
- DPRINTK(" l1e = %"PRIpte"\n", l1e_get_intpte(l1e));
+ dprintk(XENLOG_WARNING, " l2e = %"PRIpte"\n", l2e_get_intpte(l2e));
+ dprintk(XENLOG_WARNING, " l1e = %"PRIpte"\n", l1e_get_intpte(l1e));
#ifndef NDEBUG
show_registers(regs);
#endif
@@ -852,12 +841,16 @@ static int __spurious_page_fault(
static int spurious_page_fault(
unsigned long addr, struct cpu_user_regs *regs)
{
- struct domain *d = current->domain;
- int is_spurious;
+ unsigned long flags;
+ int is_spurious;
- LOCK_BIGLOCK(d);
+ /*
+ * Disabling interrupts prevents TLB flushing, and hence prevents
+ * page tables from becoming invalid under our feet during the walk.
+ */
+ local_irq_save(flags);
is_spurious = __spurious_page_fault(addr, regs);
- UNLOCK_BIGLOCK(d);
+ local_irq_restore(flags);
return is_spurious;
}
@@ -874,11 +867,7 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
if ( (addr >= GDT_LDT_VIRT_START) && (addr < GDT_LDT_VIRT_END) )
return handle_gdt_ldt_mapping_fault(
addr - GDT_LDT_VIRT_START, regs);
- /*
- * Do not propagate spurious faults in the hypervisor area to the
- * guest. It cannot fix them up.
- */
- return (spurious_page_fault(addr, regs) ? EXCRET_not_a_fault : 0);
+ return 0;
}
if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) &&
@@ -886,7 +875,7 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
/* Do not check if access-protection fault since the page may
legitimately be not present in shadow page tables */
((regs->error_code & PFEC_write_access) == PFEC_write_access) &&
- ptwr_do_page_fault(d, addr, regs) )
+ ptwr_do_page_fault(v, addr, regs) )
return EXCRET_fault_fixed;
if ( shadow_mode_enabled(d) )
@@ -935,10 +924,10 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs)
show_execution_state(regs);
show_page_walk(addr);
- panic("CPU%d FATAL PAGE FAULT\n"
+ panic("FATAL PAGE FAULT\n"
"[error_code=%04x]\n"
"Faulting linear address: %p\n",
- smp_processor_id(), regs->error_code, _p(addr));
+ regs->error_code, _p(addr));
}
propagate_page_fault(addr, regs->error_code);
@@ -969,7 +958,6 @@ static inline int guest_io_okay(
unsigned int port, unsigned int bytes,
struct vcpu *v, struct cpu_user_regs *regs)
{
- u16 x;
#if defined(__x86_64__)
/* If in user mode, switch to kernel mode just to read I/O bitmap. */
int user_mode = !(v->arch.flags & TF_kernel_mode);
@@ -984,10 +972,23 @@ static inline int guest_io_okay(
if ( v->arch.iobmp_limit > (port + bytes) )
{
+ union { uint8_t bytes[2]; uint16_t mask; } x;
+
+ /*
+ * Grab permission bytes from guest space. Inaccessible bytes are
+ * read as 0xff (no access allowed).
+ */
TOGGLE_MODE();
- __get_user(x, (u16 *)(v->arch.iobmp+(port>>3)));
+ switch ( __copy_from_guest_offset(&x.bytes[0], v->arch.iobmp,
+ port>>3, 2) )
+ {
+ default: x.bytes[0] = ~0;
+ case 1: x.bytes[1] = ~0;
+ case 0: break;
+ }
TOGGLE_MODE();
- if ( (x & (((1<<bytes)-1) << (port&7))) == 0 )
+
+ if ( (x.mask & (((1<<bytes)-1) << (port&7))) == 0 )
return 1;
}
@@ -1002,8 +1003,7 @@ static inline int admin_io_okay(
return ioports_access_permitted(v->domain, port, port + bytes - 1);
}
-/* Check admin limits. Silently fail the access if it is disallowed. */
-static inline unsigned char inb_user(
+static inline int guest_inb_okay(
unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
{
/*
@@ -1013,24 +1013,26 @@ static inline unsigned char inb_user(
* Note that we could emulate bit 4 instead of directly reading port 0x61,
* but there's not really a good reason to do so.
*/
- if ( admin_io_okay(port, 1, v, regs) || (port == 0x61) )
- return inb(port);
- return ~0;
+ return (admin_io_okay(port, 1, v, regs) || (port == 0x61));
}
-//#define inb_user(_p, _d, _r) (admin_io_okay(_p, 1, _d, _r) ? inb(_p) : ~0)
-#define inw_user(_p, _d, _r) (admin_io_okay(_p, 2, _d, _r) ? inw(_p) : ~0)
-#define inl_user(_p, _d, _r) (admin_io_okay(_p, 4, _d, _r) ? inl(_p) : ~0)
-#define outb_user(_v, _p, _d, _r) \
- (admin_io_okay(_p, 1, _d, _r) ? outb(_v, _p) : ((void)0))
-#define outw_user(_v, _p, _d, _r) \
- (admin_io_okay(_p, 2, _d, _r) ? outw(_v, _p) : ((void)0))
-#define outl_user(_v, _p, _d, _r) \
- (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0))
+#define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
+#define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
+#define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
+#define guest_outw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
+#define guest_outl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
+
+/* I/O emulation support. Helper routines for, and type of, the stack stub.*/
+void host_to_guest_gpr_switch(struct cpu_user_regs *)
+ __attribute__((__regparm__(1)));
+unsigned long guest_to_host_gpr_switch(unsigned long)
+ __attribute__((__regparm__(1)));
/* Instruction fetch with error handling. */
-#define insn_fetch(_type, _size, _ptr) \
-({ unsigned long _rc, _x; \
- if ( (_rc = copy_from_user(&_x, (_type *)eip, sizeof(_type))) != 0 ) \
+#define insn_fetch(_type, _size, cs, eip) \
+({ unsigned long _rc, _x, _ptr = eip; \
+ if ( vm86_mode(regs) ) \
+ _ptr += cs << 4; \
+ if ( (_rc = copy_from_user(&_x, (_type *)_ptr, sizeof(_type))) != 0 ) \
{ \
propagate_page_fault(eip + sizeof(_type) - _rc, 0); \
return EXCRET_fault_fixed; \
@@ -1040,15 +1042,17 @@ static inline unsigned char inb_user(
static int emulate_privileged_op(struct cpu_user_regs *regs)
{
struct vcpu *v = current;
- unsigned long *reg, eip = regs->eip, res;
+ unsigned long *reg, eip = regs->eip, cs = regs->cs, res;
u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
unsigned int port, i, op_bytes = 4, data, rc;
+ char io_emul_stub[16];
+ void (*io_emul)(struct cpu_user_regs *) __attribute__((__regparm__(1)));
u32 l, h;
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
{
- switch ( opcode = insn_fetch(u8, 1, eip) )
+ switch ( opcode = insn_fetch(u8, 1, cs, eip) )
{
case 0x66: /* operand-size override */
op_bytes ^= 6; /* switch between 2/4 bytes */
@@ -1080,9 +1084,12 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
modrm_rm = (opcode & 1) << 3; /* REX.B */
/* REX.W and REX.X do not need to be decoded. */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
}
#endif
+
+ if ( opcode == 0x0f )
+ goto twobyte_opcode;
/* Input/Output String instructions. */
if ( (opcode >= 0x6c) && (opcode <= 0x6f) )
@@ -1098,16 +1105,17 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case 0x6d: /* INSW/INSL */
if ( !guest_io_okay((u16)regs->edx, op_bytes, v, regs) )
goto fail;
+ port = (u16)regs->edx;
switch ( op_bytes )
{
case 1:
- data = (u8)inb_user((u16)regs->edx, v, regs);
+ data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : ~0);
break;
case 2:
- data = (u16)inw_user((u16)regs->edx, v, regs);
+ data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
break;
case 4:
- data = (u32)inl_user((u16)regs->edx, v, regs);
+ data = (u32)(guest_inl_okay(port, v, regs) ? inl(port) : ~0);
break;
}
if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
@@ -1130,16 +1138,20 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
propagate_page_fault(regs->esi + op_bytes - rc, 0);
return EXCRET_fault_fixed;
}
+ port = (u16)regs->edx;
switch ( op_bytes )
{
case 1:
- outb_user((u8)data, (u16)regs->edx, v, regs);
+ if ( guest_outb_okay(port, v, regs) )
+ outb((u8)data, port);
break;
case 2:
- outw_user((u16)data, (u16)regs->edx, v, regs);
+ if ( guest_outw_okay(port, v, regs) )
+ outw((u16)data, port);
break;
case 4:
- outl_user((u32)data, (u16)regs->edx, v, regs);
+ if ( guest_outl_okay(port, v, regs) )
+ outl((u32)data, port);
break;
}
regs->esi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
@@ -1156,28 +1168,60 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
goto done;
}
+ /*
+ * Very likely to be an I/O instruction (IN/OUT).
+ * Build an on-stack stub to execute the instruction with full guest
+ * GPR context. This is needed for some systems which (ab)use IN/OUT
+ * to communicate with BIOS code in system-management mode.
+ */
+ /* call host_to_guest_gpr_switch */
+ io_emul_stub[0] = 0xe8;
+ *(s32 *)&io_emul_stub[1] =
+ (char *)host_to_guest_gpr_switch - &io_emul_stub[5];
+ /* data16 or nop */
+ io_emul_stub[5] = (op_bytes != 2) ? 0x90 : 0x66;
+ /* <io-access opcode> */
+ io_emul_stub[6] = opcode;
+ /* imm8 or nop */
+ io_emul_stub[7] = 0x90;
+ /* jmp guest_to_host_gpr_switch */
+ io_emul_stub[8] = 0xe9;
+ *(s32 *)&io_emul_stub[9] =
+ (char *)guest_to_host_gpr_switch - &io_emul_stub[13];
+
+ /* Handy function-typed pointer to the stub. */
+ io_emul = (void *)io_emul_stub;
+
/* I/O Port and Interrupt Flag instructions. */
switch ( opcode )
{
case 0xe4: /* IN imm8,%al */
op_bytes = 1;
case 0xe5: /* IN imm8,%eax */
- port = insn_fetch(u8, 1, eip);
+ port = insn_fetch(u8, 1, cs, eip);
+ io_emul_stub[7] = port; /* imm8 */
exec_in:
if ( !guest_io_okay(port, op_bytes, v, regs) )
goto fail;
switch ( op_bytes )
{
case 1:
- regs->eax &= ~0xffUL;
- regs->eax |= (u8)inb_user(port, v, regs);
+ if ( guest_inb_okay(port, v, regs) )
+ io_emul(regs);
+ else
+ regs->eax |= (u8)~0;
break;
case 2:
- regs->eax &= ~0xffffUL;
- regs->eax |= (u16)inw_user(port, v, regs);
+ if ( guest_inw_okay(port, v, regs) )
+ io_emul(regs);
+ else
+ regs->eax |= (u16)~0;
break;
case 4:
- regs->eax = (u32)inl_user(port, v, regs);
+ if ( guest_inl_okay(port, v, regs) )
+ io_emul(regs);
+ else
+ regs->eax = (u32)~0;
break;
}
goto done;
@@ -1191,20 +1235,24 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case 0xe6: /* OUT %al,imm8 */
op_bytes = 1;
case 0xe7: /* OUT %eax,imm8 */
- port = insn_fetch(u8, 1, eip);
+ port = insn_fetch(u8, 1, cs, eip);
+ io_emul_stub[7] = port; /* imm8 */
exec_out:
if ( !guest_io_okay(port, op_bytes, v, regs) )
goto fail;
switch ( op_bytes )
{
case 1:
- outb_user((u8)regs->eax, port, v, regs);
+ if ( guest_outb_okay(port, v, regs) )
+ io_emul(regs);
break;
case 2:
- outw_user((u16)regs->eax, port, v, regs);
+ if ( guest_outw_okay(port, v, regs) )
+ io_emul(regs);
break;
case 4:
- outl_user((u32)regs->eax, port, v, regs);
+ if ( guest_outl_okay(port, v, regs) )
+ io_emul(regs);
break;
}
goto done;
@@ -1227,20 +1275,18 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
*/
/*v->vcpu_info->evtchn_upcall_mask = (opcode == 0xfa);*/
goto done;
-
- case 0x0f: /* Two-byte opcode */
- break;
-
- default:
- goto fail;
}
- /* Remaining instructions only emulated from guest kernel. */
+ /* No decode of this single-byte opcode. */
+ goto fail;
+
+ twobyte_opcode:
+ /* Two-byte opcodes only emulated from guest kernel. */
if ( !guest_kernel_mode(v, regs) )
goto fail;
/* Privileged (ring 0) instructions. */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
switch ( opcode )
{
case 0x06: /* CLTS */
@@ -1258,7 +1304,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
case 0x20: /* MOV CR?,<reg> */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
modrm_reg |= (opcode >> 3) & 7;
modrm_rm |= (opcode >> 0) & 7;
reg = decode_register(modrm_rm, regs, 0);
@@ -1292,7 +1338,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
case 0x21: /* MOV DR?,<reg> */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
modrm_reg |= (opcode >> 3) & 7;
modrm_rm |= (opcode >> 0) & 7;
reg = decode_register(modrm_rm, regs, 0);
@@ -1302,7 +1348,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
case 0x22: /* MOV <reg>,CR? */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
modrm_reg |= (opcode >> 3) & 7;
modrm_rm |= (opcode >> 0) & 7;
reg = decode_register(modrm_rm, regs, 0);
@@ -1311,7 +1357,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case 0: /* Write CR0 */
if ( (*reg ^ read_cr0()) & ~X86_CR0_TS )
{
- DPRINTK("Attempt to change unmodifiable CR0 flags.\n");
+ gdprintk(XENLOG_WARNING,
+ "Attempt to change unmodifiable CR0 flags.\n");
goto fail;
}
(void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS));
@@ -1324,14 +1371,16 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case 3: /* Write CR3 */
LOCK_BIGLOCK(v->domain);
- (void)new_guest_cr3(gmfn_to_mfn(v->domain, xen_cr3_to_pfn(*reg)));
+ rc = new_guest_cr3(gmfn_to_mfn(v->domain, xen_cr3_to_pfn(*reg)));
UNLOCK_BIGLOCK(v->domain);
+ if ( rc == 0 ) /* not okay */
+ goto fail;
break;
case 4:
if ( *reg != (read_cr4() & ~(X86_CR4_PGE|X86_CR4_PSE)) )
{
- DPRINTK("Attempt to change CR4 flags.\n");
+ gdprintk(XENLOG_WARNING, "Attempt to change CR4 flags.\n");
goto fail;
}
break;
@@ -1342,7 +1391,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
case 0x23: /* MOV <reg>,DR? */
- opcode = insn_fetch(u8, 1, eip);
+ opcode = insn_fetch(u8, 1, cs, eip);
modrm_reg |= (opcode >> 3) & 7;
modrm_rm |= (opcode >> 0) & 7;
reg = decode_register(modrm_rm, regs, 0);
@@ -1379,7 +1428,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
if ( (rdmsr_safe(regs->ecx, l, h) != 0) ||
(regs->eax != l) || (regs->edx != h) )
- DPRINTK("Domain attempted WRMSR %p from "
+ gdprintk(XENLOG_WARNING, "Domain attempted WRMSR %p from "
"%08x:%08x to %08lx:%08lx.\n",
_p(regs->ecx), h, l, (long)regs->edx, (long)regs->eax);
break;
@@ -1415,7 +1464,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
}
/* Everyone can read the MSR space. */
- /*DPRINTK("Domain attempted RDMSR %p.\n", _p(regs->ecx));*/
+ /* gdprintk(XENLOG_WARNING,"Domain attempted RDMSR %p.\n",
+ _p(regs->ecx));*/
if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )
goto fail;
break;
@@ -1437,8 +1487,6 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
asmlinkage int do_general_protection(struct cpu_user_regs *regs)
{
struct vcpu *v = current;
- struct trap_bounce *tb = &v->arch.trap_bounce;
- struct trap_info *ti;
unsigned long fixup;
DEBUGGER_trap_entry(TRAP_gp_fault, regs);
@@ -1472,12 +1520,13 @@ asmlinkage int do_general_protection(struct cpu_user_regs *regs)
if ( (regs->error_code & 3) == 2 )
{
/* This fault must be due to <INT n> instruction. */
- ti = &current->arch.guest_context.trap_ctxt[regs->error_code>>3];
+ const struct trap_info *ti;
+ unsigned char vector = regs->error_code >> 3;
+ ti = &v->arch.guest_context.trap_ctxt[vector];
if ( permit_softint(TI_GET_DPL(ti), v, regs) )
{
- tb->flags = TBF_EXCEPTION;
regs->eip += 2;
- goto finish_propagation;
+ return do_guest_trap(vector, regs, 0);
}
}
@@ -1494,21 +1543,13 @@ asmlinkage int do_general_protection(struct cpu_user_regs *regs)
#endif
/* Pass on GPF as is. */
- ti = &current->arch.guest_context.trap_ctxt[TRAP_gp_fault];
- tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
- tb->error_code = regs->error_code;
- finish_propagation:
- tb->cs = ti->cs;
- tb->eip = ti->address;
- if ( TI_GET_IF(ti) )
- tb->flags |= TBF_INTERRUPT;
- return 0;
+ return do_guest_trap(TRAP_gp_fault, regs, 1);
gp_in_kernel:
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
- DPRINTK("GPF (%04x): %p -> %p\n",
+ dprintk(XENLOG_WARNING, "GPF (%04x): %p -> %p\n",
regs->error_code, _p(regs->eip), _p(fixup));
regs->eip = fixup;
return 0;
@@ -1518,8 +1559,7 @@ asmlinkage int do_general_protection(struct cpu_user_regs *regs)
hardware_gp:
show_execution_state(regs);
- panic("CPU%d GENERAL PROTECTION FAULT\n[error_code=%04x]\n",
- smp_processor_id(), regs->error_code);
+ panic("GENERAL PROTECTION FAULT\n[error_code=%04x]\n", regs->error_code);
return 0;
}
@@ -1641,22 +1681,11 @@ void unset_nmi_callback(void)
asmlinkage int math_state_restore(struct cpu_user_regs *regs)
{
- struct trap_bounce *tb;
- struct trap_info *ti;
-
setup_fpu(current);
if ( current->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
{
- tb = &current->arch.trap_bounce;
- ti = &current->arch.guest_context.trap_ctxt[TRAP_no_device];
-
- tb->flags = TBF_EXCEPTION;
- tb->cs = ti->cs;
- tb->eip = ti->address;
- if ( TI_GET_IF(ti) )
- tb->flags |= TBF_INTERRUPT;
-
+ do_guest_trap(TRAP_no_device, regs, 0);
current->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
}
@@ -1667,8 +1696,6 @@ asmlinkage int do_debug(struct cpu_user_regs *regs)
{
unsigned long condition;
struct vcpu *v = current;
- struct trap_bounce *tb = &v->arch.trap_bounce;
- struct trap_info *ti;
__asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
@@ -1698,12 +1725,7 @@ asmlinkage int do_debug(struct cpu_user_regs *regs)
/* Save debug status register where guest OS can peek at it */
v->arch.guest_context.debugreg[6] = condition;
- ti = &v->arch.guest_context.trap_ctxt[TRAP_debug];
- tb->flags = TBF_EXCEPTION;
- tb->cs = ti->cs;
- tb->eip = ti->address;
- if ( TI_GET_IF(ti) )
- tb->flags |= TBF_INTERRUPT;
+ return do_guest_trap(TRAP_debug, regs, 0);
out:
return EXCRET_not_a_fault;
diff --git a/xen/arch/x86/x86_32/Makefile b/xen/arch/x86/x86_32/Makefile
index 7b4ab46be6..eb311f93d6 100644
--- a/xen/arch/x86/x86_32/Makefile
+++ b/xen/arch/x86/x86_32/Makefile
@@ -1,5 +1,6 @@
obj-y += domain_page.o
obj-y += entry.o
+obj-y += gpr_switch.o
obj-y += mm.o
obj-y += seg_fixup.o
obj-y += traps.o
diff --git a/xen/arch/x86/x86_32/asm-offsets.c b/xen/arch/x86/x86_32/asm-offsets.c
index 3a994650ca..4153b9f967 100644
--- a/xen/arch/x86/x86_32/asm-offsets.c
+++ b/xen/arch/x86/x86_32/asm-offsets.c
@@ -86,6 +86,7 @@ void __dummy__(void)
BLANK();
OFFSET(VCPU_vmx_launched, struct vcpu, arch.hvm_vmx.launched);
+ OFFSET(VCPU_vmx_cr2, struct vcpu, arch.hvm_vmx.cpu_cr2);
BLANK();
OFFSET(VMCB_rax, struct vmcb_struct, rax);
@@ -118,7 +119,6 @@ void __dummy__(void)
OFFSET(MULTICALL_arg3, struct multicall_entry, args[3]);
OFFSET(MULTICALL_arg4, struct multicall_entry, args[4]);
OFFSET(MULTICALL_arg5, struct multicall_entry, args[5]);
- OFFSET(MULTICALL_arg6, struct multicall_entry, args[6]);
OFFSET(MULTICALL_result, struct multicall_entry, result);
BLANK();
diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c
index b720003fc0..2b760ce704 100644
--- a/xen/arch/x86/x86_32/domain_page.c
+++ b/xen/arch/x86/x86_32/domain_page.c
@@ -29,7 +29,7 @@ static inline struct vcpu *mapcache_current_vcpu(void)
* then it means we are running on the idle domain's page table and must
* therefore use its mapcache.
*/
- if ( unlikely(!pagetable_get_pfn(v->arch.guest_table)) && !hvm_guest(v) )
+ if ( unlikely(!pagetable_get_pfn(v->arch.guest_table)) && !is_hvm_vcpu(v) )
{
/* If we really are idling, perform lazy context switch now. */
if ( (v = idle_vcpu[smp_processor_id()]) == current )
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index 79f0f08815..0e26f46497 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -175,7 +175,7 @@ ENTRY(hypercall)
jae bad_hypercall
PERFC_INCR(PERFC_hypercalls, %eax)
#ifndef NDEBUG
- /* Deliberately corrupt parameter regs not used by this hypercall. */
+ /* Create shadow parameters and corrupt those not used by this call. */
pushl %eax
pushl UREGS_eip+4(%esp)
pushl 28(%esp) # EBP
@@ -192,13 +192,25 @@ ENTRY(hypercall)
movl $0xDEADBEEF,%eax
rep stosl
movl %esi,%eax
+#else
+ /*
+ * We need shadow parameters even on non-debug builds. We depend on the
+ * original versions not being clobbered (needed to create a hypercall
+ * continuation). But that isn't guaranteed by the function-call ABI.
+ */
+ pushl 20(%esp) # EBP
+ pushl 20(%esp) # EDI
+ pushl 20(%esp) # ESI
+ pushl 20(%esp) # EDX
+ pushl 20(%esp) # ECX
+ pushl 20(%esp) # EBX
#endif
call *hypercall_table(,%eax,4)
+ addl $24,%esp # Discard the shadow parameters
#ifndef NDEBUG
- /* Deliberately corrupt parameter regs used by this hypercall. */
- addl $24,%esp # Shadow parameters
+ /* Deliberately corrupt real parameter regs used by this hypercall. */
popl %ecx # Shadow EIP
- cmpl %ecx,UREGS_eip(%esp)
+ cmpl %ecx,UREGS_eip+4(%esp)
popl %ecx # Shadow hypercall index
jne skip_clobber # If EIP has changed then don't clobber
movzb hypercall_args_table(,%ecx,1),%ecx
@@ -361,10 +373,11 @@ nvm86_3:/* Rewrite our stack frame and return to ring 1. */
mov %gs,UREGS_ss+4(%esp)
movl %esi,UREGS_esp+4(%esp)
movzwl TRAPBOUNCE_cs(%edx),%eax
+ /* Null selectors (0-3) are not allowed. */
+ testl $~3,%eax
+ jz domain_crash_synchronous
movl %eax,UREGS_cs+4(%esp)
movl TRAPBOUNCE_eip(%edx),%eax
- test %eax,%eax
- jz domain_crash_synchronous
movl %eax,UREGS_eip+4(%esp)
movb $0,TRAPBOUNCE_flags(%edx)
ret
@@ -386,7 +399,7 @@ domain_crash_synchronous_string:
domain_crash_synchronous:
pushl $domain_crash_synchronous_string
- call printf
+ call printk
jmp __domain_crash_synchronous
ALIGN
@@ -584,20 +597,6 @@ ENTRY(setup_vm86_frame)
addl $16,%esp
ret
-do_arch_sched_op_compat:
- # Ensure we return success even if we return via schedule_tail()
- xorl %eax,%eax
- GET_GUEST_REGS(%ecx)
- movl %eax,UREGS_eax(%ecx)
- jmp do_sched_op_compat
-
-do_arch_sched_op:
- # Ensure we return success even if we return via schedule_tail()
- xorl %eax,%eax
- GET_GUEST_REGS(%ecx)
- movl %eax,UREGS_eax(%ecx)
- jmp do_sched_op
-
.data
ENTRY(exception_table)
@@ -629,7 +628,7 @@ ENTRY(hypercall_table)
.long do_stack_switch
.long do_set_callbacks
.long do_fpu_taskswitch /* 5 */
- .long do_arch_sched_op_compat
+ .long do_sched_op_compat
.long do_platform_op
.long do_set_debugreg
.long do_get_debugreg
@@ -652,7 +651,7 @@ ENTRY(hypercall_table)
.long do_mmuext_op
.long do_acm_op
.long do_nmi_op
- .long do_arch_sched_op
+ .long do_sched_op
.long do_callback_op /* 30 */
.long do_xenoprof_op
.long do_event_channel_op
@@ -671,7 +670,7 @@ ENTRY(hypercall_args_table)
.byte 2 /* do_stack_switch */
.byte 4 /* do_set_callbacks */
.byte 1 /* do_fpu_taskswitch */ /* 5 */
- .byte 2 /* do_arch_sched_op_compat */
+ .byte 2 /* do_sched_op_compat */
.byte 1 /* do_platform_op */
.byte 2 /* do_set_debugreg */
.byte 1 /* do_get_debugreg */
@@ -694,7 +693,7 @@ ENTRY(hypercall_args_table)
.byte 4 /* do_mmuext_op */
.byte 1 /* do_acm_op */
.byte 2 /* do_nmi_op */
- .byte 2 /* do_arch_sched_op */
+ .byte 2 /* do_sched_op */
.byte 2 /* do_callback_op */ /* 30 */
.byte 2 /* do_xenoprof_op */
.byte 2 /* do_event_channel_op */
diff --git a/xen/arch/x86/x86_32/gpr_switch.S b/xen/arch/x86/x86_32/gpr_switch.S
new file mode 100644
index 0000000000..145b2472c3
--- /dev/null
+++ b/xen/arch/x86/x86_32/gpr_switch.S
@@ -0,0 +1,43 @@
+/*
+ * GPR context switch between host and guest.
+ * Used by IO-port-access emulation stub.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(host_to_guest_gpr_switch)
+ movl (%esp), %ecx
+ movl %eax, (%esp)
+ movl UREGS_edx(%eax), %edx
+ pushl %ebx
+ movl UREGS_ebx(%eax), %ebx
+ pushl %ebp
+ movl UREGS_ebp(%eax), %ebp
+ pushl %esi
+ movl UREGS_esi(%eax), %esi
+ pushl %edi
+ movl UREGS_edi(%eax), %edi
+ pushl %ecx
+ movl UREGS_ecx(%eax), %ecx
+ movl UREGS_eax(%eax), %eax
+ ret
+
+ENTRY(guest_to_host_gpr_switch)
+ pushl %edx
+ movl 5*4(%esp), %edx
+ movl %eax, UREGS_eax(%edx)
+ popl UREGS_edx(%edx)
+ movl %edi, UREGS_edi(%edx)
+ popl %edi
+ movl %esi, UREGS_esi(%edx)
+ popl %esi
+ movl %ebp, UREGS_ebp(%edx)
+ popl %ebp
+ movl %ebx, UREGS_ebx(%edx)
+ popl %ebx
+ movl %ecx, UREGS_ecx(%edx)
+ popl %ecx
+ ret
diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c
index fd91ff14bd..643a1eec1f 100644
--- a/xen/arch/x86/x86_32/seg_fixup.c
+++ b/xen/arch/x86/x86_32/seg_fixup.c
@@ -32,10 +32,6 @@
#include <asm/regs.h>
#include <asm/x86_emulate.h>
-/* Make the scary benign errors go away. */
-#undef DPRINTK
-#define DPRINTK(_f, _a...) ((void)0)
-
/* General instruction properties. */
#define INSN_SUFFIX_BYTES (7)
#define OPCODE_BYTE (1<<4)
@@ -185,7 +181,7 @@ int fixup_seg(u16 seg, unsigned long offset)
table = (unsigned long *)LDT_VIRT_START(d);
if ( idx >= d->arch.guest_context.ldt_ents )
{
- DPRINTK("Segment %04x out of LDT range (%ld)\n",
+ dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n",
seg, d->arch.guest_context.ldt_ents);
goto fail;
}
@@ -195,7 +191,7 @@ int fixup_seg(u16 seg, unsigned long offset)
table = (unsigned long *)GDT_VIRT_START(d);
if ( idx >= d->arch.guest_context.gdt_ents )
{
- DPRINTK("Segment %04x out of GDT range (%ld)\n",
+ dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n",
seg, d->arch.guest_context.gdt_ents);
goto fail;
}
@@ -205,7 +201,7 @@ int fixup_seg(u16 seg, unsigned long offset)
if ( __get_user(a, &table[2*idx+0]) ||
__get_user(b, &table[2*idx+1]) )
{
- DPRINTK("Fault while reading segment %04x\n", seg);
+ dprintk(XENLOG_DEBUG, "Fault while reading segment %04x\n", seg);
goto fail; /* Barking up the wrong tree. Decode needs a page fault.*/
}
@@ -214,7 +210,7 @@ int fixup_seg(u16 seg, unsigned long offset)
_SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) !=
(_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) )
{
- DPRINTK("Bad segment %08lx:%08lx\n", a, b);
+ dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b);
goto fail;
}
@@ -244,7 +240,8 @@ int fixup_seg(u16 seg, unsigned long offset)
}
}
- DPRINTK("None of the above! (%08lx:%08lx, %08lx, %08lx, %08lx)\n",
+ dprintk(XENLOG_DEBUG, "None of the above! "
+ "(%08lx:%08lx, %08lx, %08lx, %08lx)\n",
a, b, base, limit, base+limit);
fail:
@@ -282,13 +279,14 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
/* WARNING: We only work for ring-3 segments. */
if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) )
{
- DPRINTK("Taken fault at bad CS %04x\n", regs->cs);
+ dprintk(XENLOG_DEBUG, "Taken fault at bad CS %04x\n", regs->cs);
goto fail;
}
if ( !linearise_address((u16)regs->cs, regs->eip, (unsigned long *)&eip) )
{
- DPRINTK("Cannot linearise %04x:%08x\n", regs->cs, regs->eip);
+ dprintk(XENLOG_DEBUG, "Cannot linearise %04x:%08x\n",
+ regs->cs, regs->eip);
goto fail;
}
@@ -297,13 +295,16 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
{
if ( get_user(b, pb) )
{
- DPRINTK("Fault while accessing byte %d of instruction\n", pb-eip);
+ dprintk(XENLOG_DEBUG,
+ "Fault while accessing byte %ld of instruction\n",
+ (long)(pb-eip));
goto page_fault;
}
if ( (pb - eip) >= 15 )
{
- DPRINTK("Too many instruction prefixes for a legal instruction\n");
+ dprintk(XENLOG_DEBUG, "Too many instruction prefixes for a "
+ "legal instruction\n");
goto fail;
}
@@ -315,7 +316,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
case 0x26: /* ES override */
case 0x64: /* FS override */
case 0x36: /* SS override */
- DPRINTK("Unhandled prefix %02x\n", b);
+ dprintk(XENLOG_DEBUG, "Unhandled prefix %02x\n", b);
goto fail;
case 0x66: /* Operand-size override */
case 0xf0: /* LOCK */
@@ -333,7 +334,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
if ( !gs_override )
{
- DPRINTK("Only instructions with GS override\n");
+ dprintk(XENLOG_DEBUG, "Only instructions with GS override\n");
goto fail;
}
@@ -341,7 +342,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
pb++;
if ( decode == 0 )
{
- DPRINTK("Unsupported opcode %02x\n", b);
+ dprintk(XENLOG_DEBUG, "Unsupported opcode %02x\n", b);
goto fail;
}
@@ -353,7 +354,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
if ( get_user(offset, (u32 *)pb) )
{
- DPRINTK("Fault while extracting <disp32>.\n");
+ dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
goto page_fault;
}
pb += 4;
@@ -367,7 +368,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
if ( get_user(modrm, pb) )
{
- DPRINTK("Fault while extracting modrm byte\n");
+ dprintk(XENLOG_DEBUG, "Fault while extracting modrm byte\n");
goto page_fault;
}
@@ -379,7 +380,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
if ( rm == 4 )
{
- DPRINTK("FIXME: Add decoding for the SIB byte.\n");
+ dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n");
goto fixme;
}
@@ -397,7 +398,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
memreg = NULL;
if ( get_user(disp32, (u32 *)pb) )
{
- DPRINTK("Fault while extracting <disp8>.\n");
+ dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
goto page_fault;
}
pb += 4;
@@ -407,7 +408,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
case 1:
if ( get_user(disp8, pb) )
{
- DPRINTK("Fault while extracting <disp8>.\n");
+ dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
goto page_fault;
}
pb++;
@@ -417,14 +418,14 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
case 2:
if ( get_user(disp32, (u32 *)pb) )
{
- DPRINTK("Fault while extracting <disp8>.\n");
+ dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
goto page_fault;
}
pb += 4;
break;
case 3:
- DPRINTK("Not a memory operand!\n");
+ dprintk(XENLOG_DEBUG, "Not a memory operand!\n");
goto fail;
}
@@ -455,7 +456,8 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
return EXCRET_fault_fixed;
fixme:
- DPRINTK("Undecodable instruction %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
+ dprintk(XENLOG_DEBUG, "Undecodable instruction "
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
"caused GPF(0) at %04x:%08x\n",
eip[0], eip[1], eip[2], eip[3],
eip[4], eip[5], eip[6], eip[7],
diff --git a/xen/arch/x86/x86_32/supervisor_mode_kernel.S b/xen/arch/x86/x86_32/supervisor_mode_kernel.S
index 82f823bfa7..ea2276993d 100644
--- a/xen/arch/x86/x86_32/supervisor_mode_kernel.S
+++ b/xen/arch/x86/x86_32/supervisor_mode_kernel.S
@@ -141,5 +141,5 @@ domain_crash_synchronous_string:
domain_crash_synchronous:
pushl $domain_crash_synchronous_string
- call printf
+ call printk
jmp __domain_crash_synchronous
diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c
index 90e799a78c..d5d1e5e8f7 100644
--- a/xen/arch/x86/x86_32/traps.c
+++ b/xen/arch/x86/x86_32/traps.c
@@ -45,7 +45,7 @@ void show_registers(struct cpu_user_regs *regs)
unsigned long fault_crs[8];
const char *context;
- if ( hvm_guest(current) && guest_mode(regs) )
+ if ( is_hvm_vcpu(current) && guest_mode(regs) )
{
context = "hvm";
hvm_store_cpu_guest_regs(current, &fault_regs, fault_crs);
@@ -168,16 +168,8 @@ asmlinkage void do_double_fault(void)
printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
tss->ds, tss->es, tss->fs, tss->gs, tss->ss);
show_stack_overflow(tss->esp);
- printk("************************************\n");
- printk("CPU%d DOUBLE FAULT -- system shutdown\n", cpu);
- printk("System needs manual reset.\n");
- printk("************************************\n");
- /* Lock up the console to prevent spurious output from other CPUs. */
- console_force_lock();
-
- /* Wait for manual reset. */
- machine_halt();
+ panic("DOUBLE FAULT -- system shutdown\n");
}
unsigned long do_iret(void)
@@ -187,16 +179,16 @@ unsigned long do_iret(void)
/* Check worst-case stack frame for overlap with Xen protected area. */
if ( unlikely(!access_ok(regs->esp, 40)) )
- domain_crash_synchronous();
+ goto exit_and_crash;
/* Pop and restore EAX (clobbered by hypercall). */
if ( unlikely(__copy_from_user(&regs->eax, (void __user *)regs->esp, 4)) )
- domain_crash_synchronous();
+ goto exit_and_crash;
regs->esp += 4;
/* Pop and restore CS and EIP. */
if ( unlikely(__copy_from_user(&regs->eip, (void __user *)regs->esp, 8)) )
- domain_crash_synchronous();
+ goto exit_and_crash;
regs->esp += 8;
/*
@@ -204,7 +196,7 @@ unsigned long do_iret(void)
* to avoid firing the BUG_ON(IOPL) check in arch_getdomaininfo_ctxt.
*/
if ( unlikely(__copy_from_user(&eflags, (void __user *)regs->esp, 4)) )
- domain_crash_synchronous();
+ goto exit_and_crash;
regs->esp += 4;
regs->eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF;
@@ -212,17 +204,17 @@ unsigned long do_iret(void)
{
/* Return to VM86 mode: pop and restore ESP,SS,ES,DS,FS and GS. */
if ( __copy_from_user(&regs->esp, (void __user *)regs->esp, 24) )
- domain_crash_synchronous();
+ goto exit_and_crash;
}
else if ( unlikely(ring_0(regs)) )
{
- domain_crash_synchronous();
+ goto exit_and_crash;
}
else if ( !ring_1(regs) )
{
/* Return to ring 2/3: pop and restore ESP and SS. */
if ( __copy_from_user(&regs->esp, (void __user *)regs->esp, 8) )
- domain_crash_synchronous();
+ goto exit_and_crash;
}
/* No longer in NMI context. */
@@ -236,6 +228,11 @@ unsigned long do_iret(void)
* value.
*/
return regs->eax;
+
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Fatal error\n");
+ domain_crash(current->domain);
+ return 0;
}
#include <asm/asm_defns.h>
@@ -363,7 +360,7 @@ static long register_guest_callback(struct callback_register *reg)
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -376,12 +373,20 @@ static long unregister_guest_callback(struct callback_unregister *unreg)
switch ( unreg->type )
{
+ case CALLBACKTYPE_event:
+ case CALLBACKTYPE_failsafe:
+#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL
+ case CALLBACKTYPE_sysenter:
+#endif
+ ret = -EINVAL;
+ break;
+
case CALLBACKTYPE_nmi:
ret = unregister_guest_nmi_callback();
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -420,7 +425,7 @@ long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg)
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -515,7 +520,7 @@ static void hypercall_page_initialise_ring1_kernel(void *hypercall_page)
void hypercall_page_initialise(struct domain *d, void *hypercall_page)
{
- if ( hvm_guest(d->vcpu[0]) )
+ if ( is_hvm_domain(d) )
hvm_hypercall_page_initialise(d, hypercall_page);
else if ( supervisor_mode_kernel )
hypercall_page_initialise_ring0_kernel(hypercall_page);
diff --git a/xen/arch/x86/x86_64/Makefile b/xen/arch/x86/x86_64/Makefile
index 3ce6d01156..3c43c696d1 100644
--- a/xen/arch/x86/x86_64/Makefile
+++ b/xen/arch/x86/x86_64/Makefile
@@ -1,3 +1,4 @@
obj-y += entry.o
+obj-y += gpr_switch.o
obj-y += mm.o
obj-y += traps.o
diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c
index 6744e6c9e2..41f93fe9c5 100644
--- a/xen/arch/x86/x86_64/asm-offsets.c
+++ b/xen/arch/x86/x86_64/asm-offsets.c
@@ -80,6 +80,7 @@ void __dummy__(void)
BLANK();
OFFSET(VCPU_vmx_launched, struct vcpu, arch.hvm_vmx.launched);
+ OFFSET(VCPU_vmx_cr2, struct vcpu, arch.hvm_vmx.cpu_cr2);
BLANK();
OFFSET(VMCB_rax, struct vmcb_struct, rax);
@@ -112,7 +113,6 @@ void __dummy__(void)
OFFSET(MULTICALL_arg3, struct multicall_entry, args[3]);
OFFSET(MULTICALL_arg4, struct multicall_entry, args[4]);
OFFSET(MULTICALL_arg5, struct multicall_entry, args[5]);
- OFFSET(MULTICALL_arg6, struct multicall_entry, args[6]);
OFFSET(MULTICALL_result, struct multicall_entry, result);
BLANK();
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index d1a6c19599..3f2b8297c7 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -45,7 +45,7 @@ restore_all_guest:
addq $8,%rsp
popq %rcx # RIP
popq %r11 # CS
- cmpw $__GUEST_CS32,%r11
+ cmpw $FLAT_KERNEL_CS32,%r11
popq %r11 # RFLAGS
popq %rsp # RSP
je 1f
@@ -119,7 +119,7 @@ restore_all_xen:
ALIGN
ENTRY(syscall_enter)
sti
- movl $__GUEST_SS,24(%rsp)
+ movl $FLAT_KERNEL_SS,24(%rsp)
pushq %rcx
pushq $0
movl $TRAP_syscall,4(%rsp)
@@ -152,7 +152,7 @@ ENTRY(syscall_enter)
#ifndef NDEBUG
/* Deliberately corrupt parameter regs used by this hypercall. */
popq %r10 # Shadow RIP
- cmpq %r10,UREGS_rip(%rsp)
+ cmpq %r10,UREGS_rip+8(%rsp)
popq %rcx # Shadow hypercall index
jne skip_clobber /* If RIP has changed then don't clobber. */
leaq hypercall_args_table(%rip),%r10
@@ -298,9 +298,9 @@ FLT13: movq %rax,(%rsi) # RCX
movl $TRAP_syscall,UREGS_entry_vector+8(%rsp)
andl $~(X86_EFLAGS_AC|X86_EFLAGS_VM|X86_EFLAGS_RF|\
X86_EFLAGS_NT|X86_EFLAGS_TF),UREGS_eflags+8(%rsp)
- movq $__GUEST_SS,UREGS_ss+8(%rsp)
+ movq $FLAT_KERNEL_SS,UREGS_ss+8(%rsp)
movq %rsi,UREGS_rsp+8(%rsp)
- movq $__GUEST_CS,UREGS_cs+8(%rsp)
+ movq $FLAT_KERNEL_CS,UREGS_cs+8(%rsp)
movq TRAPBOUNCE_eip(%rdx),%rax
testq %rax,%rax
jz domain_crash_synchronous
@@ -328,7 +328,7 @@ domain_crash_synchronous:
# printk(domain_crash_synchronous_string)
leaq domain_crash_synchronous_string(%rip),%rdi
xorl %eax,%eax
- call printf
+ call printk
jmp __domain_crash_synchronous
ALIGN
@@ -497,20 +497,6 @@ nmi_in_hypervisor_mode:
call do_nmi
jmp ret_from_intr
-do_arch_sched_op_compat:
- # Ensure we return success even if we return via schedule_tail()
- xorl %eax,%eax
- GET_GUEST_REGS(%r10)
- movq %rax,UREGS_rax(%r10)
- jmp do_sched_op_compat
-
-do_arch_sched_op:
- # Ensure we return success even if we return via schedule_tail()
- xorl %eax,%eax
- GET_GUEST_REGS(%r10)
- movq %rax,UREGS_rax(%r10)
- jmp do_sched_op
-
.data
ENTRY(exception_table)
@@ -542,7 +528,7 @@ ENTRY(hypercall_table)
.quad do_stack_switch
.quad do_set_callbacks
.quad do_fpu_taskswitch /* 5 */
- .quad do_arch_sched_op_compat
+ .quad do_sched_op_compat
.quad do_platform_op
.quad do_set_debugreg
.quad do_get_debugreg
@@ -565,7 +551,7 @@ ENTRY(hypercall_table)
.quad do_mmuext_op
.quad do_acm_op
.quad do_nmi_op
- .quad do_arch_sched_op
+ .quad do_sched_op
.quad do_callback_op /* 30 */
.quad do_xenoprof_op
.quad do_event_channel_op
@@ -584,8 +570,8 @@ ENTRY(hypercall_args_table)
.byte 2 /* do_stack_switch */
.byte 3 /* do_set_callbacks */
.byte 1 /* do_fpu_taskswitch */ /* 5 */
- .byte 2 /* do_arch_sched_op_compat */
- .byte 1 /* do_platform_op */
+ .byte 2 /* do_sched_op_compat */
+ .byte 1 /* do_platform_op */
.byte 2 /* do_set_debugreg */
.byte 1 /* do_get_debugreg */
.byte 2 /* do_update_descriptor */ /* 10 */
@@ -607,7 +593,7 @@ ENTRY(hypercall_args_table)
.byte 4 /* do_mmuext_op */
.byte 1 /* do_acm_op */
.byte 2 /* do_nmi_op */
- .byte 2 /* do_arch_sched_op */
+ .byte 2 /* do_sched_op */
.byte 2 /* do_callback_op */ /* 30 */
.byte 2 /* do_xenoprof_op */
.byte 2 /* do_event_channel_op */
diff --git a/xen/arch/x86/x86_64/gpr_switch.S b/xen/arch/x86/x86_64/gpr_switch.S
new file mode 100644
index 0000000000..45a24bcc72
--- /dev/null
+++ b/xen/arch/x86/x86_64/gpr_switch.S
@@ -0,0 +1,63 @@
+/*
+ * GPR context switch between host and guest.
+ * Used by IO-port-access emulation stub.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(host_to_guest_gpr_switch)
+ movq (%rsp), %rcx
+ movq %rdi, (%rsp)
+ movq UREGS_rdx(%rdi), %rdx
+ pushq %rbx
+ movq UREGS_rax(%rdi), %rax
+ movq UREGS_rbx(%rdi), %rbx
+ pushq %rbp
+ movq UREGS_rsi(%rdi), %rsi
+ movq UREGS_rbp(%rdi), %rbp
+ pushq %r12
+ movq UREGS_r8(%rdi), %r8
+ movq UREGS_r12(%rdi), %r12
+ pushq %r13
+ movq UREGS_r9(%rdi), %r9
+ movq UREGS_r13(%rdi), %r13
+ pushq %r14
+ movq UREGS_r10(%rdi), %r10
+ movq UREGS_r14(%rdi), %r14
+ pushq %r15
+ movq UREGS_r11(%rdi), %r11
+ movq UREGS_r15(%rdi), %r15
+ pushq %rcx
+ movq UREGS_rcx(%rdi), %rcx
+ movq UREGS_rdi(%rdi), %rdi
+ ret
+
+ENTRY(guest_to_host_gpr_switch)
+ pushq %rdi
+ movq 7*8(%rsp), %rdi
+ movq %rax, UREGS_rax(%rdi)
+ popq UREGS_rdi(%rdi)
+ movq %r15, UREGS_r15(%rdi)
+ movq %r11, UREGS_r11(%rdi)
+ popq %r15
+ movq %r14, UREGS_r14(%rdi)
+ movq %r10, UREGS_r10(%rdi)
+ popq %r14
+ movq %r13, UREGS_r13(%rdi)
+ movq %r9, UREGS_r9(%rdi)
+ popq %r13
+ movq %r12, UREGS_r12(%rdi)
+ movq %r8, UREGS_r8(%rdi)
+ popq %r12
+ movq %rbp, UREGS_rbp(%rdi)
+ movq %rsi, UREGS_rsi(%rdi)
+ popq %rbp
+ movq %rbx, UREGS_rbx(%rdi)
+ movq %rdx, UREGS_rdx(%rdi)
+ popq %rbx
+ movq %rcx, UREGS_rcx(%rdi)
+ popq %rcx
+ ret
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index df08ff8fc1..c2783e897d 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -76,17 +76,17 @@ l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
void __init paging_init(void)
{
- unsigned long i, mpt_size;
+ unsigned long i, mpt_size, va;
l3_pgentry_t *l3_ro_mpt;
l2_pgentry_t *l2_ro_mpt = NULL;
- struct page_info *pg;
+ struct page_info *l1_pg, *l2_pg;
/* Create user-accessible L2 directory to map the MPT for guests. */
- l3_ro_mpt = alloc_xenheap_page();
- clear_page(l3_ro_mpt);
+ if ( (l2_pg = alloc_domheap_page(NULL)) == NULL )
+ goto nomem;
+ l3_ro_mpt = clear_page(page_to_virt(l2_pg));
idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)] =
- l4e_from_page(
- virt_to_page(l3_ro_mpt), __PAGE_HYPERVISOR | _PAGE_USER);
+ l4e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER);
/*
* Allocate and map the machine-to-phys table.
@@ -96,33 +96,37 @@ void __init paging_init(void)
mpt_size &= ~((1UL << L2_PAGETABLE_SHIFT) - 1UL);
for ( i = 0; i < (mpt_size >> L2_PAGETABLE_SHIFT); i++ )
{
- if ( (pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER, 0)) == NULL )
- panic("Not enough memory for m2p table\n");
+ if ( (l1_pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER, 0)) == NULL )
+ goto nomem;
map_pages_to_xen(
- RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT), page_to_mfn(pg),
+ RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT),
+ page_to_mfn(l1_pg),
1UL << PAGETABLE_ORDER,
PAGE_HYPERVISOR);
memset((void *)(RDWR_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT)), 0x55,
1UL << L2_PAGETABLE_SHIFT);
if ( !((unsigned long)l2_ro_mpt & ~PAGE_MASK) )
{
- unsigned long va = RO_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT);
-
- l2_ro_mpt = alloc_xenheap_page();
- clear_page(l2_ro_mpt);
+ if ( (l2_pg = alloc_domheap_page(NULL)) == NULL )
+ goto nomem;
+ va = RO_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT);
+ l2_ro_mpt = clear_page(page_to_virt(l2_pg));
l3_ro_mpt[l3_table_offset(va)] =
- l3e_from_page(
- virt_to_page(l2_ro_mpt), __PAGE_HYPERVISOR | _PAGE_USER);
+ l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER);
l2_ro_mpt += l2_table_offset(va);
}
/* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
*l2_ro_mpt++ = l2e_from_page(
- pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT);
+ l1_pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT);
}
/* Set up linear page table mapping. */
idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)] =
l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR);
+ return;
+
+ nomem:
+ panic("Not enough memory for m2p table\n");
}
void __init setup_idle_pagetable(void)
diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c
index 0c2a0f3ebc..5eb91130a5 100644
--- a/xen/arch/x86/x86_64/traps.c
+++ b/xen/arch/x86/x86_64/traps.c
@@ -15,6 +15,7 @@
#include <asm/current.h>
#include <asm/flushtlb.h>
#include <asm/msr.h>
+#include <asm/page.h>
#include <asm/shadow.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
@@ -41,7 +42,7 @@ void show_registers(struct cpu_user_regs *regs)
unsigned long fault_crs[8];
const char *context;
- if ( hvm_guest(current) && guest_mode(regs) )
+ if ( is_hvm_vcpu(current) && guest_mode(regs) )
{
context = "hvm";
hvm_store_cpu_guest_regs(current, &fault_regs, fault_crs);
@@ -171,16 +172,8 @@ asmlinkage void do_double_fault(struct cpu_user_regs *regs)
regs->r12, regs->r13, regs->r14);
printk("r15: %016lx\n", regs->r15);
show_stack_overflow(regs->rsp);
- printk("************************************\n");
- printk("CPU%d DOUBLE FAULT -- system shutdown\n", cpu);
- printk("System needs manual reset.\n");
- printk("************************************\n");
- /* Lock up the console to prevent spurious output from other CPUs. */
- console_force_lock();
-
- /* Wait for manual reset. */
- machine_halt();
+ panic("DOUBLE FAULT -- system shutdown\n");
}
void toggle_guest_mode(struct vcpu *v)
@@ -188,7 +181,12 @@ void toggle_guest_mode(struct vcpu *v)
v->arch.flags ^= TF_kernel_mode;
__asm__ __volatile__ ( "swapgs" );
update_cr3(v);
+#ifdef USER_MAPPINGS_ARE_GLOBAL
+ /* Don't flush user global mappings from the TLB. Don't tick TLB clock. */
+ __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (v->arch.cr3) : "memory" );
+#else
write_ptbase(v);
+#endif
}
unsigned long do_iret(void)
@@ -200,8 +198,9 @@ unsigned long do_iret(void)
if ( unlikely(copy_from_user(&iret_saved, (void *)regs->rsp,
sizeof(iret_saved))) )
{
- DPRINTK("Fault while reading IRET context from guest stack\n");
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "Fault while reading IRET context from "
+ "guest stack\n");
+ goto exit_and_crash;
}
/* Returning to user mode? */
@@ -209,8 +208,9 @@ unsigned long do_iret(void)
{
if ( unlikely(pagetable_is_null(v->arch.guest_table_user)) )
{
- DPRINTK("Guest switching to user mode with no user page tables\n");
- domain_crash_synchronous();
+ gdprintk(XENLOG_ERR, "Guest switching to user mode with no "
+ "user page tables\n");
+ goto exit_and_crash;
}
toggle_guest_mode(v);
}
@@ -221,7 +221,7 @@ unsigned long do_iret(void)
regs->rsp = iret_saved.rsp;
regs->ss = iret_saved.ss | 3; /* force guest privilege */
- if ( !(iret_saved.flags & VGCF_IN_SYSCALL) )
+ if ( !(iret_saved.flags & VGCF_in_syscall) )
{
regs->entry_vector = 0;
regs->r11 = iret_saved.r11;
@@ -236,6 +236,11 @@ unsigned long do_iret(void)
/* Saved %rax gets written back to regs->rax in entry.S. */
return iret_saved.rax;
+
+ exit_and_crash:
+ gdprintk(XENLOG_ERR, "Fatal error\n");
+ domain_crash(v->domain);
+ return 0;
}
asmlinkage void syscall_enter(void);
@@ -285,9 +290,9 @@ void __init percpu_traps_init(void)
stack[14] = 0x41;
stack[15] = 0x53;
- /* pushq $__GUEST_CS64 */
+ /* pushq $FLAT_KERNEL_CS64 */
stack[16] = 0x68;
- *(u32 *)&stack[17] = __GUEST_CS64;
+ *(u32 *)&stack[17] = FLAT_KERNEL_CS64;
/* jmp syscall_enter */
stack[21] = 0xe9;
@@ -317,9 +322,9 @@ void __init percpu_traps_init(void)
stack[14] = 0x41;
stack[15] = 0x53;
- /* pushq $__GUEST_CS32 */
+ /* pushq $FLAT_KERNEL_CS32 */
stack[16] = 0x68;
- *(u32 *)&stack[17] = __GUEST_CS32;
+ *(u32 *)&stack[17] = FLAT_KERNEL_CS32;
/* jmp syscall_enter */
stack[21] = 0xe9;
@@ -369,7 +374,7 @@ static long register_guest_callback(struct callback_register *reg)
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -382,12 +387,18 @@ static long unregister_guest_callback(struct callback_unregister *unreg)
switch ( unreg->type )
{
+ case CALLBACKTYPE_event:
+ case CALLBACKTYPE_failsafe:
+ case CALLBACKTYPE_syscall:
+ ret = -EINVAL;
+ break;
+
case CALLBACKTYPE_nmi:
ret = unregister_guest_nmi_callback();
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -426,7 +437,7 @@ long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg)
break;
default:
- ret = -EINVAL;
+ ret = -ENOSYS;
break;
}
@@ -492,7 +503,7 @@ static void hypercall_page_initialise_ring3_kernel(void *hypercall_page)
void hypercall_page_initialise(struct domain *d, void *hypercall_page)
{
- if ( hvm_guest(d->vcpu[0]) )
+ if ( is_hvm_domain(d) )
hvm_hypercall_page_initialise(d, hypercall_page);
else
hypercall_page_initialise_ring3_kernel(hypercall_page);
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index 58206c822d..2ce2dfb440 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -10,14 +10,14 @@
#include <stdio.h>
#include <stdint.h>
#include <public/xen.h>
-#define DPRINTF(_f, _a...) printf( _f , ## _a )
+#define dprintf(_f, _a...) printf( _f , ## _a )
#else
#include <xen/config.h>
#include <xen/types.h>
#include <xen/lib.h>
#include <xen/mm.h>
#include <asm/regs.h>
-#define DPRINTF DPRINTK
+#define dprintf(_f, _a...) gdprintk(XENLOG_WARNING, _f , ## _a )
#endif
#include <asm-x86/x86_emulate.h>
@@ -113,12 +113,10 @@ static uint8_t opcode_table[256] = {
/* 0xA0 - 0xA7 */
ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,
ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,
- ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps, ImplicitOps,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
/* 0xA8 - 0xAF */
0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps, ImplicitOps,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
/* 0xB0 - 0xBF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xC0 - 0xC7 */
@@ -368,20 +366,24 @@ do{ __asm__ __volatile__ ( \
#endif /* __i386__ */
/* Fetch next part of the instruction being emulated. */
-#define insn_fetch(_type, _size, _eip) \
-({ unsigned long _x; \
- rc = ops->read_std((unsigned long)(_eip), &_x, (_size), ctxt); \
+#define _insn_fetch(_size) \
+({ unsigned long _x, _ptr = _regs.eip; \
+ if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4; \
+ rc = ops->read_std(_ptr, &_x, (_size), ctxt); \
if ( rc != 0 ) \
goto done; \
- (_eip) += (_size); \
- (_type)_x; \
+ _regs.eip += (_size); \
+ _x; \
})
+#define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type)))
/* Access/update address held in a register, based on addressing mode. */
#define register_address(sel, reg) \
+({ unsigned long __reg = (reg); \
(((mode == X86EMUL_MODE_REAL) ? ((unsigned long)(sel) << 4) : 0) + \
- ((ad_bytes == sizeof(unsigned long)) ? (reg) : \
- ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
+ ((ad_bytes == sizeof(unsigned long)) ? __reg : \
+ (__reg & ((1UL << (ad_bytes << 3)) - 1)))); \
+})
#define register_address_increment(reg, inc) \
do { \
int _inc = (inc); /* signed type ensures sign extension to long */ \
@@ -392,6 +394,17 @@ do { \
(((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
} while (0)
+/*
+ * We cannot handle a page fault on a data access that straddles two pages
+ * and faults on the second page. This is because CR2 is not equal to the
+ * memory operand's effective address in this case. Rather than fix up the
+ * effective address it is okay for us to fail the emulation.
+ */
+#define page_boundary_test() do { \
+ if ( ((cr2 & (PAGE_SIZE-1)) == 0) && ((ea & 7) != 0) ) \
+ goto bad_ea; \
+} while ( 0 )
+
void *
decode_register(
uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs)
@@ -432,23 +445,48 @@ decode_register(
return p;
}
+static void
+dump_instr(
+ struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+#ifdef __XEN__
+ int i;
+ unsigned long x, pc;
+
+ pc = ctxt->regs->eip;
+ if ( ctxt->mode == X86EMUL_MODE_REAL )
+ pc += ctxt->regs->cs << 4;
+
+ dprintf("Instr:");
+ for ( i = 0; i < 16; i++, pc++ )
+ {
+ if ( ops->read_std(pc, &x, 1, ctxt) != 0 )
+ printk(" ??");
+ else
+ printk(" %02x", (uint8_t)x);
+ }
+ printk("\n");
+#endif
+}
+
int
x86_emulate_memop(
struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
- uint8_t b, d, sib, twobyte = 0, rex_prefix = 0;
+ /* Shadow copy of register state. Committed on successful emulation. */
+ struct cpu_user_regs _regs = *ctxt->regs;
+
+ uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
- uint16_t *seg = NULL; /* override segment */
+ uint16_t *seg = &_regs.ds; /* override segment */
unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
int rc = 0;
struct operand src, dst;
- unsigned long cr2 = ctxt->cr2;
+ unsigned long ea = 0, cr2 = ctxt->cr2;
int mode = ctxt->mode;
- /* Shadow copy of register state. Committed on successful emulation. */
- struct cpu_user_regs _regs = *ctxt->regs;
-
/*
* We do not emulate faults on instruction fetch. We assume that the
* guest never executes out of a special memory area.
@@ -478,7 +516,7 @@ x86_emulate_memop(
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
{
- switch ( b = insn_fetch(uint8_t, 1, _regs.eip) )
+ switch ( b = insn_fetch(uint8_t) )
{
case 0x66: /* operand-size override */
op_bytes ^= 6; /* switch between 2/4 bytes */
@@ -525,11 +563,9 @@ x86_emulate_memop(
if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
{
rex_prefix = b;
- if ( b & 8 )
- op_bytes = 8; /* REX.W */
- modrm_reg = (b & 4) << 1; /* REX.R */
- /* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1, _regs.eip);
+ if ( b & 8 ) /* REX.W */
+ op_bytes = 8;
+ b = insn_fetch(uint8_t);
}
/* Opcode byte(s). */
@@ -540,7 +576,7 @@ x86_emulate_memop(
if ( b == 0x0f )
{
twobyte = 1;
- b = insn_fetch(uint8_t, 1, _regs.eip);
+ b = insn_fetch(uint8_t);
d = twobyte_table[b];
}
@@ -552,58 +588,86 @@ x86_emulate_memop(
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
- modrm = insn_fetch(uint8_t, 1, _regs.eip);
- modrm_mod |= (modrm & 0xc0) >> 6;
- modrm_reg |= (modrm & 0x38) >> 3;
- modrm_rm |= (modrm & 0x07);
+ modrm = insn_fetch(uint8_t);
+ modrm_mod = (modrm & 0xc0) >> 6;
+ modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3);
+ modrm_rm = modrm & 0x07;
if ( modrm_mod == 3 )
{
- DPRINTF("Cannot parse ModRM.mod == 3.\n");
+ dprintf("Cannot parse ModRM.mod == 3.\n");
goto cannot_emulate;
}
if ( ad_bytes == 2 )
{
/* 16-bit ModR/M decode. */
+ switch ( modrm_rm )
+ {
+ case 0: ea = _regs.ebx + _regs.esi; break;
+ case 1: ea = _regs.ebx + _regs.edi; break;
+ case 2: ea = _regs.ebp + _regs.esi; break;
+ case 3: ea = _regs.ebp + _regs.edi; break;
+ case 4: ea = _regs.esi; break;
+ case 5: ea = _regs.edi; break;
+ case 6: ea = _regs.ebp; break;
+ case 7: ea = _regs.ebx; break;
+ }
switch ( modrm_mod )
{
- case 0:
- if ( modrm_rm == 6 )
- _regs.eip += 2; /* skip disp16 */
- break;
- case 1:
- _regs.eip += 1; /* skip disp8 */
- break;
- case 2:
- _regs.eip += 2; /* skip disp16 */
- break;
+ case 0: if ( modrm_rm == 6 ) ea = insn_fetch(uint16_t); break;
+ case 1: ea += insn_fetch(uint8_t); break;
+ case 2: ea += insn_fetch(uint16_t); break;
}
}
else
{
/* 32/64-bit ModR/M decode. */
+ if ( modrm_rm == 4 )
+ {
+ sib = insn_fetch(uint8_t);
+ sib_index = ((sib >> 3) & 7) | ((modrm << 2) & 8);
+ sib_base = (sib & 7) | ((modrm << 3) & 8);
+ if ( sib_index != 4 )
+ ea = *(long *)decode_register(sib_index, &_regs, 0);
+ ea <<= (sib >> 6) & 3;
+ if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
+ ea += insn_fetch(uint32_t);
+ else
+ ea += *(long *)decode_register(sib_base, &_regs, 0);
+ }
+ else
+ {
+ modrm_rm |= (rex_prefix & 1) << 3;
+ ea = *(long *)decode_register(modrm_rm, &_regs, 0);
+ }
switch ( modrm_mod )
{
case 0:
- if ( (modrm_rm == 4) &&
- (((sib = insn_fetch(uint8_t, 1, _regs.eip)) & 7) == 5) )
- _regs.eip += 4; /* skip disp32 specified by SIB.base */
- else if ( modrm_rm == 5 )
- _regs.eip += 4; /* skip disp32 */
- break;
- case 1:
- if ( modrm_rm == 4 )
- sib = insn_fetch(uint8_t, 1, _regs.eip);
- _regs.eip += 1; /* skip disp8 */
- break;
- case 2:
- if ( modrm_rm == 4 )
- sib = insn_fetch(uint8_t, 1, _regs.eip);
- _regs.eip += 4; /* skip disp32 */
+ if ( (modrm_rm & 7) != 5 )
+ break;
+ ea = insn_fetch(uint32_t);
+ if ( mode != X86EMUL_MODE_PROT64 )
+ break;
+ /* Relative to RIP of next instruction. Argh! */
+ ea += _regs.eip;
+ if ( (d & SrcMask) == SrcImm )
+ ea += (d & ByteOp) ? 1 : op_bytes;
+ else if ( (d & SrcMask) == SrcImmByte )
+ ea += 1;
+ else if ( ((b == 0xf6) || (b == 0xf7)) &&
+ ((modrm_reg & 7) <= 1) )
+ /* Special case in Grp3: test has immediate operand. */
+ ea += (d & ByteOp) ? 1
+ : ((op_bytes == 8) ? 4 : op_bytes);
break;
+ case 1: ea += insn_fetch(uint8_t); break;
+ case 2: ea += insn_fetch(uint32_t); break;
}
}
+
+ ea = register_address(*seg, ea);
+ page_boundary_test();
}
/* Decode and fetch the destination operand: register or memory. */
@@ -691,16 +755,16 @@ x86_emulate_memop(
/* NB. Immediates are sign-extended as necessary. */
switch ( src.bytes )
{
- case 1: src.val = insn_fetch(int8_t, 1, _regs.eip); break;
- case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
- case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
+ case 1: src.val = insn_fetch(int8_t); break;
+ case 2: src.val = insn_fetch(int16_t); break;
+ case 4: src.val = insn_fetch(int32_t); break;
}
break;
case SrcImmByte:
src.type = OP_IMM;
src.ptr = (unsigned long *)_regs.eip;
src.bytes = 1;
- src.val = insn_fetch(int8_t, 1, _regs.eip);
+ src.val = insn_fetch(int8_t);
break;
}
@@ -739,7 +803,7 @@ x86_emulate_memop(
dst.val = (int32_t)src.val;
break;
case 0x80 ... 0x83: /* Grp1 */
- switch ( modrm_reg )
+ switch ( modrm_reg & 7 )
{
case 0: goto add;
case 1: goto or;
@@ -770,11 +834,15 @@ x86_emulate_memop(
case 0xa0 ... 0xa1: /* mov */
dst.ptr = (unsigned long *)&_regs.eax;
dst.val = src.val;
- _regs.eip += ad_bytes; /* skip src displacement */
+ /* Source EA is not encoded via ModRM. */
+ ea = register_address(*seg, _insn_fetch(ad_bytes));
+ page_boundary_test();
break;
case 0xa2 ... 0xa3: /* mov */
dst.val = (unsigned long)_regs.eax;
- _regs.eip += ad_bytes; /* skip dst displacement */
+ /* Destination EA is not encoded via ModRM. */
+ ea = register_address(*seg, _insn_fetch(ad_bytes));
+ page_boundary_test();
break;
case 0x88 ... 0x8b: /* mov */
case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
@@ -797,7 +865,7 @@ x86_emulate_memop(
register_address_increment(_regs.esp, dst.bytes);
break;
case 0xc0 ... 0xc1: grp2: /* Grp2 */
- switch ( modrm_reg )
+ switch ( modrm_reg & 7 )
{
case 0: /* rol */
emulate_2op_SrcB("rol", src, dst, _regs.eflags);
@@ -830,7 +898,7 @@ x86_emulate_memop(
src.val = _regs.ecx;
goto grp2;
case 0xf6 ... 0xf7: /* Grp3 */
- switch ( modrm_reg )
+ switch ( modrm_reg & 7 )
{
case 0 ... 1: /* test */
/* Special case in Grp3: test has an immediate source operand. */
@@ -840,9 +908,9 @@ x86_emulate_memop(
if ( src.bytes == 8 ) src.bytes = 4;
switch ( src.bytes )
{
- case 1: src.val = insn_fetch(int8_t, 1, _regs.eip); break;
- case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
- case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
+ case 1: src.val = insn_fetch(int8_t); break;
+ case 2: src.val = insn_fetch(int16_t); break;
+ case 4: src.val = insn_fetch(int32_t); break;
}
goto test;
case 2: /* not */
@@ -856,7 +924,7 @@ x86_emulate_memop(
}
break;
case 0xfe ... 0xff: /* Grp4/Grp5 */
- switch ( modrm_reg )
+ switch ( modrm_reg & 7 )
{
case 0: /* inc */
emulate_1op("inc", dst, _regs.eflags);
@@ -950,10 +1018,10 @@ x86_emulate_memop(
{
/* Write fault: destination is special memory. */
dst.ptr = (unsigned long *)cr2;
- if ( (rc = ops->read_std(register_address(seg ? *seg : _regs.ds,
- _regs.esi),
+ if ( (rc = ops->read_std(register_address(*seg, _regs.esi),
&dst.val, dst.bytes, ctxt)) != 0 )
goto done;
+ ea = register_address(_regs.es, _regs.edi);
}
else
{
@@ -962,16 +1030,17 @@ x86_emulate_memop(
if ( (rc = ops->read_emulated(cr2, &dst.val,
dst.bytes, ctxt)) != 0 )
goto done;
+ ea = register_address(*seg, _regs.esi);
}
+ page_boundary_test();
register_address_increment(
_regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
register_address_increment(
_regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
break;
- case 0xa6 ... 0xa7: /* cmps */
- DPRINTF("Urk! I don't handle CMPS.\n");
- goto cannot_emulate;
case 0xaa ... 0xab: /* stos */
+ ea = register_address(_regs.es, _regs.edi);
+ page_boundary_test();
dst.type = OP_MEM;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.ptr = (unsigned long *)cr2;
@@ -980,6 +1049,8 @@ x86_emulate_memop(
_regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
break;
case 0xac ... 0xad: /* lods */
+ ea = register_address(*seg, _regs.esi);
+ page_boundary_test();
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.ptr = (unsigned long *)&_regs.eax;
@@ -988,9 +1059,6 @@ x86_emulate_memop(
register_address_increment(
_regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
break;
- case 0xae ... 0xaf: /* scas */
- DPRINTF("Urk! I don't handle SCAS.\n");
- goto cannot_emulate;
}
goto writeback;
@@ -1148,7 +1216,14 @@ x86_emulate_memop(
goto writeback;
cannot_emulate:
- DPRINTF("Cannot emulate %02x\n", b);
+ dprintf("Cannot emulate %02x\n", b);
+ dump_instr(ctxt, ops);
+ return -1;
+
+ bad_ea:
+ dprintf("Access faulted on page boundary (cr2=%lx,ea=%lx).\n", cr2, ea);
+ dump_instr(ctxt, ops);
+ show_execution_state(ctxt->regs);
return -1;
}
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 130e2b438b..770c4b376f 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -20,14 +20,16 @@ obj-y += softirq.o
obj-y += string.o
obj-y += symbols.o
obj-y += sysctl.o
-obj-y += trace.o
+obj-y += time.o
obj-y += timer.o
+obj-y += trace.o
obj-y += version.o
obj-y += vsprintf.o
obj-y += xmalloc.o
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
+obj-$(xenoprof) += xenoprof.o
# Object file contains changeset and compiler information.
version.o: $(BASEDIR)/include/xen/compile.h
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 1138a9aa5e..238ee037a7 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -22,12 +22,13 @@
#include <xen/delay.h>
#include <xen/shutdown.h>
#include <xen/percpu.h>
+#include <xen/multicall.h>
#include <asm/debugger.h>
#include <public/sched.h>
#include <public/vcpu.h>
/* Both these structures are protected by the domlist_lock. */
-rwlock_t domlist_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(domlist_lock);
struct domain *domain_hash[DOMAIN_HASH_SIZE];
struct domain *domain_list;
@@ -35,6 +36,11 @@ struct domain *dom0;
struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
+int current_domain_id(void)
+{
+ return current->domain->domain_id;
+}
+
struct domain *alloc_domain(domid_t domid)
{
struct domain *d;
@@ -54,22 +60,24 @@ struct domain *alloc_domain(domid_t domid)
return d;
}
-
void free_domain(struct domain *d)
{
struct vcpu *v;
int i;
- sched_destroy_domain(d);
-
for ( i = MAX_VIRT_CPUS-1; i >= 0; i-- )
- if ( (v = d->vcpu[i]) != NULL )
- free_vcpu_struct(v);
+ {
+ if ( (v = d->vcpu[i]) == NULL )
+ continue;
+ vcpu_destroy(v);
+ sched_destroy_vcpu(v);
+ free_vcpu_struct(v);
+ }
+ sched_destroy_domain(d);
xfree(d);
}
-
struct vcpu *alloc_vcpu(
struct domain *d, unsigned int vcpu_id, unsigned int cpu_id)
{
@@ -77,26 +85,29 @@ struct vcpu *alloc_vcpu(
BUG_ON(d->vcpu[vcpu_id] != NULL);
- if ( (v = alloc_vcpu_struct(d, vcpu_id)) == NULL )
+ if ( (v = alloc_vcpu_struct()) == NULL )
return NULL;
v->domain = d;
v->vcpu_id = vcpu_id;
- v->processor = cpu_id;
v->vcpu_info = &d->shared_info->vcpu_info[vcpu_id];
spin_lock_init(&v->pause_lock);
- v->cpu_affinity = is_idle_domain(d) ?
- cpumask_of_cpu(cpu_id) : CPU_MASK_ALL;
-
v->runstate.state = is_idle_vcpu(v) ? RUNSTATE_running : RUNSTATE_offline;
v->runstate.state_entry_time = NOW();
if ( (vcpu_id != 0) && !is_idle_domain(d) )
set_bit(_VCPUF_down, &v->vcpu_flags);
- if ( sched_init_vcpu(v) < 0 )
+ if ( sched_init_vcpu(v, cpu_id) != 0 )
+ {
+ free_vcpu_struct(v);
+ return NULL;
+ }
+
+ if ( vcpu_initialise(v) != 0 )
{
+ sched_destroy_vcpu(v);
free_vcpu_struct(v);
return NULL;
}
@@ -115,7 +126,7 @@ struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
unsigned int vcpu_id = cpu_id % MAX_VIRT_CPUS;
d = (vcpu_id == 0) ?
- domain_create(IDLE_DOMAIN_ID) :
+ domain_create(IDLE_DOMAIN_ID, 0) :
idle_vcpu[cpu_id - vcpu_id]->domain;
BUG_ON(d == NULL);
@@ -125,13 +136,16 @@ struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
return v;
}
-struct domain *domain_create(domid_t domid)
+struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
{
struct domain *d, **pd;
if ( (d = alloc_domain(domid)) == NULL )
return NULL;
+ if ( domcr_flags & DOMCRF_hvm )
+ d->is_hvm = 1;
+
rangeset_domain_initialise(d);
if ( !is_idle_domain(d) )
@@ -151,6 +165,9 @@ struct domain *domain_create(domid_t domid)
if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
goto fail4;
+ if ( sched_init_domain(d) != 0 )
+ goto fail4;
+
if ( !is_idle_domain(d) )
{
write_lock(&domlist_lock);
@@ -240,46 +257,24 @@ void __domain_crash(struct domain *d)
void __domain_crash_synchronous(void)
{
__domain_crash(current->domain);
- for ( ; ; )
- do_softirq();
-}
-
-
-static DEFINE_PER_CPU(struct domain *, domain_shuttingdown);
-
-static void domain_shutdown_finalise(void)
-{
- struct domain *d;
- struct vcpu *v;
-
- d = this_cpu(domain_shuttingdown);
- this_cpu(domain_shuttingdown) = NULL;
-
- BUG_ON(d == NULL);
- BUG_ON(d == current->domain);
-
- LOCK_BIGLOCK(d);
- /* Make sure that every vcpu is descheduled before we finalise. */
- for_each_vcpu ( d, v )
- vcpu_sleep_sync(v);
- BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
-
- /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
- if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
- send_guest_global_virq(dom0, VIRQ_DOM_EXC);
-
- UNLOCK_BIGLOCK(d);
+ /*
+ * Flush multicall state before dying if a multicall is in progress.
+ * This shouldn't be necessary, but some architectures are calling
+ * domain_crash_synchronous() when they really shouldn't (i.e., from
+ * within hypercall context).
+ */
+ if ( this_cpu(mc_state).flags != 0 )
+ {
+ dprintk(XENLOG_ERR,
+ "FIXME: synchronous domain crash during a multicall!\n");
+ this_cpu(mc_state).flags = 0;
+ }
- put_domain(d);
+ for ( ; ; )
+ do_softirq();
}
-static __init int domain_shutdown_finaliser_init(void)
-{
- open_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ, domain_shutdown_finalise);
- return 0;
-}
-__initcall(domain_shutdown_finaliser_init);
void domain_shutdown(struct domain *d, u8 reason)
{
@@ -288,20 +283,13 @@ void domain_shutdown(struct domain *d, u8 reason)
if ( d->domain_id == 0 )
dom0_shutdown(reason);
- /* Mark the domain as shutting down. */
d->shutdown_code = reason;
+ set_bit(_DOMF_shutdown, &d->domain_flags);
- /* Put every vcpu to sleep, but don't wait (avoids inter-vcpu deadlock). */
- spin_lock(&d->pause_lock);
- d->pause_count++;
- set_bit(_DOMF_paused, &d->domain_flags);
- spin_unlock(&d->pause_lock);
for_each_vcpu ( d, v )
vcpu_sleep_nosync(v);
- get_knownalive_domain(d);
- this_cpu(domain_shuttingdown) = d;
- raise_softirq(DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ);
+ send_guest_global_virq(dom0, VIRQ_DOM_EXC);
}
@@ -310,12 +298,8 @@ void domain_pause_for_debugger(void)
struct domain *d = current->domain;
struct vcpu *v;
- /*
- * NOTE: This does not synchronously pause the domain. The debugger
- * must issue a PAUSEDOMAIN command to ensure that all execution
- * has ceased and guest state is committed to memory.
- */
set_bit(_DOMF_ctrl_pause, &d->domain_flags);
+
for_each_vcpu ( d, v )
vcpu_sleep_nosync(v);
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index a053145a1a..bf6b8473aa 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -83,7 +83,7 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
{
struct vcpu *v;
u64 cpu_time = 0;
- int flags = DOMFLAGS_BLOCKED;
+ int flags = XEN_DOMINF_blocked;
struct vcpu_runstate_info runstate;
info->domain = d->domain_id;
@@ -93,29 +93,33 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
* - domain is marked as blocked only if all its vcpus are blocked
* - domain is marked as running if any of its vcpus is running
*/
- for_each_vcpu ( d, v ) {
+ for_each_vcpu ( d, v )
+ {
vcpu_runstate_get(v, &runstate);
cpu_time += runstate.time[RUNSTATE_running];
info->max_vcpu_id = v->vcpu_id;
if ( !test_bit(_VCPUF_down, &v->vcpu_flags) )
{
if ( !(v->vcpu_flags & VCPUF_blocked) )
- flags &= ~DOMFLAGS_BLOCKED;
+ flags &= ~XEN_DOMINF_blocked;
if ( v->vcpu_flags & VCPUF_running )
- flags |= DOMFLAGS_RUNNING;
+ flags |= XEN_DOMINF_running;
info->nr_online_vcpus++;
}
}
-
+
info->cpu_time = cpu_time;
-
+
info->flags = flags |
- ((d->domain_flags & DOMF_dying) ? DOMFLAGS_DYING : 0) |
- ((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
- ((d->domain_flags & DOMF_ctrl_pause) ? DOMFLAGS_PAUSED : 0) |
- d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
+ ((d->domain_flags & DOMF_dying) ? XEN_DOMINF_dying : 0) |
+ ((d->domain_flags & DOMF_shutdown) ? XEN_DOMINF_shutdown : 0) |
+ ((d->domain_flags & DOMF_ctrl_pause) ? XEN_DOMINF_paused : 0) |
+ d->shutdown_code << XEN_DOMINF_shutdownshift;
+
+ if ( is_hvm_domain(d) )
+ info->flags |= XEN_DOMINF_hvm_guest;
- if (d->ssid != NULL)
+ if ( d->ssid != NULL )
info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
else
info->ssidref = ACM_DEFAULT_SSID;
@@ -241,12 +245,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
struct domain *d;
domid_t dom;
static domid_t rover = 0;
+ unsigned int domcr_flags;
- /*
- * Running the domain 0 kernel in ring 0 is not compatible
- * with multiple guests.
- */
- if ( supervisor_mode_kernel )
+ if ( supervisor_mode_kernel ||
+ (op->u.createdomain.flags & ~XEN_DOMCTL_CDF_hvm_guest) )
return -EINVAL;
dom = op->domain;
@@ -273,8 +275,12 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
rover = dom;
}
+ domcr_flags = 0;
+ if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hvm_guest )
+ domcr_flags |= DOMCRF_hvm;
+
ret = -ENOMEM;
- if ( (d = domain_create(dom)) == NULL )
+ if ( (d = domain_create(dom, domcr_flags)) == NULL )
break;
memcpy(d->handle, op->u.createdomain.handle,
@@ -356,37 +362,20 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
struct vcpu *v;
cpumask_t new_affinity;
+ ret = -ESRCH;
if ( d == NULL )
- {
- ret = -ESRCH;
- break;
- }
-
- if ( (op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS) ||
- !d->vcpu[op->u.vcpuaffinity.vcpu] )
- {
- ret = -EINVAL;
- put_domain(d);
break;
- }
- v = d->vcpu[op->u.vcpuaffinity.vcpu];
- if ( v == NULL )
- {
- ret = -ESRCH;
- put_domain(d);
- break;
- }
+ ret = -EINVAL;
+ if ( op->u.vcpuaffinity.vcpu >= MAX_VIRT_CPUS )
+ goto vcpuaffinity_out;
+
+ ret = -ESRCH;
+ if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL )
+ goto vcpuaffinity_out;
if ( op->cmd == XEN_DOMCTL_setvcpuaffinity )
{
- if ( v == current )
- {
- ret = -EINVAL;
- put_domain(d);
- break;
- }
-
xenctl_cpumap_to_cpumask(
&new_affinity, &op->u.vcpuaffinity.cpumap);
ret = vcpu_set_affinity(v, &new_affinity);
@@ -395,8 +384,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
{
cpumask_to_xenctl_cpumap(
&op->u.vcpuaffinity.cpumap, &v->cpu_affinity);
+ ret = 0;
}
+ vcpuaffinity_out:
put_domain(d);
}
break;
diff --git a/xen/common/elf.c b/xen/common/elf.c
index 00730c1bb8..83381b4b1a 100644
--- a/xen/common/elf.c
+++ b/xen/common/elf.c
@@ -304,7 +304,7 @@ int parseelfimage(struct domain_setup_info *dsi)
if ( p != NULL && strncmp(p, "yes", 3) == 0 )
{
dsi->pae_kernel = PAEKERN_yes;
- if ( !strncmp(p+4, "[extended-cr3]", 14) )
+ if ( !strncmp(p+3, "[extended-cr3]", 14) )
dsi->pae_kernel = PAEKERN_extended_cr3;
}
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index e333144cf2..b0d23eb8e0 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -40,7 +40,8 @@
#define ERROR_EXIT(_errno) \
do { \
- DPRINTK("EVTCHNOP failure: domain %d, error %d, line %d\n", \
+ gdprintk(XENLOG_WARNING, \
+ "EVTCHNOP failure: domain %d, error %d, line %d\n", \
current->domain->domain_id, (_errno), __LINE__); \
rc = (_errno); \
goto out; \
diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c
index 8934122925..54a81680a7 100644
--- a/xen/common/gdbstub.c
+++ b/xen/common/gdbstub.c
@@ -53,6 +53,8 @@
static char opt_gdb[30] = "none";
string_param("gdb", opt_gdb);
+static void gdbstub_console_puts(const char *str);
+
/* value <-> char (de)serialzers */
char
hex2char(unsigned long x)
@@ -357,6 +359,24 @@ gdb_cmd_write_mem(unsigned long addr, unsigned long length,
gdb_send_packet(ctx);
}
+static void
+gdbstub_attach(struct gdb_context *ctx)
+{
+ if ( ctx->currently_attached )
+ return;
+ ctx->currently_attached = 1;
+ ctx->console_steal_id = console_steal(ctx->serhnd, gdbstub_console_puts);
+}
+
+static void
+gdbstub_detach(struct gdb_context *ctx)
+{
+ if ( !ctx->currently_attached )
+ return;
+ ctx->currently_attached = 0;
+ console_giveback(ctx->console_steal_id);
+}
+
/* command dispatcher */
static int
process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
@@ -427,7 +447,7 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
gdb_arch_read_reg(addr, regs, ctx);
break;
case 'D':
- ctx->currently_attached = 0;
+ gdbstub_detach(ctx);
gdb_send_reply("OK", ctx);
/* fall through */
case 'k':
@@ -444,7 +464,7 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
ctx->in_buf[1] )
addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long));
if ( ctx->in_buf[0] != 'D' )
- ctx->currently_attached = 1;
+ gdbstub_attach(ctx);
resume = 1;
gdb_arch_resume(regs, addr, type, ctx);
break;
@@ -459,29 +479,40 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
static struct gdb_context
__gdb_ctx = {
- .serhnd = -1,
- .currently_attached = 0,
- .running = ATOMIC_INIT(1),
- .connected = 0,
- .signum = 1,
- .in_bytes = 0,
- .out_offset = 0,
- .out_csum = 0,
+ .serhnd = -1,
+ .running = ATOMIC_INIT(1),
+ .signum = 1
};
static struct gdb_context *gdb_ctx = &__gdb_ctx;
+static void
+gdbstub_console_puts(const char *str)
+{
+ const char *p;
+
+ gdb_start_packet(gdb_ctx);
+ gdb_write_to_packet_char('O', gdb_ctx);
+
+ for ( p = str; *p != '\0'; p++ )
+ {
+ gdb_write_to_packet_char(hex2char((*p>>4) & 0x0f), gdb_ctx );
+ gdb_write_to_packet_char(hex2char((*p) & 0x0f), gdb_ctx );
+ }
+
+ gdb_send_packet(gdb_ctx);
+}
+
/* trap handler: main entry point */
int
__trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
{
- int resume = 0;
- int r;
+ int rc = 0;
unsigned long flags;
if ( gdb_ctx->serhnd < 0 )
{
dbg_printk("Debugger not ready yet.\n");
- return 0;
+ return -EBUSY;
}
/* We rely on our caller to ensure we're only on one processor
@@ -500,7 +531,7 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
{
printk("WARNING WARNING WARNING: Avoiding recursive gdb.\n");
atomic_inc(&gdb_ctx->running);
- return 0;
+ return -EBUSY;
}
if ( !gdb_ctx->connected )
@@ -525,6 +556,7 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
gdb_arch_enter(regs);
gdb_ctx->signum = gdb_arch_signal_num(regs, cookie);
+
/* If gdb is already attached, tell it we've stopped again. */
if ( gdb_ctx->currently_attached )
{
@@ -532,19 +564,14 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
gdb_cmd_signum(gdb_ctx);
}
- while ( resume == 0 )
- {
- r = receive_command(gdb_ctx);
- if ( r < 0 )
- {
- dbg_printk("GDB disappeared, trying to resume Xen...\n");
- resume = 1;
- }
- else
+ do {
+ if ( receive_command(gdb_ctx) < 0 )
{
- resume = process_command(regs, gdb_ctx);
+ dbg_printk("Error in GDB session...\n");
+ rc = -EIO;
+ break;
}
- }
+ } while ( process_command(regs, gdb_ctx) == 0 );
gdb_arch_exit(regs);
console_end_sync();
@@ -553,7 +580,7 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
local_irq_restore(flags);
- return 0;
+ return rc;
}
void
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index e2eac58487..3a6bc9587f 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -24,6 +24,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <xen/config.h>
+#include <xen/iocap.h>
#include <xen/lib.h>
#include <xen/sched.h>
#include <xen/shadow.h>
@@ -47,7 +49,7 @@ union grant_combo {
#define PIN_FAIL(_lbl, _rc, _f, _a...) \
do { \
- DPRINTK( _f, ## _a ); \
+ gdprintk(XENLOG_WARNING, _f, ## _a ); \
rc = (_rc); \
goto _lbl; \
} while ( 0 )
@@ -109,7 +111,8 @@ __gnttab_map_grant_ref(
if ( unlikely(op->ref >= NR_GRANT_ENTRIES) ||
unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
{
- DPRINTK("Bad ref (%d) or flags (%x).\n", op->ref, op->flags);
+ gdprintk(XENLOG_INFO, "Bad ref (%d) or flags (%x).\n",
+ op->ref, op->flags);
op->status = GNTST_bad_gntref;
return;
}
@@ -124,7 +127,7 @@ __gnttab_map_grant_ref(
{
if ( rd != NULL )
put_domain(rd);
- DPRINTK("Could not find domain %d\n", op->dom);
+ gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
op->status = GNTST_bad_domain;
return;
}
@@ -139,7 +142,7 @@ __gnttab_map_grant_ref(
if ( (lgt->maptrack_limit << 1) > MAPTRACK_MAX_ENTRIES )
{
put_domain(rd);
- DPRINTK("Maptrack table is at maximum size.\n");
+ gdprintk(XENLOG_INFO, "Maptrack table is at maximum size.\n");
op->status = GNTST_no_device_space;
return;
}
@@ -149,7 +152,7 @@ __gnttab_map_grant_ref(
if ( new_mt == NULL )
{
put_domain(rd);
- DPRINTK("No more map handles available.\n");
+ gdprintk(XENLOG_INFO, "No more map handles available.\n");
op->status = GNTST_no_device_space;
return;
}
@@ -166,7 +169,7 @@ __gnttab_map_grant_ref(
lgt->maptrack_order += 1;
lgt->maptrack_limit <<= 1;
- DPRINTK("Doubled maptrack size\n");
+ gdprintk(XENLOG_INFO, "Doubled maptrack size\n");
handle = get_maptrack_handle(ld->grant_table);
}
@@ -252,8 +255,12 @@ __gnttab_map_grant_ref(
get_page(mfn_to_page(frame), rd) :
get_page_and_type(mfn_to_page(frame), rd,
PGT_writable_page))) )
- PIN_FAIL(undo_out, GNTST_general_error,
- "Could not pin the granted frame (%lx)!\n", frame);
+ {
+ if ( !test_bit(_DOMF_dying, &rd->domain_flags) )
+ gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame);
+ rc = GNTST_general_error;
+ goto undo_out;
+ }
if ( op->flags & GNTMAP_host_map )
{
@@ -353,7 +360,7 @@ __gnttab_unmap_grant_ref(
if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) ||
unlikely(!map->flags) )
{
- DPRINTK("Bad handle (%d).\n", op->handle);
+ gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
op->status = GNTST_bad_handle;
return;
}
@@ -364,10 +371,9 @@ __gnttab_unmap_grant_ref(
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) )
{
- if ( rd != NULL )
- put_domain(rd);
- DPRINTK("Could not find domain %d\n", dom);
- op->status = GNTST_bad_domain;
+ /* This can happen when a grant is implicitly unmapped. */
+ gdprintk(XENLOG_INFO, "Could not find domain %d\n", dom);
+ domain_crash(ld); /* naughty... */
return;
}
@@ -486,13 +492,14 @@ gnttab_setup_table(
if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
{
- DPRINTK("Fault while reading gnttab_setup_table_t.\n");
+ gdprintk(XENLOG_INFO, "Fault while reading gnttab_setup_table_t.\n");
return -EFAULT;
}
if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) )
{
- DPRINTK("Xen only supports up to %d grant-table frames per domain.\n",
+ gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
+ " per domain.\n",
NR_GRANT_FRAMES);
op.status = GNTST_general_error;
goto out;
@@ -511,7 +518,7 @@ gnttab_setup_table(
if ( unlikely((d = find_domain_by_id(dom)) == NULL) )
{
- DPRINTK("Bad domid %d.\n", dom);
+ gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
op.status = GNTST_bad_domain;
goto out;
}
@@ -549,7 +556,7 @@ gnttab_prepare_for_transfer(
if ( unlikely((rgt = rd->grant_table) == NULL) ||
unlikely(ref >= NR_GRANT_ENTRIES) )
{
- DPRINTK("Dom %d has no g.t., or ref is bad (%d).\n",
+ gdprintk(XENLOG_INFO, "Dom %d has no g.t., or ref is bad (%d).\n",
rd->domain_id, ref);
return 0;
}
@@ -565,7 +572,8 @@ gnttab_prepare_for_transfer(
if ( unlikely(scombo.shorts.flags != GTF_accept_transfer) ||
unlikely(scombo.shorts.domid != ld->domain_id) )
{
- DPRINTK("Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
+ gdprintk(XENLOG_INFO, "Bad flags (%x) or dom (%d). "
+ "(NB. expected dom %d)\n",
scombo.shorts.flags, scombo.shorts.domid,
ld->domain_id);
goto fail;
@@ -581,7 +589,7 @@ gnttab_prepare_for_transfer(
if ( retries++ == 4 )
{
- DPRINTK("Shared grant entry is unstable.\n");
+ gdprintk(XENLOG_WARNING, "Shared grant entry is unstable.\n");
goto fail;
}
@@ -613,7 +621,8 @@ gnttab_transfer(
/* Read from caller address space. */
if ( unlikely(__copy_from_guest_offset(&gop, uop, i, 1)) )
{
- DPRINTK("gnttab_transfer: error reading req %d/%d\n", i, count);
+ gdprintk(XENLOG_INFO, "gnttab_transfer: error reading req %d/%d\n",
+ i, count);
return -EFAULT;
}
@@ -622,7 +631,7 @@ gnttab_transfer(
/* Check the passed page frame for basic validity. */
if ( unlikely(!mfn_valid(mfn)) )
{
- DPRINTK("gnttab_transfer: out-of-range %lx\n",
+ gdprintk(XENLOG_INFO, "gnttab_transfer: out-of-range %lx\n",
(unsigned long)gop.mfn);
gop.status = GNTST_bad_page;
goto copyback;
@@ -631,7 +640,7 @@ gnttab_transfer(
page = mfn_to_page(mfn);
if ( unlikely(IS_XEN_HEAP_FRAME(page)) )
{
- DPRINTK("gnttab_transfer: xen frame %lx\n",
+ gdprintk(XENLOG_INFO, "gnttab_transfer: xen frame %lx\n",
(unsigned long)gop.mfn);
gop.status = GNTST_bad_page;
goto copyback;
@@ -646,7 +655,8 @@ gnttab_transfer(
/* Find the target domain. */
if ( unlikely((e = find_domain_by_id(gop.domid)) == NULL) )
{
- DPRINTK("gnttab_transfer: can't find domain %d\n", gop.domid);
+ gdprintk(XENLOG_INFO, "gnttab_transfer: can't find domain %d\n",
+ gop.domid);
page->count_info &= ~(PGC_count_mask|PGC_allocated);
free_domheap_page(page);
gop.status = GNTST_bad_domain;
@@ -665,7 +675,8 @@ gnttab_transfer(
unlikely(!gnttab_prepare_for_transfer(e, d, gop.ref)) )
{
if ( !test_bit(_DOMF_dying, &e->domain_flags) )
- DPRINTK("gnttab_transfer: Transferee has no reservation "
+ gdprintk(XENLOG_INFO, "gnttab_transfer: "
+ "Transferee has no reservation "
"headroom (%d,%d) or provided a bad grant ref (%08x) "
"or is dying (%lx)\n",
e->tot_pages, e->max_pages, gop.ref, e->domain_flags);
@@ -701,7 +712,8 @@ gnttab_transfer(
copyback:
if ( unlikely(__copy_to_guest_offset(uop, i, &gop, 1)) )
{
- DPRINTK("gnttab_transfer: error writing resp %d/%d\n", i, count);
+ gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp %d/%d\n",
+ i, count);
return -EFAULT;
}
}
@@ -717,10 +729,6 @@ __release_grant_for_copy(
{
grant_entry_t *const sha = &rd->grant_table->shared[gref];
struct active_grant_entry *const act = &rd->grant_table->active[gref];
- const unsigned long r_frame = act->frame;
-
- if ( !readonly )
- gnttab_mark_dirty(rd, r_frame);
spin_lock(&rd->grant_table->lock);
@@ -743,7 +751,8 @@ __release_grant_for_copy(
/* Grab a frame number from a grant entry and update the flags and pin
count as appropriate. Note that this does *not* update the page
- type or reference counts. */
+ type or reference counts, and does not check that the mfn is
+ actually valid. */
static int
__acquire_grant_for_copy(
struct domain *rd, unsigned long gref, int readonly,
@@ -885,9 +894,16 @@ __gnttab_copy(
{
s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
}
- if ( !get_page(mfn_to_page(s_frame), sd) )
+ if ( unlikely(!mfn_valid(s_frame)) )
PIN_FAIL(error_out, GNTST_general_error,
- "could not get source frame %lx.\n", s_frame);
+ "source frame %lx invalid.\n", s_frame);
+ if ( !get_page(mfn_to_page(s_frame), sd) )
+ {
+ if ( !test_bit(_DOMF_dying, &sd->domain_flags) )
+ gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
+ rc = GNTST_general_error;
+ goto error_out;
+ }
have_s_ref = 1;
if ( dest_is_gref )
@@ -899,11 +915,18 @@ __gnttab_copy(
}
else
{
- d_frame = gmfn_to_mfn(sd, op->dest.u.gmfn);
+ d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
}
- if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
+ if ( unlikely(!mfn_valid(d_frame)) )
PIN_FAIL(error_out, GNTST_general_error,
- "could not get source frame %lx.\n", d_frame);
+ "destination frame %lx invalid.\n", d_frame);
+ if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
+ {
+ if ( !test_bit(_DOMF_dying, &dd->domain_flags) )
+ gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
+ rc = GNTST_general_error;
+ goto error_out;
+ }
sp = map_domain_page(s_frame);
dp = map_domain_page(d_frame);
@@ -913,6 +936,8 @@ __gnttab_copy(
unmap_domain_page(dp);
unmap_domain_page(sp);
+ gnttab_mark_dirty(dd, d_frame);
+
put_page_and_type(mfn_to_page(d_frame));
error_out:
if ( have_s_ref )
@@ -967,6 +992,9 @@ do_grant_table_op(
guest_handle_cast(uop, gnttab_map_grant_ref_t);
if ( unlikely(!guest_handle_okay(map, count)) )
goto out;
+ rc = -EPERM;
+ if ( unlikely(!grant_operation_permitted(d)) )
+ goto out;
rc = gnttab_map_grant_ref(map, count);
break;
}
@@ -976,6 +1004,9 @@ do_grant_table_op(
guest_handle_cast(uop, gnttab_unmap_grant_ref_t);
if ( unlikely(!guest_handle_okay(unmap, count)) )
goto out;
+ rc = -EPERM;
+ if ( unlikely(!grant_operation_permitted(d)) )
+ goto out;
rc = gnttab_unmap_grant_ref(unmap, count);
break;
}
@@ -991,6 +1022,9 @@ do_grant_table_op(
guest_handle_cast(uop, gnttab_transfer_t);
if ( unlikely(!guest_handle_okay(transfer, count)) )
goto out;
+ rc = -EPERM;
+ if ( unlikely(!grant_operation_permitted(d)) )
+ goto out;
rc = gnttab_transfer(transfer, count);
break;
}
@@ -1090,11 +1124,17 @@ gnttab_release_mappings(
ref = map->ref;
- DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n",
+ gdprintk(XENLOG_INFO, "Grant release (%hu) ref:(%hu) "
+ "flags:(%x) dom:(%hu)\n",
handle, ref, map->flags, map->domid);
rd = find_domain_by_id(map->domid);
- BUG_ON(rd == NULL);
+ if ( rd == NULL )
+ {
+ /* Nothing to clear up... */
+ map->flags = 0;
+ continue;
+ }
spin_lock(&rd->grant_table->lock);
@@ -1161,7 +1201,7 @@ grant_table_destroy(
return;
free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES);
- free_xenheap_page(t->maptrack);
+ free_xenheap_pages(t->maptrack, t->maptrack_order);
xfree(t->active);
xfree(t);
diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c
index e9e2b4d385..85fe6d89ca 100644
--- a/xen/common/keyhandler.c
+++ b/xen/common/keyhandler.c
@@ -36,8 +36,10 @@ static void keypress_softirq(void)
{
keyhandler_t *h;
unsigned char key = keypress_key;
+ console_start_log_everything();
if ( (h = key_table[key].u.handler) != NULL )
(*h)(key);
+ console_end_log_everything();
}
void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
@@ -46,8 +48,10 @@ void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
if ( key_table[key].flags & KEYHANDLER_IRQ_CALLBACK )
{
+ console_start_log_everything();
if ( (h = key_table[key].u.irq_handler) != NULL )
(*h)(key, regs);
+ console_end_log_everything();
}
else
{
@@ -173,6 +177,7 @@ static void dump_domains(unsigned char key)
printk("dirty_cpus=%s ", cpuset);
cpuset_print(cpuset, sizeof(cpuset), v->cpu_affinity);
printk("cpu_affinity=%s\n", cpuset);
+ arch_dump_vcpu_info(v);
printk(" Notifying guest (virq %d, port %d, stat %d/%d/%d)\n",
VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
test_bit(v->virq_to_evtchn[VIRQ_DEBUG],
diff --git a/xen/common/lib.c b/xen/common/lib.c
index 408e8eefe6..0eb58f19d2 100644
--- a/xen/common/lib.c
+++ b/xen/common/lib.c
@@ -439,21 +439,28 @@ s64 __moddi3(s64 a, s64 b)
#endif /* BITS_PER_LONG == 32 */
-unsigned long long parse_size_and_unit(char *s)
+unsigned long long parse_size_and_unit(const char *s, char **ps)
{
- unsigned long long ret = simple_strtoull(s, &s, 0);
+ unsigned long long ret = simple_strtoull(s, (char **)&s, 0);
switch (*s) {
case 'G': case 'g':
ret <<= 10;
case 'M': case 'm':
ret <<= 10;
- case 'K': case 'k': default:
+ case 'K': case 'k':
ret <<= 10;
case 'B': case 'b':
+ s++;
+ break;
+ default:
+ ret <<= 10; /* default to kB */
break;
}
+ if (ps != NULL)
+ *ps = (char *)s;
+
return ret;
}
diff --git a/xen/common/memory.c b/xen/common/memory.c
index c2827fa59f..33ead8e259 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -29,94 +29,105 @@
*/
#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
-static long
-increase_reservation(
- struct domain *d,
- XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
- unsigned int nr_extents,
- unsigned int extent_order,
- unsigned int memflags,
- int *preempted)
+struct memop_args {
+ /* INPUT */
+ struct domain *domain; /* Domain to be affected. */
+ XEN_GUEST_HANDLE(xen_pfn_t) extent_list; /* List of extent base addrs. */
+ unsigned int nr_extents; /* Number of extents to allocate or free. */
+ unsigned int extent_order; /* Size of each extent. */
+ unsigned int memflags; /* Allocation flags. */
+
+ /* INPUT/OUTPUT */
+ unsigned int nr_done; /* Number of extents processed so far. */
+ int preempted; /* Was the hypercall preempted? */
+};
+
+static unsigned int select_local_cpu(struct domain *d)
+{
+ struct vcpu *v = d->vcpu[0];
+ return (v ? v->processor : 0);
+}
+
+static void increase_reservation(struct memop_args *a)
{
struct page_info *page;
unsigned long i;
xen_pfn_t mfn;
+ struct domain *d = a->domain;
+ unsigned int cpu = select_local_cpu(d);
- if ( !guest_handle_is_null(extent_list) &&
- !guest_handle_okay(extent_list, nr_extents) )
- return 0;
+ if ( !guest_handle_is_null(a->extent_list) &&
+ !guest_handle_okay(a->extent_list, a->nr_extents) )
+ return;
- if ( (extent_order != 0) &&
+ if ( (a->extent_order != 0) &&
!multipage_allocation_permitted(current->domain) )
- return 0;
+ return;
- for ( i = 0; i < nr_extents; i++ )
+ for ( i = a->nr_done; i < a->nr_extents; i++ )
{
if ( hypercall_preempt_check() )
{
- *preempted = 1;
- return i;
+ a->preempted = 1;
+ goto out;
}
- if ( unlikely((page = alloc_domheap_pages(
- d, extent_order, memflags)) == NULL) )
+ page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags);
+ if ( unlikely(page == NULL) )
{
- DPRINTK("Could not allocate order=%d extent: "
+ gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: "
"id=%d memflags=%x (%ld of %d)\n",
- extent_order, d->domain_id, memflags, i, nr_extents);
- return i;
+ a->extent_order, d->domain_id, a->memflags,
+ i, a->nr_extents);
+ goto out;
}
/* Inform the domain of the new page's machine address. */
- if ( !guest_handle_is_null(extent_list) )
+ if ( !guest_handle_is_null(a->extent_list) )
{
mfn = page_to_mfn(page);
- if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
- return i;
+ if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
+ goto out;
}
}
- return nr_extents;
+ out:
+ a->nr_done = i;
}
-static long
-populate_physmap(
- struct domain *d,
- XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
- unsigned int nr_extents,
- unsigned int extent_order,
- unsigned int memflags,
- int *preempted)
+static void populate_physmap(struct memop_args *a)
{
struct page_info *page;
unsigned long i, j;
- xen_pfn_t gpfn;
- xen_pfn_t mfn;
+ xen_pfn_t gpfn, mfn;
+ struct domain *d = a->domain;
+ unsigned int cpu = select_local_cpu(d);
- if ( !guest_handle_okay(extent_list, nr_extents) )
- return 0;
+ if ( !guest_handle_okay(a->extent_list, a->nr_extents) )
+ return;
- if ( (extent_order != 0) &&
+ if ( (a->extent_order != 0) &&
!multipage_allocation_permitted(current->domain) )
- return 0;
+ return;
- for ( i = 0; i < nr_extents; i++ )
+ for ( i = a->nr_done; i < a->nr_extents; i++ )
{
if ( hypercall_preempt_check() )
{
- *preempted = 1;
+ a->preempted = 1;
goto out;
}
- if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) )
+ if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) )
goto out;
- if ( unlikely((page = alloc_domheap_pages(
- d, extent_order, memflags)) == NULL) )
+ page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags);
+ if ( unlikely(page == NULL) )
{
- DPRINTK("Could not allocate order=%d extent: "
- "id=%d memflags=%x (%ld of %d)\n",
- extent_order, d->domain_id, memflags, i, nr_extents);
+ gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: "
+ "id=%d memflags=%x (%ld of %d)\n",
+ a->extent_order, d->domain_id, a->memflags,
+ i, a->nr_extents);
goto out;
}
@@ -124,28 +135,25 @@ populate_physmap(
if ( unlikely(shadow_mode_translate(d)) )
{
- for ( j = 0; j < (1 << extent_order); j++ )
+ for ( j = 0; j < (1 << a->extent_order); j++ )
guest_physmap_add_page(d, gpfn + j, mfn + j);
}
else
{
- for ( j = 0; j < (1 << extent_order); j++ )
+ for ( j = 0; j < (1 << a->extent_order); j++ )
set_gpfn_from_mfn(mfn + j, gpfn + j);
/* Inform the domain of the new page's machine address. */
- if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
+ if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
goto out;
}
}
out:
- return i;
+ a->nr_done = i;
}
-int
-guest_remove_page(
- struct domain *d,
- unsigned long gmfn)
+int guest_remove_page(struct domain *d, unsigned long gmfn)
{
struct page_info *page;
unsigned long mfn;
@@ -153,7 +161,7 @@ guest_remove_page(
mfn = gmfn_to_mfn(d, gmfn);
if ( unlikely(!mfn_valid(mfn)) )
{
- DPRINTK("Domain %u page number %lx invalid\n",
+ gdprintk(XENLOG_INFO, "Domain %u page number %lx invalid\n",
d->domain_id, gmfn);
return 0;
}
@@ -161,7 +169,7 @@ guest_remove_page(
page = mfn_to_page(mfn);
if ( unlikely(!get_page(page, d)) )
{
- DPRINTK("Bad page free for domain %u\n", d->domain_id);
+ gdprintk(XENLOG_INFO, "Bad page free for domain %u\n", d->domain_id);
return 0;
}
@@ -174,7 +182,7 @@ guest_remove_page(
if ( unlikely(!page_is_removable(page)) )
{
/* We'll make this a guest-visible error in future, so take heed! */
- DPRINTK("Dom%d freeing in-use page %lx (pseudophys %lx):"
+ gdprintk(XENLOG_INFO, "Dom%d freeing in-use page %lx (pseudophys %lx):"
" count=%lx type=%lx\n",
d->domain_id, mfn, get_gpfn_from_mfn(mfn),
(unsigned long)page->count_info, page->u.inuse.type_info);
@@ -187,43 +195,35 @@ guest_remove_page(
return 1;
}
-static long
-decrease_reservation(
- struct domain *d,
- XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
- unsigned int nr_extents,
- unsigned int extent_order,
- int *preempted)
+static void decrease_reservation(struct memop_args *a)
{
unsigned long i, j;
xen_pfn_t gmfn;
- if ( !guest_handle_okay(extent_list, nr_extents) )
- return 0;
+ if ( !guest_handle_okay(a->extent_list, a->nr_extents) )
+ return;
- for ( i = 0; i < nr_extents; i++ )
+ for ( i = a->nr_done; i < a->nr_extents; i++ )
{
if ( hypercall_preempt_check() )
{
- *preempted = 1;
- return i;
+ a->preempted = 1;
+ goto out;
}
- if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) )
- return i;
+ if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) )
+ goto out;
- for ( j = 0; j < (1 << extent_order); j++ )
- {
- if ( !guest_remove_page(d, gmfn + j) )
- return i;
- }
+ for ( j = 0; j < (1 << a->extent_order); j++ )
+ if ( !guest_remove_page(a->domain, gmfn + j) )
+ goto out;
}
- return nr_extents;
+ out:
+ a->nr_done = i;
}
-static long
-translate_gpfn_list(
+static long translate_gpfn_list(
XEN_GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress)
{
struct xen_translate_gpfn_list op;
@@ -285,8 +285,7 @@ translate_gpfn_list(
return 0;
}
-static long
-memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
+static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
{
struct xen_memory_exchange exch;
LIST_HEAD(in_chunk_list);
@@ -294,7 +293,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
unsigned long in_chunk_order, out_chunk_order;
xen_pfn_t gpfn, gmfn, mfn;
unsigned long i, j, k;
- unsigned int memflags = 0;
+ unsigned int memflags = 0, cpu;
long rc = 0;
struct domain *d;
struct page_info *page;
@@ -337,24 +336,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
memflags = MEMF_dma;
}
- guest_handle_add_offset(exch.in.extent_start, exch.nr_exchanged);
- exch.in.nr_extents -= exch.nr_exchanged;
-
if ( exch.in.extent_order <= exch.out.extent_order )
{
in_chunk_order = exch.out.extent_order - exch.in.extent_order;
out_chunk_order = 0;
- guest_handle_add_offset(
- exch.out.extent_start, exch.nr_exchanged >> in_chunk_order);
- exch.out.nr_extents -= exch.nr_exchanged >> in_chunk_order;
}
else
{
in_chunk_order = 0;
out_chunk_order = exch.in.extent_order - exch.out.extent_order;
- guest_handle_add_offset(
- exch.out.extent_start, exch.nr_exchanged << out_chunk_order);
- exch.out.nr_extents -= exch.nr_exchanged << out_chunk_order;
}
/*
@@ -368,11 +358,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
}
d = current->domain;
- for ( i = 0; i < (exch.in.nr_extents >> in_chunk_order); i++ )
+ cpu = select_local_cpu(d);
+
+ for ( i = (exch.nr_exchanged >> in_chunk_order);
+ i < (exch.in.nr_extents >> in_chunk_order);
+ i++ )
{
if ( hypercall_preempt_check() )
{
- exch.nr_exchanged += i << in_chunk_order;
+ exch.nr_exchanged = i << in_chunk_order;
if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
return -EFAULT;
return hypercall_create_continuation(
@@ -413,8 +407,8 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
/* Allocate a chunk's worth of anonymous output pages. */
for ( j = 0; j < (1UL << out_chunk_order); j++ )
{
- page = alloc_domheap_pages(
- NULL, exch.out.extent_order, memflags);
+ page = __alloc_domheap_pages(
+ NULL, cpu, exch.out.extent_order, memflags);
if ( unlikely(page == NULL) )
{
rc = -ENOMEM;
@@ -473,7 +467,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
BUG_ON(j != (1UL << out_chunk_order));
}
- exch.nr_exchanged += exch.in.nr_extents;
+ exch.nr_exchanged = exch.in.nr_extents;
if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
rc = -EFAULT;
return rc;
@@ -500,7 +494,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
free_domheap_pages(page, exch.out.extent_order);
}
- exch.nr_exchanged += i << in_chunk_order;
+ exch.nr_exchanged = i << in_chunk_order;
fail_early:
if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
@@ -511,10 +505,10 @@ memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
{
struct domain *d;
- int rc, op, preempted = 0;
- unsigned int memflags = 0;
+ int rc, op;
unsigned long start_extent, progress;
struct xen_memory_reservation reservation;
+ struct memop_args args;
domid_t domid;
op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
@@ -536,9 +530,12 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
if ( unlikely(start_extent > reservation.nr_extents) )
return start_extent;
- if ( !guest_handle_is_null(reservation.extent_start) )
- guest_handle_add_offset(reservation.extent_start, start_extent);
- reservation.nr_extents -= start_extent;
+ args.extent_list = reservation.extent_start;
+ args.nr_extents = reservation.nr_extents;
+ args.extent_order = reservation.extent_order;
+ args.nr_done = start_extent;
+ args.preempted = 0;
+ args.memflags = 0;
if ( (reservation.address_bits != 0) &&
(reservation.address_bits <
@@ -546,7 +543,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
{
if ( reservation.address_bits < 31 )
return start_extent;
- memflags = MEMF_dma;
+ args.memflags = MEMF_dma;
}
if ( likely(reservation.domid == DOMID_SELF) )
@@ -554,44 +551,27 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
else if ( !IS_PRIV(current->domain) ||
((d = find_domain_by_id(reservation.domid)) == NULL) )
return start_extent;
+ args.domain = d;
switch ( op )
{
case XENMEM_increase_reservation:
- rc = increase_reservation(
- d,
- reservation.extent_start,
- reservation.nr_extents,
- reservation.extent_order,
- memflags,
- &preempted);
+ increase_reservation(&args);
break;
case XENMEM_decrease_reservation:
- rc = decrease_reservation(
- d,
- reservation.extent_start,
- reservation.nr_extents,
- reservation.extent_order,
- &preempted);
+ decrease_reservation(&args);
break;
- case XENMEM_populate_physmap:
- default:
- rc = populate_physmap(
- d,
- reservation.extent_start,
- reservation.nr_extents,
- reservation.extent_order,
- memflags,
- &preempted);
+ default: /* XENMEM_populate_physmap */
+ populate_physmap(&args);
break;
}
if ( unlikely(reservation.domid != DOMID_SELF) )
put_domain(d);
- rc += start_extent;
+ rc = args.nr_done;
- if ( preempted )
+ if ( args.preempted )
return hypercall_create_continuation(
__HYPERVISOR_memory_op, "lh",
op | (rc << START_EXTENT_SHIFT), arg);
diff --git a/xen/common/multicall.c b/xen/common/multicall.c
index 7ba43ebd64..499e6bd62c 100644
--- a/xen/common/multicall.c
+++ b/xen/common/multicall.c
@@ -24,7 +24,7 @@ do_multicall(
if ( unlikely(__test_and_set_bit(_MCSF_in_multicall, &mcs->flags)) )
{
- DPRINTK("Multicall reentry is disallowed.\n");
+ gdprintk(XENLOG_INFO, "Multicall reentry is disallowed.\n");
return -EINVAL;
}
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 70aab2799b..93fc193e17 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -4,6 +4,7 @@
* Simple buddy heap allocator for Xen.
*
* Copyright (c) 2002-2004 K A Fraser
+ * Copyright (c) 2006 IBM Ryan Harper <ryanh@us.ibm.com>
*
* 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
@@ -33,6 +34,8 @@
#include <xen/domain_page.h>
#include <xen/keyhandler.h>
#include <xen/perfc.h>
+#include <xen/numa.h>
+#include <xen/nodemask.h>
#include <asm/page.h>
/*
@@ -51,7 +54,7 @@ static unsigned long lowmem_emergency_pool_pages;
static void parse_lowmem_emergency_pool(char *s)
{
unsigned long long bytes;
- bytes = parse_size_and_unit(s);
+ bytes = parse_size_and_unit(s, NULL);
lowmem_emergency_pool_pages = bytes >> PAGE_SHIFT;
}
custom_param("lowmem_emergency_pool", parse_lowmem_emergency_pool);
@@ -247,22 +250,23 @@ unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align)
#define pfn_dom_zone_type(_pfn) \
(((_pfn) <= MAX_DMADOM_PFN) ? MEMZONE_DMADOM : MEMZONE_DOM)
-static struct list_head heap[NR_ZONES][MAX_ORDER+1];
+static struct list_head heap[NR_ZONES][MAX_NUMNODES][MAX_ORDER+1];
-static unsigned long avail[NR_ZONES];
+static unsigned long avail[NR_ZONES][MAX_NUMNODES];
static DEFINE_SPINLOCK(heap_lock);
void end_boot_allocator(void)
{
- unsigned long i, j;
+ unsigned long i, j, k;
int curr_free = 0, next_free = 0;
memset(avail, 0, sizeof(avail));
for ( i = 0; i < NR_ZONES; i++ )
- for ( j = 0; j <= MAX_ORDER; j++ )
- INIT_LIST_HEAD(&heap[i][j]);
+ for ( j = 0; j < MAX_NUMNODES; j++ )
+ for ( k = 0; k <= MAX_ORDER; k++ )
+ INIT_LIST_HEAD(&heap[i][j][k]);
/* Pages that are free now go to the domain sub-allocator. */
for ( i = 0; i < max_page; i++ )
@@ -272,29 +276,59 @@ void end_boot_allocator(void)
if ( next_free )
map_alloc(i+1, 1); /* prevent merging in free_heap_pages() */
if ( curr_free )
- free_heap_pages(pfn_dom_zone_type(i), mfn_to_page(i), 0);
+ init_heap_pages(pfn_dom_zone_type(i), mfn_to_page(i), 1);
}
}
-/* Hand the specified arbitrary page range to the specified heap zone. */
+/*
+ * Hand the specified arbitrary page range to the specified heap zone
+ * checking the node_id of the previous page. If they differ and the
+ * latter is not on a MAX_ORDER boundary, then we reserve the page by
+ * not freeing it to the buddy allocator.
+ */
+#define MAX_ORDER_ALIGNED (1UL << (MAX_ORDER))
void init_heap_pages(
unsigned int zone, struct page_info *pg, unsigned long nr_pages)
{
+ unsigned int nid_curr,nid_prev;
unsigned long i;
ASSERT(zone < NR_ZONES);
+ if ( likely(page_to_mfn(pg) != 0) )
+ nid_prev = phys_to_nid(page_to_maddr(pg-1));
+ else
+ nid_prev = phys_to_nid(page_to_maddr(pg));
+
for ( i = 0; i < nr_pages; i++ )
- free_heap_pages(zone, pg+i, 0);
+ {
+ nid_curr = phys_to_nid(page_to_maddr(pg+i));
+
+ /*
+ * free pages of the same node, or if they differ, but are on a
+ * MAX_ORDER alignement boundary (which already get reserved)
+ */
+ if ( (nid_curr == nid_prev) || (page_to_maddr(pg+i) &
+ MAX_ORDER_ALIGNED) )
+ free_heap_pages(zone, pg+i, 0);
+ else
+ printk("Reserving non-aligned node boundary @ mfn %lu\n",
+ page_to_mfn(pg+i));
+
+ nid_prev = nid_curr;
+ }
}
-
/* Allocate 2^@order contiguous pages. */
-struct page_info *alloc_heap_pages(unsigned int zone, unsigned int order)
+struct page_info *alloc_heap_pages(unsigned int zone, unsigned int cpu,
+ unsigned int order)
{
- int i;
+ unsigned int i,j, node = cpu_to_node(cpu), num_nodes = num_online_nodes();
+ unsigned int request = (1UL << order);
struct page_info *pg;
+ ASSERT(node >= 0);
+ ASSERT(node < num_nodes);
ASSERT(zone < NR_ZONES);
if ( unlikely(order > MAX_ORDER) )
@@ -302,29 +336,46 @@ struct page_info *alloc_heap_pages(unsigned int zone, unsigned int order)
spin_lock(&heap_lock);
- /* Find smallest order which can satisfy the request. */
- for ( i = order; i <= MAX_ORDER; i++ )
- if ( !list_empty(&heap[zone][i]) )
- goto found;
+ /* start with requested node, but exhaust all node memory
+ * in requested zone before failing, only calc new node
+ * value if we fail to find memory in target node, this avoids
+ * needless computation on fast-path */
+ for ( i = 0; i < num_nodes; i++ )
+ {
+ /* check if target node can support the allocation */
+ if ( avail[zone][node] >= request )
+ {
+ /* Find smallest order which can satisfy the request. */
+ for ( j = order; j <= MAX_ORDER; j++ )
+ {
+ if ( !list_empty(&heap[zone][node][j]) )
+ goto found;
+ }
+ }
+ /* pick next node, wrapping around if needed */
+ if ( ++node == num_nodes )
+ node = 0;
+ }
/* No suitable memory blocks. Fail the request. */
spin_unlock(&heap_lock);
return NULL;
found:
- pg = list_entry(heap[zone][i].next, struct page_info, list);
+ pg = list_entry(heap[zone][node][j].next, struct page_info, list);
list_del(&pg->list);
/* We may have to halve the chunk a number of times. */
- while ( i != order )
+ while ( j != order )
{
- PFN_ORDER(pg) = --i;
- list_add_tail(&pg->list, &heap[zone][i]);
- pg += 1 << i;
+ PFN_ORDER(pg) = --j;
+ list_add_tail(&pg->list, &heap[zone][node][j]);
+ pg += 1 << j;
}
- map_alloc(page_to_mfn(pg), 1 << order);
- avail[zone] -= 1 << order;
+ map_alloc(page_to_mfn(pg), request);
+ ASSERT(avail[zone][node] >= request);
+ avail[zone][node] -= request;
spin_unlock(&heap_lock);
@@ -337,14 +388,17 @@ void free_heap_pages(
unsigned int zone, struct page_info *pg, unsigned int order)
{
unsigned long mask;
+ int node = phys_to_nid(page_to_maddr(pg));
ASSERT(zone < NR_ZONES);
ASSERT(order <= MAX_ORDER);
+ ASSERT(node >= 0);
+ ASSERT(node < num_online_nodes());
spin_lock(&heap_lock);
map_free(page_to_mfn(pg), 1 << order);
- avail[zone] += 1 << order;
+ avail[zone][node] += 1 << order;
/* Merge chunks as far as possible. */
while ( order < MAX_ORDER )
@@ -370,10 +424,13 @@ void free_heap_pages(
}
order++;
+
+ /* after merging, pg should be in the same node */
+ ASSERT(phys_to_nid(page_to_maddr(pg)) == node );
}
PFN_ORDER(pg) = order;
- list_add_tail(&pg->list, &heap[zone][order]);
+ list_add_tail(&pg->list, &heap[zone][node][order]);
spin_unlock(&heap_lock);
}
@@ -466,7 +523,7 @@ void *alloc_xenheap_pages(unsigned int order)
int i;
local_irq_save(flags);
- pg = alloc_heap_pages(MEMZONE_XEN, order);
+ pg = alloc_heap_pages(MEMZONE_XEN, smp_processor_id(), order);
local_irq_restore(flags);
if ( unlikely(pg == NULL) )
@@ -542,7 +599,8 @@ int assign_pages(
if ( unlikely(test_bit(_DOMF_dying, &d->domain_flags)) )
{
- DPRINTK("Cannot assign page to domain%d -- dying.\n", d->domain_id);
+ gdprintk(XENLOG_INFO, "Cannot assign page to domain%d -- dying.\n",
+ d->domain_id);
goto fail;
}
@@ -550,7 +608,7 @@ int assign_pages(
{
if ( unlikely((d->tot_pages + (1 << order)) > d->max_pages) )
{
- DPRINTK("Over-allocation for domain %u: %u > %u\n",
+ gdprintk(XENLOG_INFO, "Over-allocation for domain %u: %u > %u\n",
d->domain_id, d->tot_pages + (1 << order), d->max_pages);
goto fail;
}
@@ -580,8 +638,9 @@ int assign_pages(
}
-struct page_info *alloc_domheap_pages(
- struct domain *d, unsigned int order, unsigned int memflags)
+struct page_info *__alloc_domheap_pages(
+ struct domain *d, unsigned int cpu, unsigned int order,
+ unsigned int memflags)
{
struct page_info *pg = NULL;
cpumask_t mask;
@@ -591,17 +650,17 @@ struct page_info *alloc_domheap_pages(
if ( !(memflags & MEMF_dma) )
{
- pg = alloc_heap_pages(MEMZONE_DOM, order);
+ pg = alloc_heap_pages(MEMZONE_DOM, cpu, order);
/* Failure? Then check if we can fall back to the DMA pool. */
if ( unlikely(pg == NULL) &&
((order > MAX_ORDER) ||
- (avail[MEMZONE_DMADOM] <
+ (avail_heap_pages(MEMZONE_DMADOM,-1) <
(lowmem_emergency_pool_pages + (1UL << order)))) )
return NULL;
}
if ( pg == NULL )
- if ( (pg = alloc_heap_pages(MEMZONE_DMADOM, order)) == NULL )
+ if ( (pg = alloc_heap_pages(MEMZONE_DMADOM, cpu, order)) == NULL )
return NULL;
mask = pg->u.free.cpumask;
@@ -640,6 +699,11 @@ struct page_info *alloc_domheap_pages(
return pg;
}
+inline struct page_info *alloc_domheap_pages(
+ struct domain *d, unsigned int order, unsigned int flags)
+{
+ return __alloc_domheap_pages(d, smp_processor_id(), order, flags);
+}
void free_domheap_pages(struct page_info *pg, unsigned int order)
{
@@ -704,7 +768,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
{
/* Freeing anonymous domain-heap pages. */
for ( i = 0; i < (1 << order); i++ )
- pg[i].u.free.cpumask = CPU_MASK_NONE;
+ cpus_clear(pg[i].u.free.cpumask);
free_heap_pages(pfn_dom_zone_type(page_to_mfn(pg)), pg, order);
drop_dom_ref = 0;
}
@@ -714,13 +778,27 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
}
+unsigned long avail_heap_pages(int zone, int node)
+{
+ int i,j, num_nodes = num_online_nodes();
+ unsigned long free_pages = 0;
+
+ for (i=0; i<NR_ZONES; i++)
+ if ( (zone == -1) || (zone == i) )
+ for (j=0; j < num_nodes; j++)
+ if ( (node == -1) || (node == j) )
+ free_pages += avail[i][j];
+
+ return free_pages;
+}
+
unsigned long avail_domheap_pages(void)
{
unsigned long avail_nrm, avail_dma;
+
+ avail_nrm = avail_heap_pages(MEMZONE_DOM,-1);
- avail_nrm = avail[MEMZONE_DOM];
-
- avail_dma = avail[MEMZONE_DMADOM];
+ avail_dma = avail_heap_pages(MEMZONE_DMADOM,-1);
if ( avail_dma > lowmem_emergency_pool_pages )
avail_dma -= lowmem_emergency_pool_pages;
else
@@ -729,6 +807,10 @@ unsigned long avail_domheap_pages(void)
return avail_nrm + avail_dma;
}
+unsigned long avail_nodeheap_pages(int node)
+{
+ return avail_heap_pages(-1, node);
+}
static void pagealloc_keyhandler(unsigned char key)
{
@@ -736,9 +818,9 @@ static void pagealloc_keyhandler(unsigned char key)
printk(" Xen heap: %lukB free\n"
" DMA heap: %lukB free\n"
" Dom heap: %lukB free\n",
- avail[MEMZONE_XEN]<<(PAGE_SHIFT-10),
- avail[MEMZONE_DMADOM]<<(PAGE_SHIFT-10),
- avail[MEMZONE_DOM]<<(PAGE_SHIFT-10));
+ avail_heap_pages(MEMZONE_XEN, -1) << (PAGE_SHIFT-10),
+ avail_heap_pages(MEMZONE_DMADOM, -1) <<(PAGE_SHIFT-10),
+ avail_heap_pages(MEMZONE_DOM, -1) <<(PAGE_SHIFT-10));
}
@@ -806,6 +888,46 @@ unsigned long avail_scrub_pages(void)
return scrub_pages;
}
+static unsigned long count_bucket(struct list_head* l, int order)
+{
+ unsigned long total_pages = 0;
+ int pages = 1 << order;
+ struct page_info *pg;
+
+ list_for_each_entry(pg, l, list)
+ total_pages += pages;
+
+ return total_pages;
+}
+
+static void dump_heap(unsigned char key)
+{
+ s_time_t now = NOW();
+ int i,j,k;
+ unsigned long total;
+
+ printk("'%c' pressed -> dumping heap info (now-0x%X:%08X)\n", key,
+ (u32)(now>>32), (u32)now);
+
+ for (i=0; i<NR_ZONES; i++ )
+ for (j=0;j<MAX_NUMNODES;j++)
+ for (k=0;k<=MAX_ORDER;k++)
+ if ( !list_empty(&heap[i][j][k]) )
+ {
+ total = count_bucket(&heap[i][j][k], k);
+ printk("heap[%d][%d][%d]-> %lu pages\n",
+ i, j, k, total);
+ }
+}
+
+static __init int register_heap_trigger(void)
+{
+ register_keyhandler('H', dump_heap, "dump heap info");
+ return 0;
+}
+__initcall(register_heap_trigger);
+
+
static __init int page_scrub_init(void)
{
open_softirq(PAGE_SCRUB_SOFTIRQ, page_scrub_softirq);
diff --git a/xen/common/perfc.c b/xen/common/perfc.c
index 1903ef2f4e..471bd3cd2b 100644
--- a/xen/common/perfc.c
+++ b/xen/common/perfc.c
@@ -143,9 +143,6 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc,
unsigned int v = 0;
atomic_t *counters = (atomic_t *)&perfcounters;
- if ( guest_handle_is_null(desc) )
- return 0;
-
/* We only copy the name and array-size information once. */
if ( !perfc_init )
{
@@ -175,7 +172,11 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc,
perfc_vals = xmalloc_array(xen_sysctl_perfc_val_t, perfc_nbr_vals);
perfc_init = 1;
}
- if (perfc_vals == NULL)
+
+ if ( guest_handle_is_null(desc) )
+ return 0;
+
+ if ( perfc_vals == NULL )
return -ENOMEM;
/* Architecture may fill counters from hardware. */
@@ -207,9 +208,9 @@ static int perfc_copy_info(XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t) desc,
}
BUG_ON(v != perfc_nbr_vals);
- if (copy_to_guest(desc, (xen_sysctl_perfc_desc_t *)perfc_d, NR_PERFCTRS))
+ if ( copy_to_guest(desc, (xen_sysctl_perfc_desc_t *)perfc_d, NR_PERFCTRS) )
return -EFAULT;
- if (copy_to_guest(val, perfc_vals, perfc_nbr_vals))
+ if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) )
return -EFAULT;
return 0;
}
diff --git a/xen/common/sched_credit.c b/xen/common/sched_credit.c
index d183f2dafa..f83f03146b 100644
--- a/xen/common/sched_credit.c
+++ b/xen/common/sched_credit.c
@@ -36,16 +36,23 @@
/*
* Basic constants
*/
-#define CSCHED_TICK 10 /* milliseconds */
-#define CSCHED_TSLICE 30 /* milliseconds */
-#define CSCHED_ACCT_NTICKS 3
-#define CSCHED_ACCT_PERIOD (CSCHED_ACCT_NTICKS * CSCHED_TICK)
-#define CSCHED_DEFAULT_WEIGHT 256
+#define CSCHED_DEFAULT_WEIGHT 256
+#define CSCHED_TICKS_PER_TSLICE 3
+#define CSCHED_TICKS_PER_ACCT 3
+#define CSCHED_MSECS_PER_TICK 10
+#define CSCHED_MSECS_PER_TSLICE \
+ (CSCHED_MSECS_PER_TICK * CSCHED_TICKS_PER_TSLICE)
+#define CSCHED_CREDITS_PER_TICK 100
+#define CSCHED_CREDITS_PER_TSLICE \
+ (CSCHED_CREDITS_PER_TICK * CSCHED_TICKS_PER_TSLICE)
+#define CSCHED_CREDITS_PER_ACCT \
+ (CSCHED_CREDITS_PER_TICK * CSCHED_TICKS_PER_ACCT)
/*
* Priorities
*/
+#define CSCHED_PRI_TS_BOOST 0 /* time-share waking up */
#define CSCHED_PRI_TS_UNDER -1 /* time-share w/ credits */
#define CSCHED_PRI_TS_OVER -2 /* time-share w/o credits */
#define CSCHED_PRI_IDLE -64 /* idle */
@@ -75,40 +82,48 @@
printk("\t%-30s = %u\n", #_X, CSCHED_STAT(_X)); \
} while ( 0 );
+/*
+ * Try and keep often cranked stats on top so they'll fit on one
+ * cache line.
+ */
#define CSCHED_STATS_EXPAND_SCHED(_MACRO) \
- _MACRO(vcpu_init) \
+ _MACRO(schedule) \
+ _MACRO(acct_run) \
+ _MACRO(acct_no_work) \
+ _MACRO(acct_balance) \
+ _MACRO(acct_reorder) \
+ _MACRO(acct_min_credit) \
+ _MACRO(acct_vcpu_active) \
+ _MACRO(acct_vcpu_idle) \
_MACRO(vcpu_sleep) \
_MACRO(vcpu_wake_running) \
_MACRO(vcpu_wake_onrunq) \
_MACRO(vcpu_wake_runnable) \
_MACRO(vcpu_wake_not_runnable) \
- _MACRO(dom_destroy) \
- _MACRO(schedule) \
_MACRO(tickle_local_idler) \
_MACRO(tickle_local_over) \
_MACRO(tickle_local_under) \
_MACRO(tickle_local_other) \
- _MACRO(acct_run) \
- _MACRO(acct_no_work) \
- _MACRO(acct_balance) \
- _MACRO(acct_reorder) \
- _MACRO(acct_min_credit) \
- _MACRO(acct_vcpu_active) \
- _MACRO(acct_vcpu_idle) \
- _MACRO(acct_vcpu_credit_min)
-
-#define CSCHED_STATS_EXPAND_SMP_LOAD_BALANCE(_MACRO) \
- _MACRO(vcpu_migrate) \
- _MACRO(load_balance_idle) \
- _MACRO(load_balance_over) \
- _MACRO(load_balance_other) \
- _MACRO(steal_trylock_failed) \
- _MACRO(steal_peer_down) \
- _MACRO(steal_peer_idle) \
- _MACRO(steal_peer_running) \
- _MACRO(steal_peer_pinned) \
- _MACRO(tickle_idlers_none) \
- _MACRO(tickle_idlers_some)
+ _MACRO(tickle_idlers_none) \
+ _MACRO(tickle_idlers_some) \
+ _MACRO(vcpu_migrate) \
+ _MACRO(load_balance_idle) \
+ _MACRO(load_balance_over) \
+ _MACRO(load_balance_other) \
+ _MACRO(steal_trylock_failed) \
+ _MACRO(steal_peer_down) \
+ _MACRO(steal_peer_idle) \
+ _MACRO(steal_peer_running) \
+ _MACRO(steal_peer_pinned) \
+ _MACRO(steal_peer_migrating) \
+ _MACRO(steal_peer_best_idler) \
+ _MACRO(steal_loner_candidate) \
+ _MACRO(steal_loner_signal) \
+ _MACRO(cpu_pick) \
+ _MACRO(dom_init) \
+ _MACRO(dom_destroy) \
+ _MACRO(vcpu_init) \
+ _MACRO(vcpu_destroy)
#ifndef NDEBUG
#define CSCHED_STATS_EXPAND_CHECKS(_MACRO) \
@@ -117,10 +132,9 @@
#define CSCHED_STATS_EXPAND_CHECKS(_MACRO)
#endif
-#define CSCHED_STATS_EXPAND(_MACRO) \
- CSCHED_STATS_EXPAND_SCHED(_MACRO) \
- CSCHED_STATS_EXPAND_SMP_LOAD_BALANCE(_MACRO) \
- CSCHED_STATS_EXPAND_CHECKS(_MACRO)
+#define CSCHED_STATS_EXPAND(_MACRO) \
+ CSCHED_STATS_EXPAND_CHECKS(_MACRO) \
+ CSCHED_STATS_EXPAND_SCHED(_MACRO)
#define CSCHED_STATS_RESET() \
do \
@@ -170,11 +184,14 @@ struct csched_vcpu {
struct csched_dom *sdom;
struct vcpu *vcpu;
atomic_t credit;
- int credit_last;
- uint32_t credit_incr;
- uint32_t state_active;
- uint32_t state_idle;
int16_t pri;
+ struct {
+ int credit_last;
+ uint32_t credit_incr;
+ uint32_t state_active;
+ uint32_t state_idle;
+ uint32_t migrate;
+ } stats;
};
/*
@@ -290,6 +307,7 @@ __runq_tickle(unsigned int cpu, struct csched_vcpu *new)
{
CSCHED_STAT_CRANK(tickle_idlers_some);
cpus_or(mask, mask, csched_priv.idlers);
+ cpus_and(mask, mask, new->vcpu->cpu_affinity);
}
}
@@ -312,7 +330,7 @@ csched_pcpu_init(int cpu)
spin_lock_irqsave(&csched_priv.lock, flags);
/* Initialize/update system-wide config */
- csched_priv.credit += CSCHED_ACCT_PERIOD;
+ csched_priv.credit += CSCHED_CREDITS_PER_ACCT;
if ( csched_priv.ncpus <= cpu )
csched_priv.ncpus = cpu + 1;
if ( csched_priv.master >= csched_priv.ncpus )
@@ -357,8 +375,42 @@ __csched_vcpu_check(struct vcpu *vc)
#define CSCHED_VCPU_CHECK(_vc)
#endif
+/*
+ * Indicates which of two given idlers is most efficient to run
+ * an additional VCPU.
+ *
+ * Returns:
+ * 0: They are the same.
+ * negative: One is less efficient than Two.
+ * positive: One is more efficient than Two.
+ */
+static int
+csched_idler_compare(int one, int two)
+{
+ cpumask_t idlers;
+ cpumask_t one_idlers;
+ cpumask_t two_idlers;
+
+ idlers = csched_priv.idlers;
+ cpu_clear(one, idlers);
+ cpu_clear(two, idlers);
+
+ if ( cpu_isset(one, cpu_core_map[two]) )
+ {
+ cpus_and(one_idlers, idlers, cpu_sibling_map[one]);
+ cpus_and(two_idlers, idlers, cpu_sibling_map[two]);
+ }
+ else
+ {
+ cpus_and(one_idlers, idlers, cpu_core_map[one]);
+ cpus_and(two_idlers, idlers, cpu_core_map[two]);
+ }
+
+ return cpus_weight(one_idlers) - cpus_weight(two_idlers);
+}
+
static inline int
-__csched_vcpu_is_stealable(int local_cpu, struct vcpu *vc)
+__csched_queued_vcpu_is_stealable(int local_cpu, struct vcpu *vc)
{
/*
* Don't pick up work that's in the peer's scheduling tail. Also only pick
@@ -379,6 +431,32 @@ __csched_vcpu_is_stealable(int local_cpu, struct vcpu *vc)
return 1;
}
+static inline int
+__csched_running_vcpu_is_stealable(int local_cpu, struct vcpu *vc)
+{
+ BUG_ON( is_idle_vcpu(vc) );
+
+ if ( unlikely(!cpu_isset(local_cpu, vc->cpu_affinity)) )
+ {
+ CSCHED_STAT_CRANK(steal_peer_pinned);
+ return 0;
+ }
+
+ if ( test_bit(_VCPUF_migrating, &vc->vcpu_flags) )
+ {
+ CSCHED_STAT_CRANK(steal_peer_migrating);
+ return 0;
+ }
+
+ if ( csched_idler_compare(local_cpu, vc->processor) <= 0 )
+ {
+ CSCHED_STAT_CRANK(steal_peer_best_idler);
+ return 0;
+ }
+
+ return 1;
+}
+
static void
csched_vcpu_acct(struct csched_vcpu *svc, int credit_dec)
{
@@ -396,7 +474,7 @@ csched_vcpu_acct(struct csched_vcpu *svc, int credit_dec)
if ( list_empty(&svc->active_vcpu_elem) )
{
CSCHED_STAT_CRANK(acct_vcpu_active);
- svc->state_active++;
+ svc->stats.state_active++;
sdom->active_vcpu_count++;
list_add(&svc->active_vcpu_elem, &sdom->active_vcpu);
@@ -409,6 +487,14 @@ csched_vcpu_acct(struct csched_vcpu *svc, int credit_dec)
spin_unlock_irqrestore(&csched_priv.lock, flags);
}
+
+ /*
+ * If this VCPU's priority was boosted when it last awoke, reset it.
+ * If the VCPU is found here, then it's consuming a non-negligeable
+ * amount of CPU resources and should no longer be boosted.
+ */
+ if ( svc->pri == CSCHED_PRI_TS_BOOST )
+ svc->pri = CSCHED_PRI_TS_UNDER;
}
static inline void
@@ -419,7 +505,7 @@ __csched_vcpu_acct_idle_locked(struct csched_vcpu *svc)
BUG_ON( list_empty(&svc->active_vcpu_elem) );
CSCHED_STAT_CRANK(acct_vcpu_idle);
- svc->state_idle++;
+ svc->stats.state_idle++;
sdom->active_vcpu_count--;
list_del_init(&svc->active_vcpu_elem);
@@ -429,51 +515,20 @@ __csched_vcpu_acct_idle_locked(struct csched_vcpu *svc)
list_del_init(&sdom->active_sdom_elem);
csched_priv.weight -= sdom->weight;
}
-
- atomic_set(&svc->credit, 0);
}
static int
csched_vcpu_init(struct vcpu *vc)
{
struct domain * const dom = vc->domain;
- struct csched_dom *sdom;
+ struct csched_dom *sdom = CSCHED_DOM(dom);
struct csched_vcpu *svc;
- int16_t pri;
CSCHED_STAT_CRANK(vcpu_init);
- /* Allocate, if appropriate, per-domain info */
- if ( is_idle_vcpu(vc) )
- {
- sdom = NULL;
- pri = CSCHED_PRI_IDLE;
- }
- else if ( CSCHED_DOM(dom) )
- {
- sdom = CSCHED_DOM(dom);
- pri = CSCHED_PRI_TS_UNDER;
- }
- else
- {
- sdom = xmalloc(struct csched_dom);
- if ( !sdom )
- return -1;
-
- /* Initialize credit and weight */
- INIT_LIST_HEAD(&sdom->active_vcpu);
- sdom->active_vcpu_count = 0;
- INIT_LIST_HEAD(&sdom->active_sdom_elem);
- sdom->dom = dom;
- sdom->weight = CSCHED_DEFAULT_WEIGHT;
- sdom->cap = 0U;
- dom->sched_priv = sdom;
- pri = CSCHED_PRI_TS_UNDER;
- }
-
/* Allocate per-VCPU info */
svc = xmalloc(struct csched_vcpu);
- if ( !svc )
+ if ( svc == NULL )
return -1;
INIT_LIST_HEAD(&svc->runq_elem);
@@ -481,11 +536,8 @@ csched_vcpu_init(struct vcpu *vc)
svc->sdom = sdom;
svc->vcpu = vc;
atomic_set(&svc->credit, 0);
- svc->credit_last = 0;
- svc->credit_incr = 0U;
- svc->state_active = 0U;
- svc->state_idle = 0U;
- svc->pri = pri;
+ svc->pri = is_idle_domain(dom) ? CSCHED_PRI_IDLE : CSCHED_PRI_TS_UNDER;
+ memset(&svc->stats, 0, sizeof(svc->stats));
vc->sched_priv = svc;
CSCHED_VCPU_CHECK(vc);
@@ -507,12 +559,14 @@ csched_vcpu_init(struct vcpu *vc)
}
static void
-csched_vcpu_free(struct vcpu *vc)
+csched_vcpu_destroy(struct vcpu *vc)
{
struct csched_vcpu * const svc = CSCHED_VCPU(vc);
struct csched_dom * const sdom = svc->sdom;
unsigned long flags;
+ CSCHED_STAT_CRANK(vcpu_destroy);
+
BUG_ON( sdom == NULL );
BUG_ON( !list_empty(&svc->runq_elem) );
@@ -565,53 +619,31 @@ csched_vcpu_wake(struct vcpu *vc)
else
CSCHED_STAT_CRANK(vcpu_wake_not_runnable);
+ /*
+ * We temporarly boost the priority of awaking VCPUs!
+ *
+ * If this VCPU consumes a non negligeable amount of CPU, it
+ * will eventually find itself in the credit accounting code
+ * path where its priority will be reset to normal.
+ *
+ * If on the other hand the VCPU consumes little CPU and is
+ * blocking and awoken a lot (doing I/O for example), its
+ * priority will remain boosted, optimizing it's wake-to-run
+ * latencies.
+ *
+ * This allows wake-to-run latency sensitive VCPUs to preempt
+ * more CPU resource intensive VCPUs without impacting overall
+ * system fairness.
+ */
+ if ( svc->pri == CSCHED_PRI_TS_UNDER )
+ svc->pri = CSCHED_PRI_TS_BOOST;
+
/* Put the VCPU on the runq and tickle CPUs */
__runq_insert(cpu, svc);
__runq_tickle(cpu, svc);
}
static int
-csched_vcpu_set_affinity(struct vcpu *vc, cpumask_t *affinity)
-{
- unsigned long flags;
- int lcpu;
-
- if ( vc == current )
- {
- /* No locking needed but also can't move on the spot... */
- if ( !cpu_isset(vc->processor, *affinity) )
- return -EBUSY;
-
- vc->cpu_affinity = *affinity;
- }
- else
- {
- /* Pause, modify, and unpause. */
- vcpu_pause(vc);
-
- vc->cpu_affinity = *affinity;
- if ( !cpu_isset(vc->processor, vc->cpu_affinity) )
- {
- /*
- * We must grab the scheduler lock for the CPU currently owning
- * this VCPU before changing its ownership.
- */
- vcpu_schedule_lock_irqsave(vc, flags);
- lcpu = vc->processor;
-
- vc->processor = first_cpu(vc->cpu_affinity);
-
- spin_unlock_irqrestore(&per_cpu(schedule_data, lcpu).schedule_lock,
- flags);
- }
-
- vcpu_unpause(vc);
- }
-
- return 0;
-}
-
-static int
csched_dom_cntl(
struct domain *d,
struct xen_domctl_scheduler_op *op)
@@ -649,21 +681,100 @@ csched_dom_cntl(
return 0;
}
+static int
+csched_dom_init(struct domain *dom)
+{
+ struct csched_dom *sdom;
+
+ CSCHED_STAT_CRANK(dom_init);
+
+ if ( is_idle_domain(dom) )
+ return 0;
+
+ sdom = xmalloc(struct csched_dom);
+ if ( sdom == NULL )
+ return -ENOMEM;
+
+ /* Initialize credit and weight */
+ INIT_LIST_HEAD(&sdom->active_vcpu);
+ sdom->active_vcpu_count = 0;
+ INIT_LIST_HEAD(&sdom->active_sdom_elem);
+ sdom->dom = dom;
+ sdom->weight = CSCHED_DEFAULT_WEIGHT;
+ sdom->cap = 0U;
+ dom->sched_priv = sdom;
+
+ return 0;
+}
+
static void
csched_dom_destroy(struct domain *dom)
{
struct csched_dom * const sdom = CSCHED_DOM(dom);
- int i;
CSCHED_STAT_CRANK(dom_destroy);
- for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ xfree(sdom);
+}
+
+static int
+csched_cpu_pick(struct vcpu *vc)
+{
+ cpumask_t cpus;
+ int cpu, nxt;
+
+ CSCHED_STAT_CRANK(cpu_pick);
+
+ /*
+ * Pick from online CPUs in VCPU's affinity mask, giving a
+ * preference to its current processor if it's in there.
+ */
+ cpus_and(cpus, cpu_online_map, vc->cpu_affinity);
+ ASSERT( !cpus_empty(cpus) );
+ cpu = cpu_isset(vc->processor, cpus) ? vc->processor : first_cpu(cpus);
+
+ /*
+ * Try to find an idle processor within the above constraints.
+ */
+ cpus_and(cpus, cpus, csched_priv.idlers);
+ if ( !cpus_empty(cpus) )
{
- if ( dom->vcpu[i] )
- csched_vcpu_free(dom->vcpu[i]);
+ cpu = cpu_isset(cpu, cpus) ? cpu : first_cpu(cpus);
+ cpu_clear(cpu, cpus);
+
+ /*
+ * In multi-core and multi-threaded CPUs, not all idle execution
+ * vehicles are equal!
+ *
+ * We give preference to the idle execution vehicle with the most
+ * idling neighbours in its grouping. This distributes work across
+ * distinct cores first and guarantees we don't do something stupid
+ * like run two VCPUs on co-hyperthreads while there are idle cores
+ * or sockets.
+ */
+ while ( !cpus_empty(cpus) )
+ {
+ nxt = first_cpu(cpus);
+
+ if ( csched_idler_compare(cpu, nxt) < 0 )
+ {
+ cpu = nxt;
+ cpu_clear(nxt, cpus);
+ }
+ else if ( cpu_isset(cpu, cpu_core_map[nxt]) )
+ {
+ cpus_andnot(cpus, cpus, cpu_sibling_map[nxt]);
+ }
+ else
+ {
+ cpus_andnot(cpus, cpus, cpu_core_map[nxt]);
+ }
+
+ ASSERT( !cpu_isset(nxt, cpus) );
+ }
}
- xfree(sdom);
+ return cpu;
}
/*
@@ -699,7 +810,7 @@ csched_runq_sort(unsigned int cpu)
next = elem->next;
svc_elem = __runq_elem(elem);
- if ( svc_elem->pri == CSCHED_PRI_TS_UNDER )
+ if ( svc_elem->pri >= CSCHED_PRI_TS_UNDER )
{
/* does elem need to move up the runq? */
if ( elem->prev != last_under )
@@ -729,6 +840,7 @@ csched_acct(void)
uint32_t weight_left;
uint32_t credit_fair;
uint32_t credit_peak;
+ uint32_t credit_cap;
int credit_balance;
int credit_xtra;
int credit;
@@ -759,6 +871,7 @@ csched_acct(void)
weight_left = weight_total;
credit_balance = 0;
credit_xtra = 0;
+ credit_cap = 0U;
list_for_each_safe( iter_sdom, next_sdom, &csched_priv.active_sdom )
{
@@ -779,18 +892,22 @@ csched_acct(void)
* for one full accounting period. We allow a domain to earn more
* only when the system-wide credit balance is negative.
*/
- credit_peak = sdom->active_vcpu_count * CSCHED_ACCT_PERIOD;
+ credit_peak = sdom->active_vcpu_count * CSCHED_CREDITS_PER_ACCT;
if ( csched_priv.credit_balance < 0 )
{
credit_peak += ( ( -csched_priv.credit_balance * sdom->weight) +
(weight_total - 1)
) / weight_total;
}
+
if ( sdom->cap != 0U )
{
- uint32_t credit_cap = ((sdom->cap * CSCHED_ACCT_PERIOD) + 99) / 100;
+ credit_cap = ((sdom->cap * CSCHED_CREDITS_PER_ACCT) + 99) / 100;
if ( credit_cap < credit_peak )
credit_peak = credit_cap;
+
+ credit_cap = ( credit_cap + ( sdom->active_vcpu_count - 1 )
+ ) / sdom->active_vcpu_count;
}
credit_fair = ( ( credit_total * sdom->weight) + (weight_total - 1)
@@ -846,15 +963,15 @@ csched_acct(void)
*/
if ( credit < 0 )
{
- if ( sdom->cap == 0U )
- svc->pri = CSCHED_PRI_TS_OVER;
- else
+ if ( sdom->cap != 0U && credit < -credit_cap )
svc->pri = CSCHED_PRI_TS_PARKED;
+ else
+ svc->pri = CSCHED_PRI_TS_OVER;
- if ( credit < -CSCHED_TSLICE )
+ if ( credit < -CSCHED_CREDITS_PER_TSLICE )
{
CSCHED_STAT_CRANK(acct_min_credit);
- credit = -CSCHED_TSLICE;
+ credit = -CSCHED_CREDITS_PER_TSLICE;
atomic_set(&svc->credit, credit);
}
}
@@ -862,12 +979,16 @@ csched_acct(void)
{
svc->pri = CSCHED_PRI_TS_UNDER;
- if ( credit > CSCHED_TSLICE )
+ if ( credit > CSCHED_CREDITS_PER_TSLICE )
+ {
__csched_vcpu_acct_idle_locked(svc);
+ credit = 0;
+ atomic_set(&svc->credit, credit);
+ }
}
- svc->credit_last = credit;
- svc->credit_incr = credit_fair;
+ svc->stats.credit_last = credit;
+ svc->stats.credit_incr = credit_fair;
credit_balance += credit;
}
}
@@ -893,7 +1014,7 @@ csched_tick(unsigned int cpu)
*/
if ( likely(sdom != NULL) )
{
- csched_vcpu_acct(svc, CSCHED_TICK);
+ csched_vcpu_acct(svc, CSCHED_CREDITS_PER_TICK);
}
/*
@@ -903,7 +1024,7 @@ csched_tick(unsigned int cpu)
* we could distribute or at the very least cycle the duty.
*/
if ( (csched_priv.master == cpu) &&
- (per_cpu(schedule_data, cpu).tick % CSCHED_ACCT_NTICKS) == 0 )
+ (per_cpu(schedule_data, cpu).tick % CSCHED_TICKS_PER_ACCT) == 0 )
{
csched_acct();
}
@@ -943,7 +1064,7 @@ csched_runq_steal(struct csched_pcpu *spc, int cpu, int pri)
vc = speer->vcpu;
BUG_ON( is_idle_vcpu(vc) );
- if ( __csched_vcpu_is_stealable(cpu, vc) )
+ if ( __csched_queued_vcpu_is_stealable(cpu, vc) )
{
/* We got a candidate. Grab it! */
__runq_remove(speer);
@@ -959,8 +1080,11 @@ csched_runq_steal(struct csched_pcpu *spc, int cpu, int pri)
static struct csched_vcpu *
csched_load_balance(int cpu, struct csched_vcpu *snext)
{
- struct csched_pcpu *spc;
struct csched_vcpu *speer;
+ struct csched_pcpu *spc;
+ struct vcpu *peer_vcpu;
+ cpumask_t workers;
+ cpumask_t loners;
int peer_cpu;
if ( snext->pri == CSCHED_PRI_IDLE )
@@ -970,15 +1094,24 @@ csched_load_balance(int cpu, struct csched_vcpu *snext)
else
CSCHED_STAT_CRANK(load_balance_other);
+ /*
+ * Peek at non-idling CPUs in the system
+ */
+ cpus_clear(loners);
+ cpus_andnot(workers, cpu_online_map, csched_priv.idlers);
+ cpu_clear(cpu, workers);
+
peer_cpu = cpu;
BUG_ON( peer_cpu != snext->vcpu->processor );
- while ( 1 )
+ while ( !cpus_empty(workers) )
{
- /* For each PCPU in the system starting with our neighbour... */
- peer_cpu = (peer_cpu + 1) % csched_priv.ncpus;
- if ( peer_cpu == cpu )
- break;
+ /* For each CPU of interest, starting with our neighbour... */
+ peer_cpu = next_cpu(peer_cpu, workers);
+ if ( peer_cpu == NR_CPUS )
+ peer_cpu = first_cpu(workers);
+
+ cpu_clear(peer_cpu, workers);
/*
* Get ahold of the scheduler lock for this peer CPU.
@@ -987,37 +1120,92 @@ csched_load_balance(int cpu, struct csched_vcpu *snext)
* cause a deadlock if the peer CPU is also load balancing and trying
* to lock this CPU.
*/
- if ( spin_trylock(&per_cpu(schedule_data, peer_cpu).schedule_lock) )
+ if ( !spin_trylock(&per_cpu(schedule_data, peer_cpu).schedule_lock) )
{
+ CSCHED_STAT_CRANK(steal_trylock_failed);
+ continue;
+ }
- spc = CSCHED_PCPU(peer_cpu);
- if ( unlikely(spc == NULL) )
- {
- CSCHED_STAT_CRANK(steal_peer_down);
- speer = NULL;
- }
- else
+ peer_vcpu = per_cpu(schedule_data, peer_cpu).curr;
+ spc = CSCHED_PCPU(peer_cpu);
+
+ if ( unlikely(spc == NULL) )
+ {
+ CSCHED_STAT_CRANK(steal_peer_down);
+ }
+ else if ( unlikely(is_idle_vcpu(peer_vcpu)) )
+ {
+ /*
+ * Don't steal from an idle CPU's runq because it's about to
+ * pick up work from it itself.
+ */
+ CSCHED_STAT_CRANK(steal_peer_idle);
+ }
+ else if ( is_idle_vcpu(__runq_elem(spc->runq.next)->vcpu) )
+ {
+ if ( snext->pri == CSCHED_PRI_IDLE &&
+ __csched_running_vcpu_is_stealable(cpu, peer_vcpu) )
{
- speer = csched_runq_steal(spc, cpu, snext->pri);
+ CSCHED_STAT_CRANK(steal_loner_candidate);
+ cpu_set(peer_cpu, loners);
}
-
- spin_unlock(&per_cpu(schedule_data, peer_cpu).schedule_lock);
-
- /* Got one! */
- if ( speer )
+ }
+ else
+ {
+ /* Try to steal work from a remote CPU's runq. */
+ speer = csched_runq_steal(spc, cpu, snext->pri);
+ if ( speer != NULL )
{
+ spin_unlock(&per_cpu(schedule_data, peer_cpu).schedule_lock);
CSCHED_STAT_CRANK(vcpu_migrate);
+ speer->stats.migrate++;
return speer;
}
}
- else
+
+ spin_unlock(&per_cpu(schedule_data, peer_cpu).schedule_lock);
+ }
+
+ /*
+ * If we failed to find any remotely queued VCPUs to move here,
+ * see if it would be more efficient to move any of the running
+ * remote VCPUs over here.
+ */
+ while ( !cpus_empty(loners) )
+ {
+ /* For each CPU of interest, starting with our neighbour... */
+ peer_cpu = next_cpu(peer_cpu, loners);
+ if ( peer_cpu == NR_CPUS )
+ peer_cpu = first_cpu(loners);
+
+ cpu_clear(peer_cpu, loners);
+
+ if ( !spin_trylock(&per_cpu(schedule_data, peer_cpu).schedule_lock) )
{
CSCHED_STAT_CRANK(steal_trylock_failed);
+ continue;
}
- }
+ peer_vcpu = per_cpu(schedule_data, peer_cpu).curr;
+ spc = CSCHED_PCPU(peer_cpu);
- /* Failed to find more important work */
+ /* Signal the first candidate only. */
+ if ( !is_idle_vcpu(peer_vcpu) &&
+ is_idle_vcpu(__runq_elem(spc->runq.next)->vcpu) &&
+ __csched_running_vcpu_is_stealable(cpu, peer_vcpu) )
+ {
+ set_bit(_VCPUF_migrating, &peer_vcpu->vcpu_flags);
+ spin_unlock(&per_cpu(schedule_data, peer_cpu).schedule_lock);
+
+ CSCHED_STAT_CRANK(steal_loner_signal);
+ cpu_raise_softirq(peer_cpu, SCHEDULE_SOFTIRQ);
+ break;
+ }
+
+ spin_unlock(&per_cpu(schedule_data, peer_cpu).schedule_lock);
+ }
+
+ /* Failed to find more important work elsewhere... */
__runq_remove(snext);
return snext;
}
@@ -1078,7 +1266,7 @@ csched_schedule(s_time_t now)
/*
* Return task to run next...
*/
- ret.time = MILLISECS(CSCHED_TSLICE);
+ ret.time = MILLISECS(CSCHED_MSECS_PER_TSLICE);
ret.task = snext->vcpu;
CSCHED_VCPU_CHECK(ret.task);
@@ -1099,12 +1287,13 @@ csched_dump_vcpu(struct csched_vcpu *svc)
if ( sdom )
{
- printk(" credit=%i (%d+%u) {a=%u i=%u w=%u}",
+ printk(" credit=%i (%d+%u) {a/i=%u/%u m=%u w=%u}",
atomic_read(&svc->credit),
- svc->credit_last,
- svc->credit_incr,
- svc->state_active,
- svc->state_idle,
+ svc->stats.credit_last,
+ svc->stats.credit_incr,
+ svc->stats.state_active,
+ svc->stats.state_idle,
+ svc->stats.migrate,
sdom->weight);
}
@@ -1122,9 +1311,11 @@ csched_dump_pcpu(int cpu)
spc = CSCHED_PCPU(cpu);
runq = &spc->runq;
- printk(" tick=%lu, sort=%d\n",
+ printk(" tick=%lu, sort=%d, sibling=0x%lx, core=0x%lx\n",
per_cpu(schedule_data, cpu).tick,
- spc->runq_sort_last);
+ spc->runq_sort_last,
+ cpu_sibling_map[cpu].bits[0],
+ cpu_core_map[cpu].bits[0]);
/* current VCPU */
svc = CSCHED_VCPU(per_cpu(schedule_data, cpu).curr);
@@ -1159,20 +1350,22 @@ csched_dump(void)
"\tcredit balance = %d\n"
"\tweight = %u\n"
"\trunq_sort = %u\n"
- "\ttick = %dms\n"
- "\ttslice = %dms\n"
- "\taccounting period = %dms\n"
- "\tdefault-weight = %d\n",
+ "\tdefault-weight = %d\n"
+ "\tmsecs per tick = %dms\n"
+ "\tcredits per tick = %d\n"
+ "\tticks per tslice = %d\n"
+ "\tticks per acct = %d\n",
csched_priv.ncpus,
csched_priv.master,
csched_priv.credit,
csched_priv.credit_balance,
csched_priv.weight,
csched_priv.runq_sort,
- CSCHED_TICK,
- CSCHED_TSLICE,
- CSCHED_ACCT_PERIOD,
- CSCHED_DEFAULT_WEIGHT);
+ CSCHED_DEFAULT_WEIGHT,
+ CSCHED_MSECS_PER_TICK,
+ CSCHED_CREDITS_PER_TICK,
+ CSCHED_TICKS_PER_TSLICE,
+ CSCHED_TICKS_PER_ACCT);
printk("idlers: 0x%lx\n", csched_priv.idlers.bits[0]);
@@ -1217,16 +1410,18 @@ struct scheduler sched_credit_def = {
.opt_name = "credit",
.sched_id = XEN_SCHEDULER_CREDIT,
- .init_vcpu = csched_vcpu_init,
+ .init_domain = csched_dom_init,
.destroy_domain = csched_dom_destroy,
+ .init_vcpu = csched_vcpu_init,
+ .destroy_vcpu = csched_vcpu_destroy,
+
.sleep = csched_vcpu_sleep,
.wake = csched_vcpu_wake,
- .set_affinity = csched_vcpu_set_affinity,
-
.adjust = csched_dom_cntl,
+ .pick_cpu = csched_cpu_pick,
.tick = csched_tick,
.do_schedule = csched_schedule,
diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c
index 8559e3bdf5..5381fcb3ca 100644
--- a/xen/common/sched_sedf.c
+++ b/xen/common/sched_sedf.c
@@ -333,14 +333,6 @@ static int sedf_init_vcpu(struct vcpu *v)
{
struct sedf_vcpu_info *inf;
- if ( v->domain->sched_priv == NULL )
- {
- v->domain->sched_priv = xmalloc(struct sedf_dom_info);
- if ( v->domain->sched_priv == NULL )
- return -1;
- memset(v->domain->sched_priv, 0, sizeof(struct sedf_dom_info));
- }
-
if ( (v->sched_priv = xmalloc(struct sedf_vcpu_info)) == NULL )
return -1;
memset(v->sched_priv, 0, sizeof(struct sedf_vcpu_info));
@@ -398,15 +390,33 @@ static int sedf_init_vcpu(struct vcpu *v)
return 0;
}
-static void sedf_destroy_domain(struct domain *d)
+static void sedf_destroy_vcpu(struct vcpu *v)
+{
+ xfree(v->sched_priv);
+}
+
+static int sedf_init_domain(struct domain *d)
{
- int i;
+ d->sched_priv = xmalloc(struct sedf_dom_info);
+ if ( d->sched_priv == NULL )
+ return -ENOMEM;
+ memset(d->sched_priv, 0, sizeof(struct sedf_dom_info));
+
+ return 0;
+}
+
+static void sedf_destroy_domain(struct domain *d)
+{
xfree(d->sched_priv);
-
- for ( i = 0; i < MAX_VIRT_CPUS; i++ )
- if ( d->vcpu[i] )
- xfree(d->vcpu[i]->sched_priv);
+}
+
+static int sedf_pick_cpu(struct vcpu *v)
+{
+ cpumask_t online_affinity;
+
+ cpus_and(online_affinity, v->cpu_affinity, cpu_online_map);
+ return first_cpu(online_affinity);
}
/*
@@ -1175,20 +1185,6 @@ void sedf_wake(struct vcpu *d)
}
-static int sedf_set_affinity(struct vcpu *v, cpumask_t *affinity)
-{
- if ( v == current )
- return cpu_isset(v->processor, *affinity) ? 0 : -EBUSY;
-
- vcpu_pause(v);
- v->cpu_affinity = *affinity;
- v->processor = first_cpu(v->cpu_affinity);
- vcpu_unpause(v);
-
- return 0;
-}
-
-
/* Print a lot of useful information about a domains in the system */
static void sedf_dump_domain(struct vcpu *d)
{
@@ -1204,10 +1200,10 @@ static void sedf_dump_domain(struct vcpu *d)
#ifdef SEDF_STATS
if ( EDOM_INFO(d)->block_time_tot != 0 )
- printf(" pen=%"PRIu64"%%", (EDOM_INFO(d)->penalty_time_tot * 100) /
+ printk(" pen=%"PRIu64"%%", (EDOM_INFO(d)->penalty_time_tot * 100) /
EDOM_INFO(d)->block_time_tot);
if ( EDOM_INFO(d)->block_tot != 0 )
- printf("\n blks=%u sh=%u (%u%%) (shc=%u (%u%%) shex=%i "\
+ printk("\n blks=%u sh=%u (%u%%) (shc=%u (%u%%) shex=%i "\
"shexsl=%i) l=%u (%u%%) avg: b=%"PRIu64" p=%"PRIu64"",
EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_block_tot,
(EDOM_INFO(d)->short_block_tot * 100)
@@ -1220,7 +1216,7 @@ static void sedf_dump_domain(struct vcpu *d)
(EDOM_INFO(d)->block_time_tot) / EDOM_INFO(d)->block_tot,
(EDOM_INFO(d)->penalty_time_tot) / EDOM_INFO(d)->block_tot);
#endif
- printf("\n");
+ printk("\n");
}
@@ -1441,15 +1437,18 @@ struct scheduler sched_sedf_def = {
.opt_name = "sedf",
.sched_id = XEN_SCHEDULER_SEDF,
- .init_vcpu = sedf_init_vcpu,
+ .init_domain = sedf_init_domain,
.destroy_domain = sedf_destroy_domain,
+ .init_vcpu = sedf_init_vcpu,
+ .destroy_vcpu = sedf_destroy_vcpu,
+
.do_schedule = sedf_do_schedule,
+ .pick_cpu = sedf_pick_cpu,
.dump_cpu_state = sedf_dump_cpu_state,
.sleep = sedf_sleep,
.wake = sedf_wake,
.adjust = sedf_adjust,
- .set_affinity = sedf_set_affinity
};
/*
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index a31bdb369c..10f63b85bf 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -29,6 +29,7 @@
#include <xen/mm.h>
#include <xen/errno.h>
#include <xen/guest_access.h>
+#include <xen/multicall.h>
#include <public/sched.h>
extern void arch_getdomaininfo_ctxt(struct vcpu *,
@@ -37,6 +38,10 @@ extern void arch_getdomaininfo_ctxt(struct vcpu *,
static char opt_sched[10] = "credit";
string_param("sched", opt_sched);
+/* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */
+static unsigned int opt_dom0_vcpus_pin;
+boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin);
+
#define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */
/* Various timer handlers. */
@@ -56,8 +61,6 @@ static struct scheduler *schedulers[] = {
NULL
};
-static void __enter_scheduler(void);
-
static struct scheduler ops;
#define SCHED_OP(fn, ...) \
@@ -97,13 +100,26 @@ void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate)
}
}
-int sched_init_vcpu(struct vcpu *v)
+int sched_init_vcpu(struct vcpu *v, unsigned int processor)
{
+ struct domain *d = v->domain;
+
+ /*
+ * Initialize processor and affinity settings. The idler, and potentially
+ * domain-0 VCPUs, are pinned onto their respective physical CPUs.
+ */
+ v->processor = processor;
+ if ( is_idle_domain(d) || ((d->domain_id == 0) && opt_dom0_vcpus_pin) )
+ v->cpu_affinity = cpumask_of_cpu(processor);
+ else
+ cpus_setall(v->cpu_affinity);
+
/* Initialise the per-domain timers. */
init_timer(&v->timer, vcpu_timer_fn, v, v->processor);
init_timer(&v->poll_timer, poll_timer_fn, v, v->processor);
- if ( is_idle_vcpu(v) )
+ /* Idle VCPUs are scheduled immediately. */
+ if ( is_idle_domain(d) )
{
per_cpu(schedule_data, v->processor).curr = v;
per_cpu(schedule_data, v->processor).idle = v;
@@ -115,17 +131,20 @@ int sched_init_vcpu(struct vcpu *v)
return SCHED_OP(init_vcpu, v);
}
-void sched_destroy_domain(struct domain *d)
+void sched_destroy_vcpu(struct vcpu *v)
{
- struct vcpu *v;
+ kill_timer(&v->timer);
+ kill_timer(&v->poll_timer);
+ SCHED_OP(destroy_vcpu, v);
+}
- for_each_vcpu ( d, v )
- {
- kill_timer(&v->timer);
- kill_timer(&v->poll_timer);
- TRACE_2D(TRC_SCHED_DOM_REM, v->domain->domain_id, v->vcpu_id);
- }
+int sched_init_domain(struct domain *d)
+{
+ return SCHED_OP(init_domain, d);
+}
+void sched_destroy_domain(struct domain *d)
+{
SCHED_OP(destroy_domain, d);
}
@@ -181,15 +200,57 @@ void vcpu_wake(struct vcpu *v)
TRACE_2D(TRC_SCHED_WAKE, v->domain->domain_id, v->vcpu_id);
}
+static void vcpu_migrate(struct vcpu *v)
+{
+ unsigned long flags;
+ int old_cpu;
+
+ vcpu_schedule_lock_irqsave(v, flags);
+
+ if ( test_bit(_VCPUF_running, &v->vcpu_flags) ||
+ !test_and_clear_bit(_VCPUF_migrating, &v->vcpu_flags) )
+ {
+ vcpu_schedule_unlock_irqrestore(v, flags);
+ return;
+ }
+
+ /* Switch to new CPU, then unlock old CPU. */
+ old_cpu = v->processor;
+ v->processor = SCHED_OP(pick_cpu, v);
+ spin_unlock_irqrestore(
+ &per_cpu(schedule_data, old_cpu).schedule_lock, flags);
+
+ /* Wake on new CPU. */
+ vcpu_wake(v);
+}
+
int vcpu_set_affinity(struct vcpu *v, cpumask_t *affinity)
{
cpumask_t online_affinity;
+ unsigned long flags;
+
+ if ( (v->domain->domain_id == 0) && opt_dom0_vcpus_pin )
+ return -EINVAL;
cpus_and(online_affinity, *affinity, cpu_online_map);
if ( cpus_empty(online_affinity) )
return -EINVAL;
- return SCHED_OP(set_affinity, v, affinity);
+ vcpu_schedule_lock_irqsave(v, flags);
+
+ v->cpu_affinity = *affinity;
+ if ( !cpu_isset(v->processor, v->cpu_affinity) )
+ set_bit(_VCPUF_migrating, &v->vcpu_flags);
+
+ vcpu_schedule_unlock_irqrestore(v, flags);
+
+ if ( test_bit(_VCPUF_migrating, &v->vcpu_flags) )
+ {
+ vcpu_sleep_nosync(v);
+ vcpu_migrate(v);
+ }
+
+ return 0;
}
/* Block the currently-executing domain until a pertinent event occurs. */
@@ -208,7 +269,7 @@ static long do_block(void)
else
{
TRACE_2D(TRC_SCHED_BLOCK, v->domain->domain_id, v->vcpu_id);
- __enter_scheduler();
+ raise_softirq(SCHEDULE_SOFTIRQ);
}
return 0;
@@ -253,9 +314,9 @@ static long do_poll(struct sched_poll *sched_poll)
set_timer(&v->poll_timer, sched_poll->timeout);
TRACE_2D(TRC_SCHED_BLOCK, v->domain->domain_id, v->vcpu_id);
- __enter_scheduler();
+ raise_softirq(SCHEDULE_SOFTIRQ);
- stop_timer(&v->poll_timer);
+ return 0;
out:
clear_bit(_VCPUF_polling, &v->vcpu_flags);
@@ -267,7 +328,7 @@ static long do_poll(struct sched_poll *sched_poll)
static long do_yield(void)
{
TRACE_2D(TRC_SCHED_YIELD, current->domain->domain_id, current->vcpu_id);
- __enter_scheduler();
+ raise_softirq(SCHEDULE_SOFTIRQ);
return 0;
}
@@ -407,7 +468,7 @@ long do_set_timer_op(s_time_t timeout)
* timeout in this case can burn a lot of CPU. We therefore go for a
* reasonable middleground of triggering a timer event in 100ms.
*/
- DPRINTK("Warning: huge timeout set by domain %d (vcpu %d):"
+ gdprintk(XENLOG_INFO, "Warning: huge timeout set by domain %d (vcpu %d):"
" %"PRIx64"\n",
v->domain->domain_id, v->vcpu_id, (uint64_t)timeout);
set_timer(&v->timer, NOW() + MILLISECS(100));
@@ -478,7 +539,7 @@ long sched_adjust(struct domain *d, struct xen_domctl_scheduler_op *op)
* - deschedule the current domain (scheduler independent).
* - pick a new domain (scheduler dependent).
*/
-static void __enter_scheduler(void)
+static void schedule(void)
{
struct vcpu *prev = current, *next = NULL;
s_time_t now = NOW();
@@ -487,6 +548,7 @@ static void __enter_scheduler(void)
s32 r_time; /* time for new dom to run */
ASSERT(!in_irq());
+ ASSERT(this_cpu(mc_state).flags == 0);
perfc_incrc(sched_run);
@@ -555,6 +617,13 @@ static void __enter_scheduler(void)
context_switch(prev, next);
}
+void context_saved(struct vcpu *prev)
+{
+ clear_bit(_VCPUF_running, &prev->vcpu_flags);
+
+ if ( unlikely(test_bit(_VCPUF_migrating, &prev->vcpu_flags)) )
+ vcpu_migrate(prev);
+}
/****************************************************************************
* Timers: the scheduler utilises a number of timers
@@ -610,7 +679,7 @@ void __init scheduler_init(void)
{
int i;
- open_softirq(SCHEDULE_SOFTIRQ, __enter_scheduler);
+ open_softirq(SCHEDULE_SOFTIRQ, schedule);
for_each_cpu ( i )
{
diff --git a/xen/common/shutdown.c b/xen/common/shutdown.c
index 1baea16205..a994e14bfc 100644
--- a/xen/common/shutdown.c
+++ b/xen/common/shutdown.c
@@ -30,8 +30,6 @@ static void maybe_reboot(void)
void dom0_shutdown(u8 reason)
{
- debugger_trap_immediate();
-
switch ( reason )
{
case SHUTDOWN_poweroff:
@@ -43,6 +41,7 @@ void dom0_shutdown(u8 reason)
case SHUTDOWN_crash:
{
+ debugger_trap_immediate();
printk("Domain 0 crashed: ");
maybe_reboot();
break; /* not reached */
diff --git a/xen/common/symbols-dummy.c b/xen/common/symbols-dummy.c
new file mode 100644
index 0000000000..562264f4e7
--- /dev/null
+++ b/xen/common/symbols-dummy.c
@@ -0,0 +1,16 @@
+/*
+ * symbols-dummy.c: dummy symbol-table definitions for the inital partial
+ * link of the hypervisor image.
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+
+unsigned long symbols_addresses[1];
+unsigned long symbols_num_syms;
+u8 symbols_names[1];
+
+u8 symbols_token_table[1];
+u16 symbols_token_index[1];
+
+unsigned long symbols_markers[1];
diff --git a/xen/common/symbols.c b/xen/common/symbols.c
index 84e04d973c..6bc3956a13 100644
--- a/xen/common/symbols.c
+++ b/xen/common/symbols.c
@@ -16,15 +16,14 @@
#include <xen/lib.h>
#include <xen/string.h>
-/* These will be re-linked against their real values during the second link stage */
-extern unsigned long symbols_addresses[] __attribute__((weak));
-extern unsigned long symbols_num_syms __attribute__((weak,section("data")));
-extern u8 symbols_names[] __attribute__((weak));
+extern unsigned long symbols_addresses[];
+extern unsigned long symbols_num_syms;
+extern u8 symbols_names[];
-extern u8 symbols_token_table[] __attribute__((weak));
-extern u16 symbols_token_index[] __attribute__((weak));
+extern u8 symbols_token_table[];
+extern u16 symbols_token_index[];
-extern unsigned long symbols_markers[] __attribute__((weak));
+extern unsigned long symbols_markers[];
/* expand a compressed symbol data into the resulting uncompressed string,
given the offset to where the symbol is in the compressed stream */
diff --git a/xen/common/time.c b/xen/common/time.c
new file mode 100644
index 0000000000..65929d1c1f
--- /dev/null
+++ b/xen/common/time.c
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * time.c
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <xen/config.h>
+#include <xen/time.h>
+
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+#define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+/* How many days are in each month. */
+const unsigned short int __mon_lengths[2][12] = {
+ /* Normal years. */
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ /* Leap years. */
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+#define SECS_PER_HOUR (60 * 60)
+#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+
+struct tm gmtime(unsigned long t)
+{
+ struct tm tbuf;
+ long days, rem;
+ int y;
+ unsigned short int *ip;
+
+ days = t / SECS_PER_DAY;
+ rem = t % SECS_PER_DAY;
+
+ tbuf.tm_hour = rem / SECS_PER_HOUR;
+ rem %= SECS_PER_HOUR;
+ tbuf.tm_min = rem / 60;
+ tbuf.tm_sec = rem % 60;
+ /* January 1, 1970 was a Thursday. */
+ tbuf.tm_wday = (4 + days) % 7;
+ if ( tbuf.tm_wday < 0 )
+ tbuf.tm_wday += 7;
+ y = 1970;
+ while ( days >= (rem = __isleap(y) ? 366 : 365) )
+ {
+ ++y;
+ days -= rem;
+ }
+ while ( days < 0 )
+ {
+ --y;
+ days += __isleap(y) ? 366 : 365;
+ }
+ tbuf.tm_year = y - 1900;
+ tbuf.tm_yday = days;
+ ip = (unsigned short int *)__mon_lengths[__isleap(y)];
+ for ( y = 0; days >= ip[y]; ++y )
+ days -= ip[y];
+ tbuf.tm_mon = y;
+ tbuf.tm_mday = days + 1;
+ tbuf.tm_isdst = -1;
+
+ return tbuf;
+}
diff --git a/xen/common/trace.c b/xen/common/trace.c
index fde88764eb..a5cec8e69a 100644
--- a/xen/common/trace.c
+++ b/xen/common/trace.c
@@ -131,7 +131,7 @@ static int tb_set_size(int size)
*/
if ( (opt_tbuf_size != 0) || (size <= 0) )
{
- DPRINTK("tb_set_size from %d to %d not implemented\n",
+ gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n",
opt_tbuf_size, size);
return -EINVAL;
}
@@ -187,7 +187,7 @@ int tb_control(xen_sysctl_tbuf_op_t *tbc)
tbc->size = opt_tbuf_size * PAGE_SIZE;
break;
case XEN_SYSCTL_TBUFOP_set_cpu_mask:
- cpumask_to_xenctl_cpumap(&tbc->cpu_mask, &tb_cpu_mask);
+ xenctl_cpumap_to_cpumask(&tb_cpu_mask, &tbc->cpu_mask);
break;
case XEN_SYSCTL_TBUFOP_set_evt_mask:
tb_event_mask = tbc->evt_mask;
diff --git a/xen/common/vsprintf.c b/xen/common/vsprintf.c
index da82029195..7de43593fe 100644
--- a/xen/common/vsprintf.c
+++ b/xen/common/vsprintf.c
@@ -16,7 +16,7 @@
* - scnprintf and vscnprintf
*/
-#include <stdarg.h>
+#include <xen/stdarg.h>
#include <xen/ctype.h>
#include <xen/lib.h>
#include <asm/div64.h>
diff --git a/xen/common/xenoprof.c b/xen/common/xenoprof.c
new file mode 100644
index 0000000000..39eee3d9a7
--- /dev/null
+++ b/xen/common/xenoprof.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright (C) 2005 Hewlett-Packard Co.
+ * written by Aravind Menon & Jose Renato Santos
+ * (email: xenoprof@groups.hp.com)
+ *
+ * arch generic xenoprof and IA64 support.
+ * dynamic map/unmap xenoprof buffer support.
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ */
+
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <public/xenoprof.h>
+#include <asm/shadow.h>
+
+/* Limit amount of pages used for shared buffer (per domain) */
+#define MAX_OPROF_SHARED_PAGES 32
+
+/* Lock protecting the following global state */
+static DEFINE_SPINLOCK(xenoprof_lock);
+
+struct domain *active_domains[MAX_OPROF_DOMAINS];
+int active_ready[MAX_OPROF_DOMAINS];
+unsigned int adomains;
+
+struct domain *passive_domains[MAX_OPROF_DOMAINS];
+unsigned int pdomains;
+
+unsigned int activated;
+struct domain *xenoprof_primary_profiler;
+int xenoprof_state = XENOPROF_IDLE;
+
+u64 total_samples;
+u64 invalid_buffer_samples;
+u64 corrupted_buffer_samples;
+u64 lost_samples;
+u64 active_samples;
+u64 passive_samples;
+u64 idle_samples;
+u64 others_samples;
+
+int is_active(struct domain *d)
+{
+ struct xenoprof *x = d->xenoprof;
+ return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE));
+}
+
+int is_passive(struct domain *d)
+{
+ struct xenoprof *x = d->xenoprof;
+ return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE));
+}
+
+int is_profiled(struct domain *d)
+{
+ return (is_active(d) || is_passive(d));
+}
+
+static void xenoprof_reset_stat(void)
+{
+ total_samples = 0;
+ invalid_buffer_samples = 0;
+ corrupted_buffer_samples = 0;
+ lost_samples = 0;
+ active_samples = 0;
+ passive_samples = 0;
+ idle_samples = 0;
+ others_samples = 0;
+}
+
+static void xenoprof_reset_buf(struct domain *d)
+{
+ int j;
+ struct xenoprof_buf *buf;
+
+ if ( d->xenoprof == NULL )
+ {
+ printk("xenoprof_reset_buf: ERROR - Unexpected "
+ "Xenoprof NULL pointer \n");
+ return;
+ }
+
+ for ( j = 0; j < MAX_VIRT_CPUS; j++ )
+ {
+ buf = d->xenoprof->vcpu[j].buffer;
+ if ( buf != NULL )
+ {
+ buf->event_head = 0;
+ buf->event_tail = 0;
+ }
+ }
+}
+
+static int
+share_xenoprof_page_with_guest(struct domain *d, unsigned long mfn, int npages)
+{
+ int i;
+
+ /* Check if previous page owner has released the page. */
+ for ( i = 0; i < npages; i++ )
+ {
+ struct page_info *page = mfn_to_page(mfn + i);
+ if ( (page->count_info & (PGC_allocated|PGC_count_mask)) != 0 )
+ {
+ gdprintk(XENLOG_INFO, "mfn 0x%lx page->count_info 0x%x\n",
+ mfn + i, page->count_info);
+ return -EBUSY;
+ }
+ page_set_owner(page, NULL);
+ }
+
+ for ( i = 0; i < npages; i++ )
+ share_xen_page_with_guest(mfn_to_page(mfn + i), d, XENSHARE_writable);
+
+ return 0;
+}
+
+static void
+unshare_xenoprof_page_with_guest(struct xenoprof *x)
+{
+ int i, npages = x->npages;
+ unsigned long mfn = virt_to_mfn(x->rawbuf);
+
+ for ( i = 0; i < npages; i++ )
+ {
+ struct page_info *page = mfn_to_page(mfn + i);
+ BUG_ON(page_get_owner(page) != current->domain);
+ if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+ put_page(page);
+ }
+}
+
+static void
+xenoprof_shared_gmfn_with_guest(
+ struct domain *d, unsigned long maddr, unsigned long gmaddr, int npages)
+{
+ int i;
+
+ for ( i = 0; i < npages; i++, maddr += PAGE_SIZE, gmaddr += PAGE_SIZE )
+ {
+ BUG_ON(page_get_owner(maddr_to_page(maddr)) != d);
+ xenoprof_shared_gmfn(d, gmaddr, maddr);
+ }
+}
+
+static int alloc_xenoprof_struct(
+ struct domain *d, int max_samples, int is_passive)
+{
+ struct vcpu *v;
+ int nvcpu, npages, bufsize, max_bufsize;
+ unsigned max_max_samples;
+ int i;
+
+ d->xenoprof = xmalloc(struct xenoprof);
+
+ if ( d->xenoprof == NULL )
+ {
+ printk("alloc_xenoprof_struct(): memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ memset(d->xenoprof, 0, sizeof(*d->xenoprof));
+
+ nvcpu = 0;
+ for_each_vcpu ( d, v )
+ nvcpu++;
+
+ /* reduce max_samples if necessary to limit pages allocated */
+ max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu;
+ max_max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) /
+ sizeof(struct event_log) ) + 1;
+ if ( (unsigned)max_samples > max_max_samples )
+ max_samples = max_max_samples;
+
+ bufsize = sizeof(struct xenoprof_buf) +
+ (max_samples - 1) * sizeof(struct event_log);
+ npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1;
+
+ d->xenoprof->rawbuf = alloc_xenheap_pages(get_order_from_pages(npages));
+ if ( d->xenoprof->rawbuf == NULL )
+ {
+ xfree(d->xenoprof);
+ d->xenoprof = NULL;
+ return -ENOMEM;
+ }
+
+ d->xenoprof->npages = npages;
+ d->xenoprof->nbuf = nvcpu;
+ d->xenoprof->bufsize = bufsize;
+ d->xenoprof->domain_ready = 0;
+ d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
+
+ /* Update buffer pointers for active vcpus */
+ i = 0;
+ for_each_vcpu ( d, v )
+ {
+ d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples;
+ d->xenoprof->vcpu[v->vcpu_id].buffer =
+ (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize];
+ d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples;
+ d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id;
+
+ i++;
+ /* in the unlikely case that the number of active vcpus changes */
+ if ( i >= nvcpu )
+ break;
+ }
+
+ return 0;
+}
+
+void free_xenoprof_pages(struct domain *d)
+{
+ struct xenoprof *x;
+ int order;
+
+ x = d->xenoprof;
+ if ( x == NULL )
+ return;
+
+ if ( x->rawbuf != NULL )
+ {
+ order = get_order_from_pages(x->npages);
+ free_xenheap_pages(x->rawbuf, order);
+ }
+
+ xfree(x);
+ d->xenoprof = NULL;
+}
+
+static int active_index(struct domain *d)
+{
+ int i;
+
+ for ( i = 0; i < adomains; i++ )
+ if ( active_domains[i] == d )
+ return i;
+
+ return -1;
+}
+
+static int set_active(struct domain *d)
+{
+ int ind;
+ struct xenoprof *x;
+
+ ind = active_index(d);
+ if ( ind < 0 )
+ return -EPERM;
+
+ x = d->xenoprof;
+ if ( x == NULL )
+ return -EPERM;
+
+ x->domain_ready = 1;
+ x->domain_type = XENOPROF_DOMAIN_ACTIVE;
+ active_ready[ind] = 1;
+ activated++;
+
+ return 0;
+}
+
+static int reset_active(struct domain *d)
+{
+ int ind;
+ struct xenoprof *x;
+
+ ind = active_index(d);
+ if ( ind < 0 )
+ return -EPERM;
+
+ x = d->xenoprof;
+ if ( x == NULL )
+ return -EPERM;
+
+ x->domain_ready = 0;
+ x->domain_type = XENOPROF_DOMAIN_IGNORED;
+ active_ready[ind] = 0;
+ active_domains[ind] = NULL;
+ activated--;
+ put_domain(d);
+
+ if ( activated <= 0 )
+ adomains = 0;
+
+ return 0;
+}
+
+static void reset_passive(struct domain *d)
+{
+ struct xenoprof *x;
+
+ if ( d == NULL )
+ return;
+
+ x = d->xenoprof;
+ if ( x == NULL )
+ return;
+
+ unshare_xenoprof_page_with_guest(x);
+ x->domain_type = XENOPROF_DOMAIN_IGNORED;
+}
+
+static void reset_active_list(void)
+{
+ int i;
+
+ for ( i = 0; i < adomains; i++ )
+ if ( active_ready[i] )
+ reset_active(active_domains[i]);
+
+ adomains = 0;
+ activated = 0;
+}
+
+static void reset_passive_list(void)
+{
+ int i;
+
+ for ( i = 0; i < pdomains; i++ )
+ {
+ reset_passive(passive_domains[i]);
+ put_domain(passive_domains[i]);
+ passive_domains[i] = NULL;
+ }
+
+ pdomains = 0;
+}
+
+static int add_active_list(domid_t domid)
+{
+ struct domain *d;
+
+ if ( adomains >= MAX_OPROF_DOMAINS )
+ return -E2BIG;
+
+ d = find_domain_by_id(domid);
+ if ( d == NULL )
+ return -EINVAL;
+
+ active_domains[adomains] = d;
+ active_ready[adomains] = 0;
+ adomains++;
+
+ return 0;
+}
+
+static int add_passive_list(XEN_GUEST_HANDLE(void) arg)
+{
+ struct xenoprof_passive passive;
+ struct domain *d;
+ int ret = 0;
+
+ if ( pdomains >= MAX_OPROF_DOMAINS )
+ return -E2BIG;
+
+ if ( copy_from_guest(&passive, arg, 1) )
+ return -EFAULT;
+
+ d = find_domain_by_id(passive.domain_id);
+ if ( d == NULL )
+ return -EINVAL;
+
+ if ( d->xenoprof == NULL )
+ {
+ ret = alloc_xenoprof_struct(d, passive.max_samples, 1);
+ if ( ret < 0 )
+ {
+ put_domain(d);
+ return -ENOMEM;
+ }
+ }
+
+ ret = share_xenoprof_page_with_guest(
+ current->domain, virt_to_mfn(d->xenoprof->rawbuf),
+ d->xenoprof->npages);
+ if ( ret < 0 )
+ {
+ put_domain(d);
+ return ret;
+ }
+
+ d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE;
+ passive.nbuf = d->xenoprof->nbuf;
+ passive.bufsize = d->xenoprof->bufsize;
+ if ( !shadow_mode_translate(d) )
+ passive.buf_gmaddr = __pa(d->xenoprof->rawbuf);
+ else
+ xenoprof_shared_gmfn_with_guest(
+ current->domain, __pa(d->xenoprof->rawbuf),
+ passive.buf_gmaddr, d->xenoprof->npages);
+
+ if ( copy_to_guest(arg, &passive, 1) )
+ {
+ put_domain(d);
+ return -EFAULT;
+ }
+
+ passive_domains[pdomains] = d;
+ pdomains++;
+
+ return ret;
+}
+
+void xenoprof_log_event(
+ struct vcpu *vcpu, unsigned long eip, int mode, int event)
+{
+ struct xenoprof_vcpu *v;
+ struct xenoprof_buf *buf;
+ int head;
+ int tail;
+ int size;
+
+
+ total_samples++;
+
+ /* ignore samples of un-monitored domains */
+ /* Count samples in idle separate from other unmonitored domains */
+ if ( !is_profiled(vcpu->domain) )
+ {
+ others_samples++;
+ return;
+ }
+
+ v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id];
+
+ /* Sanity check. Should never happen */
+ if ( v->buffer == NULL )
+ {
+ invalid_buffer_samples++;
+ return;
+ }
+
+ buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer;
+
+ head = buf->event_head;
+ tail = buf->event_tail;
+ size = v->event_size;
+
+ /* make sure indexes in shared buffer are sane */
+ if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
+ {
+ corrupted_buffer_samples++;
+ return;
+ }
+
+ if ( (head == tail - 1) || (head == size - 1 && tail == 0) )
+ {
+ buf->lost_samples++;
+ lost_samples++;
+ }
+ else
+ {
+ buf->event_log[head].eip = eip;
+ buf->event_log[head].mode = mode;
+ buf->event_log[head].event = event;
+ head++;
+ if ( head >= size )
+ head = 0;
+ buf->event_head = head;
+ if ( is_active(vcpu->domain) )
+ active_samples++;
+ else
+ passive_samples++;
+ if ( mode == 0 )
+ buf->user_samples++;
+ else if ( mode == 1 )
+ buf->kernel_samples++;
+ else
+ buf->xen_samples++;
+ }
+}
+
+static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg)
+{
+ struct xenoprof_init xenoprof_init;
+ int ret;
+
+ if ( copy_from_guest(&xenoprof_init, arg, 1) )
+ return -EFAULT;
+
+ if ( (ret = xenoprof_arch_init(&xenoprof_init.num_events,
+ &xenoprof_init.is_primary,
+ xenoprof_init.cpu_type)) )
+ return ret;
+
+ if ( copy_to_guest(arg, &xenoprof_init, 1) )
+ return -EFAULT;
+
+ if ( xenoprof_init.is_primary )
+ xenoprof_primary_profiler = current->domain;
+
+ return 0;
+}
+
+static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg)
+{
+ struct xenoprof_get_buffer xenoprof_get_buffer;
+ struct domain *d = current->domain;
+ int ret;
+
+ if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) )
+ return -EFAULT;
+
+ /*
+ * We allocate xenoprof struct and buffers only at first time
+ * get_buffer is called. Memory is then kept until domain is destroyed.
+ */
+ if ( d->xenoprof == NULL )
+ {
+ ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0);
+ if ( ret < 0 )
+ return ret;
+ }
+
+ ret = share_xenoprof_page_with_guest(
+ d, virt_to_mfn(d->xenoprof->rawbuf), d->xenoprof->npages);
+ if ( ret < 0 )
+ return ret;
+
+ xenoprof_reset_buf(d);
+
+ d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
+ d->xenoprof->domain_ready = 0;
+ d->xenoprof->is_primary = (xenoprof_primary_profiler == current->domain);
+
+ xenoprof_get_buffer.nbuf = d->xenoprof->nbuf;
+ xenoprof_get_buffer.bufsize = d->xenoprof->bufsize;
+ if ( !shadow_mode_translate(d) )
+ xenoprof_get_buffer.buf_gmaddr = __pa(d->xenoprof->rawbuf);
+ else
+ xenoprof_shared_gmfn_with_guest(
+ d, __pa(d->xenoprof->rawbuf), xenoprof_get_buffer.buf_gmaddr,
+ d->xenoprof->npages);
+
+ if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) )
+ return -EFAULT;
+
+ return 0;
+}
+
+#define NONPRIV_OP(op) ( (op == XENOPROF_init) \
+ || (op == XENOPROF_enable_virq) \
+ || (op == XENOPROF_disable_virq) \
+ || (op == XENOPROF_get_buffer))
+
+int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
+{
+ int ret = 0;
+
+ if ( (op < 0) || (op > XENOPROF_last_op) )
+ {
+ printk("xenoprof: invalid operation %d for domain %d\n",
+ op, current->domain->domain_id);
+ return -EINVAL;
+ }
+
+ if ( !NONPRIV_OP(op) && (current->domain != xenoprof_primary_profiler) )
+ {
+ printk("xenoprof: dom %d denied privileged operation %d\n",
+ current->domain->domain_id, op);
+ return -EPERM;
+ }
+
+ spin_lock(&xenoprof_lock);
+
+ switch ( op )
+ {
+ case XENOPROF_init:
+ ret = xenoprof_op_init(arg);
+ break;
+
+ case XENOPROF_get_buffer:
+ ret = xenoprof_op_get_buffer(arg);
+ break;
+
+ case XENOPROF_reset_active_list:
+ {
+ reset_active_list();
+ ret = 0;
+ break;
+ }
+ case XENOPROF_reset_passive_list:
+ {
+ reset_passive_list();
+ ret = 0;
+ break;
+ }
+ case XENOPROF_set_active:
+ {
+ domid_t domid;
+ if ( xenoprof_state != XENOPROF_IDLE )
+ {
+ ret = -EPERM;
+ break;
+ }
+ if ( copy_from_guest(&domid, arg, 1) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+ ret = add_active_list(domid);
+ break;
+ }
+ case XENOPROF_set_passive:
+ {
+ if ( xenoprof_state != XENOPROF_IDLE )
+ {
+ ret = -EPERM;
+ break;
+ }
+ ret = add_passive_list(arg);
+ break;
+ }
+ case XENOPROF_reserve_counters:
+ if ( xenoprof_state != XENOPROF_IDLE )
+ {
+ ret = -EPERM;
+ break;
+ }
+ ret = xenoprof_arch_reserve_counters();
+ if ( !ret )
+ xenoprof_state = XENOPROF_COUNTERS_RESERVED;
+ break;
+
+ case XENOPROF_counter:
+ if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) ||
+ (adomains == 0) )
+ {
+ ret = -EPERM;
+ break;
+ }
+
+ ret = xenoprof_arch_counter(arg);
+ break;
+
+ case XENOPROF_setup_events:
+ if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED )
+ {
+ ret = -EPERM;
+ break;
+ }
+ ret = xenoprof_arch_setup_events();
+ if ( !ret )
+ xenoprof_state = XENOPROF_READY;
+ break;
+
+ case XENOPROF_enable_virq:
+ {
+ int i;
+ if ( current->domain == xenoprof_primary_profiler )
+ {
+ xenoprof_arch_enable_virq();
+ xenoprof_reset_stat();
+ for ( i = 0; i < pdomains; i++ )
+ xenoprof_reset_buf(passive_domains[i]);
+ }
+ xenoprof_reset_buf(current->domain);
+ ret = set_active(current->domain);
+ break;
+ }
+
+ case XENOPROF_start:
+ ret = -EPERM;
+ if ( (xenoprof_state == XENOPROF_READY) &&
+ (activated == adomains) )
+ ret = xenoprof_arch_start();
+ if ( ret == 0 )
+ xenoprof_state = XENOPROF_PROFILING;
+ break;
+
+ case XENOPROF_stop:
+ if ( xenoprof_state != XENOPROF_PROFILING ) {
+ ret = -EPERM;
+ break;
+ }
+ xenoprof_arch_stop();
+ xenoprof_state = XENOPROF_READY;
+ break;
+
+ case XENOPROF_disable_virq:
+ {
+ struct xenoprof *x;
+ if ( (xenoprof_state == XENOPROF_PROFILING) &&
+ (is_active(current->domain)) )
+ {
+ ret = -EPERM;
+ break;
+ }
+ if ( (ret = reset_active(current->domain)) != 0 )
+ break;
+ x = current->domain->xenoprof;
+ unshare_xenoprof_page_with_guest(x);
+ break;
+ }
+
+ case XENOPROF_release_counters:
+ ret = -EPERM;
+ if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) ||
+ (xenoprof_state == XENOPROF_READY) )
+ {
+ xenoprof_state = XENOPROF_IDLE;
+ xenoprof_arch_release_counters();
+ xenoprof_arch_disable_virq();
+ reset_passive_list();
+ ret = 0;
+ }
+ break;
+
+ case XENOPROF_shutdown:
+ ret = -EPERM;
+ if ( xenoprof_state == XENOPROF_IDLE )
+ {
+ activated = 0;
+ adomains=0;
+ xenoprof_primary_profiler = NULL;
+ ret = 0;
+ }
+ break;
+
+ default:
+ ret = -ENOSYS;
+ }
+
+ spin_unlock(&xenoprof_lock);
+
+ if ( ret < 0 )
+ printk("xenoprof: operation %d failed for dom %d (status : %d)\n",
+ op, current->domain->domain_id, ret);
+
+ return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/xmalloc.c b/xen/common/xmalloc.c
index 019bf9987a..60f75d60b1 100644
--- a/xen/common/xmalloc.c
+++ b/xen/common/xmalloc.c
@@ -34,16 +34,81 @@
#include <xen/cache.h>
#include <xen/prefetch.h>
+/*
+ * XMALLOC_DEBUG:
+ * 1. Free data blocks are filled with poison bytes.
+ * 2. In-use data blocks have guard bytes at the start and end.
+ */
+#ifndef NDEBUG
+#define XMALLOC_DEBUG 1
+#endif
+
static LIST_HEAD(freelist);
static DEFINE_SPINLOCK(freelist_lock);
struct xmalloc_hdr
{
- /* Total including this hdr. */
+ /* Size is total including this header. */
size_t size;
struct list_head freelist;
} __cacheline_aligned;
+static void add_to_freelist(struct xmalloc_hdr *hdr)
+{
+#if XMALLOC_DEBUG
+ memset(hdr + 1, 0xa5, hdr->size - sizeof(*hdr));
+#endif
+ list_add(&hdr->freelist, &freelist);
+}
+
+static void del_from_freelist(struct xmalloc_hdr *hdr)
+{
+#if XMALLOC_DEBUG
+ size_t i;
+ unsigned char *data = (unsigned char *)(hdr + 1);
+ for ( i = 0; i < (hdr->size - sizeof(*hdr)); i++ )
+ BUG_ON(data[i] != 0xa5);
+ BUG_ON((hdr->size <= 0) || (hdr->size >= PAGE_SIZE));
+#endif
+ list_del(&hdr->freelist);
+}
+
+static void *data_from_header(struct xmalloc_hdr *hdr)
+{
+#if XMALLOC_DEBUG
+ /* Data block contain SMP_CACHE_BYTES of guard canary. */
+ unsigned char *data = (unsigned char *)(hdr + 1);
+ memset(data, 0x5a, SMP_CACHE_BYTES);
+ memset(data + hdr->size - sizeof(*hdr) - SMP_CACHE_BYTES,
+ 0x5a, SMP_CACHE_BYTES);
+ return data + SMP_CACHE_BYTES;
+#else
+ return hdr + 1;
+#endif
+}
+
+static struct xmalloc_hdr *header_from_data(const void *p)
+{
+#if XMALLOC_DEBUG
+ unsigned char *data = (unsigned char *)p - SMP_CACHE_BYTES;
+ struct xmalloc_hdr *hdr = (struct xmalloc_hdr *)data - 1;
+ size_t i;
+
+ /* Check header guard canary. */
+ for ( i = 0; i < SMP_CACHE_BYTES; i++ )
+ BUG_ON(data[i] != 0x5a);
+
+ /* Check footer guard canary. */
+ data += hdr->size - sizeof(*hdr) - SMP_CACHE_BYTES;
+ for ( i = 0; i < SMP_CACHE_BYTES; i++ )
+ BUG_ON(data[i] != 0x5a);
+
+ return hdr;
+#else
+ return (struct xmalloc_hdr *)p - 1;
+#endif
+}
+
static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block)
{
struct xmalloc_hdr *extra;
@@ -54,7 +119,7 @@ static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block)
{
extra = (struct xmalloc_hdr *)((unsigned long)hdr + size);
extra->size = leftover;
- list_add(&extra->freelist, &freelist);
+ add_to_freelist(extra);
}
else
{
@@ -79,7 +144,7 @@ static void *xmalloc_new_page(size_t size)
maybe_split(hdr, size, PAGE_SIZE);
spin_unlock_irqrestore(&freelist_lock, flags);
- return hdr+1;
+ return data_from_header(hdr);
}
/* Big object? Just use the page allocator. */
@@ -96,7 +161,7 @@ static void *xmalloc_whole_pages(size_t size)
/* Debugging aid. */
hdr->freelist.next = hdr->freelist.prev = NULL;
- return hdr+1;
+ return data_from_header(hdr);
}
/* Return size, increased to alignment with align. */
@@ -113,6 +178,11 @@ void *_xmalloc(size_t size, size_t align)
/* We currently always return cacheline aligned. */
BUG_ON(align > SMP_CACHE_BYTES);
+#if XMALLOC_DEBUG
+ /* Add room for canaries at start and end of data block. */
+ size += 2 * SMP_CACHE_BYTES;
+#endif
+
/* Add room for header, pad to align next header. */
size += sizeof(struct xmalloc_hdr);
size = align_up(size, __alignof__(struct xmalloc_hdr));
@@ -127,10 +197,10 @@ void *_xmalloc(size_t size, size_t align)
{
if ( i->size < size )
continue;
- list_del(&i->freelist);
+ del_from_freelist(i);
maybe_split(i, size, i->size);
spin_unlock_irqrestore(&freelist_lock, flags);
- return i+1;
+ return data_from_header(i);
}
spin_unlock_irqrestore(&freelist_lock, flags);
@@ -146,7 +216,7 @@ void xfree(const void *p)
if ( p == NULL )
return;
- hdr = (struct xmalloc_hdr *)p - 1;
+ hdr = header_from_data(p);
/* We know hdr will be on same page. */
BUG_ON(((long)p & PAGE_MASK) != ((long)hdr & PAGE_MASK));
@@ -175,7 +245,7 @@ void xfree(const void *p)
/* We follow this block? Swallow it. */
if ( (_i + i->size) == _hdr )
{
- list_del(&i->freelist);
+ del_from_freelist(i);
i->size += hdr->size;
hdr = i;
}
@@ -183,7 +253,7 @@ void xfree(const void *p)
/* We precede this block? Swallow it. */
if ( (_hdr + hdr->size) == _i )
{
- list_del(&i->freelist);
+ del_from_freelist(i);
hdr->size += i->size;
}
}
@@ -196,7 +266,7 @@ void xfree(const void *p)
}
else
{
- list_add(&hdr->freelist, &freelist);
+ add_to_freelist(hdr);
}
spin_unlock_irqrestore(&freelist_lock, flags);
diff --git a/xen/drivers/acpi/Makefile b/xen/drivers/acpi/Makefile
index 68dafe3a52..08844a529d 100644
--- a/xen/drivers/acpi/Makefile
+++ b/xen/drivers/acpi/Makefile
@@ -1 +1,2 @@
obj-y += tables.o
+obj-y += numa.o
diff --git a/xen/drivers/acpi/numa.c b/xen/drivers/acpi/numa.c
new file mode 100644
index 0000000000..ecf426ece4
--- /dev/null
+++ b/xen/drivers/acpi/numa.c
@@ -0,0 +1,216 @@
+/*
+ * acpi_numa.c - ACPI NUMA support
+ *
+ * Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#if 0
+#include <linux/module.h>
+#include <linux/kernel.h>
+#endif
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/types.h>
+#include <xen/errno.h>
+#include <xen/acpi.h>
+#include <xen/numa.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acmacros.h>
+#include <asm/page.h> /* __va() */
+
+#define ACPI_NUMA 0x80000000
+#define _COMPONENT ACPI_NUMA
+ACPI_MODULE_NAME("numa")
+
+extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
+ unsigned long madt_size,
+ int entry_id,
+ acpi_madt_entry_handler handler,
+ unsigned int max_entries);
+
+void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+{
+
+ ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
+
+ if (!header)
+ return;
+
+ switch (header->type) {
+
+ case ACPI_SRAT_PROCESSOR_AFFINITY:
+#ifdef ACPI_DEBUG_OUTPUT
+ {
+ struct acpi_table_processor_affinity *p =
+ (struct acpi_table_processor_affinity *)header;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
+ p->apic_id, p->lsapic_eid,
+ p->proximity_domain,
+ p->flags.
+ enabled ? "enabled" : "disabled"));
+ }
+#endif /* ACPI_DEBUG_OUTPUT */
+ break;
+
+ case ACPI_SRAT_MEMORY_AFFINITY:
+#ifdef ACPI_DEBUG_OUTPUT
+ {
+ struct acpi_table_memory_affinity *p =
+ (struct acpi_table_memory_affinity *)header;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
+ p->base_addr_hi, p->base_addr_lo,
+ p->length_hi, p->length_lo,
+ p->memory_type, p->proximity_domain,
+ p->flags.
+ enabled ? "enabled" : "disabled",
+ p->flags.
+ hot_pluggable ? " hot-pluggable" :
+ ""));
+ }
+#endif /* ACPI_DEBUG_OUTPUT */
+ break;
+
+ default:
+ printk(KERN_WARNING PREFIX
+ "Found unsupported SRAT entry (type = 0x%x)\n",
+ header->type);
+ break;
+ }
+}
+
+static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+{
+ struct acpi_table_slit *slit;
+ u32 localities;
+
+ if (!phys_addr || !size)
+ return -EINVAL;
+
+ slit = (struct acpi_table_slit *)__va(phys_addr);
+
+ /* downcast just for %llu vs %lu for i386/ia64 */
+ localities = (u32) slit->localities;
+
+ acpi_numa_slit_init(slit);
+
+ return 0;
+}
+
+static int __init
+acpi_parse_processor_affinity(acpi_table_entry_header * header,
+ const unsigned long end)
+{
+ struct acpi_table_processor_affinity *processor_affinity;
+
+ processor_affinity = (struct acpi_table_processor_affinity *)header;
+ if (!processor_affinity)
+ return -EINVAL;
+
+ acpi_table_print_srat_entry(header);
+
+ /* let architecture-dependent part to do it */
+ acpi_numa_processor_affinity_init(processor_affinity);
+
+ return 0;
+}
+
+static int __init
+acpi_parse_memory_affinity(acpi_table_entry_header * header,
+ const unsigned long end)
+{
+ struct acpi_table_memory_affinity *memory_affinity;
+
+ memory_affinity = (struct acpi_table_memory_affinity *)header;
+ if (!memory_affinity)
+ return -EINVAL;
+
+ acpi_table_print_srat_entry(header);
+
+ /* let architecture-dependent part to do it */
+ acpi_numa_memory_affinity_init(memory_affinity);
+
+ return 0;
+}
+
+static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+{
+ struct acpi_table_srat *srat;
+
+ if (!phys_addr || !size)
+ return -EINVAL;
+
+ srat = (struct acpi_table_srat *)__va(phys_addr);
+
+ return 0;
+}
+
+int __init
+acpi_table_parse_srat(enum acpi_srat_entry_id id,
+ acpi_madt_entry_handler handler, unsigned int max_entries)
+{
+ return acpi_table_parse_madt_family(ACPI_SRAT,
+ sizeof(struct acpi_table_srat), id,
+ handler, max_entries);
+}
+
+int __init acpi_numa_init(void)
+{
+ int result;
+
+ /* SRAT: Static Resource Affinity Table */
+ result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+
+ if (result > 0) {
+ result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+ acpi_parse_processor_affinity,
+ NR_CPUS);
+ result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ }
+
+ /* SLIT: System Locality Information Table */
+ result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+
+ acpi_numa_arch_fixup();
+ return 0;
+}
+
+#if 0
+int acpi_get_pxm(acpi_handle h)
+{
+ unsigned long pxm;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle phandle = h;
+
+ do {
+ handle = phandle;
+ status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+ if (ACPI_SUCCESS(status))
+ return (int)pxm;
+ status = acpi_get_parent(handle, &phandle);
+ } while (ACPI_SUCCESS(status));
+ return -1;
+}
+
+EXPORT_SYMBOL(acpi_get_pxm);
+#endif
diff --git a/xen/drivers/acpi/tables.c b/xen/drivers/acpi/tables.c
index 1c718efc88..313e7e5320 100644
--- a/xen/drivers/acpi/tables.c
+++ b/xen/drivers/acpi/tables.c
@@ -37,28 +37,28 @@
#define PREFIX "ACPI: "
-#define ACPI_MAX_TABLES 256
+#define ACPI_MAX_TABLES 128
static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
- [ACPI_TABLE_UNKNOWN] = "????",
- [ACPI_APIC] = "APIC",
- [ACPI_BOOT] = "BOOT",
- [ACPI_DBGP] = "DBGP",
- [ACPI_DSDT] = "DSDT",
- [ACPI_ECDT] = "ECDT",
- [ACPI_ETDT] = "ETDT",
- [ACPI_FADT] = "FACP",
- [ACPI_FACS] = "FACS",
- [ACPI_OEMX] = "OEM",
- [ACPI_PSDT] = "PSDT",
- [ACPI_SBST] = "SBST",
- [ACPI_SLIT] = "SLIT",
- [ACPI_SPCR] = "SPCR",
- [ACPI_SRAT] = "SRAT",
- [ACPI_SSDT] = "SSDT",
- [ACPI_SPMI] = "SPMI",
- [ACPI_HPET] = "HPET",
- [ACPI_MCFG] = "MCFG",
+ [ACPI_TABLE_UNKNOWN] = "????",
+ [ACPI_APIC] = "APIC",
+ [ACPI_BOOT] = "BOOT",
+ [ACPI_DBGP] = "DBGP",
+ [ACPI_DSDT] = "DSDT",
+ [ACPI_ECDT] = "ECDT",
+ [ACPI_ETDT] = "ETDT",
+ [ACPI_FADT] = "FACP",
+ [ACPI_FACS] = "FACS",
+ [ACPI_OEMX] = "OEM",
+ [ACPI_PSDT] = "PSDT",
+ [ACPI_SBST] = "SBST",
+ [ACPI_SLIT] = "SLIT",
+ [ACPI_SPCR] = "SPCR",
+ [ACPI_SRAT] = "SRAT",
+ [ACPI_SSDT] = "SSDT",
+ [ACPI_SPMI] = "SPMI",
+ [ACPI_HPET] = "HPET",
+ [ACPI_MCFG] = "MCFG",
};
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
@@ -66,52 +66,44 @@ static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
/* System Description Table (RSDT/XSDT) */
struct acpi_table_sdt {
- unsigned long pa;
- enum acpi_table_id id;
- unsigned long size;
+ unsigned long pa;
+ enum acpi_table_id id;
+ unsigned long size;
} __attribute__ ((packed));
-static unsigned long sdt_pa; /* Physical Address */
-static unsigned long sdt_count; /* Table count */
+static unsigned long sdt_pa; /* Physical Address */
+static unsigned long sdt_count; /* Table count */
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES];
+static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-void
-acpi_table_print (
- struct acpi_table_header *header,
- unsigned long phys_addr)
+void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
{
- char *name = NULL;
+ char *name = NULL;
if (!header)
return;
/* Some table signatures aren't good table names */
- if (!strncmp((char *) &header->signature,
- acpi_table_signatures[ACPI_APIC],
- sizeof(header->signature))) {
+ if (!strncmp((char *)&header->signature,
+ acpi_table_signatures[ACPI_APIC],
+ sizeof(header->signature))) {
name = "MADT";
- }
- else if (!strncmp((char *) &header->signature,
- acpi_table_signatures[ACPI_FADT],
- sizeof(header->signature))) {
+ } else if (!strncmp((char *)&header->signature,
+ acpi_table_signatures[ACPI_FADT],
+ sizeof(header->signature))) {
name = "FADT";
- }
- else
+ } else
name = header->signature;
- printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n",
- name, header->revision, header->oem_id,
- header->oem_table_id, header->oem_revision,
- header->asl_compiler_id, header->asl_compiler_revision,
- (void *) phys_addr);
+ printk(KERN_DEBUG PREFIX
+ "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
+ header->revision, header->oem_id, header->oem_table_id,
+ header->oem_revision, header->asl_compiler_id,
+ header->asl_compiler_revision, (void *)phys_addr);
}
-
-void
-acpi_table_print_madt_entry (
- acpi_table_entry_header *header)
+void acpi_table_print_madt_entry(acpi_table_entry_header * header)
{
if (!header)
return;
@@ -119,113 +111,127 @@ acpi_table_print_madt_entry (
switch (header->type) {
case ACPI_MADT_LAPIC:
- {
- struct acpi_table_lapic *p =
- (struct acpi_table_lapic*) header;
- printk(KERN_INFO PREFIX "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->acpi_id, p->id, p->flags.enabled?"enabled":"disabled");
- }
+ {
+ struct acpi_table_lapic *p =
+ (struct acpi_table_lapic *)header;
+ printk(KERN_INFO PREFIX
+ "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
+ p->acpi_id, p->id,
+ p->flags.enabled ? "enabled" : "disabled");
+ }
break;
case ACPI_MADT_IOAPIC:
- {
- struct acpi_table_ioapic *p =
- (struct acpi_table_ioapic*) header;
- printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
- p->id, p->address, p->global_irq_base);
- }
+ {
+ struct acpi_table_ioapic *p =
+ (struct acpi_table_ioapic *)header;
+ printk(KERN_INFO PREFIX
+ "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
+ p->id, p->address, p->global_irq_base);
+ }
break;
case ACPI_MADT_INT_SRC_OVR:
- {
- struct acpi_table_int_src_ovr *p =
- (struct acpi_table_int_src_ovr*) header;
- printk(KERN_INFO PREFIX "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->bus_irq, p->global_irq,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger]);
- if(p->flags.reserved)
- printk(KERN_INFO PREFIX "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->flags.reserved);
+ {
+ struct acpi_table_int_src_ovr *p =
+ (struct acpi_table_int_src_ovr *)header;
+ printk(KERN_INFO PREFIX
+ "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
+ p->bus, p->bus_irq, p->global_irq,
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger]);
+ if (p->flags.reserved)
+ printk(KERN_INFO PREFIX
+ "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
+ p->flags.reserved);
- }
+ }
break;
case ACPI_MADT_NMI_SRC:
- {
- struct acpi_table_nmi_src *p =
- (struct acpi_table_nmi_src*) header;
- printk(KERN_INFO PREFIX "NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger], p->global_irq);
- }
+ {
+ struct acpi_table_nmi_src *p =
+ (struct acpi_table_nmi_src *)header;
+ printk(KERN_INFO PREFIX
+ "NMI_SRC (%s %s global_irq %d)\n",
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger],
+ p->global_irq);
+ }
break;
case ACPI_MADT_LAPIC_NMI:
- {
- struct acpi_table_lapic_nmi *p =
- (struct acpi_table_lapic_nmi*) header;
- printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->acpi_id,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger], p->lint);
- }
+ {
+ struct acpi_table_lapic_nmi *p =
+ (struct acpi_table_lapic_nmi *)header;
+ printk(KERN_INFO PREFIX
+ "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
+ p->acpi_id,
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger],
+ p->lint);
+ }
break;
case ACPI_MADT_LAPIC_ADDR_OVR:
- {
- struct acpi_table_lapic_addr_ovr *p =
- (struct acpi_table_lapic_addr_ovr*) header;
- printk(KERN_INFO PREFIX "LAPIC_ADDR_OVR (address[%p])\n",
- (void *) (unsigned long) p->address);
- }
+ {
+ struct acpi_table_lapic_addr_ovr *p =
+ (struct acpi_table_lapic_addr_ovr *)header;
+ printk(KERN_INFO PREFIX
+ "LAPIC_ADDR_OVR (address[%p])\n",
+ (void *)(unsigned long)p->address);
+ }
break;
case ACPI_MADT_IOSAPIC:
- {
- struct acpi_table_iosapic *p =
- (struct acpi_table_iosapic*) header;
- printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
- p->id, (void *) (unsigned long) p->address, p->global_irq_base);
- }
+ {
+ struct acpi_table_iosapic *p =
+ (struct acpi_table_iosapic *)header;
+ printk(KERN_INFO PREFIX
+ "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+ p->id, (void *)(unsigned long)p->address,
+ p->global_irq_base);
+ }
break;
case ACPI_MADT_LSAPIC:
- {
- struct acpi_table_lsapic *p =
- (struct acpi_table_lsapic*) header;
- printk(KERN_INFO PREFIX "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->acpi_id, p->id, p->eid, p->flags.enabled?"enabled":"disabled");
- }
+ {
+ struct acpi_table_lsapic *p =
+ (struct acpi_table_lsapic *)header;
+ printk(KERN_INFO PREFIX
+ "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
+ p->acpi_id, p->id, p->eid,
+ p->flags.enabled ? "enabled" : "disabled");
+ }
break;
case ACPI_MADT_PLAT_INT_SRC:
- {
- struct acpi_table_plat_int_src *p =
- (struct acpi_table_plat_int_src*) header;
- printk(KERN_INFO PREFIX "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
- p->type, p->id, p->eid, p->iosapic_vector, p->global_irq);
- }
+ {
+ struct acpi_table_plat_int_src *p =
+ (struct acpi_table_plat_int_src *)header;
+ printk(KERN_INFO PREFIX
+ "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger],
+ p->type, p->id, p->eid, p->iosapic_vector,
+ p->global_irq);
+ }
break;
default:
- printk(KERN_WARNING PREFIX "Found unsupported MADT entry (type = 0x%x)\n",
- header->type);
+ printk(KERN_WARNING PREFIX
+ "Found unsupported MADT entry (type = 0x%x)\n",
+ header->type);
break;
}
}
-
static int
-acpi_table_compute_checksum (
- void *table_pointer,
- unsigned long length)
+acpi_table_compute_checksum(void *table_pointer, unsigned long length)
{
- u8 *p = (u8 *) table_pointer;
- unsigned long remains = length;
- unsigned long sum = 0;
+ u8 *p = (u8 *) table_pointer;
+ unsigned long remains = length;
+ unsigned long sum = 0;
if (!p || !length)
return -EINVAL;
@@ -241,9 +247,8 @@ acpi_table_compute_checksum (
* for acpi_blacklisted(), acpi_table_get_sdt()
*/
int __init
-acpi_get_table_header_early (
- enum acpi_table_id id,
- struct acpi_table_header **header)
+acpi_get_table_header_early(enum acpi_table_id id,
+ struct acpi_table_header **header)
{
unsigned int i;
enum acpi_table_id temp_id;
@@ -260,7 +265,7 @@ acpi_get_table_header_early (
if (sdt_entry[i].id != temp_id)
continue;
*header = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
+ __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
if (!*header) {
printk(KERN_WARNING PREFIX "Unable to map %s\n",
acpi_table_signatures[temp_id]);
@@ -277,14 +282,17 @@ acpi_get_table_header_early (
/* Map the DSDT header via the pointer in the FADT */
if (id == ACPI_DSDT) {
- struct fadt_descriptor_rev2 *fadt = (struct fadt_descriptor_rev2 *) *header;
+ struct fadt_descriptor_rev2 *fadt =
+ (struct fadt_descriptor_rev2 *)*header;
if (fadt->revision == 3 && fadt->Xdsdt) {
- *header = (void *) __acpi_map_table(fadt->Xdsdt,
- sizeof(struct acpi_table_header));
+ *header = (void *)__acpi_map_table(fadt->Xdsdt,
+ sizeof(struct
+ acpi_table_header));
} else if (fadt->V1_dsdt) {
- *header = (void *) __acpi_map_table(fadt->V1_dsdt,
- sizeof(struct acpi_table_header));
+ *header = (void *)__acpi_map_table(fadt->V1_dsdt,
+ sizeof(struct
+ acpi_table_header));
} else
*header = NULL;
@@ -296,21 +304,19 @@ acpi_get_table_header_early (
return 0;
}
-
int __init
-acpi_table_parse_madt_family (
- enum acpi_table_id id,
- unsigned long madt_size,
- int entry_id,
- acpi_madt_entry_handler handler,
- unsigned int max_entries)
+acpi_table_parse_madt_family(enum acpi_table_id id,
+ unsigned long madt_size,
+ int entry_id,
+ acpi_madt_entry_handler handler,
+ unsigned int max_entries)
{
- void *madt = NULL;
- acpi_table_entry_header *entry;
- unsigned int count = 0;
- unsigned long madt_end;
- unsigned int i;
+ void *madt = NULL;
+ acpi_table_entry_header *entry;
+ unsigned int count = 0;
+ unsigned long madt_end;
+ unsigned int i;
if (!handler)
return -EINVAL;
@@ -321,7 +327,7 @@ acpi_table_parse_madt_family (
if (sdt_entry[i].id != id)
continue;
madt = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
+ __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
if (!madt) {
printk(KERN_WARNING PREFIX "Unable to map %s\n",
acpi_table_signatures[id]);
@@ -336,21 +342,22 @@ acpi_table_parse_madt_family (
return -ENODEV;
}
- madt_end = (unsigned long) madt + sdt_entry[i].size;
+ madt_end = (unsigned long)madt + sdt_entry[i].size;
/* Parse all entries looking for a match. */
entry = (acpi_table_entry_header *)
- ((unsigned long) madt + madt_size);
+ ((unsigned long)madt + madt_size);
- while (((unsigned long) entry) + sizeof(acpi_table_entry_header) < madt_end) {
- if (entry->type == entry_id &&
- (!max_entries || count++ < max_entries))
+ while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
+ madt_end) {
+ if (entry->type == entry_id
+ && (!max_entries || count++ < max_entries))
if (handler(entry, madt_end))
return -EINVAL;
entry = (acpi_table_entry_header *)
- ((unsigned long) entry + entry->length);
+ ((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
@@ -361,25 +368,19 @@ acpi_table_parse_madt_family (
return count;
}
-
int __init
-acpi_table_parse_madt (
- enum acpi_madt_entry_id id,
- acpi_madt_entry_handler handler,
- unsigned int max_entries)
+acpi_table_parse_madt(enum acpi_madt_entry_id id,
+ acpi_madt_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt),
- id, handler, max_entries);
+ return acpi_table_parse_madt_family(ACPI_APIC,
+ sizeof(struct acpi_table_madt), id,
+ handler, max_entries);
}
-
-int __init
-acpi_table_parse (
- enum acpi_table_id id,
- acpi_table_handler handler)
+int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
{
- int count = 0;
- unsigned int i = 0;
+ int count = 0;
+ unsigned int i = 0;
if (!handler)
return -EINVAL;
@@ -392,20 +393,18 @@ acpi_table_parse (
handler(sdt_entry[i].pa, sdt_entry[i].size);
else
- printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n",
- count, acpi_table_signatures[id]);
+ printk(KERN_WARNING PREFIX
+ "%d duplicate %s table ignored.\n", count,
+ acpi_table_signatures[id]);
}
return count;
}
-
-static int __init
-acpi_table_get_sdt (
- struct acpi_table_rsdp *rsdp)
+static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
{
struct acpi_table_header *header = NULL;
- unsigned int i, id = 0;
+ unsigned int i, id = 0;
if (!rsdp)
return -EINVAL;
@@ -413,24 +412,25 @@ acpi_table_get_sdt (
/* First check XSDT (but only on ACPI 2.0-compatible systems) */
if ((rsdp->revision >= 2) &&
- (((struct acpi20_table_rsdp*)rsdp)->xsdt_address)) {
-
- struct acpi_table_xsdt *mapped_xsdt = NULL;
+ (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
+
+ struct acpi_table_xsdt *mapped_xsdt = NULL;
- sdt_pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address;
+ sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
/* map in just the header */
header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+ __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
if (!header) {
- printk(KERN_WARNING PREFIX "Unable to map XSDT header\n");
+ printk(KERN_WARNING PREFIX
+ "Unable to map XSDT header\n");
return -ENODEV;
}
/* remap in the entire table before processing */
mapped_xsdt = (struct acpi_table_xsdt *)
- __acpi_map_table(sdt_pa, header->length);
+ __acpi_map_table(sdt_pa, header->length);
if (!mapped_xsdt) {
printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
return -ENODEV;
@@ -438,7 +438,8 @@ acpi_table_get_sdt (
header = &mapped_xsdt->header;
if (strncmp(header->signature, "XSDT", 4)) {
- printk(KERN_WARNING PREFIX "XSDT signature incorrect\n");
+ printk(KERN_WARNING PREFIX
+ "XSDT signature incorrect\n");
return -ENODEV;
}
@@ -447,36 +448,39 @@ acpi_table_get_sdt (
return -ENODEV;
}
- sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 3;
+ sdt_count =
+ (header->length - sizeof(struct acpi_table_header)) >> 3;
if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
+ printk(KERN_WARNING PREFIX
+ "Truncated %lu XSDT entries\n",
+ (sdt_count - ACPI_MAX_TABLES));
sdt_count = ACPI_MAX_TABLES;
}
for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long) mapped_xsdt->entry[i];
+ sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
}
/* Then check RSDT */
else if (rsdp->rsdt_address) {
- struct acpi_table_rsdt *mapped_rsdt = NULL;
+ struct acpi_table_rsdt *mapped_rsdt = NULL;
sdt_pa = rsdp->rsdt_address;
/* map in just the header */
header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+ __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
if (!header) {
- printk(KERN_WARNING PREFIX "Unable to map RSDT header\n");
+ printk(KERN_WARNING PREFIX
+ "Unable to map RSDT header\n");
return -ENODEV;
}
/* remap in the entire table before processing */
mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt_pa, header->length);
+ __acpi_map_table(sdt_pa, header->length);
if (!mapped_rsdt) {
printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
return -ENODEV;
@@ -484,7 +488,8 @@ acpi_table_get_sdt (
header = &mapped_rsdt->header;
if (strncmp(header->signature, "RSDT", 4)) {
- printk(KERN_WARNING PREFIX "RSDT signature incorrect\n");
+ printk(KERN_WARNING PREFIX
+ "RSDT signature incorrect\n");
return -ENODEV;
}
@@ -493,19 +498,22 @@ acpi_table_get_sdt (
return -ENODEV;
}
- sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 2;
+ sdt_count =
+ (header->length - sizeof(struct acpi_table_header)) >> 2;
if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX "Truncated %lu RSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
+ printk(KERN_WARNING PREFIX
+ "Truncated %lu RSDT entries\n",
+ (sdt_count - ACPI_MAX_TABLES));
sdt_count = ACPI_MAX_TABLES;
}
for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
+ sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
}
else {
- printk(KERN_WARNING PREFIX "No System Description Table (RSDT/XSDT) specified in RSDP\n");
+ printk(KERN_WARNING PREFIX
+ "No System Description Table (RSDT/XSDT) specified in RSDP\n");
return -ENODEV;
}
@@ -515,18 +523,17 @@ acpi_table_get_sdt (
/* map in just the header */
header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa,
- sizeof(struct acpi_table_header));
+ __acpi_map_table(sdt_entry[i].pa,
+ sizeof(struct acpi_table_header));
if (!header)
continue;
/* remap in the entire table before processing */
header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa,
- header->length);
+ __acpi_map_table(sdt_entry[i].pa, header->length);
if (!header)
continue;
-
+
acpi_table_print(header, sdt_entry[i].pa);
if (acpi_table_compute_checksum(header, header->length)) {
@@ -537,9 +544,9 @@ acpi_table_get_sdt (
sdt_entry[i].size = header->length;
for (id = 0; id < ACPI_TABLE_COUNT; id++) {
- if (!strncmp((char *) &header->signature,
- acpi_table_signatures[id],
- sizeof(header->signature))) {
+ if (!strncmp((char *)&header->signature,
+ acpi_table_signatures[id],
+ sizeof(header->signature))) {
sdt_entry[i].id = id;
}
}
@@ -551,7 +558,7 @@ acpi_table_get_sdt (
* against. Unfortunately, we don't know the phys_addr, so just
* print 0. Maybe no one will notice.
*/
- if(!acpi_get_table_header_early(ACPI_DSDT, &header))
+ if (!acpi_get_table_header_early(ACPI_DSDT, &header))
acpi_table_print(header, 0);
return 0;
@@ -566,12 +573,11 @@ acpi_table_get_sdt (
* result: sdt_entry[] is initialized
*/
-int __init
-acpi_table_init (void)
+int __init acpi_table_init(void)
{
- struct acpi_table_rsdp *rsdp = NULL;
- unsigned long rsdp_phys = 0;
- int result = 0;
+ struct acpi_table_rsdp *rsdp = NULL;
+ unsigned long rsdp_phys = 0;
+ int result = 0;
/* Locate and map the Root System Description Table (RSDP) */
@@ -581,19 +587,26 @@ acpi_table_init (void)
return -ENODEV;
}
- rsdp = (struct acpi_table_rsdp *) __va(rsdp_phys);
+ rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
+ sizeof(struct acpi_table_rsdp));
if (!rsdp) {
printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
return -ENODEV;
}
- printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
- rsdp->revision, rsdp->oem_id, (void *) rsdp_phys);
+ printk(KERN_DEBUG PREFIX
+ "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
+ rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
if (rsdp->revision < 2)
- result = acpi_table_compute_checksum(rsdp, sizeof(struct acpi_table_rsdp));
+ result =
+ acpi_table_compute_checksum(rsdp,
+ sizeof(struct acpi_table_rsdp));
else
- result = acpi_table_compute_checksum(rsdp, ((struct acpi20_table_rsdp *)rsdp)->length);
+ result =
+ acpi_table_compute_checksum(rsdp,
+ ((struct acpi20_table_rsdp *)
+ rsdp)->length);
if (result) {
printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 1bba161223..6a97fc2965 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -4,9 +4,13 @@
* Emergency console I/O for Xen and the domain-0 guest OS.
*
* Copyright (c) 2002-2004, K A Fraser.
+ *
+ * Added printf_ratelimit
+ * Taken from Linux - Author: Andi Kleen (net_ratelimit)
+ * Ported to Xen - Steven Rostedt - Red Hat
*/
-#include <stdarg.h>
+#include <xen/stdarg.h>
#include <xen/config.h>
#include <xen/version.h>
#include <xen/init.h>
@@ -26,6 +30,7 @@
#include <asm/current.h>
#include <asm/debugger.h>
#include <asm/io.h>
+#include <asm/div64.h>
/* console: comma-separated list of console outputs. */
static char opt_console[30] = OPT_CONSOLE_STR;
@@ -54,6 +59,100 @@ static int sercon_handle = -1;
static DEFINE_SPINLOCK(console_lock);
/*
+ * To control the amount of printing, thresholds are added.
+ * These thresholds correspond to the XENLOG logging levels.
+ * There's an upper and lower threshold for non-guest messages and for
+ * guest-provoked messages. This works as follows, for a given log level L:
+ *
+ * L < lower_threshold : always logged
+ * lower_threshold <= L < upper_threshold : rate-limited logging
+ * upper_threshold <= L : never logged
+ *
+ * Note, in the above algorithm, to disable rate limiting simply make
+ * the lower threshold equal to the upper.
+ */
+#define XENLOG_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
+#define XENLOG_LOWER_THRESHOLD 2 /* Always print ERR and WARNING */
+#define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG */
+#define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING */
+/*
+ * The XENLOG_DEFAULT is the default given to printks that
+ * do not have any print level associated with them.
+ */
+#define XENLOG_DEFAULT 1 /* XENLOG_WARNING */
+#define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */
+
+static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;
+static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;
+static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;
+static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;
+
+static void parse_loglvl(char *s);
+static void parse_guest_loglvl(char *s);
+
+/*
+ * <lvl> := none|error|warning|info|debug|all
+ * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>]
+ * <lvl_print_always>: log level which is always printed
+ * <lvl_print_rlimit>: log level which is rate-limit printed
+ * Similar definitions for guest_loglvl, but applies to guest tracing.
+ * Defaults: loglvl=warning ; guest_loglvl=none/warning
+ */
+custom_param("loglvl", parse_loglvl);
+custom_param("guest_loglvl", parse_guest_loglvl);
+
+static atomic_t print_everything = ATOMIC_INIT(1);
+
+#define ___parse_loglvl(s, ps, lvlstr, lvlnum) \
+ if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) { \
+ *(ps) = (s) + strlen(lvlstr); \
+ return (lvlnum); \
+ }
+
+static int __parse_loglvl(char *s, char **ps)
+{
+ ___parse_loglvl(s, ps, "none", 0);
+ ___parse_loglvl(s, ps, "error", 1);
+ ___parse_loglvl(s, ps, "warning", 2);
+ ___parse_loglvl(s, ps, "info", 3);
+ ___parse_loglvl(s, ps, "debug", 4);
+ ___parse_loglvl(s, ps, "all", 4);
+ return 2; /* sane fallback */
+}
+
+static void _parse_loglvl(char *s, int *lower, int *upper)
+{
+ *lower = *upper = __parse_loglvl(s, &s);
+ if ( *s == '/' )
+ *upper = __parse_loglvl(s+1, &s);
+ if ( *upper < *lower )
+ *upper = *lower;
+}
+
+static void parse_loglvl(char *s)
+{
+ _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);
+}
+
+static void parse_guest_loglvl(char *s)
+{
+ _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);
+}
+
+static char *loglvl_str(int lvl)
+{
+ switch ( lvl )
+ {
+ case 0: return "Nothing";
+ case 1: return "Errors";
+ case 2: return "Errors and warnings";
+ case 3: return "Errors, warnings and info";
+ case 4: return "All";
+ }
+ return "???";
+}
+
+/*
* ********************************************************
* *************** ACCESS TO CONSOLE RING *****************
* ********************************************************
@@ -116,6 +215,34 @@ long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
static char serial_rx_ring[SERIAL_RX_SIZE];
static unsigned int serial_rx_cons, serial_rx_prod;
+static void (*serial_steal_fn)(const char *);
+
+int console_steal(int handle, void (*fn)(const char *))
+{
+ if ( (handle == -1) || (handle != sercon_handle) )
+ return 0;
+
+ if ( serial_steal_fn == NULL )
+ return -EBUSY;
+
+ serial_steal_fn = fn;
+ return 1;
+}
+
+void console_giveback(int id)
+{
+ if ( id == 1 )
+ serial_steal_fn = NULL;
+}
+
+static void sercon_puts(const char *s)
+{
+ if ( serial_steal_fn != NULL )
+ (*serial_steal_fn)(s);
+ else
+ serial_puts(sercon_handle, s);
+}
+
/* CTRL-<switch_char> switches input direction between Xen and DOM0. */
#define SWITCH_CODE (opt_conswitch[0]-'a'+1)
static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
@@ -191,7 +318,7 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count)
return -EFAULT;
kbuf[kcount] = '\0';
- serial_puts(sercon_handle, kbuf);
+ sercon_puts(kbuf);
for ( kptr = kbuf; *kptr != '\0'; kptr++ )
vga_putchar(*kptr);
@@ -253,11 +380,11 @@ long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer)
* *****************************************************
*/
-static inline void __putstr(const char *str)
+static void __putstr(const char *str)
{
int c;
- serial_puts(sercon_handle, str);
+ sercon_puts(str);
while ( (c = *str++) != '\0' )
{
@@ -266,29 +393,70 @@ static inline void __putstr(const char *str)
}
}
-void printf(const char *fmt, ...)
+static int printk_prefix_check(char *p, char **pp)
+{
+ int loglvl = -1;
+ int upper_thresh = xenlog_upper_thresh;
+ int lower_thresh = xenlog_lower_thresh;
+
+ while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )
+ {
+ switch ( p[1] )
+ {
+ case 'G':
+ upper_thresh = xenlog_guest_upper_thresh;
+ lower_thresh = xenlog_guest_lower_thresh;
+ if ( loglvl == -1 )
+ loglvl = XENLOG_GUEST_DEFAULT;
+ break;
+ case '0' ... '3':
+ loglvl = p[1] - '0';
+ break;
+ }
+ p += 3;
+ }
+
+ if ( loglvl == -1 )
+ loglvl = XENLOG_DEFAULT;
+
+ *pp = p;
+
+ return ((atomic_read(&print_everything) != 0) ||
+ (loglvl < lower_thresh) ||
+ ((loglvl < upper_thresh) && printk_ratelimit()));
+}
+
+void printk(const char *fmt, ...)
{
static char buf[1024];
- static int start_of_line = 1;
+ static int start_of_line = 1, do_print;
va_list args;
char *p, *q;
unsigned long flags;
- spin_lock_irqsave(&console_lock, flags);
+ /* console_lock can be acquired recursively from __printk_ratelimit(). */
+ local_irq_save(flags);
+ spin_lock_recursive(&console_lock);
va_start(args, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
p = buf;
+
while ( (q = strchr(p, '\n')) != NULL )
{
*q = '\0';
if ( start_of_line )
- __putstr(printk_prefix);
- __putstr(p);
- __putstr("\n");
+ do_print = printk_prefix_check(p, &p);
+ if ( do_print )
+ {
+ if ( start_of_line )
+ __putstr(printk_prefix);
+ __putstr(p);
+ __putstr("\n");
+ }
start_of_line = 1;
p = q + 1;
}
@@ -296,12 +464,18 @@ void printf(const char *fmt, ...)
if ( *p != '\0' )
{
if ( start_of_line )
- __putstr(printk_prefix);
- __putstr(p);
+ do_print = printk_prefix_check(p, &p);
+ if ( do_print )
+ {
+ if ( start_of_line )
+ __putstr(printk_prefix);
+ __putstr(p);
+ }
start_of_line = 0;
}
- spin_unlock_irqrestore(&console_lock, flags);
+ spin_unlock_recursive(&console_lock);
+ local_irq_restore(flags);
}
void set_printk_prefix(const char *prefix)
@@ -349,10 +523,18 @@ void console_endboot(void)
{
int i, j;
+ printk("Std. Loglevel: %s", loglvl_str(xenlog_lower_thresh));
+ if ( xenlog_upper_thresh != xenlog_lower_thresh )
+ printk(" (Rate-limited: %s)", loglvl_str(xenlog_upper_thresh));
+ printk("\nGuest Loglevel: %s", loglvl_str(xenlog_guest_lower_thresh));
+ if ( xenlog_guest_upper_thresh != xenlog_guest_lower_thresh )
+ printk(" (Rate-limited: %s)", loglvl_str(xenlog_guest_upper_thresh));
+ printk("\n");
+
if ( opt_sync_console )
{
printk("**********************************************\n");
- printk("******* WARNING: CONSOLE OUTPUT IS SYCHRONOUS\n");
+ printk("******* WARNING: CONSOLE OUTPUT IS SYNCHRONOUS\n");
printk("******* This option is intended to aid debugging "
"of Xen by ensuring\n");
printk("******* that all output is synchronously delivered "
@@ -386,11 +568,24 @@ void console_endboot(void)
/* Serial input is directed to DOM0 by default. */
switch_serial_input();
+
+ /* Now we implement the logging thresholds. */
+ console_end_log_everything();
+}
+
+void console_start_log_everything(void)
+{
+ atomic_inc(&print_everything);
+}
+
+void console_end_log_everything(void)
+{
+ atomic_dec(&print_everything);
}
void console_force_unlock(void)
{
- console_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&console_lock);
serial_force_unlock(sercon_handle);
console_start_sync();
}
@@ -402,12 +597,14 @@ void console_force_lock(void)
void console_start_sync(void)
{
+ console_start_log_everything();
serial_start_sync(sercon_handle);
}
void console_end_sync(void)
{
serial_end_sync(sercon_handle);
+ console_end_log_everything();
}
void console_putc(char c)
@@ -420,6 +617,66 @@ int console_getc(void)
return serial_getc(sercon_handle);
}
+/*
+ * printk rate limiting, lifted from Linux.
+ *
+ * This enforces a rate limit: not more than one kernel message
+ * every printk_ratelimit_ms (millisecs).
+ */
+int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
+{
+ static DEFINE_SPINLOCK(ratelimit_lock);
+ static unsigned long toks = 10 * 5 * 1000;
+ static unsigned long last_msg;
+ static int missed;
+ unsigned long flags;
+ unsigned long long now = NOW(); /* ns */
+ unsigned long ms;
+
+ do_div(now, 1000000);
+ ms = (unsigned long)now;
+
+ spin_lock_irqsave(&ratelimit_lock, flags);
+ toks += ms - last_msg;
+ last_msg = ms;
+ if ( toks > (ratelimit_burst * ratelimit_ms))
+ toks = ratelimit_burst * ratelimit_ms;
+ if ( toks >= ratelimit_ms )
+ {
+ int lost = missed;
+ missed = 0;
+ toks -= ratelimit_ms;
+ spin_unlock(&ratelimit_lock);
+ if ( lost )
+ {
+ char lost_str[8];
+ snprintf(lost_str, sizeof(lost_str), "%d", lost);
+ /* console_lock may already be acquired by printk(). */
+ spin_lock_recursive(&console_lock);
+ __putstr(printk_prefix);
+ __putstr("printk: ");
+ __putstr(lost_str);
+ __putstr(" messages suppressed.\n");
+ spin_unlock_recursive(&console_lock);
+ }
+ local_irq_restore(flags);
+ return 1;
+ }
+ missed++;
+ spin_unlock_irqrestore(&ratelimit_lock, flags);
+ return 0;
+}
+
+/* minimum time in ms between messages */
+int printk_ratelimit_ms = 5 * 1000;
+
+/* number of messages we send before ratelimiting */
+int printk_ratelimit_burst = 10;
+
+int printk_ratelimit(void)
+{
+ return __printk_ratelimit(printk_ratelimit_ms, printk_ratelimit_burst);
+}
/*
* **************************************************************
@@ -448,11 +705,11 @@ static void debugtrace_dump_worker(void)
/* Print oldest portion of the ring. */
ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
- serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
+ sercon_puts(&debugtrace_buf[debugtrace_prd]);
/* Print youngest portion of the ring. */
debugtrace_buf[debugtrace_prd] = '\0';
- serial_puts(sercon_handle, &debugtrace_buf[0]);
+ sercon_puts(&debugtrace_buf[0]);
memset(debugtrace_buf, '\0', debugtrace_bytes);
@@ -466,9 +723,10 @@ static void debugtrace_toggle(void)
watchdog_disable();
spin_lock_irqsave(&debugtrace_lock, flags);
- // dump the buffer *before* toggling, in case the act of dumping the
- // buffer itself causes more printk's...
- //
+ /*
+ * Dump the buffer *before* toggling, in case the act of dumping the
+ * buffer itself causes more printk() invocations.
+ */
printk("debugtrace_printk now writing to %s.\n",
!debugtrace_send_to_console ? "console": "buffer");
if ( !debugtrace_send_to_console )
@@ -622,9 +880,9 @@ void panic(const char *fmt, ...)
void __bug(char *file, int line)
{
console_start_sync();
- debugtrace_dump();
printk("BUG at %s:%d\n", file, line);
- FORCE_CRASH();
+ dump_execution_state();
+ panic("BUG at %s:%d\n", file, line);
for ( ; ; ) ;
}
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index 024de30ae9..cd909a6cef 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -295,8 +295,8 @@ void serial_force_unlock(int handle)
if ( handle == -1 )
return;
- port->rx_lock = SPIN_LOCK_UNLOCKED;
- port->tx_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&port->rx_lock);
+ spin_lock_init(&port->tx_lock);
serial_start_sync(handle);
}
diff --git a/xen/drivers/video/vga.c b/xen/drivers/video/vga.c
index 9355864ed7..08a260a2b7 100644
--- a/xen/drivers/video/vga.c
+++ b/xen/drivers/video/vga.c
@@ -680,11 +680,12 @@ int fill_console_start_info(struct dom0_vga_console_info *ci)
if ( !vgacon_enabled )
return 0;
- ci->video_type = 1;
- ci->video_width = COLUMNS;
- ci->video_height = LINES;
- ci->txt_mode = 3;
- ci->txt_points = font ? font->height : 16;
+ ci->video_type = XEN_VGATYPE_TEXT_MODE_3;
+ ci->u.text_mode_3.rows = LINES;
+ ci->u.text_mode_3.columns = COLUMNS;
+ ci->u.text_mode_3.cursor_x = 0;
+ ci->u.text_mode_3.cursor_y = LINES - 1;
+ ci->u.text_mode_3.font_height = font ? font->height : 16;
return 1;
}
diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h
index fb652bf041..4e956fca98 100644
--- a/xen/include/acm/acm_hooks.h
+++ b/xen/include/acm/acm_hooks.h
@@ -143,9 +143,9 @@ static inline int acm_pre_grant_map_ref(domid_t id)
{ return 0; }
static inline int acm_pre_grant_setup(domid_t id)
{ return 0; }
-static inline int acm_init(unsigned int *initrdidx,
- const multiboot_info_t *mbi,
- unsigned long start)
+static inline int acm_init(char *policy_start, unsigned long policy_len)
+{ return 0; }
+static inline int acm_is_policy(char *buf, unsigned long len)
{ return 0; }
static inline void acm_post_domain0_create(domid_t domid)
{ return; }
@@ -369,9 +369,11 @@ static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
return ACM_ACCESS_PERMITTED;
}
-extern int acm_init(unsigned int *initrdidx,
- const multiboot_info_t *mbi,
- unsigned long start);
+
+extern int acm_init(char *policy_start, unsigned long policy_len);
+
+/* Return true iff buffer has an acm policy magic number. */
+extern int acm_is_policy(char *buf, unsigned long len);
#endif
diff --git a/xen/include/acpi/platform/acenv.h b/xen/include/acpi/platform/acenv.h
index 5a956b549b..c259c4afa7 100644
--- a/xen/include/acpi/platform/acenv.h
+++ b/xen/include/acpi/platform/acenv.h
@@ -119,7 +119,7 @@
/*! [Begin] no source code translation */
-#if defined(__linux__)
+#if 1 /*defined(__linux__)*/ /* XEN: suitable for all supported build OSes */
#include "aclinux.h"
#elif defined(_AED_EFI)
diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h
index 65ef393345..05910e4310 100644
--- a/xen/include/asm-ia64/config.h
+++ b/xen/include/asm-ia64/config.h
@@ -26,6 +26,12 @@
#ifdef CONFIG_XEN_SMP
#define CONFIG_SMP 1
#define NR_CPUS 64
+#define CONFIG_NUMA
+#define CONFIG_ACPI_NUMA
+#define NODES_SHIFT 3
+#define MAX_NUMNODES (1 << NODES_SHIFT)
+#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
+#define MAX_PXM_DOMAINS 256
#else
#undef CONFIG_SMP
#define NR_CPUS 1
@@ -162,6 +168,8 @@ extern int smp_num_siblings;
#ifndef __ASSEMBLY__
#include "asm/types.h" // for u64
+#include "linux/linkage.h" // for asmlinkage which is used by
+ // xen/include/acpi/acpixf.h
#endif
// warning: unless search_extable is declared, the return value gets
@@ -232,7 +240,7 @@ typedef long clock_t;
extern unsigned long loops_per_jiffy;
extern char saved_command_line[];
struct screen_info { };
-#define seq_printf(a,b...) printf(b)
+#define seq_printf(a,b...) printk(b)
//#define CONFIG_BLK_DEV_INITRD // needed to reserve memory for domain0
#define CONFIG_SHADOW 1
@@ -265,13 +273,6 @@ struct screen_info { };
#endif /* __ASSEMBLY__ */
#endif /* __XEN_IA64_CONFIG_H__ */
-#ifndef __ASSEMBLY__
-#include <linux/linkage.h>
-#define FORCE_CRASH() asm("break.m 0;;");
-#else
-#define FORCE_CRASH break.m 0;;
-#endif
-
/* Allow .serialize.data/instruction in asm files.
Old as doesn't handle this. */
#define HAVE_SERIALIZE_DIRECTIVE
@@ -279,4 +280,9 @@ struct screen_info { };
/* Define CONFIG_PRIVIFY to support privified OS (deprecated). */
#undef CONFIG_PRIVIFY
+/* Necessary for hvm_vioapic.c */
+#define vcpu_vlapic(vcpu) (&(vcpu)->arch.arch_vmx.vlapic)
+#define vlapic_vcpu(vpic) (container_of((vpic), struct vcpu, \
+ arch.arch_vmx.vlapic))
+
#endif /* _IA64_CONFIG_H_ */
diff --git a/xen/include/asm-ia64/debugger.h b/xen/include/asm-ia64/debugger.h
index e320ff68cc..104cea9bfc 100644
--- a/xen/include/asm-ia64/debugger.h
+++ b/xen/include/asm-ia64/debugger.h
@@ -23,7 +23,6 @@
#define __ASM_DEBUGGER_H__
// this number is an arbitary number which is not used for any other purpose
-// __builtin_trap(), FORCE_CRASH() 0x0
// ski 0x80001, 0x80002
// kdb 0x80100, 0x80101
// kprobe 0x80200, jprobe 0x80300
diff --git a/xen/include/asm-ia64/dom_fw.h b/xen/include/asm-ia64/dom_fw.h
index 841ea9e200..fcf2cb5739 100644
--- a/xen/include/asm-ia64/dom_fw.h
+++ b/xen/include/asm-ia64/dom_fw.h
@@ -39,6 +39,13 @@
#define FW_HYPERCALL_NUM_MASK_HIGH ~0xffUL
#define FW_HYPERCALL_NUM_MASK_LOW 0xffUL
+/* Xen hypercalls are 0-63. */
+#define FW_HYPERCALL_XEN 0x0000UL
+
+/* Define some faster and lighter hypercalls.
+ See definitions in arch-ia64.h */
+#define FW_HYPERCALL_XEN_FAST 0x0200UL
+
/*
* PAL can be called in physical or virtual mode simply by
* branching to pal_entry_point, which is found in one of the
@@ -173,7 +180,7 @@
#define EFI_MEMDESC_VERSION 1
-extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64);
+extern struct ia64_pal_retval xen_pal_emulator(u64, u64, u64, u64);
extern struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7);
extern struct ia64_pal_retval pal_emulator_static (unsigned long);
extern efi_status_t efi_emulator (struct pt_regs *regs, unsigned long *fault);
diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h
index b93351c63c..cfe7c5e9a3 100644
--- a/xen/include/asm-ia64/domain.h
+++ b/xen/include/asm-ia64/domain.h
@@ -13,28 +13,10 @@
#include <asm/fpswa.h>
#include <xen/rangeset.h>
-struct p2m_entry {
- volatile pte_t* pte;
- pte_t used;
-};
-
-static inline void
-p2m_entry_set(struct p2m_entry* entry, volatile pte_t* pte, pte_t used)
-{
- entry->pte = pte;
- entry->used = used;
-}
-
-static inline int
-p2m_entry_retry(struct p2m_entry* entry)
-{
- //XXX see lookup_domain_pte().
- // NULL is set for invalid gpaddr for the time being.
- if (entry->pte == NULL)
- return 0;
-
- return (pte_val(*entry->pte) != pte_val(entry->used));
-}
+struct p2m_entry;
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+struct tlb_track;
+#endif
extern void domain_relinquish_resources(struct domain *);
struct vcpu;
@@ -67,6 +49,9 @@ struct mm_struct {
struct last_vcpu {
#define INVALID_VCPU_ID INT_MAX
int vcpu_id;
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+ u32 tlbflush_timestamp;
+#endif
} ____cacheline_aligned_in_smp;
/* These are data in domain memory for SAL emulator. */
@@ -87,6 +72,9 @@ struct arch_domain {
unsigned long flags;
struct {
unsigned int is_vti : 1;
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ unsigned int has_pervcpu_vhpt : 1;
+#endif
};
};
@@ -137,16 +125,21 @@ struct arch_domain {
struct last_vcpu last_vcpu[NR_CPUS];
struct arch_vmx_domain arch_vmx; /* Virtual Machine Extensions */
+
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+ struct tlb_track* tlb_track;
+#endif
};
#define INT_ENABLE_OFFSET(v) \
(sizeof(vcpu_info_t) * (v)->vcpu_id + \
offsetof(vcpu_info_t, evtchn_upcall_mask))
-struct hypercall_param {
- unsigned long va;
- unsigned long pa1;
- unsigned long pa2;
-};
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+#define HAS_PERVCPU_VHPT(d) ((d)->arch.has_pervcpu_vhpt)
+#else
+#define HAS_PERVCPU_VHPT(d) (0)
+#endif
+
struct arch_vcpu {
/* Save the state of vcpu.
@@ -192,15 +185,21 @@ struct arch_vcpu {
char irq_new_condition; // vpsr.i/vtpr change, check for pending VHPI
char hypercall_continuation;
- struct hypercall_param hypercall_param; // used to remap a hypercall param
-
//for phycial emulation
- unsigned long old_rsc;
int mode_flags;
fpswa_ret_t fpswa_ret; /* save return values of FPSWA emulation */
struct timer hlt_timer;
struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ PTA pta;
+ unsigned long vhpt_maddr;
+ struct page_info* vhpt_page;
+ unsigned long vhpt_entries;
+#endif
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+ u32 tlbflush_timestamp;
+#endif
#define INVALID_PROCESSOR INT_MAX
int last_processor;
};
diff --git a/xen/include/asm-ia64/flushtlb.h b/xen/include/asm-ia64/flushtlb.h
new file mode 100644
index 0000000000..0966d72711
--- /dev/null
+++ b/xen/include/asm-ia64/flushtlb.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * flushtlb.c
+ * based on x86 flushtlb.h
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ASM_FLUSHTLB_H__
+#define __ASM_FLUSHTLB_H__
+
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+
+#include <xen/percpu.h>
+
+extern volatile u32 tlbflush_clock;
+#define tlbflush_current_time() tlbflush_clock
+
+u32 tlbflush_clock_inc_and_return(void);
+
+static inline void
+tlbflush_update_time(volatile u32* time, u32 timestamp)
+{
+ /*
+ * this should be ld4.rel + st4.acq. but only have release semantcis.
+ * so this function can't be considered as memory barrier.
+ */
+ *time = timestamp;
+}
+
+/*
+ * taken from x86's NEED_FLUSH()
+ * obj_stamp: mTLB time stamp, per pcpu VHPT stamp, per vcpu VHPT stamp.
+ */
+static inline int
+NEED_FLUSH(u32 obj_stamp, u32 lastuse_stamp)
+{
+ u32 curr_time = tlbflush_current_time();
+ /*
+ * Two cases:
+ * 1. During a wrap, the clock ticks over to 0 while CPUs catch up. For
+ * safety during this period, we force a flush if @curr_time == 0.
+ * 2. Otherwise, we look to see if @cpu_stamp <= @lastuse_stamp.
+ * To detect false positives because @cpu_stamp has wrapped, we
+ * also check @curr_time. If less than @lastuse_stamp we definitely
+ * wrapped, so there's no need for a flush (one is forced every wrap).
+ */
+ return ((curr_time == 0) ||
+ ((obj_stamp <= lastuse_stamp) && (lastuse_stamp <= curr_time)));
+}
+
+DECLARE_PER_CPU(volatile u32, tlbflush_time);
+DECLARE_PER_CPU(volatile u32, vhpt_tlbflush_timestamp);
+
+#else
+
+#define tlbflush_current_time() (0)
+#define tlbflush_clock_inc_and_return() (0)
+#define tlbflush_update_time(time, timestamp) do {(void)timestamp;} while (0)
+#define NEED_FLUSH(obj_stamp, lastuse_stamp) (1)
+
+#endif /* CONFIG_XEN_IA64_TLBFLUSH_CLOCK */
+
+#endif /* __ASM_FLUSHTLB_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-ia64/guest_access.h b/xen/include/asm-ia64/guest_access.h
index 6605578eb9..e0522d4157 100644
--- a/xen/include/asm-ia64/guest_access.h
+++ b/xen/include/asm-ia64/guest_access.h
@@ -1,91 +1,107 @@
-/******************************************************************************
- * guest_access.h
- *
- * Copyright (c) 2006, K A Fraser
+/*
+ * 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 (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ * Tristan Gingold <tristan.gingold@bull.net>
*/
-#ifndef __ASM_IA64_GUEST_ACCESS_H__
-#define __ASM_IA64_GUEST_ACCESS_H__
+#ifndef __ASM_GUEST_ACCESS_H__
+#define __ASM_GUEST_ACCESS_H__
+
+extern unsigned long xencomm_copy_to_guest(void *to, const void *from,
+ unsigned int len, unsigned int skip);
+extern unsigned long xencomm_copy_from_guest(void *to, const void *from,
+ unsigned int len, unsigned int skip);
+extern void *xencomm_add_offset(void *handle, unsigned int bytes);
+extern int xencomm_handle_is_null(void *ptr);
-#include <asm/uaccess.h>
/* Is the guest handle a NULL reference? */
-#define guest_handle_is_null(hnd) ((hnd).p == NULL)
+#define guest_handle_is_null(hnd) \
+ ((hnd).p == NULL || xencomm_handle_is_null((hnd).p))
/* Offset the given guest handle into the array it refers to. */
-#define guest_handle_add_offset(hnd, nr) ((hnd).p += (nr))
+#define guest_handle_add_offset(hnd, nr) ({ \
+ const typeof((hnd).p) _ptr = (hnd).p; \
+ (hnd).p = xencomm_add_offset(_ptr, nr * sizeof(*_ptr)); \
+})
/* Cast a guest handle to the specified type of handle. */
-#define guest_handle_cast(hnd, type) ({ \
- type *_x = (hnd).p; \
- (XEN_GUEST_HANDLE(type)) { _x }; \
+#define guest_handle_cast(hnd, type) ({ \
+ type *_x = (hnd).p; \
+ XEN_GUEST_HANDLE(type) _y; \
+ set_xen_guest_handle(_y, _x); \
+ _y; \
})
-#define guest_handle_from_ptr(ptr, type) ((XEN_GUEST_HANDLE(type)) { (type *)ptr })
-/*
- * Copy an array of objects to guest context via a guest handle,
- * specifying an offset into the guest array.
- */
-#define copy_to_guest_offset(hnd, off, ptr, nr) ({ \
- const typeof(ptr) _x = (hnd).p; \
- const typeof(ptr) _y = (ptr); \
- copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
-})
+/* Since we run in real mode, we can safely access all addresses. That also
+ * means our __routines are identical to our "normal" routines. */
+#define guest_handle_okay(hnd, nr) 1
/*
- * Copy an array of objects from guest context via a guest handle,
- * specifying an offset into the guest array.
+ * Copy an array of objects to guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
*/
-#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \
- const typeof(ptr) _x = (hnd).p; \
- const typeof(ptr) _y = (ptr); \
- copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
-})
+#define copy_to_guest_offset(hnd, idx, ptr, nr) \
+ __copy_to_guest_offset(hnd, idx, ptr, nr)
/* Copy sub-field of a structure to guest context via a guest handle. */
-#define copy_field_to_guest(hnd, ptr, field) ({ \
- const typeof(&(ptr)->field) _x = &(hnd).p->field; \
- const typeof(&(ptr)->field) _y = &(ptr)->field; \
- copy_to_user(_x, _y, sizeof(*_x)); \
-})
-
-/* Copy sub-field of a structure from guest context via a guest handle. */
-#define copy_field_from_guest(ptr, hnd, field) ({ \
- const typeof(&(ptr)->field) _x = &(hnd).p->field; \
- const typeof(&(ptr)->field) _y = &(ptr)->field; \
- copy_from_user(_y, _x, sizeof(*_x)); \
-})
+#define copy_field_to_guest(hnd, ptr, field) \
+ __copy_field_to_guest(hnd, ptr, field)
/*
- * Pre-validate a guest handle.
- * Allows use of faster __copy_* functions.
+ * Copy an array of objects from guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
*/
-#define guest_handle_okay(hnd, nr) \
- array_access_ok((hnd).p, (nr), sizeof(*(hnd).p))
+#define copy_from_guest_offset(ptr, hnd, idx, nr) \
+ __copy_from_guest_offset(ptr, hnd, idx, nr)
-#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \
- const typeof(ptr) _x = (hnd).p; \
- const typeof(ptr) _y = (ptr); \
- __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
+/* Copy sub-field of a structure from guest context via a guest handle. */
+#define copy_field_from_guest(ptr, hnd, field) \
+ __copy_field_from_guest(ptr, hnd, field)
+
+#define __copy_to_guest_offset(hnd, idx, ptr, nr) ({ \
+ const typeof(ptr) _d = (hnd).p; \
+ const typeof(ptr) _s = (ptr); \
+ xencomm_copy_to_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \
})
-#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \
- const typeof(ptr) _x = (hnd).p; \
- const typeof(ptr) _y = (ptr); \
- __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
+#define __copy_field_to_guest(hnd, ptr, field) ({ \
+ const int _off = offsetof(typeof(*ptr), field); \
+ const typeof(ptr) _d = (hnd).p; \
+ const typeof(&(ptr)->field) _s = &(ptr)->field; \
+ xencomm_copy_to_guest(_d, _s, sizeof(*_s), _off); \
})
-#define __copy_field_to_guest(hnd, ptr, field) ({ \
- const typeof(&(ptr)->field) _x = &(hnd).p->field; \
- const typeof(&(ptr)->field) _y = &(ptr)->field; \
- __copy_to_user(_x, _y, sizeof(*_x)); \
+#define __copy_from_guest_offset(ptr, hnd, idx, nr) ({ \
+ const typeof(ptr) _s = (hnd).p; \
+ const typeof(ptr) _d = (ptr); \
+ xencomm_copy_from_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \
})
-#define __copy_field_from_guest(ptr, hnd, field) ({ \
- const typeof(&(ptr)->field) _x = &(hnd).p->field; \
- const typeof(&(ptr)->field) _y = &(ptr)->field; \
- __copy_from_user(_y, _x, sizeof(*_x)); \
+#define __copy_field_from_guest(ptr, hnd, field) ({ \
+ const int _off = offsetof(typeof(*ptr), field); \
+ const typeof(ptr) _s = (hnd).p; \
+ const typeof(&(ptr)->field) _d = &(ptr)->field; \
+ xencomm_copy_from_guest(_d, _s, sizeof(*_d), _off); \
})
-#endif /* __ASM_IA64_GUEST_ACCESS_H__ */
+/* Internal use only: returns 0 in case of bad address. */
+extern unsigned long xencomm_paddr_to_maddr(unsigned long paddr);
+
+#endif /* __ASM_GUEST_ACCESS_H__ */
diff --git a/xen/include/asm-ia64/hvm/vlapic.h b/xen/include/asm-ia64/hvm/vlapic.h
new file mode 100644
index 0000000000..198a595b82
--- /dev/null
+++ b/xen/include/asm-ia64/hvm/vlapic.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_IA64_HVM_VLAPIC_H__
+#define __ASM_IA64_HVM_VLAPIC_H__
+
+int vlapic_match_logical_addr(struct vlapic *vlapic, uint16_t dest);
+
+#endif /* __ASM_IA64_HVM_VLAPIC_H__ */
diff --git a/xen/include/asm-ia64/ia64_int.h b/xen/include/asm-ia64/ia64_int.h
index 0bef5b4a1b..711078104b 100644
--- a/xen/include/asm-ia64/ia64_int.h
+++ b/xen/include/asm-ia64/ia64_int.h
@@ -36,7 +36,9 @@
#define IA64_NO_FAULT 0x0000
#define IA64_FAULT 0x0001
#define IA64_RFI_IN_PROGRESS 0x0002
-#define IA64_RETRY 0x0003
+// To avoid conflicting with return value of handle_fpu_swa()
+// set IA64_RETRY to -0x000f
+#define IA64_RETRY (-0x000f)
#define IA64_FORCED_IFA 0x0004
#define IA64_USE_TLB 0x0005
#define IA64_ILLOP_FAULT (IA64_GENEX_VECTOR | 0x00)
diff --git a/xen/include/asm-ia64/linux-null/asm/mmzone.h b/xen/include/asm-ia64/linux-null/asm/mmzone.h
new file mode 100644
index 0000000000..81447b2f74
--- /dev/null
+++ b/xen/include/asm-ia64/linux-null/asm/mmzone.h
@@ -0,0 +1 @@
+/* Empty file. */
diff --git a/xen/include/asm-ia64/linux-xen/asm/README.origin b/xen/include/asm-ia64/linux-xen/asm/README.origin
index 290ad56a28..3f2a03f704 100644
--- a/xen/include/asm-ia64/linux-xen/asm/README.origin
+++ b/xen/include/asm-ia64/linux-xen/asm/README.origin
@@ -5,7 +5,9 @@
# (e.g. with #ifdef XEN or XEN in a comment) so that they can be
# easily updated to future versions of the corresponding Linux files.
+acpi.h -> linux/include/asm-ia64/acpi.h
asmmacro.h -> linux/include/asm-ia64/asmmacro.h
+atomic.h -> linux/include/asm-ia64/atomic.h
cache.h -> linux/include/asm-ia64/cache.h
gcc_intrin.h -> linux/include/asm-ia64/gcc_intrin.h
ia64regs.h -> linux/include/asm-ia64/ia64regs.h
@@ -13,6 +15,7 @@ io.h -> linux/include/asm-ia64/io.h
kregs.h -> linux/include/asm-ia64/kregs.h
mca_asm.h -> linux/include/asm-ia64/mca_asm.h
meminit.h -> linux/include/asm-ia64/meminit.h
+numa.h -> linux/include/asm-ia64/numa.h
page.h -> linux/include/asm-ia64/page.h
pal.h -> linux/include/asm-ia64/pal.h
pgalloc.h -> linux/include/asm-ia64/pgalloc.h
diff --git a/xen/include/asm-ia64/linux/asm/acpi.h b/xen/include/asm-ia64/linux-xen/asm/acpi.h
index 4c06d45513..bfff8bc804 100644
--- a/xen/include/asm-ia64/linux/asm/acpi.h
+++ b/xen/include/asm-ia64/linux-xen/asm/acpi.h
@@ -108,8 +108,10 @@ extern void set_cpei_target_cpu(unsigned int cpu);
extern unsigned int get_cpei_target_cpu(void);
#ifdef CONFIG_ACPI_NUMA
+#ifndef XEN
/* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
#define MAX_PXM_DOMAINS (256)
+#endif
extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
#endif
diff --git a/xen/include/asm-ia64/linux/asm/atomic.h b/xen/include/asm-ia64/linux-xen/asm/atomic.h
index 874a6f890e..f306ecd5b9 100644
--- a/xen/include/asm-ia64/linux/asm/atomic.h
+++ b/xen/include/asm-ia64/linux-xen/asm/atomic.h
@@ -23,8 +23,13 @@
typedef struct { volatile __s32 counter; } atomic_t;
typedef struct { volatile __s64 counter; } atomic64_t;
+#ifndef XEN
#define ATOMIC_INIT(i) ((atomic_t) { (i) })
#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
+#else
+#define ATOMIC_INIT(i) { (i) }
+#define ATOMIC64_INIT(i) { (i) }
+#endif
#define atomic_read(v) ((v)->counter)
#define atomic64_read(v) ((v)->counter)
diff --git a/xen/include/asm-ia64/linux-xen/asm/cache.h b/xen/include/asm-ia64/linux-xen/asm/cache.h
index 0db88a7044..542d2e23e4 100644
--- a/xen/include/asm-ia64/linux-xen/asm/cache.h
+++ b/xen/include/asm-ia64/linux-xen/asm/cache.h
@@ -32,6 +32,6 @@
#endif
#endif
-#define __read_mostly
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
#endif /* _ASM_IA64_CACHE_H */
diff --git a/xen/include/asm-ia64/linux/asm/numa.h b/xen/include/asm-ia64/linux-xen/asm/numa.h
index 3ae128fe08..77b444c72c 100644
--- a/xen/include/asm-ia64/linux/asm/numa.h
+++ b/xen/include/asm-ia64/linux-xen/asm/numa.h
@@ -18,7 +18,9 @@
#include <linux/cache.h>
#include <linux/cpumask.h>
#include <linux/numa.h>
+#ifndef XEN /* dependency loop when this is included */
#include <linux/smp.h>
+#endif
#include <linux/threads.h>
#include <asm/mmzone.h>
@@ -71,4 +73,8 @@ extern int paddr_to_nid(unsigned long paddr);
#endif /* CONFIG_NUMA */
+#ifdef XEN
+#define phys_to_nid(paddr) paddr_to_nid(paddr)
+#endif
+
#endif /* _ASM_IA64_NUMA_H */
diff --git a/xen/include/asm-ia64/linux-xen/asm/pgtable.h b/xen/include/asm-ia64/linux-xen/asm/pgtable.h
index 659c2a933f..a859a8b437 100644
--- a/xen/include/asm-ia64/linux-xen/asm/pgtable.h
+++ b/xen/include/asm-ia64/linux-xen/asm/pgtable.h
@@ -68,6 +68,42 @@
#ifdef XEN
#define _PAGE_VIRT_D (__IA64_UL(1) << 53) /* Virtual dirty bit */
#define _PAGE_PROTNONE 0
+
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+#define _PAGE_TLB_TRACKING_BIT 54
+#define _PAGE_TLB_INSERTED_BIT 55
+#define _PAGE_TLB_INSERTED_MANY_BIT 56
+
+#define _PAGE_TLB_TRACKING (1UL << _PAGE_TLB_TRACKING_BIT)
+#define _PAGE_TLB_INSERTED (1UL << _PAGE_TLB_INSERTED_BIT)
+#define _PAGE_TLB_INSERTED_MANY (1UL << _PAGE_TLB_INSERTED_MANY_BIT)
+#define _PAGE_TLB_TRACK_MASK (_PAGE_TLB_TRACKING | \
+ _PAGE_TLB_INSERTED | \
+ _PAGE_TLB_INSERTED_MANY)
+
+#define pte_tlb_tracking(pte) \
+ ((pte_val(pte) & _PAGE_TLB_TRACKING) != 0)
+#define pte_tlb_inserted(pte) \
+ ((pte_val(pte) & _PAGE_TLB_INSERTED) != 0)
+#define pte_tlb_inserted_many(pte) \
+ ((pte_val(pte) & _PAGE_TLB_INSERTED_MANY) != 0)
+#endif // CONFIG_XEN_IA64_TLB_TRACK
+
+#define _PAGE_PGC_ALLOCATED_BIT 59 /* _PGC_allocated */
+#define _PAGE_PGC_ALLOCATED (__IA64_UL(1) << _PAGE_PGC_ALLOCATED_BIT)
+/* domVTI */
+#define GPFN_MEM (0UL << 60) /* Guest pfn is normal mem */
+#define GPFN_FRAME_BUFFER (1UL << 60) /* VGA framebuffer */
+#define GPFN_LOW_MMIO (2UL << 60) /* Low MMIO range */
+#define GPFN_PIB (3UL << 60) /* PIB base */
+#define GPFN_IOSAPIC (4UL << 60) /* IOSAPIC base */
+#define GPFN_LEGACY_IO (5UL << 60) /* Legacy I/O base */
+#define GPFN_GFW (6UL << 60) /* Guest Firmware */
+#define GPFN_HIGH_MMIO (7UL << 60) /* High MMIO range */
+
+#define GPFN_IO_MASK (7UL << 60) /* Guest pfn is I/O type */
+#define GPFN_INV_MASK (1UL << 63) /* Guest pfn is invalid */
+
#else
#define _PAGE_PROTNONE (__IA64_UL(1) << 63)
#endif
@@ -299,6 +335,7 @@ set_pte_rel(volatile pte_t* ptep, pte_t pteval)
#define pte_young(pte) ((pte_val(pte) & _PAGE_A) != 0)
#define pte_file(pte) ((pte_val(pte) & _PAGE_FILE) != 0)
#ifdef XEN
+#define pte_pgc_allocated(pte) ((pte_val(pte) & _PAGE_PGC_ALLOCATED) != 0)
#define pte_mem(pte) \
(!(pte_val(pte) & (GPFN_IO_MASK | GPFN_INV_MASK)) && !pte_none(pte))
#endif
diff --git a/xen/include/asm-ia64/linux-xen/asm/processor.h b/xen/include/asm-ia64/linux-xen/asm/processor.h
index 65f65538bc..976c0960d6 100644
--- a/xen/include/asm-ia64/linux-xen/asm/processor.h
+++ b/xen/include/asm-ia64/linux-xen/asm/processor.h
@@ -89,6 +89,7 @@
#ifdef XEN
#include <asm/xenprocessor.h>
+#include <xen/bitops.h>
#else
/* like above but expressed as bitfields for more efficient access: */
struct ia64_psr {
@@ -571,6 +572,23 @@ ia64_eoi (void)
#define cpu_relax() ia64_hint(ia64_hint_pause)
+static inline int
+ia64_get_irr(unsigned int vector)
+{
+ unsigned int reg = vector / 64;
+ unsigned int bit = vector % 64;
+ u64 irr;
+
+ switch (reg) {
+ case 0: irr = ia64_getreg(_IA64_REG_CR_IRR0); break;
+ case 1: irr = ia64_getreg(_IA64_REG_CR_IRR1); break;
+ case 2: irr = ia64_getreg(_IA64_REG_CR_IRR2); break;
+ case 3: irr = ia64_getreg(_IA64_REG_CR_IRR3); break;
+ }
+
+ return test_bit(bit, &irr);
+}
+
static inline void
ia64_set_lrr0 (unsigned long val)
{
diff --git a/xen/include/asm-ia64/linux-xen/asm/spinlock.h b/xen/include/asm-ia64/linux-xen/asm/spinlock.h
index 1c2034c80d..129fbf5156 100644
--- a/xen/include/asm-ia64/linux-xen/asm/spinlock.h
+++ b/xen/include/asm-ia64/linux-xen/asm/spinlock.h
@@ -33,7 +33,7 @@ typedef struct {
#endif
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#define SPIN_LOCK_UNLOCKED /*(spinlock_t)*/ { 0 }
#define spin_lock_init(x) ((x)->lock = 0)
#ifdef ASM_SUPPORTED
@@ -136,9 +136,9 @@ typedef struct {
unsigned int break_lock;
#endif
} rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#define RW_LOCK_UNLOCKED /*(rwlock_t)*/ { 0, 0 }
-#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_init(x) do { *(x) = (rwlock_t) RW_LOCK_UNLOCKED; } while(0)
#define read_can_lock(rw) (*(volatile int *)(rw) >= 0)
#define write_can_lock(rw) (*(volatile int *)(rw) == 0)
diff --git a/xen/include/asm-ia64/linux-xen/asm/system.h b/xen/include/asm-ia64/linux-xen/asm/system.h
index c12beafd3a..9f98e2a743 100644
--- a/xen/include/asm-ia64/linux-xen/asm/system.h
+++ b/xen/include/asm-ia64/linux-xen/asm/system.h
@@ -189,6 +189,7 @@ do { \
#ifdef XEN
#define local_irq_is_enabled() (!irqs_disabled())
+extern struct vcpu *ia64_switch_to(struct vcpu *next_task);
#else
#ifdef __KERNEL__
diff --git a/xen/include/asm-ia64/linux/README.origin b/xen/include/asm-ia64/linux/README.origin
index cb7c02b0a2..e364b52977 100644
--- a/xen/include/asm-ia64/linux/README.origin
+++ b/xen/include/asm-ia64/linux/README.origin
@@ -7,6 +7,7 @@
bcd.h -> linux/include/linux/bcd.h
bitmap.h -> linux/include/linux/bitmap.h
bitops.h -> linux/include/linux/bitops.h
+hash.h -> linux/include/linux/hash.h
initrd.h -> linux/include/linux/initrd.h
jiffies.h -> linux/include/linux/jiffies.h
kmalloc_sizes.h -> linux/include/linux/kmalloc_sizes.h
diff --git a/xen/include/asm-ia64/linux/asm/README.origin b/xen/include/asm-ia64/linux/asm/README.origin
index c92c24b828..863a538b04 100644
--- a/xen/include/asm-ia64/linux/asm/README.origin
+++ b/xen/include/asm-ia64/linux/asm/README.origin
@@ -4,8 +4,6 @@
# needs to be changed, move it to ../linux-xen and follow
# the instructions in the README there.
-acpi.h -> linux/include/asm-ia64/acpi.h
-atomic.h -> linux/include/asm-ia64/atomic.h
bitops.h -> linux/include/asm-ia64/bitops.h
break.h -> linux/include/asm-ia64/break.h
byteorder.h -> linux/include/asm-ia64/byteorder.h
@@ -26,7 +24,7 @@ linkage.h -> linux/include/asm-ia64/linkage.h
machvec.h -> linux/include/asm-ia64/machvec.h
machvec_hpsim.h -> linux/include/asm-ia64/machvec_hpsim.h
mca.h -> linux/include/asm-ia64/mca.h
-numa.h -> linux/include/asm-ia64/numa.h
+nodedata.h -> linux/include/asm-ia64/nodedate.h
numnodes.h -> linux/include/asm-ia64/numnodes.h
param.h -> linux/include/asm-ia64/param.h
patch.h -> linux/include/asm-ia64/patch.h
diff --git a/xen/include/asm-ia64/linux/asm/nodedata.h b/xen/include/asm-ia64/linux/asm/nodedata.h
new file mode 100644
index 0000000000..9978c7ce75
--- /dev/null
+++ b/xen/include/asm-ia64/linux/asm/nodedata.h
@@ -0,0 +1,52 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2000 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 2002 NEC Corp.
+ * Copyright (c) 2002 Erich Focht <efocht@ess.nec.de>
+ * Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com>
+ */
+#ifndef _ASM_IA64_NODEDATA_H
+#define _ASM_IA64_NODEDATA_H
+
+#include <linux/config.h>
+#include <linux/numa.h>
+
+#include <asm/percpu.h>
+#include <asm/mmzone.h>
+
+#ifdef CONFIG_NUMA
+
+/*
+ * Node Data. One of these structures is located on each node of a NUMA system.
+ */
+
+struct pglist_data;
+struct ia64_node_data {
+ short active_cpu_count;
+ short node;
+ struct pglist_data *pg_data_ptrs[MAX_NUMNODES];
+};
+
+
+/*
+ * Return a pointer to the node_data structure for the executing cpu.
+ */
+#define local_node_data (local_cpu_data->node_data)
+
+/*
+ * Given a node id, return a pointer to the pg_data_t for the node.
+ *
+ * NODE_DATA - should be used in all code not related to system
+ * initialization. It uses pernode data structures to minimize
+ * offnode memory references. However, these structure are not
+ * present during boot. This macro can be used once cpu_init
+ * completes.
+ */
+#define NODE_DATA(nid) (local_node_data->pg_data_ptrs[nid])
+
+#endif /* CONFIG_NUMA */
+
+#endif /* _ASM_IA64_NODEDATA_H */
diff --git a/xen/include/asm-ia64/linux/asm/sal.h b/xen/include/asm-ia64/linux/asm/sal.h
index 29df88bdd2..2af85b14b6 100644
--- a/xen/include/asm-ia64/linux/asm/sal.h
+++ b/xen/include/asm-ia64/linux/asm/sal.h
@@ -657,15 +657,7 @@ ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
return isrv.status;
}
-/* Flush all the processor and platform level instruction and/or data caches */
-static inline s64
-ia64_sal_cache_flush (u64 cache_type)
-{
- struct ia64_sal_retval isrv;
- SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0);
- return isrv.status;
-}
-
+extern s64 ia64_sal_cache_flush (u64 cache_type);
/* Initialize all the processor and platform level instruction and data caches */
static inline s64
diff --git a/xen/include/asm-ia64/linux/hash.h b/xen/include/asm-ia64/linux/hash.h
new file mode 100644
index 0000000000..acf17bb8e7
--- /dev/null
+++ b/xen/include/asm-ia64/linux/hash.h
@@ -0,0 +1,58 @@
+#ifndef _LINUX_HASH_H
+#define _LINUX_HASH_H
+/* Fast hashing routine for a long.
+ (C) 2002 William Lee Irwin III, IBM */
+
+/*
+ * Knuth recommends primes in approximately golden ratio to the maximum
+ * integer representable by a machine word for multiplicative hashing.
+ * Chuck Lever verified the effectiveness of this technique:
+ * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
+ *
+ * These primes are chosen to be bit-sparse, that is operations on
+ * them can use shifts and additions instead of multiplications for
+ * machines where multiplications are slow.
+ */
+#if BITS_PER_LONG == 32
+/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
+#define GOLDEN_RATIO_PRIME 0x9e370001UL
+#elif BITS_PER_LONG == 64
+/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
+#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
+#else
+#error Define GOLDEN_RATIO_PRIME for your wordsize.
+#endif
+
+static inline unsigned long hash_long(unsigned long val, unsigned int bits)
+{
+ unsigned long hash = val;
+
+#if BITS_PER_LONG == 64
+ /* Sigh, gcc can't optimise this alone like it does for 32 bits. */
+ unsigned long n = hash;
+ n <<= 18;
+ hash -= n;
+ n <<= 33;
+ hash -= n;
+ n <<= 3;
+ hash += n;
+ n <<= 3;
+ hash -= n;
+ n <<= 4;
+ hash += n;
+ n <<= 2;
+ hash += n;
+#else
+ /* On some cpus multiply is faster, on others gcc will do shifts */
+ hash *= GOLDEN_RATIO_PRIME;
+#endif
+
+ /* High bits are more random, so use them. */
+ return hash >> (BITS_PER_LONG - bits);
+}
+
+static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
+{
+ return hash_long((unsigned long)ptr, bits);
+}
+#endif /* _LINUX_HASH_H */
diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h
index 969f680e83..4a7fa50492 100644
--- a/xen/include/asm-ia64/mm.h
+++ b/xen/include/asm-ia64/mm.h
@@ -18,6 +18,7 @@
#include <asm/processor.h>
#include <asm/atomic.h>
#include <asm/tlbflush.h>
+#include <asm/flushtlb.h>
#include <asm/io.h>
#include <public/xen.h>
@@ -103,14 +104,6 @@ struct page_info
#define _PGT_pinned 27
#define PGT_pinned (1U<<_PGT_pinned)
- /* The 27 most significant bits of virt address if this is a page table. */
-#define PGT_va_shift 32
-#define PGT_va_mask ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer still mutable (i.e. not fixed yet)? */
-#define PGT_va_mutable ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown ((unsigned long)((1U<<28)-2)<<PGT_va_shift)
-
/* 16-bit count of uses of this frame as its current type. */
#define PGT_count_mask ((1U<<16)-1)
@@ -125,10 +118,14 @@ struct page_info
#define IS_XEN_HEAP_FRAME(_pfn) ((page_to_maddr(_pfn) < xenheap_phys_end) \
&& (page_to_maddr(_pfn) >= xen_pstart))
-static inline struct domain *unpickle_domptr(u32 _d)
-{ return (_d == 0) ? NULL : __va(_d); }
+extern void *xen_heap_start;
+#define __pickle(a) ((unsigned long)a - (unsigned long)xen_heap_start)
+#define __unpickle(a) (void *)(a + xen_heap_start)
+
+static inline struct domain *unpickle_domptr(u64 _d)
+{ return (_d == 0) ? NULL : __unpickle(_d); }
static inline u32 pickle_domptr(struct domain *_d)
-{ return (_d == NULL) ? 0 : (u32)__pa(_d); }
+{ return (_d == NULL) ? 0 : (u32)__pickle(_d); }
#define page_get_owner(_p) (unpickle_domptr((_p)->u.inuse._domain))
#define page_set_owner(_p, _d) ((_p)->u.inuse._domain = pickle_domptr(_d))
@@ -178,7 +175,7 @@ static inline int get_page(struct page_info *page,
unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */
unlikely((x >> 32) != _domain)) { /* Wrong owner? */
- DPRINTK("Error pfn %lx: rd=%p, od=%p, caf=%016lx, taf=%"
+ gdprintk(XENLOG_INFO, "Error pfn %lx: rd=%p, od=%p, caf=%016lx, taf=%"
PRtype_info "\n", page_to_mfn(page), domain,
unpickle_domptr(x >> 32), x, page->u.inuse.type_info);
return 0;
@@ -428,7 +425,7 @@ extern void alloc_dom_xen_and_dom_io(void);
extern void relinquish_mm(struct domain* d);
extern struct page_info * assign_new_domain_page(struct domain *d, unsigned long mpaddr);
extern void assign_new_domain0_page(struct domain *d, unsigned long mpaddr);
-extern void __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags);
+extern int __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags);
extern void assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr);
extern void assign_domain_io_page(struct domain *d, unsigned long mpaddr, unsigned long flags);
struct p2m_entry;
@@ -443,6 +440,13 @@ extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long mpadd
extern unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3);
extern unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, unsigned int extent_order);
extern unsigned long dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, unsigned long flags, domid_t domid);
+#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
+extern void expose_p2m_init(void);
+extern unsigned long dom0vp_expose_p2m(struct domain* d, unsigned long conv_start_gpfn, unsigned long assign_start_gpfn, unsigned long expose_size, unsigned long granule_pfn);
+#else
+#define expose_p2m_init() do { } while (0)
+#define dom0vp_expose_p2m(d, conv_start_gpfn, assign_start_gpfn, expose_size, granule_pfn) (-ENOSYS)
+#endif
extern volatile unsigned long *mpt_table;
extern unsigned long gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
@@ -493,6 +497,10 @@ extern u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps,
#define __gpa_to_mpa(_d, gpa) \
((gmfn_to_mfn((_d),(gpa)>>PAGE_SHIFT)<<PAGE_SHIFT)|((gpa)&~PAGE_MASK))
+#define __mpa_to_gpa(madr) \
+ ((get_gpfn_from_mfn((madr) >> PAGE_SHIFT) << PAGE_SHIFT) | \
+ ((madr) & ~PAGE_MASK))
+
/* Arch-specific portion of memory_op hypercall. */
long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg);
diff --git a/xen/include/asm-ia64/p2m_entry.h b/xen/include/asm-ia64/p2m_entry.h
new file mode 100644
index 0000000000..4a2ff7ef6c
--- /dev/null
+++ b/xen/include/asm-ia64/p2m_entry.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * p2m_entry.h
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ASM_P2M_ENTRY_H__
+#define __ASM_P2M_ENTRY_H__
+
+#include <asm/pgtable.h>
+
+struct p2m_entry {
+#define P2M_PTE_ALWAYS_RETRY ((volatile pte_t*) -1)
+ volatile pte_t* ptep;
+ pte_t used;
+};
+
+static inline void
+p2m_entry_set(struct p2m_entry* entry, volatile pte_t* ptep, pte_t used)
+{
+ entry->ptep = ptep;
+ entry->used = used;
+}
+
+static inline void
+p2m_entry_set_retry(struct p2m_entry* entry)
+{
+ entry->ptep = P2M_PTE_ALWAYS_RETRY;
+}
+
+static inline int
+p2m_entry_retry(struct p2m_entry* entry)
+{
+ /* XXX see lookup_domain_pte().
+ NULL is set for invalid gpaddr for the time being. */
+ if (entry->ptep == NULL)
+ return 0;
+
+ if (entry->ptep == P2M_PTE_ALWAYS_RETRY)
+ return 1;
+
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+ return ((pte_val(*entry->ptep) & ~_PAGE_TLB_TRACK_MASK) !=
+ (pte_val(entry->used) & ~_PAGE_TLB_TRACK_MASK));
+#else
+ return (pte_val(*entry->ptep) != pte_val(entry->used));
+#endif
+}
+
+#endif // __ASM_P2M_ENTRY_H__
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-ia64/perfc_defn.h b/xen/include/asm-ia64/perfc_defn.h
index 58d52a97ff..37a91af5fc 100644
--- a/xen/include/asm-ia64/perfc_defn.h
+++ b/xen/include/asm-ia64/perfc_defn.h
@@ -107,3 +107,68 @@ PERFSTATUS(privop_addr_##name##_overflow, "privop-addrs overflow " #name)
PERFPRIVOPADDR(get_ifa)
PERFPRIVOPADDR(thash)
#endif
+
+// vhpt.c
+PERFCOUNTER_CPU(local_vhpt_flush, "local_vhpt_flush")
+PERFCOUNTER_CPU(vcpu_vhpt_flush, "vcpu_vhpt_flush")
+PERFCOUNTER_CPU(vcpu_flush_vtlb_all, "vcpu_flush_vtlb_all")
+PERFCOUNTER_CPU(domain_flush_vtlb_all, "domain_flush_vtlb_all")
+PERFCOUNTER_CPU(vcpu_flush_tlb_vhpt_range, "vcpu_flush_tlb_vhpt_range")
+PERFCOUNTER_CPU(domain_flush_vtlb_track_entry, "domain_flush_vtlb_track_entry")
+PERFCOUNTER_CPU(domain_flush_vtlb_local, "domain_flush_vtlb_local")
+PERFCOUNTER_CPU(domain_flush_vtlb_global, "domain_flush_vtlb_global")
+PERFCOUNTER_CPU(domain_flush_vtlb_range, "domain_flush_vtlb_range")
+
+// domain.c
+PERFCOUNTER_CPU(flush_vtlb_for_context_switch, "flush_vtlb_for_context_switch")
+
+// mm.c
+PERFCOUNTER_CPU(assign_domain_page_replace, "assign_domain_page_replace")
+PERFCOUNTER_CPU(assign_domain_pge_cmpxchg_rel, "assign_domain_pge_cmpxchg_rel")
+PERFCOUNTER_CPU(zap_dcomain_page_one, "zap_dcomain_page_one")
+PERFCOUNTER_CPU(dom0vp_zap_physmap, "dom0vp_zap_physmap")
+PERFCOUNTER_CPU(dom0vp_add_physmap, "dom0vp_add_physmap")
+PERFCOUNTER_CPU(create_grant_host_mapping, "create_grant_host_mapping")
+PERFCOUNTER_CPU(destroy_grant_host_mapping, "destroy_grant_host_mapping")
+PERFCOUNTER_CPU(steal_page_refcount, "steal_page_refcount")
+PERFCOUNTER_CPU(steal_page, "steal_page")
+PERFCOUNTER_CPU(guest_physmap_add_page, "guest_physmap_add_page")
+PERFCOUNTER_CPU(guest_physmap_remove_page, "guest_physmap_remove_page")
+PERFCOUNTER_CPU(domain_page_flush_and_put, "domain_page_flush_and_put")
+
+// dom0vp
+PERFCOUNTER_CPU(dom0vp_phystomach, "dom0vp_phystomach")
+PERFCOUNTER_CPU(dom0vp_machtophys, "dom0vp_machtophys")
+
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+// insert or dirty
+PERFCOUNTER_CPU(tlb_track_iod, "tlb_track_iod")
+PERFCOUNTER_CPU(tlb_track_iod_again, "tlb_track_iod_again")
+PERFCOUNTER_CPU(tlb_track_iod_not_tracked, "tlb_track_iod_not_tracked")
+PERFCOUNTER_CPU(tlb_track_iod_force_many, "tlb_track_iod_force_many")
+PERFCOUNTER_CPU(tlb_track_iod_tracked_many, "tlb_track_iod_tracked_many")
+PERFCOUNTER_CPU(tlb_track_iod_tracked_many_del, "tlb_track_iod_tracked_many_del")
+PERFCOUNTER_CPU(tlb_track_iod_found, "tlb_track_iod_found")
+PERFCOUNTER_CPU(tlb_track_iod_new_entry, "tlb_track_iod_new_entry")
+PERFCOUNTER_CPU(tlb_track_iod_new_failed, "tlb_track_iod_new_failed")
+PERFCOUNTER_CPU(tlb_track_iod_new_many, "tlb_track_iod_new_many")
+PERFCOUNTER_CPU(tlb_track_iod_insert, "tlb_track_iod_insert")
+PERFCOUNTER_CPU(tlb_track_iod_dirtied, "tlb_track_iod_dirtied")
+
+// search and remove
+PERFCOUNTER_CPU(tlb_track_sar, "tlb_track_sar")
+PERFCOUNTER_CPU(tlb_track_sar_not_tracked, "tlb_track_sar_not_tracked")
+PERFCOUNTER_CPU(tlb_track_sar_not_found, "tlb_track_sar_not_found")
+PERFCOUNTER_CPU(tlb_track_sar_found, "tlb_track_sar_found")
+PERFCOUNTER_CPU(tlb_track_sar_many, "tlb_track_sar_many")
+
+// flush
+PERFCOUNTER_CPU(tlb_track_use_rr7, "tlb_track_use_rr7")
+PERFCOUNTER_CPU(tlb_track_swap_rr0, "tlb_track_swap_rr0")
+#endif
+
+// tlb flush clock
+#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK
+PERFCOUNTER_CPU(tlbflush_clock_cswitch_purge, "tlbflush_clock_cswitch_purge")
+PERFCOUNTER_CPU(tlbflush_clock_cswitch_skip, "tlbflush_clock_cswitch_skip")
+#endif
diff --git a/xen/include/asm-ia64/privop.h b/xen/include/asm-ia64/privop.h
index 1324c4c2fb..64e73f473c 100644
--- a/xen/include/asm-ia64/privop.h
+++ b/xen/include/asm-ia64/privop.h
@@ -4,9 +4,9 @@
#include <asm/ia64_int.h>
#include <asm/vcpu.h>
-extern IA64FAULT priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr);
+extern IA64FAULT priv_emulate(VCPU *vcpu, REGS *regs, u64 isr);
-extern void privify_memory(void *start, UINT64 len);
+extern void privify_memory(void *start, u64 len);
extern int ia64_hyperprivop(unsigned long iim, REGS *regs);
diff --git a/xen/include/asm-ia64/tlb_track.h b/xen/include/asm-ia64/tlb_track.h
new file mode 100644
index 0000000000..5243aa6305
--- /dev/null
+++ b/xen/include/asm-ia64/tlb_track.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * tlb_track.h
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __TLB_TRACK_H__
+#define __TLB_TRACK_H__
+
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+
+#include <xen/sched.h>
+#include <xen/perfc.h>
+#include <asm/domain.h>
+#include <xen/list.h>
+#include <asm/p2m_entry.h>
+#include <asm/vcpumask.h>
+
+// TODO: compact this structure.
+struct tlb_track_entry {
+ struct list_head list;
+
+ volatile pte_t* ptep; // corresponding p2m entry
+
+ /* XXX should we use TR_ENTRY? */
+ pte_t pte_val; // mfn and other flags
+ // pte_val.p = 1:
+ // tlb entry is inserted.
+ // pte_val.p = 0:
+ // once tlb entry is inserted, so
+ // this entry is created. But tlb
+ // purge is isseued, so this
+ // virtual address need not to be
+ // purged.
+ unsigned long vaddr; // virtual address
+ unsigned long rid; // rid
+
+ cpumask_t pcpu_dirty_mask;
+ vcpumask_t vcpu_dirty_mask;
+
+#ifdef CONFIG_TLB_TRACK_CNT
+#define TLB_TRACK_CNT_FORCE_MANY 256 /* XXX how many? */
+ unsigned long cnt;
+#endif
+};
+
+struct tlb_track {
+
+/* see __gnttab_map_grant_ref()
+ A domain can map granted-page up to MAPTRACK_MAX_ENTRIES pages. */
+#define TLB_TRACK_LIMIT_ENTRIES \
+ (MAPTRACK_MAX_ENTRIES * (PAGE_SIZE / sizeof(struct tlb_track)))
+
+ spinlock_t free_list_lock;
+ struct list_head free_list;
+ unsigned int limit;
+ unsigned int num_entries;
+ unsigned int num_free;
+ struct list_head page_list;
+
+ /* XXX hash table size */
+ spinlock_t hash_lock;
+ unsigned int hash_size;
+ unsigned int hash_shift;
+ unsigned int hash_mask;
+ struct list_head* hash;
+};
+
+int tlb_track_create(struct domain* d);
+void tlb_track_destroy(struct domain* d);
+
+void tlb_track_free_entry(struct tlb_track* tlb_track,
+ struct tlb_track_entry* entry);
+
+void
+__vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr,
+ struct p2m_entry* entry);
+static inline void
+vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr,
+ struct p2m_entry* entry)
+{
+ /* optimization.
+ non-tracking pte is most common. */
+ perfc_incrc(tlb_track_iod);
+ if (!pte_tlb_tracking(entry->used)) {
+ perfc_incrc(tlb_track_iod_not_tracked);
+ return;
+ }
+
+ __vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry);
+}
+
+
+/* return value
+ * NULL if this entry is used
+ * entry if this entry isn't used
+ */
+enum TLB_TRACK_RET {
+ TLB_TRACK_NOT_TRACKED,
+ TLB_TRACK_NOT_FOUND,
+ TLB_TRACK_FOUND,
+ TLB_TRACK_MANY,
+ TLB_TRACK_AGAIN,
+};
+typedef enum TLB_TRACK_RET TLB_TRACK_RET_T;
+
+TLB_TRACK_RET_T
+tlb_track_search_and_remove(struct tlb_track* tlb_track,
+ volatile pte_t* ptep, pte_t old_pte,
+ struct tlb_track_entry** entryp);
+
+void
+__tlb_track_entry_printf(const char* func, int line,
+ const struct tlb_track_entry* entry);
+#define tlb_track_entry_printf(entry) \
+ __tlb_track_entry_printf(__func__, __LINE__, (entry))
+#else
+//define as nop
+#define tlb_track_create(d) do { } while (0)
+#define tlb_track_destroy(d) do { } while (0)
+#define tlb_track_free_entry(tlb_track, entry) do { } while (0)
+#define vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry) \
+ do { } while (0)
+#define tlb_track_search_and_remove(tlb_track, ptep, old_pte, entryp) \
+ do { } while (0)
+#define tlb_track_entry_printf(entry) do { } while (0)
+#endif /* CONFIG_XEN_IA64_TLB_TRACK */
+
+#endif /* __TLB_TRACK_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-ia64/tlbflush.h b/xen/include/asm-ia64/tlbflush.h
index 22abb53f3f..49ff463b11 100644
--- a/xen/include/asm-ia64/tlbflush.h
+++ b/xen/include/asm-ia64/tlbflush.h
@@ -22,6 +22,15 @@ void domain_flush_vtlb_all (void);
/* Global range-flush of vTLB. */
void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range);
+#ifdef CONFIG_XEN_IA64_TLB_TRACK
+struct tlb_track_entry;
+void __domain_flush_vtlb_track_entry(struct domain* d,
+ const struct tlb_track_entry* entry);
+/* Global entry-flush of vTLB */
+void domain_flush_vtlb_track_entry(struct domain* d,
+ const struct tlb_track_entry* entry);
+#endif
+
/* Flush vhpt and mTLB on every dirty cpus. */
void domain_flush_tlb_vhpt(struct domain *d);
@@ -31,7 +40,6 @@ void flush_tlb_mask(cpumask_t mask);
/* Flush local machine TLB. */
void local_flush_tlb_all (void);
-#define tlbflush_current_time() 0
#define tlbflush_filter(x,y) ((void)0)
#endif
diff --git a/xen/include/asm-ia64/uaccess.h b/xen/include/asm-ia64/uaccess.h
index 17e2a17f9d..32ef4151df 100644
--- a/xen/include/asm-ia64/uaccess.h
+++ b/xen/include/asm-ia64/uaccess.h
@@ -211,30 +211,16 @@ extern void __put_user_unknown (void);
extern unsigned long __must_check __copy_user (void __user *to, const void __user *from,
unsigned long count);
-extern int ia64_map_hypercall_param(void);
-
static inline unsigned long
__copy_to_user (void __user *to, const void *from, unsigned long count)
{
- unsigned long len;
- len = __copy_user(to, (void __user *)from, count);
- if (len == 0)
- return 0;
- if (ia64_map_hypercall_param())
- len = __copy_user(to, (void __user *)from, count); /* retry */
- return len;
+ return __copy_user(to, (void __user *)from, count);
}
static inline unsigned long
__copy_from_user (void *to, const void __user *from, unsigned long count)
{
- unsigned long len;
- len = __copy_user((void __user *)to, from, count);
- if (len == 0)
- return 0;
- if (ia64_map_hypercall_param())
- len = __copy_user((void __user *) to, from, count); /* retry */
- return len;
+ return __copy_user((void __user *)to, from, count);
}
#define __copy_to_user_inatomic __copy_to_user
diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h
index 7bfc76f761..a95d3f1c29 100644
--- a/xen/include/asm-ia64/vcpu.h
+++ b/xen/include/asm-ia64/vcpu.h
@@ -10,197 +10,197 @@
#include <asm/ia64_int.h>
#include <xen/types.h>
#include <public/xen.h>
-typedef unsigned long UINT64;
-typedef unsigned int UINT;
-typedef int BOOLEAN;
+typedef int BOOLEAN;
struct vcpu;
-typedef struct vcpu VCPU;
+typedef struct vcpu VCPU;
typedef cpu_user_regs_t REGS;
extern u64 cycle_to_ns(u64 cycle);
/* Note: PSCB stands for Privilegied State Communication Block. */
#define VCPU(_v,_x) (_v->arch.privregs->_x)
-#define PSCB(_v,_x) VCPU(_v,_x)
-#define PSCBX(_v,_x) (_v->arch._x)
+#define PSCB(_v,_x) VCPU(_v,_x)
+#define PSCBX(_v,_x) (_v->arch._x)
#define SPURIOUS_VECTOR 0xf
/* general registers */
-extern UINT64 vcpu_get_gr(VCPU *vcpu, unsigned long reg);
-extern IA64FAULT vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val);
-extern IA64FAULT vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value, int nat);
-extern IA64FAULT vcpu_get_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val);
+extern u64 vcpu_get_gr(VCPU * vcpu, unsigned long reg);
+extern IA64FAULT vcpu_get_gr_nat(VCPU * vcpu, unsigned long reg, u64 * val);
+extern IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value,
+ int nat);
+extern IA64FAULT vcpu_get_fpreg(VCPU * vcpu, unsigned long reg,
+ struct ia64_fpreg *val);
-extern IA64FAULT vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val);
+extern IA64FAULT vcpu_set_fpreg(VCPU * vcpu, unsigned long reg,
+ struct ia64_fpreg *val);
/* application registers */
-extern void vcpu_load_kernel_regs(VCPU *vcpu);
-extern IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val);
-extern IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val);
+extern void vcpu_load_kernel_regs(VCPU * vcpu);
+extern IA64FAULT vcpu_set_ar(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_get_ar(VCPU * vcpu, u64 reg, u64 * val);
/* psr */
-extern BOOLEAN vcpu_get_psr_ic(VCPU *vcpu);
-extern UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr);
-extern IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm);
-extern IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm);
-extern IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_psr_i(VCPU *vcpu);
-extern IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu);
-extern IA64FAULT vcpu_set_psr_dt(VCPU *vcpu);
+extern BOOLEAN vcpu_get_psr_ic(VCPU * vcpu);
+extern u64 vcpu_get_ipsr_int_state(VCPU * vcpu, u64 prevpsr);
+extern IA64FAULT vcpu_get_psr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_reset_psr_sm(VCPU * vcpu, u64 imm);
+extern IA64FAULT vcpu_set_psr_sm(VCPU * vcpu, u64 imm);
+extern IA64FAULT vcpu_set_psr_l(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_psr_i(VCPU * vcpu);
+extern IA64FAULT vcpu_reset_psr_dt(VCPU * vcpu);
+extern IA64FAULT vcpu_set_psr_dt(VCPU * vcpu);
/* control registers */
-extern IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_increment_iip(VCPU *vcpu);
-extern IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval);
-extern unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa);
-extern IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval);
+extern IA64FAULT vcpu_set_dcr(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_itm(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_iva(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_pta(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_ipsr(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_isr(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_iip(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_ifa(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_itir(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_iipa(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_ifs(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_iim(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_iha(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_lid(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_tpr(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_eoi(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_lrr0(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_lrr1(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_get_dcr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_itm(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_iva(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_pta(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_ipsr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_isr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_iip(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_increment_iip(VCPU * vcpu);
+extern IA64FAULT vcpu_get_ifa(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_itir(VCPU * vcpu, u64 * pval);
+extern unsigned long vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa);
+extern IA64FAULT vcpu_get_iipa(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_ifs(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_iim(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_iha(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_lid(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_tpr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_irr0(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_irr1(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_irr2(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_irr3(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_lrr0(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_lrr1(VCPU * vcpu, u64 * pval);
/* interrupt registers */
-extern void vcpu_pend_unspecified_interrupt(VCPU *vcpu);
-extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu);
-extern IA64FAULT vcpu_get_itv(VCPU *vcpu,UINT64 *pval);
-extern IA64FAULT vcpu_get_pmv(VCPU *vcpu,UINT64 *pval);
-extern IA64FAULT vcpu_get_cmcv(VCPU *vcpu,UINT64 *pval);
-extern IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval);
-extern IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val);
-extern IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val);
+extern void vcpu_pend_unspecified_interrupt(VCPU * vcpu);
+extern u64 vcpu_check_pending_interrupts(VCPU * vcpu);
+extern IA64FAULT vcpu_get_itv(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_pmv(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_cmcv(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_get_ivr(VCPU * vcpu, u64 * pval);
+extern IA64FAULT vcpu_set_itv(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_pmv(VCPU * vcpu, u64 val);
+extern IA64FAULT vcpu_set_cmcv(VCPU * vcpu, u64 val);
/* interval timer registers */
-extern IA64FAULT vcpu_set_itc(VCPU *vcpu,UINT64 val);
-extern UINT64 vcpu_timer_pending_early(VCPU *vcpu);
+extern IA64FAULT vcpu_set_itc(VCPU * vcpu, u64 val);
+extern u64 vcpu_timer_pending_early(VCPU * vcpu);
/* debug breakpoint registers */
-extern IA64FAULT vcpu_set_ibr(VCPU *vcpu,UINT64 reg,UINT64 val);
-extern IA64FAULT vcpu_set_dbr(VCPU *vcpu,UINT64 reg,UINT64 val);
-extern IA64FAULT vcpu_get_ibr(VCPU *vcpu,UINT64 reg,UINT64 *pval);
-extern IA64FAULT vcpu_get_dbr(VCPU *vcpu,UINT64 reg,UINT64 *pval);
+extern IA64FAULT vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval);
+extern IA64FAULT vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval);
/* performance monitor registers */
-extern IA64FAULT vcpu_set_pmc(VCPU *vcpu,UINT64 reg,UINT64 val);
-extern IA64FAULT vcpu_set_pmd(VCPU *vcpu,UINT64 reg,UINT64 val);
-extern IA64FAULT vcpu_get_pmc(VCPU *vcpu,UINT64 reg,UINT64 *pval);
-extern IA64FAULT vcpu_get_pmd(VCPU *vcpu,UINT64 reg,UINT64 *pval);
+extern IA64FAULT vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval);
+extern IA64FAULT vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval);
/* banked general registers */
-extern IA64FAULT vcpu_bsw0(VCPU *vcpu);
-extern IA64FAULT vcpu_bsw1(VCPU *vcpu);
+extern IA64FAULT vcpu_bsw0(VCPU * vcpu);
+extern IA64FAULT vcpu_bsw1(VCPU * vcpu);
/* region registers */
-extern IA64FAULT vcpu_set_rr(VCPU *vcpu,UINT64 reg,UINT64 val);
-extern IA64FAULT vcpu_get_rr(VCPU *vcpu,UINT64 reg,UINT64 *pval);
-extern IA64FAULT vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr);
+extern IA64FAULT vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_get_rr(VCPU * vcpu, u64 reg, u64 * pval);
+extern IA64FAULT vcpu_get_rr_ve(VCPU * vcpu, u64 vadr);
/* protection key registers */
-extern IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval);
-extern IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val);
-extern IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key);
+extern IA64FAULT vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval);
+extern IA64FAULT vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key);
/* TLB */
-static inline void vcpu_purge_tr_entry(TR_ENTRY *trp)
+static inline void vcpu_purge_tr_entry(TR_ENTRY * trp)
{
trp->pte.val = 0;
}
-extern IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 padr,
- UINT64 itir, UINT64 ifa);
-extern IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 padr,
- UINT64 itir, UINT64 ifa);
-extern IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 padr, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 padr, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range);
-extern IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr);
-extern IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range);
-extern IA64FAULT vcpu_ptc_ga(VCPU *vcpu, UINT64 vadr, UINT64 addr_range);
-extern IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr, UINT64 log_range);
-extern IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr, UINT64 log_range);
+extern IA64FAULT vcpu_itr_d(VCPU * vcpu, u64 slot, u64 padr, u64 itir, u64 ifa);
+extern IA64FAULT vcpu_itr_i(VCPU * vcpu, u64 slot, u64 padr, u64 itir, u64 ifa);
+extern IA64FAULT vcpu_itc_d(VCPU * vcpu, u64 padr, u64 itir, u64 ifa);
+extern IA64FAULT vcpu_itc_i(VCPU * vcpu, u64 padr, u64 itir, u64 ifa);
+extern IA64FAULT vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 log_range);
+extern IA64FAULT vcpu_ptc_e(VCPU * vcpu, u64 vadr);
+extern IA64FAULT vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 addr_range);
+extern IA64FAULT vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 addr_range);
+extern IA64FAULT vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 log_range);
+extern IA64FAULT vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 log_range);
union U_IA64_BUNDLE;
-extern int vcpu_get_domain_bundle(VCPU *vcpu, REGS *regs, UINT64 gip, union U_IA64_BUNDLE *bundle);
-extern IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data,
- UINT64 *pteval, UINT64 *itir, UINT64 *iha);
-extern IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr);
-extern IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa);
-extern IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa);
-extern IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr);
+extern int vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip,
+ union U_IA64_BUNDLE *bundle);
+extern IA64FAULT vcpu_translate(VCPU * vcpu, u64 address, BOOLEAN is_data,
+ u64 * pteval, u64 * itir, u64 * iha);
+extern IA64FAULT vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr);
+extern IA64FAULT vcpu_force_inst_miss(VCPU * vcpu, u64 ifa);
+extern IA64FAULT vcpu_force_data_miss(VCPU * vcpu, u64 ifa);
+extern IA64FAULT vcpu_fc(VCPU * vcpu, u64 vadr);
/* misc */
-extern IA64FAULT vcpu_rfi(VCPU *vcpu);
-extern IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval);
-extern IA64FAULT vcpu_cover(VCPU *vcpu);
-extern IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr);
-extern IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval);
-
-extern void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector);
-extern void vcpu_pend_timer(VCPU *vcpu);
-extern void vcpu_poke_timer(VCPU *vcpu);
-extern void vcpu_set_next_timer(VCPU *vcpu);
-extern BOOLEAN vcpu_timer_expired(VCPU *vcpu);
-extern UINT64 vcpu_deliverable_interrupts(VCPU *vcpu);
-extern void vcpu_itc_no_srlz(VCPU *vcpu, UINT64, UINT64, UINT64, UINT64, UINT64);
-extern UINT64 vcpu_get_tmp(VCPU *, UINT64);
-extern void vcpu_set_tmp(VCPU *, UINT64, UINT64);
-
-extern IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot,
+extern IA64FAULT vcpu_rfi(VCPU * vcpu);
+extern IA64FAULT vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval);
+extern IA64FAULT vcpu_cover(VCPU * vcpu);
+extern IA64FAULT vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * padr);
+extern IA64FAULT vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval);
+
+extern void vcpu_pend_interrupt(VCPU * vcpu, u64 vector);
+extern void vcpu_pend_timer(VCPU * vcpu);
+extern void vcpu_poke_timer(VCPU * vcpu);
+extern void vcpu_set_next_timer(VCPU * vcpu);
+extern BOOLEAN vcpu_timer_expired(VCPU * vcpu);
+extern u64 vcpu_deliverable_interrupts(VCPU * vcpu);
+struct p2m_entry;
+extern void vcpu_itc_no_srlz(VCPU * vcpu, u64, u64, u64, u64, u64,
+ struct p2m_entry *);
+extern u64 vcpu_get_tmp(VCPU *, u64);
+extern void vcpu_set_tmp(VCPU *, u64, u64);
+
+extern IA64FAULT vcpu_set_dtr(VCPU * vcpu, u64 slot,
u64 pte, u64 itir, u64 ifa, u64 rid);
-extern IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot,
+extern IA64FAULT vcpu_set_itr(VCPU * vcpu, u64 slot,
u64 pte, u64 itir, u64 ifa, u64 rid);
/* Initialize vcpu regs. */
-extern void vcpu_init_regs (struct vcpu *v);
+extern void vcpu_init_regs(struct vcpu *v);
-static inline UINT64
-itir_ps(UINT64 itir)
+static inline u64 itir_ps(u64 itir)
{
- return ((itir >> 2) & 0x3f);
+ return ((itir >> 2) & 0x3f);
}
-static inline UINT64
-itir_mask(UINT64 itir)
+static inline u64 itir_mask(u64 itir)
{
- return (~((1UL << itir_ps(itir)) - 1));
+ return (~((1UL << itir_ps(itir)) - 1));
}
-static inline s64
-vcpu_get_next_timer_ns(VCPU *vcpu)
+static inline s64 vcpu_get_next_timer_ns(VCPU * vcpu)
{
- s64 vcpu_get_next_timer_ns;
- u64 d = PSCBX(vcpu, domain_itm);
- u64 now = ia64_get_itc();
+ s64 vcpu_get_next_timer_ns;
+ u64 d = PSCBX(vcpu, domain_itm);
+ u64 now = ia64_get_itc();
- if (d > now)
- vcpu_get_next_timer_ns = cycle_to_ns(d - now) + NOW();
- else
- vcpu_get_next_timer_ns = cycle_to_ns(local_cpu_data->itm_delta) + NOW();
+ if (d > now)
+ vcpu_get_next_timer_ns = cycle_to_ns(d - now) + NOW();
+ else
+ vcpu_get_next_timer_ns =
+ cycle_to_ns(local_cpu_data->itm_delta) + NOW();
- return vcpu_get_next_timer_ns;
+ return vcpu_get_next_timer_ns;
}
-#define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0)
+#define verbose(a...) do {if (vcpu_verbose) printk(a);} while(0)
//#define vcpu_quick_region_check(_tr_regions,_ifa) 1
#define vcpu_quick_region_check(_tr_regions,_ifa) \
@@ -208,5 +208,4 @@ vcpu_get_next_timer_ns(VCPU *vcpu)
#define vcpu_quick_region_set(_tr_regions,_ifa) \
do {_tr_regions |= (1 << ((unsigned long)_ifa >> 61)); } while (0)
-
#endif
diff --git a/xen/include/asm-ia64/vcpumask.h b/xen/include/asm-ia64/vcpumask.h
new file mode 100644
index 0000000000..7a9773e411
--- /dev/null
+++ b/xen/include/asm-ia64/vcpumask.h
@@ -0,0 +1,60 @@
+#ifndef __XEN_VCPUMASK_H
+#define __XEN_VCPUMASK_H
+
+/* vcpu mask
+ stolen from cpumask.h */
+typedef struct { DECLARE_BITMAP(bits, MAX_VIRT_CPUS); } vcpumask_t;
+
+#define vcpu_set(vcpu, dst) __vcpu_set((vcpu), &(dst))
+static inline void __vcpu_set(int vcpu, volatile vcpumask_t *dstp)
+{
+ set_bit(vcpu, dstp->bits);
+}
+#define vcpus_clear(dst) __vcpus_clear(&(dst), MAX_VIRT_CPUS)
+static inline void __vcpus_clear(vcpumask_t *dstp, int nbits)
+{
+ bitmap_zero(dstp->bits, nbits);
+}
+/* No static inline type checking - see Subtlety (1) above. */
+#define vcpu_isset(vcpu, vcpumask) test_bit((vcpu), (vcpumask).bits)
+
+#define first_vcpu(src) __first_vcpu(&(src), MAX_VIRT_CPUS)
+static inline int __first_vcpu(const vcpumask_t *srcp, int nbits)
+{
+ return min_t(int, nbits, find_first_bit(srcp->bits, nbits));
+}
+
+#define next_vcpu(n, src) __next_vcpu((n), &(src), MAX_VIRT_CPUS)
+static inline int __next_vcpu(int n, const vcpumask_t *srcp, int nbits)
+{
+ return min_t(int, nbits, find_next_bit(srcp->bits, nbits, n+1));
+}
+
+#if MAX_VIRT_CPUS > 1
+#define for_each_vcpu_mask(vcpu, mask) \
+ for ((vcpu) = first_vcpu(mask); \
+ (vcpu) < MAX_VIRT_CPUS; \
+ (vcpu) = next_vcpu((vcpu), (mask)))
+#else /* NR_CPUS == 1 */
+#define for_each_vcpu_mask(vcpu, mask) for ((vcpu) = 0; (vcpu) < 1; (vcpu)++)
+#endif /* NR_CPUS */
+
+#define vcpumask_scnprintf(buf, len, src) \
+ __vcpumask_scnprintf((buf), (len), &(src), MAX_VIRT_CPUS)
+static inline int __vcpumask_scnprintf(char *buf, int len,
+ const vcpumask_t *srcp, int nbits)
+{
+ return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+}
+
+#endif /* __XEN_VCPUMASK_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-ia64/vhpt.h b/xen/include/asm-ia64/vhpt.h
index cb4fc30462..351c1d701a 100644
--- a/xen/include/asm-ia64/vhpt.h
+++ b/xen/include/asm-ia64/vhpt.h
@@ -18,6 +18,10 @@
#ifndef __ASSEMBLY__
#include <xen/percpu.h>
+#include <asm/vcpumask.h>
+
+extern void domain_purge_swtc_entries(struct domain *d);
+extern void domain_purge_swtc_entries_vcpu_dirty_mask(struct domain* d, vcpumask_t vcpu_dirty_mask);
//
// VHPT Long Format Entry (as recognized by hw)
@@ -37,11 +41,48 @@ extern void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte,
unsigned long logps);
extern void vhpt_insert (unsigned long vadr, unsigned long pte,
unsigned long logps);
-void vhpt_flush(void);
+void local_vhpt_flush(void);
+extern void vcpu_vhpt_flush(struct vcpu* v);
/* Currently the VHPT is allocated per CPU. */
DECLARE_PER_CPU (unsigned long, vhpt_paddr);
DECLARE_PER_CPU (unsigned long, vhpt_pend);
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+#if !VHPT_ENABLED
+#error "VHPT_ENABLED must be set for CONFIG_XEN_IA64_PERVCPU_VHPT"
+#endif
+#endif
+
+#include <xen/sched.h>
+int pervcpu_vhpt_alloc(struct vcpu *v);
+void pervcpu_vhpt_free(struct vcpu *v);
+static inline unsigned long
+vcpu_vhpt_maddr(struct vcpu* v)
+{
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ if (HAS_PERVCPU_VHPT(v->domain))
+ return v->arch.vhpt_maddr;
+#endif
+
+#if 0
+ // referencecing v->processor is racy.
+ return per_cpu(vhpt_paddr, v->processor);
+#endif
+ BUG_ON(v != current);
+ return __get_cpu_var(vhpt_paddr);
+}
+
+static inline unsigned long
+vcpu_pta(struct vcpu* v)
+{
+#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT
+ if (HAS_PERVCPU_VHPT(v->domain))
+ return v->arch.pta.val;
+#endif
+ return __va_ul(__get_cpu_var(vhpt_paddr)) | (1 << 8) |
+ (VHPT_SIZE_LOG2 << 2) | VHPT_ENABLED;
+}
+
#endif /* !__ASSEMBLY */
#endif
diff --git a/xen/include/asm-ia64/vlsapic.h b/xen/include/asm-ia64/vlsapic.h
index aceee921f3..98bc88f9df 100644
--- a/xen/include/asm-ia64/vlsapic.h
+++ b/xen/include/asm-ia64/vlsapic.h
@@ -24,7 +24,6 @@
#define _LSAPIC_H
#include <xen/sched.h>
-extern void vmx_virq_line_init(struct domain *d);
extern void vtm_init(struct vcpu *vcpu);
extern void vtm_set_itc(struct vcpu *vcpu, uint64_t new_itc);
extern void vtm_set_itm(struct vcpu *vcpu, uint64_t val);
diff --git a/xen/include/asm-ia64/vmmu.h b/xen/include/asm-ia64/vmmu.h
index ccd1ed5099..4b86a33711 100644
--- a/xen/include/asm-ia64/vmmu.h
+++ b/xen/include/asm-ia64/vmmu.h
@@ -305,7 +305,8 @@ extern void emulate_io_inst(struct vcpu *vcpu, u64 padr, u64 ma);
extern int vhpt_enabled(struct vcpu *vcpu, uint64_t vadr, vhpt_ref_t ref);
extern void vtlb_insert(struct vcpu *vcpu, u64 pte, u64 itir, u64 va);
extern u64 translate_phy_pte(struct vcpu *v, u64 *pte, u64 itir, u64 va);
-extern void thash_vhpt_insert(struct vcpu *v, u64 pte, u64 itir, u64 ifa);
+extern void thash_vhpt_insert(struct vcpu *v, u64 pte, u64 itir, u64 ifa,
+ int type);
extern u64 guest_vhpt_lookup(u64 iha, u64 *pte);
static inline void vmx_vcpu_set_tr (thash_data_t *trp, u64 pte, u64 itir, u64 va, u64 rid)
diff --git a/xen/include/asm-ia64/vmx.h b/xen/include/asm-ia64/vmx.h
index b9d9a67779..344ef44b95 100644
--- a/xen/include/asm-ia64/vmx.h
+++ b/xen/include/asm-ia64/vmx.h
@@ -35,6 +35,7 @@ extern void vmx_final_setup_guest(struct vcpu *v);
extern void vmx_save_state(struct vcpu *v);
extern void vmx_load_state(struct vcpu *v);
extern void vmx_setup_platform(struct domain *d);
+extern void vmx_do_launch(struct vcpu *v);
extern void vmx_io_assist(struct vcpu *v);
extern int ia64_hypercall (struct pt_regs *regs);
extern void vmx_save_state(struct vcpu *v);
@@ -43,19 +44,18 @@ extern void show_registers(struct pt_regs *regs);
#define show_execution_state show_registers
extern unsigned long __gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
extern void sync_split_caches(void);
-extern void vmx_virq_line_assist(struct vcpu *v);
extern void set_privileged_operation_isr (struct vcpu *vcpu,int inst);
extern void privilege_op (struct vcpu *vcpu);
extern void set_ifa_itir_iha (struct vcpu *vcpu, u64 vadr,
int set_ifa, int set_itir, int set_iha);
extern void inject_guest_interruption(struct vcpu *vcpu, u64 vec);
-extern void vmx_intr_assist(struct vcpu *v);
extern void set_illegal_op_isr (struct vcpu *vcpu);
extern void illegal_op (struct vcpu *vcpu);
extern void vmx_relinquish_guest_resources(struct domain *d);
extern void vmx_relinquish_vcpu_resources(struct vcpu *v);
extern void vmx_die_if_kernel(char *str, struct pt_regs *regs, long err);
extern void vmx_send_assist_req(struct vcpu *v);
+extern void vmx_vioapic_set_irq(struct domain *d, int irq, int level);
static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu)
{
diff --git a/xen/include/asm-ia64/vmx_pal_vsa.h b/xen/include/asm-ia64/vmx_pal_vsa.h
index 72ad1e6ca7..7ce8069501 100644
--- a/xen/include/asm-ia64/vmx_pal_vsa.h
+++ b/xen/include/asm-ia64/vmx_pal_vsa.h
@@ -26,10 +26,9 @@
/* PAL virtualization services */
#ifndef __ASSEMBLY__
-extern UINT64 ia64_call_vsa(UINT64 proc,UINT64 arg1, UINT64 arg2,
- UINT64 arg3, UINT64 arg4, UINT64 arg5,
- UINT64 arg6, UINT64 arg7);
-extern UINT64 __vsa_base;
+extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2, u64 arg3,
+ u64 arg4, u64 arg5, u64 arg6, u64 arg7);
+extern u64 __vsa_base;
#endif /* __ASSEMBLY__ */
#define PAL_VPS_RESUME_NORMAL 0x0000
diff --git a/xen/include/asm-ia64/vmx_phy_mode.h b/xen/include/asm-ia64/vmx_phy_mode.h
index 02f8cc643f..fcc6e5b388 100644
--- a/xen/include/asm-ia64/vmx_phy_mode.h
+++ b/xen/include/asm-ia64/vmx_phy_mode.h
@@ -90,13 +90,13 @@ extern void physical_mode_init(VCPU *);
extern void switch_to_physical_rid(VCPU *);
extern void switch_to_virtual_rid(VCPU *vcpu);
extern void switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr);
-extern void stlb_phys_lookup(VCPU *vcpu, UINT64 paddr, UINT64 type);
+extern void stlb_phys_lookup(VCPU *vcpu, u64 paddr, u64 type);
extern void check_mm_mode_switch (VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr);
extern void prepare_if_physical_mode(VCPU *vcpu);
extern void recover_if_physical_mode(VCPU *vcpu);
extern void vmx_init_all_rr(VCPU *vcpu);
extern void vmx_load_all_rr(VCPU *vcpu);
-extern void physical_tlb_miss(VCPU *vcpu, u64 vadr);
+extern void physical_tlb_miss(VCPU *vcpu, u64 vadr, int type);
/*
* No sanity check here, since all psr changes have been
* checked in switch_mm_mode().
@@ -120,9 +120,4 @@ extern void physical_tlb_miss(VCPU *vcpu, u64 vadr);
#define GUEST_VIRT 1 /* Guest in virtual mode */
#define GUEST_PHYS 2 /* Guest in physical mode, requiring emulation */
-
-
#endif /* _PHY_MODE_H_ */
-
-
-
diff --git a/xen/include/asm-ia64/vmx_platform.h b/xen/include/asm-ia64/vmx_platform.h
index 33c4003cf3..878961ef04 100644
--- a/xen/include/asm-ia64/vmx_platform.h
+++ b/xen/include/asm-ia64/vmx_platform.h
@@ -24,13 +24,15 @@
#include <asm/hvm/vioapic.h>
struct mmio_list;
typedef struct virtual_platform_def {
+ unsigned long buffered_io_va;
+ spinlock_t buffered_io_lock;
unsigned long shared_page_va;
unsigned long pib_base;
unsigned char xtp;
unsigned long params[HVM_NR_PARAMS];
struct mmio_list *mmio;
/* One IOSAPIC now... */
- struct hvm_vioapic vioapic;
+ struct vioapic vioapic;
} vir_plat_t;
static inline int __fls(uint32_t word)
@@ -53,11 +55,11 @@ typedef struct vlapic {
extern uint64_t dummy_tmr[];
#define VLAPIC_ID(l) (uint16_t)(((l)->vcpu->arch.privregs->lid) >> 16)
#define VLAPIC_IRR(l) ((l)->vcpu->arch.privregs->irr[0])
-struct vlapic* apic_round_robin(struct domain *d, uint8_t dest_mode, uint8_t vector, uint32_t bitmap);
-extern int vmx_vcpu_pend_interrupt(struct vcpu *vcpu, uint8_t vector);
+struct vlapic *apic_round_robin(struct domain *d, uint8_t vector, uint32_t bitmap);
+extern int vmx_vlapic_set_irq(struct vcpu *v, uint8_t vec, uint8_t trig);
static inline int vlapic_set_irq(struct vlapic *t, uint8_t vec, uint8_t trig)
{
- return vmx_vcpu_pend_interrupt(t->vcpu, vec);
+ return vmx_vlapic_set_irq(t->vcpu, vec, trig);
}
enum ioapic_irq_destination_types {
@@ -71,9 +73,7 @@ enum ioapic_irq_destination_types {
dest_ExtINT = 7
};
-/* As long as we register vlsapic to ioapic controller, it's said enabled */
#define vlapic_enabled(l) 1
-#define hvm_apic_support(d) 1
#define VLAPIC_DELIV_MODE_FIXED 0x0
#define VLAPIC_DELIV_MODE_REDIR 0x1
diff --git a/xen/include/asm-ia64/vmx_uaccess.h b/xen/include/asm-ia64/vmx_uaccess.h
deleted file mode 100644
index a6e27425f6..0000000000
--- a/xen/include/asm-ia64/vmx_uaccess.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
-/*
- * vmx_uaccess.h: Defines vmx specific macros to transfer memory areas
- * across the domain/hypervisor boundary.
- *
- * 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.
- *
- * Note: For vmx enabled environment, poor man's policy is actually
- * useless since HV resides in completely different address space as
- * domain. So the only way to do the access is search vTLB first, and
- * access identity mapped address if hit.
- *
- * Copyright (c) 2004, Intel Corporation.
- * Kun Tian (Kevin Tian) (kevin.tian@intel.com)
- */
-
-#ifndef __ASM_IA64_VMX_UACCESS_H__
-#define __ASM_IA64_VMX_UACCESS_H__
-
-#include <xen/compiler.h>
-#include <xen/errno.h>
-#include <xen/sched.h>
-
-#include <asm/intrinsics.h>
-#include <asm/vmmu.h>
-
-/* Since HV never accesses domain space directly, most security check can
- * be dummy now
- */
-asm (".section \"__ex_table\", \"a\"\n\t.previous");
-
-/* For back compatibility */
-#define __access_ok(addr, size, segment) 1
-#define access_ok(addr, size, segment) __access_ok((addr), (size), (segment))
-
-/*
- * These are the main single-value transfer routines. They automatically
- * use the right size if we just have the right pointer type.
- *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
- */
-#define put_user(x, ptr) __put_user((x), (ptr))
-#define get_user(x, ptr) __get_user((x), (ptr))
-
-#define __put_user(x, ptr) __do_put_user((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr)))
-#define __get_user(x, ptr) __do_get_user((x), (ptr), sizeof(*(ptr)))
-
-/* TODO: add specific unaligned access later. If assuming aligned at
- * 1,2,4,8 bytes by far, it's impossible for operand spaning two
- * vTLB entry
- */
-extern long
-__domain_va_to_ma(unsigned long va, unsigned long* ma, unsigned long *len);
-
-#define __do_put_user(x, ptr, size) \
-({ \
- __typeof__ (x) __pu_x = (x); \
- __typeof__ (*(ptr)) __user *__pu_ptr = (ptr); \
- __typeof__ (size) __pu_size = (size); \
- unsigned long __pu_ma; \
- long __pu_err; \
- \
- __pu_err = __domain_va_to_ma((unsigned long)__pu_ptr, \
- &__pu_ma, &__pu_size); \
- __pu_err ? (__pu_err = -EFAULT) : \
- (*((__typeof__ (*(ptr)) *)__va(__pu_ma)) = x); \
- __pu_err; \
-})
-
-#define __do_get_user(x, ptr, size) \
-({ \
- __typeof__ (x) __gu_x = (x); \
- __typeof__ (*(ptr)) __user *__gu_ptr = (ptr); \
- __typeof__ (size) __gu_size = (size); \
- unsigned long __gu_ma; \
- long __gu_err; \
- \
- __gu_err = __domain_va_to_ma((unsigned long)__gu_ptr, \
- &__gu_ma, &__gu_size); \
- __gu_err ? (__gu_err = -EFAULT) : \
- (x = *((__typeof__ (*(ptr)) *)__va(__gu_ma))); \
- __gu_err; \
-})
-
-/* More complex copy from domain */
-#define copy_from_user(to, from, n) __copy_from_user((to), (from), (n))
-#define copy_to_user(to, from, n) __copy_to_user((to), (from), (n))
-#define clear_user(to, n) __clear_user((t0), (n))
-
-static inline unsigned long
-__copy_from_user(void *to, void *from, unsigned long n)
-{
- unsigned long ma, i;
-
- i = n;
- while(!__domain_va_to_ma((unsigned long)from, &ma, &i)) {
- memcpy(to, (void *)__va(ma), i);
- n -= i;
- if (!n)
- break;
- from += i;
- to += i;
- i = n;
- }
- return n;
-}
-
-static inline unsigned long
-__copy_to_user(void *to, void *from, unsigned long n)
-{
- unsigned long ma, i;
-
- i = n;
- while(!__domain_va_to_ma((unsigned long)to, &ma, &i)) {
- memcpy((void *)__va(ma), from, i);
- n -= i;
- if (!n)
- break;
- from += i;
- to += i;
- i = n;
- }
- return n;
-}
-
-static inline unsigned long
-__clear_user(void *to, unsigned long n)
-{
- unsigned long ma, i;
-
- i = n;
- while(!__domain_va_to_ma((unsigned long)to, &ma, &i)) {
- memset((void *)__va(ma), 0, i);
- n -= i;
- if (!n)
- break;
- to += i;
- i = n;
- }
- return n;
-}
-
-#endif // __ASM_IA64_VMX_UACCESS_H__
diff --git a/xen/include/asm-ia64/vmx_vcpu.h b/xen/include/asm-ia64/vmx_vcpu.h
index a82e31fb7f..0defc0d4f4 100644
--- a/xen/include/asm-ia64/vmx_vcpu.h
+++ b/xen/include/asm-ia64/vmx_vcpu.h
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:nil -*- */
/*
* vmx_vcpu.h:
* Copyright (c) 2005, Intel Corporation.
@@ -23,7 +23,6 @@
#ifndef _XEN_IA64_VMX_VCPU_H
#define _XEN_IA64_VMX_VCPU_H
-
#include <xen/sched.h>
#include <asm/ia64_int.h>
#include <asm/vmx_vpd.h>
@@ -33,462 +32,438 @@
#include <asm/types.h>
#include <asm/vcpu.h>
-#define VRN_SHIFT 61
-#define VRN0 0x0UL
-#define VRN1 0x1UL
-#define VRN2 0x2UL
-#define VRN3 0x3UL
-#define VRN4 0x4UL
-#define VRN5 0x5UL
-#define VRN6 0x6UL
-#define VRN7 0x7UL
+#define VRN_SHIFT 61
+#define VRN0 0x0UL
+#define VRN1 0x1UL
+#define VRN2 0x2UL
+#define VRN3 0x3UL
+#define VRN4 0x4UL
+#define VRN5 0x5UL
+#define VRN6 0x6UL
+#define VRN7 0x7UL
// for vlsapic
-#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i])
+#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i])
#define VMX(x,y) ((x)->arch.arch_vmx.y)
+#define VMM_RR_SHIFT 20
+#define VMM_RR_MASK ((1UL<<VMM_RR_SHIFT)-1)
-#define VMM_RR_SHIFT 20
-#define VMM_RR_MASK ((1UL<<VMM_RR_SHIFT)-1)
-
-extern u64 indirect_reg_igfld_MASK ( int type, int index, u64 value);
-extern u64 cr_igfld_mask (int index, u64 value);
-extern int check_indirect_reg_rsv_fields ( int type, int index, u64 value );
-extern u64 set_isr_ei_ni (VCPU *vcpu);
-extern u64 set_isr_for_na_inst(VCPU *vcpu, int op);
-
+extern u64 indirect_reg_igfld_MASK(int type, int index, u64 value);
+extern u64 cr_igfld_mask(int index, u64 value);
+extern int check_indirect_reg_rsv_fields(int type, int index, u64 value);
+extern u64 set_isr_ei_ni(VCPU * vcpu);
+extern u64 set_isr_for_na_inst(VCPU * vcpu, int op);
/* next all for VTI domain APIs definition */
-extern void vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value);
-extern UINT64 vmx_vcpu_sync_mpsr(UINT64 mipsr, UINT64 value);
-extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, UINT64 value);
-extern IA64FAULT vmx_vcpu_cover(VCPU *vcpu);
-extern IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val);
-extern IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval);
-IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val);
-extern IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vmx_vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, UINT64 itir, UINT64 ifa);
-extern IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 ps);
-extern IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 ps);
-extern IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 ps);
-extern IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 vadr);
-extern IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 ps);
-extern IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 ps);
-extern IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval);
-extern u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa);
-extern IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval);
-extern IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr);
-extern IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key);
-extern IA64FAULT vmx_vcpu_rfi(VCPU *vcpu);
-extern UINT64 vmx_vcpu_get_psr(VCPU *vcpu);
-extern IA64FAULT vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val);
-extern IA64FAULT vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat);
+extern void vmx_vcpu_set_psr(VCPU * vcpu, unsigned long value);
+extern u64 vmx_vcpu_sync_mpsr(u64 mipsr, u64 value);
+extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, u64 value);
+extern IA64FAULT vmx_vcpu_cover(VCPU * vcpu);
+extern IA64FAULT vmx_vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vmx_vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval);
+IA64FAULT vmx_vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val);
+extern IA64FAULT vmx_vcpu_itc_i(VCPU * vcpu, u64 pte, u64 itir, u64 ifa);
+extern IA64FAULT vmx_vcpu_itc_d(VCPU * vcpu, u64 pte, u64 itir, u64 ifa);
+extern IA64FAULT vmx_vcpu_itr_i(VCPU * vcpu, u64 slot, u64 pte, u64 itir,
+ u64 ifa);
+extern IA64FAULT vmx_vcpu_itr_d(VCPU * vcpu, u64 slot, u64 pte, u64 itir,
+ u64 ifa);
+extern IA64FAULT vmx_vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 ps);
+extern IA64FAULT vmx_vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 ps);
+extern IA64FAULT vmx_vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 ps);
+extern IA64FAULT vmx_vcpu_ptc_e(VCPU * vcpu, u64 vadr);
+extern IA64FAULT vmx_vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 ps);
+extern IA64FAULT vmx_vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 ps);
+extern IA64FAULT vmx_vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval);
+extern u64 vmx_vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa);
+extern IA64FAULT vmx_vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * pval);
+extern IA64FAULT vmx_vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr);
+extern IA64FAULT vmx_vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key);
+extern IA64FAULT vmx_vcpu_rfi(VCPU * vcpu);
+extern u64 vmx_vcpu_get_psr(VCPU * vcpu);
+extern IA64FAULT vmx_vcpu_get_bgr(VCPU * vcpu, unsigned int reg, u64 * val);
+extern IA64FAULT vmx_vcpu_set_bgr(VCPU * vcpu, unsigned int reg, u64 val,
+ int nat);
#if 0
-extern IA64FAULT vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val);
-extern IA64FAULT vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat);
+extern IA64FAULT vmx_vcpu_get_gr(VCPU * vcpu, unsigned reg, u64 * val);
+extern IA64FAULT vmx_vcpu_set_gr(VCPU * vcpu, unsigned reg, u64 value, int nat);
#endif
-extern IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24);
-extern IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24);
-extern IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val);
-extern void vtm_init(VCPU *vcpu);
-extern uint64_t vtm_get_itc(VCPU *vcpu);
-extern void vtm_set_itc(VCPU *vcpu, uint64_t new_itc);
-extern void vtm_set_itv(VCPU *vcpu, uint64_t val);
-extern void vtm_set_itm(VCPU *vcpu, uint64_t val);
-extern void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm);
+extern IA64FAULT vmx_vcpu_reset_psr_sm(VCPU * vcpu, u64 imm24);
+extern IA64FAULT vmx_vcpu_set_psr_sm(VCPU * vcpu, u64 imm24);
+extern IA64FAULT vmx_vcpu_set_psr_l(VCPU * vcpu, u64 val);
+extern void vtm_init(VCPU * vcpu);
+extern uint64_t vtm_get_itc(VCPU * vcpu);
+extern void vtm_set_itc(VCPU * vcpu, uint64_t new_itc);
+extern void vtm_set_itv(VCPU * vcpu, uint64_t val);
+extern void vtm_set_itm(VCPU * vcpu, uint64_t val);
+extern void vtm_interruption_update(VCPU * vcpu, vtime_t * vtm);
//extern void vtm_domain_out(VCPU *vcpu);
//extern void vtm_domain_in(VCPU *vcpu);
-extern void vlsapic_reset(VCPU *vcpu);
-extern int vmx_check_pending_irq(VCPU *vcpu);
-extern void guest_write_eoi(VCPU *vcpu);
-extern int is_unmasked_irq(VCPU *vcpu);
-extern uint64_t guest_read_vivr(VCPU *vcpu);
-extern void vmx_inject_vhpi(VCPU *vcpu, u8 vec);
-extern int vmx_vcpu_pend_interrupt(VCPU *vcpu, uint8_t vector);
-extern struct virtual_platform_def *vmx_vcpu_get_plat(VCPU *vcpu);
-extern void memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s);
-extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s);
-extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s);
-extern void memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s);
-extern void vcpu_load_kernel_regs(VCPU *vcpu);
-extern IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu);
-extern void vmx_switch_rr7(unsigned long ,shared_info_t*,void *,void *,void *);
-
-extern void dtlb_fault (VCPU *vcpu, u64 vadr);
-extern void nested_dtlb (VCPU *vcpu);
-extern void alt_dtlb (VCPU *vcpu, u64 vadr);
-extern void dvhpt_fault (VCPU *vcpu, u64 vadr);
-extern void dnat_page_consumption (VCPU *vcpu, uint64_t vadr);
-extern void page_not_present(VCPU *vcpu, u64 vadr);
-extern void data_access_rights(VCPU *vcpu, u64 vadr);
+extern void vlsapic_reset(VCPU * vcpu);
+extern int vmx_check_pending_irq(VCPU * vcpu);
+extern void guest_write_eoi(VCPU * vcpu);
+extern int is_unmasked_irq(VCPU * vcpu);
+extern uint64_t guest_read_vivr(VCPU * vcpu);
+extern void vmx_inject_vhpi(VCPU * vcpu, u8 vec);
+extern int vmx_vcpu_pend_interrupt(VCPU * vcpu, uint8_t vector);
+extern struct virtual_platform_def *vmx_vcpu_get_plat(VCPU * vcpu);
+extern void memread_p(VCPU * vcpu, u64 * src, u64 * dest, size_t s);
+extern void memread_v(VCPU * vcpu, thash_data_t * vtlb, u64 * src, u64 * dest,
+ size_t s);
+extern void memwrite_v(VCPU * vcpu, thash_data_t * vtlb, u64 * src, u64 * dest,
+ size_t s);
+extern void memwrite_p(VCPU * vcpu, u64 * src, u64 * dest, size_t s);
+extern void vcpu_load_kernel_regs(VCPU * vcpu);
+extern IA64FAULT vmx_vcpu_increment_iip(VCPU * vcpu);
+extern IA64FAULT vmx_vcpu_decrement_iip(VCPU * vcpu);
+extern void vmx_switch_rr7(unsigned long, shared_info_t *, void *, void *,
+ void *);
+
+extern void dtlb_fault(VCPU * vcpu, u64 vadr);
+extern void nested_dtlb(VCPU * vcpu);
+extern void alt_dtlb(VCPU * vcpu, u64 vadr);
+extern void dvhpt_fault(VCPU * vcpu, u64 vadr);
+extern void dnat_page_consumption(VCPU * vcpu, uint64_t vadr);
+extern void data_page_not_present(VCPU * vcpu, u64 vadr);
+extern void inst_page_not_present(VCPU * vcpu, u64 vadr);
+extern void data_access_rights(VCPU * vcpu, u64 vadr);
/**************************************************************************
VCPU control register access routines
**************************************************************************/
-static inline
-IA64FAULT vmx_vcpu_get_dcr(VCPU *vcpu, UINT64 *pval)
+static inline IA64FAULT vmx_vcpu_get_dcr(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,dcr);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, dcr);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_itm(VCPU *vcpu, UINT64 *pval)
+static inline IA64FAULT vmx_vcpu_get_itm(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,itm);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, itm);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_iva(VCPU *vcpu, UINT64 *pval)
+static inline IA64FAULT vmx_vcpu_get_iva(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,iva);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, iva);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_pta(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_pta(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,pta);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, pta);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_lid(VCPU *vcpu, UINT64 *pval)
+static inline IA64FAULT vmx_vcpu_get_lid(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,lid);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, lid);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_ivr(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_ivr(VCPU * vcpu, u64 * pval)
{
- *pval = guest_read_vivr(vcpu);
- return (IA64_NO_FAULT);
+ *pval = guest_read_vivr(vcpu);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_tpr(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_tpr(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,tpr);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, tpr);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_eoi(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_eoi(VCPU * vcpu, u64 * pval)
{
- *pval = 0L; // reads of eoi always return 0
- return (IA64_NO_FAULT);
+ *pval = 0L; // reads of eoi always return 0
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_irr0(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_irr0(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,irr[0]);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, irr[0]);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_irr1(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_irr1(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,irr[1]);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, irr[1]);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_irr2(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_irr2(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,irr[2]);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, irr[2]);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_irr3(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_irr3(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,irr[3]);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, irr[3]);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_itv(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_itv(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,itv);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, itv);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_pmv(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_pmv(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,pmv);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, pmv);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_cmcv(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,cmcv);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, cmcv);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_lrr0(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,lrr0);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, lrr0);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_lrr1(VCPU * vcpu, u64 * pval)
{
- *pval = VCPU(vcpu,lrr1);
- return (IA64_NO_FAULT);
+ *pval = VCPU(vcpu, lrr1);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_dcr(VCPU *vcpu, u64 val)
-{
- u64 mdcr, mask;
- VCPU(vcpu,dcr)=val;
- /* All vDCR bits will go to mDCR, except for be/pp/dm bits */
- mdcr = ia64_get_dcr();
- /* Machine dcr.dm masked to handle guest ld.s on tr mapped page */
- mask = IA64_DCR_BE | IA64_DCR_PP | IA64_DCR_DM;
- mdcr = ( mdcr & mask ) | ( val & (~mask) );
- ia64_set_dcr( mdcr);
- VMX(vcpu, mdcr) = mdcr;
- return IA64_NO_FAULT;
+
+static inline IA64FAULT vmx_vcpu_set_dcr(VCPU * vcpu, u64 val)
+{
+ u64 mdcr, mask;
+ VCPU(vcpu, dcr) = val;
+ /* All vDCR bits will go to mDCR, except for be/pp/dm bits */
+ mdcr = ia64_get_dcr();
+ /* Machine dcr.dm masked to handle guest ld.s on tr mapped page */
+ mask = IA64_DCR_BE | IA64_DCR_PP | IA64_DCR_DM;
+ mdcr = (mdcr & mask) | (val & (~mask));
+ ia64_set_dcr(mdcr);
+ VMX(vcpu, mdcr) = mdcr;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_itm(VCPU *vcpu, u64 val)
+static inline IA64FAULT vmx_vcpu_set_itm(VCPU * vcpu, u64 val)
{
- vtm_set_itm(vcpu, val);
- return IA64_NO_FAULT;
+ vtm_set_itm(vcpu, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_iva(VCPU *vcpu, u64 val)
+
+static inline IA64FAULT vmx_vcpu_set_iva(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,iva)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, iva) = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_pta(VCPU *vcpu, u64 val)
+static inline IA64FAULT vmx_vcpu_set_pta(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,pta)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, pta) = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_lid(VCPU *vcpu, u64 val)
+static inline IA64FAULT vmx_vcpu_set_lid(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,lid)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, lid) = val;
+ return IA64_NO_FAULT;
}
-extern IA64FAULT vmx_vcpu_set_tpr(VCPU *vcpu, u64 val);
+extern IA64FAULT vmx_vcpu_set_tpr(VCPU * vcpu, u64 val);
-static inline
-IA64FAULT
-vmx_vcpu_set_eoi(VCPU *vcpu, u64 val)
+static inline IA64FAULT vmx_vcpu_set_eoi(VCPU * vcpu, u64 val)
{
- guest_write_eoi(vcpu);
- return IA64_NO_FAULT;
+ guest_write_eoi(vcpu);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_itv(VCPU *vcpu, u64 val)
+static inline IA64FAULT vmx_vcpu_set_itv(VCPU * vcpu, u64 val)
{
- vtm_set_itv(vcpu, val);
- return IA64_NO_FAULT;
+ vtm_set_itv(vcpu, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_pmv(VCPU *vcpu, u64 val)
+
+static inline IA64FAULT vmx_vcpu_set_pmv(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,pmv)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, pmv) = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_cmcv(VCPU *vcpu, u64 val)
+
+static inline IA64FAULT vmx_vcpu_set_cmcv(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,cmcv)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, cmcv) = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_lrr0(VCPU *vcpu, u64 val)
+
+static inline IA64FAULT vmx_vcpu_set_lrr0(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,lrr0)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, lrr0) = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT
-vmx_vcpu_set_lrr1(VCPU *vcpu, u64 val)
+
+static inline IA64FAULT vmx_vcpu_set_lrr1(VCPU * vcpu, u64 val)
{
- VCPU(vcpu,lrr1)=val;
- return IA64_NO_FAULT;
+ VCPU(vcpu, lrr1) = val;
+ return IA64_NO_FAULT;
}
-
-
-
/**************************************************************************
VCPU privileged application register access routines
**************************************************************************/
-static inline
-IA64FAULT vmx_vcpu_set_itc(VCPU *vcpu, UINT64 val)
+static inline IA64FAULT vmx_vcpu_set_itc(VCPU * vcpu, u64 val)
{
- vtm_set_itc(vcpu, val);
- return IA64_NO_FAULT;
+ vtm_set_itc(vcpu, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_itc(VCPU *vcpu,UINT64 *val)
+
+static inline IA64FAULT vmx_vcpu_get_itc(VCPU * vcpu, u64 * val)
{
- *val = vtm_get_itc(vcpu);
- return IA64_NO_FAULT;
+ *val = vtm_get_itc(vcpu);
+ return IA64_NO_FAULT;
}
+
/*
static inline
-IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, u64 reg, u64 *pval)
{
*pval = VMX(vcpu,vrr[reg>>61]);
- return (IA64_NO_FAULT);
+ return IA64_NO_FAULT;
}
*/
/**************************************************************************
VCPU debug breakpoint register access routines
**************************************************************************/
-static inline
-IA64FAULT vmx_vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+static inline IA64FAULT vmx_vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval)
{
- // TODO: unimplemented DBRs return a reserved register fault
- // TODO: Should set Logical CPU state, not just physical
- if(reg > 4){
- panic_domain(vcpu_regs(vcpu),"there are only five cpuid registers");
- }
- *pval=VCPU(vcpu,vcpuid[reg]);
- return (IA64_NO_FAULT);
+ // TODO: unimplemented DBRs return a reserved register fault
+ // TODO: Should set Logical CPU state, not just physical
+ if (reg > 4) {
+ panic_domain(vcpu_regs(vcpu),
+ "there are only five cpuid registers");
+ }
+ *pval = VCPU(vcpu, vcpuid[reg]);
+ return IA64_NO_FAULT;
}
-
-static inline
-IA64FAULT vmx_vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val)
+static inline IA64FAULT vmx_vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val)
{
- // TODO: unimplemented DBRs return a reserved register fault
- // TODO: Should set Logical CPU state, not just physical
- ia64_set_dbr(reg,val);
- return (IA64_NO_FAULT);
+ // TODO: unimplemented DBRs return a reserved register fault
+ // TODO: Should set Logical CPU state, not just physical
+ ia64_set_dbr(reg, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val)
+
+static inline IA64FAULT vmx_vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val)
{
- // TODO: unimplemented IBRs return a reserved register fault
- // TODO: Should set Logical CPU state, not just physical
- ia64_set_ibr(reg,val);
- return (IA64_NO_FAULT);
+ // TODO: unimplemented IBRs return a reserved register fault
+ // TODO: Should set Logical CPU state, not just physical
+ ia64_set_ibr(reg, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval)
{
- // TODO: unimplemented DBRs return a reserved register fault
- UINT64 val = ia64_get_dbr(reg);
- *pval = val;
- return (IA64_NO_FAULT);
+ // TODO: unimplemented DBRs return a reserved register fault
+ u64 val = ia64_get_dbr(reg);
+ *pval = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval)
{
- // TODO: unimplemented IBRs return a reserved register fault
- UINT64 val = ia64_get_ibr(reg);
- *pval = val;
- return (IA64_NO_FAULT);
+ // TODO: unimplemented IBRs return a reserved register fault
+ u64 val = ia64_get_ibr(reg);
+ *pval = val;
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU performance monitor register access routines
**************************************************************************/
-static inline
-IA64FAULT vmx_vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val)
+static inline IA64FAULT vmx_vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val)
{
- // TODO: Should set Logical CPU state, not just physical
- // NOTE: Writes to unimplemented PMC registers are discarded
- ia64_set_pmc(reg,val);
- return (IA64_NO_FAULT);
+ // TODO: Should set Logical CPU state, not just physical
+ // NOTE: Writes to unimplemented PMC registers are discarded
+ ia64_set_pmc(reg, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val)
+
+static inline IA64FAULT vmx_vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val)
{
- // TODO: Should set Logical CPU state, not just physical
- // NOTE: Writes to unimplemented PMD registers are discarded
- ia64_set_pmd(reg,val);
- return (IA64_NO_FAULT);
+ // TODO: Should set Logical CPU state, not just physical
+ // NOTE: Writes to unimplemented PMD registers are discarded
+ ia64_set_pmd(reg, val);
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval)
{
- // NOTE: Reads from unimplemented PMC registers return zero
- UINT64 val = (UINT64)ia64_get_pmc(reg);
- *pval = val;
- return (IA64_NO_FAULT);
+ // NOTE: Reads from unimplemented PMC registers return zero
+ u64 val = (u64) ia64_get_pmc(reg);
+ *pval = val;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+
+static inline IA64FAULT vmx_vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval)
{
- // NOTE: Reads from unimplemented PMD registers return zero
- UINT64 val = (UINT64)ia64_get_pmd(reg);
- *pval = val;
- return (IA64_NO_FAULT);
+ // NOTE: Reads from unimplemented PMD registers return zero
+ u64 val = (u64) ia64_get_pmd(reg);
+ *pval = val;
+ return IA64_NO_FAULT;
}
/**************************************************************************
VCPU banked general register access routines
**************************************************************************/
#if 0
-static inline
-IA64FAULT vmx_vcpu_bsw0(VCPU *vcpu)
+static inline IA64FAULT vmx_vcpu_bsw0(VCPU * vcpu)
{
- VCPU(vcpu,vpsr) &= ~IA64_PSR_BN;
- return (IA64_NO_FAULT);
+ VCPU(vcpu, vpsr) &= ~IA64_PSR_BN;
+ return IA64_NO_FAULT;
}
-static inline
-IA64FAULT vmx_vcpu_bsw1(VCPU *vcpu)
+
+static inline IA64FAULT vmx_vcpu_bsw1(VCPU * vcpu)
{
- VCPU(vcpu,vpsr) |= IA64_PSR_BN;
- return (IA64_NO_FAULT);
+ VCPU(vcpu, vpsr) |= IA64_PSR_BN;
+ return IA64_NO_FAULT;
}
#endif
#if 0
/* Another hash performance algorithm */
#define redistribute_rid(rid) (((rid) & ~0xffff) | (((rid) << 8) & 0xff00) | (((rid) >> 8) & 0xff))
#endif
-static inline unsigned long
-vrrtomrr(VCPU *v, unsigned long val)
+static inline unsigned long vrrtomrr(VCPU * v, unsigned long val)
{
- ia64_rr rr;
+ ia64_rr rr;
- rr.rrval=val;
- rr.rid = rr.rid + v->arch.starting_rid;
- if (rr.ps > PAGE_SHIFT)
- rr.ps = PAGE_SHIFT;
- rr.ve = 1;
- return vmMangleRID(rr.rrval);
+ rr.rrval = val;
+ rr.rid = rr.rid + v->arch.starting_rid;
+ if (rr.ps > PAGE_SHIFT)
+ rr.ps = PAGE_SHIFT;
+ rr.ve = 1;
+ return vmMangleRID(rr.rrval);
/* Disable this rid allocation algorithm for now */
#if 0
- rid=(((u64)vcpu->domain->domain_id)<<DOMAIN_RID_SHIFT) + rr.rid;
- rr.rid = redistribute_rid(rid);
-#endif
+ rid = (((u64) vcpu->domain->domain_id) << DOMAIN_RID_SHIFT) + rr.rid;
+ rr.rid = redistribute_rid(rid);
+#endif
}
-static inline thash_cb_t *
-vmx_vcpu_get_vtlb(VCPU *vcpu)
+static inline thash_cb_t *vmx_vcpu_get_vtlb(VCPU * vcpu)
{
- return &vcpu->arch.vtlb;
+ return &vcpu->arch.vtlb;
}
-static inline thash_cb_t *
-vcpu_get_vhpt(VCPU *vcpu)
+static inline thash_cb_t *vcpu_get_vhpt(VCPU * vcpu)
{
- return &vcpu->arch.vhpt;
+ return &vcpu->arch.vhpt;
}
#endif
diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h
index b534268ebb..17496d25f2 100644
--- a/xen/include/asm-ia64/vmx_vpd.h
+++ b/xen/include/asm-ia64/vmx_vpd.h
@@ -116,7 +116,6 @@ struct arch_vmx_struct {
#define VMX_DOMAIN(v) v->arch.arch_vmx.flags
#define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */
-#define ARCH_VMX_INTR_ASSIST 4 /* Need DM's assist to issue intr */
#define ARCH_VMX_DOMAIN 5 /* Need it to indicate VTi domain */
@@ -140,6 +139,7 @@ extern unsigned int opt_vmx_debug_level;
#define VPD_VPR_START_OFFSET 1432
#define VPD_VRSE_CFLE_START_OFFSET 1440
#define VPD_VCR_START_OFFSET 2048
+#define VPD_VTPR_START_OFFSET 2576
#define VPD_VRR_START_OFFSET 3072
#define VPD_VMM_VAIL_START_OFFSET 31744
diff --git a/xen/include/asm-ia64/vtm.h b/xen/include/asm-ia64/vtm.h
index 419d937fb5..dde6764497 100644
--- a/xen/include/asm-ia64/vtm.h
+++ b/xen/include/asm-ia64/vtm.h
@@ -33,7 +33,8 @@
typedef struct vtime {
long vtm_offset; // guest ITC = host ITC + vtm_offset
uint64_t vtm_local_drift;
- uint64_t last_itc;
+ uint64_t last_itc;
+ uint64_t pending;
/*
* Local drift (temporary) after guest suspension
* In case of long jump amount of ITC after suspension,
diff --git a/xen/include/asm-ia64/xenkregs.h b/xen/include/asm-ia64/xenkregs.h
index dcfaf65d6b..d2dcd2bc84 100644
--- a/xen/include/asm-ia64/xenkregs.h
+++ b/xen/include/asm-ia64/xenkregs.h
@@ -7,8 +7,7 @@
#define IA64_TR_SHARED_INFO 3 /* dtr3: page shared with domain */
#define IA64_TR_VHPT 4 /* dtr4: vhpt */
#define IA64_TR_MAPPED_REGS 5 /* dtr5: vcpu mapped regs */
-#define IA64_TR_PERVP_VHPT 6
-#define IA64_DTR_GUEST_KERNEL 7
+#define IA64_DTR_GUEST_KERNEL 6
#define IA64_ITR_GUEST_KERNEL 2
/* Processor status register bits: */
#define IA64_PSR_VM_BIT 46
diff --git a/xen/include/asm-ia64/xenpage.h b/xen/include/asm-ia64/xenpage.h
index f5b0f74e70..a9dc9b4a68 100644
--- a/xen/include/asm-ia64/xenpage.h
+++ b/xen/include/asm-ia64/xenpage.h
@@ -1,10 +1,6 @@
#ifndef _ASM_IA64_XENPAGE_H
#define _ASM_IA64_XENPAGE_H
-#ifdef CONFIG_DISCONTIGMEM
-#error "xenpage.h: page macros need to be defined for CONFIG_DISCONTIGMEM"
-#endif
-
#undef mfn_valid
#undef page_to_mfn
#undef mfn_to_page
diff --git a/xen/include/asm-ia64/xensystem.h b/xen/include/asm-ia64/xensystem.h
index d7c40e1735..d966d1917b 100644
--- a/xen/include/asm-ia64/xensystem.h
+++ b/xen/include/asm-ia64/xensystem.h
@@ -22,7 +22,6 @@
#define GATE_ADDR KERNEL_START
#define DEFAULT_SHAREDINFO_ADDR 0xf100000000000000
#define PERCPU_ADDR (DEFAULT_SHAREDINFO_ADDR - PERCPU_PAGE_SIZE)
-#define VHPT_ADDR 0xf200000000000000
#ifdef CONFIG_VIRTUAL_FRAME_TABLE
#define VIRT_FRAME_TABLE_ADDR 0xf300000000000000
#define VIRT_FRAME_TABLE_END 0xf400000000000000
diff --git a/xen/include/asm-powerpc/mm.h b/xen/include/asm-powerpc/mm.h
index b6dc8df34e..7d085c9dd4 100644
--- a/xen/include/asm-powerpc/mm.h
+++ b/xen/include/asm-powerpc/mm.h
@@ -102,14 +102,6 @@ struct page_extents {
#define _PGT_validated 27
#define PGT_validated (1U<<_PGT_validated)
- /* The 27 most significant bits of virt address if this is a page table. */
-#define PGT_va_shift 32
-#define PGT_va_mask ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer still mutable (i.e. not fixed yet)? */
-#define PGT_va_mutable ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown ((unsigned long)((1U<<28)-2)<<PGT_va_shift)
-
/* 16-bit count of uses of this frame as its current type. */
#define PGT_count_mask ((1U<<16)-1)
diff --git a/xen/include/asm-powerpc/powerpc64/config.h b/xen/include/asm-powerpc/powerpc64/config.h
index cf16dac479..86183d1441 100644
--- a/xen/include/asm-powerpc/powerpc64/config.h
+++ b/xen/include/asm-powerpc/powerpc64/config.h
@@ -36,10 +36,4 @@
#define HAS_FLOAT 1
#define HAS_VMX 1
-#ifndef __ASSEMBLY__
-
-#define FORCE_CRASH() __asm__ __volatile__ ( "trap" )
-
-#endif /* __ASSEMBLY__ */
-
#endif
diff --git a/xen/include/asm-powerpc/spinlock.h b/xen/include/asm-powerpc/spinlock.h
index f6574d6b76..e65e0f2bc0 100644
--- a/xen/include/asm-powerpc/spinlock.h
+++ b/xen/include/asm-powerpc/spinlock.h
@@ -81,10 +81,10 @@ typedef union {
#define __UNLOCKED (0U)
#define __LOCKED (~__UNLOCKED)
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { __UNLOCKED }
+#define SPIN_LOCK_UNLOCKED /*(spinlock_t)*/ { __UNLOCKED }
static inline void spin_lock_init(spinlock_t *lock)
{
- *lock = SPIN_LOCK_UNLOCKED;
+ *lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
}
static inline int spin_is_locked(spinlock_t *lock)
@@ -103,7 +103,7 @@ static inline void _raw_spin_lock(spinlock_t *lock)
static inline void _raw_spin_unlock(spinlock_t *lock)
{
sync_before_release();
- *lock = SPIN_LOCK_UNLOCKED;
+ *lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
}
static inline int _raw_spin_trylock(spinlock_t *lock)
@@ -121,10 +121,10 @@ typedef struct {
volatile unsigned int lock;
} rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { __UNLOCKED }
+#define RW_LOCK_UNLOCKED /*(rwlock_t)*/ { __UNLOCKED }
static inline void rwlock_init(rwlock_t *lock)
{
- *lock = RW_LOCK_UNLOCKED;
+ *lock = (rwlock_t) RW_LOCK_UNLOCKED;
}
static inline void _raw_read_lock(rwlock_t *lock)
@@ -152,7 +152,7 @@ static inline void _raw_write_lock(rwlock_t *lock)
static inline void _raw_write_unlock(rwlock_t *lock)
{
sync_before_release();
- *lock = RW_LOCK_UNLOCKED;
+ *lock = (rwlock_t) RW_LOCK_UNLOCKED;
}
static inline void _raw_read_unlock(rwlock_t *lock)
diff --git a/xen/include/asm-x86/acpi.h b/xen/include/asm-x86/acpi.h
index 51c4b8e293..227f76325c 100644
--- a/xen/include/asm-x86/acpi.h
+++ b/xen/include/asm-x86/acpi.h
@@ -157,6 +157,9 @@ static inline void check_acpi_pci(void) { }
static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
static inline int acpi_irq_balance_set(char *str) { return 0; }
+extern int acpi_scan_nodes(u64 start, u64 end);
+extern int acpi_numa;
+#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
#ifdef CONFIG_ACPI_SLEEP
@@ -173,5 +176,6 @@ extern void acpi_reserve_bootmem(void);
#endif /*CONFIG_ACPI_SLEEP*/
extern u8 x86_acpiid_to_apicid[];
+#define MAX_LOCAL_APIC 256
#endif /*_ASM_ACPI_H*/
diff --git a/xen/include/asm-x86/apicdef.h b/xen/include/asm-x86/apicdef.h
index 272ed8c08c..c8a6e161c1 100644
--- a/xen/include/asm-x86/apicdef.h
+++ b/xen/include/asm-x86/apicdef.h
@@ -40,6 +40,7 @@
#define APIC_SPIV_FOCUS_DISABLED (1<<9)
#define APIC_SPIV_APIC_ENABLED (1<<8)
#define APIC_ISR 0x100
+#define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */
#define APIC_TMR 0x180
#define APIC_IRR 0x200
#define APIC_ESR 0x280
diff --git a/xen/include/asm-x86/bitops.h b/xen/include/asm-x86/bitops.h
index 14d7e1451b..a1e0754b82 100644
--- a/xen/include/asm-x86/bitops.h
+++ b/xen/include/asm-x86/bitops.h
@@ -14,10 +14,12 @@
#endif
/*
- * We use the "+m" constraint because the memory operand is both read from
- * and written to. Since the operand is in fact a word array, we also
- * specify "memory" in the clobbers list to indicate that words other than
- * the one directly addressed by the memory operand may be modified.
+ * We specify the memory operand as both input and output because the memory
+ * operand is both read from and written to. Since the operand is in fact a
+ * word array, we also specify "memory" in the clobbers list to indicate that
+ * words other than the one directly addressed by the memory operand may be
+ * modified. We don't use "+m" because the gcc manual says that it should be
+ * used only when the constraint allows the operand to reside in a register.
*/
#define ADDR (*(volatile long *) addr)
@@ -36,8 +38,8 @@ static __inline__ void set_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btsl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
/**
@@ -53,8 +55,8 @@ static __inline__ void __set_bit(int nr, volatile void * addr)
{
__asm__(
"btsl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
/**
@@ -71,8 +73,8 @@ static __inline__ void clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btrl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
/**
@@ -88,8 +90,8 @@ static __inline__ void __clear_bit(int nr, volatile void * addr)
{
__asm__(
"btrl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
#define smp_mb__before_clear_bit() barrier()
@@ -108,8 +110,8 @@ static __inline__ void __change_bit(int nr, volatile void * addr)
{
__asm__ __volatile__(
"btcl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
/**
@@ -125,8 +127,8 @@ static __inline__ void change_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btcl %1,%0"
- :"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
}
/**
@@ -143,8 +145,8 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btsl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -163,8 +165,8 @@ static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
__asm__(
"btsl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -182,8 +184,8 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btrl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -202,8 +204,8 @@ static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
__asm__(
"btrl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -214,8 +216,8 @@ static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
__asm__ __volatile__(
"btcl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -233,8 +235,8 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)
__asm__ __volatile__( LOCK_PREFIX
"btcl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"+m" (ADDR)
- :"dIr" (nr) : "memory");
+ :"=r" (oldbit),"=m" (ADDR)
+ :"dIr" (nr), "m" (ADDR) : "memory");
return oldbit;
}
@@ -244,7 +246,7 @@ static __inline__ int constant_test_bit(int nr, const volatile void * addr)
return ((1U << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
-static __inline__ int variable_test_bit(int nr, volatile void * addr)
+static __inline__ int variable_test_bit(int nr, const volatile void * addr)
{
int oldbit;
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index e2ef90700c..cca215f4b2 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -24,6 +24,11 @@
#define CONFIG_X86_IO_APIC 1
#define CONFIG_HPET_TIMER 1
#define CONFIG_X86_MCE_P4THERMAL 1
+#define CONFIG_ACPI_NUMA 1
+#define CONFIG_NUMA 1
+#define CONFIG_ACPI_SRAT 1
+#define CONFIG_DISCONTIGMEM 1
+#define CONFIG_NUMA_EMU 1
/* Intel P4 currently has largest cache line (L2 line size is 128 bytes). */
#define CONFIG_X86_L1_CACHE_SHIFT 7
@@ -81,13 +86,6 @@
#ifndef __ASSEMBLY__
extern unsigned long _end; /* standard ELF symbol */
-
-static inline void FORCE_CRASH(void) __attribute__((noreturn,always_inline));
-static inline void FORCE_CRASH(void)
-{
- __asm__ __volatile__ ( "ud2" );
- while(1);
-}
#endif /* __ASSEMBLY__ */
#if defined(__x86_64__)
@@ -196,12 +194,6 @@ static inline void FORCE_CRASH(void)
#define __HYPERVISOR_DS32 0xe018
#define __HYPERVISOR_DS __HYPERVISOR_DS64
-#define __GUEST_CS64 0xe033
-#define __GUEST_CS32 0xe023
-#define __GUEST_CS __GUEST_CS64
-#define __GUEST_DS 0x0000
-#define __GUEST_SS 0xe02b
-
/* For generic assembly code: use macros to define operation/operand sizes. */
#define __OS "q" /* Operation Suffix */
#define __OP "r" /* Operand Prefix */
diff --git a/xen/include/asm-x86/debugger.h b/xen/include/asm-x86/debugger.h
index 3e5debebd8..b5256523e9 100644
--- a/xen/include/asm-x86/debugger.h
+++ b/xen/include/asm-x86/debugger.h
@@ -15,14 +15,13 @@
* 2. debugger_trap_fatal():
* Called when Xen is about to give up and crash. Typically you will use this
* hook to drop into a debug session. It can also be used to hook off
- * deliberately caused traps (which you then handle and return non-zero)
- * but really these should be hooked off 'debugger_trap_entry'.
+ * deliberately caused traps (which you then handle and return non-zero).
*
* 3. debugger_trap_immediate():
* Called if we want to drop into a debugger now. This is essentially the
* same as debugger_trap_fatal, except that we use the current register state
* rather than the state which was in effect when we took the trap.
- * Essentially, if we're dying because of an unhandled exception, we call
+ * For example: if we're dying because of an unhandled exception, we call
* debugger_trap_fatal; if we're dying because of a panic() we call
* debugger_trap_immediate().
*/
@@ -44,42 +43,20 @@
#include <xen/gdbstub.h>
-#define __debugger_trap_entry(_v, _r) (0)
-
-static inline int __debugger_trap_fatal(
+static inline int debugger_trap_fatal(
unsigned int vector, struct cpu_user_regs *regs)
{
- (void)__trap_to_gdb(regs, vector);
- return (vector == TRAP_int3); /* int3 is harmless */
+ int rc = __trap_to_gdb(regs, vector);
+ return ((rc == 0) || (vector == TRAP_int3));
}
/* Int3 is a trivial way to gather cpu_user_regs context. */
#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" );
-#elif 0
-
-extern int kdb_trap(int, int, struct cpu_user_regs *);
-
-static inline int __debugger_trap_entry(
- unsigned int vector, struct cpu_user_regs *regs)
-{
- return 0;
-}
-
-static inline int __debugger_trap_fatal(
- unsigned int vector, struct cpu_user_regs *regs)
-{
- return kdb_trap(vector, 0, regs);
-}
-
-/* Int3 is a trivial way to gather cpu_user_regs context. */
-#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" )
-
#else
-#define __debugger_trap_entry(_v, _r) (0)
-#define __debugger_trap_fatal(_v, _r) (0)
-#define __debugger_trap_immediate() ((void)0)
+#define debugger_trap_fatal(v, r) (0)
+#define debugger_trap_immediate() ((void)0)
#endif
@@ -96,12 +73,7 @@ static inline int debugger_trap_entry(
return 1;
}
- return __debugger_trap_entry(vector, regs);
+ return 0;
}
-#define debugger_trap_fatal(v, r) (__debugger_trap_fatal(v, r))
-#ifndef debugger_trap_immediate
-#define debugger_trap_immediate() (__debugger_trap_immediate())
-#endif
-
#endif /* __X86_DEBUGGER_H__ */
diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h
index f7d60fae61..c2262d79fb 100644
--- a/xen/include/asm-x86/desc.h
+++ b/xen/include/asm-x86/desc.h
@@ -155,17 +155,12 @@ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
#endif
extern struct desc_struct gdt_table[];
-extern struct desc_struct *gdt;
-extern idt_entry_t *idt;
struct Xgt_desc_struct {
unsigned short size;
unsigned long address __attribute__((packed));
};
-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
-
extern void set_intr_gate(unsigned int irq, void * addr);
extern void set_system_gate(unsigned int n, void *addr);
extern void set_task_gate(unsigned int n, unsigned int sel);
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index f1b7c7cc7b..03620a33ac 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -65,15 +65,14 @@ struct shadow_domain {
struct list_head freelists[SHADOW_MAX_ORDER + 1];
struct list_head p2m_freelist;
struct list_head p2m_inuse;
- struct list_head toplevel_shadows;
+ struct list_head pinned_shadows;
unsigned int total_pages; /* number of pages allocated */
unsigned int free_pages; /* number of pages on freelists */
unsigned int p2m_pages; /* number of pages in p2m map */
+ unsigned int opt_flags; /* runtime tunable optimizations on/off */
/* Shadow hashtable */
- struct shadow_hash_entry *hash_table;
- struct shadow_hash_entry *hash_freelist;
- struct shadow_hash_entry *hash_allocations;
+ struct shadow_page_info **hash_table;
int hash_walking; /* Some function is walking the hash table */
/* Shadow log-dirty bitmap */
@@ -111,6 +110,8 @@ struct arch_domain
/* Shadow translated domain: P2M mapping */
pagetable_t phys_table;
+ /* Highest guest frame that's ever been mapped in the p2m */
+ unsigned long max_mapped_pfn;
} __cacheline_aligned;
@@ -134,18 +135,20 @@ struct pae_l3_cache { };
#endif
struct shadow_vcpu {
+#if CONFIG_PAGING_LEVELS >= 3
+ /* PAE guests: per-vcpu shadow top-level table */
+ l3_pgentry_t l3table[4] __attribute__((__aligned__(32)));
+#endif
/* Pointers to mode-specific entry points. */
struct shadow_paging_mode *mode;
/* Last MFN that we emulated a write to. */
unsigned long last_emulated_mfn;
+ /* MFN of the last shadow that we shot a writeable mapping in */
+ unsigned long last_writeable_pte_smfn;
/* HVM guest: paging enabled (CR0.PG)? */
- unsigned int hvm_paging_enabled:1;
+ unsigned int translate_enabled:1;
/* Emulated fault needs to be propagated to guest? */
unsigned int propagate_fault:1;
-#if CONFIG_PAGING_LEVELS >= 3
- /* Shadow update requires this PAE cpu to recopy/install its L3 table. */
- unsigned int pae_flip_pending:1;
-#endif
};
struct arch_vcpu
@@ -167,7 +170,7 @@ struct arch_vcpu
struct trap_bounce trap_bounce;
/* I/O-port access bitmap. */
- u8 *iobmp; /* Guest kernel virtual address of the bitmap. */
+ XEN_GUEST_HANDLE(uint8_t) iobmp; /* Guest kernel virtual address of the bitmap. */
int iobmp_limit; /* Number of ports represented in the bitmap. */
int iopl; /* Current IOPL for this VCPU. */
@@ -190,13 +193,12 @@ struct arch_vcpu
pagetable_t guest_table; /* (MFN) guest notion of cr3 */
/* guest_table holds a ref to the page, and also a type-count unless
* shadow refcounts are in use */
- pagetable_t shadow_table; /* (MFN) shadow of guest */
+ pagetable_t shadow_table[4]; /* (MFN) shadow(s) of guest */
pagetable_t monitor_table; /* (MFN) hypervisor PT (for HVM) */
unsigned long cr3; /* (MA) value to install in HW CR3 */
- void *guest_vtable; /* virtual address of pagetable */
- void *shadow_vtable; /* virtual address of shadow_table */
- root_pgentry_t *monitor_vtable; /* virtual address of monitor_table */
+ void *guest_vtable; /* virtual addr of pagetable */
+ root_pgentry_t *monitor_vtable; /* virtual addr of monitor_table */
/* Current LDT details. */
unsigned long shadow_ldt_mapcnt;
diff --git a/xen/include/asm-x86/flushtlb.h b/xen/include/asm-x86/flushtlb.h
index 82cb7a7cfe..03d132797c 100644
--- a/xen/include/asm-x86/flushtlb.h
+++ b/xen/include/asm-x86/flushtlb.h
@@ -71,11 +71,8 @@ static inline unsigned long read_cr3(void)
/* Write pagetable base and implicitly tick the tlbflush clock. */
extern void write_cr3(unsigned long cr3);
-#define local_flush_tlb() \
- do { \
- unsigned long cr3 = read_cr3(); \
- write_cr3(cr3); \
- } while ( 0 )
+/* Flush guest mappings from the TLB and implicitly tick the tlbflush clock. */
+extern void local_flush_tlb(void);
#define local_flush_tlb_pge() \
do { \
diff --git a/xen/include/asm-x86/grant_table.h b/xen/include/asm-x86/grant_table.h
index 6fa67ff883..9941a5c6f8 100644
--- a/xen/include/asm-x86/grant_table.h
+++ b/xen/include/asm-x86/grant_table.h
@@ -14,9 +14,9 @@
* must hold a reference to the page.
*/
int create_grant_host_mapping(
- unsigned long addr, unsigned long frame, unsigned int flags);
+ uint64_t addr, unsigned long frame, unsigned int flags);
int destroy_grant_host_mapping(
- unsigned long addr, unsigned long frame, unsigned int flags);
+ uint64_t addr, unsigned long frame, unsigned int flags);
#define gnttab_create_shared_page(d, t, i) \
do { \
diff --git a/xen/include/asm-x86/guest_access.h b/xen/include/asm-x86/guest_access.h
index caad3525b0..01e1fa3583 100644
--- a/xen/include/asm-x86/guest_access.h
+++ b/xen/include/asm-x86/guest_access.h
@@ -8,6 +8,7 @@
#define __ASM_X86_GUEST_ACCESS_H__
#include <asm/uaccess.h>
+#include <asm/shadow.h>
#include <asm/hvm/support.h>
#include <asm/hvm/guest_access.h>
@@ -33,7 +34,7 @@
#define copy_to_guest_offset(hnd, off, ptr, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \
copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
})
@@ -45,7 +46,7 @@
#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\
copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
})
@@ -54,7 +55,7 @@
#define copy_field_to_guest(hnd, ptr, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_to_user_hvm(_x, _y, sizeof(*_x)) : \
copy_to_user(_x, _y, sizeof(*_x)); \
})
@@ -63,7 +64,7 @@
#define copy_field_from_guest(ptr, hnd, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_from_user_hvm(_y, _x, sizeof(*_x)) : \
copy_from_user(_y, _x, sizeof(*_x)); \
})
@@ -73,12 +74,13 @@
* Allows use of faster __copy_* functions.
*/
#define guest_handle_okay(hnd, nr) \
- (hvm_guest(current) || array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)))
+ (shadow_mode_external(current->domain) || \
+ array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)))
#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \
__copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
})
@@ -86,7 +88,7 @@
#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \
__copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
})
@@ -94,7 +96,7 @@
#define __copy_field_to_guest(hnd, ptr, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_to_user_hvm(_x, _y, sizeof(*_x)) : \
__copy_to_user(_x, _y, sizeof(*_x)); \
})
@@ -102,7 +104,7 @@
#define __copy_field_from_guest(ptr, hnd, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- hvm_guest(current) ? \
+ shadow_mode_translate(current->domain) ? \
copy_from_user_hvm(_x, _y, sizeof(*_x)) : \
__copy_from_user(_y, _x, sizeof(*_x)); \
})
diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
index 6561519cb1..63159504ae 100644
--- a/xen/include/asm-x86/hvm/domain.h
+++ b/xen/include/asm-x86/hvm/domain.h
@@ -16,20 +16,17 @@
* 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.
- *
*/
#ifndef __ASM_X86_HVM_DOMAIN_H__
#define __ASM_X86_HVM_DOMAIN_H__
-#include <asm/hvm/vpic.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/irq.h>
+#include <asm/hvm/vpt.h>
#include <asm/hvm/vlapic.h>
-#include <asm/hvm/vioapic.h>
+#include <asm/hvm/io.h>
#include <public/hvm/params.h>
-#define HVM_PBUF_SIZE 80
-
struct hvm_domain {
unsigned long shared_page_va;
unsigned long buffered_io_va;
@@ -37,16 +34,14 @@ struct hvm_domain {
s64 tsc_frequency;
struct pl_time pl_time;
- struct hvm_virpic vpic;
- struct hvm_vioapic vioapic;
struct hvm_io_handler io_handler;
- unsigned char round_info[256];
- spinlock_t round_robin_lock;
- int interrupt_request;
+ struct hvm_irq irq;
- int pbuf_index;
- char pbuf[HVM_PBUF_SIZE];
+ /* hvm_print_line() logging. */
+ char pbuf[80];
+ int pbuf_idx;
+ spinlock_t pbuf_lock;
uint64_t params[HVM_NR_PARAMS];
};
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index cb573e5d9c..83ebf48805 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -20,6 +20,19 @@
#ifndef __ASM_X86_HVM_HVM_H__
#define __ASM_X86_HVM_HVM_H__
+enum segment {
+ seg_cs,
+ seg_ss,
+ seg_ds,
+ seg_es,
+ seg_fs,
+ seg_gs,
+ seg_tr,
+ seg_ldtr,
+ seg_gdtr,
+ seg_idtr
+};
+
/*
* The hardware virtual machine (HVM) interface abstracts away from the
* x86/x86_64 CPU virtualization assist specifics. Currently this interface
@@ -33,10 +46,10 @@ struct hvm_function_table {
void (*disable)(void);
/*
- * Initialize/relinguish HVM guest resources
+ * Initialise/destroy HVM VCPU resources
*/
- int (*initialize_guest_resources)(struct vcpu *v);
- void (*relinquish_guest_resources)(struct domain *d);
+ int (*vcpu_initialise)(struct vcpu *v);
+ void (*vcpu_destroy)(struct vcpu *v);
/*
* Store and load guest state:
@@ -49,17 +62,19 @@ struct hvm_function_table {
struct vcpu *v, struct cpu_user_regs *r);
/*
* Examine specifics of the guest state:
- * 1) determine whether the guest is in real or vm8086 mode,
- * 2) determine whether paging is enabled,
- * 3) return the length of the instruction that caused an exit.
- * 4) return the current guest control-register value
+ * 1) determine whether paging is enabled,
+ * 2) determine whether long mode is enabled,
+ * 3) determine whether PAE paging is enabled,
+ * 4) determine the mode the guest is running in,
+ * 5) return the current guest control-register value
+ * 6) return the current guest segment descriptor base
*/
- int (*realmode)(struct vcpu *v);
int (*paging_enabled)(struct vcpu *v);
int (*long_mode_enabled)(struct vcpu *v);
+ int (*pae_enabled)(struct vcpu *v);
int (*guest_x86_mode)(struct vcpu *v);
- int (*instruction_length)(struct vcpu *v);
unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num);
+ unsigned long (*get_segment_base)(struct vcpu *v, enum segment seg);
/*
* Re-set the value of CR3 that Xen runs on when handling VM exits
@@ -92,28 +107,13 @@ hvm_disable(void)
hvm_funcs.disable();
}
-void hvm_create_event_channels(struct vcpu *v);
-void hvm_map_io_shared_pages(struct vcpu *v);
+int hvm_domain_initialise(struct domain *d);
+void hvm_domain_destroy(struct domain *d);
-static inline int
-hvm_initialize_guest_resources(struct vcpu *v)
-{
- int ret = 1;
- if ( hvm_funcs.initialize_guest_resources )
- ret = hvm_funcs.initialize_guest_resources(v);
- if ( ret == 1 ) {
- hvm_map_io_shared_pages(v);
- hvm_create_event_channels(v);
- }
- return ret;
-}
+int hvm_vcpu_initialise(struct vcpu *v);
+void hvm_vcpu_destroy(struct vcpu *v);
-static inline void
-hvm_relinquish_guest_resources(struct domain *d)
-{
- if (hvm_funcs.relinquish_guest_resources)
- hvm_funcs.relinquish_guest_resources(d);
-}
+void hvm_send_assist_req(struct vcpu *v);
static inline void
hvm_store_cpu_guest_regs(
@@ -129,12 +129,6 @@ hvm_load_cpu_guest_regs(struct vcpu *v, struct cpu_user_regs *r)
}
static inline int
-hvm_realmode(struct vcpu *v)
-{
- return hvm_funcs.realmode(v);
-}
-
-static inline int
hvm_paging_enabled(struct vcpu *v)
{
return hvm_funcs.paging_enabled(v);
@@ -146,18 +140,20 @@ hvm_long_mode_enabled(struct vcpu *v)
return hvm_funcs.long_mode_enabled(v);
}
-static inline int
-hvm_guest_x86_mode(struct vcpu *v)
+ static inline int
+hvm_pae_enabled(struct vcpu *v)
{
- return hvm_funcs.guest_x86_mode(v);
+ return hvm_funcs.pae_enabled(v);
}
static inline int
-hvm_instruction_length(struct vcpu *v)
+hvm_guest_x86_mode(struct vcpu *v)
{
- return hvm_funcs.instruction_length(v);
+ return hvm_funcs.guest_x86_mode(v);
}
+int hvm_instruction_length(unsigned long pc, int mode);
+
static inline void
hvm_update_host_cr3(struct vcpu *v)
{
@@ -175,9 +171,17 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num)
return 0; /* force to fail */
}
-extern void hvm_stts(struct vcpu *v);
-extern void hvm_set_guest_time(struct vcpu *v, u64 gtime);
-extern void hvm_do_resume(struct vcpu *v);
+static inline unsigned long
+hvm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ return hvm_funcs.get_segment_base(v, seg);
+}
+
+void hvm_stts(struct vcpu *v);
+void hvm_set_guest_time(struct vcpu *v, u64 gtime);
+void hvm_freeze_time(struct vcpu *v);
+void hvm_migrate_timers(struct vcpu *v);
+void hvm_do_resume(struct vcpu *v);
static inline void
hvm_init_ap_context(struct vcpu_guest_context *ctxt,
@@ -186,6 +190,6 @@ hvm_init_ap_context(struct vcpu_guest_context *ctxt,
return hvm_funcs.init_ap_context(ctxt, vcpuid, trampoline_vector);
}
-extern int hvm_bringup_ap(int vcpuid, int trampoline_vector);
+int hvm_bringup_ap(int vcpuid, int trampoline_vector);
#endif /* __ASM_X86_HVM_HVM_H__ */
diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h
index 0c594fdafa..028a885eb2 100644
--- a/xen/include/asm-x86/hvm/io.h
+++ b/xen/include/asm-x86/hvm/io.h
@@ -25,11 +25,6 @@
#include <public/hvm/ioreq.h>
#include <public/event_channel.h>
-#define MAX_OPERAND_NUM 2
-
-#define mk_operand(size_reg, index, seg, flag) \
- (((size_reg) << 24) | ((index) << 16) | ((seg) << 8) | (flag))
-
#define operand_size(operand) \
((operand >> 24) & 0xFF)
@@ -68,30 +63,26 @@
#define INSTR_TEST 12
#define INSTR_BT 13
#define INSTR_XCHG 14
-
-struct instruction {
- __s8 instr; /* instruction type */
- __s16 op_size; /* the operand's bit size, e.g. 16-bit or 32-bit */
- __u64 immediate;
- __u16 seg_sel; /* segmentation selector */
- __u32 operand[MAX_OPERAND_NUM]; /* order is AT&T assembly */
- __u32 flags;
-};
+#define INSTR_SUB 15
+#define INSTR_ADD 16
#define MAX_INST_LEN 15 /* Maximum instruction length = 15 bytes */
struct hvm_io_op {
- int flags;
- int instr; /* instruction */
- unsigned long operand[2]; /* operands */
- unsigned long immediate; /* immediate portion */
- struct cpu_user_regs io_context; /* current context */
+ unsigned int instr; /* instruction */
+ unsigned int flags;
+ unsigned long addr; /* virt addr for overlap PIO/MMIO */
+ struct {
+ unsigned int operand[2]; /* operands */
+ unsigned long immediate; /* immediate portion */
+ };
+ struct cpu_user_regs io_context; /* current context */
};
#define MAX_IO_HANDLER 8
-#define VMX_PORTIO 0
-#define VMX_MMIO 1
+#define HVM_PORTIO 0
+#define HVM_MMIO 1
typedef int (*intercept_action_t)(ioreq_t *);
typedef unsigned long (*hvm_mmio_read_t)(struct vcpu *v,
@@ -125,21 +116,23 @@ struct hvm_mmio_handler {
/* global io interception point in HV */
extern int hvm_io_intercept(ioreq_t *p, int type);
-extern int register_io_handler(unsigned long addr, unsigned long size,
- intercept_action_t action, int type);
+extern int register_io_handler(
+ struct domain *d, unsigned long addr, unsigned long size,
+ intercept_action_t action, int type);
static inline int hvm_portio_intercept(ioreq_t *p)
{
- return hvm_io_intercept(p, VMX_PORTIO);
+ return hvm_io_intercept(p, HVM_PORTIO);
}
-int hvm_mmio_intercept(ioreq_t *p);
+extern int hvm_mmio_intercept(ioreq_t *p);
+extern int hvm_buffered_io_intercept(ioreq_t *p);
-static inline int register_portio_handler(unsigned long addr,
- unsigned long size,
- intercept_action_t action)
+static inline int register_portio_handler(
+ struct domain *d, unsigned long addr,
+ unsigned long size, intercept_action_t action)
{
- return register_io_handler(addr, size, action, VMX_PORTIO);
+ return register_io_handler(d, addr, size, action, HVM_PORTIO);
}
#if defined(__i386__) || defined(__x86_64__)
@@ -149,17 +142,13 @@ static inline int irq_masked(unsigned long eflags)
}
#endif
-extern void handle_mmio(unsigned long, unsigned long);
+extern void send_pio_req(unsigned long port, unsigned long count, int size,
+ long value, int dir, int df, int value_is_ptr);
+extern void handle_mmio(unsigned long gpa);
extern void hvm_interrupt_post(struct vcpu *v, int vector, int type);
extern void hvm_io_assist(struct vcpu *v);
-extern void pic_irq_request(void *data, int level);
-extern void hvm_pic_assist(struct vcpu *v);
extern int cpu_get_interrupt(struct vcpu *v, int *type);
extern int cpu_has_pending_irq(struct vcpu *v);
-extern void hvm_release_assist_channel(struct vcpu *v);
-
-// XXX - think about this, maybe use bit 30 of the mfn to signify an MMIO frame.
-#define mmio_space(gpa) (!VALID_MFN(get_mfn_from_gpfn((gpa) >> PAGE_SHIFT)))
#endif /* __ASM_X86_HVM_IO_H__ */
diff --git a/xen/include/asm-x86/hvm/irq.h b/xen/include/asm-x86/hvm/irq.h
new file mode 100644
index 0000000000..cfc0de765d
--- /dev/null
+++ b/xen/include/asm-x86/hvm/irq.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * irq.h
+ *
+ * Interrupt distribution and delivery logic.
+ *
+ * Copyright (c) 2006, K A Fraser, XenSource Inc.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_X86_HVM_IRQ_H__
+#define __ASM_X86_HVM_IRQ_H__
+
+#include <xen/types.h>
+#include <xen/spinlock.h>
+#include <asm/hvm/vpic.h>
+#include <asm/hvm/vioapic.h>
+
+struct hvm_irq {
+ /* Lock protects access to all other fields. */
+ spinlock_t lock;
+
+ /*
+ * Virtual interrupt wires for a single PCI bus.
+ * Indexed by: device*4 + INTx#.
+ */
+ DECLARE_BITMAP(pci_intx, 32*4);
+
+ /*
+ * Virtual interrupt wires for ISA devices.
+ * Indexed by ISA IRQ (assumes no ISA-device IRQ sharing).
+ */
+ DECLARE_BITMAP(isa_irq, 16);
+
+ /* Virtual interrupt wire and GSI link for paravirtual platform driver. */
+ DECLARE_BITMAP(callback_irq_wire, 1);
+ unsigned int callback_gsi;
+
+ /*
+ * PCI-ISA interrupt router.
+ * Each PCI <device:INTx#> is 'wire-ORed' into one of four links using
+ * the traditional 'barber's pole' mapping ((device + INTx#) & 3).
+ * The router provides a programmable mapping from each link to a GSI.
+ */
+ u8 pci_link_route[4];
+
+ /* Number of INTx wires asserting each PCI-ISA link. */
+ u8 pci_link_assert_count[4];
+
+ /*
+ * Number of wires asserting each GSI.
+ *
+ * GSIs 0-15 are the ISA IRQs. ISA devices map directly into this space.
+ * PCI links map into this space via the PCI-ISA bridge.
+ *
+ * GSIs 16+ are used only be PCI devices. The mapping from PCI device to
+ * GSI is as follows: ((device*4 + device/8 + INTx#) & 31) + 16
+ */
+ u8 gsi_assert_count[VIOAPIC_NUM_PINS];
+
+ /*
+ * GSIs map onto PIC/IO-APIC in the usual way:
+ * 0-7: Master 8259 PIC, IO-APIC pins 0-7
+ * 8-15: Slave 8259 PIC, IO-APIC pins 8-15
+ * 16+ : IO-APIC pins 16+
+ */
+ struct vpic vpic[2]; /* 0=master; 1=slave */
+ struct vioapic vioapic;
+
+ /* Last VCPU that was delivered a LowestPrio interrupt. */
+ u8 round_robin_prev_vcpu;
+};
+
+#define hvm_pci_intx_gsi(dev, intx) \
+ (((((dev)<<2) + ((dev)>>3) + (intx)) & 31) + 16)
+#define hvm_pci_intx_link(dev, intx) \
+ (((dev) + (intx)) & 3)
+
+/* Modify state of a PCI INTx wire. */
+void hvm_pci_intx_assert(
+ struct domain *d, unsigned int device, unsigned int intx);
+void hvm_pci_intx_deassert(
+ struct domain *d, unsigned int device, unsigned int intx);
+
+/* Modify state of an ISA device's IRQ wire. */
+void hvm_isa_irq_assert(
+ struct domain *d, unsigned int isa_irq);
+void hvm_isa_irq_deassert(
+ struct domain *d, unsigned int isa_irq);
+
+void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq);
+
+void hvm_set_callback_irq_level(void);
+void hvm_set_callback_gsi(struct domain *d, unsigned int gsi);
+
+#endif /* __ASM_X86_HVM_IRQ_H__ */
diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h
index 5f81e524ad..3f3ff94386 100644
--- a/xen/include/asm-x86/hvm/support.h
+++ b/xen/include/asm-x86/hvm/support.h
@@ -32,8 +32,6 @@
#define HVM_DEBUG 1
#endif
-#define hvm_guest(v) ((v)->arch.guest_context.flags & VGCF_HVM_GUEST)
-
static inline shared_iopage_t *get_sp(struct domain *d)
{
return (shared_iopage_t *) d->arch.hvm_domain.shared_page_va;
@@ -96,13 +94,6 @@ enum hval_bitmaps {
#define VMX_DELIVER_NO_ERROR_CODE -1
-/*
- * This works for both 32bit & 64bit eflags filteration
- * done in construct_init_vmc[sb]_guest()
- */
-#define HVM_EFLAGS_RESERVED_0 0xffc08028 /* bitmap for 0 */
-#define HVM_EFLAGS_RESERVED_1 0x00000002 /* bitmap for 1 */
-
#if HVM_DEBUG
#define DBG_LEVEL_0 (1 << 0)
#define DBG_LEVEL_1 (1 << 1)
@@ -118,7 +109,7 @@ enum hval_bitmaps {
extern unsigned int opt_hvm_debug_level;
#define HVM_DBG_LOG(level, _f, _a...) \
do { \
- if ( (level) & opt_hvm_debug_level ) \
+ if ( unlikely((level) & opt_hvm_debug_level) ) \
printk("[HVM:%d.%d] <%s> " _f "\n", \
current->domain->domain_id, current->vcpu_id, __func__, \
## _a); \
@@ -127,30 +118,21 @@ extern unsigned int opt_hvm_debug_level;
#define HVM_DBG_LOG(level, _f, _a...)
#endif
-#define __hvm_bug(regs) \
- do { \
- printk("__hvm_bug at %s:%d\n", __FILE__, __LINE__); \
- show_execution_state(regs); \
- domain_crash_synchronous(); \
- } while (0)
+#define TRACE_VMEXIT(index, value) \
+ current->arch.hvm_vcpu.hvm_trace_values[index] = (value)
extern int hvm_enabled;
-enum { HVM_COPY_IN = 0, HVM_COPY_OUT };
-extern int hvm_copy(void *buf, unsigned long vaddr, int size, int dir);
+int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size);
+int hvm_copy_from_guest_phys(void *buf, paddr_t paddr, int size);
+int hvm_copy_to_guest_virt(unsigned long vaddr, void *buf, int size);
+int hvm_copy_from_guest_virt(void *buf, unsigned long vaddr, int size);
-extern void hvm_setup_platform(struct domain* d);
-extern int hvm_mmio_intercept(ioreq_t *p);
-extern int hvm_io_intercept(ioreq_t *p, int type);
-extern int hvm_buffered_io_intercept(ioreq_t *p);
-extern void hvm_hooks_assist(struct vcpu *v);
-extern void hvm_print_line(struct vcpu *v, const char c);
-extern void hlt_timer_fn(void *data);
+void hvm_print_line(struct vcpu *v, const char c);
+void hlt_timer_fn(void *data);
void hvm_do_hypercall(struct cpu_user_regs *pregs);
-void hvm_prod_vcpu(struct vcpu *v);
-
void hvm_hlt(unsigned long rflags);
#endif /* __ASM_X86_HVM_SUPPORT_H__ */
diff --git a/xen/include/asm-x86/hvm/svm/emulate.h b/xen/include/asm-x86/hvm/svm/emulate.h
index 7f693ebb23..3bb1208128 100644
--- a/xen/include/asm-x86/hvm/svm/emulate.h
+++ b/xen/include/asm-x86/hvm/svm/emulate.h
@@ -77,8 +77,8 @@ enum instruction_index {
extern unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb,
- struct cpu_user_regs *regs, const u8 prefix, const u8 *operand,
- u8 *size);
+ struct cpu_user_regs *regs, const u8 prefix, int inst_len,
+ const u8 *operand, u8 *size);
extern unsigned long get_effective_addr_sib(struct vmcb_struct *vmcb,
struct cpu_user_regs *regs, const u8 prefix, const u8 *operand,
u8 *size);
@@ -94,15 +94,14 @@ extern int __get_instruction_length_from_list(struct vmcb_struct *vmcb,
static inline int __get_instruction_length(struct vmcb_struct *vmcb,
enum instruction_index instr, u8 *guest_eip_buf)
{
- return __get_instruction_length_from_list(vmcb, &instr, 1, guest_eip_buf,
- NULL);
+ return __get_instruction_length_from_list(
+ vmcb, &instr, 1, guest_eip_buf, NULL);
}
static inline unsigned int is_prefix(u8 opc)
{
- switch(opc)
- {
+ switch ( opc ) {
case 0x66:
case 0x67:
case 0x2E:
@@ -115,22 +114,7 @@ static inline unsigned int is_prefix(u8 opc)
case 0xF3:
case 0xF2:
#if __x86_64__
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4a:
- case 0x4b:
- case 0x4c:
- case 0x4d:
- case 0x4e:
- case 0x4f:
+ case 0x40 ... 0x4f:
#endif /* __x86_64__ */
return 1;
}
@@ -141,15 +125,15 @@ static inline unsigned int is_prefix(u8 opc)
static inline int skip_prefix_bytes(u8 *buf, size_t size)
{
int index;
- for (index = 0; index < size && is_prefix(buf[index]); index ++)
- /* do nothing */ ;
+ for ( index = 0; index < size && is_prefix(buf[index]); index++ )
+ continue;
return index;
}
-static void inline __update_guest_eip(struct vmcb_struct *vmcb,
- int inst_len)
+static void inline __update_guest_eip(
+ struct vmcb_struct *vmcb, int inst_len)
{
ASSERT(inst_len > 0);
vmcb->rip += inst_len;
diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h
index 0f73f0c975..2d6a4ed0f3 100644
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -23,7 +23,7 @@
#include <asm/config.h>
#include <asm/hvm/hvm.h>
-extern int start_svm(void);
+int start_svm(void);
/* general 1 intercepts */
enum GenericIntercept1bits
@@ -310,10 +310,6 @@ enum {
SVM_CPU_STATE_LMA_ENABLED,
SVM_CPU_STATE_ASSIST_ENABLED,
};
-
-#define SVM_LONG_GUEST(ed) \
- (test_bit(SVM_CPU_STATE_LMA_ENABLED, &ed->arch.hvm_svm.cpu_state))
-
/*
* Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the
@@ -484,6 +480,7 @@ struct arch_svm_struct {
u32 *msrpm;
u64 vmexit_tsc; /* tsc read at #VMEXIT. for TSC_OFFSET */
int saved_irq_vector;
+ u32 inject_event;
u32 launch_core;
u32 asid_core;
@@ -495,15 +492,15 @@ struct arch_svm_struct {
unsigned long cpu_state;
};
-extern struct vmcb_struct *alloc_vmcb(void);
-extern struct host_save_area *alloc_host_save_area(void);
-extern void free_vmcb(struct vmcb_struct *vmcb);
-extern void free_host_save_area(struct host_save_area *hsa);
+struct vmcb_struct *alloc_vmcb(void);
+struct host_save_area *alloc_host_save_area(void);
+void free_vmcb(struct vmcb_struct *vmcb);
+void free_host_save_area(struct host_save_area *hsa);
-extern int construct_vmcb(struct arch_svm_struct *, struct cpu_user_regs *);
-extern void destroy_vmcb(struct arch_svm_struct *);
+int svm_create_vmcb(struct vcpu *v);
+void svm_destroy_vmcb(struct vcpu *v);
-extern void setup_vmcb_dump(void);
+void setup_vmcb_dump(void);
#define VMCB_USE_HOST_ENV 1
#define VMCB_USE_SEPARATE_ENV 0
diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
index b607a4578b..0c073028ee 100644
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -32,7 +32,7 @@ struct hvm_vcpu {
unsigned long hw_cr3; /* value we give to HW to use */
unsigned long ioflags;
struct hvm_io_op io_op;
- struct vlapic *vlapic;
+ struct vlapic vlapic;
s64 cache_tsc_offset;
u64 guest_time;
@@ -41,16 +41,10 @@ struct hvm_vcpu {
int xen_port;
-#if CONFIG_PAGING_LEVELS >= 3
- l3_pgentry_t hvm_lowmem_l3tab[4]
- __attribute__((__aligned__(32)));
-#endif
-
/* Flags */
int flag_dr_dirty;
- /* hlt ins emulation wakeup timer */
- struct timer hlt_timer;
+ unsigned long hvm_trace_values[5];
union {
struct arch_vmx_struct vmx;
diff --git a/xen/include/asm-x86/hvm/vioapic.h b/xen/include/asm-x86/hvm/vioapic.h
index 72c758c133..6a934b7b39 100644
--- a/xen/include/asm-x86/hvm/vioapic.h
+++ b/xen/include/asm-x86/hvm/vioapic.h
@@ -1,5 +1,4 @@
/*
- *
* Copyright (C) 2001 MandrakeSoft S.A.
*
* MandrakeSoft S.A.
@@ -23,97 +22,77 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_X86_HVM_IOAPIC_H__
-#define __ASM_X86_HVM_IOAPIC_H__
+#ifndef __ASM_X86_HVM_VIOAPIC_H__
+#define __ASM_X86_HVM_VIOAPIC_H__
#include <xen/config.h>
#include <xen/types.h>
#include <xen/smp.h>
-#ifndef __ia64__
-#define IOAPIC_VERSION_ID 0x11
+#ifdef __ia64__
+#define VIOAPIC_IS_IOSAPIC 1
+#define VIOAPIC_NUM_PINS 24
#else
-#define IOAPIC_VERSION_ID 0x21
+#define VIOAPIC_NUM_PINS 48 /* 16 ISA IRQs, 32 non-legacy PCI IRQS. */
#endif
-#define IOAPIC_NUM_PINS 24
-#define MAX_LAPIC_NUM 32
-
-#define IOAPIC_LEVEL_TRIGGER 1
-
-#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
-#define IOAPIC_MEM_LENGTH 0x100
+#if !VIOAPIC_IS_IOSAPIC
+#define VIOAPIC_VERSION_ID 0x11 /* IOAPIC version */
+#else
+#define VIOAPIC_VERSION_ID 0x21 /* IOSAPIC version */
+#endif
-#define IOAPIC_ENABLE_MASK 0x0
-#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK)
-#define IOAPICEnabled(s) (s->flags & IOAPIC_ENABLE_FLAG)
+#define VIOAPIC_EDGE_TRIG 0
+#define VIOAPIC_LEVEL_TRIG 1
-#define IOAPIC_REG_SELECT 0x0
-#define IOAPIC_REG_WINDOW 0x10
+#define VIOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
+#define VIOAPIC_MEM_LENGTH 0x100
-#ifdef __ia64__
-#define IOAPIC_REG_ASSERTION 0x20
-#define IOAPIC_REG_EOI 0x40
-#endif
+/* Direct registers. */
+#define VIOAPIC_REG_SELECT 0x00
+#define VIOAPIC_REG_WINDOW 0x10
+#define VIOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */
-#ifndef __ia64__
-#define IOAPIC_REG_APIC_ID 0x0
-#define IOAPIC_REG_ARB_ID 0x2
-#endif
+/* Indirect registers. */
+#define VIOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */
+#define VIOAPIC_REG_VERSION 0x01
+#define VIOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */
-#define IOAPIC_REG_VERSION 0x1
+#define domain_vioapic(d) (&(d)->arch.hvm_domain.irq.vioapic)
+#define vioapic_domain(v) (container_of((v), struct domain, \
+ arch.hvm_domain.irq.vioapic))
-typedef union RedirStatus
+union vioapic_redir_entry
{
- uint64_t value;
+ uint64_t bits;
struct {
uint8_t vector;
- uint8_t deliver_mode:3;
- uint8_t destmode:1;
- uint8_t delivestatus:1;
+ uint8_t delivery_mode:3;
+ uint8_t dest_mode:1;
+ uint8_t delivery_status:1;
uint8_t polarity:1;
- uint8_t remoteirr:1;
- uint8_t trigmod:1;
- uint8_t mask:1; /* interrupt mask*/
+ uint8_t remote_irr:1;
+ uint8_t trig_mode:1;
+ uint8_t mask:1;
uint8_t reserve:7;
-#ifndef __ia64__
+#if !VIOAPIC_IS_IOSAPIC
uint8_t reserved[4];
uint8_t dest_id;
#else
uint8_t reserved[3];
uint16_t dest_id;
#endif
- } RedirForm;
-} RedirStatus;
+ } fields;
+};
-typedef struct hvm_vioapic {
- uint32_t irr;
- uint32_t isr; /* This is used for level trigger */
- uint32_t imr;
- uint32_t ioregsel;
- uint32_t flags;
- uint32_t lapic_count;
- uint32_t id;
- uint32_t arb_id;
+struct vioapic {
+ uint32_t ioregsel, id;
unsigned long base_address;
- RedirStatus redirtbl[IOAPIC_NUM_PINS];
- struct vlapic *lapic_info[MAX_LAPIC_NUM];
- struct domain *domain;
-} hvm_vioapic_t;
-
-hvm_vioapic_t *hvm_vioapic_init(struct domain *d);
-
-void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs);
-void hvm_vioapic_do_irqs(struct domain *d, uint16_t irqs);
-void hvm_vioapic_set_irq(struct domain *d, int irq, int level);
+ union vioapic_redir_entry redirtbl[VIOAPIC_NUM_PINS];
+};
-int hvm_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v);
-
-void ioapic_update_EOI(struct domain *d, int vector);
-
-#ifdef HVM_DOMAIN_SAVE_RESTORE
-void ioapic_save(QEMUFile* f, void* opaque);
-int ioapic_load(QEMUFile* f, void* opaque, int version_id);
-#endif
+void vioapic_init(struct domain *d);
+void vioapic_irq_positive_edge(struct domain *d, unsigned int irq);
+void vioapic_update_EOI(struct domain *d, int vector);
-#endif /* __ASM_X86_HVM_IOAPIC_H__ */
+#endif /* __ASM_X86_HVM_VIOAPIC_H__ */
diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h
index 1da56bd0ca..003d93b389 100644
--- a/xen/include/asm-x86/hvm/vlapic.h
+++ b/xen/include/asm-x86/hvm/vlapic.h
@@ -2,6 +2,7 @@
* hvm_vlapic.h: virtualize LAPIC definitions.
*
* Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -25,141 +26,72 @@
#define MAX_VECTOR 256
-#define VEC_POS(v) ((v)%32)
-#define REG_POS(v) (((v)/32)* 0x10)
-#define vlapic_test_and_set_vector(vec, bitmap) \
- test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
-#define vlapic_test_and_clear_vector(vec, bitmap) \
- test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
-#define vlapic_set_vector(vec, bitmap) \
- set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
-#define vlapic_clear_vector(vec, bitmap) \
- clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
-
-static inline int vlapic_find_highest_vector(u32 *bitmap)
-{
- int word_offset = MAX_VECTOR / 32;
-
- /* Work backwards through the bitmap (first 32-bit word in every four). */
- while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) )
- continue;
-
- return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32);
-}
-
-#define VLAPIC(v) (v->arch.hvm_vcpu.vlapic)
-
-#define VLAPIC_VERSION 0x00050014
-
-#define VLOCAL_APIC_MEM_LENGTH (1 << 12)
-
-#define VLAPIC_LVT_NUM 6
+#define vcpu_vlapic(vcpu) (&(vcpu)->arch.hvm_vcpu.vlapic)
+#define vlapic_vcpu(vpic) (container_of((vpic), struct vcpu, \
+ arch.hvm_vcpu.vlapic))
+#define vlapic_domain(vpic) (vlapic_vcpu(vlapic)->domain)
#define VLAPIC_ID(vlapic) \
(GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)))
-/* followed define is not in apicdef.h */
-#define APIC_SHORT_MASK 0xc0000
-#define APIC_DEST_NOSHORT 0x0
-#define APIC_DEST_MASK 0x800
-
-#define vlapic_lvt_enabled(vlapic, lvt_type) \
- (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED))
-
-#define vlapic_lvt_vector(vlapic, lvt_type) \
- (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
-
-#define vlapic_lvt_dm(vlapic, lvt_type) \
- (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
-
-#define vlapic_lvtt_period(vlapic) \
- (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
-
-#define _VLAPIC_GLOB_DISABLE 0x0
-#define VLAPIC_GLOB_DISABLE_MASK 0x1
-#define VLAPIC_SOFTWARE_DISABLE_MASK 0x2
-#define _VLAPIC_BSP_ACCEPT_PIC 0x3
-
-#define vlapic_enabled(vlapic) \
- (!((vlapic)->status & \
- (VLAPIC_GLOB_DISABLE_MASK | VLAPIC_SOFTWARE_DISABLE_MASK)))
-
-#define vlapic_global_enabled(vlapic) \
- (!(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status)))
-
-#define LVT_MASK \
- APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
-
-#define LINT_MASK \
- LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
- APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
-
-typedef struct direct_intr_info {
- int deliver_mode;
- int source[6];
-} direct_intr_info_t;
+/*
+ * APIC can be disabled in two ways:
+ * 1. 'Hardware disable': via IA32_APIC_BASE_MSR[11]
+ * CPU should behave as if it does not have an APIC.
+ * 2. 'Software disable': via APIC_SPIV[8].
+ * APIC is visible but does not respond to interrupt messages.
+ */
+#define VLAPIC_HW_DISABLED 0x1
+#define VLAPIC_SW_DISABLED 0x2
+#define vlapic_sw_disabled(vlapic) ((vlapic)->disabled & VLAPIC_SW_DISABLED)
+#define vlapic_hw_disabled(vlapic) ((vlapic)->disabled & VLAPIC_HW_DISABLED)
+#define vlapic_disabled(vlapic) ((vlapic)->disabled)
+#define vlapic_enabled(vlapic) (!vlapic_disabled(vlapic))
struct vlapic {
- uint32_t status;
- uint32_t vcpu_id;
uint64_t apic_base_msr;
- unsigned long base_address;
- uint32_t timer_divide_count;
+ uint32_t disabled; /* VLAPIC_xx_DISABLED */
+ uint32_t timer_divisor;
struct timer vlapic_timer;
- int intr_pending_count[MAX_VECTOR];
+ int timer_pending_count;
+ int flush_tpr_threshold;
s_time_t timer_last_update;
- direct_intr_info_t direct_intr;
- uint32_t err_status;
- uint32_t err_write_count;
- struct vcpu *vcpu;
- struct domain *domain;
struct page_info *regs_page;
void *regs;
};
-static inline int vlapic_set_irq(struct vlapic *vlapic,
- uint8_t vec, uint8_t trig)
-{
- int ret;
-
- ret = vlapic_test_and_set_vector(vec, vlapic->regs + APIC_IRR);
- if ( trig )
- vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
-
- /* We may need to wake up target vcpu, besides set pending bit here */
- return ret;
-}
-
static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg)
{
- return *( (uint32_t *)(vlapic->regs + reg));
+ return *((uint32_t *)(vlapic->regs + reg));
}
-static inline void vlapic_set_reg(struct vlapic *vlapic,
- uint32_t reg, uint32_t val)
+static inline void vlapic_set_reg(
+ struct vlapic *vlapic, uint32_t reg, uint32_t val)
{
*((uint32_t *)(vlapic->regs + reg)) = val;
}
-void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode);
+int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig);
+
+void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode);
+
+int vlapic_find_highest_irr(struct vlapic *vlapic);
-int cpu_has_apic_interrupt(struct vcpu* v);
-int cpu_get_apic_interrupt(struct vcpu* v, int *mode);
+int cpu_get_apic_interrupt(struct vcpu *v, int *mode);
-extern int vlapic_init(struct vcpu *vc);
+int vlapic_init(struct vcpu *v);
+void vlapic_destroy(struct vcpu *v);
-extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
+void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
int vlapic_accept_pic_intr(struct vcpu *v);
-struct vlapic* apic_round_robin(struct domain *d,
- uint8_t dest_mode,
- uint8_t vector,
- uint32_t bitmap);
+struct vlapic *apic_round_robin(
+ struct domain *d, uint8_t vector, uint32_t bitmap);
s_time_t get_apictime_scheduled(struct vcpu *v);
-int hvm_apic_support(struct domain *d);
+int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda);
#endif /* __ASM_X86_HVM_VLAPIC_H__ */
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 524411be34..85a4bf395c 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -29,16 +29,6 @@ extern void vmcs_dump_vcpu(void);
extern void vmx_init_vmcs_config(void);
extern void setup_vmcs_dump(void);
-enum {
- VMX_CPU_STATE_PAE_ENABLED=0,
- VMX_CPU_STATE_LME_ENABLED,
- VMX_CPU_STATE_LMA_ENABLED,
- VMX_CPU_STATE_ASSIST_ENABLED,
-};
-
-#define VMX_LONG_GUEST(ed) \
- (test_bit(VMX_CPU_STATE_LMA_ENABLED, &ed->arch.hvm_vmx.cpu_state))
-
struct vmcs_struct {
u32 vmcs_revision_id;
unsigned char data [0]; /* vmcs size is read from MSR */
@@ -51,19 +41,15 @@ enum {
VMX_INDEX_MSR_SYSCALL_MASK,
VMX_INDEX_MSR_EFER,
- VMX_MSR_COUNT,
+ VMX_MSR_COUNT
};
struct vmx_msr_state {
unsigned long flags;
- unsigned long msr_items[VMX_MSR_COUNT];
+ unsigned long msrs[VMX_MSR_COUNT];
unsigned long shadow_gs;
};
-/* io bitmap is 4KBytes in size */
-#define IO_BITMAP_SIZE 0x1000
-#define IO_BITMAP_ORDER (get_order_from_bytes(IO_BITMAP_SIZE))
-
struct arch_vmx_struct {
/* Virtual address of VMCS. */
struct vmcs_struct *vmcs;
@@ -90,10 +76,8 @@ struct arch_vmx_struct {
unsigned long cpu_shadow_cr4; /* copy of guest read shadow CR4 */
unsigned long cpu_cr2; /* save CR2 */
unsigned long cpu_cr3;
- unsigned long cpu_state;
- unsigned long cpu_based_exec_control;
- struct vmx_msr_state msr_content;
- void *io_bitmap_a, *io_bitmap_b;
+ struct vmx_msr_state msr_state;
+ unsigned long vmxassist_enabled:1;
};
#define vmx_schedule_tail(next) \
@@ -129,12 +113,16 @@ extern int vmcs_version;
#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
#define CPU_BASED_MONITOR_EXITING 0x20000000
#define CPU_BASED_PAUSE_EXITING 0x40000000
-#define PIN_BASED_EXT_INTR_MASK 0x1
-#define PIN_BASED_NMI_EXITING 0x8
+#define PIN_BASED_EXT_INTR_MASK 0x00000001
+#define PIN_BASED_NMI_EXITING 0x00000008
+
+#define VM_EXIT_IA32E_MODE 0x00000200
#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
-#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200
+#define VM_ENTRY_IA32E_MODE 0x00000200
+#define VM_ENTRY_SMM 0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
/* VMCS Encordings */
enum vmcs_field {
@@ -153,10 +141,10 @@ enum vmcs_field {
HOST_FS_SELECTOR = 0x00000c08,
HOST_GS_SELECTOR = 0x00000c0a,
HOST_TR_SELECTOR = 0x00000c0c,
- IO_BITMAP_A = 0x00002000,
- IO_BITMAP_A_HIGH = 0x00002001,
- IO_BITMAP_B = 0x00002002,
- IO_BITMAP_B_HIGH = 0x00002003,
+ IO_BITMAP_A = 0x00002000,
+ IO_BITMAP_A_HIGH = 0x00002001,
+ IO_BITMAP_B = 0x00002002,
+ IO_BITMAP_B_HIGH = 0x00002003,
VM_EXIT_MSR_STORE_ADDR = 0x00002006,
VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
@@ -172,7 +160,7 @@ enum vmcs_field {
GUEST_IA32_DEBUGCTL = 0x00002802,
GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
- CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
+ CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
EXCEPTION_BITMAP = 0x00004004,
PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
@@ -189,7 +177,7 @@ enum vmcs_field {
SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
VM_INSTRUCTION_ERROR = 0x00004400,
VM_EXIT_REASON = 0x00004402,
- VM_EXIT_INTR_INFO = 0x00004404,
+ VM_EXIT_INTR_INFO = 0x00004404,
VM_EXIT_INTR_ERROR_CODE = 0x00004406,
IDT_VECTORING_INFO_FIELD = 0x00004408,
IDT_VECTORING_ERROR_CODE = 0x0000440a,
@@ -214,16 +202,17 @@ enum vmcs_field {
GUEST_LDTR_AR_BYTES = 0x00004820,
GUEST_TR_AR_BYTES = 0x00004822,
GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
+ GUEST_ACTIVITY_STATE = 0x00004826,
GUEST_SYSENTER_CS = 0x0000482A,
HOST_IA32_SYSENTER_CS = 0x00004c00,
CR0_GUEST_HOST_MASK = 0x00006000,
CR4_GUEST_HOST_MASK = 0x00006002,
CR0_READ_SHADOW = 0x00006004,
CR4_READ_SHADOW = 0x00006006,
- CR3_TARGET_VALUE0 = 0x00006008,
- CR3_TARGET_VALUE1 = 0x0000600a,
- CR3_TARGET_VALUE2 = 0x0000600c,
- CR3_TARGET_VALUE3 = 0x0000600e,
+ CR3_TARGET_VALUE0 = 0x00006008,
+ CR3_TARGET_VALUE1 = 0x0000600a,
+ CR3_TARGET_VALUE2 = 0x0000600c,
+ CR3_TARGET_VALUE3 = 0x0000600e,
EXIT_QUALIFICATION = 0x00006400,
GUEST_LINEAR_ADDRESS = 0x0000640a,
GUEST_CR0 = 0x00006800,
@@ -237,7 +226,7 @@ enum vmcs_field {
GUEST_GS_BASE = 0x00006810,
GUEST_LDTR_BASE = 0x00006812,
GUEST_TR_BASE = 0x00006814,
- GUEST_GDTR_BASE = 0x00006816,
+ GUEST_GDTR_BASE = 0x00006816,
GUEST_IDTR_BASE = 0x00006818,
GUEST_DR7 = 0x0000681a,
GUEST_RSP = 0x0000681c,
diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h
index 38e447259c..e0ec14518b 100644
--- a/xen/include/asm-x86/hvm/vmx/vmx.h
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h
@@ -29,81 +29,12 @@
extern void vmx_asm_vmexit_handler(struct cpu_user_regs);
extern void vmx_asm_do_vmentry(void);
extern void vmx_intr_assist(void);
-extern void vmx_migrate_timers(struct vcpu *v);
-extern void arch_vmx_do_launch(struct vcpu *);
extern void arch_vmx_do_resume(struct vcpu *);
extern void set_guest_time(struct vcpu *v, u64 gtime);
extern unsigned int cpu_rev;
/*
- * Need fill bits for SENTER
- */
-
-#define MONITOR_PIN_BASED_EXEC_CONTROLS_RESERVED_VALUE 0x00000016
-
-#define MONITOR_PIN_BASED_EXEC_CONTROLS \
- ( \
- MONITOR_PIN_BASED_EXEC_CONTROLS_RESERVED_VALUE | \
- PIN_BASED_EXT_INTR_MASK | \
- PIN_BASED_NMI_EXITING \
- )
-
-#define MONITOR_CPU_BASED_EXEC_CONTROLS_RESERVED_VALUE 0x0401e172
-
-#define _MONITOR_CPU_BASED_EXEC_CONTROLS \
- ( \
- MONITOR_CPU_BASED_EXEC_CONTROLS_RESERVED_VALUE | \
- CPU_BASED_HLT_EXITING | \
- CPU_BASED_INVDPG_EXITING | \
- CPU_BASED_MWAIT_EXITING | \
- CPU_BASED_MOV_DR_EXITING | \
- CPU_BASED_ACTIVATE_IO_BITMAP | \
- CPU_BASED_USE_TSC_OFFSETING \
- )
-
-#define MONITOR_CPU_BASED_EXEC_CONTROLS_IA32E_MODE \
- ( \
- CPU_BASED_CR8_LOAD_EXITING | \
- CPU_BASED_CR8_STORE_EXITING \
- )
-
-#define MONITOR_VM_EXIT_CONTROLS_RESERVED_VALUE 0x0003edff
-
-#define MONITOR_VM_EXIT_CONTROLS_IA32E_MODE 0x00000200
-
-#define _MONITOR_VM_EXIT_CONTROLS \
- ( \
- MONITOR_VM_EXIT_CONTROLS_RESERVED_VALUE | \
- VM_EXIT_ACK_INTR_ON_EXIT \
- )
-
-#if defined (__x86_64__)
-#define MONITOR_CPU_BASED_EXEC_CONTROLS \
- ( \
- _MONITOR_CPU_BASED_EXEC_CONTROLS | \
- MONITOR_CPU_BASED_EXEC_CONTROLS_IA32E_MODE \
- )
-#define MONITOR_VM_EXIT_CONTROLS \
- ( \
- _MONITOR_VM_EXIT_CONTROLS | \
- MONITOR_VM_EXIT_CONTROLS_IA32E_MODE \
- )
-#else
-#define MONITOR_CPU_BASED_EXEC_CONTROLS \
- _MONITOR_CPU_BASED_EXEC_CONTROLS
-
-#define MONITOR_VM_EXIT_CONTROLS \
- _MONITOR_VM_EXIT_CONTROLS
-#endif
-
-#define VM_ENTRY_CONTROLS_RESERVED_VALUE 0x000011ff
-#define VM_ENTRY_CONTROLS_IA32E_MODE 0x00000200
-
-#define MONITOR_VM_ENTRY_CONTROLS \
- VM_ENTRY_CONTROLS_RESERVED_VALUE
-
-/*
* Exit Reasons
*/
#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000
@@ -161,6 +92,7 @@ extern unsigned int cpu_rev;
#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */
#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */
+#define INTR_TYPE_NMI (2 << 8) /* NMI */
#define INTR_TYPE_HW_EXCEPTION (3 << 8) /* hardware exception */
#define INTR_TYPE_SW_EXCEPTION (6 << 8) /* software exception */
@@ -250,135 +182,55 @@ static inline void __vmpclear(u64 addr)
: "memory");
}
-#define __vmread(x, ptr) ___vmread((x), (ptr), sizeof(*(ptr)))
-
-static always_inline int ___vmread(
- const unsigned long field, void *ptr, const int size)
+static inline unsigned long __vmread(unsigned long field)
{
- unsigned long ecx = 0;
- int rc;
+ unsigned long ecx;
__asm__ __volatile__ ( VMREAD_OPCODE
MODRM_EAX_ECX
- /* CF==1 or ZF==1 --> rc = -1 */
- "setna %b0 ; neg %0"
- : "=q" (rc), "=c" (ecx)
- : "0" (0), "a" (field)
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ : "=c" (ecx)
+ : "a" (field)
: "memory");
- switch ( size ) {
- case 1:
- *((u8 *) (ptr)) = ecx;
- break;
- case 2:
- *((u16 *) (ptr)) = ecx;
- break;
- case 4:
- *((u32 *) (ptr)) = ecx;
- break;
- case 8:
- *((u64 *) (ptr)) = ecx;
- break;
- default:
- domain_crash_synchronous();
- break;
- }
-
- return rc;
-}
-
-
-static always_inline void __vmwrite_vcpu(
- struct vcpu *v, unsigned long field, unsigned long value)
-{
- switch ( field ) {
- case CR0_READ_SHADOW:
- v->arch.hvm_vmx.cpu_shadow_cr0 = value;
- break;
- case GUEST_CR0:
- v->arch.hvm_vmx.cpu_cr0 = value;
- break;
- case CR4_READ_SHADOW:
- v->arch.hvm_vmx.cpu_shadow_cr4 = value;
- break;
- case CPU_BASED_VM_EXEC_CONTROL:
- v->arch.hvm_vmx.cpu_based_exec_control = value;
- break;
- default:
- printk("__vmwrite_cpu: invalid field %lx\n", field);
- break;
- }
+ return ecx;
}
-static always_inline void __vmread_vcpu(
- struct vcpu *v, unsigned long field, unsigned long *value)
+static inline void __vmwrite(unsigned long field, unsigned long value)
{
- switch ( field ) {
- case CR0_READ_SHADOW:
- *value = v->arch.hvm_vmx.cpu_shadow_cr0;
- break;
- case GUEST_CR0:
- *value = v->arch.hvm_vmx.cpu_cr0;
- break;
- case CR4_READ_SHADOW:
- *value = v->arch.hvm_vmx.cpu_shadow_cr4;
- break;
- case CPU_BASED_VM_EXEC_CONTROL:
- *value = v->arch.hvm_vmx.cpu_based_exec_control;
- break;
- default:
- printk("__vmread_vcpu: invalid field %lx\n", field);
- break;
- }
+ __asm__ __volatile__ ( VMWRITE_OPCODE
+ MODRM_EAX_ECX
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (field) , "c" (value)
+ : "memory");
}
-static inline int __vmwrite(unsigned long field, unsigned long value)
+static inline unsigned long __vmread_safe(unsigned long field, int *error)
{
- struct vcpu *v = current;
- int rc;
+ unsigned long ecx;
- __asm__ __volatile__ ( VMWRITE_OPCODE
+ __asm__ __volatile__ ( VMREAD_OPCODE
MODRM_EAX_ECX
/* CF==1 or ZF==1 --> rc = -1 */
"setna %b0 ; neg %0"
- : "=q" (rc)
- : "0" (0), "a" (field) , "c" (value)
+ : "=q" (*error), "=c" (ecx)
+ : "0" (0), "a" (field)
: "memory");
- switch ( field ) {
- case CR0_READ_SHADOW:
- case GUEST_CR0:
- case CR4_READ_SHADOW:
- case CPU_BASED_VM_EXEC_CONTROL:
- __vmwrite_vcpu(v, field, value);
- break;
- }
-
- return rc;
+ return ecx;
}
-static inline int __vm_set_bit(unsigned long field, unsigned long mask)
+static inline void __vm_set_bit(unsigned long field, unsigned long mask)
{
- unsigned long tmp;
- int err = 0;
-
- err |= __vmread(field, &tmp);
- tmp |= mask;
- err |= __vmwrite(field, tmp);
-
- return err;
+ __vmwrite(field, __vmread(field) | mask);
}
-static inline int __vm_clear_bit(unsigned long field, unsigned long mask)
+static inline void __vm_clear_bit(unsigned long field, unsigned long mask)
{
- unsigned long tmp;
- int err = 0;
-
- err |= __vmread(field, &tmp);
- tmp &= ~mask;
- err |= __vmwrite(field, tmp);
-
- return err;
+ __vmwrite(field, __vmread(field) & ~mask);
}
static inline void __vmxoff (void)
@@ -402,30 +254,22 @@ static inline int __vmxon (u64 addr)
return rc;
}
-/* Works only for vcpu == current */
static inline int vmx_paging_enabled(struct vcpu *v)
{
- unsigned long cr0;
-
- __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
- return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
+ unsigned long cr0 = v->arch.hvm_vmx.cpu_shadow_cr0;
+ return ((cr0 & (X86_CR0_PE|X86_CR0_PG)) == (X86_CR0_PE|X86_CR0_PG));
}
-/* Works only for vcpu == current */
static inline int vmx_long_mode_enabled(struct vcpu *v)
{
- ASSERT(v == current);
- return VMX_LONG_GUEST(current);
+ u64 efer = v->arch.hvm_vmx.msr_state.msrs[VMX_INDEX_MSR_EFER];
+ return efer & EFER_LMA;
}
-/* Works only for vcpu == current */
-static inline int vmx_realmode(struct vcpu *v)
+static inline int vmx_lme_is_set(struct vcpu *v)
{
- unsigned long rflags;
- ASSERT(v == current);
-
- __vmread(GUEST_RFLAGS, &rflags);
- return rflags & X86_EFLAGS_VM;
+ u64 efer = v->arch.hvm_vmx.msr_state.msrs[VMX_INDEX_MSR_EFER];
+ return efer & EFER_LME;
}
/* Works only for vcpu == current */
@@ -435,27 +279,9 @@ static inline void vmx_update_host_cr3(struct vcpu *v)
__vmwrite(HOST_CR3, v->arch.cr3);
}
-static inline int vmx_guest_x86_mode(struct vcpu *v)
-{
- unsigned long cs_ar_bytes;
- ASSERT(v == current);
-
- if ( vmx_long_mode_enabled(v) )
- {
- __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
- return (cs_ar_bytes & (1u<<13)) ? 8 : 4;
- }
- if ( vmx_realmode(v) )
- return 2;
- __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
- return (cs_ar_bytes & (1u<<14)) ? 4 : 2;
-}
-
static inline int vmx_pgbit_test(struct vcpu *v)
{
- unsigned long cr0;
-
- __vmread_vcpu(v, CR0_READ_SHADOW, &cr0);
+ unsigned long cr0 = v->arch.hvm_vmx.cpu_shadow_cr0;
return (cr0 & X86_CR0_PG);
}
@@ -469,7 +295,7 @@ static inline void __vmx_inject_exception(struct vcpu *v, int trap, int type,
if ( error_code != VMX_DELIVER_NO_ERROR_CODE ) {
__vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
intr_fields |= INTR_INFO_DELIVER_CODE_MASK;
- }
+ }
if ( ilen )
__vmwrite(VM_ENTRY_INSTRUCTION_LEN, ilen);
@@ -499,40 +325,4 @@ static inline void vmx_inject_extint(struct vcpu *v, int trap, int error_code)
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
}
-static inline void vmx_reflect_exception(struct vcpu *v)
-{
- int error_code, intr_info, vector;
-
- __vmread(VM_EXIT_INTR_INFO, &intr_info);
- vector = intr_info & 0xff;
- if ( intr_info & INTR_INFO_DELIVER_CODE_MASK )
- __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
- else
- error_code = VMX_DELIVER_NO_ERROR_CODE;
-
-#ifndef NDEBUG
- {
- unsigned long rip;
-
- __vmread(GUEST_RIP, &rip);
- HVM_DBG_LOG(DBG_LEVEL_1, "rip = %lx, error_code = %x",
- rip, error_code);
- }
-#endif /* NDEBUG */
-
- /* According to Intel Virtualization Technology Specification for
- the IA-32 Intel Architecture (C97063-002 April 2005), section
- 2.8.3, SW_EXCEPTION should be used for #BP and #OV, and
- HW_EXCPEPTION used for everything else. The main difference
- appears to be that for SW_EXCEPTION, the EIP/RIP is incremented
- by VM_ENTER_INSTRUCTION_LEN bytes, whereas for HW_EXCEPTION,
- it is not. */
- if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_SW_EXCEPTION ) {
- int ilen;
- __vmread(VM_EXIT_INSTRUCTION_LEN, &ilen);
- vmx_inject_sw_exception(v, vector, ilen);
- } else
- vmx_inject_hw_exception(v, vector, error_code);
-}
-
#endif /* __ASM_X86_HVM_VMX_VMX_H__ */
diff --git a/xen/include/asm-x86/hvm/vpic.h b/xen/include/asm-x86/hvm/vpic.h
index 8fa5daa5ad..2195529df6 100644
--- a/xen/include/asm-x86/hvm/vpic.h
+++ b/xen/include/asm-x86/hvm/vpic.h
@@ -1,14 +1,15 @@
/*
- * QEMU System Emulator header
+ * i8259 interrupt controller emulation
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2005 Intel Corp
+ * Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* 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
+ * 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
@@ -18,68 +19,64 @@
* 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.
+ * 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 __ASM_X86_HVM_VPIC_H__
#define __ASM_X86_HVM_VPIC_H__
-#define hw_error(x) do {} while (0);
+struct vpic {
+ /* IR line bitmasks. */
+ uint8_t irr, imr, isr;
-
-/* i8259.c */
-typedef struct IOAPICState IOAPICState;
-typedef struct PicState {
- uint8_t last_irr; /* edge detection */
- uint8_t irr; /* interrupt request register */
- uint8_t imr; /* interrupt mask register */
- uint8_t isr; /* interrupt service register */
- uint8_t priority_add; /* highest irq priority */
+ /* Line IRx maps to IRQ irq_base+x */
uint8_t irq_base;
- uint8_t read_reg_select;
- uint8_t poll;
- uint8_t special_mask;
- uint8_t init_state;
- uint8_t auto_eoi;
- uint8_t rotate_on_auto_eoi;
- uint8_t special_fully_nested_mode;
- uint8_t init4; /* true if 4 byte init */
- uint8_t elcr; /* PIIX edge/trigger selection*/
- uint8_t elcr_mask;
- struct hvm_virpic *pics_state;
-} PicState;
-
-struct hvm_virpic {
- /* 0 is master pic, 1 is slave pic */
- /* XXX: better separation between the two pics */
- PicState pics[2];
- void (*irq_request)(void *opaque, int level);
- void *irq_request_opaque;
- /* IOAPIC callback support */
- void (*alt_irq_func)(void *opaque, int irq_num, int level);
- void *alt_irq_opaque;
- spinlock_t lock;
-};
+ /*
+ * Where are we in ICW2-4 initialisation (0 means no init in progress)?
+ * Bits 0-1 (=x): Next write at A=1 sets ICW(x+1).
+ * Bit 2: ICW1.IC4 (1 == ICW4 included in init sequence)
+ * Bit 3: ICW1.SNGL (0 == ICW3 included in init sequence)
+ */
+ uint8_t init_state:4;
+
+ /* IR line with highest priority. */
+ uint8_t priority_add:4;
+
+ /* Reads from A=0 obtain ISR or IRR? */
+ uint8_t readsel_isr:1;
+
+ /* Reads perform a polling read? */
+ uint8_t poll:1;
+
+ /* Automatically clear IRQs from the ISR during INTA? */
+ uint8_t auto_eoi:1;
+
+ /* Automatically rotate IRQ priorities during AEOI? */
+ uint8_t rotate_on_auto_eoi:1;
+
+ /* Exclude slave inputs when considering in-service IRQs? */
+ uint8_t special_fully_nested_mode:1;
+
+ /* Special mask mode excludes masked IRs from AEOI and priority checks. */
+ uint8_t special_mask_mode:1;
+
+ /* Is this a master PIC or slave PIC? (NB. This is not programmable.) */
+ uint8_t is_master:1;
+
+ /* Edge/trigger selection. */
+ uint8_t elcr;
+
+ /* Virtual INT output. */
+ uint8_t int_output;
+};
-void pic_set_irq(struct hvm_virpic *s, int irq, int level);
-void pic_set_irq_new(void *opaque, int irq, int level);
-void pic_init(struct hvm_virpic *s,
- void (*irq_request)(void *, int),
- void *irq_request_opaque);
-void pic_set_alt_irq_func(struct hvm_virpic *s,
- void (*alt_irq_func)(void *, int, int),
- void *alt_irq_opaque);
-int pic_read_irq(struct hvm_virpic *s);
-void pic_update_irq(struct hvm_virpic *s); /* Caller must hold s->lock */
-uint32_t pic_intack_read(struct hvm_virpic *s);
-void register_pic_io_hook (void);
+void vpic_irq_positive_edge(struct domain *d, int irq);
+void vpic_irq_negative_edge(struct domain *d, int irq);
+void vpic_init(struct domain *d);
int cpu_get_pic_interrupt(struct vcpu *v, int *type);
-int is_pit_irq(struct vcpu *v, int irq, int type);
-int is_irq_enabled(struct vcpu *v, int irq);
-void do_pic_irqs (struct hvm_virpic *s, uint16_t irqs);
-void do_pic_irqs_clear (struct hvm_virpic *s, uint16_t irqs);
+int is_periodic_irq(struct vcpu *v, int irq, int type);
#endif /* __ASM_X86_HVM_VPIC_H__ */
diff --git a/xen/include/asm-x86/hvm/vpit.h b/xen/include/asm-x86/hvm/vpt.h
index eb3ccd1207..95a4937421 100644
--- a/xen/include/asm-x86/hvm/vpit.h
+++ b/xen/include/asm-x86/hvm/vpt.h
@@ -1,5 +1,5 @@
/*
- * vpit.h: Virtual PIT definitions
+ * vpt.h: Virtual Platform Timer definitions
*
* Copyright (c) 2004, Intel Corporation.
*
@@ -17,19 +17,20 @@
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __ASM_X86_HVM_VPIT_H__
-#define __ASM_X86_HVM_VPIT_H__
+#ifndef __ASM_X86_HVM_VPT_H__
+#define __ASM_X86_HVM_VPT_H__
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/time.h>
#include <xen/errno.h>
+#include <xen/time.h>
#include <xen/timer.h>
#include <asm/hvm/vpic.h>
#define PIT_FREQ 1193181
-#define PIT_BASE 0x40
+#define PIT_BASE 0x40
typedef struct PITChannelState {
int count; /* can be 65536 */
@@ -49,55 +50,90 @@ typedef struct PITChannelState {
struct vcpu *vcpu;
struct periodic_time *pt;
} PITChannelState;
-
+
+typedef struct PITState {
+ PITChannelState channels[3];
+ int speaker_data_on;
+ int dummy_refresh_clock;
+} PITState;
+
+#define RTC_SIZE 14
+typedef struct RTCState {
+ uint8_t cmos_data[RTC_SIZE]; /* Only handle time/interrupt part in HV */
+ uint8_t cmos_index;
+ struct tm current_tm;
+ int irq;
+ /* second update */
+ int64_t next_second_time;
+ struct timer second_timer;
+ struct timer second_timer2;
+ struct timer pie_timer;
+ int period;
+ s_time_t next_pie;
+ struct vcpu *vcpu;
+} RTCState;
+
+#define FREQUENCE_PMTIMER 3579545
+typedef struct PMTState {
+ uint32_t pm1_timer;
+ uint32_t pm1_status;
+ uint64_t last_gtime;
+ struct timer timer;
+ uint64_t scale;
+ struct vcpu *vcpu;
+} PMTState;
+
/*
* Abstract layer of periodic time, one short time.
*/
+typedef void time_cb(struct vcpu *v, void *opaque);
+
struct periodic_time {
char enabled; /* enabled */
char one_shot; /* one shot time */
char irq;
char first_injected; /* flag to prevent shadow window */
+ u32 bind_vcpu; /* vcpu timer interrupt delivers to */
u32 pending_intr_nr; /* the couner for pending timer interrupts */
u32 period; /* frequency in ns */
u64 period_cycles; /* frequency in cpu cycles */
s_time_t scheduled; /* scheduled timer interrupt */
u64 last_plt_gtime; /* platform time when last IRQ is injected */
struct timer timer; /* ac_timer */
+ time_cb *cb;
void *priv; /* ponit back to platform time source */
};
-typedef struct PITState {
- PITChannelState channels[3];
- int speaker_data_on;
- int dummy_refresh_clock;
-} PITState;
-
struct pl_time { /* platform time */
struct periodic_time periodic_tm;
struct PITState vpit;
- /* TODO: RTC/ACPI time */
+ struct RTCState vrtc;
+ struct PMTState vpmt;
};
-static __inline__ s_time_t get_scheduled(
- struct vcpu *v, int irq,
- struct periodic_time *pt)
+extern u64 hvm_get_guest_time(struct vcpu *v);
+static inline int64_t hvm_get_clock(struct vcpu *v)
{
- if ( is_irq_enabled(v, irq) ) {
- return pt->scheduled;
- }
- else
- return -1;
+ return hvm_get_guest_time(v);
}
+#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
+
/* to hook the ioreq packet to get the PIT initialization info */
extern void hvm_hooks_assist(struct vcpu *v);
extern void pickup_deactive_ticks(struct periodic_time *vpit);
-extern u64 hvm_get_guest_time(struct vcpu *v);
-extern struct periodic_time *create_periodic_time(PITChannelState *v, u32 period, char irq, char one_shot);
+extern struct periodic_time *create_periodic_time(
+ u32 period, char irq, char one_shot, time_cb *cb, void *data);
extern void destroy_periodic_time(struct periodic_time *pt);
void pit_init(struct vcpu *v, unsigned long cpu_khz);
+void rtc_init(struct vcpu *v, int base, int irq);
+void rtc_deinit(struct domain *d);
+void rtc_freeze(struct vcpu *v);
+void rtc_thaw(struct vcpu *v);
+void rtc_migrate_timers(struct vcpu *v);
+void pmtimer_init(struct vcpu *v, int base);
+void pmtimer_deinit(struct domain *d);
void pt_timer_fn(void *data);
void pit_time_fired(struct vcpu *v, void *priv);
-#endif /* __ASM_X86_HVM_VPIT_H__ */
+#endif /* __ASM_X86_HVM_VPT_H__ */
diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h
index 47cd148e10..f256f5cd19 100644
--- a/xen/include/asm-x86/io_apic.h
+++ b/xen/include/asm-x86/io_apic.h
@@ -165,6 +165,7 @@ extern int io_apic_get_unique_id (int ioapic, int apic_id);
extern int io_apic_get_version (int ioapic);
extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low);
+extern int timer_uses_ioapic_pin_0;
#endif /*CONFIG_ACPI_BOOT*/
extern int (*ioapic_renumber_irq)(int ioapic, int irq);
diff --git a/xen/include/asm-x86/mach-generic/mach_apic.h b/xen/include/asm-x86/mach-generic/mach_apic.h
index 1d3ed4dc67..1e0a6019d6 100644
--- a/xen/include/asm-x86/mach-generic/mach_apic.h
+++ b/xen/include/asm-x86/mach-generic/mach_apic.h
@@ -22,11 +22,7 @@ static inline void enable_apic_mode(void)
return;
}
-/* No sane NUMA support right now. We should parse ACPI SRAT. */
-static inline int apicid_to_node(int logical_apicid)
-{
- return 0;
-}
+#define apicid_to_node(apicid) ((int)apicid_to_node[(u8)apicid])
extern u8 bios_cpu_apicid[];
static inline int cpu_present_to_apicid(int mps_cpu)
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index cb4efe9734..93d96df4fd 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -20,11 +20,7 @@
struct page_info
{
/* Each frame can be threaded onto a doubly-linked list. */
- union {
- struct list_head list;
- /* Shadow uses this field as an up-pointer in lower-level shadows */
- paddr_t up;
- };
+ struct list_head list;
/* Reference count and various PGC_xxx flags and fields. */
u32 count_info;
@@ -51,18 +47,19 @@ struct page_info
} u;
union {
- /* Timestamp from 'TLB clock', used to reduce need for safety
- * flushes. Only valid on a) free pages, and b) guest pages with a
- * zero type count. */
+ /*
+ * Timestamp from 'TLB clock', used to avoid extra safety flushes.
+ * Only valid for: a) free pages, and b) pages with zero type count
+ * (except page table pages when the guest is in shadow mode).
+ */
u32 tlbflush_timestamp;
- /* Only used on guest pages with a shadow.
- * Guest pages with a shadow must have a non-zero type count, so this
- * does not conflict with the tlbflush timestamp. */
- u32 shadow_flags;
-
- // XXX -- we expect to add another field here, to be used for min/max
- // purposes, which is only used for shadow pages.
+ /*
+ * Guest pages with a shadow. This does not conflict with
+ * tlbflush_timestamp since page table pages are explicitly not
+ * tracked for TLB-flush avoidance when a guest runs in shadow mode.
+ */
+ unsigned long shadow_flags;
};
};
@@ -75,19 +72,6 @@ struct page_info
#define PGT_gdt_page (5U<<29) /* using this page in a GDT? */
#define PGT_ldt_page (6U<<29) /* using this page in an LDT? */
#define PGT_writable_page (7U<<29) /* has writable mappings of this page? */
-
-#ifndef SHADOW
-#define PGT_l1_shadow PGT_l1_page_table
-#define PGT_l2_shadow PGT_l2_page_table
-#define PGT_l3_shadow PGT_l3_page_table
-#define PGT_l4_shadow PGT_l4_page_table
-#define PGT_hl2_shadow (5U<<29)
-#define PGT_snapshot (6U<<29)
-#define PGT_writable_pred (7U<<29) /* predicted gpfn with writable ref */
-
-#define PGT_fl1_shadow (5U<<29)
-#endif
-
#define PGT_type_mask (7U<<29) /* Bits 29-31. */
/* Owning guest has pinned this page to its current type? */
@@ -96,44 +80,13 @@ struct page_info
/* Has this page been validated for use as its current type? */
#define _PGT_validated 27
#define PGT_validated (1U<<_PGT_validated)
-#if defined(__i386__)
- /* The 11 most significant bits of virt address if this is a page table. */
-#define PGT_va_shift 16
-#define PGT_va_mask (((1U<<11)-1)<<PGT_va_shift)
- /* Is the back pointer still mutable (i.e. not fixed yet)? */
-#define PGT_va_mutable (((1U<<11)-1)<<PGT_va_shift)
- /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown (((1U<<11)-2)<<PGT_va_shift)
-#elif defined(__x86_64__)
- /* The 27 most significant bits of virt address if this is a page table. */
-#define PGT_va_shift 32
-#define PGT_va_mask ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer still mutable (i.e. not fixed yet)? */
-#define PGT_va_mutable ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
- /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown ((unsigned long)((1U<<28)-2)<<PGT_va_shift)
-#endif
+ /* PAE only: is this an L2 page directory containing Xen-private mappings? */
+#define _PGT_pae_xen_l2 26
+#define PGT_pae_xen_l2 (1U<<_PGT_pae_xen_l2)
/* 16-bit count of uses of this frame as its current type. */
#define PGT_count_mask ((1U<<16)-1)
-#ifndef SHADOW
-#ifdef __x86_64__
-#define PGT_high_mfn_shift 52
-#define PGT_high_mfn_mask (0xfffUL << PGT_high_mfn_shift)
-#define PGT_mfn_mask (((1U<<27)-1) | PGT_high_mfn_mask)
-#define PGT_high_mfn_nx (0x800UL << PGT_high_mfn_shift)
-#else
- /* 23-bit mfn mask for shadow types: good for up to 32GB RAM. */
-#define PGT_mfn_mask ((1U<<23)-1)
- /* NX for PAE xen is not supported yet */
-#define PGT_high_mfn_nx (1ULL << 63)
-
-#define PGT_score_shift 23
-#define PGT_score_mask (((1U<<4)-1)<<PGT_score_shift)
-#endif
-#endif /* SHADOW */
-
/* Cleared when the owning guest 'frees' this page. */
#define _PGC_allocated 31
#define PGC_allocated (1U<<_PGC_allocated)
@@ -146,39 +99,6 @@ struct page_info
/* 29-bit count of references to this frame. */
#define PGC_count_mask ((1U<<29)-1)
-/* shadow uses the count_info on shadow pages somewhat differently */
-/* NB: please coordinate any changes here with the SHF's in shadow.h */
-#define PGC_SH_none (0U<<28) /* on the shadow free list */
-#define PGC_SH_min_shadow (1U<<28)
-#define PGC_SH_l1_32_shadow (1U<<28) /* shadowing a 32-bit L1 guest page */
-#define PGC_SH_fl1_32_shadow (2U<<28) /* L1 shadow for a 32b 4M superpage */
-#define PGC_SH_l2_32_shadow (3U<<28) /* shadowing a 32-bit L2 guest page */
-#define PGC_SH_l1_pae_shadow (4U<<28) /* shadowing a pae L1 page */
-#define PGC_SH_fl1_pae_shadow (5U<<28) /* L1 shadow for pae 2M superpg */
-#define PGC_SH_l2_pae_shadow (6U<<28) /* shadowing a pae L2-low page */
-#define PGC_SH_l2h_pae_shadow (7U<<28) /* shadowing a pae L2-high page */
-#define PGC_SH_l3_pae_shadow (8U<<28) /* shadowing a pae L3 page */
-#define PGC_SH_l1_64_shadow (9U<<28) /* shadowing a 64-bit L1 page */
-#define PGC_SH_fl1_64_shadow (10U<<28) /* L1 shadow for 64-bit 2M superpg */
-#define PGC_SH_l2_64_shadow (11U<<28) /* shadowing a 64-bit L2 page */
-#define PGC_SH_l3_64_shadow (12U<<28) /* shadowing a 64-bit L3 page */
-#define PGC_SH_l4_64_shadow (13U<<28) /* shadowing a 64-bit L4 page */
-#define PGC_SH_max_shadow (13U<<28)
-#define PGC_SH_p2m_table (14U<<28) /* in use as the p2m table */
-#define PGC_SH_monitor_table (15U<<28) /* in use as a monitor table */
-#define PGC_SH_unused (15U<<28)
-
-#define PGC_SH_type_mask (15U<<28)
-#define PGC_SH_type_shift 28
-
-#define PGC_SH_pinned (1U<<27)
-
-#define _PGC_SH_log_dirty 26
-#define PGC_SH_log_dirty (1U<<26)
-
-/* 26 bit ref count for shadow pages */
-#define PGC_SH_count_mask ((1U<<26) - 1)
-
/* We trust the slab allocator in slab.c, and our use of it. */
#define PageSlab(page) (1)
#define PageSetSlab(page) ((void)0)
@@ -223,11 +143,8 @@ void init_frametable(void);
int alloc_page_type(struct page_info *page, unsigned long type);
void free_page_type(struct page_info *page, unsigned long type);
-extern void invalidate_shadow_ldt(struct vcpu *d);
-extern int shadow_remove_all_write_access(
- struct domain *d, unsigned long gmfn, unsigned long mfn);
-extern u32 shadow_remove_all_access( struct domain *d, unsigned long gmfn);
-extern int _shadow_mode_refcounts(struct domain *d);
+void invalidate_shadow_ldt(struct vcpu *d);
+int _shadow_mode_refcounts(struct domain *d);
static inline void put_page(struct page_info *page)
{
@@ -260,7 +177,8 @@ static inline int get_page(struct page_info *page,
unlikely(d != _domain) ) /* Wrong owner? */
{
if ( !_shadow_mode_refcounts(domain) )
- DPRINTK("Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%"
+ gdprintk(XENLOG_INFO,
+ "Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%"
PRtype_info "\n",
page_to_mfn(page), domain, unpickle_domptr(d),
x, page->u.inuse.type_info);
@@ -350,37 +268,7 @@ int check_descriptor(struct desc_struct *d);
#define gmfn_to_mfn(_d, gpfn) mfn_x(sh_gfn_to_mfn(_d, gpfn))
-
-/*
- * The phys_to_machine_mapping is the reversed mapping of MPT for full
- * virtualization. It is only used by shadow_mode_translate()==true
- * guests, so we steal the address space that would have normally
- * been used by the read-only MPT map.
- */
-#define phys_to_machine_mapping ((l1_pgentry_t *)RO_MPT_VIRT_START)
#define INVALID_MFN (~0UL)
-#define VALID_MFN(_mfn) (!((_mfn) & (1U<<31)))
-
-static inline unsigned long get_mfn_from_gpfn(unsigned long pfn)
-{
- l1_pgentry_t l1e = l1e_empty();
- int ret;
-
-#if CONFIG_PAGING_LEVELS > 2
- if ( pfn >= (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t) )
- /* This pfn is higher than the p2m map can hold */
- return INVALID_MFN;
-#endif
-
- ret = __copy_from_user(&l1e,
- &phys_to_machine_mapping[pfn],
- sizeof(l1e));
-
- if ( (ret == 0) && (l1e_get_flags(l1e) & _PAGE_PRESENT) )
- return l1e_get_pfn(l1e);
-
- return INVALID_MFN;
-}
#ifdef MEMORY_GUARD
void memguard_init(void);
@@ -394,7 +282,7 @@ void memguard_unguard_range(void *p, unsigned long l);
void memguard_guard_stack(void *p);
-int ptwr_do_page_fault(struct domain *, unsigned long,
+int ptwr_do_page_fault(struct vcpu *, unsigned long,
struct cpu_user_regs *);
int audit_adjust_pgtables(struct domain *d, int dir, int noisy);
@@ -431,4 +319,6 @@ long subarch_memory_op(int op, XEN_GUEST_HANDLE(void) arg);
int steal_page(
struct domain *d, struct page_info *page, unsigned int memflags);
+int map_ldt_shadow_page(unsigned int);
+
#endif /* __ASM_X86_MM_H__ */
diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h
index 07c09b2ae2..31e2afd8bf 100644
--- a/xen/include/asm-x86/msr.h
+++ b/xen/include/asm-x86/msr.h
@@ -302,8 +302,14 @@ static inline void wrmsrl(unsigned int msr, __u64 val)
#define MSR_K8_TOP_MEM1 0xC001001A
#define MSR_K8_TOP_MEM2 0xC001001D
+#define MSR_K8_SYSCFG 0xC0010010
+#define MSR_K8_HWCR 0xC0010015
+#define MSR_K8_VM_CR 0xC0010114
#define MSR_K8_VM_HSAVE_PA 0xC0010117
-#define MSR_K8_SYSCFG 0xC0000010
+
+/* MSR_K8_VM_CR bits: */
+#define _K8_VMCR_SVME_DISABLE 4
+#define K8_VMCR_SVME_DISABLE (1 << _K8_VMCR_SVME_DISABLE)
/* Centaur-Hauls/IDT defined MSRs. */
#define MSR_IDT_FCR1 0x107
diff --git a/xen/include/asm-x86/multicall.h b/xen/include/asm-x86/multicall.h
index 5fe37176fa..1ce7866c3e 100644
--- a/xen/include/asm-x86/multicall.h
+++ b/xen/include/asm-x86/multicall.h
@@ -16,7 +16,7 @@
" movq "STR(MULTICALL_op)"(%0),%%rax; " \
" cmpq $("STR(NR_hypercalls)"),%%rax; " \
" jae 2f; " \
- " leaq "STR(hypercall_table)"(%%rip),%%rdi; "\
+ " leaq hypercall_table(%%rip),%%rdi; " \
" leaq (%%rdi,%%rax,8),%%rax; " \
" movq "STR(MULTICALL_arg0)"(%0),%%rdi; " \
" movq "STR(MULTICALL_arg1)"(%0),%%rsi; " \
diff --git a/xen/include/asm-x86/numa.h b/xen/include/asm-x86/numa.h
new file mode 100644
index 0000000000..caa6491c96
--- /dev/null
+++ b/xen/include/asm-x86/numa.h
@@ -0,0 +1,78 @@
+#ifndef _ASM_X8664_NUMA_H
+#define _ASM_X8664_NUMA_H 1
+
+#include <xen/cpumask.h>
+
+#define NODES_SHIFT 6
+
+extern unsigned char cpu_to_node[];
+extern cpumask_t node_to_cpumask[];
+
+#define cpu_to_node(cpu) (cpu_to_node[cpu])
+#define parent_node(node) (node)
+#define node_to_first_cpu(node) (__ffs(node_to_cpumask[node]))
+#define node_to_cpumask(node) (node_to_cpumask[node])
+
+struct node {
+ u64 start,end;
+};
+
+extern int compute_hash_shift(struct node *nodes, int numnodes);
+extern int pxm_to_node(int nid);
+
+#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
+#define VIRTUAL_BUG_ON(x)
+#define NODEMAPSIZE 0xfff
+
+extern void numa_add_cpu(int cpu);
+extern void numa_init_array(void);
+extern int numa_off;
+
+extern void numa_set_node(int cpu, int node);
+
+extern void setup_node_bootmem(int nodeid, u64 start, u64 end);
+extern unsigned char apicid_to_node[256];
+#ifdef CONFIG_NUMA
+extern void __init init_cpu_to_node(void);
+
+static inline void clear_node_cpumask(int cpu)
+{
+ clear_bit(cpu, &node_to_cpumask[cpu_to_node(cpu)]);
+}
+
+/* Simple perfect hash to map physical addresses to node numbers */
+extern int memnode_shift;
+extern u8 memnodemap[NODEMAPSIZE];
+
+struct node_data {
+ unsigned long node_start_pfn;
+ unsigned long node_spanned_pages;
+ unsigned int node_id;
+};
+
+extern struct node_data node_data[];
+
+static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
+{
+ unsigned nid;
+ VIRTUAL_BUG_ON((addr >> memnode_shift) >= NODEMAPSIZE);
+ nid = memnodemap[addr >> memnode_shift];
+ VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
+ return nid;
+}
+
+#define NODE_DATA(nid) (&(node_data[nid]))
+
+#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \
+ NODE_DATA(nid)->node_spanned_pages)
+
+
+#else
+#define init_cpu_to_node() do {} while (0)
+#define clear_node_cpumask(cpu) do {} while (0)
+#endif
+
+#define NUMA_NO_NODE 0xff
+
+#endif
diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
index 905d76d576..b9c921a5cd 100644
--- a/xen/include/asm-x86/page.h
+++ b/xen/include/asm-x86/page.h
@@ -25,6 +25,18 @@
# include <asm/x86_64/page.h>
#endif
+/* Read a pte atomically from memory. */
+#define l1e_read_atomic(l1ep) l1e_from_intpte(pte_read_atomic(l1ep))
+#define l2e_read_atomic(l2ep) l2e_from_intpte(pte_read_atomic(l2ep))
+#define l3e_read_atomic(l3ep) l3e_from_intpte(pte_read_atomic(l3ep))
+#define l4e_read_atomic(l4ep) l4e_from_intpte(pte_read_atomic(l4ep))
+
+/* Write a pte atomically to memory. */
+#define l1e_write_atomic(l1ep, l1e) pte_write_atomic(l1ep, l1e_get_intpte(l1e))
+#define l2e_write_atomic(l2ep, l2e) pte_write_atomic(l2ep, l1e_get_intpte(l2e))
+#define l3e_write_atomic(l3ep, l3e) pte_write_atomic(l3ep, l1e_get_intpte(l3e))
+#define l4e_write_atomic(l4ep, l4e) pte_write_atomic(l4ep, l1e_get_intpte(l4e))
+
/* Get direct integer representation of a pte's contents (intpte_t). */
#define l1e_get_intpte(x) ((x).l1)
#define l2e_get_intpte(x) ((x).l2)
diff --git a/xen/include/asm-x86/perfc_defn.h b/xen/include/asm-x86/perfc_defn.h
index 73b9ffe9ba..ba1e32c8fd 100644
--- a/xen/include/asm-x86/perfc_defn.h
+++ b/xen/include/asm-x86/perfc_defn.h
@@ -43,6 +43,9 @@ PERFCOUNTER_CPU(shadow_linear_map_failed, "shadow hit read-only linear map")
PERFCOUNTER_CPU(shadow_a_update, "shadow A bit update")
PERFCOUNTER_CPU(shadow_ad_update, "shadow A&D bit update")
PERFCOUNTER_CPU(shadow_fault, "calls to shadow_fault")
+PERFCOUNTER_CPU(shadow_fault_fast_gnp, "shadow_fault fast path n/p")
+PERFCOUNTER_CPU(shadow_fault_fast_mmio, "shadow_fault fast path mmio")
+PERFCOUNTER_CPU(shadow_fault_fast_fail, "shadow_fault fast path error")
PERFCOUNTER_CPU(shadow_fault_bail_bad_gfn, "shadow_fault guest bad gfn")
PERFCOUNTER_CPU(shadow_fault_bail_not_present,
"shadow_fault guest not-present")
@@ -71,18 +74,18 @@ PERFCOUNTER_CPU(shadow_writeable_h_1, "shadow writeable: 32b w2k3")
PERFCOUNTER_CPU(shadow_writeable_h_2, "shadow writeable: 32pae w2k3")
PERFCOUNTER_CPU(shadow_writeable_h_3, "shadow writeable: 64b w2k3")
PERFCOUNTER_CPU(shadow_writeable_h_4, "shadow writeable: 32b linux low")
+PERFCOUNTER_CPU(shadow_writeable_h_5, "shadow writeable: 32b linux high")
PERFCOUNTER_CPU(shadow_writeable_bf, "shadow writeable brute-force")
PERFCOUNTER_CPU(shadow_mappings, "shadow removes all mappings")
PERFCOUNTER_CPU(shadow_mappings_bf, "shadow rm-mappings brute-force")
PERFCOUNTER_CPU(shadow_early_unshadow, "shadow unshadows for fork/exit")
-PERFCOUNTER_CPU(shadow_early_unshadow_top, "shadow unhooks for fork/exit")
PERFCOUNTER_CPU(shadow_unshadow, "shadow unshadows a page")
PERFCOUNTER_CPU(shadow_up_pointer, "shadow unshadow by up-pointer")
PERFCOUNTER_CPU(shadow_unshadow_bf, "shadow unshadow brute-force")
PERFCOUNTER_CPU(shadow_get_page_fail, "shadow_get_page_from_l1e failed")
PERFCOUNTER_CPU(shadow_guest_walk, "shadow walks guest tables")
-PERFCOUNTER_CPU(shadow_walk_cache_hit, "shadow walk-cache hits")
-PERFCOUNTER_CPU(shadow_walk_cache_miss, "shadow walk-cache misses")
+PERFCOUNTER_CPU(shadow_invlpg, "shadow emulates invlpg")
+PERFCOUNTER_CPU(shadow_invlpg_fault, "shadow invlpg faults")
/*#endif*/ /* __XEN_PERFC_DEFN_H__ */
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index 09ecfab041..7a18e0d3d7 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -107,7 +107,7 @@
#define TRAP_deferred_nmi 31
/* Set for entry via SYSCALL. Informs return code to use SYSRETQ not IRETQ. */
-/* NB. Same as VGCF_IN_SYSCALL. No bits in common with any other TRAP_ defn. */
+/* NB. Same as VGCF_in_syscall. No bits in common with any other TRAP_ defn. */
#define TRAP_syscall 256
/*
diff --git a/xen/include/asm-x86/regs.h b/xen/include/asm-x86/regs.h
index 8ba10c4722..48f8b86c85 100644
--- a/xen/include/asm-x86/regs.h
+++ b/xen/include/asm-x86/regs.h
@@ -39,7 +39,7 @@ enum EFLAGS {
/* If a guest frame, it must be have guest privs (unless HVM guest). */ \
/* We permit CS==0 which can come from an uninitialised trap entry. */ \
ASSERT((diff != 0) || vm86_mode(r) || ((r->cs&3) >= GUEST_KERNEL_RPL) || \
- (r->cs == 0) || hvm_guest(current)); \
+ (r->cs == 0) || is_hvm_vcpu(current)); \
/* If not a guest frame, it must be a hypervisor frame. */ \
ASSERT((diff == 0) || (!vm86_mode(r) && (r->cs == __HYPERVISOR_CS))); \
/* Return TRUE if it's a guest frame. */ \
diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h
index f15559ba0a..7bf159b21d 100644
--- a/xen/include/asm-x86/shadow.h
+++ b/xen/include/asm-x86/shadow.h
@@ -23,9 +23,10 @@
#ifndef _XEN_SHADOW_H
#define _XEN_SHADOW_H
-#include <public/domctl.h>
+#include <public/domctl.h>
#include <xen/sched.h>
#include <xen/perfc.h>
+#include <xen/domain_page.h>
#include <asm/flushtlb.h>
/* How to make sure a page is not referred to in a shadow PT */
@@ -63,21 +64,15 @@
#define shadow_mode_external(_d) ((_d)->arch.shadow.mode & SHM2_external)
/* Xen traps & emulates all reads of all page table pages:
- *not yet supported
+ * not yet supported
*/
#define shadow_mode_trap_reads(_d) ({ (void)(_d); 0; })
-// flags used in the return value of the shadow_set_lXe() functions...
-#define SHADOW_SET_CHANGED 0x1
-#define SHADOW_SET_FLUSH 0x2
-#define SHADOW_SET_ERROR 0x4
-#define SHADOW_SET_L3PAE_RECOPY 0x8
-
// How do we tell that we have a 32-bit PV guest in a 64-bit Xen?
#ifdef __x86_64__
#define pv_32bit_guest(_v) 0 // not yet supported
#else
-#define pv_32bit_guest(_v) !hvm_guest(v)
+#define pv_32bit_guest(_v) !is_hvm_vcpu(v)
#endif
/* The shadow lock.
@@ -103,36 +98,36 @@
#error shadow.h currently requires CONFIG_SMP
#endif
-#define shadow_lock_init(_d) \
- do { \
- spin_lock_init(&(_d)->arch.shadow.lock); \
- (_d)->arch.shadow.locker = -1; \
- (_d)->arch.shadow.locker_function = "nobody"; \
+#define shadow_lock_init(_d) \
+ do { \
+ spin_lock_init(&(_d)->arch.shadow.lock); \
+ (_d)->arch.shadow.locker = -1; \
+ (_d)->arch.shadow.locker_function = "nobody"; \
} while (0)
-#define shadow_lock_is_acquired(_d) \
+#define shadow_lock_is_acquired(_d) \
(current->processor == (_d)->arch.shadow.locker)
#define shadow_lock(_d) \
- do { \
+ do { \
if ( unlikely((_d)->arch.shadow.locker == current->processor) ) \
- { \
+ { \
printk("Error: shadow lock held by %s\n", \
(_d)->arch.shadow.locker_function); \
- BUG(); \
- } \
+ BUG(); \
+ } \
spin_lock(&(_d)->arch.shadow.lock); \
ASSERT((_d)->arch.shadow.locker == -1); \
(_d)->arch.shadow.locker = current->processor; \
(_d)->arch.shadow.locker_function = __func__; \
} while (0)
-#define shadow_unlock(_d) \
- do { \
- ASSERT((_d)->arch.shadow.locker == current->processor); \
- (_d)->arch.shadow.locker = -1; \
- (_d)->arch.shadow.locker_function = "nobody"; \
- spin_unlock(&(_d)->arch.shadow.lock); \
+#define shadow_unlock(_d) \
+ do { \
+ ASSERT((_d)->arch.shadow.locker == current->processor); \
+ (_d)->arch.shadow.locker = -1; \
+ (_d)->arch.shadow.locker_function = "nobody"; \
+ spin_unlock(&(_d)->arch.shadow.lock); \
} while (0)
/*
@@ -161,8 +156,11 @@ extern int shadow_audit_enable;
*/
#define SHOPT_WRITABLE_HEURISTIC 0x01 /* Guess at RW PTEs via linear maps */
#define SHOPT_EARLY_UNSHADOW 0x02 /* Unshadow l1s on fork or exit */
+#define SHOPT_FAST_FAULT_PATH 0x04 /* Fast-path MMIO and not-present */
+#define SHOPT_PREFETCH 0x08 /* Shadow multiple entries per fault */
+#define SHOPT_LINUX_L3_TOPLEVEL 0x10 /* Pin l3es on early 64bit linux */
-#define SHADOW_OPTIMIZATIONS 0x03
+#define SHADOW_OPTIMIZATIONS 0x1f
/* With shadow pagetables, the different kinds of address start
@@ -217,12 +215,6 @@ static inline _type _name##_x(_name##_t n) { return n; }
TYPE_SAFE(unsigned long,mfn)
#define SH_PRI_mfn "05lx"
-static inline int
-valid_mfn(mfn_t m)
-{
- return VALID_MFN(mfn_x(m));
-}
-
static inline mfn_t
pagetable_get_mfn(pagetable_t pt)
{
@@ -245,7 +237,9 @@ shadow_vcpu_mode_translate(struct vcpu *v)
// enabled. (HVM vcpu's with paging disabled are using the p2m table as
// its paging table, so no translation occurs in this case.)
//
- return v->arch.shadow.hvm_paging_enabled;
+ // It is also true for translated PV domains.
+ //
+ return v->arch.shadow.translate_enabled;
}
@@ -257,7 +251,7 @@ struct shadow_paging_mode {
int (*page_fault )(struct vcpu *v, unsigned long va,
struct cpu_user_regs *regs);
int (*invlpg )(struct vcpu *v, unsigned long va);
- unsigned long (*gva_to_gpa )(struct vcpu *v, unsigned long va);
+ paddr_t (*gva_to_gpa )(struct vcpu *v, unsigned long va);
unsigned long (*gva_to_gfn )(struct vcpu *v, unsigned long va);
void (*update_cr3 )(struct vcpu *v);
int (*map_and_validate_gl1e )(struct vcpu *v, mfn_t gmfn,
@@ -287,6 +281,10 @@ struct shadow_paging_mode {
struct x86_emulate_ctxt *ctxt);
mfn_t (*make_monitor_table )(struct vcpu *v);
void (*destroy_monitor_table )(struct vcpu *v, mfn_t mmfn);
+ void * (*guest_map_l1e )(struct vcpu *v, unsigned long va,
+ unsigned long *gl1mfn);
+ void (*guest_get_eff_l1e )(struct vcpu *v, unsigned long va,
+ void *eff_l1e);
#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
int (*guess_wrmap )(struct vcpu *v,
unsigned long vaddr, mfn_t gmfn);
@@ -305,6 +303,9 @@ static inline int shadow_guest_paging_levels(struct vcpu *v)
/**************************************************************************/
/* Entry points into the shadow code */
+/* Enable arbitrary shadow mode. */
+int shadow_enable(struct domain *d, u32 mode);
+
/* Turning on shadow test mode */
int shadow_test_enable(struct domain *d);
@@ -325,19 +326,19 @@ void shadow_final_teardown(struct domain *d);
void sh_do_mark_dirty(struct domain *d, mfn_t gmfn);
static inline void mark_dirty(struct domain *d, unsigned long gmfn)
{
- if ( shadow_mode_log_dirty(d) )
- {
- shadow_lock(d);
- sh_do_mark_dirty(d, _mfn(gmfn));
- shadow_unlock(d);
- }
+ if ( likely(!shadow_mode_log_dirty(d)) )
+ return;
+
+ shadow_lock(d);
+ sh_do_mark_dirty(d, _mfn(gmfn));
+ shadow_unlock(d);
}
/* Internal version, for when the shadow lock is already held */
static inline void sh_mark_dirty(struct domain *d, mfn_t gmfn)
{
ASSERT(shadow_lock_is_acquired(d));
- if ( shadow_mode_log_dirty(d) )
+ if ( unlikely(shadow_mode_log_dirty(d)) )
sh_do_mark_dirty(d, gmfn);
}
@@ -362,11 +363,13 @@ shadow_invlpg(struct vcpu *v, unsigned long va)
return v->arch.shadow.mode->invlpg(v, va);
}
-static inline unsigned long
+static inline paddr_t
shadow_gva_to_gpa(struct vcpu *v, unsigned long va)
/* Called to translate a guest virtual address to what the *guest*
* pagetables would map it to. */
{
+ if ( unlikely(!shadow_vcpu_mode_translate(v)) )
+ return (paddr_t) va;
return v->arch.shadow.mode->gva_to_gpa(v, va);
}
@@ -375,6 +378,8 @@ shadow_gva_to_gfn(struct vcpu *v, unsigned long va)
/* Called to translate a guest virtual address to what the *guest*
* pagetables would map it to. */
{
+ if ( unlikely(!shadow_vcpu_mode_translate(v)) )
+ return va >> PAGE_SHIFT;
return v->arch.shadow.mode->gva_to_gfn(v, va);
}
@@ -399,7 +404,6 @@ shadow_update_cr3(struct vcpu *v)
* for HVM guests, arch.monitor_table and hvm's guest CR3.
*
* Update ref counts to shadow tables appropriately.
- * For PAE, relocate L3 entries, if necessary, into low memory.
*/
static inline void update_cr3(struct vcpu *v)
{
@@ -452,9 +456,73 @@ shadow_destroy_monitor_table(struct vcpu *v, mfn_t mmfn)
v->arch.shadow.mode->destroy_monitor_table(v, mmfn);
}
+static inline void *
+guest_map_l1e(struct vcpu *v, unsigned long addr, unsigned long *gl1mfn)
+{
+ if ( likely(!shadow_mode_translate(v->domain)) )
+ {
+ l2_pgentry_t l2e;
+ ASSERT(!shadow_mode_external(v->domain));
+ /* Find this l1e and its enclosing l1mfn in the linear map */
+ if ( __copy_from_user(&l2e,
+ &__linear_l2_table[l2_linear_offset(addr)],
+ sizeof(l2_pgentry_t)) != 0 )
+ return NULL;
+ /* Check flags that it will be safe to read the l1e */
+ if ( (l2e_get_flags(l2e) & (_PAGE_PRESENT | _PAGE_PSE))
+ != _PAGE_PRESENT )
+ return NULL;
+ *gl1mfn = l2e_get_pfn(l2e);
+ return &__linear_l1_table[l1_linear_offset(addr)];
+ }
+
+ return v->arch.shadow.mode->guest_map_l1e(v, addr, gl1mfn);
+}
+
+static inline void
+guest_unmap_l1e(struct vcpu *v, void *p)
+{
+ if ( unlikely(shadow_mode_translate(v->domain)) )
+ unmap_domain_page(p);
+}
+
+static inline void
+guest_get_eff_l1e(struct vcpu *v, unsigned long addr, void *eff_l1e)
+{
+ if ( likely(!shadow_mode_translate(v->domain)) )
+ {
+ ASSERT(!shadow_mode_external(v->domain));
+ if ( __copy_from_user(eff_l1e,
+ &__linear_l1_table[l1_linear_offset(addr)],
+ sizeof(l1_pgentry_t)) != 0 )
+ *(l1_pgentry_t *)eff_l1e = l1e_empty();
+ return;
+ }
+
+ v->arch.shadow.mode->guest_get_eff_l1e(v, addr, eff_l1e);
+}
+
+static inline void
+guest_get_eff_kern_l1e(struct vcpu *v, unsigned long addr, void *eff_l1e)
+{
+#if defined(__x86_64__)
+ int user_mode = !(v->arch.flags & TF_kernel_mode);
+#define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)
+#else
+#define TOGGLE_MODE() ((void)0)
+#endif
+
+ TOGGLE_MODE();
+ guest_get_eff_l1e(v, addr, eff_l1e);
+ TOGGLE_MODE();
+}
+
+
/* Validate a pagetable change from the guest and update the shadows. */
extern int shadow_validate_guest_entry(struct vcpu *v, mfn_t gmfn,
void *new_guest_entry);
+extern int __shadow_validate_guest_entry(struct vcpu *v, mfn_t gmfn,
+ void *entry, u32 size);
/* Update the shadows in response to a pagetable write from a HVM guest */
extern void shadow_validate_guest_pt_write(struct vcpu *v, mfn_t gmfn,
@@ -478,10 +546,15 @@ shadow_remove_all_shadows_and_parents(struct vcpu *v, mfn_t gmfn);
* Unshadow it, and recursively unshadow pages that reference it. */
/* Remove all shadows of the guest mfn. */
-extern void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int all);
+extern void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all);
static inline void shadow_remove_all_shadows(struct vcpu *v, mfn_t gmfn)
{
- sh_remove_shadows(v, gmfn, 1);
+ int was_locked = shadow_lock_is_acquired(v->domain);
+ if ( !was_locked )
+ shadow_lock(v->domain);
+ sh_remove_shadows(v, gmfn, 0, 1);
+ if ( !was_locked )
+ shadow_unlock(v->domain);
}
/* Add a page to a domain */
@@ -494,33 +567,6 @@ void
shadow_guest_physmap_remove_page(struct domain *d, unsigned long gfn,
unsigned long mfn);
-/*
- * Definitions for the shadow_flags field in page_info.
- * These flags are stored on *guest* pages...
- * Bits 1-13 are encodings for the shadow types.
- */
-#define PGC_SH_type_to_index(_type) ((_type) >> PGC_SH_type_shift)
-#define SHF_page_type_mask \
- (((1u << (PGC_SH_type_to_index(PGC_SH_max_shadow) + 1u)) - 1u) - \
- ((1u << PGC_SH_type_to_index(PGC_SH_min_shadow)) - 1u))
-
-#define SHF_L1_32 (1u << PGC_SH_type_to_index(PGC_SH_l1_32_shadow))
-#define SHF_FL1_32 (1u << PGC_SH_type_to_index(PGC_SH_fl1_32_shadow))
-#define SHF_L2_32 (1u << PGC_SH_type_to_index(PGC_SH_l2_32_shadow))
-#define SHF_L1_PAE (1u << PGC_SH_type_to_index(PGC_SH_l1_pae_shadow))
-#define SHF_FL1_PAE (1u << PGC_SH_type_to_index(PGC_SH_fl1_pae_shadow))
-#define SHF_L2_PAE (1u << PGC_SH_type_to_index(PGC_SH_l2_pae_shadow))
-#define SHF_L2H_PAE (1u << PGC_SH_type_to_index(PGC_SH_l2h_pae_shadow))
-#define SHF_L3_PAE (1u << PGC_SH_type_to_index(PGC_SH_l3_pae_shadow))
-#define SHF_L1_64 (1u << PGC_SH_type_to_index(PGC_SH_l1_64_shadow))
-#define SHF_FL1_64 (1u << PGC_SH_type_to_index(PGC_SH_fl1_64_shadow))
-#define SHF_L2_64 (1u << PGC_SH_type_to_index(PGC_SH_l2_64_shadow))
-#define SHF_L3_64 (1u << PGC_SH_type_to_index(PGC_SH_l3_64_shadow))
-#define SHF_L4_64 (1u << PGC_SH_type_to_index(PGC_SH_l4_64_shadow))
-
-/* Used for hysteresis when automatically unhooking mappings on fork/exit */
-#define SHF_unhooked_mappings (1u<<31)
-
/*
* Allocation of shadow pages
*/
@@ -543,50 +589,42 @@ static inline unsigned int shadow_get_allocation(struct domain *d)
+ ((pg & ((1 << (20 - PAGE_SHIFT)) - 1)) ? 1 : 0));
}
-/*
- * Linked list for chaining entries in the shadow hash table.
+
+/**************************************************************************/
+/* Guest physmap (p2m) support
+ *
+ * The phys_to_machine_mapping is the reversed mapping of MPT for full
+ * virtualization. It is only used by shadow_mode_translate()==true
+ * guests, so we steal the address space that would have normally
+ * been used by the read-only MPT map.
*/
-struct shadow_hash_entry {
- struct shadow_hash_entry *next;
- mfn_t smfn; /* MFN of the shadow */
-#ifdef _x86_64_ /* Shorten 'n' so we don't waste a whole word on storing 't' */
- unsigned long n:56; /* MFN of guest PT or GFN of guest superpage */
-#else
- unsigned long n; /* MFN of guest PT or GFN of guest superpage */
-#endif
- unsigned char t; /* shadow type bits, or 0 for empty */
-};
-#define SHADOW_HASH_BUCKETS 251
-/* Other possibly useful primes are 509, 1021, 2039, 4093, 8191, 16381 */
+#define phys_to_machine_mapping ((l1_pgentry_t *)RO_MPT_VIRT_START)
+/* Read the current domain's P2M table. */
+static inline mfn_t sh_gfn_to_mfn_current(unsigned long gfn)
+{
+ l1_pgentry_t l1e = l1e_empty();
+ int ret;
-#if SHADOW_OPTIMIZATIONS & SHOPT_CACHE_WALKS
-/* Optimization: cache the results of guest walks. This helps with MMIO
- * and emulated writes, which tend to issue very similar walk requests
- * repeatedly. We keep the results of the last few walks, and blow
- * away the cache on guest cr3 write, mode change, or page fault. */
+ if ( gfn > current->domain->arch.max_mapped_pfn )
+ return _mfn(INVALID_MFN);
-#define SH_WALK_CACHE_ENTRIES 4
+ /* Don't read off the end of the p2m table */
+ ASSERT(gfn < (RO_MPT_VIRT_END - RO_MPT_VIRT_START) / sizeof(l1_pgentry_t));
-/* Rather than cache a guest walk, which would include mapped pointers
- * to pages, we cache what a TLB would remember about the walk: the
- * permissions and the l1 gfn */
-struct shadow_walk_cache {
- unsigned long va; /* The virtual address (or 0 == unused) */
- unsigned long gfn; /* The gfn from the effective l1e */
- u32 permissions; /* The aggregated permission bits */
-};
-#endif
+ ret = __copy_from_user(&l1e,
+ &phys_to_machine_mapping[gfn],
+ sizeof(l1e));
+ if ( (ret == 0) && (l1e_get_flags(l1e) & _PAGE_PRESENT) )
+ return _mfn(l1e_get_pfn(l1e));
-/**************************************************************************/
-/* Guest physmap (p2m) support */
+ return _mfn(INVALID_MFN);
+}
/* Walk another domain's P2M table, mapping pages as we go */
-extern mfn_t
-sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
-
+extern mfn_t sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
/* General conversion function from gfn to mfn */
static inline mfn_t
@@ -594,27 +632,19 @@ sh_gfn_to_mfn(struct domain *d, unsigned long gfn)
{
if ( !shadow_mode_translate(d) )
return _mfn(gfn);
- else if ( likely(current->domain == d) )
- return _mfn(get_mfn_from_gpfn(gfn));
- else
+ if ( likely(current->domain == d) )
+ return sh_gfn_to_mfn_current(gfn);
+ else
return sh_gfn_to_mfn_foreign(d, gfn);
}
-// vcpu-specific version of gfn_to_mfn(). This is where we hide the dirty
-// little secret that, for hvm guests with paging disabled, nearly all of the
-// shadow code actually think that the guest is running on *untranslated* page
-// tables (which is actually domain->phys_table).
-//
-static inline mfn_t
-sh_vcpu_gfn_to_mfn(struct vcpu *v, unsigned long gfn)
-{
- if ( !shadow_vcpu_mode_translate(v) )
- return _mfn(gfn);
- if ( likely(current->domain == v->domain) )
- return _mfn(get_mfn_from_gpfn(gfn));
- return sh_gfn_to_mfn_foreign(v->domain, gfn);
+/* Compatibility function for HVM code */
+static inline unsigned long get_mfn_from_gpfn(unsigned long pfn)
+{
+ return mfn_x(sh_gfn_to_mfn_current(pfn));
}
+/* General conversion function from mfn to gfn */
static inline unsigned long
sh_mfn_to_gfn(struct domain *d, mfn_t mfn)
{
@@ -624,7 +654,22 @@ sh_mfn_to_gfn(struct domain *d, mfn_t mfn)
return mfn_x(mfn);
}
+/* Is this guest address an mmio one? (i.e. not defined in p2m map) */
+static inline int
+mmio_space(paddr_t gpa)
+{
+ unsigned long gfn = gpa >> PAGE_SHIFT;
+ return !mfn_valid(mfn_x(sh_gfn_to_mfn_current(gfn)));
+}
+static inline l1_pgentry_t
+gl1e_to_ml1e(struct domain *d, l1_pgentry_t l1e)
+{
+ if ( unlikely(shadow_mode_translate(d)) )
+ l1e = l1e_from_pfn(gmfn_to_mfn(d, l1e_get_pfn(l1e)),
+ l1e_get_flags(l1e));
+ return l1e;
+}
#endif /* _XEN_SHADOW_H */
diff --git a/xen/include/asm-x86/spinlock.h b/xen/include/asm-x86/spinlock.h
index 1d864188da..8c148e0240 100644
--- a/xen/include/asm-x86/spinlock.h
+++ b/xen/include/asm-x86/spinlock.h
@@ -12,9 +12,9 @@ typedef struct {
u8 recurse_cnt;
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1, -1, 0 }
+#define SPIN_LOCK_UNLOCKED /*(spinlock_t)*/ { 1, -1, 0 }
-#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_lock_init(x) do { *(x) = (spinlock_t) SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0)
static inline void _raw_spin_lock(spinlock_t *lock)
@@ -89,9 +89,9 @@ typedef struct {
volatile unsigned int lock;
} rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS }
+#define RW_LOCK_UNLOCKED /*(rwlock_t)*/ { RW_LOCK_BIAS }
-#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_init(x) do { *(x) = (rwlock_t) RW_LOCK_UNLOCKED; } while(0)
/*
* On x86, we implement read-write locks as a 32-bit counter
diff --git a/xen/include/asm-x86/x86_32/page-2level.h b/xen/include/asm-x86/x86_32/page-2level.h
index e7b74dd18d..a022b12087 100644
--- a/xen/include/asm-x86/x86_32/page-2level.h
+++ b/xen/include/asm-x86/x86_32/page-2level.h
@@ -28,6 +28,9 @@ typedef l2_pgentry_t root_pgentry_t;
#endif /* !__ASSEMBLY__ */
+#define pte_read_atomic(ptep) (*(intpte_t *)(ptep))
+#define pte_write_atomic(ptep, pte) (*(intpte_t *)(ptep)) = (pte))
+
/* root table */
#define root_get_pfn l2e_get_pfn
#define root_get_flags l2e_get_flags
diff --git a/xen/include/asm-x86/x86_32/page-3level.h b/xen/include/asm-x86/x86_32/page-3level.h
index d7d2d19f3f..08864255ad 100644
--- a/xen/include/asm-x86/x86_32/page-3level.h
+++ b/xen/include/asm-x86/x86_32/page-3level.h
@@ -38,6 +38,17 @@ typedef l3_pgentry_t root_pgentry_t;
#endif /* !__ASSEMBLY__ */
+#define pte_read_atomic(ptep) ({ \
+ intpte_t __pte = *(intpte_t *)(ptep), __npte; \
+ while ( (__npte = cmpxchg((intpte_t *)(ptep), __pte, __pte)) != __pte ) \
+ __pte = __npte; \
+ __pte; })
+#define pte_write_atomic(ptep, pte) do { \
+ intpte_t __pte = *(intpte_t *)(ptep), __npte; \
+ while ( (__npte = cmpxchg((intpte_t *)(ptep), __pte, (pte))) != __pte ) \
+ __pte = __npte; \
+} while ( 0 )
+
/* root table */
#define root_get_pfn l3e_get_pfn
#define root_get_flags l3e_get_flags
@@ -49,7 +60,7 @@ typedef l3_pgentry_t root_pgentry_t;
/* misc */
#define is_guest_l1_slot(s) (1)
#define is_guest_l2_slot(t,s) \
- ( ((((t) & PGT_va_mask) >> PGT_va_shift) != 3) || \
+ ( !((t) & PGT_pae_xen_l2) || \
((s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES - 1))) )
#define is_guest_l3_slot(s) (1)
diff --git a/xen/include/asm-x86/x86_32/regs.h b/xen/include/asm-x86/x86_32/regs.h
index 5124bce79b..7306b65af5 100644
--- a/xen/include/asm-x86/x86_32/regs.h
+++ b/xen/include/asm-x86/x86_32/regs.h
@@ -16,6 +16,9 @@
#define permit_softint(dpl, v, r) \
((dpl) >= (vm86_mode(r) ? 3 : ((r)->cs & 3)))
+/* Check for null trap callback handler: Is the selector null (0-3)? */
+#define null_trap_bounce(tb) (((tb)->cs & ~3) == 0)
+
/* Number of bytes of on-stack execution state to be context-switched. */
#define CTXT_SWITCH_STACK_BYTES (sizeof(struct cpu_user_regs))
diff --git a/xen/include/asm-x86/x86_64/asm_defns.h b/xen/include/asm-x86/x86_64/asm_defns.h
index 699e81b4f0..05f708adaf 100644
--- a/xen/include/asm-x86/x86_64/asm_defns.h
+++ b/xen/include/asm-x86/x86_64/asm_defns.h
@@ -60,6 +60,12 @@
#define safe_swapgs \
"mfence; swapgs;"
+#ifdef __sun__
+#define REX64_PREFIX "rex64\\"
+#else
+#define REX64_PREFIX "rex64/"
+#endif
+
#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
#define XBUILD_SMP_INTERRUPT(x,v) \
asmlinkage void x(void); \
diff --git a/xen/include/asm-x86/x86_64/page.h b/xen/include/asm-x86/x86_64/page.h
index d323362be9..4e0f3675ce 100644
--- a/xen/include/asm-x86/x86_64/page.h
+++ b/xen/include/asm-x86/x86_64/page.h
@@ -41,6 +41,9 @@ typedef l4_pgentry_t root_pgentry_t;
#endif /* !__ASSEMBLY__ */
+#define pte_read_atomic(ptep) (*(intpte_t *)(ptep))
+#define pte_write_atomic(ptep, pte) (*(intpte_t *)(ptep)) = (pte))
+
/* Given a virtual address, get an entry offset into a linear page table. */
#define l1_linear_offset(_a) (((_a) & VADDR_MASK) >> L1_PAGETABLE_SHIFT)
#define l2_linear_offset(_a) (((_a) & VADDR_MASK) >> L2_PAGETABLE_SHIFT)
@@ -93,6 +96,21 @@ typedef l4_pgentry_t root_pgentry_t;
#define GRANT_PTE_FLAGS \
(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_GNTTAB|_PAGE_USER)
+#define USER_MAPPINGS_ARE_GLOBAL
+#ifdef USER_MAPPINGS_ARE_GLOBAL
+/*
+ * Bit 12 of a 24-bit flag mask. This corresponds to bit 52 of a pte.
+ * This is needed to distinguish between user and kernel PTEs since _PAGE_USER
+ * is asserted for both.
+ */
+#define _PAGE_GUEST_KERNEL (1U<<12)
+/* Global bit is allowed to be set on L1 PTEs. Intended for user mappings. */
+#undef L1_DISALLOW_MASK
+#define L1_DISALLOW_MASK ((BASE_DISALLOW_MASK | _PAGE_GNTTAB) & ~_PAGE_GLOBAL)
+#else
+#define _PAGE_GUEST_KERNEL 0
+#endif
+
#endif /* __X86_64_PAGE_H__ */
/*
diff --git a/xen/include/asm-x86/x86_64/regs.h b/xen/include/asm-x86/x86_64/regs.h
index 191f467343..5dadccdab1 100644
--- a/xen/include/asm-x86/x86_64/regs.h
+++ b/xen/include/asm-x86/x86_64/regs.h
@@ -16,6 +16,9 @@
#define permit_softint(dpl, v, r) \
((dpl) >= (guest_kernel_mode(v, r) ? 1 : 3))
+/* Check for null trap callback handler: Is the EIP null? */
+#define null_trap_bounce(tb) ((tb)->eip == 0)
+
/* Number of bytes of on-stack execution state to be context-switched. */
/* NB. Segment registers and bases are not saved/restored on x86/64 stack. */
#define CTXT_SWITCH_STACK_BYTES (offsetof(struct cpu_user_regs, es))
diff --git a/xen/include/asm-x86/xenoprof.h b/xen/include/asm-x86/xenoprof.h
new file mode 100644
index 0000000000..8554f7c383
--- /dev/null
+++ b/xen/include/asm-x86/xenoprof.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ * asm-x86/xenoprof.h
+ * xenoprof x86 arch specific header file
+ *
+ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_X86_XENOPROF_H__
+#define __ASM_X86_XENOPROF_H__
+
+int nmi_init(int *num_events, int *is_primary, char *cpu_type);
+int nmi_reserve_counters(void);
+int nmi_setup_events(void);
+int nmi_enable_virq(void);
+int nmi_start(void);
+void nmi_stop(void);
+void nmi_disable_virq(void);
+void nmi_release_counters(void);
+
+#define xenoprof_arch_init(num_events, is_primary, cpu_type) \
+ nmi_init(num_events, is_primary, cpu_type)
+#define xenoprof_arch_reserve_counters() nmi_reserve_counters()
+#define xenoprof_arch_setup_events() nmi_setup_events()
+#define xenoprof_arch_enable_virq() nmi_enable_virq()
+#define xenoprof_arch_start() nmi_start()
+#define xenoprof_arch_stop() nmi_stop()
+#define xenoprof_arch_disable_virq() nmi_disable_virq()
+#define xenoprof_arch_release_counters() nmi_release_counters()
+
+int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
+
+struct vcpu;
+struct cpu_user_regs;
+int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
+#define xenoprof_shared_gmfn(d, gmaddr, maddr) \
+ do { \
+ (void)(maddr); \
+ gdprintk(XENLOG_WARNING, \
+ "xenoprof/x86 with autotranslated mode enabled" \
+ "isn't supported yet\n"); \
+ } while (0)
+
+#endif /* __ASM_X86_XENOPROF_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/COPYING b/xen/include/public/COPYING
index 3377710a5c..ffc6d6166f 100644
--- a/xen/include/public/COPYING
+++ b/xen/include/public/COPYING
@@ -1,9 +1,19 @@
XEN NOTICE
==========
-This copyright applies to all files within this subdirectory. All
-other files in the Xen source distribution are covered by version 2 of
-the GNU General Public License.
+This copyright applies to all files within this subdirectory and its
+subdirectories:
+ include/public/*.h
+ include/public/hvm/*.h
+ include/public/io/*.h
+
+The intention is that these files can be freely copied into the source
+tree of an operating system when porting that OS to run on Xen. Doing
+so does *not* cause the OS to become subject to the terms of the GPL.
+
+All other files in the Xen source distribution are covered by version
+2 of the GNU General Public License except where explicitly stated
+otherwise within individual source files.
-- Keir Fraser (on behalf of the Xen team)
diff --git a/xen/include/public/acm.h b/xen/include/public/acm.h
index d53bc6bbd5..23078837fb 100644
--- a/xen/include/public/acm.h
+++ b/xen/include/public/acm.h
@@ -1,6 +1,24 @@
/*
* acm.h: Xen access control module interface defintions
*
+ * 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.
+ *
* Reiner Sailer <sailer@watson.ibm.com>
* Copyright (c) 2005, International Business Machines Corporation.
*/
diff --git a/xen/include/public/acm_ops.h b/xen/include/public/acm_ops.h
index 4a1c3b4d35..5e103dca7b 100644
--- a/xen/include/public/acm_ops.h
+++ b/xen/include/public/acm_ops.h
@@ -1,6 +1,24 @@
/*
* acm_ops.h: Xen access control module hypervisor commands
*
+ * 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.
+ *
* Reiner Sailer <sailer@watson.ibm.com>
* Copyright (c) 2005,2006 International Business Machines Corporation.
*/
diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h
index 98bda1d241..01f6362d82 100644
--- a/xen/include/public/arch-ia64.h
+++ b/xen/include/public/arch-ia64.h
@@ -2,6 +2,25 @@
* arch-ia64/hypervisor-if.h
*
* Guest OS interface to IA64 Xen.
+ *
+ * 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 __HYPERVISOR_IF_IA64_H__
@@ -28,6 +47,7 @@
__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int);
__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
+__DEFINE_XEN_GUEST_HANDLE(u64, unsigned long);
DEFINE_XEN_GUEST_HANDLE(char);
DEFINE_XEN_GUEST_HANDLE(int);
DEFINE_XEN_GUEST_HANDLE(long);
@@ -48,18 +68,6 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
typedef unsigned long xen_ulong_t;
-#define GPFN_MEM (0UL << 56) /* Guest pfn is normal mem */
-#define GPFN_FRAME_BUFFER (1UL << 56) /* VGA framebuffer */
-#define GPFN_LOW_MMIO (2UL << 56) /* Low MMIO range */
-#define GPFN_PIB (3UL << 56) /* PIB base */
-#define GPFN_IOSAPIC (4UL << 56) /* IOSAPIC base */
-#define GPFN_LEGACY_IO (5UL << 56) /* Legacy I/O base */
-#define GPFN_GFW (6UL << 56) /* Guest Firmware */
-#define GPFN_HIGH_MMIO (7UL << 56) /* High MMIO range */
-
-#define GPFN_IO_MASK (7UL << 56) /* Guest pfn is I/O type */
-#define GPFN_INV_MASK (31UL << 59) /* Guest pfn is invalid */
-
#define INVALID_MFN (~0UL)
#define MEM_G (1UL << 30)
@@ -80,6 +88,9 @@ typedef unsigned long xen_ulong_t;
#define STORE_PAGE_START (IO_PAGE_START + IO_PAGE_SIZE)
#define STORE_PAGE_SIZE PAGE_SIZE
+#define BUFFER_IO_PAGE_START (STORE_PAGE_START+PAGE_SIZE)
+#define BUFFER_IO_PAGE_SIZE PAGE_SIZE
+
#define IO_SAPIC_START 0xfec00000UL
#define IO_SAPIC_SIZE 0x100000
@@ -336,33 +347,33 @@ struct vcpu_guest_context {
typedef struct vcpu_guest_context vcpu_guest_context_t;
DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
-// dom0 vp op
+/* dom0 vp op */
#define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0
-#define IA64_DOM0VP_ioremap 0 // map io space in machine
- // address to dom0 physical
- // address space.
- // currently physical
- // assignedg address equals to
- // machine address
-#define IA64_DOM0VP_phystomach 1 // convert a pseudo physical
- // page frame number
- // to the corresponding
- // machine page frame number.
- // if no page is assigned,
- // INVALID_MFN or GPFN_INV_MASK
- // is returned depending on
- // domain's non-vti/vti mode.
-#define IA64_DOM0VP_machtophys 3 // convert a machine page
- // frame number
- // to the corresponding
- // pseudo physical page frame
- // number of the caller domain
-#define IA64_DOM0VP_zap_physmap 17 // unmap and free pages
- // contained in the specified
- // pseudo physical region
-#define IA64_DOM0VP_add_physmap 18 // assigne machine page frane
- // to dom0's pseudo physical
- // address space.
+/* Map io space in machine address to dom0 physical address space.
+ Currently physical assigned address equals to machine address. */
+#define IA64_DOM0VP_ioremap 0
+
+/* Convert a pseudo physical page frame number to the corresponding
+ machine page frame number. If no page is assigned, INVALID_MFN or
+ GPFN_INV_MASK is returned depending on domain's non-vti/vti mode. */
+#define IA64_DOM0VP_phystomach 1
+
+/* Convert a machine page frame number to the corresponding pseudo physical
+ page frame number of the caller domain. */
+#define IA64_DOM0VP_machtophys 3
+
+/* Reserved for future use. */
+#define IA64_DOM0VP_iounmap 4
+
+/* Unmap and free pages contained in the specified pseudo physical region. */
+#define IA64_DOM0VP_zap_physmap 5
+
+/* Assign machine page frame to dom0's pseudo physical address space. */
+#define IA64_DOM0VP_add_physmap 6
+
+/* expose the p2m table into domain */
+#define IA64_DOM0VP_expose_p2m 7
+
// flags for page assignement to pseudo physical address space
#define _ASSIGN_readonly 0
#define ASSIGN_readonly (1UL << _ASSIGN_readonly)
@@ -370,6 +381,12 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
/* Internal only: memory attribute must be WC/UC/UCE. */
#define _ASSIGN_nocache 1
#define ASSIGN_nocache (1UL << _ASSIGN_nocache)
+// tlb tracking
+#define _ASSIGN_tlb_track 2
+#define ASSIGN_tlb_track (1UL << _ASSIGN_tlb_track)
+/* Internal only: associated with PGC_allocated bit */
+#define _ASSIGN_pgc_allocated 3
+#define ASSIGN_pgc_allocated (1UL << _ASSIGN_pgc_allocated)
/* This structure has the same layout of struct ia64_boot_param, defined in
<asm/system.h>. It is redefined here to ease use. */
@@ -395,15 +412,12 @@ struct xen_ia64_boot_param {
#endif /* !__ASSEMBLY__ */
-/* Address of shared_info in domain virtual space.
- This is the default address, for compatibility only. */
-#define XSI_BASE 0xf100000000000000
-
/* Size of the shared_info area (this is not related to page size). */
#define XSI_SHIFT 14
#define XSI_SIZE (1 << XSI_SHIFT)
/* Log size of mapped_regs area (64 KB - only 4KB is used). */
#define XMAPPEDREGS_SHIFT 12
+#define XMAPPEDREGS_SIZE (1 << XMAPPEDREGS_SHIFT)
/* Offset of XASI (Xen arch shared info) wrt XSI_BASE. */
#define XMAPPEDREGS_OFS XSI_SIZE
@@ -435,6 +449,17 @@ struct xen_ia64_boot_param {
#define HYPERPRIVOP_GET_PSR 0x19
#define HYPERPRIVOP_MAX 0x19
+/* Fast and light hypercalls. */
+#define __HYPERVISOR_ia64_fast_eoi 0x0200
+
+/* Xencomm macros. */
+#define XENCOMM_INLINE_MASK 0xf800000000000000UL
+#define XENCOMM_INLINE_FLAG 0x8000000000000000UL
+
+#define XENCOMM_IS_INLINE(addr) \
+ (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG)
+#define XENCOMM_INLINE_ADDR(addr) \
+ ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK)
#endif /* __HYPERVISOR_IF_IA64_H__ */
/*
diff --git a/xen/include/public/arch-powerpc.h b/xen/include/public/arch-powerpc.h
index 5172563821..c7738c1c86 100644
--- a/xen/include/public/arch-powerpc.h
+++ b/xen/include/public/arch-powerpc.h
@@ -1,17 +1,21 @@
/*
- * 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.
+ * 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:
*
- * 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.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * 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.
+ * 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.
*
* Copyright (C) IBM Corp. 2005, 2006
*
diff --git a/xen/include/public/arch-x86_32.h b/xen/include/public/arch-x86_32.h
index 90bc4605bf..42651c20b6 100644
--- a/xen/include/public/arch-x86_32.h
+++ b/xen/include/public/arch-x86_32.h
@@ -3,6 +3,24 @@
*
* Guest OS interface to x86 32-bit Xen.
*
+ * 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.
+ *
* Copyright (c) 2004, K A Fraser
*/
@@ -172,12 +190,9 @@ struct vcpu_guest_context {
/* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
#define VGCF_I387_VALID (1<<0)
-#define VGCF_HVM_GUEST (1<<1)
#define VGCF_IN_KERNEL (1<<2)
#define _VGCF_i387_valid 0
#define VGCF_i387_valid (1<<_VGCF_i387_valid)
-#define _VGCF_hvm_guest 1
-#define VGCF_hvm_guest (1<<_VGCF_hvm_guest)
#define _VGCF_in_kernel 2
#define VGCF_in_kernel (1<<_VGCF_in_kernel)
#define _VGCF_failsafe_disables_events 3
diff --git a/xen/include/public/arch-x86_64.h b/xen/include/public/arch-x86_64.h
index 2891cfa29e..a60bc204ef 100644
--- a/xen/include/public/arch-x86_64.h
+++ b/xen/include/public/arch-x86_64.h
@@ -3,6 +3,24 @@
*
* Guest OS interface to x86 64-bit Xen.
*
+ * 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.
+ *
* Copyright (c) 2004, K A Fraser
*/
@@ -152,7 +170,7 @@ typedef unsigned long xen_ulong_t;
* directly with
* orb $3,1*8(%rsp)
* iretq
- * If flags contains VGCF_IN_SYSCALL:
+ * If flags contains VGCF_in_syscall:
* Restore RAX, RIP, RFLAGS, RSP.
* Discard R11, RCX, CS, SS.
* Otherwise:
@@ -160,7 +178,9 @@ typedef unsigned long xen_ulong_t;
* All other registers are saved on hypercall entry and restored to user.
*/
/* Guest exited in SYSCALL context? Return to guest with SYSRET? */
-#define VGCF_IN_SYSCALL (1<<8)
+#define _VGCF_in_syscall 8
+#define VGCF_in_syscall (1<<_VGCF_in_syscall)
+#define VGCF_IN_SYSCALL VGCF_in_syscall
struct iret_context {
/* Top of stack (%rsp at point of hypercall). */
uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
@@ -243,12 +263,9 @@ struct vcpu_guest_context {
/* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
#define VGCF_I387_VALID (1<<0)
-#define VGCF_HVM_GUEST (1<<1)
#define VGCF_IN_KERNEL (1<<2)
#define _VGCF_i387_valid 0
#define VGCF_i387_valid (1<<_VGCF_i387_valid)
-#define _VGCF_hvm_guest 1
-#define VGCF_hvm_guest (1<<_VGCF_hvm_guest)
#define _VGCF_in_kernel 2
#define VGCF_in_kernel (1<<_VGCF_in_kernel)
#define _VGCF_failsafe_disables_events 3
diff --git a/xen/include/public/callback.h b/xen/include/public/callback.h
index b497d99317..cac5389925 100644
--- a/xen/include/public/callback.h
+++ b/xen/include/public/callback.h
@@ -3,6 +3,24 @@
*
* Register guest OS callbacks with Xen.
*
+ * 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.
+ *
* Copyright (c) 2006, Ian Campbell
*/
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index b03a7ce2ee..5d2b3245c0 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -3,6 +3,24 @@
*
* Process command requests from domain-0 guest OS.
*
+ * 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.
+ *
* Copyright (c) 2002-2003, B Dragovic
* Copyright (c) 2002-2006, K Fraser
*/
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 6ad8918757..37618ad827 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -3,6 +3,24 @@
*
* Domain management operations. For use by node control stack.
*
+ * 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.
+ *
* Copyright (c) 2002-2003, B Dragovic
* Copyright (c) 2002-2006, K Fraser
*/
@@ -16,7 +34,7 @@
#include "xen.h"
-#define XEN_DOMCTL_INTERFACE_VERSION 0x00000003
+#define XEN_DOMCTL_INTERFACE_VERSION 0x00000004
struct xenctl_cpumap {
XEN_GUEST_HANDLE(uint8_t) bitmap;
@@ -32,6 +50,10 @@ struct xen_domctl_createdomain {
/* IN parameters */
uint32_t ssidref;
xen_domain_handle_t handle;
+ /* Is this an HVM guest (as opposed to a PV guest)? */
+#define _XEN_DOMCTL_CDF_hvm_guest 0
+#define XEN_DOMCTL_CDF_hvm_guest (1U<<_XEN_DOMCTL_CDF_hvm_guest)
+ uint32_t flags;
};
typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
@@ -44,22 +66,37 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
struct xen_domctl_getdomaininfo {
/* OUT variables. */
domid_t domain; /* Also echoed in domctl.domain */
-#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
-#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
-#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
-#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
-#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
-#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
-#define DOMFLAGS_CPUSHIFT 8
-#define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code. */
-#define DOMFLAGS_SHUTDOWNSHIFT 16
- uint32_t flags;
+ /* Domain is scheduled to die. */
+#define _XEN_DOMINF_dying 0
+#define XEN_DOMINF_dying (1U<<_XEN_DOMINF_dying)
+ /* Domain is an HVM guest (as opposed to a PV guest). */
+#define _XEN_DOMINF_hvm_guest 1
+#define XEN_DOMINF_hvm_guest (1U<<_XEN_DOMINF_hvm_guest)
+ /* The guest OS has shut down. */
+#define _XEN_DOMINF_shutdown 2
+#define XEN_DOMINF_shutdown (1U<<_XEN_DOMINF_shutdown)
+ /* Currently paused by control software. */
+#define _XEN_DOMINF_paused 3
+#define XEN_DOMINF_paused (1U<<_XEN_DOMINF_paused)
+ /* Currently blocked pending an event. */
+#define _XEN_DOMINF_blocked 4
+#define XEN_DOMINF_blocked (1U<<_XEN_DOMINF_blocked)
+ /* Domain is currently running. */
+#define _XEN_DOMINF_running 5
+#define XEN_DOMINF_running (1U<<_XEN_DOMINF_running)
+ /* CPU to which this domain is bound. */
+#define XEN_DOMINF_cpumask 255
+#define XEN_DOMINF_cpushift 8
+ /* XEN_DOMINF_shutdown guest-supplied code. */
+#define XEN_DOMINF_shutdownmask 255
+#define XEN_DOMINF_shutdownshift 16
+ uint32_t flags; /* XEN_DOMINF_* */
uint64_t tot_pages;
uint64_t max_pages;
uint64_t shared_info_frame; /* MFN of shared_info struct */
uint64_t cpu_time;
- uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
- uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
+ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
+ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
uint32_t ssidref;
xen_domain_handle_t handle;
};
diff --git a/xen/include/public/elfnote.h b/xen/include/public/elfnote.h
index a64d3df5bd..ccf959d6e1 100644
--- a/xen/include/public/elfnote.h
+++ b/xen/include/public/elfnote.h
@@ -3,6 +3,24 @@
*
* Definitions used for the Xen ELF notes.
*
+ * 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.
+ *
* Copyright (c) 2006, Ian Campbell, XenSource Ltd.
*/
@@ -120,6 +138,15 @@
*/
#define XEN_ELFNOTE_BSD_SYMTAB 11
+/*
+ * The lowest address the hypervisor hole can begin at (numeric).
+ *
+ * This must not be set higher than HYPERVISOR_VIRT_START. Its presence
+ * also indicates to the hypervisor that the kernel can deal with the
+ * hole starting at a higher address.
+ */
+#define XEN_ELFNOTE_HV_START_LOW 12
+
#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
/*
diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h
index 96c98fd6f8..62cf764040 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -3,6 +3,24 @@
*
* Event channels between domains.
*
+ * 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.
+ *
* Copyright (c) 2003-2004, K A Fraser.
*/
diff --git a/xen/include/public/features.h b/xen/include/public/features.h
index c46e3becfe..d4b373ff17 100644
--- a/xen/include/public/features.h
+++ b/xen/include/public/features.h
@@ -3,6 +3,24 @@
*
* Feature flags, reported by XENVER_get_features.
*
+ * 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.
+ *
* Copyright (c) 2006, Keir Fraser <keir@xensource.com>
*/
diff --git a/xen/include/public/grant_table.h b/xen/include/public/grant_table.h
index b7b8b6d3e4..9622b56d02 100644
--- a/xen/include/public/grant_table.h
+++ b/xen/include/public/grant_table.h
@@ -4,6 +4,24 @@
* Interface for granting foreign access to page frames, and receiving
* page-ownership transfers.
*
+ * 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.
+ *
* Copyright (c) 2004, K A Fraser
*/
diff --git a/xen/include/public/hvm/e820.h b/xen/include/public/hvm/e820.h
index 8190c767df..dc683720bc 100644
--- a/xen/include/public/hvm/e820.h
+++ b/xen/include/public/hvm/e820.h
@@ -1,3 +1,24 @@
+
+/*
+ * 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 __XEN_PUBLIC_HVM_E820_H__
#define __XEN_PUBLIC_HVM_E820_H__
@@ -7,12 +28,6 @@
#define E820_ACPI 3
#define E820_NVS 4
-/* Xen HVM extended E820 types. */
-#define E820_IO 16
-#define E820_SHARED_PAGE 17
-#define E820_XENSTORE 18
-#define E820_BUFFERED_IO 19
-
/* E820 location in HVM virtual address space. */
#define E820_MAP_PAGE 0x00090000
#define E820_MAP_NR_OFFSET 0x000001E8
diff --git a/xen/include/public/hvm/hvm_info_table.h b/xen/include/public/hvm/hvm_info_table.h
index 3b705eeedf..dfe34db1e5 100644
--- a/xen/include/public/hvm/hvm_info_table.h
+++ b/xen/include/public/hvm/hvm_info_table.h
@@ -2,6 +2,24 @@
* hvm/hvm_info_table.h
*
* HVM parameter and information table, written into guest memory map.
+ *
+ * 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 __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__
@@ -16,6 +34,7 @@ struct hvm_info_table {
uint32_t length;
uint8_t checksum;
uint8_t acpi_enabled;
+ uint8_t apic_mode;
uint32_t nr_vcpus;
};
diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h
new file mode 100644
index 0000000000..8322f32ee2
--- /dev/null
+++ b/xen/include/public/hvm/hvm_op.h
@@ -0,0 +1,53 @@
+#ifndef __XEN_PUBLIC_HVM_HVM_OP_H__
+#define __XEN_PUBLIC_HVM_HVM_OP_H__
+
+/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */
+#define HVMOP_set_param 0
+#define HVMOP_get_param 1
+struct xen_hvm_param {
+ domid_t domid; /* IN */
+ uint32_t index; /* IN */
+ uint64_t value; /* IN/OUT */
+};
+typedef struct xen_hvm_param xen_hvm_param_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t);
+
+/* Set the logical level of one of a domain's PCI INTx wires. */
+#define HVMOP_set_pci_intx_level 2
+struct xen_hvm_set_pci_intx_level {
+ /* Domain to be updated. */
+ domid_t domid;
+ /* PCI INTx identification in PCI topology (domain:bus:device:intx). */
+ uint8_t domain, bus, device, intx;
+ /* Assertion level (0 = unasserted, 1 = asserted). */
+ uint8_t level;
+};
+typedef struct xen_hvm_set_pci_intx_level xen_hvm_set_pci_intx_level_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t);
+
+/* Set the logical level of one of a domain's ISA IRQ wires. */
+#define HVMOP_set_isa_irq_level 3
+struct xen_hvm_set_isa_irq_level {
+ /* Domain to be updated. */
+ domid_t domid;
+ /* ISA device identification, by ISA IRQ (0-15). */
+ uint8_t isa_irq;
+ /* Assertion level (0 = unasserted, 1 = asserted). */
+ uint8_t level;
+};
+typedef struct xen_hvm_set_isa_irq_level xen_hvm_set_isa_irq_level_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_isa_irq_level_t);
+
+#define HVMOP_set_pci_link_route 4
+struct xen_hvm_set_pci_link_route {
+ /* Domain to be updated. */
+ domid_t domid;
+ /* PCI link identifier (0-3). */
+ uint8_t link;
+ /* ISA IRQ (1-15), or 0 (disable link). */
+ uint8_t isa_irq;
+};
+typedef struct xen_hvm_set_pci_link_route xen_hvm_set_pci_link_route_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t);
+
+#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h
index 8e92b004b1..0d3dc3277a 100644
--- a/xen/include/public/hvm/ioreq.h
+++ b/xen/include/public/hvm/ioreq.h
@@ -1,20 +1,24 @@
/*
* ioreq.h: I/O request definitions for device models
* Copyright (c) 2004, Intel Corporation.
+ *
+ * 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:
*
- * 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.
+ * 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 _IOREQ_H_
@@ -23,7 +27,7 @@
#define IOREQ_READ 1
#define IOREQ_WRITE 0
-#define STATE_INVALID 0
+#define STATE_IOREQ_NONE 0
#define STATE_IOREQ_READY 1
#define STATE_IOREQ_INPROCESS 2
#define STATE_IORESP_READY 3
@@ -34,6 +38,7 @@
#define IOREQ_TYPE_OR 3
#define IOREQ_TYPE_XOR 4
#define IOREQ_TYPE_XCHG 5
+#define IOREQ_TYPE_ADD 6
/*
* VMExit dispatcher should cooperate with instruction decoder to
@@ -44,12 +49,10 @@ struct ioreq {
uint64_t addr; /* physical address */
uint64_t size; /* size in bytes */
uint64_t count; /* for rep prefixes */
- union {
- uint64_t data; /* data */
- void *pdata; /* pointer to data */
- } u;
+ uint64_t data; /* data (or paddr of data) */
uint8_t state:4;
- uint8_t pdata_valid:1; /* if 1, use pdata above */
+ uint8_t data_is_ptr:1; /* if 1, data above is the guest paddr
+ * of the real data to use. */
uint8_t dir:1; /* 1=read, 0=write */
uint8_t df:1;
uint8_t type; /* I/O type */
@@ -57,14 +60,6 @@ struct ioreq {
};
typedef struct ioreq ioreq_t;
-struct global_iodata {
- uint16_t pic_elcr;
- uint16_t pic_irr;
- uint16_t pic_last_irr;
- uint16_t pic_clear_irr;
-};
-typedef struct global_iodata global_iodata_t;
-
struct vcpu_iodata {
struct ioreq vp_ioreq;
/* Event channel port */
@@ -73,7 +68,6 @@ struct vcpu_iodata {
typedef struct vcpu_iodata vcpu_iodata_t;
struct shared_iopage {
- struct global_iodata sp_global;
struct vcpu_iodata vcpu_iodata[1];
};
typedef struct shared_iopage shared_iopage_t;
@@ -86,6 +80,10 @@ struct buffered_iopage {
}; /* sizeof this structure must be in one page */
typedef struct buffered_iopage buffered_iopage_t;
+#define ACPI_PM1A_EVT_BLK_ADDRESS 0x0000000000001f40
+#define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
+#define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
+
#endif /* _IOREQ_H_ */
/*
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index 432b32cb67..caa1f1f545 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -1,24 +1,36 @@
+
+/*
+ * 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 __XEN_PUBLIC_HVM_PARAMS_H__
#define __XEN_PUBLIC_HVM_PARAMS_H__
-/* Parameter space. */
+#include "hvm_op.h"
+
+/* Parameter space for HVMOP_{set,get}_param. */
#define HVM_PARAM_CALLBACK_IRQ 0
#define HVM_PARAM_STORE_PFN 1
#define HVM_PARAM_STORE_EVTCHN 2
-#define HVM_PARAM_APIC_ENABLED 3
#define HVM_PARAM_PAE_ENABLED 4
-#define HVM_NR_PARAMS 5
-
-/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */
-#define HVMOP_set_param 0
-#define HVMOP_get_param 1
-
-struct xen_hvm_param {
- domid_t domid; /* IN */
- uint32_t index; /* IN */
- uint64_t value; /* IN/OUT */
-};
-typedef struct xen_hvm_param xen_hvm_param_t;
-DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t);
+#define HVM_PARAM_IOREQ_PFN 5
+#define HVM_PARAM_BUFIOREQ_PFN 6
+#define HVM_NR_PARAMS 7
#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
diff --git a/xen/include/public/hvm/vmx_assist.h b/xen/include/public/hvm/vmx_assist.h
index f987b0fbc2..b07573c211 100644
--- a/xen/include/public/hvm/vmx_assist.h
+++ b/xen/include/public/hvm/vmx_assist.h
@@ -1,6 +1,24 @@
/*
* vmx_assist.h: Context definitions for the VMXASSIST world switch.
*
+ * 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.
+ *
* Leendert van Doorn, leendert@watson.ibm.com
* Copyright (c) 2005, International Business Machines Corporation.
*/
diff --git a/xen/include/public/io/blkif.h b/xen/include/public/io/blkif.h
index e29e400e9b..43fdf6ecbe 100644
--- a/xen/include/public/io/blkif.h
+++ b/xen/include/public/io/blkif.h
@@ -3,6 +3,24 @@
*
* Unified block-device I/O interface for Xen guest OSes.
*
+ * 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.
+ *
* Copyright (c) 2003-2004, Keir Fraser
*/
@@ -29,8 +47,22 @@
#endif
#define blkif_sector_t uint64_t
-#define BLKIF_OP_READ 0
-#define BLKIF_OP_WRITE 1
+/*
+ * REQUEST CODES.
+ */
+#define BLKIF_OP_READ 0
+#define BLKIF_OP_WRITE 1
+/*
+ * Recognised only if "feature-barrier" is present in backend xenbus info.
+ * The "feature_barrier" node contains a boolean indicating whether barrier
+ * requests are likely to succeed or fail. Either way, a barrier request
+ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by
+ * the underlying block-device hardware. The boolean simply indicates whether
+ * or not it is worthwhile for the frontend to attempt barrier requests.
+ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not*
+ * create the "feature-barrier" node!
+ */
+#define BLKIF_OP_WRITE_BARRIER 2
/*
* Maximum scatter/gather segments per request.
@@ -61,8 +93,15 @@ struct blkif_response {
};
typedef struct blkif_response blkif_response_t;
-#define BLKIF_RSP_ERROR -1 /* non-specific 'error' */
-#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
+/*
+ * STATUS RETURN CODES.
+ */
+ /* Operation not supported (only happens on barrier writes). */
+#define BLKIF_RSP_EOPNOTSUPP -2
+ /* Operation failed for some unspecified reason (-EIO). */
+#define BLKIF_RSP_ERROR -1
+ /* Operation completed successfully. */
+#define BLKIF_RSP_OKAY 0
/*
* Generate blkif ring structures and types.
diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h
index cb59b24ffc..4b8c01a447 100644
--- a/xen/include/public/io/console.h
+++ b/xen/include/public/io/console.h
@@ -3,6 +3,24 @@
*
* Console I/O interface for Xen guest OSes.
*
+ * 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.
+ *
* Copyright (c) 2005, Keir Fraser
*/
diff --git a/xen/include/public/io/netif.h b/xen/include/public/io/netif.h
index c012d11bfa..a2e885cae5 100644
--- a/xen/include/public/io/netif.h
+++ b/xen/include/public/io/netif.h
@@ -3,6 +3,24 @@
*
* Unified network-device I/O interface for Xen guest OSes.
*
+ * 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.
+ *
* Copyright (c) 2003-2004, Keir Fraser
*/
diff --git a/xen/include/public/io/pciif.h b/xen/include/public/io/pciif.h
index a1c9ab7c95..87b64c371f 100644
--- a/xen/include/public/io/pciif.h
+++ b/xen/include/public/io/pciif.h
@@ -1,6 +1,24 @@
/*
* PCI Backend/Frontend Common Data Structures & Macros
*
+ * 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.
+ *
* Author: Ryan Wilson <hap9@epoch.ncsc.mil>
*/
#ifndef __XEN_PCI_COMMON_H__
diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h
index 3723ef359d..704460b599 100644
--- a/xen/include/public/io/ring.h
+++ b/xen/include/public/io/ring.h
@@ -3,6 +3,24 @@
*
* Shared producer-consumer ring macros.
*
+ * 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.
+ *
* Tim Deegan and Andrew Warfield November 2004.
*/
@@ -25,7 +43,7 @@ typedef unsigned int RING_IDX;
* power of two (so we can mask with (size-1) to loop around).
*/
#define __RING_SIZE(_s, _sz) \
- (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+ (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
/*
* Macros to make the correct C datatypes for a new kind of ring.
@@ -152,7 +170,7 @@ typedef struct __name##_back_ring __name##_back_ring_t
((_r)->nr_ents)
/* Number of free requests (for use on front side only). */
-#define RING_FREE_REQUESTS(_r) \
+#define RING_FREE_REQUESTS(_r) \
(RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
/* Test if there is an empty slot available on the front ring.
@@ -165,13 +183,21 @@ typedef struct __name##_back_ring __name##_back_ring_t
#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
((_r)->sring->rsp_prod - (_r)->rsp_cons)
+#ifdef __GNUC__
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \
+ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
+ unsigned int rsp = RING_SIZE(_r) - \
+ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
+ req < rsp ? req : rsp; \
+})
+#else
+/* Same as above, but without the nice GCC ({ ... }) syntax. */
#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
- ({ \
- unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
- unsigned int rsp = RING_SIZE(_r) - \
- ((_r)->req_cons - (_r)->rsp_prod_pvt); \
- req < rsp ? req : rsp; \
- })
+ ((((_r)->sring->req_prod - (_r)->req_cons) < \
+ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \
+ ((_r)->sring->req_prod - (_r)->req_cons) : \
+ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt)))
+#endif
/* Direct access to individual ring elements, by index. */
#define RING_GET_REQUEST(_r, _idx) \
diff --git a/xen/include/public/io/tpmif.h b/xen/include/public/io/tpmif.h
index a088b63098..220671d3ed 100644
--- a/xen/include/public/io/tpmif.h
+++ b/xen/include/public/io/tpmif.h
@@ -3,6 +3,24 @@
*
* TPM I/O interface for Xen guest OSes.
*
+ * 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.
+ *
* Copyright (c) 2005, IBM Corporation
*
* Author: Stefan Berger, stefanb@us.ibm.com
diff --git a/xen/include/public/io/xenbus.h b/xen/include/public/io/xenbus.h
index 1c752dfaeb..fed498b3a1 100644
--- a/xen/include/public/io/xenbus.h
+++ b/xen/include/public/io/xenbus.h
@@ -3,6 +3,24 @@
*
* Xenbus protocol details.
*
+ * 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.
+ *
* Copyright (C) 2005 XenSource Ltd.
*/
diff --git a/xen/include/public/io/xs_wire.h b/xen/include/public/io/xs_wire.h
index 3c642fd1fc..e948bef29f 100644
--- a/xen/include/public/io/xs_wire.h
+++ b/xen/include/public/io/xs_wire.h
@@ -1,6 +1,25 @@
/*
* Details of the "wire" protocol between Xen Store Daemon and client
* library or guest kernel.
+ *
+ * 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.
+ *
* Copyright (C) 2005 Rusty Russell IBM Corporation
*/
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 97cb29a811..e28ed12620 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -3,6 +3,24 @@
*
* Memory reservation and information.
*
+ * 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.
+ *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/xen/include/public/nmi.h b/xen/include/public/nmi.h
index 69c408aa4d..b2b84018a3 100644
--- a/xen/include/public/nmi.h
+++ b/xen/include/public/nmi.h
@@ -3,6 +3,24 @@
*
* NMI callback registration and reason codes.
*
+ * 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.
+ *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index 9b0baee573..5692cee897 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -1,3 +1,22 @@
+/*
+ * 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 __XEN_PUBLIC_PHYSDEV_H__
#define __XEN_PUBLIC_PHYSDEV_H__
@@ -62,7 +81,7 @@ DEFINE_XEN_GUEST_HANDLE(physdev_set_iopl_t);
#define PHYSDEVOP_set_iobitmap 7
struct physdev_set_iobitmap {
/* IN */
- uint8_t *bitmap;
+ XEN_GUEST_HANDLE_00030205(uint8_t) bitmap;
uint32_t nr_ports;
};
typedef struct physdev_set_iobitmap physdev_set_iobitmap_t;
diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h
index 46e9160915..2937b4d31d 100644
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -3,6 +3,24 @@
*
* Hardware platform operations. Intended for use by domain-0 kernel.
*
+ * 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.
+ *
* Copyright (c) 2002-2006, K Fraser
*/
diff --git a/xen/include/public/sched.h b/xen/include/public/sched.h
index abf11cce92..2227a95be6 100644
--- a/xen/include/public/sched.h
+++ b/xen/include/public/sched.h
@@ -3,6 +3,24 @@
*
* Scheduler state interactions
*
+ * 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.
+ *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index d556270a09..072e06fa4f 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -3,6 +3,24 @@
*
* System management operations. For use by node control stack.
*
+ * 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.
+ *
* Copyright (c) 2002-2006, K Fraser
*/
diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h
index 4cb73386c3..8f5ef3965c 100644
--- a/xen/include/public/trace.h
+++ b/xen/include/public/trace.h
@@ -1,6 +1,24 @@
/******************************************************************************
* include/public/trace.h
*
+ * 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.
+ *
* Mark Williamson, (C) 2004 Intel Research Cambridge
* Copyright (C) 2005 Bin Ren
*/
@@ -19,11 +37,11 @@
/* Trace subclasses */
#define TRC_SUBCLS_SHIFT 12
+
/* trace subclasses for VMX */
#define TRC_VMXEXIT 0x00081000 /* VMX exit trace */
-#define TRC_VMXTIMER 0x00082000 /* VMX timer trace */
-#define TRC_VMXINT 0x00084000 /* VMX interrupt trace */
-#define TRC_VMXIO 0x00088000 /* VMX io emulation trace */
+#define TRC_VMXENTRY 0x00082000 /* VMX exit trace */
+#define TRC_VMXINTR 0x00084000 /* VMX interrupt trace */
/* Trace events per class */
#define TRC_LOST_RECORDS (TRC_GEN + 1)
@@ -50,11 +68,8 @@
/* trace events per subclass */
#define TRC_VMX_VMEXIT (TRC_VMXEXIT + 1)
-#define TRC_VMX_VMENTRY (TRC_VMXEXIT + 2)
-
-#define TRC_VMX_TIMER_INTR (TRC_VMXTIMER + 1)
-
-#define TRC_VMX_INT (TRC_VMXINT + 1)
+#define TRC_VMX_VMENTRY (TRC_VMXENTRY + 1)
+#define TRC_VMX_INTR (TRC_VMXINTR + 1)
/* This structure represents a single trace buffer record. */
diff --git a/xen/include/public/vcpu.h b/xen/include/public/vcpu.h
index 377defe17c..12df6dbe15 100644
--- a/xen/include/public/vcpu.h
+++ b/xen/include/public/vcpu.h
@@ -3,6 +3,24 @@
*
* VCPU initialisation, query, and hotplug.
*
+ * 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.
+ *
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
@@ -68,6 +86,7 @@ struct vcpu_runstate_info {
uint64_t time[4];
};
typedef struct vcpu_runstate_info vcpu_runstate_info_t;
+DEFINE_XEN_GUEST_HANDLE(vcpu_runstate_info_t);
/* VCPU is currently running on a physical CPU. */
#define RUNSTATE_running 0
@@ -90,8 +109,9 @@ typedef struct vcpu_runstate_info vcpu_runstate_info_t;
* Register a shared memory area from which the guest may obtain its own
* runstate information without needing to execute a hypercall.
* Notes:
- * 1. The registered address may be virtual or physical, depending on the
- * platform. The virtual address should be registered on x86 systems.
+ * 1. The registered address may be virtual or physical or guest handle,
+ * depending on the platform. Virtual address or guest handle should be
+ * registered on x86 systems.
* 2. Only one shared area may be registered per VCPU. The shared area is
* updated by the hypervisor each time the VCPU is scheduled. Thus
* runstate.state will always be RUNSTATE_running and
@@ -102,6 +122,7 @@ typedef struct vcpu_runstate_info vcpu_runstate_info_t;
#define VCPUOP_register_runstate_memory_area 5
struct vcpu_register_runstate_memory_area {
union {
+ XEN_GUEST_HANDLE(vcpu_runstate_info_t) h;
struct vcpu_runstate_info *v;
uint64_t p;
} addr;
diff --git a/xen/include/public/version.h b/xen/include/public/version.h
index dbe18c9e08..944ca620b0 100644
--- a/xen/include/public/version.h
+++ b/xen/include/public/version.h
@@ -3,6 +3,24 @@
*
* Xen version, type, and compile information.
*
+ * 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.
+ *
* Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
* Copyright (c) 2005, Keir Fraser <keir@xensource.com>
*/
diff --git a/xen/include/public/xen-compat.h b/xen/include/public/xen-compat.h
index 89f7bd487a..19b0a2c733 100644
--- a/xen/include/public/xen-compat.h
+++ b/xen/include/public/xen-compat.h
@@ -3,13 +3,31 @@
*
* Guest OS interface to Xen. Compatibility layer.
*
+ * 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.
+ *
* Copyright (c) 2006, Christian Limpach
*/
#ifndef __XEN_PUBLIC_XEN_COMPAT_H__
#define __XEN_PUBLIC_XEN_COMPAT_H__
-#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030204
+#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030205
#if defined(__XEN__) || defined(__XEN_TOOLS__)
/* Xen is built with matching headers and implements the latest interface. */
@@ -23,4 +41,11 @@
#error "These header files do not support the requested interface version."
#endif
+/* Fields defined as a Xen guest handle since 0x00030205. */
+#if __XEN_INTERFACE_VERSION__ >= 0x00030205
+#define XEN_GUEST_HANDLE_00030205(type) XEN_GUEST_HANDLE(type)
+#else
+#define XEN_GUEST_HANDLE_00030205(type) type *
+#endif
+
#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index bec06df60b..1b810df364 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -3,6 +3,24 @@
*
* Guest OS interface to Xen.
*
+ * 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.
+ *
* Copyright (c) 2004, K A Fraser
*/
@@ -228,7 +246,7 @@ struct mmuext_op {
/* SET_LDT */
unsigned int nr_ents;
/* TLB_FLUSH_MULTI, INVLPG_MULTI */
- void *vcpumask;
+ XEN_GUEST_HANDLE_00030205(void) vcpumask;
} arg2;
};
typedef struct mmuext_op mmuext_op_t;
@@ -517,25 +535,37 @@ typedef struct start_info start_info_t;
#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
typedef struct dom0_vga_console_info {
- uint8_t video_type;
- uint8_t txt_points;
- uint16_t txt_mode;
- uint16_t txt_x;
- uint16_t txt_y;
- uint16_t video_width;
- uint16_t video_height;
- uint16_t lfb_linelen;
- uint16_t lfb_depth;
- unsigned long lfb_base;
- unsigned long lfb_size;
- uint8_t red_pos;
- uint8_t red_size;
- uint8_t green_pos;
- uint8_t green_size;
- uint8_t blue_pos;
- uint8_t blue_size;
- uint8_t rsvd_pos;
- uint8_t rsvd_size;
+ uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
+#define XEN_VGATYPE_TEXT_MODE_3 0x03
+#define XEN_VGATYPE_VESA_LFB 0x23
+
+ union {
+ struct {
+ /* Font height, in pixels. */
+ uint16_t font_height;
+ /* Cursor location (column, row). */
+ uint16_t cursor_x, cursor_y;
+ /* Number of rows and columns (dimensions in characters). */
+ uint16_t rows, columns;
+ } text_mode_3;
+
+ struct {
+ /* Width and height, in pixels. */
+ uint16_t width, height;
+ /* Bytes per scan line. */
+ uint16_t bytes_per_line;
+ /* Bits per pixel. */
+ uint16_t bits_per_pixel;
+ /* LFB physical address, and size (in units of 64kB). */
+ uint32_t lfb_base;
+ uint32_t lfb_size;
+ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */
+ uint8_t red_pos, red_size;
+ uint8_t green_pos, green_size;
+ uint8_t blue_pos, blue_size;
+ uint8_t rsvd_pos, rsvd_size;
+ } vesa_lfb;
+ } u;
} dom0_vga_console_info_t;
typedef uint8_t xen_domain_handle_t[16];
diff --git a/xen/include/public/xencomm.h b/xen/include/public/xencomm.h
index fc2dda7734..ac45e0712a 100644
--- a/xen/include/public/xencomm.h
+++ b/xen/include/public/xencomm.h
@@ -1,19 +1,23 @@
/*
- * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
+ * 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:
*
- * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 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.
+ *
+ * Copyright (C) IBM Corp. 2006
*/
#ifndef _XEN_XENCOMM_H_
diff --git a/xen/include/public/xenoprof.h b/xen/include/public/xenoprof.h
index a788c36f2b..a624b73249 100644
--- a/xen/include/public/xenoprof.h
+++ b/xen/include/public/xenoprof.h
@@ -4,6 +4,24 @@
* Interface for enabling system wide profiling based on hardware performance
* counters
*
+ * 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.
+ *
* Copyright (C) 2005 Hewlett-Packard Co.
* Written by Aravind Menon & Jose Renato Santos
*/
@@ -69,7 +87,7 @@ struct xenoprof_get_buffer {
int32_t max_samples;
int32_t nbuf;
int32_t bufsize;
- uint64_t buf_maddr;
+ uint64_t buf_gmaddr;
};
typedef struct xenoprof_get_buffer xenoprof_get_buffer_t;
DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t);
@@ -92,7 +110,7 @@ typedef struct xenoprof_passive {
int32_t max_samples;
int32_t nbuf;
int32_t bufsize;
- uint64_t buf_maddr;
+ uint64_t buf_gmaddr;
} xenoprof_passive_t;
DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t);
diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h
index d70833efb5..85d6cee5f1 100644
--- a/xen/include/xen/compiler.h
+++ b/xen/include/xen/compiler.h
@@ -35,7 +35,7 @@
#define offsetof(a,b) ((unsigned long)&(((a *)0)->b))
#endif
-#if defined(__x86_64__) && (__GNUC__ > 3)
+#ifdef GCC_HAS_VISIBILITY_ATTRIBUTE
/* Results in more efficient PIC code (no indirections through GOT or PLT). */
#pragma GCC visibility push(hidden)
#endif
diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h
index e3f94d5843..068a550078 100644
--- a/xen/include/xen/config.h
+++ b/xen/include/xen/config.h
@@ -12,30 +12,70 @@
#define EXPORT_SYMBOL(var)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-/* Linux syslog levels. */
-#define KERN_NOTICE ""
-#define KERN_WARNING ""
-#define KERN_DEBUG ""
-#define KERN_INFO ""
-#define KERN_ERR ""
-#define KERN_CRIT ""
-#define KERN_EMERG ""
-#define KERN_ALERT ""
+/*
+ * The following log levels are as follows:
+ *
+ * XENLOG_ERR: Fatal errors, either Xen, Guest or Dom0
+ * is about to crash.
+ *
+ * XENLOG_WARNING: Something bad happened, but we can recover.
+ *
+ * XENLOG_INFO: Interesting stuff, but not too noisy.
+ *
+ * XENLOG_DEBUG: Use where ever you like. Lots of noise.
+ *
+ *
+ * Since we don't trust the guest operating system, we don't want
+ * it to allow for DoS by causing the HV to print out a lot of
+ * info, so where ever the guest has control of what is printed
+ * we use the XENLOG_GUEST to distinguish that the output is
+ * controlled by the guest.
+ *
+ * To make it easier on the typing, the above log levels all
+ * have a corresponding _G_ equivalent that appends the
+ * XENLOG_GUEST. (see the defines below).
+ *
+ */
+#define XENLOG_ERR "<0>"
+#define XENLOG_WARNING "<1>"
+#define XENLOG_INFO "<2>"
+#define XENLOG_DEBUG "<3>"
+
+#define XENLOG_GUEST "<G>"
+
+#define XENLOG_G_ERR XENLOG_GUEST XENLOG_ERR
+#define XENLOG_G_WARNING XENLOG_GUEST XENLOG_WARNING
+#define XENLOG_G_INFO XENLOG_GUEST XENLOG_INFO
+#define XENLOG_G_DEBUG XENLOG_GUEST XENLOG_DEBUG
+
+/*
+ * Some code is copied directly from Linux.
+ * Match some of the Linux log levels to Xen.
+ */
+#define KERN_ERR XENLOG_ERR
+#define KERN_CRIT XENLOG_ERR
+#define KERN_EMERG XENLOG_ERR
+#define KERN_WARNING XENLOG_WARNING
+#define KERN_NOTICE XENLOG_INFO
+#define KERN_INFO XENLOG_INFO
+#define KERN_DEBUG XENLOG_DEBUG
/* Linux 'checker' project. */
#define __iomem
#define __user
-#ifdef VERBOSE
-#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
- __FILE__ , __LINE__ , ## _a )
-#else
-#define DPRINTK(_f, _a...) ((void)0)
-#endif
-
#ifndef __ASSEMBLY__
+
+int current_domain_id(void);
+#define dprintk(_l, _f, _a...) \
+ printk(_l "%s:%d: " _f, __FILE__ , __LINE__ , ## _a )
+#define gdprintk(_l, _f, _a...) \
+ printk(XENLOG_GUEST _l "%s:%d:d%d " _f, __FILE__, \
+ __LINE__, current_domain_id() , ## _a )
+
#include <xen/compiler.h>
-#endif
+
+#endif /* !__ASSEMBLY__ */
#define __STR(...) #__VA_ARGS__
#define STR(...) __STR(__VA_ARGS__)
@@ -50,5 +90,7 @@
#endif /* !__ASSEMBLY__ */
#define fastcall
+#define __cpuinitdata
+#define __cpuinit
#endif /* __XEN_CONFIG_H__ */
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index d7125a317c..c01dbf23ad 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -26,4 +26,16 @@ void console_force_lock(void);
void console_start_sync(void);
void console_end_sync(void);
+void console_start_log_everything(void);
+void console_end_log_everything(void);
+
+/*
+ * Steal output from the console. Returns +ve identifier, else -ve error.
+ * Takes the handle of the serial line to steal, and steal callback function.
+ */
+int console_steal(int handle, void (*fn)(const char *));
+
+/* Give back stolen console. Takes the identifier returned by console_steal. */
+void console_giveback(int id);
+
#endif /* __CONSOLE_H__ */
diff --git a/xen/include/xen/cpumask.h b/xen/include/xen/cpumask.h
index 997efb1d45..d9296201cb 100644
--- a/xen/include/xen/cpumask.h
+++ b/xen/include/xen/cpumask.h
@@ -239,14 +239,14 @@ static inline int __next_cpu(int n, const cpumask_t *srcp, int nbits)
#if NR_CPUS <= BITS_PER_LONG
#define CPU_MASK_ALL \
-(cpumask_t) { { \
+/*(cpumask_t)*/ { { \
[BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
} }
#else
#define CPU_MASK_ALL \
-(cpumask_t) { { \
+/*(cpumask_t)*/ { { \
[0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \
[BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD \
} }
@@ -254,12 +254,12 @@ static inline int __next_cpu(int n, const cpumask_t *srcp, int nbits)
#endif
#define CPU_MASK_NONE \
-(cpumask_t) { { \
+/*(cpumask_t)*/ { { \
[0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
} }
#define CPU_MASK_CPU0 \
-(cpumask_t) { { \
+/*(cpumask_t)*/ { { \
[0] = 1UL \
} }
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index e421c8442d..70e8902a73 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -15,10 +15,20 @@ void free_domain(struct domain *d);
* Arch-specifics.
*/
-struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id);
-
+/* Allocate/free a VCPU structure. */
+struct vcpu *alloc_vcpu_struct(void);
void free_vcpu_struct(struct vcpu *v);
+/*
+ * Initialise/destroy arch-specific details of a VCPU.
+ * - vcpu_initialise() is called after the basic generic fields of the
+ * VCPU structure are initialised. Many operations can be applied to the
+ * VCPU at this point (e.g., vcpu_pause()).
+ * - vcpu_destroy() is called only if vcpu_initialise() previously succeeded.
+ */
+int vcpu_initialise(struct vcpu *v);
+void vcpu_destroy(struct vcpu *v);
+
int arch_domain_create(struct domain *d);
void arch_domain_destroy(struct domain *d);
@@ -29,6 +39,8 @@ void domain_relinquish_resources(struct domain *d);
void dump_pageframe_info(struct domain *d);
+void arch_dump_vcpu_info(struct vcpu *v);
+
void arch_dump_domain_info(struct domain *d);
#endif /* __XEN_DOMAIN_H__ */
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index 6817681e7d..39bb8031ca 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -70,4 +70,11 @@ void notify_via_xen_event_channel(int lport);
do_softirq(); \
} while ( 0 )
+#define prepare_wait_on_xen_event_channel(port) \
+ do { \
+ set_bit(_VCPUF_blocked_in_xen, &current->vcpu_flags); \
+ raise_softirq(SCHEDULE_SOFTIRQ); \
+ mb(); /* set blocked status /then/ caller does his work */ \
+ } while ( 0 )
+
#endif /* __XEN_EVENT_H__ */
diff --git a/xen/include/xen/gdbstub.h b/xen/include/xen/gdbstub.h
index f851f6193d..cf6e7e547c 100644
--- a/xen/include/xen/gdbstub.h
+++ b/xen/include/xen/gdbstub.h
@@ -33,7 +33,8 @@ char str2hex(const char *str);
unsigned long str2ulong(const char *str, unsigned long bytes);
struct gdb_context {
- int serhnd;
+ int serhnd; /* handle on our serial line */
+ int console_steal_id; /* handle on stolen console */
int currently_attached:1;
atomic_t running;
unsigned long connected;
diff --git a/xen/include/xen/iocap.h b/xen/include/xen/iocap.h
index db461b9dcb..77c06f2517 100644
--- a/xen/include/xen/iocap.h
+++ b/xen/include/xen/iocap.h
@@ -31,4 +31,12 @@
#define multipage_allocation_permitted(d) \
(!rangeset_is_empty((d)->iomem_caps))
+/*
+ * Until TLB flushing issues are sorted out we consider it unsafe for
+ * domains with no hardware-access privileges to perform grant map/transfer
+ * operations.
+ */
+#define grant_operation_permitted(d) \
+ (!rangeset_is_empty((d)->iomem_caps))
+
#endif /* __XEN_IOCAP_H__ */
diff --git a/xen/include/xen/keyhandler.h b/xen/include/xen/keyhandler.h
index ba443ae48f..451b4c3345 100644
--- a/xen/include/xen/keyhandler.h
+++ b/xen/include/xen/keyhandler.h
@@ -10,6 +10,9 @@
#ifndef __XEN_KEYHANDLER_H__
#define __XEN_KEYHANDLER_H__
+/* Initialize keytable with default handlers */
+extern void initialize_keytable(void);
+
/*
* Register a callback function for key @key. The callback occurs in
* softirq context with no locks held and interrupts enabled.
diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 00bb0830e9..e05eac28a9 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -2,7 +2,7 @@
#define __LIB_H__
#include <xen/inttypes.h>
-#include <stdarg.h>
+#include <xen/stdarg.h>
#include <xen/config.h>
#include <xen/types.h>
#include <xen/xmalloc.h>
@@ -51,12 +51,13 @@ extern void debugtrace_printk(const char *fmt, ...);
/* Allows us to use '%p' as general-purpose machine-word format char. */
#define _p(_x) ((void *)(unsigned long)(_x))
-#define printk(_f , _a...) printf( _f , ## _a )
-extern void printf(const char *format, ...)
+extern void printk(const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void panic(const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern long vm_assist(struct domain *, unsigned int, unsigned int);
+extern int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst);
+extern int printk_ratelimit(void);
/* vsprintf.c */
extern int sprintf(char * buf, const char * fmt, ...)
@@ -81,7 +82,7 @@ long long simple_strtoll(
unsigned long long simple_strtoull(
const char *cp,char **endp, unsigned int base);
-unsigned long long parse_size_and_unit(char *s);
+unsigned long long parse_size_and_unit(const char *s, char **ps);
#define TAINT_UNSAFE_SMP (1<<0)
#define TAINT_MACHINE_CHECK (1<<1)
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index 8c9713971b..4d05f6917f 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -45,7 +45,8 @@ void end_boot_allocator(void);
/* Generic allocator. These functions are *not* interrupt-safe. */
void init_heap_pages(
unsigned int zone, struct page_info *pg, unsigned long nr_pages);
-struct page_info *alloc_heap_pages(unsigned int zone, unsigned int order);
+struct page_info *alloc_heap_pages(
+ unsigned int zone, unsigned int cpu, unsigned int order);
void free_heap_pages(
unsigned int zone, struct page_info *pg, unsigned int order);
void scrub_heap_pages(void);
@@ -61,8 +62,12 @@ void free_xenheap_pages(void *v, unsigned int order);
void init_domheap_pages(paddr_t ps, paddr_t pe);
struct page_info *alloc_domheap_pages(
struct domain *d, unsigned int order, unsigned int memflags);
+struct page_info *__alloc_domheap_pages(
+ struct domain *d, unsigned int cpu, unsigned int order,
+ unsigned int memflags);
void free_domheap_pages(struct page_info *pg, unsigned int order);
unsigned long avail_domheap_pages(void);
+unsigned long avail_heap_pages(int zone, int node);
#define alloc_domheap_page(d) (alloc_domheap_pages(d,0,0))
#define free_domheap_page(p) (free_domheap_pages(p,0))
diff --git a/xen/include/xen/nodemask.h b/xen/include/xen/nodemask.h
new file mode 100644
index 0000000000..30ed6f4524
--- /dev/null
+++ b/xen/include/xen/nodemask.h
@@ -0,0 +1,338 @@
+#ifndef __LINUX_NODEMASK_H
+#define __LINUX_NODEMASK_H
+
+/*
+ * Nodemasks provide a bitmap suitable for representing the
+ * set of Node's in a system, one bit position per Node number.
+ *
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these nodemasks are based.
+ *
+ * For details of nodemask_scnprintf() and nodemask_parse(),
+ * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ *
+ * The available nodemask operations are:
+ *
+ * void node_set(node, mask) turn on bit 'node' in mask
+ * void node_clear(node, mask) turn off bit 'node' in mask
+ * void nodes_setall(mask) set all bits
+ * void nodes_clear(mask) clear all bits
+ * int node_isset(node, mask) true iff bit 'node' set in mask
+ * int node_test_and_set(node, mask) test and set bit 'node' in mask
+ *
+ * void nodes_and(dst, src1, src2) dst = src1 & src2 [intersection]
+ * void nodes_or(dst, src1, src2) dst = src1 | src2 [union]
+ * void nodes_xor(dst, src1, src2) dst = src1 ^ src2
+ * void nodes_andnot(dst, src1, src2) dst = src1 & ~src2
+ * void nodes_complement(dst, src) dst = ~src
+ *
+ * int nodes_equal(mask1, mask2) Does mask1 == mask2?
+ * int nodes_intersects(mask1, mask2) Do mask1 and mask2 intersect?
+ * int nodes_subset(mask1, mask2) Is mask1 a subset of mask2?
+ * int nodes_empty(mask) Is mask empty (no bits sets)?
+ * int nodes_full(mask) Is mask full (all bits sets)?
+ * int nodes_weight(mask) Hamming weight - number of set bits
+ *
+ * void nodes_shift_right(dst, src, n) Shift right
+ * void nodes_shift_left(dst, src, n) Shift left
+ *
+ * int first_node(mask) Number lowest set bit, or MAX_NUMNODES
+ * int next_node(node, mask) Next node past 'node', or MAX_NUMNODES
+ * int first_unset_node(mask) First node not set in mask, or
+ * MAX_NUMNODES.
+ *
+ * nodemask_t nodemask_of_node(node) Return nodemask with bit 'node' set
+ * NODE_MASK_ALL Initializer - all bits set
+ * NODE_MASK_NONE Initializer - no bits set
+ * unsigned long *nodes_addr(mask) Array of unsigned long's in mask
+ *
+ * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
+ * int nodemask_parse(ubuf, ulen, mask) Parse ascii string as nodemask
+ *
+ * for_each_node_mask(node, mask) for-loop node over mask
+ *
+ * int num_online_nodes() Number of online Nodes
+ * int num_possible_nodes() Number of all possible Nodes
+ *
+ * int node_online(node) Is some node online?
+ * int node_possible(node) Is some node possible?
+ *
+ * int any_online_node(mask) First online node in mask
+ *
+ * node_set_online(node) set bit 'node' in node_online_map
+ * node_set_offline(node) clear bit 'node' in node_online_map
+ *
+ * for_each_node(node) for-loop node over node_possible_map
+ * for_each_online_node(node) for-loop node over node_online_map
+ *
+ * Subtlety:
+ * 1) The 'type-checked' form of node_isset() causes gcc (3.3.2, anyway)
+ * to generate slightly worse code. So use a simple one-line #define
+ * for node_isset(), instead of wrapping an inline inside a macro, the
+ * way we do the other calls.
+ */
+
+#include <xen/kernel.h>
+#include <xen/bitmap.h>
+#include <xen/numa.h>
+
+typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
+extern nodemask_t _unused_nodemask_arg_;
+
+#define node_set(node, dst) __node_set((node), &(dst))
+static inline void __node_set(int node, volatile nodemask_t *dstp)
+{
+ set_bit(node, dstp->bits);
+}
+
+#define node_clear(node, dst) __node_clear((node), &(dst))
+static inline void __node_clear(int node, volatile nodemask_t *dstp)
+{
+ clear_bit(node, dstp->bits);
+}
+
+#define nodes_setall(dst) __nodes_setall(&(dst), MAX_NUMNODES)
+static inline void __nodes_setall(nodemask_t *dstp, int nbits)
+{
+ bitmap_fill(dstp->bits, nbits);
+}
+
+#define nodes_clear(dst) __nodes_clear(&(dst), MAX_NUMNODES)
+static inline void __nodes_clear(nodemask_t *dstp, int nbits)
+{
+ bitmap_zero(dstp->bits, nbits);
+}
+
+/* No static inline type checking - see Subtlety (1) above. */
+#define node_isset(node, nodemask) test_bit((node), (nodemask).bits)
+
+#define node_test_and_set(node, nodemask) \
+ __node_test_and_set((node), &(nodemask))
+static inline int __node_test_and_set(int node, nodemask_t *addr)
+{
+ return test_and_set_bit(node, addr->bits);
+}
+
+#define nodes_and(dst, src1, src2) \
+ __nodes_and(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_or(dst, src1, src2) \
+ __nodes_or(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_xor(dst, src1, src2) \
+ __nodes_xor(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_andnot(dst, src1, src2) \
+ __nodes_andnot(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_complement(dst, src) \
+ __nodes_complement(&(dst), &(src), MAX_NUMNODES)
+static inline void __nodes_complement(nodemask_t *dstp,
+ const nodemask_t *srcp, int nbits)
+{
+ bitmap_complement(dstp->bits, srcp->bits, nbits);
+}
+
+#define nodes_equal(src1, src2) \
+ __nodes_equal(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_equal(const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ return bitmap_equal(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_intersects(src1, src2) \
+ __nodes_intersects(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_intersects(const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ return bitmap_intersects(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_subset(src1, src2) \
+ __nodes_subset(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_subset(const nodemask_t *src1p,
+ const nodemask_t *src2p, int nbits)
+{
+ return bitmap_subset(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_empty(src) __nodes_empty(&(src), MAX_NUMNODES)
+static inline int __nodes_empty(const nodemask_t *srcp, int nbits)
+{
+ return bitmap_empty(srcp->bits, nbits);
+}
+
+#define nodes_full(nodemask) __nodes_full(&(nodemask), MAX_NUMNODES)
+static inline int __nodes_full(const nodemask_t *srcp, int nbits)
+{
+ return bitmap_full(srcp->bits, nbits);
+}
+
+#define nodes_weight(nodemask) __nodes_weight(&(nodemask), MAX_NUMNODES)
+static inline int __nodes_weight(const nodemask_t *srcp, int nbits)
+{
+ return bitmap_weight(srcp->bits, nbits);
+}
+
+#define nodes_shift_right(dst, src, n) \
+ __nodes_shift_right(&(dst), &(src), (n), MAX_NUMNODES)
+static inline void __nodes_shift_right(nodemask_t *dstp,
+ const nodemask_t *srcp, int n, int nbits)
+{
+ bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define nodes_shift_left(dst, src, n) \
+ __nodes_shift_left(&(dst), &(src), (n), MAX_NUMNODES)
+static inline void __nodes_shift_left(nodemask_t *dstp,
+ const nodemask_t *srcp, int n, int nbits)
+{
+ bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
+}
+
+/* FIXME: better would be to fix all architectures to never return
+ > MAX_NUMNODES, then the silly min_ts could be dropped. */
+
+#define first_node(src) __first_node(&(src))
+static inline int __first_node(const nodemask_t *srcp)
+{
+ return min_t(int, MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES));
+}
+
+#define next_node(n, src) __next_node((n), &(src))
+static inline int __next_node(int n, const nodemask_t *srcp)
+{
+ return min_t(int,MAX_NUMNODES,find_next_bit(srcp->bits, MAX_NUMNODES, n+1));
+}
+
+#define nodemask_of_node(node) \
+({ \
+ typeof(_unused_nodemask_arg_) m; \
+ if (sizeof(m) == sizeof(unsigned long)) { \
+ m.bits[0] = 1UL<<(node); \
+ } else { \
+ nodes_clear(m); \
+ node_set((node), m); \
+ } \
+ m; \
+})
+
+#define first_unset_node(mask) __first_unset_node(&(mask))
+static inline int __first_unset_node(const nodemask_t *maskp)
+{
+ return min_t(int,MAX_NUMNODES,
+ find_first_zero_bit(maskp->bits, MAX_NUMNODES));
+}
+
+#define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES)
+
+#if MAX_NUMNODES <= BITS_PER_LONG
+
+#define NODE_MASK_ALL \
+((nodemask_t) { { \
+ [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD \
+} })
+
+#else
+
+#define NODE_MASK_ALL \
+((nodemask_t) { { \
+ [0 ... BITS_TO_LONGS(MAX_NUMNODES)-2] = ~0UL, \
+ [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD \
+} })
+
+#endif
+
+#define NODE_MASK_NONE \
+((nodemask_t) { { \
+ [0 ... BITS_TO_LONGS(MAX_NUMNODES)-1] = 0UL \
+} })
+
+#define nodes_addr(src) ((src).bits)
+
+#if 0
+#define nodemask_scnprintf(buf, len, src) \
+ __nodemask_scnprintf((buf), (len), &(src), MAX_NUMNODES)
+static inline int __nodemask_scnprintf(char *buf, int len,
+ const nodemask_t *srcp, int nbits)
+{
+ return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+}
+
+#define nodemask_parse(ubuf, ulen, dst) \
+ __nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES)
+static inline int __nodemask_parse(const char __user *buf, int len,
+ nodemask_t *dstp, int nbits)
+{
+ return bitmap_parse(buf, len, dstp->bits, nbits);
+}
+#endif
+
+#if MAX_NUMNODES > 1
+#define for_each_node_mask(node, mask) \
+ for ((node) = first_node(mask); \
+ (node) < MAX_NUMNODES; \
+ (node) = next_node((node), (mask)))
+#else /* MAX_NUMNODES == 1 */
+#define for_each_node_mask(node, mask) \
+ if (!nodes_empty(mask)) \
+ for ((node) = 0; (node) < 1; (node)++)
+#endif /* MAX_NUMNODES */
+
+/*
+ * The following particular system nodemasks and operations
+ * on them manage all possible and online nodes.
+ */
+
+extern nodemask_t node_online_map;
+extern nodemask_t node_possible_map;
+
+#if MAX_NUMNODES > 1
+#define num_online_nodes() nodes_weight(node_online_map)
+#define num_possible_nodes() nodes_weight(node_possible_map)
+#define node_online(node) node_isset((node), node_online_map)
+#define node_possible(node) node_isset((node), node_possible_map)
+#else
+#define num_online_nodes() 1
+#define num_possible_nodes() 1
+#define node_online(node) ((node) == 0)
+#define node_possible(node) ((node) == 0)
+#endif
+
+#define any_online_node(mask) \
+({ \
+ int node; \
+ for_each_node_mask(node, (mask)) \
+ if (node_online(node)) \
+ break; \
+ node; \
+})
+
+#define node_set_online(node) set_bit((node), node_online_map.bits)
+#define node_set_offline(node) clear_bit((node), node_online_map.bits)
+
+#define for_each_node(node) for_each_node_mask((node), node_possible_map)
+#define for_each_online_node(node) for_each_node_mask((node), node_online_map)
+
+#endif /* __LINUX_NODEMASK_H */
diff --git a/xen/include/xen/numa.h b/xen/include/xen/numa.h
new file mode 100644
index 0000000000..9585fc9c48
--- /dev/null
+++ b/xen/include/xen/numa.h
@@ -0,0 +1,13 @@
+#ifndef _XEN_NUMA_H
+#define _XEN_NUMA_H
+
+#include <xen/config.h>
+#include <asm/numa.h>
+
+#ifndef NODES_SHIFT
+#define NODES_SHIFT 0
+#endif
+
+#define MAX_NUMNODES (1 << NODES_SHIFT)
+
+#endif /* _XEN_NUMA_H */
diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h
index 4cfed1cbb8..d506d7a589 100644
--- a/xen/include/xen/sched-if.h
+++ b/xen/include/xen/sched-if.h
@@ -63,16 +63,18 @@ struct scheduler {
void (*init) (void);
void (*tick) (unsigned int cpu);
- int (*init_vcpu) (struct vcpu *);
+ int (*init_domain) (struct domain *);
void (*destroy_domain) (struct domain *);
+ int (*init_vcpu) (struct vcpu *);
+ void (*destroy_vcpu) (struct vcpu *);
+
void (*sleep) (struct vcpu *);
void (*wake) (struct vcpu *);
- int (*set_affinity) (struct vcpu *, cpumask_t *);
-
struct task_slice (*do_schedule) (s_time_t);
+ int (*pick_cpu) (struct vcpu *);
int (*adjust) (struct domain *,
struct xen_domctl_scheduler_op *);
void (*dump_settings) (void);
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index fb98daeecc..bfb59f7b0c 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -75,7 +75,7 @@ struct vcpu
void *sched_priv; /* scheduler-specific data */
struct vcpu_runstate_info runstate;
- struct vcpu_runstate_info *runstate_guest; /* guest address */
+ XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */
unsigned long vcpu_flags;
@@ -144,6 +144,12 @@ struct domain
unsigned long domain_flags;
+ /* Boolean: Is this an HVM guest? */
+ char is_hvm;
+
+ /* Boolean: Is this guest fully privileged (aka dom0)? */
+ char is_privileged;
+
spinlock_t pause_lock;
unsigned int pause_count;
@@ -237,26 +243,30 @@ static inline void get_knownalive_domain(struct domain *d)
ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTROYED));
}
-extern struct domain *domain_create(domid_t domid);
-extern int construct_dom0(
+struct domain *domain_create(domid_t domid, unsigned int domcr_flags);
+ /* DOMCRF_hvm: Create an HVM domain, as opposed to a PV domain. */
+#define _DOMCRF_hvm 0
+#define DOMCRF_hvm (1U<<_DOMCRF_hvm)
+
+int construct_dom0(
struct domain *d,
unsigned long image_start, unsigned long image_len,
unsigned long initrd_start, unsigned long initrd_len,
char *cmdline);
-extern int set_info_guest(struct domain *d, xen_domctl_vcpucontext_t *);
+int set_info_guest(struct domain *d, xen_domctl_vcpucontext_t *);
struct domain *find_domain_by_id(domid_t dom);
-extern void domain_destroy(struct domain *d);
-extern void domain_kill(struct domain *d);
-extern void domain_shutdown(struct domain *d, u8 reason);
-extern void domain_pause_for_debugger(void);
+void domain_destroy(struct domain *d);
+void domain_kill(struct domain *d);
+void domain_shutdown(struct domain *d, u8 reason);
+void domain_pause_for_debugger(void);
/*
* Mark specified domain as crashed. This function always returns, even if the
* caller is the specified domain. The domain is not synchronously descheduled
* from any processor.
*/
-extern void __domain_crash(struct domain *d);
+void __domain_crash(struct domain *d);
#define domain_crash(d) do { \
printk("domain_crash called from %s:%d\n", __FILE__, __LINE__); \
__domain_crash(d); \
@@ -266,22 +276,19 @@ extern void __domain_crash(struct domain *d);
* Mark current domain as crashed and synchronously deschedule from the local
* processor. This function never returns.
*/
-extern void __domain_crash_synchronous(void) __attribute__((noreturn));
+void __domain_crash_synchronous(void) __attribute__((noreturn));
#define domain_crash_synchronous() do { \
printk("domain_crash_sync called from %s:%d\n", __FILE__, __LINE__); \
__domain_crash_synchronous(); \
} while (0)
-void new_thread(struct vcpu *d,
- unsigned long start_pc,
- unsigned long start_stack,
- unsigned long start_info);
-
#define set_current_state(_s) do { current->state = (_s); } while (0)
void scheduler_init(void);
void schedulers_start(void);
-int sched_init_vcpu(struct vcpu *);
-void sched_destroy_domain(struct domain *);
+int sched_init_vcpu(struct vcpu *v, unsigned int processor);
+void sched_destroy_vcpu(struct vcpu *v);
+int sched_init_domain(struct domain *d);
+void sched_destroy_domain(struct domain *d);
long sched_adjust(struct domain *, struct xen_domctl_scheduler_op *);
int sched_id(void);
void vcpu_wake(struct vcpu *d);
@@ -293,7 +300,7 @@ void vcpu_sleep_sync(struct vcpu *d);
* this call will ensure that all its state is committed to memory and that
* no CPU is using critical state (e.g., page tables) belonging to the VCPU.
*/
-extern void sync_vcpu_execstate(struct vcpu *v);
+void sync_vcpu_execstate(struct vcpu *v);
/*
* Called by the scheduler to switch to another VCPU. This function must
@@ -302,7 +309,7 @@ extern void sync_vcpu_execstate(struct vcpu *v);
* implementing lazy context switching, it suffices to ensure that invoking
* sync_vcpu_execstate() will switch and commit @prev's state.
*/
-extern void context_switch(
+void context_switch(
struct vcpu *prev,
struct vcpu *next);
@@ -312,10 +319,10 @@ extern void context_switch(
* saved to memory. Alternatively, if implementing lazy context switching,
* ensure that invoking sync_vcpu_execstate() will switch and commit @prev.
*/
-#define context_saved(prev) (clear_bit(_VCPUF_running, &(prev)->vcpu_flags))
+void context_saved(struct vcpu *prev);
/* Called by the scheduler to continue running the current VCPU. */
-extern void continue_running(
+void continue_running(
struct vcpu *same);
void startup_cpu_idle_loop(void);
@@ -386,41 +393,47 @@ extern struct domain *domain_list;
/* VCPU is paused by the hypervisor? */
#define _VCPUF_paused 11
#define VCPUF_paused (1UL<<_VCPUF_paused)
-/* VCPU is blocked awaiting an event to be consumed by Xen. */
+ /* VCPU is blocked awaiting an event to be consumed by Xen. */
#define _VCPUF_blocked_in_xen 12
#define VCPUF_blocked_in_xen (1UL<<_VCPUF_blocked_in_xen)
+ /* VCPU affinity has changed: migrating to a new CPU. */
+#define _VCPUF_migrating 13
+#define VCPUF_migrating (1UL<<_VCPUF_migrating)
/*
* Per-domain flags (domain_flags).
*/
- /* Is this domain privileged? */
-#define _DOMF_privileged 0
-#define DOMF_privileged (1UL<<_DOMF_privileged)
/* Guest shut itself down for some reason. */
-#define _DOMF_shutdown 1
+#define _DOMF_shutdown 0
#define DOMF_shutdown (1UL<<_DOMF_shutdown)
/* Death rattle. */
-#define _DOMF_dying 2
+#define _DOMF_dying 1
#define DOMF_dying (1UL<<_DOMF_dying)
/* Domain is paused by controller software. */
-#define _DOMF_ctrl_pause 3
+#define _DOMF_ctrl_pause 2
#define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause)
/* Domain is being debugged by controller software. */
-#define _DOMF_debugging 4
+#define _DOMF_debugging 3
#define DOMF_debugging (1UL<<_DOMF_debugging)
/* Are any VCPUs polling event channels (SCHEDOP_poll)? */
-#define _DOMF_polling 5
+#define _DOMF_polling 4
#define DOMF_polling (1UL<<_DOMF_polling)
/* Domain is paused by the hypervisor? */
-#define _DOMF_paused 6
+#define _DOMF_paused 5
#define DOMF_paused (1UL<<_DOMF_paused)
static inline int vcpu_runnable(struct vcpu *v)
{
return ( !(v->vcpu_flags &
- (VCPUF_blocked|VCPUF_down|VCPUF_paused|VCPUF_blocked_in_xen)) &&
+ ( VCPUF_blocked |
+ VCPUF_down |
+ VCPUF_paused |
+ VCPUF_blocked_in_xen |
+ VCPUF_migrating )) &&
!(v->domain->domain_flags &
- (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
+ ( DOMF_shutdown |
+ DOMF_ctrl_pause |
+ DOMF_paused )));
}
void vcpu_pause(struct vcpu *v);
@@ -441,11 +454,13 @@ static inline void vcpu_unblock(struct vcpu *v)
vcpu_wake(v);
}
-#define IS_PRIV(_d) \
- (test_bit(_DOMF_privileged, &(_d)->domain_flags))
+#define IS_PRIV(_d) ((_d)->is_privileged)
#define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))
+#define is_hvm_domain(d) ((d)->is_hvm)
+#define is_hvm_vcpu(v) (is_hvm_domain(v->domain))
+
#endif /* __SCHED_H__ */
/*
diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h
index 00e561dc86..d4e8edd7ad 100644
--- a/xen/include/xen/softirq.h
+++ b/xen/include/xen/softirq.h
@@ -8,9 +8,8 @@
#define KEYPRESS_SOFTIRQ 3
#define NMI_SOFTIRQ 4
#define PAGE_SCRUB_SOFTIRQ 5
-#define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6
-#define TRACE_SOFTIRQ 7
-#define NR_SOFTIRQS 8
+#define TRACE_SOFTIRQ 6
+#define NR_SOFTIRQS 7
#ifndef __ASSEMBLY__
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 73184daad8..11f83119d4 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -42,10 +42,10 @@
#if (__GNUC__ > 2)
typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#define SPIN_LOCK_UNLOCKED /*(spinlock_t)*/ { }
#else
typedef struct { int gcc_is_buggy; } spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#define SPIN_LOCK_UNLOCKED /*(spinlock_t)*/ { 0 }
#endif
#define spin_lock_init(lock) do { } while(0)
@@ -58,10 +58,10 @@ typedef struct { int gcc_is_buggy; } spinlock_t;
#if (__GNUC__ > 2)
typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { }
+#define RW_LOCK_UNLOCKED /*(rwlock_t)*/ { }
#else
typedef struct { int gcc_is_buggy; } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#define RW_LOCK_UNLOCKED /*(rwlock_t)*/ { 0 }
#endif
#define rwlock_init(lock) do { } while(0)
diff --git a/xen/include/xen/stdarg.h b/xen/include/xen/stdarg.h
new file mode 100644
index 0000000000..9508bc4df4
--- /dev/null
+++ b/xen/include/xen/stdarg.h
@@ -0,0 +1,5 @@
+#if defined(__OpenBSD__)
+# include "/usr/include/stdarg.h"
+#else
+# include <stdarg.h>
+#endif
diff --git a/xen/include/xen/time.h b/xen/include/xen/time.h
index 931401388e..33b12763ed 100644
--- a/xen/include/xen/time.h
+++ b/xen/include/xen/time.h
@@ -49,6 +49,20 @@ struct domain;
typedef s64 s_time_t;
s_time_t get_s_time(void);
+unsigned long get_localtime(struct domain *d);
+
+struct tm {
+ int tm_sec; /* seconds */
+ int tm_min; /* minutes */
+ int tm_hour; /* hours */
+ int tm_mday; /* day of the month */
+ int tm_mon; /* month */
+ int tm_year; /* year */
+ int tm_wday; /* day of the week */
+ int tm_yday; /* day in the year */
+ int tm_isdst; /* daylight saving time */
+};
+struct tm gmtime(unsigned long t);
#define NOW() ((s_time_t)get_s_time())
#define SECONDS(_s) ((s_time_t)((_s) * 1000000000ULL))
diff --git a/xen/include/xen/xenoprof.h b/xen/include/xen/xenoprof.h
index c6ba5da7ff..b9fe9de528 100644
--- a/xen/include/xen/xenoprof.h
+++ b/xen/include/xen/xenoprof.h
@@ -11,6 +11,7 @@
#define __XEN_XENOPROF_H__
#include <public/xenoprof.h>
+#include <asm/xenoprof.h>
#define XENOPROF_DOMAIN_IGNORED 0
#define XENOPROF_DOMAIN_ACTIVE 1
@@ -27,7 +28,7 @@ struct xenoprof_vcpu {
};
struct xenoprof {
- char* rawbuf;
+ char *rawbuf;
int npages;
int nbuf;
int bufsize;
@@ -40,4 +41,8 @@ struct xenoprof {
struct domain;
void free_xenoprof_pages(struct domain *d);
+int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg);
+
+extern struct domain *xenoprof_primary_profiler;
+
#endif /* __XEN__XENOPROF_H__ */
diff --git a/xen/tools/figlet/figlet.c b/xen/tools/figlet/figlet.c
index 8e79e83170..5d02ad51fd 100644
--- a/xen/tools/figlet/figlet.c
+++ b/xen/tools/figlet/figlet.c
@@ -1448,8 +1448,9 @@ inchr c;
}
else {
for (k=0;k<smushamount;k++) {
- outputline[row][outlinelen-smushamount+k] =
- smushem(outputline[row][outlinelen-smushamount+k],currchar[row][k]);
+ if (outlinelen-smushamount+k >= 0)
+ outputline[row][outlinelen-smushamount+k] =
+ smushem(outputline[row][outlinelen-smushamount+k],currchar[row][k]);
}
strcat(outputline[row],currchar[row]+smushamount);
}