mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Remove sparse tree.
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
This commit is contained in:
1 parent
06809a93ad
commit
c58e445d1c
441 files changed
+5
-173455
No files matched your search
@@ -18,10 +18,11 @@ GPL when distributed separately or included in software packages
|
||||
outside this repository. Instead we specify a much more relaxed
|
||||
BSD-style license. Affected files include the Xen interface headers
|
||||
(xen/include/public/COPYING), and various drivers, support functions
|
||||
and header files within the Linux sparse source trees. In all such
|
||||
cases, license terms are stated at the top of the file or in a COPYING
|
||||
file in the same directory. Note that _any_ file that is modified and
|
||||
then distributed within a Linux kernel is still subject to the GNU GPL.
|
||||
and header files within the Linux source trees on
|
||||
http://xenbits.xensource.com/linux-2.6.X-xen.hg. In all such cases,
|
||||
license terms are stated at the top of the file or in a COPYING file
|
||||
in the same directory. Note that _any_ file that is modified and then
|
||||
distributed within a Linux kernel is still subject to the GNU GPL.
|
||||
|
||||
-- Keir Fraser (on behalf of the Xen team)
|
||||
|
||||
|
||||
@@ -92,11 +92,6 @@ kdelete:
|
||||
kclean:
|
||||
for i in $(XKERNELS) ; do $(MAKE) $$i-clean ; done
|
||||
|
||||
# Make patches from kernel sparse trees
|
||||
.PHONY: mkpatches
|
||||
mkpatches:
|
||||
for i in $(ALLSPARSETREES) ; do $(MAKE) $$i-xen.patch; done
|
||||
|
||||
# build xen, the tools, and a domain 0 plus unprivileged linux-xen images,
|
||||
# and place them in the install directory. 'make install' should then
|
||||
# copy them to the normal system directories
|
||||
@@ -121,7 +116,6 @@ distclean:
|
||||
$(MAKE) -C docs distclean
|
||||
rm -rf dist patches/tmp
|
||||
for i in $(ALLKERNELS) ; do $(MAKE) $$i-delete ; done
|
||||
for i in $(ALLSPARSETREES) ; do $(MAKE) $$i-mrproper ; done
|
||||
rm -rf patches/*/.makedep
|
||||
|
||||
# Linux name for GNU distclean
|
||||
@@ -157,8 +151,6 @@ help:
|
||||
@echo ''
|
||||
@echo 'Miscellaneous targets:'
|
||||
@echo ' prep-kernels - prepares kernel directories, does not build'
|
||||
@echo ' mkpatches - make patches against vanilla kernels from'
|
||||
@echo ' sparse trees'
|
||||
@echo ' uninstall - attempt to remove installed Xen tools'
|
||||
@echo ' (use with extreme care!)'
|
||||
@echo
|
||||
|
||||
@@ -114,8 +114,6 @@ performed with root privileges.]
|
||||
version for unstable.
|
||||
|
||||
2. cd to xen-unstable (or whatever you sensibly rename it to).
|
||||
The Linux, netbsd and freebsd kernel source trees are in
|
||||
the $os-$version-xen-sparse directories.
|
||||
|
||||
On Linux:
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ include Config.mk
|
||||
export DESTDIR
|
||||
|
||||
ALLKERNELS = $(patsubst buildconfigs/mk.%,%,$(wildcard buildconfigs/mk.*))
|
||||
ALLSPARSETREES = $(patsubst %-xen-sparse,%,$(wildcard *-xen-sparse))
|
||||
|
||||
%-install:
|
||||
$(MAKE) -f buildconfigs/mk.$* build
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
# Linux kernel version: 2.6.16.13-native
|
||||
# Mon May 15 10:59:54 2006
|
||||
#
|
||||
CONFIG_X86_PC=y
|
||||
# CONFIG_X86_XEN is not set
|
||||
# CONFIG_HPET_TIMER is not set
|
||||
# CONFIG_SCHED_SMT is not set
|
||||
# CONFIG_X86_MCE is not set
|
||||
# CONFIG_X86_MSR is not set
|
||||
# CONFIG_SWIOTLB is not set
|
||||
# CONFIG_EDD is not set
|
||||
CONFIG_ARCH_FLATMEM_ENABLE=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_SPARSEMEM_STATIC=y
|
||||
CONFIG_SPLIT_PTLOCK_CPUS=4
|
||||
# CONFIG_HIGHPTE is not set
|
||||
# CONFIG_MATH_EMULATION is not set
|
||||
# CONFIG_EFI is not set
|
||||
CONFIG_IRQBALANCE=y
|
||||
# CONFIG_KEXEC is not set
|
||||
CONFIG_DOUBLEFAULT=y
|
||||
CONFIG_PM_LEGACY=y
|
||||
# CONFIG_PM_DEBUG is not set
|
||||
# CONFIG_SOFTWARE_SUSPEND is not set
|
||||
CONFIG_SUSPEND_SMP=y
|
||||
CONFIG_ACPI_SLEEP=y
|
||||
CONFIG_ACPI_SLEEP_PROC_FS=y
|
||||
# CONFIG_ACPI_SLEEP_PROC_SLEEP is not set
|
||||
CONFIG_X86_PM_TIMER=y
|
||||
# APM (Advanced Power Management) BIOS Support
|
||||
#
|
||||
# CONFIG_APM is not set
|
||||
|
||||
#
|
||||
CONFIG_PCI_BIOS=y
|
||||
# CONFIG_XEN_PCIDEV_FRONTEND is not set
|
||||
# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
|
||||
# CONFIG_PCI_MSI is not set
|
||||
# CONFIG_ISA is not set
|
||||
# CONFIG_MCA is not set
|
||||
# CONFIG_HOTPLUG_PCI_COMPAQ is not set
|
||||
# CONFIG_HOTPLUG_PCI_IBM is not set
|
||||
# CONFIG_I2O_EXT_ADAPTEC_DMA64 is not set
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_SERIAL_CORE=y
|
||||
CONFIG_SERIAL_CORE_CONSOLE=y
|
||||
# CONFIG_TCG_XEN is not set
|
||||
# CONFIG_HUGETLBFS is not set
|
||||
# CONFIG_XEN is not set
|
||||
# CONFIG_XEN_INTERFACE_VERSION is not set
|
||||
|
||||
#
|
||||
# XEN
|
||||
#
|
||||
# CONFIG_XEN_PRIVILEGED_GUEST is not set
|
||||
# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
|
||||
# CONFIG_XEN_BACKEND is not set
|
||||
# CONFIG_XEN_PCIDEV_BACKEND is not set
|
||||
# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
|
||||
# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
|
||||
# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
|
||||
# CONFIG_XEN_BLKDEV_BACKEND is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP_BE is not set
|
||||
# CONFIG_XEN_NETDEV_BACKEND is not set
|
||||
# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_NETDEV_LOOPBACK is not set
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
# CONFIG_XEN_BLKDEV_FRONTEND is not set
|
||||
# CONFIG_XEN_NETDEV_FRONTEND is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SCRUB_PAGES is not set
|
||||
# CONFIG_XEN_DISABLE_SERIAL is not set
|
||||
# CONFIG_XEN_SYSFS is not set
|
||||
# CONFIG_XEN_COMPAT_030002_AND_LATER is not set
|
||||
# CONFIG_XEN_COMPAT_030004_AND_LATER is not set
|
||||
# CONFIG_XEN_COMPAT_LATEST_ONLY is not set
|
||||
# CONFIG_XEN_COMPAT_030002 is not set
|
||||
# CONFIG_XEN_COMPAT_030004 is not set
|
||||
# CONFIG_HAVE_ARCH_ALLOC_SKB is not set
|
||||
# CONFIG_HAVE_ARCH_DEV_ALLOC_SKB is not set
|
||||
# CONFIG_NO_IDLE_HZ is not set
|
||||
CONFIG_X86_HT=y
|
||||
# CONFIG_X86_NO_TSS is not set
|
||||
# CONFIG_X86_NO_IDT is not set
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
|
||||
# Parse arguments
|
||||
#
|
||||
if [ $# -lt 1 -o $# -gt 4 ]; then
|
||||
echo "Usage: $0 config-file EXTRAVERSION XEN_TARGET_ARCH XEN_SYSTYPE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config_file=$1
|
||||
extraversion=$2
|
||||
target_arch=$3
|
||||
systype=$4
|
||||
|
||||
|
||||
# Start with initial config skeleton file, if any.
|
||||
# Derive from linux-defconfig_xen_x86_32 otherwise.
|
||||
#
|
||||
skeleton=buildconfigs/linux-defconfig_${extraversion#-}_${target_arch}${systype}
|
||||
[ -r $skeleton ] || skeleton=buildconfigs/linux-defconfig_xen_x86_32
|
||||
[ -r $skeleton.local ] && skeleton=$skeleton.local
|
||||
cp $skeleton $config_file
|
||||
|
||||
echo "Using $skeleton as base config"
|
||||
|
||||
# Update
|
||||
#
|
||||
filter_template="s/^#\{0,1\} *\(CONFIG[^= ]*\).*/\/^#\\\{0,1\\\} *\1[= ].*\/d/p"
|
||||
config_dirs="buildconfigs/conf.linux buildconfigs/conf.linux-${target_arch} buildconfigs/conf.linux${extraversion} buildconfigs/conf.linux-${target_arch}${extraversion}"
|
||||
|
||||
for config_dir in $config_dirs
|
||||
do
|
||||
if [ -d $config_dir ]; then
|
||||
echo "Processing $config_dir..." 1>&2
|
||||
# processing is done in alphanumeric order
|
||||
find $config_dir -type f | sort | while read update
|
||||
do
|
||||
echo " ... $update" 1>&2
|
||||
# create the filter rules in a temp file
|
||||
filter_rules=`mktemp -t xenupdateconf.XXXXXXXXXX`
|
||||
sed -n "${filter_template}" < $update > $filter_rules
|
||||
|
||||
# filter the config file in place, removing any options that
|
||||
# will be updated.
|
||||
sed -f $filter_rules -i $config_file
|
||||
cat $update >> $config_file
|
||||
|
||||
# clean up
|
||||
rm -f $filter_rules
|
||||
done
|
||||
fi
|
||||
done
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,952 +0,0 @@
|
||||
#
|
||||
# Automatically generated make config: don't edit
|
||||
# Linux kernel version: 2.6.18-xenU
|
||||
# Wed Jan 17 18:36:21 2007
|
||||
#
|
||||
CONFIG_X86_32=y
|
||||
CONFIG_GENERIC_TIME=y
|
||||
CONFIG_LOCKDEP_SUPPORT=y
|
||||
CONFIG_STACKTRACE_SUPPORT=y
|
||||
CONFIG_SEMAPHORE_SLEEPERS=y
|
||||
CONFIG_X86=y
|
||||
CONFIG_MMU=y
|
||||
CONFIG_GENERIC_ISA_DMA=y
|
||||
CONFIG_GENERIC_IOMAP=y
|
||||
CONFIG_GENERIC_HWEIGHT=y
|
||||
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
|
||||
CONFIG_DMI=y
|
||||
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
|
||||
|
||||
#
|
||||
# Code maturity level options
|
||||
#
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_LOCK_KERNEL=y
|
||||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||
|
||||
#
|
||||
# General setup
|
||||
#
|
||||
CONFIG_LOCALVERSION=""
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_SWAP=y
|
||||
CONFIG_SYSVIPC=y
|
||||
# CONFIG_POSIX_MQUEUE is not set
|
||||
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||
# CONFIG_TASKSTATS is not set
|
||||
# CONFIG_AUDIT is not set
|
||||
# CONFIG_IKCONFIG is not set
|
||||
# CONFIG_CPUSETS is not set
|
||||
# CONFIG_RELAY is not set
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
# CONFIG_KALLSYMS_EXTRA_PASS is not set
|
||||
CONFIG_HOTPLUG=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_BUG=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_BASE_FULL=y
|
||||
CONFIG_FUTEX=y
|
||||
CONFIG_EPOLL=y
|
||||
CONFIG_SHMEM=y
|
||||
CONFIG_SLAB=y
|
||||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_RT_MUTEXES=y
|
||||
# CONFIG_TINY_SHMEM is not set
|
||||
CONFIG_BASE_SMALL=0
|
||||
# CONFIG_SLOB is not set
|
||||
|
||||
#
|
||||
# Loadable module support
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_MODULE_FORCE_UNLOAD is not set
|
||||
# CONFIG_MODVERSIONS is not set
|
||||
# CONFIG_MODULE_SRCVERSION_ALL is not set
|
||||
CONFIG_KMOD=y
|
||||
CONFIG_STOP_MACHINE=y
|
||||
|
||||
#
|
||||
# Block layer
|
||||
#
|
||||
# CONFIG_LBD is not set
|
||||
# CONFIG_BLK_DEV_IO_TRACE is not set
|
||||
CONFIG_LSF=y
|
||||
|
||||
#
|
||||
# IO Schedulers
|
||||
#
|
||||
CONFIG_IOSCHED_NOOP=y
|
||||
CONFIG_IOSCHED_AS=y
|
||||
CONFIG_IOSCHED_DEADLINE=y
|
||||
CONFIG_IOSCHED_CFQ=y
|
||||
CONFIG_DEFAULT_AS=y
|
||||
# CONFIG_DEFAULT_DEADLINE is not set
|
||||
# CONFIG_DEFAULT_CFQ is not set
|
||||
# CONFIG_DEFAULT_NOOP is not set
|
||||
CONFIG_DEFAULT_IOSCHED="anticipatory"
|
||||
|
||||
#
|
||||
# Processor type and features
|
||||
#
|
||||
CONFIG_SMP=y
|
||||
# CONFIG_X86_PC is not set
|
||||
CONFIG_X86_XEN=y
|
||||
# CONFIG_X86_ELAN is not set
|
||||
# CONFIG_X86_VOYAGER is not set
|
||||
# CONFIG_X86_NUMAQ is not set
|
||||
# CONFIG_X86_SUMMIT is not set
|
||||
# CONFIG_X86_BIGSMP is not set
|
||||
# CONFIG_X86_VISWS is not set
|
||||
# CONFIG_X86_GENERICARCH is not set
|
||||
# CONFIG_X86_ES7000 is not set
|
||||
# CONFIG_M386 is not set
|
||||
# CONFIG_M486 is not set
|
||||
# CONFIG_M586 is not set
|
||||
# CONFIG_M586TSC is not set
|
||||
# CONFIG_M586MMX is not set
|
||||
CONFIG_M686=y
|
||||
# CONFIG_MPENTIUMII is not set
|
||||
# CONFIG_MPENTIUMIII is not set
|
||||
# CONFIG_MPENTIUMM is not set
|
||||
# CONFIG_MPENTIUM4 is not set
|
||||
# CONFIG_MK6 is not set
|
||||
# CONFIG_MK7 is not set
|
||||
# CONFIG_MK8 is not set
|
||||
# CONFIG_MCRUSOE is not set
|
||||
# CONFIG_MEFFICEON is not set
|
||||
# CONFIG_MWINCHIPC6 is not set
|
||||
# CONFIG_MWINCHIP2 is not set
|
||||
# CONFIG_MWINCHIP3D is not set
|
||||
# CONFIG_MGEODEGX1 is not set
|
||||
# CONFIG_MGEODE_LX is not set
|
||||
# CONFIG_MCYRIXIII is not set
|
||||
# CONFIG_MVIAC3_2 is not set
|
||||
# CONFIG_X86_GENERIC is not set
|
||||
CONFIG_X86_CMPXCHG=y
|
||||
CONFIG_X86_XADD=y
|
||||
CONFIG_X86_L1_CACHE_SHIFT=5
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_X86_PPRO_FENCE=y
|
||||
CONFIG_X86_WP_WORKS_OK=y
|
||||
CONFIG_X86_INVLPG=y
|
||||
CONFIG_X86_BSWAP=y
|
||||
CONFIG_X86_POPAD_OK=y
|
||||
CONFIG_X86_CMPXCHG64=y
|
||||
CONFIG_X86_GOOD_APIC=y
|
||||
CONFIG_X86_USE_PPRO_CHECKSUM=y
|
||||
CONFIG_X86_TSC=y
|
||||
CONFIG_NR_CPUS=8
|
||||
CONFIG_PREEMPT_NONE=y
|
||||
# CONFIG_PREEMPT_VOLUNTARY is not set
|
||||
# CONFIG_PREEMPT is not set
|
||||
CONFIG_PREEMPT_BKL=y
|
||||
CONFIG_VM86=y
|
||||
# CONFIG_TOSHIBA is not set
|
||||
# CONFIG_I8K is not set
|
||||
# CONFIG_X86_REBOOTFIXUPS is not set
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_SWIOTLB=y
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
# CONFIG_DELL_RBU is not set
|
||||
# CONFIG_DCDBAS is not set
|
||||
# CONFIG_NOHIGHMEM is not set
|
||||
CONFIG_HIGHMEM4G=y
|
||||
# CONFIG_HIGHMEM64G is not set
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_FLATMEM_MANUAL=y
|
||||
# CONFIG_DISCONTIGMEM_MANUAL is not set
|
||||
# CONFIG_SPARSEMEM_MANUAL is not set
|
||||
CONFIG_FLATMEM=y
|
||||
CONFIG_FLAT_NODE_MEM_MAP=y
|
||||
# CONFIG_SPARSEMEM_STATIC is not set
|
||||
CONFIG_SPLIT_PTLOCK_CPUS=4096
|
||||
CONFIG_RESOURCES_64BIT=y
|
||||
# CONFIG_HIGHPTE is not set
|
||||
# CONFIG_REGPARM is not set
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_HZ_100=y
|
||||
# CONFIG_HZ_250 is not set
|
||||
# CONFIG_HZ_1000 is not set
|
||||
CONFIG_HZ=100
|
||||
# CONFIG_CRASH_DUMP is not set
|
||||
CONFIG_PHYSICAL_START=0x100000
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
|
||||
#
|
||||
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
|
||||
#
|
||||
# CONFIG_PCI is not set
|
||||
CONFIG_ISA_DMA_API=y
|
||||
# CONFIG_SCx200 is not set
|
||||
|
||||
#
|
||||
# PCCARD (PCMCIA/CardBus) support
|
||||
#
|
||||
# CONFIG_PCCARD is not set
|
||||
|
||||
#
|
||||
# PCI Hotplug Support
|
||||
#
|
||||
|
||||
#
|
||||
# Executable file formats
|
||||
#
|
||||
CONFIG_BINFMT_ELF=y
|
||||
# CONFIG_BINFMT_AOUT is not set
|
||||
# CONFIG_BINFMT_MISC is not set
|
||||
|
||||
#
|
||||
# Networking
|
||||
#
|
||||
CONFIG_NET=y
|
||||
|
||||
#
|
||||
# Networking options
|
||||
#
|
||||
# CONFIG_NETDEBUG is not set
|
||||
CONFIG_PACKET=y
|
||||
# CONFIG_PACKET_MMAP is not set
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM=y
|
||||
# CONFIG_XFRM_USER is not set
|
||||
# CONFIG_NET_KEY is not set
|
||||
CONFIG_INET=y
|
||||
# CONFIG_IP_MULTICAST is not set
|
||||
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||
CONFIG_IP_FIB_HASH=y
|
||||
CONFIG_IP_PNP=y
|
||||
# CONFIG_IP_PNP_DHCP is not set
|
||||
# CONFIG_IP_PNP_BOOTP is not set
|
||||
# CONFIG_IP_PNP_RARP is not set
|
||||
# CONFIG_NET_IPIP is not set
|
||||
# CONFIG_NET_IPGRE is not set
|
||||
# CONFIG_ARPD is not set
|
||||
# CONFIG_SYN_COOKIES is not set
|
||||
# CONFIG_INET_AH is not set
|
||||
# CONFIG_INET_ESP is not set
|
||||
# CONFIG_INET_IPCOMP is not set
|
||||
# CONFIG_INET_XFRM_TUNNEL is not set
|
||||
# CONFIG_INET_TUNNEL is not set
|
||||
CONFIG_INET_XFRM_MODE_TRANSPORT=y
|
||||
CONFIG_INET_XFRM_MODE_TUNNEL=y
|
||||
# CONFIG_INET_DIAG is not set
|
||||
# CONFIG_TCP_CONG_ADVANCED is not set
|
||||
CONFIG_TCP_CONG_BIC=y
|
||||
# CONFIG_IPV6 is not set
|
||||
# CONFIG_INET6_XFRM_TUNNEL is not set
|
||||
# CONFIG_INET6_TUNNEL is not set
|
||||
# CONFIG_NETWORK_SECMARK is not set
|
||||
# CONFIG_NETFILTER is not set
|
||||
|
||||
#
|
||||
# DCCP Configuration (EXPERIMENTAL)
|
||||
#
|
||||
# CONFIG_IP_DCCP is not set
|
||||
|
||||
#
|
||||
# SCTP Configuration (EXPERIMENTAL)
|
||||
#
|
||||
# CONFIG_IP_SCTP is not set
|
||||
|
||||
#
|
||||
# TIPC Configuration (EXPERIMENTAL)
|
||||
#
|
||||
# CONFIG_TIPC is not set
|
||||
# CONFIG_ATM is not set
|
||||
# CONFIG_BRIDGE is not set
|
||||
# CONFIG_VLAN_8021Q is not set
|
||||
# CONFIG_DECNET is not set
|
||||
# CONFIG_LLC2 is not set
|
||||
# CONFIG_IPX is not set
|
||||
# CONFIG_ATALK is not set
|
||||
# CONFIG_X25 is not set
|
||||
# CONFIG_LAPB is not set
|
||||
# CONFIG_ECONET is not set
|
||||
# CONFIG_WAN_ROUTER is not set
|
||||
|
||||
#
|
||||
# QoS and/or fair queueing
|
||||
#
|
||||
# CONFIG_NET_SCHED is not set
|
||||
|
||||
#
|
||||
# Network testing
|
||||
#
|
||||
# CONFIG_NET_PKTGEN is not set
|
||||
# CONFIG_HAMRADIO is not set
|
||||
# CONFIG_IRDA is not set
|
||||
# CONFIG_BT is not set
|
||||
# CONFIG_IEEE80211 is not set
|
||||
|
||||
#
|
||||
# Device Drivers
|
||||
#
|
||||
|
||||
#
|
||||
# Generic Driver Options
|
||||
#
|
||||
CONFIG_STANDALONE=y
|
||||
CONFIG_PREVENT_FIRMWARE_BUILD=y
|
||||
# CONFIG_FW_LOADER is not set
|
||||
# CONFIG_DEBUG_DRIVER is not set
|
||||
# CONFIG_SYS_HYPERVISOR is not set
|
||||
|
||||
#
|
||||
# Connector - unified userspace <-> kernelspace linker
|
||||
#
|
||||
# CONFIG_CONNECTOR is not set
|
||||
|
||||
#
|
||||
# Memory Technology Devices (MTD)
|
||||
#
|
||||
# CONFIG_MTD is not set
|
||||
|
||||
#
|
||||
# Parallel port support
|
||||
#
|
||||
# CONFIG_PARPORT is not set
|
||||
|
||||
#
|
||||
# Plug and Play support
|
||||
#
|
||||
|
||||
#
|
||||
# Block devices
|
||||
#
|
||||
# CONFIG_BLK_DEV_FD is not set
|
||||
# CONFIG_BLK_DEV_COW_COMMON is not set
|
||||
CONFIG_BLK_DEV_LOOP=m
|
||||
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
|
||||
CONFIG_BLK_DEV_NBD=m
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_CDROM_PKTCDVD is not set
|
||||
# CONFIG_ATA_OVER_ETH is not set
|
||||
|
||||
#
|
||||
# ATA/ATAPI/MFM/RLL support
|
||||
#
|
||||
# CONFIG_IDE is not set
|
||||
|
||||
#
|
||||
# SCSI device support
|
||||
#
|
||||
# CONFIG_RAID_ATTRS is not set
|
||||
CONFIG_SCSI=m
|
||||
CONFIG_SCSI_PROC_FS=y
|
||||
|
||||
#
|
||||
# SCSI support type (disk, tape, CD-ROM)
|
||||
#
|
||||
CONFIG_BLK_DEV_SD=m
|
||||
# CONFIG_CHR_DEV_ST is not set
|
||||
# CONFIG_CHR_DEV_OSST is not set
|
||||
# CONFIG_BLK_DEV_SR is not set
|
||||
# CONFIG_CHR_DEV_SG is not set
|
||||
# CONFIG_CHR_DEV_SCH is not set
|
||||
|
||||
#
|
||||
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
|
||||
#
|
||||
# CONFIG_SCSI_MULTI_LUN is not set
|
||||
# CONFIG_SCSI_CONSTANTS is not set
|
||||
# CONFIG_SCSI_LOGGING is not set
|
||||
|
||||
#
|
||||
# SCSI Transport Attributes
|
||||
#
|
||||
# CONFIG_SCSI_SPI_ATTRS is not set
|
||||
# CONFIG_SCSI_FC_ATTRS is not set
|
||||
# CONFIG_SCSI_ISCSI_ATTRS is not set
|
||||
# CONFIG_SCSI_SAS_ATTRS is not set
|
||||
|
||||
#
|
||||
# SCSI low-level drivers
|
||||
#
|
||||
# CONFIG_ISCSI_TCP is not set
|
||||
# CONFIG_SCSI_SATA is not set
|
||||
# CONFIG_SCSI_DEBUG is not set
|
||||
|
||||
#
|
||||
# Multi-device support (RAID and LVM)
|
||||
#
|
||||
# CONFIG_MD is not set
|
||||
|
||||
#
|
||||
# Fusion MPT device support
|
||||
#
|
||||
# CONFIG_FUSION is not set
|
||||
|
||||
#
|
||||
# IEEE 1394 (FireWire) support
|
||||
#
|
||||
|
||||
#
|
||||
# I2O device support
|
||||
#
|
||||
|
||||
#
|
||||
# Network device support
|
||||
#
|
||||
CONFIG_NETDEVICES=y
|
||||
# CONFIG_DUMMY is not set
|
||||
# CONFIG_BONDING is not set
|
||||
# CONFIG_EQUALIZER is not set
|
||||
# CONFIG_TUN is not set
|
||||
|
||||
#
|
||||
# PHY device support
|
||||
#
|
||||
|
||||
#
|
||||
# Ethernet (10 or 100Mbit)
|
||||
#
|
||||
# CONFIG_NET_ETHERNET is not set
|
||||
|
||||
#
|
||||
# Ethernet (1000 Mbit)
|
||||
#
|
||||
|
||||
#
|
||||
# Ethernet (10000 Mbit)
|
||||
#
|
||||
|
||||
#
|
||||
# Token Ring devices
|
||||
#
|
||||
|
||||
#
|
||||
# Wireless LAN (non-hamradio)
|
||||
#
|
||||
# CONFIG_NET_RADIO is not set
|
||||
|
||||
#
|
||||
# Wan interfaces
|
||||
#
|
||||
# CONFIG_WAN is not set
|
||||
# CONFIG_PPP is not set
|
||||
# CONFIG_SLIP is not set
|
||||
# CONFIG_SHAPER is not set
|
||||
# CONFIG_NETCONSOLE is not set
|
||||
# CONFIG_NETPOLL is not set
|
||||
# CONFIG_NET_POLL_CONTROLLER is not set
|
||||
|
||||
#
|
||||
# ISDN subsystem
|
||||
#
|
||||
# CONFIG_ISDN is not set
|
||||
|
||||
#
|
||||
# Telephony Support
|
||||
#
|
||||
# CONFIG_PHONE is not set
|
||||
|
||||
#
|
||||
# Input device support
|
||||
#
|
||||
CONFIG_INPUT=y
|
||||
|
||||
#
|
||||
# Userland interfaces
|
||||
#
|
||||
CONFIG_INPUT_MOUSEDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
|
||||
# CONFIG_INPUT_JOYDEV is not set
|
||||
# CONFIG_INPUT_TSDEV is not set
|
||||
# CONFIG_INPUT_EVDEV is not set
|
||||
# CONFIG_INPUT_EVBUG is not set
|
||||
|
||||
#
|
||||
# Input Device Drivers
|
||||
#
|
||||
CONFIG_INPUT_KEYBOARD=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
# CONFIG_KEYBOARD_SUNKBD is not set
|
||||
# CONFIG_KEYBOARD_LKKBD is not set
|
||||
# CONFIG_KEYBOARD_XTKBD is not set
|
||||
# CONFIG_KEYBOARD_NEWTON is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
# CONFIG_INPUT_JOYSTICK is not set
|
||||
# CONFIG_INPUT_TOUCHSCREEN is not set
|
||||
# CONFIG_INPUT_MISC is not set
|
||||
|
||||
#
|
||||
# Hardware I/O ports
|
||||
#
|
||||
CONFIG_SERIO=y
|
||||
CONFIG_SERIO_I8042=y
|
||||
CONFIG_SERIO_SERPORT=y
|
||||
# CONFIG_SERIO_CT82C710 is not set
|
||||
# CONFIG_SERIO_RAW is not set
|
||||
# CONFIG_GAMEPORT is not set
|
||||
|
||||
#
|
||||
# Character devices
|
||||
#
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
# CONFIG_VT_HW_CONSOLE_BINDING is not set
|
||||
# CONFIG_SERIAL_NONSTANDARD is not set
|
||||
|
||||
#
|
||||
# Serial drivers
|
||||
#
|
||||
|
||||
#
|
||||
# Non-8250 serial port support
|
||||
#
|
||||
CONFIG_UNIX98_PTYS=y
|
||||
CONFIG_LEGACY_PTYS=y
|
||||
CONFIG_LEGACY_PTY_COUNT=256
|
||||
|
||||
#
|
||||
# IPMI
|
||||
#
|
||||
# CONFIG_IPMI_HANDLER is not set
|
||||
|
||||
#
|
||||
# Watchdog Cards
|
||||
#
|
||||
# CONFIG_WATCHDOG is not set
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_VIA=y
|
||||
# CONFIG_NVRAM is not set
|
||||
# CONFIG_RTC is not set
|
||||
# CONFIG_GEN_RTC is not set
|
||||
# CONFIG_DTLK is not set
|
||||
# CONFIG_R3964 is not set
|
||||
|
||||
#
|
||||
# Ftape, the floppy tape device driver
|
||||
#
|
||||
# CONFIG_MWAVE is not set
|
||||
# CONFIG_PC8736x_GPIO is not set
|
||||
# CONFIG_NSC_GPIO is not set
|
||||
# CONFIG_CS5535_GPIO is not set
|
||||
# CONFIG_RAW_DRIVER is not set
|
||||
# CONFIG_HANGCHECK_TIMER is not set
|
||||
|
||||
#
|
||||
# TPM devices
|
||||
#
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_TELCLOCK is not set
|
||||
|
||||
#
|
||||
# I2C support
|
||||
#
|
||||
# CONFIG_I2C is not set
|
||||
|
||||
#
|
||||
# SPI support
|
||||
#
|
||||
# CONFIG_SPI is not set
|
||||
# CONFIG_SPI_MASTER is not set
|
||||
|
||||
#
|
||||
# Dallas's 1-wire bus
|
||||
#
|
||||
|
||||
#
|
||||
# Hardware Monitoring support
|
||||
#
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_HWMON_VID is not set
|
||||
|
||||
#
|
||||
# Misc devices
|
||||
#
|
||||
|
||||
#
|
||||
# Multimedia devices
|
||||
#
|
||||
# CONFIG_VIDEO_DEV is not set
|
||||
CONFIG_VIDEO_V4L2=y
|
||||
|
||||
#
|
||||
# Digital Video Broadcasting Devices
|
||||
#
|
||||
# CONFIG_DVB is not set
|
||||
|
||||
#
|
||||
# Graphics support
|
||||
#
|
||||
CONFIG_FIRMWARE_EDID=y
|
||||
# CONFIG_FB is not set
|
||||
|
||||
#
|
||||
# Console display driver support
|
||||
#
|
||||
CONFIG_VGA_CONSOLE=y
|
||||
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
|
||||
|
||||
#
|
||||
# Sound
|
||||
#
|
||||
# CONFIG_SOUND is not set
|
||||
|
||||
#
|
||||
# USB support
|
||||
#
|
||||
# CONFIG_USB_ARCH_HAS_HCD is not set
|
||||
# CONFIG_USB_ARCH_HAS_OHCI is not set
|
||||
# CONFIG_USB_ARCH_HAS_EHCI is not set
|
||||
|
||||
#
|
||||
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
|
||||
#
|
||||
|
||||
#
|
||||
# USB Gadget Support
|
||||
#
|
||||
# CONFIG_USB_GADGET is not set
|
||||
|
||||
#
|
||||
# MMC/SD Card support
|
||||
#
|
||||
# CONFIG_MMC is not set
|
||||
|
||||
#
|
||||
# LED devices
|
||||
#
|
||||
# CONFIG_NEW_LEDS is not set
|
||||
|
||||
#
|
||||
# LED drivers
|
||||
#
|
||||
|
||||
#
|
||||
# LED Triggers
|
||||
#
|
||||
|
||||
#
|
||||
# InfiniBand support
|
||||
#
|
||||
|
||||
#
|
||||
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
|
||||
#
|
||||
# CONFIG_EDAC is not set
|
||||
|
||||
#
|
||||
# Real Time Clock
|
||||
#
|
||||
# CONFIG_RTC_CLASS is not set
|
||||
|
||||
#
|
||||
# DMA Engine support
|
||||
#
|
||||
# CONFIG_DMA_ENGINE is not set
|
||||
|
||||
#
|
||||
# DMA Clients
|
||||
#
|
||||
|
||||
#
|
||||
# DMA Devices
|
||||
#
|
||||
|
||||
#
|
||||
# File systems
|
||||
#
|
||||
CONFIG_EXT2_FS=y
|
||||
# CONFIG_EXT2_FS_XATTR is not set
|
||||
# CONFIG_EXT2_FS_XIP is not set
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_EXT3_FS_XATTR=y
|
||||
# CONFIG_EXT3_FS_POSIX_ACL is not set
|
||||
# CONFIG_EXT3_FS_SECURITY is not set
|
||||
CONFIG_JBD=y
|
||||
# CONFIG_JBD_DEBUG is not set
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_REISERFS_FS=y
|
||||
# CONFIG_REISERFS_CHECK is not set
|
||||
# CONFIG_REISERFS_PROC_INFO is not set
|
||||
# CONFIG_REISERFS_FS_XATTR is not set
|
||||
# CONFIG_JFS_FS is not set
|
||||
# CONFIG_FS_POSIX_ACL is not set
|
||||
# CONFIG_XFS_FS is not set
|
||||
# CONFIG_OCFS2_FS is not set
|
||||
# CONFIG_MINIX_FS is not set
|
||||
# CONFIG_ROMFS_FS is not set
|
||||
CONFIG_INOTIFY=y
|
||||
CONFIG_INOTIFY_USER=y
|
||||
# CONFIG_QUOTA is not set
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_AUTOFS_FS=y
|
||||
CONFIG_AUTOFS4_FS=y
|
||||
# CONFIG_FUSE_FS is not set
|
||||
|
||||
#
|
||||
# CD-ROM/DVD Filesystems
|
||||
#
|
||||
CONFIG_ISO9660_FS=y
|
||||
CONFIG_JOLIET=y
|
||||
CONFIG_ZISOFS=y
|
||||
CONFIG_ZISOFS_FS=y
|
||||
# CONFIG_UDF_FS is not set
|
||||
|
||||
#
|
||||
# DOS/FAT/NT Filesystems
|
||||
#
|
||||
CONFIG_FAT_FS=m
|
||||
CONFIG_MSDOS_FS=m
|
||||
CONFIG_VFAT_FS=m
|
||||
CONFIG_FAT_DEFAULT_CODEPAGE=437
|
||||
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
|
||||
# CONFIG_NTFS_FS is not set
|
||||
|
||||
#
|
||||
# Pseudo filesystems
|
||||
#
|
||||
CONFIG_PROC_FS=y
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_SYSFS=y
|
||||
CONFIG_TMPFS=y
|
||||
# CONFIG_HUGETLB_PAGE is not set
|
||||
CONFIG_RAMFS=y
|
||||
# CONFIG_CONFIGFS_FS is not set
|
||||
|
||||
#
|
||||
# Miscellaneous filesystems
|
||||
#
|
||||
# CONFIG_ADFS_FS is not set
|
||||
# CONFIG_AFFS_FS is not set
|
||||
# CONFIG_HFS_FS is not set
|
||||
# CONFIG_HFSPLUS_FS is not set
|
||||
# CONFIG_BEFS_FS is not set
|
||||
# CONFIG_BFS_FS is not set
|
||||
# CONFIG_EFS_FS is not set
|
||||
CONFIG_CRAMFS=y
|
||||
# CONFIG_VXFS_FS is not set
|
||||
# CONFIG_HPFS_FS is not set
|
||||
# CONFIG_QNX4FS_FS is not set
|
||||
# CONFIG_SYSV_FS is not set
|
||||
# CONFIG_UFS_FS is not set
|
||||
|
||||
#
|
||||
# Network File Systems
|
||||
#
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V3=y
|
||||
# CONFIG_NFS_V3_ACL is not set
|
||||
# CONFIG_NFS_V4 is not set
|
||||
# CONFIG_NFS_DIRECTIO is not set
|
||||
# CONFIG_NFSD is not set
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_LOCKD=y
|
||||
CONFIG_LOCKD_V4=y
|
||||
CONFIG_NFS_COMMON=y
|
||||
CONFIG_SUNRPC=y
|
||||
# CONFIG_RPCSEC_GSS_KRB5 is not set
|
||||
# CONFIG_RPCSEC_GSS_SPKM3 is not set
|
||||
# CONFIG_SMB_FS is not set
|
||||
# CONFIG_CIFS is not set
|
||||
# CONFIG_NCP_FS is not set
|
||||
# CONFIG_CODA_FS is not set
|
||||
# CONFIG_AFS_FS is not set
|
||||
# CONFIG_9P_FS is not set
|
||||
|
||||
#
|
||||
# Partition Types
|
||||
#
|
||||
# CONFIG_PARTITION_ADVANCED is not set
|
||||
CONFIG_MSDOS_PARTITION=y
|
||||
|
||||
#
|
||||
# Native Language Support
|
||||
#
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NLS_DEFAULT="iso8859-1"
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
# CONFIG_NLS_CODEPAGE_737 is not set
|
||||
# CONFIG_NLS_CODEPAGE_775 is not set
|
||||
# CONFIG_NLS_CODEPAGE_850 is not set
|
||||
# CONFIG_NLS_CODEPAGE_852 is not set
|
||||
# CONFIG_NLS_CODEPAGE_855 is not set
|
||||
# CONFIG_NLS_CODEPAGE_857 is not set
|
||||
# CONFIG_NLS_CODEPAGE_860 is not set
|
||||
# CONFIG_NLS_CODEPAGE_861 is not set
|
||||
# CONFIG_NLS_CODEPAGE_862 is not set
|
||||
# CONFIG_NLS_CODEPAGE_863 is not set
|
||||
# CONFIG_NLS_CODEPAGE_864 is not set
|
||||
# CONFIG_NLS_CODEPAGE_865 is not set
|
||||
# CONFIG_NLS_CODEPAGE_866 is not set
|
||||
# CONFIG_NLS_CODEPAGE_869 is not set
|
||||
# CONFIG_NLS_CODEPAGE_936 is not set
|
||||
# CONFIG_NLS_CODEPAGE_950 is not set
|
||||
# CONFIG_NLS_CODEPAGE_932 is not set
|
||||
# CONFIG_NLS_CODEPAGE_949 is not set
|
||||
# CONFIG_NLS_CODEPAGE_874 is not set
|
||||
# CONFIG_NLS_ISO8859_8 is not set
|
||||
# CONFIG_NLS_CODEPAGE_1250 is not set
|
||||
# CONFIG_NLS_CODEPAGE_1251 is not set
|
||||
# CONFIG_NLS_ASCII is not set
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
# CONFIG_NLS_ISO8859_2 is not set
|
||||
# CONFIG_NLS_ISO8859_3 is not set
|
||||
# CONFIG_NLS_ISO8859_4 is not set
|
||||
# CONFIG_NLS_ISO8859_5 is not set
|
||||
# CONFIG_NLS_ISO8859_6 is not set
|
||||
# CONFIG_NLS_ISO8859_7 is not set
|
||||
# CONFIG_NLS_ISO8859_9 is not set
|
||||
# CONFIG_NLS_ISO8859_13 is not set
|
||||
# CONFIG_NLS_ISO8859_14 is not set
|
||||
# CONFIG_NLS_ISO8859_15 is not set
|
||||
# CONFIG_NLS_KOI8_R is not set
|
||||
# CONFIG_NLS_KOI8_U is not set
|
||||
# CONFIG_NLS_UTF8 is not set
|
||||
|
||||
#
|
||||
# Instrumentation Support
|
||||
#
|
||||
# CONFIG_PROFILING is not set
|
||||
# CONFIG_KPROBES is not set
|
||||
|
||||
#
|
||||
# Kernel hacking
|
||||
#
|
||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||
# CONFIG_PRINTK_TIME is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_UNUSED_SYMBOLS=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_DETECT_SOFTLOCKUP=y
|
||||
# CONFIG_SCHEDSTATS is not set
|
||||
# CONFIG_DEBUG_SLAB is not set
|
||||
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||
# CONFIG_RT_MUTEX_TESTER is not set
|
||||
# CONFIG_DEBUG_SPINLOCK is not set
|
||||
# CONFIG_DEBUG_MUTEXES is not set
|
||||
# CONFIG_DEBUG_RWSEMS is not set
|
||||
# CONFIG_DEBUG_LOCK_ALLOC is not set
|
||||
# CONFIG_PROVE_LOCKING is not set
|
||||
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
|
||||
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
|
||||
# CONFIG_DEBUG_KOBJECT is not set
|
||||
# CONFIG_DEBUG_HIGHMEM is not set
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_DEBUG_FS is not set
|
||||
# CONFIG_DEBUG_VM is not set
|
||||
CONFIG_FRAME_POINTER=y
|
||||
# CONFIG_UNWIND_INFO is not set
|
||||
CONFIG_FORCED_INLINING=y
|
||||
# CONFIG_RCU_TORTURE_TEST is not set
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_DEBUG_STACKOVERFLOW is not set
|
||||
# CONFIG_DEBUG_STACK_USAGE is not set
|
||||
# CONFIG_DEBUG_PAGEALLOC is not set
|
||||
# CONFIG_DEBUG_RODATA is not set
|
||||
# CONFIG_4KSTACKS is not set
|
||||
|
||||
#
|
||||
# Security options
|
||||
#
|
||||
# CONFIG_KEYS is not set
|
||||
# CONFIG_SECURITY is not set
|
||||
|
||||
#
|
||||
# Cryptographic options
|
||||
#
|
||||
CONFIG_CRYPTO=y
|
||||
# CONFIG_CRYPTO_HMAC is not set
|
||||
# CONFIG_CRYPTO_NULL is not set
|
||||
# CONFIG_CRYPTO_MD4 is not set
|
||||
CONFIG_CRYPTO_MD5=m
|
||||
# CONFIG_CRYPTO_SHA1 is not set
|
||||
# CONFIG_CRYPTO_SHA256 is not set
|
||||
# CONFIG_CRYPTO_SHA512 is not set
|
||||
# CONFIG_CRYPTO_WP512 is not set
|
||||
# CONFIG_CRYPTO_TGR192 is not set
|
||||
# CONFIG_CRYPTO_DES is not set
|
||||
# CONFIG_CRYPTO_BLOWFISH is not set
|
||||
# CONFIG_CRYPTO_TWOFISH is not set
|
||||
# CONFIG_CRYPTO_SERPENT is not set
|
||||
# CONFIG_CRYPTO_AES is not set
|
||||
# CONFIG_CRYPTO_AES_586 is not set
|
||||
# CONFIG_CRYPTO_CAST5 is not set
|
||||
# CONFIG_CRYPTO_CAST6 is not set
|
||||
# CONFIG_CRYPTO_TEA is not set
|
||||
# CONFIG_CRYPTO_ARC4 is not set
|
||||
# CONFIG_CRYPTO_KHAZAD is not set
|
||||
# CONFIG_CRYPTO_ANUBIS is not set
|
||||
# CONFIG_CRYPTO_DEFLATE is not set
|
||||
# CONFIG_CRYPTO_MICHAEL_MIC is not set
|
||||
CONFIG_CRYPTO_CRC32C=m
|
||||
# CONFIG_CRYPTO_TEST is not set
|
||||
|
||||
#
|
||||
# Hardware crypto devices
|
||||
#
|
||||
# CONFIG_CRYPTO_DEV_PADLOCK is not set
|
||||
CONFIG_XEN=y
|
||||
CONFIG_XEN_INTERFACE_VERSION=0x00030205
|
||||
|
||||
#
|
||||
# XEN
|
||||
#
|
||||
# CONFIG_XEN_PRIVILEGED_GUEST is not set
|
||||
CONFIG_XEN_UNPRIVILEGED_GUEST=y
|
||||
CONFIG_XEN_PRIVCMD=y
|
||||
CONFIG_XEN_XENBUS_DEV=y
|
||||
# CONFIG_XEN_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_SCRUB_PAGES=y
|
||||
CONFIG_XEN_DISABLE_SERIAL=y
|
||||
CONFIG_XEN_SYSFS=y
|
||||
CONFIG_XEN_COMPAT_030002_AND_LATER=y
|
||||
# CONFIG_XEN_COMPAT_030004_AND_LATER is not set
|
||||
# CONFIG_XEN_COMPAT_LATEST_ONLY is not set
|
||||
CONFIG_XEN_COMPAT_030002=y
|
||||
CONFIG_XEN_COMPAT_030004=y
|
||||
CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y
|
||||
CONFIG_NO_IDLE_HZ=y
|
||||
CONFIG_XEN_UTIL=y
|
||||
CONFIG_XEN_BALLOON=y
|
||||
CONFIG_XEN_DEVMEM=y
|
||||
CONFIG_XEN_REBOOT=y
|
||||
CONFIG_XEN_SMPBOOT=y
|
||||
|
||||
#
|
||||
# Library routines
|
||||
#
|
||||
# CONFIG_CRC_CCITT is not set
|
||||
# CONFIG_CRC16 is not set
|
||||
# CONFIG_CRC32 is not set
|
||||
CONFIG_LIBCRC32C=m
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
CONFIG_PLIST=y
|
||||
CONFIG_GENERIC_HARDIRQS=y
|
||||
CONFIG_GENERIC_IRQ_PROBE=y
|
||||
CONFIG_GENERIC_PENDING_IRQ=y
|
||||
CONFIG_X86_SMP=y
|
||||
CONFIG_X86_BIOS_REBOOT=y
|
||||
CONFIG_X86_TRAMPOLINE=y
|
||||
CONFIG_X86_NO_TSS=y
|
||||
CONFIG_X86_NO_IDT=y
|
||||
CONFIG_KTIME_SCALAR=y
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,74 +0,0 @@
|
||||
# Choose the best mirror to download linux kernel
|
||||
KERNEL_REPO = http://www.kernel.org
|
||||
|
||||
LINUX_SRCDIR ?= linux-$(LINUX_VER)-xen
|
||||
|
||||
# Setup pristine search path
|
||||
PRISTINE_SRC_PATH ?= .:..
|
||||
vpath pristine-% $(PRISTINE_SRC_PATH)
|
||||
|
||||
vpath linux-%.tar.bz2 $(LINUX_SRC_PATH)
|
||||
vpath patch-%.bz2 $(LINUX_SRC_PATH)
|
||||
|
||||
# download a pristine Linux kernel tarball if there isn't one in LINUX_SRC_PATH
|
||||
linux-%.tar.bz2: override _LINUX_VDIR = $(word 1,$(subst ., ,$*)).$(word 2,$(subst ., ,$*))
|
||||
linux-%.tar.bz2:
|
||||
@echo "Cannot find $@ in path $(LINUX_SRC_PATH)"
|
||||
wget $(KERNEL_REPO)/pub/linux/kernel/v$(_LINUX_VDIR)/$@ -O./$@
|
||||
|
||||
patch-%.bz2: override _LINUX_VDIR = $(word 1,$(subst ., ,$(*F))).$(word 2,$(subst ., ,$(*F)))
|
||||
patch-%.bz2: override _LINUX_XDIR = $(if $(word 3,$(subst -, ,$(*F))),snapshots,testing)
|
||||
patch-%.bz2:
|
||||
@echo "Cannot find $(@F) in path $(LINUX_SRC_PATH)"
|
||||
wget $(KERNEL_REPO)/pub/linux/kernel/v$(_LINUX_VDIR)/$(_LINUX_XDIR)/$(@F) -O./$@
|
||||
|
||||
pristine-%: pristine-%/.valid-pristine
|
||||
@true
|
||||
|
||||
pristine-%/.valid-pristine: %.tar.bz2
|
||||
rm -rf tmp-pristine-$* $(@D)
|
||||
mkdir -p tmp-pristine-$*
|
||||
tar -C tmp-pristine-$* -jxf $<
|
||||
-@rm -f tmp-pristine-$*/pax_global_header
|
||||
mv tmp-pristine-$*/* $(@D)
|
||||
@rm -rf tmp-pristine-$*
|
||||
touch $(@D)/.hgskip
|
||||
touch $@ # update timestamp to avoid rebuild
|
||||
|
||||
PATCHDIRS := $(wildcard patches/*-*)
|
||||
|
||||
ifneq ($(PATCHDIRS),)
|
||||
-include $(patsubst %,%/.makedep,$(PATCHDIRS))
|
||||
|
||||
$(patsubst patches/%,patches/%/.makedep,$(PATCHDIRS)): patches/%/.makedep:
|
||||
@echo 'ref-$*/.valid-ref: $$(wildcard patches/$*/*.patch)' >$@
|
||||
|
||||
ref-%/.valid-ref: pristine-%/.valid-pristine
|
||||
set -e
|
||||
rm -rf $(@D)
|
||||
cp -al $(<D) $(@D)
|
||||
if [ -d patches/$* ] ; then \
|
||||
echo Applying patches from patches/$*... ; \
|
||||
for i in $$(cat patches/$*/series) ; do \
|
||||
echo ... $$i ; \
|
||||
patch -d $(@D) -p1 --quiet <patches/$*/$$i || exit 1 ; \
|
||||
done ; \
|
||||
fi
|
||||
touch $@ # update timestamp to avoid rebuild
|
||||
endif
|
||||
|
||||
$(LINUX_SRCDIR)/.valid-src: ref-linux-$(LINUX_VER)/.valid-ref
|
||||
rm -rf $(LINUX_SRCDIR)
|
||||
cp -al $(<D) $(LINUX_SRCDIR)
|
||||
# Apply arch-xen patches
|
||||
( cd linux-$(LINUX_SERIES)-xen-sparse && \
|
||||
LINUX_ARCH=$(LINUX_ARCH) bash ./mkbuildtree ../$(LINUX_SRCDIR) )
|
||||
( cd $(LINUX_SRCDIR) && [ -e buildconfigs ] || ln -s $(PWD)/buildconfigs buildconfigs )
|
||||
touch $@
|
||||
|
||||
linux-2.6-xen.patch: ref-linux-$(LINUX_VER)/.valid-ref
|
||||
rm -rf tmp-$@
|
||||
cp -al $(<D) tmp-$@
|
||||
( cd linux-2.6-xen-sparse && bash ./mkbuildtree ../tmp-$@ )
|
||||
diff -Nurp $(patsubst ref%,pristine%,$(<D)) tmp-$@ > $@ || true
|
||||
rm -rf tmp-$@
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,315 +0,0 @@
|
||||
# Put here option for CPU selection and depending optimization
|
||||
if !X86_ELAN
|
||||
|
||||
choice
|
||||
prompt "Processor family"
|
||||
default M686
|
||||
|
||||
config M386
|
||||
bool "386"
|
||||
---help---
|
||||
This is the processor type of your CPU. This information is used for
|
||||
optimizing purposes. In order to compile a kernel that can run on
|
||||
all x86 CPU types (albeit not optimally fast), you can specify
|
||||
"386" here.
|
||||
|
||||
The kernel will not necessarily run on earlier architectures than
|
||||
the one you have chosen, e.g. a Pentium optimized kernel will run on
|
||||
a PPro, but not necessarily on a i486.
|
||||
|
||||
Here are the settings recommended for greatest speed:
|
||||
- "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI
|
||||
486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels
|
||||
will run on a 386 class machine.
|
||||
- "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or
|
||||
SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S.
|
||||
- "586" for generic Pentium CPUs lacking the TSC
|
||||
(time stamp counter) register.
|
||||
- "Pentium-Classic" for the Intel Pentium.
|
||||
- "Pentium-MMX" for the Intel Pentium MMX.
|
||||
- "Pentium-Pro" for the Intel Pentium Pro.
|
||||
- "Pentium-II" for the Intel Pentium II or pre-Coppermine Celeron.
|
||||
- "Pentium-III" for the Intel Pentium III or Coppermine Celeron.
|
||||
- "Pentium-4" for the Intel Pentium 4 or P4-based Celeron.
|
||||
- "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
|
||||
- "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird).
|
||||
- "Crusoe" for the Transmeta Crusoe series.
|
||||
- "Efficeon" for the Transmeta Efficeon series.
|
||||
- "Winchip-C6" for original IDT Winchip.
|
||||
- "Winchip-2" for IDT Winchip 2.
|
||||
- "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
|
||||
- "GeodeGX1" for Geode GX1 (Cyrix MediaGX).
|
||||
- "Geode GX/LX" For AMD Geode GX and LX processors.
|
||||
- "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
|
||||
- "VIA C3-2" for VIA C3-2 "Nehemiah" (model 9 and above).
|
||||
|
||||
If you don't know what to do, choose "386".
|
||||
|
||||
config M486
|
||||
bool "486"
|
||||
help
|
||||
Select this for a 486 series processor, either Intel or one of the
|
||||
compatible processors from AMD, Cyrix, IBM, or Intel. Includes DX,
|
||||
DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or
|
||||
U5S.
|
||||
|
||||
config M586
|
||||
bool "586/K5/5x86/6x86/6x86MX"
|
||||
help
|
||||
Select this for an 586 or 686 series processor such as the AMD K5,
|
||||
the Cyrix 5x86, 6x86 and 6x86MX. This choice does not
|
||||
assume the RDTSC (Read Time Stamp Counter) instruction.
|
||||
|
||||
config M586TSC
|
||||
bool "Pentium-Classic"
|
||||
help
|
||||
Select this for a Pentium Classic processor with the RDTSC (Read
|
||||
Time Stamp Counter) instruction for benchmarking.
|
||||
|
||||
config M586MMX
|
||||
bool "Pentium-MMX"
|
||||
help
|
||||
Select this for a Pentium with the MMX graphics/multimedia
|
||||
extended instructions.
|
||||
|
||||
config M686
|
||||
bool "Pentium-Pro"
|
||||
help
|
||||
Select this for Intel Pentium Pro chips. This enables the use of
|
||||
Pentium Pro extended instructions, and disables the init-time guard
|
||||
against the f00f bug found in earlier Pentiums.
|
||||
|
||||
config MPENTIUMII
|
||||
bool "Pentium-II/Celeron(pre-Coppermine)"
|
||||
help
|
||||
Select this for Intel chips based on the Pentium-II and
|
||||
pre-Coppermine Celeron core. This option enables an unaligned
|
||||
copy optimization, compiles the kernel with optimization flags
|
||||
tailored for the chip, and applies any applicable Pentium Pro
|
||||
optimizations.
|
||||
|
||||
config MPENTIUMIII
|
||||
bool "Pentium-III/Celeron(Coppermine)/Pentium-III Xeon"
|
||||
help
|
||||
Select this for Intel chips based on the Pentium-III and
|
||||
Celeron-Coppermine core. This option enables use of some
|
||||
extended prefetch instructions in addition to the Pentium II
|
||||
extensions.
|
||||
|
||||
config MPENTIUMM
|
||||
bool "Pentium M"
|
||||
help
|
||||
Select this for Intel Pentium M (not Pentium-4 M)
|
||||
notebook chips.
|
||||
|
||||
config MPENTIUM4
|
||||
bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/Xeon"
|
||||
help
|
||||
Select this for Intel Pentium 4 chips. This includes the
|
||||
Pentium 4, P4-based Celeron and Xeon, and Pentium-4 M
|
||||
(not Pentium M) chips. This option enables compile flags
|
||||
optimized for the chip, uses the correct cache shift, and
|
||||
applies any applicable Pentium III optimizations.
|
||||
|
||||
config MK6
|
||||
bool "K6/K6-II/K6-III"
|
||||
help
|
||||
Select this for an AMD K6-family processor. Enables use of
|
||||
some extended instructions, and passes appropriate optimization
|
||||
flags to GCC.
|
||||
|
||||
config MK7
|
||||
bool "Athlon/Duron/K7"
|
||||
help
|
||||
Select this for an AMD Athlon K7-family processor. Enables use of
|
||||
some extended instructions, and passes appropriate optimization
|
||||
flags to GCC.
|
||||
|
||||
config MK8
|
||||
bool "Opteron/Athlon64/Hammer/K8"
|
||||
help
|
||||
Select this for an AMD Opteron or Athlon64 Hammer-family processor. Enables
|
||||
use of some extended instructions, and passes appropriate optimization
|
||||
flags to GCC.
|
||||
|
||||
config MCRUSOE
|
||||
bool "Crusoe"
|
||||
help
|
||||
Select this for a Transmeta Crusoe processor. Treats the processor
|
||||
like a 586 with TSC, and sets some GCC optimization flags (like a
|
||||
Pentium Pro with no alignment requirements).
|
||||
|
||||
config MEFFICEON
|
||||
bool "Efficeon"
|
||||
help
|
||||
Select this for a Transmeta Efficeon processor.
|
||||
|
||||
config MWINCHIPC6
|
||||
bool "Winchip-C6"
|
||||
help
|
||||
Select this for an IDT Winchip C6 chip. Linux and GCC
|
||||
treat this chip as a 586TSC with some extended instructions
|
||||
and alignment requirements.
|
||||
|
||||
config MWINCHIP2
|
||||
bool "Winchip-2"
|
||||
help
|
||||
Select this for an IDT Winchip-2. Linux and GCC
|
||||
treat this chip as a 586TSC with some extended instructions
|
||||
and alignment requirements.
|
||||
|
||||
config MWINCHIP3D
|
||||
bool "Winchip-2A/Winchip-3"
|
||||
help
|
||||
Select this for an IDT Winchip-2A or 3. Linux and GCC
|
||||
treat this chip as a 586TSC with some extended instructions
|
||||
and alignment reqirements. Also enable out of order memory
|
||||
stores for this CPU, which can increase performance of some
|
||||
operations.
|
||||
|
||||
config MGEODEGX1
|
||||
bool "GeodeGX1"
|
||||
help
|
||||
Select this for a Geode GX1 (Cyrix MediaGX) chip.
|
||||
|
||||
config MGEODE_LX
|
||||
bool "Geode GX/LX"
|
||||
help
|
||||
Select this for AMD Geode GX and LX processors.
|
||||
|
||||
config MCYRIXIII
|
||||
bool "CyrixIII/VIA-C3"
|
||||
help
|
||||
Select this for a Cyrix III or C3 chip. Presently Linux and GCC
|
||||
treat this chip as a generic 586. Whilst the CPU is 686 class,
|
||||
it lacks the cmov extension which gcc assumes is present when
|
||||
generating 686 code.
|
||||
Note that Nehemiah (Model 9) and above will not boot with this
|
||||
kernel due to them lacking the 3DNow! instructions used in earlier
|
||||
incarnations of the CPU.
|
||||
|
||||
config MVIAC3_2
|
||||
bool "VIA C3-2 (Nehemiah)"
|
||||
help
|
||||
Select this for a VIA C3 "Nehemiah". Selecting this enables usage
|
||||
of SSE and tells gcc to treat the CPU as a 686.
|
||||
Note, this kernel will not boot on older (pre model 9) C3s.
|
||||
|
||||
endchoice
|
||||
|
||||
config X86_GENERIC
|
||||
bool "Generic x86 support"
|
||||
help
|
||||
Instead of just including optimizations for the selected
|
||||
x86 variant (e.g. PII, Crusoe or Athlon), include some more
|
||||
generic optimizations as well. This will make the kernel
|
||||
perform better on x86 CPUs other than that selected.
|
||||
|
||||
This is really intended for distributors who need more
|
||||
generic optimizations.
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Define implied options from the CPU selection here
|
||||
#
|
||||
config X86_CMPXCHG
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_XADD
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_L1_CACHE_SHIFT
|
||||
int
|
||||
default "7" if MPENTIUM4 || X86_GENERIC
|
||||
default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
|
||||
default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
|
||||
default "6" if MK7 || MK8 || MPENTIUMM
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
depends on M386
|
||||
default y
|
||||
|
||||
config RWSEM_XCHGADD_ALGORITHM
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config X86_PPRO_FENCE
|
||||
bool
|
||||
depends on M686 || M586MMX || M586TSC || M586 || M486 || M386 || MGEODEGX1
|
||||
default y
|
||||
|
||||
config X86_F00F_BUG
|
||||
bool
|
||||
depends on (M586MMX || M586TSC || M586 || M486 || M386) && !X86_NO_IDT
|
||||
default y
|
||||
|
||||
config X86_WP_WORKS_OK
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_INVLPG
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_BSWAP
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_POPAD_OK
|
||||
bool
|
||||
depends on !M386
|
||||
default y
|
||||
|
||||
config X86_CMPXCHG64
|
||||
bool
|
||||
depends on !M386 && !M486
|
||||
default y
|
||||
|
||||
config X86_ALIGNMENT_16
|
||||
bool
|
||||
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
|
||||
default y
|
||||
|
||||
config X86_GOOD_APIC
|
||||
bool
|
||||
depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON
|
||||
default y
|
||||
|
||||
config X86_INTEL_USERCOPY
|
||||
bool
|
||||
depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON
|
||||
default y
|
||||
|
||||
config X86_USE_PPRO_CHECKSUM
|
||||
bool
|
||||
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX
|
||||
default y
|
||||
|
||||
config X86_USE_3DNOW
|
||||
bool
|
||||
depends on MCYRIXIII || MK7 || MGEODE_LX
|
||||
default y
|
||||
|
||||
config X86_OOSTORE
|
||||
bool
|
||||
depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
|
||||
default y
|
||||
|
||||
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) && !X86_NUMAQ && !X86_XEN
|
||||
default y
|
||||
@@ -1,89 +0,0 @@
|
||||
menu "Kernel hacking"
|
||||
|
||||
config TRACE_IRQFLAGS_SUPPORT
|
||||
bool
|
||||
default y
|
||||
|
||||
source "lib/Kconfig.debug"
|
||||
|
||||
config EARLY_PRINTK
|
||||
bool "Early printk" if EMBEDDED && DEBUG_KERNEL
|
||||
default y
|
||||
help
|
||||
Write kernel log output directly into the VGA buffer or to a serial
|
||||
port.
|
||||
|
||||
This is useful for kernel debugging when your machine crashes very
|
||||
early before the console code is initialized. For normal operation
|
||||
it is not recommended because it looks ugly and doesn't cooperate
|
||||
with klogd/syslogd or the X server. You should normally N here,
|
||||
unless you want to debug such a crash.
|
||||
|
||||
config DEBUG_STACKOVERFLOW
|
||||
bool "Check for stack overflows"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
This option will cause messages to be printed if free stack space
|
||||
drops below a certain limit.
|
||||
|
||||
config DEBUG_STACK_USAGE
|
||||
bool "Stack utilization instrumentation"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Enables the display of the minimum amount of free stack which each
|
||||
task has ever had available in the sysrq-T and sysrq-P debug output.
|
||||
|
||||
This option will slow down process creation somewhat.
|
||||
|
||||
comment "Page alloc debug is incompatible with Software Suspend on i386"
|
||||
depends on DEBUG_KERNEL && SOFTWARE_SUSPEND
|
||||
|
||||
config DEBUG_PAGEALLOC
|
||||
bool "Debug page memory allocations"
|
||||
depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND && !HUGETLBFS
|
||||
help
|
||||
Unmap pages from the kernel linear mapping after free_pages().
|
||||
This results in a large slowdown, but helps to find certain types
|
||||
of memory corruptions.
|
||||
|
||||
config DEBUG_RODATA
|
||||
bool "Write protect kernel read-only data structures"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Mark the kernel read-only data as write-protected in the pagetables,
|
||||
in order to catch accidental (and incorrect) writes to such const
|
||||
data. This option may have a slight performance impact because a
|
||||
portion of the kernel code won't be covered by a 2MB TLB anymore.
|
||||
If in doubt, say "N".
|
||||
|
||||
config 4KSTACKS
|
||||
bool "Use 4Kb for kernel stacks instead of 8Kb"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
If you say Y here the kernel will use a 4Kb stacksize for the
|
||||
kernel stack attached to each process/thread. This facilitates
|
||||
running more threads on a system and also reduces the pressure
|
||||
on the VM subsystem for higher order allocations. This option
|
||||
will also use IRQ stacks to compensate for the reduced stackspace.
|
||||
|
||||
config X86_FIND_SMP_CONFIG
|
||||
bool
|
||||
depends on X86_LOCAL_APIC || X86_VOYAGER
|
||||
default y
|
||||
|
||||
config X86_MPPARSE
|
||||
bool
|
||||
depends on X86_LOCAL_APIC && !X86_VISWS
|
||||
default y
|
||||
|
||||
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
|
||||
option saves about 4k and might cause you much additional grey
|
||||
hair.
|
||||
|
||||
endmenu
|
||||
@@ -1,171 +0,0 @@
|
||||
#
|
||||
# i386/Makefile
|
||||
#
|
||||
# This file is included by the global makefile so that you can add your own
|
||||
# architecture-specific flags and dependencies. Remember to do have actions
|
||||
# for "archclean" cleaning up for this architecture.
|
||||
#
|
||||
# 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) 1994 by Linus Torvalds
|
||||
#
|
||||
# 19990713 Artur Skawina <skawina@geocities.com>
|
||||
# Added '-march' and '-mpreferred-stack-boundary' support
|
||||
#
|
||||
# 20050320 Kianusch Sayah Karadji <kianusch@sk-tech.net>
|
||||
# Added support for GEODE CPU
|
||||
|
||||
HAS_BIARCH := $(call cc-option-yn, -m32)
|
||||
ifeq ($(HAS_BIARCH),y)
|
||||
AS := $(AS) --32
|
||||
LD := $(LD) -m elf_i386
|
||||
CC := $(CC) -m32
|
||||
endif
|
||||
|
||||
LDFLAGS := -m elf_i386
|
||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
||||
LDFLAGS_vmlinux :=
|
||||
CHECKFLAGS += -D__i386__
|
||||
|
||||
CFLAGS += -pipe -msoft-float
|
||||
|
||||
# prevent gcc from keeping the stack 16 byte aligned
|
||||
CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
|
||||
|
||||
# CPU-specific tuning. Anything which can be shared with UML should go here.
|
||||
include $(srctree)/arch/i386/Makefile.cpu
|
||||
|
||||
cflags-$(CONFIG_REGPARM) += -mregparm=3
|
||||
|
||||
# temporary until string.h is fixed
|
||||
cflags-y += -ffreestanding
|
||||
|
||||
# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
|
||||
# a lot more stack due to the lack of sharing of stacklots:
|
||||
CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-option,-fno-unit-at-a-time); fi ;)
|
||||
|
||||
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
|
||||
|
||||
# Voyager subarch support
|
||||
mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-i386/mach-voyager
|
||||
mcore-$(CONFIG_X86_VOYAGER) := mach-voyager
|
||||
|
||||
# VISWS subarch support
|
||||
mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-i386/mach-visws
|
||||
mcore-$(CONFIG_X86_VISWS) := mach-visws
|
||||
|
||||
# NUMAQ subarch support
|
||||
mflags-$(CONFIG_X86_NUMAQ) := -Iinclude/asm-i386/mach-numaq
|
||||
mcore-$(CONFIG_X86_NUMAQ) := mach-default
|
||||
|
||||
# BIGSMP subarch support
|
||||
mflags-$(CONFIG_X86_BIGSMP) := -Iinclude/asm-i386/mach-bigsmp
|
||||
mcore-$(CONFIG_X86_BIGSMP) := mach-default
|
||||
|
||||
#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
|
||||
mcore-$(CONFIG_X86_GENERICARCH) := mach-default
|
||||
core-$(CONFIG_X86_GENERICARCH) += arch/i386/mach-generic/
|
||||
|
||||
# ES7000 subarch support
|
||||
mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000
|
||||
mcore-$(CONFIG_X86_ES7000) := mach-default
|
||||
core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/
|
||||
|
||||
# default subarch .h files
|
||||
mflags-y += -Iinclude/asm-i386/mach-default
|
||||
|
||||
head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
|
||||
|
||||
libs-y += arch/i386/lib/
|
||||
core-y += arch/i386/kernel/ \
|
||||
arch/i386/mm/ \
|
||||
arch/i386/$(mcore-y)/ \
|
||||
arch/i386/crypto/
|
||||
drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/
|
||||
drivers-$(CONFIG_PCI) += arch/i386/pci/
|
||||
# must be linked after kernel/
|
||||
drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/
|
||||
drivers-$(CONFIG_PM) += arch/i386/power/
|
||||
|
||||
CFLAGS += $(mflags-y)
|
||||
AFLAGS += $(mflags-y)
|
||||
|
||||
boot := arch/i386/boot
|
||||
|
||||
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-xen.o
|
||||
boot := arch/i386/boot-xen
|
||||
.PHONY: vmlinuz
|
||||
all: vmlinuz
|
||||
|
||||
vmlinuz: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||
|
||||
install:
|
||||
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||
else
|
||||
all: bzImage
|
||||
|
||||
# KBUILD_IMAGE specify target image being built
|
||||
KBUILD_IMAGE := $(boot)/bzImage
|
||||
zImage zlilo zdisk: KBUILD_IMAGE := arch/i386/boot/zImage
|
||||
|
||||
zImage bzImage: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
|
||||
|
||||
compressed: zImage
|
||||
|
||||
zlilo bzlilo: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zlilo
|
||||
|
||||
zdisk bzdisk: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) zdisk
|
||||
|
||||
fdimage fdimage144 fdimage288 isoimage: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
|
||||
|
||||
install:
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
|
||||
endif
|
||||
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=arch/i386/boot
|
||||
|
||||
define archhelp
|
||||
echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
|
||||
echo ' install - Install kernel using'
|
||||
echo ' (your) ~/bin/installkernel or'
|
||||
echo ' (distribution) /sbin/installkernel or'
|
||||
echo ' install to $$(INSTALL_PATH) and run lilo'
|
||||
echo ' bzdisk - Create a boot floppy in /dev/fd0'
|
||||
echo ' fdimage - Create a boot floppy image'
|
||||
echo ' isoimage - Create a boot CD-ROM image'
|
||||
endef
|
||||
|
||||
CLEAN_FILES += arch/$(ARCH)/boot/fdimage \
|
||||
arch/$(ARCH)/boot/image.iso \
|
||||
arch/$(ARCH)/boot/mtools.conf
|
||||
CLEAN_FILES += vmlinuz vmlinux-stripped
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
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
|
||||
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)$(shell [ -e $(objtree)/localversion-xen ] && cat $(objtree)/localversion-xen)$(INSTALL_SUFFIX)
|
||||
@@ -1,102 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y := head.o init_task.o vmlinux.lds
|
||||
|
||||
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
|
||||
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \
|
||||
pci-dma.o i386_ksyms.o i387.o bootflag.o \
|
||||
quirks.o i8237.o topology.o alternative.o i8253.o tsc.o
|
||||
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
obj-y += cpu/
|
||||
obj-y += acpi/
|
||||
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
|
||||
obj-$(CONFIG_MCA) += mca.o
|
||||
obj-$(CONFIG_X86_MSR) += msr.o
|
||||
obj-$(CONFIG_X86_CPUID) += cpuid.o
|
||||
obj-$(CONFIG_MICROCODE) += microcode.o
|
||||
obj-$(CONFIG_APM) += apm.o
|
||||
obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
|
||||
obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
|
||||
obj-$(CONFIG_X86_MPPARSE) += mpparse.o
|
||||
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
|
||||
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
|
||||
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
obj-$(CONFIG_X86_NUMAQ) += numaq.o
|
||||
obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-y += sysenter.o vsyscall.o
|
||||
obj-$(CONFIG_ACPI_SRAT) += srat.o
|
||||
obj-$(CONFIG_HPET_TIMER) += time_hpet.o
|
||||
obj-$(CONFIG_EFI) += efi.o efi_stub.o
|
||||
obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
|
||||
obj-$(CONFIG_VM86) += vm86.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
obj-$(CONFIG_HPET_TIMER) += hpet.o
|
||||
obj-$(CONFIG_K8_NB) += k8.o
|
||||
|
||||
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
|
||||
$(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so
|
||||
targets += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so)
|
||||
targets += vsyscall-note.o vsyscall.lds
|
||||
|
||||
# The DSO images are built using a special linker script.
|
||||
quiet_cmd_syscall = SYSCALL $@
|
||||
cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \
|
||||
-Wl,-T,$(filter-out FORCE,$^) -o $@
|
||||
|
||||
export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH)
|
||||
|
||||
vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
|
||||
$(call ld-option, -Wl$(comma)--hash-style=sysv)
|
||||
SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
|
||||
SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags)
|
||||
|
||||
$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
|
||||
$(obj)/vsyscall-%.so: $(src)/vsyscall.lds \
|
||||
$(obj)/vsyscall-%.o $(obj)/$(vsyscall_note) FORCE
|
||||
$(call if_changed,syscall)
|
||||
|
||||
# We also create a special relocatable object that should mirror the symbol
|
||||
# table and layout of the linked DSO. With ld -R we can then refer to
|
||||
# these symbols in the kernel code rather than hand-coded addresses.
|
||||
extra-y += vsyscall-syms.o
|
||||
$(obj)/built-in.o: $(obj)/vsyscall-syms.o
|
||||
$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
|
||||
|
||||
SYSCFLAGS_vsyscall-syms.o = -r
|
||||
$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
|
||||
$(obj)/vsyscall-sysenter.o $(obj)/$(vsyscall_note) FORCE
|
||||
$(call if_changed,syscall)
|
||||
|
||||
k8-y += ../../x86_64/kernel/k8.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
|
||||
@@ -1,12 +0,0 @@
|
||||
obj-$(CONFIG_ACPI) += boot.o
|
||||
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
|
||||
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
|
||||
|
||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||
obj-y += cstate.o processor.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_XEN
|
||||
include $(srctree)/scripts/Makefile.xen
|
||||
obj-y := $(call cherrypickxen, $(obj-y), $(src))
|
||||
endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
|
||||
|
||||
/*
|
||||
* Debug level
|
||||
*/
|
||||
int apic_verbosity;
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
static int modern_apic(void)
|
||||
{
|
||||
unsigned int lvr, version;
|
||||
/* AMD systems use old APIC versions, so check the CPU */
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
|
||||
boot_cpu_data.x86 >= 0xf)
|
||||
return 1;
|
||||
lvr = apic_read(APIC_LVR);
|
||||
version = GET_APIC_VERSION(lvr);
|
||||
return version >= 0x14;
|
||||
}
|
||||
#endif /* !CONFIG_XEN */
|
||||
|
||||
/*
|
||||
* '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();
|
||||
}
|
||||
|
||||
int get_physical_broadcast(void)
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
#ifndef CONFIG_SMP
|
||||
static void up_apic_timer_interrupt_call(struct pt_regs *regs)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
/*
|
||||
* the NMI deadlock-detector uses this.
|
||||
*/
|
||||
per_cpu(irq_stat, cpu).apic_timer_irqs++;
|
||||
|
||||
smp_local_timer_interrupt(regs);
|
||||
}
|
||||
#endif
|
||||
|
||||
void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
|
||||
{
|
||||
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(regs);
|
||||
#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;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Generate definitions needed by assembly language modules.
|
||||
* This code generates raw asm output which is post-processed
|
||||
* to extract and format the required data.
|
||||
*/
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/ucontext.h>
|
||||
#include "sigframe.h"
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/elf.h>
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
#define BLANK() asm volatile("\n->" : : )
|
||||
|
||||
#define OFFSET(sym, str, mem) \
|
||||
DEFINE(sym, offsetof(struct str, mem));
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
OFFSET(SIGCONTEXT_eax, sigcontext, eax);
|
||||
OFFSET(SIGCONTEXT_ebx, sigcontext, ebx);
|
||||
OFFSET(SIGCONTEXT_ecx, sigcontext, ecx);
|
||||
OFFSET(SIGCONTEXT_edx, sigcontext, edx);
|
||||
OFFSET(SIGCONTEXT_esi, sigcontext, esi);
|
||||
OFFSET(SIGCONTEXT_edi, sigcontext, edi);
|
||||
OFFSET(SIGCONTEXT_ebp, sigcontext, ebp);
|
||||
OFFSET(SIGCONTEXT_esp, sigcontext, esp);
|
||||
OFFSET(SIGCONTEXT_eip, sigcontext, eip);
|
||||
BLANK();
|
||||
|
||||
OFFSET(CPUINFO_x86, cpuinfo_x86, x86);
|
||||
OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
|
||||
OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
|
||||
OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask);
|
||||
OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math);
|
||||
OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level);
|
||||
OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability);
|
||||
OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
|
||||
BLANK();
|
||||
|
||||
OFFSET(TI_task, thread_info, task);
|
||||
OFFSET(TI_exec_domain, thread_info, exec_domain);
|
||||
OFFSET(TI_flags, thread_info, flags);
|
||||
OFFSET(TI_status, thread_info, status);
|
||||
OFFSET(TI_cpu, thread_info, cpu);
|
||||
OFFSET(TI_preempt_count, thread_info, preempt_count);
|
||||
OFFSET(TI_addr_limit, thread_info, addr_limit);
|
||||
OFFSET(TI_restart_block, thread_info, restart_block);
|
||||
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
|
||||
BLANK();
|
||||
|
||||
OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
|
||||
OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
|
||||
BLANK();
|
||||
|
||||
OFFSET(pbe_address, pbe, address);
|
||||
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(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);
|
||||
|
||||
OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#
|
||||
# Makefile for x86-compatible CPU details and quirks
|
||||
#
|
||||
|
||||
obj-y := common.o proc.o
|
||||
|
||||
obj-y += amd.o
|
||||
obj-y += cyrix.o
|
||||
obj-y += centaur.o
|
||||
obj-y += transmeta.o
|
||||
obj-y += intel.o intel_cacheinfo.o
|
||||
obj-y += rise.o
|
||||
obj-y += nexgen.o
|
||||
obj-y += umc.o
|
||||
|
||||
obj-$(CONFIG_X86_MCE) += mcheck/
|
||||
|
||||
obj-$(CONFIG_MTRR) += mtrr/
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
|
||||
ifdef CONFIG_XEN
|
||||
include $(srctree)/scripts/Makefile.xen
|
||||
obj-y := $(call cherrypickxen, $(obj-y), $(src))
|
||||
endif
|
||||
@@ -1,743 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/i387.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/mce.h>
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/apic.h>
|
||||
#include <mach_apic.h>
|
||||
#else
|
||||
#ifdef CONFIG_XEN
|
||||
#define phys_pkg_id(a,b) a
|
||||
#endif
|
||||
#endif
|
||||
#include <asm/hypervisor.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
|
||||
#endif
|
||||
|
||||
static int cachesize_override __cpuinitdata = -1;
|
||||
static int disable_x86_fxsr __cpuinitdata;
|
||||
static int disable_x86_serial_nr __cpuinitdata = 1;
|
||||
static int disable_x86_sep __cpuinitdata;
|
||||
|
||||
struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
|
||||
|
||||
extern int disable_pse;
|
||||
|
||||
static void default_init(struct cpuinfo_x86 * c)
|
||||
{
|
||||
/* Not much we can do here... */
|
||||
/* Check if at least it has cpuid */
|
||||
if (c->cpuid_level == -1) {
|
||||
/* No cpuid. It must be an ancient CPU */
|
||||
if (c->x86 == 4)
|
||||
strcpy(c->x86_model_id, "486");
|
||||
else if (c->x86 == 3)
|
||||
strcpy(c->x86_model_id, "386");
|
||||
}
|
||||
}
|
||||
|
||||
static struct cpu_dev default_cpu = {
|
||||
.c_init = default_init,
|
||||
.c_vendor = "Unknown",
|
||||
};
|
||||
static struct cpu_dev * this_cpu = &default_cpu;
|
||||
|
||||
static int __init cachesize_setup(char *str)
|
||||
{
|
||||
get_option (&str, &cachesize_override);
|
||||
return 1;
|
||||
}
|
||||
__setup("cachesize=", cachesize_setup);
|
||||
|
||||
int __cpuinit get_model_name(struct cpuinfo_x86 *c)
|
||||
{
|
||||
unsigned int *v;
|
||||
char *p, *q;
|
||||
|
||||
if (cpuid_eax(0x80000000) < 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;
|
||||
|
||||
/* Intel chips right-justify this string for some dumb reason;
|
||||
undo that brain damage */
|
||||
p = q = &c->x86_model_id[0];
|
||||
while ( *p == ' ' )
|
||||
p++;
|
||||
if ( p != q ) {
|
||||
while ( *p )
|
||||
*q++ = *p++;
|
||||
while ( q <= &c->x86_model_id[48] )
|
||||
*q++ = '\0'; /* Zero-pad the rest */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
|
||||
{
|
||||
unsigned int n, dummy, ecx, edx, l2size;
|
||||
|
||||
n = cpuid_eax(0x80000000);
|
||||
|
||||
if (n >= 0x80000005) {
|
||||
cpuid(0x80000005, &dummy, &dummy, &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);
|
||||
}
|
||||
|
||||
if (n < 0x80000006) /* Some chips just has a large L1. */
|
||||
return;
|
||||
|
||||
ecx = cpuid_ecx(0x80000006);
|
||||
l2size = ecx >> 16;
|
||||
|
||||
/* do processor-specific cache resizing */
|
||||
if (this_cpu->c_size_cache)
|
||||
l2size = this_cpu->c_size_cache(c,l2size);
|
||||
|
||||
/* Allow user to override all this if necessary. */
|
||||
if (cachesize_override != -1)
|
||||
l2size = cachesize_override;
|
||||
|
||||
if ( l2size == 0 )
|
||||
return; /* Again, no L2 cache is possible */
|
||||
|
||||
c->x86_cache_size = l2size;
|
||||
|
||||
printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
|
||||
l2size, ecx & 0xFF);
|
||||
}
|
||||
|
||||
/* Naming convention should be: <Name> [(<Codename>)] */
|
||||
/* This table only is used unless init_<vendor>() below doesn't set it; */
|
||||
/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
|
||||
|
||||
/* Look up CPU names by table lookup. */
|
||||
static char __cpuinit *table_lookup_model(struct cpuinfo_x86 *c)
|
||||
{
|
||||
struct cpu_model_info *info;
|
||||
|
||||
if ( c->x86_model >= 16 )
|
||||
return NULL; /* Range check */
|
||||
|
||||
if (!this_cpu)
|
||||
return NULL;
|
||||
|
||||
info = this_cpu->c_models;
|
||||
|
||||
while (info && info->family) {
|
||||
if (info->family == c->x86)
|
||||
return info->model_names[c->x86_model];
|
||||
info++;
|
||||
}
|
||||
return NULL; /* Not found */
|
||||
}
|
||||
|
||||
|
||||
static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
|
||||
{
|
||||
char *v = c->x86_vendor_id;
|
||||
int i;
|
||||
static int printed;
|
||||
|
||||
for (i = 0; i < X86_VENDOR_NUM; i++) {
|
||||
if (cpu_devs[i]) {
|
||||
if (!strcmp(v,cpu_devs[i]->c_ident[0]) ||
|
||||
(cpu_devs[i]->c_ident[1] &&
|
||||
!strcmp(v,cpu_devs[i]->c_ident[1]))) {
|
||||
c->x86_vendor = i;
|
||||
if (!early)
|
||||
this_cpu = cpu_devs[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!printed) {
|
||||
printed++;
|
||||
printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
|
||||
printk(KERN_ERR "CPU: Your system may be unstable.\n");
|
||||
}
|
||||
c->x86_vendor = X86_VENDOR_UNKNOWN;
|
||||
this_cpu = &default_cpu;
|
||||
}
|
||||
|
||||
|
||||
static int __init x86_fxsr_setup(char * s)
|
||||
{
|
||||
disable_x86_fxsr = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("nofxsr", x86_fxsr_setup);
|
||||
|
||||
|
||||
static int __init x86_sep_setup(char * s)
|
||||
{
|
||||
disable_x86_sep = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("nosep", x86_sep_setup);
|
||||
|
||||
|
||||
/* Standard macro to see if a specific flag is changeable */
|
||||
static inline int flag_is_changeable_p(u32 flag)
|
||||
{
|
||||
u32 f1, f2;
|
||||
|
||||
asm("pushfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %0\n\t"
|
||||
"movl %0,%1\n\t"
|
||||
"xorl %2,%0\n\t"
|
||||
"pushl %0\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %0\n\t"
|
||||
"popfl\n\t"
|
||||
: "=&r" (f1), "=&r" (f2)
|
||||
: "ir" (flag));
|
||||
|
||||
return ((f1^f2) & flag) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* Probe for the CPUID instruction */
|
||||
static int __cpuinit have_cpuid_p(void)
|
||||
{
|
||||
return flag_is_changeable_p(X86_EFLAGS_ID);
|
||||
}
|
||||
|
||||
/* Do minimum CPU detection early.
|
||||
Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment.
|
||||
The others are not touched to avoid unwanted side effects.
|
||||
|
||||
WARNING: this function is only called on the BP. Don't add code here
|
||||
that is supposed to run on all CPUs. */
|
||||
static void __init early_cpu_detect(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
c->x86_cache_alignment = 32;
|
||||
|
||||
if (!have_cpuid_p())
|
||||
return;
|
||||
|
||||
/* Get vendor name */
|
||||
cpuid(0x00000000, &c->cpuid_level,
|
||||
(int *)&c->x86_vendor_id[0],
|
||||
(int *)&c->x86_vendor_id[8],
|
||||
(int *)&c->x86_vendor_id[4]);
|
||||
|
||||
get_cpu_vendor(c, 1);
|
||||
|
||||
c->x86 = 4;
|
||||
if (c->cpuid_level >= 0x00000001) {
|
||||
u32 junk, tfms, cap0, misc;
|
||||
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
|
||||
c->x86 = (tfms >> 8) & 15;
|
||||
c->x86_model = (tfms >> 4) & 15;
|
||||
if (c->x86 == 0xf)
|
||||
c->x86 += (tfms >> 20) & 0xff;
|
||||
if (c->x86 >= 0x6)
|
||||
c->x86_model += ((tfms >> 16) & 0xF) << 4;
|
||||
c->x86_mask = tfms & 15;
|
||||
if (cap0 & (1<<19))
|
||||
c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void __cpuinit generic_identify(struct cpuinfo_x86 * c)
|
||||
{
|
||||
u32 tfms, xlvl;
|
||||
int ebx;
|
||||
|
||||
if (have_cpuid_p()) {
|
||||
/* Get vendor name */
|
||||
cpuid(0x00000000, &c->cpuid_level,
|
||||
(int *)&c->x86_vendor_id[0],
|
||||
(int *)&c->x86_vendor_id[8],
|
||||
(int *)&c->x86_vendor_id[4]);
|
||||
|
||||
get_cpu_vendor(c, 0);
|
||||
/* 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 capability, excap;
|
||||
cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
|
||||
c->x86_capability[0] = capability;
|
||||
c->x86_capability[4] = excap;
|
||||
c->x86 = (tfms >> 8) & 15;
|
||||
c->x86_model = (tfms >> 4) & 15;
|
||||
if (c->x86 == 0xf)
|
||||
c->x86 += (tfms >> 20) & 0xff;
|
||||
if (c->x86 >= 0x6)
|
||||
c->x86_model += ((tfms >> 16) & 0xF) << 4;
|
||||
c->x86_mask = tfms & 15;
|
||||
#ifdef CONFIG_X86_HT
|
||||
c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
|
||||
#else
|
||||
c->apicid = (ebx >> 24) & 0xFF;
|
||||
#endif
|
||||
} else {
|
||||
/* Have CPUID level 0 only - unheard of */
|
||||
c->x86 = 4;
|
||||
}
|
||||
|
||||
/* AMD-defined flags: level 0x80000001 */
|
||||
xlvl = cpuid_eax(0x80000000);
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
early_intel_workaround(c);
|
||||
|
||||
#ifdef CONFIG_X86_HT
|
||||
c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
|
||||
{
|
||||
if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
|
||||
/* Disable processor serial number */
|
||||
unsigned long lo,hi;
|
||||
rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
|
||||
lo |= 0x200000;
|
||||
wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
|
||||
printk(KERN_NOTICE "CPU serial number disabled.\n");
|
||||
clear_bit(X86_FEATURE_PN, c->x86_capability);
|
||||
|
||||
/* Disabling the serial number may affect the cpuid level */
|
||||
c->cpuid_level = cpuid_eax(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init x86_serial_nr_setup(char *s)
|
||||
{
|
||||
disable_x86_serial_nr = 0;
|
||||
return 1;
|
||||
}
|
||||
__setup("serialnumber", x86_serial_nr_setup);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This does the hard work of actually picking apart the CPU stuff...
|
||||
*/
|
||||
void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
|
||||
{
|
||||
int i;
|
||||
|
||||
c->loops_per_jiffy = loops_per_jiffy;
|
||||
c->x86_cache_size = -1;
|
||||
c->x86_vendor = X86_VENDOR_UNKNOWN;
|
||||
c->cpuid_level = -1; /* CPUID not detected */
|
||||
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_max_cores = 1;
|
||||
memset(&c->x86_capability, 0, sizeof c->x86_capability);
|
||||
|
||||
if (!have_cpuid_p()) {
|
||||
/* First of all, decide if this is a 486 or higher */
|
||||
/* It's a 486 if we can modify the AC flag */
|
||||
if ( flag_is_changeable_p(X86_EFLAGS_AC) )
|
||||
c->x86 = 4;
|
||||
else
|
||||
c->x86 = 3;
|
||||
}
|
||||
|
||||
generic_identify(c);
|
||||
|
||||
printk(KERN_DEBUG "CPU: After generic identify, caps:");
|
||||
for (i = 0; i < NCAPINTS; i++)
|
||||
printk(" %08lx", c->x86_capability[i]);
|
||||
printk("\n");
|
||||
|
||||
if (this_cpu->c_identify) {
|
||||
this_cpu->c_identify(c);
|
||||
|
||||
printk(KERN_DEBUG "CPU: After vendor identify, caps:");
|
||||
for (i = 0; i < NCAPINTS; i++)
|
||||
printk(" %08lx", c->x86_capability[i]);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
if (this_cpu->c_init)
|
||||
this_cpu->c_init(c);
|
||||
|
||||
/* Disable the PN if appropriate */
|
||||
squash_the_stupid_serial_number(c);
|
||||
|
||||
/*
|
||||
* The vendor-specific functions might have changed features. Now
|
||||
* we do "generic changes."
|
||||
*/
|
||||
|
||||
/* TSC disabled? */
|
||||
if ( tsc_disable )
|
||||
clear_bit(X86_FEATURE_TSC, c->x86_capability);
|
||||
|
||||
/* FXSR disabled? */
|
||||
if (disable_x86_fxsr) {
|
||||
clear_bit(X86_FEATURE_FXSR, c->x86_capability);
|
||||
clear_bit(X86_FEATURE_XMM, c->x86_capability);
|
||||
}
|
||||
|
||||
/* SEP disabled? */
|
||||
if (disable_x86_sep)
|
||||
clear_bit(X86_FEATURE_SEP, c->x86_capability);
|
||||
|
||||
if (disable_pse)
|
||||
clear_bit(X86_FEATURE_PSE, c->x86_capability);
|
||||
|
||||
/* If the model name is still unset, do table lookup. */
|
||||
if ( !c->x86_model_id[0] ) {
|
||||
char *p;
|
||||
p = table_lookup_model(c);
|
||||
if ( p )
|
||||
strcpy(c->x86_model_id, p);
|
||||
else
|
||||
/* Last resort... */
|
||||
sprintf(c->x86_model_id, "%02x/%02x",
|
||||
c->x86, c->x86_model);
|
||||
}
|
||||
|
||||
/* Now the feature flags better reflect actual CPU features! */
|
||||
|
||||
printk(KERN_DEBUG "CPU: After all inits, caps:");
|
||||
for (i = 0; i < NCAPINTS; i++)
|
||||
printk(" %08lx", c->x86_capability[i]);
|
||||
printk("\n");
|
||||
|
||||
/*
|
||||
* 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];
|
||||
}
|
||||
|
||||
/* Init Machine Check Exception if available. */
|
||||
mcheck_init(c);
|
||||
|
||||
if (c == &boot_cpu_data)
|
||||
sysenter_setup();
|
||||
enable_sep_cpu();
|
||||
|
||||
if (c == &boot_cpu_data)
|
||||
mtrr_bp_init();
|
||||
else
|
||||
mtrr_ap_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_HT
|
||||
void __cpuinit detect_ht(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
int index_msb, core_bits;
|
||||
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
|
||||
return;
|
||||
|
||||
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((ebx >> 24) & 0xFF, index_msb);
|
||||
|
||||
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
|
||||
c->phys_proc_id);
|
||||
|
||||
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((ebx >> 24) & 0xFF, index_msb) &
|
||||
((1 << core_bits) - 1);
|
||||
|
||||
if (c->x86_max_cores > 1)
|
||||
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
|
||||
c->cpu_core_id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
|
||||
{
|
||||
char *vendor = NULL;
|
||||
|
||||
if (c->x86_vendor < X86_VENDOR_NUM)
|
||||
vendor = this_cpu->c_vendor;
|
||||
else if (c->cpuid_level >= 0)
|
||||
vendor = c->x86_vendor_id;
|
||||
|
||||
if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
|
||||
printk("%s ", vendor);
|
||||
|
||||
if (!c->x86_model_id[0])
|
||||
printk("%d86", c->x86);
|
||||
else
|
||||
printk("%s", c->x86_model_id);
|
||||
|
||||
if (c->x86_mask || c->cpuid_level >= 0)
|
||||
printk(" stepping %02x\n", c->x86_mask);
|
||||
else
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
|
||||
|
||||
/* This is hacky. :)
|
||||
* We're emulating future behavior.
|
||||
* In the future, the cpu-specific init functions will be called implicitly
|
||||
* via the magic of initcalls.
|
||||
* They will insert themselves into the cpu_devs structure.
|
||||
* Then, when cpu_init() is called, we can just iterate over that array.
|
||||
*/
|
||||
|
||||
extern int intel_cpu_init(void);
|
||||
extern int cyrix_init_cpu(void);
|
||||
extern int nsc_init_cpu(void);
|
||||
extern int amd_init_cpu(void);
|
||||
extern int centaur_init_cpu(void);
|
||||
extern int transmeta_init_cpu(void);
|
||||
extern int rise_init_cpu(void);
|
||||
extern int nexgen_init_cpu(void);
|
||||
extern int umc_init_cpu(void);
|
||||
|
||||
void __init early_cpu_init(void)
|
||||
{
|
||||
intel_cpu_init();
|
||||
cyrix_init_cpu();
|
||||
nsc_init_cpu();
|
||||
amd_init_cpu();
|
||||
centaur_init_cpu();
|
||||
transmeta_init_cpu();
|
||||
rise_init_cpu();
|
||||
nexgen_init_cpu();
|
||||
umc_init_cpu();
|
||||
early_cpu_detect();
|
||||
|
||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||
/* pse is not compatible with on-the-fly unmapping,
|
||||
* disable it even if the cpus claim to support it.
|
||||
*/
|
||||
clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
|
||||
disable_pse = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __cpuinit cpu_gdt_init(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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void __cpuinit cpu_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
#ifndef CONFIG_X86_NO_TSS
|
||||
struct tss_struct * t = &per_cpu(init_tss, cpu);
|
||||
#endif
|
||||
struct thread_struct *thread = ¤t->thread;
|
||||
struct desc_struct *gdt;
|
||||
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
|
||||
|
||||
if (cpu_test_and_set(cpu, cpu_initialized)) {
|
||||
printk(KERN_WARNING "CPU#%d already initialized!\n", cpu);
|
||||
for (;;) local_irq_enable();
|
||||
}
|
||||
printk(KERN_INFO "Initializing CPU#%d\n", cpu);
|
||||
|
||||
if (cpu_has_vme || cpu_has_de)
|
||||
clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
|
||||
if (tsc_disable && cpu_has_tsc) {
|
||||
printk(KERN_NOTICE "Disabling TSC...\n");
|
||||
/**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
|
||||
clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
|
||||
set_in_cr4(X86_CR4_TSD);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
/* The CPU hotplug case */
|
||||
if (cpu_gdt_descr->address) {
|
||||
gdt = (struct desc_struct *)cpu_gdt_descr->address;
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
goto old_gdt;
|
||||
}
|
||||
/*
|
||||
* This is a horrible hack to allocate the GDT. The problem
|
||||
* is that cpu_init() is called really early for the boot CPU
|
||||
* (and hence needs bootmem) but much later for the secondary
|
||||
* CPUs, when bootmem will have gone away
|
||||
*/
|
||||
if (NODE_DATA(0)->bdata->node_bootmem_map) {
|
||||
gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
|
||||
/* alloc_bootmem_pages panics on failure, so no check */
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
} else {
|
||||
gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
|
||||
if (unlikely(!gdt)) {
|
||||
printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
|
||||
for (;;)
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
old_gdt:
|
||||
/*
|
||||
* Initialize the per-CPU GDT with the boot GDT,
|
||||
* and set up the GDT descriptor:
|
||||
*/
|
||||
memcpy(gdt, cpu_gdt_table, GDT_SIZE);
|
||||
|
||||
/* Set up GDT entry for 16bit stack */
|
||||
*(__u64 *)(&gdt[GDT_ENTRY_ESPFIX_SS]) |=
|
||||
((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) |
|
||||
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
|
||||
(CPU_16BIT_STACK_SIZE - 1);
|
||||
|
||||
cpu_gdt_descr->size = GDT_SIZE - 1;
|
||||
cpu_gdt_descr->address = (unsigned long)gdt;
|
||||
#else
|
||||
if (cpu == 0 && cpu_gdt_descr->address == 0) {
|
||||
gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE);
|
||||
/* alloc_bootmem_pages panics on failure, so no check */
|
||||
memset(gdt, 0, PAGE_SIZE);
|
||||
|
||||
memcpy(gdt, cpu_gdt_table, GDT_SIZE);
|
||||
|
||||
cpu_gdt_descr->size = GDT_SIZE;
|
||||
cpu_gdt_descr->address = (unsigned long)gdt;
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu_gdt_init(cpu_gdt_descr);
|
||||
|
||||
/*
|
||||
* Set up and load the per-CPU TSS and LDT
|
||||
*/
|
||||
atomic_inc(&init_mm.mm_count);
|
||||
current->active_mm = &init_mm;
|
||||
if (current->mm)
|
||||
BUG();
|
||||
enter_lazy_tlb(&init_mm, current);
|
||||
|
||||
load_esp0(t, thread);
|
||||
|
||||
load_LDT(&init_mm.context);
|
||||
|
||||
#ifdef CONFIG_DOUBLEFAULT
|
||||
/* Set up doublefault TSS pointer in the GDT */
|
||||
__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
|
||||
#endif
|
||||
|
||||
/* Clear %fs and %gs. */
|
||||
asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
|
||||
|
||||
/* Clear all 6 debug registers: */
|
||||
set_debugreg(0, 0);
|
||||
set_debugreg(0, 1);
|
||||
set_debugreg(0, 2);
|
||||
set_debugreg(0, 3);
|
||||
set_debugreg(0, 6);
|
||||
set_debugreg(0, 7);
|
||||
|
||||
/*
|
||||
* Force FPU initialization:
|
||||
*/
|
||||
current_thread_info()->status = 0;
|
||||
clear_used_math();
|
||||
mxcsr_feature_mask_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void __cpuinit cpu_uninit(void)
|
||||
{
|
||||
int cpu = raw_smp_processor_id();
|
||||
cpu_clear(cpu, cpu_initialized);
|
||||
|
||||
/* lazy TLB state */
|
||||
per_cpu(cpu_tlbstate, cpu).state = 0;
|
||||
per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
|
||||
}
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
obj-y := main.o if.o generic.o state.o
|
||||
obj-y += amd.o
|
||||
obj-y += cyrix.o
|
||||
obj-y += 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
|
||||
@@ -1,197 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/mtrr.h>
|
||||
#include "mtrr.h"
|
||||
|
||||
static DEFINE_MUTEX(mtrr_mutex);
|
||||
|
||||
void generic_get_mtrr(unsigned int reg, unsigned long *base,
|
||||
unsigned int *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;
|
||||
|
||||
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;
|
||||
unsigned int 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);
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Architecture specific (i386) functions for kexec based crash dumps.
|
||||
*
|
||||
* Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2004. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/elfcore.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/apic.h>
|
||||
#include <mach_ipi.h>
|
||||
|
||||
|
||||
/* This keeps a track of which one is crashing cpu. */
|
||||
static int crashing_cpu;
|
||||
|
||||
static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
|
||||
size_t data_len)
|
||||
{
|
||||
struct elf_note note;
|
||||
|
||||
note.n_namesz = strlen(name) + 1;
|
||||
note.n_descsz = data_len;
|
||||
note.n_type = type;
|
||||
memcpy(buf, ¬e, sizeof(note));
|
||||
buf += (sizeof(note) +3)/4;
|
||||
memcpy(buf, name, note.n_namesz);
|
||||
buf += (note.n_namesz + 3)/4;
|
||||
memcpy(buf, data, note.n_descsz);
|
||||
buf += (note.n_descsz + 3)/4;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void final_note(u32 *buf)
|
||||
{
|
||||
struct elf_note note;
|
||||
|
||||
note.n_namesz = 0;
|
||||
note.n_descsz = 0;
|
||||
note.n_type = 0;
|
||||
memcpy(buf, ¬e, sizeof(note));
|
||||
}
|
||||
|
||||
static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
|
||||
{
|
||||
struct elf_prstatus prstatus;
|
||||
u32 *buf;
|
||||
|
||||
if ((cpu < 0) || (cpu >= NR_CPUS))
|
||||
return;
|
||||
|
||||
/* Using ELF notes here is opportunistic.
|
||||
* I need a well defined structure format
|
||||
* for the data I pass, and I need tags
|
||||
* on the data to indicate what information I have
|
||||
* squirrelled away. ELF notes happen to provide
|
||||
* all of that, so there is no need to invent something new.
|
||||
*/
|
||||
buf = (u32*)per_cpu_ptr(crash_notes, cpu);
|
||||
if (!buf)
|
||||
return;
|
||||
memset(&prstatus, 0, sizeof(prstatus));
|
||||
prstatus.pr_pid = current->pid;
|
||||
elf_core_copy_regs(&prstatus.pr_reg, regs);
|
||||
buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
|
||||
sizeof(prstatus));
|
||||
final_note(buf);
|
||||
}
|
||||
|
||||
static void crash_save_self(struct pt_regs *regs)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
cpu = smp_processor_id();
|
||||
crash_save_this_cpu(regs, cpu);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
|
||||
static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
static int crash_nmi_callback(struct pt_regs *regs, int cpu)
|
||||
{
|
||||
struct pt_regs fixed_regs;
|
||||
|
||||
/* Don't do anything if this handler is invoked on crashing cpu.
|
||||
* Otherwise, system will completely hang. Crashing cpu can get
|
||||
* an NMI if system was initially booted with nmi_watchdog parameter.
|
||||
*/
|
||||
if (cpu == crashing_cpu)
|
||||
return 1;
|
||||
local_irq_disable();
|
||||
|
||||
if (!user_mode_vm(regs)) {
|
||||
crash_fixup_ss_esp(&fixed_regs, regs);
|
||||
regs = &fixed_regs;
|
||||
}
|
||||
crash_save_this_cpu(regs, cpu);
|
||||
disable_local_APIC();
|
||||
atomic_dec(&waiting_for_crash_ipi);
|
||||
/* Assume hlt works */
|
||||
halt();
|
||||
for (;;)
|
||||
cpu_relax();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void smp_send_nmi_allbutself(void)
|
||||
{
|
||||
send_IPI_allbutself(NMI_VECTOR);
|
||||
}
|
||||
|
||||
static void nmi_shootdown_cpus(void)
|
||||
{
|
||||
unsigned long msecs;
|
||||
|
||||
atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
|
||||
/* Would it be better to replace the trap vector here? */
|
||||
set_nmi_callback(crash_nmi_callback);
|
||||
/* Ensure the new callback function is set before sending
|
||||
* out the NMI
|
||||
*/
|
||||
wmb();
|
||||
|
||||
smp_send_nmi_allbutself();
|
||||
|
||||
msecs = 1000; /* Wait at most a second for the other cpus to stop */
|
||||
while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
|
||||
mdelay(1);
|
||||
msecs--;
|
||||
}
|
||||
|
||||
/* Leave the nmi callback set */
|
||||
disable_local_APIC();
|
||||
}
|
||||
#else
|
||||
static void nmi_shootdown_cpus(void)
|
||||
{
|
||||
/* There are no cpus to shootdown */
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_XEN */
|
||||
|
||||
void machine_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
/* This function is only called after the system
|
||||
* has panicked or is otherwise in a critical state.
|
||||
* The minimum amount of code to allow a kexec'd kernel
|
||||
* to run successfully needs to happen here.
|
||||
*
|
||||
* In practice this means shooting down the other cpus in
|
||||
* an SMP system.
|
||||
*/
|
||||
/* The kernel is broken so disable interrupts */
|
||||
local_irq_disable();
|
||||
|
||||
/* Make a note of crashing cpu. Will be used in NMI callback.*/
|
||||
crashing_cpu = 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_self(regs);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#include "../../x86_64/kernel/early_printk-xen.c"
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,88 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
static int __init fixup_init(void)
|
||||
{
|
||||
HYPERVISOR_vm_assist(
|
||||
VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify);
|
||||
return 0;
|
||||
}
|
||||
__initcall(fixup_init);
|
||||
@@ -1,207 +0,0 @@
|
||||
|
||||
|
||||
.text
|
||||
#include <linux/elfnote.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/page.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)
|
||||
movl %esi,xen_start_info
|
||||
cld
|
||||
|
||||
/* 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/GS and LDT
|
||||
movl %eax,%fs
|
||||
movl %eax,%gs
|
||||
cld # gcc2 wants the direction flag cleared at all times
|
||||
|
||||
pushl %eax # fake return address
|
||||
jmp start_kernel
|
||||
|
||||
#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
|
||||
|
||||
/*
|
||||
* The Global Descriptor Table contains 28 quadwords, per-CPU.
|
||||
*/
|
||||
.align L1_CACHE_BYTES
|
||||
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 16-bit SS */
|
||||
.quad 0x0000000000000000 /* 0xd8 - unused */
|
||||
.quad 0x0000000000000000 /* 0xe0 - unused */
|
||||
.quad 0x0000000000000000 /* 0xe8 - unused */
|
||||
.quad 0x0000000000000000 /* 0xf0 - unused */
|
||||
.quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
|
||||
|
||||
#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 + __PHYSICAL_START + VIRT_ENTRY_OFFSET)
|
||||
.ascii ",HYPERCALL_PAGE=0x"
|
||||
utoa ((__PHYSICAL_START+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)
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/init_task.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mqueue.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
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);
|
||||
|
||||
#define swapper_pg_dir ((pgd_t *)NULL)
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
#undef swapper_pg_dir
|
||||
|
||||
EXPORT_SYMBOL(init_mm);
|
||||
|
||||
/*
|
||||
* Initial thread structure.
|
||||
*
|
||||
* We need to make sure that this is THREAD_SIZE aligned due to the
|
||||
* way process stacks are handled. This is done by having a special
|
||||
* "init_task" linker map entry..
|
||||
*/
|
||||
union thread_union init_thread_union
|
||||
__attribute__((__section__(".data.init_task"))) =
|
||||
{ INIT_THREAD_INFO(init_task) };
|
||||
|
||||
/*
|
||||
* Initial task structure.
|
||||
*
|
||||
* All other task structs will be allocated on slabs in fork.c
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
* linux/arch/i386/kernel/irq.c
|
||||
*
|
||||
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
|
||||
*
|
||||
* This file contains the lowest level x86-specific interrupt
|
||||
* entry, irq-stacks and irq statistics code. All the remaining
|
||||
* irq logic is done by the generic kernel/irq/ code and
|
||||
* by the x86-specific irq controller code. (e.g. i8259.c and
|
||||
* io_apic.c.)
|
||||
*/
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
|
||||
EXPORT_PER_CPU_SYMBOL(irq_stat);
|
||||
|
||||
#ifndef CONFIG_X86_LOCAL_APIC
|
||||
/*
|
||||
* '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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_4KSTACKS
|
||||
/*
|
||||
* per-CPU IRQ handling contexts (thread information and stack)
|
||||
*/
|
||||
union irq_ctx {
|
||||
struct thread_info tinfo;
|
||||
u32 stack[THREAD_SIZE/sizeof(u32)];
|
||||
};
|
||||
|
||||
static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
|
||||
static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* do_IRQ handles all normal device IRQ's (the special
|
||||
* SMP cross-CPU interrupts have their own specific
|
||||
* handlers).
|
||||
*/
|
||||
fastcall unsigned int do_IRQ(struct pt_regs *regs)
|
||||
{
|
||||
/* high bit used in ret_from_ code */
|
||||
int irq = ~regs->orig_eax;
|
||||
#ifdef CONFIG_4KSTACKS
|
||||
union irq_ctx *curctx, *irqctx;
|
||||
u32 *isp;
|
||||
#endif
|
||||
|
||||
if (unlikely((unsigned)irq >= NR_IRQS)) {
|
||||
printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
|
||||
__FUNCTION__, irq);
|
||||
BUG();
|
||||
}
|
||||
|
||||
irq_enter();
|
||||
#ifdef CONFIG_DEBUG_STACKOVERFLOW
|
||||
/* Debugging check for stack overflow: is there less than 1KB free? */
|
||||
{
|
||||
long esp;
|
||||
|
||||
__asm__ __volatile__("andl %%esp,%0" :
|
||||
"=r" (esp) : "0" (THREAD_SIZE - 1));
|
||||
if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
|
||||
printk("do_IRQ: stack overflow: %ld\n",
|
||||
esp - sizeof(struct thread_info));
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_4KSTACKS
|
||||
|
||||
curctx = (union irq_ctx *) current_thread_info();
|
||||
irqctx = hardirq_ctx[smp_processor_id()];
|
||||
|
||||
/*
|
||||
* this is where we switch to the IRQ stack. However, if we are
|
||||
* already using the IRQ stack (because we interrupted a hardirq
|
||||
* handler) we can't do that and just have to keep using the
|
||||
* current stack (which is the irq stack already after all)
|
||||
*/
|
||||
if (curctx != irqctx) {
|
||||
int arg1, arg2, ebx;
|
||||
|
||||
/* build the stack frame on the IRQ stack */
|
||||
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
|
||||
irqctx->tinfo.task = curctx->tinfo.task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
|
||||
/*
|
||||
* Copy the softirq bits in preempt_count so that the
|
||||
* softirq checks work in the hardirq context.
|
||||
*/
|
||||
irqctx->tinfo.preempt_count =
|
||||
(irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
|
||||
(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
|
||||
|
||||
asm volatile(
|
||||
" xchgl %%ebx,%%esp \n"
|
||||
" call __do_IRQ \n"
|
||||
" movl %%ebx,%%esp \n"
|
||||
: "=a" (arg1), "=d" (arg2), "=b" (ebx)
|
||||
: "0" (irq), "1" (regs), "2" (isp)
|
||||
: "memory", "cc", "ecx"
|
||||
);
|
||||
} else
|
||||
#endif
|
||||
__do_IRQ(irq, regs);
|
||||
|
||||
irq_exit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_4KSTACKS
|
||||
|
||||
/*
|
||||
* These should really be __section__(".bss.page_aligned") as well, but
|
||||
* gcc's 3.0 and earlier don't handle that correctly.
|
||||
*/
|
||||
static char softirq_stack[NR_CPUS * THREAD_SIZE]
|
||||
__attribute__((__aligned__(THREAD_SIZE)));
|
||||
|
||||
static char hardirq_stack[NR_CPUS * THREAD_SIZE]
|
||||
__attribute__((__aligned__(THREAD_SIZE)));
|
||||
|
||||
/*
|
||||
* allocate per-cpu stacks for hardirq and for softirq processing
|
||||
*/
|
||||
void irq_ctx_init(int cpu)
|
||||
{
|
||||
union irq_ctx *irqctx;
|
||||
|
||||
if (hardirq_ctx[cpu])
|
||||
return;
|
||||
|
||||
irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
|
||||
irqctx->tinfo.task = NULL;
|
||||
irqctx->tinfo.exec_domain = NULL;
|
||||
irqctx->tinfo.cpu = cpu;
|
||||
irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
|
||||
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
|
||||
|
||||
hardirq_ctx[cpu] = irqctx;
|
||||
|
||||
irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
|
||||
irqctx->tinfo.task = NULL;
|
||||
irqctx->tinfo.exec_domain = NULL;
|
||||
irqctx->tinfo.cpu = cpu;
|
||||
irqctx->tinfo.preempt_count = 0;
|
||||
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
|
||||
|
||||
softirq_ctx[cpu] = irqctx;
|
||||
|
||||
printk("CPU %u irqstacks, hard=%p soft=%p\n",
|
||||
cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
|
||||
}
|
||||
|
||||
void irq_ctx_exit(int cpu)
|
||||
{
|
||||
hardirq_ctx[cpu] = NULL;
|
||||
}
|
||||
|
||||
extern asmlinkage void __do_softirq(void);
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct thread_info *curctx;
|
||||
union irq_ctx *irqctx;
|
||||
u32 *isp;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
curctx = current_thread_info();
|
||||
irqctx = softirq_ctx[smp_processor_id()];
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
|
||||
|
||||
asm volatile(
|
||||
" xchgl %%ebx,%%esp \n"
|
||||
" call __do_softirq \n"
|
||||
" movl %%ebx,%%esp \n"
|
||||
: "=b"(isp)
|
||||
: "0"(isp)
|
||||
: "memory", "cc", "edx", "ecx", "eax"
|
||||
);
|
||||
/*
|
||||
* Shouldnt happen, we returned above if in_interrupt():
|
||||
*/
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_softirq);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt statistics:
|
||||
*/
|
||||
|
||||
atomic_t irq_err_count;
|
||||
|
||||
/*
|
||||
* /proc/interrupts printing:
|
||||
*/
|
||||
|
||||
int show_interrupts(struct seq_file *p, void *v)
|
||||
{
|
||||
int i = *(loff_t *) v, j;
|
||||
struct irqaction * action;
|
||||
unsigned long flags;
|
||||
|
||||
if (i == 0) {
|
||||
seq_printf(p, " ");
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "CPU%-8d",j);
|
||||
seq_putc(p, '\n');
|
||||
}
|
||||
|
||||
if (i < NR_IRQS) {
|
||||
spin_lock_irqsave(&irq_desc[i].lock, flags);
|
||||
action = irq_desc[i].action;
|
||||
if (!action)
|
||||
goto skip;
|
||||
seq_printf(p, "%3d: ",i);
|
||||
#ifndef CONFIG_SMP
|
||||
seq_printf(p, "%10u ", kstat_irqs(i));
|
||||
#else
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
|
||||
#endif
|
||||
seq_printf(p, " %14s", irq_desc[i].chip->typename);
|
||||
seq_printf(p, " %s", action->name);
|
||||
|
||||
for (action=action->next; action; action = action->next)
|
||||
seq_printf(p, ", %s", action->name);
|
||||
|
||||
seq_putc(p, '\n');
|
||||
skip:
|
||||
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
|
||||
} else if (i == NR_IRQS) {
|
||||
seq_printf(p, "NMI: ");
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ", nmi_count(j));
|
||||
seq_putc(p, '\n');
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
seq_printf(p, "LOC: ");
|
||||
for_each_online_cpu(j)
|
||||
seq_printf(p, "%10u ",
|
||||
per_cpu(irq_stat,j).apic_timer_irqs);
|
||||
seq_putc(p, '\n');
|
||||
#endif
|
||||
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
|
||||
#if defined(CONFIG_X86_IO_APIC)
|
||||
seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
|
||||
void fixup_irqs(cpumask_t map)
|
||||
{
|
||||
unsigned int irq;
|
||||
static int warned;
|
||||
|
||||
for (irq = 0; irq < NR_IRQS; irq++) {
|
||||
cpumask_t mask;
|
||||
if (irq == 2)
|
||||
continue;
|
||||
|
||||
cpus_and(mask, irq_desc[irq].affinity, map);
|
||||
if (any_online_cpu(mask) == NR_CPUS) {
|
||||
/*printk("Breaking affinity for irq %i\n", irq);*/
|
||||
mask = map;
|
||||
}
|
||||
if (irq_desc[irq].chip->set_affinity)
|
||||
irq_desc[irq].chip->set_affinity(irq, mask);
|
||||
else if (irq_desc[irq].action && !(warned++))
|
||||
printk("Cannot set affinity for irq %i\n", irq);
|
||||
}
|
||||
|
||||
#if 0
|
||||
barrier();
|
||||
/* Ingo Molnar says: "after the IO-APIC masks have been redirected
|
||||
[note the nop - the interrupt-enable boundary on x86 is two
|
||||
instructions from sti] - to flush out pending hardirqs and
|
||||
IPIs. After this point nothing is supposed to reach this CPU." */
|
||||
__asm__ __volatile__("sti; nop; cli");
|
||||
barrier();
|
||||
#else
|
||||
/* That doesn't seem sufficient. Give it 1ms. */
|
||||
local_irq_enable();
|
||||
mdelay(1);
|
||||
local_irq_disable();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* linux/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;
|
||||
void *address;
|
||||
|
||||
err = 0;
|
||||
address = &default_ldt[0];
|
||||
size = 5*sizeof(struct desc_struct);
|
||||
if (size > bytecount)
|
||||
size = bytecount;
|
||||
|
||||
err = size;
|
||||
if (copy_to_user(ptr, address, 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;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* machine_kexec.c - handle transition of Linux booting another kernel
|
||||
* Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#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
|
||||
static u32 kexec_pmd0[1024] PAGE_ALIGNED;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
#endif /* CONFIG_XEN */
|
||||
|
||||
/*
|
||||
* A architecture hook called to validate the
|
||||
* proposed image and prepare the control pages
|
||||
* as needed. The pages for KEXEC_CONTROL_CODE_SIZE
|
||||
* have been allocated, but the segments have yet
|
||||
* been copied into the kernel.
|
||||
*
|
||||
* Do what every setup is needed on image and the
|
||||
* reboot code buffer to allow us to avoid allocations
|
||||
* later.
|
||||
*
|
||||
* Currently nothing.
|
||||
*/
|
||||
int machine_kexec_prepare(struct kimage *image)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undo anything leftover by machine_kexec_prepare
|
||||
* when an image is freed.
|
||||
*/
|
||||
void machine_kexec_cleanup(struct kimage *image)
|
||||
{
|
||||
}
|
||||
|
||||
#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.
|
||||
*/
|
||||
NORET_TYPE void machine_kexec(struct kimage *image)
|
||||
{
|
||||
unsigned long page_list[PAGES_NR];
|
||||
void *control_page;
|
||||
|
||||
/* Interrupts aren't acceptable while we reboot */
|
||||
local_irq_disable();
|
||||
|
||||
control_page = page_address(image->control_code_page);
|
||||
memcpy(control_page, relocate_kernel, PAGE_SIZE);
|
||||
|
||||
page_list[PA_CONTROL_PAGE] = __pa(control_page);
|
||||
page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
|
||||
page_list[PA_PGD] = __pa(kexec_pgd);
|
||||
page_list[VA_PGD] = (unsigned long)kexec_pgd;
|
||||
#ifdef CONFIG_X86_PAE
|
||||
page_list[PA_PMD_0] = __pa(kexec_pmd0);
|
||||
page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
|
||||
page_list[PA_PMD_1] = __pa(kexec_pmd1);
|
||||
page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
|
||||
#endif
|
||||
page_list[PA_PTE_0] = __pa(kexec_pte0);
|
||||
page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
|
||||
page_list[PA_PTE_1] = __pa(kexec_pte1);
|
||||
page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
|
||||
|
||||
relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
|
||||
image->start, cpu_has_pae);
|
||||
}
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
* 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 <xen/gnttab.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 force_iommu __read_mostly= 0;
|
||||
|
||||
__init int iommu_setup(char *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __init pci_iommu_alloc(void)
|
||||
{
|
||||
#ifdef CONFIG_SWIOTLB
|
||||
pci_swiotlb_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __init pci_iommu_init(void)
|
||||
{
|
||||
no_iommu_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must execute after PCI subsystem */
|
||||
fs_initcall(pci_iommu_init);
|
||||
#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;
|
||||
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
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 =
|
||||
gnttab_dma_map_page(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)
|
||||
{
|
||||
int i;
|
||||
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
if (swiotlb)
|
||||
swiotlb_unmap_sg(hwdev, sg, nents, direction);
|
||||
else {
|
||||
for (i = 0; i < nents; i++ )
|
||||
gnttab_dma_unmap_page(sg[i].dma_address);
|
||||
}
|
||||
}
|
||||
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(direction == DMA_NONE);
|
||||
|
||||
if (swiotlb) {
|
||||
dma_addr = swiotlb_map_page(
|
||||
dev, page, offset, size, direction);
|
||||
} else {
|
||||
dma_addr = gnttab_dma_map_page(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(direction == DMA_NONE);
|
||||
if (swiotlb)
|
||||
swiotlb_unmap_page(dev, dma_address, size, direction);
|
||||
else
|
||||
gnttab_dma_unmap_page(dma_address);
|
||||
}
|
||||
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;
|
||||
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 = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
|
||||
dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
memset(dev->dma_mem->bitmap, 0, bitmap_size);
|
||||
|
||||
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:
|
||||
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;
|
||||
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
WARN_ON(size == 0);
|
||||
|
||||
if (swiotlb) {
|
||||
dma = swiotlb_map_single(dev, ptr, size, direction);
|
||||
} else {
|
||||
dma = gnttab_dma_map_page(virt_to_page(ptr)) +
|
||||
offset_in_page(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)
|
||||
{
|
||||
if (direction == DMA_NONE)
|
||||
BUG();
|
||||
if (swiotlb)
|
||||
swiotlb_unmap_single(dev, dma_addr, size, direction);
|
||||
else
|
||||
gnttab_dma_unmap_page(dma_addr);
|
||||
}
|
||||
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);
|
||||
@@ -1,853 +0,0 @@
|
||||
/*
|
||||
* 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 <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>
|
||||
|
||||
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)
|
||||
{
|
||||
local_irq_disable();
|
||||
|
||||
if (need_resched())
|
||||
local_irq_enable();
|
||||
else {
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
smp_mb__after_clear_bit();
|
||||
safe_halt();
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_idle_wait);
|
||||
|
||||
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(), system_utsname.release,
|
||||
(int)strcspn(system_utsname.version, " "),
|
||||
system_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\n",
|
||||
0xffff & regs->xds,0xffff & regs->xes);
|
||||
|
||||
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);
|
||||
__asm__(".section .text\n"
|
||||
".align 4\n"
|
||||
"kernel_thread_helper:\n\t"
|
||||
"movl %edx,%eax\n\t"
|
||||
"pushl %edx\n\t"
|
||||
"call *%ebx\n\t"
|
||||
"pushl %eax\n\t"
|
||||
"call do_exit\n"
|
||||
".previous");
|
||||
|
||||
/*
|
||||
* 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.orig_eax = -1;
|
||||
regs.eip = (unsigned long) kernel_thread_helper;
|
||||
regs.xcs = GET_KERNEL_CS();
|
||||
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);
|
||||
savesegment(gs,p->thread.gs);
|
||||
|
||||
tsk = current;
|
||||
if (unlikely(test_tsk_thread_flag(tsk, 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, tsk->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) {
|
||||
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);
|
||||
savesegment(gs,dump->regs.gs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_iopl iopl_op;
|
||||
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->iopl != next->iopl)) {
|
||||
iopl_op.iopl = (next->iopl == 0) ? 1 : (next->iopl >> 12) & 3;
|
||||
mcl->op = __HYPERVISOR_physdev_op;
|
||||
mcl->args[0] = PHYSDEVOP_set_iopl;
|
||||
mcl->args[1] = (unsigned long)&iopl_op;
|
||||
mcl++;
|
||||
}
|
||||
|
||||
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 and %gs if needed.
|
||||
*
|
||||
* Glibc normally makes %fs be zero, and %gs is one of
|
||||
* the TLS segments.
|
||||
*/
|
||||
if (unlikely(next->fs))
|
||||
loadsegment(fs, next->fs);
|
||||
|
||||
if (next->gs)
|
||||
loadsegment(gs, next->gs);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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 (randomize_va_space)
|
||||
sp -= get_random_int() % 8192;
|
||||
return sp & ~0xf;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* This file contains work-arounds for x86 and x86_64 platform bugs.
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI)
|
||||
|
||||
static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
|
||||
{
|
||||
u8 config, rev;
|
||||
u32 word;
|
||||
|
||||
/* BIOS may enable hardware IRQ balancing for
|
||||
* E7520/E7320/E7525(revision ID 0x9 and below)
|
||||
* based platforms.
|
||||
* Disable SW irqbalance/affinity on those platforms.
|
||||
*/
|
||||
pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
|
||||
if (rev > 0x9)
|
||||
return;
|
||||
|
||||
printk(KERN_INFO "Intel E7520/7320/7525 detected.");
|
||||
|
||||
/* enable access to config space*/
|
||||
pci_read_config_byte(dev, 0xf4, &config);
|
||||
pci_write_config_byte(dev, 0xf4, config|0x2);
|
||||
|
||||
/* read xTPR register */
|
||||
raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
|
||||
|
||||
if (!(word & (1 << 13))) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* put back the original value for config space*/
|
||||
if (!(config & 0x2))
|
||||
pci_write_config_byte(dev, 0xf4, config);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,624 +0,0 @@
|
||||
/*
|
||||
* 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 mask, int vector)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int cpu;
|
||||
|
||||
local_irq_save(flags);
|
||||
WARN_ON(cpus_addr(mask)[0] & ~cpus_addr(cpu_online_map)[0]);
|
||||
|
||||
for (cpu = 0; cpu < NR_CPUS; ++cpu) {
|
||||
if (cpu_isset(cpu, mask)) {
|
||||
__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;
|
||||
}
|
||||
|
||||
@@ -1,726 +0,0 @@
|
||||
/*
|
||||
* 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/gnttab.h>
|
||||
#include <xen/interface/memory.h>
|
||||
|
||||
int swiotlb;
|
||||
EXPORT_SYMBOL(swiotlb);
|
||||
|
||||
#define OFFSET(val,align) ((unsigned long)((val) & ( (align) - 1)))
|
||||
|
||||
/*
|
||||
* 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 = gnttab_dma_map_page(virt_to_page(ptr)) +
|
||||
offset_in_page(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.
|
||||
*/
|
||||
gnttab_dma_unmap_page(dev_addr);
|
||||
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);
|
||||
else
|
||||
gnttab_dma_unmap_page(dev_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = gnttab_dma_map_page(sg->page) + sg->offset;
|
||||
|
||||
if (address_needs_mapping(hwdev, dev_addr)) {
|
||||
gnttab_dma_unmap_page(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 (in_swiotlb_aperture(sg->dma_address))
|
||||
unmap_single(hwdev,
|
||||
(void *)bus_to_virt(sg->dma_address),
|
||||
sg->dma_length, dir);
|
||||
else
|
||||
gnttab_dma_unmap_page(sg->dma_address);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (in_swiotlb_aperture(sg->dma_address))
|
||||
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 (in_swiotlb_aperture(sg->dma_address))
|
||||
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 = gnttab_dma_map_page(page) + offset;
|
||||
if (address_needs_mapping(hwdev, dev_addr)) {
|
||||
gnttab_dma_unmap_page(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(direction == DMA_NONE);
|
||||
if (in_swiotlb_aperture(dma_address))
|
||||
unmap_single(hwdev, bus_to_virt(dma_address), size, direction);
|
||||
else
|
||||
gnttab_dma_unmap_page(dma_address);
|
||||
}
|
||||
|
||||
#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);
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* linux/arch/i386/kernel/sysenter.c
|
||||
*
|
||||
* (C) Copyright 2002 Linus Torvalds
|
||||
* Portions based on the vdso-randomization code from exec-shield:
|
||||
* Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
|
||||
*
|
||||
* This file contains the needed initializations to support sysenter.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/msr.h>
|
||||
#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()?
|
||||
*/
|
||||
unsigned int __read_mostly vdso_enabled = 1;
|
||||
|
||||
EXPORT_SYMBOL_GPL(vdso_enabled);
|
||||
|
||||
static int __init vdso_setup(char *s)
|
||||
{
|
||||
vdso_enabled = simple_strtoul(s, NULL, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("vdso=", vdso_setup);
|
||||
|
||||
extern asmlinkage void sysenter_entry(void);
|
||||
|
||||
void enable_sep_cpu(void)
|
||||
{
|
||||
#ifndef CONFIG_X86_NO_TSS
|
||||
int cpu = get_cpu();
|
||||
struct tss_struct *tss = &per_cpu(init_tss, cpu);
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_SEP)) {
|
||||
put_cpu();
|
||||
return;
|
||||
}
|
||||
|
||||
tss->ss1 = __KERNEL_CS;
|
||||
tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
|
||||
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
|
||||
put_cpu();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* These symbols are defined by vsyscall.o to mark the bounds
|
||||
* of the ELF DSO images included therein.
|
||||
*/
|
||||
extern const char vsyscall_int80_start, vsyscall_int80_end;
|
||||
extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
|
||||
static void *syscall_page;
|
||||
|
||||
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);
|
||||
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)) {
|
||||
memcpy(syscall_page,
|
||||
&vsyscall_int80_start,
|
||||
&vsyscall_int80_end - &vsyscall_int80_start);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(syscall_page,
|
||||
&vsyscall_sysenter_start,
|
||||
&vsyscall_sysenter_end - &vsyscall_sysenter_start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct page *syscall_nopage(struct vm_area_struct *vma,
|
||||
unsigned long adr, int *type)
|
||||
{
|
||||
struct page *p = virt_to_page(adr - vma->vm_start + syscall_page);
|
||||
get_page(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Prevent VMA merging */
|
||||
static void syscall_vma_close(struct vm_area_struct *vma)
|
||||
{
|
||||
}
|
||||
|
||||
static struct vm_operations_struct syscall_vm_ops = {
|
||||
.close = syscall_vma_close,
|
||||
.nopage = syscall_nopage,
|
||||
};
|
||||
|
||||
/* Defined in vsyscall-sysenter.S */
|
||||
extern void SYSENTER_RETURN;
|
||||
|
||||
/* Setup a VMA at program startup for the vsyscall page */
|
||||
int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
struct mm_struct *mm = current->mm;
|
||||
unsigned long addr;
|
||||
int ret;
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
|
||||
if (IS_ERR_VALUE(addr)) {
|
||||
ret = addr;
|
||||
goto up_fail;
|
||||
}
|
||||
|
||||
vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
|
||||
if (!vma) {
|
||||
ret = -ENOMEM;
|
||||
goto up_fail;
|
||||
}
|
||||
|
||||
vma->vm_start = addr;
|
||||
vma->vm_end = addr + PAGE_SIZE;
|
||||
/* MAYWRITE to allow gdb to COW and set breakpoints */
|
||||
vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
|
||||
vma->vm_flags |= mm->def_flags;
|
||||
vma->vm_page_prot = protection_map[vma->vm_flags & 7];
|
||||
vma->vm_ops = &syscall_vm_ops;
|
||||
vma->vm_mm = mm;
|
||||
|
||||
ret = insert_vm_struct(mm, vma);
|
||||
if (unlikely(ret)) {
|
||||
kmem_cache_free(vm_area_cachep, vma);
|
||||
goto up_fail;
|
||||
}
|
||||
|
||||
current->mm->context.vdso = (void *)addr;
|
||||
current_thread_info()->sysenter_return =
|
||||
(void *)VDSO_SYM(&SYSENTER_RETURN);
|
||||
mm->total_vm++;
|
||||
up_fail:
|
||||
up_write(&mm->mmap_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *arch_vma_name(struct vm_area_struct *vma)
|
||||
{
|
||||
if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
|
||||
return "[vdso]";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int in_gate_area(struct task_struct *task, unsigned long addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_gate_area_no_task(unsigned long addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,828 +0,0 @@
|
||||
/*
|
||||
* linux/kernel/vm86.c
|
||||
*
|
||||
* Copyright (C) 1994 Linus Torvalds
|
||||
*
|
||||
* 29 dec 2001 - Fixed oopses caused by unchecked access to the vm86
|
||||
* stack - Manfred Spraul <manfred@colorfullife.com>
|
||||
*
|
||||
* 22 mar 2002 - Manfred detected the stackfaults, but didn't handle
|
||||
* them correctly. Now the emulation will be in a
|
||||
* consistent state after stackfaults - Kasper Dupont
|
||||
* <kasperd@daimi.au.dk>
|
||||
*
|
||||
* 22 mar 2002 - Added missing clear_IF in set_vflags_* Kasper Dupont
|
||||
* <kasperd@daimi.au.dk>
|
||||
*
|
||||
* ?? ??? 2002 - Fixed premature returns from handle_vm86_fault
|
||||
* caused by Kasper Dupont's changes - Stas Sergeev
|
||||
*
|
||||
* 4 apr 2002 - Fixed CHECK_IF_IN_TRAP broken by Stas' changes.
|
||||
* Kasper Dupont <kasperd@daimi.au.dk>
|
||||
*
|
||||
* 9 apr 2002 - Changed syntax of macros in handle_vm86_fault.
|
||||
* Kasper Dupont <kasperd@daimi.au.dk>
|
||||
*
|
||||
* 9 apr 2002 - Changed stack access macros to jump to a label
|
||||
* instead of returning to userspace. This simplifies
|
||||
* do_int, and is needed by handle_vm6_fault. Kasper
|
||||
* Dupont <kasperd@daimi.au.dk>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
/*
|
||||
* Known problems:
|
||||
*
|
||||
* Interrupt handling is not guaranteed:
|
||||
* - a real x86 will disable all interrupts for one instruction
|
||||
* after a "mov ss,xx" to make stack handling atomic even without
|
||||
* the 'lss' instruction. We can't guarantee this in v86 mode,
|
||||
* as the next instruction might result in a page fault or similar.
|
||||
* - a real x86 will have interrupts disabled for one instruction
|
||||
* past the 'sti' that enables them. We don't bother with all the
|
||||
* details yet.
|
||||
*
|
||||
* Let's hope these problems do not actually matter for anything.
|
||||
*/
|
||||
|
||||
|
||||
#define KVM86 ((struct kernel_vm86_struct *)regs)
|
||||
#define VMPI KVM86->vm86plus
|
||||
|
||||
|
||||
/*
|
||||
* 8- and 16-bit register defines..
|
||||
*/
|
||||
#define AL(regs) (((unsigned char *)&((regs)->eax))[0])
|
||||
#define AH(regs) (((unsigned char *)&((regs)->eax))[1])
|
||||
#define IP(regs) (*(unsigned short *)&((regs)->eip))
|
||||
#define SP(regs) (*(unsigned short *)&((regs)->esp))
|
||||
|
||||
/*
|
||||
* virtual flags (16 and 32-bit versions)
|
||||
*/
|
||||
#define VFLAGS (*(unsigned short *)&(current->thread.v86flags))
|
||||
#define VEFLAGS (current->thread.v86flags)
|
||||
|
||||
#define set_flags(X,new,mask) \
|
||||
((X) = ((X) & ~(mask)) | ((new) & (mask)))
|
||||
|
||||
#define SAFE_MASK (0xDD5)
|
||||
#define RETURN_MASK (0xDFF)
|
||||
|
||||
#define VM86_REGS_PART2 orig_eax
|
||||
#define VM86_REGS_SIZE1 \
|
||||
( (unsigned)( & (((struct kernel_vm86_regs *)0)->VM86_REGS_PART2) ) )
|
||||
#define VM86_REGS_SIZE2 (sizeof(struct kernel_vm86_regs) - VM86_REGS_SIZE1)
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* This gets called from entry.S with interrupts disabled, but
|
||||
* from process context. Enable interrupts here, before trying
|
||||
* to access user space.
|
||||
*/
|
||||
local_irq_enable();
|
||||
|
||||
if (!current->thread.vm86_info) {
|
||||
printk("no vm86_info: BAD\n");
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask);
|
||||
tmp = copy_to_user(¤t->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
|
||||
tmp += copy_to_user(¤t->thread.vm86_info->regs.VM86_REGS_PART2,
|
||||
®s->VM86_REGS_PART2, VM86_REGS_SIZE2);
|
||||
tmp += put_user(current->thread.screen_bitmap,¤t->thread.vm86_info->screen_bitmap);
|
||||
if (tmp) {
|
||||
printk("vm86: could not access userspace vm86_info\n");
|
||||
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
|
||||
|
||||
loadsegment(fs, current->thread.saved_fs);
|
||||
loadsegment(gs, current->thread.saved_gs);
|
||||
ret = KVM86->regs32;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mark_screen_rdonly(struct mm_struct *mm)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
spinlock_t *ptl;
|
||||
int i;
|
||||
|
||||
pgd = pgd_offset(mm, 0xA0000);
|
||||
if (pgd_none_or_clear_bad(pgd))
|
||||
goto out;
|
||||
pud = pud_offset(pgd, 0xA0000);
|
||||
if (pud_none_or_clear_bad(pud))
|
||||
goto out;
|
||||
pmd = pmd_offset(pud, 0xA0000);
|
||||
if (pmd_none_or_clear_bad(pmd))
|
||||
goto out;
|
||||
pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (pte_present(*pte))
|
||||
set_pte(pte, pte_wrprotect(*pte));
|
||||
pte++;
|
||||
}
|
||||
pte_unmap_unlock(pte, ptl);
|
||||
out:
|
||||
flush_tlb();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int do_vm86_irq_handling(int subfunction, int irqnumber);
|
||||
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
|
||||
|
||||
asmlinkage int sys_vm86old(struct pt_regs regs)
|
||||
{
|
||||
struct vm86_struct __user *v86 = (struct vm86_struct __user *)regs.ebx;
|
||||
struct kernel_vm86_struct info; /* declare this _on top_,
|
||||
* this avoids wasting of stack space.
|
||||
* This remains on the stack until we
|
||||
* return to 32 bit user space.
|
||||
*/
|
||||
struct task_struct *tsk;
|
||||
int tmp, ret = -EPERM;
|
||||
|
||||
tsk = current;
|
||||
if (tsk->thread.saved_esp0)
|
||||
goto out;
|
||||
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
|
||||
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
|
||||
(long)&info.vm86plus - (long)&info.regs.VM86_REGS_PART2);
|
||||
ret = -EFAULT;
|
||||
if (tmp)
|
||||
goto out;
|
||||
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
|
||||
info.regs32 = ®s;
|
||||
tsk->thread.vm86_info = v86;
|
||||
do_sys_vm86(&info, tsk);
|
||||
ret = 0; /* we never return here */
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
asmlinkage int sys_vm86(struct pt_regs regs)
|
||||
{
|
||||
struct kernel_vm86_struct info; /* declare this _on top_,
|
||||
* this avoids wasting of stack space.
|
||||
* This remains on the stack until we
|
||||
* return to 32 bit user space.
|
||||
*/
|
||||
struct task_struct *tsk;
|
||||
int tmp, ret;
|
||||
struct vm86plus_struct __user *v86;
|
||||
|
||||
tsk = current;
|
||||
switch (regs.ebx) {
|
||||
case VM86_REQUEST_IRQ:
|
||||
case VM86_FREE_IRQ:
|
||||
case VM86_GET_IRQ_BITS:
|
||||
case VM86_GET_AND_RESET_IRQ:
|
||||
ret = do_vm86_irq_handling(regs.ebx, (int)regs.ecx);
|
||||
goto out;
|
||||
case VM86_PLUS_INSTALL_CHECK:
|
||||
/* NOTE: on old vm86 stuff this will return the error
|
||||
from access_ok(), because the subfunction is
|
||||
interpreted as (invalid) address to vm86_struct.
|
||||
So the installation check works.
|
||||
*/
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
|
||||
ret = -EPERM;
|
||||
if (tsk->thread.saved_esp0)
|
||||
goto out;
|
||||
v86 = (struct vm86plus_struct __user *)regs.ecx;
|
||||
tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1);
|
||||
tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
|
||||
(long)&info.regs32 - (long)&info.regs.VM86_REGS_PART2);
|
||||
ret = -EFAULT;
|
||||
if (tmp)
|
||||
goto out;
|
||||
info.regs32 = ®s;
|
||||
info.vm86plus.is_vm86pus = 1;
|
||||
tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
|
||||
do_sys_vm86(&info, tsk);
|
||||
ret = 0; /* we never return here */
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
|
||||
{
|
||||
#ifndef CONFIG_X86_NO_TSS
|
||||
struct tss_struct *tss;
|
||||
#endif
|
||||
long eax;
|
||||
/*
|
||||
* make sure the vm86() system call doesn't try to do anything silly
|
||||
*/
|
||||
info->regs.__null_ds = 0;
|
||||
info->regs.__null_es = 0;
|
||||
|
||||
/* we are clearing fs,gs later just before "jmp resume_userspace",
|
||||
* because starting with Linux 2.1.x they aren't no longer saved/restored
|
||||
*/
|
||||
|
||||
/*
|
||||
* The eflags register is also special: we cannot trust that the user
|
||||
* has set it up safely, so this makes sure interrupt etc flags are
|
||||
* inherited from protected mode.
|
||||
*/
|
||||
VEFLAGS = info->regs.eflags;
|
||||
info->regs.eflags &= SAFE_MASK;
|
||||
info->regs.eflags |= info->regs32->eflags & ~SAFE_MASK;
|
||||
info->regs.eflags |= VM_MASK;
|
||||
|
||||
switch (info->cpu_type) {
|
||||
case CPU_286:
|
||||
tsk->thread.v86mask = 0;
|
||||
break;
|
||||
case CPU_386:
|
||||
tsk->thread.v86mask = NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
case CPU_486:
|
||||
tsk->thread.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
default:
|
||||
tsk->thread.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save old state, set default return value (%eax) to 0
|
||||
*/
|
||||
info->regs32->eax = 0;
|
||||
tsk->thread.saved_esp0 = tsk->thread.esp0;
|
||||
savesegment(fs, tsk->thread.saved_fs);
|
||||
savesegment(gs, tsk->thread.saved_gs);
|
||||
|
||||
#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)
|
||||
mark_screen_rdonly(tsk->mm);
|
||||
__asm__ __volatile__("xorl %eax,%eax; movl %eax,%fs; movl %eax,%gs\n\t");
|
||||
__asm__ __volatile__("movl %%eax, %0\n" :"=r"(eax));
|
||||
|
||||
/*call audit_syscall_exit since we do not exit via the normal paths */
|
||||
if (unlikely(current->audit_context))
|
||||
audit_syscall_exit(AUDITSC_RESULT(eax), eax);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movl %0,%%esp\n\t"
|
||||
"movl %1,%%ebp\n\t"
|
||||
"jmp resume_userspace"
|
||||
: /* no outputs */
|
||||
:"r" (&info->regs), "r" (task_thread_info(tsk)));
|
||||
/* we never return here */
|
||||
}
|
||||
|
||||
static inline void return_to_32bit(struct kernel_vm86_regs * regs16, int retval)
|
||||
{
|
||||
struct pt_regs * regs32;
|
||||
|
||||
regs32 = save_v86_state(regs16);
|
||||
regs32->eax = retval;
|
||||
__asm__ __volatile__("movl %0,%%esp\n\t"
|
||||
"movl %1,%%ebp\n\t"
|
||||
"jmp resume_userspace"
|
||||
: : "r" (regs32), "r" (current_thread_info()));
|
||||
}
|
||||
|
||||
static inline void set_IF(struct kernel_vm86_regs * regs)
|
||||
{
|
||||
VEFLAGS |= VIF_MASK;
|
||||
if (VEFLAGS & VIP_MASK)
|
||||
return_to_32bit(regs, VM86_STI);
|
||||
}
|
||||
|
||||
static inline void clear_IF(struct kernel_vm86_regs * regs)
|
||||
{
|
||||
VEFLAGS &= ~VIF_MASK;
|
||||
}
|
||||
|
||||
static inline void clear_TF(struct kernel_vm86_regs * regs)
|
||||
{
|
||||
regs->eflags &= ~TF_MASK;
|
||||
}
|
||||
|
||||
static inline void clear_AC(struct kernel_vm86_regs * regs)
|
||||
{
|
||||
regs->eflags &= ~AC_MASK;
|
||||
}
|
||||
|
||||
/* It is correct to call set_IF(regs) from the set_vflags_*
|
||||
* functions. However someone forgot to call clear_IF(regs)
|
||||
* in the opposite case.
|
||||
* After the command sequence CLI PUSHF STI POPF you should
|
||||
* end up with interrups disabled, but you ended up with
|
||||
* interrupts enabled.
|
||||
* ( I was testing my own changes, but the only bug I
|
||||
* could find was in a function I had not changed. )
|
||||
* [KD]
|
||||
*/
|
||||
|
||||
static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs)
|
||||
{
|
||||
set_flags(VEFLAGS, eflags, current->thread.v86mask);
|
||||
set_flags(regs->eflags, eflags, SAFE_MASK);
|
||||
if (eflags & IF_MASK)
|
||||
set_IF(regs);
|
||||
else
|
||||
clear_IF(regs);
|
||||
}
|
||||
|
||||
static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs)
|
||||
{
|
||||
set_flags(VFLAGS, flags, current->thread.v86mask);
|
||||
set_flags(regs->eflags, flags, SAFE_MASK);
|
||||
if (flags & IF_MASK)
|
||||
set_IF(regs);
|
||||
else
|
||||
clear_IF(regs);
|
||||
}
|
||||
|
||||
static inline unsigned long get_vflags(struct kernel_vm86_regs * regs)
|
||||
{
|
||||
unsigned long flags = regs->eflags & RETURN_MASK;
|
||||
|
||||
if (VEFLAGS & VIF_MASK)
|
||||
flags |= IF_MASK;
|
||||
flags |= IOPL_MASK;
|
||||
return flags | (VEFLAGS & current->thread.v86mask);
|
||||
}
|
||||
|
||||
static inline int is_revectored(int nr, struct revectored_struct * bitmap)
|
||||
{
|
||||
__asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (nr)
|
||||
:"m" (*bitmap),"r" (nr));
|
||||
return nr;
|
||||
}
|
||||
|
||||
#define val_byte(val, n) (((__u8 *)&val)[n])
|
||||
|
||||
#define pushb(base, ptr, val, err_label) \
|
||||
do { \
|
||||
__u8 __val = val; \
|
||||
ptr--; \
|
||||
if (put_user(__val, base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
} while(0)
|
||||
|
||||
#define pushw(base, ptr, val, err_label) \
|
||||
do { \
|
||||
__u16 __val = val; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 1), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 0), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
} while(0)
|
||||
|
||||
#define pushl(base, ptr, val, err_label) \
|
||||
do { \
|
||||
__u32 __val = val; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 3), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 2), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 1), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr--; \
|
||||
if (put_user(val_byte(__val, 0), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
} while(0)
|
||||
|
||||
#define popb(base, ptr, err_label) \
|
||||
({ \
|
||||
__u8 __res; \
|
||||
if (get_user(__res, base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#define popw(base, ptr, err_label) \
|
||||
({ \
|
||||
__u16 __res; \
|
||||
if (get_user(val_byte(__res, 0), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
if (get_user(val_byte(__res, 1), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#define popl(base, ptr, err_label) \
|
||||
({ \
|
||||
__u32 __res; \
|
||||
if (get_user(val_byte(__res, 0), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
if (get_user(val_byte(__res, 1), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
if (get_user(val_byte(__res, 2), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
if (get_user(val_byte(__res, 3), base + ptr) < 0) \
|
||||
goto err_label; \
|
||||
ptr++; \
|
||||
__res; \
|
||||
})
|
||||
|
||||
/* There are so many possible reasons for this function to return
|
||||
* VM86_INTx, so adding another doesn't bother me. We can expect
|
||||
* userspace programs to be able to handle it. (Getting a problem
|
||||
* in userspace is always better than an Oops anyway.) [KD]
|
||||
*/
|
||||
static void do_int(struct kernel_vm86_regs *regs, int i,
|
||||
unsigned char __user * ssp, unsigned short sp)
|
||||
{
|
||||
unsigned long __user *intr_ptr;
|
||||
unsigned long segoffs;
|
||||
|
||||
if (regs->cs == BIOSSEG)
|
||||
goto cannot_handle;
|
||||
if (is_revectored(i, &KVM86->int_revectored))
|
||||
goto cannot_handle;
|
||||
if (i==0x21 && is_revectored(AH(regs),&KVM86->int21_revectored))
|
||||
goto cannot_handle;
|
||||
intr_ptr = (unsigned long __user *) (i << 2);
|
||||
if (get_user(segoffs, intr_ptr))
|
||||
goto cannot_handle;
|
||||
if ((segoffs >> 16) == BIOSSEG)
|
||||
goto cannot_handle;
|
||||
pushw(ssp, sp, get_vflags(regs), cannot_handle);
|
||||
pushw(ssp, sp, regs->cs, cannot_handle);
|
||||
pushw(ssp, sp, IP(regs), cannot_handle);
|
||||
regs->cs = segoffs >> 16;
|
||||
SP(regs) -= 6;
|
||||
IP(regs) = segoffs & 0xffff;
|
||||
clear_TF(regs);
|
||||
clear_IF(regs);
|
||||
clear_AC(regs);
|
||||
return;
|
||||
|
||||
cannot_handle:
|
||||
return_to_32bit(regs, VM86_INTx + (i << 8));
|
||||
}
|
||||
|
||||
int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno)
|
||||
{
|
||||
if (VMPI.is_vm86pus) {
|
||||
if ( (trapno==3) || (trapno==1) )
|
||||
return_to_32bit(regs, VM86_TRAP + (trapno << 8));
|
||||
do_int(regs, trapno, (unsigned char __user *) (regs->ss << 4), SP(regs));
|
||||
return 0;
|
||||
}
|
||||
if (trapno !=1)
|
||||
return 1; /* we let this handle by the calling routine */
|
||||
if (current->ptrace & PT_PTRACED) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
sigdelset(¤t->blocked, SIGTRAP);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
}
|
||||
send_sig(SIGTRAP, current, 1);
|
||||
current->thread.trap_no = trapno;
|
||||
current->thread.error_code = error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
|
||||
{
|
||||
unsigned char opcode;
|
||||
unsigned char __user *csp;
|
||||
unsigned char __user *ssp;
|
||||
unsigned short ip, sp, orig_flags;
|
||||
int data32, pref_done;
|
||||
|
||||
#define CHECK_IF_IN_TRAP \
|
||||
if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
|
||||
newflags |= TF_MASK
|
||||
#define VM86_FAULT_RETURN do { \
|
||||
if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \
|
||||
return_to_32bit(regs, VM86_PICRETURN); \
|
||||
if (orig_flags & TF_MASK) \
|
||||
handle_vm86_trap(regs, 0, 1); \
|
||||
return; } while (0)
|
||||
|
||||
orig_flags = *(unsigned short *)®s->eflags;
|
||||
|
||||
csp = (unsigned char __user *) (regs->cs << 4);
|
||||
ssp = (unsigned char __user *) (regs->ss << 4);
|
||||
sp = SP(regs);
|
||||
ip = IP(regs);
|
||||
|
||||
data32 = 0;
|
||||
pref_done = 0;
|
||||
do {
|
||||
switch (opcode = popb(csp, ip, simulate_sigsegv)) {
|
||||
case 0x66: /* 32-bit data */ data32=1; break;
|
||||
case 0x67: /* 32-bit address */ break;
|
||||
case 0x2e: /* CS */ break;
|
||||
case 0x3e: /* DS */ break;
|
||||
case 0x26: /* ES */ break;
|
||||
case 0x36: /* SS */ break;
|
||||
case 0x65: /* GS */ break;
|
||||
case 0x64: /* FS */ break;
|
||||
case 0xf2: /* repnz */ break;
|
||||
case 0xf3: /* rep */ break;
|
||||
default: pref_done = 1;
|
||||
}
|
||||
} while (!pref_done);
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
/* pushf */
|
||||
case 0x9c:
|
||||
if (data32) {
|
||||
pushl(ssp, sp, get_vflags(regs), simulate_sigsegv);
|
||||
SP(regs) -= 4;
|
||||
} else {
|
||||
pushw(ssp, sp, get_vflags(regs), simulate_sigsegv);
|
||||
SP(regs) -= 2;
|
||||
}
|
||||
IP(regs) = ip;
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
/* popf */
|
||||
case 0x9d:
|
||||
{
|
||||
unsigned long newflags;
|
||||
if (data32) {
|
||||
newflags=popl(ssp, sp, simulate_sigsegv);
|
||||
SP(regs) += 4;
|
||||
} else {
|
||||
newflags = popw(ssp, sp, simulate_sigsegv);
|
||||
SP(regs) += 2;
|
||||
}
|
||||
IP(regs) = ip;
|
||||
CHECK_IF_IN_TRAP;
|
||||
if (data32) {
|
||||
set_vflags_long(newflags, regs);
|
||||
} else {
|
||||
set_vflags_short(newflags, regs);
|
||||
}
|
||||
VM86_FAULT_RETURN;
|
||||
}
|
||||
|
||||
/* int xx */
|
||||
case 0xcd: {
|
||||
int intno=popb(csp, ip, simulate_sigsegv);
|
||||
IP(regs) = ip;
|
||||
if (VMPI.vm86dbg_active) {
|
||||
if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] )
|
||||
return_to_32bit(regs, VM86_INTx + (intno << 8));
|
||||
}
|
||||
do_int(regs, intno, ssp, sp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* iret */
|
||||
case 0xcf:
|
||||
{
|
||||
unsigned long newip;
|
||||
unsigned long newcs;
|
||||
unsigned long newflags;
|
||||
if (data32) {
|
||||
newip=popl(ssp, sp, simulate_sigsegv);
|
||||
newcs=popl(ssp, sp, simulate_sigsegv);
|
||||
newflags=popl(ssp, sp, simulate_sigsegv);
|
||||
SP(regs) += 12;
|
||||
} else {
|
||||
newip = popw(ssp, sp, simulate_sigsegv);
|
||||
newcs = popw(ssp, sp, simulate_sigsegv);
|
||||
newflags = popw(ssp, sp, simulate_sigsegv);
|
||||
SP(regs) += 6;
|
||||
}
|
||||
IP(regs) = newip;
|
||||
regs->cs = newcs;
|
||||
CHECK_IF_IN_TRAP;
|
||||
if (data32) {
|
||||
set_vflags_long(newflags, regs);
|
||||
} else {
|
||||
set_vflags_short(newflags, regs);
|
||||
}
|
||||
VM86_FAULT_RETURN;
|
||||
}
|
||||
|
||||
/* cli */
|
||||
case 0xfa:
|
||||
IP(regs) = ip;
|
||||
clear_IF(regs);
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
/* sti */
|
||||
/*
|
||||
* Damn. This is incorrect: the 'sti' instruction should actually
|
||||
* enable interrupts after the /next/ instruction. Not good.
|
||||
*
|
||||
* Probably needs some horsing around with the TF flag. Aiee..
|
||||
*/
|
||||
case 0xfb:
|
||||
IP(regs) = ip;
|
||||
set_IF(regs);
|
||||
VM86_FAULT_RETURN;
|
||||
|
||||
default:
|
||||
return_to_32bit(regs, VM86_UNKNOWN);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
simulate_sigsegv:
|
||||
/* FIXME: After a long discussion with Stas we finally
|
||||
* agreed, that this is wrong. Here we should
|
||||
* really send a SIGSEGV to the user program.
|
||||
* But how do we create the correct context? We
|
||||
* are inside a general protection fault handler
|
||||
* and has just returned from a page fault handler.
|
||||
* The correct context for the signal handler
|
||||
* should be a mixture of the two, but how do we
|
||||
* get the information? [KD]
|
||||
*/
|
||||
return_to_32bit(regs, VM86_UNKNOWN);
|
||||
}
|
||||
|
||||
/* ---------------- vm86 special IRQ passing stuff ----------------- */
|
||||
|
||||
#define VM86_IRQNAME "vm86irq"
|
||||
|
||||
static struct vm86_irqs {
|
||||
struct task_struct *tsk;
|
||||
int sig;
|
||||
} vm86_irqs[16];
|
||||
|
||||
static DEFINE_SPINLOCK(irqbits_lock);
|
||||
static int irqbits;
|
||||
|
||||
#define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \
|
||||
| (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \
|
||||
| (1 << SIGUNUSED) )
|
||||
|
||||
static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs)
|
||||
{
|
||||
int irq_bit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irqbits_lock, flags);
|
||||
irq_bit = 1 << intno;
|
||||
if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk)
|
||||
goto out;
|
||||
irqbits |= irq_bit;
|
||||
if (vm86_irqs[intno].sig)
|
||||
send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1);
|
||||
/*
|
||||
* IRQ will be re-enabled when user asks for the irq (whether
|
||||
* polling or as a result of the signal)
|
||||
*/
|
||||
disable_irq_nosync(intno);
|
||||
spin_unlock_irqrestore(&irqbits_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&irqbits_lock, flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static inline void free_vm86_irq(int irqnumber)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
free_irq(irqnumber, NULL);
|
||||
vm86_irqs[irqnumber].tsk = NULL;
|
||||
|
||||
spin_lock_irqsave(&irqbits_lock, flags);
|
||||
irqbits &= ~(1 << irqnumber);
|
||||
spin_unlock_irqrestore(&irqbits_lock, flags);
|
||||
}
|
||||
|
||||
void release_vm86_irqs(struct task_struct *task)
|
||||
{
|
||||
int i;
|
||||
for (i = FIRST_VM86_IRQ ; i <= LAST_VM86_IRQ; i++)
|
||||
if (vm86_irqs[i].tsk == task)
|
||||
free_vm86_irq(i);
|
||||
}
|
||||
|
||||
static inline int get_and_reset_irq(int irqnumber)
|
||||
{
|
||||
int bit;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (invalid_vm86_irq(irqnumber)) return 0;
|
||||
if (vm86_irqs[irqnumber].tsk != current) return 0;
|
||||
spin_lock_irqsave(&irqbits_lock, flags);
|
||||
bit = irqbits & (1 << irqnumber);
|
||||
irqbits &= ~bit;
|
||||
if (bit) {
|
||||
enable_irq(irqnumber);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&irqbits_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int do_vm86_irq_handling(int subfunction, int irqnumber)
|
||||
{
|
||||
int ret;
|
||||
switch (subfunction) {
|
||||
case VM86_GET_AND_RESET_IRQ: {
|
||||
return get_and_reset_irq(irqnumber);
|
||||
}
|
||||
case VM86_GET_IRQ_BITS: {
|
||||
return irqbits;
|
||||
}
|
||||
case VM86_REQUEST_IRQ: {
|
||||
int sig = irqnumber >> 8;
|
||||
int irq = irqnumber & 255;
|
||||
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
|
||||
if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM;
|
||||
if (invalid_vm86_irq(irq)) return -EPERM;
|
||||
if (vm86_irqs[irq].tsk) return -EPERM;
|
||||
ret = request_irq(irq, &irq_handler, 0, VM86_IRQNAME, NULL);
|
||||
if (ret) return ret;
|
||||
vm86_irqs[irq].sig = sig;
|
||||
vm86_irqs[irq].tsk = current;
|
||||
return irq;
|
||||
}
|
||||
case VM86_FREE_IRQ: {
|
||||
if (invalid_vm86_irq(irqnumber)) return -EPERM;
|
||||
if (!vm86_irqs[irqnumber].tsk) return 0;
|
||||
if (vm86_irqs[irqnumber].tsk != current) return -EPERM;
|
||||
free_vm86_irq(irqnumber);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/* ld script to make i386 Linux kernel
|
||||
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
|
||||
*/
|
||||
|
||||
#define LOAD_OFFSET __PAGE_OFFSET
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(phys_startup_32)
|
||||
jiffies = jiffies_64;
|
||||
|
||||
PHDRS {
|
||||
text PT_LOAD FLAGS(5); /* R_E */
|
||||
data PT_LOAD FLAGS(7); /* RWE */
|
||||
note PT_NOTE FLAGS(4); /* R__ */
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
. = __KERNEL_START;
|
||||
phys_startup_32 = startup_32 - LOAD_OFFSET;
|
||||
/* read-only */
|
||||
_text = .; /* Text and read-only data */
|
||||
.text : AT(ADDR(.text) - LOAD_OFFSET) {
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
*(.fixup)
|
||||
*(.gnu.warning)
|
||||
} :text = 0x9090
|
||||
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
. = ALIGN(16); /* Exception table */
|
||||
__start___ex_table = .;
|
||||
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
|
||||
__stop___ex_table = .;
|
||||
|
||||
RODATA
|
||||
|
||||
. = ALIGN(4);
|
||||
__tracedata_start = .;
|
||||
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
|
||||
*(.tracedata)
|
||||
}
|
||||
__tracedata_end = .;
|
||||
|
||||
/* writeable */
|
||||
. = ALIGN(4096);
|
||||
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
|
||||
*(.data)
|
||||
CONSTRUCTORS
|
||||
} :data
|
||||
|
||||
. = ALIGN(4096);
|
||||
__nosave_begin = .;
|
||||
.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
|
||||
. = ALIGN(4096);
|
||||
__nosave_end = .;
|
||||
|
||||
. = ALIGN(4096);
|
||||
.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
|
||||
*(.data.idt)
|
||||
}
|
||||
|
||||
. = ALIGN(32);
|
||||
.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
|
||||
*(.data.cacheline_aligned)
|
||||
}
|
||||
|
||||
/* rarely changed data like cpu maps */
|
||||
. = ALIGN(32);
|
||||
.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
|
||||
_edata = .; /* End of data section */
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
. = ALIGN(4);
|
||||
.eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) {
|
||||
__start_unwind = .;
|
||||
*(.eh_frame)
|
||||
__end_unwind = .;
|
||||
}
|
||||
#endif
|
||||
|
||||
. = ALIGN(THREAD_SIZE); /* init_task */
|
||||
.data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
|
||||
*(.data.init_task)
|
||||
}
|
||||
|
||||
/* might get freed after init */
|
||||
. = ALIGN(4096);
|
||||
__smp_alt_begin = .;
|
||||
__smp_alt_instructions = .;
|
||||
.smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
|
||||
*(.smp_altinstructions)
|
||||
}
|
||||
__smp_alt_instructions_end = .;
|
||||
. = ALIGN(4);
|
||||
__smp_locks = .;
|
||||
.smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
|
||||
*(.smp_locks)
|
||||
}
|
||||
__smp_locks_end = .;
|
||||
.smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
|
||||
*(.smp_altinstr_replacement)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
__smp_alt_end = .;
|
||||
|
||||
/* will be freed after init */
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
__init_begin = .;
|
||||
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
|
||||
_sinittext = .;
|
||||
*(.init.text)
|
||||
_einittext = .;
|
||||
}
|
||||
.init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
|
||||
. = ALIGN(16);
|
||||
__setup_start = .;
|
||||
.init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
|
||||
*(.initcall1.init)
|
||||
*(.initcall2.init)
|
||||
*(.initcall3.init)
|
||||
*(.initcall4.init)
|
||||
*(.initcall5.init)
|
||||
*(.initcall6.init)
|
||||
*(.initcall7.init)
|
||||
}
|
||||
__initcall_end = .;
|
||||
__con_initcall_start = .;
|
||||
.con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
|
||||
*(.con_initcall.init)
|
||||
}
|
||||
__con_initcall_end = .;
|
||||
SECURITY_INIT
|
||||
. = ALIGN(4);
|
||||
__alt_instructions = .;
|
||||
.altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
|
||||
*(.altinstructions)
|
||||
}
|
||||
__alt_instructions_end = .;
|
||||
.altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
|
||||
*(.altinstr_replacement)
|
||||
}
|
||||
/* .exit.text is discard at runtime, not link time, to deal with references
|
||||
from .altinstructions and .eh_frame */
|
||||
.exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
|
||||
.exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
|
||||
. = ALIGN(4096);
|
||||
__initramfs_start = .;
|
||||
.init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
|
||||
__initramfs_end = .;
|
||||
. = ALIGN(L1_CACHE_BYTES);
|
||||
__per_cpu_start = .;
|
||||
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
|
||||
__per_cpu_end = .;
|
||||
. = ALIGN(4096);
|
||||
__init_end = .;
|
||||
/* freed after init ends here */
|
||||
|
||||
__bss_start = .; /* BSS */
|
||||
.bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) {
|
||||
*(.bss.page_aligned)
|
||||
}
|
||||
.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
|
||||
*(.bss)
|
||||
}
|
||||
. = ALIGN(4);
|
||||
__bss_stop = .;
|
||||
|
||||
_end = . ;
|
||||
|
||||
/* This is where the kernel creates the early boot page tables */
|
||||
. = ALIGN(4096);
|
||||
pg0 = .;
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
STABS_DEBUG
|
||||
|
||||
DWARF_DEBUG
|
||||
|
||||
NOTES
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,15 +0,0 @@
|
||||
#include <linux/init.h>
|
||||
|
||||
__INITDATA
|
||||
|
||||
.globl vsyscall_int80_start, vsyscall_int80_end
|
||||
vsyscall_int80_start:
|
||||
.incbin "arch/i386/kernel/vsyscall-int80.so"
|
||||
vsyscall_int80_end:
|
||||
|
||||
.globl vsyscall_sysenter_start, vsyscall_sysenter_end
|
||||
vsyscall_sysenter_start:
|
||||
.incbin "arch/i386/kernel/vsyscall-sysenter.so"
|
||||
vsyscall_sysenter_end:
|
||||
|
||||
__FINIT
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-y := setup.o
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
set_fixaddr_top(pp.virt_start);
|
||||
|
||||
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++;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux i386-specific parts of the memory manager.
|
||||
#
|
||||
|
||||
obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o mmap.o
|
||||
|
||||
obj-$(CONFIG_NUMA) += discontig.o
|
||||
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
|
||||
@@ -1,769 +0,0 @@
|
||||
/*
|
||||
* 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 <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/kdebug.h>
|
||||
|
||||
extern void die(const char *,struct pt_regs *,long);
|
||||
|
||||
#ifdef CONFIG_KPROBES
|
||||
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);
|
||||
}
|
||||
|
||||
int unregister_page_fault_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#else
|
||||
static inline int notify_page_fault(enum die_val val, const char *str,
|
||||
struct pt_regs *regs, long err, int trap, int sig)
|
||||
{
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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 = (seg & 2) ? USER_DS.seg : KERNEL_DS.seg;
|
||||
|
||||
/* By far the most common cases. */
|
||||
if (likely(seg == __USER_CS || seg == GET_KERNEL_CS()))
|
||||
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 long instr = 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 > limit)
|
||||
break;
|
||||
if (__get_user(opcode, (unsigned char __user *) instr))
|
||||
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 > limit)
|
||||
break;
|
||||
if (__get_user(opcode, (unsigned char __user *) instr))
|
||||
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 */
|
||||
#ifdef TEST_VERIFY_AREA
|
||||
if (regs->cs == GET_KERNEL_CS())
|
||||
printk("WP fault at %08lx\n", regs->eip);
|
||||
#endif
|
||||
/* 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)))
|
||||
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 (tsk->pid == 1) {
|
||||
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
|
||||
@@ -1,136 +0,0 @@
|
||||
#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 */
|
||||
inc_preempt_count();
|
||||
if (!PageHighMem(page))
|
||||
return page_address(page);
|
||||
|
||||
idx = type + KM_TYPE_NR*smp_processor_id();
|
||||
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
|
||||
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||
if (!pte_none(*(kmap_pte-idx)))
|
||||
BUG();
|
||||
#endif
|
||||
set_pte_at_sync(&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)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_HIGHMEM) || defined(CONFIG_XEN)
|
||||
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
|
||||
enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
|
||||
|
||||
if (vaddr < FIXADDR_START) { // FIXME
|
||||
dec_preempt_count();
|
||||
preempt_check_resched();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DEBUG_HIGHMEM)
|
||||
if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
|
||||
BUG();
|
||||
|
||||
/*
|
||||
* force other mappings to Oops if they'll try to access
|
||||
* this pte without first remap it
|
||||
*/
|
||||
pte_clear(&init_mm, vaddr, kmap_pte-idx);
|
||||
__flush_tlb_one(vaddr);
|
||||
#elif defined(CONFIG_XEN)
|
||||
/*
|
||||
* We must ensure there are no dangling pagetable references when
|
||||
* returning memory to Xen (decrease_reservation).
|
||||
* XXX TODO: We could make this faster by only zapping when
|
||||
* kmap_flush_unused is called but that is trickier and more invasive.
|
||||
*/
|
||||
pte_clear(&init_mm, vaddr, kmap_pte-idx);
|
||||
#endif
|
||||
|
||||
dec_preempt_count();
|
||||
preempt_check_resched();
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
inc_preempt_count();
|
||||
|
||||
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));
|
||||
__flush_tlb_one(vaddr);
|
||||
|
||||
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);
|
||||
@@ -1,432 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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>
|
||||
|
||||
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(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(val);
|
||||
BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_X86_PAE) || defined(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 = __pud_val(val);
|
||||
BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
void xen_l4_entry_update(pgd_t *ptr, pgd_t val)
|
||||
{
|
||||
mmu_update_t u;
|
||||
u.ptr = virt_to_machine(ptr);
|
||||
u.val = __pgd_val(val);
|
||||
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
|
||||
@@ -1,850 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
extern int is_available_memory(efi_memory_desc_t *);
|
||||
|
||||
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 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 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
|
||||
*/
|
||||
void __init noexec_setup(const char *str)
|
||||
{
|
||||
if (!strncmp(str, "on",2) && cpu_has_nx) {
|
||||
__supported_pte_mask |= _PAGE_NX;
|
||||
disable_nx = 0;
|
||||
} else if (!strncmp(str,"off",3)) {
|
||||
disable_nx = 1;
|
||||
__supported_pte_mask &= ~_PAGE_NX;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
__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 void __init set_max_mapnr_init(void)
|
||||
{
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
num_physpages = highend_pfn;
|
||||
#else
|
||||
num_physpages = max_low_pfn;
|
||||
#endif
|
||||
#ifdef CONFIG_FLATMEM
|
||||
max_mapnr = num_physpages;
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
if (!mem_map)
|
||||
BUG();
|
||||
#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
|
||||
|
||||
set_max_mapnr_init();
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
|
||||
#else
|
||||
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
|
||||
#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))
|
||||
);
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
/*
|
||||
* this is for the non-NUMA, single node SMP system case.
|
||||
* Specifically, in the case of x86, we will always add
|
||||
* memory to the highmem for now.
|
||||
*/
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
||||
int arch_add_memory(int nid, u64 start, u64 size)
|
||||
{
|
||||
struct pglist_data *pgdata = &contig_page_data;
|
||||
struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
kmem_cache_t *pgd_cache;
|
||||
kmem_cache_t *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
|
||||
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
* 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 <asm/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(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;
|
||||
}
|
||||
}
|
||||
@@ -1,727 +0,0 @@
|
||||
/*
|
||||
* 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));
|
||||
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 nr_fixmaps = 0;
|
||||
unsigned long hypervisor_virt_start = HYPERVISOR_VIRT_START;
|
||||
unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE);
|
||||
EXPORT_SYMBOL(__FIXADDR_TOP);
|
||||
|
||||
void __init set_fixaddr_top(unsigned long top)
|
||||
{
|
||||
BUG_ON(nr_fixmaps > 0);
|
||||
hypervisor_virt_start = top;
|
||||
__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;
|
||||
}
|
||||
nr_fixmaps++;
|
||||
}
|
||||
|
||||
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, kmem_cache_t *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, kmem_cache_t *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, kmem_cache_t *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);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
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 )
|
||||
|
||||
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
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
obj-y := i386.o init.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
|
||||
pci-y += legacy.o irq.o
|
||||
|
||||
pci-$(CONFIG_X86_VISWS) := visws.o fixup.o
|
||||
pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o
|
||||
|
||||
obj-y += $(pci-y) common.o
|
||||
|
||||
ifdef CONFIG_XEN
|
||||
include $(srctree)/scripts/Makefile.xen
|
||||
obj-y := $(call cherrypickxen, $(obj-y))
|
||||
endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
@@ -1,4 +0,0 @@
|
||||
obj-$(CONFIG_PM_LEGACY) += cpu.o
|
||||
obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o
|
||||
obj-$(CONFIG_ACPI_SLEEP) += cpu.o
|
||||
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
|
||||
@@ -1,587 +0,0 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see Documentation/kbuild/kconfig-language.txt.
|
||||
#
|
||||
|
||||
mainmenu "IA-64 Linux Kernel Configuration"
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
menu "Processor type and features"
|
||||
|
||||
config IA64
|
||||
bool
|
||||
default y
|
||||
help
|
||||
The Itanium Processor Family is Intel's 64-bit successor to
|
||||
the 32-bit X86 line. The IA-64 Linux project has a home
|
||||
page at <http://www.linuxia64.org/> and a mailing list at
|
||||
<linux-ia64@vger.kernel.org>.
|
||||
|
||||
config 64BIT
|
||||
bool
|
||||
default y
|
||||
|
||||
config MMU
|
||||
bool
|
||||
default y
|
||||
|
||||
config SWIOTLB
|
||||
bool
|
||||
default y
|
||||
|
||||
config RWSEM_XCHGADD_ALGORITHM
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_FIND_NEXT_BIT
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config TIME_INTERPOLATION
|
||||
bool
|
||||
default y
|
||||
|
||||
config DMI
|
||||
bool
|
||||
default y
|
||||
|
||||
config EFI
|
||||
bool
|
||||
default y
|
||||
|
||||
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
|
||||
default y
|
||||
|
||||
config IA64_UNCACHED_ALLOCATOR
|
||||
bool
|
||||
select GENERIC_ALLOCATOR
|
||||
|
||||
config DMA_IS_DMA32
|
||||
bool
|
||||
default y
|
||||
|
||||
config DMA_IS_NORMAL
|
||||
bool
|
||||
depends on IA64_SGI_SN2
|
||||
default y
|
||||
|
||||
config AUDIT_ARCH
|
||||
bool
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "System type"
|
||||
default IA64_GENERIC
|
||||
|
||||
config IA64_GENERIC
|
||||
bool "generic"
|
||||
select ACPI
|
||||
select PCI
|
||||
select NUMA
|
||||
select ACPI_NUMA
|
||||
help
|
||||
This selects the system type of your hardware. A "generic" kernel
|
||||
will run on any supported IA-64 system. However, if you configure
|
||||
a kernel for your specific system, it will be faster and smaller.
|
||||
|
||||
generic For any supported IA-64 system
|
||||
DIG-compliant For DIG ("Developer's Interface Guide") compliant systems
|
||||
HP-zx1/sx1000 For HP systems
|
||||
HP-zx1/sx1000+swiotlb For HP systems with (broken) DMA-constrained devices.
|
||||
SGI-SN2 For SGI Altix systems
|
||||
Ski-simulator For the HP simulator <http://www.hpl.hp.com/research/linux/ski/>
|
||||
|
||||
If you don't know what to do, choose "generic".
|
||||
|
||||
config IA64_DIG
|
||||
bool "DIG-compliant"
|
||||
|
||||
config IA64_HP_ZX1
|
||||
bool "HP-zx1/sx1000"
|
||||
help
|
||||
Build a kernel that runs on HP zx1 and sx1000 systems. This adds
|
||||
support for the HP I/O MMU.
|
||||
|
||||
config IA64_HP_ZX1_SWIOTLB
|
||||
bool "HP-zx1/sx1000 with software I/O TLB"
|
||||
help
|
||||
Build a kernel that runs on HP zx1 and sx1000 systems even when they
|
||||
have broken PCI devices which cannot DMA to full 32 bits. Apart
|
||||
from support for the HP I/O MMU, this includes support for the software
|
||||
I/O TLB, which allows supporting the broken devices at the expense of
|
||||
wasting some kernel memory (about 2MB by default).
|
||||
|
||||
config IA64_SGI_SN2
|
||||
bool "SGI-SN2"
|
||||
help
|
||||
Selecting this option will optimize the kernel for use on sn2 based
|
||||
systems, but the resulting kernel binary will not run on other
|
||||
types of ia64 systems. If you have an SGI Altix system, it's safe
|
||||
to select this option. If in doubt, select ia64 generic support
|
||||
instead.
|
||||
|
||||
config IA64_HP_SIM
|
||||
bool "Ski-simulator"
|
||||
|
||||
config IA64_XEN
|
||||
bool "Xen guest"
|
||||
depends on XEN
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Processor type"
|
||||
default ITANIUM
|
||||
|
||||
config ITANIUM
|
||||
bool "Itanium"
|
||||
help
|
||||
Select your IA-64 processor type. The default is Itanium.
|
||||
This choice is safe for all IA-64 systems, but may not perform
|
||||
optimally on systems with, say, Itanium 2 or newer processors.
|
||||
|
||||
config MCKINLEY
|
||||
bool "Itanium 2"
|
||||
help
|
||||
Select this to configure for an Itanium 2 (McKinley) processor.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Kernel page size"
|
||||
default IA64_PAGE_SIZE_16KB
|
||||
|
||||
config IA64_PAGE_SIZE_4KB
|
||||
bool "4KB"
|
||||
help
|
||||
This lets you select the page size of the kernel. For best IA-64
|
||||
performance, a page size of 8KB or 16KB is recommended. For best
|
||||
IA-32 compatibility, a page size of 4KB should be selected (the vast
|
||||
majority of IA-32 binaries work perfectly fine with a larger page
|
||||
size). For Itanium 2 or newer systems, a page size of 64KB can also
|
||||
be selected.
|
||||
|
||||
4KB For best IA-32 compatibility
|
||||
8KB For best IA-64 performance
|
||||
16KB For best IA-64 performance
|
||||
64KB Requires Itanium 2 or newer processor.
|
||||
|
||||
If you don't know what to do, choose 16KB.
|
||||
|
||||
config IA64_PAGE_SIZE_8KB
|
||||
bool "8KB"
|
||||
|
||||
config IA64_PAGE_SIZE_16KB
|
||||
bool "16KB"
|
||||
|
||||
config IA64_PAGE_SIZE_64KB
|
||||
depends on !ITANIUM
|
||||
bool "64KB"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Page Table Levels"
|
||||
default PGTABLE_3
|
||||
|
||||
config PGTABLE_3
|
||||
bool "3 Levels"
|
||||
|
||||
config PGTABLE_4
|
||||
depends on !IA64_PAGE_SIZE_64KB
|
||||
bool "4 Levels"
|
||||
|
||||
endchoice
|
||||
|
||||
source kernel/Kconfig.hz
|
||||
|
||||
config IA64_BRL_EMU
|
||||
bool
|
||||
depends on ITANIUM
|
||||
default y
|
||||
|
||||
# align cache-sensitive data to 128 bytes
|
||||
config IA64_L1_CACHE_SHIFT
|
||||
int
|
||||
default "7" if MCKINLEY
|
||||
default "6" if ITANIUM
|
||||
|
||||
config IA64_CYCLONE
|
||||
bool "Cyclone (EXA) Time Source support"
|
||||
help
|
||||
Say Y here to enable support for IBM EXA Cyclone time source.
|
||||
If you're unsure, answer N.
|
||||
|
||||
config IOSAPIC
|
||||
bool
|
||||
depends on !IA64_HP_SIM
|
||||
default y
|
||||
|
||||
config IA64_SGI_SN_XP
|
||||
tristate "Support communication between SGI SSIs"
|
||||
depends on IA64_GENERIC || IA64_SGI_SN2
|
||||
select IA64_UNCACHED_ALLOCATOR
|
||||
help
|
||||
An SGI machine can be divided into multiple Single System
|
||||
Images which act independently of each other and have
|
||||
hardware based memory protection from the others. Enabling
|
||||
this feature will allow for direct communication between SSIs
|
||||
based on a network adapter and DMA messaging.
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int "MAX_ORDER (11 - 17)" if !HUGETLB_PAGE
|
||||
range 11 17 if !HUGETLB_PAGE
|
||||
default "17" if HUGETLB_PAGE
|
||||
default "11"
|
||||
|
||||
config SMP
|
||||
bool "Symmetric multi-processing support"
|
||||
help
|
||||
This enables support for systems with more than one CPU. If you have
|
||||
a system with only one CPU, say N. If you have a system with more
|
||||
than one CPU, say Y.
|
||||
|
||||
If you say N here, the kernel will run on single and multiprocessor
|
||||
systems, but will use only one CPU of a multiprocessor system. If
|
||||
you say Y here, the kernel will run on many, but not all,
|
||||
single processor systems. On a single processor system, the kernel
|
||||
will run faster if you say N here.
|
||||
|
||||
See also the <file:Documentation/smp.txt> and the SMP-HOWTO
|
||||
available at <http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config NR_CPUS
|
||||
int "Maximum number of CPUs (2-1024)"
|
||||
range 2 1024
|
||||
depends on SMP
|
||||
default "1024"
|
||||
help
|
||||
You should set this to the number of CPUs in your system, but
|
||||
keep in mind that a kernel compiled for, e.g., 2 CPUs will boot but
|
||||
only use 2 CPUs on a >2 CPU system. Setting this to a value larger
|
||||
than 64 will cause the use of a CPU mask array, causing a small
|
||||
performance hit.
|
||||
|
||||
config HOTPLUG_CPU
|
||||
bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
|
||||
depends on SMP && EXPERIMENTAL
|
||||
select HOTPLUG
|
||||
default n
|
||||
---help---
|
||||
Say Y here to experiment with turning CPUs off and on. CPUs
|
||||
can be controlled through /sys/devices/system/cpu/cpu#.
|
||||
Say N if you want to disable CPU hotplug.
|
||||
|
||||
config ARCH_ENABLE_MEMORY_HOTPLUG
|
||||
def_bool y
|
||||
|
||||
config SCHED_SMT
|
||||
bool "SMT scheduler support"
|
||||
depends on SMP
|
||||
help
|
||||
Improves the CPU scheduler's decision making when dealing with
|
||||
Intel IA64 chips with MultiThreading at a cost of slightly increased
|
||||
overhead in some places. If unsure say N here.
|
||||
|
||||
config PERMIT_BSP_REMOVE
|
||||
bool "Support removal of Bootstrap Processor"
|
||||
depends on HOTPLUG_CPU
|
||||
default n
|
||||
---help---
|
||||
Say Y here if your platform SAL will support removal of BSP with HOTPLUG_CPU
|
||||
support.
|
||||
|
||||
config FORCE_CPEI_RETARGET
|
||||
bool "Force assumption that CPEI can be re-targetted"
|
||||
depends on PERMIT_BSP_REMOVE
|
||||
default n
|
||||
---help---
|
||||
Say Y if you need to force the assumption that CPEI can be re-targetted to
|
||||
any cpu in the system. This hint is available via ACPI 3.0 specifications.
|
||||
Tiger4 systems are capable of re-directing CPEI to any CPU other than BSP.
|
||||
This option it useful to enable this feature on older BIOS's as well.
|
||||
You can also enable this by using boot command line option force_cpei=1.
|
||||
|
||||
config PREEMPT
|
||||
bool "Preemptible Kernel"
|
||||
help
|
||||
This option reduces the latency of the kernel when reacting to
|
||||
real-time or interactive events by allowing a low priority process to
|
||||
be preempted even if it is in kernel mode executing a system call.
|
||||
This allows applications to run more reliably even when the system is
|
||||
under load.
|
||||
|
||||
Say Y here if you are building a kernel for a desktop, embedded
|
||||
or real-time system. Say N if you are unsure.
|
||||
|
||||
source "mm/Kconfig"
|
||||
|
||||
config ARCH_SELECT_MEMORY_MODEL
|
||||
def_bool y
|
||||
|
||||
config ARCH_DISCONTIGMEM_ENABLE
|
||||
def_bool y
|
||||
help
|
||||
Say Y to support efficient handling of discontiguous physical memory,
|
||||
for architectures which are either NUMA (Non-Uniform Memory Access)
|
||||
or have huge holes in the physical address space for other reasons.
|
||||
See <file:Documentation/vm/numa> for more.
|
||||
|
||||
config ARCH_FLATMEM_ENABLE
|
||||
def_bool y
|
||||
|
||||
config ARCH_SPARSEMEM_ENABLE
|
||||
def_bool y
|
||||
depends on ARCH_DISCONTIGMEM_ENABLE
|
||||
|
||||
config ARCH_DISCONTIGMEM_DEFAULT
|
||||
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB)
|
||||
depends on ARCH_DISCONTIGMEM_ENABLE
|
||||
|
||||
config NUMA
|
||||
bool "NUMA support"
|
||||
depends on !IA64_HP_SIM && !FLATMEM
|
||||
default y if IA64_SGI_SN2
|
||||
help
|
||||
Say Y to compile the kernel to support NUMA (Non-Uniform Memory
|
||||
Access). This option is for configuring high-end multiprocessor
|
||||
server systems. If in doubt, say N.
|
||||
|
||||
config NODES_SHIFT
|
||||
int "Max num nodes shift(3-10)"
|
||||
range 3 10
|
||||
default "10"
|
||||
depends on NEED_MULTIPLE_NODES
|
||||
help
|
||||
This option specifies the maximum number of nodes in your SSI system.
|
||||
MAX_NUMNODES will be 2^(This value).
|
||||
If in doubt, use the default.
|
||||
|
||||
# VIRTUAL_MEM_MAP and FLAT_NODE_MEM_MAP are functionally equivalent.
|
||||
# VIRTUAL_MEM_MAP has been retained for historical reasons.
|
||||
config VIRTUAL_MEM_MAP
|
||||
bool "Virtual mem map"
|
||||
depends on !SPARSEMEM
|
||||
default y if !IA64_HP_SIM
|
||||
help
|
||||
Say Y to compile the kernel with support for a virtual mem map.
|
||||
This code also only takes effect if a memory hole of greater than
|
||||
1 Gb is found during boot. You must turn this option on if you
|
||||
require the DISCONTIGMEM option for your machine. If you are
|
||||
unsure, say Y.
|
||||
|
||||
config HOLES_IN_ZONE
|
||||
bool
|
||||
default y if VIRTUAL_MEM_MAP
|
||||
|
||||
config HAVE_ARCH_EARLY_PFN_TO_NID
|
||||
def_bool y
|
||||
depends on NEED_MULTIPLE_NODES
|
||||
|
||||
config HAVE_ARCH_NODEDATA_EXTENSION
|
||||
def_bool y
|
||||
depends on NUMA
|
||||
|
||||
config IA32_SUPPORT
|
||||
bool "Support for Linux/x86 binaries"
|
||||
help
|
||||
IA-64 processors can execute IA-32 (X86) instructions. By
|
||||
saying Y here, the kernel will include IA-32 system call
|
||||
emulation support which makes it possible to transparently
|
||||
run IA-32 Linux binaries on an IA-64 Linux system.
|
||||
If in doubt, say Y.
|
||||
|
||||
config COMPAT
|
||||
bool
|
||||
depends on IA32_SUPPORT
|
||||
default y
|
||||
|
||||
config IA64_MCA_RECOVERY
|
||||
tristate "MCA recovery from errors other than TLB."
|
||||
|
||||
config PERFMON
|
||||
bool "Performance monitor support"
|
||||
help
|
||||
Selects whether support for the IA-64 performance monitor hardware
|
||||
is included in the kernel. This makes some kernel data-structures a
|
||||
little bigger and slows down execution a bit, but it is generally
|
||||
a good idea to turn this on. If you're unsure, say Y.
|
||||
|
||||
config IA64_PALINFO
|
||||
tristate "/proc/pal support"
|
||||
help
|
||||
If you say Y here, you are able to get PAL (Processor Abstraction
|
||||
Layer) information in /proc/pal. This contains useful information
|
||||
about the processors in your systems, such as cache and TLB sizes
|
||||
and the PAL firmware version in use.
|
||||
|
||||
To use this option, you have to ensure that the "/proc file system
|
||||
support" (CONFIG_PROC_FS) is enabled, too.
|
||||
|
||||
config SGI_SN
|
||||
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
|
||||
|
||||
source "drivers/sn/Kconfig"
|
||||
|
||||
source "drivers/firmware/Kconfig"
|
||||
|
||||
source "fs/Kconfig.binfmt"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Power management and ACPI"
|
||||
|
||||
source "kernel/power/Kconfig"
|
||||
|
||||
source "drivers/acpi/Kconfig"
|
||||
|
||||
if PM
|
||||
|
||||
source "arch/ia64/kernel/cpufreq/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
||||
if !IA64_HP_SIM
|
||||
|
||||
menu "Bus options (PCI, PCMCIA)"
|
||||
|
||||
config PCI
|
||||
bool "PCI support"
|
||||
help
|
||||
Real IA-64 machines all have PCI/PCI-X/PCI Express busses. Say Y
|
||||
here unless you are using a simulator without PCI support.
|
||||
|
||||
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"
|
||||
|
||||
source "drivers/pci/hotplug/Kconfig"
|
||||
|
||||
source "drivers/pcmcia/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
||||
source "fs/Kconfig"
|
||||
|
||||
source "lib/Kconfig"
|
||||
|
||||
#
|
||||
# Use the generic interrupt handling code in kernel/irq/:
|
||||
#
|
||||
config GENERIC_HARDIRQS
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_IRQ_PROBE
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_PENDING_IRQ
|
||||
bool
|
||||
depends on GENERIC_HARDIRQS && SMP
|
||||
default y
|
||||
|
||||
config IRQ_PER_CPU
|
||||
bool
|
||||
default y
|
||||
|
||||
source "arch/ia64/hp/sim/Kconfig"
|
||||
|
||||
menu "Instrumentation Support"
|
||||
depends on EXPERIMENTAL
|
||||
|
||||
source "arch/ia64/oprofile/Kconfig"
|
||||
|
||||
config KPROBES
|
||||
bool "Kprobes (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && MODULES
|
||||
help
|
||||
Kprobes allows you to trap at almost any kernel address and
|
||||
execute a callback function. register_kprobe() establishes
|
||||
a probepoint and specifies the callback. Kprobes is useful
|
||||
for kernel debugging, non-intrusive instrumentation and testing.
|
||||
If in doubt, say "N".
|
||||
endmenu
|
||||
|
||||
source "arch/ia64/Kconfig.debug"
|
||||
|
||||
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"
|
||||
@@ -1,106 +0,0 @@
|
||||
#
|
||||
# ia64/Makefile
|
||||
#
|
||||
# This file is included by the global makefile so that you can add your own
|
||||
# architecture-specific flags and dependencies.
|
||||
#
|
||||
# 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-2004 by David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
#
|
||||
|
||||
NM := $(CROSS_COMPILE)nm -B
|
||||
READELF := $(CROSS_COMPILE)readelf
|
||||
|
||||
export AWK
|
||||
|
||||
CHECKFLAGS += -m64 -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__
|
||||
|
||||
OBJCOPYFLAGS := --strip-all
|
||||
LDFLAGS_vmlinux := -static
|
||||
LDFLAGS_MODULE += -T $(srctree)/arch/ia64/module.lds
|
||||
AFLAGS_KERNEL := -mconstant-gp
|
||||
EXTRA :=
|
||||
|
||||
cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \
|
||||
-falign-functions=32 -frename-registers -fno-optimize-sibling-calls
|
||||
CFLAGS_KERNEL := -mconstant-gp
|
||||
|
||||
GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas "$(CC)" "$(OBJDUMP)")
|
||||
CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags "$(CC)" "$(OBJDUMP)" "$(READELF)")
|
||||
|
||||
ifeq ($(GAS_STATUS),buggy)
|
||||
$(error Sorry, you need a newer version of the assember, one that is built from \
|
||||
a source-tree that post-dates 18-Dec-2002. You can find a pre-compiled \
|
||||
static binary of such an assembler at: \
|
||||
\
|
||||
ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz)
|
||||
endif
|
||||
|
||||
ifeq ($(call cc-version),0304)
|
||||
cflags-$(CONFIG_ITANIUM) += -mtune=merced
|
||||
cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley
|
||||
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/
|
||||
core-y += arch/ia64/kernel/ arch/ia64/mm/
|
||||
core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/
|
||||
core-$(CONFIG_IA64_DIG) += arch/ia64/dig/
|
||||
core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/
|
||||
core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
|
||||
core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
|
||||
core-$(CONFIG_IA64_XEN) += arch/ia64/dig/
|
||||
core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
|
||||
core-$(CONFIG_XEN) += arch/ia64/xen/
|
||||
|
||||
drivers-$(CONFIG_PCI) += arch/ia64/pci/
|
||||
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
|
||||
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/
|
||||
drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/
|
||||
|
||||
boot := arch/ia64/hp/sim/boot
|
||||
|
||||
PHONY += boot compressed check
|
||||
|
||||
all: compressed unwcheck
|
||||
|
||||
compressed: vmlinux.gz
|
||||
|
||||
vmlinuz: vmlinux.gz
|
||||
|
||||
vmlinux.gz: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||
|
||||
unwcheck: vmlinux
|
||||
-$(Q)READELF=$(READELF) $(srctree)/arch/ia64/scripts/unwcheck.py $<
|
||||
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
||||
CLEAN_FILES += vmlinux.gz bootloader
|
||||
|
||||
boot: lib/lib.a vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||
|
||||
install:
|
||||
-yes | sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
|
||||
|
||||
define archhelp
|
||||
echo '* compressed - Build compressed kernel image'
|
||||
echo ' install - Install compressed kernel image'
|
||||
echo ' boot - Build vmlinux and bootloader for Ski simulator'
|
||||
echo '* unwcheck - Check vmlinux for invalid unwind info'
|
||||
endef
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,63 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
extra-y := head.o init_task.o vmlinux.lds
|
||||
|
||||
obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
|
||||
irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
|
||||
salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
|
||||
unwind.o mca.o mca_asm.o topology.o
|
||||
|
||||
obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
|
||||
obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o
|
||||
obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o
|
||||
obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o
|
||||
|
||||
ifneq ($(CONFIG_ACPI_PROCESSOR),)
|
||||
obj-y += acpi-processor.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_IA64_PALINFO) += palinfo.o
|
||||
obj-$(CONFIG_IOSAPIC) += iosapic.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_SMP) += smp.o smpboot.o
|
||||
obj-$(CONFIG_NUMA) += numa.o
|
||||
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
|
||||
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq/
|
||||
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
|
||||
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
|
||||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
mca_recovery-y += mca_drv.o mca_drv_asm.o
|
||||
|
||||
# The gate DSO image is built using a special linker script.
|
||||
targets += gate.so gate-syms.o
|
||||
|
||||
extra-y += gate.so gate-syms.o gate.lds gate.o
|
||||
|
||||
# fp_emulate() expects f2-f5,f16-f31 to contain the user-level state.
|
||||
CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31
|
||||
|
||||
CPPFLAGS_gate.lds := -P -C -U$(ARCH)
|
||||
|
||||
quiet_cmd_gate = GATE $@
|
||||
cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
|
||||
|
||||
GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
|
||||
$(call ld-option, -Wl$(comma)--hash-style=sysv)
|
||||
$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
|
||||
$(call if_changed,gate)
|
||||
|
||||
$(obj)/built-in.o: $(obj)/gate-syms.o
|
||||
$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o
|
||||
|
||||
GATECFLAGS_gate-syms.o = -r
|
||||
$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
|
||||
$(call if_changed,gate)
|
||||
|
||||
# gate-data.o contains the gate DSO image as data in section .data.gate.
|
||||
# We must build gate.so before we can assemble it.
|
||||
# Note: kbuild does not track this dependency due to usage of .incbin
|
||||
$(obj)/gate-data.o: $(obj)/gate.so
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Generate definitions needed by assembly language modules.
|
||||
* This code generates raw asm output which is post-processed
|
||||
* to extract and format the required data.
|
||||
*/
|
||||
|
||||
#define ASM_OFFSETS_C 1
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm-ia64/processor.h>
|
||||
#include <asm-ia64/ptrace.h>
|
||||
#include <asm-ia64/siginfo.h>
|
||||
#include <asm-ia64/sigcontext.h>
|
||||
#include <asm-ia64/mca.h>
|
||||
|
||||
#include "../kernel/sigframe.h"
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
#define BLANK() asm volatile("\n->" : : )
|
||||
|
||||
void foo(void)
|
||||
{
|
||||
DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct));
|
||||
DEFINE(IA64_THREAD_INFO_SIZE, sizeof (struct thread_info));
|
||||
DEFINE(IA64_PT_REGS_SIZE, sizeof (struct pt_regs));
|
||||
DEFINE(IA64_SWITCH_STACK_SIZE, sizeof (struct switch_stack));
|
||||
DEFINE(IA64_SIGINFO_SIZE, sizeof (struct siginfo));
|
||||
DEFINE(IA64_CPU_SIZE, sizeof (struct cpuinfo_ia64));
|
||||
DEFINE(SIGFRAME_SIZE, sizeof (struct sigframe));
|
||||
DEFINE(UNW_FRAME_INFO_SIZE, sizeof (struct unw_frame_info));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
|
||||
DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked));
|
||||
DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid));
|
||||
DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader));
|
||||
DEFINE(IA64_TASK_PENDING_OFFSET,offsetof (struct task_struct, pending));
|
||||
DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid));
|
||||
DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent));
|
||||
DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand));
|
||||
DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal));
|
||||
DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid));
|
||||
DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp));
|
||||
DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SIGHAND_SIGLOCK_OFFSET,offsetof (struct sighand_struct, siglock));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,offsetof (struct signal_struct,
|
||||
group_stop_count));
|
||||
DEFINE(IA64_SIGNAL_SHARED_PENDING_OFFSET,offsetof (struct signal_struct, shared_pending));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_PT_REGS_B6_OFFSET, offsetof (struct pt_regs, b6));
|
||||
DEFINE(IA64_PT_REGS_B7_OFFSET, offsetof (struct pt_regs, b7));
|
||||
DEFINE(IA64_PT_REGS_AR_CSD_OFFSET, offsetof (struct pt_regs, ar_csd));
|
||||
DEFINE(IA64_PT_REGS_AR_SSD_OFFSET, offsetof (struct pt_regs, ar_ssd));
|
||||
DEFINE(IA64_PT_REGS_R8_OFFSET, offsetof (struct pt_regs, r8));
|
||||
DEFINE(IA64_PT_REGS_R9_OFFSET, offsetof (struct pt_regs, r9));
|
||||
DEFINE(IA64_PT_REGS_R10_OFFSET, offsetof (struct pt_regs, r10));
|
||||
DEFINE(IA64_PT_REGS_R11_OFFSET, offsetof (struct pt_regs, r11));
|
||||
DEFINE(IA64_PT_REGS_CR_IPSR_OFFSET, offsetof (struct pt_regs, cr_ipsr));
|
||||
DEFINE(IA64_PT_REGS_CR_IIP_OFFSET, offsetof (struct pt_regs, cr_iip));
|
||||
DEFINE(IA64_PT_REGS_CR_IFS_OFFSET, offsetof (struct pt_regs, cr_ifs));
|
||||
DEFINE(IA64_PT_REGS_AR_UNAT_OFFSET, offsetof (struct pt_regs, ar_unat));
|
||||
DEFINE(IA64_PT_REGS_AR_PFS_OFFSET, offsetof (struct pt_regs, ar_pfs));
|
||||
DEFINE(IA64_PT_REGS_AR_RSC_OFFSET, offsetof (struct pt_regs, ar_rsc));
|
||||
DEFINE(IA64_PT_REGS_AR_RNAT_OFFSET, offsetof (struct pt_regs, ar_rnat));
|
||||
|
||||
DEFINE(IA64_PT_REGS_AR_BSPSTORE_OFFSET, offsetof (struct pt_regs, ar_bspstore));
|
||||
DEFINE(IA64_PT_REGS_PR_OFFSET, offsetof (struct pt_regs, pr));
|
||||
DEFINE(IA64_PT_REGS_B0_OFFSET, offsetof (struct pt_regs, b0));
|
||||
DEFINE(IA64_PT_REGS_LOADRS_OFFSET, offsetof (struct pt_regs, loadrs));
|
||||
DEFINE(IA64_PT_REGS_R1_OFFSET, offsetof (struct pt_regs, r1));
|
||||
DEFINE(IA64_PT_REGS_R12_OFFSET, offsetof (struct pt_regs, r12));
|
||||
DEFINE(IA64_PT_REGS_R13_OFFSET, offsetof (struct pt_regs, r13));
|
||||
DEFINE(IA64_PT_REGS_AR_FPSR_OFFSET, offsetof (struct pt_regs, ar_fpsr));
|
||||
DEFINE(IA64_PT_REGS_R15_OFFSET, offsetof (struct pt_regs, r15));
|
||||
DEFINE(IA64_PT_REGS_R14_OFFSET, offsetof (struct pt_regs, r14));
|
||||
DEFINE(IA64_PT_REGS_R2_OFFSET, offsetof (struct pt_regs, r2));
|
||||
DEFINE(IA64_PT_REGS_R3_OFFSET, offsetof (struct pt_regs, r3));
|
||||
DEFINE(IA64_PT_REGS_R16_OFFSET, offsetof (struct pt_regs, r16));
|
||||
DEFINE(IA64_PT_REGS_R17_OFFSET, offsetof (struct pt_regs, r17));
|
||||
DEFINE(IA64_PT_REGS_R18_OFFSET, offsetof (struct pt_regs, r18));
|
||||
DEFINE(IA64_PT_REGS_R19_OFFSET, offsetof (struct pt_regs, r19));
|
||||
DEFINE(IA64_PT_REGS_R20_OFFSET, offsetof (struct pt_regs, r20));
|
||||
DEFINE(IA64_PT_REGS_R21_OFFSET, offsetof (struct pt_regs, r21));
|
||||
DEFINE(IA64_PT_REGS_R22_OFFSET, offsetof (struct pt_regs, r22));
|
||||
DEFINE(IA64_PT_REGS_R23_OFFSET, offsetof (struct pt_regs, r23));
|
||||
DEFINE(IA64_PT_REGS_R24_OFFSET, offsetof (struct pt_regs, r24));
|
||||
DEFINE(IA64_PT_REGS_R25_OFFSET, offsetof (struct pt_regs, r25));
|
||||
DEFINE(IA64_PT_REGS_R26_OFFSET, offsetof (struct pt_regs, r26));
|
||||
DEFINE(IA64_PT_REGS_R27_OFFSET, offsetof (struct pt_regs, r27));
|
||||
DEFINE(IA64_PT_REGS_R28_OFFSET, offsetof (struct pt_regs, r28));
|
||||
DEFINE(IA64_PT_REGS_R29_OFFSET, offsetof (struct pt_regs, r29));
|
||||
DEFINE(IA64_PT_REGS_R30_OFFSET, offsetof (struct pt_regs, r30));
|
||||
DEFINE(IA64_PT_REGS_R31_OFFSET, offsetof (struct pt_regs, r31));
|
||||
DEFINE(IA64_PT_REGS_AR_CCV_OFFSET, offsetof (struct pt_regs, ar_ccv));
|
||||
DEFINE(IA64_PT_REGS_F6_OFFSET, offsetof (struct pt_regs, f6));
|
||||
DEFINE(IA64_PT_REGS_F7_OFFSET, offsetof (struct pt_regs, f7));
|
||||
DEFINE(IA64_PT_REGS_F8_OFFSET, offsetof (struct pt_regs, f8));
|
||||
DEFINE(IA64_PT_REGS_F9_OFFSET, offsetof (struct pt_regs, f9));
|
||||
DEFINE(IA64_PT_REGS_F10_OFFSET, offsetof (struct pt_regs, f10));
|
||||
DEFINE(IA64_PT_REGS_F11_OFFSET, offsetof (struct pt_regs, f11));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SWITCH_STACK_CALLER_UNAT_OFFSET, offsetof (struct switch_stack, caller_unat));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_FPSR_OFFSET, offsetof (struct switch_stack, ar_fpsr));
|
||||
DEFINE(IA64_SWITCH_STACK_F2_OFFSET, offsetof (struct switch_stack, f2));
|
||||
DEFINE(IA64_SWITCH_STACK_F3_OFFSET, offsetof (struct switch_stack, f3));
|
||||
DEFINE(IA64_SWITCH_STACK_F4_OFFSET, offsetof (struct switch_stack, f4));
|
||||
DEFINE(IA64_SWITCH_STACK_F5_OFFSET, offsetof (struct switch_stack, f5));
|
||||
DEFINE(IA64_SWITCH_STACK_F12_OFFSET, offsetof (struct switch_stack, f12));
|
||||
DEFINE(IA64_SWITCH_STACK_F13_OFFSET, offsetof (struct switch_stack, f13));
|
||||
DEFINE(IA64_SWITCH_STACK_F14_OFFSET, offsetof (struct switch_stack, f14));
|
||||
DEFINE(IA64_SWITCH_STACK_F15_OFFSET, offsetof (struct switch_stack, f15));
|
||||
DEFINE(IA64_SWITCH_STACK_F16_OFFSET, offsetof (struct switch_stack, f16));
|
||||
DEFINE(IA64_SWITCH_STACK_F17_OFFSET, offsetof (struct switch_stack, f17));
|
||||
DEFINE(IA64_SWITCH_STACK_F18_OFFSET, offsetof (struct switch_stack, f18));
|
||||
DEFINE(IA64_SWITCH_STACK_F19_OFFSET, offsetof (struct switch_stack, f19));
|
||||
DEFINE(IA64_SWITCH_STACK_F20_OFFSET, offsetof (struct switch_stack, f20));
|
||||
DEFINE(IA64_SWITCH_STACK_F21_OFFSET, offsetof (struct switch_stack, f21));
|
||||
DEFINE(IA64_SWITCH_STACK_F22_OFFSET, offsetof (struct switch_stack, f22));
|
||||
DEFINE(IA64_SWITCH_STACK_F23_OFFSET, offsetof (struct switch_stack, f23));
|
||||
DEFINE(IA64_SWITCH_STACK_F24_OFFSET, offsetof (struct switch_stack, f24));
|
||||
DEFINE(IA64_SWITCH_STACK_F25_OFFSET, offsetof (struct switch_stack, f25));
|
||||
DEFINE(IA64_SWITCH_STACK_F26_OFFSET, offsetof (struct switch_stack, f26));
|
||||
DEFINE(IA64_SWITCH_STACK_F27_OFFSET, offsetof (struct switch_stack, f27));
|
||||
DEFINE(IA64_SWITCH_STACK_F28_OFFSET, offsetof (struct switch_stack, f28));
|
||||
DEFINE(IA64_SWITCH_STACK_F29_OFFSET, offsetof (struct switch_stack, f29));
|
||||
DEFINE(IA64_SWITCH_STACK_F30_OFFSET, offsetof (struct switch_stack, f30));
|
||||
DEFINE(IA64_SWITCH_STACK_F31_OFFSET, offsetof (struct switch_stack, f31));
|
||||
DEFINE(IA64_SWITCH_STACK_R4_OFFSET, offsetof (struct switch_stack, r4));
|
||||
DEFINE(IA64_SWITCH_STACK_R5_OFFSET, offsetof (struct switch_stack, r5));
|
||||
DEFINE(IA64_SWITCH_STACK_R6_OFFSET, offsetof (struct switch_stack, r6));
|
||||
DEFINE(IA64_SWITCH_STACK_R7_OFFSET, offsetof (struct switch_stack, r7));
|
||||
DEFINE(IA64_SWITCH_STACK_B0_OFFSET, offsetof (struct switch_stack, b0));
|
||||
DEFINE(IA64_SWITCH_STACK_B1_OFFSET, offsetof (struct switch_stack, b1));
|
||||
DEFINE(IA64_SWITCH_STACK_B2_OFFSET, offsetof (struct switch_stack, b2));
|
||||
DEFINE(IA64_SWITCH_STACK_B3_OFFSET, offsetof (struct switch_stack, b3));
|
||||
DEFINE(IA64_SWITCH_STACK_B4_OFFSET, offsetof (struct switch_stack, b4));
|
||||
DEFINE(IA64_SWITCH_STACK_B5_OFFSET, offsetof (struct switch_stack, b5));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_PFS_OFFSET, offsetof (struct switch_stack, ar_pfs));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_LC_OFFSET, offsetof (struct switch_stack, ar_lc));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_UNAT_OFFSET, offsetof (struct switch_stack, ar_unat));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_RNAT_OFFSET, offsetof (struct switch_stack, ar_rnat));
|
||||
DEFINE(IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET, offsetof (struct switch_stack, ar_bspstore));
|
||||
DEFINE(IA64_SWITCH_STACK_PR_OFFSET, offsetof (struct switch_stack, pr));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SIGCONTEXT_IP_OFFSET, offsetof (struct sigcontext, sc_ip));
|
||||
DEFINE(IA64_SIGCONTEXT_AR_BSP_OFFSET, offsetof (struct sigcontext, sc_ar_bsp));
|
||||
DEFINE(IA64_SIGCONTEXT_AR_FPSR_OFFSET, offsetof (struct sigcontext, sc_ar_fpsr));
|
||||
DEFINE(IA64_SIGCONTEXT_AR_RNAT_OFFSET, offsetof (struct sigcontext, sc_ar_rnat));
|
||||
DEFINE(IA64_SIGCONTEXT_AR_UNAT_OFFSET, offsetof (struct sigcontext, sc_ar_unat));
|
||||
DEFINE(IA64_SIGCONTEXT_B0_OFFSET, offsetof (struct sigcontext, sc_br[0]));
|
||||
DEFINE(IA64_SIGCONTEXT_CFM_OFFSET, offsetof (struct sigcontext, sc_cfm));
|
||||
DEFINE(IA64_SIGCONTEXT_FLAGS_OFFSET, offsetof (struct sigcontext, sc_flags));
|
||||
DEFINE(IA64_SIGCONTEXT_FR6_OFFSET, offsetof (struct sigcontext, sc_fr[6]));
|
||||
DEFINE(IA64_SIGCONTEXT_PR_OFFSET, offsetof (struct sigcontext, sc_pr));
|
||||
DEFINE(IA64_SIGCONTEXT_R12_OFFSET, offsetof (struct sigcontext, sc_gr[12]));
|
||||
DEFINE(IA64_SIGCONTEXT_RBS_BASE_OFFSET,offsetof (struct sigcontext, sc_rbs_base));
|
||||
DEFINE(IA64_SIGCONTEXT_LOADRS_OFFSET, offsetof (struct sigcontext, sc_loadrs));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SIGPENDING_SIGNAL_OFFSET, offsetof (struct sigpending, signal));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_SIGFRAME_ARG0_OFFSET, offsetof (struct sigframe, arg0));
|
||||
DEFINE(IA64_SIGFRAME_ARG1_OFFSET, offsetof (struct sigframe, arg1));
|
||||
DEFINE(IA64_SIGFRAME_ARG2_OFFSET, offsetof (struct sigframe, arg2));
|
||||
DEFINE(IA64_SIGFRAME_HANDLER_OFFSET, offsetof (struct sigframe, handler));
|
||||
DEFINE(IA64_SIGFRAME_SIGCONTEXT_OFFSET, offsetof (struct sigframe, sc));
|
||||
BLANK();
|
||||
/* for assembly files which can't include sched.h: */
|
||||
DEFINE(IA64_CLONE_VFORK, CLONE_VFORK);
|
||||
DEFINE(IA64_CLONE_VM, CLONE_VM);
|
||||
|
||||
BLANK();
|
||||
DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET,
|
||||
offsetof (struct cpuinfo_ia64, nsec_per_cyc));
|
||||
DEFINE(IA64_CPUINFO_PTCE_BASE_OFFSET,
|
||||
offsetof (struct cpuinfo_ia64, ptce_base));
|
||||
DEFINE(IA64_CPUINFO_PTCE_COUNT_OFFSET,
|
||||
offsetof (struct cpuinfo_ia64, ptce_count));
|
||||
DEFINE(IA64_CPUINFO_PTCE_STRIDE_OFFSET,
|
||||
offsetof (struct cpuinfo_ia64, ptce_stride));
|
||||
BLANK();
|
||||
DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET,
|
||||
offsetof (struct timespec, tv_nsec));
|
||||
|
||||
DEFINE(CLONE_SETTLS_BIT, 19);
|
||||
#if CLONE_SETTLS != (1<<19)
|
||||
# error "CLONE_SETTLS_BIT incorrect, please fix"
|
||||
#endif
|
||||
|
||||
BLANK();
|
||||
DEFINE(IA64_MCA_CPU_MCA_STACK_OFFSET,
|
||||
offsetof (struct ia64_mca_cpu, mca_stack));
|
||||
DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET,
|
||||
offsetof (struct ia64_mca_cpu, init_stack));
|
||||
BLANK();
|
||||
DEFINE(IA64_SAL_OS_STATE_OS_GP_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, os_gp));
|
||||
DEFINE(IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, proc_state_param));
|
||||
DEFINE(IA64_SAL_OS_STATE_SAL_RA_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, sal_ra));
|
||||
DEFINE(IA64_SAL_OS_STATE_SAL_GP_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, sal_gp));
|
||||
DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, pal_min_state));
|
||||
DEFINE(IA64_SAL_OS_STATE_OS_STATUS_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, os_status));
|
||||
DEFINE(IA64_SAL_OS_STATE_CONTEXT_OFFSET,
|
||||
offsetof (struct ia64_sal_os_state, context));
|
||||
DEFINE(IA64_SAL_OS_STATE_SIZE,
|
||||
sizeof (struct ia64_sal_os_state));
|
||||
BLANK();
|
||||
|
||||
DEFINE(IA64_PMSA_GR_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_gr));
|
||||
DEFINE(IA64_PMSA_BANK1_GR_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_bank1_gr));
|
||||
DEFINE(IA64_PMSA_PR_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_pr));
|
||||
DEFINE(IA64_PMSA_BR0_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_br0));
|
||||
DEFINE(IA64_PMSA_RSC_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_rsc));
|
||||
DEFINE(IA64_PMSA_IIP_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_iip));
|
||||
DEFINE(IA64_PMSA_IPSR_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_ipsr));
|
||||
DEFINE(IA64_PMSA_IFS_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_ifs));
|
||||
DEFINE(IA64_PMSA_XIP_OFFSET,
|
||||
offsetof (struct pal_min_state_area_s, pmsa_xip));
|
||||
BLANK();
|
||||
|
||||
/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter));
|
||||
DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask));
|
||||
DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU);
|
||||
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 */
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,925 +0,0 @@
|
||||
/*
|
||||
* This file contains the light-weight system call handlers (fsyscall-handlers).
|
||||
*
|
||||
* Copyright (C) 2003 Hewlett-Packard Co
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
*
|
||||
* 25-Sep-03 davidm Implement fsys_rt_sigprocmask().
|
||||
* 18-Feb-03 louisk Implement fsys_gettimeofday().
|
||||
* 28-Feb-03 davidm Fixed several bugs in fsys_gettimeofday(). Tuned it some more,
|
||||
* probably broke it along the way... ;-)
|
||||
* 13-Jul-04 clameter Implement fsys_clock_gettime and revise fsys_gettimeofday to make
|
||||
* it capable of using memory based clocks without falling back to C code.
|
||||
*/
|
||||
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/sal.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include "entry.h"
|
||||
|
||||
/*
|
||||
* See Documentation/ia64/fsys.txt for details on fsyscalls.
|
||||
*
|
||||
* On entry to an fsyscall handler:
|
||||
* r10 = 0 (i.e., defaults to "successful syscall return")
|
||||
* r11 = saved ar.pfs (a user-level value)
|
||||
* r15 = system call number
|
||||
* r16 = "current" task pointer (in normal kernel-mode, this is in r13)
|
||||
* r32-r39 = system call arguments
|
||||
* b6 = return address (a user-level value)
|
||||
* ar.pfs = previous frame-state (a user-level value)
|
||||
* PSR.be = cleared to zero (i.e., little-endian byte order is in effect)
|
||||
* all other registers may contain values passed in from user-mode
|
||||
*
|
||||
* On return from an fsyscall handler:
|
||||
* r11 = saved ar.pfs (as passed into the fsyscall handler)
|
||||
* r15 = system call number (as passed into the fsyscall handler)
|
||||
* r32-r39 = system call arguments (as passed into the fsyscall handler)
|
||||
* b6 = return address (as passed into the fsyscall handler)
|
||||
* ar.pfs = previous frame-state (as passed into the fsyscall handler)
|
||||
*/
|
||||
|
||||
ENTRY(fsys_ni_syscall)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
mov r8=ENOSYS
|
||||
mov r10=-1
|
||||
FSYS_RETURN
|
||||
END(fsys_ni_syscall)
|
||||
|
||||
ENTRY(fsys_getpid)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
;;
|
||||
ld4 r9=[r9]
|
||||
add r8=IA64_TASK_TGID_OFFSET,r16
|
||||
;;
|
||||
and r9=TIF_ALLWORK_MASK,r9
|
||||
ld4 r8=[r8] // r8 = current->tgid
|
||||
;;
|
||||
cmp.ne p8,p0=0,r9
|
||||
(p8) br.spnt.many fsys_fallback_syscall
|
||||
FSYS_RETURN
|
||||
END(fsys_getpid)
|
||||
|
||||
ENTRY(fsys_getppid)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16
|
||||
;;
|
||||
ld8 r17=[r17] // r17 = current->group_leader
|
||||
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
;;
|
||||
|
||||
ld4 r9=[r9]
|
||||
add r17=IA64_TASK_REAL_PARENT_OFFSET,r17 // r17 = ¤t->group_leader->real_parent
|
||||
;;
|
||||
and r9=TIF_ALLWORK_MASK,r9
|
||||
|
||||
1: ld8 r18=[r17] // r18 = current->group_leader->real_parent
|
||||
;;
|
||||
cmp.ne p8,p0=0,r9
|
||||
add r8=IA64_TASK_TGID_OFFSET,r18 // r8 = ¤t->group_leader->real_parent->tgid
|
||||
;;
|
||||
|
||||
/*
|
||||
* The .acq is needed to ensure that the read of tgid has returned its data before
|
||||
* we re-check "real_parent".
|
||||
*/
|
||||
ld4.acq r8=[r8] // r8 = current->group_leader->real_parent->tgid
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Re-read current->group_leader->real_parent.
|
||||
*/
|
||||
ld8 r19=[r17] // r19 = current->group_leader->real_parent
|
||||
(p8) br.spnt.many fsys_fallback_syscall
|
||||
;;
|
||||
cmp.ne p6,p0=r18,r19 // did real_parent change?
|
||||
mov r19=0 // i must not leak kernel bits...
|
||||
(p6) br.cond.spnt.few 1b // yes -> redo the read of tgid and the check
|
||||
;;
|
||||
mov r17=0 // i must not leak kernel bits...
|
||||
mov r18=0 // i must not leak kernel bits...
|
||||
#else
|
||||
mov r17=0 // i must not leak kernel bits...
|
||||
mov r18=0 // i must not leak kernel bits...
|
||||
mov r19=0 // i must not leak kernel bits...
|
||||
#endif
|
||||
FSYS_RETURN
|
||||
END(fsys_getppid)
|
||||
|
||||
ENTRY(fsys_set_tid_address)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
;;
|
||||
ld4 r9=[r9]
|
||||
tnat.z p6,p7=r32 // check argument register for being NaT
|
||||
;;
|
||||
and r9=TIF_ALLWORK_MASK,r9
|
||||
add r8=IA64_TASK_PID_OFFSET,r16
|
||||
add r18=IA64_TASK_CLEAR_CHILD_TID_OFFSET,r16
|
||||
;;
|
||||
ld4 r8=[r8]
|
||||
cmp.ne p8,p0=0,r9
|
||||
mov r17=-1
|
||||
;;
|
||||
(p6) st8 [r18]=r32
|
||||
(p7) st8 [r18]=r17
|
||||
(p8) br.spnt.many fsys_fallback_syscall
|
||||
;;
|
||||
mov r17=0 // i must not leak kernel bits...
|
||||
mov r18=0 // i must not leak kernel bits...
|
||||
FSYS_RETURN
|
||||
END(fsys_set_tid_address)
|
||||
|
||||
/*
|
||||
* Ensure that the time interpolator structure is compatible with the asm code
|
||||
*/
|
||||
#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \
|
||||
|| IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4
|
||||
#error fsys_gettimeofday incompatible with changes to struct time_interpolator
|
||||
#endif
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#define CLOCK_DIVIDE_BY_1000 0x4000
|
||||
#define CLOCK_ADD_MONOTONIC 0x8000
|
||||
|
||||
ENTRY(fsys_gettimeofday)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
mov r31 = r32
|
||||
tnat.nz p6,p0 = r33 // guard against NaT argument
|
||||
(p6) br.cond.spnt.few .fail_einval
|
||||
mov r30 = CLOCK_DIVIDE_BY_1000
|
||||
;;
|
||||
.gettime:
|
||||
// Register map
|
||||
// Incoming r31 = pointer to address where to place result
|
||||
// r30 = flags determining how time is processed
|
||||
// r2,r3 = temp r4-r7 preserved
|
||||
// r8 = result nanoseconds
|
||||
// r9 = result seconds
|
||||
// r10 = temporary storage for clock difference
|
||||
// r11 = preserved: saved ar.pfs
|
||||
// r12 = preserved: memory stack
|
||||
// r13 = preserved: thread pointer
|
||||
// r14 = address of mask / mask
|
||||
// r15 = preserved: system call number
|
||||
// r16 = preserved: current task pointer
|
||||
// r17 = wall to monotonic use
|
||||
// r18 = time_interpolator->offset
|
||||
// r19 = address of wall_to_monotonic
|
||||
// r20 = pointer to struct time_interpolator / pointer to time_interpolator->address
|
||||
// r21 = shift factor
|
||||
// r22 = address of time interpolator->last_counter
|
||||
// r23 = address of time_interpolator->last_cycle
|
||||
// r24 = adress of time_interpolator->offset
|
||||
// r25 = last_cycle value
|
||||
// r26 = last_counter value
|
||||
// r27 = pointer to xtime
|
||||
// r28 = sequence number at the beginning of critcal section
|
||||
// r29 = address of seqlock
|
||||
// r30 = time processing flags / memory address
|
||||
// r31 = pointer to result
|
||||
// Predicates
|
||||
// p6,p7 short term use
|
||||
// p8 = timesource ar.itc
|
||||
// p9 = timesource mmio64
|
||||
// p10 = timesource mmio32
|
||||
// p11 = timesource not to be handled by asm code
|
||||
// p12 = memory time source ( = p9 | p10)
|
||||
// p13 = do cmpxchg with time_interpolator_last_cycle
|
||||
// p14 = Divide by 1000
|
||||
// p15 = Add monotonic
|
||||
//
|
||||
// Note that instructions are optimized for McKinley. McKinley can process two
|
||||
// bundles simultaneously and therefore we continuously try to feed the CPU
|
||||
// two bundles and then a stop.
|
||||
tnat.nz p6,p0 = r31 // branch deferred since it does not fit into bundle structure
|
||||
mov pr = r30,0xc000 // Set predicates according to function
|
||||
add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
movl r20 = time_interpolator
|
||||
;;
|
||||
ld8 r20 = [r20] // get pointer to time_interpolator structure
|
||||
movl r29 = xtime_lock
|
||||
ld4 r2 = [r2] // process work pending flags
|
||||
movl r27 = xtime
|
||||
;; // only one bundle here
|
||||
ld8 r21 = [r20] // first quad with control information
|
||||
and r2 = TIF_ALLWORK_MASK,r2
|
||||
(p6) br.cond.spnt.few .fail_einval // deferred branch
|
||||
;;
|
||||
add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20
|
||||
extr r3 = r21,32,32 // time_interpolator->nsec_per_cyc
|
||||
extr r8 = r21,0,16 // time_interpolator->source
|
||||
cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled
|
||||
(p6) br.cond.spnt.many fsys_fallback_syscall
|
||||
;;
|
||||
cmp.eq p8,p12 = 0,r8 // Check for cpu timer
|
||||
cmp.eq p9,p0 = 1,r8 // MMIO64 ?
|
||||
extr r2 = r21,24,8 // time_interpolator->jitter
|
||||
cmp.eq p10,p0 = 2,r8 // MMIO32 ?
|
||||
cmp.ltu p11,p0 = 2,r8 // function or other clock
|
||||
(p11) br.cond.spnt.many fsys_fallback_syscall
|
||||
;;
|
||||
setf.sig f7 = r3 // Setup for scaling of counter
|
||||
(p15) movl r19 = wall_to_monotonic
|
||||
(p12) ld8 r30 = [r10]
|
||||
cmp.ne p13,p0 = r2,r0 // need jitter compensation?
|
||||
extr r21 = r21,16,8 // shift factor
|
||||
;;
|
||||
.time_redo:
|
||||
.pred.rel.mutex p8,p9,p10
|
||||
ld4.acq r28 = [r29] // xtime_lock.sequence. Must come first for locking purposes
|
||||
(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!!
|
||||
add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
|
||||
(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency issues..
|
||||
(p10) ld4 r2 = [r30] // readw(ti->address)
|
||||
(p13) add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20
|
||||
;; // could be removed by moving the last add upward
|
||||
ld8 r26 = [r22] // time_interpolator->last_counter
|
||||
(p13) ld8 r25 = [r23] // time interpolator->last_cycle
|
||||
add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20
|
||||
(p15) ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET
|
||||
ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
|
||||
add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20
|
||||
;;
|
||||
ld8 r18 = [r24] // time_interpolator->offset
|
||||
ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec
|
||||
(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
|
||||
;;
|
||||
ld8 r14 = [r14] // time_interpolator->mask
|
||||
(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
|
||||
sub r10 = r2,r26 // current_counter - last_counter
|
||||
;;
|
||||
(p6) sub r10 = r25,r26 // time we got was less than last_cycle
|
||||
(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg
|
||||
;;
|
||||
and r10 = r10,r14 // Apply mask
|
||||
;;
|
||||
setf.sig f8 = r10
|
||||
nop.i 123
|
||||
;;
|
||||
(p7) cmpxchg8.rel r3 = [r23],r2,ar.ccv
|
||||
EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time
|
||||
xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter)
|
||||
(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs
|
||||
;;
|
||||
(p15) ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
|
||||
(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo
|
||||
// simulate tbit.nz.or p7,p0 = r28,0
|
||||
and r28 = ~1,r28 // Make sequence even to force retry if odd
|
||||
getf.sig r2 = f8
|
||||
mf
|
||||
add r8 = r8,r18 // Add time interpolator offset
|
||||
;;
|
||||
ld4 r10 = [r29] // xtime_lock.sequence
|
||||
(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs
|
||||
shr.u r2 = r2,r21
|
||||
;; // overloaded 3 bundles!
|
||||
// End critical section.
|
||||
add r8 = r8,r2 // Add xtime.nsecs
|
||||
cmp4.ne.or p7,p0 = r28,r10
|
||||
(p7) br.cond.dpnt.few .time_redo // sequence number changed ?
|
||||
// Now r8=tv->tv_nsec and r9=tv->tv_sec
|
||||
mov r10 = r0
|
||||
movl r2 = 1000000000
|
||||
add r23 = IA64_TIMESPEC_TV_NSEC_OFFSET, r31
|
||||
(p14) movl r3 = 2361183241434822607 // Prep for / 1000 hack
|
||||
;;
|
||||
.time_normalize:
|
||||
mov r21 = r8
|
||||
cmp.ge p6,p0 = r8,r2
|
||||
(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting some time
|
||||
;;
|
||||
(p14) setf.sig f8 = r20
|
||||
(p6) sub r8 = r8,r2
|
||||
(p6) add r9 = 1,r9 // two nops before the branch.
|
||||
(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod
|
||||
(p6) br.cond.dpnt.few .time_normalize
|
||||
;;
|
||||
// Divided by 8 though shift. Now divide by 125
|
||||
// The compiler was able to do that with a multiply
|
||||
// and a shift and we do the same
|
||||
EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
|
||||
(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it...
|
||||
;;
|
||||
mov r8 = r0
|
||||
(p14) getf.sig r2 = f8
|
||||
;;
|
||||
(p14) shr.u r21 = r2, 4
|
||||
;;
|
||||
EX(.fail_efault, st8 [r31] = r9)
|
||||
EX(.fail_efault, st8 [r23] = r21)
|
||||
FSYS_RETURN
|
||||
.fail_einval:
|
||||
mov r8 = EINVAL
|
||||
mov r10 = -1
|
||||
FSYS_RETURN
|
||||
.fail_efault:
|
||||
mov r8 = EFAULT
|
||||
mov r10 = -1
|
||||
FSYS_RETURN
|
||||
END(fsys_gettimeofday)
|
||||
|
||||
ENTRY(fsys_clock_gettime)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
cmp4.ltu p6, p0 = CLOCK_MONOTONIC, r32
|
||||
// Fallback if this is not CLOCK_REALTIME or CLOCK_MONOTONIC
|
||||
(p6) br.spnt.few fsys_fallback_syscall
|
||||
mov r31 = r33
|
||||
shl r30 = r32,15
|
||||
br.many .gettime
|
||||
END(fsys_clock_gettime)
|
||||
|
||||
/*
|
||||
* long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
|
||||
*/
|
||||
#if _NSIG_WORDS != 1
|
||||
# error Sorry, fsys_rt_sigprocmask() needs to be updated for _NSIG_WORDS != 1.
|
||||
#endif
|
||||
ENTRY(fsys_rt_sigprocmask)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
|
||||
add r2=IA64_TASK_BLOCKED_OFFSET,r16
|
||||
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
cmp4.ltu p6,p0=SIG_SETMASK,r32
|
||||
|
||||
cmp.ne p15,p0=r0,r34 // oset != NULL?
|
||||
tnat.nz p8,p0=r34
|
||||
add r31=IA64_TASK_SIGHAND_OFFSET,r16
|
||||
;;
|
||||
ld8 r3=[r2] // read/prefetch current->blocked
|
||||
ld4 r9=[r9]
|
||||
tnat.nz.or p6,p0=r35
|
||||
|
||||
cmp.ne.or p6,p0=_NSIG_WORDS*8,r35
|
||||
tnat.nz.or p6,p0=r32
|
||||
(p6) br.spnt.few .fail_einval // fail with EINVAL
|
||||
;;
|
||||
#ifdef CONFIG_SMP
|
||||
ld8 r31=[r31] // r31 <- current->sighand
|
||||
#endif
|
||||
and r9=TIF_ALLWORK_MASK,r9
|
||||
tnat.nz.or p8,p0=r33
|
||||
;;
|
||||
cmp.ne p7,p0=0,r9
|
||||
cmp.eq p6,p0=r0,r33 // set == NULL?
|
||||
add r31=IA64_SIGHAND_SIGLOCK_OFFSET,r31 // r31 <- current->sighand->siglock
|
||||
(p8) br.spnt.few .fail_efault // fail with EFAULT
|
||||
(p7) br.spnt.many fsys_fallback_syscall // got pending kernel work...
|
||||
(p6) br.dpnt.many .store_mask // -> short-circuit to just reading the signal mask
|
||||
|
||||
/* Argh, we actually have to do some work and _update_ the signal mask: */
|
||||
|
||||
EX(.fail_efault, probe.r.fault r33, 3) // verify user has read-access to *set
|
||||
EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set
|
||||
mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
|
||||
;;
|
||||
|
||||
rsm psr.i // mask interrupt delivery
|
||||
mov ar.ccv=0
|
||||
andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
mov r17=1
|
||||
;;
|
||||
cmpxchg4.acq r18=[r31],r17,ar.ccv // try to acquire the lock
|
||||
mov r8=EINVAL // default to EINVAL
|
||||
;;
|
||||
ld8 r3=[r2] // re-read current->blocked now that we hold the lock
|
||||
cmp4.ne p6,p0=r18,r0
|
||||
(p6) br.cond.spnt.many .lock_contention
|
||||
;;
|
||||
#else
|
||||
ld8 r3=[r2] // re-read current->blocked now that we hold the lock
|
||||
mov r8=EINVAL // default to EINVAL
|
||||
#endif
|
||||
add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
|
||||
add r19=IA64_TASK_SIGNAL_OFFSET,r16
|
||||
cmp4.eq p6,p0=SIG_BLOCK,r32
|
||||
;;
|
||||
ld8 r19=[r19] // r19 <- current->signal
|
||||
cmp4.eq p7,p0=SIG_UNBLOCK,r32
|
||||
cmp4.eq p8,p0=SIG_SETMASK,r32
|
||||
;;
|
||||
ld8 r18=[r18] // r18 <- current->pending.signal
|
||||
.pred.rel.mutex p6,p7,p8
|
||||
(p6) or r14=r3,r14 // SIG_BLOCK
|
||||
(p7) andcm r14=r3,r14 // SIG_UNBLOCK
|
||||
|
||||
(p8) mov r14=r14 // SIG_SETMASK
|
||||
(p6) mov r8=0 // clear error code
|
||||
// recalc_sigpending()
|
||||
add r17=IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,r19
|
||||
|
||||
add r19=IA64_SIGNAL_SHARED_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r19
|
||||
;;
|
||||
ld4 r17=[r17] // r17 <- current->signal->group_stop_count
|
||||
(p7) mov r8=0 // clear error code
|
||||
|
||||
ld8 r19=[r19] // r19 <- current->signal->shared_pending
|
||||
;;
|
||||
cmp4.gt p6,p7=r17,r0 // p6/p7 <- (current->signal->group_stop_count > 0)?
|
||||
(p8) mov r8=0 // clear error code
|
||||
|
||||
or r18=r18,r19 // r18 <- current->pending | current->signal->shared_pending
|
||||
;;
|
||||
// r18 <- (current->pending | current->signal->shared_pending) & ~current->blocked:
|
||||
andcm r18=r18,r14
|
||||
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
|
||||
;;
|
||||
|
||||
(p7) cmp.ne.or.andcm p6,p7=r18,r0 // p6/p7 <- signal pending
|
||||
mov r19=0 // i must not leak kernel bits...
|
||||
(p6) br.cond.dpnt.many .sig_pending
|
||||
;;
|
||||
|
||||
1: ld4 r17=[r9] // r17 <- current->thread_info->flags
|
||||
;;
|
||||
mov ar.ccv=r17
|
||||
and r18=~_TIF_SIGPENDING,r17 // r18 <- r17 & ~(1 << TIF_SIGPENDING)
|
||||
;;
|
||||
|
||||
st8 [r2]=r14 // update current->blocked with new mask
|
||||
cmpxchg4.acq r8=[r9],r18,ar.ccv // current->thread_info->flags <- r18
|
||||
;;
|
||||
cmp.ne p6,p0=r17,r8 // update failed?
|
||||
(p6) br.cond.spnt.few 1b // yes -> retry
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
st4.rel [r31]=r0 // release the lock
|
||||
#endif
|
||||
ssm psr.i
|
||||
;;
|
||||
|
||||
srlz.d // ensure psr.i is set again
|
||||
mov r18=0 // i must not leak kernel bits...
|
||||
|
||||
.store_mask:
|
||||
EX(.fail_efault, (p15) probe.w.fault r34, 3) // verify user has write-access to *oset
|
||||
EX(.fail_efault, (p15) st8 [r34]=r3)
|
||||
mov r2=0 // i must not leak kernel bits...
|
||||
mov r3=0 // i must not leak kernel bits...
|
||||
mov r8=0 // return 0
|
||||
mov r9=0 // i must not leak kernel bits...
|
||||
mov r14=0 // i must not leak kernel bits...
|
||||
mov r17=0 // i must not leak kernel bits...
|
||||
mov r31=0 // i must not leak kernel bits...
|
||||
FSYS_RETURN
|
||||
|
||||
.sig_pending:
|
||||
#ifdef CONFIG_SMP
|
||||
st4.rel [r31]=r0 // release the lock
|
||||
#endif
|
||||
ssm psr.i
|
||||
;;
|
||||
srlz.d
|
||||
br.sptk.many fsys_fallback_syscall // with signal pending, do the heavy-weight syscall
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
.lock_contention:
|
||||
/* Rather than spinning here, fall back on doing a heavy-weight syscall. */
|
||||
ssm psr.i
|
||||
;;
|
||||
srlz.d
|
||||
br.sptk.many fsys_fallback_syscall
|
||||
#endif
|
||||
END(fsys_rt_sigprocmask)
|
||||
|
||||
ENTRY(fsys_fallback_syscall)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
/*
|
||||
* We only get here from light-weight syscall handlers. Thus, we already
|
||||
* know that r15 contains a valid syscall number. No need to re-check.
|
||||
*/
|
||||
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
|
||||
END(fsys_fallback_syscall)
|
||||
/* FALL THROUGH */
|
||||
GLOBAL_ENTRY(fsys_bubble_down)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
/*
|
||||
* We get here for syscalls that don't have a lightweight
|
||||
* handler. For those, we need to bubble down into the kernel
|
||||
* and that requires setting up a minimal pt_regs structure,
|
||||
* and initializing the CPU state more or less as if an
|
||||
* interruption had occurred. To make syscall-restarts work,
|
||||
* we setup pt_regs such that cr_iip points to the second
|
||||
* instruction in syscall_via_break. Decrementing the IP
|
||||
* hence will restart the syscall via break and not
|
||||
* decrementing IP will return us to the caller, as usual.
|
||||
* Note that we preserve the value of psr.pp rather than
|
||||
* initializing it from dcr.pp. This makes it possible to
|
||||
* distinguish fsyscall execution from other privileged
|
||||
* execution.
|
||||
*
|
||||
* On entry:
|
||||
* - normal fsyscall handler register usage, except
|
||||
* that we also have:
|
||||
* - r18: address of syscall entry point
|
||||
* - r21: ar.fpsr
|
||||
* - r26: ar.pfs
|
||||
* - r27: ar.rsc
|
||||
* - r29: psr
|
||||
*
|
||||
* We used to clear some PSR bits here but that requires slow
|
||||
* serialization. Fortuntely, that isn't really necessary.
|
||||
* The rationale is as follows: we used to clear bits
|
||||
* ~PSR_PRESERVED_BITS in PSR.L. Since
|
||||
* PSR_PRESERVED_BITS==PSR.{UP,MFL,MFH,PK,DT,PP,SP,RT,IC}, we
|
||||
* ended up clearing PSR.{BE,AC,I,DFL,DFH,DI,DB,SI,TB}.
|
||||
* However,
|
||||
*
|
||||
* PSR.BE : already is turned off in __kernel_syscall_via_epc()
|
||||
* PSR.AC : don't care (kernel normally turns PSR.AC on)
|
||||
* PSR.I : already turned off by the time fsys_bubble_down gets
|
||||
* invoked
|
||||
* PSR.DFL: always 0 (kernel never turns it on)
|
||||
* PSR.DFH: don't care --- kernel never touches f32-f127 on its own
|
||||
* initiative
|
||||
* PSR.DI : always 0 (kernel never turns it on)
|
||||
* PSR.SI : always 0 (kernel never turns it on)
|
||||
* PSR.DB : don't care --- kernel never enables kernel-level
|
||||
* breakpoints
|
||||
* PSR.TB : must be 0 already; if it wasn't zero on entry to
|
||||
* __kernel_syscall_via_epc, the branch to fsys_bubble_down
|
||||
* will trigger a taken branch; the taken-trap-handler then
|
||||
* converts the syscall into a break-based system-call.
|
||||
*/
|
||||
/*
|
||||
* Reading psr.l gives us only bits 0-31, psr.it, and psr.mc.
|
||||
* The rest we have to synthesize.
|
||||
*/
|
||||
# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) \
|
||||
| (0x1 << IA64_PSR_RI_BIT) \
|
||||
| IA64_PSR_BN | IA64_PSR_I)
|
||||
|
||||
invala // M0|1
|
||||
movl r14=ia64_ret_from_syscall // X
|
||||
|
||||
nop.m 0
|
||||
movl r28=__kernel_syscall_via_break // X create cr.iip
|
||||
;;
|
||||
|
||||
mov r2=r16 // A get task addr to addl-addressable register
|
||||
adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // A
|
||||
mov r31=pr // I0 save pr (2 cyc)
|
||||
;;
|
||||
st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag
|
||||
addl r22=IA64_RBS_OFFSET,r2 // A compute base of RBS
|
||||
add r3=TI_FLAGS+IA64_TASK_SIZE,r2 // A
|
||||
;;
|
||||
ld4 r3=[r3] // M0|1 r3 = current_thread_info()->flags
|
||||
lfetch.fault.excl.nt1 [r22] // M0|1 prefetch register backing-store
|
||||
nop.i 0
|
||||
;;
|
||||
mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0
|
||||
nop.m 0
|
||||
nop.i 0
|
||||
;;
|
||||
mov r23=ar.bspstore // M2 (12 cyc) save ar.bspstore
|
||||
mov.m r24=ar.rnat // M2 (5 cyc) read ar.rnat (dual-issues!)
|
||||
nop.i 0
|
||||
;;
|
||||
mov ar.bspstore=r22 // M2 (6 cyc) switch to kernel RBS
|
||||
movl r8=PSR_ONE_BITS // X
|
||||
;;
|
||||
mov r25=ar.unat // M2 (5 cyc) save ar.unat
|
||||
mov r19=b6 // I0 save b6 (2 cyc)
|
||||
mov r20=r1 // A save caller's gp in r20
|
||||
;;
|
||||
or r29=r8,r29 // A construct cr.ipsr value to save
|
||||
mov b6=r18 // I0 copy syscall entry-point to b6 (7 cyc)
|
||||
addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // A compute base of memory stack
|
||||
|
||||
mov r18=ar.bsp // M2 save (kernel) ar.bsp (12 cyc)
|
||||
cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1
|
||||
br.call.sptk.many b7=ia64_syscall_setup // B
|
||||
;;
|
||||
mov ar.rsc=0x3 // M2 set eager mode, pl 0, LE, loadrs=0
|
||||
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
|
||||
|
||||
nop.m 0
|
||||
(p8) br.call.sptk.many b6=b6 // B (ignore return address)
|
||||
br.cond.spnt ia64_trace_syscall // B
|
||||
END(fsys_bubble_down)
|
||||
|
||||
.rodata
|
||||
.align 8
|
||||
.globl fsyscall_table
|
||||
|
||||
data8 fsys_bubble_down
|
||||
fsyscall_table:
|
||||
data8 fsys_ni_syscall
|
||||
data8 0 // exit // 1025
|
||||
data8 0 // read
|
||||
data8 0 // write
|
||||
data8 0 // open
|
||||
data8 0 // close
|
||||
data8 0 // creat // 1030
|
||||
data8 0 // link
|
||||
data8 0 // unlink
|
||||
data8 0 // execve
|
||||
data8 0 // chdir
|
||||
data8 0 // fchdir // 1035
|
||||
data8 0 // utimes
|
||||
data8 0 // mknod
|
||||
data8 0 // chmod
|
||||
data8 0 // chown
|
||||
data8 0 // lseek // 1040
|
||||
data8 fsys_getpid // getpid
|
||||
data8 fsys_getppid // getppid
|
||||
data8 0 // mount
|
||||
data8 0 // umount
|
||||
data8 0 // setuid // 1045
|
||||
data8 0 // getuid
|
||||
data8 0 // geteuid
|
||||
data8 0 // ptrace
|
||||
data8 0 // access
|
||||
data8 0 // sync // 1050
|
||||
data8 0 // fsync
|
||||
data8 0 // fdatasync
|
||||
data8 0 // kill
|
||||
data8 0 // rename
|
||||
data8 0 // mkdir // 1055
|
||||
data8 0 // rmdir
|
||||
data8 0 // dup
|
||||
data8 0 // pipe
|
||||
data8 0 // times
|
||||
data8 0 // brk // 1060
|
||||
data8 0 // setgid
|
||||
data8 0 // getgid
|
||||
data8 0 // getegid
|
||||
data8 0 // acct
|
||||
data8 0 // ioctl // 1065
|
||||
data8 0 // fcntl
|
||||
data8 0 // umask
|
||||
data8 0 // chroot
|
||||
data8 0 // ustat
|
||||
data8 0 // dup2 // 1070
|
||||
data8 0 // setreuid
|
||||
data8 0 // setregid
|
||||
data8 0 // getresuid
|
||||
data8 0 // setresuid
|
||||
data8 0 // getresgid // 1075
|
||||
data8 0 // setresgid
|
||||
data8 0 // getgroups
|
||||
data8 0 // setgroups
|
||||
data8 0 // getpgid
|
||||
data8 0 // setpgid // 1080
|
||||
data8 0 // setsid
|
||||
data8 0 // getsid
|
||||
data8 0 // sethostname
|
||||
data8 0 // setrlimit
|
||||
data8 0 // getrlimit // 1085
|
||||
data8 0 // getrusage
|
||||
data8 fsys_gettimeofday // gettimeofday
|
||||
data8 0 // settimeofday
|
||||
data8 0 // select
|
||||
data8 0 // poll // 1090
|
||||
data8 0 // symlink
|
||||
data8 0 // readlink
|
||||
data8 0 // uselib
|
||||
data8 0 // swapon
|
||||
data8 0 // swapoff // 1095
|
||||
data8 0 // reboot
|
||||
data8 0 // truncate
|
||||
data8 0 // ftruncate
|
||||
data8 0 // fchmod
|
||||
data8 0 // fchown // 1100
|
||||
data8 0 // getpriority
|
||||
data8 0 // setpriority
|
||||
data8 0 // statfs
|
||||
data8 0 // fstatfs
|
||||
data8 0 // gettid // 1105
|
||||
data8 0 // semget
|
||||
data8 0 // semop
|
||||
data8 0 // semctl
|
||||
data8 0 // msgget
|
||||
data8 0 // msgsnd // 1110
|
||||
data8 0 // msgrcv
|
||||
data8 0 // msgctl
|
||||
data8 0 // shmget
|
||||
data8 0 // shmat
|
||||
data8 0 // shmdt // 1115
|
||||
data8 0 // shmctl
|
||||
data8 0 // syslog
|
||||
data8 0 // setitimer
|
||||
data8 0 // getitimer
|
||||
data8 0 // 1120
|
||||
data8 0
|
||||
data8 0
|
||||
data8 0 // vhangup
|
||||
data8 0 // lchown
|
||||
data8 0 // remap_file_pages // 1125
|
||||
data8 0 // wait4
|
||||
data8 0 // sysinfo
|
||||
data8 0 // clone
|
||||
data8 0 // setdomainname
|
||||
data8 0 // newuname // 1130
|
||||
data8 0 // adjtimex
|
||||
data8 0
|
||||
data8 0 // init_module
|
||||
data8 0 // delete_module
|
||||
data8 0 // 1135
|
||||
data8 0
|
||||
data8 0 // quotactl
|
||||
data8 0 // bdflush
|
||||
data8 0 // sysfs
|
||||
data8 0 // personality // 1140
|
||||
data8 0 // afs_syscall
|
||||
data8 0 // setfsuid
|
||||
data8 0 // setfsgid
|
||||
data8 0 // getdents
|
||||
data8 0 // flock // 1145
|
||||
data8 0 // readv
|
||||
data8 0 // writev
|
||||
data8 0 // pread64
|
||||
data8 0 // pwrite64
|
||||
data8 0 // sysctl // 1150
|
||||
data8 0 // mmap
|
||||
data8 0 // munmap
|
||||
data8 0 // mlock
|
||||
data8 0 // mlockall
|
||||
data8 0 // mprotect // 1155
|
||||
data8 0 // mremap
|
||||
data8 0 // msync
|
||||
data8 0 // munlock
|
||||
data8 0 // munlockall
|
||||
data8 0 // sched_getparam // 1160
|
||||
data8 0 // sched_setparam
|
||||
data8 0 // sched_getscheduler
|
||||
data8 0 // sched_setscheduler
|
||||
data8 0 // sched_yield
|
||||
data8 0 // sched_get_priority_max // 1165
|
||||
data8 0 // sched_get_priority_min
|
||||
data8 0 // sched_rr_get_interval
|
||||
data8 0 // nanosleep
|
||||
data8 0 // nfsservctl
|
||||
data8 0 // prctl // 1170
|
||||
data8 0 // getpagesize
|
||||
data8 0 // mmap2
|
||||
data8 0 // pciconfig_read
|
||||
data8 0 // pciconfig_write
|
||||
data8 0 // perfmonctl // 1175
|
||||
data8 0 // sigaltstack
|
||||
data8 0 // rt_sigaction
|
||||
data8 0 // rt_sigpending
|
||||
data8 fsys_rt_sigprocmask // rt_sigprocmask
|
||||
data8 0 // rt_sigqueueinfo // 1180
|
||||
data8 0 // rt_sigreturn
|
||||
data8 0 // rt_sigsuspend
|
||||
data8 0 // rt_sigtimedwait
|
||||
data8 0 // getcwd
|
||||
data8 0 // capget // 1185
|
||||
data8 0 // capset
|
||||
data8 0 // sendfile
|
||||
data8 0
|
||||
data8 0
|
||||
data8 0 // socket // 1190
|
||||
data8 0 // bind
|
||||
data8 0 // connect
|
||||
data8 0 // listen
|
||||
data8 0 // accept
|
||||
data8 0 // getsockname // 1195
|
||||
data8 0 // getpeername
|
||||
data8 0 // socketpair
|
||||
data8 0 // send
|
||||
data8 0 // sendto
|
||||
data8 0 // recv // 1200
|
||||
data8 0 // recvfrom
|
||||
data8 0 // shutdown
|
||||
data8 0 // setsockopt
|
||||
data8 0 // getsockopt
|
||||
data8 0 // sendmsg // 1205
|
||||
data8 0 // recvmsg
|
||||
data8 0 // pivot_root
|
||||
data8 0 // mincore
|
||||
data8 0 // madvise
|
||||
data8 0 // newstat // 1210
|
||||
data8 0 // newlstat
|
||||
data8 0 // newfstat
|
||||
data8 0 // clone2
|
||||
data8 0 // getdents64
|
||||
data8 0 // getunwind // 1215
|
||||
data8 0 // readahead
|
||||
data8 0 // setxattr
|
||||
data8 0 // lsetxattr
|
||||
data8 0 // fsetxattr
|
||||
data8 0 // getxattr // 1220
|
||||
data8 0 // lgetxattr
|
||||
data8 0 // fgetxattr
|
||||
data8 0 // listxattr
|
||||
data8 0 // llistxattr
|
||||
data8 0 // flistxattr // 1225
|
||||
data8 0 // removexattr
|
||||
data8 0 // lremovexattr
|
||||
data8 0 // fremovexattr
|
||||
data8 0 // tkill
|
||||
data8 0 // futex // 1230
|
||||
data8 0 // sched_setaffinity
|
||||
data8 0 // sched_getaffinity
|
||||
data8 fsys_set_tid_address // set_tid_address
|
||||
data8 0 // fadvise64_64
|
||||
data8 0 // tgkill // 1235
|
||||
data8 0 // exit_group
|
||||
data8 0 // lookup_dcookie
|
||||
data8 0 // io_setup
|
||||
data8 0 // io_destroy
|
||||
data8 0 // io_getevents // 1240
|
||||
data8 0 // io_submit
|
||||
data8 0 // io_cancel
|
||||
data8 0 // epoll_create
|
||||
data8 0 // epoll_ctl
|
||||
data8 0 // epoll_wait // 1245
|
||||
data8 0 // restart_syscall
|
||||
data8 0 // semtimedop
|
||||
data8 0 // timer_create
|
||||
data8 0 // timer_settime
|
||||
data8 0 // timer_gettime // 1250
|
||||
data8 0 // timer_getoverrun
|
||||
data8 0 // timer_delete
|
||||
data8 0 // clock_settime
|
||||
data8 fsys_clock_gettime // clock_gettime
|
||||
|
||||
// fill in zeros for the remaining entries
|
||||
.zero:
|
||||
.space fsyscall_table + 8*NR_syscalls - .zero, 0
|
||||
@@ -1,478 +0,0 @@
|
||||
/*
|
||||
* This file contains the code that gets mapped at the upper end of each task's text
|
||||
* region. For now, it contains the signal trampoline code only.
|
||||
*
|
||||
* Copyright (C) 1999-2003 Hewlett-Packard Co
|
||||
* 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,
|
||||
* complications with the linker (which likes to create PLT stubs for branches
|
||||
* to targets outside the shared object) and to avoid multi-phase kernel builds, we
|
||||
* simply create minimalistic "patch lists" in special ELF sections.
|
||||
*/
|
||||
.section ".data.patch.fsyscall_table", "a"
|
||||
.previous
|
||||
#define LOAD_FSYSCALL_TABLE(reg) \
|
||||
[1:] movl reg=0; \
|
||||
.xdata4 ".data.patch.fsyscall_table", 1b-.
|
||||
|
||||
.section ".data.patch.brl_fsys_bubble_down", "a"
|
||||
.previous
|
||||
#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
|
||||
.altrp b6
|
||||
.body
|
||||
/*
|
||||
* Note: for (fast) syscall restart to work, the break instruction must be
|
||||
* the first one in the bundle addressed by syscall_via_break.
|
||||
*/
|
||||
{ .mib
|
||||
break 0x100000
|
||||
nop.i 0
|
||||
br.ret.sptk.many b6
|
||||
}
|
||||
END(__kernel_syscall_via_break)
|
||||
|
||||
/*
|
||||
* On entry:
|
||||
* r11 = saved ar.pfs
|
||||
* r15 = system call #
|
||||
* b0 = saved return address
|
||||
* b6 = return address
|
||||
* On exit:
|
||||
* r11 = saved ar.pfs
|
||||
* r15 = system call #
|
||||
* b0 = saved return address
|
||||
* all other "scratch" registers: undefined
|
||||
* all "preserved" registers: same as on entry
|
||||
*/
|
||||
|
||||
GLOBAL_ENTRY(__kernel_syscall_via_epc)
|
||||
.prologue
|
||||
.altrp b6
|
||||
.body
|
||||
{
|
||||
/*
|
||||
* Note: the kernel cannot assume that the first two instructions in this
|
||||
* bundle get executed. The remaining code must be safe even if
|
||||
* they do not get executed.
|
||||
*/
|
||||
adds r17=-1024,r15 // A
|
||||
mov r10=0 // A default to successful syscall execution
|
||||
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)
|
||||
shladd r18=r17,3,r14 // A
|
||||
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)?
|
||||
;;
|
||||
mov r21=ar.fpsr // M2 (12 cyc)
|
||||
tnat.nz p10,p9=r15 // I0
|
||||
mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...)
|
||||
;;
|
||||
srlz.d // M0 (forces split-issue) ensure PSR.BE==0
|
||||
(p6) ld8 r18=[r18] // M0|1
|
||||
nop.i 0
|
||||
;;
|
||||
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
|
||||
|
||||
mov r27=ar.rsc // M2 (12 cyc)
|
||||
/*
|
||||
* brl.cond doesn't work as intended because the linker would convert this branch
|
||||
* into a branch to a PLT. Perhaps there will be a way to avoid this with some
|
||||
* future version of the linker. In the meantime, we just use an indirect branch
|
||||
* instead.
|
||||
*/
|
||||
#ifdef CONFIG_ITANIUM
|
||||
(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry
|
||||
;;
|
||||
(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down
|
||||
;;
|
||||
(p6) mov b7=r14
|
||||
(p6) br.sptk.many b7
|
||||
#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)
|
||||
|
||||
# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET)
|
||||
# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET)
|
||||
# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET)
|
||||
# define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET)
|
||||
# define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET)
|
||||
|
||||
# define FLAGS_OFF IA64_SIGCONTEXT_FLAGS_OFFSET
|
||||
# define CFM_OFF IA64_SIGCONTEXT_CFM_OFFSET
|
||||
# define FR6_OFF IA64_SIGCONTEXT_FR6_OFFSET
|
||||
# define BSP_OFF IA64_SIGCONTEXT_AR_BSP_OFFSET
|
||||
# define RNAT_OFF IA64_SIGCONTEXT_AR_RNAT_OFFSET
|
||||
# define UNAT_OFF IA64_SIGCONTEXT_AR_UNAT_OFFSET
|
||||
# define FPSR_OFF IA64_SIGCONTEXT_AR_FPSR_OFFSET
|
||||
# define PR_OFF IA64_SIGCONTEXT_PR_OFFSET
|
||||
# define RP_OFF IA64_SIGCONTEXT_IP_OFFSET
|
||||
# define SP_OFF IA64_SIGCONTEXT_R12_OFFSET
|
||||
# define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET
|
||||
# define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET
|
||||
# define base0 r2
|
||||
# define base1 r3
|
||||
/*
|
||||
* When we get here, the memory stack looks like this:
|
||||
*
|
||||
* +===============================+
|
||||
* | |
|
||||
* // struct sigframe //
|
||||
* | |
|
||||
* +-------------------------------+ <-- sp+16
|
||||
* | 16 byte of scratch |
|
||||
* | space |
|
||||
* +-------------------------------+ <-- sp
|
||||
*
|
||||
* The register stack looks _exactly_ the way it looked at the time the signal
|
||||
* occurred. In other words, we're treading on a potential mine-field: each
|
||||
* incoming general register may be a NaT value (including sp, in which case the
|
||||
* process ends up dying with a SIGSEGV).
|
||||
*
|
||||
* The first thing need to do is a cover to get the registers onto the backing
|
||||
* store. Once that is done, we invoke the signal handler which may modify some
|
||||
* of the machine state. After returning from the signal handler, we return
|
||||
* control to the previous context by executing a sigreturn system call. A signal
|
||||
* handler may call the rt_sigreturn() function to directly return to a given
|
||||
* sigcontext. However, the user-level sigreturn() needs to do much more than
|
||||
* calling the rt_sigreturn() system call as it needs to unwind the stack to
|
||||
* restore preserved registers that may have been saved on the signal handler's
|
||||
* call stack.
|
||||
*/
|
||||
|
||||
#define SIGTRAMP_SAVES \
|
||||
.unwabi 3, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \
|
||||
.unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */ \
|
||||
.savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \
|
||||
.savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \
|
||||
.savesp pr, PR_OFF+SIGCONTEXT_OFF; \
|
||||
.savesp rp, RP_OFF+SIGCONTEXT_OFF; \
|
||||
.savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \
|
||||
.vframesp SP_OFF+SIGCONTEXT_OFF
|
||||
|
||||
GLOBAL_ENTRY(__kernel_sigtramp)
|
||||
// describe the state that is active when we get here:
|
||||
.prologue
|
||||
SIGTRAMP_SAVES
|
||||
.body
|
||||
|
||||
.label_state 1
|
||||
|
||||
adds base0=SIGHANDLER_OFF,sp
|
||||
adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp
|
||||
br.call.sptk.many rp=1f
|
||||
1:
|
||||
ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel
|
||||
ld8 r15=[base1] // get address of new RBS base (or NULL)
|
||||
cover // push args in interrupted frame onto backing store
|
||||
;;
|
||||
cmp.ne p1,p0=r15,r0 // do we need to switch rbs? (note: pr is saved by kernel)
|
||||
mov.m r9=ar.bsp // fetch ar.bsp
|
||||
.spillsp.p p1, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
|
||||
(p1) br.cond.spnt setup_rbs // yup -> (clobbers p8, r14-r16, and r18-r20)
|
||||
back_from_setup_rbs:
|
||||
alloc r8=ar.pfs,0,0,3,0
|
||||
ld8 out0=[base0],16 // load arg0 (signum)
|
||||
adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
|
||||
;;
|
||||
ld8 out1=[base1] // load arg1 (siginfop)
|
||||
ld8 r10=[r17],8 // get signal handler entry point
|
||||
;;
|
||||
ld8 out2=[base0] // load arg2 (sigcontextp)
|
||||
ld8 gp=[r17] // get signal handler's global pointer
|
||||
adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
.spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
|
||||
st8 [base0]=r9 // save sc_ar_bsp
|
||||
adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
|
||||
adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
stf.spill [base0]=f6,32
|
||||
stf.spill [base1]=f7,32
|
||||
;;
|
||||
stf.spill [base0]=f8,32
|
||||
stf.spill [base1]=f9,32
|
||||
mov b6=r10
|
||||
;;
|
||||
stf.spill [base0]=f10,32
|
||||
stf.spill [base1]=f11,32
|
||||
;;
|
||||
stf.spill [base0]=f12,32
|
||||
stf.spill [base1]=f13,32
|
||||
;;
|
||||
stf.spill [base0]=f14,32
|
||||
stf.spill [base1]=f15,32
|
||||
br.call.sptk.many rp=b6 // call the signal handler
|
||||
.ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
ld8 r15=[base0] // fetch sc_ar_bsp
|
||||
mov r14=ar.bsp
|
||||
;;
|
||||
cmp.ne p1,p0=r14,r15 // do we need to restore the rbs?
|
||||
(p1) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7)
|
||||
;;
|
||||
back_from_restore_rbs:
|
||||
adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
|
||||
adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
ldf.fill f6=[base0],32
|
||||
ldf.fill f7=[base1],32
|
||||
;;
|
||||
ldf.fill f8=[base0],32
|
||||
ldf.fill f9=[base1],32
|
||||
;;
|
||||
ldf.fill f10=[base0],32
|
||||
ldf.fill f11=[base1],32
|
||||
;;
|
||||
ldf.fill f12=[base0],32
|
||||
ldf.fill f13=[base1],32
|
||||
;;
|
||||
ldf.fill f14=[base0],32
|
||||
ldf.fill f15=[base1],32
|
||||
mov r15=__NR_rt_sigreturn
|
||||
.restore sp // pop .prologue
|
||||
break __BREAK_SYSCALL
|
||||
|
||||
.prologue
|
||||
SIGTRAMP_SAVES
|
||||
setup_rbs:
|
||||
mov ar.rsc=0 // put RSE into enforced lazy mode
|
||||
;;
|
||||
.save ar.rnat, r19
|
||||
mov r19=ar.rnat // save RNaT before switching backing store area
|
||||
adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp
|
||||
|
||||
mov r18=ar.bspstore
|
||||
mov ar.bspstore=r15 // switch over to new register backing store area
|
||||
;;
|
||||
|
||||
.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
|
||||
st8 [r14]=r19 // save sc_ar_rnat
|
||||
.body
|
||||
mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16
|
||||
adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
invala
|
||||
sub r15=r16,r15
|
||||
extr.u r20=r18,3,6
|
||||
;;
|
||||
mov ar.rsc=0xf // set RSE into eager mode, pl 3
|
||||
cmp.eq p8,p0=63,r20
|
||||
shl r15=r15,16
|
||||
;;
|
||||
st8 [r14]=r15 // save sc_loadrs
|
||||
(p8) st8 [r18]=r19 // if bspstore points at RNaT slot, store RNaT there now
|
||||
.restore sp // pop .prologue
|
||||
br.cond.sptk back_from_setup_rbs
|
||||
|
||||
.prologue
|
||||
SIGTRAMP_SAVES
|
||||
.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
|
||||
.body
|
||||
restore_rbs:
|
||||
// On input:
|
||||
// r14 = bsp1 (bsp at the time of return from signal handler)
|
||||
// r15 = bsp0 (bsp at the time the signal occurred)
|
||||
//
|
||||
// Here, we need to calculate bspstore0, the value that ar.bspstore needs
|
||||
// to be set to, based on bsp0 and the size of the dirty partition on
|
||||
// the alternate stack (sc_loadrs >> 16). This can be done with the
|
||||
// following algorithm:
|
||||
//
|
||||
// bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
|
||||
//
|
||||
// This is what the code below does.
|
||||
//
|
||||
alloc r2=ar.pfs,0,0,0,0 // alloc null frame
|
||||
adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
|
||||
adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
|
||||
;;
|
||||
ld8 r17=[r16]
|
||||
ld8 r16=[r18] // get new rnat
|
||||
extr.u r18=r15,3,6 // r18 <- rse_slot_num(bsp0)
|
||||
;;
|
||||
mov ar.rsc=r17 // put RSE into enforced lazy mode
|
||||
shr.u r17=r17,16
|
||||
;;
|
||||
sub r14=r14,r17 // r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
|
||||
shr.u r17=r17,3 // r17 <- (sc_loadrs >> 19)
|
||||
;;
|
||||
loadrs // restore dirty partition
|
||||
extr.u r14=r14,3,6 // r14 <- rse_slot_num(bspstore1)
|
||||
;;
|
||||
add r14=r14,r17 // r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
|
||||
;;
|
||||
shr.u r14=r14,6 // r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
|
||||
;;
|
||||
sub r14=r14,r17 // r14 <- -rse_num_regs(bspstore1, bsp1)
|
||||
movl r17=0x8208208208208209
|
||||
;;
|
||||
add r18=r18,r14 // r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
|
||||
setf.sig f7=r17
|
||||
cmp.lt p7,p0=r14,r0 // p7 <- (r14 < 0)?
|
||||
;;
|
||||
(p7) adds r18=-62,r18 // delta -= 62
|
||||
;;
|
||||
setf.sig f6=r18
|
||||
;;
|
||||
xmpy.h f6=f6,f7
|
||||
;;
|
||||
getf.sig r17=f6
|
||||
;;
|
||||
add r17=r17,r18
|
||||
shr r18=r18,63
|
||||
;;
|
||||
shr r17=r17,5
|
||||
;;
|
||||
sub r17=r17,r18 // r17 = delta/63
|
||||
;;
|
||||
add r17=r14,r17 // r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
|
||||
;;
|
||||
shladd r15=r17,3,r15 // r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
|
||||
;;
|
||||
mov ar.bspstore=r15 // switch back to old register backing store area
|
||||
;;
|
||||
mov ar.rnat=r16 // restore RNaT
|
||||
mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc)
|
||||
// invala not necessary as that will happen when returning to user-mode
|
||||
br.cond.sptk back_from_restore_rbs
|
||||
END(__kernel_sigtramp)
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Linker script for gate DSO. The gate pages are an ELF shared object prelinked to its
|
||||
* virtual address, with only one read-only segment and one execute-only segment (both fit
|
||||
* in one page). This script controls its layout.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/system.h>
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = GATE_ADDR + SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) } :readable
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.dynamic : { *(.dynamic) } :readable :dynamic
|
||||
|
||||
/*
|
||||
* This linker script is used both with -r and with -shared. For the layouts to match,
|
||||
* we need to skip more than enough space for the dynamic symbol table et al. If this
|
||||
* amount is insufficient, ld -shared will barf. Just increase it here.
|
||||
*/
|
||||
. = GATE_ADDR + 0x500;
|
||||
|
||||
.data.patch : {
|
||||
__start_gate_mckinley_e9_patchlist = .;
|
||||
*(.data.patch.mckinley_e9)
|
||||
__end_gate_mckinley_e9_patchlist = .;
|
||||
|
||||
__start_gate_vtop_patchlist = .;
|
||||
*(.data.patch.vtop)
|
||||
__end_gate_vtop_patchlist = .;
|
||||
|
||||
__start_gate_fsyscall_patchlist = .;
|
||||
*(.data.patch.fsyscall_table)
|
||||
__end_gate_fsyscall_patchlist = .;
|
||||
|
||||
__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
|
||||
#ifdef HAVE_BUGGY_SEGREL
|
||||
.text (GATE_ADDR + PAGE_SIZE) : { *(.text) *(.text.*) } :readable
|
||||
#else
|
||||
. = ALIGN (PERCPU_PAGE_SIZE) + (. & (PERCPU_PAGE_SIZE - 1));
|
||||
.text : { *(.text) *(.text.*) } :epc
|
||||
#endif
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.got.plt) *(.got)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(__ex_table)
|
||||
*(__mca_table)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We must supply the ELF program headers explicitly to get just one
|
||||
* PT_LOAD segment, and set the flags explicitly to make segments read-only.
|
||||
*/
|
||||
PHDRS
|
||||
{
|
||||
readable PT_LOAD FILEHDR PHDRS FLAGS(4); /* PF_R */
|
||||
#ifndef HAVE_BUGGY_SEGREL
|
||||
epc PT_LOAD FILEHDR PHDRS FLAGS(1); /* PF_X */
|
||||
#endif
|
||||
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
|
||||
unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */
|
||||
}
|
||||
|
||||
/*
|
||||
* This controls what symbols we export from the DSO.
|
||||
*/
|
||||
VERSION
|
||||
{
|
||||
LINUX_2.5 {
|
||||
global:
|
||||
__kernel_syscall_via_break;
|
||||
__kernel_syscall_via_epc;
|
||||
__kernel_sigtramp;
|
||||
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
||||
/* The ELF entry point can be used to set the AT_SYSINFO value. */
|
||||
ENTRY(__kernel_syscall_via_epc)
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,649 +0,0 @@
|
||||
/*
|
||||
* linux/arch/ia64/kernel/irq.c
|
||||
*
|
||||
* Copyright (C) 1998-2001 Hewlett-Packard Co
|
||||
* Stephane Eranian <eranian@hpl.hp.com>
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
*
|
||||
* 6/10/99: Updated to bring in sync with x86 version to facilitate
|
||||
* support for SMP and different interrupt controllers.
|
||||
*
|
||||
* 09/15/00 Goutham Rao <goutham.rao@intel.com> Implemented pci_irq_to_vector
|
||||
* PCI to vector allocation routine.
|
||||
* 04/14/2004 Ashok Raj <ashok.raj@intel.com>
|
||||
* Added CPU Hotplug handling for IPF.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/random.h> /* for rand_initialize_irq() */
|
||||
#include <linux/signal.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/bitops.h>
|
||||
#ifdef CONFIG_XEN
|
||||
#include <linux/cpu.h>
|
||||
#endif
|
||||
|
||||
#include <asm/delay.h>
|
||||
#include <asm/intrinsics.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#ifdef CONFIG_PERFMON
|
||||
# include <asm/perfmon.h>
|
||||
#endif
|
||||
|
||||
#define IRQ_DEBUG 0
|
||||
|
||||
/* These can be overridden in platform_irq_init */
|
||||
int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
|
||||
int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
|
||||
|
||||
/* default base addr of IPI table */
|
||||
void __iomem *ipi_base_addr = ((void __iomem *)
|
||||
(__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
|
||||
|
||||
/*
|
||||
* Legacy IRQ to IA-64 vector translation table.
|
||||
*/
|
||||
__u8 isa_irq_to_vector_map[16] = {
|
||||
/* 8259 IRQ translation, first 16 entries */
|
||||
0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
|
||||
0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21
|
||||
};
|
||||
EXPORT_SYMBOL(isa_irq_to_vector_map);
|
||||
|
||||
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
|
||||
|
||||
int
|
||||
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;
|
||||
if (vector > IA64_LAST_DEVICE_VECTOR)
|
||||
return -ENOSPC;
|
||||
if (test_and_set_bit(pos, ia64_vector_mask))
|
||||
goto again;
|
||||
return vector;
|
||||
}
|
||||
|
||||
void
|
||||
free_irq_vector (int vector)
|
||||
{
|
||||
int pos;
|
||||
|
||||
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__);
|
||||
}
|
||||
|
||||
int
|
||||
reserve_irq_vector (int vector)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (vector < IA64_FIRST_DEVICE_VECTOR ||
|
||||
vector > IA64_LAST_DEVICE_VECTOR)
|
||||
return -EINVAL;
|
||||
|
||||
pos = vector - IA64_FIRST_DEVICE_VECTOR;
|
||||
return test_and_set_bit(pos, ia64_vector_mask);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
|
||||
#else
|
||||
# define IS_RESCHEDULE(vec) (0)
|
||||
#endif
|
||||
/*
|
||||
* That's where the IVT branches when we get an external
|
||||
* interrupt. This branches to the correct hardware IRQ handler via
|
||||
* function ptr.
|
||||
*/
|
||||
void
|
||||
ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long saved_tpr;
|
||||
|
||||
#if IRQ_DEBUG
|
||||
{
|
||||
unsigned long bsp, sp;
|
||||
|
||||
/*
|
||||
* Note: if the interrupt happened while executing in
|
||||
* the context switch routine (ia64_switch_to), we may
|
||||
* get a spurious stack overflow here. This is
|
||||
* because the register and the memory stack are not
|
||||
* switched atomically.
|
||||
*/
|
||||
bsp = ia64_getreg(_IA64_REG_AR_BSP);
|
||||
sp = ia64_getreg(_IA64_REG_SP);
|
||||
|
||||
if ((sp - bsp) < 1024) {
|
||||
static unsigned char count;
|
||||
static long last_time;
|
||||
|
||||
if (jiffies - last_time > 5*HZ)
|
||||
count = 0;
|
||||
if (++count < 5) {
|
||||
last_time = jiffies;
|
||||
printk("ia64_handle_irq: DANGER: less than "
|
||||
"1KB of free stack space!!\n"
|
||||
"(bsp=0x%lx, sp=%lx)\n", bsp, sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* IRQ_DEBUG */
|
||||
|
||||
/*
|
||||
* Always set TPR to limit maximum interrupt nesting depth to
|
||||
* 16 (without this, it would be ~240, which could easily lead
|
||||
* to kernel stack overflows).
|
||||
*/
|
||||
irq_enter();
|
||||
saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
|
||||
ia64_srlz_d();
|
||||
while (vector != IA64_SPURIOUS_INT_VECTOR) {
|
||||
if (!IS_RESCHEDULE(vector)) {
|
||||
ia64_setreg(_IA64_REG_CR_TPR, vector);
|
||||
ia64_srlz_d();
|
||||
|
||||
__do_IRQ(local_vector_to_irq(vector), regs);
|
||||
|
||||
/*
|
||||
* Disable interrupts and send EOI:
|
||||
*/
|
||||
local_irq_disable();
|
||||
ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
|
||||
}
|
||||
ia64_eoi();
|
||||
vector = ia64_get_ivr();
|
||||
}
|
||||
/*
|
||||
* This must be done *after* the ia64_eoi(). For example, the keyboard softirq
|
||||
* handler needs to be able to wait for further keyboard interrupts, which can't
|
||||
* come through until ia64_eoi() has been done.
|
||||
*/
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/*
|
||||
* This function emulates a interrupt processing when a cpu is about to be
|
||||
* brought down.
|
||||
*/
|
||||
void ia64_process_pending_intr(void)
|
||||
{
|
||||
ia64_vector vector;
|
||||
unsigned long saved_tpr;
|
||||
extern unsigned int vectors_in_migration[NR_IRQS];
|
||||
|
||||
vector = ia64_get_ivr();
|
||||
|
||||
irq_enter();
|
||||
saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
|
||||
ia64_srlz_d();
|
||||
|
||||
/*
|
||||
* Perform normal interrupt style processing
|
||||
*/
|
||||
while (vector != IA64_SPURIOUS_INT_VECTOR) {
|
||||
if (!IS_RESCHEDULE(vector)) {
|
||||
ia64_setreg(_IA64_REG_CR_TPR, vector);
|
||||
ia64_srlz_d();
|
||||
|
||||
/*
|
||||
* Now try calling normal ia64_handle_irq as it would have got called
|
||||
* from a real intr handler. Try passing null for pt_regs, hopefully
|
||||
* it will work. I hope it works!.
|
||||
* Probably could shared code.
|
||||
*/
|
||||
vectors_in_migration[local_vector_to_irq(vector)]=0;
|
||||
__do_IRQ(local_vector_to_irq(vector), NULL);
|
||||
|
||||
/*
|
||||
* Disable interrupts and send EOI
|
||||
*/
|
||||
local_irq_disable();
|
||||
ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
|
||||
}
|
||||
ia64_eoi();
|
||||
vector = ia64_get_ivr();
|
||||
}
|
||||
irq_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
static struct irqaction ipi_irqaction = {
|
||||
.handler = handle_IPI,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "IPI"
|
||||
};
|
||||
#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 cpu, unsigned int vec,
|
||||
struct irqaction *action, int save)
|
||||
{
|
||||
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(smp_processor_id(),
|
||||
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_early(unsigned int cpu)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < saved_irq_cnt; i++)
|
||||
xen_register_percpu_irq(cpu, saved_percpu_irqs[i].irq,
|
||||
saved_percpu_irqs[i].action, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void xen_smp_intr_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
unsigned int cpu = smp_processor_id();
|
||||
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));
|
||||
#endif /* CONFIG_SMP */
|
||||
}
|
||||
|
||||
void
|
||||
xen_irq_init(void)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
void
|
||||
xen_platform_send_ipi(int cpu, int vector, int delivery_mode, int redirect)
|
||||
{
|
||||
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);
|
||||
|
||||
/* XXX
|
||||
* This should be in __cpu_up(cpu) in ia64 smpboot.c
|
||||
* like x86. But don't want to modify it,
|
||||
* keep it untouched.
|
||||
*/
|
||||
xen_smp_intr_init_early(cpu);
|
||||
|
||||
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 */
|
||||
|
||||
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(smp_processor_id(),
|
||||
vec, action, 1);
|
||||
#endif
|
||||
|
||||
for (irq = 0; irq < NR_IRQS; ++irq)
|
||||
if (irq_to_vector(irq) == vec) {
|
||||
desc = irq_desc + irq;
|
||||
desc->status |= IRQ_PER_CPU;
|
||||
desc->chip = &irq_type_ia64_lsapic;
|
||||
if (action)
|
||||
setup_irq(irq, action);
|
||||
}
|
||||
}
|
||||
|
||||
void __init
|
||||
init_IRQ (void)
|
||||
{
|
||||
register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
|
||||
#ifdef CONFIG_SMP
|
||||
register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
|
||||
#endif
|
||||
#ifdef CONFIG_PERFMON
|
||||
pfm_init_percpu();
|
||||
#endif
|
||||
platform_irq_init();
|
||||
#ifdef CONFIG_XEN
|
||||
if (is_running_on_xen() && !ia64_platform_is("xen"))
|
||||
xen_irq_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
|
||||
{
|
||||
void __iomem *ipi_addr;
|
||||
unsigned long ipi_data;
|
||||
unsigned long phys_cpu_id;
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
if (is_running_on_xen()) {
|
||||
xen_platform_send_ipi(cpu, vector, delivery_mode, redirect);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
phys_cpu_id = cpu_physical_id(cpu);
|
||||
#else
|
||||
phys_cpu_id = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu number is in 8bit ID and 8bit EID
|
||||
*/
|
||||
|
||||
ipi_data = (delivery_mode << 8) | (vector & 0xff);
|
||||
ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3));
|
||||
|
||||
writeq(ipi_data, ipi_addr);
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
/*
|
||||
* PAL Firmware support
|
||||
* IA-64 Processor Programmers Reference Vol 2
|
||||
*
|
||||
* Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
|
||||
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
|
||||
* Copyright (C) 1999-2001, 2003 Hewlett-Packard Co
|
||||
* David Mosberger <davidm@hpl.hp.com>
|
||||
* Stephane Eranian <eranian@hpl.hp.com>
|
||||
*
|
||||
* 05/22/2000 eranian Added support for stacked register calls
|
||||
* 05/24/2000 eranian Added support for physical mode static calls
|
||||
*/
|
||||
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
.data
|
||||
.globl pal_entry_point
|
||||
pal_entry_point:
|
||||
data8 ia64_pal_default_handler
|
||||
.text
|
||||
|
||||
/*
|
||||
* Set the PAL entry point address. This could be written in C code, but we do it here
|
||||
* to keep it all in one module (besides, it's so trivial that it's
|
||||
* not a big deal).
|
||||
*
|
||||
* in0 Address of the PAL entry point (text address, NOT a function descriptor).
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_pal_handler_init)
|
||||
alloc r3=ar.pfs,1,0,0,0
|
||||
movl r2=pal_entry_point
|
||||
;;
|
||||
st8 [r2]=in0
|
||||
br.ret.sptk.many rp
|
||||
END(ia64_pal_handler_init)
|
||||
|
||||
/*
|
||||
* Default PAL call handler. This needs to be coded in assembly because it uses
|
||||
* the static calling convention, i.e., the RSE may not be used and calls are
|
||||
* done via "br.cond" (not "br.call").
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_pal_default_handler)
|
||||
mov r8=-1
|
||||
br.cond.sptk.many rp
|
||||
END(ia64_pal_default_handler)
|
||||
|
||||
/*
|
||||
* Make a PAL call using the static calling convention.
|
||||
*
|
||||
* in0 Index of PAL service
|
||||
* in1 - in3 Remaining PAL arguments
|
||||
* in4 1 ==> clear psr.ic, 0 ==> don't clear psr.ic
|
||||
*
|
||||
*/
|
||||
GLOBAL_ENTRY(__ia64_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
|
||||
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
|
||||
mov loc3 = psr
|
||||
mov loc0 = rp
|
||||
.body
|
||||
mov r30 = in2
|
||||
|
||||
(p6) rsm psr.i | psr.ic
|
||||
mov r31 = in3
|
||||
mov b7 = loc2
|
||||
|
||||
(p7) rsm psr.i
|
||||
;;
|
||||
(p6) srlz.i
|
||||
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(__ia64_pal_call_static)
|
||||
|
||||
/*
|
||||
* Make a PAL call using the stacked registers calling convention.
|
||||
*
|
||||
* Inputs:
|
||||
* in0 Index of PAL service
|
||||
* in2 - in3 Remaning PAL arguments
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_pal_call_stacked)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
|
||||
alloc loc1 = ar.pfs,4,4,4,0
|
||||
movl loc2 = pal_entry_point
|
||||
|
||||
mov r28 = in0 // Index MUST be copied to r28
|
||||
mov out0 = in0 // AND in0 of PAL function
|
||||
mov loc0 = rp
|
||||
.body
|
||||
;;
|
||||
ld8 loc2 = [loc2] // loc2 <- entry point
|
||||
mov out1 = in1
|
||||
mov out2 = in2
|
||||
mov out3 = in3
|
||||
mov loc3 = psr
|
||||
;;
|
||||
rsm psr.i
|
||||
mov b7 = loc2
|
||||
;;
|
||||
br.call.sptk.many rp=b7 // now make the call
|
||||
.ret0: mov psr.l = loc3
|
||||
mov ar.pfs = loc1
|
||||
mov rp = loc0
|
||||
;;
|
||||
srlz.d // serialize restoration of psr.l
|
||||
br.ret.sptk.many b0
|
||||
END(ia64_pal_call_stacked)
|
||||
|
||||
/*
|
||||
* Make a physical mode PAL call using the static registers calling convention.
|
||||
*
|
||||
* Inputs:
|
||||
* in0 Index of PAL service
|
||||
* in2 - in3 Remaning PAL arguments
|
||||
*
|
||||
* PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
|
||||
* So we don't need to clear them.
|
||||
*/
|
||||
#define PAL_PSR_BITS_TO_CLEAR \
|
||||
(IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT | \
|
||||
IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
|
||||
IA64_PSR_DFL | IA64_PSR_DFH)
|
||||
|
||||
#define PAL_PSR_BITS_TO_SET \
|
||||
(IA64_PSR_BN)
|
||||
|
||||
|
||||
GLOBAL_ENTRY(ia64_pal_call_phys_static)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
|
||||
alloc loc1 = ar.pfs,4,7,0,0
|
||||
movl loc2 = pal_entry_point
|
||||
1: {
|
||||
mov r28 = in0 // copy procedure index
|
||||
mov r8 = ip // save ip to compute branch
|
||||
mov loc0 = rp // save rp
|
||||
}
|
||||
.body
|
||||
;;
|
||||
ld8 loc2 = [loc2] // loc2 <- entry point
|
||||
mov r29 = in1 // first argument
|
||||
mov r30 = in2 // copy arg2
|
||||
mov r31 = in3 // copy arg3
|
||||
;;
|
||||
mov loc3 = psr // save psr
|
||||
adds r8 = 1f-1b,r8 // calculate return address for call
|
||||
;;
|
||||
mov loc4=ar.rsc // save RSE configuration
|
||||
dep.z loc2=loc2,0,61 // convert pal entry point to physical
|
||||
tpa r8=r8 // convert rp to physical
|
||||
;;
|
||||
mov b7 = loc2 // install target to branch reg
|
||||
mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
movl r16=PAL_PSR_BITS_TO_CLEAR
|
||||
movl r17=PAL_PSR_BITS_TO_SET
|
||||
;;
|
||||
or loc3=loc3,r17 // add in psr the bits to set
|
||||
;;
|
||||
andcm r16=loc3,r16 // removes bits to clear from psr
|
||||
br.call.sptk.many rp=ia64_switch_mode_phys
|
||||
.ret1: mov rp = r8 // install return address (physical)
|
||||
mov loc5 = r19
|
||||
mov loc6 = r20
|
||||
br.cond.sptk.many b7
|
||||
1:
|
||||
mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
mov r16=loc3 // r16= original psr
|
||||
mov r19=loc5
|
||||
mov r20=loc6
|
||||
br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
|
||||
.ret2:
|
||||
mov psr.l = loc3 // restore init PSR
|
||||
|
||||
mov ar.pfs = loc1
|
||||
mov rp = loc0
|
||||
;;
|
||||
mov ar.rsc=loc4 // restore RSE configuration
|
||||
srlz.d // seralize restoration of psr.l
|
||||
br.ret.sptk.many b0
|
||||
END(ia64_pal_call_phys_static)
|
||||
|
||||
/*
|
||||
* Make a PAL call using the stacked registers in physical mode.
|
||||
*
|
||||
* Inputs:
|
||||
* in0 Index of PAL service
|
||||
* in2 - in3 Remaning PAL arguments
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
|
||||
alloc loc1 = ar.pfs,5,7,4,0
|
||||
movl loc2 = pal_entry_point
|
||||
1: {
|
||||
mov r28 = in0 // copy procedure index
|
||||
mov loc0 = rp // save rp
|
||||
}
|
||||
.body
|
||||
;;
|
||||
ld8 loc2 = [loc2] // loc2 <- entry point
|
||||
mov loc3 = psr // save psr
|
||||
;;
|
||||
mov loc4=ar.rsc // save RSE configuration
|
||||
dep.z loc2=loc2,0,61 // convert pal entry point to physical
|
||||
;;
|
||||
mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
movl r16=PAL_PSR_BITS_TO_CLEAR
|
||||
movl r17=PAL_PSR_BITS_TO_SET
|
||||
;;
|
||||
or loc3=loc3,r17 // add in psr the bits to set
|
||||
mov b7 = loc2 // install target to branch reg
|
||||
;;
|
||||
andcm r16=loc3,r16 // removes bits to clear from psr
|
||||
br.call.sptk.many rp=ia64_switch_mode_phys
|
||||
|
||||
mov out0 = in0 // first argument
|
||||
mov out1 = in1 // copy arg2
|
||||
mov out2 = in2 // copy arg3
|
||||
mov out3 = in3 // copy arg3
|
||||
mov loc5 = r19
|
||||
mov loc6 = r20
|
||||
|
||||
br.call.sptk.many rp=b7 // now make the call
|
||||
|
||||
mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
mov r16=loc3 // r16= original psr
|
||||
mov r19=loc5
|
||||
mov r20=loc6
|
||||
br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
|
||||
|
||||
mov psr.l = loc3 // restore init PSR
|
||||
mov ar.pfs = loc1
|
||||
mov rp = loc0
|
||||
;;
|
||||
mov ar.rsc=loc4 // restore RSE configuration
|
||||
srlz.d // seralize restoration of psr.l
|
||||
br.ret.sptk.many b0
|
||||
END(ia64_pal_call_phys_stacked)
|
||||
|
||||
/*
|
||||
* Save scratch fp scratch regs which aren't saved in pt_regs already (fp10-fp15).
|
||||
*
|
||||
* NOTE: We need to do this since firmware (SAL and PAL) may use any of the scratch
|
||||
* regs fp-low partition.
|
||||
*
|
||||
* Inputs:
|
||||
* in0 Address of stack storage for fp regs
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_save_scratch_fpregs)
|
||||
alloc r3=ar.pfs,1,0,0,0
|
||||
add r2=16,in0
|
||||
;;
|
||||
stf.spill [in0] = f10,32
|
||||
stf.spill [r2] = f11,32
|
||||
;;
|
||||
stf.spill [in0] = f12,32
|
||||
stf.spill [r2] = f13,32
|
||||
;;
|
||||
stf.spill [in0] = f14,32
|
||||
stf.spill [r2] = f15,32
|
||||
br.ret.sptk.many rp
|
||||
END(ia64_save_scratch_fpregs)
|
||||
|
||||
/*
|
||||
* Load scratch fp scratch regs (fp10-fp15)
|
||||
*
|
||||
* Inputs:
|
||||
* in0 Address of stack storage for fp regs
|
||||
*/
|
||||
GLOBAL_ENTRY(ia64_load_scratch_fpregs)
|
||||
alloc r3=ar.pfs,1,0,0,0
|
||||
add r2=16,in0
|
||||
;;
|
||||
ldf.fill f10 = [in0],32
|
||||
ldf.fill f11 = [r2],32
|
||||
;;
|
||||
ldf.fill f12 = [in0],32
|
||||
ldf.fill f13 = [r2],32
|
||||
;;
|
||||
ldf.fill f14 = [in0],32
|
||||
ldf.fill f15 = [r2],32
|
||||
br.ret.sptk.many rp
|
||||
END(ia64_load_scratch_fpregs)
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Instruction-patching support.
|
||||
*
|
||||
* Copyright (C) 2003 Hewlett-Packard Co
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/patch.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/*
|
||||
* This was adapted from code written by Tony Luck:
|
||||
*
|
||||
* The 64-bit value in a "movl reg=value" is scattered between the two words of the bundle
|
||||
* like this:
|
||||
*
|
||||
* 6 6 5 4 3 2 1
|
||||
* 3210987654321098765432109876543210987654321098765432109876543210
|
||||
* ABBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCDEEEEEFFFFFFFFFGGGGGGG
|
||||
*
|
||||
* CCCCCCCCCCCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* xxxxAFFFFFFFFFEEEEEDxGGGGGGGxxxxxxxxxxxxxBBBBBBBBBBBBBBBBBBBBBBB
|
||||
*/
|
||||
static u64
|
||||
get_imm64 (u64 insn_addr)
|
||||
{
|
||||
u64 *p = (u64 *) (insn_addr & -16); /* mask out slot number */
|
||||
|
||||
return ( (p[1] & 0x0800000000000000UL) << 4) | /*A*/
|
||||
((p[1] & 0x00000000007fffffUL) << 40) | /*B*/
|
||||
((p[0] & 0xffffc00000000000UL) >> 24) | /*C*/
|
||||
((p[1] & 0x0000100000000000UL) >> 23) | /*D*/
|
||||
((p[1] & 0x0003e00000000000UL) >> 29) | /*E*/
|
||||
((p[1] & 0x07fc000000000000UL) >> 43) | /*F*/
|
||||
((p[1] & 0x000007f000000000UL) >> 36); /*G*/
|
||||
}
|
||||
|
||||
/* Patch instruction with "val" where "mask" has 1 bits. */
|
||||
void
|
||||
ia64_patch (u64 insn_addr, u64 mask, u64 val)
|
||||
{
|
||||
u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16);
|
||||
# define insn_mask ((1UL << 41) - 1)
|
||||
unsigned long shift;
|
||||
|
||||
b0 = b[0]; b1 = b[1];
|
||||
shift = 5 + 41 * (insn_addr % 16); /* 5 bits of template, then 3 x 41-bit instructions */
|
||||
if (shift >= 64) {
|
||||
m1 = mask << (shift - 64);
|
||||
v1 = val << (shift - 64);
|
||||
} else {
|
||||
m0 = mask << shift; m1 = mask >> (64 - shift);
|
||||
v0 = val << shift; v1 = val >> (64 - shift);
|
||||
b[0] = (b0 & ~m0) | (v0 & m0);
|
||||
}
|
||||
b[1] = (b1 & ~m1) | (v1 & m1);
|
||||
}
|
||||
|
||||
void
|
||||
ia64_patch_imm64 (u64 insn_addr, u64 val)
|
||||
{
|
||||
/* The assembler may generate offset pointing to either slot 1
|
||||
or slot 2 for a long (2-slot) instruction, occupying slots 1
|
||||
and 2. */
|
||||
insn_addr &= -16UL;
|
||||
ia64_patch(insn_addr + 2,
|
||||
0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
|
||||
| ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */
|
||||
| ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */));
|
||||
ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
|
||||
}
|
||||
|
||||
void
|
||||
ia64_patch_imm60 (u64 insn_addr, u64 val)
|
||||
{
|
||||
/* The assembler may generate offset pointing to either slot 1
|
||||
or slot 2 for a long (2-slot) instruction, occupying slots 1
|
||||
and 2. */
|
||||
insn_addr &= -16UL;
|
||||
ia64_patch(insn_addr + 2,
|
||||
0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
|
||||
| ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
|
||||
ia64_patch(insn_addr + 1, 0x1fffffffffcUL, val >> 18);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need sometimes to load the physical address of a kernel
|
||||
* object. Often we can convert the virtual address to physical
|
||||
* at execution time, but sometimes (either for performance reasons
|
||||
* or during error recovery) we cannot to this. Patch the marked
|
||||
* bundles to load the physical address.
|
||||
*/
|
||||
void __init
|
||||
ia64_patch_vtop (unsigned long start, unsigned long end)
|
||||
{
|
||||
s32 *offp = (s32 *) start;
|
||||
u64 ip;
|
||||
|
||||
while (offp < (s32 *) end) {
|
||||
ip = (u64) offp + *offp;
|
||||
|
||||
/* replace virtual address with corresponding physical address: */
|
||||
ia64_patch_imm64(ip, ia64_tpa(get_imm64(ip)));
|
||||
ia64_fc((void *) ip);
|
||||
++offp;
|
||||
}
|
||||
ia64_sync_i();
|
||||
ia64_srlz_i();
|
||||
}
|
||||
|
||||
void __init
|
||||
ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
|
||||
{
|
||||
static int first_time = 1;
|
||||
int need_workaround;
|
||||
s32 *offp = (s32 *) start;
|
||||
u64 *wp;
|
||||
|
||||
need_workaround = (local_cpu_data->family == 0x1f && local_cpu_data->model == 0);
|
||||
|
||||
if (first_time) {
|
||||
first_time = 0;
|
||||
if (need_workaround)
|
||||
printk(KERN_INFO "Leaving McKinley Errata 9 workaround enabled\n");
|
||||
else
|
||||
printk(KERN_INFO "McKinley Errata 9 workaround not needed; "
|
||||
"disabling it\n");
|
||||
}
|
||||
if (need_workaround)
|
||||
return;
|
||||
|
||||
while (offp < (s32 *) end) {
|
||||
wp = (u64 *) ia64_imva((char *) offp + *offp);
|
||||
wp[0] = 0x0000000100000000UL; /* nop.m 0; nop.i 0; nop.i 0 */
|
||||
wp[1] = 0x0004000000000200UL;
|
||||
wp[2] = 0x0000000100000011UL; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */
|
||||
wp[3] = 0x0084006880000200UL;
|
||||
ia64_fc(wp); ia64_fc(wp + 2);
|
||||
++offp;
|
||||
}
|
||||
ia64_sync_i();
|
||||
ia64_srlz_i();
|
||||
}
|
||||
|
||||
static void __init
|
||||
patch_fsyscall_table (unsigned long start, unsigned long end)
|
||||
{
|
||||
extern unsigned long fsyscall_table[NR_syscalls];
|
||||
s32 *offp = (s32 *) start;
|
||||
u64 ip;
|
||||
|
||||
while (offp < (s32 *) end) {
|
||||
ip = (u64) ia64_imva((char *) offp + *offp);
|
||||
ia64_patch_imm64(ip, (u64) fsyscall_table);
|
||||
ia64_fc((void *) ip);
|
||||
++offp;
|
||||
}
|
||||
ia64_sync_i();
|
||||
ia64_srlz_i();
|
||||
}
|
||||
|
||||
static void __init
|
||||
patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
|
||||
{
|
||||
extern char fsys_bubble_down[];
|
||||
s32 *offp = (s32 *) start;
|
||||
u64 ip;
|
||||
|
||||
while (offp < (s32 *) end) {
|
||||
ip = (u64) offp + *offp;
|
||||
ia64_patch_imm60((u64) ia64_imva((void *) ip),
|
||||
(u64) (fsys_bubble_down - (ip & -16)) / 16);
|
||||
ia64_fc((void *) ip);
|
||||
++offp;
|
||||
}
|
||||
ia64_sync_i();
|
||||
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
|
||||
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
|
||||
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
|
||||
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)
|
||||
{
|
||||
# define START(name) ((unsigned long) __start_gate_##name##_patchlist)
|
||||
# define END(name) ((unsigned long)__end_gate_##name##_patchlist)
|
||||
|
||||
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));
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,500 +0,0 @@
|
||||
/*
|
||||
* linux/arch/ia64/kernel/time.c
|
||||
*
|
||||
* Copyright (C) 1998-2003 Hewlett-Packard Co
|
||||
* Stephane Eranian <eranian@hpl.hp.com>
|
||||
* David Mosberger <davidm@hpl.hp.com>
|
||||
* Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
|
||||
* Copyright (C) 1999-2000 VA Linux Systems
|
||||
* Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
|
||||
*/
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/sal.h>
|
||||
#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
|
||||
|
||||
extern unsigned long wall_jiffies;
|
||||
|
||||
volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
|
||||
|
||||
#ifdef CONFIG_IA64_DEBUG_IRQ
|
||||
|
||||
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 = {
|
||||
.shift = 16,
|
||||
.mask = 0xffffffffffffffffLL,
|
||||
.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, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long new_itm;
|
||||
unsigned long delta_itm; /* XEN */
|
||||
|
||||
if (unlikely(cpu_is_offline(smp_processor_id()))) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
platform_timer_interrupt(irq, dev_id, regs);
|
||||
|
||||
new_itm = local_cpu_data->itm_next;
|
||||
|
||||
if (!time_after(ia64_get_itc(), new_itm))
|
||||
printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
|
||||
ia64_get_itc(), new_itm);
|
||||
|
||||
profile_tick(CPU_PROFILING, regs);
|
||||
|
||||
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(regs));
|
||||
|
||||
new_itm += local_cpu_data->itm_delta;
|
||||
|
||||
if (smp_processor_id() == time_keeper_id) {
|
||||
/*
|
||||
* Here we are in the timer irq handler. We have irqs locally
|
||||
* disabled, but we don't know if the timer_bh is running on
|
||||
* another CPU. We need to avoid to SMP race by acquiring the
|
||||
* xtime_lock.
|
||||
*/
|
||||
write_seqlock(&xtime_lock);
|
||||
do_timer(regs);
|
||||
local_cpu_data->itm_next = new_itm;
|
||||
write_sequnlock(&xtime_lock);
|
||||
} else
|
||||
local_cpu_data->itm_next = new_itm;
|
||||
|
||||
if (time_after(new_itm, ia64_get_itc()))
|
||||
break;
|
||||
}
|
||||
|
||||
skip_process_time_accounting: /* XEN */
|
||||
|
||||
do {
|
||||
/*
|
||||
* If we're too close to the next clock tick for
|
||||
* comfort, we increase the safety margin by
|
||||
* intentionally dropping the next tick(s). We do NOT
|
||||
* update itm.next because that would force us to call
|
||||
* do_timer() which in turn would let our clock run
|
||||
* too fast (with the potentially devastating effect
|
||||
* of losing monotony of time).
|
||||
*/
|
||||
while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2))
|
||||
new_itm += local_cpu_data->itm_delta;
|
||||
ia64_set_itm(new_itm);
|
||||
/* double check, in case we got hit by a (slow) PMI: */
|
||||
} while (time_after_eq(ia64_get_itc(), new_itm));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encapsulate access to the itm structure for SMP.
|
||||
*/
|
||||
void
|
||||
ia64_cpu_local_tick (void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
unsigned long shift = 0, delta;
|
||||
|
||||
/* arrange for the cycle counter to generate a timer interrupt: */
|
||||
ia64_set_itv(IA64_TIMER_VECTOR);
|
||||
|
||||
delta = local_cpu_data->itm_delta;
|
||||
/*
|
||||
* Stagger the timer tick for each CPU so they don't occur all at (almost) the
|
||||
* same time:
|
||||
*/
|
||||
if (cpu) {
|
||||
unsigned long hi = 1UL << ia64_fls(cpu);
|
||||
shift = (2*(cpu - hi) + 1) * delta/hi/2;
|
||||
}
|
||||
local_cpu_data->itm_next = ia64_get_itc() + delta + shift;
|
||||
ia64_set_itm(local_cpu_data->itm_next);
|
||||
}
|
||||
|
||||
static int nojitter;
|
||||
|
||||
static int __init nojitter_setup(char *str)
|
||||
{
|
||||
nojitter = 1;
|
||||
printk("Jitter checking for ITC timers disabled\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
__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);
|
||||
int rc;
|
||||
|
||||
memset(runstate, 0, sizeof(*runstate));
|
||||
|
||||
area.addr.v = runstate;
|
||||
rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area);
|
||||
WARN_ON(rc && rc != -ENOSYS);
|
||||
|
||||
per_cpu(processed_blocked_time, cpu) = runstate->time[RUNSTATE_blocked];
|
||||
per_cpu(processed_stolen_time, cpu) = runstate->time[RUNSTATE_runnable]
|
||||
+ runstate->time[RUNSTATE_offline];
|
||||
}
|
||||
|
||||
static int xen_ia64_settimefoday_after_resume;
|
||||
|
||||
static int __init __xen_ia64_settimeofday_after_resume(char *str)
|
||||
{
|
||||
xen_ia64_settimefoday_after_resume = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("xen_ia64_settimefoday_after_resume",
|
||||
__xen_ia64_settimeofday_after_resume);
|
||||
|
||||
/* Called after suspend, to resume time. */
|
||||
void
|
||||
time_resume(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* Just trigger a tick. */
|
||||
ia64_cpu_local_tick();
|
||||
|
||||
if (xen_ia64_settimefoday_after_resume) {
|
||||
/* do_settimeofday() resets timer interplator */
|
||||
struct timespec xen_time;
|
||||
int ret;
|
||||
efi_gettimeofday(&xen_time);
|
||||
|
||||
ret = do_settimeofday(&xen_time);
|
||||
WARN_ON(ret);
|
||||
} else {
|
||||
#if 0
|
||||
/* adjust EFI time */
|
||||
struct timespec my_time = CURRENT_TIME;
|
||||
struct timespec xen_time;
|
||||
static timespec diff;
|
||||
struct xen_domctl domctl;
|
||||
int ret;
|
||||
|
||||
efi_gettimeofday(&xen_time);
|
||||
diff = timespec_sub(&xen_time, &my_time);
|
||||
domctl.cmd = XEN_DOMCTL_settimeoffset;
|
||||
domctl.domain = DOMID_SELF;
|
||||
domctl.u.settimeoffset.timeoffset_seconds = diff.tv_sec;
|
||||
ret = HYPERVISOR_domctl_op(&domctl);
|
||||
WARN_ON(ret);
|
||||
#endif
|
||||
/* Time interpolator remembers the last timer status.
|
||||
Forget it */
|
||||
write_seqlock_irq(&xtime_lock);
|
||||
time_interpolator_reset();
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
}
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
init_missing_ticks_accounting(cpu);
|
||||
|
||||
touch_softlockup_watchdog();
|
||||
}
|
||||
#else
|
||||
#define init_missing_ticks_accounting(cpu) do {} while (0)
|
||||
#endif
|
||||
|
||||
void __devinit
|
||||
ia64_init_itm (void)
|
||||
{
|
||||
unsigned long platform_base_freq, itc_freq;
|
||||
struct pal_freq_ratio itc_ratio, proc_ratio;
|
||||
long status, platform_base_drift, itc_drift;
|
||||
|
||||
/*
|
||||
* According to SAL v2.6, we need to use a SAL call to determine the platform base
|
||||
* frequency and then a PAL call to determine the frequency ratio between the ITC
|
||||
* and the base frequency.
|
||||
*/
|
||||
status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
|
||||
&platform_base_freq, &platform_base_drift);
|
||||
if (status != 0) {
|
||||
printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
|
||||
} else {
|
||||
status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio);
|
||||
if (status != 0)
|
||||
printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status);
|
||||
}
|
||||
if (status != 0) {
|
||||
/* invent "random" values */
|
||||
printk(KERN_ERR
|
||||
"SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
|
||||
platform_base_freq = 100000000;
|
||||
platform_base_drift = -1; /* no drift info */
|
||||
itc_ratio.num = 3;
|
||||
itc_ratio.den = 1;
|
||||
}
|
||||
if (platform_base_freq < 40000000) {
|
||||
printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
|
||||
platform_base_freq);
|
||||
platform_base_freq = 75000000;
|
||||
platform_base_drift = -1;
|
||||
}
|
||||
if (!proc_ratio.den)
|
||||
proc_ratio.den = 1; /* avoid division by zero */
|
||||
if (!itc_ratio.den)
|
||||
itc_ratio.den = 1; /* avoid division by zero */
|
||||
|
||||
itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
|
||||
|
||||
local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
|
||||
printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, "
|
||||
"ITC freq=%lu.%03luMHz", smp_processor_id(),
|
||||
platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
|
||||
itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
|
||||
|
||||
if (platform_base_drift != -1) {
|
||||
itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den;
|
||||
printk("+/-%ldppm\n", itc_drift);
|
||||
} else {
|
||||
itc_drift = -1;
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
|
||||
local_cpu_data->itc_freq = itc_freq;
|
||||
local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC;
|
||||
local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
|
||||
+ itc_freq/2)/itc_freq;
|
||||
|
||||
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
|
||||
itc_interpolator.frequency = local_cpu_data->itc_freq;
|
||||
itc_interpolator.drift = itc_drift;
|
||||
#ifdef CONFIG_SMP
|
||||
/* On IA64 in an SMP configuration ITCs are never accurately synchronized.
|
||||
* Jitter compensation requires a cmpxchg which may limit
|
||||
* the scalability of the syscalls for retrieving time.
|
||||
* The ITC synchronization is usually successful to within a few
|
||||
* ITC ticks but this is not a sure thing. If you need to improve
|
||||
* timer performance in SMP situations then boot the kernel with the
|
||||
* "nojitter" option. However, doing so may result in time fluctuating (maybe
|
||||
* even going backward) if the ITC offsets between the individual CPUs
|
||||
* are too large.
|
||||
*/
|
||||
if (!nojitter) itc_interpolator.jitter = 1;
|
||||
#endif
|
||||
register_time_interpolator(&itc_interpolator);
|
||||
}
|
||||
|
||||
if (is_running_on_xen())
|
||||
init_missing_ticks_accounting(smp_processor_id());
|
||||
|
||||
/* avoid softlock up message when cpu is unplug and plugged again. */
|
||||
touch_softlockup_watchdog();
|
||||
|
||||
/* Setup the CPU local timer tick */
|
||||
ia64_cpu_local_tick();
|
||||
}
|
||||
|
||||
static struct irqaction timer_irqaction = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "timer"
|
||||
};
|
||||
|
||||
void __devinit ia64_disable_timer(void)
|
||||
{
|
||||
ia64_set_itv(1 << 16);
|
||||
}
|
||||
|
||||
void __init
|
||||
time_init (void)
|
||||
{
|
||||
register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
|
||||
efi_gettimeofday(&xtime);
|
||||
ia64_init_itm();
|
||||
|
||||
/*
|
||||
* Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
|
||||
* tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
|
||||
*/
|
||||
set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic udelay assumes that if preemption is allowed and the thread
|
||||
* migrates to another CPU, that the ITC values are synchronized across
|
||||
* all CPUs.
|
||||
*/
|
||||
static void
|
||||
ia64_itc_udelay (unsigned long usecs)
|
||||
{
|
||||
unsigned long start = ia64_get_itc();
|
||||
unsigned long end = start + usecs*local_cpu_data->cyc_per_usec;
|
||||
|
||||
while (time_before(ia64_get_itc(), end))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
void (*ia64_udelay)(unsigned long usecs) = &ia64_itc_udelay;
|
||||
|
||||
void
|
||||
udelay (unsigned long usecs)
|
||||
{
|
||||
(*ia64_udelay)(usecs);
|
||||
}
|
||||
EXPORT_SYMBOL(udelay);
|
||||
|
||||
static unsigned long long ia64_itc_printk_clock(void)
|
||||
{
|
||||
if (ia64_get_kr(IA64_KR_PER_CPU_DATA))
|
||||
return sched_clock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long long ia64_default_printk_clock(void)
|
||||
{
|
||||
return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) *
|
||||
(1000000000/HZ);
|
||||
}
|
||||
|
||||
unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock;
|
||||
|
||||
unsigned long long printk_clock(void)
|
||||
{
|
||||
return ia64_printk_clock();
|
||||
}
|
||||
|
||||
void __init
|
||||
ia64_setup_printk_clock(void)
|
||||
{
|
||||
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
|
||||
ia64_printk_clock = ia64_itc_printk_clock;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.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/compiler.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/efi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/meminit.h>
|
||||
|
||||
static inline void __iomem *
|
||||
__ioremap (unsigned long offset, unsigned long size)
|
||||
{
|
||||
offset = HYPERVISOR_ioremap(offset, size);
|
||||
if (IS_ERR_VALUE(offset))
|
||||
return (void __iomem*)offset;
|
||||
return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
|
||||
}
|
||||
|
||||
void __iomem *
|
||||
ioremap (unsigned long offset, unsigned long size)
|
||||
{
|
||||
u64 attr;
|
||||
unsigned long gran_base, gran_size;
|
||||
|
||||
/*
|
||||
* For things in kern_memmap, we must use the same attribute
|
||||
* as the rest of the kernel. For more details, see
|
||||
* Documentation/ia64/aliasing.txt.
|
||||
*/
|
||||
attr = kern_mem_attribute(offset, size);
|
||||
if (attr & EFI_MEMORY_WB)
|
||||
return (void __iomem *) phys_to_virt(offset);
|
||||
else if (attr & EFI_MEMORY_UC)
|
||||
return __ioremap(offset, size);
|
||||
|
||||
/*
|
||||
* Some chipsets don't support UC access to memory. If
|
||||
* WB is supported for the whole granule, we prefer that.
|
||||
*/
|
||||
gran_base = GRANULEROUNDDOWN(offset);
|
||||
gran_size = GRANULEROUNDUP(offset + size) - gran_base;
|
||||
if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
|
||||
return (void __iomem *) phys_to_virt(offset);
|
||||
|
||||
return __ioremap(offset, size);
|
||||
}
|
||||
EXPORT_SYMBOL(ioremap);
|
||||
|
||||
void __iomem *
|
||||
ioremap_nocache (unsigned long offset, unsigned long size)
|
||||
{
|
||||
if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB)
|
||||
return NULL;
|
||||
|
||||
return __ioremap(offset, size);
|
||||
}
|
||||
EXPORT_SYMBOL(ioremap_nocache);
|
||||
@@ -1,14 +0,0 @@
|
||||
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) init.o backtrace.o
|
||||
oprofile-$(CONFIG_PERFMON) += perfmon.o
|
||||
ifeq ($(CONFIG_XEN), y)
|
||||
oprofile-$(CONFIG_PERFMON) += xenoprof.o \
|
||||
../../../drivers/xen/xenoprof/xenoprofile.o
|
||||
endif
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* @file init.c
|
||||
*
|
||||
* @remark Copyright 2002 OProfile authors
|
||||
* @remark Read the file COPYING
|
||||
*
|
||||
* @author John Levon <levon@movementarian.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#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);
|
||||
extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
|
||||
|
||||
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 */
|
||||
ret = perfmon_init(ops);
|
||||
#endif
|
||||
ops->backtrace = ia64_backtrace;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void oprofile_arch_exit(void)
|
||||
{
|
||||
if (is_running_on_xen()) {
|
||||
xenoprofile_exit();
|
||||
xen_perfmon_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PERFMON
|
||||
perfmon_exit();
|
||||
#endif
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#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 */
|
||||
@@ -1,118 +0,0 @@
|
||||
/**
|
||||
* @file perfmon.c
|
||||
*
|
||||
* @remark Copyright 2003 OProfile authors
|
||||
* @remark Read the file COPYING
|
||||
*
|
||||
* @author John Levon <levon@movementarian.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/oprofile.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/perfmon.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/errno.h>
|
||||
#include "oprofile_perfmon.h"
|
||||
|
||||
static int allow_ints;
|
||||
|
||||
static int
|
||||
perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
|
||||
struct pt_regs *regs, unsigned long stamp)
|
||||
{
|
||||
int event = arg->pmd_eventid;
|
||||
|
||||
arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1;
|
||||
|
||||
/* the owner of the oprofile event buffer may have exited
|
||||
* without perfmon being shutdown (e.g. SIGSEGV)
|
||||
*/
|
||||
if (allow_ints)
|
||||
oprofile_add_sample(regs, event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
STATIC_IF_NO_XEN
|
||||
int perfmon_start(void)
|
||||
{
|
||||
allow_ints = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
STATIC_IF_NO_XEN
|
||||
void perfmon_stop(void)
|
||||
{
|
||||
allow_ints = 0;
|
||||
}
|
||||
|
||||
|
||||
#define OPROFILE_FMT_UUID { \
|
||||
0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c }
|
||||
|
||||
static pfm_buffer_fmt_t oprofile_fmt = {
|
||||
.fmt_name = "oprofile_format",
|
||||
.fmt_uuid = OPROFILE_FMT_UUID,
|
||||
.fmt_handler = perfmon_handler,
|
||||
};
|
||||
|
||||
|
||||
static char * get_cpu_type(void)
|
||||
{
|
||||
__u8 family = local_cpu_data->family;
|
||||
|
||||
switch (family) {
|
||||
case 0x07:
|
||||
return "ia64/itanium";
|
||||
case 0x1f:
|
||||
return "ia64/itanium2";
|
||||
default:
|
||||
return "ia64/ia64";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* all the ops are handled via userspace for IA64 perfmon */
|
||||
|
||||
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 = __perfmon_init();
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
|
||||
ops->cpu_type = get_cpu_type();
|
||||
ops->start = perfmon_start;
|
||||
ops->stop = perfmon_stop;
|
||||
printk(KERN_INFO "oprofile: using perfmon.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void perfmon_exit(void)
|
||||
{
|
||||
__perfmon_exit();
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
@@ -1,836 +0,0 @@
|
||||
/*
|
||||
* pci.c - Low-Level PCI Access in IA-64
|
||||
*
|
||||
* Derived from bios32.c of i386 tree.
|
||||
*
|
||||
* (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P.
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
* Copyright (C) 2004 Silicon Graphics, Inc.
|
||||
*
|
||||
* Note: Above list of copyright holders is incomplete...
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/sal.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/hw_irq.h>
|
||||
|
||||
/*
|
||||
* Low-level SAL-based PCI configuration access functions. Note that SAL
|
||||
* calls are already serialized (via sal_lock), so we don't need another
|
||||
* synchronization mechanism here.
|
||||
*/
|
||||
|
||||
#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \
|
||||
(((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg))
|
||||
|
||||
/* SAL 3.2 adds support for extended config space. */
|
||||
|
||||
#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \
|
||||
(((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg))
|
||||
|
||||
static int
|
||||
pci_sal_read (unsigned int seg, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 *value)
|
||||
{
|
||||
u64 addr, data = 0;
|
||||
int mode, result;
|
||||
|
||||
if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
|
||||
return -EINVAL;
|
||||
|
||||
if ((seg | reg) <= 255) {
|
||||
addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
|
||||
mode = 0;
|
||||
} else {
|
||||
addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
|
||||
mode = 1;
|
||||
}
|
||||
result = ia64_sal_pci_config_read(addr, mode, len, &data);
|
||||
if (result != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*value = (u32) data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn,
|
||||
int reg, int len, u32 value)
|
||||
{
|
||||
u64 addr;
|
||||
int mode, result;
|
||||
|
||||
if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
|
||||
return -EINVAL;
|
||||
|
||||
if ((seg | reg) <= 255) {
|
||||
addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
|
||||
mode = 0;
|
||||
} else {
|
||||
addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
|
||||
mode = 1;
|
||||
}
|
||||
result = ia64_sal_pci_config_write(addr, mode, len, value);
|
||||
if (result != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_raw_ops pci_sal_ops = {
|
||||
.read = pci_sal_read,
|
||||
.write = pci_sal_write
|
||||
};
|
||||
|
||||
struct pci_raw_ops *raw_pci_ops = &pci_sal_ops;
|
||||
|
||||
static int
|
||||
pci_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
|
||||
{
|
||||
return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
|
||||
devfn, where, size, value);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
|
||||
{
|
||||
return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
|
||||
devfn, where, size, value);
|
||||
}
|
||||
|
||||
struct pci_ops pci_root_ops = {
|
||||
.read = pci_read,
|
||||
.write = pci_write,
|
||||
};
|
||||
|
||||
/* Called by ACPI when it finds a new root bus. */
|
||||
|
||||
static struct pci_controller * __devinit
|
||||
alloc_pci_controller (int seg)
|
||||
{
|
||||
struct pci_controller *controller;
|
||||
|
||||
controller = kmalloc(sizeof(*controller), GFP_KERNEL);
|
||||
if (!controller)
|
||||
return NULL;
|
||||
|
||||
memset(controller, 0, sizeof(*controller));
|
||||
controller->segment = seg;
|
||||
controller->node = -1;
|
||||
return controller;
|
||||
}
|
||||
|
||||
struct pci_root_info {
|
||||
struct pci_controller *controller;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
new_space (u64 phys_base, int sparse)
|
||||
{
|
||||
u64 mmio_base;
|
||||
int i;
|
||||
|
||||
if (phys_base == 0)
|
||||
return 0; /* legacy I/O port space */
|
||||
|
||||
mmio_base = (u64) ioremap(phys_base, 0);
|
||||
for (i = 0; i < num_io_spaces; i++)
|
||||
if (io_space[i].mmio_base == mmio_base &&
|
||||
io_space[i].sparse == sparse)
|
||||
return i;
|
||||
|
||||
if (num_io_spaces == MAX_IO_SPACES) {
|
||||
printk(KERN_ERR "PCI: Too many IO port spaces "
|
||||
"(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES);
|
||||
return ~0;
|
||||
}
|
||||
|
||||
i = num_io_spaces++;
|
||||
io_space[i].mmio_base = mmio_base;
|
||||
io_space[i].sparse = sparse;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static u64 __devinit
|
||||
add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr)
|
||||
{
|
||||
struct resource *resource;
|
||||
char *name;
|
||||
u64 base, min, max, base_port;
|
||||
unsigned int sparse = 0, space_nr, len;
|
||||
|
||||
resource = kzalloc(sizeof(*resource), GFP_KERNEL);
|
||||
if (!resource) {
|
||||
printk(KERN_ERR "PCI: No memory for %s I/O port space\n",
|
||||
info->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = strlen(info->name) + 32;
|
||||
name = kzalloc(len, GFP_KERNEL);
|
||||
if (!name) {
|
||||
printk(KERN_ERR "PCI: No memory for %s I/O port space name\n",
|
||||
info->name);
|
||||
goto free_resource;
|
||||
}
|
||||
|
||||
min = addr->minimum;
|
||||
max = min + addr->address_length - 1;
|
||||
if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION)
|
||||
sparse = 1;
|
||||
|
||||
space_nr = new_space(addr->translation_offset, sparse);
|
||||
if (space_nr == ~0)
|
||||
goto free_name;
|
||||
|
||||
base = __pa(io_space[space_nr].mmio_base);
|
||||
base_port = IO_SPACE_BASE(space_nr);
|
||||
snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
|
||||
base_port + min, base_port + max);
|
||||
|
||||
/*
|
||||
* The SDM guarantees the legacy 0-64K space is sparse, but if the
|
||||
* mapping is done by the processor (not the bridge), ACPI may not
|
||||
* mark it as sparse.
|
||||
*/
|
||||
if (space_nr == 0)
|
||||
sparse = 1;
|
||||
|
||||
resource->name = name;
|
||||
resource->flags = IORESOURCE_MEM;
|
||||
resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
|
||||
resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
|
||||
insert_resource(&iomem_resource, resource);
|
||||
|
||||
return base_port;
|
||||
|
||||
free_name:
|
||||
kfree(name);
|
||||
free_resource:
|
||||
kfree(resource);
|
||||
out:
|
||||
return ~0;
|
||||
}
|
||||
|
||||
static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
|
||||
struct acpi_resource_address64 *addr)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
/*
|
||||
* We're only interested in _CRS descriptors that are
|
||||
* - address space descriptors for memory or I/O space
|
||||
* - non-zero size
|
||||
* - producers, i.e., the address space is routed downstream,
|
||||
* not consumed by the bridge itself
|
||||
*/
|
||||
status = acpi_resource_to_address64(resource, addr);
|
||||
if (ACPI_SUCCESS(status) &&
|
||||
(addr->resource_type == ACPI_MEMORY_RANGE ||
|
||||
addr->resource_type == ACPI_IO_RANGE) &&
|
||||
addr->address_length &&
|
||||
addr->producer_consumer == ACPI_PRODUCER)
|
||||
return AE_OK;
|
||||
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
static acpi_status __devinit
|
||||
count_window (struct acpi_resource *resource, void *data)
|
||||
{
|
||||
unsigned int *windows = (unsigned int *) data;
|
||||
struct acpi_resource_address64 addr;
|
||||
acpi_status status;
|
||||
|
||||
status = resource_to_window(resource, &addr);
|
||||
if (ACPI_SUCCESS(status))
|
||||
(*windows)++;
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
|
||||
{
|
||||
struct pci_root_info *info = data;
|
||||
struct pci_window *window;
|
||||
struct acpi_resource_address64 addr;
|
||||
acpi_status status;
|
||||
unsigned long flags, offset = 0;
|
||||
struct resource *root;
|
||||
|
||||
/* Return AE_OK for non-window resources to keep scanning for more */
|
||||
status = resource_to_window(res, &addr);
|
||||
if (!ACPI_SUCCESS(status))
|
||||
return AE_OK;
|
||||
|
||||
if (addr.resource_type == ACPI_MEMORY_RANGE) {
|
||||
flags = IORESOURCE_MEM;
|
||||
root = &iomem_resource;
|
||||
offset = addr.translation_offset;
|
||||
} else if (addr.resource_type == ACPI_IO_RANGE) {
|
||||
flags = IORESOURCE_IO;
|
||||
root = &ioport_resource;
|
||||
offset = add_io_space(info, &addr);
|
||||
if (offset == ~0)
|
||||
return AE_OK;
|
||||
} else
|
||||
return AE_OK;
|
||||
|
||||
window = &info->controller->window[info->controller->windows++];
|
||||
window->resource.name = info->name;
|
||||
window->resource.flags = flags;
|
||||
window->resource.start = addr.minimum + offset;
|
||||
window->resource.end = window->resource.start + addr.address_length - 1;
|
||||
window->resource.child = NULL;
|
||||
window->offset = offset;
|
||||
|
||||
if (insert_resource(root, &window->resource)) {
|
||||
printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n",
|
||||
window->resource.start, window->resource.end,
|
||||
root->name, info->name);
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static void __devinit
|
||||
pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < ctrl->windows; i++) {
|
||||
struct resource *res = &ctrl->window[i].resource;
|
||||
/* HP's firmware has a hack to work around a Windows bug.
|
||||
* Ignore these tiny memory ranges */
|
||||
if ((res->flags & IORESOURCE_MEM) &&
|
||||
(res->end - res->start < 16))
|
||||
continue;
|
||||
if (j >= PCI_BUS_NUM_RESOURCES) {
|
||||
printk("Ignoring range [%lx-%lx] (%lx)\n", res->start,
|
||||
res->end, res->flags);
|
||||
continue;
|
||||
}
|
||||
bus->resource[j++] = res;
|
||||
}
|
||||
}
|
||||
|
||||
struct pci_bus * __devinit
|
||||
pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
|
||||
{
|
||||
struct pci_root_info info;
|
||||
struct pci_controller *controller;
|
||||
unsigned int windows = 0;
|
||||
struct pci_bus *pbus;
|
||||
char *name;
|
||||
int pxm;
|
||||
|
||||
controller = alloc_pci_controller(domain);
|
||||
if (!controller)
|
||||
goto out1;
|
||||
|
||||
controller->acpi_handle = device->handle;
|
||||
|
||||
pxm = acpi_get_pxm(controller->acpi_handle);
|
||||
#ifdef CONFIG_NUMA
|
||||
if (pxm >= 0)
|
||||
controller->node = pxm_to_node(pxm);
|
||||
#endif
|
||||
|
||||
acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
|
||||
&windows);
|
||||
controller->window = kmalloc_node(sizeof(*controller->window) * windows,
|
||||
GFP_KERNEL, controller->node);
|
||||
if (!controller->window)
|
||||
goto out2;
|
||||
|
||||
name = kmalloc(16, GFP_KERNEL);
|
||||
if (!name)
|
||||
goto out3;
|
||||
|
||||
sprintf(name, "PCI Bus %04x:%02x", domain, bus);
|
||||
info.controller = controller;
|
||||
info.name = name;
|
||||
acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
|
||||
&info);
|
||||
|
||||
pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
|
||||
if (pbus)
|
||||
pcibios_setup_root_windows(pbus, controller);
|
||||
|
||||
return pbus;
|
||||
|
||||
out3:
|
||||
kfree(controller->window);
|
||||
out2:
|
||||
kfree(controller);
|
||||
out1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pcibios_resource_to_bus(struct pci_dev *dev,
|
||||
struct pci_bus_region *region, struct resource *res)
|
||||
{
|
||||
struct pci_controller *controller = PCI_CONTROLLER(dev);
|
||||
unsigned long offset = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < controller->windows; i++) {
|
||||
struct pci_window *window = &controller->window[i];
|
||||
if (!(window->resource.flags & res->flags))
|
||||
continue;
|
||||
if (window->resource.start > res->start)
|
||||
continue;
|
||||
if (window->resource.end < res->end)
|
||||
continue;
|
||||
offset = window->offset;
|
||||
break;
|
||||
}
|
||||
|
||||
region->start = res->start - offset;
|
||||
region->end = res->end - offset;
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_resource_to_bus);
|
||||
|
||||
void pcibios_bus_to_resource(struct pci_dev *dev,
|
||||
struct resource *res, struct pci_bus_region *region)
|
||||
{
|
||||
struct pci_controller *controller = PCI_CONTROLLER(dev);
|
||||
unsigned long offset = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < controller->windows; i++) {
|
||||
struct pci_window *window = &controller->window[i];
|
||||
if (!(window->resource.flags & res->flags))
|
||||
continue;
|
||||
if (window->resource.start - window->offset > region->start)
|
||||
continue;
|
||||
if (window->resource.end - window->offset < region->end)
|
||||
continue;
|
||||
offset = window->offset;
|
||||
break;
|
||||
}
|
||||
|
||||
res->start = region->start + offset;
|
||||
res->end = region->end + offset;
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_bus_to_resource);
|
||||
|
||||
static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
|
||||
{
|
||||
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
|
||||
struct resource *devr = &dev->resource[idx];
|
||||
|
||||
if (!dev->bus)
|
||||
return 0;
|
||||
for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
|
||||
struct resource *busr = dev->bus->resource[i];
|
||||
|
||||
if (!busr || ((busr->flags ^ devr->flags) & type_mask))
|
||||
continue;
|
||||
if ((devr->start) && (devr->start >= busr->start) &&
|
||||
(devr->end <= busr->end))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit
|
||||
pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
|
||||
{
|
||||
struct pci_bus_region region;
|
||||
int i;
|
||||
|
||||
for (i = start; i < limit; i++) {
|
||||
if (!dev->resource[i].flags)
|
||||
continue;
|
||||
region.start = dev->resource[i].start;
|
||||
region.end = dev->resource[i].end;
|
||||
pcibios_bus_to_resource(dev, &dev->resource[i], ®ion);
|
||||
if ((is_valid_resource(dev, i)))
|
||||
pci_claim_resource(dev, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
|
||||
{
|
||||
pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
|
||||
}
|
||||
|
||||
static void __devinit pcibios_fixup_bridge_resources(struct pci_dev *dev)
|
||||
{
|
||||
pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after each bus is probed, but before its children are examined.
|
||||
*/
|
||||
void __devinit
|
||||
pcibios_fixup_bus (struct pci_bus *b)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
|
||||
if (b->self) {
|
||||
pci_read_bridge_bases(b);
|
||||
pcibios_fixup_bridge_resources(b->self);
|
||||
}
|
||||
list_for_each_entry(dev, &b->devices, bus_list)
|
||||
pcibios_fixup_device_resources(dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void __devinit
|
||||
pcibios_update_irq (struct pci_dev *dev, int irq)
|
||||
{
|
||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
|
||||
|
||||
/* ??? FIXME -- record old value for shutdown. */
|
||||
}
|
||||
|
||||
static inline int
|
||||
pcibios_enable_resources (struct pci_dev *dev, int mask)
|
||||
{
|
||||
u16 cmd, old_cmd;
|
||||
int idx;
|
||||
struct resource *r;
|
||||
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
old_cmd = cmd;
|
||||
for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
|
||||
/* Only set up the desired resources. */
|
||||
if (!(mask & (1 << idx)))
|
||||
continue;
|
||||
|
||||
r = &dev->resource[idx];
|
||||
if (!(r->flags & type_mask))
|
||||
continue;
|
||||
if ((idx == PCI_ROM_RESOURCE) &&
|
||||
(!(r->flags & IORESOURCE_ROM_ENABLE)))
|
||||
continue;
|
||||
if (!r->start && r->end) {
|
||||
printk(KERN_ERR
|
||||
"PCI: Device %s not available because of resource collisions\n",
|
||||
pci_name(dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
cmd |= PCI_COMMAND_IO;
|
||||
if (r->flags & IORESOURCE_MEM)
|
||||
cmd |= PCI_COMMAND_MEMORY;
|
||||
}
|
||||
if (cmd != old_cmd) {
|
||||
printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pcibios_enable_device (struct pci_dev *dev, int mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pcibios_enable_resources(dev, mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return acpi_pci_irq_enable(dev);
|
||||
}
|
||||
|
||||
void
|
||||
pcibios_disable_device (struct pci_dev *dev)
|
||||
{
|
||||
acpi_pci_irq_disable(dev);
|
||||
}
|
||||
|
||||
void
|
||||
pcibios_align_resource (void *data, struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* PCI BIOS setup, always defaults to SAL interface
|
||||
*/
|
||||
char * __init
|
||||
pcibios_setup (char *str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
int
|
||||
pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
|
||||
enum pci_mmap_state mmap_state, int write_combine)
|
||||
{
|
||||
/*
|
||||
* I/O space cannot be accessed via normal processor loads and
|
||||
* stores on this platform.
|
||||
*/
|
||||
if (mmap_state == pci_mmap_io)
|
||||
/*
|
||||
* XXX we could relax this for I/O spaces for which ACPI
|
||||
* indicates that the space is 1-to-1 mapped. But at the
|
||||
* moment, we don't support multiple PCI address spaces and
|
||||
* the legacy I/O space is not 1-to-1 mapped, so this is moot.
|
||||
*/
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Leave vm_pgoff as-is, the PCI space address is the physical
|
||||
* address on this platform.
|
||||
*/
|
||||
if (write_combine && efi_range_is_wc(vma->vm_start,
|
||||
vma->vm_end - vma->vm_start))
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ia64_pci_get_legacy_mem - generic legacy mem routine
|
||||
* @bus: bus to get legacy memory base address for
|
||||
*
|
||||
* Find the base of legacy memory for @bus. This is typically the first
|
||||
* megabyte of bus address space for @bus or is simply 0 on platforms whose
|
||||
* chipsets support legacy I/O and memory routing. Returns the base address
|
||||
* or an error pointer if an error occurred.
|
||||
*
|
||||
* This is the ia64 generic version of this routine. Other platforms
|
||||
* are free to override it with a machine vector.
|
||||
*/
|
||||
char *ia64_pci_get_legacy_mem(struct pci_bus *bus)
|
||||
{
|
||||
return (char *)__IA64_UNCACHED_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_mmap_legacy_page_range - map legacy memory space to userland
|
||||
* @bus: bus whose legacy space we're mapping
|
||||
* @vma: vma passed in by mmap
|
||||
*
|
||||
* Map legacy memory space for this device back to userspace using a machine
|
||||
* vector to get the base address.
|
||||
*/
|
||||
int
|
||||
pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long size = vma->vm_end - vma->vm_start;
|
||||
pgprot_t prot;
|
||||
char *addr;
|
||||
|
||||
/*
|
||||
* Avoid attribute aliasing. See Documentation/ia64/aliasing.txt
|
||||
* for more details.
|
||||
*/
|
||||
if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
|
||||
return -EINVAL;
|
||||
prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
|
||||
vma->vm_page_prot);
|
||||
if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot)))
|
||||
return -EINVAL;
|
||||
|
||||
addr = pci_get_legacy_mem(bus);
|
||||
if (IS_ERR(addr))
|
||||
return PTR_ERR(addr);
|
||||
|
||||
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))
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ia64_pci_legacy_read - read from legacy I/O space
|
||||
* @bus: bus to read
|
||||
* @port: legacy port value
|
||||
* @val: caller allocated storage for returned value
|
||||
* @size: number of bytes to read
|
||||
*
|
||||
* Simply reads @size bytes from @port and puts the result in @val.
|
||||
*
|
||||
* Again, this (and the write routine) are generic versions that can be
|
||||
* overridden by the platform. This is necessary on platforms that don't
|
||||
* support legacy I/O routing or that hard fail on legacy I/O timeouts.
|
||||
*/
|
||||
int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
|
||||
{
|
||||
int ret = size;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
*val = inb(port);
|
||||
break;
|
||||
case 2:
|
||||
*val = inw(port);
|
||||
break;
|
||||
case 4:
|
||||
*val = inl(port);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ia64_pci_legacy_write - perform a legacy I/O write
|
||||
* @bus: bus pointer
|
||||
* @port: port to write
|
||||
* @val: value to write
|
||||
* @size: number of bytes to write from @val
|
||||
*
|
||||
* Simply writes @size bytes of @val to @port.
|
||||
*/
|
||||
int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
|
||||
{
|
||||
int ret = size;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
outb(val, port);
|
||||
break;
|
||||
case 2:
|
||||
outw(val, port);
|
||||
break;
|
||||
case 4:
|
||||
outl(val, port);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_cacheline_size - determine cacheline size for PCI devices
|
||||
* @dev: void
|
||||
*
|
||||
* We want to use the line-size of the outer-most cache. We assume
|
||||
* that this line-size is the same for all CPUs.
|
||||
*
|
||||
* Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
|
||||
*
|
||||
* RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
|
||||
*/
|
||||
static unsigned long
|
||||
pci_cacheline_size (void)
|
||||
{
|
||||
u64 levels, unique_caches;
|
||||
s64 status;
|
||||
pal_cache_config_info_t cci;
|
||||
static u8 cacheline_size;
|
||||
|
||||
if (cacheline_size)
|
||||
return cacheline_size;
|
||||
|
||||
status = ia64_pal_cache_summary(&levels, &unique_caches);
|
||||
if (status != 0) {
|
||||
printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n",
|
||||
__FUNCTION__, status);
|
||||
return SMP_CACHE_BYTES;
|
||||
}
|
||||
|
||||
status = ia64_pal_cache_config_info(levels - 1, /* cache_type (data_or_unified)= */ 2,
|
||||
&cci);
|
||||
if (status != 0) {
|
||||
printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed (status=%ld)\n",
|
||||
__FUNCTION__, status);
|
||||
return SMP_CACHE_BYTES;
|
||||
}
|
||||
cacheline_size = 1 << cci.pcci_line_size;
|
||||
return cacheline_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* pcibios_prep_mwi - helper function for drivers/pci/pci.c:pci_set_mwi()
|
||||
* @dev: the PCI device for which MWI is enabled
|
||||
*
|
||||
* For ia64, we can get the cacheline sizes from PAL.
|
||||
*
|
||||
* RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
|
||||
*/
|
||||
int
|
||||
pcibios_prep_mwi (struct pci_dev *dev)
|
||||
{
|
||||
unsigned long desired_linesize, current_linesize;
|
||||
int rc = 0;
|
||||
u8 pci_linesize;
|
||||
|
||||
desired_linesize = pci_cacheline_size();
|
||||
|
||||
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_linesize);
|
||||
current_linesize = 4 * pci_linesize;
|
||||
if (desired_linesize != current_linesize) {
|
||||
printk(KERN_WARNING "PCI: slot %s has incorrect PCI cache line size of %lu bytes,",
|
||||
pci_name(dev), current_linesize);
|
||||
if (current_linesize > desired_linesize) {
|
||||
printk(" expected %lu bytes instead\n", desired_linesize);
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
printk(" correcting to %lu\n", desired_linesize);
|
||||
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, desired_linesize / 4);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pci_vector_resources(int last, int nr_released)
|
||||
{
|
||||
int count = nr_released;
|
||||
|
||||
count += (IA64_LAST_DEVICE_VECTOR - last);
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#
|
||||
# Makefile for Xen components
|
||||
#
|
||||
|
||||
obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \
|
||||
hypervisor.o util.o xencomm.o xcom_hcall.o xcom_mini.o \
|
||||
xcom_privcmd.o mem.o xen_dma.o
|
||||
|
||||
obj-$(CONFIG_IA64_GENERIC) += machvec.o
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,4 +0,0 @@
|
||||
#define MACHVEC_PLATFORM_NAME xen
|
||||
#define MACHVEC_PLATFORM_HEADER <asm/machvec_xen.h>
|
||||
#include <asm/machvec_init.h>
|
||||
|
||||
Loaded 100 of 441 files, more files were not shown because too many files have changed in this diff.
Show more