diff options
author | Alex Williamson <alex.williamson@hp.com> | 2008-02-14 09:34:27 -0700 |
---|---|---|
committer | Alex Williamson <alex.williamson@hp.com> | 2008-02-14 09:34:27 -0700 |
commit | e38c4f55fe6ef6c393388ae181630ab3a92f77dd (patch) | |
tree | 24970faea32f21f96b9048f8a36c8e8d9dafe2b2 | |
parent | 03c9b741df33f676c99c7885ca7f795190df37d5 (diff) | |
parent | df5b25e9af9248d8e00d0ef7e4ce3eec9eb44f97 (diff) | |
download | xen-e38c4f55fe6ef6c393388ae181630ab3a92f77dd.tar.gz xen-e38c4f55fe6ef6c393388ae181630ab3a92f77dd.tar.bz2 xen-e38c4f55fe6ef6c393388ae181630ab3a92f77dd.zip |
merge with xen-unstable.hg
184 files changed, 7103 insertions, 1766 deletions
@@ -80,6 +80,17 @@ ^pristine-.*$ ^ref-.*$ ^tmp-.*$ +^stubdom/binutils-.*$ +^stubdom/cross-root-.*$ +^stubdom/gcc-.*$ +^stubdom/include$ +^stubdom/ioemu$ +^stubdom/libxc$ +^stubdom/lwip-.*$ +^stubdom/mini-os$ +^stubdom/newlib-.*$ +^stubdom/pciutils-.*$ +^stubdom/zlib-.*$ ^tools/.*/TAGS$ ^tools/.*/build/lib.*/.*\.py$ ^tools/blktap/Makefile\.smh$ diff --git a/buildconfigs/enable-xen-config b/buildconfigs/enable-xen-config index 1f9945faef..75f648eab6 100644 --- a/buildconfigs/enable-xen-config +++ b/buildconfigs/enable-xen-config @@ -1,6 +1,6 @@ #!/bin/sh -set -ex +set -e if [ $# -ne 1 ] ; then echo "Usage $(basename $0) <config-file>" 1>&2 @@ -26,6 +26,7 @@ setopt() } setopt CONFIG_PARAVIRT y +setopt CONFIG_PARAVIRT_GUEST y setopt CONFIG_XEN y setopt CONFIG_VMI y setopt CONFIG_KVM y @@ -36,5 +37,12 @@ setopt CONFIG_XEN_BLKDEV_FRONTEND y setopt CONFIG_XEN_NETDEV_FRONTEND y setopt CONFIG_HVC_XEN y setopt CONFIG_NUMA n +setopt CONFIG_LOCALVERSION_AUTO n + +case ${XEN_TARGET_ARCH} in + x86_32) setopt CONFIG_64BIT n ;; + x86_64) setopt CONFIG_64BIT y ;; + *) ;; +esac exit 0 diff --git a/buildconfigs/mk.linux-2.6-common b/buildconfigs/mk.linux-2.6-common index 35150591b5..024d55f680 100644 --- a/buildconfigs/mk.linux-2.6-common +++ b/buildconfigs/mk.linux-2.6-common @@ -14,22 +14,15 @@ else __XEN_LINUX_UPDATE = endif -# Let XEN_TARGET_ARCH override ARCH. -ifeq ($(XEN_TARGET_ARCH),x86_32) -LINUX_ARCH ?= i386 +ifeq ($(XEN_LINUX_NONINTERACTIVE_CONFIG),y) +__NONINT_CONFIG = yes $$'\n' | else -LINUX_ARCH ?= $(XEN_TARGET_ARCH) +__NONINT_CONFIG = endif LINUX_DIR = build-linux-$(LINUX_VER)$(EXTRAVERSION)_$(XEN_TARGET_ARCH) IMAGE_TARGET ?= vmlinuz -ifneq ($(XEN_TARGET_ARCH),ia64) -IMAGE_PATH ?= arch/$(LINUX_ARCH)/boot/$(firstword $(IMAGE_TARGET)) -else -IMAGE_PATH ?= arch/ia64/hp/sim/boot/vmlinux.gz -endif -INSTALL_BOOT_PATH := $(DESTDIR)/boot LINUX_VER3 := $(LINUX_SERIES).$(word 3, $(subst ., ,$(LINUX_VER))) @@ -38,6 +31,11 @@ _build: build include buildconfigs/src.$(XEN_LINUX_SOURCE) +LINUX_ARCH = $$(sh buildconfigs/select-linux-arch $(LINUX_SRCDIR)) +IMAGE_PATH = $$(sh buildconfigs/select-linux-image $(LINUX_DIR) $(LINUX_ARCH) $(IMAGE_TARGET)) + +INSTALL_BOOT_PATH := $(DESTDIR)/boot + # Default to allowing interface mismatch ifndef XEN_LINUX_ALLOW_INTERFACE_MISMATCH XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y @@ -64,9 +62,9 @@ endif fi $(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_PATH=$(DESTDIR) $(IMAGE_TARGET) mkdir -p $(INSTALL_BOOT_PATH) - cp $(LINUX_DIR)/$(IMAGE_PATH) $(INSTALL_BOOT_PATH)/vmlinuz-$(KERNELRELEASE) - cp $(LINUX_DIR)/.config $(INSTALL_BOOT_PATH)/config-$(KERNELRELEASE) - cp $(LINUX_DIR)/System.map $(INSTALL_BOOT_PATH)/System.map-$(KERNELRELEASE) + @cp -v $(IMAGE_PATH) $(INSTALL_BOOT_PATH)/vmlinuz-$(KERNELRELEASE) + @cp -v $(LINUX_DIR)/.config $(INSTALL_BOOT_PATH)/config-$(KERNELRELEASE) + @cp -v $(LINUX_DIR)/System.map $(INSTALL_BOOT_PATH)/System.map-$(KERNELRELEASE) $(LINUX_DIR)/include/linux/autoconf.h: CONFIG_FILE=$(CURDIR)/$(LINUX_DIR)/.config $(LINUX_DIR)/include/linux/autoconf.h: $(LINUX_SRCDIR)/.valid-src @@ -102,7 +100,7 @@ endif ifneq ($(EXTRAVERSION),) echo "$(EXTRAVERSION)" >$(LINUX_DIR)/localversion-xen endif - $(MAKE) -C $(LINUX_SRCDIR) ARCH=$(LINUX_ARCH) oldconfig O=$$(/bin/pwd)/$(LINUX_DIR) + $(__NONINT_CONFIG) $(MAKE) -C $(LINUX_SRCDIR) ARCH=$(LINUX_ARCH) oldconfig O=$$(/bin/pwd)/$(LINUX_DIR) @set -e ; if [ ! -f $(LINUX_DIR)/Makefile ] ; then \ echo "***********************************"; \ echo "oldconfig did not create a Makefile"; \ diff --git a/buildconfigs/select-linux-arch b/buildconfigs/select-linux-arch new file mode 100755 index 0000000000..a5d0856e12 --- /dev/null +++ b/buildconfigs/select-linux-arch @@ -0,0 +1,30 @@ +#!/bin/sh + +ME=$(basename $0) + +if [ $# -lt 1 ] || [ $# -gt 2 ] ; then + echo "usage: $ME <linux-build-directory>" 1>&2 + exit 1; +fi + +LINUX_DIR=$1 + +case ${XEN_TARGET_ARCH} in + x86_32|x86_64) + if [ -d ${LINUX_DIR}/arch/x86 ] ; then + ARCH=x86 + elif [ "${XEN_TARGET_ARCH}" = "x86_32" ] ; then + ARCH=i386 + else + ARCH=x86_64 + fi + ;; + *) + ARCH=${XEN_TARGET_ARCH} + ;; +esac + +echo "$ME: ${ARCH}" 1>&2 +echo ${ARCH} + +exit 0 diff --git a/buildconfigs/select-linux-image b/buildconfigs/select-linux-image new file mode 100755 index 0000000000..07899f80e2 --- /dev/null +++ b/buildconfigs/select-linux-image @@ -0,0 +1,33 @@ +#!/bin/sh + +ME=$(basename $0) + +if [ $# -lt 3 ] ; then + echo "usage: $ME <linux-build-directory> <linux-arch> <linux-targets...>" 1>&2 + exit 1; +fi + +LINUX_DIR=$1 +LINUX_ARCH=$2 +LINUX_TARGET=$3 # We don't care about second and subsequent targets + +case ${XEN_TARGET_ARCH} in + ia64) + IMAGE=${LINUX_DIR}/arch/ia64/hp/sim/boot/vmlinux.gz + ;; + *) + if [ -f ${LINUX_DIR}/arch/${LINUX_ARCH}/boot/${LINUX_TARGET} ] ; then + IMAGE=${LINUX_DIR}/arch/${LINUX_ARCH}/boot/${LINUX_TARGET} + elif [ -f ${LINUX_DIR}/${LINUX_TARGET} ] ; then + IMAGE=${LINUX_DIR}/${LINUX_TARGET} + else + echo "$ME: cannot determine Linux image to use for ${LINUX_ARCH} in ${LINUX_DIR}" 1>&2 + exit 1 + fi + ;; +esac + +echo "$ME: ${IMAGE}" 1>&2 +echo ${IMAGE} + +exit 0 diff --git a/config/MiniOS.mk b/config/MiniOS.mk new file mode 100644 index 0000000000..fc02b70fc4 --- /dev/null +++ b/config/MiniOS.mk @@ -0,0 +1,9 @@ +include $(XEN_ROOT)/config/StdGNU.mk +include $(XEN_ROOT)/extras/mini-os/Config.mk +CFLAGS += $(DEF_CFLAGS) $(ARCH_CFLAGS) +CPPFLAGS += $(DEF_CPPFLAGS) $(ARCH_CPPFLAGS) $(extra_incl) +ASFLAGS += $(DEF_ASFLAGS) $(ARCH_ASFLAGS) +LDFLAGS += $(DEF_LDFLAGS) $(ARCH_LDFLAGS) + +# Override settings for this OS +PTHREAD_LIBS = diff --git a/config/StdGNU.mk b/config/StdGNU.mk index dfbc7ece44..82a99d3f11 100644 --- a/config/StdGNU.mk +++ b/config/StdGNU.mk @@ -35,6 +35,7 @@ PRIVATE_BINDIR = $(PRIVATE_PREFIX)/bin SOCKET_LIBS = CURSES_LIBS = -lncurses +PTHREAD_LIBS = -lpthread UTIL_LIBS = -lutil SONAME_LDFLAG = -soname SHLIB_CFLAGS = -shared diff --git a/config/SunOS.mk b/config/SunOS.mk index e6035bf4ca..c2a5594000 100644 --- a/config/SunOS.mk +++ b/config/SunOS.mk @@ -39,6 +39,7 @@ SunOS_LIBDIR_x86_64 = /usr/sfw/lib/amd64 SOCKET_LIBS = -lsocket CURSES_LIBS = -lcurses +PTHREAD_LIBS = -lpthread UTIL_LIBS = SONAME_LDFLAG = -h SHLIB_CFLAGS = -R $(SunOS_LIBDIR) -shared diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt index 90632863df..baf2c42dc0 100644 --- a/docs/misc/xenstore.txt +++ b/docs/misc/xenstore.txt @@ -296,6 +296,16 @@ RESUME <domid>| xenstored prevents the use of RESUME other than by dom0. +SET_TARGET <domid>|<tdomid>| + Notifies xenstored that domain <domid> is targeting domain + <tdomid>. This grants domain <domid> full access to paths + owned by <tdomid>. Domain <domid> also inherits all + permissions granted to <tdomid> on all other paths. This + allows <domid> to behave as if it were dom0 when modifying + paths related to <tdomid>. + + xenstored prevents the use of SET_TARGET other than by dom0. + ---------- Miscellaneous ---------- DEBUG print|<string>|?? sends <string> to debug log diff --git a/docs/xen-api/revision-history.tex b/docs/xen-api/revision-history.tex index 70ac17390f..d282adb106 100644 --- a/docs/xen-api/revision-history.tex +++ b/docs/xen-api/revision-history.tex @@ -23,5 +23,12 @@ \end{flushleft} \end{minipage}\\ \hline + 1.0.2 & 11th Feb. 08 & S. Berger & + \begin{minipage}[t]{7cm} + \begin{flushleft} + Added table of contents and hyperlink cross reference. + \end{flushleft} + \end{minipage}\\ + \hline \end{tabular} \end{center}
\ No newline at end of file diff --git a/docs/xen-api/xenapi-coversheet.tex b/docs/xen-api/xenapi-coversheet.tex index bf9371f073..c35190acfe 100644 --- a/docs/xen-api/xenapi-coversheet.tex +++ b/docs/xen-api/xenapi-coversheet.tex @@ -17,7 +17,7 @@ \newcommand{\coversheetlogo}{xen.eps} %% Document date -\newcommand{\datestring}{25th January 2008} +\newcommand{\datestring}{11th February 2008} \newcommand{\releasestatement}{Stable Release} diff --git a/docs/xen-api/xenapi.tex b/docs/xen-api/xenapi.tex index f71689e377..902d9b2daf 100644 --- a/docs/xen-api/xenapi.tex +++ b/docs/xen-api/xenapi.tex @@ -17,6 +17,7 @@ \usepackage{graphics} \usepackage{longtable} \usepackage{fancyhdr} +\usepackage{hyperref} \setlength\topskip{0cm} \setlength\topmargin{0cm} @@ -35,6 +36,10 @@ % The revision history \include{revision-history} +% Table of contents +\tableofcontents + + % ... and off we go! \chapter{Introduction} diff --git a/extras/mini-os/Config.mk b/extras/mini-os/Config.mk new file mode 100644 index 0000000000..e38fae99cb --- /dev/null +++ b/extras/mini-os/Config.mk @@ -0,0 +1,76 @@ +# Set mini-os root path, used in mini-os.mk. +MINI-OS_ROOT=$(XEN_ROOT)/extras/mini-os +export MINI-OS_ROOT + +ifeq ($(XEN_TARGET_ARCH),x86_32) +export pae ?= y +endif +libc = $(stubdom) + +XEN_INTERFACE_VERSION := 0x00030205 +export XEN_INTERFACE_VERSION + +# Try to find out the architecture family TARGET_ARCH_FAM. +# First check whether x86_... is contained (for x86_32, x86_32y, x86_64). +# If not x86 then use $(XEN_TARGET_ARCH) -> for ia64, ... +ifeq ($(findstring x86_,$(XEN_TARGET_ARCH)),x86_) +TARGET_ARCH_FAM = x86 +else +TARGET_ARCH_FAM = $(XEN_TARGET_ARCH) +endif + +# The architecture family directory below mini-os. +TARGET_ARCH_DIR := arch/$(TARGET_ARCH_FAM) + +# Export these variables for possible use in architecture dependent makefiles. +export TARGET_ARCH_DIR +export TARGET_ARCH_FAM +export XEN_TARGET_X86_PAE + +# This is used for architecture specific links. +# This can be overwritten from arch specific rules. +ARCH_LINKS = + +# The path pointing to the architecture specific header files. +ARCH_INC := $(TARGET_ARCH_FAM) + +# For possible special header directories. +# This can be overwritten from arch specific rules. +EXTRA_INC = $(ARCH_INC) + +# Include the architecture family's special makerules. +# This must be before include minios.mk! +include $(MINI-OS_ROOT)/$(TARGET_ARCH_DIR)/arch.mk + +extra_incl := $(foreach dir,$(EXTRA_INC),-I$(MINI-OS_ROOT)/include/$(dir)) + +DEF_CPPFLAGS += -I$(MINI-OS_ROOT)/include + +ifeq ($(stubdom),y) +DEF_CPPFLAGS += -DCONFIG_STUBDOM +endif + +ifeq ($(libc),y) +DEF_CPPFLAGS += -DHAVE_LIBC +DEF_CPPFLAGS += -I$(MINI-OS_ROOT)/include/posix +DEF_CPPFLAGS += -I$(XEN_ROOT)/tools/xenstore +endif + +ifneq ($(LWIPDIR),) +lwip=y +DEF_CPPFLAGS += -DHAVE_LWIP +DEF_CPPFLAGS += -I$(LWIPDIR)/src/include +DEF_CPPFLAGS += -I$(LWIPDIR)/src/include/ipv4 +endif + +ifneq ($(QEMUDIR),) +qemu=y +endif + +ifneq ($(CAMLDIR),) +caml=y +endif + +ifeq ($(pae),y) +DEF_CPPFLAGS += -DCONFIG_X86_PAE +endif diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile index a008143cf0..4811f0dbfd 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -4,54 +4,11 @@ # Makefile and a arch.mk. # -XEN_ROOT = ../.. +export XEN_ROOT = ../.. include $(XEN_ROOT)/Config.mk -XEN_INTERFACE_VERSION := 0x00030205 -export XEN_INTERFACE_VERSION - -# Set TARGET_ARCH -override TARGET_ARCH := $(XEN_TARGET_ARCH) - -# Set mini-os root path, used in mini-os.mk. -MINI-OS_ROOT=$(PWD) -export MINI-OS_ROOT - -# Try to find out the architecture family TARGET_ARCH_FAM. -# First check whether x86_... is contained (for x86_32, x86_32y, x86_64). -# If not x86 then use $(TARGET_ARCH) -> for ia64, ... -ifeq ($(findstring x86_,$(TARGET_ARCH)),x86_) -TARGET_ARCH_FAM = x86 -else -TARGET_ARCH_FAM = $(TARGET_ARCH) -endif - -# The architecture family directory below mini-os. -TARGET_ARCH_DIR := arch/$(TARGET_ARCH_FAM) - -# Export these variables for possible use in architecture dependent makefiles. -export TARGET_ARCH -export TARGET_ARCH_DIR -export TARGET_ARCH_FAM -export XEN_TARGET_X86_PAE - -# This is used for architecture specific links. -# This can be overwritten from arch specific rules. -ARCH_LINKS = - -# For possible special header directories. -# This can be overwritten from arch specific rules. -EXTRA_INC = - -# Include the architecture family's special makerules. -# This must be before include minios.mk! -include $(TARGET_ARCH_DIR)/arch.mk - -ifneq ($(LWIPDIR),) -lwip=y -DEF_CFLAGS += -DHAVE_LWIP -DEF_CFLAGS += -I$(LWIPDIR)/src/include -DEF_CFLAGS += -I$(LWIPDIR)/src/include/ipv4 +ifneq ($(stubdom),y) +include Config.mk endif # Include common mini-os makerules. @@ -63,7 +20,7 @@ include minios.mk # Define some default flags for linking. LDLIBS := LDARCHLIB := -L$(TARGET_ARCH_DIR) -l$(ARCH_LIB_NAME) -LDFLAGS_FINAL := -T $(TARGET_ARCH_DIR)/minios-$(TARGET_ARCH).lds +LDFLAGS_FINAL := -T $(TARGET_ARCH_DIR)/minios-$(XEN_TARGET_ARCH).lds # Prefix for global API names. All other symbols are localised before # linking with EXTRA_OBJS. @@ -112,14 +69,38 @@ lwip.a: $(LWO) $(AR) cqs $@ $^ OBJS += lwip.a +endif + +OBJS := $(filter-out lwip%.o $(LWO), $(OBJS)) -OBJS := $(filter-out $(LWO), $(OBJS)) +ifeq ($(caml),y) +CAMLLIB = $(shell ocamlc -where) +OBJS += $(CAMLDIR)/caml.o +OBJS += $(CAMLLIB)/libasmrun.a +CFLAGS += -I$(CAMLLIB) +LDLIBS += -lm else -OBJS := $(filter-out daytime.o lwip%.o, $(OBJS)) +OBJS := $(filter-out main-caml.o, $(OBJS)) +endif + +ifeq ($(qemu),y) +OBJS += $(QEMUDIR)/i386-dm-stubdom/qemu.a $(QEMUDIR)/i386-dm-stubdom/libqemu.a +CFLAGS += -DCONFIG_QEMU +endif + +ifeq ($(libc),y) +LDLIBS += -L$(XEN_ROOT)/stubdom/libxc -lxenctrl -lxenguest +LDLIBS += -lpci +LDLIBS += -lz +LDLIBS += -lc +endif + +ifneq ($(caml)-$(qemu)-$(lwip),--y) +OBJS := $(filter-out daytime.o, $(OBJS)) endif $(TARGET): links $(OBJS) arch_lib - $(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(OBJS) $(LDARCHLIB) -o $@.o + $(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o $(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o $(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@ gzip -f -9 -c $@ >$@.gz diff --git a/extras/mini-os/arch/ia64/Makefile b/extras/mini-os/arch/ia64/Makefile index fb5ca9fb72..6e46aa67ef 100644 --- a/extras/mini-os/arch/ia64/Makefile +++ b/extras/mini-os/arch/ia64/Makefile @@ -5,6 +5,8 @@ XEN_ROOT = ../../../.. include $(XEN_ROOT)/Config.mk +include ../../Config.mk + include arch.mk include ../../minios.mk @@ -41,7 +43,7 @@ ARCH_OBJS += __divdi3.o GEN_OFF_SRC := gen_off.c GEN_OFF_ASM := gen_off.s -GEN_OFF_H := $(ARCH_INC)/offsets.h +GEN_OFF_H := $(MINI-OS_ROOT)/include/$(ARCH_INC)/offsets.h all: $(ARCH_LIB) diff --git a/extras/mini-os/arch/ia64/minios-ia64.lds b/extras/mini-os/arch/ia64/minios-ia64.lds index 70435de11e..96911aa3fd 100644 --- a/extras/mini-os/arch/ia64/minios-ia64.lds +++ b/extras/mini-os/arch/ia64/minios-ia64.lds @@ -40,6 +40,18 @@ SECTIONS .rodata.str1.8 : AT(ADDR(.rodata.str1.8) - (((5<<(61))+0x100000000) - (1 << 20))) { *(.rodata.str1.8) } + /* newlib initialization functions */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - (((5<<(61))+0x100000000) - (1 << 20))) { *(.IA_64.unwind_info) } diff --git a/extras/mini-os/arch/ia64/mm.c b/extras/mini-os/arch/ia64/mm.c index f557730257..f2291f918c 100644 --- a/extras/mini-os/arch/ia64/mm.c +++ b/extras/mini-os/arch/ia64/mm.c @@ -43,6 +43,14 @@ extern uint64_t _text[], _etext[], _end[], kstack[], phys_start[]; uint64_t kernstart, kernend, kernsize, kernpstart, kernpend; +#ifdef HAVE_LIBC +uint8_t _heap[512 * 1024]; +unsigned long heap = (unsigned long)_heap, + brk = (unsigned long)_heap, + heap_mapped = (unsigned long)_heap + sizeof(_heap), + heap_end = (unsigned long)_heap + sizeof(_heap); +#endif + /* Print the available memory chunks. */ static void print_phys_avail(void) diff --git a/extras/mini-os/arch/x86/Makefile b/extras/mini-os/arch/x86/Makefile index 22cfe82811..21f0958f6a 100644 --- a/extras/mini-os/arch/x86/Makefile +++ b/extras/mini-os/arch/x86/Makefile @@ -5,13 +5,14 @@ XEN_ROOT = ../../../.. include $(XEN_ROOT)/Config.mk +include ../../Config.mk # include arch.mk has to be before mini-os.mk! include arch.mk include ../../minios.mk -# Sources here are all *.c *.S without $(TARGET_ARCH).S +# Sources here are all *.c *.S without $(XEN_TARGET_ARCH).S # This is handled in $(HEAD_ARCH_OBJ) ARCH_SRCS := $(wildcard *.c) diff --git a/extras/mini-os/arch/x86/arch.mk b/extras/mini-os/arch/x86/arch.mk index dd6bfe0b8d..1680362789 100644 --- a/extras/mini-os/arch/x86/arch.mk +++ b/extras/mini-os/arch/x86/arch.mk @@ -3,11 +3,11 @@ # (including x86_32, x86_32y and x86_64). # -ifeq ($(TARGET_ARCH),x86_32) +ifeq ($(XEN_TARGET_ARCH),x86_32) ARCH_CFLAGS := -m32 -march=i686 ARCH_LDFLAGS := -m elf_i386 ARCH_ASFLAGS := -m32 -EXTRA_INC += $(TARGET_ARCH_FAM)/$(TARGET_ARCH) +EXTRA_INC += $(TARGET_ARCH_FAM)/$(XEN_TARGET_ARCH) EXTRA_SRC += arch/$(EXTRA_INC) ifeq ($(XEN_TARGET_X86_PAE),y) @@ -16,12 +16,12 @@ ARCH_ASFLAGS += -DCONFIG_X86_PAE=1 endif endif -ifeq ($(TARGET_ARCH),x86_64) +ifeq ($(XEN_TARGET_ARCH),x86_64) ARCH_CFLAGS := -m64 -mno-red-zone -fno-reorder-blocks ARCH_CFLAGS += -fno-asynchronous-unwind-tables ARCH_ASFLAGS := -m64 ARCH_LDFLAGS := -m elf_x86_64 -EXTRA_INC += $(TARGET_ARCH_FAM)/$(TARGET_ARCH) +EXTRA_INC += $(TARGET_ARCH_FAM)/$(XEN_TARGET_ARCH) EXTRA_SRC += arch/$(EXTRA_INC) endif diff --git a/extras/mini-os/arch/x86/minios-x86_32.lds b/extras/mini-os/arch/x86/minios-x86_32.lds index 08ebe14328..df5301944f 100644 --- a/extras/mini-os/arch/x86/minios-x86_32.lds +++ b/extras/mini-os/arch/x86/minios-x86_32.lds @@ -16,6 +16,18 @@ SECTIONS . = ALIGN(4096); _erodata = .; + /* newlib initialization functions */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : { /* Data */ *(.data) CONSTRUCTORS diff --git a/extras/mini-os/arch/x86/minios-x86_64.lds b/extras/mini-os/arch/x86/minios-x86_64.lds index 345c38640c..f93800236b 100644 --- a/extras/mini-os/arch/x86/minios-x86_64.lds +++ b/extras/mini-os/arch/x86/minios-x86_64.lds @@ -16,6 +16,18 @@ SECTIONS . = ALIGN(4096); _erodata = .; + /* newlib initialization functions */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : { /* Data */ *(.data) CONSTRUCTORS diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c index 082527d098..dd556e4741 100644 --- a/extras/mini-os/arch/x86/mm.c +++ b/extras/mini-os/arch/x86/mm.c @@ -448,6 +448,15 @@ static unsigned long demand_map_area_start; #define DEMAND_MAP_PAGES ((2ULL << 30) / PAGE_SIZE) #endif +#ifdef HAVE_LIBC +unsigned long heap, brk, heap_mapped, heap_end; +#ifdef __x86_64__ +#define HEAP_PAGES ((128ULL << 30) / PAGE_SIZE) +#else +#define HEAP_PAGES ((1ULL << 30) / PAGE_SIZE) +#endif +#endif + void arch_init_demand_mapping_area(unsigned long cur_pfn) { cur_pfn++; @@ -455,6 +464,14 @@ void arch_init_demand_mapping_area(unsigned long cur_pfn) demand_map_area_start = (unsigned long) pfn_to_virt(cur_pfn); cur_pfn += DEMAND_MAP_PAGES; printk("Demand map pfns at %lx-%lx.\n", demand_map_area_start, pfn_to_virt(cur_pfn)); + +#ifdef HAVE_LIBC + cur_pfn++; + heap_mapped = brk = heap = (unsigned long) pfn_to_virt(cur_pfn); + cur_pfn += HEAP_PAGES; + heap_end = (unsigned long) pfn_to_virt(cur_pfn); + printk("Heap resides at %lx-%lx.\n", brk, heap_end); +#endif } #define MAP_BATCH ((STACK_SIZE / 2) / sizeof(mmu_update_t)) diff --git a/extras/mini-os/arch/x86/x86_32.S b/extras/mini-os/arch/x86/x86_32.S index 4b9a337c08..7f01851f0c 100644 --- a/extras/mini-os/arch/x86/x86_32.S +++ b/extras/mini-os/arch/x86/x86_32.S @@ -1,5 +1,5 @@ #include <os.h> -#include <arch_mm.h> +#include <arch_limits.h> #include <xen/arch-x86_32.h> .section __xen_guest @@ -22,12 +22,12 @@ _start: cld lss stack_start,%esp - andl $(~(STACK_SIZE-1)), %esp + andl $(~(__STACK_SIZE-1)), %esp push %esi call start_kernel stack_start: - .long stack+(2*STACK_SIZE), __KERNEL_SS + .long stack+(2*__STACK_SIZE), __KERNEL_SS /* Unpleasant -- the PTE that maps this page is actually overwritten */ /* to map the real shared-info page! :-) */ diff --git a/extras/mini-os/arch/x86/x86_64.S b/extras/mini-os/arch/x86/x86_64.S index fae2ae4cf5..c7a797db90 100644 --- a/extras/mini-os/arch/x86/x86_64.S +++ b/extras/mini-os/arch/x86/x86_64.S @@ -1,5 +1,5 @@ #include <os.h> -#include <arch_mm.h> +#include <arch_limits.h> #include <xen/features.h> .section __xen_guest @@ -19,12 +19,12 @@ _start: cld movq stack_start(%rip),%rsp - andq $(~(STACK_SIZE-1)), %rsp + andq $(~(__STACK_SIZE-1)), %rsp movq %rsi,%rdi call start_kernel stack_start: - .quad stack+(2*STACK_SIZE) + .quad stack+(2*__STACK_SIZE) /* Unpleasant -- the PTE that maps this page is actually overwritten */ /* to map the real shared-info page! :-) */ diff --git a/extras/mini-os/blkfront.c b/extras/mini-os/blkfront.c index 881efd3055..3210396b7b 100644 --- a/extras/mini-os/blkfront.c +++ b/extras/mini-os/blkfront.c @@ -15,6 +15,10 @@ #include <lib.h> #include <fcntl.h> +#ifndef HAVE_LIBC +#define strtoul simple_strtoul +#endif + /* Note: we generally don't need to disable IRQs since we hardly do anything in * the interrupt handler. */ @@ -49,15 +53,20 @@ struct blkfront_dev { int mode; int barrier; int flush; -}; -static inline int xenblk_rxidx(RING_IDX idx) -{ - return idx & (BLK_RING_SIZE - 1); -} +#ifdef HAVE_LIBC + int fd; +#endif +}; void blkfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) { +#ifdef HAVE_LIBC + struct blkfront_dev *dev = data; + int fd = dev->fd; + + files[fd].read = 1; +#endif wake_up(&blkfront_queue); } @@ -148,7 +157,7 @@ done: printk("backend at %s\n", dev->backend); - dev->handle = simple_strtoul(strrchr(nodename, '/')+1, NULL, 0); + dev->handle = strtoul(strrchr(nodename, '/')+1, NULL, 0); { char path[strlen(dev->backend) + 1 + 19 + 1]; @@ -313,6 +322,11 @@ int blkfront_aio_poll(struct blkfront_dev *dev) struct blkif_response *rsp; moretodo: +#ifdef HAVE_LIBC + files[dev->fd].read = 0; + mb(); /* Make sure to let the handler set read to 1 before we start looking at the ring */ +#endif + rp = dev->ring.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ cons = dev->ring.rsp_cons; @@ -322,12 +336,16 @@ moretodo: { rsp = RING_GET_RESPONSE(&dev->ring, cons); + if (rsp->status != BLKIF_RSP_OKAY) + printk("block error %d for op %d\n", rsp->status, rsp->operation); + switch (rsp->operation) { case BLKIF_OP_READ: case BLKIF_OP_WRITE: { struct blkfront_aiocb *aiocbp = (void*) (uintptr_t) rsp->id; int j; + for (j = 0; j < aiocbp->n; j++) gnttab_end_access(aiocbp->gref[j]); @@ -365,6 +383,12 @@ static void blkfront_push_operation(struct blkfront_dev *dev, uint8_t op) i = dev->ring.req_prod_pvt; req = RING_GET_REQUEST(&dev->ring, i); req->operation = op; + req->nr_segments = 0; + req->handle = dev->handle; + /* Not used */ + req->id = 0; + /* Not needed anyway, but the backend will check it */ + req->sector_number = 0; dev->ring.req_prod_pvt = i + 1; wmb(); RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&dev->ring, notify); @@ -375,11 +399,13 @@ void blkfront_sync(struct blkfront_dev *dev) { unsigned long flags; - if (dev->barrier == 1) - blkfront_push_operation(dev, BLKIF_OP_WRITE_BARRIER); + if (dev->mode == O_RDWR) { + if (dev->barrier == 1) + blkfront_push_operation(dev, BLKIF_OP_WRITE_BARRIER); - if (dev->flush == 1) - blkfront_push_operation(dev, BLKIF_OP_FLUSH_DISKCACHE); + if (dev->flush == 1) + blkfront_push_operation(dev, BLKIF_OP_FLUSH_DISKCACHE); + } /* Note: This won't finish if another thread enqueues requests. */ local_irq_save(flags); @@ -397,3 +423,13 @@ void blkfront_sync(struct blkfront_dev *dev) remove_waiter(w); local_irq_restore(flags); } + +#ifdef HAVE_LIBC +int blkfront_open(struct blkfront_dev *dev) +{ + dev->fd = alloc_fd(FTYPE_BLK); + printk("blk_open(%s) -> %d\n", dev->nodename, dev->fd); + files[dev->fd].blk.dev = dev; + return dev->fd; +} +#endif diff --git a/extras/mini-os/include/arch/cc.h b/extras/mini-os/include/arch/cc.h index 70191f0b30..e9a258d8bf 100644 --- a/extras/mini-os/include/arch/cc.h +++ b/extras/mini-os/include/arch/cc.h @@ -54,7 +54,14 @@ extern void lwip_die(char *fmt, ...); #include <errno.h> /* Not required by the docs, but needed for network-order calculations */ +#ifdef HAVE_LIBC +#include <machine/endian.h> +#ifndef BIG_ENDIAN +#error endian.h does not define byte order +#endif +#else #include <endian.h> +#endif #include <inttypes.h> #define S16_F PRIi16 diff --git a/extras/mini-os/include/byteswap.h b/extras/mini-os/include/byteswap.h new file mode 100644 index 0000000000..7c4ffe393c --- /dev/null +++ b/extras/mini-os/include/byteswap.h @@ -0,0 +1,22 @@ +#ifndef _BYTESWAP_H_ +#define _BYTESWAP_H_ + +/* Unfortunately not provided by newlib. */ +#define bswap_16(x) \ + ((((x) & 0xff00) >> 8) | (((x) & 0xff) << 8)) + +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + ((((x) & 0xff00000000000000ULL) >> 56) | \ + (((x) & 0x00ff000000000000ULL) >> 40) | \ + (((x) & 0x0000ff0000000000ULL) >> 24) | \ + (((x) & 0x000000ff00000000ULL) >> 8) | \ + (((x) & 0x00000000ff000000ULL) << 8) | \ + (((x) & 0x0000000000ff0000ULL) << 24) | \ + (((x) & 0x000000000000ff00ULL) << 40) | \ + (((x) & 0x00000000000000ffULL) << 56)) + +#endif /* _BYTESWAP_H */ diff --git a/extras/mini-os/include/console.h b/extras/mini-os/include/console.h index 6ee04f1316..9ace8dfcb1 100644 --- a/extras/mini-os/include/console.h +++ b/extras/mini-os/include/console.h @@ -36,7 +36,9 @@ #ifndef _LIB_CONSOLE_H_ #define _LIB_CONSOLE_H_ +#include<os.h> #include<traps.h> +#include<stdarg.h> void print(int direct, const char *fmt, va_list args); void printk(const char *fmt, ...); @@ -48,5 +50,6 @@ void xencons_rx(char *buf, unsigned len, struct pt_regs *regs); void xencons_tx(void); void init_console(void); +void console_print(char *data, int length); #endif /* _LIB_CONSOLE_H_ */ diff --git a/extras/mini-os/include/errno.h b/extras/mini-os/include/errno.h index 262ab3e0b4..2829420dd7 100644 --- a/extras/mini-os/include/errno.h +++ b/extras/mini-os/include/errno.h @@ -107,4 +107,11 @@ #define EOWNERDEAD 130 /* Owner died */ #define ENOTRECOVERABLE 131 /* State not recoverable */ +#ifdef HAVE_LIBC +#include <sched.h> +extern int errno; +#define ERRNO +#define errno (get_current()->reent._errno) +#endif + #endif diff --git a/extras/mini-os/include/fcntl.h b/extras/mini-os/include/fcntl.h index 64020795ab..34a6484d35 100644 --- a/extras/mini-os/include/fcntl.h +++ b/extras/mini-os/include/fcntl.h @@ -86,4 +86,7 @@ struct flock64 { #define F_LINUX_SPECIFIC_BASE 1024 */ + +int open(const char *path, int flags, ...); +int fcntl(int fd, int cmd, ...); #endif diff --git a/extras/mini-os/include/fs.h b/extras/mini-os/include/fs.h index 1555a5adcc..4c822dfb20 100644 --- a/extras/mini-os/include/fs.h +++ b/extras/mini-os/include/fs.h @@ -22,6 +22,7 @@ struct fs_import struct semaphore reqs_sem; /* Accounts requests resource */ }; +extern struct fs_import *fs_import; void init_fs_frontend(void); diff --git a/extras/mini-os/include/ia64/arch_limits.h b/extras/mini-os/include/ia64/arch_limits.h new file mode 100644 index 0000000000..c7bb9b6573 --- /dev/null +++ b/extras/mini-os/include/ia64/arch_limits.h @@ -0,0 +1,12 @@ + +#ifndef __ARCH_LIMITS_H__ +#define __ARCH_LIMITS_H__ + +/* Commonly 16K pages are used. */ +#define __PAGE_SHIFT 14 /* 16K pages */ +#define __PAGE_SIZE (1<<(__PAGE_SHIFT)) + +#define __STACK_SIZE_PAGE_ORDER 2 +#define __STACK_SIZE (__PAGE_SIZE * (1 << __STACK_SIZE_PAGE_ORDER)) + +#endif /* __ARCH_LIMITS_H__ */ diff --git a/extras/mini-os/include/ia64/arch_mm.h b/extras/mini-os/include/ia64/arch_mm.h index 2a8e1c82a6..adc1da6d0f 100644 --- a/extras/mini-os/include/ia64/arch_mm.h +++ b/extras/mini-os/include/ia64/arch_mm.h @@ -35,11 +35,9 @@ #define virt_to_mfn(x) virt_to_pfn(x) #define virtual_to_mfn(x) (ia64_tpa((uint64_t)(x)) >> PAGE_SHIFT) -#define STACK_SIZE_PAGE_ORDER 1 -#define STACK_SIZE (PAGE_SIZE * (1 << STACK_SIZE_PAGE_ORDER)) - #define map_frames(f, n) map_frames_ex(f, n, 1, 0, 1, DOMID_SELF, 0, 0) /* TODO */ #define map_zero(n, a) map_frames_ex(NULL, n, 0, 0, a, DOMID_SELF, 0, 0) +#define do_map_zero(start, n) ((void)0) #endif /* __ARCH_MM_H__ */ diff --git a/extras/mini-os/include/ia64/page.h b/extras/mini-os/include/ia64/page.h index 714227f172..67be0a555d 100644 --- a/extras/mini-os/include/ia64/page.h +++ b/extras/mini-os/include/ia64/page.h @@ -43,9 +43,9 @@ /* The efi-pal page size for text and data. */ #define PAL_TR_PAGE_SIZE PTE_PS_1M -/* Commonly 16K pages are used. */ -#define PAGE_SHIFT 14 /* 16K pages */ -#define PAGE_SIZE (1<<(PAGE_SHIFT)) +#include "arch_limits.h" +#define PAGE_SHIFT __PAGE_SHIFT +#define PAGE_SIZE __PAGE_SIZE #define PAGE_MASK (~(PAGE_SIZE-1)) #define KSTACK_PAGES 4 /* 4 pages for the kernel stack + bsp */ diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h index efe096bdba..2ddb8d07c8 100644 --- a/extras/mini-os/include/lib.h +++ b/extras/mini-os/include/lib.h @@ -57,6 +57,8 @@ #include <stdarg.h> #include <stddef.h> +#include <xen/xen.h> +#include <xen/event_channel.h> #ifdef HAVE_LIBC #include <stdio.h> @@ -103,6 +105,8 @@ char *strdup(const char *s); int rand(void); +#include <xenbus.h> + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) struct kvec { @@ -126,4 +130,59 @@ do { \ /* Consistency check as much as possible. */ void sanity_check(void); +#ifdef HAVE_LIBC +enum fd_type { + FTYPE_NONE = 0, + FTYPE_CONSOLE, + FTYPE_FILE, + FTYPE_XENBUS, + FTYPE_EVTCHN, + FTYPE_SOCKET, + FTYPE_TAP, + FTYPE_BLK, +}; + +#define MAX_EVTCHN_PORTS 16 + +extern struct file { + enum fd_type type; + union { + struct { + /* lwIP fd */ + int fd; + } socket; + struct { + /* FS import fd */ + int fd; + off_t offset; + } file; + struct { + /* To each event channel FD is associated a series of ports which + * wakes select for this FD. */ + struct { + evtchn_port_t port; + volatile unsigned long pending; + int bound; + } ports[MAX_EVTCHN_PORTS]; + } evtchn; + struct { + struct netfront_dev *dev; + } tap; + struct { + struct blkfront_dev *dev; + } blk; + struct { + /* To each xenbus FD is associated a queue of watch events for this + * FD. */ + struct xenbus_event *volatile events; + } xenbus; + }; + volatile int read; /* maybe available for read */ +} files[]; + +int alloc_fd(enum fd_type type); +void close_all_files(void); +extern struct thread *main_thread; +#endif + #endif /* _LIB_H_ */ diff --git a/extras/mini-os/include/linux/types.h b/extras/mini-os/include/linux/types.h new file mode 100644 index 0000000000..f153ce8e42 --- /dev/null +++ b/extras/mini-os/include/linux/types.h @@ -0,0 +1,5 @@ +#ifndef _LINUX_TYPES_H_ +#define _LINUX_TYPES_H_ +#include <types.h> +typedef u64 __u64; +#endif /* _LINUX_TYPES_H_ */ diff --git a/extras/mini-os/include/mm.h b/extras/mini-os/include/mm.h index 4319fa2640..8396ec6b31 100644 --- a/extras/mini-os/include/mm.h +++ b/extras/mini-os/include/mm.h @@ -36,8 +36,13 @@ #endif #include <lib.h> + +#include <arch_limits.h> #include <arch_mm.h> +#define STACK_SIZE_PAGE_ORDER __STACK_SIZE_PAGE_ORDER +#define STACK_SIZE __STACK_SIZE + void init_mm(void); unsigned long alloc_pages(int order); @@ -61,5 +66,8 @@ void arch_init_p2m(unsigned long max_pfn_p); void *map_frames_ex(unsigned long *f, unsigned long n, unsigned long stride, unsigned long increment, unsigned long alignment, domid_t id, int may_fail, unsigned long prot); +#ifdef HAVE_LIBC +extern unsigned long heap, brk, heap_mapped, heap_end; +#endif #endif /* _MM_H_ */ diff --git a/extras/mini-os/include/netfront.h b/extras/mini-os/include/netfront.h index 5c8ec9c4fa..acfc91944b 100644 --- a/extras/mini-os/include/netfront.h +++ b/extras/mini-os/include/netfront.h @@ -6,6 +6,10 @@ struct netfront_dev; struct netfront_dev *init_netfront(char *nodename, void (*netif_rx)(unsigned char *data, int len), unsigned char rawmac[6]); void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len); void shutdown_netfront(struct netfront_dev *dev); +#ifdef HAVE_LIBC +int netfront_tap_open(char *nodename); +ssize_t netfront_receive(struct netfront_dev *dev, unsigned char *data, size_t len); +#endif extern struct wait_queue_head netfront_queue; diff --git a/extras/mini-os/include/posix/dirent.h b/extras/mini-os/include/posix/dirent.h new file mode 100644 index 0000000000..56b1d67258 --- /dev/null +++ b/extras/mini-os/include/posix/dirent.h @@ -0,0 +1,24 @@ +#ifndef _POSIX_DIRENT_H +#define _POSIX_DIRENT_H + +#include <sys/types.h> + +struct dirent { + char *d_name; +}; + +typedef struct { + struct dirent dirent; + char *name; + int32_t offset; + char **entries; + int32_t curentry; + int32_t nbentries; + int has_more; +} DIR; + +DIR *opendir(const char *name); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dir); + +#endif /* _POSIX_DIRENT_H */ diff --git a/extras/mini-os/include/posix/limits.h b/extras/mini-os/include/posix/limits.h new file mode 100644 index 0000000000..ba800e33d2 --- /dev/null +++ b/extras/mini-os/include/posix/limits.h @@ -0,0 +1,9 @@ +#ifndef _POSIX_LIMITS_H +#define _POSIX_LIMITS_H + +#include_next <limits.h> +#include <arch_limits.h> + +#define PATH_MAX __PAGE_SIZE + +#endif /* _POSIX_LIMITS_H */ diff --git a/extras/mini-os/include/posix/netdb.h b/extras/mini-os/include/posix/netdb.h new file mode 100644 index 0000000000..8f76a95b76 --- /dev/null +++ b/extras/mini-os/include/posix/netdb.h @@ -0,0 +1,9 @@ +#ifndef _POSIX_NETDB_H_ +#define _POSIX_NETDB_H_ + +struct hostent { + char *h_addr; +}; +#define gethostbyname(buf) NULL + +#endif /* _POSIX_NETDB_H_ */ diff --git a/extras/mini-os/include/posix/netinet/in.h b/extras/mini-os/include/posix/netinet/in.h new file mode 100644 index 0000000000..cc1a91076d --- /dev/null +++ b/extras/mini-os/include/posix/netinet/in.h @@ -0,0 +1,7 @@ +#ifndef _POSIX_SYS_IN_H_ +#define _POSIX_SYS_IN_H_ + +#include <fcntl.h> +#include <lwip/sockets.h> + +#endif /* _POSIX_SYS_IN_H_ */ diff --git a/extras/mini-os/include/posix/netinet/tcp.h b/extras/mini-os/include/posix/netinet/tcp.h new file mode 100644 index 0000000000..3e3b060467 --- /dev/null +++ b/extras/mini-os/include/posix/netinet/tcp.h @@ -0,0 +1,6 @@ +#ifndef _POSIX_SYS_TCP_H_ +#define _POSIX_SYS_TCP_H_ + +#include <lwip/tcp.h> + +#endif /* _POSIX_SYS_TCP_H_ */ diff --git a/extras/mini-os/include/posix/pthread.h b/extras/mini-os/include/posix/pthread.h new file mode 100644 index 0000000000..7e62001e3a --- /dev/null +++ b/extras/mini-os/include/posix/pthread.h @@ -0,0 +1,19 @@ +#ifndef _POSIX_PTHREAD_H +#define _POSIX_PTHREAD_H + +/* Let's be single-threaded for now. */ + +typedef void *pthread_key_t; +typedef struct {} pthread_mutex_t, pthread_once_t; +#define PTHREAD_MUTEX_INITIALIZER {} +#define PTHREAD_ONCE_INIT {} +static inline int pthread_mutex_lock(pthread_mutex_t *mutex) { return 0; } +static inline int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; } +static inline int pthread_key_create(pthread_key_t *key, void (*destr_function)(void*)) { *key = NULL; return 0; } +static inline int pthread_setspecific(pthread_key_t *key, const void *pointer) { *key = (void*) pointer; return 0; } +static inline void *pthread_getspecific(pthread_key_t *key) { return *key; } +static inline int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) { init_routine(); return 0; } + +#define __thread + +#endif /* _POSIX_PTHREAD_H */ diff --git a/extras/mini-os/include/posix/stdlib.h b/extras/mini-os/include/posix/stdlib.h new file mode 100644 index 0000000000..53e6289635 --- /dev/null +++ b/extras/mini-os/include/posix/stdlib.h @@ -0,0 +1,8 @@ +#ifndef _POSIX_STDLIB_H +#define _POSIX_STDLIB_H + +#include_next <stdlib.h> + +#define realpath(p,r) strcpy(r,p) + +#endif /* _POSIX_STDLIB_H */ diff --git a/extras/mini-os/include/posix/strings.h b/extras/mini-os/include/posix/strings.h new file mode 100644 index 0000000000..8619ba2865 --- /dev/null +++ b/extras/mini-os/include/posix/strings.h @@ -0,0 +1,8 @@ +#ifndef _POSIX_STRINGS_H +#define _POSIX_STRINGS_H + +#include <string.h> + +#define bzero(ptr, size) (memset((ptr), '\0', (size)), (void) 0) + +#endif /* _POSIX_STRINGS_H */ diff --git a/extras/mini-os/include/posix/sys/ioctl.h b/extras/mini-os/include/posix/sys/ioctl.h new file mode 100644 index 0000000000..ecf3080d5a --- /dev/null +++ b/extras/mini-os/include/posix/sys/ioctl.h @@ -0,0 +1,16 @@ +#ifndef _POSIX_SYS_IOCTL_H +#define _POSIX_SYS_IOCTL_H + +int ioctl(int fd, int request, ...); + +#define _IOC_NONE 0 +#define _IOC_WRITE 1 +#define _IOC_READ 2 + +#define _IOC(rw, class, n, size) \ + (((rw ) << 30) | \ + ((class) << 22) | \ + ((n ) << 14) | \ + ((size ) << 0)) + +#endif /* _POSIX_SYS_IOCTL_H */ diff --git a/extras/mini-os/include/posix/sys/mman.h b/extras/mini-os/include/posix/sys/mman.h new file mode 100644 index 0000000000..318d574877 --- /dev/null +++ b/extras/mini-os/include/posix/sys/mman.h @@ -0,0 +1,19 @@ +#ifndef _POSIX_SYS_MMAN_H +#define _POSIX_SYS_MMAN_H + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANON 0x20 + +#define MAP_FAILED ((void*)0) + +void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void *start, size_t length); +#define munlock(addr, len) ((void)addr, (void)len, 0) +#define mlock(addr, len) ((void)addr, (void)len, 0) + +#endif /* _POSIX_SYS_MMAN_H */ diff --git a/extras/mini-os/include/posix/sys/select.h b/extras/mini-os/include/posix/sys/select.h new file mode 100644 index 0000000000..5132c51224 --- /dev/null +++ b/extras/mini-os/include/posix/sys/select.h @@ -0,0 +1,7 @@ +#ifndef _POSIX_SELECT_H +#define _POSIX_SELECT_H + +#include <sys/time.h> +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + +#endif /* _POSIX_SELECT_H */ diff --git a/extras/mini-os/include/posix/sys/socket.h b/extras/mini-os/include/posix/sys/socket.h new file mode 100644 index 0000000000..7c039a2f03 --- /dev/null +++ b/extras/mini-os/include/posix/sys/socket.h @@ -0,0 +1,31 @@ +#ifndef _POSIX_SYS_SOCKET_H_ +#define _POSIX_SYS_SOCKET_H_ + +#include <fcntl.h> +#include <lwip/sockets.h> + +int accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int bind(int s, struct sockaddr *name, socklen_t namelen); +int shutdown(int s, int how); +int getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int close(int s); +int connect(int s, struct sockaddr *name, socklen_t namelen); +int listen(int s, int backlog); +int recv(int s, void *mem, int len, unsigned int flags); +//int read(int s, void *mem, int len); +int recvfrom(int s, void *mem, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen); +int send(int s, void *dataptr, int size, unsigned int flags); +int sendto(int s, void *dataptr, int size, unsigned int flags, + struct sockaddr *to, socklen_t tolen); +int socket(int domain, int type, int protocol); +//int write(int s, void *dataptr, int size); +int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, + struct timeval *timeout); +//int ioctl(int s, long cmd, void *argp); +int getsockname(int s, struct sockaddr *name, socklen_t *namelen); + +#endif /* _POSIX_SYS_SOCKET_H_ */ diff --git a/extras/mini-os/include/posix/termios.h b/extras/mini-os/include/posix/termios.h new file mode 100644 index 0000000000..a57aee4556 --- /dev/null +++ b/extras/mini-os/include/posix/termios.h @@ -0,0 +1,87 @@ +#ifndef _POSIX_TERMIOS_H +#define _POSIX_TERMIOS_H + +#define NCC 32 + +struct termios { + unsigned long c_iflag; + unsigned long c_oflag; + unsigned long c_lflag; + unsigned long c_cflag; + unsigned char c_cc[NCC]; +}; + +/* modem lines */ +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RI 0x080 +#define TIOCM_DSR 0x100 + +/* c_iflag */ +#define IGNBRK 0x00000001 +#define BRKINT 0x00000002 +#define IGNPAR 0x00000004 +#define PARMRK 0x00000008 +#define INPCK 0x00000010 +#define ISTRIP 0x00000020 +#define INLCR 0x00000040 +#define IGNCR 0x00000080 +#define ICRNL 0x00000100 +#define IUCLC 0x00000200 +#define IXON 0x00000400 +#define IXANY 0x00000800 +#define IXOFF 0x00001000 +#define IMAXBEL 0x00002000 +#define IUTF8 0x00004000 + +/* c_oflag */ +#define OPOST 0x00000001 +#define OLCUC 0x00000002 +#define ONLCR 0x00000004 +#define OCRNL 0x00000008 +#define ONOCR 0x00000010 +#define ONLRET 0x00000020 +#define OFILL 0x00000040 +#define OFDEL 0x00000080 + +/* c_lflag */ +#define ISIG 0x00000001 +#define ICANON 0x00000002 +#define XCASE 0x00000004 +#define ECHO 0x00000008 +#define ECHOE 0x00000010 +#define ECHOK 0x00000020 +#define ECHONL 0x00000040 +#define NOFLSH 0x00000080 +#define TOSTOP 0x00000100 +#define ECHOCTL 0x00000200 +#define ECHOPRT 0x00000400 +#define ECHOKE 0x00000800 +#define FLUSHO 0x00002000 +#define PENDIN 0x00004000 +#define IEXTEN 0x00008000 + +/* c_cflag */ +#define CSIZE 0x00000030 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 + +/* c_cc */ +#define VTIME 5 +#define VMIN 6 + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +int tcsetattr(int fildes, int action, const struct termios *tios); +int tcgetattr(int fildes, struct termios *tios); + +#endif /* _POSIX_TERMIOS_H */ diff --git a/extras/mini-os/include/posix/time.h b/extras/mini-os/include/posix/time.h new file mode 100644 index 0000000000..4f457cb5ad --- /dev/null +++ b/extras/mini-os/include/posix/time.h @@ -0,0 +1,10 @@ +#ifndef _POSIX_TIME_H +#define _POSIX_TIME_H + +#include <sys/time.h> +#define CLOCK_MONOTONIC 2 +#include_next <time.h> + +int nanosleep(const struct timespec *req, struct timespec *rem); + +#endif /* _POSIX_TIME_H */ diff --git a/extras/mini-os/include/posix/unistd.h b/extras/mini-os/include/posix/unistd.h new file mode 100644 index 0000000000..0cd9396ec9 --- /dev/null +++ b/extras/mini-os/include/posix/unistd.h @@ -0,0 +1,12 @@ +#ifndef _POSIX_UNISTD_H +#define _POSIX_UNISTD_H + +#include_next <unistd.h> +#include <sys/select.h> +#include <arch_limits.h> + +#define getpagesize() __PAGE_SIZE + +int ftruncate(int fd, off_t length); + +#endif /* _POSIX_UNISTD_H */ diff --git a/extras/mini-os/include/sched.h b/extras/mini-os/include/sched.h index a3d2022b8a..ba0d4e3df9 100644 --- a/extras/mini-os/include/sched.h +++ b/extras/mini-os/include/sched.h @@ -19,6 +19,9 @@ struct thread struct list_head thread_list; u32 flags; s_time_t wakeup_time; +#ifdef HAVE_LIBC + struct _reent reent; +#endif }; extern struct thread *idle_thread; diff --git a/extras/mini-os/include/sys/time.h b/extras/mini-os/include/sys/time.h index 87887c27d1..d6623a4e77 100644 --- a/extras/mini-os/include/sys/time.h +++ b/extras/mini-os/include/sys/time.h @@ -20,6 +20,9 @@ #ifndef _MINIOS_SYS_TIME_H_ #define _MINIOS_SYS_TIME_H_ +#ifdef HAVE_LIBC +#include_next <sys/time.h> +#else struct timespec { time_t tv_sec; long tv_nsec; @@ -34,5 +37,6 @@ struct timeval { }; int gettimeofday(struct timeval *tv, void *tz); +#endif #endif /* _MINIOS_SYS_TIME_H_ */ diff --git a/extras/mini-os/include/time.h b/extras/mini-os/include/time.h index 914f2fcff2..e28bf171d7 100644 --- a/extras/mini-os/include/time.h +++ b/extras/mini-os/include/time.h @@ -17,8 +17,9 @@ **************************************************************************** */ -#ifndef _TIME_H_ -#define _TIME_H_ +#ifndef _MINIOS_TIME_H_ +#define _MINIOS_TIME_H_ +#include <types.h> /* * System Time @@ -44,8 +45,12 @@ typedef s64 s_time_t; /* wall clock time */ typedef long time_t; typedef long suseconds_t; + #include <sys/time.h> +#ifdef HAVE_LIBC +#include_next <time.h> +#endif /* prototypes */ void init_time(void); @@ -54,4 +59,4 @@ s_time_t get_v_time(void); u64 monotonic_clock(void); void block_domain(s_time_t until); -#endif /* _TIME_H_ */ +#endif /* _MINIOS_TIME_H_ */ diff --git a/extras/mini-os/include/x86/arch_limits.h b/extras/mini-os/include/x86/arch_limits.h new file mode 100644 index 0000000000..7f0351c67f --- /dev/null +++ b/extras/mini-os/include/x86/arch_limits.h @@ -0,0 +1,20 @@ + +#ifndef __ARCH_LIMITS_H__ +#define __ARCH_LIMITS_H__ + +#define __PAGE_SHIFT 12 + +#ifdef __ASSEMBLY__ +#define __PAGE_SIZE (1 << __PAGE_SHIFT) +#else +#ifndef CONFIG_X86_PAE +#define __PAGE_SIZE (1UL << __PAGE_SHIFT) +#else +#define __PAGE_SIZE (1ULL << __PAGE_SHIFT) +#endif +#endif + +#define __STACK_SIZE_PAGE_ORDER 4 +#define __STACK_SIZE (__PAGE_SIZE * (1 << __STACK_SIZE_PAGE_ORDER)) + +#endif /* __ARCH_LIMITS_H__ */ diff --git a/extras/mini-os/include/x86/arch_mm.h b/extras/mini-os/include/x86/arch_mm.h index c5e106e6da..7ad8bc14be 100644 --- a/extras/mini-os/include/x86/arch_mm.h +++ b/extras/mini-os/include/x86/arch_mm.h @@ -157,16 +157,9 @@ typedef unsigned long pgentry_t; #define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) #endif /* __i386__ || __x86_64__ */ -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << L1_PAGETABLE_SHIFT) -#else -#ifndef CONFIG_X86_PAE -#define PAGE_SIZE (1UL << L1_PAGETABLE_SHIFT) -#else -#define PAGE_SIZE (1ULL << L1_PAGETABLE_SHIFT) -#endif -#endif -#define PAGE_SHIFT L1_PAGETABLE_SHIFT +#include "arch_limits.h" +#define PAGE_SIZE __PAGE_SIZE +#define PAGE_SHIFT __PAGE_SHIFT #define PAGE_MASK (~(PAGE_SIZE-1)) #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT) @@ -177,9 +170,6 @@ typedef unsigned long pgentry_t; /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -#define STACK_SIZE_PAGE_ORDER 1 -#define STACK_SIZE (PAGE_SIZE * (1 << STACK_SIZE_PAGE_ORDER)) - #ifndef __ASSEMBLY__ /* Definitions for machine and pseudophysical addresses. */ #ifdef CONFIG_X86_PAE @@ -257,5 +247,11 @@ static __inline__ paddr_t machine_to_phys(maddr_t machine) #define map_frames(f, n) map_frames_ex(f, n, 1, 0, 1, DOMID_SELF, 0, L1_PROT) #define map_zero(n, a) map_frames_ex(&mfn_zero, n, 0, 0, a, DOMID_SELF, 0, L1_PROT_RO) +#ifndef __ASSEMBLY__ +void do_map_frames(unsigned long addr, + unsigned long *f, unsigned long n, unsigned long stride, + unsigned long increment, domid_t id, int may_fail, unsigned long prot); +#endif +#define do_map_zero(start, n) do_map_frames(start, &mfn_zero, n, 0, 0, DOMID_SELF, 0, L1_PROT_RO) #endif /* _ARCH_MM_H_ */ diff --git a/extras/mini-os/include/x86/arch_sched.h b/extras/mini-os/include/x86/arch_sched.h index 877440762e..d80323cd37 100644 --- a/extras/mini-os/include/x86/arch_sched.h +++ b/extras/mini-os/include/x86/arch_sched.h @@ -2,7 +2,7 @@ #ifndef __ARCH_SCHED_H__ #define __ARCH_SCHED_H__ -#include <arch_mm.h> +#include <arch_limits.h> static inline struct thread* get_current(void) { @@ -12,7 +12,7 @@ static inline struct thread* get_current(void) #else register unsigned long sp asm("rsp"); #endif - current = (void *)(unsigned long)(sp & ~(STACK_SIZE-1)); + current = (void *)(unsigned long)(sp & ~(__STACK_SIZE-1)); return *current; } diff --git a/extras/mini-os/include/x86/arch_spinlock.h b/extras/mini-os/include/x86/arch_spinlock.h index a181ed3c92..b711fe473c 100644 --- a/extras/mini-os/include/x86/arch_spinlock.h +++ b/extras/mini-os/include/x86/arch_spinlock.h @@ -4,6 +4,7 @@ #define __ARCH_ASM_SPINLOCK_H #include <lib.h> +#include "os.h" #define ARCH_SPIN_LOCK_UNLOCKED (spinlock_t) { 1 } diff --git a/extras/mini-os/include/x86/os.h b/extras/mini-os/include/x86/os.h index 7a4433b3f9..7217d0b3ca 100644 --- a/extras/mini-os/include/x86/os.h +++ b/extras/mini-os/include/x86/os.h @@ -563,6 +563,7 @@ static __inline__ int synch_var_test_bit(int nr, volatile void * addr) synch_var_test_bit((nr),(addr))) +#undef ADDR #endif /* not assembly */ #endif /* _OS_H_ */ diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c new file mode 100644 index 0000000000..f71e6966bd --- /dev/null +++ b/extras/mini-os/lib/sys.c @@ -0,0 +1,1083 @@ +/* + * POSIX-compatible libc layer + * + * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, October 2007 + * + * Provides the UNIXish part of the standard libc function. + * + * Relatively straight-forward: just multiplex the file descriptor operations + * among the various file types (console, FS, network, ...) + */ + +//#define LIBC_VERBOSE +//#define LIBC_DEBUG + +#ifdef LIBC_DEBUG +#define DEBUG(fmt,...) printk(fmt, ##__VA_ARGS__) +#else +#define DEBUG(fmt,...) +#endif + +#ifdef HAVE_LIBC +#include <os.h> +#include <console.h> +#include <sched.h> +#include <events.h> +#include <wait.h> +#include <netfront.h> +#include <blkfront.h> +#include <xenbus.h> +#include <xs.h> + +#include <sys/types.h> +#include <sys/unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <assert.h> +#include <dirent.h> +#include <stdlib.h> +#include <math.h> + +#include <lwip/sockets.h> +#include <fs.h> + +#define debug(fmt, ...) \ + +#define print_unsupported(fmt, ...) \ + printk("Unsupported function "fmt" called in Mini-OS kernel\n", ## __VA_ARGS__); + +/* Crash on function call */ +#define unsupported_function_crash(function) \ + int __unsup_##function(void) asm(#function); \ + int __unsup_##function(void) \ + { \ + print_unsupported(#function); \ + do_exit(); \ + } + +/* Log and err out on function call */ +#define unsupported_function_log(type, function, ret) \ + type __unsup_##function(void) asm(#function); \ + type __unsup_##function(void) \ + { \ + print_unsupported(#function); \ + errno = ENOSYS; \ + return ret; \ + } + +/* Err out on function call */ +#define unsupported_function(type, function, ret) \ + type __unsup_##function(void) asm(#function); \ + type __unsup_##function(void) \ + { \ + errno = ENOSYS; \ + return ret; \ + } + +#define NOFILE 32 +extern int xc_evtchn_close(int fd); + +pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER; +struct file files[NOFILE] = { + { .type = FTYPE_CONSOLE }, /* stdin */ + { .type = FTYPE_CONSOLE }, /* stdout */ + { .type = FTYPE_CONSOLE }, /* stderr */ +}; + +DECLARE_WAIT_QUEUE_HEAD(event_queue); + +int alloc_fd(enum fd_type type) +{ + int i; + pthread_mutex_lock(&fd_lock); + for (i=0; i<NOFILE; i++) { + if (files[i].type == FTYPE_NONE) { + files[i].type = type; + pthread_mutex_unlock(&fd_lock); + return i; + } + } + pthread_mutex_unlock(&fd_lock); + printk("Too many opened files\n"); + do_exit(); +} + +void close_all_files(void) +{ + int i; + pthread_mutex_lock(&fd_lock); + for (i=NOFILE - 1; i > 0; i--) + if (files[i].type != FTYPE_NONE) + close(i); + pthread_mutex_unlock(&fd_lock); +} + +int dup2(int oldfd, int newfd) +{ + pthread_mutex_lock(&fd_lock); + if (files[newfd].type != FTYPE_NONE) + close(newfd); + // XXX: this is a bit bogus, as we are supposed to share the offset etc + files[newfd] = files[oldfd]; + pthread_mutex_unlock(&fd_lock); + return 0; +} + +pid_t getpid(void) +{ + return 1; +} + +pid_t getppid(void) +{ + return 1; +} + +pid_t setsid(void) +{ + return 1; +} + +char *getcwd(char *buf, size_t size) +{ + snprintf(buf, size, "/"); + return buf; +} + +#define LOG_PATH "/var/log/" + +int mkdir(const char *pathname, mode_t mode) +{ + int ret; + ret = fs_create(fs_import, (char *) pathname, 1, mode); + if (ret < 0) { + errno = EIO; + return -1; + } + return 0; +} + +int open(const char *pathname, int flags, ...) +{ + int fs_fd, fd; + /* Ugly, but fine. */ + if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) { + fd = alloc_fd(FTYPE_CONSOLE); + printk("open(%s) -> %d\n", pathname, fd); + return fd; + } + printk("open(%s)", pathname); + fs_fd = fs_open(fs_import, (void *) pathname); + if (fs_fd < 0) { + errno = EIO; + return -1; + } + fd = alloc_fd(FTYPE_FILE); + printk("-> %d\n", fd); + files[fd].file.fd = fs_fd; + files[fd].file.offset = 0; + return fd; +} +#if defined(__x86_64__) || defined(__ia64__) +__typeof__(open) open64 __attribute__((__alias__("open"))); +#endif + +int isatty(int fd) +{ + return files[fd].type == FTYPE_CONSOLE; +} + +int read(int fd, void *buf, size_t nbytes) +{ + switch (files[fd].type) { + case FTYPE_CONSOLE: + return 0; + case FTYPE_FILE: { + ssize_t ret; + if (nbytes > PAGE_SIZE) + nbytes = PAGE_SIZE; + ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset); + if (ret > 0) { + files[fd].file.offset += ret; + return ret; + } else if (ret < 0) { + errno = EIO; + return -1; + } + return 0; + } + case FTYPE_SOCKET: + return lwip_read(files[fd].socket.fd, buf, nbytes); + case FTYPE_TAP: { + ssize_t ret; + ret = netfront_receive(files[fd].tap.dev, buf, nbytes); + if (ret <= 0) { + errno = EAGAIN; + return -1; + } + return ret; + } + case FTYPE_NONE: + case FTYPE_XENBUS: + case FTYPE_EVTCHN: + case FTYPE_BLK: + break; + } + printk("read(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +int write(int fd, const void *buf, size_t nbytes) +{ + switch (files[fd].type) { + case FTYPE_CONSOLE: + console_print((char *)buf, nbytes); + return nbytes; + case FTYPE_FILE: { + ssize_t ret; + if (nbytes > PAGE_SIZE) + nbytes = PAGE_SIZE; + ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset); + if (ret > 0) { + files[fd].file.offset += ret; + return ret; + } else if (ret < 0) { + errno = EIO; + return -1; + } + return 0; + } + case FTYPE_SOCKET: + return lwip_write(files[fd].socket.fd, (void*) buf, nbytes); + case FTYPE_TAP: + netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes); + return nbytes; + case FTYPE_NONE: + case FTYPE_XENBUS: + case FTYPE_EVTCHN: + case FTYPE_BLK: + break; + } + printk("write(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +off_t lseek(int fd, off_t offset, int whence) +{ + if (files[fd].type != FTYPE_FILE) { + errno = ESPIPE; + return (off_t) -1; + } + switch (whence) { + case SEEK_SET: + files[fd].file.offset = offset; + break; + case SEEK_CUR: + files[fd].file.offset += offset; + break; + case SEEK_END: { + struct stat st; + int ret; + ret = fstat(fd, &st); + if (ret) + return -1; + files[fd].file.offset = st.st_size + offset; + break; + } + default: + errno = EINVAL; + return -1; + } + return files[fd].file.offset; +} +#if defined(__x86_64__) || defined(__ia64__) +__typeof__(lseek) lseek64 __attribute__((__alias__("lseek"))); +#endif + +int fsync(int fd) { + switch (files[fd].type) { + case FTYPE_FILE: { + int ret; + ret = fs_sync(fs_import, files[fd].file.fd); + if (ret < 0) { + errno = EIO; + return -1; + } + return 0; + } + case FTYPE_NONE: + case FTYPE_CONSOLE: + case FTYPE_SOCKET: + case FTYPE_XENBUS: + case FTYPE_EVTCHN: + case FTYPE_TAP: + case FTYPE_BLK: + break; + } + printk("fsync(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +int close(int fd) +{ + printk("close(%d)\n", fd); + switch (files[fd].type) { + case FTYPE_CONSOLE: + files[fd].type = FTYPE_NONE; + return 0; + case FTYPE_FILE: { + int ret = fs_close(fs_import, files[fd].file.fd); + files[fd].type = FTYPE_NONE; + if (ret < 0) { + errno = EIO; + return -1; + } + return 0; + } + case FTYPE_XENBUS: + xs_daemon_close((void*)(intptr_t) fd); + return 0; + case FTYPE_SOCKET: { + int res = lwip_close(files[fd].socket.fd); + files[fd].type = FTYPE_NONE; + return res; + } + case FTYPE_EVTCHN: + xc_evtchn_close(fd); + return 0; + case FTYPE_TAP: + shutdown_netfront(files[fd].tap.dev); + files[fd].type = FTYPE_NONE; + return 0; + case FTYPE_BLK: + shutdown_blkfront(files[fd].blk.dev); + files[fd].type = FTYPE_NONE; + return 0; + case FTYPE_NONE: + break; + } + printk("close(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +static void init_stat(struct stat *buf) +{ + memset(buf, 0, sizeof(*buf)); + buf->st_dev = 0; + buf->st_ino = 0; + buf->st_nlink = 1; + buf->st_rdev = 0; + buf->st_blksize = 4096; + buf->st_blocks = 0; +} + +static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat) +{ + buf->st_mode = stat->stat_mode; + buf->st_uid = stat->stat_uid; + buf->st_gid = stat->stat_gid; + buf->st_size = stat->stat_size; + buf->st_atime = stat->stat_atime; + buf->st_mtime = stat->stat_mtime; + buf->st_ctime = stat->stat_ctime; +} + +int stat(const char *path, struct stat *buf) +{ + struct fsif_stat_response stat; + int ret; + int fs_fd; + printk("stat(%s)\n", path); + fs_fd = fs_open(fs_import, (char*) path); + if (fs_fd < 0) { + errno = EIO; + ret = -1; + goto out; + } + ret = fs_stat(fs_import, fs_fd, &stat); + if (ret < 0) { + errno = EIO; + ret = -1; + goto outfd; + } + init_stat(buf); + stat_from_fs(buf, &stat); + ret = 0; + +outfd: + fs_close(fs_import, fs_fd); +out: + return ret; +} + +int fstat(int fd, struct stat *buf) +{ + init_stat(buf); + switch (files[fd].type) { + case FTYPE_CONSOLE: + case FTYPE_SOCKET: { + buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = 0; + buf->st_atime = + buf->st_mtime = + buf->st_ctime = time(NULL); + return 0; + } + case FTYPE_FILE: { + struct fsif_stat_response stat; + int ret; + ret = fs_stat(fs_import, files[fd].file.fd, &stat); + if (ret < 0) { + errno = EIO; + return -1; + } + /* The protocol is a bit evasive about this value */ + stat_from_fs(buf, &stat); + return 0; + } + case FTYPE_NONE: + case FTYPE_XENBUS: + case FTYPE_EVTCHN: + case FTYPE_TAP: + case FTYPE_BLK: + break; + } + + printk("statf(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +int ftruncate(int fd, off_t length) +{ + switch (files[fd].type) { + case FTYPE_FILE: { + int ret; + ret = fs_truncate(fs_import, files[fd].file.fd, length); + if (ret < 0) { + errno = EIO; + return -1; + } + return 0; + } + case FTYPE_NONE: + case FTYPE_CONSOLE: + case FTYPE_SOCKET: + case FTYPE_XENBUS: + case FTYPE_EVTCHN: + case FTYPE_TAP: + case FTYPE_BLK: + break; + } + + printk("ftruncate(%d): Bad descriptor\n", fd); + errno = EBADF; + return -1; +} + +int remove(const char *pathname) +{ + int ret; + printk("remove(%s)", pathname); + ret = fs_remove(fs_import, (char*) pathname); + if (ret < 0) { + errno = EIO; + return -1; + } + return 0; +} + +int unlink(const char *pathname) +{ + return remove(pathname); +} + +int rmdir(const char *pathname) +{ + return remove(pathname); +} + +int fcntl(int fd, int cmd, ...) +{ + long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + switch (cmd) { + case F_SETFL: + if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) { + /* Only flag supported: non-blocking mode */ + uint32_t nblock = !!(arg & O_NONBLOCK); + return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock); + } + /* Fallthrough */ + default: + printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg); + errno = ENOSYS; + return -1; + } +} + +DIR *opendir(const char *name) +{ + DIR *ret; + ret = malloc(sizeof(*ret)); + ret->name = strdup(name); + ret->offset = 0; + ret->entries = NULL; + ret->curentry = -1; + ret->nbentries = 0; + ret->has_more = 1; + return ret; +} + +struct dirent *readdir(DIR *dir) +{ + if (dir->curentry >= 0) { + free(dir->entries[dir->curentry]); + dir->entries[dir->curentry] = NULL; + } + dir->curentry++; + if (dir->curentry >= dir->nbentries) { + dir->offset += dir->nbentries; + free(dir->entries); + dir->curentry = -1; + dir->nbentries = 0; + if (!dir->has_more) + return NULL; + dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more); + if (!dir->entries || !dir->nbentries) + return NULL; + dir->curentry = 0; + } + dir->dirent.d_name = dir->entries[dir->curentry]; + return &dir->dirent; +} +int closedir(DIR *dir) +{ + int i; + for (i=0; i<dir->nbentries; i++) + free(dir->entries[i]); + free(dir->entries); + free(dir->name); + free(dir); + return 0; +} + +/* We assume that only the main thread calls select(). */ + +static const char file_types[] = { + [FTYPE_NONE] = 'N', + [FTYPE_CONSOLE] = 'C', + [FTYPE_FILE] = 'F', + [FTYPE_XENBUS] = 'X', + [FTYPE_EVTCHN] = 'E', + [FTYPE_SOCKET] = 'S', + [FTYPE_TAP] = 'T', + [FTYPE_BLK] = 'B', +}; +#ifdef LIBC_DEBUG +static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + int i, comma; +#define printfds(set) do {\ + comma = 0; \ + for (i = 0; i < nfds; i++) { \ + if (FD_ISSET(i, set)) { \ + if (comma) \ + printk(", "); \ + printk("%d(%c)", i, file_types[files[i].type]); \ + comma = 1; \ + } \ + } \ +} while (0) + + printk("["); + if (readfds) + printfds(readfds); + printk("], ["); + if (writefds) + printfds(writefds); + printk("], ["); + if (exceptfds) + printfds(exceptfds); + printk("], "); + if (timeout) + printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec); +} +#else +#define dump_set(nfds, readfds, writefds, exceptfds, timeout) +#endif + +/* Just poll without blocking */ +static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) +{ + int i, n = 0, sock_n, sock_nfds = 0; + fd_set sock_readfds, sock_writefds, sock_exceptfds; + struct timeval timeout = { .tv_sec = 0, .tv_usec = 0}; + +#ifdef LIBC_VERBOSE + static int nb; + static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE]; + static s64_t lastshown; + + nb++; +#endif + + /* first poll network */ + FD_ZERO(&sock_readfds); + FD_ZERO(&sock_writefds); + FD_ZERO(&sock_exceptfds); + for (i = 0; i < nfds; i++) { + if (files[i].type == FTYPE_SOCKET) { + if (FD_ISSET(i, readfds)) { + FD_SET(files[i].socket.fd, &sock_readfds); + sock_nfds = i+1; + } + if (FD_ISSET(i, writefds)) { + FD_SET(files[i].socket.fd, &sock_writefds); + sock_nfds = i+1; + } + if (FD_ISSET(i, exceptfds)) { + FD_SET(files[i].socket.fd, &sock_exceptfds); + sock_nfds = i+1; + } + } + } + DEBUG("lwip_select("); + dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); + DEBUG("); -> "); + sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); + dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); + DEBUG("\n"); + + /* Then see others as well. */ + for (i = 0; i < nfds; i++) { + switch(files[i].type) { + case FTYPE_NONE: + if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) + printk("bogus fd %d in select\n", i); + /* Fallthrough. */ + case FTYPE_FILE: + FD_CLR(i, readfds); + FD_CLR(i, writefds); + FD_CLR(i, exceptfds); + break; + case FTYPE_CONSOLE: + FD_CLR(i, readfds); + if (FD_ISSET(i, writefds)) + n++; + FD_CLR(i, exceptfds); + break; + case FTYPE_XENBUS: + if (FD_ISSET(i, readfds)) { + if (files[i].xenbus.events) + n++; + else + FD_CLR(i, readfds); + } + FD_CLR(i, writefds); + FD_CLR(i, exceptfds); + break; + case FTYPE_EVTCHN: + case FTYPE_TAP: + case FTYPE_BLK: + if (FD_ISSET(i, readfds)) { + if (files[i].read) + n++; + else + FD_CLR(i, readfds); + } + FD_CLR(i, writefds); + FD_CLR(i, exceptfds); + break; + case FTYPE_SOCKET: + if (FD_ISSET(i, readfds)) { + /* Optimize no-network-packet case. */ + if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds)) + n++; + else + FD_CLR(i, readfds); + } + if (FD_ISSET(i, writefds)) { + if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds)) + n++; + else + FD_CLR(i, writefds); + } + if (FD_ISSET(i, exceptfds)) { + if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds)) + n++; + else + FD_CLR(i, exceptfds); + } + break; + } +#ifdef LIBC_VERBOSE + if (FD_ISSET(i, readfds)) + nbread[i]++; + if (FD_ISSET(i, writefds)) + nbwrite[i]++; + if (FD_ISSET(i, exceptfds)) + nbexcept[i]++; +#endif + } +#ifdef LIBC_VERBOSE + if (NOW() > lastshown + 1000000000ull) { + lastshown = NOW(); + printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE)); + printk("%d(%d): ", nb, sock_n); + for (i = 0; i < nfds; i++) { + if (nbread[i] || nbwrite[i] || nbexcept[i]) + printk(" %d(%c):", i, file_types[files[i].type]); + if (nbread[i]) + printk(" %dR", nbread[i]); + if (nbwrite[i]) + printk(" %dW", nbwrite[i]); + if (nbexcept[i]) + printk(" %dE", nbexcept[i]); + } + printk("\n"); + memset(nbread, 0, sizeof(nbread)); + memset(nbwrite, 0, sizeof(nbwrite)); + memset(nbexcept, 0, sizeof(nbexcept)); + nb = 0; + } +#endif + return n; +} + +/* The strategy is to + * - announce that we will maybe sleep + * - poll a bit ; if successful, return + * - if timeout, return + * - really sleep (except if somebody woke us in the meanwhile) */ +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + int n, ret; + fd_set myread, mywrite, myexcept; + struct thread *thread = get_current(); + s_time_t start = NOW(), stop; + DEFINE_WAIT(w1); + DEFINE_WAIT(w2); + DEFINE_WAIT(w3); + DEFINE_WAIT(w4); + + assert(thread == main_thread); + + DEBUG("select(%d, ", nfds); + dump_set(nfds, readfds, writefds, exceptfds, timeout); + DEBUG(");\n"); + + if (timeout) + stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000; + else + /* just make gcc happy */ + stop = start; + + /* Tell people we're going to sleep before looking at what they are + * saying, hence letting them wake us if events happen between here and + * schedule() */ + add_waiter(w1, netfront_queue); + add_waiter(w2, event_queue); + add_waiter(w3, blkfront_queue); + add_waiter(w4, xenbus_watch_queue); + + myread = *readfds; + mywrite = *writefds; + myexcept = *exceptfds; + DEBUG("polling "); + dump_set(nfds, &myread, &mywrite, &myexcept, timeout); + DEBUG("\n"); + n = select_poll(nfds, &myread, &mywrite, &myexcept); + + if (n) { + dump_set(nfds, readfds, writefds, exceptfds, timeout); + if (readfds) + *readfds = myread; + if (writefds) + *writefds = mywrite; + if (exceptfds) + *exceptfds = myexcept; + DEBUG(" -> "); + dump_set(nfds, readfds, writefds, exceptfds, timeout); + DEBUG("\n"); + wake(thread); + ret = n; + goto out; + } + if (timeout && NOW() >= stop) { + if (readfds) + FD_ZERO(readfds); + if (writefds) + FD_ZERO(writefds); + if (exceptfds) + FD_ZERO(exceptfds); + timeout->tv_sec = 0; + timeout->tv_usec = 0; + wake(thread); + ret = 0; + goto out; + } + + if (timeout) + thread->wakeup_time = stop; + schedule(); + + myread = *readfds; + mywrite = *writefds; + myexcept = *exceptfds; + n = select_poll(nfds, &myread, &mywrite, &myexcept); + + if (n) { + if (readfds) + *readfds = myread; + if (writefds) + *writefds = mywrite; + if (exceptfds) + *exceptfds = myexcept; + ret = n; + goto out; + } + errno = EINTR; + ret = -1; + +out: + remove_waiter(w1); + remove_waiter(w2); + remove_waiter(w3); + remove_waiter(w4); + return ret; +} + +int socket(int domain, int type, int protocol) +{ + int fd, res; + fd = lwip_socket(domain, type, protocol); + if (fd < 0) + return -1; + res = alloc_fd(FTYPE_SOCKET); + printk("socket -> %d\n", res); + files[res].socket.fd = fd; + return res; +} + +int accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int fd, res; + if (files[s].type != FTYPE_SOCKET) { + printk("accept(%d): Bad descriptor\n", s); + errno = EBADF; + return -1; + } + fd = lwip_accept(files[s].socket.fd, addr, addrlen); + if (fd < 0) + return -1; + res = alloc_fd(FTYPE_SOCKET); + files[res].socket.fd = fd; + printk("accepted on %d -> %d\n", s, res); + return res; +} + +#define LWIP_STUB(ret, name, proto, args) \ +ret name proto \ +{ \ + if (files[s].type != FTYPE_SOCKET) { \ + printk(#name "(%d): Bad descriptor\n", s); \ + errno = EBADF; \ + return -1; \ + } \ + s = files[s].socket.fd; \ + return lwip_##name args; \ +} + +LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen)) +LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen)) +LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen)) +LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen)) +LWIP_STUB(int, listen, (int s, int backlog), (s, backlog)); +LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags)) +LWIP_STUB(ssize_t, recvfrom, (int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen), (s, buf, len, flags, from, fromlen)) +LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags)) +LWIP_STUB(ssize_t, sendto, (int s, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen), (s, buf, len, flags, to, tolen)) +LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen)) + +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + s_time_t start = NOW(); + s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec; + s_time_t stopped; + struct thread *thread = get_current(); + + thread->wakeup_time = stop; + clear_runnable(thread); + schedule(); + stopped = NOW(); + + if (rem) + { + s_time_t remaining = stop - stopped; + if (remaining > 0) + { + rem->tv_nsec = remaining % 1000000000ULL; + rem->tv_sec = remaining / 1000000000ULL; + } else memset(rem, 0, sizeof(*rem)); + } + + return 0; +} + +int usleep(useconds_t usec) +{ + /* "usec shall be less than one million." */ + struct timespec req; + req.tv_nsec = usec * 1000; + req.tv_sec = 0; + + if (nanosleep(&req, NULL)) + return -1; + + return 0; +} + +unsigned int sleep(unsigned int seconds) +{ + struct timespec req, rem; + req.tv_sec = seconds; + req.tv_nsec = 0; + + if (nanosleep(&req, &rem)) + return -1; + + if (rem.tv_nsec > 0) + rem.tv_sec++; + + return rem.tv_sec; +} + +int clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + switch (clk_id) { + case CLOCK_MONOTONIC: + { + struct timeval tv; + + gettimeofday(&tv, NULL); + + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + + break; + } + case CLOCK_REALTIME: + { + u64 nsec = monotonic_clock(); + + tp->tv_sec = nsec / 1000000000ULL; + tp->tv_nsec = nsec % 1000000000ULL; + + break; + } + default: + print_unsupported("clock_gettime(%d)", clk_id); + errno = EINVAL; + return -1; + } + + return 0; +} + +void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + ASSERT(!start); + length = (length + PAGE_SIZE - 1) & PAGE_MASK; + ASSERT(prot == (PROT_READ|PROT_WRITE)); + ASSERT(flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON)); + ASSERT(fd == -1); + ASSERT(offset == 0); + + return map_zero(length / PAGE_SIZE, 1); +} +#if defined(__x86_64__) || defined(__ia64__) +__typeof__(mmap) mmap64 __attribute__((__alias__("mmap"))); +#endif + +int munmap(void *start, size_t length) +{ + int i, n = length / PAGE_SIZE; + multicall_entry_t call[n]; + unsigned char (*data)[PAGE_SIZE] = start; + int ret; + ASSERT(!((unsigned long)start & ~PAGE_MASK)); + ASSERT(!(length & ~PAGE_MASK)); + + for (i = 0; i < n; i++) { + call[i].op = __HYPERVISOR_update_va_mapping; + call[i].args[0] = (unsigned long) &data[i]; + call[i].args[1] = 0; + call[i].args[2] = 0; + call[i].args[3] = UVMF_INVLPG | UVMF_ALL; + } + + ret = HYPERVISOR_multicall(call, n); + if (ret) { + errno = -ret; + return -1; + } + + for (i = 0; i < n; i++) { + if (call[i].result) { + errno = call[i].result; + return -1; + } + } + return 0; +} + +/* Not supported by FS yet. */ +unsupported_function_crash(link); +unsupported_function(int, readlink, -1); + +/* We could support that. */ +unsupported_function_log(int, chdir, -1); + +/* No dynamic library support. */ +unsupported_function_log(void *, dlopen, NULL); +unsupported_function_log(void *, dlsym, NULL); +unsupported_function_log(char *, dlerror, NULL); +unsupported_function_log(int, dlclose, -1); + +/* We don't raise signals anyway. */ +unsupported_function(int, sigemptyset, -1); +unsupported_function(int, sigfillset, -1); +unsupported_function(int, sigaddset, -1); +unsupported_function(int, sigdelset, -1); +unsupported_function(int, sigismember, -1); +unsupported_function(int, sigprocmask, -1); +unsupported_function(int, sigaction, -1); +unsupported_function(int, __sigsetjmp, 0); +unsupported_function(int, sigaltstack, -1); +unsupported_function_crash(kill); + +/* Linuxish abi for the Caml runtime, don't support */ +unsupported_function_log(struct dirent *, readdir64, NULL); +unsupported_function_log(int, getrusage, -1); +unsupported_function_log(int, getrlimit, -1); +unsupported_function_log(int, getrlimit64, -1); +unsupported_function_log(int, __xstat64, -1); +unsupported_function_log(long, __strtol_internal, LONG_MIN); +unsupported_function_log(double, __strtod_internal, HUGE_VAL); +#endif diff --git a/extras/mini-os/lib/xmalloc.c b/extras/mini-os/lib/xmalloc.c index 9e59c9f834..d4c3941738 100644 --- a/extras/mini-os/lib/xmalloc.c +++ b/extras/mini-os/lib/xmalloc.c @@ -62,10 +62,19 @@ struct xmalloc_pad size_t hdr_size; }; +/* Return size, increased to alignment with align. */ +static inline size_t align_up(size_t size, size_t align) +{ + return (size + align - 1) & ~(align - 1); +} + static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block) { struct xmalloc_hdr *extra; - size_t leftover = block - size; + size_t leftover; + size = align_up(size, __alignof__(struct xmalloc_hdr)); + size = align_up(size, __alignof__(struct xmalloc_pad)); + leftover = block - size; /* If enough is left to make a block, put it on free list. */ if ( leftover >= (2 * (sizeof(struct xmalloc_hdr) + sizeof(struct xmalloc_pad))) ) @@ -100,12 +109,6 @@ static struct xmalloc_hdr *xmalloc_new_page(size_t size) return hdr; } -/* Return size, increased to alignment with align. */ -static inline size_t align_up(size_t size, size_t align) -{ - return (size + align - 1) & ~(align - 1); -} - /* Big object? Just use the page allocator. */ static void *xmalloc_whole_pages(size_t size, size_t align) { diff --git a/extras/mini-os/lib/xs.c b/extras/mini-os/lib/xs.c new file mode 100644 index 0000000000..b654b0ee5d --- /dev/null +++ b/extras/mini-os/lib/xs.c @@ -0,0 +1,187 @@ +/* + * libxs-compatible layer + * + * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, 2007-2008 + * + * Mere wrapper around xenbus_* + */ + +#ifdef HAVE_LIBC +#include <os.h> +#include <lib.h> +#include <xs.h> +#include <xenbus.h> +#include <stdlib.h> +#include <unistd.h> + +static inline int _xs_fileno(struct xs_handle *h) { + return (intptr_t) h; +} + +struct xs_handle *xs_daemon_open() +{ + int fd = alloc_fd(FTYPE_XENBUS); + files[fd].xenbus.events = NULL; + printk("xs_daemon_open -> %d, %p\n", fd, &files[fd].xenbus.events); + return (void*)(intptr_t) fd; +} + +void xs_daemon_close(struct xs_handle *h) +{ + int fd = _xs_fileno(h); + struct xenbus_event *event; + for (event = files[fd].xenbus.events; event; event = event->next) + free(event); + files[fd].type = FTYPE_NONE; +} + +int xs_fileno(struct xs_handle *h) +{ + return _xs_fileno(h); +} + +void *xs_read(struct xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *len) +{ + char *value; + char *msg; + + msg = xenbus_read(t, path, &value); + if (msg) { + printk("xs_read(%s): %s\n", path, msg); + return NULL; + } + + if (len) + *len = strlen(value); + return value; +} + +bool xs_write(struct xs_handle *h, xs_transaction_t t, + const char *path, const void *data, unsigned int len) +{ + char value[len + 1]; + char *msg; + + memcpy(value, data, len); + value[len] = 0; + + msg = xenbus_write(t, path, value); + if (msg) { + printk("xs_write(%s): %s\n", path, msg); + return false; + } + return true; +} + +static bool xs_bool(char *reply) +{ + if (!reply) + return true; + free(reply); + return false; +} + +bool xs_rm(struct xs_handle *h, xs_transaction_t t, const char *path) +{ + return xs_bool(xenbus_rm(t, path)); +} + +static void *xs_talkv(struct xs_handle *h, xs_transaction_t t, + enum xsd_sockmsg_type type, + struct write_req *iovec, + unsigned int num_vecs, + unsigned int *len) +{ + struct xsd_sockmsg *msg; + void *ret; + + msg = xenbus_msg_reply(type, t, iovec, num_vecs); + ret = malloc(msg->len); + memcpy(ret, (char*) msg + sizeof(*msg), msg->len); + if (len) + *len = msg->len - 1; + free(msg); + return ret; +} + +static void *xs_single(struct xs_handle *h, xs_transaction_t t, + enum xsd_sockmsg_type type, + const char *string, + unsigned int *len) +{ + struct write_req iovec; + + iovec.data = (void *)string; + iovec.len = strlen(string) + 1; + + return xs_talkv(h, t, type, &iovec, 1, len); +} + +char *xs_get_domain_path(struct xs_handle *h, unsigned int domid) +{ + char domid_str[MAX_STRLEN(domid)]; + + sprintf(domid_str, "%u", domid); + + return xs_single(h, XBT_NULL, XS_GET_DOMAIN_PATH, domid_str, NULL); +} + +char **xs_directory(struct xs_handle *h, xs_transaction_t t, + const char *path, unsigned int *num) +{ + char *msg; + char **entries, **res; + char *entry; + int i, n; + int size; + + msg = xenbus_ls(t, path, &res); + if (msg) { + printk("xs_directory(%s): %s\n", path, msg); + return NULL; + } + + size = 0; + for (n = 0; res[n]; n++) + size += strlen(res[n]) + 1; + + entries = malloc(n * sizeof(char *) + size); + entry = (char *) (&entries[n]); + + for (i = 0; i < n; i++) { + int l = strlen(res[i]) + 1; + memcpy(entry, res[i], l); + free(res[i]); + entries[i] = entry; + entry += l; + } + + *num = n; + return entries; +} + +bool xs_watch(struct xs_handle *h, const char *path, const char *token) +{ + int fd = _xs_fileno(h); + printk("xs_watch(%s, %s)\n", path, token); + return xs_bool(xenbus_watch_path_token(XBT_NULL, path, token, &files[fd].xenbus.events)); +} + +char **xs_read_watch(struct xs_handle *h, unsigned int *num) +{ + int fd = _xs_fileno(h); + struct xenbus_event *event; + event = files[fd].xenbus.events; + files[fd].xenbus.events = event->next; + printk("xs_read_watch() -> %s %s\n", event->path, event->token); + *num = 2; + return (char **) &event->path; +} + +bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) +{ + printk("xs_unwatch(%s, %s)\n", path, token); + return xs_bool(xenbus_unwatch_path_token(XBT_NULL, path, token)); +} +#endif diff --git a/extras/mini-os/main-caml.c b/extras/mini-os/main-caml.c new file mode 100644 index 0000000000..dd55aca38f --- /dev/null +++ b/extras/mini-os/main-caml.c @@ -0,0 +1,42 @@ +/* + * Caml bootstrap + * + * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, January 2008 + */ + +#include <stdio.h> +#include <errno.h> + +#include <caml/mlvalues.h> +#include <caml/callback.h> +#include <unistd.h> + +/* Ugly binary compatibility with Linux */ +FILE *_stderr asm("stderr"); +int *__errno_location; +/* Will probably break everything, probably need to fetch from glibc */ +void *__ctype_b_loc; + +int main(int argc, char *argv[], char *envp[]) +{ + value *val; + + /* Get current thread's value */ + _stderr = stderr; + __errno_location = &errno; + + printf("starting caml\n"); + + /* Wait before things might hang up */ + sleep(1); + + caml_startup(argv); + val = caml_named_value("main"); + if (!val) { + printf("Couldn't find Caml main"); + return 1; + } + caml_callback(*val, Val_int(0)); + printf("callback returned\n"); + return 0; +} diff --git a/extras/mini-os/main.c b/extras/mini-os/main.c new file mode 100644 index 0000000000..345f7e9487 --- /dev/null +++ b/extras/mini-os/main.c @@ -0,0 +1,167 @@ +/* + * POSIX-compatible main layer + * + * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, October 2007 + */ + +#ifdef HAVE_LIBC +#include <os.h> +#include <sched.h> +#include <console.h> +#include <netfront.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> +#include <fs.h> +#include <xenbus.h> +#include <events.h> + +extern int main(int argc, char *argv[], char *envp[]); +extern void __libc_init_array(void); +extern void __libc_fini_array(void); + +struct thread *main_thread; + +#if 0 +#include <stdio.h> +int main(int argc, char *argv[], char *envp[]) +{ + printf("Hello, World!\n"); + return 1; +} +#endif + +void _init(void) +{ +} + +void _fini(void) +{ +} + +static void call_main(void *p) +{ + char *args, /**path,*/ *msg, *c; + int argc; + char **argv; + char *envp[] = { NULL }; + char *vm; + int i; + char path[128]; + + /* Let other parts initialize (including console output) before maybe + * crashing. */ + //sleep(1); + + start_networking(); + init_fs_frontend(); + +#ifdef CONFIG_QEMU + if (!fs_import) { + printk("No FS backend found, is it running?\n"); + do_exit(); + } + + /* Fetch argc, argv from XenStore */ + char domid_s[10]; + int domid; + domid = xenbus_read_integer("target"); + if (domid == -1) { + printk("Couldn't read target\n"); + do_exit(); + } + snprintf(domid_s, sizeof(domid_s), "%d", domid); + + snprintf(path, sizeof(path), "/local/domain/%d/vm", domid); + msg = xenbus_read(XBT_NIL, path, &vm); + if (msg) { + printk("Couldn't read vm path\n"); + do_exit(); + } + printk("vm is at %s\n", vm); +#else + msg = xenbus_read(XBT_NIL, "vm", &vm); + if (msg) { + printk("Couldn't read vm path\n"); + do_exit(); + } +#endif + + snprintf(path, sizeof(path), "%s/image/dmargs", vm); + free(vm); + msg = xenbus_read(XBT_NIL, path, &args); + + if (msg) { + printk("Couldn't get stubdom args: %s\n", msg); + args = strdup(""); + } + + argc = 1; +#ifdef CONFIG_QEMU + argc += 2; +#endif + c = args; + while (*c) { + if (*c != ' ') { + argc++; + while (*c && *c != ' ') + c++; + } else { + while (*c == ' ') + c++; + } + } + argv = alloca((argc + 1) * sizeof(char *)); + argv[0] = "main"; + argc = 1; +#ifdef CONFIG_QEMU + argv[1] = "-d"; + argv[2] = domid_s; + argc += 2; +#endif + c = args; + while (*c) { + if (*c != ' ') { + argv[argc++] = c; + while (*c && *c != ' ') + c++; + } else { + *c++ = 0; + while (*c == ' ') + c++; + } + } + argv[argc] = NULL; + + for (i = 0; i < argc; i++) + printf("\"%s\" ", argv[i]); + printf("\n"); + + __libc_init_array(); + environ = envp; + tzset(); + + exit(main(argc, argv, envp)); +} + +void _exit(int ret) +{ + close_all_files(); + __libc_fini_array(); + printk("main returned %d\n", ret); + unbind_all_ports(); + if (!ret) { + /* No problem, just shutdown. */ + struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff }; + HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); + } + do_exit(); +} + +int app_main(start_info_t *si) +{ + printk("Dummy main: start_info=%p\n", si); + main_thread = create_thread("main", call_main, si); + return 0; +} +#endif diff --git a/extras/mini-os/minios.mk b/extras/mini-os/minios.mk index fa6f6bd0c9..078c396fc2 100644 --- a/extras/mini-os/minios.mk +++ b/extras/mini-os/minios.mk @@ -9,7 +9,7 @@ debug = y DEF_CFLAGS += -fno-builtin -Wall -Werror -Wredundant-decls -Wno-format DEF_CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) DEF_CFLAGS += -Wstrict-prototypes -Wnested-externs -Wpointer-arith -Winline -DEF_CFLAGS += -D__XEN_INTERFACE_VERSION__=$(XEN_INTERFACE_VERSION) +DEF_CPPFLAGS += -D__XEN_INTERFACE_VERSION__=$(XEN_INTERFACE_VERSION) DEF_ASFLAGS = -D__ASSEMBLY__ DEF_LDFLAGS = @@ -24,12 +24,10 @@ endif # DEF_... flags are the common mini-os flags, # ARCH_... flags may be defined in arch/$(TARGET_ARCH_FAM/rules.mk CFLAGS := $(DEF_CFLAGS) $(ARCH_CFLAGS) +CPPFLAGS := $(DEF_CPPFLAGS) $(ARCH_CPPFLAGS) ASFLAGS := $(DEF_ASFLAGS) $(ARCH_ASFLAGS) LDFLAGS := $(DEF_LDFLAGS) $(ARCH_LDFLAGS) -# The path pointing to the architecture specific header files. -ARCH_INC := $(MINI-OS_ROOT)/include/$(TARGET_ARCH_FAM) - # Special build dependencies. # Rebuild all after touching this/these file(s) EXTRA_DEPS = $(MINI-OS_ROOT)/minios.mk \ @@ -44,18 +42,17 @@ extra_heads := $(foreach dir,$(EXTRA_INC),$(wildcard $(dir)/*.h)) HDRS += $(extra_heads) # Add the special header directories to the include paths. -extra_incl := $(foreach dir,$(EXTRA_INC),-I$(MINI-OS_ROOT)/include/$(dir)) -override CPPFLAGS := -I$(MINI-OS_ROOT)/include $(CPPFLAGS) -I$(ARCH_INC) $(extra_incl) +override CPPFLAGS := $(CPPFLAGS) $(extra_incl) # The name of the architecture specific library. # This is on x86_32: libx86_32.a # $(ARCH_LIB) has to built in the architecture specific directory. -ARCH_LIB_NAME = $(TARGET_ARCH) +ARCH_LIB_NAME = $(XEN_TARGET_ARCH) ARCH_LIB := lib$(ARCH_LIB_NAME).a # This object contains the entrypoint for startup from Xen. # $(HEAD_ARCH_OBJ) has to be built in the architecture specific directory. -HEAD_ARCH_OBJ := $(TARGET_ARCH).o +HEAD_ARCH_OBJ := $(XEN_TARGET_ARCH).o HEAD_OBJ := $(TARGET_ARCH_DIR)/$(HEAD_ARCH_OBJ) diff --git a/extras/mini-os/mm.c b/extras/mini-os/mm.c index 11e249d421..f204fa66ec 100644 --- a/extras/mini-os/mm.c +++ b/extras/mini-os/mm.c @@ -360,6 +360,29 @@ void free_pages(void *pointer, int order) } +#ifdef HAVE_LIBC +void *sbrk(ptrdiff_t increment) +{ + unsigned long old_brk = brk; + unsigned long new_brk = old_brk + increment; + + if (new_brk > heap_end) { + printk("Heap exhausted: %p + %lx = %p > %p\n", old_brk, increment, new_brk, heap_end); + return NULL; + } + + if (new_brk > heap_mapped) { + unsigned long n = (new_brk - heap_mapped + PAGE_SIZE - 1) / PAGE_SIZE; + do_map_zero(heap_mapped, n); + heap_mapped += n * PAGE_SIZE; + } + + brk = new_brk; + + return (void *) old_brk; +} +#endif + void init_mm(void) diff --git a/extras/mini-os/netfront.c b/extras/mini-os/netfront.c index e3c56c10c4..095f55ca15 100644 --- a/extras/mini-os/netfront.c +++ b/extras/mini-os/netfront.c @@ -19,7 +19,10 @@ DECLARE_WAIT_QUEUE_HEAD(netfront_queue); +#ifdef HAVE_LIBC #define NETIF_SELECT_RX ((void*)-1) +#endif + #define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE) @@ -50,6 +53,13 @@ struct netfront_dev { char *nodename; char *backend; +#ifdef HAVE_LIBC + int fd; + unsigned char *data; + size_t len; + size_t rlen; +#endif + void (*netif_rx)(unsigned char* data, int len); }; @@ -92,7 +102,8 @@ moretodo: cons = dev->rx.rsp_cons; int nr_consumed=0; - while ((cons != rp)) + int some = 0; + while ((cons != rp) && !some) { struct net_buffer* buf; unsigned char* page; @@ -116,7 +127,18 @@ moretodo: if(rx->status>0) { - dev->netif_rx(page+rx->offset,rx->status); +#ifdef HAVE_LIBC + if (dev->netif_rx == NETIF_SELECT_RX) { + int len = rx->status; + ASSERT(current == main_thread); + if (len > dev->len) + len = dev->len; + memcpy(dev->data, page+rx->offset, len); + dev->rlen = len; + some = 1; + } else +#endif + dev->netif_rx(page+rx->offset,rx->status); } nr_consumed++; @@ -127,7 +149,7 @@ moretodo: int more; RING_FINAL_CHECK_FOR_RESPONSES(&dev->rx,more); - if(more) goto moretodo; + if(more && !some) goto moretodo; RING_IDX req_prod = dev->rx.req_prod_pvt; @@ -178,6 +200,9 @@ void network_tx_buf_gc(struct netfront_dev *dev) if (txrsp->status == NETIF_RSP_NULL) continue; + if (txrsp->status == NETIF_RSP_ERROR) + printk("packet error\n"); + id = txrsp->id; struct net_buffer* buf = &dev->tx_buffers[id]; gnttab_end_access(buf->gref); @@ -218,6 +243,22 @@ void netfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) local_irq_restore(flags); } +#ifdef HAVE_LIBC +void netfront_select_handler(evtchn_port_t port, struct pt_regs *regs, void *data) +{ + int flags; + struct netfront_dev *dev = data; + int fd = dev->fd; + + local_irq_save(flags); + network_tx_buf_gc(dev); + local_irq_restore(flags); + + files[fd].read = 1; + wake_up(&netfront_queue); +} +#endif + struct netfront_dev *init_netfront(char *nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6]) { xenbus_transaction_t xbt; @@ -266,7 +307,12 @@ struct netfront_dev *init_netfront(char *nodename, void (*thenetif_rx)(unsigned dev->dom = op.remote_dom = xenbus_read_integer(path); HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op); clear_evtchn(op.port); /* Without, handler gets invoked now! */ - dev->local_port = bind_evtchn(op.port, netfront_handler, dev); +#ifdef HAVE_LIBC + if (thenetif_rx == NETIF_SELECT_RX) + dev->local_port = bind_evtchn(op.port, netfront_select_handler, dev); + else +#endif + dev->local_port = bind_evtchn(op.port, netfront_handler, dev); dev->evtchn=op.port; txs = (struct netif_tx_sring*) alloc_page(); @@ -381,6 +427,23 @@ done: return dev; } +#ifdef HAVE_LIBC +int netfront_tap_open(char *nodename) { + struct netfront_dev *dev; + + dev = init_netfront(nodename, NETIF_SELECT_RX, NULL); + if (!dev) { + printk("TAP open failed\n"); + errno = EIO; + return -1; + } + dev->fd = alloc_fd(FTYPE_TAP); + printk("tap_open(%s) -> %d\n", nodename, dev->fd); + files[dev->fd].tap.dev = dev; + return dev->fd; +} +#endif + void shutdown_netfront(struct netfront_dev *dev) { char* err; @@ -481,3 +544,30 @@ void netfront_xmit(struct netfront_dev *dev, unsigned char* data,int len) network_tx_buf_gc(dev); local_irq_restore(flags); } + +#ifdef HAVE_LIBC +ssize_t netfront_receive(struct netfront_dev *dev, unsigned char *data, size_t len) +{ + unsigned long flags; + int fd = dev->fd; + ASSERT(current == main_thread); + + dev->rlen = 0; + dev->data = data; + dev->len = len; + + local_irq_save(flags); + network_rx(dev); + if (!dev->rlen) + /* No data for us, make select stop returning */ + files[fd].read = 0; + /* Before re-enabling the interrupts, in case a packet just arrived in the + * meanwhile. */ + local_irq_restore(flags); + + dev->data = NULL; + dev->len = 0; + + return dev->rlen; +} +#endif diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c index 18b3f01538..19a102f056 100644 --- a/extras/mini-os/sched.c +++ b/extras/mini-os/sched.c @@ -56,6 +56,7 @@ struct thread *idle_thread = NULL; LIST_HEAD(exited_threads); +static int threads_started; void inline print_runqueue(void) { @@ -172,6 +173,9 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data) /* Not runable, not exited, not sleeping */ thread->flags = 0; thread->wakeup_time = 0LL; +#ifdef HAVE_LIBC + _REENT_INIT_PTR((&thread->reent)) +#endif set_runnable(thread); local_irq_save(flags); if(idle_thread != NULL) { @@ -185,6 +189,42 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data) return thread; } +#ifdef HAVE_LIBC +static struct _reent callback_reent; +struct _reent *__getreent(void) +{ + struct _reent *_reent; + + if (!threads_started) + _reent = _impure_ptr; + else if (in_callback) + _reent = &callback_reent; + else + _reent = &get_current()->reent; + +#ifndef NDEBUG +#if defined(__x86_64__) || defined(__x86__) + { +#ifdef __x86_64__ + register unsigned long sp asm ("rsp"); +#else + register unsigned long sp asm ("esp"); +#endif + if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) { + static int overflowing; + if (!overflowing) { + overflowing = 1; + printk("stack overflow\n"); + BUG(); + } + } + } +#endif +#endif + return _reent; +} +#endif + void exit_thread(void) { unsigned long flags; @@ -228,6 +268,7 @@ void wake(struct thread *thread) void idle_thread_fn(void *unused) { s_time_t until; + threads_started = 1; unsigned long flags; struct list_head *iterator; struct thread *next, *thread; @@ -297,6 +338,9 @@ void init_sched(void) { printk("Initialising scheduler\n"); +#ifdef HAVE_LIBC + _REENT_INIT_PTR((&callback_reent)) +#endif idle_thread = create_thread("Idle", idle_thread_fn, NULL); INIT_LIST_HEAD(&idle_thread->thread_list); } diff --git a/stubdom/Makefile b/stubdom/Makefile new file mode 100644 index 0000000000..7fdcdb22c0 --- /dev/null +++ b/stubdom/Makefile @@ -0,0 +1,259 @@ +XEN_ROOT = .. + +export XEN_OS=MiniOS + +include $(XEN_ROOT)/Config.mk +export stubdom=y +export debug=y + +IOEMU_OPTIONS=--disable-vnc-tls +BINUTILS_VERSION=2.18 +GCC_VERSION=4.2.2 +ZLIB_VERSION=1.2.3 +LIBPCI_VERSION=2.2.9 +NEWLIB_DATE=2008-01-01 +LWIP_DATE=2008-02-08 + +WGET=wget -c + +GNU_TARGET_ARCH:=$(XEN_TARGET_ARCH) +ifeq ($(XEN_TARGET_ARCH),x86_32) +GNU_TARGET_ARCH:=i686 +endif + +ifeq ($(GNU_TARGET_ARCH), i686) +TARGET_CFLAGS= +endif +ifeq ($(GNU_TARGET_ARCH), x86_64) +TARGET_CFLAGS=-mno-red-zone +endif +ifeq ($(GNU_TARGET_ARCH), ia64) +TARGET_CFLAGS=-mconstant-gp +endif + +CROSS_ROOT=cross-root-$(GNU_TARGET_ARCH) +CROSS_PREFIX=$(CURDIR)/$(CROSS_ROOT) +export CROSS_COMPILE=$(GNU_TARGET_ARCH)-xen-elf- +export PATH:=$(CROSS_PREFIX)/bin:$(PATH) + +.PHONY: all +all: qemu-stubdom + +################ +# Cross-binutils +################ + +binutils-$(BINUTILS_VERSION).tar.bz2: + $(WGET) http://ftp.gnu.org/gnu/binutils/$@ +binutils-$(BINUTILS_VERSION): binutils-$(BINUTILS_VERSION).tar.bz2 + tar xjf $@.tar.bz2 + ( cd binutils-$(BINUTILS_VERSION) && patch -p1 < ../binutils.patch ) + touch $@ + +BINUTILS_STAMPFILE=$(CROSS_ROOT)/bin/$(GNU_TARGET_ARCH)-xen-elf-ar +.PHONY: cross-binutils +cross-binutils: $(BINUTILS_STAMPFILE) +$(BINUTILS_STAMPFILE): binutils-$(BINUTILS_VERSION) + mkdir -p binutils-build + ( cd binutils-build && \ + ../binutils-$(BINUTILS_VERSION)/configure --prefix=$(CROSS_PREFIX) --verbose --target=$(GNU_TARGET_ARCH)-xen-elf && \ + $(MAKE) && \ + $(MAKE) check && \ + $(MAKE) install ) + +########### +# Cross-gcc +########### + +gcc-$(GCC_VERSION).tar.bz2: + $(WGET) http://ftp.gnu.org/gnu/gcc/gcc-$(GCC_VERSION)/gcc-$(GCC_VERSION).tar.bz2 +gcc-$(GCC_VERSION): gcc-$(GCC_VERSION).tar.bz2 + tar xjf gcc-$(GCC_VERSION).tar.bz2 + ( cd gcc-$(GCC_VERSION) && patch -p1 < ../gcc.patch ) + touch $@ + +GCC_STAMPFILE=$(CROSS_ROOT)/bin/$(GNU_TARGET_ARCH)-xen-elf-gcc-$(GCC_VERSION) +.PHONY: cross-gcc +cross-gcc: $(GCC_STAMPFILE) +$(GCC_STAMPFILE): gcc-$(GCC_VERSION) $(BINUTILS_STAMPFILE) + mkdir -p gcc-build + ( cd gcc-build && \ + ../gcc-$(GCC_VERSION)/configure --prefix=$(CROSS_PREFIX) --verbose --target=$(GNU_TARGET_ARCH)-xen-elf --enable-languages=c --disable-libssp --with-gnu-as --with-gnu-ld && \ + $(MAKE) GCC_FOR_TARGET='$$$$r/gcc/xgcc -B$$$$r/gcc/ '"$(TARGET_CFLAGS)"' $$(FLAGS_FOR_TARGET)' && \ + $(MAKE) install ) + +############## +# Cross-newlib +############## + +newlib-cvs: + cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/src co -D $(NEWLIB_DATE) newlib + mv src newlib-cvs + ( cd newlib-cvs && patch -p0 < ../newlib.patch) + +NEWLIB_STAMPFILE=$(CROSS_ROOT)/$(GNU_TARGET_ARCH)-xen-elf/lib/libc.a +.PHONY: cross-newlib +cross-newlib: $(NEWLIB_STAMPFILE) +$(NEWLIB_STAMPFILE): newlib-cvs $(GCC_STAMPFILE) + mkdir -p newlib-build + ( cd newlib-build && \ + CC_FOR_TARGET="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS)" ../newlib-cvs/configure --prefix=$(CROSS_PREFIX) --verbose --target=$(GNU_TARGET_ARCH)-xen-elf --enable-newlib-io-long-long && \ + $(MAKE) && \ + $(MAKE) install ) + +############ +# Cross-zlib +############ + +zlib-$(ZLIB_VERSION).tar.gz: + $(WGET) http://www.zlib.net/zlib-$(ZLIB_VERSION).tar.gz + +ZLIB_STAMPFILE=$(CROSS_ROOT)/$(GNU_TARGET_ARCH)-xen-elf/lib/libz.a +.PHONY: cross-zlib +cross-zlib: $(ZLIB_STAMPFILE) +$(ZLIB_STAMPFILE): zlib-$(ZLIB_VERSION).tar.gz $(NEWLIB_STAMPFILE) + tar xzf $< + ( cd zlib-$(ZLIB_VERSION) && \ + CFLAGS="$(TARGET_CFLAGS)" CC=$(GNU_TARGET_ARCH)-xen-elf-gcc ./configure --prefix=$(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf && \ + $(MAKE) libz.a && \ + $(MAKE) install ) + +############## +# Cross-libpci +############## + +pciutils-$(LIBPCI_VERSION).tar.bz2: + $(WGET) http://www.kernel.org/pub/software/utils/pciutils/pciutils-$(LIBPCI_VERSION).tar.bz2 + +LIBPCI_STAMPFILE=$(CROSS_ROOT)/$(GNU_TARGET_ARCH)-xen-elf/lib/libpci.a +.PHONY: cross-libpci +cross-libpci: $(LIBPCI_STAMPFILE) +$(LIBPCI_STAMPFILE): pciutils-$(LIBPCI_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) $(ZLIB_STAMPFILE) + tar xjf $< + ( cd pciutils-$(LIBPCI_VERSION) && \ + cp ../libpci.config.h lib/config.h && \ + echo '#define PCILIB_VERSION "$(LIBPCI_VERSION)"' >> lib/config.h && \ + cp ../libpci.config.mak lib/config.mk && \ + $(MAKE) CC="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS)" lib/libpci.a && \ + $(INSTALL_DATA) lib/libpci.a $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/lib/ && \ + $(INSTALL_DIR) $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci && \ + $(INSTALL_DATA) lib/{config,header,pci,types}.h $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci/ \ + ) + +###### +# lwIP +###### + +lwip-cvs: + cvs -z 9 -d :pserver:anonymous@cvs.savannah.nongnu.org:/sources/lwip co -D $(LWIP_DATE) lwip + mv lwip lwip-cvs + +####### +# Links +####### + +.PHONY: $(CROSS_ROOT) +$(CROSS_ROOT): cross-newlib cross-zlib cross-libpci + +.PHONY: mk-symlinks +mk-symlinks: + [ -h include ] || ln -sf ../tools/include . + mkdir -p libxc + [ -h libxc/Makefile ] || ( cd libxc && \ + ln -sf ../../tools/libxc/*.h . && \ + ln -sf ../../tools/libxc/*.c . && \ + ln -sf ../../tools/libxc/Makefile . ) + mkdir -p libxc/$(XEN_TARGET_ARCH) + [ -h libxc/$(XEN_TARGET_ARCH) ] || ( cd libxc/$(XEN_TARGET_ARCH) && \ + ln -sf ../../tools/libxc/$(XEN_TARGET_ARCH)/*.c . && \ + ln -sf ../../tools/libxc/$(XEN_TARGET_ARCH)/*.h . && \ + ln -sf ../../tools/libxc/$(XEN_TARGET_ARCH)/Makefile . ) + mkdir -p ioemu + [ -h ioemu/Makefile ] || ( cd ioemu && \ + ln -sf ../../tools/ioemu/* . && \ + ([ ! -h config-host.h ] || rm -f config-host.h) && \ + ([ ! -h config-host.mak ] || rm -f config-host.mak) ) + [ -h mini-os ] || ln -sf ../extras/mini-os . + +####### +# libxc +####### + +.PHONY: libxc +libxc: cross-zlib mk-symlinks + $(MAKE) -C $@ + +####### +# ioemu +####### + +.PHONY: ioemu +ioemu: cross-zlib cross-libpci mk-symlinks libxc + [ -f ioemu/config-host.mak ] || \ + ( cd ioemu ; XEN_TARGET_ARCH=$(XEN_TARGET_ARCH) sh configure --prefix=/usr --enable-stubdom $(IOEMU_OPTIONS)) + $(MAKE) -C ioemu LWIPDIR=$(CURDIR)/lwip-cvs + +###### +# caml +###### + +.PHONY: caml +caml: + $(MAKE) -C $@ + +######## +# minios +######## + +.PHONY: qemu-stubdom +qemu-stubdom: mk-symlinks lwip-cvs libxc ioemu + $(MAKE) -C mini-os LWIPDIR=$(CURDIR)/lwip-cvs QEMUDIR=$(CURDIR)/ioemu + +.PHONY: caml-stubdom +caml-stubdom: mk-symlinks lwip-cvs libxc cross-libpci caml + $(MAKE) -C mini-os LWIPDIR=$(CURDIR)/lwia-cvs CAMLDIR=$(CURDIR)/caml + +######### +# install +######### + +install: mini-os/mini-os.gz + $(INSTALL_PROG) stubdom-dm "$(DESTDIR)/usr/lib/xen/bin" + $(INSTALL_PROG) mini-os/mini-os.gz "$(DESTDIR)/usr/lib/xen/boot/stubdom.gz" + +####### +# clean +####### + +# Only clean the libxc/ioemu/mini-os part +.PHONY: clean +clean: + -$(MAKE) -C mini-os LWIPDIR=$(CURDIR)/lwip-cvs clean + $(MAKE) -C caml clean + rm -fr libxc ioemu mini-os include + +# clean the cross-compilation result +.PHONY: crossclean +crossclean: clean + rm -fr $(CROSS_ROOT) + rm -fr binutils-build gcc-build newlib-build + rm -fr zlib-$(ZLIB_VERSION) pciutils-$(LIBPCI_VERSION) + +# clean patched sources +.PHONY: patchclean +patchclean: crossclean + rm -fr binutils-$(BINUTILS_VERSION) + rm -fr gcc-$(GCC_VERSION) + rm -fr newlib-cvs + rm -fr lwip-cvs + +# clean downloads +.PHONY: downloadclean +downloadclean: patchclean + rm -f binutils-$(BINUTILS_VERSION).tar.bz2 + rm -f gcc-$(GCC_VERSION).tar.bz2 + rm -f zlib-$(ZLIB_VERSION).tar.gz + rm -f pciutils-$(LIBPCI_VERSION).tar.bz2 + +.PHONY: distclean +distclean: downloadclean diff --git a/stubdom/README b/stubdom/README new file mode 100644 index 0000000000..42c47601fa --- /dev/null +++ b/stubdom/README @@ -0,0 +1,41 @@ +To compile +========== + +Just run make -j 4, that will download / patch / compile +Then make install to install the result. + +Also, run make and make install in $XEN_ROOT/tools/fs-back + +To run +====== + +mkdir -p /exports/usr/share/qemu +ln -s /usr/share/qemu/keymaps /exports/usr/share/qemu +/usr/sbin/fs-backend & + + +In your HVM config "hvmconfig", + +- use VNC, set vnclisten to "172.30.206.1" for instance: + +vnc=1 +vnclisten="172.30.206.1" + +- use /usr/lib/xen/bin/stubdom-dm as dm script + +device_model = '/usr/lib/xen/bin/stubdom-dm' + +- comment the disk statement: +#disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] + +Create /etc/xen/stubdom-hvmconfig ("hvmconfig" must match your main config file) +with + +kernel="/usr/lib/xen/boot/stubdom.gz" +vif=[ 'ip=172.30.206.1', 'ip=10.0.1.1,mac=aa:00:00:12:23:34'] +disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ] + +where +- 172.30.206.1 is the IP for vnc, +- 'ip=10.0.1.1,mac=' is the same net configuration as in the hvmconfig script, +- and disk = is the same block configuration as in the hvmconfig script. diff --git a/stubdom/binutils.patch b/stubdom/binutils.patch new file mode 100644 index 0000000000..65f120a377 --- /dev/null +++ b/stubdom/binutils.patch @@ -0,0 +1,14 @@ +It looks like binutils has troubles with makeinfo and the doc generation. +We don't need it anyway + +--- binutils-2.18/bfd/Makefile.inorig 2008-01-16 16:17:43.004484000 +0000 ++++ binutils-2.18/bfd/Makefile.in 2008-01-16 16:17:50.505526000 +0000 +@@ -271,7 +271,7 @@ + INCDIR = $(srcdir)/../include + CSEARCH = -I. -I$(srcdir) -I$(INCDIR) + MKDEP = gcc -MM +-SUBDIRS = doc po ++SUBDIRS = po + bfddocdir = doc + bfdlib_LTLIBRARIES = libbfd.la + AM_CFLAGS = $(WARN_CFLAGS) diff --git a/stubdom/caml/Makefile b/stubdom/caml/Makefile new file mode 100644 index 0000000000..69595a8f99 --- /dev/null +++ b/stubdom/caml/Makefile @@ -0,0 +1,18 @@ +XEN_ROOT = ../.. + +include $(XEN_ROOT)/Config.mk + +OCAMLFIND=ocamlfind +OCAMLOPT=ocamlopt + +OBJS := hello.cmx +LIBS := + +%.cmx: %.ml + $(OCAMLFIND) $(OCAMLOPT) -c $< -o $@ + +caml.o: $(OBJS) + $(OCAMLFIND) $(OCAMLOPT) $(LIBS) $^ -output-obj -o $@ + +clean: + rm -f *.o *.cmx *.cmi diff --git a/stubdom/caml/hello.ml b/stubdom/caml/hello.ml new file mode 100644 index 0000000000..3a7181134a --- /dev/null +++ b/stubdom/caml/hello.ml @@ -0,0 +1,4 @@ +let main arg = + Printf.printf "Hello, world!\n%!." + +let _ = Callback.register "main" main diff --git a/stubdom/gcc.patch b/stubdom/gcc.patch new file mode 100644 index 0000000000..d593986ab7 --- /dev/null +++ b/stubdom/gcc.patch @@ -0,0 +1,31 @@ +Backported from later versions + +--- gcc-4.2.2/gcc/config.gcc 2007-11-22 16:27:45.000000000 +0000 ++++ gcc-4.2.2/gcc/config.gcc 2007-11-22 16:23:00.000000000 +0000 +@@ -1033,6 +1033,11 @@ + tmake_file="i386/t-i386elf t-svr4" + use_fixproto=yes + ;; ++x86_64-*-elf*) ++ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h i386/i386elf.h i386/x86-64.h" ++ tmake_file="i386/t-i386elf t-svr4" ++ use_fixproto=yes ++ ;; + i[34567]86-sequent-ptx4* | i[34567]86-sequent-sysv4*) + if test x$gas = xyes + then + +We don't have a libc yet at this stage. Unused anyway + +--- gcc-4.2.2/gcc/unwind-generic.h.orig 2008-01-11 18:54:40.000000000 +0100 ++++ gcc-4.2.2/gcc/unwind-generic.h 2008-01-11 18:54:31.000000000 +0100 +@@ -203,7 +203,6 @@ + compatible with the standard ABI for IA-64, we inline these. */ + + #ifdef __ia64__ +-#include <stdlib.h> + + static inline _Unwind_Ptr + _Unwind_GetDataRelBase (struct _Unwind_Context *_C) +Backported from later versions + diff --git a/stubdom/libpci.config.h b/stubdom/libpci.config.h new file mode 100644 index 0000000000..a84ead5708 --- /dev/null +++ b/stubdom/libpci.config.h @@ -0,0 +1,5 @@ +#define PCI_OS_STUBDOM +#define PCI_HAVE_STDINT_H +#define PCI_PATH_IDS_DIR "." +#define PCI_COMPRESSED_IDS +#define PCI_IDS "pci.ids.gz" diff --git a/stubdom/libpci.config.mak b/stubdom/libpci.config.mak new file mode 100644 index 0000000000..5bc5b261d0 --- /dev/null +++ b/stubdom/libpci.config.mak @@ -0,0 +1,2 @@ +LIBZ=-lz +LDLIBS+=$(LIBZ) diff --git a/stubdom/newlib.patch b/stubdom/newlib.patch new file mode 100644 index 0000000000..217205cccf --- /dev/null +++ b/stubdom/newlib.patch @@ -0,0 +1,203 @@ +There is a mix between longs and long longs. + +Index: newlib/libc/include/inttypes.h +=================================================================== +RCS file: /cvs/src/src/newlib/libc/include/inttypes.h,v +retrieving revision 1.3 +diff -u -p -r1.3 inttypes.h +--- newlib/libc/include/inttypes.h 16 Dec 2005 19:03:12 -0000 1.3 ++++ newlib/libc/include/inttypes.h 8 Nov 2007 16:32:44 -0000 +@@ -163,12 +163,12 @@ + + + /* 64-bit types */ +-#if __have_longlong64 +-#define __PRI64(x) __STRINGIFY(ll##x) +-#define __SCN64(x) __STRINGIFY(ll##x) +-#elif __have_long64 ++#if __have_long64 + #define __PRI64(x) __STRINGIFY(l##x) + #define __SCN64(x) __STRINGIFY(l##x) ++#elif __have_longlong64 ++#define __PRI64(x) __STRINGIFY(ll##x) ++#define __SCN64(x) __STRINGIFY(ll##x) + #else + #define __PRI64(x) __STRINGIFY(x) + #define __SCN64(x) __STRINGIFY(x) +@@ -217,12 +217,12 @@ + #endif + + /* max-bit types */ +-#if __have_longlong64 +-#define __PRIMAX(x) __STRINGIFY(ll##x) +-#define __SCNMAX(x) __STRINGIFY(ll##x) +-#elif __have_long64 ++#if __have_long64 + #define __PRIMAX(x) __STRINGIFY(l##x) + #define __SCNMAX(x) __STRINGIFY(l##x) ++#elif __have_longlong64 ++#define __PRIMAX(x) __STRINGIFY(ll##x) ++#define __SCNMAX(x) __STRINGIFY(ll##x) + #else + #define __PRIMAX(x) __STRINGIFY(x) + #define __SCNMAX(x) __STRINGIFY(x) +@@ -242,12 +242,12 @@ + #define SCNxMAX __SCNMAX(x) + + /* ptr types */ +-#if __have_longlong64 +-#define __PRIPTR(x) __STRINGIFY(ll##x) +-#define __SCNPTR(x) __STRINGIFY(ll##x) +-#elif __have_long64 ++#if __have_long64 + #define __PRIPTR(x) __STRINGIFY(l##x) + #define __SCNPTR(x) __STRINGIFY(l##x) ++#elif __have_longlong64 ++#define __PRIPTR(x) __STRINGIFY(ll##x) ++#define __SCNPTR(x) __STRINGIFY(ll##x) + #else + #define __PRIPTR(x) __STRINGIFY(x) + #define __SCNPTR(x) __STRINGIFY(x) + +We don't want u?int32_t to be long as our code assume in a lot of places to be +int. + +Index: newlib/libc/include/stdint.h +=================================================================== +RCS file: /cvs/src/src/newlib/libc/include/stdint.h,v +retrieving revision 1.10 +diff -u -p -r1.10 stdint.h +--- newlib/libc/include/stdint.h 16 Aug 2006 21:39:43 -0000 1.10 ++++ newlib/libc/include/stdint.h 12 Feb 2008 13:07:52 -0000 +@@ -38,7 +38,7 @@ extern "C" { + #if __STDINT_EXP(LONG_MAX) > 0x7fffffff + #define __have_long64 1 + #elif __STDINT_EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__) +-#define __have_long32 1 ++/* #define __have_long32 1 */ + #endif + + #if __STDINT_EXP(SCHAR_MAX) == 0x7f + +Define the basic ia64 jump buffer + +Index: newlib/libc/include/machine/setjmp.h +=================================================================== +RCS file: /cvs/src/src/newlib/libc/include/machine/setjmp.h,v +retrieving revision 1.34 +diff -u -p -r1.34 setjmp.h +--- newlib/libc/include/machine/setjmp.h 7 Nov 2007 21:42:24 -0000 1.34 ++++ newlib/libc/include/machine/setjmp.h 11 Jan 2008 18:10:43 -0000 +@@ -72,6 +72,11 @@ _BEGIN_STD_C + #define _JBLEN 8 + #endif + ++#ifdef __ia64__ ++#define _JBTYPE long ++#define _JBLEN 70 ++#endif ++ + #ifdef __i960__ + #define _JBLEN 35 + #endif + +In mini-os we use a dynamic reentrency buffer. + +Index: newlib/libc/include/sys/config.h +=================================================================== +RCS file: /cvs/src/src/newlib/libc/include/sys/config.h,v +retrieving revision 1.47 +diff -u -p -r1.47 config.h +--- newlib/libc/include/sys/config.h 15 Mar 2007 21:32:12 -0000 1.47 ++++ newlib/libc/include/sys/config.h 8 Nov 2007 16:32:44 -0000 +@@ -71,6 +71,10 @@ + #endif + #endif + ++#ifndef __DYNAMIC_REENT__ ++#define __DYNAMIC_REENT__ ++#endif ++ + #ifdef __mn10200__ + #define __SMALL_BITFIELDS + #endif + +Dynamic pointer to our reentrancy zone + +Index: newlib/libc/reent/getreent.c +=================================================================== +RCS file: /cvs/src/src/newlib/libc/reent/getreent.c,v +retrieving revision 1.2 +diff -u -p -r1.2 getreent.c +--- newlib/libc/reent/getreent.c 7 Sep 2007 00:45:55 -0000 1.2 ++++ newlib/libc/reent/getreent.c 8 Nov 2007 16:32:44 -0000 +@@ -3,12 +3,20 @@ + #include <_ansi.h> + #include <reent.h> + ++#define weak_alias(name, aliasname) \ ++ extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))); ++ + #ifdef __getreent + #undef __getreent + #endif ++#ifdef __libc_getreent ++#undef __libc_getreent ++#endif + + struct _reent * +-_DEFUN_VOID(__getreent) ++__libc_getreent (void) + { + return _impure_ptr; + } ++weak_alias(__libc_getreent,__getreent) ++ + +We can't provide a red zone in mini-os. + +Index: newlib/libc/machine/x86_64/memcpy.S +=================================================================== +RCS file: /cvs/src/src/newlib/libc/machine/x86_64/memcpy.S,v +retrieving revision 1.1 +diff -u -p -r1.1 memcpy.S +--- newlib/libc/machine/x86_64/memcpy.S 28 Aug 2007 21:56:49 -0000 1.1 ++++ newlib/libc/machine/x86_64/memcpy.S 8 Nov 2007 16:32:44 -0000 +@@ -30,10 +30,18 @@ quadword_aligned: + cmpq $256, rdx + jb quadword_copy + ++#if 1 ++ subq $32, rsp ++ movq rax, 24 (rsp) ++ movq r12, 16 (rsp) ++ movq r13, 8 (rsp) ++ movq r14, 0 (rsp) ++#else + movq rax, -8 (rsp) + movq r12, -16 (rsp) + movq r13, -24 (rsp) + movq r14, -32 (rsp) ++#endif + + movq rdx, rcx /* Copy 128 bytes at a time with minimum cache polution */ + shrq $7, rcx +@@ -89,10 +97,18 @@ loop: + movq rdx, rcx + andq $127, rcx + rep movsb ++#if 1 ++ movq 24 (rsp), rax ++ movq 16 (rsp), r12 ++ movq 8 (rsp), r13 ++ movq 0 (rsp), r14 ++ addq $32, rsp ++#else + movq -8 (rsp), rax + movq -16 (rsp), r12 + movq -24 (rsp), r13 + movq -32 (rsp), r14 ++#endif + ret + + diff --git a/stubdom/stubdom-dm b/stubdom/stubdom-dm new file mode 100644 index 0000000000..3edeb9d2dc --- /dev/null +++ b/stubdom/stubdom-dm @@ -0,0 +1,97 @@ +#!/bin/bash +# +# Copyright 2007-2008 Samuel Thibault <samuel.thibault@eu.citrix.net> +# +# dm script around stubdomains. +# + +# To fit xterms nicely +height=339 + +# Parse arguments + +domid= +domname= +vncviewer=0 +vncpid= +while [ "$#" -gt 0 ]; +do + if [ "$#" -ge 2 ]; + then + case "$1" in + -d) domid=$2; shift ;; + -domain-name) domname=$2; shift ;; + -vnc) + ip=${2%:*}; + vnc_port=${2#*:}; + shift + ;; + esac + fi + case "$1" in + -vncviewer) vncviewer=1 ;; + esac + shift +done + +[ -z "$domid" ] && ( echo "couldn't find domain ID" ; exit 1 ) +[ -z "$domname" ] && ( echo "couldn't find domain name" ; exit 1 ) + +# Termination handler + +term() { + kill %1 + ( + [ -n "$vncpid" ] && kill -9 $vncpid + xm destroy stubdom-$domname + #xm destroy $domname + ) & + # We need to exit immediately so as to let xend do the commands above + exit 0 +} + +trap term SIGHUP + +############ +# stubdomain +# Wait for any previous stubdom to terminate +while xm list | grep stubdom-$domname +do + sleep 1 +done + +creation="xm create -c stubdom-$domname target=$domid memory=32" + +(while true ; do sleep 60 ; done) | $creation & +#xterm -geometry +0+0 -e /bin/sh -c "$creation ; echo ; echo press ENTER to shut down ; read" & +consolepid=$! + + +while ! vnc_port=`xenstore-read /local/domain/$domid/console/vnc-port` +do + # Check that the stubdom job is still alive + kill -0 $consolepid || term + sleep 1 +done + +################ +# DEBUG: tcpdump +#while ! stubdomid=`xm domid stubdom-$domname` +#do +# sleep 1 +#done +#xterm -geometry 160x25+0+$height -e /bin/sh -c "tcpdump -n -i vif$stubdomid.0" & +#xterm -geometry 160x25+0+$((2 * $height)) -e /bin/sh -c "tcpdump -n -i vif$stubdomid.1" & + +########### +# vncviewer +if [ "$vncviewer" = 1 ] +then + vncviewer $ip:$vnc_port & + vncpid=$! +fi + +# wait for SIGHUP or stubdom termination +wait $consolepid + +term diff --git a/tools/blktap/drivers/tapdisk.c b/tools/blktap/drivers/tapdisk.c index 993e09b155..75f06c701c 100644 --- a/tools/blktap/drivers/tapdisk.c +++ b/tools/blktap/drivers/tapdisk.c @@ -641,7 +641,7 @@ static void get_io_request(struct td_state *s) if (!run) return; /*We have received signal to close*/ rp = info->fe_ring.sring->req_prod; - rmb(); + xen_rmb(); for (j = info->fe_ring.req_cons; j != rp; j++) { int done = 0, start_seg = 0; diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index 735a77b0e6..9573333c08 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -60,6 +60,8 @@ extern int log_reload; extern int log_guest; extern int log_hv; +extern int log_time_hv; +extern int log_time_guest; extern char *log_dir; static int log_hv_fd = -1; @@ -99,6 +101,50 @@ struct domain static struct domain *dom_head; +static int write_all(int fd, const char* buf, size_t len) +{ + while (len) { + ssize_t ret = write(fd, buf, len); + if (ret == -1 && errno == EINTR) + continue; + if (ret <= 0) + return -1; + len -= ret; + buf += ret; + } + + return 0; +} + +static int write_with_timestamp(int fd, const char *data, size_t sz) +{ + char buf[sz+1]; + char ts[32]; + time_t now = time(NULL); + const struct tm *tmnow = localtime(&now); + size_t tslen = strftime(ts, sizeof(ts), "[%d-%m-%Y %H:%M:%S] ", tmnow); + + memcpy(buf, data, sz); + while (sz > 0 && buf[sz-1] == '\r') + sz--; // Don't print trailing \r's + if (sz > 0 && buf[sz-1] != '\n') + buf[sz++] = '\n'; // Force ending newline + data = buf; + + while (sz > 0) { + const char *nl = strchr(data, '\n') + 1; + size_t towrite = nl - data; + if (write_all(fd, ts, tslen) < 0) + return -1; + if (write_all(fd, data, towrite)) + return -1; + sz -= towrite; + data = nl; + } + + return 0; +} + static void buffer_append(struct domain *dom) { struct buffer *buffer = &dom->buffer; @@ -107,7 +153,7 @@ static void buffer_append(struct domain *dom) cons = intf->out_cons; prod = intf->out_prod; - mb(); + xen_mb(); size = prod - cons; if ((size == 0) || (size > sizeof(intf->out))) @@ -126,7 +172,7 @@ static void buffer_append(struct domain *dom) buffer->data[buffer->size++] = intf->out[ MASK_XENCONS_IDX(cons++, intf->out)]; - mb(); + xen_mb(); intf->out_cons = cons; xc_evtchn_notify(dom->xce_handle, dom->local_port); @@ -135,10 +181,13 @@ static void buffer_append(struct domain *dom) * and handle_tty_write will stop being called. */ if (dom->log_fd != -1) { - int len = write(dom->log_fd, - buffer->data + buffer->size - size, - size); - if (len < 0) + int logret; + if (log_time_guest) { + logret = write_with_timestamp(dom->log_fd, buffer->data + buffer->size - size, size); + } else { + logret = write_all(dom->log_fd, buffer->data + buffer->size - size, size); + } + if (logret < 0) dolog(LOG_ERR, "Write to log failed on domain %d: %d (%s)\n", dom->domid, errno, strerror(errno)); } @@ -195,6 +244,15 @@ static int create_hv_log(void) if (fd == -1) dolog(LOG_ERR, "Failed to open log %s: %d (%s)", logfile, errno, strerror(errno)); + if (fd != -1 && log_time_hv) { + if (write_with_timestamp(fd, "Logfile Opened", + strlen("Logfile Opened")) < 0) { + dolog(LOG_ERR, "Failed to log opening timestamp " + "in %s: %d (%s)", logfile, errno, + strerror(errno)); + return -1; + } + } return fd; } @@ -229,6 +287,15 @@ static int create_domain_log(struct domain *dom) if (fd == -1) dolog(LOG_ERR, "Failed to open log %s: %d (%s)", logfile, errno, strerror(errno)); + if (fd != -1 && log_time_guest) { + if (write_with_timestamp(fd, "Logfile Opened", + strlen("Logfile Opened")) < 0) { + dolog(LOG_ERR, "Failed to log opening timestamp " + "in %s: %d (%s)", logfile, errno, + strerror(errno)); + return -1; + } + } return fd; } @@ -683,7 +750,7 @@ static int ring_free_bytes(struct domain *dom) cons = intf->in_cons; prod = intf->in_prod; - mb(); + xen_mb(); space = prod - cons; if (space > sizeof(intf->in)) @@ -730,7 +797,7 @@ static void handle_tty_read(struct domain *dom) intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = msg[i]; } - wmb(); + xen_wmb(); intf->in_prod = prod; xc_evtchn_notify(dom->xce_handle, dom->local_port); } else { @@ -817,11 +884,16 @@ static void handle_hv_logs(void) if ((port = xc_evtchn_pending(xce_handle)) == -1) return; - if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0) { - int len = write(log_hv_fd, buffer, size); - if (len < 0) - dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)", - errno, strerror(errno)); + if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0 && size > 0) { + int logret; + if (log_time_guest) + logret = write_with_timestamp(log_hv_fd, buffer, size); + else + logret = write_all(log_hv_fd, buffer, size); + + if (logret < 0) + dolog(LOG_ERR, "Failed to write hypervisor log: " + "%d (%s)", errno, strerror(errno)); } (void)xc_evtchn_unmask(xce_handle, port); diff --git a/tools/console/daemon/main.c b/tools/console/daemon/main.c index ea0648f400..c66642ff46 100644 --- a/tools/console/daemon/main.c +++ b/tools/console/daemon/main.c @@ -35,6 +35,8 @@ int log_reload = 0; int log_guest = 0; int log_hv = 0; +int log_time_hv = 0; +int log_time_guest = 0; char *log_dir = NULL; static void handle_hup(int sig) @@ -44,7 +46,7 @@ static void handle_hup(int sig) static void usage(char *name) { - printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH]\n", name); + printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH] [-t, --timestamp=none|guest|hv|all]\n", name); } static void version(char *name) @@ -54,7 +56,7 @@ static void version(char *name) int main(int argc, char **argv) { - const char *sopts = "hVvi"; + const char *sopts = "hVvit:"; struct option lopts[] = { { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, @@ -63,6 +65,7 @@ int main(int argc, char **argv) { "log", 1, 0, 'l' }, { "log-dir", 1, 0, 'r' }, { "pid-file", 1, 0, 'p' }, + { "timestamp", 1, 0, 't' }, { 0 }, }; bool is_interactive = false; @@ -103,6 +106,19 @@ int main(int argc, char **argv) case 'p': pidfile = strdup(optarg); break; + case 't': + if (!strcmp(optarg, "all")) { + log_time_hv = 1; + log_time_guest = 1; + } else if (!strcmp(optarg, "hv")) { + log_time_hv = 1; + } else if (!strcmp(optarg, "guest")) { + log_time_guest = 1; + } else if (!strcmp(optarg, "none")) { + log_time_guest = 0; + log_time_hv = 0; + } + break; case '?': fprintf(stderr, "Try `%s --help' for more information\n", diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c index 247c3b5928..e33cc04795 100644 --- a/tools/firmware/hvmloader/acpi/build.c +++ b/tools/firmware/hvmloader/acpi/build.c @@ -62,11 +62,18 @@ static int uart_exists(uint16_t uart_base) return ((b == 0) && (c == 0xf)); } +static int hpet_exists(unsigned long hpet_base) +{ + uint32_t hpet_id = *(uint32_t *)hpet_base; + return ((hpet_id >> 16) == 0x8086); +} + static int construct_bios_info_table(uint8_t *buf) { struct bios_info { uint8_t com1_present:1; uint8_t com2_present:1; + uint8_t hpet_present:1; uint32_t pci_min, pci_len; } *bios_info = (struct bios_info *)buf; @@ -75,6 +82,8 @@ static int construct_bios_info_table(uint8_t *buf) bios_info->com1_present = uart_exists(0x3f8); bios_info->com2_present = uart_exists(0x2f8); + bios_info->hpet_present = hpet_exists(ACPI_HPET_ADDRESS); + bios_info->pci_min = 0xf0000000; bios_info->pci_len = 0x0c000000; @@ -272,9 +281,12 @@ static int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) } /* HPET. */ - hpet = (struct acpi_20_hpet *)&buf[offset]; - offset += construct_hpet(hpet); - table_ptrs[nr_tables++] = (unsigned long)hpet; + if ( hpet_exists(ACPI_HPET_ADDRESS) ) + { + hpet = (struct acpi_20_hpet *)&buf[offset]; + offset += construct_hpet(hpet); + table_ptrs[nr_tables++] = (unsigned long)hpet; + } /* Processor Object SSDT. */ table_ptrs[nr_tables++] = (unsigned long)&buf[offset]; diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl index f5c2fefda5..fde51ac0ad 100644 --- a/tools/firmware/hvmloader/acpi/dsdt.asl +++ b/tools/firmware/hvmloader/acpi/dsdt.asl @@ -49,6 +49,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0) Field(BIOS, ByteAcc, NoLock, Preserve) { UAR1, 1, UAR2, 1, + HPET, 1, Offset(4), PMIN, 32, PLEN, 32 @@ -296,6 +297,13 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0) Device(HPET) { Name(_HID, EISAID("PNP0103")) Name(_UID, 0) + Method (_STA, 0, NotSerialized) { + If(LEqual(\_SB.HPET, 0)) { + Return(0x00) + } Else { + Return(0x0F) + } + } Name(_CRS, ResourceTemplate() { DWordMemory( ResourceConsumer, PosDecode, MinFixed, MaxFixed, diff --git a/tools/firmware/hvmloader/acpi/dsdt.c b/tools/firmware/hvmloader/acpi/dsdt.c index ab34c068bb..54088c6746 100644 --- a/tools/firmware/hvmloader/acpi/dsdt.c +++ b/tools/firmware/hvmloader/acpi/dsdt.c @@ -5,15 +5,15 @@ * Copyright (C) 2000 - 2006 Intel Corporation * Supports ACPI Specification Revision 3.0a * - * Compilation of "dsdt.asl" - Mon Jan 21 14:11:31 2008 + * Compilation of "dsdt.asl" - Mon Feb 11 13:31:53 2008 * * C source code output * */ unsigned char AmlCode[] = { - 0x44,0x53,0x44,0x54,0x6F,0x0E,0x00,0x00, /* 00000000 "DSDTo..." */ - 0x02,0xE1,0x58,0x65,0x6E,0x00,0x00,0x00, /* 00000008 "..Xen..." */ + 0x44,0x53,0x44,0x54,0x8E,0x0E,0x00,0x00, /* 00000000 "DSDT...." */ + 0x02,0x6E,0x58,0x65,0x6E,0x00,0x00,0x00, /* 00000008 ".nXen..." */ 0x48,0x56,0x4D,0x00,0x00,0x00,0x00,0x00, /* 00000010 "HVM....." */ 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ 0x07,0x07,0x06,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */ @@ -27,452 +27,456 @@ unsigned char AmlCode[] = 0x04,0x0A,0x07,0x0A,0x07,0x00,0x00,0x08, /* 00000060 "........" */ 0x50,0x49,0x43,0x44,0x00,0x14,0x0C,0x5F, /* 00000068 "PICD..._" */ 0x50,0x49,0x43,0x01,0x70,0x68,0x50,0x49, /* 00000070 "PIC.phPI" */ - 0x43,0x44,0x10,0x44,0xDF,0x5F,0x53,0x42, /* 00000078 "CD.D._SB" */ + 0x43,0x44,0x10,0x43,0xE1,0x5F,0x53,0x42, /* 00000078 "CD.C._SB" */ 0x5F,0x5B,0x80,0x42,0x49,0x4F,0x53,0x00, /* 00000080 "_[.BIOS." */ 0x0C,0x00,0xA0,0x0E,0x00,0x0A,0x10,0x5B, /* 00000088 ".......[" */ - 0x81,0x1C,0x42,0x49,0x4F,0x53,0x01,0x55, /* 00000090 "..BIOS.U" */ + 0x81,0x21,0x42,0x49,0x4F,0x53,0x01,0x55, /* 00000090 ".!BIOS.U" */ 0x41,0x52,0x31,0x01,0x55,0x41,0x52,0x32, /* 00000098 "AR1.UAR2" */ - 0x01,0x00,0x1E,0x50,0x4D,0x49,0x4E,0x20, /* 000000A0 "...PMIN " */ - 0x50,0x4C,0x45,0x4E,0x20,0x5B,0x82,0x49, /* 000000A8 "PLEN [.I" */ - 0x04,0x4D,0x45,0x4D,0x30,0x08,0x5F,0x48, /* 000000B0 ".MEM0._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x02,0x08, /* 000000B8 "ID.A...." */ - 0x5F,0x43,0x52,0x53,0x11,0x33,0x0A,0x30, /* 000000C0 "_CRS.3.0" */ - 0x8A,0x2B,0x00,0x00,0x0D,0x03,0x00,0x00, /* 000000C8 ".+......" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D0 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF, /* 000000D8 "........" */ - 0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E0 "........" */ + 0x01,0x48,0x50,0x45,0x54,0x01,0x00,0x1D, /* 000000A0 ".HPET..." */ + 0x50,0x4D,0x49,0x4E,0x20,0x50,0x4C,0x45, /* 000000A8 "PMIN PLE" */ + 0x4E,0x20,0x5B,0x82,0x49,0x04,0x4D,0x45, /* 000000B0 "N [.I.ME" */ + 0x4D,0x30,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 000000B8 "M0._HID." */ + 0x41,0xD0,0x0C,0x02,0x08,0x5F,0x43,0x52, /* 000000C0 "A...._CR" */ + 0x53,0x11,0x33,0x0A,0x30,0x8A,0x2B,0x00, /* 000000C8 "S.3.0.+." */ + 0x00,0x0D,0x03,0x00,0x00,0x00,0x00,0x00, /* 000000D0 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000D8 "........" */ + 0x00,0x00,0x00,0xFF,0xFF,0x09,0x00,0x00, /* 000000E0 "........" */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000E8 "........" */ - 0x0A,0x00,0x00,0x00,0x00,0x00,0x79,0x00, /* 000000F0 "......y." */ - 0x5B,0x82,0x45,0xD7,0x50,0x43,0x49,0x30, /* 000000F8 "[.E.PCI0" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000100 "._HID.A." */ - 0x0A,0x03,0x08,0x5F,0x55,0x49,0x44,0x00, /* 00000108 "..._UID." */ - 0x08,0x5F,0x41,0x44,0x52,0x00,0x08,0x5F, /* 00000110 "._ADR.._" */ - 0x42,0x42,0x4E,0x00,0x14,0x4E,0x0C,0x5F, /* 00000118 "BBN..N._" */ - 0x43,0x52,0x53,0x00,0x08,0x50,0x52,0x54, /* 00000120 "CRS..PRT" */ - 0x30,0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D, /* 00000128 "0.B..n.." */ - 0x00,0x02,0x0E,0x00,0x00,0x00,0x00,0x00, /* 00000130 "........" */ - 0xFF,0x00,0x00,0x00,0x00,0x01,0x47,0x01, /* 00000138 "......G." */ - 0xF8,0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D, /* 00000140 "........" */ - 0x00,0x01,0x0C,0x03,0x00,0x00,0x00,0x00, /* 00000148 "........" */ - 0xF7,0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D, /* 00000150 "........" */ - 0x00,0x01,0x0C,0x03,0x00,0x00,0x00,0x0D, /* 00000158 "........" */ - 0xFF,0xFF,0x00,0x00,0x00,0xF3,0x87,0x17, /* 00000160 "........" */ - 0x00,0x00,0x0C,0x03,0x00,0x00,0x00,0x00, /* 00000168 "........" */ - 0x00,0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00, /* 00000170 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00, /* 00000178 "........" */ - 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000180 "........" */ - 0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF, /* 00000188 "........" */ - 0xFF,0xF4,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000190 "........" */ - 0x00,0x05,0x79,0x00,0x8A,0x50,0x52,0x54, /* 00000198 "..y..PRT" */ - 0x30,0x0A,0x5C,0x4D,0x4D,0x49,0x4E,0x8A, /* 000001A0 "0.\MMIN." */ - 0x50,0x52,0x54,0x30,0x0A,0x60,0x4D,0x4D, /* 000001A8 "PRT0.`MM" */ - 0x41,0x58,0x8A,0x50,0x52,0x54,0x30,0x0A, /* 000001B0 "AX.PRT0." */ - 0x68,0x4D,0x4C,0x45,0x4E,0x70,0x50,0x4D, /* 000001B8 "hMLENpPM" */ - 0x49,0x4E,0x4D,0x4D,0x49,0x4E,0x70,0x50, /* 000001C0 "INMMINpP" */ - 0x4C,0x45,0x4E,0x4D,0x4C,0x45,0x4E,0x72, /* 000001C8 "LENMLENr" */ - 0x4D,0x4D,0x49,0x4E,0x4D,0x4C,0x45,0x4E, /* 000001D0 "MMINMLEN" */ - 0x4D,0x4D,0x41,0x58,0x74,0x4D,0x4D,0x41, /* 000001D8 "MMAXtMMA" */ - 0x58,0x01,0x4D,0x4D,0x41,0x58,0xA4,0x50, /* 000001E0 "X.MMAX.P" */ - 0x52,0x54,0x30,0x08,0x42,0x55,0x46,0x41, /* 000001E8 "RT0.BUFA" */ - 0x11,0x09,0x0A,0x06,0x23,0x20,0x0C,0x18, /* 000001F0 "....# .." */ - 0x79,0x00,0x08,0x42,0x55,0x46,0x42,0x11, /* 000001F8 "y..BUFB." */ - 0x09,0x0A,0x06,0x23,0x00,0x00,0x18,0x79, /* 00000200 "...#...y" */ - 0x00,0x8B,0x42,0x55,0x46,0x42,0x01,0x49, /* 00000208 "..BUFB.I" */ - 0x52,0x51,0x56,0x5B,0x82,0x48,0x08,0x4C, /* 00000210 "RQV[.H.L" */ - 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000218 "NKA._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000220 ".A...._U" */ - 0x49,0x44,0x01,0x14,0x1C,0x5F,0x53,0x54, /* 00000228 "ID..._ST" */ - 0x41,0x00,0x7B,0x50,0x49,0x52,0x41,0x0A, /* 00000230 "A.{PIRA." */ - 0x80,0x60,0xA0,0x08,0x93,0x60,0x0A,0x80, /* 00000238 ".`...`.." */ - 0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B, /* 00000240 "........" */ - 0x14,0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4, /* 00000248 ".._PRS.." */ - 0x42,0x55,0x46,0x41,0x14,0x11,0x5F,0x44, /* 00000250 "BUFA.._D" */ - 0x49,0x53,0x00,0x7D,0x50,0x49,0x52,0x41, /* 00000258 "IS.}PIRA" */ - 0x0A,0x80,0x50,0x49,0x52,0x41,0x14,0x1A, /* 00000260 "..PIRA.." */ - 0x5F,0x43,0x52,0x53,0x00,0x7B,0x50,0x49, /* 00000268 "_CRS.{PI" */ - 0x52,0x41,0x0A,0x0F,0x60,0x79,0x01,0x60, /* 00000270 "RA..`y.`" */ - 0x49,0x52,0x51,0x56,0xA4,0x42,0x55,0x46, /* 00000278 "IRQV.BUF" */ - 0x42,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000280 "B.._SRS." */ - 0x8B,0x68,0x01,0x49,0x52,0x51,0x31,0x82, /* 00000288 ".h.IRQ1." */ - 0x49,0x52,0x51,0x31,0x60,0x76,0x60,0x70, /* 00000290 "IRQ1`v`p" */ - 0x60,0x50,0x49,0x52,0x41,0x5B,0x82,0x49, /* 00000298 "`PIRA[.I" */ - 0x08,0x4C,0x4E,0x4B,0x42,0x08,0x5F,0x48, /* 000002A0 ".LNKB._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 000002A8 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x1C, /* 000002B0 "_UID...." */ - 0x5F,0x53,0x54,0x41,0x00,0x7B,0x50,0x49, /* 000002B8 "_STA.{PI" */ - 0x52,0x42,0x0A,0x80,0x60,0xA0,0x08,0x93, /* 000002C0 "RB..`..." */ - 0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04, /* 000002C8 "`......." */ - 0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52, /* 000002D0 "....._PR" */ - 0x53,0x00,0xA4,0x42,0x55,0x46,0x41,0x14, /* 000002D8 "S..BUFA." */ - 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 000002E0 "._DIS.}P" */ - 0x49,0x52,0x42,0x0A,0x80,0x50,0x49,0x52, /* 000002E8 "IRB..PIR" */ - 0x42,0x14,0x1A,0x5F,0x43,0x52,0x53,0x00, /* 000002F0 "B.._CRS." */ - 0x7B,0x50,0x49,0x52,0x42,0x0A,0x0F,0x60, /* 000002F8 "{PIRB..`" */ - 0x79,0x01,0x60,0x49,0x52,0x51,0x56,0xA4, /* 00000300 "y.`IRQV." */ - 0x42,0x55,0x46,0x42,0x14,0x1B,0x5F,0x53, /* 00000308 "BUFB.._S" */ - 0x52,0x53,0x01,0x8B,0x68,0x01,0x49,0x52, /* 00000310 "RS..h.IR" */ - 0x51,0x31,0x82,0x49,0x52,0x51,0x31,0x60, /* 00000318 "Q1.IRQ1`" */ - 0x76,0x60,0x70,0x60,0x50,0x49,0x52,0x42, /* 00000320 "v`p`PIRB" */ - 0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B,0x43, /* 00000328 "[.I.LNKC" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000330 "._HID.A." */ - 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000338 "..._UID." */ - 0x03,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 00000340 "..._STA." */ - 0x7B,0x50,0x49,0x52,0x43,0x0A,0x80,0x60, /* 00000348 "{PIRC..`" */ - 0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 00000350 "...`...." */ - 0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 00000358 "........" */ - 0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 00000360 "_PRS..BU" */ - 0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 00000368 "FA.._DIS" */ - 0x00,0x7D,0x50,0x49,0x52,0x43,0x0A,0x80, /* 00000370 ".}PIRC.." */ - 0x50,0x49,0x52,0x43,0x14,0x1A,0x5F,0x43, /* 00000378 "PIRC.._C" */ - 0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x43, /* 00000380 "RS.{PIRC" */ - 0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 00000388 "..`y.`IR" */ - 0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 00000390 "QV.BUFB." */ - 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000398 "._SRS..h" */ - 0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 000003A0 ".IRQ1.IR" */ - 0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 000003A8 "Q1`v`p`P" */ - 0x49,0x52,0x43,0x5B,0x82,0x49,0x08,0x4C, /* 000003B0 "IRC[.I.L" */ - 0x4E,0x4B,0x44,0x08,0x5F,0x48,0x49,0x44, /* 000003B8 "NKD._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 000003C0 ".A...._U" */ - 0x49,0x44,0x0A,0x04,0x14,0x1C,0x5F,0x53, /* 000003C8 "ID...._S" */ - 0x54,0x41,0x00,0x7B,0x50,0x49,0x52,0x44, /* 000003D0 "TA.{PIRD" */ - 0x0A,0x80,0x60,0xA0,0x08,0x93,0x60,0x0A, /* 000003D8 "..`...`." */ - 0x80,0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A, /* 000003E0 "........" */ - 0x0B,0x14,0x0B,0x5F,0x50,0x52,0x53,0x00, /* 000003E8 "..._PRS." */ - 0xA4,0x42,0x55,0x46,0x41,0x14,0x11,0x5F, /* 000003F0 ".BUFA.._" */ - 0x44,0x49,0x53,0x00,0x7D,0x50,0x49,0x52, /* 000003F8 "DIS.}PIR" */ - 0x44,0x0A,0x80,0x50,0x49,0x52,0x44,0x14, /* 00000400 "D..PIRD." */ - 0x1A,0x5F,0x43,0x52,0x53,0x00,0x7B,0x50, /* 00000408 "._CRS.{P" */ - 0x49,0x52,0x44,0x0A,0x0F,0x60,0x79,0x01, /* 00000410 "IRD..`y." */ - 0x60,0x49,0x52,0x51,0x56,0xA4,0x42,0x55, /* 00000418 "`IRQV.BU" */ - 0x46,0x42,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000420 "FB.._SRS" */ - 0x01,0x8B,0x68,0x01,0x49,0x52,0x51,0x31, /* 00000428 "..h.IRQ1" */ - 0x82,0x49,0x52,0x51,0x31,0x60,0x76,0x60, /* 00000430 ".IRQ1`v`" */ - 0x70,0x60,0x50,0x49,0x52,0x44,0x5B,0x82, /* 00000438 "p`PIRD[." */ - 0x3A,0x48,0x50,0x45,0x54,0x08,0x5F,0x48, /* 00000440 ":HPET._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x01,0x03,0x08, /* 00000448 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x00,0x08,0x5F,0x43, /* 00000450 "_UID.._C" */ - 0x52,0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17, /* 00000458 "RS......" */ - 0x00,0x00,0x0D,0x01,0x00,0x00,0x00,0x00, /* 00000460 "........" */ - 0x00,0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE, /* 00000468 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, /* 00000470 "........" */ - 0x79,0x00,0x14,0x16,0x5F,0x50,0x52,0x54, /* 00000478 "y..._PRT" */ - 0x00,0xA0,0x0A,0x50,0x49,0x43,0x44,0xA4, /* 00000480 "...PICD." */ - 0x50,0x52,0x54,0x41,0xA4,0x50,0x52,0x54, /* 00000488 "PRTA.PRT" */ - 0x50,0x08,0x50,0x52,0x54,0x50,0x12,0x49, /* 00000490 "P.PRTP.I" */ - 0x36,0x3C,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000498 "6<......" */ - 0x01,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 000004A0 "...LNKB." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000004A8 "........" */ - 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 000004B0 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x02, /* 000004B8 "........" */ - 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 000004C0 "LNKD...." */ - 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03,0x4C, /* 000004C8 ".......L" */ - 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000004D0 "NKA....." */ - 0xFF,0xFF,0x02,0x00,0x00,0x4C,0x4E,0x4B, /* 000004D8 ".....LNK" */ - 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000004E0 "C......." */ - 0x02,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 000004E8 "...LNKD." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 000004F0 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 000004F8 "..LNKA.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 00000500 "........" */ - 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000508 ".LNKB..." */ - 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x00,0x4C, /* 00000510 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000518 "NKD....." */ - 0xFF,0xFF,0x03,0x00,0x01,0x4C,0x4E,0x4B, /* 00000520 ".....LNK" */ - 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000528 "A......." */ - 0x03,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000530 "....LNKB" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03, /* 00000538 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000540 "...LNKC." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000548 "........" */ - 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 00000550 ".LNKA..." */ - 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x01,0x4C, /* 00000558 ".......L" */ - 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 00000560 "NKB....." */ - 0xFF,0xFF,0x04,0x00,0x0A,0x02,0x4C,0x4E, /* 00000568 "......LN" */ - 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000570 "KC......" */ - 0xFF,0x04,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000578 ".....LNK" */ - 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000580 "D......." */ - 0x05,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 00000588 "...LNKB." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 00000590 "........" */ - 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000598 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x02, /* 000005A0 "........" */ - 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 000005A8 "LNKD...." */ - 0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x03,0x4C, /* 000005B0 ".......L" */ - 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000005B8 "NKA....." */ - 0xFF,0xFF,0x06,0x00,0x00,0x4C,0x4E,0x4B, /* 000005C0 ".....LNK" */ - 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000005C8 "C......." */ - 0x06,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 000005D0 "...LNKD." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 000005D8 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 000005E0 "..LNKA.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x0A, /* 000005E8 "........" */ - 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000005F0 ".LNKB..." */ - 0x04,0x0C,0xFF,0xFF,0x07,0x00,0x00,0x4C, /* 000005F8 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 00000600 "NKD....." */ - 0xFF,0xFF,0x07,0x00,0x01,0x4C,0x4E,0x4B, /* 00000608 ".....LNK" */ - 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000610 "A......." */ - 0x07,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000618 "....LNKB" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x07, /* 00000620 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000628 "...LNKC." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x08,0x00, /* 00000630 "........" */ - 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 00000638 ".LNKA..." */ - 0x04,0x0C,0xFF,0xFF,0x08,0x00,0x01,0x4C, /* 00000640 ".......L" */ - 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 00000648 "NKB....." */ - 0xFF,0xFF,0x08,0x00,0x0A,0x02,0x4C,0x4E, /* 00000650 "......LN" */ - 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000658 "KC......" */ - 0xFF,0x08,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000660 ".....LNK" */ - 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000668 "D......." */ - 0x09,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 00000670 "...LNKB." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x09,0x00, /* 00000678 "........" */ - 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000680 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x02, /* 00000688 "........" */ - 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000690 "LNKD...." */ - 0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x03,0x4C, /* 00000698 ".......L" */ - 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000006A0 "NKA....." */ - 0xFF,0xFF,0x0A,0x00,0x00,0x4C,0x4E,0x4B, /* 000006A8 ".....LNK" */ - 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006B0 "C......." */ - 0x0A,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 000006B8 "...LNKD." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 000006C0 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 000006C8 "..LNKA.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x0A, /* 000006D0 "........" */ - 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000006D8 ".LNKB..." */ - 0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x00,0x4C, /* 000006E0 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000006E8 "NKD....." */ - 0xFF,0xFF,0x0B,0x00,0x01,0x4C,0x4E,0x4B, /* 000006F0 ".....LNK" */ - 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000006F8 "A......." */ - 0x0B,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 00000700 "....LNKB" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000708 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 00000710 "...LNKC." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0C,0x00, /* 00000718 "........" */ - 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 00000720 ".LNKA..." */ - 0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x01,0x4C, /* 00000728 ".......L" */ - 0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C, /* 00000730 "NKB....." */ - 0xFF,0xFF,0x0C,0x00,0x0A,0x02,0x4C,0x4E, /* 00000738 "......LN" */ - 0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000740 "KC......" */ - 0xFF,0x0C,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000748 ".....LNK" */ - 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000750 "D......." */ - 0x0D,0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00, /* 00000758 "...LNKB." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0D,0x00, /* 00000760 "........" */ - 0x01,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E, /* 00000768 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x02, /* 00000770 "........" */ - 0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04, /* 00000778 "LNKD...." */ - 0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x03,0x4C, /* 00000780 ".......L" */ - 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000788 "NKA....." */ - 0xFF,0xFF,0x0E,0x00,0x00,0x4C,0x4E,0x4B, /* 00000790 ".....LNK" */ - 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000798 "C......." */ - 0x0E,0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00, /* 000007A0 "...LNKD." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 000007A8 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12, /* 000007B0 "..LNKA.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x0A, /* 000007B8 "........" */ - 0x03,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000007C0 ".LNKB..." */ - 0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x00,0x4C, /* 000007C8 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000007D0 "NKD....." */ - 0xFF,0xFF,0x0F,0x00,0x01,0x4C,0x4E,0x4B, /* 000007D8 ".....LNK" */ - 0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000007E0 "A......." */ - 0x0F,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 000007E8 "....LNKB" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0F, /* 000007F0 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00, /* 000007F8 "...LNKC." */ - 0x08,0x50,0x52,0x54,0x41,0x12,0x41,0x2F, /* 00000800 ".PRTA.A/" */ - 0x3C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01, /* 00000808 "<......." */ - 0x00,0x00,0x00,0x0A,0x14,0x12,0x0B,0x04, /* 00000810 "........" */ - 0x0C,0xFF,0xFF,0x01,0x00,0x01,0x00,0x0A, /* 00000818 "........" */ - 0x15,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x01, /* 00000820 "........" */ - 0x00,0x0A,0x02,0x00,0x0A,0x16,0x12,0x0C, /* 00000828 "........" */ - 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03, /* 00000830 "........" */ - 0x00,0x0A,0x17,0x12,0x0B,0x04,0x0C,0xFF, /* 00000838 "........" */ - 0xFF,0x02,0x00,0x00,0x00,0x0A,0x18,0x12, /* 00000840 "........" */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01, /* 00000848 "........" */ - 0x00,0x0A,0x19,0x12,0x0C,0x04,0x0C,0xFF, /* 00000850 "........" */ - 0xFF,0x02,0x00,0x0A,0x02,0x00,0x0A,0x1A, /* 00000858 "........" */ - 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000860 "........" */ - 0x0A,0x03,0x00,0x0A,0x1B,0x12,0x0B,0x04, /* 00000868 "........" */ - 0x0C,0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A, /* 00000870 "........" */ - 0x1C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03, /* 00000878 "........" */ - 0x00,0x01,0x00,0x0A,0x1D,0x12,0x0C,0x04, /* 00000880 "........" */ - 0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02,0x00, /* 00000888 "........" */ - 0x0A,0x1E,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000890 "........" */ - 0x03,0x00,0x0A,0x03,0x00,0x0A,0x1F,0x12, /* 00000898 "........" */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x00, /* 000008A0 "........" */ - 0x00,0x0A,0x20,0x12,0x0B,0x04,0x0C,0xFF, /* 000008A8 ".. ....." */ - 0xFF,0x04,0x00,0x01,0x00,0x0A,0x21,0x12, /* 000008B0 "......!." */ - 0x0C,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A, /* 000008B8 "........" */ - 0x02,0x00,0x0A,0x22,0x12,0x0C,0x04,0x0C, /* 000008C0 "..."...." */ - 0xFF,0xFF,0x04,0x00,0x0A,0x03,0x00,0x0A, /* 000008C8 "........" */ - 0x23,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x05, /* 000008D0 "#......." */ - 0x00,0x00,0x00,0x0A,0x24,0x12,0x0B,0x04, /* 000008D8 "....$..." */ - 0x0C,0xFF,0xFF,0x05,0x00,0x01,0x00,0x0A, /* 000008E0 "........" */ - 0x25,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x05, /* 000008E8 "%......." */ - 0x00,0x0A,0x02,0x00,0x0A,0x26,0x12,0x0C, /* 000008F0 ".....&.." */ - 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x03, /* 000008F8 "........" */ - 0x00,0x0A,0x27,0x12,0x0B,0x04,0x0C,0xFF, /* 00000900 "..'....." */ - 0xFF,0x06,0x00,0x00,0x00,0x0A,0x28,0x12, /* 00000908 "......(." */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01, /* 00000910 "........" */ - 0x00,0x0A,0x29,0x12,0x0C,0x04,0x0C,0xFF, /* 00000918 "..)....." */ - 0xFF,0x06,0x00,0x0A,0x02,0x00,0x0A,0x2A, /* 00000920 ".......*" */ - 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 00000928 "........" */ - 0x0A,0x03,0x00,0x0A,0x2B,0x12,0x0B,0x04, /* 00000930 "....+..." */ - 0x0C,0xFF,0xFF,0x07,0x00,0x00,0x00,0x0A, /* 00000938 "........" */ - 0x2C,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x07, /* 00000940 ",......." */ - 0x00,0x01,0x00,0x0A,0x2D,0x12,0x0C,0x04, /* 00000948 "....-..." */ - 0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02,0x00, /* 00000950 "........" */ - 0x0A,0x2E,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000958 "........" */ - 0x07,0x00,0x0A,0x03,0x00,0x0A,0x2F,0x12, /* 00000960 "....../." */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x00, /* 00000968 "........" */ - 0x00,0x0A,0x11,0x12,0x0B,0x04,0x0C,0xFF, /* 00000970 "........" */ - 0xFF,0x08,0x00,0x01,0x00,0x0A,0x12,0x12, /* 00000978 "........" */ - 0x0C,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A, /* 00000980 "........" */ - 0x02,0x00,0x0A,0x13,0x12,0x0C,0x04,0x0C, /* 00000988 "........" */ - 0xFF,0xFF,0x08,0x00,0x0A,0x03,0x00,0x0A, /* 00000990 "........" */ - 0x14,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x09, /* 00000998 "........" */ - 0x00,0x00,0x00,0x0A,0x15,0x12,0x0B,0x04, /* 000009A0 "........" */ - 0x0C,0xFF,0xFF,0x09,0x00,0x01,0x00,0x0A, /* 000009A8 "........" */ - 0x16,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x09, /* 000009B0 "........" */ - 0x00,0x0A,0x02,0x00,0x0A,0x17,0x12,0x0C, /* 000009B8 "........" */ - 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x03, /* 000009C0 "........" */ - 0x00,0x0A,0x18,0x12,0x0B,0x04,0x0C,0xFF, /* 000009C8 "........" */ - 0xFF,0x0A,0x00,0x00,0x00,0x0A,0x19,0x12, /* 000009D0 "........" */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01, /* 000009D8 "........" */ - 0x00,0x0A,0x1A,0x12,0x0C,0x04,0x0C,0xFF, /* 000009E0 "........" */ - 0xFF,0x0A,0x00,0x0A,0x02,0x00,0x0A,0x1B, /* 000009E8 "........" */ - 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 000009F0 "........" */ - 0x0A,0x03,0x00,0x0A,0x1C,0x12,0x0B,0x04, /* 000009F8 "........" */ - 0x0C,0xFF,0xFF,0x0B,0x00,0x00,0x00,0x0A, /* 00000A00 "........" */ - 0x1D,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000A08 "........" */ - 0x00,0x01,0x00,0x0A,0x1E,0x12,0x0C,0x04, /* 00000A10 "........" */ - 0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02,0x00, /* 00000A18 "........" */ - 0x0A,0x1F,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000A20 "........" */ - 0x0B,0x00,0x0A,0x03,0x00,0x0A,0x20,0x12, /* 00000A28 "...... ." */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x00, /* 00000A30 "........" */ - 0x00,0x0A,0x21,0x12,0x0B,0x04,0x0C,0xFF, /* 00000A38 "..!....." */ - 0xFF,0x0C,0x00,0x01,0x00,0x0A,0x22,0x12, /* 00000A40 "......"." */ - 0x0C,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A, /* 00000A48 "........" */ - 0x02,0x00,0x0A,0x23,0x12,0x0C,0x04,0x0C, /* 00000A50 "...#...." */ - 0xFF,0xFF,0x0C,0x00,0x0A,0x03,0x00,0x0A, /* 00000A58 "........" */ - 0x24,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0D, /* 00000A60 "$......." */ - 0x00,0x00,0x00,0x0A,0x25,0x12,0x0B,0x04, /* 00000A68 "....%..." */ - 0x0C,0xFF,0xFF,0x0D,0x00,0x01,0x00,0x0A, /* 00000A70 "........" */ - 0x26,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0D, /* 00000A78 "&......." */ - 0x00,0x0A,0x02,0x00,0x0A,0x27,0x12,0x0C, /* 00000A80 ".....'.." */ - 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x03, /* 00000A88 "........" */ - 0x00,0x0A,0x28,0x12,0x0B,0x04,0x0C,0xFF, /* 00000A90 "..(....." */ - 0xFF,0x0E,0x00,0x00,0x00,0x0A,0x29,0x12, /* 00000A98 "......)." */ - 0x0B,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01, /* 00000AA0 "........" */ - 0x00,0x0A,0x2A,0x12,0x0C,0x04,0x0C,0xFF, /* 00000AA8 "..*....." */ - 0xFF,0x0E,0x00,0x0A,0x02,0x00,0x0A,0x2B, /* 00000AB0 ".......+" */ - 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 00000AB8 "........" */ - 0x0A,0x03,0x00,0x0A,0x2C,0x12,0x0B,0x04, /* 00000AC0 "....,..." */ - 0x0C,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x0A, /* 00000AC8 "........" */ - 0x2D,0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0F, /* 00000AD0 "-......." */ - 0x00,0x01,0x00,0x0A,0x2E,0x12,0x0C,0x04, /* 00000AD8 "........" */ - 0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02,0x00, /* 00000AE0 "........" */ - 0x0A,0x2F,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000AE8 "./......" */ - 0x0F,0x00,0x0A,0x03,0x00,0x0A,0x10,0x5B, /* 00000AF0 ".......[" */ - 0x82,0x46,0x37,0x49,0x53,0x41,0x5F,0x08, /* 00000AF8 ".F7ISA_." */ - 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 00000B00 "_ADR...." */ - 0x00,0x5B,0x80,0x50,0x49,0x52,0x51,0x02, /* 00000B08 ".[.PIRQ." */ - 0x0A,0x60,0x0A,0x04,0x10,0x2E,0x5C,0x00, /* 00000B10 ".`....\." */ - 0x5B,0x81,0x29,0x5C,0x2F,0x04,0x5F,0x53, /* 00000B18 "[.)\/._S" */ - 0x42,0x5F,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000B20 "B_PCI0IS" */ - 0x41,0x5F,0x50,0x49,0x52,0x51,0x01,0x50, /* 00000B28 "A_PIRQ.P" */ - 0x49,0x52,0x41,0x08,0x50,0x49,0x52,0x42, /* 00000B30 "IRA.PIRB" */ - 0x08,0x50,0x49,0x52,0x43,0x08,0x50,0x49, /* 00000B38 ".PIRC.PI" */ - 0x52,0x44,0x08,0x5B,0x82,0x46,0x0B,0x53, /* 00000B40 "RD.[.F.S" */ - 0x59,0x53,0x52,0x08,0x5F,0x48,0x49,0x44, /* 00000B48 "YSR._HID" */ - 0x0C,0x41,0xD0,0x0C,0x02,0x08,0x5F,0x55, /* 00000B50 ".A...._U" */ - 0x49,0x44,0x01,0x08,0x43,0x52,0x53,0x5F, /* 00000B58 "ID..CRS_" */ - 0x11,0x4E,0x08,0x0A,0x8A,0x47,0x01,0x10, /* 00000B60 ".N...G.." */ - 0x00,0x10,0x00,0x00,0x10,0x47,0x01,0x22, /* 00000B68 ".....G."" */ - 0x00,0x22,0x00,0x00,0x0C,0x47,0x01,0x30, /* 00000B70 "."...G.0" */ - 0x00,0x30,0x00,0x00,0x10,0x47,0x01,0x44, /* 00000B78 ".0...G.D" */ - 0x00,0x44,0x00,0x00,0x1C,0x47,0x01,0x62, /* 00000B80 ".D...G.b" */ - 0x00,0x62,0x00,0x00,0x02,0x47,0x01,0x65, /* 00000B88 ".b...G.e" */ - 0x00,0x65,0x00,0x00,0x0B,0x47,0x01,0x72, /* 00000B90 ".e...G.r" */ - 0x00,0x72,0x00,0x00,0x0E,0x47,0x01,0x80, /* 00000B98 ".r...G.." */ - 0x00,0x80,0x00,0x00,0x01,0x47,0x01,0x84, /* 00000BA0 ".....G.." */ - 0x00,0x84,0x00,0x00,0x03,0x47,0x01,0x88, /* 00000BA8 ".....G.." */ - 0x00,0x88,0x00,0x00,0x01,0x47,0x01,0x8C, /* 00000BB0 ".....G.." */ - 0x00,0x8C,0x00,0x00,0x03,0x47,0x01,0x90, /* 00000BB8 ".....G.." */ - 0x00,0x90,0x00,0x00,0x10,0x47,0x01,0xA2, /* 00000BC0 ".....G.." */ - 0x00,0xA2,0x00,0x00,0x1C,0x47,0x01,0xE0, /* 00000BC8 ".....G.." */ - 0x00,0xE0,0x00,0x00,0x10,0x47,0x01,0xA0, /* 00000BD0 ".....G.." */ - 0x08,0xA0,0x08,0x00,0x04,0x47,0x01,0xC0, /* 00000BD8 ".....G.." */ - 0x0C,0xC0,0x0C,0x00,0x10,0x47,0x01,0xD0, /* 00000BE0 ".....G.." */ - 0x04,0xD0,0x04,0x00,0x02,0x79,0x00,0x14, /* 00000BE8 ".....y.." */ - 0x0B,0x5F,0x43,0x52,0x53,0x00,0xA4,0x43, /* 00000BF0 "._CRS..C" */ - 0x52,0x53,0x5F,0x5B,0x82,0x2B,0x50,0x49, /* 00000BF8 "RS_[.+PI" */ - 0x43,0x5F,0x08,0x5F,0x48,0x49,0x44,0x0B, /* 00000C00 "C_._HID." */ - 0x41,0xD0,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000C08 "A.._CRS." */ - 0x18,0x0A,0x15,0x47,0x01,0x20,0x00,0x20, /* 00000C10 "...G. . " */ - 0x00,0x01,0x02,0x47,0x01,0xA0,0x00,0xA0, /* 00000C18 "...G...." */ - 0x00,0x01,0x02,0x22,0x04,0x00,0x79,0x00, /* 00000C20 "..."..y." */ - 0x5B,0x82,0x47,0x05,0x44,0x4D,0x41,0x30, /* 00000C28 "[.G.DMA0" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000C30 "._HID.A." */ - 0x02,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000C38 "..._CRS." */ - 0x41,0x04,0x0A,0x3D,0x2A,0x10,0x04,0x47, /* 00000C40 "A..=*..G" */ - 0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x47, /* 00000C48 ".......G" */ - 0x01,0x81,0x00,0x81,0x00,0x00,0x03,0x47, /* 00000C50 ".......G" */ - 0x01,0x87,0x00,0x87,0x00,0x00,0x01,0x47, /* 00000C58 ".......G" */ - 0x01,0x89,0x00,0x89,0x00,0x00,0x03,0x47, /* 00000C60 ".......G" */ - 0x01,0x8F,0x00,0x8F,0x00,0x00,0x01,0x47, /* 00000C68 ".......G" */ - 0x01,0xC0,0x00,0xC0,0x00,0x00,0x20,0x47, /* 00000C70 "...... G" */ - 0x01,0x80,0x04,0x80,0x04,0x00,0x10,0x79, /* 00000C78 ".......y" */ - 0x00,0x5B,0x82,0x25,0x54,0x4D,0x52,0x5F, /* 00000C80 ".[.%TMR_" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000C88 "._HID.A." */ - 0x01,0x00,0x08,0x5F,0x43,0x52,0x53,0x11, /* 00000C90 "..._CRS." */ - 0x10,0x0A,0x0D,0x47,0x01,0x40,0x00,0x40, /* 00000C98 "...G.@.@" */ - 0x00,0x00,0x04,0x22,0x01,0x00,0x79,0x00, /* 00000CA0 "..."..y." */ - 0x5B,0x82,0x25,0x52,0x54,0x43,0x5F,0x08, /* 00000CA8 "[.%RTC_." */ - 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x0B, /* 00000CB0 "_HID.A.." */ - 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x10, /* 00000CB8 ".._CRS.." */ - 0x0A,0x0D,0x47,0x01,0x70,0x00,0x70,0x00, /* 00000CC0 "..G.p.p." */ - 0x00,0x02,0x22,0x00,0x01,0x79,0x00,0x5B, /* 00000CC8 ".."..y.[" */ - 0x82,0x22,0x53,0x50,0x4B,0x52,0x08,0x5F, /* 00000CD0 "."SPKR._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x08,0x00, /* 00000CD8 "HID.A..." */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x0D,0x0A, /* 00000CE0 "._CRS..." */ - 0x0A,0x47,0x01,0x61,0x00,0x61,0x00,0x00, /* 00000CE8 ".G.a.a.." */ - 0x01,0x79,0x00,0x5B,0x82,0x31,0x50,0x53, /* 00000CF0 ".y.[.1PS" */ - 0x32,0x4D,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000CF8 "2M._HID." */ - 0x41,0xD0,0x0F,0x13,0x08,0x5F,0x43,0x49, /* 00000D00 "A...._CI" */ - 0x44,0x0C,0x41,0xD0,0x0F,0x13,0x14,0x09, /* 00000D08 "D.A....." */ - 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000D10 "_STA...." */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x08,0x0A, /* 00000D18 "._CRS..." */ - 0x05,0x22,0x00,0x10,0x79,0x00,0x5B,0x82, /* 00000D20 "."..y.[." */ - 0x42,0x04,0x50,0x53,0x32,0x4B,0x08,0x5F, /* 00000D28 "B.PS2K._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x03,0x03, /* 00000D30 "HID.A..." */ - 0x08,0x5F,0x43,0x49,0x44,0x0C,0x41,0xD0, /* 00000D38 "._CID.A." */ - 0x03,0x0B,0x14,0x09,0x5F,0x53,0x54,0x41, /* 00000D40 "...._STA" */ - 0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 00000D48 "....._CR" */ - 0x53,0x11,0x18,0x0A,0x15,0x47,0x01,0x60, /* 00000D50 "S....G.`" */ - 0x00,0x60,0x00,0x00,0x01,0x47,0x01,0x64, /* 00000D58 ".`...G.d" */ - 0x00,0x64,0x00,0x00,0x01,0x22,0x02,0x00, /* 00000D60 ".d...".." */ - 0x79,0x00,0x5B,0x82,0x3A,0x46,0x44,0x43, /* 00000D68 "y.[.:FDC" */ - 0x30,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000D70 "0._HID.A" */ - 0xD0,0x07,0x00,0x14,0x09,0x5F,0x53,0x54, /* 00000D78 "....._ST" */ - 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000D80 "A....._C" */ - 0x52,0x53,0x11,0x1B,0x0A,0x18,0x47,0x01, /* 00000D88 "RS....G." */ - 0xF0,0x03,0xF0,0x03,0x01,0x06,0x47,0x01, /* 00000D90 "......G." */ - 0xF7,0x03,0xF7,0x03,0x01,0x01,0x22,0x40, /* 00000D98 "......"@" */ - 0x00,0x2A,0x04,0x00,0x79,0x00,0x5B,0x82, /* 00000DA0 ".*..y.[." */ - 0x46,0x04,0x55,0x41,0x52,0x31,0x08,0x5F, /* 00000DA8 "F.UAR1._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x05,0x01, /* 00000DB0 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x01,0x14,0x19, /* 00000DB8 "._UID..." */ - 0x5F,0x53,0x54,0x41,0x00,0xA0,0x0D,0x93, /* 00000DC0 "_STA...." */ - 0x5E,0x5E,0x5E,0x5E,0x55,0x41,0x52,0x31, /* 00000DC8 "^^^^UAR1" */ - 0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F, /* 00000DD0 "........" */ - 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000DD8 "._CRS..." */ - 0x0D,0x47,0x01,0xF8,0x03,0xF8,0x03,0x08, /* 00000DE0 ".G......" */ - 0x08,0x22,0x10,0x00,0x79,0x00,0x5B,0x82, /* 00000DE8 "."..y.[." */ - 0x47,0x04,0x55,0x41,0x52,0x32,0x08,0x5F, /* 00000DF0 "G.UAR2._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x05,0x01, /* 00000DF8 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x0A,0x02,0x14, /* 00000E00 "._UID..." */ - 0x19,0x5F,0x53,0x54,0x41,0x00,0xA0,0x0D, /* 00000E08 "._STA..." */ - 0x93,0x5E,0x5E,0x5E,0x5E,0x55,0x41,0x52, /* 00000E10 ".^^^^UAR" */ - 0x32,0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A, /* 00000E18 "2......." */ - 0x0F,0x08,0x5F,0x43,0x52,0x53,0x11,0x10, /* 00000E20 ".._CRS.." */ - 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 00000E28 "..G....." */ - 0x08,0x08,0x22,0x08,0x00,0x79,0x00,0x5B, /* 00000E30 ".."..y.[" */ - 0x82,0x36,0x4C,0x54,0x50,0x31,0x08,0x5F, /* 00000E38 ".6LTP1._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x04,0x00, /* 00000E40 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x0A,0x02,0x14, /* 00000E48 "._UID..." */ - 0x09,0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A, /* 00000E50 "._STA..." */ - 0x0F,0x08,0x5F,0x43,0x52,0x53,0x11,0x10, /* 00000E58 ".._CRS.." */ - 0x0A,0x0D,0x47,0x01,0x78,0x03,0x78,0x03, /* 00000E60 "..G.x.x." */ - 0x08,0x08,0x22,0x80,0x00,0x79,0x00, + 0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00, /* 000000F0 "........" */ + 0x00,0x00,0x00,0x79,0x00,0x5B,0x82,0x4F, /* 000000F8 "...y.[.O" */ + 0xD8,0x50,0x43,0x49,0x30,0x08,0x5F,0x48, /* 00000100 ".PCI0._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03,0x08, /* 00000108 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x00,0x08,0x5F,0x41, /* 00000110 "_UID.._A" */ + 0x44,0x52,0x00,0x08,0x5F,0x42,0x42,0x4E, /* 00000118 "DR.._BBN" */ + 0x00,0x14,0x4E,0x0C,0x5F,0x43,0x52,0x53, /* 00000120 "..N._CRS" */ + 0x00,0x08,0x50,0x52,0x54,0x30,0x11,0x42, /* 00000128 "..PRT0.B" */ + 0x07,0x0A,0x6E,0x88,0x0D,0x00,0x02,0x0E, /* 00000130 "..n....." */ + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, /* 00000138 "........" */ + 0x00,0x00,0x01,0x47,0x01,0xF8,0x0C,0xF8, /* 00000140 "...G...." */ + 0x0C,0x01,0x08,0x88,0x0D,0x00,0x01,0x0C, /* 00000148 "........" */ + 0x03,0x00,0x00,0x00,0x00,0xF7,0x0C,0x00, /* 00000150 "........" */ + 0x00,0xF8,0x0C,0x88,0x0D,0x00,0x01,0x0C, /* 00000158 "........" */ + 0x03,0x00,0x00,0x00,0x0D,0xFF,0xFF,0x00, /* 00000160 "........" */ + 0x00,0x00,0xF3,0x87,0x17,0x00,0x00,0x0C, /* 00000168 "........" */ + 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x0A, /* 00000170 "........" */ + 0x00,0xFF,0xFF,0x0B,0x00,0x00,0x00,0x00, /* 00000178 "........" */ + 0x00,0x00,0x00,0x02,0x00,0x87,0x17,0x00, /* 00000180 "........" */ + 0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00, /* 00000188 "........" */ + 0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xF4,0x00, /* 00000190 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x79, /* 00000198 ".......y" */ + 0x00,0x8A,0x50,0x52,0x54,0x30,0x0A,0x5C, /* 000001A0 "..PRT0.\" */ + 0x4D,0x4D,0x49,0x4E,0x8A,0x50,0x52,0x54, /* 000001A8 "MMIN.PRT" */ + 0x30,0x0A,0x60,0x4D,0x4D,0x41,0x58,0x8A, /* 000001B0 "0.`MMAX." */ + 0x50,0x52,0x54,0x30,0x0A,0x68,0x4D,0x4C, /* 000001B8 "PRT0.hML" */ + 0x45,0x4E,0x70,0x50,0x4D,0x49,0x4E,0x4D, /* 000001C0 "ENpPMINM" */ + 0x4D,0x49,0x4E,0x70,0x50,0x4C,0x45,0x4E, /* 000001C8 "MINpPLEN" */ + 0x4D,0x4C,0x45,0x4E,0x72,0x4D,0x4D,0x49, /* 000001D0 "MLENrMMI" */ + 0x4E,0x4D,0x4C,0x45,0x4E,0x4D,0x4D,0x41, /* 000001D8 "NMLENMMA" */ + 0x58,0x74,0x4D,0x4D,0x41,0x58,0x01,0x4D, /* 000001E0 "XtMMAX.M" */ + 0x4D,0x41,0x58,0xA4,0x50,0x52,0x54,0x30, /* 000001E8 "MAX.PRT0" */ + 0x08,0x42,0x55,0x46,0x41,0x11,0x09,0x0A, /* 000001F0 ".BUFA..." */ + 0x06,0x23,0x20,0x0C,0x18,0x79,0x00,0x08, /* 000001F8 ".# ..y.." */ + 0x42,0x55,0x46,0x42,0x11,0x09,0x0A,0x06, /* 00000200 "BUFB...." */ + 0x23,0x00,0x00,0x18,0x79,0x00,0x8B,0x42, /* 00000208 "#...y..B" */ + 0x55,0x46,0x42,0x01,0x49,0x52,0x51,0x56, /* 00000210 "UFB.IRQV" */ + 0x5B,0x82,0x48,0x08,0x4C,0x4E,0x4B,0x41, /* 00000218 "[.H.LNKA" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000220 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x01, /* 00000228 "..._UID." */ + 0x14,0x1C,0x5F,0x53,0x54,0x41,0x00,0x7B, /* 00000230 ".._STA.{" */ + 0x50,0x49,0x52,0x41,0x0A,0x80,0x60,0xA0, /* 00000238 "PIRA..`." */ + 0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A,0x09, /* 00000240 "..`....." */ + 0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B,0x5F, /* 00000248 "......._" */ + 0x50,0x52,0x53,0x00,0xA4,0x42,0x55,0x46, /* 00000250 "PRS..BUF" */ + 0x41,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 00000258 "A.._DIS." */ + 0x7D,0x50,0x49,0x52,0x41,0x0A,0x80,0x50, /* 00000260 "}PIRA..P" */ + 0x49,0x52,0x41,0x14,0x1A,0x5F,0x43,0x52, /* 00000268 "IRA.._CR" */ + 0x53,0x00,0x7B,0x50,0x49,0x52,0x41,0x0A, /* 00000270 "S.{PIRA." */ + 0x0F,0x60,0x79,0x01,0x60,0x49,0x52,0x51, /* 00000278 ".`y.`IRQ" */ + 0x56,0xA4,0x42,0x55,0x46,0x42,0x14,0x1B, /* 00000280 "V.BUFB.." */ + 0x5F,0x53,0x52,0x53,0x01,0x8B,0x68,0x01, /* 00000288 "_SRS..h." */ + 0x49,0x52,0x51,0x31,0x82,0x49,0x52,0x51, /* 00000290 "IRQ1.IRQ" */ + 0x31,0x60,0x76,0x60,0x70,0x60,0x50,0x49, /* 00000298 "1`v`p`PI" */ + 0x52,0x41,0x5B,0x82,0x49,0x08,0x4C,0x4E, /* 000002A0 "RA[.I.LN" */ + 0x4B,0x42,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 000002A8 "KB._HID." */ + 0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49, /* 000002B0 "A...._UI" */ + 0x44,0x0A,0x02,0x14,0x1C,0x5F,0x53,0x54, /* 000002B8 "D...._ST" */ + 0x41,0x00,0x7B,0x50,0x49,0x52,0x42,0x0A, /* 000002C0 "A.{PIRB." */ + 0x80,0x60,0xA0,0x08,0x93,0x60,0x0A,0x80, /* 000002C8 ".`...`.." */ + 0xA4,0x0A,0x09,0xA1,0x04,0xA4,0x0A,0x0B, /* 000002D0 "........" */ + 0x14,0x0B,0x5F,0x50,0x52,0x53,0x00,0xA4, /* 000002D8 ".._PRS.." */ + 0x42,0x55,0x46,0x41,0x14,0x11,0x5F,0x44, /* 000002E0 "BUFA.._D" */ + 0x49,0x53,0x00,0x7D,0x50,0x49,0x52,0x42, /* 000002E8 "IS.}PIRB" */ + 0x0A,0x80,0x50,0x49,0x52,0x42,0x14,0x1A, /* 000002F0 "..PIRB.." */ + 0x5F,0x43,0x52,0x53,0x00,0x7B,0x50,0x49, /* 000002F8 "_CRS.{PI" */ + 0x52,0x42,0x0A,0x0F,0x60,0x79,0x01,0x60, /* 00000300 "RB..`y.`" */ + 0x49,0x52,0x51,0x56,0xA4,0x42,0x55,0x46, /* 00000308 "IRQV.BUF" */ + 0x42,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000310 "B.._SRS." */ + 0x8B,0x68,0x01,0x49,0x52,0x51,0x31,0x82, /* 00000318 ".h.IRQ1." */ + 0x49,0x52,0x51,0x31,0x60,0x76,0x60,0x70, /* 00000320 "IRQ1`v`p" */ + 0x60,0x50,0x49,0x52,0x42,0x5B,0x82,0x49, /* 00000328 "`PIRB[.I" */ + 0x08,0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48, /* 00000330 ".LNKC._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000338 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x03,0x14,0x1C, /* 00000340 "_UID...." */ + 0x5F,0x53,0x54,0x41,0x00,0x7B,0x50,0x49, /* 00000348 "_STA.{PI" */ + 0x52,0x43,0x0A,0x80,0x60,0xA0,0x08,0x93, /* 00000350 "RC..`..." */ + 0x60,0x0A,0x80,0xA4,0x0A,0x09,0xA1,0x04, /* 00000358 "`......." */ + 0xA4,0x0A,0x0B,0x14,0x0B,0x5F,0x50,0x52, /* 00000360 "....._PR" */ + 0x53,0x00,0xA4,0x42,0x55,0x46,0x41,0x14, /* 00000368 "S..BUFA." */ + 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000370 "._DIS.}P" */ + 0x49,0x52,0x43,0x0A,0x80,0x50,0x49,0x52, /* 00000378 "IRC..PIR" */ + 0x43,0x14,0x1A,0x5F,0x43,0x52,0x53,0x00, /* 00000380 "C.._CRS." */ + 0x7B,0x50,0x49,0x52,0x43,0x0A,0x0F,0x60, /* 00000388 "{PIRC..`" */ + 0x79,0x01,0x60,0x49,0x52,0x51,0x56,0xA4, /* 00000390 "y.`IRQV." */ + 0x42,0x55,0x46,0x42,0x14,0x1B,0x5F,0x53, /* 00000398 "BUFB.._S" */ + 0x52,0x53,0x01,0x8B,0x68,0x01,0x49,0x52, /* 000003A0 "RS..h.IR" */ + 0x51,0x31,0x82,0x49,0x52,0x51,0x31,0x60, /* 000003A8 "Q1.IRQ1`" */ + 0x76,0x60,0x70,0x60,0x50,0x49,0x52,0x43, /* 000003B0 "v`p`PIRC" */ + 0x5B,0x82,0x49,0x08,0x4C,0x4E,0x4B,0x44, /* 000003B8 "[.I.LNKD" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C0 "._HID.A." */ + 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000003C8 "..._UID." */ + 0x04,0x14,0x1C,0x5F,0x53,0x54,0x41,0x00, /* 000003D0 "..._STA." */ + 0x7B,0x50,0x49,0x52,0x44,0x0A,0x80,0x60, /* 000003D8 "{PIRD..`" */ + 0xA0,0x08,0x93,0x60,0x0A,0x80,0xA4,0x0A, /* 000003E0 "...`...." */ + 0x09,0xA1,0x04,0xA4,0x0A,0x0B,0x14,0x0B, /* 000003E8 "........" */ + 0x5F,0x50,0x52,0x53,0x00,0xA4,0x42,0x55, /* 000003F0 "_PRS..BU" */ + 0x46,0x41,0x14,0x11,0x5F,0x44,0x49,0x53, /* 000003F8 "FA.._DIS" */ + 0x00,0x7D,0x50,0x49,0x52,0x44,0x0A,0x80, /* 00000400 ".}PIRD.." */ + 0x50,0x49,0x52,0x44,0x14,0x1A,0x5F,0x43, /* 00000408 "PIRD.._C" */ + 0x52,0x53,0x00,0x7B,0x50,0x49,0x52,0x44, /* 00000410 "RS.{PIRD" */ + 0x0A,0x0F,0x60,0x79,0x01,0x60,0x49,0x52, /* 00000418 "..`y.`IR" */ + 0x51,0x56,0xA4,0x42,0x55,0x46,0x42,0x14, /* 00000420 "QV.BUFB." */ + 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 00000428 "._SRS..h" */ + 0x01,0x49,0x52,0x51,0x31,0x82,0x49,0x52, /* 00000430 ".IRQ1.IR" */ + 0x51,0x31,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000438 "Q1`v`p`P" */ + 0x49,0x52,0x44,0x5B,0x82,0x44,0x05,0x48, /* 00000440 "IRD[.D.H" */ + 0x50,0x45,0x54,0x08,0x5F,0x48,0x49,0x44, /* 00000448 "PET._HID" */ + 0x0C,0x41,0xD0,0x01,0x03,0x08,0x5F,0x55, /* 00000450 ".A...._U" */ + 0x49,0x44,0x00,0x14,0x18,0x5F,0x53,0x54, /* 00000458 "ID..._ST" */ + 0x41,0x00,0xA0,0x0C,0x93,0x5E,0x5E,0x5E, /* 00000460 "A....^^^" */ + 0x48,0x50,0x45,0x54,0x00,0xA4,0x00,0xA1, /* 00000468 "HPET...." */ + 0x04,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 00000470 "....._CR" */ + 0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17,0x00, /* 00000478 "S......." */ + 0x00,0x0D,0x01,0x00,0x00,0x00,0x00,0x00, /* 00000480 "........" */ + 0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE,0x00, /* 00000488 "........" */ + 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x79, /* 00000490 ".......y" */ + 0x00,0x14,0x16,0x5F,0x50,0x52,0x54,0x00, /* 00000498 "..._PRT." */ + 0xA0,0x0A,0x50,0x49,0x43,0x44,0xA4,0x50, /* 000004A0 "..PICD.P" */ + 0x52,0x54,0x41,0xA4,0x50,0x52,0x54,0x50, /* 000004A8 "RTA.PRTP" */ + 0x08,0x50,0x52,0x54,0x50,0x12,0x49,0x36, /* 000004B0 ".PRTP.I6" */ + 0x3C,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x01, /* 000004B8 "<......." */ + 0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000004C0 "..LNKB.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x01, /* 000004C8 "........" */ + 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 000004D0 "LNKC...." */ + 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x02,0x4C, /* 000004D8 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 000004E0 "NKD....." */ + 0xFF,0xFF,0x01,0x00,0x0A,0x03,0x4C,0x4E, /* 000004E8 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000004F0 "KA......" */ + 0xFF,0x02,0x00,0x00,0x4C,0x4E,0x4B,0x43, /* 000004F8 "....LNKC" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02, /* 00000500 "........" */ + 0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 00000508 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 00000510 "........" */ + 0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000518 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A,0x03, /* 00000520 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04, /* 00000528 "LNKB...." */ + 0x0C,0xFF,0xFF,0x03,0x00,0x00,0x4C,0x4E, /* 00000530 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000538 "KD......" */ + 0xFF,0x03,0x00,0x01,0x4C,0x4E,0x4B,0x41, /* 00000540 "....LNKA" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03, /* 00000548 "........" */ + 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00, /* 00000550 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000558 "........" */ + 0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 00000560 "..LNKC.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x00, /* 00000568 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 00000570 "LNKA...." */ + 0x0C,0xFF,0xFF,0x04,0x00,0x01,0x4C,0x4E, /* 00000578 "......LN" */ + 0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000580 "KB......" */ + 0xFF,0x04,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000588 ".....LNK" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000590 "C......." */ + 0x04,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44, /* 00000598 "....LNKD" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x05, /* 000005A0 "........" */ + 0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000005A8 "..LNKB.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x01, /* 000005B0 "........" */ + 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 000005B8 "LNKC...." */ + 0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x02,0x4C, /* 000005C0 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 000005C8 "NKD....." */ + 0xFF,0xFF,0x05,0x00,0x0A,0x03,0x4C,0x4E, /* 000005D0 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000005D8 "KA......" */ + 0xFF,0x06,0x00,0x00,0x4C,0x4E,0x4B,0x43, /* 000005E0 "....LNKC" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x06, /* 000005E8 "........" */ + 0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000005F0 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x0A, /* 000005F8 "........" */ + 0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000600 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x06,0x00,0x0A,0x03, /* 00000608 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04, /* 00000610 "LNKB...." */ + 0x0C,0xFF,0xFF,0x07,0x00,0x00,0x4C,0x4E, /* 00000618 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000620 "KD......" */ + 0xFF,0x07,0x00,0x01,0x4C,0x4E,0x4B,0x41, /* 00000628 "....LNKA" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x07, /* 00000630 "........" */ + 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00, /* 00000638 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x07,0x00, /* 00000640 "........" */ + 0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 00000648 "..LNKC.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x00, /* 00000650 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 00000658 "LNKA...." */ + 0x0C,0xFF,0xFF,0x08,0x00,0x01,0x4C,0x4E, /* 00000660 "......LN" */ + 0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000668 "KB......" */ + 0xFF,0x08,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000670 ".....LNK" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000678 "C......." */ + 0x08,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44, /* 00000680 "....LNKD" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x09, /* 00000688 "........" */ + 0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000690 "..LNKB.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x09,0x00,0x01, /* 00000698 "........" */ + 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 000006A0 "LNKC...." */ + 0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x02,0x4C, /* 000006A8 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 000006B0 "NKD....." */ + 0xFF,0xFF,0x09,0x00,0x0A,0x03,0x4C,0x4E, /* 000006B8 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000006C0 "KA......" */ + 0xFF,0x0A,0x00,0x00,0x4C,0x4E,0x4B,0x43, /* 000006C8 "....LNKC" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0A, /* 000006D0 "........" */ + 0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000006D8 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x0A, /* 000006E0 "........" */ + 0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 000006E8 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x0A,0x03, /* 000006F0 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04, /* 000006F8 "LNKB...." */ + 0x0C,0xFF,0xFF,0x0B,0x00,0x00,0x4C,0x4E, /* 00000700 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 00000708 "KD......" */ + 0xFF,0x0B,0x00,0x01,0x4C,0x4E,0x4B,0x41, /* 00000710 "....LNKA" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000718 "........" */ + 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00, /* 00000720 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0B,0x00, /* 00000728 "........" */ + 0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 00000730 "..LNKC.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x00, /* 00000738 "........" */ + 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04, /* 00000740 "LNKA...." */ + 0x0C,0xFF,0xFF,0x0C,0x00,0x01,0x4C,0x4E, /* 00000748 "......LN" */ + 0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000750 "KB......" */ + 0xFF,0x0C,0x00,0x0A,0x02,0x4C,0x4E,0x4B, /* 00000758 ".....LNK" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000760 "C......." */ + 0x0C,0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44, /* 00000768 "....LNKD" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0D, /* 00000770 "........" */ + 0x00,0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000778 "..LNKB.." */ + 0x0D,0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x01, /* 00000780 "........" */ + 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 00000788 "LNKC...." */ + 0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x02,0x4C, /* 00000790 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000798 "NKD....." */ + 0xFF,0xFF,0x0D,0x00,0x0A,0x03,0x4C,0x4E, /* 000007A0 "......LN" */ + 0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000007A8 "KA......" */ + 0xFF,0x0E,0x00,0x00,0x4C,0x4E,0x4B,0x43, /* 000007B0 "....LNKC" */ + 0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0E, /* 000007B8 "........" */ + 0x00,0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000007C0 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x0A, /* 000007C8 "........" */ + 0x02,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 000007D0 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x0A,0x03, /* 000007D8 "........" */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04, /* 000007E0 "LNKB...." */ + 0x0C,0xFF,0xFF,0x0F,0x00,0x00,0x4C,0x4E, /* 000007E8 "......LN" */ + 0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF, /* 000007F0 "KD......" */ + 0xFF,0x0F,0x00,0x01,0x4C,0x4E,0x4B,0x41, /* 000007F8 "....LNKA" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0F, /* 00000800 "........" */ + 0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00, /* 00000808 "...LNKB." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0F,0x00, /* 00000810 "........" */ + 0x0A,0x03,0x4C,0x4E,0x4B,0x43,0x00,0x08, /* 00000818 "..LNKC.." */ + 0x50,0x52,0x54,0x41,0x12,0x41,0x2F,0x3C, /* 00000820 "PRTA.A/<" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 00000828 "........" */ + 0x00,0x00,0x0A,0x14,0x12,0x0B,0x04,0x0C, /* 00000830 "........" */ + 0xFF,0xFF,0x01,0x00,0x01,0x00,0x0A,0x15, /* 00000838 "........" */ + 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 00000840 "........" */ + 0x0A,0x02,0x00,0x0A,0x16,0x12,0x0C,0x04, /* 00000848 "........" */ + 0x0C,0xFF,0xFF,0x01,0x00,0x0A,0x03,0x00, /* 00000850 "........" */ + 0x0A,0x17,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 00000858 "........" */ + 0x02,0x00,0x00,0x00,0x0A,0x18,0x12,0x0B, /* 00000860 "........" */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x00, /* 00000868 "........" */ + 0x0A,0x19,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000870 "........" */ + 0x02,0x00,0x0A,0x02,0x00,0x0A,0x1A,0x12, /* 00000878 "........" */ + 0x0C,0x04,0x0C,0xFF,0xFF,0x02,0x00,0x0A, /* 00000880 "........" */ + 0x03,0x00,0x0A,0x1B,0x12,0x0B,0x04,0x0C, /* 00000888 "........" */ + 0xFF,0xFF,0x03,0x00,0x00,0x00,0x0A,0x1C, /* 00000890 "........" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000898 "........" */ + 0x01,0x00,0x0A,0x1D,0x12,0x0C,0x04,0x0C, /* 000008A0 "........" */ + 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x00,0x0A, /* 000008A8 "........" */ + 0x1E,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x03, /* 000008B0 "........" */ + 0x00,0x0A,0x03,0x00,0x0A,0x1F,0x12,0x0B, /* 000008B8 "........" */ + 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x00,0x00, /* 000008C0 "........" */ + 0x0A,0x20,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 000008C8 ". ......" */ + 0x04,0x00,0x01,0x00,0x0A,0x21,0x12,0x0C, /* 000008D0 ".....!.." */ + 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000008D8 "........" */ + 0x00,0x0A,0x22,0x12,0x0C,0x04,0x0C,0xFF, /* 000008E0 ".."....." */ + 0xFF,0x04,0x00,0x0A,0x03,0x00,0x0A,0x23, /* 000008E8 ".......#" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000008F0 "........" */ + 0x00,0x00,0x0A,0x24,0x12,0x0B,0x04,0x0C, /* 000008F8 "...$...." */ + 0xFF,0xFF,0x05,0x00,0x01,0x00,0x0A,0x25, /* 00000900 ".......%" */ + 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 00000908 "........" */ + 0x0A,0x02,0x00,0x0A,0x26,0x12,0x0C,0x04, /* 00000910 "....&..." */ + 0x0C,0xFF,0xFF,0x05,0x00,0x0A,0x03,0x00, /* 00000918 "........" */ + 0x0A,0x27,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 00000920 ".'......" */ + 0x06,0x00,0x00,0x00,0x0A,0x28,0x12,0x0B, /* 00000928 ".....(.." */ + 0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01,0x00, /* 00000930 "........" */ + 0x0A,0x29,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000938 ".)......" */ + 0x06,0x00,0x0A,0x02,0x00,0x0A,0x2A,0x12, /* 00000940 "......*." */ + 0x0C,0x04,0x0C,0xFF,0xFF,0x06,0x00,0x0A, /* 00000948 "........" */ + 0x03,0x00,0x0A,0x2B,0x12,0x0B,0x04,0x0C, /* 00000950 "...+...." */ + 0xFF,0xFF,0x07,0x00,0x00,0x00,0x0A,0x2C, /* 00000958 ".......," */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x07,0x00, /* 00000960 "........" */ + 0x01,0x00,0x0A,0x2D,0x12,0x0C,0x04,0x0C, /* 00000968 "...-...." */ + 0xFF,0xFF,0x07,0x00,0x0A,0x02,0x00,0x0A, /* 00000970 "........" */ + 0x2E,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x07, /* 00000978 "........" */ + 0x00,0x0A,0x03,0x00,0x0A,0x2F,0x12,0x0B, /* 00000980 "...../.." */ + 0x04,0x0C,0xFF,0xFF,0x08,0x00,0x00,0x00, /* 00000988 "........" */ + 0x0A,0x11,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 00000990 "........" */ + 0x08,0x00,0x01,0x00,0x0A,0x12,0x12,0x0C, /* 00000998 "........" */ + 0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A,0x02, /* 000009A0 "........" */ + 0x00,0x0A,0x13,0x12,0x0C,0x04,0x0C,0xFF, /* 000009A8 "........" */ + 0xFF,0x08,0x00,0x0A,0x03,0x00,0x0A,0x14, /* 000009B0 "........" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x09,0x00, /* 000009B8 "........" */ + 0x00,0x00,0x0A,0x15,0x12,0x0B,0x04,0x0C, /* 000009C0 "........" */ + 0xFF,0xFF,0x09,0x00,0x01,0x00,0x0A,0x16, /* 000009C8 "........" */ + 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x09,0x00, /* 000009D0 "........" */ + 0x0A,0x02,0x00,0x0A,0x17,0x12,0x0C,0x04, /* 000009D8 "........" */ + 0x0C,0xFF,0xFF,0x09,0x00,0x0A,0x03,0x00, /* 000009E0 "........" */ + 0x0A,0x18,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 000009E8 "........" */ + 0x0A,0x00,0x00,0x00,0x0A,0x19,0x12,0x0B, /* 000009F0 "........" */ + 0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01,0x00, /* 000009F8 "........" */ + 0x0A,0x1A,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000A00 "........" */ + 0x0A,0x00,0x0A,0x02,0x00,0x0A,0x1B,0x12, /* 00000A08 "........" */ + 0x0C,0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x0A, /* 00000A10 "........" */ + 0x03,0x00,0x0A,0x1C,0x12,0x0B,0x04,0x0C, /* 00000A18 "........" */ + 0xFF,0xFF,0x0B,0x00,0x00,0x00,0x0A,0x1D, /* 00000A20 "........" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0B,0x00, /* 00000A28 "........" */ + 0x01,0x00,0x0A,0x1E,0x12,0x0C,0x04,0x0C, /* 00000A30 "........" */ + 0xFF,0xFF,0x0B,0x00,0x0A,0x02,0x00,0x0A, /* 00000A38 "........" */ + 0x1F,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0B, /* 00000A40 "........" */ + 0x00,0x0A,0x03,0x00,0x0A,0x20,0x12,0x0B, /* 00000A48 "..... .." */ + 0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x00,0x00, /* 00000A50 "........" */ + 0x0A,0x21,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 00000A58 ".!......" */ + 0x0C,0x00,0x01,0x00,0x0A,0x22,0x12,0x0C, /* 00000A60 ".....".." */ + 0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A,0x02, /* 00000A68 "........" */ + 0x00,0x0A,0x23,0x12,0x0C,0x04,0x0C,0xFF, /* 00000A70 "..#....." */ + 0xFF,0x0C,0x00,0x0A,0x03,0x00,0x0A,0x24, /* 00000A78 ".......$" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0D,0x00, /* 00000A80 "........" */ + 0x00,0x00,0x0A,0x25,0x12,0x0B,0x04,0x0C, /* 00000A88 "...%...." */ + 0xFF,0xFF,0x0D,0x00,0x01,0x00,0x0A,0x26, /* 00000A90 ".......&" */ + 0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0D,0x00, /* 00000A98 "........" */ + 0x0A,0x02,0x00,0x0A,0x27,0x12,0x0C,0x04, /* 00000AA0 "....'..." */ + 0x0C,0xFF,0xFF,0x0D,0x00,0x0A,0x03,0x00, /* 00000AA8 "........" */ + 0x0A,0x28,0x12,0x0B,0x04,0x0C,0xFF,0xFF, /* 00000AB0 ".(......" */ + 0x0E,0x00,0x00,0x00,0x0A,0x29,0x12,0x0B, /* 00000AB8 ".....).." */ + 0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01,0x00, /* 00000AC0 "........" */ + 0x0A,0x2A,0x12,0x0C,0x04,0x0C,0xFF,0xFF, /* 00000AC8 ".*......" */ + 0x0E,0x00,0x0A,0x02,0x00,0x0A,0x2B,0x12, /* 00000AD0 "......+." */ + 0x0C,0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x0A, /* 00000AD8 "........" */ + 0x03,0x00,0x0A,0x2C,0x12,0x0B,0x04,0x0C, /* 00000AE0 "...,...." */ + 0xFF,0xFF,0x0F,0x00,0x00,0x00,0x0A,0x2D, /* 00000AE8 ".......-" */ + 0x12,0x0B,0x04,0x0C,0xFF,0xFF,0x0F,0x00, /* 00000AF0 "........" */ + 0x01,0x00,0x0A,0x2E,0x12,0x0C,0x04,0x0C, /* 00000AF8 "........" */ + 0xFF,0xFF,0x0F,0x00,0x0A,0x02,0x00,0x0A, /* 00000B00 "........" */ + 0x2F,0x12,0x0C,0x04,0x0C,0xFF,0xFF,0x0F, /* 00000B08 "/......." */ + 0x00,0x0A,0x03,0x00,0x0A,0x10,0x5B,0x82, /* 00000B10 "......[." */ + 0x46,0x37,0x49,0x53,0x41,0x5F,0x08,0x5F, /* 00000B18 "F7ISA_._" */ + 0x41,0x44,0x52,0x0C,0x00,0x00,0x01,0x00, /* 00000B20 "ADR....." */ + 0x5B,0x80,0x50,0x49,0x52,0x51,0x02,0x0A, /* 00000B28 "[.PIRQ.." */ + 0x60,0x0A,0x04,0x10,0x2E,0x5C,0x00,0x5B, /* 00000B30 "`....\.[" */ + 0x81,0x29,0x5C,0x2F,0x04,0x5F,0x53,0x42, /* 00000B38 ".)\/._SB" */ + 0x5F,0x50,0x43,0x49,0x30,0x49,0x53,0x41, /* 00000B40 "_PCI0ISA" */ + 0x5F,0x50,0x49,0x52,0x51,0x01,0x50,0x49, /* 00000B48 "_PIRQ.PI" */ + 0x52,0x41,0x08,0x50,0x49,0x52,0x42,0x08, /* 00000B50 "RA.PIRB." */ + 0x50,0x49,0x52,0x43,0x08,0x50,0x49,0x52, /* 00000B58 "PIRC.PIR" */ + 0x44,0x08,0x5B,0x82,0x46,0x0B,0x53,0x59, /* 00000B60 "D.[.F.SY" */ + 0x53,0x52,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000B68 "SR._HID." */ + 0x41,0xD0,0x0C,0x02,0x08,0x5F,0x55,0x49, /* 00000B70 "A...._UI" */ + 0x44,0x01,0x08,0x43,0x52,0x53,0x5F,0x11, /* 00000B78 "D..CRS_." */ + 0x4E,0x08,0x0A,0x8A,0x47,0x01,0x10,0x00, /* 00000B80 "N...G..." */ + 0x10,0x00,0x00,0x10,0x47,0x01,0x22,0x00, /* 00000B88 "....G."." */ + 0x22,0x00,0x00,0x0C,0x47,0x01,0x30,0x00, /* 00000B90 ""...G.0." */ + 0x30,0x00,0x00,0x10,0x47,0x01,0x44,0x00, /* 00000B98 "0...G.D." */ + 0x44,0x00,0x00,0x1C,0x47,0x01,0x62,0x00, /* 00000BA0 "D...G.b." */ + 0x62,0x00,0x00,0x02,0x47,0x01,0x65,0x00, /* 00000BA8 "b...G.e." */ + 0x65,0x00,0x00,0x0B,0x47,0x01,0x72,0x00, /* 00000BB0 "e...G.r." */ + 0x72,0x00,0x00,0x0E,0x47,0x01,0x80,0x00, /* 00000BB8 "r...G..." */ + 0x80,0x00,0x00,0x01,0x47,0x01,0x84,0x00, /* 00000BC0 "....G..." */ + 0x84,0x00,0x00,0x03,0x47,0x01,0x88,0x00, /* 00000BC8 "....G..." */ + 0x88,0x00,0x00,0x01,0x47,0x01,0x8C,0x00, /* 00000BD0 "....G..." */ + 0x8C,0x00,0x00,0x03,0x47,0x01,0x90,0x00, /* 00000BD8 "....G..." */ + 0x90,0x00,0x00,0x10,0x47,0x01,0xA2,0x00, /* 00000BE0 "....G..." */ + 0xA2,0x00,0x00,0x1C,0x47,0x01,0xE0,0x00, /* 00000BE8 "....G..." */ + 0xE0,0x00,0x00,0x10,0x47,0x01,0xA0,0x08, /* 00000BF0 "....G..." */ + 0xA0,0x08,0x00,0x04,0x47,0x01,0xC0,0x0C, /* 00000BF8 "....G..." */ + 0xC0,0x0C,0x00,0x10,0x47,0x01,0xD0,0x04, /* 00000C00 "....G..." */ + 0xD0,0x04,0x00,0x02,0x79,0x00,0x14,0x0B, /* 00000C08 "....y..." */ + 0x5F,0x43,0x52,0x53,0x00,0xA4,0x43,0x52, /* 00000C10 "_CRS..CR" */ + 0x53,0x5F,0x5B,0x82,0x2B,0x50,0x49,0x43, /* 00000C18 "S_[.+PIC" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0B,0x41, /* 00000C20 "_._HID.A" */ + 0xD0,0x08,0x5F,0x43,0x52,0x53,0x11,0x18, /* 00000C28 ".._CRS.." */ + 0x0A,0x15,0x47,0x01,0x20,0x00,0x20,0x00, /* 00000C30 "..G. . ." */ + 0x01,0x02,0x47,0x01,0xA0,0x00,0xA0,0x00, /* 00000C38 "..G....." */ + 0x01,0x02,0x22,0x04,0x00,0x79,0x00,0x5B, /* 00000C40 ".."..y.[" */ + 0x82,0x47,0x05,0x44,0x4D,0x41,0x30,0x08, /* 00000C48 ".G.DMA0." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x02, /* 00000C50 "_HID.A.." */ + 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x41, /* 00000C58 ".._CRS.A" */ + 0x04,0x0A,0x3D,0x2A,0x10,0x04,0x47,0x01, /* 00000C60 "..=*..G." */ + 0x00,0x00,0x00,0x00,0x00,0x10,0x47,0x01, /* 00000C68 "......G." */ + 0x81,0x00,0x81,0x00,0x00,0x03,0x47,0x01, /* 00000C70 "......G." */ + 0x87,0x00,0x87,0x00,0x00,0x01,0x47,0x01, /* 00000C78 "......G." */ + 0x89,0x00,0x89,0x00,0x00,0x03,0x47,0x01, /* 00000C80 "......G." */ + 0x8F,0x00,0x8F,0x00,0x00,0x01,0x47,0x01, /* 00000C88 "......G." */ + 0xC0,0x00,0xC0,0x00,0x00,0x20,0x47,0x01, /* 00000C90 "..... G." */ + 0x80,0x04,0x80,0x04,0x00,0x10,0x79,0x00, /* 00000C98 "......y." */ + 0x5B,0x82,0x25,0x54,0x4D,0x52,0x5F,0x08, /* 00000CA0 "[.%TMR_." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x01, /* 00000CA8 "_HID.A.." */ + 0x00,0x08,0x5F,0x43,0x52,0x53,0x11,0x10, /* 00000CB0 ".._CRS.." */ + 0x0A,0x0D,0x47,0x01,0x40,0x00,0x40,0x00, /* 00000CB8 "..G.@.@." */ + 0x00,0x04,0x22,0x01,0x00,0x79,0x00,0x5B, /* 00000CC0 ".."..y.[" */ + 0x82,0x25,0x52,0x54,0x43,0x5F,0x08,0x5F, /* 00000CC8 ".%RTC_._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0B,0x00, /* 00000CD0 "HID.A..." */ + 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000CD8 "._CRS..." */ + 0x0D,0x47,0x01,0x70,0x00,0x70,0x00,0x00, /* 00000CE0 ".G.p.p.." */ + 0x02,0x22,0x00,0x01,0x79,0x00,0x5B,0x82, /* 00000CE8 "."..y.[." */ + 0x22,0x53,0x50,0x4B,0x52,0x08,0x5F,0x48, /* 00000CF0 ""SPKR._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x08,0x00,0x08, /* 00000CF8 "ID.A...." */ + 0x5F,0x43,0x52,0x53,0x11,0x0D,0x0A,0x0A, /* 00000D00 "_CRS...." */ + 0x47,0x01,0x61,0x00,0x61,0x00,0x00,0x01, /* 00000D08 "G.a.a..." */ + 0x79,0x00,0x5B,0x82,0x31,0x50,0x53,0x32, /* 00000D10 "y.[.1PS2" */ + 0x4D,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000D18 "M._HID.A" */ + 0xD0,0x0F,0x13,0x08,0x5F,0x43,0x49,0x44, /* 00000D20 "...._CID" */ + 0x0C,0x41,0xD0,0x0F,0x13,0x14,0x09,0x5F, /* 00000D28 ".A....._" */ + 0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08, /* 00000D30 "STA....." */ + 0x5F,0x43,0x52,0x53,0x11,0x08,0x0A,0x05, /* 00000D38 "_CRS...." */ + 0x22,0x00,0x10,0x79,0x00,0x5B,0x82,0x42, /* 00000D40 ""..y.[.B" */ + 0x04,0x50,0x53,0x32,0x4B,0x08,0x5F,0x48, /* 00000D48 ".PS2K._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x03,0x03,0x08, /* 00000D50 "ID.A...." */ + 0x5F,0x43,0x49,0x44,0x0C,0x41,0xD0,0x03, /* 00000D58 "_CID.A.." */ + 0x0B,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000D60 "..._STA." */ + 0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52,0x53, /* 00000D68 "...._CRS" */ + 0x11,0x18,0x0A,0x15,0x47,0x01,0x60,0x00, /* 00000D70 "....G.`." */ + 0x60,0x00,0x00,0x01,0x47,0x01,0x64,0x00, /* 00000D78 "`...G.d." */ + 0x64,0x00,0x00,0x01,0x22,0x02,0x00,0x79, /* 00000D80 "d..."..y" */ + 0x00,0x5B,0x82,0x3A,0x46,0x44,0x43,0x30, /* 00000D88 ".[.:FDC0" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000D90 "._HID.A." */ + 0x07,0x00,0x14,0x09,0x5F,0x53,0x54,0x41, /* 00000D98 "...._STA" */ + 0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43,0x52, /* 00000DA0 "....._CR" */ + 0x53,0x11,0x1B,0x0A,0x18,0x47,0x01,0xF0, /* 00000DA8 "S....G.." */ + 0x03,0xF0,0x03,0x01,0x06,0x47,0x01,0xF7, /* 00000DB0 ".....G.." */ + 0x03,0xF7,0x03,0x01,0x01,0x22,0x40,0x00, /* 00000DB8 "....."@." */ + 0x2A,0x04,0x00,0x79,0x00,0x5B,0x82,0x46, /* 00000DC0 "*..y.[.F" */ + 0x04,0x55,0x41,0x52,0x31,0x08,0x5F,0x48, /* 00000DC8 ".UAR1._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000DD0 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x01,0x14,0x19,0x5F, /* 00000DD8 "_UID..._" */ + 0x53,0x54,0x41,0x00,0xA0,0x0D,0x93,0x5E, /* 00000DE0 "STA....^" */ + 0x5E,0x5E,0x5E,0x55,0x41,0x52,0x31,0x00, /* 00000DE8 "^^^UAR1." */ + 0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x08, /* 00000DF0 "........" */ + 0x5F,0x43,0x52,0x53,0x11,0x10,0x0A,0x0D, /* 00000DF8 "_CRS...." */ + 0x47,0x01,0xF8,0x03,0xF8,0x03,0x08,0x08, /* 00000E00 "G......." */ + 0x22,0x10,0x00,0x79,0x00,0x5B,0x82,0x47, /* 00000E08 ""..y.[.G" */ + 0x04,0x55,0x41,0x52,0x32,0x08,0x5F,0x48, /* 00000E10 ".UAR2._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000E18 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x19, /* 00000E20 "_UID...." */ + 0x5F,0x53,0x54,0x41,0x00,0xA0,0x0D,0x93, /* 00000E28 "_STA...." */ + 0x5E,0x5E,0x5E,0x5E,0x55,0x41,0x52,0x32, /* 00000E30 "^^^^UAR2" */ + 0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F, /* 00000E38 "........" */ + 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000E40 "._CRS..." */ + 0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02,0x08, /* 00000E48 ".G......" */ + 0x08,0x22,0x08,0x00,0x79,0x00,0x5B,0x82, /* 00000E50 "."..y.[." */ + 0x36,0x4C,0x54,0x50,0x31,0x08,0x5F,0x48, /* 00000E58 "6LTP1._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x04,0x00,0x08, /* 00000E60 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x09, /* 00000E68 "_UID...." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000E70 "_STA...." */ + 0x08,0x5F,0x43,0x52,0x53,0x11,0x10,0x0A, /* 00000E78 "._CRS..." */ + 0x0D,0x47,0x01,0x78,0x03,0x78,0x03,0x08, /* 00000E80 ".G.x.x.." */ + 0x08,0x22,0x80,0x00,0x79,0x00, }; int DsdtLen=sizeof(AmlCode); diff --git a/tools/fs-back/fs-backend.c b/tools/fs-back/fs-backend.c index 634d5fa31e..fd5ba2b46b 100644 --- a/tools/fs-back/fs-backend.c +++ b/tools/fs-back/fs-backend.c @@ -140,8 +140,8 @@ void* handle_mount(void *data) handle_aio_events(mount); moretodo: rp = mount->ring.sring->req_prod; - rmb(); /* Ensure we see queued requests up to 'rp'. */ - + xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ + while ((cons = mount->ring.req_cons) != rp) { int i; diff --git a/tools/ioemu/Makefile.target b/tools/ioemu/Makefile.target index ebd691b5f0..965d726adf 100644 --- a/tools/ioemu/Makefile.target +++ b/tools/ioemu/Makefile.target @@ -15,7 +15,7 @@ TARGET_BASE_ARCH:=sparc endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)$(TARGET_SUB) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio -CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) +CPPFLAGS+=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) CPPFLAGS+= -I$(XEN_ROOT)/tools/libxc CPPFLAGS+= -I$(XEN_ROOT)/tools/xenstore CPPFLAGS+= -I$(XEN_ROOT)/tools/include @@ -66,7 +66,11 @@ else QEMU_SYSTEM=qemu-fast endif +ifdef CONFIG_STUBDOM +QEMU_SYSTEM=qemu.a +else QEMU_SYSTEM=qemu-dm +endif ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) @@ -345,14 +349,25 @@ VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o isa_mmio.o VL_OBJS+=cutils.o VL_OBJS+=block.o block-raw.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o +ifdef CONFIG_STUBDOM +VL_OBJS+=block-vbd.o +endif ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o endif -ifeq (,$(wildcard /usr/include/pci)) +ifdef CONFIG_STUBDOM +CONFIG_PASSTHROUGH=1 +else + ifeq (,$(wildcard /usr/include/pci)) $(warning *** pciutils-devl package not found - missing /usr/include/pci) $(warning *** PCI passthrough capability has been disabled) -else + else +CONFIG_PASSTHROUGH=1 + endif +endif + +ifdef CONFIG_PASSTHROUGH LIBS+=-lpci VL_OBJS+= pass-through.o CFLAGS += -DCONFIG_PASSTHROUGH @@ -404,13 +419,13 @@ VL_OBJS+= ne2000.o rtl8139.o pcnet.o e100.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) extboot.o +VL_OBJS+= ide.o pckbd.o ps2.o vga.o dma.o extboot.o 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 +VL_OBJS+= cirrus_vga.o parallel.o acpi.o VL_OBJS+= usb-uhci.o smbus_eeprom.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o @@ -419,22 +434,32 @@ VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o VL_OBJS+= xenfb.o VL_OBJS+= xen_console.o +ifndef CONFIG_STUBDOM VL_OBJS+= tpm_tis.o +VL_OBJS+= $(SOUND_HW) $(AUDIODRV) mixeng.o +CPPFLAGS += -DHAS_TPM CPPFLAGS += -DHAS_AUDIO endif +endif ifeq ($(TARGET_BASE_ARCH), ppc) -VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o dma.o VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o +ifndef CONFIG_STUBDOM +VL_OBJS+= $(SOUND_HW) $(AUDIODRV) CPPFLAGS += -DHAS_AUDIO endif +endif ifeq ($(TARGET_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o -VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) +VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o +ifndef CONFIG_STUBDOM +VL_OBJS+= $(SOUND_HW) $(AUDIODRV) DEFINES += -DHAS_AUDIO endif +endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o @@ -512,7 +537,11 @@ SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a +ifdef CONFIG_STUBDOM + $(AR) rcs $@ $(VL_OBJS) +else $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) +endif cocoa.o: cocoa.m $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< diff --git a/tools/ioemu/aes.c b/tools/ioemu/aes.c index cd4484ff9b..e75b168a80 100644 --- a/tools/ioemu/aes.c +++ b/tools/ioemu/aes.c @@ -33,9 +33,11 @@ #define NDEBUG #include <assert.h> +#ifndef CONFIG_STUBDOM typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; +#endif #define MAXKC (256/32) #define MAXKB (256/8) diff --git a/tools/ioemu/block-raw.c b/tools/ioemu/block-raw.c index 68e8a370ca..182d2ec55e 100644 --- a/tools/ioemu/block-raw.c +++ b/tools/ioemu/block-raw.c @@ -25,7 +25,9 @@ #include "block_int.h" #include <assert.h> #ifndef _WIN32 +#ifndef NO_AIO #include <aio.h> +#endif #ifndef QEMU_TOOL #include "exec-all.h" @@ -167,10 +169,16 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, } s->lseek_err_cnt=0; - ret = read(s->fd, buf, count); - if (ret == count) - goto label__raw_read__success; + uint64_t done; + for (done = 0; done < count; done += ret) { + ret = read(s->fd, buf + done, count - done); + if (ret == -1) + goto label__raw_read__error; + } + ret = count; + goto label__raw_read__success; +label__raw_read__error: DEBUG_BLOCK_PRINT("raw_read(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 "] read failed %d : %d = %s\n", s->fd, bs->filename, @@ -232,9 +240,16 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, } s->lseek_err_cnt = 0; - ret = write(s->fd, buf, count); - if (ret == count) - goto label__raw_write__success; + uint64_t done; + for (done = 0; done < count; done += ret) { + ret = write(s->fd, buf + done, count - done); + if (ret == -1) + goto label__raw_write__error; + } + ret = count; + goto label__raw_write__success; + +label__raw_write__error: DEBUG_BLOCK_PRINT("raw_write(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 "] write failed %d : %d = %s\n", s->fd, @@ -255,6 +270,7 @@ label__raw_write__success: /***********************************************************/ /* Unix AIO using POSIX AIO */ +#ifndef NO_AIO typedef struct RawAIOCB { BlockDriverAIOCB common; struct aiocb aiocb; @@ -480,6 +496,7 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb) pacb = &acb->next; } } +#endif static void raw_close(BlockDriverState *bs) { @@ -600,10 +617,12 @@ BlockDriver bdrv_raw = { raw_create, raw_flush, +#ifndef NO_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), +#endif .protocol_name = "file", .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, @@ -936,10 +955,12 @@ BlockDriver bdrv_host_device = { NULL, raw_flush, +#ifndef NO_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), +#endif .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, .bdrv_getlength = raw_getlength, diff --git a/tools/ioemu/block-vbd.c b/tools/ioemu/block-vbd.c new file mode 100644 index 0000000000..937bb5e62d --- /dev/null +++ b/tools/ioemu/block-vbd.c @@ -0,0 +1,345 @@ +/* + * Block driver for Mini-os PV devices + * Based on block-raw.c + * + * Copyright (c) 2006 Fabrice Bellard, 2007 Samuel Thibault + * + * 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" +#include "block_int.h" +#include <assert.h> +#include <xenbus.h> +#include <blkfront.h> +#include <malloc.h> + +#define SECTOR_SIZE 512 + +#ifndef QEMU_TOOL +#include "exec-all.h" +#endif + +#define DEBUG_BLOCK +#ifdef DEBUG_BLOCK +#define DEBUG_BLOCK_PRINT( formatCstr, args... ) fprintf( logfile, formatCstr, ##args ); fflush( logfile ) +#else +#define DEBUG_BLOCK_PRINT( formatCstr, args... ) +#endif + +#define FTYPE_FILE 0 +#define FTYPE_CD 1 +#define FTYPE_FD 2 + +typedef struct BDRVVbdState { + struct blkfront_dev *dev; + int fd; + int type; + int mode; + uint64_t sectors; + unsigned sector_size; + QEMU_LIST_ENTRY(BDRVVbdState) list; +} BDRVVbdState; + +QEMU_LIST_HEAD(, BDRVVbdState) vbds; + +static int vbd_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + char *value; + if (xenbus_read(XBT_NIL, filename, &value)) + return 0; + free(value); + return 100; +} + +static void vbd_io_completed(void *opaque) +{ + BDRVVbdState *s = opaque; + blkfront_aio_poll(s->dev); +} + +static int vbd_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVVbdState *s = bs->opaque; + + //handy to test posix access + //return -EIO; + + s->dev = init_blkfront((char *) filename, &s->sectors, &s->sector_size, &s->mode); + + if (!s->dev) + return -EIO; + + if (SECTOR_SIZE % s->sector_size) { + printf("sector size is %d, we only support sector sizes that divide %d\n", s->sector_size, SECTOR_SIZE); + return -EIO; + } + + s->fd = blkfront_open(s->dev); + qemu_set_fd_handler(s->fd, vbd_io_completed, NULL, s); + + QEMU_LIST_INSERT_HEAD(&vbds, s, list); + + return 0; +} + +typedef struct VbdAIOCB { + BlockDriverAIOCB common; + struct blkfront_aiocb aiocb; +} VbdAIOCB; + +void qemu_aio_init(void) +{ +} + +void qemu_aio_poll(void) +{ +} + +/* Wait for all IO requests to complete. */ +void qemu_aio_flush(void) +{ + BDRVVbdState *s; + for (s = vbds.lh_first; s; s = s->list.le_next) + blkfront_sync(s->dev); +} + +void qemu_aio_wait_start(void) +{ +} + +void qemu_aio_wait(void) +{ + int some = 0; + DEFINE_WAIT(w); + while (1) { + BDRVVbdState *s; + add_waiter(w, blkfront_queue); + for (s = vbds.lh_first; s; s = s->list.le_next) + if (blkfront_aio_poll(s->dev)) + some = 1; + if (some) + break; + schedule(); + } + remove_waiter(w); +} + +void qemu_aio_wait_end(void) +{ +} + +static void vbd_aio_callback(struct blkfront_aiocb *aiocbp, int ret) { + VbdAIOCB *acb = aiocbp->data; + + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); +} + +static VbdAIOCB *vbd_aio_setup(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVVbdState *s = bs->opaque; + VbdAIOCB *acb; + + acb = qemu_aio_get(bs, cb, opaque); + if (!acb) + return NULL; + acb->aiocb.aio_dev = s->dev; + acb->aiocb.aio_buf = buf; + acb->aiocb.aio_nbytes = nb_sectors * SECTOR_SIZE; + acb->aiocb.aio_offset = sector_num * SECTOR_SIZE; + acb->aiocb.aio_cb = vbd_aio_callback; + acb->aiocb.data = acb; + + return acb; +} + +static BlockDriverAIOCB *vbd_aio_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + VbdAIOCB *acb; + + acb = vbd_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); + if (!acb) + return NULL; + blkfront_aio(&acb->aiocb, 0); + return &acb->common; +} + +static BlockDriverAIOCB *vbd_aio_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + VbdAIOCB *acb; + + acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, cb, opaque); + if (!acb) + return NULL; + blkfront_aio(&acb->aiocb, 1); + return &acb->common; +} + +static void vbd_cb(void *data, int ret) { + int *result = data; + result[0] = 1; + result[1] = ret; +} + +static int vbd_aligned_io(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, int write) +{ + VbdAIOCB *acb; + int result[2]; + result[0] = 0; + qemu_aio_wait_start(); + acb = vbd_aio_setup(bs, sector_num, (uint8_t*) buf, nb_sectors, vbd_cb, &result); + blkfront_aio(&acb->aiocb, write); + while (!result[0]) + qemu_aio_wait(); + qemu_aio_wait_end(); + return result[1]; +} + +static int vbd_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors) +{ + uint8_t *iobuf; + int ret; + /* page alignment would be a bit better, but that's still fine compared to + * copying */ + if (!((uintptr_t)buf & (SECTOR_SIZE-1))) + return vbd_aligned_io(bs, sector_num, buf, nb_sectors, 0); + iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE); + ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 0); + memcpy(buf, iobuf, nb_sectors * SECTOR_SIZE); + free(iobuf); + if (ret < 0) + return ret; + else if (ret != nb_sectors * SECTOR_SIZE) + return -EINVAL; + else + return 0; +} + +static int vbd_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors) +{ + uint8_t *iobuf; + int ret; + if (!((uintptr_t)buf & (SECTOR_SIZE-1))) + return vbd_aligned_io(bs, sector_num, (uint8_t*) buf, nb_sectors, 1); + iobuf = qemu_memalign(PAGE_SIZE, nb_sectors * SECTOR_SIZE); + memcpy(iobuf, buf, nb_sectors * SECTOR_SIZE); + ret = vbd_aligned_io(bs, sector_num, iobuf, nb_sectors, 1); + free(iobuf); + if (ret < 0) + return ret; + else if (ret != nb_sectors * SECTOR_SIZE) + return -EINVAL; + else + return 0; +} + +static void vbd_aio_cancel(BlockDriverAIOCB *blockacb) +{ + /* TODO */ + //VbdAIOCB *acb = (VbdAIOCB *)blockacb; + + // Try to cancel. If can't, wait for it, drop the callback and call qemu_aio_release(acb) +} + +static void vbd_close(BlockDriverState *bs) +{ + BDRVVbdState *s = bs->opaque; + bs->total_sectors = 0; + if (s->fd >= 0) { + close(s->fd); + s->fd = -1; + } + QEMU_LIST_REMOVE(s, list); +} + +static int64_t vbd_getlength(BlockDriverState *bs) +{ + BDRVVbdState *s = bs->opaque; + return s->sectors * s->sector_size; +} + +static void vbd_flush(BlockDriverState *bs) +{ + BDRVVbdState *s = bs->opaque; + blkfront_sync(s->dev); +} + +/***********************************************/ +/* host device */ + +static int vbd_is_inserted(BlockDriverState *bs) +{ + /* TODO: monitor the backend */ + return 1; +} + +/* currently only used by fdc.c, but a CD version would be good too */ +static int vbd_media_changed(BlockDriverState *bs) +{ + /* TODO: monitor the backend */ + return -ENOTSUP; +} + +static int vbd_eject(BlockDriverState *bs, int eject_flag) +{ + /* TODO: Xen support needed */ + return -ENOTSUP; +} + +static int vbd_set_locked(BlockDriverState *bs, int locked) +{ + /* TODO: Xen support needed */ + return -ENOTSUP; +} + +BlockDriver bdrv_vbd = { + "vbd", + sizeof(BDRVVbdState), + vbd_probe, + vbd_open, + NULL, + NULL, + vbd_close, + NULL, + vbd_flush, + + .bdrv_aio_read = vbd_aio_read, + .bdrv_aio_write = vbd_aio_write, + .bdrv_aio_cancel = vbd_aio_cancel, + .aiocb_size = sizeof(VbdAIOCB), + .bdrv_read = vbd_read, + .bdrv_write = vbd_write, + .bdrv_getlength = vbd_getlength, + + /* removable device support */ + .bdrv_is_inserted = vbd_is_inserted, + .bdrv_media_changed = vbd_media_changed, + .bdrv_eject = vbd_eject, + .bdrv_set_locked = vbd_set_locked, +}; + diff --git a/tools/ioemu/block.c b/tools/ioemu/block.c index cf84e8ffbb..a43f3fe27b 100644 --- a/tools/ioemu/block.c +++ b/tools/ioemu/block.c @@ -1235,6 +1235,9 @@ void bdrv_init(void) { bdrv_register(&bdrv_raw); bdrv_register(&bdrv_host_device); +#ifdef CONFIG_STUBDOM + bdrv_register(&bdrv_vbd); +#endif #ifndef _WIN32 bdrv_register(&bdrv_cow); #endif diff --git a/tools/ioemu/configure b/tools/ioemu/configure index ef0bac1f8e..3e3b427b87 100755 --- a/tools/ioemu/configure +++ b/tools/ioemu/configure @@ -74,6 +74,7 @@ softmmu="yes" linux_user="no" darwin_user="no" build_docs="no" +stubdom="no" uname_release="" # OS specific @@ -231,6 +232,8 @@ for opt do ;; --enable-uname-release=*) uname_release="$optarg" ;; + --enable-stubdom) stubdom="yes" + ;; esac done @@ -416,7 +419,11 @@ if test -z "$target_list" ; then target_list="i386-darwin-user ppc-darwin-user $target_list" fi # the i386-dm target - target_list="i386-dm" + if test "$stubdom" = "yes"; then + target_list="i386-dm-stubdom" + else + target_list="i386-dm" + fi else target_list=`echo "$target_list" | sed -e 's/,/ /g'` fi @@ -575,6 +582,11 @@ bindir="$prefix/$libdir/xen/bin" configdir="/etc/xen" fi +if test "$stubdom" = "yes"; then + oss="no" + sdl="no" +fi + echo "Install prefix $prefix" echo "BIOS directory $datadir" echo "binary directory $bindir" @@ -943,6 +955,14 @@ if expr $target : '.*-dm' > /dev/null ; then echo "#define CONFIG_DM 1" >> $config_h fi +if test "$stubdom" = "yes" ; then + echo "CONFIG_STUBDOM=yes" >> $config_mak + echo "#define CONFIG_STUBDOM 1" >> $config_h + echo "#define NO_UNIX_SOCKETS 1" >> $config_h + echo "#define NO_DAEMONIZE 1" >> $config_h + echo "#define NO_AIO 1" >> $config_h +fi + if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h diff --git a/tools/ioemu/console.c b/tools/ioemu/console.c index 634e3d85d0..dc904f6574 100644 --- a/tools/ioemu/console.c +++ b/tools/ioemu/console.c @@ -169,16 +169,12 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) unsigned int r, g, b, color; switch(ds->depth) { -#if 0 case 8: r = (rgba >> 16) & 0xff; g = (rgba >> 8) & 0xff; b = (rgba) & 0xff; - color = (rgb_to_index[r] * 6 * 6) + - (rgb_to_index[g] * 6) + - (rgb_to_index[b]); + color = ((r >> 5) << 5 | (g >> 5) << 2 | (b >> 6)); break; -#endif case 15: r = (rgba >> 16) & 0xff; g = (rgba >> 8) & 0xff; diff --git a/tools/ioemu/cpu-all.h b/tools/ioemu/cpu-all.h index 2f125b785d..9cc854ed7c 100644 --- a/tools/ioemu/cpu-all.h +++ b/tools/ioemu/cpu-all.h @@ -116,6 +116,7 @@ static inline void tswap64s(uint64_t *s) #define bswaptls(s) bswap64s(s) #endif +#ifdef CONFIG_SOFTFLOAT /* NOTE: arm FPA is horrible as double 32 bit words are stored in big endian ! */ typedef union { @@ -134,6 +135,7 @@ typedef union { #endif uint64_t ll; } CPU_DoubleU; +#endif /* CPU memory access without any memory or io remapping */ @@ -267,6 +269,7 @@ static inline void stq_le_p(void *ptr, uint64_t v) stl_le_p(p + 4, v >> 32); } +#ifdef CONFIG_SOFTFLOAT /* float access */ static inline float32 ldfl_le_p(void *ptr) @@ -304,6 +307,7 @@ static inline void stfq_le_p(void *ptr, float64 v) stl_le_p(ptr, u.l.lower); stl_le_p(ptr + 4, u.l.upper); } +#endif #else @@ -342,6 +346,7 @@ static inline void stq_le_p(void *ptr, uint64_t v) *(uint64_t *)ptr = v; } +#ifdef CONFIG_SOFTFLOAT /* float access */ static inline float32 ldfl_le_p(void *ptr) @@ -364,6 +369,7 @@ static inline void stfq_le_p(void *ptr, float64 v) *(float64 *)ptr = v; } #endif +#endif #if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) @@ -456,6 +462,7 @@ static inline void stq_be_p(void *ptr, uint64_t v) stl_be_p(ptr + 4, v); } +#ifdef CONFIG_SOFTFLOAT /* float access */ static inline float32 ldfl_be_p(void *ptr) @@ -493,6 +500,7 @@ static inline void stfq_be_p(void *ptr, float64 v) stl_be_p(ptr, u.l.upper); stl_be_p(ptr + 4, u.l.lower); } +#endif #else @@ -531,6 +539,7 @@ static inline void stq_be_p(void *ptr, uint64_t v) *(uint64_t *)ptr = v; } +#ifdef CONFIG_SOFTFLOAT /* float access */ static inline float32 ldfl_be_p(void *ptr) @@ -552,6 +561,7 @@ static inline void stfq_be_p(void *ptr, float64 v) { *(float64 *)ptr = v; } +#endif #endif diff --git a/tools/ioemu/exec-all.h b/tools/ioemu/exec-all.h index f6804b1a0a..28c120d4ca 100644 --- a/tools/ioemu/exec-all.h +++ b/tools/ioemu/exec-all.h @@ -481,6 +481,9 @@ static inline int testandset (int *p) } #endif +#ifdef CONFIG_STUBDOM +#include <spinlock.h> +#else typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 @@ -514,6 +517,7 @@ static inline int spin_trylock(spinlock_t *lock) return 1; } #endif +#endif extern spinlock_t tb_lock; diff --git a/tools/ioemu/hw/fdc.c b/tools/ioemu/hw/fdc.c index dc2ea6ebff..5989afd7d0 100644 --- a/tools/ioemu/hw/fdc.c +++ b/tools/ioemu/hw/fdc.c @@ -378,7 +378,7 @@ struct fdctrl_t { uint8_t cur_drv; uint8_t bootsel; /* Command FIFO */ - uint8_t fifo[FD_SECTOR_LEN]; + uint8_t *fifo; uint32_t data_pos; uint32_t data_len; uint8_t data_state; @@ -497,6 +497,11 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; + fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN); + if (fdctrl->fifo == NULL) { + qemu_free(fdctrl); + return NULL; + } fdctrl->result_timer = qemu_new_timer(vm_clock, fdctrl_result_timer, fdctrl); diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index 0e65141ec6..9dd9653aa9 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include <malloc.h> /* debug IDE devices */ //#define DEBUG_IDE @@ -347,7 +348,7 @@ typedef struct IDEState { EndTransferFunc *end_transfer_func; uint8_t *data_ptr; uint8_t *data_end; - uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; + uint8_t *io_buffer; QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ uint32_t irq_count; /* counts IRQs when using win2k install hack */ } IDEState; @@ -2305,6 +2306,7 @@ static void ide_init2(IDEState *ide_state, for(i = 0; i < 2; i++) { s = ide_state + i; + s->io_buffer = qemu_memalign(getpagesize(), MAX_MULT_SECTORS*512 + 4); if (i == 0) s->bs = hd0; else diff --git a/tools/ioemu/hw/pc.c b/tools/ioemu/hw/pc.c index 5d982016a6..c6ebc6780d 100644 --- a/tools/ioemu/hw/pc.c +++ b/tools/ioemu/hw/pc.c @@ -361,6 +361,7 @@ void bochs_bios_init(void) register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); } +#if defined(__i386__) || defined(__x86_64__) /* Generate an initial boot sector which sets state and jump to a specified vector */ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) @@ -718,6 +719,14 @@ static void load_linux(const char *kernel_filename, generate_bootsect(gpr, seg, 0); } +#else /* __ia64__ */ +static void load_linux(const char *kernel_filename, + const char *initrd_filename, + const char *kernel_cmdline) +{ + /* Direct Linux boot is unsupported. */ +} +#endif static void main_cpu_reset(void *opaque) { @@ -1013,8 +1022,10 @@ static void pc_init1(uint64_t ram_size, int vga_ram_size, char *boot_device, } } +#ifdef HAS_TPM if (has_tpm_device()) tpm_tis_init(&pic_set_irq_new, isa_pic, 11); +#endif kbd_init(); DMA_init(0); diff --git a/tools/ioemu/hw/scsi-disk.c b/tools/ioemu/hw/scsi-disk.c index c6280fd559..acbe75fc98 100644 --- a/tools/ioemu/hw/scsi-disk.c +++ b/tools/ioemu/hw/scsi-disk.c @@ -26,13 +26,18 @@ do { printf("scsi-disk: " fmt , ##args); } while (0) do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #include "vl.h" +#include <malloc.h> #define SENSE_NO_SENSE 0 #define SENSE_NOT_READY 2 #define SENSE_HARDWARE_ERROR 4 #define SENSE_ILLEGAL_REQUEST 5 +#ifdef CONFIG_STUBDOM +#define SCSI_DMA_BUF_SIZE 32768 +#else #define SCSI_DMA_BUF_SIZE 65536 +#endif typedef struct SCSIRequest { SCSIDevice *dev; @@ -44,7 +49,7 @@ typedef struct SCSIRequest { int sector_count; /* The amounnt of data in the buffer. */ int buf_len; - uint8_t dma_buf[SCSI_DMA_BUF_SIZE]; + uint8_t *dma_buf; BlockDriverAIOCB *aiocb; struct SCSIRequest *next; } SCSIRequest; @@ -76,6 +81,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) free_requests = r->next; } else { r = qemu_malloc(sizeof(SCSIRequest)); + r->dma_buf = qemu_memalign(getpagesize(), SCSI_DMA_BUF_SIZE); } r->dev = s; r->tag = tag; diff --git a/tools/ioemu/hw/usb-hid.c b/tools/ioemu/hw/usb-hid.c index e947977313..78b48b8dbb 100644 --- a/tools/ioemu/hw/usb-hid.c +++ b/tools/ioemu/hw/usb-hid.c @@ -224,15 +224,37 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = { 0xC0, /* End Collection */ }; +static int currentbutton = 0; +typedef struct _mouseclick { + int button_state; + struct _mouseclick *next; +} mouseclick; +static mouseclick mousequeue[20]; +static mouseclick *head = mousequeue; +static mouseclick *tail = mousequeue; + static void usb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { USBMouseState *s = opaque; + if (s->status_changed == 1){ + //A mouse event is lost + if (buttons_state != currentbutton && tail->next != head) { + //A left click event is lost: let's add it to the queue + //counter++; + tail->button_state = buttons_state; + tail = tail->next; + } + } + else { + s->buttons_state = buttons_state; + } + s->dx += dx1; s->dy += dy1; s->dz += dz1; - s->buttons_state = buttons_state; + currentbutton = buttons_state; s->status_changed = 1; } @@ -240,11 +262,24 @@ static void usb_tablet_event(void *opaque, int x, int y, int dz, int buttons_state) { USBMouseState *s = opaque; + + if (s->status_changed == 1){ + //A mouse event is lost + if (buttons_state != currentbutton && tail->next != head) { + //A left click event is lost: let's add it to the queue + //counter++; + tail->button_state = buttons_state; + tail = tail->next; + } + } + else { + s->buttons_state = buttons_state; + } s->x = x; s->y = y; s->dz += dz; - s->buttons_state = buttons_state; + currentbutton = buttons_state; s->status_changed = 1; } @@ -493,10 +528,17 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) else if (s->kind == USB_TABLET) ret = usb_tablet_poll(s, p->data, p->len); - if (!s->status_changed) + if (!s->status_changed) { ret = USB_RET_NAK; - else - s->status_changed = 0; + } else { + if (head != tail) { + s->buttons_state = head->button_state; + head = head->next; + } + else { + s->status_changed = 0; + } + } } else { goto fail; @@ -567,6 +609,14 @@ int usb_mouse_load(QEMUFile *f, void *opaque, int version_id) USBDevice *usb_tablet_init(void) { USBMouseState *s; + int i; + + for (i = 0; i < 19; i++) { + mousequeue[i].button_state = 0; + mousequeue[i].next = &(mousequeue[i + 1]); + } + mousequeue[i].button_state = 0; + mousequeue[i].next = mousequeue; s = qemu_mallocz(sizeof(USBMouseState)); if (!s) @@ -591,6 +641,14 @@ USBDevice *usb_tablet_init(void) USBDevice *usb_mouse_init(void) { USBMouseState *s; + int i; + + for (i = 0; i < 19; i++) { + mousequeue[i].button_state = 0; + mousequeue[i].next = &(mousequeue[i + 1]); + } + mousequeue[i].button_state = 0; + mousequeue[i].next = mousequeue; s = qemu_mallocz(sizeof(USBMouseState)); if (!s) diff --git a/tools/ioemu/hw/vga.c b/tools/ioemu/hw/vga.c index 17538bbddc..4e2f9525a7 100644 --- a/tools/ioemu/hw/vga.c +++ b/tools/ioemu/hw/vga.c @@ -1071,7 +1071,7 @@ static const uint8_t cursor_glyph[32 * 4] = { */ static void vga_draw_text(VGAState *s, int full_update) { - int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; + int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr, depth; int cx_min, cx_max, linesize, x_incr; uint32_t offset, fgcol, bgcol, v, cursor_offset; uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr; @@ -1134,6 +1134,11 @@ static void vga_draw_text(VGAState *s, int full_update) return; } + depth = s->get_bpp(s); + if (depth == 24) + depth = 32; + if (s->ds->dpy_colourdepth != NULL && s->ds->depth != depth) + s->ds->dpy_colourdepth(s->ds, depth); if (width != s->last_width || height != s->last_height || cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; @@ -1477,7 +1482,7 @@ void check_sse2(void) */ static void vga_draw_graphic(VGAState *s, int full_update) { - int y1, y, update, linesize, y_start, double_scan, mask; + int y1, y, update, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, bwidth; ram_addr_t page0, page1; int disp_width, multi_scan, multi_run; @@ -1551,6 +1556,11 @@ static void vga_draw_graphic(VGAState *s, int full_update) } vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; + depth = s->get_bpp(s); + if (depth == 24) + depth = 32; + if (s->ds->dpy_colourdepth != NULL && s->ds->depth != depth) + s->ds->dpy_colourdepth(s->ds, depth); if (disp_width != s->last_width || height != s->last_height) { dpy_resize(s->ds, disp_width, height); diff --git a/tools/ioemu/hw/xen_console.c b/tools/ioemu/hw/xen_console.c index 76aca8f3ee..44f8bcca48 100644 --- a/tools/ioemu/hw/xen_console.c +++ b/tools/ioemu/hw/xen_console.c @@ -75,7 +75,7 @@ static void buffer_append(struct domain *dom) cons = intf->out_cons; prod = intf->out_prod; - mb(); + xen_mb(); size = prod - cons; if ((size == 0) || (size > sizeof(intf->out))) @@ -94,7 +94,7 @@ static void buffer_append(struct domain *dom) buffer->data[buffer->size++] = intf->out[ MASK_XENCONS_IDX(cons++, intf->out)]; - mb(); + xen_mb(); intf->out_cons = cons; xc_evtchn_notify(dom->xce_handle, dom->local_port); @@ -289,7 +289,7 @@ static int ring_free_bytes(struct domain *dom) cons = intf->in_cons; prod = intf->in_prod; - mb(); + xen_mb(); space = prod - cons; if (space > sizeof(intf->in)) @@ -322,7 +322,7 @@ static void xencons_receive(void *opaque, const uint8_t *buf, int len) intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = buf[i]; } - wmb(); + xen_wmb(); intf->in_prod = prod; xc_evtchn_notify(dom->xce_handle, dom->local_port); } diff --git a/tools/ioemu/hw/xen_machine_fv.c b/tools/ioemu/hw/xen_machine_fv.c index 22ba1dbc3f..272f67946f 100644 --- a/tools/ioemu/hw/xen_machine_fv.c +++ b/tools/ioemu/hw/xen_machine_fv.c @@ -24,6 +24,9 @@ */ #include "vl.h" +#ifdef CONFIG_STUBDOM +#include <xenbus.h> +#endif #include <xen/hvm/params.h> #include <sys/mman.h> diff --git a/tools/ioemu/hw/xenfb.c b/tools/ioemu/hw/xenfb.c index f0d7f7936e..5418986178 100644 --- a/tools/ioemu/hw/xenfb.c +++ b/tools/ioemu/hw/xenfb.c @@ -485,7 +485,7 @@ static void xenfb_on_fb_event(struct xenfb *xenfb) prod = page->out_prod; if (prod == page->out_cons) return; - rmb(); /* ensure we see ring contents up to prod */ + xen_rmb(); /* ensure we see ring contents up to prod */ for (cons = page->out_cons; cons != prod; cons++) { union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); int x, y, w, h; @@ -512,7 +512,7 @@ static void xenfb_on_fb_event(struct xenfb *xenfb) break; } } - mb(); /* ensure we're done with ring contents */ + xen_mb(); /* ensure we're done with ring contents */ page->out_cons = cons; xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); } @@ -571,9 +571,9 @@ static int xenfb_kbd_event(struct xenfb *xenfb, return -1; } - mb(); /* ensure ring space available */ + xen_mb(); /* ensure ring space available */ XENKBD_IN_RING_REF(page, prod) = *event; - wmb(); /* ensure ring contents visible */ + xen_wmb(); /* ensure ring contents visible */ page->in_prod = prod + 1; return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } diff --git a/tools/ioemu/osdep.c b/tools/ioemu/osdep.c index d1eff8deb5..5ec16b47da 100644 --- a/tools/ioemu/osdep.c +++ b/tools/ioemu/osdep.c @@ -61,6 +61,10 @@ void *qemu_malloc(size_t size) } #if defined(_WIN32) +void *qemu_memalign(size_t alignment, size_t size) +{ + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} void *qemu_vmalloc(size_t size) { @@ -172,6 +176,22 @@ void kqemu_vfree(void *ptr) #endif +void *qemu_memalign(size_t alignment, size_t size) +{ +#if defined(_POSIX_C_SOURCE) + int ret; + void *ptr; + ret = posix_memalign(&ptr, alignment, size); + if (ret != 0) + return NULL; + return ptr; +#elif defined(_BSD) + return valloc(size); +#else + return memalign(alignment, size); +#endif +} + /* alloc shared memory pages */ void *qemu_vmalloc(size_t size) { diff --git a/tools/ioemu/osdep.h b/tools/ioemu/osdep.h index bd6ffc1713..6df1d87d12 100644 --- a/tools/ioemu/osdep.h +++ b/tools/ioemu/osdep.h @@ -14,6 +14,7 @@ void *qemu_mallocz(size_t size); void qemu_free(void *ptr); char *qemu_strdup(const char *str); +void *qemu_memalign(size_t alignment, size_t size); void *qemu_vmalloc(size_t size); void qemu_vfree(void *ptr); diff --git a/tools/ioemu/sdl.c b/tools/ioemu/sdl.c index 4d6d73a6a1..4d09469858 100644 --- a/tools/ioemu/sdl.c +++ b/tools/ioemu/sdl.c @@ -259,11 +259,9 @@ static void sdl_grab_end(void) sdl_update_caption(); } -static void sdl_send_mouse_event(int dz) +static void sdl_send_mouse_event(int dx, int dy, int dz, int state) { - int dx, dy, state, buttons; - state = SDL_GetRelativeMouseState(&dx, &dy); - buttons = 0; + int buttons = 0; if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) buttons |= MOUSE_EVENT_LBUTTON; if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) @@ -425,11 +423,19 @@ static void sdl_refresh(DisplayState *ds) case SDL_MOUSEMOTION: if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(0); + int dx, dy, state; + state = SDL_GetRelativeMouseState(&dx, &dy); + sdl_send_mouse_event(dx, dy, 0, state); } break; - case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: + if (gui_grab || kbd_mouse_is_absolute()) { + int dx, dy, state; + state = SDL_GetRelativeMouseState(&dx, &dy); + sdl_send_mouse_event(dx, dy, 0, state); + } + break; + case SDL_MOUSEBUTTONDOWN: { SDL_MouseButtonEvent *bev = &ev->button; if (!gui_grab && !kbd_mouse_is_absolute()) { @@ -439,16 +445,19 @@ static void sdl_refresh(DisplayState *ds) sdl_grab_start(); } } else { - int dz; + int dx, dy, dz, state; dz = 0; + state = SDL_GetRelativeMouseState(&dx, &dy); #ifdef SDL_BUTTON_WHEELUP - if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { + if (bev->button == SDL_BUTTON_WHEELUP) { dz = -1; - } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { + } else if (bev->button == SDL_BUTTON_WHEELDOWN) { dz = 1; + } else { + state = bev->button | state; } #endif - sdl_send_mouse_event(dz); + sdl_send_mouse_event(dx, dy, dz, state); } } break; @@ -499,6 +508,7 @@ void sdl_display_init(DisplayState *ds, int full_screen) ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; ds->dpy_refresh = sdl_refresh; + ds->dpy_colourdepth = NULL; sdl_resize(ds, 640, 400); sdl_update_caption(); diff --git a/tools/ioemu/target-i386-dm/cpu.h b/tools/ioemu/target-i386-dm/cpu.h index 017b8c021b..6071a8529e 100644 --- a/tools/ioemu/target-i386-dm/cpu.h +++ b/tools/ioemu/target-i386-dm/cpu.h @@ -37,17 +37,21 @@ #include "cpu-defs.h" +#ifdef CONFIG_SOFTFLOAT #include "softfloat.h" +#endif #if defined(__i386__) && !defined(CONFIG_SOFTMMU) #define USE_CODE_COPY #endif +#ifdef CONFIG_SOFTFLOAT #ifdef USE_X86LDOUBLE typedef floatx80 CPU86_LDouble; #else typedef float64 CPU86_LDouble; #endif +#endif /* Empty for now */ typedef struct CPUX86State { diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index d45ac7a999..4896b11ab8 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -218,7 +218,7 @@ static ioreq_t *__cpu_get_ioreq(int vcpu) return NULL; } - rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ + xen_rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ req->state = STATE_IOREQ_INPROCESS; return req; @@ -568,7 +568,7 @@ void __handle_buffered_iopage(CPUState *env) __handle_ioreq(env, &req); - mb(); + xen_mb(); buffered_io_page->read_pointer += qw ? 2 : 1; } } @@ -603,7 +603,7 @@ void cpu_handle_ioreq(void *opaque) return; } - wmb(); /* Update ioreq contents /then/ update state. */ + xen_wmb(); /* Update ioreq contents /then/ update state. */ /* * We do this before we send the response so that the tools diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index fc81fd16e1..703f1bfd6d 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -36,22 +36,29 @@ #include <sys/times.h> #include <sys/wait.h> #include <termios.h> +#ifndef CONFIG_STUBDOM #include <sys/poll.h> +#endif #include <sys/mman.h> #include <sys/ioctl.h> #include <sys/resource.h> #include <sys/socket.h> #include <netinet/in.h> +#ifndef CONFIG_STUBDOM #include <net/if.h> +#endif #if defined(__NetBSD__) #include <net/if_tap.h> #endif #if defined(__linux__) || defined(__Linux__) #include <linux/if_tun.h> #endif +#ifndef CONFIG_STUBDOM #include <arpa/inet.h> #include <dirent.h> +#endif #include <netdb.h> +#ifndef CONFIG_STUBDOM #ifdef _BSD #include <sys/stat.h> #ifndef _BSD @@ -70,6 +77,7 @@ #include <stropts.h> #endif #endif +#endif #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -80,6 +88,7 @@ #include <windows.h> #define getopt_long_only getopt_long #define memalign(align, size) malloc(size) +#define NO_DAEMONIZE 1 #endif #include "qemu_socket.h" @@ -131,10 +140,9 @@ #define MAX_IOPORTS 65536 const char *bios_dir = CONFIG_QEMU_SHAREDIR; -char phys_ram_file[1024]; -void *ioport_opaque[MAX_IOPORTS]; -IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; -IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; +void **ioport_opaque; +IOPortReadFunc *(*ioport_read_table)[MAX_IOPORTS]; +IOPortWriteFunc *(*ioport_write_table)[MAX_IOPORTS]; /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available to store the VM snapshots */ BlockDriverState *bs_table[MAX_DISKS + MAX_SCSI_DISKS + 1], *fd_table[MAX_FD]; @@ -186,7 +194,9 @@ const char *vnc_display; int acpi_enabled = 0; int fd_bootchk = 1; int no_reboot = 0; +#ifndef NO_DAEMONIZE int daemonize = 0; +#endif const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; @@ -224,17 +234,29 @@ void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) uint32_t default_ioport_readw(void *opaque, uint32_t address) { uint32_t data; - data = ioport_read_table[0][address](ioport_opaque[address], address); + IOPortReadFunc *func = ioport_read_table[0][address]; + if (!func) + func = default_ioport_readb; + data = func(ioport_opaque[address], address); address = (address + 1) & (MAX_IOPORTS - 1); - data |= ioport_read_table[0][address](ioport_opaque[address], address) << 8; + func = ioport_read_table[0][address]; + if (!func) + func = default_ioport_readb; + data |= func(ioport_opaque[address], address) << 8; return data; } void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) { - ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff); + IOPortWriteFunc *func = ioport_write_table[0][address]; + if (!func) + func = default_ioport_writeb; + func(ioport_opaque[address], address, data & 0xff); address = (address + 1) & (MAX_IOPORTS - 1); - ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff); + func = ioport_write_table[0][address]; + if (!func) + func = default_ioport_writeb; + func(ioport_opaque[address], address, (data >> 8) & 0xff); } uint32_t default_ioport_readl(void *opaque, uint32_t address) @@ -254,16 +276,9 @@ void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) void init_ioports(void) { - int i; - - for(i = 0; i < MAX_IOPORTS; i++) { - ioport_read_table[0][i] = default_ioport_readb; - ioport_write_table[0][i] = default_ioport_writeb; - ioport_read_table[1][i] = default_ioport_readw; - ioport_write_table[1][i] = default_ioport_writew; - ioport_read_table[2][i] = default_ioport_readl; - ioport_write_table[2][i] = default_ioport_writel; - } + ioport_opaque = malloc(MAX_IOPORTS * sizeof(*ioport_opaque)); + ioport_read_table = malloc(3 * MAX_IOPORTS * sizeof(**ioport_read_table)); + ioport_write_table = malloc(3 * MAX_IOPORTS * sizeof(**ioport_write_table)); } /* size is the word size in byte */ @@ -335,11 +350,14 @@ void isa_unassign_ioport(int start, int length) void cpu_outb(CPUState *env, int addr, int val) { + IOPortWriteFunc *func = ioport_write_table[0][addr]; + if (!func) + func = default_ioport_writeb; #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outb: %04x %02x\n", addr, val); #endif - ioport_write_table[0][addr](ioport_opaque[addr], addr, val); + func(ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -348,11 +366,14 @@ void cpu_outb(CPUState *env, int addr, int val) void cpu_outw(CPUState *env, int addr, int val) { + IOPortWriteFunc *func = ioport_write_table[1][addr]; + if (!func) + func = default_ioport_writew; #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outw: %04x %04x\n", addr, val); #endif - ioport_write_table[1][addr](ioport_opaque[addr], addr, val); + func(ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -361,11 +382,14 @@ void cpu_outw(CPUState *env, int addr, int val) void cpu_outl(CPUState *env, int addr, int val) { + IOPortWriteFunc *func = ioport_write_table[2][addr]; + if (!func) + func = default_ioport_writel; #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outl: %04x %08x\n", addr, val); #endif - ioport_write_table[2][addr](ioport_opaque[addr], addr, val); + func(ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) env->last_io_time = cpu_get_time_fast(); @@ -375,7 +399,10 @@ void cpu_outl(CPUState *env, int addr, int val) int cpu_inb(CPUState *env, int addr) { int val; - val = ioport_read_table[0][addr](ioport_opaque[addr], addr); + IOPortReadFunc *func = ioport_read_table[0][addr]; + if (!func) + func = default_ioport_readb; + val = func(ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inb : %04x %02x\n", addr, val); @@ -390,7 +417,10 @@ int cpu_inb(CPUState *env, int addr) int cpu_inw(CPUState *env, int addr) { int val; - val = ioport_read_table[1][addr](ioport_opaque[addr], addr); + IOPortReadFunc *func = ioport_read_table[1][addr]; + if (!func) + func = default_ioport_readw; + val = func(ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inw : %04x %04x\n", addr, val); @@ -405,7 +435,10 @@ int cpu_inw(CPUState *env, int addr) int cpu_inl(CPUState *env, int addr) { int val; - val = ioport_read_table[2][addr](ioport_opaque[addr], addr); + IOPortReadFunc *func = ioport_read_table[2][addr]; + if (!func) + func = default_ioport_readl; + val = func(ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inl : %04x %08x\n", addr, val); @@ -773,9 +806,6 @@ static QEMUTimer *active_timers[2]; static MMRESULT timerID; static HANDLE host_alarm = NULL; static unsigned int period = 1; -#else -/* frequency of the times() clock tick */ -static int timer_freq; #endif QEMUClock *qemu_new_clock(int type) @@ -1113,9 +1143,6 @@ static void init_timer_alarm(void) struct itimerval itv; #endif - /* get times() syscall frequency */ - timer_freq = sysconf(_SC_CLK_TCK); - #ifndef CONFIG_DM /* timer signal */ sigfillset(&act.sa_mask); @@ -1473,6 +1500,7 @@ static CharDriverState *qemu_chr_open_file_out(const char *file_out) return qemu_chr_open_fd(-1, fd_out); } +#ifndef CONFIG_STUBDOM static CharDriverState *qemu_chr_open_pipe(const char *filename) { int fd_in, fd_out; @@ -1718,6 +1746,7 @@ static CharDriverState *qemu_chr_open_stdio(void) } return chr; } +#endif /* * Create a store entry for a device (e.g., monitor, serial/parallel lines). @@ -1727,6 +1756,9 @@ static CharDriverState *qemu_chr_open_stdio(void) static int store_dev_info(char *devName, int domid, CharDriverState *cState, char *storeString) { +#ifdef CONFIG_STUBDOM + return 0; +#else int xc_handle; struct xs_handle *xs; char *path; @@ -1802,8 +1834,10 @@ static int store_dev_info(char *devName, int domid, close(xc_handle); return 0; +#endif } +#ifndef CONFIG_STUBDOM #ifdef __sun__ /* Once Solaris has openpty(), this is going to be removed. */ int openpty(int *amaster, int *aslave, char *name, @@ -2462,6 +2496,7 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) return qemu_chr_open_win_file(fd_out); } #endif +#endif /***********************************************************/ /* UDP Net console */ @@ -2532,7 +2567,7 @@ static void udp_chr_update_read_handler(CharDriverState *chr) } int parse_host_port(struct sockaddr_in *saddr, const char *str); -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); #endif int parse_host_src_port(struct sockaddr_in *haddr, @@ -2740,7 +2775,7 @@ static void tcp_chr_accept(void *opaque) CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; struct sockaddr_in saddr; -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS struct sockaddr_un uaddr; #endif struct sockaddr *addr; @@ -2748,7 +2783,7 @@ static void tcp_chr_accept(void *opaque) int fd; for(;;) { -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS if (s->is_unix) { len = sizeof(uaddr); addr = (struct sockaddr *)&uaddr; @@ -2797,13 +2832,13 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, int do_nodelay = 0; const char *ptr; struct sockaddr_in saddr; -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS struct sockaddr_un uaddr; #endif struct sockaddr *addr; socklen_t addrlen; -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS if (is_unix) { addr = (struct sockaddr *)&uaddr; addrlen = sizeof(uaddr); @@ -2842,7 +2877,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, if (!s) goto fail; -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS if (is_unix) fd = socket(PF_UNIX, SOCK_STREAM, 0); else @@ -2867,7 +2902,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, if (is_listen) { /* allow fast reuse */ -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS if (is_unix) { char path[109]; strncpy(path, uaddr.sun_path, 108); @@ -2954,12 +2989,14 @@ CharDriverState *qemu_chr_open(const char *filename) return qemu_chr_open_tcp(p, 0, 1); } else if (strstart(filename, "file:", &p)) { return qemu_chr_open_file_out(p); +#ifndef CONFIG_STUBDOM } else if (strstart(filename, "pipe:", &p)) { return qemu_chr_open_pipe(p); } else if (!strcmp(filename, "pty")) { return qemu_chr_open_pty(); } else if (!strcmp(filename, "stdio")) { return qemu_chr_open_stdio(); +#endif } else #endif #if defined(__linux__) @@ -3449,7 +3486,16 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd) return s; } -#ifdef _BSD +#ifdef CONFIG_STUBDOM +#include <netfront.h> +static int tap_open(char *ifname, int ifname_size) +{ + char nodename[64]; + static int num = 1; // 0 is for our own TCP/IP networking + snprintf(nodename, sizeof(nodename), "device/vif/%d", num++); + return netfront_tap_open(nodename); +} +#elif defined(_BSD) static int tap_open(char *ifname, int ifname_size) { int fd; @@ -3537,6 +3583,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, if (fd < 0) return -1; +#ifndef CONFIG_STUBDOM if (!setup_script || !strcmp(setup_script, "no")) setup_script = ""; if (setup_script[0] != '\0') { @@ -3569,6 +3616,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, } } } +#endif s = net_tap_fd_init(vlan, fd); if (!s) return -1; @@ -4397,6 +4445,7 @@ void dumb_display_init(DisplayState *ds) ds->depth = 0; ds->dpy_update = dumb_update; ds->dpy_resize = dumb_resize; + ds->dpy_colourdepth = NULL; ds->dpy_refresh = dumb_refresh; } @@ -6510,7 +6559,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" -#ifndef _WIN32 +#ifndef NO_DAEMONIZE "-daemonize daemonize QEMU after initializing\n" #endif "-option-rom rom load a file, rom, into the option ROM space\n" @@ -6600,7 +6649,9 @@ enum { QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, +#ifndef NO_DAEMONIZE QEMU_OPTION_daemonize, +#endif QEMU_OPTION_option_rom, QEMU_OPTION_semihosting , @@ -6698,7 +6749,9 @@ const QEMUOption qemu_options[] = { { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, +#ifndef NO_DAEMONIZE { "daemonize", 0, QEMU_OPTION_daemonize }, +#endif { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, #if defined(TARGET_ARM) { "semihosting", 0, QEMU_OPTION_semihosting }, @@ -7009,12 +7062,14 @@ int main(int argc, char **argv) char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; +#ifndef CONFIG_STUBDOM struct rlimit rl; +#endif sigset_t set; char qemu_dm_logfilename[128]; const char *direct_pci = NULL; -#ifndef __sun__ +#if !defined(__sun__) && !defined(CONFIG_STUBDOM) /* Maximise rlimits. Needed where default constraints are tight (*BSD). */ if (getrlimit(RLIMIT_STACK, &rl) != 0) { perror("getrlimit(RLIMIT_STACK)"); @@ -7040,6 +7095,7 @@ int main(int argc, char **argv) perror("setrlimit(RLIMIT_MEMLOCK)"); #endif +#ifndef CONFIG_STUBDOM /* Ensure that SIGUSR2 is blocked by default when a new thread is created, then only the threads that use the signal unblock it -- this fixes a race condition in Qcow support where the AIO signal is misdelivered. */ @@ -7082,6 +7138,7 @@ int main(int argc, char **argv) } } #endif +#endif register_machines(); machine = first_machine; @@ -7496,9 +7553,11 @@ int main(int argc, char **argv) case QEMU_OPTION_no_reboot: no_reboot = 1; break; +#ifndef NO_DAEMONIZE case QEMU_OPTION_daemonize: daemonize = 1; break; +#endif case QEMU_OPTION_option_rom: if (nb_option_roms >= MAX_OPTION_ROMS) { fprintf(stderr, "Too many option ROMs\n"); @@ -7542,7 +7601,7 @@ int main(int argc, char **argv) sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm-%d.log", domid); cpu_set_log_filename(qemu_dm_logfilename); -#ifndef _WIN32 +#ifndef NO_DAEMONIZE if (daemonize && !nographic && vnc_display == NULL && vncunused == 0) { fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n"); daemonize = 0; @@ -7593,7 +7652,15 @@ int main(int argc, char **argv) #ifdef CONFIG_DM bdrv_init(); xc_handle = xc_interface_open(); +#ifdef CONFIG_STUBDOM + char *domid_s, *msg; + if ((msg = xenbus_read(XBT_NIL, "domid", &domid_s))) + fprintf(stderr,"Can not read our own domid\n", msg); + else + xenstore_parse_domain_config(atoi(domid_s)); +#else /* CONFIG_STUBDOM */ xenstore_parse_domain_config(domid); +#endif /* CONFIG_STUBDOM */ #endif /* CONFIG_DM */ #ifdef USE_KQEMU @@ -7760,8 +7827,10 @@ int main(int argc, char **argv) vnc_display_password(ds, password); if ((vnc_display_port = vnc_display_open(ds, vnc_display, vncunused)) < 0) exit (0); +#ifndef CONFIG_STUBDOM if (vncviewer) vnc_start_viewer(vnc_display_port); +#endif xenstore_write_vncport(vnc_display_port); } else { #if defined(CONFIG_SDL) @@ -7863,6 +7932,7 @@ int main(int argc, char **argv) } } +#ifndef NO_DAEMONIZE if (daemonize) { uint8_t status = 0; ssize_t len; @@ -7886,12 +7956,17 @@ int main(int argc, char **argv) close(fd); } +#endif - /* Unblock SIGTERM, which may have been blocked by the caller */ +#ifndef CONFIG_STUBDOM + /* Unblock SIGTERM and SIGHUP, which may have been blocked by the caller */ + signal(SIGHUP, SIG_DFL); sigemptyset(&set); sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1) - fprintf(stderr, "Failed to unblock SIGTERM\n"); + fprintf(stderr, "Failed to unblock SIGTERM and SIGHUP\n"); +#endif main_loop(); quit_timers(); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 9d78cd25d9..00f5c16333 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -574,6 +574,9 @@ typedef struct BlockDriver BlockDriver; extern BlockDriver bdrv_raw; extern BlockDriver bdrv_host_device; +#ifdef CONFIG_STUBDOM +extern BlockDriver bdrv_vbd; +#endif extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow; extern BlockDriver bdrv_vmdk; @@ -912,8 +915,11 @@ struct DisplayState { int height; void *opaque; + int switchbpp; + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); + void (*dpy_colourdepth)(struct DisplayState *s, int depth); void (*dpy_refresh)(struct DisplayState *s); void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); }; diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c index 0dd78dd4b4..7f87f8ed18 100644 --- a/tools/ioemu/vnc.c +++ b/tools/ioemu/vnc.c @@ -30,6 +30,9 @@ #include "vl.h" #include "qemu_socket.h" #include <assert.h> +#ifdef CONFIG_STUBDOM +#include <netfront.h> +#endif /* 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 @@ -85,8 +88,8 @@ typedef void VncWritePixels(VncState *vs, void *data, int size); typedef void VncSendHextileTile(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg, - uint32_t *last_fg, + void *last_bg, + void *last_fg, int *has_bg, int *has_fg); #if 0 @@ -154,6 +157,7 @@ struct VncState int has_resize; int has_hextile; int has_pointer_type_change; + int has_WMVi; int absolute; int last_x; int last_y; @@ -187,9 +191,9 @@ struct VncState VncWritePixels *write_pixels; VncSendHextileTile *send_hextile_tile; int pix_bpp, pix_big_endian; - int red_shift, red_max, red_shift1; - int green_shift, green_max, green_shift1; - int blue_shift, blue_max, blue_shift1; + int red_shift, red_max, red_shift1, red_max1; + int green_shift, green_max, green_shift1, green_max1; + int blue_shift, blue_max, blue_shift1, blue_max1; VncReadEvent *read_handler; size_t read_handler_expect; @@ -379,54 +383,67 @@ static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) /* slowest but generic code. */ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) { - unsigned int r, g, b; + uint8_t r, g, b; - r = (v >> vs->red_shift1) & vs->red_max; - g = (v >> vs->green_shift1) & vs->green_max; - b = (v >> vs->blue_shift1) & vs->blue_max; - v = (r << vs->red_shift) | - (g << vs->green_shift) | - (b << vs->blue_shift); + r = ((v >> vs->red_shift1) & vs->red_max1) * (vs->red_max + 1) / (vs->red_max1 + 1); + g = ((v >> vs->green_shift1) & vs->green_max1) * (vs->green_max + 1) / (vs->green_max1 + 1); + b = ((v >> vs->blue_shift1) & vs->blue_max1) * (vs->blue_max + 1) / (vs->blue_max1 + 1); switch(vs->pix_bpp) { case 1: - buf[0] = v; + buf[0] = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift); break; case 2: + { + uint16_t *p = (uint16_t *) buf; + *p = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift); if (vs->pix_big_endian) { - buf[0] = v >> 8; - buf[1] = v; - } else { - buf[1] = v >> 8; - buf[0] = v; + *p = htons(*p); } + } break; default: case 4: + { + uint32_t *p = (uint32_t *) buf; + *p = (r << vs->red_shift) | (g << vs->green_shift) | (b << vs->blue_shift); if (vs->pix_big_endian) { - buf[0] = v >> 24; - buf[1] = v >> 16; - buf[2] = v >> 8; - buf[3] = v; - } else { - buf[3] = v >> 24; - buf[2] = v >> 16; - buf[1] = v >> 8; - buf[0] = v; + *p = htonl(*p); } break; } + } } static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) { - uint32_t *pixels = pixels1; uint8_t buf[4]; - int n, i; - n = size >> 2; - for(i = 0; i < n; i++) { - vnc_convert_pixel(vs, buf, pixels[i]); - vnc_write(vs, buf, vs->pix_bpp); + if (vs->depth == 4) { + uint32_t *pixels = pixels1; + int n, i; + n = size >> 2; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else if (vs->depth == 2) { + uint16_t *pixels = pixels1; + int n, i; + n = size >> 1; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else if (vs->depth == 1) { + uint8_t *pixels = pixels1; + int n, i; + n = size; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } + } else { + fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n"); } } @@ -463,6 +480,18 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) #undef BPP #define GENERIC +#define BPP 8 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + +#define GENERIC +#define BPP 16 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + +#define GENERIC #define BPP 32 #include "vnchextile.h" #undef BPP @@ -472,18 +501,22 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i { int i, j; int has_fg, has_bg; - uint32_t last_fg32, last_bg32; + void *last_fg, *last_bg; vnc_framebuffer_update(vs, x, y, w, h, 5); + last_fg = (void *) malloc(vs->depth); + last_bg = (void *) malloc(vs->depth); has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { vs->send_hextile_tile(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg32, &last_fg32, &has_bg, &has_fg); + last_bg, last_fg, &has_bg, &has_fg); } } + free(last_fg); + free(last_bg); } static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) @@ -1278,6 +1311,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->has_hextile = 0; vs->has_resize = 0; vs->has_pointer_type_change = 0; + vs->has_WMVi = 0; vs->absolute = -1; vs->ds->dpy_copy = NULL; @@ -1298,6 +1332,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) case -257: vs->has_pointer_type_change = 1; break; + case 0x574D5669: + vs->has_WMVi = 1; default: break; } @@ -1306,17 +1342,6 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) check_pointer_type_change(vs, kbd_mouse_is_absolute()); } -static int compute_nbits(unsigned int val) -{ - int n; - n = 0; - while (val != 0) { - n++; - val >>= 1; - } - return n; -} - static void set_pixel_format(VncState *vs, int bits_per_pixel, int depth, int big_endian_flag, int true_color_flag, @@ -1335,23 +1360,24 @@ static void set_pixel_format(VncState *vs, vnc_client_error(vs); return; } - if (bits_per_pixel == 32 && + if (bits_per_pixel == 32 && + bits_per_pixel == vs->depth * 8 && host_big_endian_flag == big_endian_flag && red_max == 0xff && green_max == 0xff && blue_max == 0xff && red_shift == 16 && green_shift == 8 && blue_shift == 0) { - vs->depth = 4; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_32; } else - if (bits_per_pixel == 16 && + if (bits_per_pixel == 16 && + bits_per_pixel == vs->depth * 8 && host_big_endian_flag == big_endian_flag && red_max == 31 && green_max == 63 && blue_max == 31 && red_shift == 11 && green_shift == 5 && blue_shift == 0) { - vs->depth = 2; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_16; } else if (bits_per_pixel == 8 && + bits_per_pixel == vs->depth * 8 && red_max == 7 && green_max == 7 && blue_max == 3 && red_shift == 5 && green_shift == 2 && blue_shift == 0) { vs->depth = 1; @@ -1364,28 +1390,170 @@ static void set_pixel_format(VncState *vs, bits_per_pixel != 16 && bits_per_pixel != 32) goto fail; - vs->depth = 4; - vs->red_shift = red_shift; - vs->red_max = red_max; - vs->red_shift1 = 24 - compute_nbits(red_max); - vs->green_shift = green_shift; - vs->green_max = green_max; - vs->green_shift1 = 16 - compute_nbits(green_max); - vs->blue_shift = blue_shift; - vs->blue_max = blue_max; - vs->blue_shift1 = 8 - compute_nbits(blue_max); - vs->pix_bpp = bits_per_pixel / 8; + if (vs->depth == 4) { + vs->send_hextile_tile = send_hextile_tile_generic_32; + } else if (vs->depth == 2) { + vs->send_hextile_tile = send_hextile_tile_generic_16; + } else { + vs->send_hextile_tile = send_hextile_tile_generic_8; + } + vs->pix_big_endian = big_endian_flag; vs->write_pixels = vnc_write_pixels_generic; - vs->send_hextile_tile = send_hextile_tile_generic; } - - vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); + + vs->red_shift = red_shift; + vs->red_max = red_max; + vs->green_shift = green_shift; + vs->green_max = green_max; + vs->blue_shift = blue_shift; + vs->blue_max = blue_max; + vs->pix_bpp = bits_per_pixel / 8; vga_hw_invalidate(); vga_hw_update(); } +static void pixel_format_message (VncState *vs) { + char pad[3] = { 0, 0, 0 }; + + vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ + if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */ + else vnc_write_u8(vs, vs->depth * 8); /* depth */ + +#ifdef WORDS_BIGENDIAN + vnc_write_u8(vs, 1); /* big-endian-flag */ +#else + vnc_write_u8(vs, 0); /* big-endian-flag */ +#endif + vnc_write_u8(vs, 1); /* true-color-flag */ + if (vs->depth == 4) { + vnc_write_u16(vs, 0xFF); /* red-max */ + vnc_write_u16(vs, 0xFF); /* green-max */ + vnc_write_u16(vs, 0xFF); /* blue-max */ + vnc_write_u8(vs, 16); /* red-shift */ + vnc_write_u8(vs, 8); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_32; + } else if (vs->depth == 2) { + vnc_write_u16(vs, 31); /* red-max */ + vnc_write_u16(vs, 63); /* green-max */ + vnc_write_u16(vs, 31); /* blue-max */ + vnc_write_u8(vs, 11); /* red-shift */ + vnc_write_u8(vs, 5); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_16; + } else if (vs->depth == 1) { + /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ + vnc_write_u16(vs, 7); /* red-max */ + vnc_write_u16(vs, 7); /* green-max */ + vnc_write_u16(vs, 3); /* blue-max */ + vnc_write_u8(vs, 5); /* red-shift */ + vnc_write_u8(vs, 2); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_8; + } + vs->red_max = vs->red_max1; + vs->green_max = vs->green_max1; + vs->blue_max = vs->blue_max1; + vs->red_shift = vs->red_shift1; + vs->green_shift = vs->green_shift1; + vs->blue_shift = vs->blue_shift1; + vs->pix_bpp = vs->depth * 8; + vs->write_pixels = vnc_write_pixels_copy; + + vnc_write(vs, pad, 3); /* padding */ +} + +static void vnc_dpy_colourdepth(DisplayState *ds, int depth) +{ + int host_big_endian_flag; + struct VncState *vs; + + if (!depth) return; + +#ifdef WORDS_BIGENDIAN + host_big_endian_flag = 1; +#else + host_big_endian_flag = 0; +#endif + vs = ds->opaque; + + switch (depth) { + case 8: + vs->depth = depth / 8; + vs->red_max1 = 7; + vs->green_max1 = 7; + vs->blue_max1 = 3; + vs->red_shift1 = 5; + vs->green_shift1 = 2; + vs->blue_shift1 = 0; + break; + case 16: + vs->depth = depth / 8; + vs->red_max1 = 31; + vs->green_max1 = 63; + vs->blue_max1 = 31; + vs->red_shift1 = 11; + vs->green_shift1 = 5; + vs->blue_shift1 = 0; + break; + case 32: + vs->depth = 4; + vs->red_max1 = 255; + vs->green_max1 = 255; + vs->blue_max1 = 255; + vs->red_shift1 = 16; + vs->green_shift1 = 8; + vs->blue_shift1 = 0; + break; + default: + return; + } + if (ds->switchbpp) { + vnc_client_error(vs); + } else if (vs->csock != -1 && vs->has_WMVi) { + /* Sending a WMVi message to notify the client*/ + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669); + pixel_format_message(vs); + vnc_flush(vs); + } else { + if (vs->pix_bpp == 4 && vs->depth == 4 && + host_big_endian_flag == vs->pix_big_endian && + vs->red_max == 0xff && vs->green_max == 0xff && vs->blue_max == 0xff && + vs->red_shift == 16 && vs->green_shift == 8 && vs->blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_32; + } else if (vs->pix_bpp == 2 && vs->depth == 2 && + host_big_endian_flag == vs->pix_big_endian && + vs->red_max == 31 && vs->green_max == 63 && vs->blue_max == 31 && + vs->red_shift == 11 && vs->green_shift == 5 && vs->blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_16; + } else if (vs->pix_bpp == 1 && vs->depth == 1 && + host_big_endian_flag == vs->pix_big_endian && + vs->red_max == 7 && vs->green_max == 7 && vs->blue_max == 3 && + vs->red_shift == 5 && vs->green_shift == 2 && vs->blue_shift == 0) { + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_8; + } else { + if (vs->depth == 4) { + vs->send_hextile_tile = send_hextile_tile_generic_32; + } else if (vs->depth == 2) { + vs->send_hextile_tile = send_hextile_tile_generic_16; + } else { + vs->send_hextile_tile = send_hextile_tile_generic_8; + } + vs->write_pixels = vnc_write_pixels_generic; + } + } + + vnc_dpy_resize(ds, ds->width, ds->height); +} + static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) { int i; @@ -1473,7 +1641,6 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) { size_t l; - char pad[3] = { 0, 0, 0 }; vga_hw_update(); @@ -1482,43 +1649,7 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) vnc_write_u16(vs, vs->ds->width); vnc_write_u16(vs, vs->ds->height); - vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ - vnc_write_u8(vs, vs->depth * 8); /* depth */ -#ifdef WORDS_BIGENDIAN - vnc_write_u8(vs, 1); /* big-endian-flag */ -#else - vnc_write_u8(vs, 0); /* big-endian-flag */ -#endif - vnc_write_u8(vs, 1); /* true-color-flag */ - if (vs->depth == 4) { - vnc_write_u16(vs, 0xFF); /* red-max */ - vnc_write_u16(vs, 0xFF); /* green-max */ - vnc_write_u16(vs, 0xFF); /* blue-max */ - vnc_write_u8(vs, 16); /* red-shift */ - vnc_write_u8(vs, 8); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_32; - } else if (vs->depth == 2) { - vnc_write_u16(vs, 31); /* red-max */ - vnc_write_u16(vs, 63); /* green-max */ - vnc_write_u16(vs, 31); /* blue-max */ - vnc_write_u8(vs, 11); /* red-shift */ - vnc_write_u8(vs, 5); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_16; - } else if (vs->depth == 1) { - /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ - vnc_write_u16(vs, 7); /* red-max */ - vnc_write_u16(vs, 7); /* green-max */ - vnc_write_u16(vs, 3); /* blue-max */ - vnc_write_u8(vs, 5); /* red-shift */ - vnc_write_u8(vs, 2); /* green-shift */ - vnc_write_u8(vs, 0); /* blue-shift */ - vs->send_hextile_tile = send_hextile_tile_8; - } - vs->write_pixels = vnc_write_pixels_copy; - - vnc_write(vs, pad, 3); /* padding */ + pixel_format_message(vs); l = strlen(domain_name); vnc_write_u32(vs, l); @@ -2160,7 +2291,6 @@ void vnc_display_init(DisplayState *ds) vs->lsock = -1; vs->csock = -1; - vs->depth = 4; vs->last_x = -1; vs->last_y = -1; @@ -2177,9 +2307,12 @@ void vnc_display_init(DisplayState *ds) vs->ds->data = NULL; vs->ds->dpy_update = vnc_dpy_update; vs->ds->dpy_resize = vnc_dpy_resize; + vs->ds->dpy_colourdepth = vnc_dpy_colourdepth; vs->ds->dpy_refresh = vnc_dpy_refresh; - vnc_dpy_resize(vs->ds, 640, 400); + vs->ds->width = 640; + vs->ds->height = 400; + vnc_dpy_colourdepth(vs->ds, 32); } #if CONFIG_VNC_TLS @@ -2297,10 +2430,12 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) { struct sockaddr *addr; struct sockaddr_in iaddr; -#ifndef _WIN32 +#ifndef NO_UNIX_SOCKETS struct sockaddr_un uaddr; #endif +#ifndef CONFIG_STUBDOM int reuse_addr, ret; +#endif socklen_t addrlen; const char *p; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; @@ -2325,6 +2460,8 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) options++; if (strncmp(options, "password", 8) == 0) { password = 1; /* Require password auth */ + } else if (strncmp(options, "switchbpp", 9) == 0) { + ds->switchbpp = 1; #if CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ @@ -2432,6 +2569,15 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) return -1; } +#ifdef CONFIG_STUBDOM + { + struct ip_addr ipaddr = { iaddr.sin_addr.s_addr }; + struct ip_addr netmask = { 0 }; + struct ip_addr gw = { 0 }; + networking_set_addr(&ipaddr, &netmask, &gw); + } +#endif + iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); vs->lsock = socket(PF_INET, SOCK_STREAM, 0); @@ -2442,6 +2588,7 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) return -1; } +#ifndef CONFIG_STUBDOM reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)); @@ -2453,6 +2600,7 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) vs->display = NULL; return -1; } +#endif } while (bind(vs->lsock, addr, addrlen) == -1) { @@ -2483,6 +2631,7 @@ int vnc_display_open(DisplayState *ds, const char *display, int find_unused) return ntohs(iaddr.sin_port); } +#ifndef CONFIG_STUBDOM int vnc_start_viewer(int port) { int pid, i, open_max; @@ -2510,4 +2659,5 @@ int vnc_start_viewer(int port) return pid; } } +#endif diff --git a/tools/ioemu/vnchextile.h b/tools/ioemu/vnchextile.h index 3d894cd574..29b74840f5 100644 --- a/tools/ioemu/vnchextile.h +++ b/tools/ioemu/vnchextile.h @@ -2,29 +2,29 @@ #define CONCAT(a, b) CONCAT_I(a, b) #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) #ifdef GENERIC -#define NAME generic +#define NAME CONCAT(generic_, BPP) #else #define NAME BPP #endif static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg32, - uint32_t *last_fg32, + void *last_bg_, + void *last_fg_, int *has_bg, int *has_fg) { uint8_t *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); pixel_t *irow = (pixel_t *)row; int j, i; - pixel_t *last_bg = (pixel_t *)last_bg32; - pixel_t *last_fg = (pixel_t *)last_fg32; + pixel_t *last_bg = (pixel_t *)last_bg_; + pixel_t *last_fg = (pixel_t *)last_fg_; pixel_t bg = 0; pixel_t fg = 0; int n_colors = 0; int bg_count = 0; int fg_count = 0; int flags = 0; - uint8_t data[(sizeof(pixel_t) + 2) * 16 * 16]; + uint8_t data[(vs->pix_bpp + 2) * 16 * 16]; int n_data = 0; int n_subtiles = 0; diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index 9d33237cb3..8cad6bda2d 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -11,8 +11,10 @@ #include "vl.h" #include "block_int.h" #include <unistd.h> +#ifndef CONFIG_STUBDOM #include <sys/ipc.h> #include <sys/shm.h> +#endif #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -219,10 +221,18 @@ void xenstore_parse_domain_config(int domid) } /* open device now if media present */ +#ifdef CONFIG_STUBDOM + if (pasprintf(&buf, "%s/device/vbd/%s", path, e[i]) == -1) + continue; + if (bdrv_open2(bs, buf, 0 /* snapshot */, &bdrv_vbd) == 0) { + pstrcpy(bs->filename, sizeof(bs->filename), params); + continue; + } +#endif + if (params[0]) { if (bdrv_open(bs, params, 0 /* snapshot */) < 0) - fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - params); + fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s'\n", buf, params); } } @@ -265,6 +275,10 @@ extern int vga_ram_size, bios_size; void xenstore_process_logdirty_event(void) { +#ifdef CONFIG_STUBDOM + /* XXX we just can't use shm. */ + return; +#else char *act; static char *active_path = NULL; static char *next_active_path = NULL; @@ -367,6 +381,7 @@ void xenstore_process_logdirty_event(void) /* Ack that we've switched */ xs_write(xsh, XBT_NULL, active_path, act, len); free(act); +#endif } diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index ffc5662052..b73bbfe55b 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -5,10 +5,12 @@ MAJOR = 3.2 MINOR = 0 CTRL_SRCS-y := +ifneq ($(stubdom),y) CTRL_SRCS-y += xc_core.c CTRL_SRCS-$(CONFIG_X86) += xc_core_x86.c CTRL_SRCS-$(CONFIG_IA64) += xc_core_ia64.c CTRL_SRCS-$(CONFIG_POWERPC) += xc_core_powerpc.c +endif CTRL_SRCS-y += xc_domain.c CTRL_SRCS-y += xc_evtchn.c CTRL_SRCS-y += xc_misc.c @@ -19,21 +21,27 @@ CTRL_SRCS-y += xc_private.c CTRL_SRCS-y += xc_sedf.c CTRL_SRCS-y += xc_csched.c CTRL_SRCS-y += xc_tbuf.c +ifneq ($(stubdom),y) CTRL_SRCS-y += xc_resume.c +endif 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 CTRL_SRCS-$(CONFIG_NetBSD) += xc_netbsd.c +CTRL_SRCS-$(CONFIG_MiniOS) += xc_minios.c GUEST_SRCS-y := GUEST_SRCS-y += xg_private.c +ifneq ($(stubdom),y) GUEST_SRCS-$(CONFIG_MIGRATE) += xc_domain_restore.c xc_domain_save.c GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c +endif VPATH = ../../xen/common/libelf CFLAGS += -I../../xen/common/libelf +ifneq ($(stubdom),y) GUEST_SRCS-y += libelf-tools.c libelf-loader.c GUEST_SRCS-y += libelf-dominfo.c libelf-relocate.c @@ -46,6 +54,7 @@ GUEST_SRCS-y += xc_dom_compat_linux.c GUEST_SRCS-$(CONFIG_X86) += xc_dom_x86.c GUEST_SRCS-$(CONFIG_IA64) += xc_dom_ia64.c GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_powerpc.c +endif -include $(XEN_TARGET_ARCH)/Makefile @@ -71,10 +80,14 @@ GUEST_LIB_OBJS := $(patsubst %.c,%.o,$(GUEST_SRCS-y)) GUEST_PIC_OBJS := $(patsubst %.c,%.opic,$(GUEST_SRCS-y)) LIB := libxenctrl.a +ifneq ($(stubdom),y) LIB += libxenctrl.so libxenctrl.so.$(MAJOR) libxenctrl.so.$(MAJOR).$(MINOR) +endif LIB += libxenguest.a +ifneq ($(stubdom),y) LIB += libxenguest.so libxenguest.so.$(MAJOR) libxenguest.so.$(MAJOR).$(MINOR) +endif .PHONY: all all: build @@ -133,7 +146,7 @@ libxenctrl.so.$(MAJOR): libxenctrl.so.$(MAJOR).$(MINOR) ln -sf $< $@ libxenctrl.so.$(MAJOR).$(MINOR): $(CTRL_PIC_OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ -lpthread + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ $(PTHREAD_LIBS) # libxenguest @@ -146,7 +159,7 @@ libxenguest.so.$(MAJOR): libxenguest.so.$(MAJOR).$(MINOR) ln -sf $< $@ libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so - $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz -lxenctrl -lpthread + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz -lxenctrl $(PTHREAD_LIBS) -include $(DEPS) diff --git a/tools/libxc/ia64/Makefile b/tools/libxc/ia64/Makefile index 8a23024b24..4fd4fbbe86 100644 --- a/tools/libxc/ia64/Makefile +++ b/tools/libxc/ia64/Makefile @@ -1,3 +1,4 @@ +ifneq ($(stubdom),y) CTRL_SRCS-y += ia64/xc_ia64_stubs.c GUEST_SRCS-y += ia64/xc_ia64_hvm_build.c @@ -8,6 +9,7 @@ GUEST_SRCS-y += ia64/xc_dom_ia64_util.c GUEST_SRCS-y += ia64/dom_fw_acpi.c DOMFW_SRCS_BASE := dom_fw_common.c dom_fw_domu.c dom_fw_asm.S +endif DOMFW_SRCS := $(addprefix ia64/, $(DOMFW_SRCS_BASE)) $(DOMFW_SRCS): ln -sf ../$(XEN_ROOT)/xen/arch/ia64/xen/$(@F) $@ diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index f75955c577..0f28ed5ca5 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -350,21 +350,6 @@ int xc_shadow_control(int xc_handle, return (rc == 0) ? domctl.u.shadow_op.pages : rc; } -int xc_domain_setcpuweight(int xc_handle, - uint32_t domid, - float weight) -{ - int sched_id; - int ret; - - /* Figure out which scheduler is currently used: */ - if ( (ret = xc_sched_id(xc_handle, &sched_id)) != 0 ) - return ret; - - /* No-op. */ - return 0; -} - int xc_domain_setmaxmem(int xc_handle, uint32_t domid, unsigned int max_memkb) diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index ec7e8fc9a2..52fc1155d2 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -251,7 +251,7 @@ static xen_pfn_t *load_p2m_frame_list( /* Now that we know the guest's word-size, can safely allocate * the p2m frame list */ - if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL ) + if ( (p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) == NULL ) { ERROR("Couldn't allocate p2m_frame_list array"); return NULL; @@ -1040,7 +1040,7 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, SET_FIELD(&ctxt, gdt_frames[j], p2m[pfn]); } /* Uncanonicalise the page table base pointer. */ - pfn = xen_cr3_to_pfn(GET_FIELD(&ctxt, ctrlreg[3])); + pfn = UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3])); if ( pfn >= p2m_size ) { @@ -1057,12 +1057,12 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT); goto out; } - SET_FIELD(&ctxt, ctrlreg[3], xen_pfn_to_cr3(p2m[pfn])); + SET_FIELD(&ctxt, ctrlreg[3], FOLD_CR3(p2m[pfn])); /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */ if ( (pt_levels == 4) && (ctxt.x64.ctrlreg[1] & 1) ) { - pfn = xen_cr3_to_pfn(ctxt.x64.ctrlreg[1] & ~1); + pfn = UNFOLD_CR3(ctxt.x64.ctrlreg[1] & ~1); if ( pfn >= p2m_size ) { ERROR("User PT base is bad: pfn=%lu p2m_size=%lu", @@ -1077,7 +1077,7 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT); goto out; } - ctxt.x64.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]); + ctxt.x64.ctrlreg[1] = FOLD_CR3(p2m[pfn]); } domctl.cmd = XEN_DOMCTL_setvcpucontext; domctl.domain = (domid_t)dom; @@ -1158,7 +1158,7 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, if ( guest_width > sizeof (xen_pfn_t) ) for ( i = p2m_size - 1; i >= 0; i-- ) ((uint64_t *)p2m)[i] = p2m[i]; - else if ( guest_width > sizeof (xen_pfn_t) ) + else if ( guest_width < sizeof (xen_pfn_t) ) for ( i = 0; i < p2m_size; i++ ) ((uint32_t *)p2m)[i] = p2m[i]; diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c index d37ea9cd51..3bd2db08b6 100644 --- a/tools/libxc/xc_domain_save.c +++ b/tools/libxc/xc_domain_save.c @@ -61,10 +61,11 @@ unsigned int guest_width; #define mfn_to_pfn(_mfn) (live_m2p[(_mfn)]) -#define pfn_to_mfn(_pfn) \ - ((xen_pfn_t) ((guest_width==8) \ - ? (((uint64_t *)live_p2m)[(_pfn)]) \ - : (((uint32_t *)live_p2m)[(_pfn)]))) +#define pfn_to_mfn(_pfn) \ + ((xen_pfn_t) ((guest_width==8) \ + ? (((uint64_t *)live_p2m)[(_pfn)]) \ + : ((((uint32_t *)live_p2m)[(_pfn)]) == 0xffffffffU \ + ? (-1UL) : (((uint32_t *)live_p2m)[(_pfn)])))) /* * Returns TRUE if the given machine frame number has a unique mapping @@ -496,10 +497,9 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, xen_start = L3_PAGETABLE_ENTRIES_PAE; /* - ** in PAE only the L2 mapping the top 1GB contains Xen mappings. - ** We can spot this by looking for the guest linear mapping which - ** Xen always ensures is present in that L2. Guests must ensure - ** that this check will fail for other L2s. + ** In PAE only the L2 mapping the top 1GB contains Xen mappings. + ** We can spot this by looking for the guest's mappingof the m2p. + ** Guests must ensure that this check will fail for other L2s. */ if ( (pt_levels == 3) && (type == XEN_DOMCTL_PFINFO_L2TAB) ) { @@ -555,7 +555,13 @@ static int canonicalize_pagetable(unsigned long type, unsigned long pfn, /* This will happen if the type info is stale which is quite feasible under live migration */ pfn = 0; /* zap it - we'll retransmit this page later */ - race = 1; /* inform the caller of race; fatal if !live */ + /* XXX: We can't spot Xen mappings in compat-mode L2es + * from 64-bit tools, but the only thing in them is the + * compat m2p, so we quietly zap them. This doesn't + * count as a race, so don't report it. */ + if ( !(type == XEN_DOMCTL_PFINFO_L2TAB + && sizeof (unsigned long) > guest_width) ) + race = 1; /* inform the caller; fatal if !live */ } else pfn = mfn_to_pfn(mfn); @@ -690,7 +696,7 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle, else p2m_frame_list_list[i] = 0; else if ( guest_width < sizeof(unsigned long) ) - for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i++ ) + for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i-- ) p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i]; live_p2m_frame_list = @@ -704,19 +710,20 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle, } /* Get a local copy of the live_P2M_frame_list */ - if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) ) + if ( !(p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) ) { ERROR("Couldn't allocate p2m_frame_list array"); goto out; } - memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE); + memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE); + memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE); /* Canonicalize guest's unsigned long vs ours */ if ( guest_width > sizeof(unsigned long) ) for ( i = 0; i < P2M_FL_ENTRIES; i++ ) p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i]; else if ( guest_width < sizeof(unsigned long) ) - for ( i = P2M_FL_ENTRIES - 1; i >= 0; i++ ) + for ( i = P2M_FL_ENTRIES - 1; i >= 0; i-- ) p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i]; @@ -1559,31 +1566,26 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, } /* Canonicalise the page table base pointer. */ - if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn( - GET_FIELD(&ctxt, ctrlreg[3]))) ) + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3( + GET_FIELD(&ctxt, ctrlreg[3]))) ) { ERROR("PT base is not in range of pseudophys map"); goto out; } SET_FIELD(&ctxt, ctrlreg[3], - xen_pfn_to_cr3( - mfn_to_pfn( - xen_cr3_to_pfn( - GET_FIELD(&ctxt, ctrlreg[3]))))); + FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3]))))); /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */ if ( (pt_levels == 4) && ctxt.x64.ctrlreg[1] ) { - if ( !MFN_IS_IN_PSEUDOPHYS_MAP( - xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])) ) + if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3(ctxt.x64.ctrlreg[1])) ) { ERROR("PT base is not in range of pseudophys map"); goto out; } /* Least-significant bit means 'valid PFN'. */ ctxt.x64.ctrlreg[1] = 1 | - xen_pfn_to_cr3( - mfn_to_pfn(xen_cr3_to_pfn(ctxt.x64.ctrlreg[1]))); + FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(ctxt.x64.ctrlreg[1]))); } if ( write_exact(io_fd, &ctxt, ((guest_width==8) diff --git a/tools/libxc/xc_minios.c b/tools/libxc/xc_minios.c new file mode 100644 index 0000000000..53f7a148da --- /dev/null +++ b/tools/libxc/xc_minios.c @@ -0,0 +1,313 @@ +/****************************************************************************** + * + * Copyright 2007-2008 Samuel Thibault <samuel.thibault@eu.citrix.com>. + * 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. + */ + +#undef NDEBUG +#include <types.h> +#include <os.h> +#include <mm.h> +#include <lib.h> +#include <events.h> +#include <wait.h> +#include <sys/mman.h> +#include <errno.h> + +#include <xen/memory.h> +#include <xen/sys/evtchn.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <assert.h> +#include <stdint.h> +#include <inttypes.h> + +#include "xc_private.h" + +extern struct wait_queue_head event_queue; + +int xc_interface_open(void) +{ + return 0; +} + +int xc_interface_close(int xc_handle) +{ + return 0; +} + +void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot, + xen_pfn_t *arr, int num) +{ + unsigned long pt_prot = 0; +#ifdef __ia64__ + /* TODO */ +#else + if (prot & PROT_READ) + pt_prot = L1_PROT_RO; + if (prot & PROT_WRITE) + pt_prot = L1_PROT; +#endif + return map_frames_ex(arr, num, 1, 0, 1, dom, 1, pt_prot); +} + +void *xc_map_foreign_range(int xc_handle, uint32_t dom, + int size, int prot, + unsigned long mfn) +{ + unsigned long pt_prot = 0; + printf("xc_map_foreign_range(%lx, %d)\n", mfn, size); +#ifdef __ia64__ + /* TODO */ +#else + if (prot & PROT_READ) + pt_prot = L1_PROT_RO; + if (prot & PROT_WRITE) + pt_prot = L1_PROT; +#endif + assert(!(size % getpagesize())); + return map_frames_ex(&mfn, size / getpagesize(), 0, 1, 1, dom, 0, pt_prot); +} + +int xc_map_foreign_ranges(int xc_handle, uint32_t dom, + privcmd_mmap_entry_t *entries, int nr) +{ + printf("xc_map_foreign_ranges, TODO\n"); + do_exit(); +} + +int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall) +{ + multicall_entry_t call; + int i, ret; + + call.op = hypercall->op; + for (i = 0; i < sizeof(hypercall->arg) / sizeof(*hypercall->arg); i++) + call.args[i] = hypercall->arg[i]; + + ret = HYPERVISOR_multicall(&call, 1); + + if (ret < 0) { + errno = -ret; + return -1; + } + if (call.result < 0) { + errno = -call.result; + return -1; + } + return call.result; +} + +int xc_find_device_number(const char *name) +{ + printf("xc_find_device_number(%s)\n", name); + do_exit(); +} + +int xc_evtchn_open(void) +{ + int fd = alloc_fd(FTYPE_EVTCHN), i; + for (i = 0; i < MAX_EVTCHN_PORTS; i++) { + files[fd].evtchn.ports[i].port = -1; + files[fd].evtchn.ports[i].bound = 0; + } + printf("evtchn_open() -> %d\n", fd); + return fd; +} + +int xc_evtchn_close(int xce_handle) +{ + int i; + for (i = 0; i < MAX_EVTCHN_PORTS; i++) + if (files[xce_handle].evtchn.ports[i].bound) + unbind_evtchn(files[xce_handle].evtchn.ports[i].port); + files[xce_handle].type = FTYPE_NONE; + return 0; +} + +int xc_evtchn_fd(int xce_handle) +{ + return xce_handle; +} + +int xc_evtchn_notify(int xce_handle, evtchn_port_t port) +{ + int ret; + + ret = notify_remote_via_evtchn(port); + + if (ret < 0) { + errno = -ret; + ret = -1; + } + return ret; +} + +/* XXX Note: This is not threadsafe */ +static int port_alloc(int xce_handle) { + int i; + for (i= 0; i < MAX_EVTCHN_PORTS; i++) + if (files[xce_handle].evtchn.ports[i].port == -1) + break; + if (i == MAX_EVTCHN_PORTS) { + printf("Too many ports in xc handle\n"); + errno = EMFILE; + return -1; + } + files[xce_handle].evtchn.ports[i].pending = 0; + return i; +} + +static void poke_port(int xce_handle, evtchn_port_t port) +{ + shared_info_t *s = HYPERVISOR_shared_info; + printk("poking port %d\n", port); + synch_set_bit(port, &s->evtchn_pending[0]); + xc_evtchn_unmask(xce_handle, port); +} + +static void evtchn_handler(evtchn_port_t port, struct pt_regs *regs, void *data) +{ + int xce_handle = (intptr_t) data; + int i; + assert(files[xce_handle].type == FTYPE_EVTCHN); + mask_evtchn(port); + for (i= 0; i < MAX_EVTCHN_PORTS; i++) + if (files[xce_handle].evtchn.ports[i].port == port) + break; + if (i == MAX_EVTCHN_PORTS) { + printk("Unknown port for handle %d\n", xce_handle); + return; + } + files[xce_handle].evtchn.ports[i].pending++; + files[xce_handle].read = 1; + wake_up(&event_queue); +} + +evtchn_port_or_error_t xc_evtchn_bind_unbound_port(int xce_handle, int domid) +{ + int ret, i; + evtchn_port_t port; + + assert(get_current() == main_thread); + i = port_alloc(xce_handle); + if (i == -1) + return -1; + + printf("xc_evtchn_bind_unbound_port(%d)", domid); + ret = evtchn_alloc_unbound(domid, evtchn_handler, (void*)(intptr_t)xce_handle, &port); + printf(" = %d\n", ret); + + if (ret < 0) { + errno = -ret; + return -1; + } + files[xce_handle].evtchn.ports[i].bound = 1; + files[xce_handle].evtchn.ports[i].port = port; + return port; +} + +evtchn_port_or_error_t xc_evtchn_bind_interdomain(int xce_handle, int domid, + evtchn_port_t remote_port) +{ + evtchn_port_t local_port; + int ret, i; + + assert(get_current() == main_thread); + i = port_alloc(xce_handle); + if (i == -1) + return -1; + + printf("xc_evtchn_bind_interdomain(%d, %"PRId32")", domid, remote_port); + ret = evtchn_bind_interdomain(domid, remote_port, evtchn_handler, (void*)(intptr_t)xce_handle, &local_port); + printf(" = %d\n", ret); + + if (ret < 0) { + errno = -ret; + return -1; + } + files[xce_handle].evtchn.ports[i].bound = 1; + files[xce_handle].evtchn.ports[i].port = local_port; +/* Poke port on start: HVM won't send an event for the very first request since + * we were not ready yet */ + poke_port(xce_handle, local_port); + return local_port; +} + +int xc_evtchn_unbind(int xce_handle, evtchn_port_t port) +{ + int i; + for (i = 0; i < MAX_EVTCHN_PORTS; i++) + if (files[xce_handle].evtchn.ports[i].port == port) { + files[xce_handle].evtchn.ports[i].port = -1; + break; + } + if (i == MAX_EVTCHN_PORTS) + printf("Warning: couldn't find port %"PRId32" for xc handle %x\n", port, xce_handle); + files[xce_handle].evtchn.ports[i].bound = 0; + unbind_evtchn(port); + return 0; +} + +evtchn_port_or_error_t xc_evtchn_bind_virq(int xce_handle, unsigned int virq) +{ + evtchn_port_t port; + int i; + + assert(get_current() == main_thread); + i = port_alloc(xce_handle); + if (i == -1) + return -1; + + printf("xc_evtchn_bind_virq(%d)", virq); + port = bind_virq(virq, evtchn_handler, (void*)(intptr_t)xce_handle); + + if (port < 0) { + errno = -port; + return -1; + } + files[xce_handle].evtchn.ports[i].bound = 1; + files[xce_handle].evtchn.ports[i].port = port; + return port; +} + +evtchn_port_or_error_t xc_evtchn_pending(int xce_handle) +{ + int i; + unsigned long flags; + local_irq_save(flags); + for (i = 0; i < MAX_EVTCHN_PORTS; i++) { + evtchn_port_t port = files[xce_handle].evtchn.ports[i].port; + if (port != -1 && files[xce_handle].evtchn.ports[i].pending) { + files[xce_handle].evtchn.ports[i].pending--; + local_irq_restore(flags); + return port; + } + } + files[xce_handle].read = 0; + local_irq_restore(flags); + return -1; +} + +int xc_evtchn_unmask(int xce_handle, evtchn_port_t port) +{ + unmask_evtchn(port); + 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/libxc/xenctrl.h b/tools/libxc/xenctrl.h index f6778dd946..afc80a36df 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -43,22 +43,21 @@ */ #if defined(__i386__) -#define mb() __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" ) -#define rmb() __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" ) -#define wmb() __asm__ __volatile__ ( "" : : : "memory") +#define xen_mb() asm volatile ( "lock; addl $0,0(%%esp)" : : : "memory" ) +#define xen_rmb() asm volatile ( "lock; addl $0,0(%%esp)" : : : "memory" ) +#define xen_wmb() asm volatile ( "" : : : "memory") #elif defined(__x86_64__) -#define mb() __asm__ __volatile__ ( "mfence" : : : "memory") -#define rmb() __asm__ __volatile__ ( "lfence" : : : "memory") -#define wmb() __asm__ __volatile__ ( "" : : : "memory") +#define xen_mb() asm volatile ( "mfence" : : : "memory") +#define xen_rmb() asm volatile ( "lfence" : : : "memory") +#define xen_wmb() asm volatile ( "" : : : "memory") #elif defined(__ia64__) -#define mb() __asm__ __volatile__ ("mf" ::: "memory") -#define rmb() __asm__ __volatile__ ("mf" ::: "memory") -#define wmb() __asm__ __volatile__ ("mf" ::: "memory") +#define xen_mb() asm volatile ("mf" ::: "memory") +#define xen_rmb() asm volatile ("mf" ::: "memory") +#define xen_wmb() asm volatile ("mf" ::: "memory") #elif defined(__powerpc__) -/* XXX loosen these up later */ -#define mb() __asm__ __volatile__ ("sync" : : : "memory") -#define rmb() __asm__ __volatile__ ("sync" : : : "memory") /* lwsync? */ -#define wmb() __asm__ __volatile__ ("sync" : : : "memory") /* eieio? */ +#define xen_mb() asm volatile ("sync" : : : "memory") +#define xen_rmb() asm volatile ("sync" : : : "memory") /* lwsync? */ +#define xen_wmb() asm volatile ("sync" : : : "memory") /* eieio? */ #else #error "Define barriers" #endif @@ -380,9 +379,6 @@ int xc_vcpu_getinfo(int xc_handle, uint32_t vcpu, xc_vcpuinfo_t *info); -int xc_domain_setcpuweight(int xc_handle, - uint32_t domid, - float weight); long long xc_domain_get_cpu_usage(int xc_handle, domid_t domid, int vcpu); diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h index 679c31896c..2ed3f55849 100644 --- a/tools/libxc/xg_private.h +++ b/tools/libxc/xg_private.h @@ -155,7 +155,9 @@ typedef l4_pgentry_64_t l4_pgentry_t; #define P2M_FL_ENTRIES (((p2m_size)+FPP-1)/FPP) /* Size in bytes of the pfn_to_mfn_frame_list */ -#define P2M_FL_SIZE ((P2M_FL_ENTRIES)*(guest_width)) +#define P2M_GUEST_FL_SIZE ((P2M_FL_ENTRIES) * (guest_width)) +#define P2M_TOOLS_FL_SIZE ((P2M_FL_ENTRIES) * \ + MAX((sizeof (xen_pfn_t)), guest_width)) /* Masks for PTE<->PFN conversions */ #define MADDR_BITS_X86 ((guest_width == 8) ? 52 : 44) diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h index b0379a4550..2da1e2090d 100644 --- a/tools/libxc/xg_save_restore.h +++ b/tools/libxc/xg_save_restore.h @@ -68,6 +68,13 @@ static inline int get_platform_info(int xc_handle, uint32_t dom, *guest_width = domctl.u.address_size.size / 8; + /* 64-bit tools will see the 64-bit hvirt_start, but 32-bit guests + * will be using the compat one. */ + if ( *guest_width < sizeof (unsigned long) ) + /* XXX need to fix up a way of extracting this value from Xen if + * XXX it becomes variable for domU */ + *hvirt_start = 0xf5800000; + if (strstr(xen_caps, "xen-3.0-x86_64")) /* Depends on whether it's a compat 32-on-64 guest */ *pt_levels = ( (*guest_width == 8) ? 4 : 3 ); @@ -136,6 +143,16 @@ typedef union (_p)->x32._f = (_v); \ } while (0) +#define UNFOLD_CR3(_c) \ + ((uint64_t)((guest_width == 8) \ + ? ((_c) >> 12) \ + : (((uint32_t)(_c) >> 12) | ((uint32_t)(_c) << 20)))) + +#define FOLD_CR3(_c) \ + ((uint64_t)((guest_width == 8) \ + ? ((uint64_t)(_c)) << 12 \ + : (((uint32_t)(_c) << 12) | ((uint32_t)(_c) >> 20)))) + #define MEMCPY_FIELD(_d, _s, _f) do { \ if (guest_width == 8) \ memcpy(&(_d)->x64._f, &(_s)->x64._f,sizeof((_d)->x64._f)); \ diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 425ed7b0fe..305138bd70 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -237,26 +237,6 @@ static PyObject *pyxc_vcpu_setaffinity(XcObject *self, return zero; } -static PyObject *pyxc_domain_setcpuweight(XcObject *self, - PyObject *args, - PyObject *kwds) -{ - uint32_t dom; - float cpuweight = 1; - - static char *kwd_list[] = { "domid", "cpuweight", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|f", kwd_list, - &dom, &cpuweight) ) - return NULL; - - if ( xc_domain_setcpuweight(self->xc_handle, dom, cpuweight) != 0 ) - return pyxc_error_to_exception(); - - Py_INCREF(zero); - return zero; -} - static PyObject *pyxc_domain_sethandle(XcObject *self, PyObject *args) { int i; @@ -1325,14 +1305,6 @@ static PyMethodDef pyxc_methods[] = { " cpumap [list, []]: list of usable CPUs.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, - { "domain_setcpuweight", - (PyCFunction)pyxc_domain_setcpuweight, - METH_VARARGS | METH_KEYWORDS, "\n" - "Set cpuweight scheduler parameter for domain.\n" - " dom [int]: Identifier of domain to be changed.\n" - " cpuweight [float, 1]: VCPU being pinned.\n" - "Returns: [int] 0 on success; -1 on error.\n" }, - { "domain_sethandle", (PyCFunction)pyxc_domain_sethandle, METH_VARARGS, "\n" diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 1eb7ee78ca..fafe3e8534 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -127,7 +127,7 @@ LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'loader', 'display', 'fda', 'fdb', 'keymap', 'isa', 'localtime', 'monitor', 'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl', - 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc', + 'soundhw','stdvga', 'usb', 'usbdevice', 'hpet', 'vnc', 'vncconsole', 'vncdisplay', 'vnclisten', 'timer_mode', 'vncpasswd', 'vncunused', 'xauthority', 'pci', 'vhpt', 'guest_os_type', 'hap'] @@ -406,15 +406,13 @@ class XendConfig(dict): if self.is_hvm(): if 'loader' not in self['platform']: - log.debug("No loader present") - # Old configs may have hvmloder set as PV_kernel param, - # so lets migrate them.... - if self['PV_kernel'] == "/usr/lib/xen/boot/hvmloader": + # Old configs may have hvmloader set as PV_kernel param + if self.has_key('PV_kernel') and re.search('hvmloader', self['PV_kernel']): self['platform']['loader'] = self['PV_kernel'] - log.debug("Loader copied from kernel %s" % str(self['platform']['loader'])) + self['PV_kernel'] = '' else: self['platform']['loader'] = "/usr/lib/xen/boot/hvmloader" - log.debug("Loader %s" % str(self['platform']['loader'])) + log.debug("Loader is %s" % str(self['platform']['loader'])) # Compatibility hack, can go away soon. if 'soundhw' not in self['platform'] and \ diff --git a/tools/python/xen/xend/XendConstants.py b/tools/python/xen/xend/XendConstants.py index a99dbdc92f..bca3ee7dd1 100644 --- a/tools/python/xen/xend/XendConstants.py +++ b/tools/python/xen/xend/XendConstants.py @@ -47,6 +47,7 @@ HVM_PARAM_NVRAM_FD = 7 HVM_PARAM_VHPT_SIZE = 8 HVM_PARAM_BUFPIOREQ_PFN = 9 HVM_PARAM_TIMER_MODE = 10 +HVM_PARAM_HPET_ENABLED = 11 restart_modes = [ "restart", diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 1e9c1b11f5..c1cb6aa998 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -707,9 +707,6 @@ class XendDomainInfo: log.debug("Setting memory maximum of domain %s (%s) to %d MiB.", self.info['name_label'], str(self.domid), limit) - if limit <= 0: - raise XendError('Invalid memory size') - MiB = 1024 * 1024 self._safe_set_memory('memory_static_max', limit * MiB) @@ -1692,6 +1689,12 @@ class XendDomainInfo: xc.hvm_set_param(self.domid, HVM_PARAM_TIMER_MODE, long(timer_mode)) + # Optionally enable virtual HPET + hpet = self.info["platform"].get("hpet") + if hvm and hpet is not None: + xc.hvm_set_param(self.domid, HVM_PARAM_HPET_ENABLED, + long(hpet)) + # Set maximum number of vcpus in domain xc.domain_max_vcpus(self.domid, int(self.info['VCPUs_max'])) @@ -1750,9 +1753,6 @@ class XendDomainInfo: self.image = image.create(self, self.info) - xc.domain_setcpuweight(self.domid, \ - self.info['vcpus_params']['weight']) - # repin domain vcpus if a restricted cpus list is provided # this is done prior to memory allocation to aide in memory # distribution for NUMA systems. diff --git a/tools/python/xen/xend/XendPBD.py b/tools/python/xen/xend/XendPBD.py index 10d8c32b81..2187cd7850 100644 --- a/tools/python/xen/xend/XendPBD.py +++ b/tools/python/xen/xend/XendPBD.py @@ -20,6 +20,7 @@ import uuid from XendLogging import log from xen.xend.XendBase import XendBase from xen.xend import XendAPIStore +from xen.xend import uuid as genuuid class XendPBD(XendBase): """Physical block devices.""" @@ -39,8 +40,7 @@ class XendPBD(XendBase): return XendBase.getAttrRW() + attrRW def getAttrInst(self): - return ['uuid', - 'host', + return ['host', 'SR', 'device_config'] @@ -61,31 +61,31 @@ class XendPBD(XendBase): getFuncs = classmethod(getFuncs) def recreate(uuid, record): - pbd = XendPBD(uuid, record) + pbd = XendPBD(record, uuid) return uuid def create(cls, record): uuid = genuuid.createString() - pbd = XendPBD(uuid, record) - return uuid + pbd = XendPBD(record, uuid) + return uuid create = classmethod(create) - def __init__(self, uuid, record): + def __init__(self, record, uuid): XendBase.__init__(self, uuid, record) - this.currently_attached = True + self.currently_attached = True def get_host(self): - return this.host + return self.host def get_SR(self): - return this.SR + return self.SR def get_device_config(self): - return this.device_config + return self.device_config def get_currently_attached(self): - return this.currently_attached + return self.currently_attached def destroy(self): pass diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 02ea81c748..069cde7dbe 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -91,12 +91,12 @@ class ImageHandler: ("image/cmdline", self.cmdline), ("image/ramdisk", self.ramdisk)) - self.dmargs = self.parseDeviceModelArgs(vmConfig) self.device_model = vmConfig['platform'].get('device_model') self.display = vmConfig['platform'].get('display') self.xauthority = vmConfig['platform'].get('xauthority') self.vncconsole = vmConfig['platform'].get('vncconsole') + self.dmargs = self.parseDeviceModelArgs(vmConfig) self.pid = None @@ -204,8 +204,14 @@ class ImageHandler: for dev_uuid in vmConfig['console_refs']: dev_type, dev_info = vmConfig['devices'][dev_uuid] if dev_type == 'vfb': - vnc_config = dev_info.get('other_config', {}) - has_vnc = True + vfb_type = dev_info.get('type', {}) + if vfb_type == 'sdl': + self.display = dev_info.get('display', {}) + self.xauthority = dev_info.get('xauthority', {}) + has_sdl = True + else: + vnc_config = dev_info.get('other_config', {}) + has_vnc = True break keymap = vmConfig['platform'].get("keymap") @@ -329,16 +335,27 @@ class ImageHandler: return if self.pid: try: - os.kill(self.pid, signal.SIGKILL) + os.kill(self.pid, signal.SIGHUP) except OSError, exn: log.exception(exn) try: - os.waitpid(self.pid, 0) + # Try to reap the child every 100ms for 10s. Then SIGKILL it. + for i in xrange(100): + (p, rv) = os.waitpid(self.pid, os.WNOHANG) + if p == self.pid: + break + time.sleep(0.1) + else: + log.warning("DeviceModel %d took more than 10s " + "to terminate: sending SIGKILL" % self.pid) + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) except OSError, exn: # This is expected if Xend has been restarted within the # life of this domain. In this case, we can kill the process, # but we can't wait for it because it's not our child. - pass + # We just make really sure it's going away (SIGKILL) first. + os.kill(self.pid, signal.SIGKILL) self.pid = None state = xstransact.Remove("/local/domain/0/device-model/%i" % self.vm.getDomid()) @@ -449,7 +466,7 @@ class HVMImageHandler(ImageHandler): ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) ret = ret + ['-vcpus', str(self.vm.getVCpuCount())] - if self.kernel and self.kernel != "/usr/lib/xen/boot/hvmloader": + if self.kernel: log.debug("kernel = %s", self.kernel) ret = ret + ['-kernel', self.kernel] if self.ramdisk: diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 1c508becd3..7a3d764c6b 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -198,6 +198,10 @@ gopts.var('pae', val='PAE', fn=set_int, default=1, use="Disable or enable PAE of HVM domain.") +gopts.var('hpet', val='HPET', + fn=set_int, default=0, + use="Enable virtual high-precision event timer.") + gopts.var('timer_mode', val='TIMER_MODE', fn=set_int, default=0, use="""Timer mode (0=delay virtual time when ticks are missed; @@ -740,7 +744,7 @@ def configure_hvm(config_image, vals): 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten', 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor', - 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', + 'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet', 'guest_os_type', 'hap'] for a in args: diff --git a/tools/python/xen/xm/xenapi_create.py b/tools/python/xen/xm/xenapi_create.py index 04abcc4e4e..9c16376955 100644 --- a/tools/python/xen/xm/xenapi_create.py +++ b/tools/python/xen/xm/xenapi_create.py @@ -818,7 +818,8 @@ class sxp2xml: def extract_platform(self, image, document): - platform_keys = ['acpi', 'apic', 'pae', 'vhpt', 'timer_mode', 'hap'] + platform_keys = ['acpi', 'apic', 'pae', 'vhpt', 'timer_mode', + 'hap', 'hpet'] def extract_platform_key(key): platform = document.createElement("platform") diff --git a/tools/xenmon/xenbaked.c b/tools/xenmon/xenbaked.c index 728f14b753..32ca9f36c3 100644 --- a/tools/xenmon/xenbaked.c +++ b/tools/xenmon/xenbaked.c @@ -511,10 +511,10 @@ int monitor_tbufs(void) { while ( meta[i]->cons != meta[i]->prod ) { - rmb(); /* read prod, then read item. */ + xen_rmb(); /* read prod, then read item. */ rec_size = process_record( i, (struct t_rec *)(data[i] + meta[i]->cons % data_size)); - mb(); /* read item, then update cons. */ + xen_mb(); /* read item, then update cons. */ meta[i]->cons += rec_size; } } diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 2cc9881eb4..d1d59f9f6f 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -112,7 +112,7 @@ static int writechn(struct connection *conn, /* Must read indexes once, and before anything else, and verified. */ cons = intf->rsp_cons; prod = intf->rsp_prod; - mb(); + xen_mb(); if (!check_indexes(cons, prod)) { errno = EIO; @@ -124,7 +124,7 @@ static int writechn(struct connection *conn, len = avail; memcpy(dest, data, len); - mb(); + xen_mb(); intf->rsp_prod += len; xc_evtchn_notify(xce_handle, conn->domain->port); @@ -142,7 +142,7 @@ static int readchn(struct connection *conn, void *data, unsigned int len) /* Must read indexes once, and before anything else, and verified. */ cons = intf->req_cons; prod = intf->req_prod; - mb(); + xen_mb(); if (!check_indexes(cons, prod)) { errno = EIO; @@ -154,7 +154,7 @@ static int readchn(struct connection *conn, void *data, unsigned int len) len = avail; memcpy(data, src, len); - mb(); + xen_mb(); intf->req_cons += len; xc_evtchn_notify(xce_handle, conn->domain->port); diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c index 26415bdb7d..7f394d2af0 100644 --- a/tools/xentrace/xentrace.c +++ b/tools/xentrace/xentrace.c @@ -23,6 +23,7 @@ #include <string.h> #include <getopt.h> #include <assert.h> +#include <sys/poll.h> #include <xen/xen.h> #include <xen/trace.h> @@ -40,9 +41,6 @@ do { \ /***** Compile time configuration of defaults ********************************/ -/* when we've got more records than this waiting, we log it to the output */ -#define NEW_DATA_THRESH 1 - /* sleep for this long (milliseconds) between checking the trace buffers */ #define POLL_SLEEP_MILLIS 100 @@ -51,8 +49,7 @@ do { \ typedef struct settings_st { char *outfile; - struct timespec poll_sleep; - unsigned long new_data_thresh; + unsigned long poll_sleep; /* milliseconds to sleep between polls */ uint32_t evt_mask; uint32_t cpu_mask; unsigned long tbuf_size; @@ -63,26 +60,16 @@ settings_t opts; int interrupted = 0; /* gets set if we get a SIGHUP */ +static int xc_handle = -1; +static int event_fd = -1; +static int virq_port = -1; + void close_handler(int signal) { interrupted = 1; } /** - * millis_to_timespec - convert a time in milliseconds to a struct timespec - * @millis: time interval in milliseconds - */ -struct timespec millis_to_timespec(unsigned long millis) -{ - struct timespec spec; - - spec.tv_sec = millis / 1000; - spec.tv_nsec = (millis % 1000) * 1000; - - return spec; -} - -/** * write_buffer - write a section of the trace buffer * @cpu - source buffer CPU ID * @start @@ -143,14 +130,8 @@ void write_buffer(unsigned int cpu, unsigned char *start, int size, static void get_tbufs(unsigned long *mfn, unsigned long *size) { - int xc_handle = xc_interface_open(); int ret; - if ( xc_handle < 0 ) - { - exit(EXIT_FAILURE); - } - if(!opts.tbuf_size) opts.tbuf_size = DEFAULT_TBUF_SIZE; @@ -161,8 +142,6 @@ static void get_tbufs(unsigned long *mfn, unsigned long *size) perror("Couldn't enable trace buffers"); exit(1); } - - xc_interface_close(xc_handle); } /** @@ -176,22 +155,12 @@ static void get_tbufs(unsigned long *mfn, unsigned long *size) struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num, unsigned long size) { - int xc_handle; struct t_buf *tbufs_mapped; - xc_handle = xc_interface_open(); - - if ( xc_handle < 0 ) - { - exit(EXIT_FAILURE); - } - tbufs_mapped = xc_map_foreign_range(xc_handle, DOMID_XEN, size * num, PROT_READ | PROT_WRITE, tbufs_mfn); - xc_interface_close(xc_handle); - if ( tbufs_mapped == 0 ) { PERROR("Failed to mmap trace buffers"); @@ -210,7 +179,6 @@ struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num, void set_mask(uint32_t mask, int type) { int ret = 0; - int xc_handle = xc_interface_open(); /* for accessing control interface */ if (type == 1) { ret = xc_tbuf_set_cpu_mask(xc_handle, mask); @@ -220,8 +188,6 @@ void set_mask(uint32_t mask, int type) fprintf(stderr, "change evtmask to 0x%x\n", mask); } - xc_interface_close(xc_handle); - if ( ret != 0 ) { PERROR("Failure to get trace buffer pointer from Xen and set the new mask"); @@ -295,7 +261,6 @@ unsigned char **init_rec_ptrs(struct t_buf **meta, unsigned int num) unsigned int get_num_cpus(void) { xc_physinfo_t physinfo = { 0 }; - int xc_handle = xc_interface_open(); int ret; ret = xc_physinfo(xc_handle, &physinfo); @@ -306,11 +271,70 @@ unsigned int get_num_cpus(void) exit(EXIT_FAILURE); } - xc_interface_close(xc_handle); - return physinfo.nr_cpus; } +/** + * event_init - setup to receive the VIRQ_TBUF event + */ +void event_init(void) +{ + int rc; + + rc = xc_evtchn_open(); + if (rc < 0) { + perror(xc_get_last_error()->message); + exit(EXIT_FAILURE); + } + event_fd = rc; + + rc = xc_evtchn_bind_virq(event_fd, VIRQ_TBUF); + if (rc == -1) { + PERROR("failed to bind to VIRQ port"); + exit(EXIT_FAILURE); + } + virq_port = rc; +} + +/** + * wait_for_event_or_timeout - sleep for the specified number of milliseconds, + * or until an VIRQ_TBUF event occurs + */ +void wait_for_event_or_timeout(unsigned long milliseconds) +{ + int rc; + struct pollfd fd = { .fd = event_fd, + .events = POLLIN | POLLERR }; + int port; + + rc = poll(&fd, 1, milliseconds); + if (rc == -1) { + if (errno == EINTR) + return; + PERROR("poll exitted with an error"); + exit(EXIT_FAILURE); + } + + if (rc == 1) { + port = xc_evtchn_pending(event_fd); + if (port == -1) { + PERROR("failed to read port from evtchn"); + exit(EXIT_FAILURE); + } + if (port != virq_port) { + fprintf(stderr, + "unexpected port returned from evtchn (got %d vs expected %d)\n", + port, virq_port); + exit(EXIT_FAILURE); + } + rc = xc_evtchn_unmask(event_fd, port); + if (rc == -1) { + PERROR("failed to write port to evtchn"); + exit(EXIT_FAILURE); + } + } +} + /** * monitor_tbufs - monitor the contents of tbufs and output to a file @@ -330,6 +354,9 @@ int monitor_tbufs(int outfd) unsigned long data_size; + /* prepare to listen for VIRQ_TBUF */ + event_init(); + /* get number of logical CPUs (and therefore number of trace buffers) */ num = get_num_cpus(); @@ -357,14 +384,23 @@ int monitor_tbufs(int outfd) /* Read window information only once. */ cons = meta[i]->cons; prod = meta[i]->prod; - rmb(); /* read prod, then read item. */ - + xen_rmb(); /* read prod, then read item. */ + if ( cons == prod ) continue; - assert(prod > cons); + assert(cons < 2*data_size); + assert(prod < 2*data_size); + + // NB: if (prod<cons), then (prod-cons)%data_size will not yield + // the correct answer because data_size is not a power of 2. + if ( prod < cons ) + window_size = (prod + 2*data_size) - cons; + else + window_size = prod - cons; + assert(window_size > 0); + assert(window_size <= data_size); - window_size = prod - cons; start_offset = cons % data_size; end_offset = prod % data_size; @@ -392,11 +428,11 @@ int monitor_tbufs(int outfd) outfd); } - mb(); /* read buffer, then update cons. */ + xen_mb(); /* read buffer, then update cons. */ meta[i]->cons = prod; } - nanosleep(&opts.poll_sleep, NULL); + wait_for_event_or_timeout(opts.poll_sleep); } /* cleanup */ @@ -416,7 +452,7 @@ int monitor_tbufs(int outfd) #define xstr(x) str(x) #define str(x) #x -const char *program_version = "xentrace v1.1"; +const char *program_version = "xentrace v1.2"; const char *program_bug_address = "<mark.a.williamson@intel.com>"; void usage(void) @@ -435,9 +471,6 @@ void usage(void) " N.B. that the trace buffer cannot be resized.\n" \ " if it has already been set this boot cycle,\n" \ " this argument will be ignored.\n" \ -" -t, --log-thresh=l Set number, l, of new records required to\n" \ -" trigger a write to output (default " \ - xstr(NEW_DATA_THRESH) ").\n" \ " -?, --help Show this message\n" \ " -V, --version Print program version\n" \ "\n" \ @@ -516,12 +549,8 @@ void parse_args(int argc, char **argv) { switch ( option ) { - case 't': /* set new records threshold for logging */ - opts.new_data_thresh = argtol(optarg, 0); - break; - case 's': /* set sleep time (given in milliseconds) */ - opts.poll_sleep = millis_to_timespec(argtol(optarg, 0)); + opts.poll_sleep = argtol(optarg, 0); break; case 'c': /* set new cpu mask for filtering*/ @@ -565,13 +594,19 @@ int main(int argc, char **argv) struct sigaction act; opts.outfile = 0; - opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS); - opts.new_data_thresh = NEW_DATA_THRESH; + opts.poll_sleep = POLL_SLEEP_MILLIS; opts.evt_mask = 0; opts.cpu_mask = 0; parse_args(argc, argv); - + + xc_handle = xc_interface_open(); + if ( xc_handle < 0 ) + { + perror(xc_get_last_error()->message); + exit(EXIT_FAILURE); + } + if ( opts.evt_mask != 0 ) set_mask(opts.evt_mask, 0); diff --git a/unmodified_drivers/linux-2.6/platform-pci/Kbuild b/unmodified_drivers/linux-2.6/platform-pci/Kbuild index 50951f94fd..7b332ee804 100644 --- a/unmodified_drivers/linux-2.6/platform-pci/Kbuild +++ b/unmodified_drivers/linux-2.6/platform-pci/Kbuild @@ -7,6 +7,7 @@ EXTRA_CFLAGS += -I$(M)/platform-pci xen-platform-pci-objs := evtchn.o platform-pci.o gnttab.o xen_support.o xen-platform-pci-objs += features.o platform-compat.o xen-platform-pci-objs += reboot.o machine_reboot.o +xen-platform-pci-objs += panic-handler.o xen-platform-pci-objs += ../xenbus/xenbus_comms.o xen-platform-pci-objs += ../xenbus/xenbus_xs.o diff --git a/unmodified_drivers/linux-2.6/platform-pci/panic-handler.c b/unmodified_drivers/linux-2.6/platform-pci/panic-handler.c new file mode 100644 index 0000000000..91bc03549b --- /dev/null +++ b/unmodified_drivers/linux-2.6/platform-pci/panic-handler.c @@ -0,0 +1,54 @@ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/notifier.h> +#include <asm/hypervisor.h> + +MODULE_LICENSE("GPL"); + +#ifdef __ia64__ +static void +xen_panic_hypercall(struct unw_frame_info *info, void *arg) +{ + current->thread.ksp = (__u64)info->sw - 16; + HYPERVISOR_shutdown(SHUTDOWN_crash); + /* we're never actually going to get here... */ +} +#endif + +static int +xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) +{ +#ifdef __ia64__ + unw_init_running(xen_panic_hypercall, NULL); +#else /* !__ia64__ */ + HYPERVISOR_shutdown(SHUTDOWN_crash); +#endif + /* we're never actually going to get here... */ + return NOTIFY_DONE; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +static struct notifier_block xen_panic_block = { + xen_panic_event, NULL, 0 /* try to go last */ +}; +#else +static struct notifier_block xen_panic_block = { + .notifier_call= xen_panic_event, + .next= NULL, + .priority= 0/* try to go last */ +}; +#endif /*LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)*/ + +static int __init setup_panic_event(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) + notifier_chain_register(&panic_notifier_list, &xen_panic_block); +#else + atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); +#endif /*LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)*/ + return 0; +} + +int xen_panic_handler_init(void) +{ + return setup_panic_event(); +} 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 7a512073d2..3d3a4c79a1 100644 --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @@ -249,6 +249,7 @@ static int set_callback_via(uint64_t via) int xen_irq_init(struct pci_dev *pdev); int xenbus_init(void); int xen_reboot_init(void); +int xen_panic_handler_init(void); int gnttab_init(void); static int __devinit platform_pci_init(struct pci_dev *pdev, @@ -317,6 +318,9 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, if ((ret = xen_reboot_init())) goto out; + if ((ret = xen_panic_handler_init())) + goto out; + out: if (ret) { release_mem_region(mmio_addr, mmio_len); diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S index 2c92dc6a00..143612c91f 100644 --- a/xen/arch/x86/boot/trampoline.S +++ b/xen/arch/x86/boot/trampoline.S @@ -155,6 +155,13 @@ trampoline_boot_cpu_entry: lidt bootsym(rm_idt) sti +#if defined(__x86_64__) + /* Declare that our target operating mode is long mode. */ + movw $0xec00,%ax # declare target operating mode + movw $0x0002,%bx # long mode + int $0x15 +#endif + /* * Do real-mode work: * 1. Get memory map. diff --git a/xen/arch/x86/cpu/mtrr/main.c b/xen/arch/x86/cpu/mtrr/main.c index 4881055d1a..2a606f0320 100644 --- a/xen/arch/x86/cpu/mtrr/main.c +++ b/xen/arch/x86/cpu/mtrr/main.c @@ -46,8 +46,6 @@ #define DEFINE_MUTEX(_m) DEFINE_SPINLOCK(_m) #define mutex_lock(_m) spin_lock(_m) #define mutex_unlock(_m) spin_unlock(_m) -#define lock_cpu_hotplug() ((void)0) -#define unlock_cpu_hotplug() ((void)0) #define dump_stack() ((void)0) #define get_cpu() smp_processor_id() #define put_cpu() do {} while(0) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 9d0537a9f9..25bc2c7148 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -82,7 +82,6 @@ static void default_idle(void) static void play_dead(void) { - __cpu_disable(); /* This must be done before dead CPU ack */ cpu_exit_clear(); hvm_cpu_down(); @@ -101,7 +100,7 @@ void idle_loop(void) { for ( ; ; ) { - if (cpu_is_offline(smp_processor_id())) + if ( cpu_is_offline(smp_processor_id()) ) play_dead(); page_scrub_schedule_work(); default_idle(); diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 1460f8e620..abfda3e737 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -530,7 +530,7 @@ long arch_do_domctl( u8 bus, devfn; ret = -EINVAL; - if ( !vtd_enabled ) + if ( !iommu_enabled ) break; bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff; @@ -553,7 +553,7 @@ long arch_do_domctl( u8 bus, devfn; ret = -EINVAL; - if ( !vtd_enabled ) + if ( !iommu_enabled ) break; if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) @@ -589,9 +589,9 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; bind = &(domctl->u.bind_pt_irq); - if (vtd_enabled) + if ( iommu_enabled ) ret = pt_irq_create_bind_vtd(d, bind); - if (ret < 0) + if ( ret < 0 ) gdprintk(XENLOG_ERR, "pt_irq_create_bind failed!\n"); rcu_unlock_domain(d); } diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index bb2e0e42c1..4e6e70e188 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -6,6 +6,7 @@ obj-y += i8254.o obj-y += instrlen.o obj-y += intercept.o obj-y += io.o +obj-y += iommu.o obj-y += irq.o obj-y += mtrr.o obj-y += platform.o diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c index f6845755a0..49ca998d37 100644 --- a/xen/arch/x86/hvm/hpet.c +++ b/xen/arch/x86/hvm/hpet.c @@ -353,7 +353,8 @@ static void hpet_write( static int hpet_range(struct vcpu *v, unsigned long addr) { - return ((addr >= HPET_BASE_ADDRESS) && + return (v->domain->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] && + (addr >= HPET_BASE_ADDRESS) && (addr < (HPET_BASE_ADDRESS + HPET_MMAP_SIZE))); } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 14c965cef9..92a63bf325 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -232,6 +232,8 @@ int hvm_domain_initialise(struct domain *d) spin_lock_init(&d->arch.hvm_domain.irq_lock); spin_lock_init(&d->arch.hvm_domain.uc_lock); + d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1; + hvm_init_cacheattr_region_list(d); rc = paging_enable(d, PG_refcounts|PG_translate|PG_external); @@ -285,9 +287,10 @@ static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h) { struct vcpu *v; struct hvm_hw_cpu ctxt; + struct segment_register seg; struct vcpu_guest_context *vc; - for_each_vcpu(d, v) + for_each_vcpu ( d, v ) { /* We don't need to save state for a vcpu that is down; the restore * code will leave it down if there is nothing saved. */ @@ -297,12 +300,69 @@ static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h) /* Architecture-specific vmcs/vmcb bits */ hvm_funcs.save_cpu_ctxt(v, &ctxt); - /* Other vcpu register state */ + hvm_get_segment_register(v, x86_seg_idtr, &seg); + ctxt.idtr_limit = seg.limit; + ctxt.idtr_base = seg.base; + + hvm_get_segment_register(v, x86_seg_gdtr, &seg); + ctxt.gdtr_limit = seg.limit; + ctxt.gdtr_base = seg.base; + + hvm_get_segment_register(v, x86_seg_cs, &seg); + ctxt.cs_sel = seg.sel; + ctxt.cs_limit = seg.limit; + ctxt.cs_base = seg.base; + ctxt.cs_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_ds, &seg); + ctxt.ds_sel = seg.sel; + ctxt.ds_limit = seg.limit; + ctxt.ds_base = seg.base; + ctxt.ds_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_es, &seg); + ctxt.es_sel = seg.sel; + ctxt.es_limit = seg.limit; + ctxt.es_base = seg.base; + ctxt.es_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_ss, &seg); + ctxt.ss_sel = seg.sel; + ctxt.ss_limit = seg.limit; + ctxt.ss_base = seg.base; + ctxt.ss_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_fs, &seg); + ctxt.fs_sel = seg.sel; + ctxt.fs_limit = seg.limit; + ctxt.fs_base = seg.base; + ctxt.fs_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_gs, &seg); + ctxt.gs_sel = seg.sel; + ctxt.gs_limit = seg.limit; + ctxt.gs_base = seg.base; + ctxt.gs_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_tr, &seg); + ctxt.tr_sel = seg.sel; + ctxt.tr_limit = seg.limit; + ctxt.tr_base = seg.base; + ctxt.tr_arbytes = seg.attr.bytes; + + hvm_get_segment_register(v, x86_seg_ldtr, &seg); + ctxt.ldtr_sel = seg.sel; + ctxt.ldtr_limit = seg.limit; + ctxt.ldtr_base = seg.base; + ctxt.ldtr_arbytes = seg.attr.bytes; + vc = &v->arch.guest_context; + if ( v->fpu_initialised ) memcpy(ctxt.fpu_regs, &vc->fpu_ctxt, sizeof(ctxt.fpu_regs)); else memset(ctxt.fpu_regs, 0, sizeof(ctxt.fpu_regs)); + ctxt.rax = vc->user_regs.eax; ctxt.rbx = vc->user_regs.ebx; ctxt.rcx = vc->user_regs.ecx; @@ -341,6 +401,7 @@ static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h) int vcpuid, rc; struct vcpu *v; struct hvm_hw_cpu ctxt; + struct segment_register seg; struct vcpu_guest_context *vc; /* Which vcpu is this? */ @@ -396,8 +457,64 @@ static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h) if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 ) return -EINVAL; - /* Other vcpu register state */ + seg.limit = ctxt.idtr_limit; + seg.base = ctxt.idtr_base; + hvm_set_segment_register(v, x86_seg_idtr, &seg); + + seg.limit = ctxt.gdtr_limit; + seg.base = ctxt.gdtr_base; + hvm_set_segment_register(v, x86_seg_gdtr, &seg); + + seg.sel = ctxt.cs_sel; + seg.limit = ctxt.cs_limit; + seg.base = ctxt.cs_base; + seg.attr.bytes = ctxt.cs_arbytes; + hvm_set_segment_register(v, x86_seg_cs, &seg); + + seg.sel = ctxt.ds_sel; + seg.limit = ctxt.ds_limit; + seg.base = ctxt.ds_base; + seg.attr.bytes = ctxt.ds_arbytes; + hvm_set_segment_register(v, x86_seg_ds, &seg); + + seg.sel = ctxt.es_sel; + seg.limit = ctxt.es_limit; + seg.base = ctxt.es_base; + seg.attr.bytes = ctxt.es_arbytes; + hvm_set_segment_register(v, x86_seg_es, &seg); + + seg.sel = ctxt.ss_sel; + seg.limit = ctxt.ss_limit; + seg.base = ctxt.ss_base; + seg.attr.bytes = ctxt.ss_arbytes; + hvm_set_segment_register(v, x86_seg_ss, &seg); + + seg.sel = ctxt.fs_sel; + seg.limit = ctxt.fs_limit; + seg.base = ctxt.fs_base; + seg.attr.bytes = ctxt.fs_arbytes; + hvm_set_segment_register(v, x86_seg_fs, &seg); + + seg.sel = ctxt.gs_sel; + seg.limit = ctxt.gs_limit; + seg.base = ctxt.gs_base; + seg.attr.bytes = ctxt.gs_arbytes; + hvm_set_segment_register(v, x86_seg_gs, &seg); + + seg.sel = ctxt.tr_sel; + seg.limit = ctxt.tr_limit; + seg.base = ctxt.tr_base; + seg.attr.bytes = ctxt.tr_arbytes; + hvm_set_segment_register(v, x86_seg_tr, &seg); + + seg.sel = ctxt.ldtr_sel; + seg.limit = ctxt.ldtr_limit; + seg.base = ctxt.ldtr_base; + seg.attr.bytes = ctxt.ldtr_arbytes; + hvm_set_segment_register(v, x86_seg_ldtr, &seg); + memcpy(&vc->fpu_ctxt, ctxt.fpu_regs, sizeof(ctxt.fpu_regs)); + vc->user_regs.eax = ctxt.rax; vc->user_regs.ebx = ctxt.rbx; vc->user_regs.ecx = ctxt.rcx; @@ -1269,6 +1386,7 @@ void hvm_task_switch( static enum hvm_copy_result __hvm_copy( void *buf, paddr_t addr, int size, int dir, int virt, int fetch) { + struct vcpu *curr = current; unsigned long gfn, mfn; p2m_type_t p2mt; char *p; @@ -1277,12 +1395,22 @@ static enum hvm_copy_result __hvm_copy( if ( virt ) { - struct segment_register sreg; - hvm_get_segment_register(current, x86_seg_ss, &sreg); - if ( sreg.attr.fields.dpl == 3 ) - pfec |= PFEC_user_mode; + /* + * We cannot use hvm_get_segment_register() while executing in + * vmx_realmode() as segment register state is cached. Furthermore, + * VMREADs on every data access hurts emulation performance. + */ + if ( !curr->arch.hvm_vmx.vmxemul ) + { + struct segment_register sreg; + hvm_get_segment_register(curr, x86_seg_ss, &sreg); + if ( sreg.attr.fields.dpl == 3 ) + pfec |= PFEC_user_mode; + } + if ( dir ) pfec |= PFEC_write_access; + if ( fetch ) pfec |= PFEC_insn_fetch; } @@ -1294,7 +1422,7 @@ static enum hvm_copy_result __hvm_copy( if ( virt ) { - gfn = paging_gva_to_gfn(current, addr, &pfec); + gfn = paging_gva_to_gfn(curr, addr, &pfec); if ( gfn == INVALID_GFN ) { if ( virt == 2 ) /* 2 means generate a fault */ @@ -1318,7 +1446,7 @@ static enum hvm_copy_result __hvm_copy( if ( dir ) { memcpy(p, buf, count); /* dir == TRUE: *to* guest */ - paging_mark_dirty(current->domain, mfn); + paging_mark_dirty(curr->domain, mfn); } else memcpy(buf, p, count); /* dir == FALSE: *from guest */ diff --git a/xen/arch/x86/hvm/iommu.c b/xen/arch/x86/hvm/iommu.c new file mode 100644 index 0000000000..30c92f42ea --- /dev/null +++ b/xen/arch/x86/hvm/iommu.c @@ -0,0 +1,135 @@ +/* + * 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/init.h> +#include <xen/irq.h> +#include <xen/spinlock.h> +#include <xen/sched.h> +#include <xen/xmalloc.h> +#include <xen/domain_page.h> +#include <asm/delay.h> +#include <asm/string.h> +#include <asm/mm.h> +#include <asm/iommu.h> +#include <asm/hvm/vmx/intel-iommu.h> + +extern struct iommu_ops intel_iommu_ops; +extern struct iommu_ops amd_iommu_ops; + +int iommu_domain_init(struct domain *domain) +{ + struct hvm_iommu *hd = domain_hvm_iommu(domain); + + spin_lock_init(&hd->mapping_lock); + spin_lock_init(&hd->iommu_list_lock); + INIT_LIST_HEAD(&hd->pdev_list); + INIT_LIST_HEAD(&hd->g2m_ioport_list); + + if ( !iommu_enabled ) + return 0; + + switch ( boot_cpu_data.x86_vendor ) + { + case X86_VENDOR_INTEL: + hd->platform_ops = &intel_iommu_ops; + break; + case X86_VENDOR_AMD: + hd->platform_ops = &amd_iommu_ops; + break; + default: + BUG(); + } + + return hd->platform_ops->init(domain); +} + +int assign_device(struct domain *d, u8 bus, u8 devfn) +{ + struct hvm_iommu *hd = domain_hvm_iommu(d); + + if ( !iommu_enabled || !hd->platform_ops) + return 0; + + return hd->platform_ops->assign_device(d, bus, devfn); +} + +void iommu_domain_destroy(struct domain *d) +{ + struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; + uint32_t i; + struct hvm_iommu *hd = domain_hvm_iommu(d); + struct list_head *ioport_list, *digl_list, *tmp; + struct g2m_ioport *ioport; + struct dev_intx_gsi_link *digl; + + if ( !iommu_enabled || !hd->platform_ops) + return; + + if ( hvm_irq_dpci != NULL ) + { + for ( i = 0; i < NR_IRQS; i++ ) + { + if ( !hvm_irq_dpci->mirq[i].valid ) + continue; + + pirq_guest_unbind(d, i); + kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]); + + list_for_each_safe ( digl_list, tmp, + &hvm_irq_dpci->mirq[i].digl_list ) + { + digl = list_entry(digl_list, + struct dev_intx_gsi_link, list); + list_del(&digl->list); + xfree(digl); + } + } + + d->arch.hvm_domain.irq.dpci = NULL; + xfree(hvm_irq_dpci); + } + + if ( hd ) + { + list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list ) + { + ioport = list_entry(ioport_list, struct g2m_ioport, list); + list_del(&ioport->list); + xfree(ioport); + } + } + + return hd->platform_ops->teardown(d); +} + +int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn) +{ + struct hvm_iommu *hd = domain_hvm_iommu(d); + + if ( !iommu_enabled || !hd->platform_ops) + return 0; + + return hd->platform_ops->map_page(d, gfn, mfn); +} + +int iommu_unmap_page(struct domain *d, unsigned long gfn) +{ + struct hvm_iommu *hd = domain_hvm_iommu(d); + + if ( !iommu_enabled || !hd->platform_ops) + return 0; + + return hd->platform_ops->unmap_page(d, gfn); +} diff --git a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c index 032ac0028d..c94be5f95d 100644 --- a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c +++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c @@ -89,12 +89,14 @@ int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr, u32 cap_header, cap_range; u64 mmio_bar; +#if HACK_BIOS_SETTINGS /* remove it when BIOS available */ write_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET, 0x00000000); write_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET, 0x40000001); /* remove it when BIOS available */ +#endif mmio_bar = (u64)read_pci_config(bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32; diff --git a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c index cd98ad0c87..7bdd289ca2 100644 --- a/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c +++ b/xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-map.c @@ -30,22 +30,20 @@ static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[]) u32 tail, head, *cmd_buffer; int i; - BUG_ON( !iommu || !cmd ); - tail = iommu->cmd_buffer_tail; - if ( ++tail == iommu->cmd_buffer.entries ) { + if ( ++tail == iommu->cmd_buffer.entries ) tail = 0; - } head = get_field_from_reg_u32( - readl(iommu->mmio_base+IOMMU_CMD_BUFFER_HEAD_OFFSET), - IOMMU_CMD_BUFFER_HEAD_MASK, - IOMMU_CMD_BUFFER_HEAD_SHIFT); - if ( head != tail ) { + readl(iommu->mmio_base+IOMMU_CMD_BUFFER_HEAD_OFFSET), + IOMMU_CMD_BUFFER_HEAD_MASK, + IOMMU_CMD_BUFFER_HEAD_SHIFT); + if ( head != tail ) + { cmd_buffer = (u32 *)(iommu->cmd_buffer.buffer + - (iommu->cmd_buffer_tail * IOMMU_CMD_BUFFER_ENTRY_SIZE)); - for ( i = 0; i < IOMMU_CMD_BUFFER_U32_PER_ENTRY; ++i ) { + (iommu->cmd_buffer_tail * + IOMMU_CMD_BUFFER_ENTRY_SIZE)); + for ( i = 0; i < IOMMU_CMD_BUFFER_U32_PER_ENTRY; i++ ) cmd_buffer[i] = cmd[i]; - } iommu->cmd_buffer_tail = tail; return 1; @@ -58,27 +56,25 @@ static void commit_iommu_command_buffer(struct amd_iommu *iommu) { u32 tail; - BUG_ON( !iommu ); - set_field_in_reg_u32(iommu->cmd_buffer_tail, 0, - IOMMU_CMD_BUFFER_TAIL_MASK, - IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail); + IOMMU_CMD_BUFFER_TAIL_MASK, + IOMMU_CMD_BUFFER_TAIL_SHIFT, &tail); writel(tail, iommu->mmio_base+IOMMU_CMD_BUFFER_TAIL_OFFSET); } int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]) { - BUG_ON( !iommu || !cmd ); - - if ( queue_iommu_command(iommu, cmd) ) { + if ( queue_iommu_command(iommu, cmd) ) + { commit_iommu_command_buffer(iommu); return 1; } + return 0; } static void invalidate_iommu_page(struct amd_iommu *iommu, - u64 io_addr, u16 domain_id) + u64 io_addr, u16 domain_id) { u64 addr_lo, addr_hi; u32 cmd[4], entry; @@ -87,51 +83,52 @@ static void invalidate_iommu_page(struct amd_iommu *iommu, addr_hi = io_addr >> 32; set_field_in_reg_u32(domain_id, 0, - IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK, - IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT, &entry); + IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_MASK, + IOMMU_INV_IOMMU_PAGES_DOMAIN_ID_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_IOMMU_PAGES, entry, - IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, &entry); + IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, + &entry); cmd[1] = entry; set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, 0, - IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK, - IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT, &entry); + IOMMU_INV_IOMMU_PAGES_S_FLAG_MASK, + IOMMU_INV_IOMMU_PAGES_S_FLAG_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, entry, - IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK, - IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT, &entry); + IOMMU_INV_IOMMU_PAGES_PDE_FLAG_MASK, + IOMMU_INV_IOMMU_PAGES_PDE_FLAG_SHIFT, &entry); set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, entry, - IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK, - IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT, &entry); + IOMMU_INV_IOMMU_PAGES_ADDR_LOW_MASK, + IOMMU_INV_IOMMU_PAGES_ADDR_LOW_SHIFT, &entry); cmd[2] = entry; set_field_in_reg_u32((u32)addr_hi, 0, - IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK, - IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT, &entry); + IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK, + IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT, &entry); cmd[3] = entry; cmd[0] = 0; send_iommu_command(iommu, cmd); } -static void flush_command_buffer(struct amd_iommu *iommu) +void flush_command_buffer(struct amd_iommu *iommu) { u32 cmd[4], status; int loop_count, comp_wait; /* clear 'ComWaitInt' in status register (WIC) */ set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0, - IOMMU_STATUS_COMP_WAIT_INT_MASK, - IOMMU_STATUS_COMP_WAIT_INT_SHIFT, &status); + IOMMU_STATUS_COMP_WAIT_INT_MASK, + IOMMU_STATUS_COMP_WAIT_INT_SHIFT, &status); writel(status, iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET); /* send an empty COMPLETION_WAIT command to flush command buffer */ cmd[3] = cmd[2] = 0; set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, 0, - IOMMU_CMD_OPCODE_MASK, - IOMMU_CMD_OPCODE_SHIFT, &cmd[1]); + IOMMU_CMD_OPCODE_MASK, + IOMMU_CMD_OPCODE_SHIFT, &cmd[1]); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0, - IOMMU_COMP_WAIT_I_FLAG_MASK, - IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]); + IOMMU_COMP_WAIT_I_FLAG_MASK, + IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]); send_iommu_command(iommu, cmd); /* wait for 'ComWaitInt' to signal comp#endifletion? */ @@ -139,34 +136,36 @@ static void flush_command_buffer(struct amd_iommu *iommu) loop_count = amd_iommu_poll_comp_wait; do { status = readl(iommu->mmio_base + - IOMMU_STATUS_MMIO_OFFSET); - comp_wait = get_field_from_reg_u32(status, - IOMMU_STATUS_COMP_WAIT_INT_MASK, - IOMMU_STATUS_COMP_WAIT_INT_SHIFT); + IOMMU_STATUS_MMIO_OFFSET); + comp_wait = get_field_from_reg_u32( + status, + IOMMU_STATUS_COMP_WAIT_INT_MASK, + IOMMU_STATUS_COMP_WAIT_INT_SHIFT); --loop_count; } while ( loop_count && !comp_wait ); - if ( comp_wait ) { + if ( comp_wait ) + { /* clear 'ComWaitInt' in status register (WIC) */ status &= IOMMU_STATUS_COMP_WAIT_INT_MASK; writel(status, iommu->mmio_base + - IOMMU_STATUS_MMIO_OFFSET); - } else - dprintk(XENLOG_WARNING, "AMD IOMMU: %s(): Warning:" - " ComWaitInt bit did not assert!\n", - __FUNCTION__); + IOMMU_STATUS_MMIO_OFFSET); + } + else + dprintk(XENLOG_WARNING, "AMD IOMMU: Warning:" + " ComWaitInt bit did not assert!\n"); } } static void clear_page_table_entry_present(u32 *pte) { set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, pte[0], - IOMMU_PTE_PRESENT_MASK, - IOMMU_PTE_PRESENT_SHIFT, &pte[0]); + IOMMU_PTE_PRESENT_MASK, + IOMMU_PTE_PRESENT_SHIFT, &pte[0]); } static void set_page_table_entry_present(u32 *pte, u64 page_addr, - int iw, int ir) + int iw, int ir) { u64 addr_lo, addr_hi; u32 entry; @@ -175,33 +174,33 @@ static void set_page_table_entry_present(u32 *pte, u64 page_addr, addr_hi = page_addr >> 32; set_field_in_reg_u32((u32)addr_hi, 0, - IOMMU_PTE_ADDR_HIGH_MASK, - IOMMU_PTE_ADDR_HIGH_SHIFT, &entry); + IOMMU_PTE_ADDR_HIGH_MASK, + IOMMU_PTE_ADDR_HIGH_SHIFT, &entry); set_field_in_reg_u32(iw ? IOMMU_CONTROL_ENABLED : - IOMMU_CONTROL_DISABLED, entry, - IOMMU_PTE_IO_WRITE_PERMISSION_MASK, - IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT, &entry); + IOMMU_CONTROL_DISABLED, entry, + IOMMU_PTE_IO_WRITE_PERMISSION_MASK, + IOMMU_PTE_IO_WRITE_PERMISSION_SHIFT, &entry); set_field_in_reg_u32(ir ? IOMMU_CONTROL_ENABLED : - IOMMU_CONTROL_DISABLED, entry, - IOMMU_PTE_IO_READ_PERMISSION_MASK, - IOMMU_PTE_IO_READ_PERMISSION_SHIFT, &entry); + IOMMU_CONTROL_DISABLED, entry, + IOMMU_PTE_IO_READ_PERMISSION_MASK, + IOMMU_PTE_IO_READ_PERMISSION_SHIFT, &entry); pte[1] = entry; set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0, - IOMMU_PTE_ADDR_LOW_MASK, - IOMMU_PTE_ADDR_LOW_SHIFT, &entry); + IOMMU_PTE_ADDR_LOW_MASK, + IOMMU_PTE_ADDR_LOW_SHIFT, &entry); set_field_in_reg_u32(IOMMU_PAGING_MODE_LEVEL_0, entry, - IOMMU_PTE_NEXT_LEVEL_MASK, - IOMMU_PTE_NEXT_LEVEL_SHIFT, &entry); + IOMMU_PTE_NEXT_LEVEL_MASK, + IOMMU_PTE_NEXT_LEVEL_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_PTE_PRESENT_MASK, - IOMMU_PTE_PRESENT_SHIFT, &entry); + IOMMU_PTE_PRESENT_MASK, + IOMMU_PTE_PRESENT_SHIFT, &entry); pte[0] = entry; } static void amd_iommu_set_page_directory_entry(u32 *pde, - u64 next_ptr, u8 next_level) + u64 next_ptr, u8 next_level) { u64 addr_lo, addr_hi; u32 entry; @@ -211,29 +210,31 @@ static void amd_iommu_set_page_directory_entry(u32 *pde, /* enable read/write permissions,which will be enforced at the PTE */ set_field_in_reg_u32((u32)addr_hi, 0, - IOMMU_PDE_ADDR_HIGH_MASK, IOMMU_PDE_ADDR_HIGH_SHIFT, &entry); + IOMMU_PDE_ADDR_HIGH_MASK, + IOMMU_PDE_ADDR_HIGH_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_PDE_IO_WRITE_PERMISSION_MASK, - IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &entry); + IOMMU_PDE_IO_WRITE_PERMISSION_MASK, + IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_PDE_IO_READ_PERMISSION_MASK, - IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry); + IOMMU_PDE_IO_READ_PERMISSION_MASK, + IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry); pde[1] = entry; /* mark next level as 'present' */ set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0, - IOMMU_PDE_ADDR_LOW_MASK, IOMMU_PDE_ADDR_LOW_SHIFT, &entry); + IOMMU_PDE_ADDR_LOW_MASK, + IOMMU_PDE_ADDR_LOW_SHIFT, &entry); set_field_in_reg_u32(next_level, entry, - IOMMU_PDE_NEXT_LEVEL_MASK, - IOMMU_PDE_NEXT_LEVEL_SHIFT, &entry); + IOMMU_PDE_NEXT_LEVEL_MASK, + IOMMU_PDE_NEXT_LEVEL_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_PDE_PRESENT_MASK, - IOMMU_PDE_PRESENT_SHIFT, &entry); + IOMMU_PDE_PRESENT_MASK, + IOMMU_PDE_PRESENT_SHIFT, &entry); pde[0] = entry; } void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u16 domain_id, - u8 paging_mode) + u8 paging_mode) { u64 addr_hi, addr_lo; u32 entry; @@ -241,54 +242,56 @@ void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u16 domain_id, dte[6] = dte[5] = dte[4] = 0; set_field_in_reg_u32(IOMMU_DEV_TABLE_SYS_MGT_MSG_FORWARDED, 0, - IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK, - IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry); + IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_MASK, + IOMMU_DEV_TABLE_SYS_MGT_MSG_ENABLE_SHIFT, &entry); dte[3] = entry; set_field_in_reg_u32(domain_id, 0, - IOMMU_DEV_TABLE_DOMAIN_ID_MASK, - IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry); + IOMMU_DEV_TABLE_DOMAIN_ID_MASK, + IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry); dte[2] = entry; addr_lo = root_ptr & DMA_32BIT_MASK; addr_hi = root_ptr >> 32; set_field_in_reg_u32((u32)addr_hi, 0, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT, &entry); + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK, + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK, - IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT, &entry); + IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_MASK, + IOMMU_DEV_TABLE_IO_WRITE_PERMISSION_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK, - IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry); + IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK, + IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry); dte[1] = entry; set_field_in_reg_u32((u32)addr_lo >> PAGE_SHIFT, 0, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry); + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK, + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry); set_field_in_reg_u32(paging_mode, entry, - IOMMU_DEV_TABLE_PAGING_MODE_MASK, - IOMMU_DEV_TABLE_PAGING_MODE_SHIFT, &entry); + IOMMU_DEV_TABLE_PAGING_MODE_MASK, + IOMMU_DEV_TABLE_PAGING_MODE_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK, - IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry); + IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK, + IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &entry); set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry, - IOMMU_DEV_TABLE_VALID_MASK, - IOMMU_DEV_TABLE_VALID_SHIFT, &entry); + IOMMU_DEV_TABLE_VALID_MASK, + IOMMU_DEV_TABLE_VALID_SHIFT, &entry); dte[0] = entry; } -static void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry) +void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry) { u64 addr_lo, addr_hi, ptr; - addr_lo = get_field_from_reg_u32(entry[0], - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT); + addr_lo = get_field_from_reg_u32( + entry[0], + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK, + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT); - addr_hi = get_field_from_reg_u32(entry[1], - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK, - IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT); + addr_hi = get_field_from_reg_u32( + entry[1], + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_MASK, + IOMMU_DEV_TABLE_PAGE_TABLE_PTR_HIGH_SHIFT); ptr = (addr_hi << 32) | (addr_lo << PAGE_SHIFT); return ptr ? maddr_to_virt((unsigned long)ptr) : NULL; @@ -297,42 +300,74 @@ static void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry) static int amd_iommu_is_pte_present(u32 *entry) { return (get_field_from_reg_u32(entry[0], - IOMMU_PDE_PRESENT_MASK, - IOMMU_PDE_PRESENT_SHIFT)); + IOMMU_PDE_PRESENT_MASK, + IOMMU_PDE_PRESENT_SHIFT)); +} + +void invalidate_dev_table_entry(struct amd_iommu *iommu, + u16 device_id) +{ + u32 cmd[4], entry; + + cmd[3] = cmd[2] = 0; + set_field_in_reg_u32(device_id, 0, + IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_MASK, + IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_SHIFT, &entry); + cmd[0] = entry; + + set_field_in_reg_u32(IOMMU_CMD_INVALIDATE_DEVTAB_ENTRY, 0, + IOMMU_CMD_OPCODE_MASK, IOMMU_CMD_OPCODE_SHIFT, + &entry); + cmd[1] = entry; + + send_iommu_command(iommu, cmd); +} + +int amd_iommu_is_dte_page_translation_valid(u32 *entry) +{ + return (get_field_from_reg_u32(entry[0], + IOMMU_DEV_TABLE_VALID_MASK, + IOMMU_DEV_TABLE_VALID_SHIFT) && + get_field_from_reg_u32(entry[0], + IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK, + IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT)); } static void *get_pte_from_page_tables(void *table, int level, - unsigned long io_pfn) + unsigned long io_pfn) { unsigned long offset; - void *pde = 0; + void *pde = NULL; - BUG_ON( !table ); + BUG_ON(table == NULL); while ( level > 0 ) { - void *next_table = 0; - unsigned long next_ptr; offset = io_pfn >> ((PTE_PER_TABLE_SHIFT * - (level - IOMMU_PAGING_MODE_LEVEL_1))); + (level - IOMMU_PAGING_MODE_LEVEL_1))); offset &= ~PTE_PER_TABLE_MASK; pde = table + (offset * IOMMU_PAGE_TABLE_ENTRY_SIZE); if ( level == 1 ) break; if ( !pde ) - return NULL; - if ( !amd_iommu_is_pte_present(pde) ) { - next_table = alloc_xenheap_page(); + return NULL; + if ( !amd_iommu_is_pte_present(pde) ) + { + void *next_table = alloc_xenheap_page(); if ( next_table == NULL ) return NULL; memset(next_table, 0, PAGE_SIZE); - if ( *(u64*)(pde) == 0 ) { - next_ptr = (u64)virt_to_maddr(next_table); - amd_iommu_set_page_directory_entry((u32 *)pde, - next_ptr, level - 1); - } else + if ( *(u64 *)pde == 0 ) + { + unsigned long next_ptr = (u64)virt_to_maddr(next_table); + amd_iommu_set_page_directory_entry( + (u32 *)pde, next_ptr, level - 1); + } + else + { free_xenheap_page(next_table); + } } table = amd_iommu_get_vptr_from_page_table_entry(pde); level--; @@ -341,8 +376,7 @@ static void *get_pte_from_page_tables(void *table, int level, return pde; } -int amd_iommu_map_page(struct domain *d, unsigned long gfn, - unsigned long mfn) +int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn) { void *pte; unsigned long flags; @@ -352,7 +386,7 @@ int amd_iommu_map_page(struct domain *d, unsigned long gfn, BUG_ON( !hd->root_table ); - maddr = (u64)(mfn << PAGE_SHIFT); + maddr = (u64)mfn << PAGE_SHIFT; iw = IOMMU_IO_WRITE_ENABLED; ir = IOMMU_IO_READ_ENABLED; @@ -360,18 +394,18 @@ int amd_iommu_map_page(struct domain *d, unsigned long gfn, spin_lock_irqsave(&hd->mapping_lock, flags); pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn); - - if ( pte != 0 ) { - set_page_table_entry_present((u32 *)pte, maddr, iw, ir); - spin_unlock_irqrestore(&hd->mapping_lock, flags); - return 0; - } else { + if ( pte == 0 ) + { dprintk(XENLOG_ERR, - "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", - __FUNCTION__, gfn); + "AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", gfn); spin_unlock_irqrestore(&hd->mapping_lock, flags); return -EIO; } + + set_page_table_entry_present((u32 *)pte, maddr, iw, ir); + + spin_unlock_irqrestore(&hd->mapping_lock, flags); + return 0; } int amd_iommu_unmap_page(struct domain *d, unsigned long gfn) @@ -386,34 +420,31 @@ int amd_iommu_unmap_page(struct domain *d, unsigned long gfn) BUG_ON( !hd->root_table ); requestor_id = hd->domain_id; - io_addr = (u64)(gfn << PAGE_SHIFT); + io_addr = (u64)gfn << PAGE_SHIFT; spin_lock_irqsave(&hd->mapping_lock, flags); pte = get_pte_from_page_tables(hd->root_table, hd->paging_mode, gfn); - - if ( pte != 0 ) { - /* mark PTE as 'page not present' */ - clear_page_table_entry_present((u32 *)pte); - spin_unlock_irqrestore(&hd->mapping_lock, flags); - - /* send INVALIDATE_IOMMU_PAGES command */ - for_each_amd_iommu(iommu) { - - spin_lock_irqsave(&iommu->lock, flags); - - invalidate_iommu_page(iommu, io_addr, requestor_id); - flush_command_buffer(iommu); - - spin_unlock_irqrestore(&iommu->lock, flags); - } - - return 0; - } else { + if ( pte == 0 ) + { dprintk(XENLOG_ERR, - "%s() AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", - __FUNCTION__, gfn); + "AMD IOMMU: Invalid IO pagetable entry gfn = %lx\n", gfn); spin_unlock_irqrestore(&hd->mapping_lock, flags); return -EIO; } + + /* mark PTE as 'page not present' */ + clear_page_table_entry_present((u32 *)pte); + spin_unlock_irqrestore(&hd->mapping_lock, flags); + + /* send INVALIDATE_IOMMU_PAGES command */ + for_each_amd_iommu(iommu) + { + spin_lock_irqsave(&iommu->lock, flags); + invalidate_iommu_page(iommu, io_addr, requestor_id); + flush_command_buffer(iommu); + spin_unlock_irqrestore(&iommu->lock, flags); + } + + return 0; } diff --git a/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c b/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c index 8b99a78257..7caa276f73 100644 --- a/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c +++ b/xen/arch/x86/hvm/svm/amd_iommu/pci-amd-iommu.c @@ -51,19 +51,17 @@ static void __init init_cleanup(void) { struct amd_iommu *iommu; - dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__); - - for_each_amd_iommu(iommu) { + for_each_amd_iommu ( iommu ) unmap_iommu_mmio_region(iommu); - } } static void __init deallocate_iommu_table_struct( - struct table_struct *table) + struct table_struct *table) { - if (table->buffer) { + if ( table->buffer ) + { free_xenheap_pages(table->buffer, - get_order_from_bytes(table->alloc_size)); + get_order_from_bytes(table->alloc_size)); table->buffer = NULL; } } @@ -76,11 +74,10 @@ static void __init deallocate_iommu_resources(struct amd_iommu *iommu) static void __init detect_cleanup(void) { - struct amd_iommu *iommu; + struct amd_iommu *iommu, *next; - dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__); - - for_each_amd_iommu(iommu) { + list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list ) + { list_del(&iommu->list); deallocate_iommu_resources(iommu); xfree(iommu); @@ -91,19 +88,21 @@ static int requestor_id_from_bdf(int bdf) { /* HACK - HACK */ /* account for possible 'aliasing' by parent device */ - return bdf; + return bdf; } static int __init allocate_iommu_table_struct(struct table_struct *table, - const char *name) + const char *name) { table->buffer = (void *) alloc_xenheap_pages( get_order_from_bytes(table->alloc_size)); - if ( !table->buffer ) { + if ( !table->buffer ) + { dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating %s\n", name); return -ENOMEM; } + memset(table->buffer, 0, table->alloc_size); return 0; @@ -114,32 +113,32 @@ static int __init allocate_iommu_resources(struct amd_iommu *iommu) /* allocate 'device table' on a 4K boundary */ iommu->dev_table.alloc_size = PAGE_ALIGN(((iommu->last_downstream_bus + 1) * - IOMMU_DEV_TABLE_ENTRIES_PER_BUS) * - IOMMU_DEV_TABLE_ENTRY_SIZE); + IOMMU_DEV_TABLE_ENTRIES_PER_BUS) * + IOMMU_DEV_TABLE_ENTRY_SIZE); iommu->dev_table.entries = iommu->dev_table.alloc_size / IOMMU_DEV_TABLE_ENTRY_SIZE; - if (allocate_iommu_table_struct(&iommu->dev_table, - "Device Table") != 0) + if ( allocate_iommu_table_struct(&iommu->dev_table, + "Device Table") != 0 ) goto error_out; /* allocate 'command buffer' in power of 2 increments of 4K */ iommu->cmd_buffer_tail = 0; iommu->cmd_buffer.alloc_size = PAGE_SIZE << get_order_from_bytes( - PAGE_ALIGN(amd_iommu_cmd_buffer_entries * - IOMMU_CMD_BUFFER_ENTRY_SIZE)); + PAGE_ALIGN(amd_iommu_cmd_buffer_entries * + IOMMU_CMD_BUFFER_ENTRY_SIZE)); - iommu->cmd_buffer.entries = + iommu->cmd_buffer.entries = iommu->cmd_buffer.alloc_size / IOMMU_CMD_BUFFER_ENTRY_SIZE; if ( allocate_iommu_table_struct(&iommu->cmd_buffer, - "Command Buffer") != 0 ) + "Command Buffer") != 0 ) goto error_out; return 0; -error_out: + error_out: deallocate_iommu_resources(iommu); return -ENOMEM; } @@ -149,7 +148,8 @@ int iommu_detect_callback(u8 bus, u8 dev, u8 func, u8 cap_ptr) struct amd_iommu *iommu; iommu = (struct amd_iommu *) xmalloc(struct amd_iommu); - if ( !iommu ) { + if ( !iommu ) + { dprintk(XENLOG_ERR, "AMD IOMMU: Error allocating amd_iommu\n"); return -ENOMEM; } @@ -170,7 +170,7 @@ int iommu_detect_callback(u8 bus, u8 dev, u8 func, u8 cap_ptr) return 0; -error_out: + error_out: xfree(iommu); return -ENODEV; } @@ -180,11 +180,12 @@ static int __init amd_iommu_init(void) struct amd_iommu *iommu; unsigned long flags; - for_each_amd_iommu(iommu) { + for_each_amd_iommu ( iommu ) + { spin_lock_irqsave(&iommu->lock, flags); /* register IOMMU data strucures in MMIO space */ - if (map_iommu_mmio_region(iommu) != 0) + if ( map_iommu_mmio_region(iommu) != 0 ) goto error_out; register_iommu_dev_table_in_mmio_space(iommu); register_iommu_cmd_buffer_in_mmio_space(iommu); @@ -200,7 +201,7 @@ static int __init amd_iommu_init(void) return 0; -error_out: + error_out: init_cleanup(); return -ENODEV; } @@ -209,13 +210,16 @@ struct amd_iommu *find_iommu_for_device(int bus, int devfn) { struct amd_iommu *iommu; - for_each_amd_iommu(iommu) { - if ( bus == iommu->root_bus ) { - if ( devfn >= iommu->first_devfn && - devfn <= iommu->last_devfn ) + for_each_amd_iommu ( iommu ) + { + if ( bus == iommu->root_bus ) + { + if ( (devfn >= iommu->first_devfn) && + (devfn <= iommu->last_devfn) ) return iommu; } - else if ( bus <= iommu->last_downstream_bus ) { + else if ( bus <= iommu->last_downstream_bus ) + { if ( iommu->downstream_bus_present[bus] ) return iommu; } @@ -238,16 +242,21 @@ void amd_iommu_setup_domain_device( dte = iommu->dev_table.buffer + (requestor_id * IOMMU_DEV_TABLE_ENTRY_SIZE); - spin_lock_irqsave(&iommu->lock, flags); + if ( !amd_iommu_is_dte_page_translation_valid((u32 *)dte) ) + { + spin_lock_irqsave(&iommu->lock, flags); - amd_iommu_set_dev_table_entry((u32 *)dte, - root_ptr, hd->domain_id, hd->paging_mode); + amd_iommu_set_dev_table_entry( + (u32 *)dte, + root_ptr, hd->domain_id, hd->paging_mode); + invalidate_dev_table_entry(iommu, requestor_id); + flush_command_buffer(iommu); + dprintk(XENLOG_INFO, "AMD IOMMU: Set DTE req_id:%x, " + "root_ptr:%"PRIx64", domain_id:%d, paging_mode:%d\n", + requestor_id, root_ptr, hd->domain_id, hd->paging_mode); - dprintk(XENLOG_INFO, "AMD IOMMU: Set DTE req_id:%x, " - "root_ptr:%"PRIx64", domain_id:%d, paging_mode:%d\n", - requestor_id, root_ptr, hd->domain_id, hd->paging_mode); - - spin_unlock_irqrestore(&iommu->lock, flags); + spin_unlock_irqrestore(&iommu->lock, flags); + } } void __init amd_iommu_setup_dom0_devices(void) @@ -259,13 +268,16 @@ void __init amd_iommu_setup_dom0_devices(void) u32 l; int req_id, bdf; - for ( bus = 0; bus < 256; bus++ ) { - for ( dev = 0; dev < 32; dev++ ) { - for ( func = 0; func < 8; func++ ) { + for ( bus = 0; bus < 256; bus++ ) + { + for ( dev = 0; dev < 32; dev++ ) + { + for ( func = 0; func < 8; func++ ) + { l = read_pci_config(bus, dev, func, PCI_VENDOR_ID); /* some broken boards return 0 or ~0 if a slot is empty: */ if ( l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000 ) + l == 0x0000ffff || l == 0xffff0000 ) continue; pdev = xmalloc(struct pci_dev); @@ -288,29 +300,33 @@ int amd_iommu_detect(void) { unsigned long i; - if ( !enable_amd_iommu ) { + if ( !enable_amd_iommu ) + { printk("AMD IOMMU: Disabled\n"); return 0; } INIT_LIST_HEAD(&amd_iommu_head); - if ( scan_for_iommu(iommu_detect_callback) != 0 ) { + if ( scan_for_iommu(iommu_detect_callback) != 0 ) + { dprintk(XENLOG_ERR, "AMD IOMMU: Error detection\n"); goto error_out; } - if ( !iommu_found() ) { + if ( !iommu_found() ) + { printk("AMD IOMMU: Not found!\n"); return 0; } - if ( amd_iommu_init() != 0 ) { + if ( amd_iommu_init() != 0 ) + { dprintk(XENLOG_ERR, "AMD IOMMU: Error initialization\n"); goto error_out; } - if ( amd_iommu_domain_init(dom0) != 0 ) + if ( iommu_domain_init(dom0) != 0 ) goto error_out; /* setup 1:1 page table for dom0 */ @@ -320,21 +336,31 @@ int amd_iommu_detect(void) amd_iommu_setup_dom0_devices(); return 0; -error_out: - detect_cleanup(); - return -ENODEV; + error_out: + detect_cleanup(); + return -ENODEV; } static int allocate_domain_resources(struct hvm_iommu *hd) { /* allocate root table */ - hd->root_table = (void *)alloc_xenheap_page(); + unsigned long flags; + + spin_lock_irqsave(&hd->mapping_lock, flags); if ( !hd->root_table ) - return -ENOMEM; - memset((u8*)hd->root_table, 0, PAGE_SIZE); + { + hd->root_table = (void *)alloc_xenheap_page(); + if ( !hd->root_table ) + goto error_out; + memset((u8*)hd->root_table, 0, PAGE_SIZE); + } + spin_unlock_irqrestore(&hd->mapping_lock, flags); return 0; + error_out: + spin_unlock_irqrestore(&hd->mapping_lock, flags); + return -ENOMEM; } static int get_paging_mode(unsigned long entries) @@ -346,7 +372,8 @@ static int get_paging_mode(unsigned long entries) if ( entries > max_page ) entries = max_page; - while ( entries > PTE_PER_TABLE_SIZE ) { + while ( entries > PTE_PER_TABLE_SIZE ) + { entries = PTE_PER_TABLE_ALIGN(entries) >> PTE_PER_TABLE_SHIFT; ++level; if ( level > 6 ) @@ -362,14 +389,11 @@ int amd_iommu_domain_init(struct domain *domain) { struct hvm_iommu *hd = domain_hvm_iommu(domain); - spin_lock_init(&hd->mapping_lock); - spin_lock_init(&hd->iommu_list_lock); - INIT_LIST_HEAD(&hd->pdev_list); - /* allocate page directroy */ - if ( allocate_domain_resources(hd) != 0 ) { - dprintk(XENLOG_ERR, "AMD IOMMU: %s()\n", __FUNCTION__); - goto error_out; + if ( allocate_domain_resources(hd) != 0 ) + { + deallocate_domain_resources(hd); + return -ENOMEM; } if ( is_hvm_domain(domain) ) @@ -380,10 +404,168 @@ int amd_iommu_domain_init(struct domain *domain) hd->domain_id = domain->domain_id; return 0; +} -error_out: - deallocate_domain_resources(hd); - return -ENOMEM; +static void amd_iommu_disable_domain_device( + struct domain *domain, struct amd_iommu *iommu, u16 requestor_id) +{ + void *dte; + unsigned long flags; + + dte = iommu->dev_table.buffer + + (requestor_id * IOMMU_DEV_TABLE_ENTRY_SIZE); + + if ( amd_iommu_is_dte_page_translation_valid((u32 *)dte) ) + { + spin_lock_irqsave(&iommu->lock, flags); + memset (dte, 0, IOMMU_DEV_TABLE_ENTRY_SIZE); + invalidate_dev_table_entry(iommu, requestor_id); + flush_command_buffer(iommu); + dprintk(XENLOG_INFO , "AMD IOMMU: disable DTE 0x%x," + " domain_id:%d, paging_mode:%d\n", + requestor_id, domain_hvm_iommu(domain)->domain_id, + domain_hvm_iommu(domain)->paging_mode); + spin_unlock_irqrestore(&iommu->lock, flags); + } +} + +extern void pdev_flr(u8 bus, u8 devfn); + +static int reassign_device( struct domain *source, struct domain *target, + u8 bus, u8 devfn) +{ + struct hvm_iommu *source_hd = domain_hvm_iommu(source); + struct hvm_iommu *target_hd = domain_hvm_iommu(target); + struct pci_dev *pdev; + struct amd_iommu *iommu; + int req_id, bdf; + unsigned long flags; + + for_each_pdev( source, pdev ) + { + if ( (pdev->bus != bus) || (pdev->devfn != devfn) ) + continue; + + pdev->bus = bus; + pdev->devfn = devfn; + + bdf = (bus << 8) | devfn; + req_id = requestor_id_from_bdf(bdf); + iommu = find_iommu_for_device(bus, devfn); + + if ( iommu ) + { + amd_iommu_disable_domain_device(source, iommu, req_id); + /* Move pci device from the source domain to target domain. */ + spin_lock_irqsave(&source_hd->iommu_list_lock, flags); + spin_lock_irqsave(&target_hd->iommu_list_lock, flags); + list_move(&pdev->list, &target_hd->pdev_list); + spin_unlock_irqrestore(&target_hd->iommu_list_lock, flags); + spin_unlock_irqrestore(&source_hd->iommu_list_lock, flags); + + amd_iommu_setup_domain_device(target, iommu, req_id); + gdprintk(XENLOG_INFO , + "AMD IOMMU: reassign %x:%x.%x domain %d -> domain %d\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn), + source->domain_id, target->domain_id); + } + else + { + gdprintk(XENLOG_ERR , "AMD IOMMU: fail to find iommu." + " %x:%x.%x cannot be assigned to domain %d\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn), target->domain_id); + return -ENODEV; + } + + break; + } + return 0; +} + +int amd_iommu_assign_device(struct domain *d, u8 bus, u8 devfn) +{ + pdev_flr(bus, devfn); + return reassign_device(dom0, d, bus, devfn); } +static void release_domain_devices(struct domain *d) +{ + struct hvm_iommu *hd = domain_hvm_iommu(d); + struct pci_dev *pdev; + + while ( !list_empty(&hd->pdev_list) ) + { + pdev = list_entry(hd->pdev_list.next, typeof(*pdev), list); + pdev_flr(pdev->bus, pdev->devfn); + gdprintk(XENLOG_INFO , + "AMD IOMMU: release devices %x:%x.%x\n", + pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); + reassign_device(d, dom0, pdev->bus, pdev->devfn); + } +} + +static void deallocate_next_page_table(void *table, unsigned long index, + int level) +{ + unsigned long next_index; + void *next_table, *pde; + int next_level; + + pde = table + (index * IOMMU_PAGE_TABLE_ENTRY_SIZE); + next_table = amd_iommu_get_vptr_from_page_table_entry((u32 *)pde); + + if ( next_table ) + { + next_level = level - 1; + if ( next_level > 1 ) + { + next_index = 0; + do + { + deallocate_next_page_table(next_table, + next_index, next_level); + ++next_index; + } while (next_index < PTE_PER_TABLE_SIZE); + } + + free_xenheap_page(next_table); + } +} + +static void deallocate_iommu_page_tables(struct domain *d) +{ + unsigned long index; + struct hvm_iommu *hd = domain_hvm_iommu(d); + + if ( hd ->root_table ) + { + index = 0; + do + { + deallocate_next_page_table(hd->root_table, + index, hd->paging_mode); + ++index; + } while ( index < PTE_PER_TABLE_SIZE ); + + free_xenheap_page(hd ->root_table); + } + + hd ->root_table = NULL; +} + +void amd_iommu_domain_destroy(struct domain *d) +{ + if ( !amd_iommu_enabled ) + return; + + deallocate_iommu_page_tables(d); + release_domain_devices(d); +} +struct iommu_ops amd_iommu_ops = { + .init = amd_iommu_domain_init, + .assign_device = amd_iommu_assign_device, + .teardown = amd_iommu_domain_destroy, + .map_page = amd_iommu_map_page, + .unmap_page = amd_iommu_unmap_page, +}; diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c index d2ba799a42..17a9c3bc7b 100644 --- a/xen/arch/x86/hvm/svm/intr.c +++ b/xen/arch/x86/hvm/svm/intr.c @@ -94,6 +94,46 @@ static void enable_intr_window(struct vcpu *v, struct hvm_intack intack) vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR; } +static void svm_dirq_assist(struct vcpu *v) +{ + unsigned int irq; + uint32_t device, intx; + struct domain *d = v->domain; + struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; + struct dev_intx_gsi_link *digl; + + if ( !amd_iommu_enabled || (v->vcpu_id != 0) || (hvm_irq_dpci == NULL) ) + return; + + for ( irq = find_first_bit(hvm_irq_dpci->dirq_mask, NR_IRQS); + irq < NR_IRQS; + irq = find_next_bit(hvm_irq_dpci->dirq_mask, NR_IRQS, irq + 1) ) + { + stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]); + clear_bit(irq, &hvm_irq_dpci->dirq_mask); + + list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list ) + { + device = digl->device; + intx = digl->intx; + hvm_pci_intx_assert(d, device, intx); + spin_lock(&hvm_irq_dpci->dirq_lock); + hvm_irq_dpci->mirq[irq].pending++; + spin_unlock(&hvm_irq_dpci->dirq_lock); + } + + /* + * Set a timer to see if the guest can finish the interrupt or not. For + * example, the guest OS may unmask the PIC during boot, before the + * guest driver is loaded. hvm_pci_intx_assert() may succeed, but the + * guest will never deal with the irq, then the physical interrupt line + * will never be deasserted. + */ + set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)], + NOW() + PT_IRQ_TIME_OUT); + } +} + asmlinkage void svm_intr_assist(void) { struct vcpu *v = current; @@ -102,6 +142,7 @@ asmlinkage void svm_intr_assist(void) /* Crank the handle on interrupt state. */ pt_update_irq(v); + svm_dirq_assist(v); do { intack = hvm_vcpu_has_pending_irq(v); diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 3845946633..ed42ece5e5 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -181,7 +181,7 @@ static void svm_restore_dr(struct vcpu *v) __restore_debug_registers(v); } -int svm_vmcb_save(struct vcpu *v, struct hvm_hw_cpu *c) +static int svm_vmcb_save(struct vcpu *v, struct hvm_hw_cpu *c) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; @@ -190,52 +190,6 @@ int svm_vmcb_save(struct vcpu *v, struct hvm_hw_cpu *c) c->cr3 = v->arch.hvm_vcpu.guest_cr[3]; c->cr4 = v->arch.hvm_vcpu.guest_cr[4]; - c->idtr_limit = vmcb->idtr.limit; - c->idtr_base = vmcb->idtr.base; - - c->gdtr_limit = vmcb->gdtr.limit; - c->gdtr_base = vmcb->gdtr.base; - - c->cs_sel = vmcb->cs.sel; - c->cs_limit = vmcb->cs.limit; - c->cs_base = vmcb->cs.base; - c->cs_arbytes = vmcb->cs.attr.bytes; - - c->ds_sel = vmcb->ds.sel; - c->ds_limit = vmcb->ds.limit; - c->ds_base = vmcb->ds.base; - c->ds_arbytes = vmcb->ds.attr.bytes; - - c->es_sel = vmcb->es.sel; - c->es_limit = vmcb->es.limit; - c->es_base = vmcb->es.base; - c->es_arbytes = vmcb->es.attr.bytes; - - c->ss_sel = vmcb->ss.sel; - c->ss_limit = vmcb->ss.limit; - c->ss_base = vmcb->ss.base; - c->ss_arbytes = vmcb->ss.attr.bytes; - - c->fs_sel = vmcb->fs.sel; - c->fs_limit = vmcb->fs.limit; - c->fs_base = vmcb->fs.base; - c->fs_arbytes = vmcb->fs.attr.bytes; - - c->gs_sel = vmcb->gs.sel; - c->gs_limit = vmcb->gs.limit; - c->gs_base = vmcb->gs.base; - c->gs_arbytes = vmcb->gs.attr.bytes; - - c->tr_sel = vmcb->tr.sel; - c->tr_limit = vmcb->tr.limit; - c->tr_base = vmcb->tr.base; - c->tr_arbytes = vmcb->tr.attr.bytes; - - c->ldtr_sel = vmcb->ldtr.sel; - c->ldtr_limit = vmcb->ldtr.limit; - c->ldtr_base = vmcb->ldtr.base; - c->ldtr_arbytes = vmcb->ldtr.attr.bytes; - c->sysenter_cs = vmcb->sysenter_cs; c->sysenter_esp = vmcb->sysenter_esp; c->sysenter_eip = vmcb->sysenter_eip; @@ -253,8 +207,7 @@ int svm_vmcb_save(struct vcpu *v, struct hvm_hw_cpu *c) return 1; } - -int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) +static int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) { unsigned long mfn = 0; p2m_type_t p2mt; @@ -301,53 +254,6 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) __func__, c->cr3, c->cr0, c->cr4); #endif - vmcb->idtr.limit = c->idtr_limit; - vmcb->idtr.base = c->idtr_base; - - vmcb->gdtr.limit = c->gdtr_limit; - vmcb->gdtr.base = c->gdtr_base; - - vmcb->cs.sel = c->cs_sel; - vmcb->cs.limit = c->cs_limit; - vmcb->cs.base = c->cs_base; - vmcb->cs.attr.bytes = c->cs_arbytes; - - vmcb->ds.sel = c->ds_sel; - vmcb->ds.limit = c->ds_limit; - vmcb->ds.base = c->ds_base; - vmcb->ds.attr.bytes = c->ds_arbytes; - - vmcb->es.sel = c->es_sel; - vmcb->es.limit = c->es_limit; - vmcb->es.base = c->es_base; - vmcb->es.attr.bytes = c->es_arbytes; - - vmcb->ss.sel = c->ss_sel; - vmcb->ss.limit = c->ss_limit; - vmcb->ss.base = c->ss_base; - vmcb->ss.attr.bytes = c->ss_arbytes; - vmcb->cpl = vmcb->ss.attr.fields.dpl; - - vmcb->fs.sel = c->fs_sel; - vmcb->fs.limit = c->fs_limit; - vmcb->fs.base = c->fs_base; - vmcb->fs.attr.bytes = c->fs_arbytes; - - vmcb->gs.sel = c->gs_sel; - vmcb->gs.limit = c->gs_limit; - vmcb->gs.base = c->gs_base; - vmcb->gs.attr.bytes = c->gs_arbytes; - - vmcb->tr.sel = c->tr_sel; - vmcb->tr.limit = c->tr_limit; - vmcb->tr.base = c->tr_base; - vmcb->tr.attr.bytes = c->tr_arbytes; - - vmcb->ldtr.sel = c->ldtr_sel; - vmcb->ldtr.limit = c->ldtr_limit; - vmcb->ldtr.base = c->ldtr_base; - vmcb->ldtr.attr.bytes = c->ldtr_arbytes; - vmcb->sysenter_cs = c->sysenter_cs; vmcb->sysenter_esp = c->sysenter_esp; vmcb->sysenter_eip = c->sysenter_eip; diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index cfc80c5aa1..c01618c69f 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -458,7 +458,7 @@ void vioapic_update_EOI(struct domain *d, int vector) ent->fields.remote_irr = 0; - if ( vtd_enabled ) + if ( iommu_enabled ) { spin_unlock(&d->arch.hvm_domain.irq_lock); hvm_dpci_eoi(current->domain, gsi, ent); diff --git a/xen/arch/x86/hvm/vmx/realmode.c b/xen/arch/x86/hvm/vmx/realmode.c index 6c591d1f16..8d7572e0d5 100644 --- a/xen/arch/x86/hvm/vmx/realmode.c +++ b/xen/arch/x86/hvm/vmx/realmode.c @@ -13,6 +13,7 @@ #include <xen/init.h> #include <xen/lib.h> #include <xen/sched.h> +#include <xen/paging.h> #include <asm/event.h> #include <asm/hvm/hvm.h> #include <asm/hvm/support.h> @@ -313,6 +314,57 @@ realmode_rep_outs( return X86EMUL_OKAY; } +static int +realmode_rep_movs( + enum x86_segment src_seg, + unsigned long src_offset, + enum x86_segment dst_seg, + unsigned long dst_offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + struct realmode_emulate_ctxt *rm_ctxt = + container_of(ctxt, struct realmode_emulate_ctxt, ctxt); + struct vcpu *curr = current; + uint32_t saddr = virtual_to_linear(src_seg, src_offset, rm_ctxt); + uint32_t daddr = virtual_to_linear(dst_seg, dst_offset, rm_ctxt); + p2m_type_t p2mt; + + if ( (curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) || + curr->arch.hvm_vmx.real_mode_io_in_progress ) + return X86EMUL_UNHANDLEABLE; + + mfn_x(gfn_to_mfn_current(saddr >> PAGE_SHIFT, &p2mt)); + if ( !p2m_is_ram(p2mt) ) + { + if ( !curr->arch.hvm_vmx.real_mode_io_completed ) + { + curr->arch.hvm_vmx.real_mode_io_in_progress = 1; + send_mmio_req(IOREQ_TYPE_COPY, saddr, *reps, bytes_per_rep, + daddr, IOREQ_READ, + !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1); + } + + if ( !curr->arch.hvm_vmx.real_mode_io_completed ) + return X86EMUL_RETRY; + + curr->arch.hvm_vmx.real_mode_io_completed = 0; + } + else + { + mfn_x(gfn_to_mfn_current(daddr >> PAGE_SHIFT, &p2mt)); + if ( p2m_is_ram(p2mt) ) + return X86EMUL_UNHANDLEABLE; + curr->arch.hvm_vmx.real_mode_io_in_progress = 1; + send_mmio_req(IOREQ_TYPE_COPY, daddr, *reps, bytes_per_rep, + saddr, IOREQ_WRITE, + !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1); + } + + return X86EMUL_OKAY; +} + static int realmode_read_segment( enum x86_segment seg, @@ -600,6 +652,7 @@ static struct x86_emulate_ops realmode_emulator_ops = { .cmpxchg = realmode_emulate_cmpxchg, .rep_ins = realmode_rep_ins, .rep_outs = realmode_rep_outs, + .rep_movs = realmode_rep_movs, .read_segment = realmode_read_segment, .write_segment = realmode_write_segment, .read_io = realmode_read_io, @@ -728,7 +781,7 @@ void vmx_realmode(struct cpu_user_regs *regs) struct vcpu *curr = current; struct realmode_emulate_ctxt rm_ctxt; unsigned long intr_info = __vmread(VM_ENTRY_INTR_INFO); - int i; + unsigned int i, emulations = 0; rm_ctxt.ctxt.regs = regs; @@ -751,11 +804,19 @@ void vmx_realmode(struct cpu_user_regs *regs) while ( curr->arch.hvm_vmx.vmxemul && !softirq_pending(smp_processor_id()) && - !curr->arch.hvm_vmx.real_mode_io_in_progress && - /* Check for pending interrupts only in proper real mode. */ - ((curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) || - !hvm_local_events_need_delivery(curr)) ) + !curr->arch.hvm_vmx.real_mode_io_in_progress ) + { + /* + * Check for pending interrupts only every 16 instructions, because + * hvm_local_events_need_delivery() is moderately expensive, and only + * in real mode, because we don't emulate protected-mode IDT vectoring. + */ + if ( unlikely(!(++emulations & 15)) && + !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) && + hvm_local_events_need_delivery(curr) ) + break; realmode_emulate_one(&rm_ctxt); + } if ( !curr->arch.hvm_vmx.vmxemul ) { diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 50efb4fcd9..8d4629df36 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -450,7 +450,7 @@ static void vmx_restore_dr(struct vcpu *v) __restore_debug_registers(v); } -void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c) +static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c) { uint32_t ev; @@ -463,52 +463,6 @@ void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c) c->msr_efer = v->arch.hvm_vcpu.guest_efer; - 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 = __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 = __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 = __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 = __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 = __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 = __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 = __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 = __vmread(GUEST_LDTR_AR_BYTES); - c->sysenter_cs = __vmread(GUEST_SYSENTER_CS); c->sysenter_esp = __vmread(GUEST_SYSENTER_ESP); c->sysenter_eip = __vmread(GUEST_SYSENTER_EIP); @@ -552,7 +506,7 @@ static int vmx_restore_cr0_cr3( return 0; } -int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) +static int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) { int rc; @@ -585,52 +539,6 @@ int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) v->arch.hvm_vcpu.guest_efer = c->msr_efer; vmx_update_guest_efer(v); - __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); - - __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); - - __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); - - __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); - - __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); - - __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); - - __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); - - __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); - __vmwrite(GUEST_SYSENTER_CS, c->sysenter_cs); __vmwrite(GUEST_SYSENTER_ESP, c->sysenter_esp); __vmwrite(GUEST_SYSENTER_EIP, c->sysenter_eip); @@ -821,7 +729,7 @@ static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, { uint32_t attr = 0; - ASSERT(v == current); + vmx_vmcs_enter(v); switch ( seg ) { @@ -885,6 +793,8 @@ static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, BUG(); } + vmx_vmcs_exit(v); + reg->attr.bytes = (attr & 0xff) | ((attr >> 4) & 0xf00); /* Unusable flag is folded into Present flag. */ if ( attr & (1u<<16) ) @@ -896,8 +806,6 @@ static void vmx_set_segment_register(struct vcpu *v, enum x86_segment seg, { uint32_t attr; - ASSERT((v == current) || !vcpu_runnable(v)); - attr = reg->attr.bytes; attr = ((attr & 0xf00) << 4) | (attr & 0xff); @@ -1009,6 +917,14 @@ static enum hvm_intblk vmx_interrupt_blocked( { unsigned long intr_shadow; + /* + * Test EFLAGS.IF first. It is often the most likely reason for interrupt + * blockage, and is the cheapest to test (because no VMREAD is required). + */ + if ( (intack.source != hvm_intsrc_nmi) && + !(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) ) + return hvm_intblk_rflags_ie; + intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO); if ( intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS) ) @@ -1021,15 +937,11 @@ static enum hvm_intblk vmx_interrupt_blocked( ASSERT((intack.source == hvm_intsrc_pic) || (intack.source == hvm_intsrc_lapic)); - if ( !(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) ) - return hvm_intblk_rflags_ie; - return hvm_intblk_none; } static void vmx_update_host_cr3(struct vcpu *v) { - ASSERT((v == current) || !vcpu_runnable(v)); vmx_vmcs_enter(v); __vmwrite(HOST_CR3, v->arch.cr3); vmx_vmcs_exit(v); @@ -1037,8 +949,6 @@ static void vmx_update_host_cr3(struct vcpu *v) static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr) { - ASSERT((v == current) || !vcpu_runnable(v)); - vmx_vmcs_enter(v); switch ( cr ) @@ -1089,8 +999,6 @@ static void vmx_update_guest_efer(struct vcpu *v) #ifdef __x86_64__ unsigned long vm_entry_value; - ASSERT((v == current) || !vcpu_runnable(v)); - vmx_vmcs_enter(v); vm_entry_value = __vmread(VM_ENTRY_CONTROLS); diff --git a/xen/arch/x86/hvm/vmx/vtd/Makefile b/xen/arch/x86/hvm/vmx/vtd/Makefile index 1cae6385ab..dcff4e3ab1 100644 --- a/xen/arch/x86/hvm/vmx/vtd/Makefile +++ b/xen/arch/x86/hvm/vmx/vtd/Makefile @@ -3,3 +3,4 @@ obj-y += dmar.o obj-y += utils.o obj-y += io.o obj-y += qinval.o +obj-y += intremap.o diff --git a/xen/arch/x86/hvm/vmx/vtd/extern.h b/xen/arch/x86/hvm/vmx/vtd/extern.h index 6143b935b9..9e2ac576ea 100644 --- a/xen/arch/x86/hvm/vmx/vtd/extern.h +++ b/xen/arch/x86/hvm/vmx/vtd/extern.h @@ -23,11 +23,6 @@ #include "dmar.h" -extern int iommu_setup_done; -extern int vtd2_thurley_enabled; -extern int vtd2_qinval_enabled; - -extern spinlock_t ioapic_lock; extern struct qi_ctrl *qi_ctrl; extern struct ir_ctrl *ir_ctrl; @@ -37,6 +32,7 @@ void print_vtd_entries(struct domain *d, struct iommu *iommu, void pdev_flr(u8 bus, u8 devfn); int qinval_setup(struct iommu *iommu); +int intremap_setup(struct iommu *iommu); int queue_invalidate_context(struct iommu *iommu, u16 did, u16 source_id, u8 function_mask, u8 granu); int queue_invalidate_iotlb(struct iommu *iommu, @@ -46,7 +42,6 @@ int queue_invalidate_iec(struct iommu *iommu, int invalidate_sync(struct iommu *iommu); int iommu_flush_iec_global(struct iommu *iommu); int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx); -void gsi_remapping(unsigned int gsi); void print_iommu_regs(struct acpi_drhd_unit *drhd); int vtd_hw_check(void); struct iommu * ioapic_to_iommu(unsigned int apic_id); diff --git a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c index 4b05f1d87c..c497b9c392 100644 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c @@ -1047,7 +1047,7 @@ static void free_iommu(struct iommu *iommu) agaw = 64; \ agaw; }) -int iommu_domain_init(struct domain *domain) +int intel_iommu_domain_init(struct domain *domain) { struct hvm_iommu *hd = domain_hvm_iommu(domain); struct iommu *iommu = NULL; @@ -1056,11 +1056,6 @@ int iommu_domain_init(struct domain *domain) unsigned long sagaw; struct acpi_drhd_unit *drhd; - spin_lock_init(&hd->mapping_lock); - spin_lock_init(&hd->iommu_list_lock); - INIT_LIST_HEAD(&hd->pdev_list); - INIT_LIST_HEAD(&hd->g2m_ioport_list); - if ( !vtd_enabled || list_empty(&acpi_drhd_units) ) return 0; @@ -1550,7 +1545,8 @@ static int domain_context_mapped(struct pci_dev *pdev) return 0; } -int iommu_map_page(struct domain *d, paddr_t gfn, paddr_t mfn) +int intel_iommu_map_page( + struct domain *d, unsigned long gfn, unsigned long mfn) { struct acpi_drhd_unit *drhd; struct iommu *iommu; @@ -1566,12 +1562,12 @@ int iommu_map_page(struct domain *d, paddr_t gfn, paddr_t mfn) return 0; #endif - pg = addr_to_dma_page(d, gfn << PAGE_SHIFT_4K); + pg = addr_to_dma_page(d, (paddr_t)gfn << PAGE_SHIFT_4K); if ( !pg ) return -ENOMEM; pte = (struct dma_pte *)map_domain_page(page_to_mfn(pg)); pte += gfn & LEVEL_MASK; - dma_set_pte_addr(*pte, mfn << PAGE_SHIFT_4K); + dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K); dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE); iommu_flush_cache_entry(iommu, pte); unmap_domain_page(pte); @@ -1581,7 +1577,7 @@ int iommu_map_page(struct domain *d, paddr_t gfn, paddr_t mfn) iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d), - gfn << PAGE_SHIFT_4K, 1, 0); + (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0); else if ( cap_rwbf(iommu->cap) ) iommu_flush_write_buffer(iommu); } @@ -1589,7 +1585,7 @@ int iommu_map_page(struct domain *d, paddr_t gfn, paddr_t mfn) return 0; } -int iommu_unmap_page(struct domain *d, dma_addr_t gfn) +int intel_iommu_unmap_page(struct domain *d, unsigned long gfn) { struct acpi_drhd_unit *drhd; struct iommu *iommu; @@ -1603,12 +1599,12 @@ int iommu_unmap_page(struct domain *d, dma_addr_t gfn) return 0; #endif - dma_pte_clear_one(d, gfn << PAGE_SHIFT_4K); + dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K); return 0; } -int iommu_page_mapping(struct domain *domain, dma_addr_t iova, +int iommu_page_mapping(struct domain *domain, paddr_t iova, void *hpa, size_t size, int prot) { struct acpi_drhd_unit *drhd; @@ -1655,14 +1651,14 @@ int iommu_page_mapping(struct domain *domain, dma_addr_t iova, return 0; } -int iommu_page_unmapping(struct domain *domain, dma_addr_t addr, size_t size) +int iommu_page_unmapping(struct domain *domain, paddr_t addr, size_t size) { dma_pte_clear_range(domain, addr, addr + size); return 0; } -void iommu_flush(struct domain *d, dma_addr_t gfn, u64 *p2m_entry) +void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry) { struct acpi_drhd_unit *drhd; struct iommu *iommu = NULL; @@ -1673,7 +1669,7 @@ void iommu_flush(struct domain *d, dma_addr_t gfn, u64 *p2m_entry) iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d), - gfn << PAGE_SHIFT_4K, 1, 0); + (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0); else if ( cap_rwbf(iommu->cap) ) iommu_flush_write_buffer(iommu); } @@ -1816,9 +1812,13 @@ static int init_vtd_hw(void) flush->context = flush_context_reg; flush->iotlb = flush_iotlb_reg; - if ( qinval_setup(iommu) != 0); + if ( qinval_setup(iommu) != 0 ) dprintk(XENLOG_ERR VTDPREFIX, "Queued Invalidation hardware not found\n"); + + if ( intremap_setup(iommu) != 0 ) + dprintk(XENLOG_ERR VTDPREFIX, + "Interrupt Remapping hardware not found\n"); } return 0; } @@ -1917,7 +1917,7 @@ int device_assigned(u8 bus, u8 devfn) return 1; } -int assign_device(struct domain *d, u8 bus, u8 devfn) +int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn) { struct acpi_rmrr_unit *rmrr; struct pci_dev *pdev; @@ -2147,6 +2147,14 @@ int iommu_resume(void) return 0; } +struct iommu_ops intel_iommu_ops = { + .init = intel_iommu_domain_init, + .assign_device = intel_iommu_assign_device, + .teardown = iommu_domain_teardown, + .map_page = intel_iommu_map_page, + .unmap_page = intel_iommu_unmap_page, +}; + /* * Local variables: * mode: C diff --git a/xen/arch/x86/hvm/vmx/vtd/intremap.c b/xen/arch/x86/hvm/vmx/vtd/intremap.c new file mode 100644 index 0000000000..21645599b6 --- /dev/null +++ b/xen/arch/x86/hvm/vmx/vtd/intremap.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2006, 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. + * + * Copyright (C) Allen Kay <allen.m.kay@intel.com> + * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com> + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/init.h> +#include <xen/irq.h> +#include <xen/delay.h> +#include <xen/sched.h> +#include <xen/acpi.h> +#include <xen/keyhandler.h> +#include <xen/spinlock.h> +#include <asm/io.h> +#include <asm/mc146818rtc.h> +#include <asm/smp.h> +#include <asm/desc.h> +#include <mach_apic.h> +#include <io_ports.h> + +#include <xen/spinlock.h> +#include <xen/xmalloc.h> +#include <xen/domain_page.h> +#include <asm/delay.h> +#include <asm/string.h> +#include <asm/iommu.h> +#include <asm/hvm/vmx/intel-iommu.h> +#include "dmar.h" +#include "vtd.h" +#include "pci-direct.h" +#include "pci_regs.h" +#include "msi.h" +#include "extern.h" + +u16 apicid_to_bdf(int apic_id) +{ + struct acpi_drhd_unit *drhd = ioapic_to_drhd(apic_id); + struct acpi_ioapic_unit *acpi_ioapic_unit; + + list_for_each_entry ( acpi_ioapic_unit, &drhd->ioapic_list, list ) + if ( acpi_ioapic_unit->apic_id == apic_id ) + return acpi_ioapic_unit->ioapic.info; + + dprintk(XENLOG_ERR VTDPREFIX, "Didn't find the bdf for the apic_id!\n"); + return 0; +} + +static void remap_entry_to_ioapic_rte( + struct iommu *iommu, struct IO_APIC_route_entry *old_rte) +{ + struct iremap_entry *iremap_entry = NULL; + struct IO_APIC_route_remap_entry *remap_rte; + unsigned int index; + unsigned long flags; + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); + + if ( ir_ctrl == NULL ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "remap_entry_to_ioapic_rte: ir_ctl == NULL"); + return; + } + + remap_rte = (struct IO_APIC_route_remap_entry *) old_rte; + index = (remap_rte->index_15 << 15) + remap_rte->index_0_14; + + if ( index > ir_ctrl->iremap_index ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "Index is larger than remap table entry size. Error!\n"); + return; + } + + spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); + + iremap_entry = &ir_ctrl->iremap[index]; + + old_rte->vector = iremap_entry->lo.vector; + old_rte->delivery_mode = iremap_entry->lo.dlm; + old_rte->dest_mode = iremap_entry->lo.dm; + old_rte->trigger = iremap_entry->lo.tm; + old_rte->__reserved_2 = 0; + old_rte->dest.logical.__reserved_1 = 0; + old_rte->dest.logical.logical_dest = iremap_entry->lo.dst; + + spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); +} + +static void ioapic_rte_to_remap_entry(struct iommu *iommu, + int apic_id, struct IO_APIC_route_entry *old_rte) +{ + struct iremap_entry *iremap_entry = NULL; + struct IO_APIC_route_remap_entry *remap_rte; + unsigned int index; + unsigned long flags; + int ret = 0; + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); + + remap_rte = (struct IO_APIC_route_remap_entry *) old_rte; + spin_lock_irqsave(&ir_ctrl->iremap_lock, flags); + index = ir_ctrl->iremap_index; + if ( index > IREMAP_ENTRY_NR - 1 ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "The interrupt number is more than 256!\n"); + goto out; + } + + iremap_entry = &(ir_ctrl->iremap[index]); + if ( *(u64 *)iremap_entry != 0 ) + dprintk(XENLOG_WARNING VTDPREFIX, + "Interrupt remapping entry is in use already!\n"); + iremap_entry->lo.fpd = 0; + iremap_entry->lo.dm = old_rte->dest_mode; + iremap_entry->lo.rh = 0; + iremap_entry->lo.tm = old_rte->trigger; + iremap_entry->lo.dlm = old_rte->delivery_mode; + iremap_entry->lo.avail = 0; + iremap_entry->lo.res_1 = 0; + iremap_entry->lo.vector = old_rte->vector; + iremap_entry->lo.res_2 = 0; + iremap_entry->lo.dst = (old_rte->dest.logical.logical_dest << 8); + iremap_entry->hi.sid = apicid_to_bdf(apic_id); + iremap_entry->hi.sq = 0; /* comparing all 16-bit of SID */ + iremap_entry->hi.svt = 1; /* turn on requestor ID verification SID/SQ */ + iremap_entry->hi.res_1 = 0; + iremap_entry->lo.p = 1; /* finally, set present bit */ + ir_ctrl->iremap_index++; + + iommu_flush_iec_index(iommu, 0, index); + ret = invalidate_sync(iommu); + + /* now construct new ioapic rte entry */ + remap_rte->vector = old_rte->vector; + remap_rte->delivery_mode = 0; /* has to be 0 for remap format */ + remap_rte->index_15 = index & 0x8000; + remap_rte->index_0_14 = index & 0x7fff; + remap_rte->delivery_status = old_rte->delivery_status; + remap_rte->polarity = old_rte->polarity; + remap_rte->irr = old_rte->irr; + remap_rte->trigger = old_rte->trigger; + remap_rte->mask = 1; + remap_rte->reserved = 0; + remap_rte->format = 1; /* indicate remap format */ +out: + spin_unlock_irqrestore(&ir_ctrl->iremap_lock, flags); + return; +} + +unsigned int +io_apic_read_remap_rte( + unsigned int apic, unsigned int reg) +{ + struct IO_APIC_route_entry old_rte = { 0 }; + struct IO_APIC_route_remap_entry *remap_rte; + int rte_upper = (reg & 1) ? 1 : 0; + struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); + + if ( !iommu || !(ir_ctrl->iremap) ) + { + *IO_APIC_BASE(apic) = reg; + return *(IO_APIC_BASE(apic)+4); + } + + if ( rte_upper ) + reg--; + + /* read lower and upper 32-bits of rte entry */ + *IO_APIC_BASE(apic) = reg; + *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4); + *IO_APIC_BASE(apic) = reg + 1; + *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4); + + remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte; + + if ( remap_rte->mask || (remap_rte->format == 0) ) + { + *IO_APIC_BASE(apic) = reg; + return *(IO_APIC_BASE(apic)+4); + } + + remap_entry_to_ioapic_rte(iommu, &old_rte); + if ( rte_upper ) + { + *IO_APIC_BASE(apic) = reg + 1; + return (*(((u32 *)&old_rte) + 1)); + } + else + { + *IO_APIC_BASE(apic) = reg; + return (*(((u32 *)&old_rte) + 0)); + } +} + +void +io_apic_write_remap_rte( + unsigned int apic, unsigned int reg, unsigned int value) +{ + struct IO_APIC_route_entry old_rte = { 0 }; + struct IO_APIC_route_remap_entry *remap_rte; + int rte_upper = (reg & 1) ? 1 : 0; + struct iommu *iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid); + struct ir_ctrl *ir_ctrl = iommu_ir_ctrl(iommu); + + if ( !iommu || !(ir_ctrl->iremap) ) + { + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = value; + return; + } + + if ( rte_upper ) + reg--; + + /* read both lower and upper 32-bits of rte entry */ + *IO_APIC_BASE(apic) = reg; + *(((u32 *)&old_rte) + 0) = *(IO_APIC_BASE(apic)+4); + *IO_APIC_BASE(apic) = reg + 1; + *(((u32 *)&old_rte) + 1) = *(IO_APIC_BASE(apic)+4); + + remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte; + if ( remap_rte->mask || (remap_rte->format == 0) ) + { + *IO_APIC_BASE(apic) = rte_upper ? ++reg : reg; + *(IO_APIC_BASE(apic)+4) = value; + return; + } + + *(((u32 *)&old_rte) + rte_upper) = value; + ioapic_rte_to_remap_entry(iommu, mp_ioapics[apic].mpc_apicid, &old_rte); + + /* write new entry to ioapic */ + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+0); + *IO_APIC_BASE(apic) = reg + 1; + *(IO_APIC_BASE(apic)+4) = *(((int *)&old_rte)+1); +} + +int intremap_setup(struct iommu *iommu) +{ + struct ir_ctrl *ir_ctrl; + unsigned long start_time; + u64 paddr; + + if ( !ecap_intr_remap(iommu->ecap) ) + return -ENODEV; + + ir_ctrl = iommu_ir_ctrl(iommu); + if ( ir_ctrl->iremap == NULL ) + { + ir_ctrl->iremap = alloc_xenheap_page(); + if ( ir_ctrl->iremap == NULL ) + { + dprintk(XENLOG_WARNING VTDPREFIX, + "Cannot allocate memory for ir_ctrl->iremap\n"); + return -ENODEV; + } + memset(ir_ctrl->iremap, 0, PAGE_SIZE); + } + + paddr = virt_to_maddr(ir_ctrl->iremap); +#if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT) + /* set extended interrupt mode bit */ + paddr |= ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIMI_SHIFT) : 0; +#endif + /* size field = 256 entries per 4K page = 8 - 1 */ + paddr |= 7; + dmar_writeq(iommu->reg, DMAR_IRTA_REG, paddr); + + /* set SIRTP */ + iommu->gcmd |= DMA_GCMD_SIRTP; + dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); + + /* Make sure hardware complete it */ + start_time = jiffies; + while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_SIRTPS) ) + { + if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "Cannot set SIRTP field for interrupt remapping\n"); + return -ENODEV; + } + cpu_relax(); + } + + /* enable comaptiblity format interrupt pass through */ + iommu->gcmd |= DMA_GCMD_CFI; + dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); + + start_time = jiffies; + while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) ) + { + if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "Cannot set CFI field for interrupt remapping\n"); + return -ENODEV; + } + cpu_relax(); + } + + /* enable interrupt remapping hardware */ + iommu->gcmd |= DMA_GCMD_IRE; + dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); + + start_time = jiffies; + while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) ) + { + if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) ) + { + dprintk(XENLOG_ERR VTDPREFIX, + "Cannot set IRE field for interrupt remapping\n"); + return -ENODEV; + } + cpu_relax(); + } + + /* After set SIRTP, we should do globally invalidate the IEC */ + iommu_flush_iec_global(iommu); + + return 0; +} diff --git a/xen/arch/x86/hvm/vmx/vtd/io.c b/xen/arch/x86/hvm/vmx/vtd/io.c index 39029fab9f..0962757a0e 100644 --- a/xen/arch/x86/hvm/vmx/vtd/io.c +++ b/xen/arch/x86/hvm/vmx/vtd/io.c @@ -141,7 +141,7 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; - if ( !vtd_enabled || (d == dom0) || (hvm_irq->dpci == NULL) || + if ( !iommu_enabled || (d == dom0) || (hvm_irq->dpci == NULL) || !hvm_irq->dpci->mirq[mirq].valid ) return 0; @@ -167,7 +167,7 @@ static void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq) int i; ASSERT(isairq < NR_ISAIRQS); - if ( !vtd_enabled || !dpci || + if ( !iommu_enabled || !dpci || !test_bit(isairq, dpci->isairq_map) ) return; @@ -205,7 +205,7 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; uint32_t device, intx, machine_gsi; - if ( !vtd_enabled || (hvm_irq_dpci == NULL) || + if ( !iommu_enabled || (hvm_irq_dpci == NULL) || (guest_gsi >= NR_ISAIRQS && !hvm_irq_dpci->girq[guest_gsi].valid) ) return; @@ -235,50 +235,3 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, else spin_unlock(&hvm_irq_dpci->dirq_lock); } - -void iommu_domain_destroy(struct domain *d) -{ - struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; - uint32_t i; - struct hvm_iommu *hd = domain_hvm_iommu(d); - struct list_head *ioport_list, *digl_list, *tmp; - struct g2m_ioport *ioport; - struct dev_intx_gsi_link *digl; - - if ( !vtd_enabled ) - return; - - if ( hvm_irq_dpci != NULL ) - { - for ( i = 0; i < NR_IRQS; i++ ) - if ( hvm_irq_dpci->mirq[i].valid ) - { - pirq_guest_unbind(d, i); - kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]); - - list_for_each_safe ( digl_list, tmp, - &hvm_irq_dpci->mirq[i].digl_list ) - { - digl = list_entry(digl_list, - struct dev_intx_gsi_link, list); - list_del(&digl->list); - xfree(digl); - } - } - - d->arch.hvm_domain.irq.dpci = NULL; - xfree(hvm_irq_dpci); - } - - if ( hd ) - { - list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list ) - { - ioport = list_entry(ioport_list, struct g2m_ioport, list); - list_del(&ioport->list); - xfree(ioport); - } - } - - iommu_domain_teardown(d); -} diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index ee98ae8c6a..b114de3e80 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -255,8 +255,21 @@ set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) /* level 1 entry */ paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1); - if ( vtd_enabled && (p2mt == p2m_mmio_direct) && is_hvm_domain(d) ) - iommu_flush(d, gfn, (u64*)p2m_entry); + if ( iommu_enabled && is_hvm_domain(d) ) + { + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + { + if ( (p2mt == p2m_mmio_direct) ) + iommu_flush(d, gfn, (u64*)p2m_entry); + } + else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) + { + if ( p2mt == p2m_ram_rw ) + iommu_map_page(d, gfn, mfn_x(mfn)); + else + iommu_unmap_page(d, gfn); + } + } /* Success */ rv = 1; @@ -486,6 +499,7 @@ static void audit_p2m(struct domain *d) mfn_t p2mfn; unsigned long orphans_d = 0, orphans_i = 0, mpbad = 0, pmbad = 0; int test_linear; + p2m_type_t type; if ( !paging_mode_translate(d) ) return; @@ -534,7 +548,7 @@ static void audit_p2m(struct domain *d) continue; } - p2mfn = gfn_to_mfn_foreign(d, gfn); + p2mfn = gfn_to_mfn_foreign(d, gfn, &type); if ( mfn_x(p2mfn) != mfn ) { mpbad++; @@ -547,12 +561,12 @@ static void audit_p2m(struct domain *d) /* This m2p entry is stale: the domain has another frame in * this physical slot. No great disaster, but for neatness, * blow away the m2p entry. */ - set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY, __PAGE_HYPERVISOR|_PAGE_USER); + set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); } if ( test_linear && (gfn <= d->arch.p2m.max_mapped_pfn) ) { - lp2mfn = mfn_x(gfn_to_mfn_current(gfn)); + lp2mfn = mfn_x(gfn_to_mfn_current(gfn, &type)); if ( lp2mfn != mfn_x(p2mfn) ) { P2M_PRINTK("linear mismatch gfn %#lx -> mfn %#lx " diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index f12a97fbde..8407beacf7 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -1470,10 +1470,14 @@ void sh_install_xen_entries_in_l4(struct vcpu *v, mfn_t gl4mfn, mfn_t sl4mfn) shadow_l4e_from_mfn(page_to_mfn(virt_to_page(d->arch.mm_perdomain_l3)), __PAGE_HYPERVISOR); - /* Linear mapping */ + /* Shadow linear mapping for 4-level shadows. N.B. for 3-level + * shadows on 64-bit xen, this linear mapping is later replaced by the + * monitor pagetable structure, which is built in make_monitor_table + * and maintained by sh_update_linear_entries. */ sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] = shadow_l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR); + /* Self linear mapping. */ if ( shadow_mode_translate(v->domain) && !shadow_mode_external(v->domain) ) { // linear tables may not be used with translated PV guests @@ -1745,7 +1749,7 @@ sh_make_monitor_table(struct vcpu *v) ASSERT(pagetable_get_pfn(v->arch.monitor_table) == 0); /* Guarantee we can get the memory we need */ - shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS - 1); + shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS); #if CONFIG_PAGING_LEVELS == 4 { @@ -1755,22 +1759,34 @@ sh_make_monitor_table(struct vcpu *v) /* Remember the level of this table */ mfn_to_page(m4mfn)->shadow_flags = 4; #if SHADOW_PAGING_LEVELS < 4 - // Install a monitor l3 table in slot 0 of the l4 table. - // This is used for shadow linear maps. { - mfn_t m3mfn; + mfn_t m3mfn, m2mfn; l4_pgentry_t *l4e; + l3_pgentry_t *l3e; + /* Install an l3 table and an l2 table that will hold the shadow + * linear map entries. This overrides the linear map entry that + * was installed by sh_install_xen_entries_in_l4. */ + l4e = sh_map_domain_page(m4mfn); + 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); - sh_unmap_domain_page(l4e); + l4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] + = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR); + + m2mfn = shadow_alloc(d, SH_type_monitor_table, 0); + mfn_to_page(m2mfn)->shadow_flags = 2; + l3e = sh_map_domain_page(m3mfn); + l3e[0] = l3e_from_pfn(mfn_x(m2mfn), __PAGE_HYPERVISOR); + sh_unmap_domain_page(l3e); + if ( is_pv_32on64_vcpu(v) ) { - // Install a monitor l2 table in slot 3 of the l3 table. - // This is used for all Xen entries. - mfn_t m2mfn; - l3_pgentry_t *l3e; + /* For 32-on-64 PV guests, we need to map the 32-bit Xen + * area into its usual VAs in the monitor tables */ + m3mfn = shadow_alloc(d, SH_type_monitor_table, 0); + mfn_to_page(m3mfn)->shadow_flags = 3; + l4e[0] = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR); + m2mfn = shadow_alloc(d, SH_type_monitor_table, 0); mfn_to_page(m2mfn)->shadow_flags = 2; l3e = sh_map_domain_page(m3mfn); @@ -1778,6 +1794,8 @@ sh_make_monitor_table(struct vcpu *v) sh_install_xen_entries_in_l2h(v, m2mfn); sh_unmap_domain_page(l3e); } + + sh_unmap_domain_page(l4e); } #endif /* SHADOW_PAGING_LEVELS < 4 */ return m4mfn; @@ -2181,21 +2199,34 @@ void sh_destroy_monitor_table(struct vcpu *v, mfn_t mmfn) 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 */ { mfn_t m3mfn; l4_pgentry_t *l4e = sh_map_domain_page(mmfn); - ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT); - m3mfn = _mfn(l4e_get_pfn(l4e[0])); + l3_pgentry_t *l3e; + int linear_slot = shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START); + + /* Need to destroy the l3 and l2 monitor pages used + * for the linear map */ + ASSERT(l4e_get_flags(l4e[linear_slot]) & _PAGE_PRESENT); + m3mfn = _mfn(l4e_get_pfn(l4e[linear_slot])); + l3e = sh_map_domain_page(m3mfn); + ASSERT(l3e_get_flags(l3e[0]) & _PAGE_PRESENT); + shadow_free(d, _mfn(l3e_get_pfn(l3e[0]))); + sh_unmap_domain_page(l3e); + shadow_free(d, m3mfn); + if ( is_pv_32on64_vcpu(v) ) { - /* Need to destroy the l2 monitor page in slot 3 too */ - l3_pgentry_t *l3e = sh_map_domain_page(m3mfn); + /* Need to destroy the l3 and l2 monitor pages that map the + * Xen VAs at 3GB-4GB */ + ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT); + m3mfn = _mfn(l4e_get_pfn(l4e[0])); + l3e = sh_map_domain_page(m3mfn); ASSERT(l3e_get_flags(l3e[3]) & _PAGE_PRESENT); shadow_free(d, _mfn(l3e_get_pfn(l3e[3]))); sh_unmap_domain_page(l3e); + shadow_free(d, m3mfn); } - shadow_free(d, m3mfn); sh_unmap_domain_page(l4e); } #elif CONFIG_PAGING_LEVELS == 3 @@ -3222,28 +3253,33 @@ sh_update_linear_entries(struct vcpu *v) if ( shadow_mode_external(d) ) { - /* Install copies of the shadow l3es into the monitor l3 table. - * The monitor l3 table is hooked into slot 0 of the monitor - * l4 table, so we use l3 linear indices 0 to 3 */ + /* Install copies of the shadow l3es into the monitor l2 table + * that maps SH_LINEAR_PT_VIRT_START. */ shadow_l3e_t *sl3e; - l3_pgentry_t *ml3e; - mfn_t l3mfn; + l2_pgentry_t *ml2e; int i; /* Use linear mappings if we can; otherwise make new mappings */ - if ( v == current ) - { - ml3e = __linear_l3_table; - l3mfn = _mfn(l4e_get_pfn(__linear_l4_table[0])); - } + if ( v == current ) + ml2e = __linear_l2_table + + l2_linear_offset(SH_LINEAR_PT_VIRT_START); else { + mfn_t l3mfn, l2mfn; l4_pgentry_t *ml4e; + l3_pgentry_t *ml3e; + int linear_slot = shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START); ml4e = sh_map_domain_page(pagetable_get_mfn(v->arch.monitor_table)); - ASSERT(l4e_get_flags(ml4e[0]) & _PAGE_PRESENT); - l3mfn = _mfn(l4e_get_pfn(ml4e[0])); + + ASSERT(l4e_get_flags(ml4e[linear_slot]) & _PAGE_PRESENT); + l3mfn = _mfn(l4e_get_pfn(ml4e[linear_slot])); ml3e = sh_map_domain_page(l3mfn); sh_unmap_domain_page(ml4e); + + ASSERT(l3e_get_flags(ml3e[0]) & _PAGE_PRESENT); + l2mfn = _mfn(l3e_get_pfn(ml3e[0])); + ml2e = sh_map_domain_page(l2mfn); + sh_unmap_domain_page(ml3e); } /* Shadow l3 tables are made up by sh_update_cr3 */ @@ -3251,15 +3287,15 @@ sh_update_linear_entries(struct vcpu *v) for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ ) { - ml3e[i] = + ml2e[i] = (shadow_l3e_get_flags(sl3e[i]) & _PAGE_PRESENT) - ? l3e_from_pfn(mfn_x(shadow_l3e_get_mfn(sl3e[i])), + ? l2e_from_pfn(mfn_x(shadow_l3e_get_mfn(sl3e[i])), __PAGE_HYPERVISOR) - : l3e_empty(); + : l2e_empty(); } if ( v != current ) - sh_unmap_domain_page(ml3e); + sh_unmap_domain_page(ml2e); } else domain_crash(d); /* XXX */ @@ -4180,15 +4216,12 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, if ( (vaddr & (bytes - 1)) && !is_hvm_vcpu(v) ) return X86EMUL_UNHANDLEABLE; - shadow_lock(v->domain); addr = emulate_map_dest(v, vaddr, bytes, sh_ctxt); if ( emulate_map_dest_failed(addr) ) - { - shadow_unlock(v->domain); return ((addr == MAPPING_EXCEPTION) ? X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); - } + shadow_lock(v->domain); memcpy(addr, src, bytes); emulate_unmap_dest(v, addr, bytes, sh_ctxt); @@ -4210,16 +4243,12 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr, if ( (vaddr & (bytes - 1)) && !is_hvm_vcpu(v) ) return X86EMUL_UNHANDLEABLE; - shadow_lock(v->domain); - addr = emulate_map_dest(v, vaddr, bytes, sh_ctxt); if ( emulate_map_dest_failed(addr) ) - { - shadow_unlock(v->domain); return ((addr == MAPPING_EXCEPTION) ? X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); - } + shadow_lock(v->domain); switch ( bytes ) { case 1: prev = cmpxchg(((u8 *)addr), old, new); break; @@ -4258,18 +4287,15 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, if ( (vaddr & 7) && !is_hvm_vcpu(v) ) return X86EMUL_UNHANDLEABLE; - shadow_lock(v->domain); - addr = emulate_map_dest(v, vaddr, 8, sh_ctxt); if ( emulate_map_dest_failed(addr) ) - { - shadow_unlock(v->domain); return ((addr == MAPPING_EXCEPTION) ? X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); - } old = (((u64) old_hi) << 32) | (u64) old_lo; new = (((u64) new_hi) << 32) | (u64) new_lo; + + shadow_lock(v->domain); prev = cmpxchg(((u64 *)addr), old, new); if ( prev != old ) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 32668e9455..1377355048 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -54,6 +54,7 @@ #include <mach_apic.h> #include <mach_wakecpu.h> #include <smpboot_hooks.h> +#include <xen/stop_machine.h> #define set_kernel_exec(x, y) (0) #define setup_trampoline() (bootsym_phys(trampoline_realmode_entry)) @@ -111,7 +112,7 @@ static void map_cpu_to_logical_apicid(void); DEFINE_PER_CPU(int, cpu_state) = { 0 }; static void *stack_base[NR_CPUS] __cacheline_aligned; -spinlock_t cpu_add_remove_lock; +static DEFINE_SPINLOCK(cpu_add_remove_lock); /* * The bootstrap kernel entry code has set these up. Save them for @@ -1163,7 +1164,6 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(smp_processor_id(), cpu_present_map); cpu_set(smp_processor_id(), cpu_possible_map); per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; - spin_lock_init(&cpu_add_remove_lock); } #ifdef CONFIG_HOTPLUG_CPU @@ -1208,6 +1208,15 @@ int __cpu_disable(void) if (cpu == 0) return -EBUSY; + /* + * Only S3 is using this path, and thus idle vcpus are running on all + * APs when we are called. To support full cpu hotplug, other + * notification mechanisms should be introduced (e.g., migrate vcpus + * off this physical cpu before rendezvous point). + */ + if (!is_idle_vcpu(current)) + return -EINVAL; + local_irq_disable(); clear_local_APIC(); /* Allow any queued timer interrupts to get serviced */ @@ -1244,6 +1253,11 @@ void __cpu_die(unsigned int cpu) printk(KERN_ERR "CPU %u didn't die...\n", cpu); } +static int take_cpu_down(void *unused) +{ + return __cpu_disable(); +} + /* * XXX: One important thing missed here is to migrate vcpus * from dead cpu to other online ones and then put whole @@ -1269,7 +1283,6 @@ void __cpu_die(unsigned int cpu) int cpu_down(unsigned int cpu) { int err = 0; - cpumask_t mask; spin_lock(&cpu_add_remove_lock); if (num_online_cpus() == 1) { @@ -1283,11 +1296,10 @@ int cpu_down(unsigned int cpu) } printk("Prepare to bring CPU%d down...\n", cpu); - /* Send notification to remote idle vcpu */ - cpus_clear(mask); - cpu_set(cpu, mask); - per_cpu(cpu_state, cpu) = CPU_DYING; - smp_send_event_check_mask(mask); + + err = stop_machine_run(take_cpu_down, NULL, cpu); + if ( err < 0 ) + goto out; __cpu_die(cpu); diff --git a/xen/arch/x86/trace.c b/xen/arch/x86/trace.c index ddb32202bd..65e66a3280 100644 --- a/xen/arch/x86/trace.c +++ b/xen/arch/x86/trace.c @@ -15,9 +15,6 @@ asmlinkage void trace_hypercall(void) { struct cpu_user_regs *regs = guest_cpu_user_regs(); - if ( !tb_init_done ) - return; - #ifdef __x86_64__ if ( is_pv_32on64_vcpu(current) ) { @@ -52,9 +49,6 @@ asmlinkage void trace_hypercall(void) void __trace_pv_trap(int trapnr, unsigned long eip, int use_error_code, unsigned error_code) { - if ( !tb_init_done ) - return; - #ifdef __x86_64__ if ( is_pv_32on64_vcpu(current) ) { @@ -99,9 +93,6 @@ void __trace_pv_page_fault(unsigned long addr, unsigned error_code) { unsigned long eip = guest_cpu_user_regs()->eip; - if ( !tb_init_done ) - return; - #ifdef __x86_64__ if ( is_pv_32on64_vcpu(current) ) { @@ -135,9 +126,6 @@ void __trace_pv_page_fault(unsigned long addr, unsigned error_code) void __trace_trap_one_addr(unsigned event, unsigned long va) { - if ( !tb_init_done ) - return; - #ifdef __x86_64__ if ( is_pv_32on64_vcpu(current) ) { @@ -155,9 +143,6 @@ void __trace_trap_one_addr(unsigned event, unsigned long va) void __trace_trap_two_addr(unsigned event, unsigned long va1, unsigned long va2) { - if ( !tb_init_done ) - return; - #ifdef __x86_64__ if ( is_pv_32on64_vcpu(current) ) { @@ -185,9 +170,6 @@ void __trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte) { unsigned long eip = guest_cpu_user_regs()->eip; - if ( !tb_init_done ) - return; - /* We have a couple of different modes to worry about: * - 32-on-32: 32-bit pte, 32-bit virtual addresses * - pae-on-pae, pae-on-64: 64-bit pte, 32-bit virtual addresses diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index ee0118a7b3..b240a0a48e 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -1710,11 +1710,14 @@ x86_emulate( switch ( src.bytes ) { case 1: + dst.val = (uint8_t)dst.val; dst.val *= src.val; if ( (uint8_t)dst.val != (uint16_t)dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; + dst.bytes = 2; break; case 2: + dst.val = (uint16_t)dst.val; dst.val *= src.val; if ( (uint16_t)dst.val != (uint32_t)dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; @@ -1722,6 +1725,7 @@ x86_emulate( break; #ifdef __x86_64__ case 4: + dst.val = (uint32_t)dst.val; dst.val *= src.val; if ( (uint32_t)dst.val != dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; @@ -1751,6 +1755,7 @@ x86_emulate( (uint16_t)(int8_t)dst.val); if ( (int8_t)dst.val != (uint16_t)dst.val ) _regs.eflags |= EFLG_OF|EFLG_CF; + dst.bytes = 2; break; case 2: dst.val = ((uint32_t)(int16_t)src.val * @@ -2221,11 +2226,12 @@ x86_emulate( dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes; dst.mem.seg = x86_seg_es; dst.mem.off = truncate_ea(_regs.edi); - if ( (nr_reps > 1) && (ops->rep_ins != NULL) ) + if ( (nr_reps > 1) && (ops->rep_ins != NULL) && + ((rc = ops->rep_ins((uint16_t)_regs.edx, dst.mem.seg, + dst.mem.off, dst.bytes, + &nr_reps, ctxt)) != X86EMUL_UNHANDLEABLE) ) { - if ( (rc = ops->rep_ins((uint16_t)_regs.edx, dst.mem.seg, - dst.mem.off, dst.bytes, - &nr_reps, ctxt)) != 0 ) + if ( rc != 0 ) goto done; } else @@ -2248,11 +2254,12 @@ x86_emulate( unsigned long nr_reps = get_rep_prefix(); generate_exception_if(!mode_iopl(), EXC_GP); dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes; - if ( (nr_reps > 1) && (ops->rep_outs != NULL) ) + if ( (nr_reps > 1) && (ops->rep_outs != NULL) && + ((rc = ops->rep_outs(ea.mem.seg, truncate_ea(_regs.esi), + (uint16_t)_regs.edx, dst.bytes, + &nr_reps, ctxt)) != X86EMUL_UNHANDLEABLE) ) { - if ( (rc = ops->rep_outs(ea.mem.seg, truncate_ea(_regs.esi), - (uint16_t)_regs.edx, dst.bytes, - &nr_reps, ctxt)) != 0 ) + if ( rc != 0 ) goto done; } else @@ -2399,11 +2406,12 @@ x86_emulate( dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.mem.seg = x86_seg_es; dst.mem.off = truncate_ea(_regs.edi); - if ( (nr_reps > 1) && (ops->rep_movs != NULL) ) + if ( (nr_reps > 1) && (ops->rep_movs != NULL) && + ((rc = ops->rep_movs(ea.mem.seg, truncate_ea(_regs.esi), + dst.mem.seg, dst.mem.off, dst.bytes, + &nr_reps, ctxt)) != X86EMUL_UNHANDLEABLE) ) { - if ( (rc = ops->rep_movs(ea.mem.seg, truncate_ea(_regs.esi), - dst.mem.seg, dst.mem.off, dst.bytes, - &nr_reps, ctxt)) != 0 ) + if ( rc != 0 ) goto done; } else diff --git a/xen/common/Makefile b/xen/common/Makefile index 1bf38310bf..631ac384bd 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -16,6 +16,7 @@ obj-y += sched_sedf.o obj-y += schedule.o obj-y += shutdown.o obj-y += softirq.o +obj-y += stop_machine.o obj-y += string.o obj-y += symbols.o obj-y += sysctl.o diff --git a/xen/common/stop_machine.c b/xen/common/stop_machine.c new file mode 100644 index 0000000000..1411b9f197 --- /dev/null +++ b/xen/common/stop_machine.c @@ -0,0 +1,158 @@ +/****************************************************************************** + * common/stop_machine.c + * + * Facilities to put whole machine in a safe 'stop' state + * + * Copyright 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation + * Copyright 2008 Kevin Tian <kevin.tian@intel.com>, 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 <xen/config.h> +#include <xen/init.h> +#include <xen/sched.h> +#include <xen/spinlock.h> +#include <xen/softirq.h> +#include <xen/errno.h> +#include <xen/smp.h> +#include <asm/current.h> +#include <asm/processor.h> + +enum stopmachine_state { + STOPMACHINE_START, + STOPMACHINE_PREPARE, + STOPMACHINE_DISABLE_IRQ, + STOPMACHINE_INVOKE, + STOPMACHINE_EXIT +}; + +struct stopmachine_data { + unsigned int nr_cpus; + + enum stopmachine_state state; + atomic_t done; + + unsigned int fn_cpu; + int fn_result; + int (*fn)(void *); + void *fn_data; +}; + +static struct stopmachine_data stopmachine_data; +static DEFINE_SPINLOCK(stopmachine_lock); + +static void stopmachine_set_state(enum stopmachine_state state) +{ + atomic_set(&stopmachine_data.done, 0); + smp_wmb(); + stopmachine_data.state = state; + while ( atomic_read(&stopmachine_data.done) != stopmachine_data.nr_cpus ) + cpu_relax(); +} + +int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) +{ + cpumask_t allbutself; + unsigned int i, nr_cpus; + int ret; + + BUG_ON(!local_irq_is_enabled()); + + allbutself = cpu_online_map; + cpu_clear(smp_processor_id(), allbutself); + nr_cpus = cpus_weight(allbutself); + + if ( nr_cpus == 0 ) + { + BUG_ON(cpu != smp_processor_id()); + return (*fn)(data); + } + + /* Note: We shouldn't spin on lock when it's held by others since others + * is expecting this cpus to enter softirq context. Or else deadlock + * is caused. + */ + if ( !spin_trylock(&stopmachine_lock) ) + return -EBUSY; + + stopmachine_data.fn = fn; + stopmachine_data.fn_data = data; + stopmachine_data.nr_cpus = nr_cpus; + stopmachine_data.fn_cpu = cpu; + atomic_set(&stopmachine_data.done, 0); + stopmachine_data.state = STOPMACHINE_START; + + smp_wmb(); + + for_each_cpu_mask ( i, allbutself ) + cpu_raise_softirq(i, STOPMACHINE_SOFTIRQ); + + stopmachine_set_state(STOPMACHINE_PREPARE); + + local_irq_disable(); + stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); + + if ( cpu == smp_processor_id() ) + stopmachine_data.fn_result = (*fn)(data); + stopmachine_set_state(STOPMACHINE_INVOKE); + ret = stopmachine_data.fn_result; + + stopmachine_set_state(STOPMACHINE_EXIT); + local_irq_enable(); + + spin_unlock(&stopmachine_lock); + + return ret; +} + +static void stopmachine_softirq(void) +{ + enum stopmachine_state state = STOPMACHINE_START; + + smp_mb(); + + while ( state != STOPMACHINE_EXIT ) + { + while ( stopmachine_data.state == state ) + cpu_relax(); + + state = stopmachine_data.state; + switch ( state ) + { + case STOPMACHINE_DISABLE_IRQ: + local_irq_disable(); + break; + case STOPMACHINE_INVOKE: + if ( stopmachine_data.fn_cpu == smp_processor_id() ) + stopmachine_data.fn_result = + stopmachine_data.fn(stopmachine_data.fn_data); + break; + default: + break; + } + + smp_mb(); + atomic_inc(&stopmachine_data.done); + } + + local_irq_enable(); +} + +static int __init cpu_stopmachine_init(void) +{ + open_softirq(STOPMACHINE_SOFTIRQ, stopmachine_softirq); + return 0; +} +__initcall(cpu_stopmachine_init); diff --git a/xen/common/trace.c b/xen/common/trace.c index 9af70798bb..863816b9ee 100644 --- a/xen/common/trace.c +++ b/xen/common/trace.c @@ -239,14 +239,46 @@ static inline int calc_rec_size(int cycles, int extra) return rec_size; } +static inline int calc_unconsumed_bytes(struct t_buf *buf) +{ + int x = buf->prod - buf->cons; + if ( x < 0 ) + x += 2*data_size; + + ASSERT(x >= 0); + ASSERT(x <= data_size); + + return x; +} + static inline int calc_bytes_to_wrap(struct t_buf *buf) { - return data_size - (buf->prod % data_size); + int x = data_size - buf->prod; + if ( x <= 0 ) + x += data_size; + + ASSERT(x > 0); + ASSERT(x <= data_size); + + return x; +} + +static inline int calc_bytes_avail(struct t_buf *buf) +{ + return data_size - calc_unconsumed_bytes(buf); } -static inline unsigned calc_bytes_avail(struct t_buf *buf) +static inline struct t_rec * +next_record(struct t_buf *buf) { - return data_size - (buf->prod - buf->cons); + int x = buf->prod; + if ( x >= data_size ) + x -= data_size; + + ASSERT(x >= 0); + ASSERT(x < data_size); + + return (struct t_rec *)&this_cpu(t_data)[x]; } static inline int __insert_record(struct t_buf *buf, @@ -260,24 +292,25 @@ static inline int __insert_record(struct t_buf *buf, unsigned char *dst; unsigned long extra_word = extra/sizeof(u32); int local_rec_size = calc_rec_size(cycles, extra); + uint32_t next; BUG_ON(local_rec_size != rec_size); + BUG_ON(extra & 3); /* Double-check once more that we have enough space. * Don't bugcheck here, in case the userland tool is doing * something stupid. */ if ( calc_bytes_avail(buf) < rec_size ) { - printk("%s: %u bytes left (%u - (%u - %u)) recsize %u.\n", + printk("%s: %u bytes left (%u - ((%u - %u) %% %u) recsize %u.\n", __func__, - data_size - (buf->prod - buf->cons), - data_size, - buf->prod, buf->cons, rec_size); + calc_bytes_avail(buf), + data_size, buf->prod, buf->cons, data_size, rec_size); return 0; } rmb(); - rec = (struct t_rec *)&this_cpu(t_data)[buf->prod % data_size]; + rec = next_record(buf); rec->event = event; rec->extra_u32 = extra_word; dst = (unsigned char *)rec->u.nocycles.extra_u32; @@ -293,7 +326,13 @@ static inline int __insert_record(struct t_buf *buf, memcpy(dst, extra_data, extra); wmb(); - buf->prod += rec_size; + + next = buf->prod + rec_size; + if ( next >= 2*data_size ) + next -= 2*data_size; + ASSERT(next >= 0); + ASSERT(next < 2*data_size); + buf->prod = next; return rec_size; } @@ -395,7 +434,7 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) local_irq_save(flags); - started_below_highwater = ((buf->prod - buf->cons) < t_buf_highwater); + started_below_highwater = (calc_unconsumed_bytes(buf) < t_buf_highwater); /* Calculate the record size */ rec_size = calc_rec_size(cycles, extra); @@ -413,10 +452,6 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) total_size = 0; /* First, check to see if we need to include a lost_record. - * - * calc_bytes_to_wrap() involves integer division, which we'd like to - * avoid if we can. So do the math, check it in debug versions, and - * do a final check always if we happen to write a record. */ if ( this_cpu(lost_records) ) { @@ -425,25 +460,18 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) total_size += bytes_to_wrap; bytes_to_wrap = data_size; } - else - { - bytes_to_wrap -= LOST_REC_SIZE; - if ( bytes_to_wrap == 0 ) - bytes_to_wrap = data_size; - } total_size += LOST_REC_SIZE; + bytes_to_wrap -= LOST_REC_SIZE; + + /* LOST_REC might line up perfectly with the buffer wrap */ + if ( bytes_to_wrap == 0 ) + bytes_to_wrap = data_size; } if ( rec_size > bytes_to_wrap ) { total_size += bytes_to_wrap; - bytes_to_wrap = data_size; } - else - { - bytes_to_wrap -= rec_size; - } - total_size += rec_size; /* Do we have enough space for everything? */ @@ -466,14 +494,12 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) insert_wrap_record(buf, LOST_REC_SIZE); bytes_to_wrap = data_size; } - else - { - bytes_to_wrap -= LOST_REC_SIZE; - /* LOST_REC might line up perfectly with the buffer wrap */ - if ( bytes_to_wrap == 0 ) - bytes_to_wrap = data_size; - } insert_lost_records(buf); + bytes_to_wrap -= LOST_REC_SIZE; + + /* LOST_REC might line up perfectly with the buffer wrap */ + if ( bytes_to_wrap == 0 ) + bytes_to_wrap = data_size; } if ( rec_size > bytes_to_wrap ) @@ -486,7 +512,7 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) /* Notify trace buffer consumer that we've crossed the high water mark. */ if ( started_below_highwater && - ((buf->prod - buf->cons) >= t_buf_highwater) ) + (calc_unconsumed_bytes(buf) >= t_buf_highwater) ) raise_softirq(TRACE_SOFTIRQ); } diff --git a/xen/include/asm-x86/hvm/iommu.h b/xen/include/asm-x86/hvm/iommu.h index 210530947f..5ac7aef1c9 100644 --- a/xen/include/asm-x86/hvm/iommu.h +++ b/xen/include/asm-x86/hvm/iommu.h @@ -48,6 +48,9 @@ struct hvm_iommu { int domain_id; int paging_mode; void *root_table; + + /* iommu_ops */ + struct iommu_ops *platform_ops; }; #endif // __ASM_X86_HVM_IOMMU_H__ diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h index 56089a5317..bece80c5db 100644 --- a/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-defs.h @@ -263,6 +263,10 @@ #define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_MASK 0xFFFFFFFF #define IOMMU_INV_IOMMU_PAGES_ADDR_HIGH_SHIFT 0 +/* INVALIDATE_DEVTAB_ENTRY command */ +#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_MASK 0x0000FFFF +#define IOMMU_INV_DEVTAB_ENTRY_DEVICE_ID_SHIFT 0 + /* Event Log */ #define IOMMU_EVENT_LOG_BASE_LOW_OFFSET 0x10 #define IOMMU_EVENT_LOG_BASE_HIGH_OFFSET 0x14 @@ -415,5 +419,6 @@ #define IOMMU_PAGE_TABLE_LEVEL_4 4 #define IOMMU_IO_WRITE_ENABLED 1 #define IOMMU_IO_READ_ENABLED 1 +#define HACK_BIOS_SETTINGS 0 #endif /* _ASM_X86_64_AMD_IOMMU_DEFS_H */ diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h index d9b21a5973..592f908946 100644 --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h @@ -27,13 +27,15 @@ list_for_each_entry(amd_iommu, \ &amd_iommu_head, list) +#define for_each_pdev(domain, pdev) \ + list_for_each_entry(pdev, \ + &(domain->arch.hvm_domain.hvm_iommu.pdev_list), list) + #define DMA_32BIT_MASK 0x00000000ffffffffULL #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) -#define PAGE_SHIFT_4K (12) -#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K) -#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K) -typedef int (*iommu_detect_callback_ptr_t)(u8 bus, u8 dev, u8 func, u8 cap_ptr); +typedef int (*iommu_detect_callback_ptr_t)( + u8 bus, u8 dev, u8 func, u8 cap_ptr); /* amd-iommu-detect functions */ int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback); @@ -49,16 +51,20 @@ void __init register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu); void __init enable_iommu(struct amd_iommu *iommu); /* mapping functions */ -int amd_iommu_map_page(struct domain *d, unsigned long gfn, - unsigned long mfn); +int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn); int amd_iommu_unmap_page(struct domain *d, unsigned long gfn); +void *amd_iommu_get_vptr_from_page_table_entry(u32 *entry); /* device table functions */ void amd_iommu_set_dev_table_entry(u32 *dte, u64 root_ptr, u16 domain_id, u8 paging_mode); +int amd_iommu_is_dte_page_translation_valid(u32 *entry); +void invalidate_dev_table_entry(struct amd_iommu *iommu, + u16 devic_id); /* send cmd to iommu */ int send_iommu_command(struct amd_iommu *iommu, u32 cmd[]); +void flush_command_buffer(struct amd_iommu *iommu); /* iommu domain funtions */ int amd_iommu_domain_init(struct domain *domain); diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h index 54c578f912..cb4dc10ad8 100644 --- a/xen/include/asm-x86/hvm/trace.h +++ b/xen/include/asm-x86/hvm/trace.h @@ -31,14 +31,15 @@ #define DO_TRC_HVM_CLTS 1 #define DO_TRC_HVM_LMSW 1 - - static inline void hvmtrace_vmexit(struct vcpu *v, unsigned long rip, unsigned long exit_reason) { + if ( likely(!tb_init_done) ) + return; + #ifdef __x86_64__ - if(hvm_long_mode_enabled(v)) + if ( hvm_long_mode_enabled(v) ) { struct { unsigned did:16, vid:16; @@ -50,9 +51,12 @@ static inline void hvmtrace_vmexit(struct vcpu *v, d.vid = v->vcpu_id; d.exit_reason = exit_reason; d.rip = rip; - trace_var(TRC_HVM_VMEXIT64, 1/*cycles*/, sizeof(d), (unsigned char *)&d); - } else { + __trace_var(TRC_HVM_VMEXIT64, 1/*cycles*/, sizeof(d), + (unsigned char *)&d); + } + else #endif + { struct { unsigned did:16, vid:16; unsigned exit_reason:32; @@ -63,10 +67,9 @@ static inline void hvmtrace_vmexit(struct vcpu *v, d.vid = v->vcpu_id; d.exit_reason = exit_reason; d.eip = rip; - trace_var(TRC_HVM_VMEXIT, 1/*cycles*/, sizeof(d), (unsigned char *)&d); -#ifdef __x86_64__ + __trace_var(TRC_HVM_VMEXIT, 1/*cycles*/, sizeof(d), + (unsigned char *)&d); } -#endif } @@ -75,9 +78,13 @@ static inline void hvmtrace_vmentry(struct vcpu *v) struct { unsigned did:16, vid:16; } d; + + if ( likely(!tb_init_done) ) + return; + d.did = v->domain->domain_id; d.vid = v->vcpu_id; - trace_var(TRC_HVM_VMENTRY, 1/*cycles*/, sizeof(d), (unsigned char *)&d); + __trace_var(TRC_HVM_VMENTRY, 1/*cycles*/, sizeof(d), (unsigned char *)&d); } static inline void hvmtrace_msr_read(struct vcpu *v, u32 ecx, u64 msr_content) @@ -87,11 +94,16 @@ static inline void hvmtrace_msr_read(struct vcpu *v, u32 ecx, u64 msr_content) u32 ecx; u64 msr_content; } d; + + if ( likely(!tb_init_done) ) + return; + d.did = v->domain->domain_id; d.vid = v->vcpu_id; d.ecx = ecx; d.msr_content = msr_content; - trace_var(TRC_HVM_MSR_READ, 0/*!cycles*/, sizeof(d), (unsigned char *)&d); + __trace_var(TRC_HVM_MSR_READ, 0/*!cycles*/, sizeof(d), + (unsigned char *)&d); } static inline void hvmtrace_msr_write(struct vcpu *v, u32 ecx, u64 msr_content) @@ -101,18 +113,26 @@ static inline void hvmtrace_msr_write(struct vcpu *v, u32 ecx, u64 msr_content) u32 ecx; u64 msr_content; } d; + + if ( likely(!tb_init_done) ) + return; + d.did = v->domain->domain_id; d.vid = v->vcpu_id; d.ecx = ecx; d.msr_content = msr_content; - trace_var(TRC_HVM_MSR_WRITE, 0/*!cycles*/,sizeof(d), (unsigned char *)&d); + __trace_var(TRC_HVM_MSR_WRITE, 0/*!cycles*/,sizeof(d), + (unsigned char *)&d); } static inline void hvmtrace_pf_xen(struct vcpu *v, unsigned long va, u32 error_code) { + if ( likely(!tb_init_done) ) + return; + #ifdef __x86_64__ - if(hvm_long_mode_enabled(v)) + if( hvm_long_mode_enabled(v) ) { struct { unsigned did:16, vid:16; @@ -123,10 +143,12 @@ static inline void hvmtrace_pf_xen(struct vcpu *v, unsigned long va, d.vid = v->vcpu_id; d.error_code = error_code; d.va = va; - trace_var(TRC_HVM_PF_XEN64, 0/*!cycles*/,sizeof(d), - (unsigned char *)&d); - } else { + __trace_var(TRC_HVM_PF_XEN64, 0/*!cycles*/,sizeof(d), + (unsigned char *)&d); + } + else #endif + { struct { unsigned did:16, vid:16; u32 error_code; @@ -136,15 +158,14 @@ static inline void hvmtrace_pf_xen(struct vcpu *v, unsigned long va, d.vid = v->vcpu_id; d.error_code = error_code; d.va = va; - trace_var(TRC_HVM_PF_XEN, 0/*!cycles*/,sizeof(d), (unsigned char *)&d); -#ifdef __x86_64__ + __trace_var(TRC_HVM_PF_XEN, 0/*!cycles*/,sizeof(d), + (unsigned char *)&d); } -#endif } #define HVMTRACE_ND(evt, vcpu, count, d1, d2, d3, d4) \ do { \ - if (DO_TRC_HVM_ ## evt) \ + if ( unlikely(tb_init_done) && DO_TRC_HVM_ ## evt ) \ { \ struct { \ unsigned did:16, vid:16; \ @@ -156,8 +177,8 @@ static inline void hvmtrace_pf_xen(struct vcpu *v, unsigned long va, _d.d[1]=(d2); \ _d.d[2]=(d3); \ _d.d[3]=(d4); \ - trace_var(TRC_HVM_ ## evt, 0/*!cycles*/, \ - sizeof(u32)*count+1, (unsigned char *)&_d); \ + __trace_var(TRC_HVM_ ## evt, 0/*!cycles*/, \ + sizeof(u32)*count+1, (unsigned char *)&_d); \ } \ } while(0) @@ -167,7 +188,8 @@ static inline void hvmtrace_pf_xen(struct vcpu *v, unsigned long va, #define HVMTRACE_1D(evt, vcpu, d1) HVMTRACE_ND(evt, vcpu, 1, d1, 0, 0, 0) #define HVMTRACE_0D(evt, vcpu) HVMTRACE_ND(evt, vcpu, 0, 0, 0, 0, 0) -#endif //__ASM_X86_HVM_TRACE_H__ +#endif /* __ASM_X86_HVM_TRACE_H__ */ + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/hvm/vmx/intel-iommu.h b/xen/include/asm-x86/hvm/vmx/intel-iommu.h index 0f9c08c50f..07b07c09d3 100644 --- a/xen/include/asm-x86/hvm/vmx/intel-iommu.h +++ b/xen/include/asm-x86/hvm/vmx/intel-iommu.h @@ -422,8 +422,6 @@ struct poll_info { #define VTD_PAGE_TABLE_LEVEL_3 3 #define VTD_PAGE_TABLE_LEVEL_4 4 -typedef paddr_t dma_addr_t; - #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48 #define MAX_IOMMUS 32 #define MAX_IOMMU_REGS 0xc0 @@ -447,8 +445,10 @@ struct ir_ctrl { }; struct iommu_flush { - int (*context)(void *iommu, u16 did, u16 source_id, u8 function_mask, u64 type, int non_present_entry_flush); - int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order, u64 type, int non_present_entry_flush); + int (*context)(void *iommu, u16 did, u16 source_id, + u8 function_mask, u64 type, int non_present_entry_flush); + int (*iotlb)(void *iommu, u16 did, u64 addr, unsigned int size_order, + u64 type, int non_present_entry_flush); }; struct intel_iommu { diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index e8e102a6b8..86c91b6762 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -6,6 +6,7 @@ #include <asm/mpspec.h> #include <asm/apicdef.h> #include <asm/fixmap.h> +#include <asm/iommu.h> /* * Intel IO-APIC support for SMP and UP systems. @@ -124,12 +125,16 @@ extern int mpc_default_type; static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) { + if (vtd_enabled) + return io_apic_read_remap_rte(apic, reg); *IO_APIC_BASE(apic) = reg; return *(IO_APIC_BASE(apic)+4); } static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) { + if (vtd_enabled) + return io_apic_write_remap_rte(apic, reg, value); *IO_APIC_BASE(apic) = reg; *(IO_APIC_BASE(apic)+4) = value; } diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h index daec64bf76..6707f94cbe 100644 --- a/xen/include/asm-x86/iommu.h +++ b/xen/include/asm-x86/iommu.h @@ -28,7 +28,9 @@ #include <public/domctl.h> extern int vtd_enabled; +extern int amd_iommu_enabled; +#define iommu_enabled ( amd_iommu_enabled || vtd_enabled ) #define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu) #define domain_vmx_iommu(d) (&d->arch.hvm_domain.hvm_iommu.vmx_iommu) #define iommu_qi_ctrl(iommu) (&(iommu->intel.qi_ctrl)); @@ -72,17 +74,29 @@ int iommu_domain_init(struct domain *d); void iommu_domain_destroy(struct domain *d); int device_assigned(u8 bus, u8 devfn); int assign_device(struct domain *d, u8 bus, u8 devfn); -int iommu_map_page(struct domain *d, dma_addr_t gfn, dma_addr_t mfn); -int iommu_unmap_page(struct domain *d, dma_addr_t gfn); -void iommu_flush(struct domain *d, dma_addr_t gfn, u64 *p2m_entry); +int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn); +int iommu_unmap_page(struct domain *d, unsigned long gfn); +void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry); void iommu_set_pgd(struct domain *d); void iommu_domain_teardown(struct domain *d); int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq); int dpci_ioport_intercept(ioreq_t *p); int pt_irq_create_bind_vtd(struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind); +unsigned int io_apic_read_remap_rte( + unsigned int apic, unsigned int reg); +void io_apic_write_remap_rte(unsigned int apic, + unsigned int reg, unsigned int value); #define PT_IRQ_TIME_OUT MILLISECS(8) #define VTDPREFIX "[VT-D]" +struct iommu_ops { + int (*init)(struct domain *d); + int (*assign_device)(struct domain *d, u8 bus, u8 devfn); + void (*teardown)(struct domain *d); + int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn); + int (*unmap_page)(struct domain *d, unsigned long gfn); +}; + #endif /* _IOMMU_H_ */ diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index 55b8cf7705..cf5159603d 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -51,12 +51,11 @@ extern u8 x86_cpu_to_apicid[]; /* State of each CPU. */ #define CPU_ONLINE 0x0002 /* CPU is up */ -#define CPU_DYING 0x0003 /* CPU is requested to die */ #define CPU_DEAD 0x0004 /* CPU is dead */ DECLARE_PER_CPU(int, cpu_state); #ifdef CONFIG_HOTPLUG_CPU -#define cpu_is_offline(cpu) unlikely(per_cpu(cpu_state,cpu) == CPU_DYING) +#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) extern int cpu_down(unsigned int cpu); extern int cpu_up(unsigned int cpu); extern void cpu_exit_clear(void); diff --git a/xen/include/asm-x86/trace.h b/xen/include/asm-x86/trace.h index c8b13c4b86..e65b5de6ee 100644 --- a/xen/include/asm-x86/trace.h +++ b/xen/include/asm-x86/trace.h @@ -8,7 +8,7 @@ void __trace_pv_trap(int trapnr, unsigned long eip, static inline void trace_pv_trap(int trapnr, unsigned long eip, int use_error_code, unsigned error_code) { - if ( tb_init_done ) + if ( unlikely(tb_init_done) ) __trace_pv_trap(trapnr, eip, use_error_code, error_code); } @@ -16,14 +16,14 @@ void __trace_pv_page_fault(unsigned long addr, unsigned error_code); static inline void trace_pv_page_fault(unsigned long addr, unsigned error_code) { - if ( tb_init_done ) + if ( unlikely(tb_init_done) ) __trace_pv_page_fault(addr, error_code); } void __trace_trap_one_addr(unsigned event, unsigned long va); static inline void trace_trap_one_addr(unsigned event, unsigned long va) { - if ( tb_init_done ) + if ( unlikely(tb_init_done) ) __trace_trap_one_addr(event, va); } @@ -32,14 +32,14 @@ void __trace_trap_two_addr(unsigned event, unsigned long va1, static inline void trace_trap_two_addr(unsigned event, unsigned long va1, unsigned long va2) { - if ( tb_init_done ) + if ( unlikely(tb_init_done) ) __trace_trap_two_addr(event, va1, va2); } void __trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte); static inline void trace_ptwr_emulation(unsigned long addr, l1_pgentry_t npte) { - if ( tb_init_done ) + if ( unlikely(tb_init_done) ) __trace_ptwr_emulation(addr, npte); } diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h index 486499816d..aad2196db3 100644 --- a/xen/include/public/hvm/params.h +++ b/xen/include/public/hvm/params.h @@ -81,6 +81,9 @@ #define HVMPTM_no_missed_ticks_pending 2 #define HVMPTM_one_missed_tick_pending 3 -#define HVM_NR_PARAMS 11 +/* Boolean: Enable virtual HPET (high-precision event timer)? (x86-only) */ +#define HVM_PARAM_HPET_ENABLED 11 + +#define HVM_NR_PARAMS 12 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h index 355eba5545..6ce1d0d485 100644 --- a/xen/include/public/io/ring.h +++ b/xen/include/public/io/ring.h @@ -27,6 +27,14 @@ #ifndef __XEN_PUBLIC_IO_RING_H__ #define __XEN_PUBLIC_IO_RING_H__ +#include "../xen-compat.h" + +#if __XEN_INTERFACE_VERSION__ < 0x00030208 +#define xen_mb() mb() +#define xen_rmb() rmb() +#define xen_wmb() wmb() +#endif + typedef unsigned int RING_IDX; /* Round a 32-bit unsigned constant down to the nearest power of two. */ @@ -211,12 +219,12 @@ typedef struct __name##_back_ring __name##_back_ring_t (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) #define RING_PUSH_REQUESTS(_r) do { \ - wmb(); /* back sees requests /before/ updated producer index */ \ + xen_wmb(); /* back sees requests /before/ updated producer index */ \ (_r)->sring->req_prod = (_r)->req_prod_pvt; \ } while (0) #define RING_PUSH_RESPONSES(_r) do { \ - wmb(); /* front sees responses /before/ updated producer index */ \ + xen_wmb(); /* front sees resps /before/ updated producer index */ \ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ } while (0) @@ -253,9 +261,9 @@ typedef struct __name##_back_ring __name##_back_ring_t #define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ RING_IDX __old = (_r)->sring->req_prod; \ RING_IDX __new = (_r)->req_prod_pvt; \ - wmb(); /* back sees requests /before/ updated producer index */ \ + xen_wmb(); /* back sees requests /before/ updated producer index */ \ (_r)->sring->req_prod = __new; \ - mb(); /* back sees new requests /before/ we check req_event */ \ + xen_mb(); /* back sees new requests /before/ we check req_event */ \ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ (RING_IDX)(__new - __old)); \ } while (0) @@ -263,9 +271,9 @@ typedef struct __name##_back_ring __name##_back_ring_t #define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ RING_IDX __old = (_r)->sring->rsp_prod; \ RING_IDX __new = (_r)->rsp_prod_pvt; \ - wmb(); /* front sees responses /before/ updated producer index */ \ + xen_wmb(); /* front sees resps /before/ updated producer index */ \ (_r)->sring->rsp_prod = __new; \ - mb(); /* front sees new responses /before/ we check rsp_event */ \ + xen_mb(); /* front sees new resps /before/ we check rsp_event */ \ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ (RING_IDX)(__new - __old)); \ } while (0) @@ -274,7 +282,7 @@ typedef struct __name##_back_ring __name##_back_ring_t (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ if (_work_to_do) break; \ (_r)->sring->req_event = (_r)->req_cons + 1; \ - mb(); \ + xen_mb(); \ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ } while (0) @@ -282,7 +290,7 @@ typedef struct __name##_back_ring __name##_back_ring_t (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ if (_work_to_do) break; \ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ - mb(); \ + xen_mb(); \ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ } while (0) diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h index 4cbb896342..21fe15ffb9 100644 --- a/xen/include/public/trace.h +++ b/xen/include/public/trace.h @@ -141,6 +141,14 @@ struct t_rec { * field, indexes into an array of struct t_rec's. */ struct t_buf { + /* Assume the data buffer size is X. X is generally not a power of 2. + * CONS and PROD are incremented modulo (2*X): + * 0 <= cons < 2*X + * 0 <= prod < 2*X + * This is done because addition modulo X breaks at 2^32 when X is not a + * power of 2: + * (((2^32 - 1) % X) + 1) % X != (2^32) % X + */ uint32_t cons; /* Offset of next item to be consumed by control tools. */ uint32_t prod; /* Offset of next item to be produced by Xen. */ /* Records follow immediately after the meta-data header. */ diff --git a/xen/include/public/xen-compat.h b/xen/include/public/xen-compat.h index c9f369f0e9..c2894990cd 100644 --- a/xen/include/public/xen-compat.h +++ b/xen/include/public/xen-compat.h @@ -27,7 +27,7 @@ #ifndef __XEN_PUBLIC_XEN_COMPAT_H__ #define __XEN_PUBLIC_XEN_COMPAT_H__ -#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030207 +#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030208 #if defined(__XEN__) || defined(__XEN_TOOLS__) /* Xen is built with matching headers and implements the latest interface. */ diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index c02ecd4dc3..6ab913a430 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -1,23 +1,10 @@ -#ifndef __LINUX_SMP_H -#define __LINUX_SMP_H - -/* - * Generic SMP support - * Alan Cox. <alan@redhat.com> - */ +#ifndef __XEN_SMP_H__ +#define __XEN_SMP_H__ #include <xen/config.h> - -#ifdef CONFIG_SMP - #include <asm/smp.h> /* - * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc. - * (defined in asm header): - */ - -/* * stops all CPUs but the current one: */ extern void smp_send_stop(void); @@ -66,38 +53,6 @@ extern int on_selected_cpus( */ void smp_prepare_boot_cpu(void); -#else - -/* - * These macros fold the SMP functionality into a single CPU system - */ - -#define smp_send_event_check_mask(m) ((void)0) -#define smp_send_event_check_cpu(p) ((void)0) -#define raw_smp_processor_id() 0 -#define hard_smp_processor_id() 0 -#define smp_call_function(func,info,retry,wait) ({ do {} while (0); 0; }) -#define num_booting_cpus() 1 -#define smp_prepare_boot_cpu() do {} while (0) - -static inline int on_selected_cpus( - cpumask_t selected, - void (*func) (void *info), - void *info, - int retry, - int wait) -{ - if ( cpu_isset(0, selected) ) - { - local_irq_disable(); - func(info); - local_irq_enable(); - } - return 0; -} - -#endif - /* * Call a function on all processors */ @@ -112,4 +67,8 @@ static inline int on_each_cpu( #define smp_processor_id() raw_smp_processor_id() -#endif +/* No Xen contexts can be preempted by CPU hotplug. */ +#define lock_cpu_hotplug() ((void)0) +#define unlock_cpu_hotplug() ((void)0) + +#endif /* __XEN_SMP_H__ */ diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index 9a66e0fb03..7734b3374d 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -10,8 +10,9 @@ #define PAGE_SCRUB_SOFTIRQ 5 #define TRACE_SOFTIRQ 6 #define RCU_SOFTIRQ 7 +#define STOPMACHINE_SOFTIRQ 8 -#define NR_COMMON_SOFTIRQS 8 +#define NR_COMMON_SOFTIRQS 9 #include <asm/softirq.h> diff --git a/xen/include/xen/stop_machine.h b/xen/include/xen/stop_machine.h new file mode 100644 index 0000000000..7d4506869f --- /dev/null +++ b/xen/include/xen/stop_machine.h @@ -0,0 +1,19 @@ +#ifndef __XEN_STOP_MACHINE_H__ +#define __XEN_STOP_MACHINE_H__ + +/** + * stop_machine_run: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr for the @fn() + * @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS). + * + * Description: This causes every other cpu to enter a safe point, with + * each of which disables interrupts, and finally interrupts are disabled + * on the current CPU. The result is that none is holding a spinlock + * or inside any other preempt-disabled region when @fn() runs. + * + * This can be thought of as a very heavy write lock, equivalent to + * grabbing every spinlock in the kernel. */ +int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu); + +#endif /* __XEN_STOP_MACHINE_H__ */ diff --git a/xen/include/xen/trace.h b/xen/include/xen/trace.h index 7635f2dbf6..c5ce88f7ca 100644 --- a/xen/include/xen/trace.h +++ b/xen/include/xen/trace.h @@ -39,7 +39,7 @@ void __trace_var(u32 event, int cycles, int extra, unsigned char *extra_data); static inline void trace_var(u32 event, int cycles, int extra, unsigned char *extra_data) { - if( unlikely(tb_init_done) ) + if ( unlikely(tb_init_done) ) __trace_var(event, cycles, extra, extra_data); } @@ -49,49 +49,64 @@ static inline void trace_var(u32 event, int cycles, int extra, trace_var(_e, 1, 0, NULL); \ } while ( 0 ) -#define TRACE_1D(_e,_d) \ +#define TRACE_1D(_e,d1) \ do { \ - u32 _d1; \ - _d1 = _d; \ - trace_var(_e, 1, sizeof(_d1), (unsigned char *)&_d1); \ + if ( unlikely(tb_init_done) ) \ + { \ + u32 _d[1]; \ + _d[0] = d1; \ + __trace_var(_e, 1, sizeof(*_d), (unsigned char *)_d); \ + } \ } while ( 0 ) #define TRACE_2D(_e,d1,d2) \ - do { \ - u32 _d[2]; \ - _d[0]=d1; \ - _d[1]=d2; \ - trace_var(_e, 1, sizeof(*_d)*2, (unsigned char *)_d); \ + do { \ + if ( unlikely(tb_init_done) ) \ + { \ + u32 _d[2]; \ + _d[0] = d1; \ + _d[1] = d2; \ + __trace_var(_e, 1, sizeof(*_d)*2, (unsigned char *)_d); \ + } \ } while ( 0 ) #define TRACE_3D(_e,d1,d2,d3) \ do { \ - u32 _d[3]; \ - _d[0]=d1; \ - _d[1]=d2; \ - _d[2]=d3; \ - trace_var(_e, 1, sizeof(*_d)*3, (unsigned char *)_d); \ + if ( unlikely(tb_init_done) ) \ + { \ + u32 _d[3]; \ + _d[0] = d1; \ + _d[1] = d2; \ + _d[2] = d3; \ + __trace_var(_e, 1, sizeof(*_d)*3, (unsigned char *)_d); \ + } \ } while ( 0 ) #define TRACE_4D(_e,d1,d2,d3,d4) \ do { \ - u32 _d[4]; \ - _d[0]=d1; \ - _d[1]=d2; \ - _d[2]=d3; \ - _d[3]=d4; \ - trace_var(_e, 1, sizeof(*_d)*4, (unsigned char *)_d); \ + if ( unlikely(tb_init_done) ) \ + { \ + u32 _d[4]; \ + _d[0] = d1; \ + _d[1] = d2; \ + _d[2] = d3; \ + _d[3] = d4; \ + __trace_var(_e, 1, sizeof(*_d)*4, (unsigned char *)_d); \ + } \ } while ( 0 ) #define TRACE_5D(_e,d1,d2,d3,d4,d5) \ - do { \ - u32 _d[5]; \ - _d[0]=d1; \ - _d[1]=d2; \ - _d[2]=d3; \ - _d[3]=d4; \ - _d[4]=d5; \ - trace_var(_e, 1, sizeof(*_d)*5, (unsigned char *)_d); \ + do { \ + if ( unlikely(tb_init_done) ) \ + { \ + u32 _d[5]; \ + _d[0] = d1; \ + _d[1] = d2; \ + _d[2] = d3; \ + _d[3] = d4; \ + _d[4] = d5; \ + __trace_var(_e, 1, sizeof(*_d)*5, (unsigned char *)_d); \ + } \ } while ( 0 ) #endif /* __XEN_TRACE_H__ */ |