diff options
author | 2007-10-10 21:45:01 +0000 | |
---|---|---|
committer | 2007-10-10 21:45:01 +0000 | |
commit | 75ea3a8a31550d1edfea7116bb3cd96ae6b20475 (patch) | |
tree | 6ab1b73b67e892685892331146aaea6eb100462e | |
parent | Fix CVE-2007-4573 for xen 2.6.20 (diff) | |
download | xen-75ea3a8a31550d1edfea7116bb3cd96ae6b20475.tar.gz xen-75ea3a8a31550d1edfea7116bb3cd96ae6b20475.tar.bz2 xen-75ea3a8a31550d1edfea7116bb3cd96ae6b20475.zip |
Releasing 2.6.20-3
svn path=/patches/; revision=51
18 files changed, 94231 insertions, 0 deletions
diff --git a/tags/2.6.20-3/00000_README b/tags/2.6.20-3/00000_README new file mode 100644 index 0000000..6838273 --- /dev/null +++ b/tags/2.6.20-3/00000_README @@ -0,0 +1,53 @@ +Xen Patches README +------------------ + +These patches are intended to be stacked on top of genpatches-base. + +Many of the patches included here are swiped from various sources which +use their own four digit patch numbering scheme, so we are stuck with five +digits to indiciate the source for easier tracking and re-syncing. + +Numbering +--------- + +0xxxx Gentoo, not related to Xen. (in case we pull something from extras) +1xxxx XenSource, upstream Xen patch for 2.6.18 +2xxxx Redhat, we use their Xen patch for >=2.6.20 +3xxxx Debian, we use their security fixes for 2.6.18 +5xxxx Gentoo, Xen and other fixes for Redhat and/or Debian patches. + +Patches +------- + +20950_linux-2.6.20.14-xen-3.1.0.patch + Main Xen patch + +20xxx-? + Various bug-fix patches from Redhat. + +30037_amd64-zero-extend-32bit-ptrace-xen.patch + [SECURITY] Zero extend all registers after ptrace in 32-bit entry path + (Xen). + See CVE-2007-4573 + +50001_make-install.patch + Handle make install in a semi-sane way that plays nice with + split domU/dom0 kernels. + +50002_always-enable-xen-genapic.patch + Compile fix for non-SMP (UP) kernels. Since UP support is broken in + upstream Xen I'm not sure if I trust it or not. :-P + +50003_console-tty-fix.patch + Steal tty1-63 as the upstream Xen release does so people don't get + any supprises. Redhat switched to using the special Xen tty device. + +50004_quirks-no-smp-fix.patch + Another compile fix for non-SMP (UP) kernels. + +50006_pgetable-build-fix.patch + Fix a function re-definition error when PAE is not enabled. + +50007_disable-highpte.patch + CONFIG_HIGHPTE can cause serious problems so lets save people's + sanity, avoid killing kittens, and end all war by disabling it. diff --git a/tags/2.6.20-3/20950_linux-2.6.20.14-xen-3.1.0.patch b/tags/2.6.20-3/20950_linux-2.6.20.14-xen-3.1.0.patch new file mode 100644 index 0000000..b46f4a4 --- /dev/null +++ b/tags/2.6.20-3/20950_linux-2.6.20.14-xen-3.1.0.patch @@ -0,0 +1,93230 @@ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/Kconfig +--- a/arch/i386/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -16,6 +16,7 @@ config X86_32 + + config GENERIC_TIME + bool ++ depends on !X86_XEN + default y + + config LOCKDEP_SUPPORT +@@ -107,6 +108,15 @@ config X86_PC + bool "PC-compatible" + help + Choose this option if your computer is a standard PC or compatible. ++ ++config X86_XEN ++ bool "Xen-compatible" ++ select X86_UP_APIC if !SMP && XEN_PRIVILEGED_GUEST ++ select X86_UP_IOAPIC if !SMP && XEN_PRIVILEGED_GUEST ++ select SWIOTLB ++ help ++ Choose this option if you plan to run this kernel on top of the ++ Xen Hypervisor. + + config X86_ELAN + bool "AMD Elan" +@@ -229,6 +239,7 @@ source "arch/i386/Kconfig.cpu" + + config HPET_TIMER + bool "HPET Timer Support" ++ depends on !X86_XEN + help + This enables the use of the HPET for the kernel's internal timer. + HPET is the next generation timer replacing legacy 8254s. +@@ -279,7 +290,7 @@ source "kernel/Kconfig.preempt" + + config X86_UP_APIC + bool "Local APIC support on uniprocessors" +- depends on !SMP && !(X86_VISWS || X86_VOYAGER || X86_GENERICARCH) ++ depends on !SMP && !(X86_VISWS || X86_VOYAGER || X86_GENERICARCH || XEN_UNPRIVILEGED_GUEST) + help + A local APIC (Advanced Programmable Interrupt Controller) is an + integrated interrupt controller in the CPU. If you have a single-CPU +@@ -304,12 +315,12 @@ config X86_UP_IOAPIC + + config X86_LOCAL_APIC + bool +- depends on X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER) || X86_GENERICARCH ++ depends on X86_UP_APIC || ((X86_VISWS || SMP) && !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)) || X86_GENERICARCH + default y + + config X86_IO_APIC + bool +- depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER)) || X86_GENERICARCH ++ depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)) || X86_GENERICARCH + default y + + config X86_VISWS_APIC +@@ -319,7 +330,7 @@ config X86_VISWS_APIC + + config X86_MCE + bool "Machine Check Exception" +- depends on !X86_VOYAGER ++ depends on !(X86_VOYAGER || X86_XEN) + ---help--- + Machine Check Exception support allows the processor to notify the + kernel if it detects a problem (e.g. overheating, component failure). +@@ -418,6 +429,7 @@ config X86_REBOOTFIXUPS + + config MICROCODE + tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" ++ depends on !XEN_UNPRIVILEGED_GUEST + select FW_LOADER + ---help--- + If you say Y here and also to "/dev file system support" in the +@@ -441,6 +453,7 @@ config MICROCODE_OLD_INTERFACE + + config X86_MSR + tristate "/dev/cpu/*/msr - Model-specific register support" ++ depends on !X86_XEN + help + This device gives privileged processes access to the x86 + Model-Specific Registers (MSRs). It is a character device with +@@ -455,6 +468,10 @@ config X86_CPUID + be executed on a specific processor. It is a character device + with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to + /dev/cpu/31/cpuid. ++ ++config SWIOTLB ++ bool ++ default n + + source "drivers/firmware/Kconfig" + +@@ -638,6 +655,7 @@ config HIGHPTE + + config MATH_EMULATION + bool "Math emulation" ++ depends on !X86_XEN + ---help--- + Linux can emulate a math coprocessor (used for floating point + operations) if you don't have one. 486DX and Pentium processors have +@@ -663,6 +681,8 @@ config MATH_EMULATION + + config MTRR + bool "MTRR (Memory Type Range Register) support" ++ depends on !XEN_UNPRIVILEGED_GUEST ++ default y if X86_XEN + ---help--- + On Intel P6 family processors (Pentium Pro, Pentium II and later) + the Memory Type Range Registers (MTRRs) may be used to control +@@ -697,7 +717,7 @@ config MTRR + + config EFI + bool "Boot from EFI support" +- depends on ACPI ++ depends on ACPI && !X86_XEN + default n + ---help--- + This enables the kernel to boot on EFI platforms using +@@ -715,7 +735,7 @@ config EFI + + config IRQBALANCE + bool "Enable kernel irq balancing" +- depends on SMP && X86_IO_APIC ++ depends on SMP && X86_IO_APIC && !X86_XEN + default y + help + The default yes will allow the kernel to do irq load balancing. +@@ -749,6 +769,7 @@ source kernel/Kconfig.hz + + config KEXEC + bool "kexec system call" ++ depends on !XEN_UNPRIVILEGED_GUEST + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot +@@ -866,6 +887,7 @@ config COMPAT_VDSO + bool "Compat VDSO support" + default y + depends on !PARAVIRT ++ depends on !X86_XEN + help + Map the VDSO to the predictable old-style address too. + ---help--- +@@ -882,18 +904,20 @@ config ARCH_ENABLE_MEMORY_HOTPLUG + depends on HIGHMEM + + menu "Power management options (ACPI, APM)" +- depends on !X86_VOYAGER +- ++ depends on !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST) ++ ++if !X86_XEN + source kernel/power/Kconfig ++endif + + source "drivers/acpi/Kconfig" + + menu "APM (Advanced Power Management) BIOS Support" +-depends on PM && !X86_VISWS ++depends on PM && !(X86_VISWS || X86_XEN) + + config APM + tristate "APM (Advanced Power Management) BIOS support" +- depends on PM ++ depends on PM && PM_LEGACY + ---help--- + APM is a BIOS specification for saving power using several different + techniques. This is mostly useful for battery powered laptops with +@@ -1078,6 +1102,7 @@ choice + + config PCI_GOBIOS + bool "BIOS" ++ depends on !X86_XEN + + config PCI_GOMMCONFIG + bool "MMConfig" +@@ -1085,6 +1110,13 @@ config PCI_GODIRECT + config PCI_GODIRECT + bool "Direct" + ++config PCI_GOXEN_FE ++ bool "Xen PCI Frontend" ++ depends on X86_XEN ++ help ++ The PCI device frontend driver allows the kernel to import arbitrary ++ PCI devices from a PCI backend to support PCI driver domains. ++ + config PCI_GOANY + bool "Any" + +@@ -1092,7 +1124,7 @@ endchoice + + config PCI_BIOS + bool +- depends on !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY) ++ depends on !(X86_VISWS || X86_XEN) && PCI && (PCI_GOBIOS || PCI_GOANY) + default y + + config PCI_DIRECT +@@ -1104,6 +1136,18 @@ config PCI_MMCONFIG + bool + depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY) + default y ++ ++config XEN_PCIDEV_FRONTEND ++ bool ++ depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY) ++ default y ++ ++config XEN_PCIDEV_FE_DEBUG ++ bool "Xen PCI Frontend Debugging" ++ depends on XEN_PCIDEV_FRONTEND ++ default n ++ help ++ Enables some debug statements within the PCI Frontend. + + source "drivers/pci/pcie/Kconfig" + +@@ -1115,7 +1159,7 @@ config ISA_DMA_API + + config ISA + bool "ISA support" +- depends on !(X86_VOYAGER || X86_VISWS) ++ depends on !(X86_VOYAGER || X86_VISWS || X86_XEN) + help + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff +@@ -1142,7 +1186,7 @@ source "drivers/eisa/Kconfig" + source "drivers/eisa/Kconfig" + + config MCA +- bool "MCA support" if !(X86_VISWS || X86_VOYAGER) ++ bool "MCA support" if !(X86_VISWS || X86_VOYAGER || X86_XEN) + default y if X86_VOYAGER + help + MicroChannel Architecture is found in some IBM PS/2 machines and +@@ -1218,6 +1262,8 @@ source "security/Kconfig" + + source "crypto/Kconfig" + ++source "drivers/xen/Kconfig" ++ + source "lib/Kconfig" + + # +@@ -1243,7 +1289,7 @@ config X86_SMP + + config X86_HT + bool +- depends on SMP && !(X86_VISWS || X86_VOYAGER) ++ depends on SMP && !(X86_VISWS || X86_VOYAGER || X86_XEN) + default y + + config X86_BIOS_REBOOT +@@ -1256,6 +1302,16 @@ config X86_TRAMPOLINE + depends on X86_SMP || (X86_VOYAGER && SMP) + default y + ++config X86_NO_TSS ++ bool ++ depends on X86_XEN ++ default y ++ ++config X86_NO_IDT ++ bool ++ depends on X86_XEN ++ default y ++ + config KTIME_SCALAR + bool + default y +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/Kconfig.cpu +--- a/arch/i386/Kconfig.cpu Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/Kconfig.cpu Wed Aug 08 16:25:28 2007 -0300 +@@ -267,7 +267,7 @@ config X86_PPRO_FENCE + + config X86_F00F_BUG + bool +- depends on M586MMX || M586TSC || M586 || M486 || M386 ++ depends on (M586MMX || M586TSC || M586 || M486 || M386) && !X86_NO_IDT + default y + + config X86_WP_WORKS_OK +@@ -327,5 +327,5 @@ config X86_OOSTORE + + config X86_TSC + bool +- depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ +- default y ++ depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ && !X86_XEN ++ default y +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/Kconfig.debug +--- a/arch/i386/Kconfig.debug Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/Kconfig.debug Wed Aug 08 16:25:28 2007 -0300 +@@ -79,6 +79,7 @@ config DOUBLEFAULT + config DOUBLEFAULT + default y + bool "Enable doublefault exception handler" if EMBEDDED ++ depends on !X86_NO_TSS + help + This option allows trapping of rare doublefault exceptions that + would otherwise cause a system to silently reboot. Disabling this +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/Makefile +--- a/arch/i386/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -60,6 +60,11 @@ AFLAGS += $(call as-instr,.cfi_startproc + + CFLAGS += $(cflags-y) + ++cppflags-$(CONFIG_XEN) += \ ++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) ++ ++CPPFLAGS += $(cppflags-y) ++ + # Default subarch .c files + mcore-y := mach-default + +@@ -82,6 +87,10 @@ mcore-$(CONFIG_X86_BIGSMP) := mach-defau + #Summit subarch support + mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit + mcore-$(CONFIG_X86_SUMMIT) := mach-default ++ ++# Xen subarch support ++mflags-$(CONFIG_X86_XEN) := -Iinclude/asm-i386/mach-xen ++mcore-$(CONFIG_X86_XEN) := mach-xen + + # generic subarchitecture + mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic +@@ -117,6 +126,19 @@ PHONY += zImage bzImage compressed zlilo + PHONY += zImage bzImage compressed zlilo bzlilo \ + zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install + ++ifdef CONFIG_XEN ++CPPFLAGS := -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS) ++head-y := arch/i386/kernel/head-xen.o arch/i386/kernel/init_task.o ++boot := arch/i386/boot-xen ++.PHONY: vmlinuz ++all: vmlinuz ++ ++vmlinuz: vmlinux ++ $(Q)$(MAKE) $(build)=$(boot) $@ ++ ++install: ++ $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@ ++else + all: bzImage + + # KBUILD_IMAGE specify target image being built +@@ -139,6 +161,7 @@ fdimage fdimage144 fdimage288 isoimage: + + install: + $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install ++endif + + archclean: + $(Q)$(MAKE) $(clean)=arch/i386/boot +@@ -157,3 +180,4 @@ CLEAN_FILES += arch/$(ARCH)/boot/fdimage + CLEAN_FILES += arch/$(ARCH)/boot/fdimage \ + arch/$(ARCH)/boot/image.iso \ + arch/$(ARCH)/boot/mtools.conf ++CLEAN_FILES += vmlinuz vmlinux-stripped +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/boot-xen/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/boot-xen/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,21 @@ ++ ++OBJCOPYFLAGS := -g --strip-unneeded ++ ++vmlinuz: vmlinux-stripped FORCE ++ $(call if_changed,gzip) ++ ++vmlinux-stripped: vmlinux FORCE ++ $(call if_changed,objcopy) ++ ++INSTALL_ROOT := $(patsubst %/boot,%,$(INSTALL_PATH)) ++ ++XINSTALL_NAME ?= $(KERNELRELEASE) ++install: ++ mkdir -p $(INSTALL_ROOT)/boot ++ ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(XENGUEST)$(INSTALL_SUFFIX) ++ rm -f $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) ++ install -m0644 vmlinuz $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) ++ install -m0644 vmlinux $(INSTALL_ROOT)/boot/vmlinux-syms-$(XINSTALL_NAME)$(INSTALL_SUFFIX) ++ install -m0664 .config $(INSTALL_ROOT)/boot/config-$(XINSTALL_NAME)$(INSTALL_SUFFIX) ++ install -m0664 System.map $(INSTALL_ROOT)/boot/System.map-$(XINSTALL_NAME)$(INSTALL_SUFFIX) ++ ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL)$(XENGUEST)$(INSTALL_SUFFIX) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/Makefile +--- a/arch/i386/kernel/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -47,6 +47,12 @@ EXTRA_AFLAGS := -traditional + + obj-$(CONFIG_SCx200) += scx200.o + ++ifdef CONFIG_XEN ++vsyscall_note := vsyscall-note-xen.o ++else ++vsyscall_note := vsyscall-note.o ++endif ++ + # vsyscall.o contains the vsyscall DSO images as __initdata. + # We must build both images before we can assemble it. + # Note: kbuild does not track this dependency due to usage of .incbin +@@ -68,7 +74,7 @@ SYSCFLAGS_vsyscall-int80.so = $(vsyscall + + $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ + $(obj)/vsyscall-%.so: $(src)/vsyscall.lds \ +- $(obj)/vsyscall-%.o $(obj)/vsyscall-note.o FORCE ++ $(obj)/vsyscall-%.o $(obj)/$(vsyscall_note) FORCE + $(call if_changed,syscall) + + # We also create a special relocatable object that should mirror the symbol +@@ -80,9 +86,21 @@ extra-y += vsyscall-syms.o + + SYSCFLAGS_vsyscall-syms.o = -r + $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \ +- $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE ++ $(obj)/vsyscall-sysenter.o $(obj)/$(vsyscall_note) FORCE + $(call if_changed,syscall) + + k8-y += ../../x86_64/kernel/k8.o + stacktrace-y += ../../x86_64/kernel/stacktrace.o + ++ifdef CONFIG_XEN ++include $(srctree)/scripts/Makefile.xen ++ ++obj-y += fixup.o ++microcode-$(subst m,y,$(CONFIG_MICROCODE)) := microcode-xen.o ++n-obj-xen := i8259.o timers/ reboot.o smpboot.o trampoline.o ++ ++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen)) ++obj-y := $(call cherrypickxen, $(obj-y)) ++extra-y := $(call cherrypickxen, $(extra-y)) ++%/head-xen.o %/head-xen.s: EXTRA_AFLAGS := ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/acpi/Makefile +--- a/arch/i386/kernel/acpi/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/acpi/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -7,4 +7,3 @@ ifneq ($(CONFIG_ACPI_PROCESSOR),) + ifneq ($(CONFIG_ACPI_PROCESSOR),) + obj-y += cstate.o processor.o + endif +- +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/acpi/boot.c +--- a/arch/i386/kernel/acpi/boot.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/acpi/boot.c Wed Aug 08 16:25:28 2007 -0300 +@@ -107,7 +107,7 @@ EXPORT_SYMBOL(x86_acpiid_to_apicid); + */ + enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC; + +-#ifdef CONFIG_X86_64 ++#if defined(CONFIG_X86_64) && !defined(CONFIG_XEN) + + /* rely on all ACPI tables being in the direct mapping */ + char *__acpi_map_table(unsigned long phys_addr, unsigned long size) +@@ -140,8 +140,10 @@ char *__acpi_map_table(unsigned long phy + unsigned long base, offset, mapped_size; + int idx; + ++#ifndef CONFIG_XEN + if (phys + size < 8 * 1024 * 1024) + return __va(phys); ++#endif + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; +@@ -611,7 +613,13 @@ acpi_scan_rsdp(unsigned long start, unsi + * RSDP signature. + */ + for (offset = 0; offset < length; offset += 16) { ++#ifdef CONFIG_XEN ++ unsigned long vstart = (unsigned long)isa_bus_to_virt(start); ++ ++ if (strncmp((char *)(vstart + offset), "RSD PTR ", sig_len)) ++#else + if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len)) ++#endif + continue; + return (start + offset); + } +@@ -724,7 +732,7 @@ static int __init acpi_parse_fadt(unsign + acpi_fadt.force_apic_physical_destination_mode = + fadt->force_apic_physical_destination_mode; + +-#ifdef CONFIG_X86_PM_TIMER ++#if defined(CONFIG_X86_PM_TIMER) && !defined(CONFIG_XEN) + /* detect the location of the ACPI PM Timer */ + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/apic-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/apic-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,223 @@ ++/* ++ * Local APIC handling, local APIC timers ++ * ++ * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com> ++ * ++ * Fixes ++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs; ++ * thanks to Eric Gilmore ++ * and Rolf G. Tews ++ * for testing these extensively. ++ * Maciej W. Rozycki : Various updates and fixes. ++ * Mikael Pettersson : Power Management for UP-APIC. ++ * Pavel Machek and ++ * Mikael Pettersson : PM converted to driver model. ++ */ ++ ++#include <linux/init.h> ++ ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/bootmem.h> ++#include <linux/smp_lock.h> ++#include <linux/interrupt.h> ++#include <linux/mc146818rtc.h> ++#include <linux/kernel_stat.h> ++#include <linux/sysdev.h> ++#include <linux/cpu.h> ++#include <linux/module.h> ++ ++#include <asm/atomic.h> ++#include <asm/smp.h> ++#include <asm/mtrr.h> ++#include <asm/mpspec.h> ++#include <asm/desc.h> ++#include <asm/arch_hooks.h> ++#include <asm/hpet.h> ++#include <asm/i8253.h> ++#include <asm/nmi.h> ++ ++#include <mach_apic.h> ++#include <mach_apicdef.h> ++#include <mach_ipi.h> ++ ++#include "io_ports.h" ++ ++#ifndef CONFIG_XEN ++/* ++ * cpu_mask that denotes the CPUs that needs timer interrupt coming in as ++ * IPIs in place of local APIC timers ++ */ ++static cpumask_t timer_bcast_ipi; ++#endif ++ ++/* ++ * Knob to control our willingness to enable the local APIC. ++ */ ++static int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ ++ ++static inline void lapic_disable(void) ++{ ++ enable_local_apic = -1; ++ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); ++} ++ ++static inline void lapic_enable(void) ++{ ++ enable_local_apic = 1; ++} ++ ++/* ++ * Debug level ++ */ ++int apic_verbosity; ++ ++static int modern_apic(void) ++{ ++#ifndef CONFIG_XEN ++ unsigned int lvr, version; ++ /* AMD systems use old APIC versions, so check the CPU */ ++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && ++ boot_cpu_data.x86 >= 0xf) ++ return 1; ++ lvr = apic_read(APIC_LVR); ++ version = GET_APIC_VERSION(lvr); ++ return version >= 0x14; ++#else ++ return 1; ++#endif ++} ++ ++/* ++ * 'what should we do if we get a hw irq event on an illegal vector'. ++ * each architecture has to answer this themselves. ++ */ ++void ack_bad_irq(unsigned int irq) ++{ ++ printk("unexpected IRQ trap at vector %02x\n", irq); ++ /* ++ * Currently unexpected vectors happen only on SMP and APIC. ++ * We _must_ ack these because every local APIC has only N ++ * irq slots per priority level, and a 'hanging, unacked' IRQ ++ * holds up an irq slot - in excessive cases (when multiple ++ * unexpected vectors occur) that might lock up the APIC ++ * completely. ++ * But only ack when the APIC is enabled -AK ++ */ ++ if (cpu_has_apic) ++ ack_APIC_irq(); ++} ++ ++#ifndef CONFIG_XEN ++void __init apic_intr_init(void) ++{ ++#ifdef CONFIG_SMP ++ smp_intr_init(); ++#endif ++ /* self generated IPI for local APIC timer */ ++ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); ++ ++ /* IPI vectors for APIC spurious and error interrupts */ ++ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); ++ set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); ++ ++ /* thermal monitor LVT interrupt */ ++#ifdef CONFIG_X86_MCE_P4THERMAL ++ set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); ++#endif ++} ++ ++/* Using APIC to generate smp_local_timer_interrupt? */ ++int using_apic_timer __read_mostly = 0; ++ ++static int enabled_via_apicbase; ++ ++void enable_NMI_through_LVT0 (void * dummy) ++{ ++ unsigned int v, ver; ++ ++ ver = apic_read(APIC_LVR); ++ ver = GET_APIC_VERSION(ver); ++ v = APIC_DM_NMI; /* unmask and set to NMI */ ++ if (!APIC_INTEGRATED(ver)) /* 82489DX */ ++ v |= APIC_LVT_LEVEL_TRIGGER; ++ apic_write_around(APIC_LVT0, v); ++} ++#endif /* !CONFIG_XEN */ ++ ++int get_physical_broadcast(void) ++{ ++ if (modern_apic()) ++ return 0xff; ++ else ++ return 0xf; ++} ++ ++#ifndef CONFIG_XEN ++#ifndef CONFIG_SMP ++static void up_apic_timer_interrupt_call(void) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* ++ * the NMI deadlock-detector uses this. ++ */ ++ per_cpu(irq_stat, cpu).apic_timer_irqs++; ++ ++ smp_local_timer_interrupt(); ++} ++#endif ++ ++void smp_send_timer_broadcast_ipi(void) ++{ ++ cpumask_t mask; ++ ++ cpus_and(mask, cpu_online_map, timer_bcast_ipi); ++ if (!cpus_empty(mask)) { ++#ifdef CONFIG_SMP ++ send_IPI_mask(mask, LOCAL_TIMER_VECTOR); ++#else ++ /* ++ * We can directly call the apic timer interrupt handler ++ * in UP case. Minus all irq related functions ++ */ ++ up_apic_timer_interrupt_call(); ++#endif ++ } ++} ++#endif ++ ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ return -EINVAL; ++} ++ ++/* ++ * This initializes the IO-APIC and APIC hardware if this is ++ * a UP kernel. ++ */ ++int __init APIC_init_uniprocessor (void) ++{ ++#ifdef CONFIG_X86_IO_APIC ++ if (smp_found_config) ++ if (!skip_ioapic_setup && nr_ioapics) ++ setup_IO_APIC(); ++#endif ++ ++ return 0; ++} ++ ++static int __init parse_lapic(char *arg) ++{ ++ lapic_enable(); ++ return 0; ++} ++early_param("lapic", parse_lapic); ++ ++static int __init parse_nolapic(char *arg) ++{ ++ lapic_disable(); ++ return 0; ++} ++early_param("nolapic", parse_nolapic); ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/asm-offsets.c +--- a/arch/i386/kernel/asm-offsets.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/asm-offsets.c Wed Aug 08 16:25:28 2007 -0300 +@@ -89,9 +89,14 @@ void foo(void) + OFFSET(pbe_orig_address, pbe, orig_address); + OFFSET(pbe_next, pbe, next); + ++#ifndef CONFIG_X86_NO_TSS + /* Offset from the sysenter stack to tss.esp0 */ +- DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) - ++ DEFINE(SYSENTER_stack_esp0, offsetof(struct tss_struct, esp0) - + sizeof(struct tss_struct)); ++#else ++ /* sysenter stack points directly to esp0 */ ++ DEFINE(SYSENTER_stack_esp0, 0); ++#endif + + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(VDSO_PRELINK, VDSO_PRELINK); +@@ -111,4 +116,10 @@ void foo(void) + OFFSET(PARAVIRT_iret, paravirt_ops, iret); + OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0); + #endif ++ ++ ++#ifdef CONFIG_XEN ++ BLANK(); ++ OFFSET(XEN_START_mfn_list, start_info, mfn_list); ++#endif + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/cpu/common.c +--- a/arch/i386/kernel/cpu/common.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/cpu/common.c Wed Aug 08 16:25:28 2007 -0300 +@@ -19,6 +19,10 @@ + #include <mach_apic.h> + #endif + #include <asm/pda.h> ++ ++#ifdef CONFIG_XEN ++#include <asm/hypervisor.h> ++#endif + + #include "cpu.h" + +@@ -601,6 +605,31 @@ void __init early_cpu_init(void) + #endif + } + ++/* We can't move load_gdt to asm/desc.h because it lacks make_lowmen_page_readonly() ++ definition, and as this is still the only user of load_gdt in xen. ++ ToDo: JQ ++ */ ++ ++#ifdef CONFIG_XEN ++#undef load_gdt ++static void __cpuinit load_gdt(struct Xgt_desc_struct *gdt_descr) ++{ ++ unsigned long frames[16]; ++ unsigned long va; ++ int f; ++ ++ for (va = gdt_descr->address, f = 0; ++ va < gdt_descr->address + gdt_descr->size; ++ va += PAGE_SIZE, f++) { ++ frames[f] = virt_to_mfn(va); ++ make_lowmem_page_readonly( ++ (void *)va, XENFEAT_writable_descriptor_tables); ++ } ++ if (HYPERVISOR_set_gdt(frames, gdt_descr->size / 8)) ++ BUG(); ++} ++#endif /* CONFIG_XEN */ ++ + /* Make sure %gs is initialized properly in idle threads */ + struct pt_regs * __devinit idle_regs(struct pt_regs *regs) + { +@@ -633,6 +662,10 @@ static __cpuinit int alloc_gdt(int cpu) + + memset(gdt, 0, PAGE_SIZE); + memset(pda, 0, sizeof(*pda)); ++#ifdef CONFIG_XEN ++ memcpy(gdt, cpu_gdt_table, GDT_SIZE); ++ cpu_gdt_descr->size = GDT_SIZE; ++#endif + } else { + /* GDT and PDA might already have been allocated if + this is a CPU hotplug re-insertion. */ +@@ -690,14 +723,18 @@ __cpuinit int init_gdt(int cpu, struct t + + BUG_ON(gdt == NULL || pda == NULL); + ++#ifndef CONFIG_XEN + /* + * Initialize the per-CPU GDT with the boot GDT, + * and set up the GDT descriptor: + */ + memcpy(gdt, cpu_gdt_table, GDT_SIZE); + cpu_gdt_descr->size = GDT_SIZE - 1; +- +- pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, ++#endif ++ ++ ++ if (cpu == 0) ++ pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, + (u32 *)&gdt[GDT_ENTRY_PDA].b, + (unsigned long)pda, sizeof(*pda) - 1, + 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ +@@ -724,7 +761,9 @@ void __cpuinit cpu_set_gdt(int cpu) + /* Common CPU init for both boot and secondary CPUs */ + static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) + { ++#ifndef CONFIG_X86_NO_TSS + struct tss_struct * t = &per_cpu(init_tss, cpu); ++#endif + struct thread_struct *thread = &curr->thread; + + if (cpu_test_and_set(cpu, cpu_initialized)) { +@@ -743,7 +782,9 @@ static void __cpuinit _cpu_init(int cpu, + set_in_cr4(X86_CR4_TSD); + } + ++#ifndef CONFIG_X86_NO_IDT + load_idt(&idt_descr); ++#endif + + /* + * Set up and load the per-CPU TSS and LDT +@@ -755,8 +796,10 @@ static void __cpuinit _cpu_init(int cpu, + enter_lazy_tlb(&init_mm, curr); + + load_esp0(t, thread); ++#ifndef CONFIG_X86_NO_TSS + set_tss_desc(cpu,t); + load_TR_desc(); ++#endif + load_LDT(&init_mm.context); + + #ifdef CONFIG_DOUBLEFAULT +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/cpu/mtrr/Makefile +--- a/arch/i386/kernel/cpu/mtrr/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/cpu/mtrr/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -1,3 +1,10 @@ obj-y := main.o if.o generic.o state.o + obj-y := main.o if.o generic.o state.o + obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o + ++ifdef CONFIG_XEN ++include $(srctree)/scripts/Makefile.xen ++n-obj-xen := generic.o state.o amd.o cyrix.o centaur.o ++ ++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen)) ++obj-y := $(call cherrypickxen, $(obj-y)) ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/cpu/mtrr/main-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/cpu/mtrr/main-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,198 @@ ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <linux/module.h> ++#include <linux/seq_file.h> ++#include <linux/mutex.h> ++#include <asm/uaccess.h> ++#include <linux/mutex.h> ++ ++#include <asm/mtrr.h> ++#include "mtrr.h" ++ ++static DEFINE_MUTEX(mtrr_mutex); ++ ++static void generic_get_mtrr(unsigned int reg, unsigned long *base, ++ unsigned long *size, mtrr_type * type) ++{ ++ struct xen_platform_op op; ++ ++ op.cmd = XENPF_read_memtype; ++ op.u.read_memtype.reg = reg; ++ (void)HYPERVISOR_platform_op(&op); ++ ++ *size = op.u.read_memtype.nr_mfns; ++ *base = op.u.read_memtype.mfn; ++ *type = op.u.read_memtype.type; ++} ++ ++struct mtrr_ops generic_mtrr_ops = { ++ .use_intel_if = 1, ++ .get = generic_get_mtrr, ++}; ++ ++struct mtrr_ops *mtrr_if = &generic_mtrr_ops; ++unsigned int num_var_ranges; ++unsigned int *usage_table; ++ ++/* This function returns the number of variable MTRRs */ ++static void __init set_num_var_ranges(void) ++{ ++ struct xen_platform_op op; ++ ++ for (num_var_ranges = 0; ; num_var_ranges++) { ++ op.cmd = XENPF_read_memtype; ++ op.u.read_memtype.reg = num_var_ranges; ++ if (HYPERVISOR_platform_op(&op) != 0) ++ break; ++ } ++} ++ ++static void __init init_table(void) ++{ ++ int i, max; ++ ++ max = num_var_ranges; ++ if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) ++ == NULL) { ++ printk(KERN_ERR "mtrr: could not allocate\n"); ++ return; ++ } ++ for (i = 0; i < max; i++) ++ usage_table[i] = 0; ++} ++ ++int mtrr_add_page(unsigned long base, unsigned long size, ++ unsigned int type, char increment) ++{ ++ int error; ++ struct xen_platform_op op; ++ ++ mutex_lock(&mtrr_mutex); ++ ++ op.cmd = XENPF_add_memtype; ++ op.u.add_memtype.mfn = base; ++ op.u.add_memtype.nr_mfns = size; ++ op.u.add_memtype.type = type; ++ error = HYPERVISOR_platform_op(&op); ++ if (error) { ++ mutex_unlock(&mtrr_mutex); ++ BUG_ON(error > 0); ++ return error; ++ } ++ ++ if (increment) ++ ++usage_table[op.u.add_memtype.reg]; ++ ++ mutex_unlock(&mtrr_mutex); ++ ++ return op.u.add_memtype.reg; ++} ++ ++static int mtrr_check(unsigned long base, unsigned long size) ++{ ++ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { ++ printk(KERN_WARNING ++ "mtrr: size and base must be multiples of 4 kiB\n"); ++ printk(KERN_DEBUG ++ "mtrr: size: 0x%lx base: 0x%lx\n", size, base); ++ dump_stack(); ++ return -1; ++ } ++ return 0; ++} ++ ++int ++mtrr_add(unsigned long base, unsigned long size, unsigned int type, ++ char increment) ++{ ++ if (mtrr_check(base, size)) ++ return -EINVAL; ++ return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, ++ increment); ++} ++ ++int mtrr_del_page(int reg, unsigned long base, unsigned long size) ++{ ++ unsigned i; ++ mtrr_type ltype; ++ unsigned long lbase, lsize; ++ int error = -EINVAL; ++ struct xen_platform_op op; ++ ++ mutex_lock(&mtrr_mutex); ++ ++ if (reg < 0) { ++ /* Search for existing MTRR */ ++ for (i = 0; i < num_var_ranges; ++i) { ++ mtrr_if->get(i, &lbase, &lsize, <ype); ++ if (lbase == base && lsize == size) { ++ reg = i; ++ break; ++ } ++ } ++ if (reg < 0) { ++ printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base, ++ size); ++ goto out; ++ } ++ } ++ if (usage_table[reg] < 1) { ++ printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); ++ goto out; ++ } ++ if (--usage_table[reg] < 1) { ++ op.cmd = XENPF_del_memtype; ++ op.u.del_memtype.handle = 0; ++ op.u.del_memtype.reg = reg; ++ error = HYPERVISOR_platform_op(&op); ++ if (error) { ++ BUG_ON(error > 0); ++ goto out; ++ } ++ } ++ error = reg; ++ out: ++ mutex_unlock(&mtrr_mutex); ++ return error; ++} ++ ++int ++mtrr_del(int reg, unsigned long base, unsigned long size) ++{ ++ if (mtrr_check(base, size)) ++ return -EINVAL; ++ return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); ++} ++ ++EXPORT_SYMBOL(mtrr_add); ++EXPORT_SYMBOL(mtrr_del); ++ ++void __init mtrr_bp_init(void) ++{ ++} ++ ++void mtrr_ap_init(void) ++{ ++} ++ ++static int __init mtrr_init(void) ++{ ++ struct cpuinfo_x86 *c = &boot_cpu_data; ++ ++ if (!is_initial_xendomain()) ++ return -ENODEV; ++ ++ if ((!cpu_has(c, X86_FEATURE_MTRR)) && ++ (!cpu_has(c, X86_FEATURE_K6_MTRR)) && ++ (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) && ++ (!cpu_has(c, X86_FEATURE_CENTAUR_MCR))) ++ return -ENODEV; ++ ++ set_num_var_ranges(); ++ init_table(); ++ ++ return 0; ++} ++ ++subsys_initcall(mtrr_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/crash.c +--- a/arch/i386/kernel/crash.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/crash.c Wed Aug 08 16:25:28 2007 -0300 +@@ -31,6 +31,7 @@ + /* This keeps a track of which one is crashing cpu. */ + static int crashing_cpu; + ++#ifndef CONFIG_XEN + #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) + static atomic_t waiting_for_crash_ipi; + +@@ -112,6 +113,7 @@ static void nmi_shootdown_cpus(void) + /* There are no cpus to shootdown */ + } + #endif ++#endif /* CONFIG_XEN */ + + void machine_crash_shutdown(struct pt_regs *regs) + { +@@ -128,10 +130,12 @@ void machine_crash_shutdown(struct pt_re + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = safe_smp_processor_id(); ++#ifndef CONFIG_XEN + nmi_shootdown_cpus(); + lapic_shutdown(); + #if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); + #endif ++#endif /* CONFIG_XEN */ + crash_save_cpu(regs, safe_smp_processor_id()); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/e820.c +--- a/arch/i386/kernel/e820.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/e820.c Wed Aug 08 16:25:28 2007 -0300 +@@ -15,10 +15,24 @@ + #include <asm/page.h> + #include <asm/e820.h> + ++#ifdef CONFIG_XEN ++#include <asm/hypervisor.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/memory.h> ++#include <xen/features.h> ++#include <xen/xencons.h> ++#endif ++ + #ifdef CONFIG_EFI + int efi_enabled = 0; + EXPORT_SYMBOL(efi_enabled); + #endif ++ ++#ifdef CONFIG_XEN ++struct e820map machine_e820; ++#endif ++static void __init ++e820_setup_gap(struct e820entry *e820, int nr_map); + + struct e820map e820; + struct change_member { +@@ -180,6 +194,12 @@ static void __init probe_roms(void) + unsigned char *rom; + int i; + ++#ifdef CONFIG_XEN ++ /* Nothing to do if not running in dom0. */ ++ if (!is_initial_xendomain()) ++ return; ++#endif ++ + /* video rom */ + upper = adapter_rom_resources[0].start; + for (start = video_rom_resource.start; start < upper; start += 2048) { +@@ -247,36 +267,54 @@ legacy_init_iomem_resources(struct resou + legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) + { + int i; ++ struct e820entry *map = e820.map; ++ int nr_map = e820.nr_map; ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++ struct xen_memory_map memmap; ++ ++ map = machine_e820.map; ++ memmap.nr_entries = E820MAX; ++ ++ set_xen_guest_handle(memmap.buffer, map); ++ ++ if(HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap)) ++ BUG(); ++ machine_e820.nr_map = memmap.nr_entries; ++ nr_map = memmap.nr_entries; ++ e820_setup_gap(map, memmap.nr_entries); ++#endif + + probe_roms(); +- for (i = 0; i < e820.nr_map; i++) { ++ for (i = 0; i < nr_map; i++) { + struct resource *res; + #ifndef CONFIG_RESOURCES_64BIT +- if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) ++ if (map[i].addr + map[i].size > 0x100000000ULL) + continue; + #endif + res = kzalloc(sizeof(struct resource), GFP_ATOMIC); +- switch (e820.map[i].type) { ++ switch (map[i].type) { + case E820_RAM: res->name = "System RAM"; break; + case E820_ACPI: res->name = "ACPI Tables"; break; + case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; + default: res->name = "reserved"; + } +- res->start = e820.map[i].addr; +- res->end = res->start + e820.map[i].size - 1; ++ res->start = map[i].addr; ++ res->end = res->start + map[i].size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, res)) { + kfree(res); + continue; + } +- if (e820.map[i].type == E820_RAM) { ++ if (map[i].type == E820_RAM) { + /* + * We don't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ ++#ifndef CONFIG_XEN + request_resource(res, code_resource); + request_resource(res, data_resource); ++#endif + #ifdef CONFIG_KEXEC + request_resource(res, &crashk_res); + #endif +@@ -295,6 +333,11 @@ static int __init request_standard_resou + int i; + + printk("Setting up standard PCI resources\n"); ++#ifdef CONFIG_XEN ++ /* Nothing to do if not running in dom0. */ ++ if (!is_initial_xendomain()) ++ return 0; ++#endif + if (efi_enabled) + efi_initialize_iomem_resources(&code_resource, &data_resource); + else +@@ -514,10 +557,13 @@ int __init sanitize_e820_map(struct e820 + */ + int __init copy_e820_map(struct e820entry * biosmap, int nr_map) + { ++#ifndef CONFIG_XEN + /* Only one memory region (or negative)? Ignore it */ + if (nr_map < 2) + return -1; +- ++#else ++ BUG_ON(nr_map < 1); ++#endif + do { + unsigned long long start = biosmap->addr; + unsigned long long size = biosmap->size; +@@ -529,6 +575,7 @@ int __init copy_e820_map(struct e820entr + if (start > end) + return -1; + ++#ifndef CONFIG_XEN + /* + * Some BIOSes claim RAM in the 640k - 1M region. + * Not right. Fix it up. +@@ -549,6 +596,7 @@ int __init copy_e820_map(struct e820entr + size = end - start; + } + } ++#endif + add_memory_region(start, size, type); + } while (biosmap++,--nr_map); + return 0; +@@ -653,6 +701,15 @@ void __init register_bootmem_low_pages(u + */ + last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); + ++#ifdef CONFIG_XEN ++ /* ++ * Truncate to the number of actual pages currently ++ * present. ++ */ ++ if (last_pfn > xen_start_info->nr_pages) ++ last_pfn = xen_start_info->nr_pages; ++#endif ++ + if (last_pfn > max_low_pfn) + last_pfn = max_low_pfn; + +@@ -668,7 +725,12 @@ void __init register_bootmem_low_pages(u + } + } + +-void __init e820_register_memory(void) ++/* ++ * Locate a unused range of the physical address space below 4G which ++ * can be used for PCI mappings. ++ */ ++static void __init ++e820_setup_gap(struct e820entry *e820, int nr_map) + { + unsigned long gapstart, gapsize, round; + unsigned long long last; +@@ -681,10 +743,10 @@ void __init e820_register_memory(void) + last = 0x100000000ull; + gapstart = 0x10000000; + gapsize = 0x400000; +- i = e820.nr_map; ++ i = nr_map; + while (--i >= 0) { +- unsigned long long start = e820.map[i].addr; +- unsigned long long end = start + e820.map[i].size; ++ unsigned long long start = e820[i].addr; ++ unsigned long long end = start + e820[i].size; + + /* + * Since "last" is at most 4GB, we know we'll +@@ -714,6 +776,13 @@ void __init e820_register_memory(void) + + printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", + pci_mem_start, gapstart, gapsize); ++} ++ ++void __init e820_register_memory(void) ++{ ++#ifndef CONFIG_XEN ++ e820_setup_gap(e820.map, e820.nr_map); ++#endif + } + + void __init print_memory_map(char *who) +@@ -784,7 +853,7 @@ static __init __always_inline void efi_l + + void __init limit_regions(unsigned long long size) + { +- unsigned long long current_addr; ++ unsigned long long current_addr = 0; + int i; + + print_memory_map("limit_regions start"); +@@ -813,6 +882,19 @@ void __init limit_regions(unsigned long + print_memory_map("limit_regions endfor"); + return; + } ++#ifdef CONFIG_XEN ++ if (i==e820.nr_map && current_addr < size) { ++ /* ++ * The e820 map finished before our requested size so ++ * extend the final entry to the requested address. ++ */ ++ --i; ++ if (e820.map[i].type == E820_RAM) ++ e820.map[i].size -= current_addr - size; ++ else ++ add_memory_region(current_addr, size - current_addr, E820_RAM); ++ } ++#endif + print_memory_map("limit_regions endfunc"); + } + +@@ -828,8 +910,15 @@ e820_all_mapped(unsigned long s, unsigne + u64 start = s; + u64 end = e; + int i; ++#ifndef CONFIG_XEN + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; ++#else ++ if (!is_initial_xendomain()) ++ return 0; ++ for (i = 0; i < machine_e820.nr_map; ++i) { ++ const struct e820entry *ei = &machine_e820.map[i]; ++#endif + if (type && ei->type != type) + continue; + /* is the region (part) in overlap with the current region ?*/ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/entry-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/entry-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1264 @@ ++/* ++ * linux/arch/i386/entry.S ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ */ ++ ++/* ++ * entry.S contains the system-call and fault low-level handling routines. ++ * This also contains the timer-interrupt handler, as well as all interrupts ++ * and faults that can result in a task-switch. ++ * ++ * NOTE: This code handles signal-recognition, which happens every time ++ * after a timer-interrupt and after each system call. ++ * ++ * I changed all the .align's to 4 (16 byte alignment), as that's faster ++ * on a 486. ++ * ++ * Stack layout in 'ret_from_system_call': ++ * ptrace needs to have all regs on the stack. ++ * if the order here is changed, it needs to be ++ * updated in fork.c:copy_process, signal.c:do_signal, ++ * ptrace.c and ptrace.h ++ * ++ * 0(%esp) - %ebx ++ * 4(%esp) - %ecx ++ * 8(%esp) - %edx ++ * C(%esp) - %esi ++ * 10(%esp) - %edi ++ * 14(%esp) - %ebp ++ * 18(%esp) - %eax ++ * 1C(%esp) - %ds ++ * 20(%esp) - %es ++ * 24(%esp) - %gs ++ * 28(%esp) - orig_eax ++ * 2C(%esp) - %eip ++ * 30(%esp) - %cs ++ * 34(%esp) - %eflags ++ * 38(%esp) - %oldesp ++ * 3C(%esp) - %oldss ++ * ++ * "current" is in register %ebx during any slow entries. ++ */ ++ ++#include <linux/linkage.h> ++#include <asm/thread_info.h> ++#include <asm/irqflags.h> ++#include <asm/errno.h> ++#include <asm/segment.h> ++#include <asm/smp.h> ++#include <asm/page.h> ++#include <asm/desc.h> ++#include <asm/percpu.h> ++#include <asm/dwarf2.h> ++#include "irq_vectors.h" ++#include <xen/interface/xen.h> ++ ++/* ++ * We use macros for low-level operations which need to be overridden ++ * for paravirtualization. The following will never clobber any registers: ++ * INTERRUPT_RETURN (aka. "iret") ++ * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax") ++ * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit"). ++ * ++ * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must ++ * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY). ++ * Allowing a register to be clobbered can shrink the paravirt replacement ++ * enough to patch inline, increasing performance. ++ */ ++ ++#define nr_syscalls ((syscall_table_size)/4) ++ ++CF_MASK = 0x00000001 ++TF_MASK = 0x00000100 ++IF_MASK = 0x00000200 ++DF_MASK = 0x00000400 ++NT_MASK = 0x00004000 ++VM_MASK = 0x00020000 ++/* Pseudo-eflags. */ ++NMI_MASK = 0x80000000 ++ ++#ifdef CONFIG_XEN ++/* Offsets into shared_info_t. */ ++#define evtchn_upcall_pending /* 0 */ ++#define evtchn_upcall_mask 1 ++ ++#define sizeof_vcpu_shift 6 ++ ++#ifdef CONFIG_SMP ++#define GET_VCPU_INFO movl %gs:PDA_cpu,%esi ; \ ++ shl $sizeof_vcpu_shift,%esi ; \ ++ addl HYPERVISOR_shared_info,%esi ++#else ++#define GET_VCPU_INFO movl HYPERVISOR_shared_info,%esi ++#endif ++ ++#define __DISABLE_INTERRUPTS movb $1,evtchn_upcall_mask(%esi) ++#define __ENABLE_INTERRUPTS movb $0,evtchn_upcall_mask(%esi) ++#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi) ++#endif ++ ++#ifdef CONFIG_PREEMPT ++#define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF ++#else ++#define preempt_stop(clobbers) ++#define resume_kernel restore_nocheck ++#endif ++ ++.macro TRACE_IRQS_IRET ++#ifdef CONFIG_TRACE_IRQFLAGS ++ testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off? ++ jz 1f ++ TRACE_IRQS_ON ++1: ++#endif ++.endm ++ ++#ifdef CONFIG_VM86 ++#define resume_userspace_sig check_userspace ++#else ++#define resume_userspace_sig resume_userspace ++#endif ++ ++#define SAVE_ALL \ ++ cld; \ ++ pushl %gs; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ /*CFI_REL_OFFSET gs, 0;*/\ ++ pushl %es; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ /*CFI_REL_OFFSET es, 0;*/\ ++ pushl %ds; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ /*CFI_REL_OFFSET ds, 0;*/\ ++ pushl %eax; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET eax, 0;\ ++ pushl %ebp; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET ebp, 0;\ ++ pushl %edi; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET edi, 0;\ ++ pushl %esi; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET esi, 0;\ ++ pushl %edx; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET edx, 0;\ ++ pushl %ecx; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET ecx, 0;\ ++ pushl %ebx; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ CFI_REL_OFFSET ebx, 0;\ ++ movl $(__USER_DS), %edx; \ ++ movl %edx, %ds; \ ++ movl %edx, %es; \ ++ movl $(__KERNEL_PDA), %edx; \ ++ movl %edx, %gs ++ ++#define RESTORE_INT_REGS \ ++ popl %ebx; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE ebx;\ ++ popl %ecx; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE ecx;\ ++ popl %edx; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE edx;\ ++ popl %esi; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE esi;\ ++ popl %edi; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE edi;\ ++ popl %ebp; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE ebp;\ ++ popl %eax; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ CFI_RESTORE eax ++ ++#define RESTORE_REGS \ ++ RESTORE_INT_REGS; \ ++1: popl %ds; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ /*CFI_RESTORE ds;*/\ ++2: popl %es; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ /*CFI_RESTORE es;*/\ ++3: popl %gs; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ /*CFI_RESTORE gs;*/\ ++.pushsection .fixup,"ax"; \ ++4: movl $0,(%esp); \ ++ jmp 1b; \ ++5: movl $0,(%esp); \ ++ jmp 2b; \ ++6: movl $0,(%esp); \ ++ jmp 3b; \ ++.section __ex_table,"a";\ ++ .align 4; \ ++ .long 1b,4b; \ ++ .long 2b,5b; \ ++ .long 3b,6b; \ ++.popsection ++ ++#define RING0_INT_FRAME \ ++ CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ ++ CFI_DEF_CFA esp, 3*4;\ ++ /*CFI_OFFSET cs, -2*4;*/\ ++ CFI_OFFSET eip, -3*4 ++ ++#define RING0_EC_FRAME \ ++ CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ ++ CFI_DEF_CFA esp, 4*4;\ ++ /*CFI_OFFSET cs, -2*4;*/\ ++ CFI_OFFSET eip, -3*4 ++ ++#define RING0_PTREGS_FRAME \ ++ CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ ++ CFI_DEF_CFA esp, PT_OLDESP-PT_EBX;\ ++ /*CFI_OFFSET cs, PT_CS-PT_OLDESP;*/\ ++ CFI_OFFSET eip, PT_EIP-PT_OLDESP;\ ++ /*CFI_OFFSET es, PT_ES-PT_OLDESP;*/\ ++ /*CFI_OFFSET ds, PT_DS-PT_OLDESP;*/\ ++ CFI_OFFSET eax, PT_EAX-PT_OLDESP;\ ++ CFI_OFFSET ebp, PT_EBP-PT_OLDESP;\ ++ CFI_OFFSET edi, PT_EDI-PT_OLDESP;\ ++ CFI_OFFSET esi, PT_ESI-PT_OLDESP;\ ++ CFI_OFFSET edx, PT_EDX-PT_OLDESP;\ ++ CFI_OFFSET ecx, PT_ECX-PT_OLDESP;\ ++ CFI_OFFSET ebx, PT_EBX-PT_OLDESP ++ ++ENTRY(ret_from_fork) ++ CFI_STARTPROC ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ call schedule_tail ++ GET_THREAD_INFO(%ebp) ++ popl %eax ++ CFI_ADJUST_CFA_OFFSET -4 ++ pushl $0x0202 # Reset kernel eflags ++ CFI_ADJUST_CFA_OFFSET 4 ++ popfl ++ CFI_ADJUST_CFA_OFFSET -4 ++ jmp syscall_exit ++ CFI_ENDPROC ++ ++/* ++ * Return to user mode is not as complex as all this looks, ++ * but we want the default path for a system call return to ++ * go as quickly as possible which is why some of this is ++ * less clear than it otherwise should be. ++ */ ++ ++ # userspace resumption stub bypassing syscall exit tracing ++ ALIGN ++ RING0_PTREGS_FRAME ++ret_from_exception: ++ preempt_stop(CLBR_ANY) ++ret_from_intr: ++ GET_THREAD_INFO(%ebp) ++check_userspace: ++ movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS ++ movb PT_CS(%esp), %al ++ andl $(VM_MASK | SEGMENT_RPL_MASK), %eax ++ cmpl $USER_RPL, %eax ++ jb resume_kernel # not returning to v8086 or userspace ++ ++ENTRY(resume_userspace) ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt ++ # setting need_resched or sigpending ++ # between sampling and the iret ++ movl TI_flags(%ebp), %ecx ++ andl $_TIF_WORK_MASK, %ecx # is there any work to be done on ++ # int/exception return? ++ jne work_pending ++ jmp restore_all ++ ++#ifdef CONFIG_PREEMPT ++ENTRY(resume_kernel) ++ DISABLE_INTERRUPTS(CLBR_ANY) ++ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? ++ jnz restore_nocheck ++need_resched: ++ movl TI_flags(%ebp), %ecx # need_resched set ? ++ testb $_TIF_NEED_RESCHED, %cl ++ jz restore_all ++ testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off (exception path) ? ++ jz restore_all ++ call preempt_schedule_irq ++ jmp need_resched ++#endif ++ CFI_ENDPROC ++ ++/* SYSENTER_RETURN points to after the "sysenter" instruction in ++ the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */ ++ ++ # sysenter call handler stub ++ENTRY(sysenter_entry) ++ CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME ++ CFI_DEF_CFA esp, 0 ++ CFI_REGISTER esp, ebp ++ movl SYSENTER_stack_esp0(%esp),%esp ++sysenter_past_esp: ++ /* ++ * No need to follow this irqs on/off section: the syscall ++ * disabled irqs and here we enable it straight after entry: ++ */ ++ ENABLE_INTERRUPTS(CLBR_NONE) ++ pushl $(__USER_DS) ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET ss, 0*/ ++ pushl %ebp ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET esp, 0 ++ pushfl ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $(__USER_CS) ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET cs, 0*/ ++#ifndef CONFIG_COMPAT_VDSO ++ /* ++ * Push current_thread_info()->sysenter_return to the stack. ++ * A tiny bit of offset fixup is necessary - 4*4 means the 4 words ++ * pushed above; +8 corresponds to copy_thread's esp0 setting. ++ */ ++ pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) ++#else ++ pushl $SYSENTER_RETURN ++#endif ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET eip, 0 ++ ++/* ++ * Load the potential sixth argument from user stack. ++ * Careful about security. ++ */ ++ cmpl $__PAGE_OFFSET-3,%ebp ++ jae syscall_fault ++1: movl (%ebp),%ebp ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,syscall_fault ++.previous ++ ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ GET_THREAD_INFO(%ebp) ++ ++ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ ++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) ++ jnz syscall_trace_entry ++ cmpl $(nr_syscalls), %eax ++ jae syscall_badsys ++ call *sys_call_table(,%eax,4) ++ movl %eax,PT_EAX(%esp) ++ DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX) ++ TRACE_IRQS_OFF ++ movl TI_flags(%ebp), %ecx ++ testw $_TIF_ALLWORK_MASK, %cx ++ jne syscall_exit_work ++/* if something modifies registers it must also disable sysexit */ ++ movl PT_EIP(%esp), %edx ++ movl PT_OLDESP(%esp), %ecx ++ xorl %ebp,%ebp ++ TRACE_IRQS_ON ++1: mov PT_GS(%esp), %gs ++#ifdef CONFIG_XEN ++ __ENABLE_INTERRUPTS ++sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ ++ __TEST_PENDING ++ jnz 14f # process more events if necessary... ++ movl PT_ESI(%esp), %esi ++ sysexit ++14: __DISABLE_INTERRUPTS ++ TRACE_IRQS_OFF ++sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ ++ push %esp ++ CFI_ADJUST_CFA_OFFSET 4 ++ call evtchn_do_upcall ++ add $4,%esp ++ CFI_ADJUST_CFA_OFFSET -4 ++ jmp ret_from_intr ++#else ++ ENABLE_INTERRUPTS_SYSEXIT ++#endif /* !CONFIG_XEN */ ++ CFI_ENDPROC ++.pushsection .fixup,"ax" ++2: movl $0,PT_GS(%esp) ++ jmp 1b ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,2b ++.popsection ++ ++ # system call handler stub ++ENTRY(system_call) ++ RING0_INT_FRAME # can't unwind into user space anyway ++ pushl %eax # save orig_eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ GET_THREAD_INFO(%ebp) ++ testl $TF_MASK,PT_EFLAGS(%esp) ++ jz no_singlestep ++ orl $_TIF_SINGLESTEP,TI_flags(%ebp) ++no_singlestep: ++ # system call tracing in operation / emulation ++ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ ++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) ++ jnz syscall_trace_entry ++ cmpl $(nr_syscalls), %eax ++ jae syscall_badsys ++syscall_call: ++ call *sys_call_table(,%eax,4) ++ movl %eax,PT_EAX(%esp) # store the return value ++syscall_exit: ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt ++ # setting need_resched or sigpending ++ # between sampling and the iret ++ TRACE_IRQS_OFF ++ movl TI_flags(%ebp), %ecx ++ testw $_TIF_ALLWORK_MASK, %cx # current->work ++ jne syscall_exit_work ++ ++restore_all: ++#ifndef CONFIG_XEN ++ movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS ++ # Warning: PT_OLDSS(%esp) contains the wrong/random values if we ++ # are returning to the kernel. ++ # See comments in process.c:copy_thread() for details. ++ movb PT_OLDSS(%esp), %ah ++ movb PT_CS(%esp), %al ++ andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax ++ cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax ++ CFI_REMEMBER_STATE ++ je ldt_ss # returning to user-space with LDT SS ++restore_nocheck: ++#else ++restore_nocheck: ++ movl PT_EFLAGS(%esp), %eax ++ testl $(VM_MASK|NMI_MASK), %eax ++ CFI_REMEMBER_STATE ++ jnz hypervisor_iret ++ shr $9, %eax # EAX[0] == IRET_EFLAGS.IF ++ GET_VCPU_INFO ++ andb evtchn_upcall_mask(%esi),%al ++ andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask ++ CFI_REMEMBER_STATE ++ jnz restore_all_enable_events # != 0 => enable event delivery ++ CFI_REMEMBER_STATE ++#endif ++ TRACE_IRQS_IRET ++restore_nocheck_notrace: ++ RESTORE_REGS ++ addl $4, %esp # skip orig_eax/error_code ++ CFI_ADJUST_CFA_OFFSET -4 ++1: INTERRUPT_RETURN ++.section .fixup,"ax" ++iret_exc: ++#ifndef CONFIG_XEN ++ TRACE_IRQS_ON ++ ENABLE_INTERRUPTS(CLBR_NONE) ++#endif ++ pushl $0 # no error code ++ pushl $do_iret_error ++ jmp error_code ++.previous ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,iret_exc ++.previous ++ ++ CFI_RESTORE_STATE ++#ifndef CONFIG_XEN ++ldt_ss: ++ larl PT_OLDSS(%esp), %eax ++ jnz restore_nocheck ++ testl $0x00400000, %eax # returning to 32bit stack? ++ jnz restore_nocheck # allright, normal return ++ ++#ifdef CONFIG_PARAVIRT ++ /* ++ * The kernel can't run on a non-flat stack if paravirt mode ++ * is active. Rather than try to fixup the high bits of ++ * ESP, bypass this code entirely. This may break DOSemu ++ * and/or Wine support in a paravirt VM, although the option ++ * is still available to implement the setting of the high ++ * 16-bits in the INTERRUPT_RETURN paravirt-op. ++ */ ++ cmpl $0, paravirt_ops+PARAVIRT_enabled ++ jne restore_nocheck ++#endif ++ ++ /* If returning to userspace with 16bit stack, ++ * try to fix the higher word of ESP, as the CPU ++ * won't restore it. ++ * This is an "official" bug of all the x86-compatible ++ * CPUs, which we can try to work around to make ++ * dosemu and wine happy. */ ++ movl PT_OLDESP(%esp), %eax ++ movl %esp, %edx ++ call patch_espfix_desc ++ pushl $__ESPFIX_SS ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ DISABLE_INTERRUPTS(CLBR_EAX) ++ TRACE_IRQS_OFF ++ lss (%esp), %esp ++ CFI_ADJUST_CFA_OFFSET -8 ++ jmp restore_nocheck ++#else ++ ALIGN ++restore_all_enable_events: ++ TRACE_IRQS_ON ++ __ENABLE_INTERRUPTS ++scrit: /**** START OF CRITICAL REGION ****/ ++ __TEST_PENDING ++ jnz 14f # process more events if necessary... ++ RESTORE_REGS ++ addl $4, %esp ++ CFI_ADJUST_CFA_OFFSET -4 ++1: iret ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,iret_exc ++.previous ++14: __DISABLE_INTERRUPTS ++ TRACE_IRQS_OFF ++ jmp 11f ++ecrit: /**** END OF CRITICAL REGION ****/ ++ ++ CFI_RESTORE_STATE ++hypervisor_iret: ++ andl $~NMI_MASK, PT_EFLAGS(%esp) ++ RESTORE_REGS ++ addl $4, %esp ++ CFI_ADJUST_CFA_OFFSET -4 ++ jmp hypercall_page + (__HYPERVISOR_iret * 32) ++#endif ++ CFI_ENDPROC ++ ++ # perform work that needs to be done immediately before resumption ++ ALIGN ++ RING0_PTREGS_FRAME # can't unwind into user space anyway ++work_pending: ++ testb $_TIF_NEED_RESCHED, %cl ++ jz work_notifysig ++work_resched: ++ call schedule ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt ++ # setting need_resched or sigpending ++ # between sampling and the iret ++ TRACE_IRQS_OFF ++ movl TI_flags(%ebp), %ecx ++ andl $_TIF_WORK_MASK, %ecx # is there any work to be done other ++ # than syscall tracing? ++ jz restore_all ++ testb $_TIF_NEED_RESCHED, %cl ++ jnz work_resched ++ ++work_notifysig: # deal with pending signals and ++ # notify-resume requests ++#ifdef CONFIG_VM86 ++ testl $VM_MASK, PT_EFLAGS(%esp) ++ movl %esp, %eax ++ jne work_notifysig_v86 # returning to kernel-space or ++ # vm86-space ++ xorl %edx, %edx ++ call do_notify_resume ++ jmp resume_userspace_sig ++ ++ ALIGN ++work_notifysig_v86: ++ pushl %ecx # save ti_flags for do_notify_resume ++ CFI_ADJUST_CFA_OFFSET 4 ++ call save_v86_state # %eax contains pt_regs pointer ++ popl %ecx ++ CFI_ADJUST_CFA_OFFSET -4 ++ movl %eax, %esp ++#else ++ movl %esp, %eax ++#endif ++ xorl %edx, %edx ++ call do_notify_resume ++ jmp resume_userspace_sig ++ ++ # perform syscall exit tracing ++ ALIGN ++syscall_trace_entry: ++ movl $-ENOSYS,PT_EAX(%esp) ++ movl %esp, %eax ++ xorl %edx,%edx ++ call do_syscall_trace ++ cmpl $0, %eax ++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, ++ # so must skip actual syscall ++ movl PT_ORIG_EAX(%esp), %eax ++ cmpl $(nr_syscalls), %eax ++ jnae syscall_call ++ jmp syscall_exit ++ ++ # perform syscall exit tracing ++ ALIGN ++syscall_exit_work: ++ testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl ++ jz work_pending ++ TRACE_IRQS_ON ++ ENABLE_INTERRUPTS(CLBR_ANY) # could let do_syscall_trace() call ++ # schedule() instead ++ movl %esp, %eax ++ movl $1, %edx ++ call do_syscall_trace ++ jmp resume_userspace ++ CFI_ENDPROC ++ ++ RING0_INT_FRAME # can't unwind into user space anyway ++syscall_fault: ++ pushl %eax # save orig_eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ GET_THREAD_INFO(%ebp) ++ movl $-EFAULT,PT_EAX(%esp) ++ jmp resume_userspace ++ ++syscall_badsys: ++ movl $-ENOSYS,PT_EAX(%esp) ++ jmp resume_userspace ++ CFI_ENDPROC ++ ++#ifndef CONFIG_XEN ++#define FIXUP_ESPFIX_STACK \ ++ /* since we are on a wrong stack, we cant make it a C code :( */ \ ++ movl %gs:PDA_cpu, %ebx; \ ++ PER_CPU(cpu_gdt_descr, %ebx); \ ++ movl GDS_address(%ebx), %ebx; \ ++ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ ++ addl %esp, %eax; \ ++ pushl $__KERNEL_DS; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ pushl %eax; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ lss (%esp), %esp; \ ++ CFI_ADJUST_CFA_OFFSET -8; ++#define UNWIND_ESPFIX_STACK \ ++ movl %ss, %eax; \ ++ /* see if on espfix stack */ \ ++ cmpw $__ESPFIX_SS, %ax; \ ++ jne 27f; \ ++ movl $__KERNEL_DS, %eax; \ ++ movl %eax, %ds; \ ++ movl %eax, %es; \ ++ /* switch to normal stack */ \ ++ FIXUP_ESPFIX_STACK; \ ++27:; ++ ++/* ++ * Build the entry stubs and pointer table with ++ * some assembler magic. ++ */ ++.data ++ENTRY(interrupt) ++.text ++ ++vector=0 ++ENTRY(irq_entries_start) ++ RING0_INT_FRAME ++.rept NR_IRQS ++ ALIGN ++ .if vector ++ CFI_ADJUST_CFA_OFFSET -4 ++ .endif ++1: pushl $~(vector) ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp common_interrupt ++.data ++ .long 1b ++.text ++vector=vector+1 ++.endr ++ ++/* ++ * the CPU automatically disables interrupts when executing an IRQ vector, ++ * so IRQ-flags tracing has to follow that: ++ */ ++ ALIGN ++common_interrupt: ++ SAVE_ALL ++ TRACE_IRQS_OFF ++ movl %esp,%eax ++ call do_IRQ ++ jmp ret_from_intr ++ CFI_ENDPROC ++ ++#define BUILD_INTERRUPT(name, nr) \ ++ENTRY(name) \ ++ RING0_INT_FRAME; \ ++ pushl $~(nr); \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ SAVE_ALL; \ ++ TRACE_IRQS_OFF \ ++ movl %esp,%eax; \ ++ call smp_/**/name; \ ++ jmp ret_from_intr; \ ++ CFI_ENDPROC ++ ++/* The include is where all of the SMP etc. interrupts come from */ ++#include "entry_arch.h" ++#else ++#define UNWIND_ESPFIX_STACK ++#endif ++ ++KPROBE_ENTRY(page_fault) ++ RING0_EC_FRAME ++ pushl $do_page_fault ++ CFI_ADJUST_CFA_OFFSET 4 ++ ALIGN ++error_code: ++ /* the function address is in %gs's slot on the stack */ ++ pushl %es ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET es, 0*/ ++ pushl %ds ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET ds, 0*/ ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET eax, 0 ++ pushl %ebp ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET ebp, 0 ++ pushl %edi ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET edi, 0 ++ pushl %esi ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET esi, 0 ++ pushl %edx ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET edx, 0 ++ pushl %ecx ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET ecx, 0 ++ pushl %ebx ++ CFI_ADJUST_CFA_OFFSET 4 ++ CFI_REL_OFFSET ebx, 0 ++ cld ++ pushl %gs ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET gs, 0*/ ++ movl $(__KERNEL_PDA), %ecx ++ movl %ecx, %gs ++ UNWIND_ESPFIX_STACK ++ popl %ecx ++ CFI_ADJUST_CFA_OFFSET -4 ++ /*CFI_REGISTER es, ecx*/ ++ movl PT_GS(%esp), %edi # get the function address ++ movl PT_ORIG_EAX(%esp), %edx # get the error code ++ movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart ++ mov %ecx, PT_GS(%esp) ++ /*CFI_REL_OFFSET gs, ES*/ ++ movl $(__USER_DS), %ecx ++ movl %ecx, %ds ++ movl %ecx, %es ++ movl %esp,%eax # pt_regs pointer ++ call *%edi ++ jmp ret_from_exception ++ CFI_ENDPROC ++KPROBE_END(page_fault) ++ ++#ifdef CONFIG_XEN ++# A note on the "critical region" in our callback handler. ++# We want to avoid stacking callback handlers due to events occurring ++# during handling of the last event. To do this, we keep events disabled ++# until we've done all processing. HOWEVER, we must enable events before ++# popping the stack frame (can't be done atomically) and so it would still ++# be possible to get enough handler activations to overflow the stack. ++# Although unlikely, bugs of that kind are hard to track down, so we'd ++# like to avoid the possibility. ++# So, on entry to the handler we detect whether we interrupted an ++# existing activation in its critical region -- if so, we pop the current ++# activation and restart the handler using the previous one. ++# ++# The sysexit critical region is slightly different. sysexit ++# atomically removes the entire stack frame. If we interrupt in the ++# critical region we know that the entire frame is present and correct ++# so we can simply throw away the new one. ++ENTRY(hypervisor_callback) ++ RING0_INT_FRAME ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ movl PT_EIP(%esp),%eax ++ cmpl $scrit,%eax ++ jb 11f ++ cmpl $ecrit,%eax ++ jb critical_region_fixup ++ cmpl $sysexit_scrit,%eax ++ jb 11f ++ cmpl $sysexit_ecrit,%eax ++ ja 11f ++ # interrupted in sysexit critical ++ addl $PT_OLDESP,%esp # Remove cs...ebx from stack frame. ++11: push %esp ++ CFI_ADJUST_CFA_OFFSET 4 ++ call evtchn_do_upcall ++ add $4,%esp ++ CFI_ADJUST_CFA_OFFSET -4 ++ jmp ret_from_intr ++ CFI_ENDPROC ++ ++# [How we do the fixup]. We want to merge the current stack frame with the ++# just-interrupted frame. How we do this depends on where in the critical ++# region the interrupted handler was executing, and so how many saved ++# registers are in each frame. We do this quickly using the lookup table ++# 'critical_fixup_table'. For each byte offset in the critical region, it ++# provides the number of bytes which have already been popped from the ++# interrupted stack frame. ++critical_region_fixup: ++ movzbl critical_fixup_table-scrit(%eax),%ecx # %eax contains num bytes popped ++ cmpb $0xff,%cl # 0xff => vcpu_info critical region ++ jne 15f ++ xorl %ecx,%ecx ++15: leal (%esp,%ecx),%esi # %esi points at end of src region ++ leal PT_OLDESP(%esp),%edi # %edi points at end of dst region ++ shrl $2,%ecx # convert words to bytes ++ je 17f # skip loop if nothing to copy ++16: subl $4,%esi # pre-decrementing copy loop ++ subl $4,%edi ++ movl (%esi),%eax ++ movl %eax,(%edi) ++ loop 16b ++17: movl %edi,%esp # final %edi is top of merged stack ++ jmp 11b ++ ++.section .rodata,"a" ++critical_fixup_table: ++ .byte 0xff,0xff,0xff # testb $0xff,(%esi) = __TEST_PENDING ++ .byte 0xff,0xff # jnz 14f ++ .byte 0x00 # pop %ebx ++ .byte 0x04 # pop %ecx ++ .byte 0x08 # pop %edx ++ .byte 0x0c # pop %esi ++ .byte 0x10 # pop %edi ++ .byte 0x14 # pop %ebp ++ .byte 0x18 # pop %eax ++ .byte 0x1c # pop %ds ++ .byte 0x20 # pop %es ++ .byte 0x24,0x24 # pop %gs ++ .byte 0x28,0x28,0x28 # add $4,%esp ++ .byte 0x2c # iret ++ .byte 0xff,0xff,0xff,0xff # movb $1,1(%esi) ++ .byte 0x00,0x00 # jmp 11b ++.previous ++ ++# Hypervisor uses this for application faults while it executes. ++# We get here for two reasons: ++# 1. Fault while reloading DS, ES, FS or GS ++# 2. Fault while executing IRET ++# Category 1 we fix up by reattempting the load, and zeroing the segment ++# register if the load fails. ++# Category 2 we fix up by jumping to do_iret_error. We cannot use the ++# normal Linux return path in this case because if we use the IRET hypercall ++# to pop the stack frame we end up in an infinite loop of failsafe callbacks. ++# We distinguish between categories by maintaining a status value in EAX. ++ENTRY(failsafe_callback) ++ RING0_INT_FRAME ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ movl $1,%eax ++1: mov 4(%esp),%ds ++2: mov 8(%esp),%es ++3: mov 12(%esp),%fs ++4: mov 16(%esp),%gs ++ testl %eax,%eax ++ popl %eax ++ CFI_ADJUST_CFA_OFFSET -4 ++ jz 5f ++ addl $16,%esp # EAX != 0 => Category 2 (Bad IRET) ++ jmp iret_exc ++5: addl $16,%esp # EAX == 0 => Category 1 (Bad segment) ++ pushl $0 ++ SAVE_ALL ++ jmp ret_from_exception ++.section .fixup,"ax"; \ ++6: xorl %eax,%eax; \ ++ movl %eax,4(%esp); \ ++ jmp 1b; \ ++7: xorl %eax,%eax; \ ++ movl %eax,8(%esp); \ ++ jmp 2b; \ ++8: xorl %eax,%eax; \ ++ movl %eax,12(%esp); \ ++ jmp 3b; \ ++9: xorl %eax,%eax; \ ++ movl %eax,16(%esp); \ ++ jmp 4b; \ ++.previous; \ ++.section __ex_table,"a"; \ ++ .align 4; \ ++ .long 1b,6b; \ ++ .long 2b,7b; \ ++ .long 3b,8b; \ ++ .long 4b,9b; \ ++.previous ++#endif ++ CFI_ENDPROC ++ ++ENTRY(coprocessor_error) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_coprocessor_error ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(simd_coprocessor_error) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_simd_coprocessor_error ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(device_not_available) ++ RING0_INT_FRAME ++ pushl $-1 # mark this as an int ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++#ifndef CONFIG_XEN ++ GET_CR0_INTO_EAX ++ testl $0x4, %eax # EM (math emulation bit) ++ je device_available_emulate ++ pushl $0 # temporary storage for ORIG_EIP ++ CFI_ADJUST_CFA_OFFSET 4 ++ call math_emulate ++ addl $4, %esp ++ CFI_ADJUST_CFA_OFFSET -4 ++ jmp ret_from_exception ++device_available_emulate: ++#endif ++ preempt_stop(CLBR_ANY) ++ call math_state_restore ++ jmp ret_from_exception ++ CFI_ENDPROC ++ ++#ifndef CONFIG_XEN ++/* ++ * Debug traps and NMI can happen at the one SYSENTER instruction ++ * that sets up the real kernel stack. Check here, since we can't ++ * allow the wrong stack to be used. ++ * ++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have ++ * already pushed 3 words if it hits on the sysenter instruction: ++ * eflags, cs and eip. ++ * ++ * We just load the right stack, and push the three (known) values ++ * by hand onto the new stack - while updating the return eip past ++ * the instruction that would have done it for sysenter. ++ */ ++#define FIX_STACK(offset, ok, label) \ ++ cmpw $__KERNEL_CS,4(%esp); \ ++ jne ok; \ ++label: \ ++ movl SYSENTER_stack_esp0+offset(%esp),%esp; \ ++ CFI_DEF_CFA esp, 0; \ ++ CFI_UNDEFINED eip; \ ++ pushfl; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ pushl $__KERNEL_CS; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ pushl $sysenter_past_esp; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ CFI_REL_OFFSET eip, 0 ++#endif /* CONFIG_XEN */ ++ ++KPROBE_ENTRY(debug) ++ RING0_INT_FRAME ++#ifndef CONFIG_XEN ++ cmpl $sysenter_entry,(%esp) ++ jne debug_stack_correct ++ FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) ++debug_stack_correct: ++#endif /* !CONFIG_XEN */ ++ pushl $-1 # mark this as an int ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ xorl %edx,%edx # error code 0 ++ movl %esp,%eax # pt_regs pointer ++ call do_debug ++ jmp ret_from_exception ++ CFI_ENDPROC ++KPROBE_END(debug) ++ .previous .text ++ ++#ifndef CONFIG_XEN ++/* ++ * NMI is doubly nasty. It can happen _while_ we're handling ++ * a debug fault, and the debug fault hasn't yet been able to ++ * clear up the stack. So we first check whether we got an ++ * NMI on the sysenter entry path, but after that we need to ++ * check whether we got an NMI on the debug path where the debug ++ * fault happened on the sysenter path. ++ */ ++KPROBE_ENTRY(nmi) ++ RING0_INT_FRAME ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ movl %ss, %eax ++ cmpw $__ESPFIX_SS, %ax ++ popl %eax ++ CFI_ADJUST_CFA_OFFSET -4 ++ je nmi_espfix_stack ++ cmpl $sysenter_entry,(%esp) ++ je nmi_stack_fixup ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ movl %esp,%eax ++ /* Do not access memory above the end of our stack page, ++ * it might not exist. ++ */ ++ andl $(THREAD_SIZE-1),%eax ++ cmpl $(THREAD_SIZE-20),%eax ++ popl %eax ++ CFI_ADJUST_CFA_OFFSET -4 ++ jae nmi_stack_correct ++ cmpl $sysenter_entry,12(%esp) ++ je nmi_debug_stack_check ++nmi_stack_correct: ++ /* We have a RING0_INT_FRAME here */ ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ xorl %edx,%edx # zero error code ++ movl %esp,%eax # pt_regs pointer ++ call do_nmi ++ jmp restore_nocheck_notrace ++ CFI_ENDPROC ++ ++nmi_stack_fixup: ++ RING0_INT_FRAME ++ FIX_STACK(12,nmi_stack_correct, 1) ++ jmp nmi_stack_correct ++ ++nmi_debug_stack_check: ++ /* We have a RING0_INT_FRAME here */ ++ cmpw $__KERNEL_CS,16(%esp) ++ jne nmi_stack_correct ++ cmpl $debug,(%esp) ++ jb nmi_stack_correct ++ cmpl $debug_esp_fix_insn,(%esp) ++ ja nmi_stack_correct ++ FIX_STACK(24,nmi_stack_correct, 1) ++ jmp nmi_stack_correct ++ ++nmi_espfix_stack: ++ /* We have a RING0_INT_FRAME here. ++ * ++ * create the pointer to lss back ++ */ ++ pushl %ss ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl %esp ++ CFI_ADJUST_CFA_OFFSET 4 ++ addw $4, (%esp) ++ /* copy the iret frame of 12 bytes */ ++ .rept 3 ++ pushl 16(%esp) ++ CFI_ADJUST_CFA_OFFSET 4 ++ .endr ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ FIXUP_ESPFIX_STACK # %eax == %esp ++ xorl %edx,%edx # zero error code ++ call do_nmi ++ RESTORE_REGS ++ lss 12+4(%esp), %esp # back to espfix stack ++ CFI_ADJUST_CFA_OFFSET -24 ++1: INTERRUPT_RETURN ++ CFI_ENDPROC ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,iret_exc ++.previous ++KPROBE_END(nmi) ++#else ++KPROBE_ENTRY(nmi) ++ RING0_INT_FRAME ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ xorl %edx,%edx # zero error code ++ movl %esp,%eax # pt_regs pointer ++ call do_nmi ++ orl $NMI_MASK, PT_EFLAGS(%esp) ++ jmp restore_all ++ CFI_ENDPROC ++KPROBE_END(nmi) ++#endif ++ ++#ifdef CONFIG_PARAVIRT ++ENTRY(native_iret) ++1: iret ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,iret_exc ++.previous ++ ++ENTRY(native_irq_enable_sysexit) ++ sti ++ sysexit ++#endif ++ ++KPROBE_ENTRY(int3) ++ RING0_INT_FRAME ++ pushl $-1 # mark this as an int ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ xorl %edx,%edx # zero error code ++ movl %esp,%eax # pt_regs pointer ++ call do_int3 ++ jmp ret_from_exception ++ CFI_ENDPROC ++KPROBE_END(int3) ++ ++ENTRY(overflow) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_overflow ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(bounds) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_bounds ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(invalid_op) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_invalid_op ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(coprocessor_segment_overrun) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_coprocessor_segment_overrun ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(invalid_TSS) ++ RING0_EC_FRAME ++ pushl $do_invalid_TSS ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(segment_not_present) ++ RING0_EC_FRAME ++ pushl $do_segment_not_present ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(stack_segment) ++ RING0_EC_FRAME ++ pushl $do_stack_segment ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++KPROBE_ENTRY(general_protection) ++ RING0_EC_FRAME ++ pushl $do_general_protection ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++KPROBE_END(general_protection) ++ ++ENTRY(alignment_check) ++ RING0_EC_FRAME ++ pushl $do_alignment_check ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++ENTRY(divide_error) ++ RING0_INT_FRAME ++ pushl $0 # no error code ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_divide_error ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++#ifdef CONFIG_X86_MCE ++ENTRY(machine_check) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl machine_check_vector ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++#endif ++ ++#ifndef CONFIG_XEN ++ENTRY(spurious_interrupt_bug) ++ RING0_INT_FRAME ++ pushl $0 ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_spurious_interrupt_bug ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++#endif /* !CONFIG_XEN */ ++ ++ENTRY(kernel_thread_helper) ++ pushl $0 # fake return address for unwinder ++ CFI_STARTPROC ++ movl %edx,%eax ++ push %edx ++ CFI_ADJUST_CFA_OFFSET 4 ++ call *%ebx ++ push %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ call do_exit ++ CFI_ENDPROC ++ENDPROC(kernel_thread_helper) ++ ++ENTRY(fixup_4gb_segment) ++ RING0_EC_FRAME ++ pushl $do_fixup_4gb_segment ++ CFI_ADJUST_CFA_OFFSET 4 ++ jmp error_code ++ CFI_ENDPROC ++ ++.section .rodata,"a" ++.align 4 ++#include "syscall_table.S" ++ ++syscall_table_size=(.-sys_call_table) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/entry.S +--- a/arch/i386/kernel/entry.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/entry.S Wed Aug 08 16:25:28 2007 -0300 +@@ -284,7 +284,7 @@ ENTRY(sysenter_entry) + CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, 0 + CFI_REGISTER esp, ebp +- movl TSS_sysenter_esp0(%esp),%esp ++ movl SYSENTER_stack_esp0(%esp),%esp + sysenter_past_esp: + /* + * No need to follow this irqs on/off section: the syscall +@@ -727,7 +727,7 @@ device_not_available_emulate: + * that sets up the real kernel stack. Check here, since we can't + * allow the wrong stack to be used. + * +- * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have ++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have + * already pushed 3 words if it hits on the sysenter instruction: + * eflags, cs and eip. + * +@@ -739,7 +739,7 @@ device_not_available_emulate: + cmpw $__KERNEL_CS,4(%esp); \ + jne ok; \ + label: \ +- movl TSS_sysenter_esp0+offset(%esp),%esp; \ ++ movl SYSENTER_stack_esp0+offset(%esp),%esp; \ + CFI_DEF_CFA esp, 0; \ + CFI_UNDEFINED eip; \ + pushfl; \ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/fixup.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/fixup.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,95 @@ ++/****************************************************************************** ++ * fixup.c ++ * ++ * Binary-rewriting of certain IA32 instructions, on notification by Xen. ++ * Used to avoid repeated slow emulation of common instructions used by the ++ * user-space TLS (Thread-Local Storage) libraries. ++ * ++ * **** NOTE **** ++ * Issues with the binary rewriting have caused it to be removed. Instead ++ * we rely on Xen's emulator to boot the kernel, and then print a banner ++ * message recommending that the user disables /lib/tls. ++ * ++ * Copyright (c) 2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/version.h> ++ ++#define DP(_f, _args...) printk(KERN_ALERT " " _f "\n" , ## _args ) ++ ++fastcall void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) ++{ ++#if 0 ++ static unsigned long printed = 0; ++ char info[100]; ++ int i; ++ ++ /* Ignore statically-linked init. */ ++ if (current->tgid == 1) ++ return; ++ ++ HYPERVISOR_vm_assist( ++ VMASST_CMD_disable, VMASST_TYPE_4gb_segments_notify); ++ ++ if (test_and_set_bit(0, &printed)) ++ return; ++ ++ sprintf(info, "%s (pid=%d)", current->comm, current->tgid); ++ ++ DP(""); ++ DP("***************************************************************"); ++ DP("***************************************************************"); ++ DP("** WARNING: Currently emulating unsupported memory accesses **"); ++ DP("** in /lib/tls glibc libraries. The emulation is **"); ++ DP("** slow. To ensure full performance you should **"); ++ DP("** install a 'xen-friendly' (nosegneg) version of **"); ++ DP("** the library, or disable tls support by executing **"); ++ DP("** the following as root: **"); ++ DP("** mv /lib/tls /lib/tls.disabled **"); ++ DP("** Offending process: %-38.38s **", info); ++ DP("***************************************************************"); ++ DP("***************************************************************"); ++ DP(""); ++ ++ for (i = 5; i > 0; i--) { ++ touch_softlockup_watchdog(); ++ printk("Pausing... %d", i); ++ mdelay(1000); ++ printk("\b\b\b\b\b\b\b\b\b\b\b\b"); ++ } ++ ++ printk("Continuing...\n\n"); ++#else ++ if (printk_ratelimit()) ++ printk(KERN_WARNING ++ "4gb seg fixup, process %s (pid %d), cs:ip %02x:%08lx\n", ++ current->comm, current->tgid, regs->xcs, regs->eip); ++#endif ++} ++ ++static int __init fixup_init(void) ++{ ++ HYPERVISOR_vm_assist( ++ VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify); ++ return 0; ++} ++__initcall(fixup_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/head-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/head-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,292 @@ ++ ++ ++.text ++#include <linux/elfnote.h> ++#include <linux/threads.h> ++#include <linux/linkage.h> ++#include <asm/segment.h> ++#include <asm/page.h> ++#include <asm/boot.h> ++#include <asm/cache.h> ++#include <asm/thread_info.h> ++#include <asm/asm-offsets.h> ++#include <asm/dwarf2.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/elfnote.h> ++ ++/* ++ * References to members of the new_cpu_data structure. ++ */ ++ ++#define X86 new_cpu_data+CPUINFO_x86 ++#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor ++#define X86_MODEL new_cpu_data+CPUINFO_x86_model ++#define X86_MASK new_cpu_data+CPUINFO_x86_mask ++#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math ++#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level ++#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability ++#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id ++ ++#define VIRT_ENTRY_OFFSET 0x0 ++.org VIRT_ENTRY_OFFSET ++ENTRY(startup_32) ++ ++#ifdef CONFIG_PARAVIRT ++ movl %cs, %eax ++ testl $0x3, %eax ++ jnz startup_paravirt ++#endif ++ ++ movl %esi,xen_start_info ++ cld ++ ++ call setup_pda ++ ++ /* Set up the stack pointer */ ++ movl $(init_thread_union+THREAD_SIZE),%esp ++ ++ /* get vendor info */ ++ xorl %eax,%eax # call CPUID with 0 -> return vendor ID ++ XEN_CPUID ++ movl %eax,X86_CPUID # save CPUID level ++ movl %ebx,X86_VENDOR_ID # lo 4 chars ++ movl %edx,X86_VENDOR_ID+4 # next 4 chars ++ movl %ecx,X86_VENDOR_ID+8 # last 4 chars ++ ++ movl $1,%eax # Use the CPUID instruction to get CPU type ++ XEN_CPUID ++ movb %al,%cl # save reg for future use ++ andb $0x0f,%ah # mask processor family ++ movb %ah,X86 ++ andb $0xf0,%al # mask model ++ shrb $4,%al ++ movb %al,X86_MODEL ++ andb $0x0f,%cl # mask mask revision ++ movb %cl,X86_MASK ++ movl %edx,X86_CAPABILITY ++ ++ movb $1,X86_HARD_MATH ++ ++ xorl %eax,%eax # Clear FS and LDT ++ movl %eax,%fs ++ ++ movl $(__KERNEL_PDA),%eax ++ mov %eax,%gs ++ ++ cld # gcc2 wants the direction flag cleared at all times ++ ++ pushl %eax # fake return address ++ jmp start_kernel ++ ++/* ++ * Point the GDT at this CPU's PDA. This will be ++ * cpu_gdt_table and boot_pda. ++ */ ++setup_pda: ++ /* get the PDA pointer */ ++ movl $boot_pda, %eax ++ ++ /* slot the PDA address into the GDT */ ++ mov $cpu_gdt_table, %ecx ++ mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ ++ shr $16, %eax ++ mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ ++ mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */ ++ ++ # %esi still points to start_info, and no registers ++ # need to be preserved. ++ ++ movl XEN_START_mfn_list(%esi), %ebx ++ movl $(cpu_gdt_table - __PAGE_OFFSET), %eax ++ shrl $PAGE_SHIFT, %eax ++ movl (%ebx,%eax,4), %ecx ++ pushl %ecx # frame number for set_gdt below ++ ++ xorl %esi, %esi ++ xorl %edx, %edx ++ shldl $PAGE_SHIFT, %ecx, %edx ++ shll $PAGE_SHIFT, %ecx ++ orl $0x61, %ecx ++ movl $cpu_gdt_table, %ebx ++ movl $__HYPERVISOR_update_va_mapping, %eax ++ int $0x82 ++ ++ movl $(PAGE_SIZE_asm / 8), %ecx ++ movl %esp, %ebx ++ movl $__HYPERVISOR_set_gdt, %eax ++ int $0x82 ++ ++ popl %ecx ++ ret ++ ++#define HYPERCALL_PAGE_OFFSET 0x1000 ++.org HYPERCALL_PAGE_OFFSET ++ENTRY(hypercall_page) ++ CFI_STARTPROC ++.skip 0x1000 ++ CFI_ENDPROC ++ ++/* ++ * Real beginning of normal "text" segment ++ */ ++ENTRY(stext) ++ENTRY(_stext) ++ ++/* ++ * BSS section ++ */ ++.section ".bss.page_aligned","w" ++ENTRY(empty_zero_page) ++ .fill 4096,1,0 ++ ++/* ++ * This starts the data section. ++ */ ++.data ++ENTRY(start_pda) ++ .long boot_pda ++ ++#ifdef CONFIG_PARAVIRT ++startup_paravirt: ++ cld ++ movl $(init_thread_union+THREAD_SIZE),%esp ++ ++ /* We take pains to preserve all the regs. */ ++ pushl %edx ++ pushl %ecx ++ pushl %eax ++ ++ /* paravirt.o is last in link, and that probe fn never returns */ ++ pushl $__start_paravirtprobe ++1: ++ movl 0(%esp), %eax ++ pushl (%eax) ++ movl 8(%esp), %eax ++ call *(%esp) ++ popl %eax ++ ++ movl 4(%esp), %eax ++ movl 8(%esp), %ecx ++ movl 12(%esp), %edx ++ ++ addl $4, (%esp) ++ jmp 1b ++#endif ++ ++/* ++ * The Global Descriptor Table contains 28 quadwords, per-CPU. ++ */ ++ .section .data.page_aligned, "aw" ++ .align PAGE_SIZE_asm ++ENTRY(cpu_gdt_table) ++ .quad 0x0000000000000000 /* NULL descriptor */ ++ .quad 0x0000000000000000 /* 0x0b reserved */ ++ .quad 0x0000000000000000 /* 0x13 reserved */ ++ .quad 0x0000000000000000 /* 0x1b reserved */ ++ .quad 0x0000000000000000 /* 0x20 unused */ ++ .quad 0x0000000000000000 /* 0x28 unused */ ++ .quad 0x0000000000000000 /* 0x33 TLS entry 1 */ ++ .quad 0x0000000000000000 /* 0x3b TLS entry 2 */ ++ .quad 0x0000000000000000 /* 0x43 TLS entry 3 */ ++ .quad 0x0000000000000000 /* 0x4b reserved */ ++ .quad 0x0000000000000000 /* 0x53 reserved */ ++ .quad 0x0000000000000000 /* 0x5b reserved */ ++ ++ .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ ++ .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ ++ .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */ ++ .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */ ++ ++ .quad 0x0000000000000000 /* 0x80 TSS descriptor */ ++ .quad 0x0000000000000000 /* 0x88 LDT descriptor */ ++ ++ /* ++ * Segments used for calling PnP BIOS have byte granularity. ++ * They code segments and data segments have fixed 64k limits, ++ * the transfer segment sizes are set at run time. ++ */ ++ .quad 0x0000000000000000 /* 0x90 32-bit code */ ++ .quad 0x0000000000000000 /* 0x98 16-bit code */ ++ .quad 0x0000000000000000 /* 0xa0 16-bit data */ ++ .quad 0x0000000000000000 /* 0xa8 16-bit data */ ++ .quad 0x0000000000000000 /* 0xb0 16-bit data */ ++ ++ /* ++ * The APM segments have byte granularity and their bases ++ * are set at run time. All have 64k limits. ++ */ ++ .quad 0x0000000000000000 /* 0xb8 APM CS code */ ++ .quad 0x0000000000000000 /* 0xc0 APM CS 16 code (16 bit) */ ++ .quad 0x0000000000000000 /* 0xc8 APM DS data */ ++ ++ .quad 0x0000000000000000 /* 0xd0 - ESPFIX SS */ ++ .quad 0x00cf92000000ffff /* 0xd8 - PDA */ ++ .quad 0x0000000000000000 /* 0xe0 - unused */ ++ .quad 0x0000000000000000 /* 0xe8 - unused */ ++ .quad 0x0000000000000000 /* 0xf0 - unused */ ++ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ ++ .align PAGE_SIZE_asm ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++/* ++ * __xen_guest information ++ */ ++.macro utoa value ++ .if (\value) < 0 || (\value) >= 0x10 ++ utoa (((\value)>>4)&0x0fffffff) ++ .endif ++ .if ((\value) & 0xf) < 10 ++ .byte '0' + ((\value) & 0xf) ++ .else ++ .byte 'A' + ((\value) & 0xf) - 10 ++ .endif ++.endm ++ ++.section __xen_guest ++ .ascii "GUEST_OS=linux,GUEST_VER=2.6" ++ .ascii ",XEN_VER=xen-3.0" ++ .ascii ",VIRT_BASE=0x" ++ utoa __PAGE_OFFSET ++ .ascii ",ELF_PADDR_OFFSET=0x" ++ utoa __PAGE_OFFSET ++ .ascii ",VIRT_ENTRY=0x" ++ utoa (__PAGE_OFFSET + LOAD_PHYSICAL_ADDR + VIRT_ENTRY_OFFSET) ++ .ascii ",HYPERCALL_PAGE=0x" ++ utoa ((LOAD_PHYSICAL_ADDR+HYPERCALL_PAGE_OFFSET)>>PAGE_SHIFT) ++ .ascii ",FEATURES=writable_page_tables" ++ .ascii "|writable_descriptor_tables" ++ .ascii "|auto_translated_physmap" ++ .ascii "|pae_pgdir_above_4gb" ++ .ascii "|supervisor_mode_kernel" ++#ifdef CONFIG_X86_PAE ++ .ascii ",PAE=yes[extended-cr3]" ++#else ++ .ascii ",PAE=no" ++#endif ++ .ascii ",LOADER=generic" ++ .byte 0 ++#endif /* CONFIG_XEN_COMPAT <= 0x030002 */ ++ ++ ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux") ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6") ++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0") ++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long, __PAGE_OFFSET) ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, __PAGE_OFFSET) ++#else ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, 0) ++#endif ++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, startup_32) ++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page) ++ ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long, HYPERVISOR_VIRT_START) ++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") ++#ifdef CONFIG_X86_PAE ++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "yes") ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad, _PAGE_PRESENT,_PAGE_PRESENT) ++#else ++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "no") ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .long, _PAGE_PRESENT,_PAGE_PRESENT) ++#endif ++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic") ++ ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long, 1) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/init_task.c +--- a/arch/i386/kernel/init_task.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/init_task.c Wed Aug 08 16:25:28 2007 -0300 +@@ -14,7 +14,14 @@ static struct files_struct init_files = + static struct files_struct init_files = INIT_FILES; + static struct signal_struct init_signals = INIT_SIGNALS(init_signals); + static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); ++ ++#ifdef CONFIG_XEN ++#define swapper_pg_dir ((pgd_t *)NULL) + struct mm_struct init_mm = INIT_MM(init_mm); ++#undef swapper_pg_dir ++#else ++struct mm_struct init_mm = INIT_MM(init_mm); ++#endif + + EXPORT_SYMBOL(init_mm); + +@@ -38,9 +45,11 @@ struct task_struct init_task = INIT_TASK + + EXPORT_SYMBOL(init_task); + ++#ifndef CONFIG_X86_NO_TSS + /* + * per-CPU TSS segments. Threads are completely 'soft' on Linux, + * no more per-task TSS's. + */ + DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS; ++#endif + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/io_apic-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/io_apic-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2973 @@ ++/* ++ * Intel IO-APIC support for multi-Pentium hosts. ++ * ++ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo ++ * ++ * Many thanks to Stig Venaas for trying out countless experimental ++ * patches and reporting/debugging problems patiently! ++ * ++ * (c) 1999, Multiple IO-APIC support, developed by ++ * Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and ++ * Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>, ++ * further tested and cleaned up by Zach Brown <zab@redhat.com> ++ * and Ingo Molnar <mingo@redhat.com> ++ * ++ * Fixes ++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs; ++ * thanks to Eric Gilmore ++ * and Rolf G. Tews ++ * for testing these extensively ++ * Paul Diefenbaugh : Added full ACPI support ++ */ ++ ++#include <linux/mm.h> ++#include <linux/interrupt.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/smp_lock.h> ++#include <linux/mc146818rtc.h> ++#include <linux/compiler.h> ++#include <linux/acpi.h> ++#include <linux/module.h> ++#include <linux/sysdev.h> ++#include <linux/pci.h> ++#include <linux/msi.h> ++#include <linux/htirq.h> ++#include <linux/freezer.h> ++ ++#include <asm/io.h> ++#include <asm/smp.h> ++#include <asm/desc.h> ++#include <asm/timer.h> ++#include <asm/i8259.h> ++#include <asm/nmi.h> ++#include <asm/msidef.h> ++#include <asm/hypertransport.h> ++ ++#include <mach_apic.h> ++#include <mach_apicdef.h> ++ ++#include "io_ports.h" ++ ++#ifdef CONFIG_XEN ++ ++#include <xen/interface/xen.h> ++#include <xen/interface/physdev.h> ++ ++/* Fake i8259 */ ++#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq))) ++#define disable_8259A_irq(_irq) ((void)0) ++#define i8259A_irq_pending(_irq) (0) ++ ++unsigned long io_apic_irqs; ++ ++static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) ++{ ++ struct physdev_apic apic_op; ++ int ret; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); ++ if (ret) ++ return ret; ++ return apic_op.value; ++} ++ ++static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ struct physdev_apic apic_op; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ apic_op.value = value; ++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op); ++} ++ ++#define io_apic_read(a,r) xen_io_apic_read(a,r) ++#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v) ++ ++#endif /* CONFIG_XEN */ ++ ++int (*ioapic_renumber_irq)(int ioapic, int irq); ++atomic_t irq_mis_count; ++ ++/* Where if anywhere is the i8259 connect in external int mode */ ++static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; ++ ++static DEFINE_SPINLOCK(ioapic_lock); ++static DEFINE_SPINLOCK(vector_lock); ++ ++int timer_over_8254 __initdata = 1; ++ ++/* ++ * Is the SiS APIC rmw bug present ? ++ * -1 = don't know, 0 = no, 1 = yes ++ */ ++int sis_apic_bug = -1; ++ ++/* ++ * # of IRQ routing registers ++ */ ++int nr_ioapic_registers[MAX_IO_APICS]; ++ ++static int disable_timer_pin_1 __initdata; ++ ++/* ++ * Rough estimation of how many shared IRQs there are, can ++ * be changed anytime. ++ */ ++#define MAX_PLUS_SHARED_IRQS NR_IRQS ++#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) ++ ++/* ++ * This is performance-critical, we want to do it O(1) ++ * ++ * the indexing order of this array favors 1:1 mappings ++ * between pins and IRQs. ++ */ ++ ++static struct irq_pin_list { ++ int apic, pin, next; ++} irq_2_pin[PIN_MAP_SIZE]; ++ ++#ifndef CONFIG_XEN ++struct io_apic { ++ unsigned int index; ++ unsigned int unused[3]; ++ unsigned int data; ++}; ++ ++static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ++{ ++ return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) ++ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); ++} ++ ++static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ return readl(&io_apic->data); ++} ++ ++static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++} ++ ++/* ++ * Re-write a value: to be used for read-modify-write ++ * cycles where the read already set up the index register. ++ * ++ * Older SiS APIC requires we rewrite the index register ++ */ ++static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ volatile struct io_apic *io_apic = io_apic_base(apic); ++ if (sis_apic_bug) ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++} ++#endif /* !CONFIG_XEN */ ++ ++union entry_union { ++ struct { u32 w1, w2; }; ++ struct IO_APIC_route_entry entry; ++}; ++ ++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) ++{ ++ union entry_union eu; ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin); ++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ return eu.entry; ++} ++ ++/* ++ * When we write a new IO APIC routing entry, we need to write the high ++ * word first! If the mask bit in the low word is clear, we will enable ++ * the interrupt, and we need to make sure the entry is fully populated ++ * before that happens. ++ */ ++static void ++__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ union entry_union eu; ++ eu.entry = e; ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++} ++ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, e); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++/* ++ * When we mask an IO APIC routing entry, we need to write the low ++ * word first, in order to set the mask bit before we change the ++ * high bits! ++ */ ++ ++#ifndef CONFIG_XEN ++static void ioapic_mask_entry(int apic, int pin) ++{ ++ unsigned long flags; ++ union entry_union eu = { .entry.mask = 1 }; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++#endif ++ ++/* ++ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are ++ * shared ISA-space IRQs, so we have to support them. We are super ++ * fast in the common case, and fast for shared ISA-space IRQs. ++ */ ++static void add_pin_to_irq(unsigned int irq, int apic, int pin) ++{ ++ static int first_free_entry = NR_IRQS; ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ ++ while (entry->next) ++ entry = irq_2_pin + entry->next; ++ ++ if (entry->pin != -1) { ++ entry->next = first_free_entry; ++ entry = irq_2_pin + entry->next; ++ if (++first_free_entry >= PIN_MAP_SIZE) ++ panic("io_apic.c: whoops"); ++ } ++ entry->apic = apic; ++ entry->pin = pin; ++} ++ ++#ifdef CONFIG_XEN ++#define clear_IO_APIC() ((void)0) ++#else ++/* ++ * Reroute an IRQ to a different pin. ++ */ ++static void __init replace_pin_at_irq(unsigned int irq, ++ int oldapic, int oldpin, ++ int newapic, int newpin) ++{ ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ ++ while (1) { ++ if (entry->apic == oldapic && entry->pin == oldpin) { ++ entry->apic = newapic; ++ entry->pin = newpin; ++ } ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++} ++ ++static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable) ++{ ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ unsigned int pin, reg; ++ ++ for (;;) { ++ pin = entry->pin; ++ if (pin == -1) ++ break; ++ reg = io_apic_read(entry->apic, 0x10 + pin*2); ++ reg &= ~disable; ++ reg |= enable; ++ io_apic_modify(entry->apic, 0x10 + pin*2, reg); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++} ++ ++/* mask = 1 */ ++static void __mask_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0x00010000, 0); ++} ++ ++/* mask = 0 */ ++static void __unmask_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0, 0x00010000); ++} ++ ++/* mask = 1, trigger = 0 */ ++static void __mask_and_edge_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000); ++} ++ ++/* mask = 0, trigger = 1 */ ++static void __unmask_and_level_IO_APIC_irq (unsigned int irq) ++{ ++ __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); ++} ++ ++static void mask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __mask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++static void unmask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __unmask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ++{ ++ struct IO_APIC_route_entry entry; ++ ++ /* Check delivery_mode to be sure we're not clearing an SMI pin */ ++ entry = ioapic_read_entry(apic, pin); ++ if (entry.delivery_mode == dest_SMI) ++ return; ++ ++ /* ++ * Disable it in the IO-APIC irq-routing table: ++ */ ++ ioapic_mask_entry(apic, pin); ++} ++ ++static void clear_IO_APIC (void) ++{ ++ int apic, pin; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) ++ clear_IO_APIC_pin(apic, pin); ++} ++ ++#ifdef CONFIG_SMP ++static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) ++{ ++ unsigned long flags; ++ int pin; ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ unsigned int apicid_value; ++ cpumask_t tmp; ++ ++ cpus_and(tmp, cpumask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(cpumask, tmp, CPU_MASK_ALL); ++ ++ apicid_value = cpu_mask_to_apicid(cpumask); ++ /* Prepare to do the io_apic_write */ ++ apicid_value = apicid_value << 24; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ for (;;) { ++ pin = entry->pin; ++ if (pin == -1) ++ break; ++ io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++ set_native_irq_info(irq, cpumask); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++#if defined(CONFIG_IRQBALANCE) ++# include <asm/processor.h> /* kernel_thread() */ ++# include <linux/kernel_stat.h> /* kstat */ ++# include <linux/slab.h> /* kmalloc() */ ++# include <linux/timer.h> /* time_after() */ ++ ++#ifdef CONFIG_BALANCED_IRQ_DEBUG ++# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) ++# define Dprintk(x...) do { TDprintk(x); } while (0) ++# else ++# define TDprintk(x...) ++# define Dprintk(x...) ++# endif ++ ++#define IRQBALANCE_CHECK_ARCH -999 ++#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) ++#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) ++#define BALANCED_IRQ_MORE_DELTA (HZ/10) ++#define BALANCED_IRQ_LESS_DELTA (HZ) ++ ++static int irqbalance_disabled __read_mostly = IRQBALANCE_CHECK_ARCH; ++static int physical_balance __read_mostly; ++static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL; ++ ++static struct irq_cpu_info { ++ unsigned long * last_irq; ++ unsigned long * irq_delta; ++ unsigned long irq; ++} irq_cpu_data[NR_CPUS]; ++ ++#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq) ++#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq]) ++#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq]) ++ ++#define IDLE_ENOUGH(cpu,now) \ ++ (idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1)) ++ ++#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) ++ ++#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) ++ ++static cpumask_t balance_irq_affinity[NR_IRQS] = { ++ [0 ... NR_IRQS-1] = CPU_MASK_ALL ++}; ++ ++void set_balance_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ balance_irq_affinity[irq] = mask; ++} ++ ++static unsigned long move(int curr_cpu, cpumask_t allowed_mask, ++ unsigned long now, int direction) ++{ ++ int search_idle = 1; ++ int cpu = curr_cpu; ++ ++ goto inside; ++ ++ do { ++ if (unlikely(cpu == curr_cpu)) ++ search_idle = 0; ++inside: ++ if (direction == 1) { ++ cpu++; ++ if (cpu >= NR_CPUS) ++ cpu = 0; ++ } else { ++ cpu--; ++ if (cpu == -1) ++ cpu = NR_CPUS-1; ++ } ++ } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) || ++ (search_idle && !IDLE_ENOUGH(cpu,now))); ++ ++ return cpu; ++} ++ ++static inline void balance_irq(int cpu, int irq) ++{ ++ unsigned long now = jiffies; ++ cpumask_t allowed_mask; ++ unsigned int new_cpu; ++ ++ if (irqbalance_disabled) ++ return; ++ ++ cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]); ++ new_cpu = move(cpu, allowed_mask, now, 1); ++ if (cpu != new_cpu) { ++ set_pending_irq(irq, cpumask_of_cpu(new_cpu)); ++ } ++} ++ ++static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) ++{ ++ int i, j; ++ Dprintk("Rotating IRQs among CPUs.\n"); ++ for_each_online_cpu(i) { ++ for (j = 0; j < NR_IRQS; j++) { ++ if (!irq_desc[j].action) ++ continue; ++ /* Is it a significant load ? */ ++ if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) < ++ useful_load_threshold) ++ continue; ++ balance_irq(i, j); ++ } ++ } ++ balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, ++ balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); ++ return; ++} ++ ++static void do_irq_balance(void) ++{ ++ int i, j; ++ unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); ++ unsigned long move_this_load = 0; ++ int max_loaded = 0, min_loaded = 0; ++ int load; ++ unsigned long useful_load_threshold = balanced_irq_interval + 10; ++ int selected_irq; ++ int tmp_loaded, first_attempt = 1; ++ unsigned long tmp_cpu_irq; ++ unsigned long imbalance = 0; ++ cpumask_t allowed_mask, target_cpu_mask, tmp; ++ ++ for_each_possible_cpu(i) { ++ int package_index; ++ CPU_IRQ(i) = 0; ++ if (!cpu_online(i)) ++ continue; ++ package_index = CPU_TO_PACKAGEINDEX(i); ++ for (j = 0; j < NR_IRQS; j++) { ++ unsigned long value_now, delta; ++ /* Is this an active IRQ? */ ++ if (!irq_desc[j].action) ++ continue; ++ if ( package_index == i ) ++ IRQ_DELTA(package_index,j) = 0; ++ /* Determine the total count per processor per IRQ */ ++ value_now = (unsigned long) kstat_cpu(i).irqs[j]; ++ ++ /* Determine the activity per processor per IRQ */ ++ delta = value_now - LAST_CPU_IRQ(i,j); ++ ++ /* Update last_cpu_irq[][] for the next time */ ++ LAST_CPU_IRQ(i,j) = value_now; ++ ++ /* Ignore IRQs whose rate is less than the clock */ ++ if (delta < useful_load_threshold) ++ continue; ++ /* update the load for the processor or package total */ ++ IRQ_DELTA(package_index,j) += delta; ++ ++ /* Keep track of the higher numbered sibling as well */ ++ if (i != package_index) ++ CPU_IRQ(i) += delta; ++ /* ++ * We have sibling A and sibling B in the package ++ * ++ * cpu_irq[A] = load for cpu A + load for cpu B ++ * cpu_irq[B] = load for cpu B ++ */ ++ CPU_IRQ(package_index) += delta; ++ } ++ } ++ /* Find the least loaded processor package */ ++ for_each_online_cpu(i) { ++ if (i != CPU_TO_PACKAGEINDEX(i)) ++ continue; ++ if (min_cpu_irq > CPU_IRQ(i)) { ++ min_cpu_irq = CPU_IRQ(i); ++ min_loaded = i; ++ } ++ } ++ max_cpu_irq = ULONG_MAX; ++ ++tryanothercpu: ++ /* Look for heaviest loaded processor. ++ * We may come back to get the next heaviest loaded processor. ++ * Skip processors with trivial loads. ++ */ ++ tmp_cpu_irq = 0; ++ tmp_loaded = -1; ++ for_each_online_cpu(i) { ++ if (i != CPU_TO_PACKAGEINDEX(i)) ++ continue; ++ if (max_cpu_irq <= CPU_IRQ(i)) ++ continue; ++ if (tmp_cpu_irq < CPU_IRQ(i)) { ++ tmp_cpu_irq = CPU_IRQ(i); ++ tmp_loaded = i; ++ } ++ } ++ ++ if (tmp_loaded == -1) { ++ /* In the case of small number of heavy interrupt sources, ++ * loading some of the cpus too much. We use Ingo's original ++ * approach to rotate them around. ++ */ ++ if (!first_attempt && imbalance >= useful_load_threshold) { ++ rotate_irqs_among_cpus(useful_load_threshold); ++ return; ++ } ++ goto not_worth_the_effort; ++ } ++ ++ first_attempt = 0; /* heaviest search */ ++ max_cpu_irq = tmp_cpu_irq; /* load */ ++ max_loaded = tmp_loaded; /* processor */ ++ imbalance = (max_cpu_irq - min_cpu_irq) / 2; ++ ++ Dprintk("max_loaded cpu = %d\n", max_loaded); ++ Dprintk("min_loaded cpu = %d\n", min_loaded); ++ Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); ++ Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); ++ Dprintk("load imbalance = %lu\n", imbalance); ++ ++ /* if imbalance is less than approx 10% of max load, then ++ * observe diminishing returns action. - quit ++ */ ++ if (imbalance < (max_cpu_irq >> 3)) { ++ Dprintk("Imbalance too trivial\n"); ++ goto not_worth_the_effort; ++ } ++ ++tryanotherirq: ++ /* if we select an IRQ to move that can't go where we want, then ++ * see if there is another one to try. ++ */ ++ move_this_load = 0; ++ selected_irq = -1; ++ for (j = 0; j < NR_IRQS; j++) { ++ /* Is this an active IRQ? */ ++ if (!irq_desc[j].action) ++ continue; ++ if (imbalance <= IRQ_DELTA(max_loaded,j)) ++ continue; ++ /* Try to find the IRQ that is closest to the imbalance ++ * without going over. ++ */ ++ if (move_this_load < IRQ_DELTA(max_loaded,j)) { ++ move_this_load = IRQ_DELTA(max_loaded,j); ++ selected_irq = j; ++ } ++ } ++ if (selected_irq == -1) { ++ goto tryanothercpu; ++ } ++ ++ imbalance = move_this_load; ++ ++ /* For physical_balance case, we accumlated both load ++ * values in the one of the siblings cpu_irq[], ++ * to use the same code for physical and logical processors ++ * as much as possible. ++ * ++ * NOTE: the cpu_irq[] array holds the sum of the load for ++ * sibling A and sibling B in the slot for the lowest numbered ++ * sibling (A), _AND_ the load for sibling B in the slot for ++ * the higher numbered sibling. ++ * ++ * We seek the least loaded sibling by making the comparison ++ * (A+B)/2 vs B ++ */ ++ load = CPU_IRQ(min_loaded) >> 1; ++ for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { ++ if (load > CPU_IRQ(j)) { ++ /* This won't change cpu_sibling_map[min_loaded] */ ++ load = CPU_IRQ(j); ++ min_loaded = j; ++ } ++ } ++ ++ cpus_and(allowed_mask, ++ cpu_online_map, ++ balance_irq_affinity[selected_irq]); ++ target_cpu_mask = cpumask_of_cpu(min_loaded); ++ cpus_and(tmp, target_cpu_mask, allowed_mask); ++ ++ if (!cpus_empty(tmp)) { ++ ++ Dprintk("irq = %d moved to cpu = %d\n", ++ selected_irq, min_loaded); ++ /* mark for change destination */ ++ set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded)); ++ ++ /* Since we made a change, come back sooner to ++ * check for more variation. ++ */ ++ balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, ++ balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); ++ return; ++ } ++ goto tryanotherirq; ++ ++not_worth_the_effort: ++ /* ++ * if we did not find an IRQ to move, then adjust the time interval ++ * upward ++ */ ++ balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, ++ balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); ++ Dprintk("IRQ worth rotating not found\n"); ++ return; ++} ++ ++static int balanced_irq(void *unused) ++{ ++ int i; ++ unsigned long prev_balance_time = jiffies; ++ long time_remaining = balanced_irq_interval; ++ ++ daemonize("kirqd"); ++ ++ /* push everything to CPU 0 to give us a starting point. */ ++ for (i = 0 ; i < NR_IRQS ; i++) { ++ irq_desc[i].pending_mask = cpumask_of_cpu(0); ++ set_pending_irq(i, cpumask_of_cpu(0)); ++ } ++ ++ for ( ; ; ) { ++ time_remaining = schedule_timeout_interruptible(time_remaining); ++ try_to_freeze(); ++ if (time_after(jiffies, ++ prev_balance_time+balanced_irq_interval)) { ++ preempt_disable(); ++ do_irq_balance(); ++ prev_balance_time = jiffies; ++ time_remaining = balanced_irq_interval; ++ preempt_enable(); ++ } ++ } ++ return 0; ++} ++ ++static int __init balanced_irq_init(void) ++{ ++ int i; ++ struct cpuinfo_x86 *c; ++ cpumask_t tmp; ++ ++ cpus_shift_right(tmp, cpu_online_map, 2); ++ c = &boot_cpu_data; ++ /* When not overwritten by the command line ask subarchitecture. */ ++ if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) ++ irqbalance_disabled = NO_BALANCE_IRQ; ++ if (irqbalance_disabled) ++ return 0; ++ ++ /* disable irqbalance completely if there is only one processor online */ ++ if (num_online_cpus() < 2) { ++ irqbalance_disabled = 1; ++ return 0; ++ } ++ /* ++ * Enable physical balance only if more than 1 physical processor ++ * is present ++ */ ++ if (smp_num_siblings > 1 && !cpus_empty(tmp)) ++ physical_balance = 1; ++ ++ for_each_online_cpu(i) { ++ irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); ++ irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); ++ if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { ++ printk(KERN_ERR "balanced_irq_init: out of memory"); ++ goto failed; ++ } ++ memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); ++ memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); ++ } ++ ++ printk(KERN_INFO "Starting balanced_irq\n"); ++ if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) ++ return 0; ++ else ++ printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); ++failed: ++ for_each_possible_cpu(i) { ++ kfree(irq_cpu_data[i].irq_delta); ++ irq_cpu_data[i].irq_delta = NULL; ++ kfree(irq_cpu_data[i].last_irq); ++ irq_cpu_data[i].last_irq = NULL; ++ } ++ return 0; ++} ++ ++int __init irqbalance_disable(char *str) ++{ ++ irqbalance_disabled = 1; ++ return 1; ++} ++ ++__setup("noirqbalance", irqbalance_disable); ++ ++late_initcall(balanced_irq_init); ++#endif /* CONFIG_IRQBALANCE */ ++#endif /* CONFIG_SMP */ ++#endif /* !CONFIG_XEN */ ++ ++#ifndef CONFIG_SMP ++void fastcall send_IPI_self(int vector) ++{ ++#ifndef CONFIG_XEN ++ unsigned int cfg; ++ ++ /* ++ * Wait for idle. ++ */ ++ apic_wait_icr_idle(); ++ cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; ++ /* ++ * Send the IPI. The write to APIC_ICR fires this off. ++ */ ++ apic_write_around(APIC_ICR, cfg); ++#endif ++} ++#endif /* !CONFIG_SMP */ ++ ++ ++/* ++ * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to ++ * specific CPU-side IRQs. ++ */ ++ ++#define MAX_PIRQS 8 ++static int pirq_entries [MAX_PIRQS]; ++static int pirqs_enabled; ++int skip_ioapic_setup; ++ ++static int __init ioapic_setup(char *str) ++{ ++ skip_ioapic_setup = 1; ++ return 1; ++} ++ ++__setup("noapic", ioapic_setup); ++ ++static int __init ioapic_pirq_setup(char *str) ++{ ++ int i, max; ++ int ints[MAX_PIRQS+1]; ++ ++ get_options(str, ARRAY_SIZE(ints), ints); ++ ++ for (i = 0; i < MAX_PIRQS; i++) ++ pirq_entries[i] = -1; ++ ++ pirqs_enabled = 1; ++ apic_printk(APIC_VERBOSE, KERN_INFO ++ "PIRQ redirection, working around broken MP-BIOS.\n"); ++ max = MAX_PIRQS; ++ if (ints[0] < MAX_PIRQS) ++ max = ints[0]; ++ ++ for (i = 0; i < max; i++) { ++ apic_printk(APIC_VERBOSE, KERN_DEBUG ++ "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); ++ /* ++ * PIRQs are mapped upside down, usually. ++ */ ++ pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; ++ } ++ return 1; ++} ++ ++__setup("pirq=", ioapic_pirq_setup); ++ ++/* ++ * Find the IRQ entry number of a certain pin. ++ */ ++static int find_irq_entry(int apic, int pin, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) ++ if (mp_irqs[i].mpc_irqtype == type && ++ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || ++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && ++ mp_irqs[i].mpc_dstirq == pin) ++ return i; ++ ++ return -1; ++} ++ ++/* ++ * Find the pin to which IRQ[irq] (ISA) is connected ++ */ ++static int __init find_isa_irq_pin(int irq, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || ++ mp_bus_id_to_type[lbus] == MP_BUS_EISA || ++ mp_bus_id_to_type[lbus] == MP_BUS_MCA ++ ) && ++ (mp_irqs[i].mpc_irqtype == type) && ++ (mp_irqs[i].mpc_srcbusirq == irq)) ++ ++ return mp_irqs[i].mpc_dstirq; ++ } ++ return -1; ++} ++ ++static int __init find_isa_irq_apic(int irq, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || ++ mp_bus_id_to_type[lbus] == MP_BUS_EISA || ++ mp_bus_id_to_type[lbus] == MP_BUS_MCA ++ ) && ++ (mp_irqs[i].mpc_irqtype == type) && ++ (mp_irqs[i].mpc_srcbusirq == irq)) ++ break; ++ } ++ if (i < mp_irq_entries) { ++ int apic; ++ for(apic = 0; apic < nr_ioapics; apic++) { ++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) ++ return apic; ++ } ++ } ++ ++ return -1; ++} ++ ++/* ++ * Find a specific PCI IRQ entry. ++ * Not an __init, possibly needed by modules ++ */ ++static int pin_2_irq(int idx, int apic, int pin); ++ ++int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ++{ ++ int apic, i, best_guess = -1; ++ ++ apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " ++ "slot:%d, pin:%d.\n", bus, slot, pin); ++ if (mp_bus_id_to_pci_bus[bus] == -1) { ++ printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); ++ return -1; ++ } ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || ++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) ++ break; ++ ++ if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && ++ !mp_irqs[i].mpc_irqtype && ++ (bus == lbus) && ++ (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { ++ int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); ++ ++ if (!(apic || IO_APIC_IRQ(irq))) ++ continue; ++ ++ if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) ++ return irq; ++ /* ++ * Use the first all-but-pin matching entry as a ++ * best-guess fuzzy result for broken mptables. ++ */ ++ if (best_guess < 0) ++ best_guess = irq; ++ } ++ } ++ return best_guess; ++} ++EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); ++ ++/* ++ * This function currently is only a helper for the i386 smp boot process where ++ * we need to reprogram the ioredtbls to cater for the cpus which have come online ++ * so mask in all cases should simply be TARGET_CPUS ++ */ ++#ifdef CONFIG_SMP ++#ifndef CONFIG_XEN ++void __init setup_ioapic_dest(void) ++{ ++ int pin, ioapic, irq, irq_entry; ++ ++ if (skip_ioapic_setup == 1) ++ return; ++ ++ for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { ++ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { ++ irq_entry = find_irq_entry(ioapic, pin, mp_INT); ++ if (irq_entry == -1) ++ continue; ++ irq = pin_2_irq(irq_entry, ioapic, pin); ++ set_ioapic_affinity_irq(irq, TARGET_CPUS); ++ } ++ ++ } ++} ++#endif /* !CONFIG_XEN */ ++#endif ++ ++/* ++ * EISA Edge/Level control register, ELCR ++ */ ++static int EISA_ELCR(unsigned int irq) ++{ ++ if (irq < 16) { ++ unsigned int port = 0x4d0 + (irq >> 3); ++ return (inb(port) >> (irq & 7)) & 1; ++ } ++ apic_printk(APIC_VERBOSE, KERN_INFO ++ "Broken MPtable reports ISA irq %d\n", irq); ++ return 0; ++} ++ ++/* EISA interrupts are always polarity zero and can be edge or level ++ * trigger depending on the ELCR value. If an interrupt is listed as ++ * EISA conforming in the MP table, that means its trigger type must ++ * be read in from the ELCR */ ++ ++#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq)) ++#define default_EISA_polarity(idx) (0) ++ ++/* ISA interrupts are always polarity zero edge triggered, ++ * when listed as conforming in the MP table. */ ++ ++#define default_ISA_trigger(idx) (0) ++#define default_ISA_polarity(idx) (0) ++ ++/* PCI interrupts are always polarity one level triggered, ++ * when listed as conforming in the MP table. */ ++ ++#define default_PCI_trigger(idx) (1) ++#define default_PCI_polarity(idx) (1) ++ ++/* MCA interrupts are always polarity zero level triggered, ++ * when listed as conforming in the MP table. */ ++ ++#define default_MCA_trigger(idx) (1) ++#define default_MCA_polarity(idx) (0) ++ ++static int __init MPBIOS_polarity(int idx) ++{ ++ int bus = mp_irqs[idx].mpc_srcbus; ++ int polarity; ++ ++ /* ++ * Determine IRQ line polarity (high active or low active): ++ */ ++ switch (mp_irqs[idx].mpc_irqflag & 3) ++ { ++ case 0: /* conforms, ie. bus-type dependent polarity */ ++ { ++ switch (mp_bus_id_to_type[bus]) ++ { ++ case MP_BUS_ISA: /* ISA pin */ ++ { ++ polarity = default_ISA_polarity(idx); ++ break; ++ } ++ case MP_BUS_EISA: /* EISA pin */ ++ { ++ polarity = default_EISA_polarity(idx); ++ break; ++ } ++ case MP_BUS_PCI: /* PCI pin */ ++ { ++ polarity = default_PCI_polarity(idx); ++ break; ++ } ++ case MP_BUS_MCA: /* MCA pin */ ++ { ++ polarity = default_MCA_polarity(idx); ++ break; ++ } ++ default: ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ polarity = 1; ++ break; ++ } ++ } ++ break; ++ } ++ case 1: /* high active */ ++ { ++ polarity = 0; ++ break; ++ } ++ case 2: /* reserved */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ polarity = 1; ++ break; ++ } ++ case 3: /* low active */ ++ { ++ polarity = 1; ++ break; ++ } ++ default: /* invalid */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ polarity = 1; ++ break; ++ } ++ } ++ return polarity; ++} ++ ++static int MPBIOS_trigger(int idx) ++{ ++ int bus = mp_irqs[idx].mpc_srcbus; ++ int trigger; ++ ++ /* ++ * Determine IRQ trigger mode (edge or level sensitive): ++ */ ++ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) ++ { ++ case 0: /* conforms, ie. bus-type dependent */ ++ { ++ switch (mp_bus_id_to_type[bus]) ++ { ++ case MP_BUS_ISA: /* ISA pin */ ++ { ++ trigger = default_ISA_trigger(idx); ++ break; ++ } ++ case MP_BUS_EISA: /* EISA pin */ ++ { ++ trigger = default_EISA_trigger(idx); ++ break; ++ } ++ case MP_BUS_PCI: /* PCI pin */ ++ { ++ trigger = default_PCI_trigger(idx); ++ break; ++ } ++ case MP_BUS_MCA: /* MCA pin */ ++ { ++ trigger = default_MCA_trigger(idx); ++ break; ++ } ++ default: ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ trigger = 1; ++ break; ++ } ++ } ++ break; ++ } ++ case 1: /* edge */ ++ { ++ trigger = 0; ++ break; ++ } ++ case 2: /* reserved */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ trigger = 1; ++ break; ++ } ++ case 3: /* level */ ++ { ++ trigger = 1; ++ break; ++ } ++ default: /* invalid */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ trigger = 0; ++ break; ++ } ++ } ++ return trigger; ++} ++ ++static inline int irq_polarity(int idx) ++{ ++ return MPBIOS_polarity(idx); ++} ++ ++static inline int irq_trigger(int idx) ++{ ++ return MPBIOS_trigger(idx); ++} ++ ++static int pin_2_irq(int idx, int apic, int pin) ++{ ++ int irq, i; ++ int bus = mp_irqs[idx].mpc_srcbus; ++ ++ /* ++ * Debugging check, we are in big trouble if this message pops up! ++ */ ++ if (mp_irqs[idx].mpc_dstirq != pin) ++ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); ++ ++ switch (mp_bus_id_to_type[bus]) ++ { ++ case MP_BUS_ISA: /* ISA pin */ ++ case MP_BUS_EISA: ++ case MP_BUS_MCA: ++ { ++ irq = mp_irqs[idx].mpc_srcbusirq; ++ break; ++ } ++ case MP_BUS_PCI: /* PCI pin */ ++ { ++ /* ++ * PCI IRQs are mapped in order ++ */ ++ i = irq = 0; ++ while (i < apic) ++ irq += nr_ioapic_registers[i++]; ++ irq += pin; ++ ++ /* ++ * For MPS mode, so far only needed by ES7000 platform ++ */ ++ if (ioapic_renumber_irq) ++ irq = ioapic_renumber_irq(apic, irq); ++ ++ break; ++ } ++ default: ++ { ++ printk(KERN_ERR "unknown bus type %d.\n",bus); ++ irq = 0; ++ break; ++ } ++ } ++ ++ /* ++ * PCI IRQ command line redirection. Yes, limits are hardcoded. ++ */ ++ if ((pin >= 16) && (pin <= 23)) { ++ if (pirq_entries[pin-16] != -1) { ++ if (!pirq_entries[pin-16]) { ++ apic_printk(APIC_VERBOSE, KERN_DEBUG ++ "disabling PIRQ%d\n", pin-16); ++ } else { ++ irq = pirq_entries[pin-16]; ++ apic_printk(APIC_VERBOSE, KERN_DEBUG ++ "using PIRQ%d -> IRQ %d\n", ++ pin-16, irq); ++ } ++ } ++ } ++ return irq; ++} ++ ++static inline int IO_APIC_irq_trigger(int irq) ++{ ++ int apic, idx, pin; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ idx = find_irq_entry(apic,pin,mp_INT); ++ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) ++ return irq_trigger(idx); ++ } ++ } ++ /* ++ * nonexistent IRQs are edge default ++ */ ++ return 0; ++} ++ ++/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ ++static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; /* = { FIRST_DEVICE_VECTOR , 0 }; */ ++ ++static int __assign_irq_vector(int irq) ++{ ++ int vector; ++ struct physdev_irq irq_op; ++ ++ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); ++ ++ if (irq_vector[irq] > 0) ++ return irq_vector[irq]; ++ irq_op.irq = irq; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) ++ return -ENOSPC; ++ ++ vector = irq_op.vector; ++ irq_vector[irq] = vector; ++ ++ return vector; ++} ++ ++static int assign_irq_vector(int irq) ++{ ++ unsigned long flags; ++ int vector; ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = __assign_irq_vector(irq); ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ return vector; ++} ++#ifndef CONFIG_XEN ++static struct irq_chip ioapic_chip; ++ ++#define IOAPIC_AUTO -1 ++#define IOAPIC_EDGE 0 ++#define IOAPIC_LEVEL 1 ++ ++static void ioapic_register_intr(int irq, int vector, unsigned long trigger) ++{ ++ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || ++ trigger == IOAPIC_LEVEL) ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_fasteoi_irq, "fasteoi"); ++ else { ++ irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_edge_irq, "edge"); ++ } ++ set_intr_gate(vector, interrupt[irq]); ++} ++#else ++#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0) ++#endif ++ ++static void __init setup_IO_APIC_irqs(void) ++{ ++ struct IO_APIC_route_entry entry; ++ int apic, pin, idx, irq, first_notcon = 1, vector; ++ unsigned long flags; ++ ++ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ ++ /* ++ * add it to the IO-APIC irq-routing table: ++ */ ++ memset(&entry,0,sizeof(entry)); ++ ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.dest_mode = INT_DEST_MODE; ++ entry.mask = 0; /* enable IRQ */ ++ entry.dest.logical.logical_dest = ++ cpu_mask_to_apicid(TARGET_CPUS); ++ ++ idx = find_irq_entry(apic,pin,mp_INT); ++ if (idx == -1) { ++ if (first_notcon) { ++ apic_printk(APIC_VERBOSE, KERN_DEBUG ++ " IO-APIC (apicid-pin) %d-%d", ++ mp_ioapics[apic].mpc_apicid, ++ pin); ++ first_notcon = 0; ++ } else ++ apic_printk(APIC_VERBOSE, ", %d-%d", ++ mp_ioapics[apic].mpc_apicid, pin); ++ continue; ++ } ++ ++ entry.trigger = irq_trigger(idx); ++ entry.polarity = irq_polarity(idx); ++ ++ if (irq_trigger(idx)) { ++ entry.trigger = 1; ++ entry.mask = 1; ++ } ++ ++ irq = pin_2_irq(idx, apic, pin); ++ /* ++ * skip adding the timer int on secondary nodes, which causes ++ * a small but painful rift in the time-space continuum ++ */ ++ if (multi_timer_check(apic, irq)) ++ continue; ++ else ++ add_pin_to_irq(irq, apic, pin); ++ ++ if (/*!apic &&*/ !IO_APIC_IRQ(irq)) ++ continue; ++ ++ if (IO_APIC_IRQ(irq)) { ++ vector = assign_irq_vector(irq); ++ entry.vector = vector; ++ ioapic_register_intr(irq, vector, IOAPIC_AUTO); ++ ++ if (!apic && (irq < 16)) ++ disable_8259A_irq(irq); ++ } ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, entry); ++ set_native_irq_info(irq, TARGET_CPUS); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ } ++ } ++ ++ if (!first_notcon) ++ apic_printk(APIC_VERBOSE, " not connected.\n"); ++} ++ ++/* ++ * Set up the 8259A-master output pin: ++ */ ++#ifndef CONFIG_XEN ++static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) ++{ ++ struct IO_APIC_route_entry entry; ++ ++ memset(&entry,0,sizeof(entry)); ++ ++ disable_8259A_irq(0); ++ ++ /* mask LVT0 */ ++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); ++ ++ /* ++ * We use logical delivery to get the timer IRQ ++ * to the first CPU. ++ */ ++ entry.dest_mode = INT_DEST_MODE; ++ entry.mask = 0; /* unmask IRQ now */ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.polarity = 0; ++ entry.trigger = 0; ++ entry.vector = vector; ++ ++ /* ++ * The timer IRQ doesn't have to know that behind the ++ * scene we have a 8259A-master in AEOI mode ... ++ */ ++ irq_desc[0].chip = &ioapic_chip; ++ set_irq_handler(0, handle_edge_irq); ++ ++ /* ++ * Add it to the IO-APIC irq-routing table: ++ */ ++ ioapic_write_entry(apic, pin, entry); ++ ++ enable_8259A_irq(0); ++} ++ ++static inline void UNEXPECTED_IO_APIC(void) ++{ ++} ++ ++void __init print_IO_APIC(void) ++{ ++ int apic, i; ++ union IO_APIC_reg_00 reg_00; ++ union IO_APIC_reg_01 reg_01; ++ union IO_APIC_reg_02 reg_02; ++ union IO_APIC_reg_03 reg_03; ++ unsigned long flags; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); ++ for (i = 0; i < nr_ioapics; i++) ++ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", ++ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); ++ ++ /* ++ * We are a bit conservative about what we expect. We have to ++ * know about every hardware change ASAP. ++ */ ++ printk(KERN_INFO "testing the IO APIC.......................\n"); ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(apic, 0); ++ reg_01.raw = io_apic_read(apic, 1); ++ if (reg_01.bits.version >= 0x10) ++ reg_02.raw = io_apic_read(apic, 2); ++ if (reg_01.bits.version >= 0x20) ++ reg_03.raw = io_apic_read(apic, 3); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); ++ printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); ++ printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); ++ printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); ++ printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); ++ if (reg_00.bits.ID >= get_physical_broadcast()) ++ UNEXPECTED_IO_APIC(); ++ if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ ++ printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); ++ printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); ++ if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ ++ (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ ++ (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ ++ (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ ++ (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ ++ (reg_01.bits.entries != 0x2E) && ++ (reg_01.bits.entries != 0x3F) ++ ) ++ UNEXPECTED_IO_APIC(); ++ ++ printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); ++ printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); ++ if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ ++ (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ ++ (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ ++ (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ ++ (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ ++ ) ++ UNEXPECTED_IO_APIC(); ++ if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ ++ /* ++ * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02, ++ * but the value of reg_02 is read as the previous read register ++ * value, so ignore it if reg_02 == reg_01. ++ */ ++ if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { ++ printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); ++ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); ++ if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ } ++ ++ /* ++ * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02 ++ * or reg_03, but the value of reg_0[23] is read as the previous read ++ * register value, so ignore it if reg_03 == reg_0[12]. ++ */ ++ if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw && ++ reg_03.raw != reg_01.raw) { ++ printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); ++ printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); ++ if (reg_03.bits.__reserved_1) ++ UNEXPECTED_IO_APIC(); ++ } ++ ++ printk(KERN_DEBUG ".... IRQ redirection table:\n"); ++ ++ printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" ++ " Stat Dest Deli Vect: \n"); ++ ++ for (i = 0; i <= reg_01.bits.entries; i++) { ++ struct IO_APIC_route_entry entry; ++ ++ entry = ioapic_read_entry(apic, i); ++ ++ printk(KERN_DEBUG " %02x %03X %02X ", ++ i, ++ entry.dest.logical.logical_dest, ++ entry.dest.physical.physical_dest ++ ); ++ ++ printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", ++ entry.mask, ++ entry.trigger, ++ entry.irr, ++ entry.polarity, ++ entry.delivery_status, ++ entry.dest_mode, ++ entry.delivery_mode, ++ entry.vector ++ ); ++ } ++ } ++ printk(KERN_DEBUG "IRQ to pin mappings:\n"); ++ for (i = 0; i < NR_IRQS; i++) { ++ struct irq_pin_list *entry = irq_2_pin + i; ++ if (entry->pin < 0) ++ continue; ++ printk(KERN_DEBUG "IRQ%d ", i); ++ for (;;) { ++ printk("-> %d:%d", entry->apic, entry->pin); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++ printk("\n"); ++ } ++ ++ printk(KERN_INFO ".................................... done.\n"); ++ ++ return; ++} ++ ++#if 0 ++ ++static void print_APIC_bitfield (int base) ++{ ++ unsigned int v; ++ int i, j; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); ++ for (i = 0; i < 8; i++) { ++ v = apic_read(base + i*0x10); ++ for (j = 0; j < 32; j++) { ++ if (v & (1<<j)) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ printk("\n"); ++ } ++} ++ ++void /*__init*/ print_local_APIC(void * dummy) ++{ ++ unsigned int v, ver, maxlvt; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", ++ smp_processor_id(), hard_smp_processor_id()); ++ v = apic_read(APIC_ID); ++ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v)); ++ v = apic_read(APIC_LVR); ++ printk(KERN_INFO "... APIC VERSION: %08x\n", v); ++ ver = GET_APIC_VERSION(v); ++ maxlvt = get_maxlvt(); ++ ++ v = apic_read(APIC_TASKPRI); ++ printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); ++ ++ if (APIC_INTEGRATED(ver)) { /* !82489DX */ ++ v = apic_read(APIC_ARBPRI); ++ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, ++ v & APIC_ARBPRI_MASK); ++ v = apic_read(APIC_PROCPRI); ++ printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); ++ } ++ ++ v = apic_read(APIC_EOI); ++ printk(KERN_DEBUG "... APIC EOI: %08x\n", v); ++ v = apic_read(APIC_RRR); ++ printk(KERN_DEBUG "... APIC RRR: %08x\n", v); ++ v = apic_read(APIC_LDR); ++ printk(KERN_DEBUG "... APIC LDR: %08x\n", v); ++ v = apic_read(APIC_DFR); ++ printk(KERN_DEBUG "... APIC DFR: %08x\n", v); ++ v = apic_read(APIC_SPIV); ++ printk(KERN_DEBUG "... APIC SPIV: %08x\n", v); ++ ++ printk(KERN_DEBUG "... APIC ISR field:\n"); ++ print_APIC_bitfield(APIC_ISR); ++ printk(KERN_DEBUG "... APIC TMR field:\n"); ++ print_APIC_bitfield(APIC_TMR); ++ printk(KERN_DEBUG "... APIC IRR field:\n"); ++ print_APIC_bitfield(APIC_IRR); ++ ++ if (APIC_INTEGRATED(ver)) { /* !82489DX */ ++ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ ++ apic_write(APIC_ESR, 0); ++ v = apic_read(APIC_ESR); ++ printk(KERN_DEBUG "... APIC ESR: %08x\n", v); ++ } ++ ++ v = apic_read(APIC_ICR); ++ printk(KERN_DEBUG "... APIC ICR: %08x\n", v); ++ v = apic_read(APIC_ICR2); ++ printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); ++ ++ v = apic_read(APIC_LVTT); ++ printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); ++ ++ if (maxlvt > 3) { /* PC is LVT#4. */ ++ v = apic_read(APIC_LVTPC); ++ printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); ++ } ++ v = apic_read(APIC_LVT0); ++ printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); ++ v = apic_read(APIC_LVT1); ++ printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); ++ ++ if (maxlvt > 2) { /* ERR is LVT#3. */ ++ v = apic_read(APIC_LVTERR); ++ printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); ++ } ++ ++ v = apic_read(APIC_TMICT); ++ printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); ++ v = apic_read(APIC_TMCCT); ++ printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); ++ v = apic_read(APIC_TDCR); ++ printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); ++ printk("\n"); ++} ++ ++void print_all_local_APICs (void) ++{ ++ on_each_cpu(print_local_APIC, NULL, 1, 1); ++} ++ ++void /*__init*/ print_PIC(void) ++{ ++ unsigned int v; ++ unsigned long flags; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "\nprinting PIC contents\n"); ++ ++ spin_lock_irqsave(&i8259A_lock, flags); ++ ++ v = inb(0xa1) << 8 | inb(0x21); ++ printk(KERN_DEBUG "... PIC IMR: %04x\n", v); ++ ++ v = inb(0xa0) << 8 | inb(0x20); ++ printk(KERN_DEBUG "... PIC IRR: %04x\n", v); ++ ++ outb(0x0b,0xa0); ++ outb(0x0b,0x20); ++ v = inb(0xa0) << 8 | inb(0x20); ++ outb(0x0a,0xa0); ++ outb(0x0a,0x20); ++ ++ spin_unlock_irqrestore(&i8259A_lock, flags); ++ ++ printk(KERN_DEBUG "... PIC ISR: %04x\n", v); ++ ++ v = inb(0x4d1) << 8 | inb(0x4d0); ++ printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); ++} ++ ++#endif /* 0 */ ++ ++#else ++void __init print_IO_APIC(void) { } ++#endif /* !CONFIG_XEN */ ++ ++static void __init enable_IO_APIC(void) ++{ ++ union IO_APIC_reg_01 reg_01; ++ int i8259_apic, i8259_pin; ++ int i, apic; ++ unsigned long flags; ++ ++ for (i = 0; i < PIN_MAP_SIZE; i++) { ++ irq_2_pin[i].pin = -1; ++ irq_2_pin[i].next = 0; ++ } ++ if (!pirqs_enabled) ++ for (i = 0; i < MAX_PIRQS; i++) ++ pirq_entries[i] = -1; ++ ++ /* ++ * The number of IO-APIC IRQ registers (== #pins): ++ */ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(apic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ nr_ioapic_registers[apic] = reg_01.bits.entries+1; ++ } ++ for(apic = 0; apic < nr_ioapics; apic++) { ++ int pin; ++ /* See if any of the pins is in ExtINT mode */ ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ struct IO_APIC_route_entry entry; ++ entry = ioapic_read_entry(apic, pin); ++ ++ ++ /* If the interrupt line is enabled and in ExtInt mode ++ * I have found the pin where the i8259 is connected. ++ */ ++ if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) { ++ ioapic_i8259.apic = apic; ++ ioapic_i8259.pin = pin; ++ goto found_i8259; ++ } ++ } ++ } ++ found_i8259: ++ /* Look to see what if the MP table has reported the ExtINT */ ++ /* If we could not find the appropriate pin by looking at the ioapic ++ * the i8259 probably is not connected the ioapic but give the ++ * mptable a chance anyway. ++ */ ++ i8259_pin = find_isa_irq_pin(0, mp_ExtINT); ++ i8259_apic = find_isa_irq_apic(0, mp_ExtINT); ++ /* Trust the MP table if nothing is setup in the hardware */ ++ if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) { ++ printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n"); ++ ioapic_i8259.pin = i8259_pin; ++ ioapic_i8259.apic = i8259_apic; ++ } ++ /* Complain if the MP table and the hardware disagree */ ++ if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) && ++ (i8259_pin >= 0) && (ioapic_i8259.pin >= 0)) ++ { ++ printk(KERN_WARNING "ExtINT in hardware and MP table differ\n"); ++ } ++ ++ /* ++ * Do not trust the IO-APIC being empty at bootup ++ */ ++ clear_IO_APIC(); ++} ++ ++/* ++ * Not an __init, needed by the reboot code ++ */ ++void disable_IO_APIC(void) ++{ ++ /* ++ * Clear the IO-APIC before rebooting: ++ */ ++ clear_IO_APIC(); ++ ++#ifndef CONFIG_XEN ++ /* ++ * If the i8259 is routed through an IOAPIC ++ * Put that IOAPIC in virtual wire mode ++ * so legacy interrupts can be delivered. ++ */ ++ if (ioapic_i8259.pin != -1) { ++ struct IO_APIC_route_entry entry; ++ ++ memset(&entry, 0, sizeof(entry)); ++ entry.mask = 0; /* Enabled */ ++ entry.trigger = 0; /* Edge */ ++ entry.irr = 0; ++ entry.polarity = 0; /* High */ ++ entry.delivery_status = 0; ++ entry.dest_mode = 0; /* Physical */ ++ entry.delivery_mode = dest_ExtINT; /* ExtInt */ ++ entry.vector = 0; ++ entry.dest.physical.physical_dest = ++ GET_APIC_ID(apic_read(APIC_ID)); ++ ++ /* ++ * Add it to the IO-APIC irq-routing table: ++ */ ++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); ++ } ++ disconnect_bsp_APIC(ioapic_i8259.pin != -1); ++#endif ++} ++ ++/* ++ * function to set the IO-APIC physical IDs based on the ++ * values stored in the MPC table. ++ * ++ * by Matt Domsch <Matt_Domsch@dell.com> Tue Dec 21 12:25:05 CST 1999 ++ */ ++ ++#if !defined(CONFIG_XEN) && !defined(CONFIG_X86_NUMAQ) ++static void __init setup_ioapic_ids_from_mpc(void) ++{ ++ union IO_APIC_reg_00 reg_00; ++ physid_mask_t phys_id_present_map; ++ int apic; ++ int i; ++ unsigned char old_id; ++ unsigned long flags; ++ ++ /* ++ * Don't check I/O APIC IDs for xAPIC systems. They have ++ * no meaning without the serial APIC bus. ++ */ ++ if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) ++ || APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) ++ return; ++ /* ++ * This is broken; anything with a real cpu count has to ++ * circumvent this idiocy regardless. ++ */ ++ phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map); ++ ++ /* ++ * Set the IOAPIC ID to the value stored in the MPC table. ++ */ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ ++ /* Read the register 0 value */ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(apic, 0); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ old_id = mp_ioapics[apic].mpc_apicid; ++ ++ if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) { ++ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", ++ apic, mp_ioapics[apic].mpc_apicid); ++ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", ++ reg_00.bits.ID); ++ mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; ++ } ++ ++ /* ++ * Sanity check, is the ID really free? Every APIC in a ++ * system must have a unique ID or we get lots of nice ++ * 'stuck on smp_invalidate_needed IPI wait' messages. ++ */ ++ if (check_apicid_used(phys_id_present_map, ++ mp_ioapics[apic].mpc_apicid)) { ++ printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", ++ apic, mp_ioapics[apic].mpc_apicid); ++ for (i = 0; i < get_physical_broadcast(); i++) ++ if (!physid_isset(i, phys_id_present_map)) ++ break; ++ if (i >= get_physical_broadcast()) ++ panic("Max APIC ID exceeded!\n"); ++ printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", ++ i); ++ physid_set(i, phys_id_present_map); ++ mp_ioapics[apic].mpc_apicid = i; ++ } else { ++ physid_mask_t tmp; ++ tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); ++ apic_printk(APIC_VERBOSE, "Setting %d in the " ++ "phys_id_present_map\n", ++ mp_ioapics[apic].mpc_apicid); ++ physids_or(phys_id_present_map, phys_id_present_map, tmp); ++ } ++ ++ ++ /* ++ * We need to adjust the IRQ routing table ++ * if the ID changed. ++ */ ++ if (old_id != mp_ioapics[apic].mpc_apicid) ++ for (i = 0; i < mp_irq_entries; i++) ++ if (mp_irqs[i].mpc_dstapic == old_id) ++ mp_irqs[i].mpc_dstapic ++ = mp_ioapics[apic].mpc_apicid; ++ ++ /* ++ * Read the right value from the MPC table and ++ * write it into the ID register. ++ */ ++ apic_printk(APIC_VERBOSE, KERN_INFO ++ "...changing IO-APIC physical APIC ID to %d ...", ++ mp_ioapics[apic].mpc_apicid); ++ ++ reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0, reg_00.raw); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ /* ++ * Sanity check ++ */ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(apic, 0); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) ++ printk("could not set ID!\n"); ++ else ++ apic_printk(APIC_VERBOSE, " ok.\n"); ++ } ++} ++#else ++static void __init setup_ioapic_ids_from_mpc(void) { } ++#endif ++ ++static int no_timer_check __initdata; ++ ++static int __init notimercheck(char *s) ++{ ++ no_timer_check = 1; ++ return 1; ++} ++__setup("no_timer_check", notimercheck); ++ ++#ifndef CONFIG_XEN ++/* ++ * There is a nasty bug in some older SMP boards, their mptable lies ++ * about the timer IRQ. We do the following to work around the situation: ++ * ++ * - timer IRQ defaults to IO-APIC IRQ ++ * - if this function detects that timer IRQs are defunct, then we fall ++ * back to ISA timer IRQs ++ */ ++int __init timer_irq_works(void) ++{ ++ unsigned long t1 = jiffies; ++ ++ if (no_timer_check) ++ return 1; ++ ++ local_irq_enable(); ++ /* Let ten ticks pass... */ ++ mdelay((10 * 1000) / HZ); ++ ++ /* ++ * Expect a few ticks at least, to be sure some possible ++ * glue logic does not lock up after one or two first ++ * ticks in a non-ExtINT mode. Also the local APIC ++ * might have cached one ExtINT interrupt. Finally, at ++ * least one tick may be lost due to delays. ++ */ ++ if (jiffies - t1 > 4) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * In the SMP+IOAPIC case it might happen that there are an unspecified ++ * number of pending IRQ events unhandled. These cases are very rare, ++ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much ++ * better to do it this way as thus we do not have to be aware of ++ * 'pending' interrupts in the IRQ path, except at this point. ++ */ ++/* ++ * Edge triggered needs to resend any interrupt ++ * that was delayed but this is now handled in the device ++ * independent code. ++ */ ++ ++/* ++ * Startup quirk: ++ * ++ * Starting up a edge-triggered IO-APIC interrupt is ++ * nasty - we need to make sure that we get the edge. ++ * If it is already asserted for some reason, we need ++ * return 1 to indicate that is was pending. ++ * ++ * This is not complete - we should be able to fake ++ * an edge even if it isn't on the 8259A... ++ * ++ * (We do this for level-triggered IRQs too - it cannot hurt.) ++ */ ++static unsigned int startup_ioapic_irq(unsigned int irq) ++{ ++ int was_pending = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ if (irq < 16) { ++ disable_8259A_irq(irq); ++ if (i8259A_irq_pending(irq)) ++ was_pending = 1; ++ } ++ __unmask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return was_pending; ++} ++ ++static void ack_ioapic_irq(unsigned int irq) ++{ ++ move_native_irq(irq); ++ ack_APIC_irq(); ++} ++ ++static void ack_ioapic_quirk_irq(unsigned int irq) ++{ ++ unsigned long v; ++ int i; ++ ++ move_native_irq(irq); ++/* ++ * It appears there is an erratum which affects at least version 0x11 ++ * of I/O APIC (that's the 82093AA and cores integrated into various ++ * chipsets). Under certain conditions a level-triggered interrupt is ++ * erroneously delivered as edge-triggered one but the respective IRR ++ * bit gets set nevertheless. As a result the I/O unit expects an EOI ++ * message but it will never arrive and further interrupts are blocked ++ * from the source. The exact reason is so far unknown, but the ++ * phenomenon was observed when two consecutive interrupt requests ++ * from a given source get delivered to the same CPU and the source is ++ * temporarily disabled in between. ++ * ++ * A workaround is to simulate an EOI message manually. We achieve it ++ * by setting the trigger mode to edge and then to level when the edge ++ * trigger mode gets detected in the TMR of a local APIC for a ++ * level-triggered interrupt. We mask the source for the time of the ++ * operation to prevent an edge-triggered interrupt escaping meanwhile. ++ * The idea is from Manfred Spraul. --macro ++ */ ++ i = irq_vector[irq]; ++ ++ v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); ++ ++ ack_APIC_irq(); ++ ++ if (!(v & (1 << (i & 0x1f)))) { ++ atomic_inc(&irq_mis_count); ++ spin_lock(&ioapic_lock); ++ __mask_and_edge_IO_APIC_irq(irq); ++ __unmask_and_level_IO_APIC_irq(irq); ++ spin_unlock(&ioapic_lock); ++ } ++} ++ ++static int ioapic_retrigger_irq(unsigned int irq) ++{ ++ send_IPI_self(irq_vector[irq]); ++ ++ return 1; ++} ++ ++static struct irq_chip ioapic_chip __read_mostly = { ++ .name = "IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = mask_IO_APIC_irq, ++ .unmask = unmask_IO_APIC_irq, ++ .ack = ack_ioapic_irq, ++ .eoi = ack_ioapic_quirk_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ioapic_affinity_irq, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++#endif /* !CONFIG_XEN */ ++ ++static inline void init_IO_APIC_traps(void) ++{ ++ int irq; ++ ++ /* ++ * NOTE! The local APIC isn't very good at handling ++ * multiple interrupts at the same interrupt level. ++ * As the interrupt level is determined by taking the ++ * vector number and shifting that right by 4, we ++ * want to spread these out a bit so that they don't ++ * all fall in the same interrupt level. ++ * ++ * Also, we've got to be careful not to trash gate ++ * 0x80, because int 0x80 is hm, kind of importantish. ;) ++ */ ++ for (irq = 0; irq < NR_IRQS ; irq++) { ++ int tmp = irq; ++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { ++ /* ++ * Hmm.. We don't have an entry for this, ++ * so default to an old-fashioned 8259 ++ * interrupt if we can.. ++ */ ++ if (irq < 16) ++ make_8259A_irq(irq); ++#ifndef CONFIG_XEN ++ else ++ /* Strange. Oh, well.. */ ++ irq_desc[irq].chip = &no_irq_chip; ++#endif ++ } ++ } ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * The local APIC irq-chip implementation: ++ */ ++ ++static void ack_apic(unsigned int irq) ++{ ++ ack_APIC_irq(); ++} ++ ++static void mask_lapic_irq (unsigned int irq) ++{ ++ unsigned long v; ++ ++ v = apic_read(APIC_LVT0); ++ apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); ++} ++ ++static void unmask_lapic_irq (unsigned int irq) ++{ ++ unsigned long v; ++ ++ v = apic_read(APIC_LVT0); ++ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); ++} ++ ++static struct irq_chip lapic_chip __read_mostly = { ++ .name = "local-APIC-edge", ++ .mask = mask_lapic_irq, ++ .unmask = unmask_lapic_irq, ++ .eoi = ack_apic, ++}; ++ ++static void setup_nmi (void) ++{ ++ /* ++ * Dirty trick to enable the NMI watchdog ... ++ * We put the 8259A master into AEOI mode and ++ * unmask on all local APICs LVT0 as NMI. ++ * ++ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire') ++ * is from Maciej W. Rozycki - so we do not have to EOI from ++ * the NMI handler or the timer interrupt. ++ */ ++ apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); ++ ++ on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); ++ ++ apic_printk(APIC_VERBOSE, " done.\n"); ++} ++ ++/* ++ * This looks a bit hackish but it's about the only one way of sending ++ * a few INTA cycles to 8259As and any associated glue logic. ICR does ++ * not support the ExtINT mode, unfortunately. We need to send these ++ * cycles as some i82489DX-based boards have glue logic that keeps the ++ * 8259A interrupt line asserted until INTA. --macro ++ */ ++static inline void unlock_ExtINT_logic(void) ++{ ++ int apic, pin, i; ++ struct IO_APIC_route_entry entry0, entry1; ++ unsigned char save_control, save_freq_select; ++ ++ pin = find_isa_irq_pin(8, mp_INT); ++ if (pin == -1) { ++ WARN_ON_ONCE(1); ++ return; ++ } ++ apic = find_isa_irq_apic(8, mp_INT); ++ if (apic == -1) { ++ WARN_ON_ONCE(1); ++ return; ++ } ++ ++ entry0 = ioapic_read_entry(apic, pin); ++ clear_IO_APIC_pin(apic, pin); ++ ++ memset(&entry1, 0, sizeof(entry1)); ++ ++ entry1.dest_mode = 0; /* physical delivery */ ++ entry1.mask = 0; /* unmask IRQ now */ ++ entry1.dest.physical.physical_dest = hard_smp_processor_id(); ++ entry1.delivery_mode = dest_ExtINT; ++ entry1.polarity = entry0.polarity; ++ entry1.trigger = 0; ++ entry1.vector = 0; ++ ++ ioapic_write_entry(apic, pin, entry1); ++ ++ save_control = CMOS_READ(RTC_CONTROL); ++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); ++ CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6, ++ RTC_FREQ_SELECT); ++ CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL); ++ ++ i = 100; ++ while (i-- > 0) { ++ mdelay(10); ++ if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF) ++ i -= 10; ++ } ++ ++ CMOS_WRITE(save_control, RTC_CONTROL); ++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); ++ clear_IO_APIC_pin(apic, pin); ++ ++ ioapic_write_entry(apic, pin, entry0); ++} ++#endif /* !CONFIG_XEN */ ++ ++int timer_uses_ioapic_pin_0; ++ ++#ifndef CONFIG_XEN ++/* ++ * This code may look a bit paranoid, but it's supposed to cooperate with ++ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ ++ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast ++ * fanatically on his truly buggy board. ++ */ ++static inline void __init check_timer(void) ++{ ++ int apic1, pin1, apic2, pin2; ++ int vector; ++ ++ /* ++ * get/set the timer IRQ vector: ++ */ ++ disable_8259A_irq(0); ++ vector = assign_irq_vector(0); ++ set_intr_gate(vector, interrupt[0]); ++ ++ /* ++ * Subtle, code in do_timer_interrupt() expects an AEOI ++ * mode for the 8259A whenever interrupts are routed ++ * through I/O APICs. Also IRQ0 has to be enabled in ++ * the 8259A which implies the virtual wire has to be ++ * disabled in the local APIC. ++ */ ++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); ++ init_8259A(1); ++ timer_ack = 1; ++ if (timer_over_8254 > 0) ++ enable_8259A_irq(0); ++ ++ pin1 = find_isa_irq_pin(0, mp_INT); ++ apic1 = find_isa_irq_apic(0, mp_INT); ++ pin2 = ioapic_i8259.pin; ++ apic2 = ioapic_i8259.apic; ++ ++ if (pin1 == 0) ++ timer_uses_ioapic_pin_0 = 1; ++ ++ printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", ++ vector, apic1, pin1, apic2, pin2); ++ ++ if (pin1 != -1) { ++ /* ++ * Ok, does IRQ0 through the IOAPIC work? ++ */ ++ unmask_IO_APIC_irq(0); ++ if (timer_irq_works()) { ++ if (nmi_watchdog == NMI_IO_APIC) { ++ disable_8259A_irq(0); ++ setup_nmi(); ++ enable_8259A_irq(0); ++ } ++ if (disable_timer_pin_1 > 0) ++ clear_IO_APIC_pin(0, pin1); ++ return; ++ } ++ clear_IO_APIC_pin(apic1, pin1); ++ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to " ++ "IO-APIC\n"); ++ } ++ ++ printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... "); ++ if (pin2 != -1) { ++ printk("\n..... (found pin %d) ...", pin2); ++ /* ++ * legacy devices should be connected to IO APIC #0 ++ */ ++ setup_ExtINT_IRQ0_pin(apic2, pin2, vector); ++ if (timer_irq_works()) { ++ printk("works.\n"); ++ if (pin1 != -1) ++ replace_pin_at_irq(0, apic1, pin1, apic2, pin2); ++ else ++ add_pin_to_irq(0, apic2, pin2); ++ if (nmi_watchdog == NMI_IO_APIC) { ++ setup_nmi(); ++ } ++ return; ++ } ++ /* ++ * Cleanup, just in case ... ++ */ ++ clear_IO_APIC_pin(apic2, pin2); ++ } ++ printk(" failed.\n"); ++ ++ if (nmi_watchdog == NMI_IO_APIC) { ++ printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); ++ nmi_watchdog = 0; ++ } ++ ++ printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); ++ ++ disable_8259A_irq(0); ++ set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq, ++ "fasteio"); ++ apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ ++ enable_8259A_irq(0); ++ ++ if (timer_irq_works()) { ++ printk(" works.\n"); ++ return; ++ } ++ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); ++ printk(" failed.\n"); ++ ++ printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); ++ ++ timer_ack = 0; ++ init_8259A(0); ++ make_8259A_irq(0); ++ apic_write_around(APIC_LVT0, APIC_DM_EXTINT); ++ ++ unlock_ExtINT_logic(); ++ ++ if (timer_irq_works()) { ++ printk(" works.\n"); ++ return; ++ } ++ printk(" failed :(.\n"); ++ panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " ++ "report. Then try booting with the 'noapic' option"); ++} ++#else ++#define check_timer() ((void)0) ++#endif /* CONFIG_XEN */ ++ ++/* ++ * ++ * IRQ's that are handled by the PIC in the MPS IOAPIC case. ++ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. ++ * Linux doesn't really care, as it's not actually used ++ * for any interrupt handling anyway. ++ */ ++#define PIC_IRQS (1 << PIC_CASCADE_IR) ++ ++void __init setup_IO_APIC(void) ++{ ++ enable_IO_APIC(); ++ ++ if (acpi_ioapic) ++ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ ++ else ++ io_apic_irqs = ~PIC_IRQS; ++ ++ printk("ENABLING IO-APIC IRQs\n"); ++ ++ /* ++ * Set up IO-APIC IRQ routing. ++ */ ++ if (!acpi_ioapic) ++ setup_ioapic_ids_from_mpc(); ++#ifndef CONFIG_XEN ++ sync_Arb_IDs(); ++#endif ++ setup_IO_APIC_irqs(); ++ init_IO_APIC_traps(); ++ check_timer(); ++ if (!acpi_ioapic) ++ print_IO_APIC(); ++} ++ ++static int __init setup_disable_8254_timer(char *s) ++{ ++ timer_over_8254 = -1; ++ return 1; ++} ++static int __init setup_enable_8254_timer(char *s) ++{ ++ timer_over_8254 = 2; ++ return 1; ++} ++ ++__setup("disable_8254_timer", setup_disable_8254_timer); ++__setup("enable_8254_timer", setup_enable_8254_timer); ++ ++/* ++ * Called after all the initialization is done. If we didnt find any ++ * APIC bugs then we can allow the modify fast path ++ */ ++ ++static int __init io_apic_bug_finalize(void) ++{ ++ if(sis_apic_bug == -1) ++ sis_apic_bug = 0; ++ if (is_initial_xendomain()) { ++ struct xen_platform_op op = { .cmd = XENPF_platform_quirk }; ++ op.u.platform_quirk.quirk_id = sis_apic_bug ? ++ QUIRK_IOAPIC_BAD_REGSEL : QUIRK_IOAPIC_GOOD_REGSEL; ++ HYPERVISOR_platform_op(&op); ++ } ++ return 0; ++} ++ ++late_initcall(io_apic_bug_finalize); ++ ++struct sysfs_ioapic_data { ++ struct sys_device dev; ++ struct IO_APIC_route_entry entry[0]; ++}; ++static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; ++ ++static int ioapic_suspend(struct sys_device *dev, pm_message_t state) ++{ ++ struct IO_APIC_route_entry *entry; ++ struct sysfs_ioapic_data *data; ++ int i; ++ ++ data = container_of(dev, struct sysfs_ioapic_data, dev); ++ entry = data->entry; ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) ++ entry[i] = ioapic_read_entry(dev->id, i); ++ ++ return 0; ++} ++ ++static int ioapic_resume(struct sys_device *dev) ++{ ++ struct IO_APIC_route_entry *entry; ++ struct sysfs_ioapic_data *data; ++ unsigned long flags; ++ union IO_APIC_reg_00 reg_00; ++ int i; ++ ++ data = container_of(dev, struct sysfs_ioapic_data, dev); ++ entry = data->entry; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(dev->id, 0); ++ if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { ++ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; ++ io_apic_write(dev->id, 0, reg_00.raw); ++ } ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) ++ ioapic_write_entry(dev->id, i, entry[i]); ++ ++ return 0; ++} ++ ++static struct sysdev_class ioapic_sysdev_class = { ++ set_kset_name("ioapic"), ++ .suspend = ioapic_suspend, ++ .resume = ioapic_resume, ++}; ++ ++static int __init ioapic_init_sysfs(void) ++{ ++ struct sys_device * dev; ++ int i, size, error = 0; ++ ++ error = sysdev_class_register(&ioapic_sysdev_class); ++ if (error) ++ return error; ++ ++ for (i = 0; i < nr_ioapics; i++ ) { ++ size = sizeof(struct sys_device) + nr_ioapic_registers[i] ++ * sizeof(struct IO_APIC_route_entry); ++ mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); ++ if (!mp_ioapic_data[i]) { ++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); ++ continue; ++ } ++ memset(mp_ioapic_data[i], 0, size); ++ dev = &mp_ioapic_data[i]->dev; ++ dev->id = i; ++ dev->cls = &ioapic_sysdev_class; ++ error = sysdev_register(dev); ++ if (error) { ++ kfree(mp_ioapic_data[i]); ++ mp_ioapic_data[i] = NULL; ++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); ++ continue; ++ } ++ } ++ ++ return 0; ++} ++ ++device_initcall(ioapic_init_sysfs); ++ ++/* ++ * Dynamic irq allocate and deallocation ++ */ ++int create_irq(void) ++{ ++ /* Allocate an unused irq */ ++ int irq, new, vector = 0; ++ unsigned long flags; ++ ++ irq = -ENOSPC; ++ spin_lock_irqsave(&vector_lock, flags); ++ for (new = (NR_IRQS - 1); new >= 0; new--) { ++ if (platform_legacy_irq(new)) ++ continue; ++ if (irq_vector[new] != 0) ++ continue; ++ vector = __assign_irq_vector(new); ++ if (likely(vector > 0)) ++ irq = new; ++ break; ++ } ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ if (irq >= 0) { ++#ifndef CONFIG_XEN ++ set_intr_gate(vector, interrupt[irq]); ++#endif ++ dynamic_irq_init(irq); ++ } ++ return irq; ++} ++ ++void destroy_irq(unsigned int irq) ++{ ++ unsigned long flags; ++ ++ dynamic_irq_cleanup(irq); ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ irq_vector[irq] = 0; ++ spin_unlock_irqrestore(&vector_lock, flags); ++} ++ ++/* ++ * MSI mesage composition ++ */ ++#ifdef CONFIG_PCI_MSI ++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) ++{ ++ int vector; ++ unsigned dest; ++ ++ vector = assign_irq_vector(irq); ++ if (vector >= 0) { ++ dest = cpu_mask_to_apicid(TARGET_CPUS); ++ ++ msg->address_hi = MSI_ADDR_BASE_HI; ++ msg->address_lo = ++ MSI_ADDR_BASE_LO | ++ ((INT_DEST_MODE == 0) ? ++ MSI_ADDR_DEST_MODE_PHYSICAL: ++ MSI_ADDR_DEST_MODE_LOGICAL) | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_ADDR_REDIRECTION_CPU: ++ MSI_ADDR_REDIRECTION_LOWPRI) | ++ MSI_ADDR_DEST_ID(dest); ++ ++ msg->data = ++ MSI_DATA_TRIGGER_EDGE | ++ MSI_DATA_LEVEL_ASSERT | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_DATA_DELIVERY_FIXED: ++ MSI_DATA_DELIVERY_LOWPRI) | ++ MSI_DATA_VECTOR(vector); ++ } ++ return vector; ++} ++ ++#ifdef CONFIG_SMP ++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct msi_msg msg; ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ vector = assign_irq_vector(irq); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(mask); ++ ++ read_msi_msg(irq, &msg); ++ ++ msg.data &= ~MSI_DATA_VECTOR_MASK; ++ msg.data |= MSI_DATA_VECTOR(vector); ++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; ++ msg.address_lo |= MSI_ADDR_DEST_ID(dest); ++ ++ write_msi_msg(irq, &msg); ++ set_native_irq_info(irq, mask); ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, ++ * which implement the MSI or MSI-X Capability Structure. ++ */ ++static struct irq_chip msi_chip = { ++ .name = "PCI-MSI", ++ .unmask = unmask_msi_irq, ++ .mask = mask_msi_irq, ++ .ack = ack_ioapic_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_msi_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ struct msi_msg msg; ++ int ret; ++ ret = msi_compose_msg(dev, irq, &msg); ++ if (ret < 0) ++ return ret; ++ ++ write_msi_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, ++ "edge"); ++ ++ return 0; ++} ++ ++void arch_teardown_msi_irq(unsigned int irq) ++{ ++ return; ++} ++ ++#endif /* CONFIG_PCI_MSI */ ++ ++/* ++ * Hypertransport interrupt support ++ */ ++#ifdef CONFIG_HT_IRQ ++ ++#ifdef CONFIG_SMP ++ ++static void target_ht_irq(unsigned int irq, unsigned int dest) ++{ ++ struct ht_irq_msg msg; ++ fetch_ht_irq_msg(irq, &msg); ++ ++ msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK); ++ msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); ++ ++ msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest); ++ msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); ++ ++ write_ht_irq_msg(irq, &msg); ++} ++ ++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ unsigned int dest; ++ cpumask_t tmp; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ dest = cpu_mask_to_apicid(mask); ++ ++ target_ht_irq(irq, dest); ++ set_native_irq_info(irq, mask); ++} ++#endif ++ ++static struct irq_chip ht_irq_chip = { ++ .name = "PCI-HT", ++ .mask = mask_ht_irq, ++ .unmask = unmask_ht_irq, ++ .ack = ack_ioapic_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ht_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ int vector; ++ ++ vector = assign_irq_vector(irq); ++ if (vector >= 0) { ++ struct ht_irq_msg msg; ++ unsigned dest; ++ cpumask_t tmp; ++ ++ cpus_clear(tmp); ++ cpu_set(vector >> 8, tmp); ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); ++ ++ msg.address_lo = ++ HT_IRQ_LOW_BASE | ++ HT_IRQ_LOW_DEST_ID(dest) | ++ HT_IRQ_LOW_VECTOR(vector) | ++ ((INT_DEST_MODE == 0) ? ++ HT_IRQ_LOW_DM_PHYSICAL : ++ HT_IRQ_LOW_DM_LOGICAL) | ++ HT_IRQ_LOW_RQEOI_EDGE | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ HT_IRQ_LOW_MT_FIXED : ++ HT_IRQ_LOW_MT_ARBITRATED) | ++ HT_IRQ_LOW_IRQ_MASKED; ++ ++ write_ht_irq_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &ht_irq_chip, ++ handle_edge_irq, "edge"); ++ } ++ return vector; ++} ++#endif /* CONFIG_HT_IRQ */ ++ ++/* -------------------------------------------------------------------------- ++ ACPI-based IOAPIC Configuration ++ -------------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ACPI ++ ++int __init io_apic_get_unique_id (int ioapic, int apic_id) ++{ ++#ifndef CONFIG_XEN ++ union IO_APIC_reg_00 reg_00; ++ static physid_mask_t apic_id_map = PHYSID_MASK_NONE; ++ physid_mask_t tmp; ++ unsigned long flags; ++ int i = 0; ++ ++ /* ++ * The P4 platform supports up to 256 APIC IDs on two separate APIC ++ * buses (one for LAPICs, one for IOAPICs), where predecessors only ++ * supports up to 16 on one shared APIC bus. ++ * ++ * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full ++ * advantage of new APIC bus architecture. ++ */ ++ ++ if (physids_empty(apic_id_map)) ++ apic_id_map = ioapic_phys_id_map(phys_cpu_present_map); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(ioapic, 0); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ if (apic_id >= get_physical_broadcast()) { ++ printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " ++ "%d\n", ioapic, apic_id, reg_00.bits.ID); ++ apic_id = reg_00.bits.ID; ++ } ++ ++ /* ++ * Every APIC in a system must have a unique ID or we get lots of nice ++ * 'stuck on smp_invalidate_needed IPI wait' messages. ++ */ ++ if (check_apicid_used(apic_id_map, apic_id)) { ++ ++ for (i = 0; i < get_physical_broadcast(); i++) { ++ if (!check_apicid_used(apic_id_map, i)) ++ break; ++ } ++ ++ if (i == get_physical_broadcast()) ++ panic("Max apic_id exceeded!\n"); ++ ++ printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " ++ "trying %d\n", ioapic, apic_id, i); ++ ++ apic_id = i; ++ } ++ ++ tmp = apicid_to_cpu_present(apic_id); ++ physids_or(apic_id_map, apic_id_map, tmp); ++ ++ if (reg_00.bits.ID != apic_id) { ++ reg_00.bits.ID = apic_id; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(ioapic, 0, reg_00.raw); ++ reg_00.raw = io_apic_read(ioapic, 0); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ /* Sanity check */ ++ if (reg_00.bits.ID != apic_id) { ++ printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic); ++ return -1; ++ } ++ } ++ ++ apic_printk(APIC_VERBOSE, KERN_INFO ++ "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); ++#endif /* !CONFIG_XEN */ ++ ++ return apic_id; ++} ++ ++ ++int __init io_apic_get_version (int ioapic) ++{ ++ union IO_APIC_reg_01 reg_01; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(ioapic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return reg_01.bits.version; ++} ++ ++ ++int __init io_apic_get_redir_entries (int ioapic) ++{ ++ union IO_APIC_reg_01 reg_01; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(ioapic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return reg_01.bits.entries; ++} ++ ++ ++int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low) ++{ ++ struct IO_APIC_route_entry entry; ++ unsigned long flags; ++ ++ if (!IO_APIC_IRQ(irq)) { ++ printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ++ ioapic); ++ return -EINVAL; ++ } ++ ++ /* ++ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. ++ * Note that we mask (disable) IRQs now -- these get enabled when the ++ * corresponding device driver registers for this IRQ. ++ */ ++ ++ memset(&entry,0,sizeof(entry)); ++ ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.dest_mode = INT_DEST_MODE; ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ entry.trigger = edge_level; ++ entry.polarity = active_high_low; ++ entry.mask = 1; ++ ++ /* ++ * IRQs < 16 are already in the irq_2_pin[] map ++ */ ++ if (irq >= 16) ++ add_pin_to_irq(irq, ioapic, pin); ++ ++ entry.vector = assign_irq_vector(irq); ++ ++ apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " ++ "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, ++ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, ++ edge_level, active_high_low); ++ ++ ioapic_register_intr(irq, entry.vector, edge_level); ++ ++ if (!ioapic && (irq < 16)) ++ disable_8259A_irq(irq); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(ioapic, pin, entry); ++ set_native_irq_info(irq, TARGET_CPUS); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return 0; ++} ++ ++#endif /* CONFIG_ACPI */ ++ ++static int __init parse_disable_timer_pin_1(char *arg) ++{ ++ disable_timer_pin_1 = 1; ++ return 0; ++} ++early_param("disable_timer_pin_1", parse_disable_timer_pin_1); ++ ++static int __init parse_enable_timer_pin_1(char *arg) ++{ ++ disable_timer_pin_1 = -1; ++ return 0; ++} ++early_param("enable_timer_pin_1", parse_enable_timer_pin_1); ++ ++static int __init parse_noapic(char *arg) ++{ ++ /* disable IO-APIC */ ++ disable_ioapic_setup(); ++ return 0; ++} ++early_param("noapic", parse_noapic); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/ioport-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/ioport-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,122 @@ ++/* ++ * linux/arch/i386/kernel/ioport.c ++ * ++ * This contains the io-permission bitmap code - written by obz, with changes ++ * by Linus. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/capability.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/ioport.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/stddef.h> ++#include <linux/slab.h> ++#include <linux/thread_info.h> ++#include <xen/interface/physdev.h> ++ ++/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ ++static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) ++{ ++ unsigned long mask; ++ unsigned long *bitmap_base = bitmap + (base / BITS_PER_LONG); ++ unsigned int low_index = base & (BITS_PER_LONG-1); ++ int length = low_index + extent; ++ ++ if (low_index != 0) { ++ mask = (~0UL << low_index); ++ if (length < BITS_PER_LONG) ++ mask &= ~(~0UL << length); ++ if (new_value) ++ *bitmap_base++ |= mask; ++ else ++ *bitmap_base++ &= ~mask; ++ length -= BITS_PER_LONG; ++ } ++ ++ mask = (new_value ? ~0UL : 0UL); ++ while (length >= BITS_PER_LONG) { ++ *bitmap_base++ = mask; ++ length -= BITS_PER_LONG; ++ } ++ ++ if (length > 0) { ++ mask = ~(~0UL << length); ++ if (new_value) ++ *bitmap_base++ |= mask; ++ else ++ *bitmap_base++ &= ~mask; ++ } ++} ++ ++ ++/* ++ * this changes the io permissions bitmap in the current task. ++ */ ++asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++{ ++ struct thread_struct * t = ¤t->thread; ++ unsigned long *bitmap; ++ struct physdev_set_iobitmap set_iobitmap; ++ ++ if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) ++ return -EINVAL; ++ if (turn_on && !capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ ++ /* ++ * If it's the first ioperm() call in this thread's lifetime, set the ++ * IO bitmap up. ioperm() is much less timing critical than clone(), ++ * this is why we delay this operation until now: ++ */ ++ if (!t->io_bitmap_ptr) { ++ bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); ++ if (!bitmap) ++ return -ENOMEM; ++ ++ memset(bitmap, 0xff, IO_BITMAP_BYTES); ++ t->io_bitmap_ptr = bitmap; ++ set_thread_flag(TIF_IO_BITMAP); ++ ++ set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); ++ set_iobitmap.nr_ports = IO_BITMAP_BITS; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); ++ } ++ ++ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); ++ ++ return 0; ++} ++ ++/* ++ * sys_iopl has to be used when you want to access the IO ports ++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped ++ * you'd need 8kB of bitmaps/process, which is a bit excessive. ++ * ++ * Here we just change the eflags value on the stack: we allow ++ * only the super-user to do it. This depends on the stack-layout ++ * on system-call entry - see also fork() and the signal handling ++ * code. ++ */ ++ ++asmlinkage long sys_iopl(unsigned long unused) ++{ ++ volatile struct pt_regs * regs = (struct pt_regs *) &unused; ++ unsigned int level = regs->ebx; ++ struct thread_struct *t = ¤t->thread; ++ unsigned int old = (t->iopl >> 12) & 3; ++ ++ if (level > 3) ++ return -EINVAL; ++ /* Trying to gain more privileges? */ ++ if (level > old) { ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ } ++ t->iopl = level << 12; ++ set_iopl_mask(t->iopl); ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/irq.c +--- a/arch/i386/kernel/irq.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/irq.c Wed Aug 08 16:25:28 2007 -0300 +@@ -288,7 +288,9 @@ skip: + } + + #ifdef CONFIG_HOTPLUG_CPU ++#ifndef CONFIG_XEN + #include <mach_apic.h> ++#endif + + void fixup_irqs(cpumask_t map) + { +@@ -302,7 +304,9 @@ void fixup_irqs(cpumask_t map) + + cpus_and(mask, irq_desc[irq].affinity, map); + if (any_online_cpu(mask) == NR_CPUS) { ++#ifndef CONFIG_XEN + printk("Breaking affinity for irq %i\n", irq); ++#endif + mask = map; + } + if (irq_desc[irq].chip->set_affinity) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/ldt-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/ldt-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,268 @@ ++/* ++ * linux/arch/i386/kernel/ldt.c ++ * ++ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds ++ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> ++ */ ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/vmalloc.h> ++#include <linux/slab.h> ++ ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/ldt.h> ++#include <asm/desc.h> ++#include <asm/mmu_context.h> ++ ++#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ ++static void flush_ldt(void *null) ++{ ++ if (current->active_mm) ++ load_LDT(¤t->active_mm->context); ++} ++#endif ++ ++static int alloc_ldt(mm_context_t *pc, int mincount, int reload) ++{ ++ void *oldldt; ++ void *newldt; ++ int oldsize; ++ ++ if (mincount <= pc->size) ++ return 0; ++ oldsize = pc->size; ++ mincount = (mincount+511)&(~511); ++ if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) ++ newldt = vmalloc(mincount*LDT_ENTRY_SIZE); ++ else ++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); ++ ++ if (!newldt) ++ return -ENOMEM; ++ ++ if (oldsize) ++ memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); ++ oldldt = pc->ldt; ++ memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); ++ pc->ldt = newldt; ++ wmb(); ++ pc->size = mincount; ++ wmb(); ++ ++ if (reload) { ++#ifdef CONFIG_SMP ++ cpumask_t mask; ++ preempt_disable(); ++#endif ++ make_pages_readonly( ++ pc->ldt, ++ (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ load_LDT(pc); ++#ifdef CONFIG_SMP ++ mask = cpumask_of_cpu(smp_processor_id()); ++ if (!cpus_equal(current->mm->cpu_vm_mask, mask)) ++ smp_call_function(flush_ldt, NULL, 1, 1); ++ preempt_enable(); ++#endif ++ } ++ if (oldsize) { ++ make_pages_writable( ++ oldldt, ++ (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(oldldt); ++ else ++ kfree(oldldt); ++ } ++ return 0; ++} ++ ++static inline int copy_ldt(mm_context_t *new, mm_context_t *old) ++{ ++ int err = alloc_ldt(new, old->size, 0); ++ if (err < 0) ++ return err; ++ memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); ++ make_pages_readonly( ++ new->ldt, ++ (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ return 0; ++} ++ ++/* ++ * we do not have to muck with descriptors here, that is ++ * done in switch_mm() as needed. ++ */ ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ struct mm_struct * old_mm; ++ int retval = 0; ++ ++ init_MUTEX(&mm->context.sem); ++ mm->context.size = 0; ++ mm->context.has_foreign_mappings = 0; ++ old_mm = current->mm; ++ if (old_mm && old_mm->context.size > 0) { ++ down(&old_mm->context.sem); ++ retval = copy_ldt(&mm->context, &old_mm->context); ++ up(&old_mm->context.sem); ++ } ++ return retval; ++} ++ ++/* ++ * No need to lock the MM as we are the last user ++ */ ++void destroy_context(struct mm_struct *mm) ++{ ++ if (mm->context.size) { ++ if (mm == current->active_mm) ++ clear_LDT(); ++ make_pages_writable( ++ mm->context.ldt, ++ (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(mm->context.ldt); ++ else ++ kfree(mm->context.ldt); ++ mm->context.size = 0; ++ } ++} ++ ++static int read_ldt(void __user * ptr, unsigned long bytecount) ++{ ++ int err; ++ unsigned long size; ++ struct mm_struct * mm = current->mm; ++ ++ if (!mm->context.size) ++ return 0; ++ if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) ++ bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; ++ ++ down(&mm->context.sem); ++ size = mm->context.size*LDT_ENTRY_SIZE; ++ if (size > bytecount) ++ size = bytecount; ++ ++ err = 0; ++ if (copy_to_user(ptr, mm->context.ldt, size)) ++ err = -EFAULT; ++ up(&mm->context.sem); ++ if (err < 0) ++ goto error_return; ++ if (size != bytecount) { ++ /* zero-fill the rest */ ++ if (clear_user(ptr+size, bytecount-size) != 0) { ++ err = -EFAULT; ++ goto error_return; ++ } ++ } ++ return bytecount; ++error_return: ++ return err; ++} ++ ++static int read_default_ldt(void __user * ptr, unsigned long bytecount) ++{ ++ int err; ++ unsigned long size; ++ ++ err = 0; ++ size = 5*sizeof(struct desc_struct); ++ if (size > bytecount) ++ size = bytecount; ++ ++ err = size; ++ if (clear_user(ptr, size)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) ++{ ++ struct mm_struct * mm = current->mm; ++ __u32 entry_1, entry_2; ++ int error; ++ struct user_desc ldt_info; ++ ++ error = -EINVAL; ++ if (bytecount != sizeof(ldt_info)) ++ goto out; ++ error = -EFAULT; ++ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) ++ goto out; ++ ++ error = -EINVAL; ++ if (ldt_info.entry_number >= LDT_ENTRIES) ++ goto out; ++ if (ldt_info.contents == 3) { ++ if (oldmode) ++ goto out; ++ if (ldt_info.seg_not_present == 0) ++ goto out; ++ } ++ ++ down(&mm->context.sem); ++ if (ldt_info.entry_number >= mm->context.size) { ++ error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); ++ if (error < 0) ++ goto out_unlock; ++ } ++ ++ /* Allow LDTs to be cleared by the user. */ ++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { ++ if (oldmode || LDT_empty(&ldt_info)) { ++ entry_1 = 0; ++ entry_2 = 0; ++ goto install; ++ } ++ } ++ ++ entry_1 = LDT_entry_a(&ldt_info); ++ entry_2 = LDT_entry_b(&ldt_info); ++ if (oldmode) ++ entry_2 &= ~(1 << 20); ++ ++ /* Install the new entry ... */ ++install: ++ error = write_ldt_entry(mm->context.ldt, ldt_info.entry_number, ++ entry_1, entry_2); ++ ++out_unlock: ++ up(&mm->context.sem); ++out: ++ return error; ++} ++ ++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++{ ++ int ret = -ENOSYS; ++ ++ switch (func) { ++ case 0: ++ ret = read_ldt(ptr, bytecount); ++ break; ++ case 1: ++ ret = write_ldt(ptr, bytecount, 1); ++ break; ++ case 2: ++ ret = read_default_ldt(ptr, bytecount); ++ break; ++ case 0x11: ++ ret = write_ldt(ptr, bytecount, 0); ++ break; ++ } ++ return ret; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/machine_kexec.c +--- a/arch/i386/kernel/machine_kexec.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/machine_kexec.c Wed Aug 08 16:25:28 2007 -0300 +@@ -20,6 +20,10 @@ + #include <asm/desc.h> + #include <asm/system.h> + ++#ifdef CONFIG_XEN ++#include <xen/interface/kexec.h> ++#endif ++ + #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) + static u32 kexec_pgd[1024] PAGE_ALIGNED; + #ifdef CONFIG_X86_PAE +@@ -28,6 +32,40 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED + #endif + static u32 kexec_pte0[1024] PAGE_ALIGNED; + static u32 kexec_pte1[1024] PAGE_ALIGNED; ++ ++#ifdef CONFIG_XEN ++ ++#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) ++ ++#if PAGES_NR > KEXEC_XEN_NO_PAGES ++#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break ++#endif ++ ++#if PA_CONTROL_PAGE != 0 ++#error PA_CONTROL_PAGE is non zero - Xen support will break ++#endif ++ ++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) ++{ ++ void *control_page; ++ ++ memset(xki->page_list, 0, sizeof(xki->page_list)); ++ ++ control_page = page_address(image->control_code_page); ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); ++ ++ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); ++ xki->page_list[PA_PGD] = __ma(kexec_pgd); ++#ifdef CONFIG_X86_PAE ++ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); ++ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); ++#endif ++ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); ++ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); ++ ++} ++ ++#else /* CONFIG_XEN */ + + static void set_idt(void *newidt, __u16 limit) + { +@@ -70,6 +108,7 @@ static void load_segments(void) + #undef STR + #undef __STR + } ++#endif /* !CONFIG_XEN */ + + /* + * A architecture hook called to validate the +@@ -97,6 +136,7 @@ void machine_kexec_cleanup(struct kimage + { + } + ++#ifndef CONFIG_XEN + /* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. +@@ -147,6 +187,7 @@ NORET_TYPE void machine_kexec(struct kim + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start, cpu_has_pae); + } ++#endif + + /* crashkernel=size@addr specifies the location to reserve for + * a crash kernel. By reserving this memory we guarantee +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/microcode-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/microcode-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,144 @@ ++/* ++ * Intel CPU Microcode Update Driver for Linux ++ * ++ * Copyright (C) 2000-2004 Tigran Aivazian ++ * ++ * This driver allows to upgrade microcode on Intel processors ++ * belonging to IA-32 family - PentiumPro, Pentium II, ++ * Pentium III, Xeon, Pentium 4, etc. ++ * ++ * Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, ++ * Order Number 245472 or free download from: ++ * ++ * http://developer.intel.com/design/pentium4/manuals/245472.htm ++ * ++ * For more information, go to http://www.urbanmyth.org/microcode ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++//#define DEBUG /* pr_debug */ ++#include <linux/capability.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/cpumask.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <linux/miscdevice.h> ++#include <linux/spinlock.h> ++#include <linux/mm.h> ++#include <linux/mutex.h> ++#include <linux/syscalls.h> ++ ++#include <asm/msr.h> ++#include <asm/uaccess.h> ++#include <asm/processor.h> ++ ++MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); ++MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>"); ++MODULE_LICENSE("GPL"); ++ ++static int verbose; ++module_param(verbose, int, 0644); ++ ++#define MICROCODE_VERSION "1.14a-xen" ++ ++#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ ++#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */ ++#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */ ++ ++/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ ++static DEFINE_MUTEX(microcode_mutex); ++ ++static int microcode_open (struct inode *unused1, struct file *unused2) ++{ ++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; ++} ++ ++ ++static int do_microcode_update (const void __user *ubuf, size_t len) ++{ ++ int err; ++ void *kbuf; ++ ++ kbuf = vmalloc(len); ++ if (!kbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(kbuf, ubuf, len) == 0) { ++ struct xen_platform_op op; ++ ++ op.cmd = XENPF_microcode_update; ++ set_xen_guest_handle(op.u.microcode.data, kbuf); ++ op.u.microcode.length = len; ++ err = HYPERVISOR_platform_op(&op); ++ } else ++ err = -EFAULT; ++ ++ vfree(kbuf); ++ ++ return err; ++} ++ ++static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) ++{ ++ ssize_t ret; ++ ++ if (len < MC_HEADER_SIZE) { ++ printk(KERN_ERR "microcode: not enough data\n"); ++ return -EINVAL; ++ } ++ ++ mutex_lock(µcode_mutex); ++ ++ ret = do_microcode_update(buf, len); ++ if (!ret) ++ ret = (ssize_t)len; ++ ++ mutex_unlock(µcode_mutex); ++ ++ return ret; ++} ++ ++static struct file_operations microcode_fops = { ++ .owner = THIS_MODULE, ++ .write = microcode_write, ++ .open = microcode_open, ++}; ++ ++static struct miscdevice microcode_dev = { ++ .minor = MICROCODE_MINOR, ++ .name = "microcode", ++ .fops = µcode_fops, ++}; ++ ++static int __init microcode_init (void) ++{ ++ int error; ++ ++ error = misc_register(µcode_dev); ++ if (error) { ++ printk(KERN_ERR ++ "microcode: can't misc_register on minor=%d\n", ++ MICROCODE_MINOR); ++ return error; ++ } ++ ++ printk(KERN_INFO ++ "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n"); ++ return 0; ++} ++ ++static void __exit microcode_exit (void) ++{ ++ misc_deregister(µcode_dev); ++} ++ ++module_init(microcode_init) ++module_exit(microcode_exit) ++MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/mpparse.c +--- a/arch/i386/kernel/mpparse.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/mpparse.c Wed Aug 08 16:25:28 2007 -0300 +@@ -106,6 +106,7 @@ static struct mpc_config_translation *tr + + static void __cpuinit MP_processor_info (struct mpc_config_processor *m) + { ++#ifndef CONFIG_XEN + int ver, apicid; + physid_mask_t phys_cpu; + +@@ -196,8 +197,9 @@ static void __cpuinit MP_processor_info + } + + cpu_set(num_processors, cpu_possible_map); ++#endif /* CONFIG_XEN */ + num_processors++; +- ++#ifndef CONFIG_XEN + /* + * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y + * but we need to work other dependencies like SMP_SUSPEND etc +@@ -218,6 +220,7 @@ static void __cpuinit MP_processor_info + } + } + bios_cpu_apicid[num_processors - 1] = m->mpc_apicid; ++#endif /* CONFIG_XEN */ + } + + static void __init MP_bus_info (struct mpc_config_bus *m) +@@ -684,7 +687,11 @@ void __init get_smp_config (void) + * Read the physical hardware table. Anything here will + * override the defaults. + */ ++#ifdef CONFIG_XEN ++ if (!smp_read_mpc(isa_bus_to_virt(mpf->mpf_physptr))) { ++#else + if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr))) { ++#endif + smp_found_config = 0; + printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); + printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); +@@ -719,7 +726,11 @@ void __init get_smp_config (void) + + static int __init smp_scan_config (unsigned long base, unsigned long length) + { ++#ifdef CONFIG_XEN ++ unsigned long *bp = isa_bus_to_virt(base); ++#else + unsigned long *bp = phys_to_virt(base); ++#endif + struct intel_mp_floating *mpf; + + Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); +@@ -735,6 +746,7 @@ static int __init smp_scan_config (unsig + || (mpf->mpf_specification == 4)) ) { + + smp_found_config = 1; ++#ifndef CONFIG_XEN + printk(KERN_INFO "found SMP MP-table at %08lx\n", + virt_to_phys(mpf)); + reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); +@@ -754,6 +766,10 @@ static int __init smp_scan_config (unsig + size = end - mpf->mpf_physptr; + reserve_bootmem(mpf->mpf_physptr, size); + } ++#else ++ printk(KERN_INFO "found SMP MP-table at %08lx\n", ++ ((unsigned long)bp - (unsigned long)isa_bus_to_virt(base)) + base); ++#endif + + mpf_found = mpf; + return 1; +@@ -766,7 +782,9 @@ static int __init smp_scan_config (unsig + + void __init find_smp_config (void) + { ++#ifndef CONFIG_XEN + unsigned int address; ++#endif + + /* + * FIXME: Linux assumes you have 640K of base ram.. +@@ -797,9 +815,11 @@ void __init find_smp_config (void) + * MP1.4 SPEC states to only scan first 1K of 4K EBDA. + */ + ++#ifndef CONFIG_XEN + address = get_bios_ebda(); + if (address) + smp_scan_config(address, 0x400); ++#endif + } + + int es7000_plat; +@@ -812,6 +832,7 @@ int es7000_plat; + + void __init mp_register_lapic_address(u64 address) + { ++#ifndef CONFIG_XEN + mp_lapic_addr = (unsigned long) address; + + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); +@@ -820,6 +841,7 @@ void __init mp_register_lapic_address(u6 + boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); + + Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid); ++#endif + } + + void __cpuinit mp_register_lapic (u8 id, u8 enabled) +@@ -836,6 +858,7 @@ void __cpuinit mp_register_lapic (u8 id, + if (id == boot_cpu_physical_apicid) + boot_cpu = 1; + ++#ifndef CONFIG_XEN + processor.mpc_type = MP_PROCESSOR; + processor.mpc_apicid = id; + processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); +@@ -846,6 +869,7 @@ void __cpuinit mp_register_lapic (u8 id, + processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; ++#endif + + MP_processor_info(&processor); + } +@@ -900,7 +924,9 @@ void __init mp_register_ioapic(u8 id, u3 + mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE; + mp_ioapics[idx].mpc_apicaddr = address; + ++#ifndef CONFIG_XEN + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); ++#endif + if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + && !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) + tmpid = io_apic_get_unique_id(idx, id); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/pci-dma-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/pci-dma-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,378 @@ ++/* ++ * Dynamic DMA mapping support. ++ * ++ * On i386 there is no hardware dynamic DMA address translation, ++ * so consistent alloc/free are merely page allocation/freeing. ++ * The rest of the dynamic DMA mapping interface is implemented ++ * in asm/pci.h. ++ */ ++ ++#include <linux/types.h> ++#include <linux/mm.h> ++#include <linux/string.h> ++#include <linux/pci.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <asm/io.h> ++#include <xen/balloon.h> ++#include <asm/swiotlb.h> ++#include <asm/tlbflush.h> ++#include <asm-i386/mach-xen/asm/swiotlb.h> ++#include <asm/bug.h> ++ ++#ifdef __x86_64__ ++#include <asm/proto.h> ++ ++int iommu_merge __read_mostly = 0; ++EXPORT_SYMBOL(iommu_merge); ++ ++dma_addr_t bad_dma_address __read_mostly; ++EXPORT_SYMBOL(bad_dma_address); ++ ++/* This tells the BIO block layer to assume merging. Default to off ++ because we cannot guarantee merging later. */ ++int iommu_bio_merge __read_mostly = 0; ++EXPORT_SYMBOL(iommu_bio_merge); ++ ++int iommu_sac_force __read_mostly = 0; ++EXPORT_SYMBOL(iommu_sac_force); ++ ++int no_iommu __read_mostly; ++#ifdef CONFIG_IOMMU_DEBUG ++int panic_on_overflow __read_mostly = 1; ++int force_iommu __read_mostly = 1; ++#else ++int panic_on_overflow __read_mostly = 0; ++int force_iommu __read_mostly= 0; ++#endif ++ ++/* Set this to 1 if there is a HW IOMMU in the system */ ++int iommu_detected __read_mostly = 0; ++ ++void __init pci_iommu_alloc(void) ++{ ++ /* ++ * The order of these functions is important for ++ * fall-back/fail-over reasons ++ */ ++#ifdef CONFIG_IOMMU ++ iommu_hole_init(); ++#endif ++ ++#ifdef CONFIG_CALGARY_IOMMU ++#include <asm/calgary.h> ++ /* shut up compiler */ ++ use_calgary = use_calgary; ++ detect_calgary(); ++#endif ++ ++#ifdef CONFIG_SWIOTLB ++ pci_swiotlb_init(); ++#endif ++} ++ ++#endif ++ ++struct dma_coherent_mem { ++ void *virt_base; ++ u32 device_base; ++ int size; ++ int flags; ++ unsigned long *bitmap; ++}; ++ ++#define IOMMU_BUG_ON(test) \ ++do { \ ++ if (unlikely(test)) { \ ++ printk(KERN_ALERT "Fatal DMA error! " \ ++ "Please use 'swiotlb=force'\n"); \ ++ BUG(); \ ++ } \ ++} while (0) ++ ++int ++dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ int i, rc; ++ ++ BUG_ON(!valid_dma_direction(direction)); ++ WARN_ON(nents == 0 || sg[0].length == 0); ++ ++ if (swiotlb) { ++ rc = swiotlb_map_sg(hwdev, sg, nents, direction); ++ } else { ++ for (i = 0; i < nents; i++ ) { ++ sg[i].dma_address = ++ page_to_bus(sg[i].page) + sg[i].offset; ++ sg[i].dma_length = sg[i].length; ++ BUG_ON(!sg[i].page); ++ IOMMU_BUG_ON(address_needs_mapping( ++ hwdev, sg[i].dma_address)); ++ } ++ rc = nents; ++ } ++ ++ flush_write_buffers(); ++ return rc; ++} ++EXPORT_SYMBOL(dma_map_sg); ++ ++void ++dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(!valid_dma_direction(direction)); ++ if (swiotlb) ++ swiotlb_unmap_sg(hwdev, sg, nents, direction); ++} ++EXPORT_SYMBOL(dma_unmap_sg); ++ ++#ifdef CONFIG_HIGHMEM ++dma_addr_t ++dma_map_page(struct device *dev, struct page *page, unsigned long offset, ++ size_t size, enum dma_data_direction direction) ++{ ++ dma_addr_t dma_addr; ++ ++ BUG_ON(!valid_dma_direction(direction)); ++ ++ if (swiotlb) { ++ dma_addr = swiotlb_map_page( ++ dev, page, offset, size, direction); ++ } else { ++ dma_addr = page_to_bus(page) + offset; ++ IOMMU_BUG_ON(address_needs_mapping(dev, dma_addr)); ++ } ++ ++ return dma_addr; ++} ++EXPORT_SYMBOL(dma_map_page); ++ ++void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(!valid_dma_direction(direction)); ++ if (swiotlb) ++ swiotlb_unmap_page(dev, dma_address, size, direction); ++} ++EXPORT_SYMBOL(dma_unmap_page); ++#endif /* CONFIG_HIGHMEM */ ++ ++int ++dma_mapping_error(dma_addr_t dma_addr) ++{ ++ if (swiotlb) ++ return swiotlb_dma_mapping_error(dma_addr); ++ return 0; ++} ++EXPORT_SYMBOL(dma_mapping_error); ++ ++int ++dma_supported(struct device *dev, u64 mask) ++{ ++ if (swiotlb) ++ return swiotlb_dma_supported(dev, mask); ++ /* ++ * By default we'll BUG when an infeasible DMA is requested, and ++ * request swiotlb=force (see IOMMU_BUG_ON). ++ */ ++ return 1; ++} ++EXPORT_SYMBOL(dma_supported); ++ ++void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp) ++{ ++ void *ret; ++ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; ++ unsigned int order = get_order(size); ++ unsigned long vstart; ++ u64 mask; ++ ++ /* ignore region specifiers */ ++ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); ++ ++ if (mem) { ++ int page = bitmap_find_free_region(mem->bitmap, mem->size, ++ order); ++ if (page >= 0) { ++ *dma_handle = mem->device_base + (page << PAGE_SHIFT); ++ ret = mem->virt_base + (page << PAGE_SHIFT); ++ memset(ret, 0, size); ++ return ret; ++ } ++ if (mem->flags & DMA_MEMORY_EXCLUSIVE) ++ return NULL; ++ } ++ ++ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) ++ gfp |= GFP_DMA; ++ ++ vstart = __get_free_pages(gfp, order); ++ ret = (void *)vstart; ++ ++ if (dev != NULL && dev->coherent_dma_mask) ++ mask = dev->coherent_dma_mask; ++ else ++ mask = 0xffffffff; ++ ++ if (ret != NULL) { ++ if (xen_create_contiguous_region(vstart, order, ++ fls64(mask)) != 0) { ++ free_pages(vstart, order); ++ return NULL; ++ } ++ memset(ret, 0, size); ++ *dma_handle = virt_to_bus(ret); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(dma_alloc_coherent); ++ ++void dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; ++ int order = get_order(size); ++ ++ if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { ++ int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; ++ ++ bitmap_release_region(mem->bitmap, page, order); ++ } else { ++ xen_destroy_contiguous_region((unsigned long)vaddr, order); ++ free_pages((unsigned long)vaddr, order); ++ } ++} ++EXPORT_SYMBOL(dma_free_coherent); ++ ++#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY ++int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, ++ dma_addr_t device_addr, size_t size, int flags) ++{ ++ void __iomem *mem_base = NULL; ++ int pages = size >> PAGE_SHIFT; ++ int bitmap_size = (pages + 31)/32; ++ ++ if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) ++ goto out; ++ if (!size) ++ goto out; ++ if (dev->dma_mem) ++ goto out; ++ ++ /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ ++ ++ mem_base = ioremap(bus_addr, size); ++ if (!mem_base) ++ goto out; ++ ++ dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); ++ if (!dev->dma_mem) ++ goto out; ++ dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); ++ if (!dev->dma_mem->bitmap) ++ goto free1_out; ++ ++ dev->dma_mem->virt_base = mem_base; ++ dev->dma_mem->device_base = device_addr; ++ dev->dma_mem->size = pages; ++ dev->dma_mem->flags = flags; ++ ++ if (flags & DMA_MEMORY_MAP) ++ return DMA_MEMORY_MAP; ++ ++ return DMA_MEMORY_IO; ++ ++ free1_out: ++ kfree(dev->dma_mem->bitmap); ++ out: ++ if (mem_base) ++ iounmap(mem_base); ++ return 0; ++} ++EXPORT_SYMBOL(dma_declare_coherent_memory); ++ ++void dma_release_declared_memory(struct device *dev) ++{ ++ struct dma_coherent_mem *mem = dev->dma_mem; ++ ++ if(!mem) ++ return; ++ dev->dma_mem = NULL; ++ iounmap(mem->virt_base); ++ kfree(mem->bitmap); ++ kfree(mem); ++} ++EXPORT_SYMBOL(dma_release_declared_memory); ++ ++void *dma_mark_declared_memory_occupied(struct device *dev, ++ dma_addr_t device_addr, size_t size) ++{ ++ struct dma_coherent_mem *mem = dev->dma_mem; ++ int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ int pos, err; ++ ++ if (!mem) ++ return ERR_PTR(-EINVAL); ++ ++ pos = (device_addr - mem->device_base) >> PAGE_SHIFT; ++ err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); ++ if (err != 0) ++ return ERR_PTR(err); ++ return mem->virt_base + (pos << PAGE_SHIFT); ++} ++EXPORT_SYMBOL(dma_mark_declared_memory_occupied); ++#endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */ ++ ++dma_addr_t ++dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction direction) ++{ ++ dma_addr_t dma; ++ ++ BUG_ON(!valid_dma_direction(direction)); ++ WARN_ON(size == 0); ++ ++ if (swiotlb) { ++ dma = swiotlb_map_single(dev, ptr, size, direction); ++ } else { ++ dma = virt_to_bus(ptr); ++ IOMMU_BUG_ON(range_straddles_page_boundary(ptr, size)); ++ IOMMU_BUG_ON(address_needs_mapping(dev, dma)); ++ } ++ ++ flush_write_buffers(); ++ return dma; ++} ++EXPORT_SYMBOL(dma_map_single); ++ ++void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction) ++{ ++ BUG_ON(!valid_dma_direction(direction)); ++ if (swiotlb) ++ swiotlb_unmap_single(dev, dma_addr, size, direction); ++} ++EXPORT_SYMBOL(dma_unmap_single); ++ ++void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_single_for_cpu(dev, dma_handle, size, direction); ++} ++EXPORT_SYMBOL(dma_sync_single_for_cpu); ++ ++void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_single_for_device(dev, dma_handle, size, direction); ++} ++EXPORT_SYMBOL(dma_sync_single_for_device); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/process-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/process-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,884 @@ ++/* ++ * linux/arch/i386/kernel/process.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * ++ * Pentium III FXSR, SSE support ++ * Gareth Hughes <gareth@valinux.com>, May 2000 ++ */ ++ ++/* ++ * This file handles the architecture-dependent parts of process handling.. ++ */ ++ ++#include <stdarg.h> ++ ++#include <linux/cpu.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/elfcore.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/stddef.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <linux/user.h> ++#include <linux/a.out.h> ++#include <linux/interrupt.h> ++#include <linux/utsname.h> ++#include <linux/delay.h> ++#include <linux/reboot.h> ++#include <linux/init.h> ++#include <linux/mc146818rtc.h> ++#include <linux/module.h> ++#include <linux/kallsyms.h> ++#include <linux/ptrace.h> ++#include <linux/random.h> ++#include <linux/personality.h> ++ ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/ldt.h> ++#include <asm/processor.h> ++#include <asm/i387.h> ++#include <asm/desc.h> ++#include <asm/vm86.h> ++#ifdef CONFIG_MATH_EMULATION ++#include <asm/math_emu.h> ++#endif ++ ++#include <xen/interface/physdev.h> ++#include <xen/interface/vcpu.h> ++#include <xen/cpu_hotplug.h> ++ ++#include <linux/err.h> ++ ++#include <asm/tlbflush.h> ++#include <asm/cpu.h> ++#include <asm/pda.h> ++ ++asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); ++ ++static int hlt_counter; ++ ++unsigned long boot_option_idle_override = 0; ++EXPORT_SYMBOL(boot_option_idle_override); ++ ++/* ++ * Return saved PC of a blocked thread. ++ */ ++unsigned long thread_saved_pc(struct task_struct *tsk) ++{ ++ return ((unsigned long *)tsk->thread.esp)[3]; ++} ++ ++/* ++ * Powermanagement idle function, if any.. ++ */ ++void (*pm_idle)(void); ++EXPORT_SYMBOL(pm_idle); ++static DEFINE_PER_CPU(unsigned int, cpu_idle_state); ++ ++void disable_hlt(void) ++{ ++ hlt_counter++; ++} ++ ++EXPORT_SYMBOL(disable_hlt); ++ ++void enable_hlt(void) ++{ ++ hlt_counter--; ++} ++ ++EXPORT_SYMBOL(enable_hlt); ++ ++/* ++ * On SMP it's slightly faster (but much more power-consuming!) ++ * to poll the ->work.need_resched flag instead of waiting for the ++ * cross-CPU IPI to arrive. Use this option with caution. ++ */ ++static void poll_idle (void) ++{ ++ local_irq_enable(); ++ ++ asm volatile( ++ "2:" ++ "testl %0, %1;" ++ "rep; nop;" ++ "je 2b;" ++ : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); ++} ++ ++static void xen_idle(void) ++{ ++ current_thread_info()->status &= ~TS_POLLING; ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); ++ ++ local_irq_disable(); ++ if (!need_resched()) ++ safe_halt(); /* enables interrupts racelessly */ ++ else ++ local_irq_enable(); ++ current_thread_info()->status |= TS_POLLING; ++} ++#ifdef CONFIG_APM_MODULE ++EXPORT_SYMBOL(default_idle); ++#endif ++ ++#ifdef CONFIG_HOTPLUG_CPU ++extern cpumask_t cpu_initialized; ++static inline void play_dead(void) ++{ ++ idle_task_exit(); ++ local_irq_disable(); ++ cpu_clear(smp_processor_id(), cpu_initialized); ++ preempt_enable_no_resched(); ++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); ++ cpu_bringup(); ++} ++#else ++static inline void play_dead(void) ++{ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * The idle thread. There's no useful work to be ++ * done, so just try to conserve power and have a ++ * low exit latency (ie sit in a loop waiting for ++ * somebody to say that they'd like to reschedule) ++ */ ++void cpu_idle(void) ++{ ++ int cpu = smp_processor_id(); ++ ++ current_thread_info()->status |= TS_POLLING; ++ ++ /* endless idle loop with no priority at all */ ++ while (1) { ++ while (!need_resched()) { ++ void (*idle)(void); ++ ++ if (__get_cpu_var(cpu_idle_state)) ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ rmb(); ++ idle = xen_idle; /* no alternatives */ ++ ++ if (cpu_is_offline(cpu)) ++ play_dead(); ++ ++ __get_cpu_var(irq_stat).idle_timestamp = jiffies; ++ idle(); ++ } ++ preempt_enable_no_resched(); ++ schedule(); ++ preempt_disable(); ++ } ++} ++ ++void cpu_idle_wait(void) ++{ ++ unsigned int cpu, this_cpu = get_cpu(); ++ cpumask_t map, tmp = current->cpus_allowed; ++ ++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); ++ put_cpu(); ++ ++ cpus_clear(map); ++ for_each_online_cpu(cpu) { ++ per_cpu(cpu_idle_state, cpu) = 1; ++ cpu_set(cpu, map); ++ } ++ ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ wmb(); ++ do { ++ ssleep(1); ++ for_each_online_cpu(cpu) { ++ if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) ++ cpu_clear(cpu, map); ++ } ++ cpus_and(map, map, cpu_online_map); ++ } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); ++} ++EXPORT_SYMBOL_GPL(cpu_idle_wait); ++ ++/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */ ++/* Always use xen_idle() instead. */ ++void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) {} ++ ++void __devinit select_idle_routine(const struct cpuinfo_x86 *c) ++{ ++} ++ ++static int __init idle_setup (char *str) ++{ ++ if (!strncmp(str, "poll", 4)) { ++ printk("using polling idle threads.\n"); ++ pm_idle = poll_idle; ++ } ++ ++ boot_option_idle_override = 1; ++ return 1; ++} ++ ++__setup("idle=", idle_setup); ++ ++void show_regs(struct pt_regs * regs) ++{ ++ unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; ++ ++ printk("\n"); ++ printk("Pid: %d, comm: %20s\n", current->pid, current->comm); ++ printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); ++ print_symbol("EIP is at %s\n", regs->eip); ++ ++ if (user_mode_vm(regs)) ++ printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); ++ printk(" EFLAGS: %08lx %s (%s %.*s)\n", ++ regs->eflags, print_tainted(), init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); ++ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", ++ regs->eax,regs->ebx,regs->ecx,regs->edx); ++ printk("ESI: %08lx EDI: %08lx EBP: %08lx", ++ regs->esi, regs->edi, regs->ebp); ++ printk(" DS: %04x ES: %04x GS: %04x\n", ++ 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); ++ ++ cr0 = read_cr0(); ++ cr2 = read_cr2(); ++ cr3 = read_cr3(); ++ cr4 = read_cr4_safe(); ++ printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); ++ show_trace(NULL, regs, ®s->esp); ++} ++ ++/* ++ * This gets run with %ebx containing the ++ * function to call, and %edx containing ++ * the "args". ++ */ ++extern void kernel_thread_helper(void); ++ ++/* ++ * Create a kernel thread ++ */ ++int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ++{ ++ struct pt_regs regs; ++ ++ memset(®s, 0, sizeof(regs)); ++ ++ regs.ebx = (unsigned long) fn; ++ regs.edx = (unsigned long) arg; ++ ++ regs.xds = __USER_DS; ++ regs.xes = __USER_DS; ++ regs.xgs = __KERNEL_PDA; ++ regs.orig_eax = -1; ++ regs.eip = (unsigned long) kernel_thread_helper; ++ regs.xcs = __KERNEL_CS | get_kernel_rpl(); ++ regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; ++ ++ /* Ok, create the new process.. */ ++ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); ++} ++EXPORT_SYMBOL(kernel_thread); ++ ++/* ++ * Free current thread data structures etc.. ++ */ ++void exit_thread(void) ++{ ++ /* The process may have allocated an io port bitmap... nuke it. */ ++ if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { ++ struct task_struct *tsk = current; ++ struct thread_struct *t = &tsk->thread; ++ struct physdev_set_iobitmap set_iobitmap; ++ memset(&set_iobitmap, 0, sizeof(set_iobitmap)); ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); ++ kfree(t->io_bitmap_ptr); ++ t->io_bitmap_ptr = NULL; ++ clear_thread_flag(TIF_IO_BITMAP); ++ } ++} ++ ++void flush_thread(void) ++{ ++ struct task_struct *tsk = current; ++ ++ memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); ++ memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); ++ clear_tsk_thread_flag(tsk, TIF_DEBUG); ++ /* ++ * Forget coprocessor state.. ++ */ ++ clear_fpu(tsk); ++ clear_used_math(); ++} ++ ++void release_thread(struct task_struct *dead_task) ++{ ++ BUG_ON(dead_task->mm); ++ release_vm86_irqs(dead_task); ++} ++ ++/* ++ * This gets called before we allocate a new thread and copy ++ * the current task into it. ++ */ ++void prepare_to_copy(struct task_struct *tsk) ++{ ++ unlazy_fpu(tsk); ++} ++ ++int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, ++ unsigned long unused, ++ struct task_struct * p, struct pt_regs * regs) ++{ ++ struct pt_regs * childregs; ++ struct task_struct *tsk; ++ int err; ++ ++ childregs = task_pt_regs(p); ++ *childregs = *regs; ++ childregs->eax = 0; ++ childregs->esp = esp; ++ ++ p->thread.esp = (unsigned long) childregs; ++ p->thread.esp0 = (unsigned long) (childregs+1); ++ ++ p->thread.eip = (unsigned long) ret_from_fork; ++ ++ savesegment(fs,p->thread.fs); ++ ++ tsk = current; ++ if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { ++ p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, ++ IO_BITMAP_BYTES, GFP_KERNEL); ++ if (!p->thread.io_bitmap_ptr) { ++ p->thread.io_bitmap_max = 0; ++ return -ENOMEM; ++ } ++ set_tsk_thread_flag(p, TIF_IO_BITMAP); ++ } ++ ++ /* ++ * Set a new TLS for the child thread? ++ */ ++ if (clone_flags & CLONE_SETTLS) { ++ struct desc_struct *desc; ++ struct user_desc info; ++ int idx; ++ ++ err = -EFAULT; ++ if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) ++ goto out; ++ err = -EINVAL; ++ if (LDT_empty(&info)) ++ goto out; ++ ++ idx = info.entry_number; ++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) ++ goto out; ++ ++ desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; ++ desc->a = LDT_entry_a(&info); ++ desc->b = LDT_entry_b(&info); ++ } ++ ++ p->thread.iopl = current->thread.iopl; ++ ++ err = 0; ++ out: ++ if (err && p->thread.io_bitmap_ptr) { ++ kfree(p->thread.io_bitmap_ptr); ++ p->thread.io_bitmap_max = 0; ++ } ++ return err; ++} ++ ++/* ++ * fill in the user structure for a core dump.. ++ */ ++void dump_thread(struct pt_regs * regs, struct user * dump) ++{ ++ int i; ++ ++/* changed the size calculations - should hopefully work better. lbt */ ++ dump->magic = CMAGIC; ++ dump->start_code = 0; ++ dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); ++ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; ++ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; ++ dump->u_dsize -= dump->u_tsize; ++ dump->u_ssize = 0; ++ for (i = 0; i < 8; i++) ++ dump->u_debugreg[i] = current->thread.debugreg[i]; ++ ++ if (dump->start_stack < TASK_SIZE) ++ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; ++ ++ dump->regs.ebx = regs->ebx; ++ dump->regs.ecx = regs->ecx; ++ dump->regs.edx = regs->edx; ++ dump->regs.esi = regs->esi; ++ dump->regs.edi = regs->edi; ++ dump->regs.ebp = regs->ebp; ++ dump->regs.eax = regs->eax; ++ dump->regs.ds = regs->xds; ++ dump->regs.es = regs->xes; ++ savesegment(fs,dump->regs.fs); ++ dump->regs.gs = regs->xgs; ++ dump->regs.orig_eax = regs->orig_eax; ++ dump->regs.eip = regs->eip; ++ dump->regs.cs = regs->xcs; ++ dump->regs.eflags = regs->eflags; ++ dump->regs.esp = regs->esp; ++ dump->regs.ss = regs->xss; ++ ++ dump->u_fpvalid = dump_fpu (regs, &dump->i387); ++} ++EXPORT_SYMBOL(dump_thread); ++ ++/* ++ * Capture the user space registers if the task is not running (in user space) ++ */ ++int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) ++{ ++ struct pt_regs ptregs = *task_pt_regs(tsk); ++ ptregs.xcs &= 0xffff; ++ ptregs.xds &= 0xffff; ++ ptregs.xes &= 0xffff; ++ ptregs.xss &= 0xffff; ++ ++ elf_core_copy_regs(regs, &ptregs); ++ ++ return 1; ++} ++ ++static noinline void __switch_to_xtra(struct task_struct *next_p) ++{ ++ struct thread_struct *next; ++ ++ next = &next_p->thread; ++ ++ if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { ++ set_debugreg(next->debugreg[0], 0); ++ set_debugreg(next->debugreg[1], 1); ++ set_debugreg(next->debugreg[2], 2); ++ set_debugreg(next->debugreg[3], 3); ++ /* no 4 and 5 */ ++ set_debugreg(next->debugreg[6], 6); ++ set_debugreg(next->debugreg[7], 7); ++ } ++#ifndef CONFIG_XEN ++ if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { ++ /* ++ * Disable the bitmap via an invalid offset. We still cache ++ * the previous bitmap owner and the IO bitmap contents: ++ */ ++ tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; ++ return; ++ } ++ ++ if (likely(next == tss->io_bitmap_owner)) { ++ /* ++ * Previous owner of the bitmap (hence the bitmap content) ++ * matches the next task, we dont have to do anything but ++ * to set a valid offset in the TSS: ++ */ ++ tss->io_bitmap_base = IO_BITMAP_OFFSET; ++ return; ++ } ++ /* ++ * Lazy TSS's I/O bitmap copy. We set an invalid offset here ++ * and we let the task to get a GPF in case an I/O instruction ++ * is performed. The handler of the GPF will verify that the ++ * faulting task has a valid I/O bitmap and, it true, does the ++ * real copy and restart the instruction. This will save us ++ * redundant copies when the currently switched task does not ++ * perform any I/O during its timeslice. ++ */ ++ tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY; ++#endif /* !CONFIG_XEN */ ++} ++ ++/* ++ * This function selects if the context switch from prev to next ++ * has to tweak the TSC disable bit in the cr4. ++ */ ++static inline void disable_tsc(struct task_struct *prev_p, ++ struct task_struct *next_p) ++{ ++ struct thread_info *prev, *next; ++ ++ /* ++ * gcc should eliminate the ->thread_info dereference if ++ * has_secure_computing returns 0 at compile time (SECCOMP=n). ++ */ ++ prev = task_thread_info(prev_p); ++ next = task_thread_info(next_p); ++ ++ if (has_secure_computing(prev) || has_secure_computing(next)) { ++ /* slow path here */ ++ if (has_secure_computing(prev) && ++ !has_secure_computing(next)) { ++ write_cr4(read_cr4() & ~X86_CR4_TSD); ++ } else if (!has_secure_computing(prev) && ++ has_secure_computing(next)) ++ write_cr4(read_cr4() | X86_CR4_TSD); ++ } ++} ++ ++/* ++ * switch_to(x,yn) should switch tasks from x to y. ++ * ++ * We fsave/fwait so that an exception goes off at the right time ++ * (as a call from the fsave or fwait in effect) rather than to ++ * the wrong process. Lazy FP saving no longer makes any sense ++ * with modern CPU's, and this simplifies a lot of things (SMP ++ * and UP become the same). ++ * ++ * NOTE! We used to use the x86 hardware context switching. The ++ * reason for not using it any more becomes apparent when you ++ * try to recover gracefully from saved state that is no longer ++ * valid (stale segment register values in particular). With the ++ * hardware task-switch, there is no way to fix up bad state in ++ * a reasonable manner. ++ * ++ * The fact that Intel documents the hardware task-switching to ++ * be slow is a fairly red herring - this code is not noticeably ++ * faster. However, there _is_ some room for improvement here, ++ * so the performance issues may eventually be a valid point. ++ * More important, however, is the fact that this allows us much ++ * more flexibility. ++ * ++ * The return value (in %eax) will be the "prev" task after ++ * the task-switch, and shows up in ret_from_fork in entry.S, ++ * for example. ++ */ ++struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ++{ ++ struct thread_struct *prev = &prev_p->thread, ++ *next = &next_p->thread; ++ int cpu = smp_processor_id(); ++#ifndef CONFIG_X86_NO_TSS ++ struct tss_struct *tss = &per_cpu(init_tss, cpu); ++#endif ++ struct physdev_set_iobitmap iobmp_op; ++ multicall_entry_t _mcl[8], *mcl = _mcl; ++ ++ /* XEN NOTE: FS/GS saved in switch_mm(), not here. */ ++ ++ /* ++ * This is basically '__unlazy_fpu', except that we queue a ++ * multicall to indicate FPU task switch, rather than ++ * synchronously trapping to Xen. ++ */ ++ if (prev_p->thread_info->status & TS_USEDFPU) { ++ __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ ++ mcl->op = __HYPERVISOR_fpu_taskswitch; ++ mcl->args[0] = 1; ++ mcl++; ++ } ++#if 0 /* lazy fpu sanity check */ ++ else BUG_ON(!(read_cr0() & 8)); ++#endif ++ ++ /* ++ * Reload esp0. ++ * This is load_esp0(tss, next) with a multicall. ++ */ ++ mcl->op = __HYPERVISOR_stack_switch; ++ mcl->args[0] = __KERNEL_DS; ++ mcl->args[1] = next->esp0; ++ mcl++; ++ ++ /* ++ * Load the per-thread Thread-Local Storage descriptor. ++ * This is load_TLS(next, cpu) with multicalls. ++ */ ++#define C(i) do { \ ++ if (unlikely(next->tls_array[i].a != prev->tls_array[i].a || \ ++ next->tls_array[i].b != prev->tls_array[i].b)) { \ ++ mcl->op = __HYPERVISOR_update_descriptor; \ ++ *(u64 *)&mcl->args[0] = virt_to_machine( \ ++ &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]);\ ++ *(u64 *)&mcl->args[2] = *(u64 *)&next->tls_array[i]; \ ++ mcl++; \ ++ } \ ++} while (0) ++ C(0); C(1); C(2); ++#undef C ++ ++ if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) { ++ set_xen_guest_handle(iobmp_op.bitmap, ++ (char *)next->io_bitmap_ptr); ++ iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0; ++ mcl->op = __HYPERVISOR_physdev_op; ++ mcl->args[0] = PHYSDEVOP_set_iobitmap; ++ mcl->args[1] = (unsigned long)&iobmp_op; ++ mcl++; ++ } ++ ++ (void)HYPERVISOR_multicall(_mcl, mcl - _mcl); ++ ++ /* ++ * Restore %fs if needed. ++ * ++ * Glibc normally makes %fs be zero. ++ */ ++ if (unlikely(next->fs)) ++ loadsegment(fs, next->fs); ++ ++ write_pda(pcurrent, next_p); ++ ++ /* we're going to use this soon, after a few expensive things */ ++ if (next_p->fpu_counter > 5) ++ prefetch(&next->i387.fxsave); ++ ++ /* ++ * Now maybe handle debug registers ++ */ ++ if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) ++ __switch_to_xtra(next_p); ++ ++ disable_tsc(prev_p, next_p); ++ ++ /* If the task has used fpu the last 5 timeslices, just do a full ++ * restore of the math state immediately to avoid the trap; the ++ * chances of needing FPU soon are obviously high now ++ */ ++ if (next_p->fpu_counter > 5) ++ math_state_restore(); ++ ++ return prev_p; ++} ++ ++asmlinkage int sys_fork(struct pt_regs regs) ++{ ++ return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); ++} ++ ++asmlinkage int sys_clone(struct pt_regs regs) ++{ ++ unsigned long clone_flags; ++ unsigned long newsp; ++ int __user *parent_tidptr, *child_tidptr; ++ ++ clone_flags = regs.ebx; ++ newsp = regs.ecx; ++ parent_tidptr = (int __user *)regs.edx; ++ child_tidptr = (int __user *)regs.edi; ++ if (!newsp) ++ newsp = regs.esp; ++ return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); ++} ++ ++/* ++ * This is trivial, and on the face of it looks like it ++ * could equally well be done in user mode. ++ * ++ * Not so, for quite unobvious reasons - register pressure. ++ * In user mode vfork() cannot have a stack frame, and if ++ * done by calling the "clone()" system call directly, you ++ * do not have enough call-clobbered registers to hold all ++ * the information you need. ++ */ ++asmlinkage int sys_vfork(struct pt_regs regs) ++{ ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); ++} ++ ++/* ++ * sys_execve() executes a new program. ++ */ ++asmlinkage int sys_execve(struct pt_regs regs) ++{ ++ int error; ++ char * filename; ++ ++ filename = getname((char __user *) regs.ebx); ++ error = PTR_ERR(filename); ++ if (IS_ERR(filename)) ++ goto out; ++ error = do_execve(filename, ++ (char __user * __user *) regs.ecx, ++ (char __user * __user *) regs.edx, ++ ®s); ++ if (error == 0) { ++ task_lock(current); ++ current->ptrace &= ~PT_DTRACE; ++ task_unlock(current); ++ /* Make sure we don't return using sysenter.. */ ++ set_thread_flag(TIF_IRET); ++ } ++ putname(filename); ++out: ++ return error; ++} ++ ++#define top_esp (THREAD_SIZE - sizeof(unsigned long)) ++#define top_ebp (THREAD_SIZE - 2*sizeof(unsigned long)) ++ ++unsigned long get_wchan(struct task_struct *p) ++{ ++ unsigned long ebp, esp, eip; ++ unsigned long stack_page; ++ int count = 0; ++ if (!p || p == current || p->state == TASK_RUNNING) ++ return 0; ++ stack_page = (unsigned long)task_stack_page(p); ++ esp = p->thread.esp; ++ if (!stack_page || esp < stack_page || esp > top_esp+stack_page) ++ return 0; ++ /* include/asm-i386/system.h:switch_to() pushes ebp last. */ ++ ebp = *(unsigned long *) esp; ++ do { ++ if (ebp < stack_page || ebp > top_ebp+stack_page) ++ return 0; ++ eip = *(unsigned long *) (ebp+4); ++ if (!in_sched_functions(eip)) ++ return eip; ++ ebp = *(unsigned long *) ebp; ++ } while (count++ < 16); ++ return 0; ++} ++ ++/* ++ * sys_alloc_thread_area: get a yet unused TLS descriptor index. ++ */ ++static int get_free_idx(void) ++{ ++ struct thread_struct *t = ¤t->thread; ++ int idx; ++ ++ for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) ++ if (desc_empty(t->tls_array + idx)) ++ return idx + GDT_ENTRY_TLS_MIN; ++ return -ESRCH; ++} ++ ++/* ++ * Set a given TLS descriptor: ++ */ ++asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) ++{ ++ struct thread_struct *t = ¤t->thread; ++ struct user_desc info; ++ struct desc_struct *desc; ++ int cpu, idx; ++ ++ if (copy_from_user(&info, u_info, sizeof(info))) ++ return -EFAULT; ++ idx = info.entry_number; ++ ++ /* ++ * index -1 means the kernel should try to find and ++ * allocate an empty descriptor: ++ */ ++ if (idx == -1) { ++ idx = get_free_idx(); ++ if (idx < 0) ++ return idx; ++ if (put_user(idx, &u_info->entry_number)) ++ return -EFAULT; ++ } ++ ++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) ++ return -EINVAL; ++ ++ desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; ++ ++ /* ++ * We must not get preempted while modifying the TLS. ++ */ ++ cpu = get_cpu(); ++ ++ if (LDT_empty(&info)) { ++ desc->a = 0; ++ desc->b = 0; ++ } else { ++ desc->a = LDT_entry_a(&info); ++ desc->b = LDT_entry_b(&info); ++ } ++ load_TLS(t, cpu); ++ ++ put_cpu(); ++ ++ return 0; ++} ++ ++/* ++ * Get the current Thread-Local Storage area: ++ */ ++ ++#define GET_BASE(desc) ( \ ++ (((desc)->a >> 16) & 0x0000ffff) | \ ++ (((desc)->b << 16) & 0x00ff0000) | \ ++ ( (desc)->b & 0xff000000) ) ++ ++#define GET_LIMIT(desc) ( \ ++ ((desc)->a & 0x0ffff) | \ ++ ((desc)->b & 0xf0000) ) ++ ++#define GET_32BIT(desc) (((desc)->b >> 22) & 1) ++#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) ++#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) ++#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) ++#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) ++#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) ++ ++asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) ++{ ++ struct user_desc info; ++ struct desc_struct *desc; ++ int idx; ++ ++ if (get_user(idx, &u_info->entry_number)) ++ return -EFAULT; ++ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) ++ return -EINVAL; ++ ++ memset(&info, 0, sizeof(info)); ++ ++ desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; ++ ++ info.entry_number = idx; ++ info.base_addr = GET_BASE(desc); ++ info.limit = GET_LIMIT(desc); ++ info.seg_32bit = GET_32BIT(desc); ++ info.contents = GET_CONTENTS(desc); ++ info.read_exec_only = !GET_WRITABLE(desc); ++ info.limit_in_pages = GET_LIMIT_PAGES(desc); ++ info.seg_not_present = !GET_PRESENT(desc); ++ info.useable = GET_USEABLE(desc); ++ ++ if (copy_to_user(u_info, &info, sizeof(info))) ++ return -EFAULT; ++ return 0; ++} ++ ++unsigned long arch_align_stack(unsigned long sp) ++{ ++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) ++ sp -= get_random_int() % 8192; ++ return sp & ~0xf; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/quirks.c +--- a/arch/i386/kernel/quirks.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/quirks.c Wed Aug 08 16:25:28 2007 -0300 +@@ -7,7 +7,7 @@ + #include <asm/genapic.h> + #include <asm/cpu.h> + +-#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) ++#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI) + static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev) + { + u8 config, rev; +@@ -68,11 +68,19 @@ void __init quirk_intel_irqbalance(void) + word = read_pci_config_16(0, 0, 0x40, 0x4c); + + if (!(word & (1 << 13))) { ++#ifdef CONFIG_XEN ++ struct xen_platform_op op; ++ printk(KERN_INFO "Disabling irq balancing and affinity\n"); ++ op.cmd = XENPF_platform_quirk; ++ op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING; ++ (void)HYPERVISOR_platform_op(&op); ++#else + printk(KERN_INFO "Disabling irq balancing and affinity\n"); + #ifdef CONFIG_IRQBALANCE + irqbalance_disable(""); + #endif + noirqdebug_setup(""); ++#endif /* CONFIG_XEN */ + #ifdef CONFIG_PROC_FS + no_irq_affinity = 1; + #endif +@@ -80,12 +88,12 @@ void __init quirk_intel_irqbalance(void) + printk(KERN_INFO "Disabling cpu hotplug control\n"); + enable_cpu_hotplug = 0; + #endif +-#ifdef CONFIG_X86_64 ++#if defined(CONFIG_X86_64) && !defined(CONFIG_XEN) + /* force the genapic selection to flat mode so that + * interrupts can be redirected to more than one CPU. + */ + genapic_force = &apic_flat; +-#endif ++#endif /* CONFIG_XEN */ + } + + /* put back the original value for config space */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/setup-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/setup-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,845 @@ ++/* ++ * linux/arch/i386/kernel/setup.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * ++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 ++ * ++ * Memory region support ++ * David Parsons <orc@pell.chi.il.us>, July-August 1999 ++ * ++ * Added E820 sanitization routine (removes overlapping memory regions); ++ * Brian Moyle <bmoyle@mvista.com>, February 2001 ++ * ++ * Moved CPU detection code to cpu/${cpu}.c ++ * Patrick Mochel <mochel@osdl.org>, March 2002 ++ * ++ * Provisions for empty E820 memory regions (reported by certain BIOSes). ++ * Alex Achenbach <xela@slit.de>, December 2002. ++ * ++ */ ++ ++/* ++ * This file handles the architecture-dependent parts of initialization ++ */ ++ ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <linux/mmzone.h> ++#include <linux/screen_info.h> ++#include <linux/ioport.h> ++#include <linux/acpi.h> ++#include <linux/apm_bios.h> ++#include <linux/initrd.h> ++#include <linux/bootmem.h> ++#include <linux/seq_file.h> ++#include <linux/platform_device.h> ++#include <linux/console.h> ++#include <linux/mca.h> ++#include <linux/root_dev.h> ++#include <linux/highmem.h> ++#include <linux/module.h> ++#include <linux/efi.h> ++#include <linux/init.h> ++#include <linux/edd.h> ++#include <linux/nodemask.h> ++#include <linux/notifier.h> ++#include <linux/kexec.h> ++#include <linux/crash_dump.h> ++#include <linux/dmi.h> ++#include <linux/pfn.h> ++ ++#include <video/edid.h> ++ ++#include <asm/apic.h> ++#include <asm/e820.h> ++#include <asm/mpspec.h> ++#include <asm/mmzone.h> ++#include <asm/setup.h> ++#include <asm/arch_hooks.h> ++#include <asm/sections.h> ++#include <asm/io_apic.h> ++#include <asm/ist.h> ++#include <asm/io.h> ++#include <setup_arch.h> ++#include <bios_ebda.h> ++ ++#include <asm/hypervisor.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/memory.h> ++#include <xen/features.h> ++#include <xen/xencons.h> ++#ifdef CONFIG_XEN ++#include <xen/interface/kexec.h> ++#endif ++ ++static int xen_panic_event(struct notifier_block *, unsigned long, void *); ++static struct notifier_block xen_panic_block = { ++ xen_panic_event, NULL, 0 /* try to go last */ ++}; ++ ++extern char hypercall_page[PAGE_SIZE]; ++EXPORT_SYMBOL(hypercall_page); ++ ++int disable_pse __devinitdata = 0; ++ ++/* ++ * Machine setup.. ++ */ ++extern struct resource code_resource; ++extern struct resource data_resource; ++ ++/* cpu data as detected by the assembly code in head.S */ ++struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; ++/* common cpu data for all cpus */ ++struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; ++EXPORT_SYMBOL(boot_cpu_data); ++ ++unsigned long mmu_cr4_features; ++ ++/* for MCA, but anyone else can use it if they want */ ++unsigned int machine_id; ++#ifdef CONFIG_MCA ++EXPORT_SYMBOL(machine_id); ++#endif ++unsigned int machine_submodel_id; ++unsigned int BIOS_revision; ++unsigned int mca_pentium_flag; ++ ++/* Boot loader ID as an integer, for the benefit of proc_dointvec */ ++int bootloader_type; ++ ++/* user-defined highmem size */ ++static unsigned int highmem_pages = -1; ++ ++/* ++ * Setup options ++ */ ++struct drive_info_struct { char dummy[32]; } drive_info; ++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ ++ defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) ++EXPORT_SYMBOL(drive_info); ++#endif ++struct screen_info screen_info; ++EXPORT_SYMBOL(screen_info); ++struct apm_info apm_info; ++EXPORT_SYMBOL(apm_info); ++struct sys_desc_table_struct { ++ unsigned short length; ++ unsigned char table[0]; ++}; ++struct edid_info edid_info; ++EXPORT_SYMBOL_GPL(edid_info); ++struct ist_info ist_info; ++#if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ ++ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) ++EXPORT_SYMBOL(ist_info); ++#endif ++ ++extern void early_cpu_init(void); ++extern int root_mountflags; ++ ++unsigned long saved_videomode; ++ ++#define RAMDISK_IMAGE_START_MASK 0x07FF ++#define RAMDISK_PROMPT_FLAG 0x8000 ++#define RAMDISK_LOAD_FLAG 0x4000 ++ ++static char command_line[COMMAND_LINE_SIZE]; ++ ++unsigned char __initdata boot_params[PARAM_SIZE]; ++ ++/* ++ * Point at the empty zero page to start with. We map the real shared_info ++ * page as soon as fixmap is up and running. ++ */ ++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page; ++EXPORT_SYMBOL(HYPERVISOR_shared_info); ++ ++unsigned long *phys_to_machine_mapping; ++unsigned long *pfn_to_mfn_frame_list_list, *pfn_to_mfn_frame_list[16]; ++EXPORT_SYMBOL(phys_to_machine_mapping); ++ ++/* Raw start-of-day parameters from the hypervisor. */ ++start_info_t *xen_start_info; ++EXPORT_SYMBOL(xen_start_info); ++ ++ ++#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) ++struct edd edd; ++#ifdef CONFIG_EDD_MODULE ++EXPORT_SYMBOL(edd); ++#endif ++/** ++ * copy_edd() - Copy the BIOS EDD information ++ * from boot_params into a safe place. ++ * ++ */ ++static inline void copy_edd(void) ++{ ++ memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); ++ memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); ++ edd.mbr_signature_nr = EDD_MBR_SIG_NR; ++ edd.edd_info_nr = EDD_NR; ++} ++#else ++static inline void copy_edd(void) ++{ ++} ++#endif ++ ++int __initdata user_defined_memmap = 0; ++ ++/* ++ * "mem=nopentium" disables the 4MB page tables. ++ * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM ++ * to <mem>, overriding the bios size. ++ * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from ++ * <start> to <start>+<mem>, overriding the bios size. ++ * ++ * HPA tells me bootloaders need to parse mem=, so no new ++ * option should be mem= [also see Documentation/i386/boot.txt] ++ */ ++static int __init parse_mem(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; ++ ++ if (strcmp(arg, "nopentium") == 0) { ++ clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); ++ disable_pse = 1; ++ } else { ++ /* If the user specifies memory size, we ++ * limit the BIOS-provided memory map to ++ * that size. exactmap can be used to specify ++ * the exact map. mem=number can be used to ++ * trim the existing memory map. ++ */ ++ unsigned long long mem_size; ++ ++ mem_size = memparse(arg, &arg); ++ limit_regions(mem_size); ++ user_defined_memmap = 1; ++ } ++ return 0; ++} ++early_param("mem", parse_mem); ++ ++#ifdef CONFIG_PROC_VMCORE ++/* elfcorehdr= specifies the location of elf core header ++ * stored by the crashed kernel. ++ */ ++static int __init parse_elfcorehdr(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; ++ ++ elfcorehdr_addr = memparse(arg, &arg); ++ return 0; ++} ++early_param("elfcorehdr", parse_elfcorehdr); ++#endif /* CONFIG_PROC_VMCORE */ ++ ++/* ++ * highmem=size forces highmem to be exactly 'size' bytes. ++ * This works even on boxes that have no highmem otherwise. ++ * This also works to reduce highmem size on bigger boxes. ++ */ ++static int __init parse_highmem(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; ++ ++ highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT; ++ return 0; ++} ++early_param("highmem", parse_highmem); ++ ++/* ++ * vmalloc=size forces the vmalloc area to be exactly 'size' ++ * bytes. This can be used to increase (or decrease) the ++ * vmalloc area - the default is 128m. ++ */ ++static int __init parse_vmalloc(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; ++ ++ __VMALLOC_RESERVE = memparse(arg, &arg); ++ return 0; ++} ++early_param("vmalloc", parse_vmalloc); ++ ++/* ++ * reservetop=size reserves a hole at the top of the kernel address space which ++ * a hypervisor can load into later. Needed for dynamically loaded hypervisors, ++ * so relocating the fixmap can be done before paging initialization. ++ */ ++static int __init parse_reservetop(char *arg) ++{ ++ unsigned long address; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ address = memparse(arg, &arg); ++ reserve_top_address(address); ++ return 0; ++} ++early_param("reservetop", parse_reservetop); ++ ++/* ++ * Determine low and high memory ranges: ++ */ ++unsigned long __init find_max_low_pfn(void) ++{ ++ unsigned long max_low_pfn; ++ ++ max_low_pfn = max_pfn; ++ if (max_low_pfn > MAXMEM_PFN) { ++ if (highmem_pages == -1) ++ highmem_pages = max_pfn - MAXMEM_PFN; ++ if (highmem_pages + MAXMEM_PFN < max_pfn) ++ max_pfn = MAXMEM_PFN + highmem_pages; ++ if (highmem_pages + MAXMEM_PFN > max_pfn) { ++ printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); ++ highmem_pages = 0; ++ } ++ max_low_pfn = MAXMEM_PFN; ++#ifndef CONFIG_HIGHMEM ++ /* Maximum memory usable is what is directly addressable */ ++ printk(KERN_WARNING "Warning only %ldMB will be used.\n", ++ MAXMEM>>20); ++ if (max_pfn > MAX_NONPAE_PFN) ++ printk(KERN_WARNING "Use a PAE enabled kernel.\n"); ++ else ++ printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); ++ max_pfn = MAXMEM_PFN; ++#else /* !CONFIG_HIGHMEM */ ++#ifndef CONFIG_X86_PAE ++ if (max_pfn > MAX_NONPAE_PFN) { ++ max_pfn = MAX_NONPAE_PFN; ++ printk(KERN_WARNING "Warning only 4GB will be used.\n"); ++ printk(KERN_WARNING "Use a PAE enabled kernel.\n"); ++ } ++#endif /* !CONFIG_X86_PAE */ ++#endif /* !CONFIG_HIGHMEM */ ++ } else { ++ if (highmem_pages == -1) ++ highmem_pages = 0; ++#ifdef CONFIG_HIGHMEM ++ if (highmem_pages >= max_pfn) { ++ printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); ++ highmem_pages = 0; ++ } ++ if (highmem_pages) { ++ if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ ++ printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); ++ highmem_pages = 0; ++ } ++ max_low_pfn -= highmem_pages; ++ } ++#else ++ if (highmem_pages) ++ printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n"); ++#endif ++ } ++ return max_low_pfn; ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * workaround for Dell systems that neglect to reserve EBDA ++ */ ++static void __init reserve_ebda_region(void) ++{ ++ unsigned int addr; ++ addr = get_bios_ebda(); ++ if (addr) ++ reserve_bootmem(addr, PAGE_SIZE); ++} ++#endif ++ ++#ifndef CONFIG_NEED_MULTIPLE_NODES ++void __init setup_bootmem_allocator(void); ++static unsigned long __init setup_memory(void) ++{ ++ /* ++ * partially used pages are not usable - thus ++ * we are rounding upwards: ++ */ ++ min_low_pfn = PFN_UP(__pa(xen_start_info->pt_base)) + ++ xen_start_info->nr_pt_frames; ++ ++ find_max_pfn(); ++ ++ max_low_pfn = find_max_low_pfn(); ++ ++#ifdef CONFIG_HIGHMEM ++ highstart_pfn = highend_pfn = max_pfn; ++ if (max_pfn > max_low_pfn) { ++ highstart_pfn = max_low_pfn; ++ } ++ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", ++ pages_to_mb(highend_pfn - highstart_pfn)); ++ num_physpages = highend_pfn; ++ high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; ++#else ++ num_physpages = max_low_pfn; ++ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; ++#endif ++#ifdef CONFIG_FLATMEM ++ max_mapnr = num_physpages; ++#endif ++ printk(KERN_NOTICE "%ldMB LOWMEM available.\n", ++ pages_to_mb(max_low_pfn)); ++ ++ setup_bootmem_allocator(); ++ ++ return max_low_pfn; ++} ++ ++void __init zone_sizes_init(void) ++{ ++ /* ++ * XEN: Our notion of "DMA memory" is fake when running over Xen. ++ * We simply put all RAM in the DMA zone so that those drivers which ++ * needlessly specify GFP_DMA do not get starved of RAM unnecessarily. ++ * Those drivers that *do* require lowmem are screwed anyway when ++ * running over Xen! ++ */ ++ unsigned long max_zone_pfns[MAX_NR_ZONES]; ++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); ++ max_zone_pfns[ZONE_DMA] = max_low_pfn; ++ max_zone_pfns[ZONE_NORMAL] = max_low_pfn; ++#ifdef CONFIG_HIGHMEM ++ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; ++ add_active_range(0, 0, highend_pfn); ++#else ++ add_active_range(0, 0, max_low_pfn); ++#endif ++ ++ free_area_init_nodes(max_zone_pfns); ++} ++#else ++extern unsigned long __init setup_memory(void); ++extern void zone_sizes_init(void); ++#endif /* !CONFIG_NEED_MULTIPLE_NODES */ ++ ++void __init setup_bootmem_allocator(void) ++{ ++ unsigned long bootmap_size; ++ /* ++ * Initialize the boot-time allocator (with low memory only): ++ */ ++ bootmap_size = init_bootmem(min_low_pfn, max_low_pfn); ++ ++ register_bootmem_low_pages(max_low_pfn); ++ ++ /* ++ * Reserve the bootmem bitmap itself as well. We do this in two ++ * steps (first step was init_bootmem()) because this catches ++ * the (very unlikely) case of us accidentally initializing the ++ * bootmem allocator with an invalid RAM area. ++ */ ++ reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) + ++ bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text)); ++ ++#ifndef CONFIG_XEN ++ /* ++ * reserve physical page 0 - it's a special BIOS page on many boxes, ++ * enabling clean reboots, SMP operation, laptop functions. ++ */ ++ reserve_bootmem(0, PAGE_SIZE); ++ ++ /* reserve EBDA region, it's a 4K region */ ++ reserve_ebda_region(); ++ ++ /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent ++ PCI prefetch into it (errata #56). Usually the page is reserved anyways, ++ unless you have no PS/2 mouse plugged in. */ ++ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && ++ boot_cpu_data.x86 == 6) ++ reserve_bootmem(0xa0000 - 4096, 4096); ++ ++#ifdef CONFIG_SMP ++ /* ++ * But first pinch a few for the stack/trampoline stuff ++ * FIXME: Don't need the extra page at 4K, but need to fix ++ * trampoline before removing it. (see the GDT stuff) ++ */ ++ reserve_bootmem(PAGE_SIZE, PAGE_SIZE); ++#endif ++#ifdef CONFIG_ACPI_SLEEP ++ /* ++ * Reserve low memory region for sleep support. ++ */ ++ acpi_reserve_bootmem(); ++#endif ++#endif /* !CONFIG_XEN */ ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (xen_start_info->mod_start) { ++ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { ++ /*reserve_bootmem(INITRD_START, INITRD_SIZE);*/ ++ initrd_start = INITRD_START + PAGE_OFFSET; ++ initrd_end = initrd_start+INITRD_SIZE; ++ initrd_below_start_ok = 1; ++ } ++ else { ++ printk(KERN_ERR "initrd extends beyond end of memory " ++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ INITRD_START + INITRD_SIZE, ++ max_low_pfn << PAGE_SHIFT); ++ initrd_start = 0; ++ } ++ } ++#endif ++#ifdef CONFIG_KEXEC ++#ifdef CONFIG_XEN ++ xen_machine_kexec_setup_resources(); ++#else ++ if (crashk_res.start != crashk_res.end) ++ reserve_bootmem(crashk_res.start, ++ crashk_res.end - crashk_res.start + 1); ++#endif ++#endif ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) ++ phys_to_machine_mapping = ++ (unsigned long *)xen_start_info->mfn_list; ++} ++ ++/* ++ * The node 0 pgdat is initialized before all of these because ++ * it's needed for bootmem. node>0 pgdats have their virtual ++ * space allocated before the pagetables are in place to access ++ * them, so they can't be cleared then. ++ * ++ * This should all compile down to nothing when NUMA is off. ++ */ ++void __init remapped_pgdat_init(void) ++{ ++ int nid; ++ ++ for_each_online_node(nid) { ++ if (nid != 0) ++ memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); ++ } ++} ++ ++#ifdef CONFIG_MCA ++static void set_mca_bus(int x) ++{ ++ MCA_bus = x; ++} ++#else ++static void set_mca_bus(int x) { } ++#endif ++ ++/* Overridden in paravirt.c if CONFIG_PARAVIRT */ ++char * __init __attribute__((weak)) memory_setup(void) ++{ ++ return machine_specific_memory_setup(); ++} ++ ++/* ++ * Determine if we were loaded by an EFI loader. If so, then we have also been ++ * passed the efi memmap, systab, etc., so we should use these data structures ++ * for initialization. Note, the efi init code path is determined by the ++ * global efi_enabled. This allows the same kernel image to be used on existing ++ * systems (with a traditional BIOS) as well as on EFI systems. ++ */ ++void __init setup_arch(char **cmdline_p) ++{ ++ int i, j, k, fpp; ++ struct physdev_set_iopl set_iopl; ++ unsigned long max_low_pfn; ++ ++ /* Force a quick death if the kernel panics (not domain 0). */ ++ extern int panic_timeout; ++ if (!panic_timeout && !is_initial_xendomain()) ++ panic_timeout = 1; ++ ++ /* Register a call for panic conditions. */ ++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); ++ ++ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); ++ HYPERVISOR_vm_assist(VMASST_CMD_enable, ++ VMASST_TYPE_writable_pagetables); ++ ++ memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); ++ pre_setup_arch_hook(); ++ early_cpu_init(); ++#if defined(CONFIG_XEN) && defined(CONFIG_SMP) ++ prefill_possible_map(); ++#endif ++ ++ /* ++ * FIXME: This isn't an official loader_type right ++ * now but does currently work with elilo. ++ * If we were configured as an EFI kernel, check to make ++ * sure that we were loaded correctly from elilo and that ++ * the system table is valid. If not, then initialize normally. ++ */ ++#ifdef CONFIG_EFI ++ if ((LOADER_TYPE == 0x50) && EFI_SYSTAB) ++ efi_enabled = 1; ++#endif ++ ++ /* This must be initialized to UNNAMED_MAJOR for ipconfig to work ++ properly. Setting ROOT_DEV to default to /dev/ram0 breaks initrd. ++ */ ++ ROOT_DEV = MKDEV(UNNAMED_MAJOR,0); ++ drive_info = DRIVE_INFO; ++ screen_info = SCREEN_INFO; ++ edid_info = EDID_INFO; ++ apm_info.bios = APM_BIOS_INFO; ++ ist_info = IST_INFO; ++ saved_videomode = VIDEO_MODE; ++ if( SYS_DESC_TABLE.length != 0 ) { ++ set_mca_bus(SYS_DESC_TABLE.table[3] & 0x2); ++ machine_id = SYS_DESC_TABLE.table[0]; ++ machine_submodel_id = SYS_DESC_TABLE.table[1]; ++ BIOS_revision = SYS_DESC_TABLE.table[2]; ++ } ++ bootloader_type = LOADER_TYPE; ++ ++ if (is_initial_xendomain()) { ++ /* This is drawn from a dump from vgacon:startup in ++ * standard Linux. */ ++ screen_info.orig_video_mode = 3; ++ screen_info.orig_video_isVGA = 1; ++ screen_info.orig_video_lines = 25; ++ screen_info.orig_video_cols = 80; ++ screen_info.orig_video_ega_bx = 3; ++ screen_info.orig_video_points = 16; ++ screen_info.orig_y = screen_info.orig_video_lines - 1; ++ if (xen_start_info->console.dom0.info_size >= ++ sizeof(struct dom0_vga_console_info)) { ++ const struct dom0_vga_console_info *info = ++ (struct dom0_vga_console_info *)( ++ (char *)xen_start_info + ++ xen_start_info->console.dom0.info_off); ++ dom0_init_screen_info(info); ++ } ++ xen_start_info->console.domU.mfn = 0; ++ xen_start_info->console.domU.evtchn = 0; ++ } else ++ screen_info.orig_video_isVGA = 0; ++ ++#ifdef CONFIG_BLK_DEV_RAM ++ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; ++ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); ++ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); ++#endif ++ ++ setup_xen_features(); ++ ++ ARCH_SETUP ++ if (efi_enabled) ++ efi_init(); ++ else { ++ printk(KERN_INFO "BIOS-provided physical RAM map:\n"); ++ print_memory_map(memory_setup()); ++ } ++ ++ copy_edd(); ++ ++ if (!MOUNT_ROOT_RDONLY) ++ root_mountflags &= ~MS_RDONLY; ++ init_mm.start_code = (unsigned long) _text; ++ init_mm.end_code = (unsigned long) _etext; ++ init_mm.end_data = (unsigned long) _edata; ++ init_mm.brk = (PFN_UP(__pa(xen_start_info->pt_base)) + ++ xen_start_info->nr_pt_frames) << PAGE_SHIFT; ++ ++ code_resource.start = virt_to_phys(_text); ++ code_resource.end = virt_to_phys(_etext)-1; ++ data_resource.start = virt_to_phys(_etext); ++ data_resource.end = virt_to_phys(_edata)-1; ++ ++ parse_early_param(); ++ ++ if (user_defined_memmap) { ++ printk(KERN_INFO "user-defined physical RAM map:\n"); ++ print_memory_map("user"); ++ } ++ ++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ *cmdline_p = command_line; ++ ++ max_low_pfn = setup_memory(); ++ ++ /* ++ * NOTE: before this point _nobody_ is allowed to allocate ++ * any memory using the bootmem allocator. Although the ++ * alloctor is now initialised only the first 8Mb of the kernel ++ * virtual address space has been mapped. All allocations before ++ * paging_init() has completed must use the alloc_bootmem_low_pages() ++ * variant (which allocates DMA'able memory) and care must be taken ++ * not to exceed the 8Mb limit. ++ */ ++ ++#ifdef CONFIG_SMP ++ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ ++#endif ++ paging_init(); ++ remapped_pgdat_init(); ++ sparse_init(); ++ zone_sizes_init(); ++ ++#ifdef CONFIG_X86_FIND_SMP_CONFIG ++ /* ++ * Find and reserve possible boot-time SMP configuration: ++ */ ++ find_smp_config(); ++#endif ++ numa_kva_reserve(); ++ ++ /* Make sure we have a correctly sized P->M table. */ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ phys_to_machine_mapping = alloc_bootmem_low_pages( ++ max_pfn * sizeof(unsigned long)); ++ memset(phys_to_machine_mapping, ~0, ++ max_pfn * sizeof(unsigned long)); ++ memcpy(phys_to_machine_mapping, ++ (unsigned long *)xen_start_info->mfn_list, ++ xen_start_info->nr_pages * sizeof(unsigned long)); ++ free_bootmem( ++ __pa(xen_start_info->mfn_list), ++ PFN_PHYS(PFN_UP(xen_start_info->nr_pages * ++ sizeof(unsigned long)))); ++ ++ /* ++ * Initialise the list of the frames that specify the list of ++ * frames that make up the p2m table. Used by save/restore ++ */ ++ pfn_to_mfn_frame_list_list = alloc_bootmem_low_pages(PAGE_SIZE); ++ ++ fpp = PAGE_SIZE/sizeof(unsigned long); ++ for (i=0, j=0, k=-1; i< max_pfn; i+=fpp, j++) { ++ if ((j % fpp) == 0) { ++ k++; ++ BUG_ON(k>=16); ++ pfn_to_mfn_frame_list[k] = ++ alloc_bootmem_low_pages(PAGE_SIZE); ++ pfn_to_mfn_frame_list_list[k] = ++ virt_to_mfn(pfn_to_mfn_frame_list[k]); ++ j=0; ++ } ++ pfn_to_mfn_frame_list[k][j] = ++ virt_to_mfn(&phys_to_machine_mapping[i]); ++ } ++ HYPERVISOR_shared_info->arch.max_pfn = max_pfn; ++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = ++ virt_to_mfn(pfn_to_mfn_frame_list_list); ++ } ++ ++ /* ++ * NOTE: at this point the bootmem allocator is fully available. ++ */ ++ ++ if (is_initial_xendomain()) ++ dmi_scan_machine(); ++ ++#ifdef CONFIG_X86_GENERICARCH ++ generic_apic_probe(); ++#endif ++ if (efi_enabled) ++ efi_map_memmap(); ++ ++ set_iopl.iopl = 1; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); ++ ++#ifdef CONFIG_ACPI ++ if (!is_initial_xendomain()) { ++ printk(KERN_INFO "ACPI in unprivileged domain disabled\n"); ++ acpi_disabled = 1; ++ acpi_ht = 0; ++ } ++ ++ /* ++ * Parse the ACPI tables for possible boot-time SMP configuration. ++ */ ++ acpi_boot_table_init(); ++#endif ++ ++#ifdef CONFIG_PCI ++#ifdef CONFIG_X86_IO_APIC ++ check_acpi_pci(); /* Checks more than just ACPI actually */ ++#endif ++#endif ++ ++#ifdef CONFIG_ACPI ++ acpi_boot_init(); ++ ++#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC) ++ if (def_to_bigsmp) ++ printk(KERN_WARNING "More than 8 CPUs detected and " ++ "CONFIG_X86_PC cannot handle it.\nUse " ++ "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n"); ++#endif ++#endif ++#ifdef CONFIG_X86_LOCAL_APIC ++ if (smp_found_config) ++ get_smp_config(); ++#endif ++ ++ e820_register_memory(); ++ ++ if (is_initial_xendomain()) { ++#ifdef CONFIG_VT ++#if defined(CONFIG_VGA_CONSOLE) ++ if (!efi_enabled || ++ (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) ++ conswitchp = &vga_con; ++#elif defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++#endif ++ } else { ++#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++ } ++ tsc_init(); ++ ++ xencons_early_setup(); ++} ++ ++static int ++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ HYPERVISOR_shutdown(SHUTDOWN_crash); ++ /* we're never actually going to get here... */ ++ return NOTIFY_DONE; ++} ++ ++static __init int add_pcspkr(void) ++{ ++ struct platform_device *pd; ++ int ret; ++ ++ if (!is_initial_xendomain()) ++ return 0; ++ ++ pd = platform_device_alloc("pcspkr", -1); ++ if (!pd) ++ return -ENOMEM; ++ ++ ret = platform_device_add(pd); ++ if (ret) ++ platform_device_put(pd); ++ ++ return ret; ++} ++device_initcall(add_pcspkr); ++ ++/* ++ * Local Variables: ++ * mode:c ++ * c-file-style:"k&r" ++ * c-basic-offset:8 ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/smp-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/smp-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,628 @@ ++/* ++ * Intel SMP support routines. ++ * ++ * (c) 1995 Alan Cox, Building #3 <alan@redhat.com> ++ * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com> ++ * ++ * This code is released under the GNU General Public License version 2 or ++ * later. ++ */ ++ ++#include <linux/init.h> ++ ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/spinlock.h> ++#include <linux/smp_lock.h> ++#include <linux/kernel_stat.h> ++#include <linux/mc146818rtc.h> ++#include <linux/cache.h> ++#include <linux/interrupt.h> ++#include <linux/cpu.h> ++#include <linux/module.h> ++ ++#include <asm/mtrr.h> ++#include <asm/tlbflush.h> ++#if 0 ++#include <mach_apic.h> ++#endif ++#include <xen/evtchn.h> ++ ++/* ++ * Some notes on x86 processor bugs affecting SMP operation: ++ * ++ * Pentium, Pentium Pro, II, III (and all CPUs) have bugs. ++ * The Linux implications for SMP are handled as follows: ++ * ++ * Pentium III / [Xeon] ++ * None of the E1AP-E3AP errata are visible to the user. ++ * ++ * E1AP. see PII A1AP ++ * E2AP. see PII A2AP ++ * E3AP. see PII A3AP ++ * ++ * Pentium II / [Xeon] ++ * None of the A1AP-A3AP errata are visible to the user. ++ * ++ * A1AP. see PPro 1AP ++ * A2AP. see PPro 2AP ++ * A3AP. see PPro 7AP ++ * ++ * Pentium Pro ++ * None of 1AP-9AP errata are visible to the normal user, ++ * except occasional delivery of 'spurious interrupt' as trap #15. ++ * This is very rare and a non-problem. ++ * ++ * 1AP. Linux maps APIC as non-cacheable ++ * 2AP. worked around in hardware ++ * 3AP. fixed in C0 and above steppings microcode update. ++ * Linux does not use excessive STARTUP_IPIs. ++ * 4AP. worked around in hardware ++ * 5AP. symmetric IO mode (normal Linux operation) not affected. ++ * 'noapic' mode has vector 0xf filled out properly. ++ * 6AP. 'noapic' mode might be affected - fixed in later steppings ++ * 7AP. We do not assume writes to the LVT deassering IRQs ++ * 8AP. We do not enable low power mode (deep sleep) during MP bootup ++ * 9AP. We do not use mixed mode ++ * ++ * Pentium ++ * There is a marginal case where REP MOVS on 100MHz SMP ++ * machines with B stepping processors can fail. XXX should provide ++ * an L1cache=Writethrough or L1cache=off option. ++ * ++ * B stepping CPUs may hang. There are hardware work arounds ++ * for this. We warn about it in case your board doesn't have the work ++ * arounds. Basically thats so I can tell anyone with a B stepping ++ * CPU and SMP problems "tough". ++ * ++ * Specific items [From Pentium Processor Specification Update] ++ * ++ * 1AP. Linux doesn't use remote read ++ * 2AP. Linux doesn't trust APIC errors ++ * 3AP. We work around this ++ * 4AP. Linux never generated 3 interrupts of the same priority ++ * to cause a lost local interrupt. ++ * 5AP. Remote read is never used ++ * 6AP. not affected - worked around in hardware ++ * 7AP. not affected - worked around in hardware ++ * 8AP. worked around in hardware - we get explicit CS errors if not ++ * 9AP. only 'noapic' mode affected. Might generate spurious ++ * interrupts, we log only the first one and count the ++ * rest silently. ++ * 10AP. not affected - worked around in hardware ++ * 11AP. Linux reads the APIC between writes to avoid this, as per ++ * the documentation. Make sure you preserve this as it affects ++ * the C stepping chips too. ++ * 12AP. not affected - worked around in hardware ++ * 13AP. not affected - worked around in hardware ++ * 14AP. we always deassert INIT during bootup ++ * 15AP. not affected - worked around in hardware ++ * 16AP. not affected - worked around in hardware ++ * 17AP. not affected - worked around in hardware ++ * 18AP. not affected - worked around in hardware ++ * 19AP. not affected - worked around in BIOS ++ * ++ * If this sounds worrying believe me these bugs are either ___RARE___, ++ * or are signal timing bugs worked around in hardware and there's ++ * about nothing of note with C stepping upwards. ++ */ ++ ++DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, }; ++ ++/* ++ * the following functions deal with sending IPIs between CPUs. ++ * ++ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too. ++ */ ++ ++static inline int __prepare_ICR (unsigned int shortcut, int vector) ++{ ++ unsigned int icr = shortcut | APIC_DEST_LOGICAL; ++ ++ switch (vector) { ++ default: ++ icr |= APIC_DM_FIXED | vector; ++ break; ++ case NMI_VECTOR: ++ icr |= APIC_DM_NMI; ++ break; ++ } ++ return icr; ++} ++ ++static inline int __prepare_ICR2 (unsigned int mask) ++{ ++ return SET_APIC_DEST_FIELD(mask); ++} ++ ++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); ++ ++static inline void __send_IPI_one(unsigned int cpu, int vector) ++{ ++ int irq = per_cpu(ipi_to_irq, cpu)[vector]; ++ BUG_ON(irq < 0); ++ notify_remote_via_irq(irq); ++} ++ ++void __send_IPI_shortcut(unsigned int shortcut, int vector) ++{ ++ int cpu; ++ ++ switch (shortcut) { ++ case APIC_DEST_SELF: ++ __send_IPI_one(smp_processor_id(), vector); ++ break; ++ case APIC_DEST_ALLBUT: ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (cpu == smp_processor_id()) ++ continue; ++ if (cpu_isset(cpu, cpu_online_map)) { ++ __send_IPI_one(cpu, vector); ++ } ++ } ++ break; ++ default: ++ printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, ++ vector); ++ break; ++ } ++} ++ ++void fastcall send_IPI_self(int vector) ++{ ++ __send_IPI_shortcut(APIC_DEST_SELF, vector); ++} ++ ++/* ++ * This is only used on smaller machines. ++ */ ++void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) ++{ ++ unsigned long mask = cpus_addr(cpumask)[0]; ++ unsigned long flags; ++ unsigned int cpu; ++ ++ local_irq_save(flags); ++ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); ++ ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (cpu_isset(cpu, cpumask)) { ++ __send_IPI_one(cpu, vector); ++ } ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void send_IPI_mask_sequence(cpumask_t mask, int vector) ++{ ++ ++ send_IPI_mask_bitmask(mask, vector); ++} ++ ++#include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */ ++ ++#if 0 /* XEN */ ++/* ++ * Smarter SMP flushing macros. ++ * c/o Linus Torvalds. ++ * ++ * These mean you can really definitely utterly forget about ++ * writing to user space from interrupts. (Its not allowed anyway). ++ * ++ * Optimizations Manfred Spraul <manfred@colorfullife.com> ++ */ ++ ++static cpumask_t flush_cpumask; ++static struct mm_struct * flush_mm; ++static unsigned long flush_va; ++static DEFINE_SPINLOCK(tlbstate_lock); ++#define FLUSH_ALL 0xffffffff ++ ++/* ++ * We cannot call mmdrop() because we are in interrupt context, ++ * instead update mm->cpu_vm_mask. ++ * ++ * We need to reload %cr3 since the page tables may be going ++ * away from under us.. ++ */ ++static inline void leave_mm (unsigned long cpu) ++{ ++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) ++ BUG(); ++ cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); ++ load_cr3(swapper_pg_dir); ++} ++ ++/* ++ * ++ * The flush IPI assumes that a thread switch happens in this order: ++ * [cpu0: the cpu that switches] ++ * 1) switch_mm() either 1a) or 1b) ++ * 1a) thread switch to a different mm ++ * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask); ++ * Stop ipi delivery for the old mm. This is not synchronized with ++ * the other cpus, but smp_invalidate_interrupt ignore flush ipis ++ * for the wrong mm, and in the worst case we perform a superflous ++ * tlb flush. ++ * 1a2) set cpu_tlbstate to TLBSTATE_OK ++ * Now the smp_invalidate_interrupt won't call leave_mm if cpu0 ++ * was in lazy tlb mode. ++ * 1a3) update cpu_tlbstate[].active_mm ++ * Now cpu0 accepts tlb flushes for the new mm. ++ * 1a4) cpu_set(cpu, new_mm->cpu_vm_mask); ++ * Now the other cpus will send tlb flush ipis. ++ * 1a4) change cr3. ++ * 1b) thread switch without mm change ++ * cpu_tlbstate[].active_mm is correct, cpu0 already handles ++ * flush ipis. ++ * 1b1) set cpu_tlbstate to TLBSTATE_OK ++ * 1b2) test_and_set the cpu bit in cpu_vm_mask. ++ * Atomically set the bit [other cpus will start sending flush ipis], ++ * and test the bit. ++ * 1b3) if the bit was 0: leave_mm was called, flush the tlb. ++ * 2) switch %%esp, ie current ++ * ++ * The interrupt must handle 2 special cases: ++ * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm. ++ * - the cpu performs speculative tlb reads, i.e. even if the cpu only ++ * runs in kernel space, the cpu could load tlb entries for user space ++ * pages. ++ * ++ * The good news is that cpu_tlbstate is local to each cpu, no ++ * write/read ordering problems. ++ */ ++ ++/* ++ * TLB flush IPI: ++ * ++ * 1) Flush the tlb entries if the cpu uses the mm that's being flushed. ++ * 2) Leave the mm if we are in the lazy tlb mode. ++ */ ++ ++irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ unsigned long cpu; ++ ++ cpu = get_cpu(); ++ ++ if (!cpu_isset(cpu, flush_cpumask)) ++ goto out; ++ /* ++ * This was a BUG() but until someone can quote me the ++ * line from the intel manual that guarantees an IPI to ++ * multiple CPUs is retried _only_ on the erroring CPUs ++ * its staying as a return ++ * ++ * BUG(); ++ */ ++ ++ if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { ++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { ++ if (flush_va == FLUSH_ALL) ++ local_flush_tlb(); ++ else ++ __flush_tlb_one(flush_va); ++ } else ++ leave_mm(cpu); ++ } ++ smp_mb__before_clear_bit(); ++ cpu_clear(cpu, flush_cpumask); ++ smp_mb__after_clear_bit(); ++out: ++ put_cpu_no_resched(); ++ ++ return IRQ_HANDLED; ++} ++ ++static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, ++ unsigned long va) ++{ ++ /* ++ * A couple of (to be removed) sanity checks: ++ * ++ * - current CPU must not be in mask ++ * - mask must exist :) ++ */ ++ BUG_ON(cpus_empty(cpumask)); ++ BUG_ON(cpu_isset(smp_processor_id(), cpumask)); ++ BUG_ON(!mm); ++ ++ /* If a CPU which we ran on has gone down, OK. */ ++ cpus_and(cpumask, cpumask, cpu_online_map); ++ if (cpus_empty(cpumask)) ++ return; ++ ++ /* ++ * i'm not happy about this global shared spinlock in the ++ * MM hot path, but we'll see how contended it is. ++ * Temporarily this turns IRQs off, so that lockups are ++ * detected by the NMI watchdog. ++ */ ++ spin_lock(&tlbstate_lock); ++ ++ flush_mm = mm; ++ flush_va = va; ++#if NR_CPUS <= BITS_PER_LONG ++ atomic_set_mask(cpumask, &flush_cpumask); ++#else ++ { ++ int k; ++ unsigned long *flush_mask = (unsigned long *)&flush_cpumask; ++ unsigned long *cpu_mask = (unsigned long *)&cpumask; ++ for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k) ++ atomic_set_mask(cpu_mask[k], &flush_mask[k]); ++ } ++#endif ++ /* ++ * We have to send the IPI only to ++ * CPUs affected. ++ */ ++ send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); ++ ++ while (!cpus_empty(flush_cpumask)) ++ /* nothing. lockup detection does not belong here */ ++ mb(); ++ ++ flush_mm = NULL; ++ flush_va = 0; ++ spin_unlock(&tlbstate_lock); ++} ++ ++void flush_tlb_current_task(void) ++{ ++ struct mm_struct *mm = current->mm; ++ cpumask_t cpu_mask; ++ ++ preempt_disable(); ++ cpu_mask = mm->cpu_vm_mask; ++ cpu_clear(smp_processor_id(), cpu_mask); ++ ++ local_flush_tlb(); ++ if (!cpus_empty(cpu_mask)) ++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL); ++ preempt_enable(); ++} ++ ++void flush_tlb_mm (struct mm_struct * mm) ++{ ++ cpumask_t cpu_mask; ++ ++ preempt_disable(); ++ cpu_mask = mm->cpu_vm_mask; ++ cpu_clear(smp_processor_id(), cpu_mask); ++ ++ if (current->active_mm == mm) { ++ if (current->mm) ++ local_flush_tlb(); ++ else ++ leave_mm(smp_processor_id()); ++ } ++ if (!cpus_empty(cpu_mask)) ++ flush_tlb_others(cpu_mask, mm, FLUSH_ALL); ++ ++ preempt_enable(); ++} ++ ++void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) ++{ ++ struct mm_struct *mm = vma->vm_mm; ++ cpumask_t cpu_mask; ++ ++ preempt_disable(); ++ cpu_mask = mm->cpu_vm_mask; ++ cpu_clear(smp_processor_id(), cpu_mask); ++ ++ if (current->active_mm == mm) { ++ if(current->mm) ++ __flush_tlb_one(va); ++ else ++ leave_mm(smp_processor_id()); ++ } ++ ++ if (!cpus_empty(cpu_mask)) ++ flush_tlb_others(cpu_mask, mm, va); ++ ++ preempt_enable(); ++} ++EXPORT_SYMBOL(flush_tlb_page); ++ ++static void do_flush_tlb_all(void* info) ++{ ++ unsigned long cpu = smp_processor_id(); ++ ++ __flush_tlb_all(); ++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) ++ leave_mm(cpu); ++} ++ ++void flush_tlb_all(void) ++{ ++ on_each_cpu(do_flush_tlb_all, NULL, 1, 1); ++} ++ ++#else ++ ++irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ return 0; } ++void flush_tlb_current_task(void) ++{ xen_tlb_flush_mask(¤t->mm->cpu_vm_mask); } ++void flush_tlb_mm(struct mm_struct * mm) ++{ xen_tlb_flush_mask(&mm->cpu_vm_mask); } ++void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) ++{ xen_invlpg_mask(&vma->vm_mm->cpu_vm_mask, va); } ++EXPORT_SYMBOL(flush_tlb_page); ++void flush_tlb_all(void) ++{ xen_tlb_flush_all(); } ++ ++#endif /* XEN */ ++ ++/* ++ * this function sends a 'reschedule' IPI to another CPU. ++ * it goes straight through and wastes no time serializing ++ * anything. Worst case is that we lose a reschedule ... ++ */ ++void smp_send_reschedule(int cpu) ++{ ++ WARN_ON(cpu_is_offline(cpu)); ++ send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); ++} ++ ++/* ++ * Structure and data for smp_call_function(). This is designed to minimise ++ * static memory requirements. It also looks cleaner. ++ */ ++static DEFINE_SPINLOCK(call_lock); ++ ++struct call_data_struct { ++ void (*func) (void *info); ++ void *info; ++ atomic_t started; ++ atomic_t finished; ++ int wait; ++}; ++ ++void lock_ipi_call_lock(void) ++{ ++ spin_lock_irq(&call_lock); ++} ++ ++void unlock_ipi_call_lock(void) ++{ ++ spin_unlock_irq(&call_lock); ++} ++ ++static struct call_data_struct *call_data; ++ ++/** ++ * smp_call_function(): Run a function on all other CPUs. ++ * @func: The function to run. This must be fast and non-blocking. ++ * @info: An arbitrary pointer to pass to the function. ++ * @nonatomic: currently unused. ++ * @wait: If true, wait (atomically) until function has completed on other CPUs. ++ * ++ * Returns 0 on success, else a negative status code. Does not return until ++ * remote CPUs are nearly ready to execute <<func>> or are or have executed. ++ * ++ * You must not call this function with disabled interrupts or from a ++ * hardware interrupt handler or from a bottom half handler. ++ */ ++int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ++ int wait) ++{ ++ struct call_data_struct data; ++ int cpus; ++ ++ /* Holding any lock stops cpus from going down. */ ++ spin_lock(&call_lock); ++ cpus = num_online_cpus() - 1; ++ if (!cpus) { ++ spin_unlock(&call_lock); ++ return 0; ++ } ++ ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ ++ data.func = func; ++ data.info = info; ++ atomic_set(&data.started, 0); ++ data.wait = wait; ++ if (wait) ++ atomic_set(&data.finished, 0); ++ ++ call_data = &data; ++ mb(); ++ ++ /* Send a message to all other CPUs and wait for them to respond */ ++ send_IPI_allbutself(CALL_FUNCTION_VECTOR); ++ ++ /* Wait for response */ ++ while (atomic_read(&data.started) != cpus) ++ barrier(); ++ ++ if (wait) ++ while (atomic_read(&data.finished) != cpus) ++ barrier(); ++ spin_unlock(&call_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(smp_call_function); ++ ++static void stop_this_cpu (void * dummy) ++{ ++ /* ++ * Remove this CPU: ++ */ ++ cpu_clear(smp_processor_id(), cpu_online_map); ++ local_irq_disable(); ++#if 0 ++ disable_local_APIC(); ++#endif ++ if (cpu_data[smp_processor_id()].hlt_works_ok) ++ for(;;) halt(); ++ for (;;); ++} ++ ++/* ++ * this function calls the 'stop' function on all other CPUs in the system. ++ */ ++ ++void smp_send_stop(void) ++{ ++ smp_call_function(stop_this_cpu, NULL, 1, 0); ++ ++ local_irq_disable(); ++#if 0 ++ disable_local_APIC(); ++#endif ++ local_irq_enable(); ++} ++ ++/* ++ * Reschedule call back. Nothing to do, ++ * all the work is done automatically when ++ * we return from the interrupt. ++ */ ++irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ return IRQ_HANDLED; ++} ++ ++#include <linux/kallsyms.h> ++irqreturn_t smp_call_function_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ void (*func) (void *info) = call_data->func; ++ void *info = call_data->info; ++ int wait = call_data->wait; ++ ++ /* ++ * Notify initiating CPU that I've grabbed the data and am ++ * about to execute the function ++ */ ++ mb(); ++ atomic_inc(&call_data->started); ++ /* ++ * At this point the info structure may be out of scope unless wait==1 ++ */ ++ irq_enter(); ++ (*func)(info); ++ irq_exit(); ++ ++ if (wait) { ++ mb(); ++ atomic_inc(&call_data->finished); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++int safe_smp_processor_id(void) ++{ ++ return smp_processor_id(); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/swiotlb.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/swiotlb.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,716 @@ ++/* ++ * Dynamic DMA mapping support. ++ * ++ * This implementation is a fallback for platforms that do not support ++ * I/O TLBs (aka DMA address translation hardware). ++ * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com> ++ * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com> ++ * Copyright (C) 2000, 2003 Hewlett-Packard Co ++ * David Mosberger-Tang <davidm@hpl.hp.com> ++ * Copyright (C) 2005 Keir Fraser <keir@xensource.com> ++ */ ++ ++#include <linux/cache.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/ctype.h> ++#include <linux/init.h> ++#include <linux/bootmem.h> ++#include <linux/highmem.h> ++#include <asm/io.h> ++#include <asm/pci.h> ++#include <asm/dma.h> ++#include <asm/uaccess.h> ++#include <xen/interface/memory.h> ++ ++int swiotlb; ++EXPORT_SYMBOL(swiotlb); ++ ++#define OFFSET(val,align) ((unsigned long)((val) & ( (align) - 1))) ++ ++#define SG_ENT_PHYS_ADDRESS(sg) (page_to_bus((sg)->page) + (sg)->offset) ++ ++/* ++ * Maximum allowable number of contiguous slabs to map, ++ * must be a power of 2. What is the appropriate value ? ++ * The complexity of {map,unmap}_single is linearly dependent on this value. ++ */ ++#define IO_TLB_SEGSIZE 128 ++ ++/* ++ * log of the size of each IO TLB slab. The number of slabs is command line ++ * controllable. ++ */ ++#define IO_TLB_SHIFT 11 ++ ++int swiotlb_force; ++ ++static char *iotlb_virt_start; ++static unsigned long iotlb_nslabs; ++ ++/* ++ * Used to do a quick range check in swiotlb_unmap_single and ++ * swiotlb_sync_single_*, to see if the memory was in fact allocated by this ++ * API. ++ */ ++static unsigned long iotlb_pfn_start, iotlb_pfn_end; ++ ++/* Does the given dma address reside within the swiotlb aperture? */ ++static inline int in_swiotlb_aperture(dma_addr_t dev_addr) ++{ ++ unsigned long pfn = mfn_to_local_pfn(dev_addr >> PAGE_SHIFT); ++ return (pfn_valid(pfn) ++ && (pfn >= iotlb_pfn_start) ++ && (pfn < iotlb_pfn_end)); ++} ++ ++/* ++ * When the IOMMU overflows we return a fallback buffer. This sets the size. ++ */ ++static unsigned long io_tlb_overflow = 32*1024; ++ ++void *io_tlb_overflow_buffer; ++ ++/* ++ * This is a free list describing the number of free entries available from ++ * each index ++ */ ++static unsigned int *io_tlb_list; ++static unsigned int io_tlb_index; ++ ++/* ++ * We need to save away the original address corresponding to a mapped entry ++ * for the sync operations. ++ */ ++static struct phys_addr { ++ struct page *page; ++ unsigned int offset; ++} *io_tlb_orig_addr; ++ ++/* ++ * Protect the above data structures in the map and unmap calls ++ */ ++static DEFINE_SPINLOCK(io_tlb_lock); ++ ++static unsigned int dma_bits; ++static unsigned int __initdata max_dma_bits = 32; ++static int __init ++setup_dma_bits(char *str) ++{ ++ max_dma_bits = simple_strtoul(str, NULL, 0); ++ return 0; ++} ++__setup("dma_bits=", setup_dma_bits); ++ ++static int __init ++setup_io_tlb_npages(char *str) ++{ ++ /* Unlike ia64, the size is aperture in megabytes, not 'slabs'! */ ++ if (isdigit(*str)) { ++ iotlb_nslabs = simple_strtoul(str, &str, 0) << ++ (20 - IO_TLB_SHIFT); ++ iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE); ++ /* Round up to power of two (xen_create_contiguous_region). */ ++ while (iotlb_nslabs & (iotlb_nslabs-1)) ++ iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1); ++ } ++ if (*str == ',') ++ ++str; ++ /* ++ * NB. 'force' enables the swiotlb, but doesn't force its use for ++ * every DMA like it does on native Linux. 'off' forcibly disables ++ * use of the swiotlb. ++ */ ++ if (!strcmp(str, "force")) ++ swiotlb_force = 1; ++ else if (!strcmp(str, "off")) ++ swiotlb_force = -1; ++ return 1; ++} ++__setup("swiotlb=", setup_io_tlb_npages); ++/* make io_tlb_overflow tunable too? */ ++ ++/* ++ * Statically reserve bounce buffer space and initialize bounce buffer data ++ * structures for the software IO TLB used to implement the PCI DMA API. ++ */ ++void ++swiotlb_init_with_default_size (size_t default_size) ++{ ++ unsigned long i, bytes; ++ int rc; ++ ++ if (!iotlb_nslabs) { ++ iotlb_nslabs = (default_size >> IO_TLB_SHIFT); ++ iotlb_nslabs = ALIGN(iotlb_nslabs, IO_TLB_SEGSIZE); ++ /* Round up to power of two (xen_create_contiguous_region). */ ++ while (iotlb_nslabs & (iotlb_nslabs-1)) ++ iotlb_nslabs += iotlb_nslabs & ~(iotlb_nslabs-1); ++ } ++ ++ bytes = iotlb_nslabs * (1UL << IO_TLB_SHIFT); ++ ++ /* ++ * Get IO TLB memory from the low pages ++ */ ++ iotlb_virt_start = alloc_bootmem_low_pages(bytes); ++ if (!iotlb_virt_start) ++ panic("Cannot allocate SWIOTLB buffer!\n"); ++ ++ dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT; ++ for (i = 0; i < iotlb_nslabs; i += IO_TLB_SEGSIZE) { ++ do { ++ rc = xen_create_contiguous_region( ++ (unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT), ++ get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT), ++ dma_bits); ++ } while (rc && dma_bits++ < max_dma_bits); ++ if (rc) { ++ if (i == 0) ++ panic("No suitable physical memory available for SWIOTLB buffer!\n" ++ "Use dom0_mem Xen boot parameter to reserve\n" ++ "some DMA memory (e.g., dom0_mem=-128M).\n"); ++ iotlb_nslabs = i; ++ i <<= IO_TLB_SHIFT; ++ free_bootmem(__pa(iotlb_virt_start + i), bytes - i); ++ bytes = i; ++ for (dma_bits = 0; i > 0; i -= IO_TLB_SEGSIZE << IO_TLB_SHIFT) { ++ unsigned int bits = fls64(virt_to_bus(iotlb_virt_start + i - 1)); ++ ++ if (bits > dma_bits) ++ dma_bits = bits; ++ } ++ break; ++ } ++ } ++ ++ /* ++ * Allocate and initialize the free list array. This array is used ++ * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE. ++ */ ++ io_tlb_list = alloc_bootmem(iotlb_nslabs * sizeof(int)); ++ for (i = 0; i < iotlb_nslabs; i++) ++ io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); ++ io_tlb_index = 0; ++ io_tlb_orig_addr = alloc_bootmem( ++ iotlb_nslabs * sizeof(*io_tlb_orig_addr)); ++ ++ /* ++ * Get the overflow emergency buffer ++ */ ++ io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); ++ if (!io_tlb_overflow_buffer) ++ panic("Cannot allocate SWIOTLB overflow buffer!\n"); ++ ++ do { ++ rc = xen_create_contiguous_region( ++ (unsigned long)io_tlb_overflow_buffer, ++ get_order(io_tlb_overflow), ++ dma_bits); ++ } while (rc && dma_bits++ < max_dma_bits); ++ if (rc) ++ panic("No suitable physical memory available for SWIOTLB overflow buffer!\n"); ++ ++ iotlb_pfn_start = __pa(iotlb_virt_start) >> PAGE_SHIFT; ++ iotlb_pfn_end = iotlb_pfn_start + (bytes >> PAGE_SHIFT); ++ ++ printk(KERN_INFO "Software IO TLB enabled: \n" ++ " Aperture: %lu megabytes\n" ++ " Kernel range: %p - %p\n" ++ " Address size: %u bits\n", ++ bytes >> 20, ++ iotlb_virt_start, iotlb_virt_start + bytes, ++ dma_bits); ++} ++ ++void ++swiotlb_init(void) ++{ ++ long ram_end; ++ size_t defsz = 64 * (1 << 20); /* 64MB default size */ ++ ++ if (swiotlb_force == 1) { ++ swiotlb = 1; ++ } else if ((swiotlb_force != -1) && ++ is_running_on_xen() && ++ is_initial_xendomain()) { ++ /* Domain 0 always has a swiotlb. */ ++ ram_end = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); ++ if (ram_end <= 0x7ffff) ++ defsz = 2 * (1 << 20); /* 2MB on <2GB on systems. */ ++ swiotlb = 1; ++ } ++ ++ if (swiotlb) ++ swiotlb_init_with_default_size(defsz); ++ else ++ printk(KERN_INFO "Software IO TLB disabled\n"); ++} ++ ++/* ++ * We use __copy_to_user_inatomic to transfer to the host buffer because the ++ * buffer may be mapped read-only (e.g, in blkback driver) but lower-level ++ * drivers map the buffer for DMA_BIDIRECTIONAL access. This causes an ++ * unnecessary copy from the aperture to the host buffer, and a page fault. ++ */ ++static void ++__sync_single(struct phys_addr buffer, char *dma_addr, size_t size, int dir) ++{ ++ if (PageHighMem(buffer.page)) { ++ size_t len, bytes; ++ char *dev, *host, *kmp; ++ len = size; ++ while (len != 0) { ++ unsigned long flags; ++ ++ if (((bytes = len) + buffer.offset) > PAGE_SIZE) ++ bytes = PAGE_SIZE - buffer.offset; ++ local_irq_save(flags); /* protects KM_BOUNCE_READ */ ++ kmp = kmap_atomic(buffer.page, KM_BOUNCE_READ); ++ dev = dma_addr + size - len; ++ host = kmp + buffer.offset; ++ if (dir == DMA_FROM_DEVICE) { ++ if (__copy_to_user_inatomic(host, dev, bytes)) ++ /* inaccessible */; ++ } else ++ memcpy(dev, host, bytes); ++ kunmap_atomic(kmp, KM_BOUNCE_READ); ++ local_irq_restore(flags); ++ len -= bytes; ++ buffer.page++; ++ buffer.offset = 0; ++ } ++ } else { ++ char *host = (char *)phys_to_virt( ++ page_to_pseudophys(buffer.page)) + buffer.offset; ++ if (dir == DMA_FROM_DEVICE) { ++ if (__copy_to_user_inatomic(host, dma_addr, size)) ++ /* inaccessible */; ++ } else if (dir == DMA_TO_DEVICE) ++ memcpy(dma_addr, host, size); ++ } ++} ++ ++/* ++ * Allocates bounce buffer and returns its kernel virtual address. ++ */ ++static void * ++map_single(struct device *hwdev, struct phys_addr buffer, size_t size, int dir) ++{ ++ unsigned long flags; ++ char *dma_addr; ++ unsigned int nslots, stride, index, wrap; ++ int i; ++ ++ /* ++ * For mappings greater than a page, we limit the stride (and ++ * hence alignment) to a page size. ++ */ ++ nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; ++ if (size > PAGE_SIZE) ++ stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT)); ++ else ++ stride = 1; ++ ++ BUG_ON(!nslots); ++ ++ /* ++ * Find suitable number of IO TLB entries size that will fit this ++ * request and allocate a buffer from that IO TLB pool. ++ */ ++ spin_lock_irqsave(&io_tlb_lock, flags); ++ { ++ wrap = index = ALIGN(io_tlb_index, stride); ++ ++ if (index >= iotlb_nslabs) ++ wrap = index = 0; ++ ++ do { ++ /* ++ * If we find a slot that indicates we have 'nslots' ++ * number of contiguous buffers, we allocate the ++ * buffers from that slot and mark the entries as '0' ++ * indicating unavailable. ++ */ ++ if (io_tlb_list[index] >= nslots) { ++ int count = 0; ++ ++ for (i = index; i < (int)(index + nslots); i++) ++ io_tlb_list[i] = 0; ++ for (i = index - 1; ++ (OFFSET(i, IO_TLB_SEGSIZE) != ++ IO_TLB_SEGSIZE -1) && io_tlb_list[i]; ++ i--) ++ io_tlb_list[i] = ++count; ++ dma_addr = iotlb_virt_start + ++ (index << IO_TLB_SHIFT); ++ ++ /* ++ * Update the indices to avoid searching in ++ * the next round. ++ */ ++ io_tlb_index = ++ ((index + nslots) < iotlb_nslabs ++ ? (index + nslots) : 0); ++ ++ goto found; ++ } ++ index += stride; ++ if (index >= iotlb_nslabs) ++ index = 0; ++ } while (index != wrap); ++ ++ spin_unlock_irqrestore(&io_tlb_lock, flags); ++ return NULL; ++ } ++ found: ++ spin_unlock_irqrestore(&io_tlb_lock, flags); ++ ++ /* ++ * Save away the mapping from the original address to the DMA address. ++ * This is needed when we sync the memory. Then we sync the buffer if ++ * needed. ++ */ ++ io_tlb_orig_addr[index] = buffer; ++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); ++ ++ return dma_addr; ++} ++ ++/* ++ * dma_addr is the kernel virtual address of the bounce buffer to unmap. ++ */ ++static void ++unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) ++{ ++ unsigned long flags; ++ int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; ++ int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT; ++ struct phys_addr buffer = io_tlb_orig_addr[index]; ++ ++ /* ++ * First, sync the memory before unmapping the entry ++ */ ++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE); ++ ++ /* ++ * Return the buffer to the free list by setting the corresponding ++ * entries to indicate the number of contigous entries available. ++ * While returning the entries to the free list, we merge the entries ++ * with slots below and above the pool being returned. ++ */ ++ spin_lock_irqsave(&io_tlb_lock, flags); ++ { ++ count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ? ++ io_tlb_list[index + nslots] : 0); ++ /* ++ * Step 1: return the slots to the free list, merging the ++ * slots with superceeding slots ++ */ ++ for (i = index + nslots - 1; i >= index; i--) ++ io_tlb_list[i] = ++count; ++ /* ++ * Step 2: merge the returned slots with the preceding slots, ++ * if available (non zero) ++ */ ++ for (i = index - 1; ++ (OFFSET(i, IO_TLB_SEGSIZE) != ++ IO_TLB_SEGSIZE -1) && io_tlb_list[i]; ++ i--) ++ io_tlb_list[i] = ++count; ++ } ++ spin_unlock_irqrestore(&io_tlb_lock, flags); ++} ++ ++static void ++sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir) ++{ ++ int index = (dma_addr - iotlb_virt_start) >> IO_TLB_SHIFT; ++ struct phys_addr buffer = io_tlb_orig_addr[index]; ++ BUG_ON((dir != DMA_FROM_DEVICE) && (dir != DMA_TO_DEVICE)); ++ __sync_single(buffer, dma_addr, size, dir); ++} ++ ++static void ++swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) ++{ ++ /* ++ * Ran out of IOMMU space for this operation. This is very bad. ++ * Unfortunately the drivers cannot handle this operation properly. ++ * unless they check for pci_dma_mapping_error (most don't) ++ * When the mapping is small enough return a static buffer to limit ++ * the damage, or panic when the transfer is too big. ++ */ ++ printk(KERN_ERR "PCI-DMA: Out of SW-IOMMU space for %lu bytes at " ++ "device %s\n", (unsigned long)size, dev ? dev->bus_id : "?"); ++ ++ if (size > io_tlb_overflow && do_panic) { ++ if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) ++ panic("PCI-DMA: Memory would be corrupted\n"); ++ if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) ++ panic("PCI-DMA: Random memory would be DMAed\n"); ++ } ++} ++ ++/* ++ * Map a single buffer of the indicated size for DMA in streaming mode. The ++ * PCI address to use is returned. ++ * ++ * Once the device is given the dma address, the device owns this memory until ++ * either swiotlb_unmap_single or swiotlb_dma_sync_single is performed. ++ */ ++dma_addr_t ++swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) ++{ ++ dma_addr_t dev_addr = virt_to_bus(ptr); ++ void *map; ++ struct phys_addr buffer; ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ /* ++ * If the pointer passed in happens to be in the device's DMA window, ++ * we can safely return the device addr and not worry about bounce ++ * buffering it. ++ */ ++ if (!range_straddles_page_boundary(ptr, size) && ++ !address_needs_mapping(hwdev, dev_addr)) ++ return dev_addr; ++ ++ /* ++ * Oh well, have to allocate and map a bounce buffer. ++ */ ++ buffer.page = virt_to_page(ptr); ++ buffer.offset = (unsigned long)ptr & ~PAGE_MASK; ++ map = map_single(hwdev, buffer, size, dir); ++ if (!map) { ++ swiotlb_full(hwdev, size, dir, 1); ++ map = io_tlb_overflow_buffer; ++ } ++ ++ dev_addr = virt_to_bus(map); ++ return dev_addr; ++} ++ ++/* ++ * Unmap a single streaming mode DMA translation. The dma_addr and size must ++ * match what was provided for in a previous swiotlb_map_single call. All ++ * other usages are undefined. ++ * ++ * After this call, reads by the cpu to the buffer are guaranteed to see ++ * whatever the device wrote there. ++ */ ++void ++swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, ++ int dir) ++{ ++ BUG_ON(dir == DMA_NONE); ++ if (in_swiotlb_aperture(dev_addr)) ++ unmap_single(hwdev, bus_to_virt(dev_addr), size, dir); ++} ++ ++/* ++ * Make physical memory consistent for a single streaming mode DMA translation ++ * after a transfer. ++ * ++ * If you perform a swiotlb_map_single() but wish to interrogate the buffer ++ * using the cpu, yet do not wish to teardown the PCI dma mapping, you must ++ * call this function before doing so. At the next point you give the PCI dma ++ * address back to the card, you must first perform a ++ * swiotlb_dma_sync_for_device, and then the device again owns the buffer ++ */ ++void ++swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr, ++ size_t size, int dir) ++{ ++ BUG_ON(dir == DMA_NONE); ++ if (in_swiotlb_aperture(dev_addr)) ++ sync_single(hwdev, bus_to_virt(dev_addr), size, dir); ++} ++ ++void ++swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr, ++ size_t size, int dir) ++{ ++ BUG_ON(dir == DMA_NONE); ++ if (in_swiotlb_aperture(dev_addr)) ++ sync_single(hwdev, bus_to_virt(dev_addr), size, dir); ++} ++ ++/* ++ * Map a set of buffers described by scatterlist in streaming mode for DMA. ++ * This is the scatter-gather version of the above swiotlb_map_single ++ * interface. Here the scatter gather list elements are each tagged with the ++ * appropriate dma address and length. They are obtained via ++ * sg_dma_{address,length}(SG). ++ * ++ * NOTE: An implementation may be able to use a smaller number of ++ * DMA address/length pairs than there are SG table elements. ++ * (for example via virtual mapping capabilities) ++ * The routine returns the number of addr/length pairs actually ++ * used, at most nents. ++ * ++ * Device ownership issues as mentioned above for swiotlb_map_single are the ++ * same here. ++ */ ++int ++swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, ++ int dir) ++{ ++ struct phys_addr buffer; ++ dma_addr_t dev_addr; ++ char *map; ++ int i; ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ for (i = 0; i < nelems; i++, sg++) { ++ dev_addr = SG_ENT_PHYS_ADDRESS(sg); ++ if (address_needs_mapping(hwdev, dev_addr)) { ++ buffer.page = sg->page; ++ buffer.offset = sg->offset; ++ map = map_single(hwdev, buffer, sg->length, dir); ++ if (!map) { ++ /* Don't panic here, we expect map_sg users ++ to do proper error handling. */ ++ swiotlb_full(hwdev, sg->length, dir, 0); ++ swiotlb_unmap_sg(hwdev, sg - i, i, dir); ++ sg[0].dma_length = 0; ++ return 0; ++ } ++ sg->dma_address = (dma_addr_t)virt_to_bus(map); ++ } else ++ sg->dma_address = dev_addr; ++ sg->dma_length = sg->length; ++ } ++ return nelems; ++} ++ ++/* ++ * Unmap a set of streaming mode DMA translations. Again, cpu read rules ++ * concerning calls here are the same as for swiotlb_unmap_single() above. ++ */ ++void ++swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems, ++ int dir) ++{ ++ int i; ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ for (i = 0; i < nelems; i++, sg++) ++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) ++ unmap_single(hwdev, ++ (void *)bus_to_virt(sg->dma_address), ++ sg->dma_length, dir); ++} ++ ++/* ++ * Make physical memory consistent for a set of streaming mode DMA translations ++ * after a transfer. ++ * ++ * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules ++ * and usage. ++ */ ++void ++swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg, ++ int nelems, int dir) ++{ ++ int i; ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ for (i = 0; i < nelems; i++, sg++) ++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) ++ sync_single(hwdev, ++ (void *)bus_to_virt(sg->dma_address), ++ sg->dma_length, dir); ++} ++ ++void ++swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg, ++ int nelems, int dir) ++{ ++ int i; ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ for (i = 0; i < nelems; i++, sg++) ++ if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) ++ sync_single(hwdev, ++ (void *)bus_to_virt(sg->dma_address), ++ sg->dma_length, dir); ++} ++ ++#ifdef CONFIG_HIGHMEM ++ ++dma_addr_t ++swiotlb_map_page(struct device *hwdev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ struct phys_addr buffer; ++ dma_addr_t dev_addr; ++ char *map; ++ ++ dev_addr = page_to_bus(page) + offset; ++ if (address_needs_mapping(hwdev, dev_addr)) { ++ buffer.page = page; ++ buffer.offset = offset; ++ map = map_single(hwdev, buffer, size, direction); ++ if (!map) { ++ swiotlb_full(hwdev, size, direction, 1); ++ map = io_tlb_overflow_buffer; ++ } ++ dev_addr = (dma_addr_t)virt_to_bus(map); ++ } ++ ++ return dev_addr; ++} ++ ++void ++swiotlb_unmap_page(struct device *hwdev, dma_addr_t dma_address, ++ size_t size, enum dma_data_direction direction) ++{ ++ BUG_ON(!valid_dma_direction(direction)); ++ if (in_swiotlb_aperture(dma_address)) ++ unmap_single(hwdev, bus_to_virt(dma_address), size, direction); ++} ++ ++#endif ++ ++int ++swiotlb_dma_mapping_error(dma_addr_t dma_addr) ++{ ++ return (dma_addr == virt_to_bus(io_tlb_overflow_buffer)); ++} ++ ++/* ++ * Return whether the given PCI device DMA address mask can be supported ++ * properly. For example, if your device can only drive the low 24-bits ++ * during PCI bus mastering, then you would pass 0x00ffffff as the mask to ++ * this function. ++ */ ++int ++swiotlb_dma_supported (struct device *hwdev, u64 mask) ++{ ++ return (mask >= ((1UL << dma_bits) - 1)); ++} ++ ++EXPORT_SYMBOL(swiotlb_init); ++EXPORT_SYMBOL(swiotlb_map_single); ++EXPORT_SYMBOL(swiotlb_unmap_single); ++EXPORT_SYMBOL(swiotlb_map_sg); ++EXPORT_SYMBOL(swiotlb_unmap_sg); ++EXPORT_SYMBOL(swiotlb_sync_single_for_cpu); ++EXPORT_SYMBOL(swiotlb_sync_single_for_device); ++EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu); ++EXPORT_SYMBOL(swiotlb_sync_sg_for_device); ++EXPORT_SYMBOL(swiotlb_dma_mapping_error); ++EXPORT_SYMBOL(swiotlb_dma_supported); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/sysenter.c +--- a/arch/i386/kernel/sysenter.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/sysenter.c Wed Aug 08 16:25:28 2007 -0300 +@@ -23,6 +23,10 @@ + #include <asm/pgtable.h> + #include <asm/unistd.h> + ++#ifdef CONFIG_XEN ++#include <xen/interface/callback.h> ++#endif ++ + /* + * Should the kernel map a VDSO page into processes and pass its + * address down to glibc upon exec()? +@@ -48,6 +52,7 @@ extern asmlinkage void sysenter_entry(vo + + void enable_sep_cpu(void) + { ++#ifndef CONFIG_X86_NO_TSS + int cpu = get_cpu(); + struct tss_struct *tss = &per_cpu(init_tss, cpu); + +@@ -62,6 +67,7 @@ void enable_sep_cpu(void) + wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0); + wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0); + put_cpu(); ++#endif + } + + /* +@@ -76,9 +82,26 @@ int __init sysenter_setup(void) + { + syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); + ++#ifdef CONFIG_XEN ++ if (boot_cpu_has(X86_FEATURE_SEP)) { ++ static struct callback_register __initdata sysenter = { ++ .type = CALLBACKTYPE_sysenter, ++ .address = { __KERNEL_CS, (unsigned long)sysenter_entry }, ++ }; ++ ++ if (HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) < 0) ++ clear_bit(X86_FEATURE_SEP, boot_cpu_data.x86_capability); ++ } ++#endif ++ + #ifdef CONFIG_COMPAT_VDSO + __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC); + printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO)); ++#else ++ /* ++ * In the non-compat case the ELF coredumping code needs the fixmap: ++ */ ++ __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO); + #endif + + if (!boot_cpu_has(X86_FEATURE_SEP)) { +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/time-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/time-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1091 @@ ++/* ++ * linux/arch/i386/kernel/time.c ++ * ++ * Copyright (C) 1991, 1992, 1995 Linus Torvalds ++ * ++ * This file contains the PC-specific time handling details: ++ * reading the RTC at bootup, etc.. ++ * 1994-07-02 Alan Modra ++ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime ++ * 1995-03-26 Markus Kuhn ++ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 ++ * precision CMOS clock update ++ * 1996-05-03 Ingo Molnar ++ * fixed time warps in do_[slow|fast]_gettimeoffset() ++ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 ++ * "A Kernel Model for Precision Timekeeping" by Dave Mills ++ * 1998-09-05 (Various) ++ * More robust do_fast_gettimeoffset() algorithm implemented ++ * (works with APM, Cyrix 6x86MX and Centaur C6), ++ * monotonic gettimeofday() with fast_get_timeoffset(), ++ * drift-proof precision TSC calibration on boot ++ * (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D. ++ * Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>; ++ * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>). ++ * 1998-12-16 Andrea Arcangeli ++ * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy ++ * because was not accounting lost_ticks. ++ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli ++ * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to ++ * serialize accesses to xtime/lost_ticks). ++ */ ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/param.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/module.h> ++#include <linux/sysdev.h> ++#include <linux/bcd.h> ++#include <linux/efi.h> ++#include <linux/mca.h> ++#include <linux/sysctl.h> ++#include <linux/percpu.h> ++#include <linux/kernel_stat.h> ++#include <linux/posix-timers.h> ++ ++#include <asm/io.h> ++#include <asm/smp.h> ++#include <asm/irq.h> ++#include <asm/msr.h> ++#include <asm/delay.h> ++#include <asm/mpspec.h> ++#include <asm/uaccess.h> ++#include <asm/processor.h> ++#include <asm/timer.h> ++#include <asm/time.h> ++ ++#include "mach_time.h" ++ ++#include <linux/timex.h> ++ ++#include <asm/hpet.h> ++ ++#ifdef __i386__ ++#include <asm/arch_hooks.h> ++#endif ++ ++#include <xen/evtchn.h> ++#include <xen/interface/vcpu.h> ++ ++#include <asm/i8259.h> ++ ++int pit_latch_buggy; /* extern */ ++ ++#define USEC_PER_TICK (USEC_PER_SEC / HZ) ++#define NSEC_PER_TICK (NSEC_PER_SEC / HZ) ++#define FSEC_PER_TICK (FSEC_PER_SEC / HZ) ++ ++#define NS_SCALE 10 /* 2^10, carefully chosen */ ++#define US_SCALE 32 /* 2^32, arbitralrily chosen */ ++ ++unsigned int cpu_khz; /* Detected as we calibrate the TSC */ ++EXPORT_SYMBOL(cpu_khz); ++ ++DEFINE_SPINLOCK(rtc_lock); ++EXPORT_SYMBOL(rtc_lock); ++ ++extern struct init_timer_opts timer_tsc_init; ++extern struct timer_opts timer_tsc; ++#define timer_none timer_tsc ++ ++/* These are peridically updated in shared_info, and then copied here. */ ++struct shadow_time_info { ++ u64 tsc_timestamp; /* TSC at last update of time vals. */ ++ u64 system_timestamp; /* Time, in nanosecs, since boot. */ ++ u32 tsc_to_nsec_mul; ++ u32 tsc_to_usec_mul; ++ int tsc_shift; ++ u32 version; ++}; ++static DEFINE_PER_CPU(struct shadow_time_info, shadow_time); ++static struct timespec shadow_tv; ++static u32 shadow_tv_version; ++ ++/* Keep track of last time we did processing/updating of jiffies and xtime. */ ++static u64 processed_system_time; /* System time (ns) at last processing. */ ++static DEFINE_PER_CPU(u64, processed_system_time); ++ ++/* How much CPU time was spent blocked and how much was 'stolen'? */ ++static DEFINE_PER_CPU(u64, processed_stolen_time); ++static DEFINE_PER_CPU(u64, processed_blocked_time); ++ ++/* Current runstate of each CPU (updated automatically by the hypervisor). */ ++static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate); ++ ++/* Must be signed, as it's compared with s64 quantities which can be -ve. */ ++#define NS_PER_TICK (1000000000LL/HZ) ++ ++static inline void __normalize_time(time_t *sec, s64 *nsec) ++{ ++ while (*nsec >= NSEC_PER_SEC) { ++ (*nsec) -= NSEC_PER_SEC; ++ (*sec)++; ++ } ++ while (*nsec < 0) { ++ (*nsec) += NSEC_PER_SEC; ++ (*sec)--; ++ } ++} ++ ++/* Does this guest OS track Xen time, or set its wall clock independently? */ ++static int independent_wallclock = 0; ++static int __init __independent_wallclock(char *str) ++{ ++ independent_wallclock = 1; ++ return 1; ++} ++__setup("independent_wallclock", __independent_wallclock); ++ ++/* Permitted clock jitter, in nsecs, beyond which a warning will be printed. */ ++static unsigned long permitted_clock_jitter = 10000000UL; /* 10ms */ ++static int __init __permitted_clock_jitter(char *str) ++{ ++ permitted_clock_jitter = simple_strtoul(str, NULL, 0); ++ return 1; ++} ++__setup("permitted_clock_jitter=", __permitted_clock_jitter); ++ ++/* ++ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, ++ * yielding a 64-bit result. ++ */ ++static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift) ++{ ++ u64 product; ++ u32 tmp1, tmp2; ++ ++ if (shift < 0) ++ delta >>= -shift; ++ else ++ delta <<= shift; ++ ++ __asm__ ( ++ "mul %5 ; " ++ "mov %4,%%eax ; " ++ "mov %%edx,%4 ; " ++ "mul %5 ; " ++ "xor %5,%5 ; " ++ "add %4,%%eax ; " ++ "adc %5,%%edx ; " ++ : "=A" (product), "=r" (tmp1), "=r" (tmp2) ++ : "a" ((u32)delta), "1" ((u32)(delta >> US_SCALE)), "2" (mul_frac) ); ++ ++ return product; ++} ++ ++void init_cpu_khz(void) ++{ ++ u64 __cpu_khz = 1000000ULL << US_SCALE; ++ struct vcpu_time_info *info = &vcpu_info(0)->time; ++ do_div(__cpu_khz, info->tsc_to_system_mul); ++ if (info->tsc_shift < 0) ++ cpu_khz = __cpu_khz << -info->tsc_shift; ++ else ++ cpu_khz = __cpu_khz >> info->tsc_shift; ++} ++ ++static u64 get_nsec_offset(struct shadow_time_info *shadow) ++{ ++ u64 now, delta; ++ rdtscll(now); ++ delta = now - shadow->tsc_timestamp; ++ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); ++} ++ ++static unsigned long get_usec_offset(struct shadow_time_info *shadow) ++{ ++ u64 now, delta; ++ rdtscll(now); ++ delta = now - shadow->tsc_timestamp; ++ return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); ++} ++ ++static void __update_wallclock(time_t sec, long nsec) ++{ ++ long wtm_nsec, xtime_nsec; ++ time_t wtm_sec, xtime_sec; ++ u64 tmp, wc_nsec; ++ ++ /* Adjust wall-clock time base based on jiffies ticks. */ ++ wc_nsec = processed_system_time; ++ wc_nsec += sec * (u64)NSEC_PER_SEC; ++ wc_nsec += nsec; ++ ++ /* Split wallclock base into seconds and nanoseconds. */ ++ tmp = wc_nsec; ++ xtime_nsec = do_div(tmp, 1000000000); ++ xtime_sec = (time_t)tmp; ++ ++ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec); ++ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec); ++ ++ set_normalized_timespec(&xtime, xtime_sec, xtime_nsec); ++ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); ++ ++ ntp_clear(); ++} ++ ++static void update_wallclock(void) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ ++ do { ++ shadow_tv_version = s->wc_version; ++ rmb(); ++ shadow_tv.tv_sec = s->wc_sec; ++ shadow_tv.tv_nsec = s->wc_nsec; ++ rmb(); ++ } while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version)); ++ ++ if (!independent_wallclock) ++ __update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec); ++} ++ ++/* ++ * Reads a consistent set of time-base values from Xen, into a shadow data ++ * area. ++ */ ++static void get_time_values_from_xen(int cpu) ++{ ++ struct vcpu_time_info *src; ++ struct shadow_time_info *dst; ++ ++ src = &vcpu_info(cpu)->time; ++ dst = &per_cpu(shadow_time, cpu); ++ ++ do { ++ dst->version = src->version; ++ rmb(); ++ dst->tsc_timestamp = src->tsc_timestamp; ++ dst->system_timestamp = src->system_time; ++ dst->tsc_to_nsec_mul = src->tsc_to_system_mul; ++ dst->tsc_shift = src->tsc_shift; ++ rmb(); ++ } while ((src->version & 1) | (dst->version ^ src->version)); ++ ++ dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000; ++} ++ ++static inline int time_values_up_to_date(int cpu) ++{ ++ struct vcpu_time_info *src; ++ struct shadow_time_info *dst; ++ ++ src = &vcpu_info(cpu)->time; ++ dst = &per_cpu(shadow_time, cpu); ++ ++ rmb(); ++ return (dst->version == src->version); ++} ++ ++/* ++ * This is a special lock that is owned by the CPU and holds the index ++ * register we are working with. It is required for NMI access to the ++ * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. ++ */ ++volatile unsigned long cmos_lock = 0; ++EXPORT_SYMBOL(cmos_lock); ++ ++/* Routines for accessing the CMOS RAM/RTC. */ ++unsigned char rtc_cmos_read(unsigned char addr) ++{ ++ unsigned char val; ++ lock_cmos_prefix(addr); ++ outb_p(addr, RTC_PORT(0)); ++ val = inb_p(RTC_PORT(1)); ++ lock_cmos_suffix(addr); ++ return val; ++} ++EXPORT_SYMBOL(rtc_cmos_read); ++ ++void rtc_cmos_write(unsigned char val, unsigned char addr) ++{ ++ lock_cmos_prefix(addr); ++ outb_p(addr, RTC_PORT(0)); ++ outb_p(val, RTC_PORT(1)); ++ lock_cmos_suffix(addr); ++} ++EXPORT_SYMBOL(rtc_cmos_write); ++ ++/* ++ * This version of gettimeofday has microsecond resolution ++ * and better than microsecond precision on fast x86 machines with TSC. ++ */ ++void do_gettimeofday(struct timeval *tv) ++{ ++ unsigned long seq; ++ unsigned long usec, sec; ++ unsigned long max_ntp_tick; ++ s64 nsec; ++ unsigned int cpu; ++ struct shadow_time_info *shadow; ++ u32 local_time_version; ++ ++ cpu = get_cpu(); ++ shadow = &per_cpu(shadow_time, cpu); ++ ++ do { ++ local_time_version = shadow->version; ++ seq = read_seqbegin(&xtime_lock); ++ ++ usec = get_usec_offset(shadow); ++ ++ /* ++ * If time_adjust is negative then NTP is slowing the clock ++ * so make sure not to go into next possible interval. ++ * Better to lose some accuracy than have time go backwards.. ++ */ ++ if (unlikely(time_adjust < 0)) { ++ max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj; ++ usec = min(usec, max_ntp_tick); ++ } ++ ++ sec = xtime.tv_sec; ++ usec += (xtime.tv_nsec / NSEC_PER_USEC); ++ ++ nsec = shadow->system_timestamp - processed_system_time; ++ __normalize_time(&sec, &nsec); ++ usec += (long)nsec / NSEC_PER_USEC; ++ ++ if (unlikely(!time_values_up_to_date(cpu))) { ++ /* ++ * We may have blocked for a long time, ++ * rendering our calculations invalid ++ * (e.g. the time delta may have ++ * overflowed). Detect that and recalculate ++ * with fresh values. ++ */ ++ get_time_values_from_xen(cpu); ++ continue; ++ } ++ } while (read_seqretry(&xtime_lock, seq) || ++ (local_time_version != shadow->version)); ++ ++ put_cpu(); ++ ++ while (usec >= USEC_PER_SEC) { ++ usec -= USEC_PER_SEC; ++ sec++; ++ } ++ ++ tv->tv_sec = sec; ++ tv->tv_usec = usec; ++} ++ ++EXPORT_SYMBOL(do_gettimeofday); ++ ++int do_settimeofday(struct timespec *tv) ++{ ++ time_t sec; ++ s64 nsec; ++ unsigned int cpu; ++ struct shadow_time_info *shadow; ++ struct xen_platform_op op; ++ ++ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) ++ return -EINVAL; ++ ++ cpu = get_cpu(); ++ shadow = &per_cpu(shadow_time, cpu); ++ ++ write_seqlock_irq(&xtime_lock); ++ ++ /* ++ * Ensure we don't get blocked for a long time so that our time delta ++ * overflows. If that were to happen then our shadow time values would ++ * be stale, so we can retry with fresh ones. ++ */ ++ for (;;) { ++ nsec = tv->tv_nsec - get_nsec_offset(shadow); ++ if (time_values_up_to_date(cpu)) ++ break; ++ get_time_values_from_xen(cpu); ++ } ++ sec = tv->tv_sec; ++ __normalize_time(&sec, &nsec); ++ ++ if (is_initial_xendomain() && !independent_wallclock) { ++ op.cmd = XENPF_settime; ++ op.u.settime.secs = sec; ++ op.u.settime.nsecs = nsec; ++ op.u.settime.system_time = shadow->system_timestamp; ++ HYPERVISOR_platform_op(&op); ++ update_wallclock(); ++ } else if (independent_wallclock) { ++ nsec -= shadow->system_timestamp; ++ __normalize_time(&sec, &nsec); ++ __update_wallclock(sec, nsec); ++ } ++ ++ write_sequnlock_irq(&xtime_lock); ++ ++ put_cpu(); ++ ++ clock_was_set(); ++ return 0; ++} ++ ++EXPORT_SYMBOL(do_settimeofday); ++ ++static void sync_xen_wallclock(unsigned long dummy); ++static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0); ++static void sync_xen_wallclock(unsigned long dummy) ++{ ++ time_t sec; ++ s64 nsec; ++ struct xen_platform_op op; ++ ++ if (!ntp_synced() || independent_wallclock || !is_initial_xendomain()) ++ return; ++ ++ write_seqlock_irq(&xtime_lock); ++ ++ sec = xtime.tv_sec; ++ nsec = xtime.tv_nsec; ++ __normalize_time(&sec, &nsec); ++ ++ op.cmd = XENPF_settime; ++ op.u.settime.secs = sec; ++ op.u.settime.nsecs = nsec; ++ op.u.settime.system_time = processed_system_time; ++ HYPERVISOR_platform_op(&op); ++ ++ update_wallclock(); ++ ++ write_sequnlock_irq(&xtime_lock); ++ ++ /* Once per minute. */ ++ mod_timer(&sync_xen_wallclock_timer, jiffies + 60*HZ); ++} ++ ++static int set_rtc_mmss(unsigned long nowtime) ++{ ++ int retval; ++ unsigned long flags; ++ ++ if (independent_wallclock || !is_initial_xendomain()) ++ return 0; ++ ++ /* gets recalled with irq locally disabled */ ++ /* XXX - does irqsave resolve this? -johnstul */ ++ spin_lock_irqsave(&rtc_lock, flags); ++ retval = set_wallclock(nowtime); ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ return retval; ++} ++ ++/* monotonic_clock(): returns # of nanoseconds passed since time_init() ++ * Note: This function is required to return accurate ++ * time even in the absence of multiple timer ticks. ++ */ ++unsigned long long monotonic_clock(void) ++{ ++ int cpu = get_cpu(); ++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); ++ u64 time; ++ u32 local_time_version; ++ ++ do { ++ local_time_version = shadow->version; ++ barrier(); ++ time = shadow->system_timestamp + get_nsec_offset(shadow); ++ if (!time_values_up_to_date(cpu)) ++ get_time_values_from_xen(cpu); ++ barrier(); ++ } while (local_time_version != shadow->version); ++ ++ put_cpu(); ++ ++ return time; ++} ++EXPORT_SYMBOL(monotonic_clock); ++ ++#ifdef __x86_64__ ++unsigned long long sched_clock(void) ++{ ++ return monotonic_clock(); ++} ++#endif ++ ++unsigned long profile_pc(struct pt_regs *regs) ++{ ++ unsigned long pc = instruction_pointer(regs); ++ ++#ifdef CONFIG_SMP ++ if (!user_mode_vm(regs) && in_lock_functions(pc)) { ++#ifdef CONFIG_FRAME_POINTER ++ return *(unsigned long *)(regs->ebp + 4); ++#else ++ unsigned long *sp; ++ if ((regs->xcs & 3) == 0) ++ sp = (unsigned long *)®s->esp; ++ else ++ sp = (unsigned long *)regs->esp; ++ /* Return address is either directly at stack pointer ++ or above a saved eflags. Eflags has bits 22-31 zero, ++ kernel addresses don't. */ ++ if (sp[0] >> 22) ++ return sp[0]; ++ if (sp[1] >> 22) ++ return sp[1]; ++#endif ++ } ++#endif ++ return pc; ++} ++EXPORT_SYMBOL(profile_pc); ++ ++/* ++ * This is the same as the above, except we _also_ save the current ++ * Time Stamp Counter value at the time of the timer interrupt, so that ++ * we later on can estimate the time of day more exactly. ++ */ ++irqreturn_t timer_interrupt(int irq, void *dev_id) ++{ ++ s64 delta, delta_cpu, stolen, blocked; ++ u64 sched_time; ++ int i, cpu = smp_processor_id(); ++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ ++ /* ++ * Here we are in the timer irq handler. We just have irqs locally ++ * disabled but we don't know if the timer_bh is running on the other ++ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need ++ * the irq version of write_lock because as just said we have irq ++ * locally disabled. -arca ++ */ ++ write_seqlock(&xtime_lock); ++ ++ do { ++ get_time_values_from_xen(cpu); ++ ++ /* Obtain a consistent snapshot of elapsed wallclock cycles. */ ++ delta = delta_cpu = ++ shadow->system_timestamp + get_nsec_offset(shadow); ++ delta -= processed_system_time; ++ delta_cpu -= per_cpu(processed_system_time, cpu); ++ ++ /* ++ * Obtain a consistent snapshot of stolen/blocked cycles. We ++ * can use state_entry_time to detect if we get preempted here. ++ */ ++ do { ++ sched_time = runstate->state_entry_time; ++ barrier(); ++ stolen = runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline] - ++ per_cpu(processed_stolen_time, cpu); ++ blocked = runstate->time[RUNSTATE_blocked] - ++ per_cpu(processed_blocked_time, cpu); ++ barrier(); ++ } while (sched_time != runstate->state_entry_time); ++ } while (!time_values_up_to_date(cpu)); ++ ++ if ((unlikely(delta < -(s64)permitted_clock_jitter) || ++ unlikely(delta_cpu < -(s64)permitted_clock_jitter)) ++ && printk_ratelimit()) { ++ printk("Timer ISR/%d: Time went backwards: " ++ "delta=%lld delta_cpu=%lld shadow=%lld " ++ "off=%lld processed=%lld cpu_processed=%lld\n", ++ cpu, delta, delta_cpu, shadow->system_timestamp, ++ (s64)get_nsec_offset(shadow), ++ processed_system_time, ++ per_cpu(processed_system_time, cpu)); ++ for (i = 0; i < num_online_cpus(); i++) ++ printk(" %d: %lld\n", i, ++ per_cpu(processed_system_time, i)); ++ } ++ ++ /* System-wide jiffy work. */ ++ while (delta >= NS_PER_TICK) { ++ delta -= NS_PER_TICK; ++ processed_system_time += NS_PER_TICK; ++ do_timer(1); ++ } ++ ++ if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) { ++ update_wallclock(); ++ clock_was_set(); ++ } ++ ++ write_sequnlock(&xtime_lock); ++ ++ /* ++ * Account stolen ticks. ++ * HACK: Passing NULL to account_steal_time() ++ * ensures that the ticks are accounted as stolen. ++ */ ++ if ((stolen > 0) && (delta_cpu > 0)) { ++ delta_cpu -= stolen; ++ if (unlikely(delta_cpu < 0)) ++ stolen += delta_cpu; /* clamp local-time progress */ ++ do_div(stolen, NS_PER_TICK); ++ per_cpu(processed_stolen_time, cpu) += stolen * NS_PER_TICK; ++ per_cpu(processed_system_time, cpu) += stolen * NS_PER_TICK; ++ account_steal_time(NULL, (cputime_t)stolen); ++ } ++ ++ /* ++ * Account blocked ticks. ++ * HACK: Passing idle_task to account_steal_time() ++ * ensures that the ticks are accounted as idle/wait. ++ */ ++ if ((blocked > 0) && (delta_cpu > 0)) { ++ delta_cpu -= blocked; ++ if (unlikely(delta_cpu < 0)) ++ blocked += delta_cpu; /* clamp local-time progress */ ++ do_div(blocked, NS_PER_TICK); ++ per_cpu(processed_blocked_time, cpu) += blocked * NS_PER_TICK; ++ per_cpu(processed_system_time, cpu) += blocked * NS_PER_TICK; ++ account_steal_time(idle_task(cpu), (cputime_t)blocked); ++ } ++ ++ /* Account user/system ticks. */ ++ if (delta_cpu > 0) { ++ do_div(delta_cpu, NS_PER_TICK); ++ per_cpu(processed_system_time, cpu) += delta_cpu * NS_PER_TICK; ++ if (user_mode_vm(get_irq_regs())) ++ account_user_time(current, (cputime_t)delta_cpu); ++ else ++ account_system_time(current, HARDIRQ_OFFSET, ++ (cputime_t)delta_cpu); ++ } ++ ++ /* Offlined for more than a few seconds? Avoid lockup warnings. */ ++ if (stolen > 5*HZ) ++ touch_softlockup_watchdog(); ++ ++ /* Local timer processing (see update_process_times()). */ ++ run_local_timers(); ++ if (rcu_pending(cpu)) ++ rcu_check_callbacks(cpu, user_mode_vm(get_irq_regs())); ++ scheduler_tick(); ++ run_posix_cpu_timers(current); ++// JQ: Why this works on 2.6.16 & 2.6.18 and generates a page ++// fault on 2.6.19 is a mistery to me. ++// profile_tick(CPU_PROFILING); ++ ++ return IRQ_HANDLED; ++} ++ ++static void init_missing_ticks_accounting(int cpu) ++{ ++ struct vcpu_register_runstate_memory_area area; ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ ++ memset(runstate, 0, sizeof(*runstate)); ++ ++ area.addr.v = runstate; ++ HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); ++ ++ per_cpu(processed_blocked_time, cpu) = ++ runstate->time[RUNSTATE_blocked]; ++ per_cpu(processed_stolen_time, cpu) = ++ runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline]; ++} ++ ++/* not static: needed by APM */ ++unsigned long get_cmos_time(void) ++{ ++ unsigned long retval; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rtc_lock, flags); ++ ++ retval = get_wallclock(); ++ ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ return retval; ++} ++EXPORT_SYMBOL(get_cmos_time); ++ ++static void sync_cmos_clock(unsigned long dummy); ++ ++static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); ++ ++static void sync_cmos_clock(unsigned long dummy) ++{ ++ struct timeval now, next; ++ int fail = 1; ++ ++ /* ++ * If we have an externally synchronized Linux clock, then update ++ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be ++ * called as close as possible to 500 ms before the new second starts. ++ * This code is run on a timer. If the clock is set, that timer ++ * may not expire at the correct time. Thus, we adjust... ++ */ ++ if (!ntp_synced()) ++ /* ++ * Not synced, exit, do not restart a timer (if one is ++ * running, let it run out). ++ */ ++ return; ++ ++ do_gettimeofday(&now); ++ if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && ++ now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) ++ fail = set_rtc_mmss(now.tv_sec); ++ ++ next.tv_usec = USEC_AFTER - now.tv_usec; ++ if (next.tv_usec <= 0) ++ next.tv_usec += USEC_PER_SEC; ++ ++ if (!fail) ++ next.tv_sec = 659; ++ else ++ next.tv_sec = 0; ++ ++ if (next.tv_usec >= USEC_PER_SEC) { ++ next.tv_sec++; ++ next.tv_usec -= USEC_PER_SEC; ++ } ++ mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next)); ++} ++ ++void notify_arch_cmos_timer(void) ++{ ++ mod_timer(&sync_cmos_timer, jiffies + 1); ++ mod_timer(&sync_xen_wallclock_timer, jiffies + 1); ++} ++ ++static long clock_cmos_diff; ++static unsigned long sleep_start; ++ ++static int timer_suspend(struct sys_device *dev, pm_message_t state) ++{ ++ /* ++ * Estimate time zone so that set_time can update the clock ++ */ ++ unsigned long ctime = get_cmos_time(); ++ ++ clock_cmos_diff = -ctime; ++ clock_cmos_diff += get_seconds(); ++ sleep_start = ctime; ++ return 0; ++} ++ ++static int timer_resume(struct sys_device *dev) ++{ ++ unsigned long flags; ++ unsigned long sec; ++ unsigned long ctime = get_cmos_time(); ++ long sleep_length = (ctime - sleep_start) * HZ; ++ ++ if (sleep_length < 0) { ++ printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); ++ /* The time after the resume must not be earlier than the time ++ * before the suspend or some nasty things will happen ++ */ ++ sleep_length = 0; ++ ctime = sleep_start; ++ } ++ ++#ifdef CONFIG_HPET_TIMER ++ if (is_hpet_enabled()) ++ hpet_reenable(); ++#endif ++ sec = ctime + clock_cmos_diff; ++ write_seqlock_irqsave(&xtime_lock, flags); ++ xtime.tv_sec = sec; ++ xtime.tv_nsec = 0; ++ jiffies_64 += sleep_length; ++ write_sequnlock_irqrestore(&xtime_lock, flags); ++ touch_softlockup_watchdog(); ++ return 0; ++} ++ ++static struct sysdev_class timer_sysclass = { ++ .resume = timer_resume, ++ .suspend = timer_suspend, ++ set_kset_name("timer"), ++}; ++ ++ ++/* XXX this driverfs stuff should probably go elsewhere later -john */ ++static struct sys_device device_timer = { ++ .id = 0, ++ .cls = &timer_sysclass, ++}; ++ ++static int time_init_device(void) ++{ ++ int error = sysdev_class_register(&timer_sysclass); ++ if (!error) ++ error = sysdev_register(&device_timer); ++ return error; ++} ++ ++device_initcall(time_init_device); ++ ++#ifdef CONFIG_HPET_TIMER ++extern void (*late_time_init)(void); ++/* Duplicate of time_init() below, with hpet_enable part added */ ++static void __init hpet_time_init(void) ++{ ++ xtime.tv_sec = get_cmos_time(); ++ xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); ++ set_normalized_timespec(&wall_to_monotonic, ++ -xtime.tv_sec, -xtime.tv_nsec); ++ ++ if ((hpet_enable() >= 0) && hpet_use_timer) { ++ printk("Using HPET for base-timer\n"); ++ } ++ ++ do_time_init(); ++} ++#endif ++ ++/* Dynamically-mapped IRQ. */ ++DEFINE_PER_CPU(int, timer_irq); ++ ++extern void (*late_time_init)(void); ++static void setup_cpu0_timer_irq(void) ++{ ++ per_cpu(timer_irq, 0) = ++ bind_virq_to_irqhandler( ++ VIRQ_TIMER, ++ 0, ++ timer_interrupt, ++ SA_INTERRUPT, ++ "timer0", ++ NULL); ++ BUG_ON(per_cpu(timer_irq, 0) < 0); ++} ++ ++static struct vcpu_set_periodic_timer xen_set_periodic_tick = { ++ .period_ns = NS_PER_TICK ++}; ++ ++void __init time_init(void) ++{ ++#ifdef CONFIG_HPET_TIMER ++ if (is_hpet_capable()) { ++ /* ++ * HPET initialization needs to do memory-mapped io. So, let ++ * us do a late initialization after mem_init(). ++ */ ++ late_time_init = hpet_time_init; ++ return; ++ } ++#endif ++ ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0, ++ &xen_set_periodic_tick); ++ ++ get_time_values_from_xen(0); ++ ++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp; ++ per_cpu(processed_system_time, 0) = processed_system_time; ++ init_missing_ticks_accounting(0); ++ ++ update_wallclock(); ++ ++ init_cpu_khz(); ++ printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", ++ cpu_khz / 1000, cpu_khz % 1000); ++ ++ /* Cannot request_irq() until kmem is initialised. */ ++ late_time_init = setup_cpu0_timer_irq; ++} ++ ++/* Convert jiffies to system time. */ ++u64 jiffies_to_st(unsigned long j) ++{ ++ unsigned long seq; ++ long delta; ++ u64 st; ++ ++ do { ++ seq = read_seqbegin(&xtime_lock); ++ delta = j - jiffies; ++ if (delta < 1) { ++ /* Triggers in some wrap-around cases, but that's okay: ++ * we just end up with a shorter timeout. */ ++ st = processed_system_time + NS_PER_TICK; ++ } else if (((unsigned long)delta >> (BITS_PER_LONG-3)) != 0) { ++ /* Very long timeout means there is no pending timer. ++ * We indicate this to Xen by passing zero timeout. */ ++ st = 0; ++ } else { ++ st = processed_system_time + delta * (u64)NS_PER_TICK; ++ } ++ } while (read_seqretry(&xtime_lock, seq)); ++ ++ return st; ++} ++EXPORT_SYMBOL(jiffies_to_st); ++ ++/* ++ * stop_hz_timer / start_hz_timer - enter/exit 'tickless mode' on an idle cpu ++ * These functions are based on implementations from arch/s390/kernel/time.c ++ */ ++static void stop_hz_timer(void) ++{ ++ struct vcpu_set_singleshot_timer singleshot; ++ unsigned int cpu = smp_processor_id(); ++ unsigned long j; ++ int rc; ++ ++ cpu_set(cpu, nohz_cpu_mask); ++ ++ /* See matching smp_mb in rcu_start_batch in rcupdate.c. These mbs */ ++ /* ensure that if __rcu_pending (nested in rcu_needs_cpu) fetches a */ ++ /* value of rcp->cur that matches rdp->quiescbatch and allows us to */ ++ /* stop the hz timer then the cpumasks created for subsequent values */ ++ /* of cur in rcu_start_batch are guaranteed to pick up the updated */ ++ /* nohz_cpu_mask and so will not depend on this cpu. */ ++ ++ smp_mb(); ++ ++ /* Leave ourselves in tick mode if rcu or softirq or timer pending. */ ++ if (rcu_needs_cpu(cpu) || local_softirq_pending() || ++ (j = next_timer_interrupt(), time_before_eq(j, jiffies))) { ++ cpu_clear(cpu, nohz_cpu_mask); ++ j = jiffies + 1; ++ } ++ ++ singleshot.timeout_abs_ns = jiffies_to_st(j); ++ singleshot.flags = 0; ++ rc = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &singleshot); ++#if CONFIG_XEN_COMPAT <= 0x030004 ++ if (rc) { ++ BUG_ON(rc != -ENOSYS); ++ rc = HYPERVISOR_set_timer_op(singleshot.timeout_abs_ns); ++ } ++#endif ++ BUG_ON(rc); ++} ++ ++static void start_hz_timer(void) ++{ ++ cpu_clear(smp_processor_id(), nohz_cpu_mask); ++} ++ ++void raw_safe_halt(void) ++{ ++ stop_hz_timer(); ++ /* Blocking includes an implicit local_irq_enable(). */ ++ HYPERVISOR_block(); ++ start_hz_timer(); ++} ++EXPORT_SYMBOL(raw_safe_halt); ++ ++void halt(void) ++{ ++ if (irqs_disabled()) ++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); ++} ++EXPORT_SYMBOL(halt); ++ ++/* No locking required. Interrupts are disabled on all CPUs. */ ++void time_resume(void) ++{ ++ unsigned int cpu; ++ ++ init_cpu_khz(); ++ ++ for_each_online_cpu(cpu) { ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, ++ &xen_set_periodic_tick); ++ get_time_values_from_xen(cpu); ++ per_cpu(processed_system_time, cpu) = ++ per_cpu(shadow_time, 0).system_timestamp; ++ init_missing_ticks_accounting(cpu); ++ } ++ ++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp; ++ ++ update_wallclock(); ++} ++ ++#ifdef CONFIG_SMP ++static char timer_name[NR_CPUS][15]; ++ ++int local_setup_timer(unsigned int cpu) ++{ ++ int seq, irq; ++ ++ BUG_ON(cpu == 0); ++ ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, ++ &xen_set_periodic_tick); ++ ++ do { ++ seq = read_seqbegin(&xtime_lock); ++ /* Use cpu0 timestamp: cpu's shadow is not initialised yet. */ ++ per_cpu(processed_system_time, cpu) = ++ per_cpu(shadow_time, 0).system_timestamp; ++ init_missing_ticks_accounting(cpu); ++ } while (read_seqretry(&xtime_lock, seq)); ++ ++ sprintf(timer_name[cpu], "timer%d", cpu); ++ irq = bind_virq_to_irqhandler(VIRQ_TIMER, ++ cpu, ++ timer_interrupt, ++ SA_INTERRUPT, ++ timer_name[cpu], ++ NULL); ++ if (irq < 0) ++ return irq; ++ per_cpu(timer_irq, cpu) = irq; ++ ++ return 0; ++} ++ ++void local_teardown_timer(unsigned int cpu) ++{ ++ BUG_ON(cpu == 0); ++ unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL); ++} ++#endif ++ ++/* ++ * /proc/sys/xen: This really belongs in another file. It can stay here for ++ * now however. ++ */ ++static ctl_table xen_subtable[] = { ++ { ++ .ctl_name = 1, ++ .procname = "independent_wallclock", ++ .data = &independent_wallclock, ++ .maxlen = sizeof(independent_wallclock), ++ .mode = 0644, ++ .proc_handler = proc_dointvec ++ }, ++ { ++ .ctl_name = 2, ++ .procname = "permitted_clock_jitter", ++ .data = &permitted_clock_jitter, ++ .maxlen = sizeof(permitted_clock_jitter), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax ++ }, ++ { 0 } ++}; ++static ctl_table xen_table[] = { ++ { ++ .ctl_name = 123, ++ .procname = "xen", ++ .mode = 0555, ++ .child = xen_subtable}, ++ { 0 } ++}; ++static int __init xen_sysctl_init(void) ++{ ++ (void)register_sysctl_table(xen_table, 0); ++ return 0; ++} ++__initcall(xen_sysctl_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/traps-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/traps-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1132 @@ ++/* ++ * linux/arch/i386/traps.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * Pentium III FXSR, SSE support ++ * Gareth Hughes <gareth@valinux.com>, May 2000 ++ */ ++ ++/* ++ * 'Traps.c' handles hardware traps and faults after we have saved some ++ * state in 'asm.s'. ++ */ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/highmem.h> ++#include <linux/kallsyms.h> ++#include <linux/ptrace.h> ++#include <linux/utsname.h> ++#include <linux/kprobes.h> ++#include <linux/kexec.h> ++#include <linux/unwind.h> ++#include <linux/uaccess.h> ++#include <linux/nmi.h> ++#include <linux/bug.h> ++ ++#ifdef CONFIG_EISA ++#include <linux/ioport.h> ++#include <linux/eisa.h> ++#endif ++ ++#ifdef CONFIG_MCA ++#include <linux/mca.h> ++#endif ++ ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/atomic.h> ++#include <asm/debugreg.h> ++#include <asm/desc.h> ++#include <asm/i387.h> ++#include <asm/nmi.h> ++#include <asm/unwind.h> ++#include <asm/smp.h> ++#include <asm/arch_hooks.h> ++#include <asm/kdebug.h> ++#include <asm/stacktrace.h> ++ ++#include <linux/module.h> ++ ++#include "mach_traps.h" ++ ++int panic_on_unrecovered_nmi; ++ ++asmlinkage int system_call(void); ++ ++/* Do we ignore FPU interrupts ? */ ++char ignore_fpu_irq = 0; ++ ++#ifndef CONFIG_X86_NO_IDT ++/* ++ * The IDT has to be page-aligned to simplify the Pentium ++ * F0 0F bug workaround.. We have a special link segment ++ * for this. ++ */ ++struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; ++#endif ++ ++asmlinkage void divide_error(void); ++asmlinkage void debug(void); ++asmlinkage void nmi(void); ++asmlinkage void int3(void); ++asmlinkage void overflow(void); ++asmlinkage void bounds(void); ++asmlinkage void invalid_op(void); ++asmlinkage void device_not_available(void); ++asmlinkage void coprocessor_segment_overrun(void); ++asmlinkage void invalid_TSS(void); ++asmlinkage void segment_not_present(void); ++asmlinkage void stack_segment(void); ++asmlinkage void general_protection(void); ++asmlinkage void page_fault(void); ++asmlinkage void coprocessor_error(void); ++asmlinkage void simd_coprocessor_error(void); ++asmlinkage void alignment_check(void); ++#ifndef CONFIG_XEN ++asmlinkage void spurious_interrupt_bug(void); ++#else ++asmlinkage void fixup_4gb_segment(void); ++#endif ++asmlinkage void machine_check(void); ++ ++int kstack_depth_to_print = 24; ++ATOMIC_NOTIFIER_HEAD(i386die_chain); ++ ++int register_die_notifier(struct notifier_block *nb) ++{ ++ vmalloc_sync_all(); ++ return atomic_notifier_chain_register(&i386die_chain, nb); ++} ++EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ ++ ++int unregister_die_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&i386die_chain, nb); ++} ++EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ ++ ++static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) ++{ ++ return p > (void *)tinfo && ++ p < (void *)tinfo + THREAD_SIZE - 3; ++} ++ ++static inline unsigned long print_context_stack(struct thread_info *tinfo, ++ unsigned long *stack, unsigned long ebp, ++ struct stacktrace_ops *ops, void *data) ++{ ++ unsigned long addr; ++ ++#ifdef CONFIG_FRAME_POINTER ++ while (valid_stack_ptr(tinfo, (void *)ebp)) { ++ unsigned long new_ebp; ++ addr = *(unsigned long *)(ebp + 4); ++ ops->address(data, addr); ++ /* ++ * break out of recursive entries (such as ++ * end_of_stack_stop_unwind_function). Also, ++ * we can never allow a frame pointer to ++ * move downwards! ++ */ ++ new_ebp = *(unsigned long *)ebp; ++ if (new_ebp <= ebp) ++ break; ++ ebp = new_ebp; ++ } ++#else ++ while (valid_stack_ptr(tinfo, stack)) { ++ addr = *stack++; ++ if (__kernel_text_address(addr)) ++ ops->address(data, addr); ++ } ++#endif ++ return ebp; ++} ++ ++#define MSG(msg) ops->warning(data, msg) ++ ++void dump_trace(struct task_struct *task, struct pt_regs *regs, ++ unsigned long *stack, ++ struct stacktrace_ops *ops, void *data) ++{ ++ unsigned long ebp = 0; ++ ++ if (!task) ++ task = current; ++ ++ if (!stack) { ++ unsigned long dummy; ++ stack = &dummy; ++ if (task && task != current) ++ stack = (unsigned long *)task->thread.esp; ++ } ++ ++#ifdef CONFIG_FRAME_POINTER ++ if (!ebp) { ++ if (task == current) { ++ /* Grab ebp right from our regs */ ++ asm ("movl %%ebp, %0" : "=r" (ebp) : ); ++ } else { ++ /* ebp is the last reg pushed by switch_to */ ++ ebp = *(unsigned long *) task->thread.esp; ++ } ++ } ++#endif ++ ++ while (1) { ++ struct thread_info *context; ++ context = (struct thread_info *) ++ ((unsigned long)stack & (~(THREAD_SIZE - 1))); ++ ebp = print_context_stack(context, stack, ebp, ops, data); ++ /* Should be after the line below, but somewhere ++ in early boot context comes out corrupted and we ++ can't reference it -AK */ ++ if (ops->stack(data, "IRQ") < 0) ++ break; ++ stack = (unsigned long*)context->previous_esp; ++ if (!stack) ++ break; ++ touch_nmi_watchdog(); ++ } ++} ++EXPORT_SYMBOL(dump_trace); ++ ++static void ++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) ++{ ++ printk(data); ++ print_symbol(msg, symbol); ++ printk("\n"); ++} ++ ++static void print_trace_warning(void *data, char *msg) ++{ ++ printk("%s%s\n", (char *)data, msg); ++} ++ ++static int print_trace_stack(void *data, char *name) ++{ ++ return 0; ++} ++ ++/* ++ * Print one address/symbol entries per line. ++ */ ++static void print_trace_address(void *data, unsigned long addr) ++{ ++ printk("%s [<%08lx>] ", (char *)data, addr); ++ print_symbol("%s\n", addr); ++} ++ ++static struct stacktrace_ops print_trace_ops = { ++ .warning = print_trace_warning, ++ .warning_symbol = print_trace_warning_symbol, ++ .stack = print_trace_stack, ++ .address = print_trace_address, ++}; ++ ++static void ++show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, ++ unsigned long * stack, char *log_lvl) ++{ ++ dump_trace(task, regs, stack, &print_trace_ops, log_lvl); ++ printk("%s =======================\n", log_lvl); ++} ++ ++void show_trace(struct task_struct *task, struct pt_regs *regs, ++ unsigned long * stack) ++{ ++ show_trace_log_lvl(task, regs, stack, ""); ++} ++ ++static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, ++ unsigned long *esp, char *log_lvl) ++{ ++ unsigned long *stack; ++ int i; ++ ++ if (esp == NULL) { ++ if (task) ++ esp = (unsigned long*)task->thread.esp; ++ else ++ esp = (unsigned long *)&esp; ++ } ++ ++ stack = esp; ++ for(i = 0; i < kstack_depth_to_print; i++) { ++ if (kstack_end(stack)) ++ break; ++ if (i && ((i % 8) == 0)) ++ printk("\n%s ", log_lvl); ++ printk("%08lx ", *stack++); ++ } ++ printk("\n%sCall Trace:\n", log_lvl); ++ show_trace_log_lvl(task, regs, esp, log_lvl); ++} ++ ++void show_stack(struct task_struct *task, unsigned long *esp) ++{ ++ printk(" "); ++ show_stack_log_lvl(task, NULL, esp, ""); ++} ++ ++/* ++ * The architecture-independent dump_stack generator ++ */ ++void dump_stack(void) ++{ ++ unsigned long stack; ++ ++ show_trace(current, NULL, &stack); ++} ++ ++EXPORT_SYMBOL(dump_stack); ++ ++void show_registers(struct pt_regs *regs) ++{ ++ int i; ++ int in_kernel = 1; ++ unsigned long esp; ++ unsigned short ss; ++ ++ esp = (unsigned long) (®s->esp); ++ savesegment(ss, ss); ++ if (user_mode_vm(regs)) { ++ in_kernel = 0; ++ esp = regs->esp; ++ ss = regs->xss & 0xffff; ++ } ++ print_modules(); ++ printk(KERN_EMERG "CPU: %d\n" ++ KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" ++ KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", ++ smp_processor_id(), 0xffff & regs->xcs, regs->eip, ++ print_tainted(), regs->eflags, init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); ++ print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); ++ printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", ++ regs->eax, regs->ebx, regs->ecx, regs->edx); ++ printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", ++ regs->esi, regs->edi, regs->ebp, esp); ++ printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", ++ regs->xds & 0xffff, regs->xes & 0xffff, ss); ++ printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", ++ TASK_COMM_LEN, current->comm, current->pid, ++ current_thread_info(), current, current->thread_info); ++ /* ++ * When in-kernel, we also print out the stack and code at the ++ * time of the fault.. ++ */ ++ if (in_kernel) { ++ u8 *eip; ++ int code_bytes = 64; ++ unsigned char c; ++ ++ printk("\n" KERN_EMERG "Stack: "); ++ show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); ++ ++ printk(KERN_EMERG "Code: "); ++ ++ eip = (u8 *)regs->eip - 43; ++ if (eip < (u8 *)PAGE_OFFSET || ++ probe_kernel_address(eip, c)) { ++ /* try starting at EIP */ ++ eip = (u8 *)regs->eip; ++ code_bytes = 32; ++ } ++ for (i = 0; i < code_bytes; i++, eip++) { ++ if (eip < (u8 *)PAGE_OFFSET || ++ probe_kernel_address(eip, c)) { ++ printk(" Bad EIP value."); ++ break; ++ } ++ if (eip == (u8 *)regs->eip) ++ printk("<%02x> ", c); ++ else ++ printk("%02x ", c); ++ } ++ } ++ printk("\n"); ++} ++ ++int is_valid_bugaddr(unsigned long eip) ++{ ++ unsigned short ud2; ++ ++ if (eip < PAGE_OFFSET) ++ return 0; ++ if (probe_kernel_address((unsigned short *)eip, ud2)) ++ return 0; ++ ++ return ud2 == 0x0b0f; ++} ++ ++/* ++ * This is gone through when something in the kernel has done something bad and ++ * is about to be terminated. ++ */ ++void die(const char * str, struct pt_regs * regs, long err) ++{ ++ static struct { ++ spinlock_t lock; ++ u32 lock_owner; ++ int lock_owner_depth; ++ } die = { ++ .lock = __SPIN_LOCK_UNLOCKED(die.lock), ++ .lock_owner = -1, ++ .lock_owner_depth = 0 ++ }; ++ static int die_counter; ++ unsigned long flags; ++ ++ oops_enter(); ++ ++ if (die.lock_owner != raw_smp_processor_id()) { ++ console_verbose(); ++ spin_lock_irqsave(&die.lock, flags); ++ die.lock_owner = smp_processor_id(); ++ die.lock_owner_depth = 0; ++ bust_spinlocks(1); ++ } ++ else ++ local_save_flags(flags); ++ ++ if (++die.lock_owner_depth < 3) { ++ int nl = 0; ++ unsigned long esp; ++ unsigned short ss; ++ ++ report_bug(regs->eip); ++ ++ printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); ++#ifdef CONFIG_PREEMPT ++ printk(KERN_EMERG "PREEMPT "); ++ nl = 1; ++#endif ++#ifdef CONFIG_SMP ++ if (!nl) ++ printk(KERN_EMERG); ++ printk("SMP "); ++ nl = 1; ++#endif ++#ifdef CONFIG_DEBUG_PAGEALLOC ++ if (!nl) ++ printk(KERN_EMERG); ++ printk("DEBUG_PAGEALLOC"); ++ nl = 1; ++#endif ++ if (nl) ++ printk("\n"); ++ if (notify_die(DIE_OOPS, str, regs, err, ++ current->thread.trap_no, SIGSEGV) != ++ NOTIFY_STOP) { ++ show_registers(regs); ++ /* Executive summary in case the oops scrolled away */ ++ esp = (unsigned long) (®s->esp); ++ savesegment(ss, ss); ++ if (user_mode(regs)) { ++ esp = regs->esp; ++ ss = regs->xss & 0xffff; ++ } ++ printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); ++ print_symbol("%s", regs->eip); ++ printk(" SS:ESP %04x:%08lx\n", ss, esp); ++ } ++ else ++ regs = NULL; ++ } else ++ printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); ++ ++ bust_spinlocks(0); ++ die.lock_owner = -1; ++ spin_unlock_irqrestore(&die.lock, flags); ++ ++ if (!regs) ++ return; ++ ++ if (kexec_should_crash(current)) ++ crash_kexec(regs); ++ ++ if (in_interrupt()) ++ panic("Fatal exception in interrupt"); ++ ++ if (panic_on_oops) ++ panic("Fatal exception"); ++ ++ oops_exit(); ++ do_exit(SIGSEGV); ++} ++ ++static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) ++{ ++ if (!user_mode_vm(regs)) ++ die(str, regs, err); ++} ++ ++static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, ++ struct pt_regs * regs, long error_code, ++ siginfo_t *info) ++{ ++ struct task_struct *tsk = current; ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; ++ ++ if (regs->eflags & VM_MASK) { ++ if (vm86) ++ goto vm86_trap; ++ goto trap_signal; ++ } ++ ++ if (!user_mode(regs)) ++ goto kernel_trap; ++ ++ trap_signal: { ++ if (info) ++ force_sig_info(signr, info, tsk); ++ else ++ force_sig(signr, tsk); ++ return; ++ } ++ ++ kernel_trap: { ++ if (!fixup_exception(regs)) ++ die(str, regs, error_code); ++ return; ++ } ++ ++ vm86_trap: { ++ int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); ++ if (ret) goto trap_signal; ++ return; ++ } ++} ++ ++#define DO_ERROR(trapnr, signr, str, name) \ ++fastcall void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ ++} ++ ++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ ++fastcall void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ siginfo_t info; \ ++ info.si_signo = signr; \ ++ info.si_errno = 0; \ ++ info.si_code = sicode; \ ++ info.si_addr = (void __user *)siaddr; \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ ++} ++ ++#define DO_VM86_ERROR(trapnr, signr, str, name) \ ++fastcall void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ ++} ++ ++#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ ++fastcall void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ siginfo_t info; \ ++ info.si_signo = signr; \ ++ info.si_errno = 0; \ ++ info.si_code = sicode; \ ++ info.si_addr = (void __user *)siaddr; \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ ++} ++ ++DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) ++#ifndef CONFIG_KPROBES ++DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) ++#endif ++DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) ++DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) ++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip) ++DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) ++DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) ++DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) ++DO_ERROR(12, SIGBUS, "stack segment", stack_segment) ++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) ++DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) ++ ++fastcall void __kprobes do_general_protection(struct pt_regs * regs, ++ long error_code) ++{ ++ current->thread.error_code = error_code; ++ current->thread.trap_no = 13; ++ ++ if (regs->eflags & VM_MASK) ++ goto gp_in_vm86; ++ ++ if (!user_mode(regs)) ++ goto gp_in_kernel; ++ ++ current->thread.error_code = error_code; ++ current->thread.trap_no = 13; ++ force_sig(SIGSEGV, current); ++ return; ++ ++gp_in_vm86: ++ local_irq_enable(); ++ handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); ++ return; ++ ++gp_in_kernel: ++ if (!fixup_exception(regs)) { ++ if (notify_die(DIE_GPF, "general protection fault", regs, ++ error_code, 13, SIGSEGV) == NOTIFY_STOP) ++ return; ++ die("general protection fault", regs, error_code); ++ } ++} ++ ++static __kprobes void ++mem_parity_error(unsigned char reason, struct pt_regs * regs) ++{ ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " ++ "CPU %d.\n", reason, smp_processor_id()); ++ printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); ++ ++ /* Clear and disable the memory parity error line. */ ++ clear_mem_error(reason); ++} ++ ++static __kprobes void ++io_check_error(unsigned char reason, struct pt_regs * regs) ++{ ++ printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); ++ show_registers(regs); ++ ++ /* Re-enable the IOCK line, wait for a few seconds */ ++ clear_io_check_error(reason); ++} ++ ++static __kprobes void ++unknown_nmi_error(unsigned char reason, struct pt_regs * regs) ++{ ++#ifdef CONFIG_MCA ++ /* Might actually be able to figure out what the guilty party ++ * is. */ ++ if( MCA_bus ) { ++ mca_handle_nmi(); ++ return; ++ } ++#endif ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " ++ "CPU %d.\n", reason, smp_processor_id()); ++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); ++} ++ ++static DEFINE_SPINLOCK(nmi_print_lock); ++ ++void __kprobes die_nmi(struct pt_regs *regs, const char *msg) ++{ ++ if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == ++ NOTIFY_STOP) ++ return; ++ ++ spin_lock(&nmi_print_lock); ++ /* ++ * We are in trouble anyway, lets at least try ++ * to get a message out. ++ */ ++ bust_spinlocks(1); ++ printk(KERN_EMERG "%s", msg); ++ printk(" on CPU%d, eip %08lx, registers:\n", ++ smp_processor_id(), regs->eip); ++ show_registers(regs); ++ console_silent(); ++ spin_unlock(&nmi_print_lock); ++ bust_spinlocks(0); ++ ++ /* If we are in kernel we are probably nested up pretty bad ++ * and might aswell get out now while we still can. ++ */ ++ if (!user_mode_vm(regs)) { ++ current->thread.trap_no = 2; ++ crash_kexec(regs); ++ } ++ ++ do_exit(SIGSEGV); ++} ++ ++static __kprobes void default_do_nmi(struct pt_regs * regs) ++{ ++ unsigned char reason = 0; ++ ++ /* Only the BSP gets external NMIs from the system. */ ++ if (!smp_processor_id()) ++ reason = get_nmi_reason(); ++ ++ if (!(reason & 0xc0)) { ++ if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) ++ == NOTIFY_STOP) ++ return; ++#ifdef CONFIG_X86_LOCAL_APIC ++ /* ++ * Ok, so this is none of the documented NMI sources, ++ * so it must be the NMI watchdog. ++ */ ++ if (nmi_watchdog_tick(regs, reason)) ++ return; ++ if (!do_nmi_callback(regs, smp_processor_id())) ++#endif ++ unknown_nmi_error(reason, regs); ++ ++ return; ++ } ++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) ++ return; ++ if (reason & 0x80) ++ mem_parity_error(reason, regs); ++ if (reason & 0x40) ++ io_check_error(reason, regs); ++ /* ++ * Reassert NMI in case it became active meanwhile ++ * as it's edge-triggered. ++ */ ++ reassert_nmi(); ++} ++ ++fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) ++{ ++ int cpu; ++ ++ nmi_enter(); ++ ++ cpu = smp_processor_id(); ++ ++ ++nmi_count(cpu); ++ ++ default_do_nmi(regs); ++ ++ nmi_exit(); ++} ++ ++#ifdef CONFIG_KPROBES ++fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) ++{ ++ if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) ++ == NOTIFY_STOP) ++ return; ++ /* This is an interrupt gate, because kprobes wants interrupts ++ disabled. Normal trap handlers don't. */ ++ restore_interrupts(regs); ++ do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); ++} ++#endif ++ ++/* ++ * Our handling of the processor debug registers is non-trivial. ++ * We do not clear them on entry and exit from the kernel. Therefore ++ * it is possible to get a watchpoint trap here from inside the kernel. ++ * However, the code in ./ptrace.c has ensured that the user can ++ * only set watchpoints on userspace addresses. Therefore the in-kernel ++ * watchpoint trap can only occur in code which is reading/writing ++ * from user space. Such code must not hold kernel locks (since it ++ * can equally take a page fault), therefore it is safe to call ++ * force_sig_info even though that claims and releases locks. ++ * ++ * Code in ./signal.c ensures that the debug control register ++ * is restored before we deliver any signal, and therefore that ++ * user code runs with the correct debug control register even though ++ * we clear it here. ++ * ++ * Being careful here means that we don't have to be as careful in a ++ * lot of more complicated places (task switching can be a bit lazy ++ * about restoring all the debug state, and ptrace doesn't have to ++ * find every occurrence of the TF bit that could be saved away even ++ * by user code) ++ */ ++fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code) ++{ ++ unsigned int condition; ++ struct task_struct *tsk = current; ++ ++ get_debugreg(condition, 6); ++ ++ if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, ++ SIGTRAP) == NOTIFY_STOP) ++ return; ++ /* It's safe to allow irq's after DR6 has been saved */ ++ if (regs->eflags & X86_EFLAGS_IF) ++ local_irq_enable(); ++ ++ /* Mask out spurious debug traps due to lazy DR7 setting */ ++ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { ++ if (!tsk->thread.debugreg[7]) ++ goto clear_dr7; ++ } ++ ++ if (regs->eflags & VM_MASK) ++ goto debug_vm86; ++ ++ /* Save debug status register where ptrace can see it */ ++ tsk->thread.debugreg[6] = condition; ++ ++ /* ++ * Single-stepping through TF: make sure we ignore any events in ++ * kernel space (but re-enable TF when returning to user mode). ++ */ ++ if (condition & DR_STEP) { ++ /* ++ * We already checked v86 mode above, so we can ++ * check for kernel mode by just checking the CPL ++ * of CS. ++ */ ++ if (!user_mode(regs)) ++ goto clear_TF_reenable; ++ } ++ ++ /* Ok, finally something we can handle */ ++ send_sigtrap(tsk, regs, error_code); ++ ++ /* Disable additional traps. They'll be re-enabled when ++ * the signal is delivered. ++ */ ++clear_dr7: ++ set_debugreg(0, 7); ++ return; ++ ++debug_vm86: ++ handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); ++ return; ++ ++clear_TF_reenable: ++ set_tsk_thread_flag(tsk, TIF_SINGLESTEP); ++ regs->eflags &= ~TF_MASK; ++ return; ++} ++ ++/* ++ * Note that we play around with the 'TS' bit in an attempt to get ++ * the correct behaviour even in the presence of the asynchronous ++ * IRQ13 behaviour ++ */ ++void math_error(void __user *eip) ++{ ++ struct task_struct * task; ++ siginfo_t info; ++ unsigned short cwd, swd; ++ ++ /* ++ * Save the info for the exception handler and clear the error. ++ */ ++ task = current; ++ save_init_fpu(task); ++ task->thread.trap_no = 16; ++ task->thread.error_code = 0; ++ info.si_signo = SIGFPE; ++ info.si_errno = 0; ++ info.si_code = __SI_FAULT; ++ info.si_addr = eip; ++ /* ++ * (~cwd & swd) will mask out exceptions that are not set to unmasked ++ * status. 0x3f is the exception bits in these regs, 0x200 is the ++ * C1 reg you need in case of a stack fault, 0x040 is the stack ++ * fault bit. We should only be taking one exception at a time, ++ * so if this combination doesn't produce any single exception, ++ * then we have a bad program that isn't syncronizing its FPU usage ++ * and it will suffer the consequences since we won't be able to ++ * fully reproduce the context of the exception ++ */ ++ cwd = get_fpu_cwd(task); ++ swd = get_fpu_swd(task); ++ switch (swd & ~cwd & 0x3f) { ++ case 0x000: /* No unmasked exception */ ++ return; ++ default: /* Multiple exceptions */ ++ break; ++ case 0x001: /* Invalid Op */ ++ /* ++ * swd & 0x240 == 0x040: Stack Underflow ++ * swd & 0x240 == 0x240: Stack Overflow ++ * User must clear the SF bit (0x40) if set ++ */ ++ info.si_code = FPE_FLTINV; ++ break; ++ case 0x002: /* Denormalize */ ++ case 0x010: /* Underflow */ ++ info.si_code = FPE_FLTUND; ++ break; ++ case 0x004: /* Zero Divide */ ++ info.si_code = FPE_FLTDIV; ++ break; ++ case 0x008: /* Overflow */ ++ info.si_code = FPE_FLTOVF; ++ break; ++ case 0x020: /* Precision */ ++ info.si_code = FPE_FLTRES; ++ break; ++ } ++ force_sig_info(SIGFPE, &info, task); ++} ++ ++fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code) ++{ ++ ignore_fpu_irq = 1; ++ math_error((void __user *)regs->eip); ++} ++ ++static void simd_math_error(void __user *eip) ++{ ++ struct task_struct * task; ++ siginfo_t info; ++ unsigned short mxcsr; ++ ++ /* ++ * Save the info for the exception handler and clear the error. ++ */ ++ task = current; ++ save_init_fpu(task); ++ task->thread.trap_no = 19; ++ task->thread.error_code = 0; ++ info.si_signo = SIGFPE; ++ info.si_errno = 0; ++ info.si_code = __SI_FAULT; ++ info.si_addr = eip; ++ /* ++ * The SIMD FPU exceptions are handled a little differently, as there ++ * is only a single status/control register. Thus, to determine which ++ * unmasked exception was caught we must mask the exception mask bits ++ * at 0x1f80, and then use these to mask the exception bits at 0x3f. ++ */ ++ mxcsr = get_fpu_mxcsr(task); ++ switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { ++ case 0x000: ++ default: ++ break; ++ case 0x001: /* Invalid Op */ ++ info.si_code = FPE_FLTINV; ++ break; ++ case 0x002: /* Denormalize */ ++ case 0x010: /* Underflow */ ++ info.si_code = FPE_FLTUND; ++ break; ++ case 0x004: /* Zero Divide */ ++ info.si_code = FPE_FLTDIV; ++ break; ++ case 0x008: /* Overflow */ ++ info.si_code = FPE_FLTOVF; ++ break; ++ case 0x020: /* Precision */ ++ info.si_code = FPE_FLTRES; ++ break; ++ } ++ force_sig_info(SIGFPE, &info, task); ++} ++ ++fastcall void do_simd_coprocessor_error(struct pt_regs * regs, ++ long error_code) ++{ ++ if (cpu_has_xmm) { ++ /* Handle SIMD FPU exceptions on PIII+ processors. */ ++ ignore_fpu_irq = 1; ++ simd_math_error((void __user *)regs->eip); ++ } else { ++ /* ++ * Handle strange cache flush from user space exception ++ * in all other cases. This is undocumented behaviour. ++ */ ++ if (regs->eflags & VM_MASK) { ++ handle_vm86_fault((struct kernel_vm86_regs *)regs, ++ error_code); ++ return; ++ } ++ current->thread.trap_no = 19; ++ current->thread.error_code = error_code; ++ die_if_kernel("cache flush denied", regs, error_code); ++ force_sig(SIGSEGV, current); ++ } ++} ++ ++#ifndef CONFIG_XEN ++fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, ++ long error_code) ++{ ++#if 0 ++ /* No need to warn about this any longer. */ ++ printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); ++#endif ++} ++ ++fastcall unsigned long patch_espfix_desc(unsigned long uesp, ++ unsigned long kesp) ++{ ++ int cpu = smp_processor_id(); ++ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address; ++ unsigned long base = (kesp - uesp) & -THREAD_SIZE; ++ unsigned long new_kesp = kesp - base; ++ unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; ++ __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; ++ /* Set up base for espfix segment */ ++ desc &= 0x00f0ff0000000000ULL; ++ desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | ++ ((((__u64)base) << 32) & 0xff00000000000000ULL) | ++ ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | ++ (lim_pages & 0xffff); ++ *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; ++ return new_kesp; ++} ++#endif ++ ++/* ++ * 'math_state_restore()' saves the current math information in the ++ * old math state array, and gets the new ones from the current task ++ * ++ * Careful.. There are problems with IBM-designed IRQ13 behaviour. ++ * Don't touch unless you *really* know how it works. ++ * ++ * Must be called with kernel preemption disabled (in this case, ++ * local interrupts are disabled at the call-site in entry.S). ++ */ ++asmlinkage void math_state_restore(void) ++{ ++ struct thread_info *thread = current_thread_info(); ++ struct task_struct *tsk = thread->task; ++ ++ /* NB. 'clts' is done for us by Xen during virtual trap. */ ++ if (!tsk_used_math(tsk)) ++ init_fpu(tsk); ++ restore_fpu(tsk); ++ thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ ++ tsk->fpu_counter++; ++} ++ ++#ifndef CONFIG_MATH_EMULATION ++ ++asmlinkage void math_emulate(long arg) ++{ ++ printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n"); ++ printk(KERN_EMERG "killing %s.\n",current->comm); ++ force_sig(SIGFPE,current); ++ schedule(); ++} ++ ++#endif /* CONFIG_MATH_EMULATION */ ++ ++#ifdef CONFIG_X86_F00F_BUG ++void __init trap_init_f00f_bug(void) ++{ ++ __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); ++ ++ /* ++ * Update the IDT descriptor and reload the IDT so that ++ * it uses the read-only mapped virtual address. ++ */ ++ idt_descr.address = fix_to_virt(FIX_F00F_IDT); ++ load_idt(&idt_descr); ++} ++#endif ++ ++ ++/* ++ * NB. All these are "trap gates" (i.e. events_mask isn't set) except ++ * for those that specify <dpl>|4 in the second field. ++ */ ++static trap_info_t trap_table[] = { ++ { 0, 0, __KERNEL_CS, (unsigned long)divide_error }, ++ { 1, 0|4, __KERNEL_CS, (unsigned long)debug }, ++ { 3, 3|4, __KERNEL_CS, (unsigned long)int3 }, ++ { 4, 3, __KERNEL_CS, (unsigned long)overflow }, ++ { 5, 0, __KERNEL_CS, (unsigned long)bounds }, ++ { 6, 0, __KERNEL_CS, (unsigned long)invalid_op }, ++ { 7, 0|4, __KERNEL_CS, (unsigned long)device_not_available }, ++ { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun }, ++ { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS }, ++ { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present }, ++ { 12, 0, __KERNEL_CS, (unsigned long)stack_segment }, ++ { 13, 0, __KERNEL_CS, (unsigned long)general_protection }, ++ { 14, 0|4, __KERNEL_CS, (unsigned long)page_fault }, ++ { 15, 0, __KERNEL_CS, (unsigned long)fixup_4gb_segment }, ++ { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error }, ++ { 17, 0, __KERNEL_CS, (unsigned long)alignment_check }, ++#ifdef CONFIG_X86_MCE ++ { 18, 0, __KERNEL_CS, (unsigned long)machine_check }, ++#endif ++ { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error }, ++ { SYSCALL_VECTOR, 3, __KERNEL_CS, (unsigned long)system_call }, ++ { 0, 0, 0, 0 } ++}; ++ ++void __init trap_init(void) ++{ ++ HYPERVISOR_set_trap_table(trap_table); ++ ++ if (cpu_has_fxsr) { ++ /* ++ * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. ++ * Generates a compile-time "error: zero width for bit-field" if ++ * the alignment is wrong. ++ */ ++ struct fxsrAlignAssert { ++ int _:!(offsetof(struct task_struct, ++ thread.i387.fxsave) & 15); ++ }; ++ ++ printk(KERN_INFO "Enabling fast FPU save and restore... "); ++ set_in_cr4(X86_CR4_OSFXSR); ++ printk("done.\n"); ++ } ++ if (cpu_has_xmm) { ++ printk(KERN_INFO "Enabling unmasked SIMD FPU exception " ++ "support... "); ++ set_in_cr4(X86_CR4_OSXMMEXCPT); ++ printk("done.\n"); ++ } ++ ++ /* ++ * Should be a barrier for any external CPU state. ++ */ ++ cpu_init(); ++} ++ ++void smp_trap_init(trap_info_t *trap_ctxt) ++{ ++ trap_info_t *t = trap_table; ++ ++ for (t = trap_table; t->address; t++) { ++ trap_ctxt[t->vector].flags = t->flags; ++ trap_ctxt[t->vector].cs = t->cs; ++ trap_ctxt[t->vector].address = t->address; ++ } ++} ++ ++static int __init kstack_setup(char *s) ++{ ++ kstack_depth_to_print = simple_strtoul(s, NULL, 0); ++ return 1; ++} ++__setup("kstack=", kstack_setup); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/traps.c +--- a/arch/i386/kernel/traps.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/traps.c Wed Aug 08 16:25:28 2007 -0300 +@@ -402,7 +402,6 @@ void die(const char * str, struct pt_reg + unsigned short ss; + + report_bug(regs->eip); +- + printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + #ifdef CONFIG_PREEMPT + printk(KERN_EMERG "PREEMPT "); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/vm86.c +--- a/arch/i386/kernel/vm86.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/vm86.c Wed Aug 08 16:25:28 2007 -0300 +@@ -125,7 +125,9 @@ struct pt_regs * FASTCALL(save_v86_state + struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs)); + struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs) + { ++#ifndef CONFIG_X86_NO_TSS + struct tss_struct *tss; ++#endif + struct pt_regs *ret; + unsigned long tmp; + +@@ -148,12 +150,16 @@ struct pt_regs * fastcall save_v86_state + do_exit(SIGSEGV); + } + ++#ifndef CONFIG_X86_NO_TSS + tss = &per_cpu(init_tss, get_cpu()); ++#endif + current->thread.esp0 = current->thread.saved_esp0; + current->thread.sysenter_cs = __KERNEL_CS; + load_esp0(tss, ¤t->thread); + current->thread.saved_esp0 = 0; ++#ifndef CONFIG_X86_NO_TSS + put_cpu(); ++#endif + + ret = KVM86->regs32; + +@@ -279,7 +285,9 @@ out: + + static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk) + { ++#ifndef CONFIG_X86_NO_TSS + struct tss_struct *tss; ++#endif + /* + * make sure the vm86() system call doesn't try to do anything silly + */ +@@ -324,12 +332,16 @@ static void do_sys_vm86(struct kernel_vm + savesegment(fs, tsk->thread.saved_fs); + tsk->thread.saved_gs = info->regs32->xgs; + ++#ifndef CONFIG_X86_NO_TSS + tss = &per_cpu(init_tss, get_cpu()); ++#endif + tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; + if (cpu_has_sep) + tsk->thread.sysenter_cs = 0; + load_esp0(tss, &tsk->thread); ++#ifndef CONFIG_X86_NO_TSS + put_cpu(); ++#endif + + tsk->thread.screen_bitmap = info->screen_bitmap; + if (info->flags & VM86_SCREEN_BITMAP) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/vmlinux.lds.S +--- a/arch/i386/kernel/vmlinux.lds.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/kernel/vmlinux.lds.S Wed Aug 08 16:25:28 2007 -0300 +@@ -35,7 +35,13 @@ PHDRS { + } + SECTIONS + { ++/* xen i386 redefineds LOAD_OFFSET to zero on page.h ++ quintela@redhat.com */ ++#ifdef CONFIG_XEN ++ . = __PAGE_OFFSET + LOAD_PHYSICAL_ADDR; ++#else + . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; ++#endif + phys_startup_32 = startup_32 - LOAD_OFFSET; + /* read-only */ + .text : AT(ADDR(.text) - LOAD_OFFSET) { +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/kernel/vsyscall-note-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/kernel/vsyscall-note-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,32 @@ ++/* ++ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. ++ * Here we can supply some information useful to userland. ++ * First we get the vanilla i386 note that supplies the kernel version info. ++ */ ++ ++#include "vsyscall-note.S" ++ ++/* ++ * Now we add a special note telling glibc's dynamic linker a fake hardware ++ * flavor that it will use to choose the search path for libraries in the ++ * same way it uses real hardware capabilities like "mmx". ++ * We supply "nosegneg" as the fake capability, to indicate that we ++ * do not like negative offsets in instructions using segment overrides, ++ * since we implement those inefficiently. This makes it possible to ++ * install libraries optimized to avoid those access patterns in someplace ++ * like /lib/i686/tls/nosegneg. Note that an /etc/ld.so.conf.d/file ++ * corresponding to the bits here is needed to make ldconfig work right. ++ * It should contain: ++ * hwcap 0 nosegneg ++ * to match the mapping of bit to name that we give here. ++ */ ++#define NOTE_KERNELCAP_BEGIN(ncaps, mask) \ ++ ASM_ELF_NOTE_BEGIN(".note.kernelcap", "a", "GNU", 2) \ ++ .long ncaps, mask ++#define NOTE_KERNELCAP(bit, name) \ ++ .byte bit; .asciz name ++#define NOTE_KERNELCAP_END ASM_ELF_NOTE_END ++ ++NOTE_KERNELCAP_BEGIN(1, 1) ++NOTE_KERNELCAP(0, "nosegneg") ++NOTE_KERNELCAP_END +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mach-xen/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mach-xen/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++obj-y := setup.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mach-xen/setup.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mach-xen/setup.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,168 @@ ++/* ++ * Machine specific setup for generic ++ */ ++ ++#include <linux/smp.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <asm/acpi.h> ++#include <asm/arch_hooks.h> ++#include <asm/e820.h> ++#include <asm/setup.h> ++#include <asm/fixmap.h> ++ ++#include <xen/interface/callback.h> ++#include <xen/interface/memory.h> ++ ++#ifdef CONFIG_HOTPLUG_CPU ++#define DEFAULT_SEND_IPI (1) ++#else ++#define DEFAULT_SEND_IPI (0) ++#endif ++ ++int no_broadcast=DEFAULT_SEND_IPI; ++ ++static __init int no_ipi_broadcast(char *str) ++{ ++ get_option(&str, &no_broadcast); ++ printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" : ++ "IPI Broadcast"); ++ return 1; ++} ++ ++__setup("no_ipi_broadcast", no_ipi_broadcast); ++ ++static int __init print_ipi_mode(void) ++{ ++ printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" : ++ "Shortcut"); ++ return 0; ++} ++ ++late_initcall(print_ipi_mode); ++ ++/** ++ * machine_specific_memory_setup - Hook for machine specific memory setup. ++ * ++ * Description: ++ * This is included late in kernel/setup.c so that it can make ++ * use of all of the static functions. ++ **/ ++ ++char * __init machine_specific_memory_setup(void) ++{ ++ int rc; ++ struct xen_memory_map memmap; ++ /* ++ * This is rather large for a stack variable but this early in ++ * the boot process we know we have plenty slack space. ++ */ ++ struct e820entry map[E820MAX]; ++ ++ memmap.nr_entries = E820MAX; ++ set_xen_guest_handle(memmap.buffer, map); ++ ++ rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); ++ if ( rc == -ENOSYS ) { ++ memmap.nr_entries = 1; ++ map[0].addr = 0ULL; ++ map[0].size = PFN_PHYS((unsigned long long)xen_start_info->nr_pages); ++ /* 8MB slack (to balance backend allocations). */ ++ map[0].size += 8ULL << 20; ++ map[0].type = E820_RAM; ++ rc = 0; ++ } ++ BUG_ON(rc); ++ ++ sanitize_e820_map(map, (char *)&memmap.nr_entries); ++ ++ BUG_ON(copy_e820_map(map, (char)memmap.nr_entries) < 0); ++ ++ return "Xen"; ++} ++ ++ ++extern void hypervisor_callback(void); ++extern void failsafe_callback(void); ++extern void nmi(void); ++ ++unsigned long *machine_to_phys_mapping; ++EXPORT_SYMBOL(machine_to_phys_mapping); ++unsigned int machine_to_phys_order; ++EXPORT_SYMBOL(machine_to_phys_order); ++ ++void __init machine_specific_arch_setup(void) ++{ ++ int ret; ++ struct xen_machphys_mapping mapping; ++ unsigned long machine_to_phys_nr_ents; ++ struct xen_platform_parameters pp; ++ static struct callback_register __initdata event = { ++ .type = CALLBACKTYPE_event, ++ .address = { __KERNEL_CS, (unsigned long)hypervisor_callback }, ++ }; ++ static struct callback_register __initdata failsafe = { ++ .type = CALLBACKTYPE_failsafe, ++ .address = { __KERNEL_CS, (unsigned long)failsafe_callback }, ++ }; ++ static struct callback_register __initdata nmi_cb = { ++ .type = CALLBACKTYPE_nmi, ++ .address = { __KERNEL_CS, (unsigned long)nmi }, ++ }; ++ ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event); ++ if (ret == 0) ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret == -ENOSYS) ++ ret = HYPERVISOR_set_callbacks( ++ event.address.cs, event.address.eip, ++ failsafe.address.cs, failsafe.address.eip); ++#endif ++ BUG_ON(ret); ++ ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret == -ENOSYS) { ++ static struct xennmi_callback __initdata cb = { ++ .handler_address = (unsigned long)nmi ++ }; ++ ++ HYPERVISOR_nmi_op(XENNMI_register_callback, &cb); ++ } ++#endif ++ ++ if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0) { ++ hypervisor_virt_start = pp.virt_start; ++ set_fixaddr_top(); ++ } ++ ++ machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START; ++ machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; ++ if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { ++ machine_to_phys_mapping = (unsigned long *)mapping.v_start; ++ machine_to_phys_nr_ents = mapping.max_mfn + 1; ++ } ++ while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents ) ++ machine_to_phys_order++; ++} ++ ++/** ++ * pre_setup_arch_hook - hook called prior to any setup_arch() execution ++ * ++ * Description: ++ * generally used to activate any machine specific identification ++ * routines that may be needed before setup_arch() runs. On VISWS ++ * this is used to get the board revision and type. ++ **/ ++void __init pre_setup_arch_hook(void) ++{ ++ int max_cmdline; ++ ++ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) ++ max_cmdline = COMMAND_LINE_SIZE; ++ memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline); ++ /* Save unparsed command line copy for /proc/cmdline */ ++ saved_command_line[max_cmdline-1] = '\0'; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/Makefile +--- a/arch/i386/mm/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/mm/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -8,3 +8,11 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag + obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o + obj-$(CONFIG_HIGHMEM) += highmem.o + obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o ++ ++ifdef CONFIG_XEN ++include $(srctree)/scripts/Makefile.xen ++ ++obj-y += hypervisor.o ++ ++obj-y := $(call cherrypickxen, $(obj-y)) ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/fault-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/fault-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,760 @@ ++/* ++ * linux/arch/i386/mm/fault.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ */ ++ ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/ptrace.h> ++#include <linux/mman.h> ++#include <linux/mm.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/interrupt.h> ++#include <linux/init.h> ++#include <linux/tty.h> ++#include <linux/vt_kern.h> /* For unblank_screen() */ ++#include <linux/highmem.h> ++#include <linux/module.h> ++#include <linux/kprobes.h> ++#include <linux/uaccess.h> ++ ++#include <asm/system.h> ++#include <asm/desc.h> ++#include <asm/kdebug.h> ++#include <asm/segment.h> ++ ++extern void die(const char *,struct pt_regs *,long); ++ ++static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); ++ ++int register_page_fault_notifier(struct notifier_block *nb) ++{ ++ vmalloc_sync_all(); ++ return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); ++} ++EXPORT_SYMBOL_GPL(register_page_fault_notifier); ++ ++int unregister_page_fault_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); ++} ++EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); ++ ++static inline int notify_page_fault(enum die_val val, const char *str, ++ struct pt_regs *regs, long err, int trap, int sig) ++{ ++ struct die_args args = { ++ .regs = regs, ++ .str = str, ++ .err = err, ++ .trapnr = trap, ++ .signr = sig ++ }; ++ return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); ++} ++ ++/* ++ * Unlock any spinlocks which will prevent us from getting the ++ * message out ++ */ ++void bust_spinlocks(int yes) ++{ ++ int loglevel_save = console_loglevel; ++ ++ if (yes) { ++ oops_in_progress = 1; ++ return; ++ } ++#ifdef CONFIG_VT ++ unblank_screen(); ++#endif ++ oops_in_progress = 0; ++ /* ++ * OK, the message is on the console. Now we call printk() ++ * without oops_in_progress set so that printk will give klogd ++ * a poke. Hold onto your hats... ++ */ ++ console_loglevel = 15; /* NMI oopser may have shut the console up */ ++ printk(" "); ++ console_loglevel = loglevel_save; ++} ++ ++/* ++ * Return EIP plus the CS segment base. The segment limit is also ++ * adjusted, clamped to the kernel/user address space (whichever is ++ * appropriate), and returned in *eip_limit. ++ * ++ * The segment is checked, because it might have been changed by another ++ * task between the original faulting instruction and here. ++ * ++ * If CS is no longer a valid code segment, or if EIP is beyond the ++ * limit, or if it is a kernel address when CS is not a kernel segment, ++ * then the returned value will be greater than *eip_limit. ++ * ++ * This is slow, but is very rarely executed. ++ */ ++static inline unsigned long get_segment_eip(struct pt_regs *regs, ++ unsigned long *eip_limit) ++{ ++ unsigned long eip = regs->eip; ++ unsigned seg = regs->xcs & 0xffff; ++ u32 seg_ar, seg_limit, base, *desc; ++ ++ /* Unlikely, but must come before segment checks. */ ++ if (unlikely(regs->eflags & VM_MASK)) { ++ base = seg << 4; ++ *eip_limit = base + 0xffff; ++ return base + (eip & 0xffff); ++ } ++ ++ /* The standard kernel/user address space limit. */ ++ *eip_limit = user_mode(regs) ? USER_DS.seg : KERNEL_DS.seg; ++ ++ /* By far the most common cases. */ ++ if (likely(SEGMENT_IS_FLAT_CODE(seg))) ++ return eip; ++ ++ /* Check the segment exists, is within the current LDT/GDT size, ++ that kernel/user (ring 0..3) has the appropriate privilege, ++ that it's a code segment, and get the limit. */ ++ __asm__ ("larl %3,%0; lsll %3,%1" ++ : "=&r" (seg_ar), "=r" (seg_limit) : "0" (0), "rm" (seg)); ++ if ((~seg_ar & 0x9800) || eip > seg_limit) { ++ *eip_limit = 0; ++ return 1; /* So that returned eip > *eip_limit. */ ++ } ++ ++ /* Get the GDT/LDT descriptor base. ++ When you look for races in this code remember that ++ LDT and other horrors are only used in user space. */ ++ if (seg & (1<<2)) { ++ /* Must lock the LDT while reading it. */ ++ down(¤t->mm->context.sem); ++ desc = current->mm->context.ldt; ++ desc = (void *)desc + (seg & ~7); ++ } else { ++ /* Must disable preemption while reading the GDT. */ ++ desc = (u32 *)get_cpu_gdt_table(get_cpu()); ++ desc = (void *)desc + (seg & ~7); ++ } ++ ++ /* Decode the code segment base from the descriptor */ ++ base = get_desc_base((unsigned long *)desc); ++ ++ if (seg & (1<<2)) { ++ up(¤t->mm->context.sem); ++ } else ++ put_cpu(); ++ ++ /* Adjust EIP and segment limit, and clamp at the kernel limit. ++ It's legitimate for segments to wrap at 0xffffffff. */ ++ seg_limit += base; ++ if (seg_limit < *eip_limit && seg_limit >= base) ++ *eip_limit = seg_limit; ++ return eip + base; ++} ++ ++/* ++ * Sometimes AMD Athlon/Opteron CPUs report invalid exceptions on prefetch. ++ * Check that here and ignore it. ++ */ ++static int __is_prefetch(struct pt_regs *regs, unsigned long addr) ++{ ++ unsigned long limit; ++ unsigned char *instr = (unsigned char *)get_segment_eip (regs, &limit); ++ int scan_more = 1; ++ int prefetch = 0; ++ int i; ++ ++ for (i = 0; scan_more && i < 15; i++) { ++ unsigned char opcode; ++ unsigned char instr_hi; ++ unsigned char instr_lo; ++ ++ if (instr > (unsigned char *)limit) ++ break; ++ if (probe_kernel_address(instr, opcode)) ++ break; ++ ++ instr_hi = opcode & 0xf0; ++ instr_lo = opcode & 0x0f; ++ instr++; ++ ++ switch (instr_hi) { ++ case 0x20: ++ case 0x30: ++ /* Values 0x26,0x2E,0x36,0x3E are valid x86 prefixes. */ ++ scan_more = ((instr_lo & 7) == 0x6); ++ break; ++ ++ case 0x60: ++ /* 0x64 thru 0x67 are valid prefixes in all modes. */ ++ scan_more = (instr_lo & 0xC) == 0x4; ++ break; ++ case 0xF0: ++ /* 0xF0, 0xF2, and 0xF3 are valid prefixes */ ++ scan_more = !instr_lo || (instr_lo>>1) == 1; ++ break; ++ case 0x00: ++ /* Prefetch instruction is 0x0F0D or 0x0F18 */ ++ scan_more = 0; ++ if (instr > (unsigned char *)limit) ++ break; ++ if (probe_kernel_address(instr, opcode)) ++ break; ++ prefetch = (instr_lo == 0xF) && ++ (opcode == 0x0D || opcode == 0x18); ++ break; ++ default: ++ scan_more = 0; ++ break; ++ } ++ } ++ return prefetch; ++} ++ ++static inline int is_prefetch(struct pt_regs *regs, unsigned long addr, ++ unsigned long error_code) ++{ ++ if (unlikely(boot_cpu_data.x86_vendor == X86_VENDOR_AMD && ++ boot_cpu_data.x86 >= 6)) { ++ /* Catch an obscure case of prefetch inside an NX page. */ ++ if (nx_enabled && (error_code & 16)) ++ return 0; ++ return __is_prefetch(regs, addr); ++ } ++ return 0; ++} ++ ++static noinline void force_sig_info_fault(int si_signo, int si_code, ++ unsigned long address, struct task_struct *tsk) ++{ ++ siginfo_t info; ++ ++ info.si_signo = si_signo; ++ info.si_errno = 0; ++ info.si_code = si_code; ++ info.si_addr = (void __user *)address; ++ force_sig_info(si_signo, &info, tsk); ++} ++ ++fastcall void do_invalid_op(struct pt_regs *, unsigned long); ++ ++#ifdef CONFIG_X86_PAE ++static void dump_fault_path(unsigned long address) ++{ ++ unsigned long *p, page; ++ unsigned long mfn; ++ ++ page = read_cr3(); ++ p = (unsigned long *)__va(page); ++ p += (address >> 30) * 2; ++ printk(KERN_ALERT "%08lx -> *pde = %08lx:%08lx\n", page, p[1], p[0]); ++ if (p[0] & 1) { ++ mfn = (p[0] >> PAGE_SHIFT) | (p[1] << 20); ++ page = mfn_to_pfn(mfn) << PAGE_SHIFT; ++ p = (unsigned long *)__va(page); ++ address &= 0x3fffffff; ++ p += (address >> 21) * 2; ++ printk(KERN_ALERT "%08lx -> *pme = %08lx:%08lx\n", ++ page, p[1], p[0]); ++ mfn = (p[0] >> PAGE_SHIFT) | (p[1] << 20); ++#ifdef CONFIG_HIGHPTE ++ if (mfn_to_pfn(mfn) >= highstart_pfn) ++ return; ++#endif ++ if (p[0] & 1) { ++ page = mfn_to_pfn(mfn) << PAGE_SHIFT; ++ p = (unsigned long *) __va(page); ++ address &= 0x001fffff; ++ p += (address >> 12) * 2; ++ printk(KERN_ALERT "%08lx -> *pte = %08lx:%08lx\n", ++ page, p[1], p[0]); ++ } ++ } ++} ++#else ++static void dump_fault_path(unsigned long address) ++{ ++ unsigned long page; ++ ++ page = read_cr3(); ++ page = ((unsigned long *) __va(page))[address >> 22]; ++ if (oops_may_print()) ++ printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page, ++ machine_to_phys(page)); ++ /* ++ * We must not directly access the pte in the highpte ++ * case if the page table is located in highmem. ++ * And lets rather not kmap-atomic the pte, just in case ++ * it's allocated already. ++ */ ++#ifdef CONFIG_HIGHPTE ++ if ((page >> PAGE_SHIFT) >= highstart_pfn) ++ return; ++#endif ++ if ((page & 1) && oops_may_print()) { ++ page &= PAGE_MASK; ++ address &= 0x003ff000; ++ page = machine_to_phys(page); ++ page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; ++ printk(KERN_ALERT "*pte = ma %08lx pa %08lx\n", page, ++ machine_to_phys(page)); ++ } ++} ++#endif ++ ++static int spurious_fault(struct pt_regs *regs, ++ unsigned long address, ++ unsigned long error_code) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ /* Reserved-bit violation or user access to kernel space? */ ++ if (error_code & 0x0c) ++ return 0; ++ ++ pgd = init_mm.pgd + pgd_index(address); ++ if (!pgd_present(*pgd)) ++ return 0; ++ ++ pud = pud_offset(pgd, address); ++ if (!pud_present(*pud)) ++ return 0; ++ ++ pmd = pmd_offset(pud, address); ++ if (!pmd_present(*pmd)) ++ return 0; ++ ++ pte = pte_offset_kernel(pmd, address); ++ if (!pte_present(*pte)) ++ return 0; ++ if ((error_code & 0x02) && !pte_write(*pte)) ++ return 0; ++#ifdef CONFIG_X86_PAE ++ if ((error_code & 0x10) && (pte_val(*pte) & _PAGE_NX)) ++ return 0; ++#endif ++ ++ return 1; ++} ++ ++static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) ++{ ++ unsigned index = pgd_index(address); ++ pgd_t *pgd_k; ++ pud_t *pud, *pud_k; ++ pmd_t *pmd, *pmd_k; ++ ++ pgd += index; ++ pgd_k = init_mm.pgd + index; ++ ++ if (!pgd_present(*pgd_k)) ++ return NULL; ++ ++ /* ++ * set_pgd(pgd, *pgd_k); here would be useless on PAE ++ * and redundant with the set_pmd() on non-PAE. As would ++ * set_pud. ++ */ ++ ++ pud = pud_offset(pgd, address); ++ pud_k = pud_offset(pgd_k, address); ++ if (!pud_present(*pud_k)) ++ return NULL; ++ ++ pmd = pmd_offset(pud, address); ++ pmd_k = pmd_offset(pud_k, address); ++ if (!pmd_present(*pmd_k)) ++ return NULL; ++ if (!pmd_present(*pmd)) ++#ifndef CONFIG_XEN ++ set_pmd(pmd, *pmd_k); ++#else ++ /* ++ * When running on Xen we must launder *pmd_k through ++ * pmd_val() to ensure that _PAGE_PRESENT is correctly set. ++ */ ++ set_pmd(pmd, __pmd(pmd_val(*pmd_k))); ++#endif ++ else ++ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); ++ return pmd_k; ++} ++ ++/* ++ * Handle a fault on the vmalloc or module mapping area ++ * ++ * This assumes no large pages in there. ++ */ ++static inline int vmalloc_fault(unsigned long address) ++{ ++ unsigned long pgd_paddr; ++ pmd_t *pmd_k; ++ pte_t *pte_k; ++ /* ++ * Synchronize this task's top level page-table ++ * with the 'reference' page table. ++ * ++ * Do _not_ use "current" here. We might be inside ++ * an interrupt in the middle of a task switch.. ++ */ ++ pgd_paddr = read_cr3(); ++ pmd_k = vmalloc_sync_one(__va(pgd_paddr), address); ++ if (!pmd_k) ++ return -1; ++ pte_k = pte_offset_kernel(pmd_k, address); ++ if (!pte_present(*pte_k)) ++ return -1; ++ return 0; ++} ++ ++/* ++ * This routine handles page faults. It determines the address, ++ * and the problem, and then passes it off to one of the appropriate ++ * routines. ++ * ++ * error_code: ++ * bit 0 == 0 means no page found, 1 means protection fault ++ * bit 1 == 0 means read, 1 means write ++ * bit 2 == 0 means kernel, 1 means user-mode ++ * bit 3 == 1 means use of reserved bit detected ++ * bit 4 == 1 means fault was an instruction fetch ++ */ ++fastcall void __kprobes do_page_fault(struct pt_regs *regs, ++ unsigned long error_code) ++{ ++ struct task_struct *tsk; ++ struct mm_struct *mm; ++ struct vm_area_struct * vma; ++ unsigned long address; ++ int write, si_code; ++ ++ /* get the address */ ++ address = read_cr2(); ++ ++ /* Set the "privileged fault" bit to something sane. */ ++ error_code &= ~4; ++ error_code |= (regs->xcs & 2) << 1; ++ if (regs->eflags & X86_EFLAGS_VM) ++ error_code |= 4; ++ ++ tsk = current; ++ ++ si_code = SEGV_MAPERR; ++ ++ /* ++ * We fault-in kernel-space virtual memory on-demand. The ++ * 'reference' page table is init_mm.pgd. ++ * ++ * NOTE! We MUST NOT take any locks for this case. We may ++ * be in an interrupt or a critical region, and should ++ * only copy the information from the master page table, ++ * nothing more. ++ * ++ * This verifies that the fault happens in kernel space ++ * (error_code & 4) == 0, and that the fault was not a ++ * protection error (error_code & 9) == 0. ++ */ ++ if (unlikely(address >= TASK_SIZE)) { ++#ifdef CONFIG_XEN ++ /* Faults in hypervisor area can never be patched up. */ ++ if (address >= hypervisor_virt_start) ++ goto bad_area_nosemaphore; ++#endif ++ if (!(error_code & 0x0000000d) && vmalloc_fault(address) >= 0) ++ return; ++ /* Can take a spurious fault if mapping changes R/O -> R/W. */ ++ if (spurious_fault(regs, address, error_code)) ++ return; ++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, ++ SIGSEGV) == NOTIFY_STOP) ++ return; ++ /* ++ * Don't take the mm semaphore here. If we fixup a prefetch ++ * fault we could otherwise deadlock. ++ */ ++ goto bad_area_nosemaphore; ++ } ++ ++ if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, ++ SIGSEGV) == NOTIFY_STOP) ++ return; ++ ++ /* It's safe to allow irq's after cr2 has been saved and the vmalloc ++ fault has been handled. */ ++ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK)) ++ local_irq_enable(); ++ ++ mm = tsk->mm; ++ ++ /* ++ * If we're in an interrupt, have no user context or are running in an ++ * atomic region then we must not take the fault.. ++ */ ++ if (in_atomic() || !mm) ++ goto bad_area_nosemaphore; ++ ++ /* When running in the kernel we expect faults to occur only to ++ * addresses in user space. All other faults represent errors in the ++ * kernel and should generate an OOPS. Unfortunatly, in the case of an ++ * erroneous fault occurring in a code path which already holds mmap_sem ++ * we will deadlock attempting to validate the fault against the ++ * address space. Luckily the kernel only validly references user ++ * space from well defined areas of code, which are listed in the ++ * exceptions table. ++ * ++ * As the vast majority of faults will be valid we will only perform ++ * the source reference check when there is a possibilty of a deadlock. ++ * Attempt to lock the address space, if we cannot we then validate the ++ * source. If this is invalid we can skip the address space check, ++ * thus avoiding the deadlock. ++ */ ++ if (!down_read_trylock(&mm->mmap_sem)) { ++ if ((error_code & 4) == 0 && ++ !search_exception_tables(regs->eip)) ++ goto bad_area_nosemaphore; ++ down_read(&mm->mmap_sem); ++ } ++ ++ vma = find_vma(mm, address); ++ if (!vma) ++ goto bad_area; ++ if (vma->vm_start <= address) ++ goto good_area; ++ if (!(vma->vm_flags & VM_GROWSDOWN)) ++ goto bad_area; ++ if (error_code & 4) { ++ /* ++ * Accessing the stack below %esp is always a bug. ++ * The large cushion allows instructions like enter ++ * and pusha to work. ("enter $65535,$31" pushes ++ * 32 pointers and then decrements %esp by 65535.) ++ */ ++ if (address + 65536 + 32 * sizeof(unsigned long) < regs->esp) ++ goto bad_area; ++ } ++ if (expand_stack(vma, address)) ++ goto bad_area; ++/* ++ * Ok, we have a good vm_area for this memory access, so ++ * we can handle it.. ++ */ ++good_area: ++ si_code = SEGV_ACCERR; ++ write = 0; ++ switch (error_code & 3) { ++ default: /* 3: write, present */ ++ /* fall through */ ++ case 2: /* write, not present */ ++ if (!(vma->vm_flags & VM_WRITE)) ++ goto bad_area; ++ write++; ++ break; ++ case 1: /* read, present */ ++ goto bad_area; ++ case 0: /* read, not present */ ++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) ++ goto bad_area; ++ } ++ ++ survive: ++ /* ++ * If for any reason at all we couldn't handle the fault, ++ * make sure we exit gracefully rather than endlessly redo ++ * the fault. ++ */ ++ switch (handle_mm_fault(mm, vma, address, write)) { ++ case VM_FAULT_MINOR: ++ tsk->min_flt++; ++ break; ++ case VM_FAULT_MAJOR: ++ tsk->maj_flt++; ++ break; ++ case VM_FAULT_SIGBUS: ++ goto do_sigbus; ++ case VM_FAULT_OOM: ++ goto out_of_memory; ++ default: ++ BUG(); ++ } ++ ++ /* ++ * Did it hit the DOS screen memory VA from vm86 mode? ++ */ ++ if (regs->eflags & VM_MASK) { ++ unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT; ++ if (bit < 32) ++ tsk->thread.screen_bitmap |= 1 << bit; ++ } ++ up_read(&mm->mmap_sem); ++ return; ++ ++/* ++ * Something tried to access memory that isn't in our memory map.. ++ * Fix it, but check if it's kernel or user first.. ++ */ ++bad_area: ++ up_read(&mm->mmap_sem); ++ ++bad_area_nosemaphore: ++ /* User mode accesses just cause a SIGSEGV */ ++ if (error_code & 4) { ++ /* ++ * Valid to do another page fault here because this one came ++ * from user space. ++ */ ++ if (is_prefetch(regs, address, error_code)) ++ return; ++ ++ tsk->thread.cr2 = address; ++ /* Kernel addresses are always protection faults */ ++ tsk->thread.error_code = error_code | (address >= TASK_SIZE); ++ tsk->thread.trap_no = 14; ++ force_sig_info_fault(SIGSEGV, si_code, address, tsk); ++ return; ++ } ++ ++#ifdef CONFIG_X86_F00F_BUG ++ /* ++ * Pentium F0 0F C7 C8 bug workaround. ++ */ ++ if (boot_cpu_data.f00f_bug) { ++ unsigned long nr; ++ ++ nr = (address - idt_descr.address) >> 3; ++ ++ if (nr == 6) { ++ do_invalid_op(regs, 0); ++ return; ++ } ++ } ++#endif ++ ++no_context: ++ /* Are we prepared to handle this kernel fault? */ ++ if (fixup_exception(regs)) ++ return; ++ ++ /* ++ * Valid to do another page fault here, because if this fault ++ * had been triggered by is_prefetch fixup_exception would have ++ * handled it. ++ */ ++ if (is_prefetch(regs, address, error_code)) ++ return; ++ ++/* ++ * Oops. The kernel tried to access some bad page. We'll have to ++ * terminate things with extreme prejudice. ++ */ ++ ++ bust_spinlocks(1); ++ ++ if (oops_may_print()) { ++ #ifdef CONFIG_X86_PAE ++ if (error_code & 16) { ++ pte_t *pte = lookup_address(address); ++ ++ if (pte && pte_present(*pte) && !pte_exec_kernel(*pte)) ++ printk(KERN_CRIT "kernel tried to execute " ++ "NX-protected page - exploit attempt? " ++ "(uid: %d)\n", current->uid); ++ } ++ #endif ++ if (address < PAGE_SIZE) ++ printk(KERN_ALERT "BUG: unable to handle kernel NULL " ++ "pointer dereference"); ++ else ++ printk(KERN_ALERT "BUG: unable to handle kernel paging" ++ " request"); ++ printk(" at virtual address %08lx\n",address); ++ printk(KERN_ALERT " printing eip:\n"); ++ printk("%08lx\n", regs->eip); ++ } ++ dump_fault_path(address); ++ tsk->thread.cr2 = address; ++ tsk->thread.trap_no = 14; ++ tsk->thread.error_code = error_code; ++ die("Oops", regs, error_code); ++ bust_spinlocks(0); ++ do_exit(SIGKILL); ++ ++/* ++ * We ran out of memory, or some other thing happened to us that made ++ * us unable to handle the page fault gracefully. ++ */ ++out_of_memory: ++ up_read(&mm->mmap_sem); ++ if (is_init(tsk)) { ++ yield(); ++ down_read(&mm->mmap_sem); ++ goto survive; ++ } ++ printk("VM: killing process %s\n", tsk->comm); ++ if (error_code & 4) ++ do_exit(SIGKILL); ++ goto no_context; ++ ++do_sigbus: ++ up_read(&mm->mmap_sem); ++ ++ /* Kernel mode? Handle exceptions or die */ ++ if (!(error_code & 4)) ++ goto no_context; ++ ++ /* User space => ok to do another page fault */ ++ if (is_prefetch(regs, address, error_code)) ++ return; ++ ++ tsk->thread.cr2 = address; ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 14; ++ force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); ++} ++ ++#if !HAVE_SHARED_KERNEL_PMD ++void vmalloc_sync_all(void) ++{ ++ /* ++ * Note that races in the updates of insync and start aren't ++ * problematic: insync can only get set bits added, and updates to ++ * start are only improving performance (without affecting correctness ++ * if undone). ++ */ ++ static DECLARE_BITMAP(insync, PTRS_PER_PGD); ++ static unsigned long start = TASK_SIZE; ++ unsigned long address; ++ ++ BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK); ++ for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) { ++ if (!test_bit(pgd_index(address), insync)) { ++ unsigned long flags; ++ struct page *page; ++ ++ spin_lock_irqsave(&pgd_lock, flags); ++ for (page = pgd_list; page; page = ++ (struct page *)page->index) ++ if (!vmalloc_sync_one(page_address(page), ++ address)) { ++ BUG_ON(page != pgd_list); ++ break; ++ } ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ if (!page) ++ set_bit(pgd_index(address), insync); ++ } ++ if (address == start && test_bit(pgd_index(address), insync)) ++ start = address + PGDIR_SIZE; ++ } ++} ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/highmem-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/highmem-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,120 @@ ++#include <linux/highmem.h> ++#include <linux/module.h> ++ ++void *kmap(struct page *page) ++{ ++ might_sleep(); ++ if (!PageHighMem(page)) ++ return page_address(page); ++ return kmap_high(page); ++} ++ ++void kunmap(struct page *page) ++{ ++ if (in_interrupt()) ++ BUG(); ++ if (!PageHighMem(page)) ++ return; ++ kunmap_high(page); ++} ++ ++/* ++ * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because ++ * no global lock is needed and because the kmap code must perform a global TLB ++ * invalidation when the kmap pool wraps. ++ * ++ * However when holding an atomic kmap is is not legal to sleep, so atomic ++ * kmaps are appropriate for short, tight code paths only. ++ */ ++static void *__kmap_atomic(struct page *page, enum km_type type, pgprot_t prot) ++{ ++ enum fixed_addresses idx; ++ unsigned long vaddr; ++ ++ /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ ++ pagefault_disable(); ++ if (!PageHighMem(page)) ++ return page_address(page); ++ ++ idx = type + KM_TYPE_NR*smp_processor_id(); ++ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); ++ if (!pte_none(*(kmap_pte-idx))) ++ BUG(); ++ set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); ++ ++ return (void*) vaddr; ++} ++ ++void *kmap_atomic(struct page *page, enum km_type type) ++{ ++ return __kmap_atomic(page, type, kmap_prot); ++} ++ ++/* Same as kmap_atomic but with PAGE_KERNEL_RO page protection. */ ++void *kmap_atomic_pte(struct page *page, enum km_type type) ++{ ++ return __kmap_atomic(page, type, ++ test_bit(PG_pinned, &page->flags) ++ ? PAGE_KERNEL_RO : kmap_prot); ++} ++ ++void kunmap_atomic(void *kvaddr, enum km_type type) ++{ ++ unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; ++ enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); ++ ++ /* ++ * Force other mappings to Oops if they'll try to access this pte ++ * without first remap it. Keeping stale mappings around is a bad idea ++ * also, in case the page changes cacheability attributes or becomes ++ * a protected page in a hypervisor. ++ */ ++ if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) { ++ kpte_clear_flush(kmap_pte-idx, vaddr); ++ __flush_tlb_one(vaddr); ++ } else { ++#ifdef CONFIG_DEBUG_HIGHMEM ++ BUG_ON(vaddr < PAGE_OFFSET); ++ BUG_ON(vaddr >= (unsigned long)high_memory); ++#endif ++ } ++ ++ pagefault_enable(); ++} ++ ++/* This is the same as kmap_atomic() but can map memory that doesn't ++ * have a struct page associated with it. ++ */ ++void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) ++{ ++ enum fixed_addresses idx; ++ unsigned long vaddr; ++ ++ pagefault_disable(); ++ ++ idx = type + KM_TYPE_NR*smp_processor_id(); ++ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); ++ set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); ++ ++ return (void*) vaddr; ++} ++ ++struct page *kmap_atomic_to_page(void *ptr) ++{ ++ unsigned long idx, vaddr = (unsigned long)ptr; ++ pte_t *pte; ++ ++ if (vaddr < FIXADDR_START) ++ return virt_to_page(ptr); ++ ++ idx = virt_to_fix(vaddr); ++ pte = kmap_pte - (idx - FIX_KMAP_BEGIN); ++ return pte_page(*pte); ++} ++ ++EXPORT_SYMBOL(kmap); ++EXPORT_SYMBOL(kunmap); ++EXPORT_SYMBOL(kmap_atomic); ++EXPORT_SYMBOL(kmap_atomic_pte); ++EXPORT_SYMBOL(kunmap_atomic); ++EXPORT_SYMBOL(kmap_atomic_to_page); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/hypervisor.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/hypervisor.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,451 @@ ++/****************************************************************************** ++ * mm/hypervisor.c ++ * ++ * Update page tables via the hypervisor. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <linux/vmalloc.h> ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/hypervisor.h> ++#include <xen/balloon.h> ++#include <xen/features.h> ++#include <xen/interface/memory.h> ++#include <linux/module.h> ++#include <linux/percpu.h> ++#include <asm/tlbflush.h> ++ ++#ifdef CONFIG_X86_64 ++#define pmd_val_ma(v) (v).pmd ++#else ++#ifdef CONFIG_X86_PAE ++# define pmd_val_ma(v) ((v).pmd) ++# define pud_val_ma(v) ((v).pgd.pgd) ++#else ++# define pmd_val_ma(v) ((v).pud.pgd.pgd) ++#endif ++#endif ++ ++void xen_l1_entry_update(pte_t *ptr, pte_t val) ++{ ++ mmu_update_t u; ++ u.ptr = virt_to_machine(ptr); ++ u.val = pte_val_ma(val); ++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_l2_entry_update(pmd_t *ptr, pmd_t val) ++{ ++ mmu_update_t u; ++ u.ptr = virt_to_machine(ptr); ++ u.val = pmd_val_ma(val); ++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++} ++ ++#ifdef CONFIG_X86_PAE ++void xen_l3_entry_update(pud_t *ptr, pud_t val) ++{ ++ mmu_update_t u; ++ u.ptr = virt_to_machine(ptr); ++ u.val = pud_val_ma(val); ++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++} ++#endif ++ ++#ifdef CONFIG_X86_64 ++void xen_l3_entry_update(pud_t *ptr, pud_t val) ++{ ++ mmu_update_t u; ++ u.ptr = virt_to_machine(ptr); ++ u.val = val.pud; ++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_l4_entry_update(pgd_t *ptr, pgd_t val) ++{ ++ mmu_update_t u; ++ u.ptr = virt_to_machine(ptr); ++ u.val = val.pgd; ++ BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++} ++#endif /* CONFIG_X86_64 */ ++ ++void xen_pt_switch(unsigned long ptr) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_NEW_BASEPTR; ++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_new_user_pt(unsigned long ptr) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_NEW_USER_BASEPTR; ++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_tlb_flush(void) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_TLB_FLUSH_LOCAL; ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++EXPORT_SYMBOL(xen_tlb_flush); ++ ++void xen_invlpg(unsigned long ptr) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_INVLPG_LOCAL; ++ op.arg1.linear_addr = ptr & PAGE_MASK; ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++EXPORT_SYMBOL(xen_invlpg); ++ ++#ifdef CONFIG_SMP ++ ++void xen_tlb_flush_all(void) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_TLB_FLUSH_ALL; ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_tlb_flush_mask(cpumask_t *mask) ++{ ++ struct mmuext_op op; ++ if ( cpus_empty(*mask) ) ++ return; ++ op.cmd = MMUEXT_TLB_FLUSH_MULTI; ++ set_xen_guest_handle(op.arg2.vcpumask, mask->bits); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_invlpg_all(unsigned long ptr) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_INVLPG_ALL; ++ op.arg1.linear_addr = ptr & PAGE_MASK; ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr) ++{ ++ struct mmuext_op op; ++ if ( cpus_empty(*mask) ) ++ return; ++ op.cmd = MMUEXT_INVLPG_MULTI; ++ op.arg1.linear_addr = ptr & PAGE_MASK; ++ set_xen_guest_handle(op.arg2.vcpumask, mask->bits); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++#endif /* CONFIG_SMP */ ++ ++void xen_pgd_pin(unsigned long ptr) ++{ ++ struct mmuext_op op; ++#ifdef CONFIG_X86_64 ++ op.cmd = MMUEXT_PIN_L4_TABLE; ++#elif defined(CONFIG_X86_PAE) ++ op.cmd = MMUEXT_PIN_L3_TABLE; ++#else ++ op.cmd = MMUEXT_PIN_L2_TABLE; ++#endif ++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_pgd_unpin(unsigned long ptr) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_UNPIN_TABLE; ++ op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++void xen_set_ldt(unsigned long ptr, unsigned long len) ++{ ++ struct mmuext_op op; ++ op.cmd = MMUEXT_SET_LDT; ++ op.arg1.linear_addr = ptr; ++ op.arg2.nr_ents = len; ++ BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++} ++ ++/* ++ * Bitmap is indexed by page number. If bit is set, the page is part of a ++ * xen_create_contiguous_region() area of memory. ++ */ ++unsigned long *contiguous_bitmap; ++ ++static void contiguous_bitmap_set( ++ unsigned long first_page, unsigned long nr_pages) ++{ ++ unsigned long start_off, end_off, curr_idx, end_idx; ++ ++ curr_idx = first_page / BITS_PER_LONG; ++ start_off = first_page & (BITS_PER_LONG-1); ++ end_idx = (first_page + nr_pages) / BITS_PER_LONG; ++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1); ++ ++ if (curr_idx == end_idx) { ++ contiguous_bitmap[curr_idx] |= ++ ((1UL<<end_off)-1) & -(1UL<<start_off); ++ } else { ++ contiguous_bitmap[curr_idx] |= -(1UL<<start_off); ++ while ( ++curr_idx < end_idx ) ++ contiguous_bitmap[curr_idx] = ~0UL; ++ contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1; ++ } ++} ++ ++static void contiguous_bitmap_clear( ++ unsigned long first_page, unsigned long nr_pages) ++{ ++ unsigned long start_off, end_off, curr_idx, end_idx; ++ ++ curr_idx = first_page / BITS_PER_LONG; ++ start_off = first_page & (BITS_PER_LONG-1); ++ end_idx = (first_page + nr_pages) / BITS_PER_LONG; ++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1); ++ ++ if (curr_idx == end_idx) { ++ contiguous_bitmap[curr_idx] &= ++ -(1UL<<end_off) | ((1UL<<start_off)-1); ++ } else { ++ contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1; ++ while ( ++curr_idx != end_idx ) ++ contiguous_bitmap[curr_idx] = 0; ++ contiguous_bitmap[curr_idx] &= -(1UL<<end_off); ++ } ++} ++ ++/* Protected by balloon_lock. */ ++#define MAX_CONTIG_ORDER 9 /* 2MB */ ++static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER]; ++static multicall_entry_t cr_mcl[1<<MAX_CONTIG_ORDER]; ++ ++/* Ensure multi-page extents are contiguous in machine memory. */ ++int xen_create_contiguous_region( ++ unsigned long vstart, unsigned int order, unsigned int address_bits) ++{ ++ unsigned long *in_frames = discontig_frames, out_frame; ++ unsigned long frame, i, flags; ++ long rc; ++ int success; ++ struct xen_memory_exchange exchange = { ++ .in = { ++ .nr_extents = 1UL << order, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }, ++ .out = { ++ .nr_extents = 1, ++ .extent_order = order, ++ .address_bits = address_bits, ++ .domid = DOMID_SELF ++ } ++ }; ++ ++ /* ++ * Currently an auto-translated guest will not perform I/O, nor will ++ * it require PAE page directories below 4GB. Therefore any calls to ++ * this function are redundant and can be ignored. ++ */ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return 0; ++ ++ if (unlikely(order > MAX_CONTIG_ORDER)) ++ return -ENOMEM; ++ ++ set_xen_guest_handle(exchange.in.extent_start, in_frames); ++ set_xen_guest_handle(exchange.out.extent_start, &out_frame); ++ ++ scrub_pages(vstart, 1 << order); ++ ++ balloon_lock(flags); ++ ++ /* 1. Zap current PTEs, remembering MFNs. */ ++ for (i = 0; i < (1UL<<order); i++) { ++ in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i); ++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), ++ __pte_ma(0), 0); ++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, ++ INVALID_P2M_ENTRY); ++ } ++ if (HYPERVISOR_multicall_check(cr_mcl, i, NULL)) ++ BUG(); ++ ++ /* 2. Get a new contiguous memory extent. */ ++ out_frame = __pa(vstart) >> PAGE_SHIFT; ++ rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); ++ success = (exchange.nr_exchanged == (1UL << order)); ++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0))); ++ BUG_ON(success && (rc != 0)); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ /* Compatibility when XENMEM_exchange is unsupported. */ ++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &exchange.in) != (1UL << order)) ++ BUG(); ++ success = (HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.out) == 1); ++ if (!success) { ++ /* Couldn't get special memory: fall back to normal. */ ++ for (i = 0; i < (1UL<<order); i++) ++ in_frames[i] = (__pa(vstart)>>PAGE_SHIFT) + i; ++ if (HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.in) != (1UL<<order)) ++ BUG(); ++ } ++ } ++#endif ++ ++ /* 3. Map the new extent in place of old pages. */ ++ for (i = 0; i < (1UL<<order); i++) { ++ frame = success ? (out_frame + i) : in_frames[i]; ++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), ++ pfn_pte_ma(frame, PAGE_KERNEL), 0); ++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame); ++ } ++ ++ cr_mcl[i - 1].args[MULTI_UVMFLAGS_INDEX] = order ++ ? UVMF_TLB_FLUSH|UVMF_ALL ++ : UVMF_INVLPG|UVMF_ALL; ++ if (HYPERVISOR_multicall_check(cr_mcl, i, NULL)) ++ BUG(); ++ ++ if (success) ++ contiguous_bitmap_set(__pa(vstart) >> PAGE_SHIFT, ++ 1UL << order); ++ ++ balloon_unlock(flags); ++ ++ return success ? 0 : -ENOMEM; ++} ++EXPORT_SYMBOL_GPL(xen_create_contiguous_region); ++ ++void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) ++{ ++ unsigned long *out_frames = discontig_frames, in_frame; ++ unsigned long frame, i, flags; ++ long rc; ++ int success; ++ struct xen_memory_exchange exchange = { ++ .in = { ++ .nr_extents = 1, ++ .extent_order = order, ++ .domid = DOMID_SELF ++ }, ++ .out = { ++ .nr_extents = 1UL << order, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ } ++ }; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap) || ++ !test_bit(__pa(vstart) >> PAGE_SHIFT, contiguous_bitmap)) ++ return; ++ ++ if (unlikely(order > MAX_CONTIG_ORDER)) ++ return; ++ ++ set_xen_guest_handle(exchange.in.extent_start, &in_frame); ++ set_xen_guest_handle(exchange.out.extent_start, out_frames); ++ ++ scrub_pages(vstart, 1 << order); ++ ++ balloon_lock(flags); ++ ++ contiguous_bitmap_clear(__pa(vstart) >> PAGE_SHIFT, 1UL << order); ++ ++ /* 1. Find start MFN of contiguous extent. */ ++ in_frame = pfn_to_mfn(__pa(vstart) >> PAGE_SHIFT); ++ ++ /* 2. Zap current PTEs. */ ++ for (i = 0; i < (1UL<<order); i++) { ++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), ++ __pte_ma(0), 0); ++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, ++ INVALID_P2M_ENTRY); ++ out_frames[i] = (__pa(vstart) >> PAGE_SHIFT) + i; ++ } ++ if (HYPERVISOR_multicall_check(cr_mcl, i, NULL)) ++ BUG(); ++ ++ /* 3. Do the exchange for non-contiguous MFNs. */ ++ rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); ++ success = (exchange.nr_exchanged == 1); ++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0))); ++ BUG_ON(success && (rc != 0)); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ /* Compatibility when XENMEM_exchange is unsupported. */ ++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &exchange.in) != 1) ++ BUG(); ++ if (HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.out) != (1UL << order)) ++ BUG(); ++ success = 1; ++ } ++#endif ++ ++ /* 4. Map new pages in place of old pages. */ ++ for (i = 0; i < (1UL<<order); i++) { ++ frame = success ? out_frames[i] : (in_frame + i); ++ MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), ++ pfn_pte_ma(frame, PAGE_KERNEL), 0); ++ set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame); ++ } ++ ++ cr_mcl[i - 1].args[MULTI_UVMFLAGS_INDEX] = order ++ ? UVMF_TLB_FLUSH|UVMF_ALL ++ : UVMF_INVLPG|UVMF_ALL; ++ if (HYPERVISOR_multicall_check(cr_mcl, i, NULL)) ++ BUG(); ++ ++ balloon_unlock(flags); ++} ++EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); ++ ++#ifdef __i386__ ++int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b) ++{ ++ __u32 *lp = (__u32 *)((char *)ldt + entry * 8); ++ maddr_t mach_lp = arbitrary_virt_to_machine(lp); ++ return HYPERVISOR_update_descriptor( ++ mach_lp, (u64)entry_a | ((u64)entry_b<<32)); ++} ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/init-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/init-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,871 @@ ++/* ++ * linux/arch/i386/mm/init.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * ++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 ++ */ ++ ++#include <linux/module.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/ptrace.h> ++#include <linux/mman.h> ++#include <linux/mm.h> ++#include <linux/hugetlb.h> ++#include <linux/swap.h> ++#include <linux/smp.h> ++#include <linux/init.h> ++#include <linux/highmem.h> ++#include <linux/pagemap.h> ++#include <linux/poison.h> ++#include <linux/bootmem.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/efi.h> ++#include <linux/memory_hotplug.h> ++#include <linux/initrd.h> ++#include <linux/cpumask.h> ++#include <linux/dma-mapping.h> ++#include <linux/scatterlist.h> ++ ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/dma.h> ++#include <asm/fixmap.h> ++#include <asm/e820.h> ++#include <asm/apic.h> ++#include <asm/tlb.h> ++#include <asm/tlbflush.h> ++#include <asm/sections.h> ++#include <asm/hypervisor.h> ++#include <asm/swiotlb.h> ++ ++extern unsigned long *contiguous_bitmap; ++ ++unsigned int __VMALLOC_RESERVE = 128 << 20; ++ ++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++unsigned long highstart_pfn, highend_pfn; ++ ++static int noinline do_test_wp_bit(void); ++ ++/* ++ * Creates a middle page table and puts a pointer to it in the ++ * given global directory entry. This only returns the gd entry ++ * in non-PAE compilation mode, since the middle layer is folded. ++ */ ++static pmd_t * __init one_md_table_init(pgd_t *pgd) ++{ ++ pud_t *pud; ++ pmd_t *pmd_table; ++ ++#ifdef CONFIG_X86_PAE ++ pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ make_lowmem_page_readonly(pmd_table, XENFEAT_writable_page_tables); ++ set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); ++ pud = pud_offset(pgd, 0); ++ if (pmd_table != pmd_offset(pud, 0)) ++ BUG(); ++#else ++ pud = pud_offset(pgd, 0); ++ pmd_table = pmd_offset(pud, 0); ++#endif ++ ++ return pmd_table; ++} ++ ++/* ++ * Create a page table and place a pointer to it in a middle page ++ * directory entry. ++ */ ++static pte_t * __init one_page_table_init(pmd_t *pmd) ++{ ++ if (pmd_none(*pmd)) { ++ pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ make_lowmem_page_readonly(page_table, ++ XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); ++ if (page_table != pte_offset_kernel(pmd, 0)) ++ BUG(); ++ ++ return page_table; ++ } ++ ++ return pte_offset_kernel(pmd, 0); ++} ++ ++/* ++ * This function initializes a certain range of kernel virtual memory ++ * with new bootmem page tables, everywhere page tables are missing in ++ * the given range. ++ */ ++ ++/* ++ * NOTE: The pagetables are allocated contiguous on the physical space ++ * so we can cache the place of the first one and move around without ++ * checking the pgd every time. ++ */ ++static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ int pgd_idx, pmd_idx; ++ unsigned long vaddr; ++ ++ vaddr = start; ++ pgd_idx = pgd_index(vaddr); ++ pmd_idx = pmd_index(vaddr); ++ pgd = pgd_base + pgd_idx; ++ ++ for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { ++ if (pgd_none(*pgd)) ++ one_md_table_init(pgd); ++ pud = pud_offset(pgd, vaddr); ++ pmd = pmd_offset(pud, vaddr); ++ for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { ++ if (vaddr < hypervisor_virt_start && pmd_none(*pmd)) ++ one_page_table_init(pmd); ++ ++ vaddr += PMD_SIZE; ++ } ++ pmd_idx = 0; ++ } ++} ++ ++static inline int is_kernel_text(unsigned long addr) ++{ ++ if (addr >= PAGE_OFFSET && addr <= (unsigned long)__init_end) ++ return 1; ++ return 0; ++} ++ ++/* ++ * This maps the physical memory to kernel virtual address space, a total ++ * of max_low_pfn pages, by creating page tables starting from address ++ * PAGE_OFFSET. ++ */ ++static void __init kernel_physical_mapping_init(pgd_t *pgd_base) ++{ ++ unsigned long pfn; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ int pgd_idx, pmd_idx, pte_ofs; ++ ++ unsigned long max_ram_pfn = xen_start_info->nr_pages; ++ if (max_ram_pfn > max_low_pfn) ++ max_ram_pfn = max_low_pfn; ++ ++ pgd_idx = pgd_index(PAGE_OFFSET); ++ pgd = pgd_base + pgd_idx; ++ pfn = 0; ++ pmd_idx = pmd_index(PAGE_OFFSET); ++ pte_ofs = pte_index(PAGE_OFFSET); ++ ++ for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { ++#ifdef CONFIG_XEN ++ /* ++ * Native linux hasn't PAE-paging enabled yet at this ++ * point. When running as xen domain we are in PAE ++ * mode already, thus we can't simply hook a empty ++ * pmd. That would kill the mappings we are currently ++ * using ... ++ */ ++ pmd = pmd_offset(pud_offset(pgd, PAGE_OFFSET), PAGE_OFFSET); ++#else ++ pmd = one_md_table_init(pgd); ++#endif ++ if (pfn >= max_low_pfn) ++ continue; ++ pmd += pmd_idx; ++ for (; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { ++ unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET; ++ if (address >= hypervisor_virt_start) ++ continue; ++ ++ /* Map with big pages if possible, otherwise create normal page tables. */ ++ if (cpu_has_pse) { ++ unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; ++ ++ if (is_kernel_text(address) || is_kernel_text(address2)) ++ set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); ++ else ++ set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); ++ pfn += PTRS_PER_PTE; ++ } else { ++ pte = one_page_table_init(pmd); ++ ++ pte += pte_ofs; ++ for (; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { ++ /* XEN: Only map initial RAM allocation. */ ++ if ((pfn >= max_ram_pfn) || pte_present(*pte)) ++ continue; ++ if (is_kernel_text(address)) ++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); ++ else ++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); ++ } ++ pte_ofs = 0; ++ } ++ } ++ pmd_idx = 0; ++ } ++} ++ ++#ifndef CONFIG_XEN ++ ++static inline int page_kills_ppro(unsigned long pagenr) ++{ ++ if (pagenr >= 0x70000 && pagenr <= 0x7003F) ++ return 1; ++ return 0; ++} ++ ++#else ++ ++#define page_kills_ppro(p) 0 ++ ++#endif ++ ++int page_is_ram(unsigned long pagenr) ++{ ++ int i; ++ unsigned long addr, end; ++ ++ if (efi_enabled) { ++ efi_memory_desc_t *md; ++ void *p; ++ ++ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { ++ md = p; ++ if (!is_available_memory(md)) ++ continue; ++ addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT; ++ end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT; ++ ++ if ((pagenr >= addr) && (pagenr < end)) ++ return 1; ++ } ++ return 0; ++ } ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ ++ if (e820.map[i].type != E820_RAM) /* not usable memory */ ++ continue; ++ /* ++ * !!!FIXME!!! Some BIOSen report areas as RAM that ++ * are not. Notably the 640->1Mb area. We need a sanity ++ * check here. ++ */ ++ addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; ++ end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; ++ if ((pagenr >= addr) && (pagenr < end)) ++ return 1; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_HIGHMEM ++pte_t *kmap_pte; ++pgprot_t kmap_prot; ++ ++#define kmap_get_fixmap_pte(vaddr) \ ++ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) ++ ++static void __init kmap_init(void) ++{ ++ unsigned long kmap_vstart; ++ ++ /* cache the first kmap pte */ ++ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); ++ kmap_pte = kmap_get_fixmap_pte(kmap_vstart); ++ ++ kmap_prot = PAGE_KERNEL; ++} ++ ++static void __init permanent_kmaps_init(pgd_t *pgd_base) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long vaddr; ++ ++ vaddr = PKMAP_BASE; ++ page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); ++ ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ pud = pud_offset(pgd, vaddr); ++ pmd = pmd_offset(pud, vaddr); ++ pte = pte_offset_kernel(pmd, vaddr); ++ pkmap_page_table = pte; ++} ++ ++static void __meminit free_new_highpage(struct page *page, int pfn) ++{ ++ init_page_count(page); ++ if (pfn < xen_start_info->nr_pages) ++ __free_page(page); ++ totalhigh_pages++; ++} ++ ++void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro) ++{ ++ if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) { ++ ClearPageReserved(page); ++ free_new_highpage(page, pfn); ++ } else ++ SetPageReserved(page); ++} ++ ++static int __meminit add_one_highpage_hotplug(struct page *page, unsigned long pfn) ++{ ++ free_new_highpage(page, pfn); ++ totalram_pages++; ++#ifdef CONFIG_FLATMEM ++ max_mapnr = max(pfn, max_mapnr); ++#endif ++ num_physpages++; ++ return 0; ++} ++ ++/* ++ * Not currently handling the NUMA case. ++ * Assuming single node and all memory that ++ * has been added dynamically that would be ++ * onlined here is in HIGHMEM ++ */ ++void __meminit online_page(struct page *page) ++{ ++ ClearPageReserved(page); ++ add_one_highpage_hotplug(page, page_to_pfn(page)); ++} ++ ++ ++#ifdef CONFIG_NUMA ++extern void set_highmem_pages_init(int); ++#else ++static void __init set_highmem_pages_init(int bad_ppro) ++{ ++ int pfn; ++ for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) ++ add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro); ++ totalram_pages += totalhigh_pages; ++} ++#endif /* CONFIG_FLATMEM */ ++ ++#else ++#define kmap_init() do { } while (0) ++#define permanent_kmaps_init(pgd_base) do { } while (0) ++#define set_highmem_pages_init(bad_ppro) do { } while (0) ++#endif /* CONFIG_HIGHMEM */ ++ ++unsigned long long __PAGE_KERNEL = _PAGE_KERNEL; ++EXPORT_SYMBOL(__PAGE_KERNEL); ++unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC; ++ ++#ifdef CONFIG_NUMA ++extern void __init remap_numa_kva(void); ++#else ++#define remap_numa_kva() do {} while (0) ++#endif ++ ++pgd_t *swapper_pg_dir; ++ ++static void __init pagetable_init (void) ++{ ++ unsigned long vaddr; ++ pgd_t *pgd_base = (pgd_t *)xen_start_info->pt_base; ++ ++ swapper_pg_dir = pgd_base; ++ init_mm.pgd = pgd_base; ++ ++ /* Enable PSE if available */ ++ if (cpu_has_pse) { ++ set_in_cr4(X86_CR4_PSE); ++ } ++ ++ /* Enable PGE if available */ ++ if (cpu_has_pge) { ++ set_in_cr4(X86_CR4_PGE); ++ __PAGE_KERNEL |= _PAGE_GLOBAL; ++ __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL; ++ } ++ ++ kernel_physical_mapping_init(pgd_base); ++ remap_numa_kva(); ++ ++ /* ++ * Fixed mappings, only the page table structure has to be ++ * created - mappings will be set by set_fixmap(): ++ */ ++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; ++ page_table_range_init(vaddr, hypervisor_virt_start, pgd_base); ++ ++ permanent_kmaps_init(pgd_base); ++} ++ ++#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) ++/* ++ * Swap suspend & friends need this for resume because things like the intel-agp ++ * driver might have split up a kernel 4MB mapping. ++ */ ++char __nosavedata swsusp_pg_dir[PAGE_SIZE] ++ __attribute__ ((aligned (PAGE_SIZE))); ++ ++static inline void save_pg_dir(void) ++{ ++ memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE); ++} ++#else ++static inline void save_pg_dir(void) ++{ ++} ++#endif ++ ++void zap_low_mappings (void) ++{ ++ int i; ++ ++ save_pg_dir(); ++ ++ /* ++ * Zap initial low-memory mappings. ++ * ++ * Note that "pgd_clear()" doesn't do it for ++ * us, because pgd_clear() is a no-op on i386. ++ */ ++ for (i = 0; i < USER_PTRS_PER_PGD; i++) ++#if defined(CONFIG_X86_PAE) && !defined(CONFIG_XEN) ++ set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); ++#else ++ set_pgd(swapper_pg_dir+i, __pgd(0)); ++#endif ++ flush_tlb_all(); ++} ++ ++static int disable_nx __initdata = 0; ++u64 __supported_pte_mask __read_mostly = ~_PAGE_NX; ++EXPORT_SYMBOL(__supported_pte_mask); ++ ++/* ++ * noexec = on|off ++ * ++ * Control non executable mappings. ++ * ++ * on Enable ++ * off Disable ++ */ ++static int __init noexec_setup(char *str) ++{ ++ if (!str || !strcmp(str, "on")) { ++ if (cpu_has_nx) { ++ __supported_pte_mask |= _PAGE_NX; ++ disable_nx = 0; ++ } ++ } else if (!strcmp(str,"off")) { ++ disable_nx = 1; ++ __supported_pte_mask &= ~_PAGE_NX; ++ } else ++ return -EINVAL; ++ ++ return 0; ++} ++early_param("noexec", noexec_setup); ++ ++int nx_enabled = 0; ++#ifdef CONFIG_X86_PAE ++ ++static void __init set_nx(void) ++{ ++ unsigned int v[4], l, h; ++ ++ if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { ++ cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); ++ if ((v[3] & (1 << 20)) && !disable_nx) { ++ rdmsr(MSR_EFER, l, h); ++ l |= EFER_NX; ++ wrmsr(MSR_EFER, l, h); ++ nx_enabled = 1; ++ __supported_pte_mask |= _PAGE_NX; ++ } ++ } ++} ++ ++/* ++ * Enables/disables executability of a given kernel page and ++ * returns the previous setting. ++ */ ++int __init set_kernel_exec(unsigned long vaddr, int enable) ++{ ++ pte_t *pte; ++ int ret = 1; ++ ++ if (!nx_enabled) ++ goto out; ++ ++ pte = lookup_address(vaddr); ++ BUG_ON(!pte); ++ ++ if (!pte_exec_kernel(*pte)) ++ ret = 0; ++ ++ if (enable) ++ pte->pte_high &= ~(1 << (_PAGE_BIT_NX - 32)); ++ else ++ pte->pte_high |= 1 << (_PAGE_BIT_NX - 32); ++ pte_update_defer(&init_mm, vaddr, pte); ++ __flush_tlb_all(); ++out: ++ return ret; ++} ++ ++#endif ++ ++/* ++ * paging_init() sets up the page tables - note that the first 8MB are ++ * already mapped by head.S. ++ * ++ * This routines also unmaps the page at virtual kernel address 0, so ++ * that we can trap those pesky NULL-reference errors in the kernel. ++ */ ++void __init paging_init(void) ++{ ++ int i; ++ ++#ifdef CONFIG_X86_PAE ++ set_nx(); ++ if (nx_enabled) ++ printk("NX (Execute Disable) protection: active\n"); ++#endif ++ ++ pagetable_init(); ++ ++#if defined(CONFIG_X86_PAE) && !defined(CONFIG_XEN) ++ /* ++ * We will bail out later - printk doesn't work right now so ++ * the user would just see a hanging kernel. ++ * when running as xen domain we are already in PAE mode at ++ * this point. ++ */ ++ if (cpu_has_pae) ++ set_in_cr4(X86_CR4_PAE); ++#endif ++ __flush_tlb_all(); ++ ++ kmap_init(); ++ ++ /* Switch to the real shared_info page, and clear the ++ * dummy page. */ ++ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); ++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); ++ memset(empty_zero_page, 0, sizeof(empty_zero_page)); ++ ++ /* Setup mapping of lower 1st MB */ ++ for (i = 0; i < NR_FIX_ISAMAPS; i++) ++ if (is_initial_xendomain()) ++ set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE); ++ else ++ __set_fixmap(FIX_ISAMAP_BEGIN - i, ++ virt_to_machine(empty_zero_page), ++ PAGE_KERNEL_RO); ++} ++ ++/* ++ * Test if the WP bit works in supervisor mode. It isn't supported on 386's ++ * and also on some strange 486's (NexGen etc.). All 586+'s are OK. This ++ * used to involve black magic jumps to work around some nasty CPU bugs, ++ * but fortunately the switch to using exceptions got rid of all that. ++ */ ++ ++static void __init test_wp_bit(void) ++{ ++ printk("Checking if this processor honours the WP bit even in supervisor mode... "); ++ ++ /* Any page-aligned address will do, the test is non-destructive */ ++ __set_fixmap(FIX_WP_TEST, __pa(&swapper_pg_dir), PAGE_READONLY); ++ boot_cpu_data.wp_works_ok = do_test_wp_bit(); ++ clear_fixmap(FIX_WP_TEST); ++ ++ if (!boot_cpu_data.wp_works_ok) { ++ printk("No.\n"); ++#ifdef CONFIG_X86_WP_WORKS_OK ++ panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!"); ++#endif ++ } else { ++ printk("Ok.\n"); ++ } ++} ++ ++static struct kcore_list kcore_mem, kcore_vmalloc; ++ ++void __init mem_init(void) ++{ ++ extern int ppro_with_ram_bug(void); ++ int codesize, reservedpages, datasize, initsize; ++ int tmp; ++ int bad_ppro; ++ unsigned long pfn; ++ ++ contiguous_bitmap = alloc_bootmem_low_pages( ++ (max_low_pfn + 2*BITS_PER_LONG) >> 3); ++ BUG_ON(!contiguous_bitmap); ++ memset(contiguous_bitmap, 0, (max_low_pfn + 2*BITS_PER_LONG) >> 3); ++ ++#if defined(CONFIG_SWIOTLB) ++ swiotlb_init(); ++#endif ++ ++#ifdef CONFIG_FLATMEM ++ BUG_ON(!mem_map); ++#endif ++ ++ bad_ppro = ppro_with_ram_bug(); ++ ++#ifdef CONFIG_HIGHMEM ++ /* check that fixmap and pkmap do not overlap */ ++ if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) { ++ printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n"); ++ printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n", ++ PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START); ++ BUG(); ++ } ++#endif ++ ++ printk("vmalloc area: %lx-%lx, maxmem %lx\n", ++ VMALLOC_START,VMALLOC_END,MAXMEM); ++ BUG_ON(VMALLOC_START > VMALLOC_END); ++ ++ /* this will put all low memory onto the freelists */ ++ totalram_pages += free_all_bootmem(); ++ /* XEN: init and count low-mem pages outside initial allocation. */ ++ for (pfn = xen_start_info->nr_pages; pfn < max_low_pfn; pfn++) { ++ ClearPageReserved(pfn_to_page(pfn)); ++ init_page_count(pfn_to_page(pfn)); ++ totalram_pages++; ++ } ++ ++ reservedpages = 0; ++ for (tmp = 0; tmp < max_low_pfn; tmp++) ++ /* ++ * Only count reserved RAM pages ++ */ ++ if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) ++ reservedpages++; ++ ++ set_highmem_pages_init(bad_ppro); ++ ++ codesize = (unsigned long) &_etext - (unsigned long) &_text; ++ datasize = (unsigned long) &_edata - (unsigned long) &_etext; ++ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; ++ ++ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); ++ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, ++ VMALLOC_END-VMALLOC_START); ++ ++ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", ++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), ++ num_physpages << (PAGE_SHIFT-10), ++ codesize >> 10, ++ reservedpages << (PAGE_SHIFT-10), ++ datasize >> 10, ++ initsize >> 10, ++ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ++ ); ++ ++#if 1 /* double-sanity-check paranoia */ ++ printk("virtual kernel memory layout:\n" ++ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#ifdef CONFIG_HIGHMEM ++ " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#endif ++ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", ++ FIXADDR_START, FIXADDR_TOP, ++ (FIXADDR_TOP - FIXADDR_START) >> 10, ++ ++#ifdef CONFIG_HIGHMEM ++ PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, ++ (LAST_PKMAP*PAGE_SIZE) >> 10, ++#endif ++ ++ VMALLOC_START, VMALLOC_END, ++ (VMALLOC_END - VMALLOC_START) >> 20, ++ ++ (unsigned long)__va(0), (unsigned long)high_memory, ++ ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20, ++ ++ (unsigned long)&__init_begin, (unsigned long)&__init_end, ++ ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10, ++ ++ (unsigned long)&_etext, (unsigned long)&_edata, ++ ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, ++ ++ (unsigned long)&_text, (unsigned long)&_etext, ++ ((unsigned long)&_etext - (unsigned long)&_text) >> 10); ++ ++#ifdef CONFIG_HIGHMEM ++ BUG_ON(PKMAP_BASE+LAST_PKMAP*PAGE_SIZE > FIXADDR_START); ++ BUG_ON(VMALLOC_END > PKMAP_BASE); ++#endif ++ BUG_ON(VMALLOC_START > VMALLOC_END); ++ BUG_ON((unsigned long)high_memory > VMALLOC_START); ++#endif /* double-sanity-check paranoia */ ++ ++#ifdef CONFIG_X86_PAE ++ if (!cpu_has_pae) ++ panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); ++#endif ++ if (boot_cpu_data.wp_works_ok < 0) ++ test_wp_bit(); ++ ++ /* ++ * Subtle. SMP is doing it's boot stuff late (because it has to ++ * fork idle threads) - but it also needs low mappings for the ++ * protected-mode entry to work. We zap these entries only after ++ * the WP-bit has been tested. ++ */ ++#ifndef CONFIG_SMP ++ zap_low_mappings(); ++#endif ++ ++ set_bit(PG_pinned, &virt_to_page(init_mm.pgd)->flags); ++} ++ ++#ifdef CONFIG_MEMORY_HOTPLUG ++int arch_add_memory(int nid, u64 start, u64 size) ++{ ++ struct pglist_data *pgdata = NODE_DATA(nid); ++ struct zone *zone = pgdata->node_zones + ZONE_HIGHMEM; ++ unsigned long start_pfn = start >> PAGE_SHIFT; ++ unsigned long nr_pages = size >> PAGE_SHIFT; ++ ++ return __add_pages(zone, start_pfn, nr_pages); ++} ++ ++int remove_memory(u64 start, u64 size) ++{ ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(remove_memory); ++#endif ++ ++struct kmem_cache *pgd_cache; ++struct kmem_cache *pmd_cache; ++ ++void __init pgtable_cache_init(void) ++{ ++ if (PTRS_PER_PMD > 1) { ++ pmd_cache = kmem_cache_create("pmd", ++ PTRS_PER_PMD*sizeof(pmd_t), ++ PTRS_PER_PMD*sizeof(pmd_t), ++ 0, ++ pmd_ctor, ++ NULL); ++ if (!pmd_cache) ++ panic("pgtable_cache_init(): cannot create pmd cache"); ++ } ++ pgd_cache = kmem_cache_create("pgd", ++#ifndef CONFIG_XEN ++ PTRS_PER_PGD*sizeof(pgd_t), ++ PTRS_PER_PGD*sizeof(pgd_t), ++#else ++ PAGE_SIZE, ++ PAGE_SIZE, ++#endif ++ 0, ++ pgd_ctor, ++ PTRS_PER_PMD == 1 ? pgd_dtor : NULL); ++ if (!pgd_cache) ++ panic("pgtable_cache_init(): Cannot create pgd cache"); ++} ++ ++/* ++ * This function cannot be __init, since exceptions don't work in that ++ * section. Put this after the callers, so that it cannot be inlined. ++ */ ++static int noinline do_test_wp_bit(void) ++{ ++ char tmp_reg; ++ int flag; ++ ++ __asm__ __volatile__( ++ " movb %0,%1 \n" ++ "1: movb %1,%0 \n" ++ " xorl %2,%2 \n" ++ "2: \n" ++ ".section __ex_table,\"a\"\n" ++ " .align 4 \n" ++ " .long 1b,2b \n" ++ ".previous \n" ++ :"=m" (*(char *)fix_to_virt(FIX_WP_TEST)), ++ "=q" (tmp_reg), ++ "=r" (flag) ++ :"2" (1) ++ :"memory"); ++ ++ return flag; ++} ++ ++#ifdef CONFIG_DEBUG_RODATA ++ ++void mark_rodata_ro(void) ++{ ++ unsigned long addr = (unsigned long)__start_rodata; ++ ++ for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) ++ change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO); ++ ++ printk("Write protecting the kernel read-only data: %uk\n", ++ (__end_rodata - __start_rodata) >> 10); ++ ++ /* ++ * change_page_attr() requires a global_flush_tlb() call after it. ++ * We do this after the printk so that if something went wrong in the ++ * change, the printk gets out at least to give a better debug hint ++ * of who is the culprit. ++ */ ++ global_flush_tlb(); ++} ++#endif ++ ++void free_init_pages(char *what, unsigned long begin, unsigned long end) ++{ ++ unsigned long addr; ++ ++ for (addr = begin; addr < end; addr += PAGE_SIZE) { ++ ClearPageReserved(virt_to_page(addr)); ++ init_page_count(virt_to_page(addr)); ++ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); ++ free_page(addr); ++ totalram_pages++; ++ } ++ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); ++} ++ ++void free_initmem(void) ++{ ++ free_init_pages("unused kernel memory", ++ (unsigned long)(&__init_begin), ++ (unsigned long)(&__init_end)); ++} ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++void free_initrd_mem(unsigned long start, unsigned long end) ++{ ++ free_init_pages("initrd memory", start, end); ++} ++#endif ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/ioremap-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/ioremap-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,443 @@ ++/* ++ * arch/i386/mm/ioremap.c ++ * ++ * Re-map IO memory to kernel address space so that we can access it. ++ * This is needed for high PCI addresses that aren't mapped in the ++ * 640k-1MB IO memory area on PC's ++ * ++ * (C) Copyright 1995 1996 Linus Torvalds ++ */ ++ ++#include <linux/vmalloc.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/io.h> ++#include <asm/fixmap.h> ++#include <asm/cacheflush.h> ++#include <asm/tlbflush.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++ ++#define ISA_START_ADDRESS 0x0 ++#define ISA_END_ADDRESS 0x100000 ++ ++static int direct_remap_area_pte_fn(pte_t *pte, ++ struct page *pmd_page, ++ unsigned long address, ++ void *data) ++{ ++ mmu_update_t **v = (mmu_update_t **)data; ++ ++ BUG_ON(!pte_none(*pte)); ++ ++ (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) << ++ PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK); ++ (*v)++; ++ ++ return 0; ++} ++ ++static int __direct_remap_pfn_range(struct mm_struct *mm, ++ unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid) ++{ ++ int rc; ++ unsigned long i, start_address; ++ mmu_update_t *u, *v, *w; ++ ++ u = v = w = (mmu_update_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); ++ if (u == NULL) ++ return -ENOMEM; ++ ++ start_address = address; ++ ++ flush_cache_all(); ++ ++ for (i = 0; i < size; i += PAGE_SIZE) { ++ if ((v - u) == (PAGE_SIZE / sizeof(mmu_update_t))) { ++ /* Flush a full batch after filling in the PTE ptrs. */ ++ rc = apply_to_page_range(mm, start_address, ++ address - start_address, ++ direct_remap_area_pte_fn, &w); ++ if (rc) ++ goto out; ++ rc = -EFAULT; ++ if (HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0) ++ goto out; ++ v = w = u; ++ start_address = address; ++ } ++ ++ /* ++ * Fill in the machine address: PTE ptr is done later by ++ * __direct_remap_area_pages(). ++ */ ++ v->val = pte_val_ma(pfn_pte_ma(mfn, prot)); ++ ++ mfn++; ++ address += PAGE_SIZE; ++ v++; ++ } ++ ++ if (v != u) { ++ /* Final batch. */ ++ rc = apply_to_page_range(mm, start_address, ++ address - start_address, ++ direct_remap_area_pte_fn, &w); ++ if (rc) ++ goto out; ++ rc = -EFAULT; ++ if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0)) ++ goto out; ++ } ++ ++ rc = 0; ++ ++ out: ++ flush_tlb_all(); ++ ++ free_page((unsigned long)u); ++ ++ return rc; ++} ++ ++int direct_remap_pfn_range(struct vm_area_struct *vma, ++ unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid) ++{ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return remap_pfn_range(vma, address, mfn, size, prot); ++ ++ if (domid == DOMID_SELF) ++ return -EINVAL; ++ ++ vma->vm_flags |= VM_IO | VM_RESERVED; ++ ++ vma->vm_mm->context.has_foreign_mappings = 1; ++ ++ return __direct_remap_pfn_range( ++ vma->vm_mm, address, mfn, size, prot, domid); ++} ++EXPORT_SYMBOL(direct_remap_pfn_range); ++ ++int direct_kernel_remap_pfn_range(unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid) ++{ ++ return __direct_remap_pfn_range( ++ &init_mm, address, mfn, size, prot, domid); ++} ++EXPORT_SYMBOL(direct_kernel_remap_pfn_range); ++ ++static int lookup_pte_fn( ++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) ++{ ++ uint64_t *ptep = (uint64_t *)data; ++ if (ptep) ++ *ptep = ((uint64_t)pfn_to_mfn(page_to_pfn(pmd_page)) << ++ PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK); ++ return 0; ++} ++ ++int create_lookup_pte_addr(struct mm_struct *mm, ++ unsigned long address, ++ uint64_t *ptep) ++{ ++ return apply_to_page_range(mm, address, PAGE_SIZE, ++ lookup_pte_fn, ptep); ++} ++ ++EXPORT_SYMBOL(create_lookup_pte_addr); ++ ++static int noop_fn( ++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) ++{ ++ return 0; ++} ++ ++int touch_pte_range(struct mm_struct *mm, ++ unsigned long address, ++ unsigned long size) ++{ ++ return apply_to_page_range(mm, address, size, noop_fn, NULL); ++} ++ ++EXPORT_SYMBOL(touch_pte_range); ++ ++/* ++ * Does @address reside within a non-highmem page that is local to this virtual ++ * machine (i.e., not an I/O page, nor a memory page belonging to another VM). ++ * See the comment that accompanies mfn_to_local_pfn() in page.h to understand ++ * why this works. ++ */ ++static inline int is_local_lowmem(unsigned long address) ++{ ++ extern unsigned long max_low_pfn; ++ return (mfn_to_local_pfn(address >> PAGE_SHIFT) < max_low_pfn); ++} ++ ++/* ++ * Generic mapping function (not visible outside): ++ */ ++ ++/* ++ * Remap an arbitrary physical address space into the kernel virtual ++ * address space. Needed when the kernel wants to access high addresses ++ * directly. ++ * ++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously ++ * have to convert them into an offset in a page-aligned mapping, but the ++ * caller shouldn't need to know that small detail. ++ */ ++void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) ++{ ++ void __iomem * addr; ++ struct vm_struct * area; ++ unsigned long offset, last_addr; ++ domid_t domid = DOMID_IO; ++ ++ /* Don't allow wraparound or zero size */ ++ last_addr = phys_addr + size - 1; ++ if (!size || last_addr < phys_addr) ++ return NULL; ++ ++ /* ++ * Don't remap the low PCI/ISA area, it's always mapped.. ++ */ ++ if (is_initial_xendomain() && ++ phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS) ++ return (void __iomem *) isa_bus_to_virt(phys_addr); ++ ++ /* ++ * Don't allow anybody to remap normal RAM that we're using.. ++ */ ++ if (is_local_lowmem(phys_addr)) { ++ char *t_addr, *t_end; ++ struct page *page; ++ ++ t_addr = bus_to_virt(phys_addr); ++ t_end = t_addr + (size - 1); ++ ++ for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) ++ if(!PageReserved(page)) ++ return NULL; ++ ++ domid = DOMID_SELF; ++ } ++ ++ /* ++ * Mappings have to be page-aligned ++ */ ++ offset = phys_addr & ~PAGE_MASK; ++ phys_addr &= PAGE_MASK; ++ size = PAGE_ALIGN(last_addr+1) - phys_addr; ++ ++ /* ++ * Ok, go for it.. ++ */ ++ area = get_vm_area(size, VM_IOREMAP | (flags << 20)); ++ if (!area) ++ return NULL; ++ area->phys_addr = phys_addr; ++ addr = (void __iomem *) area->addr; ++ flags |= _KERNPG_TABLE; ++ if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr, ++ phys_addr>>PAGE_SHIFT, ++ size, __pgprot(flags), domid)) { ++ vunmap((void __force *) addr); ++ return NULL; ++ } ++ return (void __iomem *) (offset + (char __iomem *)addr); ++} ++EXPORT_SYMBOL(__ioremap); ++ ++/** ++ * ioremap_nocache - map bus memory into CPU space ++ * @offset: bus address of the memory ++ * @size: size of the resource to map ++ * ++ * ioremap_nocache performs a platform specific sequence of operations to ++ * make bus memory CPU accessible via the readb/readw/readl/writeb/ ++ * writew/writel functions and the other mmio helpers. The returned ++ * address is not guaranteed to be usable directly as a virtual ++ * address. ++ * ++ * This version of ioremap ensures that the memory is marked uncachable ++ * on the CPU as well as honouring existing caching rules from things like ++ * the PCI bus. Note that there are other caches and buffers on many ++ * busses. In particular driver authors should read up on PCI writes ++ * ++ * It's useful if some control registers are in such an area and ++ * write combining or read caching is not desirable: ++ * ++ * Must be freed with iounmap. ++ */ ++ ++void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) ++{ ++ unsigned long last_addr; ++ void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD); ++ if (!p) ++ return p; ++ ++ /* Guaranteed to be > phys_addr, as per __ioremap() */ ++ last_addr = phys_addr + size - 1; ++ ++ if (is_local_lowmem(last_addr)) { ++ struct page *ppage = virt_to_page(bus_to_virt(phys_addr)); ++ unsigned long npages; ++ ++ phys_addr &= PAGE_MASK; ++ ++ /* This might overflow and become zero.. */ ++ last_addr = PAGE_ALIGN(last_addr); ++ ++ /* .. but that's ok, because modulo-2**n arithmetic will make ++ * the page-aligned "last - first" come out right. ++ */ ++ npages = (last_addr - phys_addr) >> PAGE_SHIFT; ++ ++ if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) { ++ iounmap(p); ++ p = NULL; ++ } ++ global_flush_tlb(); ++ } ++ ++ return p; ++} ++EXPORT_SYMBOL(ioremap_nocache); ++ ++/** ++ * iounmap - Free a IO remapping ++ * @addr: virtual address from ioremap_* ++ * ++ * Caller must ensure there is only one unmapping for the same pointer. ++ */ ++void iounmap(volatile void __iomem *addr) ++{ ++ struct vm_struct *p, *o; ++ ++ if ((void __force *)addr <= high_memory) ++ return; ++ ++ /* ++ * __ioremap special-cases the PCI/ISA range by not instantiating a ++ * vm_area and by simply returning an address into the kernel mapping ++ * of ISA space. So handle that here. ++ */ ++ if ((unsigned long) addr >= fix_to_virt(FIX_ISAMAP_BEGIN)) ++ return; ++ ++ addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr); ++ ++ /* Use the vm area unlocked, assuming the caller ++ ensures there isn't another iounmap for the same address ++ in parallel. Reuse of the virtual address is prevented by ++ leaving it in the global lists until we're done with it. ++ cpa takes care of the direct mappings. */ ++ read_lock(&vmlist_lock); ++ for (p = vmlist; p; p = p->next) { ++ if (p->addr == addr) ++ break; ++ } ++ read_unlock(&vmlist_lock); ++ ++ if (!p) { ++ printk("iounmap: bad address %p\n", addr); ++ dump_stack(); ++ return; ++ } ++ ++ /* Reset the direct mapping. Can block */ ++ if ((p->flags >> 20) && is_local_lowmem(p->phys_addr)) { ++ /* p->size includes the guard page, but cpa doesn't like that */ ++ change_page_attr(virt_to_page(bus_to_virt(p->phys_addr)), ++ (p->size - PAGE_SIZE) >> PAGE_SHIFT, ++ PAGE_KERNEL); ++ global_flush_tlb(); ++ } ++ ++ /* Finally remove it */ ++ o = remove_vm_area((void *)addr); ++ BUG_ON(p != o || o == NULL); ++ kfree(p); ++} ++EXPORT_SYMBOL(iounmap); ++ ++void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) ++{ ++ unsigned long offset, last_addr; ++ unsigned int nrpages; ++ enum fixed_addresses idx; ++ ++ /* Don't allow wraparound or zero size */ ++ last_addr = phys_addr + size - 1; ++ if (!size || last_addr < phys_addr) ++ return NULL; ++ ++ /* ++ * Don't remap the low PCI/ISA area, it's always mapped.. ++ */ ++ if (is_initial_xendomain() && ++ phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS) ++ return isa_bus_to_virt(phys_addr); ++ ++ /* ++ * Mappings have to be page-aligned ++ */ ++ offset = phys_addr & ~PAGE_MASK; ++ phys_addr &= PAGE_MASK; ++ size = PAGE_ALIGN(last_addr) - phys_addr; ++ ++ /* ++ * Mappings have to fit in the FIX_BTMAP area. ++ */ ++ nrpages = size >> PAGE_SHIFT; ++ if (nrpages > NR_FIX_BTMAPS) ++ return NULL; ++ ++ /* ++ * Ok, go for it.. ++ */ ++ idx = FIX_BTMAP_BEGIN; ++ while (nrpages > 0) { ++ set_fixmap(idx, phys_addr); ++ phys_addr += PAGE_SIZE; ++ --idx; ++ --nrpages; ++ } ++ return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); ++} ++ ++void __init bt_iounmap(void *addr, unsigned long size) ++{ ++ unsigned long virt_addr; ++ unsigned long offset; ++ unsigned int nrpages; ++ enum fixed_addresses idx; ++ ++ virt_addr = (unsigned long)addr; ++ if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) ++ return; ++ if (virt_addr >= fix_to_virt(FIX_ISAMAP_BEGIN)) ++ return; ++ offset = virt_addr & ~PAGE_MASK; ++ nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT; ++ ++ idx = FIX_BTMAP_BEGIN; ++ while (nrpages > 0) { ++ clear_fixmap(idx); ++ --idx; ++ --nrpages; ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/pageattr.c +--- a/arch/i386/mm/pageattr.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/mm/pageattr.c Wed Aug 08 16:25:28 2007 -0300 +@@ -90,7 +90,7 @@ static void set_pmd_pte(pte_t *kpte, uns + unsigned long flags; + + set_pte_atomic(kpte, pte); /* change init_mm */ +- if (PTRS_PER_PMD > 1) ++ if (HAVE_SHARED_KERNEL_PMD) + return; + + spin_lock_irqsave(&pgd_lock, flags); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/mm/pgtable-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/mm/pgtable-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,748 @@ ++/* ++ * linux/arch/i386/mm/pgtable.c ++ */ ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/swap.h> ++#include <linux/smp.h> ++#include <linux/highmem.h> ++#include <linux/slab.h> ++#include <linux/pagemap.h> ++#include <linux/spinlock.h> ++#include <linux/module.h> ++ ++#include <asm/system.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++#include <asm/fixmap.h> ++#include <asm/e820.h> ++#include <asm/tlb.h> ++#include <asm/tlbflush.h> ++#include <asm/io.h> ++#include <asm/mmu_context.h> ++ ++#include <xen/features.h> ++#include <asm/hypervisor.h> ++ ++static void pgd_test_and_unpin(pgd_t *pgd); ++ ++void show_mem(void) ++{ ++ int total = 0, reserved = 0; ++ int shared = 0, cached = 0; ++ int highmem = 0; ++ struct page *page; ++ pg_data_t *pgdat; ++ unsigned long i; ++ unsigned long flags; ++ ++ printk(KERN_INFO "Mem-info:\n"); ++ show_free_areas(); ++ printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); ++ for_each_online_pgdat(pgdat) { ++ pgdat_resize_lock(pgdat, &flags); ++ for (i = 0; i < pgdat->node_spanned_pages; ++i) { ++ page = pgdat_page_nr(pgdat, i); ++ total++; ++ if (PageHighMem(page)) ++ highmem++; ++ if (PageReserved(page)) ++ reserved++; ++ else if (PageSwapCache(page)) ++ cached++; ++ else if (page_count(page)) ++ shared += page_count(page) - 1; ++ } ++ pgdat_resize_unlock(pgdat, &flags); ++ } ++ printk(KERN_INFO "%d pages of RAM\n", total); ++ printk(KERN_INFO "%d pages of HIGHMEM\n", highmem); ++ printk(KERN_INFO "%d reserved pages\n", reserved); ++ printk(KERN_INFO "%d pages shared\n", shared); ++ printk(KERN_INFO "%d pages swap cached\n", cached); ++ ++ printk(KERN_INFO "%lu pages dirty\n", global_page_state(NR_FILE_DIRTY)); ++ printk(KERN_INFO "%lu pages writeback\n", ++ global_page_state(NR_WRITEBACK)); ++ printk(KERN_INFO "%lu pages mapped\n", global_page_state(NR_FILE_MAPPED)); ++ printk(KERN_INFO "%lu pages slab\n", ++ global_page_state(NR_SLAB_RECLAIMABLE) + ++ global_page_state(NR_SLAB_UNRECLAIMABLE)); ++ printk(KERN_INFO "%lu pages pagetables\n", ++ global_page_state(NR_PAGETABLE)); ++} ++ ++/* ++ * Associate a virtual page frame with a given physical page frame ++ * and protection flags for that frame. ++ */ ++static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ if (pgd_none(*pgd)) { ++ BUG(); ++ return; ++ } ++ pud = pud_offset(pgd, vaddr); ++ if (pud_none(*pud)) { ++ BUG(); ++ return; ++ } ++ pmd = pmd_offset(pud, vaddr); ++ if (pmd_none(*pmd)) { ++ BUG(); ++ return; ++ } ++ pte = pte_offset_kernel(pmd, vaddr); ++ if (pgprot_val(flags)) ++ /* <pfn,flags> stored as-is, to permit clearing entries */ ++ set_pte(pte, pfn_pte(pfn, flags)); ++ else ++ pte_clear(&init_mm, vaddr, pte); ++ ++ /* ++ * It's enough to flush this one mapping. ++ * (PGE mappings get flushed as well) ++ */ ++ __flush_tlb_one(vaddr); ++} ++ ++/* ++ * Associate a virtual page frame with a given physical page frame ++ * and protection flags for that frame. ++ */ ++static void set_pte_pfn_ma(unsigned long vaddr, unsigned long pfn, ++ pgprot_t flags) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ if (pgd_none(*pgd)) { ++ BUG(); ++ return; ++ } ++ pud = pud_offset(pgd, vaddr); ++ if (pud_none(*pud)) { ++ BUG(); ++ return; ++ } ++ pmd = pmd_offset(pud, vaddr); ++ if (pmd_none(*pmd)) { ++ BUG(); ++ return; ++ } ++ pte = pte_offset_kernel(pmd, vaddr); ++ if (pgprot_val(flags)) ++ /* <pfn,flags> stored as-is, to permit clearing entries */ ++ set_pte(pte, pfn_pte_ma(pfn, flags)); ++ else ++ pte_clear(&init_mm, vaddr, pte); ++ ++ /* ++ * It's enough to flush this one mapping. ++ * (PGE mappings get flushed as well) ++ */ ++ __flush_tlb_one(vaddr); ++} ++ ++/* ++ * Associate a large virtual page frame with a given physical page frame ++ * and protection flags for that frame. pfn is for the base of the page, ++ * vaddr is what the page gets mapped to - both must be properly aligned. ++ * The pmd must already be instantiated. Assumes PAE mode. ++ */ ++void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ ++ if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */ ++ printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n"); ++ return; /* BUG(); */ ++ } ++ if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */ ++ printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n"); ++ return; /* BUG(); */ ++ } ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ if (pgd_none(*pgd)) { ++ printk(KERN_WARNING "set_pmd_pfn: pgd_none\n"); ++ return; /* BUG(); */ ++ } ++ pud = pud_offset(pgd, vaddr); ++ pmd = pmd_offset(pud, vaddr); ++ set_pmd(pmd, pfn_pmd(pfn, flags)); ++ /* ++ * It's enough to flush this one mapping. ++ * (PGE mappings get flushed as well) ++ */ ++ __flush_tlb_one(vaddr); ++} ++ ++static int fixmaps; ++unsigned long hypervisor_virt_start = HYPERVISOR_VIRT_START; ++#ifndef CONFIG_COMPAT_VDSO ++unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE); ++EXPORT_SYMBOL(__FIXADDR_TOP); ++#endif ++ ++void __init set_fixaddr_top(void) ++{ ++ BUG_ON(fixmaps > 0); ++ __FIXADDR_TOP = hypervisor_virt_start - 2 * PAGE_SIZE; ++} ++ ++void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags) ++{ ++ unsigned long address = __fix_to_virt(idx); ++ ++ if (idx >= __end_of_fixed_addresses) { ++ BUG(); ++ return; ++ } ++ switch (idx) { ++ case FIX_WP_TEST: ++#ifdef CONFIG_X86_F00F_BUG ++ case FIX_F00F_IDT: ++#endif ++ case FIX_VDSO: ++ set_pte_pfn(address, phys >> PAGE_SHIFT, flags); ++ break; ++ default: ++ set_pte_pfn_ma(address, phys >> PAGE_SHIFT, flags); ++ break; ++ } ++ fixmaps++; ++} ++ ++/** ++ * reserve_top_address - reserves a hole in the top of kernel address space ++ * @reserve - size of hole to reserve ++ * ++ * Can be used to relocate the fixmap area and poke a hole in the top ++ * of kernel address space to make room for a hypervisor. ++ */ ++void reserve_top_address(unsigned long reserve) ++{ ++ BUG_ON(fixmaps > 0); ++#ifdef CONFIG_COMPAT_VDSO ++ BUG_ON(reserve != 0); ++#else ++ __FIXADDR_TOP = -reserve - PAGE_SIZE; ++ __VMALLOC_RESERVE += reserve; ++#endif ++} ++ ++pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) ++{ ++ pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); ++ if (pte) ++ make_lowmem_page_readonly(pte, XENFEAT_writable_page_tables); ++ return pte; ++} ++ ++struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) ++{ ++ struct page *pte; ++ ++#ifdef CONFIG_HIGHPTE ++ pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0); ++#else ++ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); ++#endif ++ if (pte) { ++ SetPageForeign(pte, pte_free); ++ init_page_count(pte); ++ } ++ return pte; ++} ++ ++void pte_free(struct page *pte) ++{ ++ unsigned long pfn = page_to_pfn(pte); ++ ++ if (!PageHighMem(pte)) { ++ unsigned long va = (unsigned long)__va(pfn << PAGE_SHIFT); ++ ++ if (!pte_write(*virt_to_ptep(va))) ++ if (HYPERVISOR_update_va_mapping( ++ va, pfn_pte(pfn, PAGE_KERNEL), 0)) ++ BUG(); ++ } else ++ clear_bit(PG_pinned, &pte->flags); ++ ++ ClearPageForeign(pte); ++ init_page_count(pte); ++ ++ __free_page(pte); ++} ++ ++void pmd_ctor(void *pmd, struct kmem_cache *cache, unsigned long flags) ++{ ++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); ++} ++ ++/* ++ * List of all pgd's needed for non-PAE so it can invalidate entries ++ * in both cached and uncached pgd's; not needed for PAE since the ++ * kernel pmd is shared. If PAE were not to share the pmd a similar ++ * tactic would be needed. This is essentially codepath-based locking ++ * against pageattr.c; it is the unique case in which a valid change ++ * of kernel pagetables can't be lazily synchronized by vmalloc faults. ++ * vmalloc faults work because attached pagetables are never freed. ++ * The locking scheme was chosen on the basis of manfred's ++ * recommendations and having no core impact whatsoever. ++ * -- wli ++ */ ++DEFINE_SPINLOCK(pgd_lock); ++struct page *pgd_list; ++ ++static inline void pgd_list_add(pgd_t *pgd) ++{ ++ struct page *page = virt_to_page(pgd); ++ page->index = (unsigned long)pgd_list; ++ if (pgd_list) ++ set_page_private(pgd_list, (unsigned long)&page->index); ++ pgd_list = page; ++ set_page_private(page, (unsigned long)&pgd_list); ++} ++ ++static inline void pgd_list_del(pgd_t *pgd) ++{ ++ struct page *next, **pprev, *page = virt_to_page(pgd); ++ next = (struct page *)page->index; ++ pprev = (struct page **)page_private(page); ++ *pprev = next; ++ if (next) ++ set_page_private(next, (unsigned long)pprev); ++} ++ ++void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) ++{ ++ unsigned long flags; ++ ++ if (PTRS_PER_PMD > 1) { ++ if (HAVE_SHARED_KERNEL_PMD) ++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, ++ swapper_pg_dir + USER_PTRS_PER_PGD, ++ KERNEL_PGD_PTRS); ++ } else { ++ spin_lock_irqsave(&pgd_lock, flags); ++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, ++ swapper_pg_dir + USER_PTRS_PER_PGD, ++ KERNEL_PGD_PTRS); ++ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); ++ pgd_list_add(pgd); ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ } ++} ++ ++/* never called when PTRS_PER_PMD > 1 */ ++void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) ++{ ++ unsigned long flags; /* can be called from interrupt context */ ++ ++ spin_lock_irqsave(&pgd_lock, flags); ++ pgd_list_del(pgd); ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ ++ pgd_test_and_unpin(pgd); ++} ++ ++pgd_t *pgd_alloc(struct mm_struct *mm) ++{ ++ int i; ++ pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL); ++ pmd_t **pmd; ++ unsigned long flags; ++ ++ pgd_test_and_unpin(pgd); ++ ++ if (PTRS_PER_PMD == 1 || !pgd) ++ return pgd; ++ ++ if (HAVE_SHARED_KERNEL_PMD) { ++ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { ++ pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); ++ if (!pmd) ++ goto out_oom; ++ set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); ++ } ++ return pgd; ++ } ++ ++ /* ++ * We can race save/restore (if we sleep during a GFP_KERNEL memory ++ * allocation). We therefore store virtual addresses of pmds as they ++ * do not change across save/restore, and poke the machine addresses ++ * into the pgdir under the pgd_lock. ++ */ ++ pmd = kmalloc(PTRS_PER_PGD * sizeof(pmd_t *), GFP_KERNEL); ++ if (!pmd) { ++ kmem_cache_free(pgd_cache, pgd); ++ return NULL; ++ } ++ ++ /* Allocate pmds, remember virtual addresses. */ ++ for (i = 0; i < PTRS_PER_PGD; ++i) { ++ pmd[i] = kmem_cache_alloc(pmd_cache, GFP_KERNEL); ++ if (!pmd[i]) ++ goto out_oom; ++ } ++ ++ spin_lock_irqsave(&pgd_lock, flags); ++ ++ /* Protect against save/restore: move below 4GB under pgd_lock. */ ++ if (!xen_feature(XENFEAT_pae_pgdir_above_4gb)) { ++ int rc = xen_create_contiguous_region( ++ (unsigned long)pgd, 0, 32); ++ if (rc) { ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ goto out_oom; ++ } ++ } ++ ++ /* Copy kernel pmd contents and write-protect the new pmds. */ ++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) { ++ unsigned long v = (unsigned long)i << PGDIR_SHIFT; ++ pgd_t *kpgd = pgd_offset_k(v); ++ pud_t *kpud = pud_offset(kpgd, v); ++ pmd_t *kpmd = pmd_offset(kpud, v); ++ memcpy(pmd[i], kpmd, PAGE_SIZE); ++ make_lowmem_page_readonly( ++ pmd[i], XENFEAT_writable_page_tables); ++ } ++ ++ /* It is safe to poke machine addresses of pmds under the pmd_lock. */ ++ for (i = 0; i < PTRS_PER_PGD; i++) ++ set_pgd(&pgd[i], __pgd(1 + __pa(pmd[i]))); ++ ++ /* Ensure this pgd gets picked up and pinned on save/restore. */ ++ pgd_list_add(pgd); ++ ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ ++ kfree(pmd); ++ ++ return pgd; ++ ++out_oom: ++ if (HAVE_SHARED_KERNEL_PMD) { ++ for (i--; i >= 0; i--) ++ kmem_cache_free(pmd_cache, ++ (void *)__va(pgd_val(pgd[i])-1)); ++ } else { ++ for (i--; i >= 0; i--) ++ kmem_cache_free(pmd_cache, pmd[i]); ++ kfree(pmd); ++ } ++ kmem_cache_free(pgd_cache, pgd); ++ return NULL; ++} ++ ++void pgd_free(pgd_t *pgd) ++{ ++ int i; ++ ++ /* ++ * After this the pgd should not be pinned for the duration of this ++ * function's execution. We should never sleep and thus never race: ++ * 1. User pmds will not become write-protected under our feet due ++ * to a concurrent mm_pin_all(). ++ * 2. The machine addresses in PGD entries will not become invalid ++ * due to a concurrent save/restore. ++ */ ++ pgd_test_and_unpin(pgd); ++ ++ /* in the PAE case user pgd entries are overwritten before usage */ ++ if (PTRS_PER_PMD > 1) { ++ for (i = 0; i < USER_PTRS_PER_PGD; ++i) { ++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1); ++ kmem_cache_free(pmd_cache, pmd); ++ } ++ ++ if (!HAVE_SHARED_KERNEL_PMD) { ++ unsigned long flags; ++ spin_lock_irqsave(&pgd_lock, flags); ++ pgd_list_del(pgd); ++ spin_unlock_irqrestore(&pgd_lock, flags); ++ ++ for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) { ++ pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1); ++ make_lowmem_page_writable( ++ pmd, XENFEAT_writable_page_tables); ++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); ++ kmem_cache_free(pmd_cache, pmd); ++ } ++ ++ if (!xen_feature(XENFEAT_pae_pgdir_above_4gb)) ++ xen_destroy_contiguous_region( ++ (unsigned long)pgd, 0); ++ } ++ } ++ ++ /* in the non-PAE case, free_pgtables() clears user pgd entries */ ++ kmem_cache_free(pgd_cache, pgd); ++} ++ ++void make_lowmem_page_readonly(void *va, unsigned int feature) ++{ ++ pte_t *pte; ++ int rc; ++ ++ if (xen_feature(feature)) ++ return; ++ ++ pte = virt_to_ptep(va); ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)va, pte_wrprotect(*pte), 0); ++ BUG_ON(rc); ++} ++ ++void make_lowmem_page_writable(void *va, unsigned int feature) ++{ ++ pte_t *pte; ++ int rc; ++ ++ if (xen_feature(feature)) ++ return; ++ ++ pte = virt_to_ptep(va); ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)va, pte_mkwrite(*pte), 0); ++ BUG_ON(rc); ++} ++ ++void make_page_readonly(void *va, unsigned int feature) ++{ ++ pte_t *pte; ++ int rc; ++ ++ if (xen_feature(feature)) ++ return; ++ ++ pte = virt_to_ptep(va); ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)va, pte_wrprotect(*pte), 0); ++ if (rc) /* fallback? */ ++ xen_l1_entry_update(pte, pte_wrprotect(*pte)); ++ if ((unsigned long)va >= (unsigned long)high_memory) { ++ unsigned long pfn = pte_pfn(*pte); ++#ifdef CONFIG_HIGHMEM ++ if (pfn >= highstart_pfn) ++ kmap_flush_unused(); /* flush stale writable kmaps */ ++ else ++#endif ++ make_lowmem_page_readonly( ++ phys_to_virt(pfn << PAGE_SHIFT), feature); ++ } ++} ++ ++void make_page_writable(void *va, unsigned int feature) ++{ ++ pte_t *pte; ++ int rc; ++ ++ if (xen_feature(feature)) ++ return; ++ ++ pte = virt_to_ptep(va); ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)va, pte_mkwrite(*pte), 0); ++ if (rc) /* fallback? */ ++ xen_l1_entry_update(pte, pte_mkwrite(*pte)); ++ if ((unsigned long)va >= (unsigned long)high_memory) { ++ unsigned long pfn = pte_pfn(*pte); ++#ifdef CONFIG_HIGHMEM ++ if (pfn < highstart_pfn) ++#endif ++ make_lowmem_page_writable( ++ phys_to_virt(pfn << PAGE_SHIFT), feature); ++ } ++} ++ ++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature) ++{ ++ if (xen_feature(feature)) ++ return; ++ ++ while (nr-- != 0) { ++ make_page_readonly(va, feature); ++ va = (void *)((unsigned long)va + PAGE_SIZE); ++ } ++} ++ ++void make_pages_writable(void *va, unsigned int nr, unsigned int feature) ++{ ++ if (xen_feature(feature)) ++ return; ++ ++ while (nr-- != 0) { ++ make_page_writable(va, feature); ++ va = (void *)((unsigned long)va + PAGE_SIZE); ++ } ++} ++ ++static inline void pgd_walk_set_prot(struct page *page, pgprot_t flags) ++{ ++ unsigned long pfn = page_to_pfn(page); ++ int rc; ++ ++ if (PageHighMem(page)) { ++ if (pgprot_val(flags) & _PAGE_RW) ++ clear_bit(PG_pinned, &page->flags); ++ else ++ set_bit(PG_pinned, &page->flags); ++ } else { ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, flags), 0); ++ if (rc) ++ BUG(); ++ } ++} ++ ++static void pgd_walk(pgd_t *pgd_base, pgprot_t flags) ++{ ++ pgd_t *pgd = pgd_base; ++ pud_t *pud; ++ pmd_t *pmd; ++ int g, u, m, rc; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return; ++ ++ for (g = 0; g < USER_PTRS_PER_PGD; g++, pgd++) { ++ if (pgd_none(*pgd)) ++ continue; ++ pud = pud_offset(pgd, 0); ++ if (PTRS_PER_PUD > 1) /* not folded */ ++ pgd_walk_set_prot(virt_to_page(pud),flags); ++ for (u = 0; u < PTRS_PER_PUD; u++, pud++) { ++ if (pud_none(*pud)) ++ continue; ++ pmd = pmd_offset(pud, 0); ++ if (PTRS_PER_PMD > 1) /* not folded */ ++ pgd_walk_set_prot(virt_to_page(pmd),flags); ++ for (m = 0; m < PTRS_PER_PMD; m++, pmd++) { ++ if (pmd_none(*pmd)) ++ continue; ++ pgd_walk_set_prot(pmd_page(*pmd),flags); ++ } ++ } ++ } ++ ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)pgd_base, ++ pfn_pte(virt_to_phys(pgd_base)>>PAGE_SHIFT, flags), ++ UVMF_TLB_FLUSH); ++ if (rc) ++ BUG(); ++} ++ ++static void __pgd_pin(pgd_t *pgd) ++{ ++ pgd_walk(pgd, PAGE_KERNEL_RO); ++ kmap_flush_unused(); ++ xen_pgd_pin(__pa(pgd)); ++ set_bit(PG_pinned, &virt_to_page(pgd)->flags); ++} ++ ++static void __pgd_unpin(pgd_t *pgd) ++{ ++ xen_pgd_unpin(__pa(pgd)); ++ pgd_walk(pgd, PAGE_KERNEL); ++ clear_bit(PG_pinned, &virt_to_page(pgd)->flags); ++} ++ ++static void pgd_test_and_unpin(pgd_t *pgd) ++{ ++ if (test_bit(PG_pinned, &virt_to_page(pgd)->flags)) ++ __pgd_unpin(pgd); ++} ++ ++void mm_pin(struct mm_struct *mm) ++{ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ spin_lock(&mm->page_table_lock); ++ __pgd_pin(mm->pgd); ++ spin_unlock(&mm->page_table_lock); ++} ++ ++void mm_unpin(struct mm_struct *mm) ++{ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ spin_lock(&mm->page_table_lock); ++ __pgd_unpin(mm->pgd); ++ spin_unlock(&mm->page_table_lock); ++} ++ ++void mm_pin_all(void) ++{ ++ struct page *page; ++ unsigned long flags; ++ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ ++ /* ++ * Allow uninterrupted access to the pgd_list. Also protects ++ * __pgd_pin() by disabling preemption. ++ * All other CPUs must be at a safe point (e.g., in stop_machine ++ * or offlined entirely). ++ */ ++ spin_lock_irqsave(&pgd_lock, flags); ++ for (page = pgd_list; page; page = (struct page *)page->index) { ++ if (!test_bit(PG_pinned, &page->flags)) ++ __pgd_pin((pgd_t *)page_address(page)); ++ } ++ spin_unlock_irqrestore(&pgd_lock, flags); ++} ++ ++void _arch_dup_mmap(struct mm_struct *mm) ++{ ++ if (!test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags)) ++ mm_pin(mm); ++} ++ ++void _arch_exit_mmap(struct mm_struct *mm) ++{ ++ struct task_struct *tsk = current; ++ ++ task_lock(tsk); ++ ++ /* ++ * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() ++ * *much* faster this way, as no tlb flushes means bigger wrpt batches. ++ */ ++ if (tsk->active_mm == mm) { ++ tsk->active_mm = &init_mm; ++ atomic_inc(&init_mm.mm_count); ++ ++ switch_mm(mm, &init_mm, tsk); ++ ++ atomic_dec(&mm->mm_count); ++ BUG_ON(atomic_read(&mm->mm_count) == 0); ++ } ++ ++ task_unlock(tsk); ++ ++ if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) && ++ (atomic_read(&mm->mm_count) == 1) && ++ !mm->context.has_foreign_mappings) ++ mm_unpin(mm); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/oprofile/Makefile +--- a/arch/i386/oprofile/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/oprofile/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -6,7 +6,14 @@ DRIVER_OBJS = $(addprefix ../../../drive + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + ++ifdef CONFIG_XEN ++XENOPROF_COMMON_OBJS = $(addprefix ../../../drivers/xen/xenoprof/, \ ++ xenoprofile.o) ++oprofile-y := $(DRIVER_OBJS) \ ++ $(XENOPROF_COMMON_OBJS) xenoprof.o ++else + oprofile-y := $(DRIVER_OBJS) init.o backtrace.o + oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ + op_model_ppro.o op_model_p4.o + oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/oprofile/xenoprof.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/oprofile/xenoprof.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,179 @@ ++/** ++ * @file xenoprof.c ++ * ++ * @remark Copyright 2002 OProfile authors ++ * @remark Read the file COPYING ++ * ++ * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon and Jose Renato Santos for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. ++ * ++ * x86-specific part ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ */ ++ ++#include <linux/init.h> ++#include <linux/oprofile.h> ++#include <linux/sched.h> ++#include <asm/pgtable.h> ++ ++#include <xen/driver_util.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/xenoprof.h> ++#include <xen/xenoprof.h> ++#include "op_counter.h" ++ ++static unsigned int num_events = 0; ++ ++void __init xenoprof_arch_init_counter(struct xenoprof_init *init) ++{ ++ num_events = init->num_events; ++ /* just in case - make sure we do not overflow event list ++ (i.e. counter_config list) */ ++ if (num_events > OP_MAX_COUNTER) { ++ num_events = OP_MAX_COUNTER; ++ init->num_events = num_events; ++ } ++} ++ ++void xenoprof_arch_counter(void) ++{ ++ int i; ++ struct xenoprof_counter counter; ++ ++ for (i=0; i<num_events; i++) { ++ counter.ind = i; ++ counter.count = (uint64_t)counter_config[i].count; ++ counter.enabled = (uint32_t)counter_config[i].enabled; ++ counter.event = (uint32_t)counter_config[i].event; ++ counter.kernel = (uint32_t)counter_config[i].kernel; ++ counter.user = (uint32_t)counter_config[i].user; ++ counter.unit_mask = (uint64_t)counter_config[i].unit_mask; ++ HYPERVISOR_xenoprof_op(XENOPROF_counter, ++ &counter); ++ } ++} ++ ++void xenoprof_arch_start(void) ++{ ++ /* nothing */ ++} ++ ++void xenoprof_arch_stop(void) ++{ ++ /* nothing */ ++} ++ ++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer * sbuf) ++{ ++ if (sbuf->buffer) { ++ vunmap(sbuf->buffer); ++ sbuf->buffer = NULL; ++ } ++} ++ ++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer * get_buffer, ++ struct xenoprof_shared_buffer * sbuf) ++{ ++ int npages, ret; ++ struct vm_struct *area; ++ ++ sbuf->buffer = NULL; ++ if ( (ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, get_buffer)) ) ++ return ret; ++ ++ npages = (get_buffer->bufsize * get_buffer->nbuf - 1) / PAGE_SIZE + 1; ++ ++ area = alloc_vm_area(npages * PAGE_SIZE); ++ if (area == NULL) ++ return -ENOMEM; ++ ++ if ( (ret = direct_kernel_remap_pfn_range( ++ (unsigned long)area->addr, ++ get_buffer->buf_gmaddr >> PAGE_SHIFT, ++ npages * PAGE_SIZE, __pgprot(_KERNPG_TABLE), ++ DOMID_SELF)) ) { ++ vunmap(area->addr); ++ return ret; ++ } ++ ++ sbuf->buffer = area->addr; ++ return ret; ++} ++ ++int xenoprof_arch_set_passive(struct xenoprof_passive * pdomain, ++ struct xenoprof_shared_buffer * sbuf) ++{ ++ int ret; ++ int npages; ++ struct vm_struct *area; ++ pgprot_t prot = __pgprot(_KERNPG_TABLE); ++ ++ sbuf->buffer = NULL; ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive, pdomain); ++ if (ret) ++ goto out; ++ ++ npages = (pdomain->bufsize * pdomain->nbuf - 1) / PAGE_SIZE + 1; ++ ++ area = alloc_vm_area(npages * PAGE_SIZE); ++ if (area == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = direct_kernel_remap_pfn_range( ++ (unsigned long)area->addr, ++ pdomain->buf_gmaddr >> PAGE_SHIFT, ++ npages * PAGE_SIZE, prot, DOMID_SELF); ++ if (ret) { ++ vunmap(area->addr); ++ goto out; ++ } ++ sbuf->buffer = area->addr; ++ ++out: ++ return ret; ++} ++ ++struct op_counter_config counter_config[OP_MAX_COUNTER]; ++ ++int xenoprof_create_files(struct super_block * sb, struct dentry * root) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num_events; ++i) { ++ struct dentry * dir; ++ char buf[2]; ++ ++ snprintf(buf, 2, "%d", i); ++ dir = oprofilefs_mkdir(sb, root, buf); ++ oprofilefs_create_ulong(sb, dir, "enabled", ++ &counter_config[i].enabled); ++ oprofilefs_create_ulong(sb, dir, "event", ++ &counter_config[i].event); ++ oprofilefs_create_ulong(sb, dir, "count", ++ &counter_config[i].count); ++ oprofilefs_create_ulong(sb, dir, "unit_mask", ++ &counter_config[i].unit_mask); ++ oprofilefs_create_ulong(sb, dir, "kernel", ++ &counter_config[i].kernel); ++ oprofilefs_create_ulong(sb, dir, "user", ++ &counter_config[i].user); ++ } ++ ++ return 0; ++} ++ ++int __init oprofile_arch_init(struct oprofile_operations * ops) ++{ ++ return xenoprofile_init(ops); ++} ++ ++void oprofile_arch_exit(void) ++{ ++ xenoprofile_exit(); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/pci/Makefile +--- a/arch/i386/pci/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/pci/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -3,6 +3,10 @@ obj-$(CONFIG_PCI_BIOS) += pcbios.o + obj-$(CONFIG_PCI_BIOS) += pcbios.o + obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o + obj-$(CONFIG_PCI_DIRECT) += direct.o ++ ++# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only ++# take over if direct access to the PCI bus is unavailable ++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o + + pci-y := fixup.o + pci-$(CONFIG_ACPI) += acpi.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/pci/irq.c +--- a/arch/i386/pci/irq.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/pci/irq.c Wed Aug 08 16:25:28 2007 -0300 +@@ -94,13 +94,25 @@ static struct irq_routing_table * __init + u8 *addr; + struct irq_routing_table *rt; + ++#ifdef CONFIG_XEN ++ if (!is_initial_xendomain()) ++ return NULL; ++#endif + if (pirq_table_addr) { ++#ifdef CONFIG_XEN ++ rt = pirq_check_routing_table((u8 *) isa_bus_to_virt(pirq_table_addr)); ++#else + rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); ++#endif + if (rt) + return rt; + printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); + } ++#ifdef CONFIG_XEN ++ for(addr = (u8 *) isa_bus_to_virt(0xf0000); addr < (u8 *) isa_bus_to_virt(0x100000); addr += 16) { ++#else + for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { ++#endif + rt = pirq_check_routing_table(addr); + if (rt) + return rt; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/pci/pcifront.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/i386/pci/pcifront.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,55 @@ ++/* ++ * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core ++ * to support the Xen PCI Frontend's operation ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <asm/acpi.h> ++#include "pci.h" ++ ++static int pcifront_enable_irq(struct pci_dev *dev) ++{ ++ u8 irq; ++ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); ++ dev->irq = irq; ++ ++ return 0; ++} ++ ++extern u8 pci_cache_line_size; ++ ++static int __init pcifront_x86_stub_init(void) ++{ ++ struct cpuinfo_x86 *c = &boot_cpu_data; ++ ++ /* Only install our method if we haven't found real hardware already */ ++ if (raw_pci_ops) ++ return 0; ++ ++ printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n"); ++ ++ /* Copied from arch/i386/pci/common.c */ ++ pci_cache_line_size = 32 >> 2; ++ if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) ++ pci_cache_line_size = 64 >> 2; /* K7 & K8 */ ++ else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) ++ pci_cache_line_size = 128 >> 2; /* P4 */ ++ ++ /* On x86, we need to disable the normal IRQ routing table and ++ * just ask the backend ++ */ ++ pcibios_enable_irq = pcifront_enable_irq; ++ pcibios_disable_irq = NULL; ++ ++#ifdef CONFIG_ACPI ++ /* Keep ACPI out of the picture */ ++ acpi_noirq = 1; ++#endif ++ ++ return 0; ++} ++ ++arch_initcall(pcifront_x86_stub_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/i386/power/Makefile +--- a/arch/i386/power/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/i386/power/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -1,2 +1,4 @@ obj-$(CONFIG_PM) += cpu.o +-obj-$(CONFIG_PM) += cpu.o ++obj-$(CONFIG_PM_LEGACY) += cpu.o ++obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o ++obj-$(CONFIG_ACPI_SLEEP) += cpu.o + obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/Kconfig +--- a/arch/ia64/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -66,6 +66,34 @@ config GENERIC_IOMAP + config GENERIC_IOMAP + bool + default y ++ ++config XEN ++ bool "Xen hypervisor support" ++ default y ++ help ++ Enable Xen hypervisor support. Resulting kernel runs ++ both as a guest OS on Xen and natively on hardware. ++ ++config XEN_IA64_VDSO_PARAVIRT ++ bool ++ depends on XEN && !ITANIUM ++ default y ++ help ++ vDSO paravirtualization ++ ++config XEN_IA64_EXPOSE_P2M ++ bool "Xen/IA64 exposure p2m table" ++ depends on XEN ++ default y ++ help ++ expose p2m from xen ++ ++config XEN_IA64_EXPOSE_P2M_USE_DTR ++ bool "Xen/IA64 map p2m table with dtr" ++ depends on XEN_IA64_EXPOSE_P2M ++ default y ++ help ++ use dtr to map the exposed p2m table + + config SCHED_NO_NO_OMIT_FRAME_POINTER + bool +@@ -500,6 +528,21 @@ config PCI_DOMAINS + bool + default PCI + ++config XEN_PCIDEV_FRONTEND ++ bool "Xen PCI Frontend" ++ depends on PCI && XEN ++ default y ++ help ++ The PCI device frontend driver allows the kernel to import arbitrary ++ PCI devices from a PCI backend to support PCI driver domains. ++ ++config XEN_PCIDEV_FE_DEBUG ++ bool "Xen PCI Frontend Debugging" ++ depends on XEN_PCIDEV_FRONTEND ++ default n ++ help ++ Enables some debug statements within the PCI Frontend. ++ + source "drivers/pci/pcie/Kconfig" + + source "drivers/pci/Kconfig" +@@ -572,3 +615,13 @@ source "security/Kconfig" + source "security/Kconfig" + + source "crypto/Kconfig" ++ ++# ++# override default values of drivers/xen/Kconfig ++# ++if XEN ++config XEN_SMPBOOT ++ default n ++endif ++ ++source "drivers/xen/Kconfig" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/Makefile +--- a/arch/ia64/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -45,6 +45,12 @@ endif + endif + + CFLAGS += $(cflags-y) ++ ++cppflags-$(CONFIG_XEN) += \ ++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) ++ ++CPPFLAGS += $(cppflags-y) ++ + head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o + + libs-y += arch/ia64/lib/ +@@ -55,9 +61,15 @@ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/ + core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ + core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ + core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ ++core-$(CONFIG_XEN) += arch/ia64/xen/ + + drivers-$(CONFIG_PCI) += arch/ia64/pci/ ++ifneq ($(CONFIG_XEN),y) + drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ ++endif ++ifneq ($(CONFIG_IA64_GENERIC),y) ++drivers-$(CONFIG_XEN) += arch/ia64/hp/sim/ ++endif + drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ + drivers-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ + drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/ +@@ -87,8 +99,8 @@ boot: lib/lib.a vmlinux + boot: lib/lib.a vmlinux + $(Q)$(MAKE) $(build)=$(boot) $@ + +-install: vmlinux.gz +- sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)" ++install: ++ -yes | sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)" + + define archhelp + echo '* compressed - Build compressed kernel image' +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/dig/setup.c +--- a/arch/ia64/dig/setup.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/dig/setup.c Wed Aug 08 16:25:28 2007 -0300 +@@ -23,6 +23,8 @@ + #include <asm/io.h> + #include <asm/machvec.h> + #include <asm/system.h> ++ ++#include <xen/xencons.h> + + void __init + dig_setup (char **cmdline_p) +@@ -67,4 +69,19 @@ dig_setup (char **cmdline_p) + screen_info.orig_video_mode = 3; /* XXX fake */ + screen_info.orig_video_isVGA = 1; /* XXX fake */ + screen_info.orig_video_ega_bx = 3; /* XXX fake */ ++#ifdef CONFIG_XEN ++ if (!is_running_on_xen() || !is_initial_xendomain()) ++ return; ++ ++ if (xen_start_info->console.dom0.info_size >= ++ sizeof(struct dom0_vga_console_info)) { ++ const struct dom0_vga_console_info *info = ++ (struct dom0_vga_console_info *)( ++ (char *)xen_start_info + ++ xen_start_info->console.dom0.info_off); ++ dom0_init_screen_info(info); ++ } ++ xen_start_info->console.domU.mfn = 0; ++ xen_start_info->console.domU.evtchn = 0; ++#endif + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/hp/sim/Makefile +--- a/arch/ia64/hp/sim/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ /dev/null Thu Jan 01 00:00:00 1970 +0000 +@@ -1,16 +0,0 @@ +-# +-# ia64/platform/hp/sim/Makefile +-# +-# Copyright (C) 2002 Hewlett-Packard Co. +-# David Mosberger-Tang <davidm@hpl.hp.com> +-# Copyright (C) 1999 Silicon Graphics, Inc. +-# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +-# +- +-obj-y := hpsim_irq.o hpsim_setup.o hpsim.o +-obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o +- +-obj-$(CONFIG_HP_SIMETH) += simeth.o +-obj-$(CONFIG_HP_SIMSERIAL) += simserial.o +-obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o +-obj-$(CONFIG_HP_SIMSCSI) += simscsi.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/asm-offsets.c +--- a/arch/ia64/kernel/asm-offsets.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/asm-offsets.c Wed Aug 08 16:25:28 2007 -0300 +@@ -268,4 +268,29 @@ void foo(void) + DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64); + DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32); + DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); ++ ++#ifdef CONFIG_XEN ++ BLANK(); ++ ++#define DEFINE_MAPPED_REG_OFS(sym, field) \ ++ DEFINE(sym, (XMAPPEDREGS_OFS + offsetof(mapped_regs_t, field))) ++ ++ DEFINE_MAPPED_REG_OFS(XSI_PSR_I_ADDR_OFS, interrupt_mask_addr); ++ DEFINE_MAPPED_REG_OFS(XSI_IPSR_OFS, ipsr); ++ DEFINE_MAPPED_REG_OFS(XSI_IIP_OFS, iip); ++ DEFINE_MAPPED_REG_OFS(XSI_IFS_OFS, ifs); ++ DEFINE_MAPPED_REG_OFS(XSI_PRECOVER_IFS_OFS, precover_ifs); ++ DEFINE_MAPPED_REG_OFS(XSI_ISR_OFS, isr); ++ DEFINE_MAPPED_REG_OFS(XSI_IFA_OFS, ifa); ++ DEFINE_MAPPED_REG_OFS(XSI_IIPA_OFS, iipa); ++ DEFINE_MAPPED_REG_OFS(XSI_IIM_OFS, iim); ++ DEFINE_MAPPED_REG_OFS(XSI_IHA_OFS, iha); ++ DEFINE_MAPPED_REG_OFS(XSI_ITIR_OFS, itir); ++ DEFINE_MAPPED_REG_OFS(XSI_PSR_IC_OFS, interrupt_collection_enabled); ++ DEFINE_MAPPED_REG_OFS(XSI_BANKNUM_OFS, banknum); ++ DEFINE_MAPPED_REG_OFS(XSI_BANK0_R16_OFS, bank0_regs[0]); ++ DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]); ++ DEFINE_MAPPED_REG_OFS(XSI_B0NATS_OFS, vbnat); ++ DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat); ++#endif /* CONFIG_XEN */ + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/entry.S +--- a/arch/ia64/kernel/entry.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/entry.S Wed Aug 08 16:25:28 2007 -0300 +@@ -180,7 +180,7 @@ END(sys_clone) + * called. The code starting at .map relies on this. The rest of the code + * doesn't care about the interrupt masking status. + */ +-GLOBAL_ENTRY(ia64_switch_to) ++GLOBAL_ENTRY(__ia64_switch_to) + .prologue + alloc r16=ar.pfs,1,0,0,0 + DO_SAVE_SWITCH_STACK +@@ -234,7 +234,7 @@ GLOBAL_ENTRY(ia64_switch_to) + ;; + srlz.d + br.cond.sptk .done +-END(ia64_switch_to) ++END(__ia64_switch_to) + + /* + * Note that interrupts are enabled during save_switch_stack and load_switch_stack. This +@@ -375,7 +375,7 @@ END(save_switch_stack) + * - b7 holds address to return to + * - must not touch r8-r11 + */ +-ENTRY(load_switch_stack) ++GLOBAL_ENTRY(load_switch_stack) + .prologue + .altrp b7 + +@@ -510,7 +510,7 @@ END(clone) + * because some system calls (such as ia64_execve) directly + * manipulate ar.pfs. + */ +-GLOBAL_ENTRY(ia64_trace_syscall) ++GLOBAL_ENTRY(__ia64_trace_syscall) + PT_REGS_UNWIND_INFO(0) + /* + * We need to preserve the scratch registers f6-f11 in case the system +@@ -582,7 +582,7 @@ strace_error: + (p6) mov r10=-1 + (p6) mov r8=r9 + br.cond.sptk .strace_save_retval +-END(ia64_trace_syscall) ++END(__ia64_trace_syscall) + + /* + * When traced and returning from sigreturn, we invoke syscall_trace but then +@@ -601,7 +601,7 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel) + .ret4: br.cond.sptk ia64_leave_kernel + END(ia64_strace_leave_kernel) + +-GLOBAL_ENTRY(ia64_ret_from_clone) ++GLOBAL_ENTRY(__ia64_ret_from_clone) + PT_REGS_UNWIND_INFO(0) + { /* + * Some versions of gas generate bad unwind info if the first instruction of a +@@ -627,7 +627,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) + cmp.ne p6,p0=r2,r0 + (p6) br.cond.spnt .strace_check_retval + ;; // added stop bits to prevent r8 dependency +-END(ia64_ret_from_clone) ++END(__ia64_ret_from_clone) + // fall through + GLOBAL_ENTRY(ia64_ret_from_syscall) + PT_REGS_UNWIND_INFO(0) +@@ -635,8 +635,11 @@ GLOBAL_ENTRY(ia64_ret_from_syscall) + adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 + mov r10=r0 // clear error indication in r10 + (p7) br.cond.spnt handle_syscall_error // handle potential syscall failure ++ ;; ++ // don't fall through, ia64_leave_syscall may be #define'd ++ br.cond.sptk.few ia64_leave_syscall ++ ;; + END(ia64_ret_from_syscall) +- // fall through + /* + * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't + * need to switch to bank 0 and doesn't restore the scratch registers. +@@ -681,7 +684,7 @@ END(ia64_ret_from_syscall) + * ar.csd: cleared + * ar.ssd: cleared + */ +-ENTRY(ia64_leave_syscall) ++GLOBAL_ENTRY(__ia64_leave_syscall) + PT_REGS_UNWIND_INFO(0) + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to +@@ -789,7 +792,7 @@ ENTRY(ia64_leave_syscall) + mov.m ar.ssd=r0 // M2 clear ar.ssd + mov f11=f0 // F clear f11 + br.cond.sptk.many rbs_switch // B +-END(ia64_leave_syscall) ++END(__ia64_leave_syscall) + + #ifdef CONFIG_IA32_SUPPORT + GLOBAL_ENTRY(ia64_ret_from_ia32_execve) +@@ -801,10 +804,13 @@ GLOBAL_ENTRY(ia64_ret_from_ia32_execve) + st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit + .mem.offset 8,0 + st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit ++ ;; ++ // don't fall through, ia64_leave_kernel may be #define'd ++ br.cond.sptk.few ia64_leave_kernel ++ ;; + END(ia64_ret_from_ia32_execve) +- // fall through + #endif /* CONFIG_IA32_SUPPORT */ +-GLOBAL_ENTRY(ia64_leave_kernel) ++GLOBAL_ENTRY(__ia64_leave_kernel) + PT_REGS_UNWIND_INFO(0) + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to +@@ -1135,7 +1141,7 @@ skip_rbs_switch: + ld8 r10=[r3] + br.cond.sptk.many .work_processed_syscall // re-check + +-END(ia64_leave_kernel) ++END(__ia64_leave_kernel) + + ENTRY(handle_syscall_error) + /* +@@ -1175,7 +1181,7 @@ END(ia64_invoke_schedule_tail) + * be set up by the caller. We declare 8 input registers so the system call + * args get preserved, in case we need to restart a system call. + */ +-ENTRY(notify_resume_user) ++GLOBAL_ENTRY(notify_resume_user) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! + mov r9=ar.unat +@@ -1263,7 +1269,7 @@ ENTRY(sys_rt_sigreturn) + adds sp=16,sp + ;; + ld8 r9=[sp] // load new ar.unat +- mov.sptk b7=r8,ia64_leave_kernel ++ mov.sptk b7=r8,__ia64_leave_kernel + ;; + mov ar.unat=r9 + br.many b7 +@@ -1605,8 +1611,8 @@ sys_call_table: + data8 sys_ni_syscall // 1295 reserved for ppoll + data8 sys_unshare + data8 sys_splice +- data8 sys_set_robust_list +- data8 sys_get_robust_list ++ data8 sys_ni_syscall // reserved for set_robust_list ++ data8 sys_ni_syscall // reserved for get_robust_list + data8 sys_sync_file_range // 1300 + data8 sys_tee + data8 sys_vmsplice +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/fsys.S +--- a/arch/ia64/kernel/fsys.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/fsys.S Wed Aug 08 16:25:28 2007 -0300 +@@ -516,11 +516,34 @@ ENTRY(fsys_fallback_syscall) + adds r17=-1024,r15 + movl r14=sys_call_table + ;; ++#ifdef CONFIG_XEN ++ movl r18=running_on_xen;; ++ ld4 r18=[r18];; ++ // p14 = running_on_xen ++ // p15 = !running_on_xen ++ cmp.ne p14,p15=r0,r18 ++ ;; ++(p14) movl r18=XSI_PSR_I_ADDR;; ++(p14) ld8 r18=[r18] ++(p14) mov r29=1;; ++(p14) st1 [r18]=r29 ++(p15) rsm psr.i ++#else + rsm psr.i ++#endif + shladd r18=r17,3,r14 + ;; + ld8 r18=[r18] // load normal (heavy-weight) syscall entry-point ++#ifdef CONFIG_XEN ++(p14) mov r27=r8 ++(p14) XEN_HYPER_GET_PSR ++ ;; ++(p14) mov r29=r8 ++(p14) mov r8=r27 ++(p15) mov r29=psr // read psr (12 cyc load latency) ++#else + mov r29=psr // read psr (12 cyc load latency) ++#endif + mov r27=ar.rsc + mov r21=ar.fpsr + mov r26=ar.pfs +@@ -632,7 +655,25 @@ GLOBAL_ENTRY(fsys_bubble_down) + mov rp=r14 // I0 set the real return addr + and r3=_TIF_SYSCALL_TRACEAUDIT,r3 // A + ;; ++#ifdef CONFIG_XEN ++ movl r14=running_on_xen;; ++ ld4 r14=[r14];; ++ // p14 = running_on_xen ++ // p15 = !running_on_xen ++ cmp.ne p14,p15=r0,r14 ++ ;; ++(p14) movl r28=XSI_PSR_I_ADDR;; ++(p14) ld8 r28=[r28];; ++(p14) adds r28=-1,r28;; // event_pending ++(p14) ld1 r14=[r28];; ++(p14) cmp.ne.unc p13,p14=r14,r0;; ++(p13) XEN_HYPER_SSM_I ++(p14) adds r28=1,r28;; // event_mask ++(p14) st1 [r28]=r0;; ++(p15) ssm psr.i ++#else + ssm psr.i // M2 we're on kernel stacks now, reenable irqs ++#endif + cmp.eq p8,p0=r3,r0 // A + (p10) br.cond.spnt.many ia64_ret_from_syscall // B return if bad call-frame or r15 is a NaT + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/gate.S +--- a/arch/ia64/kernel/gate.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/gate.S Wed Aug 08 16:25:28 2007 -0300 +@@ -6,13 +6,15 @@ + * David Mosberger-Tang <davidm@hpl.hp.com> + */ + +- + #include <asm/asmmacro.h> + #include <asm/errno.h> + #include <asm/asm-offsets.h> + #include <asm/sigcontext.h> + #include <asm/system.h> + #include <asm/unistd.h> ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++# include <asm/privop.h> ++#endif + + /* + * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, +@@ -31,6 +33,40 @@ + #define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ + [1:](pr)brl.cond.sptk 0; \ + .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-. ++ ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++ // The page in which hyperprivop lives must be pinned by ITR. ++ // However vDSO area isn't pinned. So issuing hyperprivop ++ // from vDSO page causes trouble that Kevin pointed out. ++ // After clearing vpsr.ic, the vcpu is pre-empted and the itlb ++ // is flushed. Then vcpu get cpu again, tlb miss fault occures. ++ // However it results in nested dtlb fault because vpsr.ic is off. ++ // To avoid such a situation, we jump into the kernel text area ++ // which is pinned, and then issue hyperprivop and return back ++ // to vDSO page. ++ // This is Dan Magenheimer's idea. ++ ++ // Currently is_running_on_xen() is defined as running_on_xen. ++ // If is_running_on_xen() is a real function, we must update ++ // according to it. ++ .section ".data.patch.running_on_xen", "a" ++ .previous ++#define LOAD_RUNNING_ON_XEN(reg) \ ++[1:] movl reg=0; \ ++ .xdata4 ".data.patch.running_on_xen", 1b-. ++ ++ .section ".data.patch.brl_xen_ssm_i_0", "a" ++ .previous ++#define BRL_COND_XEN_SSM_I_0(pr) \ ++[1:](pr)brl.cond.sptk 0; \ ++ .xdata4 ".data.patch.brl_xen_ssm_i_0", 1b-. ++ ++ .section ".data.patch.brl_xen_ssm_i_1", "a" ++ .previous ++#define BRL_COND_XEN_SSM_I_1(pr) \ ++[1:](pr)brl.cond.sptk 0; \ ++ .xdata4 ".data.patch.brl_xen_ssm_i_1", 1b-. ++#endif + + GLOBAL_ENTRY(__kernel_syscall_via_break) + .prologue +@@ -76,7 +112,42 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc) + epc // B causes split-issue + } + ;; ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++ // r20 = 1 ++ // r22 = &vcpu->vcpu_info->evtchn_upcall_mask ++ // r23 = &vpsr.ic ++ // r24 = &vcpu->vcpu_info->evtchn_upcall_pending ++ // r25 = tmp ++ // r28 = &running_on_xen ++ // r30 = running_on_xen ++ // r31 = tmp ++ // p11 = tmp ++ // p12 = running_on_xen ++ // p13 = !running_on_xen ++ // p14 = tmp ++ // p15 = tmp ++#define isXen p12 ++#define isRaw p13 ++ LOAD_RUNNING_ON_XEN(r28) ++ movl r22=XSI_PSR_I_ADDR ++ ;; ++ ld8 r22=[r22] ++ ;; ++ movl r23=XSI_PSR_IC ++ adds r24=-1,r22 ++ mov r20=1 ++ ;; ++ ld4 r30=[r28] ++ ;; ++ cmp.ne isXen,isRaw=r0,r30 ++ ;; ++(isRaw) rsm psr.be | psr.i ++(isXen) st1 [r22]=r20 ++(isXen) rum psr.be ++ ;; ++#else + rsm psr.be | psr.i // M2 (5 cyc to srlz.d) ++#endif + LOAD_FSYSCALL_TABLE(r14) // X + ;; + mov r16=IA64_KR(CURRENT) // M2 (12 cyc) +@@ -84,7 +155,14 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc) + mov r19=NR_syscalls-1 // A + ;; + lfetch [r18] // M0|1 ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++(isRaw) mov r29=psr ++(isXen) XEN_HYPER_GET_PSR ++ ;; ++(isXen) mov r29=r8 ++#else + mov r29=psr // M2 (12 cyc) ++#endif + // If r17 is a NaT, p6 will be zero + cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)? + ;; +@@ -98,9 +176,21 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc) + ;; + nop.m 0 + (p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!) ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++ ;; ++ // p14 = running_on_xen && p8 ++ // p15 = !running_on_xen && p8 ++(p8) cmp.ne.unc p14,p15=r0,r30 ++ ;; ++(p15) ssm psr.i ++ BRL_COND_XEN_SSM_I_0(p14) ++ .global .vdso_ssm_i_0_ret ++.vdso_ssm_i_0_ret: ++#else + nop.i 0 + ;; + (p8) ssm psr.i ++#endif + (p6) mov b7=r18 // I0 + (p8) br.dptk.many b7 // B + +@@ -121,9 +211,21 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc) + #else + BRL_COND_FSYS_BUBBLE_DOWN(p6) + #endif ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++(isRaw) ssm psr.i ++ BRL_COND_XEN_SSM_I_1(isXen) ++ .global .vdso_ssm_i_1_ret ++.vdso_ssm_i_1_ret: ++#else + ssm psr.i ++#endif + mov r10=-1 + (p10) mov r8=EINVAL ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++ dv_serialize_data // shut up gas warning. ++ // we know xen_hyper_ssm_i_0 or xen_hyper_ssm_i_1 ++ // doesn't change p9 and p10 ++#endif + (p9) mov r8=ENOSYS + FSYS_RETURN + END(__kernel_syscall_via_epc) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/gate.lds.S +--- a/arch/ia64/kernel/gate.lds.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/gate.lds.S Wed Aug 08 16:25:28 2007 -0300 +@@ -43,6 +43,20 @@ SECTIONS + __start_gate_brl_fsys_bubble_down_patchlist = .; + *(.data.patch.brl_fsys_bubble_down) + __end_gate_brl_fsys_bubble_down_patchlist = .; ++ ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++ __start_gate_running_on_xen_patchlist = .; ++ *(.data.patch.running_on_xen) ++ __end_gate_running_on_xen_patchlist = .; ++ ++ __start_gate_brl_xen_ssm_i_0_patchlist = .; ++ *(.data.patch.brl_xen_ssm_i_0) ++ __end_gate_brl_xen_ssm_i_0_patchlist = .; ++ ++ __start_gate_brl_xen_ssm_i_1_patchlist = .; ++ *(.data.patch.brl_xen_ssm_i_1) ++ __end_gate_brl_xen_ssm_i_1_patchlist = .; ++#endif + } :readable + .IA_64.unwind_info : { *(.IA_64.unwind_info*) } + .IA_64.unwind : { *(.IA_64.unwind*) } :readable :unwind +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/head.S +--- a/arch/ia64/kernel/head.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/head.S Wed Aug 08 16:25:28 2007 -0300 +@@ -366,6 +366,12 @@ 1: // now we are in virtual mode + (isBP) movl r2=ia64_boot_param + ;; + (isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader ++ ++#ifdef CONFIG_XEN ++ // Note: isBP is used by the subprogram. ++ br.call.sptk.many rp=early_xen_setup ++ ;; ++#endif + + #ifdef CONFIG_SMP + (isAP) br.call.sptk.many rp=start_secondary +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/iosapic.c +--- a/arch/ia64/kernel/iosapic.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/iosapic.c Wed Aug 08 16:25:28 2007 -0300 +@@ -159,6 +159,75 @@ static int iosapic_kmalloc_ok; + static int iosapic_kmalloc_ok; + static LIST_HEAD(free_rte_list); + ++#ifdef CONFIG_XEN ++#include <xen/interface/xen.h> ++#include <xen/interface/physdev.h> ++#include <asm/hypervisor.h> ++static inline unsigned int xen_iosapic_read(char __iomem *iosapic, unsigned int reg) ++{ ++ struct physdev_apic apic_op; ++ int ret; ++ ++ apic_op.apic_physbase = (unsigned long)iosapic - ++ __IA64_UNCACHED_OFFSET; ++ apic_op.reg = reg; ++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); ++ if (ret) ++ return ret; ++ return apic_op.value; ++} ++ ++static inline void xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val) ++{ ++ struct physdev_apic apic_op; ++ ++ apic_op.apic_physbase = (unsigned long)iosapic - ++ __IA64_UNCACHED_OFFSET; ++ apic_op.reg = reg; ++ apic_op.value = val; ++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op); ++} ++ ++static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg) ++{ ++ if (!is_running_on_xen()) { ++ writel(reg, iosapic + IOSAPIC_REG_SELECT); ++ return readl(iosapic + IOSAPIC_WINDOW); ++ } else ++ return xen_iosapic_read(iosapic, reg); ++} ++ ++static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val) ++{ ++ if (!is_running_on_xen()) { ++ writel(reg, iosapic + IOSAPIC_REG_SELECT); ++ writel(val, iosapic + IOSAPIC_WINDOW); ++ } else ++ xen_iosapic_write(iosapic, reg, val); ++} ++ ++int xen_assign_irq_vector(int irq) ++{ ++ struct physdev_irq irq_op; ++ ++ irq_op.irq = irq; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) ++ return -ENOSPC; ++ ++ return irq_op.vector; ++} ++ ++void xen_free_irq_vector(int vector) ++{ ++ struct physdev_irq irq_op; ++ ++ irq_op.vector = vector; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_free_irq_vector, &irq_op)) ++ printk(KERN_WARNING "%s: xen_free_irq_vecotr fail vector=%d\n", ++ __FUNCTION__, vector); ++} ++#endif /* XEN */ ++ + /* + * Find an IOSAPIC associated with a GSI + */ +@@ -677,6 +746,9 @@ register_intr (unsigned int gsi, int vec + iosapic_intr_info[vector].polarity = polarity; + iosapic_intr_info[vector].dmode = delivery; + iosapic_intr_info[vector].trigger = trigger; ++ ++ if (is_running_on_xen()) ++ return 0; + + if (trigger == IOSAPIC_EDGE) + irq_type = &irq_type_iosapic_edge; +@@ -1040,6 +1112,9 @@ iosapic_system_init (int system_pcat_com + } + + pcat_compat = system_pcat_compat; ++ if (is_running_on_xen()) ++ return; ++ + if (pcat_compat) { + /* + * Disable the compatibility mode interrupts (8259 style), +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/irq_ia64.c +--- a/arch/ia64/kernel/irq_ia64.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/irq_ia64.c Wed Aug 08 16:25:28 2007 -0300 +@@ -31,6 +31,10 @@ + #include <linux/threads.h> + #include <linux/bitops.h> + #include <linux/irq.h> ++#ifdef CONFIG_XEN ++#include <linux/cpu.h> ++#endif ++ + + #include <asm/delay.h> + #include <asm/intrinsics.h> +@@ -70,6 +74,13 @@ assign_irq_vector (int irq) + assign_irq_vector (int irq) + { + int pos, vector; ++ ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ extern int xen_assign_irq_vector(int); ++ return xen_assign_irq_vector(irq); ++ } ++#endif + again: + pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); + vector = IA64_FIRST_DEVICE_VECTOR + pos; +@@ -88,6 +99,13 @@ free_irq_vector (int vector) + if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR) + return; + ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ extern void xen_free_irq_vector(int); ++ xen_free_irq_vector(vector); ++ return; ++ } ++#endif + pos = vector - IA64_FIRST_DEVICE_VECTOR; + if (!test_and_clear_bit(pos, ia64_vector_mask)) + printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); +@@ -280,11 +298,267 @@ static struct irqaction resched_irqactio + }; + #endif + ++#ifdef CONFIG_XEN ++#include <xen/evtchn.h> ++#include <xen/interface/callback.h> ++ ++static DEFINE_PER_CPU(int, timer_irq) = -1; ++static DEFINE_PER_CPU(int, ipi_irq) = -1; ++static DEFINE_PER_CPU(int, resched_irq) = -1; ++static DEFINE_PER_CPU(int, cmc_irq) = -1; ++static DEFINE_PER_CPU(int, cmcp_irq) = -1; ++static DEFINE_PER_CPU(int, cpep_irq) = -1; ++static char timer_name[NR_CPUS][15]; ++static char ipi_name[NR_CPUS][15]; ++static char resched_name[NR_CPUS][15]; ++static char cmc_name[NR_CPUS][15]; ++static char cmcp_name[NR_CPUS][15]; ++static char cpep_name[NR_CPUS][15]; ++ ++struct saved_irq { ++ unsigned int irq; ++ struct irqaction *action; ++}; ++/* 16 should be far optimistic value, since only several percpu irqs ++ * are registered early. ++ */ ++#define MAX_LATE_IRQ 16 ++static struct saved_irq saved_percpu_irqs[MAX_LATE_IRQ]; ++static unsigned short late_irq_cnt = 0; ++static unsigned short saved_irq_cnt = 0; ++static int xen_slab_ready = 0; ++ ++#ifdef CONFIG_SMP ++/* Dummy stub. Though we may check RESCHEDULE_VECTOR before __do_IRQ, ++ * it ends up to issue several memory accesses upon percpu data and ++ * thus adds unnecessary traffic to other paths. ++ */ ++static irqreturn_t ++handle_reschedule(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction resched_irqaction = { ++ .handler = handle_reschedule, ++ .flags = SA_INTERRUPT, ++ .name = "RESCHED" ++}; ++#endif ++ ++/* ++ * This is xen version percpu irq registration, which needs bind ++ * to xen specific evtchn sub-system. One trick here is that xen ++ * evtchn binding interface depends on kmalloc because related ++ * port needs to be freed at device/cpu down. So we cache the ++ * registration on BSP before slab is ready and then deal them ++ * at later point. For rest instances happening after slab ready, ++ * we hook them to xen evtchn immediately. ++ * ++ * FIXME: MCA is not supported by far, and thus "nomca" boot param is ++ * required. ++ */ ++static void ++xen_register_percpu_irq (unsigned int vec, struct irqaction *action, int save) ++{ ++ unsigned int cpu = smp_processor_id(); ++ irq_desc_t *desc; ++ int irq = 0; ++ ++ if (xen_slab_ready) { ++ switch (vec) { ++ case IA64_TIMER_VECTOR: ++ sprintf(timer_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_virq_to_irqhandler(VIRQ_ITC, cpu, ++ action->handler, action->flags, ++ timer_name[cpu], action->dev_id); ++ per_cpu(timer_irq,cpu) = irq; ++ break; ++ case IA64_IPI_RESCHEDULE: ++ sprintf(resched_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, cpu, ++ action->handler, action->flags, ++ resched_name[cpu], action->dev_id); ++ per_cpu(resched_irq,cpu) = irq; ++ break; ++ case IA64_IPI_VECTOR: ++ sprintf(ipi_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_ipi_to_irqhandler(IPI_VECTOR, cpu, ++ action->handler, action->flags, ++ ipi_name[cpu], action->dev_id); ++ per_cpu(ipi_irq,cpu) = irq; ++ break; ++ case IA64_CMC_VECTOR: ++ sprintf(cmc_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_virq_to_irqhandler(VIRQ_MCA_CMC, cpu, ++ action->handler, ++ action->flags, ++ cmc_name[cpu], ++ action->dev_id); ++ per_cpu(cmc_irq,cpu) = irq; ++ break; ++ case IA64_CMCP_VECTOR: ++ sprintf(cmcp_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_ipi_to_irqhandler(CMCP_VECTOR, cpu, ++ action->handler, ++ action->flags, ++ cmcp_name[cpu], ++ action->dev_id); ++ per_cpu(cmcp_irq,cpu) = irq; ++ break; ++ case IA64_CPEP_VECTOR: ++ sprintf(cpep_name[cpu], "%s%d", action->name, cpu); ++ irq = bind_ipi_to_irqhandler(CPEP_VECTOR, cpu, ++ action->handler, ++ action->flags, ++ cpep_name[cpu], ++ action->dev_id); ++ per_cpu(cpep_irq,cpu) = irq; ++ break; ++ case IA64_CPE_VECTOR: ++ case IA64_MCA_RENDEZ_VECTOR: ++ case IA64_PERFMON_VECTOR: ++ case IA64_MCA_WAKEUP_VECTOR: ++ case IA64_SPURIOUS_INT_VECTOR: ++ /* No need to complain, these aren't supported. */ ++ break; ++ default: ++ printk(KERN_WARNING "Percpu irq %d is unsupported " ++ "by xen!\n", vec); ++ break; ++ } ++ BUG_ON(irq < 0); ++ ++ if (irq > 0) { ++ /* ++ * Mark percpu. Without this, migrate_irqs() will ++ * mark the interrupt for migrations and trigger it ++ * on cpu hotplug. ++ */ ++ desc = irq_desc + irq; ++ desc->status |= IRQ_PER_CPU; ++ } ++ } ++ ++ /* For BSP, we cache registered percpu irqs, and then re-walk ++ * them when initializing APs ++ */ ++ if (!cpu && save) { ++ BUG_ON(saved_irq_cnt == MAX_LATE_IRQ); ++ saved_percpu_irqs[saved_irq_cnt].irq = vec; ++ saved_percpu_irqs[saved_irq_cnt].action = action; ++ saved_irq_cnt++; ++ if (!xen_slab_ready) ++ late_irq_cnt++; ++ } ++} ++ ++static void ++xen_bind_early_percpu_irq (void) ++{ ++ int i; ++ ++ xen_slab_ready = 1; ++ /* There's no race when accessing this cached array, since only ++ * BSP will face with such step shortly ++ */ ++ for (i = 0; i < late_irq_cnt; i++) ++ xen_register_percpu_irq(saved_percpu_irqs[i].irq, ++ saved_percpu_irqs[i].action, 0); ++} ++ ++/* FIXME: There's no obvious point to check whether slab is ready. So ++ * a hack is used here by utilizing a late time hook. ++ */ ++extern void (*late_time_init)(void); ++extern char xen_event_callback; ++extern void xen_init_IRQ(void); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static int __devinit ++unbind_evtchn_callback(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ if (action == CPU_DEAD) { ++ /* Unregister evtchn. */ ++ if (per_cpu(cpep_irq,cpu) >= 0) { ++ unbind_from_irqhandler(per_cpu(cpep_irq, cpu), NULL); ++ per_cpu(cpep_irq, cpu) = -1; ++ } ++ if (per_cpu(cmcp_irq,cpu) >= 0) { ++ unbind_from_irqhandler(per_cpu(cmcp_irq, cpu), NULL); ++ per_cpu(cmcp_irq, cpu) = -1; ++ } ++ if (per_cpu(cmc_irq,cpu) >= 0) { ++ unbind_from_irqhandler(per_cpu(cmc_irq, cpu), NULL); ++ per_cpu(cmc_irq, cpu) = -1; ++ } ++ if (per_cpu(ipi_irq,cpu) >= 0) { ++ unbind_from_irqhandler (per_cpu(ipi_irq, cpu), NULL); ++ per_cpu(ipi_irq, cpu) = -1; ++ } ++ if (per_cpu(resched_irq,cpu) >= 0) { ++ unbind_from_irqhandler (per_cpu(resched_irq, cpu), ++ NULL); ++ per_cpu(resched_irq, cpu) = -1; ++ } ++ if (per_cpu(timer_irq,cpu) >= 0) { ++ unbind_from_irqhandler (per_cpu(timer_irq, cpu), NULL); ++ per_cpu(timer_irq, cpu) = -1; ++ } ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block unbind_evtchn_notifier = { ++ .notifier_call = unbind_evtchn_callback, ++ .priority = 0 ++}; ++#endif ++ ++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); ++void xen_smp_intr_init(void) ++{ ++#ifdef CONFIG_SMP ++ unsigned int cpu = smp_processor_id(); ++ unsigned int i = 0; ++ struct callback_register event = { ++ .type = CALLBACKTYPE_event, ++ .address = (unsigned long)&xen_event_callback, ++ }; ++ ++ if (cpu == 0) { ++ /* Initialization was already done for boot cpu. */ ++#ifdef CONFIG_HOTPLUG_CPU ++ /* Register the notifier only once. */ ++ register_cpu_notifier(&unbind_evtchn_notifier); ++#endif ++ return; ++ } ++ ++ /* This should be piggyback when setup vcpu guest context */ ++ BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event)); ++ ++ for (i = 0; i < saved_irq_cnt; i++) ++ xen_register_percpu_irq(saved_percpu_irqs[i].irq, ++ saved_percpu_irqs[i].action, 0); ++#endif /* CONFIG_SMP */ ++} ++#endif /* CONFIG_XEN */ ++ + void + register_percpu_irq (ia64_vector vec, struct irqaction *action) + { + irq_desc_t *desc; + unsigned int irq; ++ ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) ++ return xen_register_percpu_irq(vec, action, 1); ++#endif + + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == vec) { +@@ -299,6 +573,21 @@ void __init + void __init + init_IRQ (void) + { ++#ifdef CONFIG_XEN ++ /* Maybe put into platform_irq_init later */ ++ if (is_running_on_xen()) { ++ struct callback_register event = { ++ .type = CALLBACKTYPE_event, ++ .address = (unsigned long)&xen_event_callback, ++ }; ++ xen_init_IRQ(); ++ BUG_ON(HYPERVISOR_callback_op(CALLBACKOP_register, &event)); ++ late_time_init = xen_bind_early_percpu_irq; ++#ifdef CONFIG_SMP ++ register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction); ++#endif /* CONFIG_SMP */ ++ } ++#endif /* CONFIG_XEN */ + register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL); + #ifdef CONFIG_SMP + register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction); +@@ -317,6 +606,46 @@ ia64_send_ipi (int cpu, int vector, int + unsigned long ipi_data; + unsigned long phys_cpu_id; + ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ int irq = -1; ++ ++#ifdef CONFIG_SMP ++ /* TODO: we need to call vcpu_up here */ ++ if (unlikely(vector == ap_wakeup_vector)) { ++ extern void xen_send_ipi (int cpu, int vec); ++ xen_send_ipi (cpu, vector); ++ //vcpu_prepare_and_up(cpu); ++ return; ++ } ++#endif ++ ++ switch(vector) { ++ case IA64_IPI_VECTOR: ++ irq = per_cpu(ipi_to_irq, cpu)[IPI_VECTOR]; ++ break; ++ case IA64_IPI_RESCHEDULE: ++ irq = per_cpu(ipi_to_irq, cpu)[RESCHEDULE_VECTOR]; ++ break; ++ case IA64_CMCP_VECTOR: ++ irq = per_cpu(ipi_to_irq, cpu)[CMCP_VECTOR]; ++ break; ++ case IA64_CPEP_VECTOR: ++ irq = per_cpu(ipi_to_irq, cpu)[CPEP_VECTOR]; ++ break; ++ default: ++ printk(KERN_WARNING "Unsupported IPI type 0x%x\n", ++ vector); ++ irq = 0; ++ break; ++ } ++ ++ BUG_ON(irq < 0); ++ notify_remote_via_irq(irq); ++ return; ++ } ++#endif /* CONFIG_XEN */ ++ + #ifdef CONFIG_SMP + phys_cpu_id = cpu_physical_id(cpu); + #else +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/pal.S +--- a/arch/ia64/kernel/pal.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/pal.S Wed Aug 08 16:25:28 2007 -0300 +@@ -16,6 +16,7 @@ + #include <asm/processor.h> + + .data ++ .globl pal_entry_point + pal_entry_point: + data8 ia64_pal_default_handler + .text +@@ -86,7 +87,7 @@ 1: mov psr.l = loc3 + ;; + srlz.d // seralize restoration of psr.l + br.ret.sptk.many b0 +-END(ia64_pal_call_static) ++END(__ia64_pal_call_static) + + /* + * Make a PAL call using the stacked registers calling convention. +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/patch.c +--- a/arch/ia64/kernel/patch.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/patch.c Wed Aug 08 16:25:28 2007 -0300 +@@ -184,6 +184,69 @@ patch_brl_fsys_bubble_down (unsigned lon + ia64_srlz_i(); + } + ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++extern char __start_gate_running_on_xen_patchlist[]; ++extern char __end_gate_running_on_xen_patchlist[]; ++ ++void __init ++patch_running_on_xen(unsigned long start, unsigned long end) ++{ ++ extern int running_on_xen; ++ s32 *offp = (s32 *)start; ++ u64 ip; ++ ++ while (offp < (s32 *)end) { ++ ip = (u64)ia64_imva((char *)offp + *offp); ++ ia64_patch_imm64(ip, (u64)&running_on_xen); ++ ia64_fc((void *)ip); ++ ++offp; ++ } ++ ia64_sync_i(); ++ ia64_srlz_i(); ++} ++ ++static void __init ++patch_brl_symaddr(unsigned long start, unsigned long end, ++ unsigned long symaddr) ++{ ++ s32 *offp = (s32 *)start; ++ u64 ip; ++ ++ while (offp < (s32 *)end) { ++ ip = (u64)offp + *offp; ++ ia64_patch_imm60((u64)ia64_imva((void *)ip), ++ (u64)(symaddr - (ip & -16)) / 16); ++ ia64_fc((void *)ip); ++ ++offp; ++ } ++ ia64_sync_i(); ++ ia64_srlz_i(); ++} ++ ++#define EXTERN_PATCHLIST(name) \ ++ extern char __start_gate_brl_##name##_patchlist[]; \ ++ extern char __end_gate_brl_##name##_patchlist[]; \ ++ extern char name[] ++ ++#define PATCH_BRL_SYMADDR(name) \ ++ patch_brl_symaddr((unsigned long)__start_gate_brl_##name##_patchlist, \ ++ (unsigned long)__end_gate_brl_##name##_patchlist, \ ++ (unsigned long)name) ++ ++static void __init ++patch_brl_in_vdso(void) ++{ ++ EXTERN_PATCHLIST(xen_ssm_i_0); ++ EXTERN_PATCHLIST(xen_ssm_i_1); ++ ++ PATCH_BRL_SYMADDR(xen_ssm_i_0); ++ PATCH_BRL_SYMADDR(xen_ssm_i_1); ++} ++#else ++#define patch_running_on_xen(start, end) do { } while (0) ++#define patch_brl_in_vdso() do { } while (0) ++#endif ++ + void __init + ia64_patch_gate (void) + { +@@ -192,6 +255,10 @@ ia64_patch_gate (void) + + patch_fsyscall_table(START(fsyscall), END(fsyscall)); + patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down)); ++#ifdef CONFIG_XEN ++ patch_running_on_xen(START(running_on_xen), END(running_on_xen)); ++ patch_brl_in_vdso(); ++#endif + ia64_patch_vtop(START(vtop), END(vtop)); + ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9)); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/perfmon.c +--- a/arch/ia64/kernel/perfmon.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/perfmon.c Wed Aug 08 16:25:28 2007 -0300 +@@ -53,6 +53,28 @@ + #include <asm/delay.h> + + #ifdef CONFIG_PERFMON ++#ifdef CONFIG_XEN ++//#include <xen/xenoprof.h> ++#include <xen/interface/xenoprof.h> ++ ++static int xenoprof_is_primary = 0; ++#define init_xenoprof_primary(is_primary) (xenoprof_is_primary = (is_primary)) ++#define is_xenoprof_primary() (xenoprof_is_primary) ++#define XEN_NOT_SUPPORTED_YET \ ++ do { \ ++ if (is_running_on_xen()) { \ ++ printk("%s is not supported yet under xen.\n", \ ++ __func__); \ ++ return -ENOSYS; \ ++ } \ ++ } while (0) ++#else ++#define init_xenoprof_primary(is_primary) do { } while (0) ++#define is_xenoprof_primary() (0) ++#define XEN_NOT_SUPPORTED_YET do { } while (0) ++#define HYPERVISOR_perfmon_op(cmd, arg, count) do { } while (0) ++#endif ++ + /* + * perfmon context state + */ +@@ -1516,6 +1538,7 @@ pfm_read(struct file *filp, char __user + ssize_t ret; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); ++ XEN_NOT_SUPPORTED_YET; + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return -EINVAL; +@@ -2114,6 +2137,15 @@ doit: + */ + if (free_possible) pfm_context_free(ctx); + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) { ++ int ret = HYPERVISOR_perfmon_op(PFM_DESTROY_CONTEXT, ++ NULL, 0); ++ if (ret) ++ printk("%s:%d PFM_DESTROY_CONTEXT hypercall " ++ "failed\n", __func__, __LINE__); ++ } ++ } + return 0; + } + +@@ -2737,6 +2769,23 @@ pfm_context_create(pfm_context_t *ctx, v + */ + pfm_reset_pmu_state(ctx); + ++ if (is_running_on_xen()) { ++ /* ++ * kludge to get xenoprof.is_primary. ++ * XENOPROF_init/ia64 is nop. so it is safe to call it here. ++ */ ++ struct xenoprof_init init; ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init); ++ if (ret) ++ goto buffer_error; ++ init_xenoprof_primary(init.is_primary); ++ ++ if (is_xenoprof_primary()) { ++ ret = HYPERVISOR_perfmon_op(PFM_CREATE_CONTEXT, arg, 0); ++ if (ret) ++ goto buffer_error; ++ } ++ } + return 0; + + buffer_error: +@@ -2872,6 +2921,12 @@ pfm_write_pmcs(pfm_context_t *ctx, void + pfm_reg_check_t wr_func; + #define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_WRITE_PMCS, ++ arg, count); ++ return 0; ++ } + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; +@@ -3110,6 +3165,12 @@ pfm_write_pmds(pfm_context_t *ctx, void + int ret = -EINVAL; + pfm_reg_check_t wr_func; + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_WRITE_PMDS, ++ arg, count); ++ return 0; ++ } + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; +@@ -3305,6 +3366,7 @@ pfm_read_pmds(pfm_context_t *ctx, void * + int is_loaded, is_system, is_counting, expert_mode; + int ret = -EINVAL; + pfm_reg_check_t rd_func; ++ XEN_NOT_SUPPORTED_YET; + + /* + * access is possible when loaded only for +@@ -3555,6 +3617,7 @@ pfm_restart(pfm_context_t *ctx, void *ar + pfm_ovfl_ctrl_t rst_ctrl; + int state, is_system; + int ret = 0; ++ XEN_NOT_SUPPORTED_YET; + + state = ctx->ctx_state; + fmt = ctx->ctx_buf_fmt; +@@ -3704,6 +3767,7 @@ pfm_debug(pfm_context_t *ctx, void *arg, + pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) + { + unsigned int m = *(unsigned int *)arg; ++ XEN_NOT_SUPPORTED_YET; + + pfm_sysctl.debug = m == 0 ? 0 : 1; + +@@ -3974,6 +4038,8 @@ pfm_get_features(pfm_context_t *ctx, voi + { + pfarg_features_t *req = (pfarg_features_t *)arg; + ++ if (is_running_on_xen()) ++ return HYPERVISOR_perfmon_op(PFM_GET_FEATURES, &arg, 0); + req->ft_version = PFM_VERSION; + return 0; + } +@@ -3984,6 +4050,12 @@ pfm_stop(pfm_context_t *ctx, void *arg, + struct pt_regs *tregs; + struct task_struct *task = PFM_CTX_TASK(ctx); + int state, is_system; ++ ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_STOP, NULL, 0); ++ return 0; ++ } + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; +@@ -4073,6 +4145,11 @@ pfm_start(pfm_context_t *ctx, void *arg, + struct pt_regs *tregs; + int state, is_system; + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_START, NULL, 0); ++ return 0; ++ } + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + +@@ -4155,6 +4232,7 @@ pfm_get_pmc_reset(pfm_context_t *ctx, vo + unsigned int cnum; + int i; + int ret = -EINVAL; ++ XEN_NOT_SUPPORTED_YET; + + for (i = 0; i < count; i++, req++) { + +@@ -4213,6 +4291,11 @@ pfm_context_load(pfm_context_t *ctx, voi + int ret = 0; + int state, is_system, set_dbregs = 0; + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_LOAD_CONTEXT, arg, 0); ++ return 0; ++ } + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + /* +@@ -4461,6 +4544,12 @@ pfm_context_unload(pfm_context_t *ctx, v + int prev_state, is_system; + int ret; + ++ if (is_running_on_xen()) { ++ if (is_xenoprof_primary()) ++ return HYPERVISOR_perfmon_op(PFM_UNLOAD_CONTEXT, ++ NULL, 0); ++ return 0; ++ } + DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); + + prev_state = ctx->ctx_state; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/setup.c +--- a/arch/ia64/kernel/setup.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/setup.c Wed Aug 08 16:25:28 2007 -0300 +@@ -61,6 +61,12 @@ + #include <asm/system.h> + #include <asm/unistd.h> + #include <asm/system.h> ++#ifdef CONFIG_XEN ++#include <asm/hypervisor.h> ++#include <asm/xen/xencomm.h> ++#include <xen/xencons.h> ++#endif ++#include <linux/dma-mapping.h> + + #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) + # error "struct cpuinfo_ia64 too big!" +@@ -69,6 +75,36 @@ + #ifdef CONFIG_SMP + unsigned long __per_cpu_offset[NR_CPUS]; + EXPORT_SYMBOL(__per_cpu_offset); ++#endif ++ ++#ifdef CONFIG_XEN ++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... */ ++} ++ ++static int ++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ unw_init_running(xen_panic_hypercall, NULL); ++ /* we're never actually going to get here... */ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block xen_panic_block = { ++ .notifier_call = xen_panic_event, ++ .next = NULL, ++ .priority = 0 /* try to go last */ ++}; ++ ++void xen_pm_power_off(void) ++{ ++ local_irq_disable(); ++ HYPERVISOR_shutdown(SHUTDOWN_poweroff); ++} + #endif + + extern void ia64_setup_printk_clock(void); +@@ -177,15 +213,33 @@ filter_rsvd_memory (unsigned long start, + return 0; + } + ++static int __init ++rsvd_region_cmp(struct rsvd_region *lhs, struct rsvd_region *rhs) ++{ ++ if (lhs->start > rhs->start) ++ return 1; ++ if (lhs->start < rhs->start) ++ return -1; ++ ++ if (lhs->end > rhs->end) ++ return 1; ++ if (lhs->end < rhs->end) ++ return -1; ++ ++ return 0; ++} ++ + static void __init + sort_regions (struct rsvd_region *rsvd_region, int max) + { ++ int num = max; + int j; + + /* simple bubble sorting */ + while (max--) { + for (j = 0; j < max; ++j) { +- if (rsvd_region[j].start > rsvd_region[j+1].start) { ++ if (rsvd_region_cmp(&rsvd_region[j], ++ &rsvd_region[j + 1]) > 0) { + struct rsvd_region tmp; + tmp = rsvd_region[j]; + rsvd_region[j] = rsvd_region[j + 1]; +@@ -193,6 +247,36 @@ sort_regions (struct rsvd_region *rsvd_r + } + } + } ++ ++ for (j = 0; j < num - 1; j++) { ++ int k; ++ unsigned long start = rsvd_region[j].start; ++ unsigned long end = rsvd_region[j].end; ++ int collapsed; ++ ++ for (k = j + 1; k < num; k++) { ++ BUG_ON(start > rsvd_region[k].start); ++ if (end < rsvd_region[k].start) { ++ k--; ++ break; ++ } ++ end = max(end, rsvd_region[k].end); ++ } ++ if (k == num) ++ k--; ++ rsvd_region[j].end = end; ++ collapsed = k - j; ++ num -= collapsed; ++ for (k = j + 1; k < num; k++) { ++ rsvd_region[k] = rsvd_region[k + collapsed]; ++ } ++ } ++ ++ num_rsvd_regions = num; ++ for (j = 0; j < num; j++) { ++ printk("rsvd_region[%d]: [0x%016lx, 0x%06lx)\n", ++ j, rsvd_region[j].start, rsvd_region[j].end); ++ } + } + + /* +@@ -242,6 +326,14 @@ reserve_memory (void) + rsvd_region[n].start = (unsigned long) ia64_imva((void *)KERNEL_START); + rsvd_region[n].end = (unsigned long) ia64_imva(_end); + n++; ++ ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ rsvd_region[n].start = (unsigned long)__va((HYPERVISOR_shared_info->arch.start_info_pfn << PAGE_SHIFT)); ++ rsvd_region[n].end = rsvd_region[n].start + PAGE_SIZE; ++ n++; ++ } ++#endif + + #ifdef CONFIG_BLK_DEV_INITRD + if (ia64_boot_param->initrd_start) { +@@ -460,6 +552,19 @@ setup_arch (char **cmdline_p) + { + unw_init(); + ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ /* Must be done before any hypercall. */ ++ xencomm_init(); ++ ++ setup_xen_features(); ++ /* Register a call for panic conditions. */ ++ atomic_notifier_chain_register(&panic_notifier_list, ++ &xen_panic_block); ++ pm_power_off = xen_pm_power_off; ++ } ++#endif ++ + ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist); + + *cmdline_p = __va(ia64_boot_param->command_line); +@@ -538,14 +643,79 @@ setup_arch (char **cmdline_p) + conswitchp = &vga_con; + # endif + } +-#endif ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ shared_info_t *s = HYPERVISOR_shared_info; ++ ++ xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT); ++ ++ printk("Running on Xen! start_info_pfn=0x%lx nr_pages=%ld " ++ "flags=0x%x\n", s->arch.start_info_pfn, ++ xen_start_info->nr_pages, xen_start_info->flags); ++ ++ if (!is_initial_xendomain()) { ++#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = NULL; ++#endif ++ } ++ ++ /* ++ * If a console= is NOT specified, we assume using the ++ * xencons console is desired. By default, this is ttyS0 ++ * for dom0 and tty0 for domU. ++ */ ++ if (!strstr(*cmdline_p, "console=")) { ++ char *p, *q, name[5]; ++ int offset = 0; ++ ++ if (is_initial_xendomain()) ++ strncpy(name, "ttyS", 4); ++ else ++ strncpy(name, "tty", 3); ++ ++ p = strstr(*cmdline_p, "xencons="); ++ ++ if (p) { ++ p += 8; ++ if (!strncmp(p, "ttyS", 4)) { ++ strncpy(name, p, 4); ++ p += 4; ++ offset = simple_strtol(p, &q, 10); ++ if (p == q) ++ offset = 0; ++ } else if (!strncmp(p, "tty", 3) || ++ !strncmp(p, "xvc", 3)) { ++ strncpy(name, p, 3); ++ p += 3; ++ offset = simple_strtol(p, &q, 10); ++ if (p == q) ++ offset = 0; ++ } else if (!strncmp(p, "off", 3)) ++ offset = -1; ++ } ++ ++ if (offset >= 0) ++ add_preferred_console(name, offset, NULL); ++ } ++ } ++ xencons_early_setup(); ++#endif ++#endif ++ + + /* enable IA-64 Machine Check Abort Handling unless disabled */ ++#ifdef CONFIG_XEN ++ if (is_running_on_xen() && !is_initial_xendomain()) ++ nomca = 1; ++#endif + if (!nomca) + ia64_mca_init(); + + platform_setup(cmdline_p); + paging_init(); ++#ifdef CONFIG_XEN ++ contiguous_bitmap_init(max_pfn); ++#endif + } + + /* +@@ -951,6 +1121,15 @@ cpu_init (void) + /* size of physical stacked register partition plus 8 bytes: */ + __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8; + platform_cpu_init(); ++ ++#ifdef CONFIG_XEN ++ /* Need to be moved into platform_cpu_init later */ ++ if (is_running_on_xen()) { ++ extern void xen_smp_intr_init(void); ++ xen_smp_intr_init(); ++ } ++#endif ++ + pm_idle = default_idle; + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/kernel/time.c +--- a/arch/ia64/kernel/time.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/kernel/time.c Wed Aug 08 16:25:28 2007 -0300 +@@ -29,6 +29,13 @@ + #include <asm/sections.h> + #include <asm/system.h> + ++#ifdef CONFIG_XEN ++#include <linux/kernel_stat.h> ++#include <linux/posix-timers.h> ++#include <xen/interface/vcpu.h> ++#include <asm/percpu.h> ++#endif ++ + volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */ + + #ifdef CONFIG_IA64_DEBUG_IRQ +@@ -36,6 +43,13 @@ unsigned long last_cli_ip; + unsigned long last_cli_ip; + EXPORT_SYMBOL(last_cli_ip); + ++#endif ++ ++#ifdef CONFIG_XEN ++DEFINE_PER_CPU(struct vcpu_runstate_info, runstate); ++DEFINE_PER_CPU(unsigned long, processed_stolen_time); ++DEFINE_PER_CPU(unsigned long, processed_blocked_time); ++#define NS_PER_TICK (1000000000LL/HZ) + #endif + + static struct time_interpolator itc_interpolator = { +@@ -44,10 +58,96 @@ static struct time_interpolator itc_inte + .source = TIME_SOURCE_CPU + }; + ++#ifdef CONFIG_XEN ++static unsigned long ++consider_steal_time(unsigned long new_itm, struct pt_regs *regs) ++{ ++ unsigned long stolen, blocked, sched_time; ++ unsigned long delta_itm = 0, stolentick = 0; ++ int i, cpu = smp_processor_id(); ++ struct vcpu_runstate_info *runstate; ++ struct task_struct *p = current; ++ ++ runstate = &per_cpu(runstate, smp_processor_id()); ++ ++ do { ++ sched_time = runstate->state_entry_time; ++ mb(); ++ stolen = runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline] - ++ per_cpu(processed_stolen_time, cpu); ++ blocked = runstate->time[RUNSTATE_blocked] - ++ per_cpu(processed_blocked_time, cpu); ++ mb(); ++ } while (sched_time != runstate->state_entry_time); ++ ++ /* ++ * Check for vcpu migration effect ++ * In this case, itc value is reversed. ++ * This causes huge stolen value. ++ * This function just checks and reject this effect. ++ */ ++ if (!time_after_eq(runstate->time[RUNSTATE_blocked], ++ per_cpu(processed_blocked_time, cpu))) ++ blocked = 0; ++ ++ if (!time_after_eq(runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline], ++ per_cpu(processed_stolen_time, cpu))) ++ stolen = 0; ++ ++ if (!time_after(delta_itm + new_itm, ia64_get_itc())) ++ stolentick = ia64_get_itc() - delta_itm - new_itm; ++ ++ do_div(stolentick, NS_PER_TICK); ++ stolentick++; ++ ++ do_div(stolen, NS_PER_TICK); ++ ++ if (stolen > stolentick) ++ stolen = stolentick; ++ ++ stolentick -= stolen; ++ do_div(blocked, NS_PER_TICK); ++ ++ if (blocked > stolentick) ++ blocked = stolentick; ++ ++ if (stolen > 0 || blocked > 0) { ++ account_steal_time(NULL, jiffies_to_cputime(stolen)); ++ account_steal_time(idle_task(cpu), jiffies_to_cputime(blocked)); ++ run_local_timers(); ++ ++ if (rcu_pending(cpu)) ++ rcu_check_callbacks(cpu, user_mode(regs)); ++ ++ scheduler_tick(); ++ run_posix_cpu_timers(p); ++ delta_itm += local_cpu_data->itm_delta * (stolen + blocked); ++ ++ if (cpu == time_keeper_id) { ++ write_seqlock(&xtime_lock); ++ for(i = 0; i < stolen + blocked; i++) ++ do_timer(regs); ++ local_cpu_data->itm_next = delta_itm + new_itm; ++ write_sequnlock(&xtime_lock); ++ } else { ++ local_cpu_data->itm_next = delta_itm + new_itm; ++ } ++ per_cpu(processed_stolen_time,cpu) += NS_PER_TICK * stolen; ++ per_cpu(processed_blocked_time,cpu) += NS_PER_TICK * blocked; ++ } ++ return delta_itm; ++} ++#else ++#define consider_steal_time(new_itm, regs) (0) ++#endif ++ + static irqreturn_t + timer_interrupt (int irq, void *dev_id) + { + unsigned long new_itm; ++ unsigned long delta_itm; /* XEN */ + + if (unlikely(cpu_is_offline(smp_processor_id()))) { + return IRQ_HANDLED; +@@ -62,6 +162,13 @@ timer_interrupt (int irq, void *dev_id) + ia64_get_itc(), new_itm); + + profile_tick(CPU_PROFILING); ++ ++ if (is_running_on_xen()) { ++ delta_itm = consider_steal_time(new_itm, regs); ++ new_itm += delta_itm; ++ if (time_after(new_itm, ia64_get_itc()) && delta_itm) ++ goto skip_process_time_accounting; ++ } + + while (1) { + update_process_times(user_mode(get_irq_regs())); +@@ -91,6 +198,8 @@ timer_interrupt (int irq, void *dev_id) + local_irq_enable(); + local_irq_disable(); + } ++ ++skip_process_time_accounting: /* XEN */ + + do { + /* +@@ -146,6 +255,25 @@ static int __init nojitter_setup(char *s + + __setup("nojitter", nojitter_setup); + ++#ifdef CONFIG_XEN ++/* taken from i386/kernel/time-xen.c */ ++static void init_missing_ticks_accounting(int cpu) ++{ ++ struct vcpu_register_runstate_memory_area area; ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ ++ memset(runstate, 0, sizeof(*runstate)); ++ ++ area.addr.v = runstate; ++ HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); ++ ++ per_cpu(processed_blocked_time, cpu) = runstate->time[RUNSTATE_blocked]; ++ per_cpu(processed_stolen_time, cpu) = runstate->time[RUNSTATE_runnable] ++ + runstate->time[RUNSTATE_offline]; ++} ++#else ++#define init_missing_ticks_accounting(cpu) do {} while (0) ++#endif + + void __devinit + ia64_init_itm (void) +@@ -229,6 +357,9 @@ ia64_init_itm (void) + register_time_interpolator(&itc_interpolator); + } + ++ if (is_running_on_xen()) ++ init_missing_ticks_accounting(smp_processor_id()); ++ + /* Setup the CPU local timer tick */ + ia64_cpu_local_tick(); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/mm/ioremap.c +--- a/arch/ia64/mm/ioremap.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/mm/ioremap.c Wed Aug 08 16:25:28 2007 -0300 +@@ -16,6 +16,9 @@ static inline void __iomem * + static inline void __iomem * + __ioremap (unsigned long offset, unsigned long size) + { ++#ifdef CONFIG_XEN ++ offset = HYPERVISOR_ioremap(offset, size); ++#endif + return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset); + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/oprofile/Makefile +--- a/arch/ia64/oprofile/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/oprofile/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -8,3 +8,7 @@ DRIVER_OBJS := $(addprefix ../../../driv + + oprofile-y := $(DRIVER_OBJS) init.o backtrace.o + oprofile-$(CONFIG_PERFMON) += perfmon.o ++ifeq ($(CONFIG_XEN), y) ++oprofile-$(CONFIG_PERFMON) += xenoprof.o \ ++ ../../../drivers/xen/xenoprof/xenoprofile.o ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/oprofile/init.c +--- a/arch/ia64/oprofile/init.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/oprofile/init.c Wed Aug 08 16:25:28 2007 -0300 +@@ -11,6 +11,7 @@ + #include <linux/oprofile.h> + #include <linux/init.h> + #include <linux/errno.h> ++#include "oprofile_perfmon.h" + + extern int perfmon_init(struct oprofile_operations * ops); + extern void perfmon_exit(void); +@@ -19,6 +20,13 @@ int __init oprofile_arch_init(struct opr + int __init oprofile_arch_init(struct oprofile_operations * ops) + { + int ret = -ENODEV; ++ ++ if (is_running_on_xen()) { ++ ret = xen_perfmon_init(); ++ if (ret) ++ return ret; ++ return xenoprofile_init(ops); ++ } + + #ifdef CONFIG_PERFMON + /* perfmon_init() can fail, but we have no way to report it */ +@@ -32,6 +40,12 @@ int __init oprofile_arch_init(struct opr + + void oprofile_arch_exit(void) + { ++ if (is_running_on_xen()) { ++ xenoprofile_exit(); ++ xen_perfmon_exit(); ++ return; ++ } ++ + #ifdef CONFIG_PERFMON + perfmon_exit(); + #endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/oprofile/oprofile_perfmon.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/oprofile/oprofile_perfmon.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,28 @@ ++#ifndef OPROFILE_PERFMON_H ++#define OPROFILE_PERFMON_H ++ ++#ifdef CONFIG_PERFMON ++int __perfmon_init(void); ++void __perfmon_exit(void); ++int perfmon_start(void); ++void perfmon_stop(void); ++#else ++#define __perfmon_init() (-ENOSYS) ++#define __perfmon_exit() do {} while (0) ++#endif /* CONFIG_PERFMON */ ++ ++#ifdef CONFIG_XEN ++#define STATIC_IF_NO_XEN /* nothing */ ++#define xen_perfmon_init() __perfmon_init() ++#define xen_perfmon_exit() __perfmon_exit() ++extern int xenoprofile_init(struct oprofile_operations * ops); ++extern void xenoprofile_exit(void); ++#else ++#define STATIC_IF_NO_XEN static ++#define xen_perfmon_init() (-ENOSYS) ++#define xen_perfmon_exit() do {} while (0) ++#define xenoprofile_init() (-ENOSYS) ++#define xenoprofile_exit() do {} while (0) ++#endif /* CONFIG_XEN */ ++ ++#endif /* OPROFILE_PERFMON_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/oprofile/perfmon.c +--- a/arch/ia64/oprofile/perfmon.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/oprofile/perfmon.c Wed Aug 08 16:25:28 2007 -0300 +@@ -13,6 +13,7 @@ + #include <asm/perfmon.h> + #include <asm/ptrace.h> + #include <asm/errno.h> ++#include "oprofile_perfmon.h" + + static int allow_ints; + +@@ -33,14 +34,16 @@ perfmon_handler(struct task_struct *task + } + + +-static int perfmon_start(void) ++STATIC_IF_NO_XEN ++int perfmon_start(void) + { + allow_ints = 1; + return 0; + } + + +-static void perfmon_stop(void) ++STATIC_IF_NO_XEN ++void perfmon_stop(void) + { + allow_ints = 0; + } +@@ -75,16 +78,35 @@ static char * get_cpu_type(void) + + static int using_perfmon; + ++STATIC_IF_NO_XEN ++int __perfmon_init(void) ++{ ++ int ret = pfm_register_buffer_fmt(&oprofile_fmt); ++ if (ret) ++ return -ENODEV; ++ ++ using_perfmon = 1; ++ return 0; ++} ++ ++STATIC_IF_NO_XEN ++void __perfmon_exit(void) ++{ ++ if (!using_perfmon) ++ return; ++ ++ pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); ++} ++ + int perfmon_init(struct oprofile_operations * ops) + { +- int ret = pfm_register_buffer_fmt(&oprofile_fmt); ++ int ret = __perfmon_init(); + if (ret) + return -ENODEV; + + ops->cpu_type = get_cpu_type(); + ops->start = perfmon_start; + ops->stop = perfmon_stop; +- using_perfmon = 1; + printk(KERN_INFO "oprofile: using perfmon.\n"); + return 0; + } +@@ -92,8 +114,5 @@ int perfmon_init(struct oprofile_operati + + void perfmon_exit(void) + { +- if (!using_perfmon) +- return; +- +- pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); ++ __perfmon_exit(); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/oprofile/xenoprof.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/oprofile/xenoprof.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,142 @@ ++/****************************************************************************** ++ * xenoprof ia64 specific part ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#include <linux/init.h> ++#include <linux/oprofile.h> ++#include <linux/ioport.h> ++ ++#include <xen/driver_util.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/xenoprof.h> ++#include <xen/xenoprof.h> ++ ++#include "oprofile_perfmon.h" ++ ++void __init xenoprof_arch_init_counter(struct xenoprof_init *init) ++{ ++ init->num_events = 0; /* perfmon manages. */ ++} ++ ++void xenoprof_arch_counter(void) ++{ ++ /* nothing. perfmon does. */ ++} ++ ++void xenoprof_arch_start(void) ++{ ++ perfmon_start(); ++} ++ ++void xenoprof_arch_stop(void) ++{ ++ perfmon_stop(); ++} ++ ++/* XXX move them to an appropriate header file. */ ++struct resource* xen_ia64_allocate_resource(unsigned long size); ++void xen_ia64_release_resource(struct resource* res); ++void xen_ia64_unmap_resource(struct resource* res); ++ ++struct resource* ++xenoprof_ia64_allocate_resource(int32_t max_samples) ++{ ++ unsigned long bufsize; ++ ++ /* XXX add hypercall to get bufsize? */ ++ /* this value is taken from alloc_xenoprof_struct(). */ ++#if 0 ++ bufsize = NR_CPUS * (sizeof(struct xenoprof_buf) + ++ (max_samples - 1) * sizeof(struct event_log)); ++ bufsize = PAGE_ALIGN(bufsize) + PAGE_SIZE; ++#else ++#define MAX_OPROF_SHARED_PAGES 32 ++ bufsize = (MAX_OPROF_SHARED_PAGES + 1) * PAGE_SIZE; ++#endif ++ return xen_ia64_allocate_resource(bufsize); ++} ++ ++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf) ++{ ++ if (sbuf->buffer) { ++ xen_ia64_unmap_resource(sbuf->arch.res); ++ sbuf->buffer = NULL; ++ sbuf->arch.res = NULL; ++ } ++} ++ ++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, ++ struct xenoprof_shared_buffer* sbuf) ++{ ++ int ret; ++ struct resource* res; ++ ++ sbuf->buffer = NULL; ++ sbuf->arch.res = NULL; ++ ++ res = xenoprof_ia64_allocate_resource(get_buffer->max_samples); ++ if (IS_ERR(res)) ++ return PTR_ERR(res); ++ ++ get_buffer->buf_gmaddr = res->start; ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, get_buffer); ++ if (ret) { ++ xen_ia64_release_resource(res); ++ return ret; ++ } ++ ++ BUG_ON((res->end - res->start + 1) < ++ get_buffer->bufsize * get_buffer->nbuf); ++ ++ sbuf->buffer = __va(res->start); ++ sbuf->arch.res = res; ++ ++ return ret; ++} ++ ++int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, ++ struct xenoprof_shared_buffer* sbuf) ++{ ++ int ret; ++ struct resource* res; ++ ++ sbuf->buffer = NULL; ++ sbuf->arch.res = NULL; ++ ++ res = xenoprof_ia64_allocate_resource(pdomain->max_samples); ++ if (IS_ERR(res)) ++ return PTR_ERR(res); ++ ++ pdomain->buf_gmaddr = res->start; ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive, pdomain); ++ if (ret) { ++ xen_ia64_release_resource(res); ++ return ret; ++ } ++ ++ BUG_ON((res->end - res->start + 1) < pdomain->bufsize * pdomain->nbuf); ++ ++ sbuf->buffer = __va(res->start); ++ sbuf->arch.res = res; ++ ++ return ret; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/pci/pci.c +--- a/arch/ia64/pci/pci.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/ia64/pci/pci.c Wed Aug 08 16:25:28 2007 -0300 +@@ -609,6 +609,14 @@ pci_mmap_page_range (struct pci_dev *dev + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + ++ if (is_initial_xendomain()) { ++ unsigned long addr = vma->vm_pgoff << PAGE_SHIFT; ++ size_t size = vma->vm_end - vma->vm_start; ++ unsigned long offset = HYPERVISOR_ioremap(addr, size); ++ if (IS_ERR_VALUE(offset)) ++ return offset; ++ } ++ + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; +@@ -665,6 +673,14 @@ pci_mmap_legacy_page_range(struct pci_bu + + vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT; + vma->vm_page_prot = prot; ++ ++ if (is_initial_xendomain()) { ++ unsigned long addr = vma->vm_pgoff << PAGE_SHIFT; ++ size_t size = vma->vm_end - vma->vm_start; ++ unsigned long offset = HYPERVISOR_ioremap(addr, size); ++ if (IS_ERR_VALUE(offset)) ++ return offset; ++ } + + if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + size, vma->vm_page_prot)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,9 @@ ++# ++# Makefile for Xen components ++# ++ ++obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \ ++ hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \ ++ xcom_mini.o xcom_privcmd.o mem.o ++ ++pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/hypercall.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/hypercall.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,170 @@ ++/* ++ * Support routines for Xen hypercalls ++ * ++ * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer@hp.com> ++ */ ++ ++#include <asm/processor.h> ++#include <asm/asmmacro.h> ++ ++GLOBAL_ENTRY(xen_get_psr) ++ XEN_HYPER_GET_PSR ++ br.ret.sptk.many rp ++ ;; ++END(xen_get_psr) ++ ++GLOBAL_ENTRY(xen_get_ivr) ++ XEN_HYPER_GET_IVR ++ br.ret.sptk.many rp ++ ;; ++END(xen_get_ivr) ++ ++GLOBAL_ENTRY(xen_get_tpr) ++ XEN_HYPER_GET_TPR ++ br.ret.sptk.many rp ++ ;; ++END(xen_get_tpr) ++ ++GLOBAL_ENTRY(xen_set_tpr) ++ mov r8=r32 ++ XEN_HYPER_SET_TPR ++ br.ret.sptk.many rp ++ ;; ++END(xen_set_tpr) ++ ++GLOBAL_ENTRY(xen_eoi) ++ mov r8=r32 ++ XEN_HYPER_EOI ++ br.ret.sptk.many rp ++ ;; ++END(xen_eoi) ++ ++GLOBAL_ENTRY(xen_thash) ++ mov r8=r32 ++ XEN_HYPER_THASH ++ br.ret.sptk.many rp ++ ;; ++END(xen_thash) ++ ++GLOBAL_ENTRY(xen_set_itm) ++ mov r8=r32 ++ XEN_HYPER_SET_ITM ++ br.ret.sptk.many rp ++ ;; ++END(xen_set_itm) ++ ++GLOBAL_ENTRY(xen_ptcga) ++ mov r8=r32 ++ mov r9=r33 ++ XEN_HYPER_PTC_GA ++ br.ret.sptk.many rp ++ ;; ++END(xen_ptcga) ++ ++GLOBAL_ENTRY(xen_get_rr) ++ mov r8=r32 ++ XEN_HYPER_GET_RR ++ br.ret.sptk.many rp ++ ;; ++END(xen_get_rr) ++ ++GLOBAL_ENTRY(xen_set_rr) ++ mov r8=r32 ++ mov r9=r33 ++ XEN_HYPER_SET_RR ++ br.ret.sptk.many rp ++ ;; ++END(xen_set_rr) ++ ++GLOBAL_ENTRY(xen_set_kr) ++ mov r8=r32 ++ mov r9=r33 ++ XEN_HYPER_SET_KR ++ br.ret.sptk.many rp ++END(xen_set_kr) ++ ++GLOBAL_ENTRY(xen_fc) ++ mov r8=r32 ++ XEN_HYPER_FC ++ br.ret.sptk.many rp ++END(xen_fc) ++ ++GLOBAL_ENTRY(xen_get_cpuid) ++ mov r8=r32 ++ XEN_HYPER_GET_CPUID ++ br.ret.sptk.many rp ++END(xen_get_cpuid) ++ ++GLOBAL_ENTRY(xen_get_pmd) ++ mov r8=r32 ++ XEN_HYPER_GET_PMD ++ br.ret.sptk.many rp ++END(xen_get_pmd) ++ ++#ifdef CONFIG_IA32_SUPPORT ++GLOBAL_ENTRY(xen_get_eflag) ++ XEN_HYPER_GET_EFLAG ++ br.ret.sptk.many rp ++END(xen_get_eflag) ++ ++// some bits aren't set if pl!=0, see SDM vol1 3.1.8 ++GLOBAL_ENTRY(xen_set_eflag) ++ mov r8=r32 ++ XEN_HYPER_SET_EFLAG ++ br.ret.sptk.many rp ++END(xen_set_eflag) ++#endif ++ ++GLOBAL_ENTRY(xen_send_ipi) ++ mov r14=r32 ++ mov r15=r33 ++ mov r2=0x400 ++ break 0x1000 ++ ;; ++ br.ret.sptk.many rp ++ ;; ++END(xen_send_ipi) ++ ++#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT ++// Those are vdso specialized. ++// In fsys mode, call, ret can't be used. ++ ++ // see xen_ssm_i() in privop.h ++ // r22 = &vcpu->vcpu_info->evtchn_upcall_mask ++ // r23 = &vpsr.ic ++ // r24 = &vcpu->vcpu_info->evtchn_upcall_pending ++ // r25 = tmp ++ // r31 = tmp ++ // p11 = tmp ++ // p14 = tmp ++#define XEN_SET_PSR_I \ ++ ld1 r31=[r22]; \ ++ ld1 r25=[r24]; \ ++ ;; \ ++ st1 [r22]=r0; \ ++ cmp.ne.unc p14,p0=r0,r31; \ ++ ;; \ ++(p14) cmp.ne.unc p11,p0=r0,r25; \ ++ ;; \ ++(p11) st1 [r22]=r20; \ ++(p11) XEN_HYPER_SSM_I; ++ ++GLOBAL_ENTRY(xen_ssm_i_0) ++ XEN_SET_PSR_I ++ brl.cond.sptk .vdso_ssm_i_0_ret ++ ;; ++END(xen_ssm_i_0) ++ ++GLOBAL_ENTRY(xen_ssm_i_1) ++ XEN_SET_PSR_I ++ brl.cond.sptk .vdso_ssm_i_1_ret ++ ;; ++END(xen_ssm_i_1) ++ ++GLOBAL_ENTRY(__hypercall) ++ mov r2=r37 ++ break 0x1000 ++ br.ret.sptk.many b0 ++ ;; ++END(__hypercall) ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/hypervisor.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/hypervisor.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1183 @@ ++/****************************************************************************** ++ * include/asm-ia64/shadow.h ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++//#include <linux/kernel.h> ++#include <linux/spinlock.h> ++#include <linux/bootmem.h> ++#include <linux/module.h> ++#include <linux/vmalloc.h> ++#include <linux/efi.h> ++#include <asm/page.h> ++#include <asm/pgalloc.h> ++#include <asm/meminit.h> ++#include <asm/hypervisor.h> ++#include <asm/hypercall.h> ++#include <xen/interface/memory.h> ++#include <xen/balloon.h> ++ ++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)XSI_BASE; ++EXPORT_SYMBOL(HYPERVISOR_shared_info); ++ ++start_info_t *xen_start_info; ++EXPORT_SYMBOL(xen_start_info); ++ ++int running_on_xen; ++EXPORT_SYMBOL(running_on_xen); ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M ++static int p2m_expose_init(void); ++#else ++#define p2m_expose_init() (-ENOSYS) ++#endif ++ ++EXPORT_SYMBOL(__hypercall); ++ ++//XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear() ++// move those to lib/contiguous_bitmap? ++//XXX discontigmem/sparsemem ++ ++/* ++ * Bitmap is indexed by page number. If bit is set, the page is part of a ++ * xen_create_contiguous_region() area of memory. ++ */ ++unsigned long *contiguous_bitmap; ++ ++#ifdef CONFIG_VIRTUAL_MEM_MAP ++/* Following logic is stolen from create_mem_map_table() for virtual memmap */ ++static int ++create_contiguous_bitmap(u64 start, u64 end, void *arg) ++{ ++ unsigned long address, start_page, end_page; ++ unsigned long bitmap_start, bitmap_end; ++ unsigned char *bitmap; ++ int node; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ bitmap_start = (unsigned long)contiguous_bitmap + ++ ((__pa(start) >> PAGE_SHIFT) >> 3); ++ bitmap_end = (unsigned long)contiguous_bitmap + ++ (((__pa(end) >> PAGE_SHIFT) + 2 * BITS_PER_LONG) >> 3); ++ ++ start_page = bitmap_start & PAGE_MASK; ++ end_page = PAGE_ALIGN(bitmap_end); ++ node = paddr_to_nid(__pa(start)); ++ ++ bitmap = alloc_bootmem_pages_node(NODE_DATA(node), ++ end_page - start_page); ++ BUG_ON(!bitmap); ++ memset(bitmap, 0, end_page - start_page); ++ ++ for (address = start_page; address < end_page; address += PAGE_SIZE) { ++ pgd = pgd_offset_k(address); ++ if (pgd_none(*pgd)) ++ pgd_populate(&init_mm, pgd, ++ alloc_bootmem_pages_node(NODE_DATA(node), ++ PAGE_SIZE)); ++ pud = pud_offset(pgd, address); ++ ++ if (pud_none(*pud)) ++ pud_populate(&init_mm, pud, ++ alloc_bootmem_pages_node(NODE_DATA(node), ++ PAGE_SIZE)); ++ pmd = pmd_offset(pud, address); ++ ++ if (pmd_none(*pmd)) ++ pmd_populate_kernel(&init_mm, pmd, ++ alloc_bootmem_pages_node ++ (NODE_DATA(node), PAGE_SIZE)); ++ pte = pte_offset_kernel(pmd, address); ++ ++ if (pte_none(*pte)) ++ set_pte(pte, ++ pfn_pte(__pa(bitmap + (address - start_page)) ++ >> PAGE_SHIFT, PAGE_KERNEL)); ++ } ++ return 0; ++} ++#endif ++ ++static void ++__contiguous_bitmap_init(unsigned long size) ++{ ++ contiguous_bitmap = alloc_bootmem_pages(size); ++ BUG_ON(!contiguous_bitmap); ++ memset(contiguous_bitmap, 0, size); ++} ++ ++void ++contiguous_bitmap_init(unsigned long end_pfn) ++{ ++ unsigned long size = (end_pfn + 2 * BITS_PER_LONG) >> 3; ++#ifndef CONFIG_VIRTUAL_MEM_MAP ++ __contiguous_bitmap_init(size); ++#else ++ unsigned long max_gap = 0; ++ ++ efi_memmap_walk(find_largest_hole, (u64*)&max_gap); ++ if (max_gap < LARGE_GAP) { ++ __contiguous_bitmap_init(size); ++ } else { ++ unsigned long map_size = PAGE_ALIGN(size); ++ vmalloc_end -= map_size; ++ contiguous_bitmap = (unsigned long*)vmalloc_end; ++ efi_memmap_walk(create_contiguous_bitmap, NULL); ++ } ++#endif ++} ++ ++#if 0 ++int ++contiguous_bitmap_test(void* p) ++{ ++ return test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap); ++} ++#endif ++ ++static void contiguous_bitmap_set( ++ unsigned long first_page, unsigned long nr_pages) ++{ ++ unsigned long start_off, end_off, curr_idx, end_idx; ++ ++ curr_idx = first_page / BITS_PER_LONG; ++ start_off = first_page & (BITS_PER_LONG-1); ++ end_idx = (first_page + nr_pages) / BITS_PER_LONG; ++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1); ++ ++ if (curr_idx == end_idx) { ++ contiguous_bitmap[curr_idx] |= ++ ((1UL<<end_off)-1) & -(1UL<<start_off); ++ } else { ++ contiguous_bitmap[curr_idx] |= -(1UL<<start_off); ++ while ( ++curr_idx < end_idx ) ++ contiguous_bitmap[curr_idx] = ~0UL; ++ contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1; ++ } ++} ++ ++static void contiguous_bitmap_clear( ++ unsigned long first_page, unsigned long nr_pages) ++{ ++ unsigned long start_off, end_off, curr_idx, end_idx; ++ ++ curr_idx = first_page / BITS_PER_LONG; ++ start_off = first_page & (BITS_PER_LONG-1); ++ end_idx = (first_page + nr_pages) / BITS_PER_LONG; ++ end_off = (first_page + nr_pages) & (BITS_PER_LONG-1); ++ ++ if (curr_idx == end_idx) { ++ contiguous_bitmap[curr_idx] &= ++ -(1UL<<end_off) | ((1UL<<start_off)-1); ++ } else { ++ contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1; ++ while ( ++curr_idx != end_idx ) ++ contiguous_bitmap[curr_idx] = 0; ++ contiguous_bitmap[curr_idx] &= -(1UL<<end_off); ++ } ++} ++ ++// __xen_create_contiguous_region(), __xen_destroy_contiguous_region() ++// are based on i386 xen_create_contiguous_region(), ++// xen_destroy_contiguous_region() ++ ++/* Protected by balloon_lock. */ ++#define MAX_CONTIG_ORDER 7 ++static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER]; ++ ++/* Ensure multi-page extents are contiguous in machine memory. */ ++int ++__xen_create_contiguous_region(unsigned long vstart, ++ unsigned int order, unsigned int address_bits) ++{ ++ unsigned long error = 0; ++ unsigned long gphys = __pa(vstart); ++ unsigned long start_gpfn = gphys >> PAGE_SHIFT; ++ unsigned long num_gpfn = 1 << order; ++ unsigned long i; ++ unsigned long flags; ++ ++ unsigned long *in_frames = discontig_frames, out_frame; ++ int success; ++ struct xen_memory_exchange exchange = { ++ .in = { ++ .nr_extents = num_gpfn, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }, ++ .out = { ++ .nr_extents = 1, ++ .extent_order = order, ++ .address_bits = address_bits, ++ .domid = DOMID_SELF ++ }, ++ .nr_exchanged = 0 ++ }; ++ ++ if (unlikely(order > MAX_CONTIG_ORDER)) ++ return -ENOMEM; ++ ++ set_xen_guest_handle(exchange.in.extent_start, in_frames); ++ set_xen_guest_handle(exchange.out.extent_start, &out_frame); ++ ++ scrub_pages(vstart, num_gpfn); ++ ++ balloon_lock(flags); ++ ++ /* Get a new contiguous memory extent. */ ++ for (i = 0; i < num_gpfn; i++) { ++ in_frames[i] = start_gpfn + i; ++ } ++ out_frame = start_gpfn; ++ error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); ++ success = (exchange.nr_exchanged == num_gpfn); ++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (error == 0))); ++ BUG_ON(success && (error != 0)); ++ if (unlikely(error == -ENOSYS)) { ++ /* Compatibility when XENMEM_exchange is unsupported. */ ++ error = HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &exchange.in); ++ BUG_ON(error != num_gpfn); ++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.out); ++ if (error != 1) { ++ /* Couldn't get special memory: fall back to normal. */ ++ for (i = 0; i < num_gpfn; i++) { ++ in_frames[i] = start_gpfn + i; ++ } ++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.in); ++ BUG_ON(error != num_gpfn); ++ success = 0; ++ } else ++ success = 1; ++ } ++ if (success) ++ contiguous_bitmap_set(start_gpfn, num_gpfn); ++#if 0 ++ if (success) { ++ unsigned long mfn; ++ unsigned long mfn_prev = ~0UL; ++ for (i = 0; i < num_gpfn; i++) { ++ mfn = pfn_to_mfn_for_dma(start_gpfn + i); ++ if (mfn_prev != ~0UL && mfn != mfn_prev + 1) { ++ xprintk("\n"); ++ xprintk("%s:%d order %d " ++ "start 0x%lx bus 0x%lx " ++ "machine 0x%lx\n", ++ __func__, __LINE__, order, ++ vstart, virt_to_bus((void*)vstart), ++ phys_to_machine_for_dma(gphys)); ++ xprintk("mfn: "); ++ for (i = 0; i < num_gpfn; i++) { ++ mfn = pfn_to_mfn_for_dma( ++ start_gpfn + i); ++ xprintk("0x%lx ", mfn); ++ } ++ xprintk("\n"); ++ break; ++ } ++ mfn_prev = mfn; ++ } ++ } ++#endif ++ balloon_unlock(flags); ++ return success? 0: -ENOMEM; ++} ++ ++void ++__xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) ++{ ++ unsigned long flags; ++ unsigned long error = 0; ++ unsigned long start_gpfn = __pa(vstart) >> PAGE_SHIFT; ++ unsigned long num_gpfn = 1UL << order; ++ unsigned long i; ++ ++ unsigned long *out_frames = discontig_frames, in_frame; ++ int success; ++ struct xen_memory_exchange exchange = { ++ .in = { ++ .nr_extents = 1, ++ .extent_order = order, ++ .domid = DOMID_SELF ++ }, ++ .out = { ++ .nr_extents = num_gpfn, ++ .extent_order = 0, ++ .address_bits = 0, ++ .domid = DOMID_SELF ++ }, ++ .nr_exchanged = 0 ++ }; ++ ++ ++ if (!test_bit(start_gpfn, contiguous_bitmap)) ++ return; ++ ++ if (unlikely(order > MAX_CONTIG_ORDER)) ++ return; ++ ++ set_xen_guest_handle(exchange.in.extent_start, &in_frame); ++ set_xen_guest_handle(exchange.out.extent_start, out_frames); ++ ++ scrub_pages(vstart, num_gpfn); ++ ++ balloon_lock(flags); ++ ++ contiguous_bitmap_clear(start_gpfn, num_gpfn); ++ ++ /* Do the exchange for non-contiguous MFNs. */ ++ in_frame = start_gpfn; ++ for (i = 0; i < num_gpfn; i++) { ++ out_frames[i] = start_gpfn + i; ++ } ++ error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange); ++ success = (exchange.nr_exchanged == 1); ++ BUG_ON(!success && ((exchange.nr_exchanged != 0) || (error == 0))); ++ BUG_ON(success && (error != 0)); ++ if (unlikely(error == -ENOSYS)) { ++ /* Compatibility when XENMEM_exchange is unsupported. */ ++ error = HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &exchange.in); ++ BUG_ON(error != 1); ++ ++ error = HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &exchange.out); ++ BUG_ON(error != num_gpfn); ++ } ++ balloon_unlock(flags); ++} ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// grant table hack ++// cmd: GNTTABOP_xxx ++ ++#include <linux/mm.h> ++#include <xen/interface/xen.h> ++#include <xen/gnttab.h> ++ ++static void ++gnttab_map_grant_ref_pre(struct gnttab_map_grant_ref *uop) ++{ ++ uint32_t flags; ++ ++ flags = uop->flags; ++ ++ if (flags & GNTMAP_host_map) { ++ if (flags & GNTMAP_application_map) { ++ xprintd("GNTMAP_application_map is not supported yet: flags 0x%x\n", flags); ++ BUG(); ++ } ++ if (flags & GNTMAP_contains_pte) { ++ xprintd("GNTMAP_contains_pte is not supported yet flags 0x%x\n", flags); ++ BUG(); ++ } ++ } else if (flags & GNTMAP_device_map) { ++ xprintd("GNTMAP_device_map is not supported yet 0x%x\n", flags); ++ BUG();//XXX not yet. actually this flag is not used. ++ } else { ++ BUG(); ++ } ++} ++ ++int ++HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count) ++{ ++ if (cmd == GNTTABOP_map_grant_ref) { ++ unsigned int i; ++ for (i = 0; i < count; i++) { ++ gnttab_map_grant_ref_pre( ++ (struct gnttab_map_grant_ref*)uop + i); ++ } ++ } ++ return xencomm_mini_hypercall_grant_table_op(cmd, uop, count); ++} ++EXPORT_SYMBOL(HYPERVISOR_grant_table_op); ++ ++/////////////////////////////////////////////////////////////////////////// ++// foreign mapping ++#include <linux/efi.h> ++#include <asm/meminit.h> // for IA64_GRANULE_SIZE, GRANULEROUND{UP,DOWN}() ++ ++static unsigned long privcmd_resource_min = 0; ++// Xen/ia64 currently can handle pseudo physical address bits up to ++// (PAGE_SHIFT * 3) ++static unsigned long privcmd_resource_max = GRANULEROUNDDOWN((1UL << (PAGE_SHIFT * 3)) - 1); ++static unsigned long privcmd_resource_align = IA64_GRANULE_SIZE; ++ ++static unsigned long ++md_end_addr(const efi_memory_desc_t *md) ++{ ++ return md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); ++} ++ ++#define XEN_IA64_PRIVCMD_LEAST_GAP_SIZE (1024 * 1024 * 1024UL) ++static int ++xen_ia64_privcmd_check_size(unsigned long start, unsigned long end) ++{ ++ return (start < end && ++ (end - start) > XEN_IA64_PRIVCMD_LEAST_GAP_SIZE); ++} ++ ++static int __init ++xen_ia64_privcmd_init(void) ++{ ++ void *efi_map_start, *efi_map_end, *p; ++ u64 efi_desc_size; ++ efi_memory_desc_t *md; ++ unsigned long tmp_min; ++ unsigned long tmp_max; ++ unsigned long gap_size; ++ unsigned long prev_end; ++ ++ if (!is_running_on_xen()) ++ return -1; ++ ++ efi_map_start = __va(ia64_boot_param->efi_memmap); ++ efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; ++ efi_desc_size = ia64_boot_param->efi_memdesc_size; ++ ++ // at first check the used highest address ++ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { ++ // nothing ++ } ++ md = p - efi_desc_size; ++ privcmd_resource_min = GRANULEROUNDUP(md_end_addr(md)); ++ if (xen_ia64_privcmd_check_size(privcmd_resource_min, ++ privcmd_resource_max)) { ++ goto out; ++ } ++ ++ // the used highest address is too large. try to find the largest gap. ++ tmp_min = privcmd_resource_max; ++ tmp_max = 0; ++ gap_size = 0; ++ prev_end = 0; ++ for (p = efi_map_start; ++ p < efi_map_end - efi_desc_size; ++ p += efi_desc_size) { ++ unsigned long end; ++ efi_memory_desc_t* next; ++ unsigned long next_start; ++ ++ md = p; ++ end = md_end_addr(md); ++ if (end > privcmd_resource_max) { ++ break; ++ } ++ if (end < prev_end) { ++ // work around. ++ // Xen may pass incompletely sorted memory ++ // descriptors like ++ // [x, x + length] ++ // [x, x] ++ // this order should be reversed. ++ continue; ++ } ++ next = p + efi_desc_size; ++ next_start = next->phys_addr; ++ if (next_start > privcmd_resource_max) { ++ next_start = privcmd_resource_max; ++ } ++ if (end < next_start && gap_size < (next_start - end)) { ++ tmp_min = end; ++ tmp_max = next_start; ++ gap_size = tmp_max - tmp_min; ++ } ++ prev_end = end; ++ } ++ ++ privcmd_resource_min = GRANULEROUNDUP(tmp_min); ++ if (xen_ia64_privcmd_check_size(privcmd_resource_min, tmp_max)) { ++ privcmd_resource_max = tmp_max; ++ goto out; ++ } ++ ++ privcmd_resource_min = tmp_min; ++ privcmd_resource_max = tmp_max; ++ if (!xen_ia64_privcmd_check_size(privcmd_resource_min, ++ privcmd_resource_max)) { ++ // Any large enough gap isn't found. ++ // go ahead anyway with the warning hoping that large region ++ // won't be requested. ++ printk(KERN_WARNING "xen privcmd: large enough region for privcmd mmap is not found.\n"); ++ } ++ ++out: ++ printk(KERN_INFO "xen privcmd uses pseudo physical addr range [0x%lx, 0x%lx] (%ldMB)\n", ++ privcmd_resource_min, privcmd_resource_max, ++ (privcmd_resource_max - privcmd_resource_min) >> 20); ++ BUG_ON(privcmd_resource_min >= privcmd_resource_max); ++ ++ // XXX this should be somewhere appropriate ++ (void)p2m_expose_init(); ++ ++ return 0; ++} ++late_initcall(xen_ia64_privcmd_init); ++ ++struct xen_ia64_privcmd_entry { ++ atomic_t map_count; ++#define INVALID_GPFN (~0UL) ++ unsigned long gpfn; ++}; ++ ++struct xen_ia64_privcmd_range { ++ atomic_t ref_count; ++ unsigned long pgoff; // in PAGE_SIZE ++ struct resource* res; ++ ++ unsigned long num_entries; ++ struct xen_ia64_privcmd_entry entries[0]; ++}; ++ ++struct xen_ia64_privcmd_vma { ++ int is_privcmd_mmapped; ++ struct xen_ia64_privcmd_range* range; ++ ++ unsigned long num_entries; ++ struct xen_ia64_privcmd_entry* entries; ++}; ++ ++static void ++xen_ia64_privcmd_init_entry(struct xen_ia64_privcmd_entry* entry) ++{ ++ atomic_set(&entry->map_count, 0); ++ entry->gpfn = INVALID_GPFN; ++} ++ ++static int ++xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma, ++ unsigned long addr, ++ struct xen_ia64_privcmd_range* privcmd_range, ++ int i, ++ unsigned long gmfn, ++ pgprot_t prot, ++ domid_t domid) ++{ ++ int error = 0; ++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i]; ++ unsigned long gpfn; ++ unsigned long flags; ++ ++ if ((addr & ~PAGE_MASK) != 0 || gmfn == INVALID_MFN) { ++ error = -EINVAL; ++ goto out; ++ } ++ ++ if (entry->gpfn != INVALID_GPFN) { ++ error = -EBUSY; ++ goto out; ++ } ++ gpfn = (privcmd_range->res->start >> PAGE_SHIFT) + i; ++ ++ flags = ASSIGN_writable; ++ if (pgprot_val(prot) == PROT_READ) { ++ flags = ASSIGN_readonly; ++ } ++ error = HYPERVISOR_add_physmap_with_gmfn(gpfn, gmfn, flags, domid); ++ if (error != 0) { ++ goto out; ++ } ++ ++ prot = vma->vm_page_prot; ++ error = remap_pfn_range(vma, addr, gpfn, 1 << PAGE_SHIFT, prot); ++ if (error != 0) { ++ error = HYPERVISOR_zap_physmap(gpfn, 0); ++ if (error) { ++ BUG();//XXX ++ } ++ } else { ++ atomic_inc(&entry->map_count); ++ entry->gpfn = gpfn; ++ } ++ ++out: ++ return error; ++} ++ ++static void ++xen_ia64_privcmd_entry_munmap(struct xen_ia64_privcmd_range* privcmd_range, ++ int i) ++{ ++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i]; ++ unsigned long gpfn = entry->gpfn; ++ //gpfn = (privcmd_range->res->start >> PAGE_SHIFT) + ++ // (vma->vm_pgoff - privcmd_range->pgoff); ++ int error; ++ ++ error = HYPERVISOR_zap_physmap(gpfn, 0); ++ if (error) { ++ BUG();//XXX ++ } ++ entry->gpfn = INVALID_GPFN; ++} ++ ++static void ++xen_ia64_privcmd_entry_open(struct xen_ia64_privcmd_range* privcmd_range, ++ int i) ++{ ++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i]; ++ if (entry->gpfn != INVALID_GPFN) { ++ atomic_inc(&entry->map_count); ++ } else { ++ BUG_ON(atomic_read(&entry->map_count) != 0); ++ } ++} ++ ++static void ++xen_ia64_privcmd_entry_close(struct xen_ia64_privcmd_range* privcmd_range, ++ int i) ++{ ++ struct xen_ia64_privcmd_entry* entry = &privcmd_range->entries[i]; ++ if (entry->gpfn != INVALID_GPFN && ++ atomic_dec_and_test(&entry->map_count)) { ++ xen_ia64_privcmd_entry_munmap(privcmd_range, i); ++ } ++} ++ ++static void xen_ia64_privcmd_vma_open(struct vm_area_struct* vma); ++static void xen_ia64_privcmd_vma_close(struct vm_area_struct* vma); ++ ++struct vm_operations_struct xen_ia64_privcmd_vm_ops = { ++ .open = &xen_ia64_privcmd_vma_open, ++ .close = &xen_ia64_privcmd_vma_close, ++}; ++ ++static void ++__xen_ia64_privcmd_vma_open(struct vm_area_struct* vma, ++ struct xen_ia64_privcmd_vma* privcmd_vma, ++ struct xen_ia64_privcmd_range* privcmd_range) ++{ ++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff; ++ unsigned long num_entries = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long i; ++ ++ BUG_ON(entry_offset < 0); ++ BUG_ON(entry_offset + num_entries > privcmd_range->num_entries); ++ ++ privcmd_vma->range = privcmd_range; ++ privcmd_vma->num_entries = num_entries; ++ privcmd_vma->entries = &privcmd_range->entries[entry_offset]; ++ vma->vm_private_data = privcmd_vma; ++ for (i = 0; i < privcmd_vma->num_entries; i++) { ++ xen_ia64_privcmd_entry_open(privcmd_range, entry_offset + i); ++ } ++ ++ vma->vm_private_data = privcmd_vma; ++ vma->vm_ops = &xen_ia64_privcmd_vm_ops; ++} ++ ++static void ++xen_ia64_privcmd_vma_open(struct vm_area_struct* vma) ++{ ++ struct xen_ia64_privcmd_vma* old_privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data; ++ struct xen_ia64_privcmd_vma* privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data; ++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range; ++ ++ atomic_inc(&privcmd_range->ref_count); ++ // vm_op->open() can't fail. ++ privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL); ++ // copy original value if necessary ++ privcmd_vma->is_privcmd_mmapped = old_privcmd_vma->is_privcmd_mmapped; ++ ++ __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range); ++} ++ ++static void ++xen_ia64_privcmd_vma_close(struct vm_area_struct* vma) ++{ ++ struct xen_ia64_privcmd_vma* privcmd_vma = ++ (struct xen_ia64_privcmd_vma*)vma->vm_private_data; ++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range; ++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff; ++ unsigned long i; ++ ++ for (i = 0; i < privcmd_vma->num_entries; i++) { ++ xen_ia64_privcmd_entry_close(privcmd_range, entry_offset + i); ++ } ++ vma->vm_private_data = NULL; ++ kfree(privcmd_vma); ++ ++ if (atomic_dec_and_test(&privcmd_range->ref_count)) { ++#if 1 ++ for (i = 0; i < privcmd_range->num_entries; i++) { ++ struct xen_ia64_privcmd_entry* entry = ++ &privcmd_range->entries[i]; ++ BUG_ON(atomic_read(&entry->map_count) != 0); ++ BUG_ON(entry->gpfn != INVALID_GPFN); ++ } ++#endif ++ release_resource(privcmd_range->res); ++ kfree(privcmd_range->res); ++ vfree(privcmd_range); ++ } ++} ++ ++int ++privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) ++{ ++ struct xen_ia64_privcmd_vma* privcmd_vma = ++ (struct xen_ia64_privcmd_vma *)vma->vm_private_data; ++ return (xchg(&privcmd_vma->is_privcmd_mmapped, 1) == 0); ++} ++ ++int ++privcmd_mmap(struct file * file, struct vm_area_struct * vma) ++{ ++ int error; ++ unsigned long size = vma->vm_end - vma->vm_start; ++ unsigned long num_entries = size >> PAGE_SHIFT; ++ struct xen_ia64_privcmd_range* privcmd_range = NULL; ++ struct xen_ia64_privcmd_vma* privcmd_vma = NULL; ++ struct resource* res = NULL; ++ unsigned long i; ++ BUG_ON(!is_running_on_xen()); ++ ++ BUG_ON(file->private_data != NULL); ++ ++ error = -ENOMEM; ++ privcmd_range = ++ vmalloc(sizeof(*privcmd_range) + ++ sizeof(privcmd_range->entries[0]) * num_entries); ++ if (privcmd_range == NULL) { ++ goto out_enomem0; ++ } ++ privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL); ++ if (privcmd_vma == NULL) { ++ goto out_enomem1; ++ } ++ privcmd_vma->is_privcmd_mmapped = 0; ++ ++ res = kzalloc(sizeof(*res), GFP_KERNEL); ++ if (res == NULL) { ++ goto out_enomem1; ++ } ++ res->name = "Xen privcmd mmap"; ++ error = allocate_resource(&iomem_resource, res, size, ++ privcmd_resource_min, privcmd_resource_max, ++ privcmd_resource_align, NULL, NULL); ++ if (error) { ++ goto out_enomem1; ++ } ++ privcmd_range->res = res; ++ ++ /* DONTCOPY is essential for Xen as copy_page_range is broken. */ ++ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; ++ ++ atomic_set(&privcmd_range->ref_count, 1); ++ privcmd_range->pgoff = vma->vm_pgoff; ++ privcmd_range->num_entries = num_entries; ++ for (i = 0; i < privcmd_range->num_entries; i++) { ++ xen_ia64_privcmd_init_entry(&privcmd_range->entries[i]); ++ } ++ ++ __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range); ++ return 0; ++ ++out_enomem1: ++ kfree(res); ++ kfree(privcmd_vma); ++out_enomem0: ++ vfree(privcmd_range); ++ return error; ++} ++ ++int ++direct_remap_pfn_range(struct vm_area_struct *vma, ++ unsigned long address, // process virtual address ++ unsigned long gmfn, // gmfn, gmfn + 1, ... gmfn + size/PAGE_SIZE ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid) // target domain ++{ ++ struct xen_ia64_privcmd_vma* privcmd_vma = ++ (struct xen_ia64_privcmd_vma*)vma->vm_private_data; ++ struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range; ++ unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff; ++ ++ unsigned long i; ++ unsigned long offset; ++ int error = 0; ++ BUG_ON(!is_running_on_xen()); ++ ++#if 0 ++ if (prot != vm->vm_page_prot) { ++ return -EINVAL; ++ } ++#endif ++ ++ i = (address - vma->vm_start) >> PAGE_SHIFT; ++ for (offset = 0; offset < size; offset += PAGE_SIZE) { ++ error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, privcmd_range, entry_offset + i, gmfn, prot, domid); ++ if (error != 0) { ++ break; ++ } ++ ++ i++; ++ gmfn++; ++ } ++ ++ return error; ++} ++ ++ ++/* Called after suspend, to resume time. */ ++void ++time_resume(void) ++{ ++ extern void ia64_cpu_local_tick(void); ++ ++ /* Just trigger a tick. */ ++ ia64_cpu_local_tick(); ++ ++ /* Time interpolator remembers the last timer status. Forget it */ ++ time_interpolator_reset(); ++} ++ ++/////////////////////////////////////////////////////////////////////////// ++// expose p2m table ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M ++#include <linux/cpu.h> ++#include <asm/uaccess.h> ++ ++int p2m_initialized __read_mostly = 0; ++ ++unsigned long p2m_min_low_pfn __read_mostly; ++unsigned long p2m_max_low_pfn __read_mostly; ++unsigned long p2m_convert_min_pfn __read_mostly; ++unsigned long p2m_convert_max_pfn __read_mostly; ++ ++static struct resource p2m_resource = { ++ .name = "Xen p2m table", ++ .flags = IORESOURCE_MEM, ++}; ++static unsigned long p2m_assign_start_pfn __read_mostly; ++static unsigned long p2m_assign_end_pfn __read_mostly; ++volatile const pte_t* p2m_pte __read_mostly; ++ ++#define GRNULE_PFN PTRS_PER_PTE ++static unsigned long p2m_granule_pfn __read_mostly = GRNULE_PFN; ++ ++#define ROUNDDOWN(x, y) ((x) & ~((y) - 1)) ++#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1)) ++ ++#define P2M_PREFIX "Xen p2m: " ++ ++static int xen_ia64_p2m_expose __read_mostly = 1; ++module_param(xen_ia64_p2m_expose, int, 0); ++MODULE_PARM_DESC(xen_ia64_p2m_expose, ++ "enable/disable xen/ia64 p2m exposure optimization\n"); ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++static int xen_ia64_p2m_expose_use_dtr __read_mostly = 1; ++module_param(xen_ia64_p2m_expose_use_dtr, int, 0); ++MODULE_PARM_DESC(xen_ia64_p2m_expose_use_dtr, ++ "use/unuse dtr to map exposed p2m table\n"); ++ ++static const int p2m_page_shifts[] = { ++ _PAGE_SIZE_4K, ++ _PAGE_SIZE_8K, ++ _PAGE_SIZE_16K, ++ _PAGE_SIZE_64K, ++ _PAGE_SIZE_256K, ++ _PAGE_SIZE_1M, ++ _PAGE_SIZE_4M, ++ _PAGE_SIZE_16M, ++ _PAGE_SIZE_64M, ++ _PAGE_SIZE_256M, ++}; ++ ++struct p2m_itr_arg { ++ unsigned long vaddr; ++ unsigned long pteval; ++ unsigned long log_page_size; ++}; ++static struct p2m_itr_arg p2m_itr_arg __read_mostly; ++ ++// This should be in asm-ia64/kregs.h ++#define IA64_TR_P2M_TABLE 3 ++ ++static void ++p2m_itr(void* info) ++{ ++ struct p2m_itr_arg* arg = (struct p2m_itr_arg*)info; ++ ia64_itr(0x2, IA64_TR_P2M_TABLE, ++ arg->vaddr, arg->pteval, arg->log_page_size); ++ ia64_srlz_d(); ++} ++ ++static int ++p2m_expose_dtr_call(struct notifier_block *self, ++ unsigned long event, void* ptr) ++{ ++ unsigned int cpu = (unsigned int)(long)ptr; ++ if (event != CPU_ONLINE) ++ return 0; ++ if (!(p2m_initialized && xen_ia64_p2m_expose_use_dtr)) ++ smp_call_function_single(cpu, &p2m_itr, &p2m_itr_arg, 1, 1); ++ return 0; ++} ++ ++static struct notifier_block p2m_expose_dtr_hotplug_notifier = { ++ .notifier_call = p2m_expose_dtr_call, ++ .next = NULL, ++ .priority = 0 ++}; ++#endif ++ ++static int ++p2m_expose_init(void) ++{ ++ unsigned long num_pfn; ++ unsigned long size = 0; ++ unsigned long p2m_size = 0; ++ unsigned long align = ~0UL; ++ int error = 0; ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++ int i; ++ unsigned long page_size; ++ unsigned long log_page_size = 0; ++#endif ++ ++ if (!xen_ia64_p2m_expose) ++ return -ENOSYS; ++ if (p2m_initialized) ++ return 0; ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++ error = register_cpu_notifier(&p2m_expose_dtr_hotplug_notifier); ++ if (error < 0) ++ return error; ++#endif ++ ++ lock_cpu_hotplug(); ++ if (p2m_initialized) ++ goto out; ++ ++#ifdef CONFIG_DISCONTIGMEM ++ p2m_min_low_pfn = min_low_pfn; ++ p2m_max_low_pfn = max_low_pfn; ++#else ++ p2m_min_low_pfn = 0; ++ p2m_max_low_pfn = max_pfn; ++#endif ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++ if (xen_ia64_p2m_expose_use_dtr) { ++ unsigned long granule_pfn = 0; ++ p2m_size = p2m_max_low_pfn - p2m_min_low_pfn; ++ for (i = 0; ++ i < sizeof(p2m_page_shifts)/sizeof(p2m_page_shifts[0]); ++ i++) { ++ log_page_size = p2m_page_shifts[i]; ++ page_size = 1UL << log_page_size; ++ if (page_size < p2m_size) ++ continue; ++ ++ granule_pfn = max(page_size >> PAGE_SHIFT, ++ p2m_granule_pfn); ++ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn, ++ granule_pfn); ++ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, ++ granule_pfn); ++ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn; ++ size = num_pfn << PAGE_SHIFT; ++ p2m_size = num_pfn / PTRS_PER_PTE; ++ p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT); ++ if (p2m_size == page_size) ++ break; ++ } ++ if (p2m_size != page_size) { ++ printk(KERN_ERR "p2m_size != page_size\n"); ++ error = -EINVAL; ++ goto out; ++ } ++ align = max(privcmd_resource_align, granule_pfn << PAGE_SHIFT); ++ } else ++#endif ++ { ++ BUG_ON(p2m_granule_pfn & (p2m_granule_pfn - 1)); ++ p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn, ++ p2m_granule_pfn); ++ p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn); ++ num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn; ++ size = num_pfn << PAGE_SHIFT; ++ p2m_size = num_pfn / PTRS_PER_PTE; ++ p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT); ++ align = max(privcmd_resource_align, ++ p2m_granule_pfn << PAGE_SHIFT); ++ } ++ ++ // use privcmd region ++ error = allocate_resource(&iomem_resource, &p2m_resource, p2m_size, ++ privcmd_resource_min, privcmd_resource_max, ++ align, NULL, NULL); ++ if (error) { ++ printk(KERN_ERR P2M_PREFIX ++ "can't allocate region for p2m exposure " ++ "[0x%016lx, 0x%016lx) 0x%016lx\n", ++ p2m_convert_min_pfn, p2m_convert_max_pfn, p2m_size); ++ goto out; ++ } ++ ++ p2m_assign_start_pfn = p2m_resource.start >> PAGE_SHIFT; ++ p2m_assign_end_pfn = p2m_resource.end >> PAGE_SHIFT; ++ ++ error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn, ++ p2m_assign_start_pfn, ++ size, p2m_granule_pfn); ++ if (error) { ++ printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n", ++ error); ++ printk(KERN_ERR P2M_PREFIX "conv 0x%016lx assign 0x%016lx " ++ "size 0x%016lx granule 0x%016lx\n", ++ p2m_convert_min_pfn, p2m_assign_start_pfn, ++ size, p2m_granule_pfn);; ++ release_resource(&p2m_resource); ++ goto out; ++ } ++ p2m_pte = (volatile const pte_t*)pfn_to_kaddr(p2m_assign_start_pfn); ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++ if (xen_ia64_p2m_expose_use_dtr) { ++ p2m_itr_arg.vaddr = (unsigned long)__va(p2m_assign_start_pfn ++ << PAGE_SHIFT); ++ p2m_itr_arg.pteval = pte_val(pfn_pte(p2m_assign_start_pfn, ++ PAGE_KERNEL)); ++ p2m_itr_arg.log_page_size = log_page_size; ++ smp_mb(); ++ smp_call_function(&p2m_itr, &p2m_itr_arg, 1, 1); ++ p2m_itr(&p2m_itr_arg); ++ } ++#endif ++ smp_mb(); ++ p2m_initialized = 1; ++ printk(P2M_PREFIX "assign p2m table of [0x%016lx, 0x%016lx)\n", ++ p2m_convert_min_pfn << PAGE_SHIFT, ++ p2m_convert_max_pfn << PAGE_SHIFT); ++ printk(P2M_PREFIX "to [0x%016lx, 0x%016lx) (%ld KBytes)\n", ++ p2m_assign_start_pfn << PAGE_SHIFT, ++ p2m_assign_end_pfn << PAGE_SHIFT, ++ p2m_size / 1024); ++out: ++ unlock_cpu_hotplug(); ++ return error; ++} ++ ++#ifdef notyet ++void ++p2m_expose_cleanup(void) ++{ ++ BUG_ON(!p2m_initialized); ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR ++ unregister_cpu_notifier(&p2m_expose_dtr_hotplug_notifier); ++#endif ++ release_resource(&p2m_resource); ++} ++#endif ++ ++//XXX inlinize? ++unsigned long ++p2m_phystomach(unsigned long gpfn) ++{ ++ volatile const pte_t* pte; ++ unsigned long mfn; ++ unsigned long pteval; ++ ++ if (!p2m_initialized || ++ gpfn < p2m_min_low_pfn || gpfn > p2m_max_low_pfn ++ /* || !pfn_valid(gpfn) */) ++ return INVALID_MFN; ++ pte = p2m_pte + (gpfn - p2m_convert_min_pfn); ++ ++ mfn = INVALID_MFN; ++ if (likely(__get_user(pteval, (unsigned long __user *)pte) == 0 && ++ pte_present(__pte(pteval)) && ++ pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT))) ++ mfn = (pteval & _PFN_MASK) >> PAGE_SHIFT; ++ ++ return mfn; ++} ++ ++EXPORT_SYMBOL_GPL(p2m_initialized); ++EXPORT_SYMBOL_GPL(p2m_min_low_pfn); ++EXPORT_SYMBOL_GPL(p2m_max_low_pfn); ++EXPORT_SYMBOL_GPL(p2m_convert_min_pfn); ++EXPORT_SYMBOL_GPL(p2m_convert_max_pfn); ++EXPORT_SYMBOL_GPL(p2m_pte); ++EXPORT_SYMBOL_GPL(p2m_phystomach); ++#endif ++ ++/////////////////////////////////////////////////////////////////////////// ++// for xenoprof ++ ++struct resource* ++xen_ia64_allocate_resource(unsigned long size) ++{ ++ struct resource* res; ++ int error; ++ ++ res = kmalloc(sizeof(*res), GFP_KERNEL); ++ if (res == NULL) ++ return ERR_PTR(-ENOMEM); ++ ++ res->name = "Xen"; ++ res->flags = IORESOURCE_MEM; ++ error = allocate_resource(&iomem_resource, res, PAGE_ALIGN(size), ++ privcmd_resource_min, privcmd_resource_max, ++ IA64_GRANULE_SIZE, NULL, NULL); ++ if (error) { ++ kfree(res); ++ return ERR_PTR(error); ++ } ++ return res; ++} ++EXPORT_SYMBOL_GPL(xen_ia64_allocate_resource); ++ ++void ++xen_ia64_release_resource(struct resource* res) ++{ ++ release_resource(res); ++ kfree(res); ++} ++EXPORT_SYMBOL_GPL(xen_ia64_release_resource); ++ ++void ++xen_ia64_unmap_resource(struct resource* res) ++{ ++ unsigned long gpfn = res->start >> PAGE_SHIFT; ++ unsigned long nr_pages = (res->end - res->start) >> PAGE_SHIFT; ++ unsigned long i; ++ ++ for (i = 0; i < nr_pages; i++) { ++ int error = HYPERVISOR_zap_physmap(gpfn + i, 0); ++ if (error) ++ printk(KERN_ERR ++ "%s:%d zap_phsymap failed %d gpfn %lx\n", ++ __func__, __LINE__, error, gpfn + i); ++ } ++ xen_ia64_release_resource(res); ++} ++EXPORT_SYMBOL_GPL(xen_ia64_unmap_resource); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/mem.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/mem.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,75 @@ ++/* ++ * Originally from linux/drivers/char/mem.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * Added devfs support. ++ * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu> ++ * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com> ++ */ ++/* ++ * taken from ++ * linux/drivers/char/mem.c and linux-2.6-xen-sparse/drivers/xen/char/mem.c. ++ * adjusted for IA64 and made transparent. ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ */ ++ ++#include <linux/mm.h> ++#include <linux/efi.h> ++ ++/* ++ * Architectures vary in how they handle caching for addresses ++ * outside of main memory. ++ * ++ */ ++static inline int uncached_access(struct file *file, unsigned long addr) ++{ ++ /* ++ * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. ++ */ ++ return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); ++} ++ ++int xen_mmap_mem(struct file * file, struct vm_area_struct * vma) ++{ ++ unsigned long addr = vma->vm_pgoff << PAGE_SHIFT; ++ size_t size = vma->vm_end - vma->vm_start; ++ ++ ++#if 0 ++ /* ++ *XXX FIXME: linux-2.6.16.29, linux-2.6.17 ++ * valid_mmap_phys_addr_range() in linux/arch/ia64/kernel/efi.c ++ * fails checks. ++ * linux-2.6.18.1's returns always 1. ++ * Its comments says ++ * ++ * MMIO regions are often missing from the EFI memory map. ++ * We must allow mmap of them for programs like X, so we ++ * currently can't do any useful validation. ++ */ ++ if (!valid_mmap_phys_addr_range(addr, &size)) ++ return -EINVAL; ++ if (size < vma->vm_end - vma->vm_start) ++ return -EINVAL; ++#endif ++ ++ if (is_running_on_xen()) { ++ unsigned long offset = HYPERVISOR_ioremap(addr, size); ++ if (IS_ERR_VALUE(offset)) ++ return offset; ++ } ++ ++ if (uncached_access(file, vma->vm_pgoff << PAGE_SHIFT)) ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ ++ if (remap_pfn_range(vma, ++ vma->vm_start, ++ vma->vm_pgoff, ++ size, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/util.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/util.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,105 @@ ++/****************************************************************************** ++ * arch/ia64/xen/util.c ++ * This file is the ia64 counterpart of drivers/xen/util.c ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <asm/uaccess.h> ++#include <xen/driver_util.h> ++#include <xen/interface/memory.h> ++#include <asm/hypercall.h> ++ ++struct vm_struct *alloc_vm_area(unsigned long size) ++{ ++ int order; ++ unsigned long virt; ++ unsigned long nr_pages; ++ struct vm_struct* area; ++ ++ order = get_order(size); ++ virt = __get_free_pages(GFP_KERNEL, order); ++ if (virt == 0) { ++ goto err0; ++ } ++ nr_pages = 1 << order; ++ scrub_pages(virt, nr_pages); ++ ++ area = kmalloc(sizeof(*area), GFP_KERNEL); ++ if (area == NULL) { ++ goto err1; ++ } ++ ++ area->flags = VM_IOREMAP;//XXX ++ area->addr = (void*)virt; ++ area->size = size; ++ area->pages = NULL; //XXX ++ area->nr_pages = nr_pages; ++ area->phys_addr = 0; /* xenbus_map_ring_valloc uses this field! */ ++ ++ return area; ++ ++err1: ++ free_pages(virt, order); ++err0: ++ return NULL; ++ ++} ++EXPORT_SYMBOL_GPL(alloc_vm_area); ++ ++void free_vm_area(struct vm_struct *area) ++{ ++ unsigned int order = get_order(area->size); ++ unsigned long i; ++ unsigned long phys_addr = __pa(area->addr); ++ ++ // This area is used for foreign page mappping. ++ // So underlying machine page may not be assigned. ++ for (i = 0; i < (1 << order); i++) { ++ unsigned long ret; ++ unsigned long gpfn = (phys_addr >> PAGE_SHIFT) + i; ++ struct xen_memory_reservation reservation = { ++ .nr_extents = 1, ++ .address_bits = 0, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ set_xen_guest_handle(reservation.extent_start, &gpfn); ++ ret = HYPERVISOR_memory_op(XENMEM_populate_physmap, ++ &reservation); ++ BUG_ON(ret != 1); ++ } ++ free_pages((unsigned long)area->addr, order); ++ kfree(area); ++} ++EXPORT_SYMBOL_GPL(free_vm_area); ++ ++/* ++ * Local variables: ++ * c-file-style: "linux" ++ * indent-tabs-mode: t ++ * c-indent-level: 8 ++ * c-basic-offset: 8 ++ * tab-width: 8 ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xcom_hcall.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xcom_hcall.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,383 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ * ++ * Tristan Gingold <tristan.gingold@bull.net> ++ */ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/gfp.h> ++#include <linux/module.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/platform.h> ++#include <xen/interface/memory.h> ++#include <xen/interface/xencomm.h> ++#include <xen/interface/version.h> ++#include <xen/interface/sched.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/callback.h> ++#include <xen/interface/acm_ops.h> ++#include <xen/interface/hvm/params.h> ++#include <xen/interface/xenoprof.h> ++#include <xen/interface/vcpu.h> ++#include <asm/hypercall.h> ++#include <asm/page.h> ++#include <asm/uaccess.h> ++#include <asm/xen/xencomm.h> ++#include <asm/perfmon.h> ++ ++/* Xencomm notes: ++ * This file defines hypercalls to be used by xencomm. The hypercalls simply ++ * create inlines descriptors for pointers and then call the raw arch hypercall ++ * xencomm_arch_hypercall_XXX ++ * ++ * If the arch wants to directly use these hypercalls, simply define macros ++ * in asm/hypercall.h, eg: ++ * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op ++ * ++ * The arch may also define HYPERVISOR_xxx as a function and do more operations ++ * before/after doing the hypercall. ++ * ++ * Note: because only inline descriptors are created these functions must only ++ * be called with in kernel memory parameters. ++ */ ++ ++int ++xencomm_hypercall_console_io(int cmd, int count, char *str) ++{ ++ return xencomm_arch_hypercall_console_io ++ (cmd, count, xencomm_create_inline(str)); ++} ++ ++int ++xencomm_hypercall_event_channel_op(int cmd, void *op) ++{ ++ return xencomm_arch_hypercall_event_channel_op ++ (cmd, xencomm_create_inline(op)); ++} ++ ++int ++xencomm_hypercall_xen_version(int cmd, void *arg) ++{ ++ switch (cmd) { ++ case XENVER_version: ++ case XENVER_extraversion: ++ case XENVER_compile_info: ++ case XENVER_capabilities: ++ case XENVER_changeset: ++ case XENVER_platform_parameters: ++ case XENVER_pagesize: ++ case XENVER_get_features: ++ break; ++ default: ++ printk("%s: unknown version cmd %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return xencomm_arch_hypercall_xen_version ++ (cmd, xencomm_create_inline(arg)); ++} ++ ++int ++xencomm_hypercall_physdev_op(int cmd, void *op) ++{ ++ return xencomm_arch_hypercall_physdev_op ++ (cmd, xencomm_create_inline(op)); ++} ++ ++static void * ++xencommize_grant_table_op(unsigned int cmd, void *op, unsigned int count) ++{ ++ switch (cmd) { ++ case GNTTABOP_map_grant_ref: ++ case GNTTABOP_unmap_grant_ref: ++ break; ++ case GNTTABOP_setup_table: ++ { ++ struct gnttab_setup_table *setup = op; ++ struct xencomm_handle *frame_list; ++ ++ frame_list = xencomm_create_inline ++ (xen_guest_handle(setup->frame_list)); ++ ++ set_xen_guest_handle(setup->frame_list, (void *)frame_list); ++ break; ++ } ++ case GNTTABOP_dump_table: ++ case GNTTABOP_transfer: ++ case GNTTABOP_copy: ++ break; ++ default: ++ printk("%s: unknown grant table op %d\n", __func__, cmd); ++ BUG(); ++ } ++ ++ return xencomm_create_inline(op); ++} ++ ++int ++xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, unsigned int count) ++{ ++ void *desc = xencommize_grant_table_op (cmd, op, count); ++ ++ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); ++} ++ ++int ++xencomm_hypercall_sched_op(int cmd, void *arg) ++{ ++ switch (cmd) { ++ case SCHEDOP_yield: ++ case SCHEDOP_block: ++ case SCHEDOP_shutdown: ++ case SCHEDOP_remote_shutdown: ++ break; ++ case SCHEDOP_poll: ++ { ++ sched_poll_t *poll = arg; ++ struct xencomm_handle *ports; ++ ++ ports = xencomm_create_inline(xen_guest_handle(poll->ports)); ++ ++ set_xen_guest_handle(poll->ports, (void *)ports); ++ break; ++ } ++ default: ++ printk("%s: unknown sched op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return xencomm_arch_hypercall_sched_op(cmd, xencomm_create_inline(arg)); ++} ++ ++int ++xencomm_hypercall_multicall(void *call_list, int nr_calls) ++{ ++ int i; ++ multicall_entry_t *mce; ++ ++ for (i = 0; i < nr_calls; i++) { ++ mce = (multicall_entry_t *)call_list + i; ++ ++ switch (mce->op) { ++ case __HYPERVISOR_update_va_mapping: ++ case __HYPERVISOR_mmu_update: ++ /* No-op on ia64. */ ++ break; ++ case __HYPERVISOR_grant_table_op: ++ mce->args[1] = (unsigned long)xencommize_grant_table_op ++ (mce->args[0], (void *)mce->args[1], ++ mce->args[2]); ++ break; ++ case __HYPERVISOR_memory_op: ++ default: ++ printk("%s: unhandled multicall op entry op %lu\n", ++ __func__, mce->op); ++ return -ENOSYS; ++ } ++ } ++ ++ return xencomm_arch_hypercall_multicall ++ (xencomm_create_inline(call_list), nr_calls); ++} ++ ++int ++xencomm_hypercall_callback_op(int cmd, void *arg) ++{ ++ switch (cmd) ++ { ++ case CALLBACKOP_register: ++ case CALLBACKOP_unregister: ++ break; ++ default: ++ printk("%s: unknown callback op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return xencomm_arch_hypercall_callback_op ++ (cmd, xencomm_create_inline(arg)); ++} ++ ++static void ++xencommize_memory_reservation (xen_memory_reservation_t *mop) ++{ ++ struct xencomm_handle *desc; ++ ++ desc = xencomm_create_inline(xen_guest_handle(mop->extent_start)); ++ set_xen_guest_handle(mop->extent_start, (void *)desc); ++} ++ ++int ++xencomm_hypercall_memory_op(unsigned int cmd, void *arg) ++{ ++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start_va[2]; ++ xen_memory_reservation_t *xmr = NULL, *xme_in = NULL, *xme_out = NULL; ++ int rc; ++ ++ switch (cmd) { ++ case XENMEM_increase_reservation: ++ case XENMEM_decrease_reservation: ++ case XENMEM_populate_physmap: ++ xmr = (xen_memory_reservation_t *)arg; ++ xen_guest_handle(extent_start_va[0]) = ++ xen_guest_handle(xmr->extent_start); ++ xencommize_memory_reservation((xen_memory_reservation_t *)arg); ++ break; ++ ++ case XENMEM_maximum_ram_page: ++ break; ++ ++ case XENMEM_exchange: ++ xme_in = &((xen_memory_exchange_t *)arg)->in; ++ xme_out = &((xen_memory_exchange_t *)arg)->out; ++ xen_guest_handle(extent_start_va[0]) = ++ xen_guest_handle(xme_in->extent_start); ++ xen_guest_handle(extent_start_va[1]) = ++ xen_guest_handle(xme_out->extent_start); ++ xencommize_memory_reservation ++ (&((xen_memory_exchange_t *)arg)->in); ++ xencommize_memory_reservation ++ (&((xen_memory_exchange_t *)arg)->out); ++ break; ++ ++ default: ++ printk("%s: unknown memory op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ rc = xencomm_arch_hypercall_memory_op(cmd, xencomm_create_inline(arg)); ++ ++ switch (cmd) { ++ case XENMEM_increase_reservation: ++ case XENMEM_decrease_reservation: ++ case XENMEM_populate_physmap: ++ xen_guest_handle(xmr->extent_start) = ++ xen_guest_handle(extent_start_va[0]); ++ break; ++ ++ case XENMEM_exchange: ++ xen_guest_handle(xme_in->extent_start) = ++ xen_guest_handle(extent_start_va[0]); ++ xen_guest_handle(xme_out->extent_start) = ++ xen_guest_handle(extent_start_va[1]); ++ break; ++ } ++ ++ return rc; ++} ++ ++unsigned long ++xencomm_hypercall_hvm_op(int cmd, void *arg) ++{ ++ switch (cmd) { ++ case HVMOP_set_param: ++ case HVMOP_get_param: ++ break; ++ default: ++ printk("%s: unknown hvm op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return xencomm_arch_hypercall_hvm_op(cmd, xencomm_create_inline(arg)); ++} ++ ++int ++xencomm_hypercall_suspend(unsigned long srec) ++{ ++ struct sched_shutdown arg; ++ ++ arg.reason = SHUTDOWN_suspend; ++ ++ return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg)); ++} ++ ++int ++xencomm_hypercall_xenoprof_op(int op, void *arg) ++{ ++ switch (op) { ++ case XENOPROF_init: ++ case XENOPROF_set_active: ++ case XENOPROF_set_passive: ++ case XENOPROF_counter: ++ case XENOPROF_get_buffer: ++ break; ++ ++ case XENOPROF_reset_active_list: ++ case XENOPROF_reset_passive_list: ++ case XENOPROF_reserve_counters: ++ case XENOPROF_setup_events: ++ case XENOPROF_enable_virq: ++ case XENOPROF_start: ++ case XENOPROF_stop: ++ case XENOPROF_disable_virq: ++ case XENOPROF_release_counters: ++ case XENOPROF_shutdown: ++ return xencomm_arch_hypercall_xenoprof_op(op, arg); ++ break; ++ ++ default: ++ printk("%s: op %d isn't supported\n", __func__, op); ++ return -ENOSYS; ++ } ++ return xencomm_arch_hypercall_xenoprof_op(op, ++ xencomm_create_inline(arg)); ++} ++ ++int ++xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count) ++{ ++ switch (cmd) { ++ case PFM_GET_FEATURES: ++ case PFM_CREATE_CONTEXT: ++ case PFM_WRITE_PMCS: ++ case PFM_WRITE_PMDS: ++ case PFM_LOAD_CONTEXT: ++ break; ++ ++ case PFM_DESTROY_CONTEXT: ++ case PFM_UNLOAD_CONTEXT: ++ case PFM_START: ++ case PFM_STOP: ++ return xencomm_arch_hypercall_perfmon_op(cmd, arg, count); ++ ++ default: ++ printk("%s:%d cmd %ld isn't supported\n", ++ __func__,__LINE__, cmd); ++ BUG(); ++ } ++ ++ return xencomm_arch_hypercall_perfmon_op(cmd, ++ xencomm_create_inline(arg), ++ count); ++} ++ ++long ++xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg) ++{ ++ switch (cmd) { ++ case VCPUOP_register_runstate_memory_area: ++ xencommize_memory_reservation((xen_memory_reservation_t *)arg); ++ break; ++ ++ default: ++ printk("%s: unknown vcpu op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return xencomm_arch_hypercall_vcpu_op(cmd, cpu, ++ xencomm_create_inline(arg)); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xcom_mini.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xcom_mini.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,456 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ * ++ * Tristan Gingold <tristan.gingold@bull.net> ++ */ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/platform.h> ++#include <xen/interface/memory.h> ++#include <xen/interface/xencomm.h> ++#include <xen/interface/version.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/hvm/params.h> ++#include <xen/interface/xenoprof.h> ++#ifdef CONFIG_VMX_GUEST ++#include <asm/hypervisor.h> ++#else ++#include <asm/hypercall.h> ++#endif ++#include <asm/xen/xencomm.h> ++#include <asm/perfmon.h> ++ ++int ++xencomm_mini_hypercall_event_channel_op(int cmd, void *op) ++{ ++ struct xencomm_mini xc_area[2]; ++ int nbr_area = 2; ++ struct xencomm_handle *desc; ++ int rc; ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, ++ op, sizeof(evtchn_op_t), &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_event_channel_op(cmd, desc); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_event_channel_op); ++ ++static int ++xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, int *nbr_area, ++ unsigned int cmd, void *op, unsigned int count, ++ struct xencomm_handle **desc) ++{ ++ struct xencomm_handle *desc1; ++ unsigned int argsize; ++ int rc; ++ ++ switch (cmd) { ++ case GNTTABOP_map_grant_ref: ++ argsize = sizeof(struct gnttab_map_grant_ref); ++ break; ++ case GNTTABOP_unmap_grant_ref: ++ argsize = sizeof(struct gnttab_unmap_grant_ref); ++ break; ++ case GNTTABOP_setup_table: ++ { ++ struct gnttab_setup_table *setup = op; ++ ++ argsize = sizeof(*setup); ++ ++ if (count != 1) ++ return -EINVAL; ++ rc = xencomm_create_mini ++ (xc_area, nbr_area, ++ xen_guest_handle(setup->frame_list), ++ setup->nr_frames ++ * sizeof(*xen_guest_handle(setup->frame_list)), ++ &desc1); ++ if (rc) ++ return rc; ++ set_xen_guest_handle(setup->frame_list, (void *)desc1); ++ break; ++ } ++ case GNTTABOP_dump_table: ++ argsize = sizeof(struct gnttab_dump_table); ++ break; ++ case GNTTABOP_transfer: ++ argsize = sizeof(struct gnttab_transfer); ++ break; ++ case GNTTABOP_copy: ++ argsize = sizeof(struct gnttab_copy); ++ break; ++ case GNTTABOP_query_size: ++ argsize = sizeof(struct gnttab_query_size); ++ break; ++ default: ++ printk("%s: unknown mini grant table op %d\n", __func__, cmd); ++ BUG(); ++ } ++ ++ rc = xencomm_create_mini(xc_area, nbr_area, op, count * argsize, desc); ++ if (rc) ++ return rc; ++ ++ return 0; ++} ++ ++int ++xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, ++ unsigned int count) ++{ ++ int rc; ++ struct xencomm_handle *desc; ++ int nbr_area = 2; ++ struct xencomm_mini xc_area[2]; ++ ++ rc = xencommize_mini_grant_table_op(xc_area, &nbr_area, ++ cmd, op, count, &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_grant_table_op); ++ ++int ++xencomm_mini_hypercall_multicall(void *call_list, int nr_calls) ++{ ++ int i; ++ multicall_entry_t *mce; ++ int nbr_area = 2 + nr_calls * 3; ++ struct xencomm_mini xc_area[nbr_area]; ++ struct xencomm_handle *desc; ++ int rc; ++ ++ for (i = 0; i < nr_calls; i++) { ++ mce = (multicall_entry_t *)call_list + i; ++ ++ switch (mce->op) { ++ case __HYPERVISOR_update_va_mapping: ++ case __HYPERVISOR_mmu_update: ++ /* No-op on ia64. */ ++ break; ++ case __HYPERVISOR_grant_table_op: ++ rc = xencommize_mini_grant_table_op ++ (xc_area, &nbr_area, ++ mce->args[0], (void *)mce->args[1], ++ mce->args[2], &desc); ++ if (rc) ++ return rc; ++ mce->args[1] = (unsigned long)desc; ++ break; ++ case __HYPERVISOR_memory_op: ++ default: ++ printk("%s: unhandled multicall op entry op %lu\n", ++ __func__, mce->op); ++ return -ENOSYS; ++ } ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, call_list, ++ nr_calls * sizeof(multicall_entry_t), &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_multicall(desc, nr_calls); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_multicall); ++ ++static int ++xencommize_mini_memory_reservation(struct xencomm_mini *area, int *nbr_area, ++ xen_memory_reservation_t *mop) ++{ ++ struct xencomm_handle *desc; ++ int rc; ++ ++ rc = xencomm_create_mini ++ (area, nbr_area, ++ xen_guest_handle(mop->extent_start), ++ mop->nr_extents ++ * sizeof(*xen_guest_handle(mop->extent_start)), ++ &desc); ++ if (rc) ++ return rc; ++ ++ set_xen_guest_handle(mop->extent_start, (void *)desc); ++ ++ return 0; ++} ++ ++int ++xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg) ++{ ++ int nbr_area = 4; ++ struct xencomm_mini xc_area[4]; ++ struct xencomm_handle *desc; ++ int rc; ++ unsigned int argsize; ++ ++ switch (cmd) { ++ case XENMEM_increase_reservation: ++ case XENMEM_decrease_reservation: ++ case XENMEM_populate_physmap: ++ argsize = sizeof(xen_memory_reservation_t); ++ rc = xencommize_mini_memory_reservation ++ (xc_area, &nbr_area, (xen_memory_reservation_t *)arg); ++ if (rc) ++ return rc; ++ break; ++ ++ case XENMEM_maximum_ram_page: ++ argsize = 0; ++ break; ++ ++ case XENMEM_exchange: ++ argsize = sizeof(xen_memory_exchange_t); ++ rc = xencommize_mini_memory_reservation ++ (xc_area, &nbr_area, ++ &((xen_memory_exchange_t *)arg)->in); ++ if (rc) ++ return rc; ++ rc = xencommize_mini_memory_reservation ++ (xc_area, &nbr_area, ++ &((xen_memory_exchange_t *)arg)->out); ++ if (rc) ++ return rc; ++ break; ++ ++ case XENMEM_add_to_physmap: ++ argsize = sizeof (xen_add_to_physmap_t); ++ break; ++ ++ default: ++ printk("%s: unknown mini memory op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_memory_op(cmd, desc); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_memory_op); ++ ++unsigned long ++xencomm_mini_hypercall_hvm_op(int cmd, void *arg) ++{ ++ struct xencomm_handle *desc; ++ int nbr_area = 2; ++ struct xencomm_mini xc_area[2]; ++ unsigned int argsize; ++ int rc; ++ ++ switch (cmd) { ++ case HVMOP_get_param: ++ case HVMOP_set_param: ++ argsize = sizeof(xen_hvm_param_t); ++ break; ++ default: ++ printk("%s: unknown HVMOP %d\n", __func__, cmd); ++ return -EINVAL; ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_hvm_op(cmd, desc); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_hvm_op); ++ ++int ++xencomm_mini_hypercall_xen_version(int cmd, void *arg) ++{ ++ struct xencomm_handle *desc; ++ int nbr_area = 2; ++ struct xencomm_mini xc_area[2]; ++ unsigned int argsize; ++ int rc; ++ ++ switch (cmd) { ++ case XENVER_version: ++ /* do not actually pass an argument */ ++ return xencomm_arch_hypercall_xen_version(cmd, 0); ++ case XENVER_extraversion: ++ argsize = sizeof(xen_extraversion_t); ++ break; ++ case XENVER_compile_info: ++ argsize = sizeof(xen_compile_info_t); ++ break; ++ case XENVER_capabilities: ++ argsize = sizeof(xen_capabilities_info_t); ++ break; ++ case XENVER_changeset: ++ argsize = sizeof(xen_changeset_info_t); ++ break; ++ case XENVER_platform_parameters: ++ argsize = sizeof(xen_platform_parameters_t); ++ break; ++ case XENVER_pagesize: ++ argsize = (arg == NULL) ? 0 : sizeof(void *); ++ break; ++ case XENVER_get_features: ++ argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t); ++ break; ++ ++ default: ++ printk("%s: unknown version op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_xen_version(cmd, desc); ++} ++EXPORT_SYMBOL(xencomm_mini_hypercall_xen_version); ++ ++int ++xencomm_mini_hypercall_xenoprof_op(int op, void *arg) ++{ ++ unsigned int argsize; ++ struct xencomm_mini xc_area[2]; ++ int nbr_area = 2; ++ struct xencomm_handle *desc; ++ int rc; ++ ++ switch (op) { ++ case XENOPROF_init: ++ argsize = sizeof(xenoprof_init_t); ++ break; ++ case XENOPROF_set_active: ++ argsize = sizeof(domid_t); ++ break; ++ case XENOPROF_set_passive: ++ argsize = sizeof(xenoprof_passive_t); ++ break; ++ case XENOPROF_counter: ++ argsize = sizeof(xenoprof_counter_t); ++ break; ++ case XENOPROF_get_buffer: ++ argsize = sizeof(xenoprof_get_buffer_t); ++ break; ++ ++ case XENOPROF_reset_active_list: ++ case XENOPROF_reset_passive_list: ++ case XENOPROF_reserve_counters: ++ case XENOPROF_setup_events: ++ case XENOPROF_enable_virq: ++ case XENOPROF_start: ++ case XENOPROF_stop: ++ case XENOPROF_disable_virq: ++ case XENOPROF_release_counters: ++ case XENOPROF_shutdown: ++ return xencomm_arch_hypercall_xenoprof_op(op, arg); ++ ++ default: ++ printk("%s: op %d isn't supported\n", __func__, op); ++ return -ENOSYS; ++ } ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ return xencomm_arch_hypercall_xenoprof_op(op, desc); ++} ++EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_xenoprof_op); ++ ++int ++xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, ++ unsigned long count) ++{ ++ unsigned int argsize; ++ struct xencomm_mini xc_area[2]; ++ int nbr_area = 2; ++ struct xencomm_handle *desc; ++ int rc; ++ ++ switch (cmd) { ++ case PFM_GET_FEATURES: ++ argsize = sizeof(pfarg_features_t); ++ break; ++ case PFM_CREATE_CONTEXT: ++ argsize = sizeof(pfarg_context_t); ++ break; ++ case PFM_LOAD_CONTEXT: ++ argsize = sizeof(pfarg_load_t); ++ break; ++ case PFM_WRITE_PMCS: ++ case PFM_WRITE_PMDS: ++ argsize = sizeof(pfarg_reg_t) * count; ++ break; ++ ++ case PFM_DESTROY_CONTEXT: ++ case PFM_UNLOAD_CONTEXT: ++ case PFM_START: ++ case PFM_STOP: ++ return xencomm_arch_hypercall_perfmon_op(cmd, arg, count); ++ ++ default: ++ printk("%s:%d cmd %ld isn't supported\n", ++ __func__, __LINE__, cmd); ++ BUG(); ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ return xencomm_arch_hypercall_perfmon_op(cmd, desc, count); ++} ++EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_perfmon_op); ++ ++int ++xencomm_mini_hypercall_sched_op(int cmd, void *arg) ++{ ++ int rc, nbr_area = 2; ++ struct xencomm_mini xc_area[2]; ++ struct xencomm_handle *desc; ++ unsigned int argsize; ++ ++ switch (cmd) { ++ case SCHEDOP_yield: ++ case SCHEDOP_block: ++ argsize = 0; ++ break; ++ case SCHEDOP_shutdown: ++ argsize = sizeof(sched_shutdown_t); ++ break; ++ case SCHEDOP_poll: ++ argsize = sizeof(sched_poll_t); ++ break; ++ case SCHEDOP_remote_shutdown: ++ argsize = sizeof(sched_remote_shutdown_t); ++ break; ++ ++ default: ++ printk("%s: unknown sched op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); ++ if (rc) ++ return rc; ++ ++ return xencomm_arch_hypercall_sched_op(cmd, desc); ++} ++EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_sched_op); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xcom_privcmd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xcom_privcmd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,664 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ * ++ * Authors: Hollis Blanchard <hollisb@us.ibm.com> ++ * Tristan Gingold <tristan.gingold@bull.net> ++ */ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/gfp.h> ++#include <linux/module.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/platform.h> ++#define __XEN__ ++#include <xen/interface/domctl.h> ++#include <xen/interface/sysctl.h> ++#include <xen/interface/memory.h> ++#include <xen/interface/version.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/acm_ops.h> ++#include <xen/interface/hvm/params.h> ++#include <xen/public/privcmd.h> ++#include <asm/hypercall.h> ++#include <asm/page.h> ++#include <asm/uaccess.h> ++#include <asm/xen/xencomm.h> ++ ++#define ROUND_DIV(v,s) (((v) + (s) - 1) / (s)) ++ ++static int ++xencomm_privcmd_platform_op(privcmd_hypercall_t *hypercall) ++{ ++ struct xen_platform_op kern_op; ++ struct xen_platform_op __user *user_op = (struct xen_platform_op __user *)hypercall->arg[0]; ++ struct xencomm_handle *op_desc; ++ struct xencomm_handle *desc = NULL; ++ int ret = 0; ++ ++ if (copy_from_user(&kern_op, user_op, sizeof(struct xen_platform_op))) ++ return -EFAULT; ++ ++ if (kern_op.interface_version != XENPF_INTERFACE_VERSION) ++ return -EACCES; ++ ++ op_desc = xencomm_create_inline(&kern_op); ++ ++ switch (kern_op.cmd) { ++ default: ++ printk("%s: unknown platform cmd %d\n", __func__, kern_op.cmd); ++ return -ENOSYS; ++ } ++ ++ if (ret) { ++ /* error mapping the nested pointer */ ++ return ret; ++ } ++ ++ ret = xencomm_arch_hypercall_platform_op(op_desc); ++ ++ /* FIXME: should we restore the handle? */ ++ if (copy_to_user(user_op, &kern_op, sizeof(struct xen_platform_op))) ++ ret = -EFAULT; ++ ++ if (desc) ++ xencomm_free(desc); ++ return ret; ++} ++ ++/* ++ * Temporarily disable the NUMA PHYSINFO code until the rest of the ++ * changes are upstream. ++ */ ++#undef IA64_NUMA_PHYSINFO ++ ++static int ++xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall) ++{ ++ xen_sysctl_t kern_op; ++ xen_sysctl_t __user *user_op; ++ struct xencomm_handle *op_desc; ++ struct xencomm_handle *desc = NULL; ++ struct xencomm_handle *desc1 = NULL; ++ int ret = 0; ++ ++ user_op = (xen_sysctl_t __user *)hypercall->arg[0]; ++ ++ if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t))) ++ return -EFAULT; ++ ++ if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) ++ return -EACCES; ++ ++ op_desc = xencomm_create_inline(&kern_op); ++ ++ switch (kern_op.cmd) { ++ case XEN_SYSCTL_readconsole: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.readconsole.buffer), ++ kern_op.u.readconsole.count, ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.readconsole.buffer, ++ (void *)desc); ++ break; ++ case XEN_SYSCTL_tbuf_op: ++#ifndef IA64_NUMA_PHYSINFO ++ case XEN_SYSCTL_physinfo: ++#endif ++ case XEN_SYSCTL_sched_id: ++ break; ++ case XEN_SYSCTL_perfc_op: ++ { ++ struct xencomm_handle *tmp_desc; ++ xen_sysctl_t tmp_op = { ++ .cmd = XEN_SYSCTL_perfc_op, ++ .interface_version = XEN_SYSCTL_INTERFACE_VERSION, ++ .u.perfc_op = { ++ .cmd = XEN_SYSCTL_PERFCOP_query, ++ // .desc.p = NULL, ++ // .val.p = NULL, ++ }, ++ }; ++ ++ if (xen_guest_handle(kern_op.u.perfc_op.desc) == NULL) { ++ if (xen_guest_handle(kern_op.u.perfc_op.val) != NULL) ++ return -EINVAL; ++ break; ++ } ++ ++ /* query the buffer size for xencomm */ ++ tmp_desc = xencomm_create_inline(&tmp_op); ++ ret = xencomm_arch_hypercall_sysctl(tmp_desc); ++ if (ret) ++ return ret; ++ ++ ret = xencomm_create(xen_guest_handle(kern_op.u.perfc_op.desc), ++ tmp_op.u.perfc_op.nr_counters * ++ sizeof(xen_sysctl_perfc_desc_t), ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ ++ set_xen_guest_handle(kern_op.u.perfc_op.desc, (void *)desc); ++ ++ ret = xencomm_create(xen_guest_handle(kern_op.u.perfc_op.val), ++ tmp_op.u.perfc_op.nr_vals * ++ sizeof(xen_sysctl_perfc_val_t), ++ &desc1, GFP_KERNEL); ++ if (ret) ++ xencomm_free(desc); ++ ++ set_xen_guest_handle(kern_op.u.perfc_op.val, (void *)desc1); ++ break; ++ } ++ case XEN_SYSCTL_getdomaininfolist: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.getdomaininfolist.buffer), ++ kern_op.u.getdomaininfolist.max_domains * ++ sizeof(xen_domctl_getdomaininfo_t), ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer, ++ (void *)desc); ++ break; ++#ifdef IA64_NUMA_PHYSINFO ++ case XEN_SYSCTL_physinfo: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.physinfo.memory_chunks), ++ PUBLIC_MAXCHUNKS * sizeof(node_data_t), ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ set_xen_guest_handle(kern_op.u.physinfo.memory_chunks, ++ (void *)desc); ++ ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.physinfo.cpu_to_node), ++ PUBLIC_MAX_NUMNODES * sizeof(u64), ++ &desc1, GFP_KERNEL); ++ if (ret) ++ xencomm_free(desc); ++ set_xen_guest_handle(kern_op.u.physinfo.cpu_to_node, ++ (void *)desc1); ++ break; ++#endif ++ default: ++ printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd); ++ return -ENOSYS; ++ } ++ ++ if (ret) { ++ /* error mapping the nested pointer */ ++ return ret; ++ } ++ ++ ret = xencomm_arch_hypercall_sysctl(op_desc); ++ ++ /* FIXME: should we restore the handles? */ ++ if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t))) ++ ret = -EFAULT; ++ ++ if (desc) ++ xencomm_free(desc); ++ if (desc1) ++ xencomm_free(desc1); ++ return ret; ++} ++ ++static int ++xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall) ++{ ++ xen_domctl_t kern_op; ++ xen_domctl_t __user *user_op; ++ struct xencomm_handle *op_desc; ++ struct xencomm_handle *desc = NULL; ++ int ret = 0; ++ ++ user_op = (xen_domctl_t __user *)hypercall->arg[0]; ++ ++ if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t))) ++ return -EFAULT; ++ ++ if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) ++ return -EACCES; ++ ++ op_desc = xencomm_create_inline(&kern_op); ++ ++ switch (kern_op.cmd) { ++ case XEN_DOMCTL_createdomain: ++ case XEN_DOMCTL_destroydomain: ++ case XEN_DOMCTL_pausedomain: ++ case XEN_DOMCTL_unpausedomain: ++ case XEN_DOMCTL_getdomaininfo: ++ break; ++ case XEN_DOMCTL_getmemlist: ++ { ++ unsigned long nr_pages = kern_op.u.getmemlist.max_pfns; ++ ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.getmemlist.buffer), ++ nr_pages * sizeof(unsigned long), ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.getmemlist.buffer, ++ (void *)desc); ++ break; ++ } ++ case XEN_DOMCTL_getpageframeinfo: ++ break; ++ case XEN_DOMCTL_getpageframeinfo2: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.getpageframeinfo2.array), ++ kern_op.u.getpageframeinfo2.num, ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.getpageframeinfo2.array, ++ (void *)desc); ++ break; ++ case XEN_DOMCTL_shadow_op: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap), ++ ROUND_DIV(kern_op.u.shadow_op.pages, 8), ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap, ++ (void *)desc); ++ break; ++ case XEN_DOMCTL_max_mem: ++ break; ++ case XEN_DOMCTL_setvcpucontext: ++ case XEN_DOMCTL_getvcpucontext: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.vcpucontext.ctxt), ++ sizeof(vcpu_guest_context_t), ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc); ++ break; ++ case XEN_DOMCTL_getvcpuinfo: ++ break; ++ case XEN_DOMCTL_setvcpuaffinity: ++ case XEN_DOMCTL_getvcpuaffinity: ++ ret = xencomm_create( ++ xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap), ++ ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8), ++ &desc, GFP_KERNEL); ++ set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap, ++ (void *)desc); ++ break; ++ case XEN_DOMCTL_max_vcpus: ++ case XEN_DOMCTL_scheduler_op: ++ case XEN_DOMCTL_setdomainhandle: ++ case XEN_DOMCTL_setdebugging: ++ case XEN_DOMCTL_irq_permission: ++ case XEN_DOMCTL_iomem_permission: ++ case XEN_DOMCTL_ioport_permission: ++ case XEN_DOMCTL_hypercall_init: ++ case XEN_DOMCTL_arch_setup: ++ case XEN_DOMCTL_settimeoffset: ++ case XEN_DOMCTL_sendtrigger: ++ break; ++ default: ++ printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd); ++ return -ENOSYS; ++ } ++ ++ if (ret) { ++ /* error mapping the nested pointer */ ++ return ret; ++ } ++ ++ ret = xencomm_arch_hypercall_domctl (op_desc); ++ ++ /* FIXME: should we restore the handle? */ ++ if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t))) ++ ret = -EFAULT; ++ ++ if (desc) ++ xencomm_free(desc); ++ return ret; ++} ++ ++static int ++xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall) ++{ ++ int cmd = hypercall->arg[0]; ++ void __user *arg = (void __user *)hypercall->arg[1]; ++ struct xencomm_handle *op_desc; ++ struct xencomm_handle *desc = NULL; ++ int ret; ++ ++ switch (cmd) { ++ case ACMOP_getssid: ++ { ++ struct acm_getssid kern_arg; ++ ++ if (copy_from_user(&kern_arg, arg, sizeof (kern_arg))) ++ return -EFAULT; ++ ++ op_desc = xencomm_create_inline(&kern_arg); ++ ++ ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf), ++ kern_arg.ssidbuf_size, &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ ++ set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc); ++ ++ ret = xencomm_arch_hypercall_acm_op(cmd, op_desc); ++ ++ xencomm_free(desc); ++ ++ if (copy_to_user(arg, &kern_arg, sizeof (kern_arg))) ++ return -EFAULT; ++ ++ return ret; ++ } ++ default: ++ printk("%s: unknown acm_op cmd %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ return ret; ++} ++ ++static int ++xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall) ++{ ++ const unsigned long cmd = hypercall->arg[0]; ++ int ret = 0; ++ ++ switch (cmd) { ++ case XENMEM_increase_reservation: ++ case XENMEM_decrease_reservation: ++ case XENMEM_populate_physmap: ++ { ++ xen_memory_reservation_t kern_op; ++ xen_memory_reservation_t __user *user_op; ++ struct xencomm_handle *desc = NULL; ++ struct xencomm_handle *desc_op; ++ ++ user_op = (xen_memory_reservation_t __user *)hypercall->arg[1]; ++ if (copy_from_user(&kern_op, user_op, ++ sizeof(xen_memory_reservation_t))) ++ return -EFAULT; ++ desc_op = xencomm_create_inline(&kern_op); ++ ++ if (xen_guest_handle(kern_op.extent_start)) { ++ void * addr; ++ ++ addr = xen_guest_handle(kern_op.extent_start); ++ ret = xencomm_create ++ (addr, ++ kern_op.nr_extents * ++ sizeof(*xen_guest_handle ++ (kern_op.extent_start)), ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ set_xen_guest_handle(kern_op.extent_start, ++ (void *)desc); ++ } ++ ++ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op); ++ ++ if (desc) ++ xencomm_free(desc); ++ ++ if (ret != 0) ++ return ret; ++ ++ if (copy_to_user(user_op, &kern_op, ++ sizeof(xen_memory_reservation_t))) ++ return -EFAULT; ++ ++ return ret; ++ } ++ case XENMEM_translate_gpfn_list: ++ { ++ xen_translate_gpfn_list_t kern_op; ++ xen_translate_gpfn_list_t __user *user_op; ++ struct xencomm_handle *desc_gpfn = NULL; ++ struct xencomm_handle *desc_mfn = NULL; ++ struct xencomm_handle *desc_op; ++ void *addr; ++ ++ user_op = (xen_translate_gpfn_list_t __user *) ++ hypercall->arg[1]; ++ if (copy_from_user(&kern_op, user_op, ++ sizeof(xen_translate_gpfn_list_t))) ++ return -EFAULT; ++ desc_op = xencomm_create_inline(&kern_op); ++ ++ if (kern_op.nr_gpfns) { ++ /* gpfn_list. */ ++ addr = xen_guest_handle(kern_op.gpfn_list); ++ ++ ret = xencomm_create(addr, kern_op.nr_gpfns * ++ sizeof(*xen_guest_handle ++ (kern_op.gpfn_list)), ++ &desc_gpfn, GFP_KERNEL); ++ if (ret) ++ return ret; ++ set_xen_guest_handle(kern_op.gpfn_list, ++ (void *)desc_gpfn); ++ ++ /* mfn_list. */ ++ addr = xen_guest_handle(kern_op.mfn_list); ++ ++ ret = xencomm_create(addr, kern_op.nr_gpfns * ++ sizeof(*xen_guest_handle ++ (kern_op.mfn_list)), ++ &desc_mfn, GFP_KERNEL); ++ if (ret) ++ return ret; ++ set_xen_guest_handle(kern_op.mfn_list, ++ (void *)desc_mfn); ++ } ++ ++ ret = xencomm_arch_hypercall_memory_op(cmd, desc_op); ++ ++ if (desc_gpfn) ++ xencomm_free(desc_gpfn); ++ ++ if (desc_mfn) ++ xencomm_free(desc_mfn); ++ ++ if (ret != 0) ++ return ret; ++ ++ return ret; ++ } ++ default: ++ printk("%s: unknown memory op %lu\n", __func__, cmd); ++ ret = -ENOSYS; ++ } ++ return ret; ++} ++ ++static int ++xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall) ++{ ++ int cmd = hypercall->arg[0]; ++ void __user *arg = (void __user *)hypercall->arg[1]; ++ struct xencomm_handle *desc; ++ size_t argsize; ++ int rc; ++ ++ switch (cmd) { ++ case XENVER_version: ++ /* do not actually pass an argument */ ++ return xencomm_arch_hypercall_xen_version(cmd, 0); ++ case XENVER_extraversion: ++ argsize = sizeof(xen_extraversion_t); ++ break; ++ case XENVER_compile_info: ++ argsize = sizeof(xen_compile_info_t); ++ break; ++ case XENVER_capabilities: ++ argsize = sizeof(xen_capabilities_info_t); ++ break; ++ case XENVER_changeset: ++ argsize = sizeof(xen_changeset_info_t); ++ break; ++ case XENVER_platform_parameters: ++ argsize = sizeof(xen_platform_parameters_t); ++ break; ++ case XENVER_pagesize: ++ argsize = (arg == NULL) ? 0 : sizeof(void *); ++ break; ++ case XENVER_get_features: ++ argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t); ++ break; ++ ++ default: ++ printk("%s: unknown version op %d\n", __func__, cmd); ++ return -ENOSYS; ++ } ++ ++ rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL); ++ if (rc) ++ return rc; ++ ++ rc = xencomm_arch_hypercall_xen_version(cmd, desc); ++ ++ xencomm_free(desc); ++ ++ return rc; ++} ++ ++static int ++xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall) ++{ ++ int cmd = hypercall->arg[0]; ++ struct xencomm_handle *desc; ++ unsigned int argsize; ++ int ret; ++ ++ switch (cmd) { ++ case EVTCHNOP_alloc_unbound: ++ argsize = sizeof(evtchn_alloc_unbound_t); ++ break; ++ ++ case EVTCHNOP_status: ++ argsize = sizeof(evtchn_status_t); ++ break; ++ ++ default: ++ printk("%s: unknown EVTCHNOP %d\n", __func__, cmd); ++ return -EINVAL; ++ } ++ ++ ret = xencomm_create((void *)hypercall->arg[1], argsize, ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ ++ ret = xencomm_arch_hypercall_event_channel_op(cmd, desc); ++ ++ xencomm_free(desc); ++ return ret; ++} ++ ++static int ++xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall) ++{ ++ int cmd = hypercall->arg[0]; ++ struct xencomm_handle *desc; ++ unsigned int argsize; ++ int ret; ++ ++ switch (cmd) { ++ case HVMOP_get_param: ++ case HVMOP_set_param: ++ argsize = sizeof(xen_hvm_param_t); ++ break; ++ case HVMOP_set_pci_intx_level: ++ argsize = sizeof(xen_hvm_set_pci_intx_level_t); ++ break; ++ case HVMOP_set_isa_irq_level: ++ argsize = sizeof(xen_hvm_set_isa_irq_level_t); ++ break; ++ case HVMOP_set_pci_link_route: ++ argsize = sizeof(xen_hvm_set_pci_link_route_t); ++ break; ++ ++ default: ++ printk("%s: unknown HVMOP %d\n", __func__, cmd); ++ return -EINVAL; ++ } ++ ++ ret = xencomm_create((void *)hypercall->arg[1], argsize, ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ ++ ret = xencomm_arch_hypercall_hvm_op(cmd, desc); ++ ++ xencomm_free(desc); ++ return ret; ++} ++ ++static int ++xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall) ++{ ++ int cmd = hypercall->arg[0]; ++ struct xencomm_handle *desc; ++ unsigned int argsize; ++ int ret; ++ ++ switch (cmd) { ++ case SCHEDOP_remote_shutdown: ++ argsize = sizeof(sched_remote_shutdown_t); ++ break; ++ default: ++ printk("%s: unknown SCHEDOP %d\n", __func__, cmd); ++ return -EINVAL; ++ } ++ ++ ret = xencomm_create((void *)hypercall->arg[1], argsize, ++ &desc, GFP_KERNEL); ++ if (ret) ++ return ret; ++ ++ ret = xencomm_arch_hypercall_sched_op(cmd, desc); ++ ++ xencomm_free(desc); ++ return ret; ++} ++ ++int ++privcmd_hypercall(privcmd_hypercall_t *hypercall) ++{ ++ switch (hypercall->op) { ++ case __HYPERVISOR_platform_op: ++ return xencomm_privcmd_platform_op(hypercall); ++ case __HYPERVISOR_domctl: ++ return xencomm_privcmd_domctl(hypercall); ++ case __HYPERVISOR_sysctl: ++ return xencomm_privcmd_sysctl(hypercall); ++ case __HYPERVISOR_acm_op: ++ return xencomm_privcmd_acm_op(hypercall); ++ case __HYPERVISOR_xen_version: ++ return xencomm_privcmd_xen_version(hypercall); ++ case __HYPERVISOR_memory_op: ++ return xencomm_privcmd_memory_op(hypercall); ++ case __HYPERVISOR_event_channel_op: ++ return xencomm_privcmd_event_channel_op(hypercall); ++ case __HYPERVISOR_hvm_op: ++ return xencomm_privcmd_hvm_op(hypercall); ++ case __HYPERVISOR_sched_op: ++ return xencomm_privcmd_sched_op(hypercall); ++ default: ++ printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op); ++ return -ENOSYS; ++ } ++} ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xencomm.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xencomm.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,263 @@ ++/* ++ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/gfp.h> ++#include <linux/mm.h> ++#include <xen/interface/xen.h> ++#include <asm/page.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#include <asm/xen/xencomm.h> ++ ++static int xencomm_debug = 0; ++ ++static unsigned long kernel_start_pa; ++ ++void ++xencomm_init (void) ++{ ++ kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START); ++} ++ ++/* Translate virtual address to physical address. */ ++unsigned long ++xencomm_vaddr_to_paddr(unsigned long vaddr) ++{ ++#ifndef CONFIG_VMX_GUEST ++ struct page *page; ++ struct vm_area_struct *vma; ++#endif ++ ++ if (vaddr == 0) ++ return 0; ++ ++#ifdef __ia64__ ++ if (REGION_NUMBER(vaddr) == 5) { ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *ptep; ++ ++ /* On ia64, TASK_SIZE refers to current. It is not initialized ++ during boot. ++ Furthermore the kernel is relocatable and __pa() doesn't ++ work on addresses. */ ++ if (vaddr >= KERNEL_START ++ && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) { ++ return vaddr - kernel_start_pa; ++ } ++ ++ /* In kernel area -- virtually mapped. */ ++ pgd = pgd_offset_k(vaddr); ++ if (pgd_none(*pgd) || pgd_bad(*pgd)) ++ return ~0UL; ++ ++ pud = pud_offset(pgd, vaddr); ++ if (pud_none(*pud) || pud_bad(*pud)) ++ return ~0UL; ++ ++ pmd = pmd_offset(pud, vaddr); ++ if (pmd_none(*pmd) || pmd_bad(*pmd)) ++ return ~0UL; ++ ++ ptep = pte_offset_kernel(pmd, vaddr); ++ if (!ptep) ++ return ~0UL; ++ ++ return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK); ++ } ++#endif ++ ++ if (vaddr > TASK_SIZE) { ++ /* kernel address */ ++ return __pa(vaddr); ++ } ++ ++ ++#ifdef CONFIG_VMX_GUEST ++ /* No privcmd within vmx guest. */ ++ return ~0UL; ++#else ++ /* XXX double-check (lack of) locking */ ++ vma = find_extend_vma(current->mm, vaddr); ++ if (!vma) ++ return ~0UL; ++ ++ /* We assume the page is modified. */ ++ page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH); ++ if (!page) ++ return ~0UL; ++ ++ return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK); ++#endif ++} ++ ++static int ++xencomm_init_desc(struct xencomm_desc *desc, void *buffer, unsigned long bytes) ++{ ++ unsigned long recorded = 0; ++ int i = 0; ++ ++ BUG_ON((buffer == NULL) && (bytes > 0)); ++ ++ /* record the physical pages used */ ++ if (buffer == NULL) ++ desc->nr_addrs = 0; ++ ++ while ((recorded < bytes) && (i < desc->nr_addrs)) { ++ unsigned long vaddr = (unsigned long)buffer + recorded; ++ unsigned long paddr; ++ int offset; ++ int chunksz; ++ ++ offset = vaddr % PAGE_SIZE; /* handle partial pages */ ++ chunksz = min(PAGE_SIZE - offset, bytes - recorded); ++ ++ paddr = xencomm_vaddr_to_paddr(vaddr); ++ if (paddr == ~0UL) { ++ printk("%s: couldn't translate vaddr %lx\n", ++ __func__, vaddr); ++ return -EINVAL; ++ } ++ ++ desc->address[i++] = paddr; ++ recorded += chunksz; ++ } ++ ++ if (recorded < bytes) { ++ printk("%s: could only translate %ld of %ld bytes\n", ++ __func__, recorded, bytes); ++ return -ENOSPC; ++ } ++ ++ /* mark remaining addresses invalid (just for safety) */ ++ while (i < desc->nr_addrs) ++ desc->address[i++] = XENCOMM_INVALID; ++ ++ desc->magic = XENCOMM_MAGIC; ++ ++ return 0; ++} ++ ++static struct xencomm_desc * ++xencomm_alloc(gfp_t gfp_mask) ++{ ++ struct xencomm_desc *desc; ++ ++ desc = (struct xencomm_desc *)__get_free_page(gfp_mask); ++ if (desc == NULL) ++ panic("%s: page allocation failed\n", __func__); ++ ++ desc->nr_addrs = (PAGE_SIZE - sizeof(struct xencomm_desc)) / ++ sizeof(*desc->address); ++ ++ return desc; ++} ++ ++void ++xencomm_free(struct xencomm_handle *desc) ++{ ++ if (desc) ++ free_page((unsigned long)__va(desc)); ++} ++ ++int ++xencomm_create(void *buffer, unsigned long bytes, ++ struct xencomm_handle **ret, gfp_t gfp_mask) ++{ ++ struct xencomm_desc *desc; ++ struct xencomm_handle *handle; ++ int rc; ++ ++ if (xencomm_debug) ++ printk("%s: %p[%ld]\n", __func__, buffer, bytes); ++ ++ if (buffer == NULL || bytes == 0) { ++ *ret = (struct xencomm_handle *)NULL; ++ return 0; ++ } ++ ++ desc = xencomm_alloc(gfp_mask); ++ if (!desc) { ++ printk("%s failure\n", "xencomm_alloc"); ++ return -ENOMEM; ++ } ++ handle = (struct xencomm_handle *)__pa(desc); ++ ++ rc = xencomm_init_desc(desc, buffer, bytes); ++ if (rc) { ++ printk("%s failure: %d\n", "xencomm_init_desc", rc); ++ xencomm_free(handle); ++ return rc; ++ } ++ ++ *ret = handle; ++ return 0; ++} ++ ++/* "mini" routines, for stack-based communications: */ ++ ++static void * ++xencomm_alloc_mini(struct xencomm_mini *area, int *nbr_area) ++{ ++ unsigned long base; ++ unsigned int pageoffset; ++ ++ while (*nbr_area >= 0) { ++ /* Allocate an area. */ ++ (*nbr_area)--; ++ ++ base = (unsigned long)(area + *nbr_area); ++ pageoffset = base % PAGE_SIZE; ++ ++ /* If the area does not cross a page, use it. */ ++ if ((PAGE_SIZE - pageoffset) >= sizeof(struct xencomm_mini)) ++ return &area[*nbr_area]; ++ } ++ /* No more area. */ ++ return NULL; ++} ++ ++int ++xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, ++ void *buffer, unsigned long bytes, ++ struct xencomm_handle **ret) ++{ ++ struct xencomm_desc *desc; ++ int rc; ++ unsigned long res; ++ ++ desc = xencomm_alloc_mini(area, nbr_area); ++ if (!desc) ++ return -ENOMEM; ++ desc->nr_addrs = XENCOMM_MINI_ADDRS; ++ ++ rc = xencomm_init_desc(desc, buffer, bytes); ++ if (rc) ++ return rc; ++ ++ res = xencomm_vaddr_to_paddr((unsigned long)desc); ++ if (res == ~0UL) ++ return -EINVAL; ++ ++ *ret = (struct xencomm_handle*)res; ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xenentry.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xenentry.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,931 @@ ++/* ++ * ia64/xen/entry.S ++ * ++ * Alternate kernel routines for Xen. Heavily leveraged from ++ * ia64/kernel/entry.S ++ * ++ * Copyright (C) 2005 Hewlett-Packard Co ++ * Dan Magenheimer <dan.magenheimer@.hp.com> ++ */ ++ ++#include <asm/asmmacro.h> ++#include <asm/cache.h> ++#include <asm/errno.h> ++#include <asm/kregs.h> ++#include <asm/asm-offsets.h> ++#include <asm/pgtable.h> ++#include <asm/percpu.h> ++#include <asm/processor.h> ++#include <asm/thread_info.h> ++#include <asm/unistd.h> ++ ++#ifdef CONFIG_XEN ++#include "xenminstate.h" ++#else ++#include "minstate.h" ++#endif ++ ++/* ++ * prev_task <- ia64_switch_to(struct task_struct *next) ++ * With Ingo's new scheduler, interrupts are disabled when this routine gets ++ * called. The code starting at .map relies on this. The rest of the code ++ * doesn't care about the interrupt masking status. ++ */ ++#ifdef CONFIG_XEN ++GLOBAL_ENTRY(xen_switch_to) ++ .prologue ++ alloc r16=ar.pfs,1,0,0,0 ++ movl r22=running_on_xen;; ++ ld4 r22=[r22];; ++ cmp.eq p7,p0=r22,r0 ++(p7) br.cond.sptk.many __ia64_switch_to;; ++#else ++GLOBAL_ENTRY(ia64_switch_to) ++ .prologue ++ alloc r16=ar.pfs,1,0,0,0 ++#endif ++ DO_SAVE_SWITCH_STACK ++ .body ++ ++ adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 ++ movl r25=init_task ++ mov r27=IA64_KR(CURRENT_STACK) ++ adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ++ dep r20=0,in0,61,3 // physical address of "next" ++ ;; ++ st8 [r22]=sp // save kernel stack pointer of old task ++ shr.u r26=r20,IA64_GRANULE_SHIFT ++ cmp.eq p7,p6=r25,in0 ++ ;; ++ /* ++ * If we've already mapped this task's page, we can skip doing it again. ++ */ ++(p6) cmp.eq p7,p6=r26,r27 ++(p6) br.cond.dpnt .map ++ ;; ++.done: ++ ld8 sp=[r21] // load kernel stack pointer of new task ++#ifdef CONFIG_XEN ++ // update "current" application register ++ mov r8=IA64_KR_CURRENT ++ mov r9=in0;; ++ XEN_HYPER_SET_KR ++#else ++ mov IA64_KR(CURRENT)=in0 // update "current" application register ++#endif ++ mov r8=r13 // return pointer to previously running task ++ mov r13=in0 // set "current" pointer ++ ;; ++ DO_LOAD_SWITCH_STACK ++ ++#ifdef CONFIG_SMP ++ sync.i // ensure "fc"s done by this CPU are visible on other CPUs ++#endif ++ br.ret.sptk.many rp // boogie on out in new context ++ ++.map: ++#ifdef CONFIG_XEN ++ movl r25=XSI_PSR_IC // clear psr.ic ++ ;; ++ st4 [r25]=r0 ++ ;; ++#else ++ rsm psr.ic // interrupts (psr.i) are already disabled here ++#endif ++ movl r25=PAGE_KERNEL ++ ;; ++ srlz.d ++ or r23=r25,r20 // construct PA | page properties ++ mov r25=IA64_GRANULE_SHIFT<<2 ++ ;; ++#ifdef CONFIG_XEN ++ movl r8=XSI_ITIR ++ ;; ++ st8 [r8]=r25 ++ ;; ++ movl r8=XSI_IFA ++ ;; ++ st8 [r8]=in0 // VA of next task... ++ ;; ++ mov r25=IA64_TR_CURRENT_STACK ++ // remember last page we mapped... ++ mov r8=IA64_KR_CURRENT_STACK ++ mov r9=r26;; ++ XEN_HYPER_SET_KR;; ++#else ++ mov cr.itir=r25 ++ mov cr.ifa=in0 // VA of next task... ++ ;; ++ mov r25=IA64_TR_CURRENT_STACK ++ mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped... ++#endif ++ ;; ++ itr.d dtr[r25]=r23 // wire in new mapping... ++#ifdef CONFIG_XEN ++ ;; ++ srlz.d ++ mov r9=1 ++ movl r8=XSI_PSR_IC ++ ;; ++ st4 [r8]=r9 ++ ;; ++#else ++ ssm psr.ic // reenable the psr.ic bit ++ ;; ++ srlz.d ++#endif ++ br.cond.sptk .done ++#ifdef CONFIG_XEN ++END(xen_switch_to) ++#else ++END(ia64_switch_to) ++#endif ++ ++ /* ++ * Invoke a system call, but do some tracing before and after the call. ++ * We MUST preserve the current register frame throughout this routine ++ * because some system calls (such as ia64_execve) directly ++ * manipulate ar.pfs. ++ */ ++#ifdef CONFIG_XEN ++GLOBAL_ENTRY(xen_trace_syscall) ++ PT_REGS_UNWIND_INFO(0) ++ movl r16=running_on_xen;; ++ ld4 r16=[r16];; ++ cmp.eq p7,p0=r16,r0 ++(p7) br.cond.sptk.many __ia64_trace_syscall;; ++#else ++GLOBAL_ENTRY(ia64_trace_syscall) ++ PT_REGS_UNWIND_INFO(0) ++#endif ++ /* ++ * We need to preserve the scratch registers f6-f11 in case the system ++ * call is sigreturn. ++ */ ++ adds r16=PT(F6)+16,sp ++ adds r17=PT(F7)+16,sp ++ ;; ++ stf.spill [r16]=f6,32 ++ stf.spill [r17]=f7,32 ++ ;; ++ stf.spill [r16]=f8,32 ++ stf.spill [r17]=f9,32 ++ ;; ++ stf.spill [r16]=f10 ++ stf.spill [r17]=f11 ++ br.call.sptk.many rp=syscall_trace_enter // give parent a chance to catch syscall args ++ adds r16=PT(F6)+16,sp ++ adds r17=PT(F7)+16,sp ++ ;; ++ ldf.fill f6=[r16],32 ++ ldf.fill f7=[r17],32 ++ ;; ++ ldf.fill f8=[r16],32 ++ ldf.fill f9=[r17],32 ++ ;; ++ ldf.fill f10=[r16] ++ ldf.fill f11=[r17] ++ // the syscall number may have changed, so re-load it and re-calculate the ++ // syscall entry-point: ++ adds r15=PT(R15)+16,sp // r15 = &pt_regs.r15 (syscall #) ++ ;; ++ ld8 r15=[r15] ++ mov r3=NR_syscalls - 1 ++ ;; ++ adds r15=-1024,r15 ++ movl r16=sys_call_table ++ ;; ++ shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) ++ cmp.leu p6,p7=r15,r3 ++ ;; ++(p6) ld8 r20=[r20] // load address of syscall entry point ++(p7) movl r20=sys_ni_syscall ++ ;; ++ mov b6=r20 ++ br.call.sptk.many rp=b6 // do the syscall ++.strace_check_retval: ++ cmp.lt p6,p0=r8,r0 // syscall failed? ++ adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 ++ adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 ++ mov r10=0 ++(p6) br.cond.sptk strace_error // syscall failed -> ++ ;; // avoid RAW on r10 ++.strace_save_retval: ++.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 ++.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ++ br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value ++.ret3: ++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk ++ br.cond.sptk .work_pending_syscall_end ++ ++strace_error: ++ ld8 r3=[r2] // load pt_regs.r8 ++ sub r9=0,r8 // negate return value to get errno value ++ ;; ++ cmp.ne p6,p0=r3,r0 // is pt_regs.r8!=0? ++ adds r3=16,r2 // r3=&pt_regs.r10 ++ ;; ++(p6) mov r10=-1 ++(p6) mov r8=r9 ++ br.cond.sptk .strace_save_retval ++#ifdef CONFIG_XEN ++END(xen_trace_syscall) ++#else ++END(ia64_trace_syscall) ++#endif ++ ++#ifdef CONFIG_XEN ++GLOBAL_ENTRY(xen_ret_from_clone) ++ PT_REGS_UNWIND_INFO(0) ++ movl r16=running_on_xen;; ++ ld4 r16=[r16];; ++ cmp.eq p7,p0=r16,r0 ++(p7) br.cond.sptk.many __ia64_ret_from_clone;; ++#else ++GLOBAL_ENTRY(ia64_ret_from_clone) ++ PT_REGS_UNWIND_INFO(0) ++#endif ++{ /* ++ * Some versions of gas generate bad unwind info if the first instruction of a ++ * procedure doesn't go into the first slot of a bundle. This is a workaround. ++ */ ++ nop.m 0 ++ nop.i 0 ++ /* ++ * We need to call schedule_tail() to complete the scheduling process. ++ * Called by ia64_switch_to() after do_fork()->copy_thread(). r8 contains the ++ * address of the previously executing task. ++ */ ++ br.call.sptk.many rp=ia64_invoke_schedule_tail ++} ++.ret8: ++ adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 ++ ;; ++ ld4 r2=[r2] ++ ;; ++ mov r8=0 ++ and r2=_TIF_SYSCALL_TRACEAUDIT,r2 ++ ;; ++ cmp.ne p6,p0=r2,r0 ++(p6) br.cond.spnt .strace_check_retval ++ ;; // added stop bits to prevent r8 dependency ++#ifdef CONFIG_XEN ++ br.cond.sptk ia64_ret_from_syscall ++END(xen_ret_from_clone) ++#else ++END(ia64_ret_from_clone) ++#endif ++/* ++ * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't ++ * need to switch to bank 0 and doesn't restore the scratch registers. ++ * To avoid leaking kernel bits, the scratch registers are set to ++ * the following known-to-be-safe values: ++ * ++ * r1: restored (global pointer) ++ * r2: cleared ++ * r3: 1 (when returning to user-level) ++ * r8-r11: restored (syscall return value(s)) ++ * r12: restored (user-level stack pointer) ++ * r13: restored (user-level thread pointer) ++ * r14: set to __kernel_syscall_via_epc ++ * r15: restored (syscall #) ++ * r16-r17: cleared ++ * r18: user-level b6 ++ * r19: cleared ++ * r20: user-level ar.fpsr ++ * r21: user-level b0 ++ * r22: cleared ++ * r23: user-level ar.bspstore ++ * r24: user-level ar.rnat ++ * r25: user-level ar.unat ++ * r26: user-level ar.pfs ++ * r27: user-level ar.rsc ++ * r28: user-level ip ++ * r29: user-level psr ++ * r30: user-level cfm ++ * r31: user-level pr ++ * f6-f11: cleared ++ * pr: restored (user-level pr) ++ * b0: restored (user-level rp) ++ * b6: restored ++ * b7: set to __kernel_syscall_via_epc ++ * ar.unat: restored (user-level ar.unat) ++ * ar.pfs: restored (user-level ar.pfs) ++ * ar.rsc: restored (user-level ar.rsc) ++ * ar.rnat: restored (user-level ar.rnat) ++ * ar.bspstore: restored (user-level ar.bspstore) ++ * ar.fpsr: restored (user-level ar.fpsr) ++ * ar.ccv: cleared ++ * ar.csd: cleared ++ * ar.ssd: cleared ++ */ ++#ifdef CONFIG_XEN ++GLOBAL_ENTRY(xen_leave_syscall) ++ PT_REGS_UNWIND_INFO(0) ++ movl r22=running_on_xen;; ++ ld4 r22=[r22];; ++ cmp.eq p7,p0=r22,r0 ++(p7) br.cond.sptk.many __ia64_leave_syscall;; ++#else ++ENTRY(ia64_leave_syscall) ++ PT_REGS_UNWIND_INFO(0) ++#endif ++ /* ++ * work.need_resched etc. mustn't get changed by this CPU before it returns to ++ * user- or fsys-mode, hence we disable interrupts early on. ++ * ++ * p6 controls whether current_thread_info()->flags needs to be check for ++ * extra work. We always check for extra work when returning to user-level. ++ * With CONFIG_PREEMPT, we also check for extra work when the preempt_count ++ * is 0. After extra work processing has been completed, execution ++ * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check ++ * needs to be redone. ++ */ ++#ifdef CONFIG_PREEMPT ++ rsm psr.i // disable interrupts ++ cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall ++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ++ ;; ++ .pred.rel.mutex pUStk,pKStk ++(pKStk) ld4 r21=[r20] // r21 <- preempt_count ++(pUStk) mov r21=0 // r21 <- 0 ++ ;; ++ cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) ++#else /* !CONFIG_PREEMPT */ ++#ifdef CONFIG_XEN ++ movl r2=XSI_PSR_I_ADDR ++ mov r18=1 ++ ;; ++ ld8 r2=[r2] ++ ;; ++(pUStk) st1 [r2]=r18 ++#else ++(pUStk) rsm psr.i ++#endif ++ cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall ++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk ++#endif ++.work_processed_syscall: ++ adds r2=PT(LOADRS)+16,r12 ++ adds r3=PT(AR_BSPSTORE)+16,r12 ++ adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 ++ ;; ++(p6) ld4 r31=[r18] // load current_thread_info()->flags ++ ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" ++ nop.i 0 ++ ;; ++ mov r16=ar.bsp // M2 get existing backing store pointer ++ ld8 r18=[r2],PT(R9)-PT(B6) // load b6 ++(p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? ++ ;; ++ ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) ++(p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending? ++(p6) br.cond.spnt .work_pending_syscall ++ ;; ++ // start restoring the state saved on the kernel stack (struct pt_regs): ++ ld8 r9=[r2],PT(CR_IPSR)-PT(R9) ++ ld8 r11=[r3],PT(CR_IIP)-PT(R11) ++(pNonSys) break 0 // bug check: we shouldn't be here if pNonSys is TRUE! ++ ;; ++ invala // M0|1 invalidate ALAT ++#ifdef CONFIG_XEN ++ movl r28=XSI_PSR_I_ADDR ++ movl r29=XSI_PSR_IC ++ ;; ++ ld8 r28=[r28] ++ mov r30=1 ++ ;; ++ st1 [r28]=r30 ++ st4 [r29]=r0 // note: clears both vpsr.i and vpsr.ic! ++ ;; ++#else ++ rsm psr.i | psr.ic // M2 turn off interrupts and interruption collection ++#endif ++ cmp.eq p9,p0=r0,r0 // A set p9 to indicate that we should restore cr.ifs ++ ++ ld8 r29=[r2],16 // M0|1 load cr.ipsr ++ ld8 r28=[r3],16 // M0|1 load cr.iip ++ mov r22=r0 // A clear r22 ++ ;; ++ ld8 r30=[r2],16 // M0|1 load cr.ifs ++ ld8 r25=[r3],16 // M0|1 load ar.unat ++(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 ++ ;; ++ ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs ++#ifdef CONFIG_XEN ++(pKStk) mov r21=r8 ++(pKStk) XEN_HYPER_GET_PSR ++ ;; ++(pKStk) mov r22=r8 ++(pKStk) mov r8=r21 ++ ;; ++#else ++(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled ++#endif ++ nop 0 ++ ;; ++ ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // M0|1 load b0 ++ ld8 r27=[r3],PT(PR)-PT(AR_RSC) // M0|1 load ar.rsc ++ mov f6=f0 // F clear f6 ++ ;; ++ ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT) // M0|1 load ar.rnat (may be garbage) ++ ld8 r31=[r3],PT(R1)-PT(PR) // M0|1 load predicates ++ mov f7=f0 // F clear f7 ++ ;; ++ ld8 r20=[r2],PT(R12)-PT(AR_FPSR) // M0|1 load ar.fpsr ++ ld8.fill r1=[r3],16 // M0|1 load r1 ++(pUStk) mov r17=1 // A ++ ;; ++(pUStk) st1 [r14]=r17 // M2|3 ++ ld8.fill r13=[r3],16 // M0|1 ++ mov f8=f0 // F clear f8 ++ ;; ++ ld8.fill r12=[r2] // M0|1 restore r12 (sp) ++ ld8.fill r15=[r3] // M0|1 restore r15 ++ mov b6=r18 // I0 restore b6 ++ ++ addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A ++ mov f9=f0 // F clear f9 ++(pKStk) br.cond.dpnt.many skip_rbs_switch // B ++ ++ srlz.d // M0 ensure interruption collection is off (for cover) ++ shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition ++#ifdef CONFIG_XEN ++ XEN_HYPER_COVER; ++#else ++ cover // B add current frame into dirty partition & set cr.ifs ++#endif ++ ;; ++(pUStk) ld4 r17=[r17] // M0|1 r17 = cpu_data->phys_stacked_size_p8 ++ mov r19=ar.bsp // M2 get new backing store pointer ++ mov f10=f0 // F clear f10 ++ ++ nop.m 0 ++ movl r14=__kernel_syscall_via_epc // X ++ ;; ++ mov.m ar.csd=r0 // M2 clear ar.csd ++ mov.m ar.ccv=r0 // M2 clear ar.ccv ++ mov b7=r14 // I0 clear b7 (hint with __kernel_syscall_via_epc) ++ ++ mov.m ar.ssd=r0 // M2 clear ar.ssd ++ mov f11=f0 // F clear f11 ++ br.cond.sptk.many rbs_switch // B ++#ifdef CONFIG_XEN ++END(xen_leave_syscall) ++#else ++END(ia64_leave_syscall) ++#endif ++ ++#ifdef CONFIG_XEN ++GLOBAL_ENTRY(xen_leave_kernel) ++ PT_REGS_UNWIND_INFO(0) ++ movl r22=running_on_xen;; ++ ld4 r22=[r22];; ++ cmp.eq p7,p0=r22,r0 ++(p7) br.cond.sptk.many __ia64_leave_kernel;; ++#else ++GLOBAL_ENTRY(ia64_leave_kernel) ++ PT_REGS_UNWIND_INFO(0) ++#endif ++ /* ++ * work.need_resched etc. mustn't get changed by this CPU before it returns to ++ * user- or fsys-mode, hence we disable interrupts early on. ++ * ++ * p6 controls whether current_thread_info()->flags needs to be check for ++ * extra work. We always check for extra work when returning to user-level. ++ * With CONFIG_PREEMPT, we also check for extra work when the preempt_count ++ * is 0. After extra work processing has been completed, execution ++ * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check ++ * needs to be redone. ++ */ ++#ifdef CONFIG_PREEMPT ++ rsm psr.i // disable interrupts ++ cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel ++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ++ ;; ++ .pred.rel.mutex pUStk,pKStk ++(pKStk) ld4 r21=[r20] // r21 <- preempt_count ++(pUStk) mov r21=0 // r21 <- 0 ++ ;; ++ cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) ++#else ++#ifdef CONFIG_XEN ++(pUStk) movl r17=XSI_PSR_I_ADDR ++(pUStk) mov r31=1 ++ ;; ++(pUStk) ld8 r17=[r17] ++ ;; ++(pUStk) st1 [r17]=r31 ++ ;; ++#else ++(pUStk) rsm psr.i ++#endif ++ cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel ++(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk ++#endif ++.work_processed_kernel: ++ adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 ++ ;; ++(p6) ld4 r31=[r17] // load current_thread_info()->flags ++ adds r21=PT(PR)+16,r12 ++ ;; ++ ++ lfetch [r21],PT(CR_IPSR)-PT(PR) ++ adds r2=PT(B6)+16,r12 ++ adds r3=PT(R16)+16,r12 ++ ;; ++ lfetch [r21] ++ ld8 r28=[r2],8 // load b6 ++ adds r29=PT(R24)+16,r12 ++ ++ ld8.fill r16=[r3],PT(AR_CSD)-PT(R16) ++ adds r30=PT(AR_CCV)+16,r12 ++(p6) and r19=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? ++ ;; ++ ld8.fill r24=[r29] ++ ld8 r15=[r30] // load ar.ccv ++(p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending? ++ ;; ++ ld8 r29=[r2],16 // load b7 ++ ld8 r30=[r3],16 // load ar.csd ++(p6) br.cond.spnt .work_pending ++ ;; ++ ld8 r31=[r2],16 // load ar.ssd ++ ld8.fill r8=[r3],16 ++ ;; ++ ld8.fill r9=[r2],16 ++ ld8.fill r10=[r3],PT(R17)-PT(R10) ++ ;; ++ ld8.fill r11=[r2],PT(R18)-PT(R11) ++ ld8.fill r17=[r3],16 ++ ;; ++ ld8.fill r18=[r2],16 ++ ld8.fill r19=[r3],16 ++ ;; ++ ld8.fill r20=[r2],16 ++ ld8.fill r21=[r3],16 ++ mov ar.csd=r30 ++ mov ar.ssd=r31 ++ ;; ++#ifdef CONFIG_XEN ++ movl r23=XSI_PSR_I_ADDR ++ movl r22=XSI_PSR_IC ++ ;; ++ ld8 r23=[r23] ++ mov r25=1 ++ ;; ++ st1 [r23]=r25 ++ st4 [r22]=r0 // note: clears both vpsr.i and vpsr.ic! ++ ;; ++#else ++ rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection ++#endif ++ invala // invalidate ALAT ++ ;; ++ ld8.fill r22=[r2],24 ++ ld8.fill r23=[r3],24 ++ mov b6=r28 ++ ;; ++ ld8.fill r25=[r2],16 ++ ld8.fill r26=[r3],16 ++ mov b7=r29 ++ ;; ++ ld8.fill r27=[r2],16 ++ ld8.fill r28=[r3],16 ++ ;; ++ ld8.fill r29=[r2],16 ++ ld8.fill r30=[r3],24 ++ ;; ++ ld8.fill r31=[r2],PT(F9)-PT(R31) ++ adds r3=PT(F10)-PT(F6),r3 ++ ;; ++ ldf.fill f9=[r2],PT(F6)-PT(F9) ++ ldf.fill f10=[r3],PT(F8)-PT(F10) ++ ;; ++ ldf.fill f6=[r2],PT(F7)-PT(F6) ++ ;; ++ ldf.fill f7=[r2],PT(F11)-PT(F7) ++ ldf.fill f8=[r3],32 ++ ;; ++ srlz.d // ensure that inter. collection is off (VHPT is don't care, since text is pinned) ++ mov ar.ccv=r15 ++ ;; ++ ldf.fill f11=[r2] ++#ifdef CONFIG_XEN ++ ;; ++ // r16-r31 all now hold bank1 values ++ mov r15=ar.unat ++ movl r2=XSI_BANK1_R16 ++ movl r3=XSI_BANK1_R16+8 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r16,16 ++.mem.offset 8,0; st8.spill [r3]=r17,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r18,16 ++.mem.offset 8,0; st8.spill [r3]=r19,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r20,16 ++.mem.offset 8,0; st8.spill [r3]=r21,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r22,16 ++.mem.offset 8,0; st8.spill [r3]=r23,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r24,16 ++.mem.offset 8,0; st8.spill [r3]=r25,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r26,16 ++.mem.offset 8,0; st8.spill [r3]=r27,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r28,16 ++.mem.offset 8,0; st8.spill [r3]=r29,16 ++ ;; ++.mem.offset 0,0; st8.spill [r2]=r30,16 ++.mem.offset 8,0; st8.spill [r3]=r31,16 ++ ;; ++ mov r3=ar.unat ++ movl r2=XSI_B1NAT ++ ;; ++ st8 [r2]=r3 ++ mov ar.unat=r15 ++ movl r2=XSI_BANKNUM;; ++ st4 [r2]=r0; ++#else ++ bsw.0 // switch back to bank 0 (no stop bit required beforehand...) ++#endif ++ ;; ++(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency) ++ adds r16=PT(CR_IPSR)+16,r12 ++ adds r17=PT(CR_IIP)+16,r12 ++ ++#ifdef CONFIG_XEN ++(pKStk) mov r29=r8 ++(pKStk) XEN_HYPER_GET_PSR ++ ;; ++(pKStk) mov r22=r8 ++(pKStk) mov r8=r29 ++ ;; ++#else ++(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled ++#endif ++ nop.i 0 ++ nop.i 0 ++ ;; ++ ld8 r29=[r16],16 // load cr.ipsr ++ ld8 r28=[r17],16 // load cr.iip ++ ;; ++ ld8 r30=[r16],16 // load cr.ifs ++ ld8 r25=[r17],16 // load ar.unat ++ ;; ++ ld8 r26=[r16],16 // load ar.pfs ++ ld8 r27=[r17],16 // load ar.rsc ++ cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ++ ;; ++ ld8 r24=[r16],16 // load ar.rnat (may be garbage) ++ ld8 r23=[r17],16 // load ar.bspstore (may be garbage) ++ ;; ++ ld8 r31=[r16],16 // load predicates ++ ld8 r21=[r17],16 // load b0 ++ ;; ++ ld8 r19=[r16],16 // load ar.rsc value for "loadrs" ++ ld8.fill r1=[r17],16 // load r1 ++ ;; ++ ld8.fill r12=[r16],16 ++ ld8.fill r13=[r17],16 ++(pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 ++ ;; ++ ld8 r20=[r16],16 // ar.fpsr ++ ld8.fill r15=[r17],16 ++ ;; ++ ld8.fill r14=[r16],16 ++ ld8.fill r2=[r17] ++(pUStk) mov r17=1 ++ ;; ++ ld8.fill r3=[r16] ++(pUStk) st1 [r18]=r17 // restore current->thread.on_ustack ++ shr.u r18=r19,16 // get byte size of existing "dirty" partition ++ ;; ++ mov r16=ar.bsp // get existing backing store pointer ++ addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 ++ ;; ++ ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 ++(pKStk) br.cond.dpnt skip_rbs_switch ++ ++ /* ++ * Restore user backing store. ++ * ++ * NOTE: alloc, loadrs, and cover can't be predicated. ++ */ ++(pNonSys) br.cond.dpnt dont_preserve_current_frame ++ ++#ifdef CONFIG_XEN ++ XEN_HYPER_COVER; ++#else ++ cover // add current frame into dirty partition and set cr.ifs ++#endif ++ ;; ++ mov r19=ar.bsp // get new backing store pointer ++rbs_switch: ++ sub r16=r16,r18 // krbs = old bsp - size of dirty partition ++ cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs ++ ;; ++ sub r19=r19,r16 // calculate total byte size of dirty partition ++ add r18=64,r18 // don't force in0-in7 into memory... ++ ;; ++ shl r19=r19,16 // shift size of dirty partition into loadrs position ++ ;; ++dont_preserve_current_frame: ++ /* ++ * To prevent leaking bits between the kernel and user-space, ++ * we must clear the stacked registers in the "invalid" partition here. ++ * Not pretty, but at least it's fast (3.34 registers/cycle on Itanium, ++ * 5 registers/cycle on McKinley). ++ */ ++# define pRecurse p6 ++# define pReturn p7 ++#ifdef CONFIG_ITANIUM ++# define Nregs 10 ++#else ++# define Nregs 14 ++#endif ++ alloc loc0=ar.pfs,2,Nregs-2,2,0 ++ shr.u loc1=r18,9 // RNaTslots <= floor(dirtySize / (64*8)) ++ sub r17=r17,r18 // r17 = (physStackedSize + 8) - dirtySize ++ ;; ++ mov ar.rsc=r19 // load ar.rsc to be used for "loadrs" ++ shladd in0=loc1,3,r17 ++ mov in1=0 ++ ;; ++ TEXT_ALIGN(32) ++rse_clear_invalid: ++#ifdef CONFIG_ITANIUM ++ // cycle 0 ++ { .mii ++ alloc loc0=ar.pfs,2,Nregs-2,2,0 ++ cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse ++ add out0=-Nregs*8,in0 ++}{ .mfb ++ add out1=1,in1 // increment recursion count ++ nop.f 0 ++ nop.b 0 // can't do br.call here because of alloc (WAW on CFM) ++ ;; ++}{ .mfi // cycle 1 ++ mov loc1=0 ++ nop.f 0 ++ mov loc2=0 ++}{ .mib ++ mov loc3=0 ++ mov loc4=0 ++(pRecurse) br.call.sptk.many b0=rse_clear_invalid ++ ++}{ .mfi // cycle 2 ++ mov loc5=0 ++ nop.f 0 ++ cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret ++}{ .mib ++ mov loc6=0 ++ mov loc7=0 ++(pReturn) br.ret.sptk.many b0 ++} ++#else /* !CONFIG_ITANIUM */ ++ alloc loc0=ar.pfs,2,Nregs-2,2,0 ++ cmp.lt pRecurse,p0=Nregs*8,in0 // if more than Nregs regs left to clear, (re)curse ++ add out0=-Nregs*8,in0 ++ add out1=1,in1 // increment recursion count ++ mov loc1=0 ++ mov loc2=0 ++ ;; ++ mov loc3=0 ++ mov loc4=0 ++ mov loc5=0 ++ mov loc6=0 ++ mov loc7=0 ++(pRecurse) br.call.dptk.few b0=rse_clear_invalid ++ ;; ++ mov loc8=0 ++ mov loc9=0 ++ cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret ++ mov loc10=0 ++ mov loc11=0 ++(pReturn) br.ret.dptk.many b0 ++#endif /* !CONFIG_ITANIUM */ ++# undef pRecurse ++# undef pReturn ++ ;; ++ alloc r17=ar.pfs,0,0,0,0 // drop current register frame ++ ;; ++ loadrs ++ ;; ++skip_rbs_switch: ++ mov ar.unat=r25 // M2 ++(pKStk) extr.u r22=r22,21,1 // I0 extract current value of psr.pp from r22 ++(pLvSys)mov r19=r0 // A clear r19 for leave_syscall, no-op otherwise ++ ;; ++(pUStk) mov ar.bspstore=r23 // M2 ++(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp ++(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise ++ ;; ++#ifdef CONFIG_XEN ++ movl r25=XSI_IPSR ++ ;; ++ st8[r25]=r29,XSI_IFS_OFS-XSI_IPSR_OFS ++ ;; ++#else ++ mov cr.ipsr=r29 // M2 ++#endif ++ mov ar.pfs=r26 // I0 ++(pLvSys)mov r17=r0 // A clear r17 for leave_syscall, no-op otherwise ++ ++#ifdef CONFIG_XEN ++(p9) st8 [r25]=r30 ++ ;; ++ adds r25=XSI_IIP_OFS-XSI_IFS_OFS,r25 ++ ;; ++#else ++(p9) mov cr.ifs=r30 // M2 ++#endif ++ mov b0=r21 // I0 ++(pLvSys)mov r18=r0 // A clear r18 for leave_syscall, no-op otherwise ++ ++ mov ar.fpsr=r20 // M2 ++#ifdef CONFIG_XEN ++ st8 [r25]=r28 ++#else ++ mov cr.iip=r28 // M2 ++#endif ++ nop 0 ++ ;; ++(pUStk) mov ar.rnat=r24 // M2 must happen with RSE in lazy mode ++ nop 0 ++(pLvSys)mov r2=r0 ++ ++ mov ar.rsc=r27 // M2 ++ mov pr=r31,-1 // I0 ++#ifdef CONFIG_XEN ++ ;; ++ XEN_HYPER_RFI; ++#else ++ rfi // B ++#endif ++ ++ /* ++ * On entry: ++ * r20 = ¤t->thread_info->pre_count (if CONFIG_PREEMPT) ++ * r31 = current->thread_info->flags ++ * On exit: ++ * p6 = TRUE if work-pending-check needs to be redone ++ */ ++.work_pending_syscall: ++ add r2=-8,r2 ++ add r3=-8,r3 ++ ;; ++ st8 [r2]=r8 ++ st8 [r3]=r10 ++.work_pending: ++ tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? ++(p6) br.cond.sptk.few .notify ++#ifdef CONFIG_PREEMPT ++(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 ++ ;; ++(pKStk) st4 [r20]=r21 ++ ssm psr.i // enable interrupts ++#endif ++ br.call.spnt.many rp=schedule ++.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 ++#ifdef CONFIG_XEN ++ movl r2=XSI_PSR_I_ADDR ++ mov r20=1 ++ ;; ++ ld8 r2=[r2] ++ ;; ++ st1 [r2]=r20 ++#else ++ rsm psr.i // disable interrupts ++#endif ++ ;; ++#ifdef CONFIG_PREEMPT ++(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ++ ;; ++(pKStk) st4 [r20]=r0 // preempt_count() <- 0 ++#endif ++(pLvSys)br.cond.sptk.few .work_pending_syscall_end ++ br.cond.sptk.many .work_processed_kernel // re-check ++ ++.notify: ++(pUStk) br.call.spnt.many rp=notify_resume_user ++.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 ++(pLvSys)br.cond.sptk.few .work_pending_syscall_end ++ br.cond.sptk.many .work_processed_kernel // don't re-check ++ ++.work_pending_syscall_end: ++ adds r2=PT(R8)+16,r12 ++ adds r3=PT(R10)+16,r12 ++ ;; ++ ld8 r8=[r2] ++ ld8 r10=[r3] ++ br.cond.sptk.many .work_processed_syscall // re-check ++ ++#ifdef CONFIG_XEN ++END(xen_leave_kernel) ++#else ++END(ia64_leave_kernel) ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xenhpski.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xenhpski.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,19 @@ ++ ++extern unsigned long xen_get_cpuid(int); ++ ++int ++running_on_sim(void) ++{ ++ int i; ++ long cpuid[6]; ++ ++ for (i = 0; i < 5; ++i) ++ cpuid[i] = xen_get_cpuid(i); ++ if ((cpuid[0] & 0xff) != 'H') return 0; ++ if ((cpuid[3] & 0xff) != 0x4) return 0; ++ if (((cpuid[3] >> 8) & 0xff) != 0x0) return 0; ++ if (((cpuid[3] >> 16) & 0xff) != 0x0) return 0; ++ if (((cpuid[3] >> 24) & 0x7) != 0x7) return 0; ++ return 1; ++} ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xenivt.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xenivt.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2177 @@ ++/* ++ * arch/ia64/xen/ivt.S ++ * ++ * Copyright (C) 2005 Hewlett-Packard Co ++ * Dan Magenheimer <dan.magenheimer@hp.com> ++ */ ++/* ++ * This file defines the interruption vector table used by the CPU. ++ * It does not include one entry per possible cause of interruption. ++ * ++ * The first 20 entries of the table contain 64 bundles each while the ++ * remaining 48 entries contain only 16 bundles each. ++ * ++ * The 64 bundles are used to allow inlining the whole handler for critical ++ * interruptions like TLB misses. ++ * ++ * For each entry, the comment is as follows: ++ * ++ * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) ++ * entry offset ----/ / / / / ++ * entry number ---------/ / / / ++ * size of the entry -------------/ / / ++ * vector name -------------------------------------/ / ++ * interruptions triggering this vector ----------------------/ ++ * ++ * The table is 32KB in size and must be aligned on 32KB boundary. ++ * (The CPU ignores the 15 lower bits of the address) ++ * ++ * Table is based upon EAS2.6 (Oct 1999) ++ */ ++ ++#include <asm/asmmacro.h> ++#include <asm/break.h> ++#include <asm/ia32.h> ++#include <asm/kregs.h> ++#include <asm/asm-offsets.h> ++#include <asm/pgtable.h> ++#include <asm/processor.h> ++#include <asm/ptrace.h> ++#include <asm/system.h> ++#include <asm/thread_info.h> ++#include <asm/unistd.h> ++#include <asm/errno.h> ++ ++#ifdef CONFIG_XEN ++#define ia64_ivt xen_ivt ++#endif ++ ++#if 1 ++# define PSR_DEFAULT_BITS psr.ac ++#else ++# define PSR_DEFAULT_BITS 0 ++#endif ++ ++#if 0 ++ /* ++ * This lets you track the last eight faults that occurred on the CPU. Make sure ar.k2 isn't ++ * needed for something else before enabling this... ++ */ ++# define DBG_FAULT(i) mov r16=ar.k2;; shl r16=r16,8;; add r16=(i),r16;;mov ar.k2=r16 ++#else ++# define DBG_FAULT(i) ++#endif ++ ++#define MINSTATE_VIRT /* needed by minstate.h */ ++#include "xenminstate.h" ++ ++#define FAULT(n) \ ++ mov r31=pr; \ ++ mov r19=n;; /* prepare to save predicates */ \ ++ br.sptk.many dispatch_to_fault_handler ++ ++ .section .text.ivt,"ax" ++ ++ .align 32768 // align on 32KB boundary ++ .global ia64_ivt ++ia64_ivt: ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) ++ENTRY(vhpt_miss) ++ DBG_FAULT(0) ++ /* ++ * The VHPT vector is invoked when the TLB entry for the virtual page table ++ * is missing. This happens only as a result of a previous ++ * (the "original") TLB miss, which may either be caused by an instruction ++ * fetch or a data access (or non-access). ++ * ++ * What we do here is normal TLB miss handing for the _original_ miss, ++ * followed by inserting the TLB entry for the virtual page table page ++ * that the VHPT walker was attempting to access. The latter gets ++ * inserted as long as page table entry above pte level have valid ++ * mappings for the faulting address. The TLB entry for the original ++ * miss gets inserted only if the pte entry indicates that the page is ++ * present. ++ * ++ * do_page_fault gets invoked in the following cases: ++ * - the faulting virtual address uses unimplemented address bits ++ * - the faulting virtual address has no valid page table mapping ++ */ ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++#ifdef CONFIG_HUGETLB_PAGE ++ movl r18=PAGE_SHIFT ++ movl r25=XSI_ITIR ++ ;; ++ ld8 r25=[r25] ++#endif ++ ;; ++#else ++ mov r16=cr.ifa // get address that caused the TLB miss ++#ifdef CONFIG_HUGETLB_PAGE ++ movl r18=PAGE_SHIFT ++ mov r25=cr.itir ++#endif ++#endif ++ ;; ++#ifdef CONFIG_XEN ++ XEN_HYPER_RSM_PSR_DT; ++#else ++ rsm psr.dt // use physical addressing for data ++#endif ++ mov r31=pr // save the predicate registers ++ mov r19=IA64_KR(PT_BASE) // get page table base address ++ shl r21=r16,3 // shift bit 60 into sign bit ++ shr.u r17=r16,61 // get the region number into r17 ++ ;; ++ shr.u r22=r21,3 ++#ifdef CONFIG_HUGETLB_PAGE ++ extr.u r26=r25,2,6 ++ ;; ++ cmp.ne p8,p0=r18,r26 ++ sub r27=r26,r18 ++ ;; ++(p8) dep r25=r18,r25,2,6 ++(p8) shr r22=r22,r27 ++#endif ++ ;; ++ cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? ++ shr.u r18=r22,PGDIR_SHIFT // get bottom portion of pgd index bit ++ ;; ++(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place ++ ++ srlz.d ++ LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir ++ ++ .pred.rel "mutex", p6, p7 ++(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT ++(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ++ ;; ++(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5 ++(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4] ++ cmp.eq p7,p6=0,r21 // unused address bits all zeroes? ++#ifdef CONFIG_PGTABLE_4 ++ shr.u r28=r22,PUD_SHIFT // shift pud index into position ++#else ++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position ++#endif ++ ;; ++ ld8 r17=[r17] // get *pgd (may be 0) ++ ;; ++(p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL? ++#ifdef CONFIG_PGTABLE_4 ++ dep r28=r28,r17,3,(PAGE_SHIFT-3) // r28=pud_offset(pgd,addr) ++ ;; ++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position ++(p7) ld8 r29=[r28] // get *pud (may be 0) ++ ;; ++(p7) cmp.eq.or.andcm p6,p7=r29,r0 // was pud_present(*pud) == NULL? ++ dep r17=r18,r29,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr) ++#else ++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pgd,addr) ++#endif ++ ;; ++(p7) ld8 r20=[r17] // get *pmd (may be 0) ++ shr.u r19=r22,PAGE_SHIFT // shift pte index into position ++ ;; ++(p7) cmp.eq.or.andcm p6,p7=r20,r0 // was pmd_present(*pmd) == NULL? ++ dep r21=r19,r20,3,(PAGE_SHIFT-3) // r21=pte_offset(pmd,addr) ++ ;; ++(p7) ld8 r18=[r21] // read *pte ++#ifdef CONFIG_XEN ++ movl r19=XSI_ISR ++ ;; ++ ld8 r19=[r19] ++#else ++ mov r19=cr.isr // cr.isr bit 32 tells us if this is an insn miss ++#endif ++ ;; ++(p7) tbit.z p6,p7=r18,_PAGE_P_BIT // page present bit cleared? ++#ifdef CONFIG_XEN ++ movl r22=XSI_IHA ++ ;; ++ ld8 r22=[r22] ++#else ++ mov r22=cr.iha // get the VHPT address that caused the TLB miss ++#endif ++ ;; // avoid RAW on p7 ++(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? ++ dep r23=0,r20,0,PAGE_SHIFT // clear low bits to get page address ++ ;; ++#ifdef CONFIG_XEN ++ mov r24=r8 ++ mov r8=r18 ++ ;; ++(p10) XEN_HYPER_ITC_I ++ ;; ++(p11) XEN_HYPER_ITC_D ++ ;; ++ mov r8=r24 ++ ;; ++#else ++(p10) itc.i r18 // insert the instruction TLB entry ++(p11) itc.d r18 // insert the data TLB entry ++#endif ++(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) ++#ifdef CONFIG_XEN ++ movl r24=XSI_IFA ++ ;; ++ st8 [r24]=r22 ++ ;; ++#else ++ mov cr.ifa=r22 ++#endif ++ ++#ifdef CONFIG_HUGETLB_PAGE ++(p8) mov cr.itir=r25 // change to default page-size for VHPT ++#endif ++ ++ /* ++ * Now compute and insert the TLB entry for the virtual page table. We never ++ * execute in a page table page so there is no need to set the exception deferral ++ * bit. ++ */ ++ adds r24=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r23 ++ ;; ++#ifdef CONFIG_XEN ++(p7) mov r25=r8 ++(p7) mov r8=r24 ++ ;; ++(p7) XEN_HYPER_ITC_D ++ ;; ++(p7) mov r8=r25 ++ ;; ++#else ++(p7) itc.d r24 ++#endif ++ ;; ++#ifdef CONFIG_SMP ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ++ /* ++ * Re-check pagetable entry. If they changed, we may have received a ptc.g ++ * between reading the pagetable and the "itc". If so, flush the entry we ++ * inserted and retry. At this point, we have: ++ * ++ * r28 = equivalent of pud_offset(pgd, ifa) ++ * r17 = equivalent of pmd_offset(pud, ifa) ++ * r21 = equivalent of pte_offset(pmd, ifa) ++ * ++ * r29 = *pud ++ * r20 = *pmd ++ * r18 = *pte ++ */ ++ ld8 r25=[r21] // read *pte again ++ ld8 r26=[r17] // read *pmd again ++#ifdef CONFIG_PGTABLE_4 ++ ld8 r19=[r28] // read *pud again ++#endif ++ cmp.ne p6,p7=r0,r0 ++ ;; ++ cmp.ne.or.andcm p6,p7=r26,r20 // did *pmd change ++#ifdef CONFIG_PGTABLE_4 ++ cmp.ne.or.andcm p6,p7=r19,r29 // did *pud change ++#endif ++ mov r27=PAGE_SHIFT<<2 ++ ;; ++(p6) ptc.l r22,r27 // purge PTE page translation ++(p7) cmp.ne.or.andcm p6,p7=r25,r18 // did *pte change ++ ;; ++(p6) ptc.l r16,r27 // purge translation ++#endif ++ ++ mov pr=r31,-1 // restore predicate registers ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(vhpt_miss) ++ ++ .org ia64_ivt+0x400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x0400 Entry 1 (size 64 bundles) ITLB (21) ++ENTRY(itlb_miss) ++ DBG_FAULT(1) ++ /* ++ * The ITLB handler accesses the PTE via the virtually mapped linear ++ * page table. If a nested TLB miss occurs, we switch into physical ++ * mode, walk the page table, and then re-execute the PTE read and ++ * go on normally after that. ++ */ ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++#else ++ mov r16=cr.ifa // get virtual address ++#endif ++ mov r29=b0 // save b0 ++ mov r31=pr // save predicates ++.itlb_fault: ++#ifdef CONFIG_XEN ++ movl r17=XSI_IHA ++ ;; ++ ld8 r17=[r17] // get virtual address of L3 PTE ++#else ++ mov r17=cr.iha // get virtual address of PTE ++#endif ++ movl r30=1f // load nested fault continuation point ++ ;; ++1: ld8 r18=[r17] // read *pte ++ ;; ++ mov b0=r29 ++ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? ++(p6) br.cond.spnt page_fault ++ ;; ++#ifdef CONFIG_XEN ++ mov r19=r8 ++ mov r8=r18 ++ ;; ++ XEN_HYPER_ITC_I ++ ;; ++ mov r8=r19 ++#else ++ itc.i r18 ++#endif ++ ;; ++#ifdef CONFIG_SMP ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ++ ld8 r19=[r17] // read *pte again and see if same ++ mov r20=PAGE_SHIFT<<2 // setup page size for purge ++ ;; ++ cmp.ne p7,p0=r18,r19 ++ ;; ++(p7) ptc.l r16,r20 ++#endif ++ mov pr=r31,-1 ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(itlb_miss) ++ ++ .org ia64_ivt+0x0800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) ++ENTRY(dtlb_miss) ++ DBG_FAULT(2) ++ /* ++ * The DTLB handler accesses the PTE via the virtually mapped linear ++ * page table. If a nested TLB miss occurs, we switch into physical ++ * mode, walk the page table, and then re-execute the PTE read and ++ * go on normally after that. ++ */ ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++#else ++ mov r16=cr.ifa // get virtual address ++#endif ++ mov r29=b0 // save b0 ++ mov r31=pr // save predicates ++dtlb_fault: ++#ifdef CONFIG_XEN ++ movl r17=XSI_IHA ++ ;; ++ ld8 r17=[r17] // get virtual address of L3 PTE ++#else ++ mov r17=cr.iha // get virtual address of PTE ++#endif ++ movl r30=1f // load nested fault continuation point ++ ;; ++1: ld8 r18=[r17] // read *pte ++ ;; ++ mov b0=r29 ++ tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? ++(p6) br.cond.spnt page_fault ++ ;; ++#ifdef CONFIG_XEN ++ mov r19=r8 ++ mov r8=r18 ++ ;; ++ XEN_HYPER_ITC_D ++ ;; ++ mov r8=r19 ++ ;; ++#else ++ itc.d r18 ++#endif ++ ;; ++#ifdef CONFIG_SMP ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ++ ld8 r19=[r17] // read *pte again and see if same ++ mov r20=PAGE_SHIFT<<2 // setup page size for purge ++ ;; ++ cmp.ne p7,p0=r18,r19 ++ ;; ++(p7) ptc.l r16,r20 ++#endif ++ mov pr=r31,-1 ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(dtlb_miss) ++ ++ .org ia64_ivt+0x0c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) ++ENTRY(alt_itlb_miss) ++ DBG_FAULT(3) ++#ifdef CONFIG_XEN ++ movl r31=XSI_IPSR ++ ;; ++ ld8 r21=[r31],XSI_IFA_OFS-XSI_IPSR_OFS // get ipsr, point to ifa ++ movl r17=PAGE_KERNEL ++ ;; ++ ld8 r16=[r31] // get ifa ++#else ++ mov r16=cr.ifa // get address that caused the TLB miss ++ movl r17=PAGE_KERNEL ++ mov r21=cr.ipsr ++#endif ++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) ++ mov r31=pr ++ ;; ++#ifdef CONFIG_DISABLE_VHPT ++ shr.u r22=r16,61 // get the region number into r21 ++ ;; ++ cmp.gt p8,p0=6,r22 // user mode ++ ;; ++#ifndef CONFIG_XEN ++(p8) thash r17=r16 ++ ;; ++(p8) mov cr.iha=r17 ++#endif ++(p8) mov r29=b0 // save b0 ++(p8) br.cond.dptk .itlb_fault ++#endif ++ extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl ++ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits ++ shr.u r18=r16,57 // move address bit 61 to bit 4 ++ ;; ++ andcm r18=0x10,r18 // bit 4=~address-bit(61) ++ cmp.ne p8,p0=r0,r23 // psr.cpl != 0? ++ or r19=r17,r19 // insert PTE control bits into r19 ++ ;; ++ or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 ++(p8) br.cond.spnt page_fault ++ ;; ++#ifdef CONFIG_XEN ++ mov r18=r8 ++ mov r8=r19 ++ ;; ++ XEN_HYPER_ITC_I ++ ;; ++ mov r8=r18 ++ ;; ++ mov pr=r31,-1 ++ ;; ++ XEN_HYPER_RFI; ++#else ++ itc.i r19 // insert the TLB entry ++ mov pr=r31,-1 ++ rfi ++#endif ++END(alt_itlb_miss) ++ ++ .org ia64_ivt+0x1000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) ++ENTRY(alt_dtlb_miss) ++ DBG_FAULT(4) ++#ifdef CONFIG_XEN ++ movl r31=XSI_IPSR ++ ;; ++ ld8 r21=[r31],XSI_ISR_OFS-XSI_IPSR_OFS // get ipsr, point to isr ++ movl r17=PAGE_KERNEL ++ ;; ++ ld8 r20=[r31],XSI_IFA_OFS-XSI_ISR_OFS // get isr, point to ifa ++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) ++ ;; ++ ld8 r16=[r31] // get ifa ++#else ++ mov r16=cr.ifa // get address that caused the TLB miss ++ movl r17=PAGE_KERNEL ++ mov r20=cr.isr ++ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) ++ mov r21=cr.ipsr ++#endif ++ mov r31=pr ++ ;; ++#ifdef CONFIG_DISABLE_VHPT ++ shr.u r22=r16,61 // get the region number into r21 ++ ;; ++ cmp.gt p8,p0=6,r22 // access to region 0-5 ++ ;; ++#ifndef CONFIG_XEN ++(p8) thash r17=r16 ++ ;; ++(p8) mov cr.iha=r17 ++#endif ++(p8) mov r29=b0 // save b0 ++(p8) br.cond.dptk dtlb_fault ++#endif ++ extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl ++ and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field ++ tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? ++ shr.u r18=r16,57 // move address bit 61 to bit 4 ++ and r19=r19,r16 // clear ed, reserved bits, and PTE control bits ++ tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on? ++ ;; ++ andcm r18=0x10,r18 // bit 4=~address-bit(61) ++ cmp.ne p8,p0=r0,r23 ++(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field ++(p8) br.cond.spnt page_fault ++ ++ dep r21=-1,r21,IA64_PSR_ED_BIT,1 ++ or r19=r19,r17 // insert PTE control bits into r19 ++ ;; ++ or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 ++(p6) mov cr.ipsr=r21 ++ ;; ++#ifdef CONFIG_XEN ++(p7) mov r18=r8 ++(p7) mov r8=r19 ++ ;; ++(p7) XEN_HYPER_ITC_D ++ ;; ++(p7) mov r8=r18 ++ ;; ++ mov pr=r31,-1 ++ ;; ++ XEN_HYPER_RFI; ++#else ++(p7) itc.d r19 // insert the TLB entry ++ mov pr=r31,-1 ++ rfi ++#endif ++END(alt_dtlb_miss) ++ ++ .org ia64_ivt+0x1400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) ++ENTRY(nested_dtlb_miss) ++ /* ++ * In the absence of kernel bugs, we get here when the virtually mapped linear ++ * page table is accessed non-speculatively (e.g., in the Dirty-bit, Instruction ++ * Access-bit, or Data Access-bit faults). If the DTLB entry for the virtual page ++ * table is missing, a nested TLB miss fault is triggered and control is ++ * transferred to this point. When this happens, we lookup the pte for the ++ * faulting address by walking the page table in physical mode and return to the ++ * continuation point passed in register r30 (or call page_fault if the address is ++ * not mapped). ++ * ++ * Input: r16: faulting address ++ * r29: saved b0 ++ * r30: continuation address ++ * r31: saved pr ++ * ++ * Output: r17: physical address of PTE of faulting address ++ * r29: saved b0 ++ * r30: continuation address ++ * r31: saved pr ++ * ++ * Clobbered: b0, r18, r19, r21, r22, psr.dt (cleared) ++ */ ++#ifdef CONFIG_XEN ++ XEN_HYPER_RSM_PSR_DT; ++#else ++ rsm psr.dt // switch to using physical data addressing ++#endif ++ mov r19=IA64_KR(PT_BASE) // get the page table base address ++ shl r21=r16,3 // shift bit 60 into sign bit ++#ifdef CONFIG_XEN ++ movl r18=XSI_ITIR ++ ;; ++ ld8 r18=[r18] ++#else ++ mov r18=cr.itir ++#endif ++ ;; ++ shr.u r17=r16,61 // get the region number into r17 ++ extr.u r18=r18,2,6 // get the faulting page size ++ ;; ++ cmp.eq p6,p7=5,r17 // is faulting address in region 5? ++ add r22=-PAGE_SHIFT,r18 // adjustment for hugetlb address ++ add r18=PGDIR_SHIFT-PAGE_SHIFT,r18 ++ ;; ++ shr.u r22=r16,r22 ++ shr.u r18=r16,r18 ++(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place ++ ++ srlz.d ++ LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir ++ ++ .pred.rel "mutex", p6, p7 ++(p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT ++(p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ++ ;; ++(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=pgd_offset for region 5 ++(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=pgd_offset for region[0-4] ++ cmp.eq p7,p6=0,r21 // unused address bits all zeroes? ++#ifdef CONFIG_PGTABLE_4 ++ shr.u r18=r22,PUD_SHIFT // shift pud index into position ++#else ++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position ++#endif ++ ;; ++ ld8 r17=[r17] // get *pgd (may be 0) ++ ;; ++(p7) cmp.eq p6,p7=r17,r0 // was pgd_present(*pgd) == NULL? ++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=p[u|m]d_offset(pgd,addr) ++ ;; ++#ifdef CONFIG_PGTABLE_4 ++(p7) ld8 r17=[r17] // get *pud (may be 0) ++ shr.u r18=r22,PMD_SHIFT // shift pmd index into position ++ ;; ++(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pud_present(*pud) == NULL? ++ dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=pmd_offset(pud,addr) ++ ;; ++#endif ++(p7) ld8 r17=[r17] // get *pmd (may be 0) ++ shr.u r19=r22,PAGE_SHIFT // shift pte index into position ++ ;; ++(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was pmd_present(*pmd) == NULL? ++ dep r17=r19,r17,3,(PAGE_SHIFT-3) // r17=pte_offset(pmd,addr); ++(p6) br.cond.spnt page_fault ++ mov b0=r30 ++ br.sptk.many b0 // return to continuation point ++END(nested_dtlb_miss) ++ ++ .org ia64_ivt+0x1800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) ++ENTRY(ikey_miss) ++ DBG_FAULT(6) ++ FAULT(6) ++END(ikey_miss) ++ ++ //----------------------------------------------------------------------------------- ++ // call do_page_fault (predicates are in r31, psr.dt may be off, r16 is faulting address) ++ENTRY(page_fault) ++#ifdef CONFIG_XEN ++ XEN_HYPER_SSM_PSR_DT ++#else ++ ssm psr.dt ++ ;; ++ srlz.i ++#endif ++ ;; ++ SAVE_MIN_WITH_COVER ++ alloc r15=ar.pfs,0,0,3,0 ++#ifdef CONFIG_XEN ++ movl r3=XSI_ISR ++ ;; ++ ld8 out1=[r3],XSI_IFA_OFS-XSI_ISR_OFS // get vcr.isr, point to ifa ++ ;; ++ ld8 out0=[r3] // get vcr.ifa ++ mov r14=1 ++ ;; ++ add r3=XSI_PSR_IC_OFS-XSI_IFA_OFS, r3 // point to vpsr.ic ++ ;; ++ st4 [r3]=r14 // vpsr.ic = 1 ++ adds r3=8,r2 // set up second base pointer ++ ;; ++#else ++ mov out0=cr.ifa ++ mov out1=cr.isr ++ adds r3=8,r2 // set up second base pointer ++ ;; ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collectin is on ++ ;; ++#endif ++#ifdef CONFIG_XEN ++ ++#define MASK_TO_PEND_OFS (-1) ++ ++(p15) movl r14=XSI_PSR_I_ADDR ++ ;; ++(p15) ld8 r14=[r14] ++ ;; ++(p15) st1 [r14]=r0,MASK_TO_PEND_OFS // if (p15) vpsr.i = 1 ++ ;; // if (p15) (vcpu->vcpu_info->evtchn_upcall_mask)=0 ++(p15) ld1 r14=[r14] // if (vcpu->vcpu_info->evtchn_upcall_pending) ++ ;; ++(p15) cmp.ne p15,p0=r14,r0 ++ ;; ++(p15) XEN_HYPER_SSM_I ++#else ++(p15) ssm psr.i // restore psr.i ++#endif ++ movl r14=ia64_leave_kernel ++ ;; ++ SAVE_REST ++ mov rp=r14 ++ ;; ++ adds out2=16,r12 // out2 = pointer to pt_regs ++ br.call.sptk.many b6=ia64_do_page_fault // ignore return address ++END(page_fault) ++ ++ .org ia64_ivt+0x1c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) ++ENTRY(dkey_miss) ++ DBG_FAULT(7) ++ FAULT(7) ++END(dkey_miss) ++ ++ .org ia64_ivt+0x2000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) ++ENTRY(dirty_bit) ++ DBG_FAULT(8) ++ /* ++ * What we do here is to simply turn on the dirty bit in the PTE. We need to ++ * update both the page-table and the TLB entry. To efficiently access the PTE, ++ * we address it through the virtual page table. Most likely, the TLB entry for ++ * the relevant virtual page table page is still present in the TLB so we can ++ * normally do this without additional TLB misses. In case the necessary virtual ++ * page table TLB entry isn't present, we take a nested TLB miss hit where we look ++ * up the physical address of the L3 PTE and then continue at label 1 below. ++ */ ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++ ;; ++#else ++ mov r16=cr.ifa // get the address that caused the fault ++#endif ++ movl r30=1f // load continuation point in case of nested fault ++ ;; ++#ifdef CONFIG_XEN ++ mov r18=r8; ++ mov r8=r16; ++ XEN_HYPER_THASH;; ++ mov r17=r8; ++ mov r8=r18;; ++#else ++ thash r17=r16 // compute virtual address of L3 PTE ++#endif ++ mov r29=b0 // save b0 in case of nested fault ++ mov r31=pr // save pr ++#ifdef CONFIG_SMP ++ mov r28=ar.ccv // save ar.ccv ++ ;; ++1: ld8 r18=[r17] ++ ;; // avoid RAW on r18 ++ mov ar.ccv=r18 // set compare value for cmpxchg ++ or r25=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits ++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit ++ ;; ++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only update if page is present ++ mov r24=PAGE_SHIFT<<2 ++ ;; ++(p6) cmp.eq p6,p7=r26,r18 // Only compare if page is present ++ ;; ++#ifdef CONFIG_XEN ++(p6) mov r18=r8 ++(p6) mov r8=r25 ++ ;; ++(p6) XEN_HYPER_ITC_D ++ ;; ++(p6) mov r8=r18 ++#else ++(p6) itc.d r25 // install updated PTE ++#endif ++ ;; ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ++ ld8 r18=[r17] // read PTE again ++ ;; ++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed ++ ;; ++(p7) ptc.l r16,r24 ++ mov b0=r29 // restore b0 ++ mov ar.ccv=r28 ++#else ++ ;; ++1: ld8 r18=[r17] ++ ;; // avoid RAW on r18 ++ or r18=_PAGE_D|_PAGE_A,r18 // set the dirty and accessed bits ++ mov b0=r29 // restore b0 ++ ;; ++ st8 [r17]=r18 // store back updated PTE ++ itc.d r18 // install updated PTE ++#endif ++ mov pr=r31,-1 // restore pr ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(dirty_bit) ++ ++ .org ia64_ivt+0x2400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) ++ENTRY(iaccess_bit) ++ DBG_FAULT(9) ++ // Like Entry 8, except for instruction access ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++ ;; ++#else ++ mov r16=cr.ifa // get the address that caused the fault ++#endif ++ movl r30=1f // load continuation point in case of nested fault ++ mov r31=pr // save predicates ++#ifdef CONFIG_ITANIUM ++ /* ++ * Erratum 10 (IFA may contain incorrect address) has "NoFix" status. ++ */ ++ mov r17=cr.ipsr ++ ;; ++ mov r18=cr.iip ++ tbit.z p6,p0=r17,IA64_PSR_IS_BIT // IA64 instruction set? ++ ;; ++(p6) mov r16=r18 // if so, use cr.iip instead of cr.ifa ++#endif /* CONFIG_ITANIUM */ ++ ;; ++#ifdef CONFIG_XEN ++ mov r18=r8; ++ mov r8=r16; ++ XEN_HYPER_THASH;; ++ mov r17=r8; ++ mov r8=r18;; ++#else ++ thash r17=r16 // compute virtual address of L3 PTE ++#endif ++ mov r29=b0 // save b0 in case of nested fault) ++#ifdef CONFIG_SMP ++ mov r28=ar.ccv // save ar.ccv ++ ;; ++1: ld8 r18=[r17] ++ ;; ++ mov ar.ccv=r18 // set compare value for cmpxchg ++ or r25=_PAGE_A,r18 // set the accessed bit ++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit ++ ;; ++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only if page present ++ mov r24=PAGE_SHIFT<<2 ++ ;; ++(p6) cmp.eq p6,p7=r26,r18 // Only if page present ++ ;; ++#ifdef CONFIG_XEN ++ mov r26=r8 ++ mov r8=r25 ++ ;; ++(p6) XEN_HYPER_ITC_I ++ ;; ++ mov r8=r26 ++ ;; ++#else ++(p6) itc.i r25 // install updated PTE ++#endif ++ ;; ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ++ ld8 r18=[r17] // read PTE again ++ ;; ++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed ++ ;; ++(p7) ptc.l r16,r24 ++ mov b0=r29 // restore b0 ++ mov ar.ccv=r28 ++#else /* !CONFIG_SMP */ ++ ;; ++1: ld8 r18=[r17] ++ ;; ++ or r18=_PAGE_A,r18 // set the accessed bit ++ mov b0=r29 // restore b0 ++ ;; ++ st8 [r17]=r18 // store back updated PTE ++ itc.i r18 // install updated PTE ++#endif /* !CONFIG_SMP */ ++ mov pr=r31,-1 ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(iaccess_bit) ++ ++ .org ia64_ivt+0x2800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) ++ENTRY(daccess_bit) ++ DBG_FAULT(10) ++ // Like Entry 8, except for data access ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++ ;; ++#else ++ mov r16=cr.ifa // get the address that caused the fault ++#endif ++ movl r30=1f // load continuation point in case of nested fault ++ ;; ++#ifdef CONFIG_XEN ++ mov r18=r8 ++ mov r8=r16 ++ XEN_HYPER_THASH ++ ;; ++ mov r17=r8 ++ mov r8=r18 ++ ;; ++#else ++ thash r17=r16 // compute virtual address of L3 PTE ++#endif ++ mov r31=pr ++ mov r29=b0 // save b0 in case of nested fault) ++#ifdef CONFIG_SMP ++ mov r28=ar.ccv // save ar.ccv ++ ;; ++1: ld8 r18=[r17] ++ ;; // avoid RAW on r18 ++ mov ar.ccv=r18 // set compare value for cmpxchg ++ or r25=_PAGE_A,r18 // set the dirty bit ++ tbit.z p7,p6 = r18,_PAGE_P_BIT // Check present bit ++ ;; ++(p6) cmpxchg8.acq r26=[r17],r25,ar.ccv // Only if page is present ++ mov r24=PAGE_SHIFT<<2 ++ ;; ++(p6) cmp.eq p6,p7=r26,r18 // Only if page is present ++ ;; ++#ifdef CONFIG_XEN ++ mov r26=r8 ++ mov r8=r25 ++ ;; ++(p6) XEN_HYPER_ITC_D ++ ;; ++ mov r8=r26 ++ ;; ++#else ++(p6) itc.d r25 // install updated PTE ++#endif ++ /* ++ * Tell the assemblers dependency-violation checker that the above "itc" instructions ++ * cannot possibly affect the following loads: ++ */ ++ dv_serialize_data ++ ;; ++ ld8 r18=[r17] // read PTE again ++ ;; ++ cmp.eq p6,p7=r18,r25 // is it same as the newly installed ++ ;; ++(p7) ptc.l r16,r24 ++ mov ar.ccv=r28 ++#else ++ ;; ++1: ld8 r18=[r17] ++ ;; // avoid RAW on r18 ++ or r18=_PAGE_A,r18 // set the accessed bit ++ ;; ++ st8 [r17]=r18 // store back updated PTE ++ itc.d r18 // install updated PTE ++#endif ++ mov b0=r29 // restore b0 ++ mov pr=r31,-1 ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI ++ dv_serialize_data ++#else ++ rfi ++#endif ++END(daccess_bit) ++ ++ .org ia64_ivt+0x2c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) ++ENTRY(break_fault) ++ /* ++ * The streamlined system call entry/exit paths only save/restore the initial part ++ * of pt_regs. This implies that the callers of system-calls must adhere to the ++ * normal procedure calling conventions. ++ * ++ * Registers to be saved & restored: ++ * CR registers: cr.ipsr, cr.iip, cr.ifs ++ * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr ++ * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15 ++ * Registers to be restored only: ++ * r8-r11: output value from the system call. ++ * ++ * During system call exit, scratch registers (including r15) are modified/cleared ++ * to prevent leaking bits from kernel to user level. ++ */ ++ DBG_FAULT(11) ++ mov.m r16=IA64_KR(CURRENT) // M2 r16 <- current task (12 cyc) ++#ifdef CONFIG_XEN ++ movl r22=XSI_IPSR ++ ;; ++ ld8 r29=[r22],XSI_IIM_OFS-XSI_IPSR_OFS // get ipsr, point to iip ++#else ++ mov r29=cr.ipsr // M2 (12 cyc) ++#endif ++ mov r31=pr // I0 (2 cyc) ++ ++#ifdef CONFIG_XEN ++ ;; ++ ld8 r17=[r22],XSI_IIP_OFS-XSI_IIM_OFS ++#else ++ mov r17=cr.iim // M2 (2 cyc) ++#endif ++ mov.m r27=ar.rsc // M2 (12 cyc) ++ mov r18=__IA64_BREAK_SYSCALL // A ++ ++ mov.m ar.rsc=0 // M2 ++ mov.m r21=ar.fpsr // M2 (12 cyc) ++ mov r19=b6 // I0 (2 cyc) ++ ;; ++ mov.m r23=ar.bspstore // M2 (12 cyc) ++ mov.m r24=ar.rnat // M2 (5 cyc) ++ mov.i r26=ar.pfs // I0 (2 cyc) ++ ++ invala // M0|1 ++ nop.m 0 // M ++ mov r20=r1 // A save r1 ++ ++ nop.m 0 ++ movl r30=sys_call_table // X ++ ++#ifdef CONFIG_XEN ++ ld8 r28=[r22] ++#else ++ mov r28=cr.iip // M2 (2 cyc) ++#endif ++ cmp.eq p0,p7=r18,r17 // I0 is this a system call? ++(p7) br.cond.spnt non_syscall // B no -> ++ // ++ // From this point on, we are definitely on the syscall-path ++ // and we can use (non-banked) scratch registers. ++ // ++/////////////////////////////////////////////////////////////////////// ++ mov r1=r16 // A move task-pointer to "addl"-addressable reg ++ mov r2=r16 // A setup r2 for ia64_syscall_setup ++ add r9=TI_FLAGS+IA64_TASK_SIZE,r16 // A r9 = ¤t_thread_info()->flags ++ ++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 ++ adds r15=-1024,r15 // A subtract 1024 from syscall number ++ mov r3=NR_syscalls - 1 ++ ;; ++ ld1.bias r17=[r16] // M0|1 r17 = current->thread.on_ustack flag ++ ld4 r9=[r9] // M0|1 r9 = current_thread_info()->flags ++ extr.u r8=r29,41,2 // I0 extract ei field from cr.ipsr ++ ++ shladd r30=r15,3,r30 // A r30 = sys_call_table + 8*(syscall-1024) ++ addl r22=IA64_RBS_OFFSET,r1 // A compute base of RBS ++ cmp.leu p6,p7=r15,r3 // A syscall number in range? ++ ;; ++ ++ lfetch.fault.excl.nt1 [r22] // M0|1 prefetch RBS ++(p6) ld8 r30=[r30] // M0|1 load address of syscall entry point ++ tnat.nz.or p7,p0=r15 // I0 is syscall nr a NaT? ++ ++ mov.m ar.bspstore=r22 // M2 switch to kernel RBS ++ cmp.eq p8,p9=2,r8 // A isr.ei==2? ++ ;; ++ ++(p8) mov r8=0 // A clear ei to 0 ++(p7) movl r30=sys_ni_syscall // X ++ ++(p8) adds r28=16,r28 // A switch cr.iip to next bundle ++(p9) adds r8=1,r8 // A increment ei to next slot ++ nop.i 0 ++ ;; ++ ++ mov.m r25=ar.unat // M2 (5 cyc) ++ dep r29=r8,r29,41,2 // I0 insert new ei into cr.ipsr ++ adds r15=1024,r15 // A restore original syscall number ++ // ++ // If any of the above loads miss in L1D, we'll stall here until ++ // the data arrives. ++ // ++/////////////////////////////////////////////////////////////////////// ++ st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag ++ mov b6=r30 // I0 setup syscall handler branch reg early ++ cmp.eq pKStk,pUStk=r0,r17 // A were we on kernel stacks already? ++ ++ and r9=_TIF_SYSCALL_TRACEAUDIT,r9 // A mask trace or audit ++ mov r18=ar.bsp // M2 (12 cyc) ++(pKStk) br.cond.spnt .break_fixup // B we're already in kernel-mode -- fix up RBS ++ ;; ++.back_from_break_fixup: ++(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1 // A compute base of memory stack ++ cmp.eq p14,p0=r9,r0 // A are syscalls being traced/audited? ++ br.call.sptk.many b7=ia64_syscall_setup // B ++1: ++ mov ar.rsc=0x3 // M2 set eager mode, pl 0, LE, loadrs=0 ++ nop 0 ++#ifdef CONFIG_XEN ++ mov r2=b0; br.call.sptk b0=xen_bsw1;; mov b0=r2;; ++#else ++ bsw.1 // B (6 cyc) regs are saved, switch to bank 1 ++#endif ++ ;; ++ ++#ifdef CONFIG_XEN ++ movl r16=XSI_PSR_IC ++ mov r3=1 ++ ;; ++ st4 [r16]=r3,XSI_PSR_I_ADDR_OFS-XSI_PSR_IC_OFS // vpsr.ic = 1 ++#else ++ ssm psr.ic | PSR_DEFAULT_BITS // M2 now it's safe to re-enable intr.-collection ++#endif ++ movl r3=ia64_ret_from_syscall // X ++ ;; ++ ++ srlz.i // M0 ensure interruption collection is on ++ mov rp=r3 // I0 set the real return addr ++(p10) br.cond.spnt.many ia64_ret_from_syscall // B return if bad call-frame or r15 is a NaT ++ ++#ifdef CONFIG_XEN ++(p15) ld8 r16=[r16] // vpsr.i ++ ;; ++(p15) st1 [r16]=r0,MASK_TO_PEND_OFS // if (p15) vpsr.i = 1 ++ ;; // if (p15) (vcpu->vcpu_info->evtchn_upcall_mask)=0 ++(p15) ld1 r2=[r16] // if (vcpu->vcpu_info->evtchn_upcall_pending) ++ ;; ++(p15) cmp.ne.unc p6,p0=r2,r0 ++ ;; ++(p6) XEN_HYPER_SSM_I // do a real ssm psr.i ++#else ++(p15) ssm psr.i // M2 restore psr.i ++#endif ++(p14) br.call.sptk.many b6=b6 // B invoke syscall-handker (ignore return addr) ++ br.cond.spnt.many ia64_trace_syscall // B do syscall-tracing thingamagic ++ // NOT REACHED ++/////////////////////////////////////////////////////////////////////// ++ // On entry, we optimistically assumed that we're coming from user-space. ++ // For the rare cases where a system-call is done from within the kernel, ++ // we fix things up at this point: ++.break_fixup: ++ add r1=-IA64_PT_REGS_SIZE,sp // A allocate space for pt_regs structure ++ mov ar.rnat=r24 // M2 restore kernel's AR.RNAT ++ ;; ++ mov ar.bspstore=r23 // M2 restore kernel's AR.BSPSTORE ++ br.cond.sptk .back_from_break_fixup ++END(break_fault) ++ ++ .org ia64_ivt+0x3000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) ++ENTRY(interrupt) ++ DBG_FAULT(12) ++ mov r31=pr // prepare to save predicates ++ ;; ++ SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 ++#ifdef CONFIG_XEN ++ movl r3=XSI_PSR_IC ++ mov r14=1 ++ ;; ++ st4 [r3]=r14 ++#else ++ ssm psr.ic | PSR_DEFAULT_BITS ++#endif ++ ;; ++ adds r3=8,r2 // set up second base pointer for SAVE_REST ++ srlz.i // ensure everybody knows psr.ic is back on ++ ;; ++ SAVE_REST ++ ;; ++ alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group ++#ifdef CONFIG_XEN ++ ;; ++ br.call.sptk.many rp=xen_get_ivr ++ ;; ++ mov out0=r8 // pass cr.ivr as first arg ++#else ++ mov out0=cr.ivr // pass cr.ivr as first arg ++#endif ++ add out1=16,sp // pass pointer to pt_regs as second arg ++ ;; ++ srlz.d // make sure we see the effect of cr.ivr ++ movl r14=ia64_leave_kernel ++ ;; ++ mov rp=r14 ++ br.call.sptk.many b6=ia64_handle_irq ++END(interrupt) ++ ++ .org ia64_ivt+0x3400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x3400 Entry 13 (size 64 bundles) Reserved ++ DBG_FAULT(13) ++ FAULT(13) ++ ++ .org ia64_ivt+0x3800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x3800 Entry 14 (size 64 bundles) Reserved ++ DBG_FAULT(14) ++ FAULT(14) ++ ++ /* ++ * There is no particular reason for this code to be here, other than that ++ * there happens to be space here that would go unused otherwise. If this ++ * fault ever gets "unreserved", simply moved the following code to a more ++ * suitable spot... ++ * ++ * ia64_syscall_setup() is a separate subroutine so that it can ++ * allocate stacked registers so it can safely demine any ++ * potential NaT values from the input registers. ++ * ++ * On entry: ++ * - executing on bank 0 or bank 1 register set (doesn't matter) ++ * - r1: stack pointer ++ * - r2: current task pointer ++ * - r3: preserved ++ * - r11: original contents (saved ar.pfs to be saved) ++ * - r12: original contents (sp to be saved) ++ * - r13: original contents (tp to be saved) ++ * - r15: original contents (syscall # to be saved) ++ * - r18: saved bsp (after switching to kernel stack) ++ * - r19: saved b6 ++ * - r20: saved r1 (gp) ++ * - r21: saved ar.fpsr ++ * - r22: kernel's register backing store base (krbs_base) ++ * - r23: saved ar.bspstore ++ * - r24: saved ar.rnat ++ * - r25: saved ar.unat ++ * - r26: saved ar.pfs ++ * - r27: saved ar.rsc ++ * - r28: saved cr.iip ++ * - r29: saved cr.ipsr ++ * - r31: saved pr ++ * - b0: original contents (to be saved) ++ * On exit: ++ * - p10: TRUE if syscall is invoked with more than 8 out ++ * registers or r15's Nat is true ++ * - r1: kernel's gp ++ * - r3: preserved (same as on entry) ++ * - r8: -EINVAL if p10 is true ++ * - r12: points to kernel stack ++ * - r13: points to current task ++ * - r14: preserved (same as on entry) ++ * - p13: preserved ++ * - p15: TRUE if interrupts need to be re-enabled ++ * - ar.fpsr: set to kernel settings ++ * - b6: preserved (same as on entry) ++ */ ++#ifndef CONFIG_XEN ++GLOBAL_ENTRY(ia64_syscall_setup) ++#if PT(B6) != 0 ++# error This code assumes that b6 is the first field in pt_regs. ++#endif ++ st8 [r1]=r19 // save b6 ++ add r16=PT(CR_IPSR),r1 // initialize first base pointer ++ add r17=PT(R11),r1 // initialize second base pointer ++ ;; ++ alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable ++ st8 [r16]=r29,PT(AR_PFS)-PT(CR_IPSR) // save cr.ipsr ++ tnat.nz p8,p0=in0 ++ ++ st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11 ++ tnat.nz p9,p0=in1 ++(pKStk) mov r18=r0 // make sure r18 isn't NaT ++ ;; ++ ++ st8 [r16]=r26,PT(CR_IFS)-PT(AR_PFS) // save ar.pfs ++ st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip ++ mov r28=b0 // save b0 (2 cyc) ++ ;; ++ ++ st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat ++ dep r19=0,r19,38,26 // clear all bits but 0..37 [I0] ++(p8) mov in0=-1 ++ ;; ++ ++ st8 [r16]=r19,PT(AR_RNAT)-PT(CR_IFS) // store ar.pfs.pfm in cr.ifs ++ extr.u r11=r19,7,7 // I0 // get sol of ar.pfs ++ and r8=0x7f,r19 // A // get sof of ar.pfs ++ ++ st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc ++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT // I0 ++(p9) mov in1=-1 ++ ;; ++ ++(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 ++ tnat.nz p10,p0=in2 ++ add r11=8,r11 ++ ;; ++(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field ++(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field ++ tnat.nz p11,p0=in3 ++ ;; ++(p10) mov in2=-1 ++ tnat.nz p12,p0=in4 // [I0] ++(p11) mov in3=-1 ++ ;; ++(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat ++(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore ++ shl r18=r18,16 // compute ar.rsc to be used for "loadrs" ++ ;; ++ st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates ++ st8 [r17]=r28,PT(R1)-PT(B0) // save b0 ++ tnat.nz p13,p0=in5 // [I0] ++ ;; ++ st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs" ++ st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1 ++(p12) mov in4=-1 ++ ;; ++ ++.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12 ++.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13 ++(p13) mov in5=-1 ++ ;; ++ st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr ++ tnat.nz p13,p0=in6 ++ cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8 ++ ;; ++ mov r8=1 ++(p9) tnat.nz p10,p0=r15 ++ adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) ++ ++ st8.spill [r17]=r15 // save r15 ++ tnat.nz p8,p0=in7 ++ nop.i 0 ++ ++ mov r13=r2 // establish `current' ++ movl r1=__gp // establish kernel global pointer ++ ;; ++ st8 [r16]=r8 // ensure pt_regs.r8 != 0 (see handle_syscall_error) ++(p13) mov in6=-1 ++(p8) mov in7=-1 ++ ++ cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 ++ movl r17=FPSR_DEFAULT ++ ;; ++ mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value ++(p10) mov r8=-EINVAL ++ br.ret.sptk.many b7 ++END(ia64_syscall_setup) ++#endif ++ ++ .org ia64_ivt+0x3c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x3c00 Entry 15 (size 64 bundles) Reserved ++ DBG_FAULT(15) ++ FAULT(15) ++ ++ /* ++ * Squatting in this space ... ++ * ++ * This special case dispatcher for illegal operation faults allows preserved ++ * registers to be modified through a callback function (asm only) that is handed ++ * back from the fault handler in r8. Up to three arguments can be passed to the ++ * callback function by returning an aggregate with the callback as its first ++ * element, followed by the arguments. ++ */ ++ENTRY(dispatch_illegal_op_fault) ++ .prologue ++ .body ++ SAVE_MIN_WITH_COVER ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collection is on ++ ;; ++(p15) ssm psr.i // restore psr.i ++ adds r3=8,r2 // set up second base pointer for SAVE_REST ++ ;; ++ alloc r14=ar.pfs,0,0,1,0 // must be first in insn group ++ mov out0=ar.ec ++ ;; ++ SAVE_REST ++ PT_REGS_UNWIND_INFO(0) ++ ;; ++ br.call.sptk.many rp=ia64_illegal_op_fault ++.ret0: ;; ++ alloc r14=ar.pfs,0,0,3,0 // must be first in insn group ++ mov out0=r9 ++ mov out1=r10 ++ mov out2=r11 ++ movl r15=ia64_leave_kernel ++ ;; ++ mov rp=r15 ++ mov b6=r8 ++ ;; ++ cmp.ne p6,p0=0,r8 ++(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel ++ br.sptk.many ia64_leave_kernel ++END(dispatch_illegal_op_fault) ++ ++ .org ia64_ivt+0x4000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x4000 Entry 16 (size 64 bundles) Reserved ++ DBG_FAULT(16) ++ FAULT(16) ++ ++ .org ia64_ivt+0x4400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x4400 Entry 17 (size 64 bundles) Reserved ++ DBG_FAULT(17) ++ FAULT(17) ++ ++ENTRY(non_syscall) ++ mov ar.rsc=r27 // restore ar.rsc before SAVE_MIN_WITH_COVER ++ ;; ++ SAVE_MIN_WITH_COVER ++ ++ // There is no particular reason for this code to be here, other than that ++ // there happens to be space here that would go unused otherwise. If this ++ // fault ever gets "unreserved", simply moved the following code to a more ++ // suitable spot... ++ ++ alloc r14=ar.pfs,0,0,2,0 ++ mov out0=cr.iim ++ add out1=16,sp ++ adds r3=8,r2 // set up second base pointer for SAVE_REST ++ ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collection is on ++ ;; ++(p15) ssm psr.i // restore psr.i ++ movl r15=ia64_leave_kernel ++ ;; ++ SAVE_REST ++ mov rp=r15 ++ ;; ++ br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr ++END(non_syscall) ++ ++ .org ia64_ivt+0x4800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x4800 Entry 18 (size 64 bundles) Reserved ++ DBG_FAULT(18) ++ FAULT(18) ++ ++ /* ++ * There is no particular reason for this code to be here, other than that ++ * there happens to be space here that would go unused otherwise. If this ++ * fault ever gets "unreserved", simply moved the following code to a more ++ * suitable spot... ++ */ ++ ++ENTRY(dispatch_unaligned_handler) ++ SAVE_MIN_WITH_COVER ++ ;; ++ alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) ++ mov out0=cr.ifa ++ adds out1=16,sp ++ ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collection is on ++ ;; ++(p15) ssm psr.i // restore psr.i ++ adds r3=8,r2 // set up second base pointer ++ ;; ++ SAVE_REST ++ movl r14=ia64_leave_kernel ++ ;; ++ mov rp=r14 ++ br.sptk.many ia64_prepare_handle_unaligned ++END(dispatch_unaligned_handler) ++ ++ .org ia64_ivt+0x4c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x4c00 Entry 19 (size 64 bundles) Reserved ++ DBG_FAULT(19) ++ FAULT(19) ++ ++ /* ++ * There is no particular reason for this code to be here, other than that ++ * there happens to be space here that would go unused otherwise. If this ++ * fault ever gets "unreserved", simply moved the following code to a more ++ * suitable spot... ++ */ ++ ++ENTRY(dispatch_to_fault_handler) ++ /* ++ * Input: ++ * psr.ic: off ++ * r19: fault vector number (e.g., 24 for General Exception) ++ * r31: contains saved predicates (pr) ++ */ ++ SAVE_MIN_WITH_COVER_R19 ++ alloc r14=ar.pfs,0,0,5,0 ++ mov out0=r15 ++#ifdef CONFIG_XEN ++ movl out1=XSI_ISR ++ ;; ++ adds out2=XSI_IFA-XSI_ISR,out1 ++ adds out3=XSI_IIM-XSI_ISR,out1 ++ adds out4=XSI_ITIR-XSI_ISR,out1 ++ ;; ++ ld8 out1=[out1] ++ ld8 out2=[out2] ++ ld8 out3=[out4] ++ ld8 out4=[out4] ++ ;; ++#else ++ mov out1=cr.isr ++ mov out2=cr.ifa ++ mov out3=cr.iim ++ mov out4=cr.itir ++ ;; ++#endif ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collection is on ++ ;; ++(p15) ssm psr.i // restore psr.i ++ adds r3=8,r2 // set up second base pointer for SAVE_REST ++ ;; ++ SAVE_REST ++ movl r14=ia64_leave_kernel ++ ;; ++ mov rp=r14 ++ br.call.sptk.many b6=ia64_fault ++END(dispatch_to_fault_handler) ++ ++// ++// --- End of long entries, Beginning of short entries ++// ++ ++ .org ia64_ivt+0x5000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) ++ENTRY(page_not_present) ++ DBG_FAULT(20) ++ mov r16=cr.ifa ++ rsm psr.dt ++ /* ++ * The Linux page fault handler doesn't expect non-present pages to be in ++ * the TLB. Flush the existing entry now, so we meet that expectation. ++ */ ++ mov r17=PAGE_SHIFT<<2 ++ ;; ++ ptc.l r16,r17 ++ ;; ++ mov r31=pr ++ srlz.d ++ br.sptk.many page_fault ++END(page_not_present) ++ ++ .org ia64_ivt+0x5100 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) ++ENTRY(key_permission) ++ DBG_FAULT(21) ++ mov r16=cr.ifa ++ rsm psr.dt ++ mov r31=pr ++ ;; ++ srlz.d ++ br.sptk.many page_fault ++END(key_permission) ++ ++ .org ia64_ivt+0x5200 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) ++ENTRY(iaccess_rights) ++ DBG_FAULT(22) ++ mov r16=cr.ifa ++ rsm psr.dt ++ mov r31=pr ++ ;; ++ srlz.d ++ br.sptk.many page_fault ++END(iaccess_rights) ++ ++ .org ia64_ivt+0x5300 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) ++ENTRY(daccess_rights) ++ DBG_FAULT(23) ++#ifdef CONFIG_XEN ++ movl r16=XSI_IFA ++ ;; ++ ld8 r16=[r16] ++ ;; ++ XEN_HYPER_RSM_PSR_DT ++#else ++ mov r16=cr.ifa ++ rsm psr.dt ++#endif ++ mov r31=pr ++ ;; ++ srlz.d ++ br.sptk.many page_fault ++END(daccess_rights) ++ ++ .org ia64_ivt+0x5400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) ++ENTRY(general_exception) ++ DBG_FAULT(24) ++ mov r16=cr.isr ++ mov r31=pr ++ ;; ++ cmp4.eq p6,p0=0,r16 ++(p6) br.sptk.many dispatch_illegal_op_fault ++ ;; ++ mov r19=24 // fault number ++ br.sptk.many dispatch_to_fault_handler ++END(general_exception) ++ ++ .org ia64_ivt+0x5500 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) ++ENTRY(disabled_fp_reg) ++ DBG_FAULT(25) ++ rsm psr.dfh // ensure we can access fph ++ ;; ++ srlz.d ++ mov r31=pr ++ mov r19=25 ++ br.sptk.many dispatch_to_fault_handler ++END(disabled_fp_reg) ++ ++ .org ia64_ivt+0x5600 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) ++ENTRY(nat_consumption) ++ DBG_FAULT(26) ++ ++ mov r16=cr.ipsr ++ mov r17=cr.isr ++ mov r31=pr // save PR ++ ;; ++ and r18=0xf,r17 // r18 = cr.ipsr.code{3:0} ++ tbit.z p6,p0=r17,IA64_ISR_NA_BIT ++ ;; ++ cmp.ne.or p6,p0=IA64_ISR_CODE_LFETCH,r18 ++ dep r16=-1,r16,IA64_PSR_ED_BIT,1 ++(p6) br.cond.spnt 1f // branch if (cr.ispr.na == 0 || cr.ipsr.code{3:0} != LFETCH) ++ ;; ++ mov cr.ipsr=r16 // set cr.ipsr.na ++ mov pr=r31,-1 ++ ;; ++ rfi ++ ++1: mov pr=r31,-1 ++ ;; ++ FAULT(26) ++END(nat_consumption) ++ ++ .org ia64_ivt+0x5700 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5700 Entry 27 (size 16 bundles) Speculation (40) ++ENTRY(speculation_vector) ++ DBG_FAULT(27) ++ /* ++ * A [f]chk.[as] instruction needs to take the branch to the recovery code but ++ * this part of the architecture is not implemented in hardware on some CPUs, such ++ * as Itanium. Thus, in general we need to emulate the behavior. IIM contains ++ * the relative target (not yet sign extended). So after sign extending it we ++ * simply add it to IIP. We also need to reset the EI field of the IPSR to zero, ++ * i.e., the slot to restart into. ++ * ++ * cr.imm contains zero_ext(imm21) ++ */ ++ mov r18=cr.iim ++ ;; ++ mov r17=cr.iip ++ shl r18=r18,43 // put sign bit in position (43=64-21) ++ ;; ++ ++ mov r16=cr.ipsr ++ shr r18=r18,39 // sign extend (39=43-4) ++ ;; ++ ++ add r17=r17,r18 // now add the offset ++ ;; ++ mov cr.iip=r17 ++ dep r16=0,r16,41,2 // clear EI ++ ;; ++ ++ mov cr.ipsr=r16 ++ ;; ++ ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI; ++#else ++ rfi // and go back ++#endif ++END(speculation_vector) ++ ++ .org ia64_ivt+0x5800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5800 Entry 28 (size 16 bundles) Reserved ++ DBG_FAULT(28) ++ FAULT(28) ++ ++ .org ia64_ivt+0x5900 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) ++ENTRY(debug_vector) ++ DBG_FAULT(29) ++ FAULT(29) ++END(debug_vector) ++ ++ .org ia64_ivt+0x5a00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) ++ENTRY(unaligned_access) ++ DBG_FAULT(30) ++ mov r31=pr // prepare to save predicates ++ ;; ++ br.sptk.many dispatch_unaligned_handler ++END(unaligned_access) ++ ++ .org ia64_ivt+0x5b00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) ++ENTRY(unsupported_data_reference) ++ DBG_FAULT(31) ++ FAULT(31) ++END(unsupported_data_reference) ++ ++ .org ia64_ivt+0x5c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) ++ENTRY(floating_point_fault) ++ DBG_FAULT(32) ++ FAULT(32) ++END(floating_point_fault) ++ ++ .org ia64_ivt+0x5d00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) ++ENTRY(floating_point_trap) ++ DBG_FAULT(33) ++ FAULT(33) ++END(floating_point_trap) ++ ++ .org ia64_ivt+0x5e00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Transfer Trap (66) ++ENTRY(lower_privilege_trap) ++ DBG_FAULT(34) ++ FAULT(34) ++END(lower_privilege_trap) ++ ++ .org ia64_ivt+0x5f00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) ++ENTRY(taken_branch_trap) ++ DBG_FAULT(35) ++ FAULT(35) ++END(taken_branch_trap) ++ ++ .org ia64_ivt+0x6000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) ++ENTRY(single_step_trap) ++ DBG_FAULT(36) ++ FAULT(36) ++END(single_step_trap) ++ ++ .org ia64_ivt+0x6100 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6100 Entry 37 (size 16 bundles) Reserved ++ DBG_FAULT(37) ++ FAULT(37) ++ ++ .org ia64_ivt+0x6200 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6200 Entry 38 (size 16 bundles) Reserved ++ DBG_FAULT(38) ++ FAULT(38) ++ ++ .org ia64_ivt+0x6300 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6300 Entry 39 (size 16 bundles) Reserved ++ DBG_FAULT(39) ++ FAULT(39) ++ ++ .org ia64_ivt+0x6400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6400 Entry 40 (size 16 bundles) Reserved ++ DBG_FAULT(40) ++ FAULT(40) ++ ++ .org ia64_ivt+0x6500 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6500 Entry 41 (size 16 bundles) Reserved ++ DBG_FAULT(41) ++ FAULT(41) ++ ++ .org ia64_ivt+0x6600 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6600 Entry 42 (size 16 bundles) Reserved ++ DBG_FAULT(42) ++ FAULT(42) ++ ++ .org ia64_ivt+0x6700 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6700 Entry 43 (size 16 bundles) Reserved ++ DBG_FAULT(43) ++ FAULT(43) ++ ++ .org ia64_ivt+0x6800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6800 Entry 44 (size 16 bundles) Reserved ++ DBG_FAULT(44) ++ FAULT(44) ++ ++ .org ia64_ivt+0x6900 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) ++ENTRY(ia32_exception) ++ DBG_FAULT(45) ++ FAULT(45) ++END(ia32_exception) ++ ++ .org ia64_ivt+0x6a00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) ++ENTRY(ia32_intercept) ++ DBG_FAULT(46) ++#ifdef CONFIG_IA32_SUPPORT ++ mov r31=pr ++ mov r16=cr.isr ++ ;; ++ extr.u r17=r16,16,8 // get ISR.code ++ mov r18=ar.eflag ++ mov r19=cr.iim // old eflag value ++ ;; ++ cmp.ne p6,p0=2,r17 ++(p6) br.cond.spnt 1f // not a system flag fault ++ xor r16=r18,r19 ++ ;; ++ extr.u r17=r16,18,1 // get the eflags.ac bit ++ ;; ++ cmp.eq p6,p0=0,r17 ++(p6) br.cond.spnt 1f // eflags.ac bit didn't change ++ ;; ++ mov pr=r31,-1 // restore predicate registers ++#ifdef CONFIG_XEN ++ XEN_HYPER_RFI; ++#else ++ rfi ++#endif ++ ++1: ++#endif // CONFIG_IA32_SUPPORT ++ FAULT(46) ++END(ia32_intercept) ++ ++ .org ia64_ivt+0x6b00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) ++ENTRY(ia32_interrupt) ++ DBG_FAULT(47) ++#ifdef CONFIG_IA32_SUPPORT ++ mov r31=pr ++ br.sptk.many dispatch_to_ia32_handler ++#else ++ FAULT(47) ++#endif ++END(ia32_interrupt) ++ ++ .org ia64_ivt+0x6c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6c00 Entry 48 (size 16 bundles) Reserved ++ DBG_FAULT(48) ++ FAULT(48) ++ ++ .org ia64_ivt+0x6d00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6d00 Entry 49 (size 16 bundles) Reserved ++ DBG_FAULT(49) ++ FAULT(49) ++ ++ .org ia64_ivt+0x6e00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6e00 Entry 50 (size 16 bundles) Reserved ++ DBG_FAULT(50) ++ FAULT(50) ++ ++ .org ia64_ivt+0x6f00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x6f00 Entry 51 (size 16 bundles) Reserved ++ DBG_FAULT(51) ++ FAULT(51) ++ ++ .org ia64_ivt+0x7000 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7000 Entry 52 (size 16 bundles) Reserved ++ DBG_FAULT(52) ++ FAULT(52) ++ ++ .org ia64_ivt+0x7100 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7100 Entry 53 (size 16 bundles) Reserved ++ DBG_FAULT(53) ++ FAULT(53) ++ ++ .org ia64_ivt+0x7200 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7200 Entry 54 (size 16 bundles) Reserved ++ DBG_FAULT(54) ++ FAULT(54) ++ ++ .org ia64_ivt+0x7300 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7300 Entry 55 (size 16 bundles) Reserved ++ DBG_FAULT(55) ++ FAULT(55) ++ ++ .org ia64_ivt+0x7400 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7400 Entry 56 (size 16 bundles) Reserved ++ DBG_FAULT(56) ++ FAULT(56) ++ ++ .org ia64_ivt+0x7500 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7500 Entry 57 (size 16 bundles) Reserved ++ DBG_FAULT(57) ++ FAULT(57) ++ ++ .org ia64_ivt+0x7600 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7600 Entry 58 (size 16 bundles) Reserved ++ DBG_FAULT(58) ++ FAULT(58) ++ ++ .org ia64_ivt+0x7700 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7700 Entry 59 (size 16 bundles) Reserved ++ DBG_FAULT(59) ++ FAULT(59) ++ ++ .org ia64_ivt+0x7800 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7800 Entry 60 (size 16 bundles) Reserved ++ DBG_FAULT(60) ++ FAULT(60) ++ ++ .org ia64_ivt+0x7900 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7900 Entry 61 (size 16 bundles) Reserved ++ DBG_FAULT(61) ++ FAULT(61) ++ ++ .org ia64_ivt+0x7a00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7a00 Entry 62 (size 16 bundles) Reserved ++ DBG_FAULT(62) ++ FAULT(62) ++ ++ .org ia64_ivt+0x7b00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7b00 Entry 63 (size 16 bundles) Reserved ++ DBG_FAULT(63) ++ FAULT(63) ++ ++ .org ia64_ivt+0x7c00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7c00 Entry 64 (size 16 bundles) Reserved ++ DBG_FAULT(64) ++ FAULT(64) ++ ++ .org ia64_ivt+0x7d00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7d00 Entry 65 (size 16 bundles) Reserved ++ DBG_FAULT(65) ++ FAULT(65) ++ ++ .org ia64_ivt+0x7e00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7e00 Entry 66 (size 16 bundles) Reserved ++ DBG_FAULT(66) ++ FAULT(66) ++ ++ .org ia64_ivt+0x7f00 ++///////////////////////////////////////////////////////////////////////////////////////// ++// 0x7f00 Entry 67 (size 16 bundles) Reserved ++ DBG_FAULT(67) ++ FAULT(67) ++ ++#ifdef CONFIG_IA32_SUPPORT ++ ++ /* ++ * There is no particular reason for this code to be here, other than that ++ * there happens to be space here that would go unused otherwise. If this ++ * fault ever gets "unreserved", simply moved the following code to a more ++ * suitable spot... ++ */ ++ ++ // IA32 interrupt entry point ++ ++ENTRY(dispatch_to_ia32_handler) ++ SAVE_MIN ++ ;; ++ mov r14=cr.isr ++ ssm psr.ic | PSR_DEFAULT_BITS ++ ;; ++ srlz.i // guarantee that interruption collection is on ++ ;; ++(p15) ssm psr.i ++ adds r3=8,r2 // Base pointer for SAVE_REST ++ ;; ++ SAVE_REST ++ ;; ++ mov r15=0x80 ++ shr r14=r14,16 // Get interrupt number ++ ;; ++ cmp.ne p6,p0=r14,r15 ++(p6) br.call.dpnt.many b6=non_ia32_syscall ++ ++ adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions ++ adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp ++ ;; ++ cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 ++ ld8 r8=[r14] // get r8 ++ ;; ++ st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) ++ ;; ++ alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ++ ;; ++ ld4 r8=[r14],8 // r8 == eax (syscall number) ++ mov r15=IA32_NR_syscalls ++ ;; ++ cmp.ltu.unc p6,p7=r8,r15 ++ ld4 out1=[r14],8 // r9 == ecx ++ ;; ++ ld4 out2=[r14],8 // r10 == edx ++ ;; ++ ld4 out0=[r14] // r11 == ebx ++ adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp ++ ;; ++ ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp ++ ;; ++ ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi ++ adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 ++ ;; ++ ld4 out4=[r14] // r15 == edi ++ movl r16=ia32_syscall_table ++ ;; ++(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number ++ ld4 r2=[r2] // r2 = current_thread_info()->flags ++ ;; ++ ld8 r16=[r16] ++ and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit ++ ;; ++ mov b6=r16 ++ movl r15=ia32_ret_from_syscall ++ cmp.eq p8,p0=r2,r0 ++ ;; ++ mov rp=r15 ++(p8) br.call.sptk.many b6=b6 ++ br.cond.sptk ia32_trace_syscall ++ ++non_ia32_syscall: ++ alloc r15=ar.pfs,0,0,2,0 ++ mov out0=r14 // interrupt # ++ add out1=16,sp // pointer to pt_regs ++ ;; // avoid WAW on CFM ++ br.call.sptk.many rp=ia32_bad_interrupt ++.ret1: movl r15=ia64_leave_kernel ++ ;; ++ mov rp=r15 ++ br.ret.sptk.many rp ++END(dispatch_to_ia32_handler) ++#endif /* CONFIG_IA32_SUPPORT */ ++ ++#ifdef CONFIG_XEN ++ .section .text,"ax" ++GLOBAL_ENTRY(xen_event_callback) ++ mov r31=pr // prepare to save predicates ++ ;; ++ SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 ++ ;; ++ movl r3=XSI_PSR_IC ++ mov r14=1 ++ ;; ++ st4 [r3]=r14 ++ ;; ++ adds r3=8,r2 // set up second base pointer for SAVE_REST ++ srlz.i // ensure everybody knows psr.ic is back on ++ ;; ++ SAVE_REST ++ ;; ++1: ++ alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group ++ add out0=16,sp // pass pointer to pt_regs as first arg ++ ;; ++ br.call.sptk.many b0=evtchn_do_upcall ++ ;; ++ movl r20=XSI_PSR_I_ADDR ++ ;; ++ ld8 r20=[r20] ++ ;; ++ adds r20=-1,r20 // vcpu_info->evtchn_upcall_pending ++ ;; ++ ld1 r20=[r20] ++ ;; ++ cmp.ne p6,p0=r20,r0 // if there are pending events, ++ (p6) br.spnt.few 1b // call evtchn_do_upcall again. ++ br.sptk.many ia64_leave_kernel ++END(xen_event_callback) ++ ++ ++ /* ++ * There is no particular reason for this code to be here, other than that ++ * there happens to be space here that would go unused otherwise. If this ++ * fault ever gets "unreserved", simply moved the following code to a more ++ * suitable spot... ++ */ ++ ++GLOBAL_ENTRY(xen_bsw1) ++ /* FIXME: THIS CODE IS NOT NaT SAFE! */ ++ mov r14=ar.unat ++ movl r30=XSI_B1NAT ++ ;; ++ ld8 r30=[r30];; ++ mov ar.unat=r30 ++ movl r30=XSI_BANKNUM; ++ mov r31=1;; ++ st4 [r30]=r31; ++ movl r30=XSI_BANK1_R16; ++ movl r31=XSI_BANK1_R16+8;; ++ ld8.fill r16=[r30],16; ld8.fill r17=[r31],16;; ++ ld8.fill r18=[r30],16; ld8.fill r19=[r31],16;; ++ ld8.fill r20=[r30],16; ld8.fill r21=[r31],16;; ++ ld8.fill r22=[r30],16; ld8.fill r23=[r31],16;; ++ ld8.fill r24=[r30],16; ld8.fill r25=[r31],16;; ++ ld8.fill r26=[r30],16; ld8.fill r27=[r31],16;; ++ ld8.fill r28=[r30],16; ld8.fill r29=[r31],16;; ++ ld8.fill r30=[r30]; ld8.fill r31=[r31];; ++ mov ar.unat=r14 ++ br.ret.sptk.many b0 ++END(xen_bsw1) ++ ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xenminstate.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xenminstate.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,359 @@ ++ ++#include <asm/cache.h> ++ ++#ifdef CONFIG_XEN ++#include "../kernel/entry.h" ++#else ++#include "entry.h" ++#endif ++ ++/* ++ * For ivt.s we want to access the stack virtually so we don't have to disable translation ++ * on interrupts. ++ * ++ * On entry: ++ * r1: pointer to current task (ar.k6) ++ */ ++#define MINSTATE_START_SAVE_MIN_VIRT \ ++(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ ++ ;; \ ++(pUStk) mov.m r24=ar.rnat; \ ++(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ ++(pKStk) mov r1=sp; /* get sp */ \ ++ ;; \ ++(pUStk) lfetch.fault.excl.nt1 [r22]; \ ++(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ ++(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ ++ ;; \ ++(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ ++(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ ++ ;; \ ++(pUStk) mov r18=ar.bsp; \ ++(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ ++ ++#define MINSTATE_END_SAVE_MIN_VIRT \ ++ bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ ++ ;; ++ ++/* ++ * For mca_asm.S we want to access the stack physically since the state is saved before we ++ * go virtual and don't want to destroy the iip or ipsr. ++ */ ++#define MINSTATE_START_SAVE_MIN_PHYS \ ++(pKStk) mov r3=IA64_KR(PER_CPU_DATA);; \ ++(pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \ ++(pKStk) ld8 r3 = [r3];; \ ++(pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \ ++(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ ++(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ ++(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ++ ;; \ ++(pUStk) mov r24=ar.rnat; \ ++(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ ++(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ ++(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ ++ ;; \ ++(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ ++(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ ++ ;; \ ++(pUStk) mov r18=ar.bsp; \ ++(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ ++ ++#define MINSTATE_END_SAVE_MIN_PHYS \ ++ dep r12=-1,r12,61,3; /* make sp a kernel virtual address */ \ ++ ;; ++ ++#ifdef MINSTATE_VIRT ++# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT) ++# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_VIRT ++# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_VIRT ++#endif ++ ++#ifdef MINSTATE_PHYS ++# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; tpa reg=reg ++# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS ++# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS ++#endif ++ ++/* ++ * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves ++ * the minimum state necessary that allows us to turn psr.ic back ++ * on. ++ * ++ * Assumed state upon entry: ++ * psr.ic: off ++ * r31: contains saved predicates (pr) ++ * ++ * Upon exit, the state is as follows: ++ * psr.ic: off ++ * r2 = points to &pt_regs.r16 ++ * r8 = contents of ar.ccv ++ * r9 = contents of ar.csd ++ * r10 = contents of ar.ssd ++ * r11 = FPSR_DEFAULT ++ * r12 = kernel sp (kernel virtual address) ++ * r13 = points to current task_struct (kernel virtual address) ++ * p15 = TRUE if psr.i is set in cr.ipsr ++ * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: ++ * preserved ++ * CONFIG_XEN note: p6/p7 are not preserved ++ * ++ * Note that psr.ic is NOT turned on by this macro. This is so that ++ * we can pass interruption state as arguments to a handler. ++ */ ++#ifdef CONFIG_XEN ++#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ ++ MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ ++ mov r27=ar.rsc; /* M */ \ ++ mov r20=r1; /* A */ \ ++ mov r25=ar.unat; /* M */ \ ++ /* mov r29=cr.ipsr; /* M */ \ ++ movl r29=XSI_IPSR;; \ ++ ld8 r29=[r29];; \ ++ mov r26=ar.pfs; /* I */ \ ++ /* mov r28=cr.iip; /* M */ \ ++ movl r28=XSI_IIP;; \ ++ ld8 r28=[r28];; \ ++ mov r21=ar.fpsr; /* M */ \ ++ COVER; /* B;; (or nothing) */ \ ++ ;; \ ++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \ ++ ;; \ ++ ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ ++ st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ ++ adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \ ++ /* switch from user to kernel RBS: */ \ ++ ;; \ ++ invala; /* M */ \ ++ /* SAVE_IFS; /* see xen special handling below */ \ ++ cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \ ++ ;; \ ++ MINSTATE_START_SAVE_MIN \ ++ adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ ++ adds r16=PT(CR_IPSR),r1; \ ++ ;; \ ++ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ ++ st8 [r16]=r29; /* save cr.ipsr */ \ ++ ;; \ ++ lfetch.fault.excl.nt1 [r17]; \ ++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ ++ mov r29=b0 \ ++ ;; \ ++ adds r16=PT(R8),r1; /* initialize first base pointer */ \ ++ adds r17=PT(R9),r1; /* initialize second base pointer */ \ ++(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r8,16; \ ++.mem.offset 8,0; st8.spill [r17]=r9,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r10,24; \ ++.mem.offset 8,0; st8.spill [r17]=r11,24; \ ++ ;; \ ++ /* xen special handling for possibly lazy cover */ \ ++ movl r8=XSI_PRECOVER_IFS; \ ++ ;; \ ++ ld8 r30=[r8]; \ ++ ;; \ ++ st8 [r16]=r28,16; /* save cr.iip */ \ ++ st8 [r17]=r30,16; /* save cr.ifs */ \ ++(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ ++ mov r8=ar.ccv; \ ++ mov r9=ar.csd; \ ++ mov r10=ar.ssd; \ ++ movl r11=FPSR_DEFAULT; /* L-unit */ \ ++ ;; \ ++ st8 [r16]=r25,16; /* save ar.unat */ \ ++ st8 [r17]=r26,16; /* save ar.pfs */ \ ++ shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ ++ ;; \ ++ st8 [r16]=r27,16; /* save ar.rsc */ \ ++(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \ ++(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \ ++ ;; /* avoid RAW on r16 & r17 */ \ ++(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \ ++ st8 [r17]=r31,16; /* save predicates */ \ ++(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \ ++ ;; \ ++ st8 [r16]=r29,16; /* save b0 */ \ ++ st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ ++ cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ ++.mem.offset 8,0; st8.spill [r17]=r12,16; \ ++ adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r13,16; \ ++.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \ ++ mov r13=IA64_KR(CURRENT); /* establish `current' */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r15,16; \ ++.mem.offset 8,0; st8.spill [r17]=r14,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r2,16; \ ++.mem.offset 8,0; st8.spill [r17]=r3,16; \ ++ ;; \ ++ EXTRA; \ ++ mov r2=b0; br.call.sptk b0=xen_bsw1;; mov b0=r2; \ ++ adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ ++ ;; \ ++ movl r1=__gp; /* establish kernel global pointer */ \ ++ ;; \ ++ /* MINSTATE_END_SAVE_MIN */ ++#else ++#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ ++ MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ ++ mov r27=ar.rsc; /* M */ \ ++ mov r20=r1; /* A */ \ ++ mov r25=ar.unat; /* M */ \ ++ mov r29=cr.ipsr; /* M */ \ ++ mov r26=ar.pfs; /* I */ \ ++ mov r28=cr.iip; /* M */ \ ++ mov r21=ar.fpsr; /* M */ \ ++ COVER; /* B;; (or nothing) */ \ ++ ;; \ ++ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \ ++ ;; \ ++ ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ ++ st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ ++ adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \ ++ /* switch from user to kernel RBS: */ \ ++ ;; \ ++ invala; /* M */ \ ++ SAVE_IFS; \ ++ cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \ ++ ;; \ ++ MINSTATE_START_SAVE_MIN \ ++ adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ ++ adds r16=PT(CR_IPSR),r1; \ ++ ;; \ ++ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ ++ st8 [r16]=r29; /* save cr.ipsr */ \ ++ ;; \ ++ lfetch.fault.excl.nt1 [r17]; \ ++ tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ ++ mov r29=b0 \ ++ ;; \ ++ adds r16=PT(R8),r1; /* initialize first base pointer */ \ ++ adds r17=PT(R9),r1; /* initialize second base pointer */ \ ++(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r8,16; \ ++.mem.offset 8,0; st8.spill [r17]=r9,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r10,24; \ ++.mem.offset 8,0; st8.spill [r17]=r11,24; \ ++ ;; \ ++ st8 [r16]=r28,16; /* save cr.iip */ \ ++ st8 [r17]=r30,16; /* save cr.ifs */ \ ++(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ ++ mov r8=ar.ccv; \ ++ mov r9=ar.csd; \ ++ mov r10=ar.ssd; \ ++ movl r11=FPSR_DEFAULT; /* L-unit */ \ ++ ;; \ ++ st8 [r16]=r25,16; /* save ar.unat */ \ ++ st8 [r17]=r26,16; /* save ar.pfs */ \ ++ shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ ++ ;; \ ++ st8 [r16]=r27,16; /* save ar.rsc */ \ ++(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \ ++(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \ ++ ;; /* avoid RAW on r16 & r17 */ \ ++(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \ ++ st8 [r17]=r31,16; /* save predicates */ \ ++(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \ ++ ;; \ ++ st8 [r16]=r29,16; /* save b0 */ \ ++ st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ ++ cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ ++.mem.offset 8,0; st8.spill [r17]=r12,16; \ ++ adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r13,16; \ ++.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \ ++ mov r13=IA64_KR(CURRENT); /* establish `current' */ \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r15,16; \ ++.mem.offset 8,0; st8.spill [r17]=r14,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r16]=r2,16; \ ++.mem.offset 8,0; st8.spill [r17]=r3,16; \ ++ adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ ++ ;; \ ++ EXTRA; \ ++ movl r1=__gp; /* establish kernel global pointer */ \ ++ ;; \ ++ MINSTATE_END_SAVE_MIN ++#endif ++ ++/* ++ * SAVE_REST saves the remainder of pt_regs (with psr.ic on). ++ * ++ * Assumed state upon entry: ++ * psr.ic: on ++ * r2: points to &pt_regs.r16 ++ * r3: points to &pt_regs.r17 ++ * r8: contents of ar.ccv ++ * r9: contents of ar.csd ++ * r10: contents of ar.ssd ++ * r11: FPSR_DEFAULT ++ * ++ * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. ++ */ ++#define SAVE_REST \ ++.mem.offset 0,0; st8.spill [r2]=r16,16; \ ++.mem.offset 8,0; st8.spill [r3]=r17,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r18,16; \ ++.mem.offset 8,0; st8.spill [r3]=r19,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r20,16; \ ++.mem.offset 8,0; st8.spill [r3]=r21,16; \ ++ mov r18=b6; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r22,16; \ ++.mem.offset 8,0; st8.spill [r3]=r23,16; \ ++ mov r19=b7; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r24,16; \ ++.mem.offset 8,0; st8.spill [r3]=r25,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r26,16; \ ++.mem.offset 8,0; st8.spill [r3]=r27,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r28,16; \ ++.mem.offset 8,0; st8.spill [r3]=r29,16; \ ++ ;; \ ++.mem.offset 0,0; st8.spill [r2]=r30,16; \ ++.mem.offset 8,0; st8.spill [r3]=r31,32; \ ++ ;; \ ++ mov ar.fpsr=r11; /* M-unit */ \ ++ st8 [r2]=r8,8; /* ar.ccv */ \ ++ adds r24=PT(B6)-PT(F7),r3; \ ++ ;; \ ++ stf.spill [r2]=f6,32; \ ++ stf.spill [r3]=f7,32; \ ++ ;; \ ++ stf.spill [r2]=f8,32; \ ++ stf.spill [r3]=f9,32; \ ++ ;; \ ++ stf.spill [r2]=f10; \ ++ stf.spill [r3]=f11; \ ++ adds r25=PT(B7)-PT(F11),r3; \ ++ ;; \ ++ st8 [r24]=r18,16; /* b6 */ \ ++ st8 [r25]=r19,16; /* b7 */ \ ++ ;; \ ++ st8 [r24]=r9; /* ar.csd */ \ ++ st8 [r25]=r10; /* ar.ssd */ \ ++ ;; ++ ++#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov r30=cr.ifs,) ++#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19) ++#ifdef CONFIG_XEN ++#define SAVE_MIN break 0;; /* FIXME: non-cover version only for ia32 support? */ ++#else ++#define SAVE_MIN DO_SAVE_MIN( , mov r30=r0, ) ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xenpal.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xenpal.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,85 @@ ++/* ++ * ia64/xen/xenpal.S ++ * ++ * Alternate PAL routines for Xen. Heavily leveraged from ++ * ia64/kernel/pal.S ++ * ++ * Copyright (C) 2005 Hewlett-Packard Co ++ * Dan Magenheimer <dan.magenheimer@.hp.com> ++ */ ++ ++#include <asm/asmmacro.h> ++#include <asm/processor.h> ++ ++GLOBAL_ENTRY(xen_pal_call_static) ++ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) ++ alloc loc1 = ar.pfs,5,5,0,0 ++#ifdef CONFIG_XEN ++ movl r22=running_on_xen;; ++ ld4 r22=[r22];; ++ cmp.eq p7,p0=r22,r0 ++(p7) br.cond.spnt.many __ia64_pal_call_static;; ++#endif ++ movl loc2 = pal_entry_point ++1: { ++ mov r28 = in0 ++ mov r29 = in1 ++ mov r8 = ip ++ } ++ ;; ++ ld8 loc2 = [loc2] // loc2 <- entry point ++ tbit.nz p6,p7 = in4, 0 ++ adds r8 = 1f-1b,r8 ++ mov loc4=ar.rsc // save RSE configuration ++ ;; ++ mov ar.rsc=0 // put RSE in enforced lazy, LE mode ++#ifdef CONFIG_XEN ++ mov r9 = r8 ++ XEN_HYPER_GET_PSR ++ ;; ++ mov loc3 = r8 ++ mov r8 = r9 ++ ;; ++#else ++ mov loc3 = psr ++#endif ++ mov loc0 = rp ++ .body ++ mov r30 = in2 ++ ++#ifdef CONFIG_XEN ++ // this is low priority for paravirtualization, but is called ++ // from the idle loop so confuses privop counting ++ movl r31=XSI_PSR_I_ADDR ++ ;; ++ ld8 r31=[r31] ++ mov r22=1 ++ ;; ++ st1 [r31]=r22 ++ ;; ++(p6) movl r31=XSI_PSR_IC ++ ;; ++(p6) st4.rel [r31]=r0 ++ ;; ++ mov r31 = in3 ++ mov b7 = loc2 ++ ;; ++#else ++(p6) rsm psr.i | psr.ic ++ mov r31 = in3 ++ mov b7 = loc2 ++ ++(p7) rsm psr.i ++ ;; ++(p6) srlz.i ++#endif ++ mov rp = r8 ++ br.cond.sptk.many b7 ++1: mov psr.l = loc3 ++ mov ar.rsc = loc4 // restore RSE configuration ++ mov ar.pfs = loc1 ++ mov rp = loc0 ++ ;; ++ srlz.d // seralize restoration of psr.l ++ br.ret.sptk.many b0 ++END(xen_pal_call_static) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/ia64/xen/xensetup.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/ia64/xen/xensetup.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,52 @@ ++/* ++ * Support routines for Xen ++ * ++ * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer@hp.com> ++ */ ++ ++#include <asm/processor.h> ++#include <asm/asmmacro.h> ++ ++#define isBP p3 // are we the Bootstrap Processor? ++ ++ .text ++GLOBAL_ENTRY(early_xen_setup) ++ mov r8=ar.rsc // Initialized in head.S ++(isBP) movl r9=running_on_xen;; ++ extr.u r8=r8,2,2;; // Extract pl fields ++ cmp.eq p7,p0=r8,r0 // p7: !running on xen ++ mov r8=1 // booleanize. ++(p7) br.ret.sptk.many rp;; ++(isBP) st4 [r9]=r8 ++ movl r10=xen_ivt;; ++ ++ mov cr.iva=r10 ++ ++ /* Set xsi base. */ ++#define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600 ++(isBP) mov r2=FW_HYPERCALL_SET_SHARED_INFO_VA ++(isBP) movl r28=XSI_BASE;; ++(isBP) break 0x1000;; ++ ++ br.ret.sptk.many rp ++ ;; ++END(early_xen_setup) ++ ++#include <xen/interface/xen.h> ++ ++/* Stub for suspend. ++ Just force the stacked registers to be written in memory. */ ++GLOBAL_ENTRY(xencomm_arch_hypercall_suspend) ++ ;; ++ alloc r20=ar.pfs,0,0,6,0 ++ mov r2=__HYPERVISOR_sched_op ++ ;; ++ /* We don't want to deal with RSE. */ ++ flushrs ++ mov r33=r32 ++ mov r32=2 // SCHEDOP_shutdown ++ ;; ++ break 0x1000 ++ ;; ++ br.ret.sptk.many b0 ++END(xencomm_arch_hypercall_suspend) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/um/kernel/physmem.c +--- a/arch/um/kernel/physmem.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/um/kernel/physmem.c Wed Aug 08 16:25:28 2007 -0300 +@@ -226,7 +226,7 @@ EXPORT_SYMBOL(physmem_remove_mapping); + EXPORT_SYMBOL(physmem_remove_mapping); + EXPORT_SYMBOL(physmem_subst_mapping); + +-void arch_free_page(struct page *page, int order) ++int arch_free_page(struct page *page, int order) + { + void *virt; + int i; +@@ -235,6 +235,8 @@ void arch_free_page(struct page *page, i + virt = __va(page_to_phys(page + i)); + physmem_remove_mapping(virt); + } ++ ++ return 0; + } + + int is_remapped(void *virt) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/Kconfig +--- a/arch/x86_64/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -34,6 +34,7 @@ config LOCKDEP_SUPPORT + + config STACKTRACE_SUPPORT + bool ++ depends on !X86_64_XEN + default y + + config SEMAPHORE_SLEEPERS +@@ -171,6 +172,22 @@ config GENERIC_CPU + + endchoice + ++config X86_64_XEN ++ bool "Enable Xen compatible kernel" ++ select SWIOTLB ++ help ++ This option will compile a kernel compatible with Xen hypervisor ++ ++config X86_NO_TSS ++ bool ++ depends on X86_64_XEN ++ default y ++ ++config X86_NO_IDT ++ bool ++ depends on X86_64_XEN ++ default y ++ + # + # Define implied options from the CPU selection here + # +@@ -191,6 +208,7 @@ config X86_INTERNODE_CACHE_BYTES + + config X86_TSC + bool ++ depends on !X86_64_XEN + default y + + config X86_GOOD_APIC +@@ -239,7 +257,7 @@ config X86_CPUID + + config X86_HT + bool +- depends on SMP && !MK8 ++ depends on SMP && !MK8 && !X86_64_XEN + default y + + config MATH_EMULATION +@@ -253,14 +271,22 @@ config EISA + + config X86_IO_APIC + bool +- default y ++ depends !XEN_UNPRIVILEGED_GUEST ++ default y ++ ++config X86_XEN_GENAPIC ++ bool ++ depends X86_64_XEN ++ default XEN_PRIVILEGED_GUEST || SMP + + config X86_LOCAL_APIC + bool ++ depends !XEN_UNPRIVILEGED_GUEST + default y + + config MTRR + bool "MTRR (Memory Type Range Register) support" ++ depends on !XEN_UNPRIVILEGED_GUEST + ---help--- + On Intel P6 family processors (Pentium Pro, Pentium II and later) + the Memory Type Range Registers (MTRRs) may be used to control +@@ -301,7 +327,7 @@ config SMP + + config SCHED_SMT + bool "SMT (Hyperthreading) scheduler support" +- depends on SMP ++ depends on SMP && !X86_64_XEN + default n + help + SMT scheduler support improves the CPU scheduler's decision making +@@ -311,7 +337,7 @@ config SCHED_SMT + + config SCHED_MC + bool "Multi-core scheduler support" +- depends on SMP ++ depends on SMP && !X86_64_XEN + default y + help + Multi-core scheduler support improves the CPU scheduler's decision +@@ -322,7 +348,7 @@ source "kernel/Kconfig.preempt" + + config NUMA + bool "Non Uniform Memory Access (NUMA) Support" +- depends on SMP ++ depends on SMP && !X86_64_XEN + help + Enable NUMA (Non Uniform Memory Access) support. The kernel + will try to allocate memory used by a CPU on the local memory +@@ -378,7 +404,7 @@ config ARCH_DISCONTIGMEM_DEFAULT + + config ARCH_SPARSEMEM_ENABLE + def_bool y +- depends on (NUMA || EXPERIMENTAL) ++ depends on (NUMA || EXPERIMENTAL) && !X86_64_XEN + + config ARCH_MEMORY_PROBE + def_bool y +@@ -406,6 +432,7 @@ config NR_CPUS + int "Maximum number of CPUs (2-256)" + range 2 255 + depends on SMP ++ default "16" if X86_64_XEN + default "8" + help + This allows you to specify the maximum number of CPUs which this +@@ -428,6 +455,7 @@ config ARCH_ENABLE_MEMORY_HOTPLUG + + config HPET_TIMER + bool ++ depends on !X86_64_XEN + default y + help + Use the IA-PC HPET (High Precision Event Timer) to manage +@@ -448,7 +476,7 @@ config IOMMU + default y + select SWIOTLB + select AGP +- depends on PCI ++ depends on PCI && !X86_64_XEN + help + Support for full DMA access of devices with 32bit memory access only + on systems with more than 3GB. This is usually needed for USB, +@@ -495,6 +523,7 @@ config SWIOTLB + + config X86_MCE + bool "Machine check support" if EMBEDDED ++ depends on !X86_64_XEN + default y + help + Include a machine check error handler to report hardware errors. +@@ -520,6 +549,7 @@ config X86_MCE_AMD + + config KEXEC + bool "kexec system call" ++ depends on !XEN_UNPRIVILEGED_GUEST + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot +@@ -645,8 +675,11 @@ config GENERIC_PENDING_IRQ + default y + + menu "Power management options" +- ++ depends on !XEN_UNPRIVILEGED_GUEST ++ ++if !X86_64_XEN + source kernel/power/Kconfig ++endif + + source "drivers/acpi/Kconfig" + +@@ -668,6 +701,21 @@ config PCI_MMCONFIG + config PCI_MMCONFIG + bool "Support mmconfig PCI config space access" + depends on PCI && ACPI ++ ++config XEN_PCIDEV_FRONTEND ++ bool "Xen PCI Frontend" ++ depends on PCI && X86_64_XEN ++ default y ++ help ++ The PCI device frontend driver allows the kernel to import arbitrary ++ PCI devices from a PCI backend to support PCI driver domains. ++ ++config XEN_PCIDEV_FE_DEBUG ++ bool "Xen PCI Frontend Debugging" ++ depends on XEN_PCIDEV_FRONTEND ++ default n ++ help ++ Enables some debug statements within the PCI Frontend. + + source "drivers/pci/pcie/Kconfig" + +@@ -739,4 +787,6 @@ source "security/Kconfig" + + source "crypto/Kconfig" + ++source "drivers/xen/Kconfig" ++ + source "lib/Kconfig" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/Makefile +--- a/arch/x86_64/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -35,6 +35,10 @@ cflags-$(CONFIG_MCORE2) += \ + cflags-$(CONFIG_MCORE2) += \ + $(call cc-option,-march=core2,$(call cc-option,-mtune=generic)) + cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic) ++ ++cppflags-$(CONFIG_XEN) += \ ++ -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) ++CPPFLAGS += $(cppflags-y) + + cflags-y += -m64 + cflags-y += -mno-red-zone +@@ -90,6 +94,21 @@ PHONY += bzImage bzlilo install archmrpr + PHONY += bzImage bzlilo install archmrproper \ + fdimage fdimage144 fdimage288 isoimage archclean + ++ifdef CONFIG_XEN ++CPPFLAGS := -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS) ++head-y := arch/x86_64/kernel/head-xen.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o ++LDFLAGS_vmlinux := -e _start ++boot := arch/i386/boot-xen ++.PHONY: vmlinuz ++#Default target when executing "make" ++all: vmlinuz ++ ++vmlinuz: vmlinux ++ $(Q)$(MAKE) $(build)=$(boot) $@ ++ ++install: ++ $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@ ++else + #Default target when executing "make" + all: bzImage + +@@ -110,6 +129,7 @@ fdimage fdimage144 fdimage288 isoimage: + + install: + $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ ++endif + + archclean: + $(Q)$(MAKE) $(clean)=$(boot) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/ia32/Makefile +--- a/arch/x86_64/ia32/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/ia32/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -14,11 +14,19 @@ audit-class-$(CONFIG_AUDIT) := audit.o + audit-class-$(CONFIG_AUDIT) := audit.o + obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y) + ++ifdef CONFIG_XEN ++$(obj)/syscall32_syscall.o: \ ++ $(foreach F,int80 sysenter syscall,$(obj)/vsyscall-$F.so) ++ ++targets := $(foreach F,int80 sysenter syscall,vsyscall-$F.o vsyscall-$F.so) ++ ++else + $(obj)/syscall32_syscall.o: \ + $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so) + + # Teach kbuild about targets + targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so) ++endif + + # The DSO images are built using a special linker script + quiet_cmd_syscall = SYSCALL $@ +@@ -27,9 +35,20 @@ quiet_cmd_syscall = SYSCALL $@ + -Wl,-soname=linux-gate.so.1 -o $@ \ + -Wl,-T,$(filter-out FORCE,$^) + ++$(obj)/vsyscall-int80.so \ + $(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \ + $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE + $(call if_changed,syscall) + + AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 + AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 ++ ++ifdef CONFIG_XEN ++AFLAGS_vsyscall-int80.o = -m32 -Wa,-32 ++CFLAGS_syscall32.o += -DUSE_INT80 ++AFLAGS_syscall32_syscall.o += -DUSE_INT80 ++ ++include $(srctree)/scripts/Makefile.xen ++ ++obj-y := $(call cherrypickxen, $(obj-y)) ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/ia32/ia32entry-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/ia32/ia32entry-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,744 @@ ++/* ++ * Compatibility mode system call entry point for x86-64. ++ * ++ * Copyright 2000-2002 Andi Kleen, SuSE Labs. ++ */ ++ ++#include <asm/dwarf2.h> ++#include <asm/calling.h> ++#include <asm/asm-offsets.h> ++#include <asm/current.h> ++#include <asm/errno.h> ++#include <asm/ia32_unistd.h> ++#include <asm/thread_info.h> ++#include <asm/segment.h> ++#include <asm/vsyscall32.h> ++#include <asm/irqflags.h> ++#include <linux/linkage.h> ++ ++#define __XEN_X86_64 1 ++ ++#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8) ++ ++ .macro IA32_ARG_FIXUP noebp=0 ++ movl %edi,%r8d ++ .if \noebp ++ .else ++ movl %ebp,%r9d ++ .endif ++ xchg %ecx,%esi ++ movl %ebx,%edi ++ movl %edx,%edx /* zero extension */ ++ .endm ++ ++ /* clobbers %eax */ ++ .macro CLEAR_RREGS ++ xorl %eax,%eax ++ movq %rax,R11(%rsp) ++ movq %rax,R10(%rsp) ++ movq %rax,R9(%rsp) ++ movq %rax,R8(%rsp) ++ .endm ++ ++#if defined (__XEN_X86_64) ++#include "../kernel/xen_entry.S" ++ ++#define __swapgs ++#define __cli ++#define __sti ++#else ++/* ++ * Use the native instructions ++ */ ++#define __swapgs swapgs ++#define __cli cli ++#define __sti sti ++#endif ++ ++ .macro CFI_STARTPROC32 simple ++ CFI_STARTPROC \simple ++ CFI_UNDEFINED r8 ++ CFI_UNDEFINED r9 ++ CFI_UNDEFINED r10 ++ CFI_UNDEFINED r11 ++ CFI_UNDEFINED r12 ++ CFI_UNDEFINED r13 ++ CFI_UNDEFINED r14 ++ CFI_UNDEFINED r15 ++ .endm ++ ++/* ++ * 32bit SYSENTER instruction entry. ++ * ++ * Arguments: ++ * %eax System call number. ++ * %ebx Arg1 ++ * %ecx Arg2 ++ * %edx Arg3 ++ * %esi Arg4 ++ * %edi Arg5 ++ * %ebp user stack ++ * 0(%ebp) Arg6 ++ * ++ * Interrupts off. ++ * ++ * This is purely a fast path. For anything complicated we use the int 0x80 ++ * path below. Set up a complete hardware stack frame to share code ++ * with the int 0x80 path. ++ */ ++ENTRY(ia32_sysenter_target) ++ CFI_STARTPROC32 simple ++ CFI_DEF_CFA rsp,0 ++ CFI_REGISTER rsp,rbp ++ __swapgs ++ movq %gs:pda_kernelstack, %rsp ++ addq $(PDA_STACKOFFSET),%rsp ++ /* ++ * No need to follow this irqs on/off section: the syscall ++ * disabled irqs, here we enable it straight after entry: ++ */ ++ XEN_UNBLOCK_EVENTS(%r11) ++ __sti ++ movl %ebp,%ebp /* zero extension */ ++ pushq $__USER32_DS ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET ss,0*/ ++ pushq %rbp ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rsp,0 ++ pushfq ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET rflags,0*/ ++ movl $VSYSCALL32_SYSEXIT, %r10d ++ CFI_REGISTER rip,r10 ++ pushq $__USER32_CS ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET cs,0*/ ++ movl %eax, %eax ++ pushq %r10 ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rip,0 ++ pushq %rax ++ CFI_ADJUST_CFA_OFFSET 8 ++ cld ++ SAVE_ARGS 0,0,0 ++ /* no need to do an access_ok check here because rbp has been ++ 32bit zero extended */ ++1: movl (%rbp),%r9d ++ .section __ex_table,"a" ++ .quad 1b,ia32_badarg ++ .previous ++ GET_THREAD_INFO(%r10) ++ orl $TS_COMPAT,threadinfo_status(%r10) ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) ++ CFI_REMEMBER_STATE ++ jnz sysenter_tracesys ++sysenter_do_call: ++ cmpl $(IA32_NR_syscalls-1),%eax ++ ja ia32_badsys ++ IA32_ARG_FIXUP 1 ++ call *ia32_sys_call_table(,%rax,8) ++ movq %rax,RAX-ARGOFFSET(%rsp) ++ GET_THREAD_INFO(%r10) ++ XEN_BLOCK_EVENTS(%r11) ++ __cli ++ TRACE_IRQS_OFF ++ testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) ++ jnz int_ret_from_sys_call ++ andl $~TS_COMPAT,threadinfo_status(%r10) ++ /* clear IF, that popfq doesn't enable interrupts early */ ++ andl $~0x200,EFLAGS-R11(%rsp) ++ RESTORE_ARGS 1,24,1,1,1,1 ++ popfq ++ CFI_ADJUST_CFA_OFFSET -8 ++ /*CFI_RESTORE rflags*/ ++ popq %rcx /* User %esp */ ++ CFI_ADJUST_CFA_OFFSET -8 ++ CFI_REGISTER rsp,rcx ++ movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */ ++ CFI_REGISTER rip,rdx ++ TRACE_IRQS_ON ++ __swapgs ++ XEN_UNBLOCK_EVENTS(%r11) ++ __sti /* sti only takes effect after the next instruction */ ++ /* sysexit */ ++ .byte 0xf, 0x35 /* TBD */ ++ ++sysenter_tracesys: ++ CFI_RESTORE_STATE ++ SAVE_REST ++ CLEAR_RREGS ++ movq $-ENOSYS,RAX(%rsp) /* really needed? */ ++ movq %rsp,%rdi /* &pt_regs -> arg1 */ ++ call syscall_trace_enter ++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ RESTORE_REST ++ movl %ebp, %ebp ++ /* no need to do an access_ok check here because rbp has been ++ 32bit zero extended */ ++1: movl (%rbp),%r9d ++ .section __ex_table,"a" ++ .quad 1b,ia32_badarg ++ .previous ++ jmp sysenter_do_call ++ CFI_ENDPROC ++ENDPROC(ia32_sysenter_target) ++ ++/* ++ * 32bit SYSCALL instruction entry. ++ * ++ * Arguments: ++ * %eax System call number. ++ * %ebx Arg1 ++ * %ecx return EIP ++ * %edx Arg3 ++ * %esi Arg4 ++ * %edi Arg5 ++ * %ebp Arg2 [note: not saved in the stack frame, should not be touched] ++ * %esp user stack ++ * 0(%esp) Arg6 ++ * ++ * Interrupts off. ++ * ++ * This is purely a fast path. For anything complicated we use the int 0x80 ++ * path below. Set up a complete hardware stack frame to share code ++ * with the int 0x80 path. ++ */ ++ENTRY(ia32_cstar_target) ++ CFI_STARTPROC32 simple ++ CFI_DEF_CFA rsp,PDA_STACKOFFSET ++ CFI_REGISTER rip,rcx ++ /*CFI_REGISTER rflags,r11*/ ++ __swapgs ++ movl %esp,%r8d ++ CFI_REGISTER rsp,r8 ++ movq %gs:pda_kernelstack,%rsp ++ /* ++ * No need to follow this irqs on/off section: the syscall ++ * disabled irqs and here we enable it straight after entry: ++ */ ++ XEN_UNBLOCK_EVENTS(%r11) ++ __sti ++ SAVE_ARGS 8,1,1 ++ movl %eax,%eax /* zero extension */ ++ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) ++ movq %rcx,RIP-ARGOFFSET(%rsp) ++ CFI_REL_OFFSET rip,RIP-ARGOFFSET ++ movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */ ++ movl %ebp,%ecx ++ movq $__USER32_CS,CS-ARGOFFSET(%rsp) ++ movq $__USER32_DS,SS-ARGOFFSET(%rsp) ++ movq %r11,EFLAGS-ARGOFFSET(%rsp) ++ /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ ++ movq %r8,RSP-ARGOFFSET(%rsp) ++ CFI_REL_OFFSET rsp,RSP-ARGOFFSET ++ /* no need to do an access_ok check here because r8 has been ++ 32bit zero extended */ ++ /* hardware stack frame is complete now */ ++1: movl (%r8),%r9d ++ .section __ex_table,"a" ++ .quad 1b,ia32_badarg ++ .previous ++ GET_THREAD_INFO(%r10) ++ orl $TS_COMPAT,threadinfo_status(%r10) ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) ++ CFI_REMEMBER_STATE ++ jnz cstar_tracesys ++cstar_do_call: ++ cmpl $IA32_NR_syscalls-1,%eax ++ ja ia32_badsys ++ IA32_ARG_FIXUP 1 ++ call *ia32_sys_call_table(,%rax,8) ++ movq %rax,RAX-ARGOFFSET(%rsp) ++ GET_THREAD_INFO(%r10) ++ XEN_BLOCK_EVENTS(%r11) ++ __cli ++ TRACE_IRQS_OFF ++ testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) ++ jnz int_ret_from_sys_call ++ andl $~TS_COMPAT,threadinfo_status(%r10) ++ RESTORE_ARGS 1,-ARG_SKIP,1,1,1 ++ movl RIP-ARGOFFSET(%rsp),%ecx ++ CFI_REGISTER rip,rcx ++ movl EFLAGS-ARGOFFSET(%rsp),%r11d ++ /*CFI_REGISTER rflags,r11*/ ++ TRACE_IRQS_ON ++ movl RSP-ARGOFFSET(%rsp),%esp ++ CFI_RESTORE rsp ++ __swapgs ++ sysretl /* TBD */ ++ ++cstar_tracesys: ++ CFI_RESTORE_STATE ++ SAVE_REST ++ CLEAR_RREGS ++ movq $-ENOSYS,RAX(%rsp) /* really needed? */ ++ movq %rsp,%rdi /* &pt_regs -> arg1 */ ++ call syscall_trace_enter ++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ RESTORE_REST ++ movl RSP-ARGOFFSET(%rsp), %r8d ++ /* no need to do an access_ok check here because r8 has been ++ 32bit zero extended */ ++1: movl (%r8),%r9d ++ .section __ex_table,"a" ++ .quad 1b,ia32_badarg ++ .previous ++ jmp cstar_do_call ++END(ia32_cstar_target) ++ ++ia32_badarg: ++ movq $-EFAULT,%rax ++ jmp ia32_sysret ++ CFI_ENDPROC ++ ++/* ++ * Emulated IA32 system calls via int 0x80. ++ * ++ * Arguments: ++ * %eax System call number. ++ * %ebx Arg1 ++ * %ecx Arg2 ++ * %edx Arg3 ++ * %esi Arg4 ++ * %edi Arg5 ++ * %ebp Arg6 [note: not saved in the stack frame, should not be touched] ++ * ++ * Notes: ++ * Uses the same stack frame as the x86-64 version. ++ * All registers except %eax must be saved (but ptrace may violate that) ++ * Arguments are zero extended. For system calls that want sign extension and ++ * take long arguments a wrapper is needed. Most calls can just be called ++ * directly. ++ * Assumes it is only called from user space and entered with interrupts off. ++ */ ++ ++ENTRY(ia32_syscall) ++ CFI_STARTPROC simple ++ CFI_DEF_CFA rsp,SS+8-RIP ++ /*CFI_REL_OFFSET ss,SS-RIP*/ ++ CFI_REL_OFFSET rsp,RSP-RIP ++ /*CFI_REL_OFFSET rflags,EFLAGS-RIP*/ ++ /*CFI_REL_OFFSET cs,CS-RIP*/ ++ CFI_REL_OFFSET rip,RIP-RIP ++ __swapgs ++ /* ++ * No need to follow this irqs on/off section: the syscall ++ * disabled irqs and here we enable it straight after entry: ++ */ ++ XEN_UNBLOCK_EVENTS(%r11) ++ __sti ++ movq (%rsp),%rcx ++ movq 8(%rsp),%r11 ++ addq $0x10,%rsp /* skip rcx and r11 */ ++ movl %eax,%eax ++ pushq %rax ++ CFI_ADJUST_CFA_OFFSET 8 ++ cld ++/* 1: jmp 1b */ ++ /* note the registers are not zero extended to the sf. ++ this could be a problem. */ ++ SAVE_ARGS 0,0,1 ++ GET_THREAD_INFO(%r10) ++ orl $TS_COMPAT,threadinfo_status(%r10) ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) ++ jnz ia32_tracesys ++ia32_do_syscall: ++ cmpl $(IA32_NR_syscalls-1),%eax ++ ja ia32_badsys ++ IA32_ARG_FIXUP ++ call *ia32_sys_call_table(,%rax,8) # xxx: rip relative ++ia32_sysret: ++ movq %rax,RAX-ARGOFFSET(%rsp) ++ jmp int_ret_from_sys_call ++ ++ia32_tracesys: ++ SAVE_REST ++ movq $-ENOSYS,RAX(%rsp) /* really needed? */ ++ movq %rsp,%rdi /* &pt_regs -> arg1 */ ++ call syscall_trace_enter ++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ RESTORE_REST ++ jmp ia32_do_syscall ++END(ia32_syscall) ++ ++ia32_badsys: ++ movq $0,ORIG_RAX-ARGOFFSET(%rsp) ++ movq $-ENOSYS,RAX-ARGOFFSET(%rsp) ++ jmp int_ret_from_sys_call ++ ++quiet_ni_syscall: ++ movq $-ENOSYS,%rax ++ ret ++ CFI_ENDPROC ++ ++ .macro PTREGSCALL label, func, arg ++ .globl \label ++\label: ++ leaq \func(%rip),%rax ++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ ++ jmp ia32_ptregs_common ++ .endm ++ ++ CFI_STARTPROC32 ++ ++ PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi ++ PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi ++ PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx ++ PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx ++ PTREGSCALL stub32_execve, sys32_execve, %rcx ++ PTREGSCALL stub32_fork, sys_fork, %rdi ++ PTREGSCALL stub32_clone, sys32_clone, %rdx ++ PTREGSCALL stub32_vfork, sys_vfork, %rdi ++ PTREGSCALL stub32_iopl, sys_iopl, %rsi ++ PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx ++ ++ENTRY(ia32_ptregs_common) ++ popq %r11 ++ CFI_ENDPROC ++ CFI_STARTPROC32 simple ++ CFI_DEF_CFA rsp,SS+8-ARGOFFSET ++ CFI_REL_OFFSET rax,RAX-ARGOFFSET ++ CFI_REL_OFFSET rcx,RCX-ARGOFFSET ++ CFI_REL_OFFSET rdx,RDX-ARGOFFSET ++ CFI_REL_OFFSET rsi,RSI-ARGOFFSET ++ CFI_REL_OFFSET rdi,RDI-ARGOFFSET ++ CFI_REL_OFFSET rip,RIP-ARGOFFSET ++/* CFI_REL_OFFSET cs,CS-ARGOFFSET*/ ++/* CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ ++ CFI_REL_OFFSET rsp,RSP-ARGOFFSET ++/* CFI_REL_OFFSET ss,SS-ARGOFFSET*/ ++ SAVE_REST ++ call *%rax ++ RESTORE_REST ++ jmp ia32_sysret /* misbalances the return cache */ ++ CFI_ENDPROC ++END(ia32_ptregs_common) ++ ++ .section .rodata,"a" ++ .align 8 ++ia32_sys_call_table: ++ .quad sys_restart_syscall ++ .quad sys_exit ++ .quad stub32_fork ++ .quad sys_read ++ .quad sys_write ++ .quad compat_sys_open /* 5 */ ++ .quad sys_close ++ .quad sys32_waitpid ++ .quad sys_creat ++ .quad sys_link ++ .quad sys_unlink /* 10 */ ++ .quad stub32_execve ++ .quad sys_chdir ++ .quad compat_sys_time ++ .quad sys_mknod ++ .quad sys_chmod /* 15 */ ++ .quad sys_lchown16 ++ .quad quiet_ni_syscall /* old break syscall holder */ ++ .quad sys_stat ++ .quad sys32_lseek ++ .quad sys_getpid /* 20 */ ++ .quad compat_sys_mount /* mount */ ++ .quad sys_oldumount /* old_umount */ ++ .quad sys_setuid16 ++ .quad sys_getuid16 ++ .quad compat_sys_stime /* stime */ /* 25 */ ++ .quad sys32_ptrace /* ptrace */ ++ .quad sys_alarm ++ .quad sys_fstat /* (old)fstat */ ++ .quad sys_pause ++ .quad compat_sys_utime /* 30 */ ++ .quad quiet_ni_syscall /* old stty syscall holder */ ++ .quad quiet_ni_syscall /* old gtty syscall holder */ ++ .quad sys_access ++ .quad sys_nice ++ .quad quiet_ni_syscall /* 35 */ /* old ftime syscall holder */ ++ .quad sys_sync ++ .quad sys32_kill ++ .quad sys_rename ++ .quad sys_mkdir ++ .quad sys_rmdir /* 40 */ ++ .quad sys_dup ++ .quad sys32_pipe ++ .quad compat_sys_times ++ .quad quiet_ni_syscall /* old prof syscall holder */ ++ .quad sys_brk /* 45 */ ++ .quad sys_setgid16 ++ .quad sys_getgid16 ++ .quad sys_signal ++ .quad sys_geteuid16 ++ .quad sys_getegid16 /* 50 */ ++ .quad sys_acct ++ .quad sys_umount /* new_umount */ ++ .quad quiet_ni_syscall /* old lock syscall holder */ ++ .quad compat_sys_ioctl ++ .quad compat_sys_fcntl64 /* 55 */ ++ .quad quiet_ni_syscall /* old mpx syscall holder */ ++ .quad sys_setpgid ++ .quad quiet_ni_syscall /* old ulimit syscall holder */ ++ .quad sys32_olduname ++ .quad sys_umask /* 60 */ ++ .quad sys_chroot ++ .quad sys32_ustat ++ .quad sys_dup2 ++ .quad sys_getppid ++ .quad sys_getpgrp /* 65 */ ++ .quad sys_setsid ++ .quad sys32_sigaction ++ .quad sys_sgetmask ++ .quad sys_ssetmask ++ .quad sys_setreuid16 /* 70 */ ++ .quad sys_setregid16 ++ .quad stub32_sigsuspend ++ .quad compat_sys_sigpending ++ .quad sys_sethostname ++ .quad compat_sys_setrlimit /* 75 */ ++ .quad compat_sys_old_getrlimit /* old_getrlimit */ ++ .quad compat_sys_getrusage ++ .quad sys32_gettimeofday ++ .quad sys32_settimeofday ++ .quad sys_getgroups16 /* 80 */ ++ .quad sys_setgroups16 ++ .quad sys32_old_select ++ .quad sys_symlink ++ .quad sys_lstat ++ .quad sys_readlink /* 85 */ ++#ifdef CONFIG_IA32_AOUT ++ .quad sys_uselib ++#else ++ .quad quiet_ni_syscall ++#endif ++ .quad sys_swapon ++ .quad sys_reboot ++ .quad compat_sys_old_readdir ++ .quad sys32_mmap /* 90 */ ++ .quad sys_munmap ++ .quad sys_truncate ++ .quad sys_ftruncate ++ .quad sys_fchmod ++ .quad sys_fchown16 /* 95 */ ++ .quad sys_getpriority ++ .quad sys_setpriority ++ .quad quiet_ni_syscall /* old profil syscall holder */ ++ .quad compat_sys_statfs ++ .quad compat_sys_fstatfs /* 100 */ ++ .quad sys_ioperm ++ .quad compat_sys_socketcall ++ .quad sys_syslog ++ .quad compat_sys_setitimer ++ .quad compat_sys_getitimer /* 105 */ ++ .quad compat_sys_newstat ++ .quad compat_sys_newlstat ++ .quad compat_sys_newfstat ++ .quad sys32_uname ++ .quad stub32_iopl /* 110 */ ++ .quad sys_vhangup ++ .quad quiet_ni_syscall /* old "idle" system call */ ++ .quad sys32_vm86_warning /* vm86old */ ++ .quad compat_sys_wait4 ++ .quad sys_swapoff /* 115 */ ++ .quad sys32_sysinfo ++ .quad sys32_ipc ++ .quad sys_fsync ++ .quad stub32_sigreturn ++ .quad stub32_clone /* 120 */ ++ .quad sys_setdomainname ++ .quad sys_uname ++ .quad sys_modify_ldt ++ .quad compat_sys_adjtimex ++ .quad sys32_mprotect /* 125 */ ++ .quad compat_sys_sigprocmask ++ .quad quiet_ni_syscall /* create_module */ ++ .quad sys_init_module ++ .quad sys_delete_module ++ .quad quiet_ni_syscall /* 130 get_kernel_syms */ ++ .quad sys_quotactl ++ .quad sys_getpgid ++ .quad sys_fchdir ++ .quad quiet_ni_syscall /* bdflush */ ++ .quad sys_sysfs /* 135 */ ++ .quad sys_personality ++ .quad quiet_ni_syscall /* for afs_syscall */ ++ .quad sys_setfsuid16 ++ .quad sys_setfsgid16 ++ .quad sys_llseek /* 140 */ ++ .quad compat_sys_getdents ++ .quad compat_sys_select ++ .quad sys_flock ++ .quad sys_msync ++ .quad compat_sys_readv /* 145 */ ++ .quad compat_sys_writev ++ .quad sys_getsid ++ .quad sys_fdatasync ++ .quad sys32_sysctl /* sysctl */ ++ .quad sys_mlock /* 150 */ ++ .quad sys_munlock ++ .quad sys_mlockall ++ .quad sys_munlockall ++ .quad sys_sched_setparam ++ .quad sys_sched_getparam /* 155 */ ++ .quad sys_sched_setscheduler ++ .quad sys_sched_getscheduler ++ .quad sys_sched_yield ++ .quad sys_sched_get_priority_max ++ .quad sys_sched_get_priority_min /* 160 */ ++ .quad sys_sched_rr_get_interval ++ .quad compat_sys_nanosleep ++ .quad sys_mremap ++ .quad sys_setresuid16 ++ .quad sys_getresuid16 /* 165 */ ++ .quad sys32_vm86_warning /* vm86 */ ++ .quad quiet_ni_syscall /* query_module */ ++ .quad sys_poll ++ .quad compat_sys_nfsservctl ++ .quad sys_setresgid16 /* 170 */ ++ .quad sys_getresgid16 ++ .quad sys_prctl ++ .quad stub32_rt_sigreturn ++ .quad sys32_rt_sigaction ++ .quad sys32_rt_sigprocmask /* 175 */ ++ .quad sys32_rt_sigpending ++ .quad compat_sys_rt_sigtimedwait ++ .quad sys32_rt_sigqueueinfo ++ .quad stub32_rt_sigsuspend ++ .quad sys32_pread /* 180 */ ++ .quad sys32_pwrite ++ .quad sys_chown16 ++ .quad sys_getcwd ++ .quad sys_capget ++ .quad sys_capset ++ .quad stub32_sigaltstack ++ .quad sys32_sendfile ++ .quad quiet_ni_syscall /* streams1 */ ++ .quad quiet_ni_syscall /* streams2 */ ++ .quad stub32_vfork /* 190 */ ++ .quad compat_sys_getrlimit ++ .quad sys32_mmap2 ++ .quad sys32_truncate64 ++ .quad sys32_ftruncate64 ++ .quad sys32_stat64 /* 195 */ ++ .quad sys32_lstat64 ++ .quad sys32_fstat64 ++ .quad sys_lchown ++ .quad sys_getuid ++ .quad sys_getgid /* 200 */ ++ .quad sys_geteuid ++ .quad sys_getegid ++ .quad sys_setreuid ++ .quad sys_setregid ++ .quad sys_getgroups /* 205 */ ++ .quad sys_setgroups ++ .quad sys_fchown ++ .quad sys_setresuid ++ .quad sys_getresuid ++ .quad sys_setresgid /* 210 */ ++ .quad sys_getresgid ++ .quad sys_chown ++ .quad sys_setuid ++ .quad sys_setgid ++ .quad sys_setfsuid /* 215 */ ++ .quad sys_setfsgid ++ .quad sys_pivot_root ++ .quad sys_mincore ++ .quad sys_madvise ++ .quad compat_sys_getdents64 /* 220 getdents64 */ ++ .quad compat_sys_fcntl64 ++ .quad quiet_ni_syscall /* tux */ ++ .quad quiet_ni_syscall /* security */ ++ .quad sys_gettid ++ .quad sys_readahead /* 225 */ ++ .quad sys_setxattr ++ .quad sys_lsetxattr ++ .quad sys_fsetxattr ++ .quad sys_getxattr ++ .quad sys_lgetxattr /* 230 */ ++ .quad sys_fgetxattr ++ .quad sys_listxattr ++ .quad sys_llistxattr ++ .quad sys_flistxattr ++ .quad sys_removexattr /* 235 */ ++ .quad sys_lremovexattr ++ .quad sys_fremovexattr ++ .quad sys_tkill ++ .quad sys_sendfile64 ++ .quad compat_sys_futex /* 240 */ ++ .quad compat_sys_sched_setaffinity ++ .quad compat_sys_sched_getaffinity ++ .quad sys32_set_thread_area ++ .quad sys32_get_thread_area ++ .quad compat_sys_io_setup /* 245 */ ++ .quad sys_io_destroy ++ .quad compat_sys_io_getevents ++ .quad compat_sys_io_submit ++ .quad sys_io_cancel ++ .quad sys_fadvise64 /* 250 */ ++ .quad quiet_ni_syscall /* free_huge_pages */ ++ .quad sys_exit_group ++ .quad sys32_lookup_dcookie ++ .quad sys_epoll_create ++ .quad sys_epoll_ctl /* 255 */ ++ .quad sys_epoll_wait ++ .quad sys_remap_file_pages ++ .quad sys_set_tid_address ++ .quad compat_sys_timer_create ++ .quad compat_sys_timer_settime /* 260 */ ++ .quad compat_sys_timer_gettime ++ .quad sys_timer_getoverrun ++ .quad sys_timer_delete ++ .quad compat_sys_clock_settime ++ .quad compat_sys_clock_gettime /* 265 */ ++ .quad compat_sys_clock_getres ++ .quad compat_sys_clock_nanosleep ++ .quad compat_sys_statfs64 ++ .quad compat_sys_fstatfs64 ++ .quad sys_tgkill /* 270 */ ++ .quad compat_sys_utimes ++ .quad sys32_fadvise64_64 ++ .quad quiet_ni_syscall /* sys_vserver */ ++ .quad sys_mbind ++ .quad compat_sys_get_mempolicy /* 275 */ ++ .quad sys_set_mempolicy ++ .quad compat_sys_mq_open ++ .quad sys_mq_unlink ++ .quad compat_sys_mq_timedsend ++ .quad compat_sys_mq_timedreceive /* 280 */ ++ .quad compat_sys_mq_notify ++ .quad compat_sys_mq_getsetattr ++ .quad compat_sys_kexec_load /* reserved for kexec */ ++ .quad compat_sys_waitid ++ .quad quiet_ni_syscall /* 285: sys_altroot */ ++ .quad sys_add_key ++ .quad sys_request_key ++ .quad sys_keyctl ++ .quad sys_ioprio_set ++ .quad sys_ioprio_get /* 290 */ ++ .quad sys_inotify_init ++ .quad sys_inotify_add_watch ++ .quad sys_inotify_rm_watch ++ .quad sys_migrate_pages ++ .quad compat_sys_openat /* 295 */ ++ .quad sys_mkdirat ++ .quad sys_mknodat ++ .quad sys_fchownat ++ .quad compat_sys_futimesat ++ .quad sys32_fstatat /* 300 */ ++ .quad sys_unlinkat ++ .quad sys_renameat ++ .quad sys_linkat ++ .quad sys_symlinkat ++ .quad sys_readlinkat /* 305 */ ++ .quad sys_fchmodat ++ .quad sys_faccessat ++ .quad compat_sys_pselect6 ++ .quad compat_sys_ppoll ++ .quad sys_unshare /* 310 */ ++ .quad compat_sys_set_robust_list ++ .quad compat_sys_get_robust_list ++ .quad sys_splice ++ .quad sys_sync_file_range ++ .quad sys_tee ++ .quad compat_sys_vmsplice ++ .quad compat_sys_move_pages ++ .quad sys_getcpu ++ia32_syscall_end: +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/ia32/syscall32.c +--- a/arch/x86_64/ia32/syscall32.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/ia32/syscall32.c Wed Aug 08 16:25:28 2007 -0300 +@@ -14,12 +14,17 @@ + #include <asm/tlbflush.h> + #include <asm/ia32_unistd.h> + ++#ifdef USE_INT80 ++extern unsigned char syscall32_int80[], syscall32_int80_end[]; ++#endif + extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; + extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; + extern int sysctl_vsyscall32; + + char *syscall32_page; ++#ifndef USE_INT80 + static int use_sysenter = -1; ++#endif + + static struct page * + syscall32_nopage(struct vm_area_struct *vma, unsigned long adr, int *type) +@@ -95,6 +100,14 @@ static int __init init_syscall32(void) + syscall32_page = (void *)get_zeroed_page(GFP_KERNEL); + if (!syscall32_page) + panic("Cannot allocate syscall32 page"); ++ ++#ifdef USE_INT80 ++ /* ++ * At this point we use int 0x80. ++ */ ++ memcpy(syscall32_page, syscall32_int80, ++ syscall32_int80_end - syscall32_int80); ++#else + if (use_sysenter > 0) { + memcpy(syscall32_page, syscall32_sysenter, + syscall32_sysenter_end - syscall32_sysenter); +@@ -102,14 +115,20 @@ static int __init init_syscall32(void) + memcpy(syscall32_page, syscall32_syscall, + syscall32_syscall_end - syscall32_syscall); + } ++#endif + return 0; + } +- +-__initcall(init_syscall32); ++ ++/* ++ * This must be done early in case we have an initrd containing 32-bit ++ * binaries (e.g., hotplug). This could be pushed upstream to arch/x86_64. ++ */ ++core_initcall(init_syscall32); + + /* May not be __init: called during resume */ + void syscall32_cpu_init(void) + { ++#ifndef USE_INT80 + if (use_sysenter < 0) + use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); + +@@ -120,4 +139,5 @@ void syscall32_cpu_init(void) + checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); + + wrmsrl(MSR_CSTAR, ia32_cstar_target); ++#endif + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/ia32/syscall32_syscall.S +--- a/arch/x86_64/ia32/syscall32_syscall.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/ia32/syscall32_syscall.S Wed Aug 08 16:25:28 2007 -0300 +@@ -1,6 +1,17 @@ + /* 32bit VDSOs mapped into user space. */ + + .section ".init.data","aw" ++ ++#ifdef USE_INT80 ++ ++ .globl syscall32_int80 ++ .globl syscall32_int80_end ++ ++syscall32_int80: ++ .incbin "arch/x86_64/ia32/vsyscall-int80.so" ++syscall32_int80_end: ++ ++#endif + + .globl syscall32_syscall + .globl syscall32_syscall_end +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/ia32/vsyscall-int80.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/ia32/vsyscall-int80.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,58 @@ ++/* ++ * Code for the vsyscall page. This version uses the old int $0x80 method. ++ * ++ * NOTE: ++ * 1) __kernel_vsyscall _must_ be first in this page. ++ * 2) there are alignment constraints on this stub, see vsyscall-sigreturn.S ++ * for details. ++ */ ++#include <asm/ia32_unistd.h> ++#include <asm/asm-offsets.h> ++ ++ .code32 ++ .text ++ .section .text.vsyscall,"ax" ++ .globl __kernel_vsyscall ++ .type __kernel_vsyscall,@function ++__kernel_vsyscall: ++.LSTART_vsyscall: ++ int $0x80 ++ ret ++.LEND_vsyscall: ++ .size __kernel_vsyscall,.-.LSTART_vsyscall ++ .previous ++ ++ .section .eh_frame,"a",@progbits ++.LSTARTFRAME: ++ .long .LENDCIE-.LSTARTCIE ++.LSTARTCIE: ++ .long 0 /* CIE ID */ ++ .byte 1 /* Version number */ ++ .string "zR" /* NUL-terminated augmentation string */ ++ .uleb128 1 /* Code alignment factor */ ++ .sleb128 -4 /* Data alignment factor */ ++ .byte 8 /* Return address register column */ ++ .uleb128 1 /* Augmentation value length */ ++ .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ ++ .byte 0x0c /* DW_CFA_def_cfa */ ++ .uleb128 4 ++ .uleb128 4 ++ .byte 0x88 /* DW_CFA_offset, column 0x8 */ ++ .uleb128 1 ++ .align 4 ++.LENDCIE: ++ ++ .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */ ++.LSTARTFDE1: ++ .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */ ++ .long .LSTART_vsyscall-. /* PC-relative start address */ ++ .long .LEND_vsyscall-.LSTART_vsyscall ++ .uleb128 0 /* Augmentation length */ ++ .align 4 ++.LENDFDE1: ++ ++/* ++ * Get the common code for the sigreturn entry points. ++ */ ++#define SYSCALL_ENTER_KERNEL int $0x80 ++#include "vsyscall-sigreturn.S" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/Makefile +--- a/arch/x86_64/kernel/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -21,11 +21,13 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o + obj-$(CONFIG_X86_CPUID) += cpuid.o + obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o + obj-y += apic.o nmi.o ++obj-$(CONFIG_X86_XEN_GENAPIC) += genapic.o genapic_xen.o + obj-y += io_apic.o mpparse.o \ + genapic.o genapic_cluster.o genapic_flat.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o + obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +-obj-$(CONFIG_PM) += suspend.o ++obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o ++obj-$(CONFIG_ACPI_SLEEP) += suspend.o + obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +@@ -56,3 +58,17 @@ i8237-y += ../../i386/kernel/i8237.o + i8237-y += ../../i386/kernel/i8237.o + msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o + alternative-y += ../../i386/kernel/alternative.o ++ ++ifdef CONFIG_XEN ++pci-dma-y += ../../i386/kernel/pci-dma-xen.o ++microcode-$(subst m,y,$(CONFIG_MICROCODE)) := ../../i386/kernel/microcode-xen.o ++ ++n-obj-xen := i8259.o reboot.o i8237.o smpboot.o trampoline.o ++ ++include $(srctree)/scripts/Makefile.xen ++ ++obj-y := $(call filterxen, $(obj-y), $(n-obj-xen)) ++obj-y := $(call cherrypickxen, $(obj-y)) ++extra-y := $(call cherrypickxen, $(extra-y)) ++%/head-xen.o %/head-xen.s: EXTRA_AFLAGS := ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/apic-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/apic-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,254 @@ ++/* ++ * Local APIC handling, local APIC timers ++ * ++ * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com> ++ * ++ * Fixes ++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs; ++ * thanks to Eric Gilmore ++ * and Rolf G. Tews ++ * for testing these extensively. ++ * Maciej W. Rozycki : Various updates and fixes. ++ * Mikael Pettersson : Power Management for UP-APIC. ++ * Pavel Machek and ++ * Mikael Pettersson : PM converted to driver model. ++ */ ++ ++#include <linux/init.h> ++ ++#include <linux/mm.h> ++#include <linux/delay.h> ++#include <linux/bootmem.h> ++#include <linux/smp_lock.h> ++#include <linux/interrupt.h> ++#include <linux/mc146818rtc.h> ++#include <linux/kernel_stat.h> ++#include <linux/sysdev.h> ++#include <linux/module.h> ++#include <linux/ioport.h> ++ ++#include <asm/atomic.h> ++#include <asm/smp.h> ++#include <asm/mtrr.h> ++#include <asm/mpspec.h> ++#include <asm/pgalloc.h> ++#include <asm/mach_apic.h> ++#include <asm/nmi.h> ++#include <asm/idle.h> ++#include <asm/proto.h> ++#include <asm/timex.h> ++#include <asm/apic.h> ++ ++int apic_mapped; ++int apic_verbosity; ++ ++/* ++ * 'what should we do if we get a hw irq event on an illegal vector'. ++ * each architecture has to answer this themselves. ++ */ ++void ack_bad_irq(unsigned int irq) ++{ ++ printk("unexpected IRQ trap at vector %02x\n", irq); ++ /* ++ * Currently unexpected vectors happen only on SMP and APIC. ++ * We _must_ ack these because every local APIC has only N ++ * irq slots per priority level, and a 'hanging, unacked' IRQ ++ * holds up an irq slot - in excessive cases (when multiple ++ * unexpected vectors occur) that might lock up the APIC ++ * completely. ++ * But don't ack when the APIC is disabled. -AK ++ */ ++ if (!disable_apic) ++ ack_APIC_irq(); ++} ++ ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ return -EINVAL; ++} ++ ++void smp_local_timer_interrupt(void) ++{ ++ profile_tick(CPU_PROFILING); ++#ifndef CONFIG_XEN ++#ifdef CONFIG_SMP ++ update_process_times(user_mode(get_irq_regs())); ++#endif ++ if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) ++ main_timer_handler(); ++#endif ++ /* ++ * We take the 'long' return path, and there every subsystem ++ * grabs the appropriate locks (kernel lock/ irq lock). ++ * ++ * We might want to decouple profiling from the 'long path', ++ * and do the profiling totally in assembly. ++ * ++ * Currently this isn't too much of an issue (performance wise), ++ * we can take more than 100K local irqs per second on a 100 MHz P5. ++ */ ++} ++ ++/* ++ * Local APIC timer interrupt. This is the most natural way for doing ++ * local interrupts, but local timer interrupts can be emulated by ++ * broadcast interrupts too. [in case the hw doesn't support APIC timers] ++ * ++ * [ if a single-CPU system runs an SMP kernel then we call the local ++ * interrupt as well. Thus we cannot inline the local irq ... ] ++ */ ++void smp_apic_timer_interrupt(struct pt_regs *regs) ++{ ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ ++ /* ++ * the NMI deadlock-detector uses this. ++ */ ++ add_pda(apic_timer_irqs, 1); ++ ++ /* ++ * NOTE! We'd better ACK the irq immediately, ++ * because timer handling can be slow. ++ */ ++ ack_APIC_irq(); ++ /* ++ * update_process_times() expects us to have done irq_enter(). ++ * Besides, if we don't timer interrupts ignore the global ++ * interrupt lock, which is the WrongThing (tm) to do. ++ */ ++ exit_idle(); ++ irq_enter(); ++ smp_local_timer_interrupt(); ++ irq_exit(); ++ set_irq_regs(old_regs); ++} ++ ++/* ++ * This interrupt should _never_ happen with our APIC/SMP architecture ++ */ ++asmlinkage void smp_spurious_interrupt(void) ++{ ++ unsigned int v; ++ exit_idle(); ++ irq_enter(); ++ /* ++ * Check if this really is a spurious interrupt and ACK it ++ * if it is a vectored one. Just in case... ++ * Spurious interrupts should not be ACKed. ++ */ ++ v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1)); ++ if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) ++ ack_APIC_irq(); ++ ++#if 0 ++ static unsigned long last_warning; ++ static unsigned long skipped; ++ ++ /* see sw-dev-man vol 3, chapter 7.4.13.5 */ ++ if (time_before(last_warning+30*HZ,jiffies)) { ++ printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n", ++ smp_processor_id(), skipped); ++ last_warning = jiffies; ++ skipped = 0; ++ } else { ++ skipped++; ++ } ++#endif ++ irq_exit(); ++} ++ ++/* ++ * This interrupt should never happen with our APIC/SMP architecture ++ */ ++ ++asmlinkage void smp_error_interrupt(void) ++{ ++ unsigned int v, v1; ++ ++ exit_idle(); ++ irq_enter(); ++ /* First tickle the hardware, only then report what went on. -- REW */ ++ v = apic_read(APIC_ESR); ++ apic_write(APIC_ESR, 0); ++ v1 = apic_read(APIC_ESR); ++ ack_APIC_irq(); ++ atomic_inc(&irq_err_count); ++ ++ /* Here is what the APIC error bits mean: ++ 0: Send CS error ++ 1: Receive CS error ++ 2: Send accept error ++ 3: Receive accept error ++ 4: Reserved ++ 5: Send illegal vector ++ 6: Received illegal vector ++ 7: Illegal register address ++ */ ++ printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", ++ smp_processor_id(), v , v1); ++ irq_exit(); ++} ++ ++int disable_apic; ++ ++/* ++ * This initializes the IO-APIC and APIC hardware if this is ++ * a UP kernel. ++ */ ++int __init APIC_init_uniprocessor (void) ++{ ++ if (smp_found_config && !skip_ioapic_setup && nr_ioapics) ++ setup_IO_APIC(); ++ return 0; ++} ++ ++#ifndef CONFIG_XEN ++static __init int setup_disableapic(char *str) ++{ ++ disable_apic = 1; ++ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); ++ return 0; ++} ++early_param("disableapic", setup_disableapic); ++ ++/* same as disableapic, for compatibility */ ++static __init int setup_nolapic(char *str) ++{ ++ return setup_disableapic(str); ++} ++early_param("nolapic", setup_nolapic); ++ ++static __init int setup_noapictimer(char *str) ++{ ++ if (str[0] != ' ' && str[0] != 0) ++ return 0; ++ disable_apic_timer = 1; ++ return 1; ++} ++ ++static __init int setup_apicmaintimer(char *str) ++{ ++ apic_runs_main_timer = 1; ++ nohpet = 1; ++ return 1; ++} ++__setup("apicmaintimer", setup_apicmaintimer); ++ ++static __init int setup_noapicmaintimer(char *str) ++{ ++ apic_runs_main_timer = -1; ++ return 1; ++} ++__setup("noapicmaintimer", setup_noapicmaintimer); ++ ++static __init int setup_apicpmtimer(char *s) ++{ ++ apic_calibrate_pmtmr = 1; ++ notsc_setup(NULL); ++ return setup_apicmaintimer(NULL); ++} ++__setup("apicpmtimer", setup_apicpmtimer); ++ ++__setup("noapictimer", setup_noapictimer); ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/asm-offsets.c +--- a/arch/x86_64/kernel/asm-offsets.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/asm-offsets.c Wed Aug 08 16:25:28 2007 -0300 +@@ -67,8 +67,10 @@ int main(void) + DEFINE(pbe_address, offsetof(struct pbe, address)); + DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); + DEFINE(pbe_next, offsetof(struct pbe, next)); ++#ifndef CONFIG_X86_NO_TSS + BLANK(); + DEFINE(TSS_ist, offsetof(struct tss_struct, ist)); ++#endif + BLANK(); + DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); + return 0; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/crash.c +--- a/arch/x86_64/kernel/crash.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/crash.c Wed Aug 08 16:25:28 2007 -0300 +@@ -28,6 +28,7 @@ + /* This keeps a track of which one is crashing cpu. */ + static int crashing_cpu; + ++#ifndef CONFIG_XEN + #ifdef CONFIG_SMP + static atomic_t waiting_for_crash_ipi; + +@@ -107,6 +108,7 @@ static void nmi_shootdown_cpus(void) + /* There are no cpus to shootdown */ + } + #endif ++#endif /* CONFIG_XEN */ + + void machine_crash_shutdown(struct pt_regs *regs) + { +@@ -124,12 +126,14 @@ void machine_crash_shutdown(struct pt_re + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); ++ ++#ifndef CONFIG_XEN + nmi_shootdown_cpus(); + + if(cpu_has_apic) + disable_local_APIC(); + + disable_IO_APIC(); +- ++#endif /* CONFIG_XEN */ + crash_save_cpu(regs, smp_processor_id()); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/e820-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/e820-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,773 @@ ++/* ++ * Handle the memory map. ++ * The functions here do the job until bootmem takes over. ++ * ++ * Getting sanitize_e820_map() in sync with i386 version by applying change: ++ * - Provisions for empty E820 memory regions (reported by certain BIOSes). ++ * Alex Achenbach <xela@slit.de>, December 2002. ++ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/bootmem.h> ++#include <linux/ioport.h> ++#include <linux/string.h> ++#include <linux/kexec.h> ++#include <linux/module.h> ++#include <linux/mm.h> ++ ++#include <asm/pgtable.h> ++#include <asm/page.h> ++#include <asm/e820.h> ++#include <asm/proto.h> ++#include <asm/bootsetup.h> ++#include <asm/sections.h> ++#include <xen/interface/memory.h> ++ ++struct e820map e820 __initdata; ++ ++/* ++ * PFN of last memory page. ++ */ ++unsigned long end_pfn; ++EXPORT_SYMBOL(end_pfn); ++ ++/* ++ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries. ++ * The direct mapping extends to end_pfn_map, so that we can directly access ++ * apertures, ACPI and other tables without having to play with fixmaps. ++ */ ++unsigned long end_pfn_map; ++ ++/* ++ * Last pfn which the user wants to use. ++ */ ++static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; ++ ++extern struct resource code_resource, data_resource; ++ ++/* Check for some hardcoded bad areas that early boot is not allowed to touch */ ++static inline int bad_addr(unsigned long *addrp, unsigned long size) ++{ ++ unsigned long addr = *addrp, last = addr + size; ++ ++#ifndef CONFIG_XEN ++ /* various gunk below that needed for SMP startup */ ++ if (addr < 0x8000) { ++ *addrp = PAGE_ALIGN(0x8000); ++ return 1; ++ } ++ ++ /* direct mapping tables of the kernel */ ++ if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { ++ *addrp = PAGE_ALIGN(table_end << PAGE_SHIFT); ++ return 1; ++ } ++ ++ /* initrd */ ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (LOADER_TYPE && INITRD_START && last >= INITRD_START && ++ addr < INITRD_START+INITRD_SIZE) { ++ *addrp = PAGE_ALIGN(INITRD_START + INITRD_SIZE); ++ return 1; ++ } ++#endif ++ /* kernel code */ ++ if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) { ++ *addrp = PAGE_ALIGN(__pa_symbol(&_end)); ++ return 1; ++ } ++ ++ if (last >= ebda_addr && addr < ebda_addr + ebda_size) { ++ *addrp = PAGE_ALIGN(ebda_addr + ebda_size); ++ return 1; ++ } ++ ++ /* XXX ramdisk image here? */ ++#else ++ if (last < (table_end<<PAGE_SHIFT)) { ++ *addrp = table_end << PAGE_SHIFT; ++ return 1; ++ } ++#endif ++ return 0; ++} ++ ++/* ++ * This function checks if any part of the range <start,end> is mapped ++ * with type. ++ */ ++int __meminit ++e820_any_mapped(unsigned long start, unsigned long end, unsigned type) ++{ ++ int i; ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ if (type && ei->type != type) ++ continue; ++ if (ei->addr >= end || ei->addr + ei->size <= start) ++ continue; ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * This function checks if the entire range <start,end> is mapped with type. ++ * ++ * Note: this function only works correct if the e820 table is sorted and ++ * not-overlapping, which is the case ++ */ ++int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type) ++{ ++ int i; ++ ++#ifndef CONFIG_XEN ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++#else ++ extern struct e820map machine_e820; ++ ++ if (!is_initial_xendomain()) ++ return 0; ++ for (i = 0; i < machine_e820.nr_map; i++) { ++ const struct e820entry *ei = &machine_e820.map[i]; ++#endif ++ ++ if (type && ei->type != type) ++ continue; ++ /* is the region (part) in overlap with the current region ?*/ ++ if (ei->addr >= end || ei->addr + ei->size <= start) ++ continue; ++ ++ /* if the region is at the beginning of <start,end> we move ++ * start to the end of the region since it's ok until there ++ */ ++ if (ei->addr <= start) ++ start = ei->addr + ei->size; ++ /* if start is now at or beyond end, we're done, full coverage */ ++ if (start >= end) ++ return 1; /* we're done */ ++ } ++ return 0; ++} ++ ++/* ++ * Find a free area in a specific range. ++ */ ++unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) ++{ ++ int i; ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ unsigned long addr = ei->addr, last; ++ if (ei->type != E820_RAM) ++ continue; ++ if (addr < start) ++ addr = start; ++ if (addr > ei->addr + ei->size) ++ continue; ++ while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size) ++ ; ++ last = PAGE_ALIGN(addr) + size; ++ if (last > ei->addr + ei->size) ++ continue; ++ if (last > end) ++ continue; ++ return addr; ++ } ++ return -1UL; ++} ++ ++/* ++ * Find the highest page frame number we have available ++ */ ++unsigned long __init e820_end_of_ram(void) ++{ ++ unsigned long end_pfn = 0; ++ end_pfn = find_max_pfn_with_active_regions(); ++ ++ if (end_pfn > end_pfn_map) ++ end_pfn_map = end_pfn; ++ if (end_pfn_map > MAXMEM>>PAGE_SHIFT) ++ end_pfn_map = MAXMEM>>PAGE_SHIFT; ++ if (end_pfn > end_user_pfn) ++ end_pfn = end_user_pfn; ++ if (end_pfn > end_pfn_map) ++ end_pfn = end_pfn_map; ++ ++ printk("end_pfn_map = %lu\n", end_pfn_map); ++ return end_pfn; ++} ++ ++/* ++ * Mark e820 reserved areas as busy for the resource manager. ++ */ ++void __init e820_reserve_resources(struct e820entry *e820, int nr_map) ++{ ++ int i; ++ for (i = 0; i < nr_map; i++) { ++ struct resource *res; ++ res = alloc_bootmem_low(sizeof(struct resource)); ++ switch (e820[i].type) { ++ case E820_RAM: res->name = "System RAM"; break; ++ case E820_ACPI: res->name = "ACPI Tables"; break; ++ case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; ++ default: res->name = "reserved"; ++ } ++ res->start = e820[i].addr; ++ res->end = res->start + e820[i].size - 1; ++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; ++ request_resource(&iomem_resource, res); ++ if (e820[i].type == E820_RAM) { ++ /* ++ * We don't know which RAM region contains kernel data, ++ * so we try it repeatedly and let the resource manager ++ * test it. ++ */ ++#ifndef CONFIG_XEN ++ request_resource(res, &code_resource); ++ request_resource(res, &data_resource); ++#endif ++#ifdef CONFIG_KEXEC ++ if (crashk_res.start != crashk_res.end) ++ request_resource(res, &crashk_res); ++#ifdef CONFIG_XEN ++ xen_machine_kexec_register_resources(res); ++#endif ++#endif ++ } ++ } ++} ++ ++/* Mark pages corresponding to given address range as nosave */ ++static void __init ++e820_mark_nosave_range(unsigned long start, unsigned long end) ++{ ++ unsigned long pfn, max_pfn; ++ ++ if (start >= end) ++ return; ++ ++ printk("Nosave address range: %016lx - %016lx\n", start, end); ++ max_pfn = end >> PAGE_SHIFT; ++ for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++) ++ if (pfn_valid(pfn)) ++ SetPageNosave(pfn_to_page(pfn)); ++} ++ ++/* ++ * Find the ranges of physical addresses that do not correspond to ++ * e820 RAM areas and mark the corresponding pages as nosave for software ++ * suspend and suspend to RAM. ++ * ++ * This function requires the e820 map to be sorted and without any ++ * overlapping entries and assumes the first e820 area to be RAM. ++ */ ++void __init e820_mark_nosave_regions(void) ++{ ++ int i; ++ unsigned long paddr; ++ ++ paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE); ++ for (i = 1; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ ++ if (paddr < ei->addr) ++ e820_mark_nosave_range(paddr, ++ round_up(ei->addr, PAGE_SIZE)); ++ ++ paddr = round_down(ei->addr + ei->size, PAGE_SIZE); ++ if (ei->type != E820_RAM) ++ e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE), ++ paddr); ++ ++ if (paddr >= (end_pfn << PAGE_SHIFT)) ++ break; ++ } ++} ++ ++/* Walk the e820 map and register active regions within a node */ ++void __init ++e820_register_active_regions(int nid, unsigned long start_pfn, ++ unsigned long end_pfn) ++{ ++ int i; ++ unsigned long ei_startpfn, ei_endpfn; ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; ++ ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) ++ >> PAGE_SHIFT; ++ ++ /* Skip map entries smaller than a page */ ++ if (ei_startpfn >= ei_endpfn) ++ continue; ++ ++ /* Check if end_pfn_map should be updated */ ++ if (ei->type != E820_RAM && ei_endpfn > end_pfn_map) ++ end_pfn_map = ei_endpfn; ++ ++ /* Skip if map is outside the node */ ++ if (ei->type != E820_RAM || ++ ei_endpfn <= start_pfn || ++ ei_startpfn >= end_pfn) ++ continue; ++ ++ /* Check for overlaps */ ++ if (ei_startpfn < start_pfn) ++ ei_startpfn = start_pfn; ++ if (ei_endpfn > end_pfn) ++ ei_endpfn = end_pfn; ++ ++ /* Obey end_user_pfn to save on memmap */ ++ if (ei_startpfn >= end_user_pfn) ++ continue; ++ if (ei_endpfn > end_user_pfn) ++ ei_endpfn = end_user_pfn; ++ ++ add_active_range(nid, ei_startpfn, ei_endpfn); ++ } ++} ++ ++/* ++ * Add a memory region to the kernel e820 map. ++ */ ++void __init add_memory_region(unsigned long start, unsigned long size, int type) ++{ ++ int x = e820.nr_map; ++ ++ if (x == E820MAX) { ++ printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); ++ return; ++ } ++ ++ e820.map[x].addr = start; ++ e820.map[x].size = size; ++ e820.map[x].type = type; ++ e820.nr_map++; ++} ++ ++void __init e820_print_map(char *who) ++{ ++ int i; ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ printk(" %s: %016Lx - %016Lx ", who, ++ (unsigned long long) e820.map[i].addr, ++ (unsigned long long) (e820.map[i].addr + e820.map[i].size)); ++ switch (e820.map[i].type) { ++ case E820_RAM: printk("(usable)\n"); ++ break; ++ case E820_RESERVED: ++ printk("(reserved)\n"); ++ break; ++ case E820_ACPI: ++ printk("(ACPI data)\n"); ++ break; ++ case E820_NVS: ++ printk("(ACPI NVS)\n"); ++ break; ++ default: printk("type %u\n", e820.map[i].type); ++ break; ++ } ++ } ++} ++ ++/* ++ * Sanitize the BIOS e820 map. ++ * ++ * Some e820 responses include overlapping entries. The following ++ * replaces the original e820 map with a new one, removing overlaps. ++ * ++ */ ++static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) ++{ ++ struct change_member { ++ struct e820entry *pbios; /* pointer to original bios entry */ ++ unsigned long long addr; /* address for this change point */ ++ }; ++ static struct change_member change_point_list[2*E820MAX] __initdata; ++ static struct change_member *change_point[2*E820MAX] __initdata; ++ static struct e820entry *overlap_list[E820MAX] __initdata; ++ static struct e820entry new_bios[E820MAX] __initdata; ++ struct change_member *change_tmp; ++ unsigned long current_type, last_type; ++ unsigned long long last_addr; ++ int chgidx, still_changing; ++ int overlap_entries; ++ int new_bios_entry; ++ int old_nr, new_nr, chg_nr; ++ int i; ++ ++ /* ++ Visually we're performing the following (1,2,3,4 = memory types)... ++ ++ Sample memory map (w/overlaps): ++ ____22__________________ ++ ______________________4_ ++ ____1111________________ ++ _44_____________________ ++ 11111111________________ ++ ____________________33__ ++ ___________44___________ ++ __________33333_________ ++ ______________22________ ++ ___________________2222_ ++ _________111111111______ ++ _____________________11_ ++ _________________4______ ++ ++ Sanitized equivalent (no overlap): ++ 1_______________________ ++ _44_____________________ ++ ___1____________________ ++ ____22__________________ ++ ______11________________ ++ _________1______________ ++ __________3_____________ ++ ___________44___________ ++ _____________33_________ ++ _______________2________ ++ ________________1_______ ++ _________________4______ ++ ___________________2____ ++ ____________________33__ ++ ______________________4_ ++ */ ++ ++ /* if there's only one memory region, don't bother */ ++ if (*pnr_map < 2) ++ return -1; ++ ++ old_nr = *pnr_map; ++ ++ /* bail out if we find any unreasonable addresses in bios map */ ++ for (i=0; i<old_nr; i++) ++ if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) ++ return -1; ++ ++ /* create pointers for initial change-point information (for sorting) */ ++ for (i=0; i < 2*old_nr; i++) ++ change_point[i] = &change_point_list[i]; ++ ++ /* record all known change-points (starting and ending addresses), ++ omitting those that are for empty memory regions */ ++ chgidx = 0; ++ for (i=0; i < old_nr; i++) { ++ if (biosmap[i].size != 0) { ++ change_point[chgidx]->addr = biosmap[i].addr; ++ change_point[chgidx++]->pbios = &biosmap[i]; ++ change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; ++ change_point[chgidx++]->pbios = &biosmap[i]; ++ } ++ } ++ chg_nr = chgidx; ++ ++ /* sort change-point list by memory addresses (low -> high) */ ++ still_changing = 1; ++ while (still_changing) { ++ still_changing = 0; ++ for (i=1; i < chg_nr; i++) { ++ /* if <current_addr> > <last_addr>, swap */ ++ /* or, if current=<start_addr> & last=<end_addr>, swap */ ++ if ((change_point[i]->addr < change_point[i-1]->addr) || ++ ((change_point[i]->addr == change_point[i-1]->addr) && ++ (change_point[i]->addr == change_point[i]->pbios->addr) && ++ (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) ++ ) ++ { ++ change_tmp = change_point[i]; ++ change_point[i] = change_point[i-1]; ++ change_point[i-1] = change_tmp; ++ still_changing=1; ++ } ++ } ++ } ++ ++ /* create a new bios memory map, removing overlaps */ ++ overlap_entries=0; /* number of entries in the overlap table */ ++ new_bios_entry=0; /* index for creating new bios map entries */ ++ last_type = 0; /* start with undefined memory type */ ++ last_addr = 0; /* start with 0 as last starting address */ ++ /* loop through change-points, determining affect on the new bios map */ ++ for (chgidx=0; chgidx < chg_nr; chgidx++) ++ { ++ /* keep track of all overlapping bios entries */ ++ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) ++ { ++ /* add map entry to overlap list (> 1 entry implies an overlap) */ ++ overlap_list[overlap_entries++]=change_point[chgidx]->pbios; ++ } ++ else ++ { ++ /* remove entry from list (order independent, so swap with last) */ ++ for (i=0; i<overlap_entries; i++) ++ { ++ if (overlap_list[i] == change_point[chgidx]->pbios) ++ overlap_list[i] = overlap_list[overlap_entries-1]; ++ } ++ overlap_entries--; ++ } ++ /* if there are overlapping entries, decide which "type" to use */ ++ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ ++ current_type = 0; ++ for (i=0; i<overlap_entries; i++) ++ if (overlap_list[i]->type > current_type) ++ current_type = overlap_list[i]->type; ++ /* continue building up new bios map based on this information */ ++ if (current_type != last_type) { ++ if (last_type != 0) { ++ new_bios[new_bios_entry].size = ++ change_point[chgidx]->addr - last_addr; ++ /* move forward only if the new size was non-zero */ ++ if (new_bios[new_bios_entry].size != 0) ++ if (++new_bios_entry >= E820MAX) ++ break; /* no more space left for new bios entries */ ++ } ++ if (current_type != 0) { ++ new_bios[new_bios_entry].addr = change_point[chgidx]->addr; ++ new_bios[new_bios_entry].type = current_type; ++ last_addr=change_point[chgidx]->addr; ++ } ++ last_type = current_type; ++ } ++ } ++ new_nr = new_bios_entry; /* retain count for new bios entries */ ++ ++ /* copy new bios mapping into original location */ ++ memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); ++ *pnr_map = new_nr; ++ ++ return 0; ++} ++ ++/* ++ * Copy the BIOS e820 map into a safe place. ++ * ++ * Sanity-check it while we're at it.. ++ * ++ * If we're lucky and live on a modern system, the setup code ++ * will have given us a memory map that we can use to properly ++ * set up memory. If we aren't, we'll fake a memory map. ++ */ ++static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) ++{ ++#ifndef CONFIG_XEN ++ /* Only one memory region (or negative)? Ignore it */ ++ if (nr_map < 2) ++ return -1; ++#else ++ BUG_ON(nr_map < 1); ++#endif ++ ++ do { ++ unsigned long start = biosmap->addr; ++ unsigned long size = biosmap->size; ++ unsigned long end = start + size; ++ unsigned long type = biosmap->type; ++ ++ /* Overflow in 64 bits? Ignore the memory map. */ ++ if (start > end) ++ return -1; ++ ++ add_memory_region(start, size, type); ++ } while (biosmap++,--nr_map); ++ return 0; ++} ++ ++void early_panic(char *msg) ++{ ++ early_printk(msg); ++ panic(msg); ++} ++ ++void __init setup_memory_region(void) ++{ ++#ifndef CONFIG_XEN ++ /* ++ * Try to copy the BIOS-supplied E820-map. ++ * ++ * Otherwise fake a memory map; one section from 0k->640k, ++ * the next section from 1mb->appropriate_mem_k ++ */ ++ sanitize_e820_map(E820_MAP, &E820_MAP_NR); ++ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) ++ early_panic("Cannot find a valid memory map"); ++ printk(KERN_INFO "BIOS-provided physical RAM map:\n"); ++ e820_print_map("BIOS-e820"); ++#else /* CONFIG_XEN */ ++ int rc; ++ struct xen_memory_map memmap; ++ /* ++ * This is rather large for a stack variable but this early in ++ * the boot process we know we have plenty slack space. ++ */ ++ struct e820entry map[E820MAX]; ++ ++ memmap.nr_entries = E820MAX; ++ set_xen_guest_handle(memmap.buffer, map); ++ ++ rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); ++ if ( rc == -ENOSYS ) { ++ memmap.nr_entries = 1; ++ map[0].addr = 0ULL; ++ map[0].size = xen_start_info->nr_pages << PAGE_SHIFT; ++ /* 8MB slack (to balance backend allocations). */ ++ map[0].size += 8 << 20; ++ map[0].type = E820_RAM; ++ rc = 0; ++ } ++ BUG_ON(rc); ++ ++ sanitize_e820_map(map, (char *)&memmap.nr_entries); ++ if (copy_e820_map(map, (char)memmap.nr_entries) < 0) ++ early_panic("Cannot find a valid memory map"); ++ printk(KERN_INFO "BIOS-provided physical RAM map:\n"); ++ e820_print_map("Xen"); ++#endif ++} ++ ++static int __init parse_memopt(char *p) ++{ ++ int i; ++ unsigned long current_end; ++ unsigned long end; ++ ++ if (!p) ++ return -EINVAL; ++ end_user_pfn = memparse(p, &p); ++ end_user_pfn >>= PAGE_SHIFT; ++ ++ end = end_user_pfn<<PAGE_SHIFT; ++ i = e820.nr_map-1; ++ current_end = e820.map[i].addr + e820.map[i].size; ++ ++ if (current_end < end) { ++ /* ++ * The e820 map ends before our requested size so ++ * extend the final entry to the requested address. ++ */ ++ if (e820.map[i].type == E820_RAM) ++ e820.map[i].size = end - e820.map[i].addr; ++ else ++ add_memory_region(current_end, end - current_end, E820_RAM); ++ } ++ return 0; ++} ++early_param("mem", parse_memopt); ++ ++static int userdef __initdata; ++ ++static int __init parse_memmap_opt(char *p) ++{ ++ char *oldp; ++ unsigned long long start_at, mem_size; ++ ++ if (!strcmp(p, "exactmap")) { ++#ifdef CONFIG_CRASH_DUMP ++ /* If we are doing a crash dump, we ++ * still need to know the real mem ++ * size before original memory map is ++ * reset. ++ */ ++ e820_register_active_regions(0, 0, -1UL); ++ saved_max_pfn = e820_end_of_ram(); ++ remove_all_active_ranges(); ++#endif ++ end_pfn_map = 0; ++ e820.nr_map = 0; ++ userdef = 1; ++ return 0; ++ } ++ ++ oldp = p; ++ mem_size = memparse(p, &p); ++ if (p == oldp) ++ return -EINVAL; ++ if (*p == '@') { ++ start_at = memparse(p+1, &p); ++ add_memory_region(start_at, mem_size, E820_RAM); ++ } else if (*p == '#') { ++ start_at = memparse(p+1, &p); ++ add_memory_region(start_at, mem_size, E820_ACPI); ++ } else if (*p == '$') { ++ start_at = memparse(p+1, &p); ++ add_memory_region(start_at, mem_size, E820_RESERVED); ++ } else { ++ end_user_pfn = (mem_size >> PAGE_SHIFT); ++ } ++ return *p == '\0' ? 0 : -EINVAL; ++} ++early_param("memmap", parse_memmap_opt); ++ ++void finish_e820_parsing(void) ++{ ++ if (userdef) { ++ printk(KERN_INFO "user-defined physical RAM map:\n"); ++ e820_print_map("user"); ++ } ++} ++ ++unsigned long pci_mem_start = 0xaeedbabe; ++EXPORT_SYMBOL(pci_mem_start); ++ ++/* ++ * Search for the biggest gap in the low 32 bits of the e820 ++ * memory space. We pass this space to PCI to assign MMIO resources ++ * for hotplug or unconfigured devices in. ++ * Hopefully the BIOS let enough space left. ++ */ ++__init void e820_setup_gap(struct e820entry *e820, int nr_map) ++{ ++ unsigned long gapstart, gapsize, round; ++ unsigned long last; ++ int i; ++ int found = 0; ++ ++ last = 0x100000000ull; ++ gapstart = 0x10000000; ++ gapsize = 0x400000; ++ i = nr_map; ++ while (--i >= 0) { ++ unsigned long long start = e820[i].addr; ++ unsigned long long end = start + e820[i].size; ++ ++ /* ++ * Since "last" is at most 4GB, we know we'll ++ * fit in 32 bits if this condition is true ++ */ ++ if (last > end) { ++ unsigned long gap = last - end; ++ ++ if (gap > gapsize) { ++ gapsize = gap; ++ gapstart = end; ++ found = 1; ++ } ++ } ++ if (start < last) ++ last = start; ++ } ++ ++ if (!found) { ++ gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024; ++ printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n" ++ KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n"); ++ } ++ ++ /* ++ * See how much we want to round up: start off with ++ * rounding to the next 1MB area. ++ */ ++ round = 0x100000; ++ while ((gapsize >> 4) > round) ++ round += round; ++ /* Fun with two's complement */ ++ pci_mem_start = (gapstart + round) & -round; ++ ++ printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", ++ pci_mem_start, gapstart, gapsize); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/early_printk.c +--- a/arch/x86_64/kernel/early_printk.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/early_printk.c Wed Aug 08 16:25:28 2007 -0300 +@@ -17,6 +17,7 @@ + #define VGABASE ((void __iomem *)0xffffffff800b8000UL) + #endif + ++#ifndef CONFIG_XEN + static int max_ypos = 25, max_xpos = 80; + static int current_ypos = 25, current_xpos = 0; + +@@ -149,6 +150,33 @@ static __init void early_serial_init(cha + outb(c & ~DLAB, early_serial_base + LCR); + } + ++#else /* CONFIG_XEN */ ++static void ++early_serial_write(struct console *con, const char *s, unsigned count) ++{ ++ int n; ++ ++ while (count > 0) { ++ n = HYPERVISOR_console_io(CONSOLEIO_write, count, (char *)s); ++ if (n <= 0) ++ break; ++ count -= n; ++ s += n; ++ } ++} ++ ++static __init void early_serial_init(char *s) ++{ ++} ++ ++/* ++ * No early VGA console on Xen, as we do not have convenient ISA-space ++ * mappings. Someone should fix this for domain 0. For now, use fake serial. ++ */ ++#define early_vga_console early_serial_console ++ ++#endif ++ + static struct console early_serial_console = { + .name = "earlyser", + .write = early_serial_write, +@@ -234,10 +262,14 @@ static int __init setup_early_printk(cha + early_serial_init(buf); + early_console = &early_serial_console; + } else if (!strncmp(buf, "vga", 3) ++#ifndef CONFIG_XEN + && SCREEN_INFO.orig_video_isVGA == 1) { + max_xpos = SCREEN_INFO.orig_video_cols; + max_ypos = SCREEN_INFO.orig_video_lines; + current_ypos = SCREEN_INFO.orig_y; ++#else ++ || !strncmp(buf, "xen", 3)) { ++#endif + early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { + simnow_init(buf + 6); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/entry-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/entry-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1206 @@ ++/* ++ * linux/arch/x86_64/entry.S ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs ++ * Copyright (C) 2000 Pavel Machek <pavel@suse.cz> ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Asit Mallick <asit.k.mallick@intel.com> ++ * Modified for Xen ++ */ ++ ++/* ++ * entry.S contains the system-call and fault low-level handling routines. ++ * ++ * NOTE: This code handles signal-recognition, which happens every time ++ * after an interrupt and after each system call. ++ * ++ * Normal syscalls and interrupts don't save a full stack frame, this is ++ * only done for syscall tracing, signals or fork/exec et.al. ++ * ++ * A note on terminology: ++ * - top of stack: Architecture defined interrupt frame from SS to RIP ++ * at the top of the kernel process stack. ++ * - partial stack frame: partially saved registers upto R11. ++ * - full stack frame: Like partial stack frame, but all register saved. ++ * ++ * Some macro usage: ++ * - CFI macros are used to generate dwarf2 unwind information for better ++ * backtraces. They don't change any code. ++ * - SAVE_ALL/RESTORE_ALL - Save/restore all registers ++ * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify. ++ * There are unfortunately lots of special cases where some registers ++ * not touched. The macro is a big mess that should be cleaned up. ++ * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS. ++ * Gives a full stack frame. ++ * - ENTRY/END Define functions in the symbol table. ++ * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack ++ * frame that is otherwise undefined after a SYSCALL ++ * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging. ++ * - errorentry/paranoidentry/zeroentry - Define exception entry points. ++ */ ++ ++#include <linux/linkage.h> ++#include <asm/segment.h> ++#include <asm/cache.h> ++#include <asm/errno.h> ++#include <asm/dwarf2.h> ++#include <asm/calling.h> ++#include <asm/asm-offsets.h> ++#include <asm/msr.h> ++#include <asm/unistd.h> ++#include <asm/thread_info.h> ++#include <asm/hw_irq.h> ++#include <asm/page.h> ++#include <asm/irqflags.h> ++#include <asm/errno.h> ++#include <xen/interface/arch-x86_64.h> ++#include <xen/interface/features.h> ++ ++#include "irq_vectors.h" ++ ++#include "xen_entry.S" ++ ++ .code64 ++ ++#ifndef CONFIG_PREEMPT ++#define retint_kernel retint_restore_args ++#endif ++ ++ ++.macro TRACE_IRQS_IRETQ offset=ARGOFFSET ++#ifdef CONFIG_TRACE_IRQFLAGS ++ bt $9,EFLAGS-\offset(%rsp) /* interrupts off? */ ++ jnc 1f ++ TRACE_IRQS_ON ++1: ++#endif ++.endm ++ ++NMI_MASK = 0x80000000 ++ ++/* ++ * C code is not supposed to know about undefined top of stack. Every time ++ * a C function with an pt_regs argument is called from the SYSCALL based ++ * fast path FIXUP_TOP_OF_STACK is needed. ++ * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs ++ * manipulation. ++ */ ++ ++ /* %rsp:at FRAMEEND */ ++ .macro FIXUP_TOP_OF_STACK tmp ++ movq $__USER_CS,CS(%rsp) ++ movq $-1,RCX(%rsp) ++ .endm ++ ++ .macro RESTORE_TOP_OF_STACK tmp,offset=0 ++ .endm ++ ++ .macro FAKE_STACK_FRAME child_rip ++ /* push in order ss, rsp, eflags, cs, rip */ ++ xorl %eax, %eax ++ pushq %rax /* ss */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET ss,0*/ ++ pushq %rax /* rsp */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rsp,0 ++ pushq $(1<<9) /* eflags - interrupts on */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET rflags,0*/ ++ pushq $__KERNEL_CS /* cs */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ /*CFI_REL_OFFSET cs,0*/ ++ pushq \child_rip /* rip */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rip,0 ++ pushq %rax /* orig rax */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ .endm ++ ++ .macro UNFAKE_STACK_FRAME ++ addq $8*6, %rsp ++ CFI_ADJUST_CFA_OFFSET -(6*8) ++ .endm ++ ++ .macro CFI_DEFAULT_STACK start=1,adj=0 ++ .if \start ++ CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME ++ CFI_DEF_CFA rsp,SS+8-(\adj*ARGOFFSET) ++ .else ++ CFI_DEF_CFA_OFFSET SS+8-(\adj*ARGOFFSET) ++ .endif ++ .if \adj == 0 ++ CFI_REL_OFFSET r15,R15 ++ CFI_REL_OFFSET r14,R14 ++ CFI_REL_OFFSET r13,R13 ++ CFI_REL_OFFSET r12,R12 ++ CFI_REL_OFFSET rbp,RBP ++ CFI_REL_OFFSET rbx,RBX ++ .endif ++ CFI_REL_OFFSET r11,R11 ++ CFI_REL_OFFSET r10,R10 ++ CFI_REL_OFFSET r9,R9 ++ CFI_REL_OFFSET r8,R8 ++ CFI_REL_OFFSET rax,RAX ++ CFI_REL_OFFSET rcx,RCX ++ CFI_REL_OFFSET rdx,RDX ++ CFI_REL_OFFSET rsi,RSI ++ CFI_REL_OFFSET rdi,RDI ++ CFI_REL_OFFSET rip,RIP ++ /*CFI_REL_OFFSET cs,CS*/ ++ /*CFI_REL_OFFSET rflags,EFLAGS*/ ++ CFI_REL_OFFSET rsp,RSP ++ /*CFI_REL_OFFSET ss,SS*/ ++ .endm ++ ++ /* ++ * Must be consistent with the definition in arch-x86/xen-x86_64.h: ++ * struct iret_context { ++ * u64 rax, r11, rcx, flags, rip, cs, rflags, rsp, ss; ++ * }; ++ * with rax, r11, and rcx being taken care of in the hypercall stub. ++ */ ++ .macro HYPERVISOR_IRET flag ++ testb $3,1*8(%rsp) ++ jnz 2f ++ testl $NMI_MASK,2*8(%rsp) ++ jnz 2f ++ ++ cmpb $0,(xen_features+XENFEAT_supervisor_mode_kernel)(%rip) ++ jne 1f ++ ++ /* Direct iret to kernel space. Correct CS and SS. */ ++ orl $3,1*8(%rsp) ++ orl $3,4*8(%rsp) ++1: iretq ++ ++2: /* Slow iret via hypervisor. */ ++ andl $~NMI_MASK, 2*8(%rsp) ++ pushq $\flag ++ jmp hypercall_page + (__HYPERVISOR_iret * 32) ++ .endm ++ ++/* ++ * A newly forked process directly context switches into this. ++ */ ++/* rdi: prev */ ++ENTRY(ret_from_fork) ++ CFI_DEFAULT_STACK ++ push kernel_eflags(%rip) ++ CFI_ADJUST_CFA_OFFSET 4 ++ popf # reset kernel eflags ++ CFI_ADJUST_CFA_OFFSET -4 ++ call schedule_tail ++ GET_THREAD_INFO(%rcx) ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx) ++ jnz rff_trace ++rff_action: ++ RESTORE_REST ++ testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread? ++ je int_ret_from_sys_call ++ testl $_TIF_IA32,threadinfo_flags(%rcx) ++ jnz int_ret_from_sys_call ++ RESTORE_TOP_OF_STACK %rdi,ARGOFFSET ++ jmp ret_from_sys_call ++rff_trace: ++ movq %rsp,%rdi ++ call syscall_trace_leave ++ GET_THREAD_INFO(%rcx) ++ jmp rff_action ++ CFI_ENDPROC ++END(ret_from_fork) ++ ++/* ++ * initial frame state for interrupts and exceptions ++ */ ++ .macro _frame ref ++ CFI_STARTPROC simple ++ CFI_DEF_CFA rsp,SS+8-\ref ++ /*CFI_REL_OFFSET ss,SS-\ref*/ ++ CFI_REL_OFFSET rsp,RSP-\ref ++ /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/ ++ /*CFI_REL_OFFSET cs,CS-\ref*/ ++ CFI_REL_OFFSET rip,RIP-\ref ++ .endm ++ ++/* ++ * System call entry. Upto 6 arguments in registers are supported. ++ * ++ * SYSCALL does not save anything on the stack and does not change the ++ * stack pointer. ++ */ ++ ++/* ++ * Register setup: ++ * rax system call number ++ * rdi arg0 ++ * rcx return address for syscall/sysret, C arg3 ++ * rsi arg1 ++ * rdx arg2 ++ * r10 arg3 (--> moved to rcx for C) ++ * r8 arg4 ++ * r9 arg5 ++ * r11 eflags for syscall/sysret, temporary for C ++ * r12-r15,rbp,rbx saved by C code, not touched. ++ * ++ * Interrupts are off on entry. ++ * Only called from user space. ++ * ++ * XXX if we had a free scratch register we could save the RSP into the stack frame ++ * and report it properly in ps. Unfortunately we haven't. ++ * ++ * When user can change the frames always force IRET. That is because ++ * it deals with uncanonical addresses better. SYSRET has trouble ++ * with them due to bugs in both AMD and Intel CPUs. ++ */ ++ ++ENTRY(system_call) ++ _frame (RIP-0x10) ++ SAVE_ARGS -8,0 ++ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) ++ /* ++ * No need to follow this irqs off/on section - it's straight ++ * and short: ++ */ ++ XEN_UNBLOCK_EVENTS(%r11) ++ GET_THREAD_INFO(%rcx) ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx) ++ jnz tracesys ++ cmpq $__NR_syscall_max,%rax ++ ja badsys ++ movq %r10,%rcx ++ call *sys_call_table(,%rax,8) # XXX: rip relative ++ movq %rax,RAX-ARGOFFSET(%rsp) ++/* ++ * Syscall return path ending with SYSRET (fast path) ++ * Has incomplete stack frame and undefined top of stack. ++ */ ++ret_from_sys_call: ++ movl $_TIF_ALLWORK_MASK,%edi ++ /* edi: flagmask */ ++sysret_check: ++ GET_THREAD_INFO(%rcx) ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ movl threadinfo_flags(%rcx),%edx ++ andl %edi,%edx ++ jnz sysret_careful ++ CFI_REMEMBER_STATE ++ /* ++ * sysretq will re-enable interrupts: ++ */ ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ RESTORE_ARGS 0,8,0 ++ HYPERVISOR_IRET VGCF_IN_SYSCALL ++ ++ CFI_RESTORE_STATE ++ /* Handle reschedules */ ++ /* edx: work, edi: workmask */ ++sysret_careful: ++ bt $TIF_NEED_RESCHED,%edx ++ jnc sysret_signal ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ pushq %rdi ++ CFI_ADJUST_CFA_OFFSET 8 ++ call schedule ++ popq %rdi ++ CFI_ADJUST_CFA_OFFSET -8 ++ jmp sysret_check ++ ++ /* Handle a signal */ ++sysret_signal: ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx ++ jz 1f ++ ++ /* Really a signal */ ++ /* edx: work flags (arg3) */ ++ leaq do_notify_resume(%rip),%rax ++ leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1 ++ xorl %esi,%esi # oldset -> arg2 ++ call ptregscall_common ++1: movl $_TIF_NEED_RESCHED,%edi ++ /* Use IRET because user could have changed frame. This ++ works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ ++ cli ++ TRACE_IRQS_OFF ++ jmp int_with_check ++ ++badsys: ++ movq $-ENOSYS,RAX-ARGOFFSET(%rsp) ++ jmp ret_from_sys_call ++ ++ /* Do syscall tracing */ ++tracesys: ++ SAVE_REST ++ movq $-ENOSYS,RAX(%rsp) ++ FIXUP_TOP_OF_STACK %rdi ++ movq %rsp,%rdi ++ call syscall_trace_enter ++ LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ RESTORE_REST ++ cmpq $__NR_syscall_max,%rax ++ movq $-ENOSYS,%rcx ++ cmova %rcx,%rax ++ ja 1f ++ movq %r10,%rcx /* fixup for C */ ++ call *sys_call_table(,%rax,8) ++1: movq %rax,RAX-ARGOFFSET(%rsp) ++ /* Use IRET because user could have changed frame */ ++ ++/* ++ * Syscall return path ending with IRET. ++ * Has correct top of stack, but partial stack frame. ++ */ ++ .globl int_ret_from_sys_call ++int_ret_from_sys_call: ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ testb $3,CS-ARGOFFSET(%rsp) ++ jnz 1f ++ /* Need to set the proper %ss (not NULL) for ring 3 iretq */ ++ movl $__KERNEL_DS,SS-ARGOFFSET(%rsp) ++ jmp retint_restore_args # retrun from ring3 kernel ++1: ++ movl $_TIF_ALLWORK_MASK,%edi ++ /* edi: mask to check */ ++int_with_check: ++ GET_THREAD_INFO(%rcx) ++ movl threadinfo_flags(%rcx),%edx ++ andl %edi,%edx ++ jnz int_careful ++ andl $~TS_COMPAT,threadinfo_status(%rcx) ++ jmp retint_restore_args ++ ++ /* Either reschedule or signal or syscall exit tracking needed. */ ++ /* First do a reschedule test. */ ++ /* edx: work, edi: workmask */ ++int_careful: ++ bt $TIF_NEED_RESCHED,%edx ++ jnc int_very_careful ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ pushq %rdi ++ CFI_ADJUST_CFA_OFFSET 8 ++ call schedule ++ popq %rdi ++ CFI_ADJUST_CFA_OFFSET -8 ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ jmp int_with_check ++ ++ /* handle signals and tracing -- both require a full stack frame */ ++int_very_careful: ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ SAVE_REST ++ /* Check for syscall exit trace */ ++ testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx ++ jz int_signal ++ pushq %rdi ++ CFI_ADJUST_CFA_OFFSET 8 ++ leaq 8(%rsp),%rdi # &ptregs -> arg1 ++ call syscall_trace_leave ++ popq %rdi ++ CFI_ADJUST_CFA_OFFSET -8 ++ andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi ++ jmp int_restore_rest ++ ++int_signal: ++ testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx ++ jz 1f ++ movq %rsp,%rdi # &ptregs -> arg1 ++ xorl %esi,%esi # oldset -> arg2 ++ call do_notify_resume ++1: movl $_TIF_NEED_RESCHED,%edi ++int_restore_rest: ++ RESTORE_REST ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ jmp int_with_check ++ CFI_ENDPROC ++END(system_call) ++ ++/* ++ * Certain special system calls that need to save a complete full stack frame. ++ */ ++ ++ .macro PTREGSCALL label,func,arg ++ .globl \label ++\label: ++ leaq \func(%rip),%rax ++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ ++ jmp ptregscall_common ++END(\label) ++ .endm ++ ++ CFI_STARTPROC ++ ++ PTREGSCALL stub_clone, sys_clone, %r8 ++ PTREGSCALL stub_fork, sys_fork, %rdi ++ PTREGSCALL stub_vfork, sys_vfork, %rdi ++ PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx ++ PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx ++ PTREGSCALL stub_iopl, sys_iopl, %rsi ++ ++ENTRY(ptregscall_common) ++ popq %r11 ++ CFI_ADJUST_CFA_OFFSET -8 ++ CFI_REGISTER rip, r11 ++ SAVE_REST ++ movq %r11, %r15 ++ CFI_REGISTER rip, r15 ++ FIXUP_TOP_OF_STACK %r11 ++ call *%rax ++ RESTORE_TOP_OF_STACK %r11 ++ movq %r15, %r11 ++ CFI_REGISTER rip, r11 ++ RESTORE_REST ++ pushq %r11 ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rip, 0 ++ ret ++ CFI_ENDPROC ++END(ptregscall_common) ++ ++ENTRY(stub_execve) ++ CFI_STARTPROC ++ popq %r11 ++ CFI_ADJUST_CFA_OFFSET -8 ++ CFI_REGISTER rip, r11 ++ SAVE_REST ++ FIXUP_TOP_OF_STACK %r11 ++ call sys_execve ++ RESTORE_TOP_OF_STACK %r11 ++ movq %rax,RAX(%rsp) ++ RESTORE_REST ++ jmp int_ret_from_sys_call ++ CFI_ENDPROC ++END(stub_execve) ++ ++/* ++ * sigreturn is special because it needs to restore all registers on return. ++ * This cannot be done with SYSRET, so use the IRET return path instead. ++ */ ++ENTRY(stub_rt_sigreturn) ++ CFI_STARTPROC ++ addq $8, %rsp ++ CFI_ADJUST_CFA_OFFSET -8 ++ SAVE_REST ++ movq %rsp,%rdi ++ FIXUP_TOP_OF_STACK %r11 ++ call sys_rt_sigreturn ++ movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer ++ RESTORE_REST ++ jmp int_ret_from_sys_call ++ CFI_ENDPROC ++END(stub_rt_sigreturn) ++ ++/* initial frame state for interrupts (and exceptions without error code) */ ++#define INTR_FRAME _frame (RIP-0x10); \ ++ CFI_REL_OFFSET rcx,0; \ ++ CFI_REL_OFFSET r11,8 ++ ++/* initial frame state for exceptions with error code (and interrupts with ++ vector already pushed) */ ++#define XCPT_FRAME _frame (RIP-0x18); \ ++ CFI_REL_OFFSET rcx,0; \ ++ CFI_REL_OFFSET r11,8 ++ ++/* ++ * Interrupt exit. ++ * ++ */ ++ ++retint_check: ++ CFI_DEFAULT_STACK adj=1 ++ movl threadinfo_flags(%rcx),%edx ++ andl %edi,%edx ++ CFI_REMEMBER_STATE ++ jnz retint_careful ++retint_restore_args: ++ movl EFLAGS-REST_SKIP(%rsp), %eax ++ shr $9, %eax # EAX[0] == IRET_EFLAGS.IF ++ XEN_GET_VCPU_INFO(%rsi) ++ andb evtchn_upcall_mask(%rsi),%al ++ andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask ++ jnz restore_all_enable_events # != 0 => enable event delivery ++ XEN_PUT_VCPU_INFO(%rsi) ++ TRACE_IRQS_IRETQ ++ RESTORE_ARGS 0,8,0 ++ HYPERVISOR_IRET 0 ++ ++ /* edi: workmask, edx: work */ ++retint_careful: ++ CFI_RESTORE_STATE ++ bt $TIF_NEED_RESCHED,%edx ++ jnc retint_signal ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ pushq %rdi ++ CFI_ADJUST_CFA_OFFSET 8 ++ call schedule ++ popq %rdi ++ CFI_ADJUST_CFA_OFFSET -8 ++ GET_THREAD_INFO(%rcx) ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ jmp retint_check ++ ++retint_signal: ++ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx ++ jz retint_restore_args ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) ++ SAVE_REST ++ movq $-1,ORIG_RAX(%rsp) ++ xorl %esi,%esi # oldset ++ movq %rsp,%rdi # &pt_regs ++ call do_notify_resume ++ RESTORE_REST ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ movl $_TIF_NEED_RESCHED,%edi ++ GET_THREAD_INFO(%rcx) ++ jmp retint_check ++ ++#ifdef CONFIG_PREEMPT ++ /* Returning to kernel space. Check if we need preemption */ ++ /* rcx: threadinfo. interrupts off. */ ++ENTRY(retint_kernel) ++ cmpl $0,threadinfo_preempt_count(%rcx) ++ jnz retint_restore_args ++ bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx) ++ jnc retint_restore_args ++ bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */ ++ jnc retint_restore_args ++ call preempt_schedule_irq ++ jmp retint_kernel /* check again */ ++#endif ++ ++ CFI_ENDPROC ++END(retint_check) ++ ++#ifndef CONFIG_XEN ++/* ++ * APIC interrupts. ++ */ ++ .macro apicinterrupt num,func ++ INTR_FRAME ++ pushq $~(\num) ++ CFI_ADJUST_CFA_OFFSET 8 ++ interrupt \func ++ jmp error_entry ++ CFI_ENDPROC ++ .endm ++ ++ENTRY(thermal_interrupt) ++ apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt ++END(thermal_interrupt) ++ ++ENTRY(threshold_interrupt) ++ apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt ++END(threshold_interrupt) ++ ++#ifdef CONFIG_SMP ++ENTRY(reschedule_interrupt) ++ apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt ++END(reschedule_interrupt) ++ ++ .macro INVALIDATE_ENTRY num ++ENTRY(invalidate_interrupt\num) ++ apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt ++END(invalidate_interrupt\num) ++ .endm ++ ++ INVALIDATE_ENTRY 0 ++ INVALIDATE_ENTRY 1 ++ INVALIDATE_ENTRY 2 ++ INVALIDATE_ENTRY 3 ++ INVALIDATE_ENTRY 4 ++ INVALIDATE_ENTRY 5 ++ INVALIDATE_ENTRY 6 ++ INVALIDATE_ENTRY 7 ++ ++ENTRY(call_function_interrupt) ++ apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt ++END(call_function_interrupt) ++#endif ++ ++ENTRY(apic_timer_interrupt) ++ apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt ++END(apic_timer_interrupt) ++ ++ENTRY(error_interrupt) ++ apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt ++END(error_interrupt) ++ ++ENTRY(spurious_interrupt) ++ apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt ++END(spurious_interrupt) ++#endif /* !CONFIG_XEN */ ++ ++/* ++ * Exception entry points. ++ */ ++ .macro zeroentry sym ++ INTR_FRAME ++ movq (%rsp),%rcx ++ CFI_RESTORE rcx ++ movq 8(%rsp),%r11 ++ CFI_RESTORE r11 ++ addq $0x10,%rsp /* skip rcx and r11 */ ++ CFI_ADJUST_CFA_OFFSET -0x10 ++ pushq $0 /* push error code/oldrax */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ pushq %rax /* push real oldrax to the rdi slot */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rax,0 ++ leaq \sym(%rip),%rax ++ jmp error_entry ++ CFI_ENDPROC ++ .endm ++ ++ .macro errorentry sym ++ XCPT_FRAME ++ movq (%rsp),%rcx ++ CFI_RESTORE rcx ++ movq 8(%rsp),%r11 ++ CFI_RESTORE r11 ++ addq $0x10,%rsp /* rsp points to the error code */ ++ CFI_ADJUST_CFA_OFFSET -0x10 ++ pushq %rax ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rax,0 ++ leaq \sym(%rip),%rax ++ jmp error_entry ++ CFI_ENDPROC ++ .endm ++ ++#if 0 /* not XEN */ ++ /* error code is on the stack already */ ++ /* handle NMI like exceptions that can happen everywhere */ ++ .macro paranoidentry sym, ist=0 ++ movq (%rsp),%rcx ++ movq 8(%rsp),%r11 ++ addq $0x10,%rsp /* skip rcx and r11 */ ++ SAVE_ALL ++ cld ++#if 0 /* not XEN */ ++ movl $1,%ebx ++ movl $MSR_GS_BASE,%ecx ++ rdmsr ++ testl %edx,%edx ++ js 1f ++ swapgs ++ xorl %ebx,%ebx ++1: ++#endif ++ .if \ist ++ movq %gs:pda_data_offset, %rbp ++ .endif ++ movq %rsp,%rdi ++ movq ORIG_RAX(%rsp),%rsi ++ movq $-1,ORIG_RAX(%rsp) ++ .if \ist ++ subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) ++ .endif ++ call \sym ++ .if \ist ++ addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) ++ .endif ++ XEN_BLOCK_EVENTS(%rsi) ++ .if \irqtrace ++ TRACE_IRQS_OFF ++ .endif ++ .endm ++#endif ++ ++/* ++ * Exception entry point. This expects an error code/orig_rax on the stack ++ * and the exception handler in %rax. ++ */ ++KPROBE_ENTRY(error_entry) ++ _frame RDI ++ CFI_REL_OFFSET rax,0 ++ /* rdi slot contains rax, oldrax contains error code */ ++ cld ++ subq $14*8,%rsp ++ CFI_ADJUST_CFA_OFFSET (14*8) ++ movq %rsi,13*8(%rsp) ++ CFI_REL_OFFSET rsi,RSI ++ movq 14*8(%rsp),%rsi /* load rax from rdi slot */ ++ CFI_REGISTER rax,rsi ++ movq %rdx,12*8(%rsp) ++ CFI_REL_OFFSET rdx,RDX ++ movq %rcx,11*8(%rsp) ++ CFI_REL_OFFSET rcx,RCX ++ movq %rsi,10*8(%rsp) /* store rax */ ++ CFI_REL_OFFSET rax,RAX ++ movq %r8, 9*8(%rsp) ++ CFI_REL_OFFSET r8,R8 ++ movq %r9, 8*8(%rsp) ++ CFI_REL_OFFSET r9,R9 ++ movq %r10,7*8(%rsp) ++ CFI_REL_OFFSET r10,R10 ++ movq %r11,6*8(%rsp) ++ CFI_REL_OFFSET r11,R11 ++ movq %rbx,5*8(%rsp) ++ CFI_REL_OFFSET rbx,RBX ++ movq %rbp,4*8(%rsp) ++ CFI_REL_OFFSET rbp,RBP ++ movq %r12,3*8(%rsp) ++ CFI_REL_OFFSET r12,R12 ++ movq %r13,2*8(%rsp) ++ CFI_REL_OFFSET r13,R13 ++ movq %r14,1*8(%rsp) ++ CFI_REL_OFFSET r14,R14 ++ movq %r15,(%rsp) ++ CFI_REL_OFFSET r15,R15 ++#if 0 ++ cmpl $__KERNEL_CS,CS(%rsp) ++ CFI_REMEMBER_STATE ++ je error_kernelspace ++#endif ++error_call_handler: ++ movq %rdi,RDI(%rsp) ++ CFI_REL_OFFSET rdi,RDI ++ movq %rsp,%rdi ++ movq ORIG_RAX(%rsp),%rsi /* get error code */ ++ movq $-1,ORIG_RAX(%rsp) ++ call *%rax ++error_exit: ++ RESTORE_REST ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ GET_THREAD_INFO(%rcx) ++ testb $3,CS-ARGOFFSET(%rsp) ++ jz retint_kernel ++ movl threadinfo_flags(%rcx),%edx ++ movl $_TIF_WORK_MASK,%edi ++ andl %edi,%edx ++ jnz retint_careful ++ /* ++ * The iret might restore flags: ++ */ ++ TRACE_IRQS_IRETQ ++ jmp retint_restore_args ++ ++#if 0 ++ /* ++ * We need to re-write the logic here because we don't do iretq to ++ * to return to user mode. It's still possible that we get trap/fault ++ * in the kernel (when accessing buffers pointed to by system calls, ++ * for example). ++ * ++ */ ++ CFI_RESTORE_STATE ++error_kernelspace: ++ incl %ebx ++ /* There are two places in the kernel that can potentially fault with ++ usergs. Handle them here. The exception handlers after ++ iret run with kernel gs again, so don't set the user space flag. ++ B stepping K8s sometimes report an truncated RIP for IRET ++ exceptions returning to compat mode. Check for these here too. */ ++ leaq iret_label(%rip),%rbp ++ cmpq %rbp,RIP(%rsp) ++ je error_swapgs ++ movl %ebp,%ebp /* zero extend */ ++ cmpq %rbp,RIP(%rsp) ++ je error_swapgs ++ cmpq $gs_change,RIP(%rsp) ++ je error_swapgs ++ jmp error_sti ++#endif ++ CFI_ENDPROC ++KPROBE_END(error_entry) ++ ++ENTRY(hypervisor_callback) ++ zeroentry do_hypervisor_callback ++END(hypervisor_callback) ++ ++/* ++ * Copied from arch/xen/i386/kernel/entry.S ++ */ ++# A note on the "critical region" in our callback handler. ++# We want to avoid stacking callback handlers due to events occurring ++# during handling of the last event. To do this, we keep events disabled ++# until we've done all processing. HOWEVER, we must enable events before ++# popping the stack frame (can't be done atomically) and so it would still ++# be possible to get enough handler activations to overflow the stack. ++# Although unlikely, bugs of that kind are hard to track down, so we'd ++# like to avoid the possibility. ++# So, on entry to the handler we detect whether we interrupted an ++# existing activation in its critical region -- if so, we pop the current ++# activation and restart the handler using the previous one. ++ENTRY(do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) ++ CFI_STARTPROC ++# Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will ++# see the correct pointer to the pt_regs ++ movq %rdi, %rsp # we don't return, adjust the stack frame ++ CFI_ENDPROC ++ CFI_DEFAULT_STACK ++11: incl %gs:pda_irqcount ++ movq %rsp,%rbp ++ CFI_DEF_CFA_REGISTER rbp ++ cmovzq %gs:pda_irqstackptr,%rsp ++ pushq %rbp # backlink for old unwinder ++ call evtchn_do_upcall ++ popq %rsp ++ CFI_DEF_CFA_REGISTER rsp ++ decl %gs:pda_irqcount ++ jmp error_exit ++ CFI_ENDPROC ++END(do_hypervisor_callback) ++ ++KPROBE_ENTRY(nmi) ++ zeroentry xen_do_nmi_callback ++ENTRY(xen_do_nmi_callback) ++ CFI_STARTPROC ++ addq $8, %rsp ++ CFI_ENDPROC ++ CFI_DEFAULT_STACK ++ call do_nmi ++ orl $NMI_MASK,EFLAGS(%rsp) ++ RESTORE_REST ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ GET_THREAD_INFO(%rcx) ++ jmp retint_restore_args ++ CFI_ENDPROC ++ .previous .text ++KPROBE_END(nmi) ++ ++ ALIGN ++restore_all_enable_events: ++ CFI_DEFAULT_STACK adj=1 ++ TRACE_IRQS_ON ++ XEN_UNBLOCK_EVENTS(%rsi) # %rsi is already set up... ++ ++scrit: /**** START OF CRITICAL REGION ****/ ++ XEN_TEST_PENDING(%rsi) ++ CFI_REMEMBER_STATE ++ jnz 14f # process more events if necessary... ++ XEN_PUT_VCPU_INFO(%rsi) ++ RESTORE_ARGS 0,8,0 ++ HYPERVISOR_IRET 0 ++ ++ CFI_RESTORE_STATE ++14: XEN_LOCKED_BLOCK_EVENTS(%rsi) ++ XEN_PUT_VCPU_INFO(%rsi) ++ SAVE_REST ++ movq %rsp,%rdi # set the argument again ++ jmp 11b ++ CFI_ENDPROC ++ecrit: /**** END OF CRITICAL REGION ****/ ++# At this point, unlike on x86-32, we don't do the fixup to simplify the ++# code and the stack frame is more complex on x86-64. ++# When the kernel is interrupted in the critical section, the kernel ++# will do IRET in that case, and everything will be restored at that point, ++# i.e. it just resumes from the next instruction interrupted with the same context. ++ ++# Hypervisor uses this for application faults while it executes. ++# We get here for two reasons: ++# 1. Fault while reloading DS, ES, FS or GS ++# 2. Fault while executing IRET ++# Category 1 we do not need to fix up as Xen has already reloaded all segment ++# registers that could be reloaded and zeroed the others. ++# Category 2 we fix up by killing the current process. We cannot use the ++# normal Linux return path in this case because if we use the IRET hypercall ++# to pop the stack frame we end up in an infinite loop of failsafe callbacks. ++# We distinguish between categories by comparing each saved segment register ++# with its current contents: any discrepancy means we in category 1. ++ENTRY(failsafe_callback) ++ _frame (RIP-0x30) ++ CFI_REL_OFFSET rcx, 0 ++ CFI_REL_OFFSET r11, 8 ++ movw %ds,%cx ++ cmpw %cx,0x10(%rsp) ++ CFI_REMEMBER_STATE ++ jne 1f ++ movw %es,%cx ++ cmpw %cx,0x18(%rsp) ++ jne 1f ++ movw %fs,%cx ++ cmpw %cx,0x20(%rsp) ++ jne 1f ++ movw %gs,%cx ++ cmpw %cx,0x28(%rsp) ++ jne 1f ++ /* All segments match their saved values => Category 2 (Bad IRET). */ ++ movq (%rsp),%rcx ++ CFI_RESTORE rcx ++ movq 8(%rsp),%r11 ++ CFI_RESTORE r11 ++ addq $0x30,%rsp ++ CFI_ADJUST_CFA_OFFSET -0x30 ++ movq $11,%rdi /* SIGSEGV */ ++ jmp do_exit ++ CFI_RESTORE_STATE ++1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ ++ movq (%rsp),%rcx ++ CFI_RESTORE rcx ++ movq 8(%rsp),%r11 ++ CFI_RESTORE r11 ++ addq $0x30,%rsp ++ CFI_ADJUST_CFA_OFFSET -0x30 ++ pushq $0 ++ CFI_ADJUST_CFA_OFFSET 8 ++ SAVE_ALL ++ jmp error_exit ++ CFI_ENDPROC ++#if 0 ++ .section __ex_table,"a" ++ .align 8 ++ .quad gs_change,bad_gs ++ .previous ++ .section .fixup,"ax" ++ /* running with kernelgs */ ++bad_gs: ++/* swapgs */ /* switch back to user gs */ ++ xorl %eax,%eax ++ movl %eax,%gs ++ jmp 2b ++ .previous ++#endif ++ ++/* ++ * Create a kernel thread. ++ * ++ * C extern interface: ++ * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ++ * ++ * asm input arguments: ++ * rdi: fn, rsi: arg, rdx: flags ++ */ ++ENTRY(kernel_thread) ++ CFI_STARTPROC ++ FAKE_STACK_FRAME $child_rip ++ SAVE_ALL ++ ++ # rdi: flags, rsi: usp, rdx: will be &pt_regs ++ movq %rdx,%rdi ++ orq kernel_thread_flags(%rip),%rdi ++ movq $-1, %rsi ++ movq %rsp, %rdx ++ ++ xorl %r8d,%r8d ++ xorl %r9d,%r9d ++ ++ # clone now ++ call do_fork ++ movq %rax,RAX(%rsp) ++ xorl %edi,%edi ++ ++ /* ++ * It isn't worth to check for reschedule here, ++ * so internally to the x86_64 port you can rely on kernel_thread() ++ * not to reschedule the child before returning, this avoids the need ++ * of hacks for example to fork off the per-CPU idle tasks. ++ * [Hopefully no generic code relies on the reschedule -AK] ++ */ ++ RESTORE_ALL ++ UNFAKE_STACK_FRAME ++ ret ++ CFI_ENDPROC ++ENDPROC(kernel_thread) ++ ++child_rip: ++ pushq $0 # fake return address ++ CFI_STARTPROC ++ /* ++ * Here we are in the child and the registers are set as they were ++ * at kernel_thread() invocation in the parent. ++ */ ++ movq %rdi, %rax ++ movq %rsi, %rdi ++ call *%rax ++ # exit ++ xorl %edi, %edi ++ call do_exit ++ CFI_ENDPROC ++ENDPROC(child_rip) ++ ++/* ++ * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. ++ * ++ * C extern interface: ++ * extern long execve(char *name, char **argv, char **envp) ++ * ++ * asm input arguments: ++ * rdi: name, rsi: argv, rdx: envp ++ * ++ * We want to fallback into: ++ * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs) ++ * ++ * do_sys_execve asm fallback arguments: ++ * rdi: name, rsi: argv, rdx: envp, fake frame on the stack ++ */ ++ENTRY(kernel_execve) ++ CFI_STARTPROC ++ FAKE_STACK_FRAME $0 ++ SAVE_ALL ++ call sys_execve ++ movq %rax, RAX(%rsp) ++ RESTORE_REST ++ testq %rax,%rax ++ jne 1f ++ jmp int_ret_from_sys_call ++1: RESTORE_ARGS ++ UNFAKE_STACK_FRAME ++ ret ++ CFI_ENDPROC ++ENDPROC(kernel_execve) ++ ++KPROBE_ENTRY(page_fault) ++ errorentry do_page_fault ++KPROBE_END(page_fault) ++ ++ENTRY(coprocessor_error) ++ zeroentry do_coprocessor_error ++END(coprocessor_error) ++ ++ENTRY(simd_coprocessor_error) ++ zeroentry do_simd_coprocessor_error ++END(simd_coprocessor_error) ++ ++ENTRY(device_not_available) ++ zeroentry math_state_restore ++END(device_not_available) ++ ++ /* runs on exception stack */ ++KPROBE_ENTRY(debug) ++/* INTR_FRAME ++ pushq $0 ++ CFI_ADJUST_CFA_OFFSET 8 */ ++ zeroentry do_debug ++/* paranoid_exit */ ++ CFI_ENDPROC ++KPROBE_END(debug) ++ ++#if 0 ++ /* runs on exception stack */ ++KPROBE_ENTRY(nmi) ++ INTR_FRAME ++ pushq $-1 ++ CFI_ADJUST_CFA_OFFSET 8 ++ paranoidentry do_nmi, 0, 0 ++#ifdef CONFIG_TRACE_IRQFLAGS ++ paranoidexit 0 ++#else ++ jmp paranoid_exit1 ++ CFI_ENDPROC ++#endif ++KPROBE_END(nmi) ++ .previous .text ++#endif ++ ++KPROBE_ENTRY(int3) ++/* INTR_FRAME ++ pushq $0 ++ CFI_ADJUST_CFA_OFFSET 8 */ ++ zeroentry do_int3 ++/* jmp paranoid_exit1 */ ++ CFI_ENDPROC ++KPROBE_END(int3) ++ ++ENTRY(overflow) ++ zeroentry do_overflow ++END(overflow) ++ ++ENTRY(bounds) ++ zeroentry do_bounds ++END(bounds) ++ ++ENTRY(invalid_op) ++ zeroentry do_invalid_op ++END(invalid_op) ++ ++ENTRY(coprocessor_segment_overrun) ++ zeroentry do_coprocessor_segment_overrun ++END(coprocessor_segment_overrun) ++ ++ENTRY(reserved) ++ zeroentry do_reserved ++END(reserved) ++ ++#if 0 ++ /* runs on exception stack */ ++ENTRY(double_fault) ++ XCPT_FRAME ++ paranoidentry do_double_fault ++ jmp paranoid_exit1 ++ CFI_ENDPROC ++END(double_fault) ++#endif ++ ++ENTRY(invalid_TSS) ++ errorentry do_invalid_TSS ++END(invalid_TSS) ++ ++ENTRY(segment_not_present) ++ errorentry do_segment_not_present ++END(segment_not_present) ++ ++ /* runs on exception stack */ ++ENTRY(stack_segment) ++/* XCPT_FRAME ++ paranoidentry do_stack_segment */ ++ errorentry do_stack_segment ++/* jmp paranoid_exit1 ++ CFI_ENDPROC */ ++END(stack_segment) ++ ++KPROBE_ENTRY(general_protection) ++ errorentry do_general_protection ++KPROBE_END(general_protection) ++ ++ENTRY(alignment_check) ++ errorentry do_alignment_check ++END(alignment_check) ++ ++ENTRY(divide_error) ++ zeroentry do_divide_error ++END(divide_error) ++ ++ENTRY(spurious_interrupt_bug) ++ zeroentry do_spurious_interrupt_bug ++END(spurious_interrupt_bug) ++ ++#ifdef CONFIG_X86_MCE ++ /* runs on exception stack */ ++ENTRY(machine_check) ++ INTR_FRAME ++ pushq $0 ++ CFI_ADJUST_CFA_OFFSET 8 ++ paranoidentry do_machine_check ++ jmp paranoid_exit1 ++ CFI_ENDPROC ++END(machine_check) ++#endif ++ ++/* Call softirq on interrupt stack. Interrupts are off. */ ++ENTRY(call_softirq) ++ CFI_STARTPROC ++ push %rbp ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rbp,0 ++ mov %rsp,%rbp ++ CFI_DEF_CFA_REGISTER rbp ++ incl %gs:pda_irqcount ++ cmove %gs:pda_irqstackptr,%rsp ++ push %rbp # backlink for old unwinder ++ call __do_softirq ++ leaveq ++ CFI_DEF_CFA_REGISTER rsp ++ CFI_ADJUST_CFA_OFFSET -8 ++ decl %gs:pda_irqcount ++ ret ++ CFI_ENDPROC ++ENDPROC(call_softirq) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/genapic.c +--- a/arch/x86_64/kernel/genapic.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/genapic.c Wed Aug 08 16:25:28 2007 -0300 +@@ -32,14 +32,20 @@ extern struct genapic apic_flat; + extern struct genapic apic_flat; + extern struct genapic apic_physflat; + ++#ifndef CONFIG_XEN + struct genapic *genapic = &apic_flat; + struct genapic *genapic_force; ++#else ++extern struct genapic apic_xen; ++struct genapic *genapic = &apic_xen; ++#endif + + /* + * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. + */ + void __init clustered_apic_check(void) + { ++#ifndef CONFIG_XEN + long i; + u8 clusters, max_cluster; + u8 id; +@@ -121,12 +127,24 @@ void __init clustered_apic_check(void) + genapic = &apic_cluster; + + print: ++#else ++ /* hardcode to xen apic functions */ ++ genapic = &apic_xen; ++#endif + printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); + } + + /* Same for both flat and clustered. */ + ++#ifdef CONFIG_XEN ++extern void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest); ++#endif ++ + void send_IPI_self(int vector) + { ++#ifndef CONFIG_XEN + __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); ++#else ++ xen_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); ++#endif + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/genapic_xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/genapic_xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,190 @@ ++/* ++ * Copyright 2004 James Cleverdon, IBM. ++ * Subject to the GNU Public License, v.2 ++ * ++ * Xen APIC subarch code. Maximum 8 CPUs, logical delivery. ++ * ++ * Hacked for x86-64 by James Cleverdon from i386 architecture code by ++ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and ++ * James Cleverdon. ++ * ++ * Hacked to pieces for Xen by Chris Wright. ++ */ ++#include <linux/threads.h> ++#include <linux/cpumask.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <linux/ctype.h> ++#include <linux/init.h> ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++#include <asm/smp.h> ++#include <asm/ipi.h> ++#else ++#include <asm/apic.h> ++#include <asm/apicdef.h> ++#include <asm/genapic.h> ++#endif ++#include <xen/evtchn.h> ++ ++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); ++ ++static inline void __send_IPI_one(unsigned int cpu, int vector) ++{ ++ int irq = per_cpu(ipi_to_irq, cpu)[vector]; ++ BUG_ON(irq < 0); ++ notify_remote_via_irq(irq); ++} ++ ++void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) ++{ ++ int cpu; ++ ++ switch (shortcut) { ++ case APIC_DEST_SELF: ++ __send_IPI_one(smp_processor_id(), vector); ++ break; ++ case APIC_DEST_ALLBUT: ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (cpu == smp_processor_id()) ++ continue; ++ if (cpu_isset(cpu, cpu_online_map)) { ++ __send_IPI_one(cpu, vector); ++ } ++ } ++ break; ++ case APIC_DEST_ALLINC: ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (cpu_isset(cpu, cpu_online_map)) { ++ __send_IPI_one(cpu, vector); ++ } ++ } ++ break; ++ default: ++ printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, ++ vector); ++ break; ++ } ++} ++ ++static cpumask_t xen_target_cpus(void) ++{ ++ return cpu_online_map; ++} ++ ++static cpumask_t xen_vector_allocation_domain(int cpu) ++{ ++ /* Careful. Some cpus do not strictly honor the set of cpus ++ * specified in the interrupt destination when using lowest ++ * priority interrupt delivery mode. ++ * ++ * In particular there was a hyperthreading cpu observed to ++ * deliver interrupts to the wrong hyperthread when only one ++ * hyperthread was specified in the interrupt desitination. ++ */ ++ cpumask_t domain = { { [0] = APIC_ALL_CPUS, } }; ++ return domain; ++} ++ ++/* ++ * Set up the logical destination ID. ++ * Do nothing, not called now. ++ */ ++static void xen_init_apic_ldr(void) ++{ ++ Dprintk("%s\n", __FUNCTION__); ++ return; ++} ++ ++static void xen_send_IPI_mask(cpumask_t cpumask, int vector) ++{ ++ unsigned long mask = cpus_addr(cpumask)[0]; ++ unsigned int cpu; ++ unsigned long flags; ++ ++ Dprintk("%s\n", __FUNCTION__); ++ local_irq_save(flags); ++ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); ++ ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (cpu_isset(cpu, cpumask)) { ++ __send_IPI_one(cpu, vector); ++ } ++ } ++ local_irq_restore(flags); ++} ++ ++static void xen_send_IPI_allbutself(int vector) ++{ ++#ifdef CONFIG_HOTPLUG_CPU ++ int hotplug = 1; ++#else ++ int hotplug = 0; ++#endif ++ /* ++ * if there are no other CPUs in the system then ++ * we get an APIC send error if we try to broadcast. ++ * thus we have to avoid sending IPIs in this case. ++ */ ++ Dprintk("%s\n", __FUNCTION__); ++ if (hotplug || vector == NMI_VECTOR) { ++ cpumask_t allbutme = cpu_online_map; ++ ++ cpu_clear(smp_processor_id(), allbutme); ++ ++ if (!cpus_empty(allbutme)) ++ xen_send_IPI_mask(allbutme, vector); ++ } else if (num_online_cpus() > 1) { ++ xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL); ++ } ++} ++ ++static void xen_send_IPI_all(int vector) ++{ ++ Dprintk("%s\n", __FUNCTION__); ++ if (vector == NMI_VECTOR) ++ xen_send_IPI_mask(cpu_online_map, vector); ++ else ++ xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); ++} ++ ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++static int xen_apic_id_registered(void) ++{ ++ /* better be set */ ++ Dprintk("%s\n", __FUNCTION__); ++ return physid_isset(smp_processor_id(), phys_cpu_present_map); ++} ++#endif ++ ++static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask) ++{ ++ Dprintk("%s\n", __FUNCTION__); ++ return cpus_addr(cpumask)[0] & APIC_ALL_CPUS; ++} ++ ++static unsigned int phys_pkg_id(int index_msb) ++{ ++ int ebx; ++ Dprintk("%s\n", __FUNCTION__); ++ ebx = cpuid_ebx(1); ++ return ((ebx >> 24) & 0xFF) >> index_msb; ++} ++ ++struct genapic apic_xen = { ++ .name = "xen", ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++ .int_delivery_mode = dest_LowestPrio, ++#endif ++ .int_dest_mode = (APIC_DEST_LOGICAL != 0), ++ .target_cpus = xen_target_cpus, ++ .vector_allocation_domain = xen_vector_allocation_domain, ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++ .apic_id_registered = xen_apic_id_registered, ++#endif ++ .init_apic_ldr = xen_init_apic_ldr, ++ .send_IPI_all = xen_send_IPI_all, ++ .send_IPI_allbutself = xen_send_IPI_allbutself, ++ .send_IPI_mask = xen_send_IPI_mask, ++ .cpu_mask_to_apicid = xen_cpu_mask_to_apicid, ++ .phys_pkg_id = phys_pkg_id, ++}; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/head-xen.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/head-xen.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,206 @@ ++/* ++ * linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit ++ * ++ * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE ++ * Copyright (C) 2000 Pavel Machek <pavel@suse.cz> ++ * Copyright (C) 2000 Karsten Keil <kkeil@suse.de> ++ * Copyright (C) 2001,2002 Andi Kleen <ak@suse.de> ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Modified for Xen ++ */ ++ ++ ++#include <linux/linkage.h> ++#include <linux/threads.h> ++#include <linux/init.h> ++#include <linux/elfnote.h> ++#include <asm/desc.h> ++#include <asm/segment.h> ++#include <asm/page.h> ++#include <asm/msr.h> ++#include <asm/cache.h> ++#include <asm/dwarf2.h> ++#include <xen/interface/elfnote.h> ++ ++ .section .bootstrap.text, "ax", @progbits ++ .code64 ++#define VIRT_ENTRY_OFFSET 0x0 ++.org VIRT_ENTRY_OFFSET ++ .globl startup_64 ++startup_64: ++ENTRY(_start) ++ movq $(init_thread_union+THREAD_SIZE-8),%rsp ++ ++ /* rsi is pointer to startup info structure. ++ pass it to C */ ++ movq %rsi,%rdi ++ pushq $0 # fake return address ++ jmp x86_64_start_kernel ++ ++ENTRY(stext) ++ENTRY(_stext) ++ ++ $page = 0 ++#define NEXT_PAGE(name) \ ++ $page = $page + 1; \ ++ .org $page * 0x1000; \ ++ phys_##name = $page * 0x1000 + __PHYSICAL_START; \ ++ENTRY(name) ++ ++NEXT_PAGE(init_level4_pgt) ++ /* This gets initialized in x86_64_start_kernel */ ++ .fill 512,8,0 ++ ++ /* ++ * We update two pgd entries to make kernel and user pgd consistent ++ * at pgd_populate(). It can be used for kernel modules. So we place ++ * this page here for those cases to avoid memory corruption. ++ * We also use this page to establish the initiali mapping for ++ * vsyscall area. ++ */ ++NEXT_PAGE(init_level4_user_pgt) ++ .fill 512,8,0 ++ ++NEXT_PAGE(level3_kernel_pgt) ++ .fill 512,8,0 ++ ++ /* ++ * This is used for vsyscall area mapping as we have a different ++ * level4 page table for user. ++ */ ++NEXT_PAGE(level3_user_pgt) ++ .fill 512,8,0 ++ ++NEXT_PAGE(level2_kernel_pgt) ++ .fill 512,8,0 ++ ++NEXT_PAGE(hypercall_page) ++ CFI_STARTPROC ++ .rept 0x1000 / 0x20 ++ .skip 1 /* push %rcx */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rcx,0 ++ .skip 2 /* push %r11 */ ++ CFI_ADJUST_CFA_OFFSET 8 ++ CFI_REL_OFFSET rcx,0 ++ .skip 5 /* mov $#,%eax */ ++ .skip 2 /* syscall */ ++ .skip 2 /* pop %r11 */ ++ CFI_ADJUST_CFA_OFFSET -8 ++ CFI_RESTORE r11 ++ .skip 1 /* pop %rcx */ ++ CFI_ADJUST_CFA_OFFSET -8 ++ CFI_RESTORE rcx ++ .align 0x20,0 /* ret */ ++ .endr ++ CFI_ENDPROC ++ ++#undef NEXT_PAGE ++ ++ .data ++ ++ .align 16 ++ .globl cpu_gdt_descr ++cpu_gdt_descr: ++ .word gdt_end-cpu_gdt_table-1 ++gdt: ++ .quad cpu_gdt_table ++#ifdef CONFIG_SMP ++ .rept NR_CPUS-1 ++ .word 0 ++ .quad 0 ++ .endr ++#endif ++ ++/* We need valid kernel segments for data and code in long mode too ++ * IRET will check the segment types kkeil 2000/10/28 ++ * Also sysret mandates a special GDT layout ++ */ ++ ++ .section .data.page_aligned, "aw" ++ .align PAGE_SIZE ++ ++/* The TLS descriptors are currently at a different place compared to i386. ++ Hopefully nobody expects them at a fixed place (Wine?) */ ++ ++ENTRY(cpu_gdt_table) ++ .quad 0x0000000000000000 /* NULL descriptor */ ++ .quad 0x0 /* unused */ ++ .quad 0x00af9a000000ffff /* __KERNEL_CS */ ++ .quad 0x00cf92000000ffff /* __KERNEL_DS */ ++ .quad 0x00cffa000000ffff /* __USER32_CS */ ++ .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */ ++ .quad 0x00affa000000ffff /* __USER_CS */ ++ .quad 0x00cf9a000000ffff /* __KERNEL32_CS */ ++ .quad 0,0 /* TSS */ ++ .quad 0,0 /* LDT */ ++ .quad 0,0,0 /* three TLS descriptors */ ++ .quad 0x0000f40000000000 /* node/CPU stored in limit */ ++gdt_end: ++ /* asm/segment.h:GDT_ENTRIES must match this */ ++ /* This should be a multiple of the cache line size */ ++ /* GDTs of other CPUs are now dynamically allocated */ ++ ++ /* zero the remaining page */ ++ .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0 ++ ++ .section .bss, "aw", @nobits ++ .align L1_CACHE_BYTES ++ENTRY(idt_table) ++ .skip 256 * 16 ++ ++ .section .bss.page_aligned, "aw", @nobits ++ .align PAGE_SIZE ++ENTRY(empty_zero_page) ++ .skip PAGE_SIZE ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++/* ++ * __xen_guest information ++ */ ++.macro utoh value ++ .if (\value) < 0 || (\value) >= 0x10 ++ utoh (((\value)>>4)&0x0fffffffffffffff) ++ .endif ++ .if ((\value) & 0xf) < 10 ++ .byte '0' + ((\value) & 0xf) ++ .else ++ .byte 'A' + ((\value) & 0xf) - 10 ++ .endif ++.endm ++ ++.section __xen_guest ++ .ascii "GUEST_OS=linux,GUEST_VER=2.6" ++ .ascii ",XEN_VER=xen-3.0" ++ .ascii ",VIRT_BASE=0x" ++ utoh __START_KERNEL_map ++ .ascii ",ELF_PADDR_OFFSET=0x" ++ utoh __START_KERNEL_map ++ .ascii ",VIRT_ENTRY=0x" ++ utoh (__START_KERNEL_map + __PHYSICAL_START + VIRT_ENTRY_OFFSET) ++ .ascii ",HYPERCALL_PAGE=0x" ++ utoh (phys_hypercall_page >> PAGE_SHIFT) ++ .ascii ",FEATURES=writable_page_tables" ++ .ascii "|writable_descriptor_tables" ++ .ascii "|auto_translated_physmap" ++ .ascii "|supervisor_mode_kernel" ++ .ascii ",LOADER=generic" ++ .byte 0 ++#endif /* CONFIG_XEN_COMPAT <= 0x030002 */ ++ ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux") ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6") ++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0") ++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .quad, __START_KERNEL_map) ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, __START_KERNEL_map) ++#else ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, 0) ++#endif ++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad, startup_64) ++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad, hypercall_page) ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad, _PAGE_PRESENT,_PAGE_PRESENT) ++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") ++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic") ++ ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long, 1) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/head64.c +--- a/arch/x86_64/kernel/head64.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/head64.c Wed Aug 08 16:25:28 2007 -0300 +@@ -2,6 +2,9 @@ + * linux/arch/x86_64/kernel/head64.c -- prepare to run common code + * + * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Modified for Xen. + */ + + #include <linux/init.h> +@@ -10,6 +13,7 @@ + #include <linux/kernel.h> + #include <linux/string.h> + #include <linux/percpu.h> ++#include <linux/module.h> + + #include <asm/processor.h> + #include <asm/proto.h> +@@ -20,13 +24,19 @@ + #include <asm/pgtable.h> + #include <asm/sections.h> + ++#ifdef CONFIG_XEN ++unsigned long start_pfn; ++#endif ++ + /* Don't add a printk in there. printk relies on the PDA which is not initialized + yet. */ ++#ifndef CONFIG_XEN + static void __init clear_bss(void) + { + memset(__bss_start, 0, + (unsigned long) __bss_stop - (unsigned long) __bss_start); + } ++#endif + + #define NEW_CL_POINTER 0x228 /* Relative to real mode data */ + #define OLD_CL_MAGIC_ADDR 0x90020 +@@ -38,6 +48,7 @@ extern char saved_command_line[]; + + static void __init copy_bootdata(char *real_mode_data) + { ++#ifndef CONFIG_XEN + int new_data; + char * command_line; + +@@ -51,26 +62,68 @@ static void __init copy_bootdata(char *r + } + command_line = (char *) ((u64)(new_data)); + memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); ++#else ++ int max_cmdline; ++ ++ if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) ++ max_cmdline = COMMAND_LINE_SIZE; ++ memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline); ++ saved_command_line[max_cmdline-1] = '\0'; ++#endif + } ++ ++#ifdef CONFIG_XEN ++#include <xen/interface/memory.h> ++unsigned long *machine_to_phys_mapping; ++EXPORT_SYMBOL(machine_to_phys_mapping); ++unsigned int machine_to_phys_order; ++EXPORT_SYMBOL(machine_to_phys_order); ++#endif + + void __init x86_64_start_kernel(char * real_mode_data) + { ++#ifdef CONFIG_XEN ++ struct xen_machphys_mapping mapping; ++ unsigned long machine_to_phys_nr_ents; ++#endif + int i; + ++#ifdef CONFIG_XEN ++ setup_xen_features(); ++ ++ xen_start_info = (struct start_info *)real_mode_data; ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) ++ phys_to_machine_mapping = ++ (unsigned long *)xen_start_info->mfn_list; ++ start_pfn = (__pa(xen_start_info->pt_base) >> PAGE_SHIFT) + ++ xen_start_info->nr_pt_frames; ++ ++ machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START; ++ machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES; ++ if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { ++ machine_to_phys_mapping = (unsigned long *)mapping.v_start; ++ machine_to_phys_nr_ents = mapping.max_mfn + 1; ++ } ++ while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents ) ++ machine_to_phys_order++; ++ ++#else + /* clear bss before set_intr_gate with early_idt_handler */ + clear_bss(); + + for (i = 0; i < IDT_ENTRIES; i++) + set_intr_gate(i, early_idt_handler); + asm volatile("lidt %0" :: "m" (idt_descr)); +- ++#endif /* CONFIG_XEN */ + early_printk("Kernel alive\n"); + ++#ifndef CONFIG_XEN + /* + * switch to init_level4_pgt from boot_level4_pgt + */ + memcpy(init_level4_pgt, boot_level4_pgt, PTRS_PER_PGD*sizeof(pgd_t)); + asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt))); ++#endif + + for (i = 0; i < NR_CPUS; i++) + cpu_pda(i) = &boot_cpu_pda[i]; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/init_task.c +--- a/arch/x86_64/kernel/init_task.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/init_task.c Wed Aug 08 16:25:28 2007 -0300 +@@ -37,6 +37,8 @@ struct task_struct init_task = INIT_TASK + struct task_struct init_task = INIT_TASK(init_task); + + EXPORT_SYMBOL(init_task); ++ ++#ifndef CONFIG_X86_NO_TSS + /* + * per-CPU TSS segments. Threads are completely 'soft' on Linux, + * no more per-task TSS's. The TSS size is kept cacheline-aligned +@@ -50,5 +52,6 @@ DEFINE_PER_CPU(struct tss_struct, init_t + * debugging, no special alignment required. + */ + DEFINE_PER_CPU(struct orig_ist, orig_ist); ++#endif + + #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/io_apic-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/io_apic-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2221 @@ ++/* ++ * Intel IO-APIC support for multi-Pentium hosts. ++ * ++ * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo ++ * ++ * Many thanks to Stig Venaas for trying out countless experimental ++ * patches and reporting/debugging problems patiently! ++ * ++ * (c) 1999, Multiple IO-APIC support, developed by ++ * Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and ++ * Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>, ++ * further tested and cleaned up by Zach Brown <zab@redhat.com> ++ * and Ingo Molnar <mingo@redhat.com> ++ * ++ * Fixes ++ * Maciej W. Rozycki : Bits for genuine 82489DX APICs; ++ * thanks to Eric Gilmore ++ * and Rolf G. Tews ++ * for testing these extensively ++ * Paul Diefenbaugh : Added full ACPI support ++ */ ++ ++#include <linux/mm.h> ++#include <linux/interrupt.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/smp_lock.h> ++#include <linux/pci.h> ++#include <linux/mc146818rtc.h> ++#include <linux/acpi.h> ++#include <linux/sysdev.h> ++#include <linux/msi.h> ++#include <linux/htirq.h> ++#ifdef CONFIG_ACPI ++#include <acpi/acpi_bus.h> ++#endif ++ ++#include <asm/io.h> ++#include <asm/smp.h> ++#include <asm/desc.h> ++#include <asm/proto.h> ++#include <asm/mach_apic.h> ++#include <asm/acpi.h> ++#include <asm/dma.h> ++#include <asm/nmi.h> ++#include <asm/msidef.h> ++#include <asm/hypertransport.h> ++ ++DEFINE_PER_CPU(vector_irq_t, vector_irq) = { ++ [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1, ++ [FIRST_EXTERNAL_VECTOR + 0] = 0, ++ [FIRST_EXTERNAL_VECTOR + 1] = 1, ++ [FIRST_EXTERNAL_VECTOR + 2] = 2, ++ [FIRST_EXTERNAL_VECTOR + 3] = 3, ++ [FIRST_EXTERNAL_VECTOR + 4] = 4, ++ [FIRST_EXTERNAL_VECTOR + 5] = 5, ++ [FIRST_EXTERNAL_VECTOR + 6] = 6, ++ [FIRST_EXTERNAL_VECTOR + 7] = 7, ++ [FIRST_EXTERNAL_VECTOR + 8] = 8, ++ [FIRST_EXTERNAL_VECTOR + 9] = 9, ++ [FIRST_EXTERNAL_VECTOR + 10] = 10, ++ [FIRST_EXTERNAL_VECTOR + 11] = 11, ++ [FIRST_EXTERNAL_VECTOR + 12] = 12, ++ [FIRST_EXTERNAL_VECTOR + 13] = 13, ++ [FIRST_EXTERNAL_VECTOR + 14] = 14, ++ [FIRST_EXTERNAL_VECTOR + 15] = 15, ++ [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1 ++}; ++ ++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result); ++ ++#define __apicdebuginit __init ++ ++int sis_apic_bug; /* not actually supported, dummy for compile */ ++ ++static int no_timer_check; ++ ++static int disable_timer_pin_1 __initdata; ++ ++int timer_over_8254 __initdata = 1; ++ ++#ifndef CONFIG_XEN ++/* Where if anywhere is the i8259 connect in external int mode */ ++static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; ++#endif ++ ++static DEFINE_SPINLOCK(ioapic_lock); ++DEFINE_SPINLOCK(vector_lock); ++ ++/* ++ * # of IRQ routing registers ++ */ ++int nr_ioapic_registers[MAX_IO_APICS]; ++ ++/* ++ * Rough estimation of how many shared IRQs there are, can ++ * be changed anytime. ++ */ ++#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS ++#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) ++ ++/* ++ * This is performance-critical, we want to do it O(1) ++ * ++ * the indexing order of this array favors 1:1 mappings ++ * between pins and IRQs. ++ */ ++ ++static struct irq_pin_list { ++ short apic, pin, next; ++} irq_2_pin[PIN_MAP_SIZE]; ++ ++struct io_apic { ++ unsigned int index; ++ unsigned int unused[3]; ++ unsigned int data; ++}; ++ ++static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ++{ ++ return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) ++ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); ++} ++ ++static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ return readl(&io_apic->data); ++} ++ ++static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++} ++ ++/* ++ * Re-write a value: to be used for read-modify-write ++ * cycles where the read already set up the index register. ++ */ ++static inline void io_apic_modify(unsigned int apic, unsigned int value) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(value, &io_apic->data); ++} ++ ++/* ++ * Synchronize the IO-APIC and the CPU by doing ++ * a dummy read from the IO-APIC ++ */ ++static inline void io_apic_sync(unsigned int apic) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ readl(&io_apic->data); ++} ++ ++#ifdef CONFIG_XEN ++ ++#include <xen/interface/xen.h> ++#include <xen/interface/physdev.h> ++ ++/* Fake i8259 */ ++#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq))) ++#define disable_8259A_irq(_irq) ((void)0) ++#define i8259A_irq_pending(_irq) (0) ++ ++unsigned long io_apic_irqs; ++ ++static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) ++{ ++ struct physdev_apic apic_op; ++ int ret; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); ++ if (ret) ++ return ret; ++ return apic_op.value; ++} ++ ++static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ struct physdev_apic apic_op; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ apic_op.value = value; ++ HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op); ++} ++ ++#define io_apic_read(a,r) xen_io_apic_read(a,r) ++#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v) ++ ++#define clear_IO_APIC() ((void)0) ++#endif ++ ++#ifndef CONFIG_XEN ++#define __DO_ACTION(R, ACTION, FINAL) \ ++ \ ++{ \ ++ int pin; \ ++ struct irq_pin_list *entry = irq_2_pin + irq; \ ++ \ ++ BUG_ON(irq >= NR_IRQS); \ ++ for (;;) { \ ++ unsigned int reg; \ ++ pin = entry->pin; \ ++ if (pin == -1) \ ++ break; \ ++ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ ++ reg ACTION; \ ++ io_apic_modify(entry->apic, reg); \ ++ if (!entry->next) \ ++ break; \ ++ entry = irq_2_pin + entry->next; \ ++ } \ ++ FINAL; \ ++} ++#endif /* !CONFIG_XEN */ ++ ++union entry_union { ++ struct { u32 w1, w2; }; ++ struct IO_APIC_route_entry entry; ++}; ++ ++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) ++{ ++ union entry_union eu; ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin); ++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ return eu.entry; ++} ++ ++/* ++ * When we write a new IO APIC routing entry, we need to write the high ++ * word first! If the mask bit in the low word is clear, we will enable ++ * the interrupt, and we need to make sure the entry is fully populated ++ * before that happens. ++ */ ++static void ++__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ union entry_union eu; ++ eu.entry = e; ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++} ++ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, e); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++/* ++ * When we mask an IO APIC routing entry, we need to write the low ++ * word first, in order to set the mask bit before we change the ++ * high bits! ++ */ ++#ifndef CONFIG_XEN ++static void ioapic_mask_entry(int apic, int pin) ++{ ++ unsigned long flags; ++ union entry_union eu = { .entry.mask = 1 }; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++#ifdef CONFIG_SMP ++static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) ++{ ++ int apic, pin; ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ ++ BUG_ON(irq >= NR_IRQS); ++ for (;;) { ++ unsigned int reg; ++ apic = entry->apic; ++ pin = entry->pin; ++ if (pin == -1) ++ break; ++ io_apic_write(apic, 0x11 + pin*2, dest); ++ reg = io_apic_read(apic, 0x10 + pin*2); ++ reg &= ~0x000000ff; ++ reg |= vector; ++ io_apic_modify(apic, reg); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++} ++ ++static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ++{ ++ unsigned long flags; ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ /* ++ * Only the high 8 bits are valid. ++ */ ++ dest = SET_APIC_LOGICAL_ID(dest); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __target_IO_APIC_irq(irq, dest, vector); ++ set_native_irq_info(irq, mask); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++#endif ++#endif /* !CONFIG_XEN */ ++ ++/* ++ * The common case is 1:1 IRQ<->pin mappings. Sometimes there are ++ * shared ISA-space IRQs, so we have to support them. We are super ++ * fast in the common case, and fast for shared ISA-space IRQs. ++ */ ++static void add_pin_to_irq(unsigned int irq, int apic, int pin) ++{ ++ static int first_free_entry = NR_IRQS; ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ ++ BUG_ON(irq >= NR_IRQS); ++ while (entry->next) ++ entry = irq_2_pin + entry->next; ++ ++ if (entry->pin != -1) { ++ entry->next = first_free_entry; ++ entry = irq_2_pin + entry->next; ++ if (++first_free_entry >= PIN_MAP_SIZE) ++ panic("io_apic.c: ran out of irq_2_pin entries!"); ++ } ++ entry->apic = apic; ++ entry->pin = pin; ++} ++ ++#ifndef CONFIG_XEN ++ ++#define DO_ACTION(name,R,ACTION, FINAL) \ ++ \ ++ static void name##_IO_APIC_irq (unsigned int irq) \ ++ __DO_ACTION(R, ACTION, FINAL) ++ ++DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) ++ /* mask = 1 */ ++DO_ACTION( __unmask, 0, &= 0xfffeffff, ) ++ /* mask = 0 */ ++ ++static void mask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __mask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++static void unmask_IO_APIC_irq (unsigned int irq) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __unmask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ++{ ++ struct IO_APIC_route_entry entry; ++ ++ /* Check delivery_mode to be sure we're not clearing an SMI pin */ ++ entry = ioapic_read_entry(apic, pin); ++ if (entry.delivery_mode == dest_SMI) ++ return; ++ /* ++ * Disable it in the IO-APIC irq-routing table: ++ */ ++ ioapic_mask_entry(apic, pin); ++} ++ ++static void clear_IO_APIC (void) ++{ ++ int apic, pin; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) ++ clear_IO_APIC_pin(apic, pin); ++} ++ ++#endif /* !CONFIG_XEN */ ++int skip_ioapic_setup; ++int ioapic_force; ++ ++/* dummy parsing: see setup.c */ ++ ++static int __init disable_ioapic_setup(char *str) ++{ ++ skip_ioapic_setup = 1; ++ return 0; ++} ++early_param("noapic", disable_ioapic_setup); ++ ++/* Actually the next is obsolete, but keep it for paranoid reasons -AK */ ++static int __init disable_timer_pin_setup(char *arg) ++{ ++ disable_timer_pin_1 = 1; ++ return 1; ++} ++__setup("disable_timer_pin_1", disable_timer_pin_setup); ++ ++static int __init setup_disable_8254_timer(char *s) ++{ ++ timer_over_8254 = -1; ++ return 1; ++} ++static int __init setup_enable_8254_timer(char *s) ++{ ++ timer_over_8254 = 2; ++ return 1; ++} ++ ++__setup("disable_8254_timer", setup_disable_8254_timer); ++__setup("enable_8254_timer", setup_enable_8254_timer); ++ ++ ++/* ++ * Find the IRQ entry number of a certain pin. ++ */ ++static int find_irq_entry(int apic, int pin, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) ++ if (mp_irqs[i].mpc_irqtype == type && ++ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || ++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && ++ mp_irqs[i].mpc_dstirq == pin) ++ return i; ++ ++ return -1; ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * Find the pin to which IRQ[irq] (ISA) is connected ++ */ ++static int __init find_isa_irq_pin(int irq, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ if (test_bit(lbus, mp_bus_not_pci) && ++ (mp_irqs[i].mpc_irqtype == type) && ++ (mp_irqs[i].mpc_srcbusirq == irq)) ++ ++ return mp_irqs[i].mpc_dstirq; ++ } ++ return -1; ++} ++ ++static int __init find_isa_irq_apic(int irq, int type) ++{ ++ int i; ++ ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ if (test_bit(lbus, mp_bus_not_pci) && ++ (mp_irqs[i].mpc_irqtype == type) && ++ (mp_irqs[i].mpc_srcbusirq == irq)) ++ break; ++ } ++ if (i < mp_irq_entries) { ++ int apic; ++ for(apic = 0; apic < nr_ioapics; apic++) { ++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) ++ return apic; ++ } ++ } ++ ++ return -1; ++} ++#endif ++ ++/* ++ * Find a specific PCI IRQ entry. ++ * Not an __init, possibly needed by modules ++ */ ++static int pin_2_irq(int idx, int apic, int pin); ++ ++int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ++{ ++ int apic, i, best_guess = -1; ++ ++ apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", ++ bus, slot, pin); ++ if (mp_bus_id_to_pci_bus[bus] == -1) { ++ apic_printk(APIC_VERBOSE, "PCI BIOS passed nonexistent PCI bus %d!\n", bus); ++ return -1; ++ } ++ for (i = 0; i < mp_irq_entries; i++) { ++ int lbus = mp_irqs[i].mpc_srcbus; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || ++ mp_irqs[i].mpc_dstapic == MP_APIC_ALL) ++ break; ++ ++ if (!test_bit(lbus, mp_bus_not_pci) && ++ !mp_irqs[i].mpc_irqtype && ++ (bus == lbus) && ++ (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { ++ int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); ++ ++ if (!(apic || IO_APIC_IRQ(irq))) ++ continue; ++ ++ if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) ++ return irq; ++ /* ++ * Use the first all-but-pin matching entry as a ++ * best-guess fuzzy result for broken mptables. ++ */ ++ if (best_guess < 0) ++ best_guess = irq; ++ } ++ } ++ BUG_ON(best_guess >= NR_IRQS); ++ return best_guess; ++} ++ ++/* ISA interrupts are always polarity zero edge triggered, ++ * when listed as conforming in the MP table. */ ++ ++#define default_ISA_trigger(idx) (0) ++#define default_ISA_polarity(idx) (0) ++ ++/* PCI interrupts are always polarity one level triggered, ++ * when listed as conforming in the MP table. */ ++ ++#define default_PCI_trigger(idx) (1) ++#define default_PCI_polarity(idx) (1) ++ ++static int __init MPBIOS_polarity(int idx) ++{ ++ int bus = mp_irqs[idx].mpc_srcbus; ++ int polarity; ++ ++ /* ++ * Determine IRQ line polarity (high active or low active): ++ */ ++ switch (mp_irqs[idx].mpc_irqflag & 3) ++ { ++ case 0: /* conforms, ie. bus-type dependent polarity */ ++ if (test_bit(bus, mp_bus_not_pci)) ++ polarity = default_ISA_polarity(idx); ++ else ++ polarity = default_PCI_polarity(idx); ++ break; ++ case 1: /* high active */ ++ { ++ polarity = 0; ++ break; ++ } ++ case 2: /* reserved */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ polarity = 1; ++ break; ++ } ++ case 3: /* low active */ ++ { ++ polarity = 1; ++ break; ++ } ++ default: /* invalid */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ polarity = 1; ++ break; ++ } ++ } ++ return polarity; ++} ++ ++static int MPBIOS_trigger(int idx) ++{ ++ int bus = mp_irqs[idx].mpc_srcbus; ++ int trigger; ++ ++ /* ++ * Determine IRQ trigger mode (edge or level sensitive): ++ */ ++ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) ++ { ++ case 0: /* conforms, ie. bus-type dependent */ ++ if (test_bit(bus, mp_bus_not_pci)) ++ trigger = default_ISA_trigger(idx); ++ else ++ trigger = default_PCI_trigger(idx); ++ break; ++ case 1: /* edge */ ++ { ++ trigger = 0; ++ break; ++ } ++ case 2: /* reserved */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ trigger = 1; ++ break; ++ } ++ case 3: /* level */ ++ { ++ trigger = 1; ++ break; ++ } ++ default: /* invalid */ ++ { ++ printk(KERN_WARNING "broken BIOS!!\n"); ++ trigger = 0; ++ break; ++ } ++ } ++ return trigger; ++} ++ ++static inline int irq_polarity(int idx) ++{ ++ return MPBIOS_polarity(idx); ++} ++ ++static inline int irq_trigger(int idx) ++{ ++ return MPBIOS_trigger(idx); ++} ++ ++static int pin_2_irq(int idx, int apic, int pin) ++{ ++ int irq, i; ++ int bus = mp_irqs[idx].mpc_srcbus; ++ ++ /* ++ * Debugging check, we are in big trouble if this message pops up! ++ */ ++ if (mp_irqs[idx].mpc_dstirq != pin) ++ printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); ++ ++ if (test_bit(bus, mp_bus_not_pci)) { ++ irq = mp_irqs[idx].mpc_srcbusirq; ++ } else { ++ /* ++ * PCI IRQs are mapped in order ++ */ ++ i = irq = 0; ++ while (i < apic) ++ irq += nr_ioapic_registers[i++]; ++ irq += pin; ++ } ++ BUG_ON(irq >= NR_IRQS); ++ return irq; ++} ++ ++static inline int IO_APIC_irq_trigger(int irq) ++{ ++ int apic, idx, pin; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ idx = find_irq_entry(apic,pin,mp_INT); ++ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) ++ return irq_trigger(idx); ++ } ++ } ++ /* ++ * nonexistent IRQs are edge default ++ */ ++ return 0; ++} ++ ++/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ ++static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; ++ ++static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = { ++ [0] = CPU_MASK_ALL, ++ [1] = CPU_MASK_ALL, ++ [2] = CPU_MASK_ALL, ++ [3] = CPU_MASK_ALL, ++ [4] = CPU_MASK_ALL, ++ [5] = CPU_MASK_ALL, ++ [6] = CPU_MASK_ALL, ++ [7] = CPU_MASK_ALL, ++ [8] = CPU_MASK_ALL, ++ [9] = CPU_MASK_ALL, ++ [10] = CPU_MASK_ALL, ++ [11] = CPU_MASK_ALL, ++ [12] = CPU_MASK_ALL, ++ [13] = CPU_MASK_ALL, ++ [14] = CPU_MASK_ALL, ++ [15] = CPU_MASK_ALL, ++}; ++ ++ ++static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) ++{ ++ struct physdev_irq irq_op; ++ int vector; ++ ++ if (irq_vector[irq] > 0) { ++ cpus_and(*result, irq_domain[irq], mask); ++ return irq_vector[irq]; ++ } ++ ++ irq_op.irq = irq; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) ++ return -ENOSPC; ++ ++ vector = irq_op.vector; ++ per_cpu(vector_irq,0)[vector] = irq; ++ irq_vector[irq] = vector; ++ cpus_and(*result, irq_domain[irq], mask); ++ ++ return vector; ++} ++ ++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) ++{ ++ int vector; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = __assign_irq_vector(irq, mask, result); ++ spin_unlock_irqrestore(&vector_lock, flags); ++ return vector; ++} ++ ++static void __clear_irq_vector(int irq) ++{ ++ cpumask_t mask; ++ int cpu, vector; ++ ++ BUG_ON(!irq_vector[irq]); ++ ++ vector = irq_vector[irq]; ++ cpus_and(mask, irq_domain[irq], cpu_online_map); ++ for_each_cpu_mask(cpu, mask) ++ per_cpu(vector_irq, cpu)[vector] = -1; ++ ++ irq_vector[irq] = 0; ++ irq_domain[irq] = CPU_MASK_NONE; ++} ++ ++void __setup_vector_irq(int cpu) ++{ ++ /* Initialize vector_irq on a new cpu */ ++ /* This function must be called with vector_lock held */ ++ int irq, vector; ++ ++ /* Mark the inuse vectors */ ++ for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) { ++ if (!cpu_isset(cpu, irq_domain[irq])) ++ continue; ++ vector = irq_vector[irq]; ++ per_cpu(vector_irq, cpu)[vector] = irq; ++ } ++ /* Mark the free vectors */ ++ for (vector = 0; vector < NR_VECTORS; ++vector) { ++ irq = per_cpu(vector_irq, cpu)[vector]; ++ if (irq < 0) ++ continue; ++ if (!cpu_isset(cpu, irq_domain[irq])) ++ per_cpu(vector_irq, cpu)[vector] = -1; ++ } ++} ++ ++ ++extern void (*interrupt[NR_IRQS])(void); ++ ++#ifndef CONFIG_XEN ++static struct irq_chip ioapic_chip; ++ ++#define IOAPIC_AUTO -1 ++#define IOAPIC_EDGE 0 ++#define IOAPIC_LEVEL 1 ++ ++static void ioapic_register_intr(int irq, int vector, unsigned long trigger) ++{ ++ if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || ++ trigger == IOAPIC_LEVEL) ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_fasteoi_irq, "fasteoi"); ++ else { ++ irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_edge_irq, "edge"); ++ } ++} ++#else ++#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0) ++#endif /* !CONFIG_XEN */ ++ ++static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq) ++{ ++ struct IO_APIC_route_entry entry; ++ int vector; ++ unsigned long flags; ++ ++ ++ /* ++ * add it to the IO-APIC irq-routing table: ++ */ ++ memset(&entry,0,sizeof(entry)); ++ ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.dest_mode = INT_DEST_MODE; ++ entry.mask = 0; /* enable IRQ */ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ ++ entry.trigger = irq_trigger(idx); ++ entry.polarity = irq_polarity(idx); ++ ++ if (irq_trigger(idx)) { ++ entry.trigger = 1; ++ entry.mask = 1; ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ } ++ ++ if (!apic && !IO_APIC_IRQ(irq)) ++ return; ++ ++ if (IO_APIC_IRQ(irq)) { ++ cpumask_t mask; ++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask); ++ if (vector < 0) ++ return; ++ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); ++ entry.vector = vector; ++ ++ ioapic_register_intr(irq, vector, IOAPIC_AUTO); ++ if (!apic && (irq < 16)) ++ disable_8259A_irq(irq); ++ } ++ ++ ioapic_write_entry(apic, pin, entry); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ set_native_irq_info(irq, TARGET_CPUS); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++} ++ ++static void __init setup_IO_APIC_irqs(void) ++{ ++ int apic, pin, idx, irq, first_notcon = 1; ++ ++ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ ++ idx = find_irq_entry(apic,pin,mp_INT); ++ if (idx == -1) { ++ if (first_notcon) { ++ apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); ++ first_notcon = 0; ++ } else ++ apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin); ++ continue; ++ } ++ ++ irq = pin_2_irq(idx, apic, pin); ++ add_pin_to_irq(irq, apic, pin); ++ ++ setup_IO_APIC_irq(apic, pin, idx, irq); ++ ++ } ++ } ++ ++ if (!first_notcon) ++ apic_printk(APIC_VERBOSE," not connected.\n"); ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * Set up the 8259A-master output pin as broadcast to all ++ * CPUs. ++ */ ++static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) ++{ ++ struct IO_APIC_route_entry entry; ++ unsigned long flags; ++ ++ memset(&entry,0,sizeof(entry)); ++ ++ disable_8259A_irq(0); ++ ++ /* mask LVT0 */ ++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); ++ ++ /* ++ * We use logical delivery to get the timer IRQ ++ * to the first CPU. ++ */ ++ entry.dest_mode = INT_DEST_MODE; ++ entry.mask = 0; /* unmask IRQ now */ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.polarity = 0; ++ entry.trigger = 0; ++ entry.vector = vector; ++ ++ /* ++ * The timer IRQ doesn't have to know that behind the ++ * scene we have a 8259A-master in AEOI mode ... ++ */ ++ set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge"); ++ ++ /* ++ * Add it to the IO-APIC irq-routing table: ++ */ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); ++ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ enable_8259A_irq(0); ++} ++ ++void __init UNEXPECTED_IO_APIC(void) ++{ ++} ++ ++void __apicdebuginit print_IO_APIC(void) ++{ ++ int apic, i; ++ union IO_APIC_reg_00 reg_00; ++ union IO_APIC_reg_01 reg_01; ++ union IO_APIC_reg_02 reg_02; ++ unsigned long flags; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); ++ for (i = 0; i < nr_ioapics; i++) ++ printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", ++ mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); ++ ++ /* ++ * We are a bit conservative about what we expect. We have to ++ * know about every hardware change ASAP. ++ */ ++ printk(KERN_INFO "testing the IO APIC.......................\n"); ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(apic, 0); ++ reg_01.raw = io_apic_read(apic, 1); ++ if (reg_01.bits.version >= 0x10) ++ reg_02.raw = io_apic_read(apic, 2); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ printk("\n"); ++ printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); ++ printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); ++ printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); ++ if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ ++ printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); ++ printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); ++ if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ ++ (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ ++ (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ ++ (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ ++ (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ ++ (reg_01.bits.entries != 0x2E) && ++ (reg_01.bits.entries != 0x3F) && ++ (reg_01.bits.entries != 0x03) ++ ) ++ UNEXPECTED_IO_APIC(); ++ ++ printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); ++ printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); ++ if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ ++ (reg_01.bits.version != 0x02) && /* 82801BA IO-APICs (ICH2) */ ++ (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ ++ (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ ++ (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ ++ (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ ++ ) ++ UNEXPECTED_IO_APIC(); ++ if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ ++ if (reg_01.bits.version >= 0x10) { ++ printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); ++ printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); ++ if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) ++ UNEXPECTED_IO_APIC(); ++ } ++ ++ printk(KERN_DEBUG ".... IRQ redirection table:\n"); ++ ++ printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" ++ " Stat Dest Deli Vect: \n"); ++ ++ for (i = 0; i <= reg_01.bits.entries; i++) { ++ struct IO_APIC_route_entry entry; ++ ++ entry = ioapic_read_entry(apic, i); ++ ++ printk(KERN_DEBUG " %02x %03X %02X ", ++ i, ++ entry.dest.logical.logical_dest, ++ entry.dest.physical.physical_dest ++ ); ++ ++ printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", ++ entry.mask, ++ entry.trigger, ++ entry.irr, ++ entry.polarity, ++ entry.delivery_status, ++ entry.dest_mode, ++ entry.delivery_mode, ++ entry.vector ++ ); ++ } ++ } ++ printk(KERN_DEBUG "IRQ to pin mappings:\n"); ++ for (i = 0; i < NR_IRQS; i++) { ++ struct irq_pin_list *entry = irq_2_pin + i; ++ if (entry->pin < 0) ++ continue; ++ printk(KERN_DEBUG "IRQ%d ", i); ++ for (;;) { ++ printk("-> %d:%d", entry->apic, entry->pin); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++ printk("\n"); ++ } ++ ++ printk(KERN_INFO ".................................... done.\n"); ++ ++ return; ++} ++ ++#if 0 ++ ++static __apicdebuginit void print_APIC_bitfield (int base) ++{ ++ unsigned int v; ++ int i, j; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); ++ for (i = 0; i < 8; i++) { ++ v = apic_read(base + i*0x10); ++ for (j = 0; j < 32; j++) { ++ if (v & (1<<j)) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ printk("\n"); ++ } ++} ++ ++void __apicdebuginit print_local_APIC(void * dummy) ++{ ++ unsigned int v, ver, maxlvt; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", ++ smp_processor_id(), hard_smp_processor_id()); ++ v = apic_read(APIC_ID); ++ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v)); ++ v = apic_read(APIC_LVR); ++ printk(KERN_INFO "... APIC VERSION: %08x\n", v); ++ ver = GET_APIC_VERSION(v); ++ maxlvt = get_maxlvt(); ++ ++ v = apic_read(APIC_TASKPRI); ++ printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); ++ ++ v = apic_read(APIC_ARBPRI); ++ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, ++ v & APIC_ARBPRI_MASK); ++ v = apic_read(APIC_PROCPRI); ++ printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); ++ ++ v = apic_read(APIC_EOI); ++ printk(KERN_DEBUG "... APIC EOI: %08x\n", v); ++ v = apic_read(APIC_RRR); ++ printk(KERN_DEBUG "... APIC RRR: %08x\n", v); ++ v = apic_read(APIC_LDR); ++ printk(KERN_DEBUG "... APIC LDR: %08x\n", v); ++ v = apic_read(APIC_DFR); ++ printk(KERN_DEBUG "... APIC DFR: %08x\n", v); ++ v = apic_read(APIC_SPIV); ++ printk(KERN_DEBUG "... APIC SPIV: %08x\n", v); ++ ++ printk(KERN_DEBUG "... APIC ISR field:\n"); ++ print_APIC_bitfield(APIC_ISR); ++ printk(KERN_DEBUG "... APIC TMR field:\n"); ++ print_APIC_bitfield(APIC_TMR); ++ printk(KERN_DEBUG "... APIC IRR field:\n"); ++ print_APIC_bitfield(APIC_IRR); ++ ++ v = apic_read(APIC_ESR); ++ printk(KERN_DEBUG "... APIC ESR: %08x\n", v); ++ ++ v = apic_read(APIC_ICR); ++ printk(KERN_DEBUG "... APIC ICR: %08x\n", v); ++ v = apic_read(APIC_ICR2); ++ printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); ++ ++ v = apic_read(APIC_LVTT); ++ printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); ++ ++ if (maxlvt > 3) { /* PC is LVT#4. */ ++ v = apic_read(APIC_LVTPC); ++ printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); ++ } ++ v = apic_read(APIC_LVT0); ++ printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); ++ v = apic_read(APIC_LVT1); ++ printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); ++ ++ if (maxlvt > 2) { /* ERR is LVT#3. */ ++ v = apic_read(APIC_LVTERR); ++ printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); ++ } ++ ++ v = apic_read(APIC_TMICT); ++ printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); ++ v = apic_read(APIC_TMCCT); ++ printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); ++ v = apic_read(APIC_TDCR); ++ printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); ++ printk("\n"); ++} ++ ++void print_all_local_APICs (void) ++{ ++ on_each_cpu(print_local_APIC, NULL, 1, 1); ++} ++ ++void __apicdebuginit print_PIC(void) ++{ ++ unsigned int v; ++ unsigned long flags; ++ ++ if (apic_verbosity == APIC_QUIET) ++ return; ++ ++ printk(KERN_DEBUG "\nprinting PIC contents\n"); ++ ++ spin_lock_irqsave(&i8259A_lock, flags); ++ ++ v = inb(0xa1) << 8 | inb(0x21); ++ printk(KERN_DEBUG "... PIC IMR: %04x\n", v); ++ ++ v = inb(0xa0) << 8 | inb(0x20); ++ printk(KERN_DEBUG "... PIC IRR: %04x\n", v); ++ ++ outb(0x0b,0xa0); ++ outb(0x0b,0x20); ++ v = inb(0xa0) << 8 | inb(0x20); ++ outb(0x0a,0xa0); ++ outb(0x0a,0x20); ++ ++ spin_unlock_irqrestore(&i8259A_lock, flags); ++ ++ printk(KERN_DEBUG "... PIC ISR: %04x\n", v); ++ ++ v = inb(0x4d1) << 8 | inb(0x4d0); ++ printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); ++} ++ ++#endif /* 0 */ ++ ++#else ++void __init print_IO_APIC(void) { } ++#endif /* !CONFIG_XEN */ ++ ++static void __init enable_IO_APIC(void) ++{ ++ union IO_APIC_reg_01 reg_01; ++#ifndef CONFIG_XEN ++ int i8259_apic, i8259_pin; ++#endif ++ int i, apic; ++ unsigned long flags; ++ ++ for (i = 0; i < PIN_MAP_SIZE; i++) { ++ irq_2_pin[i].pin = -1; ++ irq_2_pin[i].next = 0; ++ } ++ ++ /* ++ * The number of IO-APIC IRQ registers (== #pins): ++ */ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(apic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ nr_ioapic_registers[apic] = reg_01.bits.entries+1; ++ } ++#ifndef CONFIG_XEN ++ for(apic = 0; apic < nr_ioapics; apic++) { ++ int pin; ++ /* See if any of the pins is in ExtINT mode */ ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ struct IO_APIC_route_entry entry; ++ entry = ioapic_read_entry(apic, pin); ++ ++ /* If the interrupt line is enabled and in ExtInt mode ++ * I have found the pin where the i8259 is connected. ++ */ ++ if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) { ++ ioapic_i8259.apic = apic; ++ ioapic_i8259.pin = pin; ++ goto found_i8259; ++ } ++ } ++ } ++ found_i8259: ++ /* Look to see what if the MP table has reported the ExtINT */ ++ i8259_pin = find_isa_irq_pin(0, mp_ExtINT); ++ i8259_apic = find_isa_irq_apic(0, mp_ExtINT); ++ /* Trust the MP table if nothing is setup in the hardware */ ++ if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) { ++ printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n"); ++ ioapic_i8259.pin = i8259_pin; ++ ioapic_i8259.apic = i8259_apic; ++ } ++ /* Complain if the MP table and the hardware disagree */ ++ if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) && ++ (i8259_pin >= 0) && (ioapic_i8259.pin >= 0)) ++ { ++ printk(KERN_WARNING "ExtINT in hardware and MP table differ\n"); ++ } ++#endif ++ ++ /* ++ * Do not trust the IO-APIC being empty at bootup ++ */ ++ clear_IO_APIC(); ++} ++ ++/* ++ * Not an __init, needed by the reboot code ++ */ ++void disable_IO_APIC(void) ++{ ++ /* ++ * Clear the IO-APIC before rebooting: ++ */ ++ clear_IO_APIC(); ++ ++#ifndef CONFIG_XEN ++ /* ++ * If the i8259 is routed through an IOAPIC ++ * Put that IOAPIC in virtual wire mode ++ * so legacy interrupts can be delivered. ++ */ ++ if (ioapic_i8259.pin != -1) { ++ struct IO_APIC_route_entry entry; ++ ++ memset(&entry, 0, sizeof(entry)); ++ entry.mask = 0; /* Enabled */ ++ entry.trigger = 0; /* Edge */ ++ entry.irr = 0; ++ entry.polarity = 0; /* High */ ++ entry.delivery_status = 0; ++ entry.dest_mode = 0; /* Physical */ ++ entry.delivery_mode = dest_ExtINT; /* ExtInt */ ++ entry.vector = 0; ++ entry.dest.physical.physical_dest = ++ GET_APIC_ID(apic_read(APIC_ID)); ++ ++ /* ++ * Add it to the IO-APIC irq-routing table: ++ */ ++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); ++ } ++ ++ disconnect_bsp_APIC(ioapic_i8259.pin != -1); ++#endif ++} ++ ++/* ++ * There is a nasty bug in some older SMP boards, their mptable lies ++ * about the timer IRQ. We do the following to work around the situation: ++ * ++ * - timer IRQ defaults to IO-APIC IRQ ++ * - if this function detects that timer IRQs are defunct, then we fall ++ * back to ISA timer IRQs ++ */ ++#ifndef CONFIG_XEN ++static int __init timer_irq_works(void) ++{ ++ unsigned long t1 = jiffies; ++ ++ local_irq_enable(); ++ /* Let ten ticks pass... */ ++ mdelay((10 * 1000) / HZ); ++ ++ /* ++ * Expect a few ticks at least, to be sure some possible ++ * glue logic does not lock up after one or two first ++ * ticks in a non-ExtINT mode. Also the local APIC ++ * might have cached one ExtINT interrupt. Finally, at ++ * least one tick may be lost due to delays. ++ */ ++ ++ /* jiffies wrap? */ ++ if (jiffies - t1 > 4) ++ return 1; ++ return 0; ++} ++ ++/* ++ * In the SMP+IOAPIC case it might happen that there are an unspecified ++ * number of pending IRQ events unhandled. These cases are very rare, ++ * so we 'resend' these IRQs via IPIs, to the same CPU. It's much ++ * better to do it this way as thus we do not have to be aware of ++ * 'pending' interrupts in the IRQ path, except at this point. ++ */ ++/* ++ * Edge triggered needs to resend any interrupt ++ * that was delayed but this is now handled in the device ++ * independent code. ++ */ ++ ++/* ++ * Starting up a edge-triggered IO-APIC interrupt is ++ * nasty - we need to make sure that we get the edge. ++ * If it is already asserted for some reason, we need ++ * return 1 to indicate that is was pending. ++ * ++ * This is not complete - we should be able to fake ++ * an edge even if it isn't on the 8259A... ++ */ ++ ++static unsigned int startup_ioapic_irq(unsigned int irq) ++{ ++ int was_pending = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ if (irq < 16) { ++ disable_8259A_irq(irq); ++ if (i8259A_irq_pending(irq)) ++ was_pending = 1; ++ } ++ __unmask_IO_APIC_irq(irq); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return was_pending; ++} ++ ++static int ioapic_retrigger_irq(unsigned int irq) ++{ ++ cpumask_t mask; ++ unsigned vector; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = irq_vector[irq]; ++ cpus_clear(mask); ++ cpu_set(first_cpu(irq_domain[irq]), mask); ++ ++ send_IPI_mask(mask, vector); ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ return 1; ++} ++ ++/* ++ * Level and edge triggered IO-APIC interrupts need different handling, ++ * so we use two separate IRQ descriptors. Edge triggered IRQs can be ++ * handled with the level-triggered descriptor, but that one has slightly ++ * more overhead. Level-triggered interrupts cannot be handled with the ++ * edge-triggered handler, without risking IRQ storms and other ugly ++ * races. ++ */ ++ ++static void ack_apic_edge(unsigned int irq) ++{ ++ move_native_irq(irq); ++ ack_APIC_irq(); ++} ++ ++static void ack_apic_level(unsigned int irq) ++{ ++ int do_unmask_irq = 0; ++ ++#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) ++ /* If we are moving the irq we need to mask it */ ++ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { ++ do_unmask_irq = 1; ++ mask_IO_APIC_irq(irq); ++ } ++#endif ++ ++ /* ++ * We must acknowledge the irq before we move it or the acknowledge will ++ * not propogate properly. ++ */ ++ ack_APIC_irq(); ++ ++ /* Now we can move and renable the irq */ ++ move_masked_irq(irq); ++ if (unlikely(do_unmask_irq)) ++ unmask_IO_APIC_irq(irq); ++} ++ ++static struct irq_chip ioapic_chip __read_mostly = { ++ .name = "IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = mask_IO_APIC_irq, ++ .unmask = unmask_IO_APIC_irq, ++ .ack = ack_apic_edge, ++ .eoi = ack_apic_level, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ioapic_affinity_irq, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++#endif /* !CONFIG_XEN */ ++ ++static inline void init_IO_APIC_traps(void) ++{ ++ int irq; ++ ++ /* ++ * NOTE! The local APIC isn't very good at handling ++ * multiple interrupts at the same interrupt level. ++ * As the interrupt level is determined by taking the ++ * vector number and shifting that right by 4, we ++ * want to spread these out a bit so that they don't ++ * all fall in the same interrupt level. ++ * ++ * Also, we've got to be careful not to trash gate ++ * 0x80, because int 0x80 is hm, kind of importantish. ;) ++ */ ++ for (irq = 0; irq < NR_IRQS ; irq++) { ++ int tmp = irq; ++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { ++ /* ++ * Hmm.. We don't have an entry for this, ++ * so default to an old-fashioned 8259 ++ * interrupt if we can.. ++ */ ++ if (irq < 16) ++ make_8259A_irq(irq); ++#ifndef CONFIG_XEN ++ else ++ /* Strange. Oh, well.. */ ++ irq_desc[irq].chip = &no_irq_chip; ++#endif ++ } ++ } ++} ++ ++#ifndef CONFIG_XEN ++static void enable_lapic_irq (unsigned int irq) ++{ ++ unsigned long v; ++ ++ v = apic_read(APIC_LVT0); ++ apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED); ++} ++ ++static void disable_lapic_irq (unsigned int irq) ++{ ++ unsigned long v; ++ ++ v = apic_read(APIC_LVT0); ++ apic_write(APIC_LVT0, v | APIC_LVT_MASKED); ++} ++ ++static void ack_lapic_irq (unsigned int irq) ++{ ++ ack_APIC_irq(); ++} ++ ++static void end_lapic_irq (unsigned int i) { /* nothing */ } ++ ++static struct hw_interrupt_type lapic_irq_type __read_mostly = { ++ .typename = "local-APIC-edge", ++ .startup = NULL, /* startup_irq() not used for IRQ0 */ ++ .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ ++ .enable = enable_lapic_irq, ++ .disable = disable_lapic_irq, ++ .ack = ack_lapic_irq, ++ .end = end_lapic_irq, ++}; ++ ++static void setup_nmi (void) ++{ ++ /* ++ * Dirty trick to enable the NMI watchdog ... ++ * We put the 8259A master into AEOI mode and ++ * unmask on all local APICs LVT0 as NMI. ++ * ++ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire') ++ * is from Maciej W. Rozycki - so we do not have to EOI from ++ * the NMI handler or the timer interrupt. ++ */ ++ printk(KERN_INFO "activating NMI Watchdog ..."); ++ ++ enable_NMI_through_LVT0(NULL); ++ ++ printk(" done.\n"); ++} ++ ++/* ++ * This looks a bit hackish but it's about the only one way of sending ++ * a few INTA cycles to 8259As and any associated glue logic. ICR does ++ * not support the ExtINT mode, unfortunately. We need to send these ++ * cycles as some i82489DX-based boards have glue logic that keeps the ++ * 8259A interrupt line asserted until INTA. --macro ++ */ ++static inline void unlock_ExtINT_logic(void) ++{ ++ int apic, pin, i; ++ struct IO_APIC_route_entry entry0, entry1; ++ unsigned char save_control, save_freq_select; ++ unsigned long flags; ++ ++ pin = find_isa_irq_pin(8, mp_INT); ++ apic = find_isa_irq_apic(8, mp_INT); ++ if (pin == -1) ++ return; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin); ++ *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ clear_IO_APIC_pin(apic, pin); ++ ++ memset(&entry1, 0, sizeof(entry1)); ++ ++ entry1.dest_mode = 0; /* physical delivery */ ++ entry1.mask = 0; /* unmask IRQ now */ ++ entry1.dest.physical.physical_dest = hard_smp_processor_id(); ++ entry1.delivery_mode = dest_ExtINT; ++ entry1.polarity = entry0.polarity; ++ entry1.trigger = 0; ++ entry1.vector = 0; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); ++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ save_control = CMOS_READ(RTC_CONTROL); ++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); ++ CMOS_WRITE((save_freq_select & ~RTC_RATE_SELECT) | 0x6, ++ RTC_FREQ_SELECT); ++ CMOS_WRITE(save_control | RTC_PIE, RTC_CONTROL); ++ ++ i = 100; ++ while (i-- > 0) { ++ mdelay(10); ++ if ((CMOS_READ(RTC_INTR_FLAGS) & RTC_PF) == RTC_PF) ++ i -= 10; ++ } ++ ++ CMOS_WRITE(save_control, RTC_CONTROL); ++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); ++ clear_IO_APIC_pin(apic, pin); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); ++ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++/* ++ * This code may look a bit paranoid, but it's supposed to cooperate with ++ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ ++ * is so screwy. Thanks to Brian Perkins for testing/hacking this beast ++ * fanatically on his truly buggy board. ++ * ++ * FIXME: really need to revamp this for modern platforms only. ++ */ ++static inline void check_timer(void) ++{ ++ int apic1, pin1, apic2, pin2; ++ int vector; ++ cpumask_t mask; ++ ++ /* ++ * get/set the timer IRQ vector: ++ */ ++ disable_8259A_irq(0); ++ vector = assign_irq_vector(0, TARGET_CPUS, &mask); ++ ++ /* ++ * Subtle, code in do_timer_interrupt() expects an AEOI ++ * mode for the 8259A whenever interrupts are routed ++ * through I/O APICs. Also IRQ0 has to be enabled in ++ * the 8259A which implies the virtual wire has to be ++ * disabled in the local APIC. ++ */ ++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); ++ init_8259A(1); ++ if (timer_over_8254 > 0) ++ enable_8259A_irq(0); ++ ++ pin1 = find_isa_irq_pin(0, mp_INT); ++ apic1 = find_isa_irq_apic(0, mp_INT); ++ pin2 = ioapic_i8259.pin; ++ apic2 = ioapic_i8259.apic; ++ ++ apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", ++ vector, apic1, pin1, apic2, pin2); ++ ++ if (pin1 != -1) { ++ /* ++ * Ok, does IRQ0 through the IOAPIC work? ++ */ ++ unmask_IO_APIC_irq(0); ++ if (!no_timer_check && timer_irq_works()) { ++ nmi_watchdog_default(); ++ if (nmi_watchdog == NMI_IO_APIC) { ++ disable_8259A_irq(0); ++ setup_nmi(); ++ enable_8259A_irq(0); ++ } ++ if (disable_timer_pin_1 > 0) ++ clear_IO_APIC_pin(0, pin1); ++ return; ++ } ++ clear_IO_APIC_pin(apic1, pin1); ++ apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " ++ "connected to IO-APIC\n"); ++ } ++ ++ apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " ++ "through the 8259A ... "); ++ if (pin2 != -1) { ++ apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", ++ apic2, pin2); ++ /* ++ * legacy devices should be connected to IO APIC #0 ++ */ ++ setup_ExtINT_IRQ0_pin(apic2, pin2, vector); ++ if (timer_irq_works()) { ++ apic_printk(APIC_VERBOSE," works.\n"); ++ nmi_watchdog_default(); ++ if (nmi_watchdog == NMI_IO_APIC) { ++ setup_nmi(); ++ } ++ return; ++ } ++ /* ++ * Cleanup, just in case ... ++ */ ++ clear_IO_APIC_pin(apic2, pin2); ++ } ++ apic_printk(APIC_VERBOSE," failed.\n"); ++ ++ if (nmi_watchdog == NMI_IO_APIC) { ++ printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); ++ nmi_watchdog = 0; ++ } ++ ++ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); ++ ++ disable_8259A_irq(0); ++ irq_desc[0].chip = &lapic_irq_type; ++ apic_write(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ ++ enable_8259A_irq(0); ++ ++ if (timer_irq_works()) { ++ apic_printk(APIC_VERBOSE," works.\n"); ++ return; ++ } ++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); ++ apic_printk(APIC_VERBOSE," failed.\n"); ++ ++ apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ..."); ++ ++ init_8259A(0); ++ make_8259A_irq(0); ++ apic_write(APIC_LVT0, APIC_DM_EXTINT); ++ ++ unlock_ExtINT_logic(); ++ ++ if (timer_irq_works()) { ++ apic_printk(APIC_VERBOSE," works.\n"); ++ return; ++ } ++ apic_printk(APIC_VERBOSE," failed :(.\n"); ++ panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); ++} ++#else ++#define check_timer() ((void)0) ++int timer_uses_ioapic_pin_0 = 0; ++#endif /* !CONFIG_XEN */ ++ ++static int __init notimercheck(char *s) ++{ ++ no_timer_check = 1; ++ return 1; ++} ++__setup("no_timer_check", notimercheck); ++ ++/* ++ * ++ * IRQ's that are handled by the PIC in the MPS IOAPIC case. ++ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. ++ * Linux doesn't really care, as it's not actually used ++ * for any interrupt handling anyway. ++ */ ++#define PIC_IRQS (1<<2) ++ ++void __init setup_IO_APIC(void) ++{ ++ enable_IO_APIC(); ++ ++ if (acpi_ioapic) ++ io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ ++ else ++ io_apic_irqs = ~PIC_IRQS; ++ ++ apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); ++ ++#ifndef CONFIG_XEN ++ sync_Arb_IDs(); ++#endif /* !CONFIG_XEN */ ++ setup_IO_APIC_irqs(); ++ init_IO_APIC_traps(); ++ check_timer(); ++ if (!acpi_ioapic) ++ print_IO_APIC(); ++} ++ ++struct sysfs_ioapic_data { ++ struct sys_device dev; ++ struct IO_APIC_route_entry entry[0]; ++}; ++static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; ++ ++static int ioapic_suspend(struct sys_device *dev, pm_message_t state) ++{ ++ struct IO_APIC_route_entry *entry; ++ struct sysfs_ioapic_data *data; ++ int i; ++ ++ data = container_of(dev, struct sysfs_ioapic_data, dev); ++ entry = data->entry; ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) ++ *entry = ioapic_read_entry(dev->id, i); ++ ++ return 0; ++} ++ ++static int ioapic_resume(struct sys_device *dev) ++{ ++ struct IO_APIC_route_entry *entry; ++ struct sysfs_ioapic_data *data; ++ unsigned long flags; ++ union IO_APIC_reg_00 reg_00; ++ int i; ++ ++ data = container_of(dev, struct sysfs_ioapic_data, dev); ++ entry = data->entry; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_00.raw = io_apic_read(dev->id, 0); ++ if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) { ++ reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; ++ io_apic_write(dev->id, 0, reg_00.raw); ++ } ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i++) ++ ioapic_write_entry(dev->id, i, entry[i]); ++ ++ return 0; ++} ++ ++static struct sysdev_class ioapic_sysdev_class = { ++ set_kset_name("ioapic"), ++ .suspend = ioapic_suspend, ++ .resume = ioapic_resume, ++}; ++ ++static int __init ioapic_init_sysfs(void) ++{ ++ struct sys_device * dev; ++ int i, size, error = 0; ++ ++ error = sysdev_class_register(&ioapic_sysdev_class); ++ if (error) ++ return error; ++ ++ for (i = 0; i < nr_ioapics; i++ ) { ++ size = sizeof(struct sys_device) + nr_ioapic_registers[i] ++ * sizeof(struct IO_APIC_route_entry); ++ mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); ++ if (!mp_ioapic_data[i]) { ++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); ++ continue; ++ } ++ memset(mp_ioapic_data[i], 0, size); ++ dev = &mp_ioapic_data[i]->dev; ++ dev->id = i; ++ dev->cls = &ioapic_sysdev_class; ++ error = sysdev_register(dev); ++ if (error) { ++ kfree(mp_ioapic_data[i]); ++ mp_ioapic_data[i] = NULL; ++ printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); ++ continue; ++ } ++ } ++ ++ return 0; ++} ++ ++device_initcall(ioapic_init_sysfs); ++ ++/* ++ * Dynamic irq allocate and deallocation ++ */ ++int create_irq(void) ++{ ++ /* Allocate an unused irq */ ++ int irq; ++ int new; ++ int vector = 0; ++ unsigned long flags; ++ cpumask_t mask; ++ ++ irq = -ENOSPC; ++ spin_lock_irqsave(&vector_lock, flags); ++ for (new = (NR_IRQS - 1); new >= 0; new--) { ++ if (platform_legacy_irq(new)) ++ continue; ++ if (irq_vector[new] != 0) ++ continue; ++ vector = __assign_irq_vector(new, TARGET_CPUS, &mask); ++ if (likely(vector > 0)) ++ irq = new; ++ break; ++ } ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ if (irq >= 0) { ++ dynamic_irq_init(irq); ++ } ++ return irq; ++} ++ ++void destroy_irq(unsigned int irq) ++{ ++ unsigned long flags; ++ ++ dynamic_irq_cleanup(irq); ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ __clear_irq_vector(irq); ++ spin_unlock_irqrestore(&vector_lock, flags); ++} ++ ++/* ++ * MSI mesage composition ++ */ ++#ifndef CONFIG_XEN ++#ifdef CONFIG_PCI_MSI ++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) ++{ ++ int vector; ++ unsigned dest; ++ cpumask_t tmp; ++ ++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); ++ if (vector >= 0) { ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg->address_hi = MSI_ADDR_BASE_HI; ++ msg->address_lo = ++ MSI_ADDR_BASE_LO | ++ ((INT_DEST_MODE == 0) ? ++ MSI_ADDR_DEST_MODE_PHYSICAL: ++ MSI_ADDR_DEST_MODE_LOGICAL) | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_ADDR_REDIRECTION_CPU: ++ MSI_ADDR_REDIRECTION_LOWPRI) | ++ MSI_ADDR_DEST_ID(dest); ++ ++ msg->data = ++ MSI_DATA_TRIGGER_EDGE | ++ MSI_DATA_LEVEL_ASSERT | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_DATA_DELIVERY_FIXED: ++ MSI_DATA_DELIVERY_LOWPRI) | ++ MSI_DATA_VECTOR(vector); ++ } ++ return vector; ++} ++ ++#ifdef CONFIG_SMP ++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct msi_msg msg; ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ read_msi_msg(irq, &msg); ++ ++ msg.data &= ~MSI_DATA_VECTOR_MASK; ++ msg.data |= MSI_DATA_VECTOR(vector); ++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; ++ msg.address_lo |= MSI_ADDR_DEST_ID(dest); ++ ++ write_msi_msg(irq, &msg); ++ set_native_irq_info(irq, mask); ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, ++ * which implement the MSI or MSI-X Capability Structure. ++ */ ++static struct irq_chip msi_chip = { ++ .name = "PCI-MSI", ++ .unmask = unmask_msi_irq, ++ .mask = mask_msi_irq, ++ .ack = ack_apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = set_msi_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ struct msi_msg msg; ++ int ret; ++ ret = msi_compose_msg(dev, irq, &msg); ++ if (ret < 0) ++ return ret; ++ ++ write_msi_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); ++ ++ return 0; ++} ++ ++void arch_teardown_msi_irq(unsigned int irq) ++{ ++ return; ++} ++ ++#endif /* CONFIG_PCI_MSI */ ++#endif /* !CONFIG_XEN */ ++/* ++ * Hypertransport interrupt support ++ */ ++#ifdef CONFIG_HT_IRQ ++ ++#ifdef CONFIG_SMP ++ ++static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) ++{ ++ struct ht_irq_msg msg; ++ fetch_ht_irq_msg(irq, &msg); ++ ++ msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); ++ msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); ++ ++ msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); ++ msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); ++ ++ write_ht_irq_msg(irq, &msg); ++} ++ ++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ target_ht_irq(irq, dest, vector); ++ set_native_irq_info(irq, mask); ++} ++#endif ++ ++static struct irq_chip ht_irq_chip = { ++ .name = "PCI-HT", ++ .mask = mask_ht_irq, ++ .unmask = unmask_ht_irq, ++ .ack = ack_apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ht_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ int vector; ++ cpumask_t tmp; ++ ++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); ++ if (vector >= 0) { ++ struct ht_irq_msg msg; ++ unsigned dest; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); ++ ++ msg.address_lo = ++ HT_IRQ_LOW_BASE | ++ HT_IRQ_LOW_DEST_ID(dest) | ++ HT_IRQ_LOW_VECTOR(vector) | ++ ((INT_DEST_MODE == 0) ? ++ HT_IRQ_LOW_DM_PHYSICAL : ++ HT_IRQ_LOW_DM_LOGICAL) | ++ HT_IRQ_LOW_RQEOI_EDGE | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ HT_IRQ_LOW_MT_FIXED : ++ HT_IRQ_LOW_MT_ARBITRATED) | ++ HT_IRQ_LOW_IRQ_MASKED; ++ ++ write_ht_irq_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &ht_irq_chip, ++ handle_edge_irq, "edge"); ++ } ++ return vector; ++} ++#endif /* CONFIG_HT_IRQ */ ++ ++/* -------------------------------------------------------------------------- ++ ACPI-based IOAPIC Configuration ++ -------------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ACPI ++ ++#define IO_APIC_MAX_ID 0xFE ++ ++int __init io_apic_get_redir_entries (int ioapic) ++{ ++ union IO_APIC_reg_01 reg_01; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(ioapic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return reg_01.bits.entries; ++} ++ ++ ++int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity) ++{ ++ struct IO_APIC_route_entry entry; ++ unsigned long flags; ++ int vector; ++ cpumask_t mask; ++ ++ if (!IO_APIC_IRQ(irq)) { ++ apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ++ ioapic); ++ return -EINVAL; ++ } ++ ++ /* ++ * IRQs < 16 are already in the irq_2_pin[] map ++ */ ++ if (irq >= 16) ++ add_pin_to_irq(irq, ioapic, pin); ++ ++ ++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask); ++ if (vector < 0) ++ return vector; ++ ++ /* ++ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. ++ * Note that we mask (disable) IRQs now -- these get enabled when the ++ * corresponding device driver registers for this IRQ. ++ */ ++ ++ memset(&entry,0,sizeof(entry)); ++ ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.dest_mode = INT_DEST_MODE; ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); ++ entry.trigger = triggering; ++ entry.polarity = polarity; ++ entry.mask = 1; /* Disabled (masked) */ ++ entry.vector = vector & 0xff; ++ ++ apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " ++ "IRQ %d Mode:%i Active:%i)\n", ioapic, ++ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, ++ triggering, polarity); ++ ++ ioapic_register_intr(irq, entry.vector, triggering); ++ ++ if (!ioapic && (irq < 16)) ++ disable_8259A_irq(irq); ++ ++ ioapic_write_entry(ioapic, pin, entry); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ set_native_irq_info(irq, TARGET_CPUS); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++ return 0; ++} ++ ++#endif /* CONFIG_ACPI */ ++ ++ ++#ifndef CONFIG_XEN ++/* ++ * This function currently is only a helper for the i386 smp boot process where ++ * we need to reprogram the ioredtbls to cater for the cpus which have come online ++ * so mask in all cases should simply be TARGET_CPUS ++ */ ++#ifdef CONFIG_SMP ++void __init setup_ioapic_dest(void) ++{ ++ int pin, ioapic, irq, irq_entry; ++ ++ if (skip_ioapic_setup == 1) ++ return; ++ ++ for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { ++ for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { ++ irq_entry = find_irq_entry(ioapic, pin, mp_INT); ++ if (irq_entry == -1) ++ continue; ++ irq = pin_2_irq(irq_entry, ioapic, pin); ++ ++ /* setup_IO_APIC_irqs could fail to get vector for some device ++ * when you have too many devices, because at that time only boot ++ * cpu is online. ++ */ ++ if(!irq_vector[irq]) ++ setup_IO_APIC_irq(ioapic, pin, irq_entry, irq); ++ else ++ set_ioapic_affinity_irq(irq, TARGET_CPUS); ++ } ++ ++ } ++} ++#endif ++#endif /* !CONFIG_XEN */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/ioport-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/ioport-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,100 @@ ++/* ++ * linux/arch/x86_64/kernel/ioport.c ++ * ++ * This contains the io-permission bitmap code - written by obz, with changes ++ * by Linus. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/capability.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/stddef.h> ++#include <linux/slab.h> ++#include <linux/thread_info.h> ++#include <xen/interface/physdev.h> ++ ++/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ ++static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) ++{ ++ int i; ++ ++ if (new_value) ++ for (i = base; i < base + extent; i++) ++ __set_bit(i, bitmap); ++ else ++ for (i = base; i < base + extent; i++) ++ clear_bit(i, bitmap); ++} ++ ++/* ++ * this changes the io permissions bitmap in the current task. ++ */ ++asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++{ ++ struct thread_struct * t = ¤t->thread; ++ unsigned long *bitmap; ++ struct physdev_set_iobitmap set_iobitmap; ++ ++ if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) ++ return -EINVAL; ++ if (turn_on && !capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ ++ /* ++ * If it's the first ioperm() call in this thread's lifetime, set the ++ * IO bitmap up. ioperm() is much less timing critical than clone(), ++ * this is why we delay this operation until now: ++ */ ++ if (!t->io_bitmap_ptr) { ++ bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); ++ if (!bitmap) ++ return -ENOMEM; ++ ++ memset(bitmap, 0xff, IO_BITMAP_BYTES); ++ t->io_bitmap_ptr = bitmap; ++ set_thread_flag(TIF_IO_BITMAP); ++ ++ set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); ++ set_iobitmap.nr_ports = IO_BITMAP_BITS; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap); ++ } ++ ++ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); ++ ++ return 0; ++} ++ ++/* ++ * sys_iopl has to be used when you want to access the IO ports ++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped ++ * you'd need 8kB of bitmaps/process, which is a bit excessive. ++ * ++ */ ++ ++asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs) ++{ ++ unsigned int old = current->thread.iopl; ++ struct physdev_set_iopl set_iopl; ++ ++ if (level > 3) ++ return -EINVAL; ++ /* Trying to gain more privileges? */ ++ if (level > old) { ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ } ++ /* Change our version of the privilege levels. */ ++ current->thread.iopl = level; ++ ++ /* Force the change at ring 0. */ ++ set_iopl.iopl = (level == 0) ? 1 : level; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/irq.c +--- a/arch/x86_64/kernel/irq.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/irq.c Wed Aug 08 16:25:28 2007 -0300 +@@ -113,7 +113,11 @@ asmlinkage unsigned int do_IRQ(struct pt + + exit_idle(); + irq_enter(); ++#ifdef CONFIG_XEN ++ irq = vector; ++#else + irq = __get_cpu_var(vector_irq)[vector]; ++#endif + + #ifdef CONFIG_DEBUG_STACKOVERFLOW + stack_overflow_check(regs); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/ldt-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/ldt-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,283 @@ ++/* ++ * linux/arch/x86_64/kernel/ldt.c ++ * ++ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds ++ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> ++ * Copyright (C) 2002 Andi Kleen ++ * ++ * This handles calls from both 32bit and 64bit mode. ++ */ ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/vmalloc.h> ++#include <linux/slab.h> ++ ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/ldt.h> ++#include <asm/desc.h> ++#include <asm/proto.h> ++#include <asm/pgalloc.h> ++ ++#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ ++static void flush_ldt(void *null) ++{ ++ if (current->active_mm) ++ load_LDT(¤t->active_mm->context); ++} ++#endif ++ ++static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload) ++{ ++ void *oldldt; ++ void *newldt; ++ unsigned oldsize; ++ ++ if (mincount <= (unsigned)pc->size) ++ return 0; ++ oldsize = pc->size; ++ mincount = (mincount+511)&(~511); ++ if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) ++ newldt = vmalloc(mincount*LDT_ENTRY_SIZE); ++ else ++ newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); ++ ++ if (!newldt) ++ return -ENOMEM; ++ ++ if (oldsize) ++ memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); ++ oldldt = pc->ldt; ++ memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); ++ wmb(); ++ pc->ldt = newldt; ++ wmb(); ++ pc->size = mincount; ++ wmb(); ++ if (reload) { ++#ifdef CONFIG_SMP ++ cpumask_t mask; ++ ++ preempt_disable(); ++ mask = cpumask_of_cpu(smp_processor_id()); ++#endif ++ make_pages_readonly( ++ pc->ldt, ++ (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ load_LDT(pc); ++#ifdef CONFIG_SMP ++ if (!cpus_equal(current->mm->cpu_vm_mask, mask)) ++ smp_call_function(flush_ldt, NULL, 1, 1); ++ preempt_enable(); ++#endif ++ } ++ if (oldsize) { ++ make_pages_writable( ++ oldldt, ++ (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(oldldt); ++ else ++ kfree(oldldt); ++ } ++ return 0; ++} ++ ++static inline int copy_ldt(mm_context_t *new, mm_context_t *old) ++{ ++ int err = alloc_ldt(new, old->size, 0); ++ if (err < 0) ++ return err; ++ memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); ++ make_pages_readonly( ++ new->ldt, ++ (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ return 0; ++} ++ ++/* ++ * we do not have to muck with descriptors here, that is ++ * done in switch_mm() as needed. ++ */ ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ struct mm_struct * old_mm; ++ int retval = 0; ++ ++ memset(&mm->context, 0, sizeof(mm->context)); ++ init_MUTEX(&mm->context.sem); ++ mm->context.size = 0; ++ old_mm = current->mm; ++ if (old_mm && old_mm->context.size > 0) { ++ down(&old_mm->context.sem); ++ retval = copy_ldt(&mm->context, &old_mm->context); ++ up(&old_mm->context.sem); ++ } ++ if (retval == 0) { ++ spin_lock(&mm_unpinned_lock); ++ list_add(&mm->context.unpinned, &mm_unpinned); ++ spin_unlock(&mm_unpinned_lock); ++ } ++ return retval; ++} ++ ++/* ++ * ++ * Don't touch the LDT register - we're already in the next thread. ++ */ ++void destroy_context(struct mm_struct *mm) ++{ ++ if (mm->context.size) { ++ if (mm == current->active_mm) ++ clear_LDT(); ++ make_pages_writable( ++ mm->context.ldt, ++ (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(mm->context.ldt); ++ else ++ kfree(mm->context.ldt); ++ mm->context.size = 0; ++ } ++ if (!mm->context.pinned) { ++ spin_lock(&mm_unpinned_lock); ++ list_del(&mm->context.unpinned); ++ spin_unlock(&mm_unpinned_lock); ++ } ++} ++ ++static int read_ldt(void __user * ptr, unsigned long bytecount) ++{ ++ int err; ++ unsigned long size; ++ struct mm_struct * mm = current->mm; ++ ++ if (!mm->context.size) ++ return 0; ++ if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) ++ bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; ++ ++ down(&mm->context.sem); ++ size = mm->context.size*LDT_ENTRY_SIZE; ++ if (size > bytecount) ++ size = bytecount; ++ ++ err = 0; ++ if (copy_to_user(ptr, mm->context.ldt, size)) ++ err = -EFAULT; ++ up(&mm->context.sem); ++ if (err < 0) ++ goto error_return; ++ if (size != bytecount) { ++ /* zero-fill the rest */ ++ if (clear_user(ptr+size, bytecount-size) != 0) { ++ err = -EFAULT; ++ goto error_return; ++ } ++ } ++ return bytecount; ++error_return: ++ return err; ++} ++ ++static int read_default_ldt(void __user * ptr, unsigned long bytecount) ++{ ++ /* Arbitrary number */ ++ /* x86-64 default LDT is all zeros */ ++ if (bytecount > 128) ++ bytecount = 128; ++ if (clear_user(ptr, bytecount)) ++ return -EFAULT; ++ return bytecount; ++} ++ ++static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) ++{ ++ struct task_struct *me = current; ++ struct mm_struct * mm = me->mm; ++ __u32 entry_1, entry_2, *lp; ++ unsigned long mach_lp; ++ int error; ++ struct user_desc ldt_info; ++ ++ error = -EINVAL; ++ ++ if (bytecount != sizeof(ldt_info)) ++ goto out; ++ error = -EFAULT; ++ if (copy_from_user(&ldt_info, ptr, bytecount)) ++ goto out; ++ ++ error = -EINVAL; ++ if (ldt_info.entry_number >= LDT_ENTRIES) ++ goto out; ++ if (ldt_info.contents == 3) { ++ if (oldmode) ++ goto out; ++ if (ldt_info.seg_not_present == 0) ++ goto out; ++ } ++ ++ down(&mm->context.sem); ++ if (ldt_info.entry_number >= (unsigned)mm->context.size) { ++ error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); ++ if (error < 0) ++ goto out_unlock; ++ } ++ ++ lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); ++ mach_lp = arbitrary_virt_to_machine(lp); ++ ++ /* Allow LDTs to be cleared by the user. */ ++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { ++ if (oldmode || LDT_empty(&ldt_info)) { ++ entry_1 = 0; ++ entry_2 = 0; ++ goto install; ++ } ++ } ++ ++ entry_1 = LDT_entry_a(&ldt_info); ++ entry_2 = LDT_entry_b(&ldt_info); ++ if (oldmode) ++ entry_2 &= ~(1 << 20); ++ ++ /* Install the new entry ... */ ++install: ++ error = HYPERVISOR_update_descriptor(mach_lp, (unsigned long)((entry_1 | (unsigned long) entry_2 << 32))); ++ ++out_unlock: ++ up(&mm->context.sem); ++out: ++ return error; ++} ++ ++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) ++{ ++ int ret = -ENOSYS; ++ ++ switch (func) { ++ case 0: ++ ret = read_ldt(ptr, bytecount); ++ break; ++ case 1: ++ ret = write_ldt(ptr, bytecount, 1); ++ break; ++ case 2: ++ ret = read_default_ldt(ptr, bytecount); ++ break; ++ case 0x11: ++ ret = write_ldt(ptr, bytecount, 0); ++ break; ++ } ++ return ret; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/machine_kexec.c +--- a/arch/x86_64/kernel/machine_kexec.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/machine_kexec.c Wed Aug 08 16:25:28 2007 -0300 +@@ -24,6 +24,104 @@ static u64 kexec_pmd1[512] PAGE_ALIGNED; + static u64 kexec_pmd1[512] PAGE_ALIGNED; + static u64 kexec_pte1[512] PAGE_ALIGNED; + ++#ifdef CONFIG_XEN ++ ++/* In the case of Xen, override hypervisor functions to be able to create ++ * a regular identity mapping page table... ++ */ ++ ++#include <xen/interface/kexec.h> ++#include <xen/interface/memory.h> ++ ++#define x__pmd(x) ((pmd_t) { (x) } ) ++#define x__pud(x) ((pud_t) { (x) } ) ++#define x__pgd(x) ((pgd_t) { (x) } ) ++ ++#define x_pmd_val(x) ((x).pmd) ++#define x_pud_val(x) ((x).pud) ++#define x_pgd_val(x) ((x).pgd) ++ ++static inline void x_set_pmd(pmd_t *dst, pmd_t val) ++{ ++ x_pmd_val(*dst) = x_pmd_val(val); ++} ++ ++static inline void x_set_pud(pud_t *dst, pud_t val) ++{ ++ x_pud_val(*dst) = phys_to_machine(x_pud_val(val)); ++} ++ ++static inline void x_pud_clear (pud_t *pud) ++{ ++ x_pud_val(*pud) = 0; ++} ++ ++static inline void x_set_pgd(pgd_t *dst, pgd_t val) ++{ ++ x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val)); ++} ++ ++static inline void x_pgd_clear (pgd_t * pgd) ++{ ++ x_pgd_val(*pgd) = 0; ++} ++ ++#define X__PAGE_KERNEL_LARGE_EXEC \ ++ _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE ++#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY ++ ++#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) ++ ++#if PAGES_NR > KEXEC_XEN_NO_PAGES ++#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break ++#endif ++ ++#if PA_CONTROL_PAGE != 0 ++#error PA_CONTROL_PAGE is non zero - Xen support will break ++#endif ++ ++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) ++{ ++ void *control_page; ++ void *table_page; ++ ++ memset(xki->page_list, 0, sizeof(xki->page_list)); ++ ++ control_page = page_address(image->control_code_page) + PAGE_SIZE; ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); ++ ++ table_page = page_address(image->control_code_page); ++ ++ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); ++ xki->page_list[PA_TABLE_PAGE] = __ma(table_page); ++ ++ xki->page_list[PA_PGD] = __ma(kexec_pgd); ++ xki->page_list[PA_PUD_0] = __ma(kexec_pud0); ++ xki->page_list[PA_PUD_1] = __ma(kexec_pud1); ++ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); ++ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); ++ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); ++ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); ++} ++ ++#else /* CONFIG_XEN */ ++ ++#define x__pmd(x) __pmd(x) ++#define x__pud(x) __pud(x) ++#define x__pgd(x) __pgd(x) ++ ++#define x_set_pmd(x, y) set_pmd(x, y) ++#define x_set_pud(x, y) set_pud(x, y) ++#define x_set_pgd(x, y) set_pgd(x, y) ++ ++#define x_pud_clear(x) pud_clear(x) ++#define x_pgd_clear(x) pgd_clear(x) ++ ++#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC ++#define X_KERNPG_TABLE _KERNPG_TABLE ++ ++#endif /* CONFIG_XEN */ ++ + static void init_level2_page(pmd_t *level2p, unsigned long addr) + { + unsigned long end_addr; +@@ -31,7 +129,7 @@ static void init_level2_page(pmd_t *leve + addr &= PAGE_MASK; + end_addr = addr + PUD_SIZE; + while (addr < end_addr) { +- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); ++ x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC)); + addr += PMD_SIZE; + } + } +@@ -56,12 +154,12 @@ static int init_level3_page(struct kimag + } + level2p = (pmd_t *)page_address(page); + init_level2_page(level2p, addr); +- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); ++ x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE)); + addr += PUD_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pud_clear(level3p++); ++ x_pud_clear(level3p++); + addr += PUD_SIZE; + } + out: +@@ -92,12 +190,12 @@ static int init_level4_page(struct kimag + if (result) { + goto out; + } +- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); ++ x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE)); + addr += PGDIR_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pgd_clear(level4p++); ++ x_pgd_clear(level4p++); + addr += PGDIR_SIZE; + } + out: +@@ -108,10 +206,17 @@ static int init_pgtable(struct kimage *i + static int init_pgtable(struct kimage *image, unsigned long start_pgtable) + { + pgd_t *level4p; ++ unsigned long x_end_pfn = end_pfn; ++ ++#ifdef CONFIG_XEN ++ x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); ++#endif ++ + level4p = (pgd_t *)__va(start_pgtable); +- return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); +-} +- ++ return init_level4_page(image, level4p, 0, x_end_pfn << PAGE_SHIFT); ++} ++ ++#ifndef CONFIG_XEN + static void set_idt(void *newidt, u16 limit) + { + struct desc_ptr curidt; +@@ -152,6 +257,7 @@ static void load_segments(void) + : : "a" (__KERNEL_DS) : "memory" + ); + } ++#endif /* !CONFIG_XEN */ + + int machine_kexec_prepare(struct kimage *image) + { +@@ -174,6 +280,7 @@ void machine_kexec_cleanup(struct kimage + return; + } + ++#ifndef CONFIG_XEN + /* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. +@@ -229,6 +336,7 @@ NORET_TYPE void machine_kexec(struct kim + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start); + } ++#endif + + /* crashkernel=size@addr specifies the location to reserve for + * a crash kernel. By reserving this memory we guarantee +@@ -256,4 +364,3 @@ static int __init setup_crashkernel(char + return 0; + } + early_param("crashkernel", setup_crashkernel); +- +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/mpparse.c +--- a/arch/x86_64/kernel/mpparse.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/mpparse.c Wed Aug 08 16:25:28 2007 -0300 +@@ -88,8 +88,10 @@ static int __init mpf_checksum(unsigned + return sum & 0xFF; + } + ++#ifndef CONFIG_XEN + static void __cpuinit MP_processor_info (struct mpc_config_processor *m) + { ++#ifndef CONFIG_XEN + int cpu; + cpumask_t tmp_map; + char *bootup_cpu = ""; +@@ -110,8 +112,9 @@ static void __cpuinit MP_processor_info + " Processor ignored.\n", NR_CPUS); + return; + } +- ++#endif /* !CONFIG_XEN */ + num_processors++; ++#ifndef CONFIG_XEN + cpus_complement(tmp_map, cpu_present_map); + cpu = first_cpu(tmp_map); + +@@ -129,7 +132,14 @@ static void __cpuinit MP_processor_info + + cpu_set(cpu, cpu_possible_map); + cpu_set(cpu, cpu_present_map); +-} ++#endif /* CONFIG_XEN */ ++} ++#else ++static void __cpuinit MP_processor_info (struct mpc_config_processor *m) ++{ ++ num_processors++; ++} ++#endif /* CONFIG_XEN */ + + static void __init MP_bus_info (struct mpc_config_bus *m) + { +@@ -488,7 +498,11 @@ void __init get_smp_config (void) + * Read the physical hardware table. Anything here will + * override the defaults. + */ ++#ifdef CONFIG_XEN ++ if (!smp_read_mpc(isa_bus_to_virt(mpf->mpf_physptr))) { ++#else + if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr))) { ++#endif + smp_found_config = 0; + printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); + printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); +@@ -524,7 +538,11 @@ static int __init smp_scan_config (unsig + static int __init smp_scan_config (unsigned long base, unsigned long length) + { + extern void __bad_mpf_size(void); ++#ifdef CONFIG_XEN ++ unsigned int *bp = isa_bus_to_virt(base); ++#else + unsigned int *bp = phys_to_virt(base); ++#endif + struct intel_mp_floating *mpf; + + Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); +@@ -540,9 +558,11 @@ static int __init smp_scan_config (unsig + || (mpf->mpf_specification == 4)) ) { + + smp_found_config = 1; ++#ifndef CONFIG_XEN + reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE); + if (mpf->mpf_physptr) + reserve_bootmem_generic(mpf->mpf_physptr, PAGE_SIZE); ++#endif + mpf_found = mpf; + return 1; + } +@@ -598,10 +618,12 @@ void __init find_smp_config(void) + + void __init mp_register_lapic_address(u64 address) + { ++#ifndef CONFIG_XEN + mp_lapic_addr = (unsigned long) address; + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); + if (boot_cpu_id == -1U) + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); ++#endif + } + + void __cpuinit mp_register_lapic (u8 id, u8 enabled) +@@ -612,6 +634,7 @@ void __cpuinit mp_register_lapic (u8 id, + if (id == boot_cpu_id) + boot_cpu = 1; + ++#ifndef CONFIG_XEN + processor.mpc_type = MP_PROCESSOR; + processor.mpc_apicid = id; + processor.mpc_apicver = 0; +@@ -621,6 +644,7 @@ void __cpuinit mp_register_lapic (u8 id, + processor.mpc_featureflag = 0; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; ++#endif + + MP_processor_info(&processor); + } +@@ -663,7 +687,9 @@ void __init mp_register_ioapic(u8 id, u3 + mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE; + mp_ioapics[idx].mpc_apicaddr = address; + ++#ifndef CONFIG_XEN + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); ++#endif + mp_ioapics[idx].mpc_apicid = id; + mp_ioapics[idx].mpc_apicver = 0; + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/pci-swiotlb.c +--- a/arch/x86_64/kernel/pci-swiotlb.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/pci-swiotlb.c Wed Aug 08 16:25:28 2007 -0300 +@@ -9,10 +9,13 @@ + #include <asm/swiotlb.h> + #include <asm/dma.h> + ++#ifndef CONFIG_XEN + int swiotlb __read_mostly; + EXPORT_SYMBOL(swiotlb); ++#endif + + struct dma_mapping_ops swiotlb_dma_ops = { ++#ifndef CONFIG_XEN + .mapping_error = swiotlb_dma_mapping_error, + .alloc_coherent = swiotlb_alloc_coherent, + .free_coherent = swiotlb_free_coherent, +@@ -27,10 +30,18 @@ struct dma_mapping_ops swiotlb_dma_ops = + .map_sg = swiotlb_map_sg, + .unmap_sg = swiotlb_unmap_sg, + .dma_supported = NULL, ++#endif + }; + + void pci_swiotlb_init(void) + { ++#ifdef CONFIG_XEN ++ swiotlb_init(); ++ if (swiotlb) { ++ printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n"); ++ dma_ops = &swiotlb_dma_ops; ++ } ++#else + /* don't initialize swiotlb if iommu=off (no_iommu=1) */ + if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN) + swiotlb = 1; +@@ -41,4 +52,5 @@ void pci_swiotlb_init(void) + swiotlb_init(); + dma_ops = &swiotlb_dma_ops; + } ++#endif /* CONFIG_XEN */ + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/process-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/process-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,901 @@ ++/* ++ * linux/arch/x86-64/kernel/process.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * ++ * Pentium III FXSR, SSE support ++ * Gareth Hughes <gareth@valinux.com>, May 2000 ++ * ++ * X86-64 port ++ * Andi Kleen. ++ * ++ * CPU hotplug support - ashok.raj@intel.com ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Modified for Xen ++ */ ++ ++/* ++ * This file handles the architecture-dependent parts of process handling.. ++ */ ++ ++#include <stdarg.h> ++ ++#include <linux/cpu.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/elfcore.h> ++#include <linux/smp.h> ++#include <linux/slab.h> ++#include <linux/user.h> ++#include <linux/module.h> ++#include <linux/a.out.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/ptrace.h> ++#include <linux/utsname.h> ++#include <linux/random.h> ++#include <linux/notifier.h> ++#include <linux/kprobes.h> ++ ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/processor.h> ++#include <asm/i387.h> ++#include <asm/mmu_context.h> ++#include <asm/pda.h> ++#include <asm/prctl.h> ++#include <asm/kdebug.h> ++#include <xen/interface/platform.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/vcpu.h> ++#include <asm/desc.h> ++#include <asm/proto.h> ++#include <asm/hardirq.h> ++#include <asm/ia32.h> ++#include <asm/idle.h> ++ ++#include <xen/cpu_hotplug.h> ++ ++asmlinkage extern void ret_from_fork(void); ++ ++unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; ++ ++unsigned long boot_option_idle_override = 0; ++EXPORT_SYMBOL(boot_option_idle_override); ++ ++/* ++ * Powermanagement idle function, if any.. ++ */ ++void (*pm_idle)(void); ++EXPORT_SYMBOL(pm_idle); ++static DEFINE_PER_CPU(unsigned int, cpu_idle_state); ++ ++static ATOMIC_NOTIFIER_HEAD(idle_notifier); ++ ++void idle_notifier_register(struct notifier_block *n) ++{ ++ atomic_notifier_chain_register(&idle_notifier, n); ++} ++EXPORT_SYMBOL_GPL(idle_notifier_register); ++ ++void idle_notifier_unregister(struct notifier_block *n) ++{ ++ atomic_notifier_chain_unregister(&idle_notifier, n); ++} ++EXPORT_SYMBOL(idle_notifier_unregister); ++ ++void enter_idle(void) ++{ ++ write_pda(isidle, 1); ++ atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); ++} ++ ++static void __exit_idle(void) ++{ ++ if (test_and_clear_bit_pda(0, isidle) == 0) ++ return; ++ atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); ++} ++ ++/* Called from interrupts to signify idle end */ ++void exit_idle(void) ++{ ++ /* idle loop has pid 0 */ ++ if (current->pid) ++ return; ++ __exit_idle(); ++} ++ ++/* ++ * On SMP it's slightly faster (but much more power-consuming!) ++ * to poll the ->need_resched flag instead of waiting for the ++ * cross-CPU IPI to arrive. Use this option with caution. ++ */ ++static void poll_idle (void) ++{ ++ local_irq_enable(); ++ ++ asm volatile( ++ "2:" ++ "testl %0,%1;" ++ "rep; nop;" ++ "je 2b;" ++ : : ++ "i" (_TIF_NEED_RESCHED), ++ "m" (current_thread_info()->flags)); ++} ++ ++static void xen_idle(void) ++{ ++ current_thread_info()->status &= ~TS_POLLING; ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); ++ local_irq_disable(); ++ if (!need_resched()) { ++ /* Enables interrupts one instruction before HLT. ++ x86 special cases this so there is no race. */ ++ safe_halt(); ++ } else ++ local_irq_enable(); ++ current_thread_info()->status |= TS_POLLING; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static inline void play_dead(void) ++{ ++ idle_task_exit(); ++ local_irq_disable(); ++ cpu_clear(smp_processor_id(), cpu_initialized); ++ preempt_enable_no_resched(); ++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); ++ cpu_bringup(); ++} ++#else ++static inline void play_dead(void) ++{ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * The idle thread. There's no useful work to be ++ * done, so just try to conserve power and have a ++ * low exit latency (ie sit in a loop waiting for ++ * somebody to say that they'd like to reschedule) ++ */ ++void cpu_idle (void) ++{ ++ current_thread_info()->status |= TS_POLLING; ++ /* endless idle loop with no priority at all */ ++ while (1) { ++ while (!need_resched()) { ++ void (*idle)(void); ++ ++ if (__get_cpu_var(cpu_idle_state)) ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ rmb(); ++ idle = xen_idle; /* no alternatives */ ++ if (cpu_is_offline(smp_processor_id())) ++ play_dead(); ++ /* ++ * Idle routines should keep interrupts disabled ++ * from here on, until they go to idle. ++ * Otherwise, idle callbacks can misfire. ++ */ ++ local_irq_disable(); ++ enter_idle(); ++ idle(); ++ __exit_idle(); ++ } ++ ++ preempt_enable_no_resched(); ++ schedule(); ++ preempt_disable(); ++ } ++} ++ ++void cpu_idle_wait(void) ++{ ++ unsigned int cpu, this_cpu = get_cpu(); ++ cpumask_t map, tmp = current->cpus_allowed; ++ ++ set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); ++ put_cpu(); ++ ++ cpus_clear(map); ++ for_each_online_cpu(cpu) { ++ per_cpu(cpu_idle_state, cpu) = 1; ++ cpu_set(cpu, map); ++ } ++ ++ __get_cpu_var(cpu_idle_state) = 0; ++ ++ wmb(); ++ do { ++ ssleep(1); ++ for_each_online_cpu(cpu) { ++ if (cpu_isset(cpu, map) && ++ !per_cpu(cpu_idle_state, cpu)) ++ cpu_clear(cpu, map); ++ } ++ cpus_and(map, map, cpu_online_map); ++ } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); ++} ++EXPORT_SYMBOL_GPL(cpu_idle_wait); ++ ++/* XXX XEN doesn't use mwait_idle(), select_idle_routine(), idle_setup(). */ ++/* Always use xen_idle() instead. */ ++void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) {} ++ ++void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) ++{ ++} ++ ++static int __init idle_setup (char *str) ++{ ++ if (!strncmp(str, "poll", 4)) { ++ printk("using polling idle threads.\n"); ++ pm_idle = poll_idle; ++ } ++ ++ boot_option_idle_override = 1; ++ return 1; ++} ++ ++__setup("idle=", idle_setup); ++ ++/* Prints also some state that isn't saved in the pt_regs */ ++void __show_regs(struct pt_regs * regs) ++{ ++ unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; ++ unsigned int fsindex,gsindex; ++ unsigned int ds,cs,es; ++ ++ printk("\n"); ++ print_modules(); ++ printk("Pid: %d, comm: %.20s %s %s %.*s\n", ++ current->pid, current->comm, print_tainted(), ++ init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); ++ printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); ++ printk_address(regs->rip); ++ printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, ++ regs->eflags); ++ printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", ++ regs->rax, regs->rbx, regs->rcx); ++ printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", ++ regs->rdx, regs->rsi, regs->rdi); ++ printk("RBP: %016lx R08: %016lx R09: %016lx\n", ++ regs->rbp, regs->r8, regs->r9); ++ printk("R10: %016lx R11: %016lx R12: %016lx\n", ++ regs->r10, regs->r11, regs->r12); ++ printk("R13: %016lx R14: %016lx R15: %016lx\n", ++ regs->r13, regs->r14, regs->r15); ++ ++ asm("movl %%ds,%0" : "=r" (ds)); ++ asm("movl %%cs,%0" : "=r" (cs)); ++ asm("movl %%es,%0" : "=r" (es)); ++ asm("movl %%fs,%0" : "=r" (fsindex)); ++ asm("movl %%gs,%0" : "=r" (gsindex)); ++ ++ rdmsrl(MSR_FS_BASE, fs); ++ rdmsrl(MSR_GS_BASE, gs); ++ rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); ++ ++ cr0 = read_cr0(); ++ cr2 = 0; /* No real clue how to read it. JQ */ ++ cr3 = read_cr3(); ++ cr4 = read_cr4(); ++ ++ printk("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", ++ fs,fsindex,gs,gsindex,shadowgs); ++ printk("CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); ++ printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4); ++} ++ ++void show_regs(struct pt_regs *regs) ++{ ++ printk("CPU %d:", smp_processor_id()); ++ __show_regs(regs); ++ show_trace(NULL, regs, ®s->rsp); ++} ++ ++/* ++ * Free current thread data structures etc.. ++ */ ++void exit_thread(void) ++{ ++ struct task_struct *me = current; ++ struct thread_struct *t = &me->thread; ++ ++ if (me->thread.io_bitmap_ptr) { ++#ifndef CONFIG_X86_NO_TSS ++ struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); ++#endif ++#ifdef CONFIG_XEN ++ struct physdev_set_iobitmap iobmp_op; ++ memset(&iobmp_op, 0, sizeof(iobmp_op)); ++#endif ++ ++ kfree(t->io_bitmap_ptr); ++ t->io_bitmap_ptr = NULL; ++ clear_thread_flag(TIF_IO_BITMAP); ++ /* ++ * Careful, clear this in the TSS too: ++ */ ++#ifndef CONFIG_X86_NO_TSS ++ memset(tss->io_bitmap, 0xff, t->io_bitmap_max); ++ put_cpu(); ++#endif ++#ifdef CONFIG_XEN ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &iobmp_op); ++#endif ++ t->io_bitmap_max = 0; ++ } ++} ++ ++void load_gs_index(unsigned gs) ++{ ++ HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, gs); ++} ++ ++void flush_thread(void) ++{ ++ struct task_struct *tsk = current; ++ struct thread_info *t = current_thread_info(); ++ ++ if (t->flags & _TIF_ABI_PENDING) { ++ t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32); ++ if (t->flags & _TIF_IA32) ++ current_thread_info()->status |= TS_COMPAT; ++ } ++ t->flags &= ~_TIF_DEBUG; ++ ++ tsk->thread.debugreg0 = 0; ++ tsk->thread.debugreg1 = 0; ++ tsk->thread.debugreg2 = 0; ++ tsk->thread.debugreg3 = 0; ++ tsk->thread.debugreg6 = 0; ++ tsk->thread.debugreg7 = 0; ++ memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); ++ /* ++ * Forget coprocessor state.. ++ */ ++ clear_fpu(tsk); ++ clear_used_math(); ++} ++ ++void release_thread(struct task_struct *dead_task) ++{ ++ if (dead_task->mm) { ++ if (dead_task->mm->context.size) { ++ printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", ++ dead_task->comm, ++ dead_task->mm->context.ldt, ++ dead_task->mm->context.size); ++ BUG(); ++ } ++ } ++} ++ ++static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr) ++{ ++ struct user_desc ud = { ++ .base_addr = addr, ++ .limit = 0xfffff, ++ .seg_32bit = 1, ++ .limit_in_pages = 1, ++ .useable = 1, ++ }; ++ struct n_desc_struct *desc = (void *)t->thread.tls_array; ++ desc += tls; ++ desc->a = LDT_entry_a(&ud); ++ desc->b = LDT_entry_b(&ud); ++} ++ ++static inline u32 read_32bit_tls(struct task_struct *t, int tls) ++{ ++ struct desc_struct *desc = (void *)t->thread.tls_array; ++ desc += tls; ++ return desc->base0 | ++ (((u32)desc->base1) << 16) | ++ (((u32)desc->base2) << 24); ++} ++ ++/* ++ * This gets called before we allocate a new thread and copy ++ * the current task into it. ++ */ ++void prepare_to_copy(struct task_struct *tsk) ++{ ++ unlazy_fpu(tsk); ++} ++ ++int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, ++ unsigned long unused, ++ struct task_struct * p, struct pt_regs * regs) ++{ ++ int err; ++ struct pt_regs * childregs; ++ struct task_struct *me = current; ++ ++ childregs = ((struct pt_regs *) ++ (THREAD_SIZE + task_stack_page(p))) - 1; ++ *childregs = *regs; ++ ++ childregs->rax = 0; ++ childregs->rsp = rsp; ++ if (rsp == ~0UL) ++ childregs->rsp = (unsigned long)childregs; ++ ++ p->thread.rsp = (unsigned long) childregs; ++ p->thread.rsp0 = (unsigned long) (childregs+1); ++ p->thread.userrsp = me->thread.userrsp; ++ ++ set_tsk_thread_flag(p, TIF_FORK); ++ ++ p->thread.fs = me->thread.fs; ++ p->thread.gs = me->thread.gs; ++ ++ asm("mov %%gs,%0" : "=m" (p->thread.gsindex)); ++ asm("mov %%fs,%0" : "=m" (p->thread.fsindex)); ++ asm("mov %%es,%0" : "=m" (p->thread.es)); ++ asm("mov %%ds,%0" : "=m" (p->thread.ds)); ++ ++ if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) { ++ p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); ++ if (!p->thread.io_bitmap_ptr) { ++ p->thread.io_bitmap_max = 0; ++ return -ENOMEM; ++ } ++ memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, ++ IO_BITMAP_BYTES); ++ set_tsk_thread_flag(p, TIF_IO_BITMAP); ++ } ++ ++ /* ++ * Set a new TLS for the child thread? ++ */ ++ if (clone_flags & CLONE_SETTLS) { ++#ifdef CONFIG_IA32_EMULATION ++ if (test_thread_flag(TIF_IA32)) ++ err = ia32_child_tls(p, childregs); ++ else ++#endif ++ err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8); ++ if (err) ++ goto out; ++ } ++ p->thread.iopl = current->thread.iopl; ++ ++ err = 0; ++out: ++ if (err && p->thread.io_bitmap_ptr) { ++ kfree(p->thread.io_bitmap_ptr); ++ p->thread.io_bitmap_max = 0; ++ } ++ return err; ++} ++ ++static inline void __save_init_fpu( struct task_struct *tsk ) ++{ ++ asm volatile( "rex64 ; fxsave %0 ; fnclex" ++ : "=m" (tsk->thread.i387.fxsave)); ++ tsk->thread_info->status &= ~TS_USEDFPU; ++} ++ ++/* ++ * This special macro can be used to load a debugging register ++ */ ++#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) ++ ++static inline void __switch_to_xtra(struct task_struct *prev_p, ++ struct task_struct *next_p) ++{ ++ struct thread_struct *prev, *next; ++ ++ prev = &prev_p->thread, ++ next = &next_p->thread; ++ ++ if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { ++ loaddebug(next, 0); ++ loaddebug(next, 1); ++ loaddebug(next, 2); ++ loaddebug(next, 3); ++ /* no 4 and 5 */ ++ loaddebug(next, 6); ++ loaddebug(next, 7); ++ } ++#ifndef CONFIG_XEN ++ if (test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { ++ /* ++ * Copy the relevant range of the IO bitmap. ++ * Normally this is 128 bytes or less: ++ */ ++ memcpy(tss->io_bitmap, next->io_bitmap_ptr, ++ max(prev->io_bitmap_max, next->io_bitmap_max)); ++ } else if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) { ++ /* ++ * Clear any possible leftover bits: ++ */ ++ memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); ++ } ++#endif ++} ++ ++/* ++ * switch_to(x,y) should switch tasks from x to y. ++ * ++ * This could still be optimized: ++ * - fold all the options into a flag word and test it with a single test. ++ * - could test fs/gs bitsliced ++ * ++ * Kprobes not supported here. Set the probe on schedule instead. ++ */ ++__kprobes struct task_struct * ++__switch_to(struct task_struct *prev_p, struct task_struct *next_p) ++{ ++ struct thread_struct *prev = &prev_p->thread, ++ *next = &next_p->thread; ++ int cpu = smp_processor_id(); ++#ifndef CONFIG_X86_NO_TSS ++ struct tss_struct *tss = &per_cpu(init_tss, cpu); ++#endif ++ struct physdev_set_iopl iopl_op; ++ struct physdev_set_iobitmap iobmp_op; ++ multicall_entry_t _mcl[8], *mcl = _mcl; ++ ++ /* ++ * Reload esp0, LDT and the page table pointer: ++ */ ++ mcl->op = __HYPERVISOR_stack_switch; ++ mcl->args[0] = __KERNEL_DS; ++ mcl->args[1] = next->rsp0; ++ mcl++; ++ ++ /* we're going to use this soon, after a few expensive things */ ++ if (next_p->fpu_counter>5) ++ prefetch(&next->i387.fxsave); ++ ++ /* ++ * Load the per-thread Thread-Local Storage descriptor. ++ * This is load_TLS(next, cpu) with multicalls. ++ */ ++#define C(i) do { \ ++ if (unlikely(next->tls_array[i] != prev->tls_array[i])) { \ ++ mcl->op = __HYPERVISOR_update_descriptor; \ ++ mcl->args[0] = virt_to_machine( \ ++ &cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]); \ ++ mcl->args[1] = next->tls_array[i]; \ ++ mcl++; \ ++ } \ ++} while (0) ++ C(0); C(1); C(2); ++#undef C ++ ++ if (unlikely(prev->iopl != next->iopl)) { ++ iopl_op.iopl = (next->iopl == 0) ? 1 : next->iopl; ++ mcl->op = __HYPERVISOR_physdev_op; ++ mcl->args[0] = PHYSDEVOP_set_iopl; ++ mcl->args[1] = (unsigned long)&iopl_op; ++ mcl++; ++ } ++ ++ if (test_tsk_thread_flag(prev_p, TIF_IO_BITMAP) || ++ test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { ++ set_xen_guest_handle(iobmp_op.bitmap, ++ (char *)next->io_bitmap_ptr); ++ iobmp_op.nr_ports = next->io_bitmap_ptr ? IO_BITMAP_BITS : 0; ++ mcl->op = __HYPERVISOR_physdev_op; ++ mcl->args[0] = PHYSDEVOP_set_iobitmap; ++ mcl->args[1] = (unsigned long)&iobmp_op; ++ mcl++; ++ } ++ ++ (void)HYPERVISOR_multicall(_mcl, mcl - _mcl); ++ /* ++ * Switch DS and ES. ++ * This won't pick up thread selector changes, but I guess that is ok. ++ */ ++ if (unlikely(next->es)) ++ loadsegment(es, next->es); ++ ++ if (unlikely(next->ds)) ++ loadsegment(ds, next->ds); ++ ++ /* ++ * Switch FS and GS. ++ */ ++ if (unlikely(next->fsindex)) ++ loadsegment(fs, next->fsindex); ++ ++ if (next->fs) ++ HYPERVISOR_set_segment_base(SEGBASE_FS, next->fs); ++ ++ if (unlikely(next->gsindex)) ++ load_gs_index(next->gsindex); ++ ++ if (next->gs) ++ HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs); ++ ++ /* Must be after DS reload */ ++ /* ++ * This is basically '__unlazy_fpu' ++ */ ++ if (prev_p->thread_info->status & TS_USEDFPU) { ++ __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ ++ HYPERVISOR_fpu_taskswitch(1); ++ } ++ ++ /* ++ * Switch the PDA context. ++ */ ++ prev->userrsp = read_pda(oldrsp); ++ write_pda(oldrsp, next->userrsp); ++ write_pda(pcurrent, next_p); ++ ++ write_pda(kernelstack, ++ (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); ++#ifdef CONFIG_CC_STACKPROTECTOR ++ write_pda(stack_canary, next_p->stack_canary); ++ /* ++ * Build time only check to make sure the stack_canary is at ++ * offset 40 in the pda; this is a gcc ABI requirement ++ */ ++ BUILD_BUG_ON(offsetof(struct x8664_pda, stack_canary) != 40); ++#endif ++ ++ /* ++ * Now maybe reload the debug registers and handle I/O bitmaps ++ */ ++ if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) ++ || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) ++ __switch_to_xtra(prev_p, next_p); ++ ++ /* If the task has used fpu the last 5 timeslices, just do a full ++ * restore of the math state immediately to avoid the trap; the ++ * chances of needing FPU soon are obviously high now ++ */ ++ if (next_p->fpu_counter>5) ++ math_state_restore(); ++ return prev_p; ++} ++ ++/* ++ * sys_execve() executes a new program. ++ */ ++asmlinkage ++long sys_execve(char __user *name, char __user * __user *argv, ++ char __user * __user *envp, struct pt_regs regs) ++{ ++ long error; ++ char * filename; ++ ++ filename = getname(name); ++ error = PTR_ERR(filename); ++ if (IS_ERR(filename)) ++ return error; ++ error = do_execve(filename, argv, envp, ®s); ++ if (error == 0) { ++ task_lock(current); ++ current->ptrace &= ~PT_DTRACE; ++ task_unlock(current); ++ } ++ putname(filename); ++ return error; ++} ++ ++void set_personality_64bit(void) ++{ ++ /* inherit personality from parent */ ++ ++ /* Make sure to be in 64bit mode */ ++ clear_thread_flag(TIF_IA32); ++ ++ /* TBD: overwrites user setup. Should have two bits. ++ But 64bit processes have always behaved this way, ++ so it's not too bad. The main problem is just that ++ 32bit childs are affected again. */ ++ current->personality &= ~READ_IMPLIES_EXEC; ++} ++ ++asmlinkage long sys_fork(struct pt_regs *regs) ++{ ++ return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL); ++} ++ ++asmlinkage long ++sys_clone(unsigned long clone_flags, unsigned long newsp, ++ void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) ++{ ++ if (!newsp) ++ newsp = regs->rsp; ++ return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); ++} ++ ++/* ++ * This is trivial, and on the face of it looks like it ++ * could equally well be done in user mode. ++ * ++ * Not so, for quite unobvious reasons - register pressure. ++ * In user mode vfork() cannot have a stack frame, and if ++ * done by calling the "clone()" system call directly, you ++ * do not have enough call-clobbered registers to hold all ++ * the information you need. ++ */ ++asmlinkage long sys_vfork(struct pt_regs *regs) ++{ ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0, ++ NULL, NULL); ++} ++ ++unsigned long get_wchan(struct task_struct *p) ++{ ++ unsigned long stack; ++ u64 fp,rip; ++ int count = 0; ++ ++ if (!p || p == current || p->state==TASK_RUNNING) ++ return 0; ++ stack = (unsigned long)task_stack_page(p); ++ if (p->thread.rsp < stack || p->thread.rsp > stack+THREAD_SIZE) ++ return 0; ++ fp = *(u64 *)(p->thread.rsp); ++ do { ++ if (fp < (unsigned long)stack || ++ fp > (unsigned long)stack+THREAD_SIZE) ++ return 0; ++ rip = *(u64 *)(fp+8); ++ if (!in_sched_functions(rip)) ++ return rip; ++ fp = *(u64 *)fp; ++ } while (count++ < 16); ++ return 0; ++} ++ ++long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) ++{ ++ int ret = 0; ++ int doit = task == current; ++ int cpu; ++ ++ switch (code) { ++ case ARCH_SET_GS: ++ if (addr >= TASK_SIZE_OF(task)) ++ return -EPERM; ++ cpu = get_cpu(); ++ /* handle small bases via the GDT because that's faster to ++ switch. */ ++ if (addr <= 0xffffffff) { ++ set_32bit_tls(task, GS_TLS, addr); ++ if (doit) { ++ load_TLS(&task->thread, cpu); ++ load_gs_index(GS_TLS_SEL); ++ } ++ task->thread.gsindex = GS_TLS_SEL; ++ task->thread.gs = 0; ++ } else { ++ task->thread.gsindex = 0; ++ task->thread.gs = addr; ++ if (doit) { ++ load_gs_index(0); ++ ret = HYPERVISOR_set_segment_base( ++ SEGBASE_GS_USER, addr); ++ } ++ } ++ put_cpu(); ++ break; ++ case ARCH_SET_FS: ++ /* Not strictly needed for fs, but do it for symmetry ++ with gs */ ++ if (addr >= TASK_SIZE_OF(task)) ++ return -EPERM; ++ cpu = get_cpu(); ++ /* handle small bases via the GDT because that's faster to ++ switch. */ ++ if (addr <= 0xffffffff) { ++ set_32bit_tls(task, FS_TLS, addr); ++ if (doit) { ++ load_TLS(&task->thread, cpu); ++ asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL)); ++ } ++ task->thread.fsindex = FS_TLS_SEL; ++ task->thread.fs = 0; ++ } else { ++ task->thread.fsindex = 0; ++ task->thread.fs = addr; ++ if (doit) { ++ /* set the selector to 0 to not confuse ++ __switch_to */ ++ asm volatile("movl %0,%%fs" :: "r" (0)); ++ ret = HYPERVISOR_set_segment_base(SEGBASE_FS, ++ addr); ++ } ++ } ++ put_cpu(); ++ break; ++ case ARCH_GET_FS: { ++ unsigned long base; ++ if (task->thread.fsindex == FS_TLS_SEL) ++ base = read_32bit_tls(task, FS_TLS); ++ else if (doit) ++ rdmsrl(MSR_FS_BASE, base); ++ else ++ base = task->thread.fs; ++ ret = put_user(base, (unsigned long __user *)addr); ++ break; ++ } ++ case ARCH_GET_GS: { ++ unsigned long base; ++ unsigned gsindex; ++ if (task->thread.gsindex == GS_TLS_SEL) ++ base = read_32bit_tls(task, GS_TLS); ++ else if (doit) { ++ asm("movl %%gs,%0" : "=r" (gsindex)); ++ if (gsindex) ++ rdmsrl(MSR_KERNEL_GS_BASE, base); ++ else ++ base = task->thread.gs; ++ } ++ else ++ base = task->thread.gs; ++ ret = put_user(base, (unsigned long __user *)addr); ++ break; ++ } ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++long sys_arch_prctl(int code, unsigned long addr) ++{ ++ return do_arch_prctl(current, code, addr); ++} ++ ++/* ++ * Capture the user space registers if the task is not running (in user space) ++ */ ++int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) ++{ ++ struct pt_regs *pp, ptregs; ++ ++ pp = task_pt_regs(tsk); ++ ++ ptregs = *pp; ++ ptregs.cs &= 0xffff; ++ ptregs.ss &= 0xffff; ++ ++ elf_core_copy_regs(regs, &ptregs); ++ ++ boot_option_idle_override = 1; ++ return 1; ++} ++ ++unsigned long arch_align_stack(unsigned long sp) ++{ ++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) ++ sp -= get_random_int() % 8192; ++ return sp & ~0xf; ++} ++ ++#ifndef CONFIG_SMP ++void _restore_vcpu(void) ++{ ++} ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/setup-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/setup-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1489 @@ ++/* ++ * linux/arch/x86-64/kernel/setup.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * ++ * Nov 2001 Dave Jones <davej@suse.de> ++ * Forked from i386 setup code. ++ */ ++ ++/* ++ * This file handles the architecture-dependent parts of initialization ++ */ ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/stddef.h> ++#include <linux/unistd.h> ++#include <linux/ptrace.h> ++#include <linux/slab.h> ++#include <linux/user.h> ++#include <linux/a.out.h> ++#include <linux/screen_info.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/initrd.h> ++#include <linux/highmem.h> ++#include <linux/bootmem.h> ++#include <linux/module.h> ++#include <asm/processor.h> ++#include <linux/console.h> ++#include <linux/seq_file.h> ++#include <linux/crash_dump.h> ++#include <linux/root_dev.h> ++#include <linux/pci.h> ++#include <linux/acpi.h> ++#include <linux/kallsyms.h> ++#include <linux/edd.h> ++#include <linux/mmzone.h> ++#include <linux/kexec.h> ++#include <linux/cpufreq.h> ++#include <linux/dmi.h> ++#include <linux/dma-mapping.h> ++#include <linux/ctype.h> ++ ++#include <asm/mtrr.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/smp.h> ++#include <asm/msr.h> ++#include <asm/desc.h> ++#include <video/edid.h> ++#include <asm/e820.h> ++#include <asm/dma.h> ++#include <asm/mpspec.h> ++#include <asm/mmu_context.h> ++#include <asm/bootsetup.h> ++#include <asm/proto.h> ++#include <asm/setup.h> ++#include <asm/mach_apic.h> ++#include <asm/numa.h> ++#include <asm/sections.h> ++#include <asm/dmi.h> ++#ifdef CONFIG_XEN ++#include <linux/percpu.h> ++#include <linux/pfn.h> ++#include <xen/interface/physdev.h> ++#include "setup_arch_pre.h" ++#include <asm/hypervisor.h> ++#include <xen/interface/nmi.h> ++#include <xen/features.h> ++#include <xen/xencons.h> ++#include <asm/mach-xen/setup_arch_post.h> ++#include <xen/interface/memory.h> ++ ++#ifdef CONFIG_XEN ++#include <xen/interface/kexec.h> ++#endif ++ ++extern unsigned long start_pfn; ++ ++shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page; ++EXPORT_SYMBOL(HYPERVISOR_shared_info); ++ ++extern char hypercall_page[PAGE_SIZE]; ++EXPORT_SYMBOL(hypercall_page); ++ ++static int xen_panic_event(struct notifier_block *, unsigned long, void *); ++static struct notifier_block xen_panic_block = { ++ xen_panic_event, NULL, 0 /* try to go last */ ++}; ++ ++unsigned long *phys_to_machine_mapping; ++unsigned long *pfn_to_mfn_frame_list_list, *pfn_to_mfn_frame_list[512]; ++ ++EXPORT_SYMBOL(phys_to_machine_mapping); ++ ++DEFINE_PER_CPU(multicall_entry_t, multicall_list[8]); ++DEFINE_PER_CPU(int, nr_multicall_ents); ++ ++/* Raw start-of-day parameters from the hypervisor. */ ++start_info_t *xen_start_info; ++EXPORT_SYMBOL(xen_start_info); ++#endif ++ ++/* ++ * Machine setup.. ++ */ ++ ++struct cpuinfo_x86 boot_cpu_data __read_mostly; ++EXPORT_SYMBOL(boot_cpu_data); ++ ++unsigned long mmu_cr4_features; ++ ++/* Boot loader ID as an integer, for the benefit of proc_dointvec */ ++int bootloader_type; ++ ++unsigned long saved_video_mode; ++ ++/* ++ * Early DMI memory ++ */ ++int dmi_alloc_index; ++char dmi_alloc_data[DMI_MAX_DATA]; ++ ++/* ++ * Setup options ++ */ ++struct screen_info screen_info; ++EXPORT_SYMBOL(screen_info); ++struct sys_desc_table_struct { ++ unsigned short length; ++ unsigned char table[0]; ++}; ++ ++struct edid_info edid_info; ++EXPORT_SYMBOL_GPL(edid_info); ++#ifdef CONFIG_XEN ++struct e820map machine_e820; ++#endif ++ ++extern int root_mountflags; ++ ++char command_line[COMMAND_LINE_SIZE]; ++ ++struct resource standard_io_resources[] = { ++ { .name = "dma1", .start = 0x00, .end = 0x1f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "pic1", .start = 0x20, .end = 0x21, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "timer0", .start = 0x40, .end = 0x43, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "timer1", .start = 0x50, .end = 0x53, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "keyboard", .start = 0x60, .end = 0x6f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "dma page reg", .start = 0x80, .end = 0x8f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "pic2", .start = 0xa0, .end = 0xa1, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "dma2", .start = 0xc0, .end = 0xdf, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO }, ++ { .name = "fpu", .start = 0xf0, .end = 0xff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO } ++}; ++ ++#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM) ++ ++struct resource data_resource = { ++ .name = "Kernel data", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_RAM, ++}; ++struct resource code_resource = { ++ .name = "Kernel code", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_RAM, ++}; ++ ++#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM) ++ ++static struct resource system_rom_resource = { ++ .name = "System ROM", ++ .start = 0xf0000, ++ .end = 0xfffff, ++ .flags = IORESOURCE_ROM, ++}; ++ ++static struct resource extension_rom_resource = { ++ .name = "Extension ROM", ++ .start = 0xe0000, ++ .end = 0xeffff, ++ .flags = IORESOURCE_ROM, ++}; ++ ++static struct resource adapter_rom_resources[] = { ++ { .name = "Adapter ROM", .start = 0xc8000, .end = 0, ++ .flags = IORESOURCE_ROM }, ++ { .name = "Adapter ROM", .start = 0, .end = 0, ++ .flags = IORESOURCE_ROM }, ++ { .name = "Adapter ROM", .start = 0, .end = 0, ++ .flags = IORESOURCE_ROM }, ++ { .name = "Adapter ROM", .start = 0, .end = 0, ++ .flags = IORESOURCE_ROM }, ++ { .name = "Adapter ROM", .start = 0, .end = 0, ++ .flags = IORESOURCE_ROM }, ++ { .name = "Adapter ROM", .start = 0, .end = 0, ++ .flags = IORESOURCE_ROM } ++}; ++ ++static struct resource video_rom_resource = { ++ .name = "Video ROM", ++ .start = 0xc0000, ++ .end = 0xc7fff, ++ .flags = IORESOURCE_ROM, ++}; ++ ++static struct resource video_ram_resource = { ++ .name = "Video RAM area", ++ .start = 0xa0000, ++ .end = 0xbffff, ++ .flags = IORESOURCE_RAM, ++}; ++ ++#define romsignature(x) (*(unsigned short *)(x) == 0xaa55) ++ ++static int __init romchecksum(unsigned char *rom, unsigned long length) ++{ ++ unsigned char *p, sum = 0; ++ ++ for (p = rom; p < rom + length; p++) ++ sum += *p; ++ return sum == 0; ++} ++ ++static void __init probe_roms(void) ++{ ++ unsigned long start, length, upper; ++ unsigned char *rom; ++ int i; ++ ++#ifdef CONFIG_XEN ++ /* Nothing to do if not running in dom0. */ ++ if (!is_initial_xendomain()) ++ return; ++#endif ++ ++ /* video rom */ ++ upper = adapter_rom_resources[0].start; ++ for (start = video_rom_resource.start; start < upper; start += 2048) { ++ rom = isa_bus_to_virt(start); ++ if (!romsignature(rom)) ++ continue; ++ ++ video_rom_resource.start = start; ++ ++ /* 0 < length <= 0x7f * 512, historically */ ++ length = rom[2] * 512; ++ ++ /* if checksum okay, trust length byte */ ++ if (length && romchecksum(rom, length)) ++ video_rom_resource.end = start + length - 1; ++ ++ request_resource(&iomem_resource, &video_rom_resource); ++ break; ++ } ++ ++ start = (video_rom_resource.end + 1 + 2047) & ~2047UL; ++ if (start < upper) ++ start = upper; ++ ++ /* system rom */ ++ request_resource(&iomem_resource, &system_rom_resource); ++ upper = system_rom_resource.start; ++ ++ /* check for extension rom (ignore length byte!) */ ++ rom = isa_bus_to_virt(extension_rom_resource.start); ++ if (romsignature(rom)) { ++ length = extension_rom_resource.end - extension_rom_resource.start + 1; ++ if (romchecksum(rom, length)) { ++ request_resource(&iomem_resource, &extension_rom_resource); ++ upper = extension_rom_resource.start; ++ } ++ } ++ ++ /* check for adapter roms on 2k boundaries */ ++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; ++ start += 2048) { ++ rom = isa_bus_to_virt(start); ++ if (!romsignature(rom)) ++ continue; ++ ++ /* 0 < length <= 0x7f * 512, historically */ ++ length = rom[2] * 512; ++ ++ /* but accept any length that fits if checksum okay */ ++ if (!length || start + length > upper || !romchecksum(rom, length)) ++ continue; ++ ++ adapter_rom_resources[i].start = start; ++ adapter_rom_resources[i].end = start + length - 1; ++ request_resource(&iomem_resource, &adapter_rom_resources[i]); ++ ++ start = adapter_rom_resources[i++].end & ~2047UL; ++ } ++} ++ ++#ifdef CONFIG_PROC_VMCORE ++/* elfcorehdr= specifies the location of elf core header ++ * stored by the crashed kernel. This option will be passed ++ * by kexec loader to the capture kernel. ++ */ ++static int __init setup_elfcorehdr(char *arg) ++{ ++ char *end; ++ if (!arg) ++ return -EINVAL; ++ elfcorehdr_addr = memparse(arg, &end); ++ return end > arg ? 0 : -EINVAL; ++} ++early_param("elfcorehdr", setup_elfcorehdr); ++#endif ++ ++#ifndef CONFIG_NUMA ++static void __init ++contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) ++{ ++ unsigned long bootmap_size, bootmap; ++ ++ bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT; ++ bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size); ++ if (bootmap == -1L) ++ panic("Cannot find bootmem map of size %ld\n",bootmap_size); ++ bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn); ++ e820_register_active_regions(0, start_pfn, end_pfn); ++#ifdef CONFIG_XEN ++ free_bootmem_with_active_regions(0, xen_start_info->nr_pages); ++#else ++ free_bootmem_with_active_regions(0, end_pfn); ++#endif ++ reserve_bootmem(bootmap, bootmap_size); ++} ++#endif ++ ++#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) ++struct edd edd; ++#ifdef CONFIG_EDD_MODULE ++EXPORT_SYMBOL(edd); ++#endif ++/** ++ * copy_edd() - Copy the BIOS EDD information ++ * from boot_params into a safe place. ++ * ++ */ ++static inline void copy_edd(void) ++{ ++ memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); ++ memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); ++ edd.mbr_signature_nr = EDD_MBR_SIG_NR; ++ edd.edd_info_nr = EDD_NR; ++} ++#else ++static inline void copy_edd(void) ++{ ++} ++#endif ++ ++#ifndef CONFIG_XEN ++#define EBDA_ADDR_POINTER 0x40E ++ ++unsigned __initdata ebda_addr; ++unsigned __initdata ebda_size; ++ ++static void discover_ebda(void) ++{ ++ /* ++ * there is a real-mode segmented pointer pointing to the ++ * 4K EBDA area at 0x40E ++ */ ++ ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER; ++ ebda_addr <<= 4; ++ ++ ebda_size = *(unsigned short *)(unsigned long)ebda_addr; ++ ++ /* Round EBDA up to pages */ ++ if (ebda_size == 0) ++ ebda_size = 1; ++ ebda_size <<= 10; ++ ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE); ++ if (ebda_size > 64*1024) ++ ebda_size = 64*1024; ++} ++#else ++#define discover_ebda() ((void)0) ++#endif ++ ++void __init setup_arch(char **cmdline_p) ++{ ++ printk(KERN_INFO "Command line: %s\n", saved_command_line); ++ ++#ifdef CONFIG_XEN ++ /* Register a call for panic conditions. */ ++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); ++ ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++ screen_info = SCREEN_INFO; ++ ++ if (is_initial_xendomain()) { ++ /* This is drawn from a dump from vgacon:startup in ++ * standard Linux. */ ++ screen_info.orig_video_mode = 3; ++ screen_info.orig_video_isVGA = 1; ++ screen_info.orig_video_lines = 25; ++ screen_info.orig_video_cols = 80; ++ screen_info.orig_video_ega_bx = 3; ++ screen_info.orig_video_points = 16; ++ screen_info.orig_y = screen_info.orig_video_lines - 1; ++ if (xen_start_info->console.dom0.info_size >= ++ sizeof(struct dom0_vga_console_info)) { ++ const struct dom0_vga_console_info *info = ++ (struct dom0_vga_console_info *)( ++ (char *)xen_start_info + ++ xen_start_info->console.dom0.info_off); ++ dom0_init_screen_info(info); ++ } ++ xen_start_info->console.domU.mfn = 0; ++ xen_start_info->console.domU.evtchn = 0; ++ } else ++ screen_info.orig_video_isVGA = 0; ++#else ++ ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); ++ screen_info = SCREEN_INFO; ++#endif /* !CONFIG_XEN */ ++ ++ edid_info = EDID_INFO; ++ saved_video_mode = SAVED_VIDEO_MODE; ++ bootloader_type = LOADER_TYPE; ++ ++#ifdef CONFIG_BLK_DEV_RAM ++ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; ++ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); ++ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); ++#endif ++#ifdef CONFIG_XEN ++ HYPERVISOR_vm_assist(VMASST_CMD_enable, ++ VMASST_TYPE_writable_pagetables); ++ ++ ARCH_SETUP ++#endif ++ ++ setup_memory_region(); ++ copy_edd(); ++ ++ if (!MOUNT_ROOT_RDONLY) ++ root_mountflags &= ~MS_RDONLY; ++ init_mm.start_code = (unsigned long) &_text; ++ init_mm.end_code = (unsigned long) &_etext; ++ init_mm.end_data = (unsigned long) &_edata; ++ init_mm.brk = (unsigned long) &_end; ++ ++ code_resource.start = virt_to_phys(&_text); ++ code_resource.end = virt_to_phys(&_etext)-1; ++ data_resource.start = virt_to_phys(&_etext); ++ data_resource.end = virt_to_phys(&_edata)-1; ++ ++ early_identify_cpu(&boot_cpu_data); ++ ++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ *cmdline_p = command_line; ++ ++ parse_early_param(); ++ ++ finish_e820_parsing(); ++ ++ e820_register_active_regions(0, 0, -1UL); ++ /* ++ * partially used pages are not usable - thus ++ * we are rounding upwards: ++ */ ++ end_pfn = e820_end_of_ram(); ++ num_physpages = end_pfn; ++ ++ check_efer(); ++ ++ discover_ebda(); ++ ++ init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT)); ++ ++ if (is_initial_xendomain()) ++ dmi_scan_machine(); ++ ++ zap_low_mappings(0); ++ ++ /* How many end-of-memory variables you have, grandma! */ ++ max_low_pfn = end_pfn; ++ max_pfn = end_pfn; ++ high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1; ++ ++ /* Remove active ranges so rediscovery with NUMA-awareness happens */ ++ remove_all_active_ranges(); ++ ++#ifdef CONFIG_ACPI_NUMA ++ /* ++ * Parse SRAT to discover nodes. ++ */ ++ acpi_numa_init(); ++#endif ++ ++#ifdef CONFIG_NUMA ++ numa_initmem_init(0, end_pfn); ++#else ++ contig_initmem_init(0, end_pfn); ++#endif ++ ++#ifdef CONFIG_XEN ++ /* ++ * Reserve kernel, physmap, start info, initial page tables, and ++ * direct mapping. ++ */ ++ reserve_bootmem_generic(__pa_symbol(&_text), ++ (table_end << PAGE_SHIFT) - __pa_symbol(&_text)); ++#else ++ /* Reserve direct mapping */ ++ reserve_bootmem_generic(table_start << PAGE_SHIFT, ++ (table_end - table_start) << PAGE_SHIFT); ++ ++ /* reserve kernel */ ++ reserve_bootmem_generic(__pa_symbol(&_text), ++ __pa_symbol(&_end) - __pa_symbol(&_text)); ++ ++ /* ++ * reserve physical page 0 - it's a special BIOS page on many boxes, ++ * enabling clean reboots, SMP operation, laptop functions. ++ */ ++ reserve_bootmem_generic(0, PAGE_SIZE); ++ ++ /* reserve ebda region */ ++ if (ebda_addr) ++ reserve_bootmem_generic(ebda_addr, ebda_size); ++ ++#ifdef CONFIG_SMP ++ /* ++ * But first pinch a few for the stack/trampoline stuff ++ * FIXME: Don't need the extra page at 4K, but need to fix ++ * trampoline before removing it. (see the GDT stuff) ++ */ ++ reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE); ++ ++ /* Reserve SMP trampoline */ ++ reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE); ++#endif ++#endif ++ ++#ifdef CONFIG_ACPI_SLEEP ++ /* ++ * Reserve low memory region for sleep support. ++ */ ++ acpi_reserve_bootmem(); ++#endif ++#ifdef CONFIG_XEN ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (xen_start_info->mod_start) { ++ if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { ++ /*reserve_bootmem_generic(INITRD_START, INITRD_SIZE);*/ ++ initrd_start = INITRD_START + PAGE_OFFSET; ++ initrd_end = initrd_start+INITRD_SIZE; ++ initrd_below_start_ok = 1; ++ } else { ++ printk(KERN_ERR "initrd extends beyond end of memory " ++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ (unsigned long)(INITRD_START + INITRD_SIZE), ++ (unsigned long)(end_pfn << PAGE_SHIFT)); ++ initrd_start = 0; ++ } ++ } ++#endif ++#else /* CONFIG_XEN */ ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (LOADER_TYPE && INITRD_START) { ++ if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { ++ reserve_bootmem_generic(INITRD_START, INITRD_SIZE); ++ initrd_start = INITRD_START + PAGE_OFFSET; ++ initrd_end = initrd_start+INITRD_SIZE; ++ } ++ else { ++ printk(KERN_ERR "initrd extends beyond end of memory " ++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ (unsigned long)(INITRD_START + INITRD_SIZE), ++ (unsigned long)(end_pfn << PAGE_SHIFT)); ++ initrd_start = 0; ++ } ++ } ++#endif ++#endif /* !CONFIG_XEN */ ++#ifdef CONFIG_KEXEC ++#ifdef CONFIG_XEN ++ xen_machine_kexec_setup_resources(); ++#else ++ if (crashk_res.start != crashk_res.end) { ++ reserve_bootmem_generic(crashk_res.start, ++ crashk_res.end - crashk_res.start + 1); ++ } ++#endif ++#endif ++ ++ paging_init(); ++ /* ++ * Find and reserve possible boot-time SMP configuration: ++ */ ++ find_smp_config(); ++#ifdef CONFIG_XEN ++ { ++ int i, j, k, fpp; ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Make sure we have a large enough P->M table. */ ++ phys_to_machine_mapping = alloc_bootmem_pages( ++ end_pfn * sizeof(unsigned long)); ++ memset(phys_to_machine_mapping, ~0, ++ end_pfn * sizeof(unsigned long)); ++ memcpy(phys_to_machine_mapping, ++ (unsigned long *)xen_start_info->mfn_list, ++ xen_start_info->nr_pages * sizeof(unsigned long)); ++ free_bootmem( ++ __pa(xen_start_info->mfn_list), ++ PFN_PHYS(PFN_UP(xen_start_info->nr_pages * ++ sizeof(unsigned long)))); ++ ++ /* ++ * Initialise the list of the frames that specify the ++ * list of frames that make up the p2m table. Used by ++ * save/restore. ++ */ ++ pfn_to_mfn_frame_list_list = alloc_bootmem_pages(PAGE_SIZE); ++ ++ fpp = PAGE_SIZE/sizeof(unsigned long); ++ for (i=0, j=0, k=-1; i< end_pfn; i+=fpp, j++) { ++ if ((j % fpp) == 0) { ++ k++; ++ BUG_ON(k>=fpp); ++ pfn_to_mfn_frame_list[k] = ++ alloc_bootmem_pages(PAGE_SIZE); ++ pfn_to_mfn_frame_list_list[k] = ++ virt_to_mfn(pfn_to_mfn_frame_list[k]); ++ j=0; ++ } ++ pfn_to_mfn_frame_list[k][j] = ++ virt_to_mfn(&phys_to_machine_mapping[i]); ++ } ++ HYPERVISOR_shared_info->arch.max_pfn = end_pfn; ++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = ++ virt_to_mfn(pfn_to_mfn_frame_list_list); ++ } ++ ++ } ++ ++#ifdef CONFIG_ACPI ++ if (!is_initial_xendomain()) { ++ acpi_disabled = 1; ++ acpi_ht = 0; ++ } ++#endif ++#endif ++ ++#ifndef CONFIG_XEN ++#ifdef CONFIG_PCI ++ early_quirks(); ++#endif ++#endif ++ ++ /* ++ * set this early, so we dont allocate cpu0 ++ * if MADT list doesnt list BSP first ++ * mpparse.c/MP_processor_info() allocates logical cpu numbers. ++ */ ++ cpu_set(0, cpu_present_map); ++#ifdef CONFIG_ACPI ++ /* ++ * Initialize the ACPI boot-time table parser (gets the RSDP and SDT). ++ * Call this early for SRAT node setup. ++ */ ++ acpi_boot_table_init(); ++ ++ /* ++ * Read APIC and some other early information from ACPI tables. ++ */ ++ acpi_boot_init(); ++#endif ++ ++ init_cpu_to_node(); ++ ++ /* ++ * get boot-time SMP configuration: ++ */ ++ if (smp_found_config) ++ get_smp_config(); ++#ifndef CONFIG_XEN ++ init_apic_mappings(); ++#endif ++#if defined(CONFIG_XEN) && defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU) ++ prefill_possible_map(); ++#endif ++ ++ /* ++ * Request address space for all standard RAM and ROM resources ++ * and also for regions reported as reserved by the e820. ++ */ ++ probe_roms(); ++#ifdef CONFIG_XEN ++ if (is_initial_xendomain()) { ++ struct xen_memory_map memmap; ++ ++ memmap.nr_entries = E820MAX; ++ set_xen_guest_handle(memmap.buffer, machine_e820.map); ++ ++ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap)) ++ BUG(); ++ machine_e820.nr_map = memmap.nr_entries; ++ ++ e820_reserve_resources(machine_e820.map, machine_e820.nr_map); ++ } ++#else ++ e820_reserve_resources(e820.map, e820.nr_map); ++#endif ++ e820_mark_nosave_regions(); ++ ++ request_resource(&iomem_resource, &video_ram_resource); ++ ++ { ++ unsigned i; ++ /* request I/O space for devices used on all i[345]86 PCs */ ++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) ++ request_resource(&ioport_resource, &standard_io_resources[i]); ++ } ++ ++#ifdef CONFIG_XEN ++ if (is_initial_xendomain()) ++ e820_setup_gap(machine_e820.map, machine_e820.nr_map); ++#else ++ e820_setup_gap(e820.map, e820.nr_map); ++#endif ++ ++#ifdef CONFIG_XEN ++ { ++ struct physdev_set_iopl set_iopl; ++ ++ set_iopl.iopl = 1; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); ++ ++ if (is_initial_xendomain()) { ++#ifdef CONFIG_VT ++#if defined(CONFIG_VGA_CONSOLE) ++ conswitchp = &vga_con; ++#elif defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++#endif ++ } else { ++#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++ } ++ } ++ xencons_early_setup(); ++#else /* CONFIG_XEN */ ++ ++#ifdef CONFIG_VT ++#if defined(CONFIG_VGA_CONSOLE) ++ conswitchp = &vga_con; ++#elif defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; ++#endif ++#endif ++ ++#endif /* !CONFIG_XEN */ ++} ++ ++#ifdef CONFIG_XEN ++static int ++xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ HYPERVISOR_shutdown(SHUTDOWN_crash); ++ /* we're never actually going to get here... */ ++ return NOTIFY_DONE; ++} ++#endif /* !CONFIG_XEN */ ++ ++ ++static int __cpuinit get_model_name(struct cpuinfo_x86 *c) ++{ ++ unsigned int *v; ++ ++ if (c->extended_cpuid_level < 0x80000004) ++ return 0; ++ ++ v = (unsigned int *) c->x86_model_id; ++ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); ++ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); ++ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); ++ c->x86_model_id[48] = 0; ++ return 1; ++} ++ ++ ++static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c) ++{ ++ unsigned int n, dummy, eax, ebx, ecx, edx; ++ ++ n = c->extended_cpuid_level; ++ ++ if (n >= 0x80000005) { ++ cpuid(0x80000005, &dummy, &ebx, &ecx, &edx); ++ printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", ++ edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); ++ c->x86_cache_size=(ecx>>24)+(edx>>24); ++ /* On K8 L1 TLB is inclusive, so don't count it */ ++ c->x86_tlbsize = 0; ++ } ++ ++ if (n >= 0x80000006) { ++ cpuid(0x80000006, &dummy, &ebx, &ecx, &edx); ++ ecx = cpuid_ecx(0x80000006); ++ c->x86_cache_size = ecx >> 16; ++ c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff); ++ ++ printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", ++ c->x86_cache_size, ecx & 0xFF); ++ } ++ ++ if (n >= 0x80000007) ++ cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power); ++ if (n >= 0x80000008) { ++ cpuid(0x80000008, &eax, &dummy, &dummy, &dummy); ++ c->x86_virt_bits = (eax >> 8) & 0xff; ++ c->x86_phys_bits = eax & 0xff; ++ } ++} ++ ++#ifdef CONFIG_NUMA ++static int nearby_node(int apicid) ++{ ++ int i; ++ for (i = apicid - 1; i >= 0; i--) { ++ int node = apicid_to_node[i]; ++ if (node != NUMA_NO_NODE && node_online(node)) ++ return node; ++ } ++ for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { ++ int node = apicid_to_node[i]; ++ if (node != NUMA_NO_NODE && node_online(node)) ++ return node; ++ } ++ return first_node(node_online_map); /* Shouldn't happen */ ++} ++#endif ++ ++/* ++ * On a AMD dual core setup the lower bits of the APIC id distingush the cores. ++ * Assumes number of cores is a power of two. ++ */ ++static void __init amd_detect_cmp(struct cpuinfo_x86 *c) ++{ ++#ifdef CONFIG_SMP ++ unsigned bits; ++#ifdef CONFIG_NUMA ++ int cpu = smp_processor_id(); ++ int node = 0; ++ unsigned apicid = hard_smp_processor_id(); ++#endif ++ unsigned ecx = cpuid_ecx(0x80000008); ++ ++ c->x86_max_cores = (ecx & 0xff) + 1; ++ ++ /* CPU telling us the core id bits shift? */ ++ bits = (ecx >> 12) & 0xF; ++ ++ /* Otherwise recompute */ ++ if (bits == 0) { ++ while ((1 << bits) < c->x86_max_cores) ++ bits++; ++ } ++ ++ /* Low order bits define the core id (index of core in socket) */ ++ c->cpu_core_id = c->phys_proc_id & ((1 << bits)-1); ++ /* Convert the APIC ID into the socket ID */ ++ c->phys_proc_id = phys_pkg_id(bits); ++ ++#ifdef CONFIG_NUMA ++ node = c->phys_proc_id; ++ if (apicid_to_node[apicid] != NUMA_NO_NODE) ++ node = apicid_to_node[apicid]; ++ if (!node_online(node)) { ++ /* Two possibilities here: ++ - The CPU is missing memory and no node was created. ++ In that case try picking one from a nearby CPU ++ - The APIC IDs differ from the HyperTransport node IDs ++ which the K8 northbridge parsing fills in. ++ Assume they are all increased by a constant offset, ++ but in the same order as the HT nodeids. ++ If that doesn't result in a usable node fall back to the ++ path for the previous case. */ ++ int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits); ++ if (ht_nodeid >= 0 && ++ apicid_to_node[ht_nodeid] != NUMA_NO_NODE) ++ node = apicid_to_node[ht_nodeid]; ++ /* Pick a nearby node */ ++ if (!node_online(node)) ++ node = nearby_node(apicid); ++ } ++ numa_set_node(cpu, node); ++ ++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node); ++#endif ++#endif ++} ++ ++static void __cpuinit init_amd(struct cpuinfo_x86 *c) ++{ ++ unsigned level; ++ ++#ifdef CONFIG_SMP ++ unsigned long value; ++ ++ /* ++ * Disable TLB flush filter by setting HWCR.FFDIS on K8 ++ * bit 6 of msr C001_0015 ++ * ++ * Errata 63 for SH-B3 steppings ++ * Errata 122 for all steppings (F+ have it disabled by default) ++ */ ++ if (c->x86 == 15) { ++ rdmsrl(MSR_K8_HWCR, value); ++ value |= 1 << 6; ++ wrmsrl(MSR_K8_HWCR, value); ++ } ++#endif ++ ++ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; ++ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ ++ clear_bit(0*32+31, &c->x86_capability); ++ ++ /* On C+ stepping K8 rep microcode works well for copy/memset */ ++ level = cpuid_eax(1); ++ if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)) ++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); ++ ++ /* Enable workaround for FXSAVE leak */ ++ if (c->x86 >= 6) ++ set_bit(X86_FEATURE_FXSAVE_LEAK, &c->x86_capability); ++ ++ level = get_model_name(c); ++ if (!level) { ++ switch (c->x86) { ++ case 15: ++ /* Should distinguish Models here, but this is only ++ a fallback anyways. */ ++ strcpy(c->x86_model_id, "Hammer"); ++ break; ++ } ++ } ++ display_cacheinfo(c); ++ ++ /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */ ++ if (c->x86_power & (1<<8)) ++ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); ++ ++ /* Multi core CPU? */ ++ if (c->extended_cpuid_level >= 0x80000008) ++ amd_detect_cmp(c); ++ ++ /* Fix cpuid4 emulation for more */ ++ num_cache_leaves = 3; ++ ++ /* RDTSC can be speculated around */ ++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++} ++ ++static void __cpuinit detect_ht(struct cpuinfo_x86 *c) ++{ ++#ifdef CONFIG_SMP ++ u32 eax, ebx, ecx, edx; ++ int index_msb, core_bits; ++ ++ cpuid(1, &eax, &ebx, &ecx, &edx); ++ ++ ++ if (!cpu_has(c, X86_FEATURE_HT)) ++ return; ++ if (cpu_has(c, X86_FEATURE_CMP_LEGACY)) ++ goto out; ++ ++ smp_num_siblings = (ebx & 0xff0000) >> 16; ++ ++ if (smp_num_siblings == 1) { ++ printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); ++ } else if (smp_num_siblings > 1 ) { ++ ++ if (smp_num_siblings > NR_CPUS) { ++ printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); ++ smp_num_siblings = 1; ++ return; ++ } ++ ++ index_msb = get_count_order(smp_num_siblings); ++ c->phys_proc_id = phys_pkg_id(index_msb); ++ ++ smp_num_siblings = smp_num_siblings / c->x86_max_cores; ++ ++ index_msb = get_count_order(smp_num_siblings) ; ++ ++ core_bits = get_count_order(c->x86_max_cores); ++ ++ c->cpu_core_id = phys_pkg_id(index_msb) & ++ ((1 << core_bits) - 1); ++ } ++out: ++ if ((c->x86_max_cores * smp_num_siblings) > 1) { ++ printk(KERN_INFO "CPU: Physical Processor ID: %d\n", c->phys_proc_id); ++ printk(KERN_INFO "CPU: Processor Core ID: %d\n", c->cpu_core_id); ++ } ++ ++#endif ++} ++ ++/* ++ * find out the number of processor cores on the die ++ */ ++static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c) ++{ ++ unsigned int eax, t; ++ ++ if (c->cpuid_level < 4) ++ return 1; ++ ++ cpuid_count(4, 0, &eax, &t, &t, &t); ++ ++ if (eax & 0x1f) ++ return ((eax >> 26) + 1); ++ else ++ return 1; ++} ++ ++static void srat_detect_node(void) ++{ ++#ifdef CONFIG_NUMA ++ unsigned node; ++ int cpu = smp_processor_id(); ++ int apicid = hard_smp_processor_id(); ++ ++ /* Don't do the funky fallback heuristics the AMD version employs ++ for now. */ ++ node = apicid_to_node[apicid]; ++ if (node == NUMA_NO_NODE) ++ node = first_node(node_online_map); ++ numa_set_node(cpu, node); ++ ++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node); ++#endif ++} ++ ++static void __cpuinit init_intel(struct cpuinfo_x86 *c) ++{ ++ /* Cache sizes */ ++ unsigned n; ++ ++ init_intel_cacheinfo(c); ++ if (c->cpuid_level > 9 ) { ++ unsigned eax = cpuid_eax(10); ++ /* Check for version and the number of counters */ ++ if ((eax & 0xff) && (((eax>>8) & 0xff) > 1)) ++ set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability); ++ } ++ ++ if (cpu_has_ds) { ++ unsigned int l1, l2; ++ rdmsr(MSR_IA32_MISC_ENABLE, l1, l2); ++ if (!(l1 & (1<<11))) ++ set_bit(X86_FEATURE_BTS, c->x86_capability); ++ if (!(l1 & (1<<12))) ++ set_bit(X86_FEATURE_PEBS, c->x86_capability); ++ } ++ ++ n = c->extended_cpuid_level; ++ if (n >= 0x80000008) { ++ unsigned eax = cpuid_eax(0x80000008); ++ c->x86_virt_bits = (eax >> 8) & 0xff; ++ c->x86_phys_bits = eax & 0xff; ++ /* CPUID workaround for Intel 0F34 CPU */ ++ if (c->x86_vendor == X86_VENDOR_INTEL && ++ c->x86 == 0xF && c->x86_model == 0x3 && ++ c->x86_mask == 0x4) ++ c->x86_phys_bits = 36; ++ } ++ ++ if (c->x86 == 15) ++ c->x86_cache_alignment = c->x86_clflush_size * 2; ++ if ((c->x86 == 0xf && c->x86_model >= 0x03) || ++ (c->x86 == 0x6 && c->x86_model >= 0x0e)) ++ set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); ++ if (c->x86 == 6) ++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); ++ if (c->x86 == 15) ++ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ else ++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ c->x86_max_cores = intel_num_cpu_cores(c); ++ ++ srat_detect_node(); ++} ++ ++static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) ++{ ++ char *v = c->x86_vendor_id; ++ ++ if (!strcmp(v, "AuthenticAMD")) ++ c->x86_vendor = X86_VENDOR_AMD; ++ else if (!strcmp(v, "GenuineIntel")) ++ c->x86_vendor = X86_VENDOR_INTEL; ++ else ++ c->x86_vendor = X86_VENDOR_UNKNOWN; ++} ++ ++struct cpu_model_info { ++ int vendor; ++ int family; ++ char *model_names[16]; ++}; ++ ++/* Do some early cpuid on the boot CPU to get some parameter that are ++ needed before check_bugs. Everything advanced is in identify_cpu ++ below. */ ++void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) ++{ ++ u32 tfms; ++ ++ c->loops_per_jiffy = loops_per_jiffy; ++ c->x86_cache_size = -1; ++ c->x86_vendor = X86_VENDOR_UNKNOWN; ++ c->x86_model = c->x86_mask = 0; /* So far unknown... */ ++ c->x86_vendor_id[0] = '\0'; /* Unset */ ++ c->x86_model_id[0] = '\0'; /* Unset */ ++ c->x86_clflush_size = 64; ++ c->x86_cache_alignment = c->x86_clflush_size; ++ c->x86_max_cores = 1; ++ c->extended_cpuid_level = 0; ++ memset(&c->x86_capability, 0, sizeof c->x86_capability); ++ ++ /* Get vendor name */ ++ cpuid(0x00000000, (unsigned int *)&c->cpuid_level, ++ (unsigned int *)&c->x86_vendor_id[0], ++ (unsigned int *)&c->x86_vendor_id[8], ++ (unsigned int *)&c->x86_vendor_id[4]); ++ ++ get_cpu_vendor(c); ++ ++ /* Initialize the standard set of capabilities */ ++ /* Note that the vendor-specific code below might override */ ++ ++ /* Intel-defined flags: level 0x00000001 */ ++ if (c->cpuid_level >= 0x00000001) { ++ __u32 misc; ++ cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4], ++ &c->x86_capability[0]); ++ c->x86 = (tfms >> 8) & 0xf; ++ c->x86_model = (tfms >> 4) & 0xf; ++ c->x86_mask = tfms & 0xf; ++ if (c->x86 == 0xf) ++ c->x86 += (tfms >> 20) & 0xff; ++ if (c->x86 >= 0x6) ++ c->x86_model += ((tfms >> 16) & 0xF) << 4; ++ if (c->x86_capability[0] & (1<<19)) ++ c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; ++ } else { ++ /* Have CPUID level 0 only - unheard of */ ++ c->x86 = 4; ++ } ++ ++#ifdef CONFIG_SMP ++ c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff; ++#endif ++} ++ ++/* ++ * This does the hard work of actually picking apart the CPU stuff... ++ */ ++void __cpuinit identify_cpu(struct cpuinfo_x86 *c) ++{ ++ int i; ++ u32 xlvl; ++ ++ early_identify_cpu(c); ++ ++ /* AMD-defined flags: level 0x80000001 */ ++ xlvl = cpuid_eax(0x80000000); ++ c->extended_cpuid_level = xlvl; ++ if ((xlvl & 0xffff0000) == 0x80000000) { ++ if (xlvl >= 0x80000001) { ++ c->x86_capability[1] = cpuid_edx(0x80000001); ++ c->x86_capability[6] = cpuid_ecx(0x80000001); ++ } ++ if (xlvl >= 0x80000004) ++ get_model_name(c); /* Default name */ ++ } ++ ++ /* Transmeta-defined flags: level 0x80860001 */ ++ xlvl = cpuid_eax(0x80860000); ++ if ((xlvl & 0xffff0000) == 0x80860000) { ++ /* Don't set x86_cpuid_level here for now to not confuse. */ ++ if (xlvl >= 0x80860001) ++ c->x86_capability[2] = cpuid_edx(0x80860001); ++ } ++ ++ c->apicid = phys_pkg_id(0); ++ ++ /* ++ * Vendor-specific initialization. In this section we ++ * canonicalize the feature flags, meaning if there are ++ * features a certain CPU supports which CPUID doesn't ++ * tell us, CPUID claiming incorrect flags, or other bugs, ++ * we handle them here. ++ * ++ * At the end of this section, c->x86_capability better ++ * indicate the features this CPU genuinely supports! ++ */ ++ switch (c->x86_vendor) { ++ case X86_VENDOR_AMD: ++ init_amd(c); ++ break; ++ ++ case X86_VENDOR_INTEL: ++ init_intel(c); ++ break; ++ ++ case X86_VENDOR_UNKNOWN: ++ default: ++ display_cacheinfo(c); ++ break; ++ } ++ ++ select_idle_routine(c); ++ detect_ht(c); ++ ++ /* ++ * On SMP, boot_cpu_data holds the common feature set between ++ * all CPUs; so make sure that we indicate which features are ++ * common between the CPUs. The first time this routine gets ++ * executed, c == &boot_cpu_data. ++ */ ++ if (c != &boot_cpu_data) { ++ /* AND the already accumulated flags with these */ ++ for (i = 0 ; i < NCAPINTS ; i++) ++ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; ++ } ++ ++#ifdef CONFIG_X86_MCE ++ mcheck_init(c); ++#endif ++ if (c == &boot_cpu_data) ++ mtrr_bp_init(); ++ else ++ mtrr_ap_init(); ++#ifdef CONFIG_NUMA ++ numa_add_cpu(smp_processor_id()); ++#endif ++} ++ ++ ++void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) ++{ ++ if (c->x86_model_id[0]) ++ printk("%s", c->x86_model_id); ++ ++ if (c->x86_mask || c->cpuid_level >= 0) ++ printk(" stepping %02x\n", c->x86_mask); ++ else ++ printk("\n"); ++} ++ ++/* ++ * Get CPU information for use by the procfs. ++ */ ++ ++static int show_cpuinfo(struct seq_file *m, void *v) ++{ ++ struct cpuinfo_x86 *c = v; ++ ++ /* ++ * These flag bits must match the definitions in <asm/cpufeature.h>. ++ * NULL means this bit is undefined or reserved; either way it doesn't ++ * have meaning as far as Linux is concerned. Note that it's important ++ * to realize there is a difference between this table and CPUID -- if ++ * applications want to get the raw CPUID data, they should access ++ * /dev/cpu/<cpu_nr>/cpuid instead. ++ */ ++ static char *x86_cap_flags[] = { ++ /* Intel-defined */ ++ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", ++ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", ++ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", ++ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, ++ ++ /* AMD-defined */ ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL, ++ NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow", ++ ++ /* Transmeta-defined */ ++ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ ++ /* Other (Linux-defined) */ ++ "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL, ++ "constant_tsc", NULL, NULL, ++ "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ ++ /* Intel-defined (#2) */ ++ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", ++ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, ++ NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ ++ /* VIA/Cyrix/Centaur-defined */ ++ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ ++ /* AMD-defined (#2) */ ++ "lahf_lm", "cmp_legacy", "svm", NULL, "cr8_legacy", NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ }; ++ static char *x86_power_flags[] = { ++ "ts", /* temperature sensor */ ++ "fid", /* frequency id control */ ++ "vid", /* voltage id control */ ++ "ttp", /* thermal trip */ ++ "tm", ++ "stc", ++ NULL, ++ /* nothing */ /* constant_tsc - moved to flags */ ++ }; ++ ++ ++#ifdef CONFIG_SMP ++ if (!cpu_online(c-cpu_data)) ++ return 0; ++#endif ++ ++ seq_printf(m,"processor\t: %u\n" ++ "vendor_id\t: %s\n" ++ "cpu family\t: %d\n" ++ "model\t\t: %d\n" ++ "model name\t: %s\n", ++ (unsigned)(c-cpu_data), ++ c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", ++ c->x86, ++ (int)c->x86_model, ++ c->x86_model_id[0] ? c->x86_model_id : "unknown"); ++ ++ if (c->x86_mask || c->cpuid_level >= 0) ++ seq_printf(m, "stepping\t: %d\n", c->x86_mask); ++ else ++ seq_printf(m, "stepping\t: unknown\n"); ++ ++ if (cpu_has(c,X86_FEATURE_TSC)) { ++ unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data)); ++ if (!freq) ++ freq = cpu_khz; ++ seq_printf(m, "cpu MHz\t\t: %u.%03u\n", ++ freq / 1000, (freq % 1000)); ++ } ++ ++ /* Cache size */ ++ if (c->x86_cache_size >= 0) ++ seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); ++ ++#ifdef CONFIG_SMP ++ if (smp_num_siblings * c->x86_max_cores > 1) { ++ int cpu = c - cpu_data; ++ seq_printf(m, "physical id\t: %d\n", c->phys_proc_id); ++ seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu])); ++ seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id); ++ seq_printf(m, "cpu cores\t: %d\n", c->booted_cores); ++ } ++#endif ++ ++ seq_printf(m, ++ "fpu\t\t: yes\n" ++ "fpu_exception\t: yes\n" ++ "cpuid level\t: %d\n" ++ "wp\t\t: yes\n" ++ "flags\t\t:", ++ c->cpuid_level); ++ ++ { ++ int i; ++ for ( i = 0 ; i < 32*NCAPINTS ; i++ ) ++ if (cpu_has(c, i) && x86_cap_flags[i] != NULL) ++ seq_printf(m, " %s", x86_cap_flags[i]); ++ } ++ ++ seq_printf(m, "\nbogomips\t: %lu.%02lu\n", ++ c->loops_per_jiffy/(500000/HZ), ++ (c->loops_per_jiffy/(5000/HZ)) % 100); ++ ++ if (c->x86_tlbsize > 0) ++ seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize); ++ seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size); ++ seq_printf(m, "cache_alignment\t: %d\n", c->x86_cache_alignment); ++ ++ seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", ++ c->x86_phys_bits, c->x86_virt_bits); ++ ++ seq_printf(m, "power management:"); ++ { ++ unsigned i; ++ for (i = 0; i < 32; i++) ++ if (c->x86_power & (1 << i)) { ++ if (i < ARRAY_SIZE(x86_power_flags) && ++ x86_power_flags[i]) ++ seq_printf(m, "%s%s", ++ x86_power_flags[i][0]?" ":"", ++ x86_power_flags[i]); ++ else ++ seq_printf(m, " [%d]", i); ++ } ++ } ++ ++ seq_printf(m, "\n\n"); ++ ++ return 0; ++} ++ ++static void *c_start(struct seq_file *m, loff_t *pos) ++{ ++ return *pos < NR_CPUS ? cpu_data + *pos : NULL; ++} ++ ++static void *c_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return c_start(m, pos); ++} ++ ++static void c_stop(struct seq_file *m, void *v) ++{ ++} ++ ++struct seq_operations cpuinfo_op = { ++ .start =c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = show_cpuinfo, ++}; ++ ++#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE) ++#include <linux/platform_device.h> ++static __init int add_pcspkr(void) ++{ ++ struct platform_device *pd; ++ int ret; ++ ++ if (!is_initial_xendomain()) ++ return 0; ++ ++ pd = platform_device_alloc("pcspkr", -1); ++ if (!pd) ++ return -ENOMEM; ++ ++ ret = platform_device_add(pd); ++ if (ret) ++ platform_device_put(pd); ++ ++ return ret; ++} ++device_initcall(add_pcspkr); ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/setup64-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/setup64-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,356 @@ ++/* ++ * X86-64 specific CPU setup. ++ * Copyright (C) 1995 Linus Torvalds ++ * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen. ++ * See setup.c for older changelog. ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Modified for Xen ++ * ++ */ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/bootmem.h> ++#include <linux/bitops.h> ++#include <linux/module.h> ++#include <asm/bootsetup.h> ++#include <asm/pda.h> ++#include <asm/pgtable.h> ++#include <asm/processor.h> ++#include <asm/desc.h> ++#include <asm/atomic.h> ++#include <asm/mmu_context.h> ++#include <asm/smp.h> ++#include <asm/i387.h> ++#include <asm/percpu.h> ++#include <asm/proto.h> ++#include <asm/sections.h> ++#ifdef CONFIG_XEN ++#include <asm/hypervisor.h> ++#endif ++ ++char x86_boot_params[BOOT_PARAM_SIZE] __initdata; ++ ++cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; ++ ++struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly; ++EXPORT_SYMBOL(_cpu_pda); ++struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned; ++ ++#ifndef CONFIG_X86_NO_IDT ++struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; ++#endif ++ ++char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned"))); ++ ++unsigned long __supported_pte_mask __read_mostly = ~0UL; ++EXPORT_SYMBOL(__supported_pte_mask); ++static int do_not_nx __cpuinitdata = 0; ++ ++/* noexec=on|off ++Control non executable mappings for 64bit processes. ++ ++on Enable(default) ++off Disable ++*/ ++static int __init nonx_setup(char *str) ++{ ++ if (!str) ++ return -EINVAL; ++ if (!strncmp(str, "on", 2)) { ++ __supported_pte_mask |= _PAGE_NX; ++ do_not_nx = 0; ++ } else if (!strncmp(str, "off", 3)) { ++ do_not_nx = 1; ++ __supported_pte_mask &= ~_PAGE_NX; ++ } ++ return 0; ++} ++early_param("noexec", nonx_setup); ++ ++int force_personality32 = 0; ++ ++/* noexec32=on|off ++Control non executable heap for 32bit processes. ++To control the stack too use noexec=off ++ ++on PROT_READ does not imply PROT_EXEC for 32bit processes ++off PROT_READ implies PROT_EXEC (default) ++*/ ++static int __init nonx32_setup(char *str) ++{ ++ if (!strcmp(str, "on")) ++ force_personality32 &= ~READ_IMPLIES_EXEC; ++ else if (!strcmp(str, "off")) ++ force_personality32 |= READ_IMPLIES_EXEC; ++ return 1; ++} ++__setup("noexec32=", nonx32_setup); ++ ++/* ++ * Great future plan: ++ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data. ++ * Always point %gs to its beginning ++ */ ++void __init setup_per_cpu_areas(void) ++{ ++ int i; ++ unsigned long size; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ prefill_possible_map(); ++#endif ++ ++ /* Copy section for each CPU (we discard the original) */ ++ size = PERCPU_ENOUGH_ROOM; ++ ++ printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size); ++ for_each_cpu_mask (i, cpu_possible_map) { ++ char *ptr; ++ ++ if (!NODE_DATA(cpu_to_node(i))) { ++ printk("cpu with no node %d, num_online_nodes %d\n", ++ i, num_online_nodes()); ++ ptr = alloc_bootmem(size); ++ } else { ++ ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size); ++ } ++ if (!ptr) ++ panic("Cannot allocate cpu data for CPU %d\n", i); ++ cpu_pda(i)->data_offset = ptr - __per_cpu_start; ++ memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); ++ } ++} ++ ++#ifdef CONFIG_XEN ++static void switch_pt(void) ++{ ++ xen_pt_switch(__pa(init_level4_pgt)); ++ xen_new_user_pt(__pa(init_level4_user_pgt)); ++} ++ ++void __cpuinit cpu_gdt_init(struct desc_ptr *gdt_descr) ++{ ++ unsigned long frames[16]; ++ unsigned long va; ++ int f; ++ ++ for (va = gdt_descr->address, f = 0; ++ va < gdt_descr->address + gdt_descr->size; ++ va += PAGE_SIZE, f++) { ++ frames[f] = virt_to_mfn(va); ++ make_page_readonly( ++ (void *)va, XENFEAT_writable_descriptor_tables); ++ } ++ if (HYPERVISOR_set_gdt(frames, gdt_descr->size / ++ sizeof (struct desc_struct))) ++ BUG(); ++} ++#else ++static void switch_pt(void) ++{ ++ asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt))); ++} ++ ++void __init cpu_gdt_init(struct desc_ptr *gdt_descr) ++{ ++ asm volatile("lgdt %0" :: "m" (*gdt_descr)); ++ asm volatile("lidt %0" :: "m" (idt_descr)); ++} ++#endif ++ ++void pda_init(int cpu) ++{ ++ struct x8664_pda *pda = cpu_pda(cpu); ++ ++ /* Setup up data that may be needed in __get_free_pages early */ ++ asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); ++#ifndef CONFIG_XEN ++ /* Memory clobbers used to order PDA accessed */ ++ mb(); ++ wrmsrl(MSR_GS_BASE, pda); ++ mb(); ++#else ++ HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL, (unsigned long)pda); ++#endif ++ pda->cpunumber = cpu; ++ pda->irqcount = -1; ++ pda->kernelstack = ++ (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE; ++ pda->active_mm = &init_mm; ++ pda->mmu_state = 0; ++ ++ if (cpu == 0) { ++#ifdef CONFIG_XEN ++ xen_init_pt(); ++#endif ++ /* others are initialized in smpboot.c */ ++ pda->pcurrent = &init_task; ++ pda->irqstackptr = boot_cpu_stack; ++ } else { ++ pda->irqstackptr = (char *) ++ __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER); ++ if (!pda->irqstackptr) ++ panic("cannot allocate irqstack for cpu %d", cpu); ++ } ++ ++ switch_pt(); ++ ++ pda->irqstackptr += IRQSTACKSIZE-64; ++} ++ ++#ifndef CONFIG_X86_NO_TSS ++char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ] ++__attribute__((section(".bss.page_aligned"))); ++#endif ++ ++/* May not be marked __init: used by software suspend */ ++void syscall_init(void) ++{ ++#ifndef CONFIG_XEN ++ /* ++ * LSTAR and STAR live in a bit strange symbiosis. ++ * They both write to the same internal register. STAR allows to set CS/DS ++ * but only a 32bit target. LSTAR sets the 64bit rip. ++ */ ++ wrmsrl(MSR_STAR, ((u64)__USER32_CS)<<48 | ((u64)__KERNEL_CS)<<32); ++ wrmsrl(MSR_LSTAR, system_call); ++ ++ /* Flags to clear on syscall */ ++ wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); ++#endif ++#ifdef CONFIG_IA32_EMULATION ++ syscall32_cpu_init (); ++#endif ++} ++ ++void __cpuinit check_efer(void) ++{ ++ unsigned long efer; ++ ++ rdmsrl(MSR_EFER, efer); ++ if (!(efer & EFER_NX) || do_not_nx) { ++ __supported_pte_mask &= ~_PAGE_NX; ++ } ++} ++ ++unsigned long kernel_eflags; ++ ++/* ++ * cpu_init() initializes state that is per-CPU. Some data is already ++ * initialized (naturally) in the bootstrap process, such as the GDT ++ * and IDT. We reload them nevertheless, this function acts as a ++ * 'CPU state barrier', nothing should get across. ++ * A lot of state is already set up in PDA init. ++ */ ++void __cpuinit cpu_init (void) ++{ ++ int cpu = stack_smp_processor_id(); ++#ifndef CONFIG_X86_NO_TSS ++ struct tss_struct *t = &per_cpu(init_tss, cpu); ++ struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu); ++ unsigned long v; ++ char *estacks = NULL; ++ int i; ++#endif ++ struct task_struct *me; ++ ++ /* CPU 0 is initialised in head64.c */ ++ if (cpu != 0) { ++ pda_init(cpu); ++ zap_low_mappings(cpu); ++ } ++#ifndef CONFIG_X86_NO_TSS ++ else ++ estacks = boot_exception_stacks; ++#endif ++ ++ me = current; ++ ++ if (cpu_test_and_set(cpu, cpu_initialized)) ++ panic("CPU#%d already initialized!\n", cpu); ++ ++ printk("Initializing CPU#%d\n", cpu); ++ ++ clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); ++ ++ /* ++ * Initialize the per-CPU GDT with the boot GDT, ++ * and set up the GDT descriptor: ++ */ ++#ifndef CONFIG_XEN ++ if (cpu) ++ memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE); ++#endif ++ ++ cpu_gdt_descr[cpu].size = GDT_SIZE; ++ cpu_gdt_init(&cpu_gdt_descr[cpu]); ++ ++ memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8); ++ syscall_init(); ++ ++ wrmsrl(MSR_FS_BASE, 0); ++ wrmsrl(MSR_KERNEL_GS_BASE, 0); ++ barrier(); ++ ++ check_efer(); ++ ++#ifndef CONFIG_X86_NO_TSS ++ /* ++ * set up and load the per-CPU TSS ++ */ ++ for (v = 0; v < N_EXCEPTION_STACKS; v++) { ++ static const unsigned int order[N_EXCEPTION_STACKS] = { ++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, ++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER ++ }; ++ if (cpu) { ++ estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); ++ if (!estacks) ++ panic("Cannot allocate exception stack %ld %d\n", ++ v, cpu); ++ } ++ estacks += PAGE_SIZE << order[v]; ++ orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks; ++ } ++ ++ t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap); ++ /* ++ * <= is required because the CPU will access up to ++ * 8 bits beyond the end of the IO permission bitmap. ++ */ ++ for (i = 0; i <= IO_BITMAP_LONGS; i++) ++ t->io_bitmap[i] = ~0UL; ++#endif ++ ++ atomic_inc(&init_mm.mm_count); ++ me->active_mm = &init_mm; ++ if (me->mm) ++ BUG(); ++ enter_lazy_tlb(&init_mm, me); ++ ++#ifndef CONFIG_X86_NO_TSS ++ set_tss_desc(cpu, t); ++#endif ++#ifndef CONFIG_XEN ++ load_TR_desc(); ++#endif ++ load_LDT(&init_mm.context); ++ ++ /* ++ * Clear all 6 debug registers: ++ */ ++ ++ set_debugreg(0UL, 0); ++ set_debugreg(0UL, 1); ++ set_debugreg(0UL, 2); ++ set_debugreg(0UL, 3); ++ set_debugreg(0UL, 6); ++ set_debugreg(0UL, 7); ++ ++ fpu_init(); ++ ++ raw_local_save_flags(kernel_eflags); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/smp.c +--- a/arch/x86_64/kernel/smp.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/smp.c Wed Aug 08 16:25:28 2007 -0300 +@@ -28,7 +28,11 @@ + #include <asm/proto.h> + #include <asm/apicdef.h> + #include <asm/idle.h> +- ++#ifdef CONFIG_XEN ++#include <xen/evtchn.h> ++#endif ++ ++#ifndef CONFIG_XEN + /* + * Smarter SMP flushing macros. + * c/o Linus Torvalds. +@@ -66,6 +70,7 @@ union smp_flush_state { + to a full cache line because other CPUs can access it and we don't + want false sharing in the per cpu data segment. */ + static DEFINE_PER_CPU(union smp_flush_state, flush_state); ++#endif + + /* + * We cannot call mmdrop() because we are in interrupt context, +@@ -79,6 +84,7 @@ static inline void leave_mm(int cpu) + load_cr3(swapper_pg_dir); + } + ++#ifndef CONFIG_XEN + /* + * + * The flush IPI assumes that a thread switch happens in this order: +@@ -283,6 +289,18 @@ void flush_tlb_all(void) + { + on_each_cpu(do_flush_tlb_all, NULL, 1, 1); + } ++#else ++asmlinkage void smp_invalidate_interrupt (void) ++{ return; } ++void flush_tlb_current_task(void) ++{ xen_tlb_flush_mask(¤t->mm->cpu_vm_mask); } ++void flush_tlb_mm (struct mm_struct * mm) ++{ xen_tlb_flush_mask(&mm->cpu_vm_mask); } ++void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) ++{ xen_invlpg_mask(&vma->vm_mm->cpu_vm_mask, va); } ++void flush_tlb_all(void) ++{ xen_tlb_flush_all(); } ++#endif /* Xen */ + + /* + * this function sends a 'reschedule' IPI to another CPU. +@@ -418,13 +436,21 @@ static void __smp_call_function (void (* + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) ++#ifdef CONFIG_XEN ++ barrier(); ++#else + cpu_relax(); ++#endif + + if (!wait) + return; + + while (atomic_read(&data.finished) != cpus) ++#ifdef CONFIG_XEN ++ barrier(); ++#else + cpu_relax(); ++#endif + } + + /* +@@ -460,7 +486,9 @@ void smp_stop_cpu(void) + */ + cpu_clear(smp_processor_id(), cpu_online_map); + local_irq_save(flags); ++#ifndef CONFIG_XEN + disable_local_APIC(); ++#endif + local_irq_restore(flags); + } + +@@ -474,8 +502,10 @@ void smp_send_stop(void) + void smp_send_stop(void) + { + int nolock = 0; ++#ifndef CONFIG_XEN + if (reboot_force) + return; ++#endif + /* Don't deadlock on the call lock in panic */ + if (!spin_trylock(&call_lock)) { + /* ignore locking because we have panicked anyways */ +@@ -486,7 +516,9 @@ void smp_send_stop(void) + spin_unlock(&call_lock); + + local_irq_disable(); ++#ifndef CONFIG_XEN + disable_local_APIC(); ++#endif + local_irq_enable(); + } + +@@ -495,18 +527,31 @@ void smp_send_stop(void) + * all the work is done automatically when + * we return from the interrupt. + */ ++#ifdef CONFIG_XEN ++asmlinkage irqreturn_t smp_reschedule_interrupt(void) ++{ ++ return IRQ_HANDLED; ++} ++#else + asmlinkage void smp_reschedule_interrupt(void) + { + ack_APIC_irq(); + } +- ++#endif ++ ++#ifdef CONFIG_XEN ++asmlinkage irqreturn_t smp_call_function_interrupt(void) ++#else + asmlinkage void smp_call_function_interrupt(void) ++#endif + { + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + ++#ifndef CONFIG_XEN + ack_APIC_irq(); ++#endif + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function +@@ -524,5 +569,7 @@ asmlinkage void smp_call_function_interr + mb(); + atomic_inc(&call_data->finished); + } +-} +- ++#ifdef CONFIG_XEN ++ return IRQ_HANDLED; ++#endif ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/time-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/time-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1073 @@ ++/* ++ * linux/arch/i386/kernel/time.c ++ * ++ * Copyright (C) 1991, 1992, 1995 Linus Torvalds ++ * ++ * This file contains the PC-specific time handling details: ++ * reading the RTC at bootup, etc.. ++ * 1994-07-02 Alan Modra ++ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime ++ * 1995-03-26 Markus Kuhn ++ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 ++ * precision CMOS clock update ++ * 1996-05-03 Ingo Molnar ++ * fixed time warps in do_[slow|fast]_gettimeoffset() ++ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 ++ * "A Kernel Model for Precision Timekeeping" by Dave Mills ++ * 1998-09-05 (Various) ++ * More robust do_fast_gettimeoffset() algorithm implemented ++ * (works with APM, Cyrix 6x86MX and Centaur C6), ++ * monotonic gettimeofday() with fast_get_timeoffset(), ++ * drift-proof precision TSC calibration on boot ++ * (C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D. ++ * Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>; ++ * ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>). ++ * 1998-12-16 Andrea Arcangeli ++ * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy ++ * because was not accounting lost_ticks. ++ * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli ++ * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to ++ * serialize accesses to xtime/lost_ticks). ++ */ ++ ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/param.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/module.h> ++#include <linux/sysdev.h> ++#include <linux/bcd.h> ++#include <linux/efi.h> ++#include <linux/mca.h> ++#include <linux/sysctl.h> ++#include <linux/percpu.h> ++#include <linux/kernel_stat.h> ++#include <linux/posix-timers.h> ++ ++#include <asm/io.h> ++#include <asm/smp.h> ++#include <asm/irq.h> ++#include <asm/msr.h> ++#include <asm/delay.h> ++#include <asm/mpspec.h> ++#include <asm/uaccess.h> ++#include <asm/processor.h> ++#include <asm/timer.h> ++#include <asm/sections.h> ++ ++#include "mach_time.h" ++ ++#include <linux/timex.h> ++ ++#include <asm/hpet.h> ++ ++#include <xen/evtchn.h> ++#include <xen/interface/vcpu.h> ++ ++int pit_latch_buggy; /* extern */ ++ ++unsigned long vxtime_hz = PIT_TICK_RATE; ++struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */ ++volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; ++struct timespec __xtime __section_xtime; ++struct timezone __sys_tz __section_sys_tz; ++ ++#define USEC_PER_TICK (USEC_PER_SEC / HZ) ++#define NSEC_PER_TICK (NSEC_PER_SEC / HZ) ++#define FSEC_PER_TICK (FSEC_PER_SEC / HZ) ++ ++#define NS_SCALE 10 /* 2^10, carefully chosen */ ++#define US_SCALE 32 /* 2^32, arbitralrily chosen */ ++ ++unsigned int cpu_khz; /* Detected as we calibrate the TSC */ ++EXPORT_SYMBOL(cpu_khz); ++ ++DEFINE_SPINLOCK(rtc_lock); ++EXPORT_SYMBOL(rtc_lock); ++ ++extern struct init_timer_opts timer_tsc_init; ++extern struct timer_opts timer_tsc; ++#define timer_none timer_tsc ++ ++/* These are peridically updated in shared_info, and then copied here. */ ++struct shadow_time_info { ++ u64 tsc_timestamp; /* TSC at last update of time vals. */ ++ u64 system_timestamp; /* Time, in nanosecs, since boot. */ ++ u32 tsc_to_nsec_mul; ++ u32 tsc_to_usec_mul; ++ int tsc_shift; ++ u32 version; ++}; ++static DEFINE_PER_CPU(struct shadow_time_info, shadow_time); ++static struct timespec shadow_tv; ++static u32 shadow_tv_version; ++ ++/* Keep track of last time we did processing/updating of jiffies and xtime. */ ++static u64 processed_system_time; /* System time (ns) at last processing. */ ++static DEFINE_PER_CPU(u64, processed_system_time); ++ ++/* How much CPU time was spent blocked and how much was 'stolen'? */ ++static DEFINE_PER_CPU(u64, processed_stolen_time); ++static DEFINE_PER_CPU(u64, processed_blocked_time); ++ ++/* Current runstate of each CPU (updated automatically by the hypervisor). */ ++static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate); ++ ++/* Must be signed, as it's compared with s64 quantities which can be -ve. */ ++#define NS_PER_TICK (1000000000LL/HZ) ++ ++static inline void __normalize_time(time_t *sec, s64 *nsec) ++{ ++ while (*nsec >= NSEC_PER_SEC) { ++ (*nsec) -= NSEC_PER_SEC; ++ (*sec)++; ++ } ++ while (*nsec < 0) { ++ (*nsec) += NSEC_PER_SEC; ++ (*sec)--; ++ } ++} ++ ++/* Does this guest OS track Xen time, or set its wall clock independently? */ ++static int independent_wallclock = 0; ++static int __init __independent_wallclock(char *str) ++{ ++ independent_wallclock = 1; ++ return 1; ++} ++__setup("independent_wallclock", __independent_wallclock); ++ ++/* Permitted clock jitter, in nsecs, beyond which a warning will be printed. */ ++static unsigned long permitted_clock_jitter = 10000000UL; /* 10ms */ ++static int __init __permitted_clock_jitter(char *str) ++{ ++ permitted_clock_jitter = simple_strtoul(str, NULL, 0); ++ return 1; ++} ++__setup("permitted_clock_jitter=", __permitted_clock_jitter); ++ ++/* ++ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, ++ * yielding a 64-bit result. ++ */ ++static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift) ++{ ++ u64 product; ++ ++ if (shift < 0) ++ delta >>= -shift; ++ else ++ delta <<= shift; ++ ++ __asm__ ( ++ "mul %%rdx ; shrd $32,%%rdx,%%rax" ++ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) ); ++ ++ return product; ++} ++ ++void init_cpu_khz(void) ++{ ++ u64 __cpu_khz = 1000000ULL << US_SCALE; ++ struct vcpu_time_info *info; ++ info = &HYPERVISOR_shared_info->vcpu_info[0].time; ++ do_div(__cpu_khz, info->tsc_to_system_mul); ++ if (info->tsc_shift < 0) ++ cpu_khz = __cpu_khz << -info->tsc_shift; ++ else ++ cpu_khz = __cpu_khz >> info->tsc_shift; ++} ++ ++static u64 get_nsec_offset(struct shadow_time_info *shadow) ++{ ++ u64 now, delta; ++ rdtscll(now); ++ delta = now - shadow->tsc_timestamp; ++ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); ++} ++ ++static unsigned long get_usec_offset(struct shadow_time_info *shadow) ++{ ++ u64 now, delta; ++ rdtscll(now); ++ delta = now - shadow->tsc_timestamp; ++ return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); ++} ++ ++static void __update_wallclock(time_t sec, long nsec) ++{ ++ long wtm_nsec, xtime_nsec; ++ time_t wtm_sec, xtime_sec; ++ u64 tmp, wc_nsec; ++ ++ /* Adjust wall-clock time base based on jiffies ticks. */ ++ wc_nsec = processed_system_time; ++ wc_nsec += sec * (u64)NSEC_PER_SEC; ++ wc_nsec += nsec; ++ ++ /* Split wallclock base into seconds and nanoseconds. */ ++ tmp = wc_nsec; ++ xtime_nsec = do_div(tmp, 1000000000); ++ xtime_sec = (time_t)tmp; ++ ++ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec); ++ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec); ++ ++ set_normalized_timespec(&xtime, xtime_sec, xtime_nsec); ++ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); ++ ++ ntp_clear(); ++} ++ ++static void update_wallclock(void) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ ++ do { ++ shadow_tv_version = s->wc_version; ++ rmb(); ++ shadow_tv.tv_sec = s->wc_sec; ++ shadow_tv.tv_nsec = s->wc_nsec; ++ rmb(); ++ } while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version)); ++ ++ if (!independent_wallclock) ++ __update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec); ++} ++ ++/* ++ * Reads a consistent set of time-base values from Xen, into a shadow data ++ * area. ++ */ ++static void get_time_values_from_xen(int cpu) ++{ ++ struct vcpu_time_info *src; ++ struct shadow_time_info *dst; ++ ++ src = &vcpu_info(cpu)->time; ++ dst = &per_cpu(shadow_time, cpu); ++ ++ do { ++ dst->version = src->version; ++ rmb(); ++ dst->tsc_timestamp = src->tsc_timestamp; ++ dst->system_timestamp = src->system_time; ++ dst->tsc_to_nsec_mul = src->tsc_to_system_mul; ++ dst->tsc_shift = src->tsc_shift; ++ rmb(); ++ } while ((src->version & 1) | (dst->version ^ src->version)); ++ ++ dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000; ++} ++ ++static inline int time_values_up_to_date(int cpu) ++{ ++ struct vcpu_time_info *src; ++ struct shadow_time_info *dst; ++ ++ src = &vcpu_info(cpu)->time; ++ dst = &per_cpu(shadow_time, cpu); ++ ++ rmb(); ++ return (dst->version == src->version); ++} ++ ++/* ++ * This is a special lock that is owned by the CPU and holds the index ++ * register we are working with. It is required for NMI access to the ++ * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. ++ */ ++volatile unsigned long cmos_lock = 0; ++EXPORT_SYMBOL(cmos_lock); ++ ++/* Routines for accessing the CMOS RAM/RTC. */ ++unsigned char rtc_cmos_read(unsigned char addr) ++{ ++ unsigned char val; ++ lock_cmos_prefix(addr); ++ outb_p(addr, RTC_PORT(0)); ++ val = inb_p(RTC_PORT(1)); ++ lock_cmos_suffix(addr); ++ return val; ++} ++EXPORT_SYMBOL(rtc_cmos_read); ++ ++void rtc_cmos_write(unsigned char val, unsigned char addr) ++{ ++ lock_cmos_prefix(addr); ++ outb_p(addr, RTC_PORT(0)); ++ outb_p(val, RTC_PORT(1)); ++ lock_cmos_suffix(addr); ++} ++EXPORT_SYMBOL(rtc_cmos_write); ++ ++/* ++ * This version of gettimeofday has microsecond resolution ++ * and better than microsecond precision on fast x86 machines with TSC. ++ */ ++void do_gettimeofday(struct timeval *tv) ++{ ++ unsigned long seq; ++ unsigned long usec, sec; ++ unsigned long max_ntp_tick; ++ s64 nsec; ++ unsigned int cpu; ++ struct shadow_time_info *shadow; ++ u32 local_time_version; ++ ++ cpu = get_cpu(); ++ shadow = &per_cpu(shadow_time, cpu); ++ ++ do { ++ local_time_version = shadow->version; ++ seq = read_seqbegin(&xtime_lock); ++ ++ usec = get_usec_offset(shadow); ++ ++ /* ++ * If time_adjust is negative then NTP is slowing the clock ++ * so make sure not to go into next possible interval. ++ * Better to lose some accuracy than have time go backwards.. ++ */ ++ if (unlikely(time_adjust < 0)) { ++ max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj; ++ usec = min(usec, max_ntp_tick); ++ } ++ ++ sec = xtime.tv_sec; ++ usec += (xtime.tv_nsec / NSEC_PER_USEC); ++ ++ nsec = shadow->system_timestamp - processed_system_time; ++ __normalize_time(&sec, &nsec); ++ usec += (long)nsec / NSEC_PER_USEC; ++ ++ if (unlikely(!time_values_up_to_date(cpu))) { ++ /* ++ * We may have blocked for a long time, ++ * rendering our calculations invalid ++ * (e.g. the time delta may have ++ * overflowed). Detect that and recalculate ++ * with fresh values. ++ */ ++ get_time_values_from_xen(cpu); ++ continue; ++ } ++ } while (read_seqretry(&xtime_lock, seq) || ++ (local_time_version != shadow->version)); ++ ++ put_cpu(); ++ ++ while (usec >= USEC_PER_SEC) { ++ usec -= USEC_PER_SEC; ++ sec++; ++ } ++ ++ tv->tv_sec = sec; ++ tv->tv_usec = usec; ++} ++ ++EXPORT_SYMBOL(do_gettimeofday); ++ ++int do_settimeofday(struct timespec *tv) ++{ ++ time_t sec; ++ s64 nsec; ++ unsigned int cpu; ++ struct shadow_time_info *shadow; ++ struct xen_platform_op op; ++ ++ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) ++ return -EINVAL; ++ ++ cpu = get_cpu(); ++ shadow = &per_cpu(shadow_time, cpu); ++ ++ write_seqlock_irq(&xtime_lock); ++ ++ /* ++ * Ensure we don't get blocked for a long time so that our time delta ++ * overflows. If that were to happen then our shadow time values would ++ * be stale, so we can retry with fresh ones. ++ */ ++ for (;;) { ++ nsec = tv->tv_nsec - get_nsec_offset(shadow); ++ if (time_values_up_to_date(cpu)) ++ break; ++ get_time_values_from_xen(cpu); ++ } ++ sec = tv->tv_sec; ++ __normalize_time(&sec, &nsec); ++ ++ if (is_initial_xendomain() && !independent_wallclock) { ++ op.cmd = XENPF_settime; ++ op.u.settime.secs = sec; ++ op.u.settime.nsecs = nsec; ++ op.u.settime.system_time = shadow->system_timestamp; ++ HYPERVISOR_platform_op(&op); ++ update_wallclock(); ++ } else if (independent_wallclock) { ++ nsec -= shadow->system_timestamp; ++ __normalize_time(&sec, &nsec); ++ __update_wallclock(sec, nsec); ++ } ++ ++ write_sequnlock_irq(&xtime_lock); ++ ++ put_cpu(); ++ ++ clock_was_set(); ++ return 0; ++} ++ ++EXPORT_SYMBOL(do_settimeofday); ++ ++static void sync_xen_wallclock(unsigned long dummy); ++static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0); ++static void sync_xen_wallclock(unsigned long dummy) ++{ ++ time_t sec; ++ s64 nsec; ++ struct xen_platform_op op; ++ ++ if (!ntp_synced() || independent_wallclock || !is_initial_xendomain()) ++ return; ++ ++ write_seqlock_irq(&xtime_lock); ++ ++ sec = xtime.tv_sec; ++ nsec = xtime.tv_nsec; ++ __normalize_time(&sec, &nsec); ++ ++ op.cmd = XENPF_settime; ++ op.u.settime.secs = sec; ++ op.u.settime.nsecs = nsec; ++ op.u.settime.system_time = processed_system_time; ++ HYPERVISOR_platform_op(&op); ++ ++ update_wallclock(); ++ ++ write_sequnlock_irq(&xtime_lock); ++ ++ /* Once per minute. */ ++ mod_timer(&sync_xen_wallclock_timer, jiffies + 60*HZ); ++} ++ ++static int set_rtc_mmss(unsigned long nowtime) ++{ ++ int retval; ++ unsigned long flags; ++ ++ if (independent_wallclock || !is_initial_xendomain()) ++ return 0; ++ ++ /* gets recalled with irq locally disabled */ ++ spin_lock_irqsave(&rtc_lock, flags); ++ if (efi_enabled) ++ retval = efi_set_rtc_mmss(nowtime); ++ else ++ retval = mach_set_rtc_mmss(nowtime); ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ return retval; ++} ++ ++/* monotonic_clock(): returns # of nanoseconds passed since time_init() ++ * Note: This function is required to return accurate ++ * time even in the absence of multiple timer ticks. ++ */ ++unsigned long long monotonic_clock(void) ++{ ++ int cpu = get_cpu(); ++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); ++ u64 time; ++ u32 local_time_version; ++ ++ do { ++ local_time_version = shadow->version; ++ barrier(); ++ time = shadow->system_timestamp + get_nsec_offset(shadow); ++ if (!time_values_up_to_date(cpu)) ++ get_time_values_from_xen(cpu); ++ barrier(); ++ } while (local_time_version != shadow->version); ++ ++ put_cpu(); ++ ++ return time; ++} ++EXPORT_SYMBOL(monotonic_clock); ++ ++unsigned long long sched_clock(void) ++{ ++ return monotonic_clock(); ++} ++ ++unsigned long profile_pc(struct pt_regs *regs) ++{ ++ unsigned long pc = instruction_pointer(regs); ++ ++ /* Assume the lock function has either no stack frame or a copy ++ of eflags from PUSHF ++ Eflags always has bits 22 and up cleared unlike kernel addresses. */ ++ if (!user_mode_vm(regs) && in_lock_functions(pc)) { ++ unsigned long *sp = (unsigned long *)regs->rsp; ++ if (sp[0] >> 22) ++ return sp[0]; ++ if (sp[1] >> 22) ++ return sp[1]; ++ } ++ return pc; ++} ++EXPORT_SYMBOL(profile_pc); ++ ++/* ++ * This is the same as the above, except we _also_ save the current ++ * Time Stamp Counter value at the time of the timer interrupt, so that ++ * we later on can estimate the time of day more exactly. ++ */ ++irqreturn_t timer_interrupt(int irq, void *dev_id) ++{ ++ s64 delta, delta_cpu, stolen, blocked; ++ u64 sched_time; ++ int i, cpu = smp_processor_id(); ++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ ++ /* ++ * Here we are in the timer irq handler. We just have irqs locally ++ * disabled but we don't know if the timer_bh is running on the other ++ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need ++ * the irq version of write_lock because as just said we have irq ++ * locally disabled. -arca ++ */ ++ write_seqlock(&xtime_lock); ++ ++ do { ++ get_time_values_from_xen(cpu); ++ ++ /* Obtain a consistent snapshot of elapsed wallclock cycles. */ ++ delta = delta_cpu = ++ shadow->system_timestamp + get_nsec_offset(shadow); ++ delta -= processed_system_time; ++ delta_cpu -= per_cpu(processed_system_time, cpu); ++ ++ /* ++ * Obtain a consistent snapshot of stolen/blocked cycles. We ++ * can use state_entry_time to detect if we get preempted here. ++ */ ++ do { ++ sched_time = runstate->state_entry_time; ++ barrier(); ++ stolen = runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline] - ++ per_cpu(processed_stolen_time, cpu); ++ blocked = runstate->time[RUNSTATE_blocked] - ++ per_cpu(processed_blocked_time, cpu); ++ barrier(); ++ } while (sched_time != runstate->state_entry_time); ++ } while (!time_values_up_to_date(cpu)); ++ ++ if ((unlikely(delta < -(s64)permitted_clock_jitter) || ++ unlikely(delta_cpu < -(s64)permitted_clock_jitter)) ++ && printk_ratelimit()) { ++ printk("Timer ISR/%d: Time went backwards: " ++ "delta=%lld delta_cpu=%lld shadow=%lld " ++ "off=%lld processed=%lld cpu_processed=%lld\n", ++ cpu, delta, delta_cpu, shadow->system_timestamp, ++ (s64)get_nsec_offset(shadow), ++ processed_system_time, ++ per_cpu(processed_system_time, cpu)); ++ for (i = 0; i < num_online_cpus(); i++) ++ printk(" %d: %lld\n", i, ++ per_cpu(processed_system_time, i)); ++ } ++ ++ /* System-wide jiffy work. */ ++ while (delta >= NS_PER_TICK) { ++ delta -= NS_PER_TICK; ++ processed_system_time += NS_PER_TICK; ++ do_timer(1); ++ } ++ ++ if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) { ++ update_wallclock(); ++ clock_was_set(); ++ } ++ ++ write_sequnlock(&xtime_lock); ++ ++ /* ++ * Account stolen ticks. ++ * HACK: Passing NULL to account_steal_time() ++ * ensures that the ticks are accounted as stolen. ++ */ ++ if ((stolen > 0) && (delta_cpu > 0)) { ++ delta_cpu -= stolen; ++ if (unlikely(delta_cpu < 0)) ++ stolen += delta_cpu; /* clamp local-time progress */ ++ do_div(stolen, NS_PER_TICK); ++ per_cpu(processed_stolen_time, cpu) += stolen * NS_PER_TICK; ++ per_cpu(processed_system_time, cpu) += stolen * NS_PER_TICK; ++ account_steal_time(NULL, (cputime_t)stolen); ++ } ++ ++ /* ++ * Account blocked ticks. ++ * HACK: Passing idle_task to account_steal_time() ++ * ensures that the ticks are accounted as idle/wait. ++ */ ++ if ((blocked > 0) && (delta_cpu > 0)) { ++ delta_cpu -= blocked; ++ if (unlikely(delta_cpu < 0)) ++ blocked += delta_cpu; /* clamp local-time progress */ ++ do_div(blocked, NS_PER_TICK); ++ per_cpu(processed_blocked_time, cpu) += blocked * NS_PER_TICK; ++ per_cpu(processed_system_time, cpu) += blocked * NS_PER_TICK; ++ account_steal_time(idle_task(cpu), (cputime_t)blocked); ++ } ++ ++ /* Account user/system ticks. */ ++ if (delta_cpu > 0) { ++ do_div(delta_cpu, NS_PER_TICK); ++ per_cpu(processed_system_time, cpu) += delta_cpu * NS_PER_TICK; ++ if (user_mode_vm(get_irq_regs())) ++ account_user_time(current, (cputime_t)delta_cpu); ++ else ++ account_system_time(current, HARDIRQ_OFFSET, ++ (cputime_t)delta_cpu); ++ } ++ ++ /* Local timer processing (see update_process_times()). */ ++ run_local_timers(); ++ if (rcu_pending(cpu)) ++ rcu_check_callbacks(cpu, user_mode_vm(get_irq_regs())); ++ scheduler_tick(); ++ run_posix_cpu_timers(current); ++// JQ: Why this works on 2.6.16 & 2.6.18 and generates a page ++// fault on 2.6.19 is a mistery to me. ++// profile_tick(CPU_PROFILING); ++ ++ return IRQ_HANDLED; ++} ++ ++static void init_missing_ticks_accounting(int cpu) ++{ ++ struct vcpu_register_runstate_memory_area area; ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ ++ memset(runstate, 0, sizeof(*runstate)); ++ ++ area.addr.v = runstate; ++ HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); ++ ++ per_cpu(processed_blocked_time, cpu) = ++ runstate->time[RUNSTATE_blocked]; ++ per_cpu(processed_stolen_time, cpu) = ++ runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline]; ++} ++ ++/* not static: needed by APM */ ++unsigned long get_cmos_time(void) ++{ ++ unsigned long retval; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rtc_lock, flags); ++ ++ if (efi_enabled) ++ retval = efi_get_time(); ++ else ++ retval = mach_get_cmos_time(); ++ ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ return retval; ++} ++EXPORT_SYMBOL(get_cmos_time); ++ ++static void sync_cmos_clock(unsigned long dummy); ++ ++static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); ++ ++static void sync_cmos_clock(unsigned long dummy) ++{ ++ struct timeval now, next; ++ int fail = 1; ++ ++ /* ++ * If we have an externally synchronized Linux clock, then update ++ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be ++ * called as close as possible to 500 ms before the new second starts. ++ * This code is run on a timer. If the clock is set, that timer ++ * may not expire at the correct time. Thus, we adjust... ++ */ ++ if (!ntp_synced()) ++ /* ++ * Not synced, exit, do not restart a timer (if one is ++ * running, let it run out). ++ */ ++ return; ++ ++ do_gettimeofday(&now); ++ if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && ++ now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) ++ fail = set_rtc_mmss(now.tv_sec); ++ ++ next.tv_usec = USEC_AFTER - now.tv_usec; ++ if (next.tv_usec <= 0) ++ next.tv_usec += USEC_PER_SEC; ++ ++ if (!fail) ++ next.tv_sec = 659; ++ else ++ next.tv_sec = 0; ++ ++ if (next.tv_usec >= USEC_PER_SEC) { ++ next.tv_sec++; ++ next.tv_usec -= USEC_PER_SEC; ++ } ++ mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next)); ++} ++ ++void notify_arch_cmos_timer(void) ++{ ++ mod_timer(&sync_cmos_timer, jiffies + 1); ++ mod_timer(&sync_xen_wallclock_timer, jiffies + 1); ++} ++ ++static long clock_cmos_diff; ++static unsigned long sleep_start; ++ ++static int timer_suspend(struct sys_device *dev, pm_message_t state) ++{ ++ /* ++ * Estimate time zone so that set_time can update the clock ++ */ ++ unsigned long ctime = get_cmos_time(); ++ ++ clock_cmos_diff = -ctime; ++ clock_cmos_diff += get_seconds(); ++ sleep_start = ctime; ++ return 0; ++} ++ ++static int timer_resume(struct sys_device *dev) ++{ ++ unsigned long flags; ++ unsigned long sec; ++ unsigned long ctime = get_cmos_time(); ++ long sleep_length = (ctime - sleep_start) * HZ; ++ ++ if (sleep_length < 0) { ++ printk(KERN_WARNING "CMOS clock skew detected in timer resume!\n"); ++ /* The time after the resume must not be earlier than the time ++ * before the suspend or some nasty things will happen ++ */ ++ sleep_length = 0; ++ ctime = sleep_start; ++ } ++ ++#ifdef CONFIG_HPET_TIMER ++ if (is_hpet_enabled()) ++ hpet_reenable(); ++#endif ++ sec = ctime + clock_cmos_diff; ++ write_seqlock_irqsave(&xtime_lock, flags); ++ xtime.tv_sec = sec; ++ xtime.tv_nsec = 0; ++ jiffies_64 += sleep_length; ++ write_sequnlock_irqrestore(&xtime_lock, flags); ++ touch_softlockup_watchdog(); ++ return 0; ++} ++ ++static struct sysdev_class timer_sysclass = { ++ .resume = timer_resume, ++ .suspend = timer_suspend, ++ set_kset_name("timer"), ++}; ++ ++ ++/* XXX this driverfs stuff should probably go elsewhere later -john */ ++static struct sys_device device_timer = { ++ .id = 0, ++ .cls = &timer_sysclass, ++}; ++ ++static int time_init_device(void) ++{ ++ int error = sysdev_class_register(&timer_sysclass); ++ if (!error) ++ error = sysdev_register(&device_timer); ++ return error; ++} ++ ++device_initcall(time_init_device); ++ ++#ifdef CONFIG_HPET_TIMER ++extern void (*late_time_init)(void); ++/* Duplicate of time_init() below, with hpet_enable part added */ ++static void __init hpet_time_init(void) ++{ ++ xtime.tv_sec = get_cmos_time(); ++ xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); ++ set_normalized_timespec(&wall_to_monotonic, ++ -xtime.tv_sec, -xtime.tv_nsec); ++ ++ if ((hpet_enable() >= 0) && hpet_use_timer) { ++ printk("Using HPET for base-timer\n"); ++ } ++ ++ time_init_hook(); ++} ++#endif ++ ++/* Dynamically-mapped IRQ. */ ++DEFINE_PER_CPU(int, timer_irq); ++ ++extern void (*late_time_init)(void); ++static void setup_cpu0_timer_irq(void) ++{ ++ per_cpu(timer_irq, 0) = ++ bind_virq_to_irqhandler( ++ VIRQ_TIMER, ++ 0, ++ timer_interrupt, ++ SA_INTERRUPT, ++ "timer0", ++ NULL); ++ BUG_ON(per_cpu(timer_irq, 0) < 0); ++} ++ ++static struct vcpu_set_periodic_timer xen_set_periodic_tick = { ++ .period_ns = NS_PER_TICK ++}; ++ ++void __init time_init(void) ++{ ++#ifdef CONFIG_HPET_TIMER ++ if (is_hpet_capable()) { ++ /* ++ * HPET initialization needs to do memory-mapped io. So, let ++ * us do a late initialization after mem_init(). ++ */ ++ late_time_init = hpet_time_init; ++ return; ++ } ++#endif ++ ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0, ++ &xen_set_periodic_tick); ++ ++ get_time_values_from_xen(0); ++ ++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp; ++ per_cpu(processed_system_time, 0) = processed_system_time; ++ init_missing_ticks_accounting(0); ++ ++ update_wallclock(); ++ ++ init_cpu_khz(); ++ printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", ++ cpu_khz / 1000, cpu_khz % 1000); ++ ++ /* Cannot request_irq() until kmem is initialised. */ ++ late_time_init = setup_cpu0_timer_irq; ++} ++ ++/* Convert jiffies to system time. */ ++u64 jiffies_to_st(unsigned long j) ++{ ++ unsigned long seq; ++ long delta; ++ u64 st; ++ ++ do { ++ seq = read_seqbegin(&xtime_lock); ++ delta = j - jiffies; ++ if (delta < 1) { ++ /* Triggers in some wrap-around cases, but that's okay: ++ * we just end up with a shorter timeout. */ ++ st = processed_system_time + NS_PER_TICK; ++ } else if (((unsigned long)delta >> (BITS_PER_LONG-3)) != 0) { ++ /* Very long timeout means there is no pending timer. ++ * We indicate this to Xen by passing zero timeout. */ ++ st = 0; ++ } else { ++ st = processed_system_time + delta * (u64)NS_PER_TICK; ++ } ++ } while (read_seqretry(&xtime_lock, seq)); ++ ++ return st; ++} ++EXPORT_SYMBOL(jiffies_to_st); ++ ++/* ++ * stop_hz_timer / start_hz_timer - enter/exit 'tickless mode' on an idle cpu ++ * These functions are based on implementations from arch/s390/kernel/time.c ++ */ ++static void stop_hz_timer(void) ++{ ++ struct vcpu_set_singleshot_timer singleshot; ++ unsigned int cpu = smp_processor_id(); ++ unsigned long j; ++ int rc; ++ ++ cpu_set(cpu, nohz_cpu_mask); ++ ++ /* See matching smp_mb in rcu_start_batch in rcupdate.c. These mbs */ ++ /* ensure that if __rcu_pending (nested in rcu_needs_cpu) fetches a */ ++ /* value of rcp->cur that matches rdp->quiescbatch and allows us to */ ++ /* stop the hz timer then the cpumasks created for subsequent values */ ++ /* of cur in rcu_start_batch are guaranteed to pick up the updated */ ++ /* nohz_cpu_mask and so will not depend on this cpu. */ ++ ++ smp_mb(); ++ ++ /* Leave ourselves in tick mode if rcu or softirq or timer pending. */ ++ if (rcu_needs_cpu(cpu) || local_softirq_pending() || ++ (j = next_timer_interrupt(), time_before_eq(j, jiffies))) { ++ cpu_clear(cpu, nohz_cpu_mask); ++ j = jiffies + 1; ++ } ++ ++ singleshot.timeout_abs_ns = jiffies_to_st(j); ++ singleshot.flags = 0; ++ rc = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &singleshot); ++#if CONFIG_XEN_COMPAT <= 0x030004 ++ if (rc) { ++ BUG_ON(rc != -ENOSYS); ++ rc = HYPERVISOR_set_timer_op(singleshot.timeout_abs_ns); ++ } ++#endif ++ BUG_ON(rc); ++} ++ ++static void start_hz_timer(void) ++{ ++ cpu_clear(smp_processor_id(), nohz_cpu_mask); ++} ++ ++void raw_safe_halt(void) ++{ ++ stop_hz_timer(); ++ /* Blocking includes an implicit local_irq_enable(). */ ++ HYPERVISOR_block(); ++ start_hz_timer(); ++} ++EXPORT_SYMBOL(raw_safe_halt); ++ ++void halt(void) ++{ ++ if (irqs_disabled()) ++ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); ++} ++EXPORT_SYMBOL(halt); ++ ++/* No locking required. Interrupts are disabled on all CPUs. */ ++void time_resume(void) ++{ ++ unsigned int cpu; ++ ++ init_cpu_khz(); ++ ++ for_each_online_cpu(cpu) { ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, ++ &xen_set_periodic_tick); ++ get_time_values_from_xen(cpu); ++ per_cpu(processed_system_time, cpu) = ++ per_cpu(shadow_time, 0).system_timestamp; ++ init_missing_ticks_accounting(cpu); ++ } ++ ++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp; ++ ++ update_wallclock(); ++} ++ ++#ifdef CONFIG_SMP ++static char timer_name[NR_CPUS][15]; ++ ++int local_setup_timer(unsigned int cpu) ++{ ++ int seq, irq; ++ ++ BUG_ON(cpu == 0); ++ ++ HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, ++ &xen_set_periodic_tick); ++ ++ do { ++ seq = read_seqbegin(&xtime_lock); ++ /* Use cpu0 timestamp: cpu's shadow is not initialised yet. */ ++ per_cpu(processed_system_time, cpu) = ++ per_cpu(shadow_time, 0).system_timestamp; ++ init_missing_ticks_accounting(cpu); ++ } while (read_seqretry(&xtime_lock, seq)); ++ ++ sprintf(timer_name[cpu], "timer%d", cpu); ++ irq = bind_virq_to_irqhandler(VIRQ_TIMER, ++ cpu, ++ timer_interrupt, ++ SA_INTERRUPT, ++ timer_name[cpu], ++ NULL); ++ if (irq < 0) ++ return irq; ++ per_cpu(timer_irq, cpu) = irq; ++ ++ return 0; ++} ++ ++void local_teardown_timer(unsigned int cpu) ++{ ++ BUG_ON(cpu == 0); ++ unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL); ++} ++#endif ++ ++/* ++ * /proc/sys/xen: This really belongs in another file. It can stay here for ++ * now however. ++ */ ++static ctl_table xen_subtable[] = { ++ { ++ .ctl_name = 1, ++ .procname = "independent_wallclock", ++ .data = &independent_wallclock, ++ .maxlen = sizeof(independent_wallclock), ++ .mode = 0644, ++ .proc_handler = proc_dointvec ++ }, ++ { ++ .ctl_name = 2, ++ .procname = "permitted_clock_jitter", ++ .data = &permitted_clock_jitter, ++ .maxlen = sizeof(permitted_clock_jitter), ++ .mode = 0644, ++ .proc_handler = proc_doulongvec_minmax ++ }, ++ { 0 } ++}; ++static ctl_table xen_table[] = { ++ { ++ .ctl_name = 123, ++ .procname = "xen", ++ .mode = 0555, ++ .child = xen_subtable}, ++ { 0 } ++}; ++static int __init xen_sysctl_init(void) ++{ ++ (void)register_sysctl_table(xen_table, 0); ++ return 0; ++} ++__initcall(xen_sysctl_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/traps-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/traps-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1156 @@ ++/* ++ * linux/arch/x86-64/traps.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs ++ * ++ * Pentium III FXSR, SSE support ++ * Gareth Hughes <gareth@valinux.com>, May 2000 ++ */ ++ ++/* ++ * 'Traps.c' handles hardware traps and faults after we have saved some ++ * state in 'entry.S'. ++ */ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/kallsyms.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/nmi.h> ++#include <linux/kprobes.h> ++#include <linux/kexec.h> ++#include <linux/unwind.h> ++#include <linux/uaccess.h> ++#include <linux/bug.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/atomic.h> ++#include <asm/debugreg.h> ++#include <asm/desc.h> ++#include <asm/i387.h> ++#include <asm/kdebug.h> ++#include <asm/processor.h> ++#include <asm/unwind.h> ++#include <asm/smp.h> ++#include <asm/pgalloc.h> ++#include <asm/pda.h> ++#include <asm/proto.h> ++#include <asm/nmi.h> ++#include <asm/stacktrace.h> ++ ++asmlinkage void divide_error(void); ++asmlinkage void debug(void); ++asmlinkage void nmi(void); ++asmlinkage void int3(void); ++asmlinkage void overflow(void); ++asmlinkage void bounds(void); ++asmlinkage void invalid_op(void); ++asmlinkage void device_not_available(void); ++asmlinkage void double_fault(void); ++asmlinkage void coprocessor_segment_overrun(void); ++asmlinkage void invalid_TSS(void); ++asmlinkage void segment_not_present(void); ++asmlinkage void stack_segment(void); ++asmlinkage void general_protection(void); ++asmlinkage void page_fault(void); ++asmlinkage void coprocessor_error(void); ++asmlinkage void simd_coprocessor_error(void); ++asmlinkage void reserved(void); ++asmlinkage void alignment_check(void); ++asmlinkage void machine_check(void); ++asmlinkage void spurious_interrupt_bug(void); ++ ++ATOMIC_NOTIFIER_HEAD(die_chain); ++EXPORT_SYMBOL(die_chain); ++ ++int register_die_notifier(struct notifier_block *nb) ++{ ++ vmalloc_sync_all(); ++ return atomic_notifier_chain_register(&die_chain, nb); ++} ++EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ ++ ++int unregister_die_notifier(struct notifier_block *nb) ++{ ++ return atomic_notifier_chain_unregister(&die_chain, nb); ++} ++EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ ++ ++static inline void conditional_sti(struct pt_regs *regs) ++{ ++ if (regs->eflags & X86_EFLAGS_IF) ++ local_irq_enable(); ++} ++ ++static inline void preempt_conditional_sti(struct pt_regs *regs) ++{ ++ preempt_disable(); ++ if (regs->eflags & X86_EFLAGS_IF) ++ local_irq_enable(); ++} ++ ++static inline void preempt_conditional_cli(struct pt_regs *regs) ++{ ++ if (regs->eflags & X86_EFLAGS_IF) ++ local_irq_disable(); ++ /* Make sure to not schedule here because we could be running ++ on an exception stack. */ ++ preempt_enable_no_resched(); ++} ++ ++int kstack_depth_to_print = 12; ++ ++#ifdef CONFIG_KALLSYMS ++void printk_address(unsigned long address) ++{ ++ unsigned long offset = 0, symsize; ++ const char *symname; ++ char *modname; ++ char *delim = ":"; ++ char namebuf[128]; ++ ++ symname = kallsyms_lookup(address, &symsize, &offset, ++ &modname, namebuf); ++ if (!symname) { ++ printk(" [<%016lx>]\n", address); ++ return; ++ } ++ if (!modname) ++ modname = delim = ""; ++ printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n", ++ address, delim, modname, delim, symname, offset, symsize); ++} ++#else ++void printk_address(unsigned long address) ++{ ++ printk(" [<%016lx>]\n", address); ++} ++#endif ++ ++static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, ++ unsigned *usedp, char **idp) ++{ ++#ifndef CONFIG_X86_NO_TSS ++ static char ids[][8] = { ++ [DEBUG_STACK - 1] = "#DB", ++ [NMI_STACK - 1] = "NMI", ++ [DOUBLEFAULT_STACK - 1] = "#DF", ++ [STACKFAULT_STACK - 1] = "#SS", ++ [MCE_STACK - 1] = "#MC", ++#if DEBUG_STKSZ > EXCEPTION_STKSZ ++ [N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" ++#endif ++ }; ++ unsigned k; ++ ++ /* ++ * Iterate over all exception stacks, and figure out whether ++ * 'stack' is in one of them: ++ */ ++ for (k = 0; k < N_EXCEPTION_STACKS; k++) { ++ unsigned long end = per_cpu(orig_ist, cpu).ist[k]; ++ /* ++ * Is 'stack' above this exception frame's end? ++ * If yes then skip to the next frame. ++ */ ++ if (stack >= end) ++ continue; ++ /* ++ * Is 'stack' above this exception frame's start address? ++ * If yes then we found the right frame. ++ */ ++ if (stack >= end - EXCEPTION_STKSZ) { ++ /* ++ * Make sure we only iterate through an exception ++ * stack once. If it comes up for the second time ++ * then there's something wrong going on - just ++ * break out and return NULL: ++ */ ++ if (*usedp & (1U << k)) ++ break; ++ *usedp |= 1U << k; ++ *idp = ids[k]; ++ return (unsigned long *)end; ++ } ++ /* ++ * If this is a debug stack, and if it has a larger size than ++ * the usual exception stacks, then 'stack' might still ++ * be within the lower portion of the debug stack: ++ */ ++#if DEBUG_STKSZ > EXCEPTION_STKSZ ++ if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { ++ unsigned j = N_EXCEPTION_STACKS - 1; ++ ++ /* ++ * Black magic. A large debug stack is composed of ++ * multiple exception stack entries, which we ++ * iterate through now. Dont look: ++ */ ++ do { ++ ++j; ++ end -= EXCEPTION_STKSZ; ++ ids[j][4] = '1' + (j - N_EXCEPTION_STACKS); ++ } while (stack < end - EXCEPTION_STKSZ); ++ if (*usedp & (1U << j)) ++ break; ++ *usedp |= 1U << j; ++ *idp = ids[j]; ++ return (unsigned long *)end; ++ } ++#endif ++ } ++#endif ++ return NULL; ++} ++ ++#define MSG(txt) ops->warning(data, txt) ++ ++/* ++ * x86-64 can have upto three kernel stacks: ++ * process stack ++ * interrupt stack ++ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack ++ */ ++ ++static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) ++{ ++ void *t = (void *)tinfo; ++ return p > t && p < t + THREAD_SIZE - 3; ++} ++ ++void dump_trace(struct task_struct *tsk, struct pt_regs *regs, ++ unsigned long *stack, ++ struct stacktrace_ops *ops, void *data) ++{ ++ const unsigned cpu = get_cpu(); ++ unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr; ++ unsigned used = 0; ++ struct thread_info *tinfo; ++ ++ if (!tsk) ++ tsk = current; ++ ++ if (!stack) { ++ unsigned long dummy; ++ stack = &dummy; ++ if (tsk && tsk != current) ++ stack = (unsigned long *)tsk->thread.rsp; ++ } ++ ++ /* ++ * Print function call entries within a stack. 'cond' is the ++ * "end of stackframe" condition, that the 'stack++' ++ * iteration will eventually trigger. ++ */ ++#define HANDLE_STACK(cond) \ ++ do while (cond) { \ ++ unsigned long addr = *stack++; \ ++ /* Use unlocked access here because except for NMIs \ ++ we should be already protected against module unloads */ \ ++ if (__kernel_text_address(addr)) { \ ++ /* \ ++ * If the address is either in the text segment of the \ ++ * kernel, or in the region which contains vmalloc'ed \ ++ * memory, it *may* be the address of a calling \ ++ * routine; if so, print it so that someone tracing \ ++ * down the cause of the crash will be able to figure \ ++ * out the call path that was taken. \ ++ */ \ ++ ops->address(data, addr); \ ++ } \ ++ } while (0) ++ ++ /* ++ * Print function call entries in all stacks, starting at the ++ * current stack address. If the stacks consist of nested ++ * exceptions ++ */ ++ for (;;) { ++ char *id; ++ unsigned long *estack_end; ++ estack_end = in_exception_stack(cpu, (unsigned long)stack, ++ &used, &id); ++ ++ if (estack_end) { ++ if (ops->stack(data, id) < 0) ++ break; ++ HANDLE_STACK (stack < estack_end); ++ ops->stack(data, "<EOE>"); ++ /* ++ * We link to the next stack via the ++ * second-to-last pointer (index -2 to end) in the ++ * exception stack: ++ */ ++ stack = (unsigned long *) estack_end[-2]; ++ continue; ++ } ++ if (irqstack_end) { ++ unsigned long *irqstack; ++ irqstack = irqstack_end - ++ (IRQSTACKSIZE - 64) / sizeof(*irqstack); ++ ++ if (stack >= irqstack && stack < irqstack_end) { ++ if (ops->stack(data, "IRQ") < 0) ++ break; ++ HANDLE_STACK (stack < irqstack_end); ++ /* ++ * We link to the next stack (which would be ++ * the process stack normally) the last ++ * pointer (index -1 to end) in the IRQ stack: ++ */ ++ stack = (unsigned long *) (irqstack_end[-1]); ++ irqstack_end = NULL; ++ ops->stack(data, "EOI"); ++ continue; ++ } ++ } ++ break; ++ } ++ ++ /* ++ * This handles the process stack: ++ */ ++ tinfo = task_thread_info(tsk); ++ HANDLE_STACK (valid_stack_ptr(tinfo, stack)); ++#undef HANDLE_STACK ++ put_cpu(); ++} ++EXPORT_SYMBOL(dump_trace); ++ ++static void ++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) ++{ ++ print_symbol(msg, symbol); ++ printk("\n"); ++} ++ ++static void print_trace_warning(void *data, char *msg) ++{ ++ printk("%s\n", msg); ++} ++ ++static int print_trace_stack(void *data, char *name) ++{ ++ printk(" <%s> ", name); ++ return 0; ++} ++ ++static void print_trace_address(void *data, unsigned long addr) ++{ ++ printk_address(addr); ++} ++ ++static struct stacktrace_ops print_trace_ops = { ++ .warning = print_trace_warning, ++ .warning_symbol = print_trace_warning_symbol, ++ .stack = print_trace_stack, ++ .address = print_trace_address, ++}; ++ ++void ++show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) ++{ ++ printk("\nCall Trace:\n"); ++ dump_trace(tsk, regs, stack, &print_trace_ops, NULL); ++ printk("\n"); ++} ++ ++static void ++_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp) ++{ ++ unsigned long *stack; ++ int i; ++ const int cpu = smp_processor_id(); ++ unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); ++ unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); ++ ++ // debugging aid: "show_stack(NULL, NULL);" prints the ++ // back trace for this cpu. ++ ++ if (rsp == NULL) { ++ if (tsk) ++ rsp = (unsigned long *)tsk->thread.rsp; ++ else ++ rsp = (unsigned long *)&rsp; ++ } ++ ++ stack = rsp; ++ for(i=0; i < kstack_depth_to_print; i++) { ++ if (stack >= irqstack && stack <= irqstack_end) { ++ if (stack == irqstack_end) { ++ stack = (unsigned long *) (irqstack_end[-1]); ++ printk(" <EOI> "); ++ } ++ } else { ++ if (((long) stack & (THREAD_SIZE-1)) == 0) ++ break; ++ } ++ if (i && ((i % 4) == 0)) ++ printk("\n"); ++ printk(" %016lx", *stack++); ++ touch_nmi_watchdog(); ++ } ++ show_trace(tsk, regs, rsp); ++} ++ ++void show_stack(struct task_struct *tsk, unsigned long * rsp) ++{ ++ _show_stack(tsk, NULL, rsp); ++} ++ ++/* ++ * The architecture-independent dump_stack generator ++ */ ++void dump_stack(void) ++{ ++ unsigned long dummy; ++ show_trace(NULL, NULL, &dummy); ++} ++ ++EXPORT_SYMBOL(dump_stack); ++ ++void show_registers(struct pt_regs *regs) ++{ ++ int i; ++ int in_kernel = !user_mode(regs); ++ unsigned long rsp; ++ const int cpu = smp_processor_id(); ++ struct task_struct *cur = cpu_pda(cpu)->pcurrent; ++ ++ rsp = regs->rsp; ++ ++ printk("CPU %d ", cpu); ++ __show_regs(regs); ++ printk("Process %s (pid: %d, threadinfo %p, task %p)\n", ++ cur->comm, cur->pid, task_thread_info(cur), cur); ++ ++ /* ++ * When in-kernel, we also print out the stack and code at the ++ * time of the fault.. ++ */ ++ if (in_kernel) { ++ ++ printk("Stack: "); ++ _show_stack(NULL, regs, (unsigned long*)rsp); ++ ++ printk("\nCode: "); ++ if (regs->rip < PAGE_OFFSET) ++ goto bad; ++ ++ for (i=0; i<20; i++) { ++ unsigned char c; ++ if (__get_user(c, &((unsigned char*)regs->rip)[i])) { ++bad: ++ printk(" Bad RIP value."); ++ break; ++ } ++ printk("%02x ", c); ++ } ++ } ++ printk("\n"); ++} ++ ++int is_valid_bugaddr(unsigned long rip) ++{ ++ unsigned short ud2; ++ ++ if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2))) ++ return 0; ++ ++ return ud2 == 0x0b0f; ++} ++ ++#ifdef CONFIG_BUG ++void out_of_line_bug(void) ++{ ++ BUG(); ++} ++EXPORT_SYMBOL(out_of_line_bug); ++#endif ++ ++static DEFINE_SPINLOCK(die_lock); ++static int die_owner = -1; ++static unsigned int die_nest_count; ++ ++unsigned __kprobes long oops_begin(void) ++{ ++ int cpu = smp_processor_id(); ++ unsigned long flags; ++ ++ oops_enter(); ++ ++ /* racy, but better than risking deadlock. */ ++ local_irq_save(flags); ++ if (!spin_trylock(&die_lock)) { ++ if (cpu == die_owner) ++ /* nested oops. should stop eventually */; ++ else ++ spin_lock(&die_lock); ++ } ++ die_nest_count++; ++ die_owner = cpu; ++ console_verbose(); ++ bust_spinlocks(1); ++ return flags; ++} ++ ++void __kprobes oops_end(unsigned long flags) ++{ ++ die_owner = -1; ++ bust_spinlocks(0); ++ die_nest_count--; ++ if (die_nest_count) ++ /* We still own the lock */ ++ local_irq_restore(flags); ++ else ++ /* Nest count reaches zero, release the lock. */ ++ spin_unlock_irqrestore(&die_lock, flags); ++ if (panic_on_oops) ++ panic("Fatal exception"); ++ oops_exit(); ++} ++ ++void __kprobes __die(const char * str, struct pt_regs * regs, long err) ++{ ++ static int die_counter; ++ printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter); ++#ifdef CONFIG_PREEMPT ++ printk("PREEMPT "); ++#endif ++#ifdef CONFIG_SMP ++ printk("SMP "); ++#endif ++#ifdef CONFIG_DEBUG_PAGEALLOC ++ printk("DEBUG_PAGEALLOC"); ++#endif ++ printk("\n"); ++ notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); ++ show_registers(regs); ++ /* Executive summary in case the oops scrolled away */ ++ printk(KERN_ALERT "RIP "); ++ printk_address(regs->rip); ++ printk(" RSP <%016lx>\n", regs->rsp); ++ if (kexec_should_crash(current)) ++ crash_kexec(regs); ++} ++ ++void die(const char * str, struct pt_regs * regs, long err) ++{ ++ unsigned long flags = oops_begin(); ++ ++ if (!user_mode(regs)) ++ report_bug(regs->rip); ++ ++ __die(str, regs, err); ++ oops_end(flags); ++ do_exit(SIGSEGV); ++} ++ ++void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) ++{ ++ unsigned long flags = oops_begin(); ++ ++ /* ++ * We are in trouble anyway, lets at least try ++ * to get a message out. ++ */ ++ printk(str, smp_processor_id()); ++ show_registers(regs); ++ if (kexec_should_crash(current)) ++ crash_kexec(regs); ++ if (do_panic || panic_on_oops) ++ panic("Non maskable interrupt"); ++ oops_end(flags); ++ nmi_exit(); ++ local_irq_enable(); ++ do_exit(SIGSEGV); ++} ++ ++static void __kprobes do_trap(int trapnr, int signr, char *str, ++ struct pt_regs * regs, long error_code, ++ siginfo_t *info) ++{ ++ struct task_struct *tsk = current; ++ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; ++ ++ if (user_mode(regs)) { ++ if (exception_trace && unhandled_signal(tsk, signr)) ++ printk(KERN_INFO ++ "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", ++ tsk->comm, tsk->pid, str, ++ regs->rip, regs->rsp, error_code); ++ ++ if (info) ++ force_sig_info(signr, info, tsk); ++ else ++ force_sig(signr, tsk); ++ return; ++ } ++ ++ ++ /* kernel trap */ ++ { ++ const struct exception_table_entry *fixup; ++ fixup = search_exception_tables(regs->rip); ++ if (fixup) ++ regs->rip = fixup->fixup; ++ else ++ die(str, regs, error_code); ++ return; ++ } ++} ++ ++#define DO_ERROR(trapnr, signr, str, name) \ ++asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ conditional_sti(regs); \ ++ do_trap(trapnr, signr, str, regs, error_code, NULL); \ ++} ++ ++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ ++asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ ++{ \ ++ siginfo_t info; \ ++ info.si_signo = signr; \ ++ info.si_errno = 0; \ ++ info.si_code = sicode; \ ++ info.si_addr = (void __user *)siaddr; \ ++ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ ++ == NOTIFY_STOP) \ ++ return; \ ++ conditional_sti(regs); \ ++ do_trap(trapnr, signr, str, regs, error_code, &info); \ ++} ++ ++DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->rip) ++DO_ERROR( 4, SIGSEGV, "overflow", overflow) ++DO_ERROR( 5, SIGSEGV, "bounds", bounds) ++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->rip) ++DO_ERROR( 7, SIGSEGV, "device not available", device_not_available) ++DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) ++DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) ++DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) ++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) ++DO_ERROR(18, SIGSEGV, "reserved", reserved) ++ ++/* Runs on IST stack */ ++asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code) ++{ ++ if (notify_die(DIE_TRAP, "stack segment", regs, error_code, ++ 12, SIGBUS) == NOTIFY_STOP) ++ return; ++ preempt_conditional_sti(regs); ++ do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); ++ preempt_conditional_cli(regs); ++} ++ ++asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) ++{ ++ static const char str[] = "double fault"; ++ struct task_struct *tsk = current; ++ ++ /* Return not checked because double check cannot be ignored */ ++ notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV); ++ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 8; ++ ++ /* This is always a kernel trap and never fixable (and thus must ++ never return). */ ++ for (;;) ++ die(str, regs, error_code); ++} ++ ++asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, ++ long error_code) ++{ ++ struct task_struct *tsk = current; ++ ++ conditional_sti(regs); ++ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 13; ++ ++ if (user_mode(regs)) { ++ if (exception_trace && unhandled_signal(tsk, SIGSEGV)) ++ printk(KERN_INFO ++ "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", ++ tsk->comm, tsk->pid, ++ regs->rip, regs->rsp, error_code); ++ ++ force_sig(SIGSEGV, tsk); ++ return; ++ } ++ ++ /* kernel gp */ ++ { ++ const struct exception_table_entry *fixup; ++ fixup = search_exception_tables(regs->rip); ++ if (fixup) { ++ regs->rip = fixup->fixup; ++ return; ++ } ++ if (notify_die(DIE_GPF, "general protection fault", regs, ++ error_code, 13, SIGSEGV) == NOTIFY_STOP) ++ return; ++ die("general protection fault", regs, error_code); ++ } ++} ++ ++static __kprobes void ++mem_parity_error(unsigned char reason, struct pt_regs * regs) ++{ ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", ++ reason); ++ printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); ++ ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); ++ ++#if 0 /* XEN */ ++ /* Clear and disable the memory parity error line. */ ++ reason = (reason & 0xf) | 4; ++ outb(reason, 0x61); ++#endif /* XEN */ ++} ++ ++static __kprobes void ++io_check_error(unsigned char reason, struct pt_regs * regs) ++{ ++ printk("NMI: IOCK error (debug interrupt?)\n"); ++ show_registers(regs); ++ ++#if 0 /* XEN */ ++ /* Re-enable the IOCK line, wait for a few seconds */ ++ reason = (reason & 0xf) | 8; ++ outb(reason, 0x61); ++ mdelay(2000); ++ reason &= ~8; ++ outb(reason, 0x61); ++#endif /* XEN */ ++} ++ ++static __kprobes void ++unknown_nmi_error(unsigned char reason, struct pt_regs * regs) ++{ ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", ++ reason); ++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); ++ ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); ++} ++ ++/* Runs on IST stack. This code must keep interrupts off all the time. ++ Nested NMIs are prevented by the CPU. */ ++asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) ++{ ++ unsigned char reason = 0; ++ int cpu; ++ ++ cpu = smp_processor_id(); ++ ++ /* Only the BSP gets external NMIs from the system. */ ++ if (!cpu) ++ reason = get_nmi_reason(); ++ ++ if (!(reason & 0xc0)) { ++ if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) ++ == NOTIFY_STOP) ++ return; ++ /* ++ * Ok, so this is none of the documented NMI sources, ++ * so it must be the NMI watchdog. ++ */ ++ if (nmi_watchdog_tick(regs,reason)) ++ return; ++ if (!do_nmi_callback(regs,cpu)) ++ unknown_nmi_error(reason, regs); ++ ++ return; ++ } ++ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) ++ return; ++ ++ /* AK: following checks seem to be broken on modern chipsets. FIXME */ ++ ++ if (reason & 0x80) ++ mem_parity_error(reason, regs); ++ if (reason & 0x40) ++ io_check_error(reason, regs); ++} ++ ++/* runs on IST stack. */ ++asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) ++{ ++ if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { ++ return; ++ } ++ preempt_conditional_sti(regs); ++ do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); ++ preempt_conditional_cli(regs); ++} ++ ++/* Help handler running on IST stack to switch back to user stack ++ for scheduling or signal handling. The actual stack switch is done in ++ entry.S */ ++asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) ++{ ++ struct pt_regs *regs = eregs; ++ /* Did already sync */ ++ if (eregs == (struct pt_regs *)eregs->rsp) ++ ; ++ /* Exception from user space */ ++ else if (user_mode(eregs)) ++ regs = task_pt_regs(current); ++ /* Exception from kernel and interrupts are enabled. Move to ++ kernel process stack. */ ++ else if (eregs->eflags & X86_EFLAGS_IF) ++ regs = (struct pt_regs *)(eregs->rsp -= sizeof(struct pt_regs)); ++ if (eregs != regs) ++ *regs = *eregs; ++ return regs; ++} ++ ++/* runs on IST stack. */ ++asmlinkage void __kprobes do_debug(struct pt_regs * regs, ++ unsigned long error_code) ++{ ++ unsigned long condition; ++ struct task_struct *tsk = current; ++ siginfo_t info; ++ ++ get_debugreg(condition, 6); ++ ++ if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, ++ SIGTRAP) == NOTIFY_STOP) ++ return; ++ ++ preempt_conditional_sti(regs); ++ ++ /* Mask out spurious debug traps due to lazy DR7 setting */ ++ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { ++ if (!tsk->thread.debugreg7) { ++ goto clear_dr7; ++ } ++ } ++ ++ tsk->thread.debugreg6 = condition; ++ ++ /* Mask out spurious TF errors due to lazy TF clearing */ ++ if (condition & DR_STEP) { ++ /* ++ * The TF error should be masked out only if the current ++ * process is not traced and if the TRAP flag has been set ++ * previously by a tracing process (condition detected by ++ * the PT_DTRACE flag); remember that the i386 TRAP flag ++ * can be modified by the process itself in user mode, ++ * allowing programs to debug themselves without the ptrace() ++ * interface. ++ */ ++ if (!user_mode(regs)) ++ goto clear_TF_reenable; ++ /* ++ * Was the TF flag set by a debugger? If so, clear it now, ++ * so that register information is correct. ++ */ ++ if (tsk->ptrace & PT_DTRACE) { ++ regs->eflags &= ~TF_MASK; ++ tsk->ptrace &= ~PT_DTRACE; ++ } ++ } ++ ++ /* Ok, finally something we can handle */ ++ tsk->thread.trap_no = 1; ++ tsk->thread.error_code = error_code; ++ info.si_signo = SIGTRAP; ++ info.si_errno = 0; ++ info.si_code = TRAP_BRKPT; ++ info.si_addr = user_mode(regs) ? (void __user *)regs->rip : NULL; ++ force_sig_info(SIGTRAP, &info, tsk); ++ ++clear_dr7: ++ set_debugreg(0UL, 7); ++ preempt_conditional_cli(regs); ++ return; ++ ++clear_TF_reenable: ++ set_tsk_thread_flag(tsk, TIF_SINGLESTEP); ++ regs->eflags &= ~TF_MASK; ++ preempt_conditional_cli(regs); ++} ++ ++static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) ++{ ++ const struct exception_table_entry *fixup; ++ fixup = search_exception_tables(regs->rip); ++ if (fixup) { ++ regs->rip = fixup->fixup; ++ return 1; ++ } ++ notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); ++ /* Illegal floating point operation in the kernel */ ++ current->thread.trap_no = trapnr; ++ die(str, regs, 0); ++ return 0; ++} ++ ++/* ++ * Note that we play around with the 'TS' bit in an attempt to get ++ * the correct behaviour even in the presence of the asynchronous ++ * IRQ13 behaviour ++ */ ++asmlinkage void do_coprocessor_error(struct pt_regs *regs) ++{ ++ void __user *rip = (void __user *)(regs->rip); ++ struct task_struct * task; ++ siginfo_t info; ++ unsigned short cwd, swd; ++ ++ conditional_sti(regs); ++ if (!user_mode(regs) && ++ kernel_math_error(regs, "kernel x87 math error", 16)) ++ return; ++ ++ /* ++ * Save the info for the exception handler and clear the error. ++ */ ++ task = current; ++ save_init_fpu(task); ++ task->thread.trap_no = 16; ++ task->thread.error_code = 0; ++ info.si_signo = SIGFPE; ++ info.si_errno = 0; ++ info.si_code = __SI_FAULT; ++ info.si_addr = rip; ++ /* ++ * (~cwd & swd) will mask out exceptions that are not set to unmasked ++ * status. 0x3f is the exception bits in these regs, 0x200 is the ++ * C1 reg you need in case of a stack fault, 0x040 is the stack ++ * fault bit. We should only be taking one exception at a time, ++ * so if this combination doesn't produce any single exception, ++ * then we have a bad program that isn't synchronizing its FPU usage ++ * and it will suffer the consequences since we won't be able to ++ * fully reproduce the context of the exception ++ */ ++ cwd = get_fpu_cwd(task); ++ swd = get_fpu_swd(task); ++ switch (swd & ~cwd & 0x3f) { ++ case 0x000: ++ default: ++ break; ++ case 0x001: /* Invalid Op */ ++ /* ++ * swd & 0x240 == 0x040: Stack Underflow ++ * swd & 0x240 == 0x240: Stack Overflow ++ * User must clear the SF bit (0x40) if set ++ */ ++ info.si_code = FPE_FLTINV; ++ break; ++ case 0x002: /* Denormalize */ ++ case 0x010: /* Underflow */ ++ info.si_code = FPE_FLTUND; ++ break; ++ case 0x004: /* Zero Divide */ ++ info.si_code = FPE_FLTDIV; ++ break; ++ case 0x008: /* Overflow */ ++ info.si_code = FPE_FLTOVF; ++ break; ++ case 0x020: /* Precision */ ++ info.si_code = FPE_FLTRES; ++ break; ++ } ++ force_sig_info(SIGFPE, &info, task); ++} ++ ++asmlinkage void bad_intr(void) ++{ ++ printk("bad interrupt"); ++} ++ ++asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) ++{ ++ void __user *rip = (void __user *)(regs->rip); ++ struct task_struct * task; ++ siginfo_t info; ++ unsigned short mxcsr; ++ ++ conditional_sti(regs); ++ if (!user_mode(regs) && ++ kernel_math_error(regs, "kernel simd math error", 19)) ++ return; ++ ++ /* ++ * Save the info for the exception handler and clear the error. ++ */ ++ task = current; ++ save_init_fpu(task); ++ task->thread.trap_no = 19; ++ task->thread.error_code = 0; ++ info.si_signo = SIGFPE; ++ info.si_errno = 0; ++ info.si_code = __SI_FAULT; ++ info.si_addr = rip; ++ /* ++ * The SIMD FPU exceptions are handled a little differently, as there ++ * is only a single status/control register. Thus, to determine which ++ * unmasked exception was caught we must mask the exception mask bits ++ * at 0x1f80, and then use these to mask the exception bits at 0x3f. ++ */ ++ mxcsr = get_fpu_mxcsr(task); ++ switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { ++ case 0x000: ++ default: ++ break; ++ case 0x001: /* Invalid Op */ ++ info.si_code = FPE_FLTINV; ++ break; ++ case 0x002: /* Denormalize */ ++ case 0x010: /* Underflow */ ++ info.si_code = FPE_FLTUND; ++ break; ++ case 0x004: /* Zero Divide */ ++ info.si_code = FPE_FLTDIV; ++ break; ++ case 0x008: /* Overflow */ ++ info.si_code = FPE_FLTOVF; ++ break; ++ case 0x020: /* Precision */ ++ info.si_code = FPE_FLTRES; ++ break; ++ } ++ force_sig_info(SIGFPE, &info, task); ++} ++ ++asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs) ++{ ++} ++ ++#if 0 ++asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) ++{ ++} ++#endif ++ ++asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) ++{ ++} ++ ++/* ++ * 'math_state_restore()' saves the current math information in the ++ * old math state array, and gets the new ones from the current task ++ * ++ * Careful.. There are problems with IBM-designed IRQ13 behaviour. ++ * Don't touch unless you *really* know how it works. ++ */ ++asmlinkage void math_state_restore(void) ++{ ++ struct task_struct *me = current; ++ /* clts(); */ /* 'clts' is done for us by Xen during virtual trap. */ ++ ++ if (!used_math()) ++ init_fpu(me); ++ restore_fpu_checking(&me->thread.i387.fxsave); ++ task_thread_info(me)->status |= TS_USEDFPU; ++ me->fpu_counter++; ++} ++ ++ ++/* ++ * NB. All these are "interrupt gates" (i.e. events_mask is set) because we ++ * specify <dpl>|4 in the second field. ++ */ ++static trap_info_t trap_table[] = { ++ { 0, 0|4, __KERNEL_CS, (unsigned long)divide_error }, ++ { 1, 0|4, __KERNEL_CS, (unsigned long)debug }, ++ { 3, 3|4, __KERNEL_CS, (unsigned long)int3 }, ++ { 4, 3|4, __KERNEL_CS, (unsigned long)overflow }, ++ { 5, 0|4, __KERNEL_CS, (unsigned long)bounds }, ++ { 6, 0|4, __KERNEL_CS, (unsigned long)invalid_op }, ++ { 7, 0|4, __KERNEL_CS, (unsigned long)device_not_available }, ++ { 9, 0|4, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun}, ++ { 10, 0|4, __KERNEL_CS, (unsigned long)invalid_TSS }, ++ { 11, 0|4, __KERNEL_CS, (unsigned long)segment_not_present }, ++ { 12, 0|4, __KERNEL_CS, (unsigned long)stack_segment }, ++ { 13, 0|4, __KERNEL_CS, (unsigned long)general_protection }, ++ { 14, 0|4, __KERNEL_CS, (unsigned long)page_fault }, ++ { 15, 0|4, __KERNEL_CS, (unsigned long)spurious_interrupt_bug }, ++ { 16, 0|4, __KERNEL_CS, (unsigned long)coprocessor_error }, ++ { 17, 0|4, __KERNEL_CS, (unsigned long)alignment_check }, ++#ifdef CONFIG_X86_MCE ++ { 18, 0|4, __KERNEL_CS, (unsigned long)machine_check }, ++#endif ++ { 19, 0|4, __KERNEL_CS, (unsigned long)simd_coprocessor_error }, ++#ifdef CONFIG_IA32_EMULATION ++ { IA32_SYSCALL_VECTOR, 3|4, __KERNEL_CS, (unsigned long)ia32_syscall}, ++#endif ++ { 0, 0, 0, 0 } ++}; ++ ++void __init trap_init(void) ++{ ++ int ret; ++ ++ ret = HYPERVISOR_set_trap_table(trap_table); ++ ++ if (ret) ++ printk("HYPERVISOR_set_trap_table faild: error %d\n", ++ ret); ++ ++ /* ++ * Should be a barrier for any external CPU state. ++ */ ++ cpu_init(); ++} ++ ++void smp_trap_init(trap_info_t *trap_ctxt) ++{ ++ trap_info_t *t = trap_table; ++ ++ for (t = trap_table; t->address; t++) { ++ trap_ctxt[t->vector].flags = t->flags; ++ trap_ctxt[t->vector].cs = t->cs; ++ trap_ctxt[t->vector].address = t->address; ++ } ++} ++ ++ ++static int __init oops_setup(char *s) ++{ ++ if (!s) ++ return -EINVAL; ++ if (!strcmp(s, "panic")) ++ panic_on_oops = 1; ++ return 0; ++} ++early_param("oops", oops_setup); ++ ++static int __init kstack_setup(char *s) ++{ ++ if (!s) ++ return -EINVAL; ++ kstack_depth_to_print = simple_strtoul(s,NULL,0); ++ return 0; ++} ++early_param("kstack", kstack_setup); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/vmlinux.lds.S +--- a/arch/x86_64/kernel/vmlinux.lds.S Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/vmlinux.lds.S Wed Aug 08 16:25:28 2007 -0300 +@@ -127,7 +127,7 @@ SECTIONS + . = ALIGN(8192); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) +- }:data.init ++ } :data.init + + . = ALIGN(4096); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { +@@ -227,4 +227,6 @@ SECTIONS + STABS_DEBUG + + DWARF_DEBUG ++ ++ NOTES + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/vsyscall.c +--- a/arch/x86_64/kernel/vsyscall.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/kernel/vsyscall.c Wed Aug 08 16:25:28 2007 -0300 +@@ -246,6 +246,7 @@ static ctl_table kernel_root_table2[] = + + #endif + ++#ifndef CONFIG_XEN + /* Assume __initcall executes before all user space. Hopefully kmod + doesn't violate that. We'll find out if it does. */ + static void __cpuinit vsyscall_set_cpu(int cpu) +@@ -282,6 +283,7 @@ cpu_vsyscall_notifier(struct notifier_bl + smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); + return NOTIFY_DONE; + } ++#endif + + static void __init map_vsyscall(void) + { +@@ -291,6 +293,17 @@ static void __init map_vsyscall(void) + /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */ + __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); + } ++ ++#ifdef CONFIG_XEN ++static void __init map_vsyscall_user(void) ++{ ++ extern void __set_fixmap_user(enum fixed_addresses, unsigned long, pgprot_t); ++ extern char __vsyscall_0; ++ unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0); ++ ++ __set_fixmap_user(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); ++} ++#endif + + static int __init vsyscall_init(void) + { +@@ -300,11 +313,17 @@ static int __init vsyscall_init(void) + BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); + BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); + map_vsyscall(); ++#ifdef CONFIG_XEN ++ map_vsyscall_user(); ++ sysctl_vsyscall = 0; /* disable vgettimeofay() */ ++#endif + #ifdef CONFIG_SYSCTL + register_sysctl_table(kernel_root_table2, 0); + #endif ++#ifndef CONFIG_XEN + on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); + hotcpu_notifier(cpu_vsyscall_notifier, 0); ++#endif + return 0; + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/kernel/xen_entry.S +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/kernel/xen_entry.S Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,40 @@ ++/* ++ * Copied from arch/xen/i386/kernel/entry.S ++ */ ++/* Offsets into shared_info_t. */ ++#define evtchn_upcall_pending /* 0 */ ++#define evtchn_upcall_mask 1 ++ ++#define sizeof_vcpu_shift 6 ++ ++#ifdef CONFIG_SMP ++//#define preempt_disable(reg) incl threadinfo_preempt_count(reg) ++//#define preempt_enable(reg) decl threadinfo_preempt_count(reg) ++#define preempt_disable(reg) ++#define preempt_enable(reg) ++#define XEN_GET_VCPU_INFO(reg) preempt_disable(%rbp) ; \ ++ movq %gs:pda_cpunumber,reg ; \ ++ shl $32, reg ; \ ++ shr $32-sizeof_vcpu_shift,reg ; \ ++ addq HYPERVISOR_shared_info,reg ++#define XEN_PUT_VCPU_INFO(reg) preempt_enable(%rbp) ; \ ++#define XEN_PUT_VCPU_INFO_fixup .byte 0xff,0xff,0xff ++#else ++#define XEN_GET_VCPU_INFO(reg) movq HYPERVISOR_shared_info,reg ++#define XEN_PUT_VCPU_INFO(reg) ++#define XEN_PUT_VCPU_INFO_fixup ++#endif ++ ++#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg) ++#define XEN_LOCKED_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg) ++#define XEN_BLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \ ++ XEN_LOCKED_BLOCK_EVENTS(reg) ; \ ++ XEN_PUT_VCPU_INFO(reg) ++#define XEN_UNBLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \ ++ XEN_LOCKED_UNBLOCK_EVENTS(reg) ; \ ++ XEN_PUT_VCPU_INFO(reg) ++#define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg) ++ ++VGCF_IN_SYSCALL = (1<<8) ++ ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/mm/Makefile +--- a/arch/x86_64/mm/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/mm/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -9,3 +9,13 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o + obj-$(CONFIG_ACPI_NUMA) += srat.o + + hugetlbpage-y = ../../i386/mm/hugetlbpage.o ++ ++ifdef CONFIG_XEN ++include $(srctree)/scripts/Makefile.xen ++ ++ioremap-y += ../../i386/mm/ioremap-xen.o ++hypervisor-y += ../../i386/mm/hypervisor.o ++obj-y += hypervisor.o ++ ++obj-y := $(call cherrypickxen, $(obj-y)) ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/mm/fault.c +--- a/arch/x86_64/mm/fault.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/mm/fault.c Wed Aug 08 16:25:28 2007 -0300 +@@ -180,9 +180,7 @@ void dump_pagetable(unsigned long addres + pmd_t *pmd; + pte_t *pte; + +- asm("movq %%cr3,%0" : "=r" (pgd)); +- +- pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); ++ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK); + pgd += pgd_index(address); + if (bad_address(pgd)) goto bad; + printk("PGD %lx ", pgd_val(*pgd)); +@@ -286,7 +284,13 @@ static int vmalloc_fault(unsigned long a + happen within a race in page table update. In the later + case just flush. */ + ++#ifdef CONFIG_XEN ++ /* On Xen the line below does not always work. Needs investigating! */ ++ pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK); ++ pgd += pgd_index(address); ++#else + pgd = pgd_offset(current->mm ?: &init_mm, address); ++#endif + pgd_ref = pgd_offset_k(address); + if (pgd_none(*pgd_ref)) + return -1; +@@ -325,6 +329,61 @@ int page_fault_trace = 0; + int page_fault_trace = 0; + int exception_trace = 1; + ++#ifdef CONFIG_XEN ++#define MEM_VERBOSE 1 ++ ++#ifdef MEM_VERBOSE ++#define MEM_LOG(_f, _a...) \ ++ printk("fault.c:[%d]-> " _f "\n", \ ++ __LINE__ , ## _a ) ++#else ++#define MEM_LOG(_f, _a...) ((void)0) ++#endif ++ ++static int spurious_fault(struct pt_regs *regs, ++ unsigned long address, ++ unsigned long error_code) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++#ifdef CONFIG_XEN ++ /* Faults in hypervisor area are never spurious. */ ++ if ((address >= HYPERVISOR_VIRT_START) && ++ (address < HYPERVISOR_VIRT_END)) ++ return 0; ++#endif ++ ++ /* Reserved-bit violation or user access to kernel space? */ ++ if (error_code & (PF_RSVD|PF_USER)) ++ return 0; ++ ++ pgd = init_mm.pgd + pgd_index(address); ++ if (!pgd_present(*pgd)) ++ return 0; ++ ++ pud = pud_offset(pgd, address); ++ if (!pud_present(*pud)) ++ return 0; ++ ++ pmd = pmd_offset(pud, address); ++ if (!pmd_present(*pmd)) ++ return 0; ++ ++ pte = pte_offset_kernel(pmd, address); ++ if (!pte_present(*pte)) ++ return 0; ++ if ((error_code & PF_WRITE) && !pte_write(*pte)) ++ return 0; ++ if ((error_code & PF_INSTR) && (pte_val(*pte) & _PAGE_NX)) ++ return 0; ++ ++ return 1; ++} ++#endif ++ + /* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate +@@ -342,12 +401,21 @@ asmlinkage void __kprobes do_page_fault( + unsigned long flags; + siginfo_t info; + ++#ifdef CONFIG_XEN ++ if (!user_mode(regs)) ++ error_code &= ~PF_USER; /* means kernel */ ++#endif ++ + tsk = current; + mm = tsk->mm; + prefetchw(&mm->mmap_sem); + + /* get the address */ ++#ifdef CONFIG_XEN ++ address = current_vcpu_info()->arch.cr2; ++#else + __asm__("movq %%cr2,%0":"=r" (address)); ++#endif + + info.si_code = SEGV_MAPERR; + +@@ -376,6 +444,11 @@ asmlinkage void __kprobes do_page_fault( + if (vmalloc_fault(address) >= 0) + return; + } ++#ifdef CONFIG_XEN ++ /* Can take a spurious fault if mapping changes R/O -> R/W. */ ++ if (spurious_fault(regs, address, error_code)) ++ return; ++#endif + if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, + SIGSEGV) == NOTIFY_STOP) + return; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/mm/init-xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/arch/x86_64/mm/init-xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1205 @@ ++/* ++ * linux/arch/x86_64/mm/init.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * Copyright (C) 2000 Pavel Machek <pavel@suse.cz> ++ * Copyright (C) 2002,2003 Andi Kleen <ak@suse.de> ++ * ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * Modified for Xen. ++ */ ++ ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/ptrace.h> ++#include <linux/mman.h> ++#include <linux/mm.h> ++#include <linux/swap.h> ++#include <linux/smp.h> ++#include <linux/init.h> ++#include <linux/pagemap.h> ++#include <linux/bootmem.h> ++#include <linux/proc_fs.h> ++#include <linux/pci.h> ++#include <linux/poison.h> ++#include <linux/dma-mapping.h> ++#include <linux/module.h> ++#include <linux/memory_hotplug.h> ++ ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++#include <asm/dma.h> ++#include <asm/fixmap.h> ++#include <asm/e820.h> ++#include <asm/apic.h> ++#include <asm/tlb.h> ++#include <asm/mmu_context.h> ++#include <asm/proto.h> ++#include <asm/smp.h> ++#include <asm/sections.h> ++ ++#include <xen/features.h> ++ ++#ifndef Dprintk ++#define Dprintk(x...) ++#endif ++ ++struct dma_mapping_ops* dma_ops; ++EXPORT_SYMBOL(dma_ops); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++unsigned int __kernel_page_user; ++EXPORT_SYMBOL(__kernel_page_user); ++#endif ++ ++extern unsigned long *contiguous_bitmap; ++ ++static unsigned long dma_reserve __initdata; ++ ++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++extern unsigned long start_pfn; ++ ++/* ++ * Use this until direct mapping is established, i.e. before __va() is ++ * available in init_memory_mapping(). ++ */ ++ ++#define addr_to_page(addr, page) \ ++ (addr) &= PHYSICAL_PAGE_MASK; \ ++ (page) = ((unsigned long *) ((unsigned long) \ ++ (((mfn_to_pfn((addr) >> PAGE_SHIFT)) << PAGE_SHIFT) + \ ++ __START_KERNEL_map))) ++ ++static void __meminit early_make_page_readonly(void *va, unsigned int feature) ++{ ++ unsigned long addr, _va = (unsigned long)va; ++ pte_t pte, *ptep; ++ unsigned long *page = (unsigned long *) init_level4_pgt; ++ ++ if (xen_feature(feature)) ++ return; ++ ++ addr = (unsigned long) page[pgd_index(_va)]; ++ addr_to_page(addr, page); ++ ++ addr = page[pud_index(_va)]; ++ addr_to_page(addr, page); ++ ++ addr = page[pmd_index(_va)]; ++ addr_to_page(addr, page); ++ ++ ptep = (pte_t *) &page[pte_index(_va)]; ++ ++ pte.pte = ptep->pte & ~_PAGE_RW; ++ if (HYPERVISOR_update_va_mapping(_va, pte, 0)) ++ BUG(); ++} ++ ++static void __make_page_readonly(void *va) ++{ ++ pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t pte, *ptep; ++ unsigned long addr = (unsigned long) va; ++ ++ pgd = pgd_offset_k(addr); ++ pud = pud_offset(pgd, addr); ++ pmd = pmd_offset(pud, addr); ++ ptep = pte_offset_kernel(pmd, addr); ++ ++ pte.pte = ptep->pte & ~_PAGE_RW; ++ if (HYPERVISOR_update_va_mapping(addr, pte, 0)) ++ xen_l1_entry_update(ptep, pte); /* fallback */ ++ ++ if ((addr >= VMALLOC_START) && (addr < VMALLOC_END)) ++ __make_page_readonly(__va(pte_pfn(pte) << PAGE_SHIFT)); ++} ++ ++static void __make_page_writable(void *va) ++{ ++ pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t pte, *ptep; ++ unsigned long addr = (unsigned long) va; ++ ++ pgd = pgd_offset_k(addr); ++ pud = pud_offset(pgd, addr); ++ pmd = pmd_offset(pud, addr); ++ ptep = pte_offset_kernel(pmd, addr); ++ ++ pte.pte = ptep->pte | _PAGE_RW; ++ if (HYPERVISOR_update_va_mapping(addr, pte, 0)) ++ xen_l1_entry_update(ptep, pte); /* fallback */ ++ ++ if ((addr >= VMALLOC_START) && (addr < VMALLOC_END)) ++ __make_page_writable(__va(pte_pfn(pte) << PAGE_SHIFT)); ++} ++ ++void make_page_readonly(void *va, unsigned int feature) ++{ ++ if (!xen_feature(feature)) ++ __make_page_readonly(va); ++} ++ ++void make_page_writable(void *va, unsigned int feature) ++{ ++ if (!xen_feature(feature)) ++ __make_page_writable(va); ++} ++ ++void make_pages_readonly(void *va, unsigned nr, unsigned int feature) ++{ ++ if (xen_feature(feature)) ++ return; ++ ++ while (nr-- != 0) { ++ __make_page_readonly(va); ++ va = (void*)((unsigned long)va + PAGE_SIZE); ++ } ++} ++ ++void make_pages_writable(void *va, unsigned nr, unsigned int feature) ++{ ++ if (xen_feature(feature)) ++ return; ++ ++ while (nr-- != 0) { ++ __make_page_writable(va); ++ va = (void*)((unsigned long)va + PAGE_SIZE); ++ } ++} ++ ++/* ++ * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the ++ * physical space so we can cache the place of the first one and move ++ * around without checking the pgd every time. ++ */ ++ ++void show_mem(void) ++{ ++ long i, total = 0, reserved = 0; ++ long shared = 0, cached = 0; ++ pg_data_t *pgdat; ++ struct page *page; ++ ++ printk(KERN_INFO "Mem-info:\n"); ++ show_free_areas(); ++ printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); ++ ++ for_each_online_pgdat(pgdat) { ++ for (i = 0; i < pgdat->node_spanned_pages; ++i) { ++ page = pfn_to_page(pgdat->node_start_pfn + i); ++ total++; ++ if (PageReserved(page)) ++ reserved++; ++ else if (PageSwapCache(page)) ++ cached++; ++ else if (page_count(page)) ++ shared += page_count(page) - 1; ++ } ++ } ++ printk(KERN_INFO "%lu pages of RAM\n", total); ++ printk(KERN_INFO "%lu reserved pages\n",reserved); ++ printk(KERN_INFO "%lu pages shared\n",shared); ++ printk(KERN_INFO "%lu pages swap cached\n",cached); ++} ++ ++int after_bootmem; ++ ++static __init void *spp_getpage(void) ++{ ++ void *ptr; ++ if (after_bootmem) ++ ptr = (void *) get_zeroed_page(GFP_ATOMIC); ++ else if (start_pfn < table_end) { ++ ptr = __va(start_pfn << PAGE_SHIFT); ++ start_pfn++; ++ memset(ptr, 0, PAGE_SIZE); ++ } else ++ ptr = alloc_bootmem_pages(PAGE_SIZE); ++ if (!ptr || ((unsigned long)ptr & ~PAGE_MASK)) ++ panic("set_pte_phys: cannot allocate page data %s\n", after_bootmem?"after bootmem":""); ++ ++ Dprintk("spp_getpage %p\n", ptr); ++ return ptr; ++} ++ ++#define pgd_offset_u(address) (pgd_t *)(init_level4_user_pgt + pgd_index(address)) ++ ++static inline pud_t *pud_offset_u(unsigned long address) ++{ ++ pud_t *pud = level3_user_pgt; ++ ++ return pud + pud_index(address); ++} ++ ++static __init void set_pte_phys(unsigned long vaddr, ++ unsigned long phys, pgprot_t prot, int user_mode) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte, new_pte; ++ ++ Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys); ++ ++ pgd = (user_mode ? pgd_offset_u(vaddr) : pgd_offset_k(vaddr)); ++ if (pgd_none(*pgd)) { ++ printk("PGD FIXMAP MISSING, it should be setup in head.S!\n"); ++ return; ++ } ++ pud = (user_mode ? pud_offset_u(vaddr) : pud_offset(pgd, vaddr)); ++ if (pud_none(*pud)) { ++ pmd = (pmd_t *) spp_getpage(); ++ make_page_readonly(pmd, XENFEAT_writable_page_tables); ++ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER)); ++ if (pmd != pmd_offset(pud, 0)) { ++ printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0)); ++ return; ++ } ++ } ++ pmd = pmd_offset(pud, vaddr); ++ if (pmd_none(*pmd)) { ++ pte = (pte_t *) spp_getpage(); ++ make_page_readonly(pte, XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER)); ++ if (pte != pte_offset_kernel(pmd, 0)) { ++ printk("PAGETABLE BUG #02!\n"); ++ return; ++ } ++ } ++ if (pgprot_val(prot)) ++ new_pte = pfn_pte(phys >> PAGE_SHIFT, prot); ++ else ++ new_pte = __pte(0); ++ ++ pte = pte_offset_kernel(pmd, vaddr); ++ if (!pte_none(*pte) && ++ pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask)) ++ pte_ERROR(*pte); ++ set_pte(pte, new_pte); ++ ++ /* ++ * It's enough to flush this one mapping. ++ * (PGE mappings get flushed as well) ++ */ ++ __flush_tlb_one(vaddr); ++} ++ ++static __init void set_pte_phys_ma(unsigned long vaddr, ++ unsigned long phys, pgprot_t prot) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte, new_pte; ++ ++ Dprintk("set_pte_phys %lx to %lx\n", vaddr, phys); ++ ++ pgd = pgd_offset_k(vaddr); ++ if (pgd_none(*pgd)) { ++ printk("PGD FIXMAP MISSING, it should be setup in head.S!\n"); ++ return; ++ } ++ pud = pud_offset(pgd, vaddr); ++ if (pud_none(*pud)) { ++ ++ pmd = (pmd_t *) spp_getpage(); ++ make_page_readonly(pmd, XENFEAT_writable_page_tables); ++ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER)); ++ if (pmd != pmd_offset(pud, 0)) { ++ printk("PAGETABLE BUG #01! %p <-> %p\n", pmd, pmd_offset(pud,0)); ++ return; ++ } ++ } ++ pmd = pmd_offset(pud, vaddr); ++ if (pmd_none(*pmd)) { ++ pte = (pte_t *) spp_getpage(); ++ make_page_readonly(pte, XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER)); ++ if (pte != pte_offset_kernel(pmd, 0)) { ++ printk("PAGETABLE BUG #02!\n"); ++ return; ++ } ++ } ++ new_pte = pfn_pte_ma(phys >> PAGE_SHIFT, prot); ++ ++ pte = pte_offset_kernel(pmd, vaddr); ++ set_pte(pte, new_pte); ++ ++ /* ++ * It's enough to flush this one mapping. ++ * (PGE mappings get flushed as well) ++ */ ++ __flush_tlb_one(vaddr); ++} ++ ++#define SET_FIXMAP_KERNEL 0 ++#define SET_FIXMAP_USER 1 ++ ++/* NOTE: this is meant to be run only at boot */ ++void __init ++__set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot) ++{ ++ unsigned long address = __fix_to_virt(idx); ++ ++ if (idx >= __end_of_fixed_addresses) { ++ printk("Invalid __set_fixmap\n"); ++ return; ++ } ++ switch (idx) { ++ case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: ++ set_pte_phys(address, phys, prot, SET_FIXMAP_KERNEL); ++ break; ++ default: ++ set_pte_phys_ma(address, phys, prot); ++ break; ++ } ++} ++ ++/* ++ * This only supports vsyscall area. ++ */ ++void __init ++__set_fixmap_user (enum fixed_addresses idx, unsigned long phys, pgprot_t prot) ++{ ++ unsigned long address = __fix_to_virt(idx); ++ ++ if (idx >= __end_of_fixed_addresses) { ++ printk("Invalid __set_fixmap\n"); ++ return; ++ } ++ ++ set_pte_phys(address, phys, prot, SET_FIXMAP_USER); ++} ++ ++unsigned long __initdata table_start, table_end; ++ ++#ifndef CONFIG_XEN ++extern pmd_t temp_boot_pmds[]; ++ ++static struct temp_map { ++ pmd_t *pmd; ++ void *address; ++ int allocated; ++} temp_mappings[] __initdata = { ++ { &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) }, ++ { &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) }, ++ {} ++}; ++#endif /* !CONFIG_XEN */ ++ ++static __meminit void *alloc_static_page(unsigned long *phys) ++{ ++ unsigned long va = (start_pfn << PAGE_SHIFT) + __START_KERNEL_map; ++ ++ if (after_bootmem) { ++ void *adr = (void *)get_zeroed_page(GFP_ATOMIC); ++ *phys = __pa(adr); ++ return adr; ++ } ++ ++ *phys = start_pfn << PAGE_SHIFT; ++ start_pfn++; ++ memset((void *)va, 0, PAGE_SIZE); ++ return (void *)va; ++} ++ ++#define PTE_SIZE PAGE_SIZE ++ ++static inline void __set_pte(pte_t *dst, pte_t val) ++{ ++ *dst = val; ++} ++ ++static inline int make_readonly(unsigned long paddr) ++{ ++ extern char __vsyscall_0; ++ int readonly = 0; ++ ++ /* Make new page tables read-only. */ ++ if (!xen_feature(XENFEAT_writable_page_tables) ++ && (paddr >= (table_start << PAGE_SHIFT)) ++ && (paddr < (table_end << PAGE_SHIFT))) ++ readonly = 1; ++ /* Make old page tables read-only. */ ++ if (!xen_feature(XENFEAT_writable_page_tables) ++ && (paddr >= (xen_start_info->pt_base - __START_KERNEL_map)) ++ && (paddr < (start_pfn << PAGE_SHIFT))) ++ readonly = 1; ++ ++ /* ++ * No need for writable mapping of kernel image. This also ensures that ++ * page and descriptor tables embedded inside don't have writable ++ * mappings. Exclude the vsyscall area here, allowing alternative ++ * instruction patching to work. ++ */ ++ if ((paddr >= __pa_symbol(&_text)) && (paddr < __pa_symbol(&_end)) ++ && !(paddr >= __pa_symbol(&__vsyscall_0) ++ && paddr < __pa_symbol(&__vsyscall_0) + PAGE_SIZE)) ++ readonly = 1; ++ ++ return readonly; ++} ++ ++#ifndef CONFIG_XEN ++/* Must run before zap_low_mappings */ ++__init void *early_ioremap(unsigned long addr, unsigned long size) ++{ ++ unsigned long map = round_down(addr, LARGE_PAGE_SIZE); ++ ++ /* actually usually some more */ ++ if (size >= LARGE_PAGE_SIZE) { ++ return NULL; ++ } ++ set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); ++ map += LARGE_PAGE_SIZE; ++ set_pmd(temp_mappings[1].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); ++ __flush_tlb(); ++ return temp_mappings[0].address + (addr & (LARGE_PAGE_SIZE-1)); ++} ++ ++/* To avoid virtual aliases later */ ++__init void early_iounmap(void *addr, unsigned long size) ++{ ++ if ((void *)round_down((unsigned long)addr, LARGE_PAGE_SIZE) != temp_mappings[0].address) ++ printk("early_iounmap: bad address %p\n", addr); ++ set_pmd(temp_mappings[0].pmd, __pmd(0)); ++ set_pmd(temp_mappings[1].pmd, __pmd(0)); ++ __flush_tlb(); ++} ++#endif /* !CONFIG_XEN */ ++ ++static void __meminit ++phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end) ++{ ++ int i = pmd_index(address); ++ int k; ++ ++ for (; i < PTRS_PER_PMD; i++) { ++ unsigned long pte_phys; ++ pte_t *pte, *pte_save; ++ pmd_t *pmd = pmd_page + pmd_index(address); ++ ++ if (address >= end) { ++ if (!after_bootmem) ++ for (; i < PTRS_PER_PMD; i++, pmd++) ++ set_pmd(pmd, __pmd(0)); ++ break; ++ } ++ ++ if (pmd_val(*pmd)) ++ continue; ++ ++ pte = alloc_static_page(&pte_phys); ++ pte_save = pte; ++ for (k = 0; k < PTRS_PER_PTE; pte++, k++, address += PTE_SIZE) { ++ if ((address >= end) || ++ ((address >> PAGE_SHIFT) >= ++ xen_start_info->nr_pages)) { ++ __set_pte(pte, __pte(0)); ++ continue; ++ } ++ if (make_readonly(address)) { ++ __set_pte(pte, ++ __pte(address | (_KERNPG_TABLE & ~_PAGE_RW))); ++ continue; ++ } ++ __set_pte(pte, __pte(address | _KERNPG_TABLE)); ++ } ++ pte = pte_save; ++ early_make_page_readonly(pte, XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(pte_phys | _KERNPG_TABLE)); ++ } ++} ++ ++static void __meminit ++phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end) ++{ ++ pmd_t *pmd = pmd_offset(pud,0); ++ spin_lock(&init_mm.page_table_lock); ++ phys_pmd_init(pmd, address, end); ++ spin_unlock(&init_mm.page_table_lock); ++ __flush_tlb_all(); ++} ++ ++static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) ++{ ++ int i = pud_index(addr); ++ ++ ++ for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) { ++ unsigned long pmd_phys; ++ pud_t *pud = pud_page + pud_index(addr); ++ pmd_t *pmd; ++ ++ if (addr >= end) ++ break; ++ ++ if (pud_val(*pud)) { ++ phys_pmd_update(pud, addr, end); ++ continue; ++ } ++ ++ pmd = alloc_static_page(&pmd_phys); ++ early_make_page_readonly(pmd, XENFEAT_writable_page_tables); ++ spin_lock(&init_mm.page_table_lock); ++ set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE)); ++ phys_pmd_init(pmd, addr, end); ++ spin_unlock(&init_mm.page_table_lock); ++ } ++ __flush_tlb(); ++} ++ ++void __init xen_init_pt(void) ++{ ++ unsigned long addr, *page; ++ ++ /* Find the initial pte page that was built for us. */ ++ page = (unsigned long *)xen_start_info->pt_base; ++ addr = page[pgd_index(__START_KERNEL_map)]; ++ addr_to_page(addr, page); ++ addr = page[pud_index(__START_KERNEL_map)]; ++ addr_to_page(addr, page); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ /* On Xen 3.0.2 and older we may need to explicitly specify _PAGE_USER ++ in kernel PTEs. We check that here. */ ++ if (HYPERVISOR_xen_version(XENVER_version, NULL) <= 0x30000) { ++ unsigned long *pg; ++ pte_t pte; ++ ++ /* Mess with the initial mapping of page 0. It's not needed. */ ++ BUILD_BUG_ON(__START_KERNEL <= __START_KERNEL_map); ++ addr = page[pmd_index(__START_KERNEL_map)]; ++ addr_to_page(addr, pg); ++ pte.pte = pg[pte_index(__START_KERNEL_map)]; ++ BUG_ON(!(pte.pte & _PAGE_PRESENT)); ++ ++ /* If _PAGE_USER isn't set, we obviously do not need it. */ ++ if (pte.pte & _PAGE_USER) { ++ /* _PAGE_USER is needed, but is it set implicitly? */ ++ pte.pte &= ~_PAGE_USER; ++ if ((HYPERVISOR_update_va_mapping(__START_KERNEL_map, ++ pte, 0) != 0) || ++ !(pg[pte_index(__START_KERNEL_map)] & _PAGE_USER)) ++ /* We need to explicitly specify _PAGE_USER. */ ++ __kernel_page_user = _PAGE_USER; ++ } ++ } ++#endif ++ ++ /* Construct mapping of initial pte page in our own directories. */ ++ init_level4_pgt[pgd_index(__START_KERNEL_map)] = ++ mk_kernel_pgd(__pa_symbol(level3_kernel_pgt)); ++ level3_kernel_pgt[pud_index(__START_KERNEL_map)] = ++ __pud(__pa_symbol(level2_kernel_pgt) | ++ _KERNPG_TABLE); ++ memcpy((void *)level2_kernel_pgt, page, PAGE_SIZE); ++ ++ early_make_page_readonly(init_level4_pgt, ++ XENFEAT_writable_page_tables); ++ early_make_page_readonly(init_level4_user_pgt, ++ XENFEAT_writable_page_tables); ++ early_make_page_readonly(level3_kernel_pgt, ++ XENFEAT_writable_page_tables); ++ early_make_page_readonly(level3_user_pgt, ++ XENFEAT_writable_page_tables); ++ early_make_page_readonly(level2_kernel_pgt, ++ XENFEAT_writable_page_tables); ++ ++ if (!xen_feature(XENFEAT_writable_page_tables)) { ++ xen_pgd_pin(__pa_symbol(init_level4_pgt)); ++ xen_pgd_pin(__pa_symbol(init_level4_user_pgt)); ++ } ++ ++ set_pgd((pgd_t *)(init_level4_user_pgt + 511), ++ mk_kernel_pgd(__pa_symbol(level3_user_pgt))); ++} ++ ++static void __init extend_init_mapping(unsigned long tables_space) ++{ ++ unsigned long va = __START_KERNEL_map; ++ unsigned long phys, addr, *pte_page; ++ pmd_t *pmd; ++ pte_t *pte, new_pte; ++ unsigned long *page = (unsigned long *)init_level4_pgt; ++ ++ addr = page[pgd_index(va)]; ++ addr_to_page(addr, page); ++ addr = page[pud_index(va)]; ++ addr_to_page(addr, page); ++ ++ /* Kill mapping of low 1MB. */ ++ while (va < (unsigned long)&_text) { ++ HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0); ++ va += PAGE_SIZE; ++ } ++ ++ /* Ensure init mappings cover kernel text/data and initial tables. */ ++ while (va < (__START_KERNEL_map ++ + (start_pfn << PAGE_SHIFT) ++ + tables_space)) { ++ pmd = (pmd_t *)&page[pmd_index(va)]; ++ if (pmd_none(*pmd)) { ++ pte_page = alloc_static_page(&phys); ++ early_make_page_readonly( ++ pte_page, XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(phys | _KERNPG_TABLE)); ++ } else { ++ addr = page[pmd_index(va)]; ++ addr_to_page(addr, pte_page); ++ } ++ pte = (pte_t *)&pte_page[pte_index(va)]; ++ if (pte_none(*pte)) { ++ new_pte = pfn_pte( ++ (va - __START_KERNEL_map) >> PAGE_SHIFT, ++ __pgprot(_KERNPG_TABLE)); ++ xen_l1_entry_update(pte, new_pte); ++ } ++ va += PAGE_SIZE; ++ } ++ ++ /* Finally, blow away any spurious initial mappings. */ ++ while (1) { ++ pmd = (pmd_t *)&page[pmd_index(va)]; ++ if (pmd_none(*pmd)) ++ break; ++ HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0); ++ va += PAGE_SIZE; ++ } ++} ++ ++static void __init find_early_table_space(unsigned long end) ++{ ++ unsigned long puds, pmds, ptes, tables; ++ ++ puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; ++ pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; ++ ptes = (end + PTE_SIZE - 1) >> PAGE_SHIFT; ++ ++ tables = round_up(puds * 8, PAGE_SIZE) + ++ round_up(pmds * 8, PAGE_SIZE) + ++ round_up(ptes * 8, PAGE_SIZE); ++ ++ extend_init_mapping(tables); ++ ++ table_start = start_pfn; ++ table_end = table_start + (tables>>PAGE_SHIFT); ++ ++ early_printk("kernel direct mapping tables up to %lx @ %lx-%lx\n", ++ end, table_start << PAGE_SHIFT, ++ (table_start << PAGE_SHIFT) + tables); ++} ++ ++static void xen_finish_init_mapping(void) ++{ ++ unsigned long i, start, end; ++ ++ /* Re-vector virtual addresses pointing into the initial ++ mapping to the just-established permanent ones. */ ++ xen_start_info = __va(__pa(xen_start_info)); ++ xen_start_info->pt_base = (unsigned long) ++ __va(__pa(xen_start_info->pt_base)); ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ phys_to_machine_mapping = ++ __va(__pa(xen_start_info->mfn_list)); ++ xen_start_info->mfn_list = (unsigned long) ++ phys_to_machine_mapping; ++ } ++ if (xen_start_info->mod_start) ++ xen_start_info->mod_start = (unsigned long) ++ __va(__pa(xen_start_info->mod_start)); ++ ++ /* Destroy the Xen-created mappings beyond the kernel image as ++ * well as the temporary mappings created above. Prevents ++ * overlap with modules area (if init mapping is very big). ++ */ ++ start = PAGE_ALIGN((unsigned long)_end); ++ end = __START_KERNEL_map + (table_end << PAGE_SHIFT); ++ for (; start < end; start += PAGE_SIZE) ++ WARN_ON(HYPERVISOR_update_va_mapping( ++ start, __pte_ma(0), 0)); ++ ++ /* Allocate pte's for initial fixmaps from 'start_pfn' allocator. */ ++ table_end = ~0UL; ++ ++ /* ++ * Prefetch pte's for the bt_ioremap() area. It gets used before the ++ * boot-time allocator is online, so allocate-on-demand would fail. ++ */ ++ for (i = FIX_BTMAP_END; i <= FIX_BTMAP_BEGIN; i++) ++ __set_fixmap(i, 0, __pgprot(0)); ++ ++ /* Switch to the real shared_info page, and clear the dummy page. */ ++ set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); ++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); ++ memset(empty_zero_page, 0, sizeof(empty_zero_page)); ++ ++ /* Set up mapping of lowest 1MB of physical memory. */ ++ for (i = 0; i < NR_FIX_ISAMAPS; i++) ++ if (is_initial_xendomain()) ++ set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE); ++ else ++ __set_fixmap(FIX_ISAMAP_BEGIN - i, ++ virt_to_mfn(empty_zero_page) ++ << PAGE_SHIFT, ++ PAGE_KERNEL_RO); ++ ++ /* Disable the 'start_pfn' allocator. */ ++ table_end = start_pfn; ++} ++ ++/* Setup the direct mapping of the physical memory at PAGE_OFFSET. ++ This runs before bootmem is initialized and gets pages directly from the ++ physical memory. To access them they are temporarily mapped. */ ++void __meminit init_memory_mapping(unsigned long start, unsigned long end) ++{ ++ unsigned long next; ++ ++ Dprintk("init_memory_mapping\n"); ++ ++ /* ++ * Find space for the kernel direct mapping tables. ++ * Later we should allocate these tables in the local node of the memory ++ * mapped. Unfortunately this is done currently before the nodes are ++ * discovered. ++ */ ++ if (!after_bootmem) ++ find_early_table_space(end); ++ ++ start = (unsigned long)__va(start); ++ end = (unsigned long)__va(end); ++ ++ for (; start < end; start = next) { ++ unsigned long pud_phys; ++ pgd_t *pgd = pgd_offset_k(start); ++ pud_t *pud; ++ ++ if (after_bootmem) { ++ pud = pud_offset(pgd, start & PGDIR_MASK); ++ make_page_readonly(pud, XENFEAT_writable_page_tables); ++ pud_phys = __pa(pud); ++ } else { ++ pud = alloc_static_page(&pud_phys); ++ early_make_page_readonly(pud, XENFEAT_writable_page_tables); ++ } ++ next = start + PGDIR_SIZE; ++ if (next > end) ++ next = end; ++ phys_pud_init(pud, __pa(start), __pa(next)); ++ if (!after_bootmem) ++ set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys)); ++ } ++ ++ if (!after_bootmem) { ++ BUG_ON(start_pfn != table_end); ++ xen_finish_init_mapping(); ++ } ++ ++ __flush_tlb_all(); ++} ++ ++void __cpuinit zap_low_mappings(int cpu) ++{ ++ /* this is not required for Xen */ ++#if 0 ++ swap_low_mappings(); ++#endif ++} ++ ++#ifndef CONFIG_NUMA ++void __init paging_init(void) ++{ ++ unsigned long max_zone_pfns[MAX_NR_ZONES]; ++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); ++ max_zone_pfns[ZONE_DMA] = end_pfn; ++ max_zone_pfns[ZONE_DMA32] = end_pfn; ++ max_zone_pfns[ZONE_NORMAL] = end_pfn; ++ ++ memory_present(0, 0, end_pfn); ++ sparse_init(); ++ free_area_init_nodes(max_zone_pfns); ++ ++ init_mm.context.pinned = 1; ++} ++#endif ++ ++/* Unmap a kernel mapping if it exists. This is useful to avoid prefetches ++ from the CPU leading to inconsistent cache lines. address and size ++ must be aligned to 2MB boundaries. ++ Does nothing when the mapping doesn't exist. */ ++void __init clear_kernel_mapping(unsigned long address, unsigned long size) ++{ ++ unsigned long end = address + size; ++ ++ BUG_ON(address & ~LARGE_PAGE_MASK); ++ BUG_ON(size & ~LARGE_PAGE_MASK); ++ ++ for (; address < end; address += LARGE_PAGE_SIZE) { ++ pgd_t *pgd = pgd_offset_k(address); ++ pud_t *pud; ++ pmd_t *pmd; ++ if (pgd_none(*pgd)) ++ continue; ++ pud = pud_offset(pgd, address); ++ if (pud_none(*pud)) ++ continue; ++ pmd = pmd_offset(pud, address); ++ if (!pmd || pmd_none(*pmd)) ++ continue; ++ if (0 == (pmd_val(*pmd) & _PAGE_PSE)) { ++ /* Could handle this, but it should not happen currently. */ ++ printk(KERN_ERR ++ "clear_kernel_mapping: mapping has been split. will leak memory\n"); ++ pmd_ERROR(*pmd); ++ } ++ set_pmd(pmd, __pmd(0)); ++ } ++ __flush_tlb_all(); ++} ++ ++/* ++ * Memory hotplug specific functions ++ */ ++void online_page(struct page *page) ++{ ++ ClearPageReserved(page); ++ init_page_count(page); ++ __free_page(page); ++ totalram_pages++; ++ num_physpages++; ++} ++ ++#ifdef CONFIG_MEMORY_HOTPLUG ++/* ++ * Memory is added always to NORMAL zone. This means you will never get ++ * additional DMA/DMA32 memory. ++ */ ++int arch_add_memory(int nid, u64 start, u64 size) ++{ ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct zone *zone = pgdat->node_zones + ZONE_NORMAL; ++ unsigned long start_pfn = start >> PAGE_SHIFT; ++ unsigned long nr_pages = size >> PAGE_SHIFT; ++ int ret; ++ ++ init_memory_mapping(start, (start + size -1)); ++ ++ ret = __add_pages(zone, start_pfn, nr_pages); ++ if (ret) ++ goto error; ++ ++ return ret; ++error: ++ printk("%s: Problem encountered in __add_pages!\n", __func__); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(arch_add_memory); ++ ++int remove_memory(u64 start, u64 size) ++{ ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(remove_memory); ++ ++#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA) ++int memory_add_physaddr_to_nid(u64 start) ++{ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); ++#endif ++ ++#endif /* CONFIG_MEMORY_HOTPLUG */ ++ ++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE ++/* ++ * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance, ++ * just online the pages. ++ */ ++int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages) ++{ ++ int err = -EIO; ++ unsigned long pfn; ++ unsigned long total = 0, mem = 0; ++ for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) { ++ if (pfn_valid(pfn)) { ++ online_page(pfn_to_page(pfn)); ++ err = 0; ++ mem++; ++ } ++ total++; ++ } ++ if (!err) { ++ z->spanned_pages += total; ++ z->present_pages += mem; ++ z->zone_pgdat->node_spanned_pages += total; ++ z->zone_pgdat->node_present_pages += mem; ++ } ++ return err; ++} ++#endif ++ ++static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, ++ kcore_vsyscall; ++ ++void __init mem_init(void) ++{ ++ long codesize, reservedpages, datasize, initsize; ++ unsigned long pfn; ++ ++ contiguous_bitmap = alloc_bootmem_low_pages( ++ (end_pfn + 2*BITS_PER_LONG) >> 3); ++ BUG_ON(!contiguous_bitmap); ++ memset(contiguous_bitmap, 0, (end_pfn + 2*BITS_PER_LONG) >> 3); ++ ++ pci_iommu_alloc(); ++ ++ /* clear the zero-page */ ++ memset(empty_zero_page, 0, PAGE_SIZE); ++ ++ reservedpages = 0; ++ ++ /* this will put all low memory onto the freelists */ ++#ifdef CONFIG_NUMA ++ totalram_pages = numa_free_all_bootmem(); ++#else ++ totalram_pages = free_all_bootmem(); ++#endif ++ /* XEN: init and count pages outside initial allocation. */ ++ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { ++ ClearPageReserved(pfn_to_page(pfn)); ++ init_page_count(pfn_to_page(pfn)); ++ totalram_pages++; ++ } ++ reservedpages = end_pfn - totalram_pages - ++ absent_pages_in_range(0, end_pfn); ++ ++ ++ after_bootmem = 1; ++ ++ codesize = (unsigned long) &_etext - (unsigned long) &_text; ++ datasize = (unsigned long) &_edata - (unsigned long) &_etext; ++ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; ++ ++ /* Register memory areas for /proc/kcore */ ++ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); ++ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, ++ VMALLOC_END-VMALLOC_START); ++ kclist_add(&kcore_kernel, &_stext, _end - _stext); ++ kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN); ++ kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, ++ VSYSCALL_END - VSYSCALL_START); ++ ++ printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n", ++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), ++ end_pfn << (PAGE_SHIFT-10), ++ codesize >> 10, ++ reservedpages << (PAGE_SHIFT-10), ++ datasize >> 10, ++ initsize >> 10); ++ ++#ifndef CONFIG_XEN ++#ifdef CONFIG_SMP ++ /* ++ * Sync boot_level4_pgt mappings with the init_level4_pgt ++ * except for the low identity mappings which are already zapped ++ * in init_level4_pgt. This sync-up is essential for AP's bringup ++ */ ++ memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t)); ++#endif ++#endif ++} ++ ++void free_init_pages(char *what, unsigned long begin, unsigned long end) ++{ ++ unsigned long addr; ++ ++ if (begin >= end) ++ return; ++ ++ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); ++ for (addr = begin; addr < end; addr += PAGE_SIZE) { ++ ClearPageReserved(virt_to_page(addr)); ++ init_page_count(virt_to_page(addr)); ++ memset((void *)(addr & ~(PAGE_SIZE-1)), ++ POISON_FREE_INITMEM, PAGE_SIZE); ++ if (addr >= __START_KERNEL_map) { ++ /* make_readonly() reports all kernel addresses. */ ++ __make_page_writable(__va(__pa(addr))); ++ if (HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { ++ pgd_t *pgd = pgd_offset_k(addr); ++ pud_t *pud = pud_offset(pgd, addr); ++ pmd_t *pmd = pmd_offset(pud, addr); ++ pte_t *pte = pte_offset_kernel(pmd, addr); ++ ++ xen_l1_entry_update(pte, __pte(0)); /* fallback */ ++ } ++ } ++ free_page(addr); ++ totalram_pages++; ++ } ++} ++ ++void free_initmem(void) ++{ ++ memset(__initdata_begin, POISON_FREE_INITDATA, ++ __initdata_end - __initdata_begin); ++ free_init_pages("unused kernel memory", ++ (unsigned long)(&__init_begin), ++ (unsigned long)(&__init_end)); ++} ++ ++#ifdef CONFIG_DEBUG_RODATA ++ ++void mark_rodata_ro(void) ++{ ++ unsigned long addr = (unsigned long)__start_rodata; ++ ++ for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) ++ change_page_attr_addr(addr, 1, PAGE_KERNEL_RO); ++ ++ printk ("Write protecting the kernel read-only data: %luk\n", ++ (__end_rodata - __start_rodata) >> 10); ++ ++ /* ++ * change_page_attr_addr() requires a global_flush_tlb() call after it. ++ * We do this after the printk so that if something went wrong in the ++ * change, the printk gets out at least to give a better debug hint ++ * of who is the culprit. ++ */ ++ global_flush_tlb(); ++} ++#endif ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++void free_initrd_mem(unsigned long start, unsigned long end) ++{ ++ free_init_pages("initrd memory", start, end); ++} ++#endif ++ ++void __init reserve_bootmem_generic(unsigned long phys, unsigned len) ++{ ++#ifdef CONFIG_NUMA ++ int nid = phys_to_nid(phys); ++#endif ++ unsigned long pfn = phys >> PAGE_SHIFT; ++ if (pfn >= end_pfn) { ++ /* This can happen with kdump kernels when accessing firmware ++ tables. */ ++ if (pfn < end_pfn_map) ++ return; ++ printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", ++ phys, len); ++ return; ++ } ++ ++ /* Should check here against the e820 map to avoid double free */ ++#ifdef CONFIG_NUMA ++ reserve_bootmem_node(NODE_DATA(nid), phys, len); ++#else ++ reserve_bootmem(phys, len); ++#endif ++ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) { ++ dma_reserve += len / PAGE_SIZE; ++ set_dma_reserve(dma_reserve); ++ } ++} ++ ++int kern_addr_valid(unsigned long addr) ++{ ++ unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ if (above != 0 && above != -1UL) ++ return 0; ++ ++ pgd = pgd_offset_k(addr); ++ if (pgd_none(*pgd)) ++ return 0; ++ ++ pud = pud_offset(pgd, addr); ++ if (pud_none(*pud)) ++ return 0; ++ ++ pmd = pmd_offset(pud, addr); ++ if (pmd_none(*pmd)) ++ return 0; ++ if (pmd_large(*pmd)) ++ return pfn_valid(pmd_pfn(*pmd)); ++ ++ pte = pte_offset_kernel(pmd, addr); ++ if (pte_none(*pte)) ++ return 0; ++ return pfn_valid(pte_pfn(*pte)); ++} ++ ++#ifdef CONFIG_SYSCTL ++#include <linux/sysctl.h> ++ ++extern int exception_trace, page_fault_trace; ++ ++static ctl_table debug_table2[] = { ++ { 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL, ++ proc_dointvec }, ++ { 0, } ++}; ++ ++static ctl_table debug_root_table2[] = { ++ { .ctl_name = CTL_DEBUG, .procname = "debug", .mode = 0555, ++ .child = debug_table2 }, ++ { 0 }, ++}; ++ ++static __init int x8664_sysctl_init(void) ++{ ++ register_sysctl_table(debug_root_table2, 1); ++ return 0; ++} ++__initcall(x8664_sysctl_init); ++#endif ++ ++/* A pseudo VMA to allow ptrace access for the vsyscall page. This only ++ covers the 64bit vsyscall page now. 32bit has a real VMA now and does ++ not need special handling anymore. */ ++ ++static struct vm_area_struct gate_vma = { ++ .vm_start = VSYSCALL_START, ++ .vm_end = VSYSCALL_START + (VSYSCALL_MAPPED_PAGES << PAGE_SHIFT), ++ .vm_page_prot = PAGE_READONLY_EXEC, ++ .vm_flags = VM_READ | VM_EXEC ++}; ++ ++struct vm_area_struct *get_gate_vma(struct task_struct *tsk) ++{ ++#ifdef CONFIG_IA32_EMULATION ++ if (test_tsk_thread_flag(tsk, TIF_IA32)) ++ return NULL; ++#endif ++ return &gate_vma; ++} ++ ++int in_gate_area(struct task_struct *task, unsigned long addr) ++{ ++ struct vm_area_struct *vma = get_gate_vma(task); ++ if (!vma) ++ return 0; ++ return (addr >= vma->vm_start) && (addr < vma->vm_end); ++} ++ ++/* Use this when you have no reliable task/vma, typically from interrupt ++ * context. It is less reliable than using the task's vma and may give ++ * false positives. ++ */ ++int in_gate_area_no_task(unsigned long addr) ++{ ++ return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/mm/pageattr.c +--- a/arch/x86_64/mm/pageattr.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/mm/pageattr.c Wed Aug 08 16:25:28 2007 -0300 +@@ -12,6 +12,201 @@ + #include <asm/processor.h> + #include <asm/tlbflush.h> + #include <asm/io.h> ++ ++#ifdef CONFIG_XEN ++#include <asm/pgalloc.h> ++#include <asm/mmu_context.h> ++ ++LIST_HEAD(mm_unpinned); ++DEFINE_SPINLOCK(mm_unpinned_lock); ++ ++static inline void mm_walk_set_prot(void *pt, pgprot_t flags) ++{ ++ struct page *page = virt_to_page(pt); ++ unsigned long pfn = page_to_pfn(page); ++ int rc; ++ ++ rc = HYPERVISOR_update_va_mapping( ++ (unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, flags), 0); ++ if (rc) ++ BUG(); ++} ++ ++static void mm_walk(struct mm_struct *mm, pgprot_t flags) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ int g,u,m; ++ ++ pgd = mm->pgd; ++ /* ++ * Cannot iterate up to USER_PTRS_PER_PGD as these pagetables may not ++ * be the 'current' task's pagetables (e.g., current may be 32-bit, ++ * but the pagetables may be for a 64-bit task). ++ * Subtracting 1 from TASK_SIZE64 means the loop limit is correct ++ * regardless of whether TASK_SIZE64 is a multiple of PGDIR_SIZE. ++ */ ++ for (g = 0; g <= ((TASK_SIZE64-1) / PGDIR_SIZE); g++, pgd++) { ++ if (pgd_none(*pgd)) ++ continue; ++ pud = pud_offset(pgd, 0); ++ if (PTRS_PER_PUD > 1) /* not folded */ ++ mm_walk_set_prot(pud,flags); ++ for (u = 0; u < PTRS_PER_PUD; u++, pud++) { ++ if (pud_none(*pud)) ++ continue; ++ pmd = pmd_offset(pud, 0); ++ if (PTRS_PER_PMD > 1) /* not folded */ ++ mm_walk_set_prot(pmd,flags); ++ for (m = 0; m < PTRS_PER_PMD; m++, pmd++) { ++ if (pmd_none(*pmd)) ++ continue; ++ pte = pte_offset_kernel(pmd,0); ++ mm_walk_set_prot(pte,flags); ++ } ++ } ++ } ++} ++ ++void mm_pin(struct mm_struct *mm) ++{ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ ++ spin_lock(&mm->page_table_lock); ++ ++ mm_walk(mm, PAGE_KERNEL_RO); ++ if (HYPERVISOR_update_va_mapping( ++ (unsigned long)mm->pgd, ++ pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO), ++ UVMF_TLB_FLUSH)) ++ BUG(); ++ if (HYPERVISOR_update_va_mapping( ++ (unsigned long)__user_pgd(mm->pgd), ++ pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, ++ PAGE_KERNEL_RO), ++ UVMF_TLB_FLUSH)) ++ BUG(); ++ xen_pgd_pin(__pa(mm->pgd)); /* kernel */ ++ xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */ ++ mm->context.pinned = 1; ++ spin_lock(&mm_unpinned_lock); ++ list_del(&mm->context.unpinned); ++ spin_unlock(&mm_unpinned_lock); ++ ++ spin_unlock(&mm->page_table_lock); ++} ++ ++void mm_unpin(struct mm_struct *mm) ++{ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ ++ spin_lock(&mm->page_table_lock); ++ ++ xen_pgd_unpin(__pa(mm->pgd)); ++ xen_pgd_unpin(__pa(__user_pgd(mm->pgd))); ++ if (HYPERVISOR_update_va_mapping( ++ (unsigned long)mm->pgd, ++ pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0)) ++ BUG(); ++ if (HYPERVISOR_update_va_mapping( ++ (unsigned long)__user_pgd(mm->pgd), ++ pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, ++ PAGE_KERNEL), 0)) ++ BUG(); ++ mm_walk(mm, PAGE_KERNEL); ++ xen_tlb_flush(); ++ mm->context.pinned = 0; ++ spin_lock(&mm_unpinned_lock); ++ list_add(&mm->context.unpinned, &mm_unpinned); ++ spin_unlock(&mm_unpinned_lock); ++ ++ spin_unlock(&mm->page_table_lock); ++} ++ ++void mm_pin_all(void) ++{ ++ if (xen_feature(XENFEAT_writable_page_tables)) ++ return; ++ ++ /* ++ * Allow uninterrupted access to the mm_unpinned list. We don't ++ * actually take the mm_unpinned_lock as it is taken inside mm_pin(). ++ * All other CPUs must be at a safe point (e.g., in stop_machine ++ * or offlined entirely). ++ */ ++ preempt_disable(); ++ while (!list_empty(&mm_unpinned)) ++ mm_pin(list_entry(mm_unpinned.next, struct mm_struct, ++ context.unpinned)); ++ preempt_enable(); ++} ++ ++void _arch_dup_mmap(struct mm_struct *mm) ++{ ++ if (!mm->context.pinned) ++ mm_pin(mm); ++} ++ ++void _arch_exit_mmap(struct mm_struct *mm) ++{ ++ struct task_struct *tsk = current; ++ ++ task_lock(tsk); ++ ++ /* ++ * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() ++ * *much* faster this way, as no tlb flushes means bigger wrpt batches. ++ */ ++ if ( tsk->active_mm == mm ) ++ { ++ tsk->active_mm = &init_mm; ++ atomic_inc(&init_mm.mm_count); ++ ++ switch_mm(mm, &init_mm, tsk); ++ ++ atomic_dec(&mm->mm_count); ++ BUG_ON(atomic_read(&mm->mm_count) == 0); ++ } ++ ++ task_unlock(tsk); ++ ++ if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) && ++ !mm->context.has_foreign_mappings ) ++ mm_unpin(mm); ++} ++ ++struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) ++{ ++ struct page *pte; ++ ++ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); ++ if (pte) { ++ SetPageForeign(pte, pte_free); ++ init_page_count(pte); ++ } ++ return pte; ++} ++ ++void pte_free(struct page *pte) ++{ ++ unsigned long va = (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT); ++ ++ if (!pte_write(*virt_to_ptep(va))) ++ if (HYPERVISOR_update_va_mapping( ++ va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0)) ++ BUG(); ++ ++ ClearPageForeign(pte); ++ init_page_count(pte); ++ ++ __free_page(pte); ++} ++#endif /* CONFIG_XEN */ + + static inline pte_t *lookup_address(unsigned long address) + { +@@ -154,8 +349,18 @@ __change_page_attr(unsigned long address + BUG(); + + /* on x86-64 the direct mapping set at boot is not using 4k pages */ ++ /* ++ * ..., but the XEN guest kernels (currently) do: ++ * If the pte was reserved, it means it was created at boot ++ * time (not via split_large_page) and in turn we must not ++ * replace it with a large page. ++ */ ++#ifndef CONFIG_XEN + BUG_ON(PageReserved(kpte_page)); +- ++#else ++ if(PageReserved(kpte_page)) ++ return 0; ++#endif + if (page_private(kpte_page) == 0) { + save_page(kpte_page); + revert_page(address, ref_prot); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/oprofile/Makefile +--- a/arch/x86_64/oprofile/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/oprofile/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -11,9 +11,15 @@ DRIVER_OBJS = $(addprefix ../../../drive + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + ++ifdef CONFIG_XEN ++XENOPROF_COMMON_OBJS = $(addprefix ../../../drivers/xen/xenoprof/, \ ++ xenoprofile.o) ++OPROFILE-y := xenoprof.o ++else + OPROFILE-y := init.o backtrace.o + OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \ + op_model_ppro.o + OPROFILE-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o +- +-oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y)) ++endif ++oprofile-y = $(DRIVER_OBJS) $(XENOPROF_COMMON_OBJS) \ ++ $(addprefix ../../i386/oprofile/, $(OPROFILE-y)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 arch/x86_64/pci/Makefile +--- a/arch/x86_64/pci/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/arch/x86_64/pci/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -15,8 +15,13 @@ obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o + + obj-$(CONFIG_NUMA) += k8-bus.o + ++# pcifront should be after mmconfig.o and direct.o as it should only ++# take over if direct access to the PCI bus is unavailable ++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront.o ++ + direct-y += ../../i386/pci/direct.o + acpi-y += ../../i386/pci/acpi.o ++pcifront-y += ../../i386/pci/pcifront.o + legacy-y += ../../i386/pci/legacy.o + irq-y += ../../i386/pci/irq.o + common-y += ../../i386/pci/common.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/Makefile +--- a/drivers/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -31,6 +31,7 @@ obj-$(CONFIG_NUBUS) += nubus/ + obj-$(CONFIG_NUBUS) += nubus/ + obj-$(CONFIG_ATM) += atm/ + obj-y += macintosh/ ++obj-$(CONFIG_XEN) += xen/ + obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_FC4) += fc4/ + obj-$(CONFIG_SCSI) += scsi/ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/acpi/Kconfig +--- a/drivers/acpi/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/acpi/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -11,7 +11,7 @@ config ACPI + bool "ACPI Support" + depends on IA64 || X86 + depends on PCI +- depends on PM ++ depends on PM || XEN + default y + ---help--- + Advanced Configuration and Power Interface (ACPI) support for +@@ -45,7 +45,7 @@ if ACPI + + config ACPI_SLEEP + bool "Sleep States" +- depends on X86 && (!SMP || SUSPEND_SMP) ++ depends on X86 && (!SMP || SUSPEND_SMP) && !XEN + depends on PM + default y + ---help--- +@@ -309,6 +309,7 @@ config X86_PM_TIMER + config X86_PM_TIMER + bool "Power Management Timer Support" if EMBEDDED + depends on X86 ++ depends on !XEN + default y + help + The Power Management Timer is available on all ACPI-capable, +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/mem.c +--- a/drivers/char/mem.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/char/mem.c Wed Aug 08 16:25:28 2007 -0300 +@@ -102,6 +102,7 @@ static inline int valid_mmap_phys_addr_r + } + #endif + ++#ifndef ARCH_HAS_DEV_MEM + /* + * This funcion reads the *physical* memory. The f_pos points directly to the + * memory location. +@@ -224,6 +225,7 @@ static ssize_t write_mem(struct file * f + *ppos += written; + return written; + } ++#endif + + #ifndef __HAVE_PHYS_MEM_ACCESS_PROT + static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, +@@ -810,6 +812,7 @@ static int open_port(struct inode * inod + #define open_kmem open_mem + #define open_oldmem open_mem + ++#ifndef ARCH_HAS_DEV_MEM + static const struct file_operations mem_fops = { + .llseek = memory_lseek, + .read = read_mem, +@@ -818,6 +821,9 @@ static const struct file_operations mem_ + .open = open_mem, + .get_unmapped_area = get_unmapped_area_mem, + }; ++#else ++extern const struct file_operations mem_fops; ++#endif + + static const struct file_operations kmem_fops = { + .llseek = memory_lseek, +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/Kconfig +--- a/drivers/char/tpm/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/char/tpm/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -58,5 +58,13 @@ config TCG_INFINEON + Further information on this driver and the supported hardware + can be found at http://www.prosec.rub.de/tpm + ++config TCG_XEN ++ tristate "XEN TPM Interface" ++ depends on TCG_TPM && XEN ++ ---help--- ++ If you want to make TPM support available to a Xen user domain, ++ say Yes and it will be accessible from within Linux. ++ To compile this driver as a module, choose M here; the module ++ will be called tpm_xenu. ++ + endmenu +- +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/Makefile +--- a/drivers/char/tpm/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/char/tpm/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -9,3 +9,5 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o + obj-$(CONFIG_TCG_NSC) += tpm_nsc.o + obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o + obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o ++obj-$(CONFIG_TCG_XEN) += tpm_xenu.o ++tpm_xenu-y = tpm_xen.o tpm_vtpm.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/tpm.h +--- a/drivers/char/tpm/tpm.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/char/tpm/tpm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -106,6 +106,9 @@ struct tpm_chip { + struct dentry **bios_dir; + + struct list_head list; ++#ifdef CONFIG_XEN ++ void *priv; ++#endif + }; + + #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) +@@ -121,6 +124,18 @@ static inline void tpm_write_index(int b + outb(index, base); + outb(value & 0xFF, base+1); + } ++ ++#ifdef CONFIG_XEN ++static inline void *chip_get_private(const struct tpm_chip *chip) ++{ ++ return chip->priv; ++} ++ ++static inline void chip_set_private(struct tpm_chip *chip, void *priv) ++{ ++ chip->priv = priv; ++} ++#endif + + extern void tpm_get_timeouts(struct tpm_chip *); + extern void tpm_gen_interrupt(struct tpm_chip *); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/tpm_vtpm.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/char/tpm/tpm_vtpm.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,542 @@ ++/* ++ * Copyright (C) 2006 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger <stefanb@us.ibm.com> ++ * ++ * Generic device driver part for device drivers in a virtualized ++ * environment. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation, version 2 of the ++ * License. ++ * ++ */ ++ ++#include <asm/uaccess.h> ++#include <linux/list.h> ++#include <linux/device.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include "tpm.h" ++#include "tpm_vtpm.h" ++ ++/* read status bits */ ++enum { ++ STATUS_BUSY = 0x01, ++ STATUS_DATA_AVAIL = 0x02, ++ STATUS_READY = 0x04 ++}; ++ ++struct transmission { ++ struct list_head next; ++ ++ unsigned char *request; ++ size_t request_len; ++ size_t request_buflen; ++ ++ unsigned char *response; ++ size_t response_len; ++ size_t response_buflen; ++ ++ unsigned int flags; ++}; ++ ++enum { ++ TRANSMISSION_FLAG_WAS_QUEUED = 0x1 ++}; ++ ++ ++enum { ++ DATAEX_FLAG_QUEUED_ONLY = 0x1 ++}; ++ ++ ++/* local variables */ ++ ++/* local function prototypes */ ++static int _vtpm_send_queued(struct tpm_chip *chip); ++ ++ ++/* ============================================================= ++ * Some utility functions ++ * ============================================================= ++ */ ++static void vtpm_state_init(struct vtpm_state *vtpms) ++{ ++ vtpms->current_request = NULL; ++ spin_lock_init(&vtpms->req_list_lock); ++ init_waitqueue_head(&vtpms->req_wait_queue); ++ INIT_LIST_HEAD(&vtpms->queued_requests); ++ ++ vtpms->current_response = NULL; ++ spin_lock_init(&vtpms->resp_list_lock); ++ init_waitqueue_head(&vtpms->resp_wait_queue); ++ ++ vtpms->disconnect_time = jiffies; ++} ++ ++ ++static inline struct transmission *transmission_alloc(void) ++{ ++ return kzalloc(sizeof(struct transmission), GFP_ATOMIC); ++} ++ ++static unsigned char * ++transmission_set_req_buffer(struct transmission *t, ++ unsigned char *buffer, size_t len) ++{ ++ if (t->request_buflen < len) { ++ kfree(t->request); ++ t->request = kmalloc(len, GFP_KERNEL); ++ if (!t->request) { ++ t->request_buflen = 0; ++ return NULL; ++ } ++ t->request_buflen = len; ++ } ++ ++ memcpy(t->request, buffer, len); ++ t->request_len = len; ++ ++ return t->request; ++} ++ ++static unsigned char * ++transmission_set_res_buffer(struct transmission *t, ++ const unsigned char *buffer, size_t len) ++{ ++ if (t->response_buflen < len) { ++ kfree(t->response); ++ t->response = kmalloc(len, GFP_ATOMIC); ++ if (!t->response) { ++ t->response_buflen = 0; ++ return NULL; ++ } ++ t->response_buflen = len; ++ } ++ ++ memcpy(t->response, buffer, len); ++ t->response_len = len; ++ ++ return t->response; ++} ++ ++static inline void transmission_free(struct transmission *t) ++{ ++ kfree(t->request); ++ kfree(t->response); ++ kfree(t); ++} ++ ++/* ============================================================= ++ * Interface with the lower layer driver ++ * ============================================================= ++ */ ++/* ++ * Lower layer uses this function to make a response available. ++ */ ++int vtpm_vd_recv(const struct tpm_chip *chip, ++ const unsigned char *buffer, size_t count, ++ void *ptr) ++{ ++ unsigned long flags; ++ int ret_size = 0; ++ struct transmission *t; ++ struct vtpm_state *vtpms; ++ ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ /* ++ * The list with requests must contain one request ++ * only and the element there must be the one that ++ * was passed to me from the front-end. ++ */ ++ spin_lock_irqsave(&vtpms->resp_list_lock, flags); ++ if (vtpms->current_request != ptr) { ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ return 0; ++ } ++ ++ if ((t = vtpms->current_request)) { ++ transmission_free(t); ++ vtpms->current_request = NULL; ++ } ++ ++ t = transmission_alloc(); ++ if (t) { ++ if (!transmission_set_res_buffer(t, buffer, count)) { ++ transmission_free(t); ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ return -ENOMEM; ++ } ++ ret_size = count; ++ vtpms->current_response = t; ++ wake_up_interruptible(&vtpms->resp_wait_queue); ++ } ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ ++ return ret_size; ++} ++ ++ ++/* ++ * Lower layer indicates its status (connected/disconnected) ++ */ ++void vtpm_vd_status(const struct tpm_chip *chip, u8 vd_status) ++{ ++ struct vtpm_state *vtpms; ++ ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ vtpms->vd_status = vd_status; ++ if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) { ++ vtpms->disconnect_time = jiffies; ++ } ++} ++ ++/* ============================================================= ++ * Interface with the generic TPM driver ++ * ============================================================= ++ */ ++static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) ++{ ++ int rc = 0; ++ unsigned long flags; ++ struct vtpm_state *vtpms; ++ ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ /* ++ * Check if the previous operation only queued the command ++ * In this case there won't be a response, so I just ++ * return from here and reset that flag. In any other ++ * case I should receive a response from the back-end. ++ */ ++ spin_lock_irqsave(&vtpms->resp_list_lock, flags); ++ if ((vtpms->flags & DATAEX_FLAG_QUEUED_ONLY) != 0) { ++ vtpms->flags &= ~DATAEX_FLAG_QUEUED_ONLY; ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ /* ++ * The first few commands (measurements) must be ++ * queued since it might not be possible to talk to the ++ * TPM, yet. ++ * Return a response of up to 30 '0's. ++ */ ++ ++ count = min_t(size_t, count, 30); ++ memset(buf, 0x0, count); ++ return count; ++ } ++ /* ++ * Check whether something is in the responselist and if ++ * there's nothing in the list wait for something to appear. ++ */ ++ ++ if (!vtpms->current_response) { ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ interruptible_sleep_on_timeout(&vtpms->resp_wait_queue, ++ 1000); ++ spin_lock_irqsave(&vtpms->resp_list_lock ,flags); ++ } ++ ++ if (vtpms->current_response) { ++ struct transmission *t = vtpms->current_response; ++ vtpms->current_response = NULL; ++ rc = min(count, t->response_len); ++ memcpy(buf, t->response, rc); ++ transmission_free(t); ++ } ++ ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ return rc; ++} ++ ++static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ++{ ++ int rc = 0; ++ unsigned long flags; ++ struct transmission *t = transmission_alloc(); ++ struct vtpm_state *vtpms; ++ ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ if (!t) ++ return -ENOMEM; ++ /* ++ * If there's a current request, it must be the ++ * previous request that has timed out. ++ */ ++ spin_lock_irqsave(&vtpms->req_list_lock, flags); ++ if (vtpms->current_request != NULL) { ++ printk("WARNING: Sending although there is a request outstanding.\n" ++ " Previous request must have timed out.\n"); ++ transmission_free(vtpms->current_request); ++ vtpms->current_request = NULL; ++ } ++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags); ++ ++ /* ++ * Queue the packet if the driver below is not ++ * ready, yet, or there is any packet already ++ * in the queue. ++ * If the driver below is ready, unqueue all ++ * packets first before sending our current ++ * packet. ++ * For each unqueued packet, except for the ++ * last (=current) packet, call the function ++ * tpm_xen_recv to wait for the response to come ++ * back. ++ */ ++ if ((vtpms->vd_status & TPM_VD_STATUS_CONNECTED) == 0) { ++ if (time_after(jiffies, ++ vtpms->disconnect_time + HZ * 10)) { ++ rc = -ENOENT; ++ } else { ++ goto queue_it; ++ } ++ } else { ++ /* ++ * Send all queued packets. ++ */ ++ if (_vtpm_send_queued(chip) == 0) { ++ ++ vtpms->current_request = t; ++ ++ rc = vtpm_vd_send(vtpms->tpm_private, ++ buf, ++ count, ++ t); ++ /* ++ * The generic TPM driver will call ++ * the function to receive the response. ++ */ ++ if (rc < 0) { ++ vtpms->current_request = NULL; ++ goto queue_it; ++ } ++ } else { ++queue_it: ++ if (!transmission_set_req_buffer(t, buf, count)) { ++ transmission_free(t); ++ rc = -ENOMEM; ++ goto exit; ++ } ++ /* ++ * An error occurred. Don't event try ++ * to send the current request. Just ++ * queue it. ++ */ ++ spin_lock_irqsave(&vtpms->req_list_lock, flags); ++ vtpms->flags |= DATAEX_FLAG_QUEUED_ONLY; ++ list_add_tail(&t->next, &vtpms->queued_requests); ++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags); ++ } ++ } ++ ++exit: ++ return rc; ++} ++ ++ ++/* ++ * Send all queued requests. ++ */ ++static int _vtpm_send_queued(struct tpm_chip *chip) ++{ ++ int rc; ++ int error = 0; ++ long flags; ++ unsigned char buffer[1]; ++ struct vtpm_state *vtpms; ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ spin_lock_irqsave(&vtpms->req_list_lock, flags); ++ ++ while (!list_empty(&vtpms->queued_requests)) { ++ /* ++ * Need to dequeue them. ++ * Read the result into a dummy buffer. ++ */ ++ struct transmission *qt = (struct transmission *) ++ vtpms->queued_requests.next; ++ list_del(&qt->next); ++ vtpms->current_request = qt; ++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags); ++ ++ rc = vtpm_vd_send(vtpms->tpm_private, ++ qt->request, ++ qt->request_len, ++ qt); ++ ++ if (rc < 0) { ++ spin_lock_irqsave(&vtpms->req_list_lock, flags); ++ if ((qt = vtpms->current_request) != NULL) { ++ /* ++ * requeue it at the beginning ++ * of the list ++ */ ++ list_add(&qt->next, ++ &vtpms->queued_requests); ++ } ++ vtpms->current_request = NULL; ++ error = 1; ++ break; ++ } ++ /* ++ * After this point qt is not valid anymore! ++ * It is freed when the front-end is delivering ++ * the data by calling tpm_recv ++ */ ++ /* ++ * Receive response into provided dummy buffer ++ */ ++ rc = vtpm_recv(chip, buffer, sizeof(buffer)); ++ spin_lock_irqsave(&vtpms->req_list_lock, flags); ++ } ++ ++ spin_unlock_irqrestore(&vtpms->req_list_lock, flags); ++ ++ return error; ++} ++ ++static void vtpm_cancel(struct tpm_chip *chip) ++{ ++ unsigned long flags; ++ struct vtpm_state *vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ spin_lock_irqsave(&vtpms->resp_list_lock,flags); ++ ++ if (!vtpms->current_response && vtpms->current_request) { ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ interruptible_sleep_on(&vtpms->resp_wait_queue); ++ spin_lock_irqsave(&vtpms->resp_list_lock,flags); ++ } ++ ++ if (vtpms->current_response) { ++ struct transmission *t = vtpms->current_response; ++ vtpms->current_response = NULL; ++ transmission_free(t); ++ } ++ ++ spin_unlock_irqrestore(&vtpms->resp_list_lock,flags); ++} ++ ++static u8 vtpm_status(struct tpm_chip *chip) ++{ ++ u8 rc = 0; ++ unsigned long flags; ++ struct vtpm_state *vtpms; ++ ++ vtpms = (struct vtpm_state *)chip_get_private(chip); ++ ++ spin_lock_irqsave(&vtpms->resp_list_lock, flags); ++ /* ++ * Data are available if: ++ * - there's a current response ++ * - the last packet was queued only (this is fake, but necessary to ++ * get the generic TPM layer to call the receive function.) ++ */ ++ if (vtpms->current_response || ++ 0 != (vtpms->flags & DATAEX_FLAG_QUEUED_ONLY)) { ++ rc = STATUS_DATA_AVAIL; ++ } else if (!vtpms->current_response && !vtpms->current_request) { ++ rc = STATUS_READY; ++ } ++ ++ spin_unlock_irqrestore(&vtpms->resp_list_lock, flags); ++ return rc; ++} ++ ++static struct file_operations vtpm_ops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .open = tpm_open, ++ .read = tpm_read, ++ .write = tpm_write, ++ .release = tpm_release, ++}; ++ ++static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); ++static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); ++static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); ++static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); ++static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); ++static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, ++ NULL); ++static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); ++static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); ++ ++static struct attribute *vtpm_attrs[] = { ++ &dev_attr_pubek.attr, ++ &dev_attr_pcrs.attr, ++ &dev_attr_enabled.attr, ++ &dev_attr_active.attr, ++ &dev_attr_owned.attr, ++ &dev_attr_temp_deactivated.attr, ++ &dev_attr_caps.attr, ++ &dev_attr_cancel.attr, ++ NULL, ++}; ++ ++static struct attribute_group vtpm_attr_grp = { .attrs = vtpm_attrs }; ++ ++#define TPM_LONG_TIMEOUT (10 * 60 * HZ) ++ ++static struct tpm_vendor_specific tpm_vtpm = { ++ .recv = vtpm_recv, ++ .send = vtpm_send, ++ .cancel = vtpm_cancel, ++ .status = vtpm_status, ++ .req_complete_mask = STATUS_BUSY | STATUS_DATA_AVAIL, ++ .req_complete_val = STATUS_DATA_AVAIL, ++ .req_canceled = STATUS_READY, ++ .attr_group = &vtpm_attr_grp, ++ .miscdev = { ++ .fops = &vtpm_ops, ++ }, ++ .duration = { ++ TPM_LONG_TIMEOUT, ++ TPM_LONG_TIMEOUT, ++ TPM_LONG_TIMEOUT, ++ }, ++}; ++ ++struct tpm_chip *init_vtpm(struct device *dev, ++ struct tpm_private *tp) ++{ ++ long rc; ++ struct tpm_chip *chip; ++ struct vtpm_state *vtpms; ++ ++ vtpms = kzalloc(sizeof(struct vtpm_state), GFP_KERNEL); ++ if (!vtpms) ++ return ERR_PTR(-ENOMEM); ++ ++ vtpm_state_init(vtpms); ++ vtpms->tpm_private = tp; ++ ++ chip = tpm_register_hardware(dev, &tpm_vtpm); ++ if (!chip) { ++ rc = -ENODEV; ++ goto err_free_mem; ++ } ++ ++ chip_set_private(chip, vtpms); ++ ++ return chip; ++ ++err_free_mem: ++ kfree(vtpms); ++ ++ return ERR_PTR(rc); ++} ++ ++void cleanup_vtpm(struct device *dev) ++{ ++ struct tpm_chip *chip = dev_get_drvdata(dev); ++ struct vtpm_state *vtpms = (struct vtpm_state*)chip_get_private(chip); ++ tpm_remove_hardware(dev); ++ kfree(vtpms); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/tpm_vtpm.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/char/tpm/tpm_vtpm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,55 @@ ++#ifndef TPM_VTPM_H ++#define TPM_VTPM_H ++ ++struct tpm_chip; ++struct tpm_private; ++ ++struct vtpm_state { ++ struct transmission *current_request; ++ spinlock_t req_list_lock; ++ wait_queue_head_t req_wait_queue; ++ ++ struct list_head queued_requests; ++ ++ struct transmission *current_response; ++ spinlock_t resp_list_lock; ++ wait_queue_head_t resp_wait_queue; // processes waiting for responses ++ ++ u8 vd_status; ++ u8 flags; ++ ++ unsigned long disconnect_time; ++ ++ /* ++ * The following is a private structure of the underlying ++ * driver. It is passed as parameter in the send function. ++ */ ++ struct tpm_private *tpm_private; ++}; ++ ++ ++enum vdev_status { ++ TPM_VD_STATUS_DISCONNECTED = 0x0, ++ TPM_VD_STATUS_CONNECTED = 0x1 ++}; ++ ++/* this function is called from tpm_vtpm.c */ ++int vtpm_vd_send(struct tpm_private * tp, ++ const u8 * buf, size_t count, void *ptr); ++ ++/* these functions are offered by tpm_vtpm.c */ ++struct tpm_chip *init_vtpm(struct device *, ++ struct tpm_private *); ++void cleanup_vtpm(struct device *); ++int vtpm_vd_recv(const struct tpm_chip* chip, ++ const unsigned char *buffer, size_t count, void *ptr); ++void vtpm_vd_status(const struct tpm_chip *, u8 status); ++ ++static inline struct tpm_private *tpm_private_from_dev(struct device *dev) ++{ ++ struct tpm_chip *chip = dev_get_drvdata(dev); ++ struct vtpm_state *vtpms = chip_get_private(chip); ++ return vtpms->tpm_private; ++} ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/char/tpm/tpm_xen.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/char/tpm/tpm_xen.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,720 @@ ++/* ++ * Copyright (c) 2005, IBM Corporation ++ * ++ * Author: Stefan Berger, stefanb@us.ibm.com ++ * Grant table support: Mahadevan Gomathisankaran ++ * ++ * This code has been derived from drivers/xen/netfront/netfront.c ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/errno.h> ++#include <linux/err.h> ++#include <linux/interrupt.h> ++#include <linux/mutex.h> ++#include <asm/uaccess.h> ++#include <xen/evtchn.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/io/tpmif.h> ++#include <xen/gnttab.h> ++#include <xen/xenbus.h> ++#include "tpm.h" ++#include "tpm_vtpm.h" ++ ++#undef DEBUG ++ ++/* local structures */ ++struct tpm_private { ++ struct tpm_chip *chip; ++ ++ tpmif_tx_interface_t *tx; ++ atomic_t refcnt; ++ unsigned int irq; ++ u8 is_connected; ++ u8 is_suspended; ++ ++ spinlock_t tx_lock; ++ ++ struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE]; ++ ++ atomic_t tx_busy; ++ void *tx_remember; ++ ++ domid_t backend_id; ++ wait_queue_head_t wait_q; ++ ++ struct xenbus_device *dev; ++ int ring_ref; ++}; ++ ++struct tx_buffer { ++ unsigned int size; // available space in data ++ unsigned int len; // used space in data ++ unsigned char *data; // pointer to a page ++}; ++ ++ ++/* locally visible variables */ ++static grant_ref_t gref_head; ++static struct tpm_private *my_priv; ++ ++/* local function prototypes */ ++static irqreturn_t tpmif_int(int irq, ++ void *tpm_priv, ++ struct pt_regs *ptregs); ++static void tpmif_rx_action(unsigned long unused); ++static int tpmif_connect(struct xenbus_device *dev, ++ struct tpm_private *tp, ++ domid_t domid); ++static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0); ++static int tpmif_allocate_tx_buffers(struct tpm_private *tp); ++static void tpmif_free_tx_buffers(struct tpm_private *tp); ++static void tpmif_set_connected_state(struct tpm_private *tp, ++ u8 newstate); ++static int tpm_xmit(struct tpm_private *tp, ++ const u8 * buf, size_t count, int userbuffer, ++ void *remember); ++static void destroy_tpmring(struct tpm_private *tp); ++void __exit tpmif_exit(void); ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args) ++#define IPRINTK(fmt, args...) \ ++ printk(KERN_INFO "xen_tpm_fr: " fmt, ##args) ++#define WPRINTK(fmt, args...) \ ++ printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args) ++ ++#define GRANT_INVALID_REF 0 ++ ++ ++static inline int ++tx_buffer_copy(struct tx_buffer *txb, const u8 *src, int len, ++ int isuserbuffer) ++{ ++ int copied = len; ++ ++ if (len > txb->size) ++ copied = txb->size; ++ if (isuserbuffer) { ++ if (copy_from_user(txb->data, src, copied)) ++ return -EFAULT; ++ } else { ++ memcpy(txb->data, src, copied); ++ } ++ txb->len = len; ++ return copied; ++} ++ ++static inline struct tx_buffer *tx_buffer_alloc(void) ++{ ++ struct tx_buffer *txb; ++ ++ txb = kzalloc(sizeof(struct tx_buffer), GFP_KERNEL); ++ if (!txb) ++ return NULL; ++ ++ txb->len = 0; ++ txb->size = PAGE_SIZE; ++ txb->data = (unsigned char *)__get_free_page(GFP_KERNEL); ++ if (txb->data == NULL) { ++ kfree(txb); ++ txb = NULL; ++ } ++ ++ return txb; ++} ++ ++ ++static inline void tx_buffer_free(struct tx_buffer *txb) ++{ ++ if (txb) { ++ free_page((long)txb->data); ++ kfree(txb); ++ } ++} ++ ++/************************************************************** ++ Utility function for the tpm_private structure ++**************************************************************/ ++static void tpm_private_init(struct tpm_private *tp) ++{ ++ spin_lock_init(&tp->tx_lock); ++ init_waitqueue_head(&tp->wait_q); ++ atomic_set(&tp->refcnt, 1); ++} ++ ++static void tpm_private_put(void) ++{ ++ if (!atomic_dec_and_test(&my_priv->refcnt)) ++ return; ++ ++ tpmif_free_tx_buffers(my_priv); ++ kfree(my_priv); ++ my_priv = NULL; ++} ++ ++static struct tpm_private *tpm_private_get(void) ++{ ++ int err; ++ ++ if (my_priv) { ++ atomic_inc(&my_priv->refcnt); ++ return my_priv; ++ } ++ ++ my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL); ++ if (!my_priv) ++ return NULL; ++ ++ tpm_private_init(my_priv); ++ err = tpmif_allocate_tx_buffers(my_priv); ++ if (err < 0) ++ tpm_private_put(); ++ ++ return my_priv; ++} ++ ++/************************************************************** ++ ++ The interface to let the tpm plugin register its callback ++ function and send data to another partition using this module ++ ++**************************************************************/ ++ ++static DEFINE_MUTEX(suspend_lock); ++/* ++ * Send data via this module by calling this function ++ */ ++int vtpm_vd_send(struct tpm_private *tp, ++ const u8 * buf, size_t count, void *ptr) ++{ ++ int sent; ++ ++ mutex_lock(&suspend_lock); ++ sent = tpm_xmit(tp, buf, count, 0, ptr); ++ mutex_unlock(&suspend_lock); ++ ++ return sent; ++} ++ ++/************************************************************** ++ XENBUS support code ++**************************************************************/ ++ ++static int setup_tpmring(struct xenbus_device *dev, ++ struct tpm_private *tp) ++{ ++ tpmif_tx_interface_t *sring; ++ int err; ++ ++ tp->ring_ref = GRANT_INVALID_REF; ++ ++ sring = (void *)__get_free_page(GFP_KERNEL); ++ if (!sring) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); ++ return -ENOMEM; ++ } ++ tp->tx = sring; ++ ++ err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx)); ++ if (err < 0) { ++ free_page((unsigned long)sring); ++ tp->tx = NULL; ++ xenbus_dev_fatal(dev, err, "allocating grant reference"); ++ goto fail; ++ } ++ tp->ring_ref = err; ++ ++ err = tpmif_connect(dev, tp, dev->otherend_id); ++ if (err) ++ goto fail; ++ ++ return 0; ++fail: ++ destroy_tpmring(tp); ++ return err; ++} ++ ++ ++static void destroy_tpmring(struct tpm_private *tp) ++{ ++ tpmif_set_connected_state(tp, 0); ++ ++ if (tp->ring_ref != GRANT_INVALID_REF) { ++ gnttab_end_foreign_access(tp->ring_ref, 0, ++ (unsigned long)tp->tx); ++ tp->ring_ref = GRANT_INVALID_REF; ++ tp->tx = NULL; ++ } ++ ++ if (tp->irq) ++ unbind_from_irqhandler(tp->irq, tp); ++ ++ tp->irq = 0; ++} ++ ++ ++static int talk_to_backend(struct xenbus_device *dev, ++ struct tpm_private *tp) ++{ ++ const char *message = NULL; ++ int err; ++ struct xenbus_transaction xbt; ++ ++ err = setup_tpmring(dev, tp); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "setting up ring"); ++ goto out; ++ } ++ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ goto destroy_tpmring; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, ++ "ring-ref","%u", tp->ring_ref); ++ if (err) { ++ message = "writing ring-ref"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", ++ irq_to_evtchn_port(tp->irq)); ++ if (err) { ++ message = "writing event-channel"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ if (err) { ++ xenbus_dev_fatal(dev, err, "completing transaction"); ++ goto destroy_tpmring; ++ } ++ ++ xenbus_switch_state(dev, XenbusStateConnected); ++ ++ return 0; ++ ++abort_transaction: ++ xenbus_transaction_end(xbt, 1); ++ if (message) ++ xenbus_dev_error(dev, err, "%s", message); ++destroy_tpmring: ++ destroy_tpmring(tp); ++out: ++ return err; ++} ++ ++/** ++ * Callback received when the backend's state changes. ++ */ ++static void backend_changed(struct xenbus_device *dev, ++ enum xenbus_state backend_state) ++{ ++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev); ++ DPRINTK("\n"); ++ ++ switch (backend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitWait: ++ case XenbusStateInitialised: ++ case XenbusStateUnknown: ++ break; ++ ++ case XenbusStateConnected: ++ tpmif_set_connected_state(tp, 1); ++ break; ++ ++ case XenbusStateClosing: ++ tpmif_set_connected_state(tp, 0); ++ xenbus_frontend_closed(dev); ++ break; ++ ++ case XenbusStateClosed: ++ tpmif_set_connected_state(tp, 0); ++ if (tp->is_suspended == 0) ++ device_unregister(&dev->dev); ++ xenbus_frontend_closed(dev); ++ break; ++ } ++} ++ ++static int tpmfront_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ int handle; ++ struct tpm_private *tp = tpm_private_get(); ++ ++ if (!tp) ++ return -ENOMEM; ++ ++ tp->chip = init_vtpm(&dev->dev, tp); ++ if (IS_ERR(tp->chip)) ++ return PTR_ERR(tp->chip); ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, ++ "handle", "%i", &handle); ++ if (XENBUS_EXIST_ERR(err)) ++ return err; ++ ++ if (err < 0) { ++ xenbus_dev_fatal(dev,err,"reading virtual-device"); ++ return err; ++ } ++ ++ tp->dev = dev; ++ ++ err = talk_to_backend(dev, tp); ++ if (err) { ++ tpm_private_put(); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++static int tpmfront_remove(struct xenbus_device *dev) ++{ ++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev); ++ destroy_tpmring(tp); ++ cleanup_vtpm(&dev->dev); ++ return 0; ++} ++ ++static int tpmfront_suspend(struct xenbus_device *dev) ++{ ++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev); ++ u32 ctr; ++ ++ /* Take the lock, preventing any application from sending. */ ++ mutex_lock(&suspend_lock); ++ tp->is_suspended = 1; ++ ++ for (ctr = 0; atomic_read(&tp->tx_busy); ctr++) { ++ if ((ctr % 10) == 0) ++ printk("TPM-FE [INFO]: Waiting for outstanding " ++ "request.\n"); ++ /* Wait for a request to be responded to. */ ++ interruptible_sleep_on_timeout(&tp->wait_q, 100); ++ } ++ ++ return 0; ++} ++ ++static int tpmfront_suspend_finish(struct tpm_private *tp) ++{ ++ tp->is_suspended = 0; ++ /* Allow applications to send again. */ ++ mutex_unlock(&suspend_lock); ++ return 0; ++} ++ ++static int tpmfront_suspend_cancel(struct xenbus_device *dev) ++{ ++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev); ++ return tpmfront_suspend_finish(tp); ++} ++ ++static int tpmfront_resume(struct xenbus_device *dev) ++{ ++ struct tpm_private *tp = tpm_private_from_dev(&dev->dev); ++ destroy_tpmring(tp); ++ return talk_to_backend(dev, tp); ++} ++ ++static int tpmif_connect(struct xenbus_device *dev, ++ struct tpm_private *tp, ++ domid_t domid) ++{ ++ int err; ++ ++ tp->backend_id = domid; ++ ++ err = bind_listening_port_to_irqhandler( ++ domid, tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp); ++ if (err <= 0) { ++ WPRINTK("bind_listening_port_to_irqhandler failed " ++ "(err=%d)\n", err); ++ return err; ++ } ++ tp->irq = err; ++ ++ return 0; ++} ++ ++static struct xenbus_device_id tpmfront_ids[] = { ++ { "vtpm" }, ++ { "" } ++}; ++ ++static struct xenbus_driver tpmfront = { ++ .name = "vtpm", ++ .owner = THIS_MODULE, ++ .ids = tpmfront_ids, ++ .probe = tpmfront_probe, ++ .remove = tpmfront_remove, ++ .resume = tpmfront_resume, ++ .otherend_changed = backend_changed, ++ .suspend = tpmfront_suspend, ++ .suspend_cancel = tpmfront_suspend_cancel, ++}; ++ ++static void __init init_tpm_xenbus(void) ++{ ++ xenbus_register_frontend(&tpmfront); ++} ++ ++static int tpmif_allocate_tx_buffers(struct tpm_private *tp) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < TPMIF_TX_RING_SIZE; i++) { ++ tp->tx_buffers[i] = tx_buffer_alloc(); ++ if (!tp->tx_buffers[i]) { ++ tpmif_free_tx_buffers(tp); ++ return -ENOMEM; ++ } ++ } ++ return 0; ++} ++ ++static void tpmif_free_tx_buffers(struct tpm_private *tp) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < TPMIF_TX_RING_SIZE; i++) ++ tx_buffer_free(tp->tx_buffers[i]); ++} ++ ++static void tpmif_rx_action(unsigned long priv) ++{ ++ struct tpm_private *tp = (struct tpm_private *)priv; ++ int i = 0; ++ unsigned int received; ++ unsigned int offset = 0; ++ u8 *buffer; ++ tpmif_tx_request_t *tx = &tp->tx->ring[i].req; ++ ++ atomic_set(&tp->tx_busy, 0); ++ wake_up_interruptible(&tp->wait_q); ++ ++ received = tx->size; ++ ++ buffer = kmalloc(received, GFP_ATOMIC); ++ if (!buffer) ++ return; ++ ++ for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) { ++ struct tx_buffer *txb = tp->tx_buffers[i]; ++ tpmif_tx_request_t *tx; ++ unsigned int tocopy; ++ ++ tx = &tp->tx->ring[i].req; ++ tocopy = tx->size; ++ if (tocopy > PAGE_SIZE) ++ tocopy = PAGE_SIZE; ++ ++ memcpy(&buffer[offset], txb->data, tocopy); ++ ++ gnttab_release_grant_reference(&gref_head, tx->ref); ++ ++ offset += tocopy; ++ } ++ ++ vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember); ++ kfree(buffer); ++} ++ ++ ++static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) ++{ ++ struct tpm_private *tp = tpm_priv; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tp->tx_lock, flags); ++ tpmif_rx_tasklet.data = (unsigned long)tp; ++ tasklet_schedule(&tpmif_rx_tasklet); ++ spin_unlock_irqrestore(&tp->tx_lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static int tpm_xmit(struct tpm_private *tp, ++ const u8 * buf, size_t count, int isuserbuffer, ++ void *remember) ++{ ++ tpmif_tx_request_t *tx; ++ TPMIF_RING_IDX i; ++ unsigned int offset = 0; ++ ++ spin_lock_irq(&tp->tx_lock); ++ ++ if (unlikely(atomic_read(&tp->tx_busy))) { ++ printk("tpm_xmit: There's an outstanding request/response " ++ "on the way!\n"); ++ spin_unlock_irq(&tp->tx_lock); ++ return -EBUSY; ++ } ++ ++ if (tp->is_connected != 1) { ++ spin_unlock_irq(&tp->tx_lock); ++ return -EIO; ++ } ++ ++ for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) { ++ struct tx_buffer *txb = tp->tx_buffers[i]; ++ int copied; ++ ++ if (!txb) { ++ DPRINTK("txb (i=%d) is NULL. buffers initilized?\n" ++ "Not transmitting anything!\n", i); ++ spin_unlock_irq(&tp->tx_lock); ++ return -EFAULT; ++ } ++ ++ copied = tx_buffer_copy(txb, &buf[offset], count, ++ isuserbuffer); ++ if (copied < 0) { ++ /* An error occurred */ ++ spin_unlock_irq(&tp->tx_lock); ++ return copied; ++ } ++ count -= copied; ++ offset += copied; ++ ++ tx = &tp->tx->ring[i].req; ++ tx->addr = virt_to_machine(txb->data); ++ tx->size = txb->len; ++ ++ DPRINTK("First 4 characters sent by TPM-FE are " ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ txb->data[0],txb->data[1],txb->data[2],txb->data[3]); ++ ++ /* Get the granttable reference for this page. */ ++ tx->ref = gnttab_claim_grant_reference(&gref_head); ++ if (tx->ref == -ENOSPC) { ++ spin_unlock_irq(&tp->tx_lock); ++ DPRINTK("Grant table claim reference failed in " ++ "func:%s line:%d file:%s\n", ++ __FUNCTION__, __LINE__, __FILE__); ++ return -ENOSPC; ++ } ++ gnttab_grant_foreign_access_ref(tx->ref, ++ tp->backend_id, ++ virt_to_mfn(txb->data), ++ 0 /*RW*/); ++ wmb(); ++ } ++ ++ atomic_set(&tp->tx_busy, 1); ++ tp->tx_remember = remember; ++ ++ mb(); ++ ++ notify_remote_via_irq(tp->irq); ++ ++ spin_unlock_irq(&tp->tx_lock); ++ return offset; ++} ++ ++ ++static void tpmif_notify_upperlayer(struct tpm_private *tp) ++{ ++ /* Notify upper layer about the state of the connection to the BE. */ ++ vtpm_vd_status(tp->chip, (tp->is_connected ++ ? TPM_VD_STATUS_CONNECTED ++ : TPM_VD_STATUS_DISCONNECTED)); ++} ++ ++ ++static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected) ++{ ++ /* ++ * Don't notify upper layer if we are in suspend mode and ++ * should disconnect - assumption is that we will resume ++ * The mutex keeps apps from sending. ++ */ ++ if (is_connected == 0 && tp->is_suspended == 1) ++ return; ++ ++ /* ++ * Unlock the mutex if we are connected again ++ * after being suspended - now resuming. ++ * This also removes the suspend state. ++ */ ++ if (is_connected == 1 && tp->is_suspended == 1) ++ tpmfront_suspend_finish(tp); ++ ++ if (is_connected != tp->is_connected) { ++ tp->is_connected = is_connected; ++ tpmif_notify_upperlayer(tp); ++ } ++} ++ ++ ++ ++/* ================================================================= ++ * Initialization function. ++ * ================================================================= ++ */ ++ ++ ++static int __init tpmif_init(void) ++{ ++ struct tpm_private *tp; ++ ++ if (is_initial_xendomain()) ++ return -EPERM; ++ ++ tp = tpm_private_get(); ++ if (!tp) ++ return -ENOMEM; ++ ++ IPRINTK("Initialising the vTPM driver.\n"); ++ if (gnttab_alloc_grant_references(TPMIF_TX_RING_SIZE, ++ &gref_head) < 0) { ++ tpm_private_put(); ++ return -EFAULT; ++ } ++ ++ init_tpm_xenbus(); ++ return 0; ++} ++ ++ ++module_init(tpmif_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/firmware/Kconfig +--- a/drivers/firmware/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/firmware/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -8,6 +8,7 @@ config EDD + config EDD + tristate "BIOS Enhanced Disk Drive calls determine boot disk" + depends on !IA64 ++ depends on !XEN + help + Say Y or M here if you want to enable BIOS Enhanced Disk Drive + Services real mode BIOS calls to determine which disk +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/ide/ide-lib.c +--- a/drivers/ide/ide-lib.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/ide/ide-lib.c Wed Aug 08 16:25:28 2007 -0300 +@@ -429,10 +429,10 @@ void ide_toggle_bounce(ide_drive_t *driv + { + u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ + +- if (!PCI_DMA_BUS_IS_PHYS) { +- addr = BLK_BOUNCE_ANY; +- } else if (on && drive->media == ide_disk) { +- if (HWIF(drive)->pci_dev) ++ if (on && drive->media == ide_disk) { ++ if (!PCI_DMA_BUS_IS_PHYS) ++ addr = BLK_BOUNCE_ANY; ++ else if (HWIF(drive)->pci_dev) + addr = HWIF(drive)->pci_dev->dma_mask; + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/buffer_sync.c +--- a/drivers/oprofile/buffer_sync.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/buffer_sync.c Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,10 @@ + * @remark Read the file COPYING + * + * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. + * + * This is the core of the buffer management. Each + * CPU buffer is processed and entered into the +@@ -275,15 +279,31 @@ static void add_cpu_switch(int i) + last_cookie = INVALID_COOKIE; + } + +-static void add_kernel_ctx_switch(unsigned int in_kernel) +-{ +- add_event_entry(ESCAPE_CODE); +- if (in_kernel) +- add_event_entry(KERNEL_ENTER_SWITCH_CODE); +- else +- add_event_entry(KERNEL_EXIT_SWITCH_CODE); +-} +- ++static void add_cpu_mode_switch(unsigned int cpu_mode) ++{ ++ add_event_entry(ESCAPE_CODE); ++ switch (cpu_mode) { ++ case CPU_MODE_USER: ++ add_event_entry(USER_ENTER_SWITCH_CODE); ++ break; ++ case CPU_MODE_KERNEL: ++ add_event_entry(KERNEL_ENTER_SWITCH_CODE); ++ break; ++ case CPU_MODE_XEN: ++ add_event_entry(XEN_ENTER_SWITCH_CODE); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void add_domain_switch(unsigned long domain_id) ++{ ++ add_event_entry(ESCAPE_CODE); ++ add_event_entry(DOMAIN_SWITCH_CODE); ++ add_event_entry(domain_id); ++} ++ + static void + add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) + { +@@ -348,9 +368,9 @@ static int add_us_sample(struct mm_struc + * for later lookup from userspace. + */ + static int +-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel) +-{ +- if (in_kernel) { ++add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode) ++{ ++ if (cpu_mode >= CPU_MODE_KERNEL) { + add_sample_entry(s->eip, s->event); + return 1; + } else if (mm) { +@@ -496,10 +516,11 @@ void sync_buffer(int cpu) + struct mm_struct *mm = NULL; + struct task_struct * new; + unsigned long cookie = 0; +- int in_kernel = 1; ++ int cpu_mode = 1; + unsigned int i; + sync_buffer_state state = sb_buffer_start; + unsigned long available; ++ int domain_switch = 0; + + mutex_lock(&buffer_mutex); + +@@ -512,16 +533,18 @@ void sync_buffer(int cpu) + for (i = 0; i < available; ++i) { + struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos]; + +- if (is_code(s->eip)) { +- if (s->event <= CPU_IS_KERNEL) { +- /* kernel/userspace switch */ +- in_kernel = s->event; ++ if (is_code(s->eip) && !domain_switch) { ++ if (s->event <= CPU_MODE_XEN) { ++ /* xen/kernel/userspace switch */ ++ cpu_mode = s->event; + if (state == sb_buffer_start) + state = sb_sample_start; +- add_kernel_ctx_switch(s->event); ++ add_cpu_mode_switch(s->event); + } else if (s->event == CPU_TRACE_BEGIN) { + state = sb_bt_start; + add_trace_begin(); ++ } else if (s->event == CPU_DOMAIN_SWITCH) { ++ domain_switch = 1; + } else { + struct mm_struct * oldmm = mm; + +@@ -535,11 +558,16 @@ void sync_buffer(int cpu) + add_user_ctx_switch(new, cookie); + } + } else { +- if (state >= sb_bt_start && +- !add_sample(mm, s, in_kernel)) { +- if (state == sb_bt_start) { +- state = sb_bt_ignore; +- atomic_inc(&oprofile_stats.bt_lost_no_mapping); ++ if (domain_switch) { ++ add_domain_switch(s->eip); ++ domain_switch = 0; ++ } else { ++ if (state >= sb_bt_start && ++ !add_sample(mm, s, cpu_mode)) { ++ if (state == sb_bt_start) { ++ state = sb_bt_ignore; ++ atomic_inc(&oprofile_stats.bt_lost_no_mapping); ++ } + } + } + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/cpu_buffer.c +--- a/drivers/oprofile/cpu_buffer.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/cpu_buffer.c Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,10 @@ + * @remark Read the file COPYING + * + * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. + * + * Each CPU has a local buffer that stores PC value/event + * pairs. We also log context switches when we notice them. +@@ -34,6 +38,8 @@ static void wq_sync_buffer(struct work_s + #define DEFAULT_TIMER_EXPIRE (HZ / 10) + static int work_enabled; + ++static int32_t current_domain = COORDINATOR_DOMAIN; ++ + void free_cpu_buffers(void) + { + int i; +@@ -57,7 +63,7 @@ int alloc_cpu_buffers(void) + goto fail; + + b->last_task = NULL; +- b->last_is_kernel = -1; ++ b->last_cpu_mode = -1; + b->tracing = 0; + b->buffer_size = buffer_size; + b->tail_pos = 0; +@@ -113,7 +119,7 @@ void cpu_buffer_reset(struct oprofile_cp + * collected will populate the buffer with proper + * values to initialize the buffer + */ +- cpu_buf->last_is_kernel = -1; ++ cpu_buf->last_cpu_mode = -1; + cpu_buf->last_task = NULL; + } + +@@ -163,13 +169,13 @@ add_code(struct oprofile_cpu_buffer * bu + * because of the head/tail separation of the writer and reader + * of the CPU buffer. + * +- * is_kernel is needed because on some architectures you cannot ++ * cpu_mode is needed because on some architectures you cannot + * tell if you are in kernel or user space simply by looking at +- * pc. We tag this in the buffer by generating kernel enter/exit +- * events whenever is_kernel changes ++ * pc. We tag this in the buffer by generating kernel/user (and xen) ++ * enter events whenever cpu_mode changes + */ + static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc, +- int is_kernel, unsigned long event) ++ int cpu_mode, unsigned long event) + { + struct task_struct * task; + +@@ -180,18 +186,20 @@ static int log_sample(struct oprofile_cp + return 0; + } + +- is_kernel = !!is_kernel; ++ WARN_ON(cpu_mode > CPU_MODE_XEN); + + task = current; + + /* notice a switch from user->kernel or vice versa */ +- if (cpu_buf->last_is_kernel != is_kernel) { +- cpu_buf->last_is_kernel = is_kernel; +- add_code(cpu_buf, is_kernel); +- } +- ++ if (cpu_buf->last_cpu_mode != cpu_mode) { ++ cpu_buf->last_cpu_mode = cpu_mode; ++ add_code(cpu_buf, cpu_mode); ++ } ++ + /* notice a task switch */ +- if (cpu_buf->last_task != task) { ++ /* if not processing other domain samples */ ++ if ((cpu_buf->last_task != task) && ++ (current_domain == COORDINATOR_DOMAIN)) { + cpu_buf->last_task = task; + add_code(cpu_buf, (unsigned long)task); + } +@@ -275,6 +283,25 @@ void oprofile_add_trace(unsigned long pc + add_sample(cpu_buf, pc, 0); + } + ++int oprofile_add_domain_switch(int32_t domain_id) ++{ ++ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; ++ ++ /* should have space for switching into and out of domain ++ (2 slots each) plus one sample and one cpu mode switch */ ++ if (((nr_available_slots(cpu_buf) < 6) && ++ (domain_id != COORDINATOR_DOMAIN)) || ++ (nr_available_slots(cpu_buf) < 2)) ++ return 0; ++ ++ add_code(cpu_buf, CPU_DOMAIN_SWITCH); ++ add_sample(cpu_buf, domain_id, 0); ++ ++ current_domain = domain_id; ++ ++ return 1; ++} ++ + /* + * This serves to avoid cpu buffer overflow, and makes sure + * the task mortuary progresses +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/cpu_buffer.h +--- a/drivers/oprofile/cpu_buffer.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/cpu_buffer.h Wed Aug 08 16:25:28 2007 -0300 +@@ -36,7 +36,7 @@ struct oprofile_cpu_buffer { + volatile unsigned long tail_pos; + unsigned long buffer_size; + struct task_struct * last_task; +- int last_is_kernel; ++ int last_cpu_mode; + int tracing; + struct op_sample * buffer; + unsigned long sample_received; +@@ -51,7 +51,10 @@ void cpu_buffer_reset(struct oprofile_cp + void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf); + + /* transient events for the CPU buffer -> event buffer */ +-#define CPU_IS_KERNEL 1 +-#define CPU_TRACE_BEGIN 2 ++#define CPU_MODE_USER 0 ++#define CPU_MODE_KERNEL 1 ++#define CPU_MODE_XEN 2 ++#define CPU_TRACE_BEGIN 3 ++#define CPU_DOMAIN_SWITCH 4 + + #endif /* OPROFILE_CPU_BUFFER_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/event_buffer.h +--- a/drivers/oprofile/event_buffer.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/event_buffer.h Wed Aug 08 16:25:28 2007 -0300 +@@ -29,14 +29,19 @@ void wake_up_buffer_waiter(void); + #define CPU_SWITCH_CODE 2 + #define COOKIE_SWITCH_CODE 3 + #define KERNEL_ENTER_SWITCH_CODE 4 +-#define KERNEL_EXIT_SWITCH_CODE 5 ++#define USER_ENTER_SWITCH_CODE 5 + #define MODULE_LOADED_CODE 6 + #define CTX_TGID_CODE 7 + #define TRACE_BEGIN_CODE 8 + #define TRACE_END_CODE 9 ++#define XEN_ENTER_SWITCH_CODE 10 ++#define DOMAIN_SWITCH_CODE 11 + + #define INVALID_COOKIE ~0UL + #define NO_COOKIE 0UL ++ ++/* Constant used to refer to coordinator domain (Xen) */ ++#define COORDINATOR_DOMAIN -1 + + /* add data to the event buffer */ + void add_event_entry(unsigned long data); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/oprof.c +--- a/drivers/oprofile/oprof.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/oprof.c Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,10 @@ + * @remark Read the file COPYING + * + * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. + */ + + #include <linux/kernel.h> +@@ -19,7 +23,7 @@ + #include "cpu_buffer.h" + #include "buffer_sync.h" + #include "oprofile_stats.h" +- ++ + struct oprofile_operations oprofile_ops; + + unsigned long oprofile_started; +@@ -32,6 +36,32 @@ static DEFINE_MUTEX(start_mutex); + 1 - use the timer int mechanism regardless + */ + static int timer = 0; ++ ++int oprofile_set_active(int active_domains[], unsigned int adomains) ++{ ++ int err; ++ ++ if (!oprofile_ops.set_active) ++ return -EINVAL; ++ ++ mutex_lock(&start_mutex); ++ err = oprofile_ops.set_active(active_domains, adomains); ++ mutex_unlock(&start_mutex); ++ return err; ++} ++ ++int oprofile_set_passive(int passive_domains[], unsigned int pdomains) ++{ ++ int err; ++ ++ if (!oprofile_ops.set_passive) ++ return -EINVAL; ++ ++ mutex_lock(&start_mutex); ++ err = oprofile_ops.set_passive(passive_domains, pdomains); ++ mutex_unlock(&start_mutex); ++ return err; ++} + + int oprofile_setup(void) + { +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/oprof.h +--- a/drivers/oprofile/oprof.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/oprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -35,5 +35,8 @@ void oprofile_timer_init(struct oprofile + void oprofile_timer_init(struct oprofile_operations * ops); + + int oprofile_set_backtrace(unsigned long depth); ++ ++int oprofile_set_active(int active_domains[], unsigned int adomains); ++int oprofile_set_passive(int passive_domains[], unsigned int pdomains); + + #endif /* OPROF_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/oprofile/oprofile_files.c +--- a/drivers/oprofile/oprofile_files.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/oprofile/oprofile_files.c Wed Aug 08 16:25:28 2007 -0300 +@@ -5,15 +5,21 @@ + * @remark Read the file COPYING + * + * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. + */ + + #include <linux/fs.h> + #include <linux/oprofile.h> ++#include <asm/uaccess.h> ++#include <linux/ctype.h> + + #include "event_buffer.h" + #include "oprofile_stats.h" + #include "oprof.h" +- ++ + unsigned long fs_buffer_size = 131072; + unsigned long fs_cpu_buffer_size = 8192; + unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ +@@ -117,11 +123,208 @@ static struct file_operations dump_fops + static struct file_operations dump_fops = { + .write = dump_write, + }; +- ++ ++#ifdef CONFIG_XEN ++ ++#define TMPBUFSIZE 512 ++ ++static unsigned int adomains = 0; ++static int active_domains[MAX_OPROF_DOMAINS + 1]; ++static DEFINE_MUTEX(adom_mutex); ++ ++static ssize_t adomain_write(struct file * file, char const __user * buf, ++ size_t count, loff_t * offset) ++{ ++ char *tmpbuf; ++ char *startp, *endp; ++ int i; ++ unsigned long val; ++ ssize_t retval = count; ++ ++ if (*offset) ++ return -EINVAL; ++ if (count > TMPBUFSIZE - 1) ++ return -EINVAL; ++ ++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ if (copy_from_user(tmpbuf, buf, count)) { ++ kfree(tmpbuf); ++ return -EFAULT; ++ } ++ tmpbuf[count] = 0; ++ ++ mutex_lock(&adom_mutex); ++ ++ startp = tmpbuf; ++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */ ++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) { ++ val = simple_strtoul(startp, &endp, 0); ++ if (endp == startp) ++ break; ++ while (ispunct(*endp) || isspace(*endp)) ++ endp++; ++ active_domains[i] = val; ++ if (active_domains[i] != val) ++ /* Overflow, force error below */ ++ i = MAX_OPROF_DOMAINS + 1; ++ startp = endp; ++ } ++ /* Force error on trailing junk */ ++ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i; ++ ++ kfree(tmpbuf); ++ ++ if (adomains > MAX_OPROF_DOMAINS ++ || oprofile_set_active(active_domains, adomains)) { ++ adomains = 0; ++ retval = -EINVAL; ++ } ++ ++ mutex_unlock(&adom_mutex); ++ return retval; ++} ++ ++static ssize_t adomain_read(struct file * file, char __user * buf, ++ size_t count, loff_t * offset) ++{ ++ char * tmpbuf; ++ size_t len; ++ int i; ++ ssize_t retval; ++ ++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ mutex_lock(&adom_mutex); ++ ++ len = 0; ++ for (i = 0; i < adomains; i++) ++ len += snprintf(tmpbuf + len, ++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0, ++ "%u ", active_domains[i]); ++ WARN_ON(len > TMPBUFSIZE); ++ if (len != 0 && len <= TMPBUFSIZE) ++ tmpbuf[len-1] = '\n'; ++ ++ mutex_unlock(&adom_mutex); ++ ++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len); ++ ++ kfree(tmpbuf); ++ return retval; ++} ++ ++ ++static struct file_operations active_domain_ops = { ++ .read = adomain_read, ++ .write = adomain_write, ++}; ++ ++static unsigned int pdomains = 0; ++static int passive_domains[MAX_OPROF_DOMAINS]; ++static DEFINE_MUTEX(pdom_mutex); ++ ++static ssize_t pdomain_write(struct file * file, char const __user * buf, ++ size_t count, loff_t * offset) ++{ ++ char *tmpbuf; ++ char *startp, *endp; ++ int i; ++ unsigned long val; ++ ssize_t retval = count; ++ ++ if (*offset) ++ return -EINVAL; ++ if (count > TMPBUFSIZE - 1) ++ return -EINVAL; ++ ++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ if (copy_from_user(tmpbuf, buf, count)) { ++ kfree(tmpbuf); ++ return -EFAULT; ++ } ++ tmpbuf[count] = 0; ++ ++ mutex_lock(&pdom_mutex); ++ ++ startp = tmpbuf; ++ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */ ++ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) { ++ val = simple_strtoul(startp, &endp, 0); ++ if (endp == startp) ++ break; ++ while (ispunct(*endp) || isspace(*endp)) ++ endp++; ++ passive_domains[i] = val; ++ if (passive_domains[i] != val) ++ /* Overflow, force error below */ ++ i = MAX_OPROF_DOMAINS + 1; ++ startp = endp; ++ } ++ /* Force error on trailing junk */ ++ pdomains = *startp ? MAX_OPROF_DOMAINS + 1 : i; ++ ++ kfree(tmpbuf); ++ ++ if (pdomains > MAX_OPROF_DOMAINS ++ || oprofile_set_passive(passive_domains, pdomains)) { ++ pdomains = 0; ++ retval = -EINVAL; ++ } ++ ++ mutex_unlock(&pdom_mutex); ++ return retval; ++} ++ ++static ssize_t pdomain_read(struct file * file, char __user * buf, ++ size_t count, loff_t * offset) ++{ ++ char * tmpbuf; ++ size_t len; ++ int i; ++ ssize_t retval; ++ ++ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ mutex_lock(&pdom_mutex); ++ ++ len = 0; ++ for (i = 0; i < pdomains; i++) ++ len += snprintf(tmpbuf + len, ++ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0, ++ "%u ", passive_domains[i]); ++ WARN_ON(len > TMPBUFSIZE); ++ if (len != 0 && len <= TMPBUFSIZE) ++ tmpbuf[len-1] = '\n'; ++ ++ mutex_unlock(&pdom_mutex); ++ ++ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len); ++ ++ kfree(tmpbuf); ++ return retval; ++} ++ ++static struct file_operations passive_domain_ops = { ++ .read = pdomain_read, ++ .write = pdomain_write, ++}; ++ ++#endif /* CONFIG_XEN */ ++ + void oprofile_create_files(struct super_block * sb, struct dentry * root) + { + oprofilefs_create_file(sb, root, "enable", &enable_fops); + oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); ++#ifdef CONFIG_XEN ++ oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops); ++ oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops); ++#endif + oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); + oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/pci/Kconfig +--- a/drivers/pci/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/pci/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,7 @@ config PCI_MSI + bool "Message Signaled Interrupts (MSI and MSI-X)" + depends on PCI + depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 ++ depends on !XEN + help + This allows device drivers to enable MSI (Message Signaled + Interrupts). Message Signaled Interrupts enable a device to +@@ -55,7 +56,7 @@ config HT_IRQ + config HT_IRQ + bool "Interrupts on hypertransport devices" + default y +- depends on PCI && X86_LOCAL_APIC && X86_IO_APIC ++ depends on PCI && X86_LOCAL_APIC && X86_IO_APIC && !XEN + help + This allows native hypertransport devices to use interrupts. + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/serial/Kconfig +--- a/drivers/serial/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/serial/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -11,6 +11,7 @@ config SERIAL_8250 + config SERIAL_8250 + tristate "8250/16550 and compatible serial support" + depends on (BROKEN || !SPARC) ++ depends on !XEN_DISABLE_SERIAL + select SERIAL_CORE + ---help--- + This selects whether you want to include the driver for the standard +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/video/console/Kconfig +--- a/drivers/video/console/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/drivers/video/console/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -53,6 +53,7 @@ config VIDEO_SELECT + config VIDEO_SELECT + bool "Video mode selection support" + depends on X86 && VGA_CONSOLE ++ depends on !XEN + ---help--- + This enables support for text mode selection on kernel startup. If + you want to take advantage of some high-resolution text mode your +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/Kconfig +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,260 @@ ++# ++# This Kconfig describe xen options ++# ++ ++mainmenu "Xen Configuration" ++ ++config XEN ++ bool ++ default y if X86_XEN || X86_64_XEN ++ help ++ This is the Linux Xen port. ++ ++if XEN ++config XEN_INTERFACE_VERSION ++ hex ++ default 0x00030205 ++ ++menu "XEN" ++ ++config XEN_PRIVILEGED_GUEST ++ bool "Privileged Guest (domain 0)" ++ depends XEN ++ default n ++ help ++ Support for privileged operation (domain 0) ++ ++config XEN_UNPRIVILEGED_GUEST ++ bool ++ default !XEN_PRIVILEGED_GUEST ++ ++config XEN_PRIVCMD ++ bool ++ depends on PROC_FS ++ default y ++ ++config XEN_XENBUS_DEV ++ bool ++ depends on PROC_FS ++ default y ++ ++config XEN_BACKEND ++ tristate "Backend driver support" ++ default y ++ help ++ Support for backend device drivers that provide I/O services ++ to other virtual machines. ++ ++config XEN_BLKDEV_BACKEND ++ tristate "Block-device backend driver" ++ depends on XEN_BACKEND ++ default y ++ help ++ The block-device backend driver allows the kernel to export its ++ block devices to other guests via a high-performance shared-memory ++ interface. ++ ++config XEN_BLKDEV_TAP ++ tristate "Block-device tap backend driver" ++ depends on XEN_BACKEND ++ default XEN_PRIVILEGED_GUEST ++ help ++ The block tap driver is an alternative to the block back driver ++ and allows VM block requests to be redirected to userspace through ++ a device interface. The tap allows user-space development of ++ high-performance block backends, where disk images may be implemented ++ as files, in memory, or on other hosts across the network. This ++ driver can safely coexist with the existing blockback driver. ++ ++config XEN_NETDEV_BACKEND ++ tristate "Network-device backend driver" ++ depends on XEN_BACKEND && NET ++ default y ++ help ++ The network-device backend driver allows the kernel to export its ++ network devices to other guests via a high-performance shared-memory ++ interface. ++ ++config XEN_NETDEV_PIPELINED_TRANSMITTER ++ bool "Pipelined transmitter (DANGEROUS)" ++ depends on XEN_NETDEV_BACKEND ++ default n ++ help ++ If the net backend is a dumb domain, such as a transparent Ethernet ++ bridge with no local IP interface, it is safe to say Y here to get ++ slightly lower network overhead. ++ If the backend has a local IP interface; or may be doing smart things ++ like reassembling packets to perform firewall filtering; or if you ++ are unsure; or if you experience network hangs when this option is ++ enabled; then you must say N here. ++ ++config XEN_NETDEV_LOOPBACK ++ tristate "Network-device loopback driver" ++ depends on XEN_NETDEV_BACKEND ++ default y ++ help ++ A two-interface loopback device to emulate a local netfront-netback ++ connection. ++ ++config XEN_PCIDEV_BACKEND ++ tristate "PCI-device backend driver" ++ depends on PCI && XEN_BACKEND ++ default XEN_PRIVILEGED_GUEST ++ help ++ The PCI device backend driver allows the kernel to export arbitrary ++ PCI devices to other guests. If you select this to be a module, you ++ will need to make sure no other driver has bound to the device(s) ++ you want to make visible to other guests. ++ ++choice ++ prompt "PCI Backend Mode" ++ depends on XEN_PCIDEV_BACKEND ++ default XEN_PCIDEV_BACKEND_VPCI ++ ++config XEN_PCIDEV_BACKEND_VPCI ++ bool "Virtual PCI" ++ ---help--- ++ This PCI Backend hides the true PCI topology and makes the frontend ++ think there is a single PCI bus with only the exported devices on it. ++ For example, a device at 03:05.0 will be re-assigned to 00:00.0. A ++ second device at 02:1a.1 will be re-assigned to 00:01.1. ++ ++config XEN_PCIDEV_BACKEND_PASS ++ bool "Passthrough" ++ ---help--- ++ This PCI Backend provides a real view of the PCI topology to the ++ frontend (for example, a device at 06:01.b will still appear at ++ 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed ++ PCI devices to its driver domains. This may be required for drivers ++ which depend on finding their hardward in certain bus/slot ++ locations. ++ ++config XEN_PCIDEV_BACKEND_SLOT ++ bool "Slot" ++ ---help--- ++ This PCI Backend hides the true PCI topology and makes the frontend ++ think there is a single PCI bus with only the exported devices on it. ++ Contrary to the virtual PCI backend, a function becomes a new slot. ++ For example, a device at 03:05.2 will be re-assigned to 00:00.0. A ++ second device at 02:1a.1 will be re-assigned to 00:01.0. ++ ++endchoice ++ ++config XEN_PCIDEV_BE_DEBUG ++ bool "PCI Backend Debugging" ++ depends on XEN_PCIDEV_BACKEND ++ default n ++ ++config XEN_TPMDEV_BACKEND ++ tristate "TPM-device backend driver" ++ depends on XEN_BACKEND ++ default n ++ help ++ The TPM-device backend driver ++ ++config XEN_BLKDEV_FRONTEND ++ tristate "Block-device frontend driver" ++ depends on XEN ++ default y ++ help ++ The block-device frontend driver allows the kernel to access block ++ devices mounted within another guest OS. Unless you are building a ++ dedicated device-driver domain, or your master control domain ++ (domain 0), then you almost certainly want to say Y here. ++ ++config XEN_NETDEV_FRONTEND ++ tristate "Network-device frontend driver" ++ depends on XEN && NET ++ default y ++ help ++ The network-device frontend driver allows the kernel to access ++ network interfaces within another guest OS. Unless you are building a ++ dedicated device-driver domain, or your master control domain ++ (domain 0), then you almost certainly want to say Y here. ++ ++config XEN_FRAMEBUFFER ++ tristate "Framebuffer-device frontend driver" ++ depends on XEN && FB ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ default y ++ help ++ The framebuffer-device frontend drivers allows the kernel to create a ++ virtual framebuffer. This framebuffer can be viewed in another ++ domain. Unless this domain has access to a real video card, you ++ probably want to say Y here. ++ ++config XEN_KEYBOARD ++ tristate "Keyboard-device frontend driver" ++ depends on XEN && XEN_FRAMEBUFFER && INPUT ++ default y ++ help ++ The keyboard-device frontend driver allows the kernel to create a ++ virtual keyboard. This keyboard can then be driven by another ++ domain. If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably ++ want to say Y here. ++ ++config XEN_SCRUB_PAGES ++ bool "Scrub memory before freeing it to Xen" ++ default y ++ help ++ Erase memory contents before freeing it back to Xen's global ++ pool. This ensures that any secrets contained within that ++ memory (e.g., private keys) cannot be found by other guests that ++ may be running on the machine. Most people will want to say Y here. ++ If security is not a concern then you may increase performance by ++ saying N. ++ ++config XEN_DISABLE_SERIAL ++ bool "Disable serial port drivers" ++ default y ++ help ++ Disable serial port drivers, allowing the Xen console driver ++ to provide a serial console at ttyS0. ++ ++config XEN_SYSFS ++ tristate "Export Xen attributes in sysfs" ++ depends on SYSFS ++ default y ++ help ++ Xen hypervisor attributes will show up under /sys/hypervisor/. ++ ++choice ++ prompt "Xen version compatibility" ++ default XEN_COMPAT_030002_AND_LATER ++ ++ config XEN_COMPAT_030002_AND_LATER ++ bool "3.0.2 and later" ++ ++ config XEN_COMPAT_030004_AND_LATER ++ bool "3.0.4 and later" ++ ++ config XEN_COMPAT_LATEST_ONLY ++ bool "no compatibility code" ++ ++endchoice ++ ++config XEN_COMPAT ++ hex ++ default 0xffffff if XEN_COMPAT_LATEST_ONLY ++ default 0x030004 if XEN_COMPAT_030004_AND_LATER ++ default 0x030002 if XEN_COMPAT_030002_AND_LATER ++ default 0 ++ ++endmenu ++ ++config HAVE_IRQ_IGNORE_UNHANDLED ++ bool ++ default y ++ ++config NO_IDLE_HZ ++ bool ++ default y ++ ++config XEN_SMPBOOT ++ bool ++ default y ++ depends on SMP ++ ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,20 @@ ++obj-y += core/ ++obj-y += console/ ++obj-y += evtchn/ ++obj-y += privcmd/ ++obj-y += xenbus/ ++obj-y += gntdev/ ++obj-y += balloon/ ++obj-y += char/ ++ ++obj-y += util.o ++obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ ++obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ ++obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ ++obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/ ++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ ++obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ ++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ ++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ ++obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfront/ ++obj-$(CONFIG_XEN_KEYBOARD) += fbfront/ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/balloon/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/balloon/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++obj-y := balloon.o sysfs.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/balloon/balloon.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/balloon/balloon.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,663 @@ ++/****************************************************************************** ++ * balloon.c ++ * ++ * Xen balloon driver - enables returning/claiming memory to/from Xen. ++ * ++ * Copyright (c) 2003, B Dragovic ++ * Copyright (c) 2003-2004, M Williamson, K Fraser ++ * Copyright (c) 2005 Dan M. Smith, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/mman.h> ++#include <linux/smp_lock.h> ++#include <linux/pagemap.h> ++#include <linux/bootmem.h> ++#include <linux/highmem.h> ++#include <linux/vmalloc.h> ++#include <linux/mutex.h> ++#include <xen/xen_proc.h> ++#include <asm/hypervisor.h> ++#include <xen/balloon.h> ++#include <xen/interface/memory.h> ++#include <asm/maddr.h> ++#include <asm/page.h> ++#include <asm/pgalloc.h> ++#include <asm/pgtable.h> ++#include <asm/uaccess.h> ++#include <asm/tlb.h> ++#include <linux/highmem.h> ++#include <linux/list.h> ++#include <xen/xenbus.h> ++#include "common.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#ifdef CONFIG_PROC_FS ++static struct proc_dir_entry *balloon_pde; ++#endif ++ ++static DEFINE_MUTEX(balloon_mutex); ++ ++/* ++ * Protects atomic reservation decrease/increase against concurrent increases. ++ * Also protects non-atomic updates of current_pages and driver_pages, and ++ * balloon lists. ++ */ ++DEFINE_SPINLOCK(balloon_lock); ++ ++struct balloon_stats balloon_stats; ++ ++/* We increase/decrease in batches which fit in a page */ ++static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; ++ ++/* VM /proc information for memory */ ++extern unsigned long totalram_pages; ++ ++/* List of ballooned pages, threaded through the mem_map array. */ ++static LIST_HEAD(ballooned_pages); ++ ++/* Main work function, always executed in process context. */ ++static void balloon_process(struct work_struct *unusable); ++static DECLARE_WORK(balloon_worker, balloon_process); ++static struct timer_list balloon_timer; ++ ++/* When ballooning out (allocating memory to return to Xen) we don't really ++ want the kernel to try too hard since that can trigger the oom killer. */ ++#define GFP_BALLOON \ ++ (GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC) ++ ++#define PAGE_TO_LIST(p) (&(p)->lru) ++#define LIST_TO_PAGE(l) list_entry((l), struct page, lru) ++#define UNLIST_PAGE(p) \ ++ do { \ ++ list_del(PAGE_TO_LIST(p)); \ ++ PAGE_TO_LIST(p)->next = NULL; \ ++ PAGE_TO_LIST(p)->prev = NULL; \ ++ } while(0) ++ ++#define IPRINTK(fmt, args...) \ ++ printk(KERN_INFO "xen_mem: " fmt, ##args) ++#define WPRINTK(fmt, args...) \ ++ printk(KERN_WARNING "xen_mem: " fmt, ##args) ++ ++/* balloon_append: add the given page to the balloon. */ ++static void balloon_append(struct page *page) ++{ ++ /* Lowmem is re-populated first, so highmem pages go at list tail. */ ++ if (PageHighMem(page)) { ++ list_add_tail(PAGE_TO_LIST(page), &ballooned_pages); ++ bs.balloon_high++; ++ } else { ++ list_add(PAGE_TO_LIST(page), &ballooned_pages); ++ bs.balloon_low++; ++ } ++} ++ ++/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ ++static struct page *balloon_retrieve(void) ++{ ++ struct page *page; ++ ++ if (list_empty(&ballooned_pages)) ++ return NULL; ++ ++ page = LIST_TO_PAGE(ballooned_pages.next); ++ UNLIST_PAGE(page); ++ ++ if (PageHighMem(page)) ++ bs.balloon_high--; ++ else ++ bs.balloon_low--; ++ ++ return page; ++} ++ ++static struct page *balloon_first_page(void) ++{ ++ if (list_empty(&ballooned_pages)) ++ return NULL; ++ return LIST_TO_PAGE(ballooned_pages.next); ++} ++ ++static struct page *balloon_next_page(struct page *page) ++{ ++ struct list_head *next = PAGE_TO_LIST(page)->next; ++ if (next == &ballooned_pages) ++ return NULL; ++ return LIST_TO_PAGE(next); ++} ++ ++static void balloon_alarm(unsigned long unused) ++{ ++ schedule_work(&balloon_worker); ++} ++ ++static unsigned long current_target(void) ++{ ++ unsigned long target = min(bs.target_pages, bs.hard_limit); ++ if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high)) ++ target = bs.current_pages + bs.balloon_low + bs.balloon_high; ++ return target; ++} ++ ++static int increase_reservation(unsigned long nr_pages) ++{ ++ unsigned long pfn, i, flags; ++ struct page *page; ++ long rc; ++ struct xen_memory_reservation reservation = { ++ .address_bits = 0, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ ++ if (nr_pages > ARRAY_SIZE(frame_list)) ++ nr_pages = ARRAY_SIZE(frame_list); ++ ++ balloon_lock(flags); ++ ++ page = balloon_first_page(); ++ for (i = 0; i < nr_pages; i++) { ++ BUG_ON(page == NULL); ++ frame_list[i] = page_to_pfn(page);; ++ page = balloon_next_page(page); ++ } ++ ++ set_xen_guest_handle(reservation.extent_start, frame_list); ++ reservation.nr_extents = nr_pages; ++ rc = HYPERVISOR_memory_op( ++ XENMEM_populate_physmap, &reservation); ++ if (rc < nr_pages) { ++ if (rc > 0) { ++ int ret; ++ ++ /* We hit the Xen hard limit: reprobe. */ ++ reservation.nr_extents = rc; ++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &reservation); ++ BUG_ON(ret != rc); ++ } ++ if (rc >= 0) ++ bs.hard_limit = (bs.current_pages + rc - ++ bs.driver_pages); ++ goto out; ++ } ++ ++ for (i = 0; i < nr_pages; i++) { ++ page = balloon_retrieve(); ++ BUG_ON(page == NULL); ++ ++ pfn = page_to_pfn(page); ++ BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) && ++ phys_to_machine_mapping_valid(pfn)); ++ ++ set_phys_to_machine(pfn, frame_list[i]); ++ ++#ifdef CONFIG_XEN ++ /* Link back into the page tables if not highmem. */ ++ if (pfn < max_low_pfn) { ++ int ret; ++ ret = HYPERVISOR_update_va_mapping( ++ (unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte_ma(frame_list[i], PAGE_KERNEL), ++ 0); ++ BUG_ON(ret); ++ } ++#endif ++ ++ /* Relinquish the page back to the allocator. */ ++ ClearPageReserved(page); ++ init_page_count(page); ++ __free_page(page); ++ } ++ ++ bs.current_pages += nr_pages; ++ totalram_pages = bs.current_pages; ++ ++ out: ++ balloon_unlock(flags); ++ ++ return 0; ++} ++ ++static int decrease_reservation(unsigned long nr_pages) ++{ ++ unsigned long pfn, i, flags; ++ struct page *page; ++ void *v; ++ int need_sleep = 0; ++ int ret; ++ struct xen_memory_reservation reservation = { ++ .address_bits = 0, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ ++ if (nr_pages > ARRAY_SIZE(frame_list)) ++ nr_pages = ARRAY_SIZE(frame_list); ++ ++ for (i = 0; i < nr_pages; i++) { ++ if ((page = alloc_page(GFP_BALLOON)) == NULL) { ++ nr_pages = i; ++ need_sleep = 1; ++ break; ++ } ++ ++ pfn = page_to_pfn(page); ++ frame_list[i] = pfn_to_mfn(pfn); ++ ++ if (!PageHighMem(page)) { ++ v = phys_to_virt(pfn << PAGE_SHIFT); ++ scrub_pages(v, 1); ++#ifdef CONFIG_XEN ++ ret = HYPERVISOR_update_va_mapping( ++ (unsigned long)v, __pte_ma(0), 0); ++ BUG_ON(ret); ++#endif ++ } ++#ifdef CONFIG_XEN_SCRUB_PAGES ++ else { ++ v = kmap(page); ++ scrub_pages(v, 1); ++ kunmap(page); ++ } ++#endif ++ } ++ ++#ifdef CONFIG_XEN ++ /* Ensure that ballooned highmem pages don't have kmaps. */ ++ kmap_flush_unused(); ++ flush_tlb_all(); ++#endif ++ ++ balloon_lock(flags); ++ ++ /* No more mappings: invalidate P2M and add to balloon. */ ++ for (i = 0; i < nr_pages; i++) { ++ pfn = mfn_to_pfn(frame_list[i]); ++ set_phys_to_machine(pfn, INVALID_P2M_ENTRY); ++ balloon_append(pfn_to_page(pfn)); ++ } ++ ++ set_xen_guest_handle(reservation.extent_start, frame_list); ++ reservation.nr_extents = nr_pages; ++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); ++ BUG_ON(ret != nr_pages); ++ ++ bs.current_pages -= nr_pages; ++ totalram_pages = bs.current_pages; ++ ++ balloon_unlock(flags); ++ ++ return need_sleep; ++} ++ ++/* ++ * We avoid multiple worker processes conflicting via the balloon mutex. ++ * We may of course race updates of the target counts (which are protected ++ * by the balloon lock), or with changes to the Xen hard limit, but we will ++ * recover from these in time. ++ */ ++static void balloon_process(struct work_struct *unusable) ++{ ++ int need_sleep = 0; ++ long credit; ++ ++ mutex_lock(&balloon_mutex); ++ ++ do { ++ credit = current_target() - bs.current_pages; ++ if (credit > 0) ++ need_sleep = (increase_reservation(credit) != 0); ++ if (credit < 0) ++ need_sleep = (decrease_reservation(-credit) != 0); ++ ++#ifndef CONFIG_PREEMPT ++ if (need_resched()) ++ schedule(); ++#endif ++ } while ((credit != 0) && !need_sleep); ++ ++ /* Schedule more work if there is some still to be done. */ ++ if (current_target() != bs.current_pages) ++ mod_timer(&balloon_timer, jiffies + HZ); ++ ++ mutex_unlock(&balloon_mutex); ++} ++ ++/* Resets the Xen limit, sets new target, and kicks off processing. */ ++void balloon_set_new_target(unsigned long target) ++{ ++ /* No need for lock. Not read-modify-write updates. */ ++ bs.hard_limit = ~0UL; ++ bs.target_pages = target; ++ schedule_work(&balloon_worker); ++} ++ ++static struct xenbus_watch target_watch = ++{ ++ .node = "memory/target" ++}; ++ ++/* React to a change in the target key */ ++static void watch_target(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ unsigned long long new_target; ++ int err; ++ ++ err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target); ++ if (err != 1) { ++ /* This is ok (for domain0 at least) - so just return */ ++ return; ++ } ++ ++ /* The given memory/target value is in KiB, so it needs converting to ++ * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. ++ */ ++ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); ++} ++ ++static int balloon_init_watcher(struct notifier_block *notifier, ++ unsigned long event, ++ void *data) ++{ ++ int err; ++ ++ err = register_xenbus_watch(&target_watch); ++ if (err) ++ printk(KERN_ERR "Failed to set balloon watcher\n"); ++ ++ return NOTIFY_DONE; ++} ++ ++#ifdef CONFIG_PROC_FS ++static int balloon_write(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ char memstring[64], *endchar; ++ unsigned long long target_bytes; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ if (count <= 1) ++ return -EBADMSG; /* runt */ ++ if (count > sizeof(memstring)) ++ return -EFBIG; /* too long */ ++ ++ if (copy_from_user(memstring, buffer, count)) ++ return -EFAULT; ++ memstring[sizeof(memstring)-1] = '\0'; ++ ++ target_bytes = memparse(memstring, &endchar); ++ balloon_set_new_target(target_bytes >> PAGE_SHIFT); ++ ++ return count; ++} ++ ++static int balloon_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf( ++ page, ++ "Current allocation: %8lu kB\n" ++ "Requested target: %8lu kB\n" ++ "Low-mem balloon: %8lu kB\n" ++ "High-mem balloon: %8lu kB\n" ++ "Driver pages: %8lu kB\n" ++ "Xen hard limit: ", ++ PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages), ++ PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high), ++ PAGES2KB(bs.driver_pages)); ++ ++ if (bs.hard_limit != ~0UL) ++ len += sprintf(page + len, "%8lu kB\n", ++ PAGES2KB(bs.hard_limit)); ++ else ++ len += sprintf(page + len, " ??? kB\n"); ++ ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static struct notifier_block xenstore_notifier; ++ ++static int __init balloon_init(void) ++{ ++#if defined(CONFIG_X86) && defined(CONFIG_XEN) ++ unsigned long pfn; ++ struct page *page; ++#endif ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ IPRINTK("Initialising balloon driver.\n"); ++ ++#ifdef CONFIG_XEN ++ bs.current_pages = min(xen_start_info->nr_pages, max_pfn); ++ totalram_pages = bs.current_pages; ++#else ++ bs.current_pages = totalram_pages; ++#endif ++ bs.target_pages = bs.current_pages; ++ bs.balloon_low = 0; ++ bs.balloon_high = 0; ++ bs.driver_pages = 0UL; ++ bs.hard_limit = ~0UL; ++ ++ init_timer(&balloon_timer); ++ balloon_timer.data = 0; ++ balloon_timer.function = balloon_alarm; ++ ++#ifdef CONFIG_PROC_FS ++ if ((balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL) { ++ WPRINTK("Unable to create /proc/xen/balloon.\n"); ++ return -1; ++ } ++ ++ balloon_pde->read_proc = balloon_read; ++ balloon_pde->write_proc = balloon_write; ++#endif ++ balloon_sysfs_init(); ++ ++#if defined(CONFIG_X86) && defined(CONFIG_XEN) ++ /* Initialise the balloon with excess memory space. */ ++ for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { ++ page = pfn_to_page(pfn); ++ if (!PageReserved(page)) ++ balloon_append(page); ++ } ++#endif ++ ++ target_watch.callback = watch_target; ++ xenstore_notifier.notifier_call = balloon_init_watcher; ++ ++ register_xenstore_notifier(&xenstore_notifier); ++ ++ return 0; ++} ++ ++subsys_initcall(balloon_init); ++ ++static void balloon_exit(void) ++{ ++ /* XXX - release balloon here */ ++ return; ++} ++ ++module_exit(balloon_exit); ++ ++void balloon_update_driver_allowance(long delta) ++{ ++ unsigned long flags; ++ ++ balloon_lock(flags); ++ bs.driver_pages += delta; ++ balloon_unlock(flags); ++} ++ ++#ifdef CONFIG_XEN ++static int dealloc_pte_fn( ++ pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) ++{ ++ unsigned long mfn = pte_mfn(*pte); ++ int ret; ++ struct xen_memory_reservation reservation = { ++ .nr_extents = 1, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ set_xen_guest_handle(reservation.extent_start, &mfn); ++ set_pte_at(&init_mm, addr, pte, __pte_ma(0)); ++ set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY); ++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); ++ BUG_ON(ret != 1); ++ return 0; ++} ++#endif ++ ++struct page **alloc_empty_pages_and_pagevec(int nr_pages) ++{ ++ unsigned long vaddr, flags; ++ struct page *page, **pagevec; ++ int i, ret; ++ ++ pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL); ++ if (pagevec == NULL) ++ return NULL; ++ ++ for (i = 0; i < nr_pages; i++) { ++ page = pagevec[i] = alloc_page(GFP_KERNEL); ++ if (page == NULL) ++ goto err; ++ ++ vaddr = (unsigned long)page_address(page); ++ ++ scrub_pages(vaddr, 1); ++ ++ balloon_lock(flags); ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ unsigned long gmfn = page_to_pfn(page); ++ struct xen_memory_reservation reservation = { ++ .nr_extents = 1, ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ set_xen_guest_handle(reservation.extent_start, &gmfn); ++ ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &reservation); ++ if (ret == 1) ++ ret = 0; /* success */ ++ } else { ++#ifdef CONFIG_XEN ++ ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE, ++ dealloc_pte_fn, NULL); ++#else ++ /* Cannot handle non-auto translate mode. */ ++ ret = 1; ++#endif ++ } ++ ++ if (ret != 0) { ++ balloon_unlock(flags); ++ __free_page(page); ++ goto err; ++ } ++ ++ totalram_pages = --bs.current_pages; ++ ++ balloon_unlock(flags); ++ } ++ ++ out: ++ schedule_work(&balloon_worker); ++#ifdef CONFIG_XEN ++ flush_tlb_all(); ++#endif ++ return pagevec; ++ ++ err: ++ balloon_lock(flags); ++ while (--i >= 0) ++ balloon_append(pagevec[i]); ++ balloon_unlock(flags); ++ kfree(pagevec); ++ pagevec = NULL; ++ goto out; ++} ++ ++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) ++{ ++ unsigned long flags; ++ int i; ++ ++ if (pagevec == NULL) ++ return; ++ ++ balloon_lock(flags); ++ for (i = 0; i < nr_pages; i++) { ++ BUG_ON(page_count(pagevec[i]) != 1); ++ balloon_append(pagevec[i]); ++ } ++ balloon_unlock(flags); ++ ++ kfree(pagevec); ++ ++ schedule_work(&balloon_worker); ++} ++ ++void balloon_release_driver_page(struct page *page) ++{ ++ unsigned long flags; ++ ++ balloon_lock(flags); ++ balloon_append(page); ++ bs.driver_pages--; ++ balloon_unlock(flags); ++ ++ schedule_work(&balloon_worker); ++} ++ ++EXPORT_SYMBOL_GPL(balloon_update_driver_allowance); ++EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec); ++EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec); ++EXPORT_SYMBOL_GPL(balloon_release_driver_page); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/balloon/common.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/balloon/common.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,58 @@ ++/****************************************************************************** ++ * balloon/common.h ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_BALLOON_COMMON_H__ ++#define __XEN_BALLOON_COMMON_H__ ++ ++#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) ++ ++struct balloon_stats { ++ /* We aim for 'current allocation' == 'target allocation'. */ ++ unsigned long current_pages; ++ unsigned long target_pages; ++ /* We may hit the hard limit in Xen. If we do then we remember it. */ ++ unsigned long hard_limit; ++ /* ++ * Drivers may alter the memory reservation independently, but they ++ * must inform the balloon driver so we avoid hitting the hard limit. ++ */ ++ unsigned long driver_pages; ++ /* Number of pages in high- and low-memory balloons. */ ++ unsigned long balloon_low; ++ unsigned long balloon_high; ++}; ++ ++extern struct balloon_stats balloon_stats; ++#define bs balloon_stats ++ ++int balloon_sysfs_init(void); ++void balloon_sysfs_exit(void); ++ ++void balloon_set_new_target(unsigned long target); ++ ++#endif /* __XEN_BALLOON_COMMON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/balloon/sysfs.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/balloon/sysfs.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,170 @@ ++/****************************************************************************** ++ * balloon/sysfs.c ++ * ++ * Xen balloon driver - sysfs interfaces. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/capability.h> ++#include <linux/errno.h> ++#include <linux/stat.h> ++#include <linux/string.h> ++#include <linux/sysdev.h> ++#include "common.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#define BALLOON_CLASS_NAME "memory" ++ ++#define BALLOON_SHOW(name, format, args...) \ ++ static ssize_t show_##name(struct sys_device *dev, \ ++ char *buf) \ ++ { \ ++ return sprintf(buf, format, ##args); \ ++ } \ ++ static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) ++ ++BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages)); ++BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low)); ++BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high)); ++BALLOON_SHOW(hard_limit_kb, ++ (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n", ++ (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0); ++BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages)); ++ ++static ssize_t show_target_kb(struct sys_device *dev, char *buf) ++{ ++ return sprintf(buf, "%lu\n", PAGES2KB(bs.target_pages)); ++} ++ ++static ssize_t store_target_kb(struct sys_device *dev, ++ const char *buf, ++ size_t count) ++{ ++ char memstring[64], *endchar; ++ unsigned long long target_bytes; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ if (count <= 1) ++ return -EBADMSG; /* runt */ ++ if (count > sizeof(memstring)) ++ return -EFBIG; /* too long */ ++ strcpy(memstring, buf); ++ ++ target_bytes = memparse(memstring, &endchar); ++ balloon_set_new_target(target_bytes >> PAGE_SHIFT); ++ ++ return count; ++} ++ ++static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, ++ show_target_kb, store_target_kb); ++ ++static struct sysdev_attribute *balloon_attrs[] = { ++ &attr_target_kb, ++}; ++ ++static struct attribute *balloon_info_attrs[] = { ++ &attr_current_kb.attr, ++ &attr_low_kb.attr, ++ &attr_high_kb.attr, ++ &attr_hard_limit_kb.attr, ++ &attr_driver_kb.attr, ++ NULL ++}; ++ ++static struct attribute_group balloon_info_group = { ++ .name = "info", ++ .attrs = balloon_info_attrs, ++}; ++ ++static struct sysdev_class balloon_sysdev_class = { ++ set_kset_name(BALLOON_CLASS_NAME), ++}; ++ ++static struct sys_device balloon_sysdev; ++ ++static int register_balloon(struct sys_device *sysdev) ++{ ++ int i, error; ++ ++ error = sysdev_class_register(&balloon_sysdev_class); ++ if (error) ++ return error; ++ ++ sysdev->id = 0; ++ sysdev->cls = &balloon_sysdev_class; ++ ++ error = sysdev_register(sysdev); ++ if (error) { ++ sysdev_class_unregister(&balloon_sysdev_class); ++ return error; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { ++ error = sysdev_create_file(sysdev, balloon_attrs[i]); ++ if (error) ++ goto fail; ++ } ++ ++ error = sysfs_create_group(&sysdev->kobj, &balloon_info_group); ++ if (error) ++ goto fail; ++ ++ return 0; ++ ++ fail: ++ while (--i >= 0) ++ sysdev_remove_file(sysdev, balloon_attrs[i]); ++ sysdev_unregister(sysdev); ++ sysdev_class_unregister(&balloon_sysdev_class); ++ return error; ++} ++ ++static void unregister_balloon(struct sys_device *sysdev) ++{ ++ int i; ++ ++ sysfs_remove_group(&sysdev->kobj, &balloon_info_group); ++ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) ++ sysdev_remove_file(sysdev, balloon_attrs[i]); ++ sysdev_unregister(sysdev); ++ sysdev_class_unregister(&balloon_sysdev_class); ++} ++ ++int balloon_sysfs_init(void) ++{ ++ return register_balloon(&balloon_sysdev); ++} ++ ++void balloon_sysfs_exit(void) ++{ ++ unregister_balloon(&balloon_sysdev); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o ++ ++blkbk-y := blkback.o xenbus.o interface.o vbd.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/blkback.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/blkback.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,614 @@ ++/****************************************************************************** ++ * arch/xen/drivers/blkif/backend/main.c ++ * ++ * Back-end of the driver for virtual block devices. This portion of the ++ * driver exports a 'unified' block-device interface that can be accessed ++ * by any operating system that implements a compatible front end. A ++ * reference front-end implementation can be found in: ++ * arch/xen/drivers/blkif/frontend ++ * ++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand ++ * Copyright (c) 2005, Christopher Clark ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/spinlock.h> ++#include <linux/kthread.h> ++#include <linux/list.h> ++#include <xen/balloon.h> ++#include <asm/hypervisor.h> ++#include "common.h" ++ ++/* ++ * These are rather arbitrary. They are fairly large because adjacent requests ++ * pulled from a communication ring are quite likely to end up being part of ++ * the same scatter/gather request at the disc. ++ * ++ * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW ** ++ * ++ * This will increase the chances of being able to write whole tracks. ++ * 64 should be enough to keep us competitive with Linux. ++ */ ++static int blkif_reqs = 64; ++module_param_named(reqs, blkif_reqs, int, 0); ++MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate"); ++ ++/* Run-time switchable: /sys/module/blkback/parameters/ */ ++static unsigned int log_stats = 0; ++static unsigned int debug_lvl = 0; ++module_param(log_stats, int, 0644); ++module_param(debug_lvl, int, 0644); ++ ++/* ++ * Each outstanding request that we've passed to the lower device layers has a ++ * 'pending_req' allocated to it. Each buffer_head that completes decrements ++ * the pendcnt towards zero. When it hits zero, the specified domain has a ++ * response queued for it, with the saved 'id' passed back. ++ */ ++typedef struct { ++ blkif_t *blkif; ++ u64 id; ++ int nr_pages; ++ atomic_t pendcnt; ++ unsigned short operation; ++ int status; ++ struct list_head free_list; ++} pending_req_t; ++ ++static pending_req_t *pending_reqs; ++static struct list_head pending_free; ++static DEFINE_SPINLOCK(pending_free_lock); ++static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq); ++ ++#define BLKBACK_INVALID_HANDLE (~0) ++ ++static struct page **pending_pages; ++static grant_handle_t *pending_grant_handles; ++ ++static inline int vaddr_pagenr(pending_req_t *req, int seg) ++{ ++ return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg; ++} ++ ++static inline unsigned long vaddr(pending_req_t *req, int seg) ++{ ++ unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]); ++ return (unsigned long)pfn_to_kaddr(pfn); ++} ++ ++#define pending_handle(_req, _seg) \ ++ (pending_grant_handles[vaddr_pagenr(_req, _seg)]) ++ ++ ++static int do_block_io_op(blkif_t *blkif); ++static void dispatch_rw_block_io(blkif_t *blkif, ++ blkif_request_t *req, ++ pending_req_t *pending_req); ++static void make_response(blkif_t *blkif, u64 id, ++ unsigned short op, int st); ++ ++/****************************************************************** ++ * misc small helpers ++ */ ++static pending_req_t* alloc_req(void) ++{ ++ pending_req_t *req = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ if (!list_empty(&pending_free)) { ++ req = list_entry(pending_free.next, pending_req_t, free_list); ++ list_del(&req->free_list); ++ } ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ return req; ++} ++ ++static void free_req(pending_req_t *req) ++{ ++ unsigned long flags; ++ int was_empty; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ was_empty = list_empty(&pending_free); ++ list_add(&req->free_list, &pending_free); ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ if (was_empty) ++ wake_up(&pending_free_wq); ++} ++ ++static void unplug_queue(blkif_t *blkif) ++{ ++ if (blkif->plug == NULL) ++ return; ++ if (blkif->plug->unplug_fn) ++ blkif->plug->unplug_fn(blkif->plug); ++ blk_put_queue(blkif->plug); ++ blkif->plug = NULL; ++} ++ ++static void plug_queue(blkif_t *blkif, struct bio *bio) ++{ ++ request_queue_t *q = bdev_get_queue(bio->bi_bdev); ++ ++ if (q == blkif->plug) ++ return; ++ unplug_queue(blkif); ++ blk_get_queue(q); ++ blkif->plug = q; ++} ++ ++static void fast_flush_area(pending_req_t *req) ++{ ++ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++ unsigned int i, invcount = 0; ++ grant_handle_t handle; ++ int ret; ++ ++ for (i = 0; i < req->nr_pages; i++) { ++ handle = pending_handle(req, i); ++ if (handle == BLKBACK_INVALID_HANDLE) ++ continue; ++ gnttab_set_unmap_op(&unmap[i], vaddr(req, i), GNTMAP_host_map, ++ handle); ++ pending_handle(req, i) = BLKBACK_INVALID_HANDLE; ++ invcount++; ++ } ++ ++ ret = HYPERVISOR_grant_table_op( ++ GNTTABOP_unmap_grant_ref, unmap, invcount); ++ BUG_ON(ret); ++} ++ ++/****************************************************************** ++ * SCHEDULER FUNCTIONS ++ */ ++ ++static void print_stats(blkif_t *blkif) ++{ ++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d | br %4d\n", ++ current->comm, blkif->st_oo_req, ++ blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req); ++ blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000); ++ blkif->st_rd_req = 0; ++ blkif->st_wr_req = 0; ++ blkif->st_oo_req = 0; ++} ++ ++int blkif_schedule(void *arg) ++{ ++ blkif_t *blkif = arg; ++ ++ blkif_get(blkif); ++ ++ if (debug_lvl) ++ printk(KERN_DEBUG "%s: started\n", current->comm); ++ ++ while (!kthread_should_stop()) { ++ wait_event_interruptible( ++ blkif->wq, ++ blkif->waiting_reqs || kthread_should_stop()); ++ wait_event_interruptible( ++ pending_free_wq, ++ !list_empty(&pending_free) || kthread_should_stop()); ++ ++ blkif->waiting_reqs = 0; ++ smp_mb(); /* clear flag *before* checking for work */ ++ ++ if (do_block_io_op(blkif)) ++ blkif->waiting_reqs = 1; ++ unplug_queue(blkif); ++ ++ if (log_stats && time_after(jiffies, blkif->st_print)) ++ print_stats(blkif); ++ } ++ ++ if (log_stats) ++ print_stats(blkif); ++ if (debug_lvl) ++ printk(KERN_DEBUG "%s: exiting\n", current->comm); ++ ++ blkif->xenblkd = NULL; ++ blkif_put(blkif); ++ ++ return 0; ++} ++ ++/****************************************************************** ++ * COMPLETION CALLBACK -- Called as bh->b_end_io() ++ */ ++ ++static void __end_block_io_op(pending_req_t *pending_req, int error) ++{ ++ /* An error fails the entire request. */ ++ if ((pending_req->operation == BLKIF_OP_WRITE_BARRIER) && ++ (error == -EOPNOTSUPP)) { ++ DPRINTK("blkback: write barrier op failed, not supported\n"); ++ blkback_barrier(XBT_NIL, pending_req->blkif->be, 0); ++ pending_req->status = BLKIF_RSP_EOPNOTSUPP; ++ } else if (error) { ++ DPRINTK("Buffer not up-to-date at end of operation, " ++ "error=%d\n", error); ++ pending_req->status = BLKIF_RSP_ERROR; ++ } ++ ++ if (atomic_dec_and_test(&pending_req->pendcnt)) { ++ fast_flush_area(pending_req); ++ make_response(pending_req->blkif, pending_req->id, ++ pending_req->operation, pending_req->status); ++ blkif_put(pending_req->blkif); ++ free_req(pending_req); ++ } ++} ++ ++static int end_block_io_op(struct bio *bio, unsigned int done, int error) ++{ ++ if (bio->bi_size != 0) ++ return 1; ++ __end_block_io_op(bio->bi_private, error); ++ bio_put(bio); ++ return error; ++} ++ ++ ++/****************************************************************************** ++ * NOTIFICATION FROM GUEST OS. ++ */ ++ ++static void blkif_notify_work(blkif_t *blkif) ++{ ++ blkif->waiting_reqs = 1; ++ wake_up(&blkif->wq); ++} ++ ++irqreturn_t blkif_be_int(int irq, void *dev_id) ++{ ++ blkif_notify_work(dev_id); ++ return IRQ_HANDLED; ++} ++ ++ ++ ++/****************************************************************** ++ * DOWNWARD CALLS -- These interface with the block-device layer proper. ++ */ ++ ++static int do_block_io_op(blkif_t *blkif) ++{ ++ blkif_back_rings_t *blk_rings = &blkif->blk_rings; ++ blkif_request_t req; ++ pending_req_t *pending_req; ++ RING_IDX rc, rp; ++ int more_to_do = 0; ++ ++ rc = blk_rings->common.req_cons; ++ rp = blk_rings->common.sring->req_prod; ++ rmb(); /* Ensure we see queued requests up to 'rp'. */ ++ ++ while ((rc != rp)) { ++ ++ if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc)) ++ break; ++ ++ pending_req = alloc_req(); ++ if (NULL == pending_req) { ++ blkif->st_oo_req++; ++ more_to_do = 1; ++ break; ++ } ++ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req)); ++ break; ++ case BLKIF_PROTOCOL_X86_32: ++ blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc)); ++ break; ++ case BLKIF_PROTOCOL_X86_64: ++ blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc)); ++ break; ++ default: ++ BUG(); ++ } ++ blk_rings->common.req_cons = ++rc; /* before make_response() */ ++ ++ switch (req.operation) { ++ case BLKIF_OP_READ: ++ blkif->st_rd_req++; ++ dispatch_rw_block_io(blkif, &req, pending_req); ++ break; ++ case BLKIF_OP_WRITE_BARRIER: ++ blkif->st_br_req++; ++ /* fall through */ ++ case BLKIF_OP_WRITE: ++ blkif->st_wr_req++; ++ dispatch_rw_block_io(blkif, &req, pending_req); ++ break; ++ default: ++ DPRINTK("error: unknown block io operation [%d]\n", ++ req.operation); ++ make_response(blkif, req.id, req.operation, ++ BLKIF_RSP_ERROR); ++ free_req(pending_req); ++ break; ++ } ++ } ++ return more_to_do; ++} ++ ++static void dispatch_rw_block_io(blkif_t *blkif, ++ blkif_request_t *req, ++ pending_req_t *pending_req) ++{ ++ extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); ++ struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++ struct phys_req preq; ++ struct { ++ unsigned long buf; unsigned int nsec; ++ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++ unsigned int nseg; ++ struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++ int ret, i, nbio = 0; ++ int operation; ++ ++ switch (req->operation) { ++ case BLKIF_OP_READ: ++ operation = READ; ++ break; ++ case BLKIF_OP_WRITE: ++ operation = WRITE; ++ break; ++ case BLKIF_OP_WRITE_BARRIER: ++ operation = WRITE_BARRIER; ++ break; ++ default: ++ operation = 0; /* make gcc happy */ ++ BUG(); ++ } ++ ++ /* Check that number of segments is sane. */ ++ nseg = req->nr_segments; ++ if (unlikely(nseg == 0) || ++ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { ++ DPRINTK("Bad number of segments in request (%d)\n", nseg); ++ goto fail_response; ++ } ++ ++ preq.dev = req->handle; ++ preq.sector_number = req->sector_number; ++ preq.nr_sects = 0; ++ ++ pending_req->blkif = blkif; ++ pending_req->id = req->id; ++ pending_req->operation = req->operation; ++ pending_req->status = BLKIF_RSP_OKAY; ++ pending_req->nr_pages = nseg; ++ ++ for (i = 0; i < nseg; i++) { ++ uint32_t flags; ++ ++ seg[i].nsec = req->seg[i].last_sect - ++ req->seg[i].first_sect + 1; ++ ++ if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) || ++ (req->seg[i].last_sect < req->seg[i].first_sect)) ++ goto fail_response; ++ preq.nr_sects += seg[i].nsec; ++ ++ flags = GNTMAP_host_map; ++ if (operation != READ) ++ flags |= GNTMAP_readonly; ++ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags, ++ req->seg[i].gref, blkif->domid); ++ } ++ ++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg); ++ BUG_ON(ret); ++ ++ for (i = 0; i < nseg; i++) { ++ if (unlikely(map[i].status != 0)) { ++ DPRINTK("invalid buffer -- could not remap it\n"); ++ map[i].handle = BLKBACK_INVALID_HANDLE; ++ ret |= 1; ++ } ++ ++ pending_handle(pending_req, i) = map[i].handle; ++ ++ if (ret) ++ continue; ++ ++ set_phys_to_machine(__pa(vaddr( ++ pending_req, i)) >> PAGE_SHIFT, ++ FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT)); ++ seg[i].buf = map[i].dev_bus_addr | ++ (req->seg[i].first_sect << 9); ++ } ++ ++ if (ret) ++ goto fail_flush; ++ ++ if (vbd_translate(&preq, blkif, operation) != 0) { ++ DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n", ++ operation == READ ? "read" : "write", ++ preq.sector_number, ++ preq.sector_number + preq.nr_sects, preq.dev); ++ goto fail_flush; ++ } ++ ++ for (i = 0; i < nseg; i++) { ++ if (((int)preq.sector_number|(int)seg[i].nsec) & ++ ((bdev_hardsect_size(preq.bdev) >> 9) - 1)) { ++ DPRINTK("Misaligned I/O request from domain %d", ++ blkif->domid); ++ goto fail_put_bio; ++ } ++ ++ while ((bio == NULL) || ++ (bio_add_page(bio, ++ virt_to_page(vaddr(pending_req, i)), ++ seg[i].nsec << 9, ++ seg[i].buf & ~PAGE_MASK) == 0)) { ++ bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i); ++ if (unlikely(bio == NULL)) ++ goto fail_put_bio; ++ ++ bio->bi_bdev = preq.bdev; ++ bio->bi_private = pending_req; ++ bio->bi_end_io = end_block_io_op; ++ bio->bi_sector = preq.sector_number; ++ } ++ ++ preq.sector_number += seg[i].nsec; ++ } ++ ++ plug_queue(blkif, bio); ++ atomic_set(&pending_req->pendcnt, nbio); ++ blkif_get(blkif); ++ ++ for (i = 0; i < nbio; i++) ++ submit_bio(operation, biolist[i]); ++ ++ if (operation == READ) ++ blkif->st_rd_sect += preq.nr_sects; ++ else if (operation == WRITE) ++ blkif->st_wr_sect += preq.nr_sects; ++ ++ return; ++ ++ fail_put_bio: ++ for (i = 0; i < (nbio-1); i++) ++ bio_put(biolist[i]); ++ fail_flush: ++ fast_flush_area(pending_req); ++ fail_response: ++ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); ++ free_req(pending_req); ++} ++ ++ ++ ++/****************************************************************** ++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING ++ */ ++ ++ ++static void make_response(blkif_t *blkif, u64 id, ++ unsigned short op, int st) ++{ ++ blkif_response_t resp; ++ unsigned long flags; ++ blkif_back_rings_t *blk_rings = &blkif->blk_rings; ++ int more_to_do = 0; ++ int notify; ++ ++ resp.id = id; ++ resp.operation = op; ++ resp.status = st; ++ ++ spin_lock_irqsave(&blkif->blk_ring_lock, flags); ++ /* Place on the response ring for the relevant domain. */ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case BLKIF_PROTOCOL_X86_32: ++ memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case BLKIF_PROTOCOL_X86_64: ++ memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ default: ++ BUG(); ++ } ++ blk_rings->common.rsp_prod_pvt++; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify); ++ if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) { ++ /* ++ * Tail check for pending requests. Allows frontend to avoid ++ * notifications if requests are already in flight (lower ++ * overheads and promotes batching). ++ */ ++ RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do); ++ ++ } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) { ++ more_to_do = 1; ++ } ++ ++ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags); ++ ++ if (more_to_do) ++ blkif_notify_work(blkif); ++ if (notify) ++ notify_remote_via_irq(blkif->irq); ++} ++ ++static int __init blkif_init(void) ++{ ++ int i, mmap_pages; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; ++ ++ pending_reqs = kmalloc(sizeof(pending_reqs[0]) * ++ blkif_reqs, GFP_KERNEL); ++ pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) * ++ mmap_pages, GFP_KERNEL); ++ pending_pages = alloc_empty_pages_and_pagevec(mmap_pages); ++ ++ if (!pending_reqs || !pending_grant_handles || !pending_pages) ++ goto out_of_memory; ++ ++ for (i = 0; i < mmap_pages; i++) ++ pending_grant_handles[i] = BLKBACK_INVALID_HANDLE; ++ ++ blkif_interface_init(); ++ ++ memset(pending_reqs, 0, sizeof(pending_reqs)); ++ INIT_LIST_HEAD(&pending_free); ++ ++ for (i = 0; i < blkif_reqs; i++) ++ list_add_tail(&pending_reqs[i].free_list, &pending_free); ++ ++ blkif_xenbus_init(); ++ ++ return 0; ++ ++ out_of_memory: ++ kfree(pending_reqs); ++ kfree(pending_grant_handles); ++ free_empty_pages_and_pagevec(pending_pages, mmap_pages); ++ printk("%s: out of memory\n", __FUNCTION__); ++ return -ENOMEM; ++} ++ ++module_init(blkif_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/common.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/common.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,139 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __BLKIF__BACKEND__COMMON_H__ ++#define __BLKIF__BACKEND__COMMON_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/blkdev.h> ++#include <linux/vmalloc.h> ++#include <linux/wait.h> ++#include <asm/io.h> ++#include <asm/setup.h> ++#include <asm/pgalloc.h> ++#include <xen/evtchn.h> ++#include <asm/hypervisor.h> ++#include <xen/blkif.h> ++#include <xen/gnttab.h> ++#include <xen/driver_util.h> ++#include <xen/xenbus.h> ++ ++#define DPRINTK(_f, _a...) \ ++ pr_debug("(file=%s, line=%d) " _f, \ ++ __FILE__ , __LINE__ , ## _a ) ++ ++struct vbd { ++ blkif_vdev_t handle; /* what the domain refers to this vbd as */ ++ unsigned char readonly; /* Non-zero -> read-only */ ++ unsigned char type; /* VDISK_xxx */ ++ u32 pdevice; /* phys device that this vbd maps to */ ++ struct block_device *bdev; ++}; ++ ++struct backend_info; ++ ++typedef struct blkif_st { ++ /* Unique identifier for this interface. */ ++ domid_t domid; ++ unsigned int handle; ++ /* Physical parameters of the comms window. */ ++ unsigned int irq; ++ /* Comms information. */ ++ enum blkif_protocol blk_protocol; ++ blkif_back_rings_t blk_rings; ++ struct vm_struct *blk_ring_area; ++ /* The VBD attached to this interface. */ ++ struct vbd vbd; ++ /* Back pointer to the backend_info. */ ++ struct backend_info *be; ++ /* Private fields. */ ++ spinlock_t blk_ring_lock; ++ atomic_t refcnt; ++ ++ wait_queue_head_t wq; ++ struct task_struct *xenblkd; ++ unsigned int waiting_reqs; ++ request_queue_t *plug; ++ ++ /* statistics */ ++ unsigned long st_print; ++ int st_rd_req; ++ int st_wr_req; ++ int st_oo_req; ++ int st_br_req; ++ int st_rd_sect; ++ int st_wr_sect; ++ ++ wait_queue_head_t waiting_to_free; ++ ++ grant_handle_t shmem_handle; ++ grant_ref_t shmem_ref; ++} blkif_t; ++ ++blkif_t *blkif_alloc(domid_t domid); ++void blkif_disconnect(blkif_t *blkif); ++void blkif_free(blkif_t *blkif); ++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn); ++ ++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt)) ++#define blkif_put(_b) \ ++ do { \ ++ if (atomic_dec_and_test(&(_b)->refcnt)) \ ++ wake_up(&(_b)->waiting_to_free);\ ++ } while (0) ++ ++/* Create a vbd. */ ++int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major, ++ unsigned minor, int readonly); ++void vbd_free(struct vbd *vbd); ++ ++unsigned long long vbd_size(struct vbd *vbd); ++unsigned int vbd_info(struct vbd *vbd); ++unsigned long vbd_secsize(struct vbd *vbd); ++ ++struct phys_req { ++ unsigned short dev; ++ unsigned short nr_sects; ++ struct block_device *bdev; ++ blkif_sector_t sector_number; ++}; ++ ++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation); ++ ++void blkif_interface_init(void); ++ ++void blkif_xenbus_init(void); ++ ++irqreturn_t blkif_be_int(int irq, void *dev_id); ++int blkif_schedule(void *arg); ++ ++int blkback_barrier(struct xenbus_transaction xbt, ++ struct backend_info *be, int state); ++ ++#endif /* __BLKIF__BACKEND__COMMON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/interface.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/interface.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,181 @@ ++/****************************************************************************** ++ * arch/xen/drivers/blkif/backend/interface.c ++ * ++ * Block-device interface management. ++ * ++ * Copyright (c) 2004, Keir Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "common.h" ++#include <xen/evtchn.h> ++#include <linux/kthread.h> ++ ++static struct kmem_cache *blkif_cachep; ++ ++blkif_t *blkif_alloc(domid_t domid) ++{ ++ blkif_t *blkif; ++ ++ blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL); ++ if (!blkif) ++ return ERR_PTR(-ENOMEM); ++ ++ memset(blkif, 0, sizeof(*blkif)); ++ blkif->domid = domid; ++ spin_lock_init(&blkif->blk_ring_lock); ++ atomic_set(&blkif->refcnt, 1); ++ init_waitqueue_head(&blkif->wq); ++ blkif->st_print = jiffies; ++ init_waitqueue_head(&blkif->waiting_to_free); ++ ++ return blkif; ++} ++ ++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page) ++{ ++ struct gnttab_map_grant_ref op; ++ ++ gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr, ++ GNTMAP_host_map, shared_page, blkif->domid); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status) { ++ DPRINTK(" Grant table operation failure !\n"); ++ return op.status; ++ } ++ ++ blkif->shmem_ref = shared_page; ++ blkif->shmem_handle = op.handle; ++ ++ return 0; ++} ++ ++static void unmap_frontend_page(blkif_t *blkif) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr, ++ GNTMAP_host_map, blkif->shmem_handle); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++} ++ ++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn) ++{ ++ int err; ++ ++ /* Already connected through? */ ++ if (blkif->irq) ++ return 0; ++ ++ if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL ) ++ return -ENOMEM; ++ ++ err = map_frontend_page(blkif, shared_page); ++ if (err) { ++ free_vm_area(blkif->blk_ring_area); ++ return err; ++ } ++ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ { ++ blkif_sring_t *sring; ++ sring = (blkif_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE); ++ break; ++ } ++ case BLKIF_PROTOCOL_X86_32: ++ { ++ blkif_x86_32_sring_t *sring_x86_32; ++ sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE); ++ break; ++ } ++ case BLKIF_PROTOCOL_X86_64: ++ { ++ blkif_x86_64_sring_t *sring_x86_64; ++ sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE); ++ break; ++ } ++ default: ++ BUG(); ++ } ++ ++ err = bind_interdomain_evtchn_to_irqhandler( ++ blkif->domid, evtchn, blkif_be_int, 0, "blkif-backend", blkif); ++ if (err < 0) ++ { ++ unmap_frontend_page(blkif); ++ free_vm_area(blkif->blk_ring_area); ++ blkif->blk_rings.common.sring = NULL; ++ return err; ++ } ++ blkif->irq = err; ++ ++ return 0; ++} ++ ++void blkif_disconnect(blkif_t *blkif) ++{ ++ if (blkif->xenblkd) { ++ kthread_stop(blkif->xenblkd); ++ blkif->xenblkd = NULL; ++ } ++ ++ atomic_dec(&blkif->refcnt); ++ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0); ++ atomic_inc(&blkif->refcnt); ++ ++ if (blkif->irq) { ++ unbind_from_irqhandler(blkif->irq, blkif); ++ blkif->irq = 0; ++ } ++ ++ if (blkif->blk_rings.common.sring) { ++ unmap_frontend_page(blkif); ++ free_vm_area(blkif->blk_ring_area); ++ blkif->blk_rings.common.sring = NULL; ++ } ++} ++ ++void blkif_free(blkif_t *blkif) ++{ ++ if (!atomic_dec_and_test(&blkif->refcnt)) ++ BUG(); ++ kmem_cache_free(blkif_cachep, blkif); ++} ++ ++void __init blkif_interface_init(void) ++{ ++ blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t), ++ 0, 0, NULL, NULL); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/vbd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/vbd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,118 @@ ++/****************************************************************************** ++ * blkback/vbd.c ++ * ++ * Routines for managing virtual block devices (VBDs). ++ * ++ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "common.h" ++ ++#define vbd_sz(_v) ((_v)->bdev->bd_part ? \ ++ (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity) ++ ++unsigned long long vbd_size(struct vbd *vbd) ++{ ++ return vbd_sz(vbd); ++} ++ ++unsigned int vbd_info(struct vbd *vbd) ++{ ++ return vbd->type | (vbd->readonly?VDISK_READONLY:0); ++} ++ ++unsigned long vbd_secsize(struct vbd *vbd) ++{ ++ return bdev_hardsect_size(vbd->bdev); ++} ++ ++int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major, ++ unsigned minor, int readonly) ++{ ++ struct vbd *vbd; ++ struct block_device *bdev; ++ ++ vbd = &blkif->vbd; ++ vbd->handle = handle; ++ vbd->readonly = readonly; ++ vbd->type = 0; ++ ++ vbd->pdevice = MKDEV(major, minor); ++ ++ bdev = open_by_devnum(vbd->pdevice, ++ vbd->readonly ? FMODE_READ : FMODE_WRITE); ++ ++ if (IS_ERR(bdev)) { ++ DPRINTK("vbd_creat: device %08x could not be opened.\n", ++ vbd->pdevice); ++ return -ENOENT; ++ } ++ ++ vbd->bdev = bdev; ++ ++ if (vbd->bdev->bd_disk == NULL) { ++ DPRINTK("vbd_creat: device %08x doesn't exist.\n", ++ vbd->pdevice); ++ vbd_free(vbd); ++ return -ENOENT; ++ } ++ ++ if (vbd->bdev->bd_disk->flags & GENHD_FL_CD) ++ vbd->type |= VDISK_CDROM; ++ if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE) ++ vbd->type |= VDISK_REMOVABLE; ++ ++ DPRINTK("Successful creation of handle=%04x (dom=%u)\n", ++ handle, blkif->domid); ++ return 0; ++} ++ ++void vbd_free(struct vbd *vbd) ++{ ++ if (vbd->bdev) ++ blkdev_put(vbd->bdev); ++ vbd->bdev = NULL; ++} ++ ++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation) ++{ ++ struct vbd *vbd = &blkif->vbd; ++ int rc = -EACCES; ++ ++ if ((operation != READ) && vbd->readonly) ++ goto out; ++ ++ if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd))) ++ goto out; ++ ++ req->dev = vbd->pdevice; ++ req->bdev = vbd->bdev; ++ rc = 0; ++ ++ out: ++ return rc; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkback/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkback/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,533 @@ ++/* Xenbus code for blkif backend ++ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au> ++ Copyright (C) 2005 XenSource Ltd ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include <stdarg.h> ++#include <linux/module.h> ++#include <linux/kthread.h> ++#include "common.h" ++ ++#undef DPRINTK ++#define DPRINTK(fmt, args...) \ ++ pr_debug("blkback/xenbus (%s:%d) " fmt ".\n", \ ++ __FUNCTION__, __LINE__, ##args) ++ ++struct backend_info ++{ ++ struct xenbus_device *dev; ++ blkif_t *blkif; ++ struct xenbus_watch backend_watch; ++ unsigned major; ++ unsigned minor; ++ char *mode; ++}; ++ ++static void connect(struct backend_info *); ++static int connect_ring(struct backend_info *); ++static void backend_changed(struct xenbus_watch *, const char **, ++ unsigned int); ++ ++static int blkback_name(blkif_t *blkif, char *buf) ++{ ++ char *devpath, *devname; ++ struct xenbus_device *dev = blkif->be->dev; ++ ++ devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL); ++ if (IS_ERR(devpath)) ++ return PTR_ERR(devpath); ++ ++ if ((devname = strstr(devpath, "/dev/")) != NULL) ++ devname += strlen("/dev/"); ++ else ++ devname = devpath; ++ ++ snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname); ++ kfree(devpath); ++ ++ return 0; ++} ++ ++static void update_blkif_status(blkif_t *blkif) ++{ ++ int err; ++ char name[TASK_COMM_LEN]; ++ ++ /* Not ready to connect? */ ++ if (!blkif->irq || !blkif->vbd.bdev) ++ return; ++ ++ /* Already connected? */ ++ if (blkif->be->dev->state == XenbusStateConnected) ++ return; ++ ++ /* Attempt to connect: exit if we fail to. */ ++ connect(blkif->be); ++ if (blkif->be->dev->state != XenbusStateConnected) ++ return; ++ ++ err = blkback_name(blkif, name); ++ if (err) { ++ xenbus_dev_error(blkif->be->dev, err, "get blkback dev name"); ++ return; ++ } ++ ++ blkif->xenblkd = kthread_run(blkif_schedule, blkif, name); ++ if (IS_ERR(blkif->xenblkd)) { ++ err = PTR_ERR(blkif->xenblkd); ++ blkif->xenblkd = NULL; ++ xenbus_dev_error(blkif->be->dev, err, "start xenblkd"); ++ } ++} ++ ++ ++/**************************************************************** ++ * sysfs interface for VBD I/O requests ++ */ ++ ++#define VBD_SHOW(name, format, args...) \ ++ static ssize_t show_##name(struct device *_dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ struct xenbus_device *dev = to_xenbus_device(_dev); \ ++ struct backend_info *be = dev->dev.driver_data; \ ++ \ ++ return sprintf(buf, format, ##args); \ ++ } \ ++ DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) ++ ++VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req); ++VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req); ++VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req); ++VBD_SHOW(br_req, "%d\n", be->blkif->st_br_req); ++VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect); ++VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect); ++ ++static struct attribute *vbdstat_attrs[] = { ++ &dev_attr_oo_req.attr, ++ &dev_attr_rd_req.attr, ++ &dev_attr_wr_req.attr, ++ &dev_attr_br_req.attr, ++ &dev_attr_rd_sect.attr, ++ &dev_attr_wr_sect.attr, ++ NULL ++}; ++ ++static struct attribute_group vbdstat_group = { ++ .name = "statistics", ++ .attrs = vbdstat_attrs, ++}; ++ ++VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor); ++VBD_SHOW(mode, "%s\n", be->mode); ++ ++int xenvbd_sysfs_addif(struct xenbus_device *dev) ++{ ++ int error; ++ ++ error = device_create_file(&dev->dev, &dev_attr_physical_device); ++ if (error) ++ goto fail1; ++ ++ error = device_create_file(&dev->dev, &dev_attr_mode); ++ if (error) ++ goto fail2; ++ ++ error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group); ++ if (error) ++ goto fail3; ++ ++ return 0; ++ ++fail3: sysfs_remove_group(&dev->dev.kobj, &vbdstat_group); ++fail2: device_remove_file(&dev->dev, &dev_attr_mode); ++fail1: device_remove_file(&dev->dev, &dev_attr_physical_device); ++ return error; ++} ++ ++void xenvbd_sysfs_delif(struct xenbus_device *dev) ++{ ++ sysfs_remove_group(&dev->dev.kobj, &vbdstat_group); ++ device_remove_file(&dev->dev, &dev_attr_mode); ++ device_remove_file(&dev->dev, &dev_attr_physical_device); ++} ++ ++static int blkback_remove(struct xenbus_device *dev) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ ++ DPRINTK(""); ++ ++ if (be->backend_watch.node) { ++ unregister_xenbus_watch(&be->backend_watch); ++ kfree(be->backend_watch.node); ++ be->backend_watch.node = NULL; ++ } ++ ++ if (be->blkif) { ++ blkif_disconnect(be->blkif); ++ vbd_free(&be->blkif->vbd); ++ blkif_free(be->blkif); ++ be->blkif = NULL; ++ } ++ ++ if (be->major || be->minor) ++ xenvbd_sysfs_delif(dev); ++ ++ kfree(be); ++ dev->dev.driver_data = NULL; ++ return 0; ++} ++ ++int blkback_barrier(struct xenbus_transaction xbt, ++ struct backend_info *be, int state) ++{ ++ struct xenbus_device *dev = be->dev; ++ int err; ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-barrier", ++ "%d", state); ++ if (err) ++ xenbus_dev_fatal(dev, err, "writing feature-barrier"); ++ ++ return err; ++} ++ ++/** ++ * Entry point to this code when a new device is created. Allocate the basic ++ * structures, and watch the store waiting for the hotplug scripts to tell us ++ * the device's physical major and minor numbers. Switch to InitWait. ++ */ ++static int blkback_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ struct backend_info *be = kzalloc(sizeof(struct backend_info), ++ GFP_KERNEL); ++ if (!be) { ++ xenbus_dev_fatal(dev, -ENOMEM, ++ "allocating backend structure"); ++ return -ENOMEM; ++ } ++ be->dev = dev; ++ dev->dev.driver_data = be; ++ ++ be->blkif = blkif_alloc(dev->otherend_id); ++ if (IS_ERR(be->blkif)) { ++ err = PTR_ERR(be->blkif); ++ be->blkif = NULL; ++ xenbus_dev_fatal(dev, err, "creating block interface"); ++ goto fail; ++ } ++ ++ /* setup back pointer */ ++ be->blkif->be = be; ++ ++ err = xenbus_watch_path2(dev, dev->nodename, "physical-device", ++ &be->backend_watch, backend_changed); ++ if (err) ++ goto fail; ++ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) ++ goto fail; ++ ++ return 0; ++ ++fail: ++ DPRINTK("failed"); ++ blkback_remove(dev); ++ return err; ++} ++ ++ ++/** ++ * Callback received when the hotplug scripts have placed the physical-device ++ * node. Read it and the mode node, and create a vbd. If the frontend is ++ * ready, connect. ++ */ ++static void backend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ int err; ++ unsigned major; ++ unsigned minor; ++ struct backend_info *be ++ = container_of(watch, struct backend_info, backend_watch); ++ struct xenbus_device *dev = be->dev; ++ ++ DPRINTK(""); ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x", ++ &major, &minor); ++ if (XENBUS_EXIST_ERR(err)) { ++ /* Since this watch will fire once immediately after it is ++ registered, we expect this. Ignore it, and wait for the ++ hotplug scripts. */ ++ return; ++ } ++ if (err != 2) { ++ xenbus_dev_fatal(dev, err, "reading physical-device"); ++ return; ++ } ++ ++ if ((be->major || be->minor) && ++ ((be->major != major) || (be->minor != minor))) { ++ printk(KERN_WARNING ++ "blkback: changing physical device (from %x:%x to " ++ "%x:%x) not supported.\n", be->major, be->minor, ++ major, minor); ++ return; ++ } ++ ++ be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL); ++ if (IS_ERR(be->mode)) { ++ err = PTR_ERR(be->mode); ++ be->mode = NULL; ++ xenbus_dev_fatal(dev, err, "reading mode"); ++ return; ++ } ++ ++ if (be->major == 0 && be->minor == 0) { ++ /* Front end dir is a number, which is used as the handle. */ ++ ++ char *p = strrchr(dev->otherend, '/') + 1; ++ long handle = simple_strtoul(p, NULL, 0); ++ ++ be->major = major; ++ be->minor = minor; ++ ++ err = vbd_create(be->blkif, handle, major, minor, ++ (NULL == strchr(be->mode, 'w'))); ++ if (err) { ++ be->major = be->minor = 0; ++ xenbus_dev_fatal(dev, err, "creating vbd structure"); ++ return; ++ } ++ ++ err = xenvbd_sysfs_addif(dev); ++ if (err) { ++ vbd_free(&be->blkif->vbd); ++ be->major = be->minor = 0; ++ xenbus_dev_fatal(dev, err, "creating sysfs entries"); ++ return; ++ } ++ ++ /* We're potentially connected now */ ++ update_blkif_status(be->blkif); ++ } ++} ++ ++ ++/** ++ * Callback received when the frontend's state changes. ++ */ ++static void frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ int err; ++ ++ DPRINTK("%s", xenbus_strstate(frontend_state)); ++ ++ switch (frontend_state) { ++ case XenbusStateInitialising: ++ if (dev->state == XenbusStateClosed) { ++ printk(KERN_INFO "%s: %s: prepare for reconnect\n", ++ __FUNCTION__, dev->nodename); ++ xenbus_switch_state(dev, XenbusStateInitWait); ++ } ++ break; ++ ++ case XenbusStateInitialised: ++ case XenbusStateConnected: ++ /* Ensure we connect even when two watches fire in ++ close successsion and we miss the intermediate value ++ of frontend_state. */ ++ if (dev->state == XenbusStateConnected) ++ break; ++ ++ err = connect_ring(be); ++ if (err) ++ break; ++ update_blkif_status(be->blkif); ++ break; ++ ++ case XenbusStateClosing: ++ blkif_disconnect(be->blkif); ++ xenbus_switch_state(dev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateClosed: ++ xenbus_switch_state(dev, XenbusStateClosed); ++ if (xenbus_dev_is_online(dev)) ++ break; ++ /* fall through if not online */ ++ case XenbusStateUnknown: ++ device_unregister(&dev->dev); ++ break; ++ ++ default: ++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", ++ frontend_state); ++ break; ++ } ++} ++ ++ ++/* ** Connection ** */ ++ ++ ++/** ++ * Write the physical details regarding the block device to the store, and ++ * switch to Connected state. ++ */ ++static void connect(struct backend_info *be) ++{ ++ struct xenbus_transaction xbt; ++ int err; ++ struct xenbus_device *dev = be->dev; ++ ++ DPRINTK("%s", dev->otherend); ++ ++ /* Supply the information about the device the frontend needs */ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ return; ++ } ++ ++ err = blkback_barrier(xbt, be, 1); ++ if (err) ++ goto abort; ++ ++ err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", ++ vbd_size(&be->blkif->vbd)); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "writing %s/sectors", ++ dev->nodename); ++ goto abort; ++ } ++ ++ /* FIXME: use a typename instead */ ++ err = xenbus_printf(xbt, dev->nodename, "info", "%u", ++ vbd_info(&be->blkif->vbd)); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "writing %s/info", ++ dev->nodename); ++ goto abort; ++ } ++ err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu", ++ vbd_secsize(&be->blkif->vbd)); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "writing %s/sector-size", ++ dev->nodename); ++ goto abort; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ if (err) ++ xenbus_dev_fatal(dev, err, "ending transaction"); ++ ++ err = xenbus_switch_state(dev, XenbusStateConnected); ++ if (err) ++ xenbus_dev_fatal(dev, err, "switching to Connected state", ++ dev->nodename); ++ ++ return; ++ abort: ++ xenbus_transaction_end(xbt, 1); ++} ++ ++ ++static int connect_ring(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ unsigned long ring_ref; ++ unsigned int evtchn; ++ char protocol[64] = ""; ++ int err; ++ ++ DPRINTK("%s", dev->otherend); ++ ++ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref, ++ "event-channel", "%u", &evtchn, NULL); ++ if (err) { ++ xenbus_dev_fatal(dev, err, ++ "reading %s/ring-ref and event-channel", ++ dev->otherend); ++ return err; ++ } ++ ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; ++ err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", ++ "%63s", protocol, NULL); ++ if (err) ++ strcpy(protocol, "unspecified, assuming native"); ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++ else { ++ xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); ++ return -1; ++ } ++ printk(KERN_INFO ++ "blkback: ring-ref %ld, event-channel %d, protocol %d (%s)\n", ++ ring_ref, evtchn, be->blkif->blk_protocol, protocol); ++ ++ /* Map the shared frame, irq etc. */ ++ err = blkif_map(be->blkif, ring_ref, evtchn); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u", ++ ring_ref, evtchn); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++/* ** Driver Registration ** */ ++ ++ ++static struct xenbus_device_id blkback_ids[] = { ++ { "vbd" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver blkback = { ++ .name = "vbd", ++ .owner = THIS_MODULE, ++ .ids = blkback_ids, ++ .probe = blkback_probe, ++ .remove = blkback_remove, ++ .otherend_changed = frontend_changed ++}; ++ ++ ++void blkif_xenbus_init(void) ++{ ++ xenbus_register_backend(&blkback); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkfront/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkfront/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++ ++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o ++ ++xenblk-objs := blkfront.o vbd.o ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkfront/blkfront.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkfront/blkfront.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,903 @@ ++/****************************************************************************** ++ * blkfront.c ++ * ++ * XenLinux virtual block-device driver. ++ * ++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand ++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge ++ * Copyright (c) 2004, Christian Limpach ++ * Copyright (c) 2004, Andrew Warfield ++ * Copyright (c) 2005, Christopher Clark ++ * Copyright (c) 2005, XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/version.h> ++#include "block.h" ++#include <linux/cdrom.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <scsi/scsi.h> ++#include <xen/evtchn.h> ++#include <xen/xenbus.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/io/protocols.h> ++#include <xen/gnttab.h> ++#include <asm/hypervisor.h> ++#include <asm/maddr.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#define BLKIF_STATE_DISCONNECTED 0 ++#define BLKIF_STATE_CONNECTED 1 ++#define BLKIF_STATE_SUSPENDED 2 ++ ++#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ ++ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) ++#define GRANT_INVALID_REF 0 ++ ++static void connect(struct blkfront_info *); ++static void blkfront_closing(struct xenbus_device *); ++static int blkfront_remove(struct xenbus_device *); ++static int talk_to_backend(struct xenbus_device *, struct blkfront_info *); ++static int setup_blkring(struct xenbus_device *, struct blkfront_info *); ++ ++static void kick_pending_request_queues(struct blkfront_info *); ++ ++static irqreturn_t blkif_int(int irq, void *dev_id); ++static void blkif_restart_queue(struct work_struct *work); ++static void blkif_recover(struct blkfront_info *); ++static void blkif_completion(struct blk_shadow *); ++static void blkif_free(struct blkfront_info *, int); ++ ++ ++/** ++ * Entry point to this code when a new device is created. Allocate the basic ++ * structures and the ring buffer for communication with the backend, and ++ * inform the backend of the appropriate details for those. Switch to ++ * Initialised state. ++ */ ++static int blkfront_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err, vdevice, i; ++ struct blkfront_info *info; ++ ++ /* FIXME: Use dynamic device id if this is not set. */ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, ++ "virtual-device", "%i", &vdevice); ++ if (err != 1) { ++ xenbus_dev_fatal(dev, err, "reading virtual-device"); ++ return err; ++ } ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); ++ return -ENOMEM; ++ } ++ ++ info->xbdev = dev; ++ info->vdevice = vdevice; ++ info->connected = BLKIF_STATE_DISCONNECTED; ++ INIT_WORK(&info->work, blkif_restart_queue); ++ ++ for (i = 0; i < BLK_RING_SIZE; i++) ++ info->shadow[i].req.id = i+1; ++ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; ++ ++ /* Front end dir is a number, which is used as the id. */ ++ info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0); ++ dev->dev.driver_data = info; ++ ++ err = talk_to_backend(dev, info); ++ if (err) { ++ kfree(info); ++ dev->dev.driver_data = NULL; ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * We are reconnecting to the backend, due to a suspend/resume, or a backend ++ * driver restart. We tear down our blkif structure and recreate it, but ++ * leave the device-layer structures intact so that this is transparent to the ++ * rest of the kernel. ++ */ ++static int blkfront_resume(struct xenbus_device *dev) ++{ ++ struct blkfront_info *info = dev->dev.driver_data; ++ int err; ++ ++ DPRINTK("blkfront_resume: %s\n", dev->nodename); ++ ++ blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); ++ ++ err = talk_to_backend(dev, info); ++ if (info->connected == BLKIF_STATE_SUSPENDED && !err) ++ blkif_recover(info); ++ ++ return err; ++} ++ ++ ++/* Common code used when first setting up, and when resuming. */ ++static int talk_to_backend(struct xenbus_device *dev, ++ struct blkfront_info *info) ++{ ++ const char *message = NULL; ++ struct xenbus_transaction xbt; ++ int err; ++ ++ /* Create shared ring, alloc event channel. */ ++ err = setup_blkring(dev, info); ++ if (err) ++ goto out; ++ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ goto destroy_blkring; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, ++ "ring-ref","%u", info->ring_ref); ++ if (err) { ++ message = "writing ring-ref"; ++ goto abort_transaction; ++ } ++ err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", ++ irq_to_evtchn_port(info->irq)); ++ if (err) { ++ message = "writing event-channel"; ++ goto abort_transaction; ++ } ++ err = xenbus_printf(xbt, dev->nodename, "protocol", "%s", ++ XEN_IO_PROTO_ABI_NATIVE); ++ if (err) { ++ message = "writing protocol"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err) { ++ if (err == -EAGAIN) ++ goto again; ++ xenbus_dev_fatal(dev, err, "completing transaction"); ++ goto destroy_blkring; ++ } ++ ++ xenbus_switch_state(dev, XenbusStateInitialised); ++ ++ return 0; ++ ++ abort_transaction: ++ xenbus_transaction_end(xbt, 1); ++ if (message) ++ xenbus_dev_fatal(dev, err, "%s", message); ++ destroy_blkring: ++ blkif_free(info, 0); ++ out: ++ return err; ++} ++ ++ ++static int setup_blkring(struct xenbus_device *dev, ++ struct blkfront_info *info) ++{ ++ blkif_sring_t *sring; ++ int err; ++ ++ info->ring_ref = GRANT_INVALID_REF; ++ ++ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL); ++ if (!sring) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); ++ return -ENOMEM; ++ } ++ SHARED_RING_INIT(sring); ++ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); ++ ++ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); ++ if (err < 0) { ++ free_page((unsigned long)sring); ++ info->ring.sring = NULL; ++ goto fail; ++ } ++ info->ring_ref = err; ++ ++ err = bind_listening_port_to_irqhandler( ++ dev->otherend_id, blkif_int, SA_SAMPLE_RANDOM, "blkif", info); ++ if (err <= 0) { ++ xenbus_dev_fatal(dev, err, ++ "bind_listening_port_to_irqhandler"); ++ goto fail; ++ } ++ info->irq = err; ++ ++ return 0; ++fail: ++ blkif_free(info, 0); ++ return err; ++} ++ ++ ++/** ++ * Callback received when the backend's state changes. ++ */ ++static void backend_changed(struct xenbus_device *dev, ++ enum xenbus_state backend_state) ++{ ++ struct blkfront_info *info = dev->dev.driver_data; ++ struct block_device *bd; ++ ++ DPRINTK("blkfront:backend_changed.\n"); ++ ++ switch (backend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitWait: ++ case XenbusStateInitialised: ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ break; ++ ++ case XenbusStateConnected: ++ connect(info); ++ break; ++ ++ case XenbusStateClosing: ++ bd = bdget(info->dev); ++ if (bd == NULL) ++ xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) ++ down(&bd->bd_sem); ++#else ++ mutex_lock(&bd->bd_mutex); ++#endif ++ if (info->users > 0) ++ xenbus_dev_error(dev, -EBUSY, ++ "Device in use; refusing to close"); ++ else ++ blkfront_closing(dev); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) ++ up(&bd->bd_sem); ++#else ++ mutex_unlock(&bd->bd_mutex); ++#endif ++ bdput(bd); ++ break; ++ } ++} ++ ++ ++/* ** Connection ** */ ++ ++ ++/* ++ * Invoked when the backend is finally 'ready' (and has told produced ++ * the details about the physical device - #sectors, size, etc). ++ */ ++static void connect(struct blkfront_info *info) ++{ ++ unsigned long long sectors; ++ unsigned long sector_size; ++ unsigned int binfo; ++ int err; ++ ++ if ((info->connected == BLKIF_STATE_CONNECTED) || ++ (info->connected == BLKIF_STATE_SUSPENDED) ) ++ return; ++ ++ DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend); ++ ++ err = xenbus_gather(XBT_NIL, info->xbdev->otherend, ++ "sectors", "%Lu", §ors, ++ "info", "%u", &binfo, ++ "sector-size", "%lu", §or_size, ++ NULL); ++ if (err) { ++ xenbus_dev_fatal(info->xbdev, err, ++ "reading backend fields at %s", ++ info->xbdev->otherend); ++ return; ++ } ++ ++ err = xenbus_gather(XBT_NIL, info->xbdev->otherend, ++ "feature-barrier", "%lu", &info->feature_barrier, ++ NULL); ++ if (err) ++ info->feature_barrier = 0; ++ ++ err = xlvbd_add(sectors, info->vdevice, binfo, sector_size, info); ++ if (err) { ++ xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", ++ info->xbdev->otherend); ++ return; ++ } ++ ++ (void)xenbus_switch_state(info->xbdev, XenbusStateConnected); ++ ++ /* Kick pending requests. */ ++ spin_lock_irq(&blkif_io_lock); ++ info->connected = BLKIF_STATE_CONNECTED; ++ kick_pending_request_queues(info); ++ spin_unlock_irq(&blkif_io_lock); ++ ++ add_disk(info->gd); ++} ++ ++/** ++ * Handle the change of state of the backend to Closing. We must delete our ++ * device-layer structures now, to ensure that writes are flushed through to ++ * the backend. Once is this done, we can switch to Closed in ++ * acknowledgement. ++ */ ++static void blkfront_closing(struct xenbus_device *dev) ++{ ++ struct blkfront_info *info = dev->dev.driver_data; ++ unsigned long flags; ++ ++ DPRINTK("blkfront_closing: %s removed\n", dev->nodename); ++ ++ if (info->rq == NULL) ++ goto out; ++ ++ spin_lock_irqsave(&blkif_io_lock, flags); ++ /* No more blkif_request(). */ ++ blk_stop_queue(info->rq); ++ /* No more gnttab callback work. */ ++ gnttab_cancel_free_callback(&info->callback); ++ spin_unlock_irqrestore(&blkif_io_lock, flags); ++ ++ /* Flush gnttab callback work. Must be done with no locks held. */ ++ flush_scheduled_work(); ++ ++ xlvbd_del(info); ++ ++ out: ++ xenbus_frontend_closed(dev); ++} ++ ++ ++static int blkfront_remove(struct xenbus_device *dev) ++{ ++ struct blkfront_info *info = dev->dev.driver_data; ++ ++ DPRINTK("blkfront_remove: %s removed\n", dev->nodename); ++ ++ blkif_free(info, 0); ++ ++ kfree(info); ++ ++ return 0; ++} ++ ++ ++static inline int GET_ID_FROM_FREELIST( ++ struct blkfront_info *info) ++{ ++ unsigned long free = info->shadow_free; ++ BUG_ON(free > BLK_RING_SIZE); ++ info->shadow_free = info->shadow[free].req.id; ++ info->shadow[free].req.id = 0x0fffffee; /* debug */ ++ return free; ++} ++ ++static inline void ADD_ID_TO_FREELIST( ++ struct blkfront_info *info, unsigned long id) ++{ ++ info->shadow[id].req.id = info->shadow_free; ++ info->shadow[id].request = 0; ++ info->shadow_free = id; ++} ++ ++static inline void flush_requests(struct blkfront_info *info) ++{ ++ int notify; ++ ++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); ++ ++ if (notify) ++ notify_remote_via_irq(info->irq); ++} ++ ++static void kick_pending_request_queues(struct blkfront_info *info) ++{ ++ if (!RING_FULL(&info->ring)) { ++ /* Re-enable calldowns. */ ++ blk_start_queue(info->rq); ++ /* Kick things off immediately. */ ++ do_blkif_request(info->rq); ++ } ++} ++ ++static void blkif_restart_queue(struct work_struct *work) ++{ ++ struct blkfront_info *info = container_of(work, struct blkfront_info, work); ++ ++ spin_lock_irq(&blkif_io_lock); ++ if (info->connected == BLKIF_STATE_CONNECTED) ++ kick_pending_request_queues(info); ++ spin_unlock_irq(&blkif_io_lock); ++} ++ ++static void blkif_restart_queue_callback(void *arg) ++{ ++ struct blkfront_info *info = (struct blkfront_info *)arg; ++ schedule_work(&info->work); ++} ++ ++int blkif_open(struct inode *inode, struct file *filep) ++{ ++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; ++ info->users++; ++ return 0; ++} ++ ++ ++int blkif_release(struct inode *inode, struct file *filep) ++{ ++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; ++ info->users--; ++ if (info->users == 0) { ++ /* Check whether we have been instructed to close. We will ++ have ignored this request initially, as the device was ++ still mounted. */ ++ struct xenbus_device * dev = info->xbdev; ++ enum xenbus_state state = xenbus_read_driver_state(dev->otherend); ++ ++ if (state == XenbusStateClosing) ++ blkfront_closing(dev); ++ } ++ return 0; ++} ++ ++ ++int blkif_ioctl(struct inode *inode, struct file *filep, ++ unsigned command, unsigned long argument) ++{ ++ int i; ++ ++ DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n", ++ command, (long)argument, inode->i_rdev); ++ ++ switch (command) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++ case HDIO_GETGEO: { ++ struct block_device *bd = inode->i_bdev; ++ struct hd_geometry geo; ++ int ret; ++ ++ if (!argument) ++ return -EINVAL; ++ ++ geo.start = get_start_sect(bd); ++ ret = blkif_getgeo(bd, &geo); ++ if (ret) ++ return ret; ++ ++ if (copy_to_user((struct hd_geometry __user *)argument, &geo, ++ sizeof(geo))) ++ return -EFAULT; ++ ++ return 0; ++ } ++#endif ++ case CDROMMULTISESSION: ++ DPRINTK("FIXME: support multisession CDs later\n"); ++ for (i = 0; i < sizeof(struct cdrom_multisession); i++) ++ if (put_user(0, (char __user *)(argument + i))) ++ return -EFAULT; ++ return 0; ++ ++ default: ++ /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", ++ command);*/ ++ return -EINVAL; /* same return as native Linux */ ++ } ++ ++ return 0; ++} ++ ++ ++int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) ++{ ++ /* We don't have real geometry info, but let's at least return ++ values consistent with the size of the device */ ++ sector_t nsect = get_capacity(bd->bd_disk); ++ sector_t cylinders = nsect; ++ ++ hg->heads = 0xff; ++ hg->sectors = 0x3f; ++ sector_div(cylinders, hg->heads * hg->sectors); ++ hg->cylinders = cylinders; ++ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect) ++ hg->cylinders = 0xffff; ++ return 0; ++} ++ ++ ++/* ++ * blkif_queue_request ++ * ++ * request block io ++ * ++ * id: for guest use only. ++ * operation: BLKIF_OP_{READ,WRITE,PROBE} ++ * buffer: buffer to read/write into. this should be a ++ * virtual address in the guest os. ++ */ ++static int blkif_queue_request(struct request *req) ++{ ++ struct blkfront_info *info = req->rq_disk->private_data; ++ unsigned long buffer_mfn; ++ blkif_request_t *ring_req; ++ struct bio *bio; ++ struct bio_vec *bvec; ++ int idx; ++ unsigned long id; ++ unsigned int fsect, lsect; ++ int ref; ++ grant_ref_t gref_head; ++ ++ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) ++ return 1; ++ ++ if (gnttab_alloc_grant_references( ++ BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { ++ gnttab_request_free_callback( ++ &info->callback, ++ blkif_restart_queue_callback, ++ info, ++ BLKIF_MAX_SEGMENTS_PER_REQUEST); ++ return 1; ++ } ++ ++ /* Fill out a communications ring structure. */ ++ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); ++ id = GET_ID_FROM_FREELIST(info); ++ info->shadow[id].request = (unsigned long)req; ++ ++ ring_req->id = id; ++ ring_req->sector_number = (blkif_sector_t)req->sector; ++ ring_req->handle = info->handle; ++ ++ ring_req->operation = rq_data_dir(req) ? ++ BLKIF_OP_WRITE : BLKIF_OP_READ; ++ if (blk_barrier_rq(req)) ++ ring_req->operation = BLKIF_OP_WRITE_BARRIER; ++ ++ ring_req->nr_segments = 0; ++ rq_for_each_bio (bio, req) { ++ bio_for_each_segment (bvec, bio, idx) { ++ BUG_ON(ring_req->nr_segments ++ == BLKIF_MAX_SEGMENTS_PER_REQUEST); ++ buffer_mfn = page_to_phys(bvec->bv_page) >> PAGE_SHIFT; ++ fsect = bvec->bv_offset >> 9; ++ lsect = fsect + (bvec->bv_len >> 9) - 1; ++ /* install a grant reference. */ ++ ref = gnttab_claim_grant_reference(&gref_head); ++ BUG_ON(ref == -ENOSPC); ++ ++ gnttab_grant_foreign_access_ref( ++ ref, ++ info->xbdev->otherend_id, ++ buffer_mfn, ++ rq_data_dir(req) ); ++ ++ info->shadow[id].frame[ring_req->nr_segments] = ++ mfn_to_pfn(buffer_mfn); ++ ++ ring_req->seg[ring_req->nr_segments] = ++ (struct blkif_request_segment) { ++ .gref = ref, ++ .first_sect = fsect, ++ .last_sect = lsect }; ++ ++ ring_req->nr_segments++; ++ } ++ } ++ ++ info->ring.req_prod_pvt++; ++ ++ /* Keep a private copy so we can reissue requests when recovering. */ ++ info->shadow[id].req = *ring_req; ++ ++ gnttab_free_grant_references(gref_head); ++ ++ return 0; ++} ++ ++/* ++ * do_blkif_request ++ * read a block; request is in a request queue ++ */ ++void do_blkif_request(request_queue_t *rq) ++{ ++ struct blkfront_info *info = NULL; ++ struct request *req; ++ int queued; ++ ++ DPRINTK("Entered do_blkif_request\n"); ++ ++ queued = 0; ++ ++ while ((req = elv_next_request(rq)) != NULL) { ++ info = req->rq_disk->private_data; ++ if (!blk_fs_request(req)) { ++ end_request(req, 0); ++ continue; ++ } ++ ++ if (RING_FULL(&info->ring)) ++ goto wait; ++ ++ DPRINTK("do_blk_req %p: cmd %p, sec %llx, " ++ "(%u/%li) buffer:%p [%s]\n", ++ req, req->cmd, (long long)req->sector, ++ req->current_nr_sectors, ++ req->nr_sectors, req->buffer, ++ rq_data_dir(req) ? "write" : "read"); ++ ++ ++ blkdev_dequeue_request(req); ++ if (blkif_queue_request(req)) { ++ blk_requeue_request(rq, req); ++ wait: ++ /* Avoid pointless unplugs. */ ++ blk_stop_queue(rq); ++ break; ++ } ++ ++ queued++; ++ } ++ ++ if (queued != 0) ++ flush_requests(info); ++} ++ ++ ++static irqreturn_t blkif_int(int irq, void *dev_id) ++{ ++ struct request *req; ++ blkif_response_t *bret; ++ RING_IDX i, rp; ++ unsigned long flags; ++ struct blkfront_info *info = (struct blkfront_info *)dev_id; ++ int uptodate; ++ ++ spin_lock_irqsave(&blkif_io_lock, flags); ++ ++ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { ++ spin_unlock_irqrestore(&blkif_io_lock, flags); ++ return IRQ_HANDLED; ++ } ++ ++ again: ++ rp = info->ring.sring->rsp_prod; ++ rmb(); /* Ensure we see queued responses up to 'rp'. */ ++ ++ for (i = info->ring.rsp_cons; i != rp; i++) { ++ unsigned long id; ++ int ret; ++ ++ bret = RING_GET_RESPONSE(&info->ring, i); ++ id = bret->id; ++ req = (struct request *)info->shadow[id].request; ++ ++ blkif_completion(&info->shadow[id]); ++ ++ ADD_ID_TO_FREELIST(info, id); ++ ++ uptodate = (bret->status == BLKIF_RSP_OKAY); ++ switch (bret->operation) { ++ case BLKIF_OP_WRITE_BARRIER: ++ if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { ++ printk("blkfront: %s: write barrier op failed\n", ++ info->gd->disk_name); ++ uptodate = -EOPNOTSUPP; ++ info->feature_barrier = 0; ++ xlvbd_barrier(info); ++ } ++ /* fall through */ ++ case BLKIF_OP_READ: ++ case BLKIF_OP_WRITE: ++ if (unlikely(bret->status != BLKIF_RSP_OKAY)) ++ DPRINTK("Bad return from blkdev data " ++ "request: %x\n", bret->status); ++ ++ ret = end_that_request_first(req, uptodate, ++ req->hard_nr_sectors); ++ BUG_ON(ret); ++ end_that_request_last(req, uptodate); ++ break; ++ default: ++ BUG(); ++ } ++ } ++ ++ info->ring.rsp_cons = i; ++ ++ if (i != info->ring.req_prod_pvt) { ++ int more_to_do; ++ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); ++ if (more_to_do) ++ goto again; ++ } else ++ info->ring.sring->rsp_event = i + 1; ++ ++ kick_pending_request_queues(info); ++ ++ spin_unlock_irqrestore(&blkif_io_lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static void blkif_free(struct blkfront_info *info, int suspend) ++{ ++ /* Prevent new requests being issued until we fix things up. */ ++ spin_lock_irq(&blkif_io_lock); ++ info->connected = suspend ? ++ BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; ++ /* No more blkif_request(). */ ++ if (info->rq) ++ blk_stop_queue(info->rq); ++ /* No more gnttab callback work. */ ++ gnttab_cancel_free_callback(&info->callback); ++ spin_unlock_irq(&blkif_io_lock); ++ ++ /* Flush gnttab callback work. Must be done with no locks held. */ ++ flush_scheduled_work(); ++ ++ /* Free resources associated with old device channel. */ ++ if (info->ring_ref != GRANT_INVALID_REF) { ++ gnttab_end_foreign_access(info->ring_ref, 0, ++ (unsigned long)info->ring.sring); ++ info->ring_ref = GRANT_INVALID_REF; ++ info->ring.sring = NULL; ++ } ++ if (info->irq) ++ unbind_from_irqhandler(info->irq, info); ++ info->irq = 0; ++} ++ ++static void blkif_completion(struct blk_shadow *s) ++{ ++ int i; ++ for (i = 0; i < s->req.nr_segments; i++) ++ gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL); ++} ++ ++static void blkif_recover(struct blkfront_info *info) ++{ ++ int i; ++ blkif_request_t *req; ++ struct blk_shadow *copy; ++ int j; ++ ++ /* Stage 1: Make a safe copy of the shadow state. */ ++ copy = kmalloc(sizeof(info->shadow), GFP_KERNEL | __GFP_NOFAIL); ++ memcpy(copy, info->shadow, sizeof(info->shadow)); ++ ++ /* Stage 2: Set up free list. */ ++ memset(&info->shadow, 0, sizeof(info->shadow)); ++ for (i = 0; i < BLK_RING_SIZE; i++) ++ info->shadow[i].req.id = i+1; ++ info->shadow_free = info->ring.req_prod_pvt; ++ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; ++ ++ /* Stage 3: Find pending requests and requeue them. */ ++ for (i = 0; i < BLK_RING_SIZE; i++) { ++ /* Not in use? */ ++ if (copy[i].request == 0) ++ continue; ++ ++ /* Grab a request slot and copy shadow state into it. */ ++ req = RING_GET_REQUEST( ++ &info->ring, info->ring.req_prod_pvt); ++ *req = copy[i].req; ++ ++ /* We get a new request id, and must reset the shadow state. */ ++ req->id = GET_ID_FROM_FREELIST(info); ++ memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); ++ ++ /* Rewrite any grant references invalidated by susp/resume. */ ++ for (j = 0; j < req->nr_segments; j++) ++ gnttab_grant_foreign_access_ref( ++ req->seg[j].gref, ++ info->xbdev->otherend_id, ++ pfn_to_mfn(info->shadow[req->id].frame[j]), ++ rq_data_dir( ++ (struct request *) ++ info->shadow[req->id].request)); ++ info->shadow[req->id].req = *req; ++ ++ info->ring.req_prod_pvt++; ++ } ++ ++ kfree(copy); ++ ++ (void)xenbus_switch_state(info->xbdev, XenbusStateConnected); ++ ++ spin_lock_irq(&blkif_io_lock); ++ ++ /* Now safe for us to use the shared ring */ ++ info->connected = BLKIF_STATE_CONNECTED; ++ ++ /* Send off requeued requests */ ++ flush_requests(info); ++ ++ /* Kick any other new requests queued since we resumed */ ++ kick_pending_request_queues(info); ++ ++ spin_unlock_irq(&blkif_io_lock); ++} ++ ++ ++/* ** Driver Registration ** */ ++ ++ ++static struct xenbus_device_id blkfront_ids[] = { ++ { "vbd" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver blkfront = { ++ .name = "vbd", ++ .owner = THIS_MODULE, ++ .ids = blkfront_ids, ++ .probe = blkfront_probe, ++ .remove = blkfront_remove, ++ .resume = blkfront_resume, ++ .otherend_changed = backend_changed, ++}; ++ ++ ++static int __init xlblk_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ return xenbus_register_frontend(&blkfront); ++} ++module_init(xlblk_init); ++ ++ ++static void xlblk_exit(void) ++{ ++ return xenbus_unregister_driver(&blkfront); ++} ++module_exit(xlblk_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkfront/block.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkfront/block.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,142 @@ ++/****************************************************************************** ++ * block.h ++ * ++ * Shared definitions between all levels of XenLinux Virtual block devices. ++ * ++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand ++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge ++ * Copyright (c) 2004-2005, Christian Limpach ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_DRIVERS_BLOCK_H__ ++#define __XEN_DRIVERS_BLOCK_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/hdreg.h> ++#include <linux/blkdev.h> ++#include <linux/major.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <xen/gnttab.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/io/blkif.h> ++#include <xen/interface/io/ring.h> ++#include <asm/io.h> ++#include <asm/atomic.h> ++#include <asm/uaccess.h> ++ ++#define DPRINTK(_f, _a...) pr_debug(_f, ## _a) ++ ++#if 0 ++#define DPRINTK_IOCTL(_f, _a...) printk(KERN_ALERT _f, ## _a) ++#else ++#define DPRINTK_IOCTL(_f, _a...) ((void)0) ++#endif ++ ++struct xlbd_type_info ++{ ++ int partn_shift; ++ int disks_per_major; ++ char *devname; ++ char *diskname; ++}; ++ ++struct xlbd_major_info ++{ ++ int major; ++ int index; ++ int usage; ++ struct xlbd_type_info *type; ++}; ++ ++struct blk_shadow { ++ blkif_request_t req; ++ unsigned long request; ++ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++}; ++ ++#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) ++ ++/* ++ * We have one of these per vbd, whether ide, scsi or 'other'. They ++ * hang in private_data off the gendisk structure. We may end up ++ * putting all kinds of interesting stuff here :-) ++ */ ++struct blkfront_info ++{ ++ struct xenbus_device *xbdev; ++ dev_t dev; ++ struct gendisk *gd; ++ int vdevice; ++ blkif_vdev_t handle; ++ int connected; ++ int ring_ref; ++ blkif_front_ring_t ring; ++ unsigned int irq; ++ struct xlbd_major_info *mi; ++ request_queue_t *rq; ++ struct work_struct work; ++ struct gnttab_free_callback callback; ++ struct blk_shadow shadow[BLK_RING_SIZE]; ++ unsigned long shadow_free; ++ int feature_barrier; ++ ++ /** ++ * The number of people holding this device open. We won't allow a ++ * hot-unplug unless this is 0. ++ */ ++ int users; ++}; ++ ++extern spinlock_t blkif_io_lock; ++ ++extern int blkif_open(struct inode *inode, struct file *filep); ++extern int blkif_release(struct inode *inode, struct file *filep); ++extern int blkif_ioctl(struct inode *inode, struct file *filep, ++ unsigned command, unsigned long argument); ++extern int blkif_getgeo(struct block_device *, struct hd_geometry *); ++extern int blkif_check(dev_t dev); ++extern int blkif_revalidate(dev_t dev); ++extern void do_blkif_request (request_queue_t *rq); ++ ++/* Virtual block-device subsystem. */ ++/* Note that xlvbd_add doesn't call add_disk for you: you're expected ++ to call add_disk on info->gd once the disk is properly connected ++ up. */ ++int xlvbd_add(blkif_sector_t capacity, int device, ++ u16 vdisk_info, u16 sector_size, struct blkfront_info *info); ++void xlvbd_del(struct blkfront_info *info); ++int xlvbd_barrier(struct blkfront_info *info); ++ ++#endif /* __XEN_DRIVERS_BLOCK_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blkfront/vbd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blkfront/vbd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,372 @@ ++/****************************************************************************** ++ * vbd.c ++ * ++ * XenLinux virtual block-device driver (xvd). ++ * ++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand ++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge ++ * Copyright (c) 2004-2005, Christian Limpach ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "block.h" ++#include <linux/blkdev.h> ++#include <linux/list.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#define BLKIF_MAJOR(dev) ((dev)>>8) ++#define BLKIF_MINOR(dev) ((dev) & 0xff) ++ ++/* ++ * For convenience we distinguish between ide, scsi and 'other' (i.e., ++ * potentially combinations of the two) in the naming scheme and in a few other ++ * places. ++ */ ++ ++#define NUM_IDE_MAJORS 10 ++#define NUM_SCSI_MAJORS 17 ++#define NUM_VBD_MAJORS 1 ++ ++static struct xlbd_type_info xlbd_ide_type = { ++ .partn_shift = 6, ++ .disks_per_major = 2, ++ .devname = "ide", ++ .diskname = "hd", ++}; ++ ++static struct xlbd_type_info xlbd_scsi_type = { ++ .partn_shift = 4, ++ .disks_per_major = 16, ++ .devname = "sd", ++ .diskname = "sd", ++}; ++ ++static struct xlbd_type_info xlbd_vbd_type = { ++ .partn_shift = 4, ++ .disks_per_major = 16, ++ .devname = "xvd", ++ .diskname = "xvd", ++}; ++ ++static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS + ++ NUM_VBD_MAJORS]; ++ ++#define XLBD_MAJOR_IDE_START 0 ++#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS) ++#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS) ++ ++#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1 ++#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1 ++#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1 ++ ++/* Information about our VBDs. */ ++#define MAX_VBDS 64 ++static LIST_HEAD(vbds_list); ++ ++static struct block_device_operations xlvbd_block_fops = ++{ ++ .owner = THIS_MODULE, ++ .open = blkif_open, ++ .release = blkif_release, ++ .ioctl = blkif_ioctl, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++ .getgeo = blkif_getgeo ++#endif ++}; ++ ++DEFINE_SPINLOCK(blkif_io_lock); ++ ++static struct xlbd_major_info * ++xlbd_alloc_major_info(int major, int minor, int index) ++{ ++ struct xlbd_major_info *ptr; ++ ++ ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL); ++ if (ptr == NULL) ++ return NULL; ++ ++ ptr->major = major; ++ ++ switch (index) { ++ case XLBD_MAJOR_IDE_RANGE: ++ ptr->type = &xlbd_ide_type; ++ ptr->index = index - XLBD_MAJOR_IDE_START; ++ break; ++ case XLBD_MAJOR_SCSI_RANGE: ++ ptr->type = &xlbd_scsi_type; ++ ptr->index = index - XLBD_MAJOR_SCSI_START; ++ break; ++ case XLBD_MAJOR_VBD_RANGE: ++ ptr->type = &xlbd_vbd_type; ++ ptr->index = index - XLBD_MAJOR_VBD_START; ++ break; ++ } ++ ++ if (register_blkdev(ptr->major, ptr->type->devname)) { ++ kfree(ptr); ++ return NULL; ++ } ++ ++ printk("xen-vbd: registered block device major %i\n", ptr->major); ++ major_info[index] = ptr; ++ return ptr; ++} ++ ++static struct xlbd_major_info * ++xlbd_get_major_info(int vdevice) ++{ ++ struct xlbd_major_info *mi; ++ int major, minor, index; ++ ++ major = BLKIF_MAJOR(vdevice); ++ minor = BLKIF_MINOR(vdevice); ++ ++ switch (major) { ++ case IDE0_MAJOR: index = 0; break; ++ case IDE1_MAJOR: index = 1; break; ++ case IDE2_MAJOR: index = 2; break; ++ case IDE3_MAJOR: index = 3; break; ++ case IDE4_MAJOR: index = 4; break; ++ case IDE5_MAJOR: index = 5; break; ++ case IDE6_MAJOR: index = 6; break; ++ case IDE7_MAJOR: index = 7; break; ++ case IDE8_MAJOR: index = 8; break; ++ case IDE9_MAJOR: index = 9; break; ++ case SCSI_DISK0_MAJOR: index = 10; break; ++ case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR: ++ index = 11 + major - SCSI_DISK1_MAJOR; ++ break; ++ case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR: ++ index = 18 + major - SCSI_DISK8_MAJOR; ++ break; ++ case SCSI_CDROM_MAJOR: index = 26; break; ++ default: index = 27; break; ++ } ++ ++ mi = ((major_info[index] != NULL) ? major_info[index] : ++ xlbd_alloc_major_info(major, minor, index)); ++ if (mi) ++ mi->usage++; ++ return mi; ++} ++ ++static void ++xlbd_put_major_info(struct xlbd_major_info *mi) ++{ ++ mi->usage--; ++ /* XXX: release major if 0 */ ++} ++ ++static int ++xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) ++{ ++ request_queue_t *rq; ++ ++ rq = blk_init_queue(do_blkif_request, &blkif_io_lock); ++ if (rq == NULL) ++ return -1; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) ++ elevator_init(rq, "noop"); ++#else ++ elevator_init(rq, &elevator_noop); ++#endif ++ ++ /* Hard sector size and max sectors impersonate the equiv. hardware. */ ++ blk_queue_hardsect_size(rq, sector_size); ++ blk_queue_max_sectors(rq, 512); ++ ++ /* Each segment in a request is up to an aligned page in size. */ ++ blk_queue_segment_boundary(rq, PAGE_SIZE - 1); ++ blk_queue_max_segment_size(rq, PAGE_SIZE); ++ ++ /* Ensure a merged request will fit in a single I/O ring slot. */ ++ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST); ++ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST); ++ ++ /* Make sure buffer addresses are sector-aligned. */ ++ blk_queue_dma_alignment(rq, 511); ++ ++ gd->queue = rq; ++ ++ return 0; ++} ++ ++static int ++xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice, ++ u16 vdisk_info, u16 sector_size, ++ struct blkfront_info *info) ++{ ++ struct gendisk *gd; ++ struct xlbd_major_info *mi; ++ int nr_minors = 1; ++ int err = -ENODEV; ++ unsigned int offset; ++ ++ BUG_ON(info->gd != NULL); ++ BUG_ON(info->mi != NULL); ++ BUG_ON(info->rq != NULL); ++ ++ mi = xlbd_get_major_info(vdevice); ++ if (mi == NULL) ++ goto out; ++ info->mi = mi; ++ ++ if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0) ++ nr_minors = 1 << mi->type->partn_shift; ++ ++ gd = alloc_disk(nr_minors); ++ if (gd == NULL) ++ goto out; ++ ++ offset = mi->index * mi->type->disks_per_major + ++ (minor >> mi->type->partn_shift); ++ if (nr_minors > 1) { ++ if (offset < 26) { ++ sprintf(gd->disk_name, "%s%c", ++ mi->type->diskname, 'a' + offset ); ++ } ++ else { ++ sprintf(gd->disk_name, "%s%c%c", ++ mi->type->diskname, ++ 'a' + ((offset/26)-1), 'a' + (offset%26) ); ++ } ++ } ++ else { ++ if (offset < 26) { ++ sprintf(gd->disk_name, "%s%c%d", ++ mi->type->diskname, ++ 'a' + offset, ++ minor & ((1 << mi->type->partn_shift) - 1)); ++ } ++ else { ++ sprintf(gd->disk_name, "%s%c%c%d", ++ mi->type->diskname, ++ 'a' + ((offset/26)-1), 'a' + (offset%26), ++ minor & ((1 << mi->type->partn_shift) - 1)); ++ } ++ } ++ ++ gd->major = mi->major; ++ gd->first_minor = minor; ++ gd->fops = &xlvbd_block_fops; ++ gd->private_data = info; ++ gd->driverfs_dev = &(info->xbdev->dev); ++ set_capacity(gd, capacity); ++ ++ if (xlvbd_init_blk_queue(gd, sector_size)) { ++ del_gendisk(gd); ++ goto out; ++ } ++ ++ info->rq = gd->queue; ++ info->gd = gd; ++ ++ if (info->feature_barrier) ++ xlvbd_barrier(info); ++ ++ if (vdisk_info & VDISK_READONLY) ++ set_disk_ro(gd, 1); ++ ++ if (vdisk_info & VDISK_REMOVABLE) ++ gd->flags |= GENHD_FL_REMOVABLE; ++ ++ if (vdisk_info & VDISK_CDROM) ++ gd->flags |= GENHD_FL_CD; ++ ++ return 0; ++ ++ out: ++ if (mi) ++ xlbd_put_major_info(mi); ++ info->mi = NULL; ++ return err; ++} ++ ++int ++xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info, ++ u16 sector_size, struct blkfront_info *info) ++{ ++ struct block_device *bd; ++ int err = 0; ++ ++ info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice)); ++ ++ bd = bdget(info->dev); ++ if (bd == NULL) ++ return -ENODEV; ++ ++ err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice, ++ vdisk_info, sector_size, info); ++ ++ bdput(bd); ++ return err; ++} ++ ++void ++xlvbd_del(struct blkfront_info *info) ++{ ++ if (info->mi == NULL) ++ return; ++ ++ BUG_ON(info->gd == NULL); ++ del_gendisk(info->gd); ++ put_disk(info->gd); ++ info->gd = NULL; ++ ++ xlbd_put_major_info(info->mi); ++ info->mi = NULL; ++ ++ BUG_ON(info->rq == NULL); ++ blk_cleanup_queue(info->rq); ++ info->rq = NULL; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++int ++xlvbd_barrier(struct blkfront_info *info) ++{ ++ int err; ++ ++ err = blk_queue_ordered(info->rq, ++ info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE, NULL); ++ if (err) ++ return err; ++ printk("blkfront: %s: barriers %s\n", ++ info->gd->disk_name, info->feature_barrier ? "enabled" : "disabled"); ++ return 0; ++} ++#else ++int ++xlvbd_barrier(struct blkfront_info *info) ++{ ++ printk("blkfront: %s: barriers disabled\n", info->gd->disk_name); ++ return -ENOSYS; ++} ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blktap/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blktap/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++LINUXINCLUDE += -I../xen/include/public/io ++ ++obj-$(CONFIG_XEN_BLKDEV_TAP) := xenblktap.o ++ ++xenblktap-y := xenbus.o interface.o blktap.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blktap/blktap.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blktap/blktap.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1524 @@ ++/****************************************************************************** ++ * drivers/xen/blktap/blktap.c ++ * ++ * Back-end driver for user level virtual block devices. This portion of the ++ * driver exports a 'unified' block-device interface that can be accessed ++ * by any operating system that implements a compatible front end. Requests ++ * are remapped to a user-space memory region. ++ * ++ * Based on the blkback driver code. ++ * ++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield ++ * ++ * Clean ups and fix ups: ++ * Copyright (c) 2006, Steven Rostedt - Red Hat, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/spinlock.h> ++#include <linux/kthread.h> ++#include <linux/list.h> ++#include <asm/hypervisor.h> ++#include "common.h" ++#include <xen/balloon.h> ++#include <xen/driver_util.h> ++#include <linux/kernel.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/errno.h> ++#include <linux/major.h> ++#include <linux/gfp.h> ++#include <linux/poll.h> ++#include <linux/init.h> ++#include <asm/tlbflush.h> ++ ++#define MAX_TAP_DEV 256 /*the maximum number of tapdisk ring devices */ ++#define MAX_DEV_NAME 100 /*the max tapdisk ring device name e.g. blktap0 */ ++ ++/* ++ * The maximum number of requests that can be outstanding at any time ++ * is determined by ++ * ++ * [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST] ++ * ++ * where mmap_alloc < MAX_DYNAMIC_MEM. ++ * ++ * TODO: ++ * mmap_alloc is initialised to 2 and should be adjustable on the fly via ++ * sysfs. ++ */ ++#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) ++#define MAX_DYNAMIC_MEM BLK_RING_SIZE ++#define MAX_PENDING_REQS BLK_RING_SIZE ++#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST) ++#define MMAP_VADDR(_start, _req,_seg) \ ++ (_start + \ ++ ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \ ++ ((_seg) * PAGE_SIZE)) ++static int blkif_reqs = MAX_PENDING_REQS; ++module_param(blkif_reqs, int, 0); ++ ++static int mmap_pages = MMAP_PAGES; ++ ++#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we ++ * have a bunch of pages reserved for shared ++ * memory rings. ++ */ ++ ++/*Data struct handed back to userspace for tapdisk device to VBD mapping*/ ++typedef struct domid_translate { ++ unsigned short domid; ++ unsigned short busid; ++} domid_translate_t ; ++ ++/*Data struct associated with each of the tapdisk devices*/ ++typedef struct tap_blkif { ++ struct vm_area_struct *vma; /*Shared memory area */ ++ unsigned long rings_vstart; /*Kernel memory mapping */ ++ unsigned long user_vstart; /*User memory mapping */ ++ unsigned long dev_inuse; /*One process opens device at a time. */ ++ unsigned long dev_pending; /*In process of being opened */ ++ unsigned long ring_ok; /*make this ring->state */ ++ blkif_front_ring_t ufe_ring; /*Rings up to user space. */ ++ wait_queue_head_t wait; /*for poll */ ++ unsigned long mode; /*current switching mode */ ++ int minor; /*Minor number for tapdisk device */ ++ pid_t pid; /*tapdisk process id */ ++ enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace ++ shutdown */ ++ unsigned long *idx_map; /*Record the user ring id to kern ++ [req id, idx] tuple */ ++ blkif_t *blkif; /*Associate blkif with tapdev */ ++ struct domid_translate trans; /*Translation from domid to bus. */ ++} tap_blkif_t; ++ ++static struct tap_blkif *tapfds[MAX_TAP_DEV]; ++static int blktap_next_minor; ++ ++/* Run-time switchable: /sys/module/blktap/parameters/ */ ++static unsigned int log_stats = 0; ++static unsigned int debug_lvl = 0; ++module_param(log_stats, int, 0644); ++module_param(debug_lvl, int, 0644); ++ ++/* ++ * Each outstanding request that we've passed to the lower device layers has a ++ * 'pending_req' allocated to it. Each buffer_head that completes decrements ++ * the pendcnt towards zero. When it hits zero, the specified domain has a ++ * response queued for it, with the saved 'id' passed back. ++ */ ++typedef struct { ++ blkif_t *blkif; ++ u64 id; ++ unsigned short mem_idx; ++ int nr_pages; ++ atomic_t pendcnt; ++ unsigned short operation; ++ int status; ++ struct list_head free_list; ++ int inuse; ++} pending_req_t; ++ ++static pending_req_t *pending_reqs[MAX_PENDING_REQS]; ++static struct list_head pending_free; ++static DEFINE_SPINLOCK(pending_free_lock); ++static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq); ++static int alloc_pending_reqs; ++ ++typedef unsigned int PEND_RING_IDX; ++ ++static inline int MASK_PEND_IDX(int i) { ++ return (i & (MAX_PENDING_REQS-1)); ++} ++ ++static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) { ++ return (req - pending_reqs[idx]); ++} ++ ++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) ++ ++#define BLKBACK_INVALID_HANDLE (~0) ++ ++static struct page **foreign_pages[MAX_DYNAMIC_MEM]; ++static inline unsigned long idx_to_kaddr( ++ unsigned int mmap_idx, unsigned int req_idx, unsigned int sg_idx) ++{ ++ unsigned int arr_idx = req_idx*BLKIF_MAX_SEGMENTS_PER_REQUEST + sg_idx; ++ unsigned long pfn = page_to_pfn(foreign_pages[mmap_idx][arr_idx]); ++ return (unsigned long)pfn_to_kaddr(pfn); ++} ++ ++static unsigned short mmap_alloc = 0; ++static unsigned short mmap_lock = 0; ++static unsigned short mmap_inuse = 0; ++ ++/****************************************************************** ++ * GRANT HANDLES ++ */ ++ ++/* When using grant tables to map a frame for device access then the ++ * handle returned must be used to unmap the frame. This is needed to ++ * drop the ref count on the frame. ++ */ ++struct grant_handle_pair ++{ ++ grant_handle_t kernel; ++ grant_handle_t user; ++}; ++#define INVALID_GRANT_HANDLE 0xFFFF ++ ++static struct grant_handle_pair ++ pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES]; ++#define pending_handle(_id, _idx, _i) \ ++ (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \ ++ + (_i)]) ++ ++ ++static int blktap_read_ufe_ring(tap_blkif_t *info); /*local prototypes*/ ++ ++#define BLKTAP_MINOR 0 /*/dev/xen/blktap has a dynamic major */ ++#define BLKTAP_DEV_DIR "/dev/xen" ++ ++static int blktap_major; ++ ++/* blktap IOCTLs: */ ++#define BLKTAP_IOCTL_KICK_FE 1 ++#define BLKTAP_IOCTL_KICK_BE 2 /* currently unused */ ++#define BLKTAP_IOCTL_SETMODE 3 ++#define BLKTAP_IOCTL_SENDPID 4 ++#define BLKTAP_IOCTL_NEWINTF 5 ++#define BLKTAP_IOCTL_MINOR 6 ++#define BLKTAP_IOCTL_MAJOR 7 ++#define BLKTAP_QUERY_ALLOC_REQS 8 ++#define BLKTAP_IOCTL_FREEINTF 9 ++#define BLKTAP_IOCTL_PRINT_IDXS 100 ++ ++/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */ ++#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */ ++#define BLKTAP_MODE_INTERCEPT_FE 0x00000001 ++#define BLKTAP_MODE_INTERCEPT_BE 0x00000002 /* unimp. */ ++ ++#define BLKTAP_MODE_INTERPOSE \ ++ (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE) ++ ++ ++static inline int BLKTAP_MODE_VALID(unsigned long arg) ++{ ++ return ((arg == BLKTAP_MODE_PASSTHROUGH ) || ++ (arg == BLKTAP_MODE_INTERCEPT_FE) || ++ (arg == BLKTAP_MODE_INTERPOSE )); ++} ++ ++/* Requests passing through the tap to userspace are re-assigned an ID. ++ * We must record a mapping between the BE [IDX,ID] tuple and the userspace ++ * ring ID. ++ */ ++ ++static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx) ++{ ++ return ((fe_dom << 16) | MASK_PEND_IDX(idx)); ++} ++ ++extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id) ++{ ++ return (PEND_RING_IDX)(id & 0x0000ffff); ++} ++ ++extern inline int ID_TO_MIDX(unsigned long id) ++{ ++ return (int)(id >> 16); ++} ++ ++#define INVALID_REQ 0xdead0000 ++ ++/*TODO: Convert to a free list*/ ++static inline int GET_NEXT_REQ(unsigned long *idx_map) ++{ ++ int i; ++ for (i = 0; i < MAX_PENDING_REQS; i++) ++ if (idx_map[i] == INVALID_REQ) ++ return i; ++ ++ return INVALID_REQ; ++} ++ ++ ++#define BLKTAP_INVALID_HANDLE(_g) \ ++ (((_g->kernel) == INVALID_GRANT_HANDLE) && \ ++ ((_g->user) == INVALID_GRANT_HANDLE)) ++ ++#define BLKTAP_INVALIDATE_HANDLE(_g) do { \ ++ (_g)->kernel = INVALID_GRANT_HANDLE; (_g)->user = INVALID_GRANT_HANDLE; \ ++ } while(0) ++ ++ ++/****************************************************************** ++ * BLKTAP VM OPS ++ */ ++ ++static struct page *blktap_nopage(struct vm_area_struct *vma, ++ unsigned long address, ++ int *type) ++{ ++ /* ++ * if the page has not been mapped in by the driver then return ++ * NOPAGE_SIGBUS to the domain. ++ */ ++ ++ return NOPAGE_SIGBUS; ++} ++ ++struct vm_operations_struct blktap_vm_ops = { ++ nopage: blktap_nopage, ++}; ++ ++/****************************************************************** ++ * BLKTAP FILE OPS ++ */ ++ ++/*Function Declarations*/ ++static tap_blkif_t *get_next_free_dev(void); ++static int blktap_open(struct inode *inode, struct file *filp); ++static int blktap_release(struct inode *inode, struct file *filp); ++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma); ++static int blktap_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg); ++static unsigned int blktap_poll(struct file *file, poll_table *wait); ++ ++static const struct file_operations blktap_fops = { ++ .owner = THIS_MODULE, ++ .poll = blktap_poll, ++ .ioctl = blktap_ioctl, ++ .open = blktap_open, ++ .release = blktap_release, ++ .mmap = blktap_mmap, ++}; ++ ++ ++static tap_blkif_t *get_next_free_dev(void) ++{ ++ struct class *class; ++ tap_blkif_t *info; ++ int minor; ++ ++ /* ++ * This is called only from the ioctl, which ++ * means we should always have interrupts enabled. ++ */ ++ BUG_ON(irqs_disabled()); ++ ++ spin_lock_irq(&pending_free_lock); ++ ++ /* tapfds[0] is always NULL */ ++ ++ for (minor = 1; minor < blktap_next_minor; minor++) { ++ info = tapfds[minor]; ++ /* we could have failed a previous attempt. */ ++ if (!info || ++ ((info->dev_inuse == 0) && ++ (info->dev_pending == 0)) ) { ++ info->dev_pending = 1; ++ goto found; ++ } ++ } ++ info = NULL; ++ minor = -1; ++ ++ /* ++ * We didn't find free device. If we can still allocate ++ * more, then we grab the next device minor that is ++ * available. This is done while we are still under ++ * the protection of the pending_free_lock. ++ */ ++ if (blktap_next_minor < MAX_TAP_DEV) ++ minor = blktap_next_minor++; ++found: ++ spin_unlock_irq(&pending_free_lock); ++ ++ if (!info && minor > 0) { ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (unlikely(!info)) { ++ /* ++ * If we failed here, try to put back ++ * the next minor number. But if one ++ * was just taken, then we just lose this ++ * minor. We can try to allocate this ++ * minor again later. ++ */ ++ spin_lock_irq(&pending_free_lock); ++ if (blktap_next_minor == minor+1) ++ blktap_next_minor--; ++ spin_unlock_irq(&pending_free_lock); ++ goto out; ++ } ++ ++ info->minor = minor; ++ /* ++ * Make sure that we have a minor before others can ++ * see us. ++ */ ++ wmb(); ++ tapfds[minor] = info; ++ ++ if ((class = get_xen_class()) != NULL) ++ class_device_create(class, NULL, ++ MKDEV(blktap_major, minor), NULL, ++ "blktap%d", minor); ++ } ++ ++out: ++ return info; ++} ++ ++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif) ++{ ++ tap_blkif_t *info; ++ int i; ++ ++ for (i = 1; i < blktap_next_minor; i++) { ++ info = tapfds[i]; ++ if ( info && ++ (info->trans.domid == domid) && ++ (info->trans.busid == xenbus_id) ) { ++ info->blkif = blkif; ++ info->status = RUNNING; ++ return i; ++ } ++ } ++ return -1; ++} ++ ++void signal_tapdisk(int idx) ++{ ++ tap_blkif_t *info; ++ struct task_struct *ptask; ++ ++ info = tapfds[idx]; ++ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) ++ return; ++ ++ if (info->pid > 0) { ++ ptask = find_task_by_pid(info->pid); ++ if (ptask) ++ info->status = CLEANSHUTDOWN; ++ } ++ info->blkif = NULL; ++ ++ return; ++} ++ ++static int blktap_open(struct inode *inode, struct file *filp) ++{ ++ blkif_sring_t *sring; ++ int idx = iminor(inode) - BLKTAP_MINOR; ++ tap_blkif_t *info; ++ int i; ++ ++ /* ctrl device, treat differently */ ++ if (!idx) ++ return 0; ++ ++ info = tapfds[idx]; ++ ++ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) { ++ WPRINTK("Unable to open device /dev/xen/blktap%d\n", ++ idx); ++ return -ENODEV; ++ } ++ ++ DPRINTK("Opening device /dev/xen/blktap%d\n",idx); ++ ++ /*Only one process can access device at a time*/ ++ if (test_and_set_bit(0, &info->dev_inuse)) ++ return -EBUSY; ++ ++ info->dev_pending = 0; ++ ++ /* Allocate the fe ring. */ ++ sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL); ++ if (sring == NULL) ++ goto fail_nomem; ++ ++ SetPageReserved(virt_to_page(sring)); ++ ++ SHARED_RING_INIT(sring); ++ FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE); ++ ++ filp->private_data = info; ++ info->vma = NULL; ++ ++ info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, ++ GFP_KERNEL); ++ ++ if (idx > 0) { ++ init_waitqueue_head(&info->wait); ++ for (i = 0; i < MAX_PENDING_REQS; i++) ++ info->idx_map[i] = INVALID_REQ; ++ } ++ ++ DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx); ++ return 0; ++ ++ fail_nomem: ++ return -ENOMEM; ++} ++ ++static int blktap_release(struct inode *inode, struct file *filp) ++{ ++ tap_blkif_t *info = filp->private_data; ++ ++ /* check for control device */ ++ if (!info) ++ return 0; ++ ++ info->dev_inuse = 0; ++ DPRINTK("Freeing device [/dev/xen/blktap%d]\n",info->minor); ++ ++ /* Free the ring page. */ ++ ClearPageReserved(virt_to_page(info->ufe_ring.sring)); ++ free_page((unsigned long) info->ufe_ring.sring); ++ ++ /* Clear any active mappings and free foreign map table */ ++ if (info->vma) { ++ zap_page_range( ++ info->vma, info->vma->vm_start, ++ info->vma->vm_end - info->vma->vm_start, NULL); ++ info->vma = NULL; ++ } ++ ++ if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) { ++ if (info->blkif->xenblkd != NULL) { ++ kthread_stop(info->blkif->xenblkd); ++ info->blkif->xenblkd = NULL; ++ } ++ info->status = CLEANSHUTDOWN; ++ } ++ return 0; ++} ++ ++ ++/* Note on mmap: ++ * We need to map pages to user space in a way that will allow the block ++ * subsystem set up direct IO to them. This couldn't be done before, because ++ * there isn't really a sane way to translate a user virtual address down to a ++ * physical address when the page belongs to another domain. ++ * ++ * My first approach was to map the page in to kernel memory, add an entry ++ * for it in the physical frame list (using alloc_lomem_region as in blkback) ++ * and then attempt to map that page up to user space. This is disallowed ++ * by xen though, which realizes that we don't really own the machine frame ++ * underlying the physical page. ++ * ++ * The new approach is to provide explicit support for this in xen linux. ++ * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages ++ * mapped from other vms. vma->vm_private_data is set up as a mapping ++ * from pages to actual page structs. There is a new clause in get_user_pages ++ * that does the right thing for this sort of mapping. ++ */ ++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ int size; ++ struct page **map; ++ int i; ++ tap_blkif_t *info = filp->private_data; ++ ++ if (info == NULL) { ++ WPRINTK("blktap: mmap, retrieving idx failed\n"); ++ return -ENOMEM; ++ } ++ ++ vma->vm_flags |= VM_RESERVED; ++ vma->vm_ops = &blktap_vm_ops; ++ ++ size = vma->vm_end - vma->vm_start; ++ if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) { ++ WPRINTK("you _must_ map exactly %d pages!\n", ++ mmap_pages + RING_PAGES); ++ return -EAGAIN; ++ } ++ ++ size >>= PAGE_SHIFT; ++ info->rings_vstart = vma->vm_start; ++ info->user_vstart = info->rings_vstart + (RING_PAGES << PAGE_SHIFT); ++ ++ /* Map the ring pages to the start of the region and reserve it. */ ++ if (remap_pfn_range(vma, vma->vm_start, ++ __pa(info->ufe_ring.sring) >> PAGE_SHIFT, ++ PAGE_SIZE, vma->vm_page_prot)) { ++ WPRINTK("Mapping user ring failed!\n"); ++ goto fail; ++ } ++ ++ /* Mark this VM as containing foreign pages, and set up mappings. */ ++ map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) ++ * sizeof(struct page_struct*), ++ GFP_KERNEL); ++ if (map == NULL) { ++ WPRINTK("Couldn't alloc VM_FOREIGN map.\n"); ++ goto fail; ++ } ++ ++ for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++) ++ map[i] = NULL; ++ ++ vma->vm_private_data = map; ++ vma->vm_flags |= VM_FOREIGN; ++ ++ info->vma = vma; ++ info->ring_ok = 1; ++ return 0; ++ fail: ++ /* Clear any active mappings. */ ++ zap_page_range(vma, vma->vm_start, ++ vma->vm_end - vma->vm_start, NULL); ++ ++ return -ENOMEM; ++} ++ ++ ++static int blktap_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ tap_blkif_t *info = filp->private_data; ++ ++ switch(cmd) { ++ case BLKTAP_IOCTL_KICK_FE: ++ { ++ /* There are fe messages to process. */ ++ return blktap_read_ufe_ring(info); ++ } ++ case BLKTAP_IOCTL_SETMODE: ++ { ++ if (info) { ++ if (BLKTAP_MODE_VALID(arg)) { ++ info->mode = arg; ++ /* XXX: may need to flush rings here. */ ++ DPRINTK("blktap: set mode to %lx\n", ++ arg); ++ return 0; ++ } ++ } ++ return 0; ++ } ++ case BLKTAP_IOCTL_PRINT_IDXS: ++ { ++ if (info) { ++ printk("User Rings: \n-----------\n"); ++ printk("UF: rsp_cons: %2d, req_prod_prv: %2d " ++ "| req_prod: %2d, rsp_prod: %2d\n", ++ info->ufe_ring.rsp_cons, ++ info->ufe_ring.req_prod_pvt, ++ info->ufe_ring.sring->req_prod, ++ info->ufe_ring.sring->rsp_prod); ++ } ++ return 0; ++ } ++ case BLKTAP_IOCTL_SENDPID: ++ { ++ if (info) { ++ info->pid = (pid_t)arg; ++ DPRINTK("blktap: pid received %d\n", ++ info->pid); ++ } ++ return 0; ++ } ++ case BLKTAP_IOCTL_NEWINTF: ++ { ++ uint64_t val = (uint64_t)arg; ++ domid_translate_t *tr = (domid_translate_t *)&val; ++ ++ DPRINTK("NEWINTF Req for domid %d and bus id %d\n", ++ tr->domid, tr->busid); ++ info = get_next_free_dev(); ++ if (!info) { ++ WPRINTK("Error initialising /dev/xen/blktap - " ++ "No more devices\n"); ++ return -1; ++ } ++ info->trans.domid = tr->domid; ++ info->trans.busid = tr->busid; ++ return info->minor; ++ } ++ case BLKTAP_IOCTL_FREEINTF: ++ { ++ unsigned long dev = arg; ++ unsigned long flags; ++ ++ info = tapfds[dev]; ++ ++ if ((dev > MAX_TAP_DEV) || !info) ++ return 0; /* should this be an error? */ ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ if (info->dev_pending) ++ info->dev_pending = 0; ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ return 0; ++ } ++ case BLKTAP_IOCTL_MINOR: ++ { ++ unsigned long dev = arg; ++ ++ info = tapfds[dev]; ++ ++ if ((dev > MAX_TAP_DEV) || !info) ++ return -EINVAL; ++ ++ return info->minor; ++ } ++ case BLKTAP_IOCTL_MAJOR: ++ return blktap_major; ++ ++ case BLKTAP_QUERY_ALLOC_REQS: ++ { ++ WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n", ++ alloc_pending_reqs, blkif_reqs); ++ return (alloc_pending_reqs/blkif_reqs) * 100; ++ } ++ } ++ return -ENOIOCTLCMD; ++} ++ ++static unsigned int blktap_poll(struct file *filp, poll_table *wait) ++{ ++ tap_blkif_t *info = filp->private_data; ++ ++ /* do not work on the control device */ ++ if (!info) ++ return 0; ++ ++ poll_wait(filp, &info->wait, wait); ++ if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) { ++ RING_PUSH_REQUESTS(&info->ufe_ring); ++ return POLLIN | POLLRDNORM; ++ } ++ return 0; ++} ++ ++void blktap_kick_user(int idx) ++{ ++ tap_blkif_t *info; ++ ++ info = tapfds[idx]; ++ ++ if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) ++ return; ++ ++ wake_up_interruptible(&info->wait); ++ ++ return; ++} ++ ++static int do_block_io_op(blkif_t *blkif); ++static void dispatch_rw_block_io(blkif_t *blkif, ++ blkif_request_t *req, ++ pending_req_t *pending_req); ++static void make_response(blkif_t *blkif, u64 id, ++ unsigned short op, int st); ++ ++/****************************************************************** ++ * misc small helpers ++ */ ++static int req_increase(void) ++{ ++ int i, j; ++ ++ if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock) ++ return -EINVAL; ++ ++ pending_reqs[mmap_alloc] = kzalloc(sizeof(pending_req_t) ++ * blkif_reqs, GFP_KERNEL); ++ foreign_pages[mmap_alloc] = alloc_empty_pages_and_pagevec(mmap_pages); ++ ++ if (!pending_reqs[mmap_alloc] || !foreign_pages[mmap_alloc]) ++ goto out_of_memory; ++ ++ DPRINTK("%s: reqs=%d, pages=%d\n", ++ __FUNCTION__, blkif_reqs, mmap_pages); ++ ++ for (i = 0; i < MAX_PENDING_REQS; i++) { ++ list_add_tail(&pending_reqs[mmap_alloc][i].free_list, ++ &pending_free); ++ pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc; ++ for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++) ++ BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc, ++ i, j)); ++ } ++ ++ mmap_alloc++; ++ DPRINTK("# MMAPs increased to %d\n",mmap_alloc); ++ return 0; ++ ++ out_of_memory: ++ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages); ++ kfree(pending_reqs[mmap_alloc]); ++ WPRINTK("%s: out of memory\n", __FUNCTION__); ++ return -ENOMEM; ++} ++ ++static void mmap_req_del(int mmap) ++{ ++ BUG_ON(!spin_is_locked(&pending_free_lock)); ++ ++ kfree(pending_reqs[mmap]); ++ pending_reqs[mmap] = NULL; ++ ++ free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages); ++ foreign_pages[mmap] = NULL; ++ ++ mmap_lock = 0; ++ DPRINTK("# MMAPs decreased to %d\n",mmap_alloc); ++ mmap_alloc--; ++} ++ ++static pending_req_t* alloc_req(void) ++{ ++ pending_req_t *req = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ ++ if (!list_empty(&pending_free)) { ++ req = list_entry(pending_free.next, pending_req_t, free_list); ++ list_del(&req->free_list); ++ } ++ ++ if (req) { ++ req->inuse = 1; ++ alloc_pending_reqs++; ++ } ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ return req; ++} ++ ++static void free_req(pending_req_t *req) ++{ ++ unsigned long flags; ++ int was_empty; ++ ++ spin_lock_irqsave(&pending_free_lock, flags); ++ ++ alloc_pending_reqs--; ++ req->inuse = 0; ++ if (mmap_lock && (req->mem_idx == mmap_alloc-1)) { ++ mmap_inuse--; ++ if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1); ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ return; ++ } ++ was_empty = list_empty(&pending_free); ++ list_add(&req->free_list, &pending_free); ++ ++ spin_unlock_irqrestore(&pending_free_lock, flags); ++ ++ if (was_empty) ++ wake_up(&pending_free_wq); ++} ++ ++static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, ++ int tapidx) ++{ ++ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2]; ++ unsigned int i, invcount = 0; ++ struct grant_handle_pair *khandle; ++ uint64_t ptep; ++ int ret, mmap_idx; ++ unsigned long kvaddr, uvaddr; ++ tap_blkif_t *info; ++ ++ ++ info = tapfds[tapidx]; ++ ++ if ((tapidx < 0) || (tapidx > MAX_TAP_DEV) || !info) { ++ WPRINTK("fast_flush: Couldn't get info!\n"); ++ return; ++ } ++ ++ if (info->vma != NULL && ++ xen_feature(XENFEAT_auto_translated_physmap)) { ++ down_write(&info->vma->vm_mm->mmap_sem); ++ zap_page_range(info->vma, ++ MMAP_VADDR(info->user_vstart, u_idx, 0), ++ req->nr_pages << PAGE_SHIFT, NULL); ++ up_write(&info->vma->vm_mm->mmap_sem); ++ } ++ ++ mmap_idx = req->mem_idx; ++ ++ for (i = 0; i < req->nr_pages; i++) { ++ kvaddr = idx_to_kaddr(mmap_idx, k_idx, i); ++ uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i); ++ ++ khandle = &pending_handle(mmap_idx, k_idx, i); ++ ++ if (khandle->kernel != INVALID_GRANT_HANDLE) { ++ gnttab_set_unmap_op(&unmap[invcount], ++ idx_to_kaddr(mmap_idx, k_idx, i), ++ GNTMAP_host_map, khandle->kernel); ++ invcount++; ++ } ++ ++ if (khandle->user != INVALID_GRANT_HANDLE) { ++ BUG_ON(xen_feature(XENFEAT_auto_translated_physmap)); ++ if (create_lookup_pte_addr( ++ info->vma->vm_mm, ++ MMAP_VADDR(info->user_vstart, u_idx, i), ++ &ptep) !=0) { ++ WPRINTK("Couldn't get a pte addr!\n"); ++ return; ++ } ++ ++ gnttab_set_unmap_op(&unmap[invcount], ptep, ++ GNTMAP_host_map ++ | GNTMAP_application_map ++ | GNTMAP_contains_pte, ++ khandle->user); ++ invcount++; ++ } ++ ++ BLKTAP_INVALIDATE_HANDLE(khandle); ++ } ++ ret = HYPERVISOR_grant_table_op( ++ GNTTABOP_unmap_grant_ref, unmap, invcount); ++ BUG_ON(ret); ++ ++ if (info->vma != NULL && !xen_feature(XENFEAT_auto_translated_physmap)) ++ zap_page_range(info->vma, ++ MMAP_VADDR(info->user_vstart, u_idx, 0), ++ req->nr_pages << PAGE_SHIFT, NULL); ++} ++ ++/****************************************************************** ++ * SCHEDULER FUNCTIONS ++ */ ++ ++static void print_stats(blkif_t *blkif) ++{ ++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n", ++ current->comm, blkif->st_oo_req, ++ blkif->st_rd_req, blkif->st_wr_req); ++ blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000); ++ blkif->st_rd_req = 0; ++ blkif->st_wr_req = 0; ++ blkif->st_oo_req = 0; ++} ++ ++int tap_blkif_schedule(void *arg) ++{ ++ blkif_t *blkif = arg; ++ ++ blkif_get(blkif); ++ ++ if (debug_lvl) ++ printk(KERN_DEBUG "%s: started\n", current->comm); ++ ++ while (!kthread_should_stop()) { ++ wait_event_interruptible( ++ blkif->wq, ++ blkif->waiting_reqs || kthread_should_stop()); ++ wait_event_interruptible( ++ pending_free_wq, ++ !list_empty(&pending_free) || kthread_should_stop()); ++ ++ blkif->waiting_reqs = 0; ++ smp_mb(); /* clear flag *before* checking for work */ ++ ++ if (do_block_io_op(blkif)) ++ blkif->waiting_reqs = 1; ++ ++ if (log_stats && time_after(jiffies, blkif->st_print)) ++ print_stats(blkif); ++ } ++ ++ if (log_stats) ++ print_stats(blkif); ++ if (debug_lvl) ++ printk(KERN_DEBUG "%s: exiting\n", current->comm); ++ ++ blkif->xenblkd = NULL; ++ blkif_put(blkif); ++ ++ return 0; ++} ++ ++/****************************************************************** ++ * COMPLETION CALLBACK -- Called by user level ioctl() ++ */ ++ ++static int blktap_read_ufe_ring(tap_blkif_t *info) ++{ ++ /* This is called to read responses from the UFE ring. */ ++ RING_IDX i, j, rp; ++ blkif_response_t *resp; ++ blkif_t *blkif=NULL; ++ int pending_idx, usr_idx, mmap_idx; ++ pending_req_t *pending_req; ++ ++ if (!info) ++ return 0; ++ ++ /* We currently only forward packets in INTERCEPT_FE mode. */ ++ if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE)) ++ return 0; ++ ++ /* for each outstanding message on the UFEring */ ++ rp = info->ufe_ring.sring->rsp_prod; ++ rmb(); ++ ++ for (i = info->ufe_ring.rsp_cons; i != rp; i++) { ++ blkif_response_t res; ++ resp = RING_GET_RESPONSE(&info->ufe_ring, i); ++ memcpy(&res, resp, sizeof(res)); ++ mb(); /* rsp_cons read by RING_FULL() in do_block_io_op(). */ ++ ++info->ufe_ring.rsp_cons; ++ ++ /*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/ ++ usr_idx = (int)res.id; ++ pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx])); ++ mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]); ++ ++ if ( (mmap_idx >= mmap_alloc) || ++ (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) ) ++ WPRINTK("Incorrect req map" ++ "[%d], internal map [%d,%d (%d)]\n", ++ usr_idx, mmap_idx, ++ ID_TO_IDX(info->idx_map[usr_idx]), ++ MASK_PEND_IDX( ++ ID_TO_IDX(info->idx_map[usr_idx]))); ++ ++ pending_req = &pending_reqs[mmap_idx][pending_idx]; ++ blkif = pending_req->blkif; ++ ++ for (j = 0; j < pending_req->nr_pages; j++) { ++ ++ unsigned long kvaddr, uvaddr; ++ struct page **map = info->vma->vm_private_data; ++ struct page *pg; ++ int offset; ++ ++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j); ++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, j); ++ ++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); ++ ClearPageReserved(pg); ++ offset = (uvaddr - info->vma->vm_start) ++ >> PAGE_SHIFT; ++ map[offset] = NULL; ++ } ++ fast_flush_area(pending_req, pending_idx, usr_idx, info->minor); ++ info->idx_map[usr_idx] = INVALID_REQ; ++ make_response(blkif, pending_req->id, res.operation, ++ res.status); ++ blkif_put(pending_req->blkif); ++ free_req(pending_req); ++ } ++ ++ return 0; ++} ++ ++ ++/****************************************************************************** ++ * NOTIFICATION FROM GUEST OS. ++ */ ++ ++static void blkif_notify_work(blkif_t *blkif) ++{ ++ blkif->waiting_reqs = 1; ++ wake_up(&blkif->wq); ++} ++ ++irqreturn_t tap_blkif_be_int(int irq, void *dev_id) ++{ ++ blkif_notify_work(dev_id); ++ return IRQ_HANDLED; ++} ++ ++ ++ ++/****************************************************************** ++ * DOWNWARD CALLS -- These interface with the block-device layer proper. ++ */ ++static int print_dbug = 1; ++static int do_block_io_op(blkif_t *blkif) ++{ ++ blkif_back_rings_t *blk_rings = &blkif->blk_rings; ++ blkif_request_t req; ++ pending_req_t *pending_req; ++ RING_IDX rc, rp; ++ int more_to_do = 0; ++ tap_blkif_t *info; ++ ++ rc = blk_rings->common.req_cons; ++ rp = blk_rings->common.sring->req_prod; ++ rmb(); /* Ensure we see queued requests up to 'rp'. */ ++ ++ /*Check blkif has corresponding UE ring*/ ++ if (blkif->dev_num < 0) { ++ /*oops*/ ++ if (print_dbug) { ++ WPRINTK("Corresponding UE " ++ "ring does not exist!\n"); ++ print_dbug = 0; /*We only print this message once*/ ++ } ++ return 0; ++ } ++ ++ info = tapfds[blkif->dev_num]; ++ ++ if (blkif->dev_num > MAX_TAP_DEV || !info || !info->dev_inuse) { ++ if (print_dbug) { ++ WPRINTK("Can't get UE info!\n"); ++ print_dbug = 0; ++ } ++ return 0; ++ } ++ ++ while (rc != rp) { ++ ++ if (RING_FULL(&info->ufe_ring)) { ++ WPRINTK("RING_FULL! More to do\n"); ++ more_to_do = 1; ++ break; ++ } ++ ++ if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc)) { ++ WPRINTK("RING_REQUEST_CONS_OVERFLOW!" ++ " More to do\n"); ++ more_to_do = 1; ++ break; ++ } ++ ++ pending_req = alloc_req(); ++ if (NULL == pending_req) { ++ blkif->st_oo_req++; ++ more_to_do = 1; ++ break; ++ } ++ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), ++ sizeof(req)); ++ break; ++ case BLKIF_PROTOCOL_X86_32: ++ blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc)); ++ break; ++ case BLKIF_PROTOCOL_X86_64: ++ blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc)); ++ break; ++ default: ++ BUG(); ++ } ++ blk_rings->common.req_cons = ++rc; /* before make_response() */ ++ ++ switch (req.operation) { ++ case BLKIF_OP_READ: ++ blkif->st_rd_req++; ++ dispatch_rw_block_io(blkif, &req, pending_req); ++ break; ++ ++ case BLKIF_OP_WRITE: ++ blkif->st_wr_req++; ++ dispatch_rw_block_io(blkif, &req, pending_req); ++ break; ++ ++ default: ++ WPRINTK("unknown operation [%d]\n", ++ req.operation); ++ make_response(blkif, req.id, req.operation, ++ BLKIF_RSP_ERROR); ++ free_req(pending_req); ++ break; ++ } ++ } ++ ++ blktap_kick_user(blkif->dev_num); ++ ++ return more_to_do; ++} ++ ++static void dispatch_rw_block_io(blkif_t *blkif, ++ blkif_request_t *req, ++ pending_req_t *pending_req) ++{ ++ extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); ++ int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ; ++ struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2]; ++ unsigned int nseg; ++ int ret, i, nr_sects = 0; ++ tap_blkif_t *info; ++ uint64_t sector; ++ blkif_request_t *target; ++ int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx); ++ int usr_idx; ++ uint16_t mmap_idx = pending_req->mem_idx; ++ ++ if (blkif->dev_num < 0 || blkif->dev_num > MAX_TAP_DEV) ++ goto fail_response; ++ ++ info = tapfds[blkif->dev_num]; ++ if (info == NULL) ++ goto fail_response; ++ ++ /* Check we have space on user ring - should never fail. */ ++ usr_idx = GET_NEXT_REQ(info->idx_map); ++ if (usr_idx == INVALID_REQ) { ++ BUG(); ++ goto fail_response; ++ } ++ ++ /* Check that number of segments is sane. */ ++ nseg = req->nr_segments; ++ if ( unlikely(nseg == 0) || ++ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) { ++ WPRINTK("Bad number of segments in request (%d)\n", nseg); ++ goto fail_response; ++ } ++ ++ /* Make sure userspace is ready. */ ++ if (!info->ring_ok) { ++ WPRINTK("blktap: ring not ready for requests!\n"); ++ goto fail_response; ++ } ++ ++ if (RING_FULL(&info->ufe_ring)) { ++ WPRINTK("blktap: fe_ring is full, can't add " ++ "IO Request will be dropped. %d %d\n", ++ RING_SIZE(&info->ufe_ring), ++ RING_SIZE(&blkif->blk_rings.common)); ++ goto fail_response; ++ } ++ ++ pending_req->blkif = blkif; ++ pending_req->id = req->id; ++ pending_req->operation = operation; ++ pending_req->status = BLKIF_RSP_OKAY; ++ pending_req->nr_pages = nseg; ++ op = 0; ++ for (i = 0; i < nseg; i++) { ++ unsigned long uvaddr; ++ unsigned long kvaddr; ++ uint64_t ptep; ++ uint32_t flags; ++ ++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i); ++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i); ++ ++ sector = req->sector_number + ((PAGE_SIZE / 512) * i); ++ if( (blkif->sectors > 0) && (sector >= blkif->sectors) ) { ++ WPRINTK("BLKTAP: Sector request greater" ++ "than size\n"); ++ WPRINTK("BLKTAP: %s request sector" ++ "[%llu,%llu], Total [%llu]\n", ++ (req->operation == ++ BLKIF_OP_WRITE ? "WRITE" : "READ"), ++ (long long unsigned) sector, ++ (long long unsigned) sector>>9, ++ (long long unsigned) blkif->sectors); ++ } ++ ++ flags = GNTMAP_host_map; ++ if (operation == WRITE) ++ flags |= GNTMAP_readonly; ++ gnttab_set_map_op(&map[op], kvaddr, flags, ++ req->seg[i].gref, blkif->domid); ++ op++; ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Now map it to user. */ ++ ret = create_lookup_pte_addr(info->vma->vm_mm, ++ uvaddr, &ptep); ++ if (ret) { ++ WPRINTK("Couldn't get a pte addr!\n"); ++ goto fail_flush; ++ } ++ ++ flags = GNTMAP_host_map | GNTMAP_application_map ++ | GNTMAP_contains_pte; ++ if (operation == WRITE) ++ flags |= GNTMAP_readonly; ++ gnttab_set_map_op(&map[op], ptep, flags, ++ req->seg[i].gref, blkif->domid); ++ op++; ++ } ++ ++ nr_sects += (req->seg[i].last_sect - ++ req->seg[i].first_sect + 1); ++ } ++ ++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op); ++ BUG_ON(ret); ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ for (i = 0; i < (nseg*2); i+=2) { ++ unsigned long uvaddr; ++ unsigned long kvaddr; ++ unsigned long offset; ++ struct page *pg; ++ ++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2); ++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i/2); ++ ++ if (unlikely(map[i].status != 0)) { ++ WPRINTK("invalid kernel buffer -- " ++ "could not remap it\n"); ++ ret |= 1; ++ map[i].handle = INVALID_GRANT_HANDLE; ++ } ++ ++ if (unlikely(map[i+1].status != 0)) { ++ WPRINTK("invalid user buffer -- " ++ "could not remap it\n"); ++ ret |= 1; ++ map[i+1].handle = INVALID_GRANT_HANDLE; ++ } ++ ++ pending_handle(mmap_idx, pending_idx, i/2).kernel ++ = map[i].handle; ++ pending_handle(mmap_idx, pending_idx, i/2).user ++ = map[i+1].handle; ++ ++ if (ret) ++ continue; ++ ++ set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT, ++ FOREIGN_FRAME(map[i].dev_bus_addr ++ >> PAGE_SHIFT)); ++ offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; ++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); ++ ((struct page **)info->vma->vm_private_data)[offset] = ++ pg; ++ } ++ } else { ++ for (i = 0; i < nseg; i++) { ++ unsigned long uvaddr; ++ unsigned long kvaddr; ++ unsigned long offset; ++ struct page *pg; ++ ++ uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i); ++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i); ++ ++ if (unlikely(map[i].status != 0)) { ++ WPRINTK("invalid kernel buffer -- " ++ "could not remap it\n"); ++ ret |= 1; ++ map[i].handle = INVALID_GRANT_HANDLE; ++ } ++ ++ pending_handle(mmap_idx, pending_idx, i).kernel ++ = map[i].handle; ++ ++ if (ret) ++ continue; ++ ++ offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; ++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); ++ ((struct page **)info->vma->vm_private_data)[offset] = ++ pg; ++ } ++ } ++ ++ if (ret) ++ goto fail_flush; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ down_write(&info->vma->vm_mm->mmap_sem); ++ /* Mark mapped pages as reserved: */ ++ for (i = 0; i < req->nr_segments; i++) { ++ unsigned long kvaddr; ++ struct page *pg; ++ ++ kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i); ++ pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); ++ SetPageReserved(pg); ++ if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ ret = vm_insert_page(info->vma, ++ MMAP_VADDR(info->user_vstart, ++ usr_idx, i), pg); ++ if (ret) { ++ up_write(&info->vma->vm_mm->mmap_sem); ++ goto fail_flush; ++ } ++ } ++ } ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ up_write(&info->vma->vm_mm->mmap_sem); ++ ++ /*record [mmap_idx,pending_idx] to [usr_idx] mapping*/ ++ info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx); ++ ++ blkif_get(blkif); ++ /* Finally, write the request message to the user ring. */ ++ target = RING_GET_REQUEST(&info->ufe_ring, ++ info->ufe_ring.req_prod_pvt); ++ memcpy(target, req, sizeof(*req)); ++ target->id = usr_idx; ++ wmb(); /* blktap_poll() reads req_prod_pvt asynchronously */ ++ info->ufe_ring.req_prod_pvt++; ++ ++ if (operation == READ) ++ blkif->st_rd_sect += nr_sects; ++ else if (operation == WRITE) ++ blkif->st_wr_sect += nr_sects; ++ ++ return; ++ ++ fail_flush: ++ WPRINTK("Reached Fail_flush\n"); ++ fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num); ++ fail_response: ++ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); ++ free_req(pending_req); ++} ++ ++ ++ ++/****************************************************************** ++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING ++ */ ++ ++ ++static void make_response(blkif_t *blkif, u64 id, ++ unsigned short op, int st) ++{ ++ blkif_response_t resp; ++ unsigned long flags; ++ blkif_back_rings_t *blk_rings = &blkif->blk_rings; ++ int more_to_do = 0; ++ int notify; ++ ++ resp.id = id; ++ resp.operation = op; ++ resp.status = st; ++ ++ spin_lock_irqsave(&blkif->blk_ring_lock, flags); ++ /* Place on the response ring for the relevant domain. */ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ memcpy(RING_GET_RESPONSE(&blk_rings->native, ++ blk_rings->native.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case BLKIF_PROTOCOL_X86_32: ++ memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, ++ blk_rings->x86_32.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ case BLKIF_PROTOCOL_X86_64: ++ memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, ++ blk_rings->x86_64.rsp_prod_pvt), ++ &resp, sizeof(resp)); ++ break; ++ default: ++ BUG(); ++ } ++ blk_rings->common.rsp_prod_pvt++; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify); ++ ++ if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) { ++ /* ++ * Tail check for pending requests. Allows frontend to avoid ++ * notifications if requests are already in flight (lower ++ * overheads and promotes batching). ++ */ ++ RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do); ++ } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) { ++ more_to_do = 1; ++ } ++ ++ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags); ++ if (more_to_do) ++ blkif_notify_work(blkif); ++ if (notify) ++ notify_remote_via_irq(blkif->irq); ++} ++ ++static int __init blkif_init(void) ++{ ++ int i, ret; ++ struct class *class; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ INIT_LIST_HEAD(&pending_free); ++ for(i = 0; i < 2; i++) { ++ ret = req_increase(); ++ if (ret) ++ break; ++ } ++ if (i == 0) ++ return ret; ++ ++ tap_blkif_interface_init(); ++ ++ alloc_pending_reqs = 0; ++ ++ tap_blkif_xenbus_init(); ++ ++ /* Dynamically allocate a major for this device */ ++ ret = register_chrdev(0, "blktap", &blktap_fops); ++ ++ if (ret < 0) { ++ WPRINTK("Couldn't register /dev/xen/blktap\n"); ++ return -ENOMEM; ++ } ++ ++ blktap_major = ret; ++ ++ /* tapfds[0] is always NULL */ ++ blktap_next_minor++; ++ ++ DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i); ++ ++ /* Make sure the xen class exists */ ++ if ((class = get_xen_class()) != NULL) { ++ /* ++ * This will allow udev to create the blktap ctrl device. ++ * We only want to create blktap0 first. We don't want ++ * to flood the sysfs system with needless blktap devices. ++ * We only create the device when a request of a new device is ++ * made. ++ */ ++ class_device_create(class, NULL, ++ MKDEV(blktap_major, 0), NULL, ++ "blktap0"); ++ } else { ++ /* this is bad, but not fatal */ ++ WPRINTK("blktap: sysfs xen_class not created\n"); ++ } ++ ++ DPRINTK("Blktap device successfully created\n"); ++ ++ return 0; ++} ++ ++module_init(blkif_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blktap/common.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blktap/common.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,121 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __BLKIF__BACKEND__COMMON_H__ ++#define __BLKIF__BACKEND__COMMON_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/blkdev.h> ++#include <linux/vmalloc.h> ++#include <asm/io.h> ++#include <asm/setup.h> ++#include <asm/pgalloc.h> ++#include <xen/evtchn.h> ++#include <asm/hypervisor.h> ++#include <xen/blkif.h> ++#include <xen/gnttab.h> ++#include <xen/driver_util.h> ++ ++#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \ ++ __FILE__ , __LINE__ , ## _a ) ++ ++#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args) ++ ++struct backend_info; ++ ++typedef struct blkif_st { ++ /* Unique identifier for this interface. */ ++ domid_t domid; ++ unsigned int handle; ++ /* Physical parameters of the comms window. */ ++ unsigned int irq; ++ /* Comms information. */ ++ enum blkif_protocol blk_protocol; ++ blkif_back_rings_t blk_rings; ++ struct vm_struct *blk_ring_area; ++ /* Back pointer to the backend_info. */ ++ struct backend_info *be; ++ /* Private fields. */ ++ spinlock_t blk_ring_lock; ++ atomic_t refcnt; ++ ++ wait_queue_head_t wq; ++ struct task_struct *xenblkd; ++ unsigned int waiting_reqs; ++ request_queue_t *plug; ++ ++ /* statistics */ ++ unsigned long st_print; ++ int st_rd_req; ++ int st_wr_req; ++ int st_oo_req; ++ int st_rd_sect; ++ int st_wr_sect; ++ ++ wait_queue_head_t waiting_to_free; ++ ++ grant_handle_t shmem_handle; ++ grant_ref_t shmem_ref; ++ ++ int dev_num; ++ uint64_t sectors; ++} blkif_t; ++ ++blkif_t *tap_alloc_blkif(domid_t domid); ++void tap_blkif_free(blkif_t *blkif); ++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, ++ unsigned int evtchn); ++void tap_blkif_unmap(blkif_t *blkif); ++ ++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt)) ++#define blkif_put(_b) \ ++ do { \ ++ if (atomic_dec_and_test(&(_b)->refcnt)) \ ++ wake_up(&(_b)->waiting_to_free);\ ++ } while (0) ++ ++ ++struct phys_req { ++ unsigned short dev; ++ unsigned short nr_sects; ++ struct block_device *bdev; ++ blkif_sector_t sector_number; ++}; ++ ++void tap_blkif_interface_init(void); ++ ++void tap_blkif_xenbus_init(void); ++ ++irqreturn_t tap_blkif_be_int(int irq, void *dev_id); ++int tap_blkif_schedule(void *arg); ++ ++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif); ++void signal_tapdisk(int idx); ++ ++#endif /* __BLKIF__BACKEND__COMMON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blktap/interface.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blktap/interface.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,174 @@ ++/****************************************************************************** ++ * drivers/xen/blktap/interface.c ++ * ++ * Block-device interface management. ++ * ++ * Copyright (c) 2004, Keir Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ ++ */ ++ ++#include "common.h" ++#include <xen/evtchn.h> ++ ++static struct kmem_cache *blkif_cachep; ++ ++blkif_t *tap_alloc_blkif(domid_t domid) ++{ ++ blkif_t *blkif; ++ ++ blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL); ++ if (!blkif) ++ return ERR_PTR(-ENOMEM); ++ ++ memset(blkif, 0, sizeof(*blkif)); ++ blkif->domid = domid; ++ spin_lock_init(&blkif->blk_ring_lock); ++ atomic_set(&blkif->refcnt, 1); ++ init_waitqueue_head(&blkif->wq); ++ blkif->st_print = jiffies; ++ init_waitqueue_head(&blkif->waiting_to_free); ++ ++ return blkif; ++} ++ ++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page) ++{ ++ struct gnttab_map_grant_ref op; ++ ++ gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr, ++ GNTMAP_host_map, shared_page, blkif->domid); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status) { ++ DPRINTK(" Grant table operation failure !\n"); ++ return op.status; ++ } ++ ++ blkif->shmem_ref = shared_page; ++ blkif->shmem_handle = op.handle; ++ ++ return 0; ++} ++ ++static void unmap_frontend_page(blkif_t *blkif) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr, ++ GNTMAP_host_map, blkif->shmem_handle); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++} ++ ++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, ++ unsigned int evtchn) ++{ ++ int err; ++ ++ /* Already connected through? */ ++ if (blkif->irq) ++ return 0; ++ ++ if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL ) ++ return -ENOMEM; ++ ++ err = map_frontend_page(blkif, shared_page); ++ if (err) { ++ free_vm_area(blkif->blk_ring_area); ++ return err; ++ } ++ ++ switch (blkif->blk_protocol) { ++ case BLKIF_PROTOCOL_NATIVE: ++ { ++ blkif_sring_t *sring; ++ sring = (blkif_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE); ++ break; ++ } ++ case BLKIF_PROTOCOL_X86_32: ++ { ++ blkif_x86_32_sring_t *sring_x86_32; ++ sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE); ++ break; ++ } ++ case BLKIF_PROTOCOL_X86_64: ++ { ++ blkif_x86_64_sring_t *sring_x86_64; ++ sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr; ++ BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE); ++ break; ++ } ++ default: ++ BUG(); ++ } ++ ++ err = bind_interdomain_evtchn_to_irqhandler( ++ blkif->domid, evtchn, tap_blkif_be_int, ++ 0, "blkif-backend", blkif); ++ if (err < 0) { ++ unmap_frontend_page(blkif); ++ free_vm_area(blkif->blk_ring_area); ++ blkif->blk_rings.common.sring = NULL; ++ return err; ++ } ++ blkif->irq = err; ++ ++ return 0; ++} ++ ++void tap_blkif_unmap(blkif_t *blkif) ++{ ++ if (blkif->irq) { ++ unbind_from_irqhandler(blkif->irq, blkif); ++ blkif->irq = 0; ++ } ++ if (blkif->blk_rings.common.sring) { ++ unmap_frontend_page(blkif); ++ free_vm_area(blkif->blk_ring_area); ++ blkif->blk_rings.common.sring = NULL; ++ } ++} ++ ++void tap_blkif_free(blkif_t *blkif) ++{ ++ atomic_dec(&blkif->refcnt); ++ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0); ++ ++ tap_blkif_unmap(blkif); ++ kmem_cache_free(blkif_cachep, blkif); ++} ++ ++void __init tap_blkif_interface_init(void) ++{ ++ blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), ++ 0, 0, NULL, NULL); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/blktap/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/blktap/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,473 @@ ++/* drivers/xen/blktap/xenbus.c ++ * ++ * Xenbus code for blktap ++ * ++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield ++ * ++ * Based on the blkback xenbus code: ++ * ++ * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au> ++ * Copyright (C) 2005 XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <stdarg.h> ++#include <linux/module.h> ++#include <linux/kthread.h> ++#include <xen/xenbus.h> ++#include "common.h" ++ ++ ++struct backend_info ++{ ++ struct xenbus_device *dev; ++ blkif_t *blkif; ++ struct xenbus_watch backend_watch; ++ int xenbus_id; ++ int group_added; ++}; ++ ++ ++static void connect(struct backend_info *); ++static int connect_ring(struct backend_info *); ++static int blktap_remove(struct xenbus_device *dev); ++static int blktap_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id); ++static void tap_backend_changed(struct xenbus_watch *, const char **, ++ unsigned int); ++static void tap_frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state); ++ ++static int strsep_len(const char *str, char c, unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; str[i]; i++) ++ if (str[i] == c) { ++ if (len == 0) ++ return i; ++ len--; ++ } ++ return (len == 0) ? i : -ERANGE; ++} ++ ++static long get_id(const char *str) ++{ ++ int len,end; ++ const char *ptr; ++ char *tptr, num[10]; ++ ++ len = strsep_len(str, '/', 2); ++ end = strlen(str); ++ if ( (len < 0) || (end < 0) ) return -1; ++ ++ ptr = str + len + 1; ++ strncpy(num,ptr,end - len); ++ tptr = num + (end - (len + 1)); ++ *tptr = '\0'; ++ DPRINTK("Get_id called for %s (%s)\n",str,num); ++ ++ return simple_strtol(num, NULL, 10); ++} ++ ++static int blktap_name(blkif_t *blkif, char *buf) ++{ ++ char *devpath, *devname; ++ struct xenbus_device *dev = blkif->be->dev; ++ ++ devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL); ++ if (IS_ERR(devpath)) ++ return PTR_ERR(devpath); ++ ++ if ((devname = strstr(devpath, "/dev/")) != NULL) ++ devname += strlen("/dev/"); ++ else ++ devname = devpath; ++ ++ snprintf(buf, TASK_COMM_LEN, "blktap.%d.%s", blkif->domid, devname); ++ kfree(devpath); ++ ++ return 0; ++} ++ ++/**************************************************************** ++ * sysfs interface for VBD I/O requests ++ */ ++ ++#define VBD_SHOW(name, format, args...) \ ++ static ssize_t show_##name(struct device *_dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++ { \ ++ struct xenbus_device *dev = to_xenbus_device(_dev); \ ++ struct backend_info *be = dev->dev.driver_data; \ ++ \ ++ return sprintf(buf, format, ##args); \ ++ } \ ++ DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) ++ ++VBD_SHOW(tap_oo_req, "%d\n", be->blkif->st_oo_req); ++VBD_SHOW(tap_rd_req, "%d\n", be->blkif->st_rd_req); ++VBD_SHOW(tap_wr_req, "%d\n", be->blkif->st_wr_req); ++VBD_SHOW(tap_rd_sect, "%d\n", be->blkif->st_rd_sect); ++VBD_SHOW(tap_wr_sect, "%d\n", be->blkif->st_wr_sect); ++ ++static struct attribute *tapstat_attrs[] = { ++ &dev_attr_tap_oo_req.attr, ++ &dev_attr_tap_rd_req.attr, ++ &dev_attr_tap_wr_req.attr, ++ &dev_attr_tap_rd_sect.attr, ++ &dev_attr_tap_wr_sect.attr, ++ NULL ++}; ++ ++static struct attribute_group tapstat_group = { ++ .name = "statistics", ++ .attrs = tapstat_attrs, ++}; ++ ++int xentap_sysfs_addif(struct xenbus_device *dev) ++{ ++ int err; ++ struct backend_info *be = dev->dev.driver_data; ++ err = sysfs_create_group(&dev->dev.kobj, &tapstat_group); ++ if (!err) ++ be->group_added = 1; ++ return err; ++} ++ ++void xentap_sysfs_delif(struct xenbus_device *dev) ++{ ++ sysfs_remove_group(&dev->dev.kobj, &tapstat_group); ++} ++ ++static int blktap_remove(struct xenbus_device *dev) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ ++ if (be->backend_watch.node) { ++ unregister_xenbus_watch(&be->backend_watch); ++ kfree(be->backend_watch.node); ++ be->backend_watch.node = NULL; ++ } ++ if (be->blkif) { ++ if (be->blkif->xenblkd) ++ kthread_stop(be->blkif->xenblkd); ++ signal_tapdisk(be->blkif->dev_num); ++ tap_blkif_free(be->blkif); ++ be->blkif = NULL; ++ } ++ if (be->group_added) ++ xentap_sysfs_delif(be->dev); ++ kfree(be); ++ dev->dev.driver_data = NULL; ++ return 0; ++} ++ ++static void tap_update_blkif_status(blkif_t *blkif) ++{ ++ int err; ++ char name[TASK_COMM_LEN]; ++ ++ /* Not ready to connect? */ ++ if(!blkif->irq || !blkif->sectors) { ++ return; ++ } ++ ++ /* Already connected? */ ++ if (blkif->be->dev->state == XenbusStateConnected) ++ return; ++ ++ /* Attempt to connect: exit if we fail to. */ ++ connect(blkif->be); ++ if (blkif->be->dev->state != XenbusStateConnected) ++ return; ++ ++ err = blktap_name(blkif, name); ++ if (err) { ++ xenbus_dev_error(blkif->be->dev, err, "get blktap dev name"); ++ return; ++ } ++ ++ err = xentap_sysfs_addif(blkif->be->dev); ++ if (err) { ++ xenbus_dev_fatal(blkif->be->dev, err, ++ "creating sysfs entries"); ++ return; ++ } ++ ++ blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif, name); ++ if (IS_ERR(blkif->xenblkd)) { ++ err = PTR_ERR(blkif->xenblkd); ++ blkif->xenblkd = NULL; ++ xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd"); ++ WPRINTK("Error starting thread\n"); ++ } ++} ++ ++/** ++ * Entry point to this code when a new device is created. Allocate ++ * the basic structures, and watch the store waiting for the ++ * user-space program to tell us the physical device info. Switch to ++ * InitWait. ++ */ ++static int blktap_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ struct backend_info *be = kzalloc(sizeof(struct backend_info), ++ GFP_KERNEL); ++ if (!be) { ++ xenbus_dev_fatal(dev, -ENOMEM, ++ "allocating backend structure"); ++ return -ENOMEM; ++ } ++ ++ be->dev = dev; ++ dev->dev.driver_data = be; ++ be->xenbus_id = get_id(dev->nodename); ++ ++ be->blkif = tap_alloc_blkif(dev->otherend_id); ++ if (IS_ERR(be->blkif)) { ++ err = PTR_ERR(be->blkif); ++ be->blkif = NULL; ++ xenbus_dev_fatal(dev, err, "creating block interface"); ++ goto fail; ++ } ++ ++ /* setup back pointer */ ++ be->blkif->be = be; ++ be->blkif->sectors = 0; ++ ++ /* set a watch on disk info, waiting for userspace to update details*/ ++ err = xenbus_watch_path2(dev, dev->nodename, "info", ++ &be->backend_watch, tap_backend_changed); ++ if (err) ++ goto fail; ++ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) ++ goto fail; ++ return 0; ++ ++fail: ++ DPRINTK("blktap probe failed\n"); ++ blktap_remove(dev); ++ return err; ++} ++ ++ ++/** ++ * Callback received when the user space code has placed the device ++ * information in xenstore. ++ */ ++static void tap_backend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ int err; ++ unsigned long info; ++ struct backend_info *be ++ = container_of(watch, struct backend_info, backend_watch); ++ struct xenbus_device *dev = be->dev; ++ ++ /** ++ * Check to see whether userspace code has opened the image ++ * and written sector ++ * and disk info to xenstore ++ */ ++ err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, ++ NULL); ++ if (XENBUS_EXIST_ERR(err)) ++ return; ++ if (err) { ++ xenbus_dev_error(dev, err, "getting info"); ++ return; ++ } ++ ++ DPRINTK("Userspace update on disk info, %lu\n",info); ++ ++ err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", ++ &be->blkif->sectors, NULL); ++ ++ /* Associate tap dev with domid*/ ++ be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, ++ be->blkif); ++ DPRINTK("Thread started for domid [%d], connecting disk\n", ++ be->blkif->dev_num); ++ ++ tap_update_blkif_status(be->blkif); ++} ++ ++/** ++ * Callback received when the frontend's state changes. ++ */ ++static void tap_frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ int err; ++ ++ DPRINTK("\n"); ++ ++ switch (frontend_state) { ++ case XenbusStateInitialising: ++ if (dev->state == XenbusStateClosed) { ++ printk(KERN_INFO "%s: %s: prepare for reconnect\n", ++ __FUNCTION__, dev->nodename); ++ xenbus_switch_state(dev, XenbusStateInitWait); ++ } ++ break; ++ ++ case XenbusStateInitialised: ++ case XenbusStateConnected: ++ /* Ensure we connect even when two watches fire in ++ close successsion and we miss the intermediate value ++ of frontend_state. */ ++ if (dev->state == XenbusStateConnected) ++ break; ++ ++ err = connect_ring(be); ++ if (err) ++ break; ++ tap_update_blkif_status(be->blkif); ++ break; ++ ++ case XenbusStateClosing: ++ if (be->blkif->xenblkd) { ++ kthread_stop(be->blkif->xenblkd); ++ be->blkif->xenblkd = NULL; ++ } ++ xenbus_switch_state(dev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateClosed: ++ xenbus_switch_state(dev, XenbusStateClosed); ++ if (xenbus_dev_is_online(dev)) ++ break; ++ /* fall through if not online */ ++ case XenbusStateUnknown: ++ device_unregister(&dev->dev); ++ break; ++ ++ default: ++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", ++ frontend_state); ++ break; ++ } ++} ++ ++ ++/** ++ * Switch to Connected state. ++ */ ++static void connect(struct backend_info *be) ++{ ++ int err; ++ ++ struct xenbus_device *dev = be->dev; ++ ++ err = xenbus_switch_state(dev, XenbusStateConnected); ++ if (err) ++ xenbus_dev_fatal(dev, err, "switching to Connected state", ++ dev->nodename); ++ ++ return; ++} ++ ++ ++static int connect_ring(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ unsigned long ring_ref; ++ unsigned int evtchn; ++ char protocol[64]; ++ int err; ++ ++ DPRINTK("%s\n", dev->otherend); ++ ++ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", ++ &ring_ref, "event-channel", "%u", &evtchn, NULL); ++ if (err) { ++ xenbus_dev_fatal(dev, err, ++ "reading %s/ring-ref and event-channel", ++ dev->otherend); ++ return err; ++ } ++ ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; ++ err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", ++ "%63s", protocol, NULL); ++ if (err) ++ strcpy(protocol, "unspecified, assuming native"); ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; ++ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++ else { ++ xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); ++ return -1; ++ } ++ printk(KERN_INFO ++ "blktap: ring-ref %ld, event-channel %d, protocol %d (%s)\n", ++ ring_ref, evtchn, be->blkif->blk_protocol, protocol); ++ ++ /* Map the shared frame, irq etc. */ ++ err = tap_blkif_map(be->blkif, ring_ref, evtchn); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u", ++ ring_ref, evtchn); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++/* ** Driver Registration ** */ ++ ++ ++static struct xenbus_device_id blktap_ids[] = { ++ { "tap" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver blktap = { ++ .name = "tap", ++ .owner = THIS_MODULE, ++ .ids = blktap_ids, ++ .probe = blktap_probe, ++ .remove = blktap_remove, ++ .otherend_changed = tap_frontend_changed ++}; ++ ++ ++void tap_blkif_xenbus_init(void) ++{ ++ xenbus_register_backend(&blktap); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/char/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/char/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++obj-y := mem.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/char/mem.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/char/mem.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,203 @@ ++/* ++ * Originally from linux/drivers/char/mem.c ++ * ++ * Copyright (C) 1991, 1992 Linus Torvalds ++ * ++ * Added devfs support. ++ * Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu> ++ * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com> ++ */ ++ ++#include <linux/mm.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <linux/mman.h> ++#include <linux/random.h> ++#include <linux/init.h> ++#include <linux/raw.h> ++#include <linux/tty.h> ++#include <linux/capability.h> ++#include <linux/smp_lock.h> ++#include <linux/ptrace.h> ++#include <linux/device.h> ++#include <asm/pgalloc.h> ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/hypervisor.h> ++ ++#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE ++static inline int valid_phys_addr_range(unsigned long addr, size_t count) ++{ ++ return 1; ++} ++#endif ++ ++/* ++ * This funcion reads the *physical* memory. The f_pos points directly to the ++ * memory location. ++ */ ++static ssize_t read_mem(struct file * file, char __user * buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos, ignored; ++ ssize_t read = 0, sz; ++ void __iomem *v; ++ ++ if (!valid_phys_addr_range(p, count)) ++ return -EFAULT; ++ ++ while (count > 0) { ++ /* ++ * Handle first page in case it's not aligned ++ */ ++ if (-p & (PAGE_SIZE - 1)) ++ sz = -p & (PAGE_SIZE - 1); ++ else ++ sz = PAGE_SIZE; ++ ++ sz = min_t(unsigned long, sz, count); ++ ++ v = xlate_dev_mem_ptr(p, sz); ++ if (IS_ERR(v) || v == NULL) { ++ /* ++ * Some programs (e.g., dmidecode) groove off into ++ * weird RAM areas where no tables can possibly exist ++ * (because Xen will have stomped on them!). These ++ * programs get rather upset if we let them know that ++ * Xen failed their access, so we fake out a read of ++ * all zeroes. ++ */ ++ if (clear_user(buf, count)) ++ return -EFAULT; ++ read += count; ++ break; ++ } ++ ++ ignored = copy_to_user(buf, v, sz); ++ xlate_dev_mem_ptr_unmap(v); ++ if (ignored) ++ return -EFAULT; ++ buf += sz; ++ p += sz; ++ count -= sz; ++ read += sz; ++ } ++ ++ *ppos += read; ++ return read; ++} ++ ++static ssize_t write_mem(struct file * file, const char __user * buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos, ignored; ++ ssize_t written = 0, sz; ++ void __iomem *v; ++ ++ if (!valid_phys_addr_range(p, count)) ++ return -EFAULT; ++ ++ while (count > 0) { ++ /* ++ * Handle first page in case it's not aligned ++ */ ++ if (-p & (PAGE_SIZE - 1)) ++ sz = -p & (PAGE_SIZE - 1); ++ else ++ sz = PAGE_SIZE; ++ ++ sz = min_t(unsigned long, sz, count); ++ ++ v = xlate_dev_mem_ptr(p, sz); ++ if (v == NULL) ++ break; ++ if (IS_ERR(v)) { ++ if (written == 0) ++ return PTR_ERR(v); ++ break; ++ } ++ ++ ignored = copy_from_user(v, buf, sz); ++ xlate_dev_mem_ptr_unmap(v); ++ if (ignored) { ++ written += sz - ignored; ++ if (written) ++ break; ++ return -EFAULT; ++ } ++ buf += sz; ++ p += sz; ++ count -= sz; ++ written += sz; ++ } ++ ++ *ppos += written; ++ return written; ++} ++ ++#ifndef ARCH_HAS_DEV_MEM_MMAP_MEM ++static inline int uncached_access(struct file *file) ++{ ++ if (file->f_flags & O_SYNC) ++ return 1; ++ /* Xen sets correct MTRR type on non-RAM for us. */ ++ return 0; ++} ++ ++static int xen_mmap_mem(struct file * file, struct vm_area_struct * vma) ++{ ++ size_t size = vma->vm_end - vma->vm_start; ++ ++ if (uncached_access(file)) ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ /* We want to return the real error code, not EAGAIN. */ ++ return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ size, vma->vm_page_prot, DOMID_IO); ++} ++#endif ++ ++/* ++ * The memory devices use the full 32/64 bits of the offset, and so we cannot ++ * check against negative addresses: they are ok. The return value is weird, ++ * though, in that case (0). ++ * ++ * also note that seeking relative to the "end of file" isn't supported: ++ * it has no meaning, so it returns -EINVAL. ++ */ ++static loff_t memory_lseek(struct file * file, loff_t offset, int orig) ++{ ++ loff_t ret; ++ ++ mutex_lock(&file->f_dentry->d_inode->i_mutex); ++ switch (orig) { ++ case 0: ++ file->f_pos = offset; ++ ret = file->f_pos; ++ force_successful_syscall_return(); ++ break; ++ case 1: ++ file->f_pos += offset; ++ ret = file->f_pos; ++ force_successful_syscall_return(); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ mutex_unlock(&file->f_dentry->d_inode->i_mutex); ++ return ret; ++} ++ ++static int open_mem(struct inode * inode, struct file * filp) ++{ ++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; ++} ++ ++const struct file_operations mem_fops = { ++ .llseek = memory_lseek, ++ .read = read_mem, ++ .write = write_mem, ++ .mmap = xen_mmap_mem, ++ .open = open_mem, ++}; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/console/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/console/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++obj-y := console.o xencons_ring.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/console/console.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/console/console.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,712 @@ ++/****************************************************************************** ++ * console.c ++ * ++ * Virtual console driver. ++ * ++ * Copyright (c) 2002-2004, K A Fraser. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial.h> ++#include <linux/major.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/console.h> ++#include <linux/bootmem.h> ++#include <linux/sysrq.h> ++#include <linux/screen_info.h> ++#include <linux/vt.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/event_channel.h> ++#include <asm/hypervisor.h> ++#include <xen/evtchn.h> ++#include <xen/xenbus.h> ++#include <xen/xencons.h> ++ ++/* ++ * Modes: ++ * 'xencons=off' [XC_OFF]: Console is disabled. ++ * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. ++ * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. ++ * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'. ++ * default: DOM0 -> XC_SERIAL ; all others -> XC_TTY. ++ * ++ * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses ++ * warnings from standard distro startup scripts. ++ */ ++static enum { ++ XC_OFF, XC_TTY, XC_SERIAL, XC_XVC ++} xc_mode; ++static int xc_num = -1; ++ ++/* /dev/xvc0 device number allocated by lanana.org. */ ++#define XEN_XVC_MAJOR 204 ++#define XEN_XVC_MINOR 191 ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++static unsigned long sysrq_requested; ++#endif ++ ++void xencons_early_setup(void) ++{ ++ if (is_initial_xendomain()) ++ xc_mode = XC_SERIAL; ++ else ++ xc_mode = XC_XVC; ++} ++ ++static int __init xencons_setup(char *str) ++{ ++ char *q; ++ int n; ++ ++ if (!strncmp(str, "ttyS", 4)) { ++ xc_mode = XC_SERIAL; ++ str += 4; ++ } else if (!strncmp(str, "tty", 3)) { ++ xc_mode = XC_TTY; ++ str += 3; ++ } else if (!strncmp(str, "xvc", 3)) { ++ xc_mode = XC_XVC; ++ str += 3; ++ } else if (!strncmp(str, "off", 3)) { ++ xc_mode = XC_OFF; ++ str += 3; ++ } ++ ++ n = simple_strtol(str, &q, 10); ++ if (q != str) ++ xc_num = n; ++ ++ return 1; ++} ++__setup("xencons=", xencons_setup); ++ ++/* The kernel and user-land drivers share a common transmit buffer. */ ++static unsigned int wbuf_size = 4096; ++#define WBUF_MASK(_i) ((_i)&(wbuf_size-1)) ++static char *wbuf; ++static unsigned int wc, wp; /* write_cons, write_prod */ ++ ++static int __init xencons_bufsz_setup(char *str) ++{ ++ unsigned int goal; ++ goal = simple_strtoul(str, NULL, 0); ++ if (goal) { ++ goal = roundup_pow_of_two(goal); ++ if (wbuf_size < goal) ++ wbuf_size = goal; ++ } ++ return 1; ++} ++__setup("xencons_bufsz=", xencons_bufsz_setup); ++ ++/* This lock protects accesses to the common transmit buffer. */ ++static DEFINE_SPINLOCK(xencons_lock); ++ ++/* Common transmit-kick routine. */ ++static void __xencons_tx_flush(void); ++ ++static struct tty_driver *xencons_driver; ++ ++/******************** Kernel console driver ********************************/ ++ ++static void kcons_write(struct console *c, const char *s, unsigned int count) ++{ ++ int i = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ ++ while (i < count) { ++ for (; i < count; i++) { ++ if ((wp - wc) >= (wbuf_size - 1)) ++ break; ++ if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n') ++ wbuf[WBUF_MASK(wp++)] = '\r'; ++ } ++ ++ __xencons_tx_flush(); ++ } ++ ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static void kcons_write_dom0(struct console *c, const char *s, unsigned int count) ++{ ++ ++ while (count > 0) { ++ int rc; ++ rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s); ++ if (rc <= 0) ++ break; ++ count -= rc; ++ s += rc; ++ } ++} ++ ++static struct tty_driver *kcons_device(struct console *c, int *index) ++{ ++ *index = 0; ++ return xencons_driver; ++} ++ ++static struct console kcons_info = { ++ .device = kcons_device, ++ .flags = CON_PRINTBUFFER | CON_ENABLED, ++ .index = -1, ++}; ++ ++static int __init xen_console_init(void) ++{ ++ if (!is_running_on_xen()) ++ goto out; ++ ++ if (is_initial_xendomain()) { ++ kcons_info.write = kcons_write_dom0; ++ } else { ++ if (!xen_start_info->console.domU.evtchn) ++ goto out; ++ kcons_info.write = kcons_write; ++ } ++ ++ switch (xc_mode) { ++ case XC_XVC: ++ strcpy(kcons_info.name, "xvc"); ++ if (xc_num == -1) ++ xc_num = 0; ++ break; ++ ++ case XC_SERIAL: ++ strcpy(kcons_info.name, "ttyS"); ++ if (xc_num == -1) ++ xc_num = 0; ++ break; ++ ++ case XC_TTY: ++ strcpy(kcons_info.name, "tty"); ++ if (xc_num == -1) ++ xc_num = 1; ++ break; ++ ++ default: ++ goto out; ++ } ++ ++ wbuf = alloc_bootmem(wbuf_size); ++ ++ register_console(&kcons_info); ++ ++ out: ++ return 0; ++} ++console_initcall(xen_console_init); ++ ++/*** Useful function for console debugging -- goes straight to Xen. ***/ ++asmlinkage int xprintk(const char *fmt, ...) ++{ ++ va_list args; ++ int printk_len; ++ static char printk_buf[1024]; ++ ++ /* Emit the output into the temporary buffer */ ++ va_start(args, fmt); ++ printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); ++ va_end(args); ++ ++ /* Send the processed output directly to Xen. */ ++ kcons_write_dom0(NULL, printk_buf, printk_len); ++ ++ return 0; ++} ++ ++/*** Forcibly flush console data before dying. ***/ ++void xencons_force_flush(void) ++{ ++ int sz; ++ ++ /* Emergency console is synchronous, so there's nothing to flush. */ ++ if (!is_running_on_xen() || ++ is_initial_xendomain() || ++ !xen_start_info->console.domU.evtchn) ++ return; ++ ++ /* Spin until console data is flushed through to the daemon. */ ++ while (wc != wp) { ++ int sent = 0; ++ if ((sz = wp - wc) == 0) ++ continue; ++ sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); ++ if (sent > 0) ++ wc += sent; ++ } ++} ++ ++ ++void dom0_init_screen_info(const struct dom0_vga_console_info *info) ++{ ++ switch (info->video_type) { ++ case XEN_VGATYPE_TEXT_MODE_3: ++ screen_info.orig_video_mode = 3; ++ screen_info.orig_video_ega_bx = 3; ++ screen_info.orig_video_isVGA = 1; ++ screen_info.orig_video_lines = info->u.text_mode_3.rows; ++ screen_info.orig_video_cols = info->u.text_mode_3.columns; ++ screen_info.orig_x = info->u.text_mode_3.cursor_x; ++ screen_info.orig_y = info->u.text_mode_3.cursor_y; ++ screen_info.orig_video_points = ++ info->u.text_mode_3.font_height; ++ break; ++ case XEN_VGATYPE_VESA_LFB: ++ screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB; ++ screen_info.lfb_width = info->u.vesa_lfb.width; ++ screen_info.lfb_height = info->u.vesa_lfb.height; ++ screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel; ++ screen_info.lfb_base = info->u.vesa_lfb.lfb_base; ++ screen_info.lfb_size = info->u.vesa_lfb.lfb_size; ++ screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line; ++ screen_info.red_size = info->u.vesa_lfb.red_size; ++ screen_info.red_pos = info->u.vesa_lfb.red_pos; ++ screen_info.green_size = info->u.vesa_lfb.green_size; ++ screen_info.green_pos = info->u.vesa_lfb.green_pos; ++ screen_info.blue_size = info->u.vesa_lfb.blue_size; ++ screen_info.blue_pos = info->u.vesa_lfb.blue_pos; ++ screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size; ++ screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos; ++ break; ++ } ++} ++ ++ ++/******************** User-space console driver (/dev/console) ************/ ++ ++#define DRV(_d) (_d) ++#define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) && \ ++ ((_tty)->index != (xc_num - 1))) ++ ++static struct ktermios *xencons_termios[MAX_NR_CONSOLES]; ++static struct ktermios *xencons_termios_locked[MAX_NR_CONSOLES]; ++static struct tty_struct *xencons_tty; ++static int xencons_priv_irq; ++static char x_char; ++ ++void xencons_rx(char *buf, unsigned len) ++{ ++ int i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ if (xencons_tty == NULL) ++ goto out; ++ ++ for (i = 0; i < len; i++) { ++#ifdef CONFIG_MAGIC_SYSRQ ++ if (sysrq_on()) { ++ if (buf[i] == '\x0f') { /* ^O */ ++ if (!sysrq_requested) { ++ sysrq_requested = jiffies; ++ continue; /* don't print sysrq key */ ++ } ++ sysrq_requested = 0; ++ } else if (sysrq_requested) { ++ unsigned long sysrq_timeout = ++ sysrq_requested + HZ*2; ++ sysrq_requested = 0; ++ if (time_before(jiffies, sysrq_timeout)) { ++ spin_unlock_irqrestore( ++ &xencons_lock, flags); ++ handle_sysrq( ++ buf[i], xencons_tty); ++ spin_lock_irqsave( ++ &xencons_lock, flags); ++ continue; ++ } ++ } ++ } ++#endif ++ tty_insert_flip_char(xencons_tty, buf[i], 0); ++ } ++ tty_flip_buffer_push(xencons_tty); ++ ++ out: ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static void __xencons_tx_flush(void) ++{ ++ int sent, sz, work_done = 0; ++ ++ if (x_char) { ++ if (is_initial_xendomain()) ++ kcons_write_dom0(NULL, &x_char, 1); ++ else ++ while (x_char) ++ if (xencons_ring_send(&x_char, 1) == 1) ++ break; ++ x_char = 0; ++ work_done = 1; ++ } ++ ++ while (wc != wp) { ++ sz = wp - wc; ++ if (sz > (wbuf_size - WBUF_MASK(wc))) ++ sz = wbuf_size - WBUF_MASK(wc); ++ if (is_initial_xendomain()) { ++ kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz); ++ wc += sz; ++ } else { ++ sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); ++ if (sent == 0) ++ break; ++ wc += sent; ++ } ++ work_done = 1; ++ } ++ ++ if (work_done && (xencons_tty != NULL)) { ++ wake_up_interruptible(&xencons_tty->write_wait); ++ if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && ++ (xencons_tty->ldisc.write_wakeup != NULL)) ++ (xencons_tty->ldisc.write_wakeup)(xencons_tty); ++ } ++} ++ ++void xencons_tx(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ __xencons_tx_flush(); ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++/* Privileged receive callback and transmit kicker. */ ++static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id) ++{ ++ static char rbuf[16]; ++ int l; ++ ++ while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0) ++ xencons_rx(rbuf, l); ++ ++ xencons_tx(); ++ ++ return IRQ_HANDLED; ++} ++ ++static int xencons_write_room(struct tty_struct *tty) ++{ ++ return wbuf_size - (wp - wc); ++} ++ ++static int xencons_chars_in_buffer(struct tty_struct *tty) ++{ ++ return wp - wc; ++} ++ ++static void xencons_send_xchar(struct tty_struct *tty, char ch) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ x_char = ch; ++ __xencons_tx_flush(); ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static void xencons_throttle(struct tty_struct *tty) ++{ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ if (I_IXOFF(tty)) ++ xencons_send_xchar(tty, STOP_CHAR(tty)); ++} ++ ++static void xencons_unthrottle(struct tty_struct *tty) ++{ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ if (I_IXOFF(tty)) { ++ if (x_char != 0) ++ x_char = 0; ++ else ++ xencons_send_xchar(tty, START_CHAR(tty)); ++ } ++} ++ ++static void xencons_flush_buffer(struct tty_struct *tty) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ wc = wp = 0; ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static inline int __xencons_put_char(int ch) ++{ ++ char _ch = (char)ch; ++ if ((wp - wc) == wbuf_size) ++ return 0; ++ wbuf[WBUF_MASK(wp++)] = _ch; ++ return 1; ++} ++ ++static int xencons_write( ++ struct tty_struct *tty, ++ const unsigned char *buf, ++ int count) ++{ ++ int i; ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return count; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ ++ for (i = 0; i < count; i++) ++ if (!__xencons_put_char(buf[i])) ++ break; ++ ++ if (i != 0) ++ __xencons_tx_flush(); ++ ++ spin_unlock_irqrestore(&xencons_lock, flags); ++ ++ return i; ++} ++ ++static void xencons_put_char(struct tty_struct *tty, u_char ch) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ (void)__xencons_put_char(ch); ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static void xencons_flush_chars(struct tty_struct *tty) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ __xencons_tx_flush(); ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static void xencons_wait_until_sent(struct tty_struct *tty, int timeout) ++{ ++ unsigned long orig_jiffies = jiffies; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ while (DRV(tty->driver)->chars_in_buffer(tty)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ if (signal_pending(current)) ++ break; ++ if (timeout && time_after(jiffies, orig_jiffies + timeout)) ++ break; ++ } ++ ++ set_current_state(TASK_RUNNING); ++} ++ ++static int xencons_open(struct tty_struct *tty, struct file *filp) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return 0; ++ ++ spin_lock_irqsave(&xencons_lock, flags); ++ tty->driver_data = NULL; ++ if (xencons_tty == NULL) ++ xencons_tty = tty; ++ __xencons_tx_flush(); ++ spin_unlock_irqrestore(&xencons_lock, flags); ++ ++ return 0; ++} ++ ++static void xencons_close(struct tty_struct *tty, struct file *filp) ++{ ++ unsigned long flags; ++ ++ if (DUMMY_TTY(tty)) ++ return; ++ ++ mutex_lock(&tty_mutex); ++ ++ if (tty->count != 1) { ++ mutex_unlock(&tty_mutex); ++ return; ++ } ++ ++ /* Prevent other threads from re-opening this tty. */ ++ set_bit(TTY_CLOSING, &tty->flags); ++ mutex_unlock(&tty_mutex); ++ ++ tty->closing = 1; ++ tty_wait_until_sent(tty, 0); ++ if (DRV(tty->driver)->flush_buffer != NULL) ++ DRV(tty->driver)->flush_buffer(tty); ++ if (tty->ldisc.flush_buffer != NULL) ++ tty->ldisc.flush_buffer(tty); ++ tty->closing = 0; ++ spin_lock_irqsave(&xencons_lock, flags); ++ xencons_tty = NULL; ++ spin_unlock_irqrestore(&xencons_lock, flags); ++} ++ ++static struct tty_operations xencons_ops = { ++ .open = xencons_open, ++ .close = xencons_close, ++ .write = xencons_write, ++ .write_room = xencons_write_room, ++ .put_char = xencons_put_char, ++ .flush_chars = xencons_flush_chars, ++ .chars_in_buffer = xencons_chars_in_buffer, ++ .send_xchar = xencons_send_xchar, ++ .flush_buffer = xencons_flush_buffer, ++ .throttle = xencons_throttle, ++ .unthrottle = xencons_unthrottle, ++ .wait_until_sent = xencons_wait_until_sent, ++}; ++ ++static int __init xencons_init(void) ++{ ++ int rc; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ if (xc_mode == XC_OFF) ++ return 0; ++ ++ if (!is_initial_xendomain()) { ++ rc = xencons_ring_init(); ++ if (rc) ++ return rc; ++ } ++ ++ xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ? ++ MAX_NR_CONSOLES : 1); ++ if (xencons_driver == NULL) ++ return -ENOMEM; ++ ++ DRV(xencons_driver)->name = "xencons"; ++ DRV(xencons_driver)->major = TTY_MAJOR; ++ DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL; ++ DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL; ++ DRV(xencons_driver)->init_termios = tty_std_termios; ++ DRV(xencons_driver)->flags = ++ TTY_DRIVER_REAL_RAW | ++ TTY_DRIVER_RESET_TERMIOS; ++ DRV(xencons_driver)->termios = xencons_termios; ++ DRV(xencons_driver)->termios_locked = xencons_termios_locked; ++ ++ switch (xc_mode) { ++ case XC_XVC: ++ DRV(xencons_driver)->name = "xvc"; ++ DRV(xencons_driver)->major = XEN_XVC_MAJOR; ++ DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; ++ DRV(xencons_driver)->name_base = xc_num; ++ break; ++ case XC_SERIAL: ++ DRV(xencons_driver)->name = "ttyS"; ++ DRV(xencons_driver)->minor_start = 64 + xc_num; ++ DRV(xencons_driver)->name_base = xc_num; ++ break; ++ default: ++ DRV(xencons_driver)->name = "tty"; ++ DRV(xencons_driver)->minor_start = 1; ++ DRV(xencons_driver)->name_base = 1; ++ break; ++ } ++ ++ tty_set_operations(xencons_driver, &xencons_ops); ++ ++ if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) { ++ printk("WARNING: Failed to register Xen virtual " ++ "console driver as '%s%d'\n", ++ DRV(xencons_driver)->name, ++ DRV(xencons_driver)->name_base); ++ put_tty_driver(xencons_driver); ++ xencons_driver = NULL; ++ return rc; ++ } ++ ++ if (is_initial_xendomain()) { ++ xencons_priv_irq = bind_virq_to_irqhandler( ++ VIRQ_CONSOLE, ++ 0, ++ xencons_priv_interrupt, ++ 0, ++ "console", ++ NULL); ++ BUG_ON(xencons_priv_irq < 0); ++ } ++ ++ printk("Xen virtual console successfully installed as %s%d\n", ++ DRV(xencons_driver)->name, xc_num); ++ ++ return 0; ++} ++ ++module_init(xencons_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/console/xencons_ring.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/console/xencons_ring.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,143 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial.h> ++#include <linux/major.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++ ++#include <asm/hypervisor.h> ++#include <xen/evtchn.h> ++#include <xen/xencons.h> ++#include <linux/wait.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/err.h> ++#include <xen/interface/io/console.h> ++ ++static int xencons_irq; ++ ++static inline struct xencons_interface *xencons_interface(void) ++{ ++ return mfn_to_virt(xen_start_info->console.domU.mfn); ++} ++ ++static inline void notify_daemon(void) ++{ ++ /* Use evtchn: this is called early, before irq is set up. */ ++ notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); ++} ++ ++int xencons_ring_send(const char *data, unsigned len) ++{ ++ int sent = 0; ++ struct xencons_interface *intf = xencons_interface(); ++ XENCONS_RING_IDX cons, prod; ++ ++ cons = intf->out_cons; ++ prod = intf->out_prod; ++ mb(); ++ BUG_ON((prod - cons) > sizeof(intf->out)); ++ ++ while ((sent < len) && ((prod - cons) < sizeof(intf->out))) ++ intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; ++ ++ wmb(); ++ intf->out_prod = prod; ++ ++ notify_daemon(); ++ ++ return sent; ++} ++ ++static irqreturn_t handle_input(int irq, void *unused) ++{ ++ struct xencons_interface *intf = xencons_interface(); ++ XENCONS_RING_IDX cons, prod; ++ ++ cons = intf->in_cons; ++ prod = intf->in_prod; ++ mb(); ++ BUG_ON((prod - cons) > sizeof(intf->in)); ++ ++ while (cons != prod) { ++ xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1); ++ cons++; ++ } ++ ++ mb(); ++ intf->in_cons = cons; ++ ++ notify_daemon(); ++ ++ xencons_tx(); ++ ++ return IRQ_HANDLED; ++} ++ ++int xencons_ring_init(void) ++{ ++ int irq; ++ ++ if (xencons_irq) ++ unbind_from_irqhandler(xencons_irq, NULL); ++ xencons_irq = 0; ++ ++ if (!is_running_on_xen() || ++ is_initial_xendomain() || ++ !xen_start_info->console.domU.evtchn) ++ return -ENODEV; ++ ++ irq = bind_caller_port_to_irqhandler( ++ xen_start_info->console.domU.evtchn, ++ handle_input, 0, "xencons", NULL); ++ if (irq < 0) { ++ printk(KERN_ERR "XEN console request irq failed %i\n", irq); ++ return irq; ++ } ++ ++ xencons_irq = irq; ++ ++ /* In case we have in-flight data after save/restore... */ ++ notify_daemon(); ++ ++ return 0; ++} ++ ++void xencons_resume(void) ++{ ++ (void)xencons_ring_init(); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,12 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o ++ ++obj-$(CONFIG_PROC_FS) += xen_proc.o ++obj-$(CONFIG_SYSFS) += hypervisor_sysfs.o ++obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o ++obj-$(CONFIG_XEN_SYSFS) += xen_sysfs.o ++obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o ++obj-$(CONFIG_KEXEC) += machine_kexec.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/cpu_hotplug.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/cpu_hotplug.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,172 @@ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/notifier.h> ++#include <linux/cpu.h> ++#include <xen/cpu_hotplug.h> ++#include <xen/xenbus.h> ++ ++/* ++ * Set of CPUs that remote admin software will allow us to bring online. ++ * Notified to us via xenbus. ++ */ ++static cpumask_t xenbus_allowed_cpumask; ++ ++/* Set of CPUs that local admin will allow us to bring online. */ ++static cpumask_t local_allowed_cpumask = CPU_MASK_ALL; ++ ++static int local_cpu_hotplug_request(void) ++{ ++ /* ++ * We assume a CPU hotplug request comes from local admin if it is made ++ * via a userspace process (i.e., one with a real mm_struct). ++ */ ++ return (current->mm != NULL); ++} ++ ++static void vcpu_hotplug(unsigned int cpu) ++{ ++ int err; ++ char dir[32], state[32]; ++ ++ if ((cpu >= NR_CPUS) || !cpu_possible(cpu)) ++ return; ++ ++ sprintf(dir, "cpu/%d", cpu); ++ err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state); ++ if (err != 1) { ++ printk(KERN_ERR "XENBUS: Unable to read cpu state\n"); ++ return; ++ } ++ ++ if (strcmp(state, "online") == 0) { ++ cpu_set(cpu, xenbus_allowed_cpumask); ++ (void)cpu_up(cpu); ++ } else if (strcmp(state, "offline") == 0) { ++ cpu_clear(cpu, xenbus_allowed_cpumask); ++ (void)cpu_down(cpu); ++ } else { ++ printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", ++ state, cpu); ++ } ++} ++ ++static void handle_vcpu_hotplug_event( ++ struct xenbus_watch *watch, const char **vec, unsigned int len) ++{ ++ int cpu; ++ char *cpustr; ++ const char *node = vec[XS_WATCH_PATH]; ++ ++ if ((cpustr = strstr(node, "cpu/")) != NULL) { ++ sscanf(cpustr, "cpu/%d", &cpu); ++ vcpu_hotplug(cpu); ++ } ++} ++ ++static int smpboot_cpu_notify(struct notifier_block *notifier, ++ unsigned long action, void *hcpu) ++{ ++ int cpu = (long)hcpu; ++ ++ /* ++ * We do this in a callback notifier rather than __cpu_disable() ++ * because local_cpu_hotplug_request() does not work in the latter ++ * as it's always executed from within a stopmachine kthread. ++ */ ++ if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request()) ++ cpu_clear(cpu, local_allowed_cpumask); ++ ++ return NOTIFY_OK; ++} ++ ++static int setup_cpu_watcher(struct notifier_block *notifier, ++ unsigned long event, void *data) ++{ ++ int i; ++ ++ static struct xenbus_watch cpu_watch = { ++ .node = "cpu", ++ .callback = handle_vcpu_hotplug_event, ++ .flags = XBWF_new_thread }; ++ (void)register_xenbus_watch(&cpu_watch); ++ ++ if (!is_initial_xendomain()) { ++ for_each_possible_cpu(i) ++ vcpu_hotplug(i); ++ printk(KERN_INFO "Brought up %ld CPUs\n", ++ (long)num_online_cpus()); ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static int __init setup_vcpu_hotplug_event(void) ++{ ++ static struct notifier_block hotplug_cpu = { ++ .notifier_call = smpboot_cpu_notify }; ++ static struct notifier_block xsn_cpu = { ++ .notifier_call = setup_cpu_watcher }; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ register_cpu_notifier(&hotplug_cpu); ++ register_xenstore_notifier(&xsn_cpu); ++ ++ return 0; ++} ++ ++arch_initcall(setup_vcpu_hotplug_event); ++ ++int smp_suspend(void) ++{ ++ int cpu, err; ++ ++ for_each_online_cpu(cpu) { ++ if (cpu == 0) ++ continue; ++ err = cpu_down(cpu); ++ if (err) { ++ printk(KERN_CRIT "Failed to take all CPUs " ++ "down: %d.\n", err); ++ for_each_possible_cpu(cpu) ++ vcpu_hotplug(cpu); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++void smp_resume(void) ++{ ++ int cpu; ++ ++ for_each_possible_cpu(cpu) ++ vcpu_hotplug(cpu); ++} ++ ++int cpu_up_check(unsigned int cpu) ++{ ++ int rc = 0; ++ ++ if (local_cpu_hotplug_request()) { ++ cpu_set(cpu, local_allowed_cpumask); ++ if (!cpu_isset(cpu, xenbus_allowed_cpumask)) { ++ printk("%s: attempt to bring up CPU %u disallowed by " ++ "remote admin.\n", __FUNCTION__, cpu); ++ rc = -EBUSY; ++ } ++ } else if (!cpu_isset(cpu, local_allowed_cpumask) || ++ !cpu_isset(cpu, xenbus_allowed_cpumask)) { ++ rc = -EBUSY; ++ } ++ ++ return rc; ++} ++ ++void init_xenbus_allowed_cpumask(void) ++{ ++ xenbus_allowed_cpumask = cpu_present_map; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/evtchn.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/evtchn.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,988 @@ ++/****************************************************************************** ++ * evtchn.c ++ * ++ * Communication via Xen event channels. ++ * ++ * Copyright (c) 2002-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/module.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/kernel_stat.h> ++#include <linux/version.h> ++#include <asm/atomic.h> ++#include <asm/system.h> ++#include <asm/ptrace.h> ++#include <asm/synch_bitops.h> ++#include <xen/evtchn.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/physdev.h> ++#include <asm/hypervisor.h> ++#include <linux/mc146818rtc.h> /* RTC_IRQ */ ++ ++/* ++ * This lock protects updates to the following mapping and reference-count ++ * arrays. The lock does not need to be acquired to read the mapping tables. ++ */ ++static DEFINE_SPINLOCK(irq_mapping_update_lock); ++ ++/* IRQ <-> event-channel mappings. */ ++static int evtchn_to_irq[NR_EVENT_CHANNELS] = { ++ [0 ... NR_EVENT_CHANNELS-1] = -1 }; ++ ++/* Packed IRQ information: binding type, sub-type index, and event channel. */ ++static u32 irq_info[NR_IRQS]; ++ ++/* Binding types. */ ++enum { ++ IRQT_UNBOUND, ++ IRQT_PIRQ, ++ IRQT_VIRQ, ++ IRQT_IPI, ++ IRQT_LOCAL_PORT, ++ IRQT_CALLER_PORT ++}; ++ ++/* Constructor for packed IRQ information. */ ++static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn) ++{ ++ return ((type << 24) | (index << 16) | evtchn); ++} ++ ++/* Convenient shorthand for packed representation of an unbound IRQ. */ ++#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0) ++ ++/* ++ * Accessors for packed IRQ information. ++ */ ++ ++static inline unsigned int evtchn_from_irq(int irq) ++{ ++ return (u16)(irq_info[irq]); ++} ++ ++static inline unsigned int index_from_irq(int irq) ++{ ++ return (u8)(irq_info[irq] >> 16); ++} ++ ++static inline unsigned int type_from_irq(int irq) ++{ ++ return (u8)(irq_info[irq] >> 24); ++} ++ ++/* IRQ <-> VIRQ mapping. */ ++DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1}; ++ ++/* IRQ <-> IPI mapping. */ ++#ifndef NR_IPIS ++#define NR_IPIS 1 ++#endif ++DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1}; ++ ++/* Reference counts for bindings to IRQs. */ ++static int irq_bindcount[NR_IRQS]; ++ ++/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */ ++static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS); ++ ++#ifdef CONFIG_SMP ++ ++static u8 cpu_evtchn[NR_EVENT_CHANNELS]; ++static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG]; ++ ++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh, ++ unsigned int idx) ++{ ++ return (sh->evtchn_pending[idx] & ++ cpu_evtchn_mask[cpu][idx] & ++ ~sh->evtchn_mask[idx]); ++} ++ ++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) ++{ ++ int irq = evtchn_to_irq[chn]; ++ ++ BUG_ON(irq == -1); ++ set_native_irq_info(irq, cpumask_of_cpu(cpu)); ++ ++ clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]); ++ set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]); ++ cpu_evtchn[chn] = cpu; ++} ++ ++static void init_evtchn_cpu_bindings(void) ++{ ++ int i; ++ ++ /* By default all event channels notify CPU#0. */ ++ for (i = 0; i < NR_IRQS; i++) ++ set_native_irq_info(i, cpumask_of_cpu(0)); ++ ++ memset(cpu_evtchn, 0, sizeof(cpu_evtchn)); ++ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0])); ++} ++ ++static inline unsigned int cpu_from_evtchn(unsigned int evtchn) ++{ ++ return cpu_evtchn[evtchn]; ++} ++ ++#else ++ ++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh, ++ unsigned int idx) ++{ ++ return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]); ++} ++ ++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) ++{ ++} ++ ++static void init_evtchn_cpu_bindings(void) ++{ ++} ++ ++static inline unsigned int cpu_from_evtchn(unsigned int evtchn) ++{ ++ return 0; ++} ++ ++#endif ++ ++/* Upcall to generic IRQ layer. */ ++#ifdef CONFIG_X86 ++extern fastcall unsigned int do_IRQ(struct pt_regs *regs); ++void __init xen_init_IRQ(void); ++void __init init_IRQ(void) ++{ ++ irq_ctx_init(0); ++ xen_init_IRQ(); ++} ++#if defined (__i386__) ++static inline void exit_idle(void) {} ++#define IRQ_REG orig_eax ++#elif defined (__x86_64__) ++#include <asm/idle.h> ++#define IRQ_REG orig_rax ++#endif ++#define do_IRQ(irq, regs) do { \ ++ (regs)->IRQ_REG = ~(irq); \ ++ do_IRQ((regs)); \ ++} while (0) ++#endif ++ ++/* Xen will never allocate port zero for any purpose. */ ++#define VALID_EVTCHN(chn) ((chn) != 0) ++ ++/* ++ * Force a proper event-channel callback from Xen after clearing the ++ * callback mask. We do this in a very simple manner, by making a call ++ * down into Xen. The pending flag will be checked by Xen on return. ++ */ ++void force_evtchn_callback(void) ++{ ++ (void)HYPERVISOR_xen_version(0, NULL); ++} ++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */ ++EXPORT_SYMBOL(force_evtchn_callback); ++ ++static DEFINE_PER_CPU(unsigned int, upcall_count) = { 0 }; ++ ++/* NB. Interrupts are disabled on entry. */ ++asmlinkage void evtchn_do_upcall(struct pt_regs *regs) ++{ ++ unsigned long l1, l2; ++ unsigned int l1i, l2i, port, count; ++ int irq, cpu = smp_processor_id(); ++ shared_info_t *s = HYPERVISOR_shared_info; ++ vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; ++ ++ do { ++ /* Avoid a callback storm when we reenable delivery. */ ++ vcpu_info->evtchn_upcall_pending = 0; ++ ++ /* Nested invocations bail immediately. */ ++ if (unlikely(per_cpu(upcall_count, cpu)++)) ++ return; ++ ++#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */ ++ /* Clear master flag /before/ clearing selector flag. */ ++ rmb(); ++#endif ++ l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); ++ while (l1 != 0) { ++ l1i = __ffs(l1); ++ l1 &= ~(1UL << l1i); ++ ++ while ((l2 = active_evtchns(cpu, s, l1i)) != 0) { ++ l2i = __ffs(l2); ++ ++ port = (l1i * BITS_PER_LONG) + l2i; ++ if ((irq = evtchn_to_irq[port]) != -1) ++ do_IRQ(irq, regs); ++ else { ++ exit_idle(); ++ evtchn_device_upcall(port); ++ } ++ } ++ } ++ ++ /* If there were nested callbacks then we have more to do. */ ++ count = per_cpu(upcall_count, cpu); ++ per_cpu(upcall_count, cpu) = 0; ++ } while (unlikely(count != 1)); ++} ++ ++static int find_unbound_irq(void) ++{ ++ static int warned; ++ int dynirq, irq; ++ ++ for (dynirq = 0; dynirq < NR_DYNIRQS; dynirq++) { ++ irq = dynirq_to_irq(dynirq); ++ if (irq_bindcount[irq] == 0) ++ return irq; ++ } ++ ++ if (!warned) { ++ warned = 1; ++ printk(KERN_WARNING "No available IRQ to bind to: " ++ "increase NR_DYNIRQS.\n"); ++ } ++ ++ return -ENOSPC; ++} ++ ++static int bind_caller_port_to_irq(unsigned int caller_port) ++{ ++ int irq; ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if ((irq = evtchn_to_irq[caller_port]) == -1) { ++ if ((irq = find_unbound_irq()) < 0) ++ goto out; ++ ++ evtchn_to_irq[caller_port] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_CALLER_PORT, 0, caller_port); ++ } ++ ++ irq_bindcount[irq]++; ++ ++ out: ++ spin_unlock(&irq_mapping_update_lock); ++ return irq; ++} ++ ++static int bind_local_port_to_irq(unsigned int local_port) ++{ ++ int irq; ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ BUG_ON(evtchn_to_irq[local_port] != -1); ++ ++ if ((irq = find_unbound_irq()) < 0) { ++ struct evtchn_close close = { .port = local_port }; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) ++ BUG(); ++ goto out; ++ } ++ ++ evtchn_to_irq[local_port] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_LOCAL_PORT, 0, local_port); ++ irq_bindcount[irq]++; ++ ++ out: ++ spin_unlock(&irq_mapping_update_lock); ++ return irq; ++} ++ ++static int bind_listening_port_to_irq(unsigned int remote_domain) ++{ ++ struct evtchn_alloc_unbound alloc_unbound; ++ int err; ++ ++ alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.remote_dom = remote_domain; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, ++ &alloc_unbound); ++ ++ return err ? : bind_local_port_to_irq(alloc_unbound.port); ++} ++ ++static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain, ++ unsigned int remote_port) ++{ ++ struct evtchn_bind_interdomain bind_interdomain; ++ int err; ++ ++ bind_interdomain.remote_dom = remote_domain; ++ bind_interdomain.remote_port = remote_port; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, ++ &bind_interdomain); ++ ++ return err ? : bind_local_port_to_irq(bind_interdomain.local_port); ++} ++ ++static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) ++{ ++ struct evtchn_bind_virq bind_virq; ++ int evtchn, irq; ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { ++ if ((irq = find_unbound_irq()) < 0) ++ goto out; ++ ++ bind_virq.virq = virq; ++ bind_virq.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, ++ &bind_virq) != 0) ++ BUG(); ++ evtchn = bind_virq.port; ++ ++ evtchn_to_irq[evtchn] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); ++ ++ per_cpu(virq_to_irq, cpu)[virq] = irq; ++ ++ bind_evtchn_to_cpu(evtchn, cpu); ++ } ++ ++ irq_bindcount[irq]++; ++ ++ out: ++ spin_unlock(&irq_mapping_update_lock); ++ return irq; ++} ++ ++static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) ++{ ++ struct evtchn_bind_ipi bind_ipi; ++ int evtchn, irq; ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { ++ if ((irq = find_unbound_irq()) < 0) ++ goto out; ++ ++ bind_ipi.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, ++ &bind_ipi) != 0) ++ BUG(); ++ evtchn = bind_ipi.port; ++ ++ evtchn_to_irq[evtchn] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); ++ ++ per_cpu(ipi_to_irq, cpu)[ipi] = irq; ++ ++ bind_evtchn_to_cpu(evtchn, cpu); ++ } ++ ++ irq_bindcount[irq]++; ++ ++ out: ++ spin_unlock(&irq_mapping_update_lock); ++ return irq; ++} ++ ++static void unbind_from_irq(unsigned int irq) ++{ ++ struct evtchn_close close; ++ int cpu, evtchn = evtchn_from_irq(irq); ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { ++ close.port = evtchn; ++ if ((type_from_irq(irq) != IRQT_CALLER_PORT) && ++ HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) ++ BUG(); ++ ++ switch (type_from_irq(irq)) { ++ case IRQT_VIRQ: ++ per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) ++ [index_from_irq(irq)] = -1; ++ break; ++ case IRQT_IPI: ++ per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) ++ [index_from_irq(irq)] = -1; ++ break; ++ default: ++ break; ++ } ++ ++ /* Closed ports are implicitly re-bound to VCPU0. */ ++ bind_evtchn_to_cpu(evtchn, 0); ++ ++ evtchn_to_irq[evtchn] = -1; ++ irq_info[irq] = IRQ_UNBOUND; ++ ++ /* Zap stats across IRQ changes of use. */ ++ for_each_possible_cpu(cpu) ++ kstat_cpu(cpu).irqs[irq] = 0; ++ } ++ ++ spin_unlock(&irq_mapping_update_lock); ++} ++ ++int bind_caller_port_to_irqhandler( ++ unsigned int caller_port, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id) ++{ ++ int irq, retval; ++ ++ irq = bind_caller_port_to_irq(caller_port); ++ if (irq < 0) ++ return irq; ++ ++ retval = request_irq(irq, handler, irqflags, devname, dev_id); ++ if (retval != 0) { ++ unbind_from_irq(irq); ++ return retval; ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_caller_port_to_irqhandler); ++ ++int bind_listening_port_to_irqhandler( ++ unsigned int remote_domain, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id) ++{ ++ int irq, retval; ++ ++ irq = bind_listening_port_to_irq(remote_domain); ++ if (irq < 0) ++ return irq; ++ ++ retval = request_irq(irq, handler, irqflags, devname, dev_id); ++ if (retval != 0) { ++ unbind_from_irq(irq); ++ return retval; ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_listening_port_to_irqhandler); ++ ++int bind_interdomain_evtchn_to_irqhandler( ++ unsigned int remote_domain, ++ unsigned int remote_port, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id) ++{ ++ int irq, retval; ++ ++ irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port); ++ if (irq < 0) ++ return irq; ++ ++ retval = request_irq(irq, handler, irqflags, devname, dev_id); ++ if (retval != 0) { ++ unbind_from_irq(irq); ++ return retval; ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler); ++ ++int bind_virq_to_irqhandler( ++ unsigned int virq, ++ unsigned int cpu, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id) ++{ ++ int irq, retval; ++ ++ irq = bind_virq_to_irq(virq, cpu); ++ if (irq < 0) ++ return irq; ++ ++ retval = request_irq(irq, handler, irqflags, devname, dev_id); ++ if (retval != 0) { ++ unbind_from_irq(irq); ++ return retval; ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler); ++ ++int bind_ipi_to_irqhandler( ++ unsigned int ipi, ++ unsigned int cpu, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id) ++{ ++ int irq, retval; ++ ++ irq = bind_ipi_to_irq(ipi, cpu); ++ if (irq < 0) ++ return irq; ++ ++ retval = request_irq(irq, handler, irqflags, devname, dev_id); ++ if (retval != 0) { ++ unbind_from_irq(irq); ++ return retval; ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler); ++ ++void unbind_from_irqhandler(unsigned int irq, void *dev_id) ++{ ++ free_irq(irq, dev_id); ++ unbind_from_irq(irq); ++} ++EXPORT_SYMBOL_GPL(unbind_from_irqhandler); ++ ++#ifdef CONFIG_SMP ++/* Rebind an evtchn so that it gets delivered to a specific cpu */ ++static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu) ++{ ++ struct evtchn_bind_vcpu bind_vcpu; ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (!VALID_EVTCHN(evtchn)) ++ return; ++ ++ /* Send future instances of this interrupt to other vcpu. */ ++ bind_vcpu.port = evtchn; ++ bind_vcpu.vcpu = tcpu; ++ ++ /* ++ * If this fails, it usually just indicates that we're dealing with a ++ * virq or IPI channel, which don't actually need to be rebound. Ignore ++ * it, but don't do the xenlinux-level rebind in that case. ++ */ ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) ++ bind_evtchn_to_cpu(evtchn, tcpu); ++} ++ ++static void set_affinity_irq(unsigned irq, cpumask_t dest) ++{ ++ unsigned tcpu = first_cpu(dest); ++ rebind_irq_to_cpu(irq, tcpu); ++} ++#endif ++ ++int resend_irq_on_evtchn(unsigned int irq) ++{ ++ int masked, evtchn = evtchn_from_irq(irq); ++ shared_info_t *s = HYPERVISOR_shared_info; ++ ++ if (!VALID_EVTCHN(evtchn)) ++ return 1; ++ ++ masked = synch_test_and_set_bit(evtchn, s->evtchn_mask); ++ synch_set_bit(evtchn, s->evtchn_pending); ++ if (!masked) ++ unmask_evtchn(evtchn); ++ ++ return 1; ++} ++ ++/* ++ * Interface to generic handling in irq.c ++ */ ++ ++static unsigned int startup_dynirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ unmask_evtchn(evtchn); ++ return 0; ++} ++ ++static void unmask_dynirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ unmask_evtchn(evtchn); ++} ++ ++static void mask_dynirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ mask_evtchn(evtchn); ++} ++ ++static void ack_dynirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ move_native_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) { ++ mask_evtchn(evtchn); ++ clear_evtchn(evtchn); ++ } ++} ++ ++static void ack_dynirq_quirk_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED)) ++ unmask_evtchn(evtchn); ++} ++ ++static struct irq_chip dynirq_chip = { ++ .name = "Dynamic-irq", ++ .startup = startup_dynirq_vector, ++ .mask = mask_dynirq_vector, ++ .unmask = unmask_dynirq_vector, ++ .ack = ack_dynirq_vector, ++ .eoi = ack_dynirq_quirk_vector, ++#ifdef CONFIG_SMP ++ .set_affinity = set_affinity_irq, ++#endif ++ .retrigger = resend_irq_on_evtchn, ++}; ++ ++static inline void pirq_unmask_notify(int pirq) ++{ ++ struct physdev_eoi eoi = { .irq = pirq }; ++ if (unlikely(test_bit(pirq, pirq_needs_eoi))) ++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); ++} ++ ++static inline void pirq_query_unmask(int pirq) ++{ ++ struct physdev_irq_status_query irq_status; ++ irq_status.irq = pirq; ++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status); ++ clear_bit(pirq, pirq_needs_eoi); ++ if (irq_status.flags & XENIRQSTAT_needs_eoi) ++ set_bit(pirq, pirq_needs_eoi); ++} ++ ++/* ++ * On startup, if there is no action associated with the IRQ then we are ++ * probing. In this case we should not share with others as it will confuse us. ++ */ ++#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL) ++ ++static unsigned int startup_pirq_vector(unsigned int irq) ++{ ++ struct evtchn_bind_pirq bind_pirq; ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ goto out; ++ ++ bind_pirq.pirq = irq; ++ /* NB. We are happy to share unless we are probing. */ ++ bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) { ++ if (!probing_irq(irq)) ++ printk(KERN_INFO "Failed to obtain physical IRQ %d\n", ++ irq); ++ return 0; ++ } ++ evtchn = bind_pirq.port; ++ ++ pirq_query_unmask(irq_to_pirq(irq)); ++ ++ evtchn_to_irq[evtchn] = irq; ++ bind_evtchn_to_cpu(evtchn, 0); ++ irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn); ++ ++ out: ++ unmask_evtchn(evtchn); ++ pirq_unmask_notify(irq_to_pirq(irq)); ++ ++ return 0; ++} ++ ++static void unmask_pirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) { ++ unmask_evtchn(evtchn); ++ pirq_unmask_notify(irq_to_pirq(irq)); ++ } ++} ++ ++static void mask_pirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ mask_evtchn(evtchn); ++} ++ ++static void ack_pirq_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ move_native_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) { ++ mask_evtchn(evtchn); ++ clear_evtchn(evtchn); ++ } ++} ++ ++static void ack_pirq_quirk_vector(unsigned int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED)) { ++ unmask_evtchn(evtchn); ++ pirq_unmask_notify(irq_to_pirq(irq)); ++ } ++} ++ ++static struct irq_chip pirq_chip = { ++ .name = "Phys-irq", ++ .startup = startup_pirq_vector, ++ .mask = mask_pirq_vector, ++ .unmask = unmask_pirq_vector, ++ .ack = ack_pirq_vector, ++ .eoi = ack_pirq_quirk_vector, ++#ifdef CONFIG_SMP ++ .set_affinity = set_affinity_irq, ++#endif ++ .retrigger = resend_irq_on_evtchn, ++}; ++ ++int irq_ignore_unhandled(unsigned int irq) ++{ ++ struct physdev_irq_status_query irq_status = { .irq = irq }; ++ ++ if (!is_running_on_xen()) ++ return 0; ++ ++ (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status); ++ return !!(irq_status.flags & XENIRQSTAT_shared); ++} ++ ++void notify_remote_via_irq(int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ if (VALID_EVTCHN(evtchn)) ++ notify_remote_via_evtchn(evtchn); ++} ++EXPORT_SYMBOL_GPL(notify_remote_via_irq); ++ ++int irq_to_evtchn_port(int irq) ++{ ++ return evtchn_from_irq(irq); ++} ++EXPORT_SYMBOL_GPL(irq_to_evtchn_port); ++ ++void mask_evtchn(int port) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ synch_set_bit(port, s->evtchn_mask); ++} ++EXPORT_SYMBOL_GPL(mask_evtchn); ++ ++void unmask_evtchn(int port) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ unsigned int cpu = smp_processor_id(); ++ vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; ++ ++ BUG_ON(!irqs_disabled()); ++ ++ /* Slow path (hypercall) if this is a non-local port. */ ++ if (unlikely(cpu != cpu_from_evtchn(port))) { ++ struct evtchn_unmask unmask = { .port = port }; ++ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); ++ return; ++ } ++ ++ synch_clear_bit(port, s->evtchn_mask); ++ ++ /* Did we miss an interrupt 'edge'? Re-fire if so. */ ++ if (synch_test_bit(port, s->evtchn_pending) && ++ !synch_test_and_set_bit(port / BITS_PER_LONG, ++ &vcpu_info->evtchn_pending_sel)) ++ vcpu_info->evtchn_upcall_pending = 1; ++} ++EXPORT_SYMBOL_GPL(unmask_evtchn); ++ ++static void restore_cpu_virqs(int cpu) ++{ ++ struct evtchn_bind_virq bind_virq; ++ int virq, irq, evtchn; ++ ++ for (virq = 0; virq < NR_VIRQS; virq++) { ++ if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) ++ continue; ++ ++ BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0)); ++ ++ /* Get a new binding from Xen. */ ++ bind_virq.virq = virq; ++ bind_virq.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, ++ &bind_virq) != 0) ++ BUG(); ++ evtchn = bind_virq.port; ++ ++ /* Record the new mapping. */ ++ evtchn_to_irq[evtchn] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); ++ bind_evtchn_to_cpu(evtchn, cpu); ++ ++ /* Ready for use. */ ++ unmask_evtchn(evtchn); ++ } ++} ++ ++static void restore_cpu_ipis(int cpu) ++{ ++ struct evtchn_bind_ipi bind_ipi; ++ int ipi, irq, evtchn; ++ ++ for (ipi = 0; ipi < NR_IPIS; ipi++) { ++ if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) ++ continue; ++ ++ BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0)); ++ ++ /* Get a new binding from Xen. */ ++ bind_ipi.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, ++ &bind_ipi) != 0) ++ BUG(); ++ evtchn = bind_ipi.port; ++ ++ /* Record the new mapping. */ ++ evtchn_to_irq[evtchn] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); ++ bind_evtchn_to_cpu(evtchn, cpu); ++ ++ /* Ready for use. */ ++ unmask_evtchn(evtchn); ++ ++ } ++} ++ ++void irq_resume(void) ++{ ++ int cpu, pirq, irq, evtchn; ++ ++ init_evtchn_cpu_bindings(); ++ ++ /* New event-channel space is not 'live' yet. */ ++ for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) ++ mask_evtchn(evtchn); ++ ++ /* Check that no PIRQs are still bound. */ ++ for (pirq = 0; pirq < NR_PIRQS; pirq++) ++ BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND); ++ ++ /* No IRQ <-> event-channel mappings. */ ++ for (irq = 0; irq < NR_IRQS; irq++) ++ irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */ ++ for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) ++ evtchn_to_irq[evtchn] = -1; ++ ++ for_each_possible_cpu(cpu) { ++ restore_cpu_virqs(cpu); ++ restore_cpu_ipis(cpu); ++ } ++ ++} ++ ++void __init xen_init_IRQ(void) ++{ ++ int i; ++ ++ init_evtchn_cpu_bindings(); ++ ++ /* No event channels are 'live' right now. */ ++ for (i = 0; i < NR_EVENT_CHANNELS; i++) ++ mask_evtchn(i); ++ ++ /* No IRQ -> event-channel mappings. */ ++ for (i = 0; i < NR_IRQS; i++) ++ irq_info[i] = IRQ_UNBOUND; ++ ++ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */ ++ for (i = 0; i < NR_DYNIRQS; i++) { ++ irq_bindcount[dynirq_to_irq(i)] = 0; ++ ++ irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED; ++ irq_desc[dynirq_to_irq(i)].action = NULL; ++ irq_desc[dynirq_to_irq(i)].depth = 1; ++ set_irq_chip_and_handler_name(dynirq_to_irq(i), &dynirq_chip, ++ handle_level_irq, "level"); ++ } ++ ++ /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */ ++ for (i = 0; i < NR_PIRQS; i++) { ++ irq_bindcount[pirq_to_irq(i)] = 1; ++ ++#ifdef RTC_IRQ ++ /* If not domain 0, force our RTC driver to fail its probe. */ ++ if ((i == RTC_IRQ) && !is_initial_xendomain()) ++ continue; ++#endif ++ ++ irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED; ++ irq_desc[pirq_to_irq(i)].action = NULL; ++ irq_desc[pirq_to_irq(i)].depth = 1; ++ set_irq_chip_and_handler_name(pirq_to_irq(i), &pirq_chip, ++ handle_level_irq, "level"); ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/features.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/features.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,34 @@ ++/****************************************************************************** ++ * features.c ++ * ++ * Xen feature flags. ++ * ++ * Copyright (c) 2006, Ian Campbell, XenSource Inc. ++ */ ++#include <linux/types.h> ++#include <linux/cache.h> ++#include <linux/module.h> ++#include <asm/hypervisor.h> ++#include <xen/features.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly; ++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */ ++EXPORT_SYMBOL(xen_features); ++ ++void setup_xen_features(void) ++{ ++ xen_feature_info_t fi; ++ int i, j; ++ ++ for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) { ++ fi.submap_idx = i; ++ if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0) ++ break; ++ for (j=0; j<32; j++) ++ xen_features[i*32+j] = !!(fi.submap & 1<<j); ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/gnttab.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/gnttab.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,631 @@ ++/****************************************************************************** ++ * gnttab.c ++ * ++ * Granting foreign access to our memory reservation. ++ * ++ * Copyright (c) 2005-2006, Christopher Clark ++ * Copyright (c) 2004-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <xen/interface/xen.h> ++#include <xen/gnttab.h> ++#include <asm/pgtable.h> ++#include <asm/uaccess.h> ++#include <asm/synch_bitops.h> ++#include <asm/io.h> ++#include <xen/interface/memory.h> ++#include <xen/driver_util.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++/* External tools reserve first few grant table entries. */ ++#define NR_RESERVED_ENTRIES 8 ++#define GNTTAB_LIST_END 0xffffffff ++#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t)) ++ ++static grant_ref_t **gnttab_list; ++static unsigned int nr_grant_frames; ++static unsigned int boot_max_nr_grant_frames; ++static int gnttab_free_count; ++static grant_ref_t gnttab_free_head; ++static DEFINE_SPINLOCK(gnttab_list_lock); ++ ++static struct grant_entry *shared; ++ ++static struct gnttab_free_callback *gnttab_free_callback_list; ++ ++static int gnttab_expand(unsigned int req_entries); ++ ++#define RPP (PAGE_SIZE / sizeof(grant_ref_t)) ++#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) ++ ++static int get_free_entries(int count) ++{ ++ unsigned long flags; ++ int ref, rc; ++ grant_ref_t head; ++ ++ spin_lock_irqsave(&gnttab_list_lock, flags); ++ ++ if ((gnttab_free_count < count) && ++ ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) { ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++ return rc; ++ } ++ ++ ref = head = gnttab_free_head; ++ gnttab_free_count -= count; ++ while (count-- > 1) ++ head = gnttab_entry(head); ++ gnttab_free_head = gnttab_entry(head); ++ gnttab_entry(head) = GNTTAB_LIST_END; ++ ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++ ++ return ref; ++} ++ ++#define get_free_entry() get_free_entries(1) ++ ++static void do_free_callbacks(void) ++{ ++ struct gnttab_free_callback *callback, *next; ++ ++ callback = gnttab_free_callback_list; ++ gnttab_free_callback_list = NULL; ++ ++ while (callback != NULL) { ++ next = callback->next; ++ if (gnttab_free_count >= callback->count) { ++ callback->next = NULL; ++ callback->fn(callback->arg); ++ } else { ++ callback->next = gnttab_free_callback_list; ++ gnttab_free_callback_list = callback; ++ } ++ callback = next; ++ } ++} ++ ++static inline void check_free_callbacks(void) ++{ ++ if (unlikely(gnttab_free_callback_list)) ++ do_free_callbacks(); ++} ++ ++static void put_free_entry(grant_ref_t ref) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&gnttab_list_lock, flags); ++ gnttab_entry(ref) = gnttab_free_head; ++ gnttab_free_head = ref; ++ gnttab_free_count++; ++ check_free_callbacks(); ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++} ++ ++/* ++ * Public grant-issuing interface functions ++ */ ++ ++int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, ++ int readonly) ++{ ++ int ref; ++ ++ if (unlikely((ref = get_free_entry()) < 0)) ++ return -ENOSPC; ++ ++ shared[ref].frame = frame; ++ shared[ref].domid = domid; ++ wmb(); ++ shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); ++ ++ return ref; ++} ++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); ++ ++void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, ++ unsigned long frame, int readonly) ++{ ++ shared[ref].frame = frame; ++ shared[ref].domid = domid; ++ wmb(); ++ shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); ++} ++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); ++ ++ ++int gnttab_query_foreign_access(grant_ref_t ref) ++{ ++ u16 nflags; ++ ++ nflags = shared[ref].flags; ++ ++ return (nflags & (GTF_reading|GTF_writing)); ++} ++EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); ++ ++int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) ++{ ++ u16 flags, nflags; ++ ++ nflags = shared[ref].flags; ++ do { ++ if ((flags = nflags) & (GTF_reading|GTF_writing)) { ++ printk(KERN_ALERT "WARNING: g.e. still in use!\n"); ++ return 0; ++ } ++ } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) != ++ flags); ++ ++ return 1; ++} ++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); ++ ++void gnttab_end_foreign_access(grant_ref_t ref, int readonly, ++ unsigned long page) ++{ ++ if (gnttab_end_foreign_access_ref(ref, readonly)) { ++ put_free_entry(ref); ++ if (page != 0) ++ free_page(page); ++ } else { ++ /* XXX This needs to be fixed so that the ref and page are ++ placed on a list to be freed up later. */ ++ printk(KERN_WARNING ++ "WARNING: leaking g.e. and page still in use!\n"); ++ } ++} ++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access); ++ ++int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn) ++{ ++ int ref; ++ ++ if (unlikely((ref = get_free_entry()) < 0)) ++ return -ENOSPC; ++ gnttab_grant_foreign_transfer_ref(ref, domid, pfn); ++ ++ return ref; ++} ++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer); ++ ++void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, ++ unsigned long pfn) ++{ ++ shared[ref].frame = pfn; ++ shared[ref].domid = domid; ++ wmb(); ++ shared[ref].flags = GTF_accept_transfer; ++} ++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); ++ ++unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) ++{ ++ unsigned long frame; ++ u16 flags; ++ ++ /* ++ * If a transfer is not even yet started, try to reclaim the grant ++ * reference and return failure (== 0). ++ */ ++ while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { ++ if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags) ++ return 0; ++ cpu_relax(); ++ } ++ ++ /* If a transfer is in progress then wait until it is completed. */ ++ while (!(flags & GTF_transfer_completed)) { ++ flags = shared[ref].flags; ++ cpu_relax(); ++ } ++ ++ /* Read the frame number /after/ reading completion status. */ ++ rmb(); ++ frame = shared[ref].frame; ++ BUG_ON(frame == 0); ++ ++ return frame; ++} ++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); ++ ++unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) ++{ ++ unsigned long frame = gnttab_end_foreign_transfer_ref(ref); ++ put_free_entry(ref); ++ return frame; ++} ++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer); ++ ++void gnttab_free_grant_reference(grant_ref_t ref) ++{ ++ put_free_entry(ref); ++} ++EXPORT_SYMBOL_GPL(gnttab_free_grant_reference); ++ ++void gnttab_free_grant_references(grant_ref_t head) ++{ ++ grant_ref_t ref; ++ unsigned long flags; ++ int count = 1; ++ if (head == GNTTAB_LIST_END) ++ return; ++ spin_lock_irqsave(&gnttab_list_lock, flags); ++ ref = head; ++ while (gnttab_entry(ref) != GNTTAB_LIST_END) { ++ ref = gnttab_entry(ref); ++ count++; ++ } ++ gnttab_entry(ref) = gnttab_free_head; ++ gnttab_free_head = head; ++ gnttab_free_count += count; ++ check_free_callbacks(); ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++} ++EXPORT_SYMBOL_GPL(gnttab_free_grant_references); ++ ++int gnttab_alloc_grant_references(u16 count, grant_ref_t *head) ++{ ++ int h = get_free_entries(count); ++ ++ if (h < 0) ++ return -ENOSPC; ++ ++ *head = h; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references); ++ ++int gnttab_empty_grant_references(const grant_ref_t *private_head) ++{ ++ return (*private_head == GNTTAB_LIST_END); ++} ++EXPORT_SYMBOL_GPL(gnttab_empty_grant_references); ++ ++int gnttab_claim_grant_reference(grant_ref_t *private_head) ++{ ++ grant_ref_t g = *private_head; ++ if (unlikely(g == GNTTAB_LIST_END)) ++ return -ENOSPC; ++ *private_head = gnttab_entry(g); ++ return g; ++} ++EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference); ++ ++void gnttab_release_grant_reference(grant_ref_t *private_head, ++ grant_ref_t release) ++{ ++ gnttab_entry(release) = *private_head; ++ *private_head = release; ++} ++EXPORT_SYMBOL_GPL(gnttab_release_grant_reference); ++ ++void gnttab_request_free_callback(struct gnttab_free_callback *callback, ++ void (*fn)(void *), void *arg, u16 count) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&gnttab_list_lock, flags); ++ if (callback->next) ++ goto out; ++ callback->fn = fn; ++ callback->arg = arg; ++ callback->count = count; ++ callback->next = gnttab_free_callback_list; ++ gnttab_free_callback_list = callback; ++ check_free_callbacks(); ++out: ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++} ++EXPORT_SYMBOL_GPL(gnttab_request_free_callback); ++ ++void gnttab_cancel_free_callback(struct gnttab_free_callback *callback) ++{ ++ struct gnttab_free_callback **pcb; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gnttab_list_lock, flags); ++ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { ++ if (*pcb == callback) { ++ *pcb = callback->next; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&gnttab_list_lock, flags); ++} ++EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback); ++ ++static int grow_gnttab_list(unsigned int more_frames) ++{ ++ unsigned int new_nr_grant_frames, extra_entries, i; ++ ++ new_nr_grant_frames = nr_grant_frames + more_frames; ++ extra_entries = more_frames * GREFS_PER_GRANT_FRAME; ++ ++ for (i = nr_grant_frames; i < new_nr_grant_frames; i++) ++ { ++ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC); ++ if (!gnttab_list[i]) ++ goto grow_nomem; ++ } ++ ++ ++ for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; ++ i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) ++ gnttab_entry(i) = i + 1; ++ ++ gnttab_entry(i) = gnttab_free_head; ++ gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; ++ gnttab_free_count += extra_entries; ++ ++ nr_grant_frames = new_nr_grant_frames; ++ ++ check_free_callbacks(); ++ ++ return 0; ++ ++grow_nomem: ++ for ( ; i >= nr_grant_frames; i--) ++ free_page((unsigned long) gnttab_list[i]); ++ return -ENOMEM; ++} ++ ++static unsigned int __max_nr_grant_frames(void) ++{ ++ struct gnttab_query_size query; ++ int rc; ++ ++ query.dom = DOMID_SELF; ++ ++ rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); ++ if ((rc < 0) || (query.status != GNTST_okay)) ++ return 4; /* Legacy max supported number of frames */ ++ ++ return query.max_nr_frames; ++} ++ ++static inline unsigned int max_nr_grant_frames(void) ++{ ++ unsigned int xen_max = __max_nr_grant_frames(); ++ ++ if (xen_max > boot_max_nr_grant_frames) ++ return boot_max_nr_grant_frames; ++ return xen_max; ++} ++ ++#ifdef CONFIG_XEN ++ ++#ifndef __ia64__ ++static int map_pte_fn(pte_t *pte, struct page *pmd_page, ++ unsigned long addr, void *data) ++{ ++ unsigned long **frames = (unsigned long **)data; ++ ++ set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL)); ++ (*frames)++; ++ return 0; ++} ++ ++static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, ++ unsigned long addr, void *data) ++{ ++ ++ set_pte_at(&init_mm, addr, pte, __pte(0)); ++ return 0; ++} ++#endif ++ ++static int gnttab_map(unsigned int start_idx, unsigned int end_idx) ++{ ++ struct gnttab_setup_table setup; ++ unsigned long *frames; ++ unsigned int nr_gframes = end_idx + 1; ++ int rc; ++ ++ frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); ++ if (!frames) ++ return -ENOMEM; ++ ++ setup.dom = DOMID_SELF; ++ setup.nr_frames = nr_gframes; ++ set_xen_guest_handle(setup.frame_list, frames); ++ ++ rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); ++ if (rc == -ENOSYS) { ++ kfree(frames); ++ return -ENOSYS; ++ } ++ ++ BUG_ON(rc || setup.status); ++ ++#ifndef __ia64__ ++ if (shared == NULL) { ++ struct vm_struct *area; ++ area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames()); ++ BUG_ON(area == NULL); ++ shared = area->addr; ++ } ++ rc = apply_to_page_range(&init_mm, (unsigned long)shared, ++ PAGE_SIZE * nr_gframes, ++ map_pte_fn, &frames); ++ BUG_ON(rc); ++ frames -= nr_gframes; /* adjust after map_pte_fn() */ ++#else ++ shared = __va(frames[0] << PAGE_SHIFT); ++#endif ++ ++ kfree(frames); ++ ++ return 0; ++} ++ ++int gnttab_resume(void) ++{ ++ if (max_nr_grant_frames() < nr_grant_frames) ++ return -ENOSYS; ++ return gnttab_map(0, nr_grant_frames - 1); ++} ++ ++int gnttab_suspend(void) ++{ ++#ifndef __ia64__ ++ apply_to_page_range(&init_mm, (unsigned long)shared, ++ PAGE_SIZE * nr_grant_frames, ++ unmap_pte_fn, NULL); ++#endif ++ return 0; ++} ++ ++#else /* !CONFIG_XEN */ ++ ++#include <platform-pci.h> ++ ++static unsigned long resume_frames; ++ ++static int gnttab_map(unsigned int start_idx, unsigned int end_idx) ++{ ++ struct xen_add_to_physmap xatp; ++ unsigned int i = end_idx; ++ ++ /* Loop backwards, so that the first hypercall has the largest index, ++ * ensuring that the table will grow only once. ++ */ ++ do { ++ xatp.domid = DOMID_SELF; ++ xatp.idx = i; ++ xatp.space = XENMAPSPACE_grant_table; ++ xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i; ++ if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) ++ BUG(); ++ } while (i-- > start_idx); ++ ++ return 0; ++} ++ ++int gnttab_resume(void) ++{ ++ unsigned int max_nr_gframes, nr_gframes; ++ ++ nr_gframes = nr_grant_frames; ++ max_nr_gframes = max_nr_grant_frames(); ++ if (max_nr_gframes < nr_gframes) ++ return -ENOSYS; ++ ++ if (!resume_frames) { ++ resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); ++ shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes); ++ if (shared == NULL) { ++ printk("error to ioremap gnttab share frames\n"); ++ return -1; ++ } ++ } ++ ++ gnttab_map(0, nr_gframes - 1); ++ ++ return 0; ++} ++ ++#endif /* !CONFIG_XEN */ ++ ++static int gnttab_expand(unsigned int req_entries) ++{ ++ int rc; ++ unsigned int cur, extra; ++ ++ cur = nr_grant_frames; ++ extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / ++ GREFS_PER_GRANT_FRAME); ++ if (cur + extra > max_nr_grant_frames()) ++ return -ENOSPC; ++ ++ if ((rc = gnttab_map(cur, cur + extra - 1)) == 0) ++ rc = grow_gnttab_list(extra); ++ ++ return rc; ++} ++ ++int __devinit gnttab_init(void) ++{ ++ int i; ++ unsigned int max_nr_glist_frames; ++ unsigned int nr_init_grefs; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ nr_grant_frames = 1; ++ boot_max_nr_grant_frames = __max_nr_grant_frames(); ++ ++ /* Determine the maximum number of frames required for the ++ * grant reference free list on the current hypervisor. ++ */ ++ max_nr_glist_frames = (boot_max_nr_grant_frames * ++ GREFS_PER_GRANT_FRAME / ++ (PAGE_SIZE / sizeof(grant_ref_t))); ++ ++ gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), ++ GFP_KERNEL); ++ if (gnttab_list == NULL) ++ return -ENOMEM; ++ ++ for (i = 0; i < nr_grant_frames; i++) { ++ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); ++ if (gnttab_list[i] == NULL) ++ goto ini_nomem; ++ } ++ ++ if (gnttab_resume() < 0) ++ return -ENODEV; ++ ++ nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; ++ ++ for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) ++ gnttab_entry(i) = i + 1; ++ ++ gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; ++ gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; ++ gnttab_free_head = NR_RESERVED_ENTRIES; ++ ++ return 0; ++ ++ ini_nomem: ++ for (i--; i >= 0; i--) ++ free_page((unsigned long)gnttab_list[i]); ++ kfree(gnttab_list); ++ return -ENOMEM; ++} ++ ++#ifdef CONFIG_XEN ++core_initcall(gnttab_init); ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/hypervisor_sysfs.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/hypervisor_sysfs.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,59 @@ ++/* ++ * copyright (c) 2006 IBM Corporation ++ * Authored by: Mike D. Day <ncmike@us.ibm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/kobject.h> ++#include <xen/hypervisor_sysfs.h> ++ ++decl_subsys(hypervisor, NULL, NULL); ++ ++static ssize_t hyp_sysfs_show(struct kobject *kobj, ++ struct attribute *attr, ++ char *buffer) ++{ ++ struct hyp_sysfs_attr *hyp_attr; ++ hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr); ++ if (hyp_attr->show) ++ return hyp_attr->show(hyp_attr, buffer); ++ return 0; ++} ++ ++static ssize_t hyp_sysfs_store(struct kobject *kobj, ++ struct attribute *attr, ++ const char *buffer, ++ size_t len) ++{ ++ struct hyp_sysfs_attr *hyp_attr; ++ hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr); ++ if (hyp_attr->store) ++ return hyp_attr->store(hyp_attr, buffer, len); ++ return 0; ++} ++ ++struct sysfs_ops hyp_sysfs_ops = { ++ .show = hyp_sysfs_show, ++ .store = hyp_sysfs_store, ++}; ++ ++static struct kobj_type hyp_sysfs_kobj_type = { ++ .sysfs_ops = &hyp_sysfs_ops, ++}; ++ ++static int __init hypervisor_subsys_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ hypervisor_subsys.kset.kobj.ktype = &hyp_sysfs_kobj_type; ++ return subsystem_register(&hypervisor_subsys); ++} ++ ++device_initcall(hypervisor_subsys_init); ++EXPORT_SYMBOL_GPL(hypervisor_subsys); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/machine_kexec.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/machine_kexec.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,189 @@ ++/* ++ * drivers/xen/core/machine_kexec.c ++ * handle transition of Linux booting another kernel ++ */ ++ ++#include <linux/kexec.h> ++#include <xen/interface/kexec.h> ++#include <linux/mm.h> ++#include <linux/bootmem.h> ++ ++extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, ++ struct kimage *image); ++ ++int xen_max_nr_phys_cpus; ++struct resource xen_hypervisor_res; ++struct resource *xen_phys_cpus; ++ ++void xen_machine_kexec_setup_resources(void) ++{ ++ xen_kexec_range_t range; ++ struct resource *res; ++ int k = 0; ++ ++ if (!is_initial_xendomain()) ++ return; ++ ++ /* determine maximum number of physical cpus */ ++ ++ while (1) { ++ memset(&range, 0, sizeof(range)); ++ range.range = KEXEC_RANGE_MA_CPU; ++ range.nr = k; ++ ++ if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) ++ break; ++ ++ k++; ++ } ++ ++ if (k == 0) ++ return; ++ ++ xen_max_nr_phys_cpus = k; ++ ++ /* allocate xen_phys_cpus */ ++ ++ xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); ++ BUG_ON(xen_phys_cpus == NULL); ++ ++ /* fill in xen_phys_cpus with per-cpu crash note information */ ++ ++ for (k = 0; k < xen_max_nr_phys_cpus; k++) { ++ memset(&range, 0, sizeof(range)); ++ range.range = KEXEC_RANGE_MA_CPU; ++ range.nr = k; ++ ++ if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) ++ goto err; ++ ++ res = xen_phys_cpus + k; ++ ++ memset(res, 0, sizeof(*res)); ++ res->name = "Crash note"; ++ res->start = range.start; ++ res->end = range.start + range.size - 1; ++ res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; ++ } ++ ++ /* fill in xen_hypervisor_res with hypervisor machine address range */ ++ ++ memset(&range, 0, sizeof(range)); ++ range.range = KEXEC_RANGE_MA_XEN; ++ ++ if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) ++ goto err; ++ ++ xen_hypervisor_res.name = "Hypervisor code and data"; ++ xen_hypervisor_res.start = range.start; ++ xen_hypervisor_res.end = range.start + range.size - 1; ++ xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM; ++ ++ /* fill in crashk_res if range is reserved by hypervisor */ ++ ++ memset(&range, 0, sizeof(range)); ++ range.range = KEXEC_RANGE_MA_CRASH; ++ ++ if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) ++ return; ++ ++ if (range.size) { ++ crashk_res.start = range.start; ++ crashk_res.end = range.start + range.size - 1; ++ } ++ ++ return; ++ ++ err: ++ /* ++ * It isn't possible to free xen_phys_cpus this early in the ++ * boot. Failure at this stage is unexpected and the amount of ++ * memory is small therefore we tolerate the potential leak. ++ */ ++ xen_max_nr_phys_cpus = 0; ++ return; ++} ++ ++void xen_machine_kexec_register_resources(struct resource *res) ++{ ++ int k; ++ ++ request_resource(res, &xen_hypervisor_res); ++ ++ for (k = 0; k < xen_max_nr_phys_cpus; k++) ++ request_resource(&xen_hypervisor_res, xen_phys_cpus + k); ++ ++} ++ ++static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) ++{ ++ machine_kexec_setup_load_arg(xki, image); ++ ++ xki->indirection_page = image->head; ++ xki->start_address = image->start; ++} ++ ++/* ++ * Load the image into xen so xen can kdump itself ++ * This might have been done in prepare, but prepare ++ * is currently called too early. It might make sense ++ * to move prepare, but for now, just add an extra hook. ++ */ ++int xen_machine_kexec_load(struct kimage *image) ++{ ++ xen_kexec_load_t xkl; ++ ++ memset(&xkl, 0, sizeof(xkl)); ++ xkl.type = image->type; ++ setup_load_arg(&xkl.image, image); ++ return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl); ++} ++ ++/* ++ * Unload the image that was stored by machine_kexec_load() ++ * This might have been done in machine_kexec_cleanup() but it ++ * is called too late, and its possible xen could try and kdump ++ * using resources that have been freed. ++ */ ++void xen_machine_kexec_unload(struct kimage *image) ++{ ++ xen_kexec_load_t xkl; ++ ++ memset(&xkl, 0, sizeof(xkl)); ++ xkl.type = image->type; ++ HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl); ++} ++ ++/* ++ * Do not allocate memory (or fail in any way) in machine_kexec(). ++ * We are past the point of no return, committed to rebooting now. ++ * ++ * This has the hypervisor move to the prefered reboot CPU, ++ * stop all CPUs and kexec. That is it combines machine_shutdown() ++ * and machine_kexec() in Linux kexec terms. ++ */ ++NORET_TYPE void machine_kexec(struct kimage *image) ++{ ++ xen_kexec_exec_t xke; ++ ++ memset(&xke, 0, sizeof(xke)); ++ xke.type = image->type; ++ HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke); ++ panic("KEXEC_CMD_kexec hypercall should not return\n"); ++} ++ ++void machine_shutdown(void) ++{ ++ /* do nothing */ ++} ++ ++ ++/* ++ * Local variables: ++ * c-file-style: "linux" ++ * indent-tabs-mode: t ++ * c-indent-level: 8 ++ * c-basic-offset: 8 ++ * tab-width: 8 ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/machine_reboot.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/machine_reboot.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,241 @@ ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/unistd.h> ++#include <linux/module.h> ++#include <linux/reboot.h> ++#include <linux/sysrq.h> ++#include <linux/stringify.h> ++#include <linux/stop_machine.h> ++#include <asm/irq.h> ++#include <asm/mmu_context.h> ++#include <xen/evtchn.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <linux/cpu.h> ++#include <linux/kthread.h> ++#include <xen/gnttab.h> ++#include <xen/xencons.h> ++#include <xen/cpu_hotplug.h> ++#include <xen/interface/vcpu.h> ++ ++#if defined(__i386__) || defined(__x86_64__) ++ ++/* ++ * Power off function, if any ++ */ ++void (*pm_power_off)(void); ++EXPORT_SYMBOL(pm_power_off); ++ ++void machine_emergency_restart(void) ++{ ++ /* We really want to get pending console data out before we die. */ ++ xencons_force_flush(); ++ HYPERVISOR_shutdown(SHUTDOWN_reboot); ++} ++ ++void machine_restart(char * __unused) ++{ ++ machine_emergency_restart(); ++} ++ ++void machine_halt(void) ++{ ++ machine_power_off(); ++} ++ ++void machine_power_off(void) ++{ ++ /* We really want to get pending console data out before we die. */ ++ xencons_force_flush(); ++ if (pm_power_off) ++ pm_power_off(); ++ HYPERVISOR_shutdown(SHUTDOWN_poweroff); ++} ++ ++int reboot_thru_bios = 0; /* for dmi_scan.c */ ++EXPORT_SYMBOL(machine_restart); ++EXPORT_SYMBOL(machine_halt); ++EXPORT_SYMBOL(machine_power_off); ++ ++static void pre_suspend(void) ++{ ++ HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page; ++ HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO), ++ __pte_ma(0), 0); ++ ++ xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn); ++ xen_start_info->console.domU.mfn = ++ mfn_to_pfn(xen_start_info->console.domU.mfn); ++} ++ ++static void post_suspend(int suspend_cancelled) ++{ ++ int i, j, k, fpp; ++ unsigned long shinfo_mfn; ++ extern unsigned long max_pfn; ++ extern unsigned long *pfn_to_mfn_frame_list_list; ++ extern unsigned long *pfn_to_mfn_frame_list[]; ++ ++ if (suspend_cancelled) { ++ xen_start_info->store_mfn = ++ pfn_to_mfn(xen_start_info->store_mfn); ++ xen_start_info->console.domU.mfn = ++ pfn_to_mfn(xen_start_info->console.domU.mfn); ++ } else { ++#ifdef CONFIG_SMP ++ cpu_initialized_map = cpu_online_map; ++#endif ++ } ++ ++ shinfo_mfn = xen_start_info->shared_info >> PAGE_SHIFT; ++ HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO), ++ pfn_pte_ma(shinfo_mfn, PAGE_KERNEL), 0); ++ HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); ++ ++ memset(empty_zero_page, 0, PAGE_SIZE); ++ ++ fpp = PAGE_SIZE/sizeof(unsigned long); ++ for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { ++ if ((j % fpp) == 0) { ++ k++; ++ pfn_to_mfn_frame_list_list[k] = ++ virt_to_mfn(pfn_to_mfn_frame_list[k]); ++ j = 0; ++ } ++ pfn_to_mfn_frame_list[k][j] = ++ virt_to_mfn(&phys_to_machine_mapping[i]); ++ } ++ HYPERVISOR_shared_info->arch.max_pfn = max_pfn; ++ HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = ++ virt_to_mfn(pfn_to_mfn_frame_list_list); ++} ++ ++#else /* !(defined(__i386__) || defined(__x86_64__)) */ ++ ++#ifndef HAVE_XEN_PRE_SUSPEND ++#define xen_pre_suspend() ((void)0) ++#endif ++ ++#ifndef HAVE_XEN_POST_SUSPEND ++#define xen_post_suspend(x) ((void)0) ++#endif ++ ++#define switch_idle_mm() ((void)0) ++#define mm_pin_all() ((void)0) ++#define pre_suspend() xen_pre_suspend() ++#define post_suspend(x) xen_post_suspend(x) ++ ++#endif ++ ++static int take_machine_down(void *p_fast_suspend) ++{ ++ int fast_suspend = *(int *)p_fast_suspend; ++ int suspend_cancelled, err; ++ extern void time_resume(void); ++ ++ if (fast_suspend) { ++ BUG_ON(!irqs_disabled()); ++ } else { ++ BUG_ON(irqs_disabled()); ++ ++ for (;;) { ++ err = smp_suspend(); ++ if (err) ++ return err; ++ ++ xenbus_suspend(); ++ preempt_disable(); ++ ++ if (num_online_cpus() == 1) ++ break; ++ ++ preempt_enable(); ++ xenbus_suspend_cancel(); ++ } ++ ++ local_irq_disable(); ++ } ++ ++ mm_pin_all(); ++ gnttab_suspend(); ++ pre_suspend(); ++ ++ /* ++ * This hypercall returns 1 if suspend was cancelled or the domain was ++ * merely checkpointed, and 0 if it is resuming in a new domain. ++ */ ++ suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); ++ ++ post_suspend(suspend_cancelled); ++ gnttab_resume(); ++ if (!suspend_cancelled) { ++ irq_resume(); ++#ifdef __x86_64__ ++ /* ++ * Older versions of Xen do not save/restore the user %cr3. ++ * We do it here just in case, but there's no need if we are ++ * in fast-suspend mode as that implies a new enough Xen. ++ */ ++ if (!fast_suspend) { ++ struct mmuext_op op; ++ op.cmd = MMUEXT_NEW_USER_BASEPTR; ++ op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd( ++ current->active_mm->pgd)) >> PAGE_SHIFT); ++ if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF)) ++ BUG(); ++ } ++#endif ++ } ++ time_resume(); ++ ++ if (!fast_suspend) ++ local_irq_enable(); ++ ++ return suspend_cancelled; ++} ++ ++int __xen_suspend(int fast_suspend) ++{ ++ int err, suspend_cancelled; ++ ++ BUG_ON(smp_processor_id() != 0); ++ BUG_ON(in_interrupt()); ++ ++#if defined(__i386__) || defined(__x86_64__) ++ if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ printk(KERN_WARNING "Cannot suspend in " ++ "auto_translated_physmap mode.\n"); ++ return -EOPNOTSUPP; ++ } ++#endif ++ ++ /* If we are definitely UP then 'slow mode' is actually faster. */ ++ if (num_possible_cpus() == 1) ++ fast_suspend = 0; ++ ++ if (fast_suspend) { ++ xenbus_suspend(); ++ err = stop_machine_run(take_machine_down, &fast_suspend, 0); ++ if (err < 0) ++ xenbus_suspend_cancel(); ++ } else { ++ err = take_machine_down(&fast_suspend); ++ } ++ ++ if (err < 0) ++ return err; ++ ++ suspend_cancelled = err; ++ if (!suspend_cancelled) { ++ xencons_resume(); ++ xenbus_resume(); ++ } else { ++ xenbus_suspend_cancel(); ++ } ++ ++ if (!fast_suspend) ++ smp_resume(); ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/reboot.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/reboot.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,249 @@ ++#define __KERNEL_SYSCALLS__ ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/unistd.h> ++#include <linux/module.h> ++#include <linux/reboot.h> ++#include <linux/syscalls.h> ++#include <linux/sysrq.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <linux/kthread.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++#define SHUTDOWN_INVALID -1 ++#define SHUTDOWN_POWEROFF 0 ++#define SHUTDOWN_SUSPEND 2 ++/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only ++ * report a crash, not be instructed to crash! ++ * HALT is the same as POWEROFF, as far as we're concerned. The tools use ++ * the distinction when we return the reason code to them. ++ */ ++#define SHUTDOWN_HALT 4 ++ ++/* Ignore multiple shutdown requests. */ ++static int shutting_down = SHUTDOWN_INVALID; ++ ++/* Can we leave APs online when we suspend? */ ++static int fast_suspend; ++ ++static void __shutdown_handler(struct work_struct *work); ++static DECLARE_DELAYED_WORK(shutdown_work, __shutdown_handler); ++ ++int __xen_suspend(int fast_suspend); ++ ++static int shutdown_process(void *__unused) ++{ ++ static char *envp[] = { "HOME=/", "TERM=linux", ++ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; ++ static char *poweroff_argv[] = { "/sbin/poweroff", NULL }; ++ ++ extern asmlinkage long sys_reboot(int magic1, int magic2, ++ unsigned int cmd, void *arg); ++ ++ if ((shutting_down == SHUTDOWN_POWEROFF) || ++ (shutting_down == SHUTDOWN_HALT)) { ++ if (kernel_execve("/sbin/poweroff", poweroff_argv, envp) < 0) { ++#ifdef CONFIG_XEN ++ sys_reboot(LINUX_REBOOT_MAGIC1, ++ LINUX_REBOOT_MAGIC2, ++ LINUX_REBOOT_CMD_POWER_OFF, ++ NULL); ++#endif /* CONFIG_XEN */ ++ } ++ } ++ ++ shutting_down = SHUTDOWN_INVALID; /* could try again */ ++ ++ return 0; ++} ++ ++static int xen_suspend(void *__unused) ++{ ++ int err = __xen_suspend(fast_suspend); ++ if (err) ++ printk(KERN_ERR "Xen suspend failed (%d)\n", err); ++ shutting_down = SHUTDOWN_INVALID; ++ return 0; ++} ++ ++static int kthread_create_on_cpu(int (*f)(void *arg), ++ void *arg, ++ const char *name, ++ int cpu) ++{ ++ struct task_struct *p; ++ p = kthread_create(f, arg, name); ++ if (IS_ERR(p)) ++ return PTR_ERR(p); ++ kthread_bind(p, cpu); ++ wake_up_process(p); ++ return 0; ++} ++ ++static void __shutdown_handler(struct work_struct *unused) ++{ ++ int err; ++ ++ if (shutting_down != SHUTDOWN_SUSPEND) ++ err = kernel_thread(shutdown_process, NULL, ++ CLONE_FS | CLONE_FILES); ++ else ++ err = kthread_create_on_cpu(xen_suspend, NULL, "suspend", 0); ++ ++ if (err < 0) { ++ printk(KERN_WARNING "Error creating shutdown process (%d): " ++ "retrying...\n", -err); ++ schedule_delayed_work(&shutdown_work, HZ/2); ++ } ++} ++ ++static void shutdown_handler(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ extern void ctrl_alt_del(void); ++ char *str; ++ struct xenbus_transaction xbt; ++ int err; ++ ++ if (shutting_down != SHUTDOWN_INVALID) ++ return; ++ ++ again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) ++ return; ++ ++ str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); ++ /* Ignore read errors and empty reads. */ ++ if (XENBUS_IS_ERR_READ(str)) { ++ xenbus_transaction_end(xbt, 1); ++ return; ++ } ++ ++ xenbus_write(xbt, "control", "shutdown", ""); ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) { ++ kfree(str); ++ goto again; ++ } ++ ++ if (strcmp(str, "poweroff") == 0) ++ shutting_down = SHUTDOWN_POWEROFF; ++ else if (strcmp(str, "reboot") == 0) ++ ctrl_alt_del(); ++ else if (strcmp(str, "suspend") == 0) ++ shutting_down = SHUTDOWN_SUSPEND; ++ else if (strcmp(str, "halt") == 0) ++ shutting_down = SHUTDOWN_HALT; ++ else { ++ printk("Ignoring shutdown request: %s\n", str); ++ shutting_down = SHUTDOWN_INVALID; ++ } ++ ++ if (shutting_down != SHUTDOWN_INVALID) ++ schedule_delayed_work(&shutdown_work, 0); ++ ++ kfree(str); ++} ++ ++static void sysrq_handler(struct xenbus_watch *watch, const char **vec, ++ unsigned int len) ++{ ++ char sysrq_key = '\0'; ++ struct xenbus_transaction xbt; ++ int err; ++ ++ again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) ++ return; ++ if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { ++ printk(KERN_ERR "Unable to read sysrq code in " ++ "control/sysrq\n"); ++ xenbus_transaction_end(xbt, 1); ++ return; ++ } ++ ++ if (sysrq_key != '\0') ++ xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++ if (sysrq_key != '\0') ++ handle_sysrq(sysrq_key, NULL); ++#endif ++} ++ ++static struct xenbus_watch shutdown_watch = { ++ .node = "control/shutdown", ++ .callback = shutdown_handler ++}; ++ ++static struct xenbus_watch sysrq_watch = { ++ .node = "control/sysrq", ++ .callback = sysrq_handler ++}; ++ ++static int setup_shutdown_watcher(void) ++{ ++ int err; ++ ++ xenbus_scanf(XBT_NIL, "control", ++ "platform-feature-multiprocessor-suspend", ++ "%d", &fast_suspend); ++ ++ err = register_xenbus_watch(&shutdown_watch); ++ if (err) { ++ printk(KERN_ERR "Failed to set shutdown watcher\n"); ++ return err; ++ } ++ ++ err = register_xenbus_watch(&sysrq_watch); ++ if (err) { ++ printk(KERN_ERR "Failed to set sysrq watcher\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_XEN ++ ++static int shutdown_event(struct notifier_block *notifier, ++ unsigned long event, ++ void *data) ++{ ++ setup_shutdown_watcher(); ++ return NOTIFY_DONE; ++} ++ ++static int __init setup_shutdown_event(void) ++{ ++ static struct notifier_block xenstore_notifier = { ++ .notifier_call = shutdown_event ++ }; ++ register_xenstore_notifier(&xenstore_notifier); ++ ++ return 0; ++} ++ ++subsys_initcall(setup_shutdown_event); ++ ++#else /* !defined(CONFIG_XEN) */ ++ ++int xen_reboot_init(void) ++{ ++ return setup_shutdown_watcher(); ++} ++ ++#endif /* !defined(CONFIG_XEN) */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/smpboot.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/smpboot.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,511 @@ ++/* ++ * Xen SMP booting functions ++ * ++ * See arch/i386/kernel/smpboot.c for copyright and credits for derived ++ * portions of this file. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/sched.h> ++#include <linux/kernel_stat.h> ++#include <linux/smp_lock.h> ++#include <linux/irq.h> ++#include <linux/bootmem.h> ++#include <linux/notifier.h> ++#include <linux/cpu.h> ++#include <linux/percpu.h> ++#include <asm/desc.h> ++#ifdef __i386__ ++#include <asm/arch_hooks.h> ++#endif ++#include <asm/pgalloc.h> ++#if defined(__i386__) ++#include <asm/pda.h> ++#endif ++#include <xen/evtchn.h> ++#include <xen/interface/vcpu.h> ++#include <xen/cpu_hotplug.h> ++#include <xen/xenbus.h> ++ ++extern irqreturn_t smp_reschedule_interrupt(int, void *); ++extern irqreturn_t smp_call_function_interrupt(int, void *); ++ ++extern int local_setup_timer(unsigned int cpu); ++extern void local_teardown_timer(unsigned int cpu); ++ ++extern void hypervisor_callback(void); ++extern void failsafe_callback(void); ++extern void system_call(void); ++extern void smp_trap_init(trap_info_t *); ++ ++/* Number of siblings per CPU package */ ++int smp_num_siblings = 1; ++EXPORT_SYMBOL(smp_num_siblings); ++#if defined(__i386__) ++int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; ++#elif defined(__x86_64__) ++u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; ++#endif ++EXPORT_SYMBOL(cpu_llc_id); ++ ++cpumask_t cpu_online_map; ++EXPORT_SYMBOL(cpu_online_map); ++cpumask_t cpu_possible_map; ++EXPORT_SYMBOL(cpu_possible_map); ++cpumask_t cpu_initialized_map; ++ ++struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; ++EXPORT_SYMBOL(cpu_data); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++DEFINE_PER_CPU(int, cpu_state) = { 0 }; ++#endif ++ ++static DEFINE_PER_CPU(int, resched_irq); ++static DEFINE_PER_CPU(int, callfunc_irq); ++static char resched_name[NR_CPUS][15]; ++static char callfunc_name[NR_CPUS][15]; ++ ++u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; ++ ++void *xquad_portio; ++ ++cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; ++EXPORT_SYMBOL(cpu_sibling_map); ++cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; ++EXPORT_SYMBOL(cpu_core_map); ++ ++#if defined(__i386__) ++u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff }; ++EXPORT_SYMBOL(x86_cpu_to_apicid); ++#endif ++ ++void __init prefill_possible_map(void) ++{ ++ int i, rc; ++ ++ for_each_possible_cpu(i) ++ if (i != smp_processor_id()) ++ return; ++ ++ for (i = 0; i < NR_CPUS; i++) { ++ rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL); ++ if (rc >= 0) ++ cpu_set(i, cpu_possible_map); ++ } ++} ++ ++void __init smp_alloc_memory(void) ++{ ++} ++ ++static inline void ++set_cpu_sibling_map(int cpu) ++{ ++ cpu_data[cpu].phys_proc_id = cpu; ++ cpu_data[cpu].cpu_core_id = 0; ++ ++ cpu_sibling_map[cpu] = cpumask_of_cpu(cpu); ++ cpu_core_map[cpu] = cpumask_of_cpu(cpu); ++ ++ cpu_data[cpu].booted_cores = 1; ++} ++ ++static void ++remove_siblinginfo(int cpu) ++{ ++ cpu_data[cpu].phys_proc_id = BAD_APICID; ++ cpu_data[cpu].cpu_core_id = BAD_APICID; ++ ++ cpus_clear(cpu_sibling_map[cpu]); ++ cpus_clear(cpu_core_map[cpu]); ++ ++ cpu_data[cpu].booted_cores = 0; ++} ++ ++static int xen_smp_intr_init(unsigned int cpu) ++{ ++ int rc; ++ ++ per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1; ++ ++ sprintf(resched_name[cpu], "resched%d", cpu); ++ rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, ++ cpu, ++ smp_reschedule_interrupt, ++ SA_INTERRUPT, ++ resched_name[cpu], ++ NULL); ++ if (rc < 0) ++ goto fail; ++ per_cpu(resched_irq, cpu) = rc; ++ ++ sprintf(callfunc_name[cpu], "callfunc%d", cpu); ++ rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR, ++ cpu, ++ smp_call_function_interrupt, ++ SA_INTERRUPT, ++ callfunc_name[cpu], ++ NULL); ++ if (rc < 0) ++ goto fail; ++ per_cpu(callfunc_irq, cpu) = rc; ++ ++ if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0)) ++ goto fail; ++ ++ return 0; ++ ++ fail: ++ if (per_cpu(resched_irq, cpu) >= 0) ++ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); ++ if (per_cpu(callfunc_irq, cpu) >= 0) ++ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); ++ return rc; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static void xen_smp_intr_exit(unsigned int cpu) ++{ ++ if (cpu != 0) ++ local_teardown_timer(cpu); ++ ++ unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); ++ unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); ++} ++#endif ++ ++#ifdef __i386__ ++static inline void set_kernel_gs(void) ++{ ++ /* Set %gs for this CPU's PDA. Memory clobber is to create a ++ barrier with respect to any PDA operations, so the compiler ++ doesn't move any before here. */ ++ asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory"); ++} ++#endif ++ ++void cpu_bringup(void) ++{ ++#ifdef __i386__ ++ set_kernel_gs(); ++ secondary_cpu_init(); ++#else ++ cpu_init(); ++#endif ++ touch_softlockup_watchdog(); ++ preempt_disable(); ++ local_irq_enable(); ++} ++ ++static void cpu_bringup_and_idle(void) ++{ ++ cpu_bringup(); ++ cpu_idle(); ++} ++ ++static void cpu_initialize_context(unsigned int cpu) ++{ ++ vcpu_guest_context_t ctxt; ++ struct task_struct *idle = idle_task(cpu); ++#ifdef __x86_64__ ++ struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu]; ++#else ++ struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++#endif ++ ++ if (cpu_test_and_set(cpu, cpu_initialized_map)) ++ return; ++ ++ memset(&ctxt, 0, sizeof(ctxt)); ++ ++ ctxt.flags = VGCF_IN_KERNEL; ++ ctxt.user_regs.ds = __USER_DS; ++ ctxt.user_regs.es = __USER_DS; ++ ctxt.user_regs.fs = 0; ++ ctxt.user_regs.gs = 0; ++ ctxt.user_regs.ss = __KERNEL_DS; ++ ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle; ++ ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */ ++ ++ memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt)); ++ ++ smp_trap_init(ctxt.trap_ctxt); ++ ++ ctxt.ldt_ents = 0; ++ ++ ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address); ++ ctxt.gdt_ents = gdt_descr->size / 8; ++ ++#ifdef __i386__ ++ ctxt.user_regs.cs = __KERNEL_CS; ++ ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs); ++ ++ ctxt.kernel_ss = __KERNEL_DS; ++ ctxt.kernel_sp = idle->thread.esp0; ++ ++ ctxt.event_callback_cs = __KERNEL_CS; ++ ctxt.event_callback_eip = (unsigned long)hypervisor_callback; ++ ctxt.failsafe_callback_cs = __KERNEL_CS; ++ ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback; ++ ++ ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir)); ++#else /* __x86_64__ */ ++ ctxt.user_regs.cs = __KERNEL_CS; ++ ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs); ++ ++ ctxt.kernel_ss = __KERNEL_DS; ++ ctxt.kernel_sp = idle->thread.rsp0; ++ ++ ctxt.event_callback_eip = (unsigned long)hypervisor_callback; ++ ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback; ++ ctxt.syscall_callback_eip = (unsigned long)system_call; ++ ++ ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt)); ++ ++ ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu)); ++#endif ++ ++ BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt)); ++} ++ ++void __init smp_prepare_cpus(unsigned int max_cpus) ++{ ++ int cpu; ++ struct task_struct *idle; ++#ifdef __x86_64__ ++ struct desc_ptr *gdt_descr; ++#else ++ struct Xgt_desc_struct *gdt_descr; ++#endif ++ ++ boot_cpu_data.apicid = 0; ++ cpu_data[0] = boot_cpu_data; ++ ++ cpu_2_logical_apicid[0] = 0; ++ x86_cpu_to_apicid[0] = 0; ++ ++ current_thread_info()->cpu = 0; ++ ++ for (cpu = 0; cpu < NR_CPUS; cpu++) { ++ cpus_clear(cpu_sibling_map[cpu]); ++ cpus_clear(cpu_core_map[cpu]); ++ } ++ ++ set_cpu_sibling_map(0); ++ ++ if (xen_smp_intr_init(0)) ++ BUG(); ++ ++ cpu_initialized_map = cpumask_of_cpu(0); ++ ++ /* Restrict the possible_map according to max_cpus. */ ++ while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) { ++ for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--) ++ continue; ++ cpu_clear(cpu, cpu_possible_map); ++ } ++ ++ for_each_possible_cpu (cpu) { ++#ifdef __i386__ ++ struct i386_pda *pda; ++ struct desc_struct *gdt; ++#endif ++ ++ if (cpu == 0) ++ continue; ++ ++#ifdef __x86_64__ ++ gdt_descr = &cpu_gdt_descr[cpu]; ++#else ++ gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++#endif ++ gdt_descr->address = get_zeroed_page(GFP_KERNEL); ++ if (unlikely(!gdt_descr->address)) { ++ printk(KERN_CRIT "CPU%d failed to allocate GDT\n", ++ cpu); ++ continue; ++ } ++ gdt_descr->size = GDT_SIZE; ++ memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE); ++#ifdef __i386__ ++ gdt = (struct desc_struct *)gdt_descr->address; ++ pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu)); ++ ++ if (unlikely(!pda)) { ++ printk(KERN_CRIT "CPU%d failed to allocate PDA\n", ++ cpu); ++ continue; ++ } ++ cpu_pda(cpu) = pda; ++ cpu_pda(cpu)->cpu_number = cpu; ++ pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, ++ (u32 *)&gdt[GDT_ENTRY_PDA].b, ++ (unsigned long)pda, sizeof(*pda) - 1, ++ 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ ++#endif ++ make_page_readonly( ++ (void *)gdt_descr->address, ++ XENFEAT_writable_descriptor_tables); ++ ++ cpu_data[cpu] = boot_cpu_data; ++ cpu_data[cpu].apicid = cpu; ++ ++ cpu_2_logical_apicid[cpu] = cpu; ++ x86_cpu_to_apicid[cpu] = cpu; ++ ++ idle = fork_idle(cpu); ++ if (IS_ERR(idle)) ++ panic("failed fork for CPU %d", cpu); ++ ++ cpu_pda(cpu)->pcurrent = idle; ++#ifdef __x86_64__ ++ cpu_pda(cpu)->cpunumber = cpu; ++ clear_ti_thread_flag(idle->thread_info, TIF_FORK); ++#endif ++ ++ irq_ctx_init(cpu); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ if (is_initial_xendomain()) ++ cpu_set(cpu, cpu_present_map); ++#else ++ cpu_set(cpu, cpu_present_map); ++#endif ++ } ++ ++ init_xenbus_allowed_cpumask(); ++ ++ /* ++ * Here we can be sure that there is an IO-APIC in the system. Let's ++ * go and set it up: ++ */ ++#ifdef CONFIG_X86_IO_APIC ++ if (!skip_ioapic_setup && nr_ioapics) ++ setup_IO_APIC(); ++#endif ++} ++ ++void __init smp_prepare_boot_cpu(void) ++{ ++ prefill_possible_map(); ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ ++/* ++ * Initialize cpu_present_map late to skip SMP boot code in init/main.c. ++ * But do it early enough to catch critical for_each_present_cpu() loops ++ * in i386-specific code. ++ */ ++static int __init initialize_cpu_present_map(void) ++{ ++ cpu_present_map = cpu_possible_map; ++ return 0; ++} ++core_initcall(initialize_cpu_present_map); ++ ++int __cpu_disable(void) ++{ ++ cpumask_t map = cpu_online_map; ++ int cpu = smp_processor_id(); ++ ++ if (cpu == 0) ++ return -EBUSY; ++ ++ remove_siblinginfo(cpu); ++ ++ cpu_clear(cpu, map); ++ fixup_irqs(map); ++ cpu_clear(cpu, cpu_online_map); ++ ++ return 0; ++} ++ ++void __cpu_die(unsigned int cpu) ++{ ++ while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) { ++ current->state = TASK_UNINTERRUPTIBLE; ++ schedule_timeout(HZ/10); ++ } ++ ++ xen_smp_intr_exit(cpu); ++ ++ if (num_online_cpus() == 1) ++ alternatives_smp_switch(0); ++} ++ ++#else /* !CONFIG_HOTPLUG_CPU */ ++ ++int __cpu_disable(void) ++{ ++ return -ENOSYS; ++} ++ ++void __cpu_die(unsigned int cpu) ++{ ++ BUG(); ++} ++ ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++int __cpuinit __cpu_up(unsigned int cpu) ++{ ++ int rc; ++ ++ rc = cpu_up_check(cpu); ++ if (rc) ++ return rc; ++ ++ cpu_initialize_context(cpu); ++ ++ if (num_online_cpus() == 1) ++ alternatives_smp_switch(1); ++ ++ /* This must be done before setting cpu_online_map */ ++ set_cpu_sibling_map(cpu); ++ wmb(); ++ ++ rc = xen_smp_intr_init(cpu); ++#ifdef CONFIG_HOTPLUG_CPU ++ if (rc) { ++ remove_siblinginfo(cpu); ++ return rc; ++ } ++#endif ++ cpu_set(cpu, cpu_online_map); ++ ++ rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); ++ BUG_ON(rc); ++ ++ return 0; ++} ++ ++void __init smp_cpus_done(unsigned int max_cpus) ++{ ++} ++ ++#ifdef CONFIG_X86_MPPARSE ++/* ++ * If the BIOS enumerates physical processors before logical, ++ * maxcpus=N at enumeration-time can be used to disable HT. ++ */ ++static int __init parse_maxcpus(char *arg) ++{ ++ extern unsigned int maxcpus; ++ ++ maxcpus = simple_strtoul(arg, NULL, 0); ++ return 0; ++} ++early_param("maxcpus", parse_maxcpus); ++#endif ++ ++#if defined(CONFIG_XEN_UNPRIVILEGED_GUEST) && defined(CONFIG_X86_32) ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ return -EINVAL; ++} ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/xen_proc.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/xen_proc.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,23 @@ ++ ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <xen/xen_proc.h> ++ ++static struct proc_dir_entry *xen_base; ++ ++struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode) ++{ ++ if ( xen_base == NULL ) ++ if ( (xen_base = proc_mkdir("xen", &proc_root)) == NULL ) ++ panic("Couldn't create /proc/xen"); ++ return create_proc_entry(name, mode, xen_base); ++} ++ ++EXPORT_SYMBOL_GPL(create_xen_proc_entry); ++ ++void remove_xen_proc_entry(const char *name) ++{ ++ remove_proc_entry(name, xen_base); ++} ++ ++EXPORT_SYMBOL_GPL(remove_xen_proc_entry); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/core/xen_sysfs.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/core/xen_sysfs.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,378 @@ ++/* ++ * copyright (c) 2006 IBM Corporation ++ * Authored by: Mike D. Day <ncmike@us.ibm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/err.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <asm/hypervisor.h> ++#include <xen/features.h> ++#include <xen/hypervisor_sysfs.h> ++#include <xen/xenbus.h> ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mike D. Day <ncmike@us.ibm.com>"); ++ ++static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ return sprintf(buffer, "xen\n"); ++} ++ ++HYPERVISOR_ATTR_RO(type); ++ ++static int __init xen_sysfs_type_init(void) ++{ ++ return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr); ++} ++ ++static void xen_sysfs_type_destroy(void) ++{ ++ sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr); ++} ++ ++/* xen version attributes */ ++static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int version = HYPERVISOR_xen_version(XENVER_version, NULL); ++ if (version) ++ return sprintf(buffer, "%d\n", version >> 16); ++ return -ENODEV; ++} ++ ++HYPERVISOR_ATTR_RO(major); ++ ++static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int version = HYPERVISOR_xen_version(XENVER_version, NULL); ++ if (version) ++ return sprintf(buffer, "%d\n", version & 0xff); ++ return -ENODEV; ++} ++ ++HYPERVISOR_ATTR_RO(minor); ++ ++static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ char *extra; ++ ++ extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL); ++ if (extra) { ++ ret = HYPERVISOR_xen_version(XENVER_extraversion, extra); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", extra); ++ kfree(extra); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(extra); ++ ++static struct attribute *version_attrs[] = { ++ &major_attr.attr, ++ &minor_attr.attr, ++ &extra_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group version_group = { ++ .name = "version", ++ .attrs = version_attrs, ++}; ++ ++static int __init xen_sysfs_version_init(void) ++{ ++ return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ &version_group); ++} ++ ++static void xen_sysfs_version_destroy(void) ++{ ++ sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group); ++} ++ ++/* UUID */ ++ ++static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ char *vm, *val; ++ int ret; ++ ++ vm = xenbus_read(XBT_NIL, "vm", "", NULL); ++ if (IS_ERR(vm)) ++ return PTR_ERR(vm); ++ val = xenbus_read(XBT_NIL, vm, "uuid", NULL); ++ kfree(vm); ++ if (IS_ERR(val)) ++ return PTR_ERR(val); ++ ret = sprintf(buffer, "%s\n", val); ++ kfree(val); ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(uuid); ++ ++static int __init xen_sysfs_uuid_init(void) ++{ ++ return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr); ++} ++ ++static void xen_sysfs_uuid_destroy(void) ++{ ++ sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr); ++} ++ ++/* xen compilation attributes */ ++ ++static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ struct xen_compile_info *info; ++ ++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); ++ if (info) { ++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", info->compiler); ++ kfree(info); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(compiler); ++ ++static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ struct xen_compile_info *info; ++ ++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); ++ if (info) { ++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", info->compile_by); ++ kfree(info); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(compiled_by); ++ ++static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ struct xen_compile_info *info; ++ ++ info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL); ++ if (info) { ++ ret = HYPERVISOR_xen_version(XENVER_compile_info, info); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", info->compile_date); ++ kfree(info); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(compile_date); ++ ++static struct attribute *xen_compile_attrs[] = { ++ &compiler_attr.attr, ++ &compiled_by_attr.attr, ++ &compile_date_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group xen_compilation_group = { ++ .name = "compilation", ++ .attrs = xen_compile_attrs, ++}; ++ ++int __init static xen_compilation_init(void) ++{ ++ return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ &xen_compilation_group); ++} ++ ++static void xen_compilation_destroy(void) ++{ ++ sysfs_remove_group(&hypervisor_subsys.kset.kobj, ++ &xen_compilation_group); ++} ++ ++/* xen properties info */ ++ ++static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ char *caps; ++ ++ caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL); ++ if (caps) { ++ ret = HYPERVISOR_xen_version(XENVER_capabilities, caps); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", caps); ++ kfree(caps); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(capabilities); ++ ++static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ char *cset; ++ ++ cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL); ++ if (cset) { ++ ret = HYPERVISOR_xen_version(XENVER_changeset, cset); ++ if (!ret) ++ ret = sprintf(buffer, "%s\n", cset); ++ kfree(cset); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(changeset); ++ ++static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret = -ENOMEM; ++ struct xen_platform_parameters *parms; ++ ++ parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL); ++ if (parms) { ++ ret = HYPERVISOR_xen_version(XENVER_platform_parameters, ++ parms); ++ if (!ret) ++ ret = sprintf(buffer, "%lx\n", parms->virt_start); ++ kfree(parms); ++ } ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(virtual_start); ++ ++static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ int ret; ++ ++ ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL); ++ if (ret > 0) ++ ret = sprintf(buffer, "%x\n", ret); ++ ++ return ret; ++} ++ ++HYPERVISOR_ATTR_RO(pagesize); ++ ++/* eventually there will be several more features to export */ ++static ssize_t xen_feature_show(int index, char *buffer) ++{ ++ int ret = -ENOMEM; ++ struct xen_feature_info *info; ++ ++ info = kmalloc(sizeof(struct xen_feature_info), GFP_KERNEL); ++ if (info) { ++ info->submap_idx = index; ++ ret = HYPERVISOR_xen_version(XENVER_get_features, info); ++ if (!ret) ++ ret = sprintf(buffer, "%d\n", info->submap); ++ kfree(info); ++ } ++ ++ return ret; ++} ++ ++static ssize_t writable_pt_show(struct hyp_sysfs_attr *attr, char *buffer) ++{ ++ return xen_feature_show(XENFEAT_writable_page_tables, buffer); ++} ++ ++HYPERVISOR_ATTR_RO(writable_pt); ++ ++static struct attribute *xen_properties_attrs[] = { ++ &capabilities_attr.attr, ++ &changeset_attr.attr, ++ &virtual_start_attr.attr, ++ &pagesize_attr.attr, ++ &writable_pt_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group xen_properties_group = { ++ .name = "properties", ++ .attrs = xen_properties_attrs, ++}; ++ ++static int __init xen_properties_init(void) ++{ ++ return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ &xen_properties_group); ++} ++ ++static void xen_properties_destroy(void) ++{ ++ sysfs_remove_group(&hypervisor_subsys.kset.kobj, ++ &xen_properties_group); ++} ++ ++static int __init hyper_sysfs_init(void) ++{ ++ int ret; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ ret = xen_sysfs_type_init(); ++ if (ret) ++ goto out; ++ ret = xen_sysfs_version_init(); ++ if (ret) ++ goto version_out; ++ ret = xen_compilation_init(); ++ if (ret) ++ goto comp_out; ++ ret = xen_sysfs_uuid_init(); ++ if (ret) ++ goto uuid_out; ++ ret = xen_properties_init(); ++ if (!ret) ++ goto out; ++ ++ xen_sysfs_uuid_destroy(); ++uuid_out: ++ xen_compilation_destroy(); ++comp_out: ++ xen_sysfs_version_destroy(); ++version_out: ++ xen_sysfs_type_destroy(); ++out: ++ return ret; ++} ++ ++static void hyper_sysfs_exit(void) ++{ ++ xen_properties_destroy(); ++ xen_compilation_destroy(); ++ xen_sysfs_uuid_destroy(); ++ xen_sysfs_version_destroy(); ++ xen_sysfs_type_destroy(); ++ ++} ++ ++module_init(hyper_sysfs_init); ++module_exit(hyper_sysfs_exit); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/evtchn/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/evtchn/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++obj-y := evtchn.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/evtchn/evtchn.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/evtchn/evtchn.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,469 @@ ++/****************************************************************************** ++ * evtchn.c ++ * ++ * Driver for receiving and demuxing event-channel signals. ++ * ++ * Copyright (c) 2004-2005, K A Fraser ++ * Multi-process extensions Copyright (c) 2004, Steven Smith ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/errno.h> ++#include <linux/miscdevice.h> ++#include <linux/major.h> ++#include <linux/proc_fs.h> ++#include <linux/stat.h> ++#include <linux/poll.h> ++#include <linux/irq.h> ++#include <linux/init.h> ++#include <linux/gfp.h> ++#include <linux/mutex.h> ++#include <xen/evtchn.h> ++#include <xen/public/evtchn.h> ++ ++struct per_user_data { ++ /* Notification ring, accessed via /dev/xen/evtchn. */ ++#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t)) ++#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) ++ evtchn_port_t *ring; ++ unsigned int ring_cons, ring_prod, ring_overflow; ++ struct mutex ring_cons_mutex; /* protect against concurrent readers */ ++ ++ /* Processes wait on this queue when ring is empty. */ ++ wait_queue_head_t evtchn_wait; ++ struct fasync_struct *evtchn_async_queue; ++}; ++ ++/* Who's bound to each port? */ ++static struct per_user_data *port_user[NR_EVENT_CHANNELS]; ++static spinlock_t port_user_lock; ++ ++void evtchn_device_upcall(int port) ++{ ++ struct per_user_data *u; ++ ++ spin_lock(&port_user_lock); ++ ++ mask_evtchn(port); ++ clear_evtchn(port); ++ ++ if ((u = port_user[port]) != NULL) { ++ if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) { ++ u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port; ++ if (u->ring_cons == u->ring_prod++) { ++ wake_up_interruptible(&u->evtchn_wait); ++ kill_fasync(&u->evtchn_async_queue, ++ SIGIO, POLL_IN); ++ } ++ } else { ++ u->ring_overflow = 1; ++ } ++ } ++ ++ spin_unlock(&port_user_lock); ++} ++ ++static ssize_t evtchn_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ int rc; ++ unsigned int c, p, bytes1 = 0, bytes2 = 0; ++ struct per_user_data *u = file->private_data; ++ ++ /* Whole number of ports. */ ++ count &= ~(sizeof(evtchn_port_t)-1); ++ ++ if (count == 0) ++ return 0; ++ ++ if (count > PAGE_SIZE) ++ count = PAGE_SIZE; ++ ++ for (;;) { ++ mutex_lock(&u->ring_cons_mutex); ++ ++ rc = -EFBIG; ++ if (u->ring_overflow) ++ goto unlock_out; ++ ++ if ((c = u->ring_cons) != (p = u->ring_prod)) ++ break; ++ ++ mutex_unlock(&u->ring_cons_mutex); ++ ++ if (file->f_flags & O_NONBLOCK) ++ return -EAGAIN; ++ ++ rc = wait_event_interruptible( ++ u->evtchn_wait, u->ring_cons != u->ring_prod); ++ if (rc) ++ return rc; ++ } ++ ++ /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ ++ if (((c ^ p) & EVTCHN_RING_SIZE) != 0) { ++ bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * ++ sizeof(evtchn_port_t); ++ bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t); ++ } else { ++ bytes1 = (p - c) * sizeof(evtchn_port_t); ++ bytes2 = 0; ++ } ++ ++ /* Truncate chunks according to caller's maximum byte count. */ ++ if (bytes1 > count) { ++ bytes1 = count; ++ bytes2 = 0; ++ } else if ((bytes1 + bytes2) > count) { ++ bytes2 = count - bytes1; ++ } ++ ++ rc = -EFAULT; ++ if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || ++ ((bytes2 != 0) && ++ copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) ++ goto unlock_out; ++ ++ u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t); ++ rc = bytes1 + bytes2; ++ ++ unlock_out: ++ mutex_unlock(&u->ring_cons_mutex); ++ return rc; ++} ++ ++static ssize_t evtchn_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ int rc, i; ++ evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL); ++ struct per_user_data *u = file->private_data; ++ ++ if (kbuf == NULL) ++ return -ENOMEM; ++ ++ /* Whole number of ports. */ ++ count &= ~(sizeof(evtchn_port_t)-1); ++ ++ rc = 0; ++ if (count == 0) ++ goto out; ++ ++ if (count > PAGE_SIZE) ++ count = PAGE_SIZE; ++ ++ rc = -EFAULT; ++ if (copy_from_user(kbuf, buf, count) != 0) ++ goto out; ++ ++ spin_lock_irq(&port_user_lock); ++ for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) ++ if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u)) ++ unmask_evtchn(kbuf[i]); ++ spin_unlock_irq(&port_user_lock); ++ ++ rc = count; ++ ++ out: ++ free_page((unsigned long)kbuf); ++ return rc; ++} ++ ++static void evtchn_bind_to_user(struct per_user_data *u, int port) ++{ ++ spin_lock_irq(&port_user_lock); ++ BUG_ON(port_user[port] != NULL); ++ port_user[port] = u; ++ unmask_evtchn(port); ++ spin_unlock_irq(&port_user_lock); ++} ++ ++static int evtchn_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int rc; ++ struct per_user_data *u = file->private_data; ++ void __user *uarg = (void __user *) arg; ++ ++ switch (cmd) { ++ case IOCTL_EVTCHN_BIND_VIRQ: { ++ struct ioctl_evtchn_bind_virq bind; ++ struct evtchn_bind_virq bind_virq; ++ ++ rc = -EFAULT; ++ if (copy_from_user(&bind, uarg, sizeof(bind))) ++ break; ++ ++ bind_virq.virq = bind.virq; ++ bind_virq.vcpu = 0; ++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, ++ &bind_virq); ++ if (rc != 0) ++ break; ++ ++ rc = bind_virq.port; ++ evtchn_bind_to_user(u, rc); ++ break; ++ } ++ ++ case IOCTL_EVTCHN_BIND_INTERDOMAIN: { ++ struct ioctl_evtchn_bind_interdomain bind; ++ struct evtchn_bind_interdomain bind_interdomain; ++ ++ rc = -EFAULT; ++ if (copy_from_user(&bind, uarg, sizeof(bind))) ++ break; ++ ++ bind_interdomain.remote_dom = bind.remote_domain; ++ bind_interdomain.remote_port = bind.remote_port; ++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, ++ &bind_interdomain); ++ if (rc != 0) ++ break; ++ ++ rc = bind_interdomain.local_port; ++ evtchn_bind_to_user(u, rc); ++ break; ++ } ++ ++ case IOCTL_EVTCHN_BIND_UNBOUND_PORT: { ++ struct ioctl_evtchn_bind_unbound_port bind; ++ struct evtchn_alloc_unbound alloc_unbound; ++ ++ rc = -EFAULT; ++ if (copy_from_user(&bind, uarg, sizeof(bind))) ++ break; ++ ++ alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.remote_dom = bind.remote_domain; ++ rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, ++ &alloc_unbound); ++ if (rc != 0) ++ break; ++ ++ rc = alloc_unbound.port; ++ evtchn_bind_to_user(u, rc); ++ break; ++ } ++ ++ case IOCTL_EVTCHN_UNBIND: { ++ struct ioctl_evtchn_unbind unbind; ++ struct evtchn_close close; ++ int ret; ++ ++ rc = -EFAULT; ++ if (copy_from_user(&unbind, uarg, sizeof(unbind))) ++ break; ++ ++ rc = -EINVAL; ++ if (unbind.port >= NR_EVENT_CHANNELS) ++ break; ++ ++ spin_lock_irq(&port_user_lock); ++ ++ rc = -ENOTCONN; ++ if (port_user[unbind.port] != u) { ++ spin_unlock_irq(&port_user_lock); ++ break; ++ } ++ ++ port_user[unbind.port] = NULL; ++ mask_evtchn(unbind.port); ++ ++ spin_unlock_irq(&port_user_lock); ++ ++ close.port = unbind.port; ++ ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); ++ BUG_ON(ret); ++ ++ rc = 0; ++ break; ++ } ++ ++ case IOCTL_EVTCHN_NOTIFY: { ++ struct ioctl_evtchn_notify notify; ++ ++ rc = -EFAULT; ++ if (copy_from_user(¬ify, uarg, sizeof(notify))) ++ break; ++ ++ if (notify.port >= NR_EVENT_CHANNELS) { ++ rc = -EINVAL; ++ } else if (port_user[notify.port] != u) { ++ rc = -ENOTCONN; ++ } else { ++ notify_remote_via_evtchn(notify.port); ++ rc = 0; ++ } ++ break; ++ } ++ ++ case IOCTL_EVTCHN_RESET: { ++ /* Initialise the ring to empty. Clear errors. */ ++ mutex_lock(&u->ring_cons_mutex); ++ spin_lock_irq(&port_user_lock); ++ u->ring_cons = u->ring_prod = u->ring_overflow = 0; ++ spin_unlock_irq(&port_user_lock); ++ mutex_unlock(&u->ring_cons_mutex); ++ rc = 0; ++ break; ++ } ++ ++ default: ++ rc = -ENOSYS; ++ break; ++ } ++ ++ return rc; ++} ++ ++static unsigned int evtchn_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask = POLLOUT | POLLWRNORM; ++ struct per_user_data *u = file->private_data; ++ ++ poll_wait(file, &u->evtchn_wait, wait); ++ if (u->ring_cons != u->ring_prod) ++ mask |= POLLIN | POLLRDNORM; ++ if (u->ring_overflow) ++ mask = POLLERR; ++ return mask; ++} ++ ++static int evtchn_fasync(int fd, struct file *filp, int on) ++{ ++ struct per_user_data *u = filp->private_data; ++ return fasync_helper(fd, filp, on, &u->evtchn_async_queue); ++} ++ ++static int evtchn_open(struct inode *inode, struct file *filp) ++{ ++ struct per_user_data *u; ++ ++ if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL) ++ return -ENOMEM; ++ ++ memset(u, 0, sizeof(*u)); ++ init_waitqueue_head(&u->evtchn_wait); ++ ++ u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL); ++ if (u->ring == NULL) { ++ kfree(u); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&u->ring_cons_mutex); ++ ++ filp->private_data = u; ++ ++ return 0; ++} ++ ++static int evtchn_release(struct inode *inode, struct file *filp) ++{ ++ int i; ++ struct per_user_data *u = filp->private_data; ++ struct evtchn_close close; ++ ++ spin_lock_irq(&port_user_lock); ++ ++ free_page((unsigned long)u->ring); ++ ++ for (i = 0; i < NR_EVENT_CHANNELS; i++) { ++ int ret; ++ if (port_user[i] != u) ++ continue; ++ ++ port_user[i] = NULL; ++ mask_evtchn(i); ++ ++ close.port = i; ++ ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); ++ BUG_ON(ret); ++ } ++ ++ spin_unlock_irq(&port_user_lock); ++ ++ kfree(u); ++ ++ return 0; ++} ++ ++static const struct file_operations evtchn_fops = { ++ .owner = THIS_MODULE, ++ .read = evtchn_read, ++ .write = evtchn_write, ++ .ioctl = evtchn_ioctl, ++ .poll = evtchn_poll, ++ .fasync = evtchn_fasync, ++ .open = evtchn_open, ++ .release = evtchn_release, ++}; ++ ++static struct miscdevice evtchn_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "evtchn", ++ .fops = &evtchn_fops, ++}; ++ ++static int __init evtchn_init(void) ++{ ++ int err; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ spin_lock_init(&port_user_lock); ++ memset(port_user, 0, sizeof(port_user)); ++ ++ /* Create '/dev/misc/evtchn'. */ ++ err = misc_register(&evtchn_miscdev); ++ if (err != 0) { ++ printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); ++ return err; ++ } ++ ++ printk("Event-channel device installed.\n"); ++ ++ return 0; ++} ++ ++static void evtchn_cleanup(void) ++{ ++ misc_deregister(&evtchn_miscdev); ++} ++ ++module_init(evtchn_init); ++module_exit(evtchn_cleanup); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/fbfront/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/fbfront/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o ++obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/fbfront/xenfb.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/fbfront/xenfb.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,752 @@ ++/* ++ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device ++ * ++ * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> ++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> ++ * ++ * Based on linux/drivers/video/q40fb.c ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++/* ++ * TODO: ++ * ++ * Switch to grant tables when they become capable of dealing with the ++ * frame buffer. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/fb.h> ++#include <linux/module.h> ++#include <linux/vmalloc.h> ++#include <linux/mm.h> ++#include <linux/freezer.h> ++#include <linux/mutex.h> ++#include <asm/hypervisor.h> ++#include <xen/evtchn.h> ++#include <xen/interface/io/fbif.h> ++#include <xen/interface/io/protocols.h> ++#include <xen/xenbus.h> ++#include <linux/kthread.h> ++ ++struct xenfb_mapping ++{ ++ struct list_head link; ++ struct vm_area_struct *vma; ++ atomic_t map_refs; ++ int faults; ++ struct xenfb_info *info; ++}; ++ ++struct xenfb_info ++{ ++ struct task_struct *kthread; ++ wait_queue_head_t wq; ++ ++ unsigned char *fb; ++ struct fb_info *fb_info; ++ struct timer_list refresh; ++ int dirty; ++ int x1, y1, x2, y2; /* dirty rectangle, ++ protected by dirty_lock */ ++ spinlock_t dirty_lock; ++ struct mutex mm_lock; ++ int nr_pages; ++ struct page **pages; ++ struct list_head mappings; /* protected by mm_lock */ ++ ++ int irq; ++ struct xenfb_page *page; ++ unsigned long *mfns; ++ int update_wanted; /* XENFB_TYPE_UPDATE wanted */ ++ ++ struct xenbus_device *xbdev; ++}; ++ ++/* ++ * How the locks work together ++ * ++ * There are two locks: spinlock dirty_lock protecting the dirty ++ * rectangle, and mutex mm_lock protecting mappings. ++ * ++ * The problem is that dirty rectangle and mappings aren't ++ * independent: the dirty rectangle must cover all faulted pages in ++ * mappings. We need to prove that our locking maintains this ++ * invariant. ++ * ++ * There are several kinds of critical regions: ++ * ++ * 1. Holding only dirty_lock: xenfb_refresh(). May run in ++ * interrupts. Extends the dirty rectangle. Trivially preserves ++ * invariant. ++ * ++ * 2. Holding only mm_lock: xenfb_mmap() and xenfb_vm_close(). Touch ++ * only mappings. The former creates unfaulted pages. Preserves ++ * invariant. The latter removes pages. Preserves invariant. ++ * ++ * 3. Holding both locks: xenfb_vm_nopage(). Extends the dirty ++ * rectangle and updates mappings consistently. Preserves ++ * invariant. ++ * ++ * 4. The ugliest one: xenfb_update_screen(). Clear the dirty ++ * rectangle and update mappings consistently. ++ * ++ * We can't simply hold both locks, because zap_page_range() cannot ++ * be called with a spinlock held. ++ * ++ * Therefore, we first clear the dirty rectangle with both locks ++ * held. Then we unlock dirty_lock and update the mappings. ++ * Critical regions that hold only dirty_lock may interfere with ++ * that. This can only be region 1: xenfb_refresh(). But that ++ * just extends the dirty rectangle, which can't harm the ++ * invariant. ++ * ++ * But FIXME: the invariant is too weak. It misses that the fault ++ * record in mappings must be consistent with the mapping of pages in ++ * the associated address space! do_no_page() updates the PTE after ++ * xenfb_vm_nopage() returns, i.e. outside the critical region. This ++ * allows the following race: ++ * ++ * X writes to some address in the Xen frame buffer ++ * Fault - call do_no_page() ++ * call xenfb_vm_nopage() ++ * grab mm_lock ++ * map->faults++; ++ * release mm_lock ++ * return back to do_no_page() ++ * (preempted, or SMP) ++ * Xen worker thread runs. ++ * grab mm_lock ++ * look at mappings ++ * find this mapping, zaps its pages (but page not in pte yet) ++ * clear map->faults ++ * releases mm_lock ++ * (back to X process) ++ * put page in X's pte ++ * ++ * Oh well, we wont be updating the writes to this page anytime soon. ++ */ ++ ++static int xenfb_fps = 20; ++static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; ++ ++static int xenfb_remove(struct xenbus_device *); ++static void xenfb_init_shared_page(struct xenfb_info *); ++static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); ++static void xenfb_disconnect_backend(struct xenfb_info *); ++ ++static void xenfb_do_update(struct xenfb_info *info, ++ int x, int y, int w, int h) ++{ ++ union xenfb_out_event event; ++ __u32 prod; ++ ++ event.type = XENFB_TYPE_UPDATE; ++ event.update.x = x; ++ event.update.y = y; ++ event.update.width = w; ++ event.update.height = h; ++ ++ prod = info->page->out_prod; ++ /* caller ensures !xenfb_queue_full() */ ++ mb(); /* ensure ring space available */ ++ XENFB_OUT_RING_REF(info->page, prod) = event; ++ wmb(); /* ensure ring contents visible */ ++ info->page->out_prod = prod + 1; ++ ++ notify_remote_via_irq(info->irq); ++} ++ ++static int xenfb_queue_full(struct xenfb_info *info) ++{ ++ __u32 cons, prod; ++ ++ prod = info->page->out_prod; ++ cons = info->page->out_cons; ++ return prod - cons == XENFB_OUT_RING_LEN; ++} ++ ++static void xenfb_update_screen(struct xenfb_info *info) ++{ ++ unsigned long flags; ++ int y1, y2, x1, x2; ++ struct xenfb_mapping *map; ++ ++ if (!info->update_wanted) ++ return; ++ if (xenfb_queue_full(info)) ++ return; ++ ++ mutex_lock(&info->mm_lock); ++ ++ spin_lock_irqsave(&info->dirty_lock, flags); ++ y1 = info->y1; ++ y2 = info->y2; ++ x1 = info->x1; ++ x2 = info->x2; ++ info->x1 = info->y1 = INT_MAX; ++ info->x2 = info->y2 = 0; ++ spin_unlock_irqrestore(&info->dirty_lock, flags); ++ ++ list_for_each_entry(map, &info->mappings, link) { ++ if (!map->faults) ++ continue; ++ zap_page_range(map->vma, map->vma->vm_start, ++ map->vma->vm_end - map->vma->vm_start, NULL); ++ map->faults = 0; ++ } ++ ++ mutex_unlock(&info->mm_lock); ++ ++ xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); ++} ++ ++static int xenfb_thread(void *data) ++{ ++ struct xenfb_info *info = data; ++ ++ while (!kthread_should_stop()) { ++ if (info->dirty) { ++ info->dirty = 0; ++ xenfb_update_screen(info); ++ } ++ wait_event_interruptible(info->wq, ++ kthread_should_stop() || info->dirty); ++ try_to_freeze(); ++ } ++ return 0; ++} ++ ++static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) ++{ ++ u32 v; ++ ++ if (regno > info->cmap.len) ++ return 1; ++ ++ red >>= (16 - info->var.red.length); ++ green >>= (16 - info->var.green.length); ++ blue >>= (16 - info->var.blue.length); ++ ++ v = (red << info->var.red.offset) | ++ (green << info->var.green.offset) | ++ (blue << info->var.blue.offset); ++ ++ /* FIXME is this sane? check against xxxfb_setcolreg()! */ ++ switch (info->var.bits_per_pixel) { ++ case 16: ++ case 24: ++ case 32: ++ ((u32 *)info->pseudo_palette)[regno] = v; ++ break; ++ } ++ ++ return 0; ++} ++ ++static void xenfb_timer(unsigned long data) ++{ ++ struct xenfb_info *info = (struct xenfb_info *)data; ++ info->dirty = 1; ++ wake_up(&info->wq); ++} ++ ++static void __xenfb_refresh(struct xenfb_info *info, ++ int x1, int y1, int w, int h) ++{ ++ int y2, x2; ++ ++ y2 = y1 + h; ++ x2 = x1 + w; ++ ++ if (info->y1 > y1) ++ info->y1 = y1; ++ if (info->y2 < y2) ++ info->y2 = y2; ++ if (info->x1 > x1) ++ info->x1 = x1; ++ if (info->x2 < x2) ++ info->x2 = x2; ++ ++ if (timer_pending(&info->refresh)) ++ return; ++ ++ mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); ++} ++ ++static void xenfb_refresh(struct xenfb_info *info, ++ int x1, int y1, int w, int h) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&info->dirty_lock, flags); ++ __xenfb_refresh(info, x1, y1, w, h); ++ spin_unlock_irqrestore(&info->dirty_lock, flags); ++} ++ ++static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) ++{ ++ struct xenfb_info *info = p->par; ++ ++ cfb_fillrect(p, rect); ++ xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); ++} ++ ++static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) ++{ ++ struct xenfb_info *info = p->par; ++ ++ cfb_imageblit(p, image); ++ xenfb_refresh(info, image->dx, image->dy, image->width, image->height); ++} ++ ++static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) ++{ ++ struct xenfb_info *info = p->par; ++ ++ cfb_copyarea(p, area); ++ xenfb_refresh(info, area->dx, area->dy, area->width, area->height); ++} ++ ++static void xenfb_vm_open(struct vm_area_struct *vma) ++{ ++ struct xenfb_mapping *map = vma->vm_private_data; ++ atomic_inc(&map->map_refs); ++} ++ ++static void xenfb_vm_close(struct vm_area_struct *vma) ++{ ++ struct xenfb_mapping *map = vma->vm_private_data; ++ struct xenfb_info *info = map->info; ++ ++ mutex_lock(&info->mm_lock); ++ if (atomic_dec_and_test(&map->map_refs)) { ++ list_del(&map->link); ++ kfree(map); ++ } ++ mutex_unlock(&info->mm_lock); ++} ++ ++static struct page *xenfb_vm_nopage(struct vm_area_struct *vma, ++ unsigned long vaddr, int *type) ++{ ++ struct xenfb_mapping *map = vma->vm_private_data; ++ struct xenfb_info *info = map->info; ++ int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long flags; ++ struct page *page; ++ int y1, y2; ++ ++ if (pgnr >= info->nr_pages) ++ return NOPAGE_SIGBUS; ++ ++ mutex_lock(&info->mm_lock); ++ spin_lock_irqsave(&info->dirty_lock, flags); ++ page = info->pages[pgnr]; ++ get_page(page); ++ map->faults++; ++ ++ y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length; ++ y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length; ++ if (y2 > info->fb_info->var.yres) ++ y2 = info->fb_info->var.yres; ++ __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1); ++ spin_unlock_irqrestore(&info->dirty_lock, flags); ++ mutex_unlock(&info->mm_lock); ++ ++ if (type) ++ *type = VM_FAULT_MINOR; ++ ++ return page; ++} ++ ++static struct vm_operations_struct xenfb_vm_ops = { ++ .open = xenfb_vm_open, ++ .close = xenfb_vm_close, ++ .nopage = xenfb_vm_nopage, ++}; ++ ++static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma) ++{ ++ struct xenfb_info *info = fb_info->par; ++ struct xenfb_mapping *map; ++ int map_pages; ++ ++ if (!(vma->vm_flags & VM_WRITE)) ++ return -EINVAL; ++ if (!(vma->vm_flags & VM_SHARED)) ++ return -EINVAL; ++ if (vma->vm_pgoff != 0) ++ return -EINVAL; ++ ++ map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT; ++ if (map_pages > info->nr_pages) ++ return -EINVAL; ++ ++ map = kzalloc(sizeof(*map), GFP_KERNEL); ++ if (map == NULL) ++ return -ENOMEM; ++ ++ map->vma = vma; ++ map->faults = 0; ++ map->info = info; ++ atomic_set(&map->map_refs, 1); ++ ++ mutex_lock(&info->mm_lock); ++ list_add(&map->link, &info->mappings); ++ mutex_unlock(&info->mm_lock); ++ ++ vma->vm_ops = &xenfb_vm_ops; ++ vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); ++ vma->vm_private_data = map; ++ ++ return 0; ++} ++ ++static struct fb_ops xenfb_fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_setcolreg = xenfb_setcolreg, ++ .fb_fillrect = xenfb_fillrect, ++ .fb_copyarea = xenfb_copyarea, ++ .fb_imageblit = xenfb_imageblit, ++ .fb_mmap = xenfb_mmap, ++}; ++ ++static irqreturn_t xenfb_event_handler(int rq, void *dev_id) ++{ ++ /* ++ * No in events recognized, simply ignore them all. ++ * If you need to recognize some, see xenbkd's input_handler() ++ * for how to do that. ++ */ ++ struct xenfb_info *info = dev_id; ++ struct xenfb_page *page = info->page; ++ ++ if (page->in_cons != page->in_prod) { ++ info->page->in_cons = info->page->in_prod; ++ notify_remote_via_irq(info->irq); ++ } ++ return IRQ_HANDLED; ++} ++ ++static unsigned long vmalloc_to_mfn(void *address) ++{ ++ return pfn_to_mfn(vmalloc_to_pfn(address)); ++} ++ ++static int __devinit xenfb_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ struct xenfb_info *info; ++ struct fb_info *fb_info; ++ int ret; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (info == NULL) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); ++ return -ENOMEM; ++ } ++ dev->dev.driver_data = info; ++ info->xbdev = dev; ++ info->irq = -1; ++ info->x1 = info->y1 = INT_MAX; ++ spin_lock_init(&info->dirty_lock); ++ mutex_init(&info->mm_lock); ++ init_waitqueue_head(&info->wq); ++ init_timer(&info->refresh); ++ info->refresh.function = xenfb_timer; ++ info->refresh.data = (unsigned long)info; ++ INIT_LIST_HEAD(&info->mappings); ++ ++ info->fb = vmalloc(xenfb_mem_len); ++ if (info->fb == NULL) ++ goto error_nomem; ++ memset(info->fb, 0, xenfb_mem_len); ++ ++ info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ ++ info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, ++ GFP_KERNEL); ++ if (info->pages == NULL) ++ goto error_nomem; ++ ++ info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); ++ if (!info->mfns) ++ goto error_nomem; ++ ++ /* set up shared page */ ++ info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); ++ if (!info->page) ++ goto error_nomem; ++ ++ xenfb_init_shared_page(info); ++ ++ fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); ++ /* see fishy hackery below */ ++ if (fb_info == NULL) ++ goto error_nomem; ++ ++ /* FIXME fishy hackery */ ++ fb_info->pseudo_palette = fb_info->par; ++ fb_info->par = info; ++ /* /FIXME */ ++ fb_info->screen_base = info->fb; ++ ++ fb_info->fbops = &xenfb_fb_ops; ++ fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; ++ fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; ++ fb_info->var.bits_per_pixel = info->page->depth; ++ ++ fb_info->var.red = (struct fb_bitfield){16, 8, 0}; ++ fb_info->var.green = (struct fb_bitfield){8, 8, 0}; ++ fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; ++ ++ fb_info->var.activate = FB_ACTIVATE_NOW; ++ fb_info->var.height = -1; ++ fb_info->var.width = -1; ++ fb_info->var.vmode = FB_VMODE_NONINTERLACED; ++ ++ fb_info->fix.visual = FB_VISUAL_TRUECOLOR; ++ fb_info->fix.line_length = info->page->line_length; ++ fb_info->fix.smem_start = 0; ++ fb_info->fix.smem_len = xenfb_mem_len; ++ strcpy(fb_info->fix.id, "xen"); ++ fb_info->fix.type = FB_TYPE_PACKED_PIXELS; ++ fb_info->fix.accel = FB_ACCEL_NONE; ++ ++ fb_info->flags = FBINFO_FLAG_DEFAULT; ++ ++ ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); ++ if (ret < 0) { ++ framebuffer_release(fb_info); ++ xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); ++ goto error; ++ } ++ ++ ret = register_framebuffer(fb_info); ++ if (ret) { ++ fb_dealloc_cmap(&info->fb_info->cmap); ++ framebuffer_release(fb_info); ++ xenbus_dev_fatal(dev, ret, "register_framebuffer"); ++ goto error; ++ } ++ info->fb_info = fb_info; ++ ++ /* FIXME should this be delayed until backend XenbusStateConnected? */ ++ info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); ++ if (IS_ERR(info->kthread)) { ++ ret = PTR_ERR(info->kthread); ++ info->kthread = NULL; ++ xenbus_dev_fatal(dev, ret, "register_framebuffer"); ++ goto error; ++ } ++ ++ ret = xenfb_connect_backend(dev, info); ++ if (ret < 0) ++ goto error; ++ ++ return 0; ++ ++ error_nomem: ++ ret = -ENOMEM; ++ xenbus_dev_fatal(dev, ret, "allocating device memory"); ++ error: ++ xenfb_remove(dev); ++ return ret; ++} ++ ++static int xenfb_resume(struct xenbus_device *dev) ++{ ++ struct xenfb_info *info = dev->dev.driver_data; ++ ++ xenfb_disconnect_backend(info); ++ xenfb_init_shared_page(info); ++ return xenfb_connect_backend(dev, info); ++} ++ ++static int xenfb_remove(struct xenbus_device *dev) ++{ ++ struct xenfb_info *info = dev->dev.driver_data; ++ ++ del_timer(&info->refresh); ++ if (info->kthread) ++ kthread_stop(info->kthread); ++ xenfb_disconnect_backend(info); ++ if (info->fb_info) { ++ unregister_framebuffer(info->fb_info); ++ fb_dealloc_cmap(&info->fb_info->cmap); ++ framebuffer_release(info->fb_info); ++ } ++ free_page((unsigned long)info->page); ++ vfree(info->mfns); ++ kfree(info->pages); ++ vfree(info->fb); ++ kfree(info); ++ ++ return 0; ++} ++ ++static void xenfb_init_shared_page(struct xenfb_info *info) ++{ ++ int i; ++ ++ for (i = 0; i < info->nr_pages; i++) ++ info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); ++ ++ for (i = 0; i < info->nr_pages; i++) ++ info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); ++ ++ info->page->pd[0] = vmalloc_to_mfn(info->mfns); ++ info->page->pd[1] = 0; ++ info->page->width = XENFB_WIDTH; ++ info->page->height = XENFB_HEIGHT; ++ info->page->depth = XENFB_DEPTH; ++ info->page->line_length = (info->page->depth / 8) * info->page->width; ++ info->page->mem_length = xenfb_mem_len; ++ info->page->in_cons = info->page->in_prod = 0; ++ info->page->out_cons = info->page->out_prod = 0; ++} ++ ++static int xenfb_connect_backend(struct xenbus_device *dev, ++ struct xenfb_info *info) ++{ ++ int ret; ++ struct xenbus_transaction xbt; ++ ++ ret = bind_listening_port_to_irqhandler( ++ dev->otherend_id, xenfb_event_handler, 0, "xenfb", info); ++ if (ret < 0) { ++ xenbus_dev_fatal(dev, ret, ++ "bind_listening_port_to_irqhandler"); ++ return ret; ++ } ++ info->irq = ret; ++ ++ again: ++ ret = xenbus_transaction_start(&xbt); ++ if (ret) { ++ xenbus_dev_fatal(dev, ret, "starting transaction"); ++ return ret; ++ } ++ ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", ++ virt_to_mfn(info->page)); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", ++ irq_to_evtchn_port(info->irq)); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", ++ XEN_IO_PROTO_ABI_NATIVE); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_transaction_end(xbt, 0); ++ if (ret) { ++ if (ret == -EAGAIN) ++ goto again; ++ xenbus_dev_fatal(dev, ret, "completing transaction"); ++ return ret; ++ } ++ ++ xenbus_switch_state(dev, XenbusStateInitialised); ++ return 0; ++ ++ error_xenbus: ++ xenbus_transaction_end(xbt, 1); ++ xenbus_dev_fatal(dev, ret, "writing xenstore"); ++ return ret; ++} ++ ++static void xenfb_disconnect_backend(struct xenfb_info *info) ++{ ++ if (info->irq >= 0) ++ unbind_from_irqhandler(info->irq, info); ++ info->irq = -1; ++} ++ ++static void xenfb_backend_changed(struct xenbus_device *dev, ++ enum xenbus_state backend_state) ++{ ++ struct xenfb_info *info = dev->dev.driver_data; ++ int val; ++ ++ switch (backend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitialised: ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ break; ++ ++ case XenbusStateInitWait: ++ InitWait: ++ xenbus_switch_state(dev, XenbusStateConnected); ++ break; ++ ++ case XenbusStateConnected: ++ /* ++ * Work around xenbus race condition: If backend goes ++ * through InitWait to Connected fast enough, we can ++ * get Connected twice here. ++ */ ++ if (dev->state != XenbusStateConnected) ++ goto InitWait; /* no InitWait seen yet, fudge it */ ++ ++ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, ++ "request-update", "%d", &val) < 0) ++ val = 0; ++ if (val) ++ info->update_wanted = 1; ++ break; ++ ++ case XenbusStateClosing: ++ // FIXME is this safe in any dev->state? ++ xenbus_frontend_closed(dev); ++ break; ++ } ++} ++ ++static struct xenbus_device_id xenfb_ids[] = { ++ { "vfb" }, ++ { "" } ++}; ++ ++static struct xenbus_driver xenfb = { ++ .name = "vfb", ++ .owner = THIS_MODULE, ++ .ids = xenfb_ids, ++ .probe = xenfb_probe, ++ .remove = xenfb_remove, ++ .resume = xenfb_resume, ++ .otherend_changed = xenfb_backend_changed, ++}; ++ ++static int __init xenfb_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ /* Nothing to do if running in dom0. */ ++ if (is_initial_xendomain()) ++ return -ENODEV; ++ ++ return xenbus_register_frontend(&xenfb); ++} ++ ++static void __exit xenfb_cleanup(void) ++{ ++ return xenbus_unregister_driver(&xenfb); ++} ++ ++module_init(xenfb_init); ++module_exit(xenfb_cleanup); ++ ++MODULE_LICENSE("GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/fbfront/xenkbd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/fbfront/xenkbd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,333 @@ ++/* ++ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device ++ * ++ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> ++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> ++ * ++ * Based on linux/drivers/input/mouse/sermouse.c ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++/* ++ * TODO: ++ * ++ * Switch to grant tables together with xenfb.c. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/module.h> ++#include <linux/input.h> ++#include <asm/hypervisor.h> ++#include <xen/evtchn.h> ++#include <xen/interface/io/fbif.h> ++#include <xen/interface/io/kbdif.h> ++#include <xen/xenbus.h> ++ ++struct xenkbd_info ++{ ++ struct input_dev *kbd; ++ struct input_dev *ptr; ++ struct xenkbd_page *page; ++ int irq; ++ struct xenbus_device *xbdev; ++ char phys[32]; ++}; ++ ++static int xenkbd_remove(struct xenbus_device *); ++static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); ++static void xenkbd_disconnect_backend(struct xenkbd_info *); ++ ++/* ++ * Note: if you need to send out events, see xenfb_do_update() for how ++ * to do that. ++ */ ++ ++static irqreturn_t input_handler(int rq, void *dev_id) ++{ ++ struct xenkbd_info *info = dev_id; ++ struct xenkbd_page *page = info->page; ++ __u32 cons, prod; ++ ++ prod = page->in_prod; ++ if (prod == page->out_cons) ++ return IRQ_HANDLED; ++ rmb(); /* ensure we see ring contents up to prod */ ++ for (cons = page->in_cons; cons != prod; cons++) { ++ union xenkbd_in_event *event; ++ struct input_dev *dev; ++ event = &XENKBD_IN_RING_REF(page, cons); ++ ++ dev = info->ptr; ++ switch (event->type) { ++ case XENKBD_TYPE_MOTION: ++ input_report_rel(dev, REL_X, event->motion.rel_x); ++ input_report_rel(dev, REL_Y, event->motion.rel_y); ++ break; ++ case XENKBD_TYPE_KEY: ++ dev = NULL; ++ if (test_bit(event->key.keycode, info->kbd->keybit)) ++ dev = info->kbd; ++ if (test_bit(event->key.keycode, info->ptr->keybit)) ++ dev = info->ptr; ++ if (dev) ++ input_report_key(dev, event->key.keycode, ++ event->key.pressed); ++ else ++ printk("xenkbd: unhandled keycode 0x%x\n", ++ event->key.keycode); ++ break; ++ case XENKBD_TYPE_POS: ++ input_report_abs(dev, ABS_X, event->pos.abs_x); ++ input_report_abs(dev, ABS_Y, event->pos.abs_y); ++ break; ++ } ++ if (dev) ++ input_sync(dev); ++ } ++ mb(); /* ensure we got ring contents */ ++ page->in_cons = cons; ++ notify_remote_via_irq(info->irq); ++ ++ return IRQ_HANDLED; ++} ++ ++int __devinit xenkbd_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int ret, i; ++ struct xenkbd_info *info; ++ struct input_dev *kbd, *ptr; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); ++ return -ENOMEM; ++ } ++ dev->dev.driver_data = info; ++ info->xbdev = dev; ++ snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); ++ ++ info->page = (void *)__get_free_page(GFP_KERNEL); ++ if (!info->page) ++ goto error_nomem; ++ info->page->in_cons = info->page->in_prod = 0; ++ info->page->out_cons = info->page->out_prod = 0; ++ ++ /* keyboard */ ++ kbd = input_allocate_device(); ++ if (!kbd) ++ goto error_nomem; ++ kbd->name = "Xen Virtual Keyboard"; ++ kbd->phys = info->phys; ++ kbd->id.bustype = BUS_PCI; ++ kbd->id.vendor = 0x5853; ++ kbd->id.product = 0xffff; ++ kbd->evbit[0] = BIT(EV_KEY); ++ for (i = KEY_ESC; i < KEY_UNKNOWN; i++) ++ set_bit(i, kbd->keybit); ++ for (i = KEY_OK; i < KEY_MAX; i++) ++ set_bit(i, kbd->keybit); ++ ++ ret = input_register_device(kbd); ++ if (ret) { ++ input_free_device(kbd); ++ xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); ++ goto error; ++ } ++ info->kbd = kbd; ++ ++ /* pointing device */ ++ ptr = input_allocate_device(); ++ if (!ptr) ++ goto error_nomem; ++ ptr->name = "Xen Virtual Pointer"; ++ ptr->phys = info->phys; ++ ptr->id.bustype = BUS_PCI; ++ ptr->id.vendor = 0x5853; ++ ptr->id.product = 0xfffe; ++ ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); ++ for (i = BTN_LEFT; i <= BTN_TASK; i++) ++ set_bit(i, ptr->keybit); ++ ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); ++ input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); ++ input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); ++ ++ ret = input_register_device(ptr); ++ if (ret) { ++ input_free_device(ptr); ++ xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); ++ goto error; ++ } ++ info->ptr = ptr; ++ ++ ret = xenkbd_connect_backend(dev, info); ++ if (ret < 0) ++ goto error; ++ ++ return 0; ++ ++ error_nomem: ++ ret = -ENOMEM; ++ xenbus_dev_fatal(dev, ret, "allocating device memory"); ++ error: ++ xenkbd_remove(dev); ++ return ret; ++} ++ ++static int xenkbd_resume(struct xenbus_device *dev) ++{ ++ struct xenkbd_info *info = dev->dev.driver_data; ++ ++ xenkbd_disconnect_backend(info); ++ return xenkbd_connect_backend(dev, info); ++} ++ ++static int xenkbd_remove(struct xenbus_device *dev) ++{ ++ struct xenkbd_info *info = dev->dev.driver_data; ++ ++ xenkbd_disconnect_backend(info); ++ input_unregister_device(info->kbd); ++ input_unregister_device(info->ptr); ++ free_page((unsigned long)info->page); ++ kfree(info); ++ return 0; ++} ++ ++static int xenkbd_connect_backend(struct xenbus_device *dev, ++ struct xenkbd_info *info) ++{ ++ int ret; ++ struct xenbus_transaction xbt; ++ ++ ret = bind_listening_port_to_irqhandler( ++ dev->otherend_id, input_handler, 0, "xenkbd", info); ++ if (ret < 0) { ++ xenbus_dev_fatal(dev, ret, ++ "bind_listening_port_to_irqhandler"); ++ return ret; ++ } ++ info->irq = ret; ++ ++ again: ++ ret = xenbus_transaction_start(&xbt); ++ if (ret) { ++ xenbus_dev_fatal(dev, ret, "starting transaction"); ++ return ret; ++ } ++ ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", ++ virt_to_mfn(info->page)); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", ++ irq_to_evtchn_port(info->irq)); ++ if (ret) ++ goto error_xenbus; ++ ret = xenbus_transaction_end(xbt, 0); ++ if (ret) { ++ if (ret == -EAGAIN) ++ goto again; ++ xenbus_dev_fatal(dev, ret, "completing transaction"); ++ return ret; ++ } ++ ++ xenbus_switch_state(dev, XenbusStateInitialised); ++ return 0; ++ ++ error_xenbus: ++ xenbus_transaction_end(xbt, 1); ++ xenbus_dev_fatal(dev, ret, "writing xenstore"); ++ return ret; ++} ++ ++static void xenkbd_disconnect_backend(struct xenkbd_info *info) ++{ ++ if (info->irq >= 0) ++ unbind_from_irqhandler(info->irq, info); ++ info->irq = -1; ++} ++ ++static void xenkbd_backend_changed(struct xenbus_device *dev, ++ enum xenbus_state backend_state) ++{ ++ struct xenkbd_info *info = dev->dev.driver_data; ++ int ret, val; ++ ++ switch (backend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitialised: ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ break; ++ ++ case XenbusStateInitWait: ++ InitWait: ++ ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, ++ "feature-abs-pointer", "%d", &val); ++ if (ret < 0) ++ val = 0; ++ if (val) { ++ ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, ++ "request-abs-pointer", "1"); ++ if (ret) ++ ; /* FIXME */ ++ } ++ xenbus_switch_state(dev, XenbusStateConnected); ++ break; ++ ++ case XenbusStateConnected: ++ /* ++ * Work around xenbus race condition: If backend goes ++ * through InitWait to Connected fast enough, we can ++ * get Connected twice here. ++ */ ++ if (dev->state != XenbusStateConnected) ++ goto InitWait; /* no InitWait seen yet, fudge it */ ++ break; ++ ++ case XenbusStateClosing: ++ xenbus_frontend_closed(dev); ++ break; ++ } ++} ++ ++static struct xenbus_device_id xenkbd_ids[] = { ++ { "vkbd" }, ++ { "" } ++}; ++ ++static struct xenbus_driver xenkbd = { ++ .name = "vkbd", ++ .owner = THIS_MODULE, ++ .ids = xenkbd_ids, ++ .probe = xenkbd_probe, ++ .remove = xenkbd_remove, ++ .resume = xenkbd_resume, ++ .otherend_changed = xenkbd_backend_changed, ++}; ++ ++static int __init xenkbd_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ /* Nothing to do if running in dom0. */ ++ if (is_initial_xendomain()) ++ return -ENODEV; ++ ++ return xenbus_register_frontend(&xenkbd); ++} ++ ++static void __exit xenkbd_cleanup(void) ++{ ++ return xenbus_unregister_driver(&xenkbd); ++} ++ ++module_init(xenkbd_init); ++module_exit(xenkbd_cleanup); ++ ++MODULE_LICENSE("GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/gntdev/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/gntdev/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1 @@ ++obj-y := gntdev.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/gntdev/gntdev.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/gntdev/gntdev.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,973 @@ ++/****************************************************************************** ++ * gntdev.c ++ * ++ * Device for accessing (in user-space) pages that have been granted by other ++ * domains. ++ * ++ * Copyright (c) 2006-2007, D G Murray. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <asm/atomic.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/device.h> ++#include <linux/mm.h> ++#include <linux/mman.h> ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <xen/gnttab.h> ++#include <asm/hypervisor.h> ++#include <xen/balloon.h> ++#include <xen/evtchn.h> ++#include <xen/driver_util.h> ++ ++#include <linux/types.h> ++#include <xen/public/gntdev.h> ++ ++ ++#define DRIVER_AUTHOR "Derek G. Murray <Derek.Murray@cl.cam.ac.uk>" ++#define DRIVER_DESC "User-space granted page access driver" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++ ++#define MAX_GRANTS 128 ++ ++/* A slot can be in one of three states: ++ * ++ * 0. GNTDEV_SLOT_INVALID: ++ * This slot is not associated with a grant reference, and is therefore free ++ * to be overwritten by a new grant reference. ++ * ++ * 1. GNTDEV_SLOT_NOT_YET_MAPPED: ++ * This slot is associated with a grant reference (via the ++ * IOCTL_GNTDEV_MAP_GRANT_REF ioctl), but it has not yet been mmap()-ed. ++ * ++ * 2. GNTDEV_SLOT_MAPPED: ++ * This slot is associated with a grant reference, and has been mmap()-ed. ++ */ ++typedef enum gntdev_slot_state { ++ GNTDEV_SLOT_INVALID = 0, ++ GNTDEV_SLOT_NOT_YET_MAPPED, ++ GNTDEV_SLOT_MAPPED ++} gntdev_slot_state_t; ++ ++#define GNTDEV_INVALID_HANDLE -1 ++#define GNTDEV_FREE_LIST_INVALID -1 ++/* Each opened instance of gntdev is associated with a list of grants, ++ * represented by an array of elements of the following type, ++ * gntdev_grant_info_t. ++ */ ++typedef struct gntdev_grant_info { ++ gntdev_slot_state_t state; ++ union { ++ uint32_t free_list_index; ++ struct { ++ domid_t domid; ++ grant_ref_t ref; ++ grant_handle_t kernel_handle; ++ grant_handle_t user_handle; ++ uint64_t dev_bus_addr; ++ } valid; ++ } u; ++} gntdev_grant_info_t; ++ ++/* Private data structure, which is stored in the file pointer for files ++ * associated with this device. ++ */ ++typedef struct gntdev_file_private_data { ++ ++ /* Array of grant information. */ ++ gntdev_grant_info_t grants[MAX_GRANTS]; ++ ++ /* Read/write semaphore used to protect the grants array. */ ++ struct rw_semaphore grants_sem; ++ ++ /* An array of indices of free slots in the grants array. ++ * N.B. An entry in this list may temporarily have the value ++ * GNTDEV_FREE_LIST_INVALID if the corresponding slot has been removed ++ * from the list by the contiguous allocator, but the list has not yet ++ * been compressed. However, this is not visible across invocations of ++ * the device. ++ */ ++ int32_t free_list[MAX_GRANTS]; ++ ++ /* The number of free slots in the grants array. */ ++ uint32_t free_list_size; ++ ++ /* Read/write semaphore used to protect the free list. */ ++ struct rw_semaphore free_list_sem; ++ ++ /* Index of the next slot after the most recent contiguous allocation, ++ * for use in a next-fit allocator. ++ */ ++ uint32_t next_fit_index; ++ ++ /* Used to map grants into the kernel, before mapping them into user ++ * space. ++ */ ++ struct page **foreign_pages; ++ ++} gntdev_file_private_data_t; ++ ++/* Module lifecycle operations. */ ++static int __init gntdev_init(void); ++static void __exit gntdev_exit(void); ++ ++module_init(gntdev_init); ++module_exit(gntdev_exit); ++ ++/* File operations. */ ++static int gntdev_open(struct inode *inode, struct file *flip); ++static int gntdev_release(struct inode *inode, struct file *flip); ++static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma); ++static int gntdev_ioctl (struct inode *inode, struct file *flip, ++ unsigned int cmd, unsigned long arg); ++ ++static struct file_operations gntdev_fops = { ++ .owner = THIS_MODULE, ++ .open = gntdev_open, ++ .release = gntdev_release, ++ .mmap = gntdev_mmap, ++ .ioctl = gntdev_ioctl ++}; ++ ++/* VM operations. */ ++static void gntdev_vma_close(struct vm_area_struct *vma); ++static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr, ++ pte_t *ptep, int is_fullmm); ++ ++static struct vm_operations_struct gntdev_vmops = { ++ .close = gntdev_vma_close, ++ .zap_pte = gntdev_clear_pte ++}; ++ ++/* Global variables. */ ++ ++/* The driver major number, for use when unregistering the driver. */ ++static int gntdev_major; ++ ++#define GNTDEV_NAME "gntdev" ++ ++/* Memory mapping functions ++ * ------------------------ ++ * ++ * Every granted page is mapped into both kernel and user space, and the two ++ * following functions return the respective virtual addresses of these pages. ++ * ++ * When shadow paging is disabled, the granted page is mapped directly into ++ * user space; when it is enabled, it is mapped into the kernel and remapped ++ * into user space using vm_insert_page() (see gntdev_mmap(), below). ++ */ ++ ++/* Returns the virtual address (in user space) of the @page_index'th page ++ * in the given VM area. ++ */ ++static inline unsigned long get_user_vaddr (struct vm_area_struct *vma, ++ int page_index) ++{ ++ return (unsigned long) vma->vm_start + (page_index << PAGE_SHIFT); ++} ++ ++/* Returns the virtual address (in kernel space) of the @slot_index'th page ++ * mapped by the gntdev instance that owns the given private data struct. ++ */ ++static inline unsigned long get_kernel_vaddr (gntdev_file_private_data_t *priv, ++ int slot_index) ++{ ++ unsigned long pfn; ++ void *kaddr; ++ pfn = page_to_pfn(priv->foreign_pages[slot_index]); ++ kaddr = pfn_to_kaddr(pfn); ++ return (unsigned long) kaddr; ++} ++ ++/* Helper functions. */ ++ ++/* Adds information about a grant reference to the list of grants in the file's ++ * private data structure. Returns non-zero on failure. On success, sets the ++ * value of *offset to the offset that should be mmap()-ed in order to map the ++ * grant reference. ++ */ ++static int add_grant_reference(struct file *flip, ++ struct ioctl_gntdev_grant_ref *op, ++ uint64_t *offset) ++{ ++ gntdev_file_private_data_t *private_data ++ = (gntdev_file_private_data_t *) flip->private_data; ++ ++ uint32_t slot_index; ++ ++ if (unlikely(private_data->free_list_size == 0)) { ++ return -ENOMEM; ++ } ++ ++ slot_index = private_data->free_list[--private_data->free_list_size]; ++ ++ /* Copy the grant information into file's private data. */ ++ private_data->grants[slot_index].state = GNTDEV_SLOT_NOT_YET_MAPPED; ++ private_data->grants[slot_index].u.valid.domid = op->domid; ++ private_data->grants[slot_index].u.valid.ref = op->ref; ++ ++ /* The offset is calculated as the index of the chosen entry in the ++ * file's private data's array of grant information. This is then ++ * shifted to give an offset into the virtual "file address space". ++ */ ++ *offset = slot_index << PAGE_SHIFT; ++ ++ return 0; ++} ++ ++/* Adds the @count grant references to the contiguous range in the slot array ++ * beginning at @first_slot. It is assumed that @first_slot was returned by a ++ * previous invocation of find_contiguous_free_range(), during the same ++ * invocation of the driver. ++ */ ++static int add_grant_references(struct file *flip, ++ int count, ++ struct ioctl_gntdev_grant_ref *ops, ++ uint32_t first_slot) ++{ ++ gntdev_file_private_data_t *private_data ++ = (gntdev_file_private_data_t *) flip->private_data; ++ int i; ++ ++ for (i = 0; i < count; ++i) { ++ ++ /* First, mark the slot's entry in the free list as invalid. */ ++ int free_list_index = ++ private_data->grants[first_slot+i].u.free_list_index; ++ private_data->free_list[free_list_index] = ++ GNTDEV_FREE_LIST_INVALID; ++ ++ /* Now, update the slot. */ ++ private_data->grants[first_slot+i].state = ++ GNTDEV_SLOT_NOT_YET_MAPPED; ++ private_data->grants[first_slot+i].u.valid.domid = ++ ops[i].domid; ++ private_data->grants[first_slot+i].u.valid.ref = ops[i].ref; ++ } ++ ++ return 0; ++} ++ ++/* Scans through the free list for @flip, removing entries that are marked as ++ * GNTDEV_SLOT_INVALID. This will reduce the recorded size of the free list to ++ * the number of valid entries. ++ */ ++static void compress_free_list(struct file *flip) ++{ ++ gntdev_file_private_data_t *private_data ++ = (gntdev_file_private_data_t *) flip->private_data; ++ int i, j = 0, old_size; ++ ++ old_size = private_data->free_list_size; ++ for (i = 0; i < old_size; ++i) { ++ if (private_data->free_list[i] != GNTDEV_FREE_LIST_INVALID) { ++ private_data->free_list[j] = ++ private_data->free_list[i]; ++ ++j; ++ } else { ++ --private_data->free_list_size; ++ } ++ } ++} ++ ++/* Searches the grant array in the private data of @flip for a range of ++ * @num_slots contiguous slots in the GNTDEV_SLOT_INVALID state. ++ * ++ * Returns the index of the first slot if a range is found, otherwise -ENOMEM. ++ */ ++static int find_contiguous_free_range(struct file *flip, ++ uint32_t num_slots) ++{ ++ gntdev_file_private_data_t *private_data ++ = (gntdev_file_private_data_t *) flip->private_data; ++ ++ int i; ++ int start_index = private_data->next_fit_index; ++ int range_start = 0, range_length; ++ ++ if (private_data->free_list_size < num_slots) { ++ return -ENOMEM; ++ } ++ ++ /* First search from the start_index to the end of the array. */ ++ range_length = 0; ++ for (i = start_index; i < MAX_GRANTS; ++i) { ++ if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) { ++ if (range_length == 0) { ++ range_start = i; ++ } ++ ++range_length; ++ if (range_length == num_slots) { ++ return range_start; ++ } ++ } ++ } ++ ++ /* Now search from the start of the array to the start_index. */ ++ range_length = 0; ++ for (i = 0; i < start_index; ++i) { ++ if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) { ++ if (range_length == 0) { ++ range_start = i; ++ } ++ ++range_length; ++ if (range_length == num_slots) { ++ return range_start; ++ } ++ } ++ } ++ ++ return -ENOMEM; ++} ++ ++/* Interface functions. */ ++ ++/* Initialises the driver. Called when the module is loaded. */ ++static int __init gntdev_init(void) ++{ ++ struct class *class; ++ struct class_device *device; ++ ++ if (!is_running_on_xen()) { ++ printk(KERN_ERR "You must be running Xen to use gntdev\n"); ++ return -ENODEV; ++ } ++ ++ gntdev_major = register_chrdev(0, GNTDEV_NAME, &gntdev_fops); ++ if (gntdev_major < 0) ++ { ++ printk(KERN_ERR "Could not register gntdev device\n"); ++ return -ENOMEM; ++ } ++ ++ /* Note that if the sysfs code fails, we will still initialise the ++ * device, and output the major number so that the device can be ++ * created manually using mknod. ++ */ ++ if ((class = get_xen_class()) == NULL) { ++ printk(KERN_ERR "Error setting up xen_class\n"); ++ printk(KERN_ERR "gntdev created with major number = %d\n", ++ gntdev_major); ++ return 0; ++ } ++ ++ device = class_device_create(class, NULL, MKDEV(gntdev_major, 0), ++ NULL, GNTDEV_NAME); ++ if (IS_ERR(device)) { ++ printk(KERN_ERR "Error creating gntdev device in xen_class\n"); ++ printk(KERN_ERR "gntdev created with major number = %d\n", ++ gntdev_major); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++/* Cleans up and unregisters the driver. Called when the driver is unloaded. ++ */ ++static void __exit gntdev_exit(void) ++{ ++ struct class *class; ++ if ((class = get_xen_class()) != NULL) ++ class_device_destroy(class, MKDEV(gntdev_major, 0)); ++ unregister_chrdev(gntdev_major, GNTDEV_NAME); ++} ++ ++/* Called when the device is opened. */ ++static int gntdev_open(struct inode *inode, struct file *flip) ++{ ++ gntdev_file_private_data_t *private_data; ++ int i; ++ ++ try_module_get(THIS_MODULE); ++ ++ /* Allocate space for the per-instance private data. */ ++ private_data = kmalloc(sizeof(*private_data), GFP_KERNEL); ++ if (!private_data) ++ goto nomem_out; ++ ++ /* Allocate space for the kernel-mapping of granted pages. */ ++ private_data->foreign_pages = ++ alloc_empty_pages_and_pagevec(MAX_GRANTS); ++ if (!private_data->foreign_pages) ++ goto nomem_out2; ++ ++ /* Initialise the free-list, which contains all slots at first. ++ */ ++ for (i = 0; i < MAX_GRANTS; ++i) { ++ private_data->free_list[MAX_GRANTS - i - 1] = i; ++ private_data->grants[i].state = GNTDEV_SLOT_INVALID; ++ private_data->grants[i].u.free_list_index = MAX_GRANTS - i - 1; ++ } ++ private_data->free_list_size = MAX_GRANTS; ++ private_data->next_fit_index = 0; ++ ++ init_rwsem(&private_data->grants_sem); ++ init_rwsem(&private_data->free_list_sem); ++ ++ flip->private_data = private_data; ++ ++ return 0; ++ ++nomem_out2: ++ kfree(private_data); ++nomem_out: ++ return -ENOMEM; ++} ++ ++/* Called when the device is closed. ++ */ ++static int gntdev_release(struct inode *inode, struct file *flip) ++{ ++ if (flip->private_data) { ++ gntdev_file_private_data_t *private_data = ++ (gntdev_file_private_data_t *) flip->private_data; ++ if (private_data->foreign_pages) { ++ free_empty_pages_and_pagevec ++ (private_data->foreign_pages, MAX_GRANTS); ++ } ++ kfree(private_data); ++ } ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++/* Called when an attempt is made to mmap() the device. The private data from ++ * @flip contains the list of grant references that can be mapped. The vm_pgoff ++ * field of @vma contains the index into that list that refers to the grant ++ * reference that will be mapped. Only mappings that are a multiple of ++ * PAGE_SIZE are handled. ++ */ ++static int gntdev_mmap (struct file *flip, struct vm_area_struct *vma) ++{ ++ struct gnttab_map_grant_ref op; ++ unsigned long slot_index = vma->vm_pgoff; ++ unsigned long kernel_vaddr, user_vaddr; ++ uint32_t size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ uint64_t ptep; ++ int ret; ++ int flags; ++ int i; ++ struct page *page; ++ gntdev_file_private_data_t *private_data = flip->private_data; ++ ++ if (unlikely(!private_data)) { ++ printk(KERN_ERR "File's private data is NULL.\n"); ++ return -EINVAL; ++ } ++ ++ if (unlikely((size <= 0) || (size + slot_index) > MAX_GRANTS)) { ++ printk(KERN_ERR "Invalid number of pages or offset" ++ "(num_pages = %d, first_slot = %ld).\n", ++ size, slot_index); ++ return -ENXIO; ++ } ++ ++ if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { ++ printk(KERN_ERR "Writable mappings must be shared.\n"); ++ return -EINVAL; ++ } ++ ++ /* Slots must be in the NOT_YET_MAPPED state. */ ++ down_write(&private_data->grants_sem); ++ for (i = 0; i < size; ++i) { ++ if (private_data->grants[slot_index + i].state != ++ GNTDEV_SLOT_NOT_YET_MAPPED) { ++ printk(KERN_ERR "Slot (index = %ld) is in the wrong " ++ "state (%d).\n", slot_index + i, ++ private_data->grants[slot_index + i].state); ++ up_write(&private_data->grants_sem); ++ return -EINVAL; ++ } ++ } ++ ++ /* Install the hook for unmapping. */ ++ vma->vm_ops = &gntdev_vmops; ++ ++ /* The VM area contains pages from another VM. */ ++ vma->vm_flags |= VM_FOREIGN; ++ vma->vm_private_data = kzalloc(size * sizeof(struct page_struct *), ++ GFP_KERNEL); ++ if (vma->vm_private_data == NULL) { ++ printk(KERN_ERR "Couldn't allocate mapping structure for VM " ++ "area.\n"); ++ return -ENOMEM; ++ } ++ ++ /* This flag prevents Bad PTE errors when the memory is unmapped. */ ++ vma->vm_flags |= VM_RESERVED; ++ ++ /* This flag prevents this VM area being copied on a fork(). A better ++ * behaviour might be to explicitly carry out the appropriate mappings ++ * on fork(), but I don't know if there's a hook for this. ++ */ ++ vma->vm_flags |= VM_DONTCOPY; ++ ++#ifdef CONFIG_X86 ++ /* This flag ensures that the page tables are not unpinned before the ++ * VM area is unmapped. Therefore Xen still recognises the PTE as ++ * belonging to an L1 pagetable, and the grant unmap operation will ++ * succeed, even if the process does not exit cleanly. ++ */ ++ vma->vm_mm->context.has_foreign_mappings = 1; ++#endif ++ ++ for (i = 0; i < size; ++i) { ++ ++ flags = GNTMAP_host_map; ++ if (!(vma->vm_flags & VM_WRITE)) ++ flags |= GNTMAP_readonly; ++ ++ kernel_vaddr = get_kernel_vaddr(private_data, slot_index + i); ++ user_vaddr = get_user_vaddr(vma, i); ++ page = pfn_to_page(__pa(kernel_vaddr) >> PAGE_SHIFT); ++ ++ gnttab_set_map_op(&op, kernel_vaddr, flags, ++ private_data->grants[slot_index+i] ++ .u.valid.ref, ++ private_data->grants[slot_index+i] ++ .u.valid.domid); ++ ++ /* Carry out the mapping of the grant reference. */ ++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, ++ &op, 1); ++ BUG_ON(ret); ++ if (op.status) { ++ printk(KERN_ERR "Error mapping the grant reference " ++ "into the kernel (%d). domid = %d; ref = %d\n", ++ op.status, ++ private_data->grants[slot_index+i] ++ .u.valid.domid, ++ private_data->grants[slot_index+i] ++ .u.valid.ref); ++ goto undo_map_out; ++ } ++ ++ /* Store a reference to the page that will be mapped into user ++ * space. ++ */ ++ ((struct page **) vma->vm_private_data)[i] = page; ++ ++ /* Mark mapped page as reserved. */ ++ SetPageReserved(page); ++ ++ /* Record the grant handle, for use in the unmap operation. */ ++ private_data->grants[slot_index+i].u.valid.kernel_handle = ++ op.handle; ++ private_data->grants[slot_index+i].u.valid.dev_bus_addr = ++ op.dev_bus_addr; ++ ++ private_data->grants[slot_index+i].state = GNTDEV_SLOT_MAPPED; ++ private_data->grants[slot_index+i].u.valid.user_handle = ++ GNTDEV_INVALID_HANDLE; ++ ++ /* Now perform the mapping to user space. */ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ ++ /* NOT USING SHADOW PAGE TABLES. */ ++ /* In this case, we map the grant(s) straight into user ++ * space. ++ */ ++ ++ /* Get the machine address of the PTE for the user ++ * page. ++ */ ++ if ((ret = create_lookup_pte_addr(vma->vm_mm, ++ vma->vm_start ++ + (i << PAGE_SHIFT), ++ &ptep))) ++ { ++ printk(KERN_ERR "Error obtaining PTE pointer " ++ "(%d).\n", ret); ++ goto undo_map_out; ++ } ++ ++ /* Configure the map operation. */ ++ ++ /* The reference is to be used by host CPUs. */ ++ flags = GNTMAP_host_map; ++ ++ /* Specifies a user space mapping. */ ++ flags |= GNTMAP_application_map; ++ ++ /* The map request contains the machine address of the ++ * PTE to update. ++ */ ++ flags |= GNTMAP_contains_pte; ++ ++ if (!(vma->vm_flags & VM_WRITE)) ++ flags |= GNTMAP_readonly; ++ ++ gnttab_set_map_op(&op, ptep, flags, ++ private_data->grants[slot_index+i] ++ .u.valid.ref, ++ private_data->grants[slot_index+i] ++ .u.valid.domid); ++ ++ /* Carry out the mapping of the grant reference. */ ++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, ++ &op, 1); ++ BUG_ON(ret); ++ if (op.status) { ++ printk(KERN_ERR "Error mapping the grant " ++ "reference into user space (%d). domid " ++ "= %d; ref = %d\n", op.status, ++ private_data->grants[slot_index+i].u ++ .valid.domid, ++ private_data->grants[slot_index+i].u ++ .valid.ref); ++ goto undo_map_out; ++ } ++ ++ /* Record the grant handle, for use in the unmap ++ * operation. ++ */ ++ private_data->grants[slot_index+i].u. ++ valid.user_handle = op.handle; ++ ++ /* Update p2m structure with the new mapping. */ ++ set_phys_to_machine(__pa(kernel_vaddr) >> PAGE_SHIFT, ++ FOREIGN_FRAME(private_data-> ++ grants[slot_index+i] ++ .u.valid.dev_bus_addr ++ >> PAGE_SHIFT)); ++ } else { ++ /* USING SHADOW PAGE TABLES. */ ++ /* In this case, we simply insert the page into the VM ++ * area. */ ++ ret = vm_insert_page(vma, user_vaddr, page); ++ } ++ ++ } ++ ++ up_write(&private_data->grants_sem); ++ return 0; ++ ++undo_map_out: ++ /* If we have a mapping failure, the unmapping will be taken care of ++ * by do_mmap_pgoff(), which will eventually call gntdev_clear_pte(). ++ * All we need to do here is free the vma_private_data. ++ */ ++ kfree(vma->vm_private_data); ++ ++ /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file ++ * to NULL on failure. However, we need this in gntdev_clear_pte() to ++ * unmap the grants. Therefore, we smuggle a reference to the file's ++ * private data in the VM area's private data pointer. ++ */ ++ vma->vm_private_data = private_data; ++ ++ up_write(&private_data->grants_sem); ++ ++ return -ENOMEM; ++} ++ ++static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr, ++ pte_t *ptep, int is_fullmm) ++{ ++ int slot_index, ret; ++ pte_t copy; ++ struct gnttab_unmap_grant_ref op; ++ gntdev_file_private_data_t *private_data; ++ ++ /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file ++ * to NULL on failure. However, we need this in gntdev_clear_pte() to ++ * unmap the grants. Therefore, we smuggle a reference to the file's ++ * private data in the VM area's private data pointer. ++ */ ++ if (vma->vm_file) { ++ private_data = (gntdev_file_private_data_t *) ++ vma->vm_file->private_data; ++ } else if (vma->vm_private_data) { ++ private_data = (gntdev_file_private_data_t *) ++ vma->vm_private_data; ++ } else { ++ private_data = NULL; /* gcc warning */ ++ BUG(); ++ } ++ ++ /* Copy the existing value of the PTE for returning. */ ++ copy = *ptep; ++ ++ /* Calculate the grant relating to this PTE. */ ++ slot_index = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT); ++ ++ /* Only unmap grants if the slot has been mapped. This could be being ++ * called from a failing mmap(). ++ */ ++ if (private_data->grants[slot_index].state == GNTDEV_SLOT_MAPPED) { ++ ++ /* First, we clear the user space mapping, if it has been made. ++ */ ++ if (private_data->grants[slot_index].u.valid.user_handle != ++ GNTDEV_INVALID_HANDLE && ++ !xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* NOT USING SHADOW PAGE TABLES. */ ++ gnttab_set_unmap_op(&op, virt_to_machine(ptep), ++ GNTMAP_contains_pte, ++ private_data->grants[slot_index] ++ .u.valid.user_handle); ++ ret = HYPERVISOR_grant_table_op( ++ GNTTABOP_unmap_grant_ref, &op, 1); ++ BUG_ON(ret); ++ if (op.status) ++ printk("User unmap grant status = %d\n", ++ op.status); ++ } else { ++ /* USING SHADOW PAGE TABLES. */ ++ pte_clear_not_present_full(vma->vm_mm, addr, ptep, is_fullmm); ++ } ++ ++ /* Finally, we unmap the grant from kernel space. */ ++ gnttab_set_unmap_op(&op, ++ get_kernel_vaddr(private_data, slot_index), ++ GNTMAP_host_map, ++ private_data->grants[slot_index].u.valid ++ .kernel_handle); ++ ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ++ &op, 1); ++ BUG_ON(ret); ++ if (op.status) ++ printk("Kernel unmap grant status = %d\n", op.status); ++ ++ ++ /* Return slot to the not-yet-mapped state, so that it may be ++ * mapped again, or removed by a subsequent ioctl. ++ */ ++ private_data->grants[slot_index].state = ++ GNTDEV_SLOT_NOT_YET_MAPPED; ++ ++ /* Invalidate the physical to machine mapping for this page. */ ++ set_phys_to_machine(__pa(get_kernel_vaddr(private_data, ++ slot_index)) ++ >> PAGE_SHIFT, INVALID_P2M_ENTRY); ++ ++ } else { ++ pte_clear_not_present_full(vma->vm_mm, addr, ptep, is_fullmm); ++ } ++ ++ return copy; ++} ++ ++/* "Destructor" for a VM area. ++ */ ++static void gntdev_vma_close(struct vm_area_struct *vma) { ++ if (vma->vm_private_data) { ++ kfree(vma->vm_private_data); ++ } ++} ++ ++/* Called when an ioctl is made on the device. ++ */ ++static int gntdev_ioctl(struct inode *inode, struct file *flip, ++ unsigned int cmd, unsigned long arg) ++{ ++ int rc = 0; ++ gntdev_file_private_data_t *private_data = ++ (gntdev_file_private_data_t *) flip->private_data; ++ ++ switch (cmd) { ++ case IOCTL_GNTDEV_MAP_GRANT_REF: ++ { ++ struct ioctl_gntdev_map_grant_ref op; ++ down_write(&private_data->grants_sem); ++ down_write(&private_data->free_list_sem); ++ ++ if ((rc = copy_from_user(&op, (void __user *) arg, ++ sizeof(op)))) { ++ rc = -EFAULT; ++ goto map_out; ++ } ++ if (unlikely(op.count <= 0)) { ++ rc = -EINVAL; ++ goto map_out; ++ } ++ ++ if (op.count == 1) { ++ if ((rc = add_grant_reference(flip, &op.refs[0], ++ &op.index)) < 0) { ++ printk(KERN_ERR "Adding grant reference " ++ "failed (%d).\n", rc); ++ goto map_out; ++ } ++ } else { ++ struct ioctl_gntdev_grant_ref *refs, *u; ++ refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL); ++ if (!refs) { ++ rc = -ENOMEM; ++ goto map_out; ++ } ++ u = ((struct ioctl_gntdev_map_grant_ref *)arg)->refs; ++ if ((rc = copy_from_user(refs, ++ (void __user *)u, ++ sizeof(*refs) * op.count))) { ++ printk(KERN_ERR "Copying refs from user failed" ++ " (%d).\n", rc); ++ rc = -EINVAL; ++ goto map_out; ++ } ++ if ((rc = find_contiguous_free_range(flip, op.count)) ++ < 0) { ++ printk(KERN_ERR "Finding contiguous range " ++ "failed (%d).\n", rc); ++ kfree(refs); ++ goto map_out; ++ } ++ op.index = rc << PAGE_SHIFT; ++ if ((rc = add_grant_references(flip, op.count, ++ refs, rc))) { ++ printk(KERN_ERR "Adding grant references " ++ "failed (%d).\n", rc); ++ kfree(refs); ++ goto map_out; ++ } ++ compress_free_list(flip); ++ kfree(refs); ++ } ++ if ((rc = copy_to_user((void __user *) arg, ++ &op, ++ sizeof(op)))) { ++ printk(KERN_ERR "Copying result back to user failed " ++ "(%d)\n", rc); ++ rc = -EFAULT; ++ goto map_out; ++ } ++ map_out: ++ up_write(&private_data->grants_sem); ++ up_write(&private_data->free_list_sem); ++ return rc; ++ } ++ case IOCTL_GNTDEV_UNMAP_GRANT_REF: ++ { ++ struct ioctl_gntdev_unmap_grant_ref op; ++ int i, start_index; ++ ++ down_write(&private_data->grants_sem); ++ down_write(&private_data->free_list_sem); ++ ++ if ((rc = copy_from_user(&op, ++ (void __user *) arg, ++ sizeof(op)))) { ++ rc = -EFAULT; ++ goto unmap_out; ++ } ++ ++ start_index = op.index >> PAGE_SHIFT; ++ ++ /* First, check that all pages are in the NOT_YET_MAPPED ++ * state. ++ */ ++ for (i = 0; i < op.count; ++i) { ++ if (unlikely ++ (private_data->grants[start_index + i].state ++ != GNTDEV_SLOT_NOT_YET_MAPPED)) { ++ if (private_data->grants[start_index + i].state ++ == GNTDEV_SLOT_INVALID) { ++ printk(KERN_ERR ++ "Tried to remove an invalid " ++ "grant at offset 0x%x.", ++ (start_index + i) ++ << PAGE_SHIFT); ++ rc = -EINVAL; ++ } else { ++ printk(KERN_ERR ++ "Tried to remove a grant which " ++ "is currently mmap()-ed at " ++ "offset 0x%x.", ++ (start_index + i) ++ << PAGE_SHIFT); ++ rc = -EBUSY; ++ } ++ goto unmap_out; ++ } ++ } ++ ++ /* Unmap pages and add them to the free list. ++ */ ++ for (i = 0; i < op.count; ++i) { ++ private_data->grants[start_index+i].state = ++ GNTDEV_SLOT_INVALID; ++ private_data->grants[start_index+i].u.free_list_index = ++ private_data->free_list_size; ++ private_data->free_list[private_data->free_list_size] = ++ start_index + i; ++ ++private_data->free_list_size; ++ } ++ compress_free_list(flip); ++ ++ unmap_out: ++ up_write(&private_data->grants_sem); ++ up_write(&private_data->free_list_sem); ++ return rc; ++ } ++ case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR: ++ { ++ struct ioctl_gntdev_get_offset_for_vaddr op; ++ struct vm_area_struct *vma; ++ unsigned long vaddr; ++ ++ if ((rc = copy_from_user(&op, ++ (void __user *) arg, ++ sizeof(op)))) { ++ rc = -EFAULT; ++ goto get_offset_out; ++ } ++ vaddr = (unsigned long)op.vaddr; ++ ++ down_read(¤t->mm->mmap_sem); ++ vma = find_vma(current->mm, vaddr); ++ if (vma == NULL) { ++ rc = -EFAULT; ++ goto get_offset_unlock_out; ++ } ++ if ((!vma->vm_ops) || (vma->vm_ops != &gntdev_vmops)) { ++ printk(KERN_ERR "The vaddr specified does not belong " ++ "to a gntdev instance: %#lx\n", vaddr); ++ rc = -EFAULT; ++ goto get_offset_unlock_out; ++ } ++ if (vma->vm_start != vaddr) { ++ printk(KERN_ERR "The vaddr specified in an " ++ "IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR must be at " ++ "the start of the VM area. vma->vm_start = " ++ "%#lx; vaddr = %#lx\n", ++ vma->vm_start, vaddr); ++ rc = -EFAULT; ++ goto get_offset_unlock_out; ++ } ++ op.offset = vma->vm_pgoff << PAGE_SHIFT; ++ op.count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ up_read(¤t->mm->mmap_sem); ++ if ((rc = copy_to_user((void __user *) arg, ++ &op, ++ sizeof(op)))) { ++ rc = -EFAULT; ++ goto get_offset_out; ++ } ++ goto get_offset_out; ++ get_offset_unlock_out: ++ up_read(¤t->mm->mmap_sem); ++ get_offset_out: ++ return rc; ++ } ++ default: ++ return -ENOIOCTLCMD; ++ } ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o ++obj-$(CONFIG_XEN_NETDEV_LOOPBACK) += netloop.o ++ ++netbk-y := netback.o xenbus.o interface.o ++netloop-y := loopback.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/common.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/common.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,157 @@ ++/****************************************************************************** ++ * arch/xen/drivers/netif/backend/common.h ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __NETIF__BACKEND__COMMON_H__ ++#define __NETIF__BACKEND__COMMON_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/ip.h> ++#include <linux/in.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/wait.h> ++#include <xen/evtchn.h> ++#include <xen/interface/io/netif.h> ++#include <asm/io.h> ++#include <asm/pgalloc.h> ++#include <xen/interface/grant_table.h> ++#include <xen/gnttab.h> ++#include <xen/driver_util.h> ++ ++#define DPRINTK(_f, _a...) \ ++ pr_debug("(file=%s, line=%d) " _f, \ ++ __FILE__ , __LINE__ , ## _a ) ++#define IPRINTK(fmt, args...) \ ++ printk(KERN_INFO "xen_net: " fmt, ##args) ++#define WPRINTK(fmt, args...) \ ++ printk(KERN_WARNING "xen_net: " fmt, ##args) ++ ++typedef struct netif_st { ++ /* Unique identifier for this interface. */ ++ domid_t domid; ++ unsigned int handle; ++ ++ u8 fe_dev_addr[6]; ++ ++ /* Physical parameters of the comms window. */ ++ grant_handle_t tx_shmem_handle; ++ grant_ref_t tx_shmem_ref; ++ grant_handle_t rx_shmem_handle; ++ grant_ref_t rx_shmem_ref; ++ unsigned int irq; ++ ++ /* The shared rings and indexes. */ ++ netif_tx_back_ring_t tx; ++ netif_rx_back_ring_t rx; ++ struct vm_struct *tx_comms_area; ++ struct vm_struct *rx_comms_area; ++ ++ /* Set of features that can be turned on in dev->features. */ ++ int features; ++ ++ /* Internal feature information. */ ++ int can_queue:1; /* can queue packets for receiver? */ ++ int copying_receiver:1; /* copy packets to receiver? */ ++ ++ /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */ ++ RING_IDX rx_req_cons_peek; ++ ++ /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ ++ unsigned long credit_bytes; ++ unsigned long credit_usec; ++ unsigned long remaining_credit; ++ struct timer_list credit_timeout; ++ ++ /* Enforce draining of the transmit queue. */ ++ struct timer_list tx_queue_timeout; ++ ++ /* Miscellaneous private stuff. */ ++ struct list_head list; /* scheduling list */ ++ atomic_t refcnt; ++ struct net_device *dev; ++ struct net_device_stats stats; ++ ++ unsigned int carrier; ++ ++ wait_queue_head_t waiting_to_free; ++} netif_t; ++ ++/* ++ * Implement our own carrier flag: the network stack's version causes delays ++ * when the carrier is re-enabled (in particular, dev_activate() may not ++ * immediately be called, which can cause packet loss; also the etherbridge ++ * can be rather lazy in activating its port). ++ */ ++#define netback_carrier_on(netif) ((netif)->carrier = 1) ++#define netback_carrier_off(netif) ((netif)->carrier = 0) ++#define netback_carrier_ok(netif) ((netif)->carrier) ++ ++#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) ++#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) ++ ++void netif_disconnect(netif_t *netif); ++ ++netif_t *netif_alloc(domid_t domid, unsigned int handle); ++int netif_map(netif_t *netif, unsigned long tx_ring_ref, ++ unsigned long rx_ring_ref, unsigned int evtchn); ++ ++#define netif_get(_b) (atomic_inc(&(_b)->refcnt)) ++#define netif_put(_b) \ ++ do { \ ++ if ( atomic_dec_and_test(&(_b)->refcnt) ) \ ++ wake_up(&(_b)->waiting_to_free); \ ++ } while (0) ++ ++void netif_xenbus_init(void); ++ ++#define netif_schedulable(netif) \ ++ (netif_running((netif)->dev) && netback_carrier_ok(netif)) ++ ++void netif_schedule_work(netif_t *netif); ++void netif_deschedule_work(netif_t *netif); ++ ++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev); ++struct net_device_stats *netif_be_get_stats(struct net_device *dev); ++irqreturn_t netif_be_int(int irq, void *dev_id); ++ ++static inline int netbk_can_queue(struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ return netif->can_queue; ++} ++ ++static inline int netbk_can_sg(struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ return netif->features & NETIF_F_SG; ++} ++ ++#endif /* __NETIF__BACKEND__COMMON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/interface.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/interface.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,336 @@ ++/****************************************************************************** ++ * arch/xen/drivers/netif/backend/interface.c ++ * ++ * Network-device interface management. ++ * ++ * Copyright (c) 2004-2005, Keir Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "common.h" ++#include <linux/ethtool.h> ++#include <linux/rtnetlink.h> ++ ++/* ++ * Module parameter 'queue_length': ++ * ++ * Enables queuing in the network stack when a client has run out of receive ++ * descriptors. Although this feature can improve receive bandwidth by avoiding ++ * packet loss, it can also result in packets sitting in the 'tx_queue' for ++ * unbounded time. This is bad if those packets hold onto foreign resources. ++ * For example, consider a packet that holds onto resources belonging to the ++ * guest for which it is queued (e.g., packet received on vif1.0, destined for ++ * vif1.1 which is not activated in the guest): in this situation the guest ++ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we ++ * run a timer (tx_queue_timeout) to drain the queue when the interface is ++ * blocked. ++ */ ++static unsigned long netbk_queue_length = 32; ++module_param_named(queue_length, netbk_queue_length, ulong, 0); ++ ++static void __netif_up(netif_t *netif) ++{ ++ enable_irq(netif->irq); ++ netif_schedule_work(netif); ++} ++ ++static void __netif_down(netif_t *netif) ++{ ++ disable_irq(netif->irq); ++ netif_deschedule_work(netif); ++} ++ ++static int net_open(struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ if (netback_carrier_ok(netif)) { ++ __netif_up(netif); ++ netif_start_queue(dev); ++ } ++ return 0; ++} ++ ++static int net_close(struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ if (netback_carrier_ok(netif)) ++ __netif_down(netif); ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++static int netbk_change_mtu(struct net_device *dev, int mtu) ++{ ++ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN; ++ ++ if (mtu > max) ++ return -EINVAL; ++ dev->mtu = mtu; ++ return 0; ++} ++ ++static int netbk_set_sg(struct net_device *dev, u32 data) ++{ ++ if (data) { ++ netif_t *netif = netdev_priv(dev); ++ ++ if (!(netif->features & NETIF_F_SG)) ++ return -ENOSYS; ++ } ++ ++ return ethtool_op_set_sg(dev, data); ++} ++ ++static int netbk_set_tso(struct net_device *dev, u32 data) ++{ ++ if (data) { ++ netif_t *netif = netdev_priv(dev); ++ ++ if (!(netif->features & NETIF_F_TSO)) ++ return -ENOSYS; ++ } ++ ++ return ethtool_op_set_tso(dev, data); ++} ++ ++static struct ethtool_ops network_ethtool_ops = ++{ ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = ethtool_op_set_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = netbk_set_sg, ++ .get_tso = ethtool_op_get_tso, ++ .set_tso = netbk_set_tso, ++ .get_link = ethtool_op_get_link, ++}; ++ ++netif_t *netif_alloc(domid_t domid, unsigned int handle) ++{ ++ int err = 0; ++ struct net_device *dev; ++ netif_t *netif; ++ char name[IFNAMSIZ] = {}; ++ ++ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); ++ dev = alloc_netdev(sizeof(netif_t), name, ether_setup); ++ if (dev == NULL) { ++ DPRINTK("Could not create netif: out of memory\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ netif = netdev_priv(dev); ++ memset(netif, 0, sizeof(*netif)); ++ netif->domid = domid; ++ netif->handle = handle; ++ atomic_set(&netif->refcnt, 1); ++ init_waitqueue_head(&netif->waiting_to_free); ++ netif->dev = dev; ++ ++ netback_carrier_off(netif); ++ ++ netif->credit_bytes = netif->remaining_credit = ~0UL; ++ netif->credit_usec = 0UL; ++ init_timer(&netif->credit_timeout); ++ /* Initialize 'expires' now: it's used to track the credit window. */ ++ netif->credit_timeout.expires = jiffies; ++ ++ init_timer(&netif->tx_queue_timeout); ++ ++ dev->hard_start_xmit = netif_be_start_xmit; ++ dev->get_stats = netif_be_get_stats; ++ dev->open = net_open; ++ dev->stop = net_close; ++ dev->change_mtu = netbk_change_mtu; ++ dev->features = NETIF_F_IP_CSUM; ++ ++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops); ++ ++ dev->tx_queue_len = netbk_queue_length; ++ ++ /* ++ * Initialise a dummy MAC address. We choose the numerically ++ * largest non-broadcast address to prevent the address getting ++ * stolen by an Ethernet bridge for STP purposes. ++ * (FE:FF:FF:FF:FF:FF) ++ */ ++ memset(dev->dev_addr, 0xFF, ETH_ALEN); ++ dev->dev_addr[0] &= ~0x01; ++ ++ rtnl_lock(); ++ err = register_netdevice(dev); ++ rtnl_unlock(); ++ if (err) { ++ DPRINTK("Could not register new net device %s: err=%d\n", ++ dev->name, err); ++ free_netdev(dev); ++ return ERR_PTR(err); ++ } ++ ++ DPRINTK("Successfully created netif\n"); ++ return netif; ++} ++ ++static int map_frontend_pages( ++ netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref) ++{ ++ struct gnttab_map_grant_ref op; ++ ++ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr, ++ GNTMAP_host_map, tx_ring_ref, netif->domid); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status) { ++ DPRINTK(" Gnttab failure mapping tx_ring_ref!\n"); ++ return op.status; ++ } ++ ++ netif->tx_shmem_ref = tx_ring_ref; ++ netif->tx_shmem_handle = op.handle; ++ ++ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr, ++ GNTMAP_host_map, rx_ring_ref, netif->domid); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status) { ++ DPRINTK(" Gnttab failure mapping rx_ring_ref!\n"); ++ return op.status; ++ } ++ ++ netif->rx_shmem_ref = rx_ring_ref; ++ netif->rx_shmem_handle = op.handle; ++ ++ return 0; ++} ++ ++static void unmap_frontend_pages(netif_t *netif) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr, ++ GNTMAP_host_map, netif->tx_shmem_handle); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++ ++ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr, ++ GNTMAP_host_map, netif->rx_shmem_handle); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++} ++ ++int netif_map(netif_t *netif, unsigned long tx_ring_ref, ++ unsigned long rx_ring_ref, unsigned int evtchn) ++{ ++ int err = -ENOMEM; ++ netif_tx_sring_t *txs; ++ netif_rx_sring_t *rxs; ++ ++ /* Already connected through? */ ++ if (netif->irq) ++ return 0; ++ ++ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE); ++ if (netif->tx_comms_area == NULL) ++ return -ENOMEM; ++ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE); ++ if (netif->rx_comms_area == NULL) ++ goto err_rx; ++ ++ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref); ++ if (err) ++ goto err_map; ++ ++ err = bind_interdomain_evtchn_to_irqhandler( ++ netif->domid, evtchn, netif_be_int, 0, ++ netif->dev->name, netif); ++ if (err < 0) ++ goto err_hypervisor; ++ netif->irq = err; ++ disable_irq(netif->irq); ++ ++ txs = (netif_tx_sring_t *)netif->tx_comms_area->addr; ++ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE); ++ ++ rxs = (netif_rx_sring_t *) ++ ((char *)netif->rx_comms_area->addr); ++ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE); ++ ++ netif->rx_req_cons_peek = 0; ++ ++ netif_get(netif); ++ ++ rtnl_lock(); ++ netback_carrier_on(netif); ++ if (netif_running(netif->dev)) ++ __netif_up(netif); ++ rtnl_unlock(); ++ ++ return 0; ++err_hypervisor: ++ unmap_frontend_pages(netif); ++err_map: ++ free_vm_area(netif->rx_comms_area); ++err_rx: ++ free_vm_area(netif->tx_comms_area); ++ return err; ++} ++ ++void netif_disconnect(netif_t *netif) ++{ ++ if (netback_carrier_ok(netif)) { ++ rtnl_lock(); ++ netback_carrier_off(netif); ++ netif_carrier_off(netif->dev); /* discard queued packets */ ++ if (netif_running(netif->dev)) ++ __netif_down(netif); ++ rtnl_unlock(); ++ netif_put(netif); ++ } ++ ++ atomic_dec(&netif->refcnt); ++ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0); ++ ++ del_timer_sync(&netif->credit_timeout); ++ del_timer_sync(&netif->tx_queue_timeout); ++ ++ if (netif->irq) ++ unbind_from_irqhandler(netif->irq, netif); ++ ++ unregister_netdev(netif->dev); ++ ++ if (netif->tx.sring) { ++ unmap_frontend_pages(netif); ++ free_vm_area(netif->tx_comms_area); ++ free_vm_area(netif->rx_comms_area); ++ } ++ ++ free_netdev(netif->dev); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/loopback.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/loopback.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,322 @@ ++/****************************************************************************** ++ * netback/loopback.c ++ * ++ * A two-interface loopback device to emulate a local netfront-netback ++ * connection. This ensures that local packet delivery looks identical ++ * to inter-domain delivery. Most importantly, packets delivered locally ++ * originating from other domains will get *copied* when they traverse this ++ * driver. This prevents unbounded delays in socket-buffer queues from ++ * causing the netback driver to "seize up". ++ * ++ * This driver creates a symmetric pair of loopback interfaces with names ++ * vif0.0 and veth0. The intention is that 'vif0.0' is bound to an Ethernet ++ * bridge, just like a proper netback interface, while a local IP interface ++ * is configured on 'veth0'. ++ * ++ * As with a real netback interface, vif0.0 is configured with a suitable ++ * dummy MAC address. No default is provided for veth0: a reasonable strategy ++ * is to transfer eth0's MAC address to veth0, and give eth0 a dummy address ++ * (to avoid confusing the Etherbridge). ++ * ++ * Copyright (c) 2005 K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/module.h> ++#include <linux/netdevice.h> ++#include <linux/inetdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/ethtool.h> ++#include <net/dst.h> ++#include <net/xfrm.h> /* secpath_reset() */ ++#include <asm/hypervisor.h> /* is_initial_xendomain() */ ++ ++#include "../../../net/core/kmap_skb.h" ++ ++static int nloopbacks = -1; ++module_param(nloopbacks, int, 0); ++MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create"); ++ ++struct net_private { ++ struct net_device *loopback_dev; ++ struct net_device_stats stats; ++}; ++ ++static int loopback_open(struct net_device *dev) ++{ ++ struct net_private *np = netdev_priv(dev); ++ memset(&np->stats, 0, sizeof(np->stats)); ++ netif_start_queue(dev); ++ return 0; ++} ++ ++static int loopback_close(struct net_device *dev) ++{ ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++#ifdef CONFIG_X86 ++static int is_foreign(unsigned long pfn) ++{ ++ /* NB. Play it safe for auto-translation mode. */ ++ return (xen_feature(XENFEAT_auto_translated_physmap) || ++ (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT)); ++} ++#else ++/* How to detect a foreign mapping? Play it safe. */ ++#define is_foreign(pfn) (1) ++#endif ++ ++static int skb_remove_foreign_references(struct sk_buff *skb) ++{ ++ struct page *page; ++ unsigned long pfn; ++ int i, off; ++ char *vaddr; ++ ++ BUG_ON(skb_shinfo(skb)->frag_list); ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page); ++ if (!is_foreign(pfn)) ++ continue; ++ ++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); ++ if (unlikely(!page)) ++ return 0; ++ ++ vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]); ++ off = skb_shinfo(skb)->frags[i].page_offset; ++ memcpy(page_address(page) + off, ++ vaddr + off, ++ skb_shinfo(skb)->frags[i].size); ++ kunmap_skb_frag(vaddr); ++ ++ put_page(skb_shinfo(skb)->frags[i].page); ++ skb_shinfo(skb)->frags[i].page = page; ++ } ++ ++ return 1; ++} ++ ++static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct net_private *np = netdev_priv(dev); ++ ++ if (!skb_remove_foreign_references(skb)) { ++ np->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ dst_release(skb->dst); ++ skb->dst = NULL; ++ ++ skb_orphan(skb); ++ ++ np->stats.tx_bytes += skb->len; ++ np->stats.tx_packets++; ++ ++ /* Switch to loopback context. */ ++ dev = np->loopback_dev; ++ np = netdev_priv(dev); ++ ++ np->stats.rx_bytes += skb->len; ++ np->stats.rx_packets++; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ /* Defer checksum calculation. */ ++ skb->proto_csum_blank = 1; ++ /* Must be a local packet: assert its integrity. */ ++ skb->proto_data_valid = 1; ++ } ++ ++ skb->ip_summed = skb->proto_data_valid ? ++ CHECKSUM_UNNECESSARY : CHECKSUM_NONE; ++ ++ skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */ ++ skb->protocol = eth_type_trans(skb, dev); ++ skb->dev = dev; ++ dev->last_rx = jiffies; ++ ++ /* Flush netfilter context: rx'ed skbuffs not expected to have any. */ ++ nf_reset(skb); ++ secpath_reset(skb); ++ ++ netif_rx(skb); ++ ++ return 0; ++} ++ ++static struct net_device_stats *loopback_get_stats(struct net_device *dev) ++{ ++ struct net_private *np = netdev_priv(dev); ++ return &np->stats; ++} ++ ++static struct ethtool_ops network_ethtool_ops = ++{ ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = ethtool_op_set_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = ethtool_op_set_sg, ++ .get_tso = ethtool_op_get_tso, ++ .set_tso = ethtool_op_set_tso, ++ .get_link = ethtool_op_get_link, ++}; ++ ++/* ++ * Nothing to do here. Virtual interface is point-to-point and the ++ * physical interface is probably promiscuous anyway. ++ */ ++static void loopback_set_multicast_list(struct net_device *dev) ++{ ++} ++ ++static void loopback_construct(struct net_device *dev, struct net_device *lo) ++{ ++ struct net_private *np = netdev_priv(dev); ++ ++ np->loopback_dev = lo; ++ ++ dev->open = loopback_open; ++ dev->stop = loopback_close; ++ dev->hard_start_xmit = loopback_start_xmit; ++ dev->get_stats = loopback_get_stats; ++ dev->set_multicast_list = loopback_set_multicast_list; ++ dev->change_mtu = NULL; /* allow arbitrary mtu */ ++ ++ dev->tx_queue_len = 0; ++ ++ dev->features = (NETIF_F_HIGHDMA | ++ NETIF_F_LLTX | ++ NETIF_F_TSO | ++ NETIF_F_SG | ++ NETIF_F_IP_CSUM); ++ ++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops); ++ ++ /* ++ * We do not set a jumbo MTU on the interface. Otherwise the network ++ * stack will try to send large packets that will get dropped by the ++ * Ethernet bridge (unless the physical Ethernet interface is ++ * configured to transfer jumbo packets). If a larger MTU is desired ++ * then the system administrator can specify it using the 'ifconfig' ++ * command. ++ */ ++ /*dev->mtu = 16*1024;*/ ++} ++ ++static int __init make_loopback(int i) ++{ ++ struct net_device *dev1, *dev2; ++ char dev_name[IFNAMSIZ]; ++ int err = -ENOMEM; ++ ++ sprintf(dev_name, "vif0.%d", i); ++ dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup); ++ if (!dev1) ++ return err; ++ ++ sprintf(dev_name, "veth%d", i); ++ dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup); ++ if (!dev2) ++ goto fail_netdev2; ++ ++ loopback_construct(dev1, dev2); ++ loopback_construct(dev2, dev1); ++ ++ /* ++ * Initialise a dummy MAC address for the 'dummy backend' interface. We ++ * choose the numerically largest non-broadcast address to prevent the ++ * address getting stolen by an Ethernet bridge for STP purposes. ++ */ ++ memset(dev1->dev_addr, 0xFF, ETH_ALEN); ++ dev1->dev_addr[0] &= ~0x01; ++ ++ if ((err = register_netdev(dev1)) != 0) ++ goto fail; ++ ++ if ((err = register_netdev(dev2)) != 0) { ++ unregister_netdev(dev1); ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ free_netdev(dev2); ++ fail_netdev2: ++ free_netdev(dev1); ++ return err; ++} ++ ++static void __exit clean_loopback(int i) ++{ ++ struct net_device *dev1, *dev2; ++ char dev_name[IFNAMSIZ]; ++ ++ sprintf(dev_name, "vif0.%d", i); ++ dev1 = dev_get_by_name(dev_name); ++ sprintf(dev_name, "veth%d", i); ++ dev2 = dev_get_by_name(dev_name); ++ if (dev1 && dev2) { ++ unregister_netdev(dev2); ++ unregister_netdev(dev1); ++ free_netdev(dev2); ++ free_netdev(dev1); ++ } ++} ++ ++static int __init loopback_init(void) ++{ ++ int i, err = 0; ++ ++ if (nloopbacks == -1) ++ nloopbacks = is_initial_xendomain() ? 4 : 0; ++ ++ for (i = 0; i < nloopbacks; i++) ++ if ((err = make_loopback(i)) != 0) ++ break; ++ ++ return err; ++} ++ ++module_init(loopback_init); ++ ++static void __exit loopback_exit(void) ++{ ++ int i; ++ ++ for (i = nloopbacks; i-- > 0; ) ++ clean_loopback(i); ++} ++ ++module_exit(loopback_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/netback.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/netback.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1496 @@ ++/****************************************************************************** ++ * drivers/xen/netback/netback.c ++ * ++ * Back-end of the driver for virtual network devices. This portion of the ++ * driver exports a 'unified' network-device interface that can be accessed ++ * by any operating system that implements a compatible front end. A ++ * reference front-end implementation can be found in: ++ * drivers/xen/netfront/netfront.c ++ * ++ * Copyright (c) 2002-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "common.h" ++#include <xen/balloon.h> ++#include <xen/interface/memory.h> ++ ++/*define NETBE_DEBUG_INTERRUPT*/ ++ ++/* extra field used in struct page */ ++#define netif_page_index(pg) (*(long *)&(pg)->mapping) ++ ++struct netbk_rx_meta { ++ skb_frag_t frag; ++ int id; ++ int copy:1; ++}; ++ ++static void netif_idx_release(u16 pending_idx); ++static void netif_page_release(struct page *page); ++static void make_tx_response(netif_t *netif, ++ netif_tx_request_t *txp, ++ s8 st); ++static netif_rx_response_t *make_rx_response(netif_t *netif, ++ u16 id, ++ s8 st, ++ u16 offset, ++ u16 size, ++ u16 flags); ++ ++static void net_tx_action(unsigned long unused); ++static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); ++ ++static void net_rx_action(unsigned long unused); ++static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0); ++ ++static struct timer_list net_timer; ++ ++#define MAX_PENDING_REQS 256 ++ ++static struct sk_buff_head rx_queue; ++ ++static struct page **mmap_pages; ++static inline unsigned long idx_to_kaddr(unsigned int idx) ++{ ++ return (unsigned long)pfn_to_kaddr(page_to_pfn(mmap_pages[idx])); ++} ++ ++#define PKT_PROT_LEN 64 ++ ++static struct pending_tx_info { ++ netif_tx_request_t req; ++ netif_t *netif; ++} pending_tx_info[MAX_PENDING_REQS]; ++static u16 pending_ring[MAX_PENDING_REQS]; ++typedef unsigned int PEND_RING_IDX; ++#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) ++static PEND_RING_IDX pending_prod, pending_cons; ++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) ++ ++/* Freed TX SKBs get batched on this ring before return to pending_ring. */ ++static u16 dealloc_ring[MAX_PENDING_REQS]; ++static PEND_RING_IDX dealloc_prod, dealloc_cons; ++ ++static struct sk_buff_head tx_queue; ++ ++static grant_handle_t grant_tx_handle[MAX_PENDING_REQS]; ++static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS]; ++static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS]; ++ ++static struct list_head net_schedule_list; ++static spinlock_t net_schedule_list_lock; ++ ++#define MAX_MFN_ALLOC 64 ++static unsigned long mfn_list[MAX_MFN_ALLOC]; ++static unsigned int alloc_index = 0; ++ ++static inline unsigned long alloc_mfn(void) ++{ ++ BUG_ON(alloc_index == 0); ++ return mfn_list[--alloc_index]; ++} ++ ++static int check_mfn(int nr) ++{ ++ struct xen_memory_reservation reservation = { ++ .extent_order = 0, ++ .domid = DOMID_SELF ++ }; ++ ++ if (likely(alloc_index >= nr)) ++ return 0; ++ ++ set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index); ++ reservation.nr_extents = MAX_MFN_ALLOC - alloc_index; ++ alloc_index += HYPERVISOR_memory_op(XENMEM_increase_reservation, ++ &reservation); ++ ++ return alloc_index >= nr ? 0 : -ENOMEM; ++} ++ ++static inline void maybe_schedule_tx_action(void) ++{ ++ smp_mb(); ++ if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && ++ !list_empty(&net_schedule_list)) ++ tasklet_schedule(&net_tx_tasklet); ++} ++ ++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb) ++{ ++ struct skb_shared_info *ninfo; ++ struct sk_buff *nskb; ++ unsigned long offset; ++ int ret; ++ int len; ++ int headlen; ++ ++ BUG_ON(skb_shinfo(skb)->frag_list != NULL); ++ ++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN); ++ if (unlikely(!nskb)) ++ goto err; ++ ++ skb_reserve(nskb, 16 + NET_IP_ALIGN); ++ headlen = nskb->end - nskb->data; ++ if (headlen > skb_headlen(skb)) ++ headlen = skb_headlen(skb); ++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen); ++ BUG_ON(ret); ++ ++ ninfo = skb_shinfo(nskb); ++ ninfo->gso_size = skb_shinfo(skb)->gso_size; ++ ninfo->gso_type = skb_shinfo(skb)->gso_type; ++ ++ offset = headlen; ++ len = skb->len - headlen; ++ ++ nskb->len = skb->len; ++ nskb->data_len = len; ++ nskb->truesize += len; ++ ++ while (len) { ++ struct page *page; ++ int copy; ++ int zero; ++ ++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) { ++ dump_stack(); ++ goto err_free; ++ } ++ ++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len; ++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO; ++ ++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero); ++ if (unlikely(!page)) ++ goto err_free; ++ ++ ret = skb_copy_bits(skb, offset, page_address(page), copy); ++ BUG_ON(ret); ++ ++ ninfo->frags[ninfo->nr_frags].page = page; ++ ninfo->frags[ninfo->nr_frags].page_offset = 0; ++ ninfo->frags[ninfo->nr_frags].size = copy; ++ ninfo->nr_frags++; ++ ++ offset += copy; ++ len -= copy; ++ } ++ ++ offset = nskb->data - skb->data; ++ ++ nskb->h.raw = skb->h.raw + offset; ++ nskb->nh.raw = skb->nh.raw + offset; ++ nskb->mac.raw = skb->mac.raw + offset; ++ ++ return nskb; ++ ++ err_free: ++ kfree_skb(nskb); ++ err: ++ return NULL; ++} ++ ++static inline int netbk_max_required_rx_slots(netif_t *netif) ++{ ++ if (netif->features & (NETIF_F_SG|NETIF_F_TSO)) ++ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */ ++ return 1; /* all in one */ ++} ++ ++static inline int netbk_queue_full(netif_t *netif) ++{ ++ RING_IDX peek = netif->rx_req_cons_peek; ++ RING_IDX needed = netbk_max_required_rx_slots(netif); ++ ++ return ((netif->rx.sring->req_prod - peek) < needed) || ++ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed); ++} ++ ++static void tx_queue_callback(unsigned long data) ++{ ++ netif_t *netif = (netif_t *)data; ++ if (netif_schedulable(netif)) ++ netif_wake_queue(netif->dev); ++} ++ ++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ ++ BUG_ON(skb->dev != dev); ++ ++ /* Drop the packet if the target domain has no receive buffers. */ ++ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif))) ++ goto drop; ++ ++ /* ++ * Copy the packet here if it's destined for a flipping interface ++ * but isn't flippable (e.g. extra references to data). ++ * XXX For now we also copy skbuffs whose head crosses a page ++ * boundary, because netbk_gop_skb can't handle them. ++ */ ++ if (!netif->copying_receiver || ++ ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) { ++ struct sk_buff *nskb = netbk_copy_skb(skb); ++ if ( unlikely(nskb == NULL) ) ++ goto drop; ++ /* Copy only the header fields we use in this driver. */ ++ nskb->dev = skb->dev; ++ nskb->ip_summed = skb->ip_summed; ++ nskb->proto_data_valid = skb->proto_data_valid; ++ dev_kfree_skb(skb); ++ skb = nskb; ++ } ++ ++ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 + ++ !!skb_shinfo(skb)->gso_size; ++ netif_get(netif); ++ ++ if (netbk_can_queue(dev) && netbk_queue_full(netif)) { ++ netif->rx.sring->req_event = netif->rx_req_cons_peek + ++ netbk_max_required_rx_slots(netif); ++ mb(); /* request notification /then/ check & stop the queue */ ++ if (netbk_queue_full(netif)) { ++ netif_stop_queue(dev); ++ /* ++ * Schedule 500ms timeout to restart the queue, thus ++ * ensuring that an inactive queue will be drained. ++ * Packets will be immediately be dropped until more ++ * receive buffers become available (see ++ * netbk_queue_full() check above). ++ */ ++ netif->tx_queue_timeout.data = (unsigned long)netif; ++ netif->tx_queue_timeout.function = tx_queue_callback; ++ __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2); ++ } ++ } ++ ++ skb_queue_tail(&rx_queue, skb); ++ tasklet_schedule(&net_rx_tasklet); ++ ++ return 0; ++ ++ drop: ++ netif->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++#if 0 ++static void xen_network_done_notify(void) ++{ ++ static struct net_device *eth0_dev = NULL; ++ if (unlikely(eth0_dev == NULL)) ++ eth0_dev = __dev_get_by_name("eth0"); ++ netif_rx_schedule(eth0_dev); ++} ++/* ++ * Add following to poll() function in NAPI driver (Tigon3 is example): ++ * if ( xen_network_done() ) ++ * tg3_enable_ints(tp); ++ */ ++int xen_network_done(void) ++{ ++ return skb_queue_empty(&rx_queue); ++} ++#endif ++ ++struct netrx_pending_operations { ++ unsigned trans_prod, trans_cons; ++ unsigned mmu_prod, mmu_cons; ++ unsigned mcl_prod, mcl_cons; ++ unsigned copy_prod, copy_cons; ++ unsigned meta_prod, meta_cons; ++ mmu_update_t *mmu; ++ gnttab_transfer_t *trans; ++ gnttab_copy_t *copy; ++ multicall_entry_t *mcl; ++ struct netbk_rx_meta *meta; ++}; ++ ++/* Set up the grant operations for this fragment. If it's a flipping ++ interface, we also set up the unmap request from here. */ ++static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta, ++ int i, struct netrx_pending_operations *npo, ++ struct page *page, unsigned long size, ++ unsigned long offset) ++{ ++ mmu_update_t *mmu; ++ gnttab_transfer_t *gop; ++ gnttab_copy_t *copy_gop; ++ multicall_entry_t *mcl; ++ netif_rx_request_t *req; ++ unsigned long old_mfn, new_mfn; ++ ++ old_mfn = virt_to_mfn(page_address(page)); ++ ++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i); ++ if (netif->copying_receiver) { ++ /* The fragment needs to be copied rather than ++ flipped. */ ++ meta->copy = 1; ++ copy_gop = npo->copy + npo->copy_prod++; ++ copy_gop->flags = GNTCOPY_dest_gref; ++ if (PageForeign(page)) { ++ struct pending_tx_info *src_pend = ++ &pending_tx_info[netif_page_index(page)]; ++ copy_gop->source.domid = src_pend->netif->domid; ++ copy_gop->source.u.ref = src_pend->req.gref; ++ copy_gop->flags |= GNTCOPY_source_gref; ++ } else { ++ copy_gop->source.domid = DOMID_SELF; ++ copy_gop->source.u.gmfn = old_mfn; ++ } ++ copy_gop->source.offset = offset; ++ copy_gop->dest.domid = netif->domid; ++ copy_gop->dest.offset = 0; ++ copy_gop->dest.u.ref = req->gref; ++ copy_gop->len = size; ++ } else { ++ meta->copy = 0; ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ new_mfn = alloc_mfn(); ++ ++ /* ++ * Set the new P2M table entry before ++ * reassigning the old data page. Heed the ++ * comment in pgtable-2level.h:pte_page(). :-) ++ */ ++ set_phys_to_machine(page_to_pfn(page), new_mfn); ++ ++ mcl = npo->mcl + npo->mcl_prod++; ++ MULTI_update_va_mapping(mcl, ++ (unsigned long)page_address(page), ++ pfn_pte_ma(new_mfn, PAGE_KERNEL), ++ 0); ++ ++ mmu = npo->mmu + npo->mmu_prod++; ++ mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) | ++ MMU_MACHPHYS_UPDATE; ++ mmu->val = page_to_pfn(page); ++ } ++ ++ gop = npo->trans + npo->trans_prod++; ++ gop->mfn = old_mfn; ++ gop->domid = netif->domid; ++ gop->ref = req->gref; ++ } ++ return req->id; ++} ++ ++static void netbk_gop_skb(struct sk_buff *skb, ++ struct netrx_pending_operations *npo) ++{ ++ netif_t *netif = netdev_priv(skb->dev); ++ int nr_frags = skb_shinfo(skb)->nr_frags; ++ int i; ++ int extra; ++ struct netbk_rx_meta *head_meta, *meta; ++ ++ head_meta = npo->meta + npo->meta_prod++; ++ head_meta->frag.page_offset = skb_shinfo(skb)->gso_type; ++ head_meta->frag.size = skb_shinfo(skb)->gso_size; ++ extra = !!head_meta->frag.size + 1; ++ ++ for (i = 0; i < nr_frags; i++) { ++ meta = npo->meta + npo->meta_prod++; ++ meta->frag = skb_shinfo(skb)->frags[i]; ++ meta->id = netbk_gop_frag(netif, meta, i + extra, npo, ++ meta->frag.page, ++ meta->frag.size, ++ meta->frag.page_offset); ++ } ++ ++ /* ++ * This must occur at the end to ensure that we don't trash skb_shinfo ++ * until we're done. We know that the head doesn't cross a page ++ * boundary because such packets get copied in netif_be_start_xmit. ++ */ ++ head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo, ++ virt_to_page(skb->data), ++ skb_headlen(skb), ++ offset_in_page(skb->data)); ++ ++ netif->rx.req_cons += nr_frags + extra; ++} ++ ++static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta) ++{ ++ int i; ++ ++ for (i = 0; i < nr_frags; i++) ++ put_page(meta[i].frag.page); ++} ++ ++/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was ++ used to set up the operations on the top of ++ netrx_pending_operations, which have since been done. Check that ++ they didn't give any errors and advance over them. */ ++static int netbk_check_gop(int nr_frags, domid_t domid, ++ struct netrx_pending_operations *npo) ++{ ++ multicall_entry_t *mcl; ++ gnttab_transfer_t *gop; ++ gnttab_copy_t *copy_op; ++ int status = NETIF_RSP_OKAY; ++ int i; ++ ++ for (i = 0; i <= nr_frags; i++) { ++ if (npo->meta[npo->meta_cons + i].copy) { ++ copy_op = npo->copy + npo->copy_cons++; ++ if (copy_op->status != GNTST_okay) { ++ DPRINTK("Bad status %d from copy to DOM%d.\n", ++ copy_op->status, domid); ++ status = NETIF_RSP_ERROR; ++ } ++ } else { ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ mcl = npo->mcl + npo->mcl_cons++; ++ /* The update_va_mapping() must not fail. */ ++ BUG_ON(mcl->result != 0); ++ } ++ ++ gop = npo->trans + npo->trans_cons++; ++ /* Check the reassignment error code. */ ++ if (gop->status != 0) { ++ DPRINTK("Bad status %d from grant transfer to DOM%u\n", ++ gop->status, domid); ++ /* ++ * Page no longer belongs to us unless ++ * GNTST_bad_page, but that should be ++ * a fatal error anyway. ++ */ ++ BUG_ON(gop->status == GNTST_bad_page); ++ status = NETIF_RSP_ERROR; ++ } ++ } ++ } ++ ++ return status; ++} ++ ++static void netbk_add_frag_responses(netif_t *netif, int status, ++ struct netbk_rx_meta *meta, int nr_frags) ++{ ++ int i; ++ unsigned long offset; ++ ++ for (i = 0; i < nr_frags; i++) { ++ int id = meta[i].id; ++ int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data; ++ ++ if (meta[i].copy) ++ offset = 0; ++ else ++ offset = meta[i].frag.page_offset; ++ make_rx_response(netif, id, status, offset, ++ meta[i].frag.size, flags); ++ } ++} ++ ++static void net_rx_action(unsigned long unused) ++{ ++ netif_t *netif = NULL; ++ s8 status; ++ u16 id, irq, flags; ++ netif_rx_response_t *resp; ++ multicall_entry_t *mcl; ++ struct sk_buff_head rxq; ++ struct sk_buff *skb; ++ int notify_nr = 0; ++ int ret; ++ int nr_frags; ++ int count; ++ unsigned long offset; ++ ++ /* ++ * Putting hundreds of bytes on the stack is considered rude. ++ * Static works because a tasklet can only be on one CPU at any time. ++ */ ++ static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3]; ++ static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; ++ static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE]; ++ static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE]; ++ static unsigned char rx_notify[NR_IRQS]; ++ static u16 notify_list[NET_RX_RING_SIZE]; ++ static struct netbk_rx_meta meta[NET_RX_RING_SIZE]; ++ ++ struct netrx_pending_operations npo = { ++ mmu: rx_mmu, ++ trans: grant_trans_op, ++ copy: grant_copy_op, ++ mcl: rx_mcl, ++ meta: meta}; ++ ++ skb_queue_head_init(&rxq); ++ ++ count = 0; ++ ++ while ((skb = skb_dequeue(&rx_queue)) != NULL) { ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ *(int *)skb->cb = nr_frags; ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap) && ++ !((netif_t *)netdev_priv(skb->dev))->copying_receiver && ++ check_mfn(nr_frags + 1)) { ++ /* Memory squeeze? Back off for an arbitrary while. */ ++ if ( net_ratelimit() ) ++ WPRINTK("Memory squeeze in netback " ++ "driver.\n"); ++ mod_timer(&net_timer, jiffies + HZ); ++ skb_queue_head(&rx_queue, skb); ++ break; ++ } ++ ++ netbk_gop_skb(skb, &npo); ++ ++ count += nr_frags + 1; ++ ++ __skb_queue_tail(&rxq, skb); ++ ++ /* Filled the batch queue? */ ++ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE) ++ break; ++ } ++ ++ if (npo.mcl_prod && ++ !xen_feature(XENFEAT_auto_translated_physmap)) { ++ mcl = npo.mcl + npo.mcl_prod++; ++ ++ BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping); ++ mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; ++ ++ mcl->op = __HYPERVISOR_mmu_update; ++ mcl->args[0] = (unsigned long)rx_mmu; ++ mcl->args[1] = npo.mmu_prod; ++ mcl->args[2] = 0; ++ mcl->args[3] = DOMID_SELF; ++ } ++ ++ if (npo.trans_prod) { ++ mcl = npo.mcl + npo.mcl_prod++; ++ mcl->op = __HYPERVISOR_grant_table_op; ++ mcl->args[0] = GNTTABOP_transfer; ++ mcl->args[1] = (unsigned long)grant_trans_op; ++ mcl->args[2] = npo.trans_prod; ++ } ++ ++ if (npo.copy_prod) { ++ mcl = npo.mcl + npo.mcl_prod++; ++ mcl->op = __HYPERVISOR_grant_table_op; ++ mcl->args[0] = GNTTABOP_copy; ++ mcl->args[1] = (unsigned long)grant_copy_op; ++ mcl->args[2] = npo.copy_prod; ++ } ++ ++ /* Nothing to do? */ ++ if (!npo.mcl_prod) ++ return; ++ ++ BUG_ON(npo.copy_prod > NET_RX_RING_SIZE); ++ BUG_ON(npo.mmu_prod > NET_RX_RING_SIZE); ++ BUG_ON(npo.trans_prod > NET_RX_RING_SIZE); ++ BUG_ON(npo.mcl_prod > NET_RX_RING_SIZE+3); ++ BUG_ON(npo.meta_prod > NET_RX_RING_SIZE); ++ ++ ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod); ++ BUG_ON(ret != 0); ++ ++ while ((skb = __skb_dequeue(&rxq)) != NULL) { ++ nr_frags = *(int *)skb->cb; ++ ++ netif = netdev_priv(skb->dev); ++ /* We can't rely on skb_release_data to release the ++ pages used by fragments for us, since it tries to ++ touch the pages in the fraglist. If we're in ++ flipping mode, that doesn't work. In copying mode, ++ we still have access to all of the pages, and so ++ it's safe to let release_data deal with it. */ ++ /* (Freeing the fragments is safe since we copy ++ non-linear skbs destined for flipping interfaces) */ ++ if (!netif->copying_receiver) { ++ atomic_set(&(skb_shinfo(skb)->dataref), 1); ++ skb_shinfo(skb)->frag_list = NULL; ++ skb_shinfo(skb)->nr_frags = 0; ++ netbk_free_pages(nr_frags, meta + npo.meta_cons + 1); ++ } ++ ++ netif->stats.tx_bytes += skb->len; ++ netif->stats.tx_packets++; ++ ++ status = netbk_check_gop(nr_frags, netif->domid, &npo); ++ ++ id = meta[npo.meta_cons].id; ++ flags = nr_frags ? NETRXF_more_data : 0; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ ++ flags |= NETRXF_csum_blank | NETRXF_data_validated; ++ else if (skb->proto_data_valid) /* remote but checksummed? */ ++ flags |= NETRXF_data_validated; ++ ++ if (meta[npo.meta_cons].copy) ++ offset = 0; ++ else ++ offset = offset_in_page(skb->data); ++ resp = make_rx_response(netif, id, status, offset, ++ skb_headlen(skb), flags); ++ ++ if (meta[npo.meta_cons].frag.size) { ++ struct netif_extra_info *gso = ++ (struct netif_extra_info *) ++ RING_GET_RESPONSE(&netif->rx, ++ netif->rx.rsp_prod_pvt++); ++ ++ resp->flags |= NETRXF_extra_info; ++ ++ gso->u.gso.size = meta[npo.meta_cons].frag.size; ++ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; ++ gso->u.gso.pad = 0; ++ gso->u.gso.features = 0; ++ ++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO; ++ gso->flags = 0; ++ } ++ ++ netbk_add_frag_responses(netif, status, ++ meta + npo.meta_cons + 1, ++ nr_frags); ++ ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret); ++ irq = netif->irq; ++ if (ret && !rx_notify[irq]) { ++ rx_notify[irq] = 1; ++ notify_list[notify_nr++] = irq; ++ } ++ ++ if (netif_queue_stopped(netif->dev) && ++ netif_schedulable(netif) && ++ !netbk_queue_full(netif)) ++ netif_wake_queue(netif->dev); ++ ++ netif_put(netif); ++ dev_kfree_skb(skb); ++ npo.meta_cons += nr_frags + 1; ++ } ++ ++ while (notify_nr != 0) { ++ irq = notify_list[--notify_nr]; ++ rx_notify[irq] = 0; ++ notify_remote_via_irq(irq); ++ } ++ ++ /* More work to do? */ ++ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer)) ++ tasklet_schedule(&net_rx_tasklet); ++#if 0 ++ else ++ xen_network_done_notify(); ++#endif ++} ++ ++static void net_alarm(unsigned long unused) ++{ ++ tasklet_schedule(&net_rx_tasklet); ++} ++ ++struct net_device_stats *netif_be_get_stats(struct net_device *dev) ++{ ++ netif_t *netif = netdev_priv(dev); ++ return &netif->stats; ++} ++ ++static int __on_net_schedule_list(netif_t *netif) ++{ ++ return netif->list.next != NULL; ++} ++ ++static void remove_from_net_schedule_list(netif_t *netif) ++{ ++ spin_lock_irq(&net_schedule_list_lock); ++ if (likely(__on_net_schedule_list(netif))) { ++ list_del(&netif->list); ++ netif->list.next = NULL; ++ netif_put(netif); ++ } ++ spin_unlock_irq(&net_schedule_list_lock); ++} ++ ++static void add_to_net_schedule_list_tail(netif_t *netif) ++{ ++ if (__on_net_schedule_list(netif)) ++ return; ++ ++ spin_lock_irq(&net_schedule_list_lock); ++ if (!__on_net_schedule_list(netif) && ++ likely(netif_schedulable(netif))) { ++ list_add_tail(&netif->list, &net_schedule_list); ++ netif_get(netif); ++ } ++ spin_unlock_irq(&net_schedule_list_lock); ++} ++ ++/* ++ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER: ++ * If this driver is pipelining transmit requests then we can be very ++ * aggressive in avoiding new-packet notifications -- frontend only needs to ++ * send a notification if there are no outstanding unreceived responses. ++ * If we may be buffer transmit buffers for any reason then we must be rather ++ * more conservative and treat this as the final check for pending work. ++ */ ++void netif_schedule_work(netif_t *netif) ++{ ++ int more_to_do; ++ ++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER ++ more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx); ++#else ++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do); ++#endif ++ ++ if (more_to_do) { ++ add_to_net_schedule_list_tail(netif); ++ maybe_schedule_tx_action(); ++ } ++} ++ ++void netif_deschedule_work(netif_t *netif) ++{ ++ remove_from_net_schedule_list(netif); ++} ++ ++ ++static void tx_add_credit(netif_t *netif) ++{ ++ unsigned long max_burst, max_credit; ++ ++ /* ++ * Allow a burst big enough to transmit a jumbo packet of up to 128kB. ++ * Otherwise the interface can seize up due to insufficient credit. ++ */ ++ max_burst = RING_GET_REQUEST(&netif->tx, netif->tx.req_cons)->size; ++ max_burst = min(max_burst, 131072UL); ++ max_burst = max(max_burst, netif->credit_bytes); ++ ++ /* Take care that adding a new chunk of credit doesn't wrap to zero. */ ++ max_credit = netif->remaining_credit + netif->credit_bytes; ++ if (max_credit < netif->remaining_credit) ++ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */ ++ ++ netif->remaining_credit = min(max_credit, max_burst); ++} ++ ++static void tx_credit_callback(unsigned long data) ++{ ++ netif_t *netif = (netif_t *)data; ++ tx_add_credit(netif); ++ netif_schedule_work(netif); ++} ++ ++inline static void net_tx_action_dealloc(void) ++{ ++ gnttab_unmap_grant_ref_t *gop; ++ u16 pending_idx; ++ PEND_RING_IDX dc, dp; ++ netif_t *netif; ++ int ret; ++ ++ dc = dealloc_cons; ++ dp = dealloc_prod; ++ ++ /* Ensure we see all indexes enqueued by netif_idx_release(). */ ++ smp_rmb(); ++ ++ /* ++ * Free up any grants we have finished using ++ */ ++ gop = tx_unmap_ops; ++ while (dc != dp) { ++ pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)]; ++ gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx), ++ GNTMAP_host_map, ++ grant_tx_handle[pending_idx]); ++ gop++; ++ } ++ ret = HYPERVISOR_grant_table_op( ++ GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops); ++ BUG_ON(ret); ++ ++ while (dealloc_cons != dp) { ++ pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)]; ++ ++ netif = pending_tx_info[pending_idx].netif; ++ ++ make_tx_response(netif, &pending_tx_info[pending_idx].req, ++ NETIF_RSP_OKAY); ++ ++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; ++ ++ netif_put(netif); ++ } ++} ++ ++static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end) ++{ ++ RING_IDX cons = netif->tx.req_cons; ++ ++ do { ++ make_tx_response(netif, txp, NETIF_RSP_ERROR); ++ if (cons >= end) ++ break; ++ txp = RING_GET_REQUEST(&netif->tx, cons++); ++ } while (1); ++ netif->tx.req_cons = cons; ++ netif_schedule_work(netif); ++ netif_put(netif); ++} ++ ++static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first, ++ netif_tx_request_t *txp, int work_to_do) ++{ ++ RING_IDX cons = netif->tx.req_cons; ++ int frags = 0; ++ ++ if (!(first->flags & NETTXF_more_data)) ++ return 0; ++ ++ do { ++ if (frags >= work_to_do) { ++ DPRINTK("Need more frags\n"); ++ return -frags; ++ } ++ ++ if (unlikely(frags >= MAX_SKB_FRAGS)) { ++ DPRINTK("Too many frags\n"); ++ return -frags; ++ } ++ ++ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags), ++ sizeof(*txp)); ++ if (txp->size > first->size) { ++ DPRINTK("Frags galore\n"); ++ return -frags; ++ } ++ ++ first->size -= txp->size; ++ frags++; ++ ++ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { ++ DPRINTK("txp->offset: %x, size: %u\n", ++ txp->offset, txp->size); ++ return -frags; ++ } ++ } while ((txp++)->flags & NETTXF_more_data); ++ ++ return frags; ++} ++ ++static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif, ++ struct sk_buff *skb, ++ netif_tx_request_t *txp, ++ gnttab_map_grant_ref_t *mop) ++{ ++ struct skb_shared_info *shinfo = skb_shinfo(skb); ++ skb_frag_t *frags = shinfo->frags; ++ unsigned long pending_idx = *((u16 *)skb->data); ++ int i, start; ++ ++ /* Skip first skb fragment if it is on same page as header fragment. */ ++ start = ((unsigned long)shinfo->frags[0].page == pending_idx); ++ ++ for (i = start; i < shinfo->nr_frags; i++, txp++) { ++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)]; ++ ++ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx), ++ GNTMAP_host_map | GNTMAP_readonly, ++ txp->gref, netif->domid); ++ ++ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp)); ++ netif_get(netif); ++ pending_tx_info[pending_idx].netif = netif; ++ frags[i].page = (void *)pending_idx; ++ } ++ ++ return mop; ++} ++ ++static int netbk_tx_check_mop(struct sk_buff *skb, ++ gnttab_map_grant_ref_t **mopp) ++{ ++ gnttab_map_grant_ref_t *mop = *mopp; ++ int pending_idx = *((u16 *)skb->data); ++ netif_t *netif = pending_tx_info[pending_idx].netif; ++ netif_tx_request_t *txp; ++ struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int nr_frags = shinfo->nr_frags; ++ int i, err, start; ++ ++ /* Check status of header. */ ++ err = mop->status; ++ if (unlikely(err)) { ++ txp = &pending_tx_info[pending_idx].req; ++ make_tx_response(netif, txp, NETIF_RSP_ERROR); ++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; ++ netif_put(netif); ++ } else { ++ set_phys_to_machine( ++ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT, ++ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT)); ++ grant_tx_handle[pending_idx] = mop->handle; ++ } ++ ++ /* Skip first skb fragment if it is on same page as header fragment. */ ++ start = ((unsigned long)shinfo->frags[0].page == pending_idx); ++ ++ for (i = start; i < nr_frags; i++) { ++ int j, newerr; ++ ++ pending_idx = (unsigned long)shinfo->frags[i].page; ++ ++ /* Check error status: if okay then remember grant handle. */ ++ newerr = (++mop)->status; ++ if (likely(!newerr)) { ++ set_phys_to_machine( ++ __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT, ++ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT)); ++ grant_tx_handle[pending_idx] = mop->handle; ++ /* Had a previous error? Invalidate this fragment. */ ++ if (unlikely(err)) ++ netif_idx_release(pending_idx); ++ continue; ++ } ++ ++ /* Error on this fragment: respond to client with an error. */ ++ txp = &pending_tx_info[pending_idx].req; ++ make_tx_response(netif, txp, NETIF_RSP_ERROR); ++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; ++ netif_put(netif); ++ ++ /* Not the first error? Preceding frags already invalidated. */ ++ if (err) ++ continue; ++ ++ /* First error: invalidate header and preceding fragments. */ ++ pending_idx = *((u16 *)skb->data); ++ netif_idx_release(pending_idx); ++ for (j = start; j < i; j++) { ++ pending_idx = (unsigned long)shinfo->frags[i].page; ++ netif_idx_release(pending_idx); ++ } ++ ++ /* Remember the error: invalidate all subsequent fragments. */ ++ err = newerr; ++ } ++ ++ *mopp = mop + 1; ++ return err; ++} ++ ++static void netbk_fill_frags(struct sk_buff *skb) ++{ ++ struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int nr_frags = shinfo->nr_frags; ++ int i; ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag_t *frag = shinfo->frags + i; ++ netif_tx_request_t *txp; ++ unsigned long pending_idx; ++ ++ pending_idx = (unsigned long)frag->page; ++ txp = &pending_tx_info[pending_idx].req; ++ frag->page = virt_to_page(idx_to_kaddr(pending_idx)); ++ frag->size = txp->size; ++ frag->page_offset = txp->offset; ++ ++ skb->len += txp->size; ++ skb->data_len += txp->size; ++ skb->truesize += txp->size; ++ } ++} ++ ++int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras, ++ int work_to_do) ++{ ++ struct netif_extra_info extra; ++ RING_IDX cons = netif->tx.req_cons; ++ ++ do { ++ if (unlikely(work_to_do-- <= 0)) { ++ DPRINTK("Missing extra info\n"); ++ return -EBADR; ++ } ++ ++ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons), ++ sizeof(extra)); ++ if (unlikely(!extra.type || ++ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { ++ netif->tx.req_cons = ++cons; ++ DPRINTK("Invalid extra type: %d\n", extra.type); ++ return -EINVAL; ++ } ++ ++ memcpy(&extras[extra.type - 1], &extra, sizeof(extra)); ++ netif->tx.req_cons = ++cons; ++ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE); ++ ++ return work_to_do; ++} ++ ++static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso) ++{ ++ if (!gso->u.gso.size) { ++ DPRINTK("GSO size must not be zero.\n"); ++ return -EINVAL; ++ } ++ ++ /* Currently only TCPv4 S.O. is supported. */ ++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { ++ DPRINTK("Bad GSO type %d.\n", gso->u.gso.type); ++ return -EINVAL; ++ } ++ ++ skb_shinfo(skb)->gso_size = gso->u.gso.size; ++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; ++ ++ /* Header must be checked, and gso_segs computed. */ ++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; ++ skb_shinfo(skb)->gso_segs = 0; ++ ++ return 0; ++} ++ ++/* Called after netfront has transmitted */ ++static void net_tx_action(unsigned long unused) ++{ ++ struct list_head *ent; ++ struct sk_buff *skb; ++ netif_t *netif; ++ netif_tx_request_t txreq; ++ netif_tx_request_t txfrags[MAX_SKB_FRAGS]; ++ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; ++ u16 pending_idx; ++ RING_IDX i; ++ gnttab_map_grant_ref_t *mop; ++ unsigned int data_len; ++ int ret, work_to_do; ++ ++ if (dealloc_cons != dealloc_prod) ++ net_tx_action_dealloc(); ++ ++ mop = tx_map_ops; ++ while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) && ++ !list_empty(&net_schedule_list)) { ++ /* Get a netif from the list with work to do. */ ++ ent = net_schedule_list.next; ++ netif = list_entry(ent, netif_t, list); ++ netif_get(netif); ++ remove_from_net_schedule_list(netif); ++ ++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do); ++ if (!work_to_do) { ++ netif_put(netif); ++ continue; ++ } ++ ++ i = netif->tx.req_cons; ++ rmb(); /* Ensure that we see the request before we copy it. */ ++ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq)); ++ ++ /* Credit-based scheduling. */ ++ if (txreq.size > netif->remaining_credit) { ++ unsigned long now = jiffies; ++ unsigned long next_credit = ++ netif->credit_timeout.expires + ++ msecs_to_jiffies(netif->credit_usec / 1000); ++ ++ /* Timer could already be pending in rare cases. */ ++ if (timer_pending(&netif->credit_timeout)) { ++ netif_put(netif); ++ continue; ++ } ++ ++ /* Passed the point where we can replenish credit? */ ++ if (time_after_eq(now, next_credit)) { ++ netif->credit_timeout.expires = now; ++ tx_add_credit(netif); ++ } ++ ++ /* Still too big to send right now? Set a callback. */ ++ if (txreq.size > netif->remaining_credit) { ++ netif->credit_timeout.data = ++ (unsigned long)netif; ++ netif->credit_timeout.function = ++ tx_credit_callback; ++ __mod_timer(&netif->credit_timeout, ++ next_credit); ++ netif_put(netif); ++ continue; ++ } ++ } ++ netif->remaining_credit -= txreq.size; ++ ++ work_to_do--; ++ netif->tx.req_cons = ++i; ++ ++ memset(extras, 0, sizeof(extras)); ++ if (txreq.flags & NETTXF_extra_info) { ++ work_to_do = netbk_get_extras(netif, extras, ++ work_to_do); ++ i = netif->tx.req_cons; ++ if (unlikely(work_to_do < 0)) { ++ netbk_tx_err(netif, &txreq, i); ++ continue; ++ } ++ } ++ ++ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do); ++ if (unlikely(ret < 0)) { ++ netbk_tx_err(netif, &txreq, i - ret); ++ continue; ++ } ++ i += ret; ++ ++ if (unlikely(txreq.size < ETH_HLEN)) { ++ DPRINTK("Bad packet size: %d\n", txreq.size); ++ netbk_tx_err(netif, &txreq, i); ++ continue; ++ } ++ ++ /* No crossing a page as the payload mustn't fragment. */ ++ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { ++ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n", ++ txreq.offset, txreq.size, ++ (txreq.offset &~PAGE_MASK) + txreq.size); ++ netbk_tx_err(netif, &txreq, i); ++ continue; ++ } ++ ++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; ++ ++ data_len = (txreq.size > PKT_PROT_LEN && ++ ret < MAX_SKB_FRAGS) ? ++ PKT_PROT_LEN : txreq.size; ++ ++ skb = alloc_skb(data_len + 16 + NET_IP_ALIGN, ++ GFP_ATOMIC | __GFP_NOWARN); ++ if (unlikely(skb == NULL)) { ++ DPRINTK("Can't allocate a skb in start_xmit.\n"); ++ netbk_tx_err(netif, &txreq, i); ++ break; ++ } ++ ++ /* Packets passed to netif_rx() must have some headroom. */ ++ skb_reserve(skb, 16 + NET_IP_ALIGN); ++ ++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { ++ struct netif_extra_info *gso; ++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; ++ ++ if (netbk_set_skb_gso(skb, gso)) { ++ kfree_skb(skb); ++ netbk_tx_err(netif, &txreq, i); ++ continue; ++ } ++ } ++ ++ gnttab_set_map_op(mop, idx_to_kaddr(pending_idx), ++ GNTMAP_host_map | GNTMAP_readonly, ++ txreq.gref, netif->domid); ++ mop++; ++ ++ memcpy(&pending_tx_info[pending_idx].req, ++ &txreq, sizeof(txreq)); ++ pending_tx_info[pending_idx].netif = netif; ++ *((u16 *)skb->data) = pending_idx; ++ ++ __skb_put(skb, data_len); ++ ++ skb_shinfo(skb)->nr_frags = ret; ++ if (data_len < txreq.size) { ++ skb_shinfo(skb)->nr_frags++; ++ skb_shinfo(skb)->frags[0].page = ++ (void *)(unsigned long)pending_idx; ++ } else { ++ /* Discriminate from any valid pending_idx value. */ ++ skb_shinfo(skb)->frags[0].page = (void *)~0UL; ++ } ++ ++ __skb_queue_tail(&tx_queue, skb); ++ ++ pending_cons++; ++ ++ mop = netbk_get_requests(netif, skb, txfrags, mop); ++ ++ netif->tx.req_cons = i; ++ netif_schedule_work(netif); ++ ++ if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops)) ++ break; ++ } ++ ++ if (mop == tx_map_ops) ++ return; ++ ++ ret = HYPERVISOR_grant_table_op( ++ GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops); ++ BUG_ON(ret); ++ ++ mop = tx_map_ops; ++ while ((skb = __skb_dequeue(&tx_queue)) != NULL) { ++ netif_tx_request_t *txp; ++ ++ pending_idx = *((u16 *)skb->data); ++ netif = pending_tx_info[pending_idx].netif; ++ txp = &pending_tx_info[pending_idx].req; ++ ++ /* Check the remap error code. */ ++ if (unlikely(netbk_tx_check_mop(skb, &mop))) { ++ DPRINTK("netback grant failed.\n"); ++ skb_shinfo(skb)->nr_frags = 0; ++ kfree_skb(skb); ++ continue; ++ } ++ ++ data_len = skb->len; ++ memcpy(skb->data, ++ (void *)(idx_to_kaddr(pending_idx)|txp->offset), ++ data_len); ++ if (data_len < txp->size) { ++ /* Append the packet payload as a fragment. */ ++ txp->offset += data_len; ++ txp->size -= data_len; ++ } else { ++ /* Schedule a response immediately. */ ++ netif_idx_release(pending_idx); ++ } ++ ++ /* ++ * Old frontends do not assert data_validated but we ++ * can infer it from csum_blank so test both flags. ++ */ ++ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ skb->proto_data_valid = 1; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ skb->proto_data_valid = 0; ++ } ++ skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank); ++ ++ netbk_fill_frags(skb); ++ ++ skb->dev = netif->dev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ netif->stats.rx_bytes += skb->len; ++ netif->stats.rx_packets++; ++ ++ netif_rx(skb); ++ netif->dev->last_rx = jiffies; ++ } ++} ++ ++static void netif_idx_release(u16 pending_idx) ++{ ++ static DEFINE_SPINLOCK(_lock); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&_lock, flags); ++ dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx; ++ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */ ++ smp_wmb(); ++ dealloc_prod++; ++ spin_unlock_irqrestore(&_lock, flags); ++ ++ tasklet_schedule(&net_tx_tasklet); ++} ++ ++static void netif_page_release(struct page *page) ++{ ++ /* Ready for next use. */ ++ init_page_count(page); ++ ++ netif_idx_release(netif_page_index(page)); ++} ++ ++irqreturn_t netif_be_int(int irq, void *dev_id) ++{ ++ netif_t *netif = dev_id; ++ ++ add_to_net_schedule_list_tail(netif); ++ maybe_schedule_tx_action(); ++ ++ if (netif_schedulable(netif) && !netbk_queue_full(netif)) ++ netif_wake_queue(netif->dev); ++ ++ return IRQ_HANDLED; ++} ++ ++static void make_tx_response(netif_t *netif, ++ netif_tx_request_t *txp, ++ s8 st) ++{ ++ RING_IDX i = netif->tx.rsp_prod_pvt; ++ netif_tx_response_t *resp; ++ int notify; ++ ++ resp = RING_GET_RESPONSE(&netif->tx, i); ++ resp->id = txp->id; ++ resp->status = st; ++ ++ if (txp->flags & NETTXF_extra_info) ++ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL; ++ ++ netif->tx.rsp_prod_pvt = ++i; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify); ++ if (notify) ++ notify_remote_via_irq(netif->irq); ++ ++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER ++ if (i == netif->tx.req_cons) { ++ int more_to_do; ++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do); ++ if (more_to_do) ++ add_to_net_schedule_list_tail(netif); ++ } ++#endif ++} ++ ++static netif_rx_response_t *make_rx_response(netif_t *netif, ++ u16 id, ++ s8 st, ++ u16 offset, ++ u16 size, ++ u16 flags) ++{ ++ RING_IDX i = netif->rx.rsp_prod_pvt; ++ netif_rx_response_t *resp; ++ ++ resp = RING_GET_RESPONSE(&netif->rx, i); ++ resp->offset = offset; ++ resp->flags = flags; ++ resp->id = id; ++ resp->status = (s16)size; ++ if (st < 0) ++ resp->status = (s16)st; ++ ++ netif->rx.rsp_prod_pvt = ++i; ++ ++ return resp; ++} ++ ++#ifdef NETBE_DEBUG_INTERRUPT ++static irqreturn_t netif_be_dbg(int irq, void *dev_id) ++{ ++ struct list_head *ent; ++ netif_t *netif; ++ int i = 0; ++ ++ printk(KERN_ALERT "netif_schedule_list:\n"); ++ spin_lock_irq(&net_schedule_list_lock); ++ ++ list_for_each (ent, &net_schedule_list) { ++ netif = list_entry(ent, netif_t, list); ++ printk(KERN_ALERT " %d: private(rx_req_cons=%08x " ++ "rx_resp_prod=%08x\n", ++ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt); ++ printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n", ++ netif->tx.req_cons, netif->tx.rsp_prod_pvt); ++ printk(KERN_ALERT " shared(rx_req_prod=%08x " ++ "rx_resp_prod=%08x\n", ++ netif->rx.sring->req_prod, netif->rx.sring->rsp_prod); ++ printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n", ++ netif->rx.sring->rsp_event, netif->tx.sring->req_prod); ++ printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n", ++ netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event); ++ i++; ++ } ++ ++ spin_unlock_irq(&net_schedule_list_lock); ++ printk(KERN_ALERT " ** End of netif_schedule_list **\n"); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++static int __init netback_init(void) ++{ ++ int i; ++ struct page *page; ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ /* We can increase reservation by this much in net_rx_action(). */ ++ balloon_update_driver_allowance(NET_RX_RING_SIZE); ++ ++ skb_queue_head_init(&rx_queue); ++ skb_queue_head_init(&tx_queue); ++ ++ init_timer(&net_timer); ++ net_timer.data = 0; ++ net_timer.function = net_alarm; ++ ++ mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS); ++ if (mmap_pages == NULL) { ++ printk("%s: out of memory\n", __FUNCTION__); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < MAX_PENDING_REQS; i++) { ++ page = mmap_pages[i]; ++ SetPageForeign(page, netif_page_release); ++ netif_page_index(page) = i; ++ } ++ ++ pending_cons = 0; ++ pending_prod = MAX_PENDING_REQS; ++ for (i = 0; i < MAX_PENDING_REQS; i++) ++ pending_ring[i] = i; ++ ++ spin_lock_init(&net_schedule_list_lock); ++ INIT_LIST_HEAD(&net_schedule_list); ++ ++ netif_xenbus_init(); ++ ++#ifdef NETBE_DEBUG_INTERRUPT ++ (void)bind_virq_to_irqhandler(VIRQ_DEBUG, ++ 0, ++ netif_be_dbg, ++ SA_SHIRQ, ++ "net-be-dbg", ++ &netif_be_dbg); ++#endif ++ ++ return 0; ++} ++ ++module_init(netback_init); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netback/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netback/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,448 @@ ++/* Xenbus code for netif backend ++ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au> ++ Copyright (C) 2005 XenSource Ltd ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include <stdarg.h> ++#include <linux/module.h> ++#include <xen/xenbus.h> ++#include "common.h" ++ ++#if 0 ++#undef DPRINTK ++#define DPRINTK(fmt, args...) \ ++ printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) ++#endif ++ ++struct backend_info { ++ struct xenbus_device *dev; ++ netif_t *netif; ++ enum xenbus_state frontend_state; ++}; ++ ++static int connect_rings(struct backend_info *); ++static void connect(struct backend_info *); ++static void backend_create_netif(struct backend_info *be); ++ ++static int netback_remove(struct xenbus_device *dev) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ ++ if (be->netif) { ++ netif_disconnect(be->netif); ++ be->netif = NULL; ++ } ++ kfree(be); ++ dev->dev.driver_data = NULL; ++ return 0; ++} ++ ++ ++/** ++ * Entry point to this code when a new device is created. Allocate the basic ++ * structures and switch to InitWait. ++ */ ++static int netback_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ const char *message; ++ struct xenbus_transaction xbt; ++ int err; ++ struct backend_info *be = kzalloc(sizeof(struct backend_info), ++ GFP_KERNEL); ++ if (!be) { ++ xenbus_dev_fatal(dev, -ENOMEM, ++ "allocating backend structure"); ++ return -ENOMEM; ++ } ++ ++ be->dev = dev; ++ dev->dev.driver_data = be; ++ ++ do { ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ goto fail; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); ++ if (err) { ++ message = "writing feature-sg"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", ++ "%d", 1); ++ if (err) { ++ message = "writing feature-gso-tcpv4"; ++ goto abort_transaction; ++ } ++ ++ /* We support rx-copy path. */ ++ err = xenbus_printf(xbt, dev->nodename, ++ "feature-rx-copy", "%d", 1); ++ if (err) { ++ message = "writing feature-rx-copy"; ++ goto abort_transaction; ++ } ++ ++ /* ++ * We don't support rx-flip path (except old guests who don't ++ * grok this feature flag). ++ */ ++ err = xenbus_printf(xbt, dev->nodename, ++ "feature-rx-flip", "%d", 0); ++ if (err) { ++ message = "writing feature-rx-flip"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ } while (err == -EAGAIN); ++ ++ if (err) { ++ xenbus_dev_fatal(dev, err, "completing transaction"); ++ goto fail; ++ } ++ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) ++ goto fail; ++ ++ /* This kicks hotplug scripts, so do it immediately. */ ++ backend_create_netif(be); ++ ++ return 0; ++ ++abort_transaction: ++ xenbus_transaction_end(xbt, 1); ++ xenbus_dev_fatal(dev, err, "%s", message); ++fail: ++ DPRINTK("failed"); ++ netback_remove(dev); ++ return err; ++} ++ ++ ++/** ++ * Handle the creation of the hotplug script environment. We add the script ++ * and vif variables to the environment, for the benefit of the vif-* hotplug ++ * scripts. ++ */ ++static int netback_uevent(struct xenbus_device *xdev, char **envp, ++ int num_envp, char *buffer, int buffer_size) ++{ ++ struct backend_info *be = xdev->dev.driver_data; ++ netif_t *netif = be->netif; ++ int i = 0, length = 0; ++ char *val; ++ ++ DPRINTK("netback_uevent"); ++ ++ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL); ++ if (IS_ERR(val)) { ++ int err = PTR_ERR(val); ++ xenbus_dev_fatal(xdev, err, "reading script"); ++ return err; ++ } ++ else { ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, ++ &length, "script=%s", val); ++ kfree(val); ++ } ++ ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "vif=%s", netif->dev->name); ++ ++ envp[i] = NULL; ++ ++ return 0; ++} ++ ++ ++static void backend_create_netif(struct backend_info *be) ++{ ++ int err; ++ long handle; ++ struct xenbus_device *dev = be->dev; ++ ++ if (be->netif != NULL) ++ return; ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle); ++ if (err != 1) { ++ xenbus_dev_fatal(dev, err, "reading handle"); ++ return; ++ } ++ ++ be->netif = netif_alloc(dev->otherend_id, handle); ++ if (IS_ERR(be->netif)) { ++ err = PTR_ERR(be->netif); ++ be->netif = NULL; ++ xenbus_dev_fatal(dev, err, "creating interface"); ++ return; ++ } ++ ++ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); ++} ++ ++ ++/** ++ * Callback received when the frontend's state changes. ++ */ ++static void frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ ++ DPRINTK("%s", xenbus_strstate(frontend_state)); ++ ++ be->frontend_state = frontend_state; ++ ++ switch (frontend_state) { ++ case XenbusStateInitialising: ++ if (dev->state == XenbusStateClosed) { ++ printk(KERN_INFO "%s: %s: prepare for reconnect\n", ++ __FUNCTION__, dev->nodename); ++ if (be->netif) { ++ netif_disconnect(be->netif); ++ be->netif = NULL; ++ } ++ xenbus_switch_state(dev, XenbusStateInitWait); ++ } ++ break; ++ ++ case XenbusStateInitialised: ++ break; ++ ++ case XenbusStateConnected: ++ backend_create_netif(be); ++ if (be->netif) ++ connect(be); ++ break; ++ ++ case XenbusStateClosing: ++ xenbus_switch_state(dev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateClosed: ++ xenbus_switch_state(dev, XenbusStateClosed); ++ if (xenbus_dev_is_online(dev)) ++ break; ++ /* fall through if not online */ ++ case XenbusStateUnknown: ++ if (be->netif != NULL) ++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); ++ device_unregister(&dev->dev); ++ break; ++ ++ default: ++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", ++ frontend_state); ++ break; ++ } ++} ++ ++ ++static void xen_net_read_rate(struct xenbus_device *dev, ++ unsigned long *bytes, unsigned long *usec) ++{ ++ char *s, *e; ++ unsigned long b, u; ++ char *ratestr; ++ ++ /* Default to unlimited bandwidth. */ ++ *bytes = ~0UL; ++ *usec = 0; ++ ++ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL); ++ if (IS_ERR(ratestr)) ++ return; ++ ++ s = ratestr; ++ b = simple_strtoul(s, &e, 10); ++ if ((s == e) || (*e != ',')) ++ goto fail; ++ ++ s = e + 1; ++ u = simple_strtoul(s, &e, 10); ++ if ((s == e) || (*e != '\0')) ++ goto fail; ++ ++ *bytes = b; ++ *usec = u; ++ ++ kfree(ratestr); ++ return; ++ ++ fail: ++ WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n"); ++ kfree(ratestr); ++} ++ ++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) ++{ ++ char *s, *e, *macstr; ++ int i; ++ ++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); ++ if (IS_ERR(macstr)) ++ return PTR_ERR(macstr); ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ mac[i] = simple_strtoul(s, &e, 16); ++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) { ++ kfree(macstr); ++ return -ENOENT; ++ } ++ s = e+1; ++ } ++ ++ kfree(macstr); ++ return 0; ++} ++ ++static void connect(struct backend_info *be) ++{ ++ int err; ++ struct xenbus_device *dev = be->dev; ++ ++ err = connect_rings(be); ++ if (err) ++ return; ++ ++ err = xen_net_read_mac(dev, be->netif->fe_dev_addr); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); ++ return; ++ } ++ ++ xen_net_read_rate(dev, &be->netif->credit_bytes, ++ &be->netif->credit_usec); ++ be->netif->remaining_credit = be->netif->credit_bytes; ++ ++ xenbus_switch_state(dev, XenbusStateConnected); ++ ++ netif_wake_queue(be->netif->dev); ++} ++ ++ ++static int connect_rings(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ unsigned long tx_ring_ref, rx_ring_ref; ++ unsigned int evtchn, rx_copy; ++ int err; ++ int val; ++ ++ DPRINTK(""); ++ ++ err = xenbus_gather(XBT_NIL, dev->otherend, ++ "tx-ring-ref", "%lu", &tx_ring_ref, ++ "rx-ring-ref", "%lu", &rx_ring_ref, ++ "event-channel", "%u", &evtchn, NULL); ++ if (err) { ++ xenbus_dev_fatal(dev, err, ++ "reading %s/ring-ref and event-channel", ++ dev->otherend); ++ return err; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u", ++ &rx_copy); ++ if (err == -ENOENT) { ++ err = 0; ++ rx_copy = 0; ++ } ++ if (err < 0) { ++ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy", ++ dev->otherend); ++ return err; ++ } ++ be->netif->copying_receiver = !!rx_copy; ++ ++ if (be->netif->dev->tx_queue_len != 0) { ++ if (xenbus_scanf(XBT_NIL, dev->otherend, ++ "feature-rx-notify", "%d", &val) < 0) ++ val = 0; ++ if (val) ++ be->netif->can_queue = 1; ++ else ++ /* Must be non-zero for pfifo_fast to work. */ ++ be->netif->dev->tx_queue_len = 1; ++ } ++ ++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0) ++ val = 0; ++ if (val) { ++ be->netif->features |= NETIF_F_SG; ++ be->netif->dev->features |= NETIF_F_SG; ++ } ++ ++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d", ++ &val) < 0) ++ val = 0; ++ if (val) { ++ be->netif->features |= NETIF_F_TSO; ++ be->netif->dev->features |= NETIF_F_TSO; ++ } ++ ++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload", ++ "%d", &val) < 0) ++ val = 0; ++ if (val) { ++ be->netif->features &= ~NETIF_F_IP_CSUM; ++ be->netif->dev->features &= ~NETIF_F_IP_CSUM; ++ } ++ ++ /* Map the shared frame, irq etc. */ ++ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn); ++ if (err) { ++ xenbus_dev_fatal(dev, err, ++ "mapping shared-frames %lu/%lu port %u", ++ tx_ring_ref, rx_ring_ref, evtchn); ++ return err; ++ } ++ return 0; ++} ++ ++ ++/* ** Driver Registration ** */ ++ ++ ++static struct xenbus_device_id netback_ids[] = { ++ { "vif" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver netback = { ++ .name = "vif", ++ .owner = THIS_MODULE, ++ .ids = netback_ids, ++ .probe = netback_probe, ++ .remove = netback_remove, ++ .uevent = netback_uevent, ++ .otherend_changed = frontend_changed, ++}; ++ ++ ++void netif_xenbus_init(void) ++{ ++ xenbus_register_backend(&netback); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netfront/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netfront/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,4 @@ ++ ++obj-$(CONFIG_XEN_NETDEV_FRONTEND) := xennet.o ++ ++xennet-objs := netfront.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/netfront/netfront.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/netfront/netfront.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2133 @@ ++/****************************************************************************** ++ * Virtual network driver for conversing with remote driver backends. ++ * ++ * Copyright (c) 2002-2005, K A Fraser ++ * Copyright (c) 2005, XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/netdevice.h> ++#include <linux/inetdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/init.h> ++#include <linux/bitops.h> ++#include <linux/ethtool.h> ++#include <linux/in.h> ++#include <linux/if_ether.h> ++#include <linux/io.h> ++#include <linux/moduleparam.h> ++#include <net/sock.h> ++#include <net/pkt_sched.h> ++#include <net/arp.h> ++#include <net/route.h> ++#include <asm/uaccess.h> ++#include <xen/evtchn.h> ++#include <xen/xenbus.h> ++#include <xen/interface/io/netif.h> ++#include <xen/interface/memory.h> ++#include <xen/balloon.h> ++#include <asm/page.h> ++#include <asm/maddr.h> ++#include <asm/uaccess.h> ++#include <xen/interface/grant_table.h> ++#include <xen/gnttab.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++struct netfront_cb { ++ struct page *page; ++ unsigned offset; ++}; ++ ++#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb)) ++ ++/* ++ * Mutually-exclusive module options to select receive data path: ++ * rx_copy : Packets are copied by network backend into local memory ++ * rx_flip : Page containing packet data is transferred to our ownership ++ * For fully-virtualised guests there is no option - copying must be used. ++ * For paravirtualised guests, flipping is the default. ++ */ ++#ifdef CONFIG_XEN ++static int MODPARM_rx_copy = 0; ++module_param_named(rx_copy, MODPARM_rx_copy, bool, 0); ++MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)"); ++static int MODPARM_rx_flip = 0; ++module_param_named(rx_flip, MODPARM_rx_flip, bool, 0); ++MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)"); ++#else ++static const int MODPARM_rx_copy = 1; ++static const int MODPARM_rx_flip = 0; ++#endif ++ ++#define RX_COPY_THRESHOLD 256 ++ ++/* If we don't have GSO, fake things up so that we never try to use it. */ ++#if defined(NETIF_F_GSO) ++#define HAVE_GSO 1 ++#define HAVE_TSO 1 /* TSO is a subset of GSO */ ++static inline void dev_disable_gso_features(struct net_device *dev) ++{ ++ /* Turn off all GSO bits except ROBUST. */ ++ dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1; ++ dev->features |= NETIF_F_GSO_ROBUST; ++} ++#elif defined(NETIF_F_TSO) ++#define HAVE_TSO 1 ++ ++/* Some older kernels cannot cope with incorrect checksums, ++ * particularly in netfilter. I'm not sure there is 100% correlation ++ * with the presence of NETIF_F_TSO but it appears to be a good first ++ * approximiation. ++ */ ++#define HAVE_NO_CSUM_OFFLOAD 1 ++ ++#define gso_size tso_size ++#define gso_segs tso_segs ++static inline void dev_disable_gso_features(struct net_device *dev) ++{ ++ /* Turn off all TSO bits. */ ++ dev->features &= ~NETIF_F_TSO; ++} ++static inline int skb_is_gso(const struct sk_buff *skb) ++{ ++ return skb_shinfo(skb)->tso_size; ++} ++static inline int skb_gso_ok(struct sk_buff *skb, int features) ++{ ++ return (features & NETIF_F_TSO); ++} ++ ++static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) ++{ ++ return skb_is_gso(skb) && ++ (!skb_gso_ok(skb, dev->features) || ++ unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); ++} ++#else ++#define netif_needs_gso(dev, skb) 0 ++#define dev_disable_gso_features(dev) ((void)0) ++#endif ++ ++#define GRANT_INVALID_REF 0 ++ ++#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE) ++#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE) ++ ++struct netfront_info { ++ struct list_head list; ++ struct net_device *netdev; ++ ++ struct net_device_stats stats; ++ ++ struct netif_tx_front_ring tx; ++ struct netif_rx_front_ring rx; ++ ++ spinlock_t tx_lock; ++ spinlock_t rx_lock; ++ ++ unsigned int irq; ++ unsigned int copying_receiver; ++ unsigned int carrier; ++ ++ /* Receive-ring batched refills. */ ++#define RX_MIN_TARGET 8 ++#define RX_DFL_MIN_TARGET 64 ++#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) ++ unsigned rx_min_target, rx_max_target, rx_target; ++ struct sk_buff_head rx_batch; ++ ++ struct timer_list rx_refill_timer; ++ ++ /* ++ * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs ++ * is an index into a chain of free entries. ++ */ ++ struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1]; ++ struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; ++ ++#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) ++ grant_ref_t gref_tx_head; ++ grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; ++ grant_ref_t gref_rx_head; ++ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; ++ ++ struct xenbus_device *xbdev; ++ int tx_ring_ref; ++ int rx_ring_ref; ++ u8 mac[ETH_ALEN]; ++ ++ unsigned long rx_pfn_array[NET_RX_RING_SIZE]; ++ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; ++ struct mmu_update rx_mmu[NET_RX_RING_SIZE]; ++}; ++ ++struct netfront_rx_info { ++ struct netif_rx_response rx; ++ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; ++}; ++ ++/* ++ * Implement our own carrier flag: the network stack's version causes delays ++ * when the carrier is re-enabled (in particular, dev_activate() may not ++ * immediately be called, which can cause packet loss). ++ */ ++#define netfront_carrier_on(netif) ((netif)->carrier = 1) ++#define netfront_carrier_off(netif) ((netif)->carrier = 0) ++#define netfront_carrier_ok(netif) ((netif)->carrier) ++ ++/* ++ * Access macros for acquiring freeing slots in tx_skbs[]. ++ */ ++ ++static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id) ++{ ++ list[id] = list[0]; ++ list[0] = (void *)(unsigned long)id; ++} ++ ++static inline unsigned short get_id_from_freelist(struct sk_buff **list) ++{ ++ unsigned int id = (unsigned int)(unsigned long)list[0]; ++ list[0] = list[id]; ++ return id; ++} ++ ++static inline int xennet_rxidx(RING_IDX idx) ++{ ++ return idx & (NET_RX_RING_SIZE - 1); ++} ++ ++static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np, ++ RING_IDX ri) ++{ ++ int i = xennet_rxidx(ri); ++ struct sk_buff *skb = np->rx_skbs[i]; ++ np->rx_skbs[i] = NULL; ++ return skb; ++} ++ ++static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np, ++ RING_IDX ri) ++{ ++ int i = xennet_rxidx(ri); ++ grant_ref_t ref = np->grant_rx_ref[i]; ++ np->grant_rx_ref[i] = GRANT_INVALID_REF; ++ return ref; ++} ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("netfront (%s:%d) " fmt, \ ++ __FUNCTION__, __LINE__, ##args) ++#define IPRINTK(fmt, args...) \ ++ printk(KERN_INFO "netfront: " fmt, ##args) ++#define WPRINTK(fmt, args...) \ ++ printk(KERN_WARNING "netfront: " fmt, ##args) ++ ++static int setup_device(struct xenbus_device *, struct netfront_info *); ++static struct net_device *create_netdev(struct xenbus_device *); ++ ++static void end_access(int, void *); ++static void netif_disconnect_backend(struct netfront_info *); ++ ++static int network_connect(struct net_device *); ++static void network_tx_buf_gc(struct net_device *); ++static void network_alloc_rx_buffers(struct net_device *); ++static int send_fake_arp(struct net_device *); ++ ++static irqreturn_t netif_int(int irq, void *dev_id); ++ ++#ifdef CONFIG_SYSFS ++static int xennet_sysfs_addif(struct net_device *netdev); ++static void xennet_sysfs_delif(struct net_device *netdev); ++#else /* !CONFIG_SYSFS */ ++#define xennet_sysfs_addif(dev) (0) ++#define xennet_sysfs_delif(dev) do { } while(0) ++#endif ++ ++static inline int xennet_can_sg(struct net_device *dev) ++{ ++ return dev->features & NETIF_F_SG; ++} ++ ++/** ++ * Entry point to this code when a new device is created. Allocate the basic ++ * structures and the ring buffers for communication with the backend, and ++ * inform the backend of the appropriate details for those. ++ */ ++static int __devinit netfront_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ struct net_device *netdev; ++ struct netfront_info *info; ++ ++ netdev = create_netdev(dev); ++ if (IS_ERR(netdev)) { ++ err = PTR_ERR(netdev); ++ xenbus_dev_fatal(dev, err, "creating netdev"); ++ return err; ++ } ++ ++ info = netdev_priv(netdev); ++ dev->dev.driver_data = info; ++ ++ err = register_netdev(info->netdev); ++ if (err) { ++ printk(KERN_WARNING "%s: register_netdev err=%d\n", ++ __FUNCTION__, err); ++ goto fail; ++ } ++ ++ err = xennet_sysfs_addif(info->netdev); ++ if (err) { ++ unregister_netdev(info->netdev); ++ printk(KERN_WARNING "%s: add sysfs failed err=%d\n", ++ __FUNCTION__, err); ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ free_netdev(netdev); ++ dev->dev.driver_data = NULL; ++ return err; ++} ++ ++static int __devexit netfront_remove(struct xenbus_device *dev) ++{ ++ struct netfront_info *info = dev->dev.driver_data; ++ ++ DPRINTK("%s\n", dev->nodename); ++ ++ netif_disconnect_backend(info); ++ ++ del_timer_sync(&info->rx_refill_timer); ++ ++ xennet_sysfs_delif(info->netdev); ++ ++ unregister_netdev(info->netdev); ++ ++ free_netdev(info->netdev); ++ ++ return 0; ++} ++ ++/** ++ * We are reconnecting to the backend, due to a suspend/resume, or a backend ++ * driver restart. We tear down our netif structure and recreate it, but ++ * leave the device-layer structures intact so that this is transparent to the ++ * rest of the kernel. ++ */ ++static int netfront_resume(struct xenbus_device *dev) ++{ ++ struct netfront_info *info = dev->dev.driver_data; ++ ++ DPRINTK("%s\n", dev->nodename); ++ ++ netif_disconnect_backend(info); ++ return 0; ++} ++ ++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) ++{ ++ char *s, *e, *macstr; ++ int i; ++ ++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); ++ if (IS_ERR(macstr)) ++ return PTR_ERR(macstr); ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ mac[i] = simple_strtoul(s, &e, 16); ++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) { ++ kfree(macstr); ++ return -ENOENT; ++ } ++ s = e+1; ++ } ++ ++ kfree(macstr); ++ return 0; ++} ++ ++/* Common code used when first setting up, and when resuming. */ ++static int talk_to_backend(struct xenbus_device *dev, ++ struct netfront_info *info) ++{ ++ const char *message; ++ struct xenbus_transaction xbt; ++ int err; ++ ++ err = xen_net_read_mac(dev, info->mac); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); ++ goto out; ++ } ++ ++ /* Create shared ring, alloc event channel. */ ++ err = setup_device(dev, info); ++ if (err) ++ goto out; ++ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ goto destroy_ring; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u", ++ info->tx_ring_ref); ++ if (err) { ++ message = "writing tx ring-ref"; ++ goto abort_transaction; ++ } ++ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u", ++ info->rx_ring_ref); ++ if (err) { ++ message = "writing rx ring-ref"; ++ goto abort_transaction; ++ } ++ err = xenbus_printf(xbt, dev->nodename, ++ "event-channel", "%u", ++ irq_to_evtchn_port(info->irq)); ++ if (err) { ++ message = "writing event-channel"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", ++ info->copying_receiver); ++ if (err) { ++ message = "writing request-rx-copy"; ++ goto abort_transaction; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1); ++ if (err) { ++ message = "writing feature-rx-notify"; ++ goto abort_transaction; ++ } ++ ++#ifdef HAVE_NO_CSUM_OFFLOAD ++ err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload", "%d", 1); ++ if (err) { ++ message = "writing feature-no-csum-offload"; ++ goto abort_transaction; ++ } ++#endif ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); ++ if (err) { ++ message = "writing feature-sg"; ++ goto abort_transaction; ++ } ++ ++#ifdef HAVE_TSO ++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); ++ if (err) { ++ message = "writing feature-gso-tcpv4"; ++ goto abort_transaction; ++ } ++#endif ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err) { ++ if (err == -EAGAIN) ++ goto again; ++ xenbus_dev_fatal(dev, err, "completing transaction"); ++ goto destroy_ring; ++ } ++ ++ return 0; ++ ++ abort_transaction: ++ xenbus_transaction_end(xbt, 1); ++ xenbus_dev_fatal(dev, err, "%s", message); ++ destroy_ring: ++ netif_disconnect_backend(info); ++ out: ++ return err; ++} ++ ++static int setup_device(struct xenbus_device *dev, struct netfront_info *info) ++{ ++ struct netif_tx_sring *txs; ++ struct netif_rx_sring *rxs; ++ int err; ++ struct net_device *netdev = info->netdev; ++ ++ info->tx_ring_ref = GRANT_INVALID_REF; ++ info->rx_ring_ref = GRANT_INVALID_REF; ++ info->rx.sring = NULL; ++ info->tx.sring = NULL; ++ info->irq = 0; ++ ++ txs = (struct netif_tx_sring *)get_zeroed_page(GFP_KERNEL); ++ if (!txs) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(dev, err, "allocating tx ring page"); ++ goto fail; ++ } ++ SHARED_RING_INIT(txs); ++ FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); ++ ++ err = xenbus_grant_ring(dev, virt_to_mfn(txs)); ++ if (err < 0) { ++ free_page((unsigned long)txs); ++ goto fail; ++ } ++ info->tx_ring_ref = err; ++ ++ rxs = (struct netif_rx_sring *)get_zeroed_page(GFP_KERNEL); ++ if (!rxs) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(dev, err, "allocating rx ring page"); ++ goto fail; ++ } ++ SHARED_RING_INIT(rxs); ++ FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); ++ ++ err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); ++ if (err < 0) { ++ free_page((unsigned long)rxs); ++ goto fail; ++ } ++ info->rx_ring_ref = err; ++ ++ memcpy(netdev->dev_addr, info->mac, ETH_ALEN); ++ ++ err = bind_listening_port_to_irqhandler( ++ dev->otherend_id, netif_int, SA_SAMPLE_RANDOM, netdev->name, ++ netdev); ++ if (err < 0) ++ goto fail; ++ info->irq = err; ++ ++ return 0; ++ ++ fail: ++ return err; ++} ++ ++/** ++ * Callback received when the backend's state changes. ++ */ ++static void backend_changed(struct xenbus_device *dev, ++ enum xenbus_state backend_state) ++{ ++ struct netfront_info *np = dev->dev.driver_data; ++ struct net_device *netdev = np->netdev; ++ ++ DPRINTK("%s\n", xenbus_strstate(backend_state)); ++ ++ switch (backend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitialised: ++ case XenbusStateConnected: ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ break; ++ ++ case XenbusStateInitWait: ++ if (dev->state != XenbusStateInitialising) ++ break; ++ if (network_connect(netdev) != 0) ++ break; ++ xenbus_switch_state(dev, XenbusStateConnected); ++ (void)send_fake_arp(netdev); ++ break; ++ ++ case XenbusStateClosing: ++ xenbus_frontend_closed(dev); ++ break; ++ } ++} ++ ++/** Send a packet on a net device to encourage switches to learn the ++ * MAC. We send a fake ARP request. ++ * ++ * @param dev device ++ * @return 0 on success, error code otherwise ++ */ ++static int send_fake_arp(struct net_device *dev) ++{ ++ struct sk_buff *skb; ++ u32 src_ip, dst_ip; ++ ++ dst_ip = INADDR_BROADCAST; ++ src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK); ++ ++ /* No IP? Then nothing to do. */ ++ if (src_ip == 0) ++ return 0; ++ ++ skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ++ dst_ip, dev, src_ip, ++ /*dst_hw*/ NULL, /*src_hw*/ NULL, ++ /*target_hw*/ dev->dev_addr); ++ if (skb == NULL) ++ return -ENOMEM; ++ ++ return dev_queue_xmit(skb); ++} ++ ++static inline int netfront_tx_slot_available(struct netfront_info *np) ++{ ++ return ((np->tx.req_prod_pvt - np->tx.rsp_cons) < ++ (TX_MAX_TARGET - MAX_SKB_FRAGS - 2)); ++} ++ ++static inline void network_maybe_wake_tx(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ ++ if (unlikely(netif_queue_stopped(dev)) && ++ netfront_tx_slot_available(np) && ++ likely(netif_running(dev))) ++ netif_wake_queue(dev); ++} ++ ++static int network_open(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ ++ memset(&np->stats, 0, sizeof(np->stats)); ++ ++ spin_lock_bh(&np->rx_lock); ++ if (netfront_carrier_ok(np)) { ++ network_alloc_rx_buffers(dev); ++ np->rx.sring->rsp_event = np->rx.rsp_cons + 1; ++ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) ++ netif_rx_schedule(dev); ++ } ++ spin_unlock_bh(&np->rx_lock); ++ ++ network_maybe_wake_tx(dev); ++ ++ return 0; ++} ++ ++static void network_tx_buf_gc(struct net_device *dev) ++{ ++ RING_IDX cons, prod; ++ unsigned short id; ++ struct netfront_info *np = netdev_priv(dev); ++ struct sk_buff *skb; ++ ++ BUG_ON(!netfront_carrier_ok(np)); ++ ++ do { ++ prod = np->tx.sring->rsp_prod; ++ rmb(); /* Ensure we see responses up to 'rp'. */ ++ ++ for (cons = np->tx.rsp_cons; cons != prod; cons++) { ++ struct netif_tx_response *txrsp; ++ ++ txrsp = RING_GET_RESPONSE(&np->tx, cons); ++ if (txrsp->status == NETIF_RSP_NULL) ++ continue; ++ ++ id = txrsp->id; ++ skb = np->tx_skbs[id]; ++ if (unlikely(gnttab_query_foreign_access( ++ np->grant_tx_ref[id]) != 0)) { ++ printk(KERN_ALERT "network_tx_buf_gc: warning " ++ "-- grant still in use by backend " ++ "domain.\n"); ++ BUG(); ++ } ++ gnttab_end_foreign_access_ref( ++ np->grant_tx_ref[id], GNTMAP_readonly); ++ gnttab_release_grant_reference( ++ &np->gref_tx_head, np->grant_tx_ref[id]); ++ np->grant_tx_ref[id] = GRANT_INVALID_REF; ++ add_id_to_freelist(np->tx_skbs, id); ++ dev_kfree_skb_irq(skb); ++ } ++ ++ np->tx.rsp_cons = prod; ++ ++ /* ++ * Set a new event, then check for race with update of tx_cons. ++ * Note that it is essential to schedule a callback, no matter ++ * how few buffers are pending. Even if there is space in the ++ * transmit ring, higher layers may be blocked because too much ++ * data is outstanding: in such cases notification from Xen is ++ * likely to be the only kick that we'll get. ++ */ ++ np->tx.sring->rsp_event = ++ prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; ++ mb(); ++ } while ((cons == prod) && (prod != np->tx.sring->rsp_prod)); ++ ++ network_maybe_wake_tx(dev); ++} ++ ++static void rx_refill_timeout(unsigned long data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ netif_rx_schedule(dev); ++} ++ ++static void network_alloc_rx_buffers(struct net_device *dev) ++{ ++ unsigned short id; ++ struct netfront_info *np = netdev_priv(dev); ++ struct sk_buff *skb; ++ struct page *page; ++ int i, batch_target, notify; ++ RING_IDX req_prod = np->rx.req_prod_pvt; ++ struct xen_memory_reservation reservation; ++ grant_ref_t ref; ++ unsigned long pfn; ++ void *vaddr; ++ int nr_flips; ++ netif_rx_request_t *req; ++ ++ if (unlikely(!netfront_carrier_ok(np))) ++ return; ++ ++ /* ++ * Allocate skbuffs greedily, even though we batch updates to the ++ * receive ring. This creates a less bursty demand on the memory ++ * allocator, so should reduce the chance of failed allocation requests ++ * both for ourself and for other kernel subsystems. ++ */ ++ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons); ++ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { ++ /* ++ * Allocate an skb and a page. Do not use __dev_alloc_skb as ++ * that will allocate page-sized buffers which is not ++ * necessary here. ++ * 16 bytes added as necessary headroom for netif_receive_skb. ++ */ ++ skb = alloc_skb(RX_COPY_THRESHOLD + 16 + NET_IP_ALIGN, ++ GFP_ATOMIC | __GFP_NOWARN); ++ if (unlikely(!skb)) ++ goto no_skb; ++ ++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); ++ if (!page) { ++ kfree_skb(skb); ++no_skb: ++ /* Any skbuffs queued for refill? Force them out. */ ++ if (i != 0) ++ goto refill; ++ /* Could not allocate any skbuffs. Try again later. */ ++ mod_timer(&np->rx_refill_timer, ++ jiffies + (HZ/10)); ++ break; ++ } ++ ++ skb_reserve(skb, 16 + NET_IP_ALIGN); /* mimic dev_alloc_skb() */ ++ skb_shinfo(skb)->frags[0].page = page; ++ skb_shinfo(skb)->nr_frags = 1; ++ __skb_queue_tail(&np->rx_batch, skb); ++ } ++ ++ /* Is the batch large enough to be worthwhile? */ ++ if (i < (np->rx_target/2)) { ++ if (req_prod > np->rx.sring->req_prod) ++ goto push; ++ return; ++ } ++ ++ /* Adjust our fill target if we risked running out of buffers. */ ++ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) && ++ ((np->rx_target *= 2) > np->rx_max_target)) ++ np->rx_target = np->rx_max_target; ++ ++ refill: ++ for (nr_flips = i = 0; ; i++) { ++ if ((skb = __skb_dequeue(&np->rx_batch)) == NULL) ++ break; ++ ++ skb->dev = dev; ++ ++ id = xennet_rxidx(req_prod + i); ++ ++ BUG_ON(np->rx_skbs[id]); ++ np->rx_skbs[id] = skb; ++ ++ ref = gnttab_claim_grant_reference(&np->gref_rx_head); ++ BUG_ON((signed short)ref < 0); ++ np->grant_rx_ref[id] = ref; ++ ++ pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page); ++ vaddr = page_address(skb_shinfo(skb)->frags[0].page); ++ ++ req = RING_GET_REQUEST(&np->rx, req_prod + i); ++ if (!np->copying_receiver) { ++ gnttab_grant_foreign_transfer_ref(ref, ++ np->xbdev->otherend_id, ++ pfn); ++ np->rx_pfn_array[nr_flips] = pfn_to_mfn(pfn); ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Remove this page before passing ++ * back to Xen. */ ++ set_phys_to_machine(pfn, INVALID_P2M_ENTRY); ++ MULTI_update_va_mapping(np->rx_mcl+i, ++ (unsigned long)vaddr, ++ __pte(0), 0); ++ } ++ nr_flips++; ++ } else { ++ gnttab_grant_foreign_access_ref(ref, ++ np->xbdev->otherend_id, ++ pfn_to_mfn(pfn), ++ 0); ++ } ++ ++ req->id = id; ++ req->gref = ref; ++ } ++ ++ if ( nr_flips != 0 ) { ++ /* Tell the ballon driver what is going on. */ ++ balloon_update_driver_allowance(i); ++ ++ set_xen_guest_handle(reservation.extent_start, ++ np->rx_pfn_array); ++ reservation.nr_extents = nr_flips; ++ reservation.extent_order = 0; ++ reservation.address_bits = 0; ++ reservation.domid = DOMID_SELF; ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* After all PTEs have been zapped, flush the TLB. */ ++ np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = ++ UVMF_TLB_FLUSH|UVMF_ALL; ++ ++ /* Give away a batch of pages. */ ++ np->rx_mcl[i].op = __HYPERVISOR_memory_op; ++ np->rx_mcl[i].args[0] = XENMEM_decrease_reservation; ++ np->rx_mcl[i].args[1] = (unsigned long)&reservation; ++ ++ /* Zap PTEs and give away pages in one big ++ * multicall. */ ++ (void)HYPERVISOR_multicall(np->rx_mcl, i+1); ++ ++ /* Check return status of HYPERVISOR_memory_op(). */ ++ if (unlikely(np->rx_mcl[i].result != i)) ++ panic("Unable to reduce memory reservation\n"); ++ } else { ++ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, ++ &reservation) != i) ++ panic("Unable to reduce memory reservation\n"); ++ } ++ } else { ++ wmb(); ++ } ++ ++ /* Above is a suitable barrier to ensure backend will see requests. */ ++ np->rx.req_prod_pvt = req_prod + i; ++ push: ++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify); ++ if (notify) ++ notify_remote_via_irq(np->irq); ++} ++ ++static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, ++ struct netif_tx_request *tx) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ char *data = skb->data; ++ unsigned long mfn; ++ RING_IDX prod = np->tx.req_prod_pvt; ++ int frags = skb_shinfo(skb)->nr_frags; ++ unsigned int offset = offset_in_page(data); ++ unsigned int len = skb_headlen(skb); ++ unsigned int id; ++ grant_ref_t ref; ++ int i; ++ ++ while (len > PAGE_SIZE - offset) { ++ tx->size = PAGE_SIZE - offset; ++ tx->flags |= NETTXF_more_data; ++ len -= tx->size; ++ data += tx->size; ++ offset = 0; ++ ++ id = get_id_from_freelist(np->tx_skbs); ++ np->tx_skbs[id] = skb_get(skb); ++ tx = RING_GET_REQUEST(&np->tx, prod++); ++ tx->id = id; ++ ref = gnttab_claim_grant_reference(&np->gref_tx_head); ++ BUG_ON((signed short)ref < 0); ++ ++ mfn = virt_to_mfn(data); ++ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, ++ mfn, GNTMAP_readonly); ++ ++ tx->gref = np->grant_tx_ref[id] = ref; ++ tx->offset = offset; ++ tx->size = len; ++ tx->flags = 0; ++ } ++ ++ for (i = 0; i < frags; i++) { ++ skb_frag_t *frag = skb_shinfo(skb)->frags + i; ++ ++ tx->flags |= NETTXF_more_data; ++ ++ id = get_id_from_freelist(np->tx_skbs); ++ np->tx_skbs[id] = skb_get(skb); ++ tx = RING_GET_REQUEST(&np->tx, prod++); ++ tx->id = id; ++ ref = gnttab_claim_grant_reference(&np->gref_tx_head); ++ BUG_ON((signed short)ref < 0); ++ ++ mfn = pfn_to_mfn(page_to_pfn(frag->page)); ++ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, ++ mfn, GNTMAP_readonly); ++ ++ tx->gref = np->grant_tx_ref[id] = ref; ++ tx->offset = frag->page_offset; ++ tx->size = frag->size; ++ tx->flags = 0; ++ } ++ ++ np->tx.req_prod_pvt = prod; ++} ++ ++static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ unsigned short id; ++ struct netfront_info *np = netdev_priv(dev); ++ struct netif_tx_request *tx; ++ struct netif_extra_info *extra; ++ char *data = skb->data; ++ RING_IDX i; ++ grant_ref_t ref; ++ unsigned long mfn; ++ int notify; ++ int frags = skb_shinfo(skb)->nr_frags; ++ unsigned int offset = offset_in_page(data); ++ unsigned int len = skb_headlen(skb); ++ ++ frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE; ++ if (unlikely(frags > MAX_SKB_FRAGS + 1)) { ++ printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", ++ frags); ++ dump_stack(); ++ goto drop; ++ } ++ ++ spin_lock_irq(&np->tx_lock); ++ ++ if (unlikely(!netfront_carrier_ok(np) || ++ (frags > 1 && !xennet_can_sg(dev)) || ++ netif_needs_gso(dev, skb))) { ++ spin_unlock_irq(&np->tx_lock); ++ goto drop; ++ } ++ ++ i = np->tx.req_prod_pvt; ++ ++ id = get_id_from_freelist(np->tx_skbs); ++ np->tx_skbs[id] = skb; ++ ++ tx = RING_GET_REQUEST(&np->tx, i); ++ ++ tx->id = id; ++ ref = gnttab_claim_grant_reference(&np->gref_tx_head); ++ BUG_ON((signed short)ref < 0); ++ mfn = virt_to_mfn(data); ++ gnttab_grant_foreign_access_ref( ++ ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly); ++ tx->gref = np->grant_tx_ref[id] = ref; ++ tx->offset = offset; ++ tx->size = len; ++ ++ tx->flags = 0; ++ extra = NULL; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ ++ tx->flags |= NETTXF_csum_blank | NETTXF_data_validated; ++#ifdef CONFIG_XEN ++ if (skb->proto_data_valid) /* remote but checksummed? */ ++ tx->flags |= NETTXF_data_validated; ++#endif ++ ++#ifdef HAVE_TSO ++ if (skb_is_gso(skb)) { ++ struct netif_extra_info *gso = (struct netif_extra_info *) ++ RING_GET_REQUEST(&np->tx, ++i); ++ ++ if (extra) ++ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE; ++ else ++ tx->flags |= NETTXF_extra_info; ++ ++ gso->u.gso.size = skb_shinfo(skb)->gso_size; ++ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4; ++ gso->u.gso.pad = 0; ++ gso->u.gso.features = 0; ++ ++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO; ++ gso->flags = 0; ++ extra = gso; ++ } ++#endif ++ ++ np->tx.req_prod_pvt = i + 1; ++ ++ xennet_make_frags(skb, dev, tx); ++ tx->size = skb->len; ++ ++ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify); ++ if (notify) ++ notify_remote_via_irq(np->irq); ++ ++ network_tx_buf_gc(dev); ++ ++ if (!netfront_tx_slot_available(np)) ++ netif_stop_queue(dev); ++ ++ spin_unlock_irq(&np->tx_lock); ++ ++ np->stats.tx_bytes += skb->len; ++ np->stats.tx_packets++; ++ ++ return 0; ++ ++ drop: ++ np->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static irqreturn_t netif_int(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ struct netfront_info *np = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&np->tx_lock, flags); ++ ++ if (likely(netfront_carrier_ok(np))) { ++ network_tx_buf_gc(dev); ++ /* Under tx_lock: protects access to rx shared-ring indexes. */ ++ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) ++ netif_rx_schedule(dev); ++ } ++ ++ spin_unlock_irqrestore(&np->tx_lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb, ++ grant_ref_t ref) ++{ ++ int new = xennet_rxidx(np->rx.req_prod_pvt); ++ ++ BUG_ON(np->rx_skbs[new]); ++ np->rx_skbs[new] = skb; ++ np->grant_rx_ref[new] = ref; ++ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; ++ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; ++ np->rx.req_prod_pvt++; ++} ++ ++int xennet_get_extras(struct netfront_info *np, ++ struct netif_extra_info *extras, RING_IDX rp) ++ ++{ ++ struct netif_extra_info *extra; ++ RING_IDX cons = np->rx.rsp_cons; ++ int err = 0; ++ ++ do { ++ struct sk_buff *skb; ++ grant_ref_t ref; ++ ++ if (unlikely(cons + 1 == rp)) { ++ if (net_ratelimit()) ++ WPRINTK("Missing extra info\n"); ++ err = -EBADR; ++ break; ++ } ++ ++ extra = (struct netif_extra_info *) ++ RING_GET_RESPONSE(&np->rx, ++cons); ++ ++ if (unlikely(!extra->type || ++ extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { ++ if (net_ratelimit()) ++ WPRINTK("Invalid extra type: %d\n", ++ extra->type); ++ err = -EINVAL; ++ } else { ++ memcpy(&extras[extra->type - 1], extra, ++ sizeof(*extra)); ++ } ++ ++ skb = xennet_get_rx_skb(np, cons); ++ ref = xennet_get_rx_ref(np, cons); ++ xennet_move_rx_slot(np, skb, ref); ++ } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); ++ ++ np->rx.rsp_cons = cons; ++ return err; ++} ++ ++static int xennet_get_responses(struct netfront_info *np, ++ struct netfront_rx_info *rinfo, RING_IDX rp, ++ struct sk_buff_head *list, ++ int *pages_flipped_p) ++{ ++ int pages_flipped = *pages_flipped_p; ++ struct mmu_update *mmu; ++ struct multicall_entry *mcl; ++ struct netif_rx_response *rx = &rinfo->rx; ++ struct netif_extra_info *extras = rinfo->extras; ++ RING_IDX cons = np->rx.rsp_cons; ++ struct sk_buff *skb = xennet_get_rx_skb(np, cons); ++ grant_ref_t ref = xennet_get_rx_ref(np, cons); ++ int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); ++ int frags = 1; ++ int err = 0; ++ unsigned long ret; ++ ++ if (rx->flags & NETRXF_extra_info) { ++ err = xennet_get_extras(np, extras, rp); ++ cons = np->rx.rsp_cons; ++ } ++ ++ for (;;) { ++ unsigned long mfn; ++ ++ if (unlikely(rx->status < 0 || ++ rx->offset + rx->status > PAGE_SIZE)) { ++ if (net_ratelimit()) ++ WPRINTK("rx->offset: %x, size: %u\n", ++ rx->offset, rx->status); ++ xennet_move_rx_slot(np, skb, ref); ++ err = -EINVAL; ++ goto next; ++ } ++ ++ /* ++ * This definitely indicates a bug, either in this driver or in ++ * the backend driver. In future this should flag the bad ++ * situation to the system controller to reboot the backed. ++ */ ++ if (ref == GRANT_INVALID_REF) { ++ if (net_ratelimit()) ++ WPRINTK("Bad rx response id %d.\n", rx->id); ++ err = -EINVAL; ++ goto next; ++ } ++ ++ if (!np->copying_receiver) { ++ /* Memory pressure, insufficient buffer ++ * headroom, ... */ ++ if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) { ++ if (net_ratelimit()) ++ WPRINTK("Unfulfilled rx req " ++ "(id=%d, st=%d).\n", ++ rx->id, rx->status); ++ xennet_move_rx_slot(np, skb, ref); ++ err = -ENOMEM; ++ goto next; ++ } ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Remap the page. */ ++ struct page *page = ++ skb_shinfo(skb)->frags[0].page; ++ unsigned long pfn = page_to_pfn(page); ++ void *vaddr = page_address(page); ++ ++ mcl = np->rx_mcl + pages_flipped; ++ mmu = np->rx_mmu + pages_flipped; ++ ++ MULTI_update_va_mapping(mcl, ++ (unsigned long)vaddr, ++ pfn_pte_ma(mfn, ++ PAGE_KERNEL), ++ 0); ++ mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) ++ | MMU_MACHPHYS_UPDATE; ++ mmu->val = pfn; ++ ++ set_phys_to_machine(pfn, mfn); ++ } ++ pages_flipped++; ++ } else { ++ ret = gnttab_end_foreign_access_ref(ref, 0); ++ BUG_ON(!ret); ++ } ++ ++ gnttab_release_grant_reference(&np->gref_rx_head, ref); ++ ++ __skb_queue_tail(list, skb); ++ ++next: ++ if (!(rx->flags & NETRXF_more_data)) ++ break; ++ ++ if (cons + frags == rp) { ++ if (net_ratelimit()) ++ WPRINTK("Need more frags\n"); ++ err = -ENOENT; ++ break; ++ } ++ ++ rx = RING_GET_RESPONSE(&np->rx, cons + frags); ++ skb = xennet_get_rx_skb(np, cons + frags); ++ ref = xennet_get_rx_ref(np, cons + frags); ++ frags++; ++ } ++ ++ if (unlikely(frags > max)) { ++ if (net_ratelimit()) ++ WPRINTK("Too many frags\n"); ++ err = -E2BIG; ++ } ++ ++ if (unlikely(err)) ++ np->rx.rsp_cons = cons + frags; ++ ++ *pages_flipped_p = pages_flipped; ++ ++ return err; ++} ++ ++static RING_IDX xennet_fill_frags(struct netfront_info *np, ++ struct sk_buff *skb, ++ struct sk_buff_head *list) ++{ ++ struct skb_shared_info *shinfo = skb_shinfo(skb); ++ int nr_frags = shinfo->nr_frags; ++ RING_IDX cons = np->rx.rsp_cons; ++ skb_frag_t *frag = shinfo->frags + nr_frags; ++ struct sk_buff *nskb; ++ ++ while ((nskb = __skb_dequeue(list))) { ++ struct netif_rx_response *rx = ++ RING_GET_RESPONSE(&np->rx, ++cons); ++ ++ frag->page = skb_shinfo(nskb)->frags[0].page; ++ frag->page_offset = rx->offset; ++ frag->size = rx->status; ++ ++ skb->data_len += rx->status; ++ ++ skb_shinfo(nskb)->nr_frags = 0; ++ kfree_skb(nskb); ++ ++ frag++; ++ nr_frags++; ++ } ++ ++ shinfo->nr_frags = nr_frags; ++ return cons; ++} ++ ++static int xennet_set_skb_gso(struct sk_buff *skb, ++ struct netif_extra_info *gso) ++{ ++ if (!gso->u.gso.size) { ++ if (net_ratelimit()) ++ WPRINTK("GSO size must not be zero.\n"); ++ return -EINVAL; ++ } ++ ++ /* Currently only TCPv4 S.O. is supported. */ ++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) { ++ if (net_ratelimit()) ++ WPRINTK("Bad GSO type %d.\n", gso->u.gso.type); ++ return -EINVAL; ++ } ++ ++#ifdef HAVE_TSO ++ skb_shinfo(skb)->gso_size = gso->u.gso.size; ++#ifdef HAVE_GSO ++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; ++ ++ /* Header must be checked, and gso_segs computed. */ ++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; ++#endif ++ skb_shinfo(skb)->gso_segs = 0; ++ ++ return 0; ++#else ++ if (net_ratelimit()) ++ WPRINTK("GSO unsupported by this kernel.\n"); ++ return -EINVAL; ++#endif ++} ++ ++static int netif_poll(struct net_device *dev, int *pbudget) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ struct sk_buff *skb; ++ struct netfront_rx_info rinfo; ++ struct netif_rx_response *rx = &rinfo.rx; ++ struct netif_extra_info *extras = rinfo.extras; ++ RING_IDX i, rp; ++ struct multicall_entry *mcl; ++ int work_done, budget, more_to_do = 1; ++ struct sk_buff_head rxq; ++ struct sk_buff_head errq; ++ struct sk_buff_head tmpq; ++ unsigned long flags; ++ unsigned int len; ++ int pages_flipped = 0; ++ int err; ++ ++ spin_lock(&np->rx_lock); /* no need for spin_lock_bh() in ->poll() */ ++ ++ if (unlikely(!netfront_carrier_ok(np))) { ++ spin_unlock(&np->rx_lock); ++ return 0; ++ } ++ ++ skb_queue_head_init(&rxq); ++ skb_queue_head_init(&errq); ++ skb_queue_head_init(&tmpq); ++ ++ if ((budget = *pbudget) > dev->quota) ++ budget = dev->quota; ++ rp = np->rx.sring->rsp_prod; ++ rmb(); /* Ensure we see queued responses up to 'rp'. */ ++ ++ i = np->rx.rsp_cons; ++ work_done = 0; ++ while ((i != rp) && (work_done < budget)) { ++ memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); ++ memset(extras, 0, sizeof(rinfo.extras)); ++ ++ err = xennet_get_responses(np, &rinfo, rp, &tmpq, ++ &pages_flipped); ++ ++ if (unlikely(err)) { ++err: ++ while ((skb = __skb_dequeue(&tmpq))) ++ __skb_queue_tail(&errq, skb); ++ np->stats.rx_errors++; ++ i = np->rx.rsp_cons; ++ continue; ++ } ++ ++ skb = __skb_dequeue(&tmpq); ++ ++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { ++ struct netif_extra_info *gso; ++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; ++ ++ if (unlikely(xennet_set_skb_gso(skb, gso))) { ++ __skb_queue_head(&tmpq, skb); ++ np->rx.rsp_cons += skb_queue_len(&tmpq); ++ goto err; ++ } ++ } ++ ++ NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page; ++ NETFRONT_SKB_CB(skb)->offset = rx->offset; ++ ++ len = rx->status; ++ if (len > RX_COPY_THRESHOLD) ++ len = RX_COPY_THRESHOLD; ++ skb_put(skb, len); ++ ++ if (rx->status > len) { ++ skb_shinfo(skb)->frags[0].page_offset = ++ rx->offset + len; ++ skb_shinfo(skb)->frags[0].size = rx->status - len; ++ skb->data_len = rx->status - len; ++ } else { ++ skb_shinfo(skb)->frags[0].page = NULL; ++ skb_shinfo(skb)->nr_frags = 0; ++ } ++ ++ i = xennet_fill_frags(np, skb, &tmpq); ++ ++ /* ++ * Truesize must approximates the size of true data plus ++ * any supervisor overheads. Adding hypervisor overheads ++ * has been shown to significantly reduce achievable ++ * bandwidth with the default receive buffer size. It is ++ * therefore not wise to account for it here. ++ * ++ * After alloc_skb(RX_COPY_THRESHOLD), truesize is set to ++ * RX_COPY_THRESHOLD + the supervisor overheads. Here, we ++ * add the size of the data pulled in xennet_fill_frags(). ++ * ++ * We also adjust for any unused space in the main data ++ * area by subtracting (RX_COPY_THRESHOLD - len). This is ++ * especially important with drivers which split incoming ++ * packets into header and data, using only 66 bytes of ++ * the main data area (see the e1000 driver for example.) ++ * On such systems, without this last adjustement, our ++ * achievable receive throughout using the standard receive ++ * buffer size was cut by 25%(!!!). ++ */ ++ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len); ++ skb->len += skb->data_len; ++ ++ /* ++ * Old backends do not assert data_validated but we ++ * can infer it from csum_blank so test both flags. ++ */ ++ if (rx->flags & (NETRXF_data_validated|NETRXF_csum_blank)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++#ifdef CONFIG_XEN ++ skb->proto_data_valid = (skb->ip_summed != CHECKSUM_NONE); ++ skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank); ++#endif ++ np->stats.rx_packets++; ++ np->stats.rx_bytes += skb->len; ++ ++ __skb_queue_tail(&rxq, skb); ++ ++ np->rx.rsp_cons = ++i; ++ work_done++; ++ } ++ ++ if (pages_flipped) { ++ /* Some pages are no longer absent... */ ++ balloon_update_driver_allowance(-pages_flipped); ++ ++ /* Do all the remapping work and M2P updates. */ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ mcl = np->rx_mcl + pages_flipped; ++ mcl->op = __HYPERVISOR_mmu_update; ++ mcl->args[0] = (unsigned long)np->rx_mmu; ++ mcl->args[1] = pages_flipped; ++ mcl->args[2] = 0; ++ mcl->args[3] = DOMID_SELF; ++ (void)HYPERVISOR_multicall(np->rx_mcl, ++ pages_flipped + 1); ++ } ++ } ++ ++ while ((skb = __skb_dequeue(&errq))) ++ kfree_skb(skb); ++ ++ while ((skb = __skb_dequeue(&rxq)) != NULL) { ++ struct page *page = NETFRONT_SKB_CB(skb)->page; ++ void *vaddr = page_address(page); ++ unsigned offset = NETFRONT_SKB_CB(skb)->offset; ++ ++ memcpy(skb->data, vaddr + offset, skb_headlen(skb)); ++ ++ if (page != skb_shinfo(skb)->frags[0].page) ++ __free_page(page); ++ ++ /* Ethernet work: Delayed to here as it peeks the header. */ ++ skb->protocol = eth_type_trans(skb, dev); ++ ++ /* Pass it up. */ ++ netif_receive_skb(skb); ++ dev->last_rx = jiffies; ++ } ++ ++ /* If we get a callback with very few responses, reduce fill target. */ ++ /* NB. Note exponential increase, linear decrease. */ ++ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > ++ ((3*np->rx_target) / 4)) && ++ (--np->rx_target < np->rx_min_target)) ++ np->rx_target = np->rx_min_target; ++ ++ network_alloc_rx_buffers(dev); ++ ++ *pbudget -= work_done; ++ dev->quota -= work_done; ++ ++ if (work_done < budget) { ++ local_irq_save(flags); ++ ++ RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); ++ if (!more_to_do) ++ __netif_rx_complete(dev); ++ ++ local_irq_restore(flags); ++ } ++ ++ spin_unlock(&np->rx_lock); ++ ++ return more_to_do; ++} ++ ++static void netif_release_tx_bufs(struct netfront_info *np) ++{ ++ struct sk_buff *skb; ++ int i; ++ ++ for (i = 1; i <= NET_TX_RING_SIZE; i++) { ++ if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET) ++ continue; ++ ++ skb = np->tx_skbs[i]; ++ gnttab_end_foreign_access_ref( ++ np->grant_tx_ref[i], GNTMAP_readonly); ++ gnttab_release_grant_reference( ++ &np->gref_tx_head, np->grant_tx_ref[i]); ++ np->grant_tx_ref[i] = GRANT_INVALID_REF; ++ add_id_to_freelist(np->tx_skbs, i); ++ dev_kfree_skb_irq(skb); ++ } ++} ++ ++static void netif_release_rx_bufs(struct netfront_info *np) ++{ ++ struct mmu_update *mmu = np->rx_mmu; ++ struct multicall_entry *mcl = np->rx_mcl; ++ struct sk_buff_head free_list; ++ struct sk_buff *skb; ++ unsigned long mfn; ++ int xfer = 0, noxfer = 0, unused = 0; ++ int id, ref, rc; ++ ++ if (np->copying_receiver) { ++ WPRINTK("%s: fix me for copying receiver.\n", __FUNCTION__); ++ return; ++ } ++ ++ skb_queue_head_init(&free_list); ++ ++ spin_lock_bh(&np->rx_lock); ++ ++ for (id = 0; id < NET_RX_RING_SIZE; id++) { ++ if ((ref = np->grant_rx_ref[id]) == GRANT_INVALID_REF) { ++ unused++; ++ continue; ++ } ++ ++ skb = np->rx_skbs[id]; ++ mfn = gnttab_end_foreign_transfer_ref(ref); ++ gnttab_release_grant_reference(&np->gref_rx_head, ref); ++ np->grant_rx_ref[id] = GRANT_INVALID_REF; ++ add_id_to_freelist(np->rx_skbs, id); ++ ++ if (0 == mfn) { ++ struct page *page = skb_shinfo(skb)->frags[0].page; ++ balloon_release_driver_page(page); ++ skb_shinfo(skb)->nr_frags = 0; ++ dev_kfree_skb(skb); ++ noxfer++; ++ continue; ++ } ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Remap the page. */ ++ struct page *page = skb_shinfo(skb)->frags[0].page; ++ unsigned long pfn = page_to_pfn(page); ++ void *vaddr = page_address(page); ++ ++ MULTI_update_va_mapping(mcl, (unsigned long)vaddr, ++ pfn_pte_ma(mfn, PAGE_KERNEL), ++ 0); ++ mcl++; ++ mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) ++ | MMU_MACHPHYS_UPDATE; ++ mmu->val = pfn; ++ mmu++; ++ ++ set_phys_to_machine(pfn, mfn); ++ } ++ __skb_queue_tail(&free_list, skb); ++ xfer++; ++ } ++ ++ IPRINTK("%s: %d xfer, %d noxfer, %d unused\n", ++ __FUNCTION__, xfer, noxfer, unused); ++ ++ if (xfer) { ++ /* Some pages are no longer absent... */ ++ balloon_update_driver_allowance(-xfer); ++ ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ /* Do all the remapping work and M2P updates. */ ++ mcl->op = __HYPERVISOR_mmu_update; ++ mcl->args[0] = (unsigned long)np->rx_mmu; ++ mcl->args[1] = mmu - np->rx_mmu; ++ mcl->args[2] = 0; ++ mcl->args[3] = DOMID_SELF; ++ mcl++; ++ rc = HYPERVISOR_multicall_check( ++ np->rx_mcl, mcl - np->rx_mcl, NULL); ++ BUG_ON(rc); ++ } ++ } ++ ++ while ((skb = __skb_dequeue(&free_list)) != NULL) ++ dev_kfree_skb(skb); ++ ++ spin_unlock_bh(&np->rx_lock); ++} ++ ++static int network_close(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ netif_stop_queue(np->netdev); ++ return 0; ++} ++ ++ ++static struct net_device_stats *network_get_stats(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ return &np->stats; ++} ++ ++static int xennet_change_mtu(struct net_device *dev, int mtu) ++{ ++ int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN; ++ ++ if (mtu > max) ++ return -EINVAL; ++ dev->mtu = mtu; ++ return 0; ++} ++ ++static int xennet_set_sg(struct net_device *dev, u32 data) ++{ ++ if (data) { ++ struct netfront_info *np = netdev_priv(dev); ++ int val; ++ ++ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", ++ "%d", &val) < 0) ++ val = 0; ++ if (!val) ++ return -ENOSYS; ++ } else if (dev->mtu > ETH_DATA_LEN) ++ dev->mtu = ETH_DATA_LEN; ++ ++ return ethtool_op_set_sg(dev, data); ++} ++ ++static int xennet_set_tso(struct net_device *dev, u32 data) ++{ ++#ifdef HAVE_TSO ++ if (data) { ++ struct netfront_info *np = netdev_priv(dev); ++ int val; ++ ++ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, ++ "feature-gso-tcpv4", "%d", &val) < 0) ++ val = 0; ++ if (!val) ++ return -ENOSYS; ++ } ++ ++ return ethtool_op_set_tso(dev, data); ++#else ++ return -ENOSYS; ++#endif ++} ++ ++static void xennet_set_features(struct net_device *dev) ++{ ++ dev_disable_gso_features(dev); ++ xennet_set_sg(dev, 0); ++ ++ /* We need checksum offload to enable scatter/gather and TSO. */ ++ if (!(dev->features & NETIF_F_IP_CSUM)) ++ return; ++ ++ if (xennet_set_sg(dev, 1)) ++ return; ++ ++ /* Before 2.6.9 TSO seems to be unreliable so do not enable it ++ * on older kernels. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) ++ xennet_set_tso(dev, 1); ++#endif ++ ++} ++ ++static int network_connect(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ int i, requeue_idx, err; ++ struct sk_buff *skb; ++ grant_ref_t ref; ++ netif_rx_request_t *req; ++ unsigned int feature_rx_copy, feature_rx_flip; ++ ++ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, ++ "feature-rx-copy", "%u", &feature_rx_copy); ++ if (err != 1) ++ feature_rx_copy = 0; ++ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, ++ "feature-rx-flip", "%u", &feature_rx_flip); ++ if (err != 1) ++ feature_rx_flip = 1; ++ ++ /* ++ * Copy packets on receive path if: ++ * (a) This was requested by user, and the backend supports it; or ++ * (b) Flipping was requested, but this is unsupported by the backend. ++ */ ++ np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) || ++ (MODPARM_rx_flip && !feature_rx_flip)); ++ ++ err = talk_to_backend(np->xbdev, np); ++ if (err) ++ return err; ++ ++ xennet_set_features(dev); ++ ++ IPRINTK("device %s has %sing receive path.\n", ++ dev->name, np->copying_receiver ? "copy" : "flipp"); ++ ++ spin_lock_bh(&np->rx_lock); ++ spin_lock_irq(&np->tx_lock); ++ ++ /* ++ * Recovery procedure: ++ * NB. Freelist index entries are always going to be less than ++ * PAGE_OFFSET, whereas pointers to skbs will always be equal or ++ * greater than PAGE_OFFSET: we use this property to distinguish ++ * them. ++ */ ++ ++ /* Step 1: Discard all pending TX packet fragments. */ ++ netif_release_tx_bufs(np); ++ ++ /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ ++ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { ++ if (!np->rx_skbs[i]) ++ continue; ++ ++ skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i); ++ ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); ++ req = RING_GET_REQUEST(&np->rx, requeue_idx); ++ ++ if (!np->copying_receiver) { ++ gnttab_grant_foreign_transfer_ref( ++ ref, np->xbdev->otherend_id, ++ page_to_pfn(skb_shinfo(skb)->frags->page)); ++ } else { ++ gnttab_grant_foreign_access_ref( ++ ref, np->xbdev->otherend_id, ++ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)-> ++ frags->page)), ++ 0); ++ } ++ req->gref = ref; ++ req->id = requeue_idx; ++ ++ requeue_idx++; ++ } ++ ++ np->rx.req_prod_pvt = requeue_idx; ++ ++ /* ++ * Step 3: All public and private state should now be sane. Get ++ * ready to start sending and receiving packets and give the driver ++ * domain a kick because we've probably just requeued some ++ * packets. ++ */ ++ netfront_carrier_on(np); ++ notify_remote_via_irq(np->irq); ++ network_tx_buf_gc(dev); ++ network_alloc_rx_buffers(dev); ++ ++ spin_unlock_irq(&np->tx_lock); ++ spin_unlock_bh(&np->rx_lock); ++ ++ return 0; ++} ++ ++static void netif_uninit(struct net_device *dev) ++{ ++ struct netfront_info *np = netdev_priv(dev); ++ netif_release_tx_bufs(np); ++ netif_release_rx_bufs(np); ++ gnttab_free_grant_references(np->gref_tx_head); ++ gnttab_free_grant_references(np->gref_rx_head); ++} ++ ++static struct ethtool_ops network_ethtool_ops = ++{ ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = ethtool_op_set_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = xennet_set_sg, ++ .get_tso = ethtool_op_get_tso, ++ .set_tso = xennet_set_tso, ++ .get_link = ethtool_op_get_link, ++}; ++ ++#ifdef CONFIG_SYSFS ++static ssize_t show_rxbuf_min(struct class_device *cd, char *buf) ++{ ++ struct net_device *netdev = container_of(cd, struct net_device, ++ class_dev); ++ struct netfront_info *info = netdev_priv(netdev); ++ ++ return sprintf(buf, "%u\n", info->rx_min_target); ++} ++ ++static ssize_t store_rxbuf_min(struct class_device *cd, ++ const char *buf, size_t len) ++{ ++ struct net_device *netdev = container_of(cd, struct net_device, ++ class_dev); ++ struct netfront_info *np = netdev_priv(netdev); ++ char *endp; ++ unsigned long target; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ target = simple_strtoul(buf, &endp, 0); ++ if (endp == buf) ++ return -EBADMSG; ++ ++ if (target < RX_MIN_TARGET) ++ target = RX_MIN_TARGET; ++ if (target > RX_MAX_TARGET) ++ target = RX_MAX_TARGET; ++ ++ spin_lock_bh(&np->rx_lock); ++ if (target > np->rx_max_target) ++ np->rx_max_target = target; ++ np->rx_min_target = target; ++ if (target > np->rx_target) ++ np->rx_target = target; ++ ++ network_alloc_rx_buffers(netdev); ++ ++ spin_unlock_bh(&np->rx_lock); ++ return len; ++} ++ ++static ssize_t show_rxbuf_max(struct class_device *cd, char *buf) ++{ ++ struct net_device *netdev = container_of(cd, struct net_device, ++ class_dev); ++ struct netfront_info *info = netdev_priv(netdev); ++ ++ return sprintf(buf, "%u\n", info->rx_max_target); ++} ++ ++static ssize_t store_rxbuf_max(struct class_device *cd, ++ const char *buf, size_t len) ++{ ++ struct net_device *netdev = container_of(cd, struct net_device, ++ class_dev); ++ struct netfront_info *np = netdev_priv(netdev); ++ char *endp; ++ unsigned long target; ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ target = simple_strtoul(buf, &endp, 0); ++ if (endp == buf) ++ return -EBADMSG; ++ ++ if (target < RX_MIN_TARGET) ++ target = RX_MIN_TARGET; ++ if (target > RX_MAX_TARGET) ++ target = RX_MAX_TARGET; ++ ++ spin_lock_bh(&np->rx_lock); ++ if (target < np->rx_min_target) ++ np->rx_min_target = target; ++ np->rx_max_target = target; ++ if (target < np->rx_target) ++ np->rx_target = target; ++ ++ network_alloc_rx_buffers(netdev); ++ ++ spin_unlock_bh(&np->rx_lock); ++ return len; ++} ++ ++static ssize_t show_rxbuf_cur(struct class_device *cd, char *buf) ++{ ++ struct net_device *netdev = container_of(cd, struct net_device, ++ class_dev); ++ struct netfront_info *info = netdev_priv(netdev); ++ ++ return sprintf(buf, "%u\n", info->rx_target); ++} ++ ++static const struct class_device_attribute xennet_attrs[] = { ++ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min), ++ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max), ++ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL), ++}; ++ ++static int xennet_sysfs_addif(struct net_device *netdev) ++{ ++ int i; ++ int error = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { ++ error = class_device_create_file(&netdev->class_dev, ++ &xennet_attrs[i]); ++ if (error) ++ goto fail; ++ } ++ return 0; ++ ++ fail: ++ while (--i >= 0) ++ class_device_remove_file(&netdev->class_dev, ++ &xennet_attrs[i]); ++ return error; ++} ++ ++static void xennet_sysfs_delif(struct net_device *netdev) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { ++ class_device_remove_file(&netdev->class_dev, ++ &xennet_attrs[i]); ++ } ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++ ++/* ++ * Nothing to do here. Virtual interface is point-to-point and the ++ * physical interface is probably promiscuous anyway. ++ */ ++static void network_set_multicast_list(struct net_device *dev) ++{ ++} ++ ++static struct net_device * __devinit create_netdev(struct xenbus_device *dev) ++{ ++ int i, err = 0; ++ struct net_device *netdev = NULL; ++ struct netfront_info *np = NULL; ++ ++ netdev = alloc_etherdev(sizeof(struct netfront_info)); ++ if (!netdev) { ++ printk(KERN_WARNING "%s> alloc_etherdev failed.\n", ++ __FUNCTION__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ np = netdev_priv(netdev); ++ np->xbdev = dev; ++ ++ spin_lock_init(&np->tx_lock); ++ spin_lock_init(&np->rx_lock); ++ ++ skb_queue_head_init(&np->rx_batch); ++ np->rx_target = RX_DFL_MIN_TARGET; ++ np->rx_min_target = RX_DFL_MIN_TARGET; ++ np->rx_max_target = RX_MAX_TARGET; ++ ++ init_timer(&np->rx_refill_timer); ++ np->rx_refill_timer.data = (unsigned long)netdev; ++ np->rx_refill_timer.function = rx_refill_timeout; ++ ++ /* Initialise {tx,rx}_skbs as a free chain containing every entry. */ ++ for (i = 0; i <= NET_TX_RING_SIZE; i++) { ++ np->tx_skbs[i] = (void *)((unsigned long) i+1); ++ np->grant_tx_ref[i] = GRANT_INVALID_REF; ++ } ++ ++ for (i = 0; i < NET_RX_RING_SIZE; i++) { ++ np->rx_skbs[i] = NULL; ++ np->grant_rx_ref[i] = GRANT_INVALID_REF; ++ } ++ ++ /* A grant for every tx ring slot */ ++ if (gnttab_alloc_grant_references(TX_MAX_TARGET, ++ &np->gref_tx_head) < 0) { ++ printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ /* A grant for every rx ring slot */ ++ if (gnttab_alloc_grant_references(RX_MAX_TARGET, ++ &np->gref_rx_head) < 0) { ++ printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n"); ++ err = -ENOMEM; ++ goto exit_free_tx; ++ } ++ ++ netdev->open = network_open; ++ netdev->hard_start_xmit = network_start_xmit; ++ netdev->stop = network_close; ++ netdev->get_stats = network_get_stats; ++ netdev->poll = netif_poll; ++ netdev->set_multicast_list = network_set_multicast_list; ++ netdev->uninit = netif_uninit; ++ netdev->change_mtu = xennet_change_mtu; ++ netdev->weight = 64; ++ netdev->features = NETIF_F_IP_CSUM; ++ ++ SET_ETHTOOL_OPS(netdev, &network_ethtool_ops); ++ SET_MODULE_OWNER(netdev); ++ SET_NETDEV_DEV(netdev, &dev->dev); ++ ++ np->netdev = netdev; ++ ++ netfront_carrier_off(np); ++ ++ return netdev; ++ ++ exit_free_tx: ++ gnttab_free_grant_references(np->gref_tx_head); ++ exit: ++ free_netdev(netdev); ++ return ERR_PTR(err); ++} ++ ++/* ++ * We use this notifier to send out a fake ARP reply to reset switches and ++ * router ARP caches when an IP interface is brought up on a VIF. ++ */ ++static int ++inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ struct net_device *dev = ifa->ifa_dev->dev; ++ ++ /* UP event and is it one of our devices? */ ++ if (event == NETDEV_UP && dev->open == network_open) ++ (void)send_fake_arp(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++ ++static void netif_disconnect_backend(struct netfront_info *info) ++{ ++ /* Stop old i/f to prevent errors whilst we rebuild the state. */ ++ spin_lock_bh(&info->rx_lock); ++ spin_lock_irq(&info->tx_lock); ++ netfront_carrier_off(info); ++ spin_unlock_irq(&info->tx_lock); ++ spin_unlock_bh(&info->rx_lock); ++ ++ if (info->irq) ++ unbind_from_irqhandler(info->irq, info->netdev); ++ info->irq = 0; ++ ++ end_access(info->tx_ring_ref, info->tx.sring); ++ end_access(info->rx_ring_ref, info->rx.sring); ++ info->tx_ring_ref = GRANT_INVALID_REF; ++ info->rx_ring_ref = GRANT_INVALID_REF; ++ info->tx.sring = NULL; ++ info->rx.sring = NULL; ++} ++ ++ ++static void end_access(int ref, void *page) ++{ ++ if (ref != GRANT_INVALID_REF) ++ gnttab_end_foreign_access(ref, 0, (unsigned long)page); ++} ++ ++ ++/* ** Driver registration ** */ ++ ++ ++static struct xenbus_device_id netfront_ids[] = { ++ { "vif" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver netfront = { ++ .name = "vif", ++ .owner = THIS_MODULE, ++ .ids = netfront_ids, ++ .probe = netfront_probe, ++ .remove = __devexit_p(netfront_remove), ++ .resume = netfront_resume, ++ .otherend_changed = backend_changed, ++}; ++ ++ ++static struct notifier_block notifier_inetdev = { ++ .notifier_call = inetdev_notify, ++ .next = NULL, ++ .priority = 0 ++}; ++ ++static int __init netif_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++#ifdef CONFIG_XEN ++ if (MODPARM_rx_flip && MODPARM_rx_copy) { ++ WPRINTK("Cannot specify both rx_copy and rx_flip.\n"); ++ return -EINVAL; ++ } ++ ++ if (!MODPARM_rx_flip && !MODPARM_rx_copy) ++ MODPARM_rx_flip = 1; /* Default is to flip. */ ++#endif ++ ++ if (is_initial_xendomain()) ++ return 0; ++ ++ IPRINTK("Initialising virtual ethernet driver.\n"); ++ ++ (void)register_inetaddr_notifier(¬ifier_inetdev); ++ ++ return xenbus_register_frontend(&netfront); ++} ++module_init(netif_init); ++ ++ ++static void __exit netif_exit(void) ++{ ++ if (is_initial_xendomain()) ++ return; ++ ++ unregister_inetaddr_notifier(¬ifier_inetdev); ++ ++ return xenbus_unregister_driver(&netfront); ++} ++module_exit(netif_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,15 @@ ++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o ++ ++pciback-y := pci_stub.o pciback_ops.o xenbus.o ++pciback-y += conf_space.o conf_space_header.o \ ++ conf_space_capability.o \ ++ conf_space_capability_vpd.o \ ++ conf_space_capability_pm.o \ ++ conf_space_quirks.o ++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o ++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o ++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o ++ ++ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y) ++EXTRA_CFLAGS += -DDEBUG ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,426 @@ ++/* ++ * PCI Backend - Functions for creating a virtual configuration space for ++ * exported PCI Devices. ++ * It's dangerous to allow PCI Driver Domains to change their ++ * device's resources (memory, i/o ports, interrupts). We need to ++ * restrict changes to certain PCI Configuration registers: ++ * BARs, INTERRUPT_PIN, most registers in the header... ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include "pciback.h" ++#include "conf_space.h" ++#include "conf_space_quirks.h" ++ ++#define DEFINE_PCI_CONFIG(op,size,type) \ ++int pciback_##op##_config_##size \ ++(struct pci_dev *dev, int offset, type value, void *data) \ ++{ \ ++ return pci_##op##_config_##size (dev, offset, value); \ ++} ++ ++DEFINE_PCI_CONFIG(read, byte, u8 *) ++DEFINE_PCI_CONFIG(read, word, u16 *) ++DEFINE_PCI_CONFIG(read, dword, u32 *) ++ ++DEFINE_PCI_CONFIG(write, byte, u8) ++DEFINE_PCI_CONFIG(write, word, u16) ++DEFINE_PCI_CONFIG(write, dword, u32) ++ ++static int conf_space_read(struct pci_dev *dev, ++ struct config_field_entry *entry, int offset, ++ u32 * value) ++{ ++ int ret = 0; ++ struct config_field *field = entry->field; ++ ++ *value = 0; ++ ++ switch (field->size) { ++ case 1: ++ if (field->u.b.read) ++ ret = field->u.b.read(dev, offset, (u8 *) value, ++ entry->data); ++ break; ++ case 2: ++ if (field->u.w.read) ++ ret = field->u.w.read(dev, offset, (u16 *) value, ++ entry->data); ++ break; ++ case 4: ++ if (field->u.dw.read) ++ ret = field->u.dw.read(dev, offset, value, entry->data); ++ break; ++ } ++ return ret; ++} ++ ++static int conf_space_write(struct pci_dev *dev, ++ struct config_field_entry *entry, int offset, ++ u32 value) ++{ ++ int ret = 0; ++ struct config_field *field = entry->field; ++ ++ switch (field->size) { ++ case 1: ++ if (field->u.b.write) ++ ret = field->u.b.write(dev, offset, (u8) value, ++ entry->data); ++ break; ++ case 2: ++ if (field->u.w.write) ++ ret = field->u.w.write(dev, offset, (u16) value, ++ entry->data); ++ break; ++ case 4: ++ if (field->u.dw.write) ++ ret = field->u.dw.write(dev, offset, value, ++ entry->data); ++ break; ++ } ++ return ret; ++} ++ ++static inline u32 get_mask(int size) ++{ ++ if (size == 1) ++ return 0xff; ++ else if (size == 2) ++ return 0xffff; ++ else ++ return 0xffffffff; ++} ++ ++static inline int valid_request(int offset, int size) ++{ ++ /* Validate request (no un-aligned requests) */ ++ if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0) ++ return 1; ++ return 0; ++} ++ ++static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask, ++ int offset) ++{ ++ if (offset >= 0) { ++ new_val_mask <<= (offset * 8); ++ new_val <<= (offset * 8); ++ } else { ++ new_val_mask >>= (offset * -8); ++ new_val >>= (offset * -8); ++ } ++ val = (val & ~new_val_mask) | (new_val & new_val_mask); ++ ++ return val; ++} ++ ++static int pcibios_err_to_errno(int err) ++{ ++ switch (err) { ++ case PCIBIOS_SUCCESSFUL: ++ return XEN_PCI_ERR_success; ++ case PCIBIOS_DEVICE_NOT_FOUND: ++ return XEN_PCI_ERR_dev_not_found; ++ case PCIBIOS_BAD_REGISTER_NUMBER: ++ return XEN_PCI_ERR_invalid_offset; ++ case PCIBIOS_FUNC_NOT_SUPPORTED: ++ return XEN_PCI_ERR_not_implemented; ++ case PCIBIOS_SET_FAILED: ++ return XEN_PCI_ERR_access_denied; ++ } ++ return err; ++} ++ ++int pciback_config_read(struct pci_dev *dev, int offset, int size, ++ u32 * ret_val) ++{ ++ int err = 0; ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry; ++ struct config_field *field; ++ int req_start, req_end, field_start, field_end; ++ /* if read fails for any reason, return 0 (as if device didn't respond) */ ++ u32 value = 0, tmp_val; ++ ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n", ++ pci_name(dev), size, offset); ++ ++ if (!valid_request(offset, size)) { ++ err = XEN_PCI_ERR_invalid_offset; ++ goto out; ++ } ++ ++ /* Get the real value first, then modify as appropriate */ ++ switch (size) { ++ case 1: ++ err = pci_read_config_byte(dev, offset, (u8 *) & value); ++ break; ++ case 2: ++ err = pci_read_config_word(dev, offset, (u16 *) & value); ++ break; ++ case 4: ++ err = pci_read_config_dword(dev, offset, &value); ++ break; ++ } ++ ++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { ++ field = cfg_entry->field; ++ ++ req_start = offset; ++ req_end = offset + size; ++ field_start = OFFSET(cfg_entry); ++ field_end = OFFSET(cfg_entry) + field->size; ++ ++ if ((req_start >= field_start && req_start < field_end) ++ || (req_end > field_start && req_end <= field_end)) { ++ err = conf_space_read(dev, cfg_entry, field_start, ++ &tmp_val); ++ if (err) ++ goto out; ++ ++ value = merge_value(value, tmp_val, ++ get_mask(field->size), ++ field_start - req_start); ++ } ++ } ++ ++ out: ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n", ++ pci_name(dev), size, offset, value); ++ ++ *ret_val = value; ++ return pcibios_err_to_errno(err); ++} ++ ++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value) ++{ ++ int err = 0, handled = 0; ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry; ++ struct config_field *field; ++ u32 tmp_val; ++ int req_start, req_end, field_start, field_end; ++ ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG ++ "pciback: %s: write request %d bytes at 0x%x = %x\n", ++ pci_name(dev), size, offset, value); ++ ++ if (!valid_request(offset, size)) ++ return XEN_PCI_ERR_invalid_offset; ++ ++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { ++ field = cfg_entry->field; ++ ++ req_start = offset; ++ req_end = offset + size; ++ field_start = OFFSET(cfg_entry); ++ field_end = OFFSET(cfg_entry) + field->size; ++ ++ if ((req_start >= field_start && req_start < field_end) ++ || (req_end > field_start && req_end <= field_end)) { ++ tmp_val = 0; ++ ++ err = pciback_config_read(dev, field_start, ++ field->size, &tmp_val); ++ if (err) ++ break; ++ ++ tmp_val = merge_value(tmp_val, value, get_mask(size), ++ req_start - field_start); ++ ++ err = conf_space_write(dev, cfg_entry, field_start, ++ tmp_val); ++ ++ /* handled is set true here, but not every byte ++ * may have been written! Properly detecting if ++ * every byte is handled is unnecessary as the ++ * flag is used to detect devices that need ++ * special helpers to work correctly. ++ */ ++ handled = 1; ++ } ++ } ++ ++ if (!handled && !err) { ++ /* By default, anything not specificially handled above is ++ * read-only. The permissive flag changes this behavior so ++ * that anything not specifically handled above is writable. ++ * This means that some fields may still be read-only because ++ * they have entries in the config_field list that intercept ++ * the write and do nothing. */ ++ if (dev_data->permissive) { ++ switch (size) { ++ case 1: ++ err = pci_write_config_byte(dev, offset, ++ (u8) value); ++ break; ++ case 2: ++ err = pci_write_config_word(dev, offset, ++ (u16) value); ++ break; ++ case 4: ++ err = pci_write_config_dword(dev, offset, ++ (u32) value); ++ break; ++ } ++ } else if (!dev_data->warned_on_write) { ++ dev_data->warned_on_write = 1; ++ dev_warn(&dev->dev, "Driver tried to write to a " ++ "read-only configuration space field at offset " ++ "0x%x, size %d. This may be harmless, but if " ++ "you have problems with your device:\n" ++ "1) see permissive attribute in sysfs\n" ++ "2) report problems to the xen-devel " ++ "mailing list along with details of your " ++ "device obtained from lspci.\n", offset, size); ++ } ++ } ++ ++ return pcibios_err_to_errno(err); ++} ++ ++void pciback_config_free_dyn_fields(struct pci_dev *dev) ++{ ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry, *t; ++ struct config_field *field; ++ ++ dev_dbg(&dev->dev, ++ "free-ing dynamically allocated virtual configuration space fields\n"); ++ ++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) { ++ field = cfg_entry->field; ++ ++ if (field->clean) { ++ field->clean(field); ++ ++ if (cfg_entry->data) ++ kfree(cfg_entry->data); ++ ++ list_del(&cfg_entry->list); ++ kfree(cfg_entry); ++ } ++ ++ } ++} ++ ++void pciback_config_reset_dev(struct pci_dev *dev) ++{ ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry; ++ struct config_field *field; ++ ++ dev_dbg(&dev->dev, "resetting virtual configuration space\n"); ++ ++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { ++ field = cfg_entry->field; ++ ++ if (field->reset) ++ field->reset(dev, OFFSET(cfg_entry), cfg_entry->data); ++ } ++} ++ ++void pciback_config_free_dev(struct pci_dev *dev) ++{ ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry, *t; ++ struct config_field *field; ++ ++ dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n"); ++ ++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) { ++ list_del(&cfg_entry->list); ++ ++ field = cfg_entry->field; ++ ++ if (field->release) ++ field->release(dev, OFFSET(cfg_entry), cfg_entry->data); ++ ++ kfree(cfg_entry); ++ } ++} ++ ++int pciback_config_add_field_offset(struct pci_dev *dev, ++ struct config_field *field, ++ unsigned int base_offset) ++{ ++ int err = 0; ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry; ++ void *tmp; ++ ++ cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL); ++ if (!cfg_entry) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ cfg_entry->data = NULL; ++ cfg_entry->field = field; ++ cfg_entry->base_offset = base_offset; ++ ++ /* silently ignore duplicate fields */ ++ err = pciback_field_is_dup(dev,OFFSET(cfg_entry)); ++ if (err) ++ goto out; ++ ++ if (field->init) { ++ tmp = field->init(dev, OFFSET(cfg_entry)); ++ ++ if (IS_ERR(tmp)) { ++ err = PTR_ERR(tmp); ++ goto out; ++ } ++ ++ cfg_entry->data = tmp; ++ } ++ ++ dev_dbg(&dev->dev, "added config field at offset 0x%02x\n", ++ OFFSET(cfg_entry)); ++ list_add_tail(&cfg_entry->list, &dev_data->config_fields); ++ ++ out: ++ if (err) ++ kfree(cfg_entry); ++ ++ return err; ++} ++ ++/* This sets up the device's virtual configuration space to keep track of ++ * certain registers (like the base address registers (BARs) so that we can ++ * keep the client from manipulating them directly. ++ */ ++int pciback_config_init_dev(struct pci_dev *dev) ++{ ++ int err = 0; ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ ++ dev_dbg(&dev->dev, "initializing virtual configuration space\n"); ++ ++ INIT_LIST_HEAD(&dev_data->config_fields); ++ ++ err = pciback_config_header_add_fields(dev); ++ if (err) ++ goto out; ++ ++ err = pciback_config_capability_add_fields(dev); ++ if (err) ++ goto out; ++ ++ err = pciback_config_quirks_init(dev); ++ ++ out: ++ return err; ++} ++ ++int pciback_config_init(void) ++{ ++ return pciback_config_capability_init(); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,126 @@ ++/* ++ * PCI Backend - Common data structures for overriding the configuration space ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#ifndef __XEN_PCIBACK_CONF_SPACE_H__ ++#define __XEN_PCIBACK_CONF_SPACE_H__ ++ ++#include <linux/list.h> ++#include <linux/err.h> ++ ++/* conf_field_init can return an errno in a ptr with ERR_PTR() */ ++typedef void *(*conf_field_init) (struct pci_dev * dev, int offset); ++typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data); ++typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data); ++ ++typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value, ++ void *data); ++typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value, ++ void *data); ++typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value, ++ void *data); ++typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value, ++ void *data); ++typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value, ++ void *data); ++typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value, ++ void *data); ++ ++/* These are the fields within the configuration space which we ++ * are interested in intercepting reads/writes to and changing their ++ * values. ++ */ ++struct config_field { ++ unsigned int offset; ++ unsigned int size; ++ unsigned int mask; ++ conf_field_init init; ++ conf_field_reset reset; ++ conf_field_free release; ++ void (*clean) (struct config_field * field); ++ union { ++ struct { ++ conf_dword_write write; ++ conf_dword_read read; ++ } dw; ++ struct { ++ conf_word_write write; ++ conf_word_read read; ++ } w; ++ struct { ++ conf_byte_write write; ++ conf_byte_read read; ++ } b; ++ } u; ++ struct list_head list; ++}; ++ ++struct config_field_entry { ++ struct list_head list; ++ struct config_field *field; ++ unsigned int base_offset; ++ void *data; ++}; ++ ++#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) ++ ++/* Add fields to a device - the add_fields macro expects to get a pointer to ++ * the first entry in an array (of which the ending is marked by size==0) ++ */ ++int pciback_config_add_field_offset(struct pci_dev *dev, ++ struct config_field *field, ++ unsigned int offset); ++ ++static inline int pciback_config_add_field(struct pci_dev *dev, ++ struct config_field *field) ++{ ++ return pciback_config_add_field_offset(dev, field, 0); ++} ++ ++static inline int pciback_config_add_fields(struct pci_dev *dev, ++ struct config_field *field) ++{ ++ int i, err = 0; ++ for (i = 0; field[i].size != 0; i++) { ++ err = pciback_config_add_field(dev, &field[i]); ++ if (err) ++ break; ++ } ++ return err; ++} ++ ++static inline int pciback_config_add_fields_offset(struct pci_dev *dev, ++ struct config_field *field, ++ unsigned int offset) ++{ ++ int i, err = 0; ++ for (i = 0; field[i].size != 0; i++) { ++ err = pciback_config_add_field_offset(dev, &field[i], offset); ++ if (err) ++ break; ++ } ++ return err; ++} ++ ++/* Read/Write the real configuration space */ ++int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value, ++ void *data); ++int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value, ++ void *data); ++int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value, ++ void *data); ++int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value, ++ void *data); ++int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value, ++ void *data); ++int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value, ++ void *data); ++ ++int pciback_config_capability_init(void); ++ ++int pciback_config_header_add_fields(struct pci_dev *dev); ++int pciback_config_capability_add_fields(struct pci_dev *dev); ++ ++#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_capability.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_capability.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,71 @@ ++/* ++ * PCI Backend - Handles the virtual fields found on the capability lists ++ * in the configuration space. ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include "pciback.h" ++#include "conf_space.h" ++#include "conf_space_capability.h" ++ ++static LIST_HEAD(capabilities); ++ ++static struct config_field caplist_header[] = { ++ { ++ .offset = PCI_CAP_LIST_ID, ++ .size = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */ ++ .u.w.read = pciback_read_config_word, ++ .u.w.write = NULL, ++ }, ++ { ++ .size = 0, ++ }, ++}; ++ ++static inline void register_capability(struct pciback_config_capability *cap) ++{ ++ list_add_tail(&cap->cap_list, &capabilities); ++} ++ ++int pciback_config_capability_add_fields(struct pci_dev *dev) ++{ ++ int err = 0; ++ struct pciback_config_capability *cap; ++ int cap_offset; ++ ++ list_for_each_entry(cap, &capabilities, cap_list) { ++ cap_offset = pci_find_capability(dev, cap->capability); ++ if (cap_offset) { ++ dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n", ++ cap->capability, cap_offset); ++ ++ err = pciback_config_add_fields_offset(dev, ++ caplist_header, ++ cap_offset); ++ if (err) ++ goto out; ++ err = pciback_config_add_fields_offset(dev, ++ cap->fields, ++ cap_offset); ++ if (err) ++ goto out; ++ } ++ } ++ ++ out: ++ return err; ++} ++ ++extern struct pciback_config_capability pciback_config_capability_vpd; ++extern struct pciback_config_capability pciback_config_capability_pm; ++ ++int pciback_config_capability_init(void) ++{ ++ register_capability(&pciback_config_capability_vpd); ++ register_capability(&pciback_config_capability_pm); ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_capability.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_capability.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,23 @@ ++/* ++ * PCI Backend - Data structures for special overlays for structures on ++ * the capability list. ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#ifndef __PCIBACK_CONFIG_CAPABILITY_H__ ++#define __PCIBACK_CONFIG_CAPABILITY_H__ ++ ++#include <linux/pci.h> ++#include <linux/list.h> ++ ++struct pciback_config_capability { ++ struct list_head cap_list; ++ ++ int capability; ++ ++ /* If the device has the capability found above, add these fields */ ++ struct config_field *fields; ++}; ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_capability_pm.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_capability_pm.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,128 @@ ++/* ++ * PCI Backend - Configuration space overlay for power management ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/pci.h> ++#include "conf_space.h" ++#include "conf_space_capability.h" ++ ++static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value, ++ void *data) ++{ ++ int err; ++ u16 real_value; ++ ++ err = pci_read_config_word(dev, offset, &real_value); ++ if (err) ++ goto out; ++ ++ *value = real_value & ~PCI_PM_CAP_PME_MASK; ++ ++ out: ++ return err; ++} ++ ++/* PM_OK_BITS specifies the bits that the driver domain is allowed to change. ++ * Can't allow driver domain to enable PMEs - they're shared */ ++#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK) ++ ++static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value, ++ void *data) ++{ ++ int err; ++ u16 old_value; ++ pci_power_t new_state, old_state; ++ ++ err = pci_read_config_word(dev, offset, &old_value); ++ if (err) ++ goto out; ++ ++ old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK); ++ new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK); ++ ++ new_value &= PM_OK_BITS; ++ if ((old_value & PM_OK_BITS) != new_value) { ++ new_value = (old_value & ~PM_OK_BITS) | new_value; ++ err = pci_write_config_word(dev, offset, new_value); ++ if (err) ++ goto out; ++ } ++ ++ /* Let pci core handle the power management change */ ++ dev_dbg(&dev->dev, "set power state to %x\n", new_state); ++ err = pci_set_power_state(dev, new_state); ++ if (err) { ++ err = PCIBIOS_SET_FAILED; ++ goto out; ++ } ++ ++ /* ++ * Device may lose PCI config info on D3->D0 transition. This ++ * is a problem for some guests which will not reset BARs. Even ++ * those that have a go will be foiled by our BAR-write handler ++ * which will discard the write! Since Linux won't re-init ++ * the config space automatically in all cases, we do it here. ++ * Future: Should we re-initialise all first 64 bytes of config space? ++ */ ++ if (new_state == PCI_D0 && ++ (old_state == PCI_D3hot || old_state == PCI_D3cold) && ++ !(old_value & PCI_PM_CTRL_NO_SOFT_RESET)) ++ pci_restore_bars(dev); ++ ++ out: ++ return err; ++} ++ ++/* Ensure PMEs are disabled */ ++static void *pm_ctrl_init(struct pci_dev *dev, int offset) ++{ ++ int err; ++ u16 value; ++ ++ err = pci_read_config_word(dev, offset, &value); ++ if (err) ++ goto out; ++ ++ if (value & PCI_PM_CTRL_PME_ENABLE) { ++ value &= ~PCI_PM_CTRL_PME_ENABLE; ++ err = pci_write_config_word(dev, offset, value); ++ } ++ ++ out: ++ return ERR_PTR(err); ++} ++ ++static struct config_field caplist_pm[] = { ++ { ++ .offset = PCI_PM_PMC, ++ .size = 2, ++ .u.w.read = pm_caps_read, ++ }, ++ { ++ .offset = PCI_PM_CTRL, ++ .size = 2, ++ .init = pm_ctrl_init, ++ .u.w.read = pciback_read_config_word, ++ .u.w.write = pm_ctrl_write, ++ }, ++ { ++ .offset = PCI_PM_PPB_EXTENSIONS, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ }, ++ { ++ .offset = PCI_PM_DATA_REGISTER, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ }, ++ { ++ .size = 0, ++ }, ++}; ++ ++struct pciback_config_capability pciback_config_capability_pm = { ++ .capability = PCI_CAP_ID_PM, ++ .fields = caplist_pm, ++}; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_capability_vpd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_capability_vpd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,42 @@ ++/* ++ * PCI Backend - Configuration space overlay for Vital Product Data ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/pci.h> ++#include "conf_space.h" ++#include "conf_space_capability.h" ++ ++static int vpd_address_write(struct pci_dev *dev, int offset, u16 value, ++ void *data) ++{ ++ /* Disallow writes to the vital product data */ ++ if (value & PCI_VPD_ADDR_F) ++ return PCIBIOS_SET_FAILED; ++ else ++ return pci_write_config_word(dev, offset, value); ++} ++ ++static struct config_field caplist_vpd[] = { ++ { ++ .offset = PCI_VPD_ADDR, ++ .size = 2, ++ .u.w.read = pciback_read_config_word, ++ .u.w.write = vpd_address_write, ++ }, ++ { ++ .offset = PCI_VPD_DATA, ++ .size = 4, ++ .u.dw.read = pciback_read_config_dword, ++ .u.dw.write = NULL, ++ }, ++ { ++ .size = 0, ++ }, ++}; ++ ++struct pciback_config_capability pciback_config_capability_vpd = { ++ .capability = PCI_CAP_ID_VPD, ++ .fields = caplist_vpd, ++}; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_header.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_header.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,309 @@ ++/* ++ * PCI Backend - Handles the virtual fields in the configuration space headers. ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include "pciback.h" ++#include "conf_space.h" ++ ++struct pci_bar_info { ++ u32 val; ++ u32 len_val; ++ int which; ++}; ++ ++#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) ++#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) ++ ++static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) ++{ ++ int err; ++ ++ if (!atomic_read(&dev->enable_cnt) && is_enable_cmd(value)) { ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG "pciback: %s: enable\n", ++ pci_name(dev)); ++ err = pci_enable_device(dev); ++ if (err) ++ return err; ++ } else if (atomic_read(&dev->enable_cnt) && !is_enable_cmd(value)) { ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG "pciback: %s: disable\n", ++ pci_name(dev)); ++ pci_disable_device(dev); ++ } ++ ++ if (!dev->is_busmaster && is_master_cmd(value)) { ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG "pciback: %s: set bus master\n", ++ pci_name(dev)); ++ pci_set_master(dev); ++ } ++ ++ if (value & PCI_COMMAND_INVALIDATE) { ++ if (unlikely(verbose_request)) ++ printk(KERN_DEBUG ++ "pciback: %s: enable memory-write-invalidate\n", ++ pci_name(dev)); ++ err = pci_set_mwi(dev); ++ if (err) { ++ printk(KERN_WARNING ++ "pciback: %s: cannot enable memory-write-invalidate (%d)\n", ++ pci_name(dev), err); ++ value &= ~PCI_COMMAND_INVALIDATE; ++ } ++ } ++ ++ return pci_write_config_word(dev, offset, value); ++} ++ ++static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data) ++{ ++ struct pci_bar_info *bar = data; ++ ++ if (unlikely(!bar)) { ++ printk(KERN_WARNING "pciback: driver data not found for %s\n", ++ pci_name(dev)); ++ return XEN_PCI_ERR_op_failed; ++ } ++ ++ /* A write to obtain the length must happen as a 32-bit write. ++ * This does not (yet) support writing individual bytes ++ */ ++ if (value == ~PCI_ROM_ADDRESS_ENABLE) ++ bar->which = 1; ++ else ++ bar->which = 0; ++ ++ /* Do we need to support enabling/disabling the rom address here? */ ++ ++ return 0; ++} ++ ++/* For the BARs, only allow writes which write ~0 or ++ * the correct resource information ++ * (Needed for when the driver probes the resource usage) ++ */ ++static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data) ++{ ++ struct pci_bar_info *bar = data; ++ ++ if (unlikely(!bar)) { ++ printk(KERN_WARNING "pciback: driver data not found for %s\n", ++ pci_name(dev)); ++ return XEN_PCI_ERR_op_failed; ++ } ++ ++ /* A write to obtain the length must happen as a 32-bit write. ++ * This does not (yet) support writing individual bytes ++ */ ++ if (value == ~0) ++ bar->which = 1; ++ else ++ bar->which = 0; ++ ++ return 0; ++} ++ ++static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data) ++{ ++ struct pci_bar_info *bar = data; ++ ++ if (unlikely(!bar)) { ++ printk(KERN_WARNING "pciback: driver data not found for %s\n", ++ pci_name(dev)); ++ return XEN_PCI_ERR_op_failed; ++ } ++ ++ *value = bar->which ? bar->len_val : bar->val; ++ ++ return 0; ++} ++ ++static inline void read_dev_bar(struct pci_dev *dev, ++ struct pci_bar_info *bar_info, int offset, ++ u32 len_mask) ++{ ++ pci_read_config_dword(dev, offset, &bar_info->val); ++ pci_write_config_dword(dev, offset, len_mask); ++ pci_read_config_dword(dev, offset, &bar_info->len_val); ++ pci_write_config_dword(dev, offset, bar_info->val); ++} ++ ++static void *bar_init(struct pci_dev *dev, int offset) ++{ ++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); ++ ++ if (!bar) ++ return ERR_PTR(-ENOMEM); ++ ++ read_dev_bar(dev, bar, offset, ~0); ++ bar->which = 0; ++ ++ return bar; ++} ++ ++static void *rom_init(struct pci_dev *dev, int offset) ++{ ++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); ++ ++ if (!bar) ++ return ERR_PTR(-ENOMEM); ++ ++ read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE); ++ bar->which = 0; ++ ++ return bar; ++} ++ ++static void bar_reset(struct pci_dev *dev, int offset, void *data) ++{ ++ struct pci_bar_info *bar = data; ++ ++ bar->which = 0; ++} ++ ++static void bar_release(struct pci_dev *dev, int offset, void *data) ++{ ++ kfree(data); ++} ++ ++static int interrupt_read(struct pci_dev *dev, int offset, u8 * value, ++ void *data) ++{ ++ *value = (u8) dev->irq; ++ ++ return 0; ++} ++ ++static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data) ++{ ++ u8 cur_value; ++ int err; ++ ++ err = pci_read_config_byte(dev, offset, &cur_value); ++ if (err) ++ goto out; ++ ++ if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START) ++ || value == PCI_BIST_START) ++ err = pci_write_config_byte(dev, offset, value); ++ ++ out: ++ return err; ++} ++ ++static struct config_field header_common[] = { ++ { ++ .offset = PCI_COMMAND, ++ .size = 2, ++ .u.w.read = pciback_read_config_word, ++ .u.w.write = command_write, ++ }, ++ { ++ .offset = PCI_INTERRUPT_LINE, ++ .size = 1, ++ .u.b.read = interrupt_read, ++ }, ++ { ++ .offset = PCI_INTERRUPT_PIN, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ }, ++ { ++ /* Any side effects of letting driver domain control cache line? */ ++ .offset = PCI_CACHE_LINE_SIZE, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ .u.b.write = pciback_write_config_byte, ++ }, ++ { ++ .offset = PCI_LATENCY_TIMER, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ }, ++ { ++ .offset = PCI_BIST, ++ .size = 1, ++ .u.b.read = pciback_read_config_byte, ++ .u.b.write = bist_write, ++ }, ++ { ++ .size = 0, ++ }, ++}; ++ ++#define CFG_FIELD_BAR(reg_offset) \ ++ { \ ++ .offset = reg_offset, \ ++ .size = 4, \ ++ .init = bar_init, \ ++ .reset = bar_reset, \ ++ .release = bar_release, \ ++ .u.dw.read = bar_read, \ ++ .u.dw.write = bar_write, \ ++ } ++ ++#define CFG_FIELD_ROM(reg_offset) \ ++ { \ ++ .offset = reg_offset, \ ++ .size = 4, \ ++ .init = rom_init, \ ++ .reset = bar_reset, \ ++ .release = bar_release, \ ++ .u.dw.read = bar_read, \ ++ .u.dw.write = rom_write, \ ++ } ++ ++static struct config_field header_0[] = { ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), ++ CFG_FIELD_ROM(PCI_ROM_ADDRESS), ++ { ++ .size = 0, ++ }, ++}; ++ ++static struct config_field header_1[] = { ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), ++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), ++ CFG_FIELD_ROM(PCI_ROM_ADDRESS1), ++ { ++ .size = 0, ++ }, ++}; ++ ++int pciback_config_header_add_fields(struct pci_dev *dev) ++{ ++ int err; ++ ++ err = pciback_config_add_fields(dev, header_common); ++ if (err) ++ goto out; ++ ++ switch (dev->hdr_type) { ++ case PCI_HEADER_TYPE_NORMAL: ++ err = pciback_config_add_fields(dev, header_0); ++ break; ++ ++ case PCI_HEADER_TYPE_BRIDGE: ++ err = pciback_config_add_fields(dev, header_1); ++ break; ++ ++ default: ++ err = -EINVAL; ++ printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n", ++ pci_name(dev), dev->hdr_type); ++ break; ++ } ++ ++ out: ++ return err; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_quirks.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_quirks.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,126 @@ ++/* ++ * PCI Backend - Handle special overlays for broken devices. ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ * Author: Chris Bookholt <hap10@epoch.ncsc.mil> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include "pciback.h" ++#include "conf_space.h" ++#include "conf_space_quirks.h" ++ ++LIST_HEAD(pciback_quirks); ++ ++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev) ++{ ++ struct pciback_config_quirk *tmp_quirk; ++ ++ list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list) ++ if (pci_match_id(&tmp_quirk->devid, dev)) ++ goto out; ++ tmp_quirk = NULL; ++ printk(KERN_DEBUG ++ "quirk didn't match any device pciback knows about\n"); ++ out: ++ return tmp_quirk; ++} ++ ++static inline void register_quirk(struct pciback_config_quirk *quirk) ++{ ++ list_add_tail(&quirk->quirks_list, &pciback_quirks); ++} ++ ++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg) ++{ ++ int ret = 0; ++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev); ++ struct config_field_entry *cfg_entry; ++ ++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { ++ if ( OFFSET(cfg_entry) == reg) { ++ ret = 1; ++ break; ++ } ++ } ++ return ret; ++} ++ ++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field ++ *field) ++{ ++ int err = 0; ++ ++ switch (field->size) { ++ case 1: ++ field->u.b.read = pciback_read_config_byte; ++ field->u.b.write = pciback_write_config_byte; ++ break; ++ case 2: ++ field->u.w.read = pciback_read_config_word; ++ field->u.w.write = pciback_write_config_word; ++ break; ++ case 4: ++ field->u.dw.read = pciback_read_config_dword; ++ field->u.dw.write = pciback_write_config_dword; ++ break; ++ default: ++ err = -EINVAL; ++ goto out; ++ } ++ ++ pciback_config_add_field(dev, field); ++ ++ out: ++ return err; ++} ++ ++int pciback_config_quirks_init(struct pci_dev *dev) ++{ ++ struct pciback_config_quirk *quirk; ++ int ret = 0; ++ ++ quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC); ++ if (!quirk) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ quirk->devid.vendor = dev->vendor; ++ quirk->devid.device = dev->device; ++ quirk->devid.subvendor = dev->subsystem_vendor; ++ quirk->devid.subdevice = dev->subsystem_device; ++ quirk->devid.class = 0; ++ quirk->devid.class_mask = 0; ++ quirk->devid.driver_data = 0UL; ++ ++ quirk->pdev = dev; ++ ++ register_quirk(quirk); ++ out: ++ return ret; ++} ++ ++void pciback_config_field_free(struct config_field *field) ++{ ++ kfree(field); ++} ++ ++int pciback_config_quirk_release(struct pci_dev *dev) ++{ ++ struct pciback_config_quirk *quirk; ++ int ret = 0; ++ ++ quirk = pciback_find_quirk(dev); ++ if (!quirk) { ++ ret = -ENXIO; ++ goto out; ++ } ++ ++ list_del(&quirk->quirks_list); ++ kfree(quirk); ++ ++ out: ++ return ret; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/conf_space_quirks.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/conf_space_quirks.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,35 @@ ++/* ++ * PCI Backend - Data structures for special overlays for broken devices. ++ * ++ * Ryan Wilson <hap9@epoch.ncsc.mil> ++ * Chris Bookholt <hap10@epoch.ncsc.mil> ++ */ ++ ++#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__ ++#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__ ++ ++#include <linux/pci.h> ++#include <linux/list.h> ++ ++struct pciback_config_quirk { ++ struct list_head quirks_list; ++ struct pci_device_id devid; ++ struct pci_dev *pdev; ++}; ++ ++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev); ++ ++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field ++ *field); ++ ++int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg); ++ ++int pciback_config_quirks_init(struct pci_dev *dev); ++ ++void pciback_config_field_free(struct config_field *field); ++ ++int pciback_config_quirk_release(struct pci_dev *dev); ++ ++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg); ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/passthrough.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/passthrough.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,157 @@ ++/* ++ * PCI Backend - Provides restricted access to the real PCI bus topology ++ * to the frontend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/list.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include "pciback.h" ++ ++struct passthrough_dev_data { ++ /* Access to dev_list must be protected by lock */ ++ struct list_head dev_list; ++ spinlock_t lock; ++}; ++ ++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, ++ unsigned int domain, unsigned int bus, ++ unsigned int devfn) ++{ ++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; ++ struct pci_dev_entry *dev_entry; ++ struct pci_dev *dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev_data->lock, flags); ++ ++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) { ++ if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus) ++ && bus == (unsigned int)dev_entry->dev->bus->number ++ && devfn == dev_entry->dev->devfn) { ++ dev = dev_entry->dev; ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&dev_data->lock, flags); ++ ++ return dev; ++} ++ ++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; ++ struct pci_dev_entry *dev_entry; ++ unsigned long flags; ++ ++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); ++ if (!dev_entry) ++ return -ENOMEM; ++ dev_entry->dev = dev; ++ ++ spin_lock_irqsave(&dev_data->lock, flags); ++ list_add_tail(&dev_entry->list, &dev_data->dev_list); ++ spin_unlock_irqrestore(&dev_data->lock, flags); ++ ++ return 0; ++} ++ ++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; ++ struct pci_dev_entry *dev_entry, *t; ++ struct pci_dev *found_dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev_data->lock, flags); ++ ++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { ++ if (dev_entry->dev == dev) { ++ list_del(&dev_entry->list); ++ found_dev = dev_entry->dev; ++ kfree(dev_entry); ++ } ++ } ++ ++ spin_unlock_irqrestore(&dev_data->lock, flags); ++ ++ if (found_dev) ++ pcistub_put_pci_dev(found_dev); ++} ++ ++int pciback_init_devices(struct pciback_device *pdev) ++{ ++ struct passthrough_dev_data *dev_data; ++ ++ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL); ++ if (!dev_data) ++ return -ENOMEM; ++ ++ spin_lock_init(&dev_data->lock); ++ ++ INIT_LIST_HEAD(&dev_data->dev_list); ++ ++ pdev->pci_dev_data = dev_data; ++ ++ return 0; ++} ++ ++int pciback_publish_pci_roots(struct pciback_device *pdev, ++ publish_pci_root_cb publish_root_cb) ++{ ++ int err = 0; ++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; ++ struct pci_dev_entry *dev_entry, *e; ++ struct pci_dev *dev; ++ int found; ++ unsigned int domain, bus; ++ ++ spin_lock(&dev_data->lock); ++ ++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) { ++ /* Only publish this device as a root if none of its ++ * parent bridges are exported ++ */ ++ found = 0; ++ dev = dev_entry->dev->bus->self; ++ for (; !found && dev != NULL; dev = dev->bus->self) { ++ list_for_each_entry(e, &dev_data->dev_list, list) { ++ if (dev == e->dev) { ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus); ++ bus = (unsigned int)dev_entry->dev->bus->number; ++ ++ if (!found) { ++ err = publish_root_cb(pdev, domain, bus); ++ if (err) ++ break; ++ } ++ } ++ ++ spin_unlock(&dev_data->lock); ++ ++ return err; ++} ++ ++void pciback_release_devices(struct pciback_device *pdev) ++{ ++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data; ++ struct pci_dev_entry *dev_entry, *t; ++ ++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) { ++ list_del(&dev_entry->list); ++ pcistub_put_pci_dev(dev_entry->dev); ++ kfree(dev_entry); ++ } ++ ++ kfree(dev_data); ++ pdev->pci_dev_data = NULL; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/pci_stub.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/pci_stub.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,929 @@ ++/* ++ * PCI Stub Driver - Grabs devices in backend to be exported later ++ * ++ * Ryan Wilson <hap9@epoch.ncsc.mil> ++ * Chris Bookholt <hap10@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/kref.h> ++#include <asm/atomic.h> ++#include "pciback.h" ++#include "conf_space.h" ++#include "conf_space_quirks.h" ++ ++static char *pci_devs_to_hide = NULL; ++module_param_named(hide, pci_devs_to_hide, charp, 0444); ++ ++struct pcistub_device_id { ++ struct list_head slot_list; ++ int domain; ++ unsigned char bus; ++ unsigned int devfn; ++}; ++static LIST_HEAD(pcistub_device_ids); ++static DEFINE_SPINLOCK(device_ids_lock); ++ ++struct pcistub_device { ++ struct kref kref; ++ struct list_head dev_list; ++ spinlock_t lock; ++ ++ struct pci_dev *dev; ++ struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */ ++}; ++ ++/* Access to pcistub_devices & seized_devices lists and the initialize_devices ++ * flag must be locked with pcistub_devices_lock ++ */ ++static DEFINE_SPINLOCK(pcistub_devices_lock); ++static LIST_HEAD(pcistub_devices); ++ ++/* wait for device_initcall before initializing our devices ++ * (see pcistub_init_devices_late) ++ */ ++static int initialize_devices = 0; ++static LIST_HEAD(seized_devices); ++ ++static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev) ++{ ++ struct pcistub_device *psdev; ++ ++ dev_dbg(&dev->dev, "pcistub_device_alloc\n"); ++ ++ psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC); ++ if (!psdev) ++ return NULL; ++ ++ psdev->dev = pci_dev_get(dev); ++ if (!psdev->dev) { ++ kfree(psdev); ++ return NULL; ++ } ++ ++ kref_init(&psdev->kref); ++ spin_lock_init(&psdev->lock); ++ ++ return psdev; ++} ++ ++/* Don't call this directly as it's called by pcistub_device_put */ ++static void pcistub_device_release(struct kref *kref) ++{ ++ struct pcistub_device *psdev; ++ ++ psdev = container_of(kref, struct pcistub_device, kref); ++ ++ dev_dbg(&psdev->dev->dev, "pcistub_device_release\n"); ++ ++ /* Clean-up the device */ ++ pciback_reset_device(psdev->dev); ++ pciback_config_free_dyn_fields(psdev->dev); ++ pciback_config_free_dev(psdev->dev); ++ kfree(pci_get_drvdata(psdev->dev)); ++ pci_set_drvdata(psdev->dev, NULL); ++ ++ pci_dev_put(psdev->dev); ++ ++ kfree(psdev); ++} ++ ++static inline void pcistub_device_get(struct pcistub_device *psdev) ++{ ++ kref_get(&psdev->kref); ++} ++ ++static inline void pcistub_device_put(struct pcistub_device *psdev) ++{ ++ kref_put(&psdev->kref, pcistub_device_release); ++} ++ ++static struct pcistub_device *pcistub_device_find(int domain, int bus, ++ int slot, int func) ++{ ++ struct pcistub_device *psdev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (psdev->dev != NULL ++ && domain == pci_domain_nr(psdev->dev->bus) ++ && bus == psdev->dev->bus->number ++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) { ++ pcistub_device_get(psdev); ++ goto out; ++ } ++ } ++ ++ /* didn't find it */ ++ psdev = NULL; ++ ++ out: ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ return psdev; ++} ++ ++static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev, ++ struct pcistub_device *psdev) ++{ ++ struct pci_dev *pci_dev = NULL; ++ unsigned long flags; ++ ++ pcistub_device_get(psdev); ++ ++ spin_lock_irqsave(&psdev->lock, flags); ++ if (!psdev->pdev) { ++ psdev->pdev = pdev; ++ pci_dev = psdev->dev; ++ } ++ spin_unlock_irqrestore(&psdev->lock, flags); ++ ++ if (!pci_dev) ++ pcistub_device_put(psdev); ++ ++ return pci_dev; ++} ++ ++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev, ++ int domain, int bus, ++ int slot, int func) ++{ ++ struct pcistub_device *psdev; ++ struct pci_dev *found_dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (psdev->dev != NULL ++ && domain == pci_domain_nr(psdev->dev->bus) ++ && bus == psdev->dev->bus->number ++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) { ++ found_dev = pcistub_device_get_pci_dev(pdev, psdev); ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ return found_dev; ++} ++ ++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev, ++ struct pci_dev *dev) ++{ ++ struct pcistub_device *psdev; ++ struct pci_dev *found_dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (psdev->dev == dev) { ++ found_dev = pcistub_device_get_pci_dev(pdev, psdev); ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ return found_dev; ++} ++ ++void pcistub_put_pci_dev(struct pci_dev *dev) ++{ ++ struct pcistub_device *psdev, *found_psdev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (psdev->dev == dev) { ++ found_psdev = psdev; ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ /* Cleanup our device ++ * (so it's ready for the next domain) ++ */ ++ pciback_reset_device(found_psdev->dev); ++ pciback_config_free_dyn_fields(found_psdev->dev); ++ pciback_config_reset_dev(found_psdev->dev); ++ ++ spin_lock_irqsave(&found_psdev->lock, flags); ++ found_psdev->pdev = NULL; ++ spin_unlock_irqrestore(&found_psdev->lock, flags); ++ ++ pcistub_device_put(found_psdev); ++} ++ ++static int __devinit pcistub_match_one(struct pci_dev *dev, ++ struct pcistub_device_id *pdev_id) ++{ ++ /* Match the specified device by domain, bus, slot, func and also if ++ * any of the device's parent bridges match. ++ */ ++ for (; dev != NULL; dev = dev->bus->self) { ++ if (pci_domain_nr(dev->bus) == pdev_id->domain ++ && dev->bus->number == pdev_id->bus ++ && dev->devfn == pdev_id->devfn) ++ return 1; ++ ++ /* Sometimes topmost bridge links to itself. */ ++ if (dev == dev->bus->self) ++ break; ++ } ++ ++ return 0; ++} ++ ++static int __devinit pcistub_match(struct pci_dev *dev) ++{ ++ struct pcistub_device_id *pdev_id; ++ unsigned long flags; ++ int found = 0; ++ ++ spin_lock_irqsave(&device_ids_lock, flags); ++ list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) { ++ if (pcistub_match_one(dev, pdev_id)) { ++ found = 1; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&device_ids_lock, flags); ++ ++ return found; ++} ++ ++static int __devinit pcistub_init_device(struct pci_dev *dev) ++{ ++ struct pciback_dev_data *dev_data; ++ int err = 0; ++ ++ dev_dbg(&dev->dev, "initializing...\n"); ++ ++ /* The PCI backend is not intended to be a module (or to work with ++ * removable PCI devices (yet). If it were, pciback_config_free() ++ * would need to be called somewhere to free the memory allocated ++ * here and then to call kfree(pci_get_drvdata(psdev->dev)). ++ */ ++ dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC); ++ if (!dev_data) { ++ err = -ENOMEM; ++ goto out; ++ } ++ pci_set_drvdata(dev, dev_data); ++ ++ dev_dbg(&dev->dev, "initializing config\n"); ++ err = pciback_config_init_dev(dev); ++ if (err) ++ goto out; ++ ++ /* HACK: Force device (& ACPI) to determine what IRQ it's on - we ++ * must do this here because pcibios_enable_device may specify ++ * the pci device's true irq (and possibly its other resources) ++ * if they differ from what's in the configuration space. ++ * This makes the assumption that the device's resources won't ++ * change after this point (otherwise this code may break!) ++ */ ++ dev_dbg(&dev->dev, "enabling device\n"); ++ err = pci_enable_device(dev); ++ if (err) ++ goto config_release; ++ ++ /* Now disable the device (this also ensures some private device ++ * data is setup before we export) ++ */ ++ dev_dbg(&dev->dev, "reset device\n"); ++ pciback_reset_device(dev); ++ ++ return 0; ++ ++ config_release: ++ pciback_config_free_dev(dev); ++ ++ out: ++ pci_set_drvdata(dev, NULL); ++ kfree(dev_data); ++ return err; ++} ++ ++/* ++ * Because some initialization still happens on ++ * devices during fs_initcall, we need to defer ++ * full initialization of our devices until ++ * device_initcall. ++ */ ++static int __init pcistub_init_devices_late(void) ++{ ++ struct pcistub_device *psdev; ++ unsigned long flags; ++ int err = 0; ++ ++ pr_debug("pciback: pcistub_init_devices_late\n"); ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ while (!list_empty(&seized_devices)) { ++ psdev = container_of(seized_devices.next, ++ struct pcistub_device, dev_list); ++ list_del(&psdev->dev_list); ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ err = pcistub_init_device(psdev->dev); ++ if (err) { ++ dev_err(&psdev->dev->dev, ++ "error %d initializing device\n", err); ++ kfree(psdev); ++ psdev = NULL; ++ } ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ if (psdev) ++ list_add_tail(&psdev->dev_list, &pcistub_devices); ++ } ++ ++ initialize_devices = 1; ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ return 0; ++} ++ ++static int __devinit pcistub_seize(struct pci_dev *dev) ++{ ++ struct pcistub_device *psdev; ++ unsigned long flags; ++ int err = 0; ++ ++ psdev = pcistub_device_alloc(dev); ++ if (!psdev) ++ return -ENOMEM; ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ if (initialize_devices) { ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ /* don't want irqs disabled when calling pcistub_init_device */ ++ err = pcistub_init_device(psdev->dev); ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ if (!err) ++ list_add(&psdev->dev_list, &pcistub_devices); ++ } else { ++ dev_dbg(&dev->dev, "deferring initialization\n"); ++ list_add(&psdev->dev_list, &seized_devices); ++ } ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ if (err) ++ pcistub_device_put(psdev); ++ ++ return err; ++} ++ ++static int __devinit pcistub_probe(struct pci_dev *dev, ++ const struct pci_device_id *id) ++{ ++ int err = 0; ++ ++ dev_dbg(&dev->dev, "probing...\n"); ++ ++ if (pcistub_match(dev)) { ++ ++ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL ++ && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { ++ dev_err(&dev->dev, "can't export pci devices that " ++ "don't have a normal (0) or bridge (1) " ++ "header type!\n"); ++ err = -ENODEV; ++ goto out; ++ } ++ ++ dev_info(&dev->dev, "seizing device\n"); ++ err = pcistub_seize(dev); ++ } else ++ /* Didn't find the device */ ++ err = -ENODEV; ++ ++ out: ++ return err; ++} ++ ++static void pcistub_remove(struct pci_dev *dev) ++{ ++ struct pcistub_device *psdev, *found_psdev = NULL; ++ unsigned long flags; ++ ++ dev_dbg(&dev->dev, "removing\n"); ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ ++ pciback_config_quirk_release(dev); ++ ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (psdev->dev == dev) { ++ found_psdev = psdev; ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ if (found_psdev) { ++ dev_dbg(&dev->dev, "found device to remove - in use? %p\n", ++ found_psdev->pdev); ++ ++ if (found_psdev->pdev) { ++ printk(KERN_WARNING "pciback: ****** removing device " ++ "%s while still in-use! ******\n", ++ pci_name(found_psdev->dev)); ++ printk(KERN_WARNING "pciback: ****** driver domain may " ++ "still access this device's i/o resources!\n"); ++ printk(KERN_WARNING "pciback: ****** shutdown driver " ++ "domain before binding device\n"); ++ printk(KERN_WARNING "pciback: ****** to other drivers " ++ "or domains\n"); ++ ++ pciback_release_pci_dev(found_psdev->pdev, ++ found_psdev->dev); ++ } ++ ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ list_del(&found_psdev->dev_list); ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ ++ /* the final put for releasing from the list */ ++ pcistub_device_put(found_psdev); ++ } ++} ++ ++static struct pci_device_id pcistub_ids[] = { ++ { ++ .vendor = PCI_ANY_ID, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ }, ++ {0,}, ++}; ++ ++/* ++ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't ++ * for a normal device. I don't want it to be loaded automatically. ++ */ ++ ++static struct pci_driver pciback_pci_driver = { ++ .name = "pciback", ++ .id_table = pcistub_ids, ++ .probe = pcistub_probe, ++ .remove = pcistub_remove, ++}; ++ ++static inline int str_to_slot(const char *buf, int *domain, int *bus, ++ int *slot, int *func) ++{ ++ int err; ++ ++ err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); ++ if (err == 4) ++ return 0; ++ else if (err < 0) ++ return -EINVAL; ++ ++ /* try again without domain */ ++ *domain = 0; ++ err = sscanf(buf, " %x:%x.%x", bus, slot, func); ++ if (err == 3) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static inline int str_to_quirk(const char *buf, int *domain, int *bus, int ++ *slot, int *func, int *reg, int *size, int *mask) ++{ ++ int err; ++ ++ err = ++ sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot, ++ func, reg, size, mask); ++ if (err == 7) ++ return 0; ++ return -EINVAL; ++} ++ ++static int pcistub_device_id_add(int domain, int bus, int slot, int func) ++{ ++ struct pcistub_device_id *pci_dev_id; ++ unsigned long flags; ++ ++ pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); ++ if (!pci_dev_id) ++ return -ENOMEM; ++ ++ pci_dev_id->domain = domain; ++ pci_dev_id->bus = bus; ++ pci_dev_id->devfn = PCI_DEVFN(slot, func); ++ ++ pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n", ++ domain, bus, slot, func); ++ ++ spin_lock_irqsave(&device_ids_lock, flags); ++ list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids); ++ spin_unlock_irqrestore(&device_ids_lock, flags); ++ ++ return 0; ++} ++ ++static int pcistub_device_id_remove(int domain, int bus, int slot, int func) ++{ ++ struct pcistub_device_id *pci_dev_id, *t; ++ int devfn = PCI_DEVFN(slot, func); ++ int err = -ENOENT; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&device_ids_lock, flags); ++ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) { ++ ++ if (pci_dev_id->domain == domain ++ && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) { ++ /* Don't break; here because it's possible the same ++ * slot could be in the list more than once ++ */ ++ list_del(&pci_dev_id->slot_list); ++ kfree(pci_dev_id); ++ ++ err = 0; ++ ++ pr_debug("pciback: removed %04x:%02x:%02x.%01x from " ++ "seize list\n", domain, bus, slot, func); ++ } ++ } ++ spin_unlock_irqrestore(&device_ids_lock, flags); ++ ++ return err; ++} ++ ++static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, ++ int size, int mask) ++{ ++ int err = 0; ++ struct pcistub_device *psdev; ++ struct pci_dev *dev; ++ struct config_field *field; ++ ++ psdev = pcistub_device_find(domain, bus, slot, func); ++ if (!psdev || !psdev->dev) { ++ err = -ENODEV; ++ goto out; ++ } ++ dev = psdev->dev; ++ ++ field = kzalloc(sizeof(*field), GFP_ATOMIC); ++ if (!field) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ field->offset = reg; ++ field->size = size; ++ field->mask = mask; ++ field->init = NULL; ++ field->reset = NULL; ++ field->release = NULL; ++ field->clean = pciback_config_field_free; ++ ++ err = pciback_config_quirks_add_field(dev, field); ++ if (err) ++ kfree(field); ++ out: ++ return err; ++} ++ ++static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int domain, bus, slot, func; ++ int err; ++ ++ err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ if (err) ++ goto out; ++ ++ err = pcistub_device_id_add(domain, bus, slot, func); ++ ++ out: ++ if (!err) ++ err = count; ++ return err; ++} ++ ++DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add); ++ ++static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int domain, bus, slot, func; ++ int err; ++ ++ err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ if (err) ++ goto out; ++ ++ err = pcistub_device_id_remove(domain, bus, slot, func); ++ ++ out: ++ if (!err) ++ err = count; ++ return err; ++} ++ ++DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove); ++ ++static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf) ++{ ++ struct pcistub_device_id *pci_dev_id; ++ size_t count = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&device_ids_lock, flags); ++ list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) { ++ if (count >= PAGE_SIZE) ++ break; ++ ++ count += scnprintf(buf + count, PAGE_SIZE - count, ++ "%04x:%02x:%02x.%01x\n", ++ pci_dev_id->domain, pci_dev_id->bus, ++ PCI_SLOT(pci_dev_id->devfn), ++ PCI_FUNC(pci_dev_id->devfn)); ++ } ++ spin_unlock_irqrestore(&device_ids_lock, flags); ++ ++ return count; ++} ++ ++DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL); ++ ++static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int domain, bus, slot, func, reg, size, mask; ++ int err; ++ ++ err = str_to_quirk(buf, &domain, &bus, &slot, &func, ®, &size, ++ &mask); ++ if (err) ++ goto out; ++ ++ err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask); ++ ++ out: ++ if (!err) ++ err = count; ++ return err; ++} ++ ++static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf) ++{ ++ int count = 0; ++ unsigned long flags; ++ extern struct list_head pciback_quirks; ++ struct pciback_config_quirk *quirk; ++ struct pciback_dev_data *dev_data; ++ struct config_field *field; ++ struct config_field_entry *cfg_entry; ++ ++ spin_lock_irqsave(&device_ids_lock, flags); ++ list_for_each_entry(quirk, &pciback_quirks, quirks_list) { ++ if (count >= PAGE_SIZE) ++ goto out; ++ ++ count += scnprintf(buf + count, PAGE_SIZE - count, ++ "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n", ++ quirk->pdev->bus->number, ++ PCI_SLOT(quirk->pdev->devfn), ++ PCI_FUNC(quirk->pdev->devfn), ++ quirk->devid.vendor, quirk->devid.device, ++ quirk->devid.subvendor, ++ quirk->devid.subdevice); ++ ++ dev_data = pci_get_drvdata(quirk->pdev); ++ ++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { ++ field = cfg_entry->field; ++ if (count >= PAGE_SIZE) ++ goto out; ++ ++ count += scnprintf(buf + count, PAGE_SIZE - count, ++ "\t\t%08x:%01x:%08x\n", ++ cfg_entry->base_offset + field->offset, ++ field->size, field->mask); ++ } ++ } ++ ++ out: ++ spin_unlock_irqrestore(&device_ids_lock, flags); ++ ++ return count; ++} ++ ++DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add); ++ ++static ssize_t permissive_add(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int domain, bus, slot, func; ++ int err; ++ struct pcistub_device *psdev; ++ struct pciback_dev_data *dev_data; ++ err = str_to_slot(buf, &domain, &bus, &slot, &func); ++ if (err) ++ goto out; ++ psdev = pcistub_device_find(domain, bus, slot, func); ++ if (!psdev) { ++ err = -ENODEV; ++ goto out; ++ } ++ if (!psdev->dev) { ++ err = -ENODEV; ++ goto release; ++ } ++ dev_data = pci_get_drvdata(psdev->dev); ++ /* the driver data for a device should never be null at this point */ ++ if (!dev_data) { ++ err = -ENXIO; ++ goto release; ++ } ++ if (!dev_data->permissive) { ++ dev_data->permissive = 1; ++ /* Let user know that what they're doing could be unsafe */ ++ dev_warn(&psdev->dev->dev, ++ "enabling permissive mode configuration space accesses!\n"); ++ dev_warn(&psdev->dev->dev, ++ "permissive mode is potentially unsafe!\n"); ++ } ++ release: ++ pcistub_device_put(psdev); ++ out: ++ if (!err) ++ err = count; ++ return err; ++} ++ ++static ssize_t permissive_show(struct device_driver *drv, char *buf) ++{ ++ struct pcistub_device *psdev; ++ struct pciback_dev_data *dev_data; ++ size_t count = 0; ++ unsigned long flags; ++ spin_lock_irqsave(&pcistub_devices_lock, flags); ++ list_for_each_entry(psdev, &pcistub_devices, dev_list) { ++ if (count >= PAGE_SIZE) ++ break; ++ if (!psdev->dev) ++ continue; ++ dev_data = pci_get_drvdata(psdev->dev); ++ if (!dev_data || !dev_data->permissive) ++ continue; ++ count += ++ scnprintf(buf + count, PAGE_SIZE - count, "%s\n", ++ pci_name(psdev->dev)); ++ } ++ spin_unlock_irqrestore(&pcistub_devices_lock, flags); ++ return count; ++} ++ ++DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add); ++ ++static void pcistub_exit(void) ++{ ++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot); ++ driver_remove_file(&pciback_pci_driver.driver, ++ &driver_attr_remove_slot); ++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots); ++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks); ++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive); ++ ++ pci_unregister_driver(&pciback_pci_driver); ++} ++ ++static int __init pcistub_init(void) ++{ ++ int pos = 0; ++ int err = 0; ++ int domain, bus, slot, func; ++ int parsed; ++ ++ if (pci_devs_to_hide && *pci_devs_to_hide) { ++ do { ++ parsed = 0; ++ ++ err = sscanf(pci_devs_to_hide + pos, ++ " (%x:%x:%x.%x) %n", ++ &domain, &bus, &slot, &func, &parsed); ++ if (err != 4) { ++ domain = 0; ++ err = sscanf(pci_devs_to_hide + pos, ++ " (%x:%x.%x) %n", ++ &bus, &slot, &func, &parsed); ++ if (err != 3) ++ goto parse_error; ++ } ++ ++ err = pcistub_device_id_add(domain, bus, slot, func); ++ if (err) ++ goto out; ++ ++ /* if parsed<=0, we've reached the end of the string */ ++ pos += parsed; ++ } while (parsed > 0 && pci_devs_to_hide[pos]); ++ } ++ ++ /* If we're the first PCI Device Driver to register, we're the ++ * first one to get offered PCI devices as they become ++ * available (and thus we can be the first to grab them) ++ */ ++ err = pci_register_driver(&pciback_pci_driver); ++ if (err < 0) ++ goto out; ++ ++ err = driver_create_file(&pciback_pci_driver.driver, ++ &driver_attr_new_slot); ++ if (!err) ++ err = driver_create_file(&pciback_pci_driver.driver, ++ &driver_attr_remove_slot); ++ if (!err) ++ err = driver_create_file(&pciback_pci_driver.driver, ++ &driver_attr_slots); ++ if (!err) ++ err = driver_create_file(&pciback_pci_driver.driver, ++ &driver_attr_quirks); ++ if (!err) ++ err = driver_create_file(&pciback_pci_driver.driver, ++ &driver_attr_permissive); ++ ++ if (err) ++ pcistub_exit(); ++ ++ out: ++ return err; ++ ++ parse_error: ++ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n", ++ pci_devs_to_hide + pos); ++ return -EINVAL; ++} ++ ++#ifndef MODULE ++/* ++ * fs_initcall happens before device_initcall ++ * so pciback *should* get called first (b/c we ++ * want to suck up any device before other drivers ++ * get a chance by being the first pci device ++ * driver to register) ++ */ ++fs_initcall(pcistub_init); ++#endif ++ ++static int __init pciback_init(void) ++{ ++ int err; ++ ++ err = pciback_config_init(); ++ if (err) ++ return err; ++ ++#ifdef MODULE ++ err = pcistub_init(); ++ if (err < 0) ++ return err; ++#endif ++ ++ pcistub_init_devices_late(); ++ err = pciback_xenbus_register(); ++ if (err) ++ pcistub_exit(); ++ ++ return err; ++} ++ ++static void __exit pciback_cleanup(void) ++{ ++ pciback_xenbus_unregister(); ++ pcistub_exit(); ++} ++ ++module_init(pciback_init); ++module_exit(pciback_cleanup); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/pciback.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/pciback.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,93 @@ ++/* ++ * PCI Backend Common Data Structures & Function Declarations ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#ifndef __XEN_PCIBACK_H__ ++#define __XEN_PCIBACK_H__ ++ ++#include <linux/pci.h> ++#include <linux/interrupt.h> ++#include <xen/xenbus.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/workqueue.h> ++#include <asm/atomic.h> ++#include <xen/interface/io/pciif.h> ++ ++struct pci_dev_entry { ++ struct list_head list; ++ struct pci_dev *dev; ++}; ++ ++#define _PDEVF_op_active (0) ++#define PDEVF_op_active (1<<(_PDEVF_op_active)) ++ ++struct pciback_device { ++ void *pci_dev_data; ++ spinlock_t dev_lock; ++ ++ struct xenbus_device *xdev; ++ ++ struct xenbus_watch be_watch; ++ u8 be_watching; ++ ++ int evtchn_irq; ++ ++ struct vm_struct *sh_area; ++ struct xen_pci_sharedinfo *sh_info; ++ ++ unsigned long flags; ++ ++ struct delayed_work op_work; ++}; ++ ++struct pciback_dev_data { ++ struct list_head config_fields; ++ int permissive; ++ int warned_on_write; ++}; ++ ++/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */ ++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev, ++ int domain, int bus, ++ int slot, int func); ++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev, ++ struct pci_dev *dev); ++void pcistub_put_pci_dev(struct pci_dev *dev); ++ ++/* Ensure a device is turned off or reset */ ++void pciback_reset_device(struct pci_dev *pdev); ++ ++/* Access a virtual configuration space for a PCI device */ ++int pciback_config_init(void); ++int pciback_config_init_dev(struct pci_dev *dev); ++void pciback_config_free_dyn_fields(struct pci_dev *dev); ++void pciback_config_reset_dev(struct pci_dev *dev); ++void pciback_config_free_dev(struct pci_dev *dev); ++int pciback_config_read(struct pci_dev *dev, int offset, int size, ++ u32 * ret_val); ++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value); ++ ++/* Handle requests for specific devices from the frontend */ ++typedef int (*publish_pci_root_cb) (struct pciback_device * pdev, ++ unsigned int domain, unsigned int bus); ++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); ++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); ++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, ++ unsigned int domain, unsigned int bus, ++ unsigned int devfn); ++int pciback_init_devices(struct pciback_device *pdev); ++int pciback_publish_pci_roots(struct pciback_device *pdev, ++ publish_pci_root_cb cb); ++void pciback_release_devices(struct pciback_device *pdev); ++ ++/* Handles events from front-end */ ++irqreturn_t pciback_handle_event(int irq, void *dev_id); ++void pciback_do_op(struct work_struct *work); ++ ++int pciback_xenbus_register(void); ++void pciback_xenbus_unregister(void); ++ ++extern int verbose_request; ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/pciback_ops.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/pciback_ops.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,94 @@ ++/* ++ * PCI Backend Operations - respond to PCI requests from Frontend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <asm/bitops.h> ++#include <xen/evtchn.h> ++#include "pciback.h" ++ ++int verbose_request = 0; ++module_param(verbose_request, int, 0644); ++ ++/* Ensure a device is "turned off" and ready to be exported. ++ * (Also see pciback_config_reset to ensure virtual configuration space is ++ * ready to be re-exported) ++ */ ++void pciback_reset_device(struct pci_dev *dev) ++{ ++ u16 cmd; ++ ++ /* Disable devices (but not bridges) */ ++ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) { ++ pci_disable_device(dev); ++ ++ pci_write_config_word(dev, PCI_COMMAND, 0); ++ ++ dev->is_busmaster = 0; ++ } else { ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ if (cmd & (PCI_COMMAND_INVALIDATE)) { ++ cmd &= ~(PCI_COMMAND_INVALIDATE); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ ++ dev->is_busmaster = 0; ++ } ++ } ++} ++ ++static inline void test_and_schedule_op(struct pciback_device *pdev) ++{ ++ /* Check that frontend is requesting an operation and that we are not ++ * already processing a request */ ++ if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags) ++ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags)) ++ schedule_delayed_work(&pdev->op_work, 0); ++} ++ ++/* Performing the configuration space reads/writes must not be done in atomic ++ * context because some of the pci_* functions can sleep (mostly due to ACPI ++ * use of semaphores). This function is intended to be called from a work ++ * queue in process context taking a struct pciback_device as a parameter */ ++void pciback_do_op(struct work_struct *work) ++{ ++ struct pciback_device *pdev = container_of(work, struct pciback_device, op_work.work); ++ struct pci_dev *dev; ++ struct xen_pci_op *op = &pdev->sh_info->op; ++ ++ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn); ++ ++ if (dev == NULL) ++ op->err = XEN_PCI_ERR_dev_not_found; ++ else if (op->cmd == XEN_PCI_OP_conf_read) ++ op->err = pciback_config_read(dev, op->offset, op->size, ++ &op->value); ++ else if (op->cmd == XEN_PCI_OP_conf_write) ++ op->err = pciback_config_write(dev, op->offset, op->size, ++ op->value); ++ else ++ op->err = XEN_PCI_ERR_not_implemented; ++ ++ /* Tell the driver domain that we're done. */ ++ wmb(); ++ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); ++ notify_remote_via_irq(pdev->evtchn_irq); ++ ++ /* Mark that we're done. */ ++ smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */ ++ clear_bit(_PDEVF_op_active, &pdev->flags); ++ smp_mb__after_clear_bit(); /* /before/ final check for work */ ++ ++ /* Check to see if the driver domain tried to start another request in ++ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. */ ++ test_and_schedule_op(pdev); ++} ++ ++irqreturn_t pciback_handle_event(int irq, void *dev_id) ++{ ++ struct pciback_device *pdev = dev_id; ++ ++ test_and_schedule_op(pdev); ++ ++ return IRQ_HANDLED; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/slot.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/slot.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,151 @@ ++/* ++ * PCI Backend - Provides a Virtual PCI bus (with real devices) ++ * to the frontend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c) ++ * Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c ++ */ ++ ++#include <linux/list.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include "pciback.h" ++ ++/* There are at most 32 slots in a pci bus. */ ++#define PCI_SLOT_MAX 32 ++ ++#define PCI_BUS_NBR 2 ++ ++struct slot_dev_data { ++ /* Access to dev_list must be protected by lock */ ++ struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX]; ++ spinlock_t lock; ++}; ++ ++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, ++ unsigned int domain, unsigned int bus, ++ unsigned int devfn) ++{ ++ struct pci_dev *dev = NULL; ++ struct slot_dev_data *slot_dev = pdev->pci_dev_data; ++ unsigned long flags; ++ ++ if (domain != 0 || PCI_FUNC(devfn) != 0) ++ return NULL; ++ ++ if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR) ++ return NULL; ++ ++ spin_lock_irqsave(&slot_dev->lock, flags); ++ dev = slot_dev->slots[bus][PCI_SLOT(devfn)]; ++ spin_unlock_irqrestore(&slot_dev->lock, flags); ++ ++ return dev; ++} ++ ++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ int err = 0, slot, bus; ++ struct slot_dev_data *slot_dev = pdev->pci_dev_data; ++ unsigned long flags; ++ ++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { ++ err = -EFAULT; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Can't export bridges on the virtual PCI bus"); ++ goto out; ++ } ++ ++ spin_lock_irqsave(&slot_dev->lock, flags); ++ ++ /* Assign to a new slot on the virtual PCI bus */ ++ for (bus = 0; bus < PCI_BUS_NBR; bus++) ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ if (slot_dev->slots[bus][slot] == NULL) { ++ printk(KERN_INFO ++ "pciback: slot: %s: assign to virtual slot %d, bus %d\n", ++ pci_name(dev), slot, bus); ++ slot_dev->slots[bus][slot] = dev; ++ goto unlock; ++ } ++ } ++ ++ err = -ENOMEM; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "No more space on root virtual PCI bus"); ++ ++ unlock: ++ spin_unlock_irqrestore(&slot_dev->lock, flags); ++ out: ++ return err; ++} ++ ++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ int slot, bus; ++ struct slot_dev_data *slot_dev = pdev->pci_dev_data; ++ struct pci_dev *found_dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&slot_dev->lock, flags); ++ ++ for (bus = 0; bus < PCI_BUS_NBR; bus++) ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ if (slot_dev->slots[bus][slot] == dev) { ++ slot_dev->slots[bus][slot] = NULL; ++ found_dev = dev; ++ goto out; ++ } ++ } ++ ++ out: ++ spin_unlock_irqrestore(&slot_dev->lock, flags); ++ ++ if (found_dev) ++ pcistub_put_pci_dev(found_dev); ++} ++ ++int pciback_init_devices(struct pciback_device *pdev) ++{ ++ int slot, bus; ++ struct slot_dev_data *slot_dev; ++ ++ slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL); ++ if (!slot_dev) ++ return -ENOMEM; ++ ++ spin_lock_init(&slot_dev->lock); ++ ++ for (bus = 0; bus < PCI_BUS_NBR; bus++) ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) ++ slot_dev->slots[bus][slot] = NULL; ++ ++ pdev->pci_dev_data = slot_dev; ++ ++ return 0; ++} ++ ++int pciback_publish_pci_roots(struct pciback_device *pdev, ++ publish_pci_root_cb publish_cb) ++{ ++ /* The Virtual PCI bus has only one root */ ++ return publish_cb(pdev, 0, 0); ++} ++ ++void pciback_release_devices(struct pciback_device *pdev) ++{ ++ int slot, bus; ++ struct slot_dev_data *slot_dev = pdev->pci_dev_data; ++ struct pci_dev *dev; ++ ++ for (bus = 0; bus < PCI_BUS_NBR; bus++) ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ dev = slot_dev->slots[bus][slot]; ++ if (dev != NULL) ++ pcistub_put_pci_dev(dev); ++ } ++ ++ kfree(slot_dev); ++ pdev->pci_dev_data = NULL; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/vpci.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/vpci.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,204 @@ ++/* ++ * PCI Backend - Provides a Virtual PCI bus (with real devices) ++ * to the frontend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++ ++#include <linux/list.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include "pciback.h" ++ ++#define PCI_SLOT_MAX 32 ++ ++struct vpci_dev_data { ++ /* Access to dev_list must be protected by lock */ ++ struct list_head dev_list[PCI_SLOT_MAX]; ++ spinlock_t lock; ++}; ++ ++static inline struct list_head *list_first(struct list_head *head) ++{ ++ return head->next; ++} ++ ++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, ++ unsigned int domain, unsigned int bus, ++ unsigned int devfn) ++{ ++ struct pci_dev_entry *entry; ++ struct pci_dev *dev = NULL; ++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; ++ unsigned long flags; ++ ++ if (domain != 0 || bus != 0) ++ return NULL; ++ ++ if (PCI_SLOT(devfn) < PCI_SLOT_MAX) { ++ spin_lock_irqsave(&vpci_dev->lock, flags); ++ ++ list_for_each_entry(entry, ++ &vpci_dev->dev_list[PCI_SLOT(devfn)], ++ list) { ++ if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) { ++ dev = entry->dev; ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&vpci_dev->lock, flags); ++ } ++ return dev; ++} ++ ++static inline int match_slot(struct pci_dev *l, struct pci_dev *r) ++{ ++ if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus) ++ && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn)) ++ return 1; ++ ++ return 0; ++} ++ ++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ int err = 0, slot; ++ struct pci_dev_entry *t, *dev_entry; ++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; ++ unsigned long flags; ++ ++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) { ++ err = -EFAULT; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Can't export bridges on the virtual PCI bus"); ++ goto out; ++ } ++ ++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL); ++ if (!dev_entry) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error adding entry to virtual PCI bus"); ++ goto out; ++ } ++ ++ dev_entry->dev = dev; ++ ++ spin_lock_irqsave(&vpci_dev->lock, flags); ++ ++ /* Keep multi-function devices together on the virtual PCI bus */ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ if (!list_empty(&vpci_dev->dev_list[slot])) { ++ t = list_entry(list_first(&vpci_dev->dev_list[slot]), ++ struct pci_dev_entry, list); ++ ++ if (match_slot(dev, t->dev)) { ++ pr_info("pciback: vpci: %s: " ++ "assign to virtual slot %d func %d\n", ++ pci_name(dev), slot, ++ PCI_FUNC(dev->devfn)); ++ list_add_tail(&dev_entry->list, ++ &vpci_dev->dev_list[slot]); ++ goto unlock; ++ } ++ } ++ } ++ ++ /* Assign to a new slot on the virtual PCI bus */ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ if (list_empty(&vpci_dev->dev_list[slot])) { ++ printk(KERN_INFO ++ "pciback: vpci: %s: assign to virtual slot %d\n", ++ pci_name(dev), slot); ++ list_add_tail(&dev_entry->list, ++ &vpci_dev->dev_list[slot]); ++ goto unlock; ++ } ++ } ++ ++ err = -ENOMEM; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "No more space on root virtual PCI bus"); ++ ++ unlock: ++ spin_unlock_irqrestore(&vpci_dev->lock, flags); ++ out: ++ return err; ++} ++ ++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) ++{ ++ int slot; ++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; ++ struct pci_dev *found_dev = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&vpci_dev->lock, flags); ++ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ struct pci_dev_entry *e, *tmp; ++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], ++ list) { ++ if (e->dev == dev) { ++ list_del(&e->list); ++ found_dev = e->dev; ++ kfree(e); ++ goto out; ++ } ++ } ++ } ++ ++ out: ++ spin_unlock_irqrestore(&vpci_dev->lock, flags); ++ ++ if (found_dev) ++ pcistub_put_pci_dev(found_dev); ++} ++ ++int pciback_init_devices(struct pciback_device *pdev) ++{ ++ int slot; ++ struct vpci_dev_data *vpci_dev; ++ ++ vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL); ++ if (!vpci_dev) ++ return -ENOMEM; ++ ++ spin_lock_init(&vpci_dev->lock); ++ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]); ++ } ++ ++ pdev->pci_dev_data = vpci_dev; ++ ++ return 0; ++} ++ ++int pciback_publish_pci_roots(struct pciback_device *pdev, ++ publish_pci_root_cb publish_cb) ++{ ++ /* The Virtual PCI bus has only one root */ ++ return publish_cb(pdev, 0, 0); ++} ++ ++void pciback_release_devices(struct pciback_device *pdev) ++{ ++ int slot; ++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; ++ ++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) { ++ struct pci_dev_entry *e, *tmp; ++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot], ++ list) { ++ list_del(&e->list); ++ pcistub_put_pci_dev(e->dev); ++ kfree(e); ++ } ++ } ++ ++ kfree(vpci_dev); ++ pdev->pci_dev_data = NULL; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pciback/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pciback/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,454 @@ ++/* ++ * PCI Backend Xenbus Setup - handles setup with frontend and xend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/vmalloc.h> ++#include <xen/xenbus.h> ++#include <xen/evtchn.h> ++#include "pciback.h" ++ ++#define INVALID_EVTCHN_IRQ (-1) ++ ++static struct pciback_device *alloc_pdev(struct xenbus_device *xdev) ++{ ++ struct pciback_device *pdev; ++ ++ pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL); ++ if (pdev == NULL) ++ goto out; ++ dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev); ++ ++ pdev->xdev = xdev; ++ xdev->dev.driver_data = pdev; ++ ++ spin_lock_init(&pdev->dev_lock); ++ ++ pdev->sh_area = NULL; ++ pdev->sh_info = NULL; ++ pdev->evtchn_irq = INVALID_EVTCHN_IRQ; ++ pdev->be_watching = 0; ++ ++ INIT_DELAYED_WORK(&pdev->op_work, pciback_do_op); ++ ++ if (pciback_init_devices(pdev)) { ++ kfree(pdev); ++ pdev = NULL; ++ } ++ out: ++ return pdev; ++} ++ ++static void free_pdev(struct pciback_device *pdev) ++{ ++ if (pdev->be_watching) ++ unregister_xenbus_watch(&pdev->be_watch); ++ ++ /* Ensure the guest can't trigger our handler before removing devices */ ++ if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) ++ unbind_from_irqhandler(pdev->evtchn_irq, pdev); ++ ++ /* If the driver domain started an op, make sure we complete it or ++ * delete it before releasing the shared memory */ ++ cancel_delayed_work(&pdev->op_work); ++ flush_scheduled_work(); ++ ++ if (pdev->sh_info) ++ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area); ++ ++ pciback_release_devices(pdev); ++ ++ pdev->xdev->dev.driver_data = NULL; ++ pdev->xdev = NULL; ++ ++ kfree(pdev); ++} ++ ++static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref, ++ int remote_evtchn) ++{ ++ int err = 0; ++ struct vm_struct *area; ++ ++ dev_dbg(&pdev->xdev->dev, ++ "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", ++ gnt_ref, remote_evtchn); ++ ++ area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref); ++ if (IS_ERR(area)) { ++ err = PTR_ERR(area); ++ goto out; ++ } ++ pdev->sh_area = area; ++ pdev->sh_info = area->addr; ++ ++ err = bind_interdomain_evtchn_to_irqhandler( ++ pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event, ++ SA_SAMPLE_RANDOM, "pciback", pdev); ++ if (err < 0) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error binding event channel to IRQ"); ++ goto out; ++ } ++ pdev->evtchn_irq = err; ++ err = 0; ++ ++ dev_dbg(&pdev->xdev->dev, "Attached!\n"); ++ out: ++ return err; ++} ++ ++static int pciback_attach(struct pciback_device *pdev) ++{ ++ int err = 0; ++ int gnt_ref, remote_evtchn; ++ char *magic = NULL; ++ ++ spin_lock(&pdev->dev_lock); ++ ++ /* Make sure we only do this setup once */ ++ if (xenbus_read_driver_state(pdev->xdev->nodename) != ++ XenbusStateInitialised) ++ goto out; ++ ++ /* Wait for frontend to state that it has published the configuration */ ++ if (xenbus_read_driver_state(pdev->xdev->otherend) != ++ XenbusStateInitialised) ++ goto out; ++ ++ dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); ++ ++ err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, ++ "pci-op-ref", "%u", &gnt_ref, ++ "event-channel", "%u", &remote_evtchn, ++ "magic", NULL, &magic, NULL); ++ if (err) { ++ /* If configuration didn't get read correctly, wait longer */ ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error reading configuration from frontend"); ++ goto out; ++ } ++ ++ if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { ++ xenbus_dev_fatal(pdev->xdev, -EFAULT, ++ "version mismatch (%s/%s) with pcifront - " ++ "halting pciback", ++ magic, XEN_PCI_MAGIC); ++ goto out; ++ } ++ ++ err = pciback_do_attach(pdev, gnt_ref, remote_evtchn); ++ if (err) ++ goto out; ++ ++ dev_dbg(&pdev->xdev->dev, "Connecting...\n"); ++ ++ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); ++ if (err) ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error switching to connected state!"); ++ ++ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); ++ out: ++ spin_unlock(&pdev->dev_lock); ++ ++ if (magic) ++ kfree(magic); ++ ++ return err; ++} ++ ++static void pciback_frontend_changed(struct xenbus_device *xdev, ++ enum xenbus_state fe_state) ++{ ++ struct pciback_device *pdev = xdev->dev.driver_data; ++ ++ dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); ++ ++ switch (fe_state) { ++ case XenbusStateInitialised: ++ pciback_attach(pdev); ++ break; ++ ++ case XenbusStateClosing: ++ xenbus_switch_state(xdev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); ++ device_unregister(&xdev->dev); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static int pciback_publish_pci_root(struct pciback_device *pdev, ++ unsigned int domain, unsigned int bus) ++{ ++ unsigned int d, b; ++ int i, root_num, len, err; ++ char str[64]; ++ ++ dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, ++ "root_num", "%d", &root_num); ++ if (err == 0 || err == -ENOENT) ++ root_num = 0; ++ else if (err < 0) ++ goto out; ++ ++ /* Verify that we haven't already published this pci root */ ++ for (i = 0; i < root_num; i++) { ++ len = snprintf(str, sizeof(str), "root-%d", i); ++ if (unlikely(len >= (sizeof(str) - 1))) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, ++ str, "%x:%x", &d, &b); ++ if (err < 0) ++ goto out; ++ if (err != 2) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (d == domain && b == bus) { ++ err = 0; ++ goto out; ++ } ++ } ++ ++ len = snprintf(str, sizeof(str), "root-%d", root_num); ++ if (unlikely(len >= (sizeof(str) - 1))) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", ++ root_num, domain, bus); ++ ++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, ++ "%04x:%02x", domain, bus); ++ if (err) ++ goto out; ++ ++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, ++ "root_num", "%d", (root_num + 1)); ++ ++ out: ++ return err; ++} ++ ++static int pciback_export_device(struct pciback_device *pdev, ++ int domain, int bus, int slot, int func) ++{ ++ struct pci_dev *dev; ++ int err = 0; ++ ++ dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", ++ domain, bus, slot, func); ++ ++ dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); ++ if (!dev) { ++ err = -EINVAL; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Couldn't locate PCI device " ++ "(%04x:%02x:%02x.%01x)! " ++ "perhaps already in-use?", ++ domain, bus, slot, func); ++ goto out; ++ } ++ ++ err = pciback_add_pci_dev(pdev, dev); ++ if (err) ++ goto out; ++ ++ /* TODO: It'd be nice to export a bridge and have all of its children ++ * get exported with it. This may be best done in xend (which will ++ * have to calculate resource usage anyway) but we probably want to ++ * put something in here to ensure that if a bridge gets given to a ++ * driver domain, that all devices under that bridge are not given ++ * to other driver domains (as he who controls the bridge can disable ++ * it and stop the other devices from working). ++ */ ++ out: ++ return err; ++} ++ ++static int pciback_setup_backend(struct pciback_device *pdev) ++{ ++ /* Get configuration from xend (if available now) */ ++ int domain, bus, slot, func; ++ int err = 0; ++ int i, num_devs; ++ char dev_str[64]; ++ ++ spin_lock(&pdev->dev_lock); ++ ++ /* It's possible we could get the call to setup twice, so make sure ++ * we're not already connected. ++ */ ++ if (xenbus_read_driver_state(pdev->xdev->nodename) != ++ XenbusStateInitWait) ++ goto out; ++ ++ dev_dbg(&pdev->xdev->dev, "getting be setup\n"); ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", ++ &num_devs); ++ if (err != 1) { ++ if (err >= 0) ++ err = -EINVAL; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error reading number of devices"); ++ goto out; ++ } ++ ++ for (i = 0; i < num_devs; i++) { ++ int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); ++ if (unlikely(l >= (sizeof(dev_str) - 1))) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "String overflow while reading " ++ "configuration"); ++ goto out; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, ++ "%x:%x:%x.%x", &domain, &bus, &slot, &func); ++ if (err < 0) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error reading device configuration"); ++ goto out; ++ } ++ if (err != 4) { ++ err = -EINVAL; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error parsing pci device " ++ "configuration"); ++ goto out; ++ } ++ ++ err = pciback_export_device(pdev, domain, bus, slot, func); ++ if (err) ++ goto out; ++ } ++ ++ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root); ++ if (err) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error while publish PCI root buses " ++ "for frontend"); ++ goto out; ++ } ++ ++ err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); ++ if (err) ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error switching to initialised state!"); ++ ++ out: ++ spin_unlock(&pdev->dev_lock); ++ ++ if (!err) ++ /* see if pcifront is already configured (if not, we'll wait) */ ++ pciback_attach(pdev); ++ ++ return err; ++} ++ ++static void pciback_be_watch(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ struct pciback_device *pdev = ++ container_of(watch, struct pciback_device, be_watch); ++ ++ switch (xenbus_read_driver_state(pdev->xdev->nodename)) { ++ case XenbusStateInitWait: ++ pciback_setup_backend(pdev); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static int pciback_xenbus_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err = 0; ++ struct pciback_device *pdev = alloc_pdev(dev); ++ ++ if (pdev == NULL) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(dev, err, ++ "Error allocating pciback_device struct"); ++ goto out; ++ } ++ ++ /* wait for xend to configure us */ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) ++ goto out; ++ ++ /* watch the backend node for backend configuration information */ ++ err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, ++ pciback_be_watch); ++ if (err) ++ goto out; ++ pdev->be_watching = 1; ++ ++ /* We need to force a call to our callback here in case ++ * xend already configured us! ++ */ ++ pciback_be_watch(&pdev->be_watch, NULL, 0); ++ ++ out: ++ return err; ++} ++ ++static int pciback_xenbus_remove(struct xenbus_device *dev) ++{ ++ struct pciback_device *pdev = dev->dev.driver_data; ++ ++ if (pdev != NULL) ++ free_pdev(pdev); ++ ++ return 0; ++} ++ ++static struct xenbus_device_id xenpci_ids[] = { ++ {"pci"}, ++ {{0}}, ++}; ++ ++static struct xenbus_driver xenbus_pciback_driver = { ++ .name = "pciback", ++ .owner = THIS_MODULE, ++ .ids = xenpci_ids, ++ .probe = pciback_xenbus_probe, ++ .remove = pciback_xenbus_remove, ++ .otherend_changed = pciback_frontend_changed, ++}; ++ ++int __init pciback_xenbus_register(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ return xenbus_register_backend(&xenbus_pciback_driver); ++} ++ ++void __exit pciback_xenbus_unregister(void) ++{ ++ xenbus_unregister_driver(&xenbus_pciback_driver); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pcifront/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pcifront/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,7 @@ ++obj-y += pcifront.o ++ ++pcifront-y := pci_op.o xenbus.o pci.o ++ ++ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y) ++EXTRA_CFLAGS += -DDEBUG ++endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pcifront/pci.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pcifront/pci.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,46 @@ ++/* ++ * PCI Frontend Operations - ensure only one PCI frontend runs at a time ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include "pcifront.h" ++ ++DEFINE_SPINLOCK(pcifront_dev_lock); ++static struct pcifront_device *pcifront_dev = NULL; ++ ++int pcifront_connect(struct pcifront_device *pdev) ++{ ++ int err = 0; ++ ++ spin_lock(&pcifront_dev_lock); ++ ++ if (!pcifront_dev) { ++ dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); ++ pcifront_dev = pdev; ++ } ++ else { ++ dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); ++ err = -EEXIST; ++ } ++ ++ spin_unlock(&pcifront_dev_lock); ++ ++ return err; ++} ++ ++void pcifront_disconnect(struct pcifront_device *pdev) ++{ ++ spin_lock(&pcifront_dev_lock); ++ ++ if (pdev == pcifront_dev) { ++ dev_info(&pdev->xdev->dev, ++ "Disconnecting PCI Frontend Buses\n"); ++ pcifront_dev = NULL; ++ } ++ ++ spin_unlock(&pcifront_dev_lock); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pcifront/pci_op.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pcifront/pci_op.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,268 @@ ++/* ++ * PCI Frontend Operations - Communicates with frontend ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <linux/spinlock.h> ++#include <linux/time.h> ++#include <xen/evtchn.h> ++#include "pcifront.h" ++ ++static int verbose_request = 0; ++module_param(verbose_request, int, 0644); ++ ++static int errno_to_pcibios_err(int errno) ++{ ++ switch (errno) { ++ case XEN_PCI_ERR_success: ++ return PCIBIOS_SUCCESSFUL; ++ ++ case XEN_PCI_ERR_dev_not_found: ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ case XEN_PCI_ERR_invalid_offset: ++ case XEN_PCI_ERR_op_failed: ++ return PCIBIOS_BAD_REGISTER_NUMBER; ++ ++ case XEN_PCI_ERR_not_implemented: ++ return PCIBIOS_FUNC_NOT_SUPPORTED; ++ ++ case XEN_PCI_ERR_access_denied: ++ return PCIBIOS_SET_FAILED; ++ } ++ return errno; ++} ++ ++static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) ++{ ++ int err = 0; ++ struct xen_pci_op *active_op = &pdev->sh_info->op; ++ unsigned long irq_flags; ++ evtchn_port_t port = pdev->evtchn; ++ s64 ns, ns_timeout; ++ struct timeval tv; ++ ++ spin_lock_irqsave(&pdev->sh_info_lock, irq_flags); ++ ++ memcpy(active_op, op, sizeof(struct xen_pci_op)); ++ ++ /* Go */ ++ wmb(); ++ set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); ++ notify_remote_via_evtchn(port); ++ ++ /* ++ * We set a poll timeout of 3 seconds but give up on return after ++ * 2 seconds. It is better to time out too late rather than too early ++ * (in the latter case we end up continually re-executing poll() with a ++ * timeout in the past). 1s difference gives plenty of slack for error. ++ */ ++ do_gettimeofday(&tv); ++ ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC; ++ ++ clear_evtchn(port); ++ ++ while (test_bit(_XEN_PCIF_active, ++ (unsigned long *)&pdev->sh_info->flags)) { ++ if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ)) ++ BUG(); ++ clear_evtchn(port); ++ do_gettimeofday(&tv); ++ ns = timeval_to_ns(&tv); ++ if (ns > ns_timeout) { ++ dev_err(&pdev->xdev->dev, ++ "pciback not responding!!!\n"); ++ clear_bit(_XEN_PCIF_active, ++ (unsigned long *)&pdev->sh_info->flags); ++ err = XEN_PCI_ERR_dev_not_found; ++ goto out; ++ } ++ } ++ ++ memcpy(op, active_op, sizeof(struct xen_pci_op)); ++ ++ err = op->err; ++ out: ++ spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags); ++ return err; ++} ++ ++/* Access to this function is spinlocked in drivers/pci/access.c */ ++static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 * val) ++{ ++ int err = 0; ++ struct xen_pci_op op = { ++ .cmd = XEN_PCI_OP_conf_read, ++ .domain = pci_domain_nr(bus), ++ .bus = bus->number, ++ .devfn = devfn, ++ .offset = where, ++ .size = size, ++ }; ++ struct pcifront_sd *sd = bus->sysdata; ++ struct pcifront_device *pdev = pcifront_get_pdev(sd); ++ ++ if (verbose_request) ++ dev_info(&pdev->xdev->dev, ++ "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n", ++ pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), where, size); ++ ++ err = do_pci_op(pdev, &op); ++ ++ if (likely(!err)) { ++ if (verbose_request) ++ dev_info(&pdev->xdev->dev, "read got back value %x\n", ++ op.value); ++ ++ *val = op.value; ++ } else if (err == -ENODEV) { ++ /* No device here, pretend that it just returned 0 */ ++ err = 0; ++ *val = 0; ++ } ++ ++ return errno_to_pcibios_err(err); ++} ++ ++/* Access to this function is spinlocked in drivers/pci/access.c */ ++static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ struct xen_pci_op op = { ++ .cmd = XEN_PCI_OP_conf_write, ++ .domain = pci_domain_nr(bus), ++ .bus = bus->number, ++ .devfn = devfn, ++ .offset = where, ++ .size = size, ++ .value = val, ++ }; ++ struct pcifront_sd *sd = bus->sysdata; ++ struct pcifront_device *pdev = pcifront_get_pdev(sd); ++ ++ if (verbose_request) ++ dev_info(&pdev->xdev->dev, ++ "write dev=%04x:%02x:%02x.%01x - " ++ "offset %x size %d val %x\n", ++ pci_domain_nr(bus), bus->number, ++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); ++ ++ return errno_to_pcibios_err(do_pci_op(pdev, &op)); ++} ++ ++struct pci_ops pcifront_bus_ops = { ++ .read = pcifront_bus_read, ++ .write = pcifront_bus_write, ++}; ++ ++/* Claim resources for the PCI frontend as-is, backend won't allow changes */ ++static void pcifront_claim_resource(struct pci_dev *dev, void *data) ++{ ++ struct pcifront_device *pdev = data; ++ int i; ++ struct resource *r; ++ ++ for (i = 0; i < PCI_NUM_RESOURCES; i++) { ++ r = &dev->resource[i]; ++ ++ if (!r->parent && r->start && r->flags) { ++ dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n", ++ pci_name(dev), i); ++ pci_claim_resource(dev, i); ++ } ++ } ++} ++ ++int pcifront_scan_root(struct pcifront_device *pdev, ++ unsigned int domain, unsigned int bus) ++{ ++ struct pci_bus *b; ++ struct pcifront_sd *sd = NULL; ++ struct pci_bus_entry *bus_entry = NULL; ++ int err = 0; ++ ++#ifndef CONFIG_PCI_DOMAINS ++ if (domain != 0) { ++ dev_err(&pdev->xdev->dev, ++ "PCI Root in non-zero PCI Domain! domain=%d\n", domain); ++ dev_err(&pdev->xdev->dev, ++ "Please compile with CONFIG_PCI_DOMAINS\n"); ++ err = -EINVAL; ++ goto err_out; ++ } ++#endif ++ ++ dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", ++ domain, bus); ++ ++ bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); ++ sd = kmalloc(sizeof(*sd), GFP_KERNEL); ++ if (!bus_entry || !sd) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ pcifront_init_sd(sd, domain, pdev); ++ ++ b = pci_scan_bus_parented(&pdev->xdev->dev, bus, ++ &pcifront_bus_ops, sd); ++ if (!b) { ++ dev_err(&pdev->xdev->dev, ++ "Error creating PCI Frontend Bus!\n"); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ bus_entry->bus = b; ++ ++ list_add(&bus_entry->list, &pdev->root_buses); ++ ++ /* Claim resources before going "live" with our devices */ ++ pci_walk_bus(b, pcifront_claim_resource, pdev); ++ ++ pci_bus_add_devices(b); ++ ++ return 0; ++ ++ err_out: ++ kfree(bus_entry); ++ kfree(sd); ++ ++ return err; ++} ++ ++static void free_root_bus_devs(struct pci_bus *bus) ++{ ++ struct pci_dev *dev; ++ ++ while (!list_empty(&bus->devices)) { ++ dev = container_of(bus->devices.next, struct pci_dev, ++ bus_list); ++ dev_dbg(&dev->dev, "removing device\n"); ++ pci_remove_bus_device(dev); ++ } ++} ++ ++void pcifront_free_roots(struct pcifront_device *pdev) ++{ ++ struct pci_bus_entry *bus_entry, *t; ++ ++ dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); ++ ++ list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { ++ list_del(&bus_entry->list); ++ ++ free_root_bus_devs(bus_entry->bus); ++ ++ kfree(bus_entry->bus->sysdata); ++ ++ device_unregister(bus_entry->bus->bridge); ++ pci_remove_bus(bus_entry->bus); ++ ++ kfree(bus_entry); ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pcifront/pcifront.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pcifront/pcifront.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,40 @@ ++/* ++ * PCI Frontend - Common data structures & function declarations ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#ifndef __XEN_PCIFRONT_H__ ++#define __XEN_PCIFRONT_H__ ++ ++#include <linux/spinlock.h> ++#include <linux/pci.h> ++#include <xen/xenbus.h> ++#include <xen/interface/io/pciif.h> ++#include <xen/pcifront.h> ++ ++struct pci_bus_entry { ++ struct list_head list; ++ struct pci_bus *bus; ++}; ++ ++struct pcifront_device { ++ struct xenbus_device *xdev; ++ struct list_head root_buses; ++ spinlock_t dev_lock; ++ ++ int evtchn; ++ int gnt_ref; ++ ++ /* Lock this when doing any operations in sh_info */ ++ spinlock_t sh_info_lock; ++ struct xen_pci_sharedinfo *sh_info; ++}; ++ ++int pcifront_connect(struct pcifront_device *pdev); ++void pcifront_disconnect(struct pcifront_device *pdev); ++ ++int pcifront_scan_root(struct pcifront_device *pdev, ++ unsigned int domain, unsigned int bus); ++void pcifront_free_roots(struct pcifront_device *pdev); ++ ++#endif /* __XEN_PCIFRONT_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/pcifront/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/pcifront/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,295 @@ ++/* ++ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn) ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <xen/xenbus.h> ++#include <xen/gnttab.h> ++#include "pcifront.h" ++ ++#define INVALID_GRANT_REF (0) ++#define INVALID_EVTCHN (-1) ++ ++static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) ++{ ++ struct pcifront_device *pdev; ++ ++ pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL); ++ if (pdev == NULL) ++ goto out; ++ ++ pdev->sh_info = ++ (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); ++ if (pdev->sh_info == NULL) { ++ kfree(pdev); ++ pdev = NULL; ++ goto out; ++ } ++ pdev->sh_info->flags = 0; ++ ++ xdev->dev.driver_data = pdev; ++ pdev->xdev = xdev; ++ ++ INIT_LIST_HEAD(&pdev->root_buses); ++ ++ spin_lock_init(&pdev->dev_lock); ++ spin_lock_init(&pdev->sh_info_lock); ++ ++ pdev->evtchn = INVALID_EVTCHN; ++ pdev->gnt_ref = INVALID_GRANT_REF; ++ ++ dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n", ++ pdev, pdev->sh_info); ++ out: ++ return pdev; ++} ++ ++static void free_pdev(struct pcifront_device *pdev) ++{ ++ dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); ++ ++ pcifront_free_roots(pdev); ++ ++ if (pdev->evtchn != INVALID_EVTCHN) ++ xenbus_free_evtchn(pdev->xdev, pdev->evtchn); ++ ++ if (pdev->gnt_ref != INVALID_GRANT_REF) ++ gnttab_end_foreign_access(pdev->gnt_ref, 0, ++ (unsigned long)pdev->sh_info); ++ ++ pdev->xdev->dev.driver_data = NULL; ++ ++ kfree(pdev); ++} ++ ++static int pcifront_publish_info(struct pcifront_device *pdev) ++{ ++ int err = 0; ++ struct xenbus_transaction trans; ++ ++ err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); ++ if (err < 0) ++ goto out; ++ ++ pdev->gnt_ref = err; ++ ++ err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); ++ if (err) ++ goto out; ++ ++ do_publish: ++ err = xenbus_transaction_start(&trans); ++ if (err) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error writing configuration for backend " ++ "(start transaction)"); ++ goto out; ++ } ++ ++ err = xenbus_printf(trans, pdev->xdev->nodename, ++ "pci-op-ref", "%u", pdev->gnt_ref); ++ if (!err) ++ err = xenbus_printf(trans, pdev->xdev->nodename, ++ "event-channel", "%u", pdev->evtchn); ++ if (!err) ++ err = xenbus_printf(trans, pdev->xdev->nodename, ++ "magic", XEN_PCI_MAGIC); ++ ++ if (err) { ++ xenbus_transaction_end(trans, 1); ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error writing configuration for backend"); ++ goto out; ++ } else { ++ err = xenbus_transaction_end(trans, 0); ++ if (err == -EAGAIN) ++ goto do_publish; ++ else if (err) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error completing transaction " ++ "for backend"); ++ goto out; ++ } ++ } ++ ++ xenbus_switch_state(pdev->xdev, XenbusStateInitialised); ++ ++ dev_dbg(&pdev->xdev->dev, "publishing successful!\n"); ++ ++ out: ++ return err; ++} ++ ++static int pcifront_try_connect(struct pcifront_device *pdev) ++{ ++ int err = -EFAULT; ++ int i, num_roots, len; ++ char str[64]; ++ unsigned int domain, bus; ++ ++ spin_lock(&pdev->dev_lock); ++ ++ /* Only connect once */ ++ if (xenbus_read_driver_state(pdev->xdev->nodename) != ++ XenbusStateInitialised) ++ goto out; ++ ++ err = pcifront_connect(pdev); ++ if (err) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error connecting PCI Frontend"); ++ goto out; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, ++ "root_num", "%d", &num_roots); ++ if (err == -ENOENT) { ++ xenbus_dev_error(pdev->xdev, err, ++ "No PCI Roots found, trying 0000:00"); ++ err = pcifront_scan_root(pdev, 0, 0); ++ num_roots = 0; ++ } else if (err != 1) { ++ if (err == 0) ++ err = -EINVAL; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error reading number of PCI roots"); ++ goto out; ++ } ++ ++ for (i = 0; i < num_roots; i++) { ++ len = snprintf(str, sizeof(str), "root-%d", i); ++ if (unlikely(len >= (sizeof(str) - 1))) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, ++ "%x:%x", &domain, &bus); ++ if (err != 2) { ++ if (err >= 0) ++ err = -EINVAL; ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error reading PCI root %d", i); ++ goto out; ++ } ++ ++ err = pcifront_scan_root(pdev, domain, bus); ++ if (err) { ++ xenbus_dev_fatal(pdev->xdev, err, ++ "Error scanning PCI root %04x:%02x", ++ domain, bus); ++ goto out; ++ } ++ } ++ ++ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); ++ if (err) ++ goto out; ++ ++ out: ++ spin_unlock(&pdev->dev_lock); ++ return err; ++} ++ ++static int pcifront_try_disconnect(struct pcifront_device *pdev) ++{ ++ int err = 0; ++ enum xenbus_state prev_state; ++ ++ spin_lock(&pdev->dev_lock); ++ ++ prev_state = xenbus_read_driver_state(pdev->xdev->nodename); ++ ++ if (prev_state < XenbusStateClosing) ++ err = xenbus_switch_state(pdev->xdev, XenbusStateClosing); ++ ++ if (!err && prev_state == XenbusStateConnected) ++ pcifront_disconnect(pdev); ++ ++ spin_unlock(&pdev->dev_lock); ++ ++ return err; ++} ++ ++static void pcifront_backend_changed(struct xenbus_device *xdev, ++ enum xenbus_state be_state) ++{ ++ struct pcifront_device *pdev = xdev->dev.driver_data; ++ ++ switch (be_state) { ++ case XenbusStateClosing: ++ dev_warn(&xdev->dev, "backend going away!\n"); ++ pcifront_try_disconnect(pdev); ++ break; ++ ++ case XenbusStateUnknown: ++ case XenbusStateClosed: ++ dev_warn(&xdev->dev, "backend went away!\n"); ++ pcifront_try_disconnect(pdev); ++ ++ device_unregister(&pdev->xdev->dev); ++ break; ++ ++ case XenbusStateConnected: ++ pcifront_try_connect(pdev); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static int pcifront_xenbus_probe(struct xenbus_device *xdev, ++ const struct xenbus_device_id *id) ++{ ++ int err = 0; ++ struct pcifront_device *pdev = alloc_pdev(xdev); ++ ++ if (pdev == NULL) { ++ err = -ENOMEM; ++ xenbus_dev_fatal(xdev, err, ++ "Error allocating pcifront_device struct"); ++ goto out; ++ } ++ ++ err = pcifront_publish_info(pdev); ++ ++ out: ++ return err; ++} ++ ++static int pcifront_xenbus_remove(struct xenbus_device *xdev) ++{ ++ if (xdev->dev.driver_data) ++ free_pdev(xdev->dev.driver_data); ++ ++ return 0; ++} ++ ++static struct xenbus_device_id xenpci_ids[] = { ++ {"pci"}, ++ {{0}}, ++}; ++ ++static struct xenbus_driver xenbus_pcifront_driver = { ++ .name = "pcifront", ++ .owner = THIS_MODULE, ++ .ids = xenpci_ids, ++ .probe = pcifront_xenbus_probe, ++ .remove = pcifront_xenbus_remove, ++ .otherend_changed = pcifront_backend_changed, ++}; ++ ++static int __init pcifront_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ return xenbus_register_frontend(&xenbus_pcifront_driver); ++} ++ ++/* Initialize after the Xen PCI Frontend Stub is initialized */ ++subsys_initcall(pcifront_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/privcmd/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/privcmd/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++obj-$(CONFIG_XEN_PRIVCMD) := privcmd.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/privcmd/privcmd.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/privcmd/privcmd.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,284 @@ ++/****************************************************************************** ++ * privcmd.c ++ * ++ * Interface to privileged domain-0 commands. ++ * ++ * Copyright (c) 2002-2004, K A Fraser, B Dragovic ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/mman.h> ++#include <linux/swap.h> ++#include <linux/smp_lock.h> ++#include <linux/highmem.h> ++#include <linux/pagemap.h> ++#include <linux/seq_file.h> ++#include <linux/kthread.h> ++#include <asm/hypervisor.h> ++ ++#include <asm/pgalloc.h> ++#include <asm/pgtable.h> ++#include <asm/uaccess.h> ++#include <asm/tlb.h> ++#include <asm/hypervisor.h> ++#include <xen/public/privcmd.h> ++#include <xen/interface/xen.h> ++#include <xen/xen_proc.h> ++ ++static struct proc_dir_entry *privcmd_intf; ++static struct proc_dir_entry *capabilities_intf; ++ ++#ifndef HAVE_ARCH_PRIVCMD_MMAP ++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); ++#endif ++ ++static int privcmd_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long data) ++{ ++ int ret = -ENOSYS; ++ void __user *udata = (void __user *) data; ++ ++ switch (cmd) { ++ case IOCTL_PRIVCMD_HYPERCALL: { ++ privcmd_hypercall_t hypercall; ++ ++ if (copy_from_user(&hypercall, udata, sizeof(hypercall))) ++ return -EFAULT; ++ ++#if defined(__i386__) ++ if (hypercall.op >= (PAGE_SIZE >> 5)) ++ break; ++ __asm__ __volatile__ ( ++ "pushl %%ebx; pushl %%ecx; pushl %%edx; " ++ "pushl %%esi; pushl %%edi; " ++ "movl 8(%%eax),%%ebx ;" ++ "movl 16(%%eax),%%ecx ;" ++ "movl 24(%%eax),%%edx ;" ++ "movl 32(%%eax),%%esi ;" ++ "movl 40(%%eax),%%edi ;" ++ "movl (%%eax),%%eax ;" ++ "shll $5,%%eax ;" ++ "addl $hypercall_page,%%eax ;" ++ "call *%%eax ;" ++ "popl %%edi; popl %%esi; popl %%edx; " ++ "popl %%ecx; popl %%ebx" ++ : "=a" (ret) : "0" (&hypercall) : "memory" ); ++#elif defined (__x86_64__) ++ if (hypercall.op < (PAGE_SIZE >> 5)) { ++ long ign1, ign2, ign3; ++ __asm__ __volatile__ ( ++ "movq %8,%%r10; movq %9,%%r8;" ++ "shll $5,%%eax ;" ++ "addq $hypercall_page,%%rax ;" ++ "call *%%rax" ++ : "=a" (ret), "=D" (ign1), ++ "=S" (ign2), "=d" (ign3) ++ : "0" ((unsigned int)hypercall.op), ++ "1" (hypercall.arg[0]), ++ "2" (hypercall.arg[1]), ++ "3" (hypercall.arg[2]), ++ "g" (hypercall.arg[3]), ++ "g" (hypercall.arg[4]) ++ : "r8", "r10", "memory" ); ++ } ++#elif defined (__ia64__) ++ ret = privcmd_hypercall(&hypercall); ++#endif ++ } ++ break; ++ ++ case IOCTL_PRIVCMD_MMAP: { ++ privcmd_mmap_t mmapcmd; ++ privcmd_mmap_entry_t msg; ++ privcmd_mmap_entry_t __user *p; ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ unsigned long va; ++ int i, rc; ++ ++ if (!is_initial_xendomain()) ++ return -EPERM; ++ ++ if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) ++ return -EFAULT; ++ ++ p = mmapcmd.entry; ++ if (copy_from_user(&msg, p, sizeof(msg))) ++ return -EFAULT; ++ ++ down_read(&mm->mmap_sem); ++ ++ vma = find_vma(mm, msg.va); ++ rc = -EINVAL; ++ if (!vma || (msg.va != vma->vm_start) || ++ !privcmd_enforce_singleshot_mapping(vma)) ++ goto mmap_out; ++ ++ va = vma->vm_start; ++ ++ for (i = 0; i < mmapcmd.num; i++) { ++ rc = -EFAULT; ++ if (copy_from_user(&msg, p, sizeof(msg))) ++ goto mmap_out; ++ ++ /* Do not allow range to wrap the address space. */ ++ rc = -EINVAL; ++ if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) || ++ ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va)) ++ goto mmap_out; ++ ++ /* Range chunks must be contiguous in va space. */ ++ if ((msg.va != va) || ++ ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end)) ++ goto mmap_out; ++ ++ if ((rc = direct_remap_pfn_range( ++ vma, ++ msg.va & PAGE_MASK, ++ msg.mfn, ++ msg.npages << PAGE_SHIFT, ++ vma->vm_page_prot, ++ mmapcmd.dom)) < 0) ++ goto mmap_out; ++ ++ p++; ++ va += msg.npages << PAGE_SHIFT; ++ } ++ ++ rc = 0; ++ ++ mmap_out: ++ up_read(&mm->mmap_sem); ++ ret = rc; ++ } ++ break; ++ ++ case IOCTL_PRIVCMD_MMAPBATCH: { ++ privcmd_mmapbatch_t m; ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ xen_pfn_t __user *p; ++ unsigned long addr, mfn, nr_pages; ++ int i; ++ ++ if (!is_initial_xendomain()) ++ return -EPERM; ++ ++ if (copy_from_user(&m, udata, sizeof(m))) ++ return -EFAULT; ++ ++ nr_pages = m.num; ++ if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT))) ++ return -EINVAL; ++ ++ down_read(&mm->mmap_sem); ++ ++ vma = find_vma(mm, m.addr); ++ if (!vma || ++ (m.addr != vma->vm_start) || ++ ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) || ++ !privcmd_enforce_singleshot_mapping(vma)) { ++ up_read(&mm->mmap_sem); ++ return -EINVAL; ++ } ++ ++ p = m.arr; ++ addr = m.addr; ++ for (i = 0; i < nr_pages; i++, addr += PAGE_SIZE, p++) { ++ if (get_user(mfn, p)) { ++ up_read(&mm->mmap_sem); ++ return -EFAULT; ++ } ++ ++ ret = direct_remap_pfn_range(vma, addr & PAGE_MASK, ++ mfn, PAGE_SIZE, ++ vma->vm_page_prot, m.dom); ++ if (ret < 0) ++ put_user(0xF0000000 | mfn, p); ++ } ++ ++ up_read(&mm->mmap_sem); ++ ret = 0; ++ } ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifndef HAVE_ARCH_PRIVCMD_MMAP ++static struct page *privcmd_nopage(struct vm_area_struct *vma, ++ unsigned long address, ++ int *type) ++{ ++ return NOPAGE_SIGBUS; ++} ++ ++static struct vm_operations_struct privcmd_vm_ops = { ++ .nopage = privcmd_nopage ++}; ++ ++static int privcmd_mmap(struct file * file, struct vm_area_struct * vma) ++{ ++ /* Unsupported for auto-translate guests. */ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return -ENOSYS; ++ ++ /* DONTCOPY is essential for Xen as copy_page_range is broken. */ ++ vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP; ++ vma->vm_ops = &privcmd_vm_ops; ++ vma->vm_private_data = NULL; ++ ++ return 0; ++} ++ ++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) ++{ ++ return (xchg(&vma->vm_private_data, (void *)1) == NULL); ++} ++#endif ++ ++static const struct file_operations privcmd_file_ops = { ++ .ioctl = privcmd_ioctl, ++ .mmap = privcmd_mmap, ++}; ++ ++static int capabilities_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ *page = 0; ++ ++ if (is_initial_xendomain()) ++ len = sprintf( page, "control_d\n" ); ++ ++ *eof = 1; ++ return len; ++} ++ ++static int __init privcmd_init(void) ++{ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ privcmd_intf = create_xen_proc_entry("privcmd", 0400); ++ if (privcmd_intf != NULL) ++ privcmd_intf->proc_fops = &privcmd_file_ops; ++ ++ capabilities_intf = create_xen_proc_entry("capabilities", 0400 ); ++ if (capabilities_intf != NULL) ++ capabilities_intf->read_proc = capabilities_read; ++ ++ return 0; ++} ++ ++__initcall(privcmd_init); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/tpmback/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/tpmback/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,4 @@ ++ ++obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmbk.o ++ ++tpmbk-y += tpmback.o interface.o xenbus.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/tpmback/common.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/tpmback/common.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,85 @@ ++/****************************************************************************** ++ * drivers/xen/tpmback/common.h ++ */ ++ ++#ifndef __TPM__BACKEND__COMMON_H__ ++#define __TPM__BACKEND__COMMON_H__ ++ ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <xen/evtchn.h> ++#include <xen/driver_util.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/io/tpmif.h> ++#include <asm/io.h> ++#include <asm/pgalloc.h> ++ ++#define DPRINTK(_f, _a...) \ ++ pr_debug("(file=%s, line=%d) " _f, \ ++ __FILE__ , __LINE__ , ## _a ) ++ ++struct backend_info; ++ ++typedef struct tpmif_st { ++ struct list_head tpmif_list; ++ /* Unique identifier for this interface. */ ++ domid_t domid; ++ unsigned int handle; ++ ++ /* Physical parameters of the comms window. */ ++ unsigned int irq; ++ ++ /* The shared rings and indexes. */ ++ tpmif_tx_interface_t *tx; ++ struct vm_struct *tx_area; ++ ++ /* Miscellaneous private stuff. */ ++ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; ++ int active; ++ ++ struct tpmif_st *hash_next; ++ struct list_head list; /* scheduling list */ ++ atomic_t refcnt; ++ ++ struct backend_info *bi; ++ ++ grant_handle_t shmem_handle; ++ grant_ref_t shmem_ref; ++ struct page **mmap_pages; ++ ++ char devname[20]; ++} tpmif_t; ++ ++void tpmif_disconnect_complete(tpmif_t * tpmif); ++tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi); ++void tpmif_interface_init(void); ++void tpmif_interface_exit(void); ++void tpmif_schedule_work(tpmif_t * tpmif); ++void tpmif_deschedule_work(tpmif_t * tpmif); ++void tpmif_xenbus_init(void); ++void tpmif_xenbus_exit(void); ++int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn); ++irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs); ++ ++long int tpmback_get_instance(struct backend_info *bi); ++ ++int vtpm_release_packets(tpmif_t * tpmif, int send_msgs); ++ ++ ++#define tpmif_get(_b) (atomic_inc(&(_b)->refcnt)) ++#define tpmif_put(_b) \ ++ do { \ ++ if (atomic_dec_and_test(&(_b)->refcnt)) \ ++ tpmif_disconnect_complete(_b); \ ++ } while (0) ++ ++extern int num_frontends; ++ ++static inline unsigned long idx_to_kaddr(tpmif_t *t, unsigned int idx) ++{ ++ return (unsigned long)pfn_to_kaddr(page_to_pfn(t->mmap_pages[idx])); ++} ++ ++#endif /* __TPMIF__BACKEND__COMMON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/tpmback/interface.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/tpmback/interface.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,167 @@ ++ /***************************************************************************** ++ * drivers/xen/tpmback/interface.c ++ * ++ * Vritual TPM interface management. ++ * ++ * Copyright (c) 2005, IBM Corporation ++ * ++ * Author: Stefan Berger, stefanb@us.ibm.com ++ * ++ * This code has been derived from drivers/xen/netback/interface.c ++ * Copyright (c) 2004, Keir Fraser ++ */ ++ ++#include "common.h" ++#include <xen/balloon.h> ++#include <xen/gnttab.h> ++ ++static struct kmem_cache *tpmif_cachep; ++int num_frontends = 0; ++ ++LIST_HEAD(tpmif_list); ++ ++static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi) ++{ ++ tpmif_t *tpmif; ++ ++ tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL); ++ if (tpmif == NULL) ++ goto out_of_memory; ++ ++ memset(tpmif, 0, sizeof (*tpmif)); ++ tpmif->domid = domid; ++ tpmif->status = DISCONNECTED; ++ tpmif->bi = bi; ++ snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid); ++ atomic_set(&tpmif->refcnt, 1); ++ ++ tpmif->mmap_pages = alloc_empty_pages_and_pagevec(TPMIF_TX_RING_SIZE); ++ if (tpmif->mmap_pages == NULL) ++ goto out_of_memory; ++ ++ list_add(&tpmif->tpmif_list, &tpmif_list); ++ num_frontends++; ++ ++ return tpmif; ++ ++ out_of_memory: ++ if (tpmif != NULL) ++ kmem_cache_free(tpmif_cachep, tpmif); ++ printk("%s: out of memory\n", __FUNCTION__); ++ return ERR_PTR(-ENOMEM); ++} ++ ++static void free_tpmif(tpmif_t * tpmif) ++{ ++ num_frontends--; ++ list_del(&tpmif->tpmif_list); ++ free_empty_pages_and_pagevec(tpmif->mmap_pages, TPMIF_TX_RING_SIZE); ++ kmem_cache_free(tpmif_cachep, tpmif); ++} ++ ++tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi) ++{ ++ tpmif_t *tpmif; ++ ++ list_for_each_entry(tpmif, &tpmif_list, tpmif_list) { ++ if (tpmif->bi == bi) { ++ if (tpmif->domid == domid) { ++ tpmif_get(tpmif); ++ return tpmif; ++ } else { ++ return ERR_PTR(-EEXIST); ++ } ++ } ++ } ++ ++ return alloc_tpmif(domid, bi); ++} ++ ++static int map_frontend_page(tpmif_t *tpmif, unsigned long shared_page) ++{ ++ struct gnttab_map_grant_ref op; ++ ++ gnttab_set_map_op(&op, (unsigned long)tpmif->tx_area->addr, ++ GNTMAP_host_map, shared_page, tpmif->domid); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status) { ++ DPRINTK(" Grant table operation failure !\n"); ++ return op.status; ++ } ++ ++ tpmif->shmem_ref = shared_page; ++ tpmif->shmem_handle = op.handle; ++ ++ return 0; ++} ++ ++static void unmap_frontend_page(tpmif_t *tpmif) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)tpmif->tx_area->addr, ++ GNTMAP_host_map, tpmif->shmem_handle); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++} ++ ++int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn) ++{ ++ int err; ++ ++ if (tpmif->irq) ++ return 0; ++ ++ if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL) ++ return -ENOMEM; ++ ++ err = map_frontend_page(tpmif, shared_page); ++ if (err) { ++ free_vm_area(tpmif->tx_area); ++ return err; ++ } ++ ++ tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr; ++ ++ err = bind_interdomain_evtchn_to_irqhandler( ++ tpmif->domid, evtchn, tpmif_be_int, 0, tpmif->devname, tpmif); ++ if (err < 0) { ++ unmap_frontend_page(tpmif); ++ free_vm_area(tpmif->tx_area); ++ return err; ++ } ++ tpmif->irq = err; ++ ++ tpmif->shmem_ref = shared_page; ++ tpmif->active = 1; ++ ++ return 0; ++} ++ ++void tpmif_disconnect_complete(tpmif_t *tpmif) ++{ ++ if (tpmif->irq) ++ unbind_from_irqhandler(tpmif->irq, tpmif); ++ ++ if (tpmif->tx) { ++ unmap_frontend_page(tpmif); ++ free_vm_area(tpmif->tx_area); ++ } ++ ++ free_tpmif(tpmif); ++} ++ ++void __init tpmif_interface_init(void) ++{ ++ tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t), ++ 0, 0, NULL, NULL); ++} ++ ++void __exit tpmif_interface_exit(void) ++{ ++ kmem_cache_destroy(tpmif_cachep); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/tpmback/tpmback.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/tpmback/tpmback.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,944 @@ ++/****************************************************************************** ++ * drivers/xen/tpmback/tpmback.c ++ * ++ * Copyright (c) 2005, IBM Corporation ++ * ++ * Author: Stefan Berger, stefanb@us.ibm.com ++ * Grant table support: Mahadevan Gomathisankaran ++ * ++ * This code has been derived from drivers/xen/netback/netback.c ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ */ ++ ++#include "common.h" ++#include <xen/evtchn.h> ++ ++#include <linux/types.h> ++#include <linux/list.h> ++#include <linux/miscdevice.h> ++#include <linux/poll.h> ++#include <asm/uaccess.h> ++#include <xen/xenbus.h> ++#include <xen/interface/grant_table.h> ++#include <xen/gnttab.h> ++ ++/* local data structures */ ++struct data_exchange { ++ struct list_head pending_pak; ++ struct list_head current_pak; ++ unsigned int copied_so_far; ++ u8 has_opener:1; ++ u8 aborted:1; ++ rwlock_t pak_lock; // protects all of the previous fields ++ wait_queue_head_t wait_queue; ++}; ++ ++struct vtpm_resp_hdr { ++ uint32_t instance_no; ++ uint16_t tag_no; ++ uint32_t len_no; ++ uint32_t ordinal_no; ++} __attribute__ ((packed)); ++ ++struct packet { ++ struct list_head next; ++ unsigned int data_len; ++ u8 *data_buffer; ++ tpmif_t *tpmif; ++ u32 tpm_instance; ++ u8 req_tag; ++ u32 last_read; ++ u8 flags; ++ struct timer_list processing_timer; ++}; ++ ++enum { ++ PACKET_FLAG_DISCARD_RESPONSE = 1, ++}; ++ ++/* local variables */ ++static struct data_exchange dataex; ++ ++/* local function prototypes */ ++static int _packet_write(struct packet *pak, ++ const char *data, size_t size, int userbuffer); ++static void processing_timeout(unsigned long ptr); ++static int packet_read_shmem(struct packet *pak, ++ tpmif_t * tpmif, ++ u32 offset, ++ char *buffer, int isuserbuffer, u32 left); ++static int vtpm_queue_packet(struct packet *pak); ++ ++/*************************************************************** ++ Buffer copying fo user and kernel space buffes. ++***************************************************************/ ++static inline int copy_from_buffer(void *to, ++ const void *from, unsigned long size, ++ int isuserbuffer) ++{ ++ if (isuserbuffer) { ++ if (copy_from_user(to, (void __user *)from, size)) ++ return -EFAULT; ++ } else { ++ memcpy(to, from, size); ++ } ++ return 0; ++} ++ ++static inline int copy_to_buffer(void *to, ++ const void *from, unsigned long size, ++ int isuserbuffer) ++{ ++ if (isuserbuffer) { ++ if (copy_to_user((void __user *)to, from, size)) ++ return -EFAULT; ++ } else { ++ memcpy(to, from, size); ++ } ++ return 0; ++} ++ ++ ++static void dataex_init(struct data_exchange *dataex) ++{ ++ INIT_LIST_HEAD(&dataex->pending_pak); ++ INIT_LIST_HEAD(&dataex->current_pak); ++ dataex->has_opener = 0; ++ rwlock_init(&dataex->pak_lock); ++ init_waitqueue_head(&dataex->wait_queue); ++} ++ ++/*************************************************************** ++ Packet-related functions ++***************************************************************/ ++ ++static struct packet *packet_find_instance(struct list_head *head, ++ u32 tpm_instance) ++{ ++ struct packet *pak; ++ struct list_head *p; ++ ++ /* ++ * traverse the list of packets and return the first ++ * one with the given instance number ++ */ ++ list_for_each(p, head) { ++ pak = list_entry(p, struct packet, next); ++ ++ if (pak->tpm_instance == tpm_instance) { ++ return pak; ++ } ++ } ++ return NULL; ++} ++ ++static struct packet *packet_find_packet(struct list_head *head, void *packet) ++{ ++ struct packet *pak; ++ struct list_head *p; ++ ++ /* ++ * traverse the list of packets and return the first ++ * one with the given instance number ++ */ ++ list_for_each(p, head) { ++ pak = list_entry(p, struct packet, next); ++ ++ if (pak == packet) { ++ return pak; ++ } ++ } ++ return NULL; ++} ++ ++static struct packet *packet_alloc(tpmif_t * tpmif, ++ u32 size, u8 req_tag, u8 flags) ++{ ++ struct packet *pak = NULL; ++ pak = kzalloc(sizeof (struct packet), GFP_ATOMIC); ++ if (NULL != pak) { ++ if (tpmif) { ++ pak->tpmif = tpmif; ++ pak->tpm_instance = tpmback_get_instance(tpmif->bi); ++ tpmif_get(tpmif); ++ } ++ pak->data_len = size; ++ pak->req_tag = req_tag; ++ pak->last_read = 0; ++ pak->flags = flags; ++ ++ /* ++ * cannot do tpmif_get(tpmif); bad things happen ++ * on the last tpmif_put() ++ */ ++ init_timer(&pak->processing_timer); ++ pak->processing_timer.function = processing_timeout; ++ pak->processing_timer.data = (unsigned long)pak; ++ } ++ return pak; ++} ++ ++static void inline packet_reset(struct packet *pak) ++{ ++ pak->last_read = 0; ++} ++ ++static void packet_free(struct packet *pak) ++{ ++ if (timer_pending(&pak->processing_timer)) { ++ BUG(); ++ } ++ ++ if (pak->tpmif) ++ tpmif_put(pak->tpmif); ++ kfree(pak->data_buffer); ++ /* ++ * cannot do tpmif_put(pak->tpmif); bad things happen ++ * on the last tpmif_put() ++ */ ++ kfree(pak); ++} ++ ++ ++/* ++ * Write data to the shared memory and send it to the FE. ++ */ ++static int packet_write(struct packet *pak, ++ const char *data, size_t size, int isuserbuffer) ++{ ++ int rc = 0; ++ ++ if (0 != (pak->flags & PACKET_FLAG_DISCARD_RESPONSE)) { ++ /* Don't send a respone to this packet. Just acknowledge it. */ ++ rc = size; ++ } else { ++ rc = _packet_write(pak, data, size, isuserbuffer); ++ } ++ ++ return rc; ++} ++ ++int _packet_write(struct packet *pak, ++ const char *data, size_t size, int isuserbuffer) ++{ ++ /* ++ * Write into the shared memory pages directly ++ * and send it to the front end. ++ */ ++ tpmif_t *tpmif = pak->tpmif; ++ grant_handle_t handle; ++ int rc = 0; ++ unsigned int i = 0; ++ unsigned int offset = 0; ++ ++ if (tpmif == NULL) { ++ return -EFAULT; ++ } ++ ++ if (tpmif->status == DISCONNECTED) { ++ return size; ++ } ++ ++ while (offset < size && i < TPMIF_TX_RING_SIZE) { ++ unsigned int tocopy; ++ struct gnttab_map_grant_ref map_op; ++ struct gnttab_unmap_grant_ref unmap_op; ++ tpmif_tx_request_t *tx; ++ ++ tx = &tpmif->tx->ring[i].req; ++ ++ if (0 == tx->addr) { ++ DPRINTK("ERROR: Buffer for outgoing packet NULL?! i=%d\n", i); ++ return 0; ++ } ++ ++ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i), ++ GNTMAP_host_map, tx->ref, tpmif->domid); ++ ++ if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, ++ &map_op, 1))) { ++ BUG(); ++ } ++ ++ handle = map_op.handle; ++ ++ if (map_op.status) { ++ DPRINTK(" Grant table operation failure !\n"); ++ return 0; ++ } ++ ++ tocopy = min_t(size_t, size - offset, PAGE_SIZE); ++ ++ if (copy_from_buffer((void *)(idx_to_kaddr(tpmif, i) | ++ (tx->addr & ~PAGE_MASK)), ++ &data[offset], tocopy, isuserbuffer)) { ++ tpmif_put(tpmif); ++ return -EFAULT; ++ } ++ tx->size = tocopy; ++ ++ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i), ++ GNTMAP_host_map, handle); ++ ++ if (unlikely ++ (HYPERVISOR_grant_table_op ++ (GNTTABOP_unmap_grant_ref, &unmap_op, 1))) { ++ BUG(); ++ } ++ ++ offset += tocopy; ++ i++; ++ } ++ ++ rc = offset; ++ DPRINTK("Notifying frontend via irq %d\n", tpmif->irq); ++ notify_remote_via_irq(tpmif->irq); ++ ++ return rc; ++} ++ ++/* ++ * Read data from the shared memory and copy it directly into the ++ * provided buffer. Advance the read_last indicator which tells ++ * how many bytes have already been read. ++ */ ++static int packet_read(struct packet *pak, size_t numbytes, ++ char *buffer, size_t buffersize, int isuserbuffer) ++{ ++ tpmif_t *tpmif = pak->tpmif; ++ ++ /* ++ * Read 'numbytes' of data from the buffer. The first 4 ++ * bytes are the instance number in network byte order, ++ * after that come the data from the shared memory buffer. ++ */ ++ u32 to_copy; ++ u32 offset = 0; ++ u32 room_left = buffersize; ++ ++ if (pak->last_read < 4) { ++ /* ++ * copy the instance number into the buffer ++ */ ++ u32 instance_no = htonl(pak->tpm_instance); ++ u32 last_read = pak->last_read; ++ ++ to_copy = min_t(size_t, 4 - last_read, numbytes); ++ ++ if (copy_to_buffer(&buffer[0], ++ &(((u8 *) & instance_no)[last_read]), ++ to_copy, isuserbuffer)) { ++ return -EFAULT; ++ } ++ ++ pak->last_read += to_copy; ++ offset += to_copy; ++ room_left -= to_copy; ++ } ++ ++ /* ++ * If the packet has a data buffer appended, read from it... ++ */ ++ ++ if (room_left > 0) { ++ if (pak->data_buffer) { ++ u32 to_copy = min_t(u32, pak->data_len - offset, room_left); ++ u32 last_read = pak->last_read - 4; ++ ++ if (copy_to_buffer(&buffer[offset], ++ &pak->data_buffer[last_read], ++ to_copy, isuserbuffer)) { ++ return -EFAULT; ++ } ++ pak->last_read += to_copy; ++ offset += to_copy; ++ } else { ++ offset = packet_read_shmem(pak, ++ tpmif, ++ offset, ++ buffer, ++ isuserbuffer, room_left); ++ } ++ } ++ return offset; ++} ++ ++static int packet_read_shmem(struct packet *pak, ++ tpmif_t * tpmif, ++ u32 offset, char *buffer, int isuserbuffer, ++ u32 room_left) ++{ ++ u32 last_read = pak->last_read - 4; ++ u32 i = (last_read / PAGE_SIZE); ++ u32 pg_offset = last_read & (PAGE_SIZE - 1); ++ u32 to_copy; ++ grant_handle_t handle; ++ ++ tpmif_tx_request_t *tx; ++ ++ tx = &tpmif->tx->ring[0].req; ++ /* ++ * Start copying data at the page with index 'index' ++ * and within that page at offset 'offset'. ++ * Copy a maximum of 'room_left' bytes. ++ */ ++ to_copy = min_t(u32, PAGE_SIZE - pg_offset, room_left); ++ while (to_copy > 0) { ++ void *src; ++ struct gnttab_map_grant_ref map_op; ++ struct gnttab_unmap_grant_ref unmap_op; ++ ++ tx = &tpmif->tx->ring[i].req; ++ ++ gnttab_set_map_op(&map_op, idx_to_kaddr(tpmif, i), ++ GNTMAP_host_map, tx->ref, tpmif->domid); ++ ++ if (unlikely(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, ++ &map_op, 1))) { ++ BUG(); ++ } ++ ++ if (map_op.status) { ++ DPRINTK(" Grant table operation failure !\n"); ++ return -EFAULT; ++ } ++ ++ handle = map_op.handle; ++ ++ if (to_copy > tx->size) { ++ /* ++ * User requests more than what's available ++ */ ++ to_copy = min_t(u32, tx->size, to_copy); ++ } ++ ++ DPRINTK("Copying from mapped memory at %08lx\n", ++ (unsigned long)(idx_to_kaddr(tpmif, i) | ++ (tx->addr & ~PAGE_MASK))); ++ ++ src = (void *)(idx_to_kaddr(tpmif, i) | ++ ((tx->addr & ~PAGE_MASK) + pg_offset)); ++ if (copy_to_buffer(&buffer[offset], ++ src, to_copy, isuserbuffer)) { ++ return -EFAULT; ++ } ++ ++ DPRINTK("Data from TPM-FE of domain %d are %d %d %d %d\n", ++ tpmif->domid, buffer[offset], buffer[offset + 1], ++ buffer[offset + 2], buffer[offset + 3]); ++ ++ gnttab_set_unmap_op(&unmap_op, idx_to_kaddr(tpmif, i), ++ GNTMAP_host_map, handle); ++ ++ if (unlikely ++ (HYPERVISOR_grant_table_op ++ (GNTTABOP_unmap_grant_ref, &unmap_op, 1))) { ++ BUG(); ++ } ++ ++ offset += to_copy; ++ pg_offset = 0; ++ last_read += to_copy; ++ room_left -= to_copy; ++ ++ to_copy = min_t(u32, PAGE_SIZE, room_left); ++ i++; ++ } /* while (to_copy > 0) */ ++ /* ++ * Adjust the last_read pointer ++ */ ++ pak->last_read = last_read + 4; ++ return offset; ++} ++ ++/* ============================================================ ++ * The file layer for reading data from this device ++ * ============================================================ ++ */ ++static int vtpm_op_open(struct inode *inode, struct file *f) ++{ ++ int rc = 0; ++ unsigned long flags; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ if (dataex.has_opener == 0) { ++ dataex.has_opener = 1; ++ } else { ++ rc = -EPERM; ++ } ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ return rc; ++} ++ ++static ssize_t vtpm_op_read(struct file *file, ++ char __user * data, size_t size, loff_t * offset) ++{ ++ int ret_size = -ENODATA; ++ struct packet *pak = NULL; ++ unsigned long flags; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ if (dataex.aborted) { ++ dataex.aborted = 0; ++ dataex.copied_so_far = 0; ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ return -EIO; ++ } ++ ++ if (list_empty(&dataex.pending_pak)) { ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ wait_event_interruptible(dataex.wait_queue, ++ !list_empty(&dataex.pending_pak)); ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ dataex.copied_so_far = 0; ++ } ++ ++ if (!list_empty(&dataex.pending_pak)) { ++ unsigned int left; ++ ++ pak = list_entry(dataex.pending_pak.next, struct packet, next); ++ left = pak->data_len - dataex.copied_so_far; ++ list_del(&pak->next); ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ ++ DPRINTK("size given by app: %d, available: %d\n", size, left); ++ ++ ret_size = min_t(size_t, size, left); ++ ++ ret_size = packet_read(pak, ret_size, data, size, 1); ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ ++ if (ret_size < 0) { ++ del_singleshot_timer_sync(&pak->processing_timer); ++ packet_free(pak); ++ dataex.copied_so_far = 0; ++ } else { ++ DPRINTK("Copied %d bytes to user buffer\n", ret_size); ++ ++ dataex.copied_so_far += ret_size; ++ if (dataex.copied_so_far >= pak->data_len + 4) { ++ DPRINTK("All data from this packet given to app.\n"); ++ /* All data given to app */ ++ ++ del_singleshot_timer_sync(&pak-> ++ processing_timer); ++ list_add_tail(&pak->next, &dataex.current_pak); ++ /* ++ * The more fontends that are handled at the same time, ++ * the more time we give the TPM to process the request. ++ */ ++ mod_timer(&pak->processing_timer, ++ jiffies + (num_frontends * 60 * HZ)); ++ dataex.copied_so_far = 0; ++ } else { ++ list_add(&pak->next, &dataex.pending_pak); ++ } ++ } ++ } ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ ++ DPRINTK("Returning result from read to app: %d\n", ret_size); ++ ++ return ret_size; ++} ++ ++/* ++ * Write operation - only works after a previous read operation! ++ */ ++static ssize_t vtpm_op_write(struct file *file, ++ const char __user * data, size_t size, ++ loff_t * offset) ++{ ++ struct packet *pak; ++ int rc = 0; ++ unsigned int off = 4; ++ unsigned long flags; ++ struct vtpm_resp_hdr vrh; ++ ++ /* ++ * Minimum required packet size is: ++ * 4 bytes for instance number ++ * 2 bytes for tag ++ * 4 bytes for paramSize ++ * 4 bytes for the ordinal ++ * sum: 14 bytes ++ */ ++ if (size < sizeof (vrh)) ++ return -EFAULT; ++ ++ if (copy_from_user(&vrh, data, sizeof (vrh))) ++ return -EFAULT; ++ ++ /* malformed packet? */ ++ if ((off + ntohl(vrh.len_no)) != size) ++ return -EFAULT; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ pak = packet_find_instance(&dataex.current_pak, ++ ntohl(vrh.instance_no)); ++ ++ if (pak == NULL) { ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ DPRINTK(KERN_ALERT "No associated packet! (inst=%d)\n", ++ ntohl(vrh.instance_no)); ++ return -EFAULT; ++ } ++ ++ del_singleshot_timer_sync(&pak->processing_timer); ++ list_del(&pak->next); ++ ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ ++ /* ++ * The first 'offset' bytes must be the instance number - skip them. ++ */ ++ size -= off; ++ ++ rc = packet_write(pak, &data[off], size, 1); ++ ++ if (rc > 0) { ++ /* I neglected the first 4 bytes */ ++ rc += off; ++ } ++ packet_free(pak); ++ return rc; ++} ++ ++static int vtpm_op_release(struct inode *inode, struct file *file) ++{ ++ unsigned long flags; ++ ++ vtpm_release_packets(NULL, 1); ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ dataex.has_opener = 0; ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ return 0; ++} ++ ++static unsigned int vtpm_op_poll(struct file *file, ++ struct poll_table_struct *pts) ++{ ++ unsigned int flags = POLLOUT | POLLWRNORM; ++ ++ poll_wait(file, &dataex.wait_queue, pts); ++ if (!list_empty(&dataex.pending_pak)) { ++ flags |= POLLIN | POLLRDNORM; ++ } ++ return flags; ++} ++ ++static const struct file_operations vtpm_ops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .open = vtpm_op_open, ++ .read = vtpm_op_read, ++ .write = vtpm_op_write, ++ .release = vtpm_op_release, ++ .poll = vtpm_op_poll, ++}; ++ ++static struct miscdevice vtpms_miscdevice = { ++ .minor = 225, ++ .name = "vtpm", ++ .fops = &vtpm_ops, ++}; ++ ++/*************************************************************** ++ Utility functions ++***************************************************************/ ++ ++static int tpm_send_fail_message(struct packet *pak, u8 req_tag) ++{ ++ int rc; ++ static const unsigned char tpm_error_message_fail[] = { ++ 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, ++ 0x00, 0x00, 0x00, 0x09 /* TPM_FAIL */ ++ }; ++ unsigned char buffer[sizeof (tpm_error_message_fail)]; ++ ++ memcpy(buffer, tpm_error_message_fail, ++ sizeof (tpm_error_message_fail)); ++ /* ++ * Insert the right response tag depending on the given tag ++ * All response tags are '+3' to the request tag. ++ */ ++ buffer[1] = req_tag + 3; ++ ++ /* ++ * Write the data to shared memory and notify the front-end ++ */ ++ rc = packet_write(pak, buffer, sizeof (buffer), 0); ++ ++ return rc; ++} ++ ++static int _vtpm_release_packets(struct list_head *head, ++ tpmif_t * tpmif, int send_msgs) ++{ ++ int aborted = 0; ++ int c = 0; ++ struct packet *pak; ++ struct list_head *pos, *tmp; ++ ++ list_for_each_safe(pos, tmp, head) { ++ pak = list_entry(pos, struct packet, next); ++ c += 1; ++ ++ if (tpmif == NULL || pak->tpmif == tpmif) { ++ int can_send = 0; ++ ++ del_singleshot_timer_sync(&pak->processing_timer); ++ list_del(&pak->next); ++ ++ if (pak->tpmif && pak->tpmif->status == CONNECTED) { ++ can_send = 1; ++ } ++ ++ if (send_msgs && can_send) { ++ tpm_send_fail_message(pak, pak->req_tag); ++ } ++ packet_free(pak); ++ if (c == 1) ++ aborted = 1; ++ } ++ } ++ return aborted; ++} ++ ++int vtpm_release_packets(tpmif_t * tpmif, int send_msgs) ++{ ++ unsigned long flags; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ ++ dataex.aborted = _vtpm_release_packets(&dataex.pending_pak, ++ tpmif, ++ send_msgs); ++ _vtpm_release_packets(&dataex.current_pak, tpmif, send_msgs); ++ ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ return 0; ++} ++ ++static int vtpm_queue_packet(struct packet *pak) ++{ ++ int rc = 0; ++ ++ if (dataex.has_opener) { ++ unsigned long flags; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ list_add_tail(&pak->next, &dataex.pending_pak); ++ /* give the TPM some time to pick up the request */ ++ mod_timer(&pak->processing_timer, jiffies + (30 * HZ)); ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++ ++ wake_up_interruptible(&dataex.wait_queue); ++ } else { ++ rc = -EFAULT; ++ } ++ return rc; ++} ++ ++static int vtpm_receive(tpmif_t * tpmif, u32 size) ++{ ++ int rc = 0; ++ unsigned char buffer[10]; ++ __be32 *native_size; ++ struct packet *pak = packet_alloc(tpmif, size, 0, 0); ++ ++ if (!pak) ++ return -ENOMEM; ++ /* ++ * Read 10 bytes from the received buffer to test its ++ * content for validity. ++ */ ++ if (sizeof (buffer) != packet_read(pak, ++ sizeof (buffer), buffer, ++ sizeof (buffer), 0)) { ++ goto failexit; ++ } ++ /* ++ * Reset the packet read pointer so we can read all its ++ * contents again. ++ */ ++ packet_reset(pak); ++ ++ native_size = (__force __be32 *) (&buffer[4 + 2]); ++ /* ++ * Verify that the size of the packet is correct ++ * as indicated and that there's actually someone reading packets. ++ * The minimum size of the packet is '10' for tag, size indicator ++ * and ordinal. ++ */ ++ if (size < 10 || ++ be32_to_cpu(*native_size) != size || ++ 0 == dataex.has_opener || tpmif->status != CONNECTED) { ++ rc = -EINVAL; ++ goto failexit; ++ } else { ++ rc = vtpm_queue_packet(pak); ++ if (rc < 0) ++ goto failexit; ++ } ++ return 0; ++ ++ failexit: ++ if (pak) { ++ tpm_send_fail_message(pak, buffer[4 + 1]); ++ packet_free(pak); ++ } ++ return rc; ++} ++ ++/* ++ * Timeout function that gets invoked when a packet has not been processed ++ * during the timeout period. ++ * The packet must be on a list when this function is invoked. This ++ * also means that once its taken off a list, the timer must be ++ * destroyed as well. ++ */ ++static void processing_timeout(unsigned long ptr) ++{ ++ struct packet *pak = (struct packet *)ptr; ++ unsigned long flags; ++ ++ write_lock_irqsave(&dataex.pak_lock, flags); ++ /* ++ * The packet needs to be searched whether it ++ * is still on the list. ++ */ ++ if (pak == packet_find_packet(&dataex.pending_pak, pak) || ++ pak == packet_find_packet(&dataex.current_pak, pak)) { ++ if ((pak->flags & PACKET_FLAG_DISCARD_RESPONSE) == 0) { ++ tpm_send_fail_message(pak, pak->req_tag); ++ } ++ /* discard future responses */ ++ pak->flags |= PACKET_FLAG_DISCARD_RESPONSE; ++ } ++ ++ write_unlock_irqrestore(&dataex.pak_lock, flags); ++} ++ ++static void tpm_tx_action(unsigned long unused); ++static DECLARE_TASKLET(tpm_tx_tasklet, tpm_tx_action, 0); ++ ++static struct list_head tpm_schedule_list; ++static spinlock_t tpm_schedule_list_lock; ++ ++static inline void maybe_schedule_tx_action(void) ++{ ++ smp_mb(); ++ tasklet_schedule(&tpm_tx_tasklet); ++} ++ ++static inline int __on_tpm_schedule_list(tpmif_t * tpmif) ++{ ++ return tpmif->list.next != NULL; ++} ++ ++static void remove_from_tpm_schedule_list(tpmif_t * tpmif) ++{ ++ spin_lock_irq(&tpm_schedule_list_lock); ++ if (likely(__on_tpm_schedule_list(tpmif))) { ++ list_del(&tpmif->list); ++ tpmif->list.next = NULL; ++ tpmif_put(tpmif); ++ } ++ spin_unlock_irq(&tpm_schedule_list_lock); ++} ++ ++static void add_to_tpm_schedule_list_tail(tpmif_t * tpmif) ++{ ++ if (__on_tpm_schedule_list(tpmif)) ++ return; ++ ++ spin_lock_irq(&tpm_schedule_list_lock); ++ if (!__on_tpm_schedule_list(tpmif) && tpmif->active) { ++ list_add_tail(&tpmif->list, &tpm_schedule_list); ++ tpmif_get(tpmif); ++ } ++ spin_unlock_irq(&tpm_schedule_list_lock); ++} ++ ++void tpmif_schedule_work(tpmif_t * tpmif) ++{ ++ add_to_tpm_schedule_list_tail(tpmif); ++ maybe_schedule_tx_action(); ++} ++ ++void tpmif_deschedule_work(tpmif_t * tpmif) ++{ ++ remove_from_tpm_schedule_list(tpmif); ++} ++ ++static void tpm_tx_action(unsigned long unused) ++{ ++ struct list_head *ent; ++ tpmif_t *tpmif; ++ tpmif_tx_request_t *tx; ++ ++ DPRINTK("%s: Getting data from front-end(s)!\n", __FUNCTION__); ++ ++ while (!list_empty(&tpm_schedule_list)) { ++ /* Get a tpmif from the list with work to do. */ ++ ent = tpm_schedule_list.next; ++ tpmif = list_entry(ent, tpmif_t, list); ++ tpmif_get(tpmif); ++ remove_from_tpm_schedule_list(tpmif); ++ ++ tx = &tpmif->tx->ring[0].req; ++ ++ /* pass it up */ ++ vtpm_receive(tpmif, tx->size); ++ ++ tpmif_put(tpmif); ++ } ++} ++ ++irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ tpmif_t *tpmif = (tpmif_t *) dev_id; ++ ++ add_to_tpm_schedule_list_tail(tpmif); ++ maybe_schedule_tx_action(); ++ return IRQ_HANDLED; ++} ++ ++static int __init tpmback_init(void) ++{ ++ int rc; ++ ++ if ((rc = misc_register(&vtpms_miscdevice)) != 0) { ++ printk(KERN_ALERT ++ "Could not register misc device for TPM BE.\n"); ++ return rc; ++ } ++ ++ dataex_init(&dataex); ++ ++ spin_lock_init(&tpm_schedule_list_lock); ++ INIT_LIST_HEAD(&tpm_schedule_list); ++ ++ tpmif_interface_init(); ++ tpmif_xenbus_init(); ++ ++ printk(KERN_ALERT "Successfully initialized TPM backend driver.\n"); ++ ++ return 0; ++} ++ ++module_init(tpmback_init); ++ ++void __exit tpmback_exit(void) ++{ ++ vtpm_release_packets(NULL, 0); ++ tpmif_xenbus_exit(); ++ tpmif_interface_exit(); ++ misc_deregister(&vtpms_miscdevice); ++} ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/tpmback/xenbus.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/tpmback/xenbus.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,289 @@ ++/* Xenbus code for tpmif backend ++ Copyright (C) 2005 IBM Corporation ++ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++#include <stdarg.h> ++#include <linux/module.h> ++#include <xen/xenbus.h> ++#include "common.h" ++ ++struct backend_info ++{ ++ struct xenbus_device *dev; ++ ++ /* our communications channel */ ++ tpmif_t *tpmif; ++ ++ long int frontend_id; ++ long int instance; // instance of TPM ++ u8 is_instance_set;// whether instance number has been set ++ ++ /* watch front end for changes */ ++ struct xenbus_watch backend_watch; ++}; ++ ++static void maybe_connect(struct backend_info *be); ++static void connect(struct backend_info *be); ++static int connect_ring(struct backend_info *be); ++static void backend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len); ++static void frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state); ++ ++long int tpmback_get_instance(struct backend_info *bi) ++{ ++ long int res = -1; ++ if (bi && bi->is_instance_set) ++ res = bi->instance; ++ return res; ++} ++ ++static int tpmback_remove(struct xenbus_device *dev) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ ++ if (!be) return 0; ++ ++ if (be->backend_watch.node) { ++ unregister_xenbus_watch(&be->backend_watch); ++ kfree(be->backend_watch.node); ++ be->backend_watch.node = NULL; ++ } ++ if (be->tpmif) { ++ be->tpmif->bi = NULL; ++ vtpm_release_packets(be->tpmif, 0); ++ tpmif_put(be->tpmif); ++ be->tpmif = NULL; ++ } ++ kfree(be); ++ dev->dev.driver_data = NULL; ++ return 0; ++} ++ ++static int tpmback_probe(struct xenbus_device *dev, ++ const struct xenbus_device_id *id) ++{ ++ int err; ++ struct backend_info *be = kzalloc(sizeof(struct backend_info), ++ GFP_KERNEL); ++ ++ if (!be) { ++ xenbus_dev_fatal(dev, -ENOMEM, ++ "allocating backend structure"); ++ return -ENOMEM; ++ } ++ ++ be->is_instance_set = 0; ++ be->dev = dev; ++ dev->dev.driver_data = be; ++ ++ err = xenbus_watch_path2(dev, dev->nodename, ++ "instance", &be->backend_watch, ++ backend_changed); ++ if (err) { ++ goto fail; ++ } ++ ++ err = xenbus_switch_state(dev, XenbusStateInitWait); ++ if (err) { ++ goto fail; ++ } ++ return 0; ++fail: ++ tpmback_remove(dev); ++ return err; ++} ++ ++ ++static void backend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ int err; ++ long instance; ++ struct backend_info *be ++ = container_of(watch, struct backend_info, backend_watch); ++ struct xenbus_device *dev = be->dev; ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, ++ "instance","%li", &instance); ++ if (XENBUS_EXIST_ERR(err)) { ++ return; ++ } ++ ++ if (err != 1) { ++ xenbus_dev_fatal(dev, err, "reading instance"); ++ return; ++ } ++ ++ if (be->is_instance_set == 0) { ++ be->instance = instance; ++ be->is_instance_set = 1; ++ } ++} ++ ++ ++static void frontend_changed(struct xenbus_device *dev, ++ enum xenbus_state frontend_state) ++{ ++ struct backend_info *be = dev->dev.driver_data; ++ int err; ++ ++ switch (frontend_state) { ++ case XenbusStateInitialising: ++ case XenbusStateInitialised: ++ break; ++ ++ case XenbusStateConnected: ++ err = connect_ring(be); ++ if (err) { ++ return; ++ } ++ maybe_connect(be); ++ break; ++ ++ case XenbusStateClosing: ++ be->instance = -1; ++ xenbus_switch_state(dev, XenbusStateClosing); ++ break; ++ ++ case XenbusStateUnknown: /* keep it here */ ++ case XenbusStateClosed: ++ xenbus_switch_state(dev, XenbusStateClosed); ++ device_unregister(&be->dev->dev); ++ tpmback_remove(dev); ++ break; ++ ++ default: ++ xenbus_dev_fatal(dev, -EINVAL, ++ "saw state %d at frontend", ++ frontend_state); ++ break; ++ } ++} ++ ++ ++ ++static void maybe_connect(struct backend_info *be) ++{ ++ if (be->tpmif == NULL || be->tpmif->status == CONNECTED) ++ return; ++ ++ connect(be); ++} ++ ++ ++static void connect(struct backend_info *be) ++{ ++ struct xenbus_transaction xbt; ++ int err; ++ struct xenbus_device *dev = be->dev; ++ unsigned long ready = 1; ++ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(be->dev, err, "starting transaction"); ++ return; ++ } ++ ++ err = xenbus_printf(xbt, be->dev->nodename, ++ "ready", "%lu", ready); ++ if (err) { ++ xenbus_dev_fatal(be->dev, err, "writing 'ready'"); ++ goto abort; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ if (err) ++ xenbus_dev_fatal(be->dev, err, "end of transaction"); ++ ++ err = xenbus_switch_state(dev, XenbusStateConnected); ++ if (!err) ++ be->tpmif->status = CONNECTED; ++ return; ++abort: ++ xenbus_transaction_end(xbt, 1); ++} ++ ++ ++static int connect_ring(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ unsigned long ring_ref; ++ unsigned int evtchn; ++ int err; ++ ++ err = xenbus_gather(XBT_NIL, dev->otherend, ++ "ring-ref", "%lu", &ring_ref, ++ "event-channel", "%u", &evtchn, NULL); ++ if (err) { ++ xenbus_dev_error(dev, err, ++ "reading %s/ring-ref and event-channel", ++ dev->otherend); ++ return err; ++ } ++ ++ if (!be->tpmif) { ++ be->tpmif = tpmif_find(dev->otherend_id, be); ++ if (IS_ERR(be->tpmif)) { ++ err = PTR_ERR(be->tpmif); ++ be->tpmif = NULL; ++ xenbus_dev_fatal(dev,err,"creating vtpm interface"); ++ return err; ++ } ++ } ++ ++ if (be->tpmif != NULL) { ++ err = tpmif_map(be->tpmif, ring_ref, evtchn); ++ if (err) { ++ xenbus_dev_error(dev, err, ++ "mapping shared-frame %lu port %u", ++ ring_ref, evtchn); ++ return err; ++ } ++ } ++ return 0; ++} ++ ++ ++static struct xenbus_device_id tpmback_ids[] = { ++ { "vtpm" }, ++ { "" } ++}; ++ ++ ++static struct xenbus_driver tpmback = { ++ .name = "vtpm", ++ .owner = THIS_MODULE, ++ .ids = tpmback_ids, ++ .probe = tpmback_probe, ++ .remove = tpmback_remove, ++ .otherend_changed = frontend_changed, ++}; ++ ++ ++void tpmif_xenbus_init(void) ++{ ++ xenbus_register_backend(&tpmback); ++} ++ ++void tpmif_xenbus_exit(void) ++{ ++ xenbus_unregister_driver(&tpmback); ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/util.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/util.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,70 @@ ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <asm/uaccess.h> ++#include <xen/driver_util.h> ++ ++struct class *get_xen_class(void) ++{ ++ static struct class *xen_class; ++ ++ if (xen_class) ++ return xen_class; ++ ++ xen_class = class_create(THIS_MODULE, "xen"); ++ if (IS_ERR(xen_class)) { ++ printk("Failed to create xen sysfs class.\n"); ++ xen_class = NULL; ++ } ++ ++ return xen_class; ++} ++EXPORT_SYMBOL_GPL(get_xen_class); ++ ++/* Todo: merge ia64 ('auto-translate physmap') versions of these functions. */ ++#ifndef __ia64__ ++ ++static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) ++{ ++ /* apply_to_page_range() does all the hard work. */ ++ return 0; ++} ++ ++struct vm_struct *alloc_vm_area(unsigned long size) ++{ ++ struct vm_struct *area; ++ ++ area = get_vm_area(size, VM_IOREMAP); ++ if (area == NULL) ++ return NULL; ++ ++ /* ++ * This ensures that page tables are constructed for this region ++ * of kernel virtual address space and mapped into init_mm. ++ */ ++ if (apply_to_page_range(&init_mm, (unsigned long)area->addr, ++ area->size, f, NULL)) { ++ free_vm_area(area); ++ return NULL; ++ } ++ ++ /* Map page directories into every address space. */ ++#ifdef CONFIG_X86 ++ vmalloc_sync_all(); ++#endif ++ ++ return area; ++} ++EXPORT_SYMBOL_GPL(alloc_vm_area); ++ ++void free_vm_area(struct vm_struct *area) ++{ ++ struct vm_struct *ret; ++ ret = remove_vm_area(area->addr); ++ BUG_ON(ret != area); ++ kfree(area); ++} ++EXPORT_SYMBOL_GPL(free_vm_area); ++ ++#endif /* !__ia64__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,9 @@ ++obj-y += xenbus_client.o xenbus_comms.o xenbus_xs.o xenbus_probe.o ++obj-$(CONFIG_XEN_BACKEND) += xenbus_be.o ++ ++xenbus_be-objs = ++xenbus_be-objs += xenbus_backend_client.o ++ ++xenbus-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o ++obj-y += $(xenbus-y) $(xenbus-m) ++obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_backend_client.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_backend_client.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,147 @@ ++/****************************************************************************** ++ * Backend-client-facing interface for the Xenbus driver. In other words, the ++ * interface between the Xenbus and the device-specific code in the backend ++ * driver. ++ * ++ * Copyright (C) 2005-2006 XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/err.h> ++#include <xen/gnttab.h> ++#include <xen/xenbus.h> ++#include <xen/driver_util.h> ++ ++/* Based on Rusty Russell's skeleton driver's map_page */ ++struct vm_struct *xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref) ++{ ++ struct gnttab_map_grant_ref op; ++ struct vm_struct *area; ++ ++ area = alloc_vm_area(PAGE_SIZE); ++ if (!area) ++ return ERR_PTR(-ENOMEM); ++ ++ gnttab_set_map_op(&op, (unsigned long)area->addr, GNTMAP_host_map, ++ gnt_ref, dev->otherend_id); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) { ++ free_vm_area(area); ++ xenbus_dev_fatal(dev, op.status, ++ "mapping in shared page %d from domain %d", ++ gnt_ref, dev->otherend_id); ++ BUG_ON(!IS_ERR(ERR_PTR(op.status))); ++ return ERR_PTR(op.status); ++ } ++ ++ /* Stuff the handle in an unused field */ ++ area->phys_addr = (unsigned long)op.handle; ++ ++ return area; ++} ++EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); ++ ++ ++int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, ++ grant_handle_t *handle, void *vaddr) ++{ ++ struct gnttab_map_grant_ref op; ++ ++ gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, ++ gnt_ref, dev->otherend_id); ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) { ++ xenbus_dev_fatal(dev, op.status, ++ "mapping in shared page %d from domain %d", ++ gnt_ref, dev->otherend_id); ++ } else ++ *handle = op.handle; ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_map_ring); ++ ++ ++/* Based on Rusty Russell's skeleton driver's unmap_page */ ++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, struct vm_struct *area) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)area->addr, GNTMAP_host_map, ++ (grant_handle_t)area->phys_addr); ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status == GNTST_okay) ++ free_vm_area(area); ++ else ++ xenbus_dev_error(dev, op.status, ++ "unmapping page at handle %d error %d", ++ (int16_t)area->phys_addr, op.status); ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); ++ ++ ++int xenbus_unmap_ring(struct xenbus_device *dev, ++ grant_handle_t handle, void *vaddr) ++{ ++ struct gnttab_unmap_grant_ref op; ++ ++ gnttab_set_unmap_op(&op, (unsigned long)vaddr, GNTMAP_host_map, ++ handle); ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) ++ xenbus_dev_error(dev, op.status, ++ "unmapping page at handle %d error %d", ++ handle, op.status); ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_unmap_ring); ++ ++int xenbus_dev_is_online(struct xenbus_device *dev) ++{ ++ int rc, val; ++ ++ rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val); ++ if (rc != 1) ++ val = 0; /* no online node present */ ++ ++ return val; ++} ++EXPORT_SYMBOL_GPL(xenbus_dev_is_online); ++ ++MODULE_LICENSE("Dual BSD/GPL"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_client.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_client.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,283 @@ ++/****************************************************************************** ++ * Client-facing interface for the Xenbus driver. In other words, the ++ * interface between the Xenbus and the device-specific code, be it the ++ * frontend or the backend of that driver. ++ * ++ * Copyright (C) 2005 XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <xen/evtchn.h> ++#include <xen/gnttab.h> ++#include <xen/xenbus.h> ++#include <xen/driver_util.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) ++ ++const char *xenbus_strstate(enum xenbus_state state) ++{ ++ static const char *const name[] = { ++ [ XenbusStateUnknown ] = "Unknown", ++ [ XenbusStateInitialising ] = "Initialising", ++ [ XenbusStateInitWait ] = "InitWait", ++ [ XenbusStateInitialised ] = "Initialised", ++ [ XenbusStateConnected ] = "Connected", ++ [ XenbusStateClosing ] = "Closing", ++ [ XenbusStateClosed ] = "Closed", ++ }; ++ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; ++} ++EXPORT_SYMBOL_GPL(xenbus_strstate); ++ ++int xenbus_watch_path(struct xenbus_device *dev, const char *path, ++ struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)) ++{ ++ int err; ++ ++ watch->node = path; ++ watch->callback = callback; ++ ++ err = register_xenbus_watch(watch); ++ ++ if (err) { ++ watch->node = NULL; ++ watch->callback = NULL; ++ xenbus_dev_fatal(dev, err, "adding watch on %s", path); ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_watch_path); ++ ++ ++int xenbus_watch_path2(struct xenbus_device *dev, const char *path, ++ const char *path2, struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)) ++{ ++ int err; ++ char *state = kasprintf(GFP_KERNEL, "%s/%s", path, path2); ++ if (!state) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); ++ return -ENOMEM; ++ } ++ err = xenbus_watch_path(dev, state, watch, callback); ++ ++ if (err) ++ kfree(state); ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_watch_path2); ++ ++ ++int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) ++{ ++ /* We check whether the state is currently set to the given value, and ++ if not, then the state is set. We don't want to unconditionally ++ write the given state, because we don't want to fire watches ++ unnecessarily. Furthermore, if the node has gone, we don't write ++ to it, as the device will be tearing down, and we don't want to ++ resurrect that directory. ++ ++ Note that, because of this cached value of our state, this function ++ will not work inside a Xenstore transaction (something it was ++ trying to in the past) because dev->state would not get reset if ++ the transaction was aborted. ++ ++ */ ++ ++ int current_state; ++ int err; ++ ++ if (state == dev->state) ++ return 0; ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d", ++ ¤t_state); ++ if (err != 1) ++ return 0; ++ ++ err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state); ++ if (err) { ++ if (state != XenbusStateClosing) /* Avoid looping */ ++ xenbus_dev_fatal(dev, err, "writing new state"); ++ return err; ++ } ++ ++ dev->state = state; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xenbus_switch_state); ++ ++int xenbus_frontend_closed(struct xenbus_device *dev) ++{ ++ xenbus_switch_state(dev, XenbusStateClosed); ++ complete(&dev->down); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xenbus_frontend_closed); ++ ++/** ++ * Return the path to the error node for the given device, or NULL on failure. ++ * If the value returned is non-NULL, then it is the caller's to kfree. ++ */ ++static char *error_path(struct xenbus_device *dev) ++{ ++ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename); ++} ++ ++ ++void _dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ va_list ap) ++{ ++ int ret; ++ unsigned int len; ++ char *printf_buffer = NULL, *path_buffer = NULL; ++ ++#define PRINTF_BUFFER_SIZE 4096 ++ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); ++ if (printf_buffer == NULL) ++ goto fail; ++ ++ len = sprintf(printf_buffer, "%i ", -err); ++ ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); ++ ++ BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); ++ ++ dev_err(&dev->dev, "%s\n", printf_buffer); ++ ++ path_buffer = error_path(dev); ++ ++ if (path_buffer == NULL) { ++ printk("xenbus: failed to write error node for %s (%s)\n", ++ dev->nodename, printf_buffer); ++ goto fail; ++ } ++ ++ if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { ++ printk("xenbus: failed to write error node for %s (%s)\n", ++ dev->nodename, printf_buffer); ++ goto fail; ++ } ++ ++fail: ++ if (printf_buffer) ++ kfree(printf_buffer); ++ if (path_buffer) ++ kfree(path_buffer); ++} ++ ++ ++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ _dev_error(dev, err, fmt, ap); ++ va_end(ap); ++} ++EXPORT_SYMBOL_GPL(xenbus_dev_error); ++ ++ ++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ++ ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ _dev_error(dev, err, fmt, ap); ++ va_end(ap); ++ ++ xenbus_switch_state(dev, XenbusStateClosing); ++} ++EXPORT_SYMBOL_GPL(xenbus_dev_fatal); ++ ++ ++int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) ++{ ++ int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); ++ if (err < 0) ++ xenbus_dev_fatal(dev, err, "granting access to ring page"); ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_grant_ring); ++ ++ ++int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) ++{ ++ struct evtchn_alloc_unbound alloc_unbound; ++ int err; ++ ++ alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.remote_dom = dev->otherend_id; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, ++ &alloc_unbound); ++ if (err) ++ xenbus_dev_fatal(dev, err, "allocating event channel"); ++ else ++ *port = alloc_unbound.port; ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); ++ ++ ++int xenbus_free_evtchn(struct xenbus_device *dev, int port) ++{ ++ struct evtchn_close close; ++ int err; ++ ++ close.port = port; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); ++ if (err) ++ xenbus_dev_error(dev, err, "freeing event channel %d", port); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_free_evtchn); ++ ++ ++enum xenbus_state xenbus_read_driver_state(const char *path) ++{ ++ enum xenbus_state result; ++ int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); ++ if (err) ++ result = XenbusStateUnknown; ++ ++ return result; ++} ++EXPORT_SYMBOL_GPL(xenbus_read_driver_state); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_comms.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_comms.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,232 @@ ++/****************************************************************************** ++ * xenbus_comms.c ++ * ++ * Low level code to talks to Xen Store: ringbuffer and event channel. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/wait.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/err.h> ++#include <linux/ptrace.h> ++#include <xen/evtchn.h> ++#include <xen/xenbus.h> ++ ++#include <asm/hypervisor.h> ++ ++#include "xenbus_comms.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++static int xenbus_irq; ++ ++extern void xenbus_probe(struct work_struct *); ++extern int xenstored_ready; ++static DECLARE_WORK(probe_work, xenbus_probe); ++ ++static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); ++ ++static irqreturn_t wake_waiting(int irq, void *unused) ++{ ++ if (unlikely(xenstored_ready == 0)) { ++ xenstored_ready = 1; ++ schedule_work(&probe_work); ++ } ++ ++ wake_up(&xb_waitq); ++ return IRQ_HANDLED; ++} ++ ++static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) ++{ ++ return ((prod - cons) <= XENSTORE_RING_SIZE); ++} ++ ++static void *get_output_chunk(XENSTORE_RING_IDX cons, ++ XENSTORE_RING_IDX prod, ++ char *buf, uint32_t *len) ++{ ++ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); ++ if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) ++ *len = XENSTORE_RING_SIZE - (prod - cons); ++ return buf + MASK_XENSTORE_IDX(prod); ++} ++ ++static const void *get_input_chunk(XENSTORE_RING_IDX cons, ++ XENSTORE_RING_IDX prod, ++ const char *buf, uint32_t *len) ++{ ++ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); ++ if ((prod - cons) < *len) ++ *len = prod - cons; ++ return buf + MASK_XENSTORE_IDX(cons); ++} ++ ++int xb_write(const void *data, unsigned len) ++{ ++ struct xenstore_domain_interface *intf = xen_store_interface; ++ XENSTORE_RING_IDX cons, prod; ++ int rc; ++ ++ while (len != 0) { ++ void *dst; ++ unsigned int avail; ++ ++ rc = wait_event_interruptible( ++ xb_waitq, ++ (intf->req_prod - intf->req_cons) != ++ XENSTORE_RING_SIZE); ++ if (rc < 0) ++ return rc; ++ ++ /* Read indexes, then verify. */ ++ cons = intf->req_cons; ++ prod = intf->req_prod; ++ if (!check_indexes(cons, prod)) { ++ intf->req_cons = intf->req_prod = 0; ++ return -EIO; ++ } ++ ++ dst = get_output_chunk(cons, prod, intf->req, &avail); ++ if (avail == 0) ++ continue; ++ if (avail > len) ++ avail = len; ++ ++ /* Must write data /after/ reading the consumer index. */ ++ mb(); ++ ++ memcpy(dst, data, avail); ++ data += avail; ++ len -= avail; ++ ++ /* Other side must not see new producer until data is there. */ ++ wmb(); ++ intf->req_prod += avail; ++ ++ /* Implies mb(): other side will see the updated producer. */ ++ notify_remote_via_evtchn(xen_store_evtchn); ++ } ++ ++ return 0; ++} ++ ++int xb_data_to_read(void) ++{ ++ struct xenstore_domain_interface *intf = xen_store_interface; ++ return (intf->rsp_cons != intf->rsp_prod); ++} ++ ++int xb_wait_for_data_to_read(void) ++{ ++ return wait_event_interruptible(xb_waitq, xb_data_to_read()); ++} ++ ++int xb_read(void *data, unsigned len) ++{ ++ struct xenstore_domain_interface *intf = xen_store_interface; ++ XENSTORE_RING_IDX cons, prod; ++ int rc; ++ ++ while (len != 0) { ++ unsigned int avail; ++ const char *src; ++ ++ rc = xb_wait_for_data_to_read(); ++ if (rc < 0) ++ return rc; ++ ++ /* Read indexes, then verify. */ ++ cons = intf->rsp_cons; ++ prod = intf->rsp_prod; ++ if (!check_indexes(cons, prod)) { ++ intf->rsp_cons = intf->rsp_prod = 0; ++ return -EIO; ++ } ++ ++ src = get_input_chunk(cons, prod, intf->rsp, &avail); ++ if (avail == 0) ++ continue; ++ if (avail > len) ++ avail = len; ++ ++ /* Must read data /after/ reading the producer index. */ ++ rmb(); ++ ++ memcpy(data, src, avail); ++ data += avail; ++ len -= avail; ++ ++ /* Other side must not see free space until we've copied out */ ++ mb(); ++ intf->rsp_cons += avail; ++ ++ pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); ++ ++ /* Implies mb(): other side will see the updated consumer. */ ++ notify_remote_via_evtchn(xen_store_evtchn); ++ } ++ ++ return 0; ++} ++ ++/* Set up interrupt handler off store event channel. */ ++int xb_init_comms(void) ++{ ++ struct xenstore_domain_interface *intf = xen_store_interface; ++ int err; ++ ++ if (intf->req_prod != intf->req_cons) ++ printk(KERN_ERR "XENBUS request ring is not quiescent " ++ "(%08x:%08x)!\n", intf->req_cons, intf->req_prod); ++ ++ if (intf->rsp_prod != intf->rsp_cons) { ++ printk(KERN_WARNING "XENBUS response ring is not quiescent " ++ "(%08x:%08x): fixing up\n", ++ intf->rsp_cons, intf->rsp_prod); ++ intf->rsp_cons = intf->rsp_prod; ++ } ++ ++ if (xenbus_irq) ++ unbind_from_irqhandler(xenbus_irq, &xb_waitq); ++ ++ err = bind_caller_port_to_irqhandler( ++ xen_store_evtchn, wake_waiting, ++ 0, "xenbus", &xb_waitq); ++ if (err <= 0) { ++ printk(KERN_ERR "XENBUS request irq failed %i\n", err); ++ return err; ++ } ++ ++ xenbus_irq = err; ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_comms.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_comms.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,46 @@ ++/* ++ * Private include for xenbus communications. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef _XENBUS_COMMS_H ++#define _XENBUS_COMMS_H ++ ++int xs_init(void); ++int xb_init_comms(void); ++ ++/* Low level routines. */ ++int xb_write(const void *data, unsigned len); ++int xb_read(void *data, unsigned len); ++int xb_data_to_read(void); ++int xb_wait_for_data_to_read(void); ++int xs_input_avail(void); ++extern struct xenstore_domain_interface *xen_store_interface; ++extern int xen_store_evtchn; ++ ++#endif /* _XENBUS_COMMS_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_dev.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_dev.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,404 @@ ++/* ++ * xenbus_dev.c ++ * ++ * Driver giving user-space access to the kernel's xenbus connection ++ * to xenstore. ++ * ++ * Copyright (c) 2005, Christian Limpach ++ * Copyright (c) 2005, Rusty Russell, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/uio.h> ++#include <linux/notifier.h> ++#include <linux/wait.h> ++#include <linux/fs.h> ++#include <linux/poll.h> ++#include <linux/mutex.h> ++ ++#include "xenbus_comms.h" ++ ++#include <asm/uaccess.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <xen/xen_proc.h> ++#include <asm/hypervisor.h> ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++struct xenbus_dev_transaction { ++ struct list_head list; ++ struct xenbus_transaction handle; ++}; ++ ++struct read_buffer { ++ struct list_head list; ++ unsigned int cons; ++ unsigned int len; ++ char msg[]; ++}; ++ ++struct xenbus_dev_data { ++ /* In-progress transaction. */ ++ struct list_head transactions; ++ ++ /* Active watches. */ ++ struct list_head watches; ++ ++ /* Partial request. */ ++ unsigned int len; ++ union { ++ struct xsd_sockmsg msg; ++ char buffer[PAGE_SIZE]; ++ } u; ++ ++ /* Response queue. */ ++ struct list_head read_buffers; ++ wait_queue_head_t read_waitq; ++ ++ struct mutex reply_mutex; ++}; ++ ++static struct proc_dir_entry *xenbus_dev_intf; ++ ++static ssize_t xenbus_dev_read(struct file *filp, ++ char __user *ubuf, ++ size_t len, loff_t *ppos) ++{ ++ struct xenbus_dev_data *u = filp->private_data; ++ struct read_buffer *rb; ++ int i, ret; ++ ++ mutex_lock(&u->reply_mutex); ++ while (list_empty(&u->read_buffers)) { ++ mutex_unlock(&u->reply_mutex); ++ ret = wait_event_interruptible(u->read_waitq, ++ !list_empty(&u->read_buffers)); ++ if (ret) ++ return ret; ++ mutex_lock(&u->reply_mutex); ++ } ++ ++ rb = list_entry(u->read_buffers.next, struct read_buffer, list); ++ for (i = 0; i < len;) { ++ put_user(rb->msg[rb->cons], ubuf + i); ++ i++; ++ rb->cons++; ++ if (rb->cons == rb->len) { ++ list_del(&rb->list); ++ kfree(rb); ++ if (list_empty(&u->read_buffers)) ++ break; ++ rb = list_entry(u->read_buffers.next, ++ struct read_buffer, list); ++ } ++ } ++ mutex_unlock(&u->reply_mutex); ++ ++ return i; ++} ++ ++static void queue_reply(struct xenbus_dev_data *u, ++ char *data, unsigned int len) ++{ ++ struct read_buffer *rb; ++ ++ if (len == 0) ++ return; ++ ++ rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL); ++ BUG_ON(rb == NULL); ++ ++ rb->cons = 0; ++ rb->len = len; ++ ++ memcpy(rb->msg, data, len); ++ ++ list_add_tail(&rb->list, &u->read_buffers); ++ ++ wake_up(&u->read_waitq); ++} ++ ++struct watch_adapter ++{ ++ struct list_head list; ++ struct xenbus_watch watch; ++ struct xenbus_dev_data *dev_data; ++ char *token; ++}; ++ ++static void free_watch_adapter (struct watch_adapter *watch) ++{ ++ kfree(watch->watch.node); ++ kfree(watch->token); ++ kfree(watch); ++} ++ ++static void watch_fired(struct xenbus_watch *watch, ++ const char **vec, ++ unsigned int len) ++{ ++ struct watch_adapter *adap = ++ container_of(watch, struct watch_adapter, watch); ++ struct xsd_sockmsg hdr; ++ const char *path, *token; ++ int path_len, tok_len, body_len; ++ ++ path = vec[XS_WATCH_PATH]; ++ token = adap->token; ++ ++ path_len = strlen(path) + 1; ++ tok_len = strlen(token) + 1; ++ body_len = path_len + tok_len; ++ ++ hdr.type = XS_WATCH_EVENT; ++ hdr.len = body_len; ++ ++ mutex_lock(&adap->dev_data->reply_mutex); ++ queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr)); ++ queue_reply(adap->dev_data, (char *)path, path_len); ++ queue_reply(adap->dev_data, (char *)token, tok_len); ++ mutex_unlock(&adap->dev_data->reply_mutex); ++} ++ ++static LIST_HEAD(watch_list); ++ ++static ssize_t xenbus_dev_write(struct file *filp, ++ const char __user *ubuf, ++ size_t len, loff_t *ppos) ++{ ++ struct xenbus_dev_data *u = filp->private_data; ++ struct xenbus_dev_transaction *trans = NULL; ++ uint32_t msg_type; ++ void *reply; ++ char *path, *token; ++ struct watch_adapter *watch, *tmp_watch; ++ int err, rc = len; ++ ++ if ((len + u->len) > sizeof(u->u.buffer)) { ++ rc = -EINVAL; ++ goto out; ++ } ++ ++ if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0) { ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ u->len += len; ++ if ((u->len < sizeof(u->u.msg)) || ++ (u->len < (sizeof(u->u.msg) + u->u.msg.len))) ++ return rc; ++ ++ msg_type = u->u.msg.type; ++ ++ switch (msg_type) { ++ case XS_TRANSACTION_START: ++ case XS_TRANSACTION_END: ++ case XS_DIRECTORY: ++ case XS_READ: ++ case XS_GET_PERMS: ++ case XS_RELEASE: ++ case XS_GET_DOMAIN_PATH: ++ case XS_WRITE: ++ case XS_MKDIR: ++ case XS_RM: ++ case XS_SET_PERMS: ++ if (msg_type == XS_TRANSACTION_START) { ++ trans = kmalloc(sizeof(*trans), GFP_KERNEL); ++ if (!trans) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ reply = xenbus_dev_request_and_reply(&u->u.msg); ++ if (IS_ERR(reply)) { ++ kfree(trans); ++ rc = PTR_ERR(reply); ++ goto out; ++ } ++ ++ if (msg_type == XS_TRANSACTION_START) { ++ trans->handle.id = simple_strtoul(reply, NULL, 0); ++ list_add(&trans->list, &u->transactions); ++ } else if (msg_type == XS_TRANSACTION_END) { ++ list_for_each_entry(trans, &u->transactions, list) ++ if (trans->handle.id == u->u.msg.tx_id) ++ break; ++ BUG_ON(&trans->list == &u->transactions); ++ list_del(&trans->list); ++ kfree(trans); ++ } ++ mutex_lock(&u->reply_mutex); ++ queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); ++ queue_reply(u, (char *)reply, u->u.msg.len); ++ mutex_unlock(&u->reply_mutex); ++ kfree(reply); ++ break; ++ ++ case XS_WATCH: ++ case XS_UNWATCH: { ++ static const char *XS_RESP = "OK"; ++ struct xsd_sockmsg hdr; ++ ++ path = u->u.buffer + sizeof(u->u.msg); ++ token = memchr(path, 0, u->u.msg.len); ++ if (token == NULL) { ++ rc = -EILSEQ; ++ goto out; ++ } ++ token++; ++ ++ if (msg_type == XS_WATCH) { ++ watch = kmalloc(sizeof(*watch), GFP_KERNEL); ++ watch->watch.node = kmalloc(strlen(path)+1, ++ GFP_KERNEL); ++ strcpy((char *)watch->watch.node, path); ++ watch->watch.callback = watch_fired; ++ watch->token = kmalloc(strlen(token)+1, GFP_KERNEL); ++ strcpy(watch->token, token); ++ watch->dev_data = u; ++ ++ err = register_xenbus_watch(&watch->watch); ++ if (err) { ++ free_watch_adapter(watch); ++ rc = err; ++ goto out; ++ } ++ ++ list_add(&watch->list, &u->watches); ++ } else { ++ list_for_each_entry_safe(watch, tmp_watch, ++ &u->watches, list) { ++ if (!strcmp(watch->token, token) && ++ !strcmp(watch->watch.node, path)) ++ { ++ unregister_xenbus_watch(&watch->watch); ++ list_del(&watch->list); ++ free_watch_adapter(watch); ++ break; ++ } ++ } ++ } ++ ++ hdr.type = msg_type; ++ hdr.len = strlen(XS_RESP) + 1; ++ mutex_lock(&u->reply_mutex); ++ queue_reply(u, (char *)&hdr, sizeof(hdr)); ++ queue_reply(u, (char *)XS_RESP, hdr.len); ++ mutex_unlock(&u->reply_mutex); ++ break; ++ } ++ ++ default: ++ rc = -EINVAL; ++ break; ++ } ++ ++ out: ++ u->len = 0; ++ return rc; ++} ++ ++static int xenbus_dev_open(struct inode *inode, struct file *filp) ++{ ++ struct xenbus_dev_data *u; ++ ++ if (xen_store_evtchn == 0) ++ return -ENOENT; ++ ++ nonseekable_open(inode, filp); ++ ++ u = kzalloc(sizeof(*u), GFP_KERNEL); ++ if (u == NULL) ++ return -ENOMEM; ++ ++ INIT_LIST_HEAD(&u->transactions); ++ INIT_LIST_HEAD(&u->watches); ++ INIT_LIST_HEAD(&u->read_buffers); ++ init_waitqueue_head(&u->read_waitq); ++ ++ mutex_init(&u->reply_mutex); ++ ++ filp->private_data = u; ++ ++ return 0; ++} ++ ++static int xenbus_dev_release(struct inode *inode, struct file *filp) ++{ ++ struct xenbus_dev_data *u = filp->private_data; ++ struct xenbus_dev_transaction *trans, *tmp; ++ struct watch_adapter *watch, *tmp_watch; ++ ++ list_for_each_entry_safe(trans, tmp, &u->transactions, list) { ++ xenbus_transaction_end(trans->handle, 1); ++ list_del(&trans->list); ++ kfree(trans); ++ } ++ ++ list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { ++ unregister_xenbus_watch(&watch->watch); ++ list_del(&watch->list); ++ free_watch_adapter(watch); ++ } ++ ++ kfree(u); ++ ++ return 0; ++} ++ ++static unsigned int xenbus_dev_poll(struct file *file, poll_table *wait) ++{ ++ struct xenbus_dev_data *u = file->private_data; ++ ++ poll_wait(file, &u->read_waitq, wait); ++ if (!list_empty(&u->read_buffers)) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++static const struct file_operations xenbus_dev_file_ops = { ++ .read = xenbus_dev_read, ++ .write = xenbus_dev_write, ++ .open = xenbus_dev_open, ++ .release = xenbus_dev_release, ++ .poll = xenbus_dev_poll, ++}; ++ ++int xenbus_dev_init(void) ++{ ++ xenbus_dev_intf = create_xen_proc_entry("xenbus", 0400); ++ if (xenbus_dev_intf) ++ xenbus_dev_intf->proc_fops = &xenbus_dev_file_ops; ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_probe.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_probe.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1089 @@ ++/****************************************************************************** ++ * Talks to Xen Store to figure out what devices we have. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * Copyright (C) 2005 Mike Wray, Hewlett-Packard ++ * Copyright (C) 2005, 2006 XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ ++ __FUNCTION__, __LINE__, ##args) ++ ++#include <linux/kernel.h> ++#include <linux/err.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/fcntl.h> ++#include <linux/mm.h> ++#include <linux/notifier.h> ++#include <linux/kthread.h> ++#include <linux/mutex.h> ++ ++#include <asm/io.h> ++#include <asm/page.h> ++#include <asm/maddr.h> ++#include <asm/pgtable.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <xen/xen_proc.h> ++#include <xen/evtchn.h> ++#include <xen/features.h> ++#include <xen/hvm.h> ++ ++#include "xenbus_comms.h" ++#include "xenbus_probe.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++int xen_store_evtchn; ++struct xenstore_domain_interface *xen_store_interface; ++static unsigned long xen_store_mfn; ++ ++extern struct mutex xenwatch_mutex; ++ ++static ATOMIC_NOTIFIER_HEAD(xenstore_chain); ++ ++static void wait_for_devices(struct xenbus_driver *xendrv); ++ ++static int xenbus_probe_frontend(const char *type, const char *name); ++ ++static void xenbus_dev_shutdown(struct device *_dev); ++ ++/* If something in array of ids matches this device, return it. */ ++static const struct xenbus_device_id * ++match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) ++{ ++ for (; *arr->devicetype != '\0'; arr++) { ++ if (!strcmp(arr->devicetype, dev->devicetype)) ++ return arr; ++ } ++ return NULL; ++} ++ ++int xenbus_match(struct device *_dev, struct device_driver *_drv) ++{ ++ struct xenbus_driver *drv = to_xenbus_driver(_drv); ++ ++ if (!drv->ids) ++ return 0; ++ ++ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; ++} ++ ++/* device/<type>/<id> => <type>-<id> */ ++static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) ++{ ++ nodename = strchr(nodename, '/'); ++ if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { ++ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); ++ return -EINVAL; ++ } ++ ++ strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); ++ if (!strchr(bus_id, '/')) { ++ printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); ++ return -EINVAL; ++ } ++ *strchr(bus_id, '/') = '-'; ++ return 0; ++} ++ ++ ++static void free_otherend_details(struct xenbus_device *dev) ++{ ++ kfree(dev->otherend); ++ dev->otherend = NULL; ++} ++ ++ ++static void free_otherend_watch(struct xenbus_device *dev) ++{ ++ if (dev->otherend_watch.node) { ++ unregister_xenbus_watch(&dev->otherend_watch); ++ kfree(dev->otherend_watch.node); ++ dev->otherend_watch.node = NULL; ++ } ++} ++ ++ ++int read_otherend_details(struct xenbus_device *xendev, ++ char *id_node, char *path_node) ++{ ++ int err = xenbus_gather(XBT_NIL, xendev->nodename, ++ id_node, "%i", &xendev->otherend_id, ++ path_node, NULL, &xendev->otherend, ++ NULL); ++ if (err) { ++ xenbus_dev_fatal(xendev, err, ++ "reading other end details from %s", ++ xendev->nodename); ++ return err; ++ } ++ if (strlen(xendev->otherend) == 0 || ++ !xenbus_exists(XBT_NIL, xendev->otherend, "")) { ++ xenbus_dev_fatal(xendev, -ENOENT, ++ "unable to read other end from %s. " ++ "missing or inaccessible.", ++ xendev->nodename); ++ free_otherend_details(xendev); ++ return -ENOENT; ++ } ++ ++ return 0; ++} ++ ++ ++static int read_backend_details(struct xenbus_device *xendev) ++{ ++ return read_otherend_details(xendev, "backend-id", "backend"); ++} ++ ++ ++/* Bus type for frontend drivers. */ ++static struct xen_bus_type xenbus_frontend = { ++ .root = "device", ++ .levels = 2, /* device/type/<id> */ ++ .get_bus_id = frontend_bus_id, ++ .probe = xenbus_probe_frontend, ++ .bus = { ++ .name = "xen", ++ .match = xenbus_match, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++ .probe = xenbus_dev_probe, ++ .remove = xenbus_dev_remove, ++ .shutdown = xenbus_dev_shutdown, ++#endif ++ }, ++ .dev = { ++ .bus_id = "xen", ++ }, ++}; ++ ++static void otherend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ struct xenbus_device *dev = ++ container_of(watch, struct xenbus_device, otherend_watch); ++ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); ++ enum xenbus_state state; ++ ++ /* Protect us against watches firing on old details when the otherend ++ details change, say immediately after a resume. */ ++ if (!dev->otherend || ++ strncmp(dev->otherend, vec[XS_WATCH_PATH], ++ strlen(dev->otherend))) { ++ DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); ++ return; ++ } ++ ++ state = xenbus_read_driver_state(dev->otherend); ++ ++ DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state), ++ dev->otherend_watch.node, vec[XS_WATCH_PATH]); ++ ++ /* ++ * Ignore xenbus transitions during shutdown. This prevents us doing ++ * work that can fail e.g., when the rootfs is gone. ++ */ ++ if (system_state > SYSTEM_RUNNING) { ++ struct xen_bus_type *bus = bus; ++ bus = container_of(dev->dev.bus, struct xen_bus_type, bus); ++ /* If we're frontend, drive the state machine to Closed. */ ++ /* This should cause the backend to release our resources. */ ++ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) ++ xenbus_frontend_closed(dev); ++ return; ++ } ++ ++ if (drv->otherend_changed) ++ drv->otherend_changed(dev, state); ++} ++ ++ ++static int talk_to_otherend(struct xenbus_device *dev) ++{ ++ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); ++ ++ free_otherend_watch(dev); ++ free_otherend_details(dev); ++ ++ return drv->read_otherend_details(dev); ++} ++ ++ ++static int watch_otherend(struct xenbus_device *dev) ++{ ++ return xenbus_watch_path2(dev, dev->otherend, "state", ++ &dev->otherend_watch, otherend_changed); ++} ++ ++ ++int xenbus_dev_probe(struct device *_dev) ++{ ++ struct xenbus_device *dev = to_xenbus_device(_dev); ++ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); ++ const struct xenbus_device_id *id; ++ int err; ++ ++ DPRINTK("%s", dev->nodename); ++ ++ if (!drv->probe) { ++ err = -ENODEV; ++ goto fail; ++ } ++ ++ id = match_device(drv->ids, dev); ++ if (!id) { ++ err = -ENODEV; ++ goto fail; ++ } ++ ++ err = talk_to_otherend(dev); ++ if (err) { ++ printk(KERN_WARNING ++ "xenbus_probe: talk_to_otherend on %s failed.\n", ++ dev->nodename); ++ return err; ++ } ++ ++ err = drv->probe(dev, id); ++ if (err) ++ goto fail; ++ ++ err = watch_otherend(dev); ++ if (err) { ++ printk(KERN_WARNING ++ "xenbus_probe: watch_otherend on %s failed.\n", ++ dev->nodename); ++ return err; ++ } ++ ++ return 0; ++fail: ++ xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename); ++ xenbus_switch_state(dev, XenbusStateClosed); ++ return -ENODEV; ++} ++ ++int xenbus_dev_remove(struct device *_dev) ++{ ++ struct xenbus_device *dev = to_xenbus_device(_dev); ++ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); ++ ++ DPRINTK("%s", dev->nodename); ++ ++ free_otherend_watch(dev); ++ free_otherend_details(dev); ++ ++ if (drv->remove) ++ drv->remove(dev); ++ ++ xenbus_switch_state(dev, XenbusStateClosed); ++ return 0; ++} ++ ++static void xenbus_dev_shutdown(struct device *_dev) ++{ ++ struct xenbus_device *dev = to_xenbus_device(_dev); ++ unsigned long timeout = 5*HZ; ++ ++ DPRINTK("%s", dev->nodename); ++ ++ get_device(&dev->dev); ++ if (dev->state != XenbusStateConnected) { ++ printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__, ++ dev->nodename, xenbus_strstate(dev->state)); ++ goto out; ++ } ++ xenbus_switch_state(dev, XenbusStateClosing); ++ timeout = wait_for_completion_timeout(&dev->down, timeout); ++ if (!timeout) ++ printk("%s: %s timeout closing device\n", __FUNCTION__, dev->nodename); ++ out: ++ put_device(&dev->dev); ++} ++ ++int xenbus_register_driver_common(struct xenbus_driver *drv, ++ struct xen_bus_type *bus) ++{ ++ int ret; ++ ++ if (bus->error) ++ return bus->error; ++ ++ drv->driver.name = drv->name; ++ drv->driver.bus = &bus->bus; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) ++ drv->driver.owner = drv->owner; ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++ drv->driver.probe = xenbus_dev_probe; ++ drv->driver.remove = xenbus_dev_remove; ++ drv->driver.shutdown = xenbus_dev_shutdown; ++#endif ++ ++ mutex_lock(&xenwatch_mutex); ++ ret = driver_register(&drv->driver); ++ mutex_unlock(&xenwatch_mutex); ++ return ret; ++} ++ ++int xenbus_register_frontend(struct xenbus_driver *drv) ++{ ++ int ret; ++ ++ drv->read_otherend_details = read_backend_details; ++ ++ ret = xenbus_register_driver_common(drv, &xenbus_frontend); ++ if (ret) ++ return ret; ++ ++ /* If this driver is loaded as a module wait for devices to attach. */ ++ wait_for_devices(drv); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xenbus_register_frontend); ++ ++void xenbus_unregister_driver(struct xenbus_driver *drv) ++{ ++ driver_unregister(&drv->driver); ++} ++EXPORT_SYMBOL_GPL(xenbus_unregister_driver); ++ ++struct xb_find_info ++{ ++ struct xenbus_device *dev; ++ const char *nodename; ++}; ++ ++static int cmp_dev(struct device *dev, void *data) ++{ ++ struct xenbus_device *xendev = to_xenbus_device(dev); ++ struct xb_find_info *info = data; ++ ++ if (!strcmp(xendev->nodename, info->nodename)) { ++ info->dev = xendev; ++ get_device(dev); ++ return 1; ++ } ++ return 0; ++} ++ ++struct xenbus_device *xenbus_device_find(const char *nodename, ++ struct bus_type *bus) ++{ ++ struct xb_find_info info = { .dev = NULL, .nodename = nodename }; ++ ++ bus_for_each_dev(bus, NULL, &info, cmp_dev); ++ return info.dev; ++} ++ ++static int cleanup_dev(struct device *dev, void *data) ++{ ++ struct xenbus_device *xendev = to_xenbus_device(dev); ++ struct xb_find_info *info = data; ++ int len = strlen(info->nodename); ++ ++ DPRINTK("%s", info->nodename); ++ ++ /* Match the info->nodename path, or any subdirectory of that path. */ ++ if (strncmp(xendev->nodename, info->nodename, len)) ++ return 0; ++ ++ /* If the node name is longer, ensure it really is a subdirectory. */ ++ if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/')) ++ return 0; ++ ++ info->dev = xendev; ++ get_device(dev); ++ return 1; ++} ++ ++static void xenbus_cleanup_devices(const char *path, struct bus_type *bus) ++{ ++ struct xb_find_info info = { .nodename = path }; ++ ++ do { ++ info.dev = NULL; ++ bus_for_each_dev(bus, NULL, &info, cleanup_dev); ++ if (info.dev) { ++ device_unregister(&info.dev->dev); ++ put_device(&info.dev->dev); ++ } ++ } while (info.dev); ++} ++ ++static void xenbus_dev_release(struct device *dev) ++{ ++ if (dev) ++ kfree(to_xenbus_device(dev)); ++} ++ ++static ssize_t xendev_show_nodename(struct device *dev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) ++ struct device_attribute *attr, ++#endif ++ char *buf) ++{ ++ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); ++} ++DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); ++ ++static ssize_t xendev_show_devtype(struct device *dev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) ++ struct device_attribute *attr, ++#endif ++ char *buf) ++{ ++ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); ++} ++DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); ++ ++ ++int xenbus_probe_node(struct xen_bus_type *bus, ++ const char *type, ++ const char *nodename) ++{ ++ int err; ++ struct xenbus_device *xendev; ++ size_t stringlen; ++ char *tmpstring; ++ ++ enum xenbus_state state = xenbus_read_driver_state(nodename); ++ ++ if (bus->error) ++ return bus->error; ++ ++ if (state != XenbusStateInitialising) { ++ /* Device is not new, so ignore it. This can happen if a ++ device is going away after switching to Closed. */ ++ return 0; ++ } ++ ++ stringlen = strlen(nodename) + 1 + strlen(type) + 1; ++ xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); ++ if (!xendev) ++ return -ENOMEM; ++ ++ xendev->state = XenbusStateInitialising; ++ ++ /* Copy the strings into the extra space. */ ++ ++ tmpstring = (char *)(xendev + 1); ++ strcpy(tmpstring, nodename); ++ xendev->nodename = tmpstring; ++ ++ tmpstring += strlen(tmpstring) + 1; ++ strcpy(tmpstring, type); ++ xendev->devicetype = tmpstring; ++ init_completion(&xendev->down); ++ ++ xendev->dev.parent = &bus->dev; ++ xendev->dev.bus = &bus->bus; ++ xendev->dev.release = xenbus_dev_release; ++ ++ err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); ++ if (err) ++ goto fail; ++ ++ /* Register with generic device framework. */ ++ err = device_register(&xendev->dev); ++ if (err) ++ goto fail; ++ ++ err = device_create_file(&xendev->dev, &dev_attr_nodename); ++ if (err) ++ goto unregister; ++ err = device_create_file(&xendev->dev, &dev_attr_devtype); ++ if (err) ++ goto unregister; ++ ++ return 0; ++unregister: ++ device_remove_file(&xendev->dev, &dev_attr_nodename); ++ device_remove_file(&xendev->dev, &dev_attr_devtype); ++ device_unregister(&xendev->dev); ++fail: ++ kfree(xendev); ++ return err; ++} ++ ++/* device/<typename>/<name> */ ++static int xenbus_probe_frontend(const char *type, const char *name) ++{ ++ char *nodename; ++ int err; ++ ++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name); ++ if (!nodename) ++ return -ENOMEM; ++ ++ DPRINTK("%s", nodename); ++ ++ err = xenbus_probe_node(&xenbus_frontend, type, nodename); ++ kfree(nodename); ++ return err; ++} ++ ++static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) ++{ ++ int err = 0; ++ char **dir; ++ unsigned int dir_n = 0; ++ int i; ++ ++ dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); ++ if (IS_ERR(dir)) ++ return PTR_ERR(dir); ++ ++ for (i = 0; i < dir_n; i++) { ++ err = bus->probe(type, dir[i]); ++ if (err) ++ break; ++ } ++ kfree(dir); ++ return err; ++} ++ ++int xenbus_probe_devices(struct xen_bus_type *bus) ++{ ++ int err = 0; ++ char **dir; ++ unsigned int i, dir_n; ++ ++ if (bus->error) ++ return bus->error; ++ ++ dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); ++ if (IS_ERR(dir)) ++ return PTR_ERR(dir); ++ ++ for (i = 0; i < dir_n; i++) { ++ err = xenbus_probe_device_type(bus, dir[i]); ++ if (err) ++ break; ++ } ++ kfree(dir); ++ return err; ++} ++ ++static unsigned int char_count(const char *str, char c) ++{ ++ unsigned int i, ret = 0; ++ ++ for (i = 0; str[i]; i++) ++ if (str[i] == c) ++ ret++; ++ return ret; ++} ++ ++static int strsep_len(const char *str, char c, unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; str[i]; i++) ++ if (str[i] == c) { ++ if (len == 0) ++ return i; ++ len--; ++ } ++ return (len == 0) ? i : -ERANGE; ++} ++ ++void dev_changed(const char *node, struct xen_bus_type *bus) ++{ ++ int exists, rootlen; ++ struct xenbus_device *dev; ++ char type[BUS_ID_SIZE]; ++ const char *p, *root; ++ ++ if (bus->error || char_count(node, '/') < 2) ++ return; ++ ++ exists = xenbus_exists(XBT_NIL, node, ""); ++ if (!exists) { ++ xenbus_cleanup_devices(node, &bus->bus); ++ return; ++ } ++ ++ /* backend/<type>/... or device/<type>/... */ ++ p = strchr(node, '/') + 1; ++ snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p); ++ type[BUS_ID_SIZE-1] = '\0'; ++ ++ rootlen = strsep_len(node, '/', bus->levels); ++ if (rootlen < 0) ++ return; ++ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node); ++ if (!root) ++ return; ++ ++ dev = xenbus_device_find(root, &bus->bus); ++ if (!dev) ++ xenbus_probe_node(bus, type, root); ++ else ++ put_device(&dev->dev); ++ ++ kfree(root); ++} ++ ++static void frontend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ DPRINTK(""); ++ ++ dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); ++} ++ ++/* We watch for devices appearing and vanishing. */ ++static struct xenbus_watch fe_watch = { ++ .node = "device", ++ .callback = frontend_changed, ++}; ++ ++static int suspend_dev(struct device *dev, void *data) ++{ ++ int err = 0; ++ struct xenbus_driver *drv; ++ struct xenbus_device *xdev; ++ ++ DPRINTK(""); ++ ++ if (dev->driver == NULL) ++ return 0; ++ drv = to_xenbus_driver(dev->driver); ++ xdev = container_of(dev, struct xenbus_device, dev); ++ if (drv->suspend) ++ err = drv->suspend(xdev); ++ if (err) ++ printk(KERN_WARNING ++ "xenbus: suspend %s failed: %i\n", dev->bus_id, err); ++ return 0; ++} ++ ++static int suspend_cancel_dev(struct device *dev, void *data) ++{ ++ int err = 0; ++ struct xenbus_driver *drv; ++ struct xenbus_device *xdev; ++ ++ DPRINTK(""); ++ ++ if (dev->driver == NULL) ++ return 0; ++ drv = to_xenbus_driver(dev->driver); ++ xdev = container_of(dev, struct xenbus_device, dev); ++ if (drv->suspend_cancel) ++ err = drv->suspend_cancel(xdev); ++ if (err) ++ printk(KERN_WARNING ++ "xenbus: suspend_cancel %s failed: %i\n", ++ dev->bus_id, err); ++ return 0; ++} ++ ++static int resume_dev(struct device *dev, void *data) ++{ ++ int err; ++ struct xenbus_driver *drv; ++ struct xenbus_device *xdev; ++ ++ DPRINTK(""); ++ ++ if (dev->driver == NULL) ++ return 0; ++ ++ drv = to_xenbus_driver(dev->driver); ++ xdev = container_of(dev, struct xenbus_device, dev); ++ ++ err = talk_to_otherend(xdev); ++ if (err) { ++ printk(KERN_WARNING ++ "xenbus: resume (talk_to_otherend) %s failed: %i\n", ++ dev->bus_id, err); ++ return err; ++ } ++ ++ xdev->state = XenbusStateInitialising; ++ ++ if (drv->resume) { ++ err = drv->resume(xdev); ++ if (err) { ++ printk(KERN_WARNING ++ "xenbus: resume %s failed: %i\n", ++ dev->bus_id, err); ++ return err; ++ } ++ } ++ ++ err = watch_otherend(xdev); ++ if (err) { ++ printk(KERN_WARNING ++ "xenbus_probe: resume (watch_otherend) %s failed: " ++ "%d.\n", dev->bus_id, err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void xenbus_suspend(void) ++{ ++ DPRINTK(""); ++ ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); ++ xenbus_backend_suspend(suspend_dev); ++ xs_suspend(); ++} ++EXPORT_SYMBOL_GPL(xenbus_suspend); ++ ++void xenbus_resume(void) ++{ ++ xb_init_comms(); ++ xs_resume(); ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); ++ xenbus_backend_resume(resume_dev); ++} ++EXPORT_SYMBOL_GPL(xenbus_resume); ++ ++void xenbus_suspend_cancel(void) ++{ ++ xs_suspend_cancel(); ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev); ++ xenbus_backend_resume(suspend_cancel_dev); ++} ++EXPORT_SYMBOL_GPL(xenbus_suspend_cancel); ++ ++/* A flag to determine if xenstored is 'ready' (i.e. has started) */ ++int xenstored_ready = 0; ++ ++ ++int register_xenstore_notifier(struct notifier_block *nb) ++{ ++ int ret = 0; ++ ++ if (xenstored_ready > 0) ++ ret = nb->notifier_call(nb, 0, NULL); ++ else ++ atomic_notifier_chain_register(&xenstore_chain, nb); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_xenstore_notifier); ++ ++void unregister_xenstore_notifier(struct notifier_block *nb) ++{ ++ atomic_notifier_chain_unregister(&xenstore_chain, nb); ++} ++EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); ++ ++ ++void xenbus_probe(struct work_struct *unused) ++{ ++ BUG_ON((xenstored_ready <= 0)); ++ ++ /* Enumerate devices in xenstore and watch for changes. */ ++ xenbus_probe_devices(&xenbus_frontend); ++ register_xenbus_watch(&fe_watch); ++ xenbus_backend_probe_and_watch(); ++ ++ /* Notify others that xenstore is up */ ++ atomic_notifier_call_chain(&xenstore_chain, 0, NULL); ++} ++ ++ ++#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST) ++static struct file_operations xsd_kva_fops; ++static struct proc_dir_entry *xsd_kva_intf; ++static struct proc_dir_entry *xsd_port_intf; ++ ++static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ size_t size = vma->vm_end - vma->vm_start; ++ ++ if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0)) ++ return -EINVAL; ++ ++ if (remap_pfn_range(vma, vma->vm_start, mfn_to_pfn(xen_store_mfn), ++ size, vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static int xsd_kva_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "0x%p", xen_store_interface); ++ *eof = 1; ++ return len; ++} ++ ++static int xsd_port_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d", xen_store_evtchn); ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static int xenbus_probe_init(void) ++{ ++ int err = 0; ++ unsigned long page = 0; ++ ++ DPRINTK(""); ++ ++ if (!is_running_on_xen()) ++ return -ENODEV; ++ ++ /* Register ourselves with the kernel bus subsystem */ ++ xenbus_frontend.error = bus_register(&xenbus_frontend.bus); ++ if (xenbus_frontend.error) ++ printk(KERN_WARNING ++ "XENBUS: Error registering frontend bus: %i\n", ++ xenbus_frontend.error); ++ xenbus_backend_bus_register(); ++ ++ /* ++ * Domain0 doesn't have a store_evtchn or store_mfn yet. ++ */ ++ if (is_initial_xendomain()) { ++ struct evtchn_alloc_unbound alloc_unbound; ++ ++ /* Allocate page. */ ++ page = get_zeroed_page(GFP_KERNEL); ++ if (!page) { ++ err = -ENOMEM; ++ goto err_nomem; ++ } ++ ++ xen_store_mfn = xen_start_info->store_mfn = ++ pfn_to_mfn(virt_to_phys((void *)page) >> ++ PAGE_SHIFT); ++ ++ /* Next allocate a local port which xenstored can bind to */ ++ alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.remote_dom = 0; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, ++ &alloc_unbound); ++ if (err == -ENOSYS) ++ goto err; ++ BUG_ON(err); ++ xen_store_evtchn = xen_start_info->store_evtchn = ++ alloc_unbound.port; ++ ++#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST) ++ /* And finally publish the above info in /proc/xen */ ++ xsd_kva_intf = create_xen_proc_entry("xsd_kva", 0600); ++ if (xsd_kva_intf) { ++ memcpy(&xsd_kva_fops, xsd_kva_intf->proc_fops, ++ sizeof(xsd_kva_fops)); ++ xsd_kva_fops.mmap = xsd_kva_mmap; ++ xsd_kva_intf->proc_fops = &xsd_kva_fops; ++ xsd_kva_intf->read_proc = xsd_kva_read; ++ } ++ xsd_port_intf = create_xen_proc_entry("xsd_port", 0400); ++ if (xsd_port_intf) ++ xsd_port_intf->read_proc = xsd_port_read; ++#endif ++ xen_store_interface = mfn_to_virt(xen_store_mfn); ++ } else { ++ xenstored_ready = 1; ++#ifdef CONFIG_XEN ++ xen_store_evtchn = xen_start_info->store_evtchn; ++ xen_store_mfn = xen_start_info->store_mfn; ++ xen_store_interface = mfn_to_virt(xen_store_mfn); ++#else ++ xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); ++ xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); ++ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, ++ PAGE_SIZE); ++#endif ++ } ++ ++ ++ xenbus_dev_init(); ++ ++ /* Initialize the interface to xenstore. */ ++ err = xs_init(); ++ if (err) { ++ printk(KERN_WARNING ++ "XENBUS: Error initializing xenstore comms: %i\n", err); ++ goto err; ++ } ++ ++ /* Register ourselves with the kernel device subsystem */ ++ if (!xenbus_frontend.error) { ++ xenbus_frontend.error = device_register(&xenbus_frontend.dev); ++ if (xenbus_frontend.error) { ++ bus_unregister(&xenbus_frontend.bus); ++ printk(KERN_WARNING ++ "XENBUS: Error registering frontend device: %i\n", ++ xenbus_frontend.error); ++ } ++ } ++ xenbus_backend_device_register(); ++ ++ if (!is_initial_xendomain()) ++ xenbus_probe(NULL); ++ ++ return 0; ++ ++ err: ++ if (page) ++ free_page(page); ++ ++ /* ++ * Do not unregister the xenbus front/backend buses here. The buses ++ * must exist because front/backend drivers will use them when they are ++ * registered. ++ */ ++ err_nomem: ++ bus_unregister(&xenbus_frontend.bus); ++ return err; ++} ++ ++#ifdef CONFIG_XEN ++postcore_initcall(xenbus_probe_init); ++MODULE_LICENSE("Dual BSD/GPL"); ++#else ++int xenbus_init(void) ++{ ++ return xenbus_probe_init(); ++} ++#endif ++ ++static int is_disconnected_device(struct device *dev, void *data) ++{ ++ struct xenbus_device *xendev = to_xenbus_device(dev); ++ struct device_driver *drv = data; ++ ++ /* ++ * A device with no driver will never connect. We care only about ++ * devices which should currently be in the process of connecting. ++ */ ++ if (!dev->driver) ++ return 0; ++ ++ /* Is this search limited to a particular driver? */ ++ if (drv && (dev->driver != drv)) ++ return 0; ++ ++ return (xendev->state != XenbusStateConnected); ++} ++ ++static int exists_disconnected_device(struct device_driver *drv) ++{ ++ if (xenbus_frontend.error) ++ return xenbus_frontend.error; ++ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, ++ is_disconnected_device); ++} ++ ++static int print_device_status(struct device *dev, void *data) ++{ ++ struct xenbus_device *xendev = to_xenbus_device(dev); ++ struct device_driver *drv = data; ++ ++ /* Is this operation limited to a particular driver? */ ++ if (drv && (dev->driver != drv)) ++ return 0; ++ ++ if (!dev->driver) { ++ /* Information only: is this too noisy? */ ++ printk(KERN_INFO "XENBUS: Device with no driver: %s\n", ++ xendev->nodename); ++ } else if (xendev->state != XenbusStateConnected) { ++ printk(KERN_WARNING "XENBUS: Timeout connecting " ++ "to device: %s (state %d)\n", ++ xendev->nodename, xendev->state); ++ } ++ ++ return 0; ++} ++ ++/* We only wait for device setup after most initcalls have run. */ ++static int ready_to_wait_for_devices; ++ ++/* ++ * On a 10 second timeout, wait for all devices currently configured. We need ++ * to do this to guarantee that the filesystems and / or network devices ++ * needed for boot are available, before we can allow the boot to proceed. ++ * ++ * This needs to be on a late_initcall, to happen after the frontend device ++ * drivers have been initialised, but before the root fs is mounted. ++ * ++ * A possible improvement here would be to have the tools add a per-device ++ * flag to the store entry, indicating whether it is needed at boot time. ++ * This would allow people who knew what they were doing to accelerate their ++ * boot slightly, but of course needs tools or manual intervention to set up ++ * those flags correctly. ++ */ ++static void wait_for_devices(struct xenbus_driver *xendrv) ++{ ++ unsigned long timeout = jiffies + 10*HZ; ++ struct device_driver *drv = xendrv ? &xendrv->driver : NULL; ++ ++ if (!ready_to_wait_for_devices || !is_running_on_xen()) ++ return; ++ ++ while (exists_disconnected_device(drv)) { ++ if (time_after(jiffies, timeout)) ++ break; ++ schedule_timeout_interruptible(HZ/10); ++ } ++ ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, ++ print_device_status); ++} ++ ++#ifndef MODULE ++static int __init boot_wait_for_devices(void) ++{ ++ if (!xenbus_frontend.error) { ++ ready_to_wait_for_devices = 1; ++ wait_for_devices(NULL); ++ } ++ return 0; ++} ++ ++late_initcall(boot_wait_for_devices); ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_probe.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_probe.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,74 @@ ++/****************************************************************************** ++ * xenbus_probe.h ++ * ++ * Talks to Xen Store to figure out what devices we have. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * Copyright (C) 2005 XenSource Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef _XENBUS_PROBE_H ++#define _XENBUS_PROBE_H ++ ++#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE) ++extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); ++extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); ++extern void xenbus_backend_probe_and_watch(void); ++extern void xenbus_backend_bus_register(void); ++extern void xenbus_backend_device_register(void); ++#else ++static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {} ++static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {} ++static inline void xenbus_backend_probe_and_watch(void) {} ++static inline void xenbus_backend_bus_register(void) {} ++static inline void xenbus_backend_device_register(void) {} ++#endif ++ ++struct xen_bus_type ++{ ++ char *root; ++ int error; ++ unsigned int levels; ++ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); ++ int (*probe)(const char *type, const char *dir); ++ struct bus_type bus; ++ struct device dev; ++}; ++ ++extern int xenbus_match(struct device *_dev, struct device_driver *_drv); ++extern int xenbus_dev_probe(struct device *_dev); ++extern int xenbus_dev_remove(struct device *_dev); ++extern int xenbus_register_driver_common(struct xenbus_driver *drv, ++ struct xen_bus_type *bus); ++extern int xenbus_probe_node(struct xen_bus_type *bus, ++ const char *type, ++ const char *nodename); ++extern int xenbus_probe_devices(struct xen_bus_type *bus); ++ ++extern void dev_changed(const char *node, struct xen_bus_type *bus); ++#endif ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_probe_backend.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_probe_backend.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,286 @@ ++/****************************************************************************** ++ * Talks to Xen Store to figure out what devices we have (backend half). ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * Copyright (C) 2005 Mike Wray, Hewlett-Packard ++ * Copyright (C) 2005, 2006 XenSource Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ ++ __FUNCTION__, __LINE__, ##args) ++ ++#include <linux/kernel.h> ++#include <linux/err.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/fcntl.h> ++#include <linux/mm.h> ++#include <linux/notifier.h> ++#include <linux/kthread.h> ++ ++#include <asm/io.h> ++#include <asm/page.h> ++#include <asm/maddr.h> ++#include <asm/pgtable.h> ++#include <asm/hypervisor.h> ++#include <xen/xenbus.h> ++#include <xen/xen_proc.h> ++#include <xen/evtchn.h> ++#include <xen/features.h> ++#include <xen/hvm.h> ++ ++#include "xenbus_comms.h" ++#include "xenbus_probe.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++static int xenbus_uevent_backend(struct device *dev, char **envp, ++ int num_envp, char *buffer, int buffer_size); ++static int xenbus_probe_backend(const char *type, const char *domid); ++ ++extern int read_otherend_details(struct xenbus_device *xendev, ++ char *id_node, char *path_node); ++ ++static int read_frontend_details(struct xenbus_device *xendev) ++{ ++ return read_otherend_details(xendev, "frontend-id", "frontend"); ++} ++ ++/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */ ++static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) ++{ ++ int domid, err; ++ const char *devid, *type, *frontend; ++ unsigned int typelen; ++ ++ type = strchr(nodename, '/'); ++ if (!type) ++ return -EINVAL; ++ type++; ++ typelen = strcspn(type, "/"); ++ if (!typelen || type[typelen] != '/') ++ return -EINVAL; ++ ++ devid = strrchr(nodename, '/') + 1; ++ ++ err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid, ++ "frontend", NULL, &frontend, ++ NULL); ++ if (err) ++ return err; ++ if (strlen(frontend) == 0) ++ err = -ERANGE; ++ if (!err && !xenbus_exists(XBT_NIL, frontend, "")) ++ err = -ENOENT; ++ kfree(frontend); ++ ++ if (err) ++ return err; ++ ++ if (snprintf(bus_id, BUS_ID_SIZE, ++ "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE) ++ return -ENOSPC; ++ return 0; ++} ++ ++static struct xen_bus_type xenbus_backend = { ++ .root = "backend", ++ .levels = 3, /* backend/type/<frontend>/<id> */ ++ .get_bus_id = backend_bus_id, ++ .probe = xenbus_probe_backend, ++ .bus = { ++ .name = "xen-backend", ++ .match = xenbus_match, ++ .probe = xenbus_dev_probe, ++ .remove = xenbus_dev_remove, ++// .shutdown = xenbus_dev_shutdown, ++ .uevent = xenbus_uevent_backend, ++ }, ++ .dev = { ++ .bus_id = "xen-backend", ++ }, ++}; ++ ++static int xenbus_uevent_backend(struct device *dev, char **envp, ++ int num_envp, char *buffer, int buffer_size) ++{ ++ struct xenbus_device *xdev; ++ struct xenbus_driver *drv; ++ int i = 0; ++ int length = 0; ++ ++ DPRINTK(""); ++ ++ if (dev == NULL) ++ return -ENODEV; ++ ++ xdev = to_xenbus_device(dev); ++ if (xdev == NULL) ++ return -ENODEV; ++ ++ /* stuff we want to pass to /sbin/hotplug */ ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "XENBUS_TYPE=%s", xdev->devicetype); ++ ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "XENBUS_PATH=%s", xdev->nodename); ++ ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "XENBUS_BASE_PATH=%s", xenbus_backend.root); ++ ++ /* terminate, set to next free slot, shrink available space */ ++ envp[i] = NULL; ++ envp = &envp[i]; ++ num_envp -= i; ++ buffer = &buffer[length]; ++ buffer_size -= length; ++ ++ if (dev->driver) { ++ drv = to_xenbus_driver(dev->driver); ++ if (drv && drv->uevent) ++ return drv->uevent(xdev, envp, num_envp, buffer, ++ buffer_size); ++ } ++ ++ return 0; ++} ++ ++int xenbus_register_backend(struct xenbus_driver *drv) ++{ ++ drv->read_otherend_details = read_frontend_details; ++ ++ return xenbus_register_driver_common(drv, &xenbus_backend); ++} ++EXPORT_SYMBOL_GPL(xenbus_register_backend); ++ ++/* backend/<typename>/<frontend-uuid>/<name> */ ++static int xenbus_probe_backend_unit(const char *dir, ++ const char *type, ++ const char *name) ++{ ++ char *nodename; ++ int err; ++ ++ nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name); ++ if (!nodename) ++ return -ENOMEM; ++ ++ DPRINTK("%s\n", nodename); ++ ++ err = xenbus_probe_node(&xenbus_backend, type, nodename); ++ kfree(nodename); ++ return err; ++} ++ ++/* backend/<typename>/<frontend-domid> */ ++static int xenbus_probe_backend(const char *type, const char *domid) ++{ ++ char *nodename; ++ int err = 0; ++ char **dir; ++ unsigned int i, dir_n = 0; ++ ++ DPRINTK(""); ++ ++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid); ++ if (!nodename) ++ return -ENOMEM; ++ ++ dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n); ++ if (IS_ERR(dir)) { ++ kfree(nodename); ++ return PTR_ERR(dir); ++ } ++ ++ for (i = 0; i < dir_n; i++) { ++ err = xenbus_probe_backend_unit(nodename, type, dir[i]); ++ if (err) ++ break; ++ } ++ kfree(dir); ++ kfree(nodename); ++ return err; ++} ++ ++static void backend_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ DPRINTK(""); ++ ++ dev_changed(vec[XS_WATCH_PATH], &xenbus_backend); ++} ++ ++static struct xenbus_watch be_watch = { ++ .node = "backend", ++ .callback = backend_changed, ++}; ++ ++void xenbus_backend_suspend(int (*fn)(struct device *, void *)) ++{ ++ DPRINTK(""); ++ if (!xenbus_backend.error) ++ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); ++} ++ ++void xenbus_backend_resume(int (*fn)(struct device *, void *)) ++{ ++ DPRINTK(""); ++ if (!xenbus_backend.error) ++ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); ++} ++ ++void xenbus_backend_probe_and_watch(void) ++{ ++ xenbus_probe_devices(&xenbus_backend); ++ register_xenbus_watch(&be_watch); ++} ++ ++void xenbus_backend_bus_register(void) ++{ ++ xenbus_backend.error = bus_register(&xenbus_backend.bus); ++ if (xenbus_backend.error) ++ printk(KERN_WARNING ++ "XENBUS: Error registering backend bus: %i\n", ++ xenbus_backend.error); ++} ++ ++void xenbus_backend_device_register(void) ++{ ++ if (xenbus_backend.error) ++ return; ++ ++ xenbus_backend.error = device_register(&xenbus_backend.dev); ++ if (xenbus_backend.error) { ++ bus_unregister(&xenbus_backend.bus); ++ printk(KERN_WARNING ++ "XENBUS: Error registering backend device: %i\n", ++ xenbus_backend.error); ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenbus/xenbus_xs.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenbus/xenbus_xs.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,880 @@ ++/****************************************************************************** ++ * xenbus_xs.c ++ * ++ * This is the kernel equivalent of the "xs" library. We don't need everything ++ * and we use xenbus_comms for communication. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include <linux/unistd.h> ++#include <linux/errno.h> ++#include <linux/types.h> ++#include <linux/uio.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++#include <linux/fcntl.h> ++#include <linux/kthread.h> ++#include <linux/rwsem.h> ++#include <linux/module.h> ++#include <linux/mutex.h> ++#include <xen/xenbus.h> ++#include "xenbus_comms.h" ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++struct xs_stored_msg { ++ struct list_head list; ++ ++ struct xsd_sockmsg hdr; ++ ++ union { ++ /* Queued replies. */ ++ struct { ++ char *body; ++ } reply; ++ ++ /* Queued watch events. */ ++ struct { ++ struct xenbus_watch *handle; ++ char **vec; ++ unsigned int vec_size; ++ } watch; ++ } u; ++}; ++ ++struct xs_handle { ++ /* A list of replies. Currently only one will ever be outstanding. */ ++ struct list_head reply_list; ++ spinlock_t reply_lock; ++ wait_queue_head_t reply_waitq; ++ ++ /* ++ * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. ++ * response_mutex is never taken simultaneously with the other three. ++ */ ++ ++ /* One request at a time. */ ++ struct mutex request_mutex; ++ ++ /* Protect xenbus reader thread against save/restore. */ ++ struct mutex response_mutex; ++ ++ /* Protect transactions against save/restore. */ ++ struct rw_semaphore transaction_mutex; ++ ++ /* Protect watch (de)register against save/restore. */ ++ struct rw_semaphore watch_mutex; ++}; ++ ++static struct xs_handle xs_state; ++ ++/* List of registered watches, and a lock to protect it. */ ++static LIST_HEAD(watches); ++static DEFINE_SPINLOCK(watches_lock); ++ ++/* List of pending watch callback events, and a lock to protect it. */ ++static LIST_HEAD(watch_events); ++static DEFINE_SPINLOCK(watch_events_lock); ++ ++/* ++ * Details of the xenwatch callback kernel thread. The thread waits on the ++ * watch_events_waitq for work to do (queued on watch_events list). When it ++ * wakes up it acquires the xenwatch_mutex before reading the list and ++ * carrying out work. ++ */ ++static pid_t xenwatch_pid; ++/* static */ DEFINE_MUTEX(xenwatch_mutex); ++static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); ++ ++static int get_error(const char *errorstring) ++{ ++ unsigned int i; ++ ++ for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) { ++ if (i == ARRAY_SIZE(xsd_errors) - 1) { ++ printk(KERN_WARNING ++ "XENBUS xen store gave: unknown error %s", ++ errorstring); ++ return EINVAL; ++ } ++ } ++ return xsd_errors[i].errnum; ++} ++ ++static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) ++{ ++ struct xs_stored_msg *msg; ++ char *body; ++ ++ spin_lock(&xs_state.reply_lock); ++ ++ while (list_empty(&xs_state.reply_list)) { ++ spin_unlock(&xs_state.reply_lock); ++ /* XXX FIXME: Avoid synchronous wait for response here. */ ++ wait_event(xs_state.reply_waitq, ++ !list_empty(&xs_state.reply_list)); ++ spin_lock(&xs_state.reply_lock); ++ } ++ ++ msg = list_entry(xs_state.reply_list.next, ++ struct xs_stored_msg, list); ++ list_del(&msg->list); ++ ++ spin_unlock(&xs_state.reply_lock); ++ ++ *type = msg->hdr.type; ++ if (len) ++ *len = msg->hdr.len; ++ body = msg->u.reply.body; ++ ++ kfree(msg); ++ ++ return body; ++} ++ ++void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) ++{ ++ void *ret; ++ struct xsd_sockmsg req_msg = *msg; ++ int err; ++ ++ if (req_msg.type == XS_TRANSACTION_START) ++ down_read(&xs_state.transaction_mutex); ++ ++ mutex_lock(&xs_state.request_mutex); ++ ++ err = xb_write(msg, sizeof(*msg) + msg->len); ++ if (err) { ++ msg->type = XS_ERROR; ++ ret = ERR_PTR(err); ++ } else ++ ret = read_reply(&msg->type, &msg->len); ++ ++ mutex_unlock(&xs_state.request_mutex); ++ ++ if ((req_msg.type == XS_TRANSACTION_END) || ++ ((req_msg.type == XS_TRANSACTION_START) && ++ (msg->type == XS_ERROR))) ++ up_read(&xs_state.transaction_mutex); ++ ++ return ret; ++} ++ ++/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ ++static void *xs_talkv(struct xenbus_transaction t, ++ enum xsd_sockmsg_type type, ++ const struct kvec *iovec, ++ unsigned int num_vecs, ++ unsigned int *len) ++{ ++ struct xsd_sockmsg msg; ++ void *ret = NULL; ++ unsigned int i; ++ int err; ++ ++ msg.tx_id = t.id; ++ msg.req_id = 0; ++ msg.type = type; ++ msg.len = 0; ++ for (i = 0; i < num_vecs; i++) ++ msg.len += iovec[i].iov_len; ++ ++ mutex_lock(&xs_state.request_mutex); ++ ++ err = xb_write(&msg, sizeof(msg)); ++ if (err) { ++ mutex_unlock(&xs_state.request_mutex); ++ return ERR_PTR(err); ++ } ++ ++ for (i = 0; i < num_vecs; i++) { ++ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; ++ if (err) { ++ mutex_unlock(&xs_state.request_mutex); ++ return ERR_PTR(err); ++ } ++ } ++ ++ ret = read_reply(&msg.type, len); ++ ++ mutex_unlock(&xs_state.request_mutex); ++ ++ if (IS_ERR(ret)) ++ return ret; ++ ++ if (msg.type == XS_ERROR) { ++ err = get_error(ret); ++ kfree(ret); ++ return ERR_PTR(-err); ++ } ++ ++ if (msg.type != type) { ++ if (printk_ratelimit()) ++ printk(KERN_WARNING ++ "XENBUS unexpected type [%d], expected [%d]\n", ++ msg.type, type); ++ kfree(ret); ++ return ERR_PTR(-EINVAL); ++ } ++ return ret; ++} ++ ++/* Simplified version of xs_talkv: single message. */ ++static void *xs_single(struct xenbus_transaction t, ++ enum xsd_sockmsg_type type, ++ const char *string, ++ unsigned int *len) ++{ ++ struct kvec iovec; ++ ++ iovec.iov_base = (void *)string; ++ iovec.iov_len = strlen(string) + 1; ++ return xs_talkv(t, type, &iovec, 1, len); ++} ++ ++/* Many commands only need an ack, don't care what it says. */ ++static int xs_error(char *reply) ++{ ++ if (IS_ERR(reply)) ++ return PTR_ERR(reply); ++ kfree(reply); ++ return 0; ++} ++ ++static unsigned int count_strings(const char *strings, unsigned int len) ++{ ++ unsigned int num; ++ const char *p; ++ ++ for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) ++ num++; ++ ++ return num; ++} ++ ++/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ ++static char *join(const char *dir, const char *name) ++{ ++ char *buffer; ++ ++ if (strlen(name) == 0) ++ buffer = kasprintf(GFP_KERNEL, "%s", dir); ++ else ++ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name); ++ return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; ++} ++ ++static char **split(char *strings, unsigned int len, unsigned int *num) ++{ ++ char *p, **ret; ++ ++ /* Count the strings. */ ++ *num = count_strings(strings, len); ++ ++ /* Transfer to one big alloc for easy freeing. */ ++ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); ++ if (!ret) { ++ kfree(strings); ++ return ERR_PTR(-ENOMEM); ++ } ++ memcpy(&ret[*num], strings, len); ++ kfree(strings); ++ ++ strings = (char *)&ret[*num]; ++ for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) ++ ret[(*num)++] = p; ++ ++ return ret; ++} ++ ++char **xenbus_directory(struct xenbus_transaction t, ++ const char *dir, const char *node, unsigned int *num) ++{ ++ char *strings, *path; ++ unsigned int len; ++ ++ path = join(dir, node); ++ if (IS_ERR(path)) ++ return (char **)path; ++ ++ strings = xs_single(t, XS_DIRECTORY, path, &len); ++ kfree(path); ++ if (IS_ERR(strings)) ++ return (char **)strings; ++ ++ return split(strings, len, num); ++} ++EXPORT_SYMBOL_GPL(xenbus_directory); ++ ++/* Check if a path exists. Return 1 if it does. */ ++int xenbus_exists(struct xenbus_transaction t, ++ const char *dir, const char *node) ++{ ++ char **d; ++ int dir_n; ++ ++ d = xenbus_directory(t, dir, node, &dir_n); ++ if (IS_ERR(d)) ++ return 0; ++ kfree(d); ++ return 1; ++} ++EXPORT_SYMBOL_GPL(xenbus_exists); ++ ++/* Get the value of a single file. ++ * Returns a kmalloced value: call free() on it after use. ++ * len indicates length in bytes. ++ */ ++void *xenbus_read(struct xenbus_transaction t, ++ const char *dir, const char *node, unsigned int *len) ++{ ++ char *path; ++ void *ret; ++ ++ path = join(dir, node); ++ if (IS_ERR(path)) ++ return (void *)path; ++ ++ ret = xs_single(t, XS_READ, path, len); ++ kfree(path); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_read); ++ ++/* Write the value of a single file. ++ * Returns -err on failure. ++ */ ++int xenbus_write(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *string) ++{ ++ const char *path; ++ struct kvec iovec[2]; ++ int ret; ++ ++ path = join(dir, node); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ iovec[0].iov_base = (void *)path; ++ iovec[0].iov_len = strlen(path) + 1; ++ iovec[1].iov_base = (void *)string; ++ iovec[1].iov_len = strlen(string); ++ ++ ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); ++ kfree(path); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_write); ++ ++/* Create a new directory. */ ++int xenbus_mkdir(struct xenbus_transaction t, ++ const char *dir, const char *node) ++{ ++ char *path; ++ int ret; ++ ++ path = join(dir, node); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); ++ kfree(path); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_mkdir); ++ ++/* Destroy a file or directory (directories must be empty). */ ++int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) ++{ ++ char *path; ++ int ret; ++ ++ path = join(dir, node); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ ret = xs_error(xs_single(t, XS_RM, path, NULL)); ++ kfree(path); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_rm); ++ ++/* Start a transaction: changes by others will not be seen during this ++ * transaction, and changes will not be visible to others until end. ++ */ ++int xenbus_transaction_start(struct xenbus_transaction *t) ++{ ++ char *id_str; ++ ++ down_read(&xs_state.transaction_mutex); ++ ++ id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); ++ if (IS_ERR(id_str)) { ++ up_read(&xs_state.transaction_mutex); ++ return PTR_ERR(id_str); ++ } ++ ++ t->id = simple_strtoul(id_str, NULL, 0); ++ kfree(id_str); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xenbus_transaction_start); ++ ++/* End a transaction. ++ * If abandon is true, transaction is discarded instead of committed. ++ */ ++int xenbus_transaction_end(struct xenbus_transaction t, int abort) ++{ ++ char abortstr[2]; ++ int err; ++ ++ if (abort) ++ strcpy(abortstr, "F"); ++ else ++ strcpy(abortstr, "T"); ++ ++ err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); ++ ++ up_read(&xs_state.transaction_mutex); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_transaction_end); ++ ++/* Single read and scanf: returns -errno or num scanned. */ ++int xenbus_scanf(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *fmt, ...) ++{ ++ va_list ap; ++ int ret; ++ char *val; ++ ++ val = xenbus_read(t, dir, node, NULL); ++ if (IS_ERR(val)) ++ return PTR_ERR(val); ++ ++ va_start(ap, fmt); ++ ret = vsscanf(val, fmt, ap); ++ va_end(ap); ++ kfree(val); ++ /* Distinctive errno. */ ++ if (ret == 0) ++ return -ERANGE; ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_scanf); ++ ++/* Single printf and write: returns -errno or 0. */ ++int xenbus_printf(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *fmt, ...) ++{ ++ va_list ap; ++ int ret; ++#define PRINTF_BUFFER_SIZE 4096 ++ char *printf_buffer; ++ ++ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); ++ if (printf_buffer == NULL) ++ return -ENOMEM; ++ ++ va_start(ap, fmt); ++ ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); ++ va_end(ap); ++ ++ BUG_ON(ret > PRINTF_BUFFER_SIZE-1); ++ ret = xenbus_write(t, dir, node, printf_buffer); ++ ++ kfree(printf_buffer); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_printf); ++ ++/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ ++int xenbus_gather(struct xenbus_transaction t, const char *dir, ...) ++{ ++ va_list ap; ++ const char *name; ++ int ret = 0; ++ ++ va_start(ap, dir); ++ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { ++ const char *fmt = va_arg(ap, char *); ++ void *result = va_arg(ap, void *); ++ char *p; ++ ++ p = xenbus_read(t, dir, name, NULL); ++ if (IS_ERR(p)) { ++ ret = PTR_ERR(p); ++ break; ++ } ++ if (fmt) { ++ if (sscanf(p, fmt, result) == 0) ++ ret = -EINVAL; ++ kfree(p); ++ } else ++ *(char **)result = p; ++ } ++ va_end(ap); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xenbus_gather); ++ ++static int xs_watch(const char *path, const char *token) ++{ ++ struct kvec iov[2]; ++ ++ iov[0].iov_base = (void *)path; ++ iov[0].iov_len = strlen(path) + 1; ++ iov[1].iov_base = (void *)token; ++ iov[1].iov_len = strlen(token) + 1; ++ ++ return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov, ++ ARRAY_SIZE(iov), NULL)); ++} ++ ++static int xs_unwatch(const char *path, const char *token) ++{ ++ struct kvec iov[2]; ++ ++ iov[0].iov_base = (char *)path; ++ iov[0].iov_len = strlen(path) + 1; ++ iov[1].iov_base = (char *)token; ++ iov[1].iov_len = strlen(token) + 1; ++ ++ return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov, ++ ARRAY_SIZE(iov), NULL)); ++} ++ ++static struct xenbus_watch *find_watch(const char *token) ++{ ++ struct xenbus_watch *i, *cmp; ++ ++ cmp = (void *)simple_strtoul(token, NULL, 16); ++ ++ list_for_each_entry(i, &watches, list) ++ if (i == cmp) ++ return i; ++ ++ return NULL; ++} ++ ++/* Register callback to watch this node. */ ++int register_xenbus_watch(struct xenbus_watch *watch) ++{ ++ /* Pointer in ascii is the token. */ ++ char token[sizeof(watch) * 2 + 1]; ++ int err; ++ ++ sprintf(token, "%lX", (long)watch); ++ ++ down_read(&xs_state.watch_mutex); ++ ++ spin_lock(&watches_lock); ++ BUG_ON(find_watch(token)); ++ list_add(&watch->list, &watches); ++ spin_unlock(&watches_lock); ++ ++ err = xs_watch(watch->node, token); ++ ++ /* Ignore errors due to multiple registration. */ ++ if ((err != 0) && (err != -EEXIST)) { ++ spin_lock(&watches_lock); ++ list_del(&watch->list); ++ spin_unlock(&watches_lock); ++ } ++ ++ up_read(&xs_state.watch_mutex); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(register_xenbus_watch); ++ ++void unregister_xenbus_watch(struct xenbus_watch *watch) ++{ ++ struct xs_stored_msg *msg, *tmp; ++ char token[sizeof(watch) * 2 + 1]; ++ int err; ++ ++ sprintf(token, "%lX", (long)watch); ++ ++ down_read(&xs_state.watch_mutex); ++ ++ spin_lock(&watches_lock); ++ BUG_ON(!find_watch(token)); ++ list_del(&watch->list); ++ spin_unlock(&watches_lock); ++ ++ err = xs_unwatch(watch->node, token); ++ if (err) ++ printk(KERN_WARNING ++ "XENBUS Failed to release watch %s: %i\n", ++ watch->node, err); ++ ++ up_read(&xs_state.watch_mutex); ++ ++ /* Cancel pending watch events. */ ++ spin_lock(&watch_events_lock); ++ list_for_each_entry_safe(msg, tmp, &watch_events, list) { ++ if (msg->u.watch.handle != watch) ++ continue; ++ list_del(&msg->list); ++ kfree(msg->u.watch.vec); ++ kfree(msg); ++ } ++ spin_unlock(&watch_events_lock); ++ ++ /* Flush any currently-executing callback, unless we are it. :-) */ ++ if (current->pid != xenwatch_pid) { ++ mutex_lock(&xenwatch_mutex); ++ mutex_unlock(&xenwatch_mutex); ++ } ++} ++EXPORT_SYMBOL_GPL(unregister_xenbus_watch); ++ ++void xs_suspend(void) ++{ ++ down_write(&xs_state.transaction_mutex); ++ down_write(&xs_state.watch_mutex); ++ mutex_lock(&xs_state.request_mutex); ++ mutex_lock(&xs_state.response_mutex); ++} ++ ++void xs_resume(void) ++{ ++ struct xenbus_watch *watch; ++ char token[sizeof(watch) * 2 + 1]; ++ ++ mutex_unlock(&xs_state.response_mutex); ++ mutex_unlock(&xs_state.request_mutex); ++ up_write(&xs_state.transaction_mutex); ++ ++ /* No need for watches_lock: the watch_mutex is sufficient. */ ++ list_for_each_entry(watch, &watches, list) { ++ sprintf(token, "%lX", (long)watch); ++ xs_watch(watch->node, token); ++ } ++ ++ up_write(&xs_state.watch_mutex); ++} ++ ++void xs_suspend_cancel(void) ++{ ++ mutex_unlock(&xs_state.response_mutex); ++ mutex_unlock(&xs_state.request_mutex); ++ up_write(&xs_state.watch_mutex); ++ up_write(&xs_state.transaction_mutex); ++} ++ ++static int xenwatch_handle_callback(void *data) ++{ ++ struct xs_stored_msg *msg = data; ++ ++ msg->u.watch.handle->callback(msg->u.watch.handle, ++ (const char **)msg->u.watch.vec, ++ msg->u.watch.vec_size); ++ ++ kfree(msg->u.watch.vec); ++ kfree(msg); ++ ++ /* Kill this kthread if we were spawned just for this callback. */ ++ if (current->pid != xenwatch_pid) ++ do_exit(0); ++ ++ return 0; ++} ++ ++static int xenwatch_thread(void *unused) ++{ ++ struct list_head *ent; ++ struct xs_stored_msg *msg; ++ ++ for (;;) { ++ wait_event_interruptible(watch_events_waitq, ++ !list_empty(&watch_events)); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ mutex_lock(&xenwatch_mutex); ++ ++ spin_lock(&watch_events_lock); ++ ent = watch_events.next; ++ if (ent != &watch_events) ++ list_del(ent); ++ spin_unlock(&watch_events_lock); ++ ++ if (ent != &watch_events) { ++ msg = list_entry(ent, struct xs_stored_msg, list); ++ if (msg->u.watch.handle->flags & XBWF_new_thread) ++ kthread_run(xenwatch_handle_callback, ++ msg, "xenwatch_cb"); ++ else ++ xenwatch_handle_callback(msg); ++ } ++ ++ mutex_unlock(&xenwatch_mutex); ++ } ++ ++ return 0; ++} ++ ++static int process_msg(void) ++{ ++ struct xs_stored_msg *msg; ++ char *body; ++ int err; ++ ++ /* ++ * We must disallow save/restore while reading a xenstore message. ++ * A partial read across s/r leaves us out of sync with xenstored. ++ */ ++ for (;;) { ++ err = xb_wait_for_data_to_read(); ++ if (err) ++ return err; ++ mutex_lock(&xs_state.response_mutex); ++ if (xb_data_to_read()) ++ break; ++ /* We raced with save/restore: pending data 'disappeared'. */ ++ mutex_unlock(&xs_state.response_mutex); ++ } ++ ++ ++ msg = kmalloc(sizeof(*msg), GFP_KERNEL); ++ if (msg == NULL) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ err = xb_read(&msg->hdr, sizeof(msg->hdr)); ++ if (err) { ++ kfree(msg); ++ goto out; ++ } ++ ++ body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); ++ if (body == NULL) { ++ kfree(msg); ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ err = xb_read(body, msg->hdr.len); ++ if (err) { ++ kfree(body); ++ kfree(msg); ++ goto out; ++ } ++ body[msg->hdr.len] = '\0'; ++ ++ if (msg->hdr.type == XS_WATCH_EVENT) { ++ msg->u.watch.vec = split(body, msg->hdr.len, ++ &msg->u.watch.vec_size); ++ if (IS_ERR(msg->u.watch.vec)) { ++ kfree(msg); ++ err = PTR_ERR(msg->u.watch.vec); ++ goto out; ++ } ++ ++ spin_lock(&watches_lock); ++ msg->u.watch.handle = find_watch( ++ msg->u.watch.vec[XS_WATCH_TOKEN]); ++ if (msg->u.watch.handle != NULL) { ++ spin_lock(&watch_events_lock); ++ list_add_tail(&msg->list, &watch_events); ++ wake_up(&watch_events_waitq); ++ spin_unlock(&watch_events_lock); ++ } else { ++ kfree(msg->u.watch.vec); ++ kfree(msg); ++ } ++ spin_unlock(&watches_lock); ++ } else { ++ msg->u.reply.body = body; ++ spin_lock(&xs_state.reply_lock); ++ list_add_tail(&msg->list, &xs_state.reply_list); ++ spin_unlock(&xs_state.reply_lock); ++ wake_up(&xs_state.reply_waitq); ++ } ++ ++ out: ++ mutex_unlock(&xs_state.response_mutex); ++ return err; ++} ++ ++static int xenbus_thread(void *unused) ++{ ++ int err; ++ ++ for (;;) { ++ err = process_msg(); ++ if (err) ++ printk(KERN_WARNING "XENBUS error %d while reading " ++ "message\n", err); ++ if (kthread_should_stop()) ++ break; ++ } ++ ++ return 0; ++} ++ ++int xs_init(void) ++{ ++ int err; ++ struct task_struct *task; ++ ++ INIT_LIST_HEAD(&xs_state.reply_list); ++ spin_lock_init(&xs_state.reply_lock); ++ init_waitqueue_head(&xs_state.reply_waitq); ++ ++ mutex_init(&xs_state.request_mutex); ++ mutex_init(&xs_state.response_mutex); ++ init_rwsem(&xs_state.transaction_mutex); ++ init_rwsem(&xs_state.watch_mutex); ++ ++ /* Initialize the shared memory rings to talk to xenstored */ ++ err = xb_init_comms(); ++ if (err) ++ return err; ++ ++ task = kthread_run(xenwatch_thread, NULL, "xenwatch"); ++ if (IS_ERR(task)) ++ return PTR_ERR(task); ++ xenwatch_pid = task->pid; ++ ++ task = kthread_run(xenbus_thread, NULL, "xenbus"); ++ if (IS_ERR(task)) ++ return PTR_ERR(task); ++ ++ return 0; ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 drivers/xen/xenoprof/xenoprofile.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/drivers/xen/xenoprof/xenoprofile.c Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,500 @@ ++/** ++ * @file xenoprofile.c ++ * ++ * @remark Copyright 2002 OProfile authors ++ * @remark Read the file COPYING ++ * ++ * @author John Levon <levon@movementarian.org> ++ * ++ * Modified by Aravind Menon and Jose Renato Santos for Xen ++ * These modifications are: ++ * Copyright (C) 2005 Hewlett-Packard Co. ++ * ++ * Separated out arch-generic part ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ */ ++ ++#include <linux/init.h> ++#include <linux/notifier.h> ++#include <linux/smp.h> ++#include <linux/oprofile.h> ++#include <linux/sysdev.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/vmalloc.h> ++#include <asm/pgtable.h> ++#include <xen/evtchn.h> ++#include <xen/xenoprof.h> ++#include <xen/driver_util.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/xenoprof.h> ++#include "../../../drivers/oprofile/cpu_buffer.h" ++#include "../../../drivers/oprofile/event_buffer.h" ++ ++#define MAX_XENOPROF_SAMPLES 16 ++ ++/* sample buffers shared with Xen */ ++xenoprof_buf_t * xenoprof_buf[MAX_VIRT_CPUS]; ++/* Shared buffer area */ ++struct xenoprof_shared_buffer shared_buffer; ++ ++/* Passive sample buffers shared with Xen */ ++xenoprof_buf_t *p_xenoprof_buf[MAX_OPROF_DOMAINS][MAX_VIRT_CPUS]; ++/* Passive shared buffer area */ ++struct xenoprof_shared_buffer p_shared_buffer[MAX_OPROF_DOMAINS]; ++ ++static int xenoprof_start(void); ++static void xenoprof_stop(void); ++ ++static int xenoprof_enabled = 0; ++static int xenoprof_is_primary = 0; ++static int active_defined; ++ ++/* Number of buffers in shared area (one per VCPU) */ ++int nbuf; ++/* Mappings of VIRQ_XENOPROF to irq number (per cpu) */ ++int ovf_irq[NR_CPUS]; ++/* cpu model type string - copied from Xen memory space on XENOPROF_init command */ ++char cpu_type[XENOPROF_CPU_TYPE_SIZE]; ++ ++#ifdef CONFIG_PM ++ ++static int xenoprof_suspend(struct sys_device * dev, pm_message_t state) ++{ ++ if (xenoprof_enabled == 1) ++ xenoprof_stop(); ++ return 0; ++} ++ ++ ++static int xenoprof_resume(struct sys_device * dev) ++{ ++ if (xenoprof_enabled == 1) ++ xenoprof_start(); ++ return 0; ++} ++ ++ ++static struct sysdev_class oprofile_sysclass = { ++ set_kset_name("oprofile"), ++ .resume = xenoprof_resume, ++ .suspend = xenoprof_suspend ++}; ++ ++ ++static struct sys_device device_oprofile = { ++ .id = 0, ++ .cls = &oprofile_sysclass, ++}; ++ ++ ++static int __init init_driverfs(void) ++{ ++ int error; ++ if (!(error = sysdev_class_register(&oprofile_sysclass))) ++ error = sysdev_register(&device_oprofile); ++ return error; ++} ++ ++ ++static void exit_driverfs(void) ++{ ++ sysdev_unregister(&device_oprofile); ++ sysdev_class_unregister(&oprofile_sysclass); ++} ++ ++#else ++#define init_driverfs() do { } while (0) ++#define exit_driverfs() do { } while (0) ++#endif /* CONFIG_PM */ ++ ++unsigned long long oprofile_samples = 0; ++unsigned long long p_oprofile_samples = 0; ++ ++unsigned int pdomains; ++struct xenoprof_passive passive_domains[MAX_OPROF_DOMAINS]; ++ ++static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive) ++{ ++ int head, tail, size; ++ ++ head = buf->event_head; ++ tail = buf->event_tail; ++ size = buf->event_size; ++ ++ if (tail > head) { ++ while (tail < size) { ++ oprofile_add_pc(buf->event_log[tail].eip, ++ buf->event_log[tail].mode, ++ buf->event_log[tail].event); ++ if (!is_passive) ++ oprofile_samples++; ++ else ++ p_oprofile_samples++; ++ tail++; ++ } ++ tail = 0; ++ } ++ while (tail < head) { ++ oprofile_add_pc(buf->event_log[tail].eip, ++ buf->event_log[tail].mode, ++ buf->event_log[tail].event); ++ if (!is_passive) ++ oprofile_samples++; ++ else ++ p_oprofile_samples++; ++ tail++; ++ } ++ ++ buf->event_tail = tail; ++} ++ ++static void xenoprof_handle_passive(void) ++{ ++ int i, j; ++ int flag_domain, flag_switch = 0; ++ ++ for (i = 0; i < pdomains; i++) { ++ flag_domain = 0; ++ for (j = 0; j < passive_domains[i].nbuf; j++) { ++ xenoprof_buf_t *buf = p_xenoprof_buf[i][j]; ++ if (buf->event_head == buf->event_tail) ++ continue; ++ if (!flag_domain) { ++ if (!oprofile_add_domain_switch(passive_domains[i]. ++ domain_id)) ++ goto done; ++ flag_domain = 1; ++ } ++ xenoprof_add_pc(buf, 1); ++ flag_switch = 1; ++ } ++ } ++done: ++ if (flag_switch) ++ oprofile_add_domain_switch(COORDINATOR_DOMAIN); ++} ++ ++static irqreturn_t ++xenoprof_ovf_interrupt(int irq, void * dev_id) ++{ ++ struct xenoprof_buf * buf; ++ int cpu; ++ static unsigned long flag; ++ ++ cpu = smp_processor_id(); ++ buf = xenoprof_buf[cpu]; ++ ++ xenoprof_add_pc(buf, 0); ++ ++ if (xenoprof_is_primary && !test_and_set_bit(0, &flag)) { ++ xenoprof_handle_passive(); ++ smp_mb__before_clear_bit(); ++ clear_bit(0, &flag); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static void unbind_virq(void) ++{ ++ int i; ++ ++ for_each_online_cpu(i) { ++ if (ovf_irq[i] >= 0) { ++ unbind_from_irqhandler(ovf_irq[i], NULL); ++ ovf_irq[i] = -1; ++ } ++ } ++} ++ ++ ++static int bind_virq(void) ++{ ++ int i, result; ++ ++ for_each_online_cpu(i) { ++ result = bind_virq_to_irqhandler(VIRQ_XENOPROF, ++ i, ++ xenoprof_ovf_interrupt, ++ SA_INTERRUPT, ++ "xenoprof", ++ NULL); ++ ++ if (result < 0) { ++ unbind_virq(); ++ return result; ++ } ++ ++ ovf_irq[i] = result; ++ } ++ ++ return 0; ++} ++ ++ ++static void unmap_passive_list(void) ++{ ++ int i; ++ for (i = 0; i < pdomains; i++) ++ xenoprof_arch_unmap_shared_buffer(&p_shared_buffer[i]); ++ pdomains = 0; ++} ++ ++ ++static int map_xenoprof_buffer(int max_samples) ++{ ++ struct xenoprof_get_buffer get_buffer; ++ struct xenoprof_buf *buf; ++ int ret, i; ++ ++ if ( shared_buffer.buffer ) ++ return 0; ++ ++ get_buffer.max_samples = max_samples; ++ ret = xenoprof_arch_map_shared_buffer(&get_buffer, &shared_buffer); ++ if (ret) ++ return ret; ++ nbuf = get_buffer.nbuf; ++ ++ for (i=0; i< nbuf; i++) { ++ buf = (struct xenoprof_buf*) ++ &shared_buffer.buffer[i * get_buffer.bufsize]; ++ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS); ++ xenoprof_buf[buf->vcpu_id] = buf; ++ } ++ ++ return 0; ++} ++ ++ ++static int xenoprof_setup(void) ++{ ++ int ret; ++ ++ if ( (ret = map_xenoprof_buffer(MAX_XENOPROF_SAMPLES)) ) ++ return ret; ++ ++ if ( (ret = bind_virq()) ) ++ return ret; ++ ++ if (xenoprof_is_primary) { ++ /* Define dom0 as an active domain if not done yet */ ++ if (!active_defined) { ++ domid_t domid; ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); ++ if (ret) ++ goto err; ++ domid = 0; ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); ++ if (ret) ++ goto err; ++ active_defined = 1; ++ } ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reserve_counters, NULL); ++ if (ret) ++ goto err; ++ xenoprof_arch_counter(); ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_setup_events, NULL); ++ ++ if (ret) ++ goto err; ++ } ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_enable_virq, NULL); ++ if (ret) ++ goto err; ++ ++ xenoprof_enabled = 1; ++ return 0; ++ err: ++ unbind_virq(); ++ return ret; ++} ++ ++ ++static void xenoprof_shutdown(void) ++{ ++ xenoprof_enabled = 0; ++ ++ HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL); ++ ++ if (xenoprof_is_primary) { ++ HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL); ++ active_defined = 0; ++ } ++ ++ unbind_virq(); ++ ++ xenoprof_arch_unmap_shared_buffer(&shared_buffer); ++ if (xenoprof_is_primary) ++ unmap_passive_list(); ++} ++ ++ ++static int xenoprof_start(void) ++{ ++ int ret = 0; ++ ++ if (xenoprof_is_primary) ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_start, NULL); ++ if (!ret) ++ xenoprof_arch_start(); ++ return ret; ++} ++ ++ ++static void xenoprof_stop(void) ++{ ++ if (xenoprof_is_primary) ++ HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL); ++ xenoprof_arch_stop(); ++} ++ ++ ++static int xenoprof_set_active(int * active_domains, ++ unsigned int adomains) ++{ ++ int ret = 0; ++ int i; ++ int set_dom0 = 0; ++ domid_t domid; ++ ++ if (!xenoprof_is_primary) ++ return 0; ++ ++ if (adomains > MAX_OPROF_DOMAINS) ++ return -E2BIG; ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); ++ if (ret) ++ return ret; ++ ++ for (i=0; i<adomains; i++) { ++ domid = active_domains[i]; ++ if (domid != active_domains[i]) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); ++ if (ret) ++ goto out; ++ if (active_domains[i] == 0) ++ set_dom0 = 1; ++ } ++ /* dom0 must always be active but may not be in the list */ ++ if (!set_dom0) { ++ domid = 0; ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid); ++ } ++ ++out: ++ if (ret) ++ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL); ++ active_defined = !ret; ++ return ret; ++} ++ ++static int xenoprof_set_passive(int * p_domains, ++ unsigned int pdoms) ++{ ++ int ret; ++ int i, j; ++ struct xenoprof_buf *buf; ++ ++ if (!xenoprof_is_primary) ++ return 0; ++ ++ if (pdoms > MAX_OPROF_DOMAINS) ++ return -E2BIG; ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_reset_passive_list, NULL); ++ if (ret) ++ return ret; ++ unmap_passive_list(); ++ ++ for (i = 0; i < pdoms; i++) { ++ passive_domains[i].domain_id = p_domains[i]; ++ passive_domains[i].max_samples = 2048; ++ ret = xenoprof_arch_set_passive(&passive_domains[i], ++ &p_shared_buffer[i]); ++ if (ret) ++ goto out; ++ for (j = 0; j < passive_domains[i].nbuf; j++) { ++ buf = (struct xenoprof_buf *) ++ &p_shared_buffer[i].buffer[j * passive_domains[i].bufsize]; ++ BUG_ON(buf->vcpu_id >= MAX_VIRT_CPUS); ++ p_xenoprof_buf[i][buf->vcpu_id] = buf; ++ } ++ } ++ ++ pdomains = pdoms; ++ return 0; ++ ++out: ++ for (j = 0; j < i; j++) ++ xenoprof_arch_unmap_shared_buffer(&p_shared_buffer[i]); ++ ++ return ret; ++} ++ ++struct oprofile_operations xenoprof_ops = { ++#ifdef HAVE_XENOPROF_CREATE_FILES ++ .create_files = xenoprof_create_files, ++#endif ++ .set_active = xenoprof_set_active, ++ .set_passive = xenoprof_set_passive, ++ .setup = xenoprof_setup, ++ .shutdown = xenoprof_shutdown, ++ .start = xenoprof_start, ++ .stop = xenoprof_stop ++}; ++ ++ ++/* in order to get driverfs right */ ++static int using_xenoprof; ++ ++int __init xenoprofile_init(struct oprofile_operations * ops) ++{ ++ struct xenoprof_init init; ++ int ret, i; ++ ++ ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init); ++ if (!ret) { ++ xenoprof_arch_init_counter(&init); ++ xenoprof_is_primary = init.is_primary; ++ ++ /* cpu_type is detected by Xen */ ++ cpu_type[XENOPROF_CPU_TYPE_SIZE-1] = 0; ++ strncpy(cpu_type, init.cpu_type, XENOPROF_CPU_TYPE_SIZE - 1); ++ xenoprof_ops.cpu_type = cpu_type; ++ ++ init_driverfs(); ++ using_xenoprof = 1; ++ *ops = xenoprof_ops; ++ ++ for (i=0; i<NR_CPUS; i++) ++ ovf_irq[i] = -1; ++ ++ active_defined = 0; ++ } ++ printk(KERN_INFO "%s: ret %d, events %d, xenoprof_is_primary %d\n", ++ __func__, ret, init.num_events, xenoprof_is_primary); ++ return ret; ++} ++ ++ ++void xenoprofile_exit(void) ++{ ++ if (using_xenoprof) ++ exit_driverfs(); ++ ++ xenoprof_arch_unmap_shared_buffer(&shared_buffer); ++ if (xenoprof_is_primary) { ++ unmap_passive_list(); ++ HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL); ++ } ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 fs/Kconfig +--- a/fs/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/fs/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -1003,6 +1003,7 @@ config HUGETLBFS + config HUGETLBFS + bool "HugeTLB file system support" + depends on X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN ++ depends on !XEN + help + hugetlbfs is a filesystem backing for HugeTLB pages, based on + ramfs. For architectures that support it, say Y here and read +diff -r 4a9ef6a03fd9 -r 85b796b085e5 fs/proc/vmcore.c +--- a/fs/proc/vmcore.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/fs/proc/vmcore.c Wed Aug 08 16:25:28 2007 -0300 +@@ -514,7 +514,7 @@ static int __init parse_crash_elf64_head + /* Do some basic Verification. */ + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || + (ehdr.e_type != ET_CORE) || +- !elf_check_arch(&ehdr) || ++ !vmcore_elf_check_arch(&ehdr) || + ehdr.e_ident[EI_CLASS] != ELFCLASS64 || + ehdr.e_ident[EI_VERSION] != EV_CURRENT || + ehdr.e_version != EV_CURRENT || +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/apic.h +--- a/include/asm-i386/apic.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/apic.h Wed Aug 08 16:25:28 2007 -0300 +@@ -116,10 +116,12 @@ extern void enable_APIC_timer(void); + + extern void enable_NMI_through_LVT0 (void * dummy); + ++#ifndef CONFIG_XEN + void smp_send_timer_broadcast_ipi(void); + void switch_APIC_timer_to_ipi(void *cpumask); + void switch_ipi_to_APIC_timer(void *cpumask); + #define ARCH_APICTIMER_STOPS_ON_C3 1 ++#endif + + extern int timer_over_8254; + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/desc.h +--- a/include/asm-i386/desc.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/desc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -76,12 +76,20 @@ static inline void pack_gate(__u32 *a, _ + + static inline void load_TLS(struct thread_struct *t, unsigned int cpu) + { ++#ifdef CONFIG_XEN ++#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), *(u64 *)&t->tls_array[i]) ++#else + #define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] ++#endif + C(0); C(1); C(2); + #undef C + } + ++#ifdef CONFIG_XEN ++extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); ++#else + #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#endif + #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + #define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + +@@ -92,7 +100,11 @@ static inline void write_dt_entry(void * + *(lp+1) = entry_b; + } + ++#ifdef CONFIG_XEN ++#define set_ldt(address,count) xen_set_ldt((unsigned long)address, count) ++#else + #define set_ldt native_set_ldt ++#endif + #endif /* CONFIG_PARAVIRT */ + + static inline fastcall void native_set_ldt(const void *addr, +@@ -119,6 +131,7 @@ static inline void _set_gate(int gate, u + write_idt_entry(idt_table, gate, a, b); + } + ++#ifndef CONFIG_X86_NO_TSS + static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) + { + __u32 a, b; +@@ -127,6 +140,7 @@ static inline void __set_tss_desc(unsign + DESCTYPE_TSS, 0); + write_gdt_entry(get_cpu_gdt_table(cpu), entry, a, b); + } ++#endif + + + #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/fixmap.h +--- a/include/asm-i386/fixmap.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/fixmap.h Wed Aug 08 16:25:28 2007 -0300 +@@ -88,6 +88,12 @@ enum fixed_addresses { + #ifdef CONFIG_PCI_MMCONFIG + FIX_PCIE_MCFG, + #endif ++#ifdef CONFIG_XEN ++ FIX_SHARED_INFO, ++#define NR_FIX_ISAMAPS 256 ++ FIX_ISAMAP_END, ++ FIX_ISAMAP_BEGIN = FIX_ISAMAP_END + NR_FIX_ISAMAPS - 1, ++#endif + __end_of_permanent_fixed_addresses, + /* temporary boot-time mappings, used before ioremap() is functional */ + #define NR_FIX_BTMAPS 16 +@@ -97,8 +103,15 @@ enum fixed_addresses { + __end_of_fixed_addresses + }; + ++#ifdef CONFIG_XEN ++extern void set_fixaddr_top(void); ++ ++extern void __set_fixmap(enum fixed_addresses idx, ++ maddr_t phys, pgprot_t flags); ++#else + extern void __set_fixmap (enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); ++#endif + extern void reserve_top_address(unsigned long reserve); + + #define set_fixmap(idx, phys) \ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/highmem.h +--- a/include/asm-i386/highmem.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/highmem.h Wed Aug 08 16:25:28 2007 -0300 +@@ -68,6 +68,9 @@ void *kmap(struct page *page); + void *kmap(struct page *page); + void kunmap(struct page *page); + void *kmap_atomic(struct page *page, enum km_type type); ++#ifdef CONFIG_XEN ++void *kmap_atomic_pte(struct page *page, enum km_type type); ++#endif + void kunmap_atomic(void *kvaddr, enum km_type type); + void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); + struct page *kmap_atomic_to_page(void *ptr); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/kexec.h +--- a/include/asm-i386/kexec.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/kexec.h Wed Aug 08 16:25:28 2007 -0300 +@@ -46,6 +46,9 @@ + + /* The native architecture */ + #define KEXEC_ARCH KEXEC_ARCH_386 ++ ++/* We can also handle crash dumps from 64 bit kernel. */ ++#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64) + + #define MAX_NOTE_BYTES 1024 + +@@ -98,6 +101,20 @@ relocate_kernel(unsigned long indirectio + unsigned long start_address, + unsigned int has_pae) ATTRIB_NORET; + ++ ++/* Under Xen we need to work with machine addresses. These macros give the ++ * machine address of a certain page to the generic kexec code instead of ++ * the pseudo physical address which would be given by the default macros. ++ */ ++ ++#ifdef CONFIG_XEN ++#define KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) ++#define kexec_virt_to_phys(addr) virt_to_machine(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _I386_KEXEC_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/kmap_types.h +--- a/include/asm-i386/kmap_types.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/kmap_types.h Wed Aug 08 16:25:28 2007 -0300 +@@ -22,7 +22,12 @@ D(10) KM_IRQ1, + D(10) KM_IRQ1, + D(11) KM_SOFTIRQ0, + D(12) KM_SOFTIRQ1, ++#ifdef CONFIG_XEN ++D(13) KM_SWIOTLB, ++D(14) KM_TYPE_NR ++#else + D(13) KM_TYPE_NR ++#endif + }; + + #undef D +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-default/mach_traps.h +--- a/include/asm-i386/mach-default/mach_traps.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/mach-default/mach_traps.h Wed Aug 08 16:25:28 2007 -0300 +@@ -12,6 +12,18 @@ static inline void clear_mem_error(unsig + static inline void clear_mem_error(unsigned char reason) + { + reason = (reason & 0xf) | 4; ++ outb(reason, 0x61); ++} ++ ++static inline void clear_io_check_error(unsigned char reason) ++{ ++ unsigned long i; ++ ++ reason = (reason & 0xf) | 8; ++ outb(reason, 0x61); ++ i = 2000; ++ while (--i) udelay(1000); ++ reason &= ~8; + outb(reason, 0x61); + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/agp.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/agp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,37 @@ ++#ifndef AGP_H ++#define AGP_H 1 ++ ++#include <asm/pgtable.h> ++#include <asm/cacheflush.h> ++#include <asm/system.h> ++ ++/* ++ * Functions to keep the agpgart mappings coherent with the MMU. ++ * The GART gives the CPU a physical alias of pages in memory. The alias region is ++ * mapped uncacheable. Make sure there are no conflicting mappings ++ * with different cachability attributes for the same page. This avoids ++ * data corruption on some CPUs. ++ */ ++ ++int map_page_into_agp(struct page *page); ++int unmap_page_from_agp(struct page *page); ++#define flush_agp_mappings() global_flush_tlb() ++ ++/* Could use CLFLUSH here if the cpu supports it. But then it would ++ need to be called for each cacheline of the whole page so it may not be ++ worth it. Would need a page for it. */ ++#define flush_agp_cache() wbinvd() ++ ++/* Convert a physical address to an address suitable for the GART. */ ++#define phys_to_gart(x) phys_to_machine(x) ++#define gart_to_phys(x) machine_to_phys(x) ++ ++/* GATT allocation. Returns/accepts GATT kernel virtual address. */ ++#define alloc_gatt_pages(order) ({ \ ++ char *_t; dma_addr_t _d; \ ++ _t = dma_alloc_coherent(NULL,PAGE_SIZE<<(order),&_d,GFP_KERNEL); \ ++ _t; }) ++#define free_gatt_pages(table, order) \ ++ dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table)) ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/dma-mapping.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/dma-mapping.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,157 @@ ++#ifndef _ASM_I386_DMA_MAPPING_H ++#define _ASM_I386_DMA_MAPPING_H ++ ++#include <linux/mm.h> ++ ++#include <asm/cache.h> ++#include <asm/io.h> ++#include <asm/scatterlist.h> ++#include <asm/bug.h> ++#include <asm/swiotlb.h> ++ ++static inline int ++address_needs_mapping(struct device *hwdev, dma_addr_t addr) ++{ ++ dma_addr_t mask = 0xffffffff; ++ /* If the device has a mask, use it, otherwise default to 32 bits */ ++ if (hwdev && hwdev->dma_mask) ++ mask = *hwdev->dma_mask; ++ return (addr & ~mask) != 0; ++} ++ ++static inline int ++range_straddles_page_boundary(void *p, size_t size) ++{ ++ extern unsigned long *contiguous_bitmap; ++ return (((((unsigned long)p & ~PAGE_MASK) + size) > PAGE_SIZE) && ++ !test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap)); ++} ++ ++#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) ++#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) ++ ++void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flag); ++ ++void dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle); ++ ++extern dma_addr_t ++dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction direction); ++ ++extern void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction); ++ ++extern int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction); ++ ++#ifdef CONFIG_HIGHMEM ++extern dma_addr_t ++dma_map_page(struct device *dev, struct page *page, unsigned long offset, ++ size_t size, enum dma_data_direction direction); ++ ++extern void ++dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, ++ enum dma_data_direction direction); ++#else ++#define dma_map_page(dev, page, offset, size, dir) \ ++ dma_map_single(dev, page_address(page) + (offset), (size), (dir)) ++#define dma_unmap_page dma_unmap_single ++#endif ++ ++extern void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, ++ enum dma_data_direction direction); ++ ++extern void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction); ++ ++extern void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, ++ enum dma_data_direction direction); ++ ++static inline void ++dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); ++} ++ ++static inline void ++dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction) ++{ ++ dma_sync_single_for_device(dev, dma_handle+offset, size, direction); ++} ++ ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_cpu(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_device(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++ ++extern int ++dma_mapping_error(dma_addr_t dma_addr); ++ ++extern int ++dma_supported(struct device *dev, u64 mask); ++ ++static inline int ++dma_set_mask(struct device *dev, u64 mask) ++{ ++ if(!dev->dma_mask || !dma_supported(dev, mask)) ++ return -EIO; ++ ++ *dev->dma_mask = mask; ++ ++ return 0; ++} ++ ++static inline int ++dma_get_cache_alignment(void) ++{ ++ /* no easy way to get cache size on all x86, so return the ++ * maximum possible, to be safe */ ++ return (1 << INTERNODE_CACHE_SHIFT); ++} ++ ++#define dma_is_consistent(d, h) (1) ++ ++static inline void ++dma_cache_sync(struct device *dev, void *vaddr, size_t size, ++ enum dma_data_direction direction) ++{ ++ flush_write_buffers(); ++} ++ ++#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY ++extern int ++dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, ++ dma_addr_t device_addr, size_t size, int flags); ++ ++extern void ++dma_release_declared_memory(struct device *dev); ++ ++extern void * ++dma_mark_declared_memory_occupied(struct device *dev, ++ dma_addr_t device_addr, size_t size); ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/floppy.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/floppy.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,147 @@ ++/* ++ * Architecture specific parts of the Floppy driver ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 1995 ++ * ++ * Modifications for Xen are Copyright (c) 2004, Keir Fraser. ++ */ ++#ifndef __ASM_XEN_I386_FLOPPY_H ++#define __ASM_XEN_I386_FLOPPY_H ++ ++#include <linux/vmalloc.h> ++ ++/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */ ++#include <asm/dma.h> ++#undef MAX_DMA_ADDRESS ++#define MAX_DMA_ADDRESS 0 ++#define CROSS_64KB(a,s) (0) ++ ++#define fd_inb(port) inb_p(port) ++#define fd_outb(value,port) outb_p(value,port) ++ ++#define fd_request_dma() (0) ++#define fd_free_dma() ((void)0) ++#define fd_enable_irq() enable_irq(FLOPPY_IRQ) ++#define fd_disable_irq() disable_irq(FLOPPY_IRQ) ++#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) ++#define fd_get_dma_residue() (virtual_dma_count + virtual_dma_residue) ++#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io) ++/* ++ * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from ++ * softirq context via motor_off_callback. A generic bug we happen to trigger. ++ */ ++#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL, get_order(size)) ++#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) ++ ++static int virtual_dma_count; ++static int virtual_dma_residue; ++static char *virtual_dma_addr; ++static int virtual_dma_mode; ++static int doing_pdma; ++ ++static irqreturn_t floppy_hardint(int irq, void *dev_id) ++{ ++ register unsigned char st; ++ register int lcount; ++ register char *lptr; ++ ++ if (!doing_pdma) ++ return floppy_interrupt(irq, dev_id); ++ ++ st = 1; ++ for(lcount=virtual_dma_count, lptr=virtual_dma_addr; ++ lcount; lcount--, lptr++) { ++ st=inb(virtual_dma_port+4) & 0xa0 ; ++ if(st != 0xa0) ++ break; ++ if(virtual_dma_mode) ++ outb_p(*lptr, virtual_dma_port+5); ++ else ++ *lptr = inb_p(virtual_dma_port+5); ++ } ++ virtual_dma_count = lcount; ++ virtual_dma_addr = lptr; ++ st = inb(virtual_dma_port+4); ++ ++ if(st == 0x20) ++ return IRQ_HANDLED; ++ if(!(st & 0x20)) { ++ virtual_dma_residue += virtual_dma_count; ++ virtual_dma_count=0; ++ doing_pdma = 0; ++ floppy_interrupt(irq, dev_id); ++ return IRQ_HANDLED; ++ } ++ return IRQ_HANDLED; ++} ++ ++static void fd_disable_dma(void) ++{ ++ doing_pdma = 0; ++ virtual_dma_residue += virtual_dma_count; ++ virtual_dma_count=0; ++} ++ ++static int fd_request_irq(void) ++{ ++ return request_irq(FLOPPY_IRQ, floppy_hardint, ++ IRQF_DISABLED, "floppy", NULL); ++} ++ ++static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) ++{ ++ doing_pdma = 1; ++ virtual_dma_port = io; ++ virtual_dma_mode = (mode == DMA_MODE_WRITE); ++ virtual_dma_addr = addr; ++ virtual_dma_count = size; ++ virtual_dma_residue = 0; ++ return 0; ++} ++ ++/* XEN: This trick to force 'virtual DMA' is from include/asm-m68k/floppy.h. */ ++#define FDC1 xen_floppy_init() ++static int FDC2 = -1; ++ ++static int xen_floppy_init(void) ++{ ++ use_virtual_dma = 1; ++ can_use_virtual_dma = 1; ++ return 0x3f0; ++} ++ ++/* ++ * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock ++ * is needed to prevent corrupted CMOS RAM in case "insmod floppy" ++ * coincides with another rtc CMOS user. Paul G. ++ */ ++#define FLOPPY0_TYPE ({ \ ++ unsigned long flags; \ ++ unsigned char val; \ ++ spin_lock_irqsave(&rtc_lock, flags); \ ++ val = (CMOS_READ(0x10) >> 4) & 15; \ ++ spin_unlock_irqrestore(&rtc_lock, flags); \ ++ val; \ ++}) ++ ++#define FLOPPY1_TYPE ({ \ ++ unsigned long flags; \ ++ unsigned char val; \ ++ spin_lock_irqsave(&rtc_lock, flags); \ ++ val = CMOS_READ(0x10) & 15; \ ++ spin_unlock_irqrestore(&rtc_lock, flags); \ ++ val; \ ++}) ++ ++#define N_FDC 2 ++#define N_DRIVE 8 ++ ++#define FLOPPY_MOTOR_MASK 0xf0 ++ ++#define EXTRA_FLOPPY_PARAMS ++ ++#endif /* __ASM_XEN_I386_FLOPPY_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/hypercall.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/hypercall.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,407 @@ ++/****************************************************************************** ++ * hypercall.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERCALL_H__ ++#define __HYPERCALL_H__ ++ ++#include <linux/string.h> /* memcpy() */ ++ ++#ifndef __HYPERVISOR_H__ ++# error "please don't include this file directly" ++#endif ++ ++#define __STR(x) #x ++#define STR(x) __STR(x) ++ ++#ifdef CONFIG_XEN ++#define HYPERCALL_STR(name) \ ++ "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)" ++#else ++#define HYPERCALL_STR(name) \ ++ "mov hypercall_stubs,%%eax; " \ ++ "add $("STR(__HYPERVISOR_##name)" * 32),%%eax; " \ ++ "call *%%eax" ++#endif ++ ++#define _hypercall0(type, name) \ ++({ \ ++ long __res; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res) \ ++ : \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall1(type, name, a1) \ ++({ \ ++ long __res, __ign1; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=b" (__ign1) \ ++ : "1" ((long)(a1)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall2(type, name, a1, a2) \ ++({ \ ++ long __res, __ign1, __ign2; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall3(type, name, a1, a2, a3) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ ++ "=d" (__ign3) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall4(type, name, a1, a2, a3, a4) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3, __ign4; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ ++ "=d" (__ign3), "=S" (__ign4) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)), "4" ((long)(a4)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ ++ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)), "4" ((long)(a4)), \ ++ "5" ((long)(a5)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++static inline int ++HYPERVISOR_set_trap_table( ++ trap_info_t *table) ++{ ++ return _hypercall1(int, set_trap_table, table); ++} ++ ++static inline int ++HYPERVISOR_mmu_update( ++ mmu_update_t *req, int count, int *success_count, domid_t domid) ++{ ++ return _hypercall4(int, mmu_update, req, count, success_count, domid); ++} ++ ++static inline int ++HYPERVISOR_mmuext_op( ++ struct mmuext_op *op, int count, int *success_count, domid_t domid) ++{ ++ return _hypercall4(int, mmuext_op, op, count, success_count, domid); ++} ++ ++static inline int ++HYPERVISOR_set_gdt( ++ unsigned long *frame_list, int entries) ++{ ++ return _hypercall2(int, set_gdt, frame_list, entries); ++} ++ ++static inline int ++HYPERVISOR_stack_switch( ++ unsigned long ss, unsigned long esp) ++{ ++ return _hypercall2(int, stack_switch, ss, esp); ++} ++ ++static inline int ++HYPERVISOR_set_callbacks( ++ unsigned long event_selector, unsigned long event_address, ++ unsigned long failsafe_selector, unsigned long failsafe_address) ++{ ++ return _hypercall4(int, set_callbacks, ++ event_selector, event_address, ++ failsafe_selector, failsafe_address); ++} ++ ++static inline int ++HYPERVISOR_fpu_taskswitch( ++ int set) ++{ ++ return _hypercall1(int, fpu_taskswitch, set); ++} ++ ++static inline int ++HYPERVISOR_sched_op_compat( ++ int cmd, unsigned long arg) ++{ ++ return _hypercall2(int, sched_op_compat, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_sched_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, sched_op, cmd, arg); ++} ++ ++static inline long ++HYPERVISOR_set_timer_op( ++ u64 timeout) ++{ ++ unsigned long timeout_hi = (unsigned long)(timeout>>32); ++ unsigned long timeout_lo = (unsigned long)timeout; ++ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); ++} ++ ++static inline int ++HYPERVISOR_platform_op( ++ struct xen_platform_op *platform_op) ++{ ++ platform_op->interface_version = XENPF_INTERFACE_VERSION; ++ return _hypercall1(int, platform_op, platform_op); ++} ++ ++static inline int ++HYPERVISOR_set_debugreg( ++ int reg, unsigned long value) ++{ ++ return _hypercall2(int, set_debugreg, reg, value); ++} ++ ++static inline unsigned long ++HYPERVISOR_get_debugreg( ++ int reg) ++{ ++ return _hypercall1(unsigned long, get_debugreg, reg); ++} ++ ++static inline int ++HYPERVISOR_update_descriptor( ++ u64 ma, u64 desc) ++{ ++ return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); ++} ++ ++static inline int ++HYPERVISOR_memory_op( ++ unsigned int cmd, void *arg) ++{ ++ return _hypercall2(int, memory_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_multicall( ++ multicall_entry_t *call_list, int nr_calls) ++{ ++ return _hypercall2(int, multicall, call_list, nr_calls); ++} ++ ++static inline int ++HYPERVISOR_update_va_mapping( ++ unsigned long va, pte_t new_val, unsigned long flags) ++{ ++ unsigned long pte_hi = 0; ++#ifdef CONFIG_X86_PAE ++ pte_hi = new_val.pte_high; ++#endif ++ return _hypercall4(int, update_va_mapping, va, ++ new_val.pte_low, pte_hi, flags); ++} ++ ++static inline int ++HYPERVISOR_event_channel_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, event_channel_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct evtchn_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, event_channel_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_acm_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, acm_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_xen_version( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, xen_version, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_console_io( ++ int cmd, int count, char *str) ++{ ++ return _hypercall3(int, console_io, cmd, count, str); ++} ++ ++static inline int ++HYPERVISOR_physdev_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, physdev_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct physdev_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, physdev_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_grant_table_op( ++ unsigned int cmd, void *uop, unsigned int count) ++{ ++ return _hypercall3(int, grant_table_op, cmd, uop, count); ++} ++ ++static inline int ++HYPERVISOR_update_va_mapping_otherdomain( ++ unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) ++{ ++ unsigned long pte_hi = 0; ++#ifdef CONFIG_X86_PAE ++ pte_hi = new_val.pte_high; ++#endif ++ return _hypercall5(int, update_va_mapping_otherdomain, va, ++ new_val.pte_low, pte_hi, flags, domid); ++} ++ ++static inline int ++HYPERVISOR_vm_assist( ++ unsigned int cmd, unsigned int type) ++{ ++ return _hypercall2(int, vm_assist, cmd, type); ++} ++ ++static inline int ++HYPERVISOR_vcpu_op( ++ int cmd, int vcpuid, void *extra_args) ++{ ++ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); ++} ++ ++static inline int ++HYPERVISOR_suspend( ++ unsigned long srec) ++{ ++ struct sched_shutdown sched_shutdown = { ++ .reason = SHUTDOWN_suspend ++ }; ++ ++ int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, ++ &sched_shutdown, srec); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, ++ SHUTDOWN_suspend, srec); ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_nmi_op( ++ unsigned long op, void *arg) ++{ ++ return _hypercall2(int, nmi_op, op, arg); ++} ++ ++static inline unsigned long ++HYPERVISOR_hvm_op( ++ int op, void *arg) ++{ ++ return _hypercall2(unsigned long, hvm_op, op, arg); ++} ++ ++static inline int ++HYPERVISOR_callback_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, callback_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_xenoprof_op( ++ int op, void *arg) ++{ ++ return _hypercall2(int, xenoprof_op, op, arg); ++} ++ ++static inline int ++HYPERVISOR_kexec_op( ++ unsigned long op, void *args) ++{ ++ return _hypercall2(int, kexec_op, op, args); ++} ++ ++ ++ ++#endif /* __HYPERCALL_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/hypervisor.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/hypervisor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,258 @@ ++/****************************************************************************** ++ * hypervisor.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERVISOR_H__ ++#define __HYPERVISOR_H__ ++ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/version.h> ++#include <linux/errno.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/platform.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/sched.h> ++#include <xen/interface/nmi.h> ++#include <asm/ptrace.h> ++#include <asm/page.h> ++#if defined(__i386__) ++# ifdef CONFIG_X86_PAE ++# include <asm-generic/pgtable-nopud.h> ++# else ++# include <asm-generic/pgtable-nopmd.h> ++# endif ++#endif ++ ++extern shared_info_t *HYPERVISOR_shared_info; ++ ++#define vcpu_info(cpu) (HYPERVISOR_shared_info->vcpu_info + (cpu)) ++#ifdef CONFIG_SMP ++#define current_vcpu_info() vcpu_info(smp_processor_id()) ++#else ++#define current_vcpu_info() vcpu_info(0) ++#endif ++ ++#ifdef CONFIG_X86_32 ++extern unsigned long hypervisor_virt_start; ++#endif ++ ++/* arch/xen/i386/kernel/setup.c */ ++extern start_info_t *xen_start_info; ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN) ++#else ++#define is_initial_xendomain() 0 ++#endif ++ ++/* arch/xen/kernel/evtchn.c */ ++/* Force a proper event-channel callback from Xen. */ ++void force_evtchn_callback(void); ++ ++/* arch/xen/kernel/process.c */ ++void xen_cpu_idle (void); ++ ++/* arch/xen/i386/kernel/hypervisor.c */ ++void do_hypervisor_callback(struct pt_regs *regs); ++ ++/* arch/xen/i386/mm/hypervisor.c */ ++/* ++ * NB. ptr values should be PHYSICAL, not MACHINE. 'vals' should be already ++ * be MACHINE addresses. ++ */ ++ ++void xen_pt_switch(unsigned long ptr); ++void xen_new_user_pt(unsigned long ptr); /* x86_64 only */ ++void xen_load_gs(unsigned int selector); /* x86_64 only */ ++void xen_tlb_flush(void); ++void xen_invlpg(unsigned long ptr); ++ ++void xen_l1_entry_update(pte_t *ptr, pte_t val); ++void xen_l2_entry_update(pmd_t *ptr, pmd_t val); ++void xen_l3_entry_update(pud_t *ptr, pud_t val); /* x86_64/PAE */ ++void xen_l4_entry_update(pgd_t *ptr, pgd_t val); /* x86_64 only */ ++void xen_pgd_pin(unsigned long ptr); ++void xen_pgd_unpin(unsigned long ptr); ++ ++void xen_set_ldt(unsigned long ptr, unsigned long bytes); ++ ++#ifdef CONFIG_SMP ++#include <linux/cpumask.h> ++void xen_tlb_flush_all(void); ++void xen_invlpg_all(unsigned long ptr); ++void xen_tlb_flush_mask(cpumask_t *mask); ++void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr); ++#endif ++ ++/* Returns zero on success else negative errno. */ ++int xen_create_contiguous_region( ++ unsigned long vstart, unsigned int order, unsigned int address_bits); ++void xen_destroy_contiguous_region( ++ unsigned long vstart, unsigned int order); ++ ++/* Turn jiffies into Xen system time. */ ++u64 jiffies_to_st(unsigned long jiffies); ++ ++#ifdef CONFIG_XEN_SCRUB_PAGES ++#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT) ++#else ++#define scrub_pages(_p,_n) ((void)0) ++#endif ++ ++#include <xen/hypercall.h> ++ ++#if defined(CONFIG_X86_64) ++#define MULTI_UVMFLAGS_INDEX 2 ++#define MULTI_UVMDOMID_INDEX 3 ++#else ++#define MULTI_UVMFLAGS_INDEX 3 ++#define MULTI_UVMDOMID_INDEX 4 ++#endif ++ ++#define is_running_on_xen() 1 ++ ++static inline int ++HYPERVISOR_yield( ++ void) ++{ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_block( ++ void) ++{ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0); ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_shutdown( ++ unsigned int reason) ++{ ++ struct sched_shutdown sched_shutdown = { ++ .reason = reason ++ }; ++ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason); ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_poll( ++ evtchn_port_t *ports, unsigned int nr_ports, u64 timeout) ++{ ++ int rc; ++ struct sched_poll sched_poll = { ++ .nr_ports = nr_ports, ++ .timeout = jiffies_to_st(timeout) ++ }; ++ set_xen_guest_handle(sched_poll.ports, ports); ++ ++ rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); ++#endif ++ ++ return rc; ++} ++ ++static inline void ++MULTI_update_va_mapping( ++ multicall_entry_t *mcl, unsigned long va, ++ pte_t new_val, unsigned long flags) ++{ ++ mcl->op = __HYPERVISOR_update_va_mapping; ++ mcl->args[0] = va; ++#if defined(CONFIG_X86_64) ++ mcl->args[1] = new_val.pte; ++#elif defined(CONFIG_X86_PAE) ++ mcl->args[1] = new_val.pte_low; ++ mcl->args[2] = new_val.pte_high; ++#else ++ mcl->args[1] = new_val.pte_low; ++ mcl->args[2] = 0; ++#endif ++ mcl->args[MULTI_UVMFLAGS_INDEX] = flags; ++} ++ ++static inline void ++MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd, ++ void *uop, unsigned int count) ++{ ++ mcl->op = __HYPERVISOR_grant_table_op; ++ mcl->args[0] = cmd; ++ mcl->args[1] = (unsigned long)uop; ++ mcl->args[2] = count; ++} ++ ++static inline void ++MULTI_update_va_mapping_otherdomain( ++ multicall_entry_t *mcl, unsigned long va, ++ pte_t new_val, unsigned long flags, domid_t domid) ++{ ++ mcl->op = __HYPERVISOR_update_va_mapping_otherdomain; ++ mcl->args[0] = va; ++#if defined(CONFIG_X86_64) ++ mcl->args[1] = new_val.pte; ++#elif defined(CONFIG_X86_PAE) ++ mcl->args[1] = new_val.pte_low; ++ mcl->args[2] = new_val.pte_high; ++#else ++ mcl->args[1] = new_val.pte_low; ++ mcl->args[2] = 0; ++#endif ++ mcl->args[MULTI_UVMFLAGS_INDEX] = flags; ++ mcl->args[MULTI_UVMDOMID_INDEX] = domid; ++} ++ ++#endif /* __HYPERVISOR_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/io.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/io.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,369 @@ ++#ifndef _ASM_IO_H ++#define _ASM_IO_H ++ ++#include <linux/string.h> ++#include <linux/compiler.h> ++ ++/* ++ * This file contains the definitions for the x86 IO instructions ++ * inb/inw/inl/outb/outw/outl and the "string versions" of the same ++ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" ++ * versions of the single-IO instructions (inb_p/inw_p/..). ++ * ++ * This file is not meant to be obfuscating: it's just complicated ++ * to (a) handle it all in a way that makes gcc able to optimize it ++ * as well as possible and (b) trying to avoid writing the same thing ++ * over and over again with slight variations and possibly making a ++ * mistake somewhere. ++ */ ++ ++/* ++ * Thanks to James van Artsdalen for a better timing-fix than ++ * the two short jumps: using outb's to a nonexistent port seems ++ * to guarantee better timings even on fast machines. ++ * ++ * On the other hand, I'd like to be sure of a non-existent port: ++ * I feel a bit unsafe about using 0x80 (should be safe, though) ++ * ++ * Linus ++ */ ++ ++ /* ++ * Bit simplified and optimized by Jan Hubicka ++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999. ++ * ++ * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added, ++ * isa_read[wl] and isa_write[wl] fixed ++ * - Arnaldo Carvalho de Melo <acme@conectiva.com.br> ++ */ ++ ++#define IO_SPACE_LIMIT 0xffff ++ ++#define XQUAD_PORTIO_BASE 0xfe400000 ++#define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ ++ ++#ifdef __KERNEL__ ++ ++#include <asm-generic/iomap.h> ++ ++#include <linux/vmalloc.h> ++#include <asm/fixmap.h> ++ ++/* ++ * Convert a physical pointer to a virtual kernel pointer for /dev/mem ++ * access ++ */ ++#define xlate_dev_mem_ptr(p, sz) ioremap(p, sz) ++#define xlate_dev_mem_ptr_unmap(p) iounmap(p) ++ ++/* ++ * Convert a virtual cached pointer to an uncached pointer ++ */ ++#define xlate_dev_kmem_ptr(p) p ++ ++/** ++ * virt_to_phys - map virtual addresses to physical ++ * @address: address to remap ++ * ++ * The returned physical address is the physical (CPU) mapping for ++ * the memory address given. It is only valid to use this function on ++ * addresses directly mapped or allocated via kmalloc. ++ * ++ * This function does not give bus mappings for DMA transfers. In ++ * almost all conceivable cases a device driver should not be using ++ * this function ++ */ ++ ++static inline unsigned long virt_to_phys(volatile void * address) ++{ ++ return __pa(address); ++} ++ ++/** ++ * phys_to_virt - map physical address to virtual ++ * @address: address to remap ++ * ++ * The returned virtual address is a current CPU mapping for ++ * the memory address given. It is only valid to use this function on ++ * addresses that have a kernel mapping ++ * ++ * This function does not handle bus mappings for DMA transfers. In ++ * almost all conceivable cases a device driver should not be using ++ * this function ++ */ ++ ++static inline void * phys_to_virt(unsigned long address) ++{ ++ return __va(address); ++} ++ ++/* ++ * Change "struct page" to physical address. ++ */ ++#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) ++#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page))) ++#define page_to_bus(page) (phys_to_machine(page_to_pseudophys(page))) ++ ++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \ ++ (unsigned long) bio_offset((bio))) ++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \ ++ (unsigned long) (bv)->bv_offset) ++ ++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ ++ (((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \ ++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \ ++ bvec_to_pseudophys((vec2)))) ++ ++extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); ++ ++/** ++ * ioremap - map bus memory into CPU space ++ * @offset: bus address of the memory ++ * @size: size of the resource to map ++ * ++ * ioremap performs a platform specific sequence of operations to ++ * make bus memory CPU accessible via the readb/readw/readl/writeb/ ++ * writew/writel functions and the other mmio helpers. The returned ++ * address is not guaranteed to be usable directly as a virtual ++ * address. ++ */ ++ ++static inline void __iomem * ioremap(unsigned long offset, unsigned long size) ++{ ++ return __ioremap(offset, size, 0); ++} ++ ++extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size); ++extern void iounmap(volatile void __iomem *addr); ++ ++/* ++ * bt_ioremap() and bt_iounmap() are for temporary early boot-time ++ * mappings, before the real ioremap() is functional. ++ * A boot-time mapping is currently limited to at most 16 pages. ++ */ ++extern void *bt_ioremap(unsigned long offset, unsigned long size); ++extern void bt_iounmap(void *addr, unsigned long size); ++ ++/* Use early IO mappings for DMI because it's initialized early */ ++#define dmi_ioremap bt_ioremap ++#define dmi_iounmap bt_iounmap ++#define dmi_alloc alloc_bootmem ++ ++/* ++ * ISA I/O bus memory addresses are 1:1 with the physical address. ++ */ ++#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x ++#define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x ++ ++static inline void *isa_bus_to_virt(unsigned long address) ++{ ++ return (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + address); ++} ++ ++/* ++ * However PCI ones are not necessarily 1:1 and therefore these interfaces ++ * are forbidden in portable PCI drivers. ++ * ++ * Allow them on x86 for legacy drivers, though. ++ */ ++#define virt_to_bus(_x) phys_to_machine(__pa(_x)) ++#define bus_to_virt(_x) __va(machine_to_phys(_x)) ++ ++/* ++ * readX/writeX() are used to access memory mapped devices. On some ++ * architectures the memory mapped IO stuff needs to be accessed ++ * differently. On the x86 architecture, we just read/write the ++ * memory location directly. ++ */ ++ ++static inline unsigned char readb(const volatile void __iomem *addr) ++{ ++ return *(volatile unsigned char __force *) addr; ++} ++static inline unsigned short readw(const volatile void __iomem *addr) ++{ ++ return *(volatile unsigned short __force *) addr; ++} ++static inline unsigned int readl(const volatile void __iomem *addr) ++{ ++ return *(volatile unsigned int __force *) addr; ++} ++#define readb_relaxed(addr) readb(addr) ++#define readw_relaxed(addr) readw(addr) ++#define readl_relaxed(addr) readl(addr) ++#define __raw_readb readb ++#define __raw_readw readw ++#define __raw_readl readl ++ ++static inline void writeb(unsigned char b, volatile void __iomem *addr) ++{ ++ *(volatile unsigned char __force *) addr = b; ++} ++static inline void writew(unsigned short b, volatile void __iomem *addr) ++{ ++ *(volatile unsigned short __force *) addr = b; ++} ++static inline void writel(unsigned int b, volatile void __iomem *addr) ++{ ++ *(volatile unsigned int __force *) addr = b; ++} ++#define __raw_writeb writeb ++#define __raw_writew writew ++#define __raw_writel writel ++ ++#define mmiowb() ++ ++static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) ++{ ++ memset((void __force *) addr, val, count); ++} ++static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count) ++{ ++ __memcpy(dst, (void __force *) src, count); ++} ++static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count) ++{ ++ __memcpy((void __force *) dst, src, count); ++} ++ ++/* ++ * ISA space is 'always mapped' on a typical x86 system, no need to ++ * explicitly ioremap() it. The fact that the ISA IO space is mapped ++ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values ++ * are physical addresses. The following constant pointer can be ++ * used as the IO-area pointer (it can be iounmapped as well, so the ++ * analogy with PCI is quite large): ++ */ ++#define __ISA_IO_base ((char __iomem *)(fix_to_virt(FIX_ISAMAP_BEGIN))) ++ ++/* ++ * Again, i386 does not require mem IO specific function. ++ */ ++ ++#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d)) ++ ++/* ++ * Cache management ++ * ++ * This needed for two cases ++ * 1. Out of order aware processors ++ * 2. Accidentally out of order processors (PPro errata #51) ++ */ ++ ++#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE) ++ ++static inline void flush_write_buffers(void) ++{ ++ __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory"); ++} ++ ++#define dma_cache_inv(_start,_size) flush_write_buffers() ++#define dma_cache_wback(_start,_size) flush_write_buffers() ++#define dma_cache_wback_inv(_start,_size) flush_write_buffers() ++ ++#else ++ ++/* Nothing to do */ ++ ++#define dma_cache_inv(_start,_size) do { } while (0) ++#define dma_cache_wback(_start,_size) do { } while (0) ++#define dma_cache_wback_inv(_start,_size) do { } while (0) ++#define flush_write_buffers() ++ ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++#if defined(CONFIG_PARAVIRT) ++#include <asm/paravirt.h> ++#else ++ ++#define __SLOW_DOWN_IO "outb %%al,$0x80;" ++ ++static inline void slow_down_io(void) { ++ __asm__ __volatile__( ++ __SLOW_DOWN_IO ++#ifdef REALLY_SLOW_IO ++ __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO ++#endif ++ : : ); ++} ++ ++#endif ++ ++#ifdef CONFIG_X86_NUMAQ ++extern void *xquad_portio; /* Where the IO area was mapped */ ++#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) ++#define __BUILDIO(bwl,bw,type) \ ++static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \ ++ if (xquad_portio) \ ++ write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \ ++ else \ ++ out##bwl##_local(value, port); \ ++} \ ++static inline void out##bwl(unsigned type value, int port) { \ ++ out##bwl##_quad(value, port, 0); \ ++} \ ++static inline unsigned type in##bwl##_quad(int port, int quad) { \ ++ if (xquad_portio) \ ++ return read##bwl(XQUAD_PORT_ADDR(port, quad)); \ ++ else \ ++ return in##bwl##_local(port); \ ++} \ ++static inline unsigned type in##bwl(int port) { \ ++ return in##bwl##_quad(port, 0); \ ++} ++#else ++#define __BUILDIO(bwl,bw,type) \ ++static inline void out##bwl(unsigned type value, int port) { \ ++ out##bwl##_local(value, port); \ ++} \ ++static inline unsigned type in##bwl(int port) { \ ++ return in##bwl##_local(port); \ ++} ++#endif ++ ++ ++#define BUILDIO(bwl,bw,type) \ ++static inline void out##bwl##_local(unsigned type value, int port) { \ ++ __asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \ ++} \ ++static inline unsigned type in##bwl##_local(int port) { \ ++ unsigned type value; \ ++ __asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \ ++ return value; \ ++} \ ++static inline void out##bwl##_local_p(unsigned type value, int port) { \ ++ out##bwl##_local(value, port); \ ++ slow_down_io(); \ ++} \ ++static inline unsigned type in##bwl##_local_p(int port) { \ ++ unsigned type value = in##bwl##_local(port); \ ++ slow_down_io(); \ ++ return value; \ ++} \ ++__BUILDIO(bwl,bw,type) \ ++static inline void out##bwl##_p(unsigned type value, int port) { \ ++ out##bwl(value, port); \ ++ slow_down_io(); \ ++} \ ++static inline unsigned type in##bwl##_p(int port) { \ ++ unsigned type value = in##bwl(port); \ ++ slow_down_io(); \ ++ return value; \ ++} \ ++static inline void outs##bwl(int port, const void *addr, unsigned long count) { \ ++ __asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \ ++} \ ++static inline void ins##bwl(int port, void *addr, unsigned long count) { \ ++ __asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \ ++} ++ ++BUILDIO(b,b,char) ++BUILDIO(w,w,short) ++BUILDIO(l,,int) ++ ++/* We will be supplying our own /dev/mem implementation */ ++#define ARCH_HAS_DEV_MEM ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/irqflags.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/irqflags.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,129 @@ ++/* ++ * include/asm-i386/irqflags.h ++ * ++ * IRQ flags handling ++ * ++ * This file gets included from lowlevel asm headers too, to provide ++ * wrapped versions of the local_irq_*() APIs, based on the ++ * raw_local_irq_*() functions from the lowlevel headers. ++ */ ++#ifndef _ASM_IRQFLAGS_H ++#define _ASM_IRQFLAGS_H ++ ++#ifdef CONFIG_PARAVIRT ++#include <asm/paravirt.h> ++#else ++#ifndef __ASSEMBLY__ ++ ++#define __raw_local_save_flags() (current_vcpu_info()->evtchn_upcall_mask) ++ ++#define raw_local_save_flags(flags) \ ++ do { (flags) = __raw_local_save_flags(); } while (0) ++ ++#define raw_local_irq_restore(x) \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \ ++ barrier(); /* unmask then check (avoid races) */ \ ++ if (unlikely(_vcpu->evtchn_upcall_pending)) \ ++ force_evtchn_callback(); \ ++ } \ ++} while (0) ++ ++#define raw_local_irq_disable() \ ++do { \ ++ current_vcpu_info()->evtchn_upcall_mask = 1; \ ++ barrier(); \ ++} while (0) ++ ++#define raw_local_irq_enable() \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ _vcpu->evtchn_upcall_mask = 0; \ ++ barrier(); /* unmask then check (avoid races) */ \ ++ if (unlikely(_vcpu->evtchn_upcall_pending)) \ ++ force_evtchn_callback(); \ ++} while (0) ++ ++/* ++ * Used in the idle loop; sti takes one instruction cycle ++ * to complete: ++ */ ++void raw_safe_halt(void); ++ ++/* ++ * Used when interrupts are already enabled or to ++ * shutdown the processor: ++ */ ++void halt(void); ++ ++/* ++ * For spinlocks, etc: ++ */ ++#define __raw_local_irq_save() \ ++({ \ ++ unsigned long flags = __raw_local_save_flags(); \ ++ \ ++ raw_local_irq_disable(); \ ++ \ ++ flags; \ ++}) ++ ++#else ++#define DISABLE_INTERRUPTS(clobbers) GET_VCPU_INFO ; \ ++ __DISABLE_INTERRUPTS ++#define ENABLE_INTERRUPTS(clobbers) GET_VCPU_INFO ; \ ++ __ENABLE_INTERRUPTS ++#define ENABLE_INTERRUPTS_SYSEXIT NET_DONE_YET ++#define INTERRUPT_RETURN iret ++#define GET_CR0_INTO_EAX NOT_DONE_YET ++#endif /* __ASSEMBLY__ */ ++#endif /* CONFIG_PARAVIRT */ ++ ++#ifndef __ASSEMBLY__ ++ ++#define raw_local_irq_save(flags) \ ++ do { (flags) = __raw_local_irq_save(); } while (0) ++ ++static inline int raw_irqs_disabled_flags(unsigned long flags) ++{ ++ return flags != 0; ++} ++ ++int raw_irqs_disabled(void); ++#endif /* __ASSEMBLY__ */ ++ ++/* ++ * Do the CPU's IRQ-state tracing from assembly code. We call a ++ * C function, so save all the C-clobbered registers: ++ */ ++#ifdef CONFIG_TRACE_IRQFLAGS ++ ++# define TRACE_IRQS_ON \ ++ pushl %eax; \ ++ pushl %ecx; \ ++ pushl %edx; \ ++ call trace_hardirqs_on; \ ++ popl %edx; \ ++ popl %ecx; \ ++ popl %eax; ++ ++# define TRACE_IRQS_OFF \ ++ pushl %eax; \ ++ pushl %ecx; \ ++ pushl %edx; \ ++ call trace_hardirqs_off; \ ++ popl %edx; \ ++ popl %ecx; \ ++ popl %eax; ++ ++#else ++# define TRACE_IRQS_ON ++# define TRACE_IRQS_OFF ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/maddr.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/maddr.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,193 @@ ++#ifndef _I386_MADDR_H ++#define _I386_MADDR_H ++ ++#include <xen/features.h> ++#include <xen/interface/xen.h> ++ ++/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/ ++#define INVALID_P2M_ENTRY (~0UL) ++#define FOREIGN_FRAME_BIT (1UL<<31) ++#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) ++ ++/* Definitions for machine and pseudophysical addresses. */ ++#ifdef CONFIG_X86_PAE ++typedef unsigned long long paddr_t; ++typedef unsigned long long maddr_t; ++#else ++typedef unsigned long paddr_t; ++typedef unsigned long maddr_t; ++#endif ++ ++#ifdef CONFIG_XEN ++ ++extern unsigned long *phys_to_machine_mapping; ++extern unsigned long max_mapnr; ++ ++#undef machine_to_phys_mapping ++extern unsigned long *machine_to_phys_mapping; ++extern unsigned int machine_to_phys_order; ++ ++static inline unsigned long pfn_to_mfn(unsigned long pfn) ++{ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return pfn; ++ BUG_ON(max_mapnr && pfn >= max_mapnr); ++ return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; ++} ++ ++static inline int phys_to_machine_mapping_valid(unsigned long pfn) ++{ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return 1; ++ BUG_ON(max_mapnr && pfn >= max_mapnr); ++ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); ++} ++ ++static inline unsigned long mfn_to_pfn(unsigned long mfn) ++{ ++ unsigned long pfn; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return mfn; ++ ++ if (unlikely((mfn >> machine_to_phys_order) != 0)) ++ return max_mapnr; ++ ++ /* The array access can fail (e.g., device space beyond end of RAM). */ ++ asm ( ++ "1: movl %1,%0\n" ++ "2:\n" ++ ".section .fixup,\"ax\"\n" ++ "3: movl %2,%0\n" ++ " jmp 2b\n" ++ ".previous\n" ++ ".section __ex_table,\"a\"\n" ++ " .align 4\n" ++ " .long 1b,3b\n" ++ ".previous" ++ : "=r" (pfn) ++ : "m" (machine_to_phys_mapping[mfn]), "m" (max_mapnr) ); ++ ++ return pfn; ++} ++ ++/* ++ * We detect special mappings in one of two ways: ++ * 1. If the MFN is an I/O page then Xen will set the m2p entry ++ * to be outside our maximum possible pseudophys range. ++ * 2. If the MFN belongs to a different domain then we will certainly ++ * not have MFN in our p2m table. Conversely, if the page is ours, ++ * then we'll have p2m(m2p(MFN))==MFN. ++ * If we detect a special mapping then it doesn't have a 'struct page'. ++ * We force !pfn_valid() by returning an out-of-range pointer. ++ * ++ * NB. These checks require that, for any MFN that is not in our reservation, ++ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if ++ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN. ++ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety. ++ * ++ * NB2. When deliberately mapping foreign pages into the p2m table, you *must* ++ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we ++ * require. In all the cases we care about, the FOREIGN_FRAME bit is ++ * masked (e.g., pfn_to_mfn()) so behaviour there is correct. ++ */ ++static inline unsigned long mfn_to_local_pfn(unsigned long mfn) ++{ ++ unsigned long pfn = mfn_to_pfn(mfn); ++ if ((pfn < max_mapnr) ++ && !xen_feature(XENFEAT_auto_translated_physmap) ++ && (phys_to_machine_mapping[pfn] != mfn)) ++ return max_mapnr; /* force !pfn_valid() */ ++ return pfn; ++} ++ ++static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) ++{ ++ BUG_ON(max_mapnr && pfn >= max_mapnr); ++ if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); ++ return; ++ } ++ phys_to_machine_mapping[pfn] = mfn; ++} ++ ++static inline maddr_t phys_to_machine(paddr_t phys) ++{ ++ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT); ++ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK); ++ return machine; ++} ++ ++static inline paddr_t machine_to_phys(maddr_t machine) ++{ ++ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT); ++ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK); ++ return phys; ++} ++ ++#ifdef CONFIG_X86_PAE ++static inline paddr_t pte_phys_to_machine(paddr_t phys) ++{ ++ /* ++ * In PAE mode, the NX bit needs to be dealt with in the value ++ * passed to pfn_to_mfn(). On x86_64, we need to mask it off, ++ * but for i386 the conversion to ulong for the argument will ++ * clip it off. ++ */ ++ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT); ++ machine = (machine << PAGE_SHIFT) | (phys & ~PHYSICAL_PAGE_MASK); ++ return machine; ++} ++ ++static inline paddr_t pte_machine_to_phys(maddr_t machine) ++{ ++ /* ++ * In PAE mode, the NX bit needs to be dealt with in the value ++ * passed to mfn_to_pfn(). On x86_64, we need to mask it off, ++ * but for i386 the conversion to ulong for the argument will ++ * clip it off. ++ */ ++ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT); ++ phys = (phys << PAGE_SHIFT) | (machine & ~PHYSICAL_PAGE_MASK); ++ return phys; ++} ++#endif ++ ++#ifdef CONFIG_X86_PAE ++static inline pte_t pfn_pte_ma(unsigned long page_nr, pgprot_t pgprot) ++{ ++ pte_t pte; ++ ++ pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \ ++ (pgprot_val(pgprot) >> 32); ++ pte.pte_high &= (__supported_pte_mask >> 32); ++ pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \ ++ __supported_pte_mask; ++ return pte; ++} ++#else ++#define pfn_pte_ma(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) ++#endif ++ ++#define __pte_ma(x) ((pte_t) { (x) } ) ++ ++#else /* !CONFIG_XEN */ ++ ++#define pfn_to_mfn(pfn) (pfn) ++#define mfn_to_pfn(mfn) (mfn) ++#define mfn_to_local_pfn(mfn) (mfn) ++#define set_phys_to_machine(pfn, mfn) ((void)0) ++#define phys_to_machine_mapping_valid(pfn) (1) ++#define phys_to_machine(phys) ((maddr_t)(phys)) ++#define machine_to_phys(mach) ((paddr_t)(mach)) ++#define pfn_pte_ma(pfn, prot) pfn_pte(pfn, prot) ++#define __pte_ma(x) __pte(x) ++ ++#endif /* !CONFIG_XEN */ ++ ++/* VIRT <-> MACHINE conversion */ ++#define virt_to_machine(v) (phys_to_machine(__pa(v))) ++#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT)) ++#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) ++ ++#endif /* _I386_MADDR_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/mmu_context.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/mmu_context.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,107 @@ ++#ifndef __I386_SCHED_H ++#define __I386_SCHED_H ++ ++#include <asm/desc.h> ++#include <asm/atomic.h> ++#include <asm/pgalloc.h> ++#include <asm/tlbflush.h> ++ ++/* ++ * Used for LDT copy/destruction. ++ */ ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm); ++void destroy_context(struct mm_struct *mm); ++ ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++#if 0 /* XEN: no lazy tlb */ ++ unsigned cpu = smp_processor_id(); ++ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) ++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY; ++#endif ++} ++ ++#define prepare_arch_switch(next) __prepare_arch_switch() ++ ++static inline void __prepare_arch_switch(void) ++{ ++ /* ++ * Save away %fs and %gs. No need to save %es and %ds, as those ++ * are always kernel segments while inside the kernel. Must ++ * happen before reload of cr3/ldt (i.e., not in __switch_to). ++ */ ++ asm volatile ( "mov %%fs,%0" ++ : "=m" (current->thread.fs)); ++ asm volatile ( "movl %0,%%fs" ++ : : "r" (0) ); ++} ++ ++extern void mm_pin(struct mm_struct *mm); ++extern void mm_unpin(struct mm_struct *mm); ++void mm_pin_all(void); ++ ++static inline void switch_mm(struct mm_struct *prev, ++ struct mm_struct *next, ++ struct task_struct *tsk) ++{ ++ int cpu = smp_processor_id(); ++ struct mmuext_op _op[2], *op = _op; ++ ++ if (likely(prev != next)) { ++ BUG_ON(!xen_feature(XENFEAT_writable_page_tables) && ++ !test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)); ++ ++ /* stop flush ipis for the previous mm */ ++ cpu_clear(cpu, prev->cpu_vm_mask); ++#if 0 /* XEN: no lazy tlb */ ++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; ++ per_cpu(cpu_tlbstate, cpu).active_mm = next; ++#endif ++ cpu_set(cpu, next->cpu_vm_mask); ++ ++ /* Re-load page tables: load_cr3(next->pgd) */ ++ op->cmd = MMUEXT_NEW_BASEPTR; ++ op->arg1.mfn = pfn_to_mfn(__pa(next->pgd) >> PAGE_SHIFT); ++ op++; ++ ++ /* ++ * load the LDT, if the LDT is different: ++ */ ++ if (unlikely(prev->context.ldt != next->context.ldt)) { ++ /* load_LDT_nolock(&next->context) */ ++ op->cmd = MMUEXT_SET_LDT; ++ op->arg1.linear_addr = (unsigned long)next->context.ldt; ++ op->arg2.nr_ents = next->context.size; ++ op++; ++ } ++ ++ BUG_ON(HYPERVISOR_mmuext_op(_op, op-_op, NULL, DOMID_SELF)); ++ } ++#if 0 /* XEN: no lazy tlb */ ++ else { ++ per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; ++ BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); ++ ++ if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { ++ /* We were in lazy tlb mode and leave_mm disabled ++ * tlb flush IPI delivery. We must reload %cr3. ++ */ ++ load_cr3(next->pgd); ++ load_LDT_nolock(&next->context); ++ } ++ } ++#endif ++} ++ ++#define deactivate_mm(tsk, mm) \ ++ asm("movl %0,%%fs": :"r" (0)); ++ ++static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) ++{ ++ if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)) ++ mm_pin(next); ++ switch_mm(prev, next, NULL); ++} ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/page.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/page.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,233 @@ ++#ifndef _I386_PAGE_H ++#define _I386_PAGE_H ++ ++/* PAGE_SHIFT determines the page size */ ++#define PAGE_SHIFT 12 ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++#ifdef CONFIG_X86_PAE ++#define __PHYSICAL_MASK_SHIFT 40 ++#define __PHYSICAL_MASK ((1ULL << __PHYSICAL_MASK_SHIFT) - 1) ++#define PHYSICAL_PAGE_MASK (~((1ULL << PAGE_SHIFT) - 1) & __PHYSICAL_MASK) ++#else ++#define __PHYSICAL_MASK_SHIFT 32 ++#define __PHYSICAL_MASK (~0UL) ++#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK) ++#endif ++ ++#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) ++#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Need to repeat this here in order to not include pgtable.h (which in turn ++ * depends on definitions made here), but to be able to use the symbolic ++ * below. The preprocessor will warn if the two definitions aren't identical. ++ */ ++#define _PAGE_PRESENT 0x001 ++ ++#ifndef __ASSEMBLY__ ++ ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/bug.h> ++#include <xen/interface/xen.h> ++#include <xen/features.h> ++ ++#define arch_free_page(_page,_order) \ ++({ int foreign = PageForeign(_page); \ ++ if (foreign) \ ++ PageForeignDestructor(_page); \ ++ foreign; \ ++}) ++#define HAVE_ARCH_FREE_PAGE ++ ++#ifdef CONFIG_X86_USE_3DNOW ++ ++#include <asm/mmx.h> ++ ++#define clear_page(page) mmx_clear_page((void *)(page)) ++#define copy_page(to,from) mmx_copy_page(to,from) ++ ++#else ++ ++#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr) ++#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE ++ ++/* ++ * On older X86 processors it's not a win to use MMX here it seems. ++ * Maybe the K6-III ? ++ */ ++ ++#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) ++#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) ++ ++#endif ++ ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++ ++/* ++ * These are used to make use of C type-checking.. ++ */ ++extern int nx_enabled; ++#ifdef CONFIG_X86_PAE ++extern unsigned long long __supported_pte_mask; ++typedef struct { unsigned long pte_low, pte_high; } pte_t; ++typedef struct { unsigned long long pmd; } pmd_t; ++typedef struct { unsigned long long pgd; } pgd_t; ++typedef struct { unsigned long long pgprot; } pgprot_t; ++#define pgprot_val(x) ((x).pgprot) ++#include <asm/maddr.h> ++#define __pte(x) ({ unsigned long long _x = (x); \ ++ if (_x & _PAGE_PRESENT) _x = pte_phys_to_machine(_x); \ ++ ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); }) ++#define __pgd(x) ({ unsigned long long _x = (x); \ ++ (pgd_t) {((_x) & _PAGE_PRESENT) ? pte_phys_to_machine(_x) : (_x)}; }) ++#define __pmd(x) ({ unsigned long long _x = (x); \ ++ (pmd_t) {((_x) & _PAGE_PRESENT) ? pte_phys_to_machine(_x) : (_x)}; }) ++static inline unsigned long long pte_val_ma(pte_t x) ++{ ++ return ((unsigned long long)x.pte_high << 32) | x.pte_low; ++} ++static inline unsigned long long pte_val(pte_t x) ++{ ++ unsigned long long ret = pte_val_ma(x); ++ if (x.pte_low & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++ return ret; ++} ++static inline unsigned long long pmd_val(pmd_t x) ++{ ++ unsigned long long ret = x.pmd; ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret) ret = pte_machine_to_phys(ret) | _PAGE_PRESENT; ++#else ++ if (ret & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++#endif ++ return ret; ++} ++static inline unsigned long long pgd_val(pgd_t x) ++{ ++ unsigned long long ret = x.pgd; ++ if (ret & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++ return ret; ++} ++#define HPAGE_SHIFT 21 ++#include <asm-generic/pgtable-nopud.h> ++#else ++typedef struct { unsigned long pte_low; } pte_t; ++typedef struct { unsigned long pgd; } pgd_t; ++typedef struct { unsigned long pgprot; } pgprot_t; ++#define pgprot_val(x) ((x).pgprot) ++#include <asm/maddr.h> ++#define boot_pte_t pte_t /* or would you rather have a typedef */ ++#define pte_val(x) (((x).pte_low & _PAGE_PRESENT) ? \ ++ machine_to_phys((x).pte_low) : \ ++ (x).pte_low) ++#define pte_val_ma(x) ((x).pte_low) ++#define __pte(x) ({ unsigned long _x = (x); \ ++ (pte_t) {((_x) & _PAGE_PRESENT) ? phys_to_machine(_x) : (_x)}; }) ++#define __pgd(x) ({ unsigned long _x = (x); \ ++ (pgd_t) {((_x) & _PAGE_PRESENT) ? phys_to_machine(_x) : (_x)}; }) ++static inline unsigned long pgd_val(pgd_t x) ++{ ++ unsigned long ret = x.pgd; ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret) ret = machine_to_phys(ret) | _PAGE_PRESENT; ++#else ++ if (ret & _PAGE_PRESENT) ret = machine_to_phys(ret); ++#endif ++ return ret; ++} ++#define HPAGE_SHIFT 22 ++#include <asm-generic/pgtable-nopmd.h> ++#endif ++#define PTE_MASK PHYSICAL_PAGE_MASK ++ ++#ifdef CONFIG_HUGETLB_PAGE ++#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) ++#define HPAGE_MASK (~(HPAGE_SIZE - 1)) ++#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) ++#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA ++#endif ++ ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* to align the pointer to the (next) page boundary */ ++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) ++ ++/* ++ * This handles the memory map.. We could make this a config ++ * option, but too many people screw it up, and too few need ++ * it. ++ * ++ * A __PAGE_OFFSET of 0xC0000000 means that the kernel has ++ * a virtual address space of one gigabyte, which limits the ++ * amount of physical memory you can use to about 950MB. ++ * ++ * If you want more physical memory than this then see the CONFIG_HIGHMEM4G ++ * and CONFIG_HIGHMEM64G options in the kernel configuration. ++ */ ++ ++#ifndef __ASSEMBLY__ ++ ++struct vm_area_struct; ++ ++/* ++ * This much address space is reserved for vmalloc() and iomap() ++ * as well as fixmap mappings. ++ */ ++extern unsigned int __VMALLOC_RESERVE; ++ ++extern int sysctl_legacy_va_layout; ++ ++extern int page_is_ram(unsigned long pagenr); ++ ++#endif /* __ASSEMBLY__ */ ++ ++#ifdef __ASSEMBLY__ ++#define __PAGE_OFFSET CONFIG_PAGE_OFFSET ++#else ++#define __PAGE_OFFSET ((unsigned long)CONFIG_PAGE_OFFSET) ++#endif ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++#undef LOAD_OFFSET ++#define LOAD_OFFSET 0 ++#endif ++ ++#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) ++#define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) ++#define MAXMEM (__FIXADDR_TOP-__PAGE_OFFSET-__VMALLOC_RESERVE) ++#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) ++/* __pa_symbol should be used for C visible symbols. ++ This seems to be the official gcc blessed way to do such arithmetic. */ ++#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) ++#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) ++#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) ++#ifdef CONFIG_FLATMEM ++#define pfn_valid(pfn) ((pfn) < max_mapnr) ++#endif /* CONFIG_FLATMEM */ ++#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) ++ ++#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) ++ ++#define VM_DATA_DEFAULT_FLAGS \ ++ (VM_READ | VM_WRITE | \ ++ ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ ++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) ++ ++#include <asm-generic/memory_model.h> ++#include <asm-generic/page.h> ++ ++#ifndef CONFIG_COMPAT_VDSO ++#define __HAVE_ARCH_GATE_AREA 1 ++#endif ++#endif /* __KERNEL__ */ ++ ++#endif /* _I386_PAGE_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/pgtable-2level.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/pgtable-2level.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,110 @@ ++#ifndef _I386_PGTABLE_2LEVEL_H ++#define _I386_PGTABLE_2LEVEL_H ++ ++#define pte_ERROR(e) \ ++ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low) ++#define pgd_ERROR(e) \ ++ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) ++ ++/* ++ * Certain architectures need to do special things when PTEs ++ * within a page table are directly modified. Thus, the following ++ * hook is made available. ++ */ ++#ifndef CONFIG_PARAVIRT ++#define set_pte(pteptr, pteval) (*(pteptr) = pteval) ++ ++#define set_pte_at(_mm,addr,ptep,pteval) do { \ ++ if (((_mm) != current->mm && (_mm) != &init_mm) || \ ++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \ ++ set_pte((ptep), (pteval)); \ ++} while (0) ++#define set_pmd(pmdptr, pmdval) xen_l2_entry_update((pmdptr), (pmdval)) ++#endif ++ ++#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval) ++#define set_pte_present(mm,addr,ptep,pteval) set_pte_at(mm,addr,ptep,pteval) ++ ++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) ++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++ ++#define pte_none(x) (!(x).pte_low) ++ ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR ++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_none(pte)) { ++ if (mm != &init_mm) ++ pte = __pte_ma(xchg(&ptep->pte_low, 0)); ++ else ++ HYPERVISOR_update_va_mapping(addr, __pte(0), 0); ++ } ++ return pte; ++} ++ ++#define __HAVE_ARCH_PTEP_CLEAR_FLUSH ++#define ptep_clear_flush(vma, addr, ptep) \ ++({ \ ++ pte_t *__ptep = (ptep); \ ++ pte_t __res = *__ptep; \ ++ if (!pte_none(__res) && \ ++ ((vma)->vm_mm != current->mm || \ ++ HYPERVISOR_update_va_mapping(addr, __pte(0), \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI))) { \ ++ __ptep->pte_low = 0; \ ++ flush_tlb_page(vma, addr); \ ++ } \ ++ __res; \ ++}) ++ ++#define __pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT) ++#define pte_mfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \ ++ __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte))) ++#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \ ++ mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte)) ++ ++#define pte_page(x) pfn_to_page(pte_pfn(x)) ++ ++#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) ++#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) ++ ++/* ++ * All present user pages are user-executable: ++ */ ++static inline int pte_exec(pte_t pte) ++{ ++ return pte_user(pte); ++} ++ ++/* ++ * All present pages are kernel-executable: ++ */ ++static inline int pte_exec_kernel(pte_t pte) ++{ ++ return 1; ++} ++ ++/* ++ * Bits 0, 6 and 7 are taken, split up the 29 bits of offset ++ * into this range: ++ */ ++#define PTE_FILE_MAX_BITS 29 ++ ++#define pte_to_pgoff(pte) \ ++ ((((pte).pte_low >> 1) & 0x1f ) + (((pte).pte_low >> 8) << 5 )) ++ ++#define pgoff_to_pte(off) \ ++ ((pte_t) { (((off) & 0x1f) << 1) + (((off) >> 5) << 8) + _PAGE_FILE }) ++ ++/* Encode and de-code a swap entry */ ++#define __swp_type(x) (((x).val >> 1) & 0x1f) ++#define __swp_offset(x) ((x).val >> 8) ++#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low }) ++#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++void vmalloc_sync_all(void); ++ ++#endif /* _I386_PGTABLE_2LEVEL_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/pgtable-3level.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/pgtable-3level.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,216 @@ ++#ifndef _I386_PGTABLE_3LEVEL_H ++#define _I386_PGTABLE_3LEVEL_H ++ ++/* ++ * Intel Physical Address Extension (PAE) Mode - three-level page ++ * tables on PPro+ CPUs. ++ * ++ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com> ++ */ ++ ++#define pte_ERROR(e) \ ++ printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, &(e), (e).pte_high, (e).pte_low) ++#define pmd_ERROR(e) \ ++ printk("%s:%d: bad pmd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pmd_val(e)) ++#define pgd_ERROR(e) \ ++ printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) ++ ++#define pud_none(pud) 0 ++#define pud_bad(pud) 0 ++#define pud_present(pud) 1 ++ ++/* ++ * Is the pte executable? ++ */ ++static inline int pte_x(pte_t pte) ++{ ++ return !(pte_val(pte) & _PAGE_NX); ++} ++ ++/* ++ * All present user-pages with !NX bit are user-executable: ++ */ ++static inline int pte_exec(pte_t pte) ++{ ++ return pte_user(pte) && pte_x(pte); ++} ++/* ++ * All present pages with !NX bit are kernel-executable: ++ */ ++static inline int pte_exec_kernel(pte_t pte) ++{ ++ return pte_x(pte); ++} ++ ++#ifndef CONFIG_PARAVIRT ++/* Rules for using set_pte: the pte being assigned *must* be ++ * either not present or in a state where the hardware will ++ * not attempt to update the pte. In places where this is ++ * not possible, use pte_get_and_clear to obtain the old pte ++ * value and then use set_pte to update it. -ben ++ */ ++#define __HAVE_ARCH_SET_PTE_ATOMIC ++ ++static inline void set_pte(pte_t *ptep, pte_t pte) ++{ ++ ptep->pte_high = pte.pte_high; ++ smp_wmb(); ++ ptep->pte_low = pte.pte_low; ++} ++#define set_pte_atomic(pteptr,pteval) \ ++ set_64bit((unsigned long long *)(pteptr),pte_val_ma(pteval)) ++ ++/* ++ * Since this is only called on user PTEs, and the page fault handler ++ * must handle the already racy situation of simultaneous page faults, ++ * we are justified in merely clearing the PTE present bit, followed ++ * by a set. The ordering here is important. ++ */ ++static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) ++{ ++ ptep->pte_low = 0; ++ smp_wmb(); ++ ptep->pte_high = pte.pte_high; ++ smp_wmb(); ++ ptep->pte_low = pte.pte_low; ++} ++ ++#define set_pte_at(_mm,addr,ptep,pteval) do { \ ++ if (((_mm) != current->mm && (_mm) != &init_mm) || \ ++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \ ++ set_pte((ptep), (pteval)); \ ++} while (0) ++ ++#define set_pmd(pmdptr,pmdval) \ ++ xen_l2_entry_update((pmdptr), (pmdval)) ++#define set_pud(pudptr,pudval) \ ++ xen_l3_entry_update((pudptr), (pudval)) ++ ++#endif ++ ++/* ++ * Pentium-II erratum A13: in PAE mode we explicitly have to flush ++ * the TLB via cr3 if the top-level pgd is changed... ++ * We do not let the generic code free and clear pgd entries due to ++ * this erratum. ++ */ ++static inline void pud_clear (pud_t * pud) { } ++ ++#define pud_page(pud) \ ++((struct page *) __va(pud_val(pud) & PAGE_MASK)) ++ ++#define pud_page_vaddr(pud) \ ++((unsigned long) __va(pud_val(pud) & PAGE_MASK)) ++ ++ ++/* Find an entry in the second-level page table.. */ ++#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \ ++ pmd_index(address)) ++ ++static inline int pte_none(pte_t pte) ++{ ++ return !(pte.pte_low | pte.pte_high); ++} ++ ++/* ++ * For PTEs and PDEs, we must clear the P-bit first when clearing a page table ++ * entry, so clear the bottom half first and enforce ordering with a compiler ++ * barrier. ++ */ ++static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ if ((mm != current->mm && mm != &init_mm) ++ || HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { ++ ptep->pte_low = 0; ++ smp_wmb(); ++ ptep->pte_high = 0; ++ } ++} ++ ++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++ ++static inline pte_t raw_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_none(pte)) { ++ if (mm != &init_mm) { ++ uint64_t val = pte_val_ma(pte); ++ if (__cmpxchg64(ptep, val, 0) != val) { ++ /* xchg acts as a barrier before the setting of the high bits */ ++ pte.pte_low = xchg(&ptep->pte_low, 0); ++ pte.pte_high = ptep->pte_high; ++ ptep->pte_high = 0; ++ } ++ } else ++ HYPERVISOR_update_va_mapping(addr, __pte(0), 0); ++ } ++ return pte; ++} ++ ++#define __HAVE_ARCH_PTEP_CLEAR_FLUSH ++#define ptep_clear_flush(vma, addr, ptep) \ ++({ \ ++ pte_t *__ptep = (ptep); \ ++ pte_t __res = *__ptep; \ ++ if (!pte_none(__res) && \ ++ ((vma)->vm_mm != current->mm || \ ++ HYPERVISOR_update_va_mapping(addr, __pte(0), \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI))) { \ ++ __ptep->pte_low = 0; \ ++ smp_wmb(); \ ++ __ptep->pte_high = 0; \ ++ flush_tlb_page(vma, addr); \ ++ } \ ++ __res; \ ++}) ++ ++#define __HAVE_ARCH_PTE_SAME ++static inline int pte_same(pte_t a, pte_t b) ++{ ++ return a.pte_low == b.pte_low && a.pte_high == b.pte_high; ++} ++ ++#define pte_page(x) pfn_to_page(pte_pfn(x)) ++ ++#define __pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) | \ ++ ((_pte).pte_high << (32-PAGE_SHIFT))) ++#define pte_mfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \ ++ __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte))) ++#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \ ++ mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte)) ++ ++extern unsigned long long __supported_pte_mask; ++ ++static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) ++{ ++ return __pte((((unsigned long long)page_nr << PAGE_SHIFT) | ++ pgprot_val(pgprot)) & __supported_pte_mask); ++} ++ ++static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) ++{ ++ return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | ++ pgprot_val(pgprot)) & __supported_pte_mask); ++} ++ ++/* ++ * Bits 0, 6 and 7 are taken in the low part of the pte, ++ * put the 32 bits of offset into the high part. ++ */ ++#define pte_to_pgoff(pte) ((pte).pte_high) ++#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) }) ++#define PTE_FILE_MAX_BITS 32 ++ ++/* Encode and de-code a swap entry */ ++#define __swp_type(x) (((x).val) & 0x1f) ++#define __swp_offset(x) ((x).val >> 5) ++#define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) << 5}) ++#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high }) ++#define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val }) ++ ++#define __pmd_free_tlb(tlb, x) do { } while (0) ++ ++void vmalloc_sync_all(void); ++ ++#endif /* _I386_PGTABLE_3LEVEL_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/pgtable.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/pgtable.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,568 @@ ++#ifndef _I386_PGTABLE_H ++#define _I386_PGTABLE_H ++ ++#include <asm/hypervisor.h> ++ ++/* ++ * The Linux memory management assumes a three-level page table setup. On ++ * the i386, we use that, but "fold" the mid level into the top-level page ++ * table, so that we physically have the same two-level page table as the ++ * i386 mmu expects. ++ * ++ * This file contains the functions and defines necessary to modify and use ++ * the i386 page table tree. ++ */ ++#ifndef __ASSEMBLY__ ++#include <asm/processor.h> ++#include <asm/fixmap.h> ++#include <linux/threads.h> ++#include <asm/paravirt.h> ++ ++#ifndef _I386_BITOPS_H ++#include <asm/bitops.h> ++#endif ++ ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++ ++/* Is this pagetable pinned? */ ++#define PG_pinned PG_arch_1 ++ ++struct mm_struct; ++struct vm_area_struct; ++ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) ++extern unsigned long empty_zero_page[1024]; ++extern pgd_t *swapper_pg_dir; ++extern struct kmem_cache *pgd_cache; ++extern struct kmem_cache *pmd_cache; ++extern spinlock_t pgd_lock; ++extern struct page *pgd_list; ++ ++void pmd_ctor(void *, struct kmem_cache *, unsigned long); ++void pgd_ctor(void *, struct kmem_cache *, unsigned long); ++void pgd_dtor(void *, struct kmem_cache *, unsigned long); ++void pgtable_cache_init(void); ++void paging_init(void); ++ ++/* ++ * The Linux x86 paging architecture is 'compile-time dual-mode', it ++ * implements both the traditional 2-level x86 page tables and the ++ * newer 3-level PAE-mode page tables. ++ */ ++#ifdef CONFIG_X86_PAE ++# include <asm/pgtable-3level-defs.h> ++# define PMD_SIZE (1UL << PMD_SHIFT) ++# define PMD_MASK (~(PMD_SIZE-1)) ++#else ++# include <asm/pgtable-2level-defs.h> ++#endif ++ ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE-1)) ++ ++#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) ++#define FIRST_USER_ADDRESS 0 ++ ++#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) ++#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) ++ ++#define TWOLEVEL_PGDIR_SHIFT 22 ++#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT) ++#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS) ++ ++/* Just any arbitrary offset to the start of the vmalloc VM area: the ++ * current 8MB value just means that there will be a 8MB "hole" after the ++ * physical memory until the kernel virtual memory starts. That means that ++ * any out-of-bounds memory accesses will hopefully be caught. ++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced ++ * area for the same reason. ;) ++ */ ++#define VMALLOC_OFFSET (8*1024*1024) ++#define VMALLOC_START (((unsigned long) high_memory + vmalloc_earlyreserve + \ ++ 2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1)) ++#ifdef CONFIG_HIGHMEM ++# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) ++#else ++# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) ++#endif ++ ++/* ++ * _PAGE_PSE set in the page directory entry just means that ++ * the page directory entry points directly to a 4MB-aligned block of ++ * memory. ++ */ ++#define _PAGE_BIT_PRESENT 0 ++#define _PAGE_BIT_RW 1 ++#define _PAGE_BIT_USER 2 ++#define _PAGE_BIT_PWT 3 ++#define _PAGE_BIT_PCD 4 ++#define _PAGE_BIT_ACCESSED 5 ++#define _PAGE_BIT_DIRTY 6 ++#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page, Pentium+, if present.. */ ++#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ ++#define _PAGE_BIT_UNUSED1 9 /* available for programmer */ ++#define _PAGE_BIT_UNUSED2 10 ++#define _PAGE_BIT_UNUSED3 11 ++#define _PAGE_BIT_NX 63 ++ ++#define _PAGE_PRESENT 0x001 ++#define _PAGE_RW 0x002 ++#define _PAGE_USER 0x004 ++#define _PAGE_PWT 0x008 ++#define _PAGE_PCD 0x010 ++#define _PAGE_ACCESSED 0x020 ++#define _PAGE_DIRTY 0x040 ++#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */ ++#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */ ++#define _PAGE_UNUSED1 0x200 /* available for programmer */ ++#define _PAGE_UNUSED2 0x400 ++#define _PAGE_UNUSED3 0x800 ++ ++/* If _PAGE_PRESENT is clear, we use these: */ ++#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */ ++#define _PAGE_PROTNONE 0x080 /* if the user mapped it with PROT_NONE; ++ pte_present gives true */ ++#ifdef CONFIG_X86_PAE ++#define _PAGE_NX (1ULL<<_PAGE_BIT_NX) ++#else ++#define _PAGE_NX 0 ++#endif ++ ++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) ++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) ++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) ++ ++#define PAGE_NONE \ ++ __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) ++#define PAGE_SHARED \ ++ __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) ++ ++#define PAGE_SHARED_EXEC \ ++ __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_COPY_NOEXEC \ ++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) ++#define PAGE_COPY_EXEC \ ++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_COPY \ ++ PAGE_COPY_NOEXEC ++#define PAGE_READONLY \ ++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) ++#define PAGE_READONLY_EXEC \ ++ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++ ++#define _PAGE_KERNEL \ ++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX) ++#define _PAGE_KERNEL_EXEC \ ++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) ++ ++extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; ++#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) ++#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) ++#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) ++#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) ++ ++#define PAGE_KERNEL __pgprot(__PAGE_KERNEL) ++#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) ++#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) ++#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) ++#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) ++#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) ++ ++/* ++ * The i386 can't do page protection for execute, and considers that ++ * the same are read. Also, write permissions imply read permissions. ++ * This is the closest we can get.. ++ */ ++#define __P000 PAGE_NONE ++#define __P001 PAGE_READONLY ++#define __P010 PAGE_COPY ++#define __P011 PAGE_COPY ++#define __P100 PAGE_READONLY_EXEC ++#define __P101 PAGE_READONLY_EXEC ++#define __P110 PAGE_COPY_EXEC ++#define __P111 PAGE_COPY_EXEC ++ ++#define __S000 PAGE_NONE ++#define __S001 PAGE_READONLY ++#define __S010 PAGE_SHARED ++#define __S011 PAGE_SHARED ++#define __S100 PAGE_READONLY_EXEC ++#define __S101 PAGE_READONLY_EXEC ++#define __S110 PAGE_SHARED_EXEC ++#define __S111 PAGE_SHARED_EXEC ++ ++/* ++ * Define this if things work differently on an i386 and an i486: ++ * it will (on an i486) warn about kernel memory accesses that are ++ * done without a 'access_ok(VERIFY_WRITE,..)' ++ */ ++#undef TEST_ACCESS_OK ++ ++/* The boot page tables (all created as a single array) */ ++extern unsigned long pg0[]; ++ ++#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) ++ ++/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */ ++#define pmd_none(x) (!(unsigned long)pmd_val(x)) ++#if CONFIG_XEN_COMPAT <= 0x030002 ++/* pmd_present doesn't just test the _PAGE_PRESENT bit since wr.p.t. ++ can temporarily clear it. */ ++#define pmd_present(x) (pmd_val(x)) ++#else ++#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) ++#endif ++#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER & ~_PAGE_PRESENT)) != (_KERNPG_TABLE & ~_PAGE_PRESENT)) ++ ++ ++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) ++ ++/* ++ * The following only work if pte_present() is true. ++ * Undefined behaviour if not.. ++ */ ++static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; } ++static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; } ++static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; } ++static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; } ++static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; } ++static inline int pte_huge(pte_t pte) { return (pte).pte_low & _PAGE_PSE; } ++ ++/* ++ * The following only works if pte_present() is not true. ++ */ ++static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; } ++ ++static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; } ++static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; } ++static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; } ++static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; } ++static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; } ++static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; } ++static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; } ++static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; } ++static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; } ++static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; } ++static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return pte; } ++ ++#ifdef CONFIG_X86_PAE ++# include <asm/pgtable-3level.h> ++#else ++# include <asm/pgtable-2level.h> ++#endif ++ ++#ifndef CONFIG_PARAVIRT ++/* ++ * Rules for using pte_update - it must be called after any PTE update which ++ * has not been done using the set_pte / clear_pte interfaces. It is used by ++ * shadow mode hypervisors to resynchronize the shadow page tables. Kernel PTE ++ * updates should either be sets, clears, or set_pte_atomic for P->P ++ * transitions, which means this hook should only be called for user PTEs. ++ * This hook implies a P->P protection or access change has taken place, which ++ * requires a subsequent TLB flush. The notification can optionally be delayed ++ * until the TLB flush event by using the pte_update_defer form of the ++ * interface, but care must be taken to assure that the flush happens while ++ * still holding the same page table lock so that the shadow and primary pages ++ * do not become out of sync on SMP. ++ */ ++#define pte_update(mm, addr, ptep) do { } while (0) ++#define pte_update_defer(mm, addr, ptep) do { } while (0) ++#endif ++ ++/* ++ * We don't actually have these, but we want to advertise them so that ++ * we can encompass the flush here. ++ */ ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++ ++#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH ++#define ptep_clear_flush_dirty(vma, address, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __ret = pte_dirty(__pte); \ ++ if (__ret) { \ ++ __pte = pte_mkclean(__pte); \ ++ if ((vma)->vm_mm != current->mm || \ ++ HYPERVISOR_update_va_mapping(addr, __pte, 0)) \ ++ (ptep)->pte_low = __pte.pte_low; \ ++ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++ __ret; \ ++}) ++ ++#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define ptep_clear_flush_young(vma, addr, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __ret = pte_young(__pte); \ ++ if (__ret) { \ ++ __pte = pte_mkold(__pte); \ ++ if ((vma)->vm_mm != current->mm || \ ++ HYPERVISOR_update_va_mapping(addr, __pte, 0)) \ ++ (ptep)->pte_low = __pte.pte_low; \ ++ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++ __ret; \ ++}) ++ ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR ++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = raw_ptep_get_and_clear(mm, addr, ptep); ++ pte_update(mm, addr, ptep); ++ return pte; ++} ++ ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL ++#define ptep_get_and_clear_full(mm, addr, ptep, full) \ ++ ((full) ? ({ \ ++ pte_t __res = *(ptep); \ ++ if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) \ ++ xen_l1_entry_update(ptep, __pte(0)); \ ++ else \ ++ *(ptep) = __pte(0); \ ++ __res; \ ++ }) : \ ++ ptep_get_and_clear(mm, addr, ptep)) ++ ++#define __HAVE_ARCH_PTEP_SET_WRPROTECT ++static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (pte_write(pte)) ++ set_pte_at(mm, addr, ptep, pte_wrprotect(pte)); ++ pte_update(mm, addr, ptep); ++} ++ ++/* ++ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); ++ * ++ * dst - pointer to pgd range anwhere on a pgd page ++ * src - "" ++ * count - the number of pgds to copy. ++ * ++ * dst and src can be on the same page, but the range must not overlap, ++ * and must not cross a page boundary. ++ */ ++static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) ++{ ++ memcpy(dst, src, count * sizeof(pgd_t)); ++} ++ ++/* ++ * Macro to mark a page protection value as "uncacheable". On processors which do not support ++ * it, this is a no-op. ++ */ ++#define pgprot_noncached(prot) ((boot_cpu_data.x86 > 3) \ ++ ? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) : (prot)) ++ ++/* ++ * Conversion functions: convert a page and protection to a page entry, ++ * and a page entry and page directory to the page they refer to. ++ */ ++ ++#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) ++ ++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ++{ ++ /* ++ * Since this might change the present bit (which controls whether ++ * a pte_t object has undergone p2m translation), we must use ++ * pte_val() on the input pte and __pte() for the return value. ++ */ ++ paddr_t pteval = pte_val(pte); ++ ++ pteval &= _PAGE_CHG_MASK; ++ pteval |= pgprot_val(newprot); ++#ifdef CONFIG_X86_PAE ++ pteval &= __supported_pte_mask; ++#endif ++ return __pte(pteval); ++} ++ ++#define pmd_large(pmd) \ ++((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT)) ++ ++/* ++ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] ++ * ++ * this macro returns the index of the entry in the pgd page which would ++ * control the given virtual address ++ */ ++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) ++#define pgd_index_k(addr) pgd_index(addr) ++ ++/* ++ * pgd_offset() returns a (pgd_t *) ++ * pgd_index() is used get the offset into the pgd page's array of pgd_t's; ++ */ ++#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) ++ ++/* ++ * a shortcut which implies the use of the kernel's pgd, instead ++ * of a process's ++ */ ++#define pgd_offset_k(address) pgd_offset(&init_mm, address) ++ ++/* ++ * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD] ++ * ++ * this macro returns the index of the entry in the pmd page which would ++ * control the given virtual address ++ */ ++#define pmd_index(address) \ ++ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) ++ ++/* ++ * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] ++ * ++ * this macro returns the index of the entry in the pte page which would ++ * control the given virtual address ++ */ ++#define pte_index(address) \ ++ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ++#define pte_offset_kernel(dir, address) \ ++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) ++ ++#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) ++ ++#define pmd_page_vaddr(pmd) \ ++ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) ++ ++/* ++ * Helper function that returns the kernel pagetable entry controlling ++ * the virtual address 'address'. NULL means no pagetable entry present. ++ * NOTE: the return type is pte_t but if the pmd is PSE then we return it ++ * as a pte too. ++ */ ++extern pte_t *lookup_address(unsigned long address); ++ ++/* ++ * Make a given kernel text page executable/non-executable. ++ * Returns the previous executability setting of that page (which ++ * is used to restore the previous state). Used by the SMP bootup code. ++ * NOTE: this is an __init function for security reasons. ++ */ ++#ifdef CONFIG_X86_PAE ++ extern int set_kernel_exec(unsigned long vaddr, int enable); ++#else ++ static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;} ++#endif ++ ++#if defined(CONFIG_HIGHPTE) ++#define pte_offset_map(dir, address) \ ++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + \ ++ pte_index(address)) ++#define pte_offset_map_nested(dir, address) \ ++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + \ ++ pte_index(address)) ++#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) ++#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) ++#else ++#define pte_offset_map(dir, address) \ ++ ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address)) ++#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address) ++#define pte_unmap(pte) do { } while (0) ++#define pte_unmap_nested(pte) do { } while (0) ++#endif ++ ++/* Clear a kernel PTE and flush it from the TLB */ ++#define kpte_clear_flush(ptep, vaddr) \ ++do { \ ++ pte_clear(&init_mm, vaddr, ptep); \ ++ __flush_tlb_one(vaddr); \ ++} while (0) ++ ++#define __HAVE_ARCH_PTEP_ESTABLISH ++#define ptep_establish(vma, address, ptep, pteval) \ ++ do { \ ++ if ( likely((vma)->vm_mm == current->mm) ) { \ ++ BUG_ON(HYPERVISOR_update_va_mapping(address, \ ++ pteval, \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI)); \ ++ pte_update_defer((__vma)->vm_mm, (__address), (__ptep)); \ ++ } else { \ ++ xen_l1_entry_update(ptep, pteval); \ ++ pte_update_defer((__vma)->vm_mm, (__address), (__ptep)); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++ } while (0) ++ ++/* ++ * The i386 doesn't have any external MMU info: the kernel page ++ * tables contain all the necessary information. ++ */ ++#define update_mmu_cache(vma,address,pte) do { } while (0) ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ ++ do { \ ++ if (dirty) \ ++ ptep_establish(vma, address, ptep, entry); \ ++ } while (0) ++ ++#include <xen/features.h> ++void make_lowmem_page_readonly(void *va, unsigned int feature); ++void make_lowmem_page_writable(void *va, unsigned int feature); ++void make_page_readonly(void *va, unsigned int feature); ++void make_page_writable(void *va, unsigned int feature); ++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature); ++void make_pages_writable(void *va, unsigned int nr, unsigned int feature); ++ ++#define virt_to_ptep(__va) \ ++({ \ ++ pgd_t *__pgd = pgd_offset_k((unsigned long)(__va)); \ ++ pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va)); \ ++ pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va)); \ ++ pte_offset_kernel(__pmd, (unsigned long)(__va)); \ ++}) ++ ++#define arbitrary_virt_to_machine(__va) \ ++({ \ ++ maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\ ++ m | ((unsigned long)(__va) & (PAGE_SIZE-1)); \ ++}) ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#ifdef CONFIG_FLATMEM ++#define kern_addr_valid(addr) (1) ++#endif /* CONFIG_FLATMEM */ ++ ++int direct_remap_pfn_range(struct vm_area_struct *vma, ++ unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid); ++int direct_kernel_remap_pfn_range(unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid); ++int create_lookup_pte_addr(struct mm_struct *mm, ++ unsigned long address, ++ uint64_t *ptep); ++int touch_pte_range(struct mm_struct *mm, ++ unsigned long address, ++ unsigned long size); ++ ++#define io_remap_pfn_range(vma,vaddr,pfn,size,prot) \ ++ direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO) ++ ++#define MK_IOSPACE_PFN(space, pfn) (pfn) ++#define GET_IOSPACE(pfn) 0 ++#define GET_PFN(pfn) (pfn) ++ ++#include <asm-generic/pgtable.h> ++ ++#endif /* _I386_PGTABLE_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/processor.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/processor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,759 @@ ++/* ++ * include/asm-i386/processor.h ++ * ++ * Copyright (C) 1994 Linus Torvalds ++ */ ++ ++#ifndef __ASM_I386_PROCESSOR_H ++#define __ASM_I386_PROCESSOR_H ++ ++#include <asm/vm86.h> ++#include <asm/math_emu.h> ++#include <asm/segment.h> ++#include <asm/page.h> ++#include <asm/types.h> ++#include <asm/sigcontext.h> ++#include <asm/cpufeature.h> ++#include <asm/msr.h> ++#include <asm/system.h> ++#include <linux/cache.h> ++#include <linux/threads.h> ++#include <asm/percpu.h> ++#include <linux/cpumask.h> ++#include <linux/init.h> ++#include <xen/interface/physdev.h> ++ ++/* flag for disabling the tsc */ ++extern int tsc_disable; ++ ++struct desc_struct { ++ unsigned long a,b; ++}; ++ ++#define desc_empty(desc) \ ++ (!((desc)->a | (desc)->b)) ++ ++#define desc_equal(desc1, desc2) \ ++ (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b)) ++/* ++ * Default implementation of macro that returns current ++ * instruction pointer ("program counter"). ++ */ ++#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; }) ++ ++/* ++ * CPU type and hardware bug flags. Kept separately for each CPU. ++ * Members of this structure are referenced in head.S, so think twice ++ * before touching them. [mj] ++ */ ++ ++struct cpuinfo_x86 { ++ __u8 x86; /* CPU family */ ++ __u8 x86_vendor; /* CPU vendor */ ++ __u8 x86_model; ++ __u8 x86_mask; ++ char wp_works_ok; /* It doesn't on 386's */ ++ char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */ ++ char hard_math; ++ char rfu; ++ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */ ++ unsigned long x86_capability[NCAPINTS]; ++ char x86_vendor_id[16]; ++ char x86_model_id[64]; ++ int x86_cache_size; /* in KB - valid for CPUS which support this ++ call */ ++ int x86_cache_alignment; /* In bytes */ ++ char fdiv_bug; ++ char f00f_bug; ++ char coma_bug; ++ char pad0; ++ int x86_power; ++ unsigned long loops_per_jiffy; ++#ifdef CONFIG_SMP ++ cpumask_t llc_shared_map; /* cpus sharing the last level cache */ ++#endif ++ unsigned char x86_max_cores; /* cpuid returned max cores value */ ++ unsigned char apicid; ++ unsigned short x86_clflush_size; ++#ifdef CONFIG_SMP ++ unsigned char booted_cores; /* number of cores as seen by OS */ ++ __u8 phys_proc_id; /* Physical processor id. */ ++ __u8 cpu_core_id; /* Core id */ ++#endif ++} __attribute__((__aligned__(SMP_CACHE_BYTES))); ++ ++#define X86_VENDOR_INTEL 0 ++#define X86_VENDOR_CYRIX 1 ++#define X86_VENDOR_AMD 2 ++#define X86_VENDOR_UMC 3 ++#define X86_VENDOR_NEXGEN 4 ++#define X86_VENDOR_CENTAUR 5 ++#define X86_VENDOR_RISE 6 ++#define X86_VENDOR_TRANSMETA 7 ++#define X86_VENDOR_NSC 8 ++#define X86_VENDOR_NUM 9 ++#define X86_VENDOR_UNKNOWN 0xff ++ ++/* ++ * capabilities of CPUs ++ */ ++ ++extern struct cpuinfo_x86 boot_cpu_data; ++extern struct cpuinfo_x86 new_cpu_data; ++#ifndef CONFIG_X86_NO_TSS ++extern struct tss_struct doublefault_tss; ++DECLARE_PER_CPU(struct tss_struct, init_tss); ++#endif ++ ++#ifdef CONFIG_SMP ++extern struct cpuinfo_x86 cpu_data[]; ++#define current_cpu_data cpu_data[smp_processor_id()] ++#else ++#define cpu_data (&boot_cpu_data) ++#define current_cpu_data boot_cpu_data ++#endif ++ ++extern int cpu_llc_id[NR_CPUS]; ++extern char ignore_fpu_irq; ++ ++void __init cpu_detect(struct cpuinfo_x86 *c); ++ ++extern void identify_cpu(struct cpuinfo_x86 *); ++extern void print_cpu_info(struct cpuinfo_x86 *); ++extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); ++extern unsigned short num_cache_leaves; ++ ++#ifdef CONFIG_X86_HT ++extern void detect_ht(struct cpuinfo_x86 *c); ++#else ++static inline void detect_ht(struct cpuinfo_x86 *c) {} ++#endif ++ ++/* ++ * EFLAGS bits ++ */ ++#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ ++#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ ++#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */ ++#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ ++#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ ++#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ ++#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ ++#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ ++#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ ++#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ ++#define X86_EFLAGS_NT 0x00004000 /* Nested Task */ ++#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ ++#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ ++#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ ++#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ ++#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ ++#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ ++ ++static inline fastcall void native_cpuid(unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) ++{ ++ /* ecx is often an input as well as an output. */ ++ __asm__(XEN_CPUID ++ : "=a" (*eax), ++ "=b" (*ebx), ++ "=c" (*ecx), ++ "=d" (*edx) ++ : "0" (*eax), "2" (*ecx)); ++} ++ ++#define load_cr3(pgdir) write_cr3(__pa(pgdir)) ++ ++/* ++ * Intel CPU features in CR4 ++ */ ++#define X86_CR4_VME 0x0001 /* enable vm86 extensions */ ++#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */ ++#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */ ++#define X86_CR4_DE 0x0008 /* enable debugging extensions */ ++#define X86_CR4_PSE 0x0010 /* enable page size extensions */ ++#define X86_CR4_PAE 0x0020 /* enable physical address extensions */ ++#define X86_CR4_MCE 0x0040 /* Machine check enable */ ++#define X86_CR4_PGE 0x0080 /* enable global pages */ ++#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */ ++#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ ++#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ ++ ++/* ++ * Save the cr4 feature set we're using (ie ++ * Pentium 4MB enable and PPro Global page ++ * enable), so that any CPU's that boot up ++ * after us can get the correct flags. ++ */ ++extern unsigned long mmu_cr4_features; ++ ++static inline void set_in_cr4 (unsigned long mask) ++{ ++ unsigned cr4; ++ mmu_cr4_features |= mask; ++ cr4 = read_cr4(); ++ cr4 |= mask; ++ write_cr4(cr4); ++} ++ ++static inline void clear_in_cr4 (unsigned long mask) ++{ ++ unsigned cr4; ++ mmu_cr4_features &= ~mask; ++ cr4 = read_cr4(); ++ cr4 &= ~mask; ++ write_cr4(cr4); ++} ++ ++/* ++ * NSC/Cyrix CPU configuration register indexes ++ */ ++ ++#define CX86_PCR0 0x20 ++#define CX86_GCR 0xb8 ++#define CX86_CCR0 0xc0 ++#define CX86_CCR1 0xc1 ++#define CX86_CCR2 0xc2 ++#define CX86_CCR3 0xc3 ++#define CX86_CCR4 0xe8 ++#define CX86_CCR5 0xe9 ++#define CX86_CCR6 0xea ++#define CX86_CCR7 0xeb ++#define CX86_PCR1 0xf0 ++#define CX86_DIR0 0xfe ++#define CX86_DIR1 0xff ++#define CX86_ARR_BASE 0xc4 ++#define CX86_RCR_BASE 0xdc ++ ++/* ++ * NSC/Cyrix CPU indexed register access macros ++ */ ++ ++#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) ++ ++#define setCx86(reg, data) do { \ ++ outb((reg), 0x22); \ ++ outb((data), 0x23); \ ++} while (0) ++ ++/* Stop speculative execution */ ++static inline void sync_core(void) ++{ ++ int tmp; ++ asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory"); ++} ++ ++static inline void __monitor(const void *eax, unsigned long ecx, ++ unsigned long edx) ++{ ++ /* "monitor %eax,%ecx,%edx;" */ ++ asm volatile( ++ ".byte 0x0f,0x01,0xc8;" ++ : :"a" (eax), "c" (ecx), "d"(edx)); ++} ++ ++static inline void __mwait(unsigned long eax, unsigned long ecx) ++{ ++ /* "mwait %eax,%ecx;" */ ++ asm volatile( ++ ".byte 0x0f,0x01,0xc9;" ++ : :"a" (eax), "c" (ecx)); ++} ++ ++extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); ++ ++/* from system description table in BIOS. Mostly for MCA use, but ++others may find it useful. */ ++extern unsigned int machine_id; ++extern unsigned int machine_submodel_id; ++extern unsigned int BIOS_revision; ++extern unsigned int mca_pentium_flag; ++ ++/* Boot loader type from the setup header */ ++extern int bootloader_type; ++ ++/* ++ * User space process size: 3GB (default). ++ */ ++#define TASK_SIZE (PAGE_OFFSET) ++ ++/* This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. ++ */ ++#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) ++ ++#define HAVE_ARCH_PICK_MMAP_LAYOUT ++ ++/* ++ * Size of io_bitmap. ++ */ ++#define IO_BITMAP_BITS 65536 ++#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) ++#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) ++#ifndef CONFIG_X86_NO_TSS ++#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap) ++#endif ++#define INVALID_IO_BITMAP_OFFSET 0x8000 ++#define INVALID_IO_BITMAP_OFFSET_LAZY 0x9000 ++ ++struct i387_fsave_struct { ++ long cwd; ++ long swd; ++ long twd; ++ long fip; ++ long fcs; ++ long foo; ++ long fos; ++ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ ++ long status; /* software status information */ ++}; ++ ++struct i387_fxsave_struct { ++ unsigned short cwd; ++ unsigned short swd; ++ unsigned short twd; ++ unsigned short fop; ++ long fip; ++ long fcs; ++ long foo; ++ long fos; ++ long mxcsr; ++ long mxcsr_mask; ++ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ ++ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ ++ long padding[56]; ++} __attribute__ ((aligned (16))); ++ ++struct i387_soft_struct { ++ long cwd; ++ long swd; ++ long twd; ++ long fip; ++ long fcs; ++ long foo; ++ long fos; ++ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ ++ unsigned char ftop, changed, lookahead, no_update, rm, alimit; ++ struct info *info; ++ unsigned long entry_eip; ++}; ++ ++union i387_union { ++ struct i387_fsave_struct fsave; ++ struct i387_fxsave_struct fxsave; ++ struct i387_soft_struct soft; ++}; ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++ ++struct thread_struct; ++ ++#ifndef CONFIG_X86_NO_TSS ++struct tss_struct { ++ unsigned short back_link,__blh; ++ unsigned long esp0; ++ unsigned short ss0,__ss0h; ++ unsigned long esp1; ++ unsigned short ss1,__ss1h; /* ss1 is used to cache MSR_IA32_SYSENTER_CS */ ++ unsigned long esp2; ++ unsigned short ss2,__ss2h; ++ unsigned long __cr3; ++ unsigned long eip; ++ unsigned long eflags; ++ unsigned long eax,ecx,edx,ebx; ++ unsigned long esp; ++ unsigned long ebp; ++ unsigned long esi; ++ unsigned long edi; ++ unsigned short es, __esh; ++ unsigned short cs, __csh; ++ unsigned short ss, __ssh; ++ unsigned short ds, __dsh; ++ unsigned short fs, __fsh; ++ unsigned short gs, __gsh; ++ unsigned short ldt, __ldth; ++ unsigned short trace, io_bitmap_base; ++ /* ++ * The extra 1 is there because the CPU will access an ++ * additional byte beyond the end of the IO permission ++ * bitmap. The extra byte must be all 1 bits, and must ++ * be within the limit. ++ */ ++ unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; ++ /* ++ * Cache the current maximum and the last task that used the bitmap: ++ */ ++ unsigned long io_bitmap_max; ++ struct thread_struct *io_bitmap_owner; ++ /* ++ * pads the TSS to be cacheline-aligned (size is 0x100) ++ */ ++ unsigned long __cacheline_filler[35]; ++ /* ++ * .. and then another 0x100 bytes for emergency kernel stack ++ */ ++ unsigned long stack[64]; ++} __attribute__((packed)); ++#endif ++ ++#define ARCH_MIN_TASKALIGN 16 ++ ++struct thread_struct { ++/* cached TLS descriptors. */ ++ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; ++ unsigned long esp0; ++ unsigned long sysenter_cs; ++ unsigned long eip; ++ unsigned long esp; ++ unsigned long fs; ++ unsigned long gs; ++/* Hardware debugging registers */ ++ unsigned long debugreg[8]; /* %%db0-7 debug registers */ ++/* fault info */ ++ unsigned long cr2, trap_no, error_code; ++/* floating point info */ ++ union i387_union i387; ++/* virtual 86 mode info */ ++ struct vm86_struct __user * vm86_info; ++ unsigned long screen_bitmap; ++ unsigned long v86flags, v86mask, saved_esp0; ++ unsigned int saved_fs, saved_gs; ++/* IO permissions */ ++ unsigned long *io_bitmap_ptr; ++ unsigned long iopl; ++/* max allowed port in the bitmap, in bytes: */ ++ unsigned long io_bitmap_max; ++}; ++ ++#define INIT_THREAD { \ ++ .vm86_info = NULL, \ ++ .sysenter_cs = __KERNEL_CS, \ ++ .io_bitmap_ptr = NULL, \ ++ .gs = __KERNEL_PDA, \ ++} ++ ++#ifndef CONFIG_X86_NO_TSS ++/* ++ * Note that the .io_bitmap member must be extra-big. This is because ++ * the CPU will access an additional byte beyond the end of the IO ++ * permission bitmap. The extra byte must be all 1 bits, and must ++ * be within the limit. ++ */ ++#define INIT_TSS { \ ++ .esp0 = sizeof(init_stack) + (long)&init_stack, \ ++ .ss0 = __KERNEL_DS, \ ++ .ss1 = __KERNEL_CS, \ ++ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \ ++ .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ ++} ++#endif ++ ++#define start_thread(regs, new_eip, new_esp) do { \ ++ __asm__("movl %0,%%fs": :"r" (0)); \ ++ regs->xgs = 0; \ ++ set_fs(USER_DS); \ ++ regs->xds = __USER_DS; \ ++ regs->xes = __USER_DS; \ ++ regs->xss = __USER_DS; \ ++ regs->xcs = __USER_CS; \ ++ regs->eip = new_eip; \ ++ regs->esp = new_esp; \ ++} while (0) ++ ++/* Forward declaration, a strange C thing */ ++struct task_struct; ++struct mm_struct; ++ ++/* Free all resources held by a thread. */ ++extern void release_thread(struct task_struct *); ++ ++/* Prepare to copy thread state - unlazy all lazy status */ ++extern void prepare_to_copy(struct task_struct *tsk); ++ ++/* ++ * create a kernel thread without removing it from tasklists ++ */ ++extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); ++ ++extern unsigned long thread_saved_pc(struct task_struct *tsk); ++void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack); ++ ++unsigned long get_wchan(struct task_struct *p); ++ ++#define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long)) ++#define KSTK_TOP(info) \ ++({ \ ++ unsigned long *__ptr = (unsigned long *)(info); \ ++ (unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \ ++}) ++ ++/* ++ * The below -8 is to reserve 8 bytes on top of the ring0 stack. ++ * This is necessary to guarantee that the entire "struct pt_regs" ++ * is accessable even if the CPU haven't stored the SS/ESP registers ++ * on the stack (interrupt gate does not save these registers ++ * when switching to the same priv ring). ++ * Therefore beware: accessing the xss/esp fields of the ++ * "struct pt_regs" is possible, but they may contain the ++ * completely wrong values. ++ */ ++#define task_pt_regs(task) \ ++({ \ ++ struct pt_regs *__regs__; \ ++ __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \ ++ __regs__ - 1; \ ++}) ++ ++#define KSTK_EIP(task) (task_pt_regs(task)->eip) ++#define KSTK_ESP(task) (task_pt_regs(task)->esp) ++ ++ ++struct microcode_header { ++ unsigned int hdrver; ++ unsigned int rev; ++ unsigned int date; ++ unsigned int sig; ++ unsigned int cksum; ++ unsigned int ldrver; ++ unsigned int pf; ++ unsigned int datasize; ++ unsigned int totalsize; ++ unsigned int reserved[3]; ++}; ++ ++struct microcode { ++ struct microcode_header hdr; ++ unsigned int bits[0]; ++}; ++ ++typedef struct microcode microcode_t; ++typedef struct microcode_header microcode_header_t; ++ ++/* microcode format is extended from prescott processors */ ++struct extended_signature { ++ unsigned int sig; ++ unsigned int pf; ++ unsigned int cksum; ++}; ++ ++struct extended_sigtable { ++ unsigned int count; ++ unsigned int cksum; ++ unsigned int reserved[3]; ++ struct extended_signature sigs[0]; ++}; ++ ++/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ ++static inline void rep_nop(void) ++{ ++ __asm__ __volatile__("rep;nop": : :"memory"); ++} ++ ++#define cpu_relax() rep_nop() ++ ++#ifdef CONFIG_PARAVIRT ++#include <asm/paravirt.h> ++#else ++#define paravirt_enabled() 0 ++#define __cpuid native_cpuid ++ ++#ifndef CONFIG_X86_NO_TSS ++static inline void __load_esp0(struct tss_struct *tss, struct thread_struct *thread) ++{ ++ tss->esp0 = thread->esp0; ++ /* This can only happen when SEP is enabled, no need to test "SEP"arately */ ++ if (unlikely(tss->ss1 != thread->sysenter_cs)) { ++ tss->ss1 = thread->sysenter_cs; ++ wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); ++ } ++} ++#define load_esp0(tss, thread) \ ++ __load_esp0(tss, thread) ++#else ++#define load_esp0(tss, thread) \ ++ HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0) ++#endif ++ ++ ++/* ++ * These special macros can be used to get or set a debugging register ++ */ ++#define get_debugreg(var, register) \ ++ (var) = HYPERVISOR_get_debugreg((register)) ++#define set_debugreg(value, register) \ ++ HYPERVISOR_set_debugreg((register), (value)) ++ ++#define set_iopl_mask native_set_iopl_mask ++#endif /* CONFIG_PARAVIRT */ ++ ++/* ++ * Set IOPL bits in EFLAGS from given mask ++ */ ++static fastcall inline void native_set_iopl_mask(unsigned mask) ++{ ++ struct physdev_set_iopl set_iopl; ++ ++ /* Force the change at ring 0. */ ++ set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3; ++ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); ++} ++ ++/* ++ * Generic CPUID function ++ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx ++ * resulting in stale register contents being returned. ++ */ ++static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) ++{ ++ *eax = op; ++ *ecx = 0; ++ __cpuid(eax, ebx, ecx, edx); ++} ++ ++/* Some CPUID calls want 'count' to be placed in ecx */ ++static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, ++ int *edx) ++{ ++ *eax = op; ++ *ecx = count; ++ __cpuid(eax, ebx, ecx, edx); ++} ++ ++/* ++ * CPUID functions returning a single datum ++ */ ++static inline unsigned int cpuid_eax(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return eax; ++} ++static inline unsigned int cpuid_ebx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return ebx; ++} ++static inline unsigned int cpuid_ecx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return ecx; ++} ++static inline unsigned int cpuid_edx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return edx; ++} ++ ++/* generic versions from gas */ ++#define GENERIC_NOP1 ".byte 0x90\n" ++#define GENERIC_NOP2 ".byte 0x89,0xf6\n" ++#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" ++#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" ++#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 ++#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" ++#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" ++#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 ++ ++/* Opteron nops */ ++#define K8_NOP1 GENERIC_NOP1 ++#define K8_NOP2 ".byte 0x66,0x90\n" ++#define K8_NOP3 ".byte 0x66,0x66,0x90\n" ++#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" ++#define K8_NOP5 K8_NOP3 K8_NOP2 ++#define K8_NOP6 K8_NOP3 K8_NOP3 ++#define K8_NOP7 K8_NOP4 K8_NOP3 ++#define K8_NOP8 K8_NOP4 K8_NOP4 ++ ++/* K7 nops */ ++/* uses eax dependencies (arbitary choice) */ ++#define K7_NOP1 GENERIC_NOP1 ++#define K7_NOP2 ".byte 0x8b,0xc0\n" ++#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" ++#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" ++#define K7_NOP5 K7_NOP4 ASM_NOP1 ++#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" ++#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" ++#define K7_NOP8 K7_NOP7 ASM_NOP1 ++ ++#ifdef CONFIG_MK8 ++#define ASM_NOP1 K8_NOP1 ++#define ASM_NOP2 K8_NOP2 ++#define ASM_NOP3 K8_NOP3 ++#define ASM_NOP4 K8_NOP4 ++#define ASM_NOP5 K8_NOP5 ++#define ASM_NOP6 K8_NOP6 ++#define ASM_NOP7 K8_NOP7 ++#define ASM_NOP8 K8_NOP8 ++#elif defined(CONFIG_MK7) ++#define ASM_NOP1 K7_NOP1 ++#define ASM_NOP2 K7_NOP2 ++#define ASM_NOP3 K7_NOP3 ++#define ASM_NOP4 K7_NOP4 ++#define ASM_NOP5 K7_NOP5 ++#define ASM_NOP6 K7_NOP6 ++#define ASM_NOP7 K7_NOP7 ++#define ASM_NOP8 K7_NOP8 ++#else ++#define ASM_NOP1 GENERIC_NOP1 ++#define ASM_NOP2 GENERIC_NOP2 ++#define ASM_NOP3 GENERIC_NOP3 ++#define ASM_NOP4 GENERIC_NOP4 ++#define ASM_NOP5 GENERIC_NOP5 ++#define ASM_NOP6 GENERIC_NOP6 ++#define ASM_NOP7 GENERIC_NOP7 ++#define ASM_NOP8 GENERIC_NOP8 ++#endif ++ ++#define ASM_NOP_MAX 8 ++ ++/* Prefetch instructions for Pentium III and AMD Athlon */ ++/* It's not worth to care about 3dnow! prefetches for the K6 ++ because they are microcoded there and very slow. ++ However we don't do prefetches for pre XP Athlons currently ++ That should be fixed. */ ++#define ARCH_HAS_PREFETCH ++static inline void prefetch(const void *x) ++{ ++ alternative_input(ASM_NOP4, ++ "prefetchnta (%1)", ++ X86_FEATURE_XMM, ++ "r" (x)); ++} ++ ++#define ARCH_HAS_PREFETCH ++#define ARCH_HAS_PREFETCHW ++#define ARCH_HAS_SPINLOCK_PREFETCH ++ ++/* 3dnow! prefetch to get an exclusive cache line. Useful for ++ spinlocks to avoid one state transition in the cache coherency protocol. */ ++static inline void prefetchw(const void *x) ++{ ++ alternative_input(ASM_NOP4, ++ "prefetchw (%1)", ++ X86_FEATURE_3DNOW, ++ "r" (x)); ++} ++#define spin_lock_prefetch(x) prefetchw(x) ++ ++extern void select_idle_routine(const struct cpuinfo_x86 *c); ++ ++#define cache_line_size() (boot_cpu_data.x86_cache_alignment) ++ ++extern unsigned long boot_option_idle_override; ++extern void enable_sep_cpu(void); ++extern int sysenter_setup(void); ++ ++extern int init_gdt(int cpu, struct task_struct *idle); ++extern void cpu_set_gdt(int); ++extern void secondary_cpu_init(void); ++ ++#endif /* __ASM_I386_PROCESSOR_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/scatterlist.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/scatterlist.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,22 @@ ++#ifndef _I386_SCATTERLIST_H ++#define _I386_SCATTERLIST_H ++ ++struct scatterlist { ++ struct page *page; ++ unsigned int offset; ++ unsigned int length; ++ dma_addr_t dma_address; ++ unsigned int dma_length; ++}; ++ ++/* These macros should be used after a pci_map_sg call has been done ++ * to get bus addresses of each of the SG entries and their lengths. ++ * You should only work with the number of sg entries pci_map_sg ++ * returns. ++ */ ++#define sg_dma_address(sg) ((sg)->dma_address) ++#define sg_dma_len(sg) ((sg)->dma_length) ++ ++#define ISA_DMA_THRESHOLD (0x00ffffff) ++ ++#endif /* !(_I386_SCATTERLIST_H) */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/swiotlb.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/swiotlb.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,43 @@ ++#ifndef _ASM_SWIOTLB_H ++#define _ASM_SWIOTLB_H 1 ++ ++/* SWIOTLB interface */ ++ ++extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, ++ int dir); ++extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_single_for_cpu(struct device *hwdev, ++ dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_single_for_device(struct device *hwdev, ++ dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_sg_for_cpu(struct device *hwdev, ++ struct scatterlist *sg, int nelems, ++ int dir); ++extern void swiotlb_sync_sg_for_device(struct device *hwdev, ++ struct scatterlist *sg, int nelems, ++ int dir); ++extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, ++ int nents, int direction); ++extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, ++ int nents, int direction); ++extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr); ++#ifdef CONFIG_HIGHMEM ++extern dma_addr_t swiotlb_map_page(struct device *hwdev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dma_address, ++ size_t size, enum dma_data_direction direction); ++#endif ++extern int swiotlb_dma_supported(struct device *hwdev, u64 mask); ++extern void swiotlb_init(void); ++ ++#ifdef CONFIG_SWIOTLB ++extern int swiotlb; ++#else ++#define swiotlb 0 ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/synch_bitops.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/synch_bitops.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,145 @@ ++#ifndef __XEN_SYNCH_BITOPS_H__ ++#define __XEN_SYNCH_BITOPS_H__ ++ ++/* ++ * Copyright 1992, Linus Torvalds. ++ * Heavily modified to provide guaranteed strong synchronisation ++ * when communicating with Xen or other guest OSes running on other CPUs. ++ */ ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++#define ADDR (*(volatile long *) addr) ++ ++static __inline__ void synch_set_bit(int nr, volatile void * addr) ++{ ++ __asm__ __volatile__ ( ++ "lock btsl %1,%0" ++ : "+m" (ADDR) : "Ir" (nr) : "memory" ); ++} ++ ++static __inline__ void synch_clear_bit(int nr, volatile void * addr) ++{ ++ __asm__ __volatile__ ( ++ "lock btrl %1,%0" ++ : "+m" (ADDR) : "Ir" (nr) : "memory" ); ++} ++ ++static __inline__ void synch_change_bit(int nr, volatile void * addr) ++{ ++ __asm__ __volatile__ ( ++ "lock btcl %1,%0" ++ : "+m" (ADDR) : "Ir" (nr) : "memory" ); ++} ++ ++static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr) ++{ ++ int oldbit; ++ __asm__ __volatile__ ( ++ "lock btsl %2,%1\n\tsbbl %0,%0" ++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); ++ return oldbit; ++} ++ ++static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr) ++{ ++ int oldbit; ++ __asm__ __volatile__ ( ++ "lock btrl %2,%1\n\tsbbl %0,%0" ++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); ++ return oldbit; ++} ++ ++static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr) ++{ ++ int oldbit; ++ ++ __asm__ __volatile__ ( ++ "lock btcl %2,%1\n\tsbbl %0,%0" ++ : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); ++ return oldbit; ++} ++ ++struct __synch_xchg_dummy { unsigned long a[100]; }; ++#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x)) ++ ++#define synch_cmpxchg(ptr, old, new) \ ++((__typeof__(*(ptr)))__synch_cmpxchg((ptr),\ ++ (unsigned long)(old), \ ++ (unsigned long)(new), \ ++ sizeof(*(ptr)))) ++ ++static inline unsigned long __synch_cmpxchg(volatile void *ptr, ++ unsigned long old, ++ unsigned long new, int size) ++{ ++ unsigned long prev; ++ switch (size) { ++ case 1: ++ __asm__ __volatile__("lock; cmpxchgb %b1,%2" ++ : "=a"(prev) ++ : "q"(new), "m"(*__synch_xg(ptr)), ++ "0"(old) ++ : "memory"); ++ return prev; ++ case 2: ++ __asm__ __volatile__("lock; cmpxchgw %w1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__synch_xg(ptr)), ++ "0"(old) ++ : "memory"); ++ return prev; ++#ifdef CONFIG_X86_64 ++ case 4: ++ __asm__ __volatile__("lock; cmpxchgl %k1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__synch_xg(ptr)), ++ "0"(old) ++ : "memory"); ++ return prev; ++ case 8: ++ __asm__ __volatile__("lock; cmpxchgq %1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__synch_xg(ptr)), ++ "0"(old) ++ : "memory"); ++ return prev; ++#else ++ case 4: ++ __asm__ __volatile__("lock; cmpxchgl %1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__synch_xg(ptr)), ++ "0"(old) ++ : "memory"); ++ return prev; ++#endif ++ } ++ return old; ++} ++ ++static __always_inline int synch_const_test_bit(int nr, ++ const volatile void * addr) ++{ ++ return ((1UL << (nr & 31)) & ++ (((const volatile unsigned int *) addr)[nr >> 5])) != 0; ++} ++ ++static __inline__ int synch_var_test_bit(int nr, volatile void * addr) ++{ ++ int oldbit; ++ __asm__ __volatile__ ( ++ "btl %2,%1\n\tsbbl %0,%0" ++ : "=r" (oldbit) : "m" (ADDR), "Ir" (nr) ); ++ return oldbit; ++} ++ ++#define synch_test_bit(nr,addr) \ ++(__builtin_constant_p(nr) ? \ ++ synch_const_test_bit((nr),(addr)) : \ ++ synch_var_test_bit((nr),(addr))) ++ ++#define synch_cmpxchg_subword synch_cmpxchg ++ ++#endif /* __XEN_SYNCH_BITOPS_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/asm/xenoprof.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/asm/xenoprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,48 @@ ++/****************************************************************************** ++ * asm-i386/mach-xen/asm/xenoprof.h ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#ifndef __ASM_XENOPROF_H__ ++#define __ASM_XENOPROF_H__ ++#ifdef CONFIG_XEN ++ ++struct super_block; ++struct dentry; ++int xenoprof_create_files(struct super_block * sb, struct dentry * root); ++#define HAVE_XENOPROF_CREATE_FILES ++ ++struct xenoprof_init; ++void xenoprof_arch_init_counter(struct xenoprof_init *init); ++void xenoprof_arch_counter(void); ++void xenoprof_arch_start(void); ++void xenoprof_arch_stop(void); ++ ++struct xenoprof_arch_shared_buffer { ++ /* nothing */ ++}; ++struct xenoprof_shared_buffer; ++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf); ++struct xenoprof_get_buffer; ++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, struct xenoprof_shared_buffer* sbuf); ++struct xenoprof_passive; ++int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, struct xenoprof_shared_buffer* sbuf); ++ ++#endif /* CONFIG_XEN */ ++#endif /* __ASM_XENOPROF_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/irq_vectors.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/irq_vectors.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,125 @@ ++/* ++ * This file should contain #defines for all of the interrupt vector ++ * numbers used by this architecture. ++ * ++ * In addition, there are some standard defines: ++ * ++ * FIRST_EXTERNAL_VECTOR: ++ * The first free place for external interrupts ++ * ++ * SYSCALL_VECTOR: ++ * The IRQ vector a syscall makes the user to kernel transition ++ * under. ++ * ++ * TIMER_IRQ: ++ * The IRQ number the timer interrupt comes in at. ++ * ++ * NR_IRQS: ++ * The total number of interrupt vectors (including all the ++ * architecture specific interrupts) needed. ++ * ++ */ ++#ifndef _ASM_IRQ_VECTORS_H ++#define _ASM_IRQ_VECTORS_H ++ ++/* ++ * IDT vectors usable for external interrupt sources start ++ * at 0x20: ++ */ ++#define FIRST_EXTERNAL_VECTOR 0x20 ++ ++#define SYSCALL_VECTOR 0x80 ++ ++/* ++ * Vectors 0x20-0x2f are used for ISA interrupts. ++ */ ++ ++#if 0 ++/* ++ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff ++ * ++ * some of the following vectors are 'rare', they are merged ++ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. ++ * TLB, reschedule and local APIC vectors are performance-critical. ++ * ++ * Vectors 0xf0-0xfa are free (reserved for future Linux use). ++ */ ++#define SPURIOUS_APIC_VECTOR 0xff ++#define ERROR_APIC_VECTOR 0xfe ++#define INVALIDATE_TLB_VECTOR 0xfd ++#define RESCHEDULE_VECTOR 0xfc ++#define CALL_FUNCTION_VECTOR 0xfb ++ ++#define THERMAL_APIC_VECTOR 0xf0 ++/* ++ * Local APIC timer IRQ vector is on a different priority level, ++ * to work around the 'lost local interrupt if more than 2 IRQ ++ * sources per level' errata. ++ */ ++#define LOCAL_TIMER_VECTOR 0xef ++#endif ++ ++#define SPURIOUS_APIC_VECTOR 0xff ++#define ERROR_APIC_VECTOR 0xfe ++ ++/* ++ * First APIC vector available to drivers: (vectors 0x30-0xee) ++ * we start at 0x31 to spread out vectors evenly between priority ++ * levels. (0x80 is the syscall vector) ++ */ ++#define FIRST_DEVICE_VECTOR 0x31 ++#define FIRST_SYSTEM_VECTOR 0xef ++ ++/* ++ * 16 8259A IRQ's, 208 potential APIC interrupt sources. ++ * Right now the APIC is mostly only used for SMP. ++ * 256 vectors is an architectural limit. (we can have ++ * more than 256 devices theoretically, but they will ++ * have to use shared interrupts) ++ * Since vectors 0x00-0x1f are used/reserved for the CPU, ++ * the usable vector space is 0x20-0xff (224 vectors) ++ */ ++ ++#define RESCHEDULE_VECTOR 0 ++#define CALL_FUNCTION_VECTOR 1 ++#define NR_IPIS 2 ++ ++/* ++ * The maximum number of vectors supported by i386 processors ++ * is limited to 256. For processors other than i386, NR_VECTORS ++ * should be changed accordingly. ++ */ ++#define NR_VECTORS 256 ++ ++#define FPU_IRQ 13 ++ ++#define FIRST_VM86_IRQ 3 ++#define LAST_VM86_IRQ 15 ++#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) ++ ++/* ++ * The flat IRQ space is divided into two regions: ++ * 1. A one-to-one mapping of real physical IRQs. This space is only used ++ * if we have physical device-access privilege. This region is at the ++ * start of the IRQ space so that existing device drivers do not need ++ * to be modified to translate physical IRQ numbers into our IRQ space. ++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These ++ * are bound using the provided bind/unbind functions. ++ */ ++ ++#define PIRQ_BASE 0 ++#define NR_PIRQS 256 ++ ++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS) ++#define NR_DYNIRQS 256 ++ ++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS) ++#define NR_IRQ_VECTORS NR_IRQS ++ ++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE) ++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE) ++ ++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) ++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) ++ ++#endif /* _ASM_IRQ_VECTORS_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/mach_traps.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/mach_traps.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,33 @@ ++/* ++ * include/asm-xen/asm-i386/mach-xen/mach_traps.h ++ * ++ * Machine specific NMI handling for Xen ++ */ ++#ifndef _MACH_TRAPS_H ++#define _MACH_TRAPS_H ++ ++#include <linux/bitops.h> ++#include <xen/interface/nmi.h> ++ ++static inline void clear_mem_error(unsigned char reason) {} ++static inline void clear_io_check_error(unsigned char reason) {} ++ ++static inline unsigned char get_nmi_reason(void) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ unsigned char reason = 0; ++ ++ /* construct a value which looks like it came from ++ * port 0x61. ++ */ ++ if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason)) ++ reason |= 0x40; ++ if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason)) ++ reason |= 0x80; ++ ++ return reason; ++} ++ ++static inline void reassert_nmi(void) {} ++ ++#endif /* !_MACH_TRAPS_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mach-xen/setup_arch.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-i386/mach-xen/setup_arch.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++/* Hook to call BIOS initialisation function */ ++ ++#define ARCH_SETUP machine_specific_arch_setup(); ++ ++void __init machine_specific_arch_setup(void); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/mmu.h +--- a/include/asm-i386/mmu.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/mmu.h Wed Aug 08 16:25:28 2007 -0300 +@@ -13,6 +13,19 @@ typedef struct { + struct semaphore sem; + void *ldt; + void *vdso; ++#ifdef CONFIG_XEN ++ int has_foreign_mappings; ++#endif + } mm_context_t; + ++#ifdef CONFIG_XEN ++/* mm/memory.c:exit_mmap hook */ ++extern void _arch_exit_mmap(struct mm_struct *mm); ++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm) ++ ++/* kernel/fork.c:dup_mmap hook */ ++extern void _arch_dup_mmap(struct mm_struct *mm); ++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm)) ++#endif /* CONFIG_XEN */ ++ + #endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/pci.h +--- a/include/asm-i386/pci.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/pci.h Wed Aug 08 16:25:28 2007 -0300 +@@ -42,6 +42,27 @@ int pcibios_set_irq_routing(struct pci_d + + struct pci_dev; + ++#ifdef CONFIG_SWIOTLB ++ ++ ++/* On Xen we use SWIOTLB instead of blk-specific bounce buffers. */ ++#define PCI_DMA_BUS_IS_PHYS (0) ++ ++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ ++ dma_addr_t ADDR_NAME; ++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ ++ __u32 LEN_NAME; ++#define pci_unmap_addr(PTR, ADDR_NAME) \ ++ ((PTR)->ADDR_NAME) ++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ ++ (((PTR)->ADDR_NAME) = (VAL)) ++#define pci_unmap_len(PTR, LEN_NAME) \ ++ ((PTR)->LEN_NAME) ++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ ++ (((PTR)->LEN_NAME) = (VAL)) ++ ++#else ++ + /* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. +@@ -55,6 +76,8 @@ struct pci_dev; + #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) + #define pci_unmap_len(PTR, LEN_NAME) (0) + #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) ++ ++#endif + + /* This is always fine. */ + #define pci_dac_dma_supported(pci_dev, mask) (1) +@@ -110,6 +133,10 @@ static inline void pci_dma_burst_advice( + + #endif /* __KERNEL__ */ + ++#ifdef CONFIG_XEN_PCIDEV_FRONTEND ++#include <xen/pcifront.h> ++#endif /* CONFIG_XEN_PCIDEV_FRONTEND */ ++ + /* implement the pci_ DMA API in terms of the generic device dma_ one */ + #include <asm-generic/pci-dma-compat.h> + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/pgalloc.h +--- a/include/asm-i386/pgalloc.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/pgalloc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -4,14 +4,35 @@ + #include <asm/fixmap.h> + #include <linux/threads.h> + #include <linux/mm.h> /* for struct page */ ++#ifdef CONFIG_XEN ++#include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */ ++#endif + + #define pmd_populate_kernel(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) + ++#ifdef CONFIG_XEN ++#define pmd_populate(mm, pmd, pte) \ ++do { \ ++ unsigned long pfn = page_to_pfn(pte); \ ++ if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) { \ ++ if (!PageHighMem(pte)) \ ++ BUG_ON(HYPERVISOR_update_va_mapping( \ ++ (unsigned long)__va(pfn << PAGE_SHIFT), \ ++ pfn_pte(pfn, PAGE_KERNEL_RO), 0)); \ ++ else if (!test_and_set_bit(PG_pinned, &pte->flags)) \ ++ kmap_flush_unused(); \ ++ set_pmd(pmd, \ ++ __pmd(_PAGE_TABLE + ((paddr_t)pfn << PAGE_SHIFT))); \ ++ } else \ ++ *(pmd) = __pmd(_PAGE_TABLE + ((paddr_t)pfn << PAGE_SHIFT)); \ ++} while (0) ++#else + #define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + \ + ((unsigned long long)page_to_pfn(pte) << \ + (unsigned long long) PAGE_SHIFT))) ++#endif + /* + * Allocate and free page tables. + */ +@@ -24,13 +45,19 @@ static inline void pte_free_kernel(pte_t + static inline void pte_free_kernel(pte_t *pte) + { + free_page((unsigned long)pte); ++#ifdef CONFIG_XEN ++ make_lowmem_page_writable(pte, XENFEAT_writable_page_tables); ++#endif + } + ++#ifdef CONFIG_XEN ++extern void pte_free(struct page *pte); ++#else + static inline void pte_free(struct page *pte) + { + __free_page(pte); + } +- ++#endif + + #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/pgtable-2level-defs.h +--- a/include/asm-i386/pgtable-2level-defs.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/pgtable-2level-defs.h Wed Aug 08 16:25:28 2007 -0300 +@@ -1,5 +1,7 @@ + #ifndef _I386_PGTABLE_2LEVEL_DEFS_H + #define _I386_PGTABLE_2LEVEL_DEFS_H ++ ++#define HAVE_SHARED_KERNEL_PMD 0 + + /* + * traditional i386 two-level paging structure: +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/pgtable-3level-defs.h +--- a/include/asm-i386/pgtable-3level-defs.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/pgtable-3level-defs.h Wed Aug 08 16:25:28 2007 -0300 +@@ -1,5 +1,11 @@ + #ifndef _I386_PGTABLE_3LEVEL_DEFS_H + #define _I386_PGTABLE_3LEVEL_DEFS_H ++ ++#ifdef CONFIG_XEN ++#define HAVE_SHARED_KERNEL_PMD 0 ++#else ++#define HAVE_SHARED_KERNEL_PMD 1 ++#endif + + /* + * PGDIR_SHIFT determines what a top-level page table entry can map +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/segment.h +--- a/include/asm-i386/segment.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/segment.h Wed Aug 08 16:25:28 2007 -0300 +@@ -87,7 +87,11 @@ + #define GDT_SIZE (GDT_ENTRIES * 8) + + /* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ ++#ifdef CONFIG_XEN ++#define SEGMENT_IS_FLAT_CODE(x) ((x) == __USER_CS || (x) == (__KERNEL_CS | get_kernel_rpl())) ++#else + #define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) ++#endif + /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ + #define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) + +@@ -132,6 +136,10 @@ + #define SEGMENT_GDT 0x0 + + #ifndef CONFIG_PARAVIRT ++#ifdef CONFIG_XEN ++#define get_kernel_rpl() (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) ++#else + #define get_kernel_rpl() 0 ++#endif /* CONFIG_XEN */ + #endif + #endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/setup.h +--- a/include/asm-i386/setup.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/setup.h Wed Aug 08 16:25:28 2007 -0300 +@@ -53,9 +53,15 @@ extern unsigned char boot_params[PARAM_S + #define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) + #define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) + #define KERNEL_START (*(unsigned long *) (PARAM+0x214)) ++#ifdef CONFIG_XEN ++#define INITRD_START (__pa(xen_start_info->mod_start)) ++#define INITRD_SIZE (xen_start_info->mod_len) ++#define EDID_INFO (*(struct edid_info *) (PARAM+0x440)) ++#else + #define INITRD_START (*(unsigned long *) (PARAM+0x218)) + #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) + #define EDID_INFO (*(struct edid_info *) (PARAM+0x140)) ++#endif /* CONFIG_XEN */ + #define EDD_NR (*(unsigned char *) (PARAM+EDDNR)) + #define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF)) + #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/smp.h +--- a/include/asm-i386/smp.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/smp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -59,14 +59,22 @@ extern void cpu_uninit(void); + */ + #define raw_smp_processor_id() (read_pda(cpu_number)) + ++#ifdef CONFIG_XEN ++#define cpu_callin_map cpu_possible_map ++#else + extern cpumask_t cpu_callout_map; + extern cpumask_t cpu_callin_map; ++#endif + extern cpumask_t cpu_possible_map; + + /* We don't mark CPUs online until __cpu_up(), so we need another measure */ + static inline int num_booting_cpus(void) + { ++#ifdef CONFIG_XEN ++ return cpus_weight(cpu_possible_map); ++#else + return cpus_weight(cpu_callout_map); ++#endif + } + + #ifdef CONFIG_X86_LOCAL_APIC +@@ -88,6 +96,9 @@ extern void __cpu_die(unsigned int cpu); + extern void __cpu_die(unsigned int cpu); + extern unsigned int num_processors; + ++#ifdef CONFIG_XEN ++extern void prefill_possible_map(void); ++#endif + #endif /* !__ASSEMBLY__ */ + + #else /* CONFIG_SMP */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/system.h +--- a/include/asm-i386/system.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/system.h Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,10 @@ + #include <asm/segment.h> + #include <asm/cpufeature.h> + #include <linux/bitops.h> /* for LOCK_PREFIX */ ++#ifdef CONFIG_XEN ++#include <asm/synch_bitops.h> ++#include <asm/hypervisor.h> ++#endif + + #ifdef __KERNEL__ + +@@ -101,6 +105,9 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + #define write_cr0(x) \ + __asm__ __volatile__("movl %0,%%cr0": :"r" (x)) + ++#ifdef CONFIG_XEN ++#define read_cr2() (current_vcpu_info()->arch.cr2) ++#else + #define read_cr2() ({ \ + unsigned int __dummy; \ + __asm__ __volatile__( \ +@@ -108,9 +115,25 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + :"=r" (__dummy)); \ + __dummy; \ + }) ++#endif + #define write_cr2(x) \ + __asm__ __volatile__("movl %0,%%cr2": :"r" (x)) + ++#ifdef CONFIG_XEN ++#define read_cr3() ({ \ ++ unsigned int __dummy; \ ++ __asm__ ( \ ++ "movl %%cr3,%0\n\t" \ ++ :"=r" (__dummy)); \ ++ __dummy = xen_cr3_to_pfn(__dummy); \ ++ mfn_to_pfn(__dummy) << PAGE_SHIFT; \ ++}) ++#define write_cr3(x) ({ \ ++ unsigned int __dummy = pfn_to_mfn((x) >> PAGE_SHIFT); \ ++ __dummy = xen_pfn_to_cr3(__dummy); \ ++ __asm__ __volatile__("movl %0,%%cr3": :"r" (__dummy)); \ ++}) ++#else + #define read_cr3() ({ \ + unsigned int __dummy; \ + __asm__ ( \ +@@ -120,6 +143,7 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + }) + #define write_cr3(x) \ + __asm__ __volatile__("movl %0,%%cr3": :"r" (x)) ++#endif + + #define read_cr4() ({ \ + unsigned int __dummy; \ +@@ -146,11 +170,17 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + __asm__ __volatile__ ("wbinvd": : :"memory") + + /* Clear the 'TS' bit */ ++/* ++ * Clear and set 'TS' bit respectively ++ */ ++#ifdef CONFIG_XEN ++#define clts() (HYPERVISOR_fpu_taskswitch(0)) ++#define stts() (HYPERVISOR_fpu_taskswitch(1)) ++#else + #define clts() __asm__ __volatile__ ("clts") ++#define stts() write_cr0(8 | read_cr0()) ++#endif + #endif/* CONFIG_PARAVIRT */ +- +-/* Set the 'TS' bit */ +-#define stts() write_cr0(8 | read_cr0()) + + #endif /* __KERNEL__ */ + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/tlbflush.h +--- a/include/asm-i386/tlbflush.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/tlbflush.h Wed Aug 08 16:25:28 2007 -0300 +@@ -7,10 +7,23 @@ + #ifdef CONFIG_PARAVIRT + #include <asm/paravirt.h> + #else ++#ifdef CONFIG_XEN ++#define __flush_tlb() xen_tlb_flush() ++#define __flush_tlb_global() xen_tlb_flush() ++ ++extern unsigned long pgkern_mask; ++ ++#define __flush_tlb_all() xen_tlb_flush() ++ ++#define cpu_has_invlpg (boot_cpu_data.x86 > 3) ++ ++#define __flush_tlb_single(addr) xen_invlpg(addr) ++ ++#define __flush_tlb_one(addr) __flush_tlb_single(addr) ++#else + #define __flush_tlb() __native_flush_tlb() + #define __flush_tlb_global() __native_flush_tlb_global() + #define __flush_tlb_single(addr) __native_flush_tlb_single(addr) +-#endif + + #define __native_flush_tlb() \ + do { \ +@@ -47,6 +60,7 @@ + #define __native_flush_tlb_single(addr) \ + __asm__ __volatile__("invlpg (%0)" ::"r" (addr) : "memory") + ++ + # define __flush_tlb_all() \ + do { \ + if (cpu_has_pge) \ +@@ -68,7 +82,8 @@ + __flush_tlb(); \ + } while (0) + #endif +- ++#endif /* CONFIG_XEN */ ++#endif /* CONFIG_PARAVIRT */ + /* + * TLB flushing: + * +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-i386/vga.h +--- a/include/asm-i386/vga.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-i386/vga.h Wed Aug 08 16:25:28 2007 -0300 +@@ -11,8 +11,11 @@ + * On the PC, we can just recalculate addresses and then + * access the videoram directly without any black magic. + */ +- ++#ifdef CONFIG_XEN ++#define VGA_MAP_MEM(x,s) (unsigned long)isa_bus_to_virt(x) ++#else + #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) ++#endif + + #define vga_readb(x) (*(x)) + #define vga_writeb(x,y) (*(y) = (x)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/agp.h +--- a/include/asm-ia64/agp.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/agp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -19,13 +19,44 @@ + #define flush_agp_cache() mb() + + /* Convert a physical address to an address suitable for the GART. */ ++#ifndef CONFIG_XEN + #define phys_to_gart(x) (x) + #define gart_to_phys(x) (x) ++#else ++#define phys_to_gart(x) phys_to_machine_for_dma(x) ++#define gart_to_phys(x) machine_to_phys_for_dma(x) ++#endif + + /* GATT allocation. Returns/accepts GATT kernel virtual address. */ ++#ifndef CONFIG_XEN + #define alloc_gatt_pages(order) \ + ((char *)__get_free_pages(GFP_KERNEL, (order))) + #define free_gatt_pages(table, order) \ + free_pages((unsigned long)(table), (order)) ++#else ++#include <asm/hypervisor.h> ++static inline char* ++alloc_gatt_pages(unsigned int order) ++{ ++ unsigned long error; ++ unsigned long ret = __get_free_pages(GFP_KERNEL, (order)); ++ if (ret == 0) { ++ goto out; ++ } ++ error = xen_create_contiguous_region(ret, order, 0); ++ if (error) { ++ free_pages(ret, order); ++ ret = 0; ++ } ++out: ++ return (char*)ret; ++} ++static inline void ++free_gatt_pages(void* table, unsigned int order) ++{ ++ xen_destroy_contiguous_region((unsigned long)table, order); ++ free_pages((unsigned long)table, order); ++} ++#endif /* CONFIG_XEN */ + + #endif /* _ASM_IA64_AGP_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/dma-mapping.h +--- a/include/asm-ia64/dma-mapping.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/dma-mapping.h Wed Aug 08 16:25:28 2007 -0300 +@@ -6,20 +6,67 @@ + * David Mosberger-Tang <davidm@hpl.hp.com> + */ + #include <asm/machvec.h> ++#ifndef CONFIG_XEN + +-#define dma_alloc_coherent platform_dma_alloc_coherent +-#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */ +-#define dma_free_coherent platform_dma_free_coherent +-#define dma_free_noncoherent platform_dma_free_coherent +-#define dma_map_single platform_dma_map_single +-#define dma_map_sg platform_dma_map_sg +-#define dma_unmap_single platform_dma_unmap_single +-#define dma_unmap_sg platform_dma_unmap_sg +-#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu +-#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu ++#define dma_alloc_coherent platform_dma_alloc_coherent ++#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */ ++#define dma_free_coherent platform_dma_free_coherent ++#define dma_free_noncoherent platform_dma_free_coherent ++#define dma_map_single platform_dma_map_single ++#define dma_map_sg platform_dma_map_sg ++#define dma_unmap_single platform_dma_unmap_single ++#define dma_unmap_sg platform_dma_unmap_sg ++#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu ++#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu + #define dma_sync_single_for_device platform_dma_sync_single_for_device +-#define dma_sync_sg_for_device platform_dma_sync_sg_for_device +-#define dma_mapping_error platform_dma_mapping_error ++#define dma_sync_sg_for_device platform_dma_sync_sg_for_device ++#define dma_mapping_error platform_dma_mapping_error ++ ++#else /* CONFIG_XEN */ ++/* Needed for arch/i386/kernel/swiotlb.c and arch/i386/kernel/pci-dma-xen.c */ ++#include <asm/hypervisor.h> ++/* Needed for arch/i386/kernel/swiotlb.c */ ++#include <asm/swiotlb.h> ++ ++int dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction); ++void dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++ enum dma_data_direction direction); ++int dma_supported(struct device *dev, u64 mask); ++void *dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t gfp); ++void dma_free_coherent(struct device *dev, size_t size, void *vaddr, ++ dma_addr_t dma_handle); ++dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction direction); ++void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction direction); ++void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, ++ size_t size, enum dma_data_direction direction); ++void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, ++ size_t size, ++ enum dma_data_direction direction); ++int dma_mapping_error(dma_addr_t dma_addr); ++ ++#define flush_write_buffers() do { } while (0) ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_cpu(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_device(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++#endif /* CONFIG_XEN */ + + #define dma_map_page(dev, pg, off, size, dir) \ + dma_map_single(dev, page_address(pg) + (off), (size), (dir)) +@@ -36,7 +83,9 @@ + #define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_device(dev, dma_handle, size, dir) + ++#ifndef CONFIG_XEN + #define dma_supported platform_dma_supported ++#endif + + static inline int + dma_set_mask (struct device *dev, u64 mask) +@@ -62,4 +111,29 @@ dma_cache_sync (struct device *dev, void + + #define dma_is_consistent(d, h) (1) /* all we do is coherent memory... */ + ++#ifdef CONFIG_XEN ++/* arch/i386/kernel/swiotlb.o requires */ ++void contiguous_bitmap_init(unsigned long end_pfn); ++ ++static inline int ++address_needs_mapping(struct device *hwdev, dma_addr_t addr) ++{ ++ dma_addr_t mask = DMA_64BIT_MASK; ++ /* If the device has a mask, use it, otherwise default to 64 bits */ ++ if (hwdev && hwdev->dma_mask) ++ mask = *hwdev->dma_mask; ++ return (addr & ~mask) != 0; ++} ++#else ++#define contiguous_bitmap_init(end_pfn) ((void)end_pfn) ++#endif ++ ++static inline int ++range_straddles_page_boundary(void *p, size_t size) ++{ ++ extern unsigned long *contiguous_bitmap; ++ return (((((unsigned long)p & ~PAGE_MASK) + size) > PAGE_SIZE) && ++ !test_bit(__pa(p) >> PAGE_SHIFT, contiguous_bitmap)); ++} ++ + #endif /* _ASM_IA64_DMA_MAPPING_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/fixmap.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/fixmap.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++#define clear_fixmap(x) do {} while (0) ++#define set_fixmap(x,y) do {} while (0) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/gcc_intrin.h +--- a/include/asm-ia64/gcc_intrin.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/gcc_intrin.h Wed Aug 08 16:25:28 2007 -0300 +@@ -26,7 +26,7 @@ extern void ia64_bad_param_for_getreg (v + + register unsigned long ia64_r13 asm ("r13") __attribute_used__; + +-#define ia64_setreg(regnum, val) \ ++#define __ia64_setreg(regnum, val) \ + ({ \ + switch (regnum) { \ + case _IA64_REG_PSR_L: \ +@@ -55,7 +55,7 @@ register unsigned long ia64_r13 asm ("r1 + } \ + }) + +-#define ia64_getreg(regnum) \ ++#define __ia64_getreg(regnum) \ + ({ \ + __u64 ia64_intri_res; \ + \ +@@ -92,7 +92,7 @@ register unsigned long ia64_r13 asm ("r1 + + #define ia64_hint_pause 0 + +-#define ia64_hint(mode) \ ++#define __ia64_hint(mode) \ + ({ \ + switch (mode) { \ + case ia64_hint_pause: \ +@@ -374,7 +374,7 @@ register unsigned long ia64_r13 asm ("r1 + + #define ia64_invala() asm volatile ("invala" ::: "memory") + +-#define ia64_thash(addr) \ ++#define __ia64_thash(addr) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("thash %0=%1" : "=r"(ia64_intri_res) : "r" (addr)); \ +@@ -394,18 +394,18 @@ register unsigned long ia64_r13 asm ("r1 + + #define ia64_nop(x) asm volatile ("nop %0"::"i"(x)); + +-#define ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory") +- +-#define ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory") +- +- +-#define ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \ ++#define __ia64_itci(addr) asm volatile ("itc.i %0;;" :: "r"(addr) : "memory") ++ ++#define __ia64_itcd(addr) asm volatile ("itc.d %0;;" :: "r"(addr) : "memory") ++ ++ ++#define __ia64_itri(trnum, addr) asm volatile ("itr.i itr[%0]=%1" \ + :: "r"(trnum), "r"(addr) : "memory") + +-#define ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \ ++#define __ia64_itrd(trnum, addr) asm volatile ("itr.d dtr[%0]=%1" \ + :: "r"(trnum), "r"(addr) : "memory") + +-#define ia64_tpa(addr) \ ++#define __ia64_tpa(addr) \ + ({ \ + __u64 ia64_pa; \ + asm volatile ("tpa %0 = %1" : "=r"(ia64_pa) : "r"(addr) : "memory"); \ +@@ -415,22 +415,22 @@ register unsigned long ia64_r13 asm ("r1 + #define __ia64_set_dbr(index, val) \ + asm volatile ("mov dbr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +-#define ia64_set_ibr(index, val) \ ++#define __ia64_set_ibr(index, val) \ + asm volatile ("mov ibr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +-#define ia64_set_pkr(index, val) \ ++#define __ia64_set_pkr(index, val) \ + asm volatile ("mov pkr[%0]=%1" :: "r"(index), "r"(val) : "memory") + +-#define ia64_set_pmc(index, val) \ ++#define __ia64_set_pmc(index, val) \ + asm volatile ("mov pmc[%0]=%1" :: "r"(index), "r"(val) : "memory") + +-#define ia64_set_pmd(index, val) \ ++#define __ia64_set_pmd(index, val) \ + asm volatile ("mov pmd[%0]=%1" :: "r"(index), "r"(val) : "memory") + +-#define ia64_set_rr(index, val) \ ++#define __ia64_set_rr(index, val) \ + asm volatile ("mov rr[%0]=%1" :: "r"(index), "r"(val) : "memory"); + +-#define ia64_get_cpuid(index) \ ++#define __ia64_get_cpuid(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=cpuid[%r1]" : "=r"(ia64_intri_res) : "rO"(index)); \ +@@ -444,21 +444,21 @@ register unsigned long ia64_r13 asm ("r1 + ia64_intri_res; \ + }) + +-#define ia64_get_ibr(index) \ ++#define __ia64_get_ibr(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=ibr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ + }) + +-#define ia64_get_pkr(index) \ ++#define __ia64_get_pkr(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=pkr[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ + }) + +-#define ia64_get_pmc(index) \ ++#define __ia64_get_pmc(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=pmc[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ +@@ -466,48 +466,48 @@ register unsigned long ia64_r13 asm ("r1 + }) + + +-#define ia64_get_pmd(index) \ ++#define __ia64_get_pmd(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=pmd[%1]" : "=r"(ia64_intri_res) : "r"(index)); \ + ia64_intri_res; \ + }) + +-#define ia64_get_rr(index) \ ++#define __ia64_get_rr(index) \ + ({ \ + __u64 ia64_intri_res; \ + asm volatile ("mov %0=rr[%1]" : "=r"(ia64_intri_res) : "r" (index)); \ + ia64_intri_res; \ + }) + +-#define ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") ++#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory") + + + #define ia64_sync_i() asm volatile (";; sync.i" ::: "memory") + +-#define ia64_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory") +-#define ia64_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory") ++#define __ia64_ssm(mask) asm volatile ("ssm %0":: "i"((mask)) : "memory") ++#define __ia64_rsm(mask) asm volatile ("rsm %0":: "i"((mask)) : "memory") + #define ia64_sum(mask) asm volatile ("sum %0":: "i"((mask)) : "memory") + #define ia64_rum(mask) asm volatile ("rum %0":: "i"((mask)) : "memory") + +-#define ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr)) +- +-#define ia64_ptcga(addr, size) \ ++#define __ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr)) ++ ++#define __ia64_ptcga(addr, size) \ + do { \ + asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ + } while (0) + +-#define ia64_ptcl(addr, size) \ ++#define __ia64_ptcl(addr, size) \ + do { \ + asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ + } while (0) + +-#define ia64_ptri(addr, size) \ ++#define __ia64_ptri(addr, size) \ + asm volatile ("ptr.i %0,%1" :: "r"(addr), "r"(size) : "memory") + +-#define ia64_ptrd(addr, size) \ ++#define __ia64_ptrd(addr, size) \ + asm volatile ("ptr.d %0,%1" :: "r"(addr), "r"(size) : "memory") + + /* Values for lfhint in ia64_lfetch and ia64_lfetch_fault */ +@@ -589,7 +589,7 @@ do { \ + } \ + }) + +-#define ia64_intrin_local_irq_restore(x) \ ++#define __ia64_intrin_local_irq_restore(x) \ + do { \ + asm volatile (";; cmp.ne p6,p7=%0,r0;;" \ + "(p6) ssm psr.i;" \ +@@ -598,4 +598,6 @@ do { \ + :: "r"((x)) : "p6", "p7", "memory"); \ + } while (0) + ++#define __ia64_get_psr_i() (__ia64_getreg(_IA64_REG_PSR) & 0x4000UL) ++ + #endif /* _ASM_IA64_GCC_INTRIN_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/hw_irq.h +--- a/include/asm-ia64/hw_irq.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/hw_irq.h Wed Aug 08 16:25:28 2007 -0300 +@@ -15,7 +15,11 @@ + #include <asm/ptrace.h> + #include <asm/smp.h> + ++#ifndef CONFIG_XEN + typedef u8 ia64_vector; ++#else ++typedef u16 ia64_vector; ++#endif + + /* + * 0 special +@@ -99,6 +103,12 @@ extern void register_percpu_irq (ia64_ve + + static inline void ia64_resend_irq(unsigned int vector) + { ++#ifdef CONFIG_XEN ++ extern void resend_irq_on_evtchn(unsigned int i); ++ if (is_running_on_xen()) ++ resend_irq_on_evtchn(vector); ++ else ++#endif /* CONFIG_XEN */ + platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0); + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/hypercall.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/hypercall.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,416 @@ ++/****************************************************************************** ++ * hypercall.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERCALL_H__ ++#define __HYPERCALL_H__ ++ ++#ifndef __HYPERVISOR_H__ ++# error "please don't include this file directly" ++#endif ++ ++#include <asm/xen/xcom_hcall.h> ++struct xencomm_handle; ++extern unsigned long __hypercall(unsigned long a1, unsigned long a2, ++ unsigned long a3, unsigned long a4, ++ unsigned long a5, unsigned long cmd); ++ ++/* ++ * Assembler stubs for hyper-calls. ++ */ ++ ++#define _hypercall0(type, name) \ ++({ \ ++ long __res; \ ++ __res=__hypercall(0, 0, 0, 0, 0, __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall1(type, name, a1) \ ++({ \ ++ long __res; \ ++ __res = __hypercall((unsigned long)a1, \ ++ 0, 0, 0, 0, __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall2(type, name, a1, a2) \ ++({ \ ++ long __res; \ ++ __res = __hypercall((unsigned long)a1, \ ++ (unsigned long)a2, \ ++ 0, 0, 0, __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall3(type, name, a1, a2, a3) \ ++({ \ ++ long __res; \ ++ __res = __hypercall((unsigned long)a1, \ ++ (unsigned long)a2, \ ++ (unsigned long)a3, \ ++ 0, 0, __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall4(type, name, a1, a2, a3, a4) \ ++({ \ ++ long __res; \ ++ __res = __hypercall((unsigned long)a1, \ ++ (unsigned long)a2, \ ++ (unsigned long)a3, \ ++ (unsigned long)a4, \ ++ 0, __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ ++({ \ ++ long __res; \ ++ __res = __hypercall((unsigned long)a1, \ ++ (unsigned long)a2, \ ++ (unsigned long)a3, \ ++ (unsigned long)a4, \ ++ (unsigned long)a5, \ ++ __HYPERVISOR_##name); \ ++ (type)__res; \ ++}) ++ ++ ++static inline int ++xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, sched_op, cmd, arg); ++} ++ ++static inline long ++HYPERVISOR_set_timer_op(u64 timeout) ++{ ++ unsigned long timeout_hi = (unsigned long)(timeout >> 32); ++ unsigned long timeout_lo = (unsigned long)timeout; ++ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); ++} ++ ++static inline int ++xencomm_arch_hypercall_platform_op(struct xencomm_handle *op) ++{ ++ return _hypercall1(int, platform_op, op); ++} ++ ++static inline int ++xencomm_arch_hypercall_sysctl(struct xencomm_handle *op) ++{ ++ return _hypercall1(int, sysctl, op); ++} ++ ++static inline int ++xencomm_arch_hypercall_domctl(struct xencomm_handle *op) ++{ ++ return _hypercall1(int, domctl, op); ++} ++ ++static inline int ++xencomm_arch_hypercall_multicall(struct xencomm_handle *call_list, ++ int nr_calls) ++{ ++ return _hypercall2(int, multicall, call_list, nr_calls); ++} ++ ++static inline int ++xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, memory_op, cmd, arg); ++} ++ ++static inline int ++xencomm_arch_hypercall_event_channel_op(int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, event_channel_op, cmd, arg); ++} ++ ++static inline int ++xencomm_arch_hypercall_acm_op(unsigned int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, acm_op, cmd, arg); ++} ++ ++static inline int ++xencomm_arch_hypercall_xen_version(int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, xen_version, cmd, arg); ++} ++ ++static inline int ++xencomm_arch_hypercall_console_io(int cmd, int count, ++ struct xencomm_handle *str) ++{ ++ return _hypercall3(int, console_io, cmd, count, str); ++} ++ ++static inline int ++xencomm_arch_hypercall_physdev_op(int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, physdev_op, cmd, arg); ++} ++ ++static inline int ++xencomm_arch_hypercall_grant_table_op(unsigned int cmd, ++ struct xencomm_handle *uop, ++ unsigned int count) ++{ ++ return _hypercall3(int, grant_table_op, cmd, uop, count); ++} ++ ++int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count); ++ ++extern int xencomm_arch_hypercall_suspend(struct xencomm_handle *arg); ++ ++static inline int ++xencomm_arch_hypercall_callback_op(int cmd, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, callback_op, cmd, arg); ++} ++ ++static inline unsigned long ++xencomm_arch_hypercall_hvm_op(int cmd, void *arg) ++{ ++ return _hypercall2(unsigned long, hvm_op, cmd, arg); ++} ++ ++static inline long ++xencomm_arch_hypercall_vcpu_op(int cmd, int cpu, void *arg) ++{ ++ return _hypercall3(long, vcpu_op, cmd, cpu, arg); ++} ++ ++static inline int ++HYPERVISOR_physdev_op(int cmd, void *arg) ++{ ++ switch (cmd) { ++ case PHYSDEVOP_eoi: ++ return _hypercall1(int, ia64_fast_eoi, ++ ((struct physdev_eoi *)arg)->irq); ++ default: ++ return xencomm_hypercall_physdev_op(cmd, arg); ++ } ++} ++ ++static inline int ++xencomm_arch_hypercall_xenoprof_op(int op, struct xencomm_handle *arg) ++{ ++ return _hypercall2(int, xenoprof_op, op, arg); ++} ++ ++extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); ++static inline void exit_idle(void) {} ++#define do_IRQ(irq, regs) ({ \ ++ irq_enter(); \ ++ __do_IRQ((irq), (regs)); \ ++ irq_exit(); \ ++}) ++ ++#include <linux/err.h> ++#ifdef CONFIG_XEN ++#include <asm/xen/privop.h> ++#endif /* CONFIG_XEN */ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include <xen/platform-compat.h> ++#endif ++ ++static inline unsigned long ++__HYPERVISOR_ioremap(unsigned long ioaddr, unsigned long size) ++{ ++ return _hypercall3(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_ioremap, ioaddr, size); ++} ++ ++static inline unsigned long ++HYPERVISOR_ioremap(unsigned long ioaddr, unsigned long size) ++{ ++ unsigned long ret = ioaddr; ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_ioremap(ioaddr, size); ++ if (unlikely(ret == -ENOSYS)) ++ panic("hypercall %s failed with %ld. " ++ "Please check Xen and Linux config mismatch\n", ++ __func__, -ret); ++ else if (unlikely(IS_ERR_VALUE(ret))) ++ ret = ioaddr; ++ } ++ return ret; ++} ++ ++static inline unsigned long ++__HYPERVISOR_phystomach(unsigned long gpfn) ++{ ++ return _hypercall2(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_phystomach, gpfn); ++} ++ ++static inline unsigned long ++HYPERVISOR_phystomach(unsigned long gpfn) ++{ ++ unsigned long ret = gpfn; ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_phystomach(gpfn); ++ } ++ return ret; ++} ++ ++static inline unsigned long ++__HYPERVISOR_machtophys(unsigned long mfn) ++{ ++ return _hypercall2(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_machtophys, mfn); ++} ++ ++static inline unsigned long ++HYPERVISOR_machtophys(unsigned long mfn) ++{ ++ unsigned long ret = mfn; ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_machtophys(mfn); ++ } ++ return ret; ++} ++ ++static inline unsigned long ++__HYPERVISOR_zap_physmap(unsigned long gpfn, unsigned int extent_order) ++{ ++ return _hypercall3(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_zap_physmap, gpfn, extent_order); ++} ++ ++static inline unsigned long ++HYPERVISOR_zap_physmap(unsigned long gpfn, unsigned int extent_order) ++{ ++ unsigned long ret = 0; ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_zap_physmap(gpfn, extent_order); ++ } ++ return ret; ++} ++ ++static inline unsigned long ++__HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn, ++ unsigned long flags, domid_t domid) ++{ ++ return _hypercall5(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_add_physmap, gpfn, mfn, flags, domid); ++} ++ ++static inline unsigned long ++HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn, ++ unsigned long flags, domid_t domid) ++{ ++ unsigned long ret = 0; ++ BUG_ON(!is_running_on_xen());//XXX ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_add_physmap(gpfn, mfn, flags, domid); ++ } ++ return ret; ++} ++ ++static inline unsigned long ++__HYPERVISOR_add_physmap_with_gmfn(unsigned long gpfn, unsigned long gmfn, ++ unsigned long flags, domid_t domid) ++{ ++ return _hypercall5(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_add_physmap_with_gmfn, ++ gpfn, gmfn, flags, domid); ++} ++ ++static inline unsigned long ++HYPERVISOR_add_physmap_with_gmfn(unsigned long gpfn, unsigned long gmfn, ++ unsigned long flags, domid_t domid) ++{ ++ unsigned long ret = 0; ++ BUG_ON(!is_running_on_xen());//XXX ++ if (is_running_on_xen()) { ++ ret = __HYPERVISOR_add_physmap_with_gmfn(gpfn, gmfn, ++ flags, domid); ++ } ++ return ret; ++} ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M ++static inline unsigned long ++HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, ++ unsigned long assign_start_gpfn, ++ unsigned long expose_size, unsigned long granule_pfn) ++{ ++ return _hypercall5(unsigned long, ia64_dom0vp_op, ++ IA64_DOM0VP_expose_p2m, conv_start_gpfn, ++ assign_start_gpfn, expose_size, granule_pfn); ++} ++#endif ++ ++static inline int ++xencomm_arch_hypercall_perfmon_op(unsigned long cmd, ++ struct xencomm_handle *arg, ++ unsigned long count) ++{ ++ return _hypercall4(int, ia64_dom0vp_op, ++ IA64_DOM0VP_perfmon, cmd, arg, count); ++} ++ ++// for balloon driver ++#define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) ++ ++/* Use xencomm to do hypercalls. */ ++#ifdef MODULE ++#define HYPERVISOR_sched_op xencomm_mini_hypercall_sched_op ++#define HYPERVISOR_event_channel_op xencomm_mini_hypercall_event_channel_op ++#define HYPERVISOR_callback_op xencomm_mini_hypercall_callback_op ++#define HYPERVISOR_multicall xencomm_mini_hypercall_multicall ++#define HYPERVISOR_xen_version xencomm_mini_hypercall_xen_version ++#define HYPERVISOR_console_io xencomm_mini_hypercall_console_io ++#define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op ++#define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op ++#define HYPERVISOR_xenoprof_op xencomm_mini_hypercall_xenoprof_op ++#define HYPERVISOR_perfmon_op xencomm_mini_hypercall_perfmon_op ++#else ++#define HYPERVISOR_sched_op xencomm_hypercall_sched_op ++#define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op ++#define HYPERVISOR_callback_op xencomm_hypercall_callback_op ++#define HYPERVISOR_multicall xencomm_hypercall_multicall ++#define HYPERVISOR_xen_version xencomm_hypercall_xen_version ++#define HYPERVISOR_console_io xencomm_hypercall_console_io ++#define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op ++#define HYPERVISOR_memory_op xencomm_hypercall_memory_op ++#define HYPERVISOR_xenoprof_op xencomm_hypercall_xenoprof_op ++#define HYPERVISOR_perfmon_op xencomm_hypercall_perfmon_op ++#endif ++ ++#define HYPERVISOR_suspend xencomm_hypercall_suspend ++#define HYPERVISOR_vcpu_op xencomm_hypercall_vcpu_op ++ ++#endif /* __HYPERCALL_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/hypervisor.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/hypervisor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,225 @@ ++/****************************************************************************** ++ * hypervisor.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERVISOR_H__ ++#define __HYPERVISOR_H__ ++ ++#ifdef CONFIG_XEN ++extern int running_on_xen; ++#define is_running_on_xen() (running_on_xen) ++#else /* CONFIG_XEN */ ++# ifdef CONFIG_VMX_GUEST ++# define is_running_on_xen() (1) ++# else /* CONFIG_VMX_GUEST */ ++# define is_running_on_xen() (0) ++# define HYPERVISOR_ioremap(offset, size) (offset) ++# endif /* CONFIG_VMX_GUEST */ ++#endif /* CONFIG_XEN */ ++ ++#if defined(CONFIG_XEN) || defined(CONFIG_VMX_GUEST) ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/version.h> ++#include <linux/errno.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/platform.h> ++#include <xen/interface/event_channel.h> ++#include <xen/interface/physdev.h> ++#include <xen/interface/sched.h> ++#include <xen/hypercall.h> ++#include <asm/ptrace.h> ++#include <asm/page.h> ++ ++extern shared_info_t *HYPERVISOR_shared_info; ++extern start_info_t *xen_start_info; ++ ++void force_evtchn_callback(void); ++ ++/* Turn jiffies into Xen system time. XXX Implement me. */ ++#define jiffies_to_st(j) 0 ++ ++static inline int ++HYPERVISOR_yield( ++ void) ++{ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL); ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_block( ++ void) ++{ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL); ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_shutdown( ++ unsigned int reason) ++{ ++ struct sched_shutdown sched_shutdown = { ++ .reason = reason ++ }; ++ ++ int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_poll( ++ evtchn_port_t *ports, unsigned int nr_ports, u64 timeout) ++{ ++ struct sched_poll sched_poll = { ++ .nr_ports = nr_ports, ++ .timeout = jiffies_to_st(timeout) ++ }; ++ ++ int rc; ++ ++ set_xen_guest_handle(sched_poll.ports, ports); ++ rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll); ++ ++ return rc; ++} ++ ++#include <asm/hypercall.h> ++ ++#ifndef CONFIG_VMX_GUEST ++// for drivers/xen/privcmd/privcmd.c ++#define machine_to_phys_mapping 0 ++struct vm_area_struct; ++int direct_remap_pfn_range(struct vm_area_struct *vma, ++ unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid); ++struct file; ++int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); ++int privcmd_mmap(struct file * file, struct vm_area_struct * vma); ++#define HAVE_ARCH_PRIVCMD_MMAP ++ ++// for drivers/xen/balloon/balloon.c ++#ifdef CONFIG_XEN_SCRUB_PAGES ++#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT) ++#else ++#define scrub_pages(_p,_n) ((void)0) ++#endif ++#define pte_mfn(_x) pte_pfn(_x) ++#define phys_to_machine_mapping_valid(_x) (1) ++ ++#endif /* !CONFIG_VMX_GUEST */ ++ ++#define __pte_ma(_x) ((pte_t) {(_x)}) /* unmodified use */ ++#define pfn_pte_ma(_x,_y) __pte_ma(0) /* unmodified use */ ++ ++#ifndef CONFIG_VMX_GUEST ++int __xen_create_contiguous_region(unsigned long vstart, unsigned int order, unsigned int address_bits); ++static inline int ++xen_create_contiguous_region(unsigned long vstart, ++ unsigned int order, unsigned int address_bits) ++{ ++ int ret = 0; ++ if (is_running_on_xen()) { ++ ret = __xen_create_contiguous_region(vstart, order, ++ address_bits); ++ } ++ return ret; ++} ++ ++void __xen_destroy_contiguous_region(unsigned long vstart, unsigned int order); ++static inline void ++xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) ++{ ++ if (is_running_on_xen()) ++ __xen_destroy_contiguous_region(vstart, order); ++} ++ ++#endif /* !CONFIG_VMX_GUEST */ ++ ++// for netfront.c, netback.c ++#define MULTI_UVMFLAGS_INDEX 0 //XXX any value ++ ++static inline void ++MULTI_update_va_mapping( ++ multicall_entry_t *mcl, unsigned long va, ++ pte_t new_val, unsigned long flags) ++{ ++ mcl->op = __HYPERVISOR_update_va_mapping; ++ mcl->result = 0; ++} ++ ++static inline void ++MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd, ++ void *uop, unsigned int count) ++{ ++ mcl->op = __HYPERVISOR_grant_table_op; ++ mcl->args[0] = cmd; ++ mcl->args[1] = (unsigned long)uop; ++ mcl->args[2] = count; ++} ++ ++/* ++ * for blktap.c ++ * int create_lookup_pte_addr(struct mm_struct *mm, ++ * unsigned long address, ++ * uint64_t *ptep); ++ */ ++#define create_lookup_pte_addr(mm, address, ptep) \ ++ ({ \ ++ printk(KERN_EMERG \ ++ "%s:%d " \ ++ "create_lookup_pte_addr() isn't supported.\n", \ ++ __func__, __LINE__); \ ++ BUG(); \ ++ (-ENOSYS); \ ++ }) ++ ++// for debug ++asmlinkage int xprintk(const char *fmt, ...); ++#define xprintd(fmt, ...) xprintk("%s:%d " fmt, __func__, __LINE__, \ ++ ##__VA_ARGS__) ++ ++#endif /* CONFIG_XEN || CONFIG_VMX_GUEST */ ++ ++#ifdef CONFIG_XEN_PRIVILEGED_GUEST ++#define is_initial_xendomain() \ ++ (is_running_on_xen() ? xen_start_info->flags & SIF_INITDOMAIN : 0) ++#else ++#define is_initial_xendomain() 0 ++#endif ++ ++#endif /* __HYPERVISOR_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/intel_intrin.h +--- a/include/asm-ia64/intel_intrin.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/intel_intrin.h Wed Aug 08 16:25:28 2007 -0300 +@@ -16,8 +16,11 @@ + * intrinsic + */ + +-#define ia64_getreg __getReg +-#define ia64_setreg __setReg ++#define __ia64_getreg __getReg ++#define __ia64_setreg __setReg ++ ++#define ia64_hint __hint ++#define ia64_hint_pause __hint_pause + + #define ia64_hint __hint + #define ia64_hint_pause __hint_pause +@@ -33,16 +36,16 @@ + #define ia64_getf_exp __getf_exp + #define ia64_shrp _m64_shrp + +-#define ia64_tpa __tpa ++#define __ia64_tpa __tpa + #define ia64_invala __invala + #define ia64_invala_gr __invala_gr + #define ia64_invala_fr __invala_fr + #define ia64_nop __nop + #define ia64_sum __sum +-#define ia64_ssm __ssm ++#define __ia64_ssm __ssm + #define ia64_rum __rum +-#define ia64_rsm __rsm +-#define ia64_fc __fc ++#define __ia64_rsm __rsm ++#define __ia64_fc __fc + + #define ia64_ldfs __ldfs + #define ia64_ldfd __ldfd +@@ -80,24 +83,24 @@ + + #define __ia64_set_dbr(index, val) \ + __setIndReg(_IA64_REG_INDR_DBR, index, val) +-#define ia64_set_ibr(index, val) \ ++#define __ia64_set_ibr(index, val) \ + __setIndReg(_IA64_REG_INDR_IBR, index, val) +-#define ia64_set_pkr(index, val) \ ++#define __ia64_set_pkr(index, val) \ + __setIndReg(_IA64_REG_INDR_PKR, index, val) +-#define ia64_set_pmc(index, val) \ ++#define __ia64_set_pmc(index, val) \ + __setIndReg(_IA64_REG_INDR_PMC, index, val) +-#define ia64_set_pmd(index, val) \ ++#define __ia64_set_pmd(index, val) \ + __setIndReg(_IA64_REG_INDR_PMD, index, val) +-#define ia64_set_rr(index, val) \ ++#define __ia64_set_rr(index, val) \ + __setIndReg(_IA64_REG_INDR_RR, index, val) + +-#define ia64_get_cpuid(index) __getIndReg(_IA64_REG_INDR_CPUID, index) ++#define __ia64_get_cpuid(index) __getIndReg(_IA64_REG_INDR_CPUID, index) + #define __ia64_get_dbr(index) __getIndReg(_IA64_REG_INDR_DBR, index) +-#define ia64_get_ibr(index) __getIndReg(_IA64_REG_INDR_IBR, index) +-#define ia64_get_pkr(index) __getIndReg(_IA64_REG_INDR_PKR, index) +-#define ia64_get_pmc(index) __getIndReg(_IA64_REG_INDR_PMC, index) +-#define ia64_get_pmd(index) __getIndReg(_IA64_REG_INDR_PMD, index) +-#define ia64_get_rr(index) __getIndReg(_IA64_REG_INDR_RR, index) ++#define __ia64_get_ibr(index) __getIndReg(_IA64_REG_INDR_IBR, index) ++#define __ia64_get_pkr(index) __getIndReg(_IA64_REG_INDR_PKR, index) ++#define __ia64_get_pmc(index) __getIndReg(_IA64_REG_INDR_PMC, index) ++#define __ia64_get_pmd(index) __getIndReg(_IA64_REG_INDR_PMD, index) ++#define __ia64_get_rr(index) __getIndReg(_IA64_REG_INDR_RR, index) + + #define ia64_srlz_d __dsrlz + #define ia64_srlz_i __isrlz +@@ -116,18 +119,18 @@ + #define ia64_ld8_acq __ld8_acq + + #define ia64_sync_i __synci +-#define ia64_thash __thash +-#define ia64_ttag __ttag +-#define ia64_itcd __itcd +-#define ia64_itci __itci +-#define ia64_itrd __itrd +-#define ia64_itri __itri +-#define ia64_ptce __ptce +-#define ia64_ptcl __ptcl +-#define ia64_ptcg __ptcg +-#define ia64_ptcga __ptcga +-#define ia64_ptri __ptri +-#define ia64_ptrd __ptrd ++#define __ia64_thash __thash ++#define __ia64_ttag __ttag ++#define __ia64_itcd __itcd ++#define __ia64_itci __itci ++#define __ia64_itrd __itrd ++#define __ia64_itri __itri ++#define __ia64_ptce __ptce ++#define __ia64_ptcl __ptcl ++#define __ia64_ptcg __ptcg ++#define __ia64_ptcga __ptcga ++#define __ia64_ptri __ptri ++#define __ia64_ptrd __ptrd + #define ia64_dep_mi _m64_dep_mi + + /* Values for lfhint in __lfetch and __lfetch_fault */ +@@ -142,15 +145,17 @@ + #define ia64_lfetch_fault __lfetch_fault + #define ia64_lfetch_fault_excl __lfetch_fault_excl + +-#define ia64_intrin_local_irq_restore(x) \ ++#define __ia64_intrin_local_irq_restore(x) \ + do { \ + if ((x) != 0) { \ +- ia64_ssm(IA64_PSR_I); \ ++ __ia64_ssm(IA64_PSR_I); \ + ia64_srlz_d(); \ + } else { \ +- ia64_rsm(IA64_PSR_I); \ ++ __ia64_rsm(IA64_PSR_I); \ + } \ + } while (0) ++ ++#define __ia64_get_psr_i() (__ia64_getreg(_IA64_REG_PSR) & 0x4000UL) + + #define __builtin_trap() __break(0); + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/io.h +--- a/include/asm-ia64/io.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/io.h Wed Aug 08 16:25:28 2007 -0300 +@@ -66,9 +66,11 @@ extern unsigned int num_io_spaces; + #define PIO_RESERVED __IA64_UNCACHED_OFFSET + #define HAVE_ARCH_PIO_SIZE + ++#include <asm/hypervisor.h> + #include <asm/intrinsics.h> + #include <asm/machvec.h> + #include <asm/page.h> ++#include <asm/privop.h> + #include <asm/system.h> + #include <asm-generic/iomap.h> + +@@ -96,9 +98,46 @@ extern int valid_mmap_phys_addr_range (u + * The following two macros are deprecated and scheduled for removal. + * Please use the PCI-DMA interface defined in <asm/pci.h> instead. + */ ++#ifndef CONFIG_XEN + #define bus_to_virt phys_to_virt + #define virt_to_bus virt_to_phys + #define page_to_bus page_to_phys ++#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) ++#define page_to_pseudophys(page) page_to_phys(page) ++#else /* CONFIG_XEN */ ++#define bus_to_virt(bus) \ ++ phys_to_virt(machine_to_phys_for_dma(bus)) ++#define virt_to_bus(virt) \ ++ phys_to_machine_for_dma(virt_to_phys(virt)) ++#define page_to_bus(page) \ ++ phys_to_machine_for_dma(page_to_pseudophys(page)) ++ ++#define page_to_pseudophys(page) \ ++ ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) ++ ++/* ++ * Drivers that use page_to_phys() for bus addresses are broken. ++ * This includes: ++ * drivers/ide/cris/ide-cris.c ++ * drivers/scsi/dec_esp.c ++ */ ++#define page_to_phys(page) (page_to_pseudophys(page)) ++#define bvec_to_bus(bv) (page_to_bus((bv)->bv_page) + \ ++ (unsigned long) (bv)->bv_offset) ++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \ ++ (unsigned long) bio_offset((bio))) ++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \ ++ (unsigned long) (bv)->bv_offset) ++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ ++ (((bvec_to_bus((vec1)) + (vec1)->bv_len) == bvec_to_bus((vec2))) && \ ++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \ ++ bvec_to_pseudophys((vec2)))) ++ ++/* We will be supplying our own /dev/mem implementation */ ++#define ARCH_HAS_DEV_MEM ++#define ARCH_HAS_DEV_MEM_MMAP_MEM ++int xen_mmap_mem(struct file * file, struct vm_area_struct * vma); ++#endif /* CONFIG_XEN */ + + # endif /* KERNEL */ + +@@ -418,7 +457,6 @@ __writeq (unsigned long val, volatile vo + #endif + + # ifdef __KERNEL__ +- + extern void __iomem * ioremap(unsigned long offset, unsigned long size); + extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/iosapic.h +--- a/include/asm-ia64/iosapic.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/iosapic.h Wed Aug 08 16:25:28 2007 -0300 +@@ -53,6 +53,7 @@ + + #define NR_IOSAPICS 256 + ++#ifndef CONFIG_XEN + static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg) + { + writel(reg, iosapic + IOSAPIC_REG_SELECT); +@@ -64,6 +65,7 @@ static inline void iosapic_write(char __ + writel(reg, iosapic + IOSAPIC_REG_SELECT); + writel(val, iosapic + IOSAPIC_WINDOW); + } ++#endif + + static inline void iosapic_eoi(char __iomem *iosapic, u32 vector) + { +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/irq.h +--- a/include/asm-ia64/irq.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/irq.h Wed Aug 08 16:25:28 2007 -0300 +@@ -11,8 +11,41 @@ + * 02/29/00 D.Mosberger moved most things into hw_irq.h + */ + ++#ifndef CONFIG_XEN + #define NR_IRQS 256 + #define NR_IRQ_VECTORS NR_IRQS ++#else ++/* ++ * The flat IRQ space is divided into two regions: ++ * 1. A one-to-one mapping of real physical IRQs. This space is only used ++ * if we have physical device-access privilege. This region is at the ++ * start of the IRQ space so that existing device drivers do not need ++ * to be modified to translate physical IRQ numbers into our IRQ space. ++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These ++ * are bound using the provided bind/unbind functions. ++ */ ++ ++#define PIRQ_BASE 0 ++#define NR_PIRQS 256 ++ ++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS) ++#define NR_DYNIRQS 256 ++ ++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS) ++#define NR_IRQ_VECTORS NR_IRQS ++ ++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE) ++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE) ++ ++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) ++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) ++ ++#define RESCHEDULE_VECTOR 0 ++#define IPI_VECTOR 1 ++#define CMCP_VECTOR 2 ++#define CPEP_VECTOR 3 ++#define NR_IPIS 4 ++#endif /* CONFIG_XEN */ + + static __inline__ int + irq_canonicalize (int irq) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/machvec_dig.h +--- a/include/asm-ia64/machvec_dig.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/machvec_dig.h Wed Aug 08 16:25:28 2007 -0300 +@@ -13,4 +13,19 @@ extern ia64_mv_setup_t dig_setup; + #define platform_name "dig" + #define platform_setup dig_setup + ++#ifdef CONFIG_XEN ++# define platform_dma_map_sg dma_map_sg ++# define platform_dma_unmap_sg dma_unmap_sg ++# define platform_dma_mapping_error dma_mapping_error ++# define platform_dma_supported dma_supported ++# define platform_dma_alloc_coherent dma_alloc_coherent ++# define platform_dma_free_coherent dma_free_coherent ++# define platform_dma_map_single dma_map_single ++# define platform_dma_unmap_single dma_unmap_single ++# define platform_dma_sync_single_for_cpu \ ++ dma_sync_single_for_cpu ++# define platform_dma_sync_single_for_device \ ++ dma_sync_single_for_device ++#endif ++ + #endif /* _ASM_IA64_MACHVEC_DIG_h */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/maddr.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/maddr.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,98 @@ ++#ifndef _ASM_IA64_MADDR_H ++#define _ASM_IA64_MADDR_H ++ ++#include <linux/kernel.h> ++#include <asm/hypervisor.h> ++#include <xen/features.h> ++#include <xen/interface/xen.h> ++ ++#ifdef CONFIG_XEN ++ ++#define INVALID_P2M_ENTRY (~0UL) ++ ++#ifdef CONFIG_XEN_IA64_EXPOSE_P2M ++extern int p2m_initialized; ++extern unsigned long p2m_min_low_pfn; ++extern unsigned long p2m_max_low_pfn; ++extern unsigned long p2m_convert_min_pfn; ++extern unsigned long p2m_convert_max_pfn; ++extern volatile const pte_t* p2m_pte; ++unsigned long p2m_phystomach(unsigned long gpfn); ++#else ++#define p2m_initialized (0) ++#define p2m_phystomach(gpfn) INVALID_MFN ++#endif ++ ++/* XXX xen page size != page size */ ++static inline unsigned long ++pfn_to_mfn_for_dma(unsigned long pfn) ++{ ++ unsigned long mfn; ++ if (p2m_initialized) ++ return p2m_phystomach(pfn); ++ mfn = HYPERVISOR_phystomach(pfn); ++ BUG_ON(mfn == 0); // XXX ++ BUG_ON(mfn == INVALID_P2M_ENTRY); // XXX ++ BUG_ON(mfn == INVALID_MFN); ++ return mfn; ++} ++ ++static inline unsigned long ++phys_to_machine_for_dma(unsigned long phys) ++{ ++ unsigned long machine = ++ pfn_to_mfn_for_dma(phys >> PAGE_SHIFT) << PAGE_SHIFT; ++ machine |= (phys & ~PAGE_MASK); ++ return machine; ++} ++ ++static inline unsigned long ++mfn_to_pfn_for_dma(unsigned long mfn) ++{ ++ unsigned long pfn; ++ pfn = HYPERVISOR_machtophys(mfn); ++ BUG_ON(pfn == 0); ++ //BUG_ON(pfn == INVALID_M2P_ENTRY); ++ return pfn; ++} ++ ++static inline unsigned long ++machine_to_phys_for_dma(unsigned long machine) ++{ ++ unsigned long phys = ++ mfn_to_pfn_for_dma(machine >> PAGE_SHIFT) << PAGE_SHIFT; ++ phys |= (machine & ~PAGE_MASK); ++ return phys; ++} ++ ++static inline unsigned long ++mfn_to_local_pfn(unsigned long mfn) ++{ ++ unsigned long pfn = mfn_to_pfn_for_dma(mfn); ++ if (!pfn_valid(pfn)) ++ return INVALID_P2M_ENTRY; ++ return pfn; ++} ++ ++#else /* !CONFIG_XEN */ ++ ++#define pfn_to_mfn_for_dma(pfn) (pfn) ++#define mfn_to_pfn_for_dma(mfn) (mfn) ++#define phys_to_machine_for_dma(phys) (phys) ++#define machine_to_phys_for_dma(machine) (machine) ++#define mfn_to_local_pfn(mfn) (mfn) ++ ++#endif /* !CONFIG_XEN */ ++ ++#define mfn_to_pfn(mfn) (mfn) ++#define pfn_to_mfn(pfn) (pfn) ++ ++#define mfn_to_virt(mfn) (__va((mfn) << PAGE_SHIFT)) ++#define virt_to_mfn(virt) (__pa(virt) >> PAGE_SHIFT) ++#define virt_to_machine(virt) __pa(virt) // for tpmfront.c ++ ++#define set_phys_to_machine(pfn, mfn) do { } while (0) ++ ++typedef unsigned long maddr_t; // to compile netback, netfront ++ ++#endif /* _ASM_IA64_MADDR_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/meminit.h +--- a/include/asm-ia64/meminit.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/meminit.h Wed Aug 08 16:25:28 2007 -0300 +@@ -17,10 +17,15 @@ + * - kernel code & data + * - crash dumping code reserved region + * - Kernel memory map built from EFI memory map ++ * - xen start info + * + * More could be added if necessary + */ ++#ifndef CONFIG_XEN + #define IA64_MAX_RSVD_REGIONS 7 ++#else ++#define IA64_MAX_RSVD_REGIONS 8 ++#endif + + struct rsvd_region { + unsigned long start; /* virtual address of beginning of element */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/page.h +--- a/include/asm-ia64/page.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/page.h Wed Aug 08 16:25:28 2007 -0300 +@@ -118,6 +118,7 @@ extern struct page *vmem_map; + #endif + + #ifdef CONFIG_FLATMEM ++extern unsigned long max_mapnr; + # define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) + #elif defined(CONFIG_DISCONTIGMEM) + extern unsigned long min_low_pfn; +@@ -125,7 +126,9 @@ extern unsigned long max_low_pfn; + # define pfn_valid(pfn) (((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn) && ia64_pfn_valid(pfn)) + #endif + ++#ifndef CONFIG_XEN + #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) ++#endif + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) + #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +@@ -226,5 +229,24 @@ get_order (unsigned long size) + (((current->personality & READ_IMPLIES_EXEC) != 0) \ + ? VM_EXEC : 0)) + +-# endif /* __KERNEL__ */ ++#ifndef __ASSEMBLY__ ++#ifdef CONFIG_XEN ++ ++#include <linux/kernel.h> ++#include <asm/hypervisor.h> ++#include <xen/features.h> // to compile netback, netfront ++#include <asm/maddr.h> ++ ++#define arch_free_page(_page, _order) \ ++({ \ ++ int foreign = PageForeign(_page); \ ++ if (foreign) \ ++ PageForeignDestructor(_page); \ ++ foreign; \ ++}) ++#define HAVE_ARCH_FREE_PAGE ++ ++#endif /* CONFIG_XEN */ ++#endif /* __ASSEMBLY__ */ ++#endif /* __KERNEL__ */ + #endif /* _ASM_IA64_PAGE_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/pal.h +--- a/include/asm-ia64/pal.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/pal.h Wed Aug 08 16:25:28 2007 -0300 +@@ -92,6 +92,7 @@ + #ifndef __ASSEMBLY__ + + #include <linux/types.h> ++#include <asm/processor.h> + #include <asm/fpu.h> + + /* +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/pgalloc.h +--- a/include/asm-ia64/pgalloc.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/pgalloc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -125,7 +125,11 @@ static inline void + static inline void + pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte) + { ++#ifndef CONFIG_XEN + pmd_val(*pmd_entry) = page_to_phys(pte); ++#else ++ pmd_val(*pmd_entry) = page_to_pseudophys(pte); ++#endif + } + + static inline void +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/privop.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/privop.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,60 @@ ++#ifndef _ASM_IA64_PRIVOP_H ++#define _ASM_IA64_PRIVOP_H ++ ++/* ++ * Copyright (C) 2005 Hewlett-Packard Co ++ * Dan Magenheimer <dan.magenheimer@hp.com> ++ * ++ */ ++ ++#ifdef CONFIG_XEN ++#include <asm/xen/privop.h> ++#endif ++ ++#ifndef __ASSEMBLY ++ ++#ifndef IA64_PARAVIRTUALIZED ++ ++#define ia64_getreg __ia64_getreg ++#define ia64_setreg __ia64_setreg ++#define ia64_hint __ia64_hint ++#define ia64_thash __ia64_thash ++#define ia64_itci __ia64_itci ++#define ia64_itcd __ia64_itcd ++#define ia64_itri __ia64_itri ++#define ia64_itrd __ia64_itrd ++#define ia64_tpa __ia64_tpa ++#define ia64_set_ibr __ia64_set_ibr ++#define ia64_set_pkr __ia64_set_pkr ++#define ia64_set_pmc __ia64_set_pmc ++#define ia64_set_pmd __ia64_set_pmd ++#define ia64_set_rr __ia64_set_rr ++#define ia64_get_cpuid __ia64_get_cpuid ++#define ia64_get_ibr __ia64_get_ibr ++#define ia64_get_pkr __ia64_get_pkr ++#define ia64_get_pmc __ia64_get_pmc ++#define ia64_get_pmd __ia64_get_pmd ++#define ia64_get_rr __ia64_get_rr ++#define ia64_fc __ia64_fc ++#define ia64_ssm __ia64_ssm ++#define ia64_rsm __ia64_rsm ++#define ia64_ptce __ia64_ptce ++#define ia64_ptcga __ia64_ptcga ++#define ia64_ptcl __ia64_ptcl ++#define ia64_ptri __ia64_ptri ++#define ia64_ptrd __ia64_ptrd ++#define ia64_get_psr_i __ia64_get_psr_i ++#define ia64_intrin_local_irq_restore __ia64_intrin_local_irq_restore ++#define ia64_pal_halt_light __ia64_pal_halt_light ++#define ia64_leave_kernel __ia64_leave_kernel ++#define ia64_leave_syscall __ia64_leave_syscall ++#define ia64_trace_syscall __ia64_trace_syscall ++#define ia64_ret_from_clone __ia64_ret_from_clone ++#define ia64_switch_to __ia64_switch_to ++#define ia64_pal_call_static __ia64_pal_call_static ++ ++#endif /* !IA64_PARAVIRTUALIZED */ ++ ++#endif /* !__ASSEMBLY */ ++ ++#endif /* _ASM_IA64_PRIVOP_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/processor.h +--- a/include/asm-ia64/processor.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/processor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -18,6 +18,7 @@ + #include <asm/kregs.h> + #include <asm/ptrace.h> + #include <asm/ustack.h> ++#include <asm/privop.h> + + #define IA64_NUM_DBG_REGS 8 + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/sal.h +--- a/include/asm-ia64/sal.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/sal.h Wed Aug 08 16:25:28 2007 -0300 +@@ -42,6 +42,9 @@ + #include <asm/pal.h> + #include <asm/system.h> + #include <asm/fpu.h> ++#ifdef CONFIG_XEN ++#include <asm/xen/xencomm.h> ++#endif + + extern spinlock_t sal_lock; + +@@ -687,10 +690,28 @@ ia64_sal_clear_state_info (u64 sal_info_ + /* Get the processor and platform information logged by SAL with respect to the machine + * state at the time of the MCAs, INITs, CMCs, or CPEs. + */ ++#ifdef CONFIG_XEN ++static inline u64 ia64_sal_get_state_info_size (u64 sal_info_type); ++#endif ++ + static inline u64 + ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) + { + struct ia64_sal_retval isrv; ++#ifdef CONFIG_XEN ++ if (is_running_on_xen()) { ++ struct xencomm_handle *desc; ++ ++ if (xencomm_create(sal_info, ++ ia64_sal_get_state_info_size(sal_info_type), ++ &desc, GFP_KERNEL)) ++ return 0; ++ ++ SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, ++ desc, 0, 0, 0, 0); ++ xencomm_free(desc); ++ } else ++#endif + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, + sal_info, 0, 0, 0, 0); + if (isrv.status) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/swiotlb.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/swiotlb.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,41 @@ ++#ifndef _ASM_SWIOTLB_H ++#define _ASM_SWIOTLB_H 1 ++ ++/* SWIOTLB interface */ ++ ++extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, ++ int dir); ++extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_single_for_cpu(struct device *hwdev, ++ dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_single_for_device(struct device *hwdev, ++ dma_addr_t dev_addr, ++ size_t size, int dir); ++extern void swiotlb_sync_sg_for_cpu(struct device *hwdev, ++ struct scatterlist *sg, int nelems, ++ int dir); ++extern void swiotlb_sync_sg_for_device(struct device *hwdev, ++ struct scatterlist *sg, int nelems, ++ int dir); ++extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, ++ int nents, int direction); ++extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, ++ int nents, int direction); ++extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr); ++extern dma_addr_t swiotlb_map_page(struct device *hwdev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction direction); ++extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dma_address, ++ size_t size, enum dma_data_direction direction); ++extern int swiotlb_dma_supported(struct device *hwdev, u64 mask); ++extern void swiotlb_init(void); ++ ++#ifdef CONFIG_SWIOTLB ++extern int swiotlb; ++#else ++#define swiotlb 0 ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/synch_bitops.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/synch_bitops.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,61 @@ ++#ifndef __XEN_SYNCH_BITOPS_H__ ++#define __XEN_SYNCH_BITOPS_H__ ++ ++/* ++ * Copyright 1992, Linus Torvalds. ++ * Heavily modified to provide guaranteed strong synchronisation ++ * when communicating with Xen or other guest OSes running on other CPUs. ++ */ ++ ++#define ADDR (*(volatile long *) addr) ++ ++static __inline__ void synch_set_bit(int nr, volatile void * addr) ++{ ++ set_bit(nr, addr); ++} ++ ++static __inline__ void synch_clear_bit(int nr, volatile void * addr) ++{ ++ clear_bit(nr, addr); ++} ++ ++static __inline__ void synch_change_bit(int nr, volatile void * addr) ++{ ++ change_bit(nr, addr); ++} ++ ++static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr) ++{ ++ return test_and_set_bit(nr, addr); ++} ++ ++static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr) ++{ ++ return test_and_clear_bit(nr, addr); ++} ++ ++static __inline__ int synch_test_and_change_bit(int nr, volatile void * addr) ++{ ++ return test_and_change_bit(nr, addr); ++} ++ ++static __inline__ int synch_const_test_bit(int nr, const volatile void * addr) ++{ ++ return test_bit(nr, addr); ++} ++ ++static __inline__ int synch_var_test_bit(int nr, volatile void * addr) ++{ ++ return test_bit(nr, addr); ++} ++ ++#define synch_cmpxchg ia64_cmpxchg4_acq ++ ++#define synch_test_bit(nr,addr) \ ++(__builtin_constant_p(nr) ? \ ++ synch_const_test_bit((nr),(addr)) : \ ++ synch_var_test_bit((nr),(addr))) ++ ++#define synch_cmpxchg_subword synch_cmpxchg ++ ++#endif /* __XEN_SYNCH_BITOPS_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/system.h +--- a/include/asm-ia64/system.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/system.h Wed Aug 08 16:25:28 2007 -0300 +@@ -123,7 +123,7 @@ extern struct ia64_boot_param { + #define __local_irq_save(x) \ + do { \ + ia64_stop(); \ +- (x) = ia64_getreg(_IA64_REG_PSR); \ ++ (x) = ia64_get_psr_i(); \ + ia64_stop(); \ + ia64_rsm(IA64_PSR_I); \ + } while (0) +@@ -171,7 +171,7 @@ do { \ + #endif /* !CONFIG_IA64_DEBUG_IRQ */ + + #define local_irq_enable() ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); }) +-#define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_getreg(_IA64_REG_PSR); }) ++#define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_get_psr_i(); }) + + #define irqs_disabled() \ + ({ \ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/uaccess.h +--- a/include/asm-ia64/uaccess.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-ia64/uaccess.h Wed Aug 08 16:25:28 2007 -0300 +@@ -365,6 +365,7 @@ ia64_done_with_exception (struct pt_regs + } + + #define ARCH_HAS_TRANSLATE_MEM_PTR 1 ++#ifndef CONFIG_XEN + static __inline__ char * + xlate_dev_mem_ptr (unsigned long p) + { +@@ -379,6 +380,25 @@ xlate_dev_mem_ptr (unsigned long p) + + return ptr; + } ++#else ++static __inline__ char * ++xlate_dev_mem_ptr (unsigned long p, ssize_t sz) ++{ ++ unsigned long pfn = p >> PAGE_SHIFT; ++ ++ if (pfn_valid(pfn) && !PageUncached(pfn_to_page(pfn))) ++ return __va(p); ++ ++ return ioremap(p, sz); ++} ++ ++static __inline__ void ++xlate_dev_mem_ptr_unmap (char* v) ++{ ++ if (REGION_NUMBER(v) == RGN_UNCACHED) ++ iounmap(v); ++} ++#endif + + /* + * Convert a virtual cached kernel memory pointer to an uncached pointer +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/xen/privop.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/xen/privop.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,310 @@ ++#ifndef _ASM_IA64_XEN_PRIVOP_H ++#define _ASM_IA64_XEN_PRIVOP_H ++ ++/* ++ * Copyright (C) 2005 Hewlett-Packard Co ++ * Dan Magenheimer <dan.magenheimer@hp.com> ++ * ++ * Paravirtualizations of privileged operations for Xen/ia64 ++ * ++ */ ++ ++ ++#include <xen/interface/arch-ia64.h> ++ ++#define IA64_PARAVIRTUALIZED ++ ++/* At 1 MB, before per-cpu space but still addressable using addl instead ++ of movl. */ ++#define XSI_BASE 0xfffffffffff00000 ++ ++/* Address of mapped regs. */ ++#define XMAPPEDREGS_BASE (XSI_BASE + XSI_SIZE) ++ ++#ifdef __ASSEMBLY__ ++#define XEN_HYPER_RFI break HYPERPRIVOP_RFI ++#define XEN_HYPER_RSM_PSR_DT break HYPERPRIVOP_RSM_DT ++#define XEN_HYPER_SSM_PSR_DT break HYPERPRIVOP_SSM_DT ++#define XEN_HYPER_COVER break HYPERPRIVOP_COVER ++#define XEN_HYPER_ITC_D break HYPERPRIVOP_ITC_D ++#define XEN_HYPER_ITC_I break HYPERPRIVOP_ITC_I ++#define XEN_HYPER_SSM_I break HYPERPRIVOP_SSM_I ++#define XEN_HYPER_GET_IVR break HYPERPRIVOP_GET_IVR ++#define XEN_HYPER_GET_TPR break HYPERPRIVOP_GET_TPR ++#define XEN_HYPER_SET_TPR break HYPERPRIVOP_SET_TPR ++#define XEN_HYPER_EOI break HYPERPRIVOP_EOI ++#define XEN_HYPER_SET_ITM break HYPERPRIVOP_SET_ITM ++#define XEN_HYPER_THASH break HYPERPRIVOP_THASH ++#define XEN_HYPER_PTC_GA break HYPERPRIVOP_PTC_GA ++#define XEN_HYPER_ITR_D break HYPERPRIVOP_ITR_D ++#define XEN_HYPER_GET_RR break HYPERPRIVOP_GET_RR ++#define XEN_HYPER_SET_RR break HYPERPRIVOP_SET_RR ++#define XEN_HYPER_SET_KR break HYPERPRIVOP_SET_KR ++#define XEN_HYPER_FC break HYPERPRIVOP_FC ++#define XEN_HYPER_GET_CPUID break HYPERPRIVOP_GET_CPUID ++#define XEN_HYPER_GET_PMD break HYPERPRIVOP_GET_PMD ++#define XEN_HYPER_GET_EFLAG break HYPERPRIVOP_GET_EFLAG ++#define XEN_HYPER_SET_EFLAG break HYPERPRIVOP_SET_EFLAG ++#define XEN_HYPER_GET_PSR break HYPERPRIVOP_GET_PSR ++ ++#define XSI_IFS (XSI_BASE + XSI_IFS_OFS) ++#define XSI_PRECOVER_IFS (XSI_BASE + XSI_PRECOVER_IFS_OFS) ++#define XSI_IFA (XSI_BASE + XSI_IFA_OFS) ++#define XSI_ISR (XSI_BASE + XSI_ISR_OFS) ++#define XSI_IIM (XSI_BASE + XSI_IIM_OFS) ++#define XSI_ITIR (XSI_BASE + XSI_ITIR_OFS) ++#define XSI_PSR_I_ADDR (XSI_BASE + XSI_PSR_I_ADDR_OFS) ++#define XSI_PSR_IC (XSI_BASE + XSI_PSR_IC_OFS) ++#define XSI_IPSR (XSI_BASE + XSI_IPSR_OFS) ++#define XSI_IIP (XSI_BASE + XSI_IIP_OFS) ++#define XSI_B1NAT (XSI_BASE + XSI_B1NATS_OFS) ++#define XSI_BANK1_R16 (XSI_BASE + XSI_BANK1_R16_OFS) ++#define XSI_BANKNUM (XSI_BASE + XSI_BANKNUM_OFS) ++#define XSI_IHA (XSI_BASE + XSI_IHA_OFS) ++#endif ++ ++#ifndef __ASSEMBLY__ ++#define XEN_HYPER_SSM_I asm("break %0" : : "i" (HYPERPRIVOP_SSM_I)) ++#define XEN_HYPER_GET_IVR asm("break %0" : : "i" (HYPERPRIVOP_GET_IVR)) ++ ++/************************************************/ ++/* Instructions paravirtualized for correctness */ ++/************************************************/ ++ ++/* "fc" and "thash" are privilege-sensitive instructions, meaning they ++ * may have different semantics depending on whether they are executed ++ * at PL0 vs PL!=0. When paravirtualized, these instructions mustn't ++ * be allowed to execute directly, lest incorrect semantics result. */ ++extern unsigned long xen_fc(unsigned long addr); ++#define ia64_fc(addr) xen_fc((unsigned long)(addr)) ++extern unsigned long xen_thash(unsigned long addr); ++#define ia64_thash(addr) xen_thash((unsigned long)(addr)) ++/* Note that "ttag" and "cover" are also privilege-sensitive; "ttag" ++ * is not currently used (though it may be in a long-format VHPT system!) ++ * and the semantics of cover only change if psr.ic is off which is very ++ * rare (and currently non-existent outside of assembly code */ ++ ++/* There are also privilege-sensitive registers. These registers are ++ * readable at any privilege level but only writable at PL0. */ ++extern unsigned long xen_get_cpuid(int index); ++#define ia64_get_cpuid(i) xen_get_cpuid(i) ++extern unsigned long xen_get_pmd(int index); ++#define ia64_get_pmd(i) xen_get_pmd(i) ++extern unsigned long xen_get_eflag(void); /* see xen_ia64_getreg */ ++extern void xen_set_eflag(unsigned long); /* see xen_ia64_setreg */ ++ ++/************************************************/ ++/* Instructions paravirtualized for performance */ ++/************************************************/ ++ ++/* Xen uses memory-mapped virtual privileged registers for access to many ++ * performance-sensitive privileged registers. Some, like the processor ++ * status register (psr), are broken up into multiple memory locations. ++ * Others, like "pend", are abstractions based on privileged registers. ++ * "Pend" is guaranteed to be set if reading cr.ivr would return a ++ * (non-spurious) interrupt. */ ++#define XEN_MAPPEDREGS ((struct mapped_regs *)XMAPPEDREGS_BASE) ++#define XSI_PSR_I \ ++ (*XEN_MAPPEDREGS->interrupt_mask_addr) ++#define xen_get_virtual_psr_i() \ ++ (!XSI_PSR_I) ++#define xen_set_virtual_psr_i(_val) \ ++ ({ XSI_PSR_I = (uint8_t)(_val) ? 0 : 1; }) ++#define xen_set_virtual_psr_ic(_val) \ ++ ({ XEN_MAPPEDREGS->interrupt_collection_enabled = _val ? 1 : 0; }) ++#define xen_get_virtual_pend() \ ++ (*(((uint8_t *)XEN_MAPPEDREGS->interrupt_mask_addr) - 1)) ++ ++/* Hyperprivops are "break" instructions with a well-defined API. ++ * In particular, the virtual psr.ic bit must be off; in this way ++ * it is guaranteed to never conflict with a linux break instruction. ++ * Normally, this is done in a xen stub but this one is frequent enough ++ * that we inline it */ ++#define xen_hyper_ssm_i() \ ++({ \ ++ XEN_HYPER_SSM_I; \ ++}) ++ ++/* turning off interrupts can be paravirtualized simply by writing ++ * to a memory-mapped virtual psr.i bit (implemented as a 16-bit bool) */ ++#define xen_rsm_i() xen_set_virtual_psr_i(0) ++ ++/* turning on interrupts is a bit more complicated.. write to the ++ * memory-mapped virtual psr.i bit first (to avoid race condition), ++ * then if any interrupts were pending, we have to execute a hyperprivop ++ * to ensure the pending interrupt gets delivered; else we're done! */ ++#define xen_ssm_i() \ ++({ \ ++ int old = xen_get_virtual_psr_i(); \ ++ if (!old) { \ ++ if (xen_get_virtual_pend()) \ ++ xen_hyper_ssm_i(); \ ++ else \ ++ xen_set_virtual_psr_i(1); \ ++ } \ ++}) ++ ++#define xen_ia64_intrin_local_irq_restore(x) \ ++{ \ ++ if (is_running_on_xen()) { \ ++ if ((x) & IA64_PSR_I) { xen_ssm_i(); } \ ++ else { xen_rsm_i(); } \ ++ } \ ++ else __ia64_intrin_local_irq_restore((x)); \ ++} ++ ++#define xen_get_psr_i() \ ++( \ ++ (is_running_on_xen()) ? \ ++ (xen_get_virtual_psr_i() ? IA64_PSR_I : 0) \ ++ : __ia64_get_psr_i() \ ++) ++ ++#define xen_ia64_ssm(mask) \ ++{ \ ++ if ((mask)==IA64_PSR_I) { \ ++ if (is_running_on_xen()) { xen_ssm_i(); } \ ++ else { __ia64_ssm(mask); } \ ++ } \ ++ else { __ia64_ssm(mask); } \ ++} ++ ++#define xen_ia64_rsm(mask) \ ++{ \ ++ if ((mask)==IA64_PSR_I) { \ ++ if (is_running_on_xen()) { xen_rsm_i(); } \ ++ else { __ia64_rsm(mask); } \ ++ } \ ++ else { __ia64_rsm(mask); } \ ++} ++ ++ ++/* Although all privileged operations can be left to trap and will ++ * be properly handled by Xen, some are frequent enough that we use ++ * hyperprivops for performance. */ ++ ++extern unsigned long xen_get_psr(void); ++extern unsigned long xen_get_ivr(void); ++extern unsigned long xen_get_tpr(void); ++extern void xen_set_itm(unsigned long); ++extern void xen_set_tpr(unsigned long); ++extern void xen_eoi(void); ++extern void xen_set_rr(unsigned long index, unsigned long val); ++extern unsigned long xen_get_rr(unsigned long index); ++extern void xen_set_kr(unsigned long index, unsigned long val); ++extern void xen_ptcga(unsigned long addr, unsigned long size); ++ ++/* Note: It may look wrong to test for is_running_on_xen() in each case. ++ * However regnum is always a constant so, as written, the compiler ++ * eliminates the switch statement, whereas is_running_on_xen() must be ++ * tested dynamically. */ ++#define xen_ia64_getreg(regnum) \ ++({ \ ++ __u64 ia64_intri_res; \ ++ \ ++ switch(regnum) { \ ++ case _IA64_REG_PSR: \ ++ ia64_intri_res = (is_running_on_xen()) ? \ ++ xen_get_psr() : \ ++ __ia64_getreg(regnum); \ ++ break; \ ++ case _IA64_REG_CR_IVR: \ ++ ia64_intri_res = (is_running_on_xen()) ? \ ++ xen_get_ivr() : \ ++ __ia64_getreg(regnum); \ ++ break; \ ++ case _IA64_REG_CR_TPR: \ ++ ia64_intri_res = (is_running_on_xen()) ? \ ++ xen_get_tpr() : \ ++ __ia64_getreg(regnum); \ ++ break; \ ++ case _IA64_REG_AR_EFLAG: \ ++ ia64_intri_res = (is_running_on_xen()) ? \ ++ xen_get_eflag() : \ ++ __ia64_getreg(regnum); \ ++ break; \ ++ default: \ ++ ia64_intri_res = __ia64_getreg(regnum); \ ++ break; \ ++ } \ ++ ia64_intri_res; \ ++}) ++ ++#define xen_ia64_setreg(regnum,val) \ ++({ \ ++ switch(regnum) { \ ++ case _IA64_REG_AR_KR0 ... _IA64_REG_AR_KR7: \ ++ (is_running_on_xen()) ? \ ++ xen_set_kr((regnum-_IA64_REG_AR_KR0), val) : \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ case _IA64_REG_CR_ITM: \ ++ (is_running_on_xen()) ? \ ++ xen_set_itm(val) : \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ case _IA64_REG_CR_TPR: \ ++ (is_running_on_xen()) ? \ ++ xen_set_tpr(val) : \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ case _IA64_REG_CR_EOI: \ ++ (is_running_on_xen()) ? \ ++ xen_eoi() : \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ case _IA64_REG_AR_EFLAG: \ ++ (is_running_on_xen()) ? \ ++ xen_set_eflag(val) : \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ default: \ ++ __ia64_setreg(regnum,val); \ ++ break; \ ++ } \ ++}) ++ ++#define ia64_ssm xen_ia64_ssm ++#define ia64_rsm xen_ia64_rsm ++#define ia64_intrin_local_irq_restore xen_ia64_intrin_local_irq_restore ++#define ia64_ptcga xen_ptcga ++#define ia64_set_rr(index,val) xen_set_rr(index,val) ++#define ia64_get_rr(index) xen_get_rr(index) ++#define ia64_getreg xen_ia64_getreg ++#define ia64_setreg xen_ia64_setreg ++#define ia64_get_psr_i xen_get_psr_i ++ ++/* the remainder of these are not performance-sensitive so its ++ * OK to not paravirtualize and just take a privop trap and emulate */ ++#define ia64_hint __ia64_hint ++#define ia64_set_pmd __ia64_set_pmd ++#define ia64_itci __ia64_itci ++#define ia64_itcd __ia64_itcd ++#define ia64_itri __ia64_itri ++#define ia64_itrd __ia64_itrd ++#define ia64_tpa __ia64_tpa ++#define ia64_set_ibr __ia64_set_ibr ++#define ia64_set_pkr __ia64_set_pkr ++#define ia64_set_pmc __ia64_set_pmc ++#define ia64_get_ibr __ia64_get_ibr ++#define ia64_get_pkr __ia64_get_pkr ++#define ia64_get_pmc __ia64_get_pmc ++#define ia64_ptce __ia64_ptce ++#define ia64_ptcl __ia64_ptcl ++#define ia64_ptri __ia64_ptri ++#define ia64_ptrd __ia64_ptrd ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* these routines utilize privilege-sensitive or performance-sensitive ++ * privileged instructions so the code must be replaced with ++ * paravirtualized versions */ ++#define ia64_pal_halt_light xen_pal_halt_light ++#define ia64_leave_kernel xen_leave_kernel ++#define ia64_leave_syscall xen_leave_syscall ++#define ia64_trace_syscall xen_trace_syscall ++#define ia64_ret_from_clone xen_ret_from_clone ++#define ia64_switch_to xen_switch_to ++#define ia64_pal_call_static xen_pal_call_static ++ ++#endif /* _ASM_IA64_XEN_PRIVOP_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/xen/xcom_hcall.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/xen/xcom_hcall.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2006 Tristan Gingold <tristan.gingold@bull.net>, Bull SAS ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _LINUX_XENCOMM_HCALL_H_ ++#define _LINUX_XENCOMM_HCALL_H_ ++ ++/* These function creates inline descriptor for the parameters and ++ calls the corresponding xencomm_arch_hypercall_X. ++ Architectures should defines HYPERVISOR_xxx as xencomm_hypercall_xxx unless ++ they want to use their own wrapper. */ ++extern int xencomm_hypercall_console_io(int cmd, int count, char *str); ++ ++extern int xencomm_hypercall_event_channel_op(int cmd, void *op); ++ ++extern int xencomm_hypercall_xen_version(int cmd, void *arg); ++ ++extern int xencomm_hypercall_physdev_op(int cmd, void *op); ++ ++extern int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, ++ unsigned int count); ++ ++extern int xencomm_hypercall_sched_op(int cmd, void *arg); ++ ++extern int xencomm_hypercall_multicall(void *call_list, int nr_calls); ++ ++extern int xencomm_hypercall_callback_op(int cmd, void *arg); ++ ++extern int xencomm_hypercall_memory_op(unsigned int cmd, void *arg); ++ ++extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg); ++ ++extern int xencomm_hypercall_suspend(unsigned long srec); ++ ++extern int xencomm_hypercall_xenoprof_op(int op, void *arg); ++ ++extern int xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, ++ unsigned long count); ++ ++extern long xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg); ++ ++/* Using mini xencomm. */ ++extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str); ++ ++extern int xencomm_mini_hypercall_event_channel_op(int cmd, void *op); ++ ++extern int xencomm_mini_hypercall_xen_version(int cmd, void *arg); ++ ++extern int xencomm_mini_hypercall_physdev_op(int cmd, void *op); ++ ++extern int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, ++ unsigned int count); ++ ++extern int xencomm_mini_hypercall_sched_op(int cmd, void *arg); ++ ++extern int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls); ++ ++extern int xencomm_mini_hypercall_callback_op(int cmd, void *arg); ++ ++extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg); ++ ++extern unsigned long xencomm_mini_hypercall_hvm_op(int cmd, void *arg); ++ ++extern int xencomm_mini_hypercall_xenoprof_op(int op, void *arg); ++ ++extern int xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, ++ unsigned long count); ++ ++/* For privcmd. Locally declare argument type to avoid include storm. ++ Type coherency will be checked within privcmd.c */ ++struct privcmd_hypercall; ++extern int privcmd_hypercall(struct privcmd_hypercall *hypercall); ++ ++#endif /* _LINUX_XENCOMM_HCALL_H_ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/xen/xencomm.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/xen/xencomm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _LINUX_XENCOMM_H_ ++#define _LINUX_XENCOMM_H_ ++ ++#include <xen/interface/xencomm.h> ++ ++#define XENCOMM_MINI_ADDRS 3 ++struct xencomm_mini { ++ struct xencomm_desc _desc; ++ uint64_t address[XENCOMM_MINI_ADDRS]; ++}; ++ ++/* Must be called before any hypercall. */ ++extern void xencomm_init (void); ++ ++/* To avoid additionnal virt to phys conversion, an opaque structure is ++ presented. */ ++struct xencomm_handle; ++ ++extern int xencomm_create(void *buffer, unsigned long bytes, ++ struct xencomm_handle **desc, gfp_t type); ++extern void xencomm_free(struct xencomm_handle *desc); ++ ++extern int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, ++ void *buffer, unsigned long bytes, ++ struct xencomm_handle **ret); ++ ++/* Translate virtual address to physical address. */ ++extern unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr); ++ ++/* Inline version. To be used only on linear space (kernel space). */ ++static inline struct xencomm_handle * ++xencomm_create_inline(void *buffer) ++{ ++ unsigned long paddr; ++ ++ paddr = xencomm_vaddr_to_paddr((unsigned long)buffer); ++ return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); ++} ++ ++#define xen_guest_handle(hnd) ((hnd).p) ++ ++#endif /* _LINUX_XENCOMM_H_ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-ia64/xenoprof.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-ia64/xenoprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,48 @@ ++/****************************************************************************** ++ * asm-ia64/xenoprof.h ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#ifndef __ASM_XENOPROF_H__ ++#define __ASM_XENOPROF_H__ ++#ifdef CONFIG_XEN ++ ++#undef HAVE_XENOPROF_CREATE_FILES ++ ++struct xenoprof_init; ++void xenoprof_arch_init_counter(struct xenoprof_init *init); ++void xenoprof_arch_counter(void); ++void xenoprof_arch_start(void); ++void xenoprof_arch_stop(void); ++ ++struct xenoprof_arch_shared_buffer { ++ struct resource* res; ++}; ++ ++struct xenoprof_shared_buffer; ++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf); ++struct xenoprof_get_buffer; ++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, ++ struct xenoprof_shared_buffer* sbuf); ++struct xenoprof_passive; ++int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, ++ struct xenoprof_shared_buffer* sbuf); ++ ++#endif /* CONFIG_XEN */ ++#endif /* __ASM_XENOPROF_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-um/page.h +--- a/include/asm-um/page.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-um/page.h Wed Aug 08 16:25:28 2007 -0300 +@@ -114,7 +114,7 @@ extern struct page *arch_validate(struct + extern struct page *arch_validate(struct page *page, gfp_t mask, int order); + #define HAVE_ARCH_VALIDATE + +-extern void arch_free_page(struct page *page, int order); ++extern int arch_free_page(struct page *page, int order); + #define HAVE_ARCH_FREE_PAGE + + #include <asm-generic/memory_model.h> +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/apic.h +--- a/include/asm-x86_64/apic.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/apic.h Wed Aug 08 16:25:28 2007 -0300 +@@ -95,11 +95,13 @@ extern void setup_APIC_extened_lvt(unsig + #define K8_APIC_EXT_INT_MSG_EXT 0x7 + #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0 + ++#ifndef CONFIG_XEN + void smp_send_timer_broadcast_ipi(void); + void switch_APIC_timer_to_ipi(void *cpumask); + void switch_ipi_to_APIC_timer(void *cpumask); + + #define ARCH_APICTIMER_STOPS_ON_C3 1 ++#endif + + extern unsigned boot_cpu_id; + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/bootsetup.h +--- a/include/asm-x86_64/bootsetup.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/bootsetup.h Wed Aug 08 16:25:28 2007 -0300 +@@ -24,9 +24,15 @@ extern char x86_boot_params[BOOT_PARAM_S + #define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) + #define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) + #define KERNEL_START (*(unsigned int *) (PARAM+0x214)) ++#ifdef CONFIG_XEN ++#define INITRD_START (__pa(xen_start_info->mod_start)) ++#define INITRD_SIZE (xen_start_info->mod_len) ++#define EDID_INFO (*(struct edid_info *) (PARAM+0x440)) ++#else + #define INITRD_START (*(unsigned int *) (PARAM+0x218)) + #define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c)) + #define EDID_INFO (*(struct edid_info *) (PARAM+0x140)) ++#endif /* CONFIG_XEN */ + #define EDD_NR (*(unsigned char *) (PARAM+EDDNR)) + #define EDD_MBR_SIG_NR (*(unsigned char *) (PARAM+EDD_MBR_SIG_NR_BUF)) + #define EDD_MBR_SIGNATURE ((unsigned int *) (PARAM+EDD_MBR_SIG_BUF)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/desc.h +--- a/include/asm-x86_64/desc.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/desc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -18,14 +18,31 @@ extern struct desc_struct cpu_gdt_table[ + + #define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8)) + #define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8)) ++#ifdef CONFIG_XEN ++static inline void clear_LDT(void) ++{ ++ int cpu = get_cpu(); ++ ++ /* ++ * NB. We load the default_ldt for lcall7/27 handling on demand, as ++ * it slows down context switching. Noone uses it anyway. ++ */ ++ cpu = cpu; /* XXX avoid compiler warning */ ++ xen_set_ldt(0UL, 0); ++ put_cpu(); ++} ++#else + #define clear_LDT() asm volatile("lldt %w0"::"r" (0)) ++#endif + + /* + * This is the ldt that every process will get unless we need + * something other than this. + */ + extern struct desc_struct default_ldt[]; ++#ifndef CONFIG_X86_NO_IDT + extern struct gate_struct idt_table[]; ++#endif + extern struct desc_ptr cpu_gdt_descr[]; + + /* the cpu gdt accessor */ +@@ -48,6 +65,7 @@ static inline void _set_gate(void *adr, + memcpy(adr, &s, 16); + } + ++#ifndef CONFIG_X86_NO_IDT + static inline void set_intr_gate(int nr, void *func) + { + BUG_ON((unsigned)nr > 0xFF); +@@ -70,6 +88,7 @@ static inline void set_system_gate_ist(i + { + _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); + } ++#endif + + static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, + unsigned size) +@@ -87,6 +106,7 @@ static inline void set_tssldt_descriptor + memcpy(ptr, &d, 16); + } + ++#ifndef CONFIG_X86_NO_TSS + static inline void set_tss_desc(unsigned cpu, void *addr) + { + /* +@@ -100,6 +120,7 @@ static inline void set_tss_desc(unsigned + (unsigned long)addr, DESC_TSS, + IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1); + } ++#endif + + static inline void set_ldt_desc(unsigned cpu, void *addr, int size) + { +@@ -151,10 +172,18 @@ static inline void set_seg_base(unsigned + + static inline void load_TLS(struct thread_struct *t, unsigned int cpu) + { ++#ifdef CONFIG_XEN ++#define C(i) \ ++ HYPERVISOR_update_descriptor(virt_to_machine(&cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]), t->tls_array[i]) ++ ++ C(0); C(1); C(2); ++#undef C ++#else + u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN); + gdt[0] = t->tls_array[0]; + gdt[1] = t->tls_array[1]; + gdt[2] = t->tls_array[2]; ++#endif + } + + /* +@@ -162,6 +191,15 @@ static inline void load_TLS(struct threa + */ + static inline void load_LDT_nolock (mm_context_t *pc, int cpu) + { ++#ifdef CONFIG_XEN ++ void *segments = pc->ldt; ++ int count = pc->size; ++ ++ if (likely(!count)) ++ segments = NULL; ++ ++ xen_set_ldt((unsigned long)segments, count); ++#else + int count = pc->size; + + if (likely(!count)) { +@@ -171,6 +209,7 @@ static inline void load_LDT_nolock (mm_c + + set_ldt_desc(cpu, pc->ldt, count); + load_LDT_desc(); ++#endif + } + + static inline void load_LDT(mm_context_t *pc) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/dma-mapping.h +--- a/include/asm-x86_64/dma-mapping.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/dma-mapping.h Wed Aug 08 16:25:28 2007 -0300 +@@ -55,6 +55,7 @@ extern struct dma_mapping_ops* dma_ops; + extern struct dma_mapping_ops* dma_ops; + extern int iommu_merge; + ++#ifndef CONFIG_XEN + static inline int dma_mapping_error(dma_addr_t dma_addr) + { + if (dma_ops->mapping_error) +@@ -195,6 +196,10 @@ dma_cache_sync(struct device *dev, void + } + + extern struct device fallback_dev; ++#else ++#include <asm-i386/mach-xen/asm/dma-mapping.h> ++#endif /* CONFIG_XEN */ ++ + extern int panic_on_overflow; + + #endif /* _X8664_DMA_MAPPING_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/dmi.h +--- a/include/asm-x86_64/dmi.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/dmi.h Wed Aug 08 16:25:28 2007 -0300 +@@ -5,6 +5,10 @@ + + extern void *dmi_ioremap(unsigned long addr, unsigned long size); + extern void dmi_iounmap(void *addr, unsigned long size); ++#ifdef CONFIG_XEN ++extern void *bt_ioremap(unsigned long addr, unsigned long size); ++extern void bt_iounmap(void *addr, unsigned long size); ++#endif + + #define DMI_MAX_DATA 2048 + +@@ -21,7 +25,12 @@ static inline void *dmi_alloc(unsigned l + return dmi_alloc_data + idx; + } + ++#ifdef CONFIG_XEN ++#define dmi_ioremap bt_ioremap ++#define dmi_iounmap bt_iounmap ++#else + #define dmi_ioremap early_ioremap + #define dmi_iounmap early_iounmap ++#endif + + #endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/dwarf2.h +--- a/include/asm-x86_64/dwarf2.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/dwarf2.h Wed Aug 08 16:25:28 2007 -0300 +@@ -13,7 +13,7 @@ + away for older version. + */ + +-#ifdef CONFIG_AS_CFI ++#ifdef CONFIG_UNWIND_INFO + + #define CFI_STARTPROC .cfi_startproc + #define CFI_ENDPROC .cfi_endproc +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/e820.h +--- a/include/asm-x86_64/e820.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/e820.h Wed Aug 08 16:25:28 2007 -0300 +@@ -41,13 +41,21 @@ extern void setup_memory_region(void); + extern void setup_memory_region(void); + extern void contig_e820_setup(void); + extern unsigned long e820_end_of_ram(void); ++#ifdef CONFIG_XEN ++extern void e820_reserve_resources(struct e820entry *e820, int nr_map); ++#else + extern void e820_reserve_resources(void); ++#endif + extern void e820_mark_nosave_regions(void); + extern void e820_print_map(char *who); + extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type); + extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type); + ++#ifdef CONFIG_XEN ++extern void e820_setup_gap(struct e820entry *e820, int nr_map); ++#else + extern void e820_setup_gap(void); ++#endif + extern void e820_register_active_regions(int nid, + unsigned long start_pfn, unsigned long end_pfn); + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/hw_irq.h +--- a/include/asm-x86_64/hw_irq.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/hw_irq.h Wed Aug 08 16:25:28 2007 -0300 +@@ -43,6 +43,7 @@ + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + */ ++#ifndef CONFIG_XEN + #define SPURIOUS_APIC_VECTOR 0xff + #define ERROR_APIC_VECTOR 0xfe + #define RESCHEDULE_VECTOR 0xfd +@@ -56,6 +57,7 @@ + #define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f7 used for TLB flush */ + + #define NUM_INVALIDATE_TLB_VECTORS 8 ++#endif + + /* + * Local APIC timer IRQ vector is on a different priority level, +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/ipi.h +--- a/include/asm-x86_64/ipi.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/ipi.h Wed Aug 08 16:25:28 2007 -0300 +@@ -49,8 +49,12 @@ static inline int __prepare_ICR2 (unsign + return SET_APIC_DEST_FIELD(mask); + } + ++ + static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest) + { ++#ifdef CONFIG_XEN_UNPRIVILEGED_GUEST ++ BUG(); ++#else + /* + * Subtle. In the case of the 'never do double writes' workaround + * we have to lock out interrupts to be safe. As we don't care +@@ -74,6 +78,7 @@ static inline void __send_IPI_shortcut(u + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write(APIC_ICR, cfg); ++#endif /* !CONFIG_XEN_UNPRIVILEGED_GUEST */ + } + + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/kexec.h +--- a/include/asm-x86_64/kexec.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/kexec.h Wed Aug 08 16:25:28 2007 -0300 +@@ -91,6 +91,19 @@ relocate_kernel(unsigned long indirectio + unsigned long page_list, + unsigned long start_address) ATTRIB_NORET; + ++/* Under Xen we need to work with machine addresses. These macros give the ++ * machine address of a certain page to the generic kexec code instead of ++ * the pseudo physical address which would be given by the default macros. ++ */ ++ ++#ifdef CONFIG_XEN ++#define KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) ++#define kexec_virt_to_phys(addr) virt_to_machine(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _X86_64_KEXEC_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/agp.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/agp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,35 @@ ++#ifndef AGP_H ++#define AGP_H 1 ++ ++#include <asm/cacheflush.h> ++#include <asm/system.h> ++ ++/* ++ * Functions to keep the agpgart mappings coherent. ++ * The GART gives the CPU a physical alias of memory. The alias is ++ * mapped uncacheable. Make sure there are no conflicting mappings ++ * with different cachability attributes for the same page. ++ */ ++ ++int map_page_into_agp(struct page *page); ++int unmap_page_from_agp(struct page *page); ++#define flush_agp_mappings() global_flush_tlb() ++ ++/* Could use CLFLUSH here if the cpu supports it. But then it would ++ need to be called for each cacheline of the whole page so it may not be ++ worth it. Would need a page for it. */ ++#define flush_agp_cache() wbinvd() ++ ++/* Convert a physical address to an address suitable for the GART. */ ++#define phys_to_gart(x) phys_to_machine(x) ++#define gart_to_phys(x) machine_to_phys(x) ++ ++/* GATT allocation. Returns/accepts GATT kernel virtual address. */ ++#define alloc_gatt_pages(order) ({ \ ++ char *_t; dma_addr_t _d; \ ++ _t = dma_alloc_coherent(NULL,PAGE_SIZE<<(order),&_d,GFP_KERNEL); \ ++ _t; }) ++#define free_gatt_pages(table, order) \ ++ dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table)) ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/fixmap.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/fixmap.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,108 @@ ++/* ++ * fixmap.h: compile-time virtual memory allocation ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 1998 Ingo Molnar ++ */ ++ ++#ifndef _ASM_FIXMAP_H ++#define _ASM_FIXMAP_H ++ ++#include <linux/kernel.h> ++#include <asm/apicdef.h> ++#include <asm/page.h> ++#include <asm/vsyscall.h> ++#include <asm/vsyscall32.h> ++#include <asm/acpi.h> ++ ++/* ++ * Here we define all the compile-time 'special' virtual ++ * addresses. The point is to have a constant address at ++ * compile time, but to set the physical address only ++ * in the boot process. ++ * ++ * these 'compile-time allocated' memory buffers are ++ * fixed-size 4k pages. (or larger if used with an increment ++ * highger than 1) use fixmap_set(idx,phys) to associate ++ * physical memory with fixmap indices. ++ * ++ * TLB entries of such buffers will not be flushed across ++ * task switches. ++ */ ++ ++enum fixed_addresses { ++ VSYSCALL_LAST_PAGE, ++ VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1, ++ VSYSCALL_HPET, ++ FIX_HPET_BASE, ++ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ ++ FIX_IO_APIC_BASE_0, ++ FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, ++#ifdef CONFIG_ACPI ++ FIX_ACPI_BEGIN, ++ FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, ++#endif ++ FIX_SHARED_INFO, ++#define NR_FIX_ISAMAPS 256 ++ FIX_ISAMAP_END, ++ FIX_ISAMAP_BEGIN = FIX_ISAMAP_END + NR_FIX_ISAMAPS - 1, ++ __end_of_permanent_fixed_addresses, ++ /* temporary boot-time mappings, used before ioremap() is functional */ ++#define NR_FIX_BTMAPS 16 ++ FIX_BTMAP_END = __end_of_permanent_fixed_addresses, ++ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1, ++ __end_of_fixed_addresses ++}; ++ ++extern void __set_fixmap (enum fixed_addresses idx, ++ unsigned long phys, pgprot_t flags); ++ ++#define set_fixmap(idx, phys) \ ++ __set_fixmap(idx, phys, PAGE_KERNEL) ++/* ++ * Some hardware wants to get fixmapped without caching. ++ */ ++#define set_fixmap_nocache(idx, phys) \ ++ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) ++ ++#define clear_fixmap(idx) \ ++ __set_fixmap(idx, 0, __pgprot(0)) ++ ++#define FIXADDR_TOP (VSYSCALL_END-PAGE_SIZE) ++#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) ++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) ++ ++/* Only covers 32bit vsyscalls currently. Need another set for 64bit. */ ++#define FIXADDR_USER_START ((unsigned long)VSYSCALL32_VSYSCALL) ++#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE) ++ ++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) ++ ++extern void __this_fixmap_does_not_exist(void); ++ ++/* ++ * 'index to address' translation. If anyone tries to use the idx ++ * directly without translation, we catch the bug with a NULL-deference ++ * kernel oops. Illegal ranges of incoming indices are caught too. ++ */ ++static __always_inline unsigned long fix_to_virt(const unsigned int idx) ++{ ++ /* ++ * this branch gets completely eliminated after inlining, ++ * except when someone tries to use fixaddr indices in an ++ * illegal way. (such as mixing up address types or using ++ * out-of-range indices). ++ * ++ * If it doesn't get removed, the linker will complain ++ * loudly with a reasonably clear error message.. ++ */ ++ if (idx >= __end_of_fixed_addresses) ++ __this_fixmap_does_not_exist(); ++ ++ return __fix_to_virt(idx); ++} ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/floppy.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/floppy.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,206 @@ ++/* ++ * Architecture specific parts of the Floppy driver ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 1995 ++ * ++ * Modifications for Xen are Copyright (c) 2004, Keir Fraser. ++ */ ++#ifndef __ASM_XEN_X86_64_FLOPPY_H ++#define __ASM_XEN_X86_64_FLOPPY_H ++ ++#include <linux/vmalloc.h> ++ ++/* ++ * The DMA channel used by the floppy controller cannot access data at ++ * addresses >= 16MB ++ * ++ * Went back to the 1MB limit, as some people had problems with the floppy ++ * driver otherwise. It doesn't matter much for performance anyway, as most ++ * floppy accesses go through the track buffer. ++ */ ++#define _CROSS_64KB(a,s,vdma) \ ++(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)) ++ ++/* XEN: Hit DMA paths on the head. This trick from asm-m68k/floppy.h. */ ++#include <asm/dma.h> ++#undef MAX_DMA_ADDRESS ++#define MAX_DMA_ADDRESS 0 ++#define CROSS_64KB(a,s) (0) ++ ++#define fd_inb(port) inb_p(port) ++#define fd_outb(value,port) outb_p(value,port) ++ ++#define fd_request_dma() (0) ++#define fd_free_dma() ((void)0) ++#define fd_enable_irq() enable_irq(FLOPPY_IRQ) ++#define fd_disable_irq() disable_irq(FLOPPY_IRQ) ++#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) ++#define fd_get_dma_residue() vdma_get_dma_residue(FLOPPY_DMA) ++/* ++ * Do not use vmalloc/vfree: floppy_release_irq_and_dma() gets called from ++ * softirq context via motor_off_callback. A generic bug we happen to trigger. ++ */ ++#define fd_dma_mem_alloc(size) __get_free_pages(GFP_KERNEL|__GFP_NORETRY, get_order(size)) ++#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) ++#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io) ++ ++static int virtual_dma_count; ++static int virtual_dma_residue; ++static char *virtual_dma_addr; ++static int virtual_dma_mode; ++static int doing_pdma; ++ ++static irqreturn_t floppy_hardint(int irq, void *dev_id) ++{ ++ register unsigned char st; ++ ++#undef TRACE_FLPY_INT ++ ++#ifdef TRACE_FLPY_INT ++ static int calls=0; ++ static int bytes=0; ++ static int dma_wait=0; ++#endif ++ if (!doing_pdma) ++ return floppy_interrupt(irq, dev_id); ++ ++#ifdef TRACE_FLPY_INT ++ if(!calls) ++ bytes = virtual_dma_count; ++#endif ++ ++ { ++ register int lcount; ++ register char *lptr; ++ ++ st = 1; ++ for(lcount=virtual_dma_count, lptr=virtual_dma_addr; ++ lcount; lcount--, lptr++) { ++ st=inb(virtual_dma_port+4) & 0xa0 ; ++ if(st != 0xa0) ++ break; ++ if(virtual_dma_mode) ++ outb_p(*lptr, virtual_dma_port+5); ++ else ++ *lptr = inb_p(virtual_dma_port+5); ++ } ++ virtual_dma_count = lcount; ++ virtual_dma_addr = lptr; ++ st = inb(virtual_dma_port+4); ++ } ++ ++#ifdef TRACE_FLPY_INT ++ calls++; ++#endif ++ if(st == 0x20) ++ return IRQ_HANDLED; ++ if(!(st & 0x20)) { ++ virtual_dma_residue += virtual_dma_count; ++ virtual_dma_count=0; ++#ifdef TRACE_FLPY_INT ++ printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", ++ virtual_dma_count, virtual_dma_residue, calls, bytes, ++ dma_wait); ++ calls = 0; ++ dma_wait=0; ++#endif ++ doing_pdma = 0; ++ floppy_interrupt(irq, dev_id); ++ return IRQ_HANDLED; ++ } ++#ifdef TRACE_FLPY_INT ++ if(!virtual_dma_count) ++ dma_wait++; ++#endif ++ return IRQ_HANDLED; ++} ++ ++static void fd_disable_dma(void) ++{ ++ doing_pdma = 0; ++ virtual_dma_residue += virtual_dma_count; ++ virtual_dma_count=0; ++} ++ ++static int vdma_get_dma_residue(unsigned int dummy) ++{ ++ return virtual_dma_count + virtual_dma_residue; ++} ++ ++ ++static int fd_request_irq(void) ++{ ++ return request_irq(FLOPPY_IRQ, floppy_hardint, ++ IRQF_DISABLED, "floppy", NULL); ++} ++ ++#if 0 ++static unsigned long vdma_mem_alloc(unsigned long size) ++{ ++ return (unsigned long) vmalloc(size); ++ ++} ++ ++static void vdma_mem_free(unsigned long addr, unsigned long size) ++{ ++ vfree((void *)addr); ++} ++#endif ++ ++static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) ++{ ++ doing_pdma = 1; ++ virtual_dma_port = io; ++ virtual_dma_mode = (mode == DMA_MODE_WRITE); ++ virtual_dma_addr = addr; ++ virtual_dma_count = size; ++ virtual_dma_residue = 0; ++ return 0; ++} ++ ++/* XEN: This trick to force 'virtual DMA' is from include/asm-m68k/floppy.h. */ ++#define FDC1 xen_floppy_init() ++static int FDC2 = -1; ++ ++static int xen_floppy_init(void) ++{ ++ use_virtual_dma = 1; ++ can_use_virtual_dma = 1; ++ return 0x3f0; ++} ++ ++/* ++ * Floppy types are stored in the rtc's CMOS RAM and so rtc_lock ++ * is needed to prevent corrupted CMOS RAM in case "insmod floppy" ++ * coincides with another rtc CMOS user. Paul G. ++ */ ++#define FLOPPY0_TYPE ({ \ ++ unsigned long flags; \ ++ unsigned char val; \ ++ spin_lock_irqsave(&rtc_lock, flags); \ ++ val = (CMOS_READ(0x10) >> 4) & 15; \ ++ spin_unlock_irqrestore(&rtc_lock, flags); \ ++ val; \ ++}) ++ ++#define FLOPPY1_TYPE ({ \ ++ unsigned long flags; \ ++ unsigned char val; \ ++ spin_lock_irqsave(&rtc_lock, flags); \ ++ val = CMOS_READ(0x10) & 15; \ ++ spin_unlock_irqrestore(&rtc_lock, flags); \ ++ val; \ ++}) ++ ++#define N_FDC 2 ++#define N_DRIVE 8 ++ ++#define FLOPPY_MOTOR_MASK 0xf0 ++ ++#define EXTRA_FLOPPY_PARAMS ++ ++#endif /* __ASM_XEN_X86_64_FLOPPY_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/hypercall.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/hypercall.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,406 @@ ++/****************************************************************************** ++ * hypercall.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * 64-bit updates: ++ * Benjamin Liu <benjamin.liu@intel.com> ++ * Jun Nakajima <jun.nakajima@intel.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERCALL_H__ ++#define __HYPERCALL_H__ ++ ++#include <linux/string.h> /* memcpy() */ ++ ++#ifndef __HYPERVISOR_H__ ++# error "please don't include this file directly" ++#endif ++ ++#define __STR(x) #x ++#define STR(x) __STR(x) ++ ++#ifdef CONFIG_XEN ++#define HYPERCALL_STR(name) \ ++ "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)" ++#else ++#define HYPERCALL_STR(name) \ ++ "mov hypercall_stubs,%%rax; " \ ++ "add $("STR(__HYPERVISOR_##name)" * 32),%%rax; " \ ++ "call *%%rax" ++#endif ++ ++#define _hypercall0(type, name) \ ++({ \ ++ long __res; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res) \ ++ : \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall1(type, name, a1) \ ++({ \ ++ long __res, __ign1; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=D" (__ign1) \ ++ : "1" ((long)(a1)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall2(type, name, a1, a2) \ ++({ \ ++ long __res, __ign1, __ign2; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall3(type, name, a1, a2, a3) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3; \ ++ asm volatile ( \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ ++ "=d" (__ign3) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)) \ ++ : "memory" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall4(type, name, a1, a2, a3, a4) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3; \ ++ asm volatile ( \ ++ "movq %7,%%r10; " \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ ++ "=d" (__ign3) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)), "g" ((long)(a4)) \ ++ : "memory", "r10" ); \ ++ (type)__res; \ ++}) ++ ++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ ++({ \ ++ long __res, __ign1, __ign2, __ign3; \ ++ asm volatile ( \ ++ "movq %7,%%r10; movq %8,%%r8; " \ ++ HYPERCALL_STR(name) \ ++ : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ ++ "=d" (__ign3) \ ++ : "1" ((long)(a1)), "2" ((long)(a2)), \ ++ "3" ((long)(a3)), "g" ((long)(a4)), \ ++ "g" ((long)(a5)) \ ++ : "memory", "r10", "r8" ); \ ++ (type)__res; \ ++}) ++ ++static inline int ++HYPERVISOR_set_trap_table( ++ trap_info_t *table) ++{ ++ return _hypercall1(int, set_trap_table, table); ++} ++ ++static inline int ++HYPERVISOR_mmu_update( ++ mmu_update_t *req, int count, int *success_count, domid_t domid) ++{ ++ return _hypercall4(int, mmu_update, req, count, success_count, domid); ++} ++ ++static inline int ++HYPERVISOR_mmuext_op( ++ struct mmuext_op *op, int count, int *success_count, domid_t domid) ++{ ++ return _hypercall4(int, mmuext_op, op, count, success_count, domid); ++} ++ ++static inline int ++HYPERVISOR_set_gdt( ++ unsigned long *frame_list, int entries) ++{ ++ return _hypercall2(int, set_gdt, frame_list, entries); ++} ++ ++static inline int ++HYPERVISOR_stack_switch( ++ unsigned long ss, unsigned long esp) ++{ ++ return _hypercall2(int, stack_switch, ss, esp); ++} ++ ++static inline int ++HYPERVISOR_set_callbacks( ++ unsigned long event_address, unsigned long failsafe_address, ++ unsigned long syscall_address) ++{ ++ return _hypercall3(int, set_callbacks, ++ event_address, failsafe_address, syscall_address); ++} ++ ++static inline int ++HYPERVISOR_fpu_taskswitch( ++ int set) ++{ ++ return _hypercall1(int, fpu_taskswitch, set); ++} ++ ++static inline int ++HYPERVISOR_sched_op_compat( ++ int cmd, unsigned long arg) ++{ ++ return _hypercall2(int, sched_op_compat, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_sched_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, sched_op, cmd, arg); ++} ++ ++static inline long ++HYPERVISOR_set_timer_op( ++ u64 timeout) ++{ ++ return _hypercall1(long, set_timer_op, timeout); ++} ++ ++static inline int ++HYPERVISOR_platform_op( ++ struct xen_platform_op *platform_op) ++{ ++ platform_op->interface_version = XENPF_INTERFACE_VERSION; ++ return _hypercall1(int, platform_op, platform_op); ++} ++ ++static inline int ++HYPERVISOR_set_debugreg( ++ int reg, unsigned long value) ++{ ++ return _hypercall2(int, set_debugreg, reg, value); ++} ++ ++static inline unsigned long ++HYPERVISOR_get_debugreg( ++ int reg) ++{ ++ return _hypercall1(unsigned long, get_debugreg, reg); ++} ++ ++static inline int ++HYPERVISOR_update_descriptor( ++ unsigned long ma, unsigned long word) ++{ ++ return _hypercall2(int, update_descriptor, ma, word); ++} ++ ++static inline int ++HYPERVISOR_memory_op( ++ unsigned int cmd, void *arg) ++{ ++ return _hypercall2(int, memory_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_multicall( ++ multicall_entry_t *call_list, int nr_calls) ++{ ++ return _hypercall2(int, multicall, call_list, nr_calls); ++} ++ ++static inline int ++HYPERVISOR_update_va_mapping( ++ unsigned long va, pte_t new_val, unsigned long flags) ++{ ++ return _hypercall3(int, update_va_mapping, va, new_val.pte, flags); ++} ++ ++static inline int ++HYPERVISOR_event_channel_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, event_channel_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct evtchn_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, event_channel_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_acm_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, acm_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_xen_version( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, xen_version, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_console_io( ++ int cmd, int count, char *str) ++{ ++ return _hypercall3(int, console_io, cmd, count, str); ++} ++ ++static inline int ++HYPERVISOR_physdev_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, physdev_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct physdev_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, physdev_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_grant_table_op( ++ unsigned int cmd, void *uop, unsigned int count) ++{ ++ return _hypercall3(int, grant_table_op, cmd, uop, count); ++} ++ ++static inline int ++HYPERVISOR_update_va_mapping_otherdomain( ++ unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) ++{ ++ return _hypercall4(int, update_va_mapping_otherdomain, va, ++ new_val.pte, flags, domid); ++} ++ ++static inline int ++HYPERVISOR_vm_assist( ++ unsigned int cmd, unsigned int type) ++{ ++ return _hypercall2(int, vm_assist, cmd, type); ++} ++ ++static inline int ++HYPERVISOR_vcpu_op( ++ int cmd, int vcpuid, void *extra_args) ++{ ++ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); ++} ++ ++static inline int ++HYPERVISOR_set_segment_base( ++ int reg, unsigned long value) ++{ ++ return _hypercall2(int, set_segment_base, reg, value); ++} ++ ++static inline int ++HYPERVISOR_suspend( ++ unsigned long srec) ++{ ++ struct sched_shutdown sched_shutdown = { ++ .reason = SHUTDOWN_suspend ++ }; ++ ++ int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, ++ &sched_shutdown, srec); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, ++ SHUTDOWN_suspend, srec); ++#endif ++ ++ return rc; ++} ++ ++static inline int ++HYPERVISOR_nmi_op( ++ unsigned long op, void *arg) ++{ ++ return _hypercall2(int, nmi_op, op, arg); ++} ++ ++static inline unsigned long ++HYPERVISOR_hvm_op( ++ int op, void *arg) ++{ ++ return _hypercall2(unsigned long, hvm_op, op, arg); ++} ++ ++static inline int ++HYPERVISOR_callback_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, callback_op, cmd, arg); ++} ++ ++static inline int ++HYPERVISOR_xenoprof_op( ++ int op, void *arg) ++{ ++ return _hypercall2(int, xenoprof_op, op, arg); ++} ++ ++static inline int ++HYPERVISOR_kexec_op( ++ unsigned long op, void *args) ++{ ++ return _hypercall2(int, kexec_op, op, args); ++} ++ ++#endif /* __HYPERCALL_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/hypervisor.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/hypervisor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++#include <asm-i386/mach-xen/asm/hypervisor.h> +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/io.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/io.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,303 @@ ++#ifndef _ASM_IO_H ++#define _ASM_IO_H ++ ++#include <asm/fixmap.h> ++ ++/* ++ * This file contains the definitions for the x86 IO instructions ++ * inb/inw/inl/outb/outw/outl and the "string versions" of the same ++ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" ++ * versions of the single-IO instructions (inb_p/inw_p/..). ++ * ++ * This file is not meant to be obfuscating: it's just complicated ++ * to (a) handle it all in a way that makes gcc able to optimize it ++ * as well as possible and (b) trying to avoid writing the same thing ++ * over and over again with slight variations and possibly making a ++ * mistake somewhere. ++ */ ++ ++/* ++ * Thanks to James van Artsdalen for a better timing-fix than ++ * the two short jumps: using outb's to a nonexistent port seems ++ * to guarantee better timings even on fast machines. ++ * ++ * On the other hand, I'd like to be sure of a non-existent port: ++ * I feel a bit unsafe about using 0x80 (should be safe, though) ++ * ++ * Linus ++ */ ++ ++ /* ++ * Bit simplified and optimized by Jan Hubicka ++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999. ++ * ++ * isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added, ++ * isa_read[wl] and isa_write[wl] fixed ++ * - Arnaldo Carvalho de Melo <acme@conectiva.com.br> ++ */ ++ ++#define __SLOW_DOWN_IO "\noutb %%al,$0x80" ++ ++#ifdef REALLY_SLOW_IO ++#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO ++#else ++#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO ++#endif ++ ++/* ++ * Talk about misusing macros.. ++ */ ++#define __OUT1(s,x) \ ++static inline void out##s(unsigned x value, unsigned short port) { ++ ++#define __OUT2(s,s1,s2) \ ++__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" ++ ++#define __OUT(s,s1,x) \ ++__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ ++__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ ++ ++#define __IN1(s) \ ++static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; ++ ++#define __IN2(s,s1,s2) \ ++__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" ++ ++#define __IN(s,s1,i...) \ ++__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ ++__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ ++ ++#define __INS(s) \ ++static inline void ins##s(unsigned short port, void * addr, unsigned long count) \ ++{ __asm__ __volatile__ ("rep ; ins" #s \ ++: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } ++ ++#define __OUTS(s) \ ++static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ ++{ __asm__ __volatile__ ("rep ; outs" #s \ ++: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } ++ ++#define RETURN_TYPE unsigned char ++__IN(b,"") ++#undef RETURN_TYPE ++#define RETURN_TYPE unsigned short ++__IN(w,"") ++#undef RETURN_TYPE ++#define RETURN_TYPE unsigned int ++__IN(l,"") ++#undef RETURN_TYPE ++ ++__OUT(b,"b",char) ++__OUT(w,"w",short) ++__OUT(l,,int) ++ ++__INS(b) ++__INS(w) ++__INS(l) ++ ++__OUTS(b) ++__OUTS(w) ++__OUTS(l) ++ ++#define IO_SPACE_LIMIT 0xffff ++ ++#if defined(__KERNEL__) && __x86_64__ ++ ++#include <linux/vmalloc.h> ++ ++#ifndef __i386__ ++/* ++ * Change virtual addresses to physical addresses and vv. ++ * These are pretty trivial ++ */ ++static inline unsigned long virt_to_phys(volatile void * address) ++{ ++ return __pa(address); ++} ++ ++static inline void * phys_to_virt(unsigned long address) ++{ ++ return __va(address); ++} ++ ++#define virt_to_bus(_x) phys_to_machine(__pa(_x)) ++#define bus_to_virt(_x) __va(machine_to_phys(_x)) ++#endif ++ ++/* ++ * Change "struct page" to physical address. ++ */ ++#define page_to_pseudophys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) ++#define page_to_phys(page) (phys_to_machine(page_to_pseudophys(page))) ++#define page_to_bus(page) (phys_to_machine(page_to_pseudophys(page))) ++ ++#define bio_to_pseudophys(bio) (page_to_pseudophys(bio_page((bio))) + \ ++ (unsigned long) bio_offset((bio))) ++#define bvec_to_pseudophys(bv) (page_to_pseudophys((bv)->bv_page) + \ ++ (unsigned long) (bv)->bv_offset) ++ ++#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ ++ (((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) && \ ++ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \ ++ bvec_to_pseudophys((vec2)))) ++ ++#include <asm-generic/iomap.h> ++ ++extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags); ++ ++static inline void __iomem * ioremap (unsigned long offset, unsigned long size) ++{ ++ return __ioremap(offset, size, 0); ++} ++ ++extern void *bt_ioremap(unsigned long addr, unsigned long size); ++extern void bt_iounmap(void *addr, unsigned long size); ++#define early_ioremap bt_ioremap ++#define early_iounmap bt_iounmap ++ ++/* ++ * This one maps high address device memory and turns off caching for that area. ++ * it's useful if some control registers are in such an area and write combining ++ * or read caching is not desirable: ++ */ ++extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); ++extern void iounmap(volatile void __iomem *addr); ++ ++/* ++ * ISA I/O bus memory addresses are 1:1 with the physical address. ++ */ ++ ++#define isa_virt_to_bus(_x) isa_virt_to_bus_is_UNSUPPORTED->x ++#define isa_page_to_bus(_x) isa_page_to_bus_is_UNSUPPORTED->x ++#define isa_bus_to_virt(_x) (void *)(__fix_to_virt(FIX_ISAMAP_BEGIN) + (_x)) ++ ++/* ++ * However PCI ones are not necessarily 1:1 and therefore these interfaces ++ * are forbidden in portable PCI drivers. ++ * ++ * Allow them on x86 for legacy drivers, though. ++ */ ++#define virt_to_bus(_x) phys_to_machine(__pa(_x)) ++#define bus_to_virt(_x) __va(machine_to_phys(_x)) ++ ++/* ++ * readX/writeX() are used to access memory mapped devices. On some ++ * architectures the memory mapped IO stuff needs to be accessed ++ * differently. On the x86 architecture, we just read/write the ++ * memory location directly. ++ */ ++ ++static inline __u8 __readb(const volatile void __iomem *addr) ++{ ++ return *(__force volatile __u8 *)addr; ++} ++static inline __u16 __readw(const volatile void __iomem *addr) ++{ ++ return *(__force volatile __u16 *)addr; ++} ++static __always_inline __u32 __readl(const volatile void __iomem *addr) ++{ ++ return *(__force volatile __u32 *)addr; ++} ++static inline __u64 __readq(const volatile void __iomem *addr) ++{ ++ return *(__force volatile __u64 *)addr; ++} ++#define readb(x) __readb(x) ++#define readw(x) __readw(x) ++#define readl(x) __readl(x) ++#define readq(x) __readq(x) ++#define readb_relaxed(a) readb(a) ++#define readw_relaxed(a) readw(a) ++#define readl_relaxed(a) readl(a) ++#define readq_relaxed(a) readq(a) ++#define __raw_readb readb ++#define __raw_readw readw ++#define __raw_readl readl ++#define __raw_readq readq ++ ++#define mmiowb() ++ ++static inline void __writel(__u32 b, volatile void __iomem *addr) ++{ ++ *(__force volatile __u32 *)addr = b; ++} ++static inline void __writeq(__u64 b, volatile void __iomem *addr) ++{ ++ *(__force volatile __u64 *)addr = b; ++} ++static inline void __writeb(__u8 b, volatile void __iomem *addr) ++{ ++ *(__force volatile __u8 *)addr = b; ++} ++static inline void __writew(__u16 b, volatile void __iomem *addr) ++{ ++ *(__force volatile __u16 *)addr = b; ++} ++#define writeq(val,addr) __writeq((val),(addr)) ++#define writel(val,addr) __writel((val),(addr)) ++#define writew(val,addr) __writew((val),(addr)) ++#define writeb(val,addr) __writeb((val),(addr)) ++#define __raw_writeb writeb ++#define __raw_writew writew ++#define __raw_writel writel ++#define __raw_writeq writeq ++ ++void __memcpy_fromio(void*,unsigned long,unsigned); ++void __memcpy_toio(unsigned long,const void*,unsigned); ++ ++static inline void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len) ++{ ++ __memcpy_fromio(to,(unsigned long)from,len); ++} ++static inline void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len) ++{ ++ __memcpy_toio((unsigned long)to,from,len); ++} ++ ++void memset_io(volatile void __iomem *a, int b, size_t c); ++ ++/* ++ * ISA space is 'always mapped' on a typical x86 system, no need to ++ * explicitly ioremap() it. The fact that the ISA IO space is mapped ++ * to PAGE_OFFSET is pure coincidence - it does not mean ISA values ++ * are physical addresses. The following constant pointer can be ++ * used as the IO-area pointer (it can be iounmapped as well, so the ++ * analogy with PCI is quite large): ++ */ ++#define __ISA_IO_base ((char __iomem *)(fix_to_virt(FIX_ISAMAP_BEGIN))) ++ ++/* ++ * Again, x86-64 does not require mem IO specific function. ++ */ ++ ++#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) ++ ++/* Nothing to do */ ++ ++#define dma_cache_inv(_start,_size) do { } while (0) ++#define dma_cache_wback(_start,_size) do { } while (0) ++#define dma_cache_wback_inv(_start,_size) do { } while (0) ++ ++#define flush_write_buffers() ++ ++extern int iommu_bio_merge; ++#define BIO_VMERGE_BOUNDARY iommu_bio_merge ++ ++/* ++ * Convert a physical pointer to a virtual kernel pointer for /dev/mem ++ * access ++ */ ++#define xlate_dev_mem_ptr(p, sz) ioremap(p, sz) ++#define xlate_dev_mem_ptr_unmap(p) iounmap(p) ++ ++/* ++ * Convert a virtual cached pointer to an uncached pointer ++ */ ++#define xlate_dev_kmem_ptr(p) p ++ ++#endif /* __KERNEL__ */ ++ ++#define ARCH_HAS_DEV_MEM ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/irq.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/irq.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,34 @@ ++#ifndef _ASM_IRQ_H ++#define _ASM_IRQ_H ++ ++/* ++ * linux/include/asm/irq.h ++ * ++ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar ++ * ++ * IRQ/IPI changes taken from work by Thomas Radke ++ * <tomsoft@informatik.tu-chemnitz.de> ++ */ ++ ++#include <linux/sched.h> ++/* include comes from machine specific directory */ ++#include "irq_vectors.h" ++#include <asm/thread_info.h> ++ ++static __inline__ int irq_canonicalize(int irq) ++{ ++ return ((irq == 2) ? 9 : irq); ++} ++ ++#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ ++ ++# define irq_ctx_init(cpu) do { } while (0) ++ ++#ifdef CONFIG_HOTPLUG_CPU ++#include <linux/cpumask.h> ++extern void fixup_irqs(cpumask_t map); ++#endif ++ ++#define __ARCH_HAS_DO_SOFTIRQ 1 ++ ++#endif /* _ASM_IRQ_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/irqflags.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/irqflags.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,131 @@ ++/* ++ * include/asm-x86_64/irqflags.h ++ * ++ * IRQ flags handling ++ * ++ * This file gets included from lowlevel asm headers too, to provide ++ * wrapped versions of the local_irq_*() APIs, based on the ++ * raw_local_irq_*() functions from the lowlevel headers. ++ */ ++#ifndef _ASM_IRQFLAGS_H ++#define _ASM_IRQFLAGS_H ++ ++#ifndef __ASSEMBLY__ ++/* ++ * Interrupt control: ++ */ ++ ++#define __raw_local_save_flags() (current_vcpu_info()->evtchn_upcall_mask) ++ ++#define raw_local_save_flags(flags) \ ++ do { (flags) = __raw_local_save_flags(); } while (0) ++ ++#define raw_local_irq_restore(x) \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \ ++ barrier(); /* unmask then check (avoid races) */ \ ++ if ( unlikely(_vcpu->evtchn_upcall_pending) ) \ ++ force_evtchn_callback(); \ ++ } \ ++} while (0) ++ ++#ifdef CONFIG_X86_VSMP ++ ++/* ++ * Interrupt control for the VSMP architecture: ++ */ ++ ++static inline void raw_local_irq_disable(void) ++{ ++ unsigned long flags = __raw_local_save_flags(); ++ ++ raw_local_irq_restore((flags & ~(1 << 9)) | (1 << 18)); ++} ++ ++static inline void raw_local_irq_enable(void) ++{ ++ unsigned long flags = __raw_local_save_flags(); ++ ++ raw_local_irq_restore((flags | (1 << 9)) & ~(1 << 18)); ++} ++ ++static inline int raw_irqs_disabled_flags(unsigned long flags) ++{ ++ return !(flags & (1<<9)) || (flags & (1 << 18)); ++} ++ ++#else /* CONFIG_X86_VSMP */ ++ ++#define raw_local_irq_disable() \ ++do { \ ++ current_vcpu_info()->evtchn_upcall_mask = 1; \ ++ barrier(); \ ++} while (0) ++ ++#define raw_local_irq_enable() \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ _vcpu->evtchn_upcall_mask = 0; \ ++ barrier(); /* unmask then check (avoid races) */ \ ++ if ( unlikely(_vcpu->evtchn_upcall_pending) ) \ ++ force_evtchn_callback(); \ ++} while (0) ++ ++static inline int raw_irqs_disabled_flags(unsigned long flags) ++{ ++ return (flags != 0); ++} ++ ++#endif ++ ++/* ++ * For spinlocks, etc.: ++ */ ++ ++#define __raw_local_irq_save() \ ++({ \ ++ unsigned long flags = __raw_local_save_flags(); \ ++ \ ++ raw_local_irq_disable(); \ ++ \ ++ flags; \ ++}) ++ ++#define raw_local_irq_save(flags) \ ++ do { (flags) = __raw_local_irq_save(); } while (0) ++ ++#define raw_irqs_disabled() \ ++({ \ ++ unsigned long flags = __raw_local_save_flags(); \ ++ \ ++ raw_irqs_disabled_flags(flags); \ ++}) ++ ++/* ++ * Used in the idle loop; sti takes one instruction cycle ++ * to complete: ++ */ ++void raw_safe_halt(void); ++ ++/* ++ * Used when interrupts are already enabled or to ++ * shutdown the processor: ++ */ ++void halt(void); ++ ++#else /* __ASSEMBLY__: */ ++# ifdef CONFIG_TRACE_IRQFLAGS ++# define TRACE_IRQS_ON call trace_hardirqs_on_thunk ++# define TRACE_IRQS_OFF call trace_hardirqs_off_thunk ++# else ++# define TRACE_IRQS_ON ++# define TRACE_IRQS_OFF ++# endif ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/maddr.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/maddr.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,161 @@ ++#ifndef _X86_64_MADDR_H ++#define _X86_64_MADDR_H ++ ++#include <xen/features.h> ++#include <xen/interface/xen.h> ++ ++/**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/ ++#define INVALID_P2M_ENTRY (~0UL) ++#define FOREIGN_FRAME_BIT (1UL<<63) ++#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) ++ ++/* Definitions for machine and pseudophysical addresses. */ ++typedef unsigned long paddr_t; ++typedef unsigned long maddr_t; ++ ++#ifdef CONFIG_XEN ++ ++extern unsigned long *phys_to_machine_mapping; ++ ++#undef machine_to_phys_mapping ++extern unsigned long *machine_to_phys_mapping; ++extern unsigned int machine_to_phys_order; ++ ++static inline unsigned long pfn_to_mfn(unsigned long pfn) ++{ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return pfn; ++ BUG_ON(end_pfn && pfn >= end_pfn); ++ return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; ++} ++ ++static inline int phys_to_machine_mapping_valid(unsigned long pfn) ++{ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return 1; ++ BUG_ON(end_pfn && pfn >= end_pfn); ++ return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); ++} ++ ++static inline unsigned long mfn_to_pfn(unsigned long mfn) ++{ ++ unsigned long pfn; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return mfn; ++ ++ if (unlikely((mfn >> machine_to_phys_order) != 0)) ++ return end_pfn; ++ ++ /* The array access can fail (e.g., device space beyond end of RAM). */ ++ asm ( ++ "1: movq %1,%0\n" ++ "2:\n" ++ ".section .fixup,\"ax\"\n" ++ "3: movq %2,%0\n" ++ " jmp 2b\n" ++ ".previous\n" ++ ".section __ex_table,\"a\"\n" ++ " .align 8\n" ++ " .quad 1b,3b\n" ++ ".previous" ++ : "=r" (pfn) ++ : "m" (machine_to_phys_mapping[mfn]), "m" (end_pfn) ); ++ ++ return pfn; ++} ++ ++/* ++ * We detect special mappings in one of two ways: ++ * 1. If the MFN is an I/O page then Xen will set the m2p entry ++ * to be outside our maximum possible pseudophys range. ++ * 2. If the MFN belongs to a different domain then we will certainly ++ * not have MFN in our p2m table. Conversely, if the page is ours, ++ * then we'll have p2m(m2p(MFN))==MFN. ++ * If we detect a special mapping then it doesn't have a 'struct page'. ++ * We force !pfn_valid() by returning an out-of-range pointer. ++ * ++ * NB. These checks require that, for any MFN that is not in our reservation, ++ * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if ++ * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN. ++ * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety. ++ * ++ * NB2. When deliberately mapping foreign pages into the p2m table, you *must* ++ * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we ++ * require. In all the cases we care about, the FOREIGN_FRAME bit is ++ * masked (e.g., pfn_to_mfn()) so behaviour there is correct. ++ */ ++static inline unsigned long mfn_to_local_pfn(unsigned long mfn) ++{ ++ unsigned long pfn = mfn_to_pfn(mfn); ++ if ((pfn < end_pfn) ++ && !xen_feature(XENFEAT_auto_translated_physmap) ++ && (phys_to_machine_mapping[pfn] != mfn)) ++ return end_pfn; /* force !pfn_valid() */ ++ return pfn; ++} ++ ++static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) ++{ ++ BUG_ON(end_pfn && pfn >= end_pfn); ++ if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); ++ return; ++ } ++ phys_to_machine_mapping[pfn] = mfn; ++} ++ ++static inline maddr_t phys_to_machine(paddr_t phys) ++{ ++ maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT); ++ machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK); ++ return machine; ++} ++ ++static inline paddr_t machine_to_phys(maddr_t machine) ++{ ++ paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT); ++ phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK); ++ return phys; ++} ++ ++static inline paddr_t pte_phys_to_machine(paddr_t phys) ++{ ++ maddr_t machine; ++ machine = pfn_to_mfn((phys & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT); ++ machine = (machine << PAGE_SHIFT) | (phys & ~PHYSICAL_PAGE_MASK); ++ return machine; ++} ++ ++static inline paddr_t pte_machine_to_phys(maddr_t machine) ++{ ++ paddr_t phys; ++ phys = mfn_to_pfn((machine & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT); ++ phys = (phys << PAGE_SHIFT) | (machine & ~PHYSICAL_PAGE_MASK); ++ return phys; ++} ++ ++#define __pte_ma(x) ((pte_t) { (x) } ) ++#define pfn_pte_ma(pfn, prot) __pte_ma((((pfn) << PAGE_SHIFT) | pgprot_val(prot)) & __supported_pte_mask) ++ ++#else /* !CONFIG_XEN */ ++ ++#define pfn_to_mfn(pfn) (pfn) ++#define mfn_to_pfn(mfn) (mfn) ++#define mfn_to_local_pfn(mfn) (mfn) ++#define set_phys_to_machine(pfn, mfn) ((void)0) ++#define phys_to_machine_mapping_valid(pfn) (1) ++#define phys_to_machine(phys) ((maddr_t)(phys)) ++#define machine_to_phys(mach) ((paddr_t)(mach)) ++#define pfn_pte_ma(pfn, prot) pfn_pte(pfn, prot) ++#define __pte_ma(x) __pte(x) ++ ++#endif /* !CONFIG_XEN */ ++ ++/* VIRT <-> MACHINE conversion */ ++#define virt_to_machine(v) (phys_to_machine(__pa(v))) ++#define virt_to_mfn(v) (pfn_to_mfn(__pa(v) >> PAGE_SHIFT)) ++#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) ++ ++#endif /* _X86_64_MADDR_H */ ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/mmu_context.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/mmu_context.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,136 @@ ++#ifndef __X86_64_MMU_CONTEXT_H ++#define __X86_64_MMU_CONTEXT_H ++ ++#include <asm/desc.h> ++#include <asm/atomic.h> ++#include <asm/pgalloc.h> ++#include <asm/page.h> ++#include <asm/pda.h> ++#include <asm/pgtable.h> ++#include <asm/tlbflush.h> ++ ++/* ++ * possibly do the LDT unload here? ++ */ ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm); ++void destroy_context(struct mm_struct *mm); ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN) ++ if (read_pda(mmu_state) == TLBSTATE_OK) ++ write_pda(mmu_state, TLBSTATE_LAZY); ++#endif ++} ++ ++#define prepare_arch_switch(next) __prepare_arch_switch() ++ ++static inline void __prepare_arch_switch(void) ++{ ++ /* ++ * Save away %es, %ds, %fs and %gs. Must happen before reload ++ * of cr3/ldt (i.e., not in __switch_to). ++ */ ++ __asm__ __volatile__ ( ++ "mov %%es,%0 ; mov %%ds,%1 ; mov %%fs,%2 ; mov %%gs,%3" ++ : "=m" (current->thread.es), ++ "=m" (current->thread.ds), ++ "=m" (current->thread.fsindex), ++ "=m" (current->thread.gsindex) ); ++ ++ if (current->thread.ds) ++ __asm__ __volatile__ ( "movl %0,%%ds" : : "r" (0) ); ++ ++ if (current->thread.es) ++ __asm__ __volatile__ ( "movl %0,%%es" : : "r" (0) ); ++ ++ if (current->thread.fsindex) { ++ __asm__ __volatile__ ( "movl %0,%%fs" : : "r" (0) ); ++ current->thread.fs = 0; ++ } ++ ++ if (current->thread.gsindex) { ++ load_gs_index(0); ++ current->thread.gs = 0; ++ } ++} ++ ++extern void mm_pin(struct mm_struct *mm); ++extern void mm_unpin(struct mm_struct *mm); ++void mm_pin_all(void); ++ ++static inline void load_cr3(pgd_t *pgd) ++{ ++ asm volatile("movq %0,%%cr3" :: "r" (phys_to_machine(__pa(pgd))) : ++ "memory"); ++} ++ ++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ++ struct task_struct *tsk) ++{ ++ unsigned cpu = smp_processor_id(); ++ struct mmuext_op _op[3], *op = _op; ++ ++ if (likely(prev != next)) { ++ BUG_ON(!xen_feature(XENFEAT_writable_page_tables) && ++ !next->context.pinned); ++ ++ /* stop flush ipis for the previous mm */ ++ cpu_clear(cpu, prev->cpu_vm_mask); ++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN) ++ write_pda(mmu_state, TLBSTATE_OK); ++ write_pda(active_mm, next); ++#endif ++ cpu_set(cpu, next->cpu_vm_mask); ++ ++ /* load_cr3(next->pgd) */ ++ op->cmd = MMUEXT_NEW_BASEPTR; ++ op->arg1.mfn = pfn_to_mfn(__pa(next->pgd) >> PAGE_SHIFT); ++ op++; ++ ++ /* xen_new_user_pt(__pa(__user_pgd(next->pgd))) */ ++ op->cmd = MMUEXT_NEW_USER_BASEPTR; ++ op->arg1.mfn = pfn_to_mfn(__pa(__user_pgd(next->pgd)) >> PAGE_SHIFT); ++ op++; ++ ++ if (unlikely(next->context.ldt != prev->context.ldt)) { ++ /* load_LDT_nolock(&next->context, cpu) */ ++ op->cmd = MMUEXT_SET_LDT; ++ op->arg1.linear_addr = (unsigned long)next->context.ldt; ++ op->arg2.nr_ents = next->context.size; ++ op++; ++ } ++ ++ BUG_ON(HYPERVISOR_mmuext_op(_op, op-_op, NULL, DOMID_SELF)); ++ } ++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN) ++ else { ++ write_pda(mmu_state, TLBSTATE_OK); ++ if (read_pda(active_mm) != next) ++ out_of_line_bug(); ++ if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { ++ /* We were in lazy tlb mode and leave_mm disabled ++ * tlb flush IPI delivery. We must reload CR3 ++ * to make sure to use no freed page tables. ++ */ ++ load_cr3(next->pgd); ++ xen_new_user_pt(__pa(__user_pgd(next->pgd))); ++ load_LDT_nolock(&next->context, cpu); ++ } ++ } ++#endif ++} ++ ++#define deactivate_mm(tsk,mm) do { \ ++ load_gs_index(0); \ ++ asm volatile("movl %0,%%fs"::"r"(0)); \ ++} while(0) ++ ++static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) ++{ ++ if (!next->context.pinned) ++ mm_pin(next); ++ switch_mm(prev, next, NULL); ++} ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/page.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/page.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,219 @@ ++#ifndef _X86_64_PAGE_H ++#define _X86_64_PAGE_H ++ ++/* #include <linux/string.h> */ ++#ifndef __ASSEMBLY__ ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <asm/bug.h> ++#endif ++#include <xen/interface/xen.h> ++ ++/* ++ * Need to repeat this here in order to not include pgtable.h (which in turn ++ * depends on definitions made here), but to be able to use the symbolic ++ * below. The preprocessor will warn if the two definitions aren't identical. ++ */ ++#define _PAGE_PRESENT 0x001 ++ ++#define arch_free_page(_page,_order) \ ++({ int foreign = PageForeign(_page); \ ++ if (foreign) \ ++ PageForeignDestructor(_page); \ ++ foreign; \ ++}) ++#define HAVE_ARCH_FREE_PAGE ++ ++/* PAGE_SHIFT determines the page size */ ++#define PAGE_SHIFT 12 ++#ifdef __ASSEMBLY__ ++#define PAGE_SIZE (0x1 << PAGE_SHIFT) ++#else ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#endif ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++/* See Documentation/x86_64/mm.txt for a description of the memory map. */ ++#define __PHYSICAL_MASK_SHIFT 46 ++#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) ++#define __VIRTUAL_MASK_SHIFT 48 ++#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) ++ ++#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK) ++ ++#define THREAD_ORDER 1 ++#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) ++#define CURRENT_MASK (~(THREAD_SIZE-1)) ++ ++#define EXCEPTION_STACK_ORDER 0 ++#define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER) ++ ++#define DEBUG_STACK_ORDER (EXCEPTION_STACK_ORDER + 1) ++#define DEBUG_STKSZ (PAGE_SIZE << DEBUG_STACK_ORDER) ++ ++#define IRQSTACK_ORDER 2 ++#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER) ++ ++#define STACKFAULT_STACK 1 ++#define DOUBLEFAULT_STACK 2 ++#define NMI_STACK 3 ++#define DEBUG_STACK 4 ++#define MCE_STACK 5 ++#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ ++ ++#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) ++#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) ++ ++#define HPAGE_SHIFT PMD_SHIFT ++#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) ++#define HPAGE_MASK (~(HPAGE_SIZE - 1)) ++#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) ++ ++#ifdef __KERNEL__ ++#ifndef __ASSEMBLY__ ++ ++extern unsigned long end_pfn; ++ ++#include <asm/maddr.h> ++ ++void clear_page(void *); ++void copy_page(void *, void *); ++ ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++ ++#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr) ++#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE ++/* ++ * These are used to make use of C type-checking.. ++ */ ++typedef struct { unsigned long pte; } pte_t; ++typedef struct { unsigned long pmd; } pmd_t; ++typedef struct { unsigned long pud; } pud_t; ++typedef struct { unsigned long pgd; } pgd_t; ++#define PTE_MASK PHYSICAL_PAGE_MASK ++ ++typedef struct { unsigned long pgprot; } pgprot_t; ++ ++#define pte_val(x) (((x).pte & _PAGE_PRESENT) ? \ ++ pte_machine_to_phys((x).pte) : \ ++ (x).pte) ++#define pte_val_ma(x) ((x).pte) ++ ++static inline unsigned long pmd_val(pmd_t x) ++{ ++ unsigned long ret = x.pmd; ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret) ret = pte_machine_to_phys(ret) | _PAGE_PRESENT; ++#else ++ if (ret & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++#endif ++ return ret; ++} ++ ++static inline unsigned long pud_val(pud_t x) ++{ ++ unsigned long ret = x.pud; ++ if (ret & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++ return ret; ++} ++ ++static inline unsigned long pgd_val(pgd_t x) ++{ ++ unsigned long ret = x.pgd; ++ if (ret & _PAGE_PRESENT) ret = pte_machine_to_phys(ret); ++ return ret; ++} ++ ++#define pgprot_val(x) ((x).pgprot) ++ ++static inline pte_t __pte(unsigned long x) ++{ ++ if (x & _PAGE_PRESENT) x = pte_phys_to_machine(x); ++ return ((pte_t) { (x) }); ++} ++ ++static inline pmd_t __pmd(unsigned long x) ++{ ++ if (x & _PAGE_PRESENT) x = pte_phys_to_machine(x); ++ return ((pmd_t) { (x) }); ++} ++ ++static inline pud_t __pud(unsigned long x) ++{ ++ if (x & _PAGE_PRESENT) x = pte_phys_to_machine(x); ++ return ((pud_t) { (x) }); ++} ++ ++static inline pgd_t __pgd(unsigned long x) ++{ ++ if (x & _PAGE_PRESENT) x = pte_phys_to_machine(x); ++ return ((pgd_t) { (x) }); ++} ++ ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START) ++#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) ++#define __START_KERNEL_map 0xffffffff80000000UL ++#define __PAGE_OFFSET 0xffff880000000000UL ++ ++#else ++#define __PHYSICAL_START CONFIG_PHYSICAL_START ++#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) ++#define __START_KERNEL_map 0xffffffff80000000 ++#define __PAGE_OFFSET 0xffff880000000000 ++#endif /* !__ASSEMBLY__ */ ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++#undef LOAD_OFFSET ++#define LOAD_OFFSET 0 ++#endif ++ ++/* to align the pointer to the (next) page boundary */ ++#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) ++ ++#define KERNEL_TEXT_SIZE (40UL*1024*1024) ++#define KERNEL_TEXT_START 0xffffffff80000000UL ++ ++#ifndef __ASSEMBLY__ ++ ++#include <asm/bug.h> ++ ++#endif /* __ASSEMBLY__ */ ++ ++#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) ++ ++/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol. ++ Otherwise you risk miscompilation. */ ++#define __pa(x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET) ++/* __pa_symbol should be used for C visible symbols. ++ This seems to be the official gcc blessed way to do such arithmetic. */ ++#define __pa_symbol(x) \ ++ ({unsigned long v; \ ++ asm("" : "=r" (v) : "0" (x)); \ ++ __pa(v); }) ++ ++#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) ++#define __boot_va(x) __va(x) ++#define __boot_pa(x) __pa(x) ++#ifdef CONFIG_FLATMEM ++#define pfn_valid(pfn) ((pfn) < end_pfn) ++#endif ++ ++#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) ++#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) ++#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) ++ ++#define VM_DATA_DEFAULT_FLAGS \ ++ (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ ++ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) ++ ++#define __HAVE_ARCH_GATE_AREA 1 ++ ++#include <asm-generic/memory_model.h> ++#include <asm-generic/page.h> ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _X86_64_PAGE_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/pgalloc.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/pgalloc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,205 @@ ++#ifndef _X86_64_PGALLOC_H ++#define _X86_64_PGALLOC_H ++ ++#include <asm/fixmap.h> ++#include <asm/pda.h> ++#include <linux/threads.h> ++#include <linux/mm.h> ++#include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */ ++ ++#include <xen/features.h> ++void make_page_readonly(void *va, unsigned int feature); ++void make_page_writable(void *va, unsigned int feature); ++void make_pages_readonly(void *va, unsigned int nr, unsigned int feature); ++void make_pages_writable(void *va, unsigned int nr, unsigned int feature); ++ ++#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) ++ ++static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) ++{ ++ set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))); ++} ++ ++static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) ++{ ++ if (unlikely((mm)->context.pinned)) { ++ BUG_ON(HYPERVISOR_update_va_mapping( ++ (unsigned long)__va(page_to_pfn(pte) << PAGE_SHIFT), ++ pfn_pte(page_to_pfn(pte), PAGE_KERNEL_RO), 0)); ++ set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); ++ } else { ++ *(pmd) = __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)); ++ } ++} ++ ++static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) ++{ ++ if (unlikely((mm)->context.pinned)) { ++ BUG_ON(HYPERVISOR_update_va_mapping( ++ (unsigned long)pmd, ++ pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, ++ PAGE_KERNEL_RO), 0)); ++ set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))); ++ } else { ++ *(pud) = __pud(_PAGE_TABLE | __pa(pmd)); ++ } ++} ++ ++/* ++ * We need to use the batch mode here, but pgd_pupulate() won't be ++ * be called frequently. ++ */ ++static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) ++{ ++ if (unlikely((mm)->context.pinned)) { ++ BUG_ON(HYPERVISOR_update_va_mapping( ++ (unsigned long)pud, ++ pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, ++ PAGE_KERNEL_RO), 0)); ++ set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))); ++ set_pgd(__user_pgd(pgd), __pgd(_PAGE_TABLE | __pa(pud))); ++ } else { ++ *(pgd) = __pgd(_PAGE_TABLE | __pa(pud)); ++ *(__user_pgd(pgd)) = *(pgd); ++ } ++} ++ ++extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr); ++extern void pte_free(struct page *pte); ++ ++static inline void pmd_free(pmd_t *pmd) ++{ ++ BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); ++ pte_free(virt_to_page(pmd)); ++} ++ ++static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr) ++{ ++ struct page *pg; ++ ++ pg = pte_alloc_one(mm, addr); ++ return pg ? page_address(pg) : NULL; ++} ++ ++static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) ++{ ++ struct page *pg; ++ ++ pg = pte_alloc_one(mm, addr); ++ return pg ? page_address(pg) : NULL; ++} ++ ++static inline void pud_free (pud_t *pud) ++{ ++ BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); ++ pte_free(virt_to_page(pud)); ++} ++ ++static inline void pgd_list_add(pgd_t *pgd) ++{ ++ struct page *page = virt_to_page(pgd); ++ ++ spin_lock(&pgd_lock); ++ page->index = (pgoff_t)pgd_list; ++ if (pgd_list) ++ pgd_list->private = (unsigned long)&page->index; ++ pgd_list = page; ++ page->private = (unsigned long)&pgd_list; ++ spin_unlock(&pgd_lock); ++} ++ ++static inline void pgd_list_del(pgd_t *pgd) ++{ ++ struct page *next, **pprev, *page = virt_to_page(pgd); ++ ++ spin_lock(&pgd_lock); ++ next = (struct page *)page->index; ++ pprev = (struct page **)page->private; ++ *pprev = next; ++ if (next) ++ next->private = (unsigned long)pprev; ++ spin_unlock(&pgd_lock); ++} ++ ++static inline pgd_t *pgd_alloc(struct mm_struct *mm) ++{ ++ /* ++ * We allocate two contiguous pages for kernel and user. ++ */ ++ unsigned boundary; ++ pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 1); ++ if (!pgd) ++ return NULL; ++ pgd_list_add(pgd); ++ /* ++ * Copy kernel pointers in from init. ++ * Could keep a freelist or slab cache of those because the kernel ++ * part never changes. ++ */ ++ boundary = pgd_index(__PAGE_OFFSET); ++ memset(pgd, 0, boundary * sizeof(pgd_t)); ++ memcpy(pgd + boundary, ++ init_level4_pgt + boundary, ++ (PTRS_PER_PGD - boundary) * sizeof(pgd_t)); ++ ++ memset(__user_pgd(pgd), 0, PAGE_SIZE); /* clean up user pgd */ ++ /* ++ * Set level3_user_pgt for vsyscall area ++ */ ++ set_pgd(__user_pgd(pgd) + pgd_index(VSYSCALL_START), ++ mk_kernel_pgd(__pa_symbol(level3_user_pgt))); ++ return pgd; ++} ++ ++static inline void pgd_free(pgd_t *pgd) ++{ ++ pte_t *ptep = virt_to_ptep(pgd); ++ ++ if (!pte_write(*ptep)) { ++ xen_pgd_unpin(__pa(pgd)); ++ BUG_ON(HYPERVISOR_update_va_mapping( ++ (unsigned long)pgd, ++ pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, PAGE_KERNEL), ++ 0)); ++ } ++ ++ ptep = virt_to_ptep(__user_pgd(pgd)); ++ ++ if (!pte_write(*ptep)) { ++ xen_pgd_unpin(__pa(__user_pgd(pgd))); ++ BUG_ON(HYPERVISOR_update_va_mapping( ++ (unsigned long)__user_pgd(pgd), ++ pfn_pte(virt_to_phys(__user_pgd(pgd))>>PAGE_SHIFT, ++ PAGE_KERNEL), ++ 0)); ++ } ++ ++ pgd_list_del(pgd); ++ free_pages((unsigned long)pgd, 1); ++} ++ ++static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) ++{ ++ pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); ++ if (pte) ++ make_page_readonly(pte, XENFEAT_writable_page_tables); ++ ++ return pte; ++} ++ ++/* Should really implement gc for free page table pages. This could be ++ done with a reference count in struct page. */ ++ ++static inline void pte_free_kernel(pte_t *pte) ++{ ++ BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); ++ make_page_writable(pte, XENFEAT_writable_page_tables); ++ free_page((unsigned long)pte); ++} ++ ++#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) ++ ++#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) ++#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) ++ ++#endif /* _X86_64_PGALLOC_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/pgtable.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/pgtable.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,569 @@ ++#ifndef _X86_64_PGTABLE_H ++#define _X86_64_PGTABLE_H ++ ++/* ++ * This file contains the functions and defines necessary to modify and use ++ * the x86-64 page table tree. ++ */ ++#include <asm/processor.h> ++#include <asm/fixmap.h> ++#include <asm/bitops.h> ++#include <linux/threads.h> ++#include <linux/sched.h> ++#include <asm/pda.h> ++#ifdef CONFIG_XEN ++#include <asm/hypervisor.h> ++ ++extern pud_t level3_user_pgt[512]; ++extern pud_t init_level4_user_pgt[]; ++ ++extern void xen_init_pt(void); ++ ++#define virt_to_ptep(__va) \ ++({ \ ++ pgd_t *__pgd = pgd_offset_k((unsigned long)(__va)); \ ++ pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va)); \ ++ pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va)); \ ++ pte_offset_kernel(__pmd, (unsigned long)(__va)); \ ++}) ++ ++#define arbitrary_virt_to_machine(__va) \ ++({ \ ++ maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\ ++ m | ((unsigned long)(__va) & (PAGE_SIZE-1)); \ ++}) ++#endif ++ ++extern pud_t level3_kernel_pgt[512]; ++extern pud_t level3_physmem_pgt[512]; ++extern pud_t level3_ident_pgt[512]; ++extern pmd_t level2_kernel_pgt[512]; ++extern pgd_t init_level4_pgt[]; ++extern pgd_t boot_level4_pgt[]; ++extern unsigned long __supported_pte_mask; ++ ++#define swapper_pg_dir init_level4_pgt ++ ++extern void paging_init(void); ++extern void clear_kernel_mapping(unsigned long addr, unsigned long size); ++ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; ++#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) ++ ++/* ++ * PGDIR_SHIFT determines what a top-level page table entry can map ++ */ ++#define PGDIR_SHIFT 39 ++#define PTRS_PER_PGD 512 ++ ++/* ++ * 3rd level page ++ */ ++#define PUD_SHIFT 30 ++#define PTRS_PER_PUD 512 ++ ++/* ++ * PMD_SHIFT determines the size of the area a middle-level ++ * page table can map ++ */ ++#define PMD_SHIFT 21 ++#define PTRS_PER_PMD 512 ++ ++/* ++ * entries per page directory level ++ */ ++#define PTRS_PER_PTE 512 ++ ++#define pte_ERROR(e) \ ++ printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e)) ++#define pmd_ERROR(e) \ ++ printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), pmd_val(e)) ++#define pud_ERROR(e) \ ++ printk("%s:%d: bad pud %p(%016lx).\n", __FILE__, __LINE__, &(e), pud_val(e)) ++#define pgd_ERROR(e) \ ++ printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) ++ ++#define pgd_none(x) (!pgd_val(x)) ++#define pud_none(x) (!pud_val(x)) ++ ++static inline void set_pte(pte_t *dst, pte_t val) ++{ ++ *dst = val; ++} ++#define set_pte_at(_mm,addr,ptep,pteval) do { \ ++ if (((_mm) != current->mm && (_mm) != &init_mm) || \ ++ HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \ ++ set_pte((ptep), (pteval)); \ ++} while (0) ++ ++#define set_pmd(pmdptr, pmdval) xen_l2_entry_update(pmdptr, (pmdval)) ++ ++#define set_pud(pudptr, pudval) xen_l3_entry_update(pudptr, (pudval)) ++ ++static inline void pud_clear (pud_t *pud) ++{ ++ set_pud(pud, __pud(0)); ++} ++ ++#define set_pgd(pgdptr, pgdval) xen_l4_entry_update(pgdptr, (pgdval)) ++ ++#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) ++ ++static inline void pgd_clear (pgd_t * pgd) ++{ ++ set_pgd(pgd, __pgd(0)); ++ set_pgd(__user_pgd(pgd), __pgd(0)); ++} ++ ++#define pte_same(a, b) ((a).pte == (b).pte) ++ ++#define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK)) ++ ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE-1)) ++#define PUD_SIZE (1UL << PUD_SHIFT) ++#define PUD_MASK (~(PUD_SIZE-1)) ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE-1)) ++ ++#define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1) ++#define FIRST_USER_ADDRESS 0 ++ ++#ifndef __ASSEMBLY__ ++#define MAXMEM 0x3fffffffffffUL ++#define VMALLOC_START 0xffffc20000000000UL ++#define VMALLOC_END 0xffffe1ffffffffffUL ++#define MODULES_VADDR 0xffffffff88000000UL ++#define MODULES_END 0xfffffffffff00000UL ++#define MODULES_LEN (MODULES_END - MODULES_VADDR) ++ ++#define _PAGE_BIT_PRESENT 0 ++#define _PAGE_BIT_RW 1 ++#define _PAGE_BIT_USER 2 ++#define _PAGE_BIT_PWT 3 ++#define _PAGE_BIT_PCD 4 ++#define _PAGE_BIT_ACCESSED 5 ++#define _PAGE_BIT_DIRTY 6 ++#define _PAGE_BIT_PSE 7 /* 4 MB (or 2MB) page */ ++#define _PAGE_BIT_GLOBAL 8 /* Global TLB entry PPro+ */ ++#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */ ++ ++#define _PAGE_PRESENT 0x001 ++#define _PAGE_RW 0x002 ++#define _PAGE_USER 0x004 ++#define _PAGE_PWT 0x008 ++#define _PAGE_PCD 0x010 ++#define _PAGE_ACCESSED 0x020 ++#define _PAGE_DIRTY 0x040 ++#define _PAGE_PSE 0x080 /* 2MB page */ ++#define _PAGE_FILE 0x040 /* nonlinear file mapping, saved PTE; unset:swap */ ++#define _PAGE_GLOBAL 0x100 /* Global TLB entry */ ++ ++#define _PAGE_PROTNONE 0x080 /* If not present */ ++#define _PAGE_NX (1UL<<_PAGE_BIT_NX) ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++extern unsigned int __kernel_page_user; ++#else ++#define __kernel_page_user 0 ++#endif ++ ++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) ++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user) ++ ++#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) ++ ++#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) ++#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) ++#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) ++#define PAGE_COPY PAGE_COPY_NOEXEC ++#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX) ++#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define __PAGE_KERNEL \ ++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) ++#define __PAGE_KERNEL_EXEC \ ++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | __kernel_page_user) ++#define __PAGE_KERNEL_NOCACHE \ ++ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) ++#define __PAGE_KERNEL_RO \ ++ (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX | __kernel_page_user) ++#define __PAGE_KERNEL_VSYSCALL \ ++ (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define __PAGE_KERNEL_VSYSCALL_NOCACHE \ ++ (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD) ++#define __PAGE_KERNEL_LARGE \ ++ (__PAGE_KERNEL | _PAGE_PSE) ++#define __PAGE_KERNEL_LARGE_EXEC \ ++ (__PAGE_KERNEL_EXEC | _PAGE_PSE) ++ ++/* ++ * We don't support GLOBAL page in xenolinux64 ++ */ ++#define MAKE_GLOBAL(x) __pgprot((x)) ++ ++#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL) ++#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC) ++#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO) ++#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE) ++#define PAGE_KERNEL_VSYSCALL32 __pgprot(__PAGE_KERNEL_VSYSCALL) ++#define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL) ++#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE) ++#define PAGE_KERNEL_VSYSCALL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL_NOCACHE) ++ ++/* xwr */ ++#define __P000 PAGE_NONE ++#define __P001 PAGE_READONLY ++#define __P010 PAGE_COPY ++#define __P011 PAGE_COPY ++#define __P100 PAGE_READONLY_EXEC ++#define __P101 PAGE_READONLY_EXEC ++#define __P110 PAGE_COPY_EXEC ++#define __P111 PAGE_COPY_EXEC ++ ++#define __S000 PAGE_NONE ++#define __S001 PAGE_READONLY ++#define __S010 PAGE_SHARED ++#define __S011 PAGE_SHARED ++#define __S100 PAGE_READONLY_EXEC ++#define __S101 PAGE_READONLY_EXEC ++#define __S110 PAGE_SHARED_EXEC ++#define __S111 PAGE_SHARED_EXEC ++ ++static inline unsigned long pgd_bad(pgd_t pgd) ++{ ++ return pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); ++} ++ ++static inline unsigned long pud_bad(pud_t pud) ++{ ++ return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); ++} ++ ++static inline unsigned long pmd_bad(pmd_t pmd) ++{ ++ return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); ++} ++ ++#define pte_none(x) (!(x).pte) ++#define pte_present(x) ((x).pte & (_PAGE_PRESENT | _PAGE_PROTNONE)) ++#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) ++ ++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))/* FIXME: is this ++ right? */ ++#define pte_page(x) pfn_to_page(pte_pfn(x)) ++#define __pte_mfn(_pte) (((_pte).pte & PTE_MASK) >> PAGE_SHIFT) ++#define pte_mfn(_pte) ((_pte).pte & _PAGE_PRESENT ? \ ++ __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte))) ++#define pte_pfn(_pte) ((_pte).pte & _PAGE_PRESENT ? \ ++ mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte)) ++ ++static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) ++{ ++ unsigned long pte = page_nr << PAGE_SHIFT; ++ pte |= pgprot_val(pgprot); ++ pte &= __supported_pte_mask; ++ return __pte(pte); ++} ++ ++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_none(pte)) { ++ if (mm != &init_mm) ++ pte = __pte_ma(xchg(&ptep->pte, 0)); ++ else ++ HYPERVISOR_update_va_mapping(addr, __pte(0), 0); ++ } ++ return pte; ++} ++ ++static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full) ++{ ++ if (full) { ++ pte_t pte = *ptep; ++ if (mm->context.pinned) ++ xen_l1_entry_update(ptep, __pte(0)); ++ else ++ *ptep = __pte(0); ++ return pte; ++ } ++ return ptep_get_and_clear(mm, addr, ptep); ++} ++ ++#define ptep_clear_flush(vma, addr, ptep) \ ++({ \ ++ pte_t *__ptep = (ptep); \ ++ pte_t __res = *__ptep; \ ++ if (!pte_none(__res) && \ ++ ((vma)->vm_mm != current->mm || \ ++ HYPERVISOR_update_va_mapping(addr, __pte(0), \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI))) { \ ++ __ptep->pte = 0; \ ++ flush_tlb_page(vma, addr); \ ++ } \ ++ __res; \ ++}) ++ ++/* ++ * The following only work if pte_present() is true. ++ * Undefined behaviour if not.. ++ */ ++#define __pte_val(x) ((x).pte) ++ ++#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) ++static inline int pte_user(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } ++static inline int pte_read(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } ++static inline int pte_exec(pte_t pte) { return !(__pte_val(pte) & _PAGE_NX); } ++static inline int pte_dirty(pte_t pte) { return __pte_val(pte) & _PAGE_DIRTY; } ++static inline int pte_young(pte_t pte) { return __pte_val(pte) & _PAGE_ACCESSED; } ++static inline int pte_write(pte_t pte) { return __pte_val(pte) & _PAGE_RW; } ++static inline int pte_file(pte_t pte) { return __pte_val(pte) & _PAGE_FILE; } ++static inline int pte_huge(pte_t pte) { return __pte_val(pte) & _PAGE_PSE; } ++ ++static inline pte_t pte_rdprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; } ++static inline pte_t pte_exprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; } ++static inline pte_t pte_mkclean(pte_t pte) { __pte_val(pte) &= ~_PAGE_DIRTY; return pte; } ++static inline pte_t pte_mkold(pte_t pte) { __pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } ++static inline pte_t pte_wrprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_RW; return pte; } ++static inline pte_t pte_mkread(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; } ++static inline pte_t pte_mkexec(pte_t pte) { __pte_val(pte) &= ~_PAGE_NX; return pte; } ++static inline pte_t pte_mkdirty(pte_t pte) { __pte_val(pte) |= _PAGE_DIRTY; return pte; } ++static inline pte_t pte_mkyoung(pte_t pte) { __pte_val(pte) |= _PAGE_ACCESSED; return pte; } ++static inline pte_t pte_mkwrite(pte_t pte) { __pte_val(pte) |= _PAGE_RW; return pte; } ++static inline pte_t pte_mkhuge(pte_t pte) { __pte_val(pte) |= _PAGE_PSE; return pte; } ++static inline pte_t pte_clrhuge(pte_t pte) { __pte_val(pte) &= ~_PAGE_PSE; return pte; } ++ ++#define ptep_test_and_clear_dirty(vma, addr, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __ret = pte_dirty(__pte); \ ++ if (__ret) \ ++ set_pte_at((vma)->vm_mm, addr, ptep, pte_mkclean(__pte)); \ ++ __ret; \ ++}) ++ ++#define ptep_test_and_clear_young(vma, addr, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __ret = pte_young(__pte); \ ++ if (__ret) \ ++ set_pte_at((vma)->vm_mm, addr, ptep, pte_mkold(__pte)); \ ++ __ret; \ ++}) ++ ++static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (pte_write(pte)) ++ set_pte_at(mm, addr, ptep, pte_wrprotect(pte)); ++} ++ ++/* ++ * Macro to mark a page protection value as "uncacheable". ++ */ ++#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) ++ ++static inline int pmd_large(pmd_t pte) { ++ return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE; ++} ++ ++ ++/* ++ * Conversion functions: convert a page and protection to a page entry, ++ * and a page entry and page directory to the page they refer to. ++ */ ++ ++/* ++ * Level 4 access. ++ * Never use these in the common code. ++ */ ++#define pgd_page_vaddr(pgd) ((unsigned long) __va((unsigned long)pgd_val(pgd) & PTE_MASK)) ++#define pgd_page(pgd) (pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)) ++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) ++#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) ++#define pgd_offset_k(address) (init_level4_pgt + pgd_index(address)) ++#define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT) ++#define mk_kernel_pgd(address) __pgd((address) | _KERNPG_TABLE) ++ ++/* PUD - Level3 access */ ++/* to find an entry in a page-table-directory. */ ++#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK)) ++#define pud_page(pud) (pfn_to_page(pud_val(pud) >> PAGE_SHIFT)) ++#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) ++#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address)) ++#define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT) ++ ++/* PMD - Level 2 access */ ++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK)) ++#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) ++ ++#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) ++#define pmd_offset(dir, address) ((pmd_t *) pud_page_vaddr(*(dir)) + \ ++ pmd_index(address)) ++#define pmd_none(x) (!pmd_val(x)) ++#if CONFIG_XEN_COMPAT <= 0x030002 ++/* pmd_present doesn't just test the _PAGE_PRESENT bit since wr.p.t. ++ can temporarily clear it. */ ++#define pmd_present(x) (pmd_val(x)) ++#else ++#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) ++#endif ++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot))) ++#define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT) ++ ++#define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT) ++#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE }) ++#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT ++ ++/* PTE - Level 1 access. */ ++ ++/* page, protection -> pte */ ++#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) ++#define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE) ++ ++/* physical address -> PTE */ ++static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) ++{ ++ pte_t pte; ++ pte.pte = physpage | pgprot_val(pgprot); ++ pte.pte &= __supported_pte_mask; ++ return pte; ++} ++ ++/* Change flags of a PTE */ ++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ++{ ++ /* ++ * Since this might change the present bit (which controls whether ++ * a pte_t object has undergone p2m translation), we must use ++ * pte_val() on the input pte and __pte() for the return value. ++ */ ++ unsigned long pteval = pte_val(pte); ++ ++ pteval &= _PAGE_CHG_MASK; ++ pteval |= pgprot_val(newprot); ++ pteval &= __supported_pte_mask; ++ return __pte(pteval); ++} ++ ++#define pte_index(address) \ ++ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ++#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \ ++ pte_index(address)) ++ ++/* x86-64 always has all page tables mapped. */ ++#define pte_offset_map(dir,address) pte_offset_kernel(dir,address) ++#define pte_offset_map_nested(dir,address) pte_offset_kernel(dir,address) ++#define pte_unmap(pte) /* NOP */ ++#define pte_unmap_nested(pte) /* NOP */ ++ ++#define update_mmu_cache(vma,address,pte) do { } while (0) ++ ++/* ++ * Rules for using ptep_establish: the pte MUST be a user pte, and ++ * must be a present->present transition. ++ */ ++#define __HAVE_ARCH_PTEP_ESTABLISH ++#define ptep_establish(vma, address, ptep, pteval) \ ++ do { \ ++ if ( likely((vma)->vm_mm == current->mm) ) { \ ++ BUG_ON(HYPERVISOR_update_va_mapping(address, \ ++ pteval, \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI)); \ ++ } else { \ ++ xen_l1_entry_update(ptep, pteval); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++ } while (0) ++ ++/* We only update the dirty/accessed state if we set ++ * the dirty bit by hand in the kernel, since the hardware ++ * will do the accessed bit for us, and we don't want to ++ * race with other CPU's that might be updating the dirty ++ * bit at the same time. */ ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ ++ do { \ ++ if (__dirty) \ ++ ptep_establish(__vma, __address, __ptep, __entry);\ ++ } while (0) ++ ++/* Encode and de-code a swap entry */ ++#define __swp_type(x) (((x).val >> 1) & 0x3f) ++#define __swp_offset(x) ((x).val >> 8) ++#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) ++#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++extern spinlock_t pgd_lock; ++extern struct page *pgd_list; ++void vmalloc_sync_all(void); ++ ++#endif /* !__ASSEMBLY__ */ ++ ++extern int kern_addr_valid(unsigned long addr); ++ ++#define DOMID_LOCAL (0xFFFFU) ++ ++struct vm_area_struct; ++ ++int direct_remap_pfn_range(struct vm_area_struct *vma, ++ unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid); ++ ++int direct_kernel_remap_pfn_range(unsigned long address, ++ unsigned long mfn, ++ unsigned long size, ++ pgprot_t prot, ++ domid_t domid); ++ ++int create_lookup_pte_addr(struct mm_struct *mm, ++ unsigned long address, ++ uint64_t *ptep); ++ ++int touch_pte_range(struct mm_struct *mm, ++ unsigned long address, ++ unsigned long size); ++ ++#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ ++ direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO) ++ ++#define MK_IOSPACE_PFN(space, pfn) (pfn) ++#define GET_IOSPACE(pfn) 0 ++#define GET_PFN(pfn) (pfn) ++ ++#define HAVE_ARCH_UNMAPPED_AREA ++ ++#define pgtable_cache_init() do { } while (0) ++#define check_pgt_cache() do { } while (0) ++ ++#define PAGE_AGP PAGE_KERNEL_NOCACHE ++#define HAVE_PAGE_AGP 1 ++ ++/* fs/proc/kcore.c */ ++#define kc_vaddr_to_offset(v) ((v) & __VIRTUAL_MASK) ++#define kc_offset_to_vaddr(o) \ ++ (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o)) ++ ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL ++#define __HAVE_ARCH_PTEP_CLEAR_FLUSH ++#define __HAVE_ARCH_PTEP_SET_WRPROTECT ++#define __HAVE_ARCH_PTE_SAME ++#include <asm-generic/pgtable.h> ++ ++#endif /* _X86_64_PGTABLE_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/synch_bitops.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/synch_bitops.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,2 @@ ++ ++#include <asm-i386/mach-xen/asm/synch_bitops.h> +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/timer.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/timer.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,11 @@ ++#ifndef _ASMi386_TIMER_H ++#define _ASMi386_TIMER_H ++#include <linux/init.h> ++ ++#define TICK_SIZE (tick_nsec / 1000) ++void setup_pit_timer(void); ++/* Modifiers for buggy PIT handling */ ++extern int pit_latch_buggy; ++extern int timer_ack; ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/asm/xenoprof.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/asm/xenoprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,1 @@ ++#include <asm-i386/mach-xen/asm/xenoprof.h> +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/irq_vectors.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/irq_vectors.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,123 @@ ++/* ++ * This file should contain #defines for all of the interrupt vector ++ * numbers used by this architecture. ++ * ++ * In addition, there are some standard defines: ++ * ++ * FIRST_EXTERNAL_VECTOR: ++ * The first free place for external interrupts ++ * ++ * SYSCALL_VECTOR: ++ * The IRQ vector a syscall makes the user to kernel transition ++ * under. ++ * ++ * TIMER_IRQ: ++ * The IRQ number the timer interrupt comes in at. ++ * ++ * NR_IRQS: ++ * The total number of interrupt vectors (including all the ++ * architecture specific interrupts) needed. ++ * ++ */ ++#ifndef _ASM_IRQ_VECTORS_H ++#define _ASM_IRQ_VECTORS_H ++ ++/* ++ * IDT vectors usable for external interrupt sources start ++ * at 0x20: ++ */ ++#define FIRST_EXTERNAL_VECTOR 0x20 ++ ++#define SYSCALL_VECTOR 0x80 ++ ++/* ++ * Vectors 0x20-0x2f are used for ISA interrupts. ++ */ ++ ++#if 0 ++/* ++ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff ++ * ++ * some of the following vectors are 'rare', they are merged ++ * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. ++ * TLB, reschedule and local APIC vectors are performance-critical. ++ * ++ * Vectors 0xf0-0xfa are free (reserved for future Linux use). ++ */ ++#define INVALIDATE_TLB_VECTOR 0xfd ++#define RESCHEDULE_VECTOR 0xfc ++#define CALL_FUNCTION_VECTOR 0xfb ++ ++#define THERMAL_APIC_VECTOR 0xf0 ++/* ++ * Local APIC timer IRQ vector is on a different priority level, ++ * to work around the 'lost local interrupt if more than 2 IRQ ++ * sources per level' errata. ++ */ ++#define LOCAL_TIMER_VECTOR 0xef ++#endif ++ ++#define SPURIOUS_APIC_VECTOR 0xff ++#define ERROR_APIC_VECTOR 0xfe ++ ++/* ++ * First APIC vector available to drivers: (vectors 0x30-0xee) ++ * we start at 0x31 to spread out vectors evenly between priority ++ * levels. (0x80 is the syscall vector) ++ */ ++#define FIRST_DEVICE_VECTOR 0x31 ++#define FIRST_SYSTEM_VECTOR 0xef ++ ++/* ++ * 16 8259A IRQ's, 208 potential APIC interrupt sources. ++ * Right now the APIC is mostly only used for SMP. ++ * 256 vectors is an architectural limit. (we can have ++ * more than 256 devices theoretically, but they will ++ * have to use shared interrupts) ++ * Since vectors 0x00-0x1f are used/reserved for the CPU, ++ * the usable vector space is 0x20-0xff (224 vectors) ++ */ ++ ++#define RESCHEDULE_VECTOR 0 ++#define CALL_FUNCTION_VECTOR 1 ++#define NR_IPIS 2 ++ ++/* ++ * The maximum number of vectors supported by i386 processors ++ * is limited to 256. For processors other than i386, NR_VECTORS ++ * should be changed accordingly. ++ */ ++#define NR_VECTORS 256 ++ ++#define FPU_IRQ 13 ++ ++#define FIRST_VM86_IRQ 3 ++#define LAST_VM86_IRQ 15 ++#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) ++ ++/* ++ * The flat IRQ space is divided into two regions: ++ * 1. A one-to-one mapping of real physical IRQs. This space is only used ++ * if we have physical device-access privilege. This region is at the ++ * start of the IRQ space so that existing device drivers do not need ++ * to be modified to translate physical IRQ numbers into our IRQ space. ++ * 3. A dynamic mapping of inter-domain and Xen-sourced virtual IRQs. These ++ * are bound using the provided bind/unbind functions. ++ */ ++ ++#define PIRQ_BASE 0 ++#define NR_PIRQS 256 ++ ++#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS) ++#define NR_DYNIRQS 256 ++ ++#define NR_IRQS (NR_PIRQS + NR_DYNIRQS) ++#define NR_IRQ_VECTORS NR_IRQS ++ ++#define pirq_to_irq(_x) ((_x) + PIRQ_BASE) ++#define irq_to_pirq(_x) ((_x) - PIRQ_BASE) ++ ++#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) ++#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) ++ ++#endif /* _ASM_IRQ_VECTORS_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/mach_time.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/mach_time.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,111 @@ ++/* ++ * include/asm-i386/mach-default/mach_time.h ++ * ++ * Machine specific set RTC function for generic. ++ * Split out from time.c by Osamu Tomita <tomita@cinet.co.jp> ++ */ ++#ifndef _MACH_TIME_H ++#define _MACH_TIME_H ++ ++#include <asm-i386/mc146818rtc.h> ++ ++/* for check timing call set_rtc_mmss() 500ms */ ++/* used in arch/i386/time.c::do_timer_interrupt() */ ++#define USEC_AFTER 500000 ++#define USEC_BEFORE 500000 ++ ++/* ++ * In order to set the CMOS clock precisely, set_rtc_mmss has to be ++ * called 500 ms after the second nowtime has started, because when ++ * nowtime is written into the registers of the CMOS clock, it will ++ * jump to the next second precisely 500 ms later. Check the Motorola ++ * MC146818A or Dallas DS12887 data sheet for details. ++ * ++ * BUG: This routine does not handle hour overflow properly; it just ++ * sets the minutes. Usually you'll only notice that after reboot! ++ */ ++static inline int mach_set_rtc_mmss(unsigned long nowtime) ++{ ++ int retval = 0; ++ int real_seconds, real_minutes, cmos_minutes; ++ unsigned char save_control, save_freq_select; ++ ++ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ ++ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); ++ ++ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ ++ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); ++ ++ cmos_minutes = CMOS_READ(RTC_MINUTES); ++ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) ++ BCD_TO_BIN(cmos_minutes); ++ ++ /* ++ * since we're only adjusting minutes and seconds, ++ * don't interfere with hour overflow. This avoids ++ * messing with unknown time zones but requires your ++ * RTC not to be off by more than 15 minutes ++ */ ++ real_seconds = nowtime % 60; ++ real_minutes = nowtime / 60; ++ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) ++ real_minutes += 30; /* correct for half hour time zone */ ++ real_minutes %= 60; ++ ++ if (abs(real_minutes - cmos_minutes) < 30) { ++ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { ++ BIN_TO_BCD(real_seconds); ++ BIN_TO_BCD(real_minutes); ++ } ++ CMOS_WRITE(real_seconds,RTC_SECONDS); ++ CMOS_WRITE(real_minutes,RTC_MINUTES); ++ } else { ++ printk(KERN_WARNING ++ "set_rtc_mmss: can't update from %d to %d\n", ++ cmos_minutes, real_minutes); ++ retval = -1; ++ } ++ ++ /* The following flags have to be released exactly in this order, ++ * otherwise the DS12887 (popular MC146818A clone with integrated ++ * battery and quartz) will not reset the oscillator and will not ++ * update precisely 500 ms later. You won't find this mentioned in ++ * the Dallas Semiconductor data sheets, but who believes data ++ * sheets anyway ... -- Markus Kuhn ++ */ ++ CMOS_WRITE(save_control, RTC_CONTROL); ++ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); ++ ++ return retval; ++} ++ ++static inline unsigned long mach_get_cmos_time(void) ++{ ++ unsigned int year, mon, day, hour, min, sec; ++ ++ do { ++ sec = CMOS_READ(RTC_SECONDS); ++ min = CMOS_READ(RTC_MINUTES); ++ hour = CMOS_READ(RTC_HOURS); ++ day = CMOS_READ(RTC_DAY_OF_MONTH); ++ mon = CMOS_READ(RTC_MONTH); ++ year = CMOS_READ(RTC_YEAR); ++ } while (sec != CMOS_READ(RTC_SECONDS)); ++ ++ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { ++ BCD_TO_BIN(sec); ++ BCD_TO_BIN(min); ++ BCD_TO_BIN(hour); ++ BCD_TO_BIN(day); ++ BCD_TO_BIN(mon); ++ BCD_TO_BIN(year); ++ } ++ ++ year += 1900; ++ if (year < 1970) ++ year += 100; ++ ++ return mktime(year, mon, day, hour, min, sec); ++} ++ ++#endif /* !_MACH_TIME_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/mach_timer.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/mach_timer.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,50 @@ ++/* ++ * include/asm-i386/mach-default/mach_timer.h ++ * ++ * Machine specific calibrate_tsc() for generic. ++ * Split out from timer_tsc.c by Osamu Tomita <tomita@cinet.co.jp> ++ */ ++/* ------ Calibrate the TSC ------- ++ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). ++ * Too much 64-bit arithmetic here to do this cleanly in C, and for ++ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) ++ * output busy loop as low as possible. We avoid reading the CTC registers ++ * directly because of the awkward 8-bit access mechanism of the 82C54 ++ * device. ++ */ ++#ifndef _MACH_TIMER_H ++#define _MACH_TIMER_H ++ ++#define CALIBRATE_TIME_MSEC 30 /* 30 msecs */ ++#define CALIBRATE_LATCH \ ++ ((CLOCK_TICK_RATE * CALIBRATE_TIME_MSEC + 1000/2)/1000) ++ ++static inline void mach_prepare_counter(void) ++{ ++ /* Set the Gate high, disable speaker */ ++ outb((inb(0x61) & ~0x02) | 0x01, 0x61); ++ ++ /* ++ * Now let's take care of CTC channel 2 ++ * ++ * Set the Gate high, program CTC channel 2 for mode 0, ++ * (interrupt on terminal count mode), binary count, ++ * load 5 * LATCH count, (LSB and MSB) to begin countdown. ++ * ++ * Some devices need a delay here. ++ */ ++ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ ++ outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ ++ outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ ++} ++ ++static inline void mach_countup(unsigned long *count_p) ++{ ++ unsigned long count = 0; ++ do { ++ count++; ++ } while ((inb_p(0x61) & 0x20) == 0); ++ *count_p = count; ++} ++ ++#endif /* !_MACH_TIMER_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/setup_arch_post.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/setup_arch_post.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,63 @@ ++/** ++ * machine_specific_* - Hooks for machine specific setup. ++ * ++ * Description: ++ * This is included late in kernel/setup.c so that it can make ++ * use of all of the static functions. ++ **/ ++ ++#include <xen/interface/callback.h> ++ ++extern void hypervisor_callback(void); ++extern void failsafe_callback(void); ++extern void nmi(void); ++ ++static void __init machine_specific_arch_setup(void) ++{ ++ int ret; ++ static struct callback_register __initdata event = { ++ .type = CALLBACKTYPE_event, ++ .address = (unsigned long) hypervisor_callback, ++ }; ++ static struct callback_register __initdata failsafe = { ++ .type = CALLBACKTYPE_failsafe, ++ .address = (unsigned long)failsafe_callback, ++ }; ++ static struct callback_register __initdata syscall = { ++ .type = CALLBACKTYPE_syscall, ++ .address = (unsigned long)system_call, ++ }; ++#ifdef CONFIG_X86_LOCAL_APIC ++ static struct callback_register __initdata nmi_cb = { ++ .type = CALLBACKTYPE_nmi, ++ .address = (unsigned long)nmi, ++ }; ++#endif ++ ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event); ++ if (ret == 0) ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe); ++ if (ret == 0) ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &syscall); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret == -ENOSYS) ++ ret = HYPERVISOR_set_callbacks( ++ event.address, ++ failsafe.address, ++ syscall.address); ++#endif ++ BUG_ON(ret); ++ ++#ifdef CONFIG_X86_LOCAL_APIC ++ ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb); ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (ret == -ENOSYS) { ++ static struct xennmi_callback __initdata cb = { ++ .handler_address = (unsigned long)nmi ++ }; ++ ++ HYPERVISOR_nmi_op(XENNMI_register_callback, &cb); ++ } ++#endif ++#endif ++} +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mach-xen/setup_arch_pre.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/asm-x86_64/mach-xen/setup_arch_pre.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,5 @@ ++/* Hook to call BIOS initialisation function */ ++ ++#define ARCH_SETUP machine_specific_arch_setup(); ++ ++static void __init machine_specific_arch_setup(void); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/mmu.h +--- a/include/asm-x86_64/mmu.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/mmu.h Wed Aug 08 16:25:28 2007 -0300 +@@ -15,6 +15,24 @@ typedef struct { + rwlock_t ldtlock; + int size; + struct semaphore sem; ++#ifdef CONFIG_XEN ++ unsigned pinned:1; ++ unsigned has_foreign_mappings:1; ++ struct list_head unpinned; ++#endif + } mm_context_t; + ++#ifdef CONFIG_XEN ++extern struct list_head mm_unpinned; ++extern spinlock_t mm_unpinned_lock; ++ ++/* mm/memory.c:exit_mmap hook */ ++extern void _arch_exit_mmap(struct mm_struct *mm); ++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm) ++ ++/* kernel/fork.c:dup_mmap hook */ ++extern void _arch_dup_mmap(struct mm_struct *mm); ++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm)) + #endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/msr.h +--- a/include/asm-x86_64/msr.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/msr.h Wed Aug 08 16:25:28 2007 -0300 +@@ -90,10 +90,16 @@ + : "=a" (low), "=d" (high) \ + : "c" (counter)) + ++#ifdef CONFIG_XEN ++#define CPUID_STRING XEN_CPUID ++#else ++#define CPUID_STRING "cpuid" ++#endif ++ + static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) + { +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), +@@ -105,7 +111,7 @@ static inline void cpuid_count(int op, i + static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, + int *edx) + { +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), +@@ -120,7 +126,7 @@ static inline unsigned int cpuid_eax(uns + { + unsigned int eax; + +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (eax) + : "0" (op) + : "bx", "cx", "dx"); +@@ -130,7 +136,7 @@ static inline unsigned int cpuid_ebx(uns + { + unsigned int eax, ebx; + +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (eax), "=b" (ebx) + : "0" (op) + : "cx", "dx" ); +@@ -140,7 +146,7 @@ static inline unsigned int cpuid_ecx(uns + { + unsigned int eax, ecx; + +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (eax), "=c" (ecx) + : "0" (op) + : "bx", "dx" ); +@@ -150,7 +156,7 @@ static inline unsigned int cpuid_edx(uns + { + unsigned int eax, edx; + +- __asm__("cpuid" ++ __asm__(CPUID_STRING + : "=a" (eax), "=d" (edx) + : "0" (op) + : "bx", "cx"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/nmi.h +--- a/include/asm-x86_64/nmi.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/nmi.h Wed Aug 08 16:25:28 2007 -0300 +@@ -7,6 +7,10 @@ + #include <linux/pm.h> + #include <asm/io.h> + ++#ifdef CONFIG_XEN ++#include <xen/interface/nmi.h> ++#endif ++ + /** + * do_nmi_callback + * +@@ -39,7 +43,25 @@ extern void default_do_nmi(struct pt_reg + extern void default_do_nmi(struct pt_regs *); + extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); + ++#ifdef CONFIG_XEN ++static inline unsigned char get_nmi_reason(void) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ unsigned char reason = 0; ++ ++ /* construct a value which looks like it came from ++ * port 0x61. ++ */ ++ if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason)) ++ reason |= 0x40; ++ if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason)) ++ reason |= 0x80; ++ ++ return reason; ++} ++#else + #define get_nmi_reason() inb(0x61) ++#endif + + extern int panic_on_timeout; + extern int unknown_nmi_panic; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/pci.h +--- a/include/asm-x86_64/pci.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/pci.h Wed Aug 08 16:25:28 2007 -0300 +@@ -61,6 +61,23 @@ extern int iommu_setup(char *opt); + */ + extern int iommu_sac_force; + #define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force) ++ ++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ ++ dma_addr_t ADDR_NAME; ++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ ++ __u32 LEN_NAME; ++#define pci_unmap_addr(PTR, ADDR_NAME) \ ++ ((PTR)->ADDR_NAME) ++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ ++ (((PTR)->ADDR_NAME) = (VAL)) ++#define pci_unmap_len(PTR, LEN_NAME) \ ++ ((PTR)->LEN_NAME) ++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ ++ (((PTR)->LEN_NAME) = (VAL)) ++ ++#elif defined(CONFIG_SWIOTLB) ++ ++#define pci_dac_dma_supported(pci_dev, mask) 1 + + #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ + dma_addr_t ADDR_NAME; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/processor.h +--- a/include/asm-x86_64/processor.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/processor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -188,7 +188,9 @@ static inline void clear_in_cr4 (unsigne + #define IO_BITMAP_BITS 65536 + #define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) + #define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) ++#ifndef CONFIG_X86_NO_TSS + #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap) ++#endif + #define INVALID_IO_BITMAP_OFFSET 0x8000 + + struct i387_fxsave_struct { +@@ -209,6 +211,7 @@ union i387_union { + struct i387_fxsave_struct fxsave; + }; + ++#ifndef CONFIG_X86_NO_TSS + struct tss_struct { + u32 reserved1; + u64 rsp0; +@@ -231,15 +234,18 @@ struct tss_struct { + */ + unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; + } __attribute__((packed)) ____cacheline_aligned; ++#endif + + + extern struct cpuinfo_x86 boot_cpu_data; ++#ifndef CONFIG_X86_NO_TSS + DECLARE_PER_CPU(struct tss_struct,init_tss); + /* Save the original ist values for checking stack pointers during debugging */ + struct orig_ist { + unsigned long ist[7]; + }; + DECLARE_PER_CPU(struct orig_ist, orig_ist); ++#endif + + #ifdef CONFIG_X86_VSMP + #define ARCH_MIN_TASKALIGN (1 << INTERNODE_CACHE_SHIFT) +@@ -274,15 +280,20 @@ struct thread_struct { + unsigned io_bitmap_max; + /* cached TLS descriptors. */ + u64 tls_array[GDT_ENTRY_TLS_ENTRIES]; ++#ifdef CONFIG_XEN ++ unsigned int iopl; ++#endif + } __attribute__((aligned(16))); + + #define INIT_THREAD { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ + } + ++#ifndef CONFIG_X86_NO_TSS + #define INIT_TSS { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ + } ++#endif + + #define INIT_MMAP \ + { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } +@@ -299,6 +310,12 @@ struct thread_struct { + set_fs(USER_DS); \ + } while(0) + ++#ifdef CONFIG_XEN ++#define get_debugreg(var, register) \ ++ var = HYPERVISOR_get_debugreg(register) ++#define set_debugreg(value, register) \ ++ HYPERVISOR_set_debugreg(register, value) ++#else + #define get_debugreg(var, register) \ + __asm__("movq %%db" #register ", %0" \ + :"=r" (var)) +@@ -306,6 +323,7 @@ struct thread_struct { + __asm__("movq %0,%%db" #register \ + : /* no output */ \ + :"r" (value)) ++#endif + + struct task_struct; + struct mm_struct; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/smp.h +--- a/include/asm-x86_64/smp.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/smp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -53,7 +53,11 @@ extern u8 cpu_llc_id[NR_CPUS]; + + static inline int num_booting_cpus(void) + { ++#ifdef CONFIG_XEN ++ return cpus_weight(cpu_possible_map); ++#else + return cpus_weight(cpu_callout_map); ++#endif + } + + #define raw_smp_processor_id() read_pda(cpunumber) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/system.h +--- a/include/asm-x86_64/system.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/system.h Wed Aug 08 16:25:28 2007 -0300 +@@ -4,6 +4,12 @@ + #include <linux/kernel.h> + #include <asm/segment.h> + #include <asm/alternative.h> ++ ++#ifdef CONFIG_XEN ++#include <asm/synch_bitops.h> ++#include <asm/hypervisor.h> ++#include <xen/interface/arch-x86_64.h> ++#endif + + #ifdef __KERNEL__ + +@@ -68,7 +74,11 @@ extern void load_gs_index(unsigned); + /* + * Clear and set 'TS' bit respectively + */ ++#ifdef CONFIG_XEN ++#define clts() (HYPERVISOR_fpu_taskswitch(0)) ++#else + #define clts() __asm__ __volatile__ ("clts") ++#endif + + static inline unsigned long read_cr0(void) + { +@@ -86,7 +96,11 @@ static inline unsigned long read_cr3(voi + { + unsigned long cr3; + asm("movq %%cr3,%0" : "=r" (cr3)); ++#ifdef CONFIG_XEN ++ return machine_to_phys(cr3); ++#else + return cr3; ++#endif + } + + static inline unsigned long read_cr4(void) +@@ -101,7 +115,11 @@ static inline void write_cr4(unsigned lo + asm volatile("movq %0,%%cr4" :: "r" (val)); + } + ++#ifdef CONFIG_XEN ++#define stts() (HYPERVISOR_fpu_taskswitch(1)) ++#else + #define stts() write_cr0(8 | read_cr0()) ++#endif + + #define wbinvd() \ + __asm__ __volatile__ ("wbinvd": : :"memory"); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/tlbflush.h +--- a/include/asm-x86_64/tlbflush.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/tlbflush.h Wed Aug 08 16:25:28 2007 -0300 +@@ -16,10 +16,14 @@ static inline void set_cr3(unsigned long + asm volatile("mov %0,%%cr3" :: "r" (cr3) : "memory"); + } + ++#ifdef CONFIG_XEN ++#define __flush_tlb() xen_tlb_flush() ++#else + static inline void __flush_tlb(void) + { + set_cr3(get_cr3()); + } ++#endif + + static inline unsigned long get_cr4(void) + { +@@ -33,15 +37,23 @@ static inline void set_cr4(unsigned long + asm volatile("mov %0,%%cr4" :: "r" (cr4) : "memory"); + } + ++#ifdef CONFIG_XEN ++#define __flush_tlb_all() xen_tlb_flush() ++#else + static inline void __flush_tlb_all(void) + { + unsigned long cr4 = get_cr4(); + set_cr4(cr4 & ~X86_CR4_PGE); /* clear PGE */ + set_cr4(cr4); /* write old PGE again and flush TLBs */ + } ++#endif + ++#ifdef CONFIG_XEN ++#define __flush_tlb_one(addr) xen_invlpg((unsigned long)addr) ++#else + #define __flush_tlb_one(addr) \ + __asm__ __volatile__("invlpg (%0)" :: "r" (addr) : "memory") ++#endif + + + /* +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/vga.h +--- a/include/asm-x86_64/vga.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/vga.h Wed Aug 08 16:25:28 2007 -0300 +@@ -12,7 +12,11 @@ + * access the videoram directly without any black magic. + */ + ++#ifdef CONFIG_XEN ++#define VGA_MAP_MEM(x,s) (unsigned long)isa_bus_to_virt(x) ++#else + #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) ++#endif + + #define vga_readb(x) (*(x)) + #define vga_writeb(x,y) (*(y) = (x)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/asm-x86_64/xor.h +--- a/include/asm-x86_64/xor.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/asm-x86_64/xor.h Wed Aug 08 16:25:28 2007 -0300 +@@ -37,6 +37,37 @@ typedef struct { unsigned long a,b; } __ + + /* Doesn't use gcc to save the XMM registers, because there is no easy way to + tell it to do a clts before the register saving. */ ++ ++#ifdef CONFIG_XEN ++#define XMMS_SAVE do { \ ++ preempt_disable(); \ ++ if (!(current_thread_info()->status & TS_USEDFPU)) \ ++ clts(); \ ++ asm volatile ( \ ++ "movups %%xmm0,(%1) ;\n\t" \ ++ "movups %%xmm1,0x10(%1) ;\n\t" \ ++ "movups %%xmm2,0x20(%1) ;\n\t" \ ++ "movups %%xmm3,0x30(%1) ;\n\t" \ ++ : "=&r" (cr0) \ ++ : "r" (xmm_save) \ ++ : "memory"); \ ++} while(0) ++ ++#define XMMS_RESTORE do { \ ++ asm volatile ( \ ++ "sfence ;\n\t" \ ++ "movups (%1),%%xmm0 ;\n\t" \ ++ "movups 0x10(%1),%%xmm1 ;\n\t" \ ++ "movups 0x20(%1),%%xmm2 ;\n\t" \ ++ "movups 0x30(%1),%%xmm3 ;\n\t" \ ++ : \ ++ : "r" (cr0), "r" (xmm_save) \ ++ : "memory"); \ ++ if (!(current_thread_info()->status & TS_USEDFPU)) \ ++ stts(); \ ++ preempt_enable(); \ ++} while(0) ++#else + #define XMMS_SAVE do { \ + preempt_disable(); \ + asm volatile ( \ +@@ -64,6 +95,7 @@ typedef struct { unsigned long a,b; } __ + : "memory"); \ + preempt_enable(); \ + } while(0) ++#endif /* CONFIG_XEN */ + + #define OFFS(x) "16*("#x")" + #define PF_OFFS(x) "256+16*("#x")" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/crash_dump.h +--- a/include/linux/crash_dump.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/crash_dump.h Wed Aug 08 16:25:28 2007 -0300 +@@ -14,5 +14,13 @@ extern const struct file_operations proc + extern const struct file_operations proc_vmcore_operations; + extern struct proc_dir_entry *proc_vmcore; + ++/* Architecture code defines this if there are other possible ELF ++ * machine types, e.g. on bi-arch capable hardware. */ ++#ifndef vmcore_elf_check_arch_cross ++#define vmcore_elf_check_arch_cross(x) 0 ++#endif ++ ++#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) ++ + #endif /* CONFIG_CRASH_DUMP */ + #endif /* LINUX_CRASHDUMP_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/elfnote.h +--- a/include/linux/elfnote.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/elfnote.h Wed Aug 08 16:25:28 2007 -0300 +@@ -38,13 +38,13 @@ + * e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two") + * ELFNOTE(XYZCo, 12, .long, 0xdeadbeef) + */ +-#define ELFNOTE(name, type, desctype, descdata) \ ++#define ELFNOTE(name, type, desctype, descdata...) \ + .pushsection .note.name ; \ + .align 4 ; \ + .long 2f - 1f /* namesz */ ; \ + .long 4f - 3f /* descsz */ ; \ + .long type ; \ +-1:.asciz "name" ; \ ++1:.asciz #name ; \ + 2:.align 4 ; \ + 3:desctype descdata ; \ + 4:.align 4 ; \ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/gfp.h +--- a/include/linux/gfp.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/gfp.h Wed Aug 08 16:25:28 2007 -0300 +@@ -114,7 +114,11 @@ static inline enum zone_type gfp_zone(gf + */ + + #ifndef HAVE_ARCH_FREE_PAGE +-static inline void arch_free_page(struct page *page, int order) { } ++/* ++ * If arch_free_page returns non-zero then the generic free_page code can ++ * immediately bail: the arch-specific function has done all the work. ++ */ ++static inline int arch_free_page(struct page *page, int order) { return 0; } + #endif + #ifndef HAVE_ARCH_ALLOC_PAGE + static inline void arch_alloc_page(struct page *page, int order) { } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/highmem.h +--- a/include/linux/highmem.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/highmem.h Wed Aug 08 16:25:28 2007 -0300 +@@ -26,10 +26,16 @@ static inline void flush_kernel_dcache_p + /* declarations for linux/mm/highmem.c */ + unsigned int nr_free_highpages(void); + extern unsigned long totalhigh_pages; ++#ifdef CONFIG_XEN ++void kmap_flush_unused(void); ++#endif + + #else /* CONFIG_HIGHMEM */ + + static inline unsigned int nr_free_highpages(void) { return 0; } ++#ifdef CONFIG_XEN ++static inline void kmap_flush_unused(void) { } ++#endif + + #define totalhigh_pages 0 + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/interrupt.h +--- a/include/linux/interrupt.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/interrupt.h Wed Aug 08 16:25:28 2007 -0300 +@@ -184,6 +184,12 @@ static inline int disable_irq_wake(unsig + + #endif /* CONFIG_GENERIC_HARDIRQS */ + ++#ifdef CONFIG_HAVE_IRQ_IGNORE_UNHANDLED ++int irq_ignore_unhandled(unsigned int irq); ++#else ++#define irq_ignore_unhandled(irq) 0 ++#endif ++ + #ifndef __ARCH_SET_SOFTIRQ_PENDING + #define set_softirq_pending(x) (local_softirq_pending() = (x)) + #define or_softirq_pending(x) (local_softirq_pending() |= (x)) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/kexec.h +--- a/include/linux/kexec.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/kexec.h Wed Aug 08 16:25:28 2007 -0300 +@@ -29,6 +29,13 @@ + + #ifndef KEXEC_ARCH + #error KEXEC_ARCH not defined ++#endif ++ ++#ifndef KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) page_to_pfn(page) ++#define kexec_pfn_to_page(pfn) pfn_to_page(pfn) ++#define kexec_virt_to_phys(addr) virt_to_phys(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(addr) + #endif + + /* +@@ -91,6 +98,12 @@ extern NORET_TYPE void machine_kexec(str + extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; + extern int machine_kexec_prepare(struct kimage *image); + extern void machine_kexec_cleanup(struct kimage *image); ++#ifdef CONFIG_XEN ++extern int xen_machine_kexec_load(struct kimage *image); ++extern void xen_machine_kexec_unload(struct kimage *image); ++extern void xen_machine_kexec_setup_resources(void); ++extern void xen_machine_kexec_register_resources(struct resource *res); ++#endif + extern asmlinkage long sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments, +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/mm.h +--- a/include/linux/mm.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/mm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -169,6 +169,9 @@ extern unsigned int kobjsize(const void + #define VM_MAPPED_COPY 0x01000000 /* T if mapped copy of data (nommu mmap) */ + #define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */ + #define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */ ++#ifdef CONFIG_XEN ++#define VM_FOREIGN 0x08000000 /* Has pages belonging to another VM */ ++#endif + + #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ + #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS +@@ -208,6 +211,12 @@ struct vm_operations_struct { + /* notification that a previously read-only page is about to become + * writable, if an error is returned it will cause a SIGBUS */ + int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page); ++ /* Area-specific function for clearing the PTE at @ptep. Returns the ++ * original value of @ptep. */ ++#ifdef CONFIG_XEN ++ pte_t (*zap_pte)(struct vm_area_struct *vma, ++ unsigned long addr, pte_t *ptep, int is_fullmm); ++#endif + #ifdef CONFIG_NUMA + int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new); + struct mempolicy *(*get_policy)(struct vm_area_struct *vma, +@@ -1129,6 +1138,13 @@ struct page *follow_page(struct vm_area_ + #define FOLL_GET 0x04 /* do get_page on page */ + #define FOLL_ANON 0x08 /* give ZERO_PAGE if no pgtable */ + ++#ifdef CONFIG_XEN ++typedef int (*pte_fn_t)(pte_t *pte, struct page *pmd_page, unsigned long addr, ++ void *data); ++extern int apply_to_page_range(struct mm_struct *mm, unsigned long address, ++ unsigned long size, pte_fn_t fn, void *data); ++#endif ++ + #ifdef CONFIG_PROC_FS + void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long); + #else +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/oprofile.h +--- a/include/linux/oprofile.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/oprofile.h Wed Aug 08 16:25:28 2007 -0300 +@@ -16,6 +16,10 @@ + #include <linux/types.h> + #include <linux/spinlock.h> + #include <asm/atomic.h> ++ ++#ifdef CONFIG_XEN ++#include <xen/interface/xenoprof.h> ++#endif + + struct super_block; + struct dentry; +@@ -27,6 +31,11 @@ struct oprofile_operations { + /* create any necessary configuration files in the oprofile fs. + * Optional. */ + int (*create_files)(struct super_block * sb, struct dentry * root); ++ /* setup active domains with Xen */ ++ int (*set_active)(int *active_domains, unsigned int adomains); ++ /* setup passive domains with Xen */ ++ int (*set_passive)(int *passive_domains, unsigned int pdomains); ++ + /* Do any necessary interrupt setup. Optional. */ + int (*setup)(void); + /* Do any necessary interrupt shutdown. Optional. */ +@@ -78,6 +87,8 @@ void oprofile_add_pc(unsigned long pc, i + /* add a backtrace entry, to be called from the ->backtrace callback */ + void oprofile_add_trace(unsigned long eip); + ++/* add a domain switch entry */ ++int oprofile_add_domain_switch(int32_t domain_id); + + /** + * Create a file of the given name as a child of the given root, with +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/page-flags.h +--- a/include/linux/page-flags.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/page-flags.h Wed Aug 08 16:25:28 2007 -0300 +@@ -102,6 +102,8 @@ + */ + #define PG_uncached 31 /* Page has been mapped as uncached */ + #endif ++ ++#define PG_foreign 20 /* Page is owned by foreign allocator. */ + + /* + * Manipulation of page state flags +@@ -251,6 +253,18 @@ static inline void SetPageUptodate(struc + #define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags) + #define ClearPageUncached(page) clear_bit(PG_uncached, &(page)->flags) + ++#define PageForeign(page) test_bit(PG_foreign, &(page)->flags) ++#define SetPageForeign(page, dtor) do { \ ++ set_bit(PG_foreign, &(page)->flags); \ ++ (page)->index = (long)(dtor); \ ++} while (0) ++#define ClearPageForeign(page) do { \ ++ clear_bit(PG_foreign, &(page)->flags); \ ++ (page)->index = 0; \ ++} while (0) ++#define PageForeignDestructor(page) \ ++ ( (void (*) (struct page *)) (page)->index )(page) ++ + struct page; /* forward declaration */ + + extern void cancel_dirty_page(struct page *page, unsigned int account_size); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/sched.h +--- a/include/linux/sched.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/sched.h Wed Aug 08 16:25:28 2007 -0300 +@@ -223,10 +223,15 @@ extern void scheduler_tick(void); + extern void scheduler_tick(void); + + #ifdef CONFIG_DETECT_SOFTLOCKUP ++extern unsigned long softlockup_get_next_event(void); + extern void softlockup_tick(void); + extern void spawn_softlockup_task(void); + extern void touch_softlockup_watchdog(void); + #else ++static inline unsigned long softlockup_get_next_event(void) ++{ ++ return MAX_JIFFY_OFFSET; ++} + static inline void softlockup_tick(void) + { + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/linux/skbuff.h +--- a/include/linux/skbuff.h Wed Jul 18 12:23:24 2007 -0300 ++++ b/include/linux/skbuff.h Wed Aug 08 16:25:28 2007 -0300 +@@ -202,6 +202,8 @@ enum { + * @local_df: allow local fragmentation + * @cloned: Head may be cloned (check refcnt to be sure) + * @nohdr: Payload reference only, must not modify header ++ * @proto_data_valid: Protocol data validated since arriving at localhost ++ * @proto_csum_blank: Protocol csum must be added before leaving localhost + * @pkt_type: Packet class + * @fclone: skbuff clone status + * @ip_summed: Driver fed us an IP checksum +@@ -285,7 +287,13 @@ struct sk_buff { + nfctinfo:3; + __u8 pkt_type:3, + fclone:2, ++#ifndef CONFIG_XEN + ipvs_property:1; ++#else ++ ipvs_property:1, ++ proto_data_valid:1, ++ proto_csum_blank:1; ++#endif + __be16 protocol; + + void (*destructor)(struct sk_buff *skb); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/balloon.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/balloon.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,57 @@ ++/****************************************************************************** ++ * balloon.h ++ * ++ * Xen balloon driver - enables returning/claiming memory to/from Xen. ++ * ++ * Copyright (c) 2003, B Dragovic ++ * Copyright (c) 2003-2004, M Williamson, K Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __ASM_BALLOON_H__ ++#define __ASM_BALLOON_H__ ++ ++/* ++ * Inform the balloon driver that it should allow some slop for device-driver ++ * memory activities. ++ */ ++void balloon_update_driver_allowance(long delta); ++ ++/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */ ++struct page **alloc_empty_pages_and_pagevec(int nr_pages); ++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages); ++ ++void balloon_release_driver_page(struct page *page); ++ ++/* ++ * Prevent the balloon driver from changing the memory reservation during ++ * a driver critical region. ++ */ ++extern spinlock_t balloon_lock; ++#define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags) ++#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags) ++ ++#endif /* __ASM_BALLOON_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/blkif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/blkif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,97 @@ ++#ifndef __XEN_BLKIF_H__ ++#define __XEN_BLKIF_H__ ++ ++#include <xen/interface/io/ring.h> ++#include <xen/interface/io/blkif.h> ++#include <xen/interface/io/protocols.h> ++ ++/* Not a real protocol. Used to generate ring structs which contain ++ * the elements common to all protocols only. This way we get a ++ * compiler-checkable way to use common struct elements, so we can ++ * avoid using switch(protocol) in a number of places. */ ++struct blkif_common_request { ++ char dummy; ++}; ++struct blkif_common_response { ++ char dummy; ++}; ++ ++/* i386 protocol version */ ++#pragma pack(push, 4) ++struct blkif_x86_32_request { ++ uint8_t operation; /* BLKIF_OP_??? */ ++ uint8_t nr_segments; /* number of segments */ ++ blkif_vdev_t handle; /* only for read/write requests */ ++ uint64_t id; /* private guest value, echoed in resp */ ++ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ ++ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++}; ++struct blkif_x86_32_response { ++ uint64_t id; /* copied from request */ ++ uint8_t operation; /* copied from request */ ++ int16_t status; /* BLKIF_RSP_??? */ ++}; ++typedef struct blkif_x86_32_request blkif_x86_32_request_t; ++typedef struct blkif_x86_32_response blkif_x86_32_response_t; ++#pragma pack(pop) ++ ++/* x86_64 protocol version */ ++struct blkif_x86_64_request { ++ uint8_t operation; /* BLKIF_OP_??? */ ++ uint8_t nr_segments; /* number of segments */ ++ blkif_vdev_t handle; /* only for read/write requests */ ++ uint64_t __attribute__((__aligned__(8))) id; ++ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ ++ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++}; ++struct blkif_x86_64_response { ++ uint64_t __attribute__((__aligned__(8))) id; ++ uint8_t operation; /* copied from request */ ++ int16_t status; /* BLKIF_RSP_??? */ ++}; ++typedef struct blkif_x86_64_request blkif_x86_64_request_t; ++typedef struct blkif_x86_64_response blkif_x86_64_response_t; ++ ++DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response); ++DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response); ++DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response); ++ ++union blkif_back_rings { ++ blkif_back_ring_t native; ++ blkif_common_back_ring_t common; ++ blkif_x86_32_back_ring_t x86_32; ++ blkif_x86_64_back_ring_t x86_64; ++}; ++typedef union blkif_back_rings blkif_back_rings_t; ++ ++enum blkif_protocol { ++ BLKIF_PROTOCOL_NATIVE = 1, ++ BLKIF_PROTOCOL_X86_32 = 2, ++ BLKIF_PROTOCOL_X86_64 = 3, ++}; ++ ++static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src) ++{ ++ int i; ++ dst->operation = src->operation; ++ dst->nr_segments = src->nr_segments; ++ dst->handle = src->handle; ++ dst->id = src->id; ++ dst->sector_number = src->sector_number; ++ for (i = 0; i < src->nr_segments; i++) ++ dst->seg[i] = src->seg[i]; ++} ++ ++static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src) ++{ ++ int i; ++ dst->operation = src->operation; ++ dst->nr_segments = src->nr_segments; ++ dst->handle = src->handle; ++ dst->id = src->id; ++ dst->sector_number = src->sector_number; ++ for (i = 0; i < src->nr_segments; i++) ++ dst->seg[i] = src->seg[i]; ++} ++ ++#endif /* __XEN_BLKIF_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/cpu_hotplug.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/cpu_hotplug.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,44 @@ ++#ifndef __XEN_CPU_HOTPLUG_H__ ++#define __XEN_CPU_HOTPLUG_H__ ++ ++#include <linux/kernel.h> ++#include <linux/cpumask.h> ++ ++#if defined(CONFIG_X86) && defined(CONFIG_SMP) ++extern cpumask_t cpu_initialized_map; ++#define cpu_set_initialized(cpu) cpu_set(cpu, cpu_initialized_map) ++#else ++#define cpu_set_initialized(cpu) ((void)0) ++#endif ++ ++#if defined(CONFIG_HOTPLUG_CPU) ++ ++int cpu_up_check(unsigned int cpu); ++void init_xenbus_allowed_cpumask(void); ++int smp_suspend(void); ++void smp_resume(void); ++ ++void cpu_bringup(void); ++ ++#else /* !defined(CONFIG_HOTPLUG_CPU) */ ++ ++#define cpu_up_check(cpu) (0) ++#define init_xenbus_allowed_cpumask() ((void)0) ++ ++static inline int smp_suspend(void) ++{ ++ if (num_online_cpus() > 1) { ++ printk(KERN_WARNING "Can't suspend SMP guests " ++ "without CONFIG_HOTPLUG_CPU\n"); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static inline void smp_resume(void) ++{ ++} ++ ++#endif /* !defined(CONFIG_HOTPLUG_CPU) */ ++ ++#endif /* __XEN_CPU_HOTPLUG_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/driver_util.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/driver_util.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,14 @@ ++ ++#ifndef __ASM_XEN_DRIVER_UTIL_H__ ++#define __ASM_XEN_DRIVER_UTIL_H__ ++ ++#include <linux/vmalloc.h> ++#include <linux/device.h> ++ ++/* Allocate/destroy a 'vmalloc' VM area. */ ++extern struct vm_struct *alloc_vm_area(unsigned long size); ++extern void free_vm_area(struct vm_struct *area); ++ ++extern struct class *get_xen_class(void); ++ ++#endif /* __ASM_XEN_DRIVER_UTIL_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/evtchn.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/evtchn.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,126 @@ ++/****************************************************************************** ++ * evtchn.h ++ * ++ * Communication via Xen event channels. ++ * Also definitions for the device that demuxes notifications to userspace. ++ * ++ * Copyright (c) 2004-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __ASM_EVTCHN_H__ ++#define __ASM_EVTCHN_H__ ++ ++#include <linux/interrupt.h> ++#include <asm/hypervisor.h> ++#include <asm/ptrace.h> ++#include <asm/synch_bitops.h> ++#include <xen/interface/event_channel.h> ++#include <linux/smp.h> ++ ++/* ++ * LOW-LEVEL DEFINITIONS ++ */ ++ ++/* ++ * Dynamically bind an event source to an IRQ-like callback handler. ++ * On some platforms this may not be implemented via the Linux IRQ subsystem. ++ * The IRQ argument passed to the callback handler is the same as returned ++ * from the bind call. It may not correspond to a Linux IRQ number. ++ * Returns IRQ or negative errno. ++ */ ++int bind_caller_port_to_irqhandler( ++ unsigned int caller_port, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id); ++int bind_listening_port_to_irqhandler( ++ unsigned int remote_domain, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id); ++int bind_interdomain_evtchn_to_irqhandler( ++ unsigned int remote_domain, ++ unsigned int remote_port, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id); ++int bind_virq_to_irqhandler( ++ unsigned int virq, ++ unsigned int cpu, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id); ++int bind_ipi_to_irqhandler( ++ unsigned int ipi, ++ unsigned int cpu, ++ irq_handler_t handler, ++ unsigned long irqflags, ++ const char *devname, ++ void *dev_id); ++ ++/* ++ * Common unbind function for all event sources. Takes IRQ to unbind from. ++ * Automatically closes the underlying event channel (except for bindings ++ * made with bind_caller_port_to_irqhandler()). ++ */ ++void unbind_from_irqhandler(unsigned int irq, void *dev_id); ++ ++void irq_resume(void); ++ ++/* Entry point for notifications into Linux subsystems. */ ++asmlinkage void evtchn_do_upcall(struct pt_regs *regs); ++ ++/* Entry point for notifications into the userland character device. */ ++void evtchn_device_upcall(int port); ++ ++void mask_evtchn(int port); ++void unmask_evtchn(int port); ++ ++static inline void clear_evtchn(int port) ++{ ++ shared_info_t *s = HYPERVISOR_shared_info; ++ synch_clear_bit(port, s->evtchn_pending); ++} ++ ++static inline void notify_remote_via_evtchn(int port) ++{ ++ struct evtchn_send send = { .port = port }; ++ (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); ++} ++ ++/* ++ * Use these to access the event channel underlying the IRQ handle returned ++ * by bind_*_to_irqhandler(). ++ */ ++void notify_remote_via_irq(int irq); ++int irq_to_evtchn_port(int irq); ++ ++#endif /* __ASM_EVTCHN_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/features.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/features.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,20 @@ ++/****************************************************************************** ++ * features.h ++ * ++ * Query the features reported by Xen. ++ * ++ * Copyright (c) 2006, Ian Campbell ++ */ ++ ++#ifndef __ASM_XEN_FEATURES_H__ ++#define __ASM_XEN_FEATURES_H__ ++ ++#include <xen/interface/version.h> ++ ++extern void setup_xen_features(void); ++ ++extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32]; ++ ++#define xen_feature(flag) (xen_features[flag]) ++ ++#endif /* __ASM_XEN_FEATURES_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/gnttab.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/gnttab.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,138 @@ ++/****************************************************************************** ++ * gnttab.h ++ * ++ * Two sets of functionality: ++ * 1. Granting foreign access to our memory reservation. ++ * 2. Accessing others' memory reservations via grant references. ++ * (i.e., mechanisms for both sender and recipient of grant references) ++ * ++ * Copyright (c) 2004-2005, K A Fraser ++ * Copyright (c) 2005, Christopher Clark ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __ASM_GNTTAB_H__ ++#define __ASM_GNTTAB_H__ ++ ++#include <asm/hypervisor.h> ++#include <asm/maddr.h> /* maddr_t */ ++#include <xen/interface/grant_table.h> ++#include <xen/features.h> ++ ++struct gnttab_free_callback { ++ struct gnttab_free_callback *next; ++ void (*fn)(void *); ++ void *arg; ++ u16 count; ++}; ++ ++int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, ++ int readonly); ++ ++/* ++ * End access through the given grant reference, iff the grant entry is no ++ * longer in use. Return 1 if the grant entry was freed, 0 if it is still in ++ * use. ++ */ ++int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly); ++ ++/* ++ * Eventually end access through the given grant reference, and once that ++ * access has been ended, free the given page too. Access will be ended ++ * immediately iff the grant entry is not in use, otherwise it will happen ++ * some time later. page may be 0, in which case no freeing will occur. ++ */ ++void gnttab_end_foreign_access(grant_ref_t ref, int readonly, ++ unsigned long page); ++ ++int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn); ++ ++unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref); ++unsigned long gnttab_end_foreign_transfer(grant_ref_t ref); ++ ++int gnttab_query_foreign_access(grant_ref_t ref); ++ ++/* ++ * operations on reserved batches of grant references ++ */ ++int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head); ++ ++void gnttab_free_grant_reference(grant_ref_t ref); ++ ++void gnttab_free_grant_references(grant_ref_t head); ++ ++int gnttab_empty_grant_references(const grant_ref_t *pprivate_head); ++ ++int gnttab_claim_grant_reference(grant_ref_t *pprivate_head); ++ ++void gnttab_release_grant_reference(grant_ref_t *private_head, ++ grant_ref_t release); ++ ++void gnttab_request_free_callback(struct gnttab_free_callback *callback, ++ void (*fn)(void *), void *arg, u16 count); ++void gnttab_cancel_free_callback(struct gnttab_free_callback *callback); ++ ++void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, ++ unsigned long frame, int readonly); ++ ++void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid, ++ unsigned long pfn); ++ ++int gnttab_suspend(void); ++int gnttab_resume(void); ++ ++static inline void ++gnttab_set_map_op(struct gnttab_map_grant_ref *map, maddr_t addr, ++ uint32_t flags, grant_ref_t ref, domid_t domid) ++{ ++ if (flags & GNTMAP_contains_pte) ++ map->host_addr = addr; ++ else if (xen_feature(XENFEAT_auto_translated_physmap)) ++ map->host_addr = __pa(addr); ++ else ++ map->host_addr = addr; ++ ++ map->flags = flags; ++ map->ref = ref; ++ map->dom = domid; ++} ++ ++static inline void ++gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, maddr_t addr, ++ uint32_t flags, grant_handle_t handle) ++{ ++ if (flags & GNTMAP_contains_pte) ++ unmap->host_addr = addr; ++ else if (xen_feature(XENFEAT_auto_translated_physmap)) ++ unmap->host_addr = __pa(addr); ++ else ++ unmap->host_addr = addr; ++ ++ unmap->handle = handle; ++ unmap->dev_bus_addr = 0; ++} ++ ++#endif /* __ASM_GNTTAB_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/hvm.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/hvm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,23 @@ ++/* Simple wrappers around HVM functions */ ++#ifndef XEN_HVM_H__ ++#define XEN_HVM_H__ ++ ++#include <xen/interface/hvm/params.h> ++ ++static inline unsigned long hvm_get_parameter(int idx) ++{ ++ struct xen_hvm_param xhv; ++ int r; ++ ++ xhv.domid = DOMID_SELF; ++ xhv.index = idx; ++ r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); ++ if (r < 0) { ++ printk(KERN_ERR "cannot get hvm parameter %d: %d.\n", ++ idx, r); ++ return 0; ++ } ++ return xhv.value; ++} ++ ++#endif /* XEN_HVM_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/hypercall.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/hypercall.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,24 @@ ++#ifndef __XEN_HYPERCALL_H__ ++#define __XEN_HYPERCALL_H__ ++ ++#include <asm/hypercall.h> ++ ++static inline int ++HYPERVISOR_multicall_check( ++ multicall_entry_t *call_list, int nr_calls, ++ const unsigned long *rc_list) ++{ ++ int rc = HYPERVISOR_multicall(call_list, nr_calls); ++ ++ if (unlikely(rc < 0)) ++ return rc; ++ BUG_ON(rc); ++ ++ for ( ; nr_calls > 0; --nr_calls, ++call_list) ++ if (unlikely(call_list->result != (rc_list ? *rc_list++ : 0))) ++ return nr_calls; ++ ++ return 0; ++} ++ ++#endif /* __XEN_HYPERCALL_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/hypervisor_sysfs.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/hypervisor_sysfs.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,32 @@ ++/* ++ * copyright (c) 2006 IBM Corporation ++ * Authored by: Mike D. Day <ncmike@us.ibm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef _HYP_SYSFS_H_ ++#define _HYP_SYSFS_H_ ++ ++#include <linux/kobject.h> ++#include <linux/sysfs.h> ++ ++#define HYPERVISOR_ATTR_RO(_name) \ ++static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name) ++ ++#define HYPERVISOR_ATTR_RW(_name) \ ++static struct hyp_sysfs_attr _name##_attr = \ ++ __ATTR(_name, 0644, _name##_show, _name##_store) ++ ++extern struct subsystem hypervisor_subsys; ++ ++struct hyp_sysfs_attr { ++ struct attribute attr; ++ ssize_t (*show)(struct hyp_sysfs_attr *, char *); ++ ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t); ++ void *hyp_attr_data; ++}; ++ ++#endif /* _HYP_SYSFS_H_ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/COPYING +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/COPYING Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,38 @@ ++XEN NOTICE ++========== ++ ++This copyright applies to all files within this subdirectory and its ++subdirectories: ++ include/public/*.h ++ include/public/hvm/*.h ++ include/public/io/*.h ++ ++The intention is that these files can be freely copied into the source ++tree of an operating system when porting that OS to run on Xen. Doing ++so does *not* cause the OS to become subject to the terms of the GPL. ++ ++All other files in the Xen source distribution are covered by version ++2 of the GNU General Public License except where explicitly stated ++otherwise within individual source files. ++ ++ -- Keir Fraser (on behalf of the Xen team) ++ ++===================================================================== ++ ++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. +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/acm.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/acm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,228 @@ ++/* ++ * acm.h: Xen access control module interface defintions ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Reiner Sailer <sailer@watson.ibm.com> ++ * Copyright (c) 2005, International Business Machines Corporation. ++ */ ++ ++#ifndef _XEN_PUBLIC_ACM_H ++#define _XEN_PUBLIC_ACM_H ++ ++#include "xen.h" ++ ++/* if ACM_DEBUG defined, all hooks should ++ * print a short trace message (comment it out ++ * when not in testing mode ) ++ */ ++/* #define ACM_DEBUG */ ++ ++#ifdef ACM_DEBUG ++# define printkd(fmt, args...) printk(fmt,## args) ++#else ++# define printkd(fmt, args...) ++#endif ++ ++/* default ssid reference value if not supplied */ ++#define ACM_DEFAULT_SSID 0x0 ++#define ACM_DEFAULT_LOCAL_SSID 0x0 ++ ++/* Internal ACM ERROR types */ ++#define ACM_OK 0 ++#define ACM_UNDEF -1 ++#define ACM_INIT_SSID_ERROR -2 ++#define ACM_INIT_SOID_ERROR -3 ++#define ACM_ERROR -4 ++ ++/* External ACCESS DECISIONS */ ++#define ACM_ACCESS_PERMITTED 0 ++#define ACM_ACCESS_DENIED -111 ++#define ACM_NULL_POINTER_ERROR -200 ++ ++/* ++ Error codes reported in when trying to test for a new policy ++ These error codes are reported in an array of tuples where ++ each error code is followed by a parameter describing the error ++ more closely, such as a domain id. ++*/ ++#define ACM_EVTCHN_SHARING_VIOLATION 0x100 ++#define ACM_GNTTAB_SHARING_VIOLATION 0x101 ++#define ACM_DOMAIN_LOOKUP 0x102 ++#define ACM_CHWALL_CONFLICT 0x103 ++#define ACM_SSIDREF_IN_USE 0x104 ++ ++ ++/* primary policy in lower 4 bits */ ++#define ACM_NULL_POLICY 0 ++#define ACM_CHINESE_WALL_POLICY 1 ++#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2 ++#define ACM_POLICY_UNDEFINED 15 ++ ++/* combinations have secondary policy component in higher 4bit */ ++#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY \ ++ ((ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY << 4) | ACM_CHINESE_WALL_POLICY) ++ ++/* policy: */ ++#define ACM_POLICY_NAME(X) \ ++ ((X) == (ACM_NULL_POLICY)) ? "NULL" : \ ++ ((X) == (ACM_CHINESE_WALL_POLICY)) ? "CHINESE WALL" : \ ++ ((X) == (ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)) ? "SIMPLE TYPE ENFORCEMENT" : \ ++ ((X) == (ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY)) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT" : \ ++ "UNDEFINED" ++ ++/* the following policy versions must be increased ++ * whenever the interpretation of the related ++ * policy's data structure changes ++ */ ++#define ACM_POLICY_VERSION 3 ++#define ACM_CHWALL_VERSION 1 ++#define ACM_STE_VERSION 1 ++ ++/* defines a ssid reference used by xen */ ++typedef uint32_t ssidref_t; ++ ++/* hooks that are known to domains */ ++#define ACMHOOK_none 0 ++#define ACMHOOK_sharing 1 ++ ++/* -------security policy relevant type definitions-------- */ ++ ++/* type identifier; compares to "equal" or "not equal" */ ++typedef uint16_t domaintype_t; ++ ++/* CHINESE WALL POLICY DATA STRUCTURES ++ * ++ * current accumulated conflict type set: ++ * When a domain is started and has a type that is in ++ * a conflict set, the conflicting types are incremented in ++ * the aggregate set. When a domain is destroyed, the ++ * conflicting types to its type are decremented. ++ * If a domain has multiple types, this procedure works over ++ * all those types. ++ * ++ * conflict_aggregate_set[i] holds the number of ++ * running domains that have a conflict with type i. ++ * ++ * running_types[i] holds the number of running domains ++ * that include type i in their ssidref-referenced type set ++ * ++ * conflict_sets[i][j] is "0" if type j has no conflict ++ * with type i and is "1" otherwise. ++ */ ++/* high-16 = version, low-16 = check magic */ ++#define ACM_MAGIC 0x0001debc ++ ++/* each offset in bytes from start of the struct they ++ * are part of */ ++ ++/* V3 of the policy buffer aded a version structure */ ++struct acm_policy_version ++{ ++ uint32_t major; ++ uint32_t minor; ++}; ++ ++ ++/* each buffer consists of all policy information for ++ * the respective policy given in the policy code ++ * ++ * acm_policy_buffer, acm_chwall_policy_buffer, ++ * and acm_ste_policy_buffer need to stay 32-bit aligned ++ * because we create binary policies also with external ++ * tools that assume packed representations (e.g. the java tool) ++ */ ++struct acm_policy_buffer { ++ uint32_t policy_version; /* ACM_POLICY_VERSION */ ++ uint32_t magic; ++ uint32_t len; ++ uint32_t policy_reference_offset; ++ uint32_t primary_policy_code; ++ uint32_t primary_buffer_offset; ++ uint32_t secondary_policy_code; ++ uint32_t secondary_buffer_offset; ++ struct acm_policy_version xml_pol_version; /* add in V3 */ ++}; ++ ++ ++struct acm_policy_reference_buffer { ++ uint32_t len; ++}; ++ ++struct acm_chwall_policy_buffer { ++ uint32_t policy_version; /* ACM_CHWALL_VERSION */ ++ uint32_t policy_code; ++ uint32_t chwall_max_types; ++ uint32_t chwall_max_ssidrefs; ++ uint32_t chwall_max_conflictsets; ++ uint32_t chwall_ssid_offset; ++ uint32_t chwall_conflict_sets_offset; ++ uint32_t chwall_running_types_offset; ++ uint32_t chwall_conflict_aggregate_offset; ++}; ++ ++struct acm_ste_policy_buffer { ++ uint32_t policy_version; /* ACM_STE_VERSION */ ++ uint32_t policy_code; ++ uint32_t ste_max_types; ++ uint32_t ste_max_ssidrefs; ++ uint32_t ste_ssid_offset; ++}; ++ ++struct acm_stats_buffer { ++ uint32_t magic; ++ uint32_t len; ++ uint32_t primary_policy_code; ++ uint32_t primary_stats_offset; ++ uint32_t secondary_policy_code; ++ uint32_t secondary_stats_offset; ++}; ++ ++struct acm_ste_stats_buffer { ++ uint32_t ec_eval_count; ++ uint32_t gt_eval_count; ++ uint32_t ec_denied_count; ++ uint32_t gt_denied_count; ++ uint32_t ec_cachehit_count; ++ uint32_t gt_cachehit_count; ++}; ++ ++struct acm_ssid_buffer { ++ uint32_t len; ++ ssidref_t ssidref; ++ uint32_t policy_reference_offset; ++ uint32_t primary_policy_code; ++ uint32_t primary_max_types; ++ uint32_t primary_types_offset; ++ uint32_t secondary_policy_code; ++ uint32_t secondary_max_types; ++ uint32_t secondary_types_offset; ++}; ++ ++#endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/acm_ops.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/acm_ops.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,166 @@ ++/* ++ * acm_ops.h: Xen access control module hypervisor commands ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Reiner Sailer <sailer@watson.ibm.com> ++ * Copyright (c) 2005,2006 International Business Machines Corporation. ++ */ ++ ++#ifndef __XEN_PUBLIC_ACM_OPS_H__ ++#define __XEN_PUBLIC_ACM_OPS_H__ ++ ++#include "xen.h" ++#include "acm.h" ++ ++/* ++ * Make sure you increment the interface version whenever you modify this file! ++ * This makes sure that old versions of acm tools will stop working in a ++ * well-defined way (rather than crashing the machine, for instance). ++ */ ++#define ACM_INTERFACE_VERSION 0xAAAA0009 ++ ++/************************************************************************/ ++ ++/* ++ * Prototype for this hypercall is: ++ * int acm_op(int cmd, void *args) ++ * @cmd == ACMOP_??? (access control module operation). ++ * @args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++ ++#define ACMOP_setpolicy 1 ++struct acm_setpolicy { ++ /* IN */ ++ uint32_t interface_version; ++ XEN_GUEST_HANDLE_64(void) pushcache; ++ uint32_t pushcache_size; ++}; ++ ++ ++#define ACMOP_getpolicy 2 ++struct acm_getpolicy { ++ /* IN */ ++ uint32_t interface_version; ++ XEN_GUEST_HANDLE_64(void) pullcache; ++ uint32_t pullcache_size; ++}; ++ ++ ++#define ACMOP_dumpstats 3 ++struct acm_dumpstats { ++ /* IN */ ++ uint32_t interface_version; ++ XEN_GUEST_HANDLE_64(void) pullcache; ++ uint32_t pullcache_size; ++}; ++ ++ ++#define ACMOP_getssid 4 ++#define ACM_GETBY_ssidref 1 ++#define ACM_GETBY_domainid 2 ++struct acm_getssid { ++ /* IN */ ++ uint32_t interface_version; ++ uint32_t get_ssid_by; /* ACM_GETBY_* */ ++ union { ++ domaintype_t domainid; ++ ssidref_t ssidref; ++ } id; ++ XEN_GUEST_HANDLE_64(void) ssidbuf; ++ uint32_t ssidbuf_size; ++}; ++ ++#define ACMOP_getdecision 5 ++struct acm_getdecision { ++ /* IN */ ++ uint32_t interface_version; ++ uint32_t get_decision_by1; /* ACM_GETBY_* */ ++ uint32_t get_decision_by2; /* ACM_GETBY_* */ ++ union { ++ domaintype_t domainid; ++ ssidref_t ssidref; ++ } id1; ++ union { ++ domaintype_t domainid; ++ ssidref_t ssidref; ++ } id2; ++ uint32_t hook; ++ /* OUT */ ++ uint32_t acm_decision; ++}; ++ ++ ++#define ACMOP_chgpolicy 6 ++struct acm_change_policy { ++ /* IN */ ++ uint32_t interface_version; ++ XEN_GUEST_HANDLE_64(void) policy_pushcache; ++ uint32_t policy_pushcache_size; ++ XEN_GUEST_HANDLE_64(void) del_array; ++ uint32_t delarray_size; ++ XEN_GUEST_HANDLE_64(void) chg_array; ++ uint32_t chgarray_size; ++ /* OUT */ ++ /* array with error code */ ++ XEN_GUEST_HANDLE_64(void) err_array; ++ uint32_t errarray_size; ++}; ++ ++#define ACMOP_relabeldoms 7 ++struct acm_relabel_doms { ++ /* IN */ ++ uint32_t interface_version; ++ XEN_GUEST_HANDLE_64(void) relabel_map; ++ uint32_t relabel_map_size; ++ /* OUT */ ++ XEN_GUEST_HANDLE_64(void) err_array; ++ uint32_t errarray_size; ++}; ++ ++/* future interface to Xen */ ++struct xen_acmctl { ++ uint32_t cmd; ++ uint32_t interface_version; ++ union { ++ struct acm_setpolicy setpolicy; ++ struct acm_getpolicy getpolicy; ++ struct acm_dumpstats dumpstats; ++ struct acm_getssid getssid; ++ struct acm_getdecision getdecision; ++ struct acm_change_policy change_policy; ++ struct acm_relabel_doms relabel_doms; ++ } u; ++}; ++ ++typedef struct xen_acmctl xen_acmctl_t; ++DEFINE_XEN_GUEST_HANDLE(xen_acmctl_t); ++ ++#endif /* __XEN_PUBLIC_ACM_OPS_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-ia64.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-ia64.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,508 @@ ++/****************************************************************************** ++ * arch-ia64/hypervisor-if.h ++ * ++ * Guest OS interface to IA64 Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ */ ++ ++#ifndef __HYPERVISOR_IF_IA64_H__ ++#define __HYPERVISOR_IF_IA64_H__ ++ ++/* Structural guest handles introduced in 0x00030201. */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030201 ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef struct { type *p; } __guest_handle_ ## name ++#else ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef type * __guest_handle_ ## name ++#endif ++ ++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) ++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name ++#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name) ++#define uint64_aligned_t uint64_t ++#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0) ++#ifdef __XEN_TOOLS__ ++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) ++#endif ++ ++#ifndef __ASSEMBLY__ ++/* Guest handles for primitive C types. */ ++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); ++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); ++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); ++__DEFINE_XEN_GUEST_HANDLE(u64, unsigned long); ++DEFINE_XEN_GUEST_HANDLE(char); ++DEFINE_XEN_GUEST_HANDLE(int); ++DEFINE_XEN_GUEST_HANDLE(long); ++DEFINE_XEN_GUEST_HANDLE(void); ++ ++typedef unsigned long xen_pfn_t; ++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); ++#define PRI_xen_pfn "lx" ++#endif ++ ++/* Arch specific VIRQs definition */ ++#define VIRQ_ITC VIRQ_ARCH_0 /* V. Virtual itc timer */ ++#define VIRQ_MCA_CMC VIRQ_ARCH_1 /* MCA cmc interrupt */ ++#define VIRQ_MCA_CPE VIRQ_ARCH_2 /* MCA cpe interrupt */ ++ ++/* Maximum number of virtual CPUs in multi-processor guests. */ ++/* WARNING: before changing this, check that shared_info fits on a page */ ++#define MAX_VIRT_CPUS 64 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef unsigned long xen_ulong_t; ++ ++#define INVALID_MFN (~0UL) ++ ++#define MEM_G (1UL << 30) ++#define MEM_M (1UL << 20) ++ ++#define MMIO_START (3 * MEM_G) ++#define MMIO_SIZE (512 * MEM_M) ++ ++#define VGA_IO_START 0xA0000UL ++#define VGA_IO_SIZE 0x20000 ++ ++#define LEGACY_IO_START (MMIO_START + MMIO_SIZE) ++#define LEGACY_IO_SIZE (64*MEM_M) ++ ++#define IO_PAGE_START (LEGACY_IO_START + LEGACY_IO_SIZE) ++#define IO_PAGE_SIZE PAGE_SIZE ++ ++#define STORE_PAGE_START (IO_PAGE_START + IO_PAGE_SIZE) ++#define STORE_PAGE_SIZE PAGE_SIZE ++ ++#define BUFFER_IO_PAGE_START (STORE_PAGE_START+STORE_PAGE_SIZE) ++#define BUFFER_IO_PAGE_SIZE PAGE_SIZE ++ ++#define BUFFER_PIO_PAGE_START (BUFFER_IO_PAGE_START+BUFFER_IO_PAGE_SIZE) ++#define BUFFER_PIO_PAGE_SIZE PAGE_SIZE ++ ++#define IO_SAPIC_START 0xfec00000UL ++#define IO_SAPIC_SIZE 0x100000 ++ ++#define PIB_START 0xfee00000UL ++#define PIB_SIZE 0x200000 ++ ++#define GFW_START (4*MEM_G -16*MEM_M) ++#define GFW_SIZE (16*MEM_M) ++ ++struct pt_fpreg { ++ union { ++ unsigned long bits[2]; ++ long double __dummy; /* force 16-byte alignment */ ++ } u; ++}; ++ ++struct cpu_user_regs { ++ /* The following registers are saved by SAVE_MIN: */ ++ unsigned long b6; /* scratch */ ++ unsigned long b7; /* scratch */ ++ ++ unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ ++ unsigned long ar_ssd; /* reserved for future use (scratch) */ ++ ++ unsigned long r8; /* scratch (return value register 0) */ ++ unsigned long r9; /* scratch (return value register 1) */ ++ unsigned long r10; /* scratch (return value register 2) */ ++ unsigned long r11; /* scratch (return value register 3) */ ++ ++ unsigned long cr_ipsr; /* interrupted task's psr */ ++ unsigned long cr_iip; /* interrupted task's instruction pointer */ ++ unsigned long cr_ifs; /* interrupted task's function state */ ++ ++ unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ ++ unsigned long ar_pfs; /* prev function state */ ++ unsigned long ar_rsc; /* RSE configuration */ ++ /* The following two are valid only if cr_ipsr.cpl > 0: */ ++ unsigned long ar_rnat; /* RSE NaT */ ++ unsigned long ar_bspstore; /* RSE bspstore */ ++ ++ unsigned long pr; /* 64 predicate registers (1 bit each) */ ++ unsigned long b0; /* return pointer (bp) */ ++ unsigned long loadrs; /* size of dirty partition << 16 */ ++ ++ unsigned long r1; /* the gp pointer */ ++ unsigned long r12; /* interrupted task's memory stack pointer */ ++ unsigned long r13; /* thread pointer */ ++ ++ unsigned long ar_fpsr; /* floating point status (preserved) */ ++ unsigned long r15; /* scratch */ ++ ++ /* The remaining registers are NOT saved for system calls. */ ++ ++ unsigned long r14; /* scratch */ ++ unsigned long r2; /* scratch */ ++ unsigned long r3; /* scratch */ ++ unsigned long r16; /* scratch */ ++ unsigned long r17; /* scratch */ ++ unsigned long r18; /* scratch */ ++ unsigned long r19; /* scratch */ ++ unsigned long r20; /* scratch */ ++ unsigned long r21; /* scratch */ ++ unsigned long r22; /* scratch */ ++ unsigned long r23; /* scratch */ ++ unsigned long r24; /* scratch */ ++ unsigned long r25; /* scratch */ ++ unsigned long r26; /* scratch */ ++ unsigned long r27; /* scratch */ ++ unsigned long r28; /* scratch */ ++ unsigned long r29; /* scratch */ ++ unsigned long r30; /* scratch */ ++ unsigned long r31; /* scratch */ ++ unsigned long ar_ccv; /* compare/exchange value (scratch) */ ++ ++ /* ++ * Floating point registers that the kernel considers scratch: ++ */ ++ struct pt_fpreg f6; /* scratch */ ++ struct pt_fpreg f7; /* scratch */ ++ struct pt_fpreg f8; /* scratch */ ++ struct pt_fpreg f9; /* scratch */ ++ struct pt_fpreg f10; /* scratch */ ++ struct pt_fpreg f11; /* scratch */ ++ unsigned long r4; /* preserved */ ++ unsigned long r5; /* preserved */ ++ unsigned long r6; /* preserved */ ++ unsigned long r7; /* preserved */ ++ unsigned long eml_unat; /* used for emulating instruction */ ++ unsigned long pad0; /* alignment pad */ ++ ++}; ++typedef struct cpu_user_regs cpu_user_regs_t; ++ ++union vac { ++ unsigned long value; ++ struct { ++ int a_int:1; ++ int a_from_int_cr:1; ++ int a_to_int_cr:1; ++ int a_from_psr:1; ++ int a_from_cpuid:1; ++ int a_cover:1; ++ int a_bsw:1; ++ long reserved:57; ++ }; ++}; ++typedef union vac vac_t; ++ ++union vdc { ++ unsigned long value; ++ struct { ++ int d_vmsw:1; ++ int d_extint:1; ++ int d_ibr_dbr:1; ++ int d_pmc:1; ++ int d_to_pmd:1; ++ int d_itm:1; ++ long reserved:58; ++ }; ++}; ++typedef union vdc vdc_t; ++ ++struct mapped_regs { ++ union vac vac; ++ union vdc vdc; ++ unsigned long virt_env_vaddr; ++ unsigned long reserved1[29]; ++ unsigned long vhpi; ++ unsigned long reserved2[95]; ++ union { ++ unsigned long vgr[16]; ++ unsigned long bank1_regs[16]; // bank1 regs (r16-r31) when bank0 active ++ }; ++ union { ++ unsigned long vbgr[16]; ++ unsigned long bank0_regs[16]; // bank0 regs (r16-r31) when bank1 active ++ }; ++ unsigned long vnat; ++ unsigned long vbnat; ++ unsigned long vcpuid[5]; ++ unsigned long reserved3[11]; ++ unsigned long vpsr; ++ unsigned long vpr; ++ unsigned long reserved4[76]; ++ union { ++ unsigned long vcr[128]; ++ struct { ++ unsigned long dcr; // CR0 ++ unsigned long itm; ++ unsigned long iva; ++ unsigned long rsv1[5]; ++ unsigned long pta; // CR8 ++ unsigned long rsv2[7]; ++ unsigned long ipsr; // CR16 ++ unsigned long isr; ++ unsigned long rsv3; ++ unsigned long iip; ++ unsigned long ifa; ++ unsigned long itir; ++ unsigned long iipa; ++ unsigned long ifs; ++ unsigned long iim; // CR24 ++ unsigned long iha; ++ unsigned long rsv4[38]; ++ unsigned long lid; // CR64 ++ unsigned long ivr; ++ unsigned long tpr; ++ unsigned long eoi; ++ unsigned long irr[4]; ++ unsigned long itv; // CR72 ++ unsigned long pmv; ++ unsigned long cmcv; ++ unsigned long rsv5[5]; ++ unsigned long lrr0; // CR80 ++ unsigned long lrr1; ++ unsigned long rsv6[46]; ++ }; ++ }; ++ union { ++ unsigned long reserved5[128]; ++ struct { ++ unsigned long precover_ifs; ++ unsigned long unat; // not sure if this is needed until NaT arch is done ++ int interrupt_collection_enabled; // virtual psr.ic ++ /* virtual interrupt deliverable flag is evtchn_upcall_mask in ++ * shared info area now. interrupt_mask_addr is the address ++ * of evtchn_upcall_mask for current vcpu ++ */ ++ unsigned char *interrupt_mask_addr; ++ int pending_interruption; ++ unsigned char vpsr_pp; ++ unsigned char vpsr_dfh; ++ unsigned char hpsr_dfh; ++ unsigned char hpsr_mfh; ++ unsigned long reserved5_1[4]; ++ int metaphysical_mode; // 1 = use metaphys mapping, 0 = use virtual ++ int banknum; // 0 or 1, which virtual register bank is active ++ unsigned long rrs[8]; // region registers ++ unsigned long krs[8]; // kernel registers ++ unsigned long pkrs[8]; // protection key registers ++ unsigned long tmp[8]; // temp registers (e.g. for hyperprivops) ++ }; ++ }; ++}; ++typedef struct mapped_regs mapped_regs_t; ++ ++struct vpd { ++ struct mapped_regs vpd_low; ++ unsigned long reserved6[3456]; ++ unsigned long vmm_avail[128]; ++ unsigned long reserved7[4096]; ++}; ++typedef struct vpd vpd_t; ++ ++struct arch_vcpu_info { ++}; ++typedef struct arch_vcpu_info arch_vcpu_info_t; ++ ++struct arch_shared_info { ++ /* PFN of the start_info page. */ ++ unsigned long start_info_pfn; ++ ++ /* Interrupt vector for event channel. */ ++ int evtchn_vector; ++ ++ uint64_t pad[32]; ++}; ++typedef struct arch_shared_info arch_shared_info_t; ++ ++typedef unsigned long xen_callback_t; ++ ++struct ia64_tr_entry { ++ unsigned long pte; ++ unsigned long itir; ++ unsigned long vadr; ++ unsigned long rid; ++}; ++ ++struct vcpu_extra_regs { ++ struct ia64_tr_entry itrs[8]; ++ struct ia64_tr_entry dtrs[8]; ++ unsigned long iva; ++ unsigned long dcr; ++ unsigned long event_callback_ip; ++}; ++ ++struct vcpu_guest_context { ++#define VGCF_EXTRA_REGS (1<<1) /* Get/Set extra regs. */ ++ unsigned long flags; /* VGCF_* flags */ ++ ++ struct cpu_user_regs user_regs; ++ struct vcpu_extra_regs extra_regs; ++ unsigned long privregs_pfn; ++}; ++typedef struct vcpu_guest_context vcpu_guest_context_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); ++ ++/* dom0 vp op */ ++#define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0 ++/* Map io space in machine address to dom0 physical address space. ++ Currently physical assigned address equals to machine address. */ ++#define IA64_DOM0VP_ioremap 0 ++ ++/* Convert a pseudo physical page frame number to the corresponding ++ machine page frame number. If no page is assigned, INVALID_MFN or ++ GPFN_INV_MASK is returned depending on domain's non-vti/vti mode. */ ++#define IA64_DOM0VP_phystomach 1 ++ ++/* Convert a machine page frame number to the corresponding pseudo physical ++ page frame number of the caller domain. */ ++#define IA64_DOM0VP_machtophys 3 ++ ++/* Reserved for future use. */ ++#define IA64_DOM0VP_iounmap 4 ++ ++/* Unmap and free pages contained in the specified pseudo physical region. */ ++#define IA64_DOM0VP_zap_physmap 5 ++ ++/* Assign machine page frame to dom0's pseudo physical address space. */ ++#define IA64_DOM0VP_add_physmap 6 ++ ++/* expose the p2m table into domain */ ++#define IA64_DOM0VP_expose_p2m 7 ++ ++/* xen perfmon */ ++#define IA64_DOM0VP_perfmon 8 ++ ++/* gmfn version of IA64_DOM0VP_add_physmap */ ++#define IA64_DOM0VP_add_physmap_with_gmfn 9 ++ ++// flags for page assignement to pseudo physical address space ++#define _ASSIGN_readonly 0 ++#define ASSIGN_readonly (1UL << _ASSIGN_readonly) ++#define ASSIGN_writable (0UL << _ASSIGN_readonly) // dummy flag ++/* Internal only: memory attribute must be WC/UC/UCE. */ ++#define _ASSIGN_nocache 1 ++#define ASSIGN_nocache (1UL << _ASSIGN_nocache) ++// tlb tracking ++#define _ASSIGN_tlb_track 2 ++#define ASSIGN_tlb_track (1UL << _ASSIGN_tlb_track) ++/* Internal only: associated with PGC_allocated bit */ ++#define _ASSIGN_pgc_allocated 3 ++#define ASSIGN_pgc_allocated (1UL << _ASSIGN_pgc_allocated) ++ ++/* This structure has the same layout of struct ia64_boot_param, defined in ++ <asm/system.h>. It is redefined here to ease use. */ ++struct xen_ia64_boot_param { ++ unsigned long command_line; /* physical address of cmd line args */ ++ unsigned long efi_systab; /* physical address of EFI system table */ ++ unsigned long efi_memmap; /* physical address of EFI memory map */ ++ unsigned long efi_memmap_size; /* size of EFI memory map */ ++ unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ ++ unsigned int efi_memdesc_version; /* memory descriptor version */ ++ struct { ++ unsigned short num_cols; /* number of columns on console. */ ++ unsigned short num_rows; /* number of rows on console. */ ++ unsigned short orig_x; /* cursor's x position */ ++ unsigned short orig_y; /* cursor's y position */ ++ } console_info; ++ unsigned long fpswa; /* physical address of the fpswa interface */ ++ unsigned long initrd_start; ++ unsigned long initrd_size; ++ unsigned long domain_start; /* va where the boot time domain begins */ ++ unsigned long domain_size; /* how big is the boot domain */ ++}; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* Size of the shared_info area (this is not related to page size). */ ++#define XSI_SHIFT 14 ++#define XSI_SIZE (1 << XSI_SHIFT) ++/* Log size of mapped_regs area (64 KB - only 4KB is used). */ ++#define XMAPPEDREGS_SHIFT 12 ++#define XMAPPEDREGS_SIZE (1 << XMAPPEDREGS_SHIFT) ++/* Offset of XASI (Xen arch shared info) wrt XSI_BASE. */ ++#define XMAPPEDREGS_OFS XSI_SIZE ++ ++/* Hyperprivops. */ ++#define HYPERPRIVOP_START 0x1 ++#define HYPERPRIVOP_RFI (HYPERPRIVOP_START + 0x0) ++#define HYPERPRIVOP_RSM_DT (HYPERPRIVOP_START + 0x1) ++#define HYPERPRIVOP_SSM_DT (HYPERPRIVOP_START + 0x2) ++#define HYPERPRIVOP_COVER (HYPERPRIVOP_START + 0x3) ++#define HYPERPRIVOP_ITC_D (HYPERPRIVOP_START + 0x4) ++#define HYPERPRIVOP_ITC_I (HYPERPRIVOP_START + 0x5) ++#define HYPERPRIVOP_SSM_I (HYPERPRIVOP_START + 0x6) ++#define HYPERPRIVOP_GET_IVR (HYPERPRIVOP_START + 0x7) ++#define HYPERPRIVOP_GET_TPR (HYPERPRIVOP_START + 0x8) ++#define HYPERPRIVOP_SET_TPR (HYPERPRIVOP_START + 0x9) ++#define HYPERPRIVOP_EOI (HYPERPRIVOP_START + 0xa) ++#define HYPERPRIVOP_SET_ITM (HYPERPRIVOP_START + 0xb) ++#define HYPERPRIVOP_THASH (HYPERPRIVOP_START + 0xc) ++#define HYPERPRIVOP_PTC_GA (HYPERPRIVOP_START + 0xd) ++#define HYPERPRIVOP_ITR_D (HYPERPRIVOP_START + 0xe) ++#define HYPERPRIVOP_GET_RR (HYPERPRIVOP_START + 0xf) ++#define HYPERPRIVOP_SET_RR (HYPERPRIVOP_START + 0x10) ++#define HYPERPRIVOP_SET_KR (HYPERPRIVOP_START + 0x11) ++#define HYPERPRIVOP_FC (HYPERPRIVOP_START + 0x12) ++#define HYPERPRIVOP_GET_CPUID (HYPERPRIVOP_START + 0x13) ++#define HYPERPRIVOP_GET_PMD (HYPERPRIVOP_START + 0x14) ++#define HYPERPRIVOP_GET_EFLAG (HYPERPRIVOP_START + 0x15) ++#define HYPERPRIVOP_SET_EFLAG (HYPERPRIVOP_START + 0x16) ++#define HYPERPRIVOP_RSM_BE (HYPERPRIVOP_START + 0x17) ++#define HYPERPRIVOP_GET_PSR (HYPERPRIVOP_START + 0x18) ++#define HYPERPRIVOP_MAX (0x19) ++ ++/* Fast and light hypercalls. */ ++#define __HYPERVISOR_ia64_fast_eoi __HYPERVISOR_arch_1 ++ ++/* Xencomm macros. */ ++#define XENCOMM_INLINE_MASK 0xf800000000000000UL ++#define XENCOMM_INLINE_FLAG 0x8000000000000000UL ++ ++#define XENCOMM_IS_INLINE(addr) \ ++ (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG) ++#define XENCOMM_INLINE_ADDR(addr) \ ++ ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK) ++ ++/* xen perfmon */ ++#ifdef XEN ++#ifndef __ASSEMBLY__ ++#ifndef _ASM_IA64_PERFMON_H ++ ++#include <xen/list.h> // asm/perfmon.h requires struct list_head ++#include <asm/perfmon.h> ++// for PFM_xxx and pfarg_features_t, pfarg_context_t, pfarg_reg_t, pfarg_load_t ++ ++#endif /* _ASM_IA64_PERFMON_H */ ++ ++DEFINE_XEN_GUEST_HANDLE(pfarg_features_t); ++DEFINE_XEN_GUEST_HANDLE(pfarg_context_t); ++DEFINE_XEN_GUEST_HANDLE(pfarg_reg_t); ++DEFINE_XEN_GUEST_HANDLE(pfarg_load_t); ++#endif /* __ASSEMBLY__ */ ++#endif /* XEN */ ++ ++#endif /* __HYPERVISOR_IF_IA64_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-powerpc.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-powerpc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,125 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) IBM Corp. 2005, 2006 ++ * ++ * Authors: Hollis Blanchard <hollisb@us.ibm.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_ARCH_PPC_64_H__ ++#define __XEN_PUBLIC_ARCH_PPC_64_H__ ++ ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef struct { \ ++ int __pad[(sizeof (long long) - sizeof (void *)) / sizeof (int)]; \ ++ type *p; \ ++ } __attribute__((__aligned__(8))) __guest_handle_ ## name ++ ++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) ++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name ++#define set_xen_guest_handle(hnd, val) \ ++ do { \ ++ if (sizeof ((hnd).__pad)) \ ++ (hnd).__pad[0] = 0; \ ++ (hnd).p = val; \ ++ } while (0) ++ ++#ifdef __XEN_TOOLS__ ++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) ++#endif ++ ++#ifndef __ASSEMBLY__ ++/* Guest handles for primitive C types. */ ++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); ++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); ++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); ++DEFINE_XEN_GUEST_HANDLE(char); ++DEFINE_XEN_GUEST_HANDLE(int); ++DEFINE_XEN_GUEST_HANDLE(long); ++DEFINE_XEN_GUEST_HANDLE(void); ++ ++typedef unsigned long long xen_pfn_t; ++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); ++#define PRI_xen_pfn "llx" ++#endif ++ ++/* ++ * Pointers and other address fields inside interface structures are padded to ++ * 64 bits. This means that field alignments aren't different between 32- and ++ * 64-bit architectures. ++ */ ++/* NB. Multi-level macro ensures __LINE__ is expanded before concatenation. */ ++#define __MEMORY_PADDING(_X) ++#define _MEMORY_PADDING(_X) __MEMORY_PADDING(_X) ++#define MEMORY_PADDING _MEMORY_PADDING(__LINE__) ++ ++/* And the trap vector is... */ ++#define TRAP_INSTR "li 0,-1; sc" /* XXX just "sc"? */ ++ ++#ifndef __ASSEMBLY__ ++ ++#define XENCOMM_INLINE_FLAG (1UL << 63) ++ ++typedef uint64_t xen_ulong_t; ++ ++/* User-accessible registers: nost of these need to be saved/restored ++ * for every nested Xen invocation. */ ++struct cpu_user_regs ++{ ++ uint64_t gprs[32]; ++ uint64_t lr; ++ uint64_t ctr; ++ uint64_t srr0; ++ uint64_t srr1; ++ uint64_t pc; ++ uint64_t msr; ++ uint64_t fpscr; /* XXX Is this necessary */ ++ uint64_t xer; ++ uint64_t hid4; /* debug only */ ++ uint64_t dar; /* debug only */ ++ uint32_t dsisr; /* debug only */ ++ uint32_t cr; ++ uint32_t __pad; /* good spot for another 32bit reg */ ++ uint32_t entry_vector; ++}; ++typedef struct cpu_user_regs cpu_user_regs_t; ++ ++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ /* XXX timebase */ ++ ++/* ONLY used to communicate with dom0! See also struct exec_domain. */ ++struct vcpu_guest_context { ++ cpu_user_regs_t user_regs; /* User-level CPU registers */ ++ uint64_t sdr1; /* Pagetable base */ ++ /* XXX etc */ ++}; ++typedef struct vcpu_guest_context vcpu_guest_context_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); ++ ++struct arch_shared_info { ++ uint64_t boot_timebase; ++}; ++ ++struct arch_vcpu_info { ++}; ++ ++/* Support for multi-processor guests. */ ++#define MAX_VIRT_CPUS 32 ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-x86/xen-x86_32.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-x86/xen-x86_32.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,168 @@ ++/****************************************************************************** ++ * xen-x86_32.h ++ * ++ * Guest OS interface to x86 32-bit Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004-2007, K A Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ ++#define __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ ++ ++/* ++ * Hypercall interface: ++ * Input: %ebx, %ecx, %edx, %esi, %edi (arguments 1-5) ++ * Output: %eax ++ * Access is via hypercall page (set up by guest loader or via a Xen MSR): ++ * call hypercall_page + hypercall-number * 32 ++ * Clobbered: Argument registers (e.g., 2-arg hypercall clobbers %ebx,%ecx) ++ */ ++ ++#if __XEN_INTERFACE_VERSION__ < 0x00030203 ++/* ++ * Legacy hypercall interface: ++ * As above, except the entry sequence to the hypervisor is: ++ * mov $hypercall-number*32,%eax ; int $0x82 ++ */ ++#define TRAP_INSTR "int $0x82" ++#endif ++ ++/* ++ * These flat segments are in the Xen-private section of every GDT. Since these ++ * are also present in the initial GDT, many OSes will be able to avoid ++ * installing their own GDT. ++ */ ++#define FLAT_RING1_CS 0xe019 /* GDT index 259 */ ++#define FLAT_RING1_DS 0xe021 /* GDT index 260 */ ++#define FLAT_RING1_SS 0xe021 /* GDT index 260 */ ++#define FLAT_RING3_CS 0xe02b /* GDT index 261 */ ++#define FLAT_RING3_DS 0xe033 /* GDT index 262 */ ++#define FLAT_RING3_SS 0xe033 /* GDT index 262 */ ++ ++#define FLAT_KERNEL_CS FLAT_RING1_CS ++#define FLAT_KERNEL_DS FLAT_RING1_DS ++#define FLAT_KERNEL_SS FLAT_RING1_SS ++#define FLAT_USER_CS FLAT_RING3_CS ++#define FLAT_USER_DS FLAT_RING3_DS ++#define FLAT_USER_SS FLAT_RING3_SS ++ ++/* ++ * Virtual addresses beyond this are not modifiable by guest OSes. The ++ * machine->physical mapping table starts at this address, read-only. ++ */ ++#ifdef CONFIG_X86_PAE ++#define __HYPERVISOR_VIRT_START 0xF5800000 ++#define __MACH2PHYS_VIRT_START 0xF5800000 ++#define __MACH2PHYS_VIRT_END 0xF6800000 ++#else ++#define __HYPERVISOR_VIRT_START 0xFC000000 ++#define __MACH2PHYS_VIRT_START 0xFC000000 ++#define __MACH2PHYS_VIRT_END 0xFC400000 ++#endif ++ ++#ifndef HYPERVISOR_VIRT_START ++#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) ++#endif ++ ++#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) ++#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) ++#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>2) ++#ifndef machine_to_phys_mapping ++#define machine_to_phys_mapping ((unsigned long *)MACH2PHYS_VIRT_START) ++#endif ++ ++/* 32-/64-bit invariability for control interfaces (domctl/sysctl). */ ++#if defined(__XEN__) || defined(__XEN_TOOLS__) ++#undef __DEFINE_XEN_GUEST_HANDLE ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef struct { type *p; } \ ++ __guest_handle_ ## name; \ ++ typedef struct { union { type *p; uint64_aligned_t q; }; } \ ++ __guest_handle_64_ ## name ++#undef set_xen_guest_handle ++#define set_xen_guest_handle(hnd, val) \ ++ do { if ( sizeof(hnd) == 8 ) *(uint64_t *)&(hnd) = 0; \ ++ (hnd).p = val; \ ++ } while ( 0 ) ++#define uint64_aligned_t uint64_t __attribute__((aligned(8))) ++#define XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++struct cpu_user_regs { ++ uint32_t ebx; ++ uint32_t ecx; ++ uint32_t edx; ++ uint32_t esi; ++ uint32_t edi; ++ uint32_t ebp; ++ uint32_t eax; ++ uint16_t error_code; /* private */ ++ uint16_t entry_vector; /* private */ ++ uint32_t eip; ++ uint16_t cs; ++ uint8_t saved_upcall_mask; ++ uint8_t _pad0; ++ uint32_t eflags; /* eflags.IF == !saved_upcall_mask */ ++ uint32_t esp; ++ uint16_t ss, _pad1; ++ uint16_t es, _pad2; ++ uint16_t ds, _pad3; ++ uint16_t fs, _pad4; ++ uint16_t gs, _pad5; ++}; ++typedef struct cpu_user_regs cpu_user_regs_t; ++DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t); ++ ++/* ++ * Page-directory addresses above 4GB do not fit into architectural %cr3. ++ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests ++ * must use the following accessor macros to pack/unpack valid MFNs. ++ */ ++#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) ++#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20)) ++ ++struct arch_vcpu_info { ++ unsigned long cr2; ++ unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */ ++}; ++typedef struct arch_vcpu_info arch_vcpu_info_t; ++ ++struct xen_callback { ++ unsigned long cs; ++ unsigned long eip; ++}; ++typedef struct xen_callback xen_callback_t; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-x86/xen-x86_64.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-x86/xen-x86_64.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,211 @@ ++/****************************************************************************** ++ * xen-x86_64.h ++ * ++ * Guest OS interface to x86 64-bit Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004-2006, K A Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ ++#define __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ ++ ++/* ++ * Hypercall interface: ++ * Input: %rdi, %rsi, %rdx, %r10, %r8 (arguments 1-5) ++ * Output: %rax ++ * Access is via hypercall page (set up by guest loader or via a Xen MSR): ++ * call hypercall_page + hypercall-number * 32 ++ * Clobbered: argument registers (e.g., 2-arg hypercall clobbers %rdi,%rsi) ++ */ ++ ++#if __XEN_INTERFACE_VERSION__ < 0x00030203 ++/* ++ * Legacy hypercall interface: ++ * As above, except the entry sequence to the hypervisor is: ++ * mov $hypercall-number*32,%eax ; syscall ++ * Clobbered: %rcx, %r11, argument registers (as above) ++ */ ++#define TRAP_INSTR "syscall" ++#endif ++ ++/* ++ * 64-bit segment selectors ++ * These flat segments are in the Xen-private section of every GDT. Since these ++ * are also present in the initial GDT, many OSes will be able to avoid ++ * installing their own GDT. ++ */ ++ ++#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */ ++#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */ ++#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */ ++#define FLAT_RING3_DS64 0x0000 /* NULL selector */ ++#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */ ++#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */ ++ ++#define FLAT_KERNEL_DS64 FLAT_RING3_DS64 ++#define FLAT_KERNEL_DS32 FLAT_RING3_DS32 ++#define FLAT_KERNEL_DS FLAT_KERNEL_DS64 ++#define FLAT_KERNEL_CS64 FLAT_RING3_CS64 ++#define FLAT_KERNEL_CS32 FLAT_RING3_CS32 ++#define FLAT_KERNEL_CS FLAT_KERNEL_CS64 ++#define FLAT_KERNEL_SS64 FLAT_RING3_SS64 ++#define FLAT_KERNEL_SS32 FLAT_RING3_SS32 ++#define FLAT_KERNEL_SS FLAT_KERNEL_SS64 ++ ++#define FLAT_USER_DS64 FLAT_RING3_DS64 ++#define FLAT_USER_DS32 FLAT_RING3_DS32 ++#define FLAT_USER_DS FLAT_USER_DS64 ++#define FLAT_USER_CS64 FLAT_RING3_CS64 ++#define FLAT_USER_CS32 FLAT_RING3_CS32 ++#define FLAT_USER_CS FLAT_USER_CS64 ++#define FLAT_USER_SS64 FLAT_RING3_SS64 ++#define FLAT_USER_SS32 FLAT_RING3_SS32 ++#define FLAT_USER_SS FLAT_USER_SS64 ++ ++#define __HYPERVISOR_VIRT_START 0xFFFF800000000000 ++#define __HYPERVISOR_VIRT_END 0xFFFF880000000000 ++#define __MACH2PHYS_VIRT_START 0xFFFF800000000000 ++#define __MACH2PHYS_VIRT_END 0xFFFF804000000000 ++ ++#ifndef HYPERVISOR_VIRT_START ++#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) ++#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) ++#endif ++ ++#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) ++#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) ++#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) ++#ifndef machine_to_phys_mapping ++#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) ++ * @which == SEGBASE_* ; @base == 64-bit base address ++ * Returns 0 on success. ++ */ ++#define SEGBASE_FS 0 ++#define SEGBASE_GS_USER 1 ++#define SEGBASE_GS_KERNEL 2 ++#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */ ++ ++/* ++ * int HYPERVISOR_iret(void) ++ * All arguments are on the kernel stack, in the following format. ++ * Never returns if successful. Current kernel context is lost. ++ * The saved CS is mapped as follows: ++ * RING0 -> RING3 kernel mode. ++ * RING1 -> RING3 kernel mode. ++ * RING2 -> RING3 kernel mode. ++ * RING3 -> RING3 user mode. ++ * However RING0 indicates that the guest kernel should return to iteself ++ * directly with ++ * orb $3,1*8(%rsp) ++ * iretq ++ * If flags contains VGCF_in_syscall: ++ * Restore RAX, RIP, RFLAGS, RSP. ++ * Discard R11, RCX, CS, SS. ++ * Otherwise: ++ * Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP. ++ * All other registers are saved on hypercall entry and restored to user. ++ */ ++/* Guest exited in SYSCALL context? Return to guest with SYSRET? */ ++#define _VGCF_in_syscall 8 ++#define VGCF_in_syscall (1<<_VGCF_in_syscall) ++#define VGCF_IN_SYSCALL VGCF_in_syscall ++struct iret_context { ++ /* Top of stack (%rsp at point of hypercall). */ ++ uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss; ++ /* Bottom of iret stack frame. */ ++}; ++ ++#ifdef __GNUC__ ++/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */ ++#define __DECL_REG(name) union { \ ++ uint64_t r ## name, e ## name; \ ++ uint32_t _e ## name; \ ++} ++#else ++/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */ ++#define __DECL_REG(name) uint64_t r ## name ++#endif ++ ++struct cpu_user_regs { ++ uint64_t r15; ++ uint64_t r14; ++ uint64_t r13; ++ uint64_t r12; ++ __DECL_REG(bp); ++ __DECL_REG(bx); ++ uint64_t r11; ++ uint64_t r10; ++ uint64_t r9; ++ uint64_t r8; ++ __DECL_REG(ax); ++ __DECL_REG(cx); ++ __DECL_REG(dx); ++ __DECL_REG(si); ++ __DECL_REG(di); ++ uint32_t error_code; /* private */ ++ uint32_t entry_vector; /* private */ ++ __DECL_REG(ip); ++ uint16_t cs, _pad0[1]; ++ uint8_t saved_upcall_mask; ++ uint8_t _pad1[3]; ++ __DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */ ++ __DECL_REG(sp); ++ uint16_t ss, _pad2[3]; ++ uint16_t es, _pad3[3]; ++ uint16_t ds, _pad4[3]; ++ uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */ ++ uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */ ++}; ++typedef struct cpu_user_regs cpu_user_regs_t; ++DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t); ++ ++#undef __DECL_REG ++ ++#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12) ++#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12) ++ ++struct arch_vcpu_info { ++ unsigned long cr2; ++ unsigned long pad; /* sizeof(vcpu_info_t) == 64 */ ++}; ++typedef struct arch_vcpu_info arch_vcpu_info_t; ++ ++typedef unsigned long xen_callback_t; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-x86/xen.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-x86/xen.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,204 @@ ++/****************************************************************************** ++ * arch-x86/xen.h ++ * ++ * Guest OS interface to x86 Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004-2006, K A Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_ARCH_X86_XEN_H__ ++#define __XEN_PUBLIC_ARCH_X86_XEN_H__ ++ ++/* Structural guest handles introduced in 0x00030201. */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030201 ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef struct { type *p; } __guest_handle_ ## name ++#else ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ ++ typedef type * __guest_handle_ ## name ++#endif ++ ++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) ++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name ++#define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0) ++#ifdef __XEN_TOOLS__ ++#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) ++#endif ++ ++#if defined(__i386__) ++#include "xen-x86_32.h" ++#elif defined(__x86_64__) ++#include "xen-x86_64.h" ++#endif ++ ++#ifndef __ASSEMBLY__ ++/* Guest handles for primitive C types. */ ++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); ++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); ++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); ++DEFINE_XEN_GUEST_HANDLE(char); ++DEFINE_XEN_GUEST_HANDLE(int); ++DEFINE_XEN_GUEST_HANDLE(long); ++DEFINE_XEN_GUEST_HANDLE(void); ++ ++typedef unsigned long xen_pfn_t; ++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); ++#define PRI_xen_pfn "lx" ++#endif ++ ++/* ++ * SEGMENT DESCRIPTOR TABLES ++ */ ++/* ++ * A number of GDT entries are reserved by Xen. These are not situated at the ++ * start of the GDT because some stupid OSes export hard-coded selector values ++ * in their ABI. These hard-coded values are always near the start of the GDT, ++ * so Xen places itself out of the way, at the far end of the GDT. ++ */ ++#define FIRST_RESERVED_GDT_PAGE 14 ++#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096) ++#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8) ++ ++/* Maximum number of virtual CPUs in multi-processor guests. */ ++#define MAX_VIRT_CPUS 32 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef unsigned long xen_ulong_t; ++ ++/* ++ * Send an array of these to HYPERVISOR_set_trap_table(). ++ * The privilege level specifies which modes may enter a trap via a software ++ * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate ++ * privilege levels as follows: ++ * Level == 0: Noone may enter ++ * Level == 1: Kernel may enter ++ * Level == 2: Kernel may enter ++ * Level == 3: Everyone may enter ++ */ ++#define TI_GET_DPL(_ti) ((_ti)->flags & 3) ++#define TI_GET_IF(_ti) ((_ti)->flags & 4) ++#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl)) ++#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2)) ++struct trap_info { ++ uint8_t vector; /* exception vector */ ++ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */ ++ uint16_t cs; /* code selector */ ++ unsigned long address; /* code offset */ ++}; ++typedef struct trap_info trap_info_t; ++DEFINE_XEN_GUEST_HANDLE(trap_info_t); ++ ++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ ++ ++/* ++ * The following is all CPU context. Note that the fpu_ctxt block is filled ++ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used. ++ */ ++struct vcpu_guest_context { ++ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */ ++ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */ ++#define VGCF_I387_VALID (1<<0) ++#define VGCF_IN_KERNEL (1<<2) ++#define _VGCF_i387_valid 0 ++#define VGCF_i387_valid (1<<_VGCF_i387_valid) ++#define _VGCF_in_kernel 2 ++#define VGCF_in_kernel (1<<_VGCF_in_kernel) ++#define _VGCF_failsafe_disables_events 3 ++#define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events) ++#define _VGCF_syscall_disables_events 4 ++#define VGCF_syscall_disables_events (1<<_VGCF_syscall_disables_events) ++#define _VGCF_online 5 ++#define VGCF_online (1<<_VGCF_online) ++ unsigned long flags; /* VGCF_* flags */ ++ struct cpu_user_regs user_regs; /* User-level CPU registers */ ++ struct trap_info trap_ctxt[256]; /* Virtual IDT */ ++ unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */ ++ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */ ++ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */ ++ /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */ ++ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */ ++ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */ ++#ifdef __i386__ ++ unsigned long event_callback_cs; /* CS:EIP of event callback */ ++ unsigned long event_callback_eip; ++ unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */ ++ unsigned long failsafe_callback_eip; ++#else ++ unsigned long event_callback_eip; ++ unsigned long failsafe_callback_eip; ++#ifdef __XEN__ ++ union { ++ unsigned long syscall_callback_eip; ++ struct { ++ unsigned int event_callback_cs; /* compat CS of event cb */ ++ unsigned int failsafe_callback_cs; /* compat CS of failsafe cb */ ++ }; ++ }; ++#else ++ unsigned long syscall_callback_eip; ++#endif ++#endif ++ unsigned long vm_assist; /* VMASST_TYPE_* bitmap */ ++#ifdef __x86_64__ ++ /* Segment base addresses. */ ++ uint64_t fs_base; ++ uint64_t gs_base_kernel; ++ uint64_t gs_base_user; ++#endif ++}; ++typedef struct vcpu_guest_context vcpu_guest_context_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); ++ ++struct arch_shared_info { ++ unsigned long max_pfn; /* max pfn that appears in table */ ++ /* Frame containing list of mfns containing list of mfns containing p2m. */ ++ xen_pfn_t pfn_to_mfn_frame_list_list; ++ unsigned long nmi_reason; ++ uint64_t pad[32]; ++}; ++typedef struct arch_shared_info arch_shared_info_t; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* ++ * Prefix forces emulation of some non-trapping instructions. ++ * Currently only CPUID. ++ */ ++#ifdef __ASSEMBLY__ ++#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ; ++#define XEN_CPUID XEN_EMULATE_PREFIX cpuid ++#else ++#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; " ++#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid" ++#endif ++ ++#endif /* __XEN_PUBLIC_ARCH_X86_XEN_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-x86_32.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-x86_32.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,27 @@ ++/****************************************************************************** ++ * arch-x86_32.h ++ * ++ * Guest OS interface to x86 32-bit Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004-2006, K A Fraser ++ */ ++ ++#include "arch-x86/xen.h" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/arch-x86_64.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/arch-x86_64.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,27 @@ ++/****************************************************************************** ++ * arch-x86_64.h ++ * ++ * Guest OS interface to x86 64-bit Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004-2006, K A Fraser ++ */ ++ ++#include "arch-x86/xen.h" +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/callback.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/callback.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,92 @@ ++/****************************************************************************** ++ * callback.h ++ * ++ * Register guest OS callbacks with Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2006, Ian Campbell ++ */ ++ ++#ifndef __XEN_PUBLIC_CALLBACK_H__ ++#define __XEN_PUBLIC_CALLBACK_H__ ++ ++#include "xen.h" ++ ++/* ++ * Prototype for this hypercall is: ++ * long callback_op(int cmd, void *extra_args) ++ * @cmd == CALLBACKOP_??? (callback operation). ++ * @extra_args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++#define CALLBACKTYPE_event 0 ++#define CALLBACKTYPE_failsafe 1 ++#define CALLBACKTYPE_syscall 2 /* x86_64 only */ ++/* ++ * sysenter is only available on x86_32 with the ++ * supervisor_mode_kernel option enabled. ++ */ ++#define CALLBACKTYPE_sysenter 3 ++#define CALLBACKTYPE_nmi 4 ++ ++/* ++ * Disable event deliver during callback? This flag is ignored for event and ++ * NMI callbacks: event delivery is unconditionally disabled. ++ */ ++#define _CALLBACKF_mask_events 0 ++#define CALLBACKF_mask_events (1U << _CALLBACKF_mask_events) ++ ++/* ++ * Register a callback. ++ */ ++#define CALLBACKOP_register 0 ++struct callback_register { ++ uint16_t type; ++ uint16_t flags; ++ xen_callback_t address; ++}; ++typedef struct callback_register callback_register_t; ++DEFINE_XEN_GUEST_HANDLE(callback_register_t); ++ ++/* ++ * Unregister a callback. ++ * ++ * Not all callbacks can be unregistered. -EINVAL will be returned if ++ * you attempt to unregister such a callback. ++ */ ++#define CALLBACKOP_unregister 1 ++struct callback_unregister { ++ uint16_t type; ++ uint16_t _unused; ++}; ++typedef struct callback_unregister callback_unregister_t; ++DEFINE_XEN_GUEST_HANDLE(callback_unregister_t); ++ ++#endif /* __XEN_PUBLIC_CALLBACK_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/dom0_ops.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/dom0_ops.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,120 @@ ++/****************************************************************************** ++ * dom0_ops.h ++ * ++ * Process command requests from domain-0 guest OS. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2002-2003, B Dragovic ++ * Copyright (c) 2002-2006, K Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_DOM0_OPS_H__ ++#define __XEN_PUBLIC_DOM0_OPS_H__ ++ ++#include "xen.h" ++#include "platform.h" ++ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030204 ++#error "dom0_ops.h is a compatibility interface only" ++#endif ++ ++#define DOM0_INTERFACE_VERSION XENPF_INTERFACE_VERSION ++ ++#define DOM0_SETTIME XENPF_settime ++#define dom0_settime xenpf_settime ++#define dom0_settime_t xenpf_settime_t ++ ++#define DOM0_ADD_MEMTYPE XENPF_add_memtype ++#define dom0_add_memtype xenpf_add_memtype ++#define dom0_add_memtype_t xenpf_add_memtype_t ++ ++#define DOM0_DEL_MEMTYPE XENPF_del_memtype ++#define dom0_del_memtype xenpf_del_memtype ++#define dom0_del_memtype_t xenpf_del_memtype_t ++ ++#define DOM0_READ_MEMTYPE XENPF_read_memtype ++#define dom0_read_memtype xenpf_read_memtype ++#define dom0_read_memtype_t xenpf_read_memtype_t ++ ++#define DOM0_MICROCODE XENPF_microcode_update ++#define dom0_microcode xenpf_microcode_update ++#define dom0_microcode_t xenpf_microcode_update_t ++ ++#define DOM0_PLATFORM_QUIRK XENPF_platform_quirk ++#define dom0_platform_quirk xenpf_platform_quirk ++#define dom0_platform_quirk_t xenpf_platform_quirk_t ++ ++typedef uint64_t cpumap_t; ++ ++/* Unsupported legacy operation -- defined for API compatibility. */ ++#define DOM0_MSR 15 ++struct dom0_msr { ++ /* IN variables. */ ++ uint32_t write; ++ cpumap_t cpu_mask; ++ uint32_t msr; ++ uint32_t in1; ++ uint32_t in2; ++ /* OUT variables. */ ++ uint32_t out1; ++ uint32_t out2; ++}; ++typedef struct dom0_msr dom0_msr_t; ++DEFINE_XEN_GUEST_HANDLE(dom0_msr_t); ++ ++/* Unsupported legacy operation -- defined for API compatibility. */ ++#define DOM0_PHYSICAL_MEMORY_MAP 40 ++struct dom0_memory_map_entry { ++ uint64_t start, end; ++ uint32_t flags; /* reserved */ ++ uint8_t is_ram; ++}; ++typedef struct dom0_memory_map_entry dom0_memory_map_entry_t; ++DEFINE_XEN_GUEST_HANDLE(dom0_memory_map_entry_t); ++ ++struct dom0_op { ++ uint32_t cmd; ++ uint32_t interface_version; /* DOM0_INTERFACE_VERSION */ ++ union { ++ struct dom0_msr msr; ++ struct dom0_settime settime; ++ struct dom0_add_memtype add_memtype; ++ struct dom0_del_memtype del_memtype; ++ struct dom0_read_memtype read_memtype; ++ struct dom0_microcode microcode; ++ struct dom0_platform_quirk platform_quirk; ++ struct dom0_memory_map_entry physical_memory_map; ++ uint8_t pad[128]; ++ } u; ++}; ++typedef struct dom0_op dom0_op_t; ++DEFINE_XEN_GUEST_HANDLE(dom0_op_t); ++ ++#endif /* __XEN_PUBLIC_DOM0_OPS_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/domctl.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/domctl.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,478 @@ ++/****************************************************************************** ++ * domctl.h ++ * ++ * Domain management operations. For use by node control stack. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2002-2003, B Dragovic ++ * Copyright (c) 2002-2006, K Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_DOMCTL_H__ ++#define __XEN_PUBLIC_DOMCTL_H__ ++ ++#if !defined(__XEN__) && !defined(__XEN_TOOLS__) ++#error "domctl operations are intended for use by node control tools only" ++#endif ++ ++#include "xen.h" ++ ++#define XEN_DOMCTL_INTERFACE_VERSION 0x00000005 ++ ++struct xenctl_cpumap { ++ XEN_GUEST_HANDLE_64(uint8_t) bitmap; ++ uint32_t nr_cpus; ++}; ++ ++/* ++ * NB. xen_domctl.domain is an IN/OUT parameter for this operation. ++ * If it is specified as zero, an id is auto-allocated and returned. ++ */ ++#define XEN_DOMCTL_createdomain 1 ++struct xen_domctl_createdomain { ++ /* IN parameters */ ++ uint32_t ssidref; ++ xen_domain_handle_t handle; ++ /* Is this an HVM guest (as opposed to a PV guest)? */ ++#define _XEN_DOMCTL_CDF_hvm_guest 0 ++#define XEN_DOMCTL_CDF_hvm_guest (1U<<_XEN_DOMCTL_CDF_hvm_guest) ++ uint32_t flags; ++}; ++typedef struct xen_domctl_createdomain xen_domctl_createdomain_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t); ++ ++#define XEN_DOMCTL_destroydomain 2 ++#define XEN_DOMCTL_pausedomain 3 ++#define XEN_DOMCTL_unpausedomain 4 ++#define XEN_DOMCTL_resumedomain 27 ++ ++#define XEN_DOMCTL_getdomaininfo 5 ++struct xen_domctl_getdomaininfo { ++ /* OUT variables. */ ++ domid_t domain; /* Also echoed in domctl.domain */ ++ /* Domain is scheduled to die. */ ++#define _XEN_DOMINF_dying 0 ++#define XEN_DOMINF_dying (1U<<_XEN_DOMINF_dying) ++ /* Domain is an HVM guest (as opposed to a PV guest). */ ++#define _XEN_DOMINF_hvm_guest 1 ++#define XEN_DOMINF_hvm_guest (1U<<_XEN_DOMINF_hvm_guest) ++ /* The guest OS has shut down. */ ++#define _XEN_DOMINF_shutdown 2 ++#define XEN_DOMINF_shutdown (1U<<_XEN_DOMINF_shutdown) ++ /* Currently paused by control software. */ ++#define _XEN_DOMINF_paused 3 ++#define XEN_DOMINF_paused (1U<<_XEN_DOMINF_paused) ++ /* Currently blocked pending an event. */ ++#define _XEN_DOMINF_blocked 4 ++#define XEN_DOMINF_blocked (1U<<_XEN_DOMINF_blocked) ++ /* Domain is currently running. */ ++#define _XEN_DOMINF_running 5 ++#define XEN_DOMINF_running (1U<<_XEN_DOMINF_running) ++ /* CPU to which this domain is bound. */ ++#define XEN_DOMINF_cpumask 255 ++#define XEN_DOMINF_cpushift 8 ++ /* XEN_DOMINF_shutdown guest-supplied code. */ ++#define XEN_DOMINF_shutdownmask 255 ++#define XEN_DOMINF_shutdownshift 16 ++ uint32_t flags; /* XEN_DOMINF_* */ ++ uint64_aligned_t tot_pages; ++ uint64_aligned_t max_pages; ++ uint64_aligned_t shared_info_frame; /* GMFN of shared_info struct */ ++ uint64_aligned_t cpu_time; ++ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */ ++ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */ ++ uint32_t ssidref; ++ xen_domain_handle_t handle; ++}; ++typedef struct xen_domctl_getdomaininfo xen_domctl_getdomaininfo_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getdomaininfo_t); ++ ++ ++#define XEN_DOMCTL_getmemlist 6 ++struct xen_domctl_getmemlist { ++ /* IN variables. */ ++ /* Max entries to write to output buffer. */ ++ uint64_aligned_t max_pfns; ++ /* Start index in guest's page list. */ ++ uint64_aligned_t start_pfn; ++ XEN_GUEST_HANDLE_64(uint64_t) buffer; ++ /* OUT variables. */ ++ uint64_aligned_t num_pfns; ++}; ++typedef struct xen_domctl_getmemlist xen_domctl_getmemlist_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getmemlist_t); ++ ++ ++#define XEN_DOMCTL_getpageframeinfo 7 ++ ++#define XEN_DOMCTL_PFINFO_LTAB_SHIFT 28 ++#define XEN_DOMCTL_PFINFO_NOTAB (0x0U<<28) ++#define XEN_DOMCTL_PFINFO_L1TAB (0x1U<<28) ++#define XEN_DOMCTL_PFINFO_L2TAB (0x2U<<28) ++#define XEN_DOMCTL_PFINFO_L3TAB (0x3U<<28) ++#define XEN_DOMCTL_PFINFO_L4TAB (0x4U<<28) ++#define XEN_DOMCTL_PFINFO_LTABTYPE_MASK (0x7U<<28) ++#define XEN_DOMCTL_PFINFO_LPINTAB (0x1U<<31) ++#define XEN_DOMCTL_PFINFO_XTAB (0xfU<<28) /* invalid page */ ++#define XEN_DOMCTL_PFINFO_LTAB_MASK (0xfU<<28) ++ ++struct xen_domctl_getpageframeinfo { ++ /* IN variables. */ ++ uint64_aligned_t gmfn; /* GMFN to query */ ++ /* OUT variables. */ ++ /* Is the page PINNED to a type? */ ++ uint32_t type; /* see above type defs */ ++}; ++typedef struct xen_domctl_getpageframeinfo xen_domctl_getpageframeinfo_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo_t); ++ ++ ++#define XEN_DOMCTL_getpageframeinfo2 8 ++struct xen_domctl_getpageframeinfo2 { ++ /* IN variables. */ ++ uint64_aligned_t num; ++ /* IN/OUT variables. */ ++ XEN_GUEST_HANDLE_64(uint32_t) array; ++}; ++typedef struct xen_domctl_getpageframeinfo2 xen_domctl_getpageframeinfo2_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo2_t); ++ ++ ++/* ++ * Control shadow pagetables operation ++ */ ++#define XEN_DOMCTL_shadow_op 10 ++ ++/* Disable shadow mode. */ ++#define XEN_DOMCTL_SHADOW_OP_OFF 0 ++ ++/* Enable shadow mode (mode contains ORed XEN_DOMCTL_SHADOW_ENABLE_* flags). */ ++#define XEN_DOMCTL_SHADOW_OP_ENABLE 32 ++ ++/* Log-dirty bitmap operations. */ ++ /* Return the bitmap and clean internal copy for next round. */ ++#define XEN_DOMCTL_SHADOW_OP_CLEAN 11 ++ /* Return the bitmap but do not modify internal copy. */ ++#define XEN_DOMCTL_SHADOW_OP_PEEK 12 ++ ++/* Memory allocation accessors. */ ++#define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION 30 ++#define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION 31 ++ ++/* Legacy enable operations. */ ++ /* Equiv. to ENABLE with no mode flags. */ ++#define XEN_DOMCTL_SHADOW_OP_ENABLE_TEST 1 ++ /* Equiv. to ENABLE with mode flag ENABLE_LOG_DIRTY. */ ++#define XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY 2 ++ /* Equiv. to ENABLE with mode flags ENABLE_REFCOUNT and ENABLE_TRANSLATE. */ ++#define XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE 3 ++ ++/* Mode flags for XEN_DOMCTL_SHADOW_OP_ENABLE. */ ++ /* ++ * Shadow pagetables are refcounted: guest does not use explicit mmu ++ * operations nor write-protect its pagetables. ++ */ ++#define XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT (1 << 1) ++ /* ++ * Log pages in a bitmap as they are dirtied. ++ * Used for live relocation to determine which pages must be re-sent. ++ */ ++#define XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY (1 << 2) ++ /* ++ * Automatically translate GPFNs into MFNs. ++ */ ++#define XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE (1 << 3) ++ /* ++ * Xen does not steal virtual address space from the guest. ++ * Requires HVM support. ++ */ ++#define XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL (1 << 4) ++ ++struct xen_domctl_shadow_op_stats { ++ uint32_t fault_count; ++ uint32_t dirty_count; ++}; ++typedef struct xen_domctl_shadow_op_stats xen_domctl_shadow_op_stats_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_shadow_op_stats_t); ++ ++struct xen_domctl_shadow_op { ++ /* IN variables. */ ++ uint32_t op; /* XEN_DOMCTL_SHADOW_OP_* */ ++ ++ /* OP_ENABLE */ ++ uint32_t mode; /* XEN_DOMCTL_SHADOW_ENABLE_* */ ++ ++ /* OP_GET_ALLOCATION / OP_SET_ALLOCATION */ ++ uint32_t mb; /* Shadow memory allocation in MB */ ++ ++ /* OP_PEEK / OP_CLEAN */ ++ XEN_GUEST_HANDLE_64(uint8_t) dirty_bitmap; ++ uint64_aligned_t pages; /* Size of buffer. Updated with actual size. */ ++ struct xen_domctl_shadow_op_stats stats; ++}; ++typedef struct xen_domctl_shadow_op xen_domctl_shadow_op_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_shadow_op_t); ++ ++ ++#define XEN_DOMCTL_max_mem 11 ++struct xen_domctl_max_mem { ++ /* IN variables. */ ++ uint64_aligned_t max_memkb; ++}; ++typedef struct xen_domctl_max_mem xen_domctl_max_mem_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_max_mem_t); ++ ++ ++#define XEN_DOMCTL_setvcpucontext 12 ++#define XEN_DOMCTL_getvcpucontext 13 ++struct xen_domctl_vcpucontext { ++ uint32_t vcpu; /* IN */ ++ XEN_GUEST_HANDLE_64(vcpu_guest_context_t) ctxt; /* IN/OUT */ ++}; ++typedef struct xen_domctl_vcpucontext xen_domctl_vcpucontext_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpucontext_t); ++ ++ ++#define XEN_DOMCTL_getvcpuinfo 14 ++struct xen_domctl_getvcpuinfo { ++ /* IN variables. */ ++ uint32_t vcpu; ++ /* OUT variables. */ ++ uint8_t online; /* currently online (not hotplugged)? */ ++ uint8_t blocked; /* blocked waiting for an event? */ ++ uint8_t running; /* currently scheduled on its CPU? */ ++ uint64_aligned_t cpu_time; /* total cpu time consumed (ns) */ ++ uint32_t cpu; /* current mapping */ ++}; ++typedef struct xen_domctl_getvcpuinfo xen_domctl_getvcpuinfo_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_getvcpuinfo_t); ++ ++ ++/* Get/set which physical cpus a vcpu can execute on. */ ++#define XEN_DOMCTL_setvcpuaffinity 9 ++#define XEN_DOMCTL_getvcpuaffinity 25 ++struct xen_domctl_vcpuaffinity { ++ uint32_t vcpu; /* IN */ ++ struct xenctl_cpumap cpumap; /* IN/OUT */ ++}; ++typedef struct xen_domctl_vcpuaffinity xen_domctl_vcpuaffinity_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpuaffinity_t); ++ ++ ++#define XEN_DOMCTL_max_vcpus 15 ++struct xen_domctl_max_vcpus { ++ uint32_t max; /* maximum number of vcpus */ ++}; ++typedef struct xen_domctl_max_vcpus xen_domctl_max_vcpus_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_max_vcpus_t); ++ ++ ++#define XEN_DOMCTL_scheduler_op 16 ++/* Scheduler types. */ ++#define XEN_SCHEDULER_SEDF 4 ++#define XEN_SCHEDULER_CREDIT 5 ++/* Set or get info? */ ++#define XEN_DOMCTL_SCHEDOP_putinfo 0 ++#define XEN_DOMCTL_SCHEDOP_getinfo 1 ++struct xen_domctl_scheduler_op { ++ uint32_t sched_id; /* XEN_SCHEDULER_* */ ++ uint32_t cmd; /* XEN_DOMCTL_SCHEDOP_* */ ++ union { ++ struct xen_domctl_sched_sedf { ++ uint64_aligned_t period; ++ uint64_aligned_t slice; ++ uint64_aligned_t latency; ++ uint32_t extratime; ++ uint32_t weight; ++ } sedf; ++ struct xen_domctl_sched_credit { ++ uint16_t weight; ++ uint16_t cap; ++ } credit; ++ } u; ++}; ++typedef struct xen_domctl_scheduler_op xen_domctl_scheduler_op_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_scheduler_op_t); ++ ++ ++#define XEN_DOMCTL_setdomainhandle 17 ++struct xen_domctl_setdomainhandle { ++ xen_domain_handle_t handle; ++}; ++typedef struct xen_domctl_setdomainhandle xen_domctl_setdomainhandle_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_setdomainhandle_t); ++ ++ ++#define XEN_DOMCTL_setdebugging 18 ++struct xen_domctl_setdebugging { ++ uint8_t enable; ++}; ++typedef struct xen_domctl_setdebugging xen_domctl_setdebugging_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_setdebugging_t); ++ ++ ++#define XEN_DOMCTL_irq_permission 19 ++struct xen_domctl_irq_permission { ++ uint8_t pirq; ++ uint8_t allow_access; /* flag to specify enable/disable of IRQ access */ ++}; ++typedef struct xen_domctl_irq_permission xen_domctl_irq_permission_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_irq_permission_t); ++ ++ ++#define XEN_DOMCTL_iomem_permission 20 ++struct xen_domctl_iomem_permission { ++ uint64_aligned_t first_mfn;/* first page (physical page number) in range */ ++ uint64_aligned_t nr_mfns; /* number of pages in range (>0) */ ++ uint8_t allow_access; /* allow (!0) or deny (0) access to range? */ ++}; ++typedef struct xen_domctl_iomem_permission xen_domctl_iomem_permission_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_iomem_permission_t); ++ ++ ++#define XEN_DOMCTL_ioport_permission 21 ++struct xen_domctl_ioport_permission { ++ uint32_t first_port; /* first port int range */ ++ uint32_t nr_ports; /* size of port range */ ++ uint8_t allow_access; /* allow or deny access to range? */ ++}; ++typedef struct xen_domctl_ioport_permission xen_domctl_ioport_permission_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_ioport_permission_t); ++ ++ ++#define XEN_DOMCTL_hypercall_init 22 ++struct xen_domctl_hypercall_init { ++ uint64_aligned_t gmfn; /* GMFN to be initialised */ ++}; ++typedef struct xen_domctl_hypercall_init xen_domctl_hypercall_init_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_hypercall_init_t); ++ ++ ++#define XEN_DOMCTL_arch_setup 23 ++#define _XEN_DOMAINSETUP_hvm_guest 0 ++#define XEN_DOMAINSETUP_hvm_guest (1UL<<_XEN_DOMAINSETUP_hvm_guest) ++#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save) */ ++#define XEN_DOMAINSETUP_query (1UL<<_XEN_DOMAINSETUP_query) ++typedef struct xen_domctl_arch_setup { ++ uint64_aligned_t flags; /* XEN_DOMAINSETUP_* */ ++#ifdef __ia64__ ++ uint64_aligned_t bp; /* mpaddr of boot param area */ ++ uint64_aligned_t maxmem; /* Highest memory address for MDT. */ ++ uint64_aligned_t xsi_va; /* Xen shared_info area virtual address. */ ++ uint32_t hypercall_imm; /* Break imm for Xen hypercalls. */ ++#endif ++} xen_domctl_arch_setup_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_arch_setup_t); ++ ++ ++#define XEN_DOMCTL_settimeoffset 24 ++struct xen_domctl_settimeoffset { ++ int32_t time_offset_seconds; /* applied to domain wallclock time */ ++}; ++typedef struct xen_domctl_settimeoffset xen_domctl_settimeoffset_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_settimeoffset_t); ++ ++ ++#define XEN_DOMCTL_gethvmcontext 33 ++#define XEN_DOMCTL_sethvmcontext 34 ++typedef struct xen_domctl_hvmcontext { ++ uint32_t size; /* IN/OUT: size of buffer / bytes filled */ ++ XEN_GUEST_HANDLE_64(uint8_t) buffer; /* IN/OUT: data, or call ++ * gethvmcontext with NULL ++ * buffer to get size ++ * req'd */ ++} xen_domctl_hvmcontext_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_t); ++ ++ ++#define XEN_DOMCTL_set_address_size 35 ++#define XEN_DOMCTL_get_address_size 36 ++typedef struct xen_domctl_address_size { ++ uint32_t size; ++} xen_domctl_address_size_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_address_size_t); ++ ++ ++#define XEN_DOMCTL_real_mode_area 26 ++struct xen_domctl_real_mode_area { ++ uint32_t log; /* log2 of Real Mode Area size */ ++}; ++typedef struct xen_domctl_real_mode_area xen_domctl_real_mode_area_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_real_mode_area_t); ++ ++ ++#define XEN_DOMCTL_sendtrigger 28 ++#define XEN_DOMCTL_SENDTRIGGER_NMI 0 ++#define XEN_DOMCTL_SENDTRIGGER_RESET 1 ++#define XEN_DOMCTL_SENDTRIGGER_INIT 2 ++struct xen_domctl_sendtrigger { ++ uint32_t trigger; /* IN */ ++ uint32_t vcpu; /* IN */ ++}; ++typedef struct xen_domctl_sendtrigger xen_domctl_sendtrigger_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendtrigger_t); ++ ++ ++struct xen_domctl { ++ uint32_t cmd; ++ uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ ++ domid_t domain; ++ union { ++ struct xen_domctl_createdomain createdomain; ++ struct xen_domctl_getdomaininfo getdomaininfo; ++ struct xen_domctl_getmemlist getmemlist; ++ struct xen_domctl_getpageframeinfo getpageframeinfo; ++ struct xen_domctl_getpageframeinfo2 getpageframeinfo2; ++ struct xen_domctl_vcpuaffinity vcpuaffinity; ++ struct xen_domctl_shadow_op shadow_op; ++ struct xen_domctl_max_mem max_mem; ++ struct xen_domctl_vcpucontext vcpucontext; ++ struct xen_domctl_getvcpuinfo getvcpuinfo; ++ struct xen_domctl_max_vcpus max_vcpus; ++ struct xen_domctl_scheduler_op scheduler_op; ++ struct xen_domctl_setdomainhandle setdomainhandle; ++ struct xen_domctl_setdebugging setdebugging; ++ struct xen_domctl_irq_permission irq_permission; ++ struct xen_domctl_iomem_permission iomem_permission; ++ struct xen_domctl_ioport_permission ioport_permission; ++ struct xen_domctl_hypercall_init hypercall_init; ++ struct xen_domctl_arch_setup arch_setup; ++ struct xen_domctl_settimeoffset settimeoffset; ++ struct xen_domctl_real_mode_area real_mode_area; ++ struct xen_domctl_hvmcontext hvmcontext; ++ struct xen_domctl_address_size address_size; ++ struct xen_domctl_sendtrigger sendtrigger; ++ uint8_t pad[128]; ++ } u; ++}; ++typedef struct xen_domctl xen_domctl_t; ++DEFINE_XEN_GUEST_HANDLE(xen_domctl_t); ++ ++#endif /* __XEN_PUBLIC_DOMCTL_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/elfnote.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/elfnote.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,233 @@ ++/****************************************************************************** ++ * elfnote.h ++ * ++ * Definitions used for the Xen ELF notes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2006, Ian Campbell, XenSource Ltd. ++ */ ++ ++#ifndef __XEN_PUBLIC_ELFNOTE_H__ ++#define __XEN_PUBLIC_ELFNOTE_H__ ++ ++/* ++ * The notes should live in a PT_NOTE segment and have "Xen" in the ++ * name field. ++ * ++ * Numeric types are either 4 or 8 bytes depending on the content of ++ * the desc field. ++ * ++ * LEGACY indicated the fields in the legacy __xen_guest string which ++ * this a note type replaces. ++ */ ++ ++/* ++ * NAME=VALUE pair (string). ++ */ ++#define XEN_ELFNOTE_INFO 0 ++ ++/* ++ * The virtual address of the entry point (numeric). ++ * ++ * LEGACY: VIRT_ENTRY ++ */ ++#define XEN_ELFNOTE_ENTRY 1 ++ ++/* The virtual address of the hypercall transfer page (numeric). ++ * ++ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page ++ * number not a virtual address) ++ */ ++#define XEN_ELFNOTE_HYPERCALL_PAGE 2 ++ ++/* The virtual address where the kernel image should be mapped (numeric). ++ * ++ * Defaults to 0. ++ * ++ * LEGACY: VIRT_BASE ++ */ ++#define XEN_ELFNOTE_VIRT_BASE 3 ++ ++/* ++ * The offset of the ELF paddr field from the acutal required ++ * psuedo-physical address (numeric). ++ * ++ * This is used to maintain backwards compatibility with older kernels ++ * which wrote __PAGE_OFFSET into that field. This field defaults to 0 ++ * if not present. ++ * ++ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE) ++ */ ++#define XEN_ELFNOTE_PADDR_OFFSET 4 ++ ++/* ++ * The version of Xen that we work with (string). ++ * ++ * LEGACY: XEN_VER ++ */ ++#define XEN_ELFNOTE_XEN_VERSION 5 ++ ++/* ++ * The name of the guest operating system (string). ++ * ++ * LEGACY: GUEST_OS ++ */ ++#define XEN_ELFNOTE_GUEST_OS 6 ++ ++/* ++ * The version of the guest operating system (string). ++ * ++ * LEGACY: GUEST_VER ++ */ ++#define XEN_ELFNOTE_GUEST_VERSION 7 ++ ++/* ++ * The loader type (string). ++ * ++ * LEGACY: LOADER ++ */ ++#define XEN_ELFNOTE_LOADER 8 ++ ++/* ++ * The kernel supports PAE (x86/32 only, string = "yes", "no" or ++ * "bimodal"). ++ * ++ * For compatibility with Xen 3.0.3 and earlier the "bimodal" setting ++ * may be given as "yes,bimodal" which will cause older Xen to treat ++ * this kernel as PAE. ++ * ++ * LEGACY: PAE (n.b. The legacy interface included a provision to ++ * indicate 'extended-cr3' support allowing L3 page tables to be ++ * placed above 4G. It is assumed that any kernel new enough to use ++ * these ELF notes will include this and therefore "yes" here is ++ * equivalent to "yes[entended-cr3]" in the __xen_guest interface. ++ */ ++#define XEN_ELFNOTE_PAE_MODE 9 ++ ++/* ++ * The features supported/required by this kernel (string). ++ * ++ * The string must consist of a list of feature names (as given in ++ * features.h, without the "XENFEAT_" prefix) separated by '|' ++ * characters. If a feature is required for the kernel to function ++ * then the feature name must be preceded by a '!' character. ++ * ++ * LEGACY: FEATURES ++ */ ++#define XEN_ELFNOTE_FEATURES 10 ++ ++/* ++ * The kernel requires the symbol table to be loaded (string = "yes" or "no") ++ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence ++ * of this string as a boolean flag rather than requiring "yes" or ++ * "no". ++ */ ++#define XEN_ELFNOTE_BSD_SYMTAB 11 ++ ++/* ++ * The lowest address the hypervisor hole can begin at (numeric). ++ * ++ * This must not be set higher than HYPERVISOR_VIRT_START. Its presence ++ * also indicates to the hypervisor that the kernel can deal with the ++ * hole starting at a higher address. ++ */ ++#define XEN_ELFNOTE_HV_START_LOW 12 ++ ++/* ++ * List of maddr_t-sized mask/value pairs describing how to recognize ++ * (non-present) L1 page table entries carrying valid MFNs (numeric). ++ */ ++#define XEN_ELFNOTE_L1_MFN_VALID 13 ++ ++/* ++ * Whether or not the guest supports cooperative suspend cancellation. ++ */ ++#define XEN_ELFNOTE_SUSPEND_CANCEL 14 ++ ++/* ++ * The number of the highest elfnote defined. ++ */ ++#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUSPEND_CANCEL ++ ++/* ++ * System information exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO ++ * note in case of a system crash. This note will contain various ++ * information about the system, see xen/include/xen/elfcore.h. ++ */ ++#define XEN_ELFNOTE_CRASH_INFO 0x1000001 ++ ++/* ++ * System registers exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS ++ * note per cpu in case of a system crash. This note is architecture ++ * specific and will contain registers not saved in the "CORE" note. ++ * See xen/include/xen/elfcore.h for more information. ++ */ ++#define XEN_ELFNOTE_CRASH_REGS 0x1000002 ++ ++ ++/* ++ * xen dump-core none note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_NONE ++ * in its dump file to indicate that the file is xen dump-core ++ * file. This note doesn't have any other information. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_NONE 0x2000000 ++ ++/* ++ * xen dump-core header note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_HEADER ++ * in its dump file. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_HEADER 0x2000001 ++ ++/* ++ * xen dump-core xen version note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_XEN_VERSION ++ * in its dump file. It contains the xen version obtained via the ++ * XENVER hypercall. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_XEN_VERSION 0x2000002 ++ ++/* ++ * xen dump-core format version note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION ++ * in its dump file. It contains a format version identifier. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION 0x2000003 ++ ++#endif /* __XEN_PUBLIC_ELFNOTE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/elfstructs.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/elfstructs.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,527 @@ ++#ifndef __XEN_PUBLIC_ELFSTRUCTS_H__ ++#define __XEN_PUBLIC_ELFSTRUCTS_H__ 1 ++/* ++ * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++typedef uint8_t Elf_Byte; ++ ++typedef uint32_t Elf32_Addr; /* Unsigned program address */ ++typedef uint32_t Elf32_Off; /* Unsigned file offset */ ++typedef int32_t Elf32_Sword; /* Signed large integer */ ++typedef uint32_t Elf32_Word; /* Unsigned large integer */ ++typedef uint16_t Elf32_Half; /* Unsigned medium integer */ ++ ++typedef uint64_t Elf64_Addr; ++typedef uint64_t Elf64_Off; ++typedef int32_t Elf64_Shalf; ++ ++typedef int32_t Elf64_Sword; ++typedef uint32_t Elf64_Word; ++ ++typedef int64_t Elf64_Sxword; ++typedef uint64_t Elf64_Xword; ++ ++typedef uint32_t Elf64_Half; ++typedef uint16_t Elf64_Quarter; ++ ++/* ++ * e_ident[] identification indexes ++ * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html ++ */ ++#define EI_MAG0 0 /* file ID */ ++#define EI_MAG1 1 /* file ID */ ++#define EI_MAG2 2 /* file ID */ ++#define EI_MAG3 3 /* file ID */ ++#define EI_CLASS 4 /* file class */ ++#define EI_DATA 5 /* data encoding */ ++#define EI_VERSION 6 /* ELF header version */ ++#define EI_OSABI 7 /* OS/ABI ID */ ++#define EI_ABIVERSION 8 /* ABI version */ ++#define EI_PAD 9 /* start of pad bytes */ ++#define EI_NIDENT 16 /* Size of e_ident[] */ ++ ++/* e_ident[] magic number */ ++#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ ++#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ ++#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ ++#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ ++#define ELFMAG "\177ELF" /* magic */ ++#define SELFMAG 4 /* size of magic */ ++ ++/* e_ident[] file class */ ++#define ELFCLASSNONE 0 /* invalid */ ++#define ELFCLASS32 1 /* 32-bit objs */ ++#define ELFCLASS64 2 /* 64-bit objs */ ++#define ELFCLASSNUM 3 /* number of classes */ ++ ++/* e_ident[] data encoding */ ++#define ELFDATANONE 0 /* invalid */ ++#define ELFDATA2LSB 1 /* Little-Endian */ ++#define ELFDATA2MSB 2 /* Big-Endian */ ++#define ELFDATANUM 3 /* number of data encode defines */ ++ ++/* e_ident[] Operating System/ABI */ ++#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ ++#define ELFOSABI_HPUX 1 /* HP-UX operating system */ ++#define ELFOSABI_NETBSD 2 /* NetBSD */ ++#define ELFOSABI_LINUX 3 /* GNU/Linux */ ++#define ELFOSABI_HURD 4 /* GNU/Hurd */ ++#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */ ++#define ELFOSABI_SOLARIS 6 /* Solaris */ ++#define ELFOSABI_MONTEREY 7 /* Monterey */ ++#define ELFOSABI_IRIX 8 /* IRIX */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD */ ++#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++/* e_ident */ ++#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ ++ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ ++ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ ++ (ehdr).e_ident[EI_MAG3] == ELFMAG3) ++ ++/* ELF Header */ ++typedef struct elfhdr { ++ unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ ++ Elf32_Half e_type; /* object file type */ ++ Elf32_Half e_machine; /* machine */ ++ Elf32_Word e_version; /* object file version */ ++ Elf32_Addr e_entry; /* virtual entry point */ ++ Elf32_Off e_phoff; /* program header table offset */ ++ Elf32_Off e_shoff; /* section header table offset */ ++ Elf32_Word e_flags; /* processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size */ ++ Elf32_Half e_phentsize; /* program header entry size */ ++ Elf32_Half e_phnum; /* number of program header entries */ ++ Elf32_Half e_shentsize; /* section header entry size */ ++ Elf32_Half e_shnum; /* number of section header entries */ ++ Elf32_Half e_shstrndx; /* section header table's "section ++ header string table" entry offset */ ++} Elf32_Ehdr; ++ ++typedef struct { ++ unsigned char e_ident[EI_NIDENT]; /* Id bytes */ ++ Elf64_Quarter e_type; /* file type */ ++ Elf64_Quarter e_machine; /* machine type */ ++ Elf64_Half e_version; /* version number */ ++ Elf64_Addr e_entry; /* entry point */ ++ Elf64_Off e_phoff; /* Program hdr offset */ ++ Elf64_Off e_shoff; /* Section hdr offset */ ++ Elf64_Half e_flags; /* Processor flags */ ++ Elf64_Quarter e_ehsize; /* sizeof ehdr */ ++ Elf64_Quarter e_phentsize; /* Program header entry size */ ++ Elf64_Quarter e_phnum; /* Number of program headers */ ++ Elf64_Quarter e_shentsize; /* Section header entry size */ ++ Elf64_Quarter e_shnum; /* Number of section headers */ ++ Elf64_Quarter e_shstrndx; /* String table index */ ++} Elf64_Ehdr; ++ ++/* e_type */ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* relocatable file */ ++#define ET_EXEC 2 /* executable file */ ++#define ET_DYN 3 /* shared object file */ ++#define ET_CORE 4 /* core file */ ++#define ET_NUM 5 /* number of types */ ++#define ET_LOPROC 0xff00 /* reserved range for processor */ ++#define ET_HIPROC 0xffff /* specific e_type */ ++ ++/* e_machine */ ++#define EM_NONE 0 /* No Machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola 68000 */ ++#define EM_88K 5 /* Motorola 88000 */ ++#define EM_486 6 /* Intel 80486 - unused? */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ ++/* ++ * Don't know if EM_MIPS_RS4_BE, ++ * EM_SPARC64, EM_PARISC, ++ * or EM_PPC are ABI compliant ++ */ ++#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ ++#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_ARM 40 /* Advanced RISC Machines ARM */ ++#define EM_ALPHA 41 /* DEC ALPHA */ ++#define EM_SPARCV9 43 /* SPARC version 9 */ ++#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_VAX 75 /* DEC VAX */ ++ ++/* Version */ ++#define EV_NONE 0 /* Invalid */ ++#define EV_CURRENT 1 /* Current */ ++#define EV_NUM 2 /* number of versions */ ++ ++/* Section Header */ ++typedef struct { ++ Elf32_Word sh_name; /* name - index into section header ++ string table section */ ++ Elf32_Word sh_type; /* type */ ++ Elf32_Word sh_flags; /* flags */ ++ Elf32_Addr sh_addr; /* address */ ++ Elf32_Off sh_offset; /* file offset */ ++ Elf32_Word sh_size; /* section size */ ++ Elf32_Word sh_link; /* section header table index link */ ++ Elf32_Word sh_info; /* extra information */ ++ Elf32_Word sh_addralign; /* address alignment */ ++ Elf32_Word sh_entsize; /* section entry size */ ++} Elf32_Shdr; ++ ++typedef struct { ++ Elf64_Half sh_name; /* section name */ ++ Elf64_Half sh_type; /* section type */ ++ Elf64_Xword sh_flags; /* section flags */ ++ Elf64_Addr sh_addr; /* virtual address */ ++ Elf64_Off sh_offset; /* file offset */ ++ Elf64_Xword sh_size; /* section size */ ++ Elf64_Half sh_link; /* link to another */ ++ Elf64_Half sh_info; /* misc info */ ++ Elf64_Xword sh_addralign; /* memory alignment */ ++ Elf64_Xword sh_entsize; /* table entry size */ ++} Elf64_Shdr; ++ ++/* Special Section Indexes */ ++#define SHN_UNDEF 0 /* undefined */ ++#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ ++#define SHN_LOPROC 0xff00 /* reserved range for processor */ ++#define SHN_HIPROC 0xff1f /* specific section indexes */ ++#define SHN_ABS 0xfff1 /* absolute value */ ++#define SHN_COMMON 0xfff2 /* common symbol */ ++#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ ++ ++/* sh_type */ ++#define SHT_NULL 0 /* inactive */ ++#define SHT_PROGBITS 1 /* program defined information */ ++#define SHT_SYMTAB 2 /* symbol table section */ ++#define SHT_STRTAB 3 /* string table section */ ++#define SHT_RELA 4 /* relocation section with addends*/ ++#define SHT_HASH 5 /* symbol hash table section */ ++#define SHT_DYNAMIC 6 /* dynamic section */ ++#define SHT_NOTE 7 /* note section */ ++#define SHT_NOBITS 8 /* no space section */ ++#define SHT_REL 9 /* relation section without addends */ ++#define SHT_SHLIB 10 /* reserved - purpose unknown */ ++#define SHT_DYNSYM 11 /* dynamic symbol table section */ ++#define SHT_NUM 12 /* number of section types */ ++#define SHT_LOPROC 0x70000000 /* reserved range for processor */ ++#define SHT_HIPROC 0x7fffffff /* specific section header types */ ++#define SHT_LOUSER 0x80000000 /* reserved range for application */ ++#define SHT_HIUSER 0xffffffff /* specific indexes */ ++ ++/* Section names */ ++#define ELF_BSS ".bss" /* uninitialized data */ ++#define ELF_DATA ".data" /* initialized data */ ++#define ELF_DEBUG ".debug" /* debug */ ++#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ ++#define ELF_DYNSTR ".dynstr" /* dynamic string table */ ++#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ ++#define ELF_FINI ".fini" /* termination code */ ++#define ELF_GOT ".got" /* global offset table */ ++#define ELF_HASH ".hash" /* symbol hash table */ ++#define ELF_INIT ".init" /* initialization code */ ++#define ELF_REL_DATA ".rel.data" /* relocation data */ ++#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ ++#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ ++#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ ++#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ ++#define ELF_REL_TEXT ".rel.text" /* relocation code */ ++#define ELF_RODATA ".rodata" /* read-only data */ ++#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ ++#define ELF_STRTAB ".strtab" /* string table */ ++#define ELF_SYMTAB ".symtab" /* symbol table */ ++#define ELF_TEXT ".text" /* code */ ++ ++ ++/* Section Attribute Flags - sh_flags */ ++#define SHF_WRITE 0x1 /* Writable */ ++#define SHF_ALLOC 0x2 /* occupies memory */ ++#define SHF_EXECINSTR 0x4 /* executable */ ++#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ ++ /* specific section attributes */ ++ ++/* Symbol Table Entry */ ++typedef struct elf32_sym { ++ Elf32_Word st_name; /* name - index into string table */ ++ Elf32_Addr st_value; /* symbol value */ ++ Elf32_Word st_size; /* symbol size */ ++ unsigned char st_info; /* type and binding */ ++ unsigned char st_other; /* 0 - no defined meaning */ ++ Elf32_Half st_shndx; /* section header index */ ++} Elf32_Sym; ++ ++typedef struct { ++ Elf64_Half st_name; /* Symbol name index in str table */ ++ Elf_Byte st_info; /* type / binding attrs */ ++ Elf_Byte st_other; /* unused */ ++ Elf64_Quarter st_shndx; /* section index of symbol */ ++ Elf64_Xword st_value; /* value of symbol */ ++ Elf64_Xword st_size; /* size of symbol */ ++} Elf64_Sym; ++ ++/* Symbol table index */ ++#define STN_UNDEF 0 /* undefined */ ++ ++/* Extract symbol info - st_info */ ++#define ELF32_ST_BIND(x) ((x) >> 4) ++#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) ++#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) ++ ++#define ELF64_ST_BIND(x) ((x) >> 4) ++#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf) ++#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) ++ ++/* Symbol Binding - ELF32_ST_BIND - st_info */ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* like global - lower precedence */ ++#define STB_NUM 3 /* number of symbol bindings */ ++#define STB_LOPROC 13 /* reserved range for processor */ ++#define STB_HIPROC 15 /* specific symbol bindings */ ++ ++/* Symbol type - ELF32_ST_TYPE - st_info */ ++#define STT_NOTYPE 0 /* not specified */ ++#define STT_OBJECT 1 /* data object */ ++#define STT_FUNC 2 /* function */ ++#define STT_SECTION 3 /* section */ ++#define STT_FILE 4 /* file */ ++#define STT_NUM 5 /* number of symbol types */ ++#define STT_LOPROC 13 /* reserved range for processor */ ++#define STT_HIPROC 15 /* specific symbol types */ ++ ++/* Relocation entry with implicit addend */ ++typedef struct { ++ Elf32_Addr r_offset; /* offset of relocation */ ++ Elf32_Word r_info; /* symbol table index and type */ ++} Elf32_Rel; ++ ++/* Relocation entry with explicit addend */ ++typedef struct { ++ Elf32_Addr r_offset; /* offset of relocation */ ++ Elf32_Word r_info; /* symbol table index and type */ ++ Elf32_Sword r_addend; ++} Elf32_Rela; ++ ++/* Extract relocation info - r_info */ ++#define ELF32_R_SYM(i) ((i) >> 8) ++#define ELF32_R_TYPE(i) ((unsigned char) (i)) ++#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) ++ ++typedef struct { ++ Elf64_Xword r_offset; /* where to do it */ ++ Elf64_Xword r_info; /* index & type of relocation */ ++} Elf64_Rel; ++ ++typedef struct { ++ Elf64_Xword r_offset; /* where to do it */ ++ Elf64_Xword r_info; /* index & type of relocation */ ++ Elf64_Sxword r_addend; /* adjustment value */ ++} Elf64_Rela; ++ ++#define ELF64_R_SYM(info) ((info) >> 32) ++#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF) ++#define ELF64_R_INFO(s,t) (((s) << 32) + (u_int32_t)(t)) ++ ++/* Program Header */ ++typedef struct { ++ Elf32_Word p_type; /* segment type */ ++ Elf32_Off p_offset; /* segment offset */ ++ Elf32_Addr p_vaddr; /* virtual address of segment */ ++ Elf32_Addr p_paddr; /* physical address - ignored? */ ++ Elf32_Word p_filesz; /* number of bytes in file for seg. */ ++ Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ ++ Elf32_Word p_flags; /* flags */ ++ Elf32_Word p_align; /* memory alignment */ ++} Elf32_Phdr; ++ ++typedef struct { ++ Elf64_Half p_type; /* entry type */ ++ Elf64_Half p_flags; /* flags */ ++ Elf64_Off p_offset; /* offset */ ++ Elf64_Addr p_vaddr; /* virtual address */ ++ Elf64_Addr p_paddr; /* physical address */ ++ Elf64_Xword p_filesz; /* file size */ ++ Elf64_Xword p_memsz; /* memory size */ ++ Elf64_Xword p_align; /* memory & file alignment */ ++} Elf64_Phdr; ++ ++/* Segment types - p_type */ ++#define PT_NULL 0 /* unused */ ++#define PT_LOAD 1 /* loadable segment */ ++#define PT_DYNAMIC 2 /* dynamic linking section */ ++#define PT_INTERP 3 /* the RTLD */ ++#define PT_NOTE 4 /* auxiliary information */ ++#define PT_SHLIB 5 /* reserved - purpose undefined */ ++#define PT_PHDR 6 /* program header */ ++#define PT_NUM 7 /* Number of segment types */ ++#define PT_LOPROC 0x70000000 /* reserved range for processor */ ++#define PT_HIPROC 0x7fffffff /* specific segment types */ ++ ++/* Segment flags - p_flags */ ++#define PF_X 0x1 /* Executable */ ++#define PF_W 0x2 /* Writable */ ++#define PF_R 0x4 /* Readable */ ++#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ ++ /* specific segment flags */ ++ ++/* Dynamic structure */ ++typedef struct { ++ Elf32_Sword d_tag; /* controls meaning of d_val */ ++ union { ++ Elf32_Word d_val; /* Multiple meanings - see d_tag */ ++ Elf32_Addr d_ptr; /* program virtual address */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct { ++ Elf64_Xword d_tag; /* controls meaning of d_val */ ++ union { ++ Elf64_Addr d_ptr; ++ Elf64_Xword d_val; ++ } d_un; ++} Elf64_Dyn; ++ ++/* Dynamic Array Tags - d_tag */ ++#define DT_NULL 0 /* marks end of _DYNAMIC array */ ++#define DT_NEEDED 1 /* string table offset of needed lib */ ++#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ ++#define DT_PLTGOT 3 /* address PLT/GOT */ ++#define DT_HASH 4 /* address of symbol hash table */ ++#define DT_STRTAB 5 /* address of string table */ ++#define DT_SYMTAB 6 /* address of symbol table */ ++#define DT_RELA 7 /* address of relocation table */ ++#define DT_RELASZ 8 /* size of relocation table */ ++#define DT_RELAENT 9 /* size of relocation entry */ ++#define DT_STRSZ 10 /* size of string table */ ++#define DT_SYMENT 11 /* size of symbol table entry */ ++#define DT_INIT 12 /* address of initialization func. */ ++#define DT_FINI 13 /* address of termination function */ ++#define DT_SONAME 14 /* string table offset of shared obj */ ++#define DT_RPATH 15 /* string table offset of library ++ search path */ ++#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ ++#define DT_REL 17 /* address of rel. tbl. w addends */ ++#define DT_RELSZ 18 /* size of DT_REL relocation table */ ++#define DT_RELENT 19 /* size of DT_REL relocation entry */ ++#define DT_PLTREL 20 /* PLT referenced relocation entry */ ++#define DT_DEBUG 21 /* bugger */ ++#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ ++#define DT_JMPREL 23 /* add. of PLT's relocation entries */ ++#define DT_BIND_NOW 24 /* Bind now regardless of env setting */ ++#define DT_NUM 25 /* Number used. */ ++#define DT_LOPROC 0x70000000 /* reserved range for processor */ ++#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ ++ ++/* Standard ELF hashing function */ ++unsigned int elf_hash(const unsigned char *name); ++ ++/* ++ * Note Definitions ++ */ ++typedef struct { ++ Elf32_Word namesz; ++ Elf32_Word descsz; ++ Elf32_Word type; ++} Elf32_Note; ++ ++typedef struct { ++ Elf64_Half namesz; ++ Elf64_Half descsz; ++ Elf64_Half type; ++} Elf64_Note; ++ ++ ++#if defined(ELFSIZE) ++#define CONCAT(x,y) __CONCAT(x,y) ++#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) ++#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) ++#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) ++#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) ++#endif ++ ++#if defined(ELFSIZE) && (ELFSIZE == 32) ++#define Elf_Ehdr Elf32_Ehdr ++#define Elf_Phdr Elf32_Phdr ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Rel Elf32_Rel ++#define Elf_RelA Elf32_Rela ++#define Elf_Dyn Elf32_Dyn ++#define Elf_Word Elf32_Word ++#define Elf_Sword Elf32_Sword ++#define Elf_Addr Elf32_Addr ++#define Elf_Off Elf32_Off ++#define Elf_Nhdr Elf32_Nhdr ++#define Elf_Note Elf32_Note ++ ++#define ELF_R_SYM ELF32_R_SYM ++#define ELF_R_TYPE ELF32_R_TYPE ++#define ELF_R_INFO ELF32_R_INFO ++#define ELFCLASS ELFCLASS32 ++ ++#define ELF_ST_BIND ELF32_ST_BIND ++#define ELF_ST_TYPE ELF32_ST_TYPE ++#define ELF_ST_INFO ELF32_ST_INFO ++ ++#define AuxInfo Aux32Info ++#elif defined(ELFSIZE) && (ELFSIZE == 64) ++#define Elf_Ehdr Elf64_Ehdr ++#define Elf_Phdr Elf64_Phdr ++#define Elf_Shdr Elf64_Shdr ++#define Elf_Sym Elf64_Sym ++#define Elf_Rel Elf64_Rel ++#define Elf_RelA Elf64_Rela ++#define Elf_Dyn Elf64_Dyn ++#define Elf_Word Elf64_Word ++#define Elf_Sword Elf64_Sword ++#define Elf_Addr Elf64_Addr ++#define Elf_Off Elf64_Off ++#define Elf_Nhdr Elf64_Nhdr ++#define Elf_Note Elf64_Note ++ ++#define ELF_R_SYM ELF64_R_SYM ++#define ELF_R_TYPE ELF64_R_TYPE ++#define ELF_R_INFO ELF64_R_INFO ++#define ELFCLASS ELFCLASS64 ++ ++#define ELF_ST_BIND ELF64_ST_BIND ++#define ELF_ST_TYPE ELF64_ST_TYPE ++#define ELF_ST_INFO ELF64_ST_INFO ++ ++#define AuxInfo Aux64Info ++#endif ++ ++#endif /* __XEN_PUBLIC_ELFSTRUCTS_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/event_channel.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/event_channel.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,264 @@ ++/****************************************************************************** ++ * event_channel.h ++ * ++ * Event channels between domains. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2003-2004, K A Fraser. ++ */ ++ ++#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__ ++#define __XEN_PUBLIC_EVENT_CHANNEL_H__ ++ ++/* ++ * Prototype for this hypercall is: ++ * int event_channel_op(int cmd, void *args) ++ * @cmd == EVTCHNOP_??? (event-channel operation). ++ * @args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++typedef uint32_t evtchn_port_t; ++DEFINE_XEN_GUEST_HANDLE(evtchn_port_t); ++ ++/* ++ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as ++ * accepting interdomain bindings from domain <remote_dom>. A fresh port ++ * is allocated in <dom> and returned as <port>. ++ * NOTES: ++ * 1. If the caller is unprivileged then <dom> must be DOMID_SELF. ++ * 2. <rdom> may be DOMID_SELF, allowing loopback connections. ++ */ ++#define EVTCHNOP_alloc_unbound 6 ++struct evtchn_alloc_unbound { ++ /* IN parameters */ ++ domid_t dom, remote_dom; ++ /* OUT parameters */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t; ++ ++/* ++ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between ++ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify ++ * a port that is unbound and marked as accepting bindings from the calling ++ * domain. A fresh port is allocated in the calling domain and returned as ++ * <local_port>. ++ * NOTES: ++ * 2. <remote_dom> may be DOMID_SELF, allowing loopback connections. ++ */ ++#define EVTCHNOP_bind_interdomain 0 ++struct evtchn_bind_interdomain { ++ /* IN parameters. */ ++ domid_t remote_dom; ++ evtchn_port_t remote_port; ++ /* OUT parameters. */ ++ evtchn_port_t local_port; ++}; ++typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t; ++ ++/* ++ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified ++ * vcpu. ++ * NOTES: ++ * 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list ++ * in xen.h for the classification of each VIRQ. ++ * 2. Global VIRQs must be allocated on VCPU0 but can subsequently be ++ * re-bound via EVTCHNOP_bind_vcpu. ++ * 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu. ++ * The allocated event channel is bound to the specified vcpu and the ++ * binding cannot be changed. ++ */ ++#define EVTCHNOP_bind_virq 1 ++struct evtchn_bind_virq { ++ /* IN parameters. */ ++ uint32_t virq; ++ uint32_t vcpu; ++ /* OUT parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_bind_virq evtchn_bind_virq_t; ++ ++/* ++ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>. ++ * NOTES: ++ * 1. A physical IRQ may be bound to at most one event channel per domain. ++ * 2. Only a sufficiently-privileged domain may bind to a physical IRQ. ++ */ ++#define EVTCHNOP_bind_pirq 2 ++struct evtchn_bind_pirq { ++ /* IN parameters. */ ++ uint32_t pirq; ++#define BIND_PIRQ__WILL_SHARE 1 ++ uint32_t flags; /* BIND_PIRQ__* */ ++ /* OUT parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_bind_pirq evtchn_bind_pirq_t; ++ ++/* ++ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events. ++ * NOTES: ++ * 1. The allocated event channel is bound to the specified vcpu. The binding ++ * may not be changed. ++ */ ++#define EVTCHNOP_bind_ipi 7 ++struct evtchn_bind_ipi { ++ uint32_t vcpu; ++ /* OUT parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_bind_ipi evtchn_bind_ipi_t; ++ ++/* ++ * EVTCHNOP_close: Close a local event channel <port>. If the channel is ++ * interdomain then the remote end is placed in the unbound state ++ * (EVTCHNSTAT_unbound), awaiting a new connection. ++ */ ++#define EVTCHNOP_close 3 ++struct evtchn_close { ++ /* IN parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_close evtchn_close_t; ++ ++/* ++ * EVTCHNOP_send: Send an event to the remote end of the channel whose local ++ * endpoint is <port>. ++ */ ++#define EVTCHNOP_send 4 ++struct evtchn_send { ++ /* IN parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_send evtchn_send_t; ++ ++/* ++ * EVTCHNOP_status: Get the current status of the communication channel which ++ * has an endpoint at <dom, port>. ++ * NOTES: ++ * 1. <dom> may be specified as DOMID_SELF. ++ * 2. Only a sufficiently-privileged domain may obtain the status of an event ++ * channel for which <dom> is not DOMID_SELF. ++ */ ++#define EVTCHNOP_status 5 ++struct evtchn_status { ++ /* IN parameters */ ++ domid_t dom; ++ evtchn_port_t port; ++ /* OUT parameters */ ++#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ ++#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ ++#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ ++#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ ++#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ ++#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ ++ uint32_t status; ++ uint32_t vcpu; /* VCPU to which this channel is bound. */ ++ union { ++ struct { ++ domid_t dom; ++ } unbound; /* EVTCHNSTAT_unbound */ ++ struct { ++ domid_t dom; ++ evtchn_port_t port; ++ } interdomain; /* EVTCHNSTAT_interdomain */ ++ uint32_t pirq; /* EVTCHNSTAT_pirq */ ++ uint32_t virq; /* EVTCHNSTAT_virq */ ++ } u; ++}; ++typedef struct evtchn_status evtchn_status_t; ++ ++/* ++ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an ++ * event is pending. ++ * NOTES: ++ * 1. IPI-bound channels always notify the vcpu specified at bind time. ++ * This binding cannot be changed. ++ * 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time. ++ * This binding cannot be changed. ++ * 3. All other channels notify vcpu0 by default. This default is set when ++ * the channel is allocated (a port that is freed and subsequently reused ++ * has its binding reset to vcpu0). ++ */ ++#define EVTCHNOP_bind_vcpu 8 ++struct evtchn_bind_vcpu { ++ /* IN parameters. */ ++ evtchn_port_t port; ++ uint32_t vcpu; ++}; ++typedef struct evtchn_bind_vcpu evtchn_bind_vcpu_t; ++ ++/* ++ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver ++ * a notification to the appropriate VCPU if an event is pending. ++ */ ++#define EVTCHNOP_unmask 9 ++struct evtchn_unmask { ++ /* IN parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_unmask evtchn_unmask_t; ++ ++/* ++ * EVTCHNOP_reset: Close all event channels associated with specified domain. ++ * NOTES: ++ * 1. <dom> may be specified as DOMID_SELF. ++ * 2. Only a sufficiently-privileged domain may specify other than DOMID_SELF. ++ */ ++#define EVTCHNOP_reset 10 ++struct evtchn_reset { ++ /* IN parameters. */ ++ domid_t dom; ++}; ++typedef struct evtchn_reset evtchn_reset_t; ++ ++/* ++ * Argument to event_channel_op_compat() hypercall. Superceded by new ++ * event_channel_op() hypercall since 0x00030202. ++ */ ++struct evtchn_op { ++ uint32_t cmd; /* EVTCHNOP_* */ ++ union { ++ struct evtchn_alloc_unbound alloc_unbound; ++ struct evtchn_bind_interdomain bind_interdomain; ++ struct evtchn_bind_virq bind_virq; ++ struct evtchn_bind_pirq bind_pirq; ++ struct evtchn_bind_ipi bind_ipi; ++ struct evtchn_close close; ++ struct evtchn_send send; ++ struct evtchn_status status; ++ struct evtchn_bind_vcpu bind_vcpu; ++ struct evtchn_unmask unmask; ++ } u; ++}; ++typedef struct evtchn_op evtchn_op_t; ++DEFINE_XEN_GUEST_HANDLE(evtchn_op_t); ++ ++#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/features.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/features.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,71 @@ ++/****************************************************************************** ++ * features.h ++ * ++ * Feature flags, reported by XENVER_get_features. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2006, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_FEATURES_H__ ++#define __XEN_PUBLIC_FEATURES_H__ ++ ++/* ++ * If set, the guest does not need to write-protect its pagetables, and can ++ * update them via direct writes. ++ */ ++#define XENFEAT_writable_page_tables 0 ++ ++/* ++ * If set, the guest does not need to write-protect its segment descriptor ++ * tables, and can update them via direct writes. ++ */ ++#define XENFEAT_writable_descriptor_tables 1 ++ ++/* ++ * If set, translation between the guest's 'pseudo-physical' address space ++ * and the host's machine address space are handled by the hypervisor. In this ++ * mode the guest does not need to perform phys-to/from-machine translations ++ * when performing page table operations. ++ */ ++#define XENFEAT_auto_translated_physmap 2 ++ ++/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */ ++#define XENFEAT_supervisor_mode_kernel 3 ++ ++/* ++ * If set, the guest does not need to allocate x86 PAE page directories ++ * below 4GB. This flag is usually implied by auto_translated_physmap. ++ */ ++#define XENFEAT_pae_pgdir_above_4gb 4 ++ ++#define XENFEAT_NR_SUBMAPS 1 ++ ++#endif /* __XEN_PUBLIC_FEATURES_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/foreign/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/foreign/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,37 @@ ++XEN_ROOT=../../../.. ++include $(XEN_ROOT)/Config.mk ++ ++architectures := x86_32 x86_64 ia64 ++headers := $(patsubst %, %.h, $(architectures)) ++scripts := $(wildcard *.py) ++ ++.PHONY: all clean check-headers ++all: $(headers) check-headers ++ ++clean: ++ rm -f $(headers) ++ rm -f checker checker.c $(XEN_TARGET_ARCH).size ++ rm -f *.pyc *.o *~ ++ ++ifeq ($(CROSS_COMPILE)$(XEN_TARGET_ARCH),$(XEN_COMPILE_ARCH)) ++check-headers: checker ++ ./checker > $(XEN_TARGET_ARCH).size ++ diff -u reference.size $(XEN_TARGET_ARCH).size ++checker: checker.c $(headers) ++ $(HOSTCC) $(HOSTCFLAGS) -o $@ $< ++else ++check-headers: ++ @echo "cross build: skipping check" ++endif ++ ++x86_32.h: ../arch-x86/xen-x86_32.h ../arch-x86/xen.h ../xen.h $(scripts) ++ python mkheader.py $* $@ $(filter %.h,$^) ++ ++x86_64.h: ../arch-x86/xen-x86_64.h ../arch-x86/xen.h ../xen.h $(scripts) ++ python mkheader.py $* $@ $(filter %.h,$^) ++ ++ia64.h: ../arch-ia64.h ../xen.h $(scripts) ++ python mkheader.py $* $@ $(filter %.h,$^) ++ ++checker.c: $(scripts) ++ python mkchecker.py $(XEN_TARGET_ARCH) $@ $(architectures) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/foreign/mkchecker.py +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/foreign/mkchecker.py Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,58 @@ ++#!/usr/bin/python ++ ++import sys; ++from structs import structs; ++ ++# command line arguments ++arch = sys.argv[1]; ++outfile = sys.argv[2]; ++archs = sys.argv[3:]; ++ ++f = open(outfile, "w"); ++f.write(''' ++/* ++ * sanity checks for generated foreign headers: ++ * - verify struct sizes ++ * ++ * generated by %s -- DO NOT EDIT ++ */ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stddef.h> ++#include <inttypes.h> ++#include "../xen.h" ++'''); ++ ++for a in archs: ++ f.write('#include "%s.h"\n' % a); ++ ++f.write('int main(int argc, char *argv[])\n{\n'); ++ ++f.write('\tprintf("\\n");'); ++f.write('printf("%-20s |", "structs");\n'); ++for a in archs: ++ f.write('\tprintf("%%8s", "%s");\n' % a); ++f.write('\tprintf("\\n");'); ++ ++f.write('\tprintf("\\n");'); ++for struct in structs: ++ f.write('\tprintf("%%-20s |", "%s");\n' % struct); ++ for a in archs: ++ if a == arch: ++ s = struct; # native ++ else: ++ s = struct + "_" + a; ++ f.write('#ifdef %s_has_no_%s\n' % (a, struct)); ++ f.write('\tprintf("%8s", "-");\n'); ++ f.write("#else\n"); ++ f.write('\tprintf("%%8zd", sizeof(struct %s));\n' % s); ++ f.write("#endif\n"); ++ ++ f.write('\tprintf("\\n");\n\n'); ++ ++f.write('\tprintf("\\n");\n'); ++f.write('\texit(0);\n'); ++f.write('}\n'); ++ ++f.close(); ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/foreign/mkheader.py +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/foreign/mkheader.py Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,153 @@ ++#!/usr/bin/python ++ ++import sys, re; ++from structs import structs, defines; ++ ++# command line arguments ++arch = sys.argv[1]; ++outfile = sys.argv[2]; ++infiles = sys.argv[3:]; ++ ++ ++########################################################################### ++# configuration #2: architecture information ++ ++inttypes = {}; ++header = {}; ++footer = {}; ++ ++# x86_32 ++inttypes["x86_32"] = { ++ "unsigned long" : "uint32_t", ++ "long" : "uint32_t", ++ "xen_pfn_t" : "uint32_t", ++}; ++header["x86_32"] = """ ++#define __i386___X86_32 1 ++#pragma pack(4) ++"""; ++footer["x86_32"] = """ ++#pragma pack() ++"""; ++ ++# x86_64 ++inttypes["x86_64"] = { ++ "unsigned long" : "__align8__ uint64_t", ++ "long" : "__align8__ uint64_t", ++ "xen_pfn_t" : "__align8__ uint64_t", ++}; ++header["x86_64"] = """ ++#ifdef __GNUC__ ++# define __DECL_REG(name) union { uint64_t r ## name, e ## name; } ++# define __align8__ __attribute__((aligned (8))) ++#else ++# define __DECL_REG(name) uint64_t r ## name ++# define __align8__ FIXME ++#endif ++#define __x86_64___X86_64 1 ++"""; ++ ++# ia64 ++inttypes["ia64"] = { ++ "unsigned long" : "__align8__ uint64_t", ++ "long" : "__align8__ uint64_t", ++ "xen_pfn_t" : "__align8__ uint64_t", ++ "long double" : "__align16__ ldouble_t", ++}; ++header["ia64"] = """ ++#define __align8__ __attribute__((aligned (8))) ++#define __align16__ __attribute__((aligned (16))) ++typedef unsigned char ldouble_t[16]; ++"""; ++ ++ ++########################################################################### ++# main ++ ++input = ""; ++output = ""; ++fileid = re.sub("[-.]", "_", "__FOREIGN_%s__" % outfile.upper()); ++ ++# read input header files ++for name in infiles: ++ f = open(name, "r"); ++ input += f.read(); ++ f.close(); ++ ++# add header ++output += """ ++/* ++ * public xen defines and struct for %s ++ * generated by %s -- DO NOT EDIT ++ */ ++ ++#ifndef %s ++#define %s 1 ++ ++""" % (arch, sys.argv[0], fileid, fileid) ++ ++if arch in header: ++ output += header[arch]; ++ output += "\n"; ++ ++# add defines to output ++for line in re.findall("#define[^\n]+", input): ++ for define in defines: ++ regex = "#define\s+%s\\b" % define; ++ match = re.search(regex, line); ++ if None == match: ++ continue; ++ if define.upper()[0] == define[0]: ++ replace = define + "_" + arch.upper(); ++ else: ++ replace = define + "_" + arch; ++ regex = "\\b%s\\b" % define; ++ output += re.sub(regex, replace, line) + "\n"; ++output += "\n"; ++ ++# delete defines, comments, empty lines ++input = re.sub("#define[^\n]+\n", "", input); ++input = re.compile("/\*(.*?)\*/", re.S).sub("", input) ++input = re.compile("\n\s*\n", re.S).sub("\n", input); ++ ++# add structs to output ++for struct in structs: ++ regex = "struct\s+%s\s*\{(.*?)\n\};" % struct; ++ match = re.search(regex, input, re.S) ++ if None == match: ++ output += "#define %s_has_no_%s 1\n" % (arch, struct); ++ else: ++ output += "struct %s_%s {%s\n};\n" % (struct, arch, match.group(1)); ++ output += "typedef struct %s_%s %s_%s_t;\n" % (struct, arch, struct, arch); ++ output += "\n"; ++ ++# add footer ++if arch in footer: ++ output += footer[arch]; ++ output += "\n"; ++output += "#endif /* %s */\n" % fileid; ++ ++# replace: defines ++for define in defines: ++ if define.upper()[0] == define[0]: ++ replace = define + "_" + arch.upper(); ++ else: ++ replace = define + "_" + arch; ++ output = re.sub("\\b%s\\b" % define, replace, output); ++ ++# replace: structs + struct typedefs ++for struct in structs: ++ output = re.sub("\\b(struct\s+%s)\\b" % struct, "\\1_%s" % arch, output); ++ output = re.sub("\\b(%s)_t\\b" % struct, "\\1_%s_t" % arch, output); ++ ++# replace: integer types ++integers = inttypes[arch].keys(); ++integers.sort(lambda a, b: cmp(len(b),len(a))); ++for type in integers: ++ output = re.sub("\\b%s\\b" % type, inttypes[arch][type], output); ++ ++# print results ++f = open(outfile, "w"); ++f.write(output); ++f.close; ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/foreign/reference.size +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/foreign/reference.size Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,17 @@ ++ ++structs | x86_32 x86_64 ia64 ++ ++start_info | 1104 1152 1152 ++trap_info | 8 16 - ++pt_fpreg | - - 16 ++cpu_user_regs | 68 200 496 ++xen_ia64_boot_param | - - 96 ++ia64_tr_entry | - - 32 ++vcpu_extra_regs | - - 536 ++vcpu_guest_context | 2800 5168 1056 ++arch_vcpu_info | 24 16 0 ++vcpu_time_info | 32 32 32 ++vcpu_info | 64 64 48 ++arch_shared_info | 268 280 272 ++shared_info | 2584 3368 4384 ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/foreign/structs.py +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/foreign/structs.py Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,54 @@ ++# configuration: what needs translation ++ ++structs = [ "start_info", ++ "trap_info", ++ "pt_fpreg", ++ "cpu_user_regs", ++ "xen_ia64_boot_param", ++ "ia64_tr_entry", ++ "vcpu_extra_regs", ++ "vcpu_guest_context", ++ "arch_vcpu_info", ++ "vcpu_time_info", ++ "vcpu_info", ++ "arch_shared_info", ++ "shared_info" ]; ++ ++defines = [ "__i386__", ++ "__x86_64__", ++ ++ "FLAT_RING1_CS", ++ "FLAT_RING1_DS", ++ "FLAT_RING1_SS", ++ ++ "FLAT_RING3_CS64", ++ "FLAT_RING3_DS64", ++ "FLAT_RING3_SS64", ++ "FLAT_KERNEL_CS64", ++ "FLAT_KERNEL_DS64", ++ "FLAT_KERNEL_SS64", ++ ++ "FLAT_KERNEL_CS", ++ "FLAT_KERNEL_DS", ++ "FLAT_KERNEL_SS", ++ ++ # x86_{32,64} ++ "_VGCF_i387_valid", ++ "VGCF_i387_valid", ++ "_VGCF_in_kernel", ++ "VGCF_in_kernel", ++ "_VGCF_failsafe_disables_events", ++ "VGCF_failsafe_disables_events", ++ "_VGCF_syscall_disables_events", ++ "VGCF_syscall_disables_events", ++ "_VGCF_online", ++ "VGCF_online", ++ ++ # ia64 ++ "VGCF_EXTRA_REGS", ++ ++ # all archs ++ "xen_pfn_to_cr3", ++ "MAX_VIRT_CPUS", ++ "MAX_GUEST_CMDLINE" ]; ++ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/grant_table.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/grant_table.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,399 @@ ++/****************************************************************************** ++ * grant_table.h ++ * ++ * Interface for granting foreign access to page frames, and receiving ++ * page-ownership transfers. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004, K A Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_GRANT_TABLE_H__ ++#define __XEN_PUBLIC_GRANT_TABLE_H__ ++ ++ ++/*********************************** ++ * GRANT TABLE REPRESENTATION ++ */ ++ ++/* Some rough guidelines on accessing and updating grant-table entries ++ * in a concurrency-safe manner. For more information, Linux contains a ++ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c). ++ * ++ * NB. WMB is a no-op on current-generation x86 processors. However, a ++ * compiler barrier will still be required. ++ * ++ * Introducing a valid entry into the grant table: ++ * 1. Write ent->domid. ++ * 2. Write ent->frame: ++ * GTF_permit_access: Frame to which access is permitted. ++ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new ++ * frame, or zero if none. ++ * 3. Write memory barrier (WMB). ++ * 4. Write ent->flags, inc. valid type. ++ * ++ * Invalidating an unused GTF_permit_access entry: ++ * 1. flags = ent->flags. ++ * 2. Observe that !(flags & (GTF_reading|GTF_writing)). ++ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0). ++ * NB. No need for WMB as reuse of entry is control-dependent on success of ++ * step 3, and all architectures guarantee ordering of ctrl-dep writes. ++ * ++ * Invalidating an in-use GTF_permit_access entry: ++ * This cannot be done directly. Request assistance from the domain controller ++ * which can set a timeout on the use of a grant entry and take necessary ++ * action. (NB. This is not yet implemented!). ++ * ++ * Invalidating an unused GTF_accept_transfer entry: ++ * 1. flags = ent->flags. ++ * 2. Observe that !(flags & GTF_transfer_committed). [*] ++ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0). ++ * NB. No need for WMB as reuse of entry is control-dependent on success of ++ * step 3, and all architectures guarantee ordering of ctrl-dep writes. ++ * [*] If GTF_transfer_committed is set then the grant entry is 'committed'. ++ * The guest must /not/ modify the grant entry until the address of the ++ * transferred frame is written. It is safe for the guest to spin waiting ++ * for this to occur (detect by observing GTF_transfer_completed in ++ * ent->flags). ++ * ++ * Invalidating a committed GTF_accept_transfer entry: ++ * 1. Wait for (ent->flags & GTF_transfer_completed). ++ * ++ * Changing a GTF_permit_access from writable to read-only: ++ * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing. ++ * ++ * Changing a GTF_permit_access from read-only to writable: ++ * Use SMP-safe bit-setting instruction. ++ */ ++ ++/* ++ * A grant table comprises a packed array of grant entries in one or more ++ * page frames shared between Xen and a guest. ++ * [XEN]: This field is written by Xen and read by the sharing guest. ++ * [GST]: This field is written by the guest and read by Xen. ++ */ ++struct grant_entry { ++ /* GTF_xxx: various type and flag information. [XEN,GST] */ ++ uint16_t flags; ++ /* The domain being granted foreign privileges. [GST] */ ++ domid_t domid; ++ /* ++ * GTF_permit_access: Frame that @domid is allowed to map and access. [GST] ++ * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN] ++ */ ++ uint32_t frame; ++}; ++typedef struct grant_entry grant_entry_t; ++ ++/* ++ * Type of grant entry. ++ * GTF_invalid: This grant entry grants no privileges. ++ * GTF_permit_access: Allow @domid to map/access @frame. ++ * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame ++ * to this guest. Xen writes the page number to @frame. ++ */ ++#define GTF_invalid (0U<<0) ++#define GTF_permit_access (1U<<0) ++#define GTF_accept_transfer (2U<<0) ++#define GTF_type_mask (3U<<0) ++ ++/* ++ * Subflags for GTF_permit_access. ++ * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST] ++ * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN] ++ * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN] ++ */ ++#define _GTF_readonly (2) ++#define GTF_readonly (1U<<_GTF_readonly) ++#define _GTF_reading (3) ++#define GTF_reading (1U<<_GTF_reading) ++#define _GTF_writing (4) ++#define GTF_writing (1U<<_GTF_writing) ++ ++/* ++ * Subflags for GTF_accept_transfer: ++ * GTF_transfer_committed: Xen sets this flag to indicate that it is committed ++ * to transferring ownership of a page frame. When a guest sees this flag ++ * it must /not/ modify the grant entry until GTF_transfer_completed is ++ * set by Xen. ++ * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag ++ * after reading GTF_transfer_committed. Xen will always write the frame ++ * address, followed by ORing this flag, in a timely manner. ++ */ ++#define _GTF_transfer_committed (2) ++#define GTF_transfer_committed (1U<<_GTF_transfer_committed) ++#define _GTF_transfer_completed (3) ++#define GTF_transfer_completed (1U<<_GTF_transfer_completed) ++ ++ ++/*********************************** ++ * GRANT TABLE QUERIES AND USES ++ */ ++ ++/* ++ * Reference to a grant entry in a specified domain's grant table. ++ */ ++typedef uint32_t grant_ref_t; ++ ++/* ++ * Handle to track a mapping created via a grant reference. ++ */ ++typedef uint32_t grant_handle_t; ++ ++/* ++ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access ++ * by devices and/or host CPUs. If successful, <handle> is a tracking number ++ * that must be presented later to destroy the mapping(s). On error, <handle> ++ * is a negative status code. ++ * NOTES: ++ * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address ++ * via which I/O devices may access the granted frame. ++ * 2. If GNTMAP_host_map is specified then a mapping will be added at ++ * either a host virtual address in the current address space, or at ++ * a PTE at the specified machine address. The type of mapping to ++ * perform is selected through the GNTMAP_contains_pte flag, and the ++ * address is specified in <host_addr>. ++ * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a ++ * host mapping is destroyed by other means then it is *NOT* guaranteed ++ * to be accounted to the correct grant reference! ++ */ ++#define GNTTABOP_map_grant_ref 0 ++struct gnttab_map_grant_ref { ++ /* IN parameters. */ ++ uint64_t host_addr; ++ uint32_t flags; /* GNTMAP_* */ ++ grant_ref_t ref; ++ domid_t dom; ++ /* OUT parameters. */ ++ int16_t status; /* GNTST_* */ ++ grant_handle_t handle; ++ uint64_t dev_bus_addr; ++}; ++typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_map_grant_ref_t); ++ ++/* ++ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings ++ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that ++ * field is ignored. If non-zero, they must refer to a device/host mapping ++ * that is tracked by <handle> ++ * NOTES: ++ * 1. The call may fail in an undefined manner if either mapping is not ++ * tracked by <handle>. ++ * 3. After executing a batch of unmaps, it is guaranteed that no stale ++ * mappings will remain in the device or host TLBs. ++ */ ++#define GNTTABOP_unmap_grant_ref 1 ++struct gnttab_unmap_grant_ref { ++ /* IN parameters. */ ++ uint64_t host_addr; ++ uint64_t dev_bus_addr; ++ grant_handle_t handle; ++ /* OUT parameters. */ ++ int16_t status; /* GNTST_* */ ++}; ++typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t); ++ ++/* ++ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least ++ * <nr_frames> pages. The frame addresses are written to the <frame_list>. ++ * Only <nr_frames> addresses are written, even if the table is larger. ++ * NOTES: ++ * 1. <dom> may be specified as DOMID_SELF. ++ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. ++ * 3. Xen may not support more than a single grant-table page per domain. ++ */ ++#define GNTTABOP_setup_table 2 ++struct gnttab_setup_table { ++ /* IN parameters. */ ++ domid_t dom; ++ uint32_t nr_frames; ++ /* OUT parameters. */ ++ int16_t status; /* GNTST_* */ ++ XEN_GUEST_HANDLE(ulong) frame_list; ++}; ++typedef struct gnttab_setup_table gnttab_setup_table_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t); ++ ++/* ++ * GNTTABOP_dump_table: Dump the contents of the grant table to the ++ * xen console. Debugging use only. ++ */ ++#define GNTTABOP_dump_table 3 ++struct gnttab_dump_table { ++ /* IN parameters. */ ++ domid_t dom; ++ /* OUT parameters. */ ++ int16_t status; /* GNTST_* */ ++}; ++typedef struct gnttab_dump_table gnttab_dump_table_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_dump_table_t); ++ ++/* ++ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The ++ * foreign domain has previously registered its interest in the transfer via ++ * <domid, ref>. ++ * ++ * Note that, even if the transfer fails, the specified page no longer belongs ++ * to the calling domain *unless* the error is GNTST_bad_page. ++ */ ++#define GNTTABOP_transfer 4 ++struct gnttab_transfer { ++ /* IN parameters. */ ++ xen_pfn_t mfn; ++ domid_t domid; ++ grant_ref_t ref; ++ /* OUT parameters. */ ++ int16_t status; ++}; ++typedef struct gnttab_transfer gnttab_transfer_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t); ++ ++ ++/* ++ * GNTTABOP_copy: Hypervisor based copy ++ * source and destinations can be eithers MFNs or, for foreign domains, ++ * grant references. the foreign domain has to grant read/write access ++ * in its grant table. ++ * ++ * The flags specify what type source and destinations are (either MFN ++ * or grant reference). ++ * ++ * Note that this can also be used to copy data between two domains ++ * via a third party if the source and destination domains had previously ++ * grant appropriate access to their pages to the third party. ++ * ++ * source_offset specifies an offset in the source frame, dest_offset ++ * the offset in the target frame and len specifies the number of ++ * bytes to be copied. ++ */ ++ ++#define _GNTCOPY_source_gref (0) ++#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref) ++#define _GNTCOPY_dest_gref (1) ++#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref) ++ ++#define GNTTABOP_copy 5 ++typedef struct gnttab_copy { ++ /* IN parameters. */ ++ struct { ++ union { ++ grant_ref_t ref; ++ xen_pfn_t gmfn; ++ } u; ++ domid_t domid; ++ uint16_t offset; ++ } source, dest; ++ uint16_t len; ++ uint16_t flags; /* GNTCOPY_* */ ++ /* OUT parameters. */ ++ int16_t status; ++} gnttab_copy_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t); ++ ++/* ++ * GNTTABOP_query_size: Query the current and maximum sizes of the shared ++ * grant table. ++ * NOTES: ++ * 1. <dom> may be specified as DOMID_SELF. ++ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. ++ */ ++#define GNTTABOP_query_size 6 ++struct gnttab_query_size { ++ /* IN parameters. */ ++ domid_t dom; ++ /* OUT parameters. */ ++ uint32_t nr_frames; ++ uint32_t max_nr_frames; ++ int16_t status; /* GNTST_* */ ++}; ++typedef struct gnttab_query_size gnttab_query_size_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t); ++ ++ ++/* ++ * Bitfield values for update_pin_status.flags. ++ */ ++ /* Map the grant entry for access by I/O devices. */ ++#define _GNTMAP_device_map (0) ++#define GNTMAP_device_map (1<<_GNTMAP_device_map) ++ /* Map the grant entry for access by host CPUs. */ ++#define _GNTMAP_host_map (1) ++#define GNTMAP_host_map (1<<_GNTMAP_host_map) ++ /* Accesses to the granted frame will be restricted to read-only access. */ ++#define _GNTMAP_readonly (2) ++#define GNTMAP_readonly (1<<_GNTMAP_readonly) ++ /* ++ * GNTMAP_host_map subflag: ++ * 0 => The host mapping is usable only by the guest OS. ++ * 1 => The host mapping is usable by guest OS + current application. ++ */ ++#define _GNTMAP_application_map (3) ++#define GNTMAP_application_map (1<<_GNTMAP_application_map) ++ ++ /* ++ * GNTMAP_contains_pte subflag: ++ * 0 => This map request contains a host virtual address. ++ * 1 => This map request contains the machine addess of the PTE to update. ++ */ ++#define _GNTMAP_contains_pte (4) ++#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte) ++ ++/* ++ * Values for error status returns. All errors are -ve. ++ */ ++#define GNTST_okay (0) /* Normal return. */ ++#define GNTST_general_error (-1) /* General undefined error. */ ++#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */ ++#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */ ++#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */ ++#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */ ++#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/ ++#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ ++#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ ++#define GNTST_bad_page (-9) /* Specified page was invalid for op. */ ++#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */ ++ ++#define GNTTABOP_error_msgs { \ ++ "okay", \ ++ "undefined error", \ ++ "unrecognised domain id", \ ++ "invalid grant reference", \ ++ "invalid mapping handle", \ ++ "invalid virtual address", \ ++ "invalid device address", \ ++ "no spare translation slot in the I/O MMU", \ ++ "permission denied", \ ++ "bad page", \ ++ "copy arguments cross page boundary" \ ++} ++ ++#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/e820.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/e820.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,47 @@ ++ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_HVM_E820_H__ ++#define __XEN_PUBLIC_HVM_E820_H__ ++ ++/* PC BIOS standard E820 types. */ ++#define E820_RAM 1 ++#define E820_RESERVED 2 ++#define E820_ACPI 3 ++#define E820_NVS 4 ++ ++/* E820 location in HVM virtual address space. */ ++#define E820_MAP_PAGE 0x00090000 ++#define E820_MAP_NR_OFFSET 0x000001E8 ++#define E820_MAP_OFFSET 0x000002D0 ++ ++struct e820entry { ++ uint64_t addr; ++ uint64_t size; ++ uint32_t type; ++} __attribute__((packed)); ++ ++#define HVM_BELOW_4G_RAM_END 0xF0000000 ++ ++#define HVM_BELOW_4G_MMIO_START HVM_BELOW_4G_RAM_END ++#define HVM_BELOW_4G_MMIO_LENGTH ((1ULL << 32) - HVM_BELOW_4G_MMIO_START) ++ ++#endif /* __XEN_PUBLIC_HVM_E820_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/hvm_info_table.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/hvm_info_table.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,41 @@ ++/****************************************************************************** ++ * hvm/hvm_info_table.h ++ * ++ * HVM parameter and information table, written into guest memory map. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ ++#define __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ ++ ++#define HVM_INFO_PFN 0x09F ++#define HVM_INFO_OFFSET 0x800 ++#define HVM_INFO_PADDR ((HVM_INFO_PFN << 12) + HVM_INFO_OFFSET) ++ ++struct hvm_info_table { ++ char signature[8]; /* "HVM INFO" */ ++ uint32_t length; ++ uint8_t checksum; ++ uint8_t acpi_enabled; ++ uint8_t apic_mode; ++ uint32_t nr_vcpus; ++}; ++ ++#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/hvm_op.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/hvm_op.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,73 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_HVM_HVM_OP_H__ ++#define __XEN_PUBLIC_HVM_HVM_OP_H__ ++ ++/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */ ++#define HVMOP_set_param 0 ++#define HVMOP_get_param 1 ++struct xen_hvm_param { ++ domid_t domid; /* IN */ ++ uint32_t index; /* IN */ ++ uint64_t value; /* IN/OUT */ ++}; ++typedef struct xen_hvm_param xen_hvm_param_t; ++DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t); ++ ++/* Set the logical level of one of a domain's PCI INTx wires. */ ++#define HVMOP_set_pci_intx_level 2 ++struct xen_hvm_set_pci_intx_level { ++ /* Domain to be updated. */ ++ domid_t domid; ++ /* PCI INTx identification in PCI topology (domain:bus:device:intx). */ ++ uint8_t domain, bus, device, intx; ++ /* Assertion level (0 = unasserted, 1 = asserted). */ ++ uint8_t level; ++}; ++typedef struct xen_hvm_set_pci_intx_level xen_hvm_set_pci_intx_level_t; ++DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t); ++ ++/* Set the logical level of one of a domain's ISA IRQ wires. */ ++#define HVMOP_set_isa_irq_level 3 ++struct xen_hvm_set_isa_irq_level { ++ /* Domain to be updated. */ ++ domid_t domid; ++ /* ISA device identification, by ISA IRQ (0-15). */ ++ uint8_t isa_irq; ++ /* Assertion level (0 = unasserted, 1 = asserted). */ ++ uint8_t level; ++}; ++typedef struct xen_hvm_set_isa_irq_level xen_hvm_set_isa_irq_level_t; ++DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_isa_irq_level_t); ++ ++#define HVMOP_set_pci_link_route 4 ++struct xen_hvm_set_pci_link_route { ++ /* Domain to be updated. */ ++ domid_t domid; ++ /* PCI link identifier (0-3). */ ++ uint8_t link; ++ /* ISA IRQ (1-15), or 0 (disable link). */ ++ uint8_t isa_irq; ++}; ++typedef struct xen_hvm_set_pci_link_route xen_hvm_set_pci_link_route_t; ++DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t); ++ ++#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/ioreq.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/ioreq.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,122 @@ ++/* ++ * ioreq.h: I/O request definitions for device models ++ * Copyright (c) 2004, Intel Corporation. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _IOREQ_H_ ++#define _IOREQ_H_ ++ ++#define IOREQ_READ 1 ++#define IOREQ_WRITE 0 ++ ++#define STATE_IOREQ_NONE 0 ++#define STATE_IOREQ_READY 1 ++#define STATE_IOREQ_INPROCESS 2 ++#define STATE_IORESP_READY 3 ++ ++#define IOREQ_TYPE_PIO 0 /* pio */ ++#define IOREQ_TYPE_COPY 1 /* mmio ops */ ++#define IOREQ_TYPE_AND 2 ++#define IOREQ_TYPE_OR 3 ++#define IOREQ_TYPE_XOR 4 ++#define IOREQ_TYPE_XCHG 5 ++#define IOREQ_TYPE_ADD 6 ++#define IOREQ_TYPE_TIMEOFFSET 7 ++#define IOREQ_TYPE_INVALIDATE 8 /* mapcache */ ++#define IOREQ_TYPE_SUB 9 ++ ++/* ++ * VMExit dispatcher should cooperate with instruction decoder to ++ * prepare this structure and notify service OS and DM by sending ++ * virq ++ */ ++struct ioreq { ++ uint64_t addr; /* physical address */ ++ uint64_t size; /* size in bytes */ ++ uint64_t count; /* for rep prefixes */ ++ uint64_t data; /* data (or paddr of data) */ ++ uint8_t state:4; ++ uint8_t data_is_ptr:1; /* if 1, data above is the guest paddr ++ * of the real data to use. */ ++ uint8_t dir:1; /* 1=read, 0=write */ ++ uint8_t df:1; ++ uint8_t type; /* I/O type */ ++ uint8_t _pad0[6]; ++ uint64_t io_count; /* How many IO done on a vcpu */ ++}; ++typedef struct ioreq ioreq_t; ++ ++struct vcpu_iodata { ++ struct ioreq vp_ioreq; ++ /* Event channel port, used for notifications to/from the device model. */ ++ uint32_t vp_eport; ++ uint32_t _pad0; ++}; ++typedef struct vcpu_iodata vcpu_iodata_t; ++ ++struct shared_iopage { ++ struct vcpu_iodata vcpu_iodata[1]; ++}; ++typedef struct shared_iopage shared_iopage_t; ++ ++#define IOREQ_BUFFER_SLOT_NUM 80 ++struct buffered_iopage { ++ unsigned int read_pointer; ++ unsigned int write_pointer; ++ ioreq_t ioreq[IOREQ_BUFFER_SLOT_NUM]; ++}; /* NB. Size of this structure must be no greater than one page. */ ++typedef struct buffered_iopage buffered_iopage_t; ++ ++#if defined(__ia64__) ++struct pio_buffer { ++ uint32_t page_offset; ++ uint32_t pointer; ++ uint32_t data_end; ++ uint32_t buf_size; ++ void *opaque; ++}; ++ ++#define PIO_BUFFER_IDE_PRIMARY 0 /* I/O port = 0x1F0 */ ++#define PIO_BUFFER_IDE_SECONDARY 1 /* I/O port = 0x170 */ ++#define PIO_BUFFER_ENTRY_NUM 2 ++struct buffered_piopage { ++ struct pio_buffer pio[PIO_BUFFER_ENTRY_NUM]; ++ uint8_t buffer[1]; ++}; ++#endif /* defined(__ia64__) */ ++ ++#if defined(__i386__) || defined(__x86_64__) ++#define ACPI_PM1A_EVT_BLK_ADDRESS 0x0000000000001f40 ++#define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04) ++#define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08) ++#endif /* defined(__i386__) || defined(__x86_64__) */ ++ ++#endif /* _IOREQ_H_ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/params.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/params.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,55 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_HVM_PARAMS_H__ ++#define __XEN_PUBLIC_HVM_PARAMS_H__ ++ ++#include "hvm_op.h" ++ ++/* ++ * Parameter space for HVMOP_{set,get}_param. ++ */ ++ ++/* ++ * How should CPU0 event-channel notifications be delivered? ++ * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt). ++ * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows: ++ * Domain = val[47:32], Bus = val[31:16], ++ * DevFn = val[15: 8], IntX = val[ 1: 0] ++ * If val == 0 then CPU0 event-channel notifications are not delivered. ++ */ ++#define HVM_PARAM_CALLBACK_IRQ 0 ++ ++/* ++ * These are not used by Xen. They are here for convenience of HVM-guest ++ * xenbus implementations. ++ */ ++#define HVM_PARAM_STORE_PFN 1 ++#define HVM_PARAM_STORE_EVTCHN 2 ++ ++#define HVM_PARAM_PAE_ENABLED 4 ++ ++#define HVM_PARAM_IOREQ_PFN 5 ++ ++#define HVM_PARAM_BUFIOREQ_PFN 6 ++ ++#define HVM_NR_PARAMS 7 ++ ++#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/save.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/save.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,462 @@ ++/* ++ * hvm/save.h ++ * ++ * Structure definitions for HVM state that is held by Xen and must ++ * be saved along with the domain's memory and device-model state. ++ * ++ * ++ * Copyright (c) 2007 XenSource Ltd. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_HVM_SAVE_H__ ++#define __XEN_PUBLIC_HVM_SAVE_H__ ++ ++/* ++ * Structures in this header *must* have the same layout in 32bit ++ * and 64bit environments: this means that all fields must be explicitly ++ * sized types and aligned to their sizes, and the structs must be ++ * a multiple of eight bytes long. ++ * ++ * Only the state necessary for saving and restoring (i.e. fields ++ * that are analogous to actual hardware state) should go in this file. ++ * Internal mechanisms should be kept in Xen-private headers. ++ */ ++ ++/* ++ * Each entry is preceded by a descriptor giving its type and length ++ */ ++struct hvm_save_descriptor { ++ uint16_t typecode; /* Used to demux the various types below */ ++ uint16_t instance; /* Further demux within a type */ ++ uint32_t length; /* In bytes, *not* including this descriptor */ ++}; ++ ++ ++/* ++ * Each entry has a datatype associated with it: for example, the CPU state ++ * is saved as a HVM_SAVE_TYPE(CPU), which has HVM_SAVE_LENGTH(CPU), ++ * and is identified by a descriptor with typecode HVM_SAVE_CODE(CPU). ++ * DECLARE_HVM_SAVE_TYPE binds these things together with some type-system ++ * ugliness. ++ */ ++ ++#define DECLARE_HVM_SAVE_TYPE(_x, _code, _type) \ ++ struct __HVM_SAVE_TYPE_##_x { _type t; char c[_code]; } ++ ++#define HVM_SAVE_TYPE(_x) typeof (((struct __HVM_SAVE_TYPE_##_x *)(0))->t) ++#define HVM_SAVE_LENGTH(_x) (sizeof (HVM_SAVE_TYPE(_x))) ++#define HVM_SAVE_CODE(_x) (sizeof (((struct __HVM_SAVE_TYPE_##_x *)(0))->c)) ++ ++ ++/* ++ * Save/restore header: general info about the save file. ++ */ ++ ++#define HVM_FILE_MAGIC 0x54381286 ++#define HVM_FILE_VERSION 0x00000001 ++ ++struct hvm_save_header { ++ uint32_t magic; /* Must be HVM_FILE_MAGIC */ ++ uint32_t version; /* File format version */ ++ uint64_t changeset; /* Version of Xen that saved this file */ ++ uint32_t cpuid; /* CPUID[0x01][%eax] on the saving machine */ ++ uint32_t pad0; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(HEADER, 1, struct hvm_save_header); ++ ++ ++/* ++ * Processor ++ */ ++ ++struct hvm_hw_cpu { ++ uint8_t fpu_regs[512]; ++ ++ uint64_t rax; ++ uint64_t rbx; ++ uint64_t rcx; ++ uint64_t rdx; ++ uint64_t rbp; ++ uint64_t rsi; ++ uint64_t rdi; ++ uint64_t rsp; ++ uint64_t r8; ++ uint64_t r9; ++ uint64_t r10; ++ uint64_t r11; ++ uint64_t r12; ++ uint64_t r13; ++ uint64_t r14; ++ uint64_t r15; ++ ++ uint64_t rip; ++ uint64_t rflags; ++ ++ uint64_t cr0; ++ uint64_t cr2; ++ uint64_t cr3; ++ uint64_t cr4; ++ ++ uint64_t dr0; ++ uint64_t dr1; ++ uint64_t dr2; ++ uint64_t dr3; ++ uint64_t dr6; ++ uint64_t dr7; ++ ++ uint32_t cs_sel; ++ uint32_t ds_sel; ++ uint32_t es_sel; ++ uint32_t fs_sel; ++ uint32_t gs_sel; ++ uint32_t ss_sel; ++ uint32_t tr_sel; ++ uint32_t ldtr_sel; ++ ++ uint32_t cs_limit; ++ uint32_t ds_limit; ++ uint32_t es_limit; ++ uint32_t fs_limit; ++ uint32_t gs_limit; ++ uint32_t ss_limit; ++ uint32_t tr_limit; ++ uint32_t ldtr_limit; ++ uint32_t idtr_limit; ++ uint32_t gdtr_limit; ++ ++ uint64_t cs_base; ++ uint64_t ds_base; ++ uint64_t es_base; ++ uint64_t fs_base; ++ uint64_t gs_base; ++ uint64_t ss_base; ++ uint64_t tr_base; ++ uint64_t ldtr_base; ++ uint64_t idtr_base; ++ uint64_t gdtr_base; ++ ++ uint32_t cs_arbytes; ++ uint32_t ds_arbytes; ++ uint32_t es_arbytes; ++ uint32_t fs_arbytes; ++ uint32_t gs_arbytes; ++ uint32_t ss_arbytes; ++ uint32_t tr_arbytes; ++ uint32_t ldtr_arbytes; ++ ++ uint32_t sysenter_cs; ++ uint32_t padding0; ++ ++ uint64_t sysenter_esp; ++ uint64_t sysenter_eip; ++ ++ /* msr for em64t */ ++ uint64_t shadow_gs; ++ ++ /* msr content saved/restored. */ ++ uint64_t msr_flags; ++ uint64_t msr_lstar; ++ uint64_t msr_star; ++ uint64_t msr_cstar; ++ uint64_t msr_syscall_mask; ++ uint64_t msr_efer; ++ ++ /* guest's idea of what rdtsc() would return */ ++ uint64_t tsc; ++ ++ /* pending event, if any */ ++ union { ++ uint32_t pending_event; ++ struct { ++ uint8_t pending_vector:8; ++ uint8_t pending_type:3; ++ uint8_t pending_error_valid:1; ++ uint32_t pending_reserved:19; ++ uint8_t pending_valid:1; ++ }; ++ }; ++ /* error code for pending event */ ++ uint32_t error_code; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(CPU, 2, struct hvm_hw_cpu); ++ ++ ++/* ++ * PIC ++ */ ++ ++struct hvm_hw_vpic { ++ /* IR line bitmasks. */ ++ uint8_t irr; ++ uint8_t imr; ++ uint8_t isr; ++ ++ /* Line IRx maps to IRQ irq_base+x */ ++ uint8_t irq_base; ++ ++ /* ++ * Where are we in ICW2-4 initialisation (0 means no init in progress)? ++ * Bits 0-1 (=x): Next write at A=1 sets ICW(x+1). ++ * Bit 2: ICW1.IC4 (1 == ICW4 included in init sequence) ++ * Bit 3: ICW1.SNGL (0 == ICW3 included in init sequence) ++ */ ++ uint8_t init_state:4; ++ ++ /* IR line with highest priority. */ ++ uint8_t priority_add:4; ++ ++ /* Reads from A=0 obtain ISR or IRR? */ ++ uint8_t readsel_isr:1; ++ ++ /* Reads perform a polling read? */ ++ uint8_t poll:1; ++ ++ /* Automatically clear IRQs from the ISR during INTA? */ ++ uint8_t auto_eoi:1; ++ ++ /* Automatically rotate IRQ priorities during AEOI? */ ++ uint8_t rotate_on_auto_eoi:1; ++ ++ /* Exclude slave inputs when considering in-service IRQs? */ ++ uint8_t special_fully_nested_mode:1; ++ ++ /* Special mask mode excludes masked IRs from AEOI and priority checks. */ ++ uint8_t special_mask_mode:1; ++ ++ /* Is this a master PIC or slave PIC? (NB. This is not programmable.) */ ++ uint8_t is_master:1; ++ ++ /* Edge/trigger selection. */ ++ uint8_t elcr; ++ ++ /* Virtual INT output. */ ++ uint8_t int_output; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(PIC, 3, struct hvm_hw_vpic); ++ ++ ++/* ++ * IO-APIC ++ */ ++ ++#ifdef __ia64__ ++#define VIOAPIC_IS_IOSAPIC 1 ++#define VIOAPIC_NUM_PINS 24 ++#else ++#define VIOAPIC_NUM_PINS 48 /* 16 ISA IRQs, 32 non-legacy PCI IRQS. */ ++#endif ++ ++struct hvm_hw_vioapic { ++ uint64_t base_address; ++ uint32_t ioregsel; ++ uint32_t id; ++ union vioapic_redir_entry ++ { ++ uint64_t bits; ++ struct { ++ uint8_t vector; ++ uint8_t delivery_mode:3; ++ uint8_t dest_mode:1; ++ uint8_t delivery_status:1; ++ uint8_t polarity:1; ++ uint8_t remote_irr:1; ++ uint8_t trig_mode:1; ++ uint8_t mask:1; ++ uint8_t reserve:7; ++#if !VIOAPIC_IS_IOSAPIC ++ uint8_t reserved[4]; ++ uint8_t dest_id; ++#else ++ uint8_t reserved[3]; ++ uint16_t dest_id; ++#endif ++ } fields; ++ } redirtbl[VIOAPIC_NUM_PINS]; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(IOAPIC, 4, struct hvm_hw_vioapic); ++ ++ ++/* ++ * LAPIC ++ */ ++ ++struct hvm_hw_lapic { ++ uint64_t apic_base_msr; ++ uint32_t disabled; /* VLAPIC_xx_DISABLED */ ++ uint32_t timer_divisor; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(LAPIC, 5, struct hvm_hw_lapic); ++ ++struct hvm_hw_lapic_regs { ++ /* A 4k page of register state */ ++ uint8_t data[0x400]; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(LAPIC_REGS, 6, struct hvm_hw_lapic_regs); ++ ++ ++/* ++ * IRQs ++ */ ++ ++struct hvm_hw_pci_irqs { ++ /* ++ * Virtual interrupt wires for a single PCI bus. ++ * Indexed by: device*4 + INTx#. ++ */ ++ union { ++ DECLARE_BITMAP(i, 32*4); ++ uint64_t pad[2]; ++ }; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(PCI_IRQ, 7, struct hvm_hw_pci_irqs); ++ ++struct hvm_hw_isa_irqs { ++ /* ++ * Virtual interrupt wires for ISA devices. ++ * Indexed by ISA IRQ (assumes no ISA-device IRQ sharing). ++ */ ++ union { ++ DECLARE_BITMAP(i, 16); ++ uint64_t pad[1]; ++ }; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(ISA_IRQ, 8, struct hvm_hw_isa_irqs); ++ ++struct hvm_hw_pci_link { ++ /* ++ * PCI-ISA interrupt router. ++ * Each PCI <device:INTx#> is 'wire-ORed' into one of four links using ++ * the traditional 'barber's pole' mapping ((device + INTx#) & 3). ++ * The router provides a programmable mapping from each link to a GSI. ++ */ ++ uint8_t route[4]; ++ uint8_t pad0[4]; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(PCI_LINK, 9, struct hvm_hw_pci_link); ++ ++/* ++ * PIT ++ */ ++ ++struct hvm_hw_pit { ++ struct hvm_hw_pit_channel { ++ uint32_t count; /* can be 65536 */ ++ uint16_t latched_count; ++ uint8_t count_latched; ++ uint8_t status_latched; ++ uint8_t status; ++ uint8_t read_state; ++ uint8_t write_state; ++ uint8_t write_latch; ++ uint8_t rw_mode; ++ uint8_t mode; ++ uint8_t bcd; /* not supported */ ++ uint8_t gate; /* timer start */ ++ } channels[3]; /* 3 x 16 bytes */ ++ uint32_t speaker_data_on; ++ uint32_t pad0; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(PIT, 10, struct hvm_hw_pit); ++ ++ ++/* ++ * RTC ++ */ ++ ++#define RTC_CMOS_SIZE 14 ++struct hvm_hw_rtc { ++ /* CMOS bytes */ ++ uint8_t cmos_data[RTC_CMOS_SIZE]; ++ /* Index register for 2-part operations */ ++ uint8_t cmos_index; ++ uint8_t pad0; ++}; ++ ++DECLARE_HVM_SAVE_TYPE(RTC, 11, struct hvm_hw_rtc); ++ ++ ++/* ++ * HPET ++ */ ++ ++#define HPET_TIMER_NUM 3 /* 3 timers supported now */ ++struct hvm_hw_hpet { ++ /* Memory-mapped, software visible registers */ ++ uint64_t capability; /* capabilities */ ++ uint64_t res0; /* reserved */ ++ uint64_t config; /* configuration */ ++ uint64_t res1; /* reserved */ ++ uint64_t isr; /* interrupt status reg */ ++ uint64_t res2[25]; /* reserved */ ++ uint64_t mc64; /* main counter */ ++ uint64_t res3; /* reserved */ ++ struct { /* timers */ ++ uint64_t config; /* configuration/cap */ ++ uint64_t cmp; /* comparator */ ++ uint64_t fsb; /* FSB route, not supported now */ ++ uint64_t res4; /* reserved */ ++ } timers[HPET_TIMER_NUM]; ++ uint64_t res5[4*(24-HPET_TIMER_NUM)]; /* reserved, up to 0x3ff */ ++ ++ /* Hidden register state */ ++ uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */ ++}; ++ ++DECLARE_HVM_SAVE_TYPE(HPET, 12, struct hvm_hw_hpet); ++ ++ ++/* ++ * PM timer ++ */ ++ ++struct hvm_hw_pmtimer { ++ uint32_t tmr_val; /* PM_TMR_BLK.TMR_VAL: 32bit free-running counter */ ++ uint16_t pm1a_sts; /* PM1a_EVT_BLK.PM1a_STS: status register */ ++ uint16_t pm1a_en; /* PM1a_EVT_BLK.PM1a_EN: enable register */ ++}; ++ ++DECLARE_HVM_SAVE_TYPE(PMTIMER, 13, struct hvm_hw_pmtimer); ++ ++/* ++ * Largest type-code in use ++ */ ++#define HVM_SAVE_CODE_MAX 13 ++ ++ ++/* ++ * The series of save records is teminated by a zero-type, zero-length ++ * descriptor. ++ */ ++ ++struct hvm_save_end {}; ++DECLARE_HVM_SAVE_TYPE(END, 0, struct hvm_save_end); ++ ++#endif /* __XEN_PUBLIC_HVM_SAVE_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/hvm/vmx_assist.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/hvm/vmx_assist.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,116 @@ ++/* ++ * vmx_assist.h: Context definitions for the VMXASSIST world switch. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Leendert van Doorn, leendert@watson.ibm.com ++ * Copyright (c) 2005, International Business Machines Corporation. ++ */ ++ ++#ifndef _VMX_ASSIST_H_ ++#define _VMX_ASSIST_H_ ++ ++#define VMXASSIST_BASE 0xD0000 ++#define VMXASSIST_MAGIC 0x17101966 ++#define VMXASSIST_MAGIC_OFFSET (VMXASSIST_BASE+8) ++ ++#define VMXASSIST_NEW_CONTEXT (VMXASSIST_BASE + 12) ++#define VMXASSIST_OLD_CONTEXT (VMXASSIST_NEW_CONTEXT + 4) ++ ++#ifndef __ASSEMBLY__ ++ ++union vmcs_arbytes { ++ struct arbyte_fields { ++ unsigned int seg_type : 4, ++ s : 1, ++ dpl : 2, ++ p : 1, ++ reserved0 : 4, ++ avl : 1, ++ reserved1 : 1, ++ default_ops_size: 1, ++ g : 1, ++ null_bit : 1, ++ reserved2 : 15; ++ } fields; ++ unsigned int bytes; ++}; ++ ++/* ++ * World switch state ++ */ ++struct vmx_assist_context { ++ uint32_t eip; /* execution pointer */ ++ uint32_t esp; /* stack pointer */ ++ uint32_t eflags; /* flags register */ ++ uint32_t cr0; ++ uint32_t cr3; /* page table directory */ ++ uint32_t cr4; ++ uint32_t idtr_limit; /* idt */ ++ uint32_t idtr_base; ++ uint32_t gdtr_limit; /* gdt */ ++ uint32_t gdtr_base; ++ uint32_t cs_sel; /* cs selector */ ++ uint32_t cs_limit; ++ uint32_t cs_base; ++ union vmcs_arbytes cs_arbytes; ++ uint32_t ds_sel; /* ds selector */ ++ uint32_t ds_limit; ++ uint32_t ds_base; ++ union vmcs_arbytes ds_arbytes; ++ uint32_t es_sel; /* es selector */ ++ uint32_t es_limit; ++ uint32_t es_base; ++ union vmcs_arbytes es_arbytes; ++ uint32_t ss_sel; /* ss selector */ ++ uint32_t ss_limit; ++ uint32_t ss_base; ++ union vmcs_arbytes ss_arbytes; ++ uint32_t fs_sel; /* fs selector */ ++ uint32_t fs_limit; ++ uint32_t fs_base; ++ union vmcs_arbytes fs_arbytes; ++ uint32_t gs_sel; /* gs selector */ ++ uint32_t gs_limit; ++ uint32_t gs_base; ++ union vmcs_arbytes gs_arbytes; ++ uint32_t tr_sel; /* task selector */ ++ uint32_t tr_limit; ++ uint32_t tr_base; ++ union vmcs_arbytes tr_arbytes; ++ uint32_t ldtr_sel; /* ldtr selector */ ++ uint32_t ldtr_limit; ++ uint32_t ldtr_base; ++ union vmcs_arbytes ldtr_arbytes; ++}; ++typedef struct vmx_assist_context vmx_assist_context_t; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* _VMX_ASSIST_H_ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/blkif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/blkif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,128 @@ ++/****************************************************************************** ++ * blkif.h ++ * ++ * Unified block-device I/O interface for Xen guest OSes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2003-2004, Keir Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_BLKIF_H__ ++#define __XEN_PUBLIC_IO_BLKIF_H__ ++ ++#include "ring.h" ++#include "../grant_table.h" ++ ++/* ++ * Front->back notifications: When enqueuing a new request, sending a ++ * notification can be made conditional on req_event (i.e., the generic ++ * hold-off mechanism provided by the ring macros). Backends must set ++ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()). ++ * ++ * Back->front notifications: When enqueuing a new response, sending a ++ * notification can be made conditional on rsp_event (i.e., the generic ++ * hold-off mechanism provided by the ring macros). Frontends must set ++ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()). ++ */ ++ ++#ifndef blkif_vdev_t ++#define blkif_vdev_t uint16_t ++#endif ++#define blkif_sector_t uint64_t ++ ++/* ++ * REQUEST CODES. ++ */ ++#define BLKIF_OP_READ 0 ++#define BLKIF_OP_WRITE 1 ++/* ++ * Recognised only if "feature-barrier" is present in backend xenbus info. ++ * The "feature_barrier" node contains a boolean indicating whether barrier ++ * requests are likely to succeed or fail. Either way, a barrier request ++ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by ++ * the underlying block-device hardware. The boolean simply indicates whether ++ * or not it is worthwhile for the frontend to attempt barrier requests. ++ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not* ++ * create the "feature-barrier" node! ++ */ ++#define BLKIF_OP_WRITE_BARRIER 2 ++ ++/* ++ * Maximum scatter/gather segments per request. ++ * This is carefully chosen so that sizeof(blkif_ring_t) <= PAGE_SIZE. ++ * NB. This could be 12 if the ring indexes weren't stored in the same page. ++ */ ++#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11 ++ ++struct blkif_request_segment { ++ grant_ref_t gref; /* reference to I/O buffer frame */ ++ /* @first_sect: first sector in frame to transfer (inclusive). */ ++ /* @last_sect: last sector in frame to transfer (inclusive). */ ++ uint8_t first_sect, last_sect; ++}; ++ ++struct blkif_request { ++ uint8_t operation; /* BLKIF_OP_??? */ ++ uint8_t nr_segments; /* number of segments */ ++ blkif_vdev_t handle; /* only for read/write requests */ ++ uint64_t id; /* private guest value, echoed in resp */ ++ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ ++ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++}; ++typedef struct blkif_request blkif_request_t; ++ ++struct blkif_response { ++ uint64_t id; /* copied from request */ ++ uint8_t operation; /* copied from request */ ++ int16_t status; /* BLKIF_RSP_??? */ ++}; ++typedef struct blkif_response blkif_response_t; ++ ++/* ++ * STATUS RETURN CODES. ++ */ ++ /* Operation not supported (only happens on barrier writes). */ ++#define BLKIF_RSP_EOPNOTSUPP -2 ++ /* Operation failed for some unspecified reason (-EIO). */ ++#define BLKIF_RSP_ERROR -1 ++ /* Operation completed successfully. */ ++#define BLKIF_RSP_OKAY 0 ++ ++/* ++ * Generate blkif ring structures and types. ++ */ ++ ++DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response); ++ ++#define VDISK_CDROM 0x1 ++#define VDISK_REMOVABLE 0x2 ++#define VDISK_READONLY 0x4 ++ ++#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/console.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/console.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,51 @@ ++/****************************************************************************** ++ * console.h ++ * ++ * Console I/O interface for Xen guest OSes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Keir Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_CONSOLE_H__ ++#define __XEN_PUBLIC_IO_CONSOLE_H__ ++ ++typedef uint32_t XENCONS_RING_IDX; ++ ++#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1)) ++ ++struct xencons_interface { ++ char in[1024]; ++ char out[2048]; ++ XENCONS_RING_IDX in_cons, in_prod; ++ XENCONS_RING_IDX out_cons, out_prod; ++}; ++ ++#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/fbif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/fbif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,138 @@ ++/* ++ * fbif.h -- Xen virtual frame buffer device ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> ++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_FBIF_H__ ++#define __XEN_PUBLIC_IO_FBIF_H__ ++ ++/* Out events (frontend -> backend) */ ++ ++/* ++ * Out events may be sent only when requested by backend, and receipt ++ * of an unknown out event is an error. ++ */ ++ ++/* Event type 1 currently not used */ ++/* ++ * Framebuffer update notification event ++ * Capable frontend sets feature-update in xenstore. ++ * Backend requests it by setting request-update in xenstore. ++ */ ++#define XENFB_TYPE_UPDATE 2 ++ ++struct xenfb_update ++{ ++ uint8_t type; /* XENFB_TYPE_UPDATE */ ++ int32_t x; /* source x */ ++ int32_t y; /* source y */ ++ int32_t width; /* rect width */ ++ int32_t height; /* rect height */ ++}; ++ ++#define XENFB_OUT_EVENT_SIZE 40 ++ ++union xenfb_out_event ++{ ++ uint8_t type; ++ struct xenfb_update update; ++ char pad[XENFB_OUT_EVENT_SIZE]; ++}; ++ ++/* In events (backend -> frontend) */ ++ ++/* ++ * Frontends should ignore unknown in events. ++ * No in events currently defined. ++ */ ++ ++#define XENFB_IN_EVENT_SIZE 40 ++ ++union xenfb_in_event ++{ ++ uint8_t type; ++ char pad[XENFB_IN_EVENT_SIZE]; ++}; ++ ++/* shared page */ ++ ++#define XENFB_IN_RING_SIZE 1024 ++#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) ++#define XENFB_IN_RING_OFFS 1024 ++#define XENFB_IN_RING(page) \ ++ ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) ++#define XENFB_IN_RING_REF(page, idx) \ ++ (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) ++ ++#define XENFB_OUT_RING_SIZE 2048 ++#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) ++#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) ++#define XENFB_OUT_RING(page) \ ++ ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) ++#define XENFB_OUT_RING_REF(page, idx) \ ++ (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) ++ ++struct xenfb_page ++{ ++ uint32_t in_cons, in_prod; ++ uint32_t out_cons, out_prod; ++ ++ int32_t width; /* the width of the framebuffer (in pixels) */ ++ int32_t height; /* the height of the framebuffer (in pixels) */ ++ uint32_t line_length; /* the length of a row of pixels (in bytes) */ ++ uint32_t mem_length; /* the length of the framebuffer (in bytes) */ ++ uint8_t depth; /* the depth of a pixel (in bits) */ ++ ++ /* ++ * Framebuffer page directory ++ * ++ * Each directory page holds PAGE_SIZE / sizeof(*pd) ++ * framebuffer pages, and can thus map up to PAGE_SIZE * ++ * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and ++ * sizeof(unsigned long) == 4, that's 4 Megs. Two directory ++ * pages should be enough for a while. ++ */ ++ unsigned long pd[2]; ++}; ++ ++/* ++ * Wart: xenkbd needs to know resolution. Put it here until a better ++ * solution is found, but don't leak it to the backend. ++ */ ++#ifdef __KERNEL__ ++#define XENFB_WIDTH 800 ++#define XENFB_HEIGHT 600 ++#define XENFB_DEPTH 32 ++#endif ++ ++#endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/kbdif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/kbdif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,130 @@ ++/* ++ * kbdif.h -- Xen virtual keyboard/mouse ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> ++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_KBDIF_H__ ++#define __XEN_PUBLIC_IO_KBDIF_H__ ++ ++/* In events (backend -> frontend) */ ++ ++/* ++ * Frontends should ignore unknown in events. ++ */ ++ ++/* Pointer movement event */ ++#define XENKBD_TYPE_MOTION 1 ++/* Event type 2 currently not used */ ++/* Key event (includes pointer buttons) */ ++#define XENKBD_TYPE_KEY 3 ++/* ++ * Pointer position event ++ * Capable backend sets feature-abs-pointer in xenstore. ++ * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting ++ * request-abs-update in xenstore. ++ */ ++#define XENKBD_TYPE_POS 4 ++ ++struct xenkbd_motion ++{ ++ uint8_t type; /* XENKBD_TYPE_MOTION */ ++ int32_t rel_x; /* relative X motion */ ++ int32_t rel_y; /* relative Y motion */ ++}; ++ ++struct xenkbd_key ++{ ++ uint8_t type; /* XENKBD_TYPE_KEY */ ++ uint8_t pressed; /* 1 if pressed; 0 otherwise */ ++ uint32_t keycode; /* KEY_* from linux/input.h */ ++}; ++ ++struct xenkbd_position ++{ ++ uint8_t type; /* XENKBD_TYPE_POS */ ++ int32_t abs_x; /* absolute X position (in FB pixels) */ ++ int32_t abs_y; /* absolute Y position (in FB pixels) */ ++}; ++ ++#define XENKBD_IN_EVENT_SIZE 40 ++ ++union xenkbd_in_event ++{ ++ uint8_t type; ++ struct xenkbd_motion motion; ++ struct xenkbd_key key; ++ struct xenkbd_position pos; ++ char pad[XENKBD_IN_EVENT_SIZE]; ++}; ++ ++/* Out events (frontend -> backend) */ ++ ++/* ++ * Out events may be sent only when requested by backend, and receipt ++ * of an unknown out event is an error. ++ * No out events currently defined. ++ */ ++ ++#define XENKBD_OUT_EVENT_SIZE 40 ++ ++union xenkbd_out_event ++{ ++ uint8_t type; ++ char pad[XENKBD_OUT_EVENT_SIZE]; ++}; ++ ++/* shared page */ ++ ++#define XENKBD_IN_RING_SIZE 2048 ++#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) ++#define XENKBD_IN_RING_OFFS 1024 ++#define XENKBD_IN_RING(page) \ ++ ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) ++#define XENKBD_IN_RING_REF(page, idx) \ ++ (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) ++ ++#define XENKBD_OUT_RING_SIZE 1024 ++#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) ++#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) ++#define XENKBD_OUT_RING(page) \ ++ ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) ++#define XENKBD_OUT_RING_REF(page, idx) \ ++ (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) ++ ++struct xenkbd_page ++{ ++ uint32_t in_cons, in_prod; ++ uint32_t out_cons, out_prod; ++}; ++ ++#endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/netif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/netif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,184 @@ ++/****************************************************************************** ++ * netif.h ++ * ++ * Unified network-device I/O interface for Xen guest OSes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2003-2004, Keir Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_NETIF_H__ ++#define __XEN_PUBLIC_IO_NETIF_H__ ++ ++#include "ring.h" ++#include "../grant_table.h" ++ ++/* ++ * Notifications after enqueuing any type of message should be conditional on ++ * the appropriate req_event or rsp_event field in the shared ring. ++ * If the client sends notification for rx requests then it should specify ++ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume ++ * that it cannot safely queue packets (as it may not be kicked to send them). ++ */ ++ ++/* ++ * This is the 'wire' format for packets: ++ * Request 1: netif_tx_request -- NETTXF_* (any flags) ++ * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info) ++ * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE) ++ * Request 4: netif_tx_request -- NETTXF_more_data ++ * Request 5: netif_tx_request -- NETTXF_more_data ++ * ... ++ * Request N: netif_tx_request -- 0 ++ */ ++ ++/* Protocol checksum field is blank in the packet (hardware offload)? */ ++#define _NETTXF_csum_blank (0) ++#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank) ++ ++/* Packet data has been validated against protocol checksum. */ ++#define _NETTXF_data_validated (1) ++#define NETTXF_data_validated (1U<<_NETTXF_data_validated) ++ ++/* Packet continues in the next request descriptor. */ ++#define _NETTXF_more_data (2) ++#define NETTXF_more_data (1U<<_NETTXF_more_data) ++ ++/* Packet to be followed by extra descriptor(s). */ ++#define _NETTXF_extra_info (3) ++#define NETTXF_extra_info (1U<<_NETTXF_extra_info) ++ ++struct netif_tx_request { ++ grant_ref_t gref; /* Reference to buffer page */ ++ uint16_t offset; /* Offset within buffer page */ ++ uint16_t flags; /* NETTXF_* */ ++ uint16_t id; /* Echoed in response message. */ ++ uint16_t size; /* Packet size in bytes. */ ++}; ++typedef struct netif_tx_request netif_tx_request_t; ++ ++/* Types of netif_extra_info descriptors. */ ++#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ ++#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ ++#define XEN_NETIF_EXTRA_TYPE_MAX (2) ++ ++/* netif_extra_info flags. */ ++#define _XEN_NETIF_EXTRA_FLAG_MORE (0) ++#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE) ++ ++/* GSO types - only TCPv4 currently supported. */ ++#define XEN_NETIF_GSO_TYPE_TCPV4 (1) ++ ++/* ++ * This structure needs to fit within both netif_tx_request and ++ * netif_rx_response for compatibility. ++ */ ++struct netif_extra_info { ++ uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */ ++ uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */ ++ ++ union { ++ struct { ++ /* ++ * Maximum payload size of each segment. For example, for TCP this ++ * is just the path MSS. ++ */ ++ uint16_t size; ++ ++ /* ++ * GSO type. This determines the protocol of the packet and any ++ * extra features required to segment the packet properly. ++ */ ++ uint8_t type; /* XEN_NETIF_GSO_TYPE_* */ ++ ++ /* Future expansion. */ ++ uint8_t pad; ++ ++ /* ++ * GSO features. This specifies any extra GSO features required ++ * to process this packet, such as ECN support for TCPv4. ++ */ ++ uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ ++ } gso; ++ ++ uint16_t pad[3]; ++ } u; ++}; ++ ++struct netif_tx_response { ++ uint16_t id; ++ int16_t status; /* NETIF_RSP_* */ ++}; ++typedef struct netif_tx_response netif_tx_response_t; ++ ++struct netif_rx_request { ++ uint16_t id; /* Echoed in response message. */ ++ grant_ref_t gref; /* Reference to incoming granted frame */ ++}; ++typedef struct netif_rx_request netif_rx_request_t; ++ ++/* Packet data has been validated against protocol checksum. */ ++#define _NETRXF_data_validated (0) ++#define NETRXF_data_validated (1U<<_NETRXF_data_validated) ++ ++/* Protocol checksum field is blank in the packet (hardware offload)? */ ++#define _NETRXF_csum_blank (1) ++#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank) ++ ++/* Packet continues in the next request descriptor. */ ++#define _NETRXF_more_data (2) ++#define NETRXF_more_data (1U<<_NETRXF_more_data) ++ ++/* Packet to be followed by extra descriptor(s). */ ++#define _NETRXF_extra_info (3) ++#define NETRXF_extra_info (1U<<_NETRXF_extra_info) ++ ++struct netif_rx_response { ++ uint16_t id; ++ uint16_t offset; /* Offset in page of start of received packet */ ++ uint16_t flags; /* NETRXF_* */ ++ int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */ ++}; ++typedef struct netif_rx_response netif_rx_response_t; ++ ++/* ++ * Generate netif ring structures and types. ++ */ ++ ++DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response); ++DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response); ++ ++#define NETIF_RSP_DROPPED -2 ++#define NETIF_RSP_ERROR -1 ++#define NETIF_RSP_OKAY 0 ++/* No response: used for auxiliary requests (e.g., netif_tx_extra). */ ++#define NETIF_RSP_NULL 1 ++ ++#endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/pciif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/pciif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,83 @@ ++/* ++ * PCI Backend/Frontend Common Data Structures & Macros ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#ifndef __XEN_PCI_COMMON_H__ ++#define __XEN_PCI_COMMON_H__ ++ ++/* Be sure to bump this number if you change this file */ ++#define XEN_PCI_MAGIC "7" ++ ++/* xen_pci_sharedinfo flags */ ++#define _XEN_PCIF_active (0) ++#define XEN_PCIF_active (1<<_XEN_PCI_active) ++ ++/* xen_pci_op commands */ ++#define XEN_PCI_OP_conf_read (0) ++#define XEN_PCI_OP_conf_write (1) ++ ++/* xen_pci_op error numbers */ ++#define XEN_PCI_ERR_success (0) ++#define XEN_PCI_ERR_dev_not_found (-1) ++#define XEN_PCI_ERR_invalid_offset (-2) ++#define XEN_PCI_ERR_access_denied (-3) ++#define XEN_PCI_ERR_not_implemented (-4) ++/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */ ++#define XEN_PCI_ERR_op_failed (-5) ++ ++struct xen_pci_op { ++ /* IN: what action to perform: XEN_PCI_OP_* */ ++ uint32_t cmd; ++ ++ /* OUT: will contain an error number (if any) from errno.h */ ++ int32_t err; ++ ++ /* IN: which device to touch */ ++ uint32_t domain; /* PCI Domain/Segment */ ++ uint32_t bus; ++ uint32_t devfn; ++ ++ /* IN: which configuration registers to touch */ ++ int32_t offset; ++ int32_t size; ++ ++ /* IN/OUT: Contains the result after a READ or the value to WRITE */ ++ uint32_t value; ++}; ++ ++struct xen_pci_sharedinfo { ++ /* flags - XEN_PCIF_* */ ++ uint32_t flags; ++ struct xen_pci_op op; ++}; ++ ++#endif /* __XEN_PCI_COMMON_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/protocols.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/protocols.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,21 @@ ++#ifndef __XEN_PROTOCOLS_H__ ++#define __XEN_PROTOCOLS_H__ ++ ++#define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi" ++#define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" ++#define XEN_IO_PROTO_ABI_IA64 "ia64-abi" ++#define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi" ++ ++#if defined(__i386__) ++# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 ++#elif defined(__x86_64__) ++# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64 ++#elif defined(__ia64__) ++# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 ++#elif defined(__powerpc64__) ++# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 ++#else ++# error arch fixup needed here ++#endif ++ ++#endif +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/ring.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/ring.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,299 @@ ++/****************************************************************************** ++ * ring.h ++ * ++ * Shared producer-consumer ring macros. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Tim Deegan and Andrew Warfield November 2004. ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_RING_H__ ++#define __XEN_PUBLIC_IO_RING_H__ ++ ++typedef unsigned int RING_IDX; ++ ++/* Round a 32-bit unsigned constant down to the nearest power of two. */ ++#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) ++#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x)) ++#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x)) ++#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) ++#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x)) ++ ++/* ++ * Calculate size of a shared ring, given the total available space for the ++ * ring and indexes (_sz), and the name tag of the request/response structure. ++ * A ring contains as many entries as will fit, rounded down to the nearest ++ * power of two (so we can mask with (size-1) to loop around). ++ */ ++#define __RING_SIZE(_s, _sz) \ ++ (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) ++ ++/* ++ * Macros to make the correct C datatypes for a new kind of ring. ++ * ++ * To make a new ring datatype, you need to have two message structures, ++ * let's say request_t, and response_t already defined. ++ * ++ * In a header where you want the ring datatype declared, you then do: ++ * ++ * DEFINE_RING_TYPES(mytag, request_t, response_t); ++ * ++ * These expand out to give you a set of types, as you can see below. ++ * The most important of these are: ++ * ++ * mytag_sring_t - The shared ring. ++ * mytag_front_ring_t - The 'front' half of the ring. ++ * mytag_back_ring_t - The 'back' half of the ring. ++ * ++ * To initialize a ring in your code you need to know the location and size ++ * of the shared memory area (PAGE_SIZE, for instance). To initialise ++ * the front half: ++ * ++ * mytag_front_ring_t front_ring; ++ * SHARED_RING_INIT((mytag_sring_t *)shared_page); ++ * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); ++ * ++ * Initializing the back follows similarly (note that only the front ++ * initializes the shared ring): ++ * ++ * mytag_back_ring_t back_ring; ++ * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); ++ */ ++ ++#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ ++ \ ++/* Shared ring entry */ \ ++union __name##_sring_entry { \ ++ __req_t req; \ ++ __rsp_t rsp; \ ++}; \ ++ \ ++/* Shared ring page */ \ ++struct __name##_sring { \ ++ RING_IDX req_prod, req_event; \ ++ RING_IDX rsp_prod, rsp_event; \ ++ uint8_t pad[48]; \ ++ union __name##_sring_entry ring[1]; /* variable-length */ \ ++}; \ ++ \ ++/* "Front" end's private variables */ \ ++struct __name##_front_ring { \ ++ RING_IDX req_prod_pvt; \ ++ RING_IDX rsp_cons; \ ++ unsigned int nr_ents; \ ++ struct __name##_sring *sring; \ ++}; \ ++ \ ++/* "Back" end's private variables */ \ ++struct __name##_back_ring { \ ++ RING_IDX rsp_prod_pvt; \ ++ RING_IDX req_cons; \ ++ unsigned int nr_ents; \ ++ struct __name##_sring *sring; \ ++}; \ ++ \ ++/* Syntactic sugar */ \ ++typedef struct __name##_sring __name##_sring_t; \ ++typedef struct __name##_front_ring __name##_front_ring_t; \ ++typedef struct __name##_back_ring __name##_back_ring_t ++ ++/* ++ * Macros for manipulating rings. ++ * ++ * FRONT_RING_whatever works on the "front end" of a ring: here ++ * requests are pushed on to the ring and responses taken off it. ++ * ++ * BACK_RING_whatever works on the "back end" of a ring: here ++ * requests are taken off the ring and responses put on. ++ * ++ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL. ++ * This is OK in 1-for-1 request-response situations where the ++ * requestor (front end) never has more than RING_SIZE()-1 ++ * outstanding requests. ++ */ ++ ++/* Initialising empty rings */ ++#define SHARED_RING_INIT(_s) do { \ ++ (_s)->req_prod = (_s)->rsp_prod = 0; \ ++ (_s)->req_event = (_s)->rsp_event = 1; \ ++ memset((_s)->pad, 0, sizeof((_s)->pad)); \ ++} while(0) ++ ++#define FRONT_RING_INIT(_r, _s, __size) do { \ ++ (_r)->req_prod_pvt = 0; \ ++ (_r)->rsp_cons = 0; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++ (_r)->sring = (_s); \ ++} while (0) ++ ++#define BACK_RING_INIT(_r, _s, __size) do { \ ++ (_r)->rsp_prod_pvt = 0; \ ++ (_r)->req_cons = 0; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++ (_r)->sring = (_s); \ ++} while (0) ++ ++/* Initialize to existing shared indexes -- for recovery */ ++#define FRONT_RING_ATTACH(_r, _s, __size) do { \ ++ (_r)->sring = (_s); \ ++ (_r)->req_prod_pvt = (_s)->req_prod; \ ++ (_r)->rsp_cons = (_s)->rsp_prod; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++} while (0) ++ ++#define BACK_RING_ATTACH(_r, _s, __size) do { \ ++ (_r)->sring = (_s); \ ++ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ ++ (_r)->req_cons = (_s)->req_prod; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++} while (0) ++ ++/* How big is this ring? */ ++#define RING_SIZE(_r) \ ++ ((_r)->nr_ents) ++ ++/* Number of free requests (for use on front side only). */ ++#define RING_FREE_REQUESTS(_r) \ ++ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons)) ++ ++/* Test if there is an empty slot available on the front ring. ++ * (This is only meaningful from the front. ) ++ */ ++#define RING_FULL(_r) \ ++ (RING_FREE_REQUESTS(_r) == 0) ++ ++/* Test if there are outstanding messages to be processed on a ring. */ ++#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ ++ ((_r)->sring->rsp_prod - (_r)->rsp_cons) ++ ++#ifdef __GNUC__ ++#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ ++ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ ++ unsigned int rsp = RING_SIZE(_r) - \ ++ ((_r)->req_cons - (_r)->rsp_prod_pvt); \ ++ req < rsp ? req : rsp; \ ++}) ++#else ++/* Same as above, but without the nice GCC ({ ... }) syntax. */ ++#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ ++ ((((_r)->sring->req_prod - (_r)->req_cons) < \ ++ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ ++ ((_r)->sring->req_prod - (_r)->req_cons) : \ ++ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ++#endif ++ ++/* Direct access to individual ring elements, by index. */ ++#define RING_GET_REQUEST(_r, _idx) \ ++ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) ++ ++#define RING_GET_RESPONSE(_r, _idx) \ ++ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) ++ ++/* Loop termination condition: Would the specified index overflow the ring? */ ++#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ ++ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) ++ ++#define RING_PUSH_REQUESTS(_r) do { \ ++ 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 */ \ ++ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ ++} while (0) ++ ++/* ++ * Notification hold-off (req_event and rsp_event): ++ * ++ * When queueing requests or responses on a shared ring, it may not always be ++ * necessary to notify the remote end. For example, if requests are in flight ++ * in a backend, the front may be able to queue further requests without ++ * notifying the back (if the back checks for new requests when it queues ++ * responses). ++ * ++ * When enqueuing requests or responses: ++ * ++ * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument ++ * is a boolean return value. True indicates that the receiver requires an ++ * asynchronous notification. ++ * ++ * After dequeuing requests or responses (before sleeping the connection): ++ * ++ * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES(). ++ * The second argument is a boolean return value. True indicates that there ++ * are pending messages on the ring (i.e., the connection should not be put ++ * to sleep). ++ * ++ * These macros will set the req_event/rsp_event field to trigger a ++ * notification on the very next message that is enqueued. If you want to ++ * create batches of work (i.e., only receive a notification after several ++ * messages have been enqueued) then you will need to create a customised ++ * version of the FINAL_CHECK macro in your own code, which sets the event ++ * field appropriately. ++ */ ++ ++#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 */ \ ++ (_r)->sring->req_prod = __new; \ ++ mb(); /* back sees new requests /before/ we check req_event */ \ ++ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ ++ (RING_IDX)(__new - __old)); \ ++} while (0) ++ ++#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 */ \ ++ (_r)->sring->rsp_prod = __new; \ ++ mb(); /* front sees new responses /before/ we check rsp_event */ \ ++ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ ++ (RING_IDX)(__new - __old)); \ ++} while (0) ++ ++#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ ++ if (_work_to_do) break; \ ++ (_r)->sring->req_event = (_r)->req_cons + 1; \ ++ mb(); \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ ++} while (0) ++ ++#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ ++ if (_work_to_do) break; \ ++ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ ++ mb(); \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ ++} while (0) ++ ++#endif /* __XEN_PUBLIC_IO_RING_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/tpmif.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/tpmif.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,77 @@ ++/****************************************************************************** ++ * tpmif.h ++ * ++ * TPM I/O interface for Xen guest OSes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, IBM Corporation ++ * ++ * Author: Stefan Berger, stefanb@us.ibm.com ++ * Grant table support: Mahadevan Gomathisankaran ++ * ++ * This code has been derived from tools/libxc/xen/io/netif.h ++ * ++ * Copyright (c) 2003-2004, Keir Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_TPMIF_H__ ++#define __XEN_PUBLIC_IO_TPMIF_H__ ++ ++#include "../grant_table.h" ++ ++struct tpmif_tx_request { ++ unsigned long addr; /* Machine address of packet. */ ++ grant_ref_t ref; /* grant table access reference */ ++ uint16_t unused; ++ uint16_t size; /* Packet size in bytes. */ ++}; ++typedef struct tpmif_tx_request tpmif_tx_request_t; ++ ++/* ++ * The TPMIF_TX_RING_SIZE defines the number of pages the ++ * front-end and backend can exchange (= size of array). ++ */ ++typedef uint32_t TPMIF_RING_IDX; ++ ++#define TPMIF_TX_RING_SIZE 1 ++ ++/* This structure must fit in a memory page. */ ++ ++struct tpmif_ring { ++ struct tpmif_tx_request req; ++}; ++typedef struct tpmif_ring tpmif_ring_t; ++ ++struct tpmif_tx_interface { ++ struct tpmif_ring ring[TPMIF_TX_RING_SIZE]; ++}; ++typedef struct tpmif_tx_interface tpmif_tx_interface_t; ++ ++#endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/xenbus.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/xenbus.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,73 @@ ++/***************************************************************************** ++ * xenbus.h ++ * ++ * Xenbus protocol details. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) 2005 XenSource Ltd. ++ */ ++ ++#ifndef _XEN_PUBLIC_IO_XENBUS_H ++#define _XEN_PUBLIC_IO_XENBUS_H ++ ++/* ++ * The state of either end of the Xenbus, i.e. the current communication ++ * status of initialisation across the bus. States here imply nothing about ++ * the state of the connection between the driver and the kernel's device ++ * layers. ++ */ ++enum xenbus_state { ++ XenbusStateUnknown = 0, ++ ++ XenbusStateInitialising = 1, ++ ++ /* ++ * InitWait: Finished early initialisation but waiting for information ++ * from the peer or hotplug scripts. ++ */ ++ XenbusStateInitWait = 2, ++ ++ /* ++ * Initialised: Waiting for a connection from the peer. ++ */ ++ XenbusStateInitialised = 3, ++ ++ XenbusStateConnected = 4, ++ ++ /* ++ * Closing: The device is being closed due to an error or an unplug event. ++ */ ++ XenbusStateClosing = 5, ++ ++ XenbusStateClosed = 6 ++}; ++typedef enum xenbus_state XenbusState; ++ ++#endif /* _XEN_PUBLIC_IO_XENBUS_H */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/io/xs_wire.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/io/xs_wire.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,117 @@ ++/* ++ * Details of the "wire" protocol between Xen Store Daemon and client ++ * library or guest kernel. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) 2005 Rusty Russell IBM Corporation ++ */ ++ ++#ifndef _XS_WIRE_H ++#define _XS_WIRE_H ++ ++enum xsd_sockmsg_type ++{ ++ XS_DEBUG, ++ XS_DIRECTORY, ++ XS_READ, ++ XS_GET_PERMS, ++ XS_WATCH, ++ XS_UNWATCH, ++ XS_TRANSACTION_START, ++ XS_TRANSACTION_END, ++ XS_INTRODUCE, ++ XS_RELEASE, ++ XS_GET_DOMAIN_PATH, ++ XS_WRITE, ++ XS_MKDIR, ++ XS_RM, ++ XS_SET_PERMS, ++ XS_WATCH_EVENT, ++ XS_ERROR, ++ XS_IS_DOMAIN_INTRODUCED, ++ XS_RESUME ++}; ++ ++#define XS_WRITE_NONE "NONE" ++#define XS_WRITE_CREATE "CREATE" ++#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" ++ ++/* We hand errors as strings, for portability. */ ++struct xsd_errors ++{ ++ int errnum; ++ const char *errstring; ++}; ++#define XSD_ERROR(x) { x, #x } ++static struct xsd_errors xsd_errors[] __attribute__((unused)) = { ++ XSD_ERROR(EINVAL), ++ XSD_ERROR(EACCES), ++ XSD_ERROR(EEXIST), ++ XSD_ERROR(EISDIR), ++ XSD_ERROR(ENOENT), ++ XSD_ERROR(ENOMEM), ++ XSD_ERROR(ENOSPC), ++ XSD_ERROR(EIO), ++ XSD_ERROR(ENOTEMPTY), ++ XSD_ERROR(ENOSYS), ++ XSD_ERROR(EROFS), ++ XSD_ERROR(EBUSY), ++ XSD_ERROR(EAGAIN), ++ XSD_ERROR(EISCONN) ++}; ++ ++struct xsd_sockmsg ++{ ++ uint32_t type; /* XS_??? */ ++ uint32_t req_id;/* Request identifier, echoed in daemon's response. */ ++ uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */ ++ uint32_t len; /* Length of data following this. */ ++ ++ /* Generally followed by nul-terminated string(s). */ ++}; ++ ++enum xs_watch_type ++{ ++ XS_WATCH_PATH = 0, ++ XS_WATCH_TOKEN ++}; ++ ++/* Inter-domain shared memory communications. */ ++#define XENSTORE_RING_SIZE 1024 ++typedef uint32_t XENSTORE_RING_IDX; ++#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1)) ++struct xenstore_domain_interface { ++ char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */ ++ char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */ ++ XENSTORE_RING_IDX req_cons, req_prod; ++ XENSTORE_RING_IDX rsp_cons, rsp_prod; ++}; ++ ++#endif /* _XS_WIRE_H */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/kexec.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/kexec.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,137 @@ ++/****************************************************************************** ++ * kexec.h - Public portion ++ * ++ * Xen port written by: ++ * - Simon 'Horms' Horman <horms@verge.net.au> ++ * - Magnus Damm <magnus@valinux.co.jp> ++ */ ++ ++#ifndef _XEN_PUBLIC_KEXEC_H ++#define _XEN_PUBLIC_KEXEC_H ++ ++ ++/* This file describes the Kexec / Kdump hypercall interface for Xen. ++ * ++ * Kexec under vanilla Linux allows a user to reboot the physical machine ++ * into a new user-specified kernel. The Xen port extends this idea ++ * to allow rebooting of the machine from dom0. When kexec for dom0 ++ * is used to reboot, both the hypervisor and the domains get replaced ++ * with some other kernel. It is possible to kexec between vanilla ++ * Linux and Xen and back again. Xen to Xen works well too. ++ * ++ * The hypercall interface for kexec can be divided into three main ++ * types of hypercall operations: ++ * ++ * 1) Range information: ++ * This is used by the dom0 kernel to ask the hypervisor about various ++ * address information. This information is needed to allow kexec-tools ++ * to fill in the ELF headers for /proc/vmcore properly. ++ * ++ * 2) Load and unload of images: ++ * There are no big surprises here, the kexec binary from kexec-tools ++ * runs in userspace in dom0. The tool loads/unloads data into the ++ * dom0 kernel such as new kernel, initramfs and hypervisor. When ++ * loaded the dom0 kernel performs a load hypercall operation, and ++ * before releasing all page references the dom0 kernel calls unload. ++ * ++ * 3) Kexec operation: ++ * This is used to start a previously loaded kernel. ++ */ ++ ++#include "xen.h" ++ ++#if defined(__i386__) || defined(__x86_64__) ++#define KEXEC_XEN_NO_PAGES 17 ++#endif ++ ++/* ++ * Prototype for this hypercall is: ++ * int kexec_op(int cmd, void *args) ++ * @cmd == KEXEC_CMD_... ++ * KEXEC operation to perform ++ * @args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++/* ++ * Kexec supports two types of operation: ++ * - kexec into a regular kernel, very similar to a standard reboot ++ * - KEXEC_TYPE_DEFAULT is used to specify this type ++ * - kexec into a special "crash kernel", aka kexec-on-panic ++ * - KEXEC_TYPE_CRASH is used to specify this type ++ * - parts of our system may be broken at kexec-on-panic time ++ * - the code should be kept as simple and self-contained as possible ++ */ ++ ++#define KEXEC_TYPE_DEFAULT 0 ++#define KEXEC_TYPE_CRASH 1 ++ ++ ++/* The kexec implementation for Xen allows the user to load two ++ * types of kernels, KEXEC_TYPE_DEFAULT and KEXEC_TYPE_CRASH. ++ * All data needed for a kexec reboot is kept in one xen_kexec_image_t ++ * per "instance". The data mainly consists of machine address lists to pages ++ * together with destination addresses. The data in xen_kexec_image_t ++ * is passed to the "code page" which is one page of code that performs ++ * the final relocations before jumping to the new kernel. ++ */ ++ ++typedef struct xen_kexec_image { ++#if defined(__i386__) || defined(__x86_64__) ++ unsigned long page_list[KEXEC_XEN_NO_PAGES]; ++#endif ++ unsigned long indirection_page; ++ unsigned long start_address; ++} xen_kexec_image_t; ++ ++/* ++ * Perform kexec having previously loaded a kexec or kdump kernel ++ * as appropriate. ++ * type == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in] ++ */ ++#define KEXEC_CMD_kexec 0 ++typedef struct xen_kexec_exec { ++ int type; ++} xen_kexec_exec_t; ++ ++/* ++ * Load/Unload kernel image for kexec or kdump. ++ * type == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in] ++ * image == relocation information for kexec (ignored for unload) [in] ++ */ ++#define KEXEC_CMD_kexec_load 1 ++#define KEXEC_CMD_kexec_unload 2 ++typedef struct xen_kexec_load { ++ int type; ++ xen_kexec_image_t image; ++} xen_kexec_load_t; ++ ++#define KEXEC_RANGE_MA_CRASH 0 /* machine address and size of crash area */ ++#define KEXEC_RANGE_MA_XEN 1 /* machine address and size of Xen itself */ ++#define KEXEC_RANGE_MA_CPU 2 /* machine address and size of a CPU note */ ++ ++/* ++ * Find the address and size of certain memory areas ++ * range == KEXEC_RANGE_... [in] ++ * nr == physical CPU number (starting from 0) if KEXEC_RANGE_MA_CPU [in] ++ * size == number of bytes reserved in window [out] ++ * start == address of the first byte in the window [out] ++ */ ++#define KEXEC_CMD_kexec_get_range 3 ++typedef struct xen_kexec_range { ++ int range; ++ int nr; ++ unsigned long size; ++ unsigned long start; ++} xen_kexec_range_t; ++ ++#endif /* _XEN_PUBLIC_KEXEC_H */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/libelf.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/libelf.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,241 @@ ++#ifndef __XC_LIBELF__ ++#define __XC_LIBELF__ 1 ++ ++#if defined(__i386__) || defined(__x86_64) || defined(__ia64__) ++#define XEN_ELF_LITTLE_ENDIAN ++#elif defined(__powerpc__) ++#define XEN_ELF_BIG_ENDIAN ++#else ++#error define architectural endianness ++#endif ++ ++#undef ELFSIZE ++#include "elfnote.h" ++#include "elfstructs.h" ++#include "features.h" ++ ++/* ------------------------------------------------------------------------ */ ++ ++typedef union { ++ Elf32_Ehdr e32; ++ Elf64_Ehdr e64; ++} elf_ehdr; ++ ++typedef union { ++ Elf32_Phdr e32; ++ Elf64_Phdr e64; ++} elf_phdr; ++ ++typedef union { ++ Elf32_Shdr e32; ++ Elf64_Shdr e64; ++} elf_shdr; ++ ++typedef union { ++ Elf32_Sym e32; ++ Elf64_Sym e64; ++} elf_sym; ++ ++typedef union { ++ Elf32_Rel e32; ++ Elf64_Rel e64; ++} elf_rel; ++ ++typedef union { ++ Elf32_Rela e32; ++ Elf64_Rela e64; ++} elf_rela; ++ ++typedef union { ++ Elf32_Note e32; ++ Elf64_Note e64; ++} elf_note; ++ ++struct elf_binary { ++ /* elf binary */ ++ const char *image; ++ size_t size; ++ char class; ++ char data; ++ ++ const elf_ehdr *ehdr; ++ const char *sec_strtab; ++ const elf_shdr *sym_tab; ++ const char *sym_strtab; ++ ++ /* loaded to */ ++ char *dest; ++ uint64_t pstart; ++ uint64_t pend; ++ uint64_t reloc_offset; ++ ++#ifndef __XEN__ ++ /* misc */ ++ FILE *log; ++#endif ++ int verbose; ++}; ++ ++/* ------------------------------------------------------------------------ */ ++/* accessing elf header fields */ ++ ++#ifdef XEN_ELF_BIG_ENDIAN ++# define NATIVE_ELFDATA ELFDATA2MSB ++#else ++# define NATIVE_ELFDATA ELFDATA2LSB ++#endif ++ ++#define elf_32bit(elf) (ELFCLASS32 == (elf)->class) ++#define elf_64bit(elf) (ELFCLASS64 == (elf)->class) ++#define elf_msb(elf) (ELFDATA2MSB == (elf)->data) ++#define elf_lsb(elf) (ELFDATA2LSB == (elf)->data) ++#define elf_swap(elf) (NATIVE_ELFDATA != (elf)->data) ++ ++#define elf_uval(elf, str, elem) \ ++ ((ELFCLASS64 == (elf)->class) \ ++ ? elf_access_unsigned((elf), (str), \ ++ offsetof(typeof(*(str)),e64.elem), \ ++ sizeof((str)->e64.elem)) \ ++ : elf_access_unsigned((elf), (str), \ ++ offsetof(typeof(*(str)),e32.elem), \ ++ sizeof((str)->e32.elem))) ++ ++#define elf_sval(elf, str, elem) \ ++ ((ELFCLASS64 == (elf)->class) \ ++ ? elf_access_signed((elf), (str), \ ++ offsetof(typeof(*(str)),e64.elem), \ ++ sizeof((str)->e64.elem)) \ ++ : elf_access_signed((elf), (str), \ ++ offsetof(typeof(*(str)),e32.elem), \ ++ sizeof((str)->e32.elem))) ++ ++#define elf_size(elf, str) \ ++ ((ELFCLASS64 == (elf)->class) \ ++ ? sizeof((str)->e64) \ ++ : sizeof((str)->e32)) ++ ++uint64_t elf_access_unsigned(struct elf_binary *elf, const void *ptr, ++ uint64_t offset, size_t size); ++int64_t elf_access_signed(struct elf_binary *elf, const void *ptr, ++ uint64_t offset, size_t size); ++ ++uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr); ++ ++/* ------------------------------------------------------------------------ */ ++/* xc_libelf_tools.c */ ++ ++int elf_shdr_count(struct elf_binary *elf); ++int elf_phdr_count(struct elf_binary *elf); ++ ++const elf_shdr *elf_shdr_by_name(struct elf_binary *elf, const char *name); ++const elf_shdr *elf_shdr_by_index(struct elf_binary *elf, int index); ++const elf_phdr *elf_phdr_by_index(struct elf_binary *elf, int index); ++ ++const char *elf_section_name(struct elf_binary *elf, const elf_shdr * shdr); ++const void *elf_section_start(struct elf_binary *elf, const elf_shdr * shdr); ++const void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr); ++ ++const void *elf_segment_start(struct elf_binary *elf, const elf_phdr * phdr); ++const void *elf_segment_end(struct elf_binary *elf, const elf_phdr * phdr); ++ ++const elf_sym *elf_sym_by_name(struct elf_binary *elf, const char *symbol); ++const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index); ++ ++const char *elf_note_name(struct elf_binary *elf, const elf_note * note); ++const void *elf_note_desc(struct elf_binary *elf, const elf_note * note); ++uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note); ++const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note); ++ ++int elf_is_elfbinary(const void *image); ++int elf_phdr_is_loadable(struct elf_binary *elf, const elf_phdr * phdr); ++ ++/* ------------------------------------------------------------------------ */ ++/* xc_libelf_loader.c */ ++ ++int elf_init(struct elf_binary *elf, const char *image, size_t size); ++#ifdef __XEN__ ++void elf_set_verbose(struct elf_binary *elf); ++#else ++void elf_set_logfile(struct elf_binary *elf, FILE * log, int verbose); ++#endif ++ ++void elf_parse_binary(struct elf_binary *elf); ++void elf_load_binary(struct elf_binary *elf); ++ ++void *elf_get_ptr(struct elf_binary *elf, unsigned long addr); ++uint64_t elf_lookup_addr(struct elf_binary *elf, const char *symbol); ++ ++/* ------------------------------------------------------------------------ */ ++/* xc_libelf_relocate.c */ ++ ++int elf_reloc(struct elf_binary *elf); ++ ++/* ------------------------------------------------------------------------ */ ++/* xc_libelf_dominfo.c */ ++ ++#define UNSET_ADDR ((uint64_t)-1) ++ ++enum xen_elfnote_type { ++ XEN_ENT_NONE = 0, ++ XEN_ENT_LONG = 1, ++ XEN_ENT_STR = 2 ++}; ++ ++struct xen_elfnote { ++ enum xen_elfnote_type type; ++ const char *name; ++ union { ++ const char *str; ++ uint64_t num; ++ } data; ++}; ++ ++struct elf_dom_parms { ++ /* raw */ ++ const char *guest_info; ++ const void *elf_note_start; ++ const void *elf_note_end; ++ struct xen_elfnote elf_notes[XEN_ELFNOTE_MAX + 1]; ++ ++ /* parsed */ ++ char guest_os[16]; ++ char guest_ver[16]; ++ char xen_ver[16]; ++ char loader[16]; ++ int pae; ++ int bsd_symtab; ++ uint64_t virt_base; ++ uint64_t virt_entry; ++ uint64_t virt_hypercall; ++ uint64_t virt_hv_start_low; ++ uint64_t elf_paddr_offset; ++ uint32_t f_supported[XENFEAT_NR_SUBMAPS]; ++ uint32_t f_required[XENFEAT_NR_SUBMAPS]; ++ ++ /* calculated */ ++ uint64_t virt_offset; ++ uint64_t virt_kstart; ++ uint64_t virt_kend; ++}; ++ ++static inline void elf_xen_feature_set(int nr, uint32_t * addr) ++{ ++ addr[nr >> 5] |= 1 << (nr & 31); ++} ++static inline int elf_xen_feature_get(int nr, uint32_t * addr) ++{ ++ return !!(addr[nr >> 5] & (1 << (nr & 31))); ++} ++ ++int elf_xen_parse_features(const char *features, ++ uint32_t *supported, ++ uint32_t *required); ++int elf_xen_parse_note(struct elf_binary *elf, ++ struct elf_dom_parms *parms, ++ const elf_note *note); ++int elf_xen_parse_guest_info(struct elf_binary *elf, ++ struct elf_dom_parms *parms); ++int elf_xen_parse(struct elf_binary *elf, ++ struct elf_dom_parms *parms); ++ ++#endif /* __XC_LIBELF__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/memory.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/memory.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,281 @@ ++/****************************************************************************** ++ * memory.h ++ * ++ * Memory reservation and information. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_MEMORY_H__ ++#define __XEN_PUBLIC_MEMORY_H__ ++ ++/* ++ * Increase or decrease the specified domain's memory reservation. Returns the ++ * number of extents successfully allocated or freed. ++ * arg == addr of struct xen_memory_reservation. ++ */ ++#define XENMEM_increase_reservation 0 ++#define XENMEM_decrease_reservation 1 ++#define XENMEM_populate_physmap 6 ++struct xen_memory_reservation { ++ ++ /* ++ * XENMEM_increase_reservation: ++ * OUT: MFN (*not* GMFN) bases of extents that were allocated ++ * XENMEM_decrease_reservation: ++ * IN: GMFN bases of extents to free ++ * XENMEM_populate_physmap: ++ * IN: GPFN bases of extents to populate with memory ++ * OUT: GMFN bases of extents that were allocated ++ * (NB. This command also updates the mach_to_phys translation table) ++ */ ++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start; ++ ++ /* Number of extents, and size/alignment of each (2^extent_order pages). */ ++ xen_ulong_t nr_extents; ++ unsigned int extent_order; ++ ++ /* ++ * Maximum # bits addressable by the user of the allocated region (e.g., ++ * I/O devices often have a 32-bit limitation even in 64-bit systems). If ++ * zero then the user has no addressing restriction. ++ * This field is not used by XENMEM_decrease_reservation. ++ */ ++ unsigned int address_bits; ++ ++ /* ++ * Domain whose reservation is being changed. ++ * Unprivileged domains can specify only DOMID_SELF. ++ */ ++ domid_t domid; ++}; ++typedef struct xen_memory_reservation xen_memory_reservation_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_reservation_t); ++ ++/* ++ * An atomic exchange of memory pages. If return code is zero then ++ * @out.extent_list provides GMFNs of the newly-allocated memory. ++ * Returns zero on complete success, otherwise a negative error code. ++ * On complete success then always @nr_exchanged == @in.nr_extents. ++ * On partial success @nr_exchanged indicates how much work was done. ++ */ ++#define XENMEM_exchange 11 ++struct xen_memory_exchange { ++ /* ++ * [IN] Details of memory extents to be exchanged (GMFN bases). ++ * Note that @in.address_bits is ignored and unused. ++ */ ++ struct xen_memory_reservation in; ++ ++ /* ++ * [IN/OUT] Details of new memory extents. ++ * We require that: ++ * 1. @in.domid == @out.domid ++ * 2. @in.nr_extents << @in.extent_order == ++ * @out.nr_extents << @out.extent_order ++ * 3. @in.extent_start and @out.extent_start lists must not overlap ++ * 4. @out.extent_start lists GPFN bases to be populated ++ * 5. @out.extent_start is overwritten with allocated GMFN bases ++ */ ++ struct xen_memory_reservation out; ++ ++ /* ++ * [OUT] Number of input extents that were successfully exchanged: ++ * 1. The first @nr_exchanged input extents were successfully ++ * deallocated. ++ * 2. The corresponding first entries in the output extent list correctly ++ * indicate the GMFNs that were successfully exchanged. ++ * 3. All other input and output extents are untouched. ++ * 4. If not all input exents are exchanged then the return code of this ++ * command will be non-zero. ++ * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER! ++ */ ++ xen_ulong_t nr_exchanged; ++}; ++typedef struct xen_memory_exchange xen_memory_exchange_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_exchange_t); ++ ++/* ++ * Returns the maximum machine frame number of mapped RAM in this system. ++ * This command always succeeds (it never returns an error code). ++ * arg == NULL. ++ */ ++#define XENMEM_maximum_ram_page 2 ++ ++/* ++ * Returns the current or maximum memory reservation, in pages, of the ++ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure. ++ * arg == addr of domid_t. ++ */ ++#define XENMEM_current_reservation 3 ++#define XENMEM_maximum_reservation 4 ++ ++/* ++ * Returns the maximum GPFN in use by the guest, or -ve errcode on failure. ++ */ ++#define XENMEM_maximum_gpfn 14 ++ ++/* ++ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys ++ * mapping table. Architectures which do not have a m2p table do not implement ++ * this command. ++ * arg == addr of xen_machphys_mfn_list_t. ++ */ ++#define XENMEM_machphys_mfn_list 5 ++struct xen_machphys_mfn_list { ++ /* ++ * Size of the 'extent_start' array. Fewer entries will be filled if the ++ * machphys table is smaller than max_extents * 2MB. ++ */ ++ unsigned int max_extents; ++ ++ /* ++ * Pointer to buffer to fill with list of extent starts. If there are ++ * any large discontiguities in the machine address space, 2MB gaps in ++ * the machphys table will be represented by an MFN base of zero. ++ */ ++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start; ++ ++ /* ++ * Number of extents written to the above array. This will be smaller ++ * than 'max_extents' if the machphys table is smaller than max_e * 2MB. ++ */ ++ unsigned int nr_extents; ++}; ++typedef struct xen_machphys_mfn_list xen_machphys_mfn_list_t; ++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mfn_list_t); ++ ++/* ++ * Returns the location in virtual address space of the machine_to_phys ++ * mapping table. Architectures which do not have a m2p table, or which do not ++ * map it by default into guest address space, do not implement this command. ++ * arg == addr of xen_machphys_mapping_t. ++ */ ++#define XENMEM_machphys_mapping 12 ++struct xen_machphys_mapping { ++ xen_ulong_t v_start, v_end; /* Start and end virtual addresses. */ ++ xen_ulong_t max_mfn; /* Maximum MFN that can be looked up. */ ++}; ++typedef struct xen_machphys_mapping xen_machphys_mapping_t; ++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t); ++ ++/* ++ * Sets the GPFN at which a particular page appears in the specified guest's ++ * pseudophysical address space. ++ * arg == addr of xen_add_to_physmap_t. ++ */ ++#define XENMEM_add_to_physmap 7 ++struct xen_add_to_physmap { ++ /* Which domain to change the mapping for. */ ++ domid_t domid; ++ ++ /* Source mapping space. */ ++#define XENMAPSPACE_shared_info 0 /* shared info page */ ++#define XENMAPSPACE_grant_table 1 /* grant table page */ ++ unsigned int space; ++ ++ /* Index into source mapping space. */ ++ xen_ulong_t idx; ++ ++ /* GPFN where the source mapping page should appear. */ ++ xen_pfn_t gpfn; ++}; ++typedef struct xen_add_to_physmap xen_add_to_physmap_t; ++DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); ++ ++/* ++ * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error ++ * code on failure. This call only works for auto-translated guests. ++ */ ++#define XENMEM_translate_gpfn_list 8 ++struct xen_translate_gpfn_list { ++ /* Which domain to translate for? */ ++ domid_t domid; ++ ++ /* Length of list. */ ++ xen_ulong_t nr_gpfns; ++ ++ /* List of GPFNs to translate. */ ++ XEN_GUEST_HANDLE(xen_pfn_t) gpfn_list; ++ ++ /* ++ * Output list to contain MFN translations. May be the same as the input ++ * list (in which case each input GPFN is overwritten with the output MFN). ++ */ ++ XEN_GUEST_HANDLE(xen_pfn_t) mfn_list; ++}; ++typedef struct xen_translate_gpfn_list xen_translate_gpfn_list_t; ++DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t); ++ ++/* ++ * Returns the pseudo-physical memory map as it was when the domain ++ * was started (specified by XENMEM_set_memory_map). ++ * arg == addr of xen_memory_map_t. ++ */ ++#define XENMEM_memory_map 9 ++struct xen_memory_map { ++ /* ++ * On call the number of entries which can be stored in buffer. On ++ * return the number of entries which have been stored in ++ * buffer. ++ */ ++ unsigned int nr_entries; ++ ++ /* ++ * Entries in the buffer are in the same format as returned by the ++ * BIOS INT 0x15 EAX=0xE820 call. ++ */ ++ XEN_GUEST_HANDLE(void) buffer; ++}; ++typedef struct xen_memory_map xen_memory_map_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t); ++ ++/* ++ * Returns the real physical memory map. Passes the same structure as ++ * XENMEM_memory_map. ++ * arg == addr of xen_memory_map_t. ++ */ ++#define XENMEM_machine_memory_map 10 ++ ++/* ++ * Set the pseudo-physical memory map of a domain, as returned by ++ * XENMEM_memory_map. ++ * arg == addr of xen_foreign_memory_map_t. ++ */ ++#define XENMEM_set_memory_map 13 ++struct xen_foreign_memory_map { ++ domid_t domid; ++ struct xen_memory_map map; ++}; ++typedef struct xen_foreign_memory_map xen_foreign_memory_map_t; ++DEFINE_XEN_GUEST_HANDLE(xen_foreign_memory_map_t); ++ ++#endif /* __XEN_PUBLIC_MEMORY_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/nmi.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/nmi.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,78 @@ ++/****************************************************************************** ++ * nmi.h ++ * ++ * NMI callback registration and reason codes. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_NMI_H__ ++#define __XEN_PUBLIC_NMI_H__ ++ ++/* ++ * NMI reason codes: ++ * Currently these are x86-specific, stored in arch_shared_info.nmi_reason. ++ */ ++ /* I/O-check error reported via ISA port 0x61, bit 6. */ ++#define _XEN_NMIREASON_io_error 0 ++#define XEN_NMIREASON_io_error (1UL << _XEN_NMIREASON_io_error) ++ /* Parity error reported via ISA port 0x61, bit 7. */ ++#define _XEN_NMIREASON_parity_error 1 ++#define XEN_NMIREASON_parity_error (1UL << _XEN_NMIREASON_parity_error) ++ /* Unknown hardware-generated NMI. */ ++#define _XEN_NMIREASON_unknown 2 ++#define XEN_NMIREASON_unknown (1UL << _XEN_NMIREASON_unknown) ++ ++/* ++ * long nmi_op(unsigned int cmd, void *arg) ++ * NB. All ops return zero on success, else a negative error code. ++ */ ++ ++/* ++ * Register NMI callback for this (calling) VCPU. Currently this only makes ++ * sense for domain 0, vcpu 0. All other callers will be returned EINVAL. ++ * arg == pointer to xennmi_callback structure. ++ */ ++#define XENNMI_register_callback 0 ++struct xennmi_callback { ++ unsigned long handler_address; ++ unsigned long pad; ++}; ++typedef struct xennmi_callback xennmi_callback_t; ++DEFINE_XEN_GUEST_HANDLE(xennmi_callback_t); ++ ++/* ++ * Deregister NMI callback for this (calling) VCPU. ++ * arg == NULL. ++ */ ++#define XENNMI_unregister_callback 1 ++ ++#endif /* __XEN_PUBLIC_NMI_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/physdev.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/physdev.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,169 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_PHYSDEV_H__ ++#define __XEN_PUBLIC_PHYSDEV_H__ ++ ++/* ++ * Prototype for this hypercall is: ++ * int physdev_op(int cmd, void *args) ++ * @cmd == PHYSDEVOP_??? (physdev operation). ++ * @args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++/* ++ * Notify end-of-interrupt (EOI) for the specified IRQ. ++ * @arg == pointer to physdev_eoi structure. ++ */ ++#define PHYSDEVOP_eoi 12 ++struct physdev_eoi { ++ /* IN */ ++ uint32_t irq; ++}; ++typedef struct physdev_eoi physdev_eoi_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t); ++ ++/* ++ * Query the status of an IRQ line. ++ * @arg == pointer to physdev_irq_status_query structure. ++ */ ++#define PHYSDEVOP_irq_status_query 5 ++struct physdev_irq_status_query { ++ /* IN */ ++ uint32_t irq; ++ /* OUT */ ++ uint32_t flags; /* XENIRQSTAT_* */ ++}; ++typedef struct physdev_irq_status_query physdev_irq_status_query_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_irq_status_query_t); ++ ++/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */ ++#define _XENIRQSTAT_needs_eoi (0) ++#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi) ++ ++/* IRQ shared by multiple guests? */ ++#define _XENIRQSTAT_shared (1) ++#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared) ++ ++/* ++ * Set the current VCPU's I/O privilege level. ++ * @arg == pointer to physdev_set_iopl structure. ++ */ ++#define PHYSDEVOP_set_iopl 6 ++struct physdev_set_iopl { ++ /* IN */ ++ uint32_t iopl; ++}; ++typedef struct physdev_set_iopl physdev_set_iopl_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_set_iopl_t); ++ ++/* ++ * Set the current VCPU's I/O-port permissions bitmap. ++ * @arg == pointer to physdev_set_iobitmap structure. ++ */ ++#define PHYSDEVOP_set_iobitmap 7 ++struct physdev_set_iobitmap { ++ /* IN */ ++ XEN_GUEST_HANDLE_00030205(uint8_t) bitmap; ++ uint32_t nr_ports; ++}; ++typedef struct physdev_set_iobitmap physdev_set_iobitmap_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_set_iobitmap_t); ++ ++/* ++ * Read or write an IO-APIC register. ++ * @arg == pointer to physdev_apic structure. ++ */ ++#define PHYSDEVOP_apic_read 8 ++#define PHYSDEVOP_apic_write 9 ++struct physdev_apic { ++ /* IN */ ++ unsigned long apic_physbase; ++ uint32_t reg; ++ /* IN or OUT */ ++ uint32_t value; ++}; ++typedef struct physdev_apic physdev_apic_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_apic_t); ++ ++/* ++ * Allocate or free a physical upcall vector for the specified IRQ line. ++ * @arg == pointer to physdev_irq structure. ++ */ ++#define PHYSDEVOP_alloc_irq_vector 10 ++#define PHYSDEVOP_free_irq_vector 11 ++struct physdev_irq { ++ /* IN */ ++ uint32_t irq; ++ /* IN or OUT */ ++ uint32_t vector; ++}; ++typedef struct physdev_irq physdev_irq_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); ++ ++/* ++ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() ++ * hypercall since 0x00030202. ++ */ ++struct physdev_op { ++ uint32_t cmd; ++ union { ++ struct physdev_irq_status_query irq_status_query; ++ struct physdev_set_iopl set_iopl; ++ struct physdev_set_iobitmap set_iobitmap; ++ struct physdev_apic apic_op; ++ struct physdev_irq irq_op; ++ } u; ++}; ++typedef struct physdev_op physdev_op_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_op_t); ++ ++/* ++ * Notify that some PIRQ-bound event channels have been unmasked. ++ * ** This command is obsolete since interface version 0x00030202 and is ** ++ * ** unsupported by newer versions of Xen. ** ++ */ ++#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4 ++ ++/* ++ * These all-capitals physdev operation names are superceded by the new names ++ * (defined above) since interface version 0x00030202. ++ */ ++#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query ++#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl ++#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap ++#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read ++#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write ++#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector ++#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector ++#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi ++#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared ++ ++#endif /* __XEN_PUBLIC_PHYSDEV_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/platform.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/platform.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,143 @@ ++/****************************************************************************** ++ * platform.h ++ * ++ * Hardware platform operations. Intended for use by domain-0 kernel. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2002-2006, K Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_PLATFORM_H__ ++#define __XEN_PUBLIC_PLATFORM_H__ ++ ++#include "xen.h" ++ ++#define XENPF_INTERFACE_VERSION 0x03000001 ++ ++/* ++ * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC, ++ * 1 January, 1970 if the current system time was <system_time>. ++ */ ++#define XENPF_settime 17 ++struct xenpf_settime { ++ /* IN variables. */ ++ uint32_t secs; ++ uint32_t nsecs; ++ uint64_t system_time; ++}; ++typedef struct xenpf_settime xenpf_settime_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_settime_t); ++ ++/* ++ * Request memory range (@mfn, @mfn+@nr_mfns-1) to have type @type. ++ * On x86, @type is an architecture-defined MTRR memory type. ++ * On success, returns the MTRR that was used (@reg) and a handle that can ++ * be passed to XENPF_DEL_MEMTYPE to accurately tear down the new setting. ++ * (x86-specific). ++ */ ++#define XENPF_add_memtype 31 ++struct xenpf_add_memtype { ++ /* IN variables. */ ++ xen_pfn_t mfn; ++ uint64_t nr_mfns; ++ uint32_t type; ++ /* OUT variables. */ ++ uint32_t handle; ++ uint32_t reg; ++}; ++typedef struct xenpf_add_memtype xenpf_add_memtype_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_add_memtype_t); ++ ++/* ++ * Tear down an existing memory-range type. If @handle is remembered then it ++ * should be passed in to accurately tear down the correct setting (in case ++ * of overlapping memory regions with differing types). If it is not known ++ * then @handle should be set to zero. In all cases @reg must be set. ++ * (x86-specific). ++ */ ++#define XENPF_del_memtype 32 ++struct xenpf_del_memtype { ++ /* IN variables. */ ++ uint32_t handle; ++ uint32_t reg; ++}; ++typedef struct xenpf_del_memtype xenpf_del_memtype_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_del_memtype_t); ++ ++/* Read current type of an MTRR (x86-specific). */ ++#define XENPF_read_memtype 33 ++struct xenpf_read_memtype { ++ /* IN variables. */ ++ uint32_t reg; ++ /* OUT variables. */ ++ xen_pfn_t mfn; ++ uint64_t nr_mfns; ++ uint32_t type; ++}; ++typedef struct xenpf_read_memtype xenpf_read_memtype_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_read_memtype_t); ++ ++#define XENPF_microcode_update 35 ++struct xenpf_microcode_update { ++ /* IN variables. */ ++ XEN_GUEST_HANDLE(void) data; /* Pointer to microcode data */ ++ uint32_t length; /* Length of microcode data. */ ++}; ++typedef struct xenpf_microcode_update xenpf_microcode_update_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_microcode_update_t); ++ ++#define XENPF_platform_quirk 39 ++#define QUIRK_NOIRQBALANCING 1 /* Do not restrict IO-APIC RTE targets */ ++#define QUIRK_IOAPIC_BAD_REGSEL 2 /* IO-APIC REGSEL forgets its value */ ++#define QUIRK_IOAPIC_GOOD_REGSEL 3 /* IO-APIC REGSEL behaves properly */ ++struct xenpf_platform_quirk { ++ /* IN variables. */ ++ uint32_t quirk_id; ++}; ++typedef struct xenpf_platform_quirk xenpf_platform_quirk_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t); ++ ++struct xen_platform_op { ++ uint32_t cmd; ++ uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ ++ union { ++ struct xenpf_settime settime; ++ struct xenpf_add_memtype add_memtype; ++ struct xenpf_del_memtype del_memtype; ++ struct xenpf_read_memtype read_memtype; ++ struct xenpf_microcode_update microcode; ++ struct xenpf_platform_quirk platform_quirk; ++ uint8_t pad[128]; ++ } u; ++}; ++typedef struct xen_platform_op xen_platform_op_t; ++DEFINE_XEN_GUEST_HANDLE(xen_platform_op_t); ++ ++#endif /* __XEN_PUBLIC_PLATFORM_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/sched.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/sched.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,121 @@ ++/****************************************************************************** ++ * sched.h ++ * ++ * Scheduler state interactions ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_SCHED_H__ ++#define __XEN_PUBLIC_SCHED_H__ ++ ++#include "event_channel.h" ++ ++/* ++ * The prototype for this hypercall is: ++ * long sched_op(int cmd, void *arg) ++ * @cmd == SCHEDOP_??? (scheduler operation). ++ * @arg == Operation-specific extra argument(s), as described below. ++ * ++ * Versions of Xen prior to 3.0.2 provided only the following legacy version ++ * of this hypercall, supporting only the commands yield, block and shutdown: ++ * long sched_op(int cmd, unsigned long arg) ++ * @cmd == SCHEDOP_??? (scheduler operation). ++ * @arg == 0 (SCHEDOP_yield and SCHEDOP_block) ++ * == SHUTDOWN_* code (SCHEDOP_shutdown) ++ * This legacy version is available to new guests as sched_op_compat(). ++ */ ++ ++/* ++ * Voluntarily yield the CPU. ++ * @arg == NULL. ++ */ ++#define SCHEDOP_yield 0 ++ ++/* ++ * Block execution of this VCPU until an event is received for processing. ++ * If called with event upcalls masked, this operation will atomically ++ * reenable event delivery and check for pending events before blocking the ++ * VCPU. This avoids a "wakeup waiting" race. ++ * @arg == NULL. ++ */ ++#define SCHEDOP_block 1 ++ ++/* ++ * Halt execution of this domain (all VCPUs) and notify the system controller. ++ * @arg == pointer to sched_shutdown structure. ++ */ ++#define SCHEDOP_shutdown 2 ++struct sched_shutdown { ++ unsigned int reason; /* SHUTDOWN_* */ ++}; ++typedef struct sched_shutdown sched_shutdown_t; ++DEFINE_XEN_GUEST_HANDLE(sched_shutdown_t); ++ ++/* ++ * Poll a set of event-channel ports. Return when one or more are pending. An ++ * optional timeout may be specified. ++ * @arg == pointer to sched_poll structure. ++ */ ++#define SCHEDOP_poll 3 ++struct sched_poll { ++ XEN_GUEST_HANDLE(evtchn_port_t) ports; ++ unsigned int nr_ports; ++ uint64_t timeout; ++}; ++typedef struct sched_poll sched_poll_t; ++DEFINE_XEN_GUEST_HANDLE(sched_poll_t); ++ ++/* ++ * Declare a shutdown for another domain. The main use of this function is ++ * in interpreting shutdown requests and reasons for fully-virtualized ++ * domains. A para-virtualized domain may use SCHEDOP_shutdown directly. ++ * @arg == pointer to sched_remote_shutdown structure. ++ */ ++#define SCHEDOP_remote_shutdown 4 ++struct sched_remote_shutdown { ++ domid_t domain_id; /* Remote domain ID */ ++ unsigned int reason; /* SHUTDOWN_xxx reason */ ++}; ++typedef struct sched_remote_shutdown sched_remote_shutdown_t; ++DEFINE_XEN_GUEST_HANDLE(sched_remote_shutdown_t); ++ ++/* ++ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control ++ * software to determine the appropriate action. For the most part, Xen does ++ * not care about the shutdown code. ++ */ ++#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */ ++#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */ ++#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */ ++#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */ ++ ++#endif /* __XEN_PUBLIC_SCHED_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/sysctl.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/sysctl.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,182 @@ ++/****************************************************************************** ++ * sysctl.h ++ * ++ * System management operations. For use by node control stack. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2002-2006, K Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_SYSCTL_H__ ++#define __XEN_PUBLIC_SYSCTL_H__ ++ ++#if !defined(__XEN__) && !defined(__XEN_TOOLS__) ++#error "sysctl operations are intended for use by node control tools only" ++#endif ++ ++#include "xen.h" ++#include "domctl.h" ++ ++#define XEN_SYSCTL_INTERFACE_VERSION 0x00000003 ++ ++/* ++ * Read console content from Xen buffer ring. ++ */ ++#define XEN_SYSCTL_readconsole 1 ++struct xen_sysctl_readconsole { ++ /* IN variables. */ ++ uint32_t clear; /* Non-zero -> clear after reading. */ ++ XEN_GUEST_HANDLE_64(char) buffer; /* Buffer start */ ++ /* IN/OUT variables. */ ++ uint32_t count; /* In: Buffer size; Out: Used buffer size */ ++}; ++typedef struct xen_sysctl_readconsole xen_sysctl_readconsole_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_readconsole_t); ++ ++/* Get trace buffers machine base address */ ++#define XEN_SYSCTL_tbuf_op 2 ++struct xen_sysctl_tbuf_op { ++ /* IN variables */ ++#define XEN_SYSCTL_TBUFOP_get_info 0 ++#define XEN_SYSCTL_TBUFOP_set_cpu_mask 1 ++#define XEN_SYSCTL_TBUFOP_set_evt_mask 2 ++#define XEN_SYSCTL_TBUFOP_set_size 3 ++#define XEN_SYSCTL_TBUFOP_enable 4 ++#define XEN_SYSCTL_TBUFOP_disable 5 ++ uint32_t cmd; ++ /* IN/OUT variables */ ++ struct xenctl_cpumap cpu_mask; ++ uint32_t evt_mask; ++ /* OUT variables */ ++ uint64_aligned_t buffer_mfn; ++ uint32_t size; ++}; ++typedef struct xen_sysctl_tbuf_op xen_sysctl_tbuf_op_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_tbuf_op_t); ++ ++/* ++ * Get physical information about the host machine ++ */ ++#define XEN_SYSCTL_physinfo 3 ++struct xen_sysctl_physinfo { ++ uint32_t threads_per_core; ++ uint32_t cores_per_socket; ++ uint32_t sockets_per_node; ++ uint32_t nr_nodes; ++ uint32_t cpu_khz; ++ uint64_aligned_t total_pages; ++ uint64_aligned_t free_pages; ++ uint64_aligned_t scrub_pages; ++ uint32_t hw_cap[8]; ++}; ++typedef struct xen_sysctl_physinfo xen_sysctl_physinfo_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_physinfo_t); ++ ++/* ++ * Get the ID of the current scheduler. ++ */ ++#define XEN_SYSCTL_sched_id 4 ++struct xen_sysctl_sched_id { ++ /* OUT variable */ ++ uint32_t sched_id; ++}; ++typedef struct xen_sysctl_sched_id xen_sysctl_sched_id_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_sched_id_t); ++ ++/* Interface for controlling Xen software performance counters. */ ++#define XEN_SYSCTL_perfc_op 5 ++/* Sub-operations: */ ++#define XEN_SYSCTL_PERFCOP_reset 1 /* Reset all counters to zero. */ ++#define XEN_SYSCTL_PERFCOP_query 2 /* Get perfctr information. */ ++struct xen_sysctl_perfc_desc { ++ char name[80]; /* name of perf counter */ ++ uint32_t nr_vals; /* number of values for this counter */ ++}; ++typedef struct xen_sysctl_perfc_desc xen_sysctl_perfc_desc_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_desc_t); ++typedef uint32_t xen_sysctl_perfc_val_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_val_t); ++ ++struct xen_sysctl_perfc_op { ++ /* IN variables. */ ++ uint32_t cmd; /* XEN_SYSCTL_PERFCOP_??? */ ++ /* OUT variables. */ ++ uint32_t nr_counters; /* number of counters description */ ++ uint32_t nr_vals; /* number of values */ ++ /* counter information (or NULL) */ ++ XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc; ++ /* counter values (or NULL) */ ++ XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val; ++}; ++typedef struct xen_sysctl_perfc_op xen_sysctl_perfc_op_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_perfc_op_t); ++ ++#define XEN_SYSCTL_getdomaininfolist 6 ++struct xen_sysctl_getdomaininfolist { ++ /* IN variables. */ ++ domid_t first_domain; ++ uint32_t max_domains; ++ XEN_GUEST_HANDLE_64(xen_domctl_getdomaininfo_t) buffer; ++ /* OUT variables. */ ++ uint32_t num_domains; ++}; ++typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t); ++ ++/* ++ * Inject debug keys into Xen. ++ */ ++#define XEN_SYSCTL_debug_keys 7 ++struct xen_sysctl_debug_keys { ++ /* IN variables. */ ++ XEN_GUEST_HANDLE_64(char) keys; ++ uint32_t nr_keys; ++}; ++typedef struct xen_sysctl_debug_keys xen_sysctl_debug_keys_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_debug_keys_t); ++ ++struct xen_sysctl { ++ uint32_t cmd; ++ uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ ++ union { ++ struct xen_sysctl_readconsole readconsole; ++ struct xen_sysctl_tbuf_op tbuf_op; ++ struct xen_sysctl_physinfo physinfo; ++ struct xen_sysctl_sched_id sched_id; ++ struct xen_sysctl_perfc_op perfc_op; ++ struct xen_sysctl_getdomaininfolist getdomaininfolist; ++ struct xen_sysctl_debug_keys debug_keys; ++ uint8_t pad[128]; ++ } u; ++}; ++typedef struct xen_sysctl xen_sysctl_t; ++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_t); ++ ++#endif /* __XEN_PUBLIC_SYSCTL_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/trace.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/trace.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,119 @@ ++/****************************************************************************** ++ * include/public/trace.h ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Mark Williamson, (C) 2004 Intel Research Cambridge ++ * Copyright (C) 2005 Bin Ren ++ */ ++ ++#ifndef __XEN_PUBLIC_TRACE_H__ ++#define __XEN_PUBLIC_TRACE_H__ ++ ++/* Trace classes */ ++#define TRC_CLS_SHIFT 16 ++#define TRC_GEN 0x0001f000 /* General trace */ ++#define TRC_SCHED 0x0002f000 /* Xen Scheduler trace */ ++#define TRC_DOM0OP 0x0004f000 /* Xen DOM0 operation trace */ ++#define TRC_HVM 0x0008f000 /* Xen HVM trace */ ++#define TRC_MEM 0x0010f000 /* Xen memory trace */ ++#define TRC_ALL 0xfffff000 ++ ++/* Trace subclasses */ ++#define TRC_SUBCLS_SHIFT 12 ++ ++/* trace subclasses for SVM */ ++#define TRC_HVM_ENTRYEXIT 0x00081000 /* VMENTRY and #VMEXIT */ ++#define TRC_HVM_HANDLER 0x00082000 /* various HVM handlers */ ++ ++/* Trace events per class */ ++#define TRC_LOST_RECORDS (TRC_GEN + 1) ++ ++#define TRC_SCHED_DOM_ADD (TRC_SCHED + 1) ++#define TRC_SCHED_DOM_REM (TRC_SCHED + 2) ++#define TRC_SCHED_SLEEP (TRC_SCHED + 3) ++#define TRC_SCHED_WAKE (TRC_SCHED + 4) ++#define TRC_SCHED_YIELD (TRC_SCHED + 5) ++#define TRC_SCHED_BLOCK (TRC_SCHED + 6) ++#define TRC_SCHED_SHUTDOWN (TRC_SCHED + 7) ++#define TRC_SCHED_CTL (TRC_SCHED + 8) ++#define TRC_SCHED_ADJDOM (TRC_SCHED + 9) ++#define TRC_SCHED_SWITCH (TRC_SCHED + 10) ++#define TRC_SCHED_S_TIMER_FN (TRC_SCHED + 11) ++#define TRC_SCHED_T_TIMER_FN (TRC_SCHED + 12) ++#define TRC_SCHED_DOM_TIMER_FN (TRC_SCHED + 13) ++#define TRC_SCHED_SWITCH_INFPREV (TRC_SCHED + 14) ++#define TRC_SCHED_SWITCH_INFNEXT (TRC_SCHED + 15) ++ ++#define TRC_MEM_PAGE_GRANT_MAP (TRC_MEM + 1) ++#define TRC_MEM_PAGE_GRANT_UNMAP (TRC_MEM + 2) ++#define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3) ++ ++/* trace events per subclass */ ++#define TRC_HVM_VMENTRY (TRC_HVM_ENTRYEXIT + 0x01) ++#define TRC_HVM_VMEXIT (TRC_HVM_ENTRYEXIT + 0x02) ++#define TRC_HVM_PF_XEN (TRC_HVM_HANDLER + 0x01) ++#define TRC_HVM_PF_INJECT (TRC_HVM_HANDLER + 0x02) ++#define TRC_HVM_INJ_EXC (TRC_HVM_HANDLER + 0x03) ++#define TRC_HVM_INJ_VIRQ (TRC_HVM_HANDLER + 0x04) ++#define TRC_HVM_REINJ_VIRQ (TRC_HVM_HANDLER + 0x05) ++#define TRC_HVM_IO_READ (TRC_HVM_HANDLER + 0x06) ++#define TRC_HVM_IO_WRITE (TRC_HVM_HANDLER + 0x07) ++#define TRC_HVM_CR_READ (TRC_HVM_HANDLER + 0x08) ++#define TRC_HVM_CR_WRITE (TRC_HVM_HANDLER + 0x09) ++#define TRC_HVM_DR_READ (TRC_HVM_HANDLER + 0x0A) ++#define TRC_HVM_DR_WRITE (TRC_HVM_HANDLER + 0x0B) ++#define TRC_HVM_MSR_READ (TRC_HVM_HANDLER + 0x0C) ++#define TRC_HVM_MSR_WRITE (TRC_HVM_HANDLER + 0x0D) ++#define TRC_HVM_CPUID (TRC_HVM_HANDLER + 0x0E) ++#define TRC_HVM_INTR (TRC_HVM_HANDLER + 0x0F) ++#define TRC_HVM_NMI (TRC_HVM_HANDLER + 0x10) ++#define TRC_HVM_SMI (TRC_HVM_HANDLER + 0x11) ++#define TRC_HVM_VMMCALL (TRC_HVM_HANDLER + 0x12) ++#define TRC_HVM_HLT (TRC_HVM_HANDLER + 0x13) ++#define TRC_HVM_INVLPG (TRC_HVM_HANDLER + 0x14) ++ ++/* This structure represents a single trace buffer record. */ ++struct t_rec { ++ uint64_t cycles; /* cycle counter timestamp */ ++ uint32_t event; /* event ID */ ++ unsigned long data[5]; /* event data items */ ++}; ++ ++/* ++ * This structure contains the metadata for a single trace buffer. The head ++ * field, indexes into an array of struct t_rec's. ++ */ ++struct t_buf { ++ uint32_t cons; /* Next item to be consumed by control tools. */ ++ uint32_t prod; /* Next item to be produced by Xen. */ ++ /* 'nr_recs' records follow immediately after the meta-data header. */ ++}; ++ ++#endif /* __XEN_PUBLIC_TRACE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/vcpu.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/vcpu.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,192 @@ ++/****************************************************************************** ++ * vcpu.h ++ * ++ * VCPU initialisation, query, and hotplug. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_VCPU_H__ ++#define __XEN_PUBLIC_VCPU_H__ ++ ++/* ++ * Prototype for this hypercall is: ++ * int vcpu_op(int cmd, int vcpuid, void *extra_args) ++ * @cmd == VCPUOP_??? (VCPU operation). ++ * @vcpuid == VCPU to operate on. ++ * @extra_args == Operation-specific extra arguments (NULL if none). ++ */ ++ ++/* ++ * Initialise a VCPU. Each VCPU can be initialised only once. A ++ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up. ++ * ++ * @extra_arg == pointer to vcpu_guest_context structure containing initial ++ * state for the VCPU. ++ */ ++#define VCPUOP_initialise 0 ++ ++/* ++ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail ++ * if the VCPU has not been initialised (VCPUOP_initialise). ++ */ ++#define VCPUOP_up 1 ++ ++/* ++ * Bring down a VCPU (i.e., make it non-runnable). ++ * There are a few caveats that callers should observe: ++ * 1. This operation may return, and VCPU_is_up may return false, before the ++ * VCPU stops running (i.e., the command is asynchronous). It is a good ++ * idea to ensure that the VCPU has entered a non-critical loop before ++ * bringing it down. Alternatively, this operation is guaranteed ++ * synchronous if invoked by the VCPU itself. ++ * 2. After a VCPU is initialised, there is currently no way to drop all its ++ * references to domain memory. Even a VCPU that is down still holds ++ * memory references via its pagetable base pointer and GDT. It is good ++ * practise to move a VCPU onto an 'idle' or default page table, LDT and ++ * GDT before bringing it down. ++ */ ++#define VCPUOP_down 2 ++ ++/* Returns 1 if the given VCPU is up. */ ++#define VCPUOP_is_up 3 ++ ++/* ++ * Return information about the state and running time of a VCPU. ++ * @extra_arg == pointer to vcpu_runstate_info structure. ++ */ ++#define VCPUOP_get_runstate_info 4 ++struct vcpu_runstate_info { ++ /* VCPU's current state (RUNSTATE_*). */ ++ int state; ++ /* When was current state entered (system time, ns)? */ ++ uint64_t state_entry_time; ++ /* ++ * Time spent in each RUNSTATE_* (ns). The sum of these times is ++ * guaranteed not to drift from system time. ++ */ ++ uint64_t time[4]; ++}; ++typedef struct vcpu_runstate_info vcpu_runstate_info_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_runstate_info_t); ++ ++/* VCPU is currently running on a physical CPU. */ ++#define RUNSTATE_running 0 ++ ++/* VCPU is runnable, but not currently scheduled on any physical CPU. */ ++#define RUNSTATE_runnable 1 ++ ++/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */ ++#define RUNSTATE_blocked 2 ++ ++/* ++ * VCPU is not runnable, but it is not blocked. ++ * This is a 'catch all' state for things like hotplug and pauses by the ++ * system administrator (or for critical sections in the hypervisor). ++ * RUNSTATE_blocked dominates this state (it is the preferred state). ++ */ ++#define RUNSTATE_offline 3 ++ ++/* ++ * Register a shared memory area from which the guest may obtain its own ++ * runstate information without needing to execute a hypercall. ++ * Notes: ++ * 1. The registered address may be virtual or physical or guest handle, ++ * depending on the platform. Virtual address or guest handle should be ++ * registered on x86 systems. ++ * 2. Only one shared area may be registered per VCPU. The shared area is ++ * updated by the hypervisor each time the VCPU is scheduled. Thus ++ * runstate.state will always be RUNSTATE_running and ++ * runstate.state_entry_time will indicate the system time at which the ++ * VCPU was last scheduled to run. ++ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure. ++ */ ++#define VCPUOP_register_runstate_memory_area 5 ++struct vcpu_register_runstate_memory_area { ++ union { ++ XEN_GUEST_HANDLE(vcpu_runstate_info_t) h; ++ struct vcpu_runstate_info *v; ++ uint64_t p; ++ } addr; ++}; ++typedef struct vcpu_register_runstate_memory_area vcpu_register_runstate_memory_area_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_register_runstate_memory_area_t); ++ ++/* ++ * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer ++ * which can be set via these commands. Periods smaller than one millisecond ++ * may not be supported. ++ */ ++#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */ ++#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */ ++struct vcpu_set_periodic_timer { ++ uint64_t period_ns; ++}; ++typedef struct vcpu_set_periodic_timer vcpu_set_periodic_timer_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_set_periodic_timer_t); ++ ++/* ++ * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot ++ * timer which can be set via these commands. ++ */ ++#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */ ++#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */ ++struct vcpu_set_singleshot_timer { ++ uint64_t timeout_abs_ns; /* Absolute system time value in nanoseconds. */ ++ uint32_t flags; /* VCPU_SSHOTTMR_??? */ ++}; ++typedef struct vcpu_set_singleshot_timer vcpu_set_singleshot_timer_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_set_singleshot_timer_t); ++ ++/* Flags to VCPUOP_set_singleshot_timer. */ ++ /* Require the timeout to be in the future (return -ETIME if it's passed). */ ++#define _VCPU_SSHOTTMR_future (0) ++#define VCPU_SSHOTTMR_future (1U << _VCPU_SSHOTTMR_future) ++ ++/* ++ * Register a memory location in the guest address space for the ++ * vcpu_info structure. This allows the guest to place the vcpu_info ++ * structure in a convenient place, such as in a per-cpu data area. ++ * The pointer need not be page aligned, but the structure must not ++ * cross a page boundary. ++ * ++ * If the specified mfn is INVALID_MFN, then it reverts to using the ++ * vcpu_info structure in the shared_info page. ++ */ ++#define VCPUOP_register_vcpu_info 10 /* arg == struct vcpu_info */ ++struct vcpu_register_vcpu_info { ++ xen_pfn_t mfn; /* mfn of page to place vcpu_info */ ++ uint32_t offset; /* offset within page */ ++}; ++typedef struct vcpu_register_vcpu_info vcpu_register_vcpu_info_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_register_vcpu_info_t); ++ ++#endif /* __XEN_PUBLIC_VCPU_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/version.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/version.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,91 @@ ++/****************************************************************************** ++ * version.h ++ * ++ * Xen version, type, and compile information. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com> ++ * Copyright (c) 2005, Keir Fraser <keir@xensource.com> ++ */ ++ ++#ifndef __XEN_PUBLIC_VERSION_H__ ++#define __XEN_PUBLIC_VERSION_H__ ++ ++/* NB. All ops return zero on success, except XENVER_{version,pagesize} */ ++ ++/* arg == NULL; returns major:minor (16:16). */ ++#define XENVER_version 0 ++ ++/* arg == xen_extraversion_t. */ ++#define XENVER_extraversion 1 ++typedef char xen_extraversion_t[16]; ++#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) ++ ++/* arg == xen_compile_info_t. */ ++#define XENVER_compile_info 2 ++struct xen_compile_info { ++ char compiler[64]; ++ char compile_by[16]; ++ char compile_domain[32]; ++ char compile_date[32]; ++}; ++typedef struct xen_compile_info xen_compile_info_t; ++ ++#define XENVER_capabilities 3 ++typedef char xen_capabilities_info_t[1024]; ++#define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t)) ++ ++#define XENVER_changeset 4 ++typedef char xen_changeset_info_t[64]; ++#define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t)) ++ ++#define XENVER_platform_parameters 5 ++struct xen_platform_parameters { ++ unsigned long virt_start; ++}; ++typedef struct xen_platform_parameters xen_platform_parameters_t; ++ ++#define XENVER_get_features 6 ++struct xen_feature_info { ++ unsigned int submap_idx; /* IN: which 32-bit submap to return */ ++ uint32_t submap; /* OUT: 32-bit submap */ ++}; ++typedef struct xen_feature_info xen_feature_info_t; ++ ++/* Declares the features reported by XENVER_get_features. */ ++#include "features.h" ++ ++/* arg == NULL; returns host memory page size. */ ++#define XENVER_pagesize 7 ++ ++/* arg == xen_domain_handle_t. */ ++#define XENVER_guest_handle 8 ++ ++#endif /* __XEN_PUBLIC_VERSION_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/xen-compat.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/xen-compat.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,51 @@ ++/****************************************************************************** ++ * xen-compat.h ++ * ++ * Guest OS interface to Xen. Compatibility layer. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2006, Christian Limpach ++ */ ++ ++#ifndef __XEN_PUBLIC_XEN_COMPAT_H__ ++#define __XEN_PUBLIC_XEN_COMPAT_H__ ++ ++#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030205 ++ ++#if defined(__XEN__) || defined(__XEN_TOOLS__) ++/* Xen is built with matching headers and implements the latest interface. */ ++#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__ ++#elif !defined(__XEN_INTERFACE_VERSION__) ++/* Guests which do not specify a version get the legacy interface. */ ++#define __XEN_INTERFACE_VERSION__ 0x00000000 ++#endif ++ ++#if __XEN_INTERFACE_VERSION__ > __XEN_LATEST_INTERFACE_VERSION__ ++#error "These header files do not support the requested interface version." ++#endif ++ ++/* Fields defined as a Xen guest handle since 0x00030205. */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030205 ++#define XEN_GUEST_HANDLE_00030205(type) XEN_GUEST_HANDLE(type) ++#else ++#define XEN_GUEST_HANDLE_00030205(type) type * ++#endif ++ ++#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/xen.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/xen.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,610 @@ ++/****************************************************************************** ++ * xen.h ++ * ++ * Guest OS interface to Xen. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (c) 2004, K A Fraser ++ */ ++ ++#ifndef __XEN_PUBLIC_XEN_H__ ++#define __XEN_PUBLIC_XEN_H__ ++ ++#include "xen-compat.h" ++ ++#if defined(__i386__) || defined(__x86_64__) ++#include "arch-x86/xen.h" ++#elif defined(__ia64__) ++#include "arch-ia64.h" ++#elif defined(__powerpc__) ++#include "arch-powerpc.h" ++#else ++#error "Unsupported architecture" ++#endif ++ ++/* ++ * HYPERCALLS ++ */ ++ ++#define __HYPERVISOR_set_trap_table 0 ++#define __HYPERVISOR_mmu_update 1 ++#define __HYPERVISOR_set_gdt 2 ++#define __HYPERVISOR_stack_switch 3 ++#define __HYPERVISOR_set_callbacks 4 ++#define __HYPERVISOR_fpu_taskswitch 5 ++#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */ ++#define __HYPERVISOR_platform_op 7 ++#define __HYPERVISOR_set_debugreg 8 ++#define __HYPERVISOR_get_debugreg 9 ++#define __HYPERVISOR_update_descriptor 10 ++#define __HYPERVISOR_memory_op 12 ++#define __HYPERVISOR_multicall 13 ++#define __HYPERVISOR_update_va_mapping 14 ++#define __HYPERVISOR_set_timer_op 15 ++#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */ ++#define __HYPERVISOR_xen_version 17 ++#define __HYPERVISOR_console_io 18 ++#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */ ++#define __HYPERVISOR_grant_table_op 20 ++#define __HYPERVISOR_vm_assist 21 ++#define __HYPERVISOR_update_va_mapping_otherdomain 22 ++#define __HYPERVISOR_iret 23 /* x86 only */ ++#define __HYPERVISOR_vcpu_op 24 ++#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ ++#define __HYPERVISOR_mmuext_op 26 ++#define __HYPERVISOR_acm_op 27 ++#define __HYPERVISOR_nmi_op 28 ++#define __HYPERVISOR_sched_op 29 ++#define __HYPERVISOR_callback_op 30 ++#define __HYPERVISOR_xenoprof_op 31 ++#define __HYPERVISOR_event_channel_op 32 ++#define __HYPERVISOR_physdev_op 33 ++#define __HYPERVISOR_hvm_op 34 ++#define __HYPERVISOR_sysctl 35 ++#define __HYPERVISOR_domctl 36 ++#define __HYPERVISOR_kexec_op 37 ++ ++/* Architecture-specific hypercall definitions. */ ++#define __HYPERVISOR_arch_0 48 ++#define __HYPERVISOR_arch_1 49 ++#define __HYPERVISOR_arch_2 50 ++#define __HYPERVISOR_arch_3 51 ++#define __HYPERVISOR_arch_4 52 ++#define __HYPERVISOR_arch_5 53 ++#define __HYPERVISOR_arch_6 54 ++#define __HYPERVISOR_arch_7 55 ++ ++/* ++ * HYPERCALL COMPATIBILITY. ++ */ ++ ++/* New sched_op hypercall introduced in 0x00030101. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030101 ++#undef __HYPERVISOR_sched_op ++#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat ++#endif ++ ++/* New event-channel and physdev hypercalls introduced in 0x00030202. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030202 ++#undef __HYPERVISOR_event_channel_op ++#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat ++#undef __HYPERVISOR_physdev_op ++#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat ++#endif ++ ++/* New platform_op hypercall introduced in 0x00030204. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030204 ++#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op ++#endif ++ ++/* ++ * VIRTUAL INTERRUPTS ++ * ++ * Virtual interrupts that a guest OS may receive from Xen. ++ * ++ * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a ++ * global VIRQ. The former can be bound once per VCPU and cannot be re-bound. ++ * The latter can be allocated only once per guest: they must initially be ++ * allocated to VCPU0 but can subsequently be re-bound. ++ */ ++#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */ ++#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */ ++#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */ ++#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */ ++#define VIRQ_TBUF 4 /* G. (DOM0) Trace buffer has records available. */ ++#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */ ++#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */ ++#define VIRQ_CON_RING 8 /* G. (DOM0) Bytes received on console */ ++ ++/* Architecture-specific VIRQ definitions. */ ++#define VIRQ_ARCH_0 16 ++#define VIRQ_ARCH_1 17 ++#define VIRQ_ARCH_2 18 ++#define VIRQ_ARCH_3 19 ++#define VIRQ_ARCH_4 20 ++#define VIRQ_ARCH_5 21 ++#define VIRQ_ARCH_6 22 ++#define VIRQ_ARCH_7 23 ++ ++#define NR_VIRQS 24 ++ ++/* ++ * MMU-UPDATE REQUESTS ++ * ++ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs. ++ * A foreigndom (FD) can be specified (or DOMID_SELF for none). ++ * Where the FD has some effect, it is described below. ++ * ptr[1:0] specifies the appropriate MMU_* command. ++ * ++ * ptr[1:0] == MMU_NORMAL_PT_UPDATE: ++ * Updates an entry in a page table. If updating an L1 table, and the new ++ * table entry is valid/present, the mapped frame must belong to the FD, if ++ * an FD has been specified. If attempting to map an I/O page then the ++ * caller assumes the privilege of the FD. ++ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller. ++ * FD == DOMID_XEN: Map restricted areas of Xen's heap space. ++ * ptr[:2] -- Machine address of the page-table entry to modify. ++ * val -- Value to write. ++ * ++ * ptr[1:0] == MMU_MACHPHYS_UPDATE: ++ * Updates an entry in the machine->pseudo-physical mapping table. ++ * ptr[:2] -- Machine address within the frame whose mapping to modify. ++ * The frame must belong to the FD, if one is specified. ++ * val -- Value to write into the mapping entry. ++ */ ++#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ ++#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ ++ ++/* ++ * MMU EXTENDED OPERATIONS ++ * ++ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures. ++ * A foreigndom (FD) can be specified (or DOMID_SELF for none). ++ * Where the FD has some effect, it is described below. ++ * ++ * cmd: MMUEXT_(UN)PIN_*_TABLE ++ * mfn: Machine frame number to be (un)pinned as a p.t. page. ++ * The frame must belong to the FD, if one is specified. ++ * ++ * cmd: MMUEXT_NEW_BASEPTR ++ * mfn: Machine frame number of new page-table base to install in MMU. ++ * ++ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only] ++ * mfn: Machine frame number of new page-table base to install in MMU ++ * when in user space. ++ * ++ * cmd: MMUEXT_TLB_FLUSH_LOCAL ++ * No additional arguments. Flushes local TLB. ++ * ++ * cmd: MMUEXT_INVLPG_LOCAL ++ * linear_addr: Linear address to be flushed from the local TLB. ++ * ++ * cmd: MMUEXT_TLB_FLUSH_MULTI ++ * vcpumask: Pointer to bitmap of VCPUs to be flushed. ++ * ++ * cmd: MMUEXT_INVLPG_MULTI ++ * linear_addr: Linear address to be flushed. ++ * vcpumask: Pointer to bitmap of VCPUs to be flushed. ++ * ++ * cmd: MMUEXT_TLB_FLUSH_ALL ++ * No additional arguments. Flushes all VCPUs' TLBs. ++ * ++ * cmd: MMUEXT_INVLPG_ALL ++ * linear_addr: Linear address to be flushed from all VCPUs' TLBs. ++ * ++ * cmd: MMUEXT_FLUSH_CACHE ++ * No additional arguments. Writes back and flushes cache contents. ++ * ++ * cmd: MMUEXT_SET_LDT ++ * linear_addr: Linear address of LDT base (NB. must be page-aligned). ++ * nr_ents: Number of entries in LDT. ++ */ ++#define MMUEXT_PIN_L1_TABLE 0 ++#define MMUEXT_PIN_L2_TABLE 1 ++#define MMUEXT_PIN_L3_TABLE 2 ++#define MMUEXT_PIN_L4_TABLE 3 ++#define MMUEXT_UNPIN_TABLE 4 ++#define MMUEXT_NEW_BASEPTR 5 ++#define MMUEXT_TLB_FLUSH_LOCAL 6 ++#define MMUEXT_INVLPG_LOCAL 7 ++#define MMUEXT_TLB_FLUSH_MULTI 8 ++#define MMUEXT_INVLPG_MULTI 9 ++#define MMUEXT_TLB_FLUSH_ALL 10 ++#define MMUEXT_INVLPG_ALL 11 ++#define MMUEXT_FLUSH_CACHE 12 ++#define MMUEXT_SET_LDT 13 ++#define MMUEXT_NEW_USER_BASEPTR 15 ++ ++#ifndef __ASSEMBLY__ ++struct mmuext_op { ++ unsigned int cmd; ++ union { ++ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */ ++ xen_pfn_t mfn; ++ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */ ++ unsigned long linear_addr; ++ } arg1; ++ union { ++ /* SET_LDT */ ++ unsigned int nr_ents; ++ /* TLB_FLUSH_MULTI, INVLPG_MULTI */ ++ XEN_GUEST_HANDLE_00030205(void) vcpumask; ++ } arg2; ++}; ++typedef struct mmuext_op mmuext_op_t; ++DEFINE_XEN_GUEST_HANDLE(mmuext_op_t); ++#endif ++ ++/* These are passed as 'flags' to update_va_mapping. They can be ORed. */ ++/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */ ++/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */ ++#define UVMF_NONE (0UL<<0) /* No flushing at all. */ ++#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */ ++#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */ ++#define UVMF_FLUSHTYPE_MASK (3UL<<0) ++#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */ ++#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */ ++#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */ ++ ++/* ++ * Commands to HYPERVISOR_console_io(). ++ */ ++#define CONSOLEIO_write 0 ++#define CONSOLEIO_read 1 ++ ++/* ++ * Commands to HYPERVISOR_vm_assist(). ++ */ ++#define VMASST_CMD_enable 0 ++#define VMASST_CMD_disable 1 ++ ++/* x86/32 guests: simulate full 4GB segment limits. */ ++#define VMASST_TYPE_4gb_segments 0 ++ ++/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */ ++#define VMASST_TYPE_4gb_segments_notify 1 ++ ++/* ++ * x86 guests: support writes to bottom-level PTEs. ++ * NB1. Page-directory entries cannot be written. ++ * NB2. Guest must continue to remove all writable mappings of PTEs. ++ */ ++#define VMASST_TYPE_writable_pagetables 2 ++ ++/* x86/PAE guests: support PDPTs above 4GB. */ ++#define VMASST_TYPE_pae_extended_cr3 3 ++ ++#define MAX_VMASST_TYPE 3 ++ ++#ifndef __ASSEMBLY__ ++ ++typedef uint16_t domid_t; ++ ++/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */ ++#define DOMID_FIRST_RESERVED (0x7FF0U) ++ ++/* DOMID_SELF is used in certain contexts to refer to oneself. */ ++#define DOMID_SELF (0x7FF0U) ++ ++/* ++ * DOMID_IO is used to restrict page-table updates to mapping I/O memory. ++ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO ++ * is useful to ensure that no mappings to the OS's own heap are accidentally ++ * installed. (e.g., in Linux this could cause havoc as reference counts ++ * aren't adjusted on the I/O-mapping code path). ++ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can ++ * be specified by any calling domain. ++ */ ++#define DOMID_IO (0x7FF1U) ++ ++/* ++ * DOMID_XEN is used to allow privileged domains to map restricted parts of ++ * Xen's heap space (e.g., the machine_to_phys table). ++ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if ++ * the caller is privileged. ++ */ ++#define DOMID_XEN (0x7FF2U) ++ ++/* ++ * Send an array of these to HYPERVISOR_mmu_update(). ++ * NB. The fields are natural pointer/address size for this architecture. ++ */ ++struct mmu_update { ++ uint64_t ptr; /* Machine address of PTE. */ ++ uint64_t val; /* New contents of PTE. */ ++}; ++typedef struct mmu_update mmu_update_t; ++DEFINE_XEN_GUEST_HANDLE(mmu_update_t); ++ ++/* ++ * Send an array of these to HYPERVISOR_multicall(). ++ * NB. The fields are natural register size for this architecture. ++ */ ++struct multicall_entry { ++ unsigned long op, result; ++ unsigned long args[6]; ++}; ++typedef struct multicall_entry multicall_entry_t; ++DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); ++ ++/* ++ * Event channel endpoints per domain: ++ * 1024 if a long is 32 bits; 4096 if a long is 64 bits. ++ */ ++#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64) ++ ++struct vcpu_time_info { ++ /* ++ * Updates to the following values are preceded and followed by an ++ * increment of 'version'. The guest can therefore detect updates by ++ * looking for changes to 'version'. If the least-significant bit of ++ * the version number is set then an update is in progress and the guest ++ * must wait to read a consistent set of values. ++ * The correct way to interact with the version number is similar to ++ * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry. ++ */ ++ uint32_t version; ++ uint32_t pad0; ++ uint64_t tsc_timestamp; /* TSC at last update of time vals. */ ++ uint64_t system_time; /* Time, in nanosecs, since boot. */ ++ /* ++ * Current system time: ++ * system_time + ++ * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32) ++ * CPU frequency (Hz): ++ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift ++ */ ++ uint32_t tsc_to_system_mul; ++ int8_t tsc_shift; ++ int8_t pad1[3]; ++}; /* 32 bytes */ ++typedef struct vcpu_time_info vcpu_time_info_t; ++ ++struct vcpu_info { ++ /* ++ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate ++ * a pending notification for a particular VCPU. It is then cleared ++ * by the guest OS /before/ checking for pending work, thus avoiding ++ * a set-and-check race. Note that the mask is only accessed by Xen ++ * on the CPU that is currently hosting the VCPU. This means that the ++ * pending and mask flags can be updated by the guest without special ++ * synchronisation (i.e., no need for the x86 LOCK prefix). ++ * This may seem suboptimal because if the pending flag is set by ++ * a different CPU then an IPI may be scheduled even when the mask ++ * is set. However, note: ++ * 1. The task of 'interrupt holdoff' is covered by the per-event- ++ * channel mask bits. A 'noisy' event that is continually being ++ * triggered can be masked at source at this very precise ++ * granularity. ++ * 2. The main purpose of the per-VCPU mask is therefore to restrict ++ * reentrant execution: whether for concurrency control, or to ++ * prevent unbounded stack usage. Whatever the purpose, we expect ++ * that the mask will be asserted only for short periods at a time, ++ * and so the likelihood of a 'spurious' IPI is suitably small. ++ * The mask is read before making an event upcall to the guest: a ++ * non-zero mask therefore guarantees that the VCPU will not receive ++ * an upcall activation. The mask is cleared when the VCPU requests ++ * to block: this avoids wakeup-waiting races. ++ */ ++ uint8_t evtchn_upcall_pending; ++ uint8_t evtchn_upcall_mask; ++ unsigned long evtchn_pending_sel; ++ struct arch_vcpu_info arch; ++ struct vcpu_time_info time; ++}; /* 64 bytes (x86) */ ++#ifndef __XEN__ ++typedef struct vcpu_info vcpu_info_t; ++#endif ++ ++/* ++ * Xen/kernel shared data -- pointer provided in start_info. ++ * ++ * This structure is defined to be both smaller than a page, and the ++ * only data on the shared page, but may vary in actual size even within ++ * compatible Xen versions; guests should not rely on the size ++ * of this structure remaining constant. ++ */ ++struct shared_info { ++ struct vcpu_info vcpu_info[MAX_VIRT_CPUS]; ++ ++ /* ++ * A domain can create "event channels" on which it can send and receive ++ * asynchronous event notifications. There are three classes of event that ++ * are delivered by this mechanism: ++ * 1. Bi-directional inter- and intra-domain connections. Domains must ++ * arrange out-of-band to set up a connection (usually by allocating ++ * an unbound 'listener' port and avertising that via a storage service ++ * such as xenstore). ++ * 2. Physical interrupts. A domain with suitable hardware-access ++ * privileges can bind an event-channel port to a physical interrupt ++ * source. ++ * 3. Virtual interrupts ('events'). A domain can bind an event-channel ++ * port to a virtual interrupt source, such as the virtual-timer ++ * device or the emergency console. ++ * ++ * Event channels are addressed by a "port index". Each channel is ++ * associated with two bits of information: ++ * 1. PENDING -- notifies the domain that there is a pending notification ++ * to be processed. This bit is cleared by the guest. ++ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING ++ * will cause an asynchronous upcall to be scheduled. This bit is only ++ * updated by the guest. It is read-only within Xen. If a channel ++ * becomes pending while the channel is masked then the 'edge' is lost ++ * (i.e., when the channel is unmasked, the guest must manually handle ++ * pending notifications as no upcall will be scheduled by Xen). ++ * ++ * To expedite scanning of pending notifications, any 0->1 pending ++ * transition on an unmasked channel causes a corresponding bit in a ++ * per-vcpu selector word to be set. Each bit in the selector covers a ++ * 'C long' in the PENDING bitfield array. ++ */ ++ unsigned long evtchn_pending[sizeof(unsigned long) * 8]; ++ unsigned long evtchn_mask[sizeof(unsigned long) * 8]; ++ ++ /* ++ * Wallclock time: updated only by control software. Guests should base ++ * their gettimeofday() syscall on this wallclock-base value. ++ */ ++ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */ ++ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ ++ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */ ++ ++ struct arch_shared_info arch; ++ ++}; ++#ifndef __XEN__ ++typedef struct shared_info shared_info_t; ++#endif ++ ++/* ++ * Start-of-day memory layout: ++ * 1. The domain is started within contiguous virtual-memory region. ++ * 2. The contiguous region ends on an aligned 4MB boundary. ++ * 3. This the order of bootstrap elements in the initial virtual region: ++ * a. relocated kernel image ++ * b. initial ram disk [mod_start, mod_len] ++ * c. list of allocated page frames [mfn_list, nr_pages] ++ * d. start_info_t structure [register ESI (x86)] ++ * e. bootstrap page tables [pt_base, CR3 (x86)] ++ * f. bootstrap stack [register ESP (x86)] ++ * 4. Bootstrap elements are packed together, but each is 4kB-aligned. ++ * 5. The initial ram disk may be omitted. ++ * 6. The list of page frames forms a contiguous 'pseudo-physical' memory ++ * layout for the domain. In particular, the bootstrap virtual-memory ++ * region is a 1:1 mapping to the first section of the pseudo-physical map. ++ * 7. All bootstrap elements are mapped read-writable for the guest OS. The ++ * only exception is the bootstrap page table, which is mapped read-only. ++ * 8. There is guaranteed to be at least 512kB padding after the final ++ * bootstrap element. If necessary, the bootstrap virtual region is ++ * extended by an extra 4MB to ensure this. ++ */ ++ ++#define MAX_GUEST_CMDLINE 1024 ++struct start_info { ++ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ ++ char magic[32]; /* "xen-<version>-<platform>". */ ++ unsigned long nr_pages; /* Total pages allocated to this domain. */ ++ unsigned long shared_info; /* MACHINE address of shared info struct. */ ++ uint32_t flags; /* SIF_xxx flags. */ ++ xen_pfn_t store_mfn; /* MACHINE page number of shared page. */ ++ uint32_t store_evtchn; /* Event channel for store communication. */ ++ union { ++ struct { ++ xen_pfn_t mfn; /* MACHINE page number of console page. */ ++ uint32_t evtchn; /* Event channel for console page. */ ++ } domU; ++ struct { ++ uint32_t info_off; /* Offset of console_info struct. */ ++ uint32_t info_size; /* Size of console_info struct from start.*/ ++ } dom0; ++ } console; ++ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */ ++ unsigned long pt_base; /* VIRTUAL address of page directory. */ ++ unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */ ++ unsigned long mfn_list; /* VIRTUAL address of page-frame list. */ ++ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ ++ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ ++ int8_t cmd_line[MAX_GUEST_CMDLINE]; ++}; ++typedef struct start_info start_info_t; ++ ++/* New console union for dom0 introduced in 0x00030203. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030203 ++#define console_mfn console.domU.mfn ++#define console_evtchn console.domU.evtchn ++#endif ++ ++/* These flags are passed in the 'flags' field of start_info_t. */ ++#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */ ++#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */ ++ ++typedef struct dom0_vga_console_info { ++ uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */ ++#define XEN_VGATYPE_TEXT_MODE_3 0x03 ++#define XEN_VGATYPE_VESA_LFB 0x23 ++ ++ union { ++ struct { ++ /* Font height, in pixels. */ ++ uint16_t font_height; ++ /* Cursor location (column, row). */ ++ uint16_t cursor_x, cursor_y; ++ /* Number of rows and columns (dimensions in characters). */ ++ uint16_t rows, columns; ++ } text_mode_3; ++ ++ struct { ++ /* Width and height, in pixels. */ ++ uint16_t width, height; ++ /* Bytes per scan line. */ ++ uint16_t bytes_per_line; ++ /* Bits per pixel. */ ++ uint16_t bits_per_pixel; ++ /* LFB physical address, and size (in units of 64kB). */ ++ uint32_t lfb_base; ++ uint32_t lfb_size; ++ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */ ++ uint8_t red_pos, red_size; ++ uint8_t green_pos, green_size; ++ uint8_t blue_pos, blue_size; ++ uint8_t rsvd_pos, rsvd_size; ++ } vesa_lfb; ++ } u; ++} dom0_vga_console_info_t; ++ ++typedef uint8_t xen_domain_handle_t[16]; ++ ++/* Turn a plain number into a C unsigned long constant. */ ++#define __mk_unsigned_long(x) x ## UL ++#define mk_unsigned_long(x) __mk_unsigned_long(x) ++ ++DEFINE_XEN_GUEST_HANDLE(uint8_t); ++DEFINE_XEN_GUEST_HANDLE(uint16_t); ++DEFINE_XEN_GUEST_HANDLE(uint32_t); ++DEFINE_XEN_GUEST_HANDLE(uint64_t); ++ ++#else /* __ASSEMBLY__ */ ++ ++/* In assembly code we cannot use C numeric constant suffixes. */ ++#define mk_unsigned_long(x) x ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* Default definitions for macros used by domctl/sysctl. */ ++#if defined(__XEN__) || defined(__XEN_TOOLS__) ++#ifndef uint64_aligned_t ++#define uint64_aligned_t uint64_t ++#endif ++#ifndef XEN_GUEST_HANDLE_64 ++#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name) ++#endif ++#endif ++ ++#endif /* __XEN_PUBLIC_XEN_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/xencomm.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/xencomm.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,41 @@ ++/* ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) IBM Corp. 2006 ++ */ ++ ++#ifndef _XEN_XENCOMM_H_ ++#define _XEN_XENCOMM_H_ ++ ++/* A xencomm descriptor is a scatter/gather list containing physical ++ * addresses corresponding to a virtually contiguous memory area. The ++ * hypervisor translates these physical addresses to machine addresses to copy ++ * to and from the virtually contiguous area. ++ */ ++ ++#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */ ++#define XENCOMM_INVALID (~0UL) ++ ++struct xencomm_desc { ++ uint32_t magic; ++ uint32_t nr_addrs; /* the number of entries in address[] */ ++ uint64_t address[0]; ++}; ++ ++#endif /* _XEN_XENCOMM_H_ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/interface/xenoprof.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/interface/xenoprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,132 @@ ++/****************************************************************************** ++ * xenoprof.h ++ * ++ * Interface for enabling system wide profiling based on hardware performance ++ * counters ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Copyright (C) 2005 Hewlett-Packard Co. ++ * Written by Aravind Menon & Jose Renato Santos ++ */ ++ ++#ifndef __XEN_PUBLIC_XENOPROF_H__ ++#define __XEN_PUBLIC_XENOPROF_H__ ++ ++#include "xen.h" ++ ++/* ++ * Commands to HYPERVISOR_xenoprof_op(). ++ */ ++#define XENOPROF_init 0 ++#define XENOPROF_reset_active_list 1 ++#define XENOPROF_reset_passive_list 2 ++#define XENOPROF_set_active 3 ++#define XENOPROF_set_passive 4 ++#define XENOPROF_reserve_counters 5 ++#define XENOPROF_counter 6 ++#define XENOPROF_setup_events 7 ++#define XENOPROF_enable_virq 8 ++#define XENOPROF_start 9 ++#define XENOPROF_stop 10 ++#define XENOPROF_disable_virq 11 ++#define XENOPROF_release_counters 12 ++#define XENOPROF_shutdown 13 ++#define XENOPROF_get_buffer 14 ++#define XENOPROF_last_op 14 ++ ++#define MAX_OPROF_EVENTS 32 ++#define MAX_OPROF_DOMAINS 25 ++#define XENOPROF_CPU_TYPE_SIZE 64 ++ ++/* Xenoprof performance events (not Xen events) */ ++struct event_log { ++ uint64_t eip; ++ uint8_t mode; ++ uint8_t event; ++}; ++ ++/* Xenoprof buffer shared between Xen and domain - 1 per VCPU */ ++struct xenoprof_buf { ++ uint32_t event_head; ++ uint32_t event_tail; ++ uint32_t event_size; ++ uint32_t vcpu_id; ++ uint64_t xen_samples; ++ uint64_t kernel_samples; ++ uint64_t user_samples; ++ uint64_t lost_samples; ++ struct event_log event_log[1]; ++}; ++#ifndef __XEN__ ++typedef struct xenoprof_buf xenoprof_buf_t; ++DEFINE_XEN_GUEST_HANDLE(xenoprof_buf_t); ++#endif ++ ++struct xenoprof_init { ++ int32_t num_events; ++ int32_t is_primary; ++ char cpu_type[XENOPROF_CPU_TYPE_SIZE]; ++}; ++typedef struct xenoprof_init xenoprof_init_t; ++DEFINE_XEN_GUEST_HANDLE(xenoprof_init_t); ++ ++struct xenoprof_get_buffer { ++ int32_t max_samples; ++ int32_t nbuf; ++ int32_t bufsize; ++ uint64_t buf_gmaddr; ++}; ++typedef struct xenoprof_get_buffer xenoprof_get_buffer_t; ++DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t); ++ ++struct xenoprof_counter { ++ uint32_t ind; ++ uint64_t count; ++ uint32_t enabled; ++ uint32_t event; ++ uint32_t hypervisor; ++ uint32_t kernel; ++ uint32_t user; ++ uint64_t unit_mask; ++}; ++typedef struct xenoprof_counter xenoprof_counter_t; ++DEFINE_XEN_GUEST_HANDLE(xenoprof_counter_t); ++ ++typedef struct xenoprof_passive { ++ uint16_t domain_id; ++ int32_t max_samples; ++ int32_t nbuf; ++ int32_t bufsize; ++ uint64_t buf_gmaddr; ++} xenoprof_passive_t; ++DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t); ++ ++ ++#endif /* __XEN_PUBLIC_XENOPROF_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/pcifront.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/pcifront.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,76 @@ ++/* ++ * PCI Frontend - arch-dependendent declarations ++ * ++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil> ++ */ ++#ifndef __XEN_ASM_PCIFRONT_H__ ++#define __XEN_ASM_PCIFRONT_H__ ++ ++#include <linux/spinlock.h> ++ ++#ifdef __KERNEL__ ++ ++#ifndef __ia64__ ++ ++struct pcifront_device; ++struct pci_bus; ++ ++struct pcifront_sd { ++ int domain; ++ struct pcifront_device *pdev; ++}; ++ ++static inline struct pcifront_device * ++pcifront_get_pdev(struct pcifront_sd *sd) ++{ ++ return sd->pdev; ++} ++ ++static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, ++ struct pcifront_device *pdev) ++{ ++ sd->domain = domain; ++ sd->pdev = pdev; ++} ++ ++#if defined(CONFIG_PCI_DOMAINS) ++static inline int pci_domain_nr(struct pci_bus *bus) ++{ ++ struct pcifront_sd *sd = bus->sysdata; ++ return sd->domain; ++} ++static inline int pci_proc_domain(struct pci_bus *bus) ++{ ++ return pci_domain_nr(bus); ++} ++#endif /* CONFIG_PCI_DOMAINS */ ++ ++#else /* __ia64__ */ ++ ++#include <asm/pci.h> ++#define pcifront_sd pci_controller ++ ++static inline struct pcifront_device * ++pcifront_get_pdev(struct pcifront_sd *sd) ++{ ++ return (struct pcifront_device *)sd->platform_data; ++} ++ ++static inline void pcifront_init_sd(struct pcifront_sd *sd, int domain, ++ struct pcifront_device *pdev) ++{ ++ sd->segment = domain; ++ sd->acpi_handle = NULL; ++ sd->iommu = NULL; ++ sd->windows = 0; ++ sd->window = NULL; ++ sd->platform_data = pdev; ++} ++ ++#endif /* __ia64__ */ ++ ++extern struct rw_semaphore pci_bus_sem; ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __XEN_ASM_PCIFRONT_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/public/evtchn.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/public/evtchn.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,88 @@ ++/****************************************************************************** ++ * evtchn.h ++ * ++ * Interface to /dev/xen/evtchn. ++ * ++ * Copyright (c) 2003-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __LINUX_PUBLIC_EVTCHN_H__ ++#define __LINUX_PUBLIC_EVTCHN_H__ ++ ++/* ++ * Bind a fresh port to VIRQ @virq. ++ * Return allocated port. ++ */ ++#define IOCTL_EVTCHN_BIND_VIRQ \ ++ _IOC(_IOC_NONE, 'E', 0, sizeof(struct ioctl_evtchn_bind_virq)) ++struct ioctl_evtchn_bind_virq { ++ unsigned int virq; ++}; ++ ++/* ++ * Bind a fresh port to remote <@remote_domain, @remote_port>. ++ * Return allocated port. ++ */ ++#define IOCTL_EVTCHN_BIND_INTERDOMAIN \ ++ _IOC(_IOC_NONE, 'E', 1, sizeof(struct ioctl_evtchn_bind_interdomain)) ++struct ioctl_evtchn_bind_interdomain { ++ unsigned int remote_domain, remote_port; ++}; ++ ++/* ++ * Allocate a fresh port for binding to @remote_domain. ++ * Return allocated port. ++ */ ++#define IOCTL_EVTCHN_BIND_UNBOUND_PORT \ ++ _IOC(_IOC_NONE, 'E', 2, sizeof(struct ioctl_evtchn_bind_unbound_port)) ++struct ioctl_evtchn_bind_unbound_port { ++ unsigned int remote_domain; ++}; ++ ++/* ++ * Unbind previously allocated @port. ++ */ ++#define IOCTL_EVTCHN_UNBIND \ ++ _IOC(_IOC_NONE, 'E', 3, sizeof(struct ioctl_evtchn_unbind)) ++struct ioctl_evtchn_unbind { ++ unsigned int port; ++}; ++ ++/* ++ * Unbind previously allocated @port. ++ */ ++#define IOCTL_EVTCHN_NOTIFY \ ++ _IOC(_IOC_NONE, 'E', 4, sizeof(struct ioctl_evtchn_notify)) ++struct ioctl_evtchn_notify { ++ unsigned int port; ++}; ++ ++/* Clear and reinitialise the event buffer. Clear error condition. */ ++#define IOCTL_EVTCHN_RESET \ ++ _IOC(_IOC_NONE, 'E', 5, 0) ++ ++#endif /* __LINUX_PUBLIC_EVTCHN_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/public/gntdev.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/public/gntdev.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,105 @@ ++/****************************************************************************** ++ * gntdev.h ++ * ++ * Interface to /dev/xen/gntdev. ++ * ++ * Copyright (c) 2007, D G Murray ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __LINUX_PUBLIC_GNTDEV_H__ ++#define __LINUX_PUBLIC_GNTDEV_H__ ++ ++struct ioctl_gntdev_grant_ref { ++ /* The domain ID of the grant to be mapped. */ ++ uint32_t domid; ++ /* The grant reference of the grant to be mapped. */ ++ uint32_t ref; ++}; ++ ++/* ++ * Inserts the grant references into the mapping table of an instance ++ * of gntdev. N.B. This does not perform the mapping, which is deferred ++ * until mmap() is called with @index as the offset. ++ */ ++#define IOCTL_GNTDEV_MAP_GRANT_REF \ ++_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref)) ++struct ioctl_gntdev_map_grant_ref { ++ /* IN parameters */ ++ /* The number of grants to be mapped. */ ++ uint32_t count; ++ uint32_t pad; ++ /* OUT parameters */ ++ /* The offset to be used on a subsequent call to mmap(). */ ++ uint64_t index; ++ /* Variable IN parameter. */ ++ /* Array of grant references, of size @count. */ ++ struct ioctl_gntdev_grant_ref refs[1]; ++}; ++ ++/* ++ * Removes the grant references from the mapping table of an instance of ++ * of gntdev. N.B. munmap() must be called on the relevant virtual address(es) ++ * before this ioctl is called, or an error will result. ++ */ ++#define IOCTL_GNTDEV_UNMAP_GRANT_REF \ ++_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref)) ++struct ioctl_gntdev_unmap_grant_ref { ++ /* IN parameters */ ++ /* The offset was returned by the corresponding map operation. */ ++ uint64_t index; ++ /* The number of pages to be unmapped. */ ++ uint32_t count; ++ uint32_t pad; ++}; ++ ++/* ++ * Returns the offset in the driver's address space that corresponds ++ * to @vaddr. This can be used to perform a munmap(), followed by an ++ * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by ++ * the caller. The number of pages that were allocated at the same time as ++ * @vaddr is returned in @count. ++ * ++ * N.B. Where more than one page has been mapped into a contiguous range, the ++ * supplied @vaddr must correspond to the start of the range; otherwise ++ * an error will result. It is only possible to munmap() the entire ++ * contiguously-allocated range at once, and not any subrange thereof. ++ */ ++#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \ ++_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr)) ++struct ioctl_gntdev_get_offset_for_vaddr { ++ /* IN parameters */ ++ /* The virtual address of the first mapped page in a range. */ ++ uint64_t vaddr; ++ /* OUT parameters */ ++ /* The offset that was used in the initial mmap() operation. */ ++ uint64_t offset; ++ /* The number of pages mapped in the VM area that begins at @vaddr. */ ++ uint32_t count; ++ uint32_t pad; ++}; ++ ++#endif /* __LINUX_PUBLIC_GNTDEV_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/public/privcmd.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/public/privcmd.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,79 @@ ++/****************************************************************************** ++ * privcmd.h ++ * ++ * Interface to /proc/xen/privcmd. ++ * ++ * Copyright (c) 2003-2005, K A Fraser ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __LINUX_PUBLIC_PRIVCMD_H__ ++#define __LINUX_PUBLIC_PRIVCMD_H__ ++ ++#include <linux/types.h> ++ ++#ifndef __user ++#define __user ++#endif ++ ++typedef struct privcmd_hypercall ++{ ++ __u64 op; ++ __u64 arg[5]; ++} privcmd_hypercall_t; ++ ++typedef struct privcmd_mmap_entry { ++ __u64 va; ++ __u64 mfn; ++ __u64 npages; ++} privcmd_mmap_entry_t; ++ ++typedef struct privcmd_mmap { ++ int num; ++ domid_t dom; /* target domain */ ++ privcmd_mmap_entry_t __user *entry; ++} privcmd_mmap_t; ++ ++typedef struct privcmd_mmapbatch { ++ int num; /* number of pages to populate */ ++ domid_t dom; /* target domain */ ++ __u64 addr; /* virtual address */ ++ xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */ ++} privcmd_mmapbatch_t; ++ ++/* ++ * @cmd: IOCTL_PRIVCMD_HYPERCALL ++ * @arg: &privcmd_hypercall_t ++ * Return: Value returned from execution of the specified hypercall. ++ */ ++#define IOCTL_PRIVCMD_HYPERCALL \ ++ _IOC(_IOC_NONE, 'P', 0, sizeof(privcmd_hypercall_t)) ++#define IOCTL_PRIVCMD_MMAP \ ++ _IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t)) ++#define IOCTL_PRIVCMD_MMAPBATCH \ ++ _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t)) ++ ++#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/xen_proc.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/xen_proc.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,12 @@ ++ ++#ifndef __ASM_XEN_PROC_H__ ++#define __ASM_XEN_PROC_H__ ++ ++#include <linux/proc_fs.h> ++ ++extern struct proc_dir_entry *create_xen_proc_entry( ++ const char *name, mode_t mode); ++extern void remove_xen_proc_entry( ++ const char *name); ++ ++#endif /* __ASM_XEN_PROC_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/xenbus.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/xenbus.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,302 @@ ++/****************************************************************************** ++ * xenbus.h ++ * ++ * Talks to Xen Store to figure out what devices we have. ++ * ++ * Copyright (C) 2005 Rusty Russell, IBM Corporation ++ * Copyright (C) 2005 XenSource Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef _XEN_XENBUS_H ++#define _XEN_XENBUS_H ++ ++#include <linux/device.h> ++#include <linux/notifier.h> ++#include <linux/mutex.h> ++#include <linux/completion.h> ++#include <linux/init.h> ++#include <xen/interface/xen.h> ++#include <xen/interface/grant_table.h> ++#include <xen/interface/io/xenbus.h> ++#include <xen/interface/io/xs_wire.h> ++ ++/* Register callback to watch this node. */ ++struct xenbus_watch ++{ ++ struct list_head list; ++ ++ /* Path being watched. */ ++ const char *node; ++ ++ /* Callback (executed in a process context with no locks held). */ ++ void (*callback)(struct xenbus_watch *, ++ const char **vec, unsigned int len); ++ ++ /* See XBWF_ definitions below. */ ++ unsigned long flags; ++}; ++ ++/* ++ * Execute callback in its own kthread. Useful if the callback is long ++ * running or heavily serialised, to avoid taking out the main xenwatch thread ++ * for a long period of time (or even unwittingly causing a deadlock). ++ */ ++#define XBWF_new_thread 1 ++ ++/* A xenbus device. */ ++struct xenbus_device { ++ const char *devicetype; ++ const char *nodename; ++ const char *otherend; ++ int otherend_id; ++ struct xenbus_watch otherend_watch; ++ struct device dev; ++ enum xenbus_state state; ++ struct completion down; ++}; ++ ++static inline struct xenbus_device *to_xenbus_device(struct device *dev) ++{ ++ return container_of(dev, struct xenbus_device, dev); ++} ++ ++struct xenbus_device_id ++{ ++ /* .../device/<device_type>/<identifier> */ ++ char devicetype[32]; /* General class of device. */ ++}; ++ ++/* A xenbus driver. */ ++struct xenbus_driver { ++ char *name; ++ struct module *owner; ++ const struct xenbus_device_id *ids; ++ int (*probe)(struct xenbus_device *dev, ++ const struct xenbus_device_id *id); ++ void (*otherend_changed)(struct xenbus_device *dev, ++ enum xenbus_state backend_state); ++ int (*remove)(struct xenbus_device *dev); ++ int (*suspend)(struct xenbus_device *dev); ++ int (*suspend_cancel)(struct xenbus_device *dev); ++ int (*resume)(struct xenbus_device *dev); ++ int (*uevent)(struct xenbus_device *, char **, int, char *, int); ++ struct device_driver driver; ++ int (*read_otherend_details)(struct xenbus_device *dev); ++}; ++ ++static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) ++{ ++ return container_of(drv, struct xenbus_driver, driver); ++} ++ ++int xenbus_register_frontend(struct xenbus_driver *drv); ++int xenbus_register_backend(struct xenbus_driver *drv); ++void xenbus_unregister_driver(struct xenbus_driver *drv); ++ ++struct xenbus_transaction ++{ ++ u32 id; ++}; ++ ++/* Nil transaction ID. */ ++#define XBT_NIL ((struct xenbus_transaction) { 0 }) ++ ++char **xenbus_directory(struct xenbus_transaction t, ++ const char *dir, const char *node, unsigned int *num); ++void *xenbus_read(struct xenbus_transaction t, ++ const char *dir, const char *node, unsigned int *len); ++int xenbus_write(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *string); ++int xenbus_mkdir(struct xenbus_transaction t, ++ const char *dir, const char *node); ++int xenbus_exists(struct xenbus_transaction t, ++ const char *dir, const char *node); ++int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node); ++int xenbus_transaction_start(struct xenbus_transaction *t); ++int xenbus_transaction_end(struct xenbus_transaction t, int abort); ++ ++/* Single read and scanf: returns -errno or num scanned if > 0. */ ++int xenbus_scanf(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *fmt, ...) ++ __attribute__((format(scanf, 4, 5))); ++ ++/* Single printf and write: returns -errno or 0. */ ++int xenbus_printf(struct xenbus_transaction t, ++ const char *dir, const char *node, const char *fmt, ...) ++ __attribute__((format(printf, 4, 5))); ++ ++/* Generic read function: NULL-terminated triples of name, ++ * sprintf-style type string, and pointer. Returns 0 or errno.*/ ++int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); ++ ++/* notifer routines for when the xenstore comes up */ ++int register_xenstore_notifier(struct notifier_block *nb); ++void unregister_xenstore_notifier(struct notifier_block *nb); ++ ++int register_xenbus_watch(struct xenbus_watch *watch); ++void unregister_xenbus_watch(struct xenbus_watch *watch); ++void xs_suspend(void); ++void xs_resume(void); ++void xs_suspend_cancel(void); ++ ++/* Used by xenbus_dev to borrow kernel's store connection. */ ++void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); ++ ++/* Prepare for domain suspend: then resume or cancel the suspend. */ ++void xenbus_suspend(void); ++void xenbus_resume(void); ++void xenbus_suspend_cancel(void); ++ ++#define XENBUS_IS_ERR_READ(str) ({ \ ++ if (!IS_ERR(str) && strlen(str) == 0) { \ ++ kfree(str); \ ++ str = ERR_PTR(-ERANGE); \ ++ } \ ++ IS_ERR(str); \ ++}) ++ ++#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) ++ ++ ++/** ++ * Register a watch on the given path, using the given xenbus_watch structure ++ * for storage, and the given callback function as the callback. Return 0 on ++ * success, or -errno on error. On success, the given path will be saved as ++ * watch->node, and remains the caller's to free. On error, watch->node will ++ * be NULL, the device will switch to XenbusStateClosing, and the error will ++ * be saved in the store. ++ */ ++int xenbus_watch_path(struct xenbus_device *dev, const char *path, ++ struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)); ++ ++ ++/** ++ * Register a watch on the given path/path2, using the given xenbus_watch ++ * structure for storage, and the given callback function as the callback. ++ * Return 0 on success, or -errno on error. On success, the watched path ++ * (path/path2) will be saved as watch->node, and becomes the caller's to ++ * kfree(). On error, watch->node will be NULL, so the caller has nothing to ++ * free, the device will switch to XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ ++int xenbus_watch_path2(struct xenbus_device *dev, const char *path, ++ const char *path2, struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)); ++ ++ ++/** ++ * Advertise in the store a change of the given driver to the given new_state. ++ * Return 0 on success, or -errno on error. On error, the device will switch ++ * to XenbusStateClosing, and the error will be saved in the store. ++ */ ++int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); ++ ++ ++/** ++ * Grant access to the given ring_mfn to the peer of the given device. Return ++ * 0 on success, or -errno on error. On error, the device will switch to ++ * XenbusStateClosing, and the error will be saved in the store. ++ */ ++int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); ++ ++ ++/** ++ * Map a page of memory into this domain from another domain's grant table. ++ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the ++ * page to that address, and sets *vaddr to that address. ++ * xenbus_map_ring does not allocate the virtual address space (you must do ++ * this yourself!). It only maps in the page to the specified address. ++ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) ++ * or -ENOMEM on error. If an error is returned, device will switch to ++ * XenbusStateClosing and the error message will be saved in XenStore. ++ */ ++struct vm_struct *xenbus_map_ring_valloc(struct xenbus_device *dev, ++ int gnt_ref); ++int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, ++ grant_handle_t *handle, void *vaddr); ++ ++ ++/** ++ * Unmap a page of memory in this domain that was imported from another domain. ++ * Use xenbus_unmap_ring_vfree if you mapped in your memory with ++ * xenbus_map_ring_valloc (it will free the virtual address space). ++ * Returns 0 on success and returns GNTST_* on error ++ * (see xen/include/interface/grant_table.h). ++ */ ++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, struct vm_struct *); ++int xenbus_unmap_ring(struct xenbus_device *dev, ++ grant_handle_t handle, void *vaddr); ++ ++ ++/** ++ * Allocate an event channel for the given xenbus_device, assigning the newly ++ * created local port to *port. Return 0 on success, or -errno on error. On ++ * error, the device will switch to XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ ++int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); ++ ++ ++/** ++ * Free an existing event channel. Returns 0 on success or -errno on error. ++ */ ++int xenbus_free_evtchn(struct xenbus_device *dev, int port); ++ ++ ++/** ++ * Return the state of the driver rooted at the given store path, or ++ * XenbusStateUnknown if no state can be read. ++ */ ++enum xenbus_state xenbus_read_driver_state(const char *path); ++ ++ ++/*** ++ * Report the given negative errno into the store, along with the given ++ * formatted message. ++ */ ++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ ...); ++ ++ ++/*** ++ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by ++ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly ++ * closedown of this driver and its peer. ++ */ ++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ++ ...); ++ ++int xenbus_dev_init(void); ++ ++const char *xenbus_strstate(enum xenbus_state state); ++int xenbus_dev_is_online(struct xenbus_device *dev); ++int xenbus_frontend_closed(struct xenbus_device *dev); ++ ++#endif /* _XEN_XENBUS_H */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/xencons.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/xencons.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,19 @@ ++#ifndef __ASM_XENCONS_H__ ++#define __ASM_XENCONS_H__ ++ ++struct dom0_vga_console_info; ++void dom0_init_screen_info(const struct dom0_vga_console_info *info); ++ ++void xencons_force_flush(void); ++void xencons_resume(void); ++ ++/* Interrupt work hooks. Receive data, or kick data out. */ ++void xencons_rx(char *buf, unsigned len); ++void xencons_tx(void); ++ ++int xencons_ring_init(void); ++int xencons_ring_send(const char *data, unsigned len); ++ ++void xencons_early_setup(void); ++ ++#endif /* __ASM_XENCONS_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 include/xen/xenoprof.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/xen/xenoprof.h Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,42 @@ ++/****************************************************************************** ++ * xen/xenoprof.h ++ * ++ * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> ++ * VA Linux Systems Japan K.K. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#ifndef __XEN_XENOPROF_H__ ++#define __XEN_XENOPROF_H__ ++#ifdef CONFIG_XEN ++ ++#include <asm/xenoprof.h> ++ ++struct oprofile_operations; ++int xenoprofile_init(struct oprofile_operations * ops); ++void xenoprofile_exit(void); ++ ++struct xenoprof_shared_buffer { ++ char *buffer; ++ struct xenoprof_arch_shared_buffer arch; ++}; ++#else ++#define xenoprofile_init(ops) (-ENOSYS) ++#define xenoprofile_exit() do { } while (0) ++ ++#endif /* CONFIG_XEN */ ++#endif /* __XEN_XENOPROF_H__ */ +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/Kconfig.preempt +--- a/kernel/Kconfig.preempt Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/Kconfig.preempt Wed Aug 08 16:25:28 2007 -0300 +@@ -35,6 +35,7 @@ config PREEMPT_VOLUNTARY + + config PREEMPT + bool "Preemptible Kernel (Low-Latency Desktop)" ++ depends on !XEN + help + This option reduces the latency of the kernel by making + all kernel code (that is not executing in a critical section) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/fork.c +--- a/kernel/fork.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/fork.c Wed Aug 08 16:25:28 2007 -0300 +@@ -286,6 +286,9 @@ static inline int dup_mmap(struct mm_str + if (retval) + goto out; + } ++#ifdef arch_dup_mmap ++ arch_dup_mmap(mm, oldmm); ++#endif + retval = 0; + out: + up_write(&mm->mmap_sem); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/irq/manage.c +--- a/kernel/irq/manage.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/irq/manage.c Wed Aug 08 16:25:28 2007 -0300 +@@ -30,6 +30,7 @@ void synchronize_irq(unsigned int irq) + { + struct irq_desc *desc = irq_desc + irq; + ++ WARN_ON(in_interrupt()); + if (irq >= NR_IRQS) + return; + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/irq/spurious.c +--- a/kernel/irq/spurious.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/irq/spurious.c Wed Aug 08 16:25:28 2007 -0300 +@@ -139,7 +139,8 @@ void note_interrupt(unsigned int irq, st + irqreturn_t action_ret) + { + if (unlikely(action_ret != IRQ_HANDLED)) { +- desc->irqs_unhandled++; ++ if (!irq_ignore_unhandled(irq)) ++ desc->irqs_unhandled++; + if (unlikely(action_ret != IRQ_NONE)) + report_bad_irq(irq, desc, action_ret); + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/kexec.c +--- a/kernel/kexec.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/kexec.c Wed Aug 08 16:25:28 2007 -0300 +@@ -331,13 +331,27 @@ static int kimage_is_destination_range(s + return 0; + } + +-static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) ++static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order, unsigned long limit) + { + struct page *pages; + + pages = alloc_pages(gfp_mask, order); + if (pages) { + unsigned int count, i; ++#ifdef CONFIG_XEN ++ int address_bits; ++ ++ if (limit == ~0UL) ++ address_bits = BITS_PER_LONG; ++ else ++ address_bits = ilog2(limit); ++ ++ if (xen_create_contiguous_region((unsigned long)page_address(pages), ++ order, address_bits) < 0) { ++ __free_pages(pages, order); ++ return NULL; ++ } ++#endif + pages->mapping = NULL; + set_page_private(pages, order); + count = 1 << order; +@@ -356,6 +370,9 @@ static void kimage_free_pages(struct pag + count = 1 << order; + for (i = 0; i < count; i++) + ClearPageReserved(page + i); ++#ifdef CONFIG_XEN ++ xen_destroy_contiguous_region((unsigned long)page_address(page), order); ++#endif + __free_pages(page, order); + } + +@@ -401,10 +418,10 @@ static struct page *kimage_alloc_normal_ + do { + unsigned long pfn, epfn, addr, eaddr; + +- pages = kimage_alloc_pages(GFP_KERNEL, order); ++ pages = kimage_alloc_pages(GFP_KERNEL, order, KEXEC_CONTROL_MEMORY_LIMIT); + if (!pages) + break; +- pfn = page_to_pfn(pages); ++ pfn = kexec_page_to_pfn(pages); + epfn = pfn + count; + addr = pfn << PAGE_SHIFT; + eaddr = epfn << PAGE_SHIFT; +@@ -438,6 +455,7 @@ static struct page *kimage_alloc_normal_ + return pages; + } + ++#ifndef CONFIG_XEN + static struct page *kimage_alloc_crash_control_pages(struct kimage *image, + unsigned int order) + { +@@ -491,7 +509,7 @@ static struct page *kimage_alloc_crash_c + } + /* If I don't overlap any segments I have found my hole! */ + if (i == image->nr_segments) { +- pages = pfn_to_page(hole_start >> PAGE_SHIFT); ++ pages = kexec_pfn_to_page(hole_start >> PAGE_SHIFT); + break; + } + } +@@ -518,6 +536,13 @@ struct page *kimage_alloc_control_pages( + + return pages; + } ++#else /* !CONFIG_XEN */ ++struct page *kimage_alloc_control_pages(struct kimage *image, ++ unsigned int order) ++{ ++ return kimage_alloc_normal_control_pages(image, order); ++} ++#endif + + static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) + { +@@ -533,7 +558,7 @@ static int kimage_add_entry(struct kimag + return -ENOMEM; + + ind_page = page_address(page); +- *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; ++ *image->entry = kexec_virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = ind_page + + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); +@@ -594,13 +619,13 @@ static int kimage_terminate(struct kimag + #define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION)? \ +- phys_to_virt((entry & PAGE_MASK)): ptr +1) ++ kexec_phys_to_virt((entry & PAGE_MASK)): ptr +1) + + static void kimage_free_entry(kimage_entry_t entry) + { + struct page *page; + +- page = pfn_to_page(entry >> PAGE_SHIFT); ++ page = kexec_pfn_to_page(entry >> PAGE_SHIFT); + kimage_free_pages(page); + } + +@@ -611,6 +636,10 @@ static void kimage_free(struct kimage *i + + if (!image) + return; ++ ++#ifdef CONFIG_XEN ++ xen_machine_kexec_unload(image); ++#endif + + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { +@@ -687,7 +716,7 @@ static struct page *kimage_alloc_page(st + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, lru) { +- addr = page_to_pfn(page) << PAGE_SHIFT; ++ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->lru); + return page; +@@ -698,16 +727,16 @@ static struct page *kimage_alloc_page(st + kimage_entry_t *old; + + /* Allocate a page, if we run out of memory give up */ +- page = kimage_alloc_pages(gfp_mask, 0); ++ page = kimage_alloc_pages(gfp_mask, 0, KEXEC_SOURCE_MEMORY_LIMIT); + if (!page) + return NULL; + /* If the page cannot be used file it away */ +- if (page_to_pfn(page) > ++ if (kexec_page_to_pfn(page) > + (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->lru, &image->unuseable_pages); + continue; + } +- addr = page_to_pfn(page) << PAGE_SHIFT; ++ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) +@@ -730,7 +759,7 @@ static struct page *kimage_alloc_page(st + struct page *old_page; + + old_addr = *old & PAGE_MASK; +- old_page = pfn_to_page(old_addr >> PAGE_SHIFT); ++ old_page = kexec_pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + +@@ -780,7 +809,7 @@ static int kimage_load_normal_segment(st + result = -ENOMEM; + goto out; + } +- result = kimage_add_page(image, page_to_pfn(page) ++ result = kimage_add_page(image, kexec_page_to_pfn(page) + << PAGE_SHIFT); + if (result < 0) + goto out; +@@ -812,6 +841,7 @@ out: + return result; + } + ++#ifndef CONFIG_XEN + static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) + { +@@ -834,7 +864,7 @@ static int kimage_load_crash_segment(str + char *ptr; + size_t uchunk, mchunk; + +- page = pfn_to_page(maddr >> PAGE_SHIFT); ++ page = kexec_pfn_to_page(maddr >> PAGE_SHIFT); + if (page == 0) { + result = -ENOMEM; + goto out; +@@ -883,6 +913,13 @@ static int kimage_load_segment(struct ki + + return result; + } ++#else /* CONFIG_XEN */ ++static int kimage_load_segment(struct kimage *image, ++ struct kexec_segment *segment) ++{ ++ return kimage_load_normal_segment(image, segment); ++} ++#endif + + /* + * Exec Kernel system call: for obvious reasons only root may call it. +@@ -993,6 +1030,13 @@ asmlinkage long sys_kexec_load(unsigned + if (result) + goto out; + } ++#ifdef CONFIG_XEN ++ if (image) { ++ result = xen_machine_kexec_load(image); ++ if (result) ++ goto out; ++ } ++#endif + /* Install the new kernel, and Uninstall the old */ + image = xchg(dest_image, image); + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/softlockup.c +--- a/kernel/softlockup.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/softlockup.c Wed Aug 08 16:25:28 2007 -0300 +@@ -39,6 +39,19 @@ void touch_softlockup_watchdog(void) + __raw_get_cpu_var(touch_timestamp) = jiffies; + } + EXPORT_SYMBOL(touch_softlockup_watchdog); ++ ++unsigned long softlockup_get_next_event(void) ++{ ++ int this_cpu = smp_processor_id(); ++ unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu); ++ ++ if (per_cpu(print_timestamp, this_cpu) == touch_timestamp || ++ did_panic || ++ !per_cpu(watchdog_task, this_cpu)) ++ return MAX_JIFFY_OFFSET; ++ ++ return max_t(long, 0, touch_timestamp + HZ - jiffies); ++} + + /* + * This callback runs from the timer interrupt, and checks +diff -r 4a9ef6a03fd9 -r 85b796b085e5 kernel/timer.c +--- a/kernel/timer.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/kernel/timer.c Wed Aug 08 16:25:28 2007 -0300 +@@ -616,7 +616,9 @@ unsigned long next_timer_interrupt(void) + if (hr_expires < 3) + return hr_expires + jiffies; + } +- hr_expires += jiffies; ++ hr_expires = min_t(unsigned long, ++ softlockup_get_next_event(), ++ hr_expires) + jiffies; + + base = __get_cpu_var(tvec_bases); + spin_lock(&base->lock); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 lib/Makefile +--- a/lib/Makefile Wed Jul 18 12:23:24 2007 -0300 ++++ b/lib/Makefile Wed Aug 08 16:25:28 2007 -0300 +@@ -57,6 +57,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o + + obj-$(CONFIG_SWIOTLB) += swiotlb.o + obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o ++swiotlb-$(CONFIG_XEN) := ../arch/i386/kernel/swiotlb.o + + lib-$(CONFIG_GENERIC_BUG) += bug.o + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 mm/Kconfig +--- a/mm/Kconfig Wed Jul 18 12:23:24 2007 -0300 ++++ b/mm/Kconfig Wed Aug 08 16:25:28 2007 -0300 +@@ -132,11 +132,14 @@ config MEMORY_HOTPLUG_SPARSE + # Default to 4 for wider testing, though 8 might be more appropriate. + # ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. + # PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes. ++# XEN on x86 architecture uses the mapping field on pagetable pages to store a ++# pointer to the destructor. This conflicts with pte_lock_deinit(). + # + config SPLIT_PTLOCK_CPUS + int + default "4096" if ARM && !CPU_CACHE_VIPT + default "4096" if PARISC && !PA20 ++ default "4096" if X86_XEN || X86_64_XEN + default "4" + + # +diff -r 4a9ef6a03fd9 -r 85b796b085e5 mm/highmem.c +--- a/mm/highmem.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/mm/highmem.c Wed Aug 08 16:25:28 2007 -0300 +@@ -147,6 +147,17 @@ start: + + return vaddr; + } ++ ++#ifdef CONFIG_XEN ++void kmap_flush_unused(void) ++{ ++ spin_lock(&kmap_lock); ++ flush_all_zero_pkmaps(); ++ spin_unlock(&kmap_lock); ++} ++ ++EXPORT_SYMBOL(kmap_flush_unused); ++#endif + + void fastcall *kmap_high(struct page *page) + { +diff -r 4a9ef6a03fd9 -r 85b796b085e5 mm/memory.c +--- a/mm/memory.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/mm/memory.c Wed Aug 08 16:25:28 2007 -0300 +@@ -404,7 +404,8 @@ struct page *vm_normal_page(struct vm_ar + * and that the resulting page looks ok. + */ + if (unlikely(!pfn_valid(pfn))) { +- print_bad_pte(vma, pte, addr); ++ if (!(vma->vm_flags & VM_RESERVED)) ++ print_bad_pte(vma, pte, addr); + return NULL; + } + +@@ -662,8 +663,17 @@ static unsigned long zap_pte_range(struc + page->index > details->last_index)) + continue; + } ++#ifdef CONFIG_XEN ++ if (unlikely(vma->vm_ops && vma->vm_ops->zap_pte)) ++ ptent = vma->vm_ops->zap_pte(vma, addr, pte, ++ tlb->fullmm); ++ else ++ ptent = ptep_get_and_clear_full(mm, addr, pte, ++ tlb->fullmm); ++#else + ptent = ptep_get_and_clear_full(mm, addr, pte, + tlb->fullmm); ++#endif + tlb_remove_tlb_entry(tlb, pte, addr); + if (unlikely(!page)) + continue; +@@ -896,6 +906,7 @@ unsigned long zap_page_range(struct vm_a + tlb_finish_mmu(tlb, address, end); + return end; + } ++EXPORT_SYMBOL(zap_page_range); + + /* + * Do a quick page-table lookup for a single page. +@@ -1035,6 +1046,26 @@ int get_user_pages(struct task_struct *t + continue; + } + ++#ifdef CONFIG_XEN ++ if (vma && (vma->vm_flags & VM_FOREIGN)) { ++ struct page **map = vma->vm_private_data; ++ int offset = (start - vma->vm_start) >> PAGE_SHIFT; ++ if (map[offset] != NULL) { ++ if (pages) { ++ struct page *page = map[offset]; ++ ++ pages[i] = page; ++ get_page(page); ++ } ++ if (vmas) ++ vmas[i] = vma; ++ i++; ++ start += PAGE_SIZE; ++ len--; ++ continue; ++ } ++ } ++#endif + if (!vma || (vma->vm_flags & (VM_IO | VM_PFNMAP)) + || !(vm_flags & vma->vm_flags)) + return i ? : -EFAULT; +@@ -1403,6 +1434,102 @@ int remap_pfn_range(struct vm_area_struc + } + EXPORT_SYMBOL(remap_pfn_range); + ++#ifdef CONFIG_XEN ++static inline int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd, ++ unsigned long addr, unsigned long end, ++ pte_fn_t fn, void *data) ++{ ++ pte_t *pte; ++ int err; ++ struct page *pmd_page; ++ spinlock_t *ptl; ++ ++ pte = (mm == &init_mm) ? ++ pte_alloc_kernel(pmd, addr) : ++ pte_alloc_map_lock(mm, pmd, addr, &ptl); ++ if (!pte) ++ return -ENOMEM; ++ ++ BUG_ON(pmd_huge(*pmd)); ++ ++ pmd_page = pmd_page(*pmd); ++ ++ do { ++ err = fn(pte, pmd_page, addr, data); ++ if (err) ++ break; ++ } while (pte++, addr += PAGE_SIZE, addr != end); ++ ++ if (mm != &init_mm) ++ pte_unmap_unlock(pte-1, ptl); ++ return err; ++} ++ ++static inline int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud, ++ unsigned long addr, unsigned long end, ++ pte_fn_t fn, void *data) ++{ ++ pmd_t *pmd; ++ unsigned long next; ++ int err; ++ ++ pmd = pmd_alloc(mm, pud, addr); ++ if (!pmd) ++ return -ENOMEM; ++ do { ++ next = pmd_addr_end(addr, end); ++ err = apply_to_pte_range(mm, pmd, addr, next, fn, data); ++ if (err) ++ break; ++ } while (pmd++, addr = next, addr != end); ++ return err; ++} ++ ++static inline int apply_to_pud_range(struct mm_struct *mm, pgd_t *pgd, ++ unsigned long addr, unsigned long end, ++ pte_fn_t fn, void *data) ++{ ++ pud_t *pud; ++ unsigned long next; ++ int err; ++ ++ pud = pud_alloc(mm, pgd, addr); ++ if (!pud) ++ return -ENOMEM; ++ do { ++ next = pud_addr_end(addr, end); ++ err = apply_to_pmd_range(mm, pud, addr, next, fn, data); ++ if (err) ++ break; ++ } while (pud++, addr = next, addr != end); ++ return err; ++} ++ ++/* ++ * Scan a region of virtual memory, filling in page tables as necessary ++ * and calling a provided function on each leaf page table. ++ */ ++int apply_to_page_range(struct mm_struct *mm, unsigned long addr, ++ unsigned long size, pte_fn_t fn, void *data) ++{ ++ pgd_t *pgd; ++ unsigned long next; ++ unsigned long end = addr + size; ++ int err; ++ ++ BUG_ON(addr >= end); ++ pgd = pgd_offset(mm, addr); ++ do { ++ next = pgd_addr_end(addr, end); ++ err = apply_to_pud_range(mm, pgd, addr, next, fn, data); ++ if (err) ++ break; ++ } while (pgd++, addr = next, addr != end); ++ return err; ++} ++EXPORT_SYMBOL_GPL(apply_to_page_range); ++#endif ++ + /* + * handle_pte_fault chooses page fault handler according to an entry + * which was read non-atomically. Before making any commitment, on +@@ -1462,7 +1589,6 @@ static inline void cow_user_page(struct + if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) + memset(kaddr, 0, PAGE_SIZE); + kunmap_atomic(kaddr, KM_USER0); +- flush_dcache_page(dst); + return; + + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 mm/mmap.c +--- a/mm/mmap.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/mm/mmap.c Wed Aug 08 16:25:28 2007 -0300 +@@ -1976,6 +1976,10 @@ void exit_mmap(struct mm_struct *mm) + struct vm_area_struct *vma = mm->mmap; + unsigned long nr_accounted = 0; + unsigned long end; ++ ++#ifdef arch_exit_mmap ++ arch_exit_mmap(mm); ++#endif + + lru_add_drain(); + flush_cache_mm(mm); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 mm/page_alloc.c +--- a/mm/page_alloc.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/mm/page_alloc.c Wed Aug 08 16:25:28 2007 -0300 +@@ -199,7 +199,11 @@ static void bad_page(struct page *page) + 1 << PG_slab | + 1 << PG_swapcache | + 1 << PG_writeback | +- 1 << PG_buddy ); ++ 1 << PG_buddy | ++#ifdef CONFIG_X86_XEN ++ 1 << PG_pinned | ++#endif ++ 1 << PG_foreign ); + set_page_count(page, 0); + reset_page_mapcount(page); + page->mapping = NULL; +@@ -434,7 +438,11 @@ static inline int free_pages_check(struc + 1 << PG_swapcache | + 1 << PG_writeback | + 1 << PG_reserved | +- 1 << PG_buddy )))) ++ 1 << PG_buddy | ++#ifdef CONFIG_X86_XEN ++ 1 << PG_pinned | ++#endif ++ 1 << PG_foreign )))) + bad_page(page); + if (PageDirty(page)) + __ClearPageDirty(page); +@@ -490,6 +498,8 @@ static void __free_pages_ok(struct page + int i; + int reserved = 0; + ++ if (arch_free_page(page, order)) ++ return; + for (i = 0 ; i < (1 << order) ; ++i) + reserved += free_pages_check(page + i); + if (reserved) +@@ -497,7 +507,6 @@ static void __free_pages_ok(struct page + + if (!PageHighMem(page)) + debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order); +- arch_free_page(page, order); + kernel_map_pages(page, 1 << order, 0); + + local_irq_save(flags); +@@ -584,7 +593,11 @@ static int prep_new_page(struct page *pa + 1 << PG_swapcache | + 1 << PG_writeback | + 1 << PG_reserved | +- 1 << PG_buddy )))) ++ 1 << PG_buddy | ++#ifdef CONFIG_X86_XEN ++ 1 << PG_pinned | ++#endif ++ 1 << PG_foreign )))) + bad_page(page); + + /* +@@ -783,6 +796,9 @@ static void fastcall free_hot_cold_page( + struct zone *zone = page_zone(page); + struct per_cpu_pages *pcp; + unsigned long flags; ++ ++ if (arch_free_page(page, 0)) ++ return; + + if (PageAnon(page)) + page->mapping = NULL; +diff -r 4a9ef6a03fd9 -r 85b796b085e5 net/core/dev.c +--- a/net/core/dev.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/net/core/dev.c Wed Aug 08 16:25:28 2007 -0300 +@@ -117,6 +117,12 @@ + #include <linux/err.h> + #include <linux/ctype.h> + ++#ifdef CONFIG_XEN ++#include <net/ip.h> ++#include <linux/tcp.h> ++#include <linux/udp.h> ++#endif ++ + /* + * The list of packet types we will receive (as opposed to discard) + * and the routines to invoke. +@@ -1392,6 +1398,43 @@ out_kfree_skb: + } \ + } + ++#ifdef CONFIG_XEN ++inline int skb_checksum_setup(struct sk_buff *skb) ++{ ++ if (skb->proto_csum_blank) { ++ if (skb->protocol != htons(ETH_P_IP)) ++ goto out; ++ skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; ++ if (skb->h.raw >= skb->tail) ++ goto out; ++ switch (skb->nh.iph->protocol) { ++ case IPPROTO_TCP: ++ skb->csum = offsetof(struct tcphdr, check); ++ break; ++ case IPPROTO_UDP: ++ skb->csum = offsetof(struct udphdr, check); ++ break; ++ default: ++ if (net_ratelimit()) ++ printk(KERN_ERR "Attempting to checksum a non-" ++ "TCP/UDP packet, dropping a protocol" ++ " %d packet", skb->nh.iph->protocol); ++ goto out; ++ } ++ if ((skb->h.raw + skb->csum + 2) > skb->tail) ++ goto out; ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ skb->proto_csum_blank = 0; ++ } ++ return 0; ++out: ++ return -EPROTO; ++} ++#else ++inline int skb_checksum_setup(struct sk_buff *skb) { return 0; } ++#endif ++ ++ + /** + * dev_queue_xmit - transmit a buffer + * @skb: buffer to transmit +@@ -1423,6 +1466,12 @@ int dev_queue_xmit(struct sk_buff *skb) + struct net_device *dev = skb->dev; + struct Qdisc *q; + int rc = -ENOMEM; ++ ++ /* If a checksum-deferred packet is forwarded to a device that needs a ++ * checksum, correct the pointers and force checksumming. ++ */ ++ if (skb_checksum_setup(skb)) ++ goto out_kfree_skb; + + /* GSO will handle the following emulations directly. */ + if (netif_needs_gso(dev, skb)) +@@ -1796,6 +1845,19 @@ int netif_receive_skb(struct sk_buff *sk + if (skb->tc_verd & TC_NCLS) { + skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); + goto ncls; ++ } ++#endif ++ ++#ifdef CONFIG_XEN ++ switch (skb->ip_summed) { ++ case CHECKSUM_UNNECESSARY: ++ skb->proto_data_valid = 1; ++ break; ++ case CHECKSUM_PARTIAL: ++ /* XXX Implement me. */ ++ default: ++ skb->proto_data_valid = 0; ++ break; + } + #endif + +@@ -3565,6 +3627,7 @@ EXPORT_SYMBOL(net_enable_timestamp); + EXPORT_SYMBOL(net_enable_timestamp); + EXPORT_SYMBOL(net_disable_timestamp); + EXPORT_SYMBOL(dev_get_flags); ++EXPORT_SYMBOL(skb_checksum_setup); + + #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + EXPORT_SYMBOL(br_handle_frame_hook); +diff -r 4a9ef6a03fd9 -r 85b796b085e5 net/core/skbuff.c +--- a/net/core/skbuff.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/net/core/skbuff.c Wed Aug 08 16:25:28 2007 -0300 +@@ -243,6 +243,7 @@ struct sk_buff *alloc_skb_from_cache(str + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_segs = 0; + skb_shinfo(skb)->gso_type = 0; ++ skb_shinfo(skb)->ip6_frag_id = 0; + skb_shinfo(skb)->frag_list = NULL; + out: + return skb; +@@ -469,6 +470,10 @@ struct sk_buff *skb_clone(struct sk_buff + C(local_df); + n->cloned = 1; + n->nohdr = 0; ++#ifdef CONFIG_XEN ++ C(proto_data_valid); ++ C(proto_csum_blank); ++#endif + C(pkt_type); + C(ip_summed); + C(priority); +@@ -643,7 +648,6 @@ struct sk_buff *pskb_copy(struct sk_buff + n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + +- n->truesize += skb->data_len; + n->data_len = skb->data_len; + n->len = skb->len; + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 net/ipv4/netfilter/ip_nat_proto_tcp.c +--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c Wed Aug 08 16:25:28 2007 -0300 +@@ -129,8 +129,15 @@ tcp_manip_pkt(struct sk_buff **pskb, + if (hdrsize < sizeof(*hdr)) + return 1; + ++#ifdef CONFIG_XEN ++ if ((*pskb)->proto_csum_blank) ++ nf_csum_replace4(&hdr->check, oldip, newip); ++ else ++#endif ++ { + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); ++ } + return 1; + } + +diff -r 4a9ef6a03fd9 -r 85b796b085e5 net/ipv4/netfilter/ip_nat_proto_udp.c +--- a/net/ipv4/netfilter/ip_nat_proto_udp.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/net/ipv4/netfilter/ip_nat_proto_udp.c Wed Aug 08 16:25:28 2007 -0300 +@@ -115,8 +115,16 @@ udp_manip_pkt(struct sk_buff **pskb, + } + + if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { ++#ifdef CONFIG_XEN ++ if ((*pskb)->proto_csum_blank) ++ nf_csum_replace4(&hdr->check, oldip, newip); ++ else ++#endif ++ { + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); ++ } ++ + if (!hdr->check) + hdr->check = CSUM_MANGLED_0; + } +diff -r 4a9ef6a03fd9 -r 85b796b085e5 net/ipv4/xfrm4_output.c +--- a/net/ipv4/xfrm4_output.c Wed Jul 18 12:23:24 2007 -0300 ++++ b/net/ipv4/xfrm4_output.c Wed Aug 08 16:25:28 2007 -0300 +@@ -17,6 +17,8 @@ + #include <net/ip.h> + #include <net/xfrm.h> + #include <net/icmp.h> ++ ++extern int skb_checksum_setup(struct sk_buff *skb); + + static int xfrm4_tunnel_check_size(struct sk_buff *skb) + { +@@ -48,6 +50,10 @@ static int xfrm4_output_one(struct sk_bu + struct xfrm_state *x = dst->xfrm; + int err; + ++ err = skb_checksum_setup(skb); ++ if (err) ++ goto error_nolock; ++ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + err = skb_checksum_help(skb); + if (err) +diff -r 4a9ef6a03fd9 -r 85b796b085e5 scripts/Makefile.xen +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/scripts/Makefile.xen Wed Aug 08 16:25:28 2007 -0300 +@@ -0,0 +1,14 @@ ++ ++# cherrypickxen($1 = allobj) ++cherrypickxen = $(foreach var, $(1), \ ++ $(shell o=$(var); \ ++ c=$${o%.o}-xen.c; \ ++ s=$${o%.o}-xen.S; \ ++ oxen=$${o%.o}-xen.o; \ ++ [ -f $(srctree)/$(src)/$${c} ] || \ ++ [ -f $(srctree)/$(src)/$${s} ] \ ++ && echo $$oxen \ ++ || echo $(var) ) \ ++ ) ++# filterxen($1 = allobj, $2 = noobjs) ++filterxen = $(filter-out $(2), $(1)) diff --git a/tags/2.6.20-3/20952-linux-2.6-xen-x86_64-silence-up-apic-errors.patch b/tags/2.6.20-3/20952-linux-2.6-xen-x86_64-silence-up-apic-errors.patch new file mode 100644 index 0000000..788af81 --- /dev/null +++ b/tags/2.6.20-3/20952-linux-2.6-xen-x86_64-silence-up-apic-errors.patch @@ -0,0 +1,13 @@ +diff -r 00cc4568f10f arch/x86_64/kernel/apic-xen.c +--- a/arch/x86_64/kernel/apic-xen.c Tue Jul 25 21:07:37 2006 +0200 ++++ b/arch/x86_64/kernel/apic-xen.c Tue Jul 25 21:17:54 2006 +0200 +@@ -174,7 +174,8 @@ asmlinkage void smp_error_interrupt(void + 6: Received illegal vector + 7: Illegal register address + */ +- printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", ++ if (num_online_cpus() > 1) ++ printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", + smp_processor_id(), v , v1); + irq_exit(); + } diff --git a/tags/2.6.20-3/20957-linux-2.6-fix-x86_64-vgetcpu.patch b/tags/2.6.20-3/20957-linux-2.6-fix-x86_64-vgetcpu.patch new file mode 100644 index 0000000..17e0247 --- /dev/null +++ b/tags/2.6.20-3/20957-linux-2.6-fix-x86_64-vgetcpu.patch @@ -0,0 +1,65 @@ +--- linux-2.6.20.noarch/arch/x86_64/kernel/vsyscall.c~orig 2007-04-26 02:05:31.000000000 -0700 ++++ linux-2.6.20.noarch/arch/x86_64/kernel/vsyscall.c 2007-04-26 15:11:02.000000000 -0700 +@@ -40,6 +40,9 @@ + #include <asm/segment.h> + #include <asm/desc.h> + #include <asm/topology.h> ++#ifdef CONFIG_XEN ++#include <asm/hypercall.h> ++#endif + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + #define __syscall_clobber "r11","rcx","memory" +@@ -246,12 +249,11 @@ + + #endif + +-#ifndef CONFIG_XEN + /* Assume __initcall executes before all user space. Hopefully kmod + doesn't violate that. We'll find out if it does. */ + static void __cpuinit vsyscall_set_cpu(int cpu) + { +- unsigned long *d; ++ unsigned long *d, n; + unsigned long node = 0; + #ifdef CONFIG_NUMA + node = cpu_to_node[cpu]; +@@ -263,10 +265,15 @@ + in user space in vgetcpu. + 12 bits for the CPU and 8 bits for the node. */ + d = (unsigned long *)(cpu_gdt(cpu) + GDT_ENTRY_PER_CPU); +- *d = 0x0f40000000000ULL; +- *d |= cpu; +- *d |= (node & 0xf) << 12; +- *d |= (node >> 4) << 48; ++ n = 0x0f40000000000ULL; ++ n |= cpu; ++ n |= (node & 0xf) << 12; ++ n |= (node >> 4) << 48; ++#ifndef CONFIG_XEN ++ *d = n; ++#else ++ HYPERVISOR_update_descriptor(virt_to_machine(d), n); ++#endif + } + + static void __cpuinit cpu_vsyscall_init(void *arg) +@@ -283,7 +290,6 @@ + smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); + return NOTIFY_DONE; + } +-#endif + + static void __init map_vsyscall(void) + { +@@ -320,10 +326,8 @@ + #ifdef CONFIG_SYSCTL + register_sysctl_table(kernel_root_table2, 0); + #endif +-#ifndef CONFIG_XEN + on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); + hotcpu_notifier(cpu_vsyscall_notifier, 0); +-#endif + return 0; + } + diff --git a/tags/2.6.20-3/20958-linux-2.6-xen-iscsi-x86_64-no_iommu_init.patch b/tags/2.6.20-3/20958-linux-2.6-xen-iscsi-x86_64-no_iommu_init.patch new file mode 100644 index 0000000..925b47b --- /dev/null +++ b/tags/2.6.20-3/20958-linux-2.6-xen-iscsi-x86_64-no_iommu_init.patch @@ -0,0 +1,45 @@ +# HG changeset patch +# User chrisw@sous-sol.org +# Date Tue Oct 03 13:44:38 2006 -0400 +# Node ID e5a7f30e1db3f1084f6789d21ea2a6fdaafdb96d +# parent: 6cd0fae5d84c4a4b15546ceaade74b7d7f044404 +Make sure no_iommu_init is called when needed on x86_64. Thanks +to Mark McLoughlin <markmc@redhat.com> for spotting the issue and +proposing a fix. + +Index: patching/arch/i386/kernel/pci-dma-xen.c +=================================================================== +--- patching.orig/arch/i386/kernel/pci-dma-xen.c ++++ patching/arch/i386/kernel/pci-dma-xen.c +@@ -22,6 +22,8 @@ + + #ifdef __x86_64__ + #include <asm/proto.h> ++#include <asm/calgary.h> ++ + + int iommu_merge __read_mostly = 0; + EXPORT_SYMBOL(iommu_merge); +@@ -71,6 +73,22 @@ void __init pci_iommu_alloc(void) + #endif + } + ++static int __init pci_iommu_init(void) ++{ ++#ifdef CONFIG_CALGARY_IOMMU ++ calgary_iommu_init(); ++#endif ++ ++#ifdef CONFIG_IOMMU ++ gart_iommu_init(); ++#endif ++ ++ no_iommu_init(); ++ return 0; ++} ++ ++/* Must execute after PCI subsystem */ ++fs_initcall(pci_iommu_init); + #endif + + struct dma_coherent_mem { diff --git a/tags/2.6.20-3/20960-linux-2.6-xen-blkfront-wait-add.patch b/tags/2.6.20-3/20960-linux-2.6-xen-blkfront-wait-add.patch new file mode 100644 index 0000000..0450058 --- /dev/null +++ b/tags/2.6.20-3/20960-linux-2.6-xen-blkfront-wait-add.patch @@ -0,0 +1,82 @@ +Index: linux-2.6.20.i386/drivers/xen/blkfront/blkfront.c +=================================================================== +--- linux-2.6.20.i386.orig/drivers/xen/blkfront/blkfront.c ++++ linux-2.6.20.i386/drivers/xen/blkfront/blkfront.c +@@ -343,6 +343,8 @@ static void connect(struct blkfront_info + spin_unlock_irq(&blkif_io_lock); + + add_disk(info->gd); ++ ++ info->is_ready = 1; + } + + /** +@@ -852,6 +854,13 @@ static void blkif_recover(struct blkfron + spin_unlock_irq(&blkif_io_lock); + } + ++int blkfront_is_ready(struct xenbus_device *dev) ++{ ++ struct blkfront_info *info = dev->dev.driver_data; ++ ++ return info->is_ready; ++} ++ + + /* ** Driver Registration ** */ + +@@ -870,6 +879,7 @@ static struct xenbus_driver blkfront = { + .remove = blkfront_remove, + .resume = blkfront_resume, + .otherend_changed = backend_changed, ++ .is_ready = blkfront_is_ready, + }; + + +Index: linux-2.6.20.i386/drivers/xen/blkfront/block.h +=================================================================== +--- linux-2.6.20.i386.orig/drivers/xen/blkfront/block.h ++++ linux-2.6.20.i386/drivers/xen/blkfront/block.h +@@ -125,6 +125,7 @@ struct blkfront_info + struct blk_shadow shadow[BLK_RING_SIZE]; + unsigned long shadow_free; + int feature_barrier; ++ int is_ready; + + /** + * The number of people holding this device open. We won't allow a +Index: linux-2.6.20.i386/drivers/xen/xenbus/xenbus_probe.c +=================================================================== +--- linux-2.6.20.i386.orig/drivers/xen/xenbus/xenbus_probe.c ++++ linux-2.6.20.i386/drivers/xen/xenbus/xenbus_probe.c +@@ -940,6 +940,7 @@ static int is_disconnected_device(struct + { + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; ++ struct xenbus_driver *xendrv; + + /* + * A device with no driver will never connect. We care only about +@@ -952,7 +953,9 @@ static int is_disconnected_device(struct + if (drv && (dev->driver != drv)) + return 0; + +- return (xendev->state != XenbusStateConnected); ++ xendrv = to_xenbus_driver(dev->driver); ++ return (xendev->state != XenbusStateConnected || ++ (xendrv->is_ready && !xendrv->is_ready(xendev))); + } + + static int exists_disconnected_device(struct device_driver *drv) +Index: linux-2.6.20.i386/include/xen/xenbus.h +=================================================================== +--- linux-2.6.20.i386.orig/include/xen/xenbus.h ++++ linux-2.6.20.i386/include/xen/xenbus.h +@@ -105,6 +105,7 @@ struct xenbus_driver { + int (*uevent)(struct xenbus_device *, char **, int, char *, int); + struct device_driver driver; + int (*read_otherend_details)(struct xenbus_device *dev); ++ int (*is_ready)(struct xenbus_device *dev); + }; + + static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) diff --git a/tags/2.6.20-3/20961_linux-2.6-xen-backwards-time.patch b/tags/2.6.20-3/20961_linux-2.6-xen-backwards-time.patch new file mode 100644 index 0000000..44552c7 --- /dev/null +++ b/tags/2.6.20-3/20961_linux-2.6-xen-backwards-time.patch @@ -0,0 +1,63 @@ + +# HG changeset patch +# User kfraser@localhost.localdomain +# Date 1182263776 -3600 +# Node ID 87bb8705768a66ceabb15a419c5f86580bffb6bf +# Parent a413dd61e7e5e1bba11bab447184cf5e6b43513a +x86 time: Ensure gettimeofday() is monotonically increasing. +Signed-off-by: Atsushi SAKAI <sakaia@jp.fujitsu.com> + +Index: linux-2.6.20.i386/arch/i386/kernel/time-xen.c +=================================================================== +--- linux-2.6.20.i386.orig/arch/i386/kernel/time-xen.c ++++ linux-2.6.20.i386/arch/i386/kernel/time-xen.c +@@ -109,6 +109,9 @@ static DEFINE_PER_CPU(struct shadow_time + static struct timespec shadow_tv; + static u32 shadow_tv_version; + ++static struct timeval monotonic_tv; ++static spinlock_t monotonic_lock = SPIN_LOCK_UNLOCKED; ++ + /* Keep track of last time we did processing/updating of jiffies and xtime. */ + static u64 processed_system_time; /* System time (ns) at last processing. */ + static DEFINE_PER_CPU(u64, processed_system_time); +@@ -324,6 +327,7 @@ void do_gettimeofday(struct timeval *tv) + unsigned long seq; + unsigned long usec, sec; + unsigned long max_ntp_tick; ++ unsigned long flags; + s64 nsec; + unsigned int cpu; + struct shadow_time_info *shadow; +@@ -376,6 +380,18 @@ void do_gettimeofday(struct timeval *tv) + sec++; + } + ++ spin_lock_irqsave(&monotonic_lock, flags); ++ if ((sec > monotonic_tv.tv_sec) || ++ ((sec == monotonic_tv.tv_sec) && (usec > monotonic_tv.tv_usec))) ++ { ++ monotonic_tv.tv_sec = sec; ++ monotonic_tv.tv_usec = usec; ++ } else { ++ sec = monotonic_tv.tv_sec; ++ usec = monotonic_tv.tv_usec; ++ } ++ spin_unlock_irqrestore(&monotonic_lock, flags); ++ + tv->tv_sec = sec; + tv->tv_usec = usec; + } +@@ -425,6 +441,12 @@ int do_settimeofday(struct timespec *tv) + __update_wallclock(sec, nsec); + } + ++ /* Reset monotonic gettimeofday() timeval. */ ++ spin_lock(&monotonic_lock); ++ monotonic_tv.tv_sec = 0; ++ monotonic_tv.tv_usec = 0; ++ spin_unlock(&monotonic_lock); ++ + write_sequnlock_irq(&xtime_lock); + + put_cpu(); diff --git a/tags/2.6.20-3/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch b/tags/2.6.20-3/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch new file mode 100644 index 0000000..16f11fa --- /dev/null +++ b/tags/2.6.20-3/20962_linux-2.6-xen-add-packet_auxdata-cmsg-1.patch @@ -0,0 +1,233 @@ +From: Herbert Xu <herbert.xu@redhat.com> +Subject: [RHEL5 PATCH] [PACKET]: Add PACKET_AUXDATA cmsg +Date: Wed, 10 Jan 2007 20:17:36 +1100 +Message-Id: <20070110091736.GA28579@gondor.apana.org.au> +Changelog: xen: Add PACKET_AUXDATA cmsg + + +Hi: + +RHEL5 BZ 219681 + +This patch forms part of the solution to #219681 where the DHCP server +can't serve any requests from clients running (in different domains) +on the same Xen host. + +I've sent a similar patch (without the Xen-specific code) upstream. + +This obsoletes the previous patch that computed the checksums in +kernel-space. + +[PACKET]: Add PACKET_AUXDATA cmsg + +HCP servers/clients using AF_PACKET) to be able to serve another +client on the same Xen host. + +The problem is that packets between different domains on the same +Xen host only have partial checksums. Unfortunately this piece of +information is not passed along in AF_PACKET unless you're using +the mmap interface. Since dhcpd doesn't support packet-mmap, UDP +packets from the same host come out with apparently bogus checksums. + +This patch adds a mechanism for AF_PACKET recvmsg(2) to return the +status along with the packet. It does so by adding a new cmsg that +contains this information along with some other relevant data such +as the original packet length. + +I didn't include the time stamp information since there is already +a cmsg for that. + +This patch also changes the mmap code to set the CSUMNOTREADY flag +on all packets instead of just outoing packets on cooked sockets. + +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> + +Index: linux-2.6.20.i386/include/linux/if_packet.h +=================================================================== +--- linux-2.6.20.i386.orig/include/linux/if_packet.h ++++ linux-2.6.20.i386/include/linux/if_packet.h +@@ -41,6 +41,7 @@ struct sockaddr_ll + #define PACKET_RX_RING 5 + #define PACKET_STATISTICS 6 + #define PACKET_COPY_THRESH 7 ++#define PACKET_AUXDATA 8 + + struct tpacket_stats + { +@@ -48,6 +49,15 @@ struct tpacket_stats + unsigned int tp_drops; + }; + ++struct tpacket_auxdata ++{ ++ __u32 tp_status; ++ __u32 tp_len; ++ __u32 tp_snaplen; ++ __u16 tp_mac; ++ __u16 tp_net; ++}; ++ + struct tpacket_hdr + { + unsigned long tp_status; +Index: linux-2.6.20.i386/net/packet/af_packet.c +=================================================================== +--- linux-2.6.20.i386.orig/net/packet/af_packet.c ++++ linux-2.6.20.i386/net/packet/af_packet.c +@@ -200,7 +200,8 @@ struct packet_sock { + #endif + struct packet_type prot_hook; + spinlock_t bind_lock; +- char running; /* prot_hook is attached*/ ++ unsigned int running:1, /* prot_hook is attached*/ ++ auxdata:1; + int ifindex; /* bound device */ + __be16 num; + #ifdef CONFIG_PACKET_MULTICAST +@@ -214,6 +215,10 @@ struct packet_sock { + #endif + }; + ++#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) ++ ++extern int skb_checksum_setup(struct sk_buff *skb); ++ + #ifdef CONFIG_PACKET_MMAP + + static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) +@@ -462,6 +467,7 @@ static int packet_rcv(struct sk_buff *sk + u8 * skb_head = skb->data; + int skb_len = skb->len; + unsigned int snaplen, res; ++ struct tpacket_auxdata *aux; + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; +@@ -523,6 +529,18 @@ static int packet_rcv(struct sk_buff *sk + if (dev->hard_header_parse) + sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + ++ if (skb_checksum_setup(skb)) ++ goto drop_n_acct; ++ ++ aux = PACKET_SKB_CB(skb); ++ aux->tp_status = TP_STATUS_USER; ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ aux->tp_status |= TP_STATUS_CSUMNOTREADY; ++ aux->tp_len = skb->len; ++ aux->tp_snaplen = snaplen; ++ aux->tp_mac = 0; ++ aux->tp_net = skb->nh.raw - skb->data; ++ + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; + +@@ -582,8 +600,6 @@ static int tpacket_rcv(struct sk_buff *s + else if (skb->pkt_type == PACKET_OUTGOING) { + /* Special case: outgoing packets have ll header at head */ + skb_pull(skb, skb->nh.raw - skb->data); +- if (skb->ip_summed == CHECKSUM_PARTIAL) +- status |= TP_STATUS_CSUMNOTREADY; + } + } + +@@ -595,6 +611,11 @@ static int tpacket_rcv(struct sk_buff *s + if (snaplen > res) + snaplen = res; + ++ if (skb_checksum_setup(skb)) ++ goto drop; ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ status |= TP_STATUS_CSUMNOTREADY; ++ + if (sk->sk_type == SOCK_DGRAM) { + macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; + } else { +@@ -1119,6 +1140,11 @@ static int packet_recvmsg(struct kiocb * + if (msg->msg_name) + memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + ++ if (pkt_sk(sk)->auxdata) { ++ struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); ++ put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); ++ } ++ + /* + * Free or return the buffer as appropriate. Again this + * hides all the races and re-entrancy issues from us. +@@ -1317,6 +1343,7 @@ static int + packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) + { + struct sock *sk = sock->sk; ++ struct packet_sock *po = pkt_sk(sk); + int ret; + + if (level != SOL_PACKET) +@@ -1369,6 +1396,18 @@ packet_setsockopt(struct socket *sock, i + return 0; + } + #endif ++ case PACKET_AUXDATA: ++ { ++ int val; ++ ++ if (optlen < sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ ++ po->auxdata = !!val; ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -1378,8 +1417,11 @@ static int packet_getsockopt(struct sock + char __user *optval, int __user *optlen) + { + int len; ++ int val; + struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); ++ void *data; ++ struct tpacket_stats st; + + if (level != SOL_PACKET) + return -ENOPROTOOPT; +@@ -1392,9 +1434,6 @@ static int packet_getsockopt(struct sock + + switch(optname) { + case PACKET_STATISTICS: +- { +- struct tpacket_stats st; +- + if (len > sizeof(struct tpacket_stats)) + len = sizeof(struct tpacket_stats); + spin_lock_bh(&sk->sk_receive_queue.lock); +@@ -1403,16 +1442,23 @@ static int packet_getsockopt(struct sock + spin_unlock_bh(&sk->sk_receive_queue.lock); + st.tp_packets += st.tp_drops; + +- if (copy_to_user(optval, &st, len)) +- return -EFAULT; ++ data = &st; ++ break; ++ case PACKET_AUXDATA: ++ if (len > sizeof(int)) ++ len = sizeof(int); ++ val = po->auxdata; ++ ++ data = &val; + break; +- } + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; ++ if (copy_to_user(optval, data, len)) ++ return -EFAULT; + return 0; + } + diff --git a/tags/2.6.20-3/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch b/tags/2.6.20-3/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch new file mode 100644 index 0000000..8bf6bf7 --- /dev/null +++ b/tags/2.6.20-3/20963_linux-2.6-xen-add-packet_auxdata-cmsg-2.patch @@ -0,0 +1,144 @@ +From: Herbert Xu <herbert.xu@redhat.com> +Subject: Re: Help on BZ 223505 tcpdump causes ppc64 to enter xmon +Date: Wed, 24 Jan 2007 10:23:55 +1100 +Message-Id: <20070123232355.GA4724@gondor.apana.org.au> + +On Wed, Jan 24, 2007 at 09:03:24AM +1100, Herbert Xu wrote: +> +> OK, I've found the problem. The skb->cb buffer is already being +> used for sockaddr_ll which the aux data is overwriting. Let me +> fix this up by getting them to share the buffer. + +The obvious fix of putting them together in the cb doesn't quite work +because sockaddr_ll's last member can be as large as MAX_ADDR_LEN (32). +In fact this means that older kernels with skb->cb less than 44 bytes +may in fact be vulnerable if net devices with an address length of 32 +bytes exist. + +[PACKET]: Fix skb->cb clobbering between aux and sockaddr + +Both aux data and sockaddr tries to use the same buffer which +obviously doesn't work. We just happen to have 4 bytes free in +the skb->cb if you take away the maximum length of sockaddr_ll. +That's just enough to store the one piece of info from aux data +that we can't generate at recvmsg(2) time. + +This is what the following patch does. + +Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> + +Cheers, +-- +Visit Openswan at http://www.openswan.org/ +Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> +Home Page: http://gondor.apana.org.au/~herbert/ +PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt +-- +Index: linux-2.6.20.i386/net/packet/af_packet.c +=================================================================== +--- linux-2.6.20.i386.orig/net/packet/af_packet.c ++++ linux-2.6.20.i386/net/packet/af_packet.c +@@ -60,6 +60,7 @@ + #include <linux/netdevice.h> + #include <linux/if_packet.h> + #include <linux/wireless.h> ++#include <linux/kernel.h> + #include <linux/kmod.h> + #include <net/ip.h> + #include <net/protocol.h> +@@ -215,7 +216,15 @@ struct packet_sock { + #endif + }; + +-#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) ++struct packet_skb_cb { ++ unsigned int origlen; ++ union { ++ struct sockaddr_pkt pkt; ++ struct sockaddr_ll ll; ++ } sa; ++}; ++ ++#define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) + + extern int skb_checksum_setup(struct sk_buff *skb); + +@@ -298,7 +307,7 @@ static int packet_rcv_spkt(struct sk_buf + /* drop conntrack reference */ + nf_reset(skb); + +- spkt = (struct sockaddr_pkt*)skb->cb; ++ spkt = &PACKET_SKB_CB(skb)->sa.pkt; + + skb_push(skb, skb->data-skb->mac.raw); + +@@ -467,7 +476,6 @@ static int packet_rcv(struct sk_buff *sk + u8 * skb_head = skb->data; + int skb_len = skb->len; + unsigned int snaplen, res; +- struct tpacket_auxdata *aux; + + if (skb->pkt_type == PACKET_LOOPBACK) + goto drop; +@@ -518,7 +526,10 @@ static int packet_rcv(struct sk_buff *sk + skb = nskb; + } + +- sll = (struct sockaddr_ll*)skb->cb; ++ BUILD_BUG_ON(sizeof(*PACKET_SKB_CB(skb)) + MAX_ADDR_LEN - 8 > ++ sizeof(skb->cb)); ++ ++ sll = &PACKET_SKB_CB(skb)->sa.ll; + sll->sll_family = AF_PACKET; + sll->sll_hatype = dev->type; + sll->sll_protocol = skb->protocol; +@@ -532,14 +543,7 @@ static int packet_rcv(struct sk_buff *sk + if (skb_checksum_setup(skb)) + goto drop_n_acct; + +- aux = PACKET_SKB_CB(skb); +- aux->tp_status = TP_STATUS_USER; +- if (skb->ip_summed == CHECKSUM_PARTIAL) +- aux->tp_status |= TP_STATUS_CSUMNOTREADY; +- aux->tp_len = skb->len; +- aux->tp_snaplen = snaplen; +- aux->tp_mac = 0; +- aux->tp_net = skb->nh.raw - skb->data; ++ PACKET_SKB_CB(skb)->origlen = skb->len; + + if (pskb_trim(skb, snaplen)) + goto drop_n_acct; +@@ -1113,7 +1117,7 @@ static int packet_recvmsg(struct kiocb * + * it in now. + */ + +- sll = (struct sockaddr_ll*)skb->cb; ++ sll = &PACKET_SKB_CB(skb)->sa.ll; + if (sock->type == SOCK_PACKET) + msg->msg_namelen = sizeof(struct sockaddr_pkt); + else +@@ -1138,11 +1142,21 @@ static int packet_recvmsg(struct kiocb * + sock_recv_timestamp(msg, sk, skb); + + if (msg->msg_name) +- memcpy(msg->msg_name, skb->cb, msg->msg_namelen); ++ memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, ++ msg->msg_namelen); + + if (pkt_sk(sk)->auxdata) { +- struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); +- put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); ++ struct tpacket_auxdata aux; ++ ++ aux.tp_status = TP_STATUS_USER; ++ if (skb->ip_summed == CHECKSUM_PARTIAL) ++ aux.tp_status |= TP_STATUS_CSUMNOTREADY; ++ aux.tp_len = PACKET_SKB_CB(skb)->origlen; ++ aux.tp_snaplen = skb->len; ++ aux.tp_mac = 0; ++ aux.tp_net = skb->nh.raw - skb->data; ++ ++ put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); + } + + /* diff --git a/tags/2.6.20-3/21665-linux-2.6-disable-netback-checksum.patch b/tags/2.6.20-3/21665-linux-2.6-disable-netback-checksum.patch new file mode 100644 index 0000000..18b4dae --- /dev/null +++ b/tags/2.6.20-3/21665-linux-2.6-disable-netback-checksum.patch @@ -0,0 +1,37 @@ +From: Herbert Xu <herbert.xu@redhat.com> +Subject: Re: Final resolution for the checksum problems + + +Daniel P. Berrange <berrange@redhat.com> wrote: +> +>> > Alternatively we could just make netback default tx checksums to off +>> > which should have a similar effect as disabling it on virbr0. +>> +>> This seems like a simpler path than introducing new infrastructure for +>> scripts to run every time the interface is brought up/down. And then +>> it's even easier to remove the "trigger" when we get the functionality +>> in the kernel +> +> I agree - this would be even simpler. + +Here is a patch which does just that. + +Cheers, +-- +Visit Openswan at http://www.openswan.org/ +Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> +Home Page: http://gondor.apana.org.au/~herbert/ +PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt +-- +--- a/drivers/xen/netback/interface.c 2007-04-28 11:57:31.000000000 +1000 ++++ b/drivers/xen/netback/interface.c 2007-05-02 19:58:16.000000000 +1000 +@@ -161,7 +161,6 @@ + dev->open = net_open; + dev->stop = net_close; + dev->change_mtu = netbk_change_mtu; +- dev->features = NETIF_F_IP_CSUM; + + SET_ETHTOOL_OPS(dev, &network_ethtool_ops); + + + diff --git a/tags/2.6.20-3/23000-linux-2.6-acpi-config_pm-poweroff.patch b/tags/2.6.20-3/23000-linux-2.6-acpi-config_pm-poweroff.patch new file mode 100644 index 0000000..e925785 --- /dev/null +++ b/tags/2.6.20-3/23000-linux-2.6-acpi-config_pm-poweroff.patch @@ -0,0 +1,38 @@ +See http://bugzilla.redhat.com/241381 + +From b7da11fc422b5d06ab6ed5444a1f01ac0e805c74 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost <ehabkost@redhat.com> +Date: Tue, 10 Jul 2007 19:02:14 -0300 +Subject: [PATCH] Remove #ifdef CONFIG_PM from ACPI power-off code + +The ACPI poweroff code is inside a #ifdef CONFIG_PM, that was added on +commit b35c67a46b025e8dc320b59fbe5c283094e1d7f5. It is not necessary +because the poweroff code compiles and works even with CONFIG_PM disabled. + +Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> +--- + drivers/acpi/sleep/poweroff.c | 4 ---- + 1 files changed, 0 insertions(+), 4 deletions(-) + +diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c +index d9801ef..5d6ba10 100644 +--- a/drivers/acpi/sleep/poweroff.c ++++ b/drivers/acpi/sleep/poweroff.c +@@ -37,8 +37,6 @@ #endif + return 0; + } + +-#ifdef CONFIG_PM +- + void acpi_power_off(void) + { + /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ +@@ -94,5 +92,3 @@ static int acpi_poweroff_init(void) + } + + late_initcall(acpi_poweroff_init); +- +-#endif /* CONFIG_PM */ +-- +silverbrick.install.2006.08.14-dirty + diff --git a/tags/2.6.20-3/30037_amd64-zero-extend-32bit-ptrace-xen.patch b/tags/2.6.20-3/30037_amd64-zero-extend-32bit-ptrace-xen.patch new file mode 100644 index 0000000..25e56d3 --- /dev/null +++ b/tags/2.6.20-3/30037_amd64-zero-extend-32bit-ptrace-xen.patch @@ -0,0 +1,50 @@ +Adjusted to apply to Debian's 2.6.18 Xen + +--- linux-source-2.6.18.orig/arch/x86_64/ia32/ia32entry-xen.S 2006-09-19 21:42:06.000000000 -0600 ++++ linux-source-2.6.18/arch/x86_64/ia32/ia32entry-xen.S 2007-09-25 00:10:16.089100799 -0600 +@@ -38,6 +38,18 @@ + #define __sti sti + #endif + ++ .macro LOAD_ARGS32 offset ++ movl \offset(%rsp),%r11d ++ movl \offset+8(%rsp),%r10d ++ movl \offset+16(%rsp),%r9d ++ movl \offset+24(%rsp),%r8d ++ movl \offset+40(%rsp),%ecx ++ movl \offset+48(%rsp),%edx ++ movl \offset+56(%rsp),%esi ++ movl \offset+64(%rsp),%edi ++ movl \offset+72(%rsp),%eax ++ .endm ++ + .macro CFI_STARTPROC32 simple + CFI_STARTPROC \simple + CFI_UNDEFINED r8 +@@ -151,7 +163,7 @@ sysenter_tracesys: + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter +- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + movl %ebp, %ebp + /* no need to do an access_ok check here because rbp has been +@@ -253,7 +265,7 @@ cstar_tracesys: + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter +- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + movl RSP-ARGOFFSET(%rsp), %r8d + /* no need to do an access_ok check here because r8 has been +@@ -330,7 +342,7 @@ ia32_tracesys: + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter +- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ ++ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + jmp ia32_do_syscall + END(ia32_syscall) diff --git a/tags/2.6.20-3/50001_make-install.patch b/tags/2.6.20-3/50001_make-install.patch new file mode 100644 index 0000000..108c648 --- /dev/null +++ b/tags/2.6.20-3/50001_make-install.patch @@ -0,0 +1,52 @@ +diff -ru linux-2.6.18-xen.orig/arch/i386/Makefile linux-2.6.18-xen/arch/i386/Makefile +--- linux-2.6.18-xen.orig/arch/i386/Makefile 2007-07-16 17:58:05.000000000 -0700 ++++ linux-2.6.18-xen/arch/i386/Makefile 2007-07-16 18:22:18.000000000 -0700 +@@ -125,7 +125,7 @@ + $(Q)$(MAKE) $(build)=$(boot) $@ + + install: +- $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@ ++ $(Q)$(MAKE) $(build)=$(boot) $@ + else + all: bzImage + +diff -ru linux-2.6.18-xen.orig/arch/i386/boot-xen/Makefile linux-2.6.18-xen/arch/i386/boot-xen/Makefile +--- linux-2.6.18-xen.orig/arch/i386/boot-xen/Makefile 2007-07-16 17:58:05.000000000 -0700 ++++ linux-2.6.18-xen/arch/i386/boot-xen/Makefile 2007-07-16 18:36:08.000000000 -0700 +@@ -10,12 +10,17 @@ + INSTALL_ROOT := $(patsubst %/boot,%,$(INSTALL_PATH)) + + XINSTALL_NAME ?= $(KERNELRELEASE) ++ ++ifdef CONFIG_XEN_PRIVILEGED_GUEST ++XENGUEST= ++else ++XENGUEST=-domU ++endif ++ + install: + mkdir -p $(INSTALL_ROOT)/boot +- ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(XENGUEST)$(INSTALL_SUFFIX) +- rm -f $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) +- install -m0644 vmlinuz $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) +- install -m0644 vmlinux $(INSTALL_ROOT)/boot/vmlinux-syms-$(XINSTALL_NAME)$(INSTALL_SUFFIX) +- install -m0664 .config $(INSTALL_ROOT)/boot/config-$(XINSTALL_NAME)$(INSTALL_SUFFIX) +- install -m0664 System.map $(INSTALL_ROOT)/boot/System.map-$(XINSTALL_NAME)$(INSTALL_SUFFIX) +- ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL)$(XENGUEST)$(INSTALL_SUFFIX) ++ install -m0644 vmlinuz $(INSTALL_ROOT)/boot/vmlinuz-$(XINSTALL_NAME)$(XENGUEST)$(INSTALL_SUFFIX) ++ install -m0644 vmlinux $(INSTALL_ROOT)/boot/vmlinux-syms-$(XINSTALL_NAME)$(XENGUEST)$(INSTALL_SUFFIX) ++ install -m0664 .config $(INSTALL_ROOT)/boot/config-$(XINSTALL_NAME)$(XENGUEST)$(INSTALL_SUFFIX) ++ install -m0664 System.map $(INSTALL_ROOT)/boot/System.map-$(XINSTALL_NAME)$(XENGUEST)$(INSTALL_SUFFIX) ++ ln -f -s vmlinuz-$(XINSTALL_NAME)$(INSTALL_SUFFIX) $(INSTALL_ROOT)/boot/vmlinuz-$(VERSION).$(PATCHLEVEL)-xen$(XENGUEST)$(INSTALL_SUFFIX) +diff -ru linux-2.6.18-xen.orig/arch/x86_64/Makefile linux-2.6.18-xen/arch/x86_64/Makefile +--- linux-2.6.18-xen.orig/arch/x86_64/Makefile 2007-07-16 17:58:05.000000000 -0700 ++++ linux-2.6.18-xen/arch/x86_64/Makefile 2007-07-16 18:22:34.000000000 -0700 +@@ -91,7 +91,7 @@ + $(Q)$(MAKE) $(build)=$(boot) $@ + + install: +- $(Q)$(MAKE) $(build)=$(boot) XENGUEST=$(XENGUEST) $@ ++ $(Q)$(MAKE) $(build)=$(boot) $@ + else + #Default target when executing "make" + all: bzImage diff --git a/tags/2.6.20-3/50002_always-enable-xen-genapic.patch b/tags/2.6.20-3/50002_always-enable-xen-genapic.patch new file mode 100644 index 0000000..a9b8b77 --- /dev/null +++ b/tags/2.6.20-3/50002_always-enable-xen-genapic.patch @@ -0,0 +1,12 @@ +diff -ru linux-2.6.18-xen.orig/arch/x86_64/Kconfig linux-2.6.18-xen/arch/x86_64/Kconfig +--- linux-2.6.18-xen.orig/arch/x86_64/Kconfig 2007-08-07 17:37:58.000000000 -0700 ++++ linux-2.6.18-xen/arch/x86_64/Kconfig 2007-08-07 17:39:32.000000000 -0700 +@@ -234,7 +234,7 @@ + config X86_XEN_GENAPIC + bool + depends X86_64_XEN +- default XEN_PRIVILEGED_GUEST || SMP ++ default y + + config X86_LOCAL_APIC + bool diff --git a/tags/2.6.20-3/50003_console-tty-fix.patch b/tags/2.6.20-3/50003_console-tty-fix.patch new file mode 100644 index 0000000..72a90a8 --- /dev/null +++ b/tags/2.6.20-3/50003_console-tty-fix.patch @@ -0,0 +1,75 @@ +diff -rup linux-2.6.20-xen.orig/drivers/char/tty_io.c linux-2.6.20-xen/drivers/char/tty_io.c +--- linux-2.6.20-xen.orig/drivers/char/tty_io.c 2007-07-16 11:14:52.000000000 -0700 ++++ linux-2.6.20-xen/drivers/char/tty_io.c 2007-07-16 15:57:19.000000000 -0700 +@@ -133,6 +133,8 @@ LIST_HEAD(tty_drivers); /* linked list + DEFINE_MUTEX(tty_mutex); + EXPORT_SYMBOL(tty_mutex); + ++int console_use_vt = 1; ++ + #ifdef CONFIG_UNIX98_PTYS + extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ + extern int pty_limit; /* Config limit on Unix98 ptys */ +@@ -2518,7 +2520,7 @@ retry_open: + goto got_driver; + } + #ifdef CONFIG_VT +- if (device == MKDEV(TTY_MAJOR,0)) { ++ if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { + extern struct tty_driver *console_driver; + driver = console_driver; + index = fg_console; +@@ -3910,6 +3912,8 @@ static int __init tty_init(void) + #endif + + #ifdef CONFIG_VT ++ if (!console_use_vt) ++ goto out_vt; + cdev_init(&vc0_cdev, &console_fops); + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) +@@ -3917,6 +3921,7 @@ static int __init tty_init(void) + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0"); + + vty_init(); ++ out_vt: + #endif + return 0; + } +diff -rup linux-2.6.20-xen.orig/drivers/xen/console/console.c linux-2.6.20-xen/drivers/xen/console/console.c +--- linux-2.6.20-xen.orig/drivers/xen/console/console.c 2007-07-16 11:14:52.000000000 -0700 ++++ linux-2.6.20-xen/drivers/xen/console/console.c 2007-07-16 16:02:26.000000000 -0700 +@@ -86,23 +86,30 @@ static unsigned long sysrq_requested; + + void xencons_early_setup(void) + { +- if (is_initial_xendomain()) ++ extern int console_use_vt; ++ ++ if (is_initial_xendomain()) { + xc_mode = XC_SERIAL; +- else +- xc_mode = XC_XVC; ++ } else { ++ xc_mode = XC_TTY; ++ console_use_vt = 0; ++ } + } + + static int __init xencons_setup(char *str) + { + char *q; + int n; ++ extern int console_use_vt; + ++ console_use_vt = 1; + if (!strncmp(str, "ttyS", 4)) { + xc_mode = XC_SERIAL; + str += 4; + } else if (!strncmp(str, "tty", 3)) { + xc_mode = XC_TTY; + str += 3; ++ console_use_vt = 0; + } else if (!strncmp(str, "xvc", 3)) { + xc_mode = XC_XVC; + str += 3; diff --git a/tags/2.6.20-3/50004_quirks-no-smp-fix.patch b/tags/2.6.20-3/50004_quirks-no-smp-fix.patch new file mode 100644 index 0000000..77de84c --- /dev/null +++ b/tags/2.6.20-3/50004_quirks-no-smp-fix.patch @@ -0,0 +1,12 @@ +diff -rup linux-2.6.20-xen.orig/arch/i386/kernel/quirks.c linux-2.6.20-xen/arch/i386/kernel/quirks.c +--- linux-2.6.20-xen.orig/arch/i386/kernel/quirks.c 2007-07-23 10:59:51.000000000 -0700 ++++ linux-2.6.20-xen/arch/i386/kernel/quirks.c 2007-07-23 11:02:15.000000000 -0700 +@@ -7,7 +7,7 @@ + #include <asm/genapic.h> + #include <asm/cpu.h> + +-#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI) ++#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) + static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev) + { + u8 config, rev; diff --git a/tags/2.6.20-3/50006_pgetable-build-fix.patch b/tags/2.6.20-3/50006_pgetable-build-fix.patch new file mode 100644 index 0000000..aa4f99c --- /dev/null +++ b/tags/2.6.20-3/50006_pgetable-build-fix.patch @@ -0,0 +1,14 @@ +Index: linux-2.6.20-xen-r3/include/asm-i386/mach-xen/asm/pgtable-2level.h +=================================================================== +--- linux-2.6.20-xen-r3.orig/include/asm-i386/mach-xen/asm/pgtable-2level.h ++++ linux-2.6.20-xen-r3/include/asm-i386/mach-xen/asm/pgtable-2level.h +@@ -30,8 +30,7 @@ + + #define pte_none(x) (!(x).pte_low) + +-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +-static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++static inline pte_t raw_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + pte_t pte = *ptep; + if (!pte_none(pte)) { diff --git a/tags/2.6.20-3/50007_disable-highpte.patch b/tags/2.6.20-3/50007_disable-highpte.patch new file mode 100644 index 0000000..3d829fc --- /dev/null +++ b/tags/2.6.20-3/50007_disable-highpte.patch @@ -0,0 +1,13 @@ +Index: linux-2.6.18/arch/i386/Kconfig +=================================================================== +--- linux-2.6.18.orig/arch/i386/Kconfig ++++ linux-2.6.18/arch/i386/Kconfig +@@ -624,7 +624,7 @@ config HAVE_ARCH_EARLY_PFN_TO_NID + + config HIGHPTE + bool "Allocate 3rd-level pagetables from highmem" +- depends on HIGHMEM4G || HIGHMEM64G ++ depends on ( HIGHMEM4G || HIGHMEM64G ) && !X86_XEN + help + The VM uses one page table entry for each page of physical memory. + For systems with a lot of RAM, this can be wasteful of precious |