diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/Kconfig --- a/linux-2.6-xen-sparse/arch/xen/Kconfig Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig Fri Dec 23 11:14:21 2005 @@ -210,3 +210,5 @@ source "lib/Kconfig" source "arch/xen/Kconfig.debug" + +source "arch/xen/oprofile/Kconfig" diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/Makefile --- a/linux-2.6-xen-sparse/arch/xen/Makefile Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Makefile Fri Dec 23 11:14:21 2005 @@ -31,6 +31,8 @@ @echo ' SYMLINK ../include/asm-$(XENARCH) -> include2/asm' $(Q)ln -fsn ../include/asm-$(XENARCH) include2/asm endif + +drivers-$(CONFIG_OPROFILE) += arch/xen/oprofile/ include/.asm-ignore: include/asm @rm -f include/.asm-ignore diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/i386/Makefile --- a/linux-2.6-xen-sparse/arch/xen/i386/Makefile Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/Makefile Fri Dec 23 11:14:21 2005 @@ -84,7 +84,6 @@ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ drivers-$(CONFIG_PCI) += arch/xen/i386/pci/ # must be linked after kernel/ -drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ drivers-$(CONFIG_PM) += arch/i386/power/ # for clean diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c Fri Dec 23 11:14:21 2005 @@ -170,6 +170,32 @@ EXPORT_SYMBOL(touch_pte_range); +void *vm_map_xen_pages (unsigned long maddr, int vm_size, pgprot_t prot) +{ + int error; + + struct vm_struct *vma; + vma = get_vm_area (vm_size, VM_IOREMAP); + + if (vma == NULL) { + printk ("ioremap.c,vm_map_xen_pages(): Failed to get VMA area\n"); + return NULL; + } + + error = direct_kernel_remap_pfn_range((unsigned long) vma->addr, + maddr >> PAGE_SHIFT, vm_size, + prot, DOMID_SELF ); + if (error == 0){ + return (vma->addr); + + } + else { + printk ("ioremap.c,vm_map_xen_pages(): Failed to map xen shared pages into kernel space\n"); + return NULL; + } +} +EXPORT_SYMBOL(vm_map_xen_pages); + #ifdef CONFIG_XEN_PHYSDEV_ACCESS /* diff -r 5baa96bedc13 linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h Fri Dec 23 11:14:21 2005 @@ -300,6 +300,23 @@ SHUTDOWN_suspend, srec); } +static inline int +HYPERVISOR_pmc_op( + int op, unsigned int arg1, unsigned int arg2) +{ + int ret; + unsigned long ign1, ign2, ign3; + + __asm__ __volatile__ ( + TRAP_INSTR + : "=a"(ret), "=b"(ign1), "=c"(ign2), "=d"(ign3) + : "0"(__HYPERVISOR_pmc_op), "1"(op), "2"(arg1), "3"(arg2) + : "memory" ); + + return ret; +} + + #endif /* __HYPERCALL_H__ */ /* diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/Kconfig.orig --- /dev/null Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/Kconfig.orig Fri Dec 23 11:14:21 2005 @@ -0,0 +1,212 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config XEN + bool + default y + help + This is the Linux Xen port. + +config ARCH_XEN + bool + default y + + +config NO_IDLE_HZ + bool + default y + + +menu "XEN" + +config XEN_PRIVILEGED_GUEST + bool "Privileged Guest (domain 0)" + default n + select XEN_PHYSDEV_ACCESS + help + Support for privileged operation (domain 0) + +config XEN_PHYSDEV_ACCESS + bool "Physical device access" + default XEN_PRIVILEGED_GUEST + help + Assume access is available to physical hardware devices + (e.g., hard drives, network cards). This allows you to configure + such devices and also includes some low-level support that is + otherwise not compiled into the kernel. + +config XEN_BLKDEV_BACKEND + bool "Block-device backend driver" + depends on XEN_PHYSDEV_ACCESS + 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_BE + bool "Block Tap support for backend driver (DANGEROUS)" + depends on XEN_BLKDEV_BACKEND + default n + help + If you intend to use the block tap driver, the backend domain will + not know the domain id of the real frontend, and so will not be able + to map its data pages. This modifies the backend to attempt to map + from both the tap domain and the real frontend. This presents a + security risk, and so should ONLY be used for development + with the blktap. This option will be removed as the block drivers are + modified to use grant tables. + +config XEN_NETDEV_BACKEND + bool "Network-device backend driver" + depends on XEN_PHYSDEV_ACCESS + 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_TPMDEV_FRONTEND + bool "TPM-device frontend driver" + default n + select TCG_TPM + select TCG_XEN + help + The TPM-device frontend driver. + +config XEN_TPMDEV_BACKEND + bool "TPM-device backend driver" + default n + help + The TPM-device backend driver + +config XEN_TPMDEV_CLOSE_IF_VTPM_FAILS + bool "TPM backend closes upon vTPM failure" + depends on XEN_TPMDEV_BACKEND + default n + help + The TPM backend closes the channel if the vTPM in userspace indicates + a failure. The corresponding domain's channel will be closed. + Say Y if you want this feature. + +config XEN_BLKDEV_FRONTEND + tristate "Block-device frontend driver" + 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" + 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_BLKDEV_TAP + bool "Block device tap driver" + default n + help + This driver allows a VM to interact on block device channels + to other VMs. Block messages may be passed through or redirected + to a character device, allowing device prototyping in application + space. Odds are that you want to say N here. + +config XEN_SHADOW_MODE + bool "Fake shadow mode" + default n + help + fakes out a shadow mode kernel + + +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. + +choice + prompt "Processor Type" + default XEN_X86 + +config XEN_X86 + bool "X86" + help + Choose this option if your computer is a X86 architecture. + +config XEN_X86_64 + bool "X86_64" + help + Choose this option if your computer is a X86_64 architecture. + +endchoice + +endmenu + +config HAVE_ARCH_ALLOC_SKB + bool + default y + +config HAVE_ARCH_DEV_ALLOC_SKB + bool + default y + +source "init/Kconfig" + +if XEN_X86 +source "arch/xen/i386/Kconfig" +endif + +if XEN_X86_64 +source "arch/xen/x86_64/Kconfig" +endif + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "arch/xen/Kconfig.drivers" + +if XEN_PRIVILEGED_GUEST +menu "Power management options" +source "drivers/acpi/Kconfig" +endmenu +endif + +source "fs/Kconfig" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +source "arch/xen/Kconfig.debug" diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/oprofile/Kconfig --- /dev/null Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/oprofile/Kconfig Fri Dec 23 11:14:21 2005 @@ -0,0 +1,25 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + default n + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + default n + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/oprofile/Makefile --- /dev/null Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/oprofile/Makefile Fri Dec 23 11:14:21 2005 @@ -0,0 +1,9 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) pmc.o diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/oprofile/op_counter.h --- /dev/null Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/oprofile/op_counter.h Fri Dec 23 11:14:21 2005 @@ -0,0 +1,29 @@ +/** + * @file op_counter.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OP_COUNTER_H +#define OP_COUNTER_H + +#define OP_MAX_COUNTER 8 + +/* Per-perfctr configuration as set via + * oprofilefs. + */ +struct op_counter_config { + unsigned long count; + unsigned long enabled; + unsigned long event; + unsigned long kernel; + unsigned long user; + unsigned long unit_mask; +}; + +extern struct op_counter_config counter_config[]; + +#endif /* OP_COUNTER_H */ diff -r 5baa96bedc13 linux-2.6-xen-sparse/arch/xen/oprofile/pmc.c --- /dev/null Thu Dec 15 19:57:27 2005 +++ b/linux-2.6-xen-sparse/arch/xen/oprofile/pmc.c Fri Dec 23 11:14:21 2005 @@ -0,0 +1,367 @@ +/** + * @file nmi_int.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * + * Modified by Aravind Menon and Jose Renato Santos for Xen + * These modifications are: + * Copyright (C) 2005 Hewlett-Packard Co. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "op_counter.h" + +static int pmc_start(void); +static void pmc_stop(void); + +extern void *vm_map_xen_pages (unsigned long maddr, int vm_size, pgprot_t prot); +static int pmc_enabled = 0; +static int num_events = 0; +static int is_primary = 0; + +/* sample buffers shared with Xen */ +xenoprof_buf_t* xenoprof_buf [MAX_VIRT_CPUS]; +/* Shared buffer area */ +char *shared_buffer; +/* Number of buffers in shared area (one per VCPU) */ +int nbuf; +/* cpu model type string - copied from Xen memory space on PMC_INIT command */ +char cpu_type[XENOPROF_CPU_TYPE_SIZE]; + +#ifdef CONFIG_PM + +static int pmc_suspend(struct sys_device *dev, u32 state) +{ + if (pmc_enabled == 1) + pmc_stop(); + return 0; +} + + +static int pmc_resume(struct sys_device *dev) +{ + if (pmc_enabled == 1) + pmc_start(); + return 0; +} + + +static struct sysdev_class oprofile_sysclass = { + set_kset_name("oprofile"), + .resume = pmc_resume, + .suspend = pmc_suspend, +} + + +static struct sys_device device_oprofile = { + .id = 0, + .cls = &oprofile_sysclass, +}; + + +static int __init init_driverfs(void) +{ + int error; + if (!(error = sysdev_class_register(&oprofile_sysclass))) + error = sysdev_register(&device_oprofile); + return error; +} + + +static void __exit exit_driverfs(void) +{ + sysdev_unregister(&device_oprofile); + sysdev_class_unregister(&oprofile_sysclass); +} + +#else +#define init_driverfs() do { } while (0) +#define exit_driverfs() do { } while (0) +#endif /* CONFIG_PM */ + +unsigned long long oprofile_samples = 0; + +static irqreturn_t pmc_ovf_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + int head, tail, size; + xenoprof_buf_t* buf; + int cpu; + + cpu = smp_processor_id(); + buf = xenoprof_buf[cpu]; + + head = buf->event_head; + tail = buf->event_tail; + size = buf->event_size; + + if (tail > head) { + while (tail < size) { + oprofile_add_sample_xen(buf->event_log[tail].eip, + buf->event_log[tail].mode, + buf->event_log[tail].event); + oprofile_samples++; + tail++; + } + tail = 0; + } + while (tail < head) { + oprofile_add_sample_xen(buf->event_log[tail].eip, + buf->event_log[tail].mode, + buf->event_log[tail].event); + oprofile_samples++; + tail++; + } + + buf->event_tail = tail; + + return IRQ_HANDLED; +} + +extern int virq_to_phys(int virq); + +int ovf_irq[NR_CPUS]; + +void unbind_pmc_ovf_cpu (void* info) +{ + int cpu = smp_processor_id(); + if (ovf_irq[cpu] >= 0) { + unbind_from_irqhandler(ovf_irq[cpu], NULL); + ovf_irq[cpu] = -1; + } +} + +void unbind_pmc_ovf (void) +{ + on_each_cpu (unbind_pmc_ovf_cpu, NULL, 0 , 1); +} + +int bind_pmc_error; + +void bind_pmc_ovf_cpu (void* info) +{ + int result; + int cpu = smp_processor_id(); + + result = bind_virq_to_irqhandler( VIRQ_PMC_OVF, + cpu, + pmc_ovf_interrupt, + SA_INTERRUPT, + "pmc_ovf", + NULL ); + + if (result<0) { + bind_pmc_error = result; + printk ("pmc.c: binding VIRQ_PMC_OVF to IRQ failed on CPU %d\n", cpu); + } + else { + ovf_irq[cpu] = result; + } + +} + +int bind_pmc_ovf (void) +{ + bind_pmc_error = 0; + on_each_cpu (bind_pmc_ovf_cpu, NULL, 0 , 1); + if (bind_pmc_error){ + unbind_pmc_ovf(); + return bind_pmc_error; + } + else + return 0; +} + +static int pmc_setup(void) +{ + int ret; + + ret = bind_pmc_ovf(); + if (ret) + return ret; + + if (is_primary) { + ret = HYPERVISOR_pmc_op(PMC_RESERVE_COUNTERS, (unsigned int)NULL, (unsigned int)NULL); + if (ret) + goto err; + ret = HYPERVISOR_pmc_op(PMC_SETUP_EVENTS, (unsigned int)&counter_config, (unsigned int)num_events); + if (ret) + goto err; + } + + ret = HYPERVISOR_pmc_op(PMC_ENABLE_VIRQ, (unsigned int)NULL, (unsigned int)NULL); + if (ret) + goto err; + + pmc_enabled = 1; + return 0; + + err: + unbind_pmc_ovf(); + return ret; + +} + +static void pmc_shutdown(void) +{ + + pmc_enabled = 0; + + HYPERVISOR_pmc_op(PMC_DISABLE_VIRQ, (unsigned int)NULL, (unsigned int)NULL); + + if (is_primary) { + HYPERVISOR_pmc_op(PMC_RELEASE_COUNTERS, (unsigned int)NULL, (unsigned int)NULL); + } + + unbind_pmc_ovf (); + +} + +static int pmc_start(void) +{ + int ret = 0; + + if (is_primary) + ret = HYPERVISOR_pmc_op(PMC_START, (unsigned int)NULL, (unsigned int)NULL); + return ret; +} + +static void pmc_stop(void) +{ + if (is_primary) + HYPERVISOR_pmc_op(PMC_STOP, (unsigned int)NULL, (unsigned int)NULL); +} + +static int pmc_set_active(int *active_domains, unsigned int adomains) +{ + int ret = 0; + if (is_primary) + ret = HYPERVISOR_pmc_op(PMC_SET_ACTIVE, + (unsigned int)active_domains, (unsigned int)adomains); + return ret; +} + +struct op_counter_config counter_config[OP_MAX_COUNTER]; + +static int pmc_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; +} + + +struct oprofile_operations pmc_ops = { + .create_files = pmc_create_files, + .set_active = pmc_set_active, + .setup = pmc_setup, + .shutdown = pmc_shutdown, + .start = pmc_start, + .stop = pmc_stop +}; + + +/* in order to get driverfs right */ +static int using_pmc; + +int __init oprofile_arch_init(struct oprofile_operations * ops) +{ + + pmc_init_result_t result; + xenoprof_buf_t* buf; + int max_samples = 16; + int vm_size; + int npages; + int i; + + int ret = HYPERVISOR_pmc_op(PMC_INIT, + (unsigned int)max_samples, + (unsigned int)&result); + + if ( !ret ) { + /* + __u8 vendor = current_cpu_data.x86_vendor; + __u8 family = current_cpu_data.x86; + */ + pgprot_t prot = __pgprot(_KERNPG_TABLE); + + num_events = result.num_events; + is_primary = result.is_primary; + nbuf = result.nbuf; + + npages = (result.bufsize * nbuf - 1) / PAGE_SIZE + 1; + vm_size = npages * PAGE_SIZE; + + + shared_buffer = (char *) vm_map_xen_pages(result.buf_maddr,vm_size,prot); + + if (!shared_buffer) + return -ENOMEM; + + for (i=0; i< nbuf; i++){ + buf = (xenoprof_buf_t*) &shared_buffer[i* result.bufsize]; + /* Just a sanity check - This should always be true */ + if ( buf->vcpu_id < MAX_VIRT_CPUS ) + xenoprof_buf[buf->vcpu_id] = buf; + } + + strncpy(cpu_type, result.cpu_type, XENOPROF_CPU_TYPE_SIZE); + pmc_ops.cpu_type = cpu_type; + + init_driverfs(); + using_pmc = 1; + *ops = pmc_ops; + + for (i=0; i