Remove sparse tree.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
This commit is contained in:
Ian Campbell committed 2007-06-04 11:16:19 +01:00
1 parent 06809a93ad
commit c58e445d1c
441 files changed
+5 -173455

No files matched your search

+5 -4
View File
@@ -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)
-8
View File
@@ -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
-2
View File
@@ -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:
-1
View File
@@ -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
-54
View File
@@ -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
-952
View File
@@ -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
-74
View File
@@ -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
-315
View File
@@ -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
-171
View File
@@ -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 = &current->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, &ltype);
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, &note, 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, &note, 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 = &current->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 = &current->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(&current->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(&current->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(&microcode_mutex);
ret = do_microcode_update(buf, len);
if (!ret)
ret = (ssize_t)len;
mutex_unlock(&microcode_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 = &microcode_fops,
};
static int __init microcode_init (void)
{
int error;
error = misc_register(&microcode_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(&microcode_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, &regs->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(&regs, 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, &regs, 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, &regs, 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, &regs, 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, &regs, 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,
&regs);
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 = &current->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 = &current->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(&current->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(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
&regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
tmp += put_user(current->thread.screen_bitmap,&current->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, &current->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 = &regs;
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 = &regs;
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(&current->sighand->siglock, flags);
sigdelset(&current->blocked, SIGTRAP);
recalc_sigpending();
spin_unlock_irqrestore(&current->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 *)&regs->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(&notify_page_fault_chain, nb);
}
int unregister_page_fault_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&notify_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(&notify_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(&current->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(&current->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
-587
View File
@@ -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"
-106
View File
@@ -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 = &current->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 = &current->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);
}
-303
View File
@@ -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;
}
-836
View File
@@ -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], &region);
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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.